用opengl画图SDL Renderer就没用了吗?

Is SDL Renderer useless if I use opengl for drawing?

我正在学习 SDL2,但我也在使用使用 OpenGL 调用的 imgui 库。根据我在各种在线博客上阅读的内容,我不能轻易混合 SDL2 渲染器和 opengl 调用;我要么使用其中一个。

我读过的大部分教程都使用渲染器,所以我不太明白如何在没有渲染器的情况下使用 SDL2 来绘制基元或绘制精灵。

以此为例:http://lazyfoo.net/tutorials/SDL/11_clip_rendering_and_sprite_sheets/index.php

他创建了 sdl 渲染器:

gRenderer = SDL_CreateRenderer( gWindow, -1, SDL_RENDERER_ACCELERATED );

然后他用它来渲染图像:

void LTexture::render( int x, int y, SDL_Rect* clip )
{
        //Set rendering space and render to screen
        SDL_Rect renderQuad = { x, y, mWidth, mHeight };

        //Set clip rendering dimensions
        if( clip != NULL )
        {
                renderQuad.w = clip->w;
                renderQuad.h = clip->h;
        }

        //Render to screen
        SDL_RenderCopy( gRenderer, mTexture, clip, &renderQuad );
}

然后他调用他的 render() 从 spritesheet 中绘制图像:

//Clear screen
SDL_SetRenderDrawColor( gRenderer, 0xFF, 0xFF, 0xFF, 0xFF );
SDL_RenderClear( gRenderer );

//Render top left sprite
gSpriteSheetTexture.render( 0, 0, &gSpriteClips[ 0 ] );

//Render top right sprite
gSpriteSheetTexture.render( SCREEN_WIDTH - gSpriteClips[ 1 ].w, 0, &gSpriteClips[ 1 ] );

//Render bottom left sprite
gSpriteSheetTexture.render( 0, SCREEN_HEIGHT - gSpriteClips[ 2 ].h, &gSpriteClips[ 2 ] );

//Render bottom right sprite
gSpriteSheetTexture.render( SCREEN_WIDTH - gSpriteClips[ 3 ].w, SCREEN_HEIGHT - gSpriteClips[ 3 ].h, &gSpriteClips[ 3 ] );

//Update screen
SDL_RenderPresent( gRenderer );

我明白发生了什么,但现在我不能使用 sdl 渲染器,我该如何完成同样的事情?我现在不能使用任何 SDL2 绘图功能吗?我是否只使用原始 opengl 调用,并且只使用 SDL 进行键盘绑定?

基本上,如果我不能使用 SDL Renderer,我不明白如何使用 SDL2 来绘制东西(比如在精灵示例中),因为它似乎与我正在使用的 gui 库不兼容,它使用opengl 调用渲染。

Can I not use any SDL2 drawing functions now? Do I only use raw opengl calls, and only use SDL for keyboard bindings?

正确。

为了直接使用 OpenGL API,必须使用标志 SDL_WINDOW_OPENGL 创建 SDL window,并为其创建一个新的 OpenGL 上下文:

auto window = SDL_CreateWindow("Window name",
                 SDL_WINDOWPOS_UNDEFINED,
                 SDL_WINDOWPOS_UNDEFINED,
                 width, height, SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN);
auto context = SDL_GL_CreateContext(window);

如果成功,将像在任何其他上下文处理程序中一样简单地执行对 OpenGL 的调用。问题中链接的同一个网站提供了将 OpenGL 与 SDL 2 结合使用的教程,两者都 legacy and modern。请注意,两者中的 none 涉及创建 SDL 渲染器。 事实上,使用它是不合适的,因为两个 API 是相互排斥的:您应该使用一个或另一个。 快速解释了为什么你不应该混合使用它们。

尽管如此,有一些方法可以使用 OpenGL 从某些 SDLRenderer 调用中获得相同的输出(因为相同的渲染器具有 OpenGL 实现!),但这自然会因具体情况而异.想画一个简单的矩形?遗留 glBeginglEnd 方法可能就足够了。想画精灵吗?您必须先将其发送到 OpenGL 设备的内存中。一旦了解了 OpenGL 的基本原理,通常就可以制作合适的包装层。 如果您想使用现有的依赖 OpenGL 的库,替换其他绘图程序以使用此 API(或 GLU 等实用程序库)是正确的方法。

另请注意,SDL 渲染器不必依赖 OpenGL(它可能在 Windows 上使用 Direct3D)。

如果我了解到您想知道如何在不使用 SDL 函数的情况下渲染到 SDL 屏幕,那么您想使用 opengl 函数。 SDL 支持 opengl,要使用 SDL 使用 opengl 渲染事物,您必须遵循以下最少步骤:在创建 window 之前调用 SDL_GL_SetAttribute 以设置 OpenGL 属性,然后创建 window使用 SDL_WINDOW_OPENGL 标志,之后您必须创建 opengl 上下文(每个 gl 应用程序都有一个)调用 SDL_GL_CreateContext,请参阅 SDL Wiki 了解我提到的功能:CategoryVideo - SDL Wiki

这里有一段代码作为例子:

void start(SDL_Window** window, SDL_GLContext* gl){
if(SDL_Init(SDL_INIT_VIDEO) < 0){
    throw std::runtime_error(SDL_GetError());
}
//set the gl version to be loaded
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);

*window = SDL_CreateWindow("Widget Tests", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_OPENGL);

if(*window == nullptr){
    throw std::runtime_error(SDL_GetError());
}

//create the opengl context
*gl = SDL_GL_CreateContext(*window);

if(*gl == nullptr){
    throw std::runtime_error(SDL_GetError());
}
}

int main(){
SDL_Window* window;
SDL_GLContext gl;
...

//init sdl and opengl
start(&window, &gl);
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glMatrixMode(GL_PROJECTION_MATRIX);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW_MATRIX);
glLoadIdentity();
glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);

while(running){
    while(SDL_PollEvent(&event)){
        switch(event.type){
            ...
        }
    }
    glClear(GL_COLOR_BUFFER_BIT);

    //... draw calls with opengl

    SDL_GL_SwapWindow(window);//update the window
}
}