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); }
const char* GetName()
{ return m_strName; }
PieceInfo* GetPieceInfo()
PieceInfo* GetPieceInfo() const
{ return m_pPieceInfo; }
void SetStepShow(unsigned char step)
{ m_nStepShow = step; }
@ -98,6 +98,8 @@ public:
{ return m_fPosition; }
inline Vector3 GetPosition() const
{ 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)
{ memcpy(position, m_fPosition, sizeof(m_fPosition)); }
void GetRotation (float* rotation)

View file

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

View file

@ -7,12 +7,16 @@
#endif
#include "algebra.h"
#define LC_PIECE_COUNT 0x01 // Count this piece in the totals ?
#define LC_PIECE_LONGDATA_FILE 0x02 // unsigned long/short index
#define LC_PIECE_CCW 0x04 // Use back-face culling
#define LC_PIECE_SMALL 0x10 // scale = 10000
#define LC_PIECE_MEDIUM 0x20 // scale = 1000 (otherwise = 100)
#define LC_PIECE_PLACEHOLDER 0x40 // Placeholder for a piece not in the library.
#define LC_PIECE_COUNT 0x001 // Count this piece in the totals ?
#define LC_PIECE_LONGDATA_FILE 0x002 // unsigned long/short index
#define LC_PIECE_CCW 0x004 // Use back-face culling
#define LC_PIECE_SMALL 0x010 // scale = 10000
#define LC_PIECE_MEDIUM 0x020 // scale = 1000 (otherwise = 100)
#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
@ -81,7 +85,7 @@ public:
float m_fDimensions[6];
lcuint32 m_nOffset;
lcuint32 m_nSize;
unsigned char m_nFlags;
lcuint32 m_nFlags;
protected:
int m_nRef;

View file

@ -1711,166 +1711,26 @@ void Project::RenderBackground(View* view)
glDepthMask(GL_TRUE);
}
typedef struct LC_BSPNODE
struct lcTranslucentRenderSection
{
float plane[4];
float Distance;
Piece* piece;
LC_BSPNODE* front;
LC_BSPNODE* back;
};
~LC_BSPNODE()
{
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)
int lcTranslucentRenderCompare(const lcTranslucentRenderSection& a, const lcTranslucentRenderSection& b, void*)
{
if (node->piece)
{
if (node->piece->IsSelected())
{
if (!*bSel)
{
*bSel = true;
glLineWidth (2);//*m_fLineWidth);
}
}
else
{
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);
}
if (a.Distance > b.Distance)
return 1;
else
{
RenderBSP(node->front, eye, bSel, bLighting, bEdges);
RenderBSP(node->back, eye, bSel, bLighting, bEdges);
}
return -1;
}
static void BuildBSP(LC_BSPNODE* node, Piece* pList)
int lcOpaqueRenderCompare(const Piece* a, const Piece* b, void*)
{
Piece *front_list = NULL, *back_list = NULL;
Piece *pPiece, *pNext;
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
node->plane[2] = 1.0f;
}
if (a->GetPieceInfo() > b->GetPieceInfo())
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;
return -1;
}
void Project::RenderScenePieces(View* view)
@ -1901,64 +1761,195 @@ void Project::RenderScenePieces(View* view)
if (m_nScene & LC_SCENE_FLOOR)
m_pTerrain->Render(view->m_Camera, AspectRatio);
bool bSel = false;
bool bCull = false;
Piece* pPiece;
PtrArray<Piece> OpaquePieces(512);
ObjArray<lcTranslucentRenderSection> TranslucentSections(512);
LC_BSPNODE tree;
tree.front = tree.back = NULL;
Piece* pList = NULL;
Matrix44 ModelView;
Camera* Cam = view->m_Camera;
ModelView.CreateLookAt(Cam->GetEyePosition(), Cam->GetTargetPosition(), Cam->GetUpVector());
// Draw opaque pieces first
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
for (Piece* pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
{
if (!pPiece->IsVisible(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation))
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);
lcTranslucentRenderSection RenderSection;
RenderSection.Distance = Pos[2];
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())
{
if (!bSel)
{
bSel = true;
glLineWidth (2*m_fLineWidth);
}
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
{
if (bSel)
{
bSel = false;
glLineWidth(m_fLineWidth);
}
glVertexPointer(3, GL_FLOAT, 0, Mesh->mVertexBuffer.mData);
ElementsOffset = (char*)Mesh->mIndexBuffer.mData;
}
pPiece->Render((m_nDetail & LC_DET_LIGHTING) != 0, (m_nDetail & LC_DET_BRICKEDGES) != 0);
PreviousMesh = Mesh;
}
if (piece->IsSelected())
{
if (!PreviousSelected)
glLineWidth(2.0f * m_fLineWidth);
PreviousSelected = true;
}
else
{
pPiece->m_pLink = pList;
pList = pPiece;
if (PreviousSelected)
glLineWidth(m_fLineWidth);
PreviousSelected = false;
}
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
{
if (piece->IsFocused())
lcSetColorFocused();
else if (piece->IsSelected())
lcSetColorSelected();
else if (ColorIdx == gEdgeColor)
lcSetEdgeColor(piece->mColorIndex);
else
lcSetColor(ColorIdx);
}
glDrawElements(Section->PrimitiveType, Section->NumIndices, Mesh->mIndexType, ElementsOffset + Section->IndexOffset);
}
glPopMatrix();
}
if (pList)
{
float eye[3];
view->m_Camera->GetEyePos (eye);
BuildBSP(&tree, pList);
RenderBSP(&tree, eye, &bSel, (m_nDetail & LC_DET_LIGHTING) != 0, (m_nDetail & LC_DET_BRICKEDGES) != 0);
}
glDepthMask(GL_TRUE);
glDisable(GL_BLEND);
if (bSel)
if (PreviousSelected)
glLineWidth(m_fLineWidth);
if (bCull)
glDisable(GL_CULL_FACE);
if (TranslucentSections.GetSize())
{
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glDepthMask(GL_FALSE);
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);
glDisable(GL_BLEND);
}
if (GL_HasVertexBufferObject())
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
}
else
glVertexPointer(3, GL_FLOAT, 0, NULL);
glDisableClientState(GL_VERTEX_ARRAY);
}
void Project::RenderSceneBoxes(View* view)