// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. #pragma once #include "../Actor.h" #include "Engine/Core/Math/OrientedBoundingBox.h" #include "Engine/Content/Assets/MaterialBase.h" #include "Engine/CSG/Brush.h" /// /// Represents a part of the CSG brush actor. Contains information about single surface. /// API_STRUCT() struct BrushSurface : ISerializable { DECLARE_SCRIPTING_TYPE_NO_SPAWN(BrushSurface); /// /// The parent brush. /// API_FIELD(Attributes="HideInEditor") BoxBrush* Brush = nullptr; /// /// The surface index in the parent brush surfaces list. /// API_FIELD(Attributes="HideInEditor") int32 Index = -1; /// /// The material used to render the brush surface. /// API_FIELD(Attributes="EditorOrder(10), EditorDisplay(\"Brush\")") AssetReference Material; /// /// The surface texture coordinates scale. /// API_FIELD(Attributes="EditorOrder(30), EditorDisplay(\"Brush\", \"UV Scale\"), Limit(-1000, 1000, 0.01f)") Float2 TexCoordScale = Float2::One; /// /// The surface texture coordinates offset. /// API_FIELD(Attributes="EditorOrder(40), EditorDisplay(\"Brush\", \"UV Offset\"), Limit(-1000, 1000, 0.01f)") Float2 TexCoordOffset = Float2::Zero; /// /// The surface texture coordinates rotation angle (in degrees). /// API_FIELD(Attributes="EditorOrder(50), EditorDisplay(\"Brush\", \"UV Rotation\")") float TexCoordRotation = 0.0f; /// /// The scale in lightmap (per surface). /// API_FIELD(Attributes="EditorOrder(20), EditorDisplay(\"Brush\", \"Scale In Lightmap\"), Limit(0, 10000, 0.1f)") float ScaleInLightmap = 1.0f; public: // [ISerializable] void Serialize(SerializeStream& stream, const void* otherObj) override; void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override; }; /// /// Performs CSG box brush operation that adds or removes geometry. /// API_CLASS(Attributes="ActorContextMenu(\"New/Other/Box Brush\"), ActorToolbox(\"Other\", \"CSG Box Brush\")") class FLAXENGINE_API BoxBrush : public Actor, public CSG::Brush { DECLARE_SCENE_OBJECT(BoxBrush); private: Vector3 _center; Vector3 _size; OrientedBoundingBox _bounds; BrushMode _mode; public: /// /// Brush surfaces scale in lightmap /// API_FIELD(Attributes="EditorOrder(30), DefaultValue(1.0f), EditorDisplay(\"CSG\", \"Scale In Lightmap\"), Limit(0, 1000.0f, 0.1f)") float ScaleInLightmap = 1.0f; /// /// Brush proxy per surface /// BrushSurface Surfaces[6]; /// /// Gets the brush proxies per surface. /// API_PROPERTY(Attributes="Serialize, EditorOrder(100), EditorDisplay(\"Surfaces\", EditorDisplayAttribute.InlineStyle), Collection(CanReorderItems = false, NotNullItems = true, ReadOnly = true)") Array GetSurfaces() const; /// /// Sets the brush proxies per surface. /// API_PROPERTY() void SetSurfaces(const Array& value); /// /// Gets the CSG brush mode. /// API_PROPERTY(Attributes="EditorOrder(10), DefaultValue(BrushMode.Additive), EditorDisplay(\"CSG\")") FORCE_INLINE BrushMode GetMode() const { return _mode; } /// /// Sets the CSG brush mode. /// /// The value. API_PROPERTY() void SetMode(BrushMode value); /// /// Gets the brush center (in local space). /// /// The value. API_PROPERTY(Attributes="EditorOrder(21), DefaultValue(typeof(Vector3), \"0,0,0\"), EditorDisplay(\"CSG\")") FORCE_INLINE Vector3 GetCenter() const { return _center; } /// /// Sets the brush center (in local space). /// /// The value. API_PROPERTY() void SetCenter(const Vector3& value); /// /// Gets the brush size. /// /// The value. API_PROPERTY(Attributes="EditorOrder(20), EditorDisplay(\"CSG\")") FORCE_INLINE Vector3 GetSize() const { return _size; } /// /// Sets the brush size. /// /// The value. API_PROPERTY() void SetSize(const Vector3& value); /// /// Gets CSG surfaces /// /// Surfaces void GetSurfaces(CSG::Surface surfaces[6]); /// /// Sets the brush surface material. /// /// The brush surface index. /// The material. API_FUNCTION() void SetMaterial(int32 surfaceIndex, MaterialBase* material); public: /// /// Gets the volume bounding box (oriented). /// API_PROPERTY() FORCE_INLINE OrientedBoundingBox GetOrientedBox() const { return _bounds; } /// /// Determines if there is an intersection between the brush surface and a ray. /// If collision data is available on the CPU performs exact intersection check with the geometry. /// Otherwise performs simple vs test. /// For more efficient collisions detection and ray casting use physics. /// /// The brush surface index. /// The ray to test. /// When the method completes and returns true, contains the distance of the intersection (if any valid). /// When the method completes, contains the intersection surface normal vector (if any valid). /// True if the actor is intersected by the ray, otherwise false. API_FUNCTION() bool Intersects(int32 surfaceIndex, API_PARAM(Ref) const Ray& ray, API_PARAM(Out) Real& distance, API_PARAM(Out) Vector3& normal) const; /// /// Gets the brush surface triangles array (group by 3 vertices). /// /// The brush surface index. /// The output vertices buffer with triangles or empty if no data loaded. API_FUNCTION() void GetVertices(int32 surfaceIndex, API_PARAM(Out) Array& outputData) const; private: FORCE_INLINE void UpdateBounds() { OrientedBoundingBox::CreateCentered(_center, _size, _bounds); _bounds.Transform(_transform); _bounds.GetBoundingBox(_box); BoundingSphere::FromBox(_box, _sphere); } public: // [Actor] void Serialize(SerializeStream& stream, const void* otherObj) override; void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override; bool IntersectsItself(const Ray& ray, Real& distance, Vector3& normal) override; #if USE_EDITOR void OnDebugDrawSelected() override; #endif // [CSG::Brush] Scene* GetBrushScene() const override; Guid GetBrushID() const override; bool CanUseCSG() const override; CSG::Mode GetBrushMode() const override; void GetSurfaces(Array& surfaces) override; int32 GetSurfacesCount() override; protected: // [Actor] void OnTransformChanged() override; void OnActiveInTreeChanged() override; void OnOrderInParentChanged() override; void OnParentChanged() override; };