diff --git a/common/lc_global.h b/common/lc_global.h index 410014e4..d6f449d9 100644 --- a/common/lc_global.h +++ b/common/lc_global.h @@ -74,6 +74,7 @@ struct lcMeshSection; struct lcRenderMesh; class lcTexture; class lcScene; +enum class lcRenderMeshState : int; class lcFile; class lcMemFile; diff --git a/common/lc_mesh.h b/common/lc_mesh.h index 63ee5b78..c32e6e35 100644 --- a/common/lc_mesh.h +++ b/common/lc_mesh.h @@ -112,24 +112,5 @@ public: int mIndexType; }; -enum class lcRenderMeshState : int -{ - NORMAL, - SELECTED, - FOCUSED, - DISABLED, - HIGHLIGHT -}; - -struct lcRenderMesh -{ - lcMatrix44 WorldMatrix; - lcMesh* Mesh; - float Distance; - int ColorIndex; - int LodIndex; - lcRenderMeshState State; -}; - extern lcMesh* gPlaceholderMesh; diff --git a/common/lc_model.h b/common/lc_model.h index 0091308b..f1ad7866 100644 --- a/common/lc_model.h +++ b/common/lc_model.h @@ -19,7 +19,6 @@ #define LC_SEL_CAN_REMOVE_CONTROL_POINT 0x1000 // Can remove control points from focused piece class lcGLWidget; -enum class lcRenderMeshState : int; enum class lcSelectionMode { diff --git a/common/lc_scene.cpp b/common/lc_scene.cpp index 5164c7f5..19e05e3c 100644 --- a/common/lc_scene.cpp +++ b/common/lc_scene.cpp @@ -43,9 +43,9 @@ void lcScene::End() std::sort(mOpaqueMeshes.begin(), mOpaqueMeshes.end(), OpaqueMeshCompare); - auto TranslucentMeshCompare = [this](int Index1, int Index2) + auto TranslucentMeshCompare = [this](const lcTranslucentMeshInstance& Mesh1, const lcTranslucentMeshInstance& Mesh2) { - return mRenderMeshes[Index1].Distance > mRenderMeshes[Index2].Distance; + return Mesh1.Distance > Mesh2.Distance; }; std::sort(mTranslucentMeshes.begin(), mTranslucentMeshes.end(), TranslucentMeshCompare); @@ -59,8 +59,8 @@ void lcScene::AddMesh(lcMesh* Mesh, const lcMatrix44& WorldMatrix, int ColorInde RenderMesh.Mesh = Mesh; RenderMesh.ColorIndex = ColorIndex; RenderMesh.State = State; - RenderMesh.Distance = fabsf(lcMul31(WorldMatrix[3], mViewMatrix).z); - RenderMesh.LodIndex = RenderMesh.Mesh->GetLodIndex(RenderMesh.Distance); + float Distance = fabsf(lcMul31(WorldMatrix[3], mViewMatrix).z); + RenderMesh.LodIndex = RenderMesh.Mesh->GetLodIndex(Distance); bool Translucent = lcIsColorTranslucent(ColorIndex); lcMeshFlags Flags = Mesh->mFlags; @@ -69,21 +69,60 @@ void lcScene::AddMesh(lcMesh* Mesh, const lcMatrix44& WorldMatrix, int ColorInde mOpaqueMeshes.Add(mRenderMeshes.GetSize() - 1); if ((Flags & lcMeshFlag::HasTranslucent) || ((Flags & lcMeshFlag::HasDefault) && Translucent)) - mTranslucentMeshes.Add(mRenderMeshes.GetSize() - 1); + { + const lcMeshLod& Lod = Mesh->mLods[RenderMesh.LodIndex]; + + for (int SectionIdx = 0; SectionIdx < Lod.NumSections; SectionIdx++) + { + const lcMeshSection* Section = &Lod.Sections[SectionIdx]; + + if ((Section->PrimitiveType & (LC_MESH_TRIANGLES | LC_MESH_TEXTURED_TRIANGLES)) == 0) + continue; + + int ColorIndex = Section->ColorIndex; + + if (ColorIndex == gDefaultColor) + ColorIndex = RenderMesh.ColorIndex; + + if (!lcIsColorTranslucent(ColorIndex)) + continue; + + lcVector3 Center = (Section->BoundingBox.Min + Section->BoundingBox.Max) / 2; + float Distance = fabsf(lcMul31(lcMul31(Center, WorldMatrix), mViewMatrix).z); + + lcTranslucentMeshInstance& Instance = mTranslucentMeshes.Add(); + Instance.Section = Section; + Instance.Distance = Distance; + Instance.RenderMeshIndex = mRenderMeshes.GetSize() - 1; + } + } } -void lcScene::DrawPass(lcContext* Context, lcRenderPass RenderPass, int PrimitiveTypes) const +void lcScene::DrawDebugNormals(lcContext* Context, lcMesh* Mesh) const { - bool IsTranslucent = (RenderPass == lcRenderPass::UnlitTranslucent || RenderPass == lcRenderPass::LitTranslucent); - const lcArray& Meshes = IsTranslucent ? mTranslucentMeshes : mOpaqueMeshes; + lcVertex* VertexBuffer = (lcVertex*)Mesh->mVertexData; + lcVector3* Vertices = (lcVector3*)malloc(Mesh->mNumVertices * 2 * sizeof(lcVector3)); - if (Meshes.IsEmpty()) + for (int VertexIdx = 0; VertexIdx < Mesh->mNumVertices; VertexIdx++) + { + Vertices[VertexIdx * 2] = VertexBuffer[VertexIdx].Position; + Vertices[VertexIdx * 2 + 1] = VertexBuffer[VertexIdx].Position + lcUnpackNormal(VertexBuffer[VertexIdx].Normal); + } + + Context->SetVertexBufferPointer(Vertices); + Context->SetVertexFormatPosition(3); + Context->DrawPrimitives(GL_LINES, 0, Mesh->mNumVertices * 2); + free(Vertices); +} + +void lcScene::DrawOpaqueMeshes(lcContext* Context, bool DrawLit, int PrimitiveTypes) const +{ + if (mOpaqueMeshes.IsEmpty()) return; - bool IsLit = (RenderPass == lcRenderPass::LitOpaque || RenderPass == lcRenderPass::LitTranslucent); lcMaterialType FlatMaterial, TexturedMaterial; - if (IsLit) + if (DrawLit) { FlatMaterial = LC_MATERIAL_FAKELIT_COLOR; TexturedMaterial = LC_MATERIAL_FAKELIT_TEXTURE_DECAL; @@ -94,16 +133,9 @@ void lcScene::DrawPass(lcContext* Context, lcRenderPass RenderPass, int Primitiv TexturedMaterial = LC_MATERIAL_UNLIT_TEXTURE_DECAL; } - if (IsTranslucent) - { - glEnable(GL_BLEND); - Context->SetDepthWrite(false); - Context->SetPolygonOffset(LC_POLYGON_OFFSET_TRANSLUCENT); - } - else - Context->SetPolygonOffset(LC_POLYGON_OFFSET_OPAQUE); + Context->SetPolygonOffset(LC_POLYGON_OFFSET_OPAQUE); - for (int MeshIndex : Meshes) + for (int MeshIndex : mOpaqueMeshes) { const lcRenderMesh& RenderMesh = mRenderMeshes[MeshIndex]; const lcMesh* Mesh = RenderMesh.Mesh; @@ -126,7 +158,7 @@ void lcScene::DrawPass(lcContext* Context, lcRenderPass RenderPass, int Primitiv if (ColorIndex == gDefaultColor) ColorIndex = RenderMesh.ColorIndex; - if (lcIsColorTranslucent(ColorIndex) != IsTranslucent) + if (lcIsColorTranslucent(ColorIndex)) continue; switch (RenderMesh.State) @@ -184,7 +216,7 @@ void lcScene::DrawPass(lcContext* Context, lcRenderPass RenderPass, int Primitiv int IndexBufferOffset = Mesh->mIndexCacheOffset != -1 ? Mesh->mIndexCacheOffset : 0; int VertexBufferOffset = Mesh->mVertexCacheOffset != -1 ? Mesh->mVertexCacheOffset : 0; - Context->SetVertexFormat(VertexBufferOffset, 3, 1, 0, 0, IsLit); + Context->SetVertexFormat(VertexBufferOffset, 3, 1, 0, 0, DrawLit); if (Mesh->mIndexType == GL_UNSIGNED_SHORT) { @@ -227,13 +259,13 @@ void lcScene::DrawPass(lcContext* Context, lcRenderPass RenderPass, int Primitiv if (!Texture) { Context->SetMaterial(FlatMaterial); - Context->SetVertexFormat(VertexBufferOffset, 3, 1, 0, 0, IsLit); + Context->SetVertexFormat(VertexBufferOffset, 3, 1, 0, 0, DrawLit); } else { Context->SetMaterial(TexturedMaterial); VertexBufferOffset += Mesh->mNumVertices * sizeof(lcVertex); - Context->SetVertexFormat(VertexBufferOffset, 3, 1, 2, 0, IsLit); + Context->SetVertexFormat(VertexBufferOffset, 3, 1, 2, 0, DrawLit); Context->BindTexture2D(Texture->mTexture); } @@ -241,36 +273,102 @@ void lcScene::DrawPass(lcContext* Context, lcRenderPass RenderPass, int Primitiv Context->DrawIndexedPrimitives(DrawPrimitiveType, Section->NumIndices, Mesh->mIndexType, IndexBufferOffset + Section->IndexOffset); } -#ifdef QT_DEBUG - const bool DrawNormals = false; +#ifdef LC_DEBUG_NORMALS + DrawDebugNormals(Context, Mesh); +#endif + } - if (DrawNormals) + Context->BindTexture2D(0); + Context->SetPolygonOffset(LC_POLYGON_OFFSET_NONE); +} + +void lcScene::DrawTranslucentMeshes(lcContext* Context, bool DrawLit) const +{ + if (mTranslucentMeshes.IsEmpty()) + return; + + lcMaterialType FlatMaterial, TexturedMaterial; + + if (DrawLit) + { + FlatMaterial = LC_MATERIAL_FAKELIT_COLOR; + TexturedMaterial = LC_MATERIAL_FAKELIT_TEXTURE_DECAL; + } + else + { + FlatMaterial = LC_MATERIAL_UNLIT_COLOR; + TexturedMaterial = LC_MATERIAL_UNLIT_TEXTURE_DECAL; + } + + glEnable(GL_BLEND); + Context->SetDepthWrite(false); + Context->SetPolygonOffset(LC_POLYGON_OFFSET_TRANSLUCENT); + + for (const lcTranslucentMeshInstance& MeshInstance : mTranslucentMeshes) + { + const lcRenderMesh& RenderMesh = mRenderMeshes[MeshInstance.RenderMeshIndex]; + const lcMesh* Mesh = RenderMesh.Mesh; + + Context->BindMesh(Mesh); + Context->SetWorldMatrix(RenderMesh.WorldMatrix); + + const lcMeshSection* Section = MeshInstance.Section; + + int ColorIndex = Section->ColorIndex; + + if (ColorIndex == gDefaultColor) + ColorIndex = RenderMesh.ColorIndex; + + switch (RenderMesh.State) { - lcVertex* VertexBuffer = (lcVertex*)Mesh->mVertexData; - lcVector3* Vertices = (lcVector3*)malloc(Mesh->mNumVertices * 2 * sizeof(lcVector3)); + case lcRenderMeshState::NORMAL: + case lcRenderMeshState::HIGHLIGHT: + Context->SetColorIndex(ColorIndex); + break; - for (int VertexIdx = 0; VertexIdx < Mesh->mNumVertices; VertexIdx++) - { - Vertices[VertexIdx * 2] = VertexBuffer[VertexIdx].Position; - Vertices[VertexIdx * 2 + 1] = VertexBuffer[VertexIdx].Position + lcUnpackNormal(VertexBuffer[VertexIdx].Normal); - } + case lcRenderMeshState::SELECTED: + Context->SetColorIndexTinted(ColorIndex, LC_COLOR_SELECTED, 0.5f); + break; - Context->SetVertexBufferPointer(Vertices); - Context->SetVertexFormatPosition(3); - Context->DrawPrimitives(GL_LINES, 0, Mesh->mNumVertices * 2); - free(Vertices); + case lcRenderMeshState::FOCUSED: + Context->SetColorIndexTinted(ColorIndex, LC_COLOR_FOCUSED, 0.5f); + break; + + case lcRenderMeshState::DISABLED: + Context->SetColorIndexTinted(ColorIndex, LC_COLOR_DISABLED, 0.25f); + break; } + + lcTexture* Texture = Section->Texture; + int VertexBufferOffset = Mesh->mVertexCacheOffset != -1 ? Mesh->mVertexCacheOffset : 0; + int IndexBufferOffset = Mesh->mIndexCacheOffset != -1 ? Mesh->mIndexCacheOffset : 0; + + if (!Texture) + { + Context->SetMaterial(FlatMaterial); + Context->SetVertexFormat(VertexBufferOffset, 3, 1, 0, 0, DrawLit); + } + else + { + Context->SetMaterial(TexturedMaterial); + VertexBufferOffset += Mesh->mNumVertices * sizeof(lcVertex); + Context->SetVertexFormat(VertexBufferOffset, 3, 1, 2, 0, DrawLit); + Context->BindTexture2D(Texture->mTexture); + } + + GLenum DrawPrimitiveType = Section->PrimitiveType & (LC_MESH_TRIANGLES | LC_MESH_TEXTURED_TRIANGLES) ? GL_TRIANGLES : GL_LINES; + Context->DrawIndexedPrimitives(DrawPrimitiveType, Section->NumIndices, Mesh->mIndexType, IndexBufferOffset + Section->IndexOffset); + +#ifdef LC_DEBUG_NORMALS + DrawDebugNormals(Context, Mesh); #endif } Context->BindTexture2D(0); Context->SetPolygonOffset(LC_POLYGON_OFFSET_NONE); - if (IsTranslucent) - { - Context->SetDepthWrite(true); - glDisable(GL_BLEND); - } + Context->SetDepthWrite(true); + glDisable(GL_BLEND); } void lcScene::Draw(lcContext* Context) const @@ -295,7 +393,7 @@ void lcScene::Draw(lcContext* Context) const if (DrawConditional) PrimitiveTypes |= LC_MESH_CONDITIONAL_LINES; - DrawPass(Context, lcRenderPass::UnlitOpaque, PrimitiveTypes); + DrawOpaqueMeshes(Context, false, PrimitiveTypes); } else if (ShadingMode == LC_SHADING_FLAT) { @@ -311,8 +409,8 @@ void lcScene::Draw(lcContext* Context) const PrimitiveTypes |= LC_MESH_CONDITIONAL_LINES; } - DrawPass(Context, lcRenderPass::UnlitOpaque, PrimitiveTypes); - DrawPass(Context, lcRenderPass::UnlitTranslucent, LC_MESH_TRIANGLES | LC_MESH_TEXTURED_TRIANGLES); + DrawOpaqueMeshes(Context, false, PrimitiveTypes); + DrawTranslucentMeshes(Context, false); } else { @@ -325,11 +423,11 @@ void lcScene::Draw(lcContext* Context) const if (DrawConditional) PrimitiveTypes |= LC_MESH_CONDITIONAL_LINES; - DrawPass(Context, lcRenderPass::UnlitOpaque, PrimitiveTypes); + DrawOpaqueMeshes(Context, false, PrimitiveTypes); } - DrawPass(Context, lcRenderPass::LitOpaque, LC_MESH_TRIANGLES | LC_MESH_TEXTURED_TRIANGLES); - DrawPass(Context, lcRenderPass::LitTranslucent, LC_MESH_TRIANGLES | LC_MESH_TEXTURED_TRIANGLES); + DrawOpaqueMeshes(Context, true, LC_MESH_TRIANGLES | LC_MESH_TEXTURED_TRIANGLES); + DrawTranslucentMeshes(Context, true); } } diff --git a/common/lc_scene.h b/common/lc_scene.h index ef900603..3baf577a 100644 --- a/common/lc_scene.h +++ b/common/lc_scene.h @@ -3,12 +3,29 @@ #include "lc_mesh.h" #include "lc_array.h" -enum class lcRenderPass +enum class lcRenderMeshState : int { - UnlitOpaque, - UnlitTranslucent, - LitOpaque, - LitTranslucent + NORMAL, + SELECTED, + FOCUSED, + DISABLED, + HIGHLIGHT +}; + +struct lcRenderMesh +{ + lcMatrix44 WorldMatrix; + lcMesh* Mesh; + int ColorIndex; + int LodIndex; + lcRenderMeshState State; +}; + +struct lcTranslucentMeshInstance +{ + const lcMeshSection* Section; + int RenderMeshIndex; + float Distance; }; class lcScene @@ -65,7 +82,9 @@ public: void DrawInterfaceObjects(lcContext* Context) const; protected: - void DrawPass(lcContext* Context, lcRenderPass RenderPass, int PrimitiveTypes) const; + void DrawOpaqueMeshes(lcContext* Context, bool DrawLit, int PrimitiveTypes) const; + void DrawTranslucentMeshes(lcContext* Context, bool DrawLit) const; + void DrawDebugNormals(lcContext* Context, lcMesh* Mesh) const; lcMatrix44 mViewMatrix; lcMatrix44 mActiveSubmodelTransform; @@ -75,6 +94,6 @@ protected: lcArray mRenderMeshes; lcArray mOpaqueMeshes; - lcArray mTranslucentMeshes; + lcArray mTranslucentMeshes; lcArray mInterfaceObjects; }; diff --git a/common/piece.h b/common/piece.h index dd866e94..7044606e 100644 --- a/common/piece.h +++ b/common/piece.h @@ -1,7 +1,6 @@ #pragma once class PieceInfo; -enum class lcRenderMeshState : int; #include "object.h" #include "lc_colors.h"