feat: add new fancy reflection
This commit is contained in:
@@ -27,6 +27,7 @@ public:
|
||||
|
||||
std::string GetTypeName() const override { return "AudioSource"; }
|
||||
|
||||
void Reflect(FieldVisitor& v) override;
|
||||
nlohmann::json Serialize() const override;
|
||||
void Deserialize(const nlohmann::json& data) override;
|
||||
void ImGuiInspector() override;
|
||||
|
||||
@@ -17,8 +17,7 @@ public:
|
||||
|
||||
std::string GetTypeName() const override { return "CameraComponent"; }
|
||||
|
||||
nlohmann::json Serialize() const override;
|
||||
void Deserialize(const nlohmann::json& data) override;
|
||||
void Reflect(FieldVisitor& v) override;
|
||||
void ImGuiInspector() override;
|
||||
|
||||
// Places the camera at this object's world transform, looking down its local -Z.
|
||||
|
||||
@@ -19,9 +19,7 @@ public:
|
||||
|
||||
std::string GetTypeName() const override { return "LightComponent"; }
|
||||
|
||||
nlohmann::json Serialize() const override;
|
||||
void Deserialize(const nlohmann::json& data) override;
|
||||
void ImGuiInspector() override;
|
||||
void Reflect(FieldVisitor& v) override;
|
||||
|
||||
void SetType(LightType type) { m_Type = type; }
|
||||
[[nodiscard]] LightType GetType() const { return m_Type; }
|
||||
|
||||
@@ -26,9 +26,10 @@ public:
|
||||
|
||||
std::string GetTypeName() const override { return "OrbitAndSpin"; }
|
||||
|
||||
nlohmann::json Serialize() const override;
|
||||
void Reflect(FieldVisitor& v) override;
|
||||
void Deserialize(const nlohmann::json& data) override;
|
||||
void ImGuiInspector() override;
|
||||
void OnFieldsEdited() override;
|
||||
|
||||
// optional setters
|
||||
void SetRadius(float r) { m_Radius = r; }
|
||||
@@ -36,6 +37,7 @@ public:
|
||||
|
||||
private:
|
||||
void BuildOrbitBasis(); // builds m_U/m_V from m_OrbitAxis
|
||||
void Sanitize();
|
||||
|
||||
float m_Radius = 5.0f;
|
||||
glm::vec3 m_Center{0.0f};
|
||||
|
||||
@@ -11,16 +11,13 @@ public:
|
||||
|
||||
void Update(float) override {}
|
||||
|
||||
nlohmann::json Serialize() const override;
|
||||
void Deserialize(const nlohmann::json& data) override;
|
||||
void ImGuiInspector() override;
|
||||
void Reflect(FieldVisitor& v) override;
|
||||
|
||||
std::string GetTypeName() const override
|
||||
{
|
||||
return "BoxCollider";
|
||||
}
|
||||
|
||||
|
||||
void DrawDebugLines(const glm::vec4& color) const override;
|
||||
|
||||
[[nodiscard]] PhysicsShapeDesc BuildPhysicsShape() const override {
|
||||
|
||||
@@ -17,24 +17,7 @@ public:
|
||||
return "CapsuleCollider";
|
||||
}
|
||||
|
||||
void ImGuiInspector() override;
|
||||
|
||||
nlohmann::json Serialize() const override {
|
||||
auto data = SerializeCollider();
|
||||
data["radius"] = m_Radius;
|
||||
data["height"] = m_Height;
|
||||
return data;
|
||||
}
|
||||
|
||||
void Deserialize(const nlohmann::json& data) override {
|
||||
DeserializeCollider(data);
|
||||
if (data.contains("radius")) {
|
||||
SetRadius(data.at("radius").get<float>());
|
||||
}
|
||||
if (data.contains("height")) {
|
||||
SetHeight(data.at("height").get<float>());
|
||||
}
|
||||
}
|
||||
void Reflect(FieldVisitor& v) override;
|
||||
|
||||
void DrawDebugLines(const glm::vec4& color) const override;
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ public:
|
||||
|
||||
[[nodiscard]] bool AffectsPhysics() const override { return true; }
|
||||
|
||||
void ImGuiInspector() override;
|
||||
void Reflect(FieldVisitor& v) override;
|
||||
|
||||
[[nodiscard]] virtual PhysicsShapeDesc BuildPhysicsShape() const = 0;
|
||||
virtual void DrawDebugLines(const glm::vec4& color) const = 0;
|
||||
@@ -30,18 +30,6 @@ public:
|
||||
void SetCenterOffset(const glm::vec3& offset) { m_CenterOffset = offset; NotifyPhysicsChanged(); }
|
||||
|
||||
protected:
|
||||
[[nodiscard]] nlohmann::json SerializeCollider() const {
|
||||
return {
|
||||
{"centerOffset", m_CenterOffset},
|
||||
{"isTrigger", m_IsTrigger}
|
||||
};
|
||||
}
|
||||
|
||||
void DeserializeCollider(const nlohmann::json& data) {
|
||||
m_CenterOffset = data.value("centerOffset", m_CenterOffset);
|
||||
m_IsTrigger = data.value("isTrigger", m_IsTrigger);
|
||||
}
|
||||
|
||||
bool m_IsTrigger{false};
|
||||
glm::vec3 m_CenterOffset{0.0f};
|
||||
};
|
||||
|
||||
@@ -17,9 +17,7 @@ public:
|
||||
return "ConvexHullCollider";
|
||||
}
|
||||
|
||||
nlohmann::json Serialize() const override;
|
||||
void Deserialize(const nlohmann::json& data) override;
|
||||
void ImGuiInspector() override;
|
||||
void Reflect(FieldVisitor& v) override;
|
||||
|
||||
void DrawDebugLines(const glm::vec4& color) const override;
|
||||
|
||||
|
||||
@@ -17,24 +17,7 @@ public:
|
||||
return "CylinderCollider";
|
||||
}
|
||||
|
||||
void ImGuiInspector() override;
|
||||
|
||||
nlohmann::json Serialize() const override {
|
||||
auto data = SerializeCollider();
|
||||
data["radius"] = m_Radius;
|
||||
data["height"] = m_Height;
|
||||
return data;
|
||||
}
|
||||
|
||||
void Deserialize(const nlohmann::json& data) override {
|
||||
DeserializeCollider(data);
|
||||
if (data.contains("radius")) {
|
||||
SetRadius(data.at("radius").get<float>());
|
||||
}
|
||||
if (data.contains("height")) {
|
||||
SetHeight(data.at("height").get<float>());
|
||||
}
|
||||
}
|
||||
void Reflect(FieldVisitor& v) override;
|
||||
|
||||
void DrawDebugLines(const glm::vec4& color) const override;
|
||||
|
||||
|
||||
@@ -14,14 +14,6 @@ public:
|
||||
return "MeshCollider";
|
||||
}
|
||||
|
||||
nlohmann::json Serialize() const override {
|
||||
return SerializeCollider();
|
||||
}
|
||||
|
||||
void Deserialize(const nlohmann::json& data) override {
|
||||
DeserializeCollider(data);
|
||||
}
|
||||
|
||||
void ImGuiInspector() override;
|
||||
|
||||
void DrawDebugLines(const glm::vec4& color) const override;
|
||||
|
||||
@@ -21,8 +21,7 @@ public:
|
||||
void Start() override;
|
||||
void Destroy() override;
|
||||
|
||||
nlohmann::json Serialize() const override;
|
||||
void Deserialize(const nlohmann::json& data) override;
|
||||
void Reflect(FieldVisitor& v) override;
|
||||
void ImGuiInspector() override;
|
||||
|
||||
std::string GetTypeName() const override
|
||||
|
||||
@@ -12,9 +12,7 @@ public:
|
||||
|
||||
void Update(float) override {}
|
||||
|
||||
nlohmann::json Serialize() const override;
|
||||
void Deserialize(const nlohmann::json& data) override;
|
||||
void ImGuiInspector() override;
|
||||
void Reflect(FieldVisitor& v) override;
|
||||
std::string GetTypeName() const override
|
||||
{
|
||||
return "SphereCollider";
|
||||
|
||||
@@ -20,9 +20,7 @@ public:
|
||||
|
||||
std::string GetTypeName() const override { return "Rotator"; }
|
||||
|
||||
nlohmann::json Serialize() const override;
|
||||
void Deserialize(const nlohmann::json& data) override;
|
||||
void ImGuiInspector() override;
|
||||
void Reflect(FieldVisitor& v) override;
|
||||
|
||||
void SetDistance(float distance);
|
||||
void SetSpeed(float speed) { m_Speed = speed; }
|
||||
|
||||
@@ -18,9 +18,7 @@ public:
|
||||
|
||||
std::string GetTypeName() const override { return "Spinner"; }
|
||||
|
||||
nlohmann::json Serialize() const override;
|
||||
void Deserialize(const nlohmann::json& data) override;
|
||||
void ImGuiInspector() override;
|
||||
void Reflect(FieldVisitor& v) override;
|
||||
|
||||
void SetAxis(const glm::vec3& axis) {
|
||||
m_Axis = glm::dot(axis, axis) > 0.000001f
|
||||
|
||||
@@ -23,9 +23,7 @@ public:
|
||||
void Render(const RenderContext& ctx) override;
|
||||
void Draw(const glm::vec2& screenSize);
|
||||
|
||||
nlohmann::json Serialize() const override;
|
||||
void Deserialize(const nlohmann::json& data) override;
|
||||
void ImGuiInspector() override;
|
||||
void Reflect(FieldVisitor& v) override;
|
||||
|
||||
[[nodiscard]] float GetScale(const glm::vec2& screenSize) const;
|
||||
|
||||
|
||||
@@ -22,8 +22,7 @@ public:
|
||||
|
||||
std::string GetTypeName() const override { return "RectTransform"; }
|
||||
|
||||
nlohmann::json Serialize() const override;
|
||||
void Deserialize(const nlohmann::json& data) override;
|
||||
void Reflect(FieldVisitor& v) override;
|
||||
void ImGuiInspector() override;
|
||||
|
||||
[[nodiscard]] UIRect ComputeRect(const UIRect& parentRect, float scale) const;
|
||||
|
||||
@@ -20,9 +20,7 @@ public:
|
||||
|
||||
void DrawUI(const UIRect& rect, float scale) override;
|
||||
|
||||
nlohmann::json Serialize() const override;
|
||||
void Deserialize(const nlohmann::json& data) override;
|
||||
void ImGuiInspector() override;
|
||||
void Reflect(FieldVisitor& v) override;
|
||||
|
||||
void SetShape(UIImageShape shape) { m_Shape = shape; }
|
||||
void SetOutline(float thickness) { m_Outline = thickness; }
|
||||
|
||||
@@ -21,9 +21,7 @@ public:
|
||||
|
||||
void DrawUI(const UIRect& rect, float scale) override;
|
||||
|
||||
nlohmann::json Serialize() const override;
|
||||
void Deserialize(const nlohmann::json& data) override;
|
||||
void ImGuiInspector() override;
|
||||
void Reflect(FieldVisitor& v) override;
|
||||
|
||||
void SetText(std::string text) { m_Text = std::move(text); }
|
||||
void SetFont(std::string assetPath) { m_FontPath = std::move(assetPath); }
|
||||
|
||||
@@ -29,10 +29,14 @@ struct FieldOptions {
|
||||
std::optional<double> max;
|
||||
const char* format = nullptr;
|
||||
bool color = false;
|
||||
bool angle = false; // radians, shown in degrees
|
||||
bool multiline = false;
|
||||
bool acceptAssets = false; // strings take a virtual path dropped from the asset browser
|
||||
bool readOnly = false;
|
||||
bool hidden = false;
|
||||
bool transient = false;
|
||||
bool hidden = false; // saved, not shown
|
||||
bool transient = false; // shown, not saved
|
||||
const char* label = nullptr;
|
||||
const char* tooltip = nullptr;
|
||||
std::span<const char* const> enumNames;
|
||||
std::function<bool(const GameObject&)> filter;
|
||||
};
|
||||
@@ -66,6 +70,7 @@ namespace reflect_detail {
|
||||
}
|
||||
|
||||
bool DrawScalar(const char* label, Scalar type, void* value, int components, const void* min, const void* max, const FieldOptions& options);
|
||||
bool DrawAngle(const char* label, float& radians, const FieldOptions& options);
|
||||
bool DrawEnum(const char* label, std::int64_t& value, const FieldOptions& options);
|
||||
|
||||
void BeginList(const char* label);
|
||||
@@ -77,6 +82,9 @@ namespace reflect_detail {
|
||||
|
||||
template <class T>
|
||||
concept Numeric = std::is_arithmetic_v<T> && !std::same_as<T, bool>;
|
||||
|
||||
template <class T>
|
||||
concept FloatVec = std::same_as<T, glm::vec2> || std::same_as<T, glm::vec3> || std::same_as<T, glm::vec4>;
|
||||
}
|
||||
|
||||
bool DrawField(const char* label, bool& value, const FieldOptions& options, const Scene* scene);
|
||||
@@ -90,6 +98,11 @@ bool DrawField(const char* label, std::vector<ObjectRef>& value, const FieldOpti
|
||||
template <reflect_detail::Numeric T>
|
||||
bool DrawField(const char* label, T& value, const FieldOptions& options, const Scene*)
|
||||
{
|
||||
if constexpr (std::same_as<T, float>) {
|
||||
if (options.angle) {
|
||||
return reflect_detail::DrawAngle(label, value, options);
|
||||
}
|
||||
}
|
||||
const T min = options.min ? static_cast<T>(*options.min) : T{};
|
||||
const T max = options.max ? static_cast<T>(*options.max) : T{};
|
||||
return reflect_detail::DrawScalar(label, reflect_detail::ScalarOf<T>(), &value, 1,
|
||||
@@ -181,6 +194,9 @@ struct FieldCodec {
|
||||
if constexpr (reflect_detail::Numeric<T>) {
|
||||
if (options.min && typed < static_cast<T>(*options.min)) typed = static_cast<T>(*options.min);
|
||||
if (options.max && typed > static_cast<T>(*options.max)) typed = static_cast<T>(*options.max);
|
||||
} else if constexpr (reflect_detail::FloatVec<T>) {
|
||||
if (options.min) typed = glm::max(typed, T{static_cast<float>(*options.min)});
|
||||
if (options.max) typed = glm::min(typed, T{static_cast<float>(*options.max)});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,14 +219,26 @@ class FieldVisitor {
|
||||
public:
|
||||
virtual ~FieldVisitor() = default;
|
||||
|
||||
using Commit = std::function<void(void* value)>;
|
||||
|
||||
template <Reflectable T>
|
||||
void Field(std::string_view key, T& value, const FieldOptions& options = {})
|
||||
{
|
||||
Visit(key, &value, options, FieldCodec<T>::Ops);
|
||||
Visit(key, &value, options, FieldCodec<T>::Ops, {});
|
||||
}
|
||||
|
||||
// Loads and edits go through the setter, so it can validate and react
|
||||
template <Reflectable T, std::invocable<const T&> Setter>
|
||||
void Property(std::string_view key, const T& value, Setter&& setter, const FieldOptions& options = {})
|
||||
{
|
||||
T copy = value;
|
||||
Visit(key, ©, options, FieldCodec<T>::Ops, [&setter](void* changed) {
|
||||
setter(*static_cast<const T*>(changed));
|
||||
});
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void Visit(std::string_view key, void* value, const FieldOptions& options, const FieldOps& ops) = 0;
|
||||
virtual void Visit(std::string_view key, void* value, const FieldOptions& options, const FieldOps& ops, const Commit& commit) = 0;
|
||||
};
|
||||
|
||||
class JsonWriter final : public FieldVisitor {
|
||||
@@ -218,7 +246,7 @@ public:
|
||||
[[nodiscard]] nlohmann::json& Result() { return m_Result; }
|
||||
|
||||
protected:
|
||||
void Visit(std::string_view key, void* value, const FieldOptions& options, const FieldOps& ops) override;
|
||||
void Visit(std::string_view key, void* value, const FieldOptions& options, const FieldOps& ops, const Commit& commit) override;
|
||||
|
||||
private:
|
||||
nlohmann::json m_Result = nlohmann::json::object();
|
||||
@@ -229,7 +257,7 @@ public:
|
||||
explicit JsonReader(const nlohmann::json& data) : m_Data(data) {}
|
||||
|
||||
protected:
|
||||
void Visit(std::string_view key, void* value, const FieldOptions& options, const FieldOps& ops) override;
|
||||
void Visit(std::string_view key, void* value, const FieldOptions& options, const FieldOps& ops, const Commit& commit) override;
|
||||
|
||||
private:
|
||||
const nlohmann::json& m_Data;
|
||||
@@ -240,7 +268,7 @@ public:
|
||||
ReferenceResolver(const Component& owner, const ObjectRef::ObjectMap& objects) : m_Owner(owner), m_Objects(objects) {}
|
||||
|
||||
protected:
|
||||
void Visit(std::string_view key, void* value, const FieldOptions& options, const FieldOps& ops) override;
|
||||
void Visit(std::string_view key, void* value, const FieldOptions& options, const FieldOps& ops, const Commit& commit) override;
|
||||
|
||||
private:
|
||||
const Component& m_Owner;
|
||||
@@ -254,7 +282,7 @@ public:
|
||||
[[nodiscard]] bool Changed() const { return m_Changed; }
|
||||
|
||||
protected:
|
||||
void Visit(std::string_view key, void* value, const FieldOptions& options, const FieldOps& ops) override;
|
||||
void Visit(std::string_view key, void* value, const FieldOptions& options, const FieldOps& ops, const Commit& commit) override;
|
||||
|
||||
private:
|
||||
const Scene* m_Scene;
|
||||
|
||||
Reference in New Issue
Block a user