From e4b900e721fe4aa7e20f4a274c708f0453e90356 Mon Sep 17 00:00:00 2001 From: loic Date: Fri, 13 Dec 2024 21:06:46 +0100 Subject: [PATCH] implement perlin noise render --- includes/math/Vector2.hpp | 28 +++++++++ includes/noise/perlin.hpp | 20 +++++++ includes/windowManager/WindowManager.hpp | 10 +++- srcs/main.cpp | 24 +++++--- srcs/math/Vector2.cpp | 34 +++++++++++ srcs/noise/perlin.cpp | 57 +++++++++++++++++++ srcs/windowManager/WindowManager.cpp | 72 +++++++++++++++--------- 7 files changed, 207 insertions(+), 38 deletions(-) create mode 100644 includes/math/Vector2.hpp create mode 100644 includes/noise/perlin.hpp create mode 100644 srcs/math/Vector2.cpp create mode 100644 srcs/noise/perlin.cpp diff --git a/includes/math/Vector2.hpp b/includes/math/Vector2.hpp new file mode 100644 index 0000000..17389eb --- /dev/null +++ b/includes/math/Vector2.hpp @@ -0,0 +1,28 @@ +#ifndef VECTPR2_HPP +#define VECTOR2_HPP + +class Vector2 { +public: + Vector2(int x, int y); + Vector2(float x, float y); + Vector2(double x, double y); + Vector2(); + Vector2(const Vector2 &v); + + ~Vector2(); + + Vector2 &operator=(const Vector2 &v); + Vector2 operator+(const Vector2 &v) const; + Vector2 operator-(const Vector2 &v) const; + Vector2 operator*(const Vector2 &v) const; + + float dot(const Vector2 &v) const; + + float getX() const; + float getY() const; +private: + double x; + double y; +}; + +#endif \ No newline at end of file diff --git a/includes/noise/perlin.hpp b/includes/noise/perlin.hpp new file mode 100644 index 0000000..88d1cc2 --- /dev/null +++ b/includes/noise/perlin.hpp @@ -0,0 +1,20 @@ + +#ifndef PERLIN_HPP +#define PERLIN_HPP +#include "math/Vector2.hpp" + + +class PerlinNoise { +public: + PerlinNoise(); + float noise(float x, float y); + +private: + void initializeGradients(); + Vector2 grad[256]; + Vector2 randoGradient(int ix, int iy); + float dotGridGradient(int ix, int iy, float x, float y); + float interpolate(float a, float a1, float w); +}; + +#endif \ No newline at end of file diff --git a/includes/windowManager/WindowManager.hpp b/includes/windowManager/WindowManager.hpp index 7ce1d1c..54a2c69 100644 --- a/includes/windowManager/WindowManager.hpp +++ b/includes/windowManager/WindowManager.hpp @@ -4,18 +4,23 @@ #include #include +#include #include "err.h" class WindowManager { public: - WindowManager(int width, int height); + WindowManager(int width, int height, int (*)(u_int32_t *img)); ~WindowManager(); u_int32_t *get_image_addr() { return img; } - void display_image(); void loop(); private: + void update_image(int (*)(u_int32_t *img)); + void display_image(); + void handle_events(XEvent &GeneralEvent); + + int (*render)(u_int32_t *img); u_int32_t *img; int WindowX; int WindowY; @@ -32,6 +37,7 @@ private: Window RootWindow; Atom wmDelete; bool isWindowOpen; + bool isDisplayReady; }; #endif //NOISE_GENERATOR_WINDOWMANAGER_HPP diff --git a/srcs/main.cpp b/srcs/main.cpp index 91d5311..114ee98 100644 --- a/srcs/main.cpp +++ b/srcs/main.cpp @@ -1,21 +1,27 @@ -#include #include "windowManager/WindowManager.hpp" +#include "noise/perlin.hpp" -#define WIDTH 500 -#define HEIGHT 800 - -int main() { - WindowManager window(WIDTH, HEIGHT); - u_int32_t *img = window.get_image_addr(); +#define WIDTH 720 +#define HEIGHT 420 +int render(uint32_t *img) { + static PerlinNoise PerlinNoise; + static float time = 0.0; for (int y = 0; y < HEIGHT; y++) { for (int x = 0; x < WIDTH; x++) { - img[y * WIDTH + x] = (y * 255 / HEIGHT) * 0x100 + (x * 255 / WIDTH); + float n = (PerlinNoise.noise(x / 100.0 + time, (y / 100.0) + time)); + + int color = static_cast((n + 1) * 127.5); + img[y * WIDTH + x] = (color << 16) | (color << 8) | color ; } } + time += 0.1; + return 0; +} - +int main() { + WindowManager window(WIDTH, HEIGHT, render); window.loop(); return 0; diff --git a/srcs/math/Vector2.cpp b/srcs/math/Vector2.cpp new file mode 100644 index 0000000..e13228e --- /dev/null +++ b/srcs/math/Vector2.cpp @@ -0,0 +1,34 @@ +#include "math/Vector2.hpp" + +Vector2::Vector2(int x, int y) : x(x), y(y) {}; +Vector2::Vector2(float x, float y) : x(x), y(y) {}; +Vector2::Vector2() : x(0), y(0) {}; +Vector2::Vector2(const Vector2 &v) : x(v.x), y(v.y) {}; +Vector2::Vector2(double x, double y) : x(x), y(y) {}; + +float Vector2::getX() const { return x; } +float Vector2::getY() const { return y; } + +Vector2 &Vector2::operator=(const Vector2 &v) { + x = v.x; + y = v.y; + return *this; +} + +Vector2 Vector2::operator+(const Vector2 &v) const { + return Vector2(x + v.x, y + v.y); +} + +Vector2 Vector2::operator-(const Vector2 &v) const { + return Vector2(x - v.x, y - v.y); +} + +Vector2 Vector2::operator*(const Vector2 &v) const { + return Vector2(x * v.x, y * v.y); +} + +float Vector2::dot(const Vector2 &v) const { + return x * v.x + y * v.y; +} + +Vector2::~Vector2() {} diff --git a/srcs/noise/perlin.cpp b/srcs/noise/perlin.cpp new file mode 100644 index 0000000..0695d24 --- /dev/null +++ b/srcs/noise/perlin.cpp @@ -0,0 +1,57 @@ + +#include +#include +#include +#include "noise/perlin.hpp" + + + +PerlinNoise::PerlinNoise() { + initializeGradients(); +} + +void PerlinNoise::initializeGradients() { + std::mt19937 gen(0); + std::uniform_real_distribution dis(0.0, 2 * M_PI); + + for (int i = 0; i < 256; ++i) { + float angle = dis(gen); + grad[i] = Vector2(cos(angle), sin(angle)); + } +} + +Vector2 PerlinNoise::randoGradient(int ix, int iy) { + uint32_t hash = ix * 7385451 ^ iy * 19349663; + return grad[hash & 0xFF]; +} + +float PerlinNoise::dotGridGradient(int ix, int iy, float x, float y) { + Vector2 gradient = randoGradient(ix, iy); + float dx = x - (float)ix; + float dy = y - (float)iy; + return dx * gradient.getX() + dy * gradient.getY(); +} + +float PerlinNoise::interpolate(float a, float a1, float w) { + return (a1 - a) * (3.0 - w * 2.0) * w * w + a; +} + +float PerlinNoise::noise(float x, float y) { + int x0 = (int)x; + int y0 = (int)y; + int x1 = x0 + 1; + int y1 = y0 + 1; + + float sx = x - (float)x0; + float sy = y - (float)y0; + + float n0 = dotGridGradient(x0, y0, x, y); + float n1 = dotGridGradient(x1, y0, x, y); + float ix0 = interpolate(n0, n1, sx); + + n0 = dotGridGradient(x0, y1, x, y); + n1 = dotGridGradient(x1, y1, x, y); + float ix1 = interpolate(n0, n1, sx); + + return interpolate(ix0, ix1, sy); +} diff --git a/srcs/windowManager/WindowManager.cpp b/srcs/windowManager/WindowManager.cpp index 5cb41a1..922dd64 100644 --- a/srcs/windowManager/WindowManager.cpp +++ b/srcs/windowManager/WindowManager.cpp @@ -1,24 +1,25 @@ #include "windowManager/WindowManager.hpp" -#include +#include "noise/perlin.hpp" #include #include #include #include -#include -WindowManager::WindowManager(int width, int height) : +WindowManager::WindowManager(int width, int height, int (*render)(u_int32_t *img)) : + render(render), WindowX(0), WindowY(0), WindowWidth(width), WindowHeight(height), BorderWidth(0), WindowDepth(CopyFromParent), WindowClass(CopyFromParent), WindowVisual(CopyFromParent), - AttributeValueMask(CWBackPixel | CWEventMask) + AttributeValueMask(CWBackPixel | CWEventMask), + isDisplayReady(false) { img = new u_int32_t[width * height]; MainDisplay = XOpenDisplay(0); RootWindow = XDefaultRootWindow(MainDisplay); - bzero(&WindowAttributes, sizeof(XSetWindowAttributes)); + WindowAttributes = {}; WindowAttributes.background_pixel = 0x0; WindowAttributes.event_mask = StructureNotifyMask | KeyPressMask | KeyReleaseMask | ExposureMask; @@ -40,30 +41,41 @@ WindowManager::~WindowManager() { delete[] img; } +void WindowManager::handle_events(XEvent &GeneralEvent) { + switch(GeneralEvent.type) { + case KeyPress: + case KeyRelease: + { + XKeyPressedEvent *event = (XKeyPressedEvent *)&GeneralEvent; + if (event->keycode == XKeysymToKeycode(this->MainDisplay, XK_Escape)) { + this->isWindowOpen = false; + } + } break; + case ClientMessage: { + if (static_cast(GeneralEvent.xclient.data.l[0]) == this->wmDelete) { + this->isWindowOpen = false; + } + } break; + case Expose: + { + if (!isDisplayReady) + isDisplayReady = true; + display_image(); + } break; + } +} + void WindowManager::loop() { while (isWindowOpen) { - XEvent GeneralEvent = {}; - XNextEvent(this->MainDisplay, &GeneralEvent); - - switch(GeneralEvent.type) { - case KeyPress: - case KeyRelease: - { - XKeyPressedEvent *event = (XKeyPressedEvent *)&GeneralEvent; - if (event->keycode == XKeysymToKeycode(this->MainDisplay, XK_Escape)) { - this->isWindowOpen = false; - } - } break; - case ClientMessage: { - if (static_cast(GeneralEvent.xclient.data.l[0]) == this->wmDelete) { - this->isWindowOpen = false; - } - } break; - case Expose: - { - std::cout << "test" << std::endl; - display_image(); - } break; + while (XPending(this->MainDisplay) > 0) + { + XEvent GeneralEvent = {}; + XNextEvent(this->MainDisplay, &GeneralEvent); + handle_events(GeneralEvent); + } + if (isDisplayReady) { + update_image(this->render); + display_image(); } } } @@ -86,3 +98,9 @@ void WindowManager::display_image() { XPutImage(MainDisplay, MainWindow, DefaultGC(MainDisplay, 0), &image, 0, 0, 0, 0, WindowWidth, WindowHeight); XFlush(MainDisplay); } + +void WindowManager::update_image(int (*func)(u_int32_t *img)) { + if (func(this->img)) + this->isWindowOpen = false; + +} \ No newline at end of file