diff --git a/Source/Editor/Tools/Terrain/TerrainTools.cpp b/Source/Editor/Tools/Terrain/TerrainTools.cpp index 89d0aa17d..ba1da6638 100644 --- a/Source/Editor/Tools/Terrain/TerrainTools.cpp +++ b/Source/Editor/Tools/Terrain/TerrainTools.cpp @@ -20,7 +20,7 @@ bool TerrainTools::TryGetPatchCoordToAdd(Terrain* terrain, const Ray& ray, Int2& { CHECK_RETURN(terrain, true); result = Int2::Zero; - const float patchSize = terrain->GetChunkSize() * TERRAIN_UNITS_PER_VERTEX * TerrainPatch::CHUNKS_COUNT_EDGE; + const float patchSize = terrain->GetChunkSize() * TERRAIN_UNITS_PER_VERTEX * Terrain::ChunksCountEdge; // Try to pick any of the patch edges for (int32 patchIndex = 0; patchIndex < terrain->GetPatchesCount(); patchIndex++) @@ -179,7 +179,7 @@ bool TerrainTools::GenerateTerrain(Terrain* terrain, const Int2& numberOfPatches terrain->AddPatches(numberOfPatches); // Prepare data - const auto heightmapSize = terrain->GetChunkSize() * TerrainPatch::CHUNKS_COUNT_EDGE + 1; + const auto heightmapSize = terrain->GetChunkSize() * Terrain::ChunksCountEdge + 1; Array heightmapData; heightmapData.Resize(heightmapSize * heightmapSize); @@ -380,7 +380,7 @@ bool TerrainTools::ExportTerrain(Terrain* terrain, String outputFolder) const auto firstPatch = terrain->GetPatch(0); // Calculate texture size - const int32 patchEdgeVertexCount = terrain->GetChunkSize() * TerrainPatch::CHUNKS_COUNT_EDGE + 1; + const int32 patchEdgeVertexCount = terrain->GetChunkSize() * Terrain::ChunksCountEdge + 1; const int32 patchVertexCount = patchEdgeVertexCount * patchEdgeVertexCount; // Find size of heightmap in patches diff --git a/Source/Engine/ShadowsOfMordor/Builder.Entries.cpp b/Source/Engine/ShadowsOfMordor/Builder.Entries.cpp index ed6ecbf9c..67af59585 100644 --- a/Source/Engine/ShadowsOfMordor/Builder.Entries.cpp +++ b/Source/Engine/ShadowsOfMordor/Builder.Entries.cpp @@ -84,7 +84,7 @@ bool cacheStaticGeometryTree(Actor* actor, ShadowsOfMordor::Builder::SceneBuildC { auto patch = terrain->GetPatch(patchIndex); entry.AsTerrain.PatchIndex = patchIndex; - for (int32 chunkIndex = 0; chunkIndex < TerrainPatch::CHUNKS_COUNT; chunkIndex++) + for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++) { auto chunk = patch->Chunks[chunkIndex]; entry.AsTerrain.ChunkIndex = chunkIndex; diff --git a/Source/Engine/ShadowsOfMordor/Builder.Jobs.cpp b/Source/Engine/ShadowsOfMordor/Builder.Jobs.cpp index 11d136d62..8aed89eb3 100644 --- a/Source/Engine/ShadowsOfMordor/Builder.Jobs.cpp +++ b/Source/Engine/ShadowsOfMordor/Builder.Jobs.cpp @@ -165,7 +165,7 @@ void ShadowsOfMordor::Builder::onJobRender(GPUContext* context) Matrix::Transpose(world, shaderData.WorldMatrix); shaderData.LightmapArea = chunk->Lightmap.UVsArea; shaderData.TerrainChunkSizeLOD0 = TERRAIN_UNITS_PER_VERTEX * chunkSize; - chunk->GetHeightmapUVScaleBias(&shaderData.HeightmapUVScaleBias); + shaderData.HeightmapUVScaleBias = chunk->GetHeightmapUVScaleBias(); // Extract per axis scales from LocalToWorld transform const float scaleX = Float3(world.M11, world.M12, world.M13).Length(); diff --git a/Source/Engine/Terrain/Terrain.cpp b/Source/Engine/Terrain/Terrain.cpp index 497e9bf80..83b30166d 100644 --- a/Source/Engine/Terrain/Terrain.cpp +++ b/Source/Engine/Terrain/Terrain.cpp @@ -59,7 +59,7 @@ void Terrain::CacheNeighbors() for (int32 pathIndex = 0; pathIndex < _patches.Count(); pathIndex++) { const auto patch = _patches[pathIndex]; - for (int32 chunkIndex = 0; chunkIndex < TerrainPatch::CHUNKS_COUNT; chunkIndex++) + for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++) { patch->Chunks[chunkIndex].CacheNeighbors(); } @@ -215,7 +215,7 @@ void Terrain::DrawPatch(const RenderContext& renderContext, const Int2& patchCoo auto patch = GetPatch(patchCoord); if (patch) { - for (int32 i = 0; i < TerrainPatch::CHUNKS_COUNT; i++) + for (int32 i = 0; i < Terrain::ChunksCount; i++) patch->Chunks[i].Draw(renderContext, material, lodIndex); } } @@ -544,7 +544,7 @@ void Terrain::Draw(RenderContext& renderContext) Matrix localToWorld, worldToLocal; BoundingSphere chunkSphere; BoundingBox localBounds; - for (int32 chunkIndex = 0; chunkIndex < TerrainPatch::CHUNKS_COUNT; chunkIndex++) + for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++) { TerrainChunk* chunk = &patch->Chunks[chunkIndex]; chunk->GetTransform().GetWorld(localToWorld); // TODO: large-worlds @@ -574,7 +574,7 @@ void Terrain::Draw(RenderContext& renderContext) continue; // Frustum vs Box culling for chunks - for (int32 chunkIndex = 0; chunkIndex < TerrainPatch::CHUNKS_COUNT; chunkIndex++) + for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++) { auto chunk = &patch->Chunks[chunkIndex]; chunk->_cachedDrawLOD = 0; @@ -592,7 +592,7 @@ void Terrain::Draw(RenderContext& renderContext) else { // Reset cached LOD for chunks (prevent LOD transition from invisible chunks) - for (int32 chunkIndex = 0; chunkIndex < TerrainPatch::CHUNKS_COUNT; chunkIndex++) + for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++) { auto chunk = &patch->Chunks[chunkIndex]; chunk->_cachedDrawLOD = 0; @@ -620,10 +620,10 @@ void Terrain::OnDebugDrawSelected() for (int32 pathIndex = 0; pathIndex < _patches.Count(); pathIndex++) { const auto patch = _patches[pathIndex]; - for (int32 chunkIndex = 0; chunkIndex < TerrainPatch::CHUNKS_COUNT; chunkIndex++) + for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++) { auto chunk = &patch->Chunks[chunkIndex]; - DebugDraw::DrawBox(chunk->_bounds, Color(chunk->_x / (float)TerrainPatch::CHUNKS_COUNT_EDGE, 1.0f, chunk->_z / (float)TerrainPatch::CHUNKS_COUNT_EDGE)); + DebugDraw::DrawBox(chunk->_bounds, Color(chunk->_x / (float)Terrain::ChunksCountEdge, 1.0f, chunk->_z / (float)Terrain::ChunksCountEdge)); } } */ diff --git a/Source/Engine/Terrain/Terrain.h b/Source/Engine/Terrain/Terrain.h index 7db9b8500..5a1eb5e95 100644 --- a/Source/Engine/Terrain/Terrain.h +++ b/Source/Engine/Terrain/Terrain.h @@ -44,6 +44,22 @@ API_CLASS(Sealed) class FLAXENGINE_API Terrain : public PhysicsColliderActor friend TerrainPatch; friend TerrainChunk; + /// + /// Various defines regarding terrain configuration. + /// + API_ENUM() enum Config + { + /// + /// The maximum allowed amount of chunks per patch. + /// + ChunksCount = 16, + + /// + /// The maximum allowed amount of chunks per chunk. + /// + ChunksCountEdge = 4, + }; + private: char _lodBias; char _forcedLod; @@ -223,7 +239,7 @@ public: /// /// The patch location (x and z). /// The patch. - TerrainPatch* GetPatch(const Int2& patchCoord) const; + API_FUNCTION() TerrainPatch* GetPatch(API_PARAM(Ref) const Int2& patchCoord) const; /// /// Gets the patch at the given location. @@ -231,7 +247,7 @@ public: /// The patch location x. /// The patch location z. /// The patch. - TerrainPatch* GetPatch(int32 x, int32 z) const; + API_FUNCTION() TerrainPatch* GetPatch(int32 x, int32 z) const; /// /// Gets the zero-based index of the terrain patch in the terrain patches collection. @@ -245,7 +261,7 @@ public: /// /// The index. /// The patch. - FORCE_INLINE TerrainPatch* GetPatch(int32 index) const + API_FUNCTION() FORCE_INLINE TerrainPatch* GetPatch(int32 index) const { return _patches[index]; } @@ -316,7 +332,6 @@ public: public: #if TERRAIN_EDITING - /// /// Setups the terrain. Clears the existing data. /// @@ -341,7 +356,6 @@ public: /// /// The patch location (x and z). API_FUNCTION() void RemovePatch(API_PARAM(Ref) const Int2& patchCoord); - #endif /// @@ -374,7 +388,7 @@ public: /// The raycast result hit chunk. Valid only if raycast hits anything. /// The maximum distance the ray should check for collisions. /// True if ray hits an object, otherwise false. - bool RayCast(const Vector3& origin, const Vector3& direction, float& resultHitDistance, TerrainChunk*& resultChunk, float maxDistance = MAX_float) const; + API_FUNCTION() bool RayCast(const Vector3& origin, const Vector3& direction, API_PARAM(Out) float& resultHitDistance, API_PARAM(Out) TerrainChunk*& resultChunk, float maxDistance = MAX_float) const; /// /// Performs a raycast against this terrain collision shape. Returns the hit chunk. diff --git a/Source/Engine/Terrain/TerrainChunk.cpp b/Source/Engine/Terrain/TerrainChunk.cpp index 9bf1c1208..8ef32e58b 100644 --- a/Source/Engine/Terrain/TerrainChunk.cpp +++ b/Source/Engine/Terrain/TerrainChunk.cpp @@ -11,7 +11,14 @@ #include "Engine/Renderer/RenderList.h" #include "Engine/Core/Math/OrientedBoundingBox.h" #include "Engine/Level/Scene/Scene.h" +#if USE_EDITOR #include "Engine/Level/Prefabs/PrefabManager.h" +#endif + +TerrainChunk::TerrainChunk(const SpawnParams& params) + : ScriptingObject(params) +{ +} void TerrainChunk::Init(TerrainPatch* patch, uint16 x, uint16 z) { @@ -21,7 +28,7 @@ void TerrainChunk::Init(TerrainPatch* patch, uint16 x, uint16 z) _z = z; _yOffset = 0; _yHeight = 1; - _heightmapUVScaleBias = Float4(1.0f, 1.0f, _x, _z) * (1.0f / TerrainPatch::CHUNKS_COUNT_EDGE); + _heightmapUVScaleBias = Float4(1.0f, 1.0f, _x, _z) * (1.0f / Terrain::ChunksCountEdge); _perInstanceRandom = (_patch->_terrain->_id.C ^ _x ^ _z) * (1.0f / (float)MAX_uint32); OverrideMaterial = nullptr; } @@ -51,8 +58,8 @@ bool TerrainChunk::PrepareDraw(const RenderContext& renderContext) //lod = 0; //lod = 10; - //lod = (_x + _z + TerrainPatch::CHUNKS_COUNT_EDGE * (_patch->_x + _patch->_z)); - //lod = (int32)Vector2::Distance(Vector2(2, 2), Vector2(_patch->_x, _patch->_z) * TerrainPatch::CHUNKS_COUNT_EDGE + Vector2(_x, _z)); + //lod = (_x + _z + Terrain::ChunksCountEdge * (_patch->_x + _patch->_z)); + //lod = (int32)Vector2::Distance(Vector2(2, 2), Vector2(_patch->_x, _patch->_z) * Terrain::ChunksCountEdge + Vector2(_x, _z)); //lod = (int32)(Vector3::Distance(_bounds.GetCenter(), view.Position) / 10000.0f); } lod = Math::Clamp(lod, minStreamedLod, lodCount - 1); @@ -93,7 +100,7 @@ void TerrainChunk::Draw(const RenderContext& renderContext) const drawCall.ObjectRadius = _sphere.Radius; drawCall.Terrain.Patch = _patch; drawCall.Terrain.HeightmapUVScaleBias = _heightmapUVScaleBias; - drawCall.Terrain.OffsetUV = Vector2((float)(_patch->_x * TerrainPatch::CHUNKS_COUNT_EDGE + _x), (float)(_patch->_z * TerrainPatch::CHUNKS_COUNT_EDGE + _z)); + drawCall.Terrain.OffsetUV = Vector2((float)(_patch->_x * Terrain::ChunksCountEdge + _x), (float)(_patch->_z * Terrain::ChunksCountEdge + _z)); drawCall.Terrain.CurrentLOD = (float)lod; drawCall.Terrain.ChunkSizeNextLOD = (float)(((chunkSize + 1) >> (lod + 1)) - 1); drawCall.Terrain.TerrainChunkSizeLOD0 = TERRAIN_UNITS_PER_VERTEX * chunkSize; @@ -151,7 +158,7 @@ void TerrainChunk::Draw(const RenderContext& renderContext, MaterialBase* materi drawCall.ObjectRadius = _sphere.Radius; drawCall.Terrain.Patch = _patch; drawCall.Terrain.HeightmapUVScaleBias = _heightmapUVScaleBias; - drawCall.Terrain.OffsetUV = Vector2((float)(_patch->_x * TerrainPatch::CHUNKS_COUNT_EDGE + _x), (float)(_patch->_z * TerrainPatch::CHUNKS_COUNT_EDGE + _z)); + drawCall.Terrain.OffsetUV = Vector2((float)(_patch->_x * Terrain::ChunksCountEdge + _x), (float)(_patch->_z * Terrain::ChunksCountEdge + _z)); drawCall.Terrain.CurrentLOD = (float)lod; drawCall.Terrain.ChunkSizeNextLOD = (float)(((chunkSize + 1) >> (lod + 1)) - 1); drawCall.Terrain.TerrainChunkSizeLOD0 = TERRAIN_UNITS_PER_VERTEX * chunkSize; @@ -232,46 +239,46 @@ void TerrainChunk::CacheNeighbors() _neighbors[0] = this; if (_z > 0) { - _neighbors[0] = &_patch->Chunks[(_z - 1) * TerrainPatch::CHUNKS_COUNT_EDGE + _x]; + _neighbors[0] = &_patch->Chunks[(_z - 1) * Terrain::ChunksCountEdge + _x]; } else { const auto patch = _patch->_terrain->GetPatch(_patch->_x, _patch->_z - 1); if (patch) - _neighbors[0] = &patch->Chunks[(TerrainPatch::CHUNKS_COUNT_EDGE - 1) * TerrainPatch::CHUNKS_COUNT_EDGE + _x]; + _neighbors[0] = &patch->Chunks[(Terrain::ChunksCountEdge - 1) * Terrain::ChunksCountEdge + _x]; } // 1: left _neighbors[1] = this; if (_x > 0) { - _neighbors[1] = &_patch->Chunks[_z * TerrainPatch::CHUNKS_COUNT_EDGE + (_x - 1)]; + _neighbors[1] = &_patch->Chunks[_z * Terrain::ChunksCountEdge + (_x - 1)]; } else { const auto patch = _patch->_terrain->GetPatch(_patch->_x - 1, _patch->_z); if (patch) - _neighbors[1] = &patch->Chunks[_z * TerrainPatch::CHUNKS_COUNT_EDGE + (TerrainPatch::CHUNKS_COUNT_EDGE - 1)]; + _neighbors[1] = &patch->Chunks[_z * Terrain::ChunksCountEdge + (Terrain::ChunksCountEdge - 1)]; } // 2: right _neighbors[2] = this; - if (_x < TerrainPatch::CHUNKS_COUNT_EDGE - 1) + if (_x < Terrain::ChunksCountEdge - 1) { - _neighbors[2] = &_patch->Chunks[_z * TerrainPatch::CHUNKS_COUNT_EDGE + (_x + 1)]; + _neighbors[2] = &_patch->Chunks[_z * Terrain::ChunksCountEdge + (_x + 1)]; } else { const auto patch = _patch->_terrain->GetPatch(_patch->_x + 1, _patch->_z); if (patch) - _neighbors[2] = &patch->Chunks[_z * TerrainPatch::CHUNKS_COUNT_EDGE]; + _neighbors[2] = &patch->Chunks[_z * Terrain::ChunksCountEdge]; } // 3: top _neighbors[3] = this; - if (_z < TerrainPatch::CHUNKS_COUNT_EDGE - 1) + if (_z < Terrain::ChunksCountEdge - 1) { - _neighbors[3] = &_patch->Chunks[(_z + 1) * TerrainPatch::CHUNKS_COUNT_EDGE + _x]; + _neighbors[3] = &_patch->Chunks[(_z + 1) * Terrain::ChunksCountEdge + _x]; } else { diff --git a/Source/Engine/Terrain/TerrainChunk.h b/Source/Engine/Terrain/TerrainChunk.h index 884160b45..60f38ed0e 100644 --- a/Source/Engine/Terrain/TerrainChunk.h +++ b/Source/Engine/Terrain/TerrainChunk.h @@ -17,14 +17,14 @@ struct RenderContext; /// /// Represents a single terrain chunk. /// -class FLAXENGINE_API TerrainChunk : public ISerializable +API_CLASS(Sealed, NoSpawn) class FLAXENGINE_API TerrainChunk : public ScriptingObject, public ISerializable { + DECLARE_SCRIPTING_TYPE(TerrainChunk); friend Terrain; friend TerrainPatch; friend TerrainChunk; private: - TerrainPatch* _patch; uint16 _x, _z; Float4 _heightmapUVScaleBias; @@ -41,11 +41,10 @@ private: void Init(TerrainPatch* patch, uint16 x, uint16 z); public: - /// /// The material to override the terrain default one for this chunk. /// - AssetReference OverrideMaterial; + API_FIELD() AssetReference OverrideMaterial; /// /// The baked lightmap entry info for this chunk. @@ -53,11 +52,10 @@ public: LightmapEntry Lightmap; public: - /// /// Gets the x coordinate. /// - FORCE_INLINE int32 GetX() const + API_FUNCTION() FORCE_INLINE int32 GetX() const { return _x; } @@ -65,7 +63,7 @@ public: /// /// Gets the z coordinate. /// - FORCE_INLINE int32 GetZ() const + API_FUNCTION() FORCE_INLINE int32 GetZ() const { return _z; } @@ -73,7 +71,7 @@ public: /// /// Gets the patch. /// - FORCE_INLINE TerrainPatch* GetPatch() const + API_FUNCTION() FORCE_INLINE TerrainPatch* GetPatch() const { return _patch; } @@ -81,7 +79,7 @@ public: /// /// Gets the chunk world bounds. /// - FORCE_INLINE const BoundingBox& GetBounds() const + API_FUNCTION() FORCE_INLINE const BoundingBox& GetBounds() const { return _bounds; } @@ -89,7 +87,7 @@ public: /// /// Gets the chunk transformation (world to local). /// - FORCE_INLINE const Transform& GetTransform() const + API_FUNCTION() FORCE_INLINE const Transform& GetTransform() const { return _transform; } @@ -97,10 +95,9 @@ public: /// /// Gets the scale (in XY) and bias (in ZW) applied to the vertex UVs to get the chunk coordinates. /// - /// The result. - FORCE_INLINE void GetHeightmapUVScaleBias(Float4* result) const + API_FUNCTION() FORCE_INLINE const Float4& GetHeightmapUVScaleBias() const { - *result = _heightmapUVScaleBias; + return _heightmapUVScaleBias; } /// @@ -120,7 +117,6 @@ public: } public: - /// /// Prepares for drawing chunk. Cached LOD and material. /// @@ -140,7 +136,7 @@ public: /// The rendering context. /// The material to use for rendering. /// The LOD index. - void Draw(const RenderContext& renderContext, MaterialBase* material, int32 lodIndex = 0) const; + API_FUNCTION() void Draw(API_PARAM(Ref) const RenderContext& renderContext, MaterialBase* material, int32 lodIndex = 0) const; /// /// Determines if there is an intersection between the terrain chunk and a point @@ -148,7 +144,7 @@ public: /// The ray. /// The output distance. /// True if chunk intersects with the ray, otherwise false. - bool Intersects(const Ray& ray, Real& distance); + API_FUNCTION() bool Intersects(const Ray& ray, API_PARAM(Out) Real& distance); /// /// Updates the cached bounds of the chunk. @@ -166,7 +162,6 @@ public: void CacheNeighbors(); public: - // [ISerializable] void Serialize(SerializeStream& stream, const void* otherObj) override; void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override; diff --git a/Source/Engine/Terrain/TerrainPatch.cpp b/Source/Engine/Terrain/TerrainPatch.cpp index aa369f2ed..c5d1ace05 100644 --- a/Source/Engine/Terrain/TerrainPatch.cpp +++ b/Source/Engine/Terrain/TerrainPatch.cpp @@ -44,6 +44,11 @@ struct TerrainCollisionDataHeader float ScaleXZ; }; +TerrainPatch::TerrainPatch(const SpawnParams& params) + : ScriptingObject(params) +{ +} + void TerrainPatch::Init(Terrain* terrain, int16 x, int16 z) { ScopeLock lock(_collisionLocker); @@ -54,13 +59,13 @@ void TerrainPatch::Init(Terrain* terrain, int16 x, int16 z) _physicsHeightField = nullptr; _x = x; _z = z; - const float size = _terrain->_chunkSize * TERRAIN_UNITS_PER_VERTEX * CHUNKS_COUNT_EDGE; + const float size = _terrain->_chunkSize * TERRAIN_UNITS_PER_VERTEX * Terrain::Terrain::ChunksCountEdge; _offset = Float3(_x * size, 0.0f, _z * size); _yOffset = 0.0f; _yHeight = 1.0f; - for (int32 i = 0; i < CHUNKS_COUNT; i++) + for (int32 i = 0; i < Terrain::ChunksCount; i++) { - Chunks[i].Init(this, i % CHUNKS_COUNT_EDGE, i / CHUNKS_COUNT_EDGE); + Chunks[i].Init(this, i % Terrain::Terrain::ChunksCountEdge, i / Terrain::Terrain::ChunksCountEdge); } Heightmap = nullptr; for (int32 i = 0; i < TERRAIN_MAX_SPLATMAPS_COUNT; i++) @@ -111,7 +116,7 @@ void TerrainPatch::UpdateBounds() PROFILE_CPU(); Chunks[0].UpdateBounds(); _bounds = Chunks[0]._bounds; - for (int32 i = 1; i < CHUNKS_COUNT; i++) + for (int32 i = 1; i < Terrain::ChunksCount; i++) { Chunks[i].UpdateBounds(); BoundingBox::Merge(_bounds, Chunks[i]._bounds, _bounds); @@ -130,7 +135,7 @@ void TerrainPatch::UpdateTransform() } // Update chunks cache - for (int32 i = 0; i < CHUNKS_COUNT; i++) + for (int32 i = 0; i < Terrain::ChunksCount; i++) { Chunks[i].UpdateTransform(); } @@ -168,9 +173,9 @@ struct TerrainDataUpdateInfo { ChunkSize = patch->GetTerrain()->GetChunkSize(); VertexCountEdge = ChunkSize + 1; - HeightmapSize = ChunkSize * TerrainPatch::CHUNKS_COUNT_EDGE + 1; + HeightmapSize = ChunkSize * Terrain::ChunksCountEdge + 1; HeightmapLength = HeightmapSize * HeightmapSize; - TextureSize = VertexCountEdge * TerrainPatch::CHUNKS_COUNT_EDGE; + TextureSize = VertexCountEdge * Terrain::ChunksCountEdge; } bool UsePhysicalMaterials() const @@ -231,7 +236,7 @@ FORCE_INLINE bool ReadIsHole(const Color32& raw) return (raw.B + raw.A) >= (int32)(1.9f * MAX_uint8); } -void CalculateHeightmapRange(Terrain* terrain, TerrainDataUpdateInfo& info, const float* heightmap, float chunkOffsets[TerrainPatch::CHUNKS_COUNT], float chunkHeights[TerrainPatch::CHUNKS_COUNT]) +void CalculateHeightmapRange(Terrain* terrain, TerrainDataUpdateInfo& info, const float* heightmap, float chunkOffsets[Terrain::ChunksCount], float chunkHeights[Terrain::ChunksCount]) { PROFILE_CPU_NAMED("Terrain.CalculateRange"); @@ -240,10 +245,10 @@ void CalculateHeightmapRange(Terrain* terrain, TerrainDataUpdateInfo& info, cons float minPatchHeight = MAX_float; float maxPatchHeight = MIN_float; - for (int32 chunkIndex = 0; chunkIndex < TerrainPatch::CHUNKS_COUNT; chunkIndex++) + for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++) { - const int32 chunkX = (chunkIndex % TerrainPatch::CHUNKS_COUNT_EDGE) * info.ChunkSize; - const int32 chunkZ = (chunkIndex / TerrainPatch::CHUNKS_COUNT_EDGE) * info.ChunkSize; + const int32 chunkX = (chunkIndex % Terrain::ChunksCountEdge) * info.ChunkSize; + const int32 chunkZ = (chunkIndex / Terrain::ChunksCountEdge) * info.ChunkSize; float minHeight = MAX_float; float maxHeight = MIN_float; @@ -286,10 +291,10 @@ void UpdateHeightMap(const TerrainDataUpdateInfo& info, const float* heightmap, const auto heightmapPtr = heightmap; const auto ptr = (Color32*)data; - for (int32 chunkIndex = 0; chunkIndex < TerrainPatch::CHUNKS_COUNT; chunkIndex++) + for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++) { - const int32 chunkX = (chunkIndex % TerrainPatch::CHUNKS_COUNT_EDGE); - const int32 chunkZ = (chunkIndex / TerrainPatch::CHUNKS_COUNT_EDGE); + const int32 chunkX = (chunkIndex % Terrain::ChunksCountEdge); + const int32 chunkZ = (chunkIndex / Terrain::ChunksCountEdge); const int32 chunkTextureX = chunkX * info.VertexCountEdge; const int32 chunkTextureZ = chunkZ * info.VertexCountEdge; @@ -328,10 +333,10 @@ void UpdateSplatMap(const TerrainDataUpdateInfo& info, const Color32* splatMap, const auto splatPtr = splatMap; const auto ptr = (Color32*)data; - for (int32 chunkIndex = 0; chunkIndex < TerrainPatch::CHUNKS_COUNT; chunkIndex++) + for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++) { - const int32 chunkX = (chunkIndex % TerrainPatch::CHUNKS_COUNT_EDGE); - const int32 chunkZ = (chunkIndex / TerrainPatch::CHUNKS_COUNT_EDGE); + const int32 chunkX = (chunkIndex % Terrain::ChunksCountEdge); + const int32 chunkZ = (chunkIndex / Terrain::ChunksCountEdge); const int32 chunkTextureX = chunkX * info.VertexCountEdge; const int32 chunkTextureZ = chunkZ * info.VertexCountEdge; @@ -450,10 +455,10 @@ void UpdateNormalsAndHoles(const TerrainDataUpdateInfo& info, const float* heigh // Write back to the data container const auto ptr = (Color32*)data; - for (int32 chunkIndex = 0; chunkIndex < TerrainPatch::CHUNKS_COUNT; chunkIndex++) + for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++) { - const int32 chunkX = (chunkIndex % TerrainPatch::CHUNKS_COUNT_EDGE); - const int32 chunkZ = (chunkIndex / TerrainPatch::CHUNKS_COUNT_EDGE); + const int32 chunkX = (chunkIndex % Terrain::ChunksCountEdge); + const int32 chunkZ = (chunkIndex / Terrain::ChunksCountEdge); const int32 chunkTextureX = chunkX * info.VertexCountEdge; const int32 chunkTextureZ = chunkZ * info.VertexCountEdge; @@ -543,9 +548,9 @@ void FixMips(const TerrainDataUpdateInfo& info, TextureBase::InitData* initData, const int32 textureSizeMipHigher = textureSizeMip << 1; // Make heightmap values on left edge the same as the left edge of the chunk on the higher LOD - for (int32 chunkX = 0; chunkX < TerrainPatch::CHUNKS_COUNT_EDGE; chunkX++) + for (int32 chunkX = 0; chunkX < Terrain::ChunksCountEdge; chunkX++) { - for (int32 chunkZ = 0; chunkZ < TerrainPatch::CHUNKS_COUNT_EDGE; chunkZ++) + for (int32 chunkZ = 0; chunkZ < Terrain::ChunksCountEdge; chunkZ++) { const int32 chunkTextureX = chunkX * vertexCountEdgeMip; const int32 chunkTextureZ = chunkZ * vertexCountEdgeMip; @@ -558,11 +563,11 @@ void FixMips(const TerrainDataUpdateInfo& info, TextureBase::InitData* initData, int32 x = 0, xCount = vertexCountEdgeMip; if (chunkX == 0) x = 1; - else if (chunkX == TerrainPatch::CHUNKS_COUNT_EDGE - 1) + else if (chunkX == Terrain::ChunksCountEdge - 1) xCount--; if (chunkZ == 0) z = 1; - else if (chunkZ == TerrainPatch::CHUNKS_COUNT_EDGE - 1) + else if (chunkZ == Terrain::ChunksCountEdge - 1) zCount--; for (; z < zCount; z++) @@ -638,7 +643,7 @@ bool CookCollision(TerrainDataUpdateInfo& info, TextureBase::InitData* initData, const int32 collisionLOD = Math::Clamp(collisionLod, 0, initData->Mips.Count() - 1); const int32 collisionLODInv = (int32)Math::Pow(2.0f, (float)collisionLOD); const int32 heightFieldChunkSize = ((info.ChunkSize + 1) >> collisionLOD) - 1; - const int32 heightFieldSize = heightFieldChunkSize * TerrainPatch::CHUNKS_COUNT_EDGE + 1; + const int32 heightFieldSize = heightFieldChunkSize * Terrain::ChunksCountEdge + 1; const int32 heightFieldLength = heightFieldSize * heightFieldSize; GET_TERRAIN_SCRATCH_BUFFER(heightFieldData, heightFieldLength, PhysicsBackend::HeightFieldSample); PhysicsBackend::HeightFieldSample sample; @@ -649,11 +654,11 @@ bool CookCollision(TerrainDataUpdateInfo& info, TextureBase::InitData* initData, const auto& mip = initData->Mips[collisionLOD]; const int32 vertexCountEdgeMip = info.VertexCountEdge >> collisionLOD; const int32 textureSizeMip = info.TextureSize >> collisionLOD; - for (int32 chunkX = 0; chunkX < TerrainPatch::CHUNKS_COUNT_EDGE; chunkX++) + for (int32 chunkX = 0; chunkX < Terrain::ChunksCountEdge; chunkX++) { const int32 chunkTextureX = chunkX * vertexCountEdgeMip; const int32 chunkStartX = chunkX * heightFieldChunkSize; - for (int32 chunkZ = 0; chunkZ < TerrainPatch::CHUNKS_COUNT_EDGE; chunkZ++) + for (int32 chunkZ = 0; chunkZ < Terrain::ChunksCountEdge; chunkZ++) { const int32 chunkTextureZ = chunkZ * vertexCountEdgeMip; const int32 chunkStartZ = chunkZ * heightFieldChunkSize; @@ -709,7 +714,7 @@ bool ModifyCollision(TerrainDataUpdateInfo& info, TextureBase::InitData* initDat const int32 collisionLOD = Math::Clamp(collisionLod, 0, initData->Mips.Count() - 1); const int32 collisionLODInv = (int32)Math::Pow(2.0f, (float)collisionLOD); const int32 heightFieldChunkSize = ((info.ChunkSize + 1) >> collisionLOD) - 1; - const int32 heightFieldSize = heightFieldChunkSize * TerrainPatch::CHUNKS_COUNT_EDGE + 1; + const int32 heightFieldSize = heightFieldChunkSize * Terrain::ChunksCountEdge + 1; const Int2 samplesOffset(Vector2::Floor(modifiedOffsetRatio * (float)heightFieldSize)); Int2 samplesSize(Vector2::Ceil(modifiedSizeRatio * (float)heightFieldSize)); samplesSize.X = Math::Max(samplesSize.X, 1); @@ -729,14 +734,14 @@ bool ModifyCollision(TerrainDataUpdateInfo& info, TextureBase::InitData* initDat const auto& mip = initData->Mips[collisionLOD]; const int32 vertexCountEdgeMip = info.VertexCountEdge >> collisionLOD; const int32 textureSizeMip = info.TextureSize >> collisionLOD; - for (int32 chunkX = 0; chunkX < TerrainPatch::CHUNKS_COUNT_EDGE; chunkX++) + for (int32 chunkX = 0; chunkX < Terrain::ChunksCountEdge; chunkX++) { const int32 chunkTextureX = chunkX * vertexCountEdgeMip; const int32 chunkStartX = chunkX * heightFieldChunkSize; if (chunkStartX >= samplesEnd.X || chunkStartX + vertexCountEdgeMip < samplesOffset.X) continue; // Skip unmodified chunks - for (int32 chunkZ = 0; chunkZ < TerrainPatch::CHUNKS_COUNT_EDGE; chunkZ++) + for (int32 chunkZ = 0; chunkZ < Terrain::ChunksCountEdge; chunkZ++) { const int32 chunkTextureZ = chunkZ * vertexCountEdgeMip; const int32 chunkStartZ = chunkZ * heightFieldChunkSize; @@ -806,15 +811,15 @@ bool TerrainPatch::SetupHeightMap(int32 heightMapLength, const float* heightMap, const int32 lodCount = Math::Min(_terrain->_lodCount, MipLevelsCount(info.VertexCountEdge) - 2); // Process heightmap to get per-patch height normalization values - float chunkOffsets[CHUNKS_COUNT]; - float chunkHeights[CHUNKS_COUNT]; + float chunkOffsets[Terrain::ChunksCount]; + float chunkHeights[Terrain::ChunksCount]; CalculateHeightmapRange(_terrain, info, heightMap, chunkOffsets, chunkHeights); // Prepare #if USE_EDITOR const bool useVirtualStorage = Editor::IsPlayMode || forceUseVirtualStorage; #else - const bool useVirtualStorage = true; + const bool useVirtualStorage = true; #endif #if USE_EDITOR String heightMapPath, heightFieldPath; @@ -910,11 +915,11 @@ bool TerrainPatch::SetupHeightMap(int32 heightMapLength, const float* heightMap, } } #else - else - { - // Not supported - CRASH; - } + else + { + // Not supported + CRASH; + } #endif // Prepare collision data destination container @@ -975,7 +980,7 @@ bool TerrainPatch::SetupHeightMap(int32 heightMapLength, const float* heightMap, // Update data _yOffset = info.PatchOffset; _yHeight = info.PatchHeight; - for (int32 chunkIndex = 0; chunkIndex < CHUNKS_COUNT; chunkIndex++) + for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++) { auto& chunk = Chunks[chunkIndex]; chunk._yOffset = chunkOffsets[chunkIndex]; @@ -1031,7 +1036,7 @@ bool TerrainPatch::SetupSplatMap(int32 index, int32 splatMapLength, const Color3 #if USE_EDITOR const bool useVirtualStorage = Editor::IsPlayMode || forceUseVirtualStorage; #else - const bool useVirtualStorage = true; + const bool useVirtualStorage = true; #endif #if USE_EDITOR String splatMapPath; @@ -1126,11 +1131,11 @@ bool TerrainPatch::SetupSplatMap(int32 index, int32 splatMapLength, const Color3 } } #else - else - { - // Not supported - CRASH; - } + else + { + // Not supported + CRASH; + } #endif #if TERRAIN_UPDATING @@ -1147,7 +1152,7 @@ bool TerrainPatch::SetupSplatMap(int32 index, int32 splatMapLength, const Color3 bool TerrainPatch::InitializeHeightMap() { PROFILE_CPU_NAMED("Terrain.InitializeHeightMap"); - const auto heightmapSize = _terrain->GetChunkSize() * TerrainPatch::CHUNKS_COUNT_EDGE + 1; + const auto heightmapSize = _terrain->GetChunkSize() * Terrain::ChunksCountEdge + 1; Array heightmap; heightmap.Resize(heightmapSize * heightmapSize); heightmap.SetAll(0.0f); @@ -1242,7 +1247,7 @@ void TerrainPatch::CacheHeightData() const float patchHeight = _yHeight; const auto heightmapPtr = _cachedHeightMap.Get(); const auto holesMaskPtr = _cachedHolesMask.Get(); - for (int32 chunkIndex = 0; chunkIndex < CHUNKS_COUNT; chunkIndex++) + for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++) { const int32 chunkTextureX = Chunks[chunkIndex]._x * info.VertexCountEdge; const int32 chunkTextureZ = Chunks[chunkIndex]._z * info.VertexCountEdge; @@ -1315,7 +1320,7 @@ void TerrainPatch::CacheSplatData() // Extract splatmap data const auto splatMapPtr = static_cast(_cachedSplatMap[index].Get()); - for (int32 chunkIndex = 0; chunkIndex < CHUNKS_COUNT; chunkIndex++) + for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++) { const int32 chunkTextureX = Chunks[chunkIndex]._x * info.VertexCountEdge; const int32 chunkTextureZ = Chunks[chunkIndex]._z * info.VertexCountEdge; @@ -1394,8 +1399,8 @@ bool TerrainPatch::ModifyHeightMap(const float* samples, const Int2& modifiedOff } // Process heightmap to get per-patch height normalization values - float chunkOffsets[CHUNKS_COUNT]; - float chunkHeights[CHUNKS_COUNT]; + float chunkOffsets[Terrain::ChunksCount]; + float chunkHeights[Terrain::ChunksCount]; CalculateHeightmapRange(_terrain, info, heightMap, chunkOffsets, chunkHeights); // TODO: maybe calculate chunk ranges for only modified chunks const bool wasHeightRangeChanged = Math::NotNearEqual(_yOffset, info.PatchOffset) || Math::NotNearEqual(_yHeight, info.PatchHeight); @@ -1425,7 +1430,7 @@ bool TerrainPatch::ModifyHeightMap(const float* samples, const Int2& modifiedOff // Update all the stuff _yOffset = info.PatchOffset; _yHeight = info.PatchHeight; - for (int32 chunkIndex = 0; chunkIndex < CHUNKS_COUNT; chunkIndex++) + for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++) { auto& chunk = Chunks[chunkIndex]; chunk._yOffset = chunkOffsets[chunkIndex]; @@ -1631,7 +1636,7 @@ bool TerrainPatch::ModifySplatMap(int32 index, const Color32* samples, const Int #if USE_EDITOR const bool useVirtualStorage = Editor::IsPlayMode || Heightmap->IsVirtual(); #else - const bool useVirtualStorage = true; + const bool useVirtualStorage = true; #endif // Save the splatmap data to the asset @@ -1675,11 +1680,11 @@ bool TerrainPatch::ModifySplatMap(int32 index, const Color32* samples, const Int } } #else - else - { - // Not supported - CRASH; - } + else + { + // Not supported + CRASH; + } #endif } @@ -1987,7 +1992,7 @@ bool TerrainPatch::RayCast(const Vector3& origin, const Vector3& direction, floa // Find hit chunk resultChunk = nullptr; const auto hitPoint = origin + direction * hitDistance; - for (int32 chunkIndex = 0; chunkIndex < CHUNKS_COUNT; chunkIndex++) + for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++) { const auto box = Chunks[chunkIndex]._bounds; if (box.Minimum.X <= hitPoint.X && box.Maximum.X >= hitPoint.X && @@ -2042,7 +2047,7 @@ void TerrainPatch::ClosestPoint(const Vector3& position, Vector3& result) const void TerrainPatch::UpdatePostManualDeserialization() { // Update data - for (int32 chunkIndex = 0; chunkIndex < CHUNKS_COUNT; chunkIndex++) + for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++) { auto& chunk = Chunks[chunkIndex]; chunk.UpdateTransform(); @@ -2101,7 +2106,7 @@ void TerrainPatch::CreateCollision() // Create shape JsonAsset* materials[8]; - for (int32 i = 0;i<8;i++) + for (int32 i = 0; i < 8; i++) materials[i] = _terrain->GetPhysicalMaterials()[i]; _physicsShape = PhysicsBackend::CreateShape(_terrain, shape, ToSpan(materials, 8), _terrain->IsActiveInHierarchy(), false); PhysicsBackend::SetShapeLocalPose(_physicsShape, Vector3(0, _yOffset * terrainTransform.Scale.Y, 0), Quaternion::Identity); @@ -2295,7 +2300,7 @@ const Array& TerrainPatch::GetCollisionTriangles() #define GET_VERTEX(x, y) Vector3 v##x##y((float)(row + (x)), PhysicsBackend::GetHeightFieldHeight(_physicsHeightField, row + (x), col + (y)) / TERRAIN_PATCH_COLLISION_QUANTIZATION, (float)(col + (y))); Vector3::Transform(v##x##y, world, v##x##y) - const float size = _terrain->_chunkSize * TERRAIN_UNITS_PER_VERTEX * CHUNKS_COUNT_EDGE; + const float size = _terrain->_chunkSize * TERRAIN_UNITS_PER_VERTEX * Terrain::Terrain::ChunksCountEdge; const Transform terrainTransform = _terrain->_transform; Transform localTransform(Vector3(_x * size, _yOffset, _z * size), Quaternion::Identity, Vector3(_collisionScaleXZ, _yHeight, _collisionScaleXZ)); const Matrix world = localTransform.GetWorld() * terrainTransform.GetWorld(); @@ -2344,7 +2349,7 @@ void TerrainPatch::GetCollisionTriangles(const BoundingSphere& bounds, Array_chunkSize * TERRAIN_UNITS_PER_VERTEX * CHUNKS_COUNT_EDGE; + const float size = _terrain->_chunkSize * TERRAIN_UNITS_PER_VERTEX * Terrain::Terrain::ChunksCountEdge; Transform transform; transform.Translation = _offset + Vector3(0, _yOffset, 0); transform.Orientation = Quaternion::Identity; @@ -2450,7 +2455,7 @@ void TerrainPatch::ExtractCollisionGeometry(Array& vertexBuffer, Array_chunkSize * TERRAIN_UNITS_PER_VERTEX * CHUNKS_COUNT_EDGE; + const float size = _terrain->_chunkSize * TERRAIN_UNITS_PER_VERTEX * Terrain::Terrain::ChunksCountEdge; const Transform terrainTransform = _terrain->_transform; const Transform localTransform(Vector3(_x * size, _yOffset, _z * size), Quaternion::Identity, Float3(_collisionScaleXZ, _yHeight, _collisionScaleXZ)); const Matrix world = localTransform.GetWorld() * terrainTransform.GetWorld(); @@ -2512,7 +2517,7 @@ void TerrainPatch::Serialize(SerializeStream& stream, const void* otherObj) stream.JKEY("Chunks"); stream.StartArray(); - for (int32 i = 0; i < CHUNKS_COUNT; i++) + for (int32 i = 0; i < Terrain::Terrain::ChunksCount; i++) { stream.StartObject(); Chunks[i].Serialize(stream, other ? &other->Chunks[i] : nullptr); @@ -2539,15 +2544,14 @@ void TerrainPatch::Deserialize(DeserializeStream& stream, ISerializeModifier* mo DESERIALIZE_MEMBER(Heightfield, _heightfield); // Update offset (x or/and z may be modified) - const float size = _terrain->_chunkSize * TERRAIN_UNITS_PER_VERTEX * CHUNKS_COUNT_EDGE; + const float size = _terrain->_chunkSize * TERRAIN_UNITS_PER_VERTEX * Terrain::ChunksCountEdge; _offset = Vector3(_x * size, 0.0f, _z * size); auto member = stream.FindMember("Chunks"); if (member != stream.MemberEnd() && member->value.IsArray()) { auto& chunksData = member->value; - const auto chunksCount = Math::Min((int32)chunksData.Size(), CHUNKS_COUNT); - + const auto chunksCount = Math::Min((int32)chunksData.Size(), Terrain::ChunksCount); for (int32 i = 0; i < chunksCount; i++) { Chunks[i].Deserialize(chunksData[i], modifier); diff --git a/Source/Engine/Terrain/TerrainPatch.h b/Source/Engine/Terrain/TerrainPatch.h index ac1a237c1..f1a82dea1 100644 --- a/Source/Engine/Terrain/TerrainPatch.h +++ b/Source/Engine/Terrain/TerrainPatch.h @@ -15,19 +15,13 @@ class TerrainMaterialShader; /// /// Represents single terrain patch made of 16 terrain chunks. /// -class FLAXENGINE_API TerrainPatch : public ISerializable +API_CLASS(Sealed, NoSpawn) class FLAXENGINE_API TerrainPatch : public ScriptingObject, public ISerializable { + DECLARE_SCRIPTING_TYPE(TerrainPatch); friend Terrain; friend TerrainPatch; friend TerrainChunk; -public: - enum - { - CHUNKS_COUNT = 16, - CHUNKS_COUNT_EDGE = 4, - }; - private: Terrain* _terrain; int16 _x, _z; @@ -69,12 +63,12 @@ public: /// /// The chunks contained within the patch. Organized in 4x4 square. /// - TerrainChunk Chunks[CHUNKS_COUNT]; + TerrainChunk Chunks[Terrain::ChunksCount]; /// /// The heightmap texture. /// - AssetReference Heightmap; + API_FIELD() AssetReference Heightmap; /// /// The splatmap textures. @@ -85,7 +79,7 @@ public: /// /// Gets the Y axis heightmap offset from terrain origin. /// - FORCE_INLINE float GetOffsetY() const + API_FUNCTION() FORCE_INLINE float GetOffsetY() const { return _yOffset; } @@ -93,7 +87,7 @@ public: /// /// Gets the Y axis heightmap height. /// - FORCE_INLINE float GetHeightY() const + API_FUNCTION() FORCE_INLINE float GetHeightY() const { return _yHeight; } @@ -101,7 +95,7 @@ public: /// /// Gets the x coordinate. /// - FORCE_INLINE int32 GetX() const + API_FUNCTION() FORCE_INLINE int32 GetX() const { return _x; } @@ -109,7 +103,7 @@ public: /// /// Gets the z coordinate. /// - FORCE_INLINE int32 GetZ() const + API_FUNCTION() FORCE_INLINE int32 GetZ() const { return _z; } @@ -117,7 +111,7 @@ public: /// /// Gets the terrain. /// - FORCE_INLINE Terrain* GetTerrain() const + API_FUNCTION() FORCE_INLINE Terrain* GetTerrain() const { return _terrain; } @@ -127,9 +121,9 @@ public: /// /// The chunk zero-based index. /// The chunk. - TerrainChunk* GetChunk(int32 index) + API_FUNCTION() TerrainChunk* GetChunk(int32 index) { - if (index < 0 || index >= CHUNKS_COUNT) + if (index < 0 || index >= Terrain::ChunksCount) return nullptr; return &Chunks[index]; } @@ -139,9 +133,9 @@ public: /// /// The chunk location (x and z). /// The chunk. - TerrainChunk* GetChunk(const Int2& chunkCoord) + API_FUNCTION() TerrainChunk* GetChunk(API_PARAM(Ref) const Int2& chunkCoord) { - return GetChunk(chunkCoord.Y * CHUNKS_COUNT_EDGE + chunkCoord.X); + return GetChunk(chunkCoord.Y * Terrain::ChunksCountEdge + chunkCoord.X); } /// @@ -150,15 +144,38 @@ public: /// The chunk location x. /// The chunk location z. /// The chunk. - TerrainChunk* GetChunk(int32 x, int32 z) + API_FUNCTION() TerrainChunk* GetChunk(int32 x, int32 z) { - return GetChunk(z * CHUNKS_COUNT_EDGE + x); + return GetChunk(z * Terrain::ChunksCountEdge + x); + } + + /// + /// Gets the splatmap assigned to this patch. + /// + /// The zero-based index of the splatmap. + /// The splatmap texture. + API_FUNCTION() AssetReference GetSplatmap(int32 index) + { + if (index < 0 || index >= TERRAIN_MAX_SPLATMAPS_COUNT) + return nullptr; + return Splatmap[index]; + } + + /// + /// Sets a splatmap to this patch. + /// + /// The zero-based index of the splatmap. + /// Splatmap texture. + API_FUNCTION() void SetSplatmap(int32 index, const AssetReference& splatMap) + { + if (index >= 0 && index < TERRAIN_MAX_SPLATMAPS_COUNT) + Splatmap[index] = splatMap; } /// /// Gets the patch world bounds. /// - FORCE_INLINE const BoundingBox& GetBounds() const + API_FUNCTION() FORCE_INLINE const BoundingBox& GetBounds() const { return _bounds; } @@ -184,7 +201,7 @@ public: /// Initializes the patch heightmap and collision to the default flat level. /// /// True if failed, otherwise false. - bool InitializeHeightMap(); + API_FUNCTION() bool InitializeHeightMap(); /// /// Setups the terrain patch using the specified heightmap data. @@ -194,7 +211,7 @@ public: /// The holes mask (optional). Normalized to 0-1 range values with holes mask per-vertex. Must match the heightmap dimensions. /// If set to true patch will use virtual storage by force. Otherwise it can use normal texture asset storage on drive (valid only during Editor). Runtime-created terrain can only use virtual storage (in RAM). /// True if failed, otherwise false. - bool SetupHeightMap(int32 heightMapLength, const float* heightMap, const byte* holesMask = nullptr, bool forceUseVirtualStorage = false); + API_FUNCTION() bool SetupHeightMap(int32 heightMapLength, API_PARAM(Ref) const float* heightMap, API_PARAM(Ref) const byte* holesMask = nullptr, bool forceUseVirtualStorage = false); /// /// Setups the terrain patch layer weights using the specified splatmaps data. @@ -204,7 +221,7 @@ public: /// The splat map. Each array item contains 4 layer weights. /// If set to true patch will use virtual storage by force. Otherwise it can use normal texture asset storage on drive (valid only during Editor). Runtime-created terrain can only use virtual storage (in RAM). /// True if failed, otherwise false. - bool SetupSplatMap(int32 index, int32 splatMapLength, const Color32* splatMap, bool forceUseVirtualStorage = false); + API_FUNCTION() bool SetupSplatMap(int32 index, int32 splatMapLength, API_PARAM(Ref) const Color32* splatMap, bool forceUseVirtualStorage = false); #endif #if TERRAIN_UPDATING @@ -212,40 +229,40 @@ public: /// Gets the raw pointer to the heightmap data. /// /// The heightmap data. - float* GetHeightmapData(); + API_FUNCTION() float* GetHeightmapData(); /// /// Clears cache of the heightmap data. /// - void ClearHeightmapCache(); + API_FUNCTION() void ClearHeightmapCache(); /// /// Gets the raw pointer to the holes mask data. /// /// The holes mask data. - byte* GetHolesMaskData(); + API_FUNCTION() byte* GetHolesMaskData(); /// /// Clears cache of the holes mask data. /// - void ClearHolesMaskCache(); + API_FUNCTION() void ClearHolesMaskCache(); /// /// Gets the raw pointer to the splat map data. /// /// The zero-based index of the splatmap texture. /// The splat map data. - Color32* GetSplatMapData(int32 index); + API_FUNCTION() Color32* GetSplatMapData(int32 index); /// /// Clears cache of the splat map data. /// - void ClearSplatMapCache(); + API_FUNCTION() void ClearSplatMapCache(); /// /// Clears all caches. /// - void ClearCache(); + API_FUNCTION() void ClearCache(); /// /// Modifies the terrain patch heightmap with the given samples. @@ -254,7 +271,7 @@ public: /// The offset from the first row and column of the heightmap data (offset destination x and z start position). /// The size of the heightmap to modify (x and z). Amount of samples in each direction. /// True if failed, otherwise false. - bool ModifyHeightMap(const float* samples, const Int2& modifiedOffset, const Int2& modifiedSize); + API_FUNCTION() bool ModifyHeightMap(API_PARAM(Ref) const float* samples, API_PARAM(Ref) const Int2& modifiedOffset, API_PARAM(Ref) const Int2& modifiedSize); /// /// Modifies the terrain patch holes mask with the given samples. @@ -263,7 +280,7 @@ public: /// The offset from the first row and column of the holes map data (offset destination x and z start position). /// The size of the holes map to modify (x and z). Amount of samples in each direction. /// True if failed, otherwise false. - bool ModifyHolesMask(const byte* samples, const Int2& modifiedOffset, const Int2& modifiedSize); + API_FUNCTION() bool ModifyHolesMask(API_PARAM(Ref) const byte* samples, API_PARAM(Ref) const Int2& modifiedOffset, API_PARAM(Ref) const Int2& modifiedSize); /// /// Modifies the terrain patch splat map (layers mask) with the given samples. @@ -273,7 +290,7 @@ public: /// The offset from the first row and column of the splat map data (offset destination x and z start position). /// The size of the splat map to modify (x and z). Amount of samples in each direction. /// True if failed, otherwise false. - bool ModifySplatMap(int32 index, const Color32* samples, const Int2& modifiedOffset, const Int2& modifiedSize); + API_FUNCTION() bool ModifySplatMap(int32 index, API_PARAM(Ref) const Color32* samples, API_PARAM(Ref) const Int2& modifiedOffset, API_PARAM(Ref) const Int2& modifiedSize); private: bool UpdateHeightData(struct TerrainDataUpdateInfo& info, const Int2& modifiedOffset, const Int2& modifiedSize, bool wasHeightRangeChanged, bool wasHeightChanged); @@ -293,7 +310,7 @@ public: /// The raycast result hit position distance from the ray origin. Valid only if raycast hits anything. /// The maximum distance the ray should check for collisions. /// True if ray hits an object, otherwise false. - bool RayCast(const Vector3& origin, const Vector3& direction, float& resultHitDistance, float maxDistance = MAX_float) const; + API_FUNCTION() bool RayCast(const Vector3& origin, const Vector3& direction, API_PARAM(Out) float& resultHitDistance, float maxDistance = MAX_float) const; /// /// Performs a raycast against this terrain collision shape. @@ -304,7 +321,7 @@ public: /// The raycast result hit position normal vector. Valid only if raycast hits anything. /// The maximum distance the ray should check for collisions. /// True if ray hits an object, otherwise false. - bool RayCast(const Vector3& origin, const Vector3& direction, float& resultHitDistance, Vector3& resultHitNormal, float maxDistance = MAX_float) const; + API_FUNCTION() bool RayCast(const Vector3& origin, const Vector3& direction, API_PARAM(Out) float& resultHitDistance, API_PARAM(Out) Vector3& resultHitNormal, float maxDistance = MAX_float) const; /// /// Performs a raycast against this terrain collision shape. Returns the hit chunk. @@ -315,7 +332,7 @@ public: /// The raycast result hit chunk. Valid only if raycast hits anything. /// The maximum distance the ray should check for collisions. /// True if ray hits an object, otherwise false. - bool RayCast(const Vector3& origin, const Vector3& direction, float& resultHitDistance, TerrainChunk*& resultChunk, float maxDistance = MAX_float) const; + API_FUNCTION() bool RayCast(const Vector3& origin, const Vector3& direction, API_PARAM(Out) float& resultHitDistance, API_PARAM(Out) TerrainChunk*& resultChunk, float maxDistance = MAX_float) const; /// /// Performs a raycast against terrain collision, returns results in a RaycastHit structure. @@ -325,14 +342,14 @@ public: /// The result hit information. Valid only when method returns true. /// The maximum distance the ray should check for collisions. /// True if ray hits an object, otherwise false. - bool RayCast(const Vector3& origin, const Vector3& direction, RayCastHit& hitInfo, float maxDistance = MAX_float) const; + API_FUNCTION() bool RayCast(const Vector3& origin, const Vector3& direction, API_PARAM(Out) RayCastHit& hitInfo, float maxDistance = MAX_float) const; /// /// Gets a point on the terrain collider that is closest to a given location. Can be used to find a hit location or position to apply explosion force or any other special effects. /// /// The position to find the closest point to it. /// The result point on the collider that is closest to the specified location. - void ClosestPoint(const Vector3& position, Vector3& result) const; + API_FUNCTION() void ClosestPoint(API_PARAM(Ref) const Vector3& position, API_PARAM(Out) Vector3& result) const; #if USE_EDITOR /// @@ -354,7 +371,7 @@ public: /// /// The world-space bounds to find terrain triangles that intersect with it. /// The result triangles that intersect with the given bounds (in world-space). - void GetCollisionTriangles(const BoundingSphere& bounds, Array& result); + void GetCollisionTriangles(API_PARAM(Ref) const BoundingSphere& bounds, API_PARAM(Out) Array& result); #endif /// @@ -362,7 +379,7 @@ public: /// /// The output vertex buffer. /// The output index buffer. - void ExtractCollisionGeometry(Array& vertexBuffer, Array& indexBuffer); + API_FUNCTION() void ExtractCollisionGeometry(API_PARAM(Out) Array& vertexBuffer, API_PARAM(Out) Array& indexBuffer); private: ///