如果我用OpenGL绘图的话SDL Renderer就没用了吗?

问题描述 投票:0回答:4

我正在学习 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 渲染器,我不明白如何使用 SDL2 来绘制东西(就像在精灵示例中),因为它似乎与我正在使用的 GUI 库不兼容,它使用 OpenGL 调用进行渲染。

c++ opengl sdl-2 opengl-3
4个回答
14
投票

我现在不能使用任何SDL2绘图功能吗?我是否只使用原始 opengl 调用,并且只使用 SDL 进行键盘绑定?

正确。

为了直接使用 OpenGL API,必须使用标志

SDL_WINDOW_OPENGL
创建 SDL 窗口,并为其创建一个新的 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 的教程,包括legacymodern。请注意,两者都不涉及创建 SDL 渲染器。 事实上,使用它是不合适的,因为这两个 API 是互斥的:您应该使用其中之一。 这个答案快速解释了为什么你不应该混合它们。

尽管如此,有一些方法可以使用 OpenGL 从某些 SDLRenderer 调用中实现相同的输出(因为相同的渲染器具有 OpenGL 实现!),但这自然是特定于具体情况的。想画一个简单的矩形吗?传统的

glBegin
glEnd
方法可能就足够了。想画精灵吗?您必须首先将其发送到 OpenGL 设备的内存。一旦了解了 OpenGL 的相关知识,制作合适的包装层通常是合适的。 如果您想使用依赖于 OpenGL 的现有库,替换其他绘图程序以使用此 API(或实用程序库,例如 GLU)是正确的方法。

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


1
投票

如果我理解您想知道如何在不使用 SDL 函数的情况下渲染到 SDL 屏幕,那么您想使用 opengl 函数。 SDL 支持 opengl,要使用 SDL 使用 opengl 渲染内容,您必须遵循以下最低步骤:在创建窗口之前,调用

SDL_GL_SetAttribute
来设置 OpenGL 属性,然后使用
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
}
}

0
投票

自 2021 年 10 月 12 日起 亲爱的 ImGui 现在正式支持 SDL_Renderer 后端 您需要版本 >= 1.85 且 SDL 版本 >= 2.0.18+

如果您想遵循基于 SDL_Renderer 的教程,请使用它。

另外作为一个技术问题,如果您使用 OpenGL 后端,您仍然可以使用 SDL_Renderer 渲染到离屏渲染目标,然后将其作为 OpenGL 纹理上传到 OpenGL。 Dear ImGui 通过精确地执行此一般过程来提供多个后端。

或者,您可以直接写入 OpenGL 帧缓冲区(不需要纹理)。对于初学者教程,只需使用 >v1.85 和 SDL_Renderer 即可。


0
投票

由于您使用的是 ImGui,因此您不需要为 2D 游戏使用 SDL 渲染器或 OpenGL 绘图函数。 ImGui 有适合您的功能。这就是您使用 ImGui 的原因,对吗?制作一个全屏窗口并获取其绘制列表,并使用

AddImage()
等功能来绘制图像。有关其他类似功能,请参阅 imgui.h。

// Create a full screen window  
ImGuiIO& io = ImGui::GetIO();
const ImGuiWindowFlags mainFlags = ImGuiWindowFlags_NoResize
        | ImGuiWindowFlags_NoCollapse
        | ImGuiWindowFlags_NoTitleBar
        | ImGuiWindowFlags_NoScrollbar
        | ImGuiWindowFlags_NoBackground
        | ImGuiWindowFlags_NoMove
        | ImGuiWindowFlags_NoSavedSettings
        | ImGuiWindowFlags_NoBringToFrontOnFocus;

ImGui::SetNextWindowPos(ImVec2(0.0, 0.0));
ImGui::SetNextWindowSize(ImVec2(io.DisplaySize.x, io.DisplaySize.y));
ImGui::Begin("Game scene", NULL, mainFlags);

// Get draw list
ImDrawList* draw_list = ImGui::GetWindowDrawList();

// Get viewport
ImVec2 canvasViewportStart = ImGui::GetCursorScreenPos();

// Load texture (to be implemented by you)
auto texture = loadTexture("texture.png");

// Draw the texture
draw_list->AddImage(texture, ImVec2(canvasViewportStart.x, canvasViewportStart.y), ImVec2(canvasViewportStart.x + 32, canvasViewportStart.y + 32));

// Handle mouse input
if (ImGui::IsWindowHovered()) {
    const ImVec2 mousePosAbs = ImGui::GetMousePos();
    const ImVec2 mousePos = ImVec2(mousePosAbs.x - canvasViewportStart.x, mousePosAbs.y - canvasViewportStart.y);
    
    if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
        // ...
    }
}                   

ImGui::End();

// Create other windows, call ImGui::Render()

如果您想直接使用 OpenGL 绘图函数(也许是 3D 游戏),那也是可能的。在这种情况下,您不应为场景创建 ImGui 窗口。在渲染 ImGui 窗口之前渲染场景。将代码放在 ImGui OpenGL 示例中的渲染调用之间:

ImGui::Render();

// Clear the screen
ImGuiIO& io = ImGui::GetIO();
glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y);
glClearColor(0, 0, 0, 255);
glClear(GL_COLOR_BUFFER_BIT);

// Render your own game scene here
// Note: You don't need this if you are using ImGui draw functions

// Render ImGui windows
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
SDL_GL_SwapWindow(window);
© www.soinside.com 2019 - 2024. All rights reserved.