Sort translucent pieces by distance when rendering.

This commit is contained in:
leo 2012-05-16 23:48:16 +00:00
parent b0f3abe302
commit cedfb6af8f
4 changed files with 208 additions and 197 deletions

View file

@ -76,7 +76,7 @@ public:
{ strcpy(m_strName, name); } { strcpy(m_strName, name); }
const char* GetName() const char* GetName()
{ return m_strName; } { return m_strName; }
PieceInfo* GetPieceInfo() PieceInfo* GetPieceInfo() const
{ return m_pPieceInfo; } { return m_pPieceInfo; }
void SetStepShow(unsigned char step) void SetStepShow(unsigned char step)
{ m_nStepShow = step; } { m_nStepShow = step; }
@ -98,6 +98,8 @@ public:
{ return m_fPosition; } { return m_fPosition; }
inline Vector3 GetPosition() const inline Vector3 GetPosition() const
{ return Vector3(m_fPosition[0], m_fPosition[1], m_fPosition[2]); } { return Vector3(m_fPosition[0], m_fPosition[1], m_fPosition[2]); }
inline Vector4 GetRotation() const
{ return Vector4(m_fRotation[0], m_fRotation[1], m_fRotation[2], m_fRotation[3]); }
void GetPosition (float* position) void GetPosition (float* position)
{ memcpy(position, m_fPosition, sizeof(m_fPosition)); } { memcpy(position, m_fPosition, sizeof(m_fPosition)); }
void GetRotation (float* rotation) void GetRotation (float* rotation)

View file

@ -156,7 +156,9 @@ void PieceInfo::LoadIndex(lcFile& file)
file.ReadBuffer(m_strDescription, 64); file.ReadBuffer(m_strDescription, 64);
m_strDescription[64] = '\0'; m_strDescription[64] = '\0';
file.ReadS16(sh, 6); file.ReadS16(sh, 6);
file.ReadU8(&m_nFlags, 1); lcuint8 Flags;
file.ReadU8(&Flags, 1);
m_nFlags = Flags;
lcuint32 Groups; file.ReadU32(&Groups, 1); lcuint32 Groups; file.ReadU32(&Groups, 1);
file.ReadU32(&m_nOffset, 1); file.ReadU32(&m_nOffset, 1);
file.ReadU32(&m_nSize, 1); file.ReadU32(&m_nSize, 1);
@ -543,6 +545,16 @@ void PieceInfo::BuildMesh(void* Data, int* SectionIndices)
IndexOffset += SectionIndices[ColorIdx * 2 + 0] * sizeof(DstType); IndexOffset += SectionIndices[ColorIdx * 2 + 0] * sizeof(DstType);
NumSections++; NumSections++;
if (ColorIdx == gDefaultColor)
m_nFlags |= LC_PIECE_HAS_DEFAULT;
else
{
if (lcIsColorTranslucent(ColorIdx))
m_nFlags |= LC_PIECE_HAS_TRANSLUCENT;
else
m_nFlags |= LC_PIECE_HAS_SOLID;
}
} }
if (SectionIndices[ColorIdx * 2 + 1]) if (SectionIndices[ColorIdx * 2 + 1])
@ -557,6 +569,8 @@ void PieceInfo::BuildMesh(void* Data, int* SectionIndices)
IndexOffset += SectionIndices[ColorIdx * 2 + 1] * sizeof(DstType); IndexOffset += SectionIndices[ColorIdx * 2 + 1] * sizeof(DstType);
NumSections++; NumSections++;
m_nFlags |= LC_PIECE_HAS_LINES;
} }
} }

View file

@ -7,12 +7,16 @@
#endif #endif
#include "algebra.h" #include "algebra.h"
#define LC_PIECE_COUNT 0x01 // Count this piece in the totals ? #define LC_PIECE_COUNT 0x001 // Count this piece in the totals ?
#define LC_PIECE_LONGDATA_FILE 0x02 // unsigned long/short index #define LC_PIECE_LONGDATA_FILE 0x002 // unsigned long/short index
#define LC_PIECE_CCW 0x04 // Use back-face culling #define LC_PIECE_CCW 0x004 // Use back-face culling
#define LC_PIECE_SMALL 0x10 // scale = 10000 #define LC_PIECE_SMALL 0x010 // scale = 10000
#define LC_PIECE_MEDIUM 0x20 // scale = 1000 (otherwise = 100) #define LC_PIECE_MEDIUM 0x020 // scale = 1000 (otherwise = 100)
#define LC_PIECE_PLACEHOLDER 0x40 // Placeholder for a piece not in the library. #define LC_PIECE_PLACEHOLDER 0x040 // Placeholder for a piece not in the library.
#define LC_PIECE_HAS_DEFAULT 0x100 // Piece has triangles using the default color
#define LC_PIECE_HAS_SOLID 0x200 // Piece has triangles using a solid color
#define LC_PIECE_HAS_TRANSLUCENT 0x400 // Piece has triangles using a translucent color
#define LC_PIECE_HAS_LINES 0x800 // Piece has lines
#define LC_PIECE_NAME_LEN 256 #define LC_PIECE_NAME_LEN 256
@ -81,7 +85,7 @@ public:
float m_fDimensions[6]; float m_fDimensions[6];
lcuint32 m_nOffset; lcuint32 m_nOffset;
lcuint32 m_nSize; lcuint32 m_nSize;
unsigned char m_nFlags; lcuint32 m_nFlags;
protected: protected:
int m_nRef; int m_nRef;

View file

@ -1711,166 +1711,26 @@ void Project::RenderBackground(View* view)
glDepthMask(GL_TRUE); glDepthMask(GL_TRUE);
} }
typedef struct LC_BSPNODE struct lcTranslucentRenderSection
{ {
float plane[4]; float Distance;
Piece* piece; Piece* piece;
LC_BSPNODE* front; };
LC_BSPNODE* back;
~LC_BSPNODE() int lcTranslucentRenderCompare(const lcTranslucentRenderSection& a, const lcTranslucentRenderSection& b, void*)
{
if (piece == NULL)
{
if (front)
delete front;
if (back)
delete back;
}
}
} LC_BSPNODE;
static void RenderBSP(LC_BSPNODE* node, float* eye, bool* bSel, bool bLighting, bool bEdges)
{ {
if (node->piece) if (a.Distance > b.Distance)
{ return 1;
if (node->piece->IsSelected())
{
if (!*bSel)
{
*bSel = true;
glLineWidth (2);//*m_fLineWidth);
}
}
else else
{ return -1;
if (*bSel)
{
*bSel = false;
glLineWidth(1);//m_fLineWidth);
}
}
node->piece->Render(bLighting, bEdges);
return;
}
if (eye[0]*node->plane[0] + eye[1]*node->plane[1] +
eye[2]*node->plane[2] + node->plane[3] > 0.0f)
{
RenderBSP(node->back, eye, bSel, bLighting, bEdges);
RenderBSP(node->front, eye, bSel, bLighting, bEdges);
}
else
{
RenderBSP(node->front, eye, bSel, bLighting, bEdges);
RenderBSP(node->back, eye, bSel, bLighting, bEdges);
}
} }
static void BuildBSP(LC_BSPNODE* node, Piece* pList) int lcOpaqueRenderCompare(const Piece* a, const Piece* b, void*)
{ {
Piece *front_list = NULL, *back_list = NULL; if (a->GetPieceInfo() > b->GetPieceInfo())
Piece *pPiece, *pNext; return 1;
node->piece = NULL;
if (pList->m_pLink == NULL)
{
// This is a leaf
node->piece = pList;
return;
}
float dx, dy, dz, bs[6] = { 10000, 10000, 10000, -10000, -10000, -10000 };
const float *pos;
for (pPiece = pList; pPiece; pPiece = pPiece->m_pLink)
{
pos = pPiece->GetConstPosition();
if (pos[0] < bs[0]) bs[0] = pos[0];
if (pos[1] < bs[1]) bs[1] = pos[1];
if (pos[2] < bs[2]) bs[2] = pos[2];
if (pos[0] > bs[3]) bs[3] = pos[0];
if (pos[1] > bs[4]) bs[4] = pos[1];
if (pos[2] > bs[5]) bs[5] = pos[2];
}
dx = ABS(bs[0]-bs[3]);
dy = ABS(bs[1]-bs[4]);
dz = ABS(bs[2]-bs[5]);
node->plane[0] = node->plane[1] = node->plane[2] = 0.0f;
if (dx > dy)
{
if (dx > dz)
node->plane[0] = 1.0f;
else else
node->plane[2] = 1.0f; return -1;
}
else
{
if (dy > dz)
node->plane[1] = 1.0f;
else
node->plane[2] = 1.0f;
}
// D = -Ax -By -Cz
node->plane[3] = -(node->plane[0]*(bs[0]+bs[3])/2)-(node->plane[1]*(bs[1]+bs[4])/2)-(node->plane[2]*(bs[2]+bs[5])/2);
for (pPiece = pList; pPiece;)
{
pos = pPiece->GetConstPosition();
pNext = pPiece->m_pLink;
if (pos[0]*node->plane[0] + pos[1]*node->plane[1] +
pos[2]*node->plane[2] + node->plane[3] > 0.0f)
{
pPiece->m_pLink = front_list;
front_list = pPiece;
}
else
{
pPiece->m_pLink = back_list;
back_list = pPiece;
}
pPiece = pNext;
}
if (bs[0] == bs[3] && bs[1] == bs[4] && bs[2] == bs[5])
{
if (back_list)
{
front_list = back_list;
back_list = back_list->m_pLink;
front_list->m_pLink = NULL;
}
else
{
back_list = front_list;
front_list = front_list->m_pLink;
back_list->m_pLink = NULL;
}
}
if (front_list)
{
node->front = new LC_BSPNODE;
BuildBSP(node->front, front_list);
}
else
node->front = NULL;
if (back_list)
{
node->back = new LC_BSPNODE;
BuildBSP(node->back, back_list);
}
else
node->back = NULL;
} }
void Project::RenderScenePieces(View* view) void Project::RenderScenePieces(View* view)
@ -1901,64 +1761,195 @@ void Project::RenderScenePieces(View* view)
if (m_nScene & LC_SCENE_FLOOR) if (m_nScene & LC_SCENE_FLOOR)
m_pTerrain->Render(view->m_Camera, AspectRatio); m_pTerrain->Render(view->m_Camera, AspectRatio);
bool bSel = false; PtrArray<Piece> OpaquePieces(512);
bool bCull = false; ObjArray<lcTranslucentRenderSection> TranslucentSections(512);
Piece* pPiece;
LC_BSPNODE tree; Matrix44 ModelView;
tree.front = tree.back = NULL; Camera* Cam = view->m_Camera;
Piece* pList = NULL; ModelView.CreateLookAt(Cam->GetEyePosition(), Cam->GetTargetPosition(), Cam->GetUpVector());
// Draw opaque pieces first for (Piece* pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
{ {
if (!pPiece->IsVisible(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation)) if (!pPiece->IsVisible(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation))
continue; continue;
if (!pPiece->IsTranslucent()) bool Translucent = lcIsColorTranslucent(pPiece->mColorIndex);
PieceInfo* Info = pPiece->GetPieceInfo();
if ((Info->m_nFlags & (LC_PIECE_HAS_SOLID | LC_PIECE_HAS_LINES)) || ((Info->m_nFlags & LC_PIECE_HAS_DEFAULT) && !Translucent))
OpaquePieces.AddSorted(pPiece, lcOpaqueRenderCompare, NULL);
if ((Info->m_nFlags & LC_PIECE_HAS_TRANSLUCENT) || ((Info->m_nFlags & LC_PIECE_HAS_DEFAULT) && Translucent))
{ {
if (pPiece->IsSelected()) Vector3 Pos = Mul31(pPiece->GetPosition(), ModelView);
{
if (!bSel) lcTranslucentRenderSection RenderSection;
{
bSel = true; RenderSection.Distance = Pos[2];
glLineWidth (2*m_fLineWidth); RenderSection.piece = pPiece;
TranslucentSections.AddSorted(RenderSection, lcTranslucentRenderCompare, NULL);
} }
} }
lcMesh* PreviousMesh = NULL;
bool PreviousSelected = false;
char* ElementsOffset;
glEnableClientState(GL_VERTEX_ARRAY);
for (int PieceIdx = 0; PieceIdx < OpaquePieces.GetSize(); PieceIdx++)
{
Piece* piece = OpaquePieces[PieceIdx];
lcMesh* Mesh = piece->GetPieceInfo()->mMesh;
const Vector3& Position = piece->GetPosition();
const Vector4& Rotation = piece->GetRotation();
glPushMatrix();
glTranslatef(Position[0], Position[1], Position[2]);
glRotatef(Rotation[3], Rotation[0], Rotation[1], Rotation[2]);
if (PreviousMesh != Mesh)
{
if (GL_HasVertexBufferObject())
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, Mesh->mVertexBuffer.mBuffer);
glVertexPointer(3, GL_FLOAT, 0, NULL);
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, Mesh->mIndexBuffer.mBuffer);
ElementsOffset = NULL;
}
else else
{ {
if (bSel) glVertexPointer(3, GL_FLOAT, 0, Mesh->mVertexBuffer.mData);
ElementsOffset = (char*)Mesh->mIndexBuffer.mData;
}
PreviousMesh = Mesh;
}
if (piece->IsSelected())
{ {
bSel = false; if (!PreviousSelected)
glLineWidth(2.0f * m_fLineWidth);
PreviousSelected = true;
}
else
{
if (PreviousSelected)
glLineWidth(m_fLineWidth); glLineWidth(m_fLineWidth);
}
PreviousSelected = false;
} }
pPiece->Render((m_nDetail & LC_DET_LIGHTING) != 0, (m_nDetail & LC_DET_BRICKEDGES) != 0); for (int SectionIdx = 0; SectionIdx < Mesh->mNumSections; SectionIdx++)
{
lcMeshSection* Section = &Mesh->mSections[SectionIdx];
int ColorIdx = Section->ColorIndex;
if (Section->PrimitiveType == GL_TRIANGLES)
{
if (ColorIdx == gDefaultColor)
ColorIdx = piece->mColorIndex;
if (lcIsColorTranslucent(ColorIdx))
continue;
lcSetColor(ColorIdx);
} }
else else
{ {
pPiece->m_pLink = pList; if (piece->IsFocused())
pList = pPiece; lcSetColorFocused();
} else if (piece->IsSelected())
lcSetColorSelected();
else if (ColorIdx == gEdgeColor)
lcSetEdgeColor(piece->mColorIndex);
else
lcSetColor(ColorIdx);
} }
if (pList) glDrawElements(Section->PrimitiveType, Section->NumIndices, Mesh->mIndexType, ElementsOffset + Section->IndexOffset);
}
glPopMatrix();
}
if (PreviousSelected)
glLineWidth(m_fLineWidth);
if (TranslucentSections.GetSize())
{ {
float eye[3]; glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
view->m_Camera->GetEyePos (eye); glEnable(GL_BLEND);
BuildBSP(&tree, pList); glDepthMask(GL_FALSE);
RenderBSP(&tree, eye, &bSel, (m_nDetail & LC_DET_LIGHTING) != 0, (m_nDetail & LC_DET_BRICKEDGES) != 0);
for (int PieceIdx = 0; PieceIdx < TranslucentSections.GetSize(); PieceIdx++)
{
Piece* piece = TranslucentSections[PieceIdx].piece;
lcMesh* Mesh = piece->GetPieceInfo()->mMesh;
const Vector3& Position = piece->GetPosition();
const Vector4& Rotation = piece->GetRotation();
glPushMatrix();
glTranslatef(Position[0], Position[1], Position[2]);
glRotatef(Rotation[3], Rotation[0], Rotation[1], Rotation[2]);
if (PreviousMesh != Mesh)
{
if (GL_HasVertexBufferObject())
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, Mesh->mVertexBuffer.mBuffer);
glVertexPointer(3, GL_FLOAT, 0, NULL);
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, Mesh->mIndexBuffer.mBuffer);
ElementsOffset = NULL;
}
else
{
glVertexPointer(3, GL_FLOAT, 0, Mesh->mVertexBuffer.mData);
ElementsOffset = (char*)Mesh->mIndexBuffer.mData;
}
PreviousMesh = Mesh;
}
for (int SectionIdx = 0; SectionIdx < Mesh->mNumSections; SectionIdx++)
{
lcMeshSection* Section = &Mesh->mSections[SectionIdx];
int ColorIdx = Section->ColorIndex;
if (Section->PrimitiveType != GL_TRIANGLES)
continue;
if (ColorIdx == gDefaultColor)
ColorIdx = piece->mColorIndex;
if (!lcIsColorTranslucent(ColorIdx))
continue;
lcSetColor(ColorIdx);
glDrawElements(Section->PrimitiveType, Section->NumIndices, Mesh->mIndexType, ElementsOffset + Section->IndexOffset);
}
glPopMatrix();
} }
glDepthMask(GL_TRUE); glDepthMask(GL_TRUE);
glDisable(GL_BLEND); glDisable(GL_BLEND);
}
if (bSel) if (GL_HasVertexBufferObject())
glLineWidth(m_fLineWidth); {
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
}
else
glVertexPointer(3, GL_FLOAT, 0, NULL);
if (bCull) glDisableClientState(GL_VERTEX_ARRAY);
glDisable(GL_CULL_FACE);
} }
void Project::RenderSceneBoxes(View* view) void Project::RenderSceneBoxes(View* view)