// Standard C++ stuff #include #include #include #include // SDL2 stuff #include "SDL2/SDL.h" // Compile: g++ -std=c++20 -Wall -Wextra -pedantic -Ofast SDL2Plasma.cpp -o SDL2Plasma -lSDL2 -fopenmp struct RGB { int Red, Green, Blue; }; RGB HSBToRGB(const double hue, const double saturation, const double brightness) { double Red = 0, Green = 0, Blue = 0; if (hue == 1) { Red = brightness; } else { double Sector = hue * 360, Cosine = std::cos(Sector*std::numbers::pi/180), Sine = std::sin(Sector*std::numbers::pi/180); Red = brightness * Cosine + saturation * Sine; Green = brightness * Cosine - saturation * Sine; Blue = brightness - saturation * Cosine; } RGB Result; Result.Red = (int)(Red * 255); Result.Green = (int)(Green * 255); Result.Blue = (int)(Blue * 255); return Result; } template void CalculatePlasma(std::array, height_array_length> &array) { #pragma omp parallel for for (unsigned long y = 0; y < array.size(); y++) #pragma omp simd for (unsigned long x = 0; x < array.at(0).size(); x++) { // Calculate the hue double Hue = std::sin(x/16.0); Hue += std::sin(y/8.0); Hue += std::sin((x+y)/16.0); Hue += std::sin(std::sqrt(x*x+y*y)/8.0); Hue += 4; // Clamp the hue to the range of [0, 1] Hue /= 8; array[y][x] = Hue; } } template void DrawPlasma(SDL_Renderer *r, const std::array, height_array_length> &array, const double &hue_shift) { for (unsigned long y = 0; y < array.size(); y++) for (unsigned long x = 0; x < array.at(0).size(); x++) { // Convert the HSB value to RGB value double Hue = hue_shift + std::fmod(array[y][x], 1); RGB CurrentColour = HSBToRGB(Hue, 1, 1); // Draw the actual plasma SDL_SetRenderDrawColor(r, CurrentColour.Red, CurrentColour.Green, CurrentColour.Blue, 0xff); SDL_RenderDrawPoint(r, x, y); } } int main() { const unsigned DefaultWidth = 640, DefaultHeight = 640; std::array, DefaultHeight> ScreenArray; SDL_Window *Window = NULL; // Define window SDL_Renderer *Renderer = NULL; // Define renderer // Init everything just for sure SDL_Init(SDL_INIT_EVERYTHING); // Set window size to 640x640, always shown Window = SDL_CreateWindow("Plasma effect", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, DefaultWidth, DefaultHeight, SDL_WINDOW_SHOWN); Renderer = SDL_CreateRenderer(Window, -1, SDL_RENDERER_ACCELERATED); // Set background colour to white SDL_SetRenderDrawColor(Renderer, 0xff, 0xff, 0xff, 0xff); SDL_RenderClear(Renderer); // Create an event handler and a "quit" flag SDL_Event e; bool KillWindow = false; CalculatePlasma(ScreenArray); double HueShift = 0.0; // The window runs until the "quit" flag is set to true while (!KillWindow) { while (SDL_PollEvent(&e) != 0) { // Go through the events in the queue switch (e.type) { // Event: user hits a key case SDL_QUIT: case SDL_KEYDOWN: // Destroy window KillWindow = true; break; } } // Render the plasma DrawPlasma(Renderer, ScreenArray, HueShift); SDL_RenderPresent(Renderer); if (HueShift < 1) { HueShift = std::fmod(HueShift + 0.0025, 3); } else { CalculatePlasma(ScreenArray); HueShift = 0.0; } } // Destroy renderer and window SDL_DestroyRenderer(Renderer); SDL_DestroyWindow(Window); SDL_Quit(); return 0; }