Files
FlaxEngine/Source/Engine/Level/Scene/SceneCSGData.cpp

169 lines
4.3 KiB
C++

// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
#include "SceneCSGData.h"
#include "Engine/Core/Log.h"
#include "Engine/CSG/CSGBuilder.h"
#include "Engine/Serialization/Serialization.h"
#include "Engine/Level/Scene/Scene.h"
#include "Engine/Serialization/MemoryReadStream.h"
#include "Engine/Content/Assets/Model.h"
#include "Engine/Content/Assets/RawDataAsset.h"
#include "Engine/Content/AssetReference.h"
#include "Engine/Physics/CollisionData.h"
using namespace CSG;
void Brush::OnBrushModified()
{
#if COMPILE_WITH_CSG_BUILDER
const auto scene = GetBrushScene();
if (scene && scene->IsDuringPlay())
{
Builder::OnBrushModified(this);
}
#endif
}
SceneCSGData::SceneCSGData(Scene* scene)
: _scene(scene)
, BuildTime(0)
{
Data.Loaded.Bind<SceneCSGData, &SceneCSGData::OnDataChanged>(this);
Data.Changed.Bind<SceneCSGData, &SceneCSGData::OnDataChanged>(this);
}
void SceneCSGData::BuildCSG(float timeoutMs) const
{
#if COMPILE_WITH_CSG_BUILDER
Builder::Build(_scene, timeoutMs);
#endif
}
bool SceneCSGData::HasData() const
{
return Model && Data;
}
bool SceneCSGData::SurfaceData::Intersects(const Ray& ray, Real& distance, Vector3& normal)
{
bool result = false;
Real minDistance = MAX_Real;
Vector3 minDistanceNormal = Vector3::Up;
for (int32 i = 0; i < Triangles.Count(); i++)
{
auto& e = Triangles[i];
if (CollisionsHelper::RayIntersectsTriangle(ray, e.V0, e.V1, e.V2, distance, normal) && distance < minDistance)
{
minDistance = distance;
minDistanceNormal = normal;
result = true;
}
}
distance = minDistance;
normal = minDistanceNormal;
return result;
}
bool SceneCSGData::TryGetSurfaceData(const Guid& brushId, int32 brushSurfaceIndex, SurfaceData& outData)
{
if (Data == nullptr || !Data->IsLoaded() || Data->Data.IsEmpty())
{
// Missing data or not loaded
return false;
}
MemoryReadStream stream(Data->Data);
// Check if has missing cache
if (DataBrushLocations.IsEmpty())
{
int32 version;
stream.ReadInt32(&version);
if (version == 1)
{
int32 brushesCount;
stream.ReadInt32(&brushesCount);
if (brushesCount < 0)
{
// Invalid data
return false;
}
DataBrushLocations.EnsureCapacity((int32)(brushesCount * 4.0f));
for (int32 i = 0; i < brushesCount; i++)
{
Guid id;
int32 pos;
stream.Read(&id);
stream.ReadInt32(&pos);
DataBrushLocations.Add(id, pos);
}
}
else
{
// Unknown version
LOG(Warning, "Unknwon version for scene CSG surface data (or corrupted file).");
return false;
}
}
// Find brush data
int32 brushLocation;
if (!DataBrushLocations.TryGet(brushId, brushLocation))
{
// Brush not found
return false;
}
stream.SetPosition(brushLocation);
// Skip leading surfaces data
int32 trianglesCount;
while (brushSurfaceIndex-- > 0)
{
stream.ReadInt32(&trianglesCount);
if (trianglesCount < 0 || trianglesCount > 100)
{
// Invalid data
return false;
}
stream.Move(trianglesCount * sizeof(Float3) * 3);
}
// Read surface data
stream.ReadInt32(&trianglesCount);
if (trianglesCount < 0 || trianglesCount > 100)
{
// Invalid data
return false;
}
outData.Triangles.Clear();
outData.Triangles.Resize(trianglesCount);
Float3* src = stream.Move<Float3>(trianglesCount * 3);
Vector3* dst = (Vector3*)outData.Triangles.Get();
for (int32 i = 0; i < trianglesCount * 3; i++)
*dst++ = *src++;
return true;
}
void SceneCSGData::OnDataChanged()
{
// Clear cache
DataBrushLocations.Clear();
}
void SceneCSGData::Serialize(SerializeStream& stream, const void* otherObj)
{
SERIALIZE_GET_OTHER_OBJ(SceneCSGData);
SERIALIZE(Model);
SERIALIZE(Data);
SERIALIZE(CollisionData);
}
void SceneCSGData::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier)
{
DESERIALIZE(Model);
DESERIALIZE(Data);
DESERIALIZE(CollisionData);
}