Serious-Engine/Sources/Engine/Terrain/TerrainRender.cpp
Daniel Gibson 72edf1c720 Commented out unused functions and variables
many unused functions and variables are now commented out

You'll still get tons of warnings, which should mostly fall in one of
the following categories:
1. Unnecessary variables or values generated from .es scripts
2. Pointers assigned to from functions with side-effects: DO NOT REMOVE!
   Like CEntity *penNew = CreateEntity_t(...); - even if penNew isn't
   used, CreateEntity() must be called there!
2016-05-09 18:51:03 +02:00

1412 lines
49 KiB
C++

/* Copyright (c) 2002-2012 Croteam Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License as published by
the Free Software Foundation
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
#include "Engine/StdH.h"
#include <Engine/Terrain/Terrain.h>
#include <Engine/Terrain/TerrainRender.h>
#include <Engine/Terrain/TerrainEditing.h>
#include <Engine/Math/Projection.h>
#include <Engine/Math/OBBox.h>
#include <Engine/Graphics/DrawPort.h>
#include <Engine/Graphics/Fog_internal.h>
#include <Engine/Rendering/Render.h>
#include <Engine/Entities/Entity.h>
static CAnyProjection3D _aprProjection; // Current projection
static CDrawPort *_pdp = NULL; // Current drawport
CTerrain *_ptrTerrain; // Current terrain
FLOAT3D _vViewerAbs; // Position of viewer
static COLOR _colTerrainEdges; // Color of terrain edges
static FLOATmatrix3D _mObjectToView;
static FLOAT3D _vObjectToView;
static FLOAT3D _vViewer;
static FLOAT3D _vViewerObj;
extern INDEX _ctNodesVis; // visible quad nodes
extern INDEX _ctTris; // tris rendered
extern INDEX _ctDelayedNodes; // DelayedNodes
extern INDEX ter_bLerpVertices; // prepare smoth vertices before rendering
// Vertex array for calculating smoth vertices
CStaticStackArray<GFXVertex4> _avLerpedVerices;
CStaticStackArray<GFXVertex4> _avLerpedTileLayerVertices;
// Arrays for batch rendering of tiles is lowest mip
static CStaticStackArray<GFXVertex4> _avDelayedVertices;
static CStaticStackArray<INDEX> _aiDelayedIndices;
static CStaticStackArray<GFXTexCoord> _auvDelayedTexCoords;
static CStaticStackArray<GFXTexCoord> _auvDelayedShadowMapTC;
typedef FLOAT Matrix16[16];
typedef FLOAT Matrix12[12];
static void RenderFogLayer(INDEX itt);
static void RenderHazeLayer(INDEX itt);
FLOATaabbox3D _bboxDrawNextFrame; // TEMP
SLONG GetUsedMemoryForTileBatching(void)
{
SLONG slUsedMemory = 0;
slUsedMemory += _avDelayedVertices.sa_Count * sizeof(GFXVertex4);
slUsedMemory += _aiDelayedIndices.sa_Count * sizeof(INDEX);
slUsedMemory += _auvDelayedTexCoords.sa_Count * sizeof(GFXTexCoord);
slUsedMemory += _auvDelayedShadowMapTC.sa_Count * sizeof(GFXTexCoord);
return slUsedMemory;
}
CStaticStackArray<GFXColor> _acolVtxConstColors;
static void FillConstColorArray(INDEX ctVertices)
{
INDEX ctColors=_acolVtxConstColors.Count();
_acolVtxConstColors.PopAll();
_acolVtxConstColors.Push(ctVertices);
// if requested array is larger then existing one
if(ctVertices>ctColors) {
memset(&_acolVtxConstColors[ctColors],255,(ctVertices-ctColors)*sizeof(GFXColor));
}
}
// Regenerate one tile
void ReGenerateTile(INDEX itt)
{
ASSERT(_ptrTerrain!=NULL);
CTerrainTile &tt = _ptrTerrain->tr_attTiles[itt];
tt.ReGenerate();
}
// Convert matrix12 to
void CreateOpenGLMatrix(Matrix12 &m12,Matrix16 &mgl16)
{
mgl16[ 0] = m12[ 0]; mgl16[ 1] = m12[ 4]; mgl16[ 2] = m12[ 8]; mgl16[ 3] = 0;
mgl16[ 4] = m12[ 1]; mgl16[ 5] = m12[ 5]; mgl16[ 6] = m12[ 9]; mgl16[ 7] = 0;
mgl16[ 8] = m12[ 2]; mgl16[ 9] = m12[ 6]; mgl16[10] = m12[10]; mgl16[11] = 0;
mgl16[12] = m12[ 3]; mgl16[13] = m12[ 7]; mgl16[14] = m12[11]; mgl16[15] = 1;
}
// set given matrix as identity matrix
inline static void SetMatrixDiagonal(Matrix12 &mat,FLOAT fValue)
{
memset(&mat,0,sizeof(mat));
mat[0] = fValue;
mat[5] = fValue;
mat[10] = fValue;
}
// Set texture matrix
static inline void gfxSetTextureMatrix2(Matrix12 *pMatrix)
{
pglMatrixMode( GL_TEXTURE);
if(pMatrix==NULL) {
pglLoadIdentity();
} else {
Matrix16 mrot16;
Matrix16 mtra16;
CreateOpenGLMatrix(*pMatrix,mrot16);
Matrix12 mtr12;
SetMatrixDiagonal(mtr12,1);
CreateOpenGLMatrix(mtr12,mtra16);
pglLoadMatrixf(mtra16);
pglMultMatrixf(mrot16);
}
pglMatrixMode(GL_MODELVIEW);
}
/*
* Render
*/
// Prepare scene for terrain rendering
void PrepareScene(CAnyProjection3D &apr, CDrawPort *pdp, CTerrain *ptrTerrain)
{
ASSERT(ptrTerrain!=NULL);
ASSERT(ptrTerrain->tr_penEntity!=NULL);
// Set current terrain
_ptrTerrain = ptrTerrain;
// Set drawport
_pdp = pdp;
// Prepare and set the projection
apr->ObjectPlacementL() = CPlacement3D(FLOAT3D(0,0,0), ANGLE3D(0,0,0));
apr->Prepare();
_aprProjection = apr;
_pdp->SetProjection( _aprProjection);
CEntity *pen = ptrTerrain->tr_penEntity;
// calculate projection of viewer in absolute space
const FLOATmatrix3D &mViewer = _aprProjection->pr_ViewerRotationMatrix;
_vViewer(1) = -mViewer(3,1);
_vViewer(2) = -mViewer(3,2);
_vViewer(3) = -mViewer(3,3);
// calculate projection of viewer in object space
_vViewerObj = _vViewer * !pen->en_mRotation;
const CPlacement3D &plTerrain = pen->GetLerpedPlacement();
_mObjectToView = mViewer * pen->en_mRotation;
_vObjectToView = (plTerrain.pl_PositionVector - _aprProjection->pr_vViewerPosition) * mViewer;
// make transform matrix
const FLOATmatrix3D &m = _mObjectToView;
const FLOAT3D &v = _vObjectToView;
FLOAT glm[16];
glm[0] = m(1,1); glm[4] = m(1,2); glm[ 8] = m(1,3); glm[12] = v(1);
glm[1] = m(2,1); glm[5] = m(2,2); glm[ 9] = m(2,3); glm[13] = v(2);
glm[2] = m(3,1); glm[6] = m(3,2); glm[10] = m(3,3); glm[14] = v(3);
glm[3] = 0; glm[7] = 0; glm[11] = 0; glm[15] = 1;
gfxSetViewMatrix(glm);
// Get viewer in absolute space
_vViewerAbs = (_aprProjection->ViewerPlacementR().pl_PositionVector -
pen->en_plPlacement.pl_PositionVector) * !pen->en_mRotation;
gfxDisableBlend();
gfxDisableTexture();
gfxDisableAlphaTest();
gfxEnableDepthTest();
gfxEnableDepthWrite();
gfxCullFace(GFX_BACK);
}
__forceinline void Lerp(GFXVertex &vResult, const GFXVertex &vOriginal, const GFXVertex &v1, const GFXVertex &v2, const FLOAT &fFactor)
{
FLOAT fHalfPosY = Lerp(v1.y,v2.y,0.5f);
vResult.x = vOriginal.x;
vResult.y = Lerp(vOriginal.y, fHalfPosY, fFactor);
vResult.z = vOriginal.z;
}
void PrepareSmothVertices(INDEX itt)
{
CTerrainTile &tt = _ptrTerrain->tr_attTiles[itt];
const INDEX ctVertices = tt.GetVertices().Count();
const FLOAT &fLerpFactor = tt.tt_fLodLerpFactor;
// Allocate memory for all vertices
_avLerpedVerices.PopAll();
_avLerpedVerices.Push(ctVertices);
// Get pointers to src and dst vertex arrays
GFXVertex *pavSrcFirst = &tt.GetVertices()[0];
GFXVertex *pavDstFirst = &_avLerpedVerices[0];
GFXVertex *pavSrc = &pavSrcFirst[0];
GFXVertex *pavDst = &pavDstFirst[0];
INDEX iFacing=0;
// for each vertex column
for(INDEX iy=0;iy<tt.tt_ctLodVtxY;iy++) {
// for each vertex in row in even column step by 2
for(INDEX ix=0;ix<tt.tt_ctLodVtxX-2;ix+=2) {
// Copy first vertex
pavDst[0] = pavSrc[0];
// Second vertex is lerped between left and right vertices
Lerp(pavDst[1],pavSrc[1],pavSrc[0],pavSrc[2],fLerpFactor);
// Increment vertex pointers
pavDst+=2;
pavSrc+=2;
}
// Copy last vertex in row
pavDst[0] = pavSrc[0];
// Increment vertex pointers and go to odd column
pavDst++;
pavSrc++;
iy++;
// if this is not last row
if(iy<tt.tt_ctLodVtxY) {
// for each vertex in row in odd column step by 2
for(INDEX ix=0;ix<tt.tt_ctLodVtxX-2;ix+=2) {
// First vertex is lerped between top and bottom vertices
Lerp(pavDst[0],pavSrc[0],pavSrc[-tt.tt_ctLodVtxX],pavSrc[tt.tt_ctLodVtxX],fLerpFactor);
// is this odd vertex in row
#pragma message(">> Fix this")
if(((ix+iy)/2)%2) {
// if(iFacing&1)
// Second vertex (diagonal one) is lerped between topright and bottom left vertices
Lerp(pavDst[1],pavSrc[1],pavSrc[-tt.tt_ctLodVtxX+2],pavSrc[tt.tt_ctLodVtxX],fLerpFactor);
} else {
// Second vertex (diagonal one) is lerped between topleft and bottom right vertices
Lerp(pavDst[1],pavSrc[1],pavSrc[-tt.tt_ctLodVtxX],pavSrc[tt.tt_ctLodVtxX+2],fLerpFactor);
}
iFacing++;
// Increment vertex pointers
pavDst+=2;
pavSrc+=2;
}
// Last vertex in row is lerped between top and bottom vertices (same as first in row)
Lerp(pavDst[0],pavSrc[0],pavSrc[-tt.tt_ctLodVtxX],pavSrc[tt.tt_ctLodVtxX],fLerpFactor);
}
// Increment vertex pointers
pavDst++;
pavSrc++;
}
pavDst--;
pavSrc--;
/*
// Copy border vertices
GFXVertex *pvBorderDst = pavDst;
GFXVertex *pvBorderSrc = pavSrc;
for(INDEX ivx=tt.tt_ctNonBorderVertices;ivx<ctVertices;ivx++) {
// *pavDst++ = *pavSrc++;
pvBorderDst[0] = pvBorderSrc[0];
pvBorderDst++;
pvBorderSrc++;
}
*/
// Lerp top border vertices
const INDEX &iTopNeigbour = tt.tt_aiNeighbours[NB_TOP];
// if top neighbour exists
if(iTopNeigbour>=0) {
CTerrainTile &ttTop = _ptrTerrain->tr_attTiles[iTopNeigbour];
const FLOAT &fLerpFactor = ttTop.tt_fLodLerpFactor;
// Get source vertex pointer in top neighbour (vertex in bottom left corner of top neighbour)
const INDEX iSrcVtx = ttTop.tt_ctLodVtxX * (ttTop.tt_ctLodVtxY-1);
GFXVertex *pavSrc = &ttTop.GetVertices()[iSrcVtx];
// Calculate num of vertices that needs to be lerped
const INDEX ctLerps = (ttTop.tt_ctLodVtxX-1)/2;
// is top tile in same lod as this tile and has smaller or equal lerp factor
if(tt.tt_iLod==ttTop.tt_iLod && fLerpFactor<=tt.tt_fLodLerpFactor) {
// Get destination vertex pointer in this tile (first vertex in top left corner of this tile - first vertex in array)
const INDEX iDstVtx = 0;
GFXVertex *pavDst = &pavDstFirst[iDstVtx];
// for each vertex in bottom row of top tile that needs to be lerped
for(INDEX ivx=0;ivx<ctLerps;ivx++) {
// First vertex is same as in top tile
pavDst[0] = pavSrc[0];
// Second vertex is lerped between left and right vertices
Lerp(pavDst[1],pavSrc[1],pavSrc[0],pavSrc[2],fLerpFactor);
pavDst+=2;
pavSrc+=2;
}
// is top tile in higher lod
} else if(tt.tt_iLod>ttTop.tt_iLod) {
const INDEX iVtxDiff = (ttTop.tt_ctLodVtxX-1) / (tt.tt_ctLodVtxX-1);
// Get destination vertex pointer to copy vertices from top neighbour (first vertex in top left corner of this tile - first vertex in array)
// Get destination vertex pointer to lerp vertices from top neighbour (first vertex added as additional top border vertex)
const INDEX iDstCopyVtx = 0;
const INDEX iDstLerpVtx = tt.tt_iFirstBorderVertex[NB_TOP];
GFXVertex *pavDstCopy = &pavDstFirst[iDstCopyVtx];
GFXVertex *pavDstLerp = &pavDstFirst[iDstLerpVtx];
// if diference is in one lod
if(iVtxDiff==2) {
// for each vertex in bottom row of top tile that needs to be lerped
for(INDEX ivx=0;ivx<ctLerps;ivx++) {
// Copy src vertex in normal dst vertex array
pavDstCopy[0] = pavSrc[0];
// Lerp left and right src vertices in border dst vertex
Lerp(pavDstLerp[0],pavSrc[1],pavSrc[0],pavSrc[2],fLerpFactor);
pavDstLerp++;
pavDstCopy++;
pavSrc+=2;
}
// diference is more than one lod
} else {
INDEX ctbv = tt.tt_ctBorderVertices[NB_TOP];
INDEX ivxInQuad = 2; // This is 2 cos first and last non border vertex
// for each border vertex
for(INDEX ivx=0;ivx<ctbv;ivx+=2) {
// Lerp left and right src vertices in border dst vertex
Lerp(pavDstLerp[0],pavSrc[1],pavSrc[0],pavSrc[2],fLerpFactor);
// if this border vertex is not last in quad
if(ivxInQuad!=iVtxDiff) {
// Copy second border vertex
pavDstLerp[1] = pavSrc[2];
pavDstLerp+=2;
ivxInQuad+=2;
// this is last border vertex
} else {
// Copy second non border vertex
pavDstCopy[1] = pavSrc[2];
pavDstCopy++;
// since this wasn't border vertex, fix border vertex loop counter
ctbv++;
pavDstLerp++;
ivxInQuad=2;
}
pavSrc+=2;
}
}
}
}
// Lerp bottom border vertices
const INDEX &iBottomNeigbour = tt.tt_aiNeighbours[NB_BOTTOM];
// if bottom neighbour exists
if(iBottomNeigbour>=0) {
CTerrainTile &ttBottom = _ptrTerrain->tr_attTiles[iBottomNeigbour];
const FLOAT &fLerpFactor = ttBottom.tt_fLodLerpFactor;
// Get source vertex pointer in bottom neighbour (vertex in top left corner of bottom neighbour - first vertex in array)
const INDEX iSrcVtx = 0;
GFXVertex *pavSrc = &ttBottom.GetVertices()[iSrcVtx];
// Calculate num of vertices that needs to be lerped
const INDEX ctLerps = (ttBottom.tt_ctLodVtxX-1)/2;
// is bottom tile in same lod as this tile and has smaller lerp factor
if(tt.tt_iLod==ttBottom.tt_iLod && fLerpFactor<tt.tt_fLodLerpFactor) {
// Get destination vertex pointer in this tile (first vertex in bottom left corner of this tile)
const INDEX iDstVtx = tt.tt_ctLodVtxX * (tt.tt_ctLodVtxY-1);
GFXVertex *pavDst = &pavDstFirst[iDstVtx];
// for each vertex in top row of bottom tile that needs to be lerped
for(INDEX ivx=0;ivx<ctLerps;ivx++) {
// First vertex is same as in bottom tile
pavDst[0] = pavSrc[0];
// Second vertex is lerped between left and right vertices
Lerp(pavDst[1],pavSrc[1],pavSrc[0],pavSrc[2],fLerpFactor);
pavDst+=2;
pavSrc+=2;
}
// is bottom tile in higher lod
} else if(tt.tt_iLod>ttBottom.tt_iLod) {
const INDEX iVtxDiff = (ttBottom.tt_ctLodVtxX-1) / (tt.tt_ctLodVtxX-1);
// Get destination vertex pointer to copy vertices from bottom neighbour (first vertex in bottom left corner of this tile)
// Get destination vertex pointer to lerp vertices from bottom neighbour (first vertex added as additional bottom border vertex)
const INDEX iDstCopyVtx = tt.tt_ctLodVtxX * (tt.tt_ctLodVtxY-1);
const INDEX iDstLerpVtx = tt.tt_iFirstBorderVertex[NB_BOTTOM];
GFXVertex *pavDstCopy = &pavDstFirst[iDstCopyVtx];
GFXVertex *pavDstLerp = &pavDstFirst[iDstLerpVtx];
// if diference is in one lod
if(iVtxDiff==2) {
// for each vertex in top row of bottom tile that needs to be lerped
for(INDEX ivx=0;ivx<ctLerps;ivx++) {
// Copy src vertex in normal dst vertex array
pavDstCopy[0] = pavSrc[0];
// Lerp left and right src vertices in border dst vertex
Lerp(pavDstLerp[0],pavSrc[1],pavSrc[0],pavSrc[2],fLerpFactor);
pavDstLerp++;
pavDstCopy++;
pavSrc+=2;
}
// diference is more than one lod
} else {
INDEX ctbv = tt.tt_ctBorderVertices[NB_BOTTOM];
INDEX ivxInQuad = 2; // This is 2 cos first and last non border vertex
// for each border vertex
for(INDEX ivx=0;ivx<ctbv;ivx+=2) {
// Lerp left and right src vertices in border dst vertex
Lerp(pavDstLerp[0],pavSrc[1],pavSrc[0],pavSrc[2],fLerpFactor);
// if this border vertex is not last in quad
if(ivxInQuad!=iVtxDiff) {
// Copy second border vertex
pavDstLerp[1] = pavSrc[2];
pavDstLerp+=2;
ivxInQuad+=2;
// this is last border vertex
} else {
// Copy second non border vertex
pavDstCopy[1] = pavSrc[2];
pavDstCopy++;
// since this wasn't border vertex, fix border vertex loop counter
ctbv++;
pavDstLerp++;
ivxInQuad=2;
}
pavSrc+=2;
}
}
}
}
// Lerp left border vertices
const INDEX &iLeftNeigbour = tt.tt_aiNeighbours[NB_LEFT];
// if left neighbour exists
if(iLeftNeigbour>=0) {
CTerrainTile &ttLeft = _ptrTerrain->tr_attTiles[iLeftNeigbour];
const FLOAT &fLerpFactor = ttLeft.tt_fLodLerpFactor;
// Get source vertex pointer in left neighbour (vertex in top right corner of left neighbour)
const INDEX iSrcVtx = ttLeft.tt_ctLodVtxX-1;
const INDEX iSrcStep = ttLeft.tt_ctLodVtxX;
GFXVertex *pavSrc = &ttLeft.GetVertices()[iSrcVtx];
// Calculate num of vertices that needs to be lerped
const INDEX ctLerps = (ttLeft.tt_ctLodVtxX-1)/2;
// is left tile in same lod as this tile and has smaller or equal lerp factor
if(tt.tt_iLod==ttLeft.tt_iLod && fLerpFactor<=tt.tt_fLodLerpFactor) {
// Get destination vertex pointer in this tile (first vertex in top left corner of this tile - first vertex in array)
const INDEX iDstVtx = 0;
const INDEX iDstStep = tt.tt_ctLodVtxX;
GFXVertex *pavDst = &pavDstFirst[iDstVtx];
// for each vertex in last column of left tile that needs to be lerped
for(INDEX ivx=0;ivx<ctLerps;ivx++) {
// First vertex is same as in left tile
pavDst[0] = pavSrc[0];
// Second vertex is lerped between top and bottom vertices
Lerp(pavDst[iDstStep],pavSrc[iSrcStep],pavSrc[0],pavSrc[iSrcStep*2],fLerpFactor);
pavDst+=iDstStep*2;
pavSrc+=iSrcStep*2;
}
// is left tile in higher lod
} else if(tt.tt_iLod>ttLeft.tt_iLod) {
const INDEX iVtxDiff = (ttLeft.tt_ctLodVtxX-1) / (tt.tt_ctLodVtxX-1);
// Get destination vertex pointer to copy vertices from left neighbour (first vertex in top left corner of this tile - first vertex in array)
// Get destination vertex pointer to lerp vertices from left neighbour (first vertex added as additional left border vertex)
const INDEX iDstCopyVtx = 0;
const INDEX iDstLerpVtx = tt.tt_iFirstBorderVertex[NB_LEFT];
const INDEX iDstStep = tt.tt_ctLodVtxX;
GFXVertex *pavDstCopy = &pavDstFirst[iDstCopyVtx];
GFXVertex *pavDstLerp = &pavDstFirst[iDstLerpVtx];
// if diference is in one lod
if(iVtxDiff==2) {
// for each vertex in last column of left tile that needs to be lerped
for(INDEX ivx=0;ivx<ctLerps;ivx++) {
// Copy src vertex in normal dst vertex array
pavDstCopy[0] = pavSrc[0];
// Lerp left and right src vertices in border dst vertex
Lerp(pavDstLerp[0],pavSrc[iSrcStep],pavSrc[0],pavSrc[iSrcStep*2],fLerpFactor);
pavDstLerp++;
pavDstCopy+=iDstStep;
pavSrc+=iSrcStep*2;
}
// diference is more than one lod
} else {
INDEX ctbv = tt.tt_ctBorderVertices[NB_LEFT];
INDEX ivxInQuad = 2; // This is 2 cos first and last non border vertex
// for each border vertex
for(INDEX ivx=0;ivx<ctbv;ivx+=2) {
// Lerp left and right src vertices in border dst vertex
Lerp(pavDstLerp[0],pavSrc[iSrcStep],pavSrc[0],pavSrc[iSrcStep*2],fLerpFactor);
// if this border vertex is not last in quad
if(ivxInQuad!=iVtxDiff) {
// Copy second border vertex
pavDstLerp[1] = pavSrc[iSrcStep*2];
pavDstLerp+=2;
ivxInQuad+=2;
// this is last border vertex
} else {
// Copy second non border vertex
pavDstCopy[iDstStep] = pavSrc[iSrcStep*2];
pavDstCopy+=iDstStep;
// since this wasn't border vertex, fix border vertex loop counter
ctbv++;
pavDstLerp++;
ivxInQuad=2;
}
pavSrc+=iSrcStep*2;
}
}
}
}
// Lerp right border vertices
const INDEX &iRightNeigbour = tt.tt_aiNeighbours[NB_RIGHT];
// if right neighbour exists
if(iRightNeigbour>=0) {
CTerrainTile &ttRight = _ptrTerrain->tr_attTiles[iRightNeigbour];
const FLOAT &fLerpFactor = ttRight.tt_fLodLerpFactor;
// Get source vertex pointer in right neighbour (vertex in top left corner of left neighbour - first vertex in array)
const INDEX iSrcVtx = 0;
const INDEX iSrcStep = ttRight.tt_ctLodVtxX;
GFXVertex *pavSrc = &ttRight.GetVertices()[iSrcVtx];
// Calculate num of vertices that needs to be lerped
const INDEX ctLerps = (ttRight.tt_ctLodVtxX-1)/2;
// is right tile in same lod as this tile and has smaller lerp factor
if(tt.tt_iLod==ttRight.tt_iLod && fLerpFactor<tt.tt_fLodLerpFactor) {
// Get destination vertex pointer in this tile (first vertex in top right corner of this tile)
INDEX iDstVtx = tt.tt_ctLodVtxX-1;
INDEX iDstStep = tt.tt_ctLodVtxX;
GFXVertex *pavDst = &pavDstFirst[iDstVtx];
// for each vertex in first column of right tile that needs to be lerped
for(INDEX ivx=0;ivx<ctLerps;ivx++) {
// First vertex is same as in right tile
pavDst[0] = pavSrc[0];
// Second vertex is lerped between top and bottom vertices
Lerp(pavDst[iDstStep],pavSrc[iSrcStep],pavSrc[0],pavSrc[iSrcStep*2],fLerpFactor);
pavDst+=iDstStep*2;
pavSrc+=iSrcStep*2;
}
// is right tile in higher lod
} else if(tt.tt_iLod>ttRight.tt_iLod) {
const INDEX iVtxDiff = (ttRight.tt_ctLodVtxX-1) / (tt.tt_ctLodVtxX-1);
// Get destination vertex pointer to copy vertices from right neighbour (first vertex in top right corner of this tile)
// Get destination vertex pointer to lerp vertices from right neighbour (first vertex added as additional right border vertex)
const INDEX iDstCopyVtx = tt.tt_ctLodVtxX-1;
const INDEX iDstLerpVtx = tt.tt_iFirstBorderVertex[NB_RIGHT];
const INDEX iDstStep = tt.tt_ctLodVtxX;
GFXVertex *pavDstCopy = &pavDstFirst[iDstCopyVtx];
GFXVertex *pavDstLerp = &pavDstFirst[iDstLerpVtx];
// if diference is in one lod
if(iVtxDiff==2) {
// for each vertex in first column of right tile that needs to be lerped
for(INDEX ivx=0;ivx<ctLerps;ivx++) {
// Copy src vertex in normal dst vertex array
pavDstCopy[0] = pavSrc[0];
// Lerp left and right src vertices in border dst vertex
Lerp(pavDstLerp[0],pavSrc[iSrcStep],pavSrc[0],pavSrc[iSrcStep*2],fLerpFactor);
pavDstLerp++;
pavDstCopy+=iDstStep;
pavSrc+=iSrcStep*2;
}
// diference is more than one lod
} else {
INDEX ctbv = tt.tt_ctBorderVertices[NB_RIGHT];
INDEX ivxInQuad = 2; // This is 2 cos first and last non border vertex
// for each border vertex
for(INDEX ivx=0;ivx<ctbv;ivx+=2) {
// Lerp left and right src vertices in border dst vertex
Lerp(pavDstLerp[0],pavSrc[iSrcStep],pavSrc[0],pavSrc[iSrcStep*2],fLerpFactor);
// if this border vertex is not last in quad
if(ivxInQuad!=iVtxDiff) {
// Copy second border vertex
pavDstLerp[1] = pavSrc[iSrcStep*2];
pavDstLerp+=2;
ivxInQuad+=2;
// this is last border vertex
} else {
// Copy second non border vertex
pavDstCopy[iDstStep] = pavSrc[iSrcStep*2];
pavDstCopy+=iDstStep;
// since this wasn't border vertex, fix border vertex loop counter
ctbv++;
pavDstLerp++;
ivxInQuad=2;
}
pavSrc+=iSrcStep*2;
}
}
}
}
}
void PrepareSmothVerticesOnTileLayer(INDEX iTerrainTile, INDEX iTileLayer)
{
CTerrainTile &tt = _ptrTerrain->tr_attTiles[iTerrainTile];
//CTerrainLayer &tl = _ptrTerrain->tr_atlLayers[iTileLayer];
TileLayer &ttl = tt.GetTileLayers()[iTileLayer];
ASSERT(tt.tt_iLod==0);
const INDEX ctVertices = ttl.tl_avVertices.Count();
const FLOAT &fLerpFactor = tt.tt_fLodLerpFactor;
// Allocate memory for all vertices
_avLerpedTileLayerVertices.PopAll();
_avLerpedTileLayerVertices.Push(ctVertices);
// Get pointers to src and dst vertex arrays
GFXVertex *pavSrcFirst = &ttl.tl_avVertices[0];
GFXVertex *pavDstFirst = &_avLerpedTileLayerVertices[0];
GFXVertex *pavSrc = &pavSrcFirst[0];
GFXVertex *pavDst = &pavDstFirst[0];
INDEX ctQuadsPerRow = _ptrTerrain->tr_ctQuadsInTileRow;
INDEX ctVerticesInRow = _ptrTerrain->tr_ctQuadsInTileRow*2;
INDEX iFacing = 1;
// Minimize popping on vertices using 4 quads, 2 from current row and 2 from next row in same tile
for(INDEX iz=0;iz<ctQuadsPerRow;iz+=2) {
for(INDEX ix=0;ix<ctQuadsPerRow;ix+=2) {
// Get pointer for quads in next row
GFXVertex *pavNRSrc = &pavSrc[ctVerticesInRow*2];
GFXVertex *pavNRDst = &pavDst[ctVerticesInRow*2];
pavDst[0] = pavSrc[0];
Lerp(pavDst[1],pavSrc[1],pavSrc[0],pavSrc[5],fLerpFactor);
Lerp(pavDst[2],pavSrc[2],pavSrc[0],pavNRSrc[2],fLerpFactor);
if(iFacing&1) {
Lerp(pavDst[3],pavSrc[3],pavSrc[0],pavNRSrc[7],fLerpFactor);
} else {
Lerp(pavDst[3],pavSrc[3],pavSrc[5],pavNRSrc[2],fLerpFactor);
}
pavDst[4] = pavDst[1];
pavDst[5] = pavSrc[5];
pavDst[6] = pavDst[3];
Lerp(pavDst[7],pavSrc[7],pavSrc[5],pavNRSrc[7],fLerpFactor);
pavNRDst[0] = pavDst[2];
pavNRDst[1] = pavDst[3];
pavNRDst[2] = pavNRSrc[2];
Lerp(pavNRDst[3],pavNRSrc[3],pavNRSrc[2],pavNRSrc[7],fLerpFactor);
pavNRDst[4] = pavDst[3];
pavNRDst[5] = pavDst[7];
pavNRDst[6] = pavNRDst[3];
pavNRDst[7] = pavNRSrc[7];
// Increment vertex pointers
pavSrc+=8;
pavDst+=8;
iFacing++;
}
iFacing++;
pavSrc+=ctVerticesInRow*2;
pavDst+=ctVerticesInRow*2;
}
// Lerp top border
INDEX iTopNeighbour = tt.tt_aiNeighbours[NB_TOP];
// if top border exists
if(iTopNeighbour>=0) {
CTerrainTile &ttTop = _ptrTerrain->tr_attTiles[iTopNeighbour];
const FLOAT fTopLerpFactor = ttTop.tt_fLodLerpFactor;
// is top tile in highest lod and has smaller or equal lerp factor
if(ttTop.tt_iLod==0 && fTopLerpFactor<=fLerpFactor) {
TileLayer &ttl = ttTop.GetTileLayers()[iTileLayer];
INDEX iFirstVertex = ctVerticesInRow*(ctVerticesInRow-2);
GFXVertex *pavSrc = &ttl.tl_avVertices[iFirstVertex];
GFXVertex *pavDst = &_avLerpedTileLayerVertices[0];
// for each quad
for(INDEX ix=0;ix<ctQuadsPerRow;ix+=2) {
Lerp(pavDst[1],pavSrc[6],pavSrc[2],pavSrc[7],fTopLerpFactor);
pavDst[4] = pavDst[1];
pavSrc+=8;
pavDst+=8;
}
}
}
// Lerp bottom border
INDEX iBottomNeighbour = tt.tt_aiNeighbours[NB_BOTTOM];
// if bottom border exists
if(iBottomNeighbour>=0) {
CTerrainTile &ttBottom = _ptrTerrain->tr_attTiles[iBottomNeighbour];
const FLOAT fBottomLerpFactor = ttBottom.tt_fLodLerpFactor;
// is bottom tile in highest lod and has smaller lerp factor
if(ttBottom.tt_iLod==0 && fBottomLerpFactor<fLerpFactor) {
TileLayer &ttl = ttBottom.GetTileLayers()[iTileLayer];
INDEX iFirstVertex = ctVerticesInRow*(ctVerticesInRow-2);
GFXVertex *pavSrc = &ttl.tl_avVertices[0];
GFXVertex *pavDst = &_avLerpedTileLayerVertices[iFirstVertex];
// for each quad
for(INDEX ix=0;ix<ctQuadsPerRow;ix+=2) {
Lerp(pavDst[3],pavSrc[1],pavSrc[0],pavSrc[5],fBottomLerpFactor);
pavDst[6] = pavDst[3];
pavSrc+=8;
pavDst+=8;
}
}
}
// Lerp left border
INDEX iLeftNeighbour = tt.tt_aiNeighbours[NB_LEFT];
// if left neightbour exits
if(iLeftNeighbour>=0) {
CTerrainTile &ttLeft = _ptrTerrain->tr_attTiles[iLeftNeighbour];
const FLOAT fLeftLerpFactor = ttLeft.tt_fLodLerpFactor;
// is left tile in highest lod and has smaller or equal left factor
if(ttLeft.tt_iLod==0 && fLeftLerpFactor<=fLerpFactor) {
TileLayer &ttl = ttLeft.GetTileLayers()[iTileLayer];
INDEX iFirstVertex = ctVerticesInRow*2-8;
GFXVertex *pavSrc = &ttl.tl_avVertices[iFirstVertex];
GFXVertex *pavDst = &_avLerpedTileLayerVertices[0];
// for each quad
for(INDEX ix=0;ix<ctQuadsPerRow;ix+=2) {
GFXVertex *pavNRSrc = &pavSrc[ctVerticesInRow*2];
GFXVertex *pavNRDst = &pavDst[ctVerticesInRow*2];
Lerp(pavDst[2],pavSrc[7],pavSrc[5],pavNRSrc[7],fLeftLerpFactor);
pavNRDst[0] = pavDst[2];
pavSrc+=ctVerticesInRow*4;
pavDst+=ctVerticesInRow*4;
}
}
}
// Lerp right border
INDEX iRightNeighbour = tt.tt_aiNeighbours[NB_RIGHT];
// if right neightbour exits
if(iRightNeighbour>=0) {
CTerrainTile &ttRight = _ptrTerrain->tr_attTiles[iRightNeighbour];
const FLOAT fRightLerpFactor = ttRight.tt_fLodLerpFactor;
// is right tile in highest lod and has smaller left factor
if(ttRight.tt_iLod==0 && fRightLerpFactor<fLerpFactor) {
TileLayer &ttl = ttRight.GetTileLayers()[iTileLayer];
INDEX iFirstVertex = ctVerticesInRow*2-8;
GFXVertex *pavSrc = &ttl.tl_avVertices[0];
GFXVertex *pavDst = &_avLerpedTileLayerVertices[iFirstVertex];
// for each quad
for(INDEX ix=0;ix<ctQuadsPerRow;ix+=2) {
GFXVertex *pavNRSrc = &pavSrc[ctVerticesInRow*2];
GFXVertex *pavNRDst = &pavDst[ctVerticesInRow*2];
Lerp(pavDst[7],pavSrc[2],pavSrc[0],pavNRSrc[2],fRightLerpFactor);
pavNRDst[5] = pavDst[7];
pavSrc+=ctVerticesInRow*4;
pavDst+=ctVerticesInRow*4;
}
}
}
}
// Draw all tiles that are in lowest lod
static void RenderBatchedTiles(void)
{
// Set texture wrapping
gfxSetTextureWrapping(GFX_CLAMP,GFX_CLAMP);
// Use terrains global top map as texture
_ptrTerrain->tr_tdTopMap.SetAsCurrent();
GFXVertex4 *pavVertices = &_avDelayedVertices[0];
GFXTexCoord *pauvTexCoords = &_auvDelayedTexCoords[0];
GFXTexCoord *pauvShadowMapTC = &_auvDelayedShadowMapTC[0];
INDEX *paiIndices = &_aiDelayedIndices[0];
INDEX ctVertices = _avDelayedVertices.Count();
INDEX ctIndices = _aiDelayedIndices.Count();
// Prepare white color array
FillConstColorArray(ctVertices);
GFXColor *pacolColors = &_acolVtxConstColors[0];
gfxEnableAlphaTest();
gfxDisableBlend();
gfxSetVertexArray(pavVertices,ctVertices);
gfxSetTexCoordArray(pauvTexCoords, FALSE);
gfxSetColorArray(pacolColors);
gfxLockArrays();
gfxDrawElements(ctIndices,paiIndices);
gfxDisableAlphaTest();
_ctTris +=ctIndices/2;
// if shadows are visible
if(_wrpWorldRenderPrefs.wrp_shtShadows!=CWorldRenderPrefs::SHT_NONE) {
gfxDepthFunc(GFX_EQUAL);
gfxBlendFunc(GFX_DST_COLOR,GFX_SRC_COLOR);
gfxEnableBlend();
gfxSetTexCoordArray(pauvShadowMapTC, FALSE);
_ptrTerrain->tr_tdShadowMap.SetAsCurrent();
gfxDrawElements(ctIndices,paiIndices);
gfxDepthFunc(GFX_LESS_EQUAL);
}
if(_ptrTerrain->GetFlags()&TR_HAS_FOG) {
RenderFogLayer(-1);
}
if(_ptrTerrain->GetFlags()&TR_HAS_HAZE) {
RenderHazeLayer(-1);
}
gfxUnlockArrays();
// Popall delayed arrays
_avDelayedVertices.PopAll();
_auvDelayedTexCoords.PopAll();
_auvDelayedShadowMapTC.PopAll();
_aiDelayedIndices.PopAll();
}
static void BatchTile(INDEX itt)
{
CTerrainTile &tt = _ptrTerrain->tr_attTiles[itt];
ASSERT(tt.GetVertices().Count()==9);
ASSERT(tt.GetIndices().Count()==24);
INDEX ctDelayedVertices = _avDelayedVertices.Count();
GFXVertex4 *pavVertices = &tt.GetVertices()[0];
GFXTexCoord *pauvTexCoords = &tt.GetTexCoords()[0];
GFXTexCoord *pauvShadowMapTC = &tt.GetShadowMapTC()[0];
INDEX *paiIndices = &tt.GetIndices()[0];
GFXVertex4 *pavDelVertices = _avDelayedVertices.Push(9);
GFXTexCoord *pauvDelTexCoords = _auvDelayedTexCoords.Push(9);
GFXTexCoord *pauvDelShadowMapTC = _auvDelayedShadowMapTC.Push(9);
INDEX *paiDelIndices = _aiDelayedIndices.Push(24);
// for each vertex in tile
for(INDEX ivx=0;ivx<9;ivx++) {
// copy vertex, texcoord & shadow map texcoord to delayed array
pavDelVertices[ivx] = pavVertices[ivx];
pauvDelTexCoords[ivx] = pauvTexCoords[ivx];
pauvDelShadowMapTC[ivx] = pauvShadowMapTC[ivx];
}
// for each index in tile
for(INDEX iind=0;iind<24;iind++) {
// reindex indice for new arrays
paiDelIndices[iind] = paiIndices[iind] + ctDelayedVertices;
}
_ctDelayedNodes++;
}
// returns haze/fog value in vertex
static FLOAT3D _vFViewerObj, _vHDirObj;
static FLOAT _fFogAddZ, _fFogAddH;
static FLOAT _fHazeAdd;
// check vertex against haze
#pragma message(">> no asm in GetHazeMapInVertex and GetFogMapInVertex")
static void GetHazeMapInVertex( GFXVertex4 &vtx, GFXTexCoord &txHaze)
{
const FLOAT fD = vtx.x*_vViewerObj(1) + vtx.y*_vViewerObj(2) + vtx.z*_vViewerObj(3);
txHaze.uv.u = (fD+_fHazeAdd) * _haze_fMul;
txHaze.uv.v = 0.0f;
}
static void GetFogMapInVertex( GFXVertex4 &vtx, GFXTexCoord &tex)
{
const FLOAT fD = vtx.x*_vFViewerObj(1) + vtx.y*_vFViewerObj(2) + vtx.z*_vFViewerObj(3);
const FLOAT fH = vtx.x*_vHDirObj(1) + vtx.y*_vHDirObj(2) + vtx.z*_vHDirObj(3);
tex.uv.u = (fD+_fFogAddZ) * _fog_fMulZ;
tex.uv.v = (fH+_fFogAddH) * _fog_fMulH;
}
static CStaticStackArray<GFXTexCoord> _atcHaze;
static CStaticStackArray<GFXColor> _acolHaze;
static void RenderFogLayer(INDEX itt)
{
FLOATmatrix3D &mViewer = _aprProjection->pr_ViewerRotationMatrix;
FLOAT3D vObjPosition = _ptrTerrain->tr_penEntity->en_plPlacement.pl_PositionVector;
// get viewer -z in object space
_vFViewerObj = FLOAT3D(0,0,-1) * !_mObjectToView;
// get fog direction in object space
_vHDirObj = _fog_vHDirAbs * !(!mViewer*_mObjectToView);
// get viewer offset
_fFogAddZ = _vViewer(1) * (vObjPosition(1) - _aprProjection->pr_vViewerPosition(1));
_fFogAddZ += _vViewer(2) * (vObjPosition(2) - _aprProjection->pr_vViewerPosition(2));
_fFogAddZ += _vViewer(3) * (vObjPosition(3) - _aprProjection->pr_vViewerPosition(3));
// get fog offset
_fFogAddH = (_fog_vHDirAbs % vObjPosition) + _fog_fp.fp_fH3;
GFXVertex *pvVtx;
INDEX *piIndices;
INDEX ctVertices;
INDEX ctIndices;
// if this is tile
if(itt>=0) {
CTerrainTile &tt = _ptrTerrain->tr_attTiles[itt];
pvVtx = &tt.GetVertices()[0];
piIndices = &tt.GetIndices()[0];
ctVertices = tt.GetVertices().Count();
ctIndices = tt.GetIndices().Count();
// else this are batched tiles
} else {
pvVtx = &_avDelayedVertices[0];
piIndices = &_aiDelayedIndices[0];
ctVertices = _avDelayedVertices.Count();
ctIndices = _aiDelayedIndices.Count();
}
GFXTexCoord *pfFogTC = _atcHaze.Push(ctVertices);
GFXColor *pcolFog = _acolHaze.Push(ctVertices);
const COLOR colF = AdjustColor( _fog_fp.fp_colColor, _slTexHueShift, _slTexSaturation);
GFXColor colFog(colF);
// for each vertex in tile
for(INDEX ivx=0;ivx<ctVertices;ivx++) {
GetFogMapInVertex(pvVtx[ivx],pfFogTC[ivx]);
pcolFog[ivx] = colFog;
}
// render fog layer
gfxDepthFunc(GFX_EQUAL);
gfxSetTextureWrapping( GFX_CLAMP, GFX_CLAMP);
gfxSetTexture( _fog_ulTexture, _fog_tpLocal);
gfxSetTexCoordArray(pfFogTC, FALSE);
gfxSetColorArray(pcolFog);
gfxBlendFunc( GFX_SRC_ALPHA, GFX_INV_SRC_ALPHA);
gfxEnableBlend();
gfxDisableAlphaTest();
gfxDrawElements(ctIndices,piIndices);
gfxDepthFunc(GFX_LESS_EQUAL);
_atcHaze.PopAll();
_acolHaze.PopAll();
}
static void RenderHazeLayer(INDEX itt)
{
FLOAT3D vObjPosition = _ptrTerrain->tr_penEntity->en_plPlacement.pl_PositionVector;
_fHazeAdd = -_haze_hp.hp_fNear;
_fHazeAdd += _vViewer(1) * (vObjPosition(1) - _aprProjection->pr_vViewerPosition(1));
_fHazeAdd += _vViewer(2) * (vObjPosition(2) - _aprProjection->pr_vViewerPosition(2));
_fHazeAdd += _vViewer(3) * (vObjPosition(3) - _aprProjection->pr_vViewerPosition(3));
GFXVertex *pvVtx;
INDEX *piIndices;
INDEX ctVertices;
INDEX ctIndices;
// if this is tile
if(itt>=0) {
CTerrainTile &tt = _ptrTerrain->tr_attTiles[itt];
pvVtx = &tt.GetVertices()[0];
piIndices = &tt.GetIndices()[0];
ctVertices = tt.GetVertices().Count();
ctIndices = tt.GetIndices().Count();
// else this are batched tiles
} else {
pvVtx = &_avDelayedVertices[0];
piIndices = &_aiDelayedIndices[0];
ctVertices = _avDelayedVertices.Count();
ctIndices = _aiDelayedIndices.Count();
}
GFXTexCoord *pfHazeTC = _atcHaze.Push(ctVertices);
GFXColor *pcolHaze = _acolHaze.Push(ctVertices);
const COLOR colH = AdjustColor( _haze_hp.hp_colColor, _slTexHueShift, _slTexSaturation);
GFXColor colHaze(colH);
// for each vertex in tile
for(INDEX ivx=0;ivx<ctVertices;ivx++) {
GetHazeMapInVertex(pvVtx[ivx],pfHazeTC[ivx]);
pcolHaze[ivx] = colHaze;
}
// render haze layer
gfxDepthFunc(GFX_EQUAL);
gfxSetTextureWrapping( GFX_CLAMP, GFX_CLAMP);
gfxSetTexture( _haze_ulTexture, _haze_tpLocal);
gfxSetTexCoordArray(pfHazeTC, FALSE);
gfxSetColorArray(pcolHaze);
gfxBlendFunc( GFX_SRC_ALPHA, GFX_INV_SRC_ALPHA);
gfxEnableBlend();
gfxDrawElements(ctIndices,piIndices);
gfxDepthFunc(GFX_LESS_EQUAL);
_atcHaze.PopAll();
_acolHaze.PopAll();
}
// Render one tile
static void RenderTile(INDEX itt)
{
ASSERT(_ptrTerrain!=NULL);
CTerrainTile &tt = _ptrTerrain->tr_attTiles[itt];
INDEX ctVertices = tt.GetVertices().Count();
extern INDEX ter_bOptimizeRendering;
// if tile is in posible lowest lod and doesn't have any border vertices
if(ter_bOptimizeRendering && tt.GetFlags()&TT_IN_LOWEST_LOD) {
// delay tile rendering
BatchTile(itt);
return;
}
GFXVertex4 *pavVertices;
// if vertex lerping is requested
if(ter_bLerpVertices==1) {
// Prepare smoth vertices
PrepareSmothVertices(itt);
pavVertices = &_avLerpedVerices[0];
} else {
// use non smoth vertices
pavVertices = &tt.GetVertices()[0];
}
// if tile is in highest lod
if(tt.tt_iLod==0) {
gfxBlendFunc(GFX_SRC_ALPHA, GFX_INV_SRC_ALPHA);
gfxSetVertexArray(pavVertices,ctVertices);
gfxLockArrays();
// for each tile layer
INDEX cttl= tt.GetTileLayers().Count();
for(INDEX itl=0;itl<cttl;itl++) {
CTerrainLayer &tl = _ptrTerrain->tr_atlLayers[itl];
// if layer isn't visible
if(!tl.tl_bVisible) {
continue; // skip it
}
TileLayer &ttl = tt.GetTileLayers()[itl];
// Set tile stretch
Matrix12 m12;
SetMatrixDiagonal(m12,tl.tl_fStretchX);
gfxSetTextureMatrix2(&m12);
// Set tile blend mode
if(tl.tl_fSmoothness==0) {
gfxDisableBlend();
gfxEnableAlphaTest();
} else {
gfxEnableBlend();
gfxDisableAlphaTest();
}
// if this tile has any polygons in this layer
INDEX ctIndices = ttl.tl_auiIndices.Count();
if(ctIndices>0) {
gfxSetTextureWrapping(GFX_REPEAT,GFX_REPEAT);
tl.tl_ptdTexture->SetAsCurrent();
// if this is tile layer
if(tl.tl_ltType==LT_TILE) {
gfxUnlockArrays();
GFXVertex4 *pavLayerVertices;
if(ter_bLerpVertices==1) {
PrepareSmothVerticesOnTileLayer(itt,itl);
pavLayerVertices = &_avLerpedTileLayerVertices[0];
} else {
pavLayerVertices = &ttl.tl_avVertices[0];
}
gfxSetVertexArray(pavLayerVertices,ttl.tl_avVertices.Count());
gfxLockArrays();
// gfxSetColorArray(&ttl.tl_acColors[0]);
gfxSetTexCoordArray(&ttl.tl_atcTexCoords[0], FALSE);
// set wireframe mode
/*
gfxEnableDepthBias();
gfxPolygonMode(GFX_LINE);
gfxDisableTexture();*/
gfxSetConstantColor(0xFFFFFFFF);
// Draw tiled layer
gfxDrawElements(ttl.tl_auiIndices.Count(),&ttl.tl_auiIndices[0]);
_ctTris +=ttl.tl_auiIndices.Count()/2;
/*
// set fill mode
gfxDisableDepthBias();
gfxPolygonMode(GFX_FILL);*/
// Set old vertex array
gfxUnlockArrays();
gfxSetVertexArray(pavVertices,ctVertices);
gfxLockArrays();
// if this is normal layer
} else {
// render layer
gfxSetColorArray(&ttl.tl_acColors[0]);
gfxSetTexCoordArray(&ttl.tl_atcTexCoords[0], FALSE);
gfxDrawElements(ctIndices,&ttl.tl_auiIndices[0]);
_ctTris +=ctIndices/2;
}
}
}
gfxSetTextureMatrix2(NULL);
INDEX ctIndices = tt.GetIndices().Count();
if(ctIndices>0) {
INDEX *paiIndices = &tt.GetIndices()[0];
// if detail map exists
if(_ptrTerrain->tr_ptdDetailMap!=NULL) {
gfxSetTextureWrapping(GFX_REPEAT,GFX_REPEAT);
gfxDisableAlphaTest();
shaBlendFunc( GFX_DST_COLOR, GFX_SRC_COLOR);
gfxEnableBlend();
gfxSetTexCoordArray(&tt.GetDetailTC()[0], FALSE);
_ptrTerrain->tr_ptdDetailMap->SetAsCurrent();
gfxDrawElements(ctIndices,paiIndices);
}
// if shadows are visible
if(_wrpWorldRenderPrefs.wrp_shtShadows!=CWorldRenderPrefs::SHT_NONE) {
gfxDisableAlphaTest();
shaBlendFunc( GFX_DST_COLOR, GFX_SRC_COLOR);
gfxEnableBlend();
gfxSetTextureWrapping(GFX_CLAMP,GFX_CLAMP);
gfxSetTexCoordArray(&tt.GetShadowMapTC()[0], FALSE);
_ptrTerrain->tr_tdShadowMap.SetAsCurrent();
gfxDrawElements(ctIndices,paiIndices);
}
}
// if tile is not in highest lod
} else {
gfxSetTextureWrapping(GFX_CLAMP,GFX_CLAMP);
// if tile is in lowest lod
if(tt.tt_iLod == _ptrTerrain->tr_iMaxTileLod) {
// use terrains global top map
_ptrTerrain->tr_tdTopMap.SetAsCurrent();
// else tile is in some midle lod
} else {
// use its own topmap
tt.GetTopMap()->SetAsCurrent();
}
// Render tile
INDEX ctIndices = tt.GetIndices().Count();
gfxEnableAlphaTest();
gfxDisableBlend();
gfxSetVertexArray(pavVertices,ctVertices);
gfxSetTexCoordArray(&tt.GetTexCoords()[0], FALSE);
FillConstColorArray(ctVertices);
gfxSetColorArray(&_acolVtxConstColors[0]);
gfxLockArrays();
gfxDrawElements(ctIndices,&tt.GetIndices()[0]);
_ctTris +=ctIndices/2;
gfxDisableAlphaTest();
// if shadows are visible
if(_wrpWorldRenderPrefs.wrp_shtShadows!=CWorldRenderPrefs::SHT_NONE) {
gfxDepthFunc(GFX_EQUAL);
INDEX ctIndices = tt.GetIndices().Count();
INDEX *paiIndices = &tt.GetIndices()[0];
gfxSetTextureWrapping(GFX_CLAMP,GFX_CLAMP);
gfxBlendFunc(GFX_DST_COLOR,GFX_SRC_COLOR);
gfxEnableBlend();
gfxSetTexCoordArray(&tt.GetShadowMapTC()[0], FALSE);
_ptrTerrain->tr_tdShadowMap.SetAsCurrent();
gfxDrawElements(ctIndices,paiIndices);
gfxDepthFunc(GFX_LESS_EQUAL);
}
}
if(_ptrTerrain->GetFlags()&TR_HAS_FOG) {
RenderFogLayer(itt);
}
if(_ptrTerrain->GetFlags()&TR_HAS_HAZE) {
RenderHazeLayer(itt);
}
gfxUnlockArrays();
}
// Draw one quad tree node ( draws terrain tile if leaf node )
static void DrawQuadTreeNode(INDEX iqtn)
{
ASSERT(_ptrTerrain!=NULL);
CEntity *pen = _ptrTerrain->tr_penEntity;
QuadTreeNode &qtn = _ptrTerrain->tr_aqtnQuadTreeNodes[iqtn];
FLOATmatrix3D &mAbsToView = _aprProjection->pr_ViewerRotationMatrix;
FLOATobbox3D obbox = FLOATobbox3D( qtn.qtn_aabbox,
(pen->en_plPlacement.pl_PositionVector-_aprProjection->pr_vViewerPosition)*mAbsToView, mAbsToView*pen->en_mRotation);
INDEX iFrustumTest = _aprProjection->TestBoxToFrustum(obbox);
if(iFrustumTest!=(-1)) {
// is this leaf node
if(qtn.qtn_iTileIndex != -1) {
_ctNodesVis++;
// draw terrain tile for this node
RenderTile(qtn.qtn_iTileIndex);
// this node has some children
} else {
for(INDEX iqc=0;iqc<4;iqc++) {
INDEX iChildNode = qtn.qtn_iChild[iqc];
// if child node exists
if(iChildNode != -1) {
// draw child node
DrawQuadTreeNode(qtn.qtn_iChild[iqc]);
}
}
}
}
}
// Render one terrain
void RenderTerrain(void)
{
ASSERT(_ptrTerrain!=NULL);
ASSERT(_ptrTerrain->tr_penEntity!=NULL);
_ctNodesVis = 0;
_ctTris = 0;
_ctDelayedNodes = 0;
// draw node from last level
INDEX ctqtl = _ptrTerrain->tr_aqtlQuadTreeLevels.Count();
QuadTreeLevel &qtl = _ptrTerrain->tr_aqtlQuadTreeLevels[ctqtl-1];
DrawQuadTreeNode(qtl.qtl_iFirstNode);
// if any delayed tiles
if(_ctDelayedNodes>0) {
// Draw delayed tiles
RenderBatchedTiles();
}
//CEntity *pen = _ptrTerrain->tr_penEntity;
extern void ShowRayPath(CDrawPort *pdp);
ShowRayPath(_pdp);
/*
extern CStaticStackArray<GFXVertex> _avExtVertices;
extern CStaticStackArray<INDEX> _aiExtIndices;
extern FLOATaabbox3D _bboxDrawOne;
extern FLOATaabbox3D _bboxDrawTwo;
#pragma message(">> Remove gfxDrawWireBox")
FLOATaabbox3D bboxAllTerrain;
extern FLOAT3D _vHitBegin;
extern FLOAT3D _vHitEnd;
extern FLOAT3D _vHitExact;
_ptrTerrain->GetAllTerrainBBox(bboxAllTerrain);
gfxDrawWireBox(bboxAllTerrain,0xFFFF00FF);
gfxEnableDepthBias();
gfxDisableDepthTest();
_pdp->DrawPoint3D(_vHitBegin,0x00FF00FF,8);
_pdp->DrawPoint3D(_vHitEnd,0xFF0000FF,8);
_pdp->DrawPoint3D(_vHitExact,0x00FFFF,8);
_pdp->DrawLine3D(_vHitBegin,FLOAT3D(_vHitEnd(1),_vHitBegin(2),_vHitEnd(3)),0x00FF00FF);
_pdp->DrawLine3D(FLOAT3D(_vHitBegin(1),_vHitEnd(2),_vHitBegin(3)),_vHitEnd,0xFF0000FF);
_pdp->DrawLine3D(_vHitBegin,_vHitEnd,0xFFFF00FF);
gfxEnableDepthTest();
gfxDisableDepthBias();
*/
//gfxDrawWireBox(_bboxDrawOne,0xFF0000FF);
//gfxDrawWireBox(_bboxDrawTwo,0x0000FFFF);
//gfxDrawWireBox(_bboxDrawNextFrame,0xFFFFFFFF);
}
// Render one tile in wireframe mode
static void RenderWireTile(INDEX itt)
{
ASSERT(_ptrTerrain!=NULL);
CTerrainTile &tt = _ptrTerrain->tr_attTiles[itt];
INDEX ctVertices = tt.GetVertices().Count();
GFXVertex4 *pavVertices;
if(ter_bLerpVertices) {
PrepareSmothVertices(itt);
pavVertices = &_avLerpedVerices[0];
} else {
pavVertices = &tt.GetVertices()[0];
}
INDEX ctIndices = tt.GetIndices().Count();
if(ctIndices>0) {
gfxDisableBlend();
gfxDisableTexture();
gfxSetConstantColor(_colTerrainEdges);
gfxSetVertexArray(pavVertices,ctVertices);
gfxLockArrays();
gfxDrawElements(ctIndices,&tt.GetIndices()[0]);
gfxUnlockArrays();
}
}
// Draw one quad tree node ( draws terrain tile in wireframe mode if leaf node )
static void DrawWireQuadTreeNode(INDEX iqtn)
{
ASSERT(_ptrTerrain!=NULL);
CEntity *pen = _ptrTerrain->tr_penEntity;
QuadTreeNode &qtn = _ptrTerrain->tr_aqtnQuadTreeNodes[iqtn];
FLOATmatrix3D &mAbsToView = _aprProjection->pr_ViewerRotationMatrix;
FLOATobbox3D obbox = FLOATobbox3D( qtn.qtn_aabbox,
(pen->en_plPlacement.pl_PositionVector-_aprProjection->pr_vViewerPosition)*mAbsToView, mAbsToView*pen->en_mRotation);
INDEX iFrustumTest = _aprProjection->TestBoxToFrustum(obbox);
if(iFrustumTest!=(-1)) {
// is this leaf node
if(qtn.qtn_iTileIndex != -1) {
_ctNodesVis++;
// draw terrain tile for this node
RenderWireTile(qtn.qtn_iTileIndex);
// this node has some children
} else {
for(INDEX iqc=0;iqc<4;iqc++) {
INDEX iChildNode = qtn.qtn_iChild[iqc];
// if child node exists
if(iChildNode != -1) {
// draw child node
DrawWireQuadTreeNode(qtn.qtn_iChild[iqc]);
}
}
}
}
}
// Render one terrain in wireframe mode
void RenderTerrainWire(COLOR &colEdges)
{
// set wireframe mode
gfxEnableDepthBias();
gfxPolygonMode(GFX_LINE);
// remember edges color
_colTerrainEdges = colEdges;
ASSERT(_ptrTerrain!=NULL);
// draw last node
INDEX ctqtl = _ptrTerrain->tr_aqtlQuadTreeLevels.Count();
QuadTreeLevel &qtl = _ptrTerrain->tr_aqtlQuadTreeLevels[ctqtl-1];
DrawWireQuadTreeNode(qtl.qtl_iFirstNode);
// set fill mode
gfxDisableDepthBias();
gfxPolygonMode(GFX_FILL);
}
// Draw terrain quad tree
void DrawQuadTree(void)
{
ASSERT(_ptrTerrain!=NULL);
QuadTreeLevel &qtl = _ptrTerrain->tr_aqtlQuadTreeLevels[0];
gfxDisableTexture();
// for each quad tree node
for(INDEX iqtn=qtl.qtl_iFirstNode;iqtn<qtl.qtl_iFirstNode+qtl.qtl_ctNodes;iqtn++) {
// draw node
QuadTreeNode &qtn = _ptrTerrain->tr_aqtnQuadTreeNodes[iqtn];
gfxDrawWireBox(qtn.qtn_aabbox,0x00FF00FF);
}
}
void DrawSelectedVertices(GFXVertex *pavVertices, GFXColor *pacolColors, INDEX ctVertices)
{
gfxEnableDepthBias();
// for each vertex
for(INDEX ivx=0;ivx<ctVertices;ivx++) {
GFXVertex &vtx = pavVertices[ivx];
GFXColor &col = pacolColors[ivx];
// draw vertex
_pdp->DrawPoint3D(FLOAT3D(vtx.x,vtx.y,vtx.z),ByteSwap(col.ul.abgr),3);
}
gfxDisableDepthBias();
}
// TEMP - Draw one AABBox
void gfxDrawWireBox(FLOATaabbox3D &bbox, COLOR col)
{
FLOAT3D vMinVtx = bbox.Min();
FLOAT3D vMaxVtx = bbox.Max();
// fill vertex array so it represents bounding box
FLOAT3D vBoxVtxs[8];
vBoxVtxs[0] = FLOAT3D( vMinVtx(1), vMinVtx(2), vMinVtx(3));
vBoxVtxs[1] = FLOAT3D( vMaxVtx(1), vMinVtx(2), vMinVtx(3));
vBoxVtxs[2] = FLOAT3D( vMaxVtx(1), vMinVtx(2), vMaxVtx(3));
vBoxVtxs[3] = FLOAT3D( vMinVtx(1), vMinVtx(2), vMaxVtx(3));
vBoxVtxs[4] = FLOAT3D( vMinVtx(1), vMaxVtx(2), vMinVtx(3));
vBoxVtxs[5] = FLOAT3D( vMaxVtx(1), vMaxVtx(2), vMinVtx(3));
vBoxVtxs[6] = FLOAT3D( vMaxVtx(1), vMaxVtx(2), vMaxVtx(3));
vBoxVtxs[7] = FLOAT3D( vMinVtx(1), vMaxVtx(2), vMaxVtx(3));
// connect vertices into lines of bounding box
INDEX iBoxLines[12][2];
iBoxLines[ 0][0] = 0; iBoxLines[ 0][1] = 1; iBoxLines[ 1][0] = 1; iBoxLines[ 1][1] = 2;
iBoxLines[ 2][0] = 2; iBoxLines[ 2][1] = 3; iBoxLines[ 3][0] = 3; iBoxLines[ 3][1] = 0;
iBoxLines[ 4][0] = 0; iBoxLines[ 4][1] = 4; iBoxLines[ 5][0] = 1; iBoxLines[ 5][1] = 5;
iBoxLines[ 6][0] = 2; iBoxLines[ 6][1] = 6; iBoxLines[ 7][0] = 3; iBoxLines[ 7][1] = 7;
iBoxLines[ 8][0] = 4; iBoxLines[ 8][1] = 5; iBoxLines[ 9][0] = 5; iBoxLines[ 9][1] = 6;
iBoxLines[10][0] = 6; iBoxLines[10][1] = 7; iBoxLines[11][0] = 7; iBoxLines[11][1] = 4;
// for all vertices in bounding box
for( INDEX i=0; i<12; i++) {
// get starting and ending vertices of one line
FLOAT3D &v0 = vBoxVtxs[iBoxLines[i][0]];
FLOAT3D &v1 = vBoxVtxs[iBoxLines[i][1]];
_pdp->DrawLine3D(v0,v1,col);
}
}