2016-03-11 14:57:17 +01:00
|
|
|
/* Copyright (c) 2002-2012 Croteam Ltd. All rights reserved. */
|
|
|
|
|
2016-03-29 03:03:54 +02:00
|
|
|
#include "Engine/StdH.h"
|
2016-03-11 14:57:17 +01:00
|
|
|
#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>
|
2016-03-29 03:03:54 +02:00
|
|
|
#include <Engine/Graphics/DrawPort.h>
|
2016-03-11 14:57:17 +01:00
|
|
|
#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;
|
|
|
|
|
|
|
|
|
2016-03-29 03:03:54 +02:00
|
|
|
const CPlacement3D &plTerrain = pen->GetLerpedPlacement();
|
2016-03-11 14:57:17 +01:00
|
|
|
|
|
|
|
_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);
|
2016-03-29 03:03:54 +02:00
|
|
|
txHaze.uv.u = (fD+_fHazeAdd) * _haze_fMul;
|
|
|
|
txHaze.uv.v = 0.0f;
|
2016-03-11 14:57:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2016-03-29 03:03:54 +02:00
|
|
|
tex.uv.u = (fD+_fFogAddZ) * _fog_fMulZ;
|
|
|
|
tex.uv.v = (fH+_fFogAddH) * _fog_fMulH;
|
2016-03-11 14:57:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2016-03-29 03:03:54 +02:00
|
|
|
_pdp->DrawPoint3D(FLOAT3D(vtx.x,vtx.y,vtx.z),ByteSwap(col.ul.abgr),3);
|
2016-03-11 14:57:17 +01:00
|
|
|
}
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|