void CGrassDrawer::CreateGrassDispList(int listNum) { CVertexArray* va = GetVertexArray(); va->Initialize(); grng.Seed(15); for (int a = 0; a < strawPerTurf; ++a) { // draw a single blade const float lngRnd = grng.NextFloat(); const float length = mapInfo->grass.bladeHeight * (1.0f + lngRnd); const float maxAng = mapInfo->grass.bladeAngle * std::max(grng.NextFloat(), 1.0f - smoothstep(0.0f, 1.0f, lngRnd)); float3 sideVect; sideVect.x = grng.NextFloat() - 0.5f; sideVect.z = grng.NextFloat() - 0.5f; sideVect.ANormalize(); float3 bendVect = sideVect.cross(UpVector); // direction to bend into sideVect *= mapInfo->grass.bladeWidth * (-0.15f * lngRnd + 1.0f); const float3 basePos = grng.NextVector2D() * (turfSize - (bendVect * std::sin(maxAng) * length).Length2D()); // select one of the 16 color shadings const float xtexCoord = grng.NextInt(16) / 16.0f; const int numSections = 2 + int(maxAng * 1.2f + length * 0.2f); float3 normalBend = -bendVect; // start btm va->AddVertexTN(basePos + sideVect - float3(0.0f, 3.0f, 0.0f), xtexCoord , 0.f, normalBend); va->AddVertexTN(basePos - sideVect - float3(0.0f, 3.0f, 0.0f), xtexCoord + (1.0f / 16), 0.f, normalBend); for (float h = 0.0f; h < 1.0f; h += (1.0f / numSections)) { const float ang = maxAng * h; const float3 n = (normalBend * std::cos(ang) + UpVector * std::sin(ang)).ANormalize(); const float3 edgePos = (UpVector * std::cos(ang) + bendVect * std::sin(ang)) * length * h; const float3 edgePosL = edgePos - sideVect * (1.0f - h); const float3 edgePosR = edgePos + sideVect * (1.0f - h); va->AddVertexTN(basePos + edgePosR, xtexCoord + (1.0f / 32) * h , h, (n + sideVect * 0.04f).ANormalize()); va->AddVertexTN(basePos + edgePosL, xtexCoord - (1.0f / 32) * h + (1.0f / 16), h, (n - sideVect * 0.04f).ANormalize()); } // end top tip (single triangle) const float3 edgePos = (UpVector * std::cos(maxAng) + bendVect * std::sin(maxAng)) * length; const float3 n = (normalBend * std::cos(maxAng) + UpVector * std::sin(maxAng)).ANormalize(); va->AddVertexTN(basePos + edgePos, xtexCoord + (1.0f / 32), 1.0f, n); // next blade va->EndStrip(); } glNewList(listNum, GL_COMPILE); va->DrawArrayTN(GL_TRIANGLE_STRIP); glEndList(); }
void CLegacyMeshDrawer::DoDrawGroundShadowLOD(int nlod) { CVertexArray* ma = GetVertexArray(); ma->Initialize(); bool inStrip = false; int x,y; int lod = 1 << nlod; float cx2 = camera->GetPos().x / SQUARE_SIZE; float cy2 = camera->GetPos().z / SQUARE_SIZE; float oldcamxpart = 0.0f; float oldcamypart = 0.0f; int hlod = lod >> 1; int dlod = lod << 1; int cx = (int)cx2; int cy = (int)cy2; if (lod > 1) { int cxo = (cx / hlod) * hlod; int cyo = (cy / hlod) * hlod; float cx2o = (cxo / lod) * lod; float cy2o = (cyo / lod) * lod; oldcamxpart = (cx2 - cx2o) / lod; oldcamypart = (cy2 - cy2o) / lod; } cx = (cx / lod) * lod; cy = (cy / lod) * lod; const int ysquaremod = (cy % dlod) / lod; const int xsquaremod = (cx % dlod) / lod; const float camxpart = (cx2 - (cx / dlod) * dlod) / dlod; const float camypart = (cy2 - (cy / dlod) * dlod) / dlod; const int minty = 0, maxty = mapDims.mapy; const int mintx = 0, maxtx = mapDims.mapx; const int minly = cy + (-viewRadius + 3 - ysquaremod) * lod, maxly = cy + ( viewRadius - 1 - ysquaremod) * lod; const int minlx = cx + (-viewRadius + 3 - xsquaremod) * lod, maxlx = cx + ( viewRadius - 1 - xsquaremod) * lod; const int xstart = std::max(minlx, mintx), xend = std::min(maxlx, maxtx); const int ystart = std::max(minly, minty), yend = std::min(maxly, maxty); const int lhdx = lod * smfReadMap->heightMapSizeX; const int hhdx = hlod * smfReadMap->heightMapSizeX; const int dhdx = dlod * smfReadMap->heightMapSizeX; const float mcxp = 1.0f - camxpart, mcyp = 1.0f - camypart; const float hcxp = 0.5f * camxpart, hcyp = 0.5f * camypart; const float hmcxp = 0.5f * mcxp, hmcyp = 0.5f * mcyp; const float mocxp = 1.0f - oldcamxpart, mocyp = 1.0f - oldcamypart; const float hocxp = 0.5f * oldcamxpart, hocyp = 0.5f * oldcamypart; const float hmocxp = 0.5f * mocxp, hmocyp = 0.5f * mocyp; const int vrhlod = viewRadius * hlod; for (y = ystart; y < yend; y += lod) { int xs = xstart; int xe = xend; if (xe < xs) continue; int ylod = y + lod; int yhlod = y + hlod; int ydx = y * smfReadMap->heightMapSizeX; int nloop = (xe - xs) / lod + 1; ma->EnlargeArrays(52 * nloop); for (x = xs; x < xe; x += lod) { int xlod = x + lod; int xhlod = x + hlod; if ((lod == 1) || (x > cx + vrhlod) || (x < cx - vrhlod) || (y > cy + vrhlod) || (y < cy - vrhlod)) { if (!inStrip) { DrawVertexAQ(ma, x, y ); DrawVertexAQ(ma, x, ylod); inStrip = true; } DrawVertexAQ(ma, xlod, y ); DrawVertexAQ(ma, xlod, ylod); } else { //! inre begr?sning mot f?eg?nde lod int yhdx=ydx+x; int ylhdx=yhdx+lhdx; int yhhdx=yhdx+hhdx; if ( x>= cx + vrhlod) { const float h1 = (GetVisibleVertexHeight(yhdx ) + GetVisibleVertexHeight(ylhdx )) * hmocxp + GetVisibleVertexHeight(yhhdx ) * oldcamxpart; const float h2 = (GetVisibleVertexHeight(yhdx ) + GetVisibleVertexHeight(yhdx+lod )) * hmocxp + GetVisibleVertexHeight(yhdx+hlod ) * oldcamxpart; const float h3 = (GetVisibleVertexHeight(ylhdx) + GetVisibleVertexHeight(yhdx+lod )) * hmocxp + GetVisibleVertexHeight(yhhdx+hlod) * oldcamxpart; const float h4 = (GetVisibleVertexHeight(ylhdx) + GetVisibleVertexHeight(ylhdx+lod)) * hmocxp + GetVisibleVertexHeight(ylhdx+hlod) * oldcamxpart; if(inStrip){ ma->EndStrip(); inStrip=false; } DrawVertexAQ(ma, x,y); DrawVertexAQ(ma, x,yhlod,h1); DrawVertexAQ(ma, xhlod,y,h2); DrawVertexAQ(ma, xhlod,yhlod,h3); ma->EndStrip(); DrawVertexAQ(ma, x,yhlod,h1); DrawVertexAQ(ma, x,ylod); DrawVertexAQ(ma, xhlod,yhlod,h3); DrawVertexAQ(ma, xhlod,ylod,h4); ma->EndStrip(); DrawVertexAQ(ma, xhlod,ylod,h4); DrawVertexAQ(ma, xlod,ylod); DrawVertexAQ(ma, xhlod,yhlod,h3); DrawVertexAQ(ma, xlod,y); DrawVertexAQ(ma, xhlod,y,h2); ma->EndStrip(); } if (x <= cx - vrhlod) { const float h1 = (GetVisibleVertexHeight(yhdx+lod) + GetVisibleVertexHeight(ylhdx+lod)) * hocxp + GetVisibleVertexHeight(yhhdx+lod ) * mocxp; const float h2 = (GetVisibleVertexHeight(yhdx ) + GetVisibleVertexHeight(yhdx+lod )) * hocxp + GetVisibleVertexHeight(yhdx+hlod ) * mocxp; const float h3 = (GetVisibleVertexHeight(ylhdx ) + GetVisibleVertexHeight(yhdx+lod )) * hocxp + GetVisibleVertexHeight(yhhdx+hlod) * mocxp; const float h4 = (GetVisibleVertexHeight(ylhdx ) + GetVisibleVertexHeight(ylhdx+lod)) * hocxp + GetVisibleVertexHeight(ylhdx+hlod) * mocxp; if(inStrip){ ma->EndStrip(); inStrip=false; } DrawVertexAQ(ma, xlod,yhlod,h1); DrawVertexAQ(ma, xlod,y); DrawVertexAQ(ma, xhlod,yhlod,h3); DrawVertexAQ(ma, xhlod,y,h2); ma->EndStrip(); DrawVertexAQ(ma, xlod,ylod); DrawVertexAQ(ma, xlod,yhlod,h1); DrawVertexAQ(ma, xhlod,ylod,h4); DrawVertexAQ(ma, xhlod,yhlod,h3); ma->EndStrip(); DrawVertexAQ(ma, xhlod,y,h2); DrawVertexAQ(ma, x,y); DrawVertexAQ(ma, xhlod,yhlod,h3); DrawVertexAQ(ma, x,ylod); DrawVertexAQ(ma, xhlod,ylod,h4); ma->EndStrip(); } if (y >= cy + vrhlod) { const float h1 = (GetVisibleVertexHeight(yhdx ) + GetVisibleVertexHeight(yhdx+lod)) * hmocyp + GetVisibleVertexHeight(yhdx+hlod ) * oldcamypart; const float h2 = (GetVisibleVertexHeight(yhdx ) + GetVisibleVertexHeight(ylhdx )) * hmocyp + GetVisibleVertexHeight(yhhdx ) * oldcamypart; const float h3 = (GetVisibleVertexHeight(ylhdx ) + GetVisibleVertexHeight(yhdx+lod)) * hmocyp + GetVisibleVertexHeight(yhhdx+hlod) * oldcamypart; const float h4 = (GetVisibleVertexHeight(ylhdx+lod) + GetVisibleVertexHeight(yhdx+lod)) * hmocyp + GetVisibleVertexHeight(yhhdx+lod ) * oldcamypart; if(inStrip){ ma->EndStrip(); inStrip=false; } DrawVertexAQ(ma, x,y); DrawVertexAQ(ma, x,yhlod,h2); DrawVertexAQ(ma, xhlod,y,h1); DrawVertexAQ(ma, xhlod,yhlod,h3); DrawVertexAQ(ma, xlod,y); DrawVertexAQ(ma, xlod,yhlod,h4); ma->EndStrip(); DrawVertexAQ(ma, x,yhlod,h2); DrawVertexAQ(ma, x,ylod); DrawVertexAQ(ma, xhlod,yhlod,h3); DrawVertexAQ(ma, xlod,ylod); DrawVertexAQ(ma, xlod,yhlod,h4); ma->EndStrip(); } if (y <= cy - vrhlod) { const float h1 = (GetVisibleVertexHeight(ylhdx ) + GetVisibleVertexHeight(ylhdx+lod)) * hocyp + GetVisibleVertexHeight(ylhdx+hlod) * mocyp; const float h2 = (GetVisibleVertexHeight(yhdx ) + GetVisibleVertexHeight(ylhdx )) * hocyp + GetVisibleVertexHeight(yhhdx ) * mocyp; const float h3 = (GetVisibleVertexHeight(ylhdx ) + GetVisibleVertexHeight(yhdx+lod )) * hocyp + GetVisibleVertexHeight(yhhdx+hlod) * mocyp; const float h4 = (GetVisibleVertexHeight(ylhdx+lod) + GetVisibleVertexHeight(yhdx+lod )) * hocyp + GetVisibleVertexHeight(yhhdx+lod ) * mocyp; if (inStrip) { ma->EndStrip(); inStrip = false; } DrawVertexAQ(ma, x,yhlod,h2); DrawVertexAQ(ma, x,ylod); DrawVertexAQ(ma, xhlod,yhlod,h3); DrawVertexAQ(ma, xhlod,ylod,h1); DrawVertexAQ(ma, xlod,yhlod,h4); DrawVertexAQ(ma, xlod,ylod); ma->EndStrip(); DrawVertexAQ(ma, xlod,yhlod,h4); DrawVertexAQ(ma, xlod,y); DrawVertexAQ(ma, xhlod,yhlod,h3); DrawVertexAQ(ma, x,y); DrawVertexAQ(ma, x,yhlod,h2); ma->EndStrip(); } } } if (inStrip) { ma->EndStrip(); inStrip=false; } } int yst = std::max(ystart - lod, minty); int yed = std::min(yend + lod, maxty); int nloop = (yed - yst) / lod + 1; ma->EnlargeArrays(8 * nloop); //!rita yttre begr?snings yta mot n?ta lod if (maxlx < maxtx && maxlx >= mintx) { x = maxlx; const int xlod = x + lod; for (y = yst; y < yed; y += lod) { DrawVertexAQ(ma, x, y ); DrawVertexAQ(ma, x, y + lod); const int yhdx = y * smfReadMap->heightMapSizeX + x; if (y % dlod) { const float h = (GetVisibleVertexHeight(yhdx - lhdx + lod) + GetVisibleVertexHeight(yhdx + lhdx + lod)) * hmcxp + GetVisibleVertexHeight(yhdx+lod) * camxpart; DrawVertexAQ(ma, xlod, y, h); DrawVertexAQ(ma, xlod, y + lod); } else { const float h = (GetVisibleVertexHeight(yhdx+lod) + GetVisibleVertexHeight(yhdx+dhdx+lod)) * hmcxp + GetVisibleVertexHeight(yhdx+lhdx+lod) * camxpart; DrawVertexAQ(ma, xlod,y); DrawVertexAQ(ma, xlod,y+lod,h); } ma->EndStrip(); } } if (minlx > mintx && minlx < maxtx) { x = minlx - lod; const int xlod = x + lod; for(y = yst; y < yed; y += lod) { int yhdx = y * smfReadMap->heightMapSizeX + x; if(y%dlod){ const float h = (GetVisibleVertexHeight(yhdx-lhdx) + GetVisibleVertexHeight(yhdx+lhdx)) * hcxp + GetVisibleVertexHeight(yhdx) * mcxp; DrawVertexAQ(ma, x,y,h); DrawVertexAQ(ma, x,y+lod); } else { const float h = (GetVisibleVertexHeight(yhdx) + GetVisibleVertexHeight(yhdx+dhdx)) * hcxp + GetVisibleVertexHeight(yhdx+lhdx) * mcxp; DrawVertexAQ(ma, x,y); DrawVertexAQ(ma, x,y+lod,h); } DrawVertexAQ(ma, xlod,y); DrawVertexAQ(ma, xlod,y+lod); ma->EndStrip(); } } if (maxly < maxty && maxly > minty) { y = maxly; const int xs = std::max(xstart -lod, mintx); const int xe = std::min(xend + lod, maxtx); if (xs < xe) { x = xs; const int ylod = y + lod; const int ydx = y * smfReadMap->heightMapSizeX; const int nloop = (xe - xs) / lod + 2; //! two extra for if statment ma->EnlargeArrays(2 * nloop); if (x % dlod) { const int ylhdx = ydx + x + lhdx; const float h = (GetVisibleVertexHeight(ylhdx-lod) + GetVisibleVertexHeight(ylhdx+lod)) * hmcyp + GetVisibleVertexHeight(ylhdx) * camypart; DrawVertexAQ(ma, x, y); DrawVertexAQ(ma, x, ylod, h); } else { DrawVertexAQ(ma, x, y); DrawVertexAQ(ma, x, ylod); } for (x = xs; x < xe; x += lod) { if (x % dlod) { DrawVertexAQ(ma, x + lod, y); DrawVertexAQ(ma, x + lod, ylod); } else { DrawVertexAQ(ma, x+lod,y); const int ylhdx = ydx + x + lhdx; const float h = (GetVisibleVertexHeight(ylhdx+dlod) + GetVisibleVertexHeight(ylhdx)) * hmcyp + GetVisibleVertexHeight(ylhdx+lod) * camypart; DrawVertexAQ(ma, x+lod,ylod,h); } } ma->EndStrip(); } } if (minly > minty && minly < maxty) { y = minly - lod; const int xs = std::max(xstart - lod, mintx); const int xe = std::min(xend + lod, maxtx); if (xs < xe) { x = xs; const int ylod = y + lod; const int ydx = y * smfReadMap->heightMapSizeX; const int nloop = (xe - xs) / lod + 2; //! two extra for if statment ma->EnlargeArrays(2 * nloop); if (x % dlod) { const int yhdx = ydx + x; const float h = (GetVisibleVertexHeight(yhdx-lod) + GetVisibleVertexHeight(yhdx + lod)) * hcyp + GetVisibleVertexHeight(yhdx) * mcyp; DrawVertexAQ(ma, x, y, h); DrawVertexAQ(ma, x, ylod); } else { DrawVertexAQ(ma, x, y); DrawVertexAQ(ma, x, ylod); } for (x = xs; x < xe; x += lod) { if (x % dlod) { DrawVertexAQ(ma, x + lod, y); DrawVertexAQ(ma, x + lod, ylod); } else { const int yhdx = ydx + x; const float h = (GetVisibleVertexHeight(yhdx+dlod) + GetVisibleVertexHeight(yhdx)) * hcyp + GetVisibleVertexHeight(yhdx+lod) * mcyp; DrawVertexAQ(ma, x + lod, y, h); DrawVertexAQ(ma, x + lod, ylod); } } ma->EndStrip(); } } DrawGroundVertexArrayQ(ma); }
void CLegacyMeshDrawer::DoDrawGroundRow(const CCamera* cam, int bty) { if (!BigTexSquareRowVisible(cam, bty)) { //! skip this entire row of squares if we can't see it return; } CVertexArray* ma = GetVertexArray(); bool inStrip = false; float x0, x1; int x,y; int sx = 0; int ex = smfReadMap->numBigTexX; //! only process the necessary big squares in the x direction const int bigSquareSizeY = bty * smfReadMap->bigSquareSize; const std::vector<CCamera::FrustumLine> negSides = cam->GetNegFrustumSides(); const std::vector<CCamera::FrustumLine> posSides = cam->GetPosFrustumSides(); std::vector<CCamera::FrustumLine>::const_iterator fli; for (fli = negSides.begin(); fli != negSides.end(); ++fli) { x0 = fli->base + fli->dir * bigSquareSizeY; x1 = x0 + fli->dir * smfReadMap->bigSquareSize; if (x0 > x1) x0 = x1; x0 /= smfReadMap->bigSquareSize; if (x0 > sx) sx = (int) x0; } for (fli = posSides.begin(); fli != posSides.end(); ++fli) { x0 = fli->base + fli->dir * bigSquareSizeY + smfReadMap->bigSquareSize; x1 = x0 + fli->dir * smfReadMap->bigSquareSize; if (x0 < x1) x0 = x1; x0 /= smfReadMap->bigSquareSize; if (x0 < ex) ex = (int) x0; } if (sx > ex) return; const float cx2 = cam2->GetPos().x / SQUARE_SIZE; const float cy2 = cam2->GetPos().z / SQUARE_SIZE; for (int btx = sx; btx < ex; ++btx) { ma->Initialize(); for (int lod = 1; lod < neededLod; lod <<= 1) { float oldcamxpart = 0.0f; float oldcamypart = 0.0f; const int hlod = lod >> 1; const int dlod = lod << 1; int cx = cx2; int cy = cy2; if (lod > 1) { int cxo = (cx / hlod) * hlod; int cyo = (cy / hlod) * hlod; float cx2o = (cxo / lod) * lod; float cy2o = (cyo / lod) * lod; oldcamxpart = (cx2 - cx2o) / lod; oldcamypart = (cy2 - cy2o) / lod; } cx = (cx / lod) * lod; cy = (cy / lod) * lod; const int ysquaremod = (cy % dlod) / lod; const int xsquaremod = (cx % dlod) / lod; const float camxpart = (cx2 - ((cx / dlod) * dlod)) / dlod; const float camypart = (cy2 - ((cy / dlod) * dlod)) / dlod; const float mcxp = 1.0f - camxpart, mcyp = 1.0f - camypart; const float hcxp = 0.5f * camxpart, hcyp = 0.5f * camypart; const float hmcxp = 0.5f * mcxp, hmcyp = 0.5f * mcyp; const float mocxp = 1.0f - oldcamxpart, mocyp = 1.0f - oldcamypart; const float hocxp = 0.5f * oldcamxpart, hocyp = 0.5f * oldcamypart; const float hmocxp = 0.5f * mocxp, hmocyp = 0.5f * mocyp; const int minty = bty * smfReadMap->bigSquareSize, maxty = minty + smfReadMap->bigSquareSize; const int mintx = btx * smfReadMap->bigSquareSize, maxtx = mintx + smfReadMap->bigSquareSize; const int minly = cy + (-viewRadius + 3 - ysquaremod) * lod; const int maxly = cy + ( viewRadius - 1 - ysquaremod) * lod; const int minlx = cx + (-viewRadius + 3 - xsquaremod) * lod; const int maxlx = cx + ( viewRadius - 1 - xsquaremod) * lod; const int xstart = std::max(minlx, mintx), xend = std::min(maxlx, maxtx); const int ystart = std::max(minly, minty), yend = std::min(maxly, maxty); const int vrhlod = viewRadius * hlod; for (y = ystart; y < yend; y += lod) { int xs = xstart; int xe = xend; FindRange(cam2, /*inout*/ xs, /*inout*/ xe, y, lod); // If FindRange modifies (xs, xe) to a (less then) empty range, // continue to the next row. // If we'd continue, nloop (below) would become negative and we'd // allocate a vertex array with negative size. (mantis #1415) if (xe < xs) continue; int ylod = y + lod; int yhlod = y + hlod; int nloop = (xe - xs) / lod + 1; ma->EnlargeArrays(52 * nloop); int yhdx = y * smfReadMap->heightMapSizeX; int ylhdx = yhdx + lod * smfReadMap->heightMapSizeX; int yhhdx = yhdx + hlod * smfReadMap->heightMapSizeX; for (x = xs; x < xe; x += lod) { int xlod = x + lod; int xhlod = x + hlod; //! info: all triangle quads start in the top left corner if ((lod == 1) || (x > cx + vrhlod) || (x < cx - vrhlod) || (y > cy + vrhlod) || (y < cy - vrhlod)) { //! normal terrain (all vertices in one LOD) if (!inStrip) { DrawVertexAQ(ma, x, y); DrawVertexAQ(ma, x, ylod); inStrip = true; } DrawVertexAQ(ma, xlod, y); DrawVertexAQ(ma, xlod, ylod); } else { //! border between 2 different LODs if ((x >= cx + vrhlod)) { //! lower LOD to the right int idx1 = CLAMP(yhdx + x), idx1LOD = CLAMP(idx1 + lod), idx1HLOD = CLAMP(idx1 + hlod); int idx2 = CLAMP(ylhdx + x), idx2LOD = CLAMP(idx2 + lod), idx2HLOD = CLAMP(idx2 + hlod); int idx3 = CLAMP(yhhdx + x), idx3HLOD = CLAMP(idx3 + hlod); float h1 = (GetVisibleVertexHeight(idx1) + GetVisibleVertexHeight(idx2)) * hmocxp + GetVisibleVertexHeight(idx3) * oldcamxpart; float h2 = (GetVisibleVertexHeight(idx1) + GetVisibleVertexHeight(idx1LOD)) * hmocxp + GetVisibleVertexHeight(idx1HLOD) * oldcamxpart; float h3 = (GetVisibleVertexHeight(idx2) + GetVisibleVertexHeight(idx1LOD)) * hmocxp + GetVisibleVertexHeight(idx3HLOD) * oldcamxpart; float h4 = (GetVisibleVertexHeight(idx2) + GetVisibleVertexHeight(idx2LOD)) * hmocxp + GetVisibleVertexHeight(idx2HLOD) * oldcamxpart; if (inStrip) { ma->EndStrip(); inStrip = false; } DrawVertexAQ(ma, x, y); DrawVertexAQ(ma, x, yhlod, h1); DrawVertexAQ(ma, xhlod, y, h2); DrawVertexAQ(ma, xhlod, yhlod, h3); ma->EndStrip(); DrawVertexAQ(ma, x, yhlod, h1); DrawVertexAQ(ma, x, ylod); DrawVertexAQ(ma, xhlod, yhlod, h3); DrawVertexAQ(ma, xhlod, ylod, h4); ma->EndStrip(); DrawVertexAQ(ma, xhlod, ylod, h4); DrawVertexAQ(ma, xlod, ylod); DrawVertexAQ(ma, xhlod, yhlod, h3); DrawVertexAQ(ma, xlod, y); DrawVertexAQ(ma, xhlod, y, h2); ma->EndStrip(); } else if ((x <= cx - vrhlod)) { //! lower LOD to the left int idx1 = CLAMP(yhdx + x), idx1LOD = CLAMP(idx1 + lod), idx1HLOD = CLAMP(idx1 + hlod); int idx2 = CLAMP(ylhdx + x), idx2LOD = CLAMP(idx2 + lod), idx2HLOD = CLAMP(idx2 + hlod); int idx3 = CLAMP(yhhdx + x), idx3LOD = CLAMP(idx3 + lod), idx3HLOD = CLAMP(idx3 + hlod); float h1 = (GetVisibleVertexHeight(idx1LOD) + GetVisibleVertexHeight(idx2LOD)) * hocxp + GetVisibleVertexHeight(idx3LOD ) * mocxp; float h2 = (GetVisibleVertexHeight(idx1 ) + GetVisibleVertexHeight(idx1LOD)) * hocxp + GetVisibleVertexHeight(idx1HLOD) * mocxp; float h3 = (GetVisibleVertexHeight(idx2 ) + GetVisibleVertexHeight(idx1LOD)) * hocxp + GetVisibleVertexHeight(idx3HLOD) * mocxp; float h4 = (GetVisibleVertexHeight(idx2 ) + GetVisibleVertexHeight(idx2LOD)) * hocxp + GetVisibleVertexHeight(idx2HLOD) * mocxp; if (inStrip) { ma->EndStrip(); inStrip = false; } DrawVertexAQ(ma, xlod, yhlod, h1); DrawVertexAQ(ma, xlod, y); DrawVertexAQ(ma, xhlod, yhlod, h3); DrawVertexAQ(ma, xhlod, y, h2); ma->EndStrip(); DrawVertexAQ(ma, xlod, ylod); DrawVertexAQ(ma, xlod, yhlod, h1); DrawVertexAQ(ma, xhlod, ylod, h4); DrawVertexAQ(ma, xhlod, yhlod, h3); ma->EndStrip(); DrawVertexAQ(ma, xhlod, y, h2); DrawVertexAQ(ma, x, y); DrawVertexAQ(ma, xhlod, yhlod, h3); DrawVertexAQ(ma, x, ylod); DrawVertexAQ(ma, xhlod, ylod, h4); ma->EndStrip(); } if ((y >= cy + vrhlod)) { //! lower LOD above int idx1 = yhdx + x, idx1LOD = CLAMP(idx1 + lod), idx1HLOD = CLAMP(idx1 + hlod); int idx2 = ylhdx + x, idx2LOD = CLAMP(idx2 + lod); int idx3 = yhhdx + x, idx3LOD = CLAMP(idx3 + lod), idx3HLOD = CLAMP(idx3 + hlod); float h1 = (GetVisibleVertexHeight(idx1 ) + GetVisibleVertexHeight(idx1LOD)) * hmocyp + GetVisibleVertexHeight(idx1HLOD) * oldcamypart; float h2 = (GetVisibleVertexHeight(idx1 ) + GetVisibleVertexHeight(idx2 )) * hmocyp + GetVisibleVertexHeight(idx3 ) * oldcamypart; float h3 = (GetVisibleVertexHeight(idx2 ) + GetVisibleVertexHeight(idx1LOD)) * hmocyp + GetVisibleVertexHeight(idx3HLOD) * oldcamypart; float h4 = (GetVisibleVertexHeight(idx2LOD) + GetVisibleVertexHeight(idx1LOD)) * hmocyp + GetVisibleVertexHeight(idx3LOD ) * oldcamypart; if (inStrip) { ma->EndStrip(); inStrip = false; } DrawVertexAQ(ma, x, y); DrawVertexAQ(ma, x, yhlod, h2); DrawVertexAQ(ma, xhlod, y, h1); DrawVertexAQ(ma, xhlod, yhlod, h3); DrawVertexAQ(ma, xlod, y); DrawVertexAQ(ma, xlod, yhlod, h4); ma->EndStrip(); DrawVertexAQ(ma, x, yhlod, h2); DrawVertexAQ(ma, x, ylod); DrawVertexAQ(ma, xhlod, yhlod, h3); DrawVertexAQ(ma, xlod, ylod); DrawVertexAQ(ma, xlod, yhlod, h4); ma->EndStrip(); } else if ((y <= cy - vrhlod)) { //! lower LOD beneath int idx1 = CLAMP(yhdx + x), idx1LOD = CLAMP(idx1 + lod); int idx2 = CLAMP(ylhdx + x), idx2LOD = CLAMP(idx2 + lod), idx2HLOD = CLAMP(idx2 + hlod); int idx3 = CLAMP(yhhdx + x), idx3LOD = CLAMP(idx3 + lod), idx3HLOD = CLAMP(idx3 + hlod); float h1 = (GetVisibleVertexHeight(idx2 ) + GetVisibleVertexHeight(idx2LOD)) * hocyp + GetVisibleVertexHeight(idx2HLOD) * mocyp; float h2 = (GetVisibleVertexHeight(idx1 ) + GetVisibleVertexHeight(idx2 )) * hocyp + GetVisibleVertexHeight(idx3 ) * mocyp; float h3 = (GetVisibleVertexHeight(idx2 ) + GetVisibleVertexHeight(idx1LOD)) * hocyp + GetVisibleVertexHeight(idx3HLOD) * mocyp; float h4 = (GetVisibleVertexHeight(idx2LOD) + GetVisibleVertexHeight(idx1LOD)) * hocyp + GetVisibleVertexHeight(idx3LOD ) * mocyp; if (inStrip) { ma->EndStrip(); inStrip = false; } DrawVertexAQ(ma, x, yhlod, h2); DrawVertexAQ(ma, x, ylod); DrawVertexAQ(ma, xhlod, yhlod, h3); DrawVertexAQ(ma, xhlod, ylod, h1); DrawVertexAQ(ma, xlod, yhlod, h4); DrawVertexAQ(ma, xlod, ylod); ma->EndStrip(); DrawVertexAQ(ma, xlod, yhlod, h4); DrawVertexAQ(ma, xlod, y); DrawVertexAQ(ma, xhlod, yhlod, h3); DrawVertexAQ(ma, x, y); DrawVertexAQ(ma, x, yhlod, h2); ma->EndStrip(); } } } if (inStrip) { ma->EndStrip(); inStrip = false; } } //for (y = ystart; y < yend; y += lod) const int yst = std::max(ystart - lod, minty); const int yed = std::min(yend + lod, maxty); int nloop = (yed - yst) / lod + 1; if (nloop > 0) ma->EnlargeArrays(8 * nloop); //! rita yttre begr?snings yta mot n?ta lod if (maxlx < maxtx && maxlx >= mintx) { x = maxlx; int xlod = x + lod; for (y = yst; y < yed; y += lod) { DrawVertexAQ(ma, x, y); DrawVertexAQ(ma, x, y + lod); if (y % dlod) { const int idx1 = CLAMP((y ) * smfReadMap->heightMapSizeX + x), idx1LOD = CLAMP(idx1 + lod); const int idx2 = CLAMP((y + lod) * smfReadMap->heightMapSizeX + x), idx2LOD = CLAMP(idx2 + lod); const int idx3 = CLAMP((y - lod) * smfReadMap->heightMapSizeX + x), idx3LOD = CLAMP(idx3 + lod); const float h = (GetVisibleVertexHeight(idx3LOD) + GetVisibleVertexHeight(idx2LOD)) * hmcxp + GetVisibleVertexHeight(idx1LOD) * camxpart; DrawVertexAQ(ma, xlod, y, h); DrawVertexAQ(ma, xlod, y + lod); } else { const int idx1 = CLAMP((y ) * smfReadMap->heightMapSizeX + x), idx1LOD = CLAMP(idx1 + lod); const int idx2 = CLAMP((y + lod) * smfReadMap->heightMapSizeX + x), idx2LOD = CLAMP(idx2 + lod); const int idx3 = CLAMP((y + dlod) * smfReadMap->heightMapSizeX + x), idx3LOD = CLAMP(idx3 + lod); const float h = (GetVisibleVertexHeight(idx1LOD) + GetVisibleVertexHeight(idx3LOD)) * hmcxp + GetVisibleVertexHeight(idx2LOD) * camxpart; DrawVertexAQ(ma, xlod, y); DrawVertexAQ(ma, xlod, y + lod, h); } ma->EndStrip(); } } if (minlx > mintx && minlx < maxtx) { x = minlx - lod; int xlod = x + lod; for (y = yst; y < yed; y += lod) { if (y % dlod) { int idx1 = CLAMP((y ) * smfReadMap->heightMapSizeX + x); int idx2 = CLAMP((y + lod) * smfReadMap->heightMapSizeX + x); int idx3 = CLAMP((y - lod) * smfReadMap->heightMapSizeX + x); float h = (GetVisibleVertexHeight(idx3) + GetVisibleVertexHeight(idx2)) * hcxp + GetVisibleVertexHeight(idx1) * mcxp; DrawVertexAQ(ma, x, y, h); DrawVertexAQ(ma, x, y + lod); } else { int idx1 = CLAMP((y ) * smfReadMap->heightMapSizeX + x); int idx2 = CLAMP((y + lod) * smfReadMap->heightMapSizeX + x); int idx3 = CLAMP((y + dlod) * smfReadMap->heightMapSizeX + x); float h = (GetVisibleVertexHeight(idx1) + GetVisibleVertexHeight(idx3)) * hcxp + GetVisibleVertexHeight(idx2) * mcxp; DrawVertexAQ(ma, x, y); DrawVertexAQ(ma, x, y + lod, h); } DrawVertexAQ(ma, xlod, y); DrawVertexAQ(ma, xlod, y + lod); ma->EndStrip(); } } if (maxly < maxty && maxly > minty) { y = maxly; int xs = std::max(xstart - lod, mintx); int xe = std::min(xend + lod, maxtx); FindRange(cam2, xs, xe, y, lod); if (xs < xe) { x = xs; int ylod = y + lod; int nloop = (xe - xs) / lod + 2; //! one extra for if statment int ylhdx = (y + lod) * smfReadMap->heightMapSizeX; ma->EnlargeArrays(2 * nloop); if (x % dlod) { int idx2 = CLAMP(ylhdx + x), idx2PLOD = CLAMP(idx2 + lod), idx2MLOD = CLAMP(idx2 - lod); float h = (GetVisibleVertexHeight(idx2MLOD) + GetVisibleVertexHeight(idx2PLOD)) * hmcyp + GetVisibleVertexHeight(idx2) * camypart; DrawVertexAQ(ma, x, y); DrawVertexAQ(ma, x, ylod, h); } else { DrawVertexAQ(ma, x, y); DrawVertexAQ(ma, x, ylod); } for (x = xs; x < xe; x += lod) { if (x % dlod) { DrawVertexAQ(ma, x + lod, y); DrawVertexAQ(ma, x + lod, ylod); } else { int idx2 = CLAMP(ylhdx + x), idx2PLOD = CLAMP(idx2 + lod), idx2PLOD2 = CLAMP(idx2 + dlod); float h = (GetVisibleVertexHeight(idx2PLOD2) + GetVisibleVertexHeight(idx2)) * hmcyp + GetVisibleVertexHeight(idx2PLOD) * camypart; DrawVertexAQ(ma, x + lod, y); DrawVertexAQ(ma, x + lod, ylod, h); } } ma->EndStrip(); } } if (minly > minty && minly < maxty) { y = minly - lod; int xs = std::max(xstart - lod, mintx); int xe = std::min(xend + lod, maxtx); FindRange(cam2, xs, xe, y, lod); if (xs < xe) { x = xs; int ylod = y + lod; int yhdx = y * smfReadMap->heightMapSizeX; int nloop = (xe - xs) / lod + 2; //! one extra for if statment ma->EnlargeArrays(2 * nloop); if (x % dlod) { int idx1 = CLAMP(yhdx + x), idx1PLOD = CLAMP(idx1 + lod), idx1MLOD = CLAMP(idx1 - lod); float h = (GetVisibleVertexHeight(idx1MLOD) + GetVisibleVertexHeight(idx1PLOD)) * hcyp + GetVisibleVertexHeight(idx1) * mcyp; DrawVertexAQ(ma, x, y, h); DrawVertexAQ(ma, x, ylod); } else { DrawVertexAQ(ma, x, y); DrawVertexAQ(ma, x, ylod); } for (x = xs; x < xe; x+= lod) { if (x % dlod) { DrawVertexAQ(ma, x + lod, y); DrawVertexAQ(ma, x + lod, ylod); } else { int idx1 = CLAMP(yhdx + x), idx1PLOD = CLAMP(idx1 + lod), idx1PLOD2 = CLAMP(idx1 + dlod); float h = (GetVisibleVertexHeight(idx1PLOD2) + GetVisibleVertexHeight(idx1)) * hcyp + GetVisibleVertexHeight(idx1PLOD) * mcyp; DrawVertexAQ(ma, x + lod, y, h); DrawVertexAQ(ma, x + lod, ylod); } } ma->EndStrip(); } } } //for (int lod = 1; lod < neededLod; lod <<= 1) smfGroundDrawer->SetupBigSquare(btx, bty); DrawGroundVertexArrayQ(ma); } }
CBumpWater::CBumpWater() : CEventClient("[CBumpWater]", 271923, false) { eventHandler.AddClient(this); // LOAD USER CONFIGS reflTexSize = next_power_of_2(configHandler->GetInt("BumpWaterTexSizeReflection")); reflection = configHandler->GetInt("BumpWaterReflection"); refraction = configHandler->GetInt("BumpWaterRefraction"); anisotropy = configHandler->GetFloat("BumpWaterAnisotropy"); depthCopy = configHandler->GetBool("BumpWaterUseDepthTexture"); depthBits = configHandler->GetInt("BumpWaterDepthBits"); if ((depthBits == 24) && !globalRendering->support24bitDepthBuffers) depthBits = 16; blurRefl = configHandler->GetBool("BumpWaterBlurReflection"); shoreWaves = (configHandler->GetBool("BumpWaterShoreWaves")) && mapInfo->water.shoreWaves; endlessOcean = (configHandler->GetBool("BumpWaterEndlessOcean")) && mapInfo->water.hasWaterPlane && ((readmap->initMinHeight <= 0.0f) || (mapInfo->water.forceRendering)); dynWaves = (configHandler->GetBool("BumpWaterDynamicWaves")) && (mapInfo->water.numTiles>1); useUniforms = (configHandler->GetBool("BumpWaterUseUniforms")); refractTexture = 0; reflectTexture = 0; // CHECK HARDWARE if (!globalRendering->haveGLSL) { throw content_error("["LOG_SECTION_BUMP_WATER"] your hardware/driver setup does not support GLSL"); } shoreWaves = shoreWaves && (GLEW_EXT_framebuffer_object); dynWaves = dynWaves && (GLEW_EXT_framebuffer_object && GLEW_ARB_imaging); // LOAD TEXTURES foamTexture = LoadTexture(mapInfo->water.foamTexture); normalTexture = LoadTexture(mapInfo->water.normalTexture , anisotropy , &normalTextureX, &normalTextureY); //! caustic textures const vector<string>& causticNames = mapInfo->water.causticTextures; if (causticNames.size() <= 0) { throw content_error("["LOG_SECTION_BUMP_WATER"] no caustic textures"); } for (int i = 0; i < (int)causticNames.size(); ++i) { caustTextures.push_back(LoadTexture(causticNames[i])); } // CHECK SHOREWAVES TEXTURE SIZE if (shoreWaves) { GLint maxw, maxh; glTexImage2D(GL_PROXY_TEXTURE_2D, 0, GL_RGBA16F_ARB, 4096, 4096, 0, GL_RGBA, GL_FLOAT, NULL); glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &maxw); glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &maxh); if (gs->mapx>maxw || gs->mapy>maxh) { shoreWaves = false; LOG_L(L_WARNING, "Can not display shorewaves (map too large)!"); } } // SHOREWAVES if (shoreWaves) { waveRandTexture = LoadTexture( "bitmaps/shorewaverand.png" ); glGenTextures(1, &coastTexture); glBindTexture(GL_TEXTURE_2D, coastTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); //glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, gs->mapx, gs->mapy, 0, GL_RGBA, GL_FLOAT, NULL); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5, gs->mapx, gs->mapy, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); //glGenerateMipmapEXT(GL_TEXTURE_2D); { blurShader = shaderHandler->CreateProgramObject("[BumpWater]", "CoastBlurShader", false); blurShader->AttachShaderObject(shaderHandler->CreateShaderObject("GLSL/bumpWaterCoastBlurFS.glsl", "", GL_FRAGMENT_SHADER)); blurShader->Link(); if (!blurShader->IsValid()) { const char* fmt = "shorewaves-shader compilation error: %s"; const char* log = (blurShader->GetLog()).c_str(); LOG_L(L_ERROR, fmt, log); //! string size is limited with content_error() throw content_error(string("["LOG_SECTION_BUMP_WATER"] shorewaves-shader compilation error!")); } blurShader->SetUniformLocation("tex0"); // idx 0 blurShader->SetUniformLocation("tex1"); // idx 1 blurShader->Enable(); blurShader->SetUniform1i(0, 0); blurShader->SetUniform1i(1, 1); blurShader->Disable(); blurShader->Validate(); if (!blurShader->IsValid()) { const char* fmt = "shorewaves-shader validation error: %s"; const char* log = (blurShader->GetLog()).c_str(); LOG_L(L_ERROR, fmt, log); throw content_error(string("["LOG_SECTION_BUMP_WATER"] shorewaves-shader validation error!")); } } coastFBO.reloadOnAltTab = true; coastFBO.Bind(); coastFBO.AttachTexture(coastTexture, GL_TEXTURE_2D, GL_COLOR_ATTACHMENT0_EXT); if (coastFBO.CheckStatus("BUMPWATER(Coastmap)")) { //! initialize texture glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT); //! fill with current heightmap/coastmap UnsyncedHeightMapUpdate(SRectangle(0, 0, gs->mapx, gs->mapy)); UploadCoastline(true); UpdateCoastmap(); } else shoreWaves = false; if (shoreWaves) eventHandler.InsertEvent(this, "UnsyncedHeightMapUpdate"); //coastFBO.Unbind(); // gets done below } // CREATE TEXTURES if ((refraction > 0) || depthCopy) { //! ATIs do not have GLSL support for texrects screenTextureX = globalRendering->viewSizeX; screenTextureY = globalRendering->viewSizeY; if (GLEW_ARB_texture_rectangle && !globalRendering->atiHacks) { target = GL_TEXTURE_RECTANGLE_ARB; } else { target = GL_TEXTURE_2D; if (!globalRendering->supportNPOTs) { screenTextureX = next_power_of_2(globalRendering->viewSizeX); screenTextureY = next_power_of_2(globalRendering->viewSizeY); } } } if (refraction > 0) { //! CREATE REFRACTION TEXTURE glGenTextures(1, &refractTexture); glBindTexture(target, refractTexture); glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); if (GLEW_EXT_texture_edge_clamp) { glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } else { glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP); } glTexImage2D(target, 0, GL_RGBA8, screenTextureX, screenTextureY, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); } if (reflection > 0) { //! CREATE REFLECTION TEXTURE glGenTextures(1, &reflectTexture); glBindTexture(GL_TEXTURE_2D, reflectTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); if (GLEW_EXT_texture_edge_clamp) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } else { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); } glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, reflTexSize, reflTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); } if (depthCopy) { //! CREATE DEPTH TEXTURE glGenTextures(1, &depthTexture); glBindTexture(target, depthTexture); glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); GLuint depthFormat = GL_DEPTH_COMPONENT; switch (globalRendering->depthBufferBits) { // use same depth as screen framebuffer case 16: depthFormat = GL_DEPTH_COMPONENT16; break; case 24: if (!globalRendering->atiHacks) { depthFormat = GL_DEPTH_COMPONENT24; break; } // ATIs fall through and use 32bit! default: depthFormat = GL_DEPTH_COMPONENT32; break; } glTexImage2D(target, 0, depthFormat, screenTextureX, screenTextureY, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); } if (dynWaves) { //! SETUP DYNAMIC WAVES tileOffsets = new unsigned char[mapInfo->water.numTiles * mapInfo->water.numTiles]; normalTexture2 = normalTexture; glBindTexture(GL_TEXTURE_2D, normalTexture2); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 0.0); glGenTextures(1, &normalTexture); glBindTexture(GL_TEXTURE_2D, normalTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); if (anisotropy > 0.0f) { glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy); } glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, normalTextureX, normalTextureY, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glGenerateMipmapEXT(GL_TEXTURE_2D); } // CREATE FBOs if (GLEW_EXT_framebuffer_object) { GLuint depthRBOFormat = GL_DEPTH_COMPONENT; switch (depthBits) { case 16: depthRBOFormat = GL_DEPTH_COMPONENT16; break; case 24: depthRBOFormat = GL_DEPTH_COMPONENT24; break; case 32: depthRBOFormat = GL_DEPTH_COMPONENT32; break; } if (reflection>0) { reflectFBO.Bind(); reflectFBO.CreateRenderBuffer(GL_DEPTH_ATTACHMENT_EXT, depthRBOFormat, reflTexSize, reflTexSize); reflectFBO.AttachTexture(reflectTexture); } if (refraction>0) { refractFBO.Bind(); refractFBO.CreateRenderBuffer(GL_DEPTH_ATTACHMENT_EXT, depthRBOFormat, screenTextureX, screenTextureY); refractFBO.AttachTexture(refractTexture,target); } if (!reflectFBO.CheckStatus("BUMPWATER(reflection)")) { reflection = 0; } if (!refractFBO.CheckStatus("BUMPWATER(refraction)")) { refraction = 0; } if (dynWaves) { dynWavesFBO.reloadOnAltTab = true; dynWavesFBO.Bind(); dynWavesFBO.AttachTexture(normalTexture); if (dynWavesFBO.CheckStatus("BUMPWATER(DynWaves)")) { UpdateDynWaves(true); //! initialize } } FBO::Unbind(); } /* * DEFINE SOME SHADER RUNTIME CONSTANTS * (I do not use Uniforms for that, because the GLSL compiler can not * optimize those!) */ string definitions; if (reflection>0) definitions += "#define opt_reflection\n"; if (refraction>0) definitions += "#define opt_refraction\n"; if (shoreWaves) definitions += "#define opt_shorewaves\n"; if (depthCopy) definitions += "#define opt_depth\n"; if (blurRefl) definitions += "#define opt_blurreflection\n"; if (endlessOcean) definitions += "#define opt_endlessocean\n"; if (target == GL_TEXTURE_RECTANGLE_ARB) definitions += "#define opt_texrect\n"; GLSLDefineConstf3(definitions, "MapMid", float3(readmap->width * SQUARE_SIZE * 0.5f, 0.0f, readmap->height * SQUARE_SIZE * 0.5f) ); GLSLDefineConstf2(definitions, "ScreenInverse", 1.0f / globalRendering->viewSizeX, 1.0f / globalRendering->viewSizeY ); GLSLDefineConstf2(definitions, "ScreenTextureSizeInverse", 1.0f / screenTextureX, 1.0f / screenTextureY ); GLSLDefineConstf2(definitions, "ViewPos", globalRendering->viewPosX, globalRendering->viewPosY ); if (useUniforms) { SetupUniforms(definitions); } else { GLSLDefineConstf4(definitions, "SurfaceColor", mapInfo->water.surfaceColor*0.4, mapInfo->water.surfaceAlpha ); GLSLDefineConstf4(definitions, "PlaneColor", mapInfo->water.planeColor*0.4, mapInfo->water.surfaceAlpha ); GLSLDefineConstf3(definitions, "DiffuseColor", mapInfo->water.diffuseColor); GLSLDefineConstf3(definitions, "SpecularColor", mapInfo->water.specularColor); GLSLDefineConstf1(definitions, "SpecularPower", mapInfo->water.specularPower); GLSLDefineConstf1(definitions, "SpecularFactor", mapInfo->water.specularFactor); GLSLDefineConstf1(definitions, "AmbientFactor", mapInfo->water.ambientFactor); GLSLDefineConstf1(definitions, "DiffuseFactor", mapInfo->water.diffuseFactor * 15.0f); GLSLDefineConstf3(definitions, "SunDir", sky->GetLight()->GetLightDir()); // FIXME: not a constant GLSLDefineConstf1(definitions, "FresnelMin", mapInfo->water.fresnelMin); GLSLDefineConstf1(definitions, "FresnelMax", mapInfo->water.fresnelMax); GLSLDefineConstf1(definitions, "FresnelPower", mapInfo->water.fresnelPower); GLSLDefineConstf1(definitions, "ReflDistortion", mapInfo->water.reflDistortion); GLSLDefineConstf2(definitions, "BlurBase", 0.0f, mapInfo->water.blurBase / globalRendering->viewSizeY); GLSLDefineConstf1(definitions, "BlurExponent", mapInfo->water.blurExponent); GLSLDefineConstf1(definitions, "PerlinStartFreq", mapInfo->water.perlinStartFreq); GLSLDefineConstf1(definitions, "PerlinLacunarity", mapInfo->water.perlinLacunarity); GLSLDefineConstf1(definitions, "PerlinAmp", mapInfo->water.perlinAmplitude); GLSLDefineConstf1(definitions, "WindSpeed", mapInfo->water.windSpeed); } { const int mapX = readmap->width * SQUARE_SIZE; const int mapZ = readmap->height * SQUARE_SIZE; const float shadingX = (float)gs->mapx / gs->pwr2mapx; const float shadingZ = (float)gs->mapy / gs->pwr2mapy; const float scaleX = (mapX > mapZ) ? (readmap->height/64)/16.0f * (float)mapX/mapZ : (readmap->width/64)/16.0f; const float scaleZ = (mapX > mapZ) ? (readmap->height/64)/16.0f : (readmap->width/64)/16.0f * (float)mapZ/mapX; GLSLDefineConst4f(definitions, "TexGenPlane", 1.0f/mapX, 1.0f/mapZ, scaleX/mapX, scaleZ/mapZ); GLSLDefineConst4f(definitions, "ShadingPlane", shadingX/mapX, shadingZ/mapZ, shadingX, shadingZ); } // LOAD SHADERS { waterShader = shaderHandler->CreateProgramObject("[BumpWater]", "WaterShader", false); waterShader->AttachShaderObject(shaderHandler->CreateShaderObject("GLSL/bumpWaterVS.glsl", definitions, GL_VERTEX_SHADER)); waterShader->AttachShaderObject(shaderHandler->CreateShaderObject("GLSL/bumpWaterFS.glsl", definitions, GL_FRAGMENT_SHADER)); waterShader->Link(); waterShader->SetUniformLocation("eyePos"); // idx 0 waterShader->SetUniformLocation("frame"); // idx 1 waterShader->SetUniformLocation("normalmap"); // idx 2 waterShader->SetUniformLocation("heightmap"); // idx 3 waterShader->SetUniformLocation("caustic"); // idx 4 waterShader->SetUniformLocation("foam"); // idx 5 waterShader->SetUniformLocation("reflection"); // idx 6 waterShader->SetUniformLocation("refraction"); // idx 7 waterShader->SetUniformLocation("depthmap"); // idx 8 waterShader->SetUniformLocation("coastmap"); // idx 9 waterShader->SetUniformLocation("waverand"); // idx 10 if (!waterShader->IsValid()) { const char* fmt = "water-shader compilation error: %s"; const char* log = (waterShader->GetLog()).c_str(); LOG_L(L_ERROR, fmt, log); throw content_error(string("["LOG_SECTION_BUMP_WATER"] water-shader compilation error!")); } if (useUniforms) { GetUniformLocations(waterShader); } // BIND TEXTURE UNIFORMS // NOTE: ATI shader validation code is stricter wrt. state, // so postpone the call until all texture uniforms are set waterShader->Enable(); waterShader->SetUniform1i( 2, 0); waterShader->SetUniform1i( 3, 1); waterShader->SetUniform1i( 4, 2); waterShader->SetUniform1i( 5, 3); waterShader->SetUniform1i( 6, 4); waterShader->SetUniform1i( 7, 5); waterShader->SetUniform1i( 8, 7); waterShader->SetUniform1i( 9, 6); waterShader->SetUniform1i(10, 8); waterShader->Disable(); waterShader->Validate(); if (!waterShader->IsValid()) { const char* fmt = "water-shader validation error: %s"; const char* log = (waterShader->GetLog()).c_str(); LOG_L(L_ERROR, fmt, log); throw content_error(string("["LOG_SECTION_BUMP_WATER"] water-shader validation error!")); } } // CREATE DISPLAYLIST displayList = glGenLists(1); glNewList(displayList, GL_COMPILE); if (endlessOcean) { DrawRadialDisc(); } else { const int mapX = readmap->width * SQUARE_SIZE; const int mapZ = readmap->height * SQUARE_SIZE; CVertexArray* va = GetVertexArray(); va->Initialize(); for (int z = 0; z < 9; z++) { for (int x = 0; x < 10; x++) { for (int zs = 0; zs <= 1; zs++) { va->AddVertex0(float3(x*(mapX/9.0f), 0.0f, (z + zs)*(mapZ/9.0f))); } } va->EndStrip(); } va->DrawArray0(GL_TRIANGLE_STRIP); } glEndList(); /* windndir = wind.GetCurrentDirection(); windStrength = (smoothstep(0.0f, 12.0f, wind.GetCurrentStrength()) * 0.5f + 4.0f); windVec = windndir * windStrength; */ windVec = float3(20.0, 0.0, 20.0); occlusionQuery = 0; occlusionQueryResult = GL_TRUE; wasLastFrameVisible = true; bool useOcclQuery = (configHandler->GetBool("BumpWaterOcclusionQuery")); if (useOcclQuery && GLEW_ARB_occlusion_query && (refraction < 2)) { //! in the case of a separate refraction pass, there isn't enough time for a occlusion query GLint bitsSupported; glGetQueryiv(GL_SAMPLES_PASSED, GL_QUERY_COUNTER_BITS, &bitsSupported); if (bitsSupported > 0) { glGenQueries(1, &occlusionQuery); } } if (refraction > 1) { drawSolid = true; } }
void CAdvWater::Draw(bool useBlending) { if (!waterRendering->forceRendering && !readMap->HasVisibleWater()) return; float3 base = camera->CalcPixelDir(globalRendering->viewPosX, globalRendering->viewSizeY); float3 dv = camera->CalcPixelDir(globalRendering->viewPosX, 0) - camera->CalcPixelDir(globalRendering->viewPosX, globalRendering->viewSizeY); float3 dh = camera->CalcPixelDir(globalRendering->viewPosX + globalRendering->viewSizeX, 0) - camera->CalcPixelDir(globalRendering->viewPosX, 0); float3 xbase; float3 forward = camera->GetDir(); float3 dir; float3 zpos; const int numDivs = 20; base *= numDivs; float maxY = -0.1f; float yInc = 1.0f / numDivs; float screenY = 1.0f; unsigned char col[4]; col[0] = (unsigned char)(waterSurfaceColor.x * 255); col[1] = (unsigned char)(waterSurfaceColor.y * 255); col[2] = (unsigned char)(waterSurfaceColor.z * 255); glDisable(GL_ALPHA_TEST); if (useBlending) { glEnable(GL_BLEND); } else { glDisable(GL_BLEND); } glDepthMask(0); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, bumpTexture); GLfloat plan[] = {0.02f, 0, 0, 0}; glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); glTexGenfv(GL_S, GL_EYE_PLANE, plan); glEnable(GL_TEXTURE_GEN_S); GLfloat plan2[] = {0, 0, 0.02f, 0}; glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); glTexGenfv(GL_T, GL_EYE_PLANE, plan2); glEnable(GL_TEXTURE_GEN_T); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, reflectTexture); glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, waterFP); glEnable(GL_FRAGMENT_PROGRAM_ARB); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE * wireFrameMode + GL_FILL * (1 - wireFrameMode)); forward.ANormalize2D(); glProgramEnvParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 0, forward.z, forward.x, 0.0f, 0.0f); glProgramEnvParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 1, -forward.x, forward.z, 0.0f, 0.0f); CVertexArray* va = GetVertexArray(); va->Initialize(); va->EnlargeArrays(5 * numDivs * (numDivs + 1) * 2, 5 * numDivs, VA_SIZE_TC); //! alloc room for all vertexes and strips for (int a = 0; a < 5; ++a) { //! CAUTION: loop count must match EnlargeArrays above bool maxReached = false; for (int y = 0; y < numDivs; ++y) { dir = base; dir.ANormalize(); if (dir.y >= maxY) { maxReached = true; break; } xbase = base; for (int x = 0; x < numDivs + 1; ++x) { //! CAUTION: loop count must match EnlargeArrays above dir = xbase + dv; dir.ANormalize(); zpos = camera->GetPos() + dir * (camera->GetPos().y / -dir.y); zpos.y = fastmath::sin(zpos.z * 0.1f + gs->frameNum * 0.06f) * 0.06f + 0.05f; col[3] = (unsigned char)((0.8f + 0.7f * dir.y) * 255); va->AddVertexQTC(zpos, x * (1.0f / numDivs), screenY - yInc, col); dir = xbase; dir.ANormalize(); zpos = camera->GetPos() + dir * (camera->GetPos().y / -dir.y); zpos.y = fastmath::sin(zpos.z * 0.1f + gs->frameNum * 0.06f) * 0.06f + 0.05f; col[3] = (unsigned char)((0.8f + 0.7f * dir.y) * 255); va->AddVertexQTC(zpos, x * (1.0f / numDivs), screenY, col); xbase += dh; } va->EndStrip(); base += dv; screenY -= yInc; } if (!maxReached) break; dv *= 0.5f; maxY *= 0.5f; yInc *= 0.5f; } va->DrawArrayTC(GL_TRIANGLE_STRIP); glDepthMask(1); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glDisable(GL_FRAGMENT_PROGRAM_ARB); glActiveTexture(GL_TEXTURE1); glDisable(GL_TEXTURE_GEN_S); glDisable(GL_TEXTURE_GEN_T); glActiveTexture(GL_TEXTURE0); // for translucent stuff like water, the default mode is blending and alpha testing enabled if (!useBlending) glEnable(GL_BLEND); }
CBumpWater::CBumpWater() { /** LOAD USER CONFIGS **/ reflTexSize = next_power_of_2(configHandler->Get("BumpWaterTexSizeReflection", 512)); reflection = !!configHandler->Get("BumpWaterReflection", 1); refraction = configHandler->Get("BumpWaterRefraction", 1); /// 0:=off, 1:=screencopy, 2:=own rendering cycle anisotropy = atof(configHandler->GetString("BumpWaterAnisotropy", "0.0").c_str()); depthCopy = !!configHandler->Get("BumpWaterUseDepthTexture", 1); depthBits = configHandler->Get("BumpWaterDepthBits", (gu->atiHacks)?16:24); blurRefl = !!configHandler->Get("BumpWaterBlurReflection", 0); shoreWaves = (!!configHandler->Get("", 1)) && mapInfo->water.shoreWaves; endlessOcean = (!!configHandler->Get("BumpWaterEndlessOcean", 1)) && mapInfo->water.hasWaterPlane && ((readmap->minheight <= 0.0f) || (mapInfo->water.forceRendering)); dynWaves = (!!configHandler->Get("BumpWaterDynamicWaves", 1)) && (mapInfo->water.numTiles>1); useUniforms = (!!configHandler->Get("BumpWaterUseUniforms", 0)); refractTexture = 0; reflectTexture = 0; /** CHECK HARDWARE **/ if (!GL_ARB_shading_language_100) throw content_error("BumpWater: your hardware/driver setup does not support GLSL."); shoreWaves = shoreWaves && (GLEW_EXT_framebuffer_object); dynWaves = dynWaves && (GLEW_EXT_framebuffer_object && GLEW_ARB_imaging); /** LOAD TEXTURES **/ foamTexture = LoadTexture( mapInfo->water.foamTexture ); normalTexture = LoadTexture( mapInfo->water.normalTexture , anisotropy , &normalTextureX, &normalTextureY); //! caustic textures const vector<string>& causticNames = mapInfo->water.causticTextures; if (causticNames.size() <= 0) { throw content_error("no caustic textures"); } for (int i = 0; i < (int)causticNames.size(); ++i) { caustTextures.push_back(LoadTexture(causticNames[i])); } /** CHECK SHOREWAVES TEXTURE SIZE **/ if (shoreWaves) { GLint maxw,maxh; glTexImage2D(GL_PROXY_TEXTURE_2D, 0, GL_RGBA16F_ARB, 4096, 4096, 0, GL_RGBA, GL_FLOAT, NULL); glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &maxw); glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &maxh); if (gs->mapx>maxw || gs->mapy>maxh) { shoreWaves = false; logOutput.Print("BumpWater: can't display shorewaves (map too large)!"); } } /** SHOREWAVES **/ if (shoreWaves) { waveRandTexture = LoadTexture( "bitmaps/shorewaverand.png" ); glGenTextures(1, &coastTexture); glBindTexture(GL_TEXTURE_2D, coastTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); //glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, gs->mapx, gs->mapy, 0, GL_RGBA, GL_FLOAT, NULL); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5, gs->mapx, gs->mapy, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); //glGenerateMipmapEXT(GL_TEXTURE_2D); const string fsSource = LoadShaderSource("shaders/bumpWaterCoastBlurFS.glsl"); const GLchar* fsSourceStr = fsSource.c_str(); blurFP = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(blurFP, 1, &fsSourceStr, NULL); glCompileShader(blurFP); PrintShaderLog(blurFP, "blurFP"); blurShader = glCreateProgram(); glAttachShader(blurShader, blurFP); glLinkProgram(blurShader); PrintShaderLog(blurShader, "blurShader"); glUseProgram(blurShader); GLuint tex0Loc = glGetUniformLocation(blurShader, "tex0"); GLuint tex1Loc = glGetUniformLocation(blurShader, "tex1"); glUniform1i(tex0Loc, 0); glUniform1i(tex1Loc, 1); glUseProgram(0); coastFBO.reloadOnAltTab = true; coastFBO.Bind(); coastFBO.AttachTexture(coastTexture, GL_TEXTURE_2D, GL_COLOR_ATTACHMENT0_EXT); if (coastFBO.CheckStatus("BUMPWATER(Coastmap)")) { //! initialize texture glClearColor(0.0f,0.0f,0.0f,0.0f); glClear(GL_COLOR_BUFFER_BIT); //! fill with current heightmap/coastmap HeightmapChanged(0, 0, gs->mapx, gs->mapy); UploadCoastline(true); UpdateCoastmap(); }else shoreWaves=false; //coastFBO.Unbind(); gets done below } /** CREATE TEXTURES **/ if ((refraction>0) || depthCopy) { //! ati's don't have glsl support for texrects screenTextureX = gu->viewSizeX; screenTextureY = gu->viewSizeY; if (GLEW_ARB_texture_rectangle && !gu->atiHacks) { target = GL_TEXTURE_RECTANGLE_ARB; } else { target = GL_TEXTURE_2D; if (!gu->supportNPOTs) { screenTextureX = next_power_of_2(gu->viewSizeX); screenTextureY = next_power_of_2(gu->viewSizeY); } } } if (refraction>0) { //! CREATE REFRACTION TEXTURE glGenTextures(1, &refractTexture); glBindTexture(target, refractTexture); glTexParameteri(target,GL_TEXTURE_MAG_FILTER,GL_NEAREST); glTexParameteri(target,GL_TEXTURE_MIN_FILTER,GL_NEAREST); if (GLEW_EXT_texture_edge_clamp) { glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } else { glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP); } glTexImage2D(target, 0, GL_RGBA8, screenTextureX, screenTextureY, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); } if (reflection) { //! CREATE REFLECTION TEXTURE glGenTextures(1, &reflectTexture); glBindTexture(GL_TEXTURE_2D, reflectTexture); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); if (GLEW_EXT_texture_edge_clamp) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } else { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); } glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, reflTexSize, reflTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); } if (depthCopy) { //! CREATE DEPTH TEXTURE glGenTextures(1, &depthTexture); glBindTexture(target, depthTexture); glTexParameteri(target,GL_TEXTURE_MAG_FILTER,GL_NEAREST); glTexParameteri(target,GL_TEXTURE_MIN_FILTER,GL_NEAREST); GLuint depthFormat = GL_DEPTH_COMPONENT; switch (gu->depthBufferBits) { /// use same depth as screen framebuffer case 16: depthFormat = GL_DEPTH_COMPONENT16; break; case 24: if (!gu->atiHacks) { depthFormat = GL_DEPTH_COMPONENT24; break; } //ATIs fall through and use 32bit! default: depthFormat = GL_DEPTH_COMPONENT32; break; } glTexImage2D(target, 0, depthFormat, screenTextureX, screenTextureY, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); } if (dynWaves) { //! SETUP DYNAMIC WAVES tileOffsets = new unsigned char[mapInfo->water.numTiles * mapInfo->water.numTiles]; normalTexture2 = normalTexture; glBindTexture(GL_TEXTURE_2D, normalTexture2); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 0.0); glGenTextures(1, &normalTexture); glBindTexture(GL_TEXTURE_2D, normalTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); if (anisotropy>0.0f) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, normalTextureX, normalTextureY, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glGenerateMipmapEXT(GL_TEXTURE_2D); } /** CREATE FBOs **/ if (GLEW_EXT_framebuffer_object) { GLuint depthRBOFormat = GL_DEPTH_COMPONENT; switch (depthBits) { case 16: depthRBOFormat = GL_DEPTH_COMPONENT16; break; case 24: depthRBOFormat = GL_DEPTH_COMPONENT24; break; case 32: depthRBOFormat = GL_DEPTH_COMPONENT32; break; } if (reflection) { reflectFBO.Bind(); reflectFBO.CreateRenderBuffer(GL_DEPTH_ATTACHMENT_EXT, depthRBOFormat, reflTexSize, reflTexSize); reflectFBO.AttachTexture(reflectTexture); } if (refraction>0) { refractFBO.Bind(); refractFBO.CreateRenderBuffer(GL_DEPTH_ATTACHMENT_EXT, depthRBOFormat, screenTextureX, screenTextureY); refractFBO.AttachTexture(refractTexture,target); } if (!reflectFBO.CheckStatus("BUMPWATER(reflection)")) { reflection = false; } if (!refractFBO.CheckStatus("BUMPWATER(refraction)")) { refraction = 0; } if (dynWaves) { dynWavesFBO.reloadOnAltTab = true; dynWavesFBO.Bind(); dynWavesFBO.AttachTexture(normalTexture); if (dynWavesFBO.CheckStatus("BUMPWATER(DynWaves)")) { UpdateDynWaves(true); //! initialize } } FBO::Unbind(); } /** DEFINE SOME SHADER RUNTIME CONSTANTS (I don't use Uniforms for that, because the glsl compiler can't optimize those!) **/ string definitions; if (reflection) definitions += "#define opt_reflection\n"; if (refraction>0) definitions += "#define opt_refraction\n"; if (shoreWaves) definitions += "#define opt_shorewaves\n"; if (depthCopy) definitions += "#define opt_depth\n"; if (blurRefl) definitions += "#define opt_blurreflection\n"; if (endlessOcean) definitions += "#define opt_endlessocean\n"; if (target==GL_TEXTURE_RECTANGLE_ARB) definitions += "#define opt_texrect\n"; GLSLDefineConstf3(definitions, "MapMid", float3(readmap->width*SQUARE_SIZE*0.5f,0.0f,readmap->height*SQUARE_SIZE*0.5f) ); GLSLDefineConstf2(definitions, "ScreenInverse", 1.0f/gu->viewSizeX, 1.0f/gu->viewSizeY ); GLSLDefineConstf2(definitions, "ScreenTextureSizeInverse", 1.0f/screenTextureX, 1.0f/screenTextureY ); GLSLDefineConstf2(definitions, "ViewPos", gu->viewPosX,gu->viewPosY ); if (useUniforms) { SetupUniforms(definitions); } else { GLSLDefineConstf4(definitions, "SurfaceColor", mapInfo->water.surfaceColor*0.4, mapInfo->water.surfaceAlpha ); GLSLDefineConstf4(definitions, "PlaneColor", mapInfo->water.planeColor*0.4, mapInfo->water.surfaceAlpha ); GLSLDefineConstf3(definitions, "DiffuseColor", mapInfo->water.diffuseColor); GLSLDefineConstf3(definitions, "SpecularColor", mapInfo->water.specularColor); GLSLDefineConstf1(definitions, "SpecularPower", mapInfo->water.specularPower); GLSLDefineConstf1(definitions, "SpecularFactor", mapInfo->water.specularFactor); GLSLDefineConstf1(definitions, "AmbientFactor", mapInfo->water.ambientFactor); GLSLDefineConstf1(definitions, "DiffuseFactor", mapInfo->water.diffuseFactor * 15.0f); GLSLDefineConstf3(definitions, "SunDir", mapInfo->light.sunDir); GLSLDefineConstf1(definitions, "FresnelMin", mapInfo->water.fresnelMin); GLSLDefineConstf1(definitions, "FresnelMax", mapInfo->water.fresnelMax); GLSLDefineConstf1(definitions, "FresnelPower", mapInfo->water.fresnelPower); GLSLDefineConstf1(definitions, "ReflDistortion", mapInfo->water.reflDistortion); GLSLDefineConstf2(definitions, "BlurBase", 0.0f,mapInfo->water.blurBase/gu->viewSizeY); GLSLDefineConstf1(definitions, "BlurExponent", mapInfo->water.blurExponent); GLSLDefineConstf1(definitions, "PerlinStartFreq", mapInfo->water.perlinStartFreq); GLSLDefineConstf1(definitions, "PerlinLacunarity", mapInfo->water.perlinLacunarity); GLSLDefineConstf1(definitions, "PerlinAmp", mapInfo->water.perlinAmplitude); GLSLDefineConstf1(definitions, "WindSpeed", mapInfo->water.windSpeed); } { const int mapX = readmap->width * SQUARE_SIZE; const int mapZ = readmap->height * SQUARE_SIZE; const float shadingX = (float)gs->mapx / gs->pwr2mapx; const float shadingZ = (float)gs->mapy / gs->pwr2mapy; const float scaleX = (mapX > mapZ) ? (readmap->height/64)/16.0f * (float)mapX/mapZ : (readmap->width/64)/16.0f; const float scaleZ = (mapX > mapZ) ? (readmap->height/64)/16.0f : (readmap->width/64)/16.0f * (float)mapZ/mapX; GLSLDefineConst4f(definitions, "TexGenPlane", 1.0f/mapX, 1.0f/mapZ, scaleX/mapX, scaleZ/mapZ); GLSLDefineConst4f(definitions, "ShadingPlane", shadingX/mapX, shadingZ/mapZ, shadingX,shadingZ); } /** LOAD SHADERS **/ string vsSource = LoadShaderSource("shaders/bumpWaterVS.glsl"); string fsSource = LoadShaderSource("shaders/bumpWaterFS.glsl"); vector<GLint> lengths(2); vector<const GLchar*> strings(2); lengths[0] = definitions.length(); strings[0] = definitions.c_str(); waterVP = glCreateShader(GL_VERTEX_SHADER); lengths[1] = vsSource.length(); strings[1] = vsSource.c_str(); glShaderSource(waterVP, strings.size(), &strings.front(), &lengths.front()); glCompileShader(waterVP); PrintShaderLog(waterVP, "waterVP"); waterFP = glCreateShader(GL_FRAGMENT_SHADER); lengths[1] = fsSource.length(); strings[1] = fsSource.c_str(); glShaderSource(waterFP, strings.size(), &strings.front(), &lengths.front()); glCompileShader(waterFP); PrintShaderLog(waterFP, "waterFP"); waterShader = glCreateProgram(); glAttachShader(waterShader, waterVP); glAttachShader(waterShader, waterFP); glLinkProgram(waterShader); PrintShaderLog(waterShader, "waterShader"); /** BIND TEXTURE UNIFORMS **/ glUseProgram(waterShader); eyePosLoc = glGetUniformLocation(waterShader, "eyePos"); frameLoc = glGetUniformLocation(waterShader, "frame"); if (useUniforms) GetUniformLocations(waterShader); //! Texture Uniform Locations GLuint normalmapLoc = glGetUniformLocation(waterShader, "normalmap"); GLuint heightmapLoc = glGetUniformLocation(waterShader, "heightmap"); GLuint causticLoc = glGetUniformLocation(waterShader, "caustic"); GLuint foamLoc = glGetUniformLocation(waterShader, "foam"); GLuint reflectionLoc = glGetUniformLocation(waterShader, "reflection"); GLuint refractionLoc = glGetUniformLocation(waterShader, "refraction"); GLuint depthmapLoc = glGetUniformLocation(waterShader, "depthmap"); GLuint coastmapLoc = glGetUniformLocation(waterShader, "coastmap"); GLuint waverandLoc = glGetUniformLocation(waterShader, "waverand"); glUniform1i(normalmapLoc, 0); glUniform1i(heightmapLoc, 1); glUniform1i(causticLoc, 2); glUniform1i(foamLoc, 3); glUniform1i(reflectionLoc, 4); glUniform1i(refractionLoc, 5); glUniform1i(coastmapLoc, 6); glUniform1i(depthmapLoc, 7); glUniform1i(waverandLoc, 8); glUseProgram(0); /** CREATE DISPLAYLIST **/ displayList = glGenLists(1); glNewList(displayList,GL_COMPILE); if (endlessOcean) { DrawRadialDisc(); }else{ const int mapX = readmap->width * SQUARE_SIZE; const int mapZ = readmap->height * SQUARE_SIZE; CVertexArray *va = GetVertexArray(); va->Initialize(); for (int z = 0; z < 9; z++) { for (int x = 0; x < 10; x++) { for (int zs = 0; zs <= 1; zs++) { va->AddVertex0(float3(x*(mapX/9.0f), 0.0f, (z+zs)*(mapZ/9.0f))); } } va->EndStrip(); } va->DrawArray0(GL_TRIANGLE_STRIP); } glEndList(); /* windndir = wind.GetCurrentDirection(); windStrength = (smoothstep(0.0f, 12.0f, wind.GetCurrentStrength()) * 0.5f + 4.0f); windVec = windndir * windStrength; */ windVec = float3(20.0,0.0,20.0); occlusionQuery = 0; occlusionQueryResult = GL_TRUE; wasLastFrameVisible = false; bool useOcclQuery = (!!configHandler->Get("BumpWaterOcclusionQuery", 1)); if (useOcclQuery && GLEW_ARB_occlusion_query && refraction<2) { //! in the case of a separate refraction pass, there isn't enough time for a occlusion query GLint bitsSupported; glGetQueryiv(GL_SAMPLES_PASSED, GL_QUERY_COUNTER_BITS, &bitsSupported); if (bitsSupported > 0) glGenQueries(1,&occlusionQuery); } if (refraction>1) drawSolid = true; }