// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#pragma once
#include "Engine/Core/Collections/Array.h"
#include "Mesh.h"
class MemoryReadStream;
///
/// Represents single Level Of Detail for the model. Contains a collection of the meshes.
///
API_CLASS(NoSpawn) class FLAXENGINE_API ModelLOD : public PersistentScriptingObject
{
DECLARE_SCRIPTING_TYPE_WITH_CONSTRUCTOR_IMPL(ModelLOD, PersistentScriptingObject);
friend Model;
friend Mesh;
private:
Model* _model = nullptr;
uint32 _verticesCount;
public:
///
/// The screen size to switch LODs. Bottom limit of the model screen size to render this LOD.
///
API_FIELD() float ScreenSize = 1.0f;
///
/// The meshes array.
///
API_FIELD(ReadOnly) Array Meshes;
///
/// Determines whether any mesh has been initialized.
///
/// True if any mesh has been initialized, otherwise false.
FORCE_INLINE bool HasAnyMeshInitialized() const
{
// Note: we initialize all meshes at once so the last one can be used to check it.
return Meshes.HasItems() && Meshes.Last().IsInitialized();
}
///
/// Gets the vertex count for this model LOD level.
///
API_PROPERTY() FORCE_INLINE int32 GetVertexCount() const
{
return _verticesCount;
}
public:
///
/// Initializes the LOD from the data stream.
///
/// The stream.
/// True if fails, otherwise false.
bool Load(MemoryReadStream& stream);
///
/// Unloads the LOD meshes data (vertex buffers and cache). It won't dispose the meshes collection. The opposite to Load.
///
void Unload();
///
/// Cleanups the data.
///
void Dispose();
public:
///
/// Determines if there is an intersection between the Model and a Ray in given world using given instance
///
/// The ray to test
/// World to test
/// When the method completes, contains the distance of the intersection (if any valid).
/// When the method completes, contains the intersection surface normal vector (if any valid).
/// Mesh, or null
/// True whether the two objects intersected
bool Intersects(const Ray& ray, const Matrix& world, float& distance, Vector3& normal, Mesh** mesh);
///
/// Get model bounding box in transformed world for given instance buffer
///
/// World matrix
/// Bounding box
BoundingBox GetBox(const Matrix& world) const;
///
/// Get model bounding box in transformed world for given instance buffer for only one mesh
///
/// World matrix
/// esh index
/// Bounding box
BoundingBox GetBox(const Matrix& world, int32 meshIndex) const;
///
/// Gets the bounding box combined for all meshes in this model LOD.
///
API_PROPERTY() BoundingBox GetBox() const;
///
/// Draws the meshes. Binds vertex and index buffers and invokes the draw calls.
///
/// The GPU context to draw with.
FORCE_INLINE void Render(GPUContext* context)
{
for (int32 i = 0; i < Meshes.Count(); i++)
{
Meshes[i].Render(context);
}
}
///
/// Draws the meshes from the model LOD.
///
/// The rendering context.
/// The material to use for rendering.
/// The world transformation of the model.
/// The object static flags.
/// True if rendered geometry can receive decals, otherwise false.
API_FUNCTION() void Draw(API_PARAM(Ref) const RenderContext& renderContext, MaterialBase* material, API_PARAM(Ref) const Matrix& world, StaticFlags flags = StaticFlags::None, bool receiveDecals = true) const
{
for (int32 i = 0; i < Meshes.Count(); i++)
{
Meshes[i].Draw(renderContext, material, world, flags, receiveDecals);
}
}
///
/// Draws all the meshes from the model LOD.
///
/// The rendering context.
/// The packed drawing info data.
/// The LOD transition dither factor.
FORCE_INLINE void Draw(const RenderContext& renderContext, const Mesh::DrawInfo& info, float lodDitherFactor) const
{
for (int32 i = 0; i < Meshes.Count(); i++)
{
Meshes[i].Draw(renderContext, info, lodDitherFactor);
}
}
};