08: Add first particle system prototype
Also update the README.md
This commit is contained in:
parent
351286d16a
commit
7a218edcce
|
@ -15,8 +15,7 @@ out float _ctt;
|
|||
|
||||
void main() {
|
||||
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);
|
||||
_color = color;
|
||||
_texture_position = texture_position;
|
||||
|
|
|
@ -25,52 +25,16 @@ int main() {
|
|||
|
||||
std::vector<Sprite> sprites;
|
||||
|
||||
int limit_x = 10;
|
||||
int limit_y = 10;
|
||||
float scale = 0.2;
|
||||
Sprite sprite(main_renderer);
|
||||
sprite.bake();
|
||||
|
||||
for (int i = -limit_x/2; i < limit_x/2; i++) {
|
||||
for (int j = -limit_y/2; j < limit_y/2; j++) {
|
||||
Sprite new_sprite(main_renderer);
|
||||
new_sprite.bake();
|
||||
sprite.origin = glm::vec4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
|
||||
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)) {
|
||||
glClearColor(0, 0, 0, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
for (int i = 0; i < sprites.size(); i++) {
|
||||
// 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();
|
||||
}
|
||||
|
||||
|
||||
sprite.update();
|
||||
main_renderer.logic();
|
||||
main_renderer.batch();
|
||||
|
||||
|
|
BIN
08-particle-system/.imgs/showcase.png
Normal file
BIN
08-particle-system/.imgs/showcase.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 89 KiB |
28
08-particle-system/Makefile
Normal file
28
08-particle-system/Makefile
Normal 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)
|
10
08-particle-system/README.md
Normal file
10
08-particle-system/README.md
Normal 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.
|
BIN
08-particle-system/assets/brick.jpg
Normal file
BIN
08-particle-system/assets/brick.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.8 MiB |
BIN
08-particle-system/assets/particle.png
Normal file
BIN
08-particle-system/assets/particle.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
BIN
08-particle-system/assets/player/idle.png
Normal file
BIN
08-particle-system/assets/player/idle.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
BIN
08-particle-system/assets/player/run.png
Normal file
BIN
08-particle-system/assets/player/run.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.2 KiB |
12
08-particle-system/assets/shaders/default_fragment.glsl
Normal file
12
08-particle-system/assets/shaders/default_fragment.glsl
Normal 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);
|
||||
}
|
26
08-particle-system/assets/shaders/default_vertex.glsl
Normal file
26
08-particle-system/assets/shaders/default_vertex.glsl
Normal 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;
|
||||
}
|
13
08-particle-system/assets/shaders/fragment.glsl
Normal file
13
08-particle-system/assets/shaders/fragment.glsl
Normal 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;
|
||||
}
|
14
08-particle-system/assets/shaders/vertex.glsl
Normal file
14
08-particle-system/assets/shaders/vertex.glsl
Normal 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;
|
||||
}
|
BIN
08-particle-system/assets/smoke.png
Normal file
BIN
08-particle-system/assets/smoke.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 119 KiB |
BIN
08-particle-system/boilerplate.trace
Normal file
BIN
08-particle-system/boilerplate.trace
Normal file
Binary file not shown.
22
08-particle-system/src/base/common.cpp
Normal file
22
08-particle-system/src/base/common.cpp
Normal 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;
|
||||
}
|
5
08-particle-system/src/base/common.hpp
Normal file
5
08-particle-system/src/base/common.hpp
Normal file
|
@ -0,0 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
std::string read_file(const char *path);
|
0
08-particle-system/src/base/force/force.cpp
Normal file
0
08-particle-system/src/base/force/force.cpp
Normal file
2
08-particle-system/src/base/force/force.hpp
Normal file
2
08-particle-system/src/base/force/force.hpp
Normal file
|
@ -0,0 +1,2 @@
|
|||
#pragma once
|
||||
|
11
08-particle-system/src/base/graphics/graphics.hpp
Normal file
11
08-particle-system/src/base/graphics/graphics.hpp
Normal 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
|
38
08-particle-system/src/base/graphics/program.cpp
Normal file
38
08-particle-system/src/base/graphics/program.cpp
Normal 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;
|
||||
}
|
14
08-particle-system/src/base/graphics/program.hpp
Normal file
14
08-particle-system/src/base/graphics/program.hpp
Normal 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();
|
||||
};
|
206
08-particle-system/src/base/graphics/renderer.cpp
Normal file
206
08-particle-system/src/base/graphics/renderer.cpp
Normal 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);
|
||||
}
|
52
08-particle-system/src/base/graphics/renderer.hpp
Normal file
52
08-particle-system/src/base/graphics/renderer.hpp
Normal 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;
|
||||
};
|
33
08-particle-system/src/base/graphics/shader.cpp
Normal file
33
08-particle-system/src/base/graphics/shader.cpp
Normal 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;
|
||||
}
|
8
08-particle-system/src/base/graphics/shader.hpp
Normal file
8
08-particle-system/src/base/graphics/shader.hpp
Normal file
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
struct Shader {
|
||||
unsigned int id;
|
||||
unsigned int type;
|
||||
|
||||
unsigned int load(const char *path, unsigned int type);
|
||||
};
|
12
08-particle-system/src/base/macros.hpp
Normal file
12
08-particle-system/src/base/macros.hpp
Normal 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
|
38
08-particle-system/src/base/particle-system/fog-system.cpp
Normal file
38
08-particle-system/src/base/particle-system/fog-system.cpp
Normal 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() {
|
||||
}
|
18
08-particle-system/src/base/particle-system/fog-system.hpp
Normal file
18
08-particle-system/src/base/particle-system/fog-system.hpp
Normal 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;
|
||||
};
|
|
@ -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() {
|
||||
|
||||
}
|
|
@ -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;
|
||||
};
|
16
08-particle-system/src/base/particle-system/particle.cpp
Normal file
16
08-particle-system/src/base/particle-system/particle.cpp
Normal 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() {
|
||||
|
||||
}
|
55
08-particle-system/src/base/sprite/sprite.cpp
Normal file
55
08-particle-system/src/base/sprite/sprite.cpp
Normal 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() {
|
||||
|
||||
}
|
27
08-particle-system/src/base/sprite/sprite.hpp
Normal file
27
08-particle-system/src/base/sprite/sprite.hpp
Normal 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;
|
||||
};
|
31
08-particle-system/src/base/window/window.cpp
Normal file
31
08-particle-system/src/base/window/window.cpp
Normal 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;
|
||||
}
|
30
08-particle-system/src/base/window/window.hpp
Normal file
30
08-particle-system/src/base/window/window.hpp
Normal 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;
|
||||
};
|
85
08-particle-system/src/main.cpp
Normal file
85
08-particle-system/src/main.cpp
Normal 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;
|
||||
}
|
2
08-particle-system/src/other/stb_image.cpp
Normal file
2
08-particle-system/src/other/stb_image.cpp
Normal file
|
@ -0,0 +1,2 @@
|
|||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "stb_image.h"
|
7987
08-particle-system/src/other/stb_image.h
Normal file
7987
08-particle-system/src/other/stb_image.h
Normal file
File diff suppressed because it is too large
Load Diff
22
README.md
22
README.md
|
@ -13,6 +13,28 @@
|
|||
|
||||
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
|
||||
|
||||
The code is licensed under the GPL-3.0 license. See the `LICENSE` file for more information
|
||||
|
|
Loading…
Reference in New Issue
Block a user