Example #1
0
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);
	}
}
Example #4
0
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;
	}
}
Example #5
0
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);
}
Example #6
0
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;
}