Files
2026-06-08 17:07:34 -04:00

201 lines
4.9 KiB
C++

#ifndef PARTICLE_CLASS
#define PARTICLE_CLASS
#include <random>
#include <vector>
#include <map>
#include<glm/glm.hpp>
#include "common.h"
#include "Engine.h"
#include "Object.h"
#include "Mesh.h"
#include "QuadVertices.h"
#include "t.h"
#include "VAO.h"
#include "VBO.h"
#include "EBO.h"
#include "shaderClass.h"
#include "Vertex.h"
#include "texture.h"
#include "Camera.h"
#include "RenderSystem.h"
class Particle : public t_package {
public:
Particle() {
}
void Render() {
}
void Step(float dt) {
t.RotateByEulerAnglesCumulate(angularvelocity * dt);
t.TranslateBy(linearvelocity*dt);
}
glm::vec3 linearvelocity;
glm::vec3 angularvelocity;
float lifespan;
private:
};
class ParticleEmitter : public Renderable, public t_package, public Object {
public:
enum EmitDirection {
Perpendicular,
Aligned,
Outward
};
EmitDirection emitdirection = Outward;
//PARTICLE SETTINGS
glm::vec3 size = {1.0f,1.0f,1.0f};
glm::vec3 emitangle = {0.0f,0.0f,0.0f};
float lifespan = 5.0f;
float speed = 1.0f;
glm::vec3 angularvelocity = {0.0f,0.0f,0.0f};
bool facecamera = false;
glm::vec4 color = {1.0f,1.0f,1.0f,1.0f};
public:
std::vector<Particle*> particles;
Texture* tex;
Mesh* mesh;
ParticleEmitter() {
shadertype = ParticleShader;
mesh = new Mesh(quadVertices3D, quadIndices3D);
}
ParticleEmitter(const std::vector<Vertex>& meshvertices, const std::vector<GLuint>& meshindices) {
shadertype = ParticleShader;
mesh = new Mesh(meshvertices, meshindices);
}
~ParticleEmitter() {
mesh->Delete();
}
void Emit() {
Particle* np = new Particle();
glm::quat rot = glm::quat(glm::vec3({ (float)rand() / (float)RAND_MAX * emitangle[0] - emitangle[0] / 2.0f,(float)rand() / (float)RAND_MAX * emitangle[1] - emitangle[1] / 2.0f,(float)rand() / RAND_MAX * emitangle[2] - emitangle[2] / 2.0f }));
np->t.TranslateTo(t.GetTranslation());
np->linearvelocity = (t.GetFrontVector() * speed) * rot;
np->angularvelocity = angularvelocity;
np->t.ScaleTo(size);
if (emitdirection == Perpendicular) {
np->t.RotateToQuaternion(glm::conjugate(rot) * glm::quat({ glm::radians(90.0f),0.0f,0.0f }) * t.GetRotationQuaternion());
}
else if (emitdirection == Outward) {
np->t.RotateToQuaternion(glm::conjugate(rot) * t.GetRotationQuaternion());
}
else {
np->t.RotateToQuaternion(t.GetRotationQuaternion());
}
np->lifespan = lifespan;
particles.push_back(np);
}
void Step(float dt) {
for (auto it = particles.begin(); it != particles.end(); ) {
Particle* p = *it;
p->lifespan -= dt;
if (p->lifespan <= 0.0f) {
delete p;
it = particles.erase(it);
}
else {
p->Step(dt);
++it;
}
}
}
void Render(Shader& ShaderProgram) override {
if (particles.size() <= 0) return;
ShaderProgram.Activate();
mesh->vao.Bind();
ShaderProgram.Set4F("color",color);
glActiveTexture(0);
if (tex != nullptr) {
glBindTexture(GL_TEXTURE_2D, tex->ID);
ShaderProgram.SetInt("tex", 0);
}
else glBindTexture(GL_TEXTURE_2D, 0);
std::vector<glm::mat4> matrices;
if (color.w != 1.0f) {
std::map<float, Particle*> sorted;
for (unsigned int i = 0; i < particles.size(); i++)
{
sorted[Magnitude2(engine->camera->t.GetTranslation() - particles[i]->t.GetTranslation())] = particles[i];
}
for (std::map<float, Particle*>::reverse_iterator it = sorted.rbegin(); it != sorted.rend(); ++it)
{
if (facecamera) {
matrices.emplace_back(it->second->t.GetTranslationMatrix() * engine->camera->t.GetRotationMatrix() * it->second->t.GetScaleMatrix());
}
else {
matrices.emplace_back(it->second->t.GetMatrix());
}
}
}
else {
for (int i = 0; i < particles.size(); i++)
{
if (facecamera) {
matrices.emplace_back(particles[i]->t.GetTranslationMatrix() * engine->camera->t.GetRotationMatrix() * particles[i]->t.GetScaleMatrix());
}
else {
matrices.emplace_back(particles[i]->t.GetMatrix());
}
}
}
unsigned int buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, particles.size() * sizeof(glm::mat4), &matrices[0], GL_STATIC_DRAW);
mesh->vao.Bind();
// vertex attributes
std::size_t vec4Size = sizeof(glm::vec4);
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, 4 * vec4Size, (void*)0);
glEnableVertexAttribArray(4);
glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, 4 * vec4Size, (void*)(1 * vec4Size));
glEnableVertexAttribArray(5);
glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, 4 * vec4Size, (void*)(2 * vec4Size));
glEnableVertexAttribArray(6);
glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, 4 * vec4Size, (void*)(3 * vec4Size));
glVertexAttribDivisor(3, 1);
glVertexAttribDivisor(4, 1);
glVertexAttribDivisor(5, 1);
glVertexAttribDivisor(6, 1);
glDrawElementsInstanced(GL_TRIANGLES, mesh->indices.size(), GL_UNSIGNED_INT, 0, particles.size());
mesh->vao.Unbind();
}
private:
};
#endif