Files
FlaxEngine/Source/Engine/Level/Actors/BoxBrush.cpp
2023-01-10 15:29:37 +01:00

313 lines
7.4 KiB
C++

// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
#include "BoxBrush.h"
#include "Engine/Core/Math/Matrix.h"
#include "Engine/Content/Content.h"
#include "Engine/Serialization/Serialization.h"
#include "Engine/Level/Scene/Scene.h"
void BrushSurface::Serialize(SerializeStream& stream, const void* otherObj)
{
SERIALIZE_GET_OTHER_OBJ(BrushSurface);
SERIALIZE(Material);
SERIALIZE_MEMBER(Offset, TexCoordOffset);
SERIALIZE_MEMBER(Scale, TexCoordScale);
SERIALIZE_MEMBER(Rotation, TexCoordRotation);
SERIALIZE_MEMBER(ScaleInLightmap, ScaleInLightmap);
}
void BrushSurface::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier)
{
DESERIALIZE(Material);
DESERIALIZE_MEMBER(Offset, TexCoordOffset);
DESERIALIZE_MEMBER(Scale, TexCoordScale);
DESERIALIZE_MEMBER(Rotation, TexCoordRotation);
DESERIALIZE_MEMBER(ScaleInLightmap, ScaleInLightmap);
}
BoxBrush::BoxBrush(const SpawnParams& params)
: Actor(params)
, _center(Vector3::Zero)
, _size(100.0f)
, _mode(CSG::Mode::Additive)
{
for (uint32 i = 0; i < ARRAY_COUNT(Surfaces); i++)
{
auto& surface = Surfaces[i];
surface.Brush = this;
surface.Index = i;
}
}
Array<BrushSurface> BoxBrush::GetSurfaces() const
{
Array<BrushSurface> value;
value.Set(Surfaces, ARRAY_COUNT(Surfaces));
return value;
}
void BoxBrush::SetSurfaces(const Array<BrushSurface>& value)
{
CHECK(value.Count() == ARRAY_COUNT(Surfaces));
Platform::MemoryCopy(Surfaces, value.Get(), sizeof(Surfaces));
OnBrushModified();
}
void BoxBrush::SetMode(BrushMode value)
{
if (_mode != value)
{
_mode = value;
OnBrushModified();
}
}
void BoxBrush::SetCenter(const Vector3& value)
{
if (Vector3::NearEqual(value, _center))
return;
_center = value;
// Fire events
UpdateBounds();
OnBrushModified();
}
void BoxBrush::SetSize(const Vector3& value)
{
if (Vector3::NearEqual(value, _size))
return;
_size = value;
// Fire events
UpdateBounds();
OnBrushModified();
}
void BoxBrush::GetSurfaces(CSG::Surface surfaces[6])
{
// Init normals
surfaces[0].Normal = Vector3::Right;
surfaces[1].Normal = Vector3::Left;
surfaces[2].Normal = Vector3::Up;
surfaces[3].Normal = Vector3::Down;
surfaces[4].Normal = Vector3::Forward;
surfaces[5].Normal = Vector3::Backward;
// Calculate final transformation
const auto transform = _transform.LocalToWorld(Transform(_center, Quaternion::Identity, _size));
// Set size and scale
surfaces[0].D = surfaces[1].D = transform.Scale.X / 2;
surfaces[2].D = surfaces[3].D = transform.Scale.Y / 2;
surfaces[4].D = surfaces[5].D = transform.Scale.Z / 2;
// Add rotation
Matrix rotation;
Matrix::RotationQuaternion(transform.Orientation, rotation);
for (int32 i = 0; i < 6; i++)
Vector3::TransformNormal(surfaces[i].Normal, rotation, surfaces[i].Normal);
// Add translation
for (int32 i = 0; i < 6; i++)
surfaces[i].Translate(transform.Translation);
// Copy per surface properties
for (int32 i = 0; i < 6; i++)
{
auto& dst = surfaces[i];
auto& src = Surfaces[i];
dst.Material = src.Material.GetID();
dst.TexCoordScale = src.TexCoordScale;
dst.TexCoordOffset = src.TexCoordOffset;
dst.TexCoordRotation = src.TexCoordRotation;
dst.ScaleInLightmap = src.ScaleInLightmap;
}
}
void BoxBrush::SetMaterial(int32 surfaceIndex, MaterialBase* material)
{
CHECK(Math::IsInRange(surfaceIndex, 0, 5));
Surfaces[surfaceIndex].Material = material;
OnBrushModified();
}
bool BoxBrush::Intersects(int32 surfaceIndex, const Ray& ray, Real& distance, Vector3& normal) const
{
distance = MAX_Real;
normal = Vector3::Up;
auto scene = GetScene();
CHECK_RETURN(scene, false);
// Get surface data handle
CSG::SceneCSGData::SurfaceData surfaceData;
if (scene->CSGData.TryGetSurfaceData(GetBrushID(), surfaceIndex, surfaceData))
{
return surfaceData.Intersects(ray, distance, normal);
}
return false;
}
void BoxBrush::GetVertices(int32 surfaceIndex, Array<Vector3>& outputData) const
{
auto scene = GetScene();
CHECK(scene);
CSG::SceneCSGData::SurfaceData surfaceData;
if (scene->CSGData.TryGetSurfaceData(GetBrushID(), surfaceIndex, surfaceData))
{
outputData.Add((Vector3*)surfaceData.Triangles.Get(), 3 * surfaceData.Triangles.Count());
}
}
void BoxBrush::Serialize(SerializeStream& stream, const void* otherObj)
{
// Base
Actor::Serialize(stream, otherObj);
SERIALIZE_GET_OTHER_OBJ(BoxBrush);
SERIALIZE_MEMBER(Mode, _mode);
SERIALIZE_MEMBER(Center, _center);
SERIALIZE_MEMBER(Size, _size);
SERIALIZE(ScaleInLightmap);
stream.JKEY("Surfaces");
stream.StartArray();
for (int32 i = 0; i < 6; i++)
{
stream.Object(&Surfaces[i], other ? &other->Surfaces[i] : nullptr);
}
stream.EndArray();
}
void BoxBrush::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier)
{
// Base
Actor::Deserialize(stream, modifier);
DESERIALIZE_MEMBER(Mode, _mode);
DESERIALIZE_MEMBER(Center, _center);
DESERIALIZE_MEMBER(Size, _size);
DESERIALIZE(ScaleInLightmap);
const DeserializeStream& surfaces = stream["Surfaces"];
ASSERT(surfaces.IsArray() && surfaces.Size() == ARRAY_COUNT(Surfaces));
for (rapidjson::SizeType i = 0; i < surfaces.Size(); i++)
{
Surfaces[i].Deserialize((DeserializeStream&)surfaces[i], modifier);
}
}
bool BoxBrush::IntersectsItself(const Ray& ray, Real& distance, Vector3& normal)
{
bool result = false;
Real minDistance = MAX_float;
Vector3 minDistanceNormal = Vector3::Up;
if (_bounds.Intersects(ray, distance))
{
for (int32 surfaceIndex = 0; surfaceIndex < 6; surfaceIndex++)
{
if (Intersects(surfaceIndex, ray, distance, normal) && distance < minDistance)
{
minDistance = distance;
minDistanceNormal = normal;
result = true;
}
}
}
distance = minDistance;
normal = minDistanceNormal;
return result;
}
#if USE_EDITOR
#include "Engine/Debug/DebugDraw.h"
void BoxBrush::OnDebugDrawSelected()
{
DEBUG_DRAW_WIRE_BOX(_bounds, Color::Yellow, 0, false);
// Base
Actor::OnDebugDrawSelected();
}
#endif
Scene* BoxBrush::GetBrushScene() const
{
return GetScene();
}
Guid BoxBrush::GetBrushID() const
{
return GetID();
}
bool BoxBrush::CanUseCSG() const
{
return IsActiveInHierarchy();
}
CSG::Mode BoxBrush::GetBrushMode() const
{
return _mode;
}
void BoxBrush::GetSurfaces(Array<CSG::Surface>& surfaces)
{
surfaces.Clear();
surfaces.Resize(6, false);
GetSurfaces(surfaces.Get());
}
int32 BoxBrush::GetSurfacesCount()
{
return 6;
}
void BoxBrush::OnTransformChanged()
{
// Base
Actor::OnTransformChanged();
// Fire events
UpdateBounds();
OnBrushModified();
}
void BoxBrush::OnActiveInTreeChanged()
{
// Base
Actor::OnActiveInTreeChanged();
// Fire event
OnBrushModified();
}
void BoxBrush::OnOrderInParentChanged()
{
// Base
Actor::OnOrderInParentChanged();
// Fire event
OnBrushModified();
}
void BoxBrush::OnParentChanged()
{
// Base
Actor::OnParentChanged();
if (!IsDuringPlay())
return;
// Fire event
OnBrushModified();
}