diff --git a/engine/includes/components/effectrender.h b/engine/includes/components/effectrender.h new file mode 100644 index 000000000..87663c095 --- /dev/null +++ b/engine/includes/components/effectrender.h @@ -0,0 +1,46 @@ +#ifndef EFFECTRENDER_H +#define EFFECTRENDER_H + +#include "renderable.h" + +#include "resources/visualeffect.h" + +class ENGINE_EXPORT EffectRender : public Renderable { + A_REGISTER(EffectRender, Renderable, Components/Effects) + + A_PROPERTIES( + A_PROPERTYEX(VisualEffect *, effect, EffectRender::effect, EffectRender::setEffect, "editor=Asset") + ) + A_NOMETHODS() + +public: + EffectRender(); + ~EffectRender() override; + + VisualEffect *effect() const; + void setEffect(VisualEffect *effect); + + void deltaUpdate(float dt); + +private: + AABBox localBound() const override; + + Mesh *meshToDraw() const override; + + void update() override; + + static void effectUpdated(int state, void *ptr); + +private: + std::vector m_emitterData; + + std::vector m_particleData; + + std::vector m_renderData; + + std::vector m_offsets; + + VisualEffect *m_effect; +}; + +#endif // EFFECTRENDER_H diff --git a/engine/includes/components/particlerender.h b/engine/includes/components/particlerender.h deleted file mode 100644 index 5f1ea5030..000000000 --- a/engine/includes/components/particlerender.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef PARTICLERENDER_H -#define PARTICLERENDER_H - -#include "renderable.h" - -#include "resources/particleeffect.h" - -struct GpuQuadParticle { - // xyz - world position, w - objectID.x - Vector4 worldPosition; - - // xy - size, z - rotation, w - objectID.y - Vector4 sizeRot; - - // xy - uvScale, z - distance, w - objectID.z - Vector4 uvScaleDist; - - // xy - uvOffset, z - unused, w - objectID.w - Vector4 uvOffset; - - // xyzw - color - Vector4 color; -}; - -class ENGINE_EXPORT ParticleRender : public Renderable { - A_REGISTER(ParticleRender, Renderable, Components/Effects) - - A_PROPERTIES( - A_PROPERTYEX(ParticleEffect *, effect, ParticleRender::effect, ParticleRender::setEffect, "editor=Asset") - ) - A_NOMETHODS() - -public: - ParticleRender(); - ~ParticleRender() override; - - ParticleEffect *effect() const; - void setEffect(ParticleEffect *effect); - - void deltaUpdate(float dt); - -private: - AABBox localBound() const override; - - Mesh *meshToDraw() const override; - - void update() override; - - void loadUserData(const VariantMap &data) override; - VariantMap saveUserData() const override; - - static void effectUpdated(int state, void *ptr); - -private: - std::vector m_particles; - - std::vector m_quads; - - ParticleEffect *m_effect; - - float m_ejectionTime; - - float m_count; -}; - -#endif // PARTICLERENDER_H diff --git a/engine/includes/editor/assetconverter.h b/engine/includes/editor/assetconverter.h index cfbed2f7b..501462e6b 100644 --- a/engine/includes/editor/assetconverter.h +++ b/engine/includes/editor/assetconverter.h @@ -132,9 +132,10 @@ struct Template { type(MetaType::INVALID) { } - Template(const QString &p, const uint32_t t) : - path(p) { - type = MetaType::name(t); + Template(const QString &p, const QString &t) : + path(p), + type(t) { + type = type.replace("*", ""); type = type.trimmed(); } diff --git a/engine/includes/resources/particleeffect.h b/engine/includes/resources/particleeffect.h deleted file mode 100644 index e52a638b3..000000000 --- a/engine/includes/resources/particleeffect.h +++ /dev/null @@ -1,141 +0,0 @@ -#ifndef PARTICLEEFFECT_H -#define PARTICLEEFFECT_H - -#include - -#include -#include - -#include -#include - -class ParticleModificator; - -struct ParticleTransientData { - Vector4 color; - - Vector4 uv; - - Vector3 velocity; - - float mass; - - Vector3 position; - - float life; - - Vector3 size; - - float lifetime; - - Vector3 rotation; - - float distance; - -}; - -class ENGINE_EXPORT ParticleEffect : public Resource { - A_REGISTER(ParticleEffect, Resource, Resources) - - A_PROPERTIES( - A_PROPERTY(int, capacity, ParticleEffect::capacity, ParticleEffect::setCapacity), - A_PROPERTY(Mesh *, mesh, ParticleEffect::mesh, ParticleEffect::setMesh), - A_PROPERTY(Material *, material, ParticleEffect::material, ParticleEffect::setMaterial), - A_PROPERTY(float, distibution, ParticleEffect::distribution, ParticleEffect::setDistribution), - A_PROPERTY(bool, local, ParticleEffect::local, ParticleEffect::setLocal), - A_PROPERTY(bool, continous, ParticleEffect::continous, ParticleEffect::setContinous) - ) - -public: - ParticleEffect(); - - int capacity() const; - void setCapacity(int capacity); - - Mesh *mesh() const; - void setMesh(Mesh *mesh); - - Material *material() const; - void setMaterial(Material *material); - - float distribution() const; - void setDistribution(float distibution); - - bool local() const; - void setLocal(bool local); - - bool gpu() const; - void setGpu(bool gpu); - - bool continous() const; - void setContinous(bool continuous); - - AABBox bound() const; - - const std::vector &modificators() const; - - void loadUserData(const VariantMap &data) override; - -protected: - std::vector m_modificators; - - AABBox m_aabb; - - Mesh *m_mesh; - - Material *m_material; - - float m_distibution; - - int m_capacity; - - bool m_gpu; - - bool m_local; - - bool m_continous; - -}; - -class ENGINE_EXPORT ParticleModificator { -public: - enum Randomness { - Off = 0, - PerComponent - }; - - enum Attribute { - Lifetime = 1, - Position, - Velocity, - Rotation, - Size, - Color, - - ScaleSize, - ScaleColor, - ScaleRotation - }; - -public: - explicit ParticleModificator(ParticleEffect *effect); - - virtual void spawnParticle(ParticleTransientData &data, int index) const; - virtual void updateParticle(std::vector &data, float dt) const; - - void setAttribute(Attribute attribute); - - void loadData(const VariantList &list); - -protected: - std::vector m_transientData; - - Attribute m_attribute; - - Randomness m_random; - - ParticleEffect *m_effect; - -}; - -#endif // PARTICLEEFFECT_H diff --git a/engine/includes/resources/visualeffect.h b/engine/includes/resources/visualeffect.h new file mode 100644 index 000000000..8ed6f9a6f --- /dev/null +++ b/engine/includes/resources/visualeffect.h @@ -0,0 +1,113 @@ +#ifndef VISUALEFFECT_H +#define VISUALEFFECT_H + +#include + +#include +#include + +class ENGINE_EXPORT VisualEffect : public Resource { + A_REGISTER(VisualEffect, Resource, Resources) + + A_NOPROPERTIES() + A_NOMETHODS() + A_NOENUMS() + +public: + struct Argument { + int32_t space; + + int32_t size; + + int32_t offset; + }; + + struct Operator { + int32_t op; + + int32_t resultSpace; + + int32_t resultOffset; + + int32_t resultSize; + + std::vector arguments; + + std::vector constData; + }; + + enum EmitterAttributes { + EmitterAge = 0, + DeltaTime, + AliveParticles, + SpawnRate, + SpawnCounter, + LastAttribute + }; + +public: + VisualEffect(); + + void update(std::vector &emitter, std::vector &particles, std::vector &render); + + int capacity() const; + void setCapacity(int capacity); + + Mesh *mesh() const; + void setMesh(Mesh *mesh); + + Material *material() const; + void setMaterial(Material *material); + + float spawnRate() const; + void setSpawnRate(float rate); + + bool local() const; + void setLocal(bool local); + + bool gpu() const; + void setGpu(bool gpu); + + bool continous() const; + void setContinous(bool continuous); + + int particleStride() const; + int renderableStride() const; + + AABBox bound() const; + + void loadUserData(const VariantMap &data) override; + +protected: + std::vector m_spawnOperations; + std::vector m_updateOperations; + std::vector m_renderOperations; + + AABBox m_aabb; + + Mesh *m_mesh; + + Material *m_material; + + float m_spawnRate; + + int m_capacity; + + int m_particleStride; + + int m_renderableStride; + + bool m_gpu; + + bool m_local; + + bool m_continous; + +private: + void apply(std::vector &operations, std::vector &emitter, std::vector &particle, std::vector &render, int stage) const; + + void loadOperations(const VariantList &list, std::vector &operations); + +}; + +#endif // VISUALEFFECT_H diff --git a/engine/src/components/effectrender.cpp b/engine/src/components/effectrender.cpp new file mode 100644 index 000000000..04a7283b9 --- /dev/null +++ b/engine/src/components/effectrender.cpp @@ -0,0 +1,168 @@ +#include "effectrender.h" + +#include +#include +#include + +#include "actor.h" +#include "transform.h" +#include "camera.h" + +#include "visualeffect.h" +#include "material.h" + +#include "commandbuffer.h" +#include "timer.h" + +/*! + \class EffectRender + \brief Draws a particle effect on the scene. + \inmodule Components + + The ParticleRender component allows you to display Particle Effects such as fire and explosions. +*/ + +EffectRender::EffectRender() : + m_effect(nullptr) { + +} + +EffectRender::~EffectRender() { + if(m_effect) { + m_effect->unsubscribe(this); + } +} +/*! + \internal +*/ +void EffectRender::update() { + deltaUpdate(Timer::deltaTime() * Timer::scale()); +} +/*! + \internal +*/ +void EffectRender::deltaUpdate(float dt) { + if(m_effect && isEnabled()) { + Camera *camera = Camera::current(); + if(camera == nullptr || m_materials.empty()) { + return; + } + + float &emitterAge = m_emitterData[VisualEffect::EmitterAge]; + float &deltaTime = m_emitterData[VisualEffect::DeltaTime]; + + deltaTime = dt; + + if(m_effect->continous() || emitterAge > 0.0f) { + float &emitterSpawnCounter = m_emitterData[VisualEffect::SpawnCounter]; + + emitterSpawnCounter += m_effect->spawnRate() * deltaTime; + + if(emitterAge > 0.0f) { + emitterAge -= dt; + } + } + + m_effect->update(m_emitterData, m_particleData, m_renderData); + + if(m_effect->local()) { + Matrix4 world(transform()->worldTransform()); + + int32_t count = static_cast(m_emitterData[VisualEffect::AliveParticles]); + int32_t stride = m_effect->renderableStride(); + + for(int32_t i = 0; i < count; i++) { + int index = i * stride; + Vector3 p(world * Vector3(m_renderData[index + 12], m_renderData[index + 13], m_renderData[index + 14])); + m_renderData[index + 12] = p.x; + m_renderData[index + 13] = p.y; + m_renderData[index + 14] = p.z; + } + } + + MaterialInstance *instance = m_materials.front(); + instance->setInstanceCount(static_cast(m_emitterData[VisualEffect::AliveParticles])); + + memcpy(instance->rawUniformBuffer().data(), m_renderData.data(), m_renderData.size()); + } +} +/*! + \internal +*/ +Mesh *EffectRender::meshToDraw() const { + return m_effect ? m_effect->mesh() : nullptr; +} +/*! + Returns a ParticleEffect assigned to the this component. +*/ +VisualEffect *EffectRender::effect() const { + return m_effect; +} +/*! + Assgines a particle \a effect to the this component. +*/ +void EffectRender::setEffect(VisualEffect *effect) { + PROFILE_FUNCTION(); + + if(m_effect) { + m_effect->unsubscribe(this); + } + + m_effect = effect; + if(m_effect) { + effectUpdated(Resource::Ready, this); + m_effect->subscribe(&EffectRender::effectUpdated, this); + } +} +/*! + \internal +*/ +AABBox EffectRender::localBound() const { + if(m_effect) { + m_effect->bound(); + } + return Renderable::localBound(); +} +/*! + \internal +*/ +void EffectRender::effectUpdated(int state, void *ptr) { + if(state == Resource::Ready) { + EffectRender *p = static_cast(ptr); + + // Update materials + for(auto it : p->m_materials) { + delete it; + } + p->m_materials.clear(); + + int capacity = p->m_effect->capacity(); + + if(p->m_effect->material()) { + MaterialInstance *instance = p->m_effect->material()->createInstance(Material::Billboard); + + instance->setInstanceCount(capacity); + + p->m_materials.push_back(instance); + } + + // Update emitter buffer + p->m_emitterData.resize(VisualEffect::LastAttribute); + // Update particles buffer + p->m_particleData.resize(capacity * p->m_effect->particleStride()); + + int renderableStride = p->m_effect->renderableStride(); + p->m_renderData.resize(capacity * renderableStride); + + Vector4 colorID(CommandBuffer::idToColor(p->actor()->uuid())); + + for(int i = 0; i < capacity; i++) { + int r = i * renderableStride; + + p->m_renderData[r + 3] = colorID.x; + p->m_renderData[r + 7] = colorID.y; + p->m_renderData[r + 11] = colorID.z; + p->m_renderData[r + 15] = colorID.w; + } + } +} diff --git a/engine/src/components/particlerender.cpp b/engine/src/components/particlerender.cpp deleted file mode 100644 index 9db9c51d8..000000000 --- a/engine/src/components/particlerender.cpp +++ /dev/null @@ -1,237 +0,0 @@ -#include "particlerender.h" - -#include -#include -#include - -#include "actor.h" -#include "transform.h" -#include "camera.h" - -#include "particleeffect.h" -#include "material.h" - -#include "commandbuffer.h" -#include "timer.h" - -namespace { - const char *gEffect("Effect"); -}; - -/*! - \class ParticleRender - \brief Draws a particle effect on the scene. - \inmodule Components - - The ParticleRender component allows you to display Particle Effects such as fire and explosions. -*/ - -ParticleRender::ParticleRender() : - m_ejectionTime(0.0f), - m_count(0.0f), - m_effect(nullptr) { - -} - -ParticleRender::~ParticleRender() { - if(m_effect) { - m_effect->unsubscribe(this); - } -} -/*! - \internal -*/ -void ParticleRender::update() { - deltaUpdate(Timer::deltaTime() * Timer::scale()); -} -/*! - \internal -*/ -void ParticleRender::deltaUpdate(float dt) { - if(m_effect && isEnabled()) { - Camera *camera = Camera::current(); - if(camera == nullptr || m_materials.empty()) { - return; - } - - bool local = m_effect->local(); - bool continous = m_effect->continous(); - - if(continous || m_ejectionTime > 0.0f) { - m_count += m_effect->distribution() * dt; - - for(int i = 0; i < m_particles.size(); i++) { - if(m_count >= 1.0f) { - ParticleTransientData &p = m_particles[i]; - if(p.life <= 0.0f) { - p.position = Vector3(); - p.size = Vector3(1.0f); - p.color = Vector4(1.0f); - p.uv = Vector4(1.0f, 1.0f, 0.0f, 0.0f); - - for(auto &it : m_effect->modificators()) { - it->spawnParticle(p, i); - } - - p.life = p.lifetime; - - m_count -= 1.0f; - } - } else { - break; - } - } - - if(!continous) { - m_ejectionTime -= dt; - } - } - - // Update particles - for(auto &it : m_effect->modificators()) { - it->updateParticle(m_particles, dt); - } - - Matrix4 world(transform()->worldTransform()); - Vector3 cameraPos(camera->transform()->worldPosition()); - - uint32_t visibleCount = 0; - for(int i = 0; i < m_particles.size(); i++) { - ParticleTransientData &p = m_particles[i]; - p.life -= dt; - - if(p.life > 0.0f) { - GpuQuadParticle &q = m_quads[visibleCount]; - - q.worldPosition = (local) ? world * p.position : p.position; - - q.sizeRot.x = p.size.x; - q.sizeRot.y = p.size.y; - q.sizeRot.z = p.rotation.z; - - q.uvScaleDist.x = p.uv.x; - q.uvScaleDist.y = p.uv.y; - q.uvScaleDist.z = (cameraPos - q.worldPosition).sqrLength(); - - q.uvOffset.x = p.uv.z; - q.uvOffset.y = p.uv.w; - - q.color = p.color; - - visibleCount++; - } - } - - std::sort(m_quads.begin(), m_quads.end(), [](const GpuQuadParticle &left, const GpuQuadParticle &right) { return left.uvScaleDist.z > right.uvScaleDist.z; }); - - MaterialInstance *instance = m_materials.front(); - instance->setInstanceCount(visibleCount); - - memcpy(instance->rawUniformBuffer().data(), m_quads.data(), sizeof(GpuQuadParticle) * m_quads.size()); - } -} -/*! - \internal -*/ -Mesh *ParticleRender::meshToDraw() const { - return m_effect ? m_effect->mesh() : nullptr; -} -/*! - Returns a ParticleEffect assigned to the this component. -*/ -ParticleEffect *ParticleRender::effect() const { - return m_effect; -} -/*! - Assgines a particle \a effect to the this component. -*/ -void ParticleRender::setEffect(ParticleEffect *effect) { - PROFILE_FUNCTION(); - - if(m_effect != effect) { - if(m_effect) { - m_effect->unsubscribe(this); - } - - m_effect = effect; - if(m_effect) { - effectUpdated(Resource::Ready, this); - m_effect->subscribe(&ParticleRender::effectUpdated, this); - } - } -} -/*! - \internal -*/ -AABBox ParticleRender::localBound() const { - if(m_effect) { - m_effect->bound(); - } - return Renderable::localBound(); -} -/*! - \internal -*/ -void ParticleRender::loadUserData(const VariantMap &data) { - PROFILE_FUNCTION(); - - Component::loadUserData(data); - - auto it = data.find(gEffect); - if(it != data.end()) { - setEffect(Engine::loadResource((*it).second.toString())); - } -} -/*! - \internal -*/ -VariantMap ParticleRender::saveUserData() const { - PROFILE_FUNCTION(); - - VariantMap result = Component::saveUserData(); - - std::string ref = Engine::reference(m_effect); - if(!ref.empty()) { - result[gEffect] = ref; - } - - return result; -} -/*! - \internal -*/ -void ParticleRender::effectUpdated(int state, void *ptr) { - if(state == Resource::Ready) { - ParticleRender *p = static_cast(ptr); - - // Update materials - for(auto it : p->m_materials) { - delete it; - } - p->m_materials.clear(); - - int capacity = p->m_effect->capacity(); - - if(p->m_effect->material()) { - MaterialInstance *instance = p->m_effect->material()->createInstance(Material::Billboard); - - instance->setInstanceCount(capacity); - - p->m_materials.push_back(instance); - } - - // Update particles pool - p->m_particles.resize(capacity); - - p->m_quads.resize(capacity); - - Vector4 colorID(CommandBuffer::idToColor(p->actor()->uuid())); - - for(int i = 0; i < capacity; i++) { - p->m_quads[i].worldPosition.w = colorID.x; - p->m_quads[i].sizeRot.w = colorID.y; - p->m_quads[i].uvScaleDist.w = colorID.z; - p->m_quads[i].uvOffset.w = colorID.w; - } - } -} diff --git a/engine/src/editor/projectsettings.cpp b/engine/src/editor/projectsettings.cpp index d0ea7d71b..c7b4338ab 100644 --- a/engine/src/editor/projectsettings.cpp +++ b/engine/src/editor/projectsettings.cpp @@ -15,6 +15,7 @@ #include "config.h" +#include #include #include @@ -131,7 +132,7 @@ void ProjectSettings::loadSettings() { if(index > -1) { QMetaProperty property = meta->property(index); if(property.userType() == qMetaTypeId