void CGrassDrawer::DrawFarBillboards(const std::vector<GrassStruct*>& inviewFarGrass)
{
	// update far grass blocks
	if (updateBillboards) {
		updateBillboards = false;

		for_mt(0, inviewFarGrass.size(), [&](const int i){
			GrassStruct& g = *inviewFarGrass[i];
			if (!g.va) {
				//TODO vertex arrays need to be send each frame to the gpu, that's slow. switch to VBOs.
				CVertexArray* va = new CVertexArray;
				g.va = va;
				g.lastDist = -1; // force a recreate
			}

			const float distSq = GetCamDistOfGrassBlock((g.posX + 0.5f) * grassBlockSize, (g.posZ + 0.5f) * grassBlockSize, true);
			if (distSq == g.lastDist)
				return;

			bool inAlphaRange1 = (    distSq < Square(maxDetailedDist + 128.f * 1.5f)) || (    distSq > Square(maxGrassDist - 128.f));
			bool inAlphaRange2 = (g.lastDist < Square(maxDetailedDist + 128.f * 1.5f)) || (g.lastDist > Square(maxGrassDist - 128.f));
			if (!inAlphaRange1 && (inAlphaRange1 == inAlphaRange2)) {
				return;
			}

			g.lastDist = distSq;
			CVertexArray* va = g.va;
			va->Initialize();

			for (int y2 = g.posZ * grassBlockSize; y2 < (g.posZ + 1) * grassBlockSize; ++y2) {
				for (int x2 = g.posX * grassBlockSize; x2 < (g.posX  + 1) * grassBlockSize; ++x2) {
					if (!grassMap[y2 * mapDims.mapx / grassSquareSize + x2]) {
						continue;
					}

					const float dist = GetCamDistOfGrassBlock(x2, y2);
					auto* va_tn = va->GetTypedVertexArray<VA_TYPE_TN>(numTurfs * 4);
					DrawBillboard(x2, y2, dist, va_tn);
				}
			}
		});
	}

	// render far grass blocks
	for (const GrassStruct* g: inviewFarGrass) {
		g->va->DrawArrayTN(GL_QUADS);
	}
}
	void DrawQuad(int x, int y) {
		const float distSq = GetCamDistOfGrassBlock((x + 0.5f) * grassBlockSize, (y + 0.5f) * grassBlockSize, true);

		if (distSq > Square(gd->maxGrassDist))
			return;

		if (abs(x - cx) <= gd->detailedBlocks && abs(y - cy) <= gd->detailedBlocks) {
			return DrawDetailQuad(x, y);
		}
		DrawFarQuad(x, y);
	}
Exemple #3
0
void CGrassBlockDrawer::DrawDetailQuad(const int x, const int y)
{
	const float maxDetailedDist = gd->maxDetailedDist;

	// blocks close to the camera
	for (int y2 = y * grassBlockSize; y2 < (y + 1) * grassBlockSize; ++y2) {
		for (int x2 = x * grassBlockSize; x2 < (x + 1) * grassBlockSize; ++x2) {
			if (!gd->grassMap[y2 * gs->mapx / grassSquareSize + x2]) {
				continue;
			}

			rng.Seed(y2 * gs->mapx / grassSquareSize + x2);
			const float dist  = GetCamDistOfGrassBlock(x2, y2, false);
			const float rdist = 1.0f + rng.RandFloat() * 0.5f;

			//TODO instead of adding grass turfs depending on their distance to the camera,
			//     there should be a fixed sized pool for mesh & billboard turfs
			//     and then we fill these pools with _preference_ for close distance turfs.
			//     So when a map has only less turfs, render them independent of the cam distance as mesh.
			//     -> see Ravaged_2
			if (dist < (maxDetailedDist + 128.f * rdist)) {
				// close grass (render as mesh)
				CGrassDrawer::InviewNearGrass iv;
				iv.dist = dist;
				iv.x = x2;
				iv.y = y2;
				inviewGrass.push_back(iv);
			}

			if (dist > maxDetailedDist) {
				// near but not close, save for later drawing
				CGrassDrawer::InviewNearGrass iv;
				iv.dist = dist;
				iv.x = x2;
				iv.y = y2;
				inviewNearGrass.push_back(iv);
			}
		}
	}
}
static const bool GrassSort(const CGrassDrawer::GrassStruct* a, const CGrassDrawer::GrassStruct* b) {
	const float distA = GetCamDistOfGrassBlock((a->posX + 0.5f) * grassBlockSize, (a->posZ + 0.5f) * grassBlockSize, true);
	const float distB = GetCamDistOfGrassBlock((b->posX + 0.5f) * grassBlockSize, (b->posZ + 0.5f) * grassBlockSize, true);
	return (distA > distB);
}