6#include <brenta/renderer/opengl/gl.hpp>
7#include <brenta/renderer/camera.hpp>
8#include <brenta/renderer/particles.hpp>
9#include <brenta/renderer/opengl/shader.hpp>
10#include <brenta/renderer/opengl/texture.hpp>
11#include <brenta/asset.hpp>
12#include <brenta/logger.hpp>
17#include "./shaders/c/particle_render_fs.c"
18#include "./shaders/c/particle_render_vs.c"
19#include "./shaders/c/particle_render_gs.c"
20#include "./shaders/c/particle_update_vs.c"
31 float spawnProbability;
32 glm::vec3 emitterSpread;
38using namespace brenta;
40ParticleEmitter::ParticleEmitter(Config conf)
42 this->starting_position = conf.starting_position;
43 this->starting_velocity = conf.starting_velocity;
44 this->starting_spread = conf.starting_spread;
45 this->starting_time_to_live = conf.starting_time_to_live;
46 this->num_particles = conf.num_particles;
47 this->spawn_rate = conf.spawn_rate;
48 this->scale = conf.scale;
49 this->atlas_width = conf.atlas_width;
50 this->atlas_height = conf.atlas_height;
51 this->atlas_index = conf.atlas_index;
52 this->current_fbo_index = 0;
58 .target(Texture::Target::Texture2D)
59 .path(conf.atlas_path)
61 .set_wrapping(Texture::Wrapping::Repeat)
62 .set_filtering_min(Texture::Filtering::Nearest)
63 .set_filtering_mag(Texture::Filtering::Nearest)
64 .set_has_mipmap(Gl::True)
65 .set_mipmap_min(Texture::Filtering::NearestMipmapNearest)
66 .set_mipmap_mag(Texture::Filtering::Nearest))
70 const GLchar *varyings[] = {
"outPosition",
"outVelocity",
"outTTL"};
72 AssetManager::new_asset<Shader>(
"particle_update_shader",
75 sizeof(varyings) /
sizeof(varyings[0]))
80 if (!this->shader_update)
return;
82 this->shader_render = AssetManager::new_asset<Shader>(
"particole_render_shader",
85 { Shader::Type::Vertex, particle_render_vs },
86 { Shader::Type::Geometry, particle_render_gs },
87 { Shader::Type::Fragment, particle_render_fs }}));
88 if (!this->shader_render)
return;
91 glEnable(GL_PROGRAM_POINT_SIZE);
98 this->fbo[0].init(Buffer::Target::TransformFeedback);
99 this->fbo[1].init(Buffer::Target::TransformFeedback);
102 this->fbo[0].copy_data(NULL, this->num_particles * 2 *
sizeof(glm::vec3)
103 + this->num_particles *
sizeof(
float),
104 Buffer::DataUsage::DynamicCopy);
106 this->fbo[1].copy_data(NULL,
107 this->num_particles * 2 *
sizeof(glm::vec3)
108 + this->num_particles *
sizeof(
float),
109 Buffer::DataUsage::DynamicCopy);
113 this->fbo[0].unbind();
117 this->ubo.init(*this->shader_update,
"settings", 3,
sizeof(
ParticleSettings));
119 this->ubo.copy_data(NULL,
121 Buffer::DataUsage::DynamicDraw);
128void ParticleEmitter::update(
float delta_time)
130 if (!this->shader_update)
return;
131 this->shader_update->use();
134 .gravity = glm::vec3(0.0f, -9.81f, 0.0f),
135 .deltaTime = delta_time,
136 .emitterVel = this->starting_velocity,
137 .emitterTTL = this->starting_time_to_live,
138 .emitterPos = this->starting_position,
139 .spawnProbability = this->spawn_rate,
140 .emitterSpread = this->starting_spread,
148 Buffer::DataUsage::DynamicDraw);
155 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, fbo[current_fbo_index].get_id());
157 glBindBuffer(GL_ARRAY_BUFFER, fbo[!current_fbo_index].get_id());
158 this->vao.link_buffer(this->fbo[!current_fbo_index],
159 0, 3, Gl::Float, Gl::False,
160 2 *
sizeof(glm::vec3) +
sizeof(
float), (
void *) 0);
161 this->vao.link_buffer(this->fbo[!current_fbo_index],
162 1, 3, Gl::Float, Gl::False,
163 2 *
sizeof(glm::vec3) +
sizeof(
float),
164 (
void *)
sizeof(glm::vec3));
165 this->vao.link_buffer(this->fbo[!current_fbo_index],
166 2, 1, Gl::Float, Gl::False,
167 2 *
sizeof(glm::vec3) +
sizeof(
float),
168 (
void *) (2 *
sizeof(glm::vec3)));
171 glEnable(GL_RASTERIZER_DISCARD);
172 glBeginTransformFeedback(GL_POINTS);
175 glDrawArrays(GL_POINTS, 0, num_particles);
178 glEndTransformFeedback();
179 glDisable(GL_RASTERIZER_DISCARD);
182 glBindBuffer(GL_ARRAY_BUFFER, 0);
184 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);
189void ParticleEmitter::render(
int width,
int height)
191 tenno::shared_ptr<Camera> camera = this->cam.lock();
194 ERROR(
"ParticleEmitter::render_particles: Camera not set or null for emitter");
198 if (!this->shader_render)
return;
202 glBindBuffer(GL_ARRAY_BUFFER, fbo[current_fbo_index].get_id());
203 this->vao.link_buffer(this->fbo[current_fbo_index],
204 0, 3, Gl::Float, Gl::False,
205 2 *
sizeof(glm::vec3) +
sizeof(
float), (
void *) 0);
206 this->vao.link_buffer(this->fbo[current_fbo_index],
207 1, 1, Gl::Float, Gl::False,
208 2 *
sizeof(glm::vec3) +
sizeof(
float),
209 (
void *) (2 *
sizeof(glm::vec3)));
214 camera->get_projection_matrix(width, height);
216 shader_render->use();
217 shader_render->set_mat4(
"view", camera->get_view_matrix());
218 shader_render->set_mat4(
"projection", projection);
219 shader_render->set_mat4(
"model", glm::mat4(1.0f));
220 shader_render->set_int(
"atlas_width", this->atlas_width);
221 shader_render->set_int(
"atlas_height", this->atlas_height);
222 shader_render->set_int(
"atlas_index", this->atlas_index);
223 shader_render->set_float(
"scale", this->scale);
224 shader_render->set_float(
"aspect_ratio",
225 (
float) width / (
float) height);
228 Texture::active_texture(0);
231 glDrawArrays(GL_POINTS, 0, num_particles);
234 glBindBuffer(GL_ARRAY_BUFFER, 0);
238 current_fbo_index = !current_fbo_index;
247ParticleEmitter::Builder::starting_position(glm::vec3 starting_position)
249 this->conf.starting_position = starting_position;
254ParticleEmitter::Builder::starting_velocity(glm::vec3 starting_velocity)
256 this->conf.starting_velocity = starting_velocity;
261ParticleEmitter::Builder::starting_spread(glm::vec3 starting_spread)
263 this->conf.starting_spread = starting_spread;
268 float starting_time_to_live)
270 this->conf.starting_time_to_live = starting_time_to_live;
275ParticleEmitter::Builder::num_particles(
int num_particles)
277 this->conf.num_particles = num_particles;
282ParticleEmitter::Builder::spawn_rate(
float spawn_rate)
284 this->conf.spawn_rate = spawn_rate;
290 this->conf.scale = scale;
295ParticleEmitter::Builder::atlas_path(
const std::filesystem::path &atlas_path)
297 this->conf.atlas_path = atlas_path;
302ParticleEmitter::Builder::atlas_width(
int atlas_width)
304 this->conf.atlas_width = atlas_width;
309ParticleEmitter::Builder::atlas_height(
int atlas_height)
311 this->conf.atlas_height = atlas_height;
316ParticleEmitter::Builder::atlas_index(
int atlas_index)
318 this->conf.atlas_index = atlas_index;
323ParticleEmitter::Builder::with_camera(tenno::weak_ptr<Camera> cam)
325 this->conf.cam = cam;