Reorganized scene and context classes.

This commit is contained in:
Leonardo Zide 2017-04-01 16:53:54 -07:00
parent a77a8e1485
commit b9726a2a99
16 changed files with 400 additions and 505 deletions

View file

@ -77,6 +77,16 @@ public:
return true;
}
T* begin() const
{
return &mData[0];
}
T* end() const
{
return &mData[0] + mLength;
}
bool IsEmpty() const
{
return mLength == 0;

View file

@ -6,7 +6,6 @@
#include "lc_colors.h"
#include "lc_mainwindow.h"
#include "lc_library.h"
#include "pieceinf.h"
#ifdef LC_OPENGLES
#define glEnableClientState(...)
@ -21,61 +20,6 @@
lcProgram lcContext::mPrograms[LC_NUM_MATERIALS];
lcScene::lcScene()
: mRenderMeshes(0, 1024), mOpaqueMeshes(0, 1024), mTranslucentMeshes(0, 1024), mInterfaceObjects(0, 1024)
{
}
void lcScene::Begin(const lcMatrix44& ViewMatrix)
{
mViewMatrix = ViewMatrix;
mRenderMeshes.RemoveAll();
mOpaqueMeshes.RemoveAll();
mTranslucentMeshes.RemoveAll();
mInterfaceObjects.RemoveAll();
mHasTexture = false;
}
void lcScene::End()
{
auto OpaqueMeshCompare = [this](int Index1, int Index2)
{
return mRenderMeshes[Index1].Mesh < mRenderMeshes[Index2].Mesh;
};
std::sort(&mOpaqueMeshes[0], &mOpaqueMeshes[0] + mOpaqueMeshes.GetSize(), OpaqueMeshCompare);
auto TranslucentMeshCompare = [this](int Index1, int Index2)
{
return mRenderMeshes[Index1].Distance < mRenderMeshes[Index2].Distance;
};
std::sort(&mTranslucentMeshes[0], &mTranslucentMeshes[0] + mTranslucentMeshes.GetSize(), TranslucentMeshCompare);
}
void lcScene::AddMesh(lcMesh* Mesh, const lcMatrix44& WorldMatrix, int ColorIndex, lcRenderMeshState State, int Flags)
{
lcRenderMesh& RenderMesh = mRenderMeshes.Add();
RenderMesh.WorldMatrix = WorldMatrix;
RenderMesh.Mesh = Mesh;
RenderMesh.ColorIndex = ColorIndex;
RenderMesh.State = State;
RenderMesh.Distance = fabsf(lcMul31(WorldMatrix[3], mViewMatrix).z);
RenderMesh.LodIndex = RenderMesh.Mesh->GetLodIndex(RenderMesh.Distance);
bool Translucent = lcIsColorTranslucent(ColorIndex);
if ((Flags & (LC_PIECE_HAS_SOLID | LC_PIECE_HAS_LINES)) || ((Flags & LC_PIECE_HAS_DEFAULT) && !Translucent))
mOpaqueMeshes.Add(mRenderMeshes.GetSize() - 1);
if ((Flags & LC_PIECE_HAS_TRANSLUCENT) || ((Flags & LC_PIECE_HAS_DEFAULT) && Translucent))
mTranslucentMeshes.Add(mRenderMeshes.GetSize() - 1);
if (Flags & LC_PIECE_HAS_TEXTURE)
mHasTexture = true;
}
lcContext::lcContext()
{
mVertexBufferObject = 0;
@ -470,7 +414,7 @@ void lcContext::ClearResources()
{
ClearVertexBuffer();
ClearIndexBuffer();
SetTexture(0);
BindTexture(0);
}
void lcContext::SetMaterial(lcMaterialType MaterialType)
@ -544,7 +488,7 @@ void lcContext::SetLineWidth(float LineWidth)
mLineWidth = LineWidth;
}
void lcContext::SetTexture(GLuint Texture)
void lcContext::BindTexture(GLuint Texture)
{
if (mTexture == Texture)
return;
@ -588,7 +532,7 @@ bool lcContext::BeginRenderToTexture(int Width, int Height)
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mFramebufferObject);
SetTexture(mFramebufferTexture);
BindTexture(mFramebufferTexture);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Width, Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mFramebufferTexture, 0);
@ -597,7 +541,7 @@ bool lcContext::BeginRenderToTexture(int Width, int Height)
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, Width, Height);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mDepthRenderbufferObject);
SetTexture(0);
BindTexture(0);
glBindFramebuffer(GL_FRAMEBUFFER, mFramebufferObject);
if (glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
@ -615,7 +559,7 @@ bool lcContext::BeginRenderToTexture(int Width, int Height)
glGenFramebuffersEXT(1, &mFramebufferObject);
glGenTextures(1, &mFramebufferTexture);
SetTexture(mFramebufferTexture);
BindTexture(mFramebufferTexture);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, Width, Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
@ -630,7 +574,7 @@ bool lcContext::BeginRenderToTexture(int Width, int Height)
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, mDepthRenderbufferObject);
SetTexture(0);
BindTexture(0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFramebufferObject);
if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT)
@ -1121,7 +1065,7 @@ void lcContext::SetIndexBufferPointer(const void* IndexBuffer)
mIndexBufferPointer = (char*)IndexBuffer;
}
void lcContext::BindMesh(lcMesh* Mesh)
void lcContext::BindMesh(const lcMesh* Mesh)
{
lcPiecesLibrary* Library = lcGetPiecesLibrary();
@ -1256,393 +1200,3 @@ void lcContext::DrawIndexedPrimitives(GLenum Mode, GLsizei Count, GLenum Type, i
FlushState();
glDrawElements(Mode, Count, Type, mIndexBufferPointer + Offset);
}
void lcContext::DrawMeshSection(lcMesh* Mesh, lcMeshSection* Section)
{
lcTexture* Texture = Section->Texture;
int VertexBufferOffset = Mesh->mVertexCacheOffset != -1 ? Mesh->mVertexCacheOffset : 0;
int IndexBufferOffset = Mesh->mIndexCacheOffset != -1 ? Mesh->mIndexCacheOffset : 0;
lcLightingMode LightingMode = lcGetPreferences().mLightingMode;
if (!Texture)
{
SetMaterial(LightingMode == LC_LIGHTING_UNLIT ? LC_MATERIAL_UNLIT_COLOR : LC_MATERIAL_FAKELIT_COLOR);
SetVertexFormat(VertexBufferOffset, 3, 1, 0, 0, LightingMode != LC_LIGHTING_UNLIT);
SetTexture(0);
}
else
{
VertexBufferOffset += Mesh->mNumVertices * sizeof(lcVertex);
SetMaterial(LightingMode == LC_LIGHTING_UNLIT ? LC_MATERIAL_UNLIT_TEXTURE_DECAL : LC_MATERIAL_FAKELIT_TEXTURE_DECAL);
SetVertexFormat(VertexBufferOffset, 3, 1, 2, 0, LightingMode != LC_LIGHTING_UNLIT);
SetTexture(Texture->mTexture);
}
const bool DrawConditional = false;
if (Section->PrimitiveType != LC_MESH_CONDITIONAL_LINES)
{
GLenum PrimitiveType = (Section->PrimitiveType == LC_MESH_TRIANGLES || Section->PrimitiveType == LC_MESH_TEXTURED_TRIANGLES) ? GL_TRIANGLES : GL_LINES;
DrawIndexedPrimitives(PrimitiveType, Section->NumIndices, Mesh->mIndexType, IndexBufferOffset + Section->IndexOffset);
}
else if (DrawConditional)
{
FlushState();
lcMatrix44 WorldViewProjectionMatrix = lcMul(mWorldMatrix, mViewProjectionMatrix);
lcVertex* VertexBuffer = (lcVertex*)Mesh->mVertexData;
if (Mesh->mIndexType == GL_UNSIGNED_SHORT)
{
lcuint16* Indices = (lcuint16*)((char*)Mesh->mIndexData + Section->IndexOffset);
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)
DrawIndexedPrimitives(GL_LINES, 2, Mesh->mIndexType, IndexBufferOffset + Section->IndexOffset + i * sizeof(lcuint16));
}
}
else
{
lcuint32* Indices = (lcuint32*)((char*)Mesh->mIndexData + Section->IndexOffset);
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)
DrawIndexedPrimitives(GL_LINES, 2, Mesh->mIndexType, IndexBufferOffset + Section->IndexOffset + i * sizeof(lcuint32));
}
}
}
}
void lcContext::DrawOpaqueMeshes(const lcScene& Scene)
{
bool DrawLines = lcGetPreferences().mDrawEdgeLines;
const lcArray<lcRenderMesh>& RenderMeshes = Scene.mRenderMeshes;
const lcArray<int>& OpaqueMeshes = Scene.mOpaqueMeshes;
for (int MeshIdx = 0; MeshIdx < OpaqueMeshes.GetSize(); MeshIdx++)
{
const lcRenderMesh& RenderMesh = RenderMeshes[OpaqueMeshes[MeshIdx]];
lcMesh* Mesh = RenderMesh.Mesh;
int LodIndex = RenderMesh.LodIndex;
BindMesh(Mesh);
SetWorldMatrix(RenderMesh.WorldMatrix);
for (int SectionIdx = 0; SectionIdx < Mesh->mLods[LodIndex].NumSections; SectionIdx++)
{
lcMeshSection* Section = &Mesh->mLods[LodIndex].Sections[SectionIdx];
int ColorIndex = Section->ColorIndex;
if (Section->PrimitiveType == LC_MESH_TRIANGLES || Section->PrimitiveType == LC_MESH_TEXTURED_TRIANGLES)
{
if (ColorIndex == gDefaultColor)
ColorIndex = RenderMesh.ColorIndex;
if (lcIsColorTranslucent(ColorIndex))
continue;
switch (RenderMesh.State)
{
case LC_RENDERMESH_NONE:
SetColorIndex(ColorIndex);
break;
case LC_RENDERMESH_SELECTED:
SetColorIndexTinted(ColorIndex, LC_COLOR_SELECTED);
break;
case LC_RENDERMESH_FOCUSED:
SetColorIndexTinted(ColorIndex, LC_COLOR_FOCUSED);
break;
}
}
else
{
switch (RenderMesh.State)
{
case LC_RENDERMESH_NONE:
if (DrawLines)
{
if (ColorIndex == gEdgeColor)
SetEdgeColorIndex(RenderMesh.ColorIndex);
else
SetColorIndex(ColorIndex);
}
else
continue;
break;
case LC_RENDERMESH_SELECTED:
SetInterfaceColor(LC_COLOR_SELECTED);
break;
case LC_RENDERMESH_FOCUSED:
SetInterfaceColor(LC_COLOR_FOCUSED);
break;
}
}
DrawMeshSection(Mesh, Section);
}
const bool DrawNormals = false;
if (DrawNormals)
{
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);
}
SetVertexBufferPointer(Vertices);
SetVertexFormatPosition(3);
DrawPrimitives(GL_LINES, 0, Mesh->mNumVertices * 2);
free(Vertices);
}
}
}
void lcContext::DrawTranslucentMeshes(const lcScene& Scene)
{
const lcArray<lcRenderMesh>& RenderMeshes = Scene.mRenderMeshes;
const lcArray<int>& TranslucentMeshes = Scene.mTranslucentMeshes;
if (TranslucentMeshes.IsEmpty())
return;
glEnable(GL_BLEND);
glDepthMask(GL_FALSE);
for (int MeshIdx = 0; MeshIdx < TranslucentMeshes.GetSize(); MeshIdx++)
{
const lcRenderMesh& RenderMesh = RenderMeshes[TranslucentMeshes[MeshIdx]];
lcMesh* Mesh = RenderMesh.Mesh;
int LodIndex = RenderMesh.LodIndex;
BindMesh(Mesh);
SetWorldMatrix(RenderMesh.WorldMatrix);
for (int SectionIdx = 0; SectionIdx < Mesh->mLods[LodIndex].NumSections; SectionIdx++)
{
lcMeshSection* Section = &Mesh->mLods[LodIndex].Sections[SectionIdx];
int ColorIndex = Section->ColorIndex;
if (Section->PrimitiveType != LC_MESH_TRIANGLES)
continue;
if (ColorIndex == gDefaultColor)
ColorIndex = RenderMesh.ColorIndex;
if (!lcIsColorTranslucent(ColorIndex))
continue;
switch (RenderMesh.State)
{
case LC_RENDERMESH_NONE:
SetColorIndex(ColorIndex);
break;
case LC_RENDERMESH_SELECTED:
SetColorIndexTinted(ColorIndex, LC_COLOR_SELECTED);
break;
case LC_RENDERMESH_FOCUSED:
SetColorIndexTinted(ColorIndex, LC_COLOR_FOCUSED);
break;
}
DrawMeshSection(Mesh, Section);
}
}
glDepthMask(GL_TRUE);
glDisable(GL_BLEND);
}
void lcContext::DrawRenderMeshes(const lcArray<lcRenderMesh>& RenderMeshes, const lcArray<int>& Meshes, lcMeshPrimitiveType PrimitiveType, bool EnableNormals, bool DrawTranslucent, bool DrawTextured)
{
for (int MeshIdx = 0; MeshIdx < Meshes.GetSize(); MeshIdx++)
{
const lcRenderMesh& RenderMesh = RenderMeshes[Meshes[MeshIdx]];
lcMesh* Mesh = RenderMesh.Mesh;
int LodIndex = RenderMesh.LodIndex;
BindMesh(Mesh);
SetWorldMatrix(RenderMesh.WorldMatrix);
for (int SectionIdx = 0; SectionIdx < Mesh->mLods[LodIndex].NumSections; SectionIdx++)
{
lcMeshSection* Section = &Mesh->mLods[LodIndex].Sections[SectionIdx];
if (Section->PrimitiveType != PrimitiveType || (Section->Texture != NULL) != DrawTextured)
continue;
int ColorIndex = Section->ColorIndex;
if (PrimitiveType == LC_MESH_TRIANGLES || PrimitiveType == LC_MESH_TEXTURED_TRIANGLES)
{
if (ColorIndex == gDefaultColor)
ColorIndex = RenderMesh.ColorIndex;
if (lcIsColorTranslucent(ColorIndex) != DrawTranslucent)
continue;
switch (RenderMesh.State)
{
case LC_RENDERMESH_NONE:
SetColorIndex(ColorIndex);
break;
case LC_RENDERMESH_SELECTED:
SetColorIndexTinted(ColorIndex, LC_COLOR_SELECTED);
break;
case LC_RENDERMESH_FOCUSED:
SetColorIndexTinted(ColorIndex, LC_COLOR_FOCUSED);
break;
}
}
else if (PrimitiveType == LC_MESH_LINES || PrimitiveType == LC_MESH_TEXTURED_LINES)
{
switch (RenderMesh.State)
{
case LC_RENDERMESH_NONE:
if (ColorIndex == gEdgeColor)
SetEdgeColorIndex(RenderMesh.ColorIndex);
else
SetColorIndex(ColorIndex);
break;
case LC_RENDERMESH_SELECTED:
SetInterfaceColor(LC_COLOR_SELECTED);
break;
case LC_RENDERMESH_FOCUSED:
SetInterfaceColor(LC_COLOR_FOCUSED);
break;
}
}
lcTexture* Texture = Section->Texture;
int VertexBufferOffset = Mesh->mVertexCacheOffset != -1 ? Mesh->mVertexCacheOffset : 0;
int IndexBufferOffset = Mesh->mIndexCacheOffset != -1 ? Mesh->mIndexCacheOffset : 0;
if (!Texture)
{
SetVertexFormat(VertexBufferOffset, 3, 1, 0, 0, EnableNormals);
}
else
{
VertexBufferOffset += Mesh->mNumVertices * sizeof(lcVertex);
SetVertexFormat(VertexBufferOffset, 3, 1, 2, 0, EnableNormals);
SetTexture(Texture->mTexture);
}
GLenum DrawPrimitiveType = (PrimitiveType == LC_MESH_TRIANGLES || PrimitiveType == LC_MESH_TEXTURED_TRIANGLES) ? GL_TRIANGLES : GL_LINES;
DrawIndexedPrimitives(DrawPrimitiveType, Section->NumIndices, Mesh->mIndexType, IndexBufferOffset + Section->IndexOffset);
}
const bool DrawNormals = false;
if (DrawNormals)
{
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);
}
SetVertexBufferPointer(Vertices);
SetVertexFormatPosition(3);
DrawPrimitives(GL_LINES, 0, Mesh->mNumVertices * 2);
free(Vertices);
}
}
}
void lcContext::DrawScene(const lcScene& Scene)
{
lcGetPiecesLibrary()->UpdateBuffers(this); // TODO: find a better place for this update
lcLightingMode LightingMode = lcGetPreferences().mLightingMode;
if (LightingMode == LC_LIGHTING_UNLIT)
{
DrawOpaqueMeshes(Scene);
DrawTranslucentMeshes(Scene);
}
else
{
bool DrawLines = lcGetPreferences().mDrawEdgeLines;
SetTexture(0);
if (DrawLines)
{
SetMaterial(LC_MATERIAL_UNLIT_COLOR);
DrawRenderMeshes(Scene.mRenderMeshes, Scene.mOpaqueMeshes, LC_MESH_LINES, false, false, false);
}
SetMaterial(LC_MATERIAL_FAKELIT_COLOR);
DrawRenderMeshes(Scene.mRenderMeshes, Scene.mOpaqueMeshes, LC_MESH_TRIANGLES, true, false, false);
if (!Scene.mTranslucentMeshes.IsEmpty())
{
glEnable(GL_BLEND);
glDepthMask(GL_FALSE);
DrawRenderMeshes(Scene.mRenderMeshes, Scene.mTranslucentMeshes, LC_MESH_TRIANGLES, true, true, false);
glDepthMask(GL_TRUE);
glDisable(GL_BLEND);
}
if (Scene.mHasTexture)
{
if (DrawLines)
{
SetMaterial(LC_MATERIAL_UNLIT_TEXTURE_DECAL);
DrawRenderMeshes(Scene.mRenderMeshes, Scene.mOpaqueMeshes, LC_MESH_TEXTURED_LINES, false, false, true);
}
SetMaterial(LC_MATERIAL_FAKELIT_TEXTURE_DECAL);
DrawRenderMeshes(Scene.mRenderMeshes, Scene.mOpaqueMeshes, LC_MESH_TEXTURED_TRIANGLES, true, false, true);
if (!Scene.mTranslucentMeshes.IsEmpty())
{
glEnable(GL_BLEND);
glDepthMask(GL_FALSE);
DrawRenderMeshes(Scene.mRenderMeshes, Scene.mTranslucentMeshes, LC_MESH_TEXTURED_TRIANGLES, true, true, true);
glDepthMask(GL_TRUE);
glDisable(GL_BLEND);
}
SetTexture(0);
}
}
}
void lcContext::DrawInterfaceObjects(const lcArray<const lcObject*>& InterfaceObjects)
{
for (int ObjectIdx = 0; ObjectIdx < InterfaceObjects.GetSize(); ObjectIdx++)
InterfaceObjects[ObjectIdx]->DrawInterface(this);
}

View file

@ -6,23 +6,6 @@
#include "lc_colors.h"
#include "lc_mesh.h"
class lcScene
{
public:
lcScene();
void Begin(const lcMatrix44& ViewMatrix);
void End();
void AddMesh(lcMesh* Mesh, const lcMatrix44& WorldMatrix, int ColorIndex, lcRenderMeshState State, int Flags);
lcMatrix44 mViewMatrix;
lcArray<lcRenderMesh> mRenderMeshes;
lcArray<int> mOpaqueMeshes;
lcArray<int> mTranslucentMeshes;
lcArray<const lcObject*> mInterfaceObjects;
bool mHasTexture;
};
class lcVertexBuffer
{
public:
@ -124,10 +107,15 @@ public:
mViewProjectionMatrixDirty = true;
}
const lcMatrix44& GetProjectionMatrix()
{
return mProjectionMatrix;
}
void SetMaterial(lcMaterialType MaterialType);
void SetViewport(int x, int y, int Width, int Height);
void SetLineWidth(float LineWidth);
void SetTexture(GLuint Texture);
void BindTexture(GLuint Texture);
void SetColor(const lcVector4& Color)
{
@ -164,19 +152,12 @@ public:
void DrawPrimitives(GLenum Mode, GLint First, GLsizei Count);
void DrawIndexedPrimitives(GLenum Mode, GLsizei Count, GLenum Type, int Offset);
void DrawScene(const lcScene& Scene);
void DrawInterfaceObjects(const lcArray<const lcObject*>& InterfaceObjects);
void BindMesh(const lcMesh* Mesh);
protected:
static void CreateShaderPrograms();
void BindMesh(lcMesh* Mesh);
void FlushState();
void DrawMeshSection(lcMesh* Mesh, lcMeshSection* Section);
void DrawOpaqueMeshes(const lcScene& Scene);
void DrawTranslucentMeshes(const lcScene& Scene);
void DrawRenderMeshes(const lcArray<lcRenderMesh>& RenderMeshes, const lcArray<int>& Meshes, lcMeshPrimitiveType PrimitiveType, bool EnableNormals, bool DrawTranslucent, bool DrawTextured);
GLuint mVertexBufferObject;
GLuint mIndexBufferObject;
char* mVertexBufferPointer;

View file

@ -4,15 +4,15 @@
#include "lc_math.h"
#define LC_MESH_FILE_ID LC_FOURCC('M', 'E', 'S', 'H')
#define LC_MESH_FILE_VERSION 0x0112
#define LC_MESH_FILE_VERSION 0x0113
enum lcMeshPrimitiveType
{
LC_MESH_LINES,
LC_MESH_TRIANGLES,
LC_MESH_TEXTURED_LINES,
LC_MESH_TEXTURED_TRIANGLES,
LC_MESH_CONDITIONAL_LINES,
LC_MESH_LINES = 0x01,
LC_MESH_TRIANGLES = 0x02,
LC_MESH_TEXTURED_LINES = 0x04,
LC_MESH_TEXTURED_TRIANGLES = 0x08,
LC_MESH_CONDITIONAL_LINES = 0x10,
LC_MESH_NUM_PRIMITIVE_TYPES
};

View file

@ -1120,7 +1120,7 @@ void lcModel::GetScene(lcScene& Scene, lcCamera* ViewCamera, bool DrawInterface)
lcCamera* Camera = mCameras[CameraIdx];
if (Camera != ViewCamera && Camera->IsVisible())
Scene.mInterfaceObjects.Add(Camera);
Scene.AddInterfaceObject(Camera);
}
for (int LightIdx = 0; LightIdx < mLights.GetSize(); LightIdx++)
@ -1128,7 +1128,7 @@ void lcModel::GetScene(lcScene& Scene, lcCamera* ViewCamera, bool DrawInterface)
lcLight* Light = mLights[LightIdx];
if (Light->IsVisible())
Scene.mInterfaceObjects.Add(Light);
Scene.AddInterfaceObject(Light);
}
}
@ -1197,7 +1197,7 @@ void lcModel::DrawBackground(lcGLWidget* Widget)
}
else if (mProperties.mBackgroundType == LC_BACKGROUND_IMAGE)
{
Context->SetTexture(mBackgroundTexture->mTexture);
Context->BindTexture(mBackgroundTexture->mTexture);
float TileWidth = 1.0f, TileHeight = 1.0f;

View file

@ -351,8 +351,7 @@ void lcPartSelectionListModel::DrawPreview(int InfoIndex)
Scene.End();
Context->SetViewMatrix(ViewMatrix);
Context->DrawScene(Scene);
Scene.Draw(Context);
mParts[InfoIndex].second = QPixmap::fromImage(Context->GetRenderToTextureImage(Width, Height)).scaled(mIconSize, mIconSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);

318
common/lc_scene.cpp Normal file
View file

@ -0,0 +1,318 @@
#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)
{
}
void lcScene::Begin(const lcMatrix44& ViewMatrix)
{
mViewMatrix = ViewMatrix;
mRenderMeshes.RemoveAll();
mOpaqueMeshes.RemoveAll();
mTranslucentMeshes.RemoveAll();
mInterfaceObjects.RemoveAll();
mHasTexture = false;
}
void lcScene::End()
{
auto OpaqueMeshCompare = [this](int Index1, int Index2)
{
return mRenderMeshes[Index1].Mesh < mRenderMeshes[Index2].Mesh;
};
std::sort(&mOpaqueMeshes[0], &mOpaqueMeshes[0] + mOpaqueMeshes.GetSize(), OpaqueMeshCompare);
auto TranslucentMeshCompare = [this](int Index1, int Index2)
{
return mRenderMeshes[Index1].Distance < mRenderMeshes[Index2].Distance;
};
std::sort(&mTranslucentMeshes[0], &mTranslucentMeshes[0] + mTranslucentMeshes.GetSize(), TranslucentMeshCompare);
}
void lcScene::AddMesh(lcMesh* Mesh, const lcMatrix44& WorldMatrix, int ColorIndex, lcRenderMeshState State, int Flags)
{
lcRenderMesh& RenderMesh = mRenderMeshes.Add();
RenderMesh.WorldMatrix = WorldMatrix;
RenderMesh.Mesh = Mesh;
RenderMesh.ColorIndex = ColorIndex;
RenderMesh.State = State;
RenderMesh.Distance = fabsf(lcMul31(WorldMatrix[3], mViewMatrix).z);
RenderMesh.LodIndex = RenderMesh.Mesh->GetLodIndex(RenderMesh.Distance);
bool Translucent = lcIsColorTranslucent(ColorIndex);
if ((Flags & (LC_PIECE_HAS_SOLID | LC_PIECE_HAS_LINES)) || ((Flags & LC_PIECE_HAS_DEFAULT) && !Translucent))
mOpaqueMeshes.Add(mRenderMeshes.GetSize() - 1);
if ((Flags & LC_PIECE_HAS_TRANSLUCENT) || ((Flags & LC_PIECE_HAS_DEFAULT) && Translucent))
mTranslucentMeshes.Add(mRenderMeshes.GetSize() - 1);
if (Flags & LC_PIECE_HAS_TEXTURE)
mHasTexture = true;
}
void lcScene::DrawRenderMeshes(lcContext* Context, int PrimitiveTypes, bool EnableNormals, bool DrawTranslucent, bool DrawTextured) const
{
const lcArray<int>& Meshes = DrawTranslucent ? mTranslucentMeshes : mOpaqueMeshes;
for (int MeshIndex : Meshes)
{
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 || (Section->Texture != NULL) != DrawTextured)
continue;
int ColorIndex = Section->ColorIndex;
if (Section->PrimitiveType & (LC_MESH_TRIANGLES | LC_MESH_TEXTURED_TRIANGLES))
{
if (ColorIndex == gDefaultColor)
ColorIndex = RenderMesh.ColorIndex;
if (lcIsColorTranslucent(ColorIndex) != DrawTranslucent)
continue;
switch (RenderMesh.State)
{
case LC_RENDERMESH_NONE:
Context->SetColorIndex(ColorIndex);
break;
case LC_RENDERMESH_SELECTED:
Context->SetColorIndexTinted(ColorIndex, LC_COLOR_SELECTED);
break;
case LC_RENDERMESH_FOCUSED:
Context->SetColorIndexTinted(ColorIndex, LC_COLOR_FOCUSED);
break;
}
}
else if (Section->PrimitiveType & (LC_MESH_LINES | LC_MESH_TEXTURED_LINES))
{
switch (RenderMesh.State)
{
case LC_RENDERMESH_NONE:
if (ColorIndex == gEdgeColor)
Context->SetEdgeColorIndex(RenderMesh.ColorIndex);
else
Context->SetColorIndex(ColorIndex);
break;
case LC_RENDERMESH_SELECTED:
Context->SetInterfaceColor(LC_COLOR_SELECTED);
break;
case LC_RENDERMESH_FOCUSED:
Context->SetInterfaceColor(LC_COLOR_FOCUSED);
break;
}
}
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;
if (Mesh->mIndexType == GL_UNSIGNED_SHORT)
{
lcuint16* Indices = (lcuint16*)((char*)Mesh->mIndexData + Section->IndexOffset);
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)
Context->DrawIndexedPrimitives(GL_LINES, 2, Mesh->mIndexType, IndexBufferOffset + Section->IndexOffset + i * sizeof(lcuint16));
}
}
else
{
lcuint32* Indices = (lcuint32*)((char*)Mesh->mIndexData + Section->IndexOffset);
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)
Context->DrawIndexedPrimitives(GL_LINES, 2, Mesh->mIndexType, IndexBufferOffset + Section->IndexOffset + i * sizeof(lcuint32));
}
}
}
lcTexture* Texture = Section->Texture;
int VertexBufferOffset = Mesh->mVertexCacheOffset != -1 ? Mesh->mVertexCacheOffset : 0;
int IndexBufferOffset = Mesh->mIndexCacheOffset != -1 ? Mesh->mIndexCacheOffset : 0;
if (!Texture)
{
Context->SetVertexFormat(VertexBufferOffset, 3, 1, 0, 0, EnableNormals);
}
else
{
VertexBufferOffset += Mesh->mNumVertices * sizeof(lcVertex);
Context->SetVertexFormat(VertexBufferOffset, 3, 1, 2, 0, EnableNormals);
Context->BindTexture(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 QT_DEBUG
const bool DrawNormals = false;
if (DrawNormals)
{
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);
}
#endif
}
}
void lcScene::Draw(lcContext* Context) const
{
lcGetPiecesLibrary()->UpdateBuffers(Context); // TODO: find a better place for this update
Context->SetViewMatrix(mViewMatrix);
if (lcGetPreferences().mLightingMode == LC_LIGHTING_UNLIT)
{
bool DrawLines = lcGetPreferences().mDrawEdgeLines;
Context->BindTexture(0);
Context->SetMaterial(LC_MATERIAL_UNLIT_COLOR);
if (DrawLines)
DrawRenderMeshes(Context, LC_MESH_LINES | LC_MESH_TRIANGLES, false, false, false);
else
DrawRenderMeshes(Context, LC_MESH_TRIANGLES, false, false, false);
if (!mTranslucentMeshes.IsEmpty())
{
glEnable(GL_BLEND);
glDepthMask(GL_FALSE);
DrawRenderMeshes(Context, LC_MESH_TRIANGLES, false, true, false);
glDepthMask(GL_TRUE);
glDisable(GL_BLEND);
}
if (mHasTexture)
{
Context->SetMaterial(LC_MATERIAL_UNLIT_TEXTURE_DECAL);
if (DrawLines)
DrawRenderMeshes(Context, LC_MESH_TEXTURED_LINES | LC_MESH_TEXTURED_TRIANGLES, false, false, false);
else
DrawRenderMeshes(Context, LC_MESH_TEXTURED_TRIANGLES, false, false, false);
if (!mTranslucentMeshes.IsEmpty())
{
glEnable(GL_BLEND); // todo: remove GL calls
glDepthMask(GL_FALSE);
DrawRenderMeshes(Context, LC_MESH_TEXTURED_TRIANGLES, false, true, false);
glDepthMask(GL_TRUE);
glDisable(GL_BLEND);
}
Context->BindTexture(0);
}
}
else
{
bool DrawLines = lcGetPreferences().mDrawEdgeLines;
Context->BindTexture(0);
if (DrawLines)
{
Context->SetMaterial(LC_MATERIAL_UNLIT_COLOR);
DrawRenderMeshes(Context, LC_MESH_LINES, false, false, false);
}
Context->SetMaterial(LC_MATERIAL_FAKELIT_COLOR);
DrawRenderMeshes(Context, LC_MESH_TRIANGLES, true, false, false);
if (!mTranslucentMeshes.IsEmpty())
{
glEnable(GL_BLEND);
glDepthMask(GL_FALSE);
DrawRenderMeshes(Context, LC_MESH_TRIANGLES, true, true, false);
glDepthMask(GL_TRUE);
glDisable(GL_BLEND);
}
if (mHasTexture)
{
if (DrawLines)
{
Context->SetMaterial(LC_MATERIAL_UNLIT_TEXTURE_DECAL);
DrawRenderMeshes(Context, LC_MESH_TEXTURED_LINES, false, false, true);
}
Context->SetMaterial(LC_MATERIAL_FAKELIT_TEXTURE_DECAL);
DrawRenderMeshes(Context, LC_MESH_TEXTURED_TRIANGLES, true, false, true);
if (!mTranslucentMeshes.IsEmpty())
{
glEnable(GL_BLEND);
glDepthMask(GL_FALSE);
DrawRenderMeshes(Context, LC_MESH_TEXTURED_TRIANGLES, true, true, true);
glDepthMask(GL_TRUE);
glDisable(GL_BLEND);
}
Context->BindTexture(0);
}
}
}
void lcScene::DrawInterfaceObjects(lcContext* Context) const
{
for (const lcObject* Object : mInterfaceObjects)
Object->DrawInterface(Context);
}

32
common/lc_scene.h Normal file
View file

@ -0,0 +1,32 @@
#pragma once
#include "lc_mesh.h"
#include "lc_array.h"
class lcScene
{
public:
lcScene();
void Begin(const lcMatrix44& ViewMatrix);
void End();
void AddMesh(lcMesh* Mesh, const lcMatrix44& WorldMatrix, int ColorIndex, lcRenderMeshState State, int Flags);
void AddInterfaceObject(const lcObject* Object)
{
mInterfaceObjects.Add(Object);
}
void Draw(lcContext* Context) const;
void DrawInterfaceObjects(lcContext* Context) const;
protected:
void DrawRenderMeshes(lcContext* Context, int PrimitiveTypes, bool EnableNormals, bool DrawTranslucent, bool DrawTextured) const;
lcMatrix44 mViewMatrix;
lcArray<lcRenderMesh> mRenderMeshes;
lcArray<int> mOpaqueMeshes;
lcArray<int> mTranslucentMeshes;
lcArray<const lcObject*> mInterfaceObjects;
bool mHasTexture;
};

View file

@ -10,6 +10,7 @@
#include "lc_library.h"
#include "lc_application.h"
#include "lc_context.h"
#include "lc_scene.h"
#include "lc_file.h"
MinifigWizard::MinifigWizard()
@ -279,8 +280,6 @@ void MinifigWizard::OnDraw()
ViewMatrix = lcMatrix44LookAt(Eye * mDistance, Center, lcVector3(0, 0, 1));
}
mContext->SetViewMatrix(ViewMatrix);
Calculate();
lcScene Scene;
@ -292,7 +291,7 @@ void MinifigWizard::OnDraw()
Scene.End();
mContext->DrawScene(Scene);
Scene.Draw(mContext);
mContext->ClearResources();
}

View file

@ -11,6 +11,7 @@
#include "lc_application.h"
#include "lc_library.h"
#include "lc_context.h"
#include "lc_scene.h"
#include "lc_qutils.h"
#include "lc_synth.h"
@ -645,7 +646,7 @@ void lcPiece::AddRenderMeshes(lcScene& Scene, bool DrawInterface) const
Scene.AddMesh(mMesh, mModelWorld, mColorIndex, Focused ? LC_RENDERMESH_FOCUSED : (Selected ? LC_RENDERMESH_SELECTED : LC_RENDERMESH_NONE), mPieceInfo->mFlags);
if (Selected)
Scene.mInterfaceObjects.Add(this);
Scene.AddInterfaceObject(this);
}
void lcPiece::SubModelAddRenderMeshes(lcScene& Scene, const lcMatrix44& WorldMatrix, int DefaultColorIndex, bool Focused, bool Selected) const

View file

@ -8,7 +8,7 @@
#include "lc_application.h"
#include "lc_model.h"
#include "project.h"
#include "lc_context.h"
#include "lc_scene.h"
#include "lc_synth.h"
#include "lc_file.h"
#include <locale.h>

View file

@ -1331,8 +1331,7 @@ void Project::ExportHTML()
Scene.End();
Context->SetViewMatrix(ViewMatrix);
Context->DrawScene(Scene);
Scene.Draw(Context);
QString FileName = QFileInfo(Dir, QLatin1String(Info->m_strName) + QLatin1String(".png")).absoluteFilePath();
if (!Context->SaveRenderToTextureImage(FileName, Width, Height))

View file

@ -112,7 +112,7 @@ bool TexFont::Load(lcContext* Context)
mFontHeight = 16;
glGenTextures(1, &mTexture);
Context->SetTexture(mTexture);
Context->BindTexture(mTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

View file

@ -567,7 +567,6 @@ void View::OnDraw()
const lcPreferences& Preferences = lcGetPreferences();
mContext->SetViewMatrix(mCamera->mWorldView);
mContext->SetProjectionMatrix(GetProjectionMatrix());
#ifndef LC_OPENGLES
@ -584,7 +583,7 @@ void View::OnDraw()
mContext->SetLineWidth(Preferences.mLineWidth);
mContext->DrawScene(mScene);
mScene.Draw(mContext);
#ifndef LC_OPENGLES
if (Properties.mFogEnabled)
@ -593,7 +592,7 @@ void View::OnDraw()
if (DrawInterface)
{
mContext->DrawInterfaceObjects(mScene.mInterfaceObjects);
mScene.DrawInterfaceObjects(mContext);
mContext->SetLineWidth(1.0f);
@ -1085,7 +1084,7 @@ void View::DrawRotateOverlay()
mContext->SetWorldMatrix(lcMatrix44Identity());
mContext->SetViewMatrix(lcMatrix44Translation(lcVector3(0.375, 0.375, 0.0)));
mContext->SetProjectionMatrix(lcMatrix44Ortho(0.0f, mWidth, 0.0f, mHeight, -1.0f, 1.0f));
mContext->SetTexture(gTexFont.GetTexture());
mContext->BindTexture(gTexFont.GetTexture());
glEnable(GL_BLEND);
char buf[32];
@ -1397,7 +1396,7 @@ void View::DrawGrid()
if (Preferences.mDrawGridStuds)
{
mContext->SetTexture(gGridTexture->mTexture);
mContext->BindTexture(gGridTexture->mTexture);
glEnable(GL_BLEND);
mContext->SetMaterial(LC_MATERIAL_UNLIT_TEXTURE_MODULATE);
@ -1472,7 +1471,7 @@ void View::DrawAxes()
mContext->SetMaterial(LC_MATERIAL_UNLIT_TEXTURE_MODULATE);
mContext->SetViewMatrix(TranslationMatrix);
mContext->SetTexture(gTexFont.GetTexture());
mContext->BindTexture(gTexFont.GetTexture());
glEnable(GL_BLEND);
float TextBuffer[6 * 5 * 3];
@ -1518,7 +1517,7 @@ void View::DrawViewport()
{
mContext->SetMaterial(LC_MATERIAL_UNLIT_TEXTURE_MODULATE);
mContext->SetColor(0.0f, 0.0f, 0.0f, 1.0f);
mContext->SetTexture(gTexFont.GetTexture());
mContext->BindTexture(gTexFont.GetTexture());
glEnable(GL_BLEND);

View file

@ -3,6 +3,7 @@
#include "lc_glwidget.h"
#include "camera.h"
#include "lc_scene.h"
enum lcTrackButton
{

View file

@ -144,6 +144,7 @@ SOURCES += common/view.cpp \
common/lc_mesh.cpp \
common/lc_model.cpp \
common/lc_profile.cpp \
common/lc_scene.cpp \
common/lc_selectbycolordialog.cpp \
common/lc_shortcuts.cpp \
common/lc_synth.cpp \
@ -205,6 +206,7 @@ HEADERS += \
common/lc_mesh.h \
common/lc_model.h \
common/lc_profile.h \
common/lc_scene.h \
common/lc_selectbycolordialog.h \
common/lc_shortcuts.h \
common/lc_synth.h \