#pragma once #include "lc_math.h" #include "lc_mesh.h" class lcLibraryMeshData; class lcMeshLoader; enum lcMeshDataType { LC_MESHDATA_HIGH, LC_MESHDATA_LOW, LC_MESHDATA_SHARED, LC_NUM_MESHDATA_TYPES }; struct lcMeshLoaderVertex { lcVector3 Position; lcVector3 Normal; float NormalWeight; }; struct lcMeshLoaderTexturedVertex { lcVector3 Position; lcVector3 Normal; lcVector2 TexCoords; }; struct lcMeshLoaderConditionalVertex { lcVector3 Position[4]; }; enum class lcMeshLoaderMaterialType { Solid, Planar, Cylindrical, Spherical }; struct lcMeshLoaderMaterial { lcMeshLoaderMaterialType Type = lcMeshLoaderMaterialType::Solid; quint32 Color = 16; lcVector3 Points[3] = {}; float Angles[2] = {}; char Name[256] = {}; }; class lcMeshLoaderSection { public: lcMeshLoaderSection(lcMeshPrimitiveType PrimitiveType, lcMeshLoaderMaterial* Material) : mMaterial(Material), mPrimitiveType(PrimitiveType) { mIndices.reserve(1024); } lcMeshLoaderMaterial* mMaterial; lcMeshPrimitiveType mPrimitiveType; std::vector mIndices; }; struct lcMeshLoaderFinalSection { quint32 Color; lcMeshPrimitiveType PrimitiveType; char Name[256]; }; struct lcMeshLoaderTextureMap { union lcTextureMapParams { lcTextureMapParams() { } struct lcTextureMapSphericalParams { } Spherical; } Params; lcMeshLoaderMaterialType Type; lcVector3 Points[3]; float Angles[2]; char Name[LC_MAXPATH]; bool Fallback = false; bool Next = false; }; class lcMeshLoaderTypeData { public: lcMeshLoaderTypeData() = default; lcMeshLoaderTypeData(const lcMeshLoaderTypeData&) = delete; lcMeshLoaderTypeData& operator=(const lcMeshLoaderTypeData&) = delete; bool IsEmpty() const { return mSections.empty(); } void Clear() { mSections.clear(); mVertices.clear(); mConditionalVertices.clear(); } void SetMeshData(lcLibraryMeshData* MeshData) { mMeshData = MeshData; } lcMeshLoaderSection* AddSection(lcMeshPrimitiveType PrimitiveType, lcMeshLoaderMaterial* Material); quint32 AddVertex(const lcVector3& Position, bool Optimize); quint32 AddVertex(const lcVector3& Position, const lcVector3& Normal, float NormalWeight, bool Optimize); quint32 AddConditionalVertex(const lcVector3 (&Position)[4]); void ProcessLine(int LineType, lcMeshLoaderMaterial* Material, bool WindingCCW, lcVector3 (&Vertices)[4], bool Optimize); void AddMeshData(const lcMeshLoaderTypeData& Data, const lcMatrix44& Transform, quint32 CurrentColorCode, bool InvertWinding, bool InvertNormals, lcMeshLoaderTextureMap* TextureMap); void AddMeshDataNoDuplicateCheck(const lcMeshLoaderTypeData& Data, const lcMatrix44& Transform, quint32 CurrentColorCode, bool InvertWinding, bool InvertNormals, lcMeshLoaderTextureMap* TextureMap); std::vector> mSections; std::vector mVertices; std::vector mConditionalVertices; protected: lcLibraryMeshData* mMeshData = nullptr; }; class lcLibraryMeshData { public: lcLibraryMeshData() { mHasTextures = false; mHasStyleStud = false; for (lcMeshLoaderTypeData& Data : mData) Data.SetMeshData(this); } lcLibraryMeshData(const lcLibraryMeshData&) = delete; lcLibraryMeshData& operator=(const lcLibraryMeshData&) = delete; bool IsEmpty() const { for (const lcMeshLoaderTypeData& Data : mData) if (!Data.IsEmpty()) return false; return true; } void Clear() { for (lcMeshLoaderTypeData& Data : mData) Data.Clear(); mHasTextures = false; mHasStyleStud = false; } void SetMeshLoader(lcMeshLoader* MeshLoader) { mMeshLoader = MeshLoader; } lcMesh* CreateMesh(); void AddVertices(lcMeshDataType MeshDataType, size_t VertexCount, int* BaseVertex, lcMeshLoaderVertex** VertexBuffer); void AddIndices(lcMeshDataType MeshDataType, lcMeshPrimitiveType PrimitiveType, quint32 ColorCode, size_t IndexCount, quint32** IndexBuffer); void AddMeshData(const lcLibraryMeshData& Data, const lcMatrix44& Transform, quint32 CurrentColorCode, bool InvertWinding, bool InvertNormals, lcMeshLoaderTextureMap* TextureMap, lcMeshDataType OverrideDestIndex); void AddMeshDataNoDuplicateCheck(const lcLibraryMeshData& Data, const lcMatrix44& Transform, quint32 CurrentColorCode, bool InvertWinding, bool InvertNormals, lcMeshLoaderTextureMap* TextureMap, lcMeshDataType OverrideDestIndex); lcMeshLoaderMaterial* GetMaterial(quint32 ColorCode); lcMeshLoaderMaterial* GetTexturedMaterial(quint32 ColorCode, const lcMeshLoaderTextureMap& TextureMap); std::array mData; bool mHasTextures; bool mHasStyleStud; protected: lcMeshLoader* mMeshLoader = nullptr; std::vector> mMaterials; std::vector mTexturedVertices; void GenerateTexturedVertices(); void GeneratePlanarTexcoords(lcMeshLoaderSection* Section, const lcMeshLoaderTypeData& Data); void GenerateCylindricalTexcoords(lcMeshLoaderSection* Section, const lcMeshLoaderTypeData& Data); void GenerateSphericalTexcoords(lcMeshLoaderSection* Section, const lcMeshLoaderTypeData& Data); quint32 AddTexturedVertex(const lcVector3& Position, const lcVector3& Normal, const lcVector2& TexCoords); template void WriteSections(lcMesh* Mesh, const std::vector (&FinalSections)[LC_NUM_MESH_LODS], int (&BaseVertices)[LC_NUM_MESHDATA_TYPES], int (&BaseConditionalVertices)[LC_NUM_MESHDATA_TYPES]); static void UpdateMeshBoundingBox(lcMesh* Mesh); template static void UpdateMeshSectionBoundingBox(const lcMesh* Mesh, const lcMeshSection& Section, lcVector3& SectionMin, lcVector3& SectionMax); }; class lcMeshLoader { public: lcMeshLoader(lcLibraryMeshData& MeshData, bool Optimize, Project* CurrentProject, bool SearchProjectFolder); bool LoadMesh(lcFile& File, lcMeshDataType MeshDataType); Project* mCurrentProject; bool mSearchProjectFolder; protected: bool ReadMeshData(lcFile& File, const lcMatrix44& CurrentTransform, quint32 CurrentColorCode, bool InvertWinding, lcMeshDataType MeshDataType); std::vector mTextureStack; lcLibraryMeshData& mMeshData; bool mOptimize; };