moved drawEffect() to SparkEmitter

This commit is contained in:
Vlad 2025-12-12 16:58:23 +06:00
parent 115cbbb7fa
commit d2605d9108
4 changed files with 131 additions and 132 deletions

View File

@ -200,8 +200,7 @@ namespace ZL
sparkTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/spark.png", CONST_ZIP_FILE)); sparkTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/spark.png", CONST_ZIP_FILE));
sparkQuad.data = CreateRect2D({ 0, 0 }, { 0.08f, 0.08f }, 0); sparkEmitter.setTexture(sparkTexture);
sparkQuad.RefreshVBO();
renderer.InitOpenGL(); renderer.InitOpenGL();
@ -241,75 +240,6 @@ namespace ZL
CheckGlError(); CheckGlError();
} }
void Game::drawEffects()
{
if (sparkEmitter.getActiveParticleCount() == 0) {
return;
}
sparkQuad.data.PositionData.clear();
sparkQuad.data.TexCoordData.clear();
const auto& particles = sparkEmitter.getParticles();
for (const auto& particle : particles) {
if (!particle.active) continue;
Vector3f pos = particle.position;
float size = 0.04f * particle.scale;
sparkQuad.data.PositionData.push_back({ pos.v[0] - size, pos.v[1] - size, pos.v[2] });
sparkQuad.data.TexCoordData.push_back({ 0.0f, 0.0f });
sparkQuad.data.PositionData.push_back({ pos.v[0] - size, pos.v[1] + size, pos.v[2] });
sparkQuad.data.TexCoordData.push_back({ 0.0f, 1.0f });
sparkQuad.data.PositionData.push_back({ pos.v[0] + size, pos.v[1] + size, pos.v[2] });
sparkQuad.data.TexCoordData.push_back({ 1.0f, 1.0f });
sparkQuad.data.PositionData.push_back({ pos.v[0] - size, pos.v[1] - size, pos.v[2] });
sparkQuad.data.TexCoordData.push_back({ 0.0f, 0.0f });
sparkQuad.data.PositionData.push_back({ pos.v[0] + size, pos.v[1] + size, pos.v[2] });
sparkQuad.data.TexCoordData.push_back({ 1.0f, 1.0f });
sparkQuad.data.PositionData.push_back({ pos.v[0] + size, pos.v[1] - size, pos.v[2] });
sparkQuad.data.TexCoordData.push_back({ 1.0f, 0.0f });
}
if (sparkQuad.data.PositionData.empty()) return;
sparkQuad.RefreshVBO();
static const std::string defaultShaderName = "default";
static const std::string vPositionName = "vPosition";
static const std::string vTexCoordName = "vTexCoord";
static const std::string textureUniformName = "Texture";
renderer.shaderManager.PushShader(defaultShaderName);
renderer.RenderUniform1i(textureUniformName, 0);
renderer.EnableVertexAttribArray(vPositionName);
renderer.EnableVertexAttribArray(vTexCoordName);
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
1, 1000);
glBindTexture(GL_TEXTURE_2D, sparkTexture->getTexID());
renderer.PushMatrix();
renderer.LoadIdentity();
renderer.TranslateMatrix({ 0, 0, -1.0f * Environment::zoom });
renderer.DrawVertexRenderStruct(sparkQuad);
renderer.PopMatrix();
renderer.PopProjectionMatrix();
renderer.DisableVertexAttribArray(vPositionName);
renderer.DisableVertexAttribArray(vTexCoordName);
renderer.shaderManager.PopShader();
CheckGlError();
}
void Game::drawShip() void Game::drawShip()
{ {
static const std::string defaultShaderName = "default"; static const std::string defaultShaderName = "default";
@ -335,7 +265,7 @@ namespace ZL
glBindTexture(GL_TEXTURE_2D, spaceshipTexture->getTexID()); glBindTexture(GL_TEXTURE_2D, spaceshipTexture->getTexID());
renderer.DrawVertexRenderStruct(spaceship); renderer.DrawVertexRenderStruct(spaceship);
drawEffects(); sparkEmitter.draw(renderer, Environment::zoom, Environment::width, Environment::height);
renderer.PopMatrix(); renderer.PopMatrix();
renderer.PopProjectionMatrix(); renderer.PopProjectionMatrix();

3
Game.h
View File

@ -31,7 +31,6 @@ namespace ZL {
void processTickCount(); void processTickCount();
void drawScene(); void drawScene();
void drawCubemap(); void drawCubemap();
void drawEffects();
void drawShip(); void drawShip();
void drawBoxes(); void drawBoxes();
@ -59,9 +58,7 @@ namespace ZL {
std::vector<BoxCoords> boxCoordsArr; std::vector<BoxCoords> boxCoordsArr;
std::vector<VertexRenderStruct> boxRenderArr; std::vector<VertexRenderStruct> boxRenderArr;
//VertexRenderStruct singleSpark;
SparkEmitter sparkEmitter; SparkEmitter sparkEmitter;
VertexRenderStruct sparkQuad;
}; };
} // namespace ZL } // namespace ZL

View File

@ -6,59 +6,127 @@
namespace ZL { namespace ZL {
SparkEmitter::SparkEmitter() SparkEmitter::SparkEmitter()
: emissionRate(100.0f), isActive(true), buffersDirty(true), maxParticles(200) { : emissionRate(100.0f), isActive(true), drawDataDirty(true), maxParticles(200) {
particles.resize(maxParticles); particles.resize(maxParticles);
positionBuffer.resize(maxParticles * 4, 0.0f); drawPositions.reserve(maxParticles * 6);
texCoordBuffer.resize(maxParticles * 2, 0.0f); drawTexCoords.reserve(maxParticles * 6);
lastEmissionTime = std::chrono::steady_clock::now(); lastEmissionTime = std::chrono::steady_clock::now();
sparkQuad.data = VertexDataStruct();
} }
SparkEmitter::SparkEmitter(const std::vector<Vector3f>& positions, float rate) SparkEmitter::SparkEmitter(const std::vector<Vector3f>& positions, float rate)
: emissionPoints(positions), emissionRate(rate), isActive(true), : emissionPoints(positions), emissionRate(rate), isActive(true),
buffersDirty(true), maxParticles(positions.size() * 100) { drawDataDirty(true), maxParticles(positions.size() * 100) {
particles.resize(maxParticles); particles.resize(maxParticles);
positionBuffer.resize(maxParticles * 4, 0.0f); drawPositions.reserve(maxParticles * 6);
texCoordBuffer.resize(maxParticles * 2, 0.0f); drawTexCoords.reserve(maxParticles * 6);
lastEmissionTime = std::chrono::steady_clock::now(); lastEmissionTime = std::chrono::steady_clock::now();
sparkQuad.data = VertexDataStruct();
} }
void SparkEmitter::setEmissionPoints(const std::vector<Vector3f>& positions) { SparkEmitter::SparkEmitter(const std::vector<Vector3f>& positions,
emissionPoints = positions; std::shared_ptr<Texture> tex,
maxParticles = positions.size() * 100; float rate)
: emissionPoints(positions), texture(tex), emissionRate(rate),
isActive(true), drawDataDirty(true), maxParticles(positions.size() * 100) {
particles.resize(maxParticles); particles.resize(maxParticles);
positionBuffer.resize(maxParticles * 4, 0.0f); drawPositions.reserve(maxParticles * 6);
texCoordBuffer.resize(maxParticles * 2, 0.0f); drawTexCoords.reserve(maxParticles * 6);
buffersDirty = true; lastEmissionTime = std::chrono::steady_clock::now();
sparkQuad.data = VertexDataStruct();
} }
void SparkEmitter::updateBuffers() { void SparkEmitter::setTexture(std::shared_ptr<Texture> tex) {
if (!buffersDirty) return; texture = tex;
}
void SparkEmitter::prepareDrawData() {
if (!drawDataDirty) return;
drawPositions.clear();
drawTexCoords.clear();
if (getActiveParticleCount() == 0) {
drawDataDirty = false;
return;
}
size_t bufferIndex = 0;
for (const auto& particle : particles) { for (const auto& particle : particles) {
if (particle.active) { if (!particle.active) continue;
positionBuffer[bufferIndex * 4] = particle.position.v[0];
positionBuffer[bufferIndex * 4 + 1] = particle.position.v[1];
positionBuffer[bufferIndex * 4 + 2] = particle.position.v[2];
positionBuffer[bufferIndex * 4 + 3] = particle.scale;
texCoordBuffer[bufferIndex * 2] = 0.0f; Vector3f pos = particle.position;
texCoordBuffer[bufferIndex * 2 + 1] = 0.0f; float size = 0.04f * particle.scale;
bufferIndex++; drawPositions.push_back({ pos.v[0] - size, pos.v[1] - size, pos.v[2] });
} drawTexCoords.push_back({ 0.0f, 0.0f });
drawPositions.push_back({ pos.v[0] - size, pos.v[1] + size, pos.v[2] });
drawTexCoords.push_back({ 0.0f, 1.0f });
drawPositions.push_back({ pos.v[0] + size, pos.v[1] + size, pos.v[2] });
drawTexCoords.push_back({ 1.0f, 1.0f });
drawPositions.push_back({ pos.v[0] - size, pos.v[1] - size, pos.v[2] });
drawTexCoords.push_back({ 0.0f, 0.0f });
drawPositions.push_back({ pos.v[0] + size, pos.v[1] + size, pos.v[2] });
drawTexCoords.push_back({ 1.0f, 1.0f });
drawPositions.push_back({ pos.v[0] + size, pos.v[1] - size, pos.v[2] });
drawTexCoords.push_back({ 1.0f, 0.0f });
} }
for (size_t i = bufferIndex; i < maxParticles; i++) { drawDataDirty = false;
positionBuffer[i * 4] = 0.0f; }
positionBuffer[i * 4 + 1] = 0.0f;
positionBuffer[i * 4 + 2] = 0.0f; void SparkEmitter::draw(Renderer& renderer, float zoom, int screenWidth, int screenHeight) {
positionBuffer[i * 4 + 3] = 0.0f; if (getActiveParticleCount() == 0) {
texCoordBuffer[i * 2] = 0.0f; return;
texCoordBuffer[i * 2 + 1] = 0.0f;
} }
buffersDirty = false; if (!texture) {
return;
}
prepareDrawData();
if (drawPositions.empty()) {
return;
}
sparkQuad.data.PositionData = drawPositions;
sparkQuad.data.TexCoordData = drawTexCoords;
sparkQuad.RefreshVBO();
static const std::string defaultShaderName = "default";
static const std::string vPositionName = "vPosition";
static const std::string vTexCoordName = "vTexCoord";
static const std::string textureUniformName = "Texture";
renderer.shaderManager.PushShader(defaultShaderName);
renderer.RenderUniform1i(textureUniformName, 0);
renderer.EnableVertexAttribArray(vPositionName);
renderer.EnableVertexAttribArray(vTexCoordName);
float aspectRatio = static_cast<float>(screenWidth) / static_cast<float>(screenHeight);
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5, aspectRatio, 1, 1000);
glBindTexture(GL_TEXTURE_2D, texture->getTexID());
renderer.PushMatrix();
renderer.LoadIdentity();
renderer.TranslateMatrix({ 0, 0, -1.0f * zoom });
renderer.DrawVertexRenderStruct(sparkQuad);
renderer.PopMatrix();
renderer.PopProjectionMatrix();
renderer.DisableVertexAttribArray(vPositionName);
renderer.DisableVertexAttribArray(vTexCoordName);
renderer.shaderManager.PopShader();
} }
void SparkEmitter::update(float deltaTimeMs) { void SparkEmitter::update(float deltaTimeMs) {
@ -69,12 +137,14 @@ namespace ZL {
if (isActive && elapsed >= emissionRate) { if (isActive && elapsed >= emissionRate) {
emit(); emit();
lastEmissionTime = currentTime; lastEmissionTime = currentTime;
drawDataDirty = true;
} }
bool anyChanged = false; bool anyChanged = false;
for (auto& particle : particles) { for (auto& particle : particles) {
if (particle.active) { if (particle.active) {
Vector3f oldPosition = particle.position; Vector3f oldPosition = particle.position;
float oldScale = particle.scale;
particle.position.v[0] += particle.velocity.v[0] * deltaTimeMs / 1000.0f; particle.position.v[0] += particle.velocity.v[0] * deltaTimeMs / 1000.0f;
particle.position.v[1] += particle.velocity.v[1] * deltaTimeMs / 1000.0f; particle.position.v[1] += particle.velocity.v[1] * deltaTimeMs / 1000.0f;
@ -92,7 +162,8 @@ namespace ZL {
if (oldPosition.v[0] != particle.position.v[0] || if (oldPosition.v[0] != particle.position.v[0] ||
oldPosition.v[1] != particle.position.v[1] || oldPosition.v[1] != particle.position.v[1] ||
oldPosition.v[2] != particle.position.v[2]) { oldPosition.v[2] != particle.position.v[2] ||
oldScale != particle.scale) {
anyChanged = true; anyChanged = true;
} }
} }
@ -100,7 +171,7 @@ namespace ZL {
} }
if (anyChanged) { if (anyChanged) {
buffersDirty = true; drawDataDirty = true;
} }
} }
@ -145,10 +216,17 @@ namespace ZL {
} }
if (emitted) { if (emitted) {
buffersDirty = true; drawDataDirty = true;
} }
} }
void SparkEmitter::setEmissionPoints(const std::vector<Vector3f>& positions) {
emissionPoints = positions;
maxParticles = positions.size() * 100;
particles.resize(maxParticles);
drawDataDirty = true;
}
void SparkEmitter::initParticle(SparkParticle& particle, int emitterIndex) { void SparkEmitter::initParticle(SparkParticle& particle, int emitterIndex) {
particle.velocity = getRandomVelocity(emitterIndex); particle.velocity = getRandomVelocity(emitterIndex);
particle.scale = 1.0f; particle.scale = 1.0f;
@ -197,15 +275,4 @@ namespace ZL {
return count; return count;
} }
size_t SparkEmitter::getActiveParticleBufferIndex(size_t particleIndex) const {
size_t activeIndex = 0;
for (size_t i = 0; i <= particleIndex; i++) {
if (particles[i].active) {
if (i == particleIndex) return activeIndex;
activeIndex++;
}
}
return 0;
}
} // namespace ZL } // namespace ZL

View File

@ -1,6 +1,8 @@
#pragma once #pragma once
#include "ZLMath.h" #include "ZLMath.h"
#include "Renderer.h"
#include "TextureManager.h"
#include <vector> #include <vector>
#include <chrono> #include <chrono>
@ -14,7 +16,6 @@ namespace ZL {
float maxLifeTime; float maxLifeTime;
bool active; bool active;
int emitterIndex; int emitterIndex;
Vector2f texCoord;
SparkParticle() : position({ 0,0,0 }), velocity({ 0,0,0 }), scale(1.0f), SparkParticle() : position({ 0,0,0 }), velocity({ 0,0,0 }), scale(1.0f),
lifeTime(0), maxLifeTime(1000.0f), active(false), emitterIndex(0) { lifeTime(0), maxLifeTime(1000.0f), active(false), emitterIndex(0) {
@ -29,30 +30,34 @@ namespace ZL {
float emissionRate; float emissionRate;
bool isActive; bool isActive;
std::vector<float> positionBuffer; std::vector<Vector3f> drawPositions;
std::vector<float> texCoordBuffer; std::vector<Vector2f> drawTexCoords;
bool buffersDirty; bool drawDataDirty;
VertexRenderStruct sparkQuad;
std::shared_ptr<Texture> texture;
int maxParticles; int maxParticles;
void prepareDrawData();
public: public:
SparkEmitter(); SparkEmitter();
SparkEmitter(const std::vector<Vector3f>& positions, float rate = 100.0f); SparkEmitter(const std::vector<Vector3f>& positions, float rate = 100.0f);
SparkEmitter(const std::vector<Vector3f>& positions,
std::shared_ptr<Texture> tex,
float rate = 100.0f);
void setEmissionPoints(const std::vector<Vector3f>& positions); void setEmissionPoints(const std::vector<Vector3f>& positions);
void setTexture(std::shared_ptr<Texture> tex);
void update(float deltaTimeMs); void update(float deltaTimeMs);
void emit(); void emit();
void draw(Renderer& renderer, float zoom, int screenWidth, int screenHeight);
const std::vector<SparkParticle>& getParticles() const; const std::vector<SparkParticle>& getParticles() const;
size_t getActiveParticleCount() const; size_t getActiveParticleCount() const;
const float* getPositionBuffer() const { return positionBuffer.data(); }
const float* getTexCoordBuffer() const { return texCoordBuffer.data(); }
size_t getBufferSize() const { return positionBuffer.size() / 4; }
void updateBuffers();
size_t getActiveParticleBufferIndex(size_t particleIndex) const;
private: private:
void initParticle(SparkParticle& particle, int emitterIndex); void initParticle(SparkParticle& particle, int emitterIndex);
Vector3f getRandomVelocity(int emitterIndex); Vector3f getRandomVelocity(int emitterIndex);