Reflection rework (#1357)

new reflection system - faster to compiler, saner errors
This commit is contained in:
Mikulas Florek 2021-03-04 22:06:18 +01:00 committed by GitHub
parent b2ea3536cb
commit 4bf33479b1
40 changed files with 1005 additions and 1189 deletions

View file

@ -1,7 +1,6 @@
#pragma once #pragma once
#include "engine/hash_map.h" #include "engine/hash_map.h"
#include "engine/math.h"
#include "engine/resource.h" #include "engine/resource.h"
#include "engine/string.h" #include "engine/string.h"

View file

@ -950,24 +950,21 @@ UniquePtr<AnimationScene> AnimationScene::create(Engine& engine, IPlugin& plugin
} }
void AnimationScene::reflect(Engine& engine) { void AnimationScene::reflect(Engine& engine) {
LUMIX_SCENE(AnimationSceneImpl, "animation", LUMIX_SCENE(AnimationSceneImpl, "animation")
LUMIX_CMP(PropertyAnimator, "property_animator", "Animation / Property animator", .LUMIX_CMP(PropertyAnimator, "property_animator", "Animation / Property animator")
LUMIX_PROP(PropertyAnimation, "Animation", ResourceAttribute(PropertyAnimation::TYPE)), .LUMIX_PROP(PropertyAnimation, "Animation").resourceAttribute(PropertyAnimation::TYPE)
property("Enabled", &AnimationScene::isPropertyAnimatorEnabled, &AnimationScene::enablePropertyAnimator) .prop<&AnimationScene::isPropertyAnimatorEnabled, &AnimationScene::enablePropertyAnimator>("Enabled")
), .LUMIX_CMP(Animator, "animator", "Animation / Animator")
LUMIX_CMP(Animator, "animator", "Animation / Animator", .function<(void (AnimationScene::*)(EntityRef, u32, u32))&AnimationScene::setAnimatorInput>("AnimationScene::setAnimatorInput", "setU32Input")
function((void (AnimationScene::*)(EntityRef, u32, u32))&AnimationScene::setAnimatorInput, "AnimationScene::setAnimatorInput", "setU32Input"), .function<(void (AnimationScene::*)(EntityRef, u32, float))&AnimationScene::setAnimatorInput>("AnimationScene::setAnimatorInput", "setFloatInput")
function((void (AnimationScene::*)(EntityRef, u32, float))&AnimationScene::setAnimatorInput, "AnimationScene::setAnimatorInput", "setFloatInput"), .function<(void (AnimationScene::*)(EntityRef, u32, bool))&AnimationScene::setAnimatorInput>("AnimationScene::setAnimatorInput", "setBoolInput")
function((void (AnimationScene::*)(EntityRef, u32, bool))&AnimationScene::setAnimatorInput, "AnimationScene::setAnimatorInput", "setBoolInput"), .LUMIX_FUNC_EX(getAnimatorInputIndex, "getInputIndex")
LUMIX_FUNC_EX(AnimationScene::getAnimatorInputIndex, "getInputIndex"), .LUMIX_FUNC_EX(setAnimatorIK, "setIK")
LUMIX_FUNC_EX(AnimationScene::setAnimatorIK, "setIK"), .LUMIX_PROP(AnimatorSource, "Source").resourceAttribute(anim::Controller::TYPE)
LUMIX_PROP(AnimatorSource, "Source", ResourceAttribute(anim::Controller::TYPE)), .LUMIX_PROP(AnimatorDefaultSet, "Default set")
LUMIX_PROP(AnimatorDefaultSet, "Default set") .LUMIX_CMP(Animable, "animable", "Animation / Animable")
), .LUMIX_PROP(Animation, "Animation").resourceAttribute(Animation::TYPE)
LUMIX_CMP(Animable, "animable", "Animation / Animable", ;
LUMIX_PROP(Animation, "Animation", ResourceAttribute(Animation::TYPE))
)
);
} }
} // namespace Lumix } // namespace Lumix

View file

@ -4,7 +4,6 @@
#include "animation/property_animation.h" #include "animation/property_animation.h"
#include "animation/controller.h" #include "animation/controller.h"
#include "engine/engine.h" #include "engine/engine.h"
#include "engine/reflection.h"
#include "engine/resource_manager.h" #include "engine/resource_manager.h"
#include "engine/universe.h" #include "engine/universe.h"

View file

@ -9,7 +9,6 @@
#include "engine/crc32.h" #include "engine/crc32.h"
#include "engine/engine.h" #include "engine/engine.h"
#include "engine/log.h" #include "engine/log.h"
#include "engine/reflection.h"
#include "engine/resource_manager.h" #include "engine/resource_manager.h"
#include "engine/universe.h" #include "engine/universe.h"
#include "renderer/model.h" #include "renderer/model.h"

View file

@ -490,27 +490,24 @@ UniquePtr<AudioScene> AudioScene::createInstance(AudioSystem& system,
} }
void AudioScene::reflect(Engine& engine) { void AudioScene::reflect(Engine& engine) {
LUMIX_SCENE(AudioSceneImpl, "audio", LUMIX_SCENE(AudioSceneImpl, "audio")
LUMIX_FUNC(AudioScene::setMasterVolume), .LUMIX_FUNC(AudioScene::setMasterVolume)
LUMIX_FUNC(AudioScene::play), .LUMIX_FUNC(AudioScene::play)
LUMIX_FUNC(AudioScene::setVolume), .LUMIX_FUNC(AudioScene::setVolume)
LUMIX_FUNC(AudioScene::setEcho), .LUMIX_FUNC(AudioScene::setEcho)
LUMIX_CMP(AmbientSound, "ambient_sound", "Audio / Ambient sound", .LUMIX_CMP(AmbientSound, "ambient_sound", "Audio / Ambient sound")
LUMIX_FUNC_EX(AudioScene::pauseAmbientSound, "pause"), .LUMIX_FUNC_EX(AudioScene::pauseAmbientSound, "pause")
LUMIX_FUNC_EX(AudioScene::resumeAmbientSound, "resume"), .LUMIX_FUNC_EX(AudioScene::resumeAmbientSound, "resume")
property("3D", &AudioScene::isAmbientSound3D, &AudioScene::setAmbientSound3D), .prop<&AudioScene::isAmbientSound3D, &AudioScene::setAmbientSound3D>("3D")
LUMIX_PROP(AmbientSoundClip, "Sound", ResourceAttribute(Clip::TYPE)) .LUMIX_PROP(AmbientSoundClip, "Sound").resourceAttribute(Clip::TYPE)
), .LUMIX_CMP(Listener, "audio_listener", "Audio / Listener").icon(ICON_FA_HEADPHONES)
LUMIX_CMP(Listener, "audio_listener", "Audio / Listener", icon(ICON_FA_HEADPHONES)), .LUMIX_CMP(EchoZone, "echo_zone", "Audio / Echo zone")
LUMIX_CMP(EchoZone, "echo_zone", "Audio / Echo zone", .var_prop<&AudioScene::getEchoZone, &EchoZone::radius>("Radius").minAttribute(0)
var_property("Radius", &AudioScene::getEchoZone, &EchoZone::radius, MinAttribute(0)), .var_prop<&AudioScene::getEchoZone, &EchoZone::delay>("Delay (ms)").minAttribute(0)
var_property("Delay (ms)", &AudioScene::getEchoZone, &EchoZone::delay, MinAttribute(0)) .LUMIX_CMP(ChorusZone, "chorus_zone", "Audio / Chorus zone")
), .var_prop<&AudioScene::getChorusZone, &ChorusZone::radius>("Radius").minAttribute(0)
LUMIX_CMP(ChorusZone, "chorus_zone", "Audio / Chorus zone", .var_prop<&AudioScene::getChorusZone, &ChorusZone::delay>("Delay (ms)").minAttribute(0)
var_property("Radius", &AudioScene::getChorusZone, &ChorusZone::radius, MinAttribute(0)), ;
var_property("Delay (ms)", &AudioScene::getChorusZone, &ChorusZone::delay, MinAttribute(0))
)
);
} }

View file

@ -12,7 +12,6 @@
#include "engine/crc32.h" #include "engine/crc32.h"
#include "engine/engine.h" #include "engine/engine.h"
#include "engine/lua_wrapper.h" #include "engine/lua_wrapper.h"
#include "engine/reflection.h"
#include "engine/universe.h" #include "engine/universe.h"

View file

@ -335,25 +335,25 @@ public:
void visit(const reflection::Property<bool>& prop) override { clone(prop); } void visit(const reflection::Property<bool>& prop) override { clone(prop); }
void visit(const reflection::Property<const char*>& prop) override { clone(prop); } void visit(const reflection::Property<const char*>& prop) override { clone(prop); }
void visit(const reflection::IArrayProperty& prop) override { void visit(const reflection::ArrayProperty& prop) override {
const i32 c = prop.getCount(src); const u32 c = prop.getCount(src);
while (prop.getCount(dst) < c) { prop.addItem(dst, prop.getCount(dst) - 1); } while (prop.getCount(dst) < c) { prop.addItem(dst, prop.getCount(dst) - 1); }
while (prop.getCount(dst) > c) { prop.removeItem(dst, prop.getCount(dst) - 1); } while (prop.getCount(dst) > c) { prop.removeItem(dst, prop.getCount(dst) - 1); }
ASSERT(index == -1); ASSERT(index == -1);
for (int i = 0; i < c; ++i) { for (u32 i = 0; i < c; ++i) {
index = i; index = i;
prop.visit(*this); prop.visit(*this);
} }
index = -1; index = -1;
} }
void visit(const reflection::IDynamicProperties& prop) override { void visit(const reflection::DynamicProperties& prop) override {
for (u32 i = 0, c = prop.getCount(src, index); i < c; ++i) { for (u32 i = 0, c = prop.getCount(src, index); i < c; ++i) {
const char* name = prop.getName(src, index, i); const char* name = prop.getName(src, index, i);
reflection::IDynamicProperties::Type type = prop.getType(src, index, i); reflection::DynamicProperties::Type type = prop.getType(src, index, i);
reflection::IDynamicProperties::Value val = prop.getValue(src, index, i); reflection::DynamicProperties::Value val = prop.getValue(src, index, i);
if (type == reflection::IDynamicProperties::ENTITY) { if (type == reflection::DynamicProperties::ENTITY) {
auto iter = map->find(val.e); auto iter = map->find(val.e);
if (iter.isValid()) { if (iter.isValid()) {
val.e = iter.value(); val.e = iter.value();
@ -365,12 +365,15 @@ public:
prop.set(dst, index, name, type, val); prop.set(dst, index, name, type, val);
} }
} }
void visit(const reflection::IBlobProperty& prop) override {
void visit(const reflection::BlobProperty& prop) override {
OutputMemoryStream tmp(*allocator); OutputMemoryStream tmp(*allocator);
prop.getValue(src, index, tmp); prop.getValue(src, index, tmp);
InputMemoryStream blob(tmp); InputMemoryStream blob(tmp);
prop.setValue(dst, index, blob); prop.setValue(dst, index, blob);
} }
const HashMap<EntityPtr, EntityPtr>* map; const HashMap<EntityPtr, EntityPtr>* map;
IAllocator* allocator; IAllocator* allocator;

View file

@ -78,7 +78,7 @@ struct GridUIVisitor final : reflection::IPropertyVisitor
static Attributes getAttributes(const reflection::Property<T>& prop) static Attributes getAttributes(const reflection::Property<T>& prop)
{ {
Attributes attrs; Attributes attrs;
for (const reflection::IAttribute* attr : prop.getAttributes()) { for (const reflection::IAttribute* attr : prop.attributes) {
switch (attr->getType()) { switch (attr->getType()) {
case reflection::IAttribute::RADIANS: case reflection::IAttribute::RADIANS:
attrs.is_radians = true; attrs.is_radians = true;
@ -108,90 +108,92 @@ struct GridUIVisitor final : reflection::IPropertyVisitor
} }
template <typename T> template <typename T>
void dynamicProperty(const ComponentUID& cmp, const reflection::IDynamicProperties& prop, u32 prop_index) { void dynamicProperty(const ComponentUID& cmp, const reflection::DynamicProperties& prop, u32 prop_index) {
struct : reflection::Property<T> { struct Prop : reflection::Property<T> {
Span<const reflection::IAttribute* const> getAttributes() const override { return {}; } Prop(IAllocator& allocator) : reflection::Property<T>(allocator) {}
T get(ComponentUID cmp, int array_index) const override { T get(ComponentUID cmp, u32 array_index) const override {
return reflection::get<T>(prop->getValue(cmp, array_index, index)); return reflection::get<T>(prop->getValue(cmp, array_index, index));
} }
void set(ComponentUID cmp, int array_index, T value) const override { void set(ComponentUID cmp, u32 array_index, T value) const override {
reflection::IDynamicProperties::Value v; reflection::DynamicProperties::Value v;
reflection::set<T>(v, value); reflection::set<T>(v, value);
prop->set(cmp, array_index, index, v); prop->set(cmp, array_index, index, v);
} }
const reflection::IDynamicProperties* prop; const reflection::DynamicProperties* prop;
ComponentUID cmp; ComponentUID cmp;
int index; int index;
} p; } p(m_app.getAllocator());
p.name = prop.getName(cmp, m_index, prop_index); p.name = prop.getName(cmp, m_index, prop_index);
p.prop = &prop; p.prop = &prop;
p.index = prop_index; p.index = prop_index;
visit(p); visit(p);
} }
void visit(const reflection::IDynamicProperties& prop) override { void visit(const reflection::DynamicProperties& prop) override {
ComponentUID cmp = getComponent();; ComponentUID cmp = getComponent();;
for (u32 i = 0, c = prop.getCount(cmp, m_index); i < c; ++i) { for (u32 i = 0, c = prop.getCount(cmp, m_index); i < c; ++i) {
const reflection::IDynamicProperties::Type type = prop.getType(cmp, m_index, i); const reflection::DynamicProperties::Type type = prop.getType(cmp, m_index, i);
switch(type) { switch(type) {
case reflection::IDynamicProperties::FLOAT: dynamicProperty<float>(cmp, prop, i); break; case reflection::DynamicProperties::FLOAT: dynamicProperty<float>(cmp, prop, i); break;
case reflection::IDynamicProperties::BOOLEAN: dynamicProperty<bool>(cmp, prop, i); break; case reflection::DynamicProperties::BOOLEAN: dynamicProperty<bool>(cmp, prop, i); break;
case reflection::IDynamicProperties::ENTITY: dynamicProperty<EntityPtr>(cmp, prop, i); break; case reflection::DynamicProperties::ENTITY: dynamicProperty<EntityPtr>(cmp, prop, i); break;
case reflection::IDynamicProperties::I32: dynamicProperty<i32>(cmp, prop, i); break; case reflection::DynamicProperties::I32: dynamicProperty<i32>(cmp, prop, i); break;
case reflection::IDynamicProperties::STRING: dynamicProperty<const char*>(cmp, prop, i); break; case reflection::DynamicProperties::STRING: dynamicProperty<const char*>(cmp, prop, i); break;
case reflection::IDynamicProperties::COLOR: { case reflection::DynamicProperties::COLOR: {
struct : reflection::Property<Vec3> { struct Prop : reflection::Property<Vec3> {
Span<const reflection::IAttribute* const> getAttributes() const override { Prop(IAllocator& allocator) : Property<Vec3>(allocator) {}
return Span((const reflection::IAttribute*const*)attrs, 1);
} Vec3 get(ComponentUID cmp, u32 array_index) const override {
Vec3 get(ComponentUID cmp, int array_index) const override {
return reflection::get<Vec3>(prop->getValue(cmp, array_index, index)); return reflection::get<Vec3>(prop->getValue(cmp, array_index, index));
} }
void set(ComponentUID cmp, int array_index, Vec3 value) const override { void set(ComponentUID cmp, u32 array_index, Vec3 value) const override {
reflection::IDynamicProperties::Value v; reflection::DynamicProperties::Value v;
reflection::set(v, value); reflection::set(v, value);
prop->set(cmp, array_index, index, v); prop->set(cmp, array_index, index, v);
} }
const reflection::IDynamicProperties* prop;
const reflection::DynamicProperties* prop;
ComponentUID cmp; ComponentUID cmp;
int index; int index;
reflection::ColorAttribute attr; reflection::ColorAttribute attr;
reflection::IAttribute* attrs[1] = { &attr }; } p(m_app.getAllocator());
} p;
p.name = prop.getName(cmp, m_index, i); p.name = prop.getName(cmp, m_index, i);
p.prop = &prop; p.prop = &prop;
p.index = i; p.index = i;
p.attributes.push(&p.attr);
visit(p); visit(p);
break; break;
} }
case reflection::IDynamicProperties::RESOURCE: { case reflection::DynamicProperties::RESOURCE: {
struct : reflection::Property<Path> { struct Prop : reflection::Property<Path> {
Span<const reflection::IAttribute* const> getAttributes() const override { Prop(IAllocator& allocator) : Property<Path>(allocator) {}
return Span((const reflection::IAttribute*const*)attrs, 1);
} Path get(ComponentUID cmp, u32 array_index) const override {
Path get(ComponentUID cmp, int array_index) const override {
return Path(reflection::get<const char*>(prop->getValue(cmp, array_index, index))); return Path(reflection::get<const char*>(prop->getValue(cmp, array_index, index)));
} }
void set(ComponentUID cmp, int array_index, Path value) const override {
reflection::IDynamicProperties::Value v; void set(ComponentUID cmp, u32 array_index, Path value) const override {
reflection::DynamicProperties::Value v;
reflection::set(v, value.c_str()); reflection::set(v, value.c_str());
prop->set(cmp, array_index, index, v); prop->set(cmp, array_index, index, v);
} }
const reflection::IDynamicProperties* prop;
const reflection::DynamicProperties* prop;
ComponentUID cmp; ComponentUID cmp;
int index; int index;
reflection::ResourceAttribute attr; reflection::ResourceAttribute attr;
reflection::IAttribute* attrs[1] = { &attr }; } p(m_app.getAllocator());
} p;
p.attr = prop.getResourceAttribute(cmp, m_index, i); p.attr = prop.getResourceAttribute(cmp, m_index, i);
p.name = prop.getName(cmp, m_index, i); p.name = prop.getName(cmp, m_index, i);
p.prop = &prop; p.prop = &prop;
p.index = i; p.index = i;
p.attributes.push(&p.attr);
visit(p); visit(p);
break; break;
} }
@ -200,7 +202,6 @@ struct GridUIVisitor final : reflection::IPropertyVisitor
} }
} }
void visit(const reflection::Property<float>& prop) override void visit(const reflection::Property<float>& prop) override
{ {
Attributes attrs = getAttributes(prop); Attributes attrs = getAttributes(prop);
@ -556,11 +557,9 @@ struct GridUIVisitor final : reflection::IPropertyVisitor
ImGui::PopID(); ImGui::PopID();
} }
void visit(const reflection::BlobProperty& prop) override {}
void visit(const reflection::IBlobProperty& prop) override {} void visit(const reflection::ArrayProperty& prop) override
void visit(const reflection::IArrayProperty& prop) override
{ {
ImGui::Unindent(); ImGui::Unindent();
bool is_open = ImGui::TreeNodeEx(prop.name, ImGuiTreeNodeFlags_AllowItemOverlap); bool is_open = ImGui::TreeNodeEx(prop.name, ImGuiTreeNodeFlags_AllowItemOverlap);
@ -611,7 +610,7 @@ struct GridUIVisitor final : reflection::IPropertyVisitor
{ {
GridUIVisitor v(m_app, i, m_entities, m_cmp_type, m_editor); GridUIVisitor v(m_app, i, m_entities, m_cmp_type, m_editor);
v.m_array = prop.name; v.m_array = prop.name;
prop.visit(v); prop.visitChildren(v);
ImGui::TreePop(); ImGui::TreePop();
} }

View file

@ -2581,7 +2581,7 @@ struct StudioAppImpl final : StudioApp
struct : reflection::IEmptyPropertyVisitor { struct : reflection::IEmptyPropertyVisitor {
void visit(const reflection::Property<Path>& prop) override { void visit(const reflection::Property<Path>& prop) override {
for (const reflection::IAttribute* attr : prop.getAttributes()) { for (const reflection::IAttribute* attr : prop.attributes) {
if (attr->getType() == reflection::IAttribute::RESOURCE) { if (attr->getType() == reflection::IAttribute::RESOURCE) {
is_res = true; is_res = true;
reflection::ResourceAttribute* a = (reflection::ResourceAttribute*)attr; reflection::ResourceAttribute* a = (reflection::ResourceAttribute*)attr;
@ -2792,8 +2792,8 @@ struct StudioAppImpl final : StudioApp
} }
void visit(const reflection::Property<EntityPtr>& prop) override { notSupported(prop); } void visit(const reflection::Property<EntityPtr>& prop) override { notSupported(prop); }
void visit(const reflection::IArrayProperty& prop) override { notSupported(prop); } void visit(const reflection::ArrayProperty& prop) override { notSupported(prop); }
void visit(const reflection::IBlobProperty& prop) override { notSupported(prop); } void visit(const reflection::BlobProperty& prop) override { notSupported(prop); }
template <typename T> template <typename T>
void notSupported(const T& prop) void notSupported(const T& prop)

View file

@ -3,7 +3,6 @@
#include "utils.h" #include "utils.h"
#include "engine/math.h" #include "engine/math.h"
#include "engine/path.h" #include "engine/path.h"
#include "engine/reflection.h"
#include "editor/render_interface.h" #include "editor/render_interface.h"
#include "editor/studio_app.h" #include "editor/studio_app.h"
#include "editor/world_editor.h" #include "editor/world_editor.h"

View file

@ -341,6 +341,51 @@ void addSphere(UniverseView& view, const DVec3& center, float radius, Color colo
} }
} }
template <typename T> void writeToStream(OutputMemoryStream& stream, T value) { stream.write(value); }
template <typename T> T readFromStream(InputMemoryStream& stream) { return stream.read<T>(); }
template <> LUMIX_ENGINE_API Path readFromStream<Path>(InputMemoryStream& stream);
template <> LUMIX_ENGINE_API void writeToStream<Path>(OutputMemoryStream& stream, Path);
template <> LUMIX_ENGINE_API void writeToStream<const Path&>(OutputMemoryStream& stream, const Path& path);
template <> LUMIX_ENGINE_API const char* readFromStream<const char*>(InputMemoryStream& stream);
template <> LUMIX_ENGINE_API void writeToStream<const char*>(OutputMemoryStream& stream, const char* path);
template <> Path readFromStream<Path>(InputMemoryStream& stream)
{
const char* c_str = (const char*)stream.getData() + stream.getPosition();
Path path(c_str);
stream.skip(stringLength(c_str) + 1);
return path;
}
template <> void writeToStream<const Path&>(OutputMemoryStream& stream, const Path& path)
{
const char* str = path.c_str();
stream.write(str, stringLength(str) + 1);
}
template <> void writeToStream<Path>(OutputMemoryStream& stream, Path path)
{
const char* str = path.c_str();
stream.write(str, stringLength(str) + 1);
}
template <> const char* readFromStream<const char*>(InputMemoryStream& stream)
{
const char* c_str = (const char*)stream.getData() + stream.getPosition();
stream.skip(stringLength(c_str) + 1);
return c_str;
}
template <> void writeToStream<const char*>(OutputMemoryStream& stream, const char* value)
{
stream.write(value, stringLength(value) + 1);
}
struct PropertyDeserializeVisitor : reflection::IPropertyVisitor { struct PropertyDeserializeVisitor : reflection::IPropertyVisitor {
PropertyDeserializeVisitor(Ref<InputMemoryStream> deserializer PropertyDeserializeVisitor(Ref<InputMemoryStream> deserializer
, ComponentUID cmp , ComponentUID cmp
@ -354,7 +399,7 @@ struct PropertyDeserializeVisitor : reflection::IPropertyVisitor {
template <typename T> template <typename T>
void set(const reflection::Property<T>& prop) { void set(const reflection::Property<T>& prop) {
prop.set(cmp, idx, reflection::readFromStream<T>(deserializer)); prop.set(cmp, idx, readFromStream<T>(deserializer));
} }
void visit(const reflection::Property<float>& prop) override { set(prop); } void visit(const reflection::Property<float>& prop) override { set(prop); }
@ -365,28 +410,28 @@ struct PropertyDeserializeVisitor : reflection::IPropertyVisitor {
void visit(const reflection::Property<IVec3>& prop) override { set(prop); } void visit(const reflection::Property<IVec3>& prop) override { set(prop); }
void visit(const reflection::Property<Vec4>& prop) override { set(prop); } void visit(const reflection::Property<Vec4>& prop) override { set(prop); }
void visit(const reflection::Property<bool>& prop) override { set(prop); } void visit(const reflection::Property<bool>& prop) override { set(prop); }
void visit(const reflection::IBlobProperty& prop) override { prop.setValue(cmp, idx, deserializer); }
void visit(const reflection::Property<const char*>& prop) override { set(prop); } void visit(const reflection::Property<const char*>& prop) override { set(prop); }
void visit(const reflection::Property<Path>& prop) override { set(prop); } void visit(const reflection::Property<Path>& prop) override { set(prop); }
void visit(const reflection::BlobProperty& prop) override { prop.setValue(cmp, idx, deserializer); }
void visit(const reflection::IDynamicProperties& prop) override { void visit(const reflection::DynamicProperties& prop) override {
u32 c; u32 c;
deserializer.read(c); deserializer.read(c);
for (u32 i = 0; i < c; ++i) { for (u32 i = 0; i < c; ++i) {
const char* name = deserializer.readString(); const char* name = deserializer.readString();
reflection::IDynamicProperties::Type type; reflection::DynamicProperties::Type type;
deserializer.read(type); deserializer.read(type);
switch(type) { switch(type) {
case reflection::IDynamicProperties::RESOURCE: case reflection::DynamicProperties::RESOURCE:
case reflection::IDynamicProperties::STRING: { case reflection::DynamicProperties::STRING: {
const char* tmp = deserializer.readString(); const char* tmp = deserializer.readString();
reflection::IDynamicProperties::Value v; reflection::DynamicProperties::Value v;
v.s = tmp; v.s = tmp;
prop.set(cmp, idx, name, type, v); prop.set(cmp, idx, name, type, v);
break; break;
} }
default: { default: {
reflection::IDynamicProperties::Value v; reflection::DynamicProperties::Value v;
deserializer.read(v); deserializer.read(v);
prop.set(cmp, idx, name, type, v); prop.set(cmp, idx, name, type, v);
break; break;
@ -394,7 +439,7 @@ struct PropertyDeserializeVisitor : reflection::IPropertyVisitor {
} }
} }
} }
void visit(const reflection::Property<EntityPtr>& prop) override { void visit(const reflection::Property<EntityPtr>& prop) override {
EntityPtr value; EntityPtr value;
deserializer.read(Ref(value)); deserializer.read(Ref(value));
@ -404,8 +449,8 @@ struct PropertyDeserializeVisitor : reflection::IPropertyVisitor {
prop.set(cmp, idx, value); prop.set(cmp, idx, value);
} }
void visit(const reflection::IArrayProperty& prop) override { void visit(const reflection::ArrayProperty& prop) override {
int count; u32 count;
deserializer.read(Ref(count)); deserializer.read(Ref(count));
const int idx_backup = idx; const int idx_backup = idx;
while (prop.getCount(cmp) > count) { while (prop.getCount(cmp) > count) {
@ -414,9 +459,9 @@ struct PropertyDeserializeVisitor : reflection::IPropertyVisitor {
while (prop.getCount(cmp) < count) { while (prop.getCount(cmp) < count) {
prop.addItem(cmp, -1); prop.addItem(cmp, -1);
} }
for (int i = 0; i < count; ++i) { for (u32 i = 0; i < count; ++i) {
idx = i; idx = i;
prop.visit(*this); prop.visitChildren(*this);
} }
idx = idx_backup; idx = idx_backup;
} }
@ -436,7 +481,7 @@ struct PropertySerializeVisitor : reflection::IPropertyVisitor {
template <typename T> template <typename T>
void get(const reflection::Property<T>& prop) { void get(const reflection::Property<T>& prop) {
reflection::writeToStream(serializer, prop.get(cmp, idx)); writeToStream(serializer, prop.get(cmp, idx));
} }
void visit(const reflection::Property<float>& prop) override { get(prop); } void visit(const reflection::Property<float>& prop) override { get(prop); }
@ -448,22 +493,22 @@ struct PropertySerializeVisitor : reflection::IPropertyVisitor {
void visit(const reflection::Property<IVec3>& prop) override { get(prop); } void visit(const reflection::Property<IVec3>& prop) override { get(prop); }
void visit(const reflection::Property<Vec4>& prop) override { get(prop); } void visit(const reflection::Property<Vec4>& prop) override { get(prop); }
void visit(const reflection::Property<bool>& prop) override { get(prop); } void visit(const reflection::Property<bool>& prop) override { get(prop); }
void visit(const reflection::IBlobProperty& prop) override { prop.getValue(cmp, idx, serializer); } void visit(const reflection::BlobProperty& prop) override { prop.getValue(cmp, idx, serializer); }
void visit(const reflection::Property<Path>& prop) override { get(prop); } void visit(const reflection::Property<Path>& prop) override { get(prop); }
void visit(const reflection::Property<const char*>& prop) override { get(prop); } void visit(const reflection::Property<const char*>& prop) override { get(prop); }
void visit(const reflection::IDynamicProperties& prop) override { void visit(const reflection::DynamicProperties& prop) override {
const u32 c = prop.getCount(cmp, idx); const u32 c = prop.getCount(cmp, idx);
serializer.write(c); serializer.write(c);
for (u32 i = 0; i < c; ++i) { for (u32 i = 0; i < c; ++i) {
const char* name = prop.getName(cmp, idx, i); const char* name = prop.getName(cmp, idx, i);
serializer.writeString(name); serializer.writeString(name);
const reflection::IDynamicProperties::Type type = prop.getType(cmp, idx, i); const reflection::DynamicProperties::Type type = prop.getType(cmp, idx, i);
serializer.write(type); serializer.write(type);
const reflection::IDynamicProperties::Value v = prop.getValue(cmp, idx, i); const reflection::DynamicProperties::Value v = prop.getValue(cmp, idx, i);
switch(type) { switch(type) {
case reflection::IDynamicProperties::RESOURCE: case reflection::DynamicProperties::RESOURCE:
case reflection::IDynamicProperties::STRING: case reflection::DynamicProperties::STRING:
serializer.writeString(v.s); serializer.writeString(v.s);
break; break;
default: default:
@ -473,20 +518,20 @@ struct PropertySerializeVisitor : reflection::IPropertyVisitor {
} }
} }
void visit(const reflection::IArrayProperty& prop) override { void visit(const reflection::ArrayProperty& prop) override {
const int count = prop.getCount(cmp); const int count = prop.getCount(cmp);
serializer.write(count); serializer.write(count);
const int idx_backup = idx; const int idx_backup = idx;
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
idx = i; idx = i;
prop.visit(*this); prop.visitChildren(*this);
} }
idx = idx_backup; idx = idx_backup;
} }
OutputMemoryStream& serializer; OutputMemoryStream& serializer;
ComponentUID cmp; ComponentUID cmp;
int idx; int idx = -1;
}; };
@ -917,12 +962,12 @@ private:
struct GatherResourcesVisitor final : reflection::IEmptyPropertyVisitor struct GatherResourcesVisitor final : reflection::IEmptyPropertyVisitor
{ {
void visit(const reflection::IArrayProperty& prop) override void visit(const reflection::ArrayProperty& prop) override
{ {
int count = prop.getCount(cmp); int count = prop.getCount(cmp);
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
index = i; index = i;
prop.visit(*this); prop.visitChildren(*this);
} }
index = -1; index = -1;
} }
@ -966,7 +1011,7 @@ public:
bool execute() override bool execute() override
{ {
struct : reflection::IEmptyPropertyVisitor { struct : reflection::IEmptyPropertyVisitor {
void visit(const reflection::IArrayProperty& prop) override { void visit(const reflection::ArrayProperty& prop) override {
if (!equalStrings(prop.name, propname)) return; if (!equalStrings(prop.name, propname)) return;
prop.removeItem(cmp, index); prop.removeItem(cmp, index);
} }
@ -1022,20 +1067,9 @@ public:
bool execute() override bool execute() override
{ {
struct : reflection::IEmptyPropertyVisitor { reflection::ArrayProperty* prop = (reflection::ArrayProperty*)reflection::getProperty(m_component.type, m_property);
void visit(const reflection::IArrayProperty& prop) override { m_index = prop->getCount(m_component);
if (!equalStrings(prop.name, prop_name)) return; prop->addItem(m_component, m_index);
index = prop.getCount(cmp);
prop.addItem(cmp, index);
}
ComponentUID cmp;
int index;
const char* prop_name;
} v;
v.cmp = m_component;
v.prop_name = m_property;
reflection::getComponent(m_component.type)->visit(v);
m_index = v.index;
return true; return true;
} }
@ -1043,7 +1077,7 @@ public:
void undo() override void undo() override
{ {
struct : reflection::IEmptyPropertyVisitor { struct : reflection::IEmptyPropertyVisitor {
void visit(const reflection::IArrayProperty& prop) override { void visit(const reflection::ArrayProperty& prop) override {
if (!equalStrings(prop.name, prop_name)) return; if (!equalStrings(prop.name, prop_name)) return;
prop.removeItem(cmp, index); prop.removeItem(cmp, index);
} }
@ -1133,15 +1167,15 @@ public:
} }
template <typename T2> static void set(Ref<reflection::IDynamicProperties::Value> v, T2) { ASSERT(false); } template <typename T2> static void set(Ref<reflection::DynamicProperties::Value> v, T2) { ASSERT(false); }
static void set(Ref<reflection::IDynamicProperties::Value> v, i32 val) { reflection::set(v.value, val); } static void set(Ref<reflection::DynamicProperties::Value> v, i32 val) { reflection::set(v.value, val); }
static void set(Ref<reflection::IDynamicProperties::Value> v, float val) { reflection::set(v.value, val); } static void set(Ref<reflection::DynamicProperties::Value> v, float val) { reflection::set(v.value, val); }
static void set(Ref<reflection::IDynamicProperties::Value> v, const Path& val) { reflection::set(v.value, val.c_str()); } static void set(Ref<reflection::DynamicProperties::Value> v, const Path& val) { reflection::set(v.value, val.c_str()); }
static void set(Ref<reflection::IDynamicProperties::Value> v, const char* val) { reflection::set(v.value, val); } static void set(Ref<reflection::DynamicProperties::Value> v, const char* val) { reflection::set(v.value, val); }
static void set(Ref<reflection::IDynamicProperties::Value> v, EntityPtr val) { reflection::set(v.value, val); } static void set(Ref<reflection::DynamicProperties::Value> v, EntityPtr val) { reflection::set(v.value, val); }
static void set(Ref<reflection::IDynamicProperties::Value> v, bool val) { reflection::set(v.value, val); } static void set(Ref<reflection::DynamicProperties::Value> v, bool val) { reflection::set(v.value, val); }
static void set(Ref<reflection::IDynamicProperties::Value> v, Vec3 val) { reflection::set(v.value, val); } static void set(Ref<reflection::DynamicProperties::Value> v, Vec3 val) { reflection::set(v.value, val); }
static void set(Ref<reflection::IDynamicProperties::Value> v, const String& val) { reflection::set(v.value, val.c_str()); } static void set(Ref<reflection::DynamicProperties::Value> v, const String& val) { reflection::set(v.value, val.c_str()); }
bool execute() override bool execute() override
@ -1157,16 +1191,17 @@ public:
} }
} }
void visit(const reflection::IArrayProperty& prop) override { void visit(const reflection::ArrayProperty& prop) override {
if (!equalStrings(array, prop.name)) return; if (!equalStrings(array, prop.name)) return;
const char* tmp = array; const char* tmp = array;
array = ""; array = "";
prop.visit(*this); prop.visitChildren(*this);
array = tmp; array = tmp;
} }
// TODO refl
void visit(const reflection::IDynamicProperties& prop) override { /*
void visit(const reflection::DynamicProperties& prop) override {
for (EntityPtr entity : cmd->m_entities) { for (EntityPtr entity : cmd->m_entities) {
const ComponentUID cmp = cmd->m_editor.getUniverse()->getComponent((EntityRef)entity, cmd->m_component_type); const ComponentUID cmp = cmd->m_editor.getUniverse()->getComponent((EntityRef)entity, cmd->m_component_type);
const u32 c = prop.getCount(cmp, cmd->m_index); const u32 c = prop.getCount(cmp, cmd->m_index);
@ -1174,12 +1209,12 @@ public:
const char* name = prop.getName(cmp, cmd->m_index, i); const char* name = prop.getName(cmp, cmd->m_index, i);
if (!equalStrings(prop_name, name)) continue; if (!equalStrings(prop_name, name)) continue;
found = true; found = true;
reflection::IDynamicProperties::Value v; reflection::DynamicProperties::Value v;
set(Ref(v), cmd->m_new_value); set(Ref(v), cmd->m_new_value);
prop.set(cmp, cmd->m_index, i, v); prop.set(cmp, cmd->m_index, i, v);
} }
} }
} }*/
SetPropertyCommand<T>* cmd; SetPropertyCommand<T>* cmd;
const char* prop_name; const char* prop_name;
const char* array; const char* array;

View file

@ -13,7 +13,6 @@
#include "engine/path.h" #include "engine/path.h"
#include "engine/prefab.h" #include "engine/prefab.h"
#include "engine/profiler.h" #include "engine/profiler.h"
#include "engine/reflection.h"
#include "engine/resource_manager.h" #include "engine/resource_manager.h"
#include "engine/stream.h" #include "engine/stream.h"
#include "engine/universe.h" #include "engine/universe.h"

View file

@ -222,6 +222,8 @@ inline EntityPtr::operator EntityRef() const
return {index}; return {index};
} }
namespace reflection { LUMIX_ENGINE_API ComponentType getComponentType(const char* id); }
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(disable : 4251) #pragma warning(disable : 4251)
// this is disabled because VS19 16.5.0 has false positives :( // this is disabled because VS19 16.5.0 has false positives :(

View file

@ -31,131 +31,6 @@ struct BuildIndices<offset, 0, T...>
using result = Indices<T...>; using result = Indices<T...>;
}; };
template <typename... Types> struct Tuple;
template <> struct Tuple<> {};
template <typename Head, typename... Tail>
struct Tuple<Head, Tail...> : Tuple<Tail...>
{
Head value;
Tuple() {}
Tuple(Head head, Tail... tail) : Tuple<Tail...>(tail...), value(head) {}
Tuple(const Tuple<Head, Tail...>& rhs) : Tuple<Tail...>(rhs) { value = rhs.value; }
};
template <typename... Types>
auto makeTuple(Types... types)
{
return Tuple<Types...>(types...);
}
template <typename T> struct TupleSize;
template <typename... Types>
struct TupleSize<const Tuple<Types...> >
{
enum { result = sizeof...(Types) };
};
template <typename... Types>
struct TupleSize<Tuple<Types...> >
{
enum { result = sizeof...(Types) };
};
template <int Index, typename Tuple> struct TupleElement;
template <typename HeadType, typename... TailTypes>
struct TupleElement<0, const Tuple<HeadType, TailTypes...> >
{
using Head = HeadType;
using Tail = const Tuple<HeadType, TailTypes...>;
};
template <int Index, typename Head, typename... Tail>
struct TupleElement<Index, const Tuple<Head, Tail...> >
: TupleElement<Index - 1, const Tuple<Tail...> >
{
};
template <typename HeadType, typename... TailTypes>
struct TupleElement<0, Tuple<HeadType, TailTypes...> >
{
using Head = HeadType;
using Tail = Tuple<HeadType, TailTypes...>;
};
template <int Index, typename Head, typename... Tail>
struct TupleElement<Index, Tuple<Head, Tail...> >
: TupleElement<Index - 1, Tuple<Tail...> >
{
};
template <int Index, typename... Types>
constexpr auto& get(const Tuple<Types...>& tuple)
{
using Subtuple = typename TupleElement<Index, const ::Lumix::Tuple<Types...> >::Tail;
return (((Subtuple&)tuple).value);
}
template <int Index, typename... Types>
constexpr auto& get(Tuple<Types...>& tuple)
{
using Subtuple = typename TupleElement<Index, ::Lumix::Tuple<Types...> >::Tail;
return (((Subtuple&)tuple).value);
}
template <typename F, typename Tuple, int... I>
constexpr void apply_impl(F& f, Tuple& t, Indices<I...>)
{
using expand = bool[];
(void)expand
{
(
f(get<I>(t)),
true
)...
};
}
template <typename F, typename Tuple>
constexpr void apply_impl(F& f, Tuple& t, Indices<>) {}
template <typename F, typename Tuple>
constexpr void apply(F& f, Tuple& t)
{
apply_impl(f, t, typename BuildIndices<-1, TupleSize<Tuple>::result>::result{});
}
template <typename F, typename Tuple, int... I>
constexpr void apply_impl(const F& f, Tuple& t, Indices<I...>)
{
using expand = bool[];
(void)expand
{
(
f(get<I>(t)),
true
)...
};
}
template <typename F, typename Tuple>
constexpr void apply_impl(const F& f, Tuple& t, Indices<>) {}
template <typename F, typename Tuple>
constexpr void apply(const F& f, Tuple& t)
{
apply_impl(f, t, typename BuildIndices<-1, TupleSize<Tuple>::result>::result{});
}
template <typename T> struct ResultOf; template <typename T> struct ResultOf;
template <typename R, typename C, typename... Args> struct ResultOf<R(C::*)(Args...)> { using Type = R; }; template <typename R, typename C, typename... Args> struct ResultOf<R(C::*)(Args...)> { using Type = R; };
@ -169,4 +44,10 @@ template <typename R, typename C, typename... Args> struct ClassOf<R(C::*)(Args.
template <typename R, typename C> struct ClassOf<R(C::*)> { using Type = C; }; template <typename R, typename C> struct ClassOf<R(C::*)> { using Type = C; };
template <typename T> struct ArgsCount;
template <typename R, typename C, typename... Args> struct ArgsCount<R(C::*)(Args...)> { static constexpr u32 value = sizeof...(Args); };
template <typename R, typename C, typename... Args> struct ArgsCount<R(C::*)(Args...)const > { static constexpr u32 value = sizeof...(Args); };
template <typename R, typename C> struct ArgsCount<R(C::*)> { static constexpr u32 value = 0; };
} // namespace Lumix } // namespace Lumix

View file

@ -11,46 +11,10 @@ namespace Lumix
namespace reflection namespace reflection
{ {
template <> Path readFromStream<Path>(InputMemoryStream& stream)
{
const char* c_str = (const char*)stream.getData() + stream.getPosition();
Path path(c_str);
stream.skip(stringLength(c_str) + 1);
return path;
}
template <> void writeToStream<const Path&>(OutputMemoryStream& stream, const Path& path)
{
const char* str = path.c_str();
stream.write(str, stringLength(str) + 1);
}
template <> void writeToStream<Path>(OutputMemoryStream& stream, Path path)
{
const char* str = path.c_str();
stream.write(str, stringLength(str) + 1);
}
template <> const char* readFromStream<const char*>(InputMemoryStream& stream)
{
const char* c_str = (const char*)stream.getData() + stream.getPosition();
stream.skip(stringLength(c_str) + 1);
return c_str;
}
template <> void writeToStream<const char*>(OutputMemoryStream& stream, const char* value)
{
stream.write(value, stringLength(value) + 1);
}
struct Context { struct Context {
SceneBase* first_scene = nullptr; Scene* first_scene = nullptr;
RegisteredComponent components[ComponentType::MAX_TYPES_COUNT]; RegisteredComponent ComponentBases[ComponentType::MAX_TYPES_COUNT];
u32 components_count = 0; u32 components_count = 0;
}; };
@ -59,35 +23,61 @@ static Context& getContext() {
return ctx; return ctx;
} }
static IAllocator& getAllocator() {
static DefaultAllocator alloc;
return alloc;
}
Array<FunctionBase*>& allFunctions() { Array<FunctionBase*>& allFunctions() {
static DefaultAllocator allocator; static Array<FunctionBase*> fncs(getAllocator());
static Array<FunctionBase*> fncs(allocator);
return fncs; return fncs;
} }
const ComponentBase* getComponent(ComponentType cmp_type) { ComponentBase::ComponentBase(IAllocator& allocator)
return getContext().components[cmp_type.index].cmp; : props(allocator)
} , functions(allocator)
{}
SceneBase* getFirstScene() { return getContext().first_scene; } void ComponentBase::visit(IPropertyVisitor& visitor) const {
for (const PropertyBase* prop : props) {
void registerScene(SceneBase& scene) { prop->visit(visitor);
Context& ctx = getContext();
scene.next = ctx.first_scene;
ctx.first_scene = &scene;
const u32 scene_name_hash = crc32(scene.name);
for (ComponentBase* cmp : scene.getComponents()) {
ctx.components[cmp->component_type.index].cmp = cmp;
ctx.components[cmp->component_type.index].scene = scene_name_hash;
} }
} }
const ComponentBase* getComponent(ComponentType cmp_type) {
return getContext().ComponentBases[cmp_type.index].cmp;
}
const PropertyBase* getProperty(ComponentType cmp_type, const char* prop_name) {
const ComponentBase* cmp = getComponent(cmp_type);
for (PropertyBase* prop : cmp->props) {
if (equalStrings(prop->name, prop_name)) return prop;
}
return nullptr;
}
Scene::Scene(IAllocator& allocator)
: cmps(allocator)
, functions(allocator)
{}
builder::builder(IAllocator& allocator)
: allocator(allocator)
{
scene = LUMIX_NEW(allocator, Scene)(allocator);
}
void builder::registerCmp(ComponentBase* cmp) {
getContext().ComponentBases[cmp->component_type.index].cmp = cmp;
getContext().ComponentBases[cmp->component_type.index].name_hash = crc32(cmp->name);
getContext().ComponentBases[cmp->component_type.index].scene = crc32(scene->name);
scene->cmps.push(cmp);
}
ComponentType getComponentTypeFromHash(u32 hash) ComponentType getComponentTypeFromHash(u32 hash)
{ {
for (u32 i = 0, c = getContext().components_count; i < c; ++i) { for (u32 i = 0, c = getContext().components_count; i < c; ++i) {
if (getContext().components[i].name_hash == hash) { if (getContext().ComponentBases[i].name_hash == hash) {
return {(i32)i}; return {(i32)i};
} }
} }
@ -98,35 +88,170 @@ ComponentType getComponentTypeFromHash(u32 hash)
u32 getComponentTypeHash(ComponentType type) u32 getComponentTypeHash(ComponentType type)
{ {
return getContext().components[type.index].name_hash; return getContext().ComponentBases[type.index].name_hash;
} }
ComponentType getComponentType(const char* name) ComponentType getComponentType(const char* name)
{ {
Context& ctx = getContext();
u32 name_hash = crc32(name); u32 name_hash = crc32(name);
for (u32 i = 0, c = getContext().components_count; i < c; ++i) { for (u32 i = 0, c = ctx.components_count; i < c; ++i) {
if (getContext().components[i].name_hash == name_hash) { if (ctx.ComponentBases[i].name_hash == name_hash) {
return {(i32)i}; return {(i32)i};
} }
} }
if (getContext().components_count == ComponentType::MAX_TYPES_COUNT) { if (ctx.components_count == ComponentType::MAX_TYPES_COUNT) {
logError("Too many component types"); logError("Too many component types");
return INVALID_COMPONENT_TYPE; return INVALID_COMPONENT_TYPE;
} }
RegisteredComponent& type = getContext().components[getContext().components_count]; RegisteredComponent& type = ctx.ComponentBases[getContext().components_count];
type.name_hash = name_hash; type.name_hash = name_hash;
++getContext().components_count; ++ctx.components_count;
return {i32(getContext().components_count - 1)}; return {i32(getContext().components_count - 1)};
} }
Span<const RegisteredComponent> getComponents() { Scene* getFirstScene() {
return Span(getContext().components, getContext().components_count); return getContext().first_scene;
} }
Span<const RegisteredComponent> getComponents() {
return Span(getContext().ComponentBases, getContext().components_count);
}
struct RadiansAttribute : IAttribute
{
int getType() const override { return RADIANS; }
};
struct MultilineAttribute : IAttribute
{
int getType() const override { return MULTILINE; }
};
struct NoUIAttribute : IAttribute {
int getType() const override { return NO_UI; }
};
builder build_scene(const char* name) {
builder res(getAllocator());
Context& ctx = getContext();
res.scene->next = ctx.first_scene;
ctx.first_scene = res.scene;
res.scene->name = name;
return res;
}
builder& builder::radiansAttribute() {
auto* a = LUMIX_NEW(allocator, RadiansAttribute);
last_prop->attributes.push(a);
return *this;
}
builder& builder::colorAttribute() {
auto* a = LUMIX_NEW(allocator, ColorAttribute);
last_prop->attributes.push(a);
return *this;
}
builder& builder::noUIAttribute() {
auto* a = LUMIX_NEW(allocator, NoUIAttribute);
last_prop->attributes.push(a);
return *this;
}
builder& builder::multilineAttribute() {
auto* a = LUMIX_NEW(allocator, MultilineAttribute);
last_prop->attributes.push(a);
return *this;
}
builder& builder::minAttribute(float value) {
auto* a = LUMIX_NEW(allocator, MinAttribute)(value);
last_prop->attributes.push(a);
return *this;
}
builder& builder::clampAttribute(float min, float max) {
auto* a = LUMIX_NEW(allocator, ClampAttribute)(min, max);
last_prop->attributes.push(a);
return *this;
}
builder& builder::resourceAttribute(ResourceType type) {
auto* a = LUMIX_NEW(allocator, ResourceAttribute)(type);
last_prop->attributes.push(a);
return *this;
}
builder& builder::end_array() {
array = nullptr;
last_prop = nullptr;
return *this;
}
builder& builder::icon(const char* icon) {
scene->cmps.back()->icon = icon;
return *this;
}
void builder::addProp(PropertyBase* p) {
if (array) {
array->children.push(p);
}
else {
scene->cmps.back()->props.push(p);
}
last_prop = p;
}
BlobProperty::BlobProperty(IAllocator& allocator)
: PropertyBase(allocator)
{}
void BlobProperty::visit(struct IPropertyVisitor& visitor) const {
visitor.visit(*this);
}
void BlobProperty::getValue(ComponentUID cmp, u32 idx, OutputMemoryStream& stream) const {
getter(cmp.scene, (EntityRef)cmp.entity, idx, stream);
}
void BlobProperty::setValue(ComponentUID cmp, u32 idx, InputMemoryStream& stream) const {
setter(cmp.scene, (EntityRef)cmp.entity, idx, stream);
}
ArrayProperty::ArrayProperty(IAllocator& allocator)
: PropertyBase(allocator)
, children(allocator)
{}
u32 ArrayProperty::getCount(ComponentUID cmp) const {
return counter(cmp.scene, (EntityRef)cmp.entity);
}
void ArrayProperty::addItem(ComponentUID cmp, u32 idx) const {
adder(cmp.scene, (EntityRef)cmp.entity, idx);
}
void ArrayProperty::removeItem(ComponentUID cmp, u32 idx) const {
remover(cmp.scene, (EntityRef)cmp.entity, idx);
}
void ArrayProperty::visit(struct IPropertyVisitor& visitor) const {
visitor.visit(*this);
}
void ArrayProperty::visitChildren(struct IPropertyVisitor& visitor) const {
for (PropertyBase* prop : children) {
prop->visit(visitor);
}
}
} // namespace Reflection } // namespace Reflection

View file

@ -4,21 +4,16 @@
#include "engine/lumix.h" #include "engine/lumix.h"
#include "engine/metaprogramming.h" #include "engine/metaprogramming.h"
#include "engine/resource.h" #include "engine/resource.h"
#include "engine/stream.h"
#include "engine/universe.h" #include "engine/universe.h"
#define LUMIX_CMP(Component, ...) component<&ReflScene::create##Component, &ReflScene::destroy##Component>(__VA_ARGS__) #define LUMIX_SCENE(Class, Label) using ReflScene = Class; reflection::build_scene(Label)
#define LUMIX_PROP(Property, Label, ...) property(Label, &ReflScene::get##Property, &ReflScene::set##Property, ##__VA_ARGS__) #define LUMIX_FUNC_EX(F, Name) function<&ReflScene::F>(Name, #F)
#define LUMIX_FUNC_EX(Func, Name) reflection::function(&Func, #Func, Name) #define LUMIX_FUNC(F) function<&F>(#F, #F)
#define LUMIX_FUNC(Func) reflection::function(&Func, #Func, nullptr) #define LUMIX_CMP(Cmp, Name, Label) cmp<&ReflScene::create##Cmp, &ReflScene::destroy##Cmp>(Name, Label)
#define LUMIX_SCENE(Type, Name, ...) \ #define LUMIX_PROP(Property, Label) prop<&ReflScene::get##Property, &ReflScene::set##Property>(Label)
do { \ #define LUMIX_ENUM_PROP(Property, Label) enum_prop<&ReflScene::get##Property, &ReflScene::set##Property>(Label)
using namespace reflection; \ #define LUMIX_GLOBAL_FUNC(Func) reflection::function(&Func, #Func, nullptr)
static auto registered_scene = [](){ using ReflScene = Type; return reflection::scene(Name, ##__VA_ARGS__); }(); \
reflection::registerScene(registered_scene); \
} while(false)
namespace Lumix namespace Lumix
{ {
@ -52,9 +47,6 @@ struct IAttribute {
virtual int getType() const = 0; virtual int getType() const = 0;
}; };
struct ComponentBase;
struct SceneBase;
// we don't use method pointers here because VS has sizeof issues if IScene is forward declared // we don't use method pointers here because VS has sizeof issues if IScene is forward declared
using CreateComponent = void (*)(IScene*, EntityRef); using CreateComponent = void (*)(IScene*, EntityRef);
using DestroyComponent = void (*)(IScene*, EntityRef); using DestroyComponent = void (*)(IScene*, EntityRef);
@ -62,26 +54,16 @@ using DestroyComponent = void (*)(IScene*, EntityRef);
struct RegisteredComponent { struct RegisteredComponent {
u32 name_hash = 0; u32 name_hash = 0;
u32 scene = 0; u32 scene = 0;
ComponentBase* cmp = nullptr; struct ComponentBase* cmp = nullptr;
}; };
LUMIX_ENGINE_API void registerScene(SceneBase& scene);
LUMIX_ENGINE_API SceneBase* getFirstScene();
LUMIX_ENGINE_API const ComponentBase* getComponent(ComponentType cmp_type); LUMIX_ENGINE_API const ComponentBase* getComponent(ComponentType cmp_type);
LUMIX_ENGINE_API const struct PropertyBase* getProperty(ComponentType cmp_type, const char* prop);
LUMIX_ENGINE_API Span<const RegisteredComponent> getComponents(); LUMIX_ENGINE_API Span<const RegisteredComponent> getComponents();
LUMIX_ENGINE_API ComponentType getComponentType(const char* id); LUMIX_ENGINE_API ComponentType getComponentType(const char* id);
LUMIX_ENGINE_API ComponentType getComponentTypeFromHash(u32 hash); LUMIX_ENGINE_API ComponentType getComponentTypeFromHash(u32 hash);
template <typename T> void writeToStream(OutputMemoryStream& stream, T value) { stream.write(value); }
template <typename T> T readFromStream(InputMemoryStream& stream) { return stream.read<T>(); }
template <> LUMIX_ENGINE_API Path readFromStream<Path>(InputMemoryStream& stream);
template <> LUMIX_ENGINE_API void writeToStream<Path>(OutputMemoryStream& stream, Path);
template <> LUMIX_ENGINE_API void writeToStream<const Path&>(OutputMemoryStream& stream, const Path& path);
template <> LUMIX_ENGINE_API const char* readFromStream<const char*>(InputMemoryStream& stream);
template <> LUMIX_ENGINE_API void writeToStream<const char*>(OutputMemoryStream& stream, const char* path);
struct ResourceAttribute : IAttribute struct ResourceAttribute : IAttribute
{ {
ResourceAttribute(ResourceType type) : resource_type(type) {} ResourceAttribute(ResourceType type) : resource_type(type) {}
@ -113,6 +95,10 @@ struct ClampAttribute : IAttribute
float max; float max;
}; };
struct ColorAttribute : IAttribute {
int getType() const override { return COLOR; }
};
struct EnumAttribute : IAttribute { struct EnumAttribute : IAttribute {
virtual u32 count(ComponentUID cmp) const = 0; virtual u32 count(ComponentUID cmp) const = 0;
virtual const char* name(ComponentUID cmp, u32 idx) const = 0; virtual const char* name(ComponentUID cmp, u32 idx) const = 0;
@ -127,41 +113,17 @@ struct StringEnumAttribute : IAttribute {
int getType() const override { return STRING_ENUM; } int getType() const override { return STRING_ENUM; }
}; };
struct RadiansAttribute : IAttribute
{
int getType() const override { return RADIANS; }
};
struct MultilineAttribute : IAttribute struct PropertyBase {
{ PropertyBase(IAllocator& allocator) : attributes(allocator) {}
int getType() const override { return MULTILINE; } Array<IAttribute*> attributes;
};
struct ColorAttribute : IAttribute virtual void visit(struct IPropertyVisitor& visitor) const = 0;
{
int getType() const override { return COLOR; }
};
struct NoUIAttribute : IAttribute {
int getType() const override { return NO_UI; }
};
struct PropertyTag {};
template <typename T> struct Property : PropertyTag {
virtual Span<const IAttribute* const> getAttributes() const = 0;
virtual T get(ComponentUID cmp, int index) const = 0;
virtual void set(ComponentUID cmp, int index, T) const = 0;
const char* name; const char* name;
}; };
struct IBlobProperty : PropertyTag {
virtual void getValue(ComponentUID cmp, int index, OutputMemoryStream& stream) const = 0;
virtual void setValue(ComponentUID cmp, int index, InputMemoryStream& stream) const = 0;
const char* name;
};
struct IDynamicProperties : PropertyTag { struct DynamicProperties : PropertyBase {
enum Type { enum Type {
I32, I32,
FLOAT, FLOAT,
@ -182,47 +144,60 @@ struct IDynamicProperties : PropertyTag {
bool b; bool b;
Vec3 v3; Vec3 v3;
}; };
DynamicProperties(IAllocator& allocator) : PropertyBase(allocator) {}
virtual u32 getCount(ComponentUID cmp, int array_idx) const = 0; virtual u32 getCount(ComponentUID cmp, int array_idx) const = 0;
virtual Type getType(ComponentUID cmp, int array_idx, u32 idx) const = 0; virtual Type getType(ComponentUID cmp, int array_idx, u32 idx) const = 0;
virtual const char* getName(ComponentUID cmp, int array_idx, u32 idx) const = 0; virtual const char* getName(ComponentUID cmp, int array_idx, u32 idx) const = 0;
virtual Value getValue(ComponentUID cmp, int array_idx, u32 idx) const = 0; virtual Value getValue(ComponentUID cmp, int array_idx, u32 idx) const = 0;
virtual reflection::ResourceAttribute getResourceAttribute(ComponentUID cmp, int array_idx, u32 idx) const = 0; virtual ResourceAttribute getResourceAttribute(ComponentUID cmp, int array_idx, u32 idx) const = 0;
virtual void set(ComponentUID cmp, int array_idx, const char* name, Type type, Value value) const = 0; virtual void set(ComponentUID cmp, int array_idx, const char* name, Type type, Value value) const = 0;
virtual void set(ComponentUID cmp, int array_idx, u32 idx, Value value) const = 0; virtual void set(ComponentUID cmp, int array_idx, u32 idx, Value value) const = 0;
const char* name;
};
template <typename T> inline T get(IDynamicProperties::Value);
template <> inline float get(IDynamicProperties::Value v) { return v.f; }
template <> inline i32 get(IDynamicProperties::Value v) { return v.i; }
template <> inline const char* get(IDynamicProperties::Value v) { return v.s; }
template <> inline EntityPtr get(IDynamicProperties::Value v) { return v.e; }
template <> inline bool get(IDynamicProperties::Value v) { return v.b; }
template <> inline Vec3 get(IDynamicProperties::Value v) { return v.v3; }
template <typename T> inline void set(IDynamicProperties::Value& v, T);
template <> inline void set(IDynamicProperties::Value& v, float val) { v.f = val; }
template <> inline void set(IDynamicProperties::Value& v, i32 val) { v.i = val; }
template <> inline void set(IDynamicProperties::Value& v, const char* val) { v.s = val; }
template <> inline void set(IDynamicProperties::Value& v, EntityPtr val) { v.e = val; }
template <> inline void set(IDynamicProperties::Value& v, bool val) { v.b = val; }
template <> inline void set(IDynamicProperties::Value& v, Vec3 val) { v.v3 = val; }
struct IArrayProperty : PropertyTag
{
virtual void addItem(ComponentUID cmp, int index) const = 0;
virtual void removeItem(ComponentUID cmp, int index) const = 0;
virtual int getCount(ComponentUID cmp) const = 0;
virtual void visit(struct IPropertyVisitor& visitor) const = 0; virtual void visit(struct IPropertyVisitor& visitor) const = 0;
const char* name;
}; };
struct IPropertyVisitor template <typename T> inline T get(DynamicProperties::Value);
{ template <> inline float get(DynamicProperties::Value v) { return v.f; }
virtual ~IPropertyVisitor() {} template <> inline i32 get(DynamicProperties::Value v) { return v.i; }
template <> inline const char* get(DynamicProperties::Value v) { return v.s; }
template <> inline EntityPtr get(DynamicProperties::Value v) { return v.e; }
template <> inline bool get(DynamicProperties::Value v) { return v.b; }
template <> inline Vec3 get(DynamicProperties::Value v) { return v.v3; }
template <typename T> inline void set(DynamicProperties::Value& v, T);
template <> inline void set(DynamicProperties::Value& v, float val) { v.f = val; }
template <> inline void set(DynamicProperties::Value& v, i32 val) { v.i = val; }
template <> inline void set(DynamicProperties::Value& v, const char* val) { v.s = val; }
template <> inline void set(DynamicProperties::Value& v, EntityPtr val) { v.e = val; }
template <> inline void set(DynamicProperties::Value& v, bool val) { v.b = val; }
template <> inline void set(DynamicProperties::Value& v, Vec3 val) { v.v3 = val; }
template <typename T>
struct Property : PropertyBase {
Property(IAllocator& allocator) : PropertyBase(allocator) {}
typedef void (*Setter)(IScene*, EntityRef, u32, const T&);
typedef T (*Getter)(IScene*, EntityRef, u32);
void visit(IPropertyVisitor& visitor) const override {
visitor.visit(*this);
}
virtual T get(ComponentUID cmp, u32 idx) const {
return getter(cmp.scene, (EntityRef)cmp.entity, idx);
}
virtual void set(ComponentUID cmp, u32 idx, T val) const {
setter(cmp.scene, (EntityRef)cmp.entity, idx, val);
}
Setter setter;
Getter getter;
};
struct IPropertyVisitor {
virtual ~IPropertyVisitor() {}
virtual void visit(const Property<float>& prop) = 0; virtual void visit(const Property<float>& prop) = 0;
virtual void visit(const Property<int>& prop) = 0; virtual void visit(const Property<int>& prop) = 0;
virtual void visit(const Property<u32>& prop) = 0; virtual void visit(const Property<u32>& prop) = 0;
@ -234,13 +209,13 @@ struct IPropertyVisitor
virtual void visit(const Property<Path>& prop) = 0; virtual void visit(const Property<Path>& prop) = 0;
virtual void visit(const Property<bool>& prop) = 0; virtual void visit(const Property<bool>& prop) = 0;
virtual void visit(const Property<const char*>& prop) = 0; virtual void visit(const Property<const char*>& prop) = 0;
virtual void visit(const IDynamicProperties& prop) {} virtual void visit(const struct ArrayProperty& prop) = 0;
virtual void visit(const IArrayProperty& prop) = 0; virtual void visit(const struct BlobProperty& prop) = 0;
virtual void visit(const IBlobProperty& prop) = 0; virtual void visit(const DynamicProperties& prop) {}
}; };
struct IEmptyPropertyVisitor : IPropertyVisitor struct IEmptyPropertyVisitor : IPropertyVisitor {
{ virtual ~IEmptyPropertyVisitor() {}
void visit(const Property<float>& prop) override {} void visit(const Property<float>& prop) override {}
void visit(const Property<int>& prop) override {} void visit(const Property<int>& prop) override {}
void visit(const Property<u32>& prop) override {} void visit(const Property<u32>& prop) override {}
@ -252,25 +227,43 @@ struct IEmptyPropertyVisitor : IPropertyVisitor
void visit(const Property<Path>& prop) override {} void visit(const Property<Path>& prop) override {}
void visit(const Property<bool>& prop) override {} void visit(const Property<bool>& prop) override {}
void visit(const Property<const char*>& prop) override {} void visit(const Property<const char*>& prop) override {}
void visit(const IArrayProperty& prop) override {} void visit(const ArrayProperty& prop) override {}
void visit(const IBlobProperty& prop) override {} void visit(const BlobProperty& prop) override {}
void visit(const IDynamicProperties& prop) override {} void visit(const DynamicProperties& prop) override {}
}; };
struct ComponentBase struct LUMIX_ENGINE_API ArrayProperty : PropertyBase {
{ typedef u32 (*Counter)(IScene*, EntityRef);
virtual ~ComponentBase() {} typedef void (*Adder)(IScene*, EntityRef, u32);
typedef void (*Remover)(IScene*, EntityRef, u32);
virtual int getPropertyCount() const = 0; ArrayProperty(IAllocator& allocator);
virtual void visit(IPropertyVisitor&) const = 0;
virtual Span<const struct FunctionBase* const> getFunctions() const = 0;
const char* name; u32 getCount(ComponentUID cmp) const;
const char* label; void addItem(ComponentUID cmp, u32 idx) const;
const char* icon = ""; void removeItem(ComponentUID cmp, u32 idx) const;
CreateComponent creator;
DestroyComponent destroyer; void visit(struct IPropertyVisitor& visitor) const override;
ComponentType component_type; void visitChildren(struct IPropertyVisitor& visitor) const;
Array<PropertyBase*> children;
Counter counter;
Adder adder;
Remover remover;
};
struct LUMIX_ENGINE_API BlobProperty : PropertyBase {
BlobProperty(IAllocator& allocator);
void visit(struct IPropertyVisitor& visitor) const override;
void getValue(ComponentUID cmp, u32 idx, OutputMemoryStream& stream) const;
void setValue(ComponentUID cmp, u32 idx, InputMemoryStream& stream) const;
typedef void (*Getter)(IScene*, EntityRef, u32, OutputMemoryStream&);
typedef void (*Setter)(IScene*, EntityRef, u32, InputMemoryStream&);
Getter getter;
Setter setter;
}; };
struct Icon { const char* name; }; struct Icon { const char* name; };
@ -294,98 +287,15 @@ bool getPropertyValue(IScene& scene, EntityRef e, ComponentType cmp_type, const
visitor.cmp.scene = &scene; visitor.cmp.scene = &scene;
visitor.cmp.type = cmp_type; visitor.cmp.type = cmp_type;
visitor.cmp.entity = e; visitor.cmp.entity = e;
const reflection::ComponentBase* cmp_desc = getComponent(cmp_type); const ComponentBase* cmp_desc = getComponent(cmp_type);
cmp_desc->visit(visitor); cmp_desc->visit(visitor);
out = visitor.value; out = visitor.value;
return visitor.found; return visitor.found;
} }
template <typename Base, typename... T>
struct TupleHolder {
TupleHolder() {}
TupleHolder(Tuple<T...> tuple) { init(tuple); }
TupleHolder(TupleHolder&& rhs) { init(rhs.objects); }
TupleHolder(const TupleHolder& rhs) { init(rhs.objects); }
void init(const Tuple<T...>& tuple)
{
objects = tuple;
int i = 0;
apply([&](auto& v){
ptrs[i] = &v;
++i;
}, objects);
}
void operator =(Tuple<T...>&& tuple) { init(tuple); }
void operator =(const TupleHolder& rhs) { init(rhs.objects); }
void operator =(TupleHolder&& rhs) { init(rhs.objects); }
Span<const Base* const> get() const {
return Span(static_cast<const Base*const*>(ptrs), (u32)sizeof...(T));
}
Span<Base* const> get() {
return Span(static_cast<Base*const*>(ptrs), (u32)sizeof...(T));
}
Tuple<T...> objects;
Base* ptrs[sizeof...(T) + 1];
};
template <typename Getter, typename Setter>
struct BlobProperty : IBlobProperty
{
void getValue(ComponentUID cmp, int index, OutputMemoryStream& stream) const override
{
using C = typename ClassOf<Getter>::Type;
C* inst = static_cast<C*>(cmp.scene);
(inst->*getter)((EntityRef)cmp.entity, stream);
}
void setValue(ComponentUID cmp, int index, InputMemoryStream& stream) const override
{
using C = typename ClassOf<Getter>::Type;
C* inst = static_cast<C*>(cmp.scene);
(inst->*setter)((EntityRef)cmp.entity, stream);
}
Getter getter;
Setter setter;
};
template <typename T, typename CmpGetter, typename PtrType, typename... Attributes>
struct VarProperty : Property<T>
{
Span<const IAttribute* const> getAttributes() const override { return attributes.get(); }
T get(ComponentUID cmp, int index) const override
{
using C = typename ClassOf<CmpGetter>::Type;
C* inst = static_cast<C*>(cmp.scene);
auto& c = (inst->*cmp_getter)((EntityRef)cmp.entity);
auto& v = c.*ptr;
return static_cast<T>(v);
}
void set(ComponentUID cmp, int index, T value) const override
{
using C = typename ClassOf<CmpGetter>::Type;
C* inst = static_cast<C*>(cmp.scene);
auto& c = (inst->*cmp_getter)((EntityRef)cmp.entity);
c.*ptr = value;
}
CmpGetter cmp_getter;
PtrType ptr;
TupleHolder<IAttribute, Attributes...> attributes;
};
namespace detail { namespace detail {
static const unsigned int FRONT_SIZE = sizeof("Lumix::reflection::detail::GetTypeNameHelper<") - 1u; static const unsigned int FRONT_SIZE = sizeof("Lumix::detail::GetTypeNameHelper<") - 1u;
static const unsigned int BACK_SIZE = sizeof(">::GetTypeName") - 1u; static const unsigned int BACK_SIZE = sizeof(">::GetTypeName") - 1u;
template <typename T> template <typename T>
@ -406,124 +316,12 @@ struct GetTypeNameHelper
} }
}; };
template <typename Getter> struct GetterProxy;
template <typename R, typename C>
struct GetterProxy<R(C::*)(EntityRef, int)>
{
using Getter = R(C::*)(EntityRef, int);
static R invoke(C* inst, Getter getter, EntityRef entity, int index)
{
return (inst->*getter)(entity, index);
}
};
template <typename R, typename C>
struct GetterProxy<R(C::*)(EntityRef)>
{
using Getter = R(C::*)(EntityRef);
static R invoke(C* inst, Getter getter, EntityRef entity, int index)
{
return (inst->*getter)(entity);
}
};
template <typename Setter> struct SetterProxy;
template <typename C, typename A>
struct SetterProxy<void (C::*)(EntityRef, int, A)>
{
using Setter = void (C::*)(EntityRef, int, A);
template <typename T>
static void invoke(C* inst, Setter setter, EntityRef entity, int index, T value)
{
(inst->*setter)(entity, index, static_cast<A>(value));
}
};
template <typename C, typename A>
struct SetterProxy<void (C::*)(EntityRef, A)>
{
using Setter = void (C::*)(EntityRef, A);
template <typename T>
static void invoke(C* inst, Setter setter, EntityRef entity, int index, T value)
{
(inst->*setter)(entity, static_cast<A>(value));
}
};
} // namespace detail } // namespace detail
template <typename T, typename Getter, typename Setter, typename... Attributes>
struct CommonProperty : Property<T>
{
Span<const IAttribute* const> getAttributes() const override { return attributes.get(); }
T get(ComponentUID cmp, int index) const override
{
using C = typename ClassOf<Getter>::Type;
C* inst = static_cast<C*>(cmp.scene);
return static_cast<T>(detail::GetterProxy<Getter>::invoke(inst, getter, (EntityRef)cmp.entity, index));
}
void set(ComponentUID cmp, int index, T value) const override
{
using C = typename ClassOf<Getter>::Type;
C* inst = static_cast<C*>(cmp.scene);
detail::SetterProxy<Setter>::invoke(inst, setter, (EntityRef)cmp.entity, index, value);
}
TupleHolder<IAttribute, Attributes...> attributes;
Getter getter;
Setter setter;
};
template <typename Counter, typename Adder, typename Remover, typename... Props>
struct ArrayProperty : IArrayProperty
{
ArrayProperty() {}
void addItem(ComponentUID cmp, int index) const override
{
using C = typename ClassOf<Counter>::Type;
C* inst = static_cast<C*>(cmp.scene);
(inst->*adder)((EntityRef)cmp.entity, index);
}
void removeItem(ComponentUID cmp, int index) const override
{
using C = typename ClassOf<Counter>::Type;
C* inst = static_cast<C*>(cmp.scene);
(inst->*remover)((EntityRef)cmp.entity, index);
}
int getCount(ComponentUID cmp) const override
{
using C = typename ClassOf<Counter>::Type;
C* inst = static_cast<C*>(cmp.scene);
return (inst->*counter)((EntityRef)cmp.entity);
}
void visit(IPropertyVisitor& visitor) const override
{
apply([&](auto& x) { visitor.visit(x); }, properties);
}
Tuple<Props...> properties;
Counter counter;
Adder adder;
Remover remover;
};
template <typename T> template <typename T>
const IAttribute* getAttribute(const Property<T>& prop, IAttribute::Type type) { const IAttribute* getAttribute(const Property<T>& prop, IAttribute::Type type) {
for (const IAttribute* attr : prop.getAttributes()) { for (const IAttribute* attr : prop.attributes) {
if (attr->getType() == type) return attr; if (attr->getType() == type) return attr;
} }
return nullptr; return nullptr;
@ -590,117 +388,6 @@ struct FunctionBase
const char* name; const char* name;
}; };
struct SceneBase
{
virtual ~SceneBase() {}
virtual Span<const FunctionBase* const> getFunctions() const = 0;
virtual Span<ComponentBase* const> getComponents() = 0;
const char* name;
SceneBase* next = nullptr;
};
template <typename Components, typename Funcs> struct Scene;
template <typename... Components, typename... Funcs>
struct Scene<Tuple<Components...>, Tuple<Funcs...>> : SceneBase
{
Span<const FunctionBase* const> getFunctions() const override { return functions.get(); }
Span<ComponentBase* const> getComponents() override { return components.get(); }
TupleHolder<ComponentBase, Components...> components;
TupleHolder<FunctionBase, Funcs...> functions;
};
template <typename Funcs, typename Props> struct Component;
template <typename... Funcs, typename Props>
struct Component<Tuple<Funcs...>, Props> : ComponentBase
{
int getPropertyCount() const override { return TupleSize<Props>::result; }
void visit(IPropertyVisitor& visitor) const override
{
apply([&](auto& x) { visitor.visit(x); }, properties);
}
Span<const FunctionBase* const> getFunctions() const override { return functions.get(); }
Props properties;
TupleHolder<FunctionBase, Funcs...> functions;
};
template <typename... T>
struct Filter {
template <typename B>
struct HasBase {
static u8 check(const void*) { return {}; }
static u32 check(const B*) { return {}; }
template <typename T2>
static constexpr bool has() { return sizeof(check((T2*)nullptr)) == sizeof(u32); }
};
static auto properties(T... t) { return makeTuple(t...); }
static auto functions(T... t) { return makeTuple(t...); }
static auto components(T... t) { return makeTuple(t...); }
template <typename... T2, typename H>
static auto properties(T... t, H h, T2... t2) {
if constexpr (HasBase<PropertyTag>::template has<H>()) {
return Filter<T..., H>::properties(t..., h, t2...);
}
else {
return Filter<T...>::properties(t..., t2...);
}
}
template <typename... T2, typename H>
static auto functions(T... t, H h, T2... t2) {
if constexpr (HasBase<FunctionBase>::template has<H>()) {
return Filter<T..., H>::functions(t..., h, t2...);
}
else {
return Filter<T...>::functions(t..., t2...);
}
}
template <typename... T2, typename H>
static auto components(T... t, H h, T2... t2) {
if constexpr (HasBase<ComponentBase>::template has<H>()) {
return Filter<T..., H>::components(t..., h, t2...);
}
else {
return Filter<T...>::components(t..., t2...);
}
}
static const char* icon() { return ""; }
template <typename H, typename... T2> static const char* icon(H h, T2... t) {
if constexpr (HasBase<Icon>::template has<H>()) {
return h.name;
}
else {
return icon(t...);
}
}
};
template <typename... Members>
auto scene(const char* name, Members... members)
{
using ComponentsTuple = decltype(Filter<>::components(members...));
using FunctionsTuple = decltype(Filter<>::functions(members...));
Scene<ComponentsTuple, FunctionsTuple> scene;
scene.name = name;
scene.functions = Filter<>::functions(members...);
scene.components = Filter<>::components(members...);
return scene;
}
template <typename T> struct VariantTag {}; template <typename T> struct VariantTag {};
template <typename T> inline Variant::Type _getVariantType(VariantTag<T*>) { return Variant::PTR; } template <typename T> inline Variant::Type _getVariantType(VariantTag<T*>) { return Variant::PTR; }
@ -818,89 +505,207 @@ auto& function(F func, const char* decl_code, const char* name)
return ret; return ret;
} }
struct ComponentBase {
ComponentBase(IAllocator& allocator);
template <auto Creator, auto Destroyer, typename... Props> void visit(IPropertyVisitor& visitor) const;
auto component(const char* name, const char* label, Props... props)
{ const char* icon = "";
auto creator = [](IScene* scene, EntityRef e){ (scene->*static_cast<void (IScene::*)(EntityRef)>(Creator))(e); }; const char* name;
auto destroyer = [](IScene* scene, EntityRef e){ (scene->*static_cast<void (IScene::*)(EntityRef)>(Destroyer))(e); }; const char* label;
u32 scene;
CreateComponent creator;
DestroyComponent destroyer;
ComponentType component_type;
Array<PropertyBase*> props;
Array<FunctionBase*> functions;
};
struct Scene {
Scene(IAllocator& allocator);
Array<FunctionBase*> functions;
Array<ComponentBase*> cmps;
const char* name;
Scene* next = nullptr;
};
LUMIX_ENGINE_API Scene* getFirstScene();
struct builder {
builder(IAllocator& allocator);
template <auto Creator, auto Destroyer>
builder& cmp(const char* name, const char* label) {
auto creator = [](IScene* scene, EntityRef e){ (scene->*static_cast<void (IScene::*)(EntityRef)>(Creator))(e); };
auto destroyer = [](IScene* scene, EntityRef e){ (scene->*static_cast<void (IScene::*)(EntityRef)>(Destroyer))(e); };
using PropsTuple = decltype(Filter<>::properties(props...)); ComponentBase* cmp = LUMIX_NEW(allocator, ComponentBase)(allocator);
using FuncsTuple = decltype(Filter<>::functions(props...)); cmp->name = name;
cmp->label = label;
cmp->component_type = getComponentType(name);
cmp->creator = creator;
cmp->destroyer = destroyer;
cmp->scene = crc32(scene->name);
registerCmp(cmp);
Component<FuncsTuple, PropsTuple> cmp; return *this;
cmp.creator = (CreateComponent)creator; }
cmp.destroyer = (DestroyComponent)destroyer;
cmp.label = label;
cmp.name = name;
cmp.icon = Filter<>::icon(props...);
cmp.functions = Filter<>::functions(props...);
cmp.properties = Filter<>::properties(props...);
cmp.component_type = getComponentType(name);
return cmp;
}
template <typename Getter, typename Setter> template <auto Getter, auto Setter>
auto blob_property(const char* name, Getter getter, Setter setter) builder& enum_prop(const char* name) {
{ auto* p = LUMIX_NEW(allocator, Property<i32>)(allocator);
BlobProperty<Getter, Setter> p; p->setter = [](IScene* scene, EntityRef e, u32 idx, const i32& value) {
p.getter = getter; using T = typename ResultOf<decltype(Getter)>::Type;
p.setter = setter; using C = typename ClassOf<decltype(Setter)>::Type;
p.name = name; if constexpr (ArgsCount<decltype(Setter)>::value == 2) {
return p; (static_cast<C*>(scene)->*Setter)(e, static_cast<T>(value));
} }
else {
(static_cast<C*>(scene)->*Setter)(e, idx, static_cast<T>(value));
}
};
template <typename CmpGetter, typename PtrType, typename... Attributes> p->getter = [](IScene* scene, EntityRef e, u32 idx) -> i32 {
auto var_property(const char* name, CmpGetter getter, PtrType ptr, Attributes... attributes) using T = typename ResultOf<decltype(Getter)>::Type;
{ using C = typename ClassOf<decltype(Getter)>::Type;
using T = typename ResultOf<PtrType>::Type; if constexpr (ArgsCount<decltype(Getter)>::value == 1) {
VarProperty<T, CmpGetter, PtrType, Attributes...> p; return static_cast<i32>((static_cast<C*>(scene)->*Getter)(e));
p.attributes = makeTuple(attributes...); }
p.cmp_getter = getter; else {
p.ptr = ptr; return static_cast<i32>((static_cast<C*>(scene)->*Getter)(e, idx));
p.name = name; }
return p; };
} p->name = name;
addProp(p);
return *this;
}
template <auto Getter, auto Setter>
builder& prop(const char* name) {
using T = typename ResultOf<decltype(Getter)>::Type;
auto* p = LUMIX_NEW(allocator, Property<T>)(allocator);
p->setter = [](IScene* scene, EntityRef e, u32 idx, const T& value) {
using C = typename ClassOf<decltype(Setter)>::Type;
if constexpr (ArgsCount<decltype(Setter)>::value == 2) {
(static_cast<C*>(scene)->*Setter)(e, value);
}
else {
(static_cast<C*>(scene)->*Setter)(e, idx, value);
}
};
p->getter = [](IScene* scene, EntityRef e, u32 idx) -> T {
using C = typename ClassOf<decltype(Getter)>::Type;
if constexpr (ArgsCount<decltype(Getter)>::value == 1) {
return (static_cast<C*>(scene)->*Getter)(e);
}
else {
return (static_cast<C*>(scene)->*Getter)(e, idx);
}
};
p->name = name;
addProp(p);
return *this;
}
template <auto Getter, auto PropGetter>
builder& blob_property(const char* name) {
auto* p = LUMIX_NEW(allocator, BlobProperty)(allocator);
p->name = name;
addProp(p);
return *this;
}
template <auto Getter, auto PropGetter>
builder& var_prop(const char* name) {
using T = typename ResultOf<decltype(PropGetter)>::Type;
auto* p = LUMIX_NEW(allocator, Property<T>)(allocator);
p->setter = [](IScene* scene, EntityRef e, u32, const T& value) {
using C = typename ClassOf<decltype(Getter)>::Type;
auto& c = (static_cast<C*>(scene)->*Getter)(e);
auto& v = c.*PropGetter;
v = value;
};
p->getter = [](IScene* scene, EntityRef e, u32) -> T {
using C = typename ClassOf<decltype(Getter)>::Type;
auto& c = (static_cast<C*>(scene)->*Getter)(e);
auto& v = c.*PropGetter;
return static_cast<T>(v);
};
p->name = name;
addProp(p);
return *this;
}
template <typename Getter, typename Setter, typename... Attributes> template <auto Counter, auto Adder, auto Remover>
auto property(const char* name, Getter getter, Setter setter, Attributes... attributes) builder& begin_array(const char* name) {
{ ArrayProperty* prop = LUMIX_NEW(allocator, ArrayProperty)(allocator);
using R = typename ResultOf<Getter>::Type; using C = typename ClassOf<decltype(Counter)>::Type;
CommonProperty<R, Getter, Setter, Attributes...> p; prop->counter = [](IScene* scene, EntityRef e) -> u32 {
p.attributes = makeTuple(attributes...); return (static_cast<C*>(scene)->*Counter)(e);
p.getter = getter; };
p.setter = setter; prop->adder = [](IScene* scene, EntityRef e, u32 idx) {
p.name = name; (static_cast<C*>(scene)->*Adder)(e, idx);
return p; };
} prop->remover = [](IScene* scene, EntityRef e, u32 idx) {
(static_cast<C*>(scene)->*Remover)(e, idx);
};
prop->name = name;
scene->cmps.back()->props.push(prop);
array = prop;
last_prop = prop;
return *this;
}
template <typename Getter, typename Setter, typename... Attributes> template <typename T>
auto enum_property(const char* name, Getter getter, Setter setter, Attributes... attributes) builder& attribute() {
{ auto* a = LUMIX_NEW(allocator, T);
using R = typename ResultOf<Getter>::Type; last_prop->attributes.push(a);
CommonProperty<i32, Getter, Setter, Attributes...> p; return *this;
p.attributes = makeTuple(attributes...); }
p.getter = getter;
p.setter = setter;
p.name = name;
return p;
}
template <typename Counter, typename Adder, typename Remover, typename... Props> template <auto F>
auto array(const char* name, Counter counter, Adder adder, Remover remover, Props... properties) builder& function(const char* name, const char* decl_code) {
{ auto* f = LUMIX_NEW(allocator, Function<decltype(F)>);
ArrayProperty<Counter, Adder, Remover, Props...> p; f->function = F;
p.name = name; f->name = name;
p.counter = counter; f->decl_code = decl_code;
p.adder = adder; if (scene->cmps.empty()) {
p.remover = remover; scene->functions.push(f);
p.properties = makeTuple(properties...); }
return p; else {
} scene->cmps.back()->functions.push(f);
}
return *this;
}
void registerCmp(ComponentBase* cmp);
} // namespace Reflection builder& minAttribute(float value);
builder& clampAttribute(float min, float max);
builder& resourceAttribute(ResourceType type);
builder& radiansAttribute();
builder& colorAttribute();
builder& noUIAttribute();
builder& multilineAttribute();
builder& icon(const char* icon);
builder& end_array();
void addProp(PropertyBase* prop);
IAllocator& allocator;
Scene* scene;
ArrayProperty* array = nullptr;
PropertyBase* last_prop = nullptr;
};
builder build_scene(const char* scene_name);
} // namespace reflection
} // namespace Lumix } // namespace Lumix

View file

@ -5,6 +5,23 @@
namespace Lumix namespace Lumix
{ {
bool isLetter(char c)
{
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
}
bool isNumeric(char c)
{
return c >= '0' && c <= '9';
}
bool isUpperCase(char c)
{
return c >= 'A' && c <= 'Z';
}
String::String(IAllocator& allocator) String::String(IAllocator& allocator)

View file

@ -51,25 +51,9 @@ LUMIX_ENGINE_API int compareStringN(const char* lhs, const char* rhs, int length
LUMIX_ENGINE_API int compareIStringN(const char* lhs, const char* rhs, int length); LUMIX_ENGINE_API int compareIStringN(const char* lhs, const char* rhs, int length);
LUMIX_ENGINE_API const char* findSubstring(const char* str, const char* substr); LUMIX_ENGINE_API const char* findSubstring(const char* str, const char* substr);
LUMIX_ENGINE_API bool endsWith(const char* str, const char* substr); LUMIX_ENGINE_API bool endsWith(const char* str, const char* substr);
LUMIX_ENGINE_API bool isLetter(char c);
LUMIX_ENGINE_API bool isNumeric(char c);
inline bool isLetter(char c) LUMIX_ENGINE_API bool isUpperCase(char c);
{
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
}
inline bool isNumeric(char c)
{
return c >= '0' && c <= '9';
}
inline bool isUpperCase(char c)
{
return c >= 'A' && c <= 'Z';
}
template <int SIZE> bool copyString(char(&destination)[SIZE], const char* source) template <int SIZE> bool copyString(char(&destination)[SIZE], const char* source)
{ {

View file

@ -1,12 +1,6 @@
#include "engine/controller_device.h" #include "engine/controller_device.h"
#include "engine/allocator.h" #include "engine/allocator.h"
#include "engine/win/simple_win.h"
#define NOGDI
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <Xinput.h>
namespace Lumix namespace Lumix
{ {
@ -101,13 +95,13 @@ void ControllerDevice::init(InputSystem& input_system)
g_controllers.input = &input_system; g_controllers.input = &input_system;
g_controllers.last_checked = 0; g_controllers.last_checked = 0;
g_controllers.lib = LoadLibrary("Xinput9_1_0.dll"); g_controllers.lib = os::loadLibrary("Xinput9_1_0.dll");
if (g_controllers.lib) if (g_controllers.lib)
{ {
g_controllers.get_state = (XInputGetState_fn_ptr)GetProcAddress(g_controllers.lib, "XInputGetState"); g_controllers.get_state = (XInputGetState_fn_ptr)os::getLibrarySymbol(g_controllers.lib, "XInputGetState");
if (!g_controllers.get_state) if (!g_controllers.get_state)
{ {
FreeLibrary(g_controllers.lib); os::unloadLibrary(g_controllers.lib);
g_controllers.lib = nullptr; g_controllers.lib = nullptr;
} }
} }
@ -145,7 +139,7 @@ void ControllerDevice::frame(float dt)
void ControllerDevice::shutdown() void ControllerDevice::shutdown()
{ {
if (g_controllers.lib) FreeLibrary(g_controllers.lib); if (g_controllers.lib) os::unloadLibrary(g_controllers.lib);
} }

View file

@ -4,6 +4,8 @@
#ifndef _W64 #ifndef _W64
#define _W64 __w64 #define _W64 __w64
#endif #endif
#define ERROR_SUCCESS 0L
#define XUSER_MAX_COUNT 4
#define MEM_COMMIT 0x00001000 #define MEM_COMMIT 0x00001000
#define MEM_RESERVE 0x00002000 #define MEM_RESERVE 0x00002000
#define MEM_RELEASE 0x00008000 #define MEM_RELEASE 0x00008000
@ -277,8 +279,26 @@ struct sockaddr_in
typedef UINT_PTR SOCKET; typedef UINT_PTR SOCKET;
typedef unsigned short WORD; typedef unsigned short WORD;
typedef short SHORT;
typedef struct sockaddr_in SOCKADDR_IN; typedef struct sockaddr_in SOCKADDR_IN;
typedef struct _XINPUT_GAMEPAD
{
WORD wButtons;
BYTE bLeftTrigger;
BYTE bRightTrigger;
SHORT sThumbLX;
SHORT sThumbLY;
SHORT sThumbRX;
SHORT sThumbRY;
} XINPUT_GAMEPAD, *PXINPUT_GAMEPAD;
typedef struct _XINPUT_STATE
{
DWORD dwPacketNumber;
XINPUT_GAMEPAD Gamepad;
} XINPUT_STATE, *PXINPUT_STATE;
typedef struct _LIST_ENTRY { typedef struct _LIST_ENTRY {
struct _LIST_ENTRY *Flink; struct _LIST_ENTRY *Flink;
struct _LIST_ENTRY *Blink; struct _LIST_ENTRY *Blink;
@ -346,6 +366,11 @@ typedef struct tagWNDCLASSEXA
} WNDCLASSEXA, *PWNDCLASSEXA, *NPWNDCLASSEXA, *LPWNDCLASSEXA; } WNDCLASSEXA, *PWNDCLASSEXA, *NPWNDCLASSEXA, *LPWNDCLASSEXA;
typedef WNDCLASSEXA WNDCLASSEX; typedef WNDCLASSEXA WNDCLASSEX;
typedef PWNDCLASSEXA PWNDCLASSEX; typedef PWNDCLASSEXA PWNDCLASSEX;
typedef enum PROCESS_DPI_AWARENESS {
PROCESS_DPI_UNAWARE = 0,
PROCESS_SYSTEM_DPI_AWARE = 1,
PROCESS_PER_MONITOR_DPI_AWARE = 2
} PROCESS_DPI_AWARENESS;
typedef struct _SYSTEM_INFO typedef struct _SYSTEM_INFO
@ -369,6 +394,7 @@ typedef struct _SYSTEM_INFO
WORD wProcessorRevision; WORD wProcessorRevision;
} SYSTEM_INFO, *LPSYSTEM_INFO; } SYSTEM_INFO, *LPSYSTEM_INFO;
typedef long HRESULT;
typedef struct _OVERLAPPED typedef struct _OVERLAPPED
{ {
@ -477,6 +503,7 @@ typedef struct _WIN32_FIND_DATAA* LPWIN32_FIND_DATAA;
extern "C" { extern "C" {
DWORD WINAPI XInputGetState(DWORD dwUserIndex, XINPUT_STATE* pState);
int PASCAL closesocket(SOCKET s); int PASCAL closesocket(SOCKET s);
int PASCAL WSAStartup(WORD wVersionRequired, LPWSADATA lpWSAData); int PASCAL WSAStartup(WORD wVersionRequired, LPWSADATA lpWSAData);
SOCKET PASCAL socket(int af, int type, int protocol); SOCKET PASCAL socket(int af, int type, int protocol);
@ -628,5 +655,7 @@ LPVOID WINAPI CreateFiber(SIZE_T dwStackSize, LPFIBER_START_ROUTINE lpStartAddre
LPVOID WINAPI ConvertThreadToFiber(LPVOID lpParameter); LPVOID WINAPI ConvertThreadToFiber(LPVOID lpParameter);
WINBASEAPI VOID WINAPI SwitchToFiber(LPVOID lpFiber); WINBASEAPI VOID WINAPI SwitchToFiber(LPVOID lpFiber);
WINBASEAPI VOID WINAPI DeleteFiber(PVOID lpFiber); WINBASEAPI VOID WINAPI DeleteFiber(PVOID lpFiber);
HRESULT WINAPI SetProcessDpiAwareness(PROCESS_DPI_AWARENESS value);
DECLSPEC_IMPORT BOOL WINAPI SetProcessDPIAware(VOID);
} // extern "C" } // extern "C"

View file

@ -1339,49 +1339,44 @@ void GUIScene::reflect() {
} }
}; };
LUMIX_SCENE(GUISceneImpl, "gui", LUMIX_SCENE(GUISceneImpl, "gui")
LUMIX_FUNC(GUIScene::getRectAt), .LUMIX_FUNC(GUIScene::getRectAt)
LUMIX_FUNC(GUIScene::isOver), .LUMIX_FUNC(GUIScene::isOver)
LUMIX_FUNC(GUIScene::getSystem), .LUMIX_FUNC(GUIScene::getSystem)
LUMIX_CMP(RenderTarget, "gui_render_target", "GUI / Render taget"), .LUMIX_CMP(RenderTarget, "gui_render_target", "GUI / Render taget")
LUMIX_CMP(Text, "gui_text", "GUI / Text", .LUMIX_CMP(Text, "gui_text", "GUI / Text")
icon(ICON_FA_FONT), .icon(ICON_FA_FONT)
LUMIX_PROP(Text, "Text", MultilineAttribute()), .LUMIX_PROP(Text, "Text").multilineAttribute()
LUMIX_PROP(TextFontPath, "Font", ResourceAttribute(FontResource::TYPE)), .LUMIX_PROP(TextFontPath, "Font").resourceAttribute(FontResource::TYPE)
LUMIX_PROP(TextFontSize, "Font Size"), .LUMIX_PROP(TextFontSize, "Font Size")
enum_property("Horizontal align", &GUIScene::getTextHAlign, &GUIScene::setTextHAlign, TextHAlignEnum()), .LUMIX_ENUM_PROP(TextHAlign, "Horizontal align").attribute<TextHAlignEnum>()
enum_property("Vertical align", &GUIScene::getTextVAlign, &GUIScene::setTextVAlign, TextVAlignEnum()), .LUMIX_ENUM_PROP(TextVAlign, "Vertical align").attribute<TextVAlignEnum>()
LUMIX_PROP(TextColorRGBA, "Color", ColorAttribute()) .LUMIX_PROP(TextColorRGBA, "Color").colorAttribute()
), .LUMIX_CMP(InputField, "gui_input_field", "GUI / Input field").icon(ICON_FA_KEYBOARD)
LUMIX_CMP(InputField, "gui_input_field", "GUI / Input field", icon(ICON_FA_KEYBOARD)), .LUMIX_CMP(Canvas, "gui_canvas", "GUI / Canvas")
LUMIX_CMP(Canvas, "gui_canvas", "GUI / Canvas", .var_prop<&GUIScene::getCanvas, &GUICanvas::is_3d>("Is 3D")
var_property("Is 3D", &GUIScene::getCanvas, &GUICanvas::is_3d), .var_prop<&GUIScene::getCanvas, &GUICanvas::orient_to_camera>("Orient to camera")
var_property("Orient to camera", &GUIScene::getCanvas, &GUICanvas::orient_to_camera), .var_prop<&GUIScene::getCanvas, &GUICanvas::virtual_size>("Virtual size")
var_property("Virtual size", &GUIScene::getCanvas, &GUICanvas::virtual_size) .LUMIX_CMP(Button, "gui_button", "GUI / Button")
), .LUMIX_PROP(ButtonHoveredColorRGBA, "Hovered color").colorAttribute()
LUMIX_CMP(Button, "gui_button", "GUI / Button", .LUMIX_ENUM_PROP(ButtonHoveredCursor, "Cursor").attribute<CursorEnum>()
LUMIX_PROP(ButtonHoveredColorRGBA, "Hovered color", ColorAttribute()), .LUMIX_CMP(Image, "gui_image", "GUI / Image")
enum_property("Cursor", &GUIScene::getButtonHoveredCursor, &GUIScene::setButtonHoveredCursor, CursorEnum()) .icon(ICON_FA_IMAGE)
), .prop<&GUIScene::isImageEnabled, &GUIScene::enableImage>("Enabled")
LUMIX_CMP(Image, "gui_image", "GUI / Image", .LUMIX_PROP(ImageColorRGBA, "Color").colorAttribute()
icon(ICON_FA_IMAGE), .LUMIX_PROP(ImageSprite, "Sprite").resourceAttribute(Sprite::TYPE)
property("Enabled", &GUIScene::isImageEnabled, &GUIScene::enableImage), .LUMIX_CMP(Rect, "gui_rect", "GUI / Rect")
LUMIX_PROP(ImageColorRGBA, "Color", ColorAttribute()), .prop<&GUIScene::isRectEnabled, &GUIScene::enableRect>("Enabled")
LUMIX_PROP(ImageSprite, "Sprite", ResourceAttribute(Sprite::TYPE)) .LUMIX_PROP(RectClip, "Clip content")
), .LUMIX_PROP(RectTopPoints, "Top Points")
LUMIX_CMP(Rect, "gui_rect", "GUI / Rect", .LUMIX_PROP(RectTopRelative, "Top Relative")
property("Enabled", &GUIScene::isRectEnabled, &GUIScene::enableRect), .LUMIX_PROP(RectRightPoints, "Right Points")
LUMIX_PROP(RectClip, "Clip content"), .LUMIX_PROP(RectRightRelative, "Right Relative")
LUMIX_PROP(RectTopPoints, "Top Points"), .LUMIX_PROP(RectBottomPoints, "Bottom Points")
LUMIX_PROP(RectTopRelative, "Top Relative"), .LUMIX_PROP(RectBottomRelative, "Bottom Relative")
LUMIX_PROP(RectRightPoints, "Right Points"), .LUMIX_PROP(RectLeftPoints, "Left Points")
LUMIX_PROP(RectRightRelative, "Right Relative"), .LUMIX_PROP(RectLeftRelative, "Left Relative")
LUMIX_PROP(RectBottomPoints, "Bottom Points"), ;
LUMIX_PROP(RectBottomRelative, "Bottom Relative"),
LUMIX_PROP(RectLeftPoints, "Left Points"),
LUMIX_PROP(RectLeftRelative, "Left Relative")
)
);
} }
} // namespace Lumix } // namespace Lumix

View file

@ -65,7 +65,7 @@ struct GUISystemImpl final : GUISystem
, m_sprite_manager(engine.getAllocator()) , m_sprite_manager(engine.getAllocator())
{ {
GUIScene::reflect(); GUIScene::reflect();
LUMIX_FUNC(GUISystem::enableCursor); LUMIX_GLOBAL_FUNC(GUISystem::enableCursor);
m_sprite_manager.create(Sprite::TYPE, m_engine.getResourceManager()); m_sprite_manager.create(Sprite::TYPE, m_engine.getResourceManager());
} }

View file

@ -17,7 +17,6 @@
#include "engine/lua_wrapper.h" #include "engine/lua_wrapper.h"
#include "engine/os.h" #include "engine/os.h"
#include "engine/path.h" #include "engine/path.h"
#include "engine/reflection.h"
#include "engine/stream.h" #include "engine/stream.h"
#include "engine/universe.h" #include "engine/universe.h"
#include "lua_script/lua_script.h" #include "lua_script/lua_script.h"

View file

@ -924,8 +924,8 @@ namespace Lumix
LuaWrapper::push(L, tmp); LuaWrapper::push(L, tmp);
} }
void visit(const reflection::IArrayProperty& prop) override {} void visit(const reflection::ArrayProperty& prop) override {}
void visit(const reflection::IBlobProperty& prop) override {} void visit(const reflection::BlobProperty& prop) override {}
ComponentUID cmp; ComponentUID cmp;
const char* prop_name; const char* prop_name;
@ -979,8 +979,8 @@ namespace Lumix
prop.set(cmp, idx, val); prop.set(cmp, idx, val);
} }
void visit(const reflection::IArrayProperty& prop) override {} void visit(const reflection::ArrayProperty& prop) override {}
void visit(const reflection::IBlobProperty& prop) override {} void visit(const reflection::BlobProperty& prop) override {}
ComponentUID cmp; ComponentUID cmp;
const char* prop_name; const char* prop_name;
@ -1044,8 +1044,7 @@ namespace Lumix
if (v.found) return 1; if (v.found) return 1;
// TODO put this directly in table, so we don't have to look it up here every time // TODO put this directly in table, so we don't have to look it up here every time
const auto& functions = cmp->getFunctions(); for (auto* f : cmp->functions) {
for (auto* f : functions) {
if (equalStrings(v.prop_name, f->name)) { if (equalStrings(v.prop_name, f->name)) {
lua_pushlightuserdata(L, (void*)f); lua_pushlightuserdata(L, (void*)f);
lua_pushcclosure(L, luaCmpMethodClosure, 1); lua_pushcclosure(L, luaCmpMethodClosure, 1);
@ -1098,7 +1097,7 @@ namespace Lumix
lua_State* L = m_system.m_engine.getState(); lua_State* L = m_system.m_engine.getState();
LuaWrapper::DebugGuard guard(L); LuaWrapper::DebugGuard guard(L);
reflection::SceneBase* scene = reflection::getFirstScene(); reflection::Scene* scene = reflection::getFirstScene();
while (scene) { while (scene) {
lua_newtable(L); // [ scene ] lua_newtable(L); // [ scene ]
lua_getglobal(L, "Lumix"); // [ scene, Lumix ] lua_getglobal(L, "Lumix"); // [ scene, Lumix ]
@ -1112,9 +1111,10 @@ namespace Lumix
lua_pushcfunction(L, lua_new_scene); // [ scene, fn_new_scene ] lua_pushcfunction(L, lua_new_scene); // [ scene, fn_new_scene ]
lua_setfield(L, -2, "new"); // [ scene ] lua_setfield(L, -2, "new"); // [ scene ]
for (const reflection::FunctionBase* f : scene->getFunctions()) { for (const reflection::FunctionBase* f : scene->functions) {
const char* c = f->decl_code; const char* c = f->decl_code;
while (*c != ':') ++c; while (*c != ':' && *c) ++c;
ASSERT(*c == ':');
c += 2; c += 2;
lua_pushlightuserdata(L, (void*)f); // [scene, f] lua_pushlightuserdata(L, (void*)f); // [scene, f]
lua_pushcclosure(L, luaSceneMethodClosure, 1); // [scene, fn] lua_pushcclosure(L, luaSceneMethodClosure, 1); // [scene, fn]
@ -2207,8 +2207,12 @@ namespace Lumix
} }
struct LuaProperties : reflection::IDynamicProperties { struct LuaProperties : reflection::DynamicProperties {
LuaProperties() { name = "lua_properties"; } LuaProperties(IAllocator& allocator)
: DynamicProperties(allocator)
{
name = "lua_properties";
}
u32 getCount(ComponentUID cmp, int index) const override { u32 getCount(ComponentUID cmp, int index) const override {
LuaScriptSceneImpl& scene = (LuaScriptSceneImpl&)*cmp.scene; LuaScriptSceneImpl& scene = (LuaScriptSceneImpl&)*cmp.scene;
@ -2319,15 +2323,15 @@ namespace Lumix
{ {
m_script_manager.create(LuaScript::TYPE, engine.getResourceManager()); m_script_manager.create(LuaScript::TYPE, engine.getResourceManager());
LUMIX_SCENE(LuaScriptSceneImpl, "lua_script", LUMIX_SCENE(LuaScriptSceneImpl, "lua_script")
LUMIX_CMP(Component, "lua_script", "Lua script", .LUMIX_CMP(Component, "lua_script", "Lua script")
array("scripts", &LuaScriptScene::getScriptCount, &LuaScriptScene::addScript, &LuaScriptScene::removeScript, .begin_array<&LuaScriptScene::getScriptCount, &LuaScriptScene::addScript, &LuaScriptScene::removeScript>("scripts")
property("Enabled", &LuaScriptScene::isScriptEnabled, &LuaScriptScene::enableScript), .prop<&LuaScriptScene::isScriptEnabled, &LuaScriptScene::enableScript>("Enabled")
LUMIX_PROP(ScriptPath, "Path", ResourceAttribute(LuaScript::TYPE)), .LUMIX_PROP(ScriptPath, "Path").resourceAttribute(LuaScript::TYPE)
LuaProperties() //LuaProperties()
) .end_array()
) // TODO refl
); ;
} }
void LuaScriptSystemImpl::init() { void LuaScriptSystemImpl::init() {

View file

@ -1534,33 +1534,32 @@ UniquePtr<NavigationScene> NavigationScene::create(Engine& engine, IPlugin& syst
return UniquePtr<NavigationSceneImpl>::create(allocator, engine, system, universe, allocator); return UniquePtr<NavigationSceneImpl>::create(allocator, engine, system, universe, allocator);
} }
void NavigationScene::reflect() { void NavigationScene::reflect() {
LUMIX_SCENE(NavigationSceneImpl, "navigation", LUMIX_SCENE(NavigationSceneImpl, "navigation")
LUMIX_FUNC(NavigationScene::setGeneratorParams), .LUMIX_FUNC(NavigationSceneImpl::setGeneratorParams)
LUMIX_CMP(Zone, "navmesh_zone", "Navigation / Zone",
icon(ICON_FA_MAP_MARKED_ALT), .LUMIX_CMP(Zone, "navmesh_zone", "Navigation / Zone")
LUMIX_FUNC_EX(NavigationScene::debugDrawContours, "drawContours"), .icon(ICON_FA_STREET_VIEW)
LUMIX_FUNC_EX(NavigationScene::debugDrawNavmesh, "drawNavmesh"), .LUMIX_FUNC_EX(debugDrawContours, "drawContours")
LUMIX_FUNC_EX(NavigationScene::debugDrawCompactHeightfield, "drawCompactHeightfield"), .LUMIX_FUNC_EX(debugDrawNavmesh, "drawNavmesh")
LUMIX_FUNC_EX(NavigationScene::debugDrawHeightfield, "drawHeightfield"), .LUMIX_FUNC_EX(debugDrawCompactHeightfield, "drawCompactHeightfield")
LUMIX_FUNC(NavigationScene::save), .LUMIX_FUNC_EX(debugDrawHeightfield, "drawHeightfield")
LUMIX_FUNC(NavigationScene::load), .LUMIX_FUNC(save)
LUMIX_FUNC(NavigationScene::generateNavmesh), .LUMIX_FUNC(load)
var_property("Extents", &NavigationScene::getZone, &NavmeshZone::extents) .LUMIX_FUNC(generateNavmesh)
), .var_prop<&NavigationScene::getZone, &NavmeshZone::extents>("Extents")
LUMIX_CMP(Agent, "navmesh_agent", "Navigation / Agent",
icon(ICON_FA_STREET_VIEW), .LUMIX_CMP(Agent, "navmesh_agent", "Navigation / Agent")
LUMIX_FUNC_EX(NavigationScene::setActorActive, "setActive"), .icon(ICON_FA_MAP_MARKED_ALT)
LUMIX_FUNC_EX(NavigationScene::navigate, "navigate"), .LUMIX_FUNC_EX(setActorActive, "setActive")
LUMIX_FUNC_EX(NavigationScene::cancelNavigation, "cancelNavigation"), .LUMIX_FUNC_EX(navigate, "navigate")
LUMIX_FUNC_EX(NavigationScene::getAgentSpeed, "getSpeed"), .LUMIX_FUNC_EX(cancelNavigation, "cancelNavigation")
LUMIX_FUNC_EX(NavigationScene::debugDrawPath, "drawPath"), .LUMIX_FUNC_EX(getAgentSpeed, "getSpeed")
LUMIX_PROP(AgentRadius, "Radius", MinAttribute(0)), .LUMIX_FUNC_EX(debugDrawPath, "drawPath")
LUMIX_PROP(AgentHeight, "Height", MinAttribute(0)), .LUMIX_PROP(AgentRadius, "Radius").minAttribute(0)
property("Use root motion", &NavigationScene::useAgentRootMotion, &NavigationScene::setUseAgentRootMotion) .LUMIX_PROP(AgentHeight, "Height").minAttribute(0)
//property("Get root motion from animation", LUMIX_PROP_FULL(NavigationScene, isGettingRootMotionFromAnim, setIsGettingRootMotionFromAnim)) .prop<&NavigationScene::useAgentRootMotion, &NavigationScene::setUseAgentRootMotion>("Use root motion");
)
);
} }
} // namespace Lumix } // namespace Lumix

View file

@ -3,7 +3,6 @@
#include "engine/engine.h" #include "engine/engine.h"
#include "engine/lumix.h" #include "engine/lumix.h"
#include "engine/math.h" #include "engine/math.h"
#include "engine/reflection.h"
#include "engine/universe.h" #include "engine/universe.h"
#include "navigation/navigation_scene.h" #include "navigation/navigation_scene.h"
#include "renderer/material.h" #include "renderer/material.h"

View file

@ -19,7 +19,6 @@
#include "engine/log.h" #include "engine/log.h"
#include "engine/math.h" #include "engine/math.h"
#include "engine/path.h" #include "engine/path.h"
#include "engine/reflection.h"
#include "engine/universe.h" #include "engine/universe.h"
#include "physics/physics_geometry.h" #include "physics/physics_geometry.h"
#include "physics/physics_scene.h" #include "physics/physics_scene.h"

View file

@ -4532,125 +4532,106 @@ void PhysicsScene::reflect() {
} }
}; };
// "temporary" hack to fix crash at startup on linux LUMIX_SCENE(PhysicsSceneImpl, "physics")
// last good commmit around eb0e5c9b6fc7ce3de197c5c0b2b30e9f8c9653eb .LUMIX_FUNC(PhysicsSceneImpl::raycast)
#ifdef _WIN32 .LUMIX_CMP(Ragdoll, "ragdoll", "Physics / Ragdoll")
#define VEHICLE_CMP \ .icon(ICON_FA_MALE)
, \ .LUMIX_FUNC(PhysicsScene::setRagdollKinematic)
LUMIX_FUNC_EX(PhysicsScene::setVehicleAccel, "setAccel"), \ .blob_property<&PhysicsScene::getRagdollData, &PhysicsScene::setRagdollData>("data")
LUMIX_FUNC_EX(PhysicsScene::setVehicleSteer, "setSteer"), \ .LUMIX_ENUM_PROP(RagdollLayer, "Layer").attribute<LayerEnum>()
LUMIX_PROP(VehicleMass, "Mass", MinAttribute(0)), \ .LUMIX_CMP(D6Joint, "d6_joint", "Physics / Joint / D6")
LUMIX_PROP(VehicleCenterOfMass, "Center of mass"), \ .LUMIX_PROP(JointConnectedBody, "Connected body")
LUMIX_PROP(VehicleMOIMultiplier, "MOI multiplier"), \ .LUMIX_PROP(JointAxisPosition, "Axis position")
LUMIX_PROP(VehicleChassis, "Chassis", ResourceAttribute(PhysicsGeometry::TYPE)), \ .LUMIX_PROP(JointAxisDirection, "Axis direction")
LUMIX_PROP(VehicleChassisLayer, "Chassis layer", LayerEnum()), \ .LUMIX_ENUM_PROP(D6JointXMotion, "X motion").attribute<D6MotionEnum>()
LUMIX_PROP(VehicleWheelsLayer, "Wheels layer", LayerEnum()) .LUMIX_ENUM_PROP(D6JointYMotion, "Y motion").attribute<D6MotionEnum>()
#else .LUMIX_ENUM_PROP(D6JointZMotion, "Z motion").attribute<D6MotionEnum>()
#define VEHICLE_CMP .LUMIX_ENUM_PROP(D6JointSwing1Motion, "Swing 1").attribute<D6MotionEnum>()
#endif .LUMIX_ENUM_PROP(D6JointSwing2Motion, "Swing 2").attribute<D6MotionEnum>()
.LUMIX_ENUM_PROP(D6JointTwistMotion, "Twist").attribute<D6MotionEnum>()
LUMIX_SCENE(PhysicsSceneImpl, "physics", .LUMIX_PROP(D6JointLinearLimit, "Linear limit").minAttribute(0)
LUMIX_FUNC(PhysicsSceneImpl::raycast), .LUMIX_PROP(D6JointSwingLimit, "Swing limit").radiansAttribute()
//function(LUMIX_FUNC(PhysicsScene::raycastEx)) .LUMIX_PROP(D6JointTwistLimit, "Twist limit").radiansAttribute()
LUMIX_CMP(Ragdoll, "ragdoll", "Physics / Ragdoll", .LUMIX_PROP(D6JointDamping, "Damping")
icon(ICON_FA_MALE), .LUMIX_PROP(D6JointStiffness, "Stiffness")
LUMIX_FUNC(PhysicsScene::setRagdollKinematic), .LUMIX_PROP(D6JointRestitution, "Restitution")
blob_property("data", &PhysicsScene::getRagdollData, &PhysicsScene::setRagdollData), .LUMIX_CMP(SphericalJoint, "spherical_joint", "Physics / Joint / Spherical")
LUMIX_PROP(RagdollLayer, "Layer", LayerEnum()) .LUMIX_PROP(JointConnectedBody, "Connected body")
), .LUMIX_PROP(JointAxisPosition, "Axis position")
LUMIX_CMP(D6Joint, "d6_joint", "Physics / Joint / D6", .LUMIX_PROP(JointAxisDirection, "Axis direction")
LUMIX_PROP(JointConnectedBody, "Connected body"), .LUMIX_PROP(SphericalJointUseLimit, "Use limit")
LUMIX_PROP(JointAxisPosition, "Axis position"), .LUMIX_PROP(SphericalJointLimit, "Limit").radiansAttribute()
LUMIX_PROP(JointAxisDirection, "Axis direction"), .LUMIX_CMP(DistanceJoint, "distance_joint", "Physics / Joint / Distance")
enum_property("X motion", &PhysicsScene::getD6JointXMotion, &PhysicsScene::setD6JointXMotion, D6MotionEnum()), .LUMIX_PROP(JointConnectedBody, "Connected body")
enum_property("Y motion", &PhysicsScene::getD6JointYMotion, &PhysicsScene::setD6JointYMotion, D6MotionEnum()), .LUMIX_PROP(JointAxisPosition, "Axis position")
enum_property("Z motion", &PhysicsScene::getD6JointZMotion, &PhysicsScene::setD6JointZMotion, D6MotionEnum()), .LUMIX_PROP(DistanceJointDamping, "Damping").minAttribute(0)
enum_property("Swing 1", &PhysicsScene::getD6JointSwing1Motion, &PhysicsScene::setD6JointSwing1Motion, D6MotionEnum()), .LUMIX_PROP(DistanceJointStiffness, "Stiffness").minAttribute(0)
enum_property("Swing 2", &PhysicsScene::getD6JointSwing2Motion, &PhysicsScene::setD6JointSwing2Motion, D6MotionEnum()), .LUMIX_PROP(DistanceJointTolerance, "Tolerance").minAttribute(0)
enum_property("Twist", &PhysicsScene::getD6JointTwistMotion, &PhysicsScene::setD6JointTwistMotion, D6MotionEnum()), .LUMIX_PROP(DistanceJointLimits, "Limits")
LUMIX_PROP(D6JointLinearLimit, "Linear limit", MinAttribute(0)), .LUMIX_CMP(HingeJoint, "hinge_joint", "Physics / Joint / Hinge")
LUMIX_PROP(D6JointSwingLimit, "Swing limit", RadiansAttribute()), .LUMIX_PROP(JointConnectedBody, "Connected body")
LUMIX_PROP(D6JointTwistLimit, "Twist limit", RadiansAttribute()), .LUMIX_PROP(JointAxisPosition, "Axis position")
LUMIX_PROP(D6JointDamping, "Damping"), .LUMIX_PROP(JointAxisDirection, "Axis direction")
LUMIX_PROP(D6JointStiffness, "Stiffness"), .LUMIX_PROP(HingeJointDamping, "Damping").minAttribute(0)
LUMIX_PROP(D6JointRestitution, "Restitution") .LUMIX_PROP(HingeJointStiffness, "Stiffness").minAttribute(0)
), .LUMIX_PROP(HingeJointUseLimit, "Use limit")
LUMIX_CMP(SphericalJoint, "spherical_joint", "Physics / Joint / Spherical", .LUMIX_PROP(HingeJointLimit, "Limit").radiansAttribute()
LUMIX_PROP(JointConnectedBody, "Connected body"), .LUMIX_CMP(Controller, "physical_controller", "Physics / Controller")
LUMIX_PROP(JointAxisPosition, "Axis position"), .LUMIX_FUNC_EX(PhysicsScene::moveController, "move")
LUMIX_PROP(JointAxisDirection, "Axis direction"), .LUMIX_FUNC_EX(PhysicsScene::isControllerCollisionDown, "isCollisionDown")
LUMIX_PROP(SphericalJointUseLimit, "Use limit"), .LUMIX_PROP(ControllerRadius, "Radius")
LUMIX_PROP(SphericalJointLimit, "Limit", RadiansAttribute()) .LUMIX_PROP(ControllerHeight, "Height")
), .LUMIX_ENUM_PROP(ControllerLayer, "Layer").attribute<LayerEnum>()
LUMIX_CMP(DistanceJoint, "distance_joint", "Physics / Joint / Distance", .LUMIX_PROP(ControllerUseRootMotion, "Use root motion")
LUMIX_PROP(JointConnectedBody, "Connected body"), .LUMIX_PROP(ControllerCustomGravity, "Use custom gravity")
LUMIX_PROP(JointAxisPosition, "Axis position"), .LUMIX_PROP(ControllerCustomGravityAcceleration, "Custom gravity acceleration")
LUMIX_PROP(DistanceJointDamping, "Damping", MinAttribute(0)), .LUMIX_CMP(RigidActor, "rigid_actor", "Physics / Rigid actor")
LUMIX_PROP(DistanceJointStiffness, "Stiffness", MinAttribute(0)), .icon(ICON_FA_VOLLEYBALL_BALL)
LUMIX_PROP(DistanceJointTolerance, "Tolerance", MinAttribute(0)), .LUMIX_FUNC_EX(PhysicsScene::putToSleep, "putToSleep")
LUMIX_PROP(DistanceJointLimits, "Limits") .LUMIX_FUNC_EX(PhysicsScene::getActorSpeed, "getSpeed")
), .LUMIX_FUNC_EX(PhysicsScene::getActorVelocity, "getVelocity")
LUMIX_CMP(HingeJoint, "hinge_joint", "Physics / Joint / Hinge", .LUMIX_FUNC_EX(PhysicsScene::applyForceToActor, "applyForce")
LUMIX_PROP(JointConnectedBody, "Connected body"), .LUMIX_FUNC_EX(PhysicsScene::applyForceToActor, "applyImpulse")
LUMIX_PROP(JointAxisPosition, "Axis position"), .LUMIX_FUNC_EX(PhysicsScene::addForceAtPos, "addForceAtPos")
LUMIX_PROP(JointAxisDirection, "Axis direction"), .LUMIX_ENUM_PROP(ActorLayer, "Layer").attribute<LayerEnum>()
LUMIX_PROP(HingeJointDamping, "Damping", MinAttribute(0)), .LUMIX_ENUM_PROP(DynamicType, "Dynamic").attribute<DynamicTypeEnum>()
LUMIX_PROP(HingeJointStiffness, "Stiffness", MinAttribute(0)), .LUMIX_PROP(IsTrigger, "Trigger")
LUMIX_PROP(HingeJointUseLimit, "Use limit"), .begin_array<&PhysicsScene::getBoxGeometryCount, &PhysicsScene::addBoxGeometry, &PhysicsScene::removeBoxGeometry>("Box geometry")
LUMIX_PROP(HingeJointLimit, "Limit", RadiansAttribute()) .LUMIX_PROP(BoxGeomHalfExtents, "Size")
), .LUMIX_PROP(BoxGeomOffsetPosition, "Position offset")
LUMIX_CMP(Controller, "physical_controller", "Physics / Controller", .LUMIX_PROP(BoxGeomOffsetRotation, "Rotation offset").radiansAttribute()
LUMIX_FUNC_EX(PhysicsScene::moveController, "move"), .end_array()
LUMIX_FUNC_EX(PhysicsScene::isControllerCollisionDown, "isCollisionDown"), .begin_array<&PhysicsScene::getSphereGeometryCount, &PhysicsScene::addSphereGeometry, &PhysicsScene::removeSphereGeometry>("Sphere geometry")
LUMIX_PROP(ControllerRadius, "Radius"), .LUMIX_PROP(SphereGeomRadius, "Radius").minAttribute(0)
LUMIX_PROP(ControllerHeight, "Height"), .LUMIX_PROP(SphereGeomOffsetPosition, "Position offset")
LUMIX_PROP(ControllerLayer, "Layer", LayerEnum()), .end_array()
LUMIX_PROP(ControllerUseRootMotion, "Use root motion"), .LUMIX_PROP(MeshGeomPath, "Mesh").resourceAttribute(PhysicsGeometry::TYPE)
LUMIX_PROP(ControllerCustomGravity, "Use custom gravity"), .LUMIX_CMP(Vehicle, "vehicle", "Physics / Vehicle")
LUMIX_PROP(ControllerCustomGravityAcceleration, "Custom gravity acceleration") .icon(ICON_FA_CAR_ALT)
), .LUMIX_FUNC_EX(PhysicsScene::setVehicleAccel, "setAccel")
LUMIX_CMP(RigidActor, "rigid_actor", "Physics / Rigid actor", .LUMIX_FUNC_EX(PhysicsScene::setVehicleSteer, "setSteer")
icon(ICON_FA_VOLLEYBALL_BALL), .LUMIX_PROP(VehicleMass, "Mass").minAttribute(0)
LUMIX_FUNC_EX(PhysicsScene::putToSleep, "putToSleep"), .LUMIX_PROP(VehicleCenterOfMass, "Center of mass")
LUMIX_FUNC_EX(PhysicsScene::getActorSpeed, "getSpeed"), .LUMIX_PROP(VehicleMOIMultiplier, "MOI multiplier")
LUMIX_FUNC_EX(PhysicsScene::getActorVelocity, "getVelocity"), .LUMIX_PROP(VehicleChassis, "Chassis").resourceAttribute(PhysicsGeometry::TYPE)
LUMIX_FUNC_EX(PhysicsScene::applyForceToActor, "applyForce"), .LUMIX_ENUM_PROP(VehicleChassisLayer, "Chassis layer").attribute<LayerEnum>()
LUMIX_FUNC_EX(PhysicsScene::applyForceToActor, "applyImpulse"), .LUMIX_ENUM_PROP(VehicleWheelsLayer, "Wheels layer").attribute<LayerEnum>()
LUMIX_FUNC_EX(PhysicsScene::addForceAtPos, "addForceAtPos"), .LUMIX_CMP(Wheel, "wheel", "Physics / Wheel")
LUMIX_PROP(ActorLayer, "Layer", LayerEnum()), .LUMIX_PROP(WheelRadius, "Radius").minAttribute(0)
enum_property("Dynamic", &PhysicsSceneImpl::getDynamicType, &PhysicsSceneImpl::setDynamicType, DynamicTypeEnum()), .LUMIX_PROP(WheelWidth, "Width").minAttribute(0)
LUMIX_PROP(IsTrigger, "Trigger"), .LUMIX_PROP(WheelMass, "Mass").minAttribute(0)
array("Box geometry", &PhysicsScene::getBoxGeometryCount, &PhysicsScene::addBoxGeometry, &PhysicsScene::removeBoxGeometry, .LUMIX_PROP(WheelMOI, "MOI").minAttribute(0)
LUMIX_PROP(BoxGeomHalfExtents, "Size"), .LUMIX_PROP(WheelSpringMaxCompression, "Max compression").minAttribute(0)
LUMIX_PROP(BoxGeomOffsetPosition, "Position offset"), .LUMIX_PROP(WheelSpringMaxDroop, "Max droop").minAttribute(0)
LUMIX_PROP(BoxGeomOffsetRotation, "Rotation offset", RadiansAttribute())), .LUMIX_PROP(WheelSpringStrength, "Spring strength").minAttribute(0)
array("Sphere geometry", &PhysicsScene::getSphereGeometryCount, &PhysicsScene::addSphereGeometry, &PhysicsScene::removeSphereGeometry, .LUMIX_PROP(WheelSpringDamperRate, "Spring damper rate").minAttribute(0)
LUMIX_PROP(SphereGeomRadius, "Radius", MinAttribute(0)), .LUMIX_ENUM_PROP(WheelSlot, "Slot").attribute<WheelSlotEnum>()
LUMIX_PROP(SphereGeomOffsetPosition, "Position offset")), .LUMIX_CMP(Heightfield, "physical_heightfield", "Physics / Heightfield")
LUMIX_PROP(MeshGeomPath, "Mesh", ResourceAttribute(PhysicsGeometry::TYPE)) .LUMIX_ENUM_PROP(HeightfieldLayer, "Layer").attribute<LayerEnum>()
), .LUMIX_PROP(HeightmapSource, "Heightmap").resourceAttribute(Texture::TYPE)
LUMIX_CMP(Vehicle, "vehicle", "Physics / Vehicle", .LUMIX_PROP(HeightmapYScale, "Y scale").minAttribute(0)
icon(ICON_FA_CAR_ALT) .LUMIX_PROP(HeightmapXZScale, "XZ scale").minAttribute(0)
VEHICLE_CMP ;
),
LUMIX_CMP(Wheel, "wheel", "Physics / Wheel",
LUMIX_PROP(WheelRadius, "Radius", MinAttribute(0)),
LUMIX_PROP(WheelWidth, "Width", MinAttribute(0)),
LUMIX_PROP(WheelMass, "Mass", MinAttribute(0)),
LUMIX_PROP(WheelMOI, "MOI", MinAttribute(0)),
LUMIX_PROP(WheelSpringMaxCompression, "Max compression", MinAttribute(0)),
LUMIX_PROP(WheelSpringMaxDroop, "Max droop", MinAttribute(0)),
LUMIX_PROP(WheelSpringStrength, "Spring strength", MinAttribute(0)),
LUMIX_PROP(WheelSpringDamperRate, "Spring damper rate", MinAttribute(0)),
enum_property("Slot", &PhysicsSceneImpl::getWheelSlot, &PhysicsSceneImpl::setWheelSlot, WheelSlotEnum())
),
LUMIX_CMP(Heightfield, "physical_heightfield", "Physics / Heightfield",
LUMIX_PROP(HeightfieldLayer, "Layer", LayerEnum()),
LUMIX_PROP(HeightmapSource, "Heightmap", ResourceAttribute(Texture::TYPE)),
LUMIX_PROP(HeightmapYScale, "Y scale", MinAttribute(0)),
LUMIX_PROP(HeightmapXZScale, "XZ scale", MinAttribute(0))
)
);
} }
void PhysicsSceneImpl::RigidActor::onStateChanged(Resource::State, Resource::State new_state, Resource&) void PhysicsSceneImpl::RigidActor::onStateChanged(Resource::State, Resource::State new_state, Resource&)

View file

@ -13,7 +13,6 @@
#include "engine/engine.h" #include "engine/engine.h"
#include "engine/log.h" #include "engine/log.h"
#include "engine/lua_wrapper.h" #include "engine/lua_wrapper.h"
#include "engine/reflection.h"
#include "engine/resource_manager.h" #include "engine/resource_manager.h"
#include "engine/universe.h" #include "engine/universe.h"
#include "physics/physics_geometry.h" #include "physics/physics_geometry.h"

View file

@ -5,7 +5,6 @@
#include "engine/geometry.h" #include "engine/geometry.h"
#include "engine/math.h" #include "engine/math.h"
#include "engine/os.h" #include "engine/os.h"
#include "engine/reflection.h"
#include "engine/resource_manager.h" #include "engine/resource_manager.h"
#include "engine/universe.h" #include "engine/universe.h"
#include "renderer/model.h" #include "renderer/model.h"

View file

@ -9,7 +9,6 @@
#include "engine/engine.h" #include "engine/engine.h"
#include "engine/file_system.h" #include "engine/file_system.h"
#include "engine/log.h" #include "engine/log.h"
#include "engine/reflection.h"
#include "engine/string.h" #include "engine/string.h"
#include "engine/universe.h" #include "engine/universe.h"
#include "renderer/material.h" #include "renderer/material.h"

View file

@ -26,7 +26,6 @@
#include "engine/prefab.h" #include "engine/prefab.h"
#include "engine/profiler.h" #include "engine/profiler.h"
#include "engine/queue.h" #include "engine/queue.h"
#include "engine/reflection.h"
#include "engine/resource_manager.h" #include "engine/resource_manager.h"
#include "engine/universe.h" #include "engine/universe.h"
#include "fbx_importer.h" #include "fbx_importer.h"

View file

@ -17,7 +17,6 @@
#include "engine/path.h" #include "engine/path.h"
#include "engine/prefab.h" #include "engine/prefab.h"
#include "engine/profiler.h" #include "engine/profiler.h"
#include "engine/reflection.h"
#include "engine/resource_manager.h" #include "engine/resource_manager.h"
#include "engine/string.h" #include "engine/string.h"
#include "engine/universe.h" #include "engine/universe.h"

View file

@ -15,7 +15,6 @@
#include "engine/path.h" #include "engine/path.h"
#include "engine/prefab.h" #include "engine/prefab.h"
#include "engine/profiler.h" #include "engine/profiler.h"
#include "engine/reflection.h"
#include "engine/resource_manager.h" #include "engine/resource_manager.h"
#include "engine/universe.h" #include "engine/universe.h"
#include "physics/physics_scene.h" #include "physics/physics_scene.h"

View file

@ -7,7 +7,6 @@
#include "engine/log.h" #include "engine/log.h"
#include "engine/math.h" #include "engine/math.h"
#include "engine/profiler.h" #include "engine/profiler.h"
#include "engine/reflection.h"
#include "engine/resource_manager.h" #include "engine/resource_manager.h"
#include "engine/simd.h" #include "engine/simd.h"
#include "engine/stream.h" #include "engine/stream.h"

View file

@ -3694,6 +3694,7 @@ struct PipelineImpl final : Pipeline
if (!iter.value().enabled) continue; if (!iter.value().enabled) continue;
const Model* model = mi[e.index].model; const Model* model = mi[e.index].model;
if (!model) continue;
if (!model->isReady()) continue; if (!model->isReady()) continue;
for (i32 i = 0; i < model->getMeshCount(); ++i) { for (i32 i = 0; i < model->getMeshCount(); ++i) {

View file

@ -2781,97 +2781,85 @@ void RenderScene::reflect() {
} }
}; };
LUMIX_SCENE(RenderSceneImpl, "renderer", LUMIX_SCENE(RenderSceneImpl, "renderer")
LUMIX_FUNC(RenderScene::setGlobalLODMultiplier), .LUMIX_FUNC(RenderSceneImpl::setGlobalLODMultiplier)
LUMIX_FUNC(RenderScene::getGlobalLODMultiplier), .LUMIX_FUNC(RenderSceneImpl::getGlobalLODMultiplier)
LUMIX_FUNC(RenderScene::addDebugCross), .LUMIX_FUNC(RenderSceneImpl::addDebugCross)
LUMIX_FUNC(RenderScene::addDebugLine), .LUMIX_FUNC(RenderSceneImpl::addDebugLine)
LUMIX_FUNC(RenderScene::addDebugTriangle), .LUMIX_FUNC(RenderSceneImpl::addDebugTriangle)
LUMIX_CMP(BoneAttachment, "bone_attachment", "Render / Bone attachment", .LUMIX_CMP(BoneAttachment, "bone_attachment", "Render / Bone attachment")
icon(ICON_FA_BONE), .icon(ICON_FA_BONE)
LUMIX_PROP(BoneAttachmentParent, "Parent"), .LUMIX_PROP(BoneAttachmentParent, "Parent")
LUMIX_PROP(BoneAttachmentPosition, "Relative position"), .LUMIX_PROP(BoneAttachmentPosition, "Relative position")
LUMIX_PROP(BoneAttachmentRotation, "Relative rotation", RadiansAttribute()), .LUMIX_PROP(BoneAttachmentRotation, "Relative rotation").radiansAttribute()
LUMIX_PROP(BoneAttachmentBone, "Bone", BoneEnum()) .LUMIX_PROP(BoneAttachmentBone, "Bone").attribute<BoneEnum>()
), .LUMIX_CMP(Fur, "fur", "Render / Fur")
LUMIX_CMP(Fur, "fur", "Render / Fur", .var_prop<&RenderScene::getFur, &FurComponent::layers>("Layers")
var_property("Layers", &RenderScene::getFur, &FurComponent::layers), .var_prop<&RenderScene::getFur, &FurComponent::scale>("Scale")
var_property("Scale", &RenderScene::getFur, &FurComponent::scale), .var_prop<&RenderScene::getFur, &FurComponent::gravity>("Gravity")
var_property("Gravity", &RenderScene::getFur, &FurComponent::gravity), .var_prop<&RenderScene::getFur, &FurComponent::enabled>("Enabled")
var_property("Enabled", &RenderScene::getFur, &FurComponent::enabled) .LUMIX_CMP(EnvironmentProbe, "environment_probe", "Render / Environment probe")
), .prop<&RenderScene::isEnvironmentProbeEnabled, &RenderScene::enableEnvironmentProbe>("Enabled")
LUMIX_CMP(EnvironmentProbe, "environment_probe", "Render / Environment probe", .var_prop<&RenderScene::getEnvironmentProbe, &EnvironmentProbe::inner_range>("Inner range")
property("Enabled", &RenderScene::isEnvironmentProbeEnabled, &RenderScene::enableEnvironmentProbe), .var_prop<&RenderScene::getEnvironmentProbe, &EnvironmentProbe::outer_range>("Outer range")
var_property("Inner range", &RenderScene::getEnvironmentProbe, &EnvironmentProbe::inner_range), .LUMIX_CMP(ReflectionProbe, "reflection_probe", "Render / Reflection probe")
var_property("Outer range", &RenderScene::getEnvironmentProbe, &EnvironmentProbe::outer_range) .prop<&RenderScene::isReflectionProbeEnabled, &RenderScene::enableReflectionProbe>("Enabled")
), .var_prop<&RenderScene::getReflectionProbe, &ReflectionProbe::size>("size")
LUMIX_CMP(ReflectionProbe, "reflection_probe", "Render / Reflection probe", .var_prop<&RenderScene::getReflectionProbe, &ReflectionProbe::half_extents>("half_extents")
property("Enabled", &RenderScene::isReflectionProbeEnabled, &RenderScene::enableReflectionProbe), .LUMIX_CMP(ParticleEmitter, "particle_emitter", "Render / Particle emitter")
var_property("size", &RenderScene::getReflectionProbe, &ReflectionProbe::size), .LUMIX_PROP(ParticleEmitterRate, "Emit rate")
var_property("half_extents", &RenderScene::getReflectionProbe, &ReflectionProbe::half_extents) .LUMIX_PROP(ParticleEmitterPath, "Source").resourceAttribute(ParticleEmitterResource::TYPE)
), .LUMIX_CMP(Camera, "camera", "Render / Camera")
LUMIX_CMP(ParticleEmitter, "particle_emitter", "Render / Particle emitter", .icon(ICON_FA_CAMERA)
LUMIX_PROP(ParticleEmitterRate, "Emit rate"), .var_prop<&RenderScene::getCamera, &Camera::fov>("FOV").radiansAttribute()
LUMIX_PROP(ParticleEmitterPath, "Source", ResourceAttribute(ParticleEmitterResource::TYPE)) .var_prop<&RenderScene::getCamera, &Camera::near>("Near").minAttribute(0)
), .var_prop<&RenderScene::getCamera, &Camera::far>("Far").minAttribute(0)
LUMIX_CMP(Camera, "camera", "Render / Camera", .var_prop<&RenderScene::getCamera, &Camera::is_ortho>("Orthographic")
icon(ICON_FA_CAMERA), .var_prop<&RenderScene::getCamera, &Camera::ortho_size>("Orthographic size").minAttribute(0)
var_property("FOV", &RenderScene::getCamera, &Camera::fov, RadiansAttribute()), .LUMIX_CMP(ModelInstance, "model_instance", "Render / Mesh")
var_property("Near", &RenderScene::getCamera, &Camera::near, MinAttribute(0)), .LUMIX_FUNC_EX(RenderScene::getModelInstanceModel, "getModel")
var_property("Far", &RenderScene::getCamera, &Camera::far, MinAttribute(0)), .prop<&RenderScene::isModelInstanceEnabled, &RenderScene::enableModelInstance>("Enabled")
var_property("Orthographic", &RenderScene::getCamera, &Camera::is_ortho), .prop<&RenderScene::getModelInstanceMaterialOverride,&RenderScene::setModelInstanceMaterialOverride>("Material").noUIAttribute()
var_property("Orthographic size", &RenderScene::getCamera, &Camera::ortho_size, MinAttribute(0)) .LUMIX_PROP(ModelInstancePath, "Source").resourceAttribute(Model::TYPE)
), .LUMIX_CMP(Environment, "environment", "Render / Environment")
LUMIX_CMP(ModelInstance, "model_instance", "Render / Mesh", .icon(ICON_FA_GLOBE)
LUMIX_FUNC_EX(RenderScene::getModelInstanceModel, "getModel"), .var_prop<&RenderScene::getEnvironment, &Environment::light_color>("Color").colorAttribute()
property("Enabled", &RenderScene::isModelInstanceEnabled, &RenderScene::enableModelInstance), .var_prop<&RenderScene::getEnvironment, &Environment::direct_intensity>("Intensity").minAttribute(0)
property("Material", &RenderScene::getModelInstanceMaterialOverride,&RenderScene::setModelInstanceMaterialOverride, NoUIAttribute()), .var_prop<&RenderScene::getEnvironment, &Environment::indirect_intensity>("Indirect intensity").minAttribute(0)
LUMIX_PROP(ModelInstancePath, "Source", ResourceAttribute(Model::TYPE)) .LUMIX_PROP(ShadowmapCascades, "Shadow cascades")
), .LUMIX_PROP(EnvironmentCastShadows, "Cast shadows")
LUMIX_CMP(Environment, "environment", "Render / Environment", .LUMIX_CMP(PointLight, "point_light", "Render / Point light")
icon(ICON_FA_GLOBE), .icon(ICON_FA_LIGHTBULB)
var_property("Color", &RenderScene::getEnvironment, &Environment::light_color, ColorAttribute()), .LUMIX_PROP(PointLightCastShadows, "Cast shadows")
var_property("Intensity", &RenderScene::getEnvironment, &Environment::direct_intensity, MinAttribute(0)), .LUMIX_PROP(PointLightDynamic, "Dynamic")
var_property("Indirect intensity", &RenderScene::getEnvironment, &Environment::indirect_intensity, MinAttribute(0)), .var_prop<&RenderScene::getPointLight, &PointLight::intensity>("Intensity").minAttribute(0)
LUMIX_PROP(ShadowmapCascades, "Shadow cascades"), .var_prop<&RenderScene::getPointLight, &PointLight::fov>("FOV").clampAttribute(0, 360).radiansAttribute()
LUMIX_PROP(EnvironmentCastShadows, "Cast shadows") .var_prop<&RenderScene::getPointLight, &PointLight::attenuation_param>("Attenuation").clampAttribute(0, 100)
), .var_prop<&RenderScene::getPointLight, &PointLight::color>("Color").colorAttribute()
LUMIX_CMP(PointLight, "point_light", "Render / Point light", .LUMIX_PROP(LightRange, "Range").minAttribute(0)
icon(ICON_FA_LIGHTBULB), .LUMIX_CMP(Decal, "decal", "Render / Decal")
LUMIX_PROP(PointLightCastShadows, "Cast shadows"), .LUMIX_PROP(DecalMaterialPath, "Material").resourceAttribute(Material::TYPE)
LUMIX_PROP(PointLightDynamic, "Dynamic"), .LUMIX_PROP(DecalHalfExtents, "Half extents").minAttribute(0)
var_property("Intensity", &RenderScene::getPointLight, &PointLight::intensity, MinAttribute(0)), .var_prop<&RenderScene::getDecal, &Decal::uv_scale>("UV scale").minAttribute(0)
var_property("FOV", &RenderScene::getPointLight, &PointLight::fov, ClampAttribute(0, 360), RadiansAttribute()), .LUMIX_CMP(CurveDecal, "curve_decal", "Render / Curve decal")
var_property("Attenuation", &RenderScene::getPointLight, &PointLight::attenuation_param, ClampAttribute(0, 100)), .LUMIX_PROP(CurveDecalMaterialPath, "Material").resourceAttribute(Material::TYPE)
var_property("Color", &RenderScene::getPointLight, &PointLight::color, ColorAttribute()), .LUMIX_PROP(CurveDecalHalfExtents, "Half extents").minAttribute(0)
LUMIX_PROP(LightRange, "Range", MinAttribute(0)) .LUMIX_PROP(CurveDecalUVScale, "UV scale").minAttribute(0)
), .LUMIX_PROP(CurveDecalBezierP0, "Bezier P0").noUIAttribute()
LUMIX_CMP(Decal, "decal", "Render / Decal", .LUMIX_PROP(CurveDecalBezierP2, "Bezier P2").noUIAttribute()
LUMIX_PROP(DecalMaterialPath, "Material", ResourceAttribute(Material::TYPE)), .LUMIX_CMP(Terrain, "terrain", "Render / Terrain")
LUMIX_PROP(DecalHalfExtents, "Half extents", MinAttribute(0)), .LUMIX_FUNC(RenderScene::getTerrainNormalAt)
var_property("UV scale", &RenderScene::getDecal, &Decal::uv_scale, MinAttribute(0)) .LUMIX_FUNC(RenderScene::getTerrainHeightAt)
), .LUMIX_PROP(TerrainMaterialPath, "Material").resourceAttribute(Material::TYPE)
LUMIX_CMP(CurveDecal, "curve_decal", "Render / Curve decal", .LUMIX_PROP(TerrainXZScale, "XZ scale").minAttribute(0)
LUMIX_PROP(CurveDecalMaterialPath, "Material", ResourceAttribute(Material::TYPE)), .LUMIX_PROP(TerrainYScale, "Height scale").minAttribute(0)
LUMIX_PROP(CurveDecalHalfExtents, "Half extents", MinAttribute(0)), .begin_array<&RenderScene::getGrassCount, &RenderScene::addGrass, &RenderScene::removeGrass>("grass")
LUMIX_PROP(CurveDecalUVScale, "UV scale", MinAttribute(0)), .LUMIX_PROP(GrassPath, "Mesh").resourceAttribute(Model::TYPE)
LUMIX_PROP(CurveDecalBezierP0, "Bezier P0", NoUIAttribute()), .LUMIX_PROP(GrassDistance, "Distance").minAttribute(1)
LUMIX_PROP(CurveDecalBezierP2, "Bezier P2", NoUIAttribute()) .LUMIX_PROP(GrassSpacing, "Spacing")
), .LUMIX_PROP(GrassRotationMode, "Mode").attribute<RotationModeEnum>()
LUMIX_CMP(Terrain, "terrain", "Render / Terrain", .end_array()
LUMIX_FUNC(RenderScene::getTerrainNormalAt), ;
LUMIX_FUNC(RenderScene::getTerrainHeightAt),
LUMIX_PROP(TerrainMaterialPath, "Material", ResourceAttribute(Material::TYPE)),
LUMIX_PROP(TerrainXZScale, "XZ scale", MinAttribute(0)),
LUMIX_PROP(TerrainYScale, "Height scale", MinAttribute(0)),
array("grass", &RenderScene::getGrassCount, &RenderScene::addGrass, &RenderScene::removeGrass,
LUMIX_PROP(GrassPath, "Mesh", ResourceAttribute(Model::TYPE)),
LUMIX_PROP(GrassDistance, "Distance", MinAttribute(1)),
LUMIX_PROP(GrassSpacing, "Spacing"),
LUMIX_PROP(GrassRotationMode, "Mode", RotationModeEnum())
)
)
);
} }
RenderSceneImpl::RenderSceneImpl(Renderer& renderer, RenderSceneImpl::RenderSceneImpl(Renderer& renderer,

View file

@ -357,9 +357,9 @@ struct RendererImpl final : Renderer
{ {
RenderScene::reflect(); RenderScene::reflect();
LUMIX_FUNC(Model::getBoneCount); LUMIX_GLOBAL_FUNC(Model::getBoneCount);
LUMIX_FUNC(Model::getBoneName); LUMIX_GLOBAL_FUNC(Model::getBoneName);
LUMIX_FUNC(Model::getBoneParent); LUMIX_GLOBAL_FUNC(Model::getBoneParent);
m_shader_defines.reserve(32); m_shader_defines.reserve(32);

View file

@ -6,7 +6,6 @@
#include "engine/log.h" #include "engine/log.h"
#include "engine/math.h" #include "engine/math.h"
#include "engine/profiler.h" #include "engine/profiler.h"
#include "engine/reflection.h"
#include "engine/resource_manager.h" #include "engine/resource_manager.h"
#include "engine/stream.h" #include "engine/stream.h"
#include "renderer/material.h" #include "renderer/material.h"

View file

@ -1,16 +1,13 @@
#define NOGDI #include "engine/os.h"
#define WIN32_LEAN_AND_MEAN #include "engine/win/simple_win.h"
#include <Windows.h>
#include <Winuser.h>
#include <ShellScalingAPI.h>
#include "editor/studio_app.h" #include "editor/studio_app.h"
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
SetProcessDPIAware(); SetProcessDPIAware();
HMODULE shcore = LoadLibrary("shcore.dll"); void* shcore = Lumix::os::loadLibrary("shcore.dll");
if (shcore) { if (shcore) {
auto setter = (decltype(&SetProcessDpiAwareness))GetProcAddress(shcore, "SetProcessDpiAwareness"); auto setter = (decltype(&SetProcessDpiAwareness))Lumix::os::getLibrarySymbol(shcore, "SetProcessDpiAwareness");
if (setter) setter(PROCESS_PER_MONITOR_DPI_AWARE); if (setter) setter(PROCESS_PER_MONITOR_DPI_AWARE);
} }
@ -18,6 +15,6 @@ int main(int argc, char* argv[])
app->run(); app->run();
const int exit_code = app->getExitCode(); const int exit_code = app->getExitCode();
Lumix::StudioApp::destroy(*app); Lumix::StudioApp::destroy(*app);
if(shcore) FreeLibrary(shcore); if(shcore) Lumix::os::unloadLibrary(shcore);
return exit_code; return exit_code;
} }