C SDL2-是否有可能消除一些抽象层?

C SDL2- is it possible to eliminate some of the abstraction layers?

我一直在尝试学习如何将 SDL 库与 C(而非 C++)一起使用,最近发现我遇到所有错误的原因是我在看 SDL1 教程,而不是 SDL2教程。从那以后,我发现 SDL2 已经实现了许多抽象层(据我所知),而 SDL1 似乎无法绕过这些抽象层。

具体而言,在 SDL1 中,在屏幕上绘制一组像素是通过以下方式完成的:

定义表面 - 找到像素的 rgb 值 - 在表面上绘制像素 - 在屏幕上绘制表面

在 SDL2 中,它似乎是由以下人员完成的:

定义 window - 为 window 创建渲染器 - 创建表面 - 找到像素的 rgb 值 - 将像素绘制到表面 - 将表面转换为纹理 - 将纹理发送到渲染器 - 重绘 window

虽然我理解纹理如何成为一种更简单的处理方式,但如果涉及原始像素数据以外的其他内容,尤其是当数据有多个来源时,在特定情况下我想将其用于 (单个 window 程序,其中原始像素数据是唯一会被绘制的东西)window、渲染器和纹理之间的区别只是毫无意义的抽象。此外,似乎在大多数情况下,来自图像的数据将被加载到 SDL_Surface class,然后必须将其转换为纹理,从而添加更多不必要的抽象。

除了恢复到旧版本的 SDL 之外,还有什么方法可以避免这种情况吗?

当我开始使用 SDL2 时,我也有同样的想法。

首先,它可能不清楚,因为你没有探索很多 SDL2,但即使你不想做 OGL/DX,这些额外的层对纯 2D 和像素处理也很有用.


例如,SDL_RenderCopyEx 可以在动态旋转和调整表面大小的同时渲染表面。在 SDL1 中,您需要使用第三方库或编写您自己的旋转缩放算法来实现相同的目的。

另一个有用的功能是您可以轻松渲染图元。例如,有一个优化的 SDL_RenderDrawLine 方法,在 SDL1 中,您需要构建自己的方法来创建表面、浏览和 blit 像素信息,然后将线 blit 回您的整个表面。

还有很多其他的方法,我相信你会在给定的时间发现,比如颜色调制。


下一点是您认为 SDL1 更底层,'realistic' 并且 SDL2 添加了一些额外的层。事实上,现代图形卡的工作方式与 SDL2 一样。通常,你不会在内存中存储一​​个巨大的位图(SDL_Surfaces 是原始数据),你不会将一些其他表面 blit 到它,然后将它发送到图形卡。显卡正在考虑纹理


现在,如果您仍然想绕过这些 "additional layers",您仍然可以通过隔离纹理渲染过程。我认为实现这一点的最干净的方法是创建一个要 blit 的表面的链接列表:

struct SurfaceElement {
   SDL_Surface* s;
   SDL_Rect clip;
   SDL_Rect position;
   struct SurfaceElement * next;
};

typedef struct SurfaceElement SurfaceElement;

void ProcessingLoop() {
    SurfaceElement *surfacesList = (SurfaceElement *)malloc(sizeof(SurfaceElement));

    // Create surfaces, work on surfaces
    // When you're done with a surface, add it to the list:
    surfacesList =  AddToBlitList(yourSurface, yourClipPos, yourBlitPos, surfacesList);

    // When everything is okay and you're ready to blit:
    TextureBlittingProcess(surfacesList, renderer);
}

SurfaceElement* AddToBlitList(SDL_Surface *s, SDL_Rect clip, SDL_Rect position, SurfaceElement *head)   {
    SurfaceElement *current = (SurfaceElement*)malloc(sizeof(SurfaceElement));
    current->s = s;
    current->clip = clip;
    current->position = position;
    current->next = head;
    return current;
}

void TextureBlittingProcess(SurfaceElement *surfacesList, SDL_Renderer *renderer)   {
    while (surfaceList) {
        SDL_Texture *t = SDL_CreateTextureFromSurface(renderer, surfaceList->s)
        SDL_RenderCopy(renderer, t, &(surfaceList->clip), &(surfaceList->position));
        surfaceList = surfaceList->next;
    }
}

最后,如果您真的看不到使用这些纹理的意义,如果您不一定要对纹理进行 blit,而只是对其像素进行操作,那么 SDL 可能不适合您。您应该阅读有关 Matlab 或 Python 或 Caml 等脚本语言的信息。

通过 SDL_GetWindowSurface()SDL_BlitSurface() 抓住你的 window 的 SDL_Surface,尽情享受吧。不要忘记 SDL_UpdateWindowSurface() 当你完成 blitting 将更新的帧缓冲区推回到 OS.

有个usage example right on the SDL_GetWindowSurface() wiki page:

#include "SDL.h" // include SDL header

int main(int argc, char* argv[])
{
    SDL_Surface *screen; // even with SDL2, we can still bring ancient code back
    SDL_Window *window;
    SDL_Surface *image;

    SDL_Init(SDL_INIT_VIDEO); // init video

    // create the window like normal
    window = SDL_CreateWindow("SDL2 Example", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, 0);

    // but instead of creating a renderer, we can draw directly to the screen
    screen = SDL_GetWindowSurface(window);

    // let's just show some classic code for reference
    image = SDL_LoadBMP("box.bmp"); // loads image
    SDL_BlitSurface(image, NULL, screen, NULL); // blit it to the screen
    SDL_FreeSurface(image);

    // this works just like SDL_Flip() in SDL 1.2
    SDL_UpdateWindowSurface(window);

    // show image for 2 seconds
    SDL_Delay(2000);
    SDL_DestroyWindow(window);
    SDL_Quit();
    return 0;
}