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/gl.hpp>
7#include <brenta/camera.hpp>
8#include <brenta/particles.hpp>
9#include <brenta/window.hpp>
10#include <brenta/shader.hpp>
11#include <brenta/texture.hpp>
12#include <brenta/translation.hpp>
13
14#include <iostream>
15#include <time.h>
16
17using namespace brenta;
18
19const particle_emitter::config particle_emitter::default_config = {
20 glm::vec3(0.0f, 0.0f, 0.0f),
21 glm::vec3(0.0f, 0.0f, 0.0f),
22 glm::vec3(0.0f, 0.0f, 0.0f),
23 1.0f,
24 MAX_PARTICLES,
25 0.01f,
26 1.0f,
27 "",
28 8,
29 8,
30 0,
31 nullptr,
32};
33
34particle_emitter::particle_emitter(config conf)
35{
36 this->starting_position = conf.starting_position;
37 this->starting_velocity = conf.starting_velocity;
38 this->starting_spread = conf.starting_spread;
39 this->starting_time_to_live = conf.starting_time_to_live;
40 this->num_particles = conf.num_particles;
41 this->spawn_rate = conf.spawn_rate;
42 this->scale = conf.scale;
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 = std::move(texture(conf.atlas_path, false));
51
52 // Create shaders
53 const GLchar *varyings[] = {"outPosition", "outVelocity", "outTTL"};
54 shader::create(varyings, 3, "particle_update",
55 shader::type::vertex, "src/shaders/particle_update.vs");
56 shader::create("particle_render",
57 shader::type::vertex, "src/shaders/particle_render.vs",
58 shader::type::geometry, "src/shaders/particle_render.gs",
59 shader::type::fragment, "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 gl::check_error();
67
68 // Create fbos
69 this->fbo[0].init(GL_TRANSFORM_FEEDBACK_BUFFER);
70 this->fbo[1].init(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 gl::check_error();
83
84 // Unbind buffers
85 glBindBuffer(GL_ARRAY_BUFFER, 0);
86 glBindVertexArray(0);
87 this->vao.unbind();
88}
89
90// Update particles using Transform Feedback
91// directly from the wiki
93{
94 shader::use("particle_update");
95 shader::set_float("particle_update", "deltaTime", delta_time);
96 shader::set_vec3("particle_update", "emitterPos", this->starting_position);
97 shader::set_vec3("particle_update", "emitterSpread", this->starting_spread);
98 shader::set_float("particle_update", "spawnProbability", this->spawn_rate);
99 shader::set_vec3("particle_update", "emitterVel", this->starting_velocity);
100 shader::set_float("particle_update", "emitterTTL",
101 this->starting_time_to_live);
102 gl::check_error();
103
104 this->vao.bind();
105
106 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, fbo[current].id);
107 gl::check_error();
108
109 glBindBuffer(GL_ARRAY_BUFFER, fbo[!current].id);
110 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,
111 2 * sizeof(glm::vec3) + sizeof(float), (void *) 0);
112 glEnableVertexAttribArray(0);
113 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE,
114 2 * sizeof(glm::vec3) + sizeof(float),
115 (void *) sizeof(glm::vec3));
116 glEnableVertexAttribArray(1);
117 glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE,
118 2 * sizeof(glm::vec3) + sizeof(float),
119 (void *) (2 * sizeof(glm::vec3)));
120 glEnableVertexAttribArray(2);
121
122 // Start transform feedback
123 glEnable(GL_RASTERIZER_DISCARD); // Disable rasterization
124 glBeginTransformFeedback(GL_POINTS); // Enter transform feedback mode
125 gl::check_error();
126
127 glDrawArrays(GL_POINTS, 0, num_particles);
128 gl::check_error();
129
130 glEndTransformFeedback(); // Exit transform feedback mode
131 glDisable(GL_RASTERIZER_DISCARD); // Enable rasterization
132 // Unbind buffers
133 glBindVertexArray(0);
134 glBindBuffer(GL_ARRAY_BUFFER, 0);
135 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);
136 this->vao.unbind();
137 current = !current; // Swap buffers
138}
139
140// Render particles
141void particle_emitter::render_particles()
142{
143 if (this->cam == nullptr)
144 {
145 ERROR("particle_emitter::render_particles: Camera not set or null for emitter");
146 return;
147 }
148
149 shader::use("particle_render");
150
151 this->vao.bind();
152
153 glBindBuffer(GL_ARRAY_BUFFER, fbo[current].id);
154 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,
155 2 * sizeof(glm::vec3) + sizeof(float), (void *) 0);
156 glEnableVertexAttribArray(0);
157 glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE,
158 2 * sizeof(glm::vec3) + sizeof(float),
159 (void *) (2 * sizeof(glm::vec3)));
160 gl::check_error();
161 glEnableVertexAttribArray(1);
162
163 // Set uniforms
164 int window_width = window::get_width();
165 int window_height = window::get_height();
167 t.set_view(this->cam->get_view_matrix());
168 t.set_projection(this->cam->get_projection_matrix(window_width, window_height));
169 t.set_model(glm::mat4(1.0f));
170 t.set_shader("particle_render");
171 shader::set_int("particle_render", "atlas_width", this->atlas_width);
172 shader::set_int("particle_render", "atlas_height", this->atlas_height);
173 shader::set_int("particle_render", "atlas_index", this->atlas_index);
174 shader::set_float("particle_render", "scale", this->scale);
175 shader::set_float("particle_render", "aspect_ratio",
176 (float) window_width
177 / (float) window_height);
178
179 // Set Textures
180 texture::active_texture(GL_TEXTURE0);
181 this->atlas.bind(GL_TEXTURE_2D, GL_REPEAT, GL_NEAREST,
182 GL_NEAREST, GL_TRUE, GL_NEAREST_MIPMAP_NEAREST,
183 GL_NEAREST);
184
185 glDrawArrays(GL_POINTS, 0, num_particles);
186 gl::check_error();
187
188 glBindBuffer(GL_ARRAY_BUFFER, 0);
189 glBindVertexArray(0);
190 vao.unbind();
191}
192
193//
194// Builder functions
195//
196
198particle_emitter::builder::starting_position(glm::vec3 starting_position)
199{
200 this->conf.starting_position = starting_position;
201 return *this;
202}
203
205particle_emitter::builder::starting_velocity(glm::vec3 starting_velocity)
206{
207 this->conf.starting_velocity = starting_velocity;
208 return *this;
209}
210
212particle_emitter::builder::starting_spread(glm::vec3 starting_spread)
213{
214 this->conf.starting_spread = starting_spread;
215 return *this;
216}
217
218particle_emitter::builder &particle_emitter::builder::starting_time_to_live(
219 float starting_time_to_live)
220{
221 this->conf.starting_time_to_live = starting_time_to_live;
222 return *this;
223}
224
226particle_emitter::builder::num_particles(int num_particles)
227{
228 this->conf.num_particles = num_particles;
229 return *this;
230}
231
233particle_emitter::builder::spawn_rate(float spawn_rate)
234{
235 this->conf.spawn_rate = spawn_rate;
236 return *this;
237}
238
239particle_emitter::builder &particle_emitter::builder::scale(float scale)
240{
241 this->conf.scale = scale;
242 return *this;
243}
244
246particle_emitter::builder::atlas_path(std::string atlas_path)
247{
248 this->conf.atlas_path = atlas_path;
249 return *this;
250}
251
253particle_emitter::builder::atlas_width(int atlas_width)
254{
255 this->conf.atlas_width = atlas_width;
256 return *this;
257}
258
260particle_emitter::builder::atlas_height(int atlas_height)
261{
262 this->conf.atlas_height = atlas_height;
263 return *this;
264}
265
267particle_emitter::builder::atlas_index(int atlas_index)
268{
269 this->conf.atlas_index = atlas_index;
270 return *this;
271}
272
273particle_emitter::builder &particle_emitter::builder::with_camera(camera *cam)
274{
275 this->conf.cam = cam;
276 return *this;
277}
278
279particle_emitter particle_emitter::builder::build()
280{
281 return particle_emitter(this->conf);
282}
The Camera class.
Definition camera.hpp:81
Builder pattern for ParticleEmitter.
Particle Emitter class.
Definition particles.hpp:32
int current
Current fbo index.
Definition particles.hpp:52
types::vao vao
Vertex array object.
Definition particles.hpp:63
types::buffer fbo[2]
Feddback buffer objects.
Definition particles.hpp:48
void update_particles(float delta_time)
Update the particles.
Definition particles.cpp:92
texture atlas
Atlas texture.
Definition particles.hpp:56
static bool use(shader::name_t shader_name)
Use the shader.
Definition shader.cpp:24
static bool set_float(shader::name_t shader_name, const GLchar *name, float value)
Set a float in the shader.
Definition shader.cpp:89
static bool set_vec3(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(const std::string &shader_name, shader::type type, const std::string &path, Args... args)
Create a new shader.
Definition shader.hpp:75
static bool set_int(shader::name_t shader_name, const GLchar *name, int value)
Set an integer in the shader.
Definition shader.cpp:63
Texture class.
Definition texture.hpp:20
static void active_texture(GLenum texture)
Activate a texture unit.
Definition texture.cpp:39
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(shader::name_t shader_name)
Set the shader.