【问题标题】:SDL2 doesn't render multiple viewportsSDL2 不呈现多个视口
【发布时间】:2020-05-17 12:48:42
【问题描述】:

我正在学习 Lazy Foo 的 SDL2 教程,但一直在尝试渲染多个 viewports。想法是将PNG作为纹理加载,为3个不同的视口(左上、右上、下)创建SDL_Rect结构,然后将纹理复制到每个视口,最后渲染所有3个视口。我的代码只渲染第一个视口。

我已尝试更改顺序 - 在每种情况下,首先定义的视口都是唯一呈现的视口。

我还尝试更改视口尺寸,以防重叠是问题 - 同样的问题。

我发现的关于多个视口的唯一question 并没有为我指明正确的方向。但这确实让我开始思考——我的代码是用 C 编写的,教程是用 C++ 编写的。虽然我认为我翻译的一切都正确(其他课程工作正常),但也许我在这里遗漏了一些明显的东西?

我正在使用 CFLAGS = -Wall -Wextra -pedantic -std=c99 进行编译 - 没有警告或错误。

编辑:我尝试渲染填充的矩形而不是加载的 PNG,但问题是一样的 - 只有第一个渲染。

这是我的代码:

#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <stdio.h>

#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480

int init_renderer();
int load_media();
SDL_Texture *load_texture(char *);
void close_renderer();

SDL_Window *g_window = NULL;
SDL_Renderer *g_renderer = NULL;
SDL_Texture *g_texture = NULL;

int main()
{
  if (init_renderer() != 1) {
    return -1;
  }

  if (!SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1")) {
    printf("Warning: Linear texture filtering not enabled!\n");
  }

  if (load_media() != 1) {
    return -1;
  }

  int quit = 0;
  SDL_Event e;
  while (quit != 1) {
    while (SDL_PollEvent(&e) != 0) {
      if (e.type == SDL_QUIT || e.key.keysym.sym == SDLK_q) {
        quit = 1;
      }
    }

    SDL_SetRenderDrawColor(g_renderer, 0xff, 0xff, 0xff, 0xff);
    SDL_RenderClear(g_renderer);

    SDL_Rect top_left_vp;
    top_left_vp.x = 0;
    top_left_vp.y = 0;
    top_left_vp.w = SCREEN_WIDTH / 2;
    top_left_vp.h = SCREEN_HEIGHT / 2;
    SDL_RenderSetViewport(g_renderer, &top_left_vp);
    SDL_RenderCopy(g_renderer, g_texture, NULL, NULL);

    SDL_Rect top_right_vp;
    top_right_vp.x = SCREEN_WIDTH / 2;
    top_right_vp.y = 0;
    top_right_vp.w = SCREEN_WIDTH / 2;
    top_right_vp.h = SCREEN_HEIGHT / 2;
    SDL_RenderSetViewport(g_renderer, &top_right_vp);
    SDL_RenderCopy(g_renderer, g_texture, NULL, NULL);

    SDL_Rect bottom_vp;
    bottom_vp.x = 0;
    bottom_vp.y = SCREEN_HEIGHT / 2;
    bottom_vp.w = SCREEN_WIDTH;
    bottom_vp.h = SCREEN_HEIGHT / 2;
    SDL_RenderSetViewport(g_renderer, &bottom_vp);
    SDL_RenderCopy(g_renderer, g_texture, NULL, NULL);

    SDL_RenderPresent(g_renderer);
  }

  close_renderer();

  return 0;
}

int init_renderer()
{
  if (SDL_Init(SDL_INIT_VIDEO) < 0) {
    printf("Failed to initialize SDL. Error: %s\n", SDL_GetError());
    return 0;
  }

  g_window = SDL_CreateWindow("SDL Tuts",
                              SDL_WINDOWPOS_UNDEFINED,
                              SDL_WINDOWPOS_UNDEFINED,
                              SCREEN_WIDTH,
                              SCREEN_HEIGHT,
                              SDL_WINDOW_SHOWN);

  if (g_window == NULL) {
    printf("Failed to create window. Error: %s\n", SDL_GetError());
    return 0;
  }

  g_renderer = SDL_CreateRenderer(g_window, -1, SDL_RENDERER_ACCELERATED);
  if (g_renderer == NULL) {
    printf("Failed to create renderer. Error: %s\n", SDL_GetError());
    return 0;
  }

  SDL_SetRenderDrawColor(g_renderer, 0x29, 0xAB, 0x87, 0xFF);

  int img_flags = IMG_INIT_PNG;
  if (!(IMG_Init(img_flags) & img_flags)) {
    printf("Failed to initialize SDL Image. SDL_Image Error: %s\n", IMG_GetError());
    return 0;
  }

  return 1;
}

int load_media()
{
  g_texture = load_texture("assets/texture.png");
  if (g_texture == NULL) {
    return 0;
  }

  return 1;
}

SDL_Texture *load_texture(char *path)
{
  SDL_Texture *new_texture = NULL;
  SDL_Surface *loaded_surface = IMG_Load(path);
  if (loaded_surface == NULL) {
    printf("Failed to load image. SDL_Image Error: %s\n", IMG_GetError());
  } else {
    new_texture = SDL_CreateTextureFromSurface(g_renderer, loaded_surface);
    if (new_texture == NULL) {
      printf("Failed to create texture from %s. Error: %s\n", path, SDL_GetError());
    }

    SDL_FreeSurface(loaded_surface);
  }

  return new_texture;
}

void close_renderer()
{
  SDL_DestroyTexture(g_texture);
  g_texture = NULL;

  SDL_DestroyRenderer(g_renderer);
  SDL_DestroyWindow(g_window);
  g_renderer = NULL;
  g_window = NULL;

  IMG_Quit();
  SDL_Quit();
}

【问题讨论】:

  • 所有这些 SDL_* 函数都是同步的吗?渲染最后一个窗口后,您将立即退出 main。可能是在后台线程上进行渲染并且您的进程在所有排队的工作完成之前退出?
  • @jwdonahue 好问题。我认为因为渲染被包裹在while 循环中,只有当用户按下Q 或退出程序时才会中断,它应该允许所有渲染完成。
  • @red.connors 没错。您已经将所有内容渲染到屏幕并呈现了屏幕,因此只要 while 循环不关闭,线程处理渲染就会在主线程关闭之前完成。
  • 我想我可能会提交错误报告。如果我这样做,我会留下一个链接
  • 原来这已经被报道了。 bugzilla.libsdl.org/show_bug.cgi?id=4960

标签: c sdl sdl-2


【解决方案1】:

要检查更多错误,您应该查看对SDL_RenderSetViewPort 的调用返回了什么。根据the docs,它返回一个int,成功时为0,如果出错则为负int。 SDL 中更深层次的东西完全有可能适合。

其他专业提示:您可以在 while 循环之外定义 SDL_Rect 结构,以节省处理能力的微小余量。为了省去一些输入,您可以使用列表构造函数初始化 SDL_Rect,而不是手动打孔每个属性。例如:

SDL_Rect top_left_vp;
top_left_vp.x = 0;
top_left_vp.y = 0;
top_left_vp.w = SCREEN_WIDTH / 2;
top_left_vp.h = SCREEN_HEIGHT / 2;

更简单

SDL_Rect top_left_vp = {
    0,
    0,
    SCREEN_WIDTH / 2,
    SCREEN_HEIGHT / 2
};

【讨论】:

  • 感谢您的建议。不幸的是,在调用 SDL_RenderSetViewport 或任何其他非 void SDL 函数时,我没有收到任何错误。并感谢专业提示!
  • @red.connors 在这种情况下,我想尝试的下一件事是在调用 RenderPresent 之前将视口设置为 NULL。我半信半疑这是问题所在,但在修补后清理它们也是一种好习惯。
  • 我使用SDL_RenderSetViewport(g_renderer, NULL); 将视口设置为NULL,但它没有改变任何东西。很好的清理工作,不过
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多