为什么使用 SDL2 时会出现双图像?

Why is there a double Image when using SDL2?

提问人:Parsa Eslami 提问时间:10/26/2023 更新时间:10/26/2023 访问量:47

问:

我有一个 c++ 的 Mandelbrot 集渲染代码,我正在使用 SDL2 来显示图像。当我想让我的程序具有交互性时,我遇到了一个问题。通过按 W,我的代码应该清除上一个图像并显示一个带有新参数的新图像,但无论我做什么,之前的渲染都不会清除。顺便说一句,我注意到每次按 W 时,我的内存使用量都会更高。我应该如何解决这个问题?

#include <complex>
#include <iostream>
#include <SDL.h>
#include <chrono>
#include <omp.h>
using namespace std;

int main(int argc, char** argv) {
    const int resolution= 2000;

    const int rows = resolution;
    const int cols = resolution;
    complex<long double> position;
    
    int dots[rows][cols];
    for (int i = 0; i < rows; ++i) {
        for (int j = 0; j < cols; ++j) {
            dots[i][j] = 0;
        }
    }
    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        std::cerr << "SDL initialization failed: " << SDL_GetError() << std::endl;
        return 1;
    }

    const int screenWidth = cols * 1; // Adjust the window size as needed
    const int screenHeight = rows * 1;
    SDL_Window* window = SDL_CreateWindow("Mandelbrot set Visualization", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, screenWidth, screenHeight, SDL_WINDOW_SHOWN);
    SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
    SDL_Rect rect;

    long double startx = -2;
    long double endx = 2;
    long double starty = 2;
    long double endy = -2;
    
    long double stepx = (endx - startx) / (cols - 1);
    long double stepy = (endy - starty) / (rows - 1);

    rect.w = screenWidth / cols;
    rect.h = screenHeight / rows;

    int numThreads = 16;
    omp_set_num_threads(numThreads);

    #pragma omp parallel
    {
        int threadID = omp_get_thread_num(); // Get the thread ID

    #pragma omp for
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                long double real = startx + j * stepx;
                long double imag = starty + i * stepy;
                position = complex<long double>(real, imag);
                complex<long double> iterate(0, 0);
                int color = 0;
                for (int n = 0; n < 256; n++) {
                    iterate = iterate * iterate + position;
                    color++;
                    if (abs(iterate) > 2) {
                        dots[i][j] = color;
                        break;
                    }
                }
            }
        }
    }
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {

            SDL_SetRenderDrawColor(renderer, 0, dots[i][j], dots[i][j], 255); 


            rect.x = j * (screenWidth / cols);
            rect.y = i * (screenHeight / rows);
            SDL_RenderFillRect(renderer, &rect);
        }
    }
    SDL_RenderPresent(renderer);



    // Main game loop
    bool quit = false;
    SDL_Event event;
    while (!quit) {
        while (SDL_PollEvent(&event)) {
            if (event.type == SDL_QUIT) {
                quit = true;
            }
            else if (event.type == SDL_KEYDOWN) {
                if (event.key.keysym.sym == SDLK_w) {
                    // Zoom or change parameters, as needed
                    cout << "loop start";
                    SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
                    SDL_RenderClear(renderer);
                    long double decreaseAmountx = (abs(endx) + abs(startx)) / 20;
                    long double decreaseAmounty = (abs(endy) + abs(starty)) / 20;
                    endx -= decreaseAmountx;
                    startx += decreaseAmountx;
                    endy += decreaseAmounty;
                    starty -= decreaseAmounty;
                    stepx = (endx - startx) / (cols - 1);
                    stepy = (endy - starty) / (rows - 1);
                    // Render the Mandelbrot set with new parameters
                    #pragma omp parallel
                    {
                        int threadID = omp_get_thread_num(); // Get the thread ID

                        #pragma omp for
                        for (int i = 0; i < rows; i++) {
                            for (int j = 0; j < cols; j++) {
                                long double real = startx + j * stepx;
                                long double imag = starty + i * stepy;
                                position = complex<long double>(real, imag);
                                complex<long double> iterate(0, 0);
                                int color = 0;
                                for (int n = 0; n < 256; n++) {
                                    iterate = iterate * iterate + position;
                                    color++;
                                    if (abs(iterate) > 2) {
                                        dots[i][j] = color;
                                        break;
                                    }
                                }
                            }
                        }
                    }
                    for (int i = 0; i < rows; i++) {
                        for (int j = 0; j < cols; j++) {

                            SDL_SetRenderDrawColor(renderer, 0, dots[i][j], dots[i][j], 255); 


                            rect.x = j * (screenWidth / cols);
                            rect.y = i * (screenHeight / rows);
                            SDL_RenderFillRect(renderer, &rect);
                        }
                    }
                    cout << "Present";
                    SDL_RenderPresent(renderer);
                    

                }
                else if (event.key.keysym.sym == SDLK_r) {
                    // Trigger an SDL_QUIT event to exit the application
                    SDL_Event quitEvent;
                    quitEvent.type = SDL_QUIT;
                    SDL_PushEvent(&quitEvent);
                }
            }
        }
    }

    // Cleanup and quit
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();
    return 0;
}

在代码中按 W 的结果

C++ 渲染 SDL-2 Mandelbrot OMP

评论

1赞 Ted Lyngmo 10/26/2023
不相关:您在堆栈上分配了一个巨大的数组。对我来说,这会导致堆栈溢出。我用它代替了它。int dots[rows][cols];auto dots = std::make_unique<int[][cols]>(rows);

答:

0赞 Ted Lyngmo 10/26/2023 #1

问题出在现有数组中分配新值的循环中。dots

for (int i = 0; i < rows; i++) {
    for (int j = 0; j < cols; j++) {
        long double real = startx + j * stepx;
        long double imag = starty + i * stepy;
        position = complex<long double>(real, imag);
        complex<long double> iterate(0, 0);
        int color = 0;
        for (int n = 0; n < 256; n++) {
            iterate = iterate * iterate + position;
            color++;
            if (abs(iterate) > 2) {
                dots[i][j] = color;                    // <- here
                break;
            }
        }
    }
}

旧值仍在数组中,因此您将获得叠加效果。

首先,我建议不要在堆栈上分配巨大的数组,而是在堆上分配。并非所有环境都允许您在堆栈上分配这么多。只

#include <algorithm>
#include <vector>

并替换为int dots[rows][cols];

std::vector<int[cols]> dots(rows);

然后,为了验证我的理论,我在上面的重新缩放循环之前清除了:dots

std::for_each(dots.begin(), dots.end(),
              [](auto& inner) {
                  std::fill(std::begin(inner), std::end(inner), 0);
              });

或者使用执行策略来更快地清除它:

#include <execution>
//...
std::for_each(std::execution::par, dots.begin(), dots.end(),
              [](auto& inner) {
                  std::fill(std::begin(inner), std::end(inner), 0);
              });

通过这些更改,它可以正确地重新绘制。您还可以使用并行执行策略(或 )将清除与绘图结合起来。使用标准执行策略时,它可能如下所示:

std::for_each(std::execution::par_unseq, dots.begin(), dots.end(),
    [&](auto& inner) {
        // clear this row first:
        std::fill(std::begin(inner), std::end(inner), 0);

        auto i = std::distance(dots.data(), &inner);
        long double imag = starty + i * stepy;

        for(int j = 0; j < cols; j++) {
            long double real = startx + j * stepx;
            position = complex<long double>(real, imag);
            complex<long double> iterate(0, 0);
            int color = 0;
            for(int n = 0; n < 256; n++) {
                iterate = iterate * iterate + position;
                color++;
                if(abs(iterate) > 2) {
                    inner[j] = color;
                    break;
                }
            }
        }
    });