📄 terrrender.cc
字号:
*zDiff = vec.z;
return vec.len();
}
void TerrainRender::emitTerrChunk(SquareStackNode *n, F32 squareDistance, U32 lightMask, bool farClip, bool drawDetails, bool drawBumps)
{
//if(n->pos.x || n->pos.y)
// return;
GridChunk *gc = mCurrentBlock->findChunk(n->pos);
EmitChunk *chunk = (EmitChunk *) FrameAllocator::alloc(sizeof(EmitChunk));
chunk->x = n->pos.x + mBlockOffset.x + mTerrainOffset.x;
chunk->y = n->pos.y + mBlockOffset.y + mTerrainOffset.y;
chunk->gridX = n->pos.x;
chunk->gridY = n->pos.y;
chunk->lightMask = lightMask;
chunk->next = mCurrentTexture->list;
mCurrentTexture->list = chunk;
if(mRenderingCommander)
return;
chunk->edge[0] = (ChunkEdge *) n->top;
chunk->edge[1] = (ChunkEdge *) n->right;
chunk->edge[2] = (ChunkEdge *) n->bottom;
chunk->edge[3] = (ChunkEdge *) n->left;
chunk->edge[0]->c2 = chunk;
chunk->edge[1]->c1 = chunk;
chunk->edge[2]->c1 = chunk;
chunk->edge[3]->c2 = chunk;
// holes only in the primary terrain block
if (gc->emptyFlags && mBlockPos.x == 0 && mBlockPos.y == 0)
chunk->emptyFlags = gc->emptyFlags;
else
chunk->emptyFlags = 0;
S32 subDivLevel;
F32 growFactor = 0;
F32 minSubdivideDistance = 1000000;
chunk->clip = farClip;
chunk->renderDetails = drawDetails;
chunk->renderBumps = drawBumps;
if(squareDistance < 1)
subDivLevel = -1;
else
{
for(subDivLevel = 2; subDivLevel >= 0; subDivLevel--)
{
F32 subdivideDistance = fixedToFloat(gc->heightDeviance[subDivLevel]) / mPixelError;
if(subdivideDistance > minSubdivideDistance)
subdivideDistance = minSubdivideDistance;
if(squareDistance >= subdivideDistance)
break;
F32 clampDistance = subdivideDistance * 0.75;
if(squareDistance > clampDistance)
{
growFactor = (squareDistance - clampDistance) / (0.25 * subdivideDistance);
subDivLevel--;
break;
}
minSubdivideDistance = clampDistance;
}
}
chunk->subDivLevel = subDivLevel;
chunk->growFactor = growFactor;
}
void TerrainRender::processCurrentBlock(SceneState*, EdgeParent *topEdge, EdgeParent *rightEdge, EdgeParent *bottomEdge, EdgeParent *leftEdge)
{
SquareStackNode stack[TerrainBlock::BlockShift*4];
Point3F minPoint, maxPoint;
stack[0].level = TerrainBlock::BlockShift;
stack[0].clipFlags = ((1 << mNumClipPlanes) - 1) | FarSphereMask; // test all the planes
stack[0].pos.set(0,0);
stack[0].top = topEdge;
stack[0].right = rightEdge;
stack[0].bottom = bottomEdge;
stack[0].left = leftEdge;
stack[0].lightMask = (1 << mDynamicLightCount) - 1; // test all the lights
stack[0].texAllocated = false;
Vector<SceneState::FogBand> *posFog = mSceneState->getPosFogBands();
Vector<SceneState::FogBand> *negFog = mSceneState->getNegFogBands();
bool clipAbove = posFog->size() > 0 && (*posFog)[0].isFog == false;
bool clipBelow = negFog->size() > 0 && (*negFog)[0].isFog == false;
bool clipOn = posFog->size() > 0 && (*posFog)[0].isFog == true;
if(posFog->size() != 0 || negFog->size() != 0)
stack[0].clipFlags |= FogPlaneBoxMask;
S32 curStackSize = 1;
F32 squareDistance;
F32 worldToScreenScale = dglProjectRadius(1,1);
F32 zeroDetailDistance = (mSquareSize * worldToScreenScale) / (1 << 6) - (mSquareSize >> 1);
F32 zeroBumpDistance = (mSquareSize * worldToScreenScale) / (1 << mCurrentBlock->mZeroBumpScale) - (mSquareSize >> 1);
while(curStackSize)
{
SquareStackNode *n = stack + curStackSize - 1;
// see if it's visible
GridSquare *sq = mCurrentBlock->findSquare(n->level, n->pos);
minPoint.set(mSquareSize * n->pos.x + mBlockPos.x,
mSquareSize * n->pos.y + mBlockPos.y,
fixedToFloat(sq->minHeight));
maxPoint.set(minPoint.x + (mSquareSize << n->level),
minPoint.y + (mSquareSize << n->level),
fixedToFloat(sq->maxHeight));
// holes only in the primary terrain block
if ((sq->flags & GridSquare::Empty) && mBlockPos.x == 0 && mBlockPos.y == 0)
{
curStackSize--;
continue;
}
F32 zDiff;
squareDistance = getSquareDistance(minPoint, maxPoint, &zDiff);
S32 nextClipFlags = 0;
if(n->clipFlags)
{
if(n->clipFlags & FogPlaneBoxMask)
{
F32 camZ = mCamPos.z;
bool boxBelow = camZ > maxPoint.z;
bool boxAbove = camZ < minPoint.z;
bool boxOn = !(boxAbove || boxBelow);
if( clipOn ||
(clipAbove && boxAbove && (maxPoint.z - camZ > (*posFog)[0].cap)) ||
(clipBelow && boxBelow && (camZ - minPoint.z > (*negFog)[0].cap)) ||
(boxOn && (( clipAbove && maxPoint.z - camZ > (*posFog)[0].cap ) ||
( clipBelow && camZ - minPoint.z > (*negFog)[0].cap ))))
{
// Using the fxSunLight can cause the "sky" to extend down below the camera.
// To avoid the sun showing through, the terrain must always be rendered.
// If the fxSunLight is not being used, the following optimization can be
// uncommented.
#if 0
if(boxBelow && !mSceneState->isBoxFogVisible(squareDistance, maxPoint.z, minPoint.z))
{
// Totally fogged terrain tiles can be thrown out as long as they are
// below the camera. If they are ubove, the sky will show through the
// fog.
curStackSize--;
continue;
}
#endif
nextClipFlags |= FogPlaneBoxMask;
}
}
if(n->clipFlags & FarSphereMask)
{
if(squareDistance >= mFarDistance)
{
curStackSize--;
continue;
}
S32 squareSz = mSquareSize << n->level;
if(squareDistance + maxPoint.z - minPoint.z + squareSz + squareSz > mFarDistance)
nextClipFlags |= FarSphereMask;
}
// zDelta for screen error height deviance.
F32 zDelta = squareDistance * mPixelError;
minPoint.z -= zDelta;
maxPoint.z += zDelta;
nextClipFlags |= TestSquareVisibility(minPoint, maxPoint, n->clipFlags, mSquareSize);
if(nextClipFlags == -1)
{
//if(!n->texAllocated)
// textureRecurse(n);
// trivially rejected, so pop it off the stack
curStackSize--;
continue;
}
}
if(!n->texAllocated)
{
S32 squareSz = mSquareSize << n->level;
// first check the level - if its 3 or less, we have to just make a bitmap:
// level 3 == 8x8 square - 8x8 * 16x16 == 128x128
if(n->level > 6)
goto notexalloc;
S32 mipLevel = TerrainTextureMipLevel;
if(!mRenderingCommander)
{
if(n->level > mTextureMinSquareSize + 2)
{
// get the mip level of the square and see if we're in range
if(squareDistance > 0.001)
{
S32 size = S32(dglProjectRadius(squareDistance + (squareSz >> 1), squareSz));
mipLevel = getPower((S32)(size * 0.75));
if(mipLevel > TerrainTextureMipLevel) // too big for this square
goto notexalloc;
}
else
goto notexalloc;
}
}
allocTerrTexture(n->pos, n->level, mipLevel, true, squareDistance);
n->texAllocated = true;
if(mRenderingCommander) // level == 6
{
emitTerrChunk(n, 0, 0, 0, 0, 0);
curStackSize--;
continue;
}
}
notexalloc:
if(n->lightMask)
n->lightMask = TestSquareLights(sq, n->level, n->pos, n->lightMask);
if(n->level == 2)
{
AssertFatal(n->texAllocated, "Invalid texture index.");
bool drawDetails = false;
if (mEnableTerrainDetails && squareDistance < zeroDetailDistance)
drawDetails = true;
//END
bool drawBumps = false;
// CW - stuff with bump maps
if (mEnableTerrainEmbossBumps && squareDistance < zeroBumpDistance)
drawBumps = true;
// CW - end bump map stuff
emitTerrChunk(n, squareDistance, n->lightMask, nextClipFlags & FarSphereMask, drawDetails, drawBumps);
curStackSize--;
continue;
}
bool allocChunkEdges = (n->level == 3);
Point2I pos = n->pos;
ChunkScanEdge *top = (ChunkScanEdge *) n->top;
ChunkScanEdge *right = (ChunkScanEdge *) n->right;
ChunkScanEdge *bottom = (ChunkScanEdge *) n->bottom;
ChunkScanEdge *left = (ChunkScanEdge *) n->left;
// subdivide this square and throw it on the stack
S32 squareOneSize = 1 << n->level;
S32 squareHalfSize = squareOneSize >> 1;
ChunkCornerPoint *midPoint = allocPoint(Point2I(pos.x + squareHalfSize, pos.y + squareHalfSize));
S32 nextLevel = n->level - 1;
subdivideChunkEdge(top, Point2I(pos.x + squareHalfSize, pos.y + squareOneSize), allocChunkEdges);
subdivideChunkEdge(right, Point2I(pos.x + squareOneSize, pos.y + squareHalfSize), allocChunkEdges);
subdivideChunkEdge(bottom, Point2I(pos.x + squareHalfSize, pos.y), allocChunkEdges);
subdivideChunkEdge(left, Point2I(pos.x, pos.y + squareHalfSize), allocChunkEdges);
// cross edges go top, right, bottom, left
EdgeParent *crossEdges[4];
allocRenderEdges(4, crossEdges, allocChunkEdges);
crossEdges[0]->p1 = top->mp;
crossEdges[0]->p2 = midPoint;
crossEdges[1]->p1 = midPoint;
crossEdges[1]->p2 = right->mp;
crossEdges[2]->p1 = midPoint;
crossEdges[2]->p2 = bottom->mp;
crossEdges[3]->p1 = left->mp;
crossEdges[3]->p2 = midPoint;
n->level = nextLevel;
n->clipFlags = nextClipFlags;
for(S32 i = 1; i < 4; i++)
{
n[i].level = nextLevel;
n[i].clipFlags = nextClipFlags;
n[i].lightMask = n->lightMask;
n[i].texAllocated = n->texAllocated;
}
// push in reverse order of processing.
n[3].pos = pos;
n[3].top = crossEdges[3];
n[3].right = crossEdges[2];
n[3].bottom = bottom->e1;
n[3].left = left->e2;
n[2].pos.set(pos.x + squareHalfSize, pos.y);
n[2].top = crossEdges[1];
n[2].right = right->e2;
n[2].bottom = bottom->e2;
n[2].left = crossEdges[2];
n[1].pos.set(pos.x, pos.y + squareHalfSize);
n[1].top = top->e1;
n[1].right = crossEdges[0];
n[1].bottom = crossEdges[3];
n[1].left = left->e1;
n[0].pos.set(pos.x + squareHalfSize, pos.y + squareHalfSize);
n[0].top = top->e2;
n[0].right = right->e1;
n[0].bottom = crossEdges[1];
n[0].left = crossEdges[0];
curStackSize += 3;
}
}
//---------------------------------------------------------------
//---------------------------------------------------------------
// Root block render function
//---------------------------------------------------------------
//---------------------------------------------------------------
void TerrainRender::fixEdge(ChunkEdge *edge, S32 x, S32 y, S32 dx, S32 dy)
{
S32 minLevel, maxLevel;
F32 growFactor;
if(edge->c1)
{
minLevel = edge->c1->subDivLevel;
maxLevel = edge->c1->subDivLevel;
growFactor = edge->c1->growFactor;
if(edge->c2)
{
if(edge->c2->subDivLevel < minLevel)
minLevel = edge->c2->subDivLevel;
else if(edge->c2->subDivLevel > maxLevel)
{
maxLevel = edge->c2->subDivLevel;
growFactor = edge->c2->growFactor;
}
else if(edge->c2->growFactor > growFactor)
growFactor = edge->c2->growFactor;
}
}
else
{
minLevel = maxLevel = edge->c2->subDivLevel;
growFactor = edge->c2->growFactor;
}
if(minLevel == 2)
{
edge->pointCount = 0;
return;
}
// get the mid heights
EdgePoint *pmid = &edge->pt[1];
ChunkCornerPoint *p1 = edge->p1;
ChunkCornerPoint *p2 = edge->p2;
pmid->x = (p1->x + p2->x) * 0.5;
pmid->y = (p1->y + p2->y) * 0.5;
if(maxLevel == 2)
{
// pure interp
pmid->z = (p1->z + p2->z) * 0.5;
pmid->distance = (*pmid - mCamPos).len();
pmid->fogRed = (p1->fogRed + p2->fogRed) * 0.5;
pmid->fogGreen = (p1->fogGreen + p2->fogGreen) * 0.5;
if(minLevel >= 0)
{
edge->pointCount = 1;
return;
}
}
else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -