add loading from json
This commit is contained in:
parent
bc49540a95
commit
01d362615f
7
Game.cpp
7
Game.cpp
@ -160,6 +160,8 @@ namespace ZL
|
||||
|
||||
#endif
|
||||
|
||||
bool cfgLoaded = sparkEmitter.loadFromJsonFile("../config/spark_config.json", renderer, CONST_ZIP_FILE);
|
||||
|
||||
cubemapTexture = std::make_shared<Texture>(
|
||||
std::array<TextureDataStruct, 6>{
|
||||
CreateTextureDataFromBmp24("./resources/sky/space_rt.bmp", CONST_ZIP_FILE),
|
||||
@ -198,9 +200,12 @@ namespace ZL
|
||||
boxRenderArr[i].RefreshVBO();
|
||||
}
|
||||
|
||||
// Если конфиг не загрузился — делаем fallback: загрузим текстуру и присвоим эмиттеру.
|
||||
/*if (!cfgLoaded) {
|
||||
sparkTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/spark.png", CONST_ZIP_FILE));
|
||||
|
||||
sparkEmitter.setTexture(sparkTexture);
|
||||
}*/
|
||||
// Если конфиг загрузился и содержал texture, sparkEmitter уже имеет свою текстуру; иначе — она установлена выше.
|
||||
|
||||
renderer.InitOpenGL();
|
||||
|
||||
|
||||
198
SparkEmitter.cpp
198
SparkEmitter.cpp
@ -2,11 +2,17 @@
|
||||
#include <random>
|
||||
#include <cmath>
|
||||
#include "OpenGlExtensions.h"
|
||||
#include <fstream>
|
||||
#include "external/nlohmann/json.hpp"
|
||||
#include <iostream>
|
||||
|
||||
namespace ZL {
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
SparkEmitter::SparkEmitter()
|
||||
: emissionRate(100.0f), isActive(true), drawDataDirty(true), maxParticles(200) {
|
||||
: emissionRate(100.0f), isActive(true), drawDataDirty(true), maxParticles(200),
|
||||
shaderProgramName("default"), particleSize(0.04f), biasX(0.3f) {
|
||||
particles.resize(maxParticles);
|
||||
drawPositions.reserve(maxParticles * 6);
|
||||
drawTexCoords.reserve(maxParticles * 6);
|
||||
@ -17,7 +23,8 @@ namespace ZL {
|
||||
|
||||
SparkEmitter::SparkEmitter(const std::vector<Vector3f>& positions, float rate)
|
||||
: emissionPoints(positions), emissionRate(rate), isActive(true),
|
||||
drawDataDirty(true), maxParticles(positions.size() * 100) {
|
||||
drawDataDirty(true), maxParticles(positions.size() * 100),
|
||||
shaderProgramName("default"), particleSize(0.04f), biasX(0.3f) {
|
||||
particles.resize(maxParticles);
|
||||
drawPositions.reserve(maxParticles * 6);
|
||||
drawTexCoords.reserve(maxParticles * 6);
|
||||
@ -30,7 +37,8 @@ namespace ZL {
|
||||
std::shared_ptr<Texture> tex,
|
||||
float rate)
|
||||
: emissionPoints(positions), texture(tex), emissionRate(rate),
|
||||
isActive(true), drawDataDirty(true), maxParticles(positions.size() * 100) {
|
||||
isActive(true), drawDataDirty(true), maxParticles(positions.size() * 100),
|
||||
shaderProgramName("default"), particleSize(0.04f), biasX(0.3f) {
|
||||
particles.resize(maxParticles);
|
||||
drawPositions.reserve(maxParticles * 6);
|
||||
drawTexCoords.reserve(maxParticles * 6);
|
||||
@ -71,7 +79,7 @@ namespace ZL {
|
||||
for (const auto& [particlePtr, depth] : sortedParticles) {
|
||||
const auto& particle = *particlePtr;
|
||||
Vector3f pos = particle.position;
|
||||
float size = 0.04f * particle.scale;
|
||||
float size = particleSize * particle.scale;
|
||||
|
||||
drawPositions.push_back({ pos.v[0] - size, pos.v[1] - size, pos.v[2] });
|
||||
drawTexCoords.push_back({ 0.0f, 0.0f });
|
||||
@ -114,12 +122,11 @@ namespace ZL {
|
||||
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.shaderManager.PushShader(shaderProgramName);
|
||||
renderer.RenderUniform1i(textureUniformName, 0);
|
||||
renderer.EnableVertexAttribArray(vPositionName);
|
||||
renderer.EnableVertexAttribArray(vTexCoordName);
|
||||
@ -130,7 +137,7 @@ namespace ZL {
|
||||
glBindTexture(GL_TEXTURE_2D, texture->getTexID());
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE);// Аддитивное смешивание для эффекта свечения
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
||||
|
||||
renderer.PushMatrix();
|
||||
renderer.LoadIdentity();
|
||||
@ -241,39 +248,43 @@ namespace ZL {
|
||||
|
||||
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) {
|
||||
particle.velocity = getRandomVelocity(emitterIndex);
|
||||
particle.scale = 1.0f;
|
||||
particle.maxLifeTime = 800.0f + (rand() % 400);
|
||||
static std::random_device rd;
|
||||
static std::mt19937 gen(rd());
|
||||
std::uniform_real_distribution<float> scaleDist(scaleRange.min, scaleRange.max);
|
||||
particle.scale = scaleDist(gen);
|
||||
|
||||
std::uniform_real_distribution<float> lifeDist(lifeTimeRange.min, lifeTimeRange.max);
|
||||
particle.maxLifeTime = lifeDist(gen);
|
||||
particle.emitterIndex = emitterIndex;
|
||||
}
|
||||
|
||||
Vector3f SparkEmitter::getRandomVelocity(int emitterIndex) {
|
||||
static std::random_device rd;
|
||||
static std::mt19937 gen(rd());
|
||||
static std::uniform_real_distribution<> angleDist(0, 2 * M_PI);
|
||||
static std::uniform_real_distribution<> speedDist(0.5f, 2.0f);
|
||||
static std::uniform_real_distribution<> zSpeedDist(1.0f, 3.0f);
|
||||
std::uniform_real_distribution<float> angleDist(0.0f, 2.0f * static_cast<float>(M_PI));
|
||||
std::uniform_real_distribution<float> speedDist(speedRange.min, speedRange.max);
|
||||
std::uniform_real_distribution<float> zSpeedDist(zSpeedRange.min, zSpeedRange.max);
|
||||
|
||||
float angle = angleDist(gen);
|
||||
float speed = speedDist(gen);
|
||||
float zSpeed = zSpeedDist(gen);
|
||||
|
||||
// Теперь biasX берется из JSON
|
||||
if (emitterIndex == 0) {
|
||||
return Vector3f{
|
||||
cosf(angle) * speed - 0.3f,
|
||||
cosf(angle) * speed - biasX,
|
||||
sinf(angle) * speed,
|
||||
zSpeed
|
||||
};
|
||||
}
|
||||
else {
|
||||
return Vector3f{
|
||||
cosf(angle) * speed + 0.3f,
|
||||
cosf(angle) * speed + biasX,
|
||||
sinf(angle) * speed,
|
||||
zSpeed
|
||||
};
|
||||
@ -294,4 +305,159 @@ namespace ZL {
|
||||
return count;
|
||||
}
|
||||
|
||||
bool SparkEmitter::loadFromJsonFile(const std::string& path, Renderer& renderer, const std::string& zipFile) {
|
||||
std::cout << "Loading spark config from: " << path << std::endl;
|
||||
std::ifstream in(path);
|
||||
if (!in.is_open()) {
|
||||
std::cerr << "Failed to open JSON file: " << path << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
json j;
|
||||
try {
|
||||
in >> j;
|
||||
std::cout << "JSON parsed successfully" << std::endl;
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cerr << "JSON parse error: " << e.what() << std::endl;
|
||||
return false;
|
||||
}
|
||||
std::cout << "JSON content: " << j.dump(2) << std::endl;
|
||||
|
||||
// Основные параметры
|
||||
if (j.contains("emissionRate")) {
|
||||
emissionRate = j["emissionRate"].get<float>();
|
||||
}
|
||||
|
||||
if (j.contains("maxParticles")) {
|
||||
maxParticles = j["maxParticles"].get<int>();
|
||||
particles.resize(maxParticles);
|
||||
drawPositions.reserve(maxParticles * 6);
|
||||
drawTexCoords.reserve(maxParticles * 6);
|
||||
std::cout << "Max particles: " << maxParticles << std::endl;
|
||||
}
|
||||
|
||||
if (j.contains("particleSize")) {
|
||||
particleSize = j["particleSize"].get<float>();
|
||||
std::cout << "Particle size: " << particleSize << std::endl;
|
||||
}
|
||||
|
||||
if (j.contains("biasX")) {
|
||||
biasX = j["biasX"].get<float>();
|
||||
std::cout << "Bias X: " << biasX << std::endl;
|
||||
}
|
||||
|
||||
// emissionPoints
|
||||
std::vector<Vector3f> points;
|
||||
if (j.contains("emissionPoints") && j["emissionPoints"].is_array()) {
|
||||
for (const auto& el : j["emissionPoints"]) {
|
||||
if (el.contains("position") && el["position"].is_array()) {
|
||||
auto arr = el["position"];
|
||||
points.push_back(Vector3f{ arr[0].get<float>(), arr[1].get<float>(), arr[2].get<float>() });
|
||||
std::cout << "Fixed point: [" << arr[0] << ", " << arr[1] << ", " << arr[2] << "]" << std::endl;
|
||||
}
|
||||
else if (el.contains("positionRange") && el["positionRange"].is_object()) {
|
||||
auto pr = el["positionRange"];
|
||||
auto minArr = pr["min"];
|
||||
auto maxArr = pr["max"];
|
||||
int count = 1;
|
||||
if (el.contains("count")) count = el["count"].get<int>();
|
||||
|
||||
std::random_device rd;
|
||||
std::mt19937 gen(rd());
|
||||
std::uniform_real_distribution<float> dx(minArr[0].get<float>(), maxArr[0].get<float>());
|
||||
std::uniform_real_distribution<float> dy(minArr[1].get<float>(), maxArr[1].get<float>());
|
||||
std::uniform_real_distribution<float> dz(minArr[2].get<float>(), maxArr[2].get<float>());
|
||||
|
||||
for (int k = 0; k < count; ++k) {
|
||||
Vector3f randomPoint{ dx(gen), dy(gen), dz(gen) };
|
||||
points.push_back(randomPoint);
|
||||
std::cout << "Random point " << k + 1 << ": [" << randomPoint.v[0]
|
||||
<< ", " << randomPoint.v[1] << ", " << randomPoint.v[2] << "]" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!points.empty()) {
|
||||
setEmissionPoints(points);
|
||||
std::cout << "Total emission points: " << emissionPoints.size() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// Ranges
|
||||
if (j.contains("speedRange") && j["speedRange"].is_array()) {
|
||||
auto a = j["speedRange"];
|
||||
speedRange.min = a[0].get<float>();
|
||||
speedRange.max = a[1].get<float>();
|
||||
std::cout << "Speed range: [" << speedRange.min << ", " << speedRange.max << "]" << std::endl;
|
||||
}
|
||||
|
||||
if (j.contains("zSpeedRange") && j["zSpeedRange"].is_array()) {
|
||||
auto a = j["zSpeedRange"];
|
||||
zSpeedRange.min = a[0].get<float>();
|
||||
zSpeedRange.max = a[1].get<float>();
|
||||
std::cout << "Z speed range: [" << zSpeedRange.min << ", " << zSpeedRange.max << "]" << std::endl;
|
||||
}
|
||||
|
||||
if (j.contains("scaleRange") && j["scaleRange"].is_array()) {
|
||||
auto a = j["scaleRange"];
|
||||
scaleRange.min = a[0].get<float>();
|
||||
scaleRange.max = a[1].get<float>();
|
||||
std::cout << "Scale range: [" << scaleRange.min << ", " << scaleRange.max << "]" << std::endl;
|
||||
}
|
||||
|
||||
if (j.contains("lifeTimeRange") && j["lifeTimeRange"].is_array()) {
|
||||
auto a = j["lifeTimeRange"];
|
||||
lifeTimeRange.min = a[0].get<float>();
|
||||
lifeTimeRange.max = a[1].get<float>();
|
||||
std::cout << "Life time range: [" << lifeTimeRange.min << ", " << lifeTimeRange.max << "]" << std::endl;
|
||||
}
|
||||
|
||||
// texture
|
||||
if (j.contains("texture") && j["texture"].is_string()) {
|
||||
std::string texPath = j["texture"].get<std::string>();
|
||||
std::cout << "Loading texture: " << texPath << std::endl;
|
||||
|
||||
try {
|
||||
auto texData = CreateTextureDataFromPng(texPath.c_str(), zipFile.c_str());
|
||||
texture = std::make_shared<Texture>(texData);
|
||||
std::cout << "Texture loaded successfully, ID: " << texture->getTexID() << std::endl;
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cerr << "Texture load error: " << e.what() << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
std::cout << "No texture specified in JSON" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// shaders
|
||||
if (j.contains("shaderProgramName") && j["shaderProgramName"].is_string()) {
|
||||
shaderProgramName = j["shaderProgramName"].get<std::string>();
|
||||
std::cout << "Shader program name: " << shaderProgramName << std::endl;
|
||||
}
|
||||
|
||||
if (j.contains("vertexShader") && j.contains("fragmentShader")
|
||||
&& j["vertexShader"].is_string() && j["fragmentShader"].is_string()) {
|
||||
std::string v = j["vertexShader"].get<std::string>();
|
||||
std::string f = j["fragmentShader"].get<std::string>();
|
||||
std::cout << "Loading shaders - vertex: " << v << ", fragment: " << f << std::endl;
|
||||
|
||||
try {
|
||||
renderer.shaderManager.AddShaderFromFiles(shaderProgramName, v, f, zipFile.c_str());
|
||||
std::cout << "Shaders loaded successfully" << std::endl;
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cerr << "Shader load error: " << e.what() << std::endl;
|
||||
std::cerr << "Using default shader" << std::endl;
|
||||
shaderProgramName = "default";
|
||||
}
|
||||
}
|
||||
|
||||
drawDataDirty = true;
|
||||
std::cout << "SparkEmitter configuration loaded successfully!" << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace ZL
|
||||
@ -5,6 +5,7 @@
|
||||
#include "TextureManager.h"
|
||||
#include <vector>
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
|
||||
namespace ZL {
|
||||
|
||||
@ -37,6 +38,17 @@ namespace ZL {
|
||||
std::shared_ptr<Texture> texture;
|
||||
|
||||
int maxParticles;
|
||||
float particleSize;
|
||||
float biasX;
|
||||
|
||||
// Ranges (used when config supplies intervals)
|
||||
struct FloatRange { float min; float max; };
|
||||
FloatRange speedRange; // XY speed
|
||||
FloatRange zSpeedRange; // Z speed
|
||||
FloatRange scaleRange;
|
||||
FloatRange lifeTimeRange;
|
||||
|
||||
std::string shaderProgramName;
|
||||
|
||||
void prepareDrawData();
|
||||
|
||||
@ -49,6 +61,13 @@ namespace ZL {
|
||||
|
||||
void setEmissionPoints(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; }
|
||||
|
||||
bool loadFromJsonFile(const std::string& path, Renderer& renderer, const std::string& zipFile = "");
|
||||
|
||||
void update(float deltaTimeMs);
|
||||
void emit();
|
||||
@ -57,6 +76,7 @@ namespace ZL {
|
||||
|
||||
const std::vector<SparkParticle>& getParticles() const;
|
||||
size_t getActiveParticleCount() const;
|
||||
std::shared_ptr<Texture> getTexture() const { return texture; }
|
||||
|
||||
private:
|
||||
void initParticle(SparkParticle& particle, int emitterIndex);
|
||||
|
||||
22
config/spark_config.json
Normal file
22
config/spark_config.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"emissionRate": 100.0,
|
||||
"maxParticles": 200,
|
||||
"particleSize": 0.04,
|
||||
"biasX": 0.3,
|
||||
"emissionPoints": [
|
||||
{
|
||||
"position": [-2.1, 0.9, 5.0]
|
||||
},
|
||||
{
|
||||
"position": [2.1, 0.9, 5.0]
|
||||
}
|
||||
],
|
||||
"speedRange": [0.5, 2.0],
|
||||
"zSpeedRange": [1.0, 3.0],
|
||||
"scaleRange": [0.8, 1.2],
|
||||
"lifeTimeRange": [600.0, 1400.0],
|
||||
"texture": "./resources/spark.png",
|
||||
"shaderProgramName": "default",
|
||||
"vertexShader": "./shaders/default.vertex",
|
||||
"fragmentShader": "./shaders/default.fragment"
|
||||
}
|
||||
25526
external/nlohmann/json.hpp
vendored
Normal file
25526
external/nlohmann/json.hpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
8
shaders/spark.fragment
Normal file
8
shaders/spark.fragment
Normal file
@ -0,0 +1,8 @@
|
||||
#version 120
|
||||
varying vec2 fTexCoord;
|
||||
uniform sampler2D Texture;
|
||||
void main() {
|
||||
vec4 col = texture2D(Texture, fTexCoord);
|
||||
// простой аддитивный блёк
|
||||
gl_FragColor = col;
|
||||
}
|
||||
8
shaders/spark.vertex
Normal file
8
shaders/spark.vertex
Normal file
@ -0,0 +1,8 @@
|
||||
#version 120
|
||||
attribute vec3 vPosition;
|
||||
attribute vec2 vTexCoord;
|
||||
varying vec2 fTexCoord;
|
||||
void main() {
|
||||
fTexCoord = vTexCoord;
|
||||
gl_Position = gl_ModelViewProjectionMatrix * vec4(vPosition, 1.0);
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user