leocad/common/lc_scene.cpp

439 lines
13 KiB
C++
Raw Normal View History

2017-04-02 01:53:54 +02:00
#include "lc_global.h"
#include "lc_scene.h"
#include "lc_context.h"
#include "pieceinf.h"
#include "lc_texture.h"
#include "lc_library.h"
#include "lc_application.h"
#include "object.h"
lcScene::lcScene()
: mRenderMeshes(0, 1024), mOpaqueMeshes(0, 1024), mTranslucentMeshes(0, 1024), mInterfaceObjects(0, 1024)
{
mActiveSubmodelInstance = nullptr;
mAllowWireframe = true;
2017-04-02 01:53:54 +02:00
}
void lcScene::Begin(const lcMatrix44& ViewMatrix)
{
mViewMatrix = ViewMatrix;
mActiveSubmodelInstance = nullptr;
mDrawInterface = false;
2017-04-02 01:53:54 +02:00
mRenderMeshes.RemoveAll();
mOpaqueMeshes.RemoveAll();
mTranslucentMeshes.RemoveAll();
mInterfaceObjects.RemoveAll();
}
void lcScene::End()
{
auto OpaqueMeshCompare = [this](int Index1, int Index2)
{
const lcMesh* Mesh1 = mRenderMeshes[Index1].Mesh;
const lcMesh* Mesh2 = mRenderMeshes[Index2].Mesh;
int Texture1 = Mesh1->mFlags & lcMeshFlag::HasTexture;
int Texture2 = Mesh2->mFlags & lcMeshFlag::HasTexture;
if (Texture1 == Texture2)
return Mesh1 < Mesh2;
return Texture1 ? false : true;
2017-04-02 01:53:54 +02:00
};
2019-03-29 01:59:58 +01:00
std::sort(mOpaqueMeshes.begin(), mOpaqueMeshes.end(), OpaqueMeshCompare);
2017-04-02 01:53:54 +02:00
2019-11-23 01:47:58 +01:00
auto TranslucentMeshCompare = [this](const lcTranslucentMeshInstance& Mesh1, const lcTranslucentMeshInstance& Mesh2)
2017-04-02 01:53:54 +02:00
{
2019-11-23 01:47:58 +01:00
return Mesh1.Distance > Mesh2.Distance;
2017-04-02 01:53:54 +02:00
};
2019-03-29 01:59:58 +01:00
std::sort(mTranslucentMeshes.begin(), mTranslucentMeshes.end(), TranslucentMeshCompare);
2017-04-02 01:53:54 +02:00
}
2019-07-21 17:56:37 +02:00
void lcScene::AddMesh(lcMesh* Mesh, const lcMatrix44& WorldMatrix, int ColorIndex, lcRenderMeshState State)
2017-04-02 01:53:54 +02:00
{
lcRenderMesh& RenderMesh = mRenderMeshes.Add();
RenderMesh.WorldMatrix = WorldMatrix;
RenderMesh.Mesh = Mesh;
RenderMesh.ColorIndex = ColorIndex;
RenderMesh.State = State;
2019-11-23 01:47:58 +01:00
float Distance = fabsf(lcMul31(WorldMatrix[3], mViewMatrix).z);
RenderMesh.LodIndex = RenderMesh.Mesh->GetLodIndex(Distance);
2017-04-02 01:53:54 +02:00
bool Translucent = lcIsColorTranslucent(ColorIndex);
2019-07-21 17:56:37 +02:00
lcMeshFlags Flags = Mesh->mFlags;
2017-04-02 01:53:54 +02:00
2019-07-21 17:56:37 +02:00
if ((Flags & (lcMeshFlag::HasSolid | lcMeshFlag::HasLines)) || ((Flags & lcMeshFlag::HasDefault) && !Translucent))
2017-04-02 01:53:54 +02:00
mOpaqueMeshes.Add(mRenderMeshes.GetSize() - 1);
2019-07-21 17:56:37 +02:00
if ((Flags & lcMeshFlag::HasTranslucent) || ((Flags & lcMeshFlag::HasDefault) && Translucent))
2019-11-23 01:47:58 +01:00
{
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;
}
}
2017-04-02 01:53:54 +02:00
}
2019-11-23 01:47:58 +01:00
void lcScene::DrawDebugNormals(lcContext* Context, lcMesh* Mesh) const
2017-04-02 01:53:54 +02:00
{
2019-11-23 01:47:58 +01:00
lcVertex* VertexBuffer = (lcVertex*)Mesh->mVertexData;
lcVector3* Vertices = (lcVector3*)malloc(Mesh->mNumVertices * 2 * sizeof(lcVector3));
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);
}
2019-11-23 01:47:58 +01:00
void lcScene::DrawOpaqueMeshes(lcContext* Context, bool DrawLit, int PrimitiveTypes) const
{
if (mOpaqueMeshes.IsEmpty())
return;
lcMaterialType FlatMaterial, TexturedMaterial;
2019-11-23 01:47:58 +01:00
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;
}
2019-11-23 01:47:58 +01:00
Context->SetPolygonOffset(LC_POLYGON_OFFSET_OPAQUE);
2017-04-02 01:53:54 +02:00
2019-11-23 01:47:58 +01:00
for (int MeshIndex : mOpaqueMeshes)
2017-04-02 01:53:54 +02:00
{
const lcRenderMesh& RenderMesh = mRenderMeshes[MeshIndex];
const lcMesh* Mesh = RenderMesh.Mesh;
int LodIndex = RenderMesh.LodIndex;
Context->BindMesh(Mesh);
Context->SetWorldMatrix(RenderMesh.WorldMatrix);
for (int SectionIdx = 0; SectionIdx < Mesh->mLods[LodIndex].NumSections; SectionIdx++)
{
lcMeshSection* Section = &Mesh->mLods[LodIndex].Sections[SectionIdx];
if ((Section->PrimitiveType & PrimitiveTypes) == 0)
2017-04-02 01:53:54 +02:00
continue;
int ColorIndex = Section->ColorIndex;
if (Section->PrimitiveType & (LC_MESH_TRIANGLES | LC_MESH_TEXTURED_TRIANGLES))
{
if (ColorIndex == gDefaultColor)
ColorIndex = RenderMesh.ColorIndex;
2019-11-23 01:47:58 +01:00
if (lcIsColorTranslucent(ColorIndex))
2017-04-02 01:53:54 +02:00
continue;
switch (RenderMesh.State)
{
case lcRenderMeshState::NORMAL:
case lcRenderMeshState::HIGHLIGHT:
2017-04-02 01:53:54 +02:00
Context->SetColorIndex(ColorIndex);
break;
case lcRenderMeshState::SELECTED:
Context->SetColorIndexTinted(ColorIndex, LC_COLOR_SELECTED, 0.5f);
2017-04-02 01:53:54 +02:00
break;
case lcRenderMeshState::FOCUSED:
Context->SetColorIndexTinted(ColorIndex, LC_COLOR_FOCUSED, 0.5f);
break;
case lcRenderMeshState::DISABLED:
Context->SetColorIndexTinted(ColorIndex, LC_COLOR_DISABLED, 0.25f);
2017-04-02 01:53:54 +02:00
break;
}
}
2019-11-02 19:38:24 +01:00
else if (Section->PrimitiveType & LC_MESH_LINES)
2017-04-02 01:53:54 +02:00
{
switch (RenderMesh.State)
{
case lcRenderMeshState::NORMAL:
2017-04-02 01:53:54 +02:00
if (ColorIndex == gEdgeColor)
Context->SetEdgeColorIndex(RenderMesh.ColorIndex);
else
Context->SetColorIndex(ColorIndex);
break;
case lcRenderMeshState::SELECTED:
2017-04-02 01:53:54 +02:00
Context->SetInterfaceColor(LC_COLOR_SELECTED);
break;
case lcRenderMeshState::FOCUSED:
2017-04-02 01:53:54 +02:00
Context->SetInterfaceColor(LC_COLOR_FOCUSED);
break;
case lcRenderMeshState::HIGHLIGHT:
Context->SetInterfaceColor(LC_COLOR_HIGHLIGHT);
break;
case lcRenderMeshState::DISABLED:
Context->SetInterfaceColor(LC_COLOR_DISABLED);
break;
2017-04-02 01:53:54 +02:00
}
}
else if (Section->PrimitiveType == LC_MESH_CONDITIONAL_LINES)
{
lcMatrix44 WorldViewProjectionMatrix = lcMul(RenderMesh.WorldMatrix, lcMul(mViewMatrix, Context->GetProjectionMatrix()));
lcVertex* VertexBuffer = (lcVertex*)Mesh->mVertexData;
int IndexBufferOffset = Mesh->mIndexCacheOffset != -1 ? Mesh->mIndexCacheOffset : 0;
2017-06-23 03:45:45 +02:00
int VertexBufferOffset = Mesh->mVertexCacheOffset != -1 ? Mesh->mVertexCacheOffset : 0;
2019-11-23 01:47:58 +01:00
Context->SetVertexFormat(VertexBufferOffset, 3, 1, 0, 0, DrawLit);
2017-06-23 03:45:45 +02:00
2017-04-02 01:53:54 +02:00
if (Mesh->mIndexType == GL_UNSIGNED_SHORT)
{
2017-12-02 21:22:04 +01:00
quint16* Indices = (quint16*)((char*)Mesh->mIndexData + Section->IndexOffset);
2017-04-02 01:53:54 +02:00
for (int i = 0; i < Section->NumIndices; i += 4)
{
lcVector3 p1 = lcMul31(VertexBuffer[Indices[i + 0]].Position, WorldViewProjectionMatrix);
lcVector3 p2 = lcMul31(VertexBuffer[Indices[i + 1]].Position, WorldViewProjectionMatrix);
lcVector3 p3 = lcMul31(VertexBuffer[Indices[i + 2]].Position, WorldViewProjectionMatrix);
lcVector3 p4 = lcMul31(VertexBuffer[Indices[i + 3]].Position, WorldViewProjectionMatrix);
if (((p1.y - p2.y) * (p3.x - p1.x) + (p2.x - p1.x) * (p3.y - p1.y)) * ((p1.y - p2.y) * (p4.x - p1.x) + (p2.x - p1.x) * (p4.y - p1.y)) >= 0)
2017-12-02 21:22:04 +01:00
Context->DrawIndexedPrimitives(GL_LINES, 2, Mesh->mIndexType, IndexBufferOffset + Section->IndexOffset + i * sizeof(quint16));
2017-04-02 01:53:54 +02:00
}
}
else
{
2017-12-02 21:22:04 +01:00
quint32* Indices = (quint32*)((char*)Mesh->mIndexData + Section->IndexOffset);
2017-04-02 01:53:54 +02:00
for (int i = 0; i < Section->NumIndices; i += 4)
{
lcVector3 p1 = lcMul31(VertexBuffer[Indices[i + 0]].Position, WorldViewProjectionMatrix);
lcVector3 p2 = lcMul31(VertexBuffer[Indices[i + 1]].Position, WorldViewProjectionMatrix);
lcVector3 p3 = lcMul31(VertexBuffer[Indices[i + 2]].Position, WorldViewProjectionMatrix);
lcVector3 p4 = lcMul31(VertexBuffer[Indices[i + 3]].Position, WorldViewProjectionMatrix);
if (((p1.y - p2.y) * (p3.x - p1.x) + (p2.x - p1.x) * (p3.y - p1.y)) * ((p1.y - p2.y) * (p4.x - p1.x) + (p2.x - p1.x) * (p4.y - p1.y)) >= 0)
2017-12-02 21:22:04 +01:00
Context->DrawIndexedPrimitives(GL_LINES, 2, Mesh->mIndexType, IndexBufferOffset + Section->IndexOffset + i * sizeof(quint32));
2017-04-02 01:53:54 +02:00
}
}
2017-06-23 03:45:45 +02:00
continue;
2017-04-02 01:53:54 +02:00
}
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);
2019-11-23 01:47:58 +01:00
Context->SetVertexFormat(VertexBufferOffset, 3, 1, 0, 0, DrawLit);
2017-04-02 01:53:54 +02:00
}
else
{
Context->SetMaterial(TexturedMaterial);
2017-04-02 01:53:54 +02:00
VertexBufferOffset += Mesh->mNumVertices * sizeof(lcVertex);
2019-11-23 01:47:58 +01:00
Context->SetVertexFormat(VertexBufferOffset, 3, 1, 2, 0, DrawLit);
2017-12-26 19:19:20 +01:00
Context->BindTexture2D(Texture->mTexture);
2017-04-02 01:53:54 +02:00
}
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);
}
2019-11-23 01:47:58 +01:00
#ifdef LC_DEBUG_NORMALS
DrawDebugNormals(Context, Mesh);
#endif
}
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;
2017-04-02 01:53:54 +02:00
2019-11-23 01:47:58 +01:00
int ColorIndex = Section->ColorIndex;
if (ColorIndex == gDefaultColor)
ColorIndex = RenderMesh.ColorIndex;
switch (RenderMesh.State)
2017-04-02 01:53:54 +02:00
{
2019-11-23 01:47:58 +01:00
case lcRenderMeshState::NORMAL:
case lcRenderMeshState::HIGHLIGHT:
Context->SetColorIndex(ColorIndex);
break;
case lcRenderMeshState::SELECTED:
Context->SetColorIndexTinted(ColorIndex, LC_COLOR_SELECTED, 0.5f);
break;
case lcRenderMeshState::FOCUSED:
Context->SetColorIndexTinted(ColorIndex, LC_COLOR_FOCUSED, 0.5f);
break;
case lcRenderMeshState::DISABLED:
Context->SetColorIndexTinted(ColorIndex, LC_COLOR_DISABLED, 0.25f);
break;
}
2017-04-02 01:53:54 +02:00
2019-11-23 01:47:58 +01:00
lcTexture* Texture = Section->Texture;
int VertexBufferOffset = Mesh->mVertexCacheOffset != -1 ? Mesh->mVertexCacheOffset : 0;
int IndexBufferOffset = Mesh->mIndexCacheOffset != -1 ? Mesh->mIndexCacheOffset : 0;
2017-04-02 01:53:54 +02:00
2019-11-23 01:47:58 +01:00
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);
2017-04-02 01:53:54 +02:00
}
2019-11-23 01:47:58 +01:00
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);
2017-04-02 01:53:54 +02:00
#endif
}
2019-11-18 23:32:53 +01:00
Context->BindTexture2D(0);
Context->SetPolygonOffset(LC_POLYGON_OFFSET_NONE);
2019-11-23 01:47:58 +01:00
Context->SetDepthWrite(true);
glDisable(GL_BLEND);
2017-04-02 01:53:54 +02:00
}
void lcScene::Draw(lcContext* Context) const
{
// TODO: find a better place for these updates
lcGetPiecesLibrary()->UpdateBuffers(Context);
lcGetPiecesLibrary()->UploadTextures(Context);
2017-04-02 01:53:54 +02:00
Context->SetViewMatrix(mViewMatrix);
2017-06-23 03:45:45 +02:00
const bool DrawConditional = false;
const lcPreferences& Preferences = lcGetPreferences();
2017-06-23 03:45:45 +02:00
lcShadingMode ShadingMode = Preferences.mShadingMode;
if (ShadingMode == LC_SHADING_WIREFRAME && !mAllowWireframe)
ShadingMode = LC_SHADING_FLAT;
2017-08-25 21:57:14 +02:00
if (ShadingMode == LC_SHADING_WIREFRAME)
2017-04-02 01:53:54 +02:00
{
int PrimitiveTypes = LC_MESH_LINES;
if (DrawConditional)
PrimitiveTypes |= LC_MESH_CONDITIONAL_LINES;
2017-08-25 21:57:14 +02:00
2019-11-23 01:47:58 +01:00
DrawOpaqueMeshes(Context, false, PrimitiveTypes);
}
else if (ShadingMode == LC_SHADING_FLAT)
{
bool DrawLines = Preferences.mDrawEdgeLines && Preferences.mLineWidth != 0.0f;
2017-04-02 01:53:54 +02:00
int PrimitiveTypes = LC_MESH_TRIANGLES | LC_MESH_TEXTURED_TRIANGLES;
2017-06-23 03:45:45 +02:00
2017-04-02 01:53:54 +02:00
if (DrawLines)
2017-06-23 03:45:45 +02:00
{
PrimitiveTypes |= LC_MESH_LINES;
2017-06-23 03:45:45 +02:00
if (DrawConditional)
PrimitiveTypes |= LC_MESH_CONDITIONAL_LINES;
}
2019-11-23 01:47:58 +01:00
DrawOpaqueMeshes(Context, false, PrimitiveTypes);
DrawTranslucentMeshes(Context, false);
2017-04-02 01:53:54 +02:00
}
else
{
bool DrawLines = Preferences.mDrawEdgeLines && Preferences.mLineWidth != 0.0f;
2017-04-02 01:53:54 +02:00
if (DrawLines)
{
int PrimitiveTypes = LC_MESH_LINES;
2017-06-23 03:45:45 +02:00
if (DrawConditional)
PrimitiveTypes |= LC_MESH_CONDITIONAL_LINES;
2017-06-23 03:45:45 +02:00
2019-11-23 01:47:58 +01:00
DrawOpaqueMeshes(Context, false, PrimitiveTypes);
2017-04-02 01:53:54 +02:00
}
2019-11-23 01:47:58 +01:00
DrawOpaqueMeshes(Context, true, LC_MESH_TRIANGLES | LC_MESH_TEXTURED_TRIANGLES);
DrawTranslucentMeshes(Context, true);
2017-04-02 01:53:54 +02:00
}
}
void lcScene::DrawInterfaceObjects(lcContext* Context) const
{
for (const lcObject* Object : mInterfaceObjects)
Object->DrawInterface(Context, *this);
2017-04-02 01:53:54 +02:00
}