08: Add first particle system prototype

Also update the README.md
This commit is contained in:
Kevin J. 2023-12-23 17:09:43 +01:00
parent 351286d16a
commit 7a218edcce
40 changed files with 8930 additions and 43 deletions

View File

@ -15,8 +15,7 @@ out float _ctt;
void main() { void main() {
vec3 origined_position = origin.xyz + position.xyz; vec3 origined_position = origin.xyz + position.xyz;
origined_position *= 0.2;
//gl_Position = projection_matrix * view_matrix * position;
gl_Position = projection_matrix * view_matrix * vec4(origined_position, 1.0); gl_Position = projection_matrix * view_matrix * vec4(origined_position, 1.0);
_color = color; _color = color;
_texture_position = texture_position; _texture_position = texture_position;

View File

@ -25,52 +25,16 @@ int main() {
std::vector<Sprite> sprites; std::vector<Sprite> sprites;
int limit_x = 10; Sprite sprite(main_renderer);
int limit_y = 10; sprite.bake();
float scale = 0.2;
for (int i = -limit_x/2; i < limit_x/2; i++) { sprite.origin = glm::vec4(0.0f, 0.0f, 0.0f, 0.0f);
for (int j = -limit_y/2; j < limit_y/2; j++) {
Sprite new_sprite(main_renderer);
new_sprite.bake();
float r = (float) rand() / (float) RAND_MAX;
float g = (float) rand() / (float) RAND_MAX;
float b = (float) rand() / (float) RAND_MAX;
new_sprite.color = glm::vec4(r, g, b, 1.0f);
new_sprite.origin = glm::vec4(i*scale, j*scale, 0.0f, 0.0f);
sprites.push_back(new_sprite);
}
}
while (!glfwWindowShouldClose(window.window)) { while (!glfwWindowShouldClose(window.window)) {
glClearColor(0, 0, 0, 1); glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
for (int i = 0; i < sprites.size(); i++) { sprite.update();
// randomly update their position by little
float x = ((float) rand() / (float) RAND_MAX) * 0.5;
float y = ((float) rand() / (float) RAND_MAX) * 0.5;
int x_side = rand() % 2;
int y_side = rand() % 2;
if (x_side == 0)
sprites[i].origin.x += x;
else
sprites[i].origin.x -= x;
if (y_side == 0)
sprites[i].origin.y += y;
else
sprites[i].origin.y -= y;
sprites[i].update();
}
main_renderer.logic(); main_renderer.logic();
main_renderer.batch(); main_renderer.batch();

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

View File

@ -0,0 +1,28 @@
CC=g++
CFLAGS=-std=c++20 `pkg-config --cflags glfw3 glew glm`
LDFLAGS=`pkg-config --libs glfw3 glew glm`
TARGET=boilerplate
SDIR=src
ADIR=assets
ODIR=build
SRC=$(shell find $(SDIR) -type f -name *.cpp)
OBJ=$(SRC:.cpp=.o)
all: $(TARGET)
.PHONY: default
$(TARGET): $(OBJ)
mkdir -p build
cp -rf $(ADIR) $(ODIR)/
$(CC) -o $(ODIR)/$@ $^ $(LDFLAGS)
%.o: %.cpp
$(CC) $(CFLAGS) -o $@ -c $<
run:
$(ODIR)/$(TARGET)
.PHONY: clean
clean:
rm -f $(ODIR)/$(TARGET) $(OBJ)

View File

@ -0,0 +1,10 @@
<p align="center">
<img src=".imgs/showcase.png" width="300" />
</p>
# Particle System OpenGL
Contains a particle system abstraction on top of the previous OpenGL boilerplate code (`07-boilerplate`).
Each particle system is supposed (although not necessary) to have 1 renderer fully for itself.
Meaning that all the particles will be batched into 1 draw call.

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -0,0 +1,12 @@
#version 330 core
in vec4 _color;
in vec2 _texture_position;
in float _ctt;
out vec4 color;
uniform sampler2D sampler;
void main() {
color = texture(sampler, _texture_position) * (_color * _ctt);
}

View File

@ -0,0 +1,26 @@
#version 330 core
layout (location = 0) in vec4 position;
layout (location = 1) in vec4 origin;
layout (location = 2) in vec4 size;
layout (location = 3) in vec4 color;
layout (location = 4) in vec2 texture_position;
layout (location = 5) in float ctt;
uniform mat4 view_matrix;
uniform mat4 projection_matrix;
out vec4 _color;
out vec2 _texture_position;
out float _ctt;
void main() {
vec3 origined_position = origin.xyz + position.xyz;
origined_position *= size.xyz;
gl_Position = projection_matrix * view_matrix * vec4(origined_position, 1.0);
_color = color;
_texture_position = texture_position;
_ctt = ctt;
}

View File

@ -0,0 +1,13 @@
#version 330 core
out vec4 color;
in vec2 tex_coord;
uniform sampler2D sampler;
void main() {
color = texture(sampler, tex_coord);
// color = vec4(1.0, 0.0, 0.0, 1.0);
if (color.a < 0.1)
discard;
}

View File

@ -0,0 +1,14 @@
#version 330 core
layout (location = 0) in vec3 pos;
layout (location = 1) in vec2 texture_coord;
uniform mat4 view;
uniform mat4 projection;
out vec2 tex_coord;
void main() {
gl_Position = projection * view * vec4(pos.xyz, 1.0);
tex_coord = texture_coord;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

View File

@ -0,0 +1,22 @@
#include <iostream>
#include <fstream>
#include "common.hpp"
std::string read_file(const char *path) {
std::string content;
std::ifstream fs(path, std::ios::in);
if(!fs.is_open()) {
std::cerr << "Error: Could not read file " << path << ". File does not exist." << std::endl;
return NULL;
}
std::string line = "";
while(!fs.eof()) {
std::getline(fs, line);
content.append(line + "\n");
}
fs.close();
return content;
}

View File

@ -0,0 +1,5 @@
#pragma once
#include <string>
std::string read_file(const char *path);

View File

@ -0,0 +1,2 @@
#pragma once

View File

@ -0,0 +1,11 @@
#pragma once
#define DEFAULT_POSITION_ATTRIBUTE 0
#define DEFAULT_ORIGIN_ATTRIBUTE 1
#define DEFAULT_SIZE_ATTRIBUTE 2
#define DEFAULT_COLOR_ATTRIBUTE 3
#define DEFAULT_TEXTURE_ATTRIBUTE 4
#define DEFAULT_CTT_ATTRIBUTE 5
#define QUAD 6
#define DEFAULT_VBO_SIZE QUAD * 1000000 // unit: rows of RenderData

View File

@ -0,0 +1,38 @@
#include <iostream>
#include <GL/glew.h>
#include "program.hpp"
#include "../macros.hpp"
Program::Program() {
this->id = glCreateProgram();
}
int Program::add_shader(const char *path, unsigned int type) {
Shader new_shader;
unsigned int ret = new_shader.load(path, type);
if (!ret)
return RET_ERR;
this->shaders.push_back(new_shader);
return 0;
}
int Program::link() {
for (int shader = 0; shader < this->shaders.size(); shader++)
glAttachShader(this->id, this->shaders[shader].id);
glLinkProgram(this->id);
int success;
char info_log[512];
glGetProgramiv(this->id, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(this->id, 512, NULL, info_log);
return RET_ERR;
}
return 0;
}

View File

@ -0,0 +1,14 @@
#pragma once
#include <GL/glew.h>
#include <vector>
#include "shader.hpp"
struct Program {
GLuint id;
std::vector<Shader> shaders;
Program();
int add_shader(const char *path, unsigned int type);
int link();
};

View File

@ -0,0 +1,206 @@
#include <optional>
#include <glm/vec3.hpp>
#include <glm/mat4x4.hpp>
#include <glm/gtc/type_ptr.hpp>
#include "../../other/stb_image.h"
#include "renderer.hpp"
#include "../macros.hpp"
#include "graphics.hpp"
Renderer::Renderer(Window &window) : window(window) {
this->batch_buffer = std::vector<struct RendererData>();
this->window = window;
glGenBuffers(1, &this->vertex_buffer_id);
glGenVertexArrays(1, &this->array_buffer_id);
glGenTextures(1, &this->texture_id);
this->view_matrix = glm::mat4(1.0f);
this->projection_matrix = glm::mat4(1.0f);
}
int Renderer::setup_attributes() {
glVertexAttribPointer(
DEFAULT_POSITION_ATTRIBUTE,
4,
GL_FLOAT,
GL_FALSE,
sizeof(struct RendererData),
(void *) offsetof(RendererData, vertex)
);
glEnableVertexAttribArray(DEFAULT_POSITION_ATTRIBUTE);
glVertexAttribPointer(
DEFAULT_ORIGIN_ATTRIBUTE,
4,
GL_FLOAT,
GL_FALSE,
sizeof(struct RendererData),
(void *) offsetof(RendererData, origin)
);
glEnableVertexAttribArray(DEFAULT_ORIGIN_ATTRIBUTE);
glVertexAttribPointer(
DEFAULT_SIZE_ATTRIBUTE,
4,
GL_FLOAT,
GL_FALSE,
sizeof(struct RendererData),
(void *) offsetof(RendererData, size)
);
glEnableVertexAttribArray(DEFAULT_SIZE_ATTRIBUTE);
glVertexAttribPointer(
DEFAULT_COLOR_ATTRIBUTE,
4,
GL_FLOAT,
GL_FALSE,
sizeof(struct RendererData),
(void *) offsetof(RendererData, color)
);
glEnableVertexAttribArray(DEFAULT_COLOR_ATTRIBUTE);
glVertexAttribPointer(
DEFAULT_TEXTURE_ATTRIBUTE,
2,
GL_FLOAT,
GL_FALSE,
sizeof(struct RendererData),
(void *) offsetof(RendererData, tex)
);
glEnableVertexAttribArray(DEFAULT_TEXTURE_ATTRIBUTE);
glVertexAttribPointer(
DEFAULT_CTT_ATTRIBUTE,
1,
GL_FLOAT,
GL_FALSE,
sizeof(struct RendererData),
(void *) offsetof(RendererData, ctt_ratio)
);
glEnableVertexAttribArray(DEFAULT_CTT_ATTRIBUTE);
return RET_OK;
}
int Renderer::setup(std::optional<Program> program) {
int ret;
if (program != std::nullopt)
this->program = program.value();
else {
Program new_program = Program();
ret = new_program.add_shader("assets/shaders/default_vertex.glsl", GL_VERTEX_SHADER);
if (ret != RET_OK) {
LOG(LOG_ERR, "Failed adding vertex shader to program");
return RET_ERR;
}
ret = new_program.add_shader("assets/shaders/default_fragment.glsl", GL_FRAGMENT_SHADER);
if (ret != RET_OK) {
LOG(LOG_ERR, "Failed adding fragment shader to program");
return RET_ERR;
}
ret = new_program.link();
if (ret != RET_OK) {
LOG(LOG_ERR, "Failed linking program");
return RET_ERR;
}
this->program = new_program;
}
Renderer::blend();
glBindVertexArray(this->array_buffer_id);
glBindBuffer(GL_ARRAY_BUFFER, this->vertex_buffer_id);
glBufferData(GL_ARRAY_BUFFER, sizeof(struct RendererData) * DEFAULT_VBO_SIZE, nullptr, GL_DYNAMIC_DRAW);
setup_attributes();
// setup matrices
this->view_matrix = glm::translate(this->view_matrix, glm::vec3(0.0f, 0.0f, -3.0f));
// setup textures
glBindTexture(GL_TEXTURE_2D, this->texture_id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
return RET_OK;
}
int Renderer::load_texture(std::string location, GLenum format) {
int width;
int height;
int channels;
unsigned char *data = stbi_load(location.c_str(), &width, &height, &channels, 0);
if (!data)
return RET_ERR;
glBindTexture(GL_TEXTURE_2D, this->texture_id);
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
stbi_image_free(data);
return RET_OK;
}
void Renderer::draw(struct RendererData data) {
if (batch_buffer.size() >= DEFAULT_VBO_SIZE) {
LOG(LOG_WARN, "Batch buffer limit reached!");
return;
}
batch_buffer.push_back(data);
}
void Renderer::batch() {
glUseProgram(this->program.id);
glUniformMatrix4fv(glGetUniformLocation(this->program.id, "view_matrix"), 1, GL_FALSE, &this->view_matrix[0][0]);
glUniformMatrix4fv(glGetUniformLocation(this->program.id, "projection_matrix"), 1, GL_FALSE, &this->projection_matrix[0][0]);
glUniform1i(glGetUniformLocation(this->program.id, "sampler"), 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, this->texture_id);
glBindVertexArray(this->array_buffer_id);
glBindBuffer(GL_ARRAY_BUFFER, this->vertex_buffer_id);
glBufferSubData(GL_ARRAY_BUFFER, 0, batch_buffer.size() * sizeof(struct RendererData), batch_buffer.data());
glDrawArrays(GL_TRIANGLES, 0, DEFAULT_VBO_SIZE);
batch_buffer.clear();
}
void Renderer::logic() {
int window_width;
int window_height;
float half_width;
float half_height;
this->window.get_size(&window_width, &window_height);
half_width = window_width / 2.0f;
half_height = window_height / 2.0f;
this->projection_matrix = glm::ortho(-half_width/100, half_width/100, -half_height/100, half_height/100, 0.1f, 100.0f);
}
Renderer::~Renderer() {
glDisableVertexAttribArray(DEFAULT_POSITION_ATTRIBUTE);
glDisableVertexAttribArray(DEFAULT_COLOR_ATTRIBUTE);
glDisableVertexAttribArray(DEFAULT_TEXTURE_ATTRIBUTE);
glDisableVertexAttribArray(DEFAULT_CTT_ATTRIBUTE);
}

View File

@ -0,0 +1,52 @@
#pragma once
#include <GL/glew.h>
#include <optional>
#include <glm/mat4x4.hpp>
#include "program.hpp"
#include "../window/window.hpp"
struct RendererData {
glm::vec4 vertex;
glm::vec4 origin;
glm::vec4 size;
glm::vec4 color;
glm::vec2 tex;
float ctt_ratio; // color to texture ratio (i.e. how much does the collor affect the texture)
};
class Renderer {
public:
Renderer(Window &window);
~Renderer();
int setup_attributes();
int setup(std::optional<Program> program = std::nullopt);
void logic();
int load_texture(std::string location, GLenum format);
void draw(struct RendererData data);
void batch();
inline static void blend() {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
inline static void clear(glm::vec4 color) {
glClearColor(color.r, color.g, color.b, color.a);
glClear(GL_COLOR_BUFFER_BIT);
}
std::vector<struct RendererData> batch_buffer;
private:
GLuint array_buffer_id;
GLuint vertex_buffer_id;
GLuint texture_id;
glm::mat4 view_matrix;
glm::mat4 projection_matrix;
Window &window;
Program program;
};

View File

@ -0,0 +1,33 @@
#include <iostream>
#include <GL/glew.h>
#include "shader.hpp"
#include "../common.hpp"
#include "../macros.hpp"
unsigned int Shader::load(const char *path, unsigned int type) {
std::string source_s = read_file(path);
const char *source = source_s.c_str();
unsigned int new_shader = glCreateShader(type);
if (!new_shader)
return 0;
glShaderSource(new_shader, 1, &source, NULL);
glCompileShader(new_shader);
int success;
char info_log[512];
glGetShaderiv(new_shader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(new_shader, 512, NULL, info_log);
std::cout << "Error: failed compiling new shader " << info_log << std::endl;
LOG(LOG_ERR, "Failed compiling new shader");
return RET_OK;
}
this->id = new_shader;
this->type = type;
return new_shader;
}

View File

@ -0,0 +1,8 @@
#pragma once
struct Shader {
unsigned int id;
unsigned int type;
unsigned int load(const char *path, unsigned int type);
};

View File

@ -0,0 +1,12 @@
#pragma once
#include <iostream>
#define LOG_DEBUG "debug"
#define LOG_WARN "warning"
#define LOG_ERR "error"
#define LOG(level, ...) std::cout << "[" << __TIME__ << " " << level << "]: " << __VA_ARGS__ << std::endl;
#define RET_OK 0
#define RET_ERR -1

View File

@ -0,0 +1,38 @@
#include <glm/vec4.hpp>
#include "particle-system.hpp"
#include "fog-system.hpp"
extern glm::vec4 generate_origin(Rectangle rect);
extern float randomize();
void FogSystem::logic() {
for (int i = 0; i < this->particles.size(); i++) {
Particle &particle = this->particles[i];
Sprite &sprite = particle.sprite;
sprite.origin += particle.force * this->speed;
particle.update();
}
for (int i = 0; i < (int) this->data.spawn_rate; i++)
this->spawn_particle();
}
void FogSystem::spawn_particle() {
glm::vec4 new_force = this->data.default_force;
new_force.x = (randomize() - 0.5f) * 0.02f;
new_force.y = randomize() * new_force.y;
Particle new_particle(this->renderer, new_force);
glm::vec4 new_origin = generate_origin(this->data.spawn_area);
new_particle.sprite.origin = new_origin;
new_particle.sprite.size = this->data.default_size;
new_particle.sprite.color = this->data.default_color;
this->particles.push_back(new_particle);
}
FogSystem::~FogSystem() {
}

View File

@ -0,0 +1,18 @@
#pragma once
#include "particle-system.hpp"
class FogSystem : public ParticleSystem {
public:
FogSystem(Renderer &renderer, struct ParticleSystemData data) : ParticleSystem(renderer, data) {}
~FogSystem();
void logic();
void spawn_particle();
inline void set_speed(float new_speed) {
this->speed = new_speed;
}
private:
float speed = 1.0f;
};

View File

@ -0,0 +1,56 @@
#include "particle-system.hpp"
float randomize() {
return (float) rand() / (float) RAND_MAX;
}
ParticleSystem::ParticleSystem(Renderer& renderer, struct ParticleSystemData data) : renderer(renderer) {
this->data = data;
}
int ParticleSystem::setup() {
int ret = this->renderer.load_texture(this->data.default_texture, GL_RGBA);
if (ret != RET_OK)
return RET_ERR;
return RET_OK;
}
void ParticleSystem::logic() {
for (int i = 0; i < this->particles.size(); i++) {
Particle &particle = this->particles[i];
Sprite &sprite = particle.sprite;
sprite.origin += particle.force;
particle.update();
}
for (int i = 0; i < (int) this->data.spawn_rate; i++)
this->spawn_particle();
}
glm::vec4 generate_origin(Rectangle rect) {
glm::vec4 new_origin = glm::vec4(0.0f);
new_origin.x = rect.x + (randomize() * rect.width);
new_origin.y = rect.y + (randomize() * rect.height);
return new_origin;
}
void ParticleSystem::spawn_particle() {
Particle new_particle(this->renderer, this->data.default_force);
glm::vec4 new_origin = generate_origin(this->data.spawn_area);
new_particle.sprite.origin = new_origin;
new_particle.sprite.size = this->data.default_size;
new_particle.sprite.color = this->data.default_color;
this->particles.push_back(new_particle);
}
ParticleSystem::~ParticleSystem() {
}

View File

@ -0,0 +1,51 @@
#pragma once
#include <iostream>
#include <vector>
#include "../graphics/renderer.hpp"
#include "../sprite/sprite.hpp"
#include "../macros.hpp"
#include <glm/vec4.hpp>
class Particle {
public:
Particle(Renderer &renderer, glm::vec4 force);
~Particle();
void update();
Sprite sprite;
glm::vec4 force;
float time;
};
struct Rectangle {
float x;
float y;
float width;
float height;
};
struct ParticleSystemData {
float spawn_rate; // spawn per call
glm::vec4 default_force;
glm::vec4 default_color;
glm::vec4 default_size;
struct Rectangle spawn_area;
std::string default_texture;
};
class ParticleSystem {
public:
ParticleSystem(Renderer &renderer, struct ParticleSystemData data);
~ParticleSystem();
int setup();
virtual void logic();
virtual void spawn_particle();
protected:
Renderer &renderer;
struct ParticleSystemData data;
std::vector<Particle> particles;
};

View File

@ -0,0 +1,16 @@
#include "particle-system.hpp"
Particle::Particle(Renderer &renderer, glm::vec4 force = glm::vec4(0.0f)) : sprite(renderer) {
this->force = force;
this->sprite.bake();
this->time = 0.0f;
}
void Particle::update() {
this->time += 0.0001f;
this->sprite.update();
}
Particle::~Particle() {
}

View File

@ -0,0 +1,55 @@
#include <iostream>
#include <vector>
#include <glm/vec4.hpp>
#include <glm/vec2.hpp>
#include <GL/glew.h>
#include "../graphics/renderer.hpp"
#include "../macros.hpp"
#include "sprite.hpp"
Sprite::Sprite(Renderer &renderer) : renderer(renderer) {
this->vertices = std::vector<glm::vec4>();
this->texture_positions = std::vector<glm::vec2>();
this->origin = glm::vec4(0.0f);
this->size = glm::vec4(1.0f);
this->color = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f);
this->ctt = 1.0f;
}
// prepare data
void Sprite::bake() {
this->vertices.push_back(glm::vec4(0.5f, 0.5f, 0.0f, 0.0f));
this->vertices.push_back(glm::vec4(0.5f, -0.5f, 0.0f, 0.0f));
this->vertices.push_back(glm::vec4(-0.5f, -0.5f, 0.0f, 0.0f));
this->vertices.push_back(glm::vec4(-0.5f, 0.5f, 0.0f, 0.0f));
this->vertices.push_back(glm::vec4(0.5f, 0.5f, 0.0f, 0.0f));
this->vertices.push_back(glm::vec4(-0.5f, -0.5f, 0.0f, 0.0f));
this->texture_positions.push_back(glm::vec2(1.0f, 1.0f));
this->texture_positions.push_back(glm::vec2(1.0f, 0.0f));
this->texture_positions.push_back(glm::vec2(0.0f, 0.0f));
this->texture_positions.push_back(glm::vec2(0.0f, 1.0f));
this->texture_positions.push_back(glm::vec2(1.0f, 1.0f));
this->texture_positions.push_back(glm::vec2(0.0f, 0.0f));
}
void Sprite::update() {
for (int i = 0; i < this->vertices.size(); i++) {
struct RendererData data = {
.vertex = this->vertices[i],
.origin = this->origin,
.size = this->size,
.color = this->color,
.tex = this->texture_positions[i],
.ctt_ratio = this->ctt
};
this->renderer.draw(data);
}
}
Sprite::~Sprite() {
}

View File

@ -0,0 +1,27 @@
#pragma once
#include <iostream>
#include <vector>
#include <glm/vec4.hpp>
#include <glm/vec2.hpp>
#include <GL/glew.h>
#include "../graphics/renderer.hpp"
class Sprite {
public:
Sprite(Renderer &renderer);
~Sprite();
void bake();
void update();
glm::vec4 origin;
glm::vec4 size;
glm::vec4 color;
float ctt;
private:
std::vector<glm::vec4> vertices;
std::vector<glm::vec2> texture_positions;
Renderer &renderer;
};

View File

@ -0,0 +1,31 @@
#include <iostream>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "window.hpp"
#include "../macros.hpp"
int Window::init(int width, int height, std::string title) {
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
this->window = glfwCreateWindow(width, height, title.c_str(), NULL, NULL);
if (this->window == NULL) {
LOG(LOG_ERR, "Failed creating window");
glfwTerminate();
return RET_ERR;
}
glfwMakeContextCurrent(this->window);
GLenum err = glewInit();
if (err != GLEW_OK) {
LOG(LOG_ERR, "FAiled initializing Glew");
return RET_ERR;
}
glfwSetFramebufferSizeCallback(this->window, this->resize_callback);
return RET_OK;
}

View File

@ -0,0 +1,30 @@
#pragma once
#include <iostream>
#include <GLFW/glfw3.h>
class Window {
public:
int init(int width, int height, std::string title);
inline static void resize_callback(GLFWwindow *window, int new_width, int new_height) {
glViewport(0, 0, new_width, new_height);
}
inline void set_keyboard_callback(void (*callback)(GLFWwindow *window, int key, int scancode, int action, int mode)) {
glfwSetKeyCallback(this->window, callback);
}
inline void get_size(int *width, int *height) {
glfwGetWindowSize(this->window, width, height);
}
inline bool should_close() {
return glfwWindowShouldClose(this->window);
}
inline void end_frame() {
glfwPollEvents();
glfwSwapBuffers(this->window);
}
bool pressed_e = false;
private:
GLFWwindow *window;
};

View File

@ -0,0 +1,85 @@
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <stb/stb_image.h>
#include "base/window/window.hpp"
#include "base/graphics/renderer.hpp"
#include "base/particle-system/particle-system.hpp"
#include "base/particle-system/fog-system.hpp"
#include "base/macros.hpp"
const int initial_height = 600;
const int initial_width = 1000;
Window main_window;
void _keyboard(GLFWwindow *window, int key, int scancode, int action, int mode) {
if (action != GLFW_PRESS)
return;
switch (key) {
case GLFW_KEY_E:
LOG(LOG_DEBUG, "PRESSING E!");
main_window.pressed_e = !main_window.pressed_e;
break;
default:
break;
}
}
int main() {
int ret;
ret = main_window.init(initial_width, initial_height, "OpenGL");
if (ret != RET_OK) {
LOG(LOG_ERR, "Failed initializing GLFW window");
return RET_ERR;
}
main_window.set_keyboard_callback(_keyboard);
Renderer main_renderer(main_window);
ret = main_renderer.setup();
if (ret != RET_OK) {
LOG(LOG_ERR, "Failed setting up a new renderer");
return RET_ERR;
}
ParticleSystemData ps_data = {
.spawn_rate = 20,
.default_force = glm::vec4(0.0f, 0.1f, 0.0f, 0.0f),
.default_color = glm::vec4(0.0f, 0.8f, 0.4f, 0.4f),
.default_size = glm::vec4(0.3f, 0.3f, 0.1f, 0.1f),
.spawn_area = {
.x = -120.0f,
.y = -240.0f,
.width = 220.0f,
.height = 220.0f
},
.default_texture = "assets/particle.png"
};
FogSystem ps(main_renderer, ps_data);
ps.setup();
while (!main_window.should_close()) {
Renderer::clear(glm::vec4(0.0f, 0.0f, 0.0f, 1.0f));
if (main_window.pressed_e)
ps.set_speed(10.0f);
else
ps.set_speed(1.0f);
ps.logic();
main_renderer.logic();
main_renderer.batch();
main_window.end_frame();
}
glfwTerminate();
return RET_OK;
}

View File

@ -0,0 +1,2 @@
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

File diff suppressed because it is too large Load Diff

View File

@ -13,6 +13,28 @@
My little playground for everything graphics My little playground for everything graphics
- `01-introduction`: SDL introduction (texture loading, player movement)
- `02-jumping`: jumping in SDL (animations, jumping)
- `03-network`: connection handling + server side calculations in SDL (client, server)
- `04-map`: map generation testing for SDL
- `05-opengl`: OpenGL introduction (texture loading)
- `06-monogame`: Monogame introduction tests
- `07-boilerplate`: Boilerplate OpenGL abstraction (batch rendering)
- `08-particle-system`: Expanding OpenGL boilerplate for particle systems + texture loading
## Goal Experiments
- [x] OpenGL boilerplate
- [x] Particle Systems
- [ ] Basic physics
- [ ] Effects
- [ ] Bloom
- [ ] Blur
- [ ] Sound
- [ ] Multiplayer
- [ ] Procedural map generation
- [ ] Super Mario movement
## License ## License
The code is licensed under the GPL-3.0 license. See the `LICENSE` file for more information The code is licensed under the GPL-3.0 license. See the `LICENSE` file for more information