added trail effect

This commit is contained in:
2025-01-31 14:09:33 -05:00
parent 07c970749f
commit 27dd9b3639

101
main.cpp
View File

@@ -1,5 +1,5 @@
// ReWalker
// A random walker that moves around the screen
// A random walker that moves around the screen with a fading trail.
// Written using Redacted ReWindow https://git.redacted.cc/Redacted/ReWindow
// Written by Rich
// With help from (and thanks to) from Maxine, Josh and Bill
@@ -11,14 +11,18 @@
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <vector>
// Define window size and dot size (dot size should be odd for symmetry)
#define WIDTH 800
#define HEIGHT 600
#define DOT_SIZE 5
// Define fading speed (higher = faster fading, range: 0.001 - 0.2)
#define FADE_SPEED 0.01f
// Enable debug mode (set to 0 to disable debug output)
#define DEBUG 1
#define DEBUG 0
/**
* @brief Represents the walker that moves randomly on the screen.
@@ -33,9 +37,6 @@ struct Walker {
/**
* @brief Moves the walker one step in a random direction.
*
* Uses a random angle (0-360 degrees) to determine movement direction.
* Ensures the walker stays within the screen bounds using std::clamp.
*/
void step() {
float angle = static_cast<float>(rand()) / RAND_MAX * 360.0f;
@@ -47,7 +48,6 @@ struct Walker {
x = std::clamp(x + dx, 0.0f, static_cast<float>(WIDTH - 1));
y = std::clamp(y + dy, 0.0f, static_cast<float>(HEIGHT - 1));
// Debugging: Print walker's position if debug mode is enabled
#if DEBUG
std::cout << "Walker Position: (" << x << ", " << y << ")\n";
#endif
@@ -60,19 +60,20 @@ struct Walker {
class RandomWalkerWindow : public ReWindow::RWindow {
public:
/**
* @brief Constructor initializes the window and walker.
* @brief Constructor initializes the window, walker, and trail buffer.
* @param title Window title
* @param width Window width
* @param height Window height
*/
RandomWalkerWindow(const std::string& title, int width, int height)
: ReWindow::RWindow(title, width, height), walker(std::make_unique<Walker>()) {}
: ReWindow::RWindow(title, width, height),
walker(std::make_unique<Walker>()),
trailBuffer(WIDTH * HEIGHT, 1.0f) // Initialize trail buffer to white (1.0)
{}
/**
* @brief Called once when the window is opened.
*
* Configures OpenGL to use a 2D orthographic projection
* so that pixel coordinates match OpenGL coordinates.
* Configures OpenGL to use a 2D orthographic projection.
*/
void OnOpen() override {
glMatrixMode(GL_PROJECTION);
@@ -82,50 +83,74 @@ public:
}
/**
* @brief Called every frame to update and render the walker.
*
* Clears the screen, moves the walker, draws it, and swaps buffers.
* @param elapsed Time elapsed since the last frame (not currently used).
* @brief Called every frame to update and render the walker with a fading trail.
*/
void OnRefresh(float elapsed) override {
// Clear the screen to white each frame
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
// Clear the OpenGL buffer (not the trail buffer)
glClear(GL_COLOR_BUFFER_BIT);
// Move the walker in a random direction
// Update trail (fade effect)
fadeTrail();
// Move the walker
walker->step();
// Render the walker on the screen
drawWalker();
// Update the trail buffer with the walker's current position
plotWalker();
// Render the updated trail
drawTrail();
// Swap buffers to display the frame
GLSwapBuffers();
}
private:
std::unique_ptr<Walker> walker; // Unique pointer to manage walker instance
std::unique_ptr<Walker> walker;
std::vector<float> trailBuffer; // Stores grayscale intensity of pixels (1.0 = white, 0.0 = black)
/**
* @brief Draws the walker as a black square on the screen.
*
* Uses OpenGL `GL_QUADS` to draw a filled square at the walkers position.
* @brief Applies the fade effect to the trail buffer.
* Each pixel brightness gradually increases toward 1.0 (white).
*/
void drawWalker() {
float halfSize = DOT_SIZE / 2.0f;
float left = walker->x - halfSize;
float right = walker->x + halfSize;
float top = walker->y - halfSize;
float bottom = walker->y + halfSize;
void fadeTrail() {
for (auto& pixel : trailBuffer) {
pixel = std::min(pixel + FADE_SPEED, 1.0f); // Ensure value does not exceed 1.0 (white)
}
}
glColor3f(0.0f, 0.0f, 0.0f); // Set color to black
/**
* @brief Plots the walker current position as a black dot in the trail buffer.
*/
void plotWalker() {
int centerX = static_cast<int>(walker->x);
int centerY = static_cast<int>(walker->y);
int halfSize = DOT_SIZE / 2;
// Draw a filled square (dot) at the walker's position
glBegin(GL_QUADS);
glVertex2f(left, top);
glVertex2f(right, top);
glVertex2f(right, bottom);
glVertex2f(left, bottom);
glEnd();
for (int dy = -halfSize; dy <= halfSize; ++dy) {
for (int dx = -halfSize; dx <= halfSize; ++dx) {
int px = centerX + dx;
int py = centerY + dy;
if (px >= 0 && px < WIDTH && py >= 0 && py < HEIGHT) {
trailBuffer[py * WIDTH + px] = 0.0f; // Set to black (no fade)
}
}
}
}
/**
* @brief Renders the trail buffer to the screen using OpenGL.
*/
void drawTrail() {
// Convert float values (0.0-1.0) to grayscale (0-255) for rendering
std::vector<uint8_t> grayscale(WIDTH * HEIGHT);
for (size_t i = 0; i < trailBuffer.size(); ++i) {
grayscale[i] = static_cast<uint8_t>(trailBuffer[i] * 255.0f);
}
// Render grayscale buffer
glDrawPixels(WIDTH, HEIGHT, GL_LUMINANCE, GL_UNSIGNED_BYTE, grayscale.data());
}
};