Wasm with emscripten and SDL - 如何只清除部分渲染器

Wasm with emscripten and SDL - How to clear only part of the renderer

我使用 emscripten 和 SDL 创建了一个 Wasm 动画。我现在正在尝试创建一个按钮,用户可以在其中启动和 stop/pause 动画。我遇到的问题是每次迭代都会清除整个 canvas 。如我所见,这里有 3 个选项:

  1. 在每一帧重绘按钮。
  2. 只清除动画在每次迭代中使用的canvas部分。
  3. 输入按钮使用 HTML 形式。

(1) 似乎效率低下。 (3) 将要求我开始在 JS 和 Wasm 之间进行互操作。到目前为止,我已经能够在不编写一行 JS 的情况下构建整个东西,并且更愿意保持这种状态。所以可能 (2) 是最好的。

我知道使用 JS 可以指定 clearRect 调用的尺寸。但是,我在 SDL API 中找不到此功能。

下面是 mainLoop 函数(每秒调用大约 60 次)(如果不清楚,这是用 C 编写的。不是 C++)。我的问题是,如何调整 "SDL_RenderClear" 以便它只清除 canvas 的一半? (有动画的那一半。即不要清除我想制作按钮的那一半。

main.c

#include <stdio.h>
#include <SDL2/SDL.h>
#include <emscripten.h>
#include <stdlib.h>
#include <stdbool.h>

<....>

/**
 * The loop handler, will be called repeatedly
 */
void mainLoop(void *arg) {
    struct Context *ctx = arg;
    printf("iteration: %d\n", ctx->iteration);

    SDL_SetRenderDrawColor(ctx->renderer, 255, 0, 100, 255);
    SDL_RenderClear(ctx->renderer);

    bool running = true;

    if (running) {
        for (int j=1; j<8; j++) {
            for (int i=1; i<130; i++) {
                // drawRect is another app function that calls the SDL to draw a rectangles.
                drawRectangle(ctx, i, j);
            }
        }
    }
    SDL_RenderPresent(ctx->renderer);
    ctx->iteration++;
}

<....>

您可以使用 SDL_RenderFillRect 在不需要的部分上涂漆。但是,除非你做很多诡计,否则它不是很有帮助。

正式原因 - https://wiki.libsdl.org/SDL_RenderPresent 说 "The backbuffer should be considered invalidated after each present; do not assume that previous contents will exist between frames."

在很多情况下,您的缓冲区将(部分)失效,例如将 window 移出屏幕边界。我不知道 webasm,你可能需要检查 webgl 文档,如果有任何关于缓冲区内容的承诺。

即使您可以依赖要保留的内容,但是例如你有双缓冲设置。您已经渲染到第一个缓冲区,执行缓冲区交换 - 现在您有第二个缓冲区,其内容尚未初始化。第二次交换后它可能或多或少相似,但任何变化都会滞后 1 帧。

一些 3d 软件(例如 blender)可以执行您所描述的操作,但即使在那里它也不是 100% 稳定的,通常有一个选项可以禁用该行为。执行完全重绘比您想象的要便宜得多,如果它变得太昂贵 - 您总是可以将屏幕的一部分渲染到渲染纹理中并将其用作单个静态图像,并在必要时更新它。