【问题标题】:How to sync SDL window with terminal?如何将 SDL 窗口与终端同步?
【发布时间】:2021-08-10 21:33:48
【问题描述】:

我正在尝试创建一个响应控制台输入的 SDL 窗口。我读了这个question,下面是我到目前为止尝试过的。

/* 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 窗口相互同步而不会出现问题?

【问题讨论】:

  • SDL_WaitThread(thread, &amp;cmd); 执行阻塞操作 - 这意味着在您获得输入并且线程终止之前,您的代码中不会发生任何其他事情,从而使线程无用。您需要在单独的线程上处理所有控制台输入,就像在您链接的问题中完成的那样

标签: c++ c sdl sdl-2


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

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

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;
}

【讨论】:

    【解决方案2】:

    供日后参考

    /* 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;
    
    SDL_atomic_t active;
    
    int inputLoop(void *a)
    {
        int in = 2;
    
        while (in != 1)
        {
            cout << ">> ";
            cin >> in;
            SDL_AtomicSet(&active, in);
        }
    
        return 0;
    }
    
    int main()
    {
        srand(unsigned(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);
        SDL_Event event;
        bool quit = false;
    
        cout << "Inputs: 0 (rerender); 1 (quit the program)" << endl;
        
        SDL_AtomicSet(&active, 2);
        SDL_CreateThread(inputLoop, "InputThread", (void*) NULL);
    
        while (!quit)
        {
            while(SDL_PollEvent(&event))
            {
                if(event.type == SDL_QUIT)
                {
                    SDL_AtomicSet(&active, 1);
                    break;
                }
            }
    
            switch (SDL_AtomicGet(&active))
            {
            case 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 = rand() % 256;
                        int g = rand() % 256;
                        int b = 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);
    
                SDL_AtomicSet(&active, 2);
                break;
            }
            case 1: // quit
            {
                quit = true;
                break;
            }
            default: // > 2 - nothing
                break;
            }
        }
    
        SDL_DestroyRenderer(renderer);
        renderer = NULL;
        SDL_DestroyWindow(window);
        window = NULL;
        SDL_Quit();
    
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-02-17
      • 2016-06-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-12
      • 2012-01-21
      相关资源
      最近更新 更多