首页 > 解决方案 > 如何将 SDL 窗口与终端同步?

问题描述

我正在尝试制作一个响应控制台输入的 SDL 窗口。我读了这个问题,以下是我到目前为止所尝试的。

/* g++ test.cpp -o test -lSDL2 */

#include <iostream>
#include <string>
#include <vector>

#include <cstdlib>
#include <ctime>

#define SDL_MAIN_HANDLED

#include <SDL2/SDL.h>
#include <SDL2/SDL_render.h>

using namespace std;

const int width = 160;
const int height = 144;

static int inputThread(void *a)
{
    int in;
    cout << ">> ";
    cin >> in;
    return in;
}

int main()
{
    std::srand(unsigned(std::time(NULL)));

    SDL_Init(SDL_INIT_EVERYTHING);

    SDL_Window* window = SDL_CreateWindow(
        "SDL2",
        SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
        width * 3, height * 3,
        SDL_WINDOW_SHOWN);

    SDL_Renderer* renderer = SDL_CreateRenderer(
        window,
        -1,
        SDL_RENDERER_ACCELERATED);

    SDL_Texture* texture = SDL_CreateTexture(
        renderer,
        SDL_PIXELFORMAT_ARGB8888,
        SDL_TEXTUREACCESS_STREAMING,
        width, height);

    vector<uint8_t> pixels(width * height * 4, 0);

    cout << "0 - rerender; 1 - quit the program" << endl;

    while(true)
    {
        // get input
        SDL_Thread *thread = SDL_CreateThread(inputThread, "InputThread", (void *) NULL);
        int cmd;

        if (thread == NULL) {
            printf("SDL_CreateThread failed: %s\n", SDL_GetError());
        }

        SDL_WaitThread(thread, &cmd);

        if (cmd == 0) // rerender
        {
            SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
            SDL_RenderClear(renderer);

            // splat down some random pixels
            for (int i = 0; i < height; i++)
            {
                for (int j = 0; j < width; j++)
                {
                    int offset = i * width * 4 + j * 4;

                    int r = std::rand() % 256;
                    int g = std::rand() % 256;
                    int b = std::rand() % 256;

                    pixels[offset] = b;
                    pixels[offset + 1] = g;
                    pixels[offset + 2] = r;
                    pixels[offset + 3] = 255;
                }
            }

            SDL_UpdateTexture(
                texture,
                NULL,
                &pixels[0],
                width * 4);

            SDL_RenderCopy(renderer, texture, NULL, NULL);
            SDL_RenderPresent(renderer);
        }
        else if (cmd == 1) // quit
        {
            break;
        }
    }

    SDL_DestroyRenderer(renderer);
    renderer = NULL;
    SDL_DestroyWindow(window);
    window = NULL;
    SDL_Quit();

    return 0;
}

当我运行程序时,SDL 窗口没有响应,有时会崩溃。有什么办法可以改进我的程序,使控制台和 SDL 窗口相互同步而不会出现问题?

标签: c++csdlsdl-2

解决方案


  • 您必须将线程创建排除在循环之外
  • 在(渲染)循环中,不要等待线程完成/终止(阻塞,无响应窗口)
  • 建立一个全局变量,将从主线程读取并由输入线程写入
    • 因此我们必须同步两个线程
    • 这里我们使用原子变量,或者我们可以使用互斥锁

为简单起见,代码被缩短:

SDL_atomic_t active;

int inputThread(void *a)
{
    int in;
    //read from cin into in
    
    //we will set the global var only if in equals to zero
    if (in == 0)
        SDL_AtomicSet(&active, 0);

    return in;
}

int main()
{
    //initial stuff
    
    SDL_AtomicSet(&active, 1);
    SDL_CreateThread(inputThread, "InputThread", (void*) NULL);

    while (SDL_AtomicGet(&active)) {
        //listen to and process sdl events
        //render
    }

    //cleanup

    return 0;
}

推荐阅读