Brenta Engine 1.1
Loading...
Searching...
No Matches
particles.cpp
1/*
2 * MIT License
3 *
4 * Copyright (c) 2024 Giovanni Santini
5
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 all
15 * copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 *
25 */
26
27#include "particles.hpp"
28
29#include "camera.hpp"
30#include "shader.hpp"
31#include "texture.hpp"
32#include "translation.hpp"
33
34#include <filesystem>
35#include <iostream>
36#include <time.h>
37
38using namespace brenta;
39
41{
42 starting_position = glm::vec3(0.0f, 0.0f, 0.0f);
43 starting_velocity = glm::vec3(0.0f, 0.0f, 0.0f);
44 starting_spread = glm::vec3(0.0f, 0.0f, 0.0f);
46 num_particles = MAX_PARTICLES;
47 spawn_rate = 0.01f;
48 scale = 1.0f;
49 atlas = 0;
50 atlas_width = 8;
51 atlas_height = 8;
52 atlas_index = 0;
53 current = 0;
54 cam = nullptr;
55}
56
58 glm::vec3 starting_position, glm::vec3 starting_velocity,
59 glm::vec3 starting_spread, float starting_time_to_live, int num_particles,
60 float spawn_rate, float scale, std::string atlas_path, int atlas_width,
61 int atlas_height, int atlas_index, camera *cam)
62{
63 this->starting_position = starting_position;
64 this->starting_velocity = starting_velocity;
65 this->starting_spread = starting_spread;
66 this->starting_time_to_live = starting_time_to_live;
67 this->num_particles = num_particles;
68 this->spawn_rate = spawn_rate;
69 this->scale = scale;
70 this->atlas = atlas;
71 this->atlas_width = atlas_width;
72 this->atlas_height = atlas_height;
73 this->atlas_index = atlas_index;
74 this->current = 0;
75 this->cam = cam;
76
77 // Load Texture Atlas
79 atlas_path, GL_REPEAT, GL_NEAREST, GL_NEAREST, GL_TRUE,
80 GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST, false);
81
82 // Create shaders
83 const GLchar *varyings[] = {"outPosition", "outVelocity", "outTTL"};
85 varyings, 3, "particle_update", GL_VERTEX_SHADER,
86 std::filesystem::absolute("engine/shaders/particle_update.vs"));
88 "particle_render", GL_VERTEX_SHADER,
89 std::filesystem::absolute("engine/shaders/particle_render.vs").string(),
90 GL_GEOMETRY_SHADER,
91 std::filesystem::absolute("engine/shaders/particle_render.gs").string(),
92 GL_FRAGMENT_SHADER,
93 std::filesystem::absolute("engine/shaders/particle_render.fs")
94 .string());
95
96 // This is needed to render points
97 glEnable(GL_PROGRAM_POINT_SIZE);
98
99 this->vao.init();
100 this->vao.bind();
101 check_opengl_error("vao bind");
102
103 // Create fbos
104 this->fbo[0] = types::buffer(GL_TRANSFORM_FEEDBACK_BUFFER);
105 this->fbo[1] = types::buffer(GL_TRANSFORM_FEEDBACK_BUFFER);
106
107 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, this->fbo[0].id);
108 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER,
109 this->num_particles * 2 * sizeof(glm::vec3)
110 + this->num_particles * sizeof(float),
111 NULL, GL_DYNAMIC_COPY);
112 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, this->fbo[1].id);
113 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER,
114 this->num_particles * 2 * sizeof(glm::vec3)
115 + this->num_particles * sizeof(float),
116 NULL, GL_DYNAMIC_COPY);
117 check_opengl_error("glBindBufferBase A");
118
119 // Unbind buffers
120 glBindBuffer(GL_ARRAY_BUFFER, 0);
121 glBindVertexArray(0);
122 this->vao.unbind();
123}
124
126{
127 fbo[0].destroy();
128 fbo[1].destroy();
129 INFO("Deleted ParticleEmitter");
130}
131
132// Update particles using Transform Feedback
133// directly from the wiki
135{
136 shader::use("particle_update");
137 shader::set_float("particle_update", "deltaTime", delta_time);
138 shader::set_vec3("particle_update", "emitterPos", this->starting_position);
139 shader::set_vec3("particle_update", "emitterSpread", this->starting_spread);
140 shader::set_float("particle_update", "spawnProbability", this->spawn_rate);
141 shader::set_vec3("particle_update", "emitterVel", this->starting_velocity);
142 shader::set_float("particle_update", "emitterTTL",
144 check_opengl_error("settin update shader");
145
146 this->vao.bind();
147
148 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, fbo[current].id);
149 check_opengl_error("glBindBufferBase B");
150
151 glBindBuffer(GL_ARRAY_BUFFER, fbo[!current].id);
152 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,
153 2 * sizeof(glm::vec3) + sizeof(float), (void *) 0);
154 glEnableVertexAttribArray(0);
155 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE,
156 2 * sizeof(glm::vec3) + sizeof(float),
157 (void *) sizeof(glm::vec3));
158 glEnableVertexAttribArray(1);
159 glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE,
160 2 * sizeof(glm::vec3) + sizeof(float),
161 (void *) (2 * sizeof(glm::vec3)));
162 glEnableVertexAttribArray(2);
163
164 // Start transform feedback
165 glEnable(GL_RASTERIZER_DISCARD); // Disable rasterization
166 glBeginTransformFeedback(GL_POINTS); // Enter transform feedback mode
167 check_opengl_error("glBeginTransformFeedback");
168
169 glDrawArrays(GL_POINTS, 0, num_particles);
170 check_opengl_error("glDrawTransformFeedback");
171
172 glEndTransformFeedback(); // Exit transform feedback mode
173 glDisable(GL_RASTERIZER_DISCARD); // Enable rasterization
174 // Unbind buffers
175 glBindVertexArray(0);
176 glBindBuffer(GL_ARRAY_BUFFER, 0);
177 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);
178 this->vao.unbind();
179 current = !current; // Swap buffers
180}
181
182// Render particles
184{
185 if (this->cam == nullptr)
186 {
187 ERROR("Camera not set or null for ParticleEmitter");
188 return;
189 }
190
191 shader::use("particle_render");
192
193 this->vao.bind();
194
195 glBindBuffer(GL_ARRAY_BUFFER, fbo[current].id);
196 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,
197 2 * sizeof(glm::vec3) + sizeof(float), (void *) 0);
198 glEnableVertexAttribArray(0);
199 glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE,
200 2 * sizeof(glm::vec3) + sizeof(float),
201 (void *) (2 * sizeof(glm::vec3)));
202 check_opengl_error("glVertexAttribPointer");
203 glEnableVertexAttribArray(1);
204
205 // Set uniforms
207 t.set_view(this->cam->get_view_matrix());
209 t.set_model(glm::mat4(1.0f));
210 t.set_shader("particle_render");
211 shader::set_int("particle_render", "atlas_width", this->atlas_width);
212 shader::set_int("particle_render", "atlas_height", this->atlas_height);
213 shader::set_int("particle_render", "atlas_index", this->atlas_index);
214 shader::set_float("particle_render", "scale", this->scale);
215 shader::set_float("particle_render", "aspect_ratio",
216 (float) screen::get_width()
217 / (float) screen::get_height());
218
219 // Set Textures
220 texture::active_texture(GL_TEXTURE0);
221 texture::bind_texture(GL_TEXTURE_2D, this->atlas, GL_REPEAT, GL_NEAREST,
222 GL_NEAREST, GL_TRUE, GL_NEAREST_MIPMAP_NEAREST,
223 GL_NEAREST);
224
225 glDrawArrays(GL_POINTS, 0, num_particles);
226 check_opengl_error("glDrawArrays");
227
228 glBindBuffer(GL_ARRAY_BUFFER, 0);
229 glBindVertexArray(0);
230 vao.unbind();
231}
232
233void particle_emitter::check_opengl_error(const std::string &function_name)
234{
235 GLenum error;
236 while ((error = glGetError()) != GL_NO_ERROR)
237 {
238 std::cerr << "OpenGL Error after " << function_name << ": " << error
239 << std::endl;
240 }
241}
242
244particle_emitter::builder::set_starting_position(glm::vec3 starting_position)
245{
246 this->starting_position = starting_position;
247 return *this;
248}
249
251particle_emitter::builder::set_starting_velocity(glm::vec3 starting_velocity)
252{
253 this->starting_velocity = starting_velocity;
254 return *this;
255}
256
258particle_emitter::builder::set_starting_spread(glm::vec3 starting_spread)
259{
260 this->starting_spread = starting_spread;
261 return *this;
262}
263
264particle_emitter::builder &particle_emitter::builder::set_starting_time_to_live(
266{
267 this->starting_time_to_live = starting_time_to_live;
268 return *this;
269}
270
272particle_emitter::builder::set_num_particles(int num_particles)
273{
274 this->num_particles = num_particles;
275 return *this;
276}
277
279particle_emitter::builder::set_spawn_rate(float spawn_rate)
280{
281 this->spawn_rate = spawn_rate;
282 return *this;
283}
284
285particle_emitter::builder &particle_emitter::builder::set_scale(float scale)
286{
287 this->scale = scale;
288 return *this;
289}
290
292particle_emitter::builder::set_atlas_path(std::string atlas_path)
293{
294 this->atlas_path = atlas_path;
295 return *this;
296}
297
299particle_emitter::builder::set_atlas_width(int atlas_width)
300{
301 this->atlas_width = atlas_width;
302 return *this;
303}
304
306particle_emitter::builder::set_atlas_height(int atlas_height)
307{
308 this->atlas_height = atlas_height;
309 return *this;
310}
311
313particle_emitter::builder::set_atlas_index(int atlas_index)
314{
315 this->atlas_index = atlas_index;
316 return *this;
317}
318
319particle_emitter::builder &particle_emitter::builder::set_camera(camera *cam)
320{
321 this->cam = cam;
322 return *this;
323}
324
325particle_emitter particle_emitter::builder::build()
326{
327 /* C++17 has RVO (Return Value Optimization) so move is implicit */
330 this->num_particles, this->spawn_rate, this->scale,
331 this->atlas_path, this->atlas_width,
332 this->atlas_height, this->atlas_index, this->cam);
333}
The Camera class.
Definition camera.hpp:148
glm::mat4 get_projection_matrix()
Get the projection matrix.
Definition camera.cpp:88
glm::mat4 get_view_matrix()
Get the view matrix.
Definition camera.cpp:74
Builder pattern for ParticleEmitter.
ParticleEmitter class.
Definition particles.hpp:54
int current
Current fbo index.
Definition particles.hpp:94
void render_particles()
Render the particles.
glm::vec3 starting_velocity
Starting velocity of a new particle.
Definition particles.hpp:63
types::vao vao
Vertex array object.
int atlas
Atlas texture.
Definition particles.hpp:98
~particle_emitter()
Destroy the ParticleEmitter object.
float starting_time_to_live
Time to live of a new particle.
Definition particles.hpp:71
particle_emitter()
Empty constructor.
Definition particles.cpp:40
types::buffer fbo[2]
Feddback buffer objects.
Definition particles.hpp:90
float scale
Scale of particles.
Definition particles.hpp:83
void update_particles(float deltaTime)
Update the particles.
float spawn_rate
Spawn rate of particles.
Definition particles.hpp:79
int atlas_index
Atlas index.
glm::vec3 starting_spread
Starting spread of a new particle.
Definition particles.hpp:67
glm::vec3 starting_position
Starting position of a new particle.
Definition particles.hpp:59
int num_particles
Number of particles.
Definition particles.hpp:75
int atlas_width
Atlas width.
int atlas_height
Atlas height.
static int get_width()
Get the width of the window.
Definition screen.cpp:105
static int get_height()
Get the height of the window.
Definition screen.cpp:110
static void create(std::string shader_name, GLenum type, std::string path, Args... args)
Create a new shader.
Definition shader.hpp:93
static void use(types::shader_name_t shader_name)
Use the shader.
Definition shader.cpp:43
static void set_int(types::shader_name_t shader_name, const std::string &name, int value)
Set an integer in the shader.
Definition shader.cpp:66
static void 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:100
static void set_float(types::shader_name_t shader_name, const std::string &name, float value)
Set a float in the shader.
Definition shader.cpp:77
static void active_texture(GLenum texture)
Activate a texture unit.
Definition texture.cpp:52
static unsigned int load_texture(std::string path, GLint wrapping=GL_REPEAT, GLint filtering_min=GL_NEAREST, GLint filtering_mag=GL_NEAREST, GLboolean has_mipmap=GL_TRUE, GLint mipmap_min=GL_LINEAR_MIPMAP_LINEAR, GLint mipmap_mag=GL_LINEAR, bool flip=true)
Load a texture from a file.
Definition texture.cpp:37
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:57
Buffer wrapper around OpenGL buffer objects.
Definition buffer.hpp:50
void destroy()
Delete the buffer object.
Definition buffer.cpp:77
Translation util class.
void set_projection(glm::mat4 projection)
Set the projection matrix.
void set_shader(types::shader_name_t shader_name)
Set the shader.
void set_model(glm::mat4 model)
Set the model matrix.
void set_view(glm::mat4 view)
Set the view matrix.
void bind()
Bind the VAO.
Definition vao.cpp:49
void unbind()
Unbind the VAO.
Definition vao.cpp:59
void init()
Init Constructor.
Definition vao.cpp:33