Skip to content

Instantly share code, notes, and snippets.

@KatsumiKougen
Last active August 9, 2023 08:13
Show Gist options
  • Save KatsumiKougen/7899840cd661e3c236314eaa1c9fd5ca to your computer and use it in GitHub Desktop.
Save KatsumiKougen/7899840cd661e3c236314eaa1c9fd5ca to your computer and use it in GitHub Desktop.
// Standard C++ stuff
#include <iostream>
#include <array>
#include <cmath>
#include <numbers>
// 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 <int width_array_length, int height_array_length>
void CalculatePlasma(std::array<std::array<double, width_array_length>, 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 <int width_array_length, int height_array_length>
void DrawPlasma(SDL_Renderer *r, const std::array<std::array<double, width_array_length>, 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<std::array<double, DefaultWidth>, 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<DefaultWidth, DefaultHeight>(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<DefaultWidth, DefaultHeight>(Renderer, ScreenArray, HueShift);
SDL_RenderPresent(Renderer);
if (HueShift < 1) {
HueShift = std::fmod(HueShift + 0.0025, 3);
} else {
CalculatePlasma<DefaultWidth, DefaultHeight>(ScreenArray);
HueShift = 0.025;
}
}
// Destroy renderer and window
SDL_DestroyRenderer(Renderer);
SDL_DestroyWindow(Window);
SDL_Quit();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment