📄 terrrender.cc
字号:
buildLightTri(&lightTris[j], &mTerrainLights[i]);
}
start += count;
} else {
AssertFatal(mXFIndexBuffer[start] == GL_TRIANGLES, "Error, bad start code!");
start++;
U32 count = mXFIndexBuffer[start];
AssertFatal((count / 3) * 3 == count, "Error, vertex count not divisible by 3!");
U32 triCount = count/3;
LightTriangle* lightTris = (LightTriangle*)FrameAllocator::alloc(sizeof(LightTriangle) * triCount);
U32 j;
for (j = 0; j < (triCount-1); j++)
lightTris[j].next = &lightTris[j+1];
lightTris[triCount-1].next = sgCurrLightTris;
sgCurrLightTris = lightTris;
// Copy out tri data here...
for (j = 0; j < triCount; j++) {
lightTris[j].point1 = mXFVertices[mXFIndexBuffer[start + 1 + (j*3) + 0]];
lightTris[j].point2 = mXFVertices[mXFIndexBuffer[start + 1 + (j*3) + 1]];
lightTris[j].point3 = mXFVertices[mXFIndexBuffer[start + 1 + (j*3) + 2]];
buildLightTri(&lightTris[j], &mTerrainLights[i]);
}
start += count;
}
}
}
}
}
/*void TerrainRender::drawTriFan(U32 vCount, U32 *indexBuffer)
{
glBegin(GL_LINES);
U32 cur = vCount - 1;
for(U32 i = 1; i < vCount; i++)
{
glArrayElement(indexBuffer[0]);
glArrayElement(indexBuffer[cur]);
glArrayElement(indexBuffer[cur]);
glArrayElement(indexBuffer[i]);
cur = i;
}
glEnd();
}*/
void TerrainRender::renderXFCache()
{
U32 count = 0;
while (count < mXFIndexCount)
{
U32 mode = mXFIndexBuffer[count];
U32 vertexCount = mXFIndexBuffer[count + 1];
glDrawElements(mode, vertexCount, GL_UNSIGNED_SHORT, mXFIndexBuffer + count + 2);
count += vertexCount + 2;
}
}
void doTexGens(Point4F &s, Point4F &t)
{
EdgePoint *pt = mXFVertices;
EdgePoint *last = pt + mXFPointCount;
for(;pt < last; pt++)
{
pt->haze = pt->x * s.x + pt->y * s.y + pt->z * s.z + s.w;
pt->distance = pt->x * t.x + pt->y * t.y + pt->z * t.z + t.w;
}
}
#ifdef TORQUE_OS_WIN32
void TerrainRender::renderD3DBumps(Point2F bumpTextureOffset)
{
PROFILE_START(TerrainRenderBumpsD3D);
glColor3f(1.0,1.0,1.0);
//First pass - normal bump map, no blending, no offset
doTexGens(bumpTexGenS, bumpTexGenT);
glBindTexture(GL_TEXTURE_2D, mCurrentBlock->mBumpTextureHandle.getGLName());
renderXFCache();
//Second pass - inverted bump map, additive blending, offset
Point4F bumpTexGenOS = bumpTexGenS;
Point4F bumpTexGenOT = bumpTexGenT;
bumpTexGenOS.w += bumpTextureOffset.x;
bumpTexGenOT.w += bumpTextureOffset.y;
doTexGens(bumpTexGenOS, bumpTexGenOT);
glBindTexture(GL_TEXTURE_2D, mCurrentBlock->mInvertedBumpTextureHandle.getGLName());
glBlendFunc(GL_ONE, GL_ONE);
glEnable(GL_BLEND);
renderXFCache();
//Setup blending for the terrain pass
glBlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
PROFILE_END();
}
#endif
void TerrainRender::renderGLBumps(Point2F bumpTextureOffset, U32 hazeName)
{
PROFILE_START(TerrainRenderBumpsGL);
//have to set color to white or bumps turn up black on the terrain
glColor3f(1.0,1.0,1.0);
doTexGens(bumpTexGenS, bumpTexGenT);
//Set up TMU #0
//Normal bump texture
glBindTexture(GL_TEXTURE_2D, mCurrentBlock->mBumpTextureHandle.getGLName());
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
//Set up TMU #1
//Inverted bump texture
//Offset the texture matrix
glActiveTextureARB(GL_TEXTURE1_ARB);
glClientActiveTextureARB(GL_TEXTURE1_ARB);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, mCurrentBlock->mInvertedBumpTextureHandle.getGLName());
glTexCoordPointer(2, GL_FLOAT, sizeof(EdgePoint), &mXFVertices->haze);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD);
glMatrixMode(GL_TEXTURE);
glPushMatrix();
glTranslatef(bumpTextureOffset.x, bumpTextureOffset.y, 0.0);
//Render!
renderXFCache();
//Restore TMU #1
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
glBindTexture(GL_TEXTURE_2D, hazeName);
glTexCoordPointer(2, GL_FLOAT, sizeof(EdgePoint), &mXFVertices->fogRed);
//Restore TMU #0
glActiveTextureARB(GL_TEXTURE0_ARB);
glClientActiveTextureARB(GL_TEXTURE0_ARB);
//Set up for the bump mapping application
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glEnable(GL_BLEND);
//Do the rest in the function
PROFILE_END();
}
void TerrainRender::renderBlock(TerrainBlock *block, SceneState *state)
{
PROFILE_START(TerrainRender);
PROFILE_START(TerrainRenderSetup);
dglSetRenderPrimType(1);
U32 storedWaterMark = FrameAllocator::getWaterMark();
if (sgTextureFreeListPrimed == false) {
sgTextureFreeListPrimed = true;
AssertFatal(mTextureFreeList.size() == 0, "Error, unprimed free list should always be size 0");
mTextureFreeList.setSize(sgFreeListPrimeCount);
for (U32 i = 0; i < sgFreeListPrimeCount; i++) {
constructInPlace(&mTextureFreeList[i]);
mTextureFreeList[i] = TextureHandle((const char*)NULL, mBlendBitmap, TerrainTexture, true);
}
}
mFrameIndex++;
mSceneState = state;
mFarDistance = state->getVisibleDistance();
dglGetModelview(&mCameraToObject);
mCameraToObject.inverse();
mCameraToObject.getColumn(3, &mCamPos);
mFogColor = state->getFogColor();
TextureHandle hazeTexture = gClientSceneGraph->getFogTexture();
mCurrentBlock = block;
Point4F detTexGenS = Point4F(1, 0, 0, 0);
Point4F detTexGenT = Point4F(0, 1, 0, 0);
if (mEnableTerrainDetails && mCurrentBlock->mDetailTextureHandle.getGLName() != 0) {
detTexGenS.x *= 62.0 / mCurrentBlock->mDetailTextureHandle.getWidth();
detTexGenT.y *= 62.0 / mCurrentBlock->mDetailTextureHandle.getHeight();
detTexGenS.w = -(S32) (mCamPos.x*detTexGenS.x);
detTexGenT.w = -(S32) (mCamPos.y*detTexGenT.y);
}
// CW - stuff with bump maps
//calculate the texture offset
if (mEnableTerrainEmbossBumps && mCurrentBlock->mBumpTextureHandle.getGLName() != 0)
{
PROFILE_START(TerrainRenderBumpBuild);
//There should be a better way to do this, really...
#ifdef TORQUE_OS_WIN32
if (dStrcmp(Con::getVariable( "$pref::Video::displayDevice" ), "OpenGL") == 0)
mRenderGL = true;
else
mRenderGL = false;
#endif
//note: don't multiply light by inverse modelview matrix
//because it is already in object space (or world or anything, really)
//The first light in the light manager is always the sun.
//This is also how players are lit, so if this is broken, that is broken as well.
Point3F sTangent,tTangent;
//celestial
// VectorF sunVector = gClientSceneGraph->getLightManager()->getShadowLightDirection();
VectorF sunVector;
if(gCelestials == NULL)
sunVector = gClientSceneGraph->getLightManager()->getShadowLightDirection();
else
sunVector = gCelestials->mSunVector;
//celestial end
//find s and t tangents
F32 pHeight[4];
for (int i = 0; i < 4; i++)
{
int x = i == 0 || i == 3 ? 0 : 255;
int y = i == 1 || i == 2 ? 0 : 255;
block->getHeight(Point2F(x,y), &pHeight[i]);
}
S32 pSquareSize = block->getSquareSize();
sTangent.x = pSquareSize;
sTangent.y = pHeight[3] - pHeight[0];
sTangent.z = 0;
tTangent.x = 0;
tTangent.y = pHeight[1] - pHeight[0];
tTangent.z = pSquareSize;
sTangent.normalize();
tTangent.normalize();
// The above is needed for both emboss and dot3 bump mapping
// techniques. However, the below 2 lines are emboss-specific.
// So, dot3 bump mapping would not be too difficult because
// I have already computed most of the necessary info.
bumpTextureOffset.x = mDot(sTangent, sunVector) * mCurrentBlock->mBumpOffset;
bumpTextureOffset.y = mDot(tTangent, sunVector) * mCurrentBlock->mBumpOffset;
PROFILE_END();
}
// CW - end bump map stuff
mSquareSize = block->getSquareSize();
// mNewGenTextureCount = 0;
// compute pixelError
if(mScreenError >= 0.001)
mPixelError = 1 / dglProjectRadius(mScreenError, 1);
else
mPixelError = 0.000001;
buildClippingPlanes(state->mFlipCull);
buildLightArray();
F32 worldToScreenScale = dglProjectRadius(1,1);
F32 zeroDetailDistance = (mSquareSize * worldToScreenScale) / (1 << 6) - (mSquareSize >> 1);
F32 zeroBumpDistance = (mSquareSize * worldToScreenScale) / (1 << mCurrentBlock->mZeroBumpScale) - (mSquareSize >> 1);
F32 blockSize = mSquareSize * TerrainBlock::BlockSquareWidth;
S32 xStart;
S32 xEnd;
S32 yStart;
S32 yEnd;
if(mCurrentBlock->mTile)
{
xStart = (S32)mFloor( (mCamPos.x - mFarDistance) / blockSize );
xEnd = (S32)mCeil ( (mCamPos.x + mFarDistance) / blockSize );
yStart = (S32)mFloor( (mCamPos.y - mFarDistance) / blockSize );
yEnd = (S32)mCeil ( (mCamPos.y + mFarDistance) / blockSize );
}
else
{
xStart = 0;
xEnd = 1;
yStart = 0;
yEnd = 1;
}
S32 xExt = (S32)(xEnd - xStart);
S32 yExt = (S32)(yEnd - yStart);
PROFILE_END();
PROFILE_START(TerrainRenderRecurse);
F32 height = fixedToFloat(block->getHeight(0,0));
EdgeParent **bottomEdges = (EdgeParent **) FrameAllocator::alloc(sizeof(ChunkScanEdge *) * xExt);
TerrainRender::allocRenderEdges(xExt, bottomEdges, false);
ChunkCornerPoint *prevCorner = TerrainRender::allocInitialPoint(Point3F(xStart * blockSize, yStart * blockSize, height));
mTerrainOffset.set(xStart * TerrainBlock::BlockSquareWidth, yStart * TerrainBlock::BlockSquareWidth);
for(S32 x = 0; x < xExt; x++)
{
bottomEdges[x]->p1 = prevCorner;
prevCorner = TerrainRender::allocInitialPoint(Point3F((xStart + x ) * blockSize, yStart * blockSize, height));
bottomEdges[x]->p2 = prevCorner;
}
for(S32 y = 0; y < yExt; y++)
{
// allocate the left edge:
EdgeParent *left;
TerrainRender::allocRenderEdges(1, &left, false);
left->p1 = TerrainRender::allocInitialPoint(Point3F(xStart * blockSize, (yStart + y + 1) * blockSize, height));
left->p2 = bottomEdges[0]->p1;
for(S32 x = 0; x < xExt; x++)
{
EdgeParent *right;
TerrainRender::allocRenderEdges(1, &right, false);
right->p1 = TerrainRender::allocInitialPoint(Point3F((xStart + x + 1) * blockSize, (yStart + y + 1) * blockSize, height));
right->p2 = bottomEdges[x]->p2;
EdgeParent *top;
TerrainRender::allocRenderEdges(1, &top, false);
top->p1 = left->p1;
top->p2 = right->p1;
mBlockOffset.set(x << TerrainBlock::BlockShift,
y << TerrainBlock::BlockShift);
mBlockPos.set((xStart + x) * blockSize,
(yStart + y) * blockSize);
TerrainRender::processCurrentBlock(state, top, right, bottomEdges[x], left);
left = right;
bottomEdges[x] = top;
}
}
U32 slop = 0;
AllocatedTexture *fwalk = mTextureFreeListHead.next;
while(fwalk != &mTextureFreeListTail && slop < mTextureSlopSize)
{
fwalk = fwalk->next;
slop++;
}
while(fwalk != &mTextureFreeListTail)
{
AllocatedTexture *next = fwalk->next;
fwalk->unlink();
S32 x = (fwalk->x & TerrainBlock::BlockMask) >> fwalk->level;
S32 y = (fwalk->y & TerrainBlock::BlockMask) >> fwalk->level;
mTextureGridPtr[fwalk->level - 2][x + (y << (8 - fwalk->level))] = NULL;
freeTerrTexture(fwalk);
fwalk = next;
}
PROFILE_END();
PROFILE_START(TerrainRenderEmit);
bool lockArrays = dglDoesSupportCompiledVertexArray() && dglDoesSupportARBMultitexture();
bool multitextureFog = dglDoesSupportARBMultitexture(); // dc 6-1-01 - this flag is BAD. The non mtex path doesn't currently work. !!!!!!TBD
bool vertexBuffer = dglDoesSupportVertexBuffer() && (block->mVertexBuffer != -1);
glFrontFace(GL_CW);
glEnable(GL_CULL_FACE);
glEnableClientState(GL_VERTEX_ARRAY);
if(!vertexBuffer)
mXFVertices = (EdgePoint *) FrameAllocator::alloc(sizeof(EdgePoint) * VertexBufferSize);
//CW - D3D goes crazy if we stick our bump colors in the EdgePoint structure, so make a new one
ColorI *bumpColors = (ColorI*)FrameAllocator::alloc(sizeof(ColorI) * VertexBufferSize);
glVertexPointer(3, GL_FLOAT, sizeof(EdgePoint), mXFVertices);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ZERO);
// see if we should setup hazing on the second TMU
// if not, we'll have to 2-pass the terrain...
// and that ain't gonna be fast no matter how ya slice it.
if(multitextureFog)
{
// Hazing
glCl
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -