129 lines
4.8 KiB
C++
129 lines
4.8 KiB
C++
#pragma once
|
|
|
|
#include "render/Renderer.h"
|
|
#include "render/TextureManager.h"
|
|
#include <vector>
|
|
#include <chrono>
|
|
#include <string>
|
|
|
|
namespace ZL {
|
|
|
|
struct SparkParticle {
|
|
Vector3f position;
|
|
Vector3f velocity;
|
|
float scale;
|
|
float lifeTime;
|
|
float maxLifeTime;
|
|
bool active;
|
|
int emitterIndex;
|
|
|
|
SparkParticle() : position({ 0,0,0 }), velocity({ 0,0,0 }), scale(1.0f),
|
|
lifeTime(0), maxLifeTime(1000.0f), active(false), emitterIndex(0) {
|
|
}
|
|
};
|
|
|
|
class SparkEmitter {
|
|
private:
|
|
std::vector<SparkParticle> particles;
|
|
std::vector<Vector3f> emissionPoints;
|
|
std::vector<Vector3f> prevEmissionPoints;
|
|
std::chrono::steady_clock::time_point lastEmissionTime;
|
|
float emissionRate;
|
|
bool isActive;
|
|
|
|
std::vector<Vector3f> drawPositions;
|
|
std::vector<Vector2f> drawTexCoords;
|
|
bool drawDataDirty;
|
|
VertexRenderStruct sparkQuad;
|
|
std::shared_ptr<Texture> texture;
|
|
|
|
int maxParticles;
|
|
float particleSize;
|
|
float biasX;
|
|
|
|
// Ranges (used when config supplies intervals)
|
|
struct FloatRange { float min=0; float max=0; };
|
|
FloatRange speedRange; // XY speed
|
|
FloatRange zSpeedRange; // Z speed
|
|
FloatRange scaleRange;
|
|
FloatRange lifeTimeRange;
|
|
|
|
std::string shaderProgramName;
|
|
|
|
// Sparks spawn within this radius of each emission point. 0 means
|
|
// "spawn exactly at the point" (legacy behavior).
|
|
float emissionRadius;
|
|
|
|
bool configured;
|
|
// Rebuilds the CPU-side quad/UV arrays. If cameraViewMatrix is identity,
|
|
// particles are rendered as axis-aligned quads in world XY and sorted by
|
|
// world Z (legacy behavior). Otherwise quads are billboarded toward the
|
|
// camera using its world-space right/up axes, and particles are sorted
|
|
// back-to-front in eye space for correct alpha blending.
|
|
void prepareDrawData(const Eigen::Matrix4f& cameraViewMatrix);
|
|
bool useWorldSpace;
|
|
|
|
// When non-zero, velocities spray in a cone around this direction
|
|
// instead of the default planar XY + Z spread used by JSON emitters.
|
|
Vector3f emissionDirection = Vector3f{ 0.f, 0.f, 0.f };
|
|
|
|
public:
|
|
SparkEmitter();
|
|
SparkEmitter(const SparkEmitter& copyFrom);
|
|
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 resetEmissionPoints(const std::vector<Vector3f>& positions);
|
|
void setTexture(std::shared_ptr<Texture> tex);
|
|
void setEmissionRate(float rate) { emissionRate = rate; }
|
|
void setShaderProgramName(const std::string& name) { shaderProgramName = name; }
|
|
void setMaxParticles(int max) { maxParticles = max; particles.resize(maxParticles); }
|
|
void setParticleSize(float size) { particleSize = size; }
|
|
void setBiasX(float bias) { biasX = bias; }
|
|
|
|
void setUseWorldSpace(bool use) { useWorldSpace = use; }
|
|
bool loadFromJsonFile(const std::string& path, Renderer& renderer, const std::string& zipFile = "");
|
|
|
|
// Programmatic configuration (alternative to loadFromJsonFile).
|
|
// Ranges follow the same semantics as the JSON fields.
|
|
void setSpeedRange(float minVal, float maxVal) { speedRange.min = minVal; speedRange.max = maxVal; }
|
|
void setZSpeedRange(float minVal, float maxVal) { zSpeedRange.min = minVal; zSpeedRange.max = maxVal; }
|
|
void setScaleRange(float minVal, float maxVal) { scaleRange.min = minVal; scaleRange.max = maxVal; }
|
|
void setLifeTimeRange(float minVal, float maxVal) { lifeTimeRange.min = minVal; lifeTimeRange.max = maxVal; }
|
|
void setEmissionDirection(const Vector3f& dir) { emissionDirection = dir; }
|
|
// 0 = spawn exactly at the emission point; >0 = spawn at a uniform random
|
|
// point inside a 3D ball of this radius around the emission point.
|
|
void setEmissionRadius(float r) { emissionRadius = r; }
|
|
void markConfigured() { configured = true; }
|
|
bool isConfigured() const { return configured; }
|
|
|
|
void update(float deltaTimeMs);
|
|
void emit(float ageMs = 0.0f, float lerpT = 0.0f);
|
|
|
|
// Вызывать ДО draw() в начале кадра: готовит данные и загружает в VBO.
|
|
// Pass the current camera view matrix (world → eye) to billboard sparks
|
|
// toward the camera and sort them back-to-front. Identity (default)
|
|
// keeps the legacy non-billboarded behavior.
|
|
void prepareForDraw(const Eigen::Matrix4f& cameraViewMatrix = Eigen::Matrix4f::Identity());
|
|
|
|
void draw(Renderer& renderer, float zoom, int screenWidth, int screenHeight);
|
|
void draw(Renderer& renderer, float zoom, int screenWidth, int screenHeight, bool withRotation);
|
|
|
|
const std::vector<SparkParticle>& getParticles() const;
|
|
size_t getActiveParticleCount() const;
|
|
std::shared_ptr<Texture> getTexture() const { return texture; }
|
|
|
|
void setIsActive(bool newActive)
|
|
{
|
|
isActive = newActive;
|
|
}
|
|
|
|
private:
|
|
void initParticle(SparkParticle& particle, int emitterIndex);
|
|
Vector3f getRandomVelocity(int emitterIndex);
|
|
};
|
|
|
|
} // namespace ZL
|