Esempio n. 1
0
void CPatchRData::RenderPriorities(CTextRenderer& textRenderer)
{
	CTerrain* terrain = m_Patch->m_Parent;
	CCamera* camera = g_Game->GetView()->GetCamera();

	for (ssize_t j = 0; j < PATCH_SIZE; ++j)
	{
		for (ssize_t i = 0; i < PATCH_SIZE; ++i)
		{
			ssize_t gx = m_Patch->m_X * PATCH_SIZE + i;
			ssize_t gz = m_Patch->m_Z * PATCH_SIZE + j;

			CVector3D pos;
			terrain->CalcPosition(gx, gz, pos);

			// Move a bit towards the center of the tile
			pos.X += TERRAIN_TILE_SIZE/4.f;
			pos.Z += TERRAIN_TILE_SIZE/4.f;

			float x, y;
			camera->GetScreenCoordinates(pos, x, y);

			textRenderer.PrintfAt(x, y, L"%d", m_Patch->m_MiniPatches[j][i].Priority);
		}
	}
}
Esempio n. 2
0
void CPatchRData::RenderOutline()
{
	CTerrain* terrain = m_Patch->m_Parent;
	ssize_t gx = m_Patch->m_X * PATCH_SIZE;
	ssize_t gz = m_Patch->m_Z * PATCH_SIZE;

	CVector3D pos;
	std::vector<CVector3D> line;

	ssize_t i, j;

	for (i = 0, j = 0; i <= PATCH_SIZE; ++i)
	{
		terrain->CalcPosition(gx + i, gz + j, pos);
		line.push_back(pos);
	}
	for (i = PATCH_SIZE, j = 1; j <= PATCH_SIZE; ++j)
	{
		terrain->CalcPosition(gx + i, gz + j, pos);
		line.push_back(pos);
	}
	for (i = PATCH_SIZE-1, j = PATCH_SIZE; i >= 0; --i)
	{
		terrain->CalcPosition(gx + i, gz + j, pos);
		line.push_back(pos);
	}
	for (i = 0, j = PATCH_SIZE-1; j >= 0; --j)
	{
		terrain->CalcPosition(gx + i, gz + j, pos);
		line.push_back(pos);
	}

#if CONFIG2_GLES
#warning TODO: implement CPatchRData::RenderOutlines for GLES
#else
	glVertexPointer(3, GL_FLOAT, sizeof(CVector3D), &line[0]);
	glDrawArrays(GL_LINE_STRIP, 0, line.size());
#endif
}
Esempio n. 3
0
void CPatchRData::BuildSide(std::vector<SSideVertex>& vertices, CPatchSideFlags side)
{
	ssize_t vsize = PATCH_SIZE + 1;
	CTerrain* terrain = m_Patch->m_Parent;
	CmpPtr<ICmpWaterManager> cmpWaterManager(*m_Simulation, SYSTEM_ENTITY);

	for (ssize_t k = 0; k < vsize; k++)
	{
		ssize_t gx = m_Patch->m_X * PATCH_SIZE;
		ssize_t gz = m_Patch->m_Z * PATCH_SIZE;
		switch (side)
		{
		case CPATCH_SIDE_NEGX: gz += k; break;
		case CPATCH_SIDE_POSX: gx += PATCH_SIZE; gz += PATCH_SIZE-k; break;
		case CPATCH_SIDE_NEGZ: gx += PATCH_SIZE-k; break;
		case CPATCH_SIDE_POSZ: gz += PATCH_SIZE; gx += k; break;
		}

		CVector3D pos;
		terrain->CalcPosition(gx, gz, pos);

		// Clamp the height to the water level
		float waterHeight = 0.f;
		if (cmpWaterManager)
			waterHeight = cmpWaterManager->GetExactWaterLevel(pos.X, pos.Z);
		pos.Y = std::max(pos.Y, waterHeight);

		SSideVertex v0, v1;
		v0.m_Position = pos;
		v1.m_Position = pos;
		v1.m_Position.Y = 0;

		// If this is the start of this tristrip, but we've already got a partial
		// tristrip, add a couple of degenerate triangles to join the strips properly
		if (k == 0 && !vertices.empty())
		{
			vertices.push_back(vertices.back());
			vertices.push_back(v1);
		}

		// Now add the new triangles
		vertices.push_back(v1);
		vertices.push_back(v0);
	}
}
Esempio n. 4
0
void CPatchRData::AddBlend(std::vector<SBlendVertex>& blendVertices, std::vector<u16>& blendIndices, 
			   u16 i, u16 j, u8 shape, CTerrainTextureEntry* texture)
{
	CTerrain* terrain = m_Patch->m_Parent;

	ssize_t gx = m_Patch->m_X * PATCH_SIZE + i;
	ssize_t gz = m_Patch->m_Z * PATCH_SIZE + j;

	// uses the current neighbour texture
	BlendShape8 shape8;
	for (size_t m = 0; m < 8; ++m)
		shape8[m] = (shape & (1 << m)) ? 0 : 1;

	// calculate the required alphamap and the required rotation of the alphamap from blendshape
	unsigned int alphamapflags;
	int alphamap = CAlphaMapCalculator::Calculate(shape8, alphamapflags);

	// now actually render the blend tile (if we need one)
	if (alphamap == -1)
		return;
	
	float u0 = texture->m_TerrainAlpha->second.m_AlphaMapCoords[alphamap].u0;
	float u1 = texture->m_TerrainAlpha->second.m_AlphaMapCoords[alphamap].u1;
	float v0 = texture->m_TerrainAlpha->second.m_AlphaMapCoords[alphamap].v0;
	float v1 = texture->m_TerrainAlpha->second.m_AlphaMapCoords[alphamap].v1;

	if (alphamapflags & BLENDMAP_FLIPU)
		std::swap(u0, u1);

	if (alphamapflags & BLENDMAP_FLIPV)
		std::swap(v0, v1);

	int base = 0;
	if (alphamapflags & BLENDMAP_ROTATE90)
		base = 1;
	else if (alphamapflags & BLENDMAP_ROTATE180)
		base = 2;
	else if (alphamapflags & BLENDMAP_ROTATE270)
		base = 3;

	SBlendVertex vtx[4];
	vtx[(base + 0) % 4].m_AlphaUVs[0] = u0;
	vtx[(base + 0) % 4].m_AlphaUVs[1] = v0;
	vtx[(base + 1) % 4].m_AlphaUVs[0] = u1;
	vtx[(base + 1) % 4].m_AlphaUVs[1] = v0;
	vtx[(base + 2) % 4].m_AlphaUVs[0] = u1;
	vtx[(base + 2) % 4].m_AlphaUVs[1] = v1;
	vtx[(base + 3) % 4].m_AlphaUVs[0] = u0;
	vtx[(base + 3) % 4].m_AlphaUVs[1] = v1;

	SBlendVertex dst;

	const CLightEnv& lightEnv = g_Renderer.GetLightEnv();
	CVector3D normal;

	bool cpuLighting = (g_Renderer.GetRenderPath() == CRenderer::RP_FIXED);

	size_t index = blendVertices.size();

	terrain->CalcPosition(gx, gz, dst.m_Position);
	terrain->CalcNormal(gx, gz, normal);
	dst.m_Normal = normal;
	dst.m_DiffuseColor = cpuLighting ? lightEnv.EvaluateTerrainDiffuseScaled(normal) : lightEnv.EvaluateTerrainDiffuseFactor(normal);
	dst.m_AlphaUVs[0] = vtx[0].m_AlphaUVs[0];
	dst.m_AlphaUVs[1] = vtx[0].m_AlphaUVs[1];
	blendVertices.push_back(dst);

	terrain->CalcPosition(gx + 1, gz, dst.m_Position);
	terrain->CalcNormal(gx + 1, gz, normal);
	dst.m_Normal = normal;
	dst.m_DiffuseColor = cpuLighting ? lightEnv.EvaluateTerrainDiffuseScaled(normal) : lightEnv.EvaluateTerrainDiffuseFactor(normal);
	dst.m_AlphaUVs[0] = vtx[1].m_AlphaUVs[0];
	dst.m_AlphaUVs[1] = vtx[1].m_AlphaUVs[1];
	blendVertices.push_back(dst);

	terrain->CalcPosition(gx + 1, gz + 1, dst.m_Position);
	terrain->CalcNormal(gx + 1, gz + 1, normal);
	dst.m_Normal = normal;
	dst.m_DiffuseColor = cpuLighting ? lightEnv.EvaluateTerrainDiffuseScaled(normal) : lightEnv.EvaluateTerrainDiffuseFactor(normal);
	dst.m_AlphaUVs[0] = vtx[2].m_AlphaUVs[0];
	dst.m_AlphaUVs[1] = vtx[2].m_AlphaUVs[1];
	blendVertices.push_back(dst);

	terrain->CalcPosition(gx, gz + 1, dst.m_Position);
	terrain->CalcNormal(gx, gz + 1, normal);
	dst.m_Normal = normal;
	dst.m_DiffuseColor = cpuLighting ? lightEnv.EvaluateTerrainDiffuseScaled(normal) : lightEnv.EvaluateTerrainDiffuseFactor(normal);
	dst.m_AlphaUVs[0] = vtx[3].m_AlphaUVs[0];
	dst.m_AlphaUVs[1] = vtx[3].m_AlphaUVs[1];
	blendVertices.push_back(dst);

	bool dir = terrain->GetTriangulationDir(gx, gz);
	if (dir)
	{
		blendIndices.push_back(index+0);
		blendIndices.push_back(index+1);
		blendIndices.push_back(index+3);

		blendIndices.push_back(index+1);
		blendIndices.push_back(index+2);
		blendIndices.push_back(index+3);
	}
	else
	{
		blendIndices.push_back(index+0);
		blendIndices.push_back(index+1);
		blendIndices.push_back(index+2);

		blendIndices.push_back(index+2);
		blendIndices.push_back(index+3);
		blendIndices.push_back(index+0);
	}
}
Esempio n. 5
0
// Build vertex buffer for water vertices over our patch
void CPatchRData::BuildWater()
{
	PROFILE3("build water");

	// number of vertices in each direction in each patch
	ENSURE((PATCH_SIZE % water_cell_size) == 0);

	if (m_VBWater)
	{
		g_VBMan.Release(m_VBWater);
		m_VBWater = 0;
	}
	if (m_VBWaterIndices)
	{
		g_VBMan.Release(m_VBWaterIndices);
		m_VBWaterIndices = 0;
	}
	m_WaterBounds.SetEmpty();

	// We need to use this to access the water manager or we may not have the
	// actual values but some compiled-in defaults
	CmpPtr<ICmpWaterManager> cmpWaterManager(*m_Simulation, SYSTEM_ENTITY);
	if (!cmpWaterManager)
		return;
	
	// Build data for water
	std::vector<SWaterVertex> water_vertex_data;
	std::vector<GLushort> water_indices;
	u16 water_index_map[PATCH_SIZE+1][PATCH_SIZE+1];
	memset(water_index_map, 0xFF, sizeof(water_index_map));

	// TODO: This is not (yet) exported via the ICmp interface so... we stick to these values which can be compiled in defaults
	WaterManager* WaterMgr = g_Renderer.GetWaterManager();

	if (WaterMgr->m_NeedsFullReloading && !g_AtlasGameLoop->running)
	{
		WaterMgr->m_NeedsFullReloading = false;
		WaterMgr->CreateSuperfancyInfo(m_Simulation);
	}
	CPatch* patch = m_Patch;
	CTerrain* terrain = patch->m_Parent;

	ssize_t mapSize = (size_t)terrain->GetVerticesPerSide();

	ssize_t x1 = m_Patch->m_X*PATCH_SIZE;
	ssize_t z1 = m_Patch->m_Z*PATCH_SIZE;

	// build vertices, uv, and shader varying
	for (ssize_t z = 0; z < PATCH_SIZE; z += water_cell_size)
	{
		for (ssize_t x = 0; x <= PATCH_SIZE; x += water_cell_size)
		{
			// Check that the edge at x is partially underwater
			float startTerrainHeight[2] = { terrain->GetVertexGroundLevel(x+x1, z+z1), terrain->GetVertexGroundLevel(x+x1, z+z1 + water_cell_size) };
			float startWaterHeight[2] = { cmpWaterManager->GetExactWaterLevel(x+x1, z+z1), cmpWaterManager->GetExactWaterLevel(x+x1, z+z1 + water_cell_size) };
			if (startTerrainHeight[0] >= startWaterHeight[0] && startTerrainHeight[1] >= startWaterHeight[1])
				continue;

			// Move x back one cell (unless at start of patch), then scan rightwards
			bool belowWater = true;
			ssize_t stripStart;
			for (stripStart = x = std::max(x-water_cell_size, (ssize_t)0); x <= PATCH_SIZE; x += water_cell_size)
			{
				// If this edge is not underwater, and neither is the previous edge
				// (i.e. belowWater == false), then stop this strip since we've reached
				// a cell that's entirely above water
				float terrainHeight[2] = { terrain->GetVertexGroundLevel(x+x1, z+z1), terrain->GetVertexGroundLevel(x+x1, z+z1 + water_cell_size) };
				float waterHeight[2] = { cmpWaterManager->GetExactWaterLevel(x+x1, z+z1), cmpWaterManager->GetExactWaterLevel(x+x1, z+z1 + water_cell_size) };
				if (terrainHeight[0] >= waterHeight[0] && terrainHeight[1] >= waterHeight[1])
				{
					if (!belowWater)
						break;
					belowWater = false;
				}
				else
					belowWater = true;

				// Edge (x,z)-(x,z+1) is at least partially underwater, so extend the water plane strip across it

				// Compute vertex data for the 2 points on the edge
				for (int j = 0; j < 2; j++)
				{
					// Check if we already computed this vertex from an earlier strip
					if (water_index_map[z+j*water_cell_size][x] != 0xFFFF)
						continue;

					SWaterVertex vertex;

					terrain->CalcPosition(x+x1, z+z1 + j*water_cell_size, vertex.m_Position);
					float depth = waterHeight[j] - vertex.m_Position.Y;
					vertex.m_Position.Y = waterHeight[j];
					m_WaterBounds += vertex.m_Position;

					// NB: Usually this factor is view dependent, but for performance reasons
					// we do not take it into account with basic non-shader based water.
					// Average constant Fresnel effect for non-fancy water
					float alpha = clamp(depth / WaterMgr->m_WaterFullDepth + WaterMgr->m_WaterAlphaOffset, WaterMgr->m_WaterAlphaOffset, WaterMgr->m_WaterMaxAlpha);

					// Split the depth data across 24 bits, so the fancy-water shader can reconstruct
					// the depth value while the simple-water can just use the precomputed alpha
					float depthInt = floor(depth);
					float depthFrac = depth - depthInt;
					vertex.m_DepthData = SColor4ub(
						u8(clamp(depthInt, 0.0f, 255.0f)),
						u8(clamp(-depthInt, 0.0f, 255.0f)),
						u8(clamp(depthFrac*255.0f, 0.0f, 255.0f)),
						u8(clamp(alpha*255.0f, 0.0f, 255.0f)));

					int tx = x+x1;
					int ty = z+z1 + j*water_cell_size;

					if (g_AtlasGameLoop->running)
					{
						// currently no foam is used so push whatever
						vertex.m_WaterData = CVector4D(0.0f,0.0f,0.0f,0.0f);
					}
					else
					{
						vertex.m_WaterData = CVector4D(WaterMgr->m_WaveX[tx + ty*mapSize],
												   WaterMgr->m_WaveZ[tx + ty*mapSize],
												   WaterMgr->m_DistanceToShore[tx + ty*mapSize],
												   WaterMgr->m_FoamFactor[tx + ty*mapSize]);
					}
					water_index_map[z+j*water_cell_size][x] = water_vertex_data.size();
					water_vertex_data.push_back(vertex);
				}

				// If this was not the first x in the strip, then add a quad
				// using the computed vertex data

				if (x <= stripStart)
					continue;

				water_indices.push_back(water_index_map[z + water_cell_size][x - water_cell_size]);
				water_indices.push_back(water_index_map[z][x - water_cell_size]);
				water_indices.push_back(water_index_map[z][x]);
				water_indices.push_back(water_index_map[z + water_cell_size][x]);
			}
		}
	}

	// no vertex buffers if no data generated
	if (water_indices.size() == 0)
		return;

	// allocate vertex buffer
	m_VBWater = g_VBMan.Allocate(sizeof(SWaterVertex), water_vertex_data.size(), GL_STATIC_DRAW, GL_ARRAY_BUFFER);
	m_VBWater->m_Owner->UpdateChunkVertices(m_VBWater, &water_vertex_data[0]);

	// Construct indices buffer
	m_VBWaterIndices = g_VBMan.Allocate(sizeof(GLushort), water_indices.size(), GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER);
	m_VBWaterIndices->m_Owner->UpdateChunkVertices(m_VBWaterIndices, &water_indices[0]);
}