implement perlin noise render

This commit is contained in:
loic 2024-12-13 21:06:46 +01:00
parent e0d23c9a82
commit e4b900e721
7 changed files with 207 additions and 38 deletions

28
includes/math/Vector2.hpp Normal file
View file

@ -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

20
includes/noise/perlin.hpp Normal file
View file

@ -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

View file

@ -4,18 +4,23 @@
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <mutex> #include <mutex>
#include <cstdint>
#include "err.h" #include "err.h"
class WindowManager { class WindowManager {
public: public:
WindowManager(int width, int height); WindowManager(int width, int height, int (*)(u_int32_t *img));
~WindowManager(); ~WindowManager();
u_int32_t *get_image_addr() { return img; } u_int32_t *get_image_addr() { return img; }
void display_image();
void loop(); void loop();
private: 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; u_int32_t *img;
int WindowX; int WindowX;
int WindowY; int WindowY;
@ -32,6 +37,7 @@ private:
Window RootWindow; Window RootWindow;
Atom wmDelete; Atom wmDelete;
bool isWindowOpen; bool isWindowOpen;
bool isDisplayReady;
}; };
#endif //NOISE_GENERATOR_WINDOWMANAGER_HPP #endif //NOISE_GENERATOR_WINDOWMANAGER_HPP

View file

@ -1,21 +1,27 @@
#include <csignal>
#include "windowManager/WindowManager.hpp" #include "windowManager/WindowManager.hpp"
#include "noise/perlin.hpp"
#define WIDTH 500 #define WIDTH 720
#define HEIGHT 800 #define HEIGHT 420
int main() {
WindowManager window(WIDTH, HEIGHT);
u_int32_t *img = window.get_image_addr();
int render(uint32_t *img) {
static PerlinNoise PerlinNoise;
static float time = 0.0;
for (int y = 0; y < HEIGHT; y++) { for (int y = 0; y < HEIGHT; y++) {
for (int x = 0; x < WIDTH; x++) { 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<int>((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(); window.loop();
return 0; return 0;

34
srcs/math/Vector2.cpp Normal file
View file

@ -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() {}

57
srcs/noise/perlin.cpp Normal file
View file

@ -0,0 +1,57 @@
#include <cmath>
#include <algorithm>
#include <random>
#include "noise/perlin.hpp"
PerlinNoise::PerlinNoise() {
initializeGradients();
}
void PerlinNoise::initializeGradients() {
std::mt19937 gen(0);
std::uniform_real_distribution<float> 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);
}

View file

@ -1,24 +1,25 @@
#include "windowManager/WindowManager.hpp" #include "windowManager/WindowManager.hpp"
#include <string.h> #include "noise/perlin.hpp"
#include <X11/Xutil.h> #include <X11/Xutil.h>
#include <iostream> #include <iostream>
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <csignal> #include <csignal>
#include <mutex>
WindowManager::WindowManager(int width, int height) : WindowManager::WindowManager(int width, int height, int (*render)(u_int32_t *img)) :
render(render),
WindowX(0), WindowY(0), WindowX(0), WindowY(0),
WindowWidth(width), WindowHeight(height), WindowWidth(width), WindowHeight(height),
BorderWidth(0), BorderWidth(0),
WindowDepth(CopyFromParent), WindowDepth(CopyFromParent),
WindowClass(CopyFromParent), WindowClass(CopyFromParent),
WindowVisual(CopyFromParent), WindowVisual(CopyFromParent),
AttributeValueMask(CWBackPixel | CWEventMask) AttributeValueMask(CWBackPixel | CWEventMask),
isDisplayReady(false)
{ {
img = new u_int32_t[width * height]; img = new u_int32_t[width * height];
MainDisplay = XOpenDisplay(0); MainDisplay = XOpenDisplay(0);
RootWindow = XDefaultRootWindow(MainDisplay); RootWindow = XDefaultRootWindow(MainDisplay);
bzero(&WindowAttributes, sizeof(XSetWindowAttributes)); WindowAttributes = {};
WindowAttributes.background_pixel = 0x0; WindowAttributes.background_pixel = 0x0;
WindowAttributes.event_mask = StructureNotifyMask | KeyPressMask | KeyReleaseMask | ExposureMask; WindowAttributes.event_mask = StructureNotifyMask | KeyPressMask | KeyReleaseMask | ExposureMask;
@ -40,30 +41,41 @@ WindowManager::~WindowManager() {
delete[] img; 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<Atom>(GeneralEvent.xclient.data.l[0]) == this->wmDelete) {
this->isWindowOpen = false;
}
} break;
case Expose:
{
if (!isDisplayReady)
isDisplayReady = true;
display_image();
} break;
}
}
void WindowManager::loop() { void WindowManager::loop() {
while (isWindowOpen) { while (isWindowOpen) {
XEvent GeneralEvent = {}; while (XPending(this->MainDisplay) > 0)
XNextEvent(this->MainDisplay, &GeneralEvent); {
XEvent GeneralEvent = {};
switch(GeneralEvent.type) { XNextEvent(this->MainDisplay, &GeneralEvent);
case KeyPress: handle_events(GeneralEvent);
case KeyRelease: }
{ if (isDisplayReady) {
XKeyPressedEvent *event = (XKeyPressedEvent *)&GeneralEvent; update_image(this->render);
if (event->keycode == XKeysymToKeycode(this->MainDisplay, XK_Escape)) { display_image();
this->isWindowOpen = false;
}
} break;
case ClientMessage: {
if (static_cast<Atom>(GeneralEvent.xclient.data.l[0]) == this->wmDelete) {
this->isWindowOpen = false;
}
} break;
case Expose:
{
std::cout << "test" << std::endl;
display_image();
} break;
} }
} }
} }
@ -86,3 +98,9 @@ void WindowManager::display_image() {
XPutImage(MainDisplay, MainWindow, DefaultGC(MainDisplay, 0), &image, 0, 0, 0, 0, WindowWidth, WindowHeight); XPutImage(MainDisplay, MainWindow, DefaultGC(MainDisplay, 0), &image, 0, 0, 0, 0, WindowWidth, WindowHeight);
XFlush(MainDisplay); XFlush(MainDisplay);
} }
void WindowManager::update_image(int (*func)(u_int32_t *img)) {
if (func(this->img))
this->isWindowOpen = false;
}