Brenta Engine 1.2
Loading...
Searching...
No Matches
particles.cpp
1// SPDX-License-Identifier: MIT
2// Author: Giovanni Santini
3// Mail: giovanni.santini@proton.me
4// Github: @San7o
5
6#include <brenta/camera.hpp>
7#include <brenta/particles.hpp>
8#include <brenta/window.hpp>
9#include <brenta/shader.hpp>
10#include <brenta/texture.hpp>
11#include <brenta/translation.hpp>
12
13#include <iostream>
14#include <time.h>
15
16using namespace brenta;
17
18const particle_emitter::config particle_emitter::default_config = {
19 glm::vec3(0.0f, 0.0f, 0.0f),
20 glm::vec3(0.0f, 0.0f, 0.0f),
21 glm::vec3(0.0f, 0.0f, 0.0f),
22 1.0f,
23 MAX_PARTICLES,
24 0.01f,
25 1.0f,
26 "",
27 8,
28 8,
29 0,
30 nullptr,
31};
32
33particle_emitter::particle_emitter(config conf)
34{
35 this->starting_position = conf.starting_position;
36 this->starting_velocity = conf.starting_velocity;
37 this->starting_spread = conf.starting_spread;
38 this->starting_time_to_live = conf.starting_time_to_live;
39 this->num_particles = conf.num_particles;
40 this->spawn_rate = conf.spawn_rate;
41 this->scale = conf.scale;
42 this->atlas = 0;
43 this->atlas_width = conf.atlas_width;
44 this->atlas_height = conf.atlas_height;
45 this->atlas_index = conf.atlas_index;
46 this->current = 0;
47 this->cam = conf.cam;
48
49 // Load Texture Atlas
50 this->atlas = texture::load_texture(conf.atlas_path, false);
51
52 // Create shaders
53 const GLchar *varyings[] = {"outPosition", "outVelocity", "outTTL"};
54 shader::create(varyings, 3, "particle_update",
55 GL_VERTEX_SHADER, "src/shaders/particle_update.vs");
56 shader::create("particle_render",
57 GL_VERTEX_SHADER, "src/shaders/particle_render.vs",
58 GL_GEOMETRY_SHADER, "src/shaders/particle_render.gs",
59 GL_FRAGMENT_SHADER, "src/shaders/particle_render.fs");
60
61 // This is needed to render points
62 glEnable(GL_PROGRAM_POINT_SIZE);
63
64 this->vao.init();
65 this->vao.bind();
66 check_opengl_error("vao bind");
67
68 // Create fbos
69 this->fbo[0] = types::buffer(GL_TRANSFORM_FEEDBACK_BUFFER);
70 this->fbo[1] = types::buffer(GL_TRANSFORM_FEEDBACK_BUFFER);
71
72 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, this->fbo[0].id);
73 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER,
74 this->num_particles * 2 * sizeof(glm::vec3)
75 + this->num_particles * sizeof(float),
76 NULL, GL_DYNAMIC_COPY);
77 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, this->fbo[1].id);
78 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER,
79 this->num_particles * 2 * sizeof(glm::vec3)
80 + this->num_particles * sizeof(float),
81 NULL, GL_DYNAMIC_COPY);
82 check_opengl_error("glBindBufferBase A");
83
84 // Unbind buffers
85 glBindBuffer(GL_ARRAY_BUFFER, 0);
86 glBindVertexArray(0);
87 this->vao.unbind();
88}
89
90particle_emitter::~particle_emitter()
91{
92 fbo[0].destroy();
93 fbo[1].destroy();
94}
95
96// Update particles using Transform Feedback
97// directly from the wiki
99{
100 shader::use("particle_update");
101 shader::set_float("particle_update", "deltaTime", delta_time);
102 shader::set_vec3("particle_update", "emitterPos", this->starting_position);
103 shader::set_vec3("particle_update", "emitterSpread", this->starting_spread);
104 shader::set_float("particle_update", "spawnProbability", this->spawn_rate);
105 shader::set_vec3("particle_update", "emitterVel", this->starting_velocity);
106 shader::set_float("particle_update", "emitterTTL",
107 this->starting_time_to_live);
108 check_opengl_error("settin update shader");
109
110 this->vao.bind();
111
112 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, fbo[current].id);
113 check_opengl_error("glBindBufferBase B");
114
115 glBindBuffer(GL_ARRAY_BUFFER, fbo[!current].id);
116 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,
117 2 * sizeof(glm::vec3) + sizeof(float), (void *) 0);
118 glEnableVertexAttribArray(0);
119 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE,
120 2 * sizeof(glm::vec3) + sizeof(float),
121 (void *) sizeof(glm::vec3));
122 glEnableVertexAttribArray(1);
123 glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE,
124 2 * sizeof(glm::vec3) + sizeof(float),
125 (void *) (2 * sizeof(glm::vec3)));
126 glEnableVertexAttribArray(2);
127
128 // Start transform feedback
129 glEnable(GL_RASTERIZER_DISCARD); // Disable rasterization
130 glBeginTransformFeedback(GL_POINTS); // Enter transform feedback mode
131 check_opengl_error("glBeginTransformFeedback");
132
133 glDrawArrays(GL_POINTS, 0, num_particles);
134 check_opengl_error("glDrawTransformFeedback");
135
136 glEndTransformFeedback(); // Exit transform feedback mode
137 glDisable(GL_RASTERIZER_DISCARD); // Enable rasterization
138 // Unbind buffers
139 glBindVertexArray(0);
140 glBindBuffer(GL_ARRAY_BUFFER, 0);
141 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);
142 this->vao.unbind();
143 current = !current; // Swap buffers
144}
145
146// Render particles
147void particle_emitter::render_particles()
148{
149 if (this->cam == nullptr)
150 {
151 ERROR("particle_emitter::render_particles: Camera not set or null for emitter");
152 return;
153 }
154
155 shader::use("particle_render");
156
157 this->vao.bind();
158
159 glBindBuffer(GL_ARRAY_BUFFER, fbo[current].id);
160 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,
161 2 * sizeof(glm::vec3) + sizeof(float), (void *) 0);
162 glEnableVertexAttribArray(0);
163 glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE,
164 2 * sizeof(glm::vec3) + sizeof(float),
165 (void *) (2 * sizeof(glm::vec3)));
166 check_opengl_error("glVertexAttribPointer");
167 glEnableVertexAttribArray(1);
168
169 // Set uniforms
170 int window_width = window::get_width();
171 int window_height = window::get_height();
173 t.set_view(this->cam->get_view_matrix());
174 t.set_projection(this->cam->get_projection_matrix(window_width, window_height));
175 t.set_model(glm::mat4(1.0f));
176 t.set_shader("particle_render");
177 shader::set_int("particle_render", "atlas_width", this->atlas_width);
178 shader::set_int("particle_render", "atlas_height", this->atlas_height);
179 shader::set_int("particle_render", "atlas_index", this->atlas_index);
180 shader::set_float("particle_render", "scale", this->scale);
181 shader::set_float("particle_render", "aspect_ratio",
182 (float) window_width
183 / (float) window_height);
184
185 // Set Textures
186 texture::active_texture(GL_TEXTURE0);
187 texture::bind_texture(GL_TEXTURE_2D, this->atlas, GL_REPEAT, GL_NEAREST,
188 GL_NEAREST, GL_TRUE, GL_NEAREST_MIPMAP_NEAREST,
189 GL_NEAREST);
190
191 glDrawArrays(GL_POINTS, 0, num_particles);
192 check_opengl_error("glDrawArrays");
193
194 glBindBuffer(GL_ARRAY_BUFFER, 0);
195 glBindVertexArray(0);
196 vao.unbind();
197}
198
199void particle_emitter::check_opengl_error(const std::string &function_name)
200{
201 GLenum error;
202 while ((error = glGetError()) != GL_NO_ERROR)
203 {
204 std::cerr << "OpenGL Error after " << function_name << ": " << error
205 << std::endl;
206 }
207}
208
209//
210// Builder functions
211//
212
214particle_emitter::builder::starting_position(glm::vec3 starting_position)
215{
216 this->conf.starting_position = starting_position;
217 return *this;
218}
219
221particle_emitter::builder::starting_velocity(glm::vec3 starting_velocity)
222{
223 this->conf.starting_velocity = starting_velocity;
224 return *this;
225}
226
228particle_emitter::builder::starting_spread(glm::vec3 starting_spread)
229{
230 this->conf.starting_spread = starting_spread;
231 return *this;
232}
233
234particle_emitter::builder &particle_emitter::builder::starting_time_to_live(
235 float starting_time_to_live)
236{
237 this->conf.starting_time_to_live = starting_time_to_live;
238 return *this;
239}
240
242particle_emitter::builder::num_particles(int num_particles)
243{
244 this->conf.num_particles = num_particles;
245 return *this;
246}
247
249particle_emitter::builder::spawn_rate(float spawn_rate)
250{
251 this->conf.spawn_rate = spawn_rate;
252 return *this;
253}
254
255particle_emitter::builder &particle_emitter::builder::scale(float scale)
256{
257 this->conf.scale = scale;
258 return *this;
259}
260
262particle_emitter::builder::atlas_path(std::string atlas_path)
263{
264 this->conf.atlas_path = atlas_path;
265 return *this;
266}
267
269particle_emitter::builder::atlas_width(int atlas_width)
270{
271 this->conf.atlas_width = atlas_width;
272 return *this;
273}
274
276particle_emitter::builder::atlas_height(int atlas_height)
277{
278 this->conf.atlas_height = atlas_height;
279 return *this;
280}
281
283particle_emitter::builder::atlas_index(int atlas_index)
284{
285 this->conf.atlas_index = atlas_index;
286 return *this;
287}
288
289particle_emitter::builder &particle_emitter::builder::with_camera(camera *cam)
290{
291 this->conf.cam = cam;
292 return *this;
293}
294
295particle_emitter particle_emitter::builder::build()
296{
297 return particle_emitter(this->conf);
298}
The Camera class.
Definition camera.hpp:97
Builder pattern for ParticleEmitter.
ParticleEmitter class.
Definition particles.hpp:31
int current
Current fbo index.
Definition particles.hpp:51
types::vao vao
Vertex array object.
Definition particles.hpp:62
int atlas
Atlas texture.
Definition particles.hpp:55
types::buffer fbo[2]
Feddback buffer objects.
Definition particles.hpp:47
void update_particles(float deltaTime)
Update the particles.
Definition particles.cpp:98
static bool set_vec3(types::shader_name_t shader_name, const GLchar *name, float x, float y, float z)
Set a 3D vector in the shader.
Definition shader.cpp:140
static bool create(std::string shader_name, GLenum type, std::string path, Args... args)
Create a new shader.
Definition shader.hpp:71
static bool set_int(types::shader_name_t shader_name, const GLchar *name, int value)
Set an integer in the shader.
Definition shader.cpp:63
static bool use(types::shader_name_t shader_name)
Use the shader.
Definition shader.cpp:24
static bool set_float(types::shader_name_t shader_name, const GLchar *name, float value)
Set a float in the shader.
Definition shader.cpp:89
static void active_texture(GLenum texture)
Activate a texture unit.
Definition texture.cpp:24
static unsigned int load_texture(std::string path, bool flip=true)
Load a texture from a file.
Definition texture.cpp:15
static void bind_texture(GLenum target, unsigned int texture, GLint wrapping=GL_REPEAT, GLint filtering_min=GL_NEAREST, GLint filtering_mag=GL_NEAREST, GLboolean hasMipmap=GL_TRUE, GLint mipmap_min=GL_LINEAR_MIPMAP_LINEAR, GLint mipmap_mag=GL_LINEAR)
Bind a texture.
Definition texture.cpp:29
Buffer wrapper around OpenGL buffer objects.
Definition buffer.hpp:30
void destroy()
Delete the buffer object.
Definition buffer.cpp:54
Translation util class.
void set_projection(glm::mat4 projection)
Set the projection matrix.
void set_model(glm::mat4 model)
Set the model matrix.
void set_view(glm::mat4 view)
Set the view matrix.
bool set_shader(types::shader_name_t shader_name)
Set the shader.
void bind()
Bind the VAO.
Definition vao.cpp:26
void unbind()
Unbind the VAO.
Definition vao.cpp:36
void init()
Init Constructor.
Definition vao.cpp:11