Brenta Engine 1.0
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 camera = nullptr;
55}
56
58 glm::vec3 starting_position, glm::vec3 starting_velocity,
59 glm::vec3 starting_spread, float starting_timeToLive, int num_particles,
60 float spawn_rate, float scale, std::string atlas_path, int atlas_width,
61 int atlas_height, int atlas_index, Camera *camera)
62{
63 this->starting_position = starting_position;
64 this->starting_velocity = starting_velocity;
65 this->starting_spread = starting_spread;
66 this->starting_timeToLive = starting_timeToLive;
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->camera = camera;
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"};
84 Shader::New(varyings, 3, "particle_update", GL_VERTEX_SHADER,
85 std::filesystem::absolute("engine/shaders/particle_update.vs"));
87 "particle_render", GL_VERTEX_SHADER,
88 std::filesystem::absolute("engine/shaders/particle_render.vs").string(),
89 GL_GEOMETRY_SHADER,
90 std::filesystem::absolute("engine/shaders/particle_render.gs").string(),
91 GL_FRAGMENT_SHADER,
92 std::filesystem::absolute("engine/shaders/particle_render.fs").string());
93
94 // This is needed to render points
95 glEnable(GL_PROGRAM_POINT_SIZE);
96
97 this->vao.Init();
98 this->vao.Bind();
99 checkOpenGLError("vao bind");
100
101 // Create fbos
102 this->fbo[0] = Types::Buffer(GL_TRANSFORM_FEEDBACK_BUFFER);
103 this->fbo[1] = Types::Buffer(GL_TRANSFORM_FEEDBACK_BUFFER);
104
105 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, this->fbo[0].id);
106 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER,
107 this->num_particles * 2 * sizeof(glm::vec3)
108 + this->num_particles * sizeof(float),
109 NULL, GL_DYNAMIC_COPY);
110 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, this->fbo[1].id);
111 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER,
112 this->num_particles * 2 * sizeof(glm::vec3)
113 + this->num_particles * sizeof(float),
114 NULL, GL_DYNAMIC_COPY);
115 checkOpenGLError("glBindBufferBase A");
116
117 // Unbind buffers
118 glBindBuffer(GL_ARRAY_BUFFER, 0);
119 glBindVertexArray(0);
120 this->vao.Unbind();
121}
122
124{
125 fbo[0].Delete();
126 fbo[1].Delete();
127 INFO("Deleted ParticleEmitter");
128}
129
130// Update particles using Transform Feedback
131// directly from the wiki
133{
134 Shader::Use("particle_update");
135 Shader::SetFloat("particle_update", "deltaTime", deltaTime);
136 Shader::SetVec3("particle_update", "emitterPos", this->starting_position);
137 Shader::SetVec3("particle_update", "emitterSpread", this->starting_spread);
138 Shader::SetFloat("particle_update", "spawnProbability", this->spawn_rate);
139 Shader::SetVec3("particle_update", "emitterVel", this->starting_velocity);
140 Shader::SetFloat("particle_update", "emitterTTL",
141 this->starting_timeToLive);
142 checkOpenGLError("settin update shader");
143
144 this->vao.Bind();
145
146 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, fbo[current].id);
147 checkOpenGLError("glBindBufferBase B");
148
149 glBindBuffer(GL_ARRAY_BUFFER, fbo[!current].id);
150 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,
151 2 * sizeof(glm::vec3) + sizeof(float), (void *) 0);
152 glEnableVertexAttribArray(0);
153 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE,
154 2 * sizeof(glm::vec3) + sizeof(float),
155 (void *) sizeof(glm::vec3));
156 glEnableVertexAttribArray(1);
157 glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE,
158 2 * sizeof(glm::vec3) + sizeof(float),
159 (void *) (2 * sizeof(glm::vec3)));
160 glEnableVertexAttribArray(2);
161
162 // Start transform feedback
163 glEnable(GL_RASTERIZER_DISCARD); // Disable rasterization
164 glBeginTransformFeedback(GL_POINTS); // Enter transform feedback mode
165 checkOpenGLError("glBeginTransformFeedback");
166
167 glDrawArrays(GL_POINTS, 0, num_particles);
168 checkOpenGLError("glDrawTransformFeedback");
169
170 glEndTransformFeedback(); // Exit transform feedback mode
171 glDisable(GL_RASTERIZER_DISCARD); // Enable rasterization
172 // Unbind buffers
173 glBindVertexArray(0);
174 glBindBuffer(GL_ARRAY_BUFFER, 0);
175 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);
176 this->vao.Unbind();
177 current = !current; // Swap buffers
178}
179
180// Render particles
182{
183 if (camera == nullptr)
184 {
185 ERROR("Camera not set or null for ParticleEmitter");
186 return;
187 }
188
189 Shader::Use("particle_render");
190
191 this->vao.Bind();
192
193 glBindBuffer(GL_ARRAY_BUFFER, fbo[current].id);
194 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,
195 2 * sizeof(glm::vec3) + sizeof(float), (void *) 0);
196 glEnableVertexAttribArray(0);
197 glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE,
198 2 * sizeof(glm::vec3) + sizeof(float),
199 (void *) (2 * sizeof(glm::vec3)));
200 checkOpenGLError("glVertexAttribPointer");
201 glEnableVertexAttribArray(1);
202
203 // Set uniforms
205 t.setView(camera->GetViewMatrix());
207 t.setModel(glm::mat4(1.0f));
208 t.setShader("particle_render");
209 Shader::SetInt("particle_render", "atlas_width", this->atlas_width);
210 Shader::SetInt("particle_render", "atlas_height", this->atlas_height);
211 Shader::SetInt("particle_render", "atlas_index", this->atlas_index);
212 Shader::SetFloat("particle_render", "scale", this->scale);
213 Shader::SetFloat("particle_render", "aspect_ratio",
214 (float) Screen::GetWidth() / (float) Screen::GetHeight());
215
216 // Set Textures
217 Texture::ActiveTexture(GL_TEXTURE0);
218 Texture::BindTexture(GL_TEXTURE_2D, this->atlas, GL_REPEAT, GL_NEAREST,
219 GL_NEAREST, GL_TRUE, GL_NEAREST_MIPMAP_NEAREST,
220 GL_NEAREST);
221
222 glDrawArrays(GL_POINTS, 0, num_particles);
223 checkOpenGLError("glDrawArrays");
224
225 glBindBuffer(GL_ARRAY_BUFFER, 0);
226 glBindVertexArray(0);
227 vao.Unbind();
228}
229
230void ParticleEmitter::checkOpenGLError(const std::string &functionName)
231{
232 GLenum error;
233 while ((error = glGetError()) != GL_NO_ERROR)
234 {
235 std::cerr << "OpenGL Error after " << functionName << ": " << error
236 << std::endl;
237 }
238}
239
241ParticleEmitter::Builder::set_starting_position(glm::vec3 starting_position)
242{
243 this->starting_position = starting_position;
244 return *this;
245}
246
248ParticleEmitter::Builder::set_starting_velocity(glm::vec3 starting_velocity)
249{
250 this->starting_velocity = starting_velocity;
251 return *this;
252}
253
255ParticleEmitter::Builder::set_starting_spread(glm::vec3 starting_spread)
256{
257 this->starting_spread = starting_spread;
258 return *this;
259}
260
262ParticleEmitter::Builder::set_starting_timeToLive(float starting_timeToLive)
263{
264 this->starting_timeToLive = starting_timeToLive;
265 return *this;
266}
267
269ParticleEmitter::Builder::set_num_particles(int num_particles)
270{
271 this->num_particles = num_particles;
272 return *this;
273}
274
276ParticleEmitter::Builder::set_spawn_rate(float spawn_rate)
277{
278 this->spawn_rate = spawn_rate;
279 return *this;
280}
281
282ParticleEmitter::Builder &ParticleEmitter::Builder::set_scale(float scale)
283{
284 this->scale = scale;
285 return *this;
286}
287
289ParticleEmitter::Builder::set_atlas_path(std::string atlas_path)
290{
291 this->atlas_path = atlas_path;
292 return *this;
293}
294
296ParticleEmitter::Builder::set_atlas_width(int atlas_width)
297{
298 this->atlas_width = atlas_width;
299 return *this;
300}
301
303ParticleEmitter::Builder::set_atlas_height(int atlas_height)
304{
305 this->atlas_height = atlas_height;
306 return *this;
307}
308
310ParticleEmitter::Builder::set_atlas_index(int atlas_index)
311{
312 this->atlas_index = atlas_index;
313 return *this;
314}
315
316ParticleEmitter::Builder &ParticleEmitter::Builder::set_camera(Camera *camera)
317{
318 this->camera = camera;
319 return *this;
320}
321
322ParticleEmitter ParticleEmitter::Builder::build()
323{
324 /* C++17 has RVO (Return Value Optimization) so move is implicit */
327 this->num_particles, this->spawn_rate, this->scale,
328 this->atlas_path, this->atlas_width,
329 this->atlas_height, this->atlas_index, this->camera);
330}
The Camera class.
Definition camera.hpp:120
glm::mat4 GetProjectionMatrix()
Get the projection matrix.
Definition camera.cpp:88
glm::mat4 GetViewMatrix()
Get the view matrix.
Definition camera.cpp:75
Builder pattern for ParticleEmitter.
ParticleEmitter class.
Definition particles.hpp:54
int atlas_width
Atlas width.
float spawn_rate
Spawn rate of particles.
Definition particles.hpp:79
glm::vec3 starting_position
Starting position of a new particle.
Definition particles.hpp:59
ParticleEmitter()
Empty constructor.
Definition particles.cpp:40
float scale
Scale of particles.
Definition particles.hpp:83
int atlas_height
Atlas height.
int num_particles
Number of particles.
Definition particles.hpp:75
int atlas
Atlas texture.
Definition particles.hpp:98
glm::vec3 starting_spread
Starting spread of a new particle.
Definition particles.hpp:67
~ParticleEmitter()
Destroy the ParticleEmitter object.
Types::Buffer fbo[2]
Feddback buffer objects.
Definition particles.hpp:90
void updateParticles(float deltaTime)
Update the particles.
void renderParticles()
Render the particles.
int atlas_index
Atlas index.
Types::VAO vao
Vertex array object.
int current
Current fbo index.
Definition particles.hpp:94
float starting_timeToLive
Time to live of a new particle.
Definition particles.hpp:71
glm::vec3 starting_velocity
Starting velocity of a new particle.
Definition particles.hpp:63
static int GetHeight()
Get the height of the window.
Definition screen.cpp:110
static int GetWidth()
Get the width of the window.
Definition screen.cpp:105
static void SetVec3(Types::ShaderName shader_name, const GLchar *name, float x, float y, float z)
Set a 3D vector in the shader.
Definition shader.cpp:103
static void SetInt(Types::ShaderName shader_name, const std::string &name, int value)
Set an integer in the shader.
Definition shader.cpp:67
static void New(std::string shader_name, GLenum type, std::string path, Args... args)
Create a new shader.
Definition shader.hpp:93
static void SetFloat(Types::ShaderName shader_name, const std::string &name, float value)
Set a float in the shader.
Definition shader.cpp:79
static void Use(Types::ShaderName shader_name)
Use the shader.
Definition shader.cpp:43
static void BindTexture(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:56
static void ActiveTexture(GLenum texture)
Activate a texture unit.
Definition texture.cpp:51
static unsigned int LoadTexture(std::string path, 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, bool flip=true)
Load a texture from a file.
Definition texture.cpp:36
Buffer wrapper around OpenGL buffer objects.
Definition buffer.hpp:50
void Delete()
Delete the buffer object.
Definition buffer.cpp:77
Translation util class.
void setProjection(glm::mat4 projection)
Set the projection matrix.
void setView(glm::mat4 view)
Set the view matrix.
void setModel(glm::mat4 model)
Set the model matrix.
void setShader(Types::ShaderName shader_name)
Set the shader.
void Init()
Init Constructor.
Definition vao.cpp:33
void Unbind()
Unbind the VAO.
Definition vao.cpp:59
void Bind()
Bind the VAO.
Definition vao.cpp:49