terrain.cpp
来自「这是整套横扫千军3D版游戏的源码」· C++ 代码 · 共 1,186 行 · 第 1/3 页
CPP
1,186 行
// find the nabours, and make sure at least them or their parents are drawn
TQuad *parent = q->parent;
QuadMap *qm = qmaps[parent->depth];
if (parent->qmPos.x>0) CheckNabourLod (parent, -1, 0);
if (parent->qmPos.y>0) CheckNabourLod (parent, 0, -1);
if (parent->qmPos.x<qm->w-1) CheckNabourLod (parent, 1, 0);
if (parent->qmPos.y<qm->w-1) CheckNabourLod (parent, 0, 1);
}
}
// Handle visibility with the frustum, and select LOD based on distance to camera and LOD setting
void Terrain::QuadVisLod (TQuad *q)
{
if (q->InFrustum (&frustum)) {
// Node is visible, now determine if this LOD is suitable, or that a higher LOD should be used.
float lod = config.detailMod * q->CalcLod (curRC->cam->pos);
if (q->depth < quadTreeDepth-config.maxLodLevel || (lod > 1.0f && !q->isLeaf())) {
q->drawState=TQuad::Parent;
for (int a=0;a<4;a++)
QuadVisLod (q->childs[a]);
} else q->drawState=TQuad::Queued;
updatequads.push_back (q);
// update max lod value
if (q->maxLodValue < lod)
q->maxLodValue = lod;
} else {
q->drawState=TQuad::Culled;
culled.push_back (q);
}
}
static inline bool QuadSortFunc (const QuadRenderInfo& q1, const QuadRenderInfo& q2)
{
return q1.quad->textureSetup->sortkey < q2.quad->textureSetup->sortkey;
}
// update quad node drawing list
void Terrain::Update ()
{
nodeUpdateCount = 0;
renderDataManager->ClearStat();
// clear LOD values of previously used renderquads
for (int a=0;a<contexts.size();a++)
{
RenderContext *rc = contexts[a];
for (int n = 0; n < rc->quads.size();n++) {
TQuad *q = rc->quads [n].quad;
q->maxLodValue = 0.0f;
if (q->renderData)
q->renderData->used = true;
}
}
for (int ctx=0;ctx<contexts.size();ctx++)
{
RenderContext *rc = curRC = contexts[ctx];
// Update the frustum based on the camera, to cull away TQuad nodes
//Camera *camera = rc->cam;
// frustum.CalcCameraPlanes (&camera->pos, &camera->right, &camera->up, &camera->front, camera->fov, camera->aspect);
//assert (camera->pos.x == 0.0f || frustum.IsPointVisible (camera->pos + camera->front * 20)==Frustum::Inside);
// determine the new set of quads to draw
QuadVisLod (quadtree);
// go through nabours to make sure there is a maximum of one LOD difference between nabours
UpdateLodFix (quadtree);
if (debugQuad)
ForceQueue (debugQuad);
// update lod state and copy the rendering list to the render context...
rc->quads.clear();
for (int a=0;a<updatequads.size();a++)
{
if (updatequads[a]->drawState == TQuad::Queued)
{
TQuad *q = updatequads[a];
// calculate lod state
QuadMap *qm = qmaps[q->depth];
int ls=0;
if (q->qmPos.x>0 && qm->At (q->qmPos.x-1,q->qmPos.y)->drawState == TQuad::NoDraw) ls |= left_bit;
if (q->qmPos.y>0 && qm->At (q->qmPos.x,q->qmPos.y-1)->drawState == TQuad::NoDraw) ls |= up_bit;
if (q->qmPos.x<qm->w-1 && qm->At (q->qmPos.x+1,q->qmPos.y)->drawState == TQuad::NoDraw) ls |= right_bit;
if (q->qmPos.y<qm->w-1 && qm->At (q->qmPos.x,q->qmPos.y+1)->drawState == TQuad::NoDraw) ls |= down_bit;
rc->quads.push_back (QuadRenderInfo());
rc->quads.back().quad = q;
rc->quads.back().lodState = ls;
if (q->renderData) q->renderData->used = true;
}
}
// sort rendering quads based on sorting key
sort (rc->quads.begin(), rc->quads.end(), QuadSortFunc);
// the active set of quads is determined, so their draw-states can be reset for the next context
for (int a=0;a<culled.size();a++)
culled[a]->drawState = TQuad::NoDraw;
culled.clear();
// clear the list of queued quads
for (int a=0;a<updatequads.size();a++)
updatequads[a]->drawState = TQuad::NoDraw;
updatequads.clear ();
}
renderDataManager->FreeUnused ();
for (int ctx=0;ctx<contexts.size();ctx++)
{
RenderContext *rc = curRC = contexts[ctx];
// allocate required vertex buffers
for (int a=0;a<rc->quads.size();a++)
{
TQuad *q = rc->quads[a].quad;
if (!q->renderData) {
renderDataManager->InitializeNode (q);
if (config.terrainNormalMaps && rc->needsNormalMap)
renderDataManager->InitializeNodeNormalMap(q, config.normalMapLevel);
nodeUpdateCount ++;
}
}
}
if (logUpdates) {
if (nodeUpdateCount) d_trace ("NodeUpdates: %d, NormalDataAllocs:%d, RenderDataAllocs:%d\n",
nodeUpdateCount, renderDataManager->normalDataAllocates, renderDataManager->renderDataAllocates);
}
curRC = 0;
}
void Terrain::DrawSimple ()
{
glEnable(GL_CULL_FACE);
for (int a=0;a<activeRC->quads.size();a++)
{
QuadRenderInfo *q = &activeRC->quads[a];
q->quad->Draw (indexTable, true, q->lodState);
}
}
void Terrain::DrawOverlayTexture (uint tex)
{
glEnable (GL_TEXTURE_2D);
glBindTexture (GL_TEXTURE_2D, tex);
glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE, GL_MODULATE);
SetTexGen (1.0f / (heightmap->w * SquareSize));
DrawSimple ();
glDisable (GL_TEXTURE_GEN_S);
glDisable (GL_TEXTURE_GEN_T);
glDisable (GL_TEXTURE_2D);
}
void DrawNormals (TQuad *q, Heightmap *hm)
{
glBegin (GL_LINES);
for (int y=q->hmPos.y;y<q->hmPos.y+QUAD_W;y++)
for (int x=q->hmPos.x;x<q->hmPos.x+QUAD_W;x++)
{
Vector3 origin (x * hm->squareSize, hm->HeightAt (x,y), y * hm->squareSize);
Vector3 tangent, binormal;
CalculateTangents(hm, x,y, tangent, binormal);
Vector3 normal = binormal.cross(tangent);
normal.Normalize();
binormal.Normalize ();
tangent.Normalize ();
glColor3f (1,1,0);
glVertex3fv(&origin[0]);
glVertex3fv(&(origin + normal * 7)[0]);
glColor3f (1,0,0);
glVertex3fv(&origin[0]);
glVertex3fv(&(origin + binormal * 7)[0]);
glColor3f (0,0,1);
glVertex3fv(&origin[0]);
glVertex3fv(&(origin + tangent * 7)[0]);
}
glEnd();
glColor3f (1,1,1);
}
void Terrain::Draw ()
{
if (!fill)
glPolygonMode (GL_FRONT_AND_BACK,GL_LINE);
else {
glPolygonMode (GL_FRONT_AND_BACK,GL_FILL);
const float diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };
glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, diffuse);
}
glEnable(GL_CULL_FACE);
glColor3f(1.0f,1.0f,1.0f);
if (config.cacheTextures)
{
// draw all terrain nodes using their cached textures
glEnable (GL_TEXTURE_GEN_S);
glEnable (GL_TEXTURE_GEN_T);
glTexGeni (GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
glTexGeni (GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
glEnable (GL_TEXTURE_2D);
glDisable (GL_LIGHTING);
for (int a=0;a<activeRC->quads.size();a++)
{
TQuad *q = activeRC->quads[a].quad;
// set quad texture
glBindTexture (GL_TEXTURE_2D, q->cacheTexture);
// set texture gen
float ht = (q->end.x-q->start.x) / ( 2 * config.cacheTextureSize );
float v[4] = {0.0f, 0.0f, 0.0f, 0.0f};
v[0] = 1.0f / (q->end.x - q->start.x + ht * 2);
v[3] = -v[0] * (q->start.x - ht);
glTexGenfv (GL_S, GL_OBJECT_PLANE, v);
v[0] = 0.0f;
v[2] = 1.0f / (q->end.z - q->start.z + ht * 2);
v[3] = -v[2] * (q->start.z - ht);
glTexGenfv (GL_T, GL_OBJECT_PLANE, v);
// draw
q->Draw (indexTable, false, activeRC->quads[a].lodState);
}
glDisable (GL_TEXTURE_2D);
glDisable (GL_TEXTURE_GEN_S);
glDisable (GL_TEXTURE_GEN_T);
}
else // no texture caching, so use the texturing system directly
{
int numPasses=texturing->NumPasses();
glEnable(GL_DEPTH_TEST);
if (fill) texturing->BeginTexturing();
if (!fill) numPasses=1;
for (int pass=0;pass<numPasses;pass++)
{
bool skipNodes=false;
if (fill)
texturing->BeginPass(pass);
for (int a=0;a<activeRC->quads.size();a++)
{
TQuad *q = activeRC->quads[a].quad;
// Setup node texturing
if (fill)
skipNodes = !texturing->SetupNode (q, pass);
assert (q->renderData);
if (!skipNodes) {
// Draw the node
q->Draw (indexTable, false, activeRC->quads[a].lodState);
}
}
if (fill) texturing->EndPass();
}
glDisable (GL_BLEND);
glDepthMask (GL_TRUE);
if (fill)
texturing->EndTexturing ();
}
if (debugQuad)
DrawNormals (debugQuad, lowdetailhm->GetLevel (debugQuad->depth));
glPolygonMode (GL_FRONT_AND_BACK,GL_FILL);
}
void Terrain::CalcRenderStats (RenderStats& stats, RenderContext *ctx)
{
if (!ctx)
ctx = activeRC;
stats.cacheTextureSize = 0;
stats.renderDataSize = 0;
stats.tris = 0;
for (int a=0;a<ctx->quads.size();a++) {
TQuad *q = ctx->quads[a].quad;
if (q->cacheTexture)
stats.cacheTextureSize += config.cacheTextureSize * config.cacheTextureSize * 3;
stats.renderDataSize += q->renderData->GetDataSize();
stats.tris += MAX_INDICES/3;
}
stats.passes = texturing->NumPasses ();
}
#ifndef TERRAINRENDERERLIB_EXPORTS
void Terrain::DebugPrint (IFontRenderer *fr)
{
const float s=16.0f;
if (debugQuad) {
fr->printf (0, 30, s, "Selected quad: (%d,%d) on depth %d. Lod=%3.3f",
debugQuad->qmPos.x, debugQuad->qmPos.y, debugQuad->depth, config.detailMod * debugQuad->CalcLod (activeRC->cam->pos));
}
RenderStats stats;
CalcRenderStats(stats);
fr->printf (0, 46, s, "Rendered nodes: %d, tris: %d, VBufSize: %d(kb), TotalRenderData(kb): %d, DetailMod: %g, CacheTextureMemory: %d",
activeRC->quads.size(), stats.tris, VertexBuffer::TotalSize()/1024, stats.renderDataSize/1024, config.detailMod, stats.cacheTextureSize);
fr->printf (0, 60, s, "NodeUpdateCount: %d, RenderDataAlloc: %d, #RenderData: %d",
nodeUpdateCount, renderDataManager->normalDataAllocates, renderDataManager->QuadRenderDataCount ());
texturing->DebugPrint(fr);
}
#endif
TQuad* FindQuad (TQuad *q, const Vector3& cpos)
{
if (cpos.x >= q->start.x && cpos.z >= q->start.z &&
cpos.x < q->end.x && cpos.z < q->end.z)
{
if (q->isLeaf ()) return q;
for (int a=0;a<4;a++) {
TQuad *r = FindQuad (q->childs[a], cpos);
if (r) return r;
}
}
return 0;
}
void Terrain::RenderNodeFlat (int x,int y,int depth)
{
RenderNode (qmaps[depth]->At (x,y));
}
void Terrain::RenderNode (TQuad *q)
{
// setup projection matrix, so the quad is exactly mapped onto the viewport
glMatrixMode (GL_PROJECTION);
glPushMatrix ();
glLoadIdentity ();
glOrtho (q->start.x, q->end.x, q->start.z, q->end.z, -10000.0f, 100000.0f);
glColor3f(1.f,1.f,1.f);
if (!q->renderData)
renderDataManager->InitializeNode (q);
texturing->BeginTexturing();
// render to the framebuffer
for (int p=0;p<q->textureSetup->renderSetup [0]->passes.size();p++)
{
texturing->BeginPass(p);
if (texturing->SetupNode (q, p))
{
glBegin(GL_QUADS);
glVertex3f (q->start.x, 0.0f, q->start.z);
glVertex3f (q->end.x, 0.0f, q->start.z);
glVertex3f (q->end.x, 0.0f, q->end.z);
glVertex3f (q->start.x, 0.0f, q->end.z);
glEnd();
}
texturing->EndPass();
}
texturing->EndTexturing();
glMatrixMode (GL_PROJECTION);
glPopMatrix ();
}
void Terrain::CacheTextures ()
{
if (!config.cacheTextures)
return;
glPushAttrib (GL_VIEWPORT_BIT | GL_DEPTH_BUFFER_BIT);
glViewport (0, 0, config.cacheTextureSize, config.cacheTextureSize);
glMatrixMode (GL_MODELVIEW);
glPushMatrix ();
glLoadIdentity ();
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?