void CAdvTreeDrawer::DrawShadowPass() { const float treeDistance = oldTreeDistance; const int activeFarTex = (camera->forward.z < 0.0f)? treeGen->farTex[0] : treeGen->farTex[1]; const bool drawDetailed = (treeDistance >= 4.0f); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, activeFarTex); glEnable(GL_TEXTURE_2D); glEnable(GL_ALPHA_TEST); glDisable(GL_CULL_FACE); glPolygonOffset(1, 1); glEnable(GL_POLYGON_OFFSET_FILL); CAdvTreeSquareDrawer_SP drawer; const int cx = drawer.cx = (int)(camera->pos.x / (SQUARE_SIZE * TREE_SQUARE_SIZE)); const int cy = drawer.cy = (int)(camera->pos.z / (SQUARE_SIZE * TREE_SQUARE_SIZE)); drawer.drawDetailed = drawDetailed; drawer.td = this; drawer.treeDistance = treeDistance * SQUARE_SIZE * TREE_SQUARE_SIZE; Shader::IProgramObject* po = NULL; GML_STDMUTEX_LOCK(tree); // DrawShadowPass // draw with extraSize=1 readmap->GridVisibility(camera, TREE_SQUARE_SIZE, drawer.treeDistance * 2.0f, &drawer, 1); if (drawDetailed) { const int xstart = std::max( 0, cx - 2); const int xend = std::min(gs->mapx / TREE_SQUARE_SIZE - 1, cx + 2); const int ystart = std::max( 0, cy - 2); const int yend = std::min(gs->mapy / TREE_SQUARE_SIZE - 1, cy + 2); glBindTexture(GL_TEXTURE_2D, treeGen->barkTex); glEnable(GL_TEXTURE_2D); po = shadowHandler->GetShadowGenProg(CShadowHandler::SHADOWGEN_PROGRAM_TREE_NEAR); po->Enable(); if (globalRendering->haveGLSL) { po->SetUniform3fv(1, &camera->right[0]); po->SetUniform3fv(2, &camera->up[0]); } else { po->SetUniformTarget(GL_VERTEX_PROGRAM_ARB); po->SetUniform4f(13, camera->right.x, camera->right.y, camera->right.z, 0.0f); po->SetUniform4f(9, camera->up.x, camera->up.y, camera->up.z, 0.0f); po->SetUniform4f(11, 1.0f, 1.0f, 1.0f, 0.85f ); po->SetUniform4f(12, 0.0f, 0.0f, 0.0f, 0.20f * (1.0f / MAX_TREE_HEIGHT)); // w = alpha/height modifier } glAlphaFunc(GL_GREATER, 0.5f); glEnable(GL_ALPHA_TEST); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); CVertexArray* va = GetVertexArray(); va->Initialize(); static FadeTree fadeTrees[3000]; FadeTree* pFT = fadeTrees; for (TreeSquareStruct* pTSS = trees + (ystart * treesX); pTSS <= trees + (yend * treesX); pTSS += treesX) { for (TreeSquareStruct* tss = pTSS + xstart; tss <= pTSS + xend; ++tss) { tss->lastSeen = gs->frameNum; va->EnlargeArrays(12 * tss->trees.size(), 0, VA_SIZE_T); //!alloc room for all tree vertexes for (std::map<int, TreeStruct>::iterator ti = tss->trees.begin(); ti != tss->trees.end(); ++ti) { const TreeStruct* ts = &ti->second; const float3 pos(ts->pos); if (!camera->InView(pos + float3(0, MAX_TREE_HEIGHT / 2, 0), MAX_TREE_HEIGHT / 2 + 150)) { continue; } const float camDist = (pos - camera->pos).SqLength(); int type = ts->type; float dy = 0.0f; unsigned int dispList; if (type < 8) { dy = 0.5f; dispList = treeGen->pineDL + type; } else { type -= 8; dy = 0; dispList = treeGen->leafDL + type; } if (camDist < SQUARE_SIZE * SQUARE_SIZE * 110 * 110) { po->SetUniform3f((globalRendering->haveGLSL? 3: 10), pos.x, pos.y, pos.z); glCallList(dispList); } else if (camDist < SQUARE_SIZE * SQUARE_SIZE * 125 * 125) { const float relDist = (pos.distance(camera->pos) - SQUARE_SIZE * 110) / (SQUARE_SIZE * 15); glAlphaFunc(GL_GREATER, 0.8f + relDist * 0.2f); po->SetUniform3f((globalRendering->haveGLSL? 3: 10), pos.x, pos.y, pos.z); glCallList(dispList); glAlphaFunc(GL_GREATER, 0.5f); pFT->pos = pos; pFT->deltaY = dy; pFT->type = type; pFT->relDist = relDist; ++pFT; } else { CAdvTreeDrawer::DrawTreeVertex(va, pos, type * 0.125f, dy, false); } } } } po->SetUniform3f((globalRendering->haveGLSL? 3: 10), 0.0f, 0.0f, 0.0f); for (std::list<FallingTree>::iterator fti = fallingTrees.begin(); fti != fallingTrees.end(); ++fti) { const float3 pos = fti->pos - UpVector * (fti->fallPos * 20); if (camera->InView(pos + float3(0, MAX_TREE_HEIGHT / 2, 0), MAX_TREE_HEIGHT / 2)) { const float ang = fti->fallPos * PI; const float3 yvec(fti->dir.x * sin(ang), cos(ang), fti->dir.z * sin(ang)); const float3 zvec((yvec.cross(float3(1.0f, 0.0f, 0.0f))).ANormalize()); const float3 xvec(zvec.cross(yvec)); CMatrix44f transMatrix(pos, xvec, yvec, zvec); glPushMatrix(); glMultMatrixf(&transMatrix[0]); int type = fti->type; int dispList; if (type < 8) { dispList = treeGen->pineDL + type; } else { type -= 8; dispList = treeGen->leafDL + type; } glCallList(dispList); glPopMatrix(); } } po->Disable(); po = shadowHandler->GetShadowGenProg(CShadowHandler::SHADOWGEN_PROGRAM_TREE_FAR); po->Enable(); glBindTexture(GL_TEXTURE_2D, activeFarTex); va->DrawArrayT(GL_QUADS); for (FadeTree* pFTree = fadeTrees; pFTree < pFT; ++pFTree) { // faded close trees va = GetVertexArray(); va->Initialize(); va->CheckInitSize(12 * VA_SIZE_T); CAdvTreeDrawer::DrawTreeVertex(va, pFTree->pos, pFTree->type * 0.125f, pFTree->deltaY, false); glAlphaFunc(GL_GREATER, 1.0f - (pFTree->relDist * 0.5f)); va->DrawArrayT(GL_QUADS); } po->Disable(); } glEnable(GL_CULL_FACE); glDisable(GL_POLYGON_OFFSET_FILL); glDisable(GL_TEXTURE_2D); glDisable(GL_ALPHA_TEST); }
void CAdvTreeDrawer::Draw(float treeDistance, bool drawReflection) { const int activeFarTex = (camera->forward.z < 0.0f)? treeGen->farTex[0]: treeGen->farTex[1]; const bool drawDetailed = ((treeDistance >= 4.0f) || drawReflection); CBaseGroundDrawer* gd = readmap->GetGroundDrawer(); Shader::IProgramObject* treeShader = NULL; const CMapInfo::light_t& light = mapInfo->light; glEnable(GL_ALPHA_TEST); glEnable(GL_TEXTURE_2D); ISky::SetupFog(); if (shadowHandler->shadowsLoaded && !gd->DrawExtraTex()) { glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, activeFarTex); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, shadowHandler->shadowTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL); glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_ALPHA); treeShader = treeShaders[TREE_PROGRAM_DIST_SHADOW]; treeShader->Enable(); if (globalRendering->haveGLSL) { treeShader->SetUniformMatrix4fv(7, false, &shadowHandler->shadowMatrix.m[0]); treeShader->SetUniform4fv(8, &(shadowHandler->GetShadowParams().x)); } else { treeShader->SetUniformTarget(GL_FRAGMENT_PROGRAM_ARB); treeShader->SetUniform4f(10, light.groundAmbientColor.x, light.groundAmbientColor.y, light.groundAmbientColor.z, 1.0f); treeShader->SetUniform4f(11, 0.0f, 0.0f, 0.0f, 1.0f - (sky->GetLight()->GetGroundShadowDensity() * 0.5f)); treeShader->SetUniformTarget(GL_VERTEX_PROGRAM_ARB); glMatrixMode(GL_MATRIX0_ARB); glLoadMatrixf(shadowHandler->shadowMatrix.m); glMatrixMode(GL_MODELVIEW); } } else { glBindTexture(GL_TEXTURE_2D, activeFarTex); } const int cx = int(camera->pos.x / (SQUARE_SIZE * TREE_SQUARE_SIZE)); const int cy = int(camera->pos.z / (SQUARE_SIZE * TREE_SQUARE_SIZE)); CAdvTreeSquareDrawer drawer(this, cx, cy, treeDistance * SQUARE_SIZE * TREE_SQUARE_SIZE, drawDetailed); GML_STDMUTEX_LOCK(tree); // Draw oldTreeDistance = treeDistance; // draw far-trees using map-dependent grid-visibility readmap->GridVisibility(camera, TREE_SQUARE_SIZE, drawer.treeDistance * 2.0f, &drawer); if (drawDetailed) { // draw near-trees const int xstart = std::max( 0, cx - 2); const int xend = std::min(gs->mapx / TREE_SQUARE_SIZE - 1, cx + 2); const int ystart = std::max( 0, cy - 2); const int yend = std::min(gs->mapy / TREE_SQUARE_SIZE - 1, cy + 2); if (shadowHandler->shadowsLoaded && !gd->DrawExtraTex()) { treeShader->Disable(); treeShader = treeShaders[TREE_PROGRAM_NEAR_SHADOW]; treeShader->Enable(); if (globalRendering->haveGLSL) { treeShader->SetUniformMatrix4fv(7, false, &shadowHandler->shadowMatrix.m[0]); treeShader->SetUniform4fv(8, &(shadowHandler->GetShadowParams().x)); } glActiveTexture(GL_TEXTURE1); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, treeGen->barkTex); glActiveTexture(GL_TEXTURE0); } else { glBindTexture(GL_TEXTURE_2D, treeGen->barkTex); treeShader = treeShaders[TREE_PROGRAM_NEAR_BASIC]; treeShader->Enable(); if (!globalRendering->haveGLSL) { const int mx = gs->pwr2mapx * SQUARE_SIZE; const int my = gs->pwr2mapy * SQUARE_SIZE; treeShader->SetUniformTarget(GL_VERTEX_PROGRAM_ARB); treeShader->SetUniform4f(15, 1.0f / mx, 1.0f / my, 1.0f / mx, 1.0f); } } if (globalRendering->haveGLSL) { treeShader->SetUniform3fv(0, &camera->right[0]); treeShader->SetUniform3fv(1, &camera->up[0]); treeShader->SetUniform2f(5, 0.20f * (1.0f / MAX_TREE_HEIGHT), 0.85f); } else { treeShader->SetUniformTarget(GL_VERTEX_PROGRAM_ARB); treeShader->SetUniform3f(13, camera->right.x, camera->right.y, camera->right.z); treeShader->SetUniform3f( 9, camera->up.x, camera->up.y, camera->up.z ); treeShader->SetUniform4f(11, light.groundSunColor.x, light.groundSunColor.y, light.groundSunColor.z, 0.85f); treeShader->SetUniform4f(14, light.groundAmbientColor.x, light.groundAmbientColor.y, light.groundAmbientColor.z, 0.85f); treeShader->SetUniform4f(12, 0.0f, 0.0f, 0.0f, 0.20f * (1.0f / MAX_TREE_HEIGHT)); // w = alpha/height modifier } glAlphaFunc(GL_GREATER, 0.5f); glDisable(GL_BLEND); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); CVertexArray* va = GetVertexArray(); va->Initialize(); static FadeTree fadeTrees[3000]; FadeTree* pFT = fadeTrees; for (TreeSquareStruct* pTSS = trees + (ystart * treesX); pTSS <= trees + (yend * treesX); pTSS += treesX) { for (TreeSquareStruct* tss = pTSS + xstart; tss <= (pTSS + xend); ++tss) { tss->lastSeen = gs->frameNum; va->EnlargeArrays(12 * tss->trees.size(), 0, VA_SIZE_T); //!alloc room for all tree vertexes for (std::map<int, TreeStruct>::iterator ti = tss->trees.begin(); ti != tss->trees.end(); ++ti) { const TreeStruct* ts = &ti->second; const float3 pos(ts->pos); if (!camera->InView(pos + float3(0.0f, MAX_TREE_HEIGHT / 2.0f, 0.0f), MAX_TREE_HEIGHT / 2.0f)) { continue; } const float camDist = (pos - camera->pos).SqLength(); int type = ts->type; float dy = 0.0f; unsigned int dispList; if (type < 8) { dy = 0.5f; dispList = treeGen->pineDL + type; } else { type -= 8; dy = 0.0f; dispList = treeGen->leafDL + type; } if (camDist < (SQUARE_SIZE * SQUARE_SIZE * 110 * 110)) { // draw detailed near-distance tree (same as mid-distance trees without alpha) treeShader->SetUniform3f(((globalRendering->haveGLSL)? 2: 10), pos.x, pos.y, pos.z); glCallList(dispList); } else if (camDist < (SQUARE_SIZE * SQUARE_SIZE * 125 * 125)) { // draw mid-distance tree const float relDist = (pos.distance(camera->pos) - SQUARE_SIZE * 110) / (SQUARE_SIZE * 15); treeShader->SetUniform3f(((globalRendering->haveGLSL)? 2: 10), pos.x, pos.y, pos.z); glAlphaFunc(GL_GREATER, 0.8f + relDist * 0.2f); glCallList(dispList); glAlphaFunc(GL_GREATER, 0.5f); // save for second pass pFT->pos = pos; pFT->deltaY = dy; pFT->type = type; pFT->relDist = relDist; ++pFT; } else { // draw far-distance tree CAdvTreeDrawer::DrawTreeVertex(va, pos, type * 0.125f, dy, false); } } } } // reset the world-offset treeShader->SetUniform3f(((globalRendering->haveGLSL)? 2: 10), 0.0f, 0.0f, 0.0f); // draw trees that have been marked as falling for (std::list<FallingTree>::iterator fti = fallingTrees.begin(); fti != fallingTrees.end(); ++fti) { const float3 pos = fti->pos - UpVector * (fti->fallPos * 20); if (camera->InView(pos + float3(0.0f, MAX_TREE_HEIGHT / 2, 0.0f), MAX_TREE_HEIGHT / 2.0f)) { const float ang = fti->fallPos * PI; const float3 yvec(fti->dir.x * sin(ang), cos(ang), fti->dir.z * sin(ang)); const float3 zvec((yvec.cross(float3(-1.0f, 0.0f, 0.0f))).ANormalize()); const float3 xvec(yvec.cross(zvec)); CMatrix44f transMatrix(pos, xvec, yvec, zvec); glPushMatrix(); glMultMatrixf(&transMatrix[0]); int type = fti->type; int dispList = 0; if (type < 8) { dispList = treeGen->pineDL + type; } else { type -= 8; dispList = treeGen->leafDL + type; } glCallList(dispList); glPopMatrix(); } } if (shadowHandler->shadowsLoaded && !gd->DrawExtraTex()) { treeShader->Disable(); treeShader = treeShaders[TREE_PROGRAM_DIST_SHADOW]; treeShader->Enable(); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, activeFarTex); glActiveTexture(GL_TEXTURE0); } else { treeShader->Disable(); glBindTexture(GL_TEXTURE_2D, activeFarTex); } // draw far-distance trees va->DrawArrayT(GL_QUADS); // draw faded mid-distance trees for (FadeTree* pFTree = fadeTrees; pFTree < pFT; ++pFTree) { va = GetVertexArray(); va->Initialize(); va->CheckInitSize(12 * VA_SIZE_T); CAdvTreeDrawer::DrawTreeVertex(va, pFTree->pos, pFTree->type * 0.125f, pFTree->deltaY, false); glAlphaFunc(GL_GREATER, 1.0f - (pFTree->relDist * 0.5f)); va->DrawArrayT(GL_QUADS); } } if (shadowHandler->shadowsLoaded && !gd->DrawExtraTex()) { treeShader->Disable(); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, 0); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, 0); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE); glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE); } else { glBindTexture(GL_TEXTURE_2D, 0); } glDisable(GL_TEXTURE_2D); glDisable(GL_FOG); glDisable(GL_ALPHA_TEST); // clean out squares from memory that are no longer visible const int startClean = lastListClean * 20 % (nTrees); const int endClean = gs->frameNum * 20 % (nTrees); lastListClean = gs->frameNum; if (startClean > endClean) { for (TreeSquareStruct* pTSS = trees + startClean; pTSS < (trees + nTrees); ++pTSS) { if ((pTSS->lastSeen < gs->frameNum - 50) && pTSS->dispList) { glDeleteLists(pTSS->dispList, 1); pTSS->dispList = 0; } if ((pTSS->lastSeenFar < (gs->frameNum - 50)) && pTSS->farDispList) { glDeleteLists(pTSS->farDispList, 1); pTSS->farDispList = 0; } } for (TreeSquareStruct* pTSS = trees; pTSS < (trees + endClean); ++pTSS) { if ((pTSS->lastSeen < (gs->frameNum - 50)) && pTSS->dispList) { glDeleteLists(pTSS->dispList, 1); pTSS->dispList = 0; } if ((pTSS->lastSeenFar < (gs->frameNum - 50)) && pTSS->farDispList) { glDeleteLists(pTSS->farDispList, 1); pTSS->farDispList = 0; } } } else { for (TreeSquareStruct* pTSS = trees + startClean; pTSS < (trees + endClean); ++pTSS) { if ((pTSS->lastSeen < (gs->frameNum - 50)) && pTSS->dispList) { glDeleteLists(pTSS->dispList, 1); pTSS->dispList = 0; } if ((pTSS->lastSeenFar < (gs->frameNum - 50)) && pTSS->farDispList) { glDeleteLists(pTSS->farDispList, 1); pTSS->farDispList = 0; } } } }