Ejemplo n.º 1
0
void CMiniMap::SetCameraPos()
{
	CTerrain* terrain = g_Game->GetWorld()->GetTerrain();

	CVector3D target;
	GetMouseWorldCoordinates(target.X, target.Z);
	target.Y = terrain->GetExactGroundLevel(target.X, target.Z);
	g_Game->GetView()->MoveCameraTarget(target);
}
Ejemplo n.º 2
0
///////////////////////////////////////////////////////////////////
// Calculate The blurred normal map to get an idea of where water ought to go.
void WaterManager::RecomputeBlurredNormalMap()
{
	// used to cache terrain normals since otherwise we'd recalculate them a lot (I'm blurring the "normal" map).
	// this might be updated to actually cache in the terrain manager but that's not for now.
	if (m_BlurredNormalMap == NULL)
		m_BlurredNormalMap = new CVector3D[m_MapSize*m_MapSize];

	CTerrain* terrain = g_Game->GetWorld()->GetTerrain();
	
	// It's really slow to calculate normals so cache them first.
	CVector3D* normals = new CVector3D[m_MapSize*m_MapSize];
	
	// Not the edges, we won't care about them.
	float ii = 8.0f, jj = 8.0f;
	for (size_t j = 2; j < m_MapSize-2; ++j, jj += 4.0f)
		for (size_t i = 2; i < m_MapSize-2; ++i, ii += 4.0f)
		{
			CVector3D norm;
			terrain->CalcNormal(i,j,norm);
			normals[j*m_MapSize + i] = norm;
		}
	
	// We could be way fancier (and faster) for our blur but we probably don't need the complexity.
	// Two pass filter, nothing complicated here.
	CVector3D blurValue;
	ii = 8.0f; jj = 8.0f;
	size_t idx = 2;
	for (size_t j = 2; j < m_MapSize-2; ++j, jj += 4.0f)
		for (size_t i = 2; i < m_MapSize-2; ++i, ii += 4.0f,++idx)
		{
			blurValue = normals[idx-2];
			blurValue += normals[idx-1];
			blurValue += normals[idx];
			blurValue += normals[idx+1];
			blurValue += normals[idx+2];
			m_BlurredNormalMap[idx] = blurValue * 0.2f;
		}
	// y direction, probably slower because of cache misses but I don't see an easy way around that.
	ii = 8.0f; jj = 8.0f;
	for (size_t i = 2; i < m_MapSize-2; ++i, ii += 4.0f)
	{
		for (size_t j = 2; j < m_MapSize-2; ++j, jj += 4.0f)
		{
			blurValue = normals[(j-2)*m_MapSize + i];
			blurValue += normals[(j-1)*m_MapSize + i];
			blurValue += normals[j*m_MapSize + i];
			blurValue += normals[(j+1)*m_MapSize + i];
			blurValue += normals[(j+2)*m_MapSize + i];
			m_BlurredNormalMap[j*m_MapSize + i] = blurValue * 0.2f;
		}
	}
	
	delete[] normals;
}
Ejemplo n.º 3
0
//--------------------------------------------------------------------------------------
// RenderTerrain
//--------------------------------------------------------------------------------------
void RenderTerrain( ID3D10Device* pd3dDevice )
{
    D3DXMATRIX mWorld;
    D3DXMatrixIdentity( &mWorld );

    D3DXVECTOR3 vEye;
    D3DXVECTOR3 vDir;
    D3DXMATRIX mCamWorld;
    D3DXMATRIX mView;
    D3DXMATRIX mProj;
    GetCameraData( &mCamWorld, &mView, &mProj, &vEye, &vDir );
    D3DXMATRIX mWVP = mCamWorld * mView * mProj;

    pd3dDevice->IASetInputLayout( g_pBasicDecl10 );

    g_pmWorldViewProj->SetMatrix( ( float* )&mWVP );
    g_pmWorld->SetMatrix( ( float* )&mWorld );

    g_ptxNormal->SetResource( g_pNormalTexRV );
    g_ptxDirt->SetResource( g_pDirtTexRV );
    g_ptxGrass->SetResource( g_pGroundGrassTexRV );
    g_ptxMask->SetResource( g_pMaskTexRV );

    if( !g_bShowTiles )
    {
        D3DXVECTOR4 color( 1,1,1,1 );
        g_pvColor->SetFloatVector( ( float* )&color );
    }

    pd3dDevice->IASetIndexBuffer( g_Terrain.GetTerrainIB10(), DXGI_FORMAT_R16_UINT, 0 );

    D3D10_TECHNIQUE_DESC techDesc;
    g_pRenderTerrain->GetDesc( &techDesc );

    for( UINT p = 0; p < techDesc.Passes; ++p )
    {
        // Render front to back
        UINT NumTiles = g_VisibleTileArray.GetSize();
        SetNumVisibleTiles( NumTiles );
        for( UINT i = 0; i < NumTiles; i++ )
        {
            TERRAIN_TILE* pTile = g_Terrain.GetTile( g_VisibleTileArray.GetAt( i ) );

            if( g_bShowTiles )
            {
                g_pvColor->SetFloatVector( ( float* )&pTile->Color );
            }
            g_pRenderTerrain->GetPassByIndex( p )->Apply( 0 );

            g_Terrain.RenderTile( pTile );
        }
    }
}
Ejemplo n.º 4
0
//--------------------------------------------------------------------------------------
// Release D3D9 resources created in the OnD3D9CreateDevice callback 
//--------------------------------------------------------------------------------------
void CALLBACK OnD3D10DestroyDevice( void* pUserContext )
{
    g_DialogResourceManager.OnD3D10DestroyDevice();
    g_SettingsDlg.OnD3D10DestroyDevice();
    DXUTGetGlobalResourceCache().OnDestroyDevice();

    g_Terrain.OnDestroyDevice();
    g_BallMesh.Destroy();
    g_SkyMesh.Destroy();

    SAFE_RELEASE( g_pFont10 );
    SAFE_RELEASE( g_pSprite10 );
    SAFE_DELETE( g_pTxtHelper );

    SAFE_RELEASE( g_pEffect10 );
    SAFE_RELEASE( g_pBasicDecl10 );
    SAFE_RELEASE( g_pBallDecl10 );
    SAFE_RELEASE( g_pGrassDecl10 );

    SAFE_RELEASE( g_pHeightTexRV );
    SAFE_RELEASE( g_pNormalTexRV );
    SAFE_RELEASE( g_pGrassTexRV );
    SAFE_RELEASE( g_pDirtTexRV );
    SAFE_RELEASE( g_pGroundGrassTexRV );
    SAFE_RELEASE( g_pMaskTexRV );
    SAFE_RELEASE( g_pShadeNormalTexRV );
    SAFE_RELEASE( g_pStreamDataVB10 );
    SAFE_RELEASE( g_pGrassDataVB10 );
}
Ejemplo n.º 5
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);
	}
}
Ejemplo n.º 6
0
//--------------------------------------------------------------------------------------
// RenderGrass
//--------------------------------------------------------------------------------------
void RenderGrass( ID3D10Device* pd3dDevice )
{
    D3DXMATRIX mWorld;
    D3DXMatrixIdentity( &mWorld );

    D3DXVECTOR3 vEye;
    D3DXVECTOR3 vDir;
    D3DXMATRIX mCamWorld;
    D3DXMATRIX mView;
    D3DXMATRIX mProj;
    GetCameraData( &mCamWorld, &mView, &mProj, &vEye, &vDir );
    D3DXMATRIX mWVP = mCamWorld * mView * mProj;

    // set vb streams
    ID3D10Buffer* pBuffers[1];
    pBuffers[0] = g_pGrassDataVB10;
    UINT strides[1];
    strides[0] = sizeof( D3DXVECTOR3 );
    UINT offsets[1] = {0};
    pd3dDevice->IASetVertexBuffers( 1, 1, pBuffers, strides, offsets );

    SetNumVisibleGrassTiles( g_NumGrassTiles );

    // set effect variables
    g_pmWorldViewProj->SetMatrix( ( float* )&mWVP );
    g_pfWorldScale->SetFloat( g_fWorldScale );
    g_pfHeightScale->SetFloat( g_fHeightScale );
    D3DXVECTOR4 vEye4( vEye, 1 );
    g_pvEyePt->SetFloatVector( ( float* )&vEye4 );
    g_pfFadeStart->SetFloat( g_fFadeStart );
    g_pfFadeEnd->SetFloat( g_fFadeEnd );

    g_ptxDiffuse->SetResource( g_pGrassTexRV );
    g_ptxHeight->SetResource( g_pHeightTexRV );
    g_ptxMask->SetResource( g_pMaskTexRV );
    g_ptxShadeNormals->SetResource( g_pShadeNormalTexRV );

    ID3D10EffectTechnique* pTechnique = g_pRenderGrass;

    pd3dDevice->IASetInputLayout( g_pGrassDecl10 );

    D3D10_TECHNIQUE_DESC techDesc;
    pTechnique->GetDesc( &techDesc );

    for( UINT p = 0; p < techDesc.Passes; p++ )
    {
        pTechnique->GetPassByIndex( p )->Apply( 0 );

        g_Terrain.RenderGrass( &vDir, g_NumGrassTiles );
    }

    pBuffers[0] = NULL;
    pd3dDevice->IASetVertexBuffers( 1, 1, pBuffers, strides, offsets );
}
Ejemplo n.º 7
0
void CPythonMiniMap::SetCenterPosition(float fCenterX, float fCenterY)
{
	m_fCenterX = fCenterX;
	m_fCenterY = fCenterY;

	CMapOutdoor& rkMap = CPythonBackground::Instance().GetMapOutdoorRef();
	for (BYTE byTerrainNum = 0; byTerrainNum < AROUND_AREA_NUM; ++byTerrainNum)
	{
		m_lpMiniMapTexture[byTerrainNum] = NULL;
		CTerrain * pTerrain;
		if (rkMap.GetTerrainPointer(byTerrainNum, &pTerrain))
			m_lpMiniMapTexture[byTerrainNum] = pTerrain->GetMiniMapTexture();
	}

	const TOutdoorMapCoordinate & rOutdoorMapCoord = rkMap.GetCurCoordinate();

	m_fCenterCellX = (m_fCenterX - (float)(rOutdoorMapCoord.m_sTerrainCoordX * CTerrainImpl::TERRAIN_XSIZE)) / (float)(CTerrainImpl::CELLSCALE);
	m_fCenterCellY = (m_fCenterY - (float)(rOutdoorMapCoord.m_sTerrainCoordY * CTerrainImpl::TERRAIN_YSIZE)) / (float)(CTerrainImpl::CELLSCALE);

	__SetPosition();
}
Ejemplo n.º 8
0
void CGameView::CheckLightEnv()
{
	if (m->CachedLightEnv == g_LightEnv)
		return;

	if (m->CachedLightEnv.GetLightingModel() != g_LightEnv.GetLightingModel())
		g_Renderer.MakeShadersDirty();

	m->CachedLightEnv = g_LightEnv;
	CTerrain* pTerrain = m->Game->GetWorld()->GetTerrain();

	if (!pTerrain)
		return;

	PROFILE("update light env");
	pTerrain->MakeDirty(RENDERDATA_UPDATE_COLOR);

	const std::vector<CUnit*>& units = m->Game->GetWorld()->GetUnitManager().GetUnits();
	for (size_t i = 0; i < units.size(); ++i)
		units[i]->GetModel().SetDirtyRec(RENDERDATA_UPDATE_COLOR);
}
Ejemplo n.º 9
0
void TerrainTextureOverlay::RenderAfterWater()
{
	CTerrain* terrain = g_Game->GetWorld()->GetTerrain();

	ssize_t w = (ssize_t)(terrain->GetTilesPerSide() * m_TexelsPerTile);
	ssize_t h = (ssize_t)(terrain->GetTilesPerSide() * m_TexelsPerTile);

	pglActiveTextureARB(GL_TEXTURE0);

	// Recreate the texture with new size if necessary
	if (round_up_to_pow2(w) != m_TextureW || round_up_to_pow2(h) != m_TextureH)
	{
		m_TextureW = round_up_to_pow2(w);
		m_TextureH = round_up_to_pow2(h);

		glBindTexture(GL_TEXTURE_2D, m_Texture);
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_TextureW, m_TextureH, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);

		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	}

	u8* data = (u8*)calloc(w * h, 4);
	BuildTextureRGBA(data, w, h);

	glBindTexture(GL_TEXTURE_2D, m_Texture);
	glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, data);

	free(data);

	CMatrix3D matrix;
	matrix.SetZero();
	matrix._11 = m_TexelsPerTile / (m_TextureW * TERRAIN_TILE_SIZE);
	matrix._23 = m_TexelsPerTile / (m_TextureH * TERRAIN_TILE_SIZE);
	matrix._44 = 1;

	g_Renderer.GetTerrainRenderer().RenderTerrainOverlayTexture(matrix);
}
Ejemplo n.º 10
0
float CMenuMarcher::FindHoverHeight(Vector vecPosition) const
{
	CTerrain* pTerrain = DigitanksGame()->GetTerrain();

	float flHighestTerrain = pTerrain->GetHeight(vecPosition.x, vecPosition.y);

	float flTerrain;

	flTerrain = pTerrain->GetHeight(vecPosition.x+2, vecPosition.y+2);
	if (flTerrain > flHighestTerrain)
		flHighestTerrain = flTerrain;

	flTerrain = pTerrain->GetHeight(vecPosition.x+2, vecPosition.y-2);
	if (flTerrain > flHighestTerrain)
		flHighestTerrain = flTerrain;

	flTerrain = pTerrain->GetHeight(vecPosition.x-2, vecPosition.y+2);
	if (flTerrain > flHighestTerrain)
		flHighestTerrain = flTerrain;

	flTerrain = pTerrain->GetHeight(vecPosition.x-2, vecPosition.y-2);
	if (flTerrain > flHighestTerrain)
		flHighestTerrain = flTerrain;

	return flHighestTerrain;
}
Ejemplo n.º 11
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
}
Ejemplo n.º 12
0
float CDigitanksEntity::GetVisibility(CDigitanksPlayer* pPlayer) const
{
	CDigitanksGame* pGame = DigitanksGame();

	CTerrain* pTerrain = pGame->GetTerrain();

	float flConceal = 0.0f;
	if (GetsConcealmentBonus() && pTerrain)
	{
		if (pTerrain->GetBit(CTerrain::WorldToArraySpace(GetGlobalOrigin().x), CTerrain::WorldToArraySpace(GetGlobalOrigin().y), TB_TREE))
			flConceal = 0.7f;
	}

	float flCloak = GetCloakConcealment();
	if (flCloak > flConceal)
		flConceal = flCloak;

	if (HasLostConcealment())
		flConceal = 0;

	if (pPlayer && pPlayer == GetDigitanksPlayer())
		return 1 - flConceal/2;

	if (!pGame->ShouldRenderFogOfWar())
	{
		if (pPlayer && pPlayer->IsHumanControlled())
			return 1 - flConceal;
	}

	if (!pPlayer)
		return 0;

	float flVisibility = pPlayer->GetEntityVisibility(GetHandle()) - flConceal;

	if (flVisibility < 0)
		return 0;

	return flVisibility;
}
Ejemplo n.º 13
0
///////////////////////////////////////////////////////////////////
// Calculate our binary heightmap from the terrain heightmap.
void WaterManager::RecomputeDistanceHeightmap()
{
	size_t SideSize = m_MapSize*2;
	if (m_DistanceHeightmap == NULL)
		m_DistanceHeightmap = new float[SideSize*SideSize];
		
	CTerrain* terrain = g_Game->GetWorld()->GetTerrain();
	
	// Create a manhattan-distance heightmap.
	// This is currently upsampled by a factor of 2 to get more precision
	// This could be refined to only be done near the coast itself, but it's probably not necessary.
	
	for (size_t z = 0; z < SideSize; ++z)
	{
		float level = SideSize;
		for (size_t x = 0; x < SideSize; ++x)
			m_DistanceHeightmap[z*SideSize + x] = terrain->GetExactGroundLevel(x*2, z*2) >= m_WaterHeight ? level = 0.f : ++level;
		level = SideSize;
		for (size_t x = SideSize-1; x != (size_t)-1; --x)
		{
			if (terrain->GetExactGroundLevel(x*2, z*2) >= m_WaterHeight)
				level = 0.f;
			else
			{
				++level;
				if (level < m_DistanceHeightmap[z*SideSize + x])
					m_DistanceHeightmap[z*SideSize + x] = level;
			}
		}
	}
	for (size_t x = 0; x < SideSize; ++x)
	{
		float level = SideSize;
		for (size_t z = 0; z < SideSize; ++z)
		{
			if (terrain->GetExactGroundLevel(x*2, z*2) >= m_WaterHeight)
				level = 0.f;
			else if (level > m_DistanceHeightmap[z*SideSize + x])
				level = m_DistanceHeightmap[z*SideSize + x];
			else
			{
				++level;
				if (level < m_DistanceHeightmap[z*SideSize + x])
					m_DistanceHeightmap[z*SideSize + x] = level;
			}
		}
		level = SideSize;
		for (size_t z = SideSize-1; z != (size_t)-1; --z)
		{
			if (terrain->GetExactGroundLevel(x*2, z*2) >= m_WaterHeight)
				level = 0.f;
			else if (level > m_DistanceHeightmap[z*SideSize + x])
				level = m_DistanceHeightmap[z*SideSize + x];
			else
			{
				++level;
				if (level < m_DistanceHeightmap[z*SideSize + x])
					m_DistanceHeightmap[z*SideSize + x] = level;
			}
		}
	}
}
Ejemplo n.º 14
0
///////////////////////////////////////////////////////////////////
// Calculate the strength of the wind at a given point on the map.
// This is too slow and should support limited recomputation.
void WaterManager::RecomputeWindStrength()
{
	if (m_WindStrength == NULL)
		m_WindStrength = new float[m_MapSize*m_MapSize];
		
	CTerrain* terrain = g_Game->GetWorld()->GetTerrain();
	float waterLevel = m_WaterHeight;
	
	CVector2D windDir = CVector2D(cos(m_WindAngle),sin(m_WindAngle));
	CVector2D perp = CVector2D(-windDir.Y, windDir.X);

	// Our kernel will sample 5 points going towards the wind (generally).
	int kernel[5][2] = { {(int)windDir.X*2,(int)windDir.Y*2}, {(int)windDir.X*5,(int)windDir.Y*5}, {(int)windDir.X*9,(int)windDir.Y*9}, {(int)windDir.X*16,(int)windDir.Y*16}, {(int)windDir.X*25,(int)windDir.Y*25} };
	
	float* Temp = new float[m_MapSize*m_MapSize];
	std::fill(Temp, Temp + m_MapSize*m_MapSize, 1.0f);

	for (size_t j = 0; j < m_MapSize; ++j)
		for (size_t i = 0; i < m_MapSize; ++i)
		{
			float curHeight = terrain->GetVertexGroundLevel(i,j);
			if (curHeight >= waterLevel)
			{
				Temp[j*m_MapSize + i] = 0.3f;	// blurs too strong otherwise
				continue;
			}
			if (terrain->GetVertexGroundLevel(i + ceil(windDir.X),j + ceil(windDir.Y)) < waterLevel)
				continue;
			
			// Calculate how dampened our waves should be.
			float tendency = 0.0f;
			float oldHeight = std::max(waterLevel,terrain->GetVertexGroundLevel(i+kernel[4][0],j+kernel[4][1]));
			float currentHeight = std::max(waterLevel,terrain->GetVertexGroundLevel(i+kernel[3][0],j+kernel[3][1]));
			float avgheight = oldHeight + currentHeight;
			tendency = currentHeight - oldHeight;
			oldHeight = currentHeight;
			currentHeight = std::max(waterLevel,terrain->GetVertexGroundLevel(i+kernel[2][0],j+kernel[2][1]));
			avgheight += currentHeight;
			tendency += currentHeight - oldHeight;
			oldHeight = currentHeight;
			currentHeight = std::max(waterLevel,terrain->GetVertexGroundLevel(i+kernel[1][0],j+kernel[1][1]));
			avgheight += currentHeight;
			tendency += currentHeight - oldHeight;
			oldHeight = currentHeight;
			currentHeight = std::max(waterLevel,terrain->GetVertexGroundLevel(i+kernel[0][0],j+kernel[0][1]));
			avgheight += currentHeight;
			tendency += currentHeight - oldHeight;
			
			float baseLevel = std::max(0.0f,1.0f - (avgheight/5.0f-waterLevel)/20.0f);
			baseLevel *= baseLevel;
			tendency /= 15.0f;
			baseLevel -= tendency;	// if the terrain was sloping downwards, increase baselevel. Otherwise reduce.
			baseLevel = clamp(baseLevel,0.0f,1.0f);
			
			// Draw on map. This is pretty slow.
			float length = 35.0f * (1.0f-baseLevel/1.8f);
			for (float y = 0; y < length; y += 0.6f)
				{
					int xx = clamp(i - y * windDir.X,0.0f,(float)(m_MapSize-1));
					int yy = clamp(j - y * windDir.Y,0.0f,(float)(m_MapSize-1));
					Temp[yy*m_MapSize + xx] = Temp[yy*m_MapSize + xx] < (0.0f+baseLevel/1.5f) * (1.0f-y/length) + y/length * 1.0f ?
												Temp[yy*m_MapSize + xx] : (0.0f+baseLevel/1.5f) * (1.0f-y/length) + y/length * 1.0f;
				}
		}
	
	int blurKernel[4][2] = { {(int)ceil(windDir.X),(int)ceil(windDir.Y)}, {(int)windDir.X*3,(int)windDir.Y*3}, {(int)ceil(perp.X),(int)ceil(perp.Y)}, {(int)-ceil(perp.X),(int)-ceil(perp.Y)} };
	float blurValue;
	for (size_t j = 2; j < m_MapSize-2; ++j)
		for (size_t i = 2; i < m_MapSize-2; ++i)
		{
			blurValue = Temp[(j+blurKernel[0][1])*m_MapSize + i+blurKernel[0][0]];
			blurValue += Temp[(j+blurKernel[0][1])*m_MapSize + i+blurKernel[0][0]];
			blurValue += Temp[(j+blurKernel[0][1])*m_MapSize + i+blurKernel[0][0]];
			blurValue += Temp[(j+blurKernel[0][1])*m_MapSize + i+blurKernel[0][0]];
			m_WindStrength[j*m_MapSize + i] = blurValue * 0.25f;
		}
	delete[] Temp;
}
Ejemplo n.º 15
0
void CGameView::Update(const float deltaRealTime)
{
	// If camera movement is being handled by the touch-input system,
	// then we should stop to avoid conflicting with it
	if (g_TouchInput.IsEnabled())
		return;

	if (!g_app_has_focus)
		return;

	// TODO: this is probably not an ideal place for this, it should probably go
	// in a CCmpWaterManager or some such thing (once such a thing exists)
	if (!m->Game->m_Paused)
		g_Renderer.GetWaterManager()->m_WaterTexTimer += deltaRealTime;

	if (m->TrackManager.IsActive() && m->TrackManager.IsPlaying())
	{
		if (! m->TrackManager.Update(deltaRealTime))
		{
//			ResetCamera();
		}
		return;
	}

	// Calculate mouse movement
	static int mouse_last_x = 0;
	static int mouse_last_y = 0;
	int mouse_dx = g_mouse_x - mouse_last_x;
	int mouse_dy = g_mouse_y - mouse_last_y;
	mouse_last_x = g_mouse_x;
	mouse_last_y = g_mouse_y;

	if (HotkeyIsPressed("camera.rotate.cw"))
		m->RotateY.AddSmoothly(m->ViewRotateYSpeed * deltaRealTime);
	if (HotkeyIsPressed("camera.rotate.ccw"))
		m->RotateY.AddSmoothly(-m->ViewRotateYSpeed * deltaRealTime);
	if (HotkeyIsPressed("camera.rotate.up"))
		m->RotateX.AddSmoothly(-m->ViewRotateXSpeed * deltaRealTime);
	if (HotkeyIsPressed("camera.rotate.down"))
		m->RotateX.AddSmoothly(m->ViewRotateXSpeed * deltaRealTime);

	float moveRightward = 0.f;
	float moveForward = 0.f;

	if (HotkeyIsPressed("camera.pan"))
	{
		moveRightward += m->ViewDragSpeed * mouse_dx;
		moveForward += m->ViewDragSpeed * -mouse_dy;
	}

	if (g_mouse_active)
	{
		if (g_mouse_x >= g_xres - 2 && g_mouse_x < g_xres)
			moveRightward += m->ViewScrollSpeed * deltaRealTime;
		else if (g_mouse_x <= 3 && g_mouse_x >= 0)
			moveRightward -= m->ViewScrollSpeed * deltaRealTime;

		if (g_mouse_y >= g_yres - 2 && g_mouse_y < g_yres)
			moveForward -= m->ViewScrollSpeed * deltaRealTime;
		else if (g_mouse_y <= 3 && g_mouse_y >= 0)
			moveForward += m->ViewScrollSpeed * deltaRealTime;
	}

	if (HotkeyIsPressed("camera.right"))
		moveRightward += m->ViewScrollSpeed * deltaRealTime;
	if (HotkeyIsPressed("camera.left"))
		moveRightward -= m->ViewScrollSpeed * deltaRealTime;
	if (HotkeyIsPressed("camera.up"))
		moveForward += m->ViewScrollSpeed * deltaRealTime;
	if (HotkeyIsPressed("camera.down"))
		moveForward -= m->ViewScrollSpeed * deltaRealTime;

	if (g_Joystick.IsEnabled())
	{
		// This could all be improved with extra speed and sensitivity settings
		// (maybe use pow to allow finer control?), and inversion settings

		moveRightward += g_Joystick.GetAxisValue(m->JoystickPanX) * m->ViewScrollSpeed * deltaRealTime;
		moveForward -= g_Joystick.GetAxisValue(m->JoystickPanY) * m->ViewScrollSpeed * deltaRealTime;

		m->RotateX.AddSmoothly(g_Joystick.GetAxisValue(m->JoystickRotateX) * m->ViewRotateXSpeed * deltaRealTime);
		m->RotateY.AddSmoothly(-g_Joystick.GetAxisValue(m->JoystickRotateY) * m->ViewRotateYSpeed * deltaRealTime);

		// Use a +1 bias for zoom because I want this to work with trigger buttons that default to -1
		m->Zoom.AddSmoothly((g_Joystick.GetAxisValue(m->JoystickZoomIn) + 1.0f) / 2.0f * m->ViewZoomSpeed * deltaRealTime);
		m->Zoom.AddSmoothly(-(g_Joystick.GetAxisValue(m->JoystickZoomOut) + 1.0f) / 2.0f * m->ViewZoomSpeed * deltaRealTime);
	}

	if (moveRightward || moveForward)
	{
		// Break out of following mode when the user starts scrolling
		m->FollowEntity = INVALID_ENTITY;

		float s = sin(m->RotateY.GetSmoothedValue());
		float c = cos(m->RotateY.GetSmoothedValue());
		m->PosX.AddSmoothly(c * moveRightward);
		m->PosZ.AddSmoothly(-s * moveRightward);
		m->PosX.AddSmoothly(s * moveForward);
		m->PosZ.AddSmoothly(c * moveForward);
	}

	if (m->FollowEntity)
	{
		CmpPtr<ICmpPosition> cmpPosition(*(m->Game->GetSimulation2()), m->FollowEntity);
		if (cmpPosition && cmpPosition->IsInWorld())
		{
			// Get the most recent interpolated position
			float frameOffset = m->Game->GetSimulation2()->GetLastFrameOffset();
			CMatrix3D transform = cmpPosition->GetInterpolatedTransform(frameOffset, false);
			CVector3D pos = transform.GetTranslation();

			if (m->FollowFirstPerson)
			{
				float x, z, angle;
				cmpPosition->GetInterpolatedPosition2D(frameOffset, x, z, angle);
				float height = 4.f;
				m->ViewCamera.m_Orientation.SetIdentity();
				m->ViewCamera.m_Orientation.RotateX((float)M_PI/24.f);
				m->ViewCamera.m_Orientation.RotateY(angle);
				m->ViewCamera.m_Orientation.Translate(pos.X, pos.Y + height, pos.Z);

				m->ViewCamera.UpdateFrustum();
				return;
			}
			else
			{
				// Move the camera to match the unit
				CCamera targetCam = m->ViewCamera;
				SetupCameraMatrixSmoothRot(m, &targetCam.m_Orientation);

				CVector3D pivot = GetSmoothPivot(targetCam);
				CVector3D delta = pos - pivot;
				m->PosX.AddSmoothly(delta.X);
				m->PosY.AddSmoothly(delta.Y);
				m->PosZ.AddSmoothly(delta.Z);
			}
		}
		else
		{
			// The unit disappeared (died or garrisoned etc), so stop following it
			m->FollowEntity = INVALID_ENTITY;
		}
	}

	if (HotkeyIsPressed("camera.zoom.in"))
		m->Zoom.AddSmoothly(-m->ViewZoomSpeed * deltaRealTime);
	if (HotkeyIsPressed("camera.zoom.out"))
		m->Zoom.AddSmoothly(m->ViewZoomSpeed * deltaRealTime);

	if (m->ConstrainCamera)
		m->Zoom.ClampSmoothly(m->ViewZoomMin, m->ViewZoomMax);

	float zoomDelta = -m->Zoom.Update(deltaRealTime);
	if (zoomDelta)
	{
		CVector3D forwards = m->ViewCamera.m_Orientation.GetIn();
		m->PosX.AddSmoothly(forwards.X * zoomDelta);
		m->PosY.AddSmoothly(forwards.Y * zoomDelta);
		m->PosZ.AddSmoothly(forwards.Z * zoomDelta);
	}

	if (m->ConstrainCamera)
		m->RotateX.ClampSmoothly(DEGTORAD(m->ViewRotateXMin), DEGTORAD(m->ViewRotateXMax));

	FocusHeight(m, true);

	// Ensure the ViewCamera focus is inside the map with the chosen margins
	// if not so - apply margins to the camera
	if (m->ConstrainCamera)
	{
		CCamera targetCam = m->ViewCamera;
		SetupCameraMatrixSmoothRot(m, &targetCam.m_Orientation);

		CTerrain* pTerrain = m->Game->GetWorld()->GetTerrain();

		CVector3D pivot = GetSmoothPivot(targetCam);
		CVector3D delta = targetCam.m_Orientation.GetTranslation() - pivot;

		CVector3D desiredPivot = pivot;

		CmpPtr<ICmpRangeManager> cmpRangeManager(*m->Game->GetSimulation2(), SYSTEM_ENTITY);
		if (cmpRangeManager && cmpRangeManager->GetLosCircular())
		{
			// Clamp to a circular region around the center of the map
			float r = pTerrain->GetMaxX() / 2;
			CVector3D center(r, desiredPivot.Y, r);
			float dist = (desiredPivot - center).Length();
			if (dist > r - CAMERA_EDGE_MARGIN)
				desiredPivot = center + (desiredPivot - center).Normalized() * (r - CAMERA_EDGE_MARGIN);
		}
		else
		{
			// Clamp to the square edges of the map
			desiredPivot.X = Clamp(desiredPivot.X, pTerrain->GetMinX() + CAMERA_EDGE_MARGIN, pTerrain->GetMaxX() - CAMERA_EDGE_MARGIN);
			desiredPivot.Z = Clamp(desiredPivot.Z, pTerrain->GetMinZ() + CAMERA_EDGE_MARGIN, pTerrain->GetMaxZ() - CAMERA_EDGE_MARGIN);
		}

		// Update the position so that pivot is within the margin
		m->PosX.SetValueSmoothly(desiredPivot.X + delta.X);
		m->PosZ.SetValueSmoothly(desiredPivot.Z + delta.Z);
	}

	m->PosX.Update(deltaRealTime);
	m->PosY.Update(deltaRealTime);
	m->PosZ.Update(deltaRealTime);

	// Handle rotation around the Y (vertical) axis
	{
		CCamera targetCam = m->ViewCamera;
		SetupCameraMatrixSmooth(m, &targetCam.m_Orientation);

		float rotateYDelta = m->RotateY.Update(deltaRealTime);
		if (rotateYDelta)
		{
			// We've updated RotateY, and need to adjust Pos so that it's still
			// facing towards the original focus point (the terrain in the center
			// of the screen).

			CVector3D upwards(0.0f, 1.0f, 0.0f);

			CVector3D pivot = GetSmoothPivot(targetCam);
			CVector3D delta = targetCam.m_Orientation.GetTranslation() - pivot;

			CQuaternion q;
			q.FromAxisAngle(upwards, rotateYDelta);
			CVector3D d = q.Rotate(delta) - delta;

			m->PosX.Add(d.X);
			m->PosY.Add(d.Y);
			m->PosZ.Add(d.Z);
		}
	}

	// Handle rotation around the X (sideways, relative to camera) axis
	{
		CCamera targetCam = m->ViewCamera;
		SetupCameraMatrixSmooth(m, &targetCam.m_Orientation);

		float rotateXDelta = m->RotateX.Update(deltaRealTime);
		if (rotateXDelta)
		{
			CVector3D rightwards = targetCam.m_Orientation.GetLeft() * -1.0f;

			CVector3D pivot = GetSmoothPivot(targetCam);
			CVector3D delta = targetCam.m_Orientation.GetTranslation() - pivot;

			CQuaternion q;
			q.FromAxisAngle(rightwards, rotateXDelta);
			CVector3D d = q.Rotate(delta) - delta;

			m->PosX.Add(d.X);
			m->PosY.Add(d.Y);
			m->PosZ.Add(d.Z);
		}
	}

	/* This is disabled since it doesn't seem necessary:

	// Ensure the camera's near point is never inside the terrain
	if (m->ConstrainCamera)
	{
		CMatrix3D target;
		target.SetIdentity();
		target.RotateX(m->RotateX.GetValue());
		target.RotateY(m->RotateY.GetValue());
		target.Translate(m->PosX.GetValue(), m->PosY.GetValue(), m->PosZ.GetValue());

		CVector3D nearPoint = target.GetTranslation() + target.GetIn() * defaultNear;
		float ground = m->Game->GetWorld()->GetTerrain()->GetExactGroundLevel(nearPoint.X, nearPoint.Z);
		float limit = ground + 16.f;
		if (nearPoint.Y < limit)
			m->PosY.AddSmoothly(limit - nearPoint.Y);
	}
	*/

	m->RotateY.Wrap(-(float)M_PI, (float)M_PI);

	// Update the camera matrix
	m->ViewCamera.SetProjection(m->ViewNear, m->ViewFar, m->ViewFOV);
	SetupCameraMatrixSmooth(m, &m->ViewCamera.m_Orientation);
	m->ViewCamera.UpdateFrustum();
}
Ejemplo n.º 16
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]);
}
Ejemplo n.º 17
0
///////////////////////////////////////////////////////////
// This callback is part of the Scene interface
// Submit all objects visible in the given frustum
void CGameView::EnumerateObjects(const CFrustum& frustum, SceneCollector* c)
{
	{
	PROFILE3("submit terrain");

	CTerrain* pTerrain = m->Game->GetWorld()->GetTerrain();
	const ssize_t patchesPerSide = pTerrain->GetPatchesPerSide();

	// find out which patches will be drawn
	for (ssize_t j=0; j<patchesPerSide; j++) {
		for (ssize_t i=0; i<patchesPerSide; i++) {
			CPatch* patch=pTerrain->GetPatch(i,j);	// can't fail

			// If the patch is underwater, calculate a bounding box that also contains the water plane
			CBoundingBoxAligned bounds = patch->GetWorldBounds();
			float waterHeight = g_Renderer.GetWaterManager()->m_WaterHeight + 0.001f;
			if(bounds[1].Y < waterHeight) {
				bounds[1].Y = waterHeight;
			}

			if (!m->Culling || frustum.IsBoxVisible (CVector3D(0,0,0), bounds)) {
				//c->Submit(patch);

				// set the renderstate for this patch
				patch->setDrawState(true);

				// set the renderstate for the neighbors
				CPatch *nPatch;

				nPatch = pTerrain->GetPatch(i-1,j-1);
				if(nPatch) nPatch->setDrawState(true);

				nPatch = pTerrain->GetPatch(i,j-1);
				if(nPatch) nPatch->setDrawState(true);

				nPatch = pTerrain->GetPatch(i+1,j-1);
				if(nPatch) nPatch->setDrawState(true);

				nPatch = pTerrain->GetPatch(i-1,j);
				if(nPatch) nPatch->setDrawState(true);

				nPatch = pTerrain->GetPatch(i+1,j);
				if(nPatch) nPatch->setDrawState(true);

				nPatch = pTerrain->GetPatch(i-1,j+1);
				if(nPatch) nPatch->setDrawState(true);

				nPatch = pTerrain->GetPatch(i,j+1);
				if(nPatch) nPatch->setDrawState(true);

				nPatch = pTerrain->GetPatch(i+1,j+1);
				if(nPatch) nPatch->setDrawState(true);
			}
		}
	}

	// draw the patches
	for (ssize_t j=0; j<patchesPerSide; j++)
	{
		for (ssize_t i=0; i<patchesPerSide; i++)
		{
			CPatch* patch=pTerrain->GetPatch(i,j);	// can't fail
			if(patch->getDrawState() == true)
			{
				c->Submit(patch);
				patch->setDrawState(false);
			}
		}
	}
	}

	m->Game->GetSimulation2()->RenderSubmit(*c, frustum, m->Culling);
}
Ejemplo n.º 18
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);
	}
}
Ejemplo n.º 19
0
void CPatchRData::BuildBlends()
{
	PROFILE3("build blends");

	m_BlendSplats.clear();

	std::vector<SBlendVertex> blendVertices;
	std::vector<u16> blendIndices;

	CTerrain* terrain = m_Patch->m_Parent;

	std::vector<STileBlendStack> blendStacks;
	blendStacks.reserve(PATCH_SIZE*PATCH_SIZE);

	// For each tile in patch ..
	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;

			std::vector<STileBlend> blends;
			blends.reserve(9);

			// Compute a blend for every tile in the 3x3 square around this tile
			for (size_t n = 0; n < 9; ++n)
			{
				ssize_t ox = gx + BlendOffsets[n][1];
				ssize_t oz = gz + BlendOffsets[n][0];

				CMiniPatch* nmp = terrain->GetTile(ox, oz);
				if (!nmp)
					continue;

				STileBlend blend;
				blend.m_Texture = nmp->GetTextureEntry();
				blend.m_Priority = nmp->GetPriority();
				blend.m_TileMask = 1 << n;
				blends.push_back(blend);
			}

			// Sort the blends, highest priority first
			std::sort(blends.begin(), blends.end(), STileBlend::DecreasingPriority());

			STileBlendStack blendStack;
			blendStack.i = i;
			blendStack.j = j;

			// Put the blends into the tile's stack, merging any adjacent blends with the same texture
			for (size_t k = 0; k < blends.size(); ++k)
			{
				if (!blendStack.blends.empty() && blendStack.blends.back().m_Texture == blends[k].m_Texture)
					blendStack.blends.back().m_TileMask |= blends[k].m_TileMask;
				else
					blendStack.blends.push_back(blends[k]);
			}

			// Remove blends that are after (i.e. lower priority than) the current tile
			// (including the current tile), since we don't want to render them on top of
			// the tile's base texture
			blendStack.blends.erase(
				std::find_if(blendStack.blends.begin(), blendStack.blends.end(), STileBlend::CurrentTile()),
				blendStack.blends.end());

			blendStacks.push_back(blendStack);
		}
	}

	// Given the blend stack per tile, we want to batch together as many blends as possible.
	// Group them into a series of layers (each of which has a single texture):
	// (This is effectively a topological sort / linearisation of the partial order induced
	// by the per-tile stacks, preferring to make tiles with equal textures adjacent.)

	std::vector<SBlendLayer> blendLayers;

	while (true)
	{
		if (!blendLayers.empty())
		{
			// Try to grab as many tiles as possible that match our current layer,
			// from off the blend stacks of all the tiles

			CTerrainTextureEntry* tex = blendLayers.back().m_Texture;

			for (size_t k = 0; k < blendStacks.size(); ++k)
			{
				if (!blendStacks[k].blends.empty() && blendStacks[k].blends.back().m_Texture == tex)
				{
					SBlendLayer::Tile t = { blendStacks[k].i, blendStacks[k].j, blendStacks[k].blends.back().m_TileMask };
					blendLayers.back().m_Tiles.push_back(t);
					blendStacks[k].blends.pop_back();
				}
				// (We've already merged adjacent entries of the same texture in each stack,
				// so we don't need to bother looping to check the next entry in this stack again)
			}
		}

		// We've grabbed as many tiles as possible; now we need to start a new layer.
		// The new layer's texture could come from the back of any non-empty stack;
		// choose the longest stack as a heuristic to reduce the number of layers
		CTerrainTextureEntry* bestTex = NULL;
		size_t bestStackSize = 0;

		for (size_t k = 0; k < blendStacks.size(); ++k)
		{
			if (blendStacks[k].blends.size() > bestStackSize)
			{
				bestStackSize = blendStacks[k].blends.size();
				bestTex = blendStacks[k].blends.back().m_Texture;
			}
		}

		// If all our stacks were empty, we're done
		if (bestStackSize == 0)
			break;

		// Otherwise add the new layer, then loop back and start filling it in

		SBlendLayer layer;
		layer.m_Texture = bestTex;
		blendLayers.push_back(layer);
	}

	// Now build outgoing splats
	m_BlendSplats.resize(blendLayers.size());

	for (size_t k = 0; k < blendLayers.size(); ++k)
	{
		SSplat& splat = m_BlendSplats[k];
		splat.m_IndexStart = blendIndices.size();
		splat.m_Texture = blendLayers[k].m_Texture;

		for (size_t t = 0; t < blendLayers[k].m_Tiles.size(); ++t)
		{
			SBlendLayer::Tile& tile = blendLayers[k].m_Tiles[t];
			AddBlend(blendVertices, blendIndices, tile.i, tile.j, tile.shape, splat.m_Texture);
		}

		splat.m_IndexCount = blendIndices.size() - splat.m_IndexStart;
	}

	// Release existing vertex buffer chunks
	if (m_VBBlends)
	{
		g_VBMan.Release(m_VBBlends);
		m_VBBlends = 0;
	}

	if (m_VBBlendIndices)
	{
		g_VBMan.Release(m_VBBlendIndices);
		m_VBBlendIndices = 0;
	}

	if (blendVertices.size())
	{
		// Construct vertex buffer

		m_VBBlends = g_VBMan.Allocate(sizeof(SBlendVertex), blendVertices.size(), GL_STATIC_DRAW, GL_ARRAY_BUFFER);
		m_VBBlends->m_Owner->UpdateChunkVertices(m_VBBlends, &blendVertices[0]);

		// Update the indices to include the base offset of the vertex data
		for (size_t k = 0; k < blendIndices.size(); ++k)
			blendIndices[k] += m_VBBlends->m_Index;

		m_VBBlendIndices = g_VBMan.Allocate(sizeof(u16), blendIndices.size(), GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER);
		m_VBBlendIndices->m_Owner->UpdateChunkVertices(m_VBBlendIndices, &blendIndices[0]);
	}
}
Ejemplo n.º 20
0
//传入pcy为NULL表示释放资源
bool d3dbase::DrawBasicScene(CCourtyard* pcy,IDirect3DDevice9* device, float scale)	
{
	//定义需要用到的指针、变量
	static std::vector<sLitVertex> v;                                  //每个平面的最多顶点数
	static std::vector<IDirect3DTexture9*>      tex;                //平面的纹理


	static  ID3DXMesh*      pMesh[MaxObject];                        //模型
	static std::vector<D3DMATERIAL9>       Mtrls[MaxTexPerObj];      //组成模型的材质
	static std::vector<IDirect3DTexture9*> Textures[MaxTexPerObj];    //组成模型的纹理


	int i,j;
	static bool bfirst = true;

	static int nPolys = 0;      //平面数
	static int nObjs = 0;        //模型物体数
	static int nTerrain = 0; //地形数
	

	if( pcy == NULL&&bfirst == true)
	{
		return false;
	}

	//当传入参数pcy的值为NULL时,释放资源
	if(pcy == NULL && bfirst == false)
	{
		int i;

		//释放平面纹理
		for(i = 0; i<nPolys; i++)
		{
			Release<IDirect3DTexture9*>(tex[i]);
		}
		//释放模型
		for(i = 0; i<nObjs; i++)
		{
			Release<ID3DXMesh*>(pMesh[i]);
		}
		//释放地形
		for(i = 0; i<nTerrain; i++)
		{
			Delete<CTerrain*>(g_pTerrain[i]);
		}
		return false;
	}
	
	//如果使用纹理,设置混合方式	
	if( g_useTextures )
	{
		device->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
		device->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
		device->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_MODULATE );
	}
	
	D3DXMATRIX I;
	D3DXMatrixIdentity(&I);                   //产生单位矩阵
	device->SetTransform(D3DTS_WORLD, &I);    //设置世界坐标,调整作用
	

	nPolys = pcy->m_polyList.size();      //平面数
	nObjs = pcy->m_objList.size();        //模型物体数
	nTerrain = pcy->m_TerrainList.size(); //地形数

	
	D3DXVECTOR3 lightDirection(0.0f, 1.0f, 0.0f);         //创建平行光,创建地形时使用
	
   	//第一次运行:加载纹理图,模型,创建地形
	if(bfirst)
	{
		
		const char * ch;
		HRESULT hr;

		//若使用纹理,加载纹理图
		if(g_useTextures){
			IDirect3DTexture9* temttex = NULL;
			for( i=0; i<nPolys; i++ )
			{
				hr = D3DXCreateTextureFromFile(  //从文件创建纹理  tex
					device,
					ch = pcy->m_polyList[i].m_texfile.c_str(),
					&temttex);

				tex.push_back(temttex);

				if(FAILED(hr))
				{
					throw cGameError("create texture failed");
				}
				
			}
		}


		//加载模型
		for( i=0; i<nObjs; i++ )
		{
			
			if(LoadXFileMesh(&pMesh[i],pcy->m_objList[i].m_meshfile,device,Mtrls[i],Textures[i]) == false)
			{
				throw cGameError("create mesh failed");

			}

		}
	

		//创建、加载地形
		for( i=0; i<nTerrain; i++ )
		{
			CTerrain *pTer = NULL;
			D3DXVECTOR3 p(pcy->m_TerrainList[i].m_pos.x,pcy->m_TerrainList[i].m_pos.y,pcy->m_TerrainList[i].m_pos.z);
			pTer = new CTerrain(device,pcy->m_TerrainList[i].m_terrainfile,p,
				pcy->m_TerrainList[i].m_numVertsPerRow,pcy->m_TerrainList[i].m_numVertsPerCol,
				pcy->m_TerrainList[i].m_cellSpacing,pcy->m_TerrainList[i].m_heightScale);
			
			pTer->genTexture(&lightDirection);              ////创建纹理并根据每个位置的高度来设置其颜色(纹理颜色)

			g_pTerrain.push_back(pTer);
			
		}

		bfirst = false;
	}

	//设置绘画状态

	//使用镜面反射
	device->SetRenderState( D3DRS_SPECULARENABLE, TRUE );
	//自动法向量归一化
	device->SetRenderState(D3DRS_NORMALIZENORMALS, true);

	//开始画图
	//渲染平面
	for( i=0; i<nPolys; i++ )
	{
		
		
		
		if(g_useTextures)
		{
			device->SetTexture( 0, tex[i]);
			device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP);
			device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);
		}
		
		int nVerts = pcy->m_polyList[i].m_nVerts;

		sLitVertex tempv;
		v.clear();
		for( j=0; j<nVerts; j++ )
		{
			tempv = sLitVertex(
				pcy->m_ptList[ pcy->m_polyList[i].m_vList[j].m_ind ],
				pcy->m_polyList[i].m_vList[j].m_col,
				0,
				pcy->m_polyList[i].m_vList[j].m_u,
				pcy->m_polyList[i].m_vList[j].m_v );

			v.push_back(tempv);
		}
		

		// 指定自定义的FVF
		//device->SetVertexShader( D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX1 );
		device->SetFVF( D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX1 );
	
		//以三角扇形的格画出平面
		device->DrawPrimitiveUP(
			D3DPT_TRIANGLEFAN,//三角扇形
			pcy->m_polyList[i].m_nVerts - 2,//三角形个数
			(void*)&v[0],
			sizeof( sLitVertex ) );// 
		
	}

	//渲染模型
	for(i = 0;i<nObjs; i++)
	{
		D3DXMATRIX World,World1;

		//平移
		point3 p = pcy->m_objList[i].m_pos;
		D3DXMatrixTranslation(&World, p.x,p.y,p.z);

		//旋转
		float angle = pcy->m_objList[i].m_angle;
		D3DXMatrixRotationY(&World1,angle);

		//复合变换
		D3DXMatrixMultiply(&World,&World1,&World);
	
		//设置世界矩阵
		device->SetTransform(D3DTS_WORLD, &World);
	
		for(j = 0; j < Mtrls[i].size(); j++)
		{
			
			
			device->SetMaterial( &Mtrls[i][j] );
			device->SetTexture(0, Textures[i][j]);
			pMesh[i]->DrawSubset(j);
		}
	}


	//渲染地形
	for( i=0; i<nTerrain; i++ )
	{
		g_pTerrain[i]->draw(&I,false);
	
	}
	return true;
}
Ejemplo n.º 21
0
	// Simplistic implementation of the Scene interface
	virtual void EnumerateObjects(const CFrustum& frustum, SceneCollector* c)
	{
		if (GroundEnabled)
		{
			for (ssize_t pj = 0; pj < Terrain.GetPatchesPerSide(); ++pj)
				for (ssize_t pi = 0; pi < Terrain.GetPatchesPerSide(); ++pi)
					c->Submit(Terrain.GetPatch(pi, pj));
		}

		CmpPtr<ICmpVisual> cmpVisual(Simulation2, Entity);
		if (cmpVisual)
		{
			// add selection box outlines manually
			if (SelectionBoxEnabled)
			{
				SelectionBoxOverlay.m_Color = CColor(35/255.f, 86/255.f, 188/255.f, .75f); // pretty blue
				SelectionBoxOverlay.m_Thickness = 2;

				SimRender::ConstructBoxOutline(cmpVisual->GetSelectionBox(), SelectionBoxOverlay);
				c->Submit(&SelectionBoxOverlay);
			}

			// add origin axis thingy
			if (AxesMarkerEnabled)
			{
				CMatrix3D worldSpaceAxes;
				// offset from the ground a little bit to prevent fighting with the floor texture (also note: SetTranslation
				// sets the identity 3x3 transformation matrix, which are the world axes)
				worldSpaceAxes.SetTranslation(cmpVisual->GetPosition() + CVector3D(0, 0.02f, 0));
				SimRender::ConstructAxesMarker(worldSpaceAxes, AxesMarkerOverlays[0], AxesMarkerOverlays[1], AxesMarkerOverlays[2]);

				c->Submit(&AxesMarkerOverlays[0]);
				c->Submit(&AxesMarkerOverlays[1]);
				c->Submit(&AxesMarkerOverlays[2]);
			}

			// add prop point overlays
			if (PropPointsMode > 0 && Props.size() > 0)
			{
				PropPointOverlays.clear(); // doesn't clear capacity, but should be ok since the number of prop points is usually pretty limited
				for (size_t i = 0; i < Props.size(); ++i)
				{
					CModel::Prop& prop = Props[i];
					if (prop.m_Model) // should always be the case
					{
						// prop point positions are automatically updated during animations etc. by CModel::ValidatePosition
						const CMatrix3D& propCoordSystem = prop.m_Model->GetTransform();
						
						SOverlayLine pointGimbal;
						pointGimbal.m_Color = CColor(1.f, 0.f, 1.f, 1.f);
						SimRender::ConstructGimbal(propCoordSystem.GetTranslation(), 0.05f, pointGimbal);
						PropPointOverlays.push_back(pointGimbal);

						if (PropPointsMode > 1)
						{
							// scale the prop axes coord system down a bit to distinguish them from the main world-space axes markers
							CMatrix3D displayCoordSystem = propCoordSystem;
							displayCoordSystem.Scale(0.5f, 0.5f, 0.5f);
							// revert translation scaling
							displayCoordSystem._14 = propCoordSystem._14;
							displayCoordSystem._24 = propCoordSystem._24;
							displayCoordSystem._34 = propCoordSystem._34;

							// construct an XYZ axes marker for the prop's coordinate system
							SOverlayLine xAxis, yAxis, zAxis;
							SimRender::ConstructAxesMarker(displayCoordSystem, xAxis, yAxis, zAxis);
							PropPointOverlays.push_back(xAxis);
							PropPointOverlays.push_back(yAxis);
							PropPointOverlays.push_back(zAxis);
						}
					}
				}

				for (size_t i = 0; i < PropPointOverlays.size(); ++i)
				{
					c->Submit(&PropPointOverlays[i]);
				}
			}
		}

		// send a RenderSubmit message so the components can submit their visuals to the renderer
		Simulation2.RenderSubmit(*c, frustum, false);
	}
Ejemplo n.º 22
0
//--------------------------------------------------------------------------------------
// Create any D3D9 resources that will live through a device reset (D3DPOOL_MANAGED)
// and aren't tied to the back buffer size
//--------------------------------------------------------------------------------------
HRESULT CALLBACK OnD3D10CreateDevice( ID3D10Device* pd3dDevice, const DXGI_SURFACE_DESC* pBackBufferSurfaceDesc,
                                      void* pUserContext )
{
    HRESULT hr;

    V_RETURN( g_DialogResourceManager.OnD3D10CreateDevice( pd3dDevice ) );
    V_RETURN( g_SettingsDlg.OnD3D10CreateDevice( pd3dDevice ) );
    V_RETURN( D3DX10CreateFont( pd3dDevice, 15, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET,
                                OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE,
                                L"Arial", &g_pFont10 ) );
    V_RETURN( D3DX10CreateSprite( pd3dDevice, 512, &g_pSprite10 ) );
    g_pTxtHelper = new CDXUTTextHelper( NULL, NULL, g_pFont10, g_pSprite10, 15 );

#define IDC_WIREFRAME			10
    g_SampleUI.GetCheckBox( IDC_WIREFRAME )->SetVisible( false );

    V_RETURN( LoadEffect10( pd3dDevice ) );

    WCHAR str[MAX_PATH];
    V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"PIXWorkshop\\Terrain1.bmp" ) );
    V_RETURN( g_Terrain.LoadTerrain( str, g_SqrtNumTiles, g_SidesPerTile, g_fWorldScale, g_fHeightScale, 1000, 1.0f,
                                     2.0f ) );

    ResetBalls();

    // Create a Vertex Decl for the terrain and basic meshes
    const D3D10_INPUT_ELEMENT_DESC basiclayout[] =
    {
        { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0,  D3D10_INPUT_PER_VERTEX_DATA, 0 },
        { "NORMAL",   0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0 },
        { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT,    0, 24, D3D10_INPUT_PER_VERTEX_DATA, 0 },
    };
    D3D10_PASS_DESC PassDesc;
    g_pRenderTerrain->GetPassByIndex( 0 )->GetDesc( &PassDesc );
    V_RETURN( pd3dDevice->CreateInputLayout( basiclayout, sizeof( basiclayout ) / sizeof( basiclayout[0] ),
                                             PassDesc.pIAInputSignature,
                                             PassDesc.IAInputSignatureSize, &g_pBasicDecl10 ) );

    // Create a Vertex Decl for the ball
    const D3D10_INPUT_ELEMENT_DESC balllayout[] =
    {
        { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0,  D3D10_INPUT_PER_VERTEX_DATA,   0 },
        { "NORMAL",   0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA,   0 },
        { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT,    0, 24, D3D10_INPUT_PER_VERTEX_DATA,   0 },
        { "TEXCOORD", 1, DXGI_FORMAT_R32G32B32_FLOAT, 1, 0,  D3D10_INPUT_PER_INSTANCE_DATA, 1 },
    };
    g_pRenderBall->GetPassByIndex( 0 )->GetDesc( &PassDesc );
    V_RETURN( pd3dDevice->CreateInputLayout( balllayout, sizeof( balllayout ) / sizeof( balllayout[0] ),
                                             PassDesc.pIAInputSignature,
                                             PassDesc.IAInputSignatureSize, &g_pBallDecl10 ) );

    // Create a Vertex Decl for the grass
    const D3D10_INPUT_ELEMENT_DESC grasslayout[] =
    {
        { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0,  D3D10_INPUT_PER_VERTEX_DATA,   0 },
        { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT,    0, 12, D3D10_INPUT_PER_VERTEX_DATA,   0 },
        { "TEXCOORD", 1, DXGI_FORMAT_R32G32B32_FLOAT, 1, 0,  D3D10_INPUT_PER_INSTANCE_DATA, 1 },
    };
    g_pRenderGrass->GetPassByIndex( 0 )->GetDesc( &PassDesc );
    V_RETURN( pd3dDevice->CreateInputLayout( grasslayout, sizeof( grasslayout ) / sizeof( grasslayout[0] ),
                                             PassDesc.pIAInputSignature,
                                             PassDesc.IAInputSignatureSize, &g_pGrassDecl10 ) );

    // Load terrain device objects
    V_RETURN( g_Terrain.OnCreateDevice( pd3dDevice ) );

    // Load a mesh
    g_BallMesh.Create( pd3dDevice, L"PIXWorkshop\\lowpolysphere.sdkmesh" );
    g_SkyMesh.Create( pd3dDevice, L"PIXWorkshop\\desertsky.sdkmesh" );

    // Create a VB for the stream data
    D3D10_BUFFER_DESC BufferDesc;
    BufferDesc.ByteWidth = NUM_PLAYERS * sizeof( D3DXVECTOR3 );
    BufferDesc.Usage = D3D10_USAGE_DYNAMIC;
    BufferDesc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
    BufferDesc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
    BufferDesc.MiscFlags = 0;
    V_RETURN( pd3dDevice->CreateBuffer( &BufferDesc, NULL, &g_pStreamDataVB10 ) );

    // Create a VB for the grass instances
    BufferDesc.ByteWidth = g_SqrtNumTiles * g_SqrtNumTiles * sizeof( D3DXVECTOR3 );
    V_RETURN( pd3dDevice->CreateBuffer( &BufferDesc, NULL, &g_pGrassDataVB10 ) );

    // Load a texture for the mesh
    V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"PIXWorkshop\\Terrain1.bmp" ) );
    V_RETURN( D3DX10CreateShaderResourceViewFromFile( pd3dDevice, str, NULL, NULL, &g_pHeightTexRV, NULL ) );
    V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"PIXWorkshop\\Terrain1_Norm.dds" ) );
    V_RETURN( D3DX10CreateShaderResourceViewFromFile( pd3dDevice, str, NULL, NULL, &g_pNormalTexRV, NULL ) );
    V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"PIXWorkshop\\grass_v3_dark_tex.dds" ) );
    V_RETURN( D3DX10CreateShaderResourceViewFromFile( pd3dDevice, str, NULL, NULL, &g_pGrassTexRV, NULL ) );
    V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"PIXWorkshop\\Dirt_Diff.dds" ) );
    V_RETURN( D3DX10CreateShaderResourceViewFromFile( pd3dDevice, str, NULL, NULL, &g_pDirtTexRV, NULL ) );
    V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"PIXWorkshop\\Grass_Diff.dds" ) );
    V_RETURN( D3DX10CreateShaderResourceViewFromFile( pd3dDevice, str, NULL, NULL, &g_pGroundGrassTexRV, NULL ) );
    V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"PIXWorkshop\\Terrain1_Mask.dds" ) );
    V_RETURN( D3DX10CreateShaderResourceViewFromFile( pd3dDevice, str, NULL, NULL, &g_pMaskTexRV, NULL ) );
    V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"PIXWorkshop\\Terrain1_ShadeNormals.dds" ) );
    V_RETURN( D3DX10CreateShaderResourceViewFromFile( pd3dDevice, str, NULL, NULL, &g_pShadeNormalTexRV, NULL ) );

    // Setup the camera's view parameters
    D3DXVECTOR3 vecEye( 0.0f, 20.0f, -50.0f );
    D3DXVECTOR3 vecAt ( 0.0f, 5.0f, 0.0f );
    g_Camera.SetViewParams( &vecEye, &vecAt );

    return S_OK;
}
Ejemplo n.º 23
0
///////////////////////////////////////////////////////////////////
// Create information about the terrain and wave vertices.
void WaterManager::CreateSuperfancyInfo(CSimulation2* simulation)
{
	if (m_VBWaves)
	{
		g_VBMan.Release(m_VBWaves);
		m_VBWaves = NULL;
	}
	if (m_VBWavesIndices)
	{
		g_VBMan.Release(m_VBWavesIndices);
		m_VBWavesIndices = NULL;
	}

	CTerrain* terrain = g_Game->GetWorld()->GetTerrain();
	
	CmpPtr<ICmpWaterManager> cmpWaterManager(*simulation, SYSTEM_ENTITY);
	if (!cmpWaterManager)
		return;	// REALLY shouldn't happen and will most likely crash.

	// Using this to get some more optimization on circular maps
	CmpPtr<ICmpRangeManager> cmpRangeManager(*simulation, SYSTEM_ENTITY);
	if (!cmpRangeManager)
		return;
	bool circular = cmpRangeManager->GetLosCircular();
	float mSize = m_MapSize*m_MapSize;
	float halfSize = (m_MapSize/2.0);

	// Warning: this won't work with multiple water planes
	m_WaterHeight = cmpWaterManager->GetExactWaterLevel(0,0);
	
	// Get the square we want to work on.
	size_t Xstart = m_updatei0 >= m_MapSize ? m_MapSize-1 : m_updatei0;
	size_t Xend = m_updatei1 >= m_MapSize ? m_MapSize-1 : m_updatei1;
	size_t Zstart = m_updatej0 >= m_MapSize ? m_MapSize-1 : m_updatej0;
	size_t Zend = m_updatej1 >= m_MapSize ? m_MapSize-1 : m_updatej1;
	
	if (m_WaveX == NULL)
	{
		m_WaveX = new float[m_MapSize*m_MapSize];
		m_WaveZ = new float[m_MapSize*m_MapSize];
		m_DistanceToShore = new float[m_MapSize*m_MapSize];
		m_FoamFactor = new float[m_MapSize*m_MapSize];
	}

	u16* heightmap = terrain->GetHeightMap();
	
	// some temporary stuff for wave intensity
	// not really used too much right now.
	//u8* waveForceHQ = new u8[mapSize*mapSize];

	// used to cache terrain normals since otherwise we'd recalculate them a lot (I'm blurring the "normal" map).
	// this might be updated to actually cache in the terrain manager but that's not for now.
	CVector3D* normals = new CVector3D[m_MapSize*m_MapSize];

	// taken out of the bottom loop, blurs the normal map
	// To remove if below is reactivated
	size_t blurZstart = (int)(Zstart-4) < 0 ? 0 : Zstart - 4;
	size_t blurZend = Zend+4 >= m_MapSize ? m_MapSize-1 : Zend + 4;
	size_t blurXstart = (int)(Xstart-4) < 0 ? 0 : Xstart - 4;
	size_t blurXend = Xend+4 >= m_MapSize ? m_MapSize-1 : Xend + 4;
	
	float ii = blurXstart*4.0f, jj = blurXend*4.0f;
	for (size_t j = blurZstart; j < blurZend; ++j, jj += 4.0f)
	{
		for (size_t i = blurXstart; i < blurXend; ++i, ii += 4.0f)
		{
			normals[j*m_MapSize + i] = terrain->CalcExactNormal(ii,jj);
		}
	}
	// TODO: reactivate?
	/*
	// calculate wave force (not really used right now)
	// and puts into "normals" the terrain normal at that point
	// so as to avoid recalculating terrain normals too often.
	for (ssize_t i = 0; i < mapSize; ++i)
	{
		for (ssize_t j = 0; j < mapSize; ++j)
		{
			normals[j*mapSize + i] = terrain->CalcExactNormal(((float)i)*4.0f,((float)j)*4.0f);
			if (circular && (i-halfSize)*(i-halfSize)+(j-halfSize)*(j-halfSize) > mSize)
			{
				waveForceHQ[j*mapSize + i] = 255;
				continue;
			}
			u8 color = 0;
			for (int v = 0; v <= 18; v += 3){
				if (j-v >= 0 && i-v >= 0 && heightmap[(j-v)*mapSize + i-v] > waterHeightInu16)
				{
					if (color == 0)
						color = 5;
					else
						color++;
				}
			}
			waveForceHQ[j*mapSize + i] = 255 - color * 40;
		}
	}
	 */

	// Cache some data to spiral-search for the closest tile that's either coastal or water depending on what we are.
	// this is insanely faster.
	// I use a define because it's more readable and C++11 doesn't like this otherwise
#define m_MapSize (ssize_t)m_MapSize
	ssize_t offset[24] = { -1,1,-m_MapSize,+m_MapSize, -1-m_MapSize,+1-m_MapSize,-1+m_MapSize,1+m_MapSize,
		-2,2,-2*m_MapSize,2*m_MapSize,-2-m_MapSize,-2+m_MapSize,2-m_MapSize,2+m_MapSize,
		-1-2*m_MapSize,+1-2*m_MapSize,-1+2*m_MapSize,1+2*m_MapSize,
		-2-2*m_MapSize,2+2*m_MapSize,-2+2*m_MapSize,2-2*m_MapSize };
	float dist[24] = { 1.0f, 1.0f, 1.0f, 1.0f, 1.414f, 1.414f, 1.414f, 1.414f,
		2.0f, 2.0f, 2.0f, 2.0f, 2.236f, 2.236f, 2.236f, 2.236f,
		2.236f, 2.236f, 2.236f, 2.236f,
		2.828f, 2.828f, 2.828f, 2.828f };
#undef m_MapSize
	
	// this creates information for waves and stores it in float arrays. PatchRData then puts it in the vertex info for speed.
	CVector3D normal;
	for (size_t j = Zstart; j < Zend; ++j)
	{
		for (size_t i = Xstart; i < Xend; ++i)
		{
			ssize_t register index = j*m_MapSize + i;
			if (circular && (i-halfSize)*(i-halfSize)+(j-halfSize)*(j-halfSize) > mSize)
			{
				m_WaveX[index] = 0.0f;
				m_WaveZ[index] = 0.0f;
				m_DistanceToShore[index] = 100;
				m_FoamFactor[index] = 0.0f;
				continue;
			}
			float depth = m_WaterHeight - heightmap[index]*HEIGHT_SCALE;
			float register distanceToShore = 10000.0f;
			
			// calculation of the distance to the shore.
			if (i > 0 && i < m_MapSize-1 && j > 0 && j < m_MapSize-1)
			{
				// search a 5x5 array with us in the center (do not search me)
				// much faster since we spiral search and can just stop once we've found the shore.
				// also everything is precomputed and we get exact results instead.
				int max = 8;
				if (i > 1 && i < m_MapSize-2 && j > 1 && j < m_MapSize-2)
					max = 24;
				
				for(int lookupI = 0; lookupI < max;++lookupI)
				{
					float hereDepth = m_WaterHeight - heightmap[index+offset[lookupI]]*HEIGHT_SCALE;
					distanceToShore = hereDepth <= 0 && depth >= 0 ? dist[lookupI] : (depth < 0 ? 1 : distanceToShore);
					if (distanceToShore < 5000.0f)
						goto FoundShore;
				}
			} else {
				// revert to for and if-based because I can't be bothered to special case all that.
				for (int xx = -1; xx <= 1;++xx)
					for (int yy = -1; yy <= 1;++yy)
					{
						if ((int)(i+xx) >= 0 && i+xx < m_MapSize && (int)(j+yy) >= 0 && j+yy < m_MapSize)
						{
							float hereDepth = m_WaterHeight - heightmap[index+xx+yy*m_MapSize]*HEIGHT_SCALE;
							distanceToShore = (hereDepth < 0 && sqrt((double)xx*xx+yy*yy) < distanceToShore) ? sqrt((double)xx*xx+yy*yy) : distanceToShore;
						}
					}
			}

			// speedup with default values for land squares
			if (distanceToShore > 5000.0f)
			{
				m_WaveX[index] = 0.0f;
				m_WaveZ[index] = 0.0f;
				m_DistanceToShore[index] = 100.0f;
				m_FoamFactor[index] = 0.0f;
				continue;
			}
		FoundShore:
			// We'll compute the normals and the "water raise", to know about foam
			// Normals are a pretty good calculation but it's slow since we normalize so much.
			normal.X = normal.Y = normal.Z = 0.0f;
			int waterRaise = 0;
			for (size_t yy = (int(j-3) < 0 ? 0 : j-3); yy <= (j+3 < m_MapSize-1 ? 0 : j-3); yy += 2)
			{
				for (size_t xx = (int(i-3) < 0 ? 0 : i-3); xx <= (i+3 < m_MapSize-1 ? 0 : i+3); xx += 2)	// every 2 tile is good enough.
				{
					normal += normals[yy*m_MapSize + xx];
					waterRaise += (heightmap[index]*HEIGHT_SCALE - heightmap[yy*m_MapSize + xx]) > 0 ? (heightmap[index]*HEIGHT_SCALE - heightmap[yy*m_MapSize + xx]) : 0;
				}
			}
			// normalizes the terrain info to avoid foam moving at too different speeds.
			normal *= 0.08f;	// divide by about 11.
			normal[1] = 0.1f;
			normal = normal.Normalized();

			m_WaveX[index] = normal[0];
			m_WaveZ[index] = normal[2];
			// distance is /5.0 to be a [0,1] value.

			m_DistanceToShore[index] = distanceToShore;

			// computing the amount of foam I want
			depth = clamp(depth,0.0f,10.0f);
			float foamAmount = (waterRaise/255.0f) * (1.0f - depth/10.0f) /** (waveForceHQ[j*m_MapSize+i]/255.0f)*/ * (m_Waviness/8.0f);
			foamAmount += clamp(m_Waviness/2.0f,0.0f,m_Waviness/2.0f)/(m_Waviness/2.0f) * clamp(m_Waviness/9.0f,0.3f,1.0f);
			foamAmount *= (m_Waviness/4.0f - distanceToShore);
			foamAmount = foamAmount > 1.0f ? 1.0f: (foamAmount < 0.0f ? 0.0f : foamAmount);
			
			m_FoamFactor[index] = foamAmount;
		}
	}

	delete[] normals;
	//delete[] waveForceHQ;
	
	// TODO: reactivate this with something that looks good and is efficient.
/*
	// okay let's create the waves squares. i'll divide the map in arbitrary squares
	// For each of these squares, check if waves are needed.
	// If yes, look for the best positionning (in order to have a nice blending with the shore)
	// Then clean-up: remove squares that are too close to each other
	
	std::vector<CVector2D> waveSquares;
	
	int size = 8;	// I think this is the size of the squares.
	for (size_t j = 0; j < m_MapSize/size; ++j)
	{
		for (size_t i = 0; i < m_MapSize/size; ++i)
		{
			int landTexel = 0;
			int waterTexel = 0;
			CVector3D avnormal (0.0f,0.0f,0.0f);
			CVector2D landPosition(0.0f,0.0f);
			CVector2D waterPosition(0.0f,0.0f);
			for (int yy = 0; yy < size; ++yy)
			{
				for (int xx = 0; xx < size; ++xx)
				{
					if (terrain->GetVertexGroundLevel(i*size+xx,j*size+yy) > m_WaterHeight)
					{
						landTexel++;
						landPosition += CVector2D(i*size+xx,j*size+yy);
					}
					else
					{
						waterPosition += CVector2D(i*size+xx,j*size+yy);
						waterTexel++;
						avnormal += terrain->CalcExactNormal( (i*size+xx)*4.0f,(j*size+yy)*4.0f);
					}
				}
			}
			if (landTexel < size/2)
				continue;

			landPosition /= landTexel;
			waterPosition /= waterTexel;
			
			avnormal[1] = 1.0f;
			avnormal.Normalize();
			avnormal[1] = 0.0f;
			
			// this should help ensure that the shore is pretty flat.
			if (avnormal.Length() <= 0.2f)
				continue;
			
			// To get the best position for squares, I start at the mean "ocean" position
			// And step by step go to the mean "land" position. I keep the position where I change from water to land.
			// If this never happens, the square is scrapped.
			if (terrain->GetExactGroundLevel(waterPosition.X*4.0f,waterPosition.Y*4.0f) > m_WaterHeight)
				continue;
			
			CVector2D squarePos(-1,-1);
			for (u8 i = 0; i < 40; i++)
			{
				squarePos = landPosition * (i/40.0f) + waterPosition * (1.0f-(i/40.0f));
				if (terrain->GetExactGroundLevel(squarePos.X*4.0f,squarePos.Y*4.0f) > m_WaterHeight)
					break;
			}
			if (squarePos.X == -1)
				continue;
			
			u8 enter = 1;
			// okaaaaaay. Got a square. Check for proximity.
			for (unsigned long i = 0; i < waveSquares.size(); i++)
			{
				if ( CVector2D(waveSquares[i]-squarePos).LengthSquared() < 80) {
					enter = 0;
					break;
				}
			}
			if (enter == 1)
				waveSquares.push_back(squarePos);
		}
	}
	
	// Actually create the waves' meshes.
	std::vector<SWavesVertex> waves_vertex_data;
	std::vector<GLushort> waves_indices;
	
	// loop through each square point. Look in the square around it, calculate the normal
	// create the square.
	for (unsigned long i = 0; i < waveSquares.size(); i++)
	{
		CVector2D pos(waveSquares[i]);
		
		CVector3D avgnorm(0.0f,0.0f,0.0f);
		for (int yy = -size/2; yy < size/2; ++yy)
		{
			for (int xx = -size/2; xx < size/2; ++xx)
			{
				avgnorm += terrain->CalcExactNormal((pos.X+xx)*4.0f,(pos.Y+yy)*4.0f);
			}
		}
		avgnorm[1] = 0.1f;
		// okay crank out a square.
		// we have the direction of the square. We'll get the perpendicular vector too
		CVector2D perp(-avgnorm[2],avgnorm[0]);
		perp = perp.Normalized();
		avgnorm = avgnorm.Normalized();
		
		GLushort index[4];
		SWavesVertex vertex[4];
		vertex[0].m_Position = CVector3D(pos.X + perp.X*(size/2.2f) - avgnorm[0]*1.0f, 0.0f,pos.Y + perp.Y*(size/2.2f) - avgnorm[2]*1.0f);
		vertex[0].m_Position *= 4.0f;
		vertex[0].m_Position.Y = m_WaterHeight + 1.0f;
		vertex[0].m_UV[1] = 1;
		vertex[0].m_UV[0] = 0;
		index[0] = waves_vertex_data.size();
		waves_vertex_data.push_back(vertex[0]);
		
		vertex[1].m_Position = CVector3D(pos.X - perp.X*(size/2.2f) - avgnorm[0]*1.0f, 0.0f,pos.Y - perp.Y*(size/2.2f) - avgnorm[2]*1.0f);
		vertex[1].m_Position *= 4.0f;
		vertex[1].m_Position.Y = m_WaterHeight + 1.0f;
		vertex[1].m_UV[1] = 1;
		vertex[1].m_UV[0] = 1;
		index[1] = waves_vertex_data.size();
		waves_vertex_data.push_back(vertex[1]);
		
		vertex[3].m_Position = CVector3D(pos.X + perp.X*(size/2.2f) + avgnorm[0]*(size/1.5f), 0.0f,pos.Y + perp.Y*(size/2.2f) + avgnorm[2]*(size/1.5f));
		vertex[3].m_Position *= 4.0f;
		vertex[3].m_Position.Y = m_WaterHeight + 1.0f;
		vertex[3].m_UV[1] = 0;
		vertex[3].m_UV[0] = 0;
		index[3] = waves_vertex_data.size();
		waves_vertex_data.push_back(vertex[3]);
		
		vertex[2].m_Position = CVector3D(pos.X - perp.X*(size/2.2f) + avgnorm[0]*(size/1.5f), 0.0f,pos.Y - perp.Y*(size/2.2f) + avgnorm[2]*(size/1.5f));
		vertex[2].m_Position *= 4.0f;
		vertex[2].m_Position.Y = m_WaterHeight + 1.0f;
		vertex[2].m_UV[1] = 0;
		vertex[2].m_UV[0] = 1;
		index[2] = waves_vertex_data.size();
		waves_vertex_data.push_back(vertex[2]);

		waves_indices.push_back(index[0]);
		waves_indices.push_back(index[1]);
		waves_indices.push_back(index[2]);

		waves_indices.push_back(index[2]);
		waves_indices.push_back(index[3]);
		waves_indices.push_back(index[0]);
	}

	// no vertex buffers if no data generated
	if (waves_indices.empty())
		return;

	// waves
	// allocate vertex buffer
	m_VBWaves = g_VBMan.Allocate(sizeof(SWavesVertex), waves_vertex_data.size(), GL_STATIC_DRAW, GL_ARRAY_BUFFER);
	m_VBWaves->m_Owner->UpdateChunkVertices(m_VBWaves, &waves_vertex_data[0]);

	// Construct indices buffer
	m_VBWavesIndices = g_VBMan.Allocate(sizeof(GLushort), waves_indices.size(), GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER);
	m_VBWavesIndices->m_Owner->UpdateChunkVertices(m_VBWavesIndices, &waves_indices[0]);
 */
}
Ejemplo n.º 24
0
// This requires m_DistanceHeightmap to be defined properly.
void WaterManager::CreateWaveMeshes()
{
	size_t SideSize = m_MapSize*2;
	CTerrain* terrain = g_Game->GetWorld()->GetTerrain();

	for (WaveObject* const& obj : m_ShoreWaves)
	{
		if (obj->m_VBvertices)
			g_VBMan.Release(obj->m_VBvertices);
		delete obj;
	}
	m_ShoreWaves.clear();

	if (m_ShoreWaves_VBIndices)
	{
		g_VBMan.Release(m_ShoreWaves_VBIndices);
		m_ShoreWaves_VBIndices = NULL;
	}

	if (m_Waviness < 5.0f && m_WaterType != L"ocean")
		return;
		
	// First step: get the points near the coast.
	std::set<int> CoastalPointsSet;
	for (size_t z = 1; z < SideSize-1; ++z)
		for (size_t x = 1; x < SideSize-1; ++x)
			if (fabs(m_DistanceHeightmap[z*SideSize + x]-1.0f) < 0.2f)
				CoastalPointsSet.insert(z*SideSize + x);
	
	// Second step: create chains out of those coastal points.
	static const int around[8][2] = { { -1,-1 }, { -1,0 }, { -1,1 }, { 0,1 }, { 1,1 }, { 1,0 }, { 1,-1 }, { 0,-1 } };

	std::vector<std::deque<CoastalPoint> > CoastalPointsChains;
	while (!CoastalPointsSet.empty())
	{
		int index = *(CoastalPointsSet.begin());
		int x = index % SideSize;
		int y = (index - x ) / SideSize;
		
		std::deque<CoastalPoint> Chain;
		
		Chain.push_front(CoastalPoint(index,CVector2D(x*2,y*2)));
		
		// Erase us.
		CoastalPointsSet.erase(CoastalPointsSet.begin());
		
		// We're our starter points. At most we can have 2 points close to us.
		// We'll pick the first one and look for its neighbors (he can only have one new)
		// Up until we either reach the end of the chain, or ourselves.
		// Then go down the other direction if there is any.
		int neighbours[2] = { -1, -1 };
		int nbNeighb = 0;
		for (int i = 0; i < 8; ++i)
		{
			if (CoastalPointsSet.count(x + around[i][0] + (y + around[i][1])*SideSize))
			{
				if (nbNeighb < 2)
					neighbours[nbNeighb] = x + around[i][0] + (y + around[i][1])*SideSize;
				++nbNeighb;
			}
		}
		if (nbNeighb > 2)
			continue;

		for (int i = 0; i < 2; ++i)
		{
			if (neighbours[i] == -1)
				continue;
			// Move to our neighboring point
			int xx = neighbours[i] % SideSize;
			int yy = (neighbours[i] - xx ) / SideSize;
			int indexx = xx + yy*SideSize;
			int endedChain = false;
			
			if (i == 0)
				Chain.push_back(CoastalPoint(indexx,CVector2D(xx*2,yy*2)));
			else
				Chain.push_front(CoastalPoint(indexx,CVector2D(xx*2,yy*2)));

			// If there's a loop we'll be the "other" neighboring point already so check for that.
			// We'll readd at the end/front the other one to have full squares.
			if (CoastalPointsSet.count(indexx) == 0)
				break;
						
			CoastalPointsSet.erase(indexx);

			// Start checking from there.
			while(!endedChain)
			{
				bool found = false;
				nbNeighb = 0;
				for (int p = 0; p < 8; ++p)
				{
					if (CoastalPointsSet.count(xx+around[p][0] + (yy + around[p][1])*SideSize))
					{
						if (nbNeighb >= 2)
						{
							CoastalPointsSet.erase(xx + yy*SideSize);
							continue;
						}
						++nbNeighb;
						// We've found a new point around us.
						// Move there
						xx = xx + around[p][0];
						yy = yy + around[p][1];
						indexx = xx + yy*SideSize;
						if (i == 0)
							Chain.push_back(CoastalPoint(indexx,CVector2D(xx*2,yy*2)));
						else
							Chain.push_front(CoastalPoint(indexx,CVector2D(xx*2,yy*2)));
						CoastalPointsSet.erase(xx + yy*SideSize);
						found = true;
						break;
					}
				}
				if (!found)
					endedChain = true;
			}
		}
		if (Chain.size() > 10)
			CoastalPointsChains.push_back(Chain);
	}
		
	// (optional) third step: Smooth chains out.
	// This is also really dumb.
	for (size_t i = 0; i < CoastalPointsChains.size(); ++i)
	{
		// Bump 1 for smoother.
		for (int p = 0; p < 3; ++p)
		{
			for (size_t j = 1; j < CoastalPointsChains[i].size()-1; ++j)
			{
				CVector2D realPos = CoastalPointsChains[i][j-1].position + CoastalPointsChains[i][j+1].position;
				
				CoastalPointsChains[i][j].position = (CoastalPointsChains[i][j].position + realPos/2.0f)/2.0f;
			}
		}
	}
	
	// Fourth step: create waves themselves, using those chains. We basically create subchains.
	size_t waveSizes = 14;	// maximal size in width.
	
	// Construct indices buffer (we can afford one for all of them)
	std::vector<GLushort> water_indices;
	for (size_t a = 0; a < waveSizes-1;++a)
	{
		for (size_t rect = 0; rect < 7; ++rect)
		{
			water_indices.push_back(a*9 + rect);
			water_indices.push_back(a*9 + 9 + rect);
			water_indices.push_back(a*9 + 1 + rect);
			water_indices.push_back(a*9 + 9 + rect);
			water_indices.push_back(a*9 + 10 + rect);
			water_indices.push_back(a*9 + 1 + rect);
		}
	}
	// Generic indexes, max-length
	m_ShoreWaves_VBIndices = g_VBMan.Allocate(sizeof(GLushort), water_indices.size(), GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER);
	m_ShoreWaves_VBIndices->m_Owner->UpdateChunkVertices(m_ShoreWaves_VBIndices, &water_indices[0]);
	
	float diff = (rand() % 50) / 5.0f;
	
	for (size_t i = 0; i < CoastalPointsChains.size(); ++i)
	{
		for (size_t j = 0; j < CoastalPointsChains[i].size()-waveSizes; ++j)
		{
			if (CoastalPointsChains[i].size()- 1 - j < waveSizes)
				break;
			
			size_t width = waveSizes;
			
			// First pass to get some parameters out.
			float outmost = 0.0f;	// how far to move on the shore.
			float avgDepth = 0.0f;
			int sign = 1;
			CVector2D firstPerp(0,0), perp(0,0), lastPerp(0,0);
			for (size_t a = 0; a < waveSizes;++a)
			{
				lastPerp = perp;
				perp = CVector2D(0,0);
				int nb = 0;
				CVector2D pos = CoastalPointsChains[i][j+a].position;
				CVector2D posPlus;
				CVector2D posMinus;
				if (a > 0)
				{
					++nb;
					posMinus = CoastalPointsChains[i][j+a-1].position;
					perp += pos-posMinus;
				}
				if (a < waveSizes-1)
				{
					++nb;
					posPlus = CoastalPointsChains[i][j+a+1].position;
					perp += posPlus-pos;
				}
				perp /= nb;
				perp = CVector2D(-perp.Y,perp.X).Normalized();
				
				if (a == 0)
					firstPerp = perp;
				
				if ( a > 1 && perp.Dot(lastPerp) < 0.90f && perp.Dot(firstPerp) < 0.70f)
				{
					width = a+1;
					break;
				}
				
				if (m_BlurredNormalMap[ (int)(pos.X/4) + (int)(pos.Y/4)*m_MapSize].Y < 0.9)
				{
					width = a-1;
					break;
				}
				
				if (terrain->GetExactGroundLevel(pos.X+perp.X*1.5f, pos.Y+perp.Y*1.5f) > m_WaterHeight)
					sign = -1;
				
				avgDepth += terrain->GetExactGroundLevel(pos.X+sign*perp.X*20.0f, pos.Y+sign*perp.Y*20.0f) - m_WaterHeight;
				
				float localOutmost = -2.0f;
				while (localOutmost < 0.0f)
				{
					float depth = terrain->GetExactGroundLevel(pos.X+sign*perp.X*localOutmost, pos.Y+sign*perp.Y*localOutmost) - m_WaterHeight;
					if (depth < 0.0f || depth > 0.6f)
						localOutmost += 0.2f;
					else
						break;
				}

				outmost += localOutmost;
			}
			if (width < 5)
			{
				j += 6;
				continue;
			}

			outmost /= width;
			
			if (outmost > -0.5f)
			{
				j += 3;
				continue;
			}
			outmost = -0.5f + outmost * m_Waviness/10.0f;

			avgDepth /= width;

			if (avgDepth > -1.3f)
			{
				j += 3;
				continue;
			}
			// we passed the checks, we can create a wave of size "width".
			
			WaveObject* shoreWave = new WaveObject;
			std::vector<SWavesVertex> vertices;

			shoreWave->m_Width = width;
			shoreWave->m_TimeDiff = diff;
			diff += (rand() % 100) / 25.0f + 4.0f;

			for (size_t a = 0; a < width;++a)
			{
				CVector2D perp = CVector2D(0,0);
				int nb = 0;
				CVector2D pos = CoastalPointsChains[i][j+a].position;
				CVector2D posPlus;
				CVector2D posMinus;
				if (a > 0)
				{
					++nb;
					posMinus = CoastalPointsChains[i][j+a-1].position;
					perp += pos-posMinus;
				}
				if (a < waveSizes-1)
				{
					++nb;
					posPlus = CoastalPointsChains[i][j+a+1].position;
					perp += posPlus-pos;
				}
				perp /= nb;
				perp = CVector2D(-perp.Y,perp.X).Normalized();
				
				SWavesVertex point[9];
				
				float baseHeight = 0.04f;
				
				float halfWidth = (width-1.0f)/2.0f;
				float sideNess = sqrtf(clamp( (halfWidth - fabsf(a-halfWidth))/3.0f, 0.0f,1.0f));
				
				point[0].m_UV[0] = a; point[0].m_UV[1] = 8;
				point[1].m_UV[0] = a; point[1].m_UV[1] = 7;
				point[2].m_UV[0] = a; point[2].m_UV[1] = 6;
				point[3].m_UV[0] = a; point[3].m_UV[1] = 5;
				point[4].m_UV[0] = a; point[4].m_UV[1] = 4;
				point[5].m_UV[0] = a; point[5].m_UV[1] = 3;
				point[6].m_UV[0] = a; point[6].m_UV[1] = 2;
				point[7].m_UV[0] = a; point[7].m_UV[1] = 1;
				point[8].m_UV[0] = a; point[8].m_UV[1] = 0;
				
				point[0].m_PerpVect = perp;
				point[1].m_PerpVect = perp;
				point[2].m_PerpVect = perp;
				point[3].m_PerpVect = perp;
				point[4].m_PerpVect = perp;
				point[5].m_PerpVect = perp;
				point[6].m_PerpVect = perp;
				point[7].m_PerpVect = perp;
				point[8].m_PerpVect = perp;
				
				static const float perpT1[9] = { 6.0f, 6.05f, 6.1f, 6.2f, 6.3f, 6.4f, 6.5f, 6.6f, 9.7f };
				static const float perpT2[9] = { 2.0f, 2.1f,  2.2f, 2.3f, 2.4f, 3.0f, 3.3f, 3.6f, 9.5f };
				static const float perpT3[9] = { 1.1f, 0.7f, -0.2f, 0.0f, 0.6f, 1.3f, 2.2f, 3.6f, 9.0f };
				static const float perpT4[9] = { 2.0f, 2.1f,  1.2f, 1.5f, 1.7f, 1.9f, 2.7f, 3.8f, 9.0f };
				
				static const float heightT1[9] = { 0.0f, 0.2f, 0.5f, 0.8f, 0.9f, 0.85f, 0.6f, 0.2f, 0.0 };
				static const float heightT2[9] = { -0.8f, -0.4f, 0.0f, 0.1f, 0.1f, 0.03f, 0.0f, 0.0f, 0.0 };
				static const float heightT3[9] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0 };

				for (size_t t = 0; t < 9; ++t)
				{
					float terrHeight = 0.05f + terrain->GetExactGroundLevel(pos.X+sign*perp.X*(perpT1[t]+outmost),
																			pos.Y+sign*perp.Y*(perpT1[t]+outmost));
					point[t].m_BasePosition = CVector3D(pos.X+sign*perp.X*(perpT1[t]+outmost), baseHeight + heightT1[t]*sideNess + std::max(m_WaterHeight,terrHeight),
														pos.Y+sign*perp.Y*(perpT1[t]+outmost));
				}
				for (size_t t = 0; t < 9; ++t)
				{
					float terrHeight = 0.05f + terrain->GetExactGroundLevel(pos.X+sign*perp.X*(perpT2[t]+outmost),
																			pos.Y+sign*perp.Y*(perpT2[t]+outmost));
					point[t].m_ApexPosition = CVector3D(pos.X+sign*perp.X*(perpT2[t]+outmost), baseHeight + heightT1[t]*sideNess + std::max(m_WaterHeight,terrHeight),
														pos.Y+sign*perp.Y*(perpT2[t]+outmost));
				}
				for (size_t t = 0; t < 9; ++t)
				{
					float terrHeight = 0.05f + terrain->GetExactGroundLevel(pos.X+sign*perp.X*(perpT3[t]+outmost*sideNess),
																			pos.Y+sign*perp.Y*(perpT3[t]+outmost*sideNess));
					point[t].m_SplashPosition = CVector3D(pos.X+sign*perp.X*(perpT3[t]+outmost*sideNess), baseHeight + heightT2[t]*sideNess + std::max(m_WaterHeight,terrHeight), pos.Y+sign*perp.Y*(perpT3[t]+outmost*sideNess));
				}
				for (size_t t = 0; t < 9; ++t)
				{
					float terrHeight = 0.05f + terrain->GetExactGroundLevel(pos.X+sign*perp.X*(perpT4[t]+outmost),
																			pos.Y+sign*perp.Y*(perpT4[t]+outmost));
					point[t].m_RetreatPosition = CVector3D(pos.X+sign*perp.X*(perpT4[t]+outmost), baseHeight + heightT3[t]*sideNess + std::max(m_WaterHeight,terrHeight),
														   pos.Y+sign*perp.Y*(perpT4[t]+outmost));
				}
				
				vertices.push_back(point[8]);
				vertices.push_back(point[7]);
				vertices.push_back(point[6]);
				vertices.push_back(point[5]);
				vertices.push_back(point[4]);
				vertices.push_back(point[3]);
				vertices.push_back(point[2]);
				vertices.push_back(point[1]);
				vertices.push_back(point[0]);
				
				shoreWave->m_AABB += point[8].m_SplashPosition;
				shoreWave->m_AABB += point[8].m_BasePosition;
				shoreWave->m_AABB += point[0].m_SplashPosition;
				shoreWave->m_AABB += point[0].m_BasePosition;
				shoreWave->m_AABB += point[4].m_ApexPosition;
			}

			if (sign == 1)
			{
				// Let's do some fancy reversing.
				std::vector<SWavesVertex> reversed;
				for (int a = width-1; a >= 0; --a)
				{
					for (size_t t = 0; t < 9; ++t)
						reversed.push_back(vertices[a*9+t]);
				}
				vertices = reversed;
			}
			j += width/2-1;
			
			shoreWave->m_VBvertices = g_VBMan.Allocate(sizeof(SWavesVertex), vertices.size(), GL_STATIC_DRAW, GL_ARRAY_BUFFER);
			shoreWave->m_VBvertices->m_Owner->UpdateChunkVertices(shoreWave->m_VBvertices, &vertices[0]);
			
			m_ShoreWaves.push_back(shoreWave);
		}
	}
}
Ejemplo n.º 25
0
///////////////////////////////////////////////////////////////////
// Create information about the terrain and wave vertices.
void WaterManager::CreateSuperfancyInfo(CSimulation2* simulation)
{
	if (m_VBWaves)
	{
		g_VBMan.Release(m_VBWaves);
		m_VBWaves = NULL;
	}
	if (m_VBWavesIndices)
	{
		g_VBMan.Release(m_VBWavesIndices);
		m_VBWavesIndices = NULL;
	}

	CTerrain* terrain = g_Game->GetWorld()->GetTerrain();
	ssize_t mapSize = terrain->GetVerticesPerSide();
	
	CmpPtr<ICmpWaterManager> cmpWaterManager(*simulation, SYSTEM_ENTITY);
	if (!cmpWaterManager)
		return;	// REALLY shouldn't happen and will most likely crash.

	// Using this to get some more optimization on circular maps
	CmpPtr<ICmpRangeManager> cmpRangeManager(*simulation, SYSTEM_ENTITY);
	if (!cmpRangeManager)
		return;
	bool circular = cmpRangeManager->GetLosCircular();
	float mSize = mapSize*mapSize;
	float halfSize = (mapSize/2.0);

	// Warning: this won't work with multiple water planes
	m_WaterHeight = cmpWaterManager->GetExactWaterLevel(0,0);
	
	// TODO: change this whenever we incrementally update because it's def. not too efficient
	delete[] m_WaveX;
	delete[] m_WaveZ;
	delete[] m_DistanceToShore;
	delete[] m_FoamFactor;
	
	m_WaveX = new float[mapSize*mapSize];
	m_WaveZ = new float[mapSize*mapSize];
	m_DistanceToShore = new float[mapSize*mapSize];
	m_FoamFactor = new float[mapSize*mapSize];

	u16* heightmap = terrain->GetHeightMap();
	
	// some temporary stuff for wave intensity
	// not really used too much right now.
	u8* waveForceHQ = new u8[mapSize*mapSize];
	u16 waterHeightInu16 = m_WaterHeight/HEIGHT_SCALE;

	// used to cache terrain normals since otherwise we'd recalculate them a lot (I'm blurring the "normal" map).
	// this might be updated to actually cache in the terrain manager but that's not for now.
	CVector3D* normals = new CVector3D[mapSize*mapSize];

	// calculate wave force (not really used right now)
	// and puts into "normals" the terrain normal at that point
	// so as to avoid recalculating terrain normals too often.
	for (ssize_t i = 0; i < mapSize; ++i)
	{
		for (ssize_t j = 0; j < mapSize; ++j)
		{
			normals[j*mapSize + i] = terrain->CalcExactNormal(((float)i)*4.0f,((float)j)*4.0f);
			if (circular && (i-halfSize)*(i-halfSize)+(j-halfSize)*(j-halfSize) > mSize)
			{
				waveForceHQ[j*mapSize + i] = 255;
				continue;
			}
			u8 color = 0;
			for (int v = 0; v <= 18; v += 3){
				if (j-v >= 0 && i-v >= 0 && heightmap[(j-v)*mapSize + i-v] > waterHeightInu16)
				{
					if (color == 0)
						color = 5;
					else
						color++;
				}
			}
			waveForceHQ[j*mapSize + i] = 255 - color * 40;
		}
	}
	// this creates information for waves and stores it in float arrays. PatchRData then puts it in the vertex info for speed.
	for (ssize_t i = 0; i < mapSize; ++i)
	{
		for (ssize_t j = 0; j < mapSize; ++j)
		{
			if (circular && (i-halfSize)*(i-halfSize)+(j-halfSize)*(j-halfSize) > mSize)
			{
				m_WaveX[j*mapSize + i] = 0.0f;
				m_WaveZ[j*mapSize + i] = 0.0f;
				m_DistanceToShore[j*mapSize + i] = 100;
				m_FoamFactor[j*mapSize + i] = 0.0f;
				continue;
			}
			float depth = m_WaterHeight - heightmap[j*mapSize + i]*HEIGHT_SCALE;
			int distanceToShore = 10000;
			
			// calculation of the distance to the shore.
			// TODO: this is fairly dumb, though it returns a good result
			// Could be sped up a fair bit.
			if (depth >= 0)
			{
				// check in the square around.
				for (int xx = -5; xx <= 5; ++xx)
				{
					for (int yy = -5; yy <= 5; ++yy)
					{
						if (i+xx >= 0 && i + xx < mapSize)
							if (j + yy >= 0 && j + yy < mapSize)
							{
								float hereDepth = m_WaterHeight - heightmap[(j+yy)*mapSize + (i+xx)]*HEIGHT_SCALE;
								if (hereDepth < 0 && xx*xx + yy*yy < distanceToShore)
									distanceToShore = xx*xx + yy*yy;
							}
					}
				}
				// refine the calculation if we're close enough
				if (distanceToShore < 9)
				{
					for (float xx = -2.5f; xx <= 2.5f; ++xx)
					{
						for (float yy = -2.5f; yy <= 2.5f; ++yy)
						{
							float hereDepth = m_WaterHeight - terrain->GetExactGroundLevel( (i+xx)*4, (j+yy)*4 );
							if (hereDepth < 0 && xx*xx + yy*yy < distanceToShore)
								distanceToShore = xx*xx + yy*yy;
						}
					}
				}
			}
			else
			{
				for (int xx = -2; xx <= 2; ++xx)
				{
					for (int yy = -2; yy <= 2; ++yy)
					{
						float hereDepth = m_WaterHeight - terrain->GetVertexGroundLevel(i+xx, j+yy);
						if (hereDepth > 0)
							distanceToShore = 0;
					}
				}
				
			}
			// speedup with default values for land squares
			if (distanceToShore == 10000)
			{
				m_WaveX[j*mapSize + i] = 0.0f;
				m_WaveZ[j*mapSize + i] = 0.0f;
				m_DistanceToShore[j*mapSize + i] = 100;
				m_FoamFactor[j*mapSize + i] = 0.0f;
				continue;
			}
			// We'll compute the normals and the "water raise", to know about foam
			// Normals are a pretty good calculation but it's slow since we normalize so much.
			CVector3D normal;
			int waterRaise = 0;
			for (int xx = -4; xx <= 4; xx += 2)	// every 2 tile is good enough.
			{
				for (int yy = -4; yy <= 4; yy += 2)
				{
					if (j+yy < mapSize && i+xx < mapSize && i+xx >= 0 && j+yy >= 0)
						normal += normals[(j+yy)*mapSize + (i+xx)];
					if (terrain->GetVertexGroundLevel(i+xx,j+yy) < heightmap[j*mapSize + i]*HEIGHT_SCALE)
						waterRaise += heightmap[j*mapSize + i]*HEIGHT_SCALE - terrain->GetVertexGroundLevel(i+xx,j+yy);
				}
			}
			// normalizes the terrain info to avoid foam moving at too different speeds.
			normal *= 0.012345679f;
			normal[1] = 0.1f;
			normal = normal.Normalized();

			m_WaveX[j*mapSize + i] = normal[0];
			m_WaveZ[j*mapSize + i] = normal[2];
			// distance is /5.0 to be a [0,1] value.

			m_DistanceToShore[j*mapSize + i] = sqrtf(distanceToShore)/5.0f; // TODO: this can probably be cached as I'm integer here.

			// computing the amount of foam I want

			depth = clamp(depth,0.0f,10.0f);
			float foamAmount = (waterRaise/255.0f) * (1.0f - depth/10.0f) * (waveForceHQ[j*mapSize+i]/255.0f) * (m_Waviness/8.0f);
			foamAmount += clamp(m_Waviness/2.0f - distanceToShore,0.0f,m_Waviness/2.0f)/(m_Waviness/2.0f) * clamp(m_Waviness/9.0f,0.3f,1.0f);
			foamAmount = foamAmount > 1.0f ? 1.0f: foamAmount;
			
			m_FoamFactor[j*mapSize + i] = foamAmount;
		}
	}

	delete[] normals;
	delete[] waveForceHQ;
	
	// TODO: The rest should be cleaned up
	
	// okay let's create the waves squares. i'll divide the map in arbitrary squares
	// For each of these squares, check if waves are needed.
	// If yes, look for the best positionning (in order to have a nice blending with the shore)
	// Then clean-up: remove squares that are too close to each other
	
	std::vector<CVector2D> waveSquares;
	
	int size = 8;	// I think this is the size of the squares.
	for (int i = 0; i < mapSize/size; ++i)
	{
		for (int j = 0; j < mapSize/size; ++j)
		{
			
			int landTexel = 0;
			int waterTexel = 0;
			CVector3D avnormal (0.0f,0.0f,0.0f);
			CVector2D landPosition(0.0f,0.0f);
			CVector2D waterPosition(0.0f,0.0f);
			for (int xx = 0; xx < size; ++xx)
			{
				for (int yy = 0; yy < size; ++yy)
				{
					if (terrain->GetVertexGroundLevel(i*size+xx,j*size+yy) > m_WaterHeight)
					{
						landTexel++;
						landPosition += CVector2D(i*size+xx,j*size+yy);
					}
					else
					{
						waterPosition += CVector2D(i*size+xx,j*size+yy);
						waterTexel++;
						avnormal += terrain->CalcExactNormal( (i*size+xx)*4.0f,(j*size+yy)*4.0f);
					}
				}
			}
			if (landTexel < size/2)
				continue;

			landPosition /= landTexel;
			waterPosition /= waterTexel;
			
			avnormal[1] = 1.0f;
			avnormal.Normalize();
			avnormal[1] = 0.0f;
			
			// this should help ensure that the shore is pretty flat.
			if (avnormal.Length() <= 0.2f)
				continue;
			
			// To get the best position for squares, I start at the mean "ocean" position
			// And step by step go to the mean "land" position. I keep the position where I change from water to land.
			// If this never happens, the square is scrapped.
			if (terrain->GetExactGroundLevel(waterPosition.X*4.0f,waterPosition.Y*4.0f) > m_WaterHeight)
				continue;
			
			CVector2D squarePos(-1,-1);
			for (u8 i = 0; i < 40; i++)
			{
				squarePos = landPosition * (i/40.0f) + waterPosition * (1.0f-(i/40.0f));
				if (terrain->GetExactGroundLevel(squarePos.X*4.0f,squarePos.Y*4.0f) > m_WaterHeight)
					break;
			}
			if (squarePos.X == -1)
				continue;
			
			u8 enter = 1;
			// okaaaaaay. Got a square. Check for proximity.
			for (unsigned long i = 0; i < waveSquares.size(); i++)
			{
				if ( CVector2D(waveSquares[i]-squarePos).LengthSquared() < 80) {
					enter = 0;
					break;
				}
			}
			if (enter == 1)
				waveSquares.push_back(squarePos);
		}
	}
	
	// Actually create the waves' meshes.
	std::vector<SWavesVertex> waves_vertex_data;
	std::vector<GLushort> waves_indices;
	
	// loop through each square point. Look in the square around it, calculate the normal
	// create the square.
	for (unsigned long i = 0; i < waveSquares.size(); i++)
	{
		CVector2D pos(waveSquares[i]);
		
		CVector3D avgnorm(0.0f,0.0f,0.0f);
		for (int xx = -size/2; xx < size/2; ++xx)
		{
			for (int yy = -size/2; yy < size/2; ++yy)
			{
				avgnorm += terrain->CalcExactNormal((pos.X+xx)*4.0f,(pos.Y+yy)*4.0f);
			}
		}
		avgnorm[1] = 0.1f;
		// okay crank out a square.
		// we have the direction of the square. We'll get the perpendicular vector too
		CVector2D perp(-avgnorm[2],avgnorm[0]);
		perp = perp.Normalized();
		avgnorm = avgnorm.Normalized();
		
		SWavesVertex vertex[4];
		vertex[0].m_Position = CVector3D(pos.X + perp.X*(size/2.2f) - avgnorm[0]*1.0f, 0.0f,pos.Y + perp.Y*(size/2.2f) - avgnorm[2]*1.0f);
		vertex[0].m_Position *= 4.0f;
		vertex[0].m_Position.Y = m_WaterHeight + 1.0f;
		vertex[0].m_UV[1] = 1;
		vertex[0].m_UV[0] = 0;
		
		vertex[1].m_Position = CVector3D(pos.X - perp.X*(size/2.2f) - avgnorm[0]*1.0f, 0.0f,pos.Y - perp.Y*(size/2.2f) - avgnorm[2]*1.0f);
		vertex[1].m_Position *= 4.0f;
		vertex[1].m_Position.Y = m_WaterHeight + 1.0f;
		vertex[1].m_UV[1] = 1;
		vertex[1].m_UV[0] = 1;
		
		vertex[3].m_Position = CVector3D(pos.X + perp.X*(size/2.2f) + avgnorm[0]*(size/1.5f), 0.0f,pos.Y + perp.Y*(size/2.2f) + avgnorm[2]*(size/1.5f));
		vertex[3].m_Position *= 4.0f;
		vertex[3].m_Position.Y = m_WaterHeight + 1.0f;
		vertex[3].m_UV[1] = 0;
		vertex[3].m_UV[0] = 0;
		
		vertex[2].m_Position = CVector3D(pos.X - perp.X*(size/2.2f) + avgnorm[0]*(size/1.5f), 0.0f,pos.Y - perp.Y*(size/2.2f) + avgnorm[2]*(size/1.5f));
		vertex[2].m_Position *= 4.0f;
		vertex[2].m_Position.Y = m_WaterHeight + 1.0f;
		vertex[2].m_UV[1] = 0;
		vertex[2].m_UV[0] = 1;
		
		waves_indices.push_back(waves_vertex_data.size());
		waves_vertex_data.push_back(vertex[0]);
		waves_indices.push_back(waves_vertex_data.size());
		waves_vertex_data.push_back(vertex[1]);
		waves_indices.push_back(waves_vertex_data.size());
		waves_vertex_data.push_back(vertex[2]);
		waves_indices.push_back(waves_vertex_data.size());
		waves_vertex_data.push_back(vertex[3]);
	}

	// no vertex buffers if no data generated
	if (waves_indices.empty())
		return;

	// waves
	// allocate vertex buffer
	m_VBWaves = g_VBMan.Allocate(sizeof(SWavesVertex), waves_vertex_data.size(), GL_STATIC_DRAW, GL_ARRAY_BUFFER);
	m_VBWaves->m_Owner->UpdateChunkVertices(m_VBWaves, &waves_vertex_data[0]);

	// Construct indices buffer
	m_VBWavesIndices = g_VBMan.Allocate(sizeof(GLushort), waves_indices.size(), GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER);
	m_VBWavesIndices->m_Owner->UpdateChunkVertices(m_VBWavesIndices, &waves_indices[0]);
}
Ejemplo n.º 26
0
int main(void)
{	
	// Make sure these four lines are put first since some of the 
	// other classes need the managers to be initialised so they 
	// can pick up the correct data.	
	SPS2Manager.Initialise(4096);	// 4096 * 4K Pages = 16MB Total
	VIFStaticDMA.Initialise(3072);	// 1536 * 4K Pages = 6MB Static DMA
	VIFDynamicDMA.Initialise(256);	// 256 * 4K Pages * 2 Buffers =
									// 2MB Dynamic DMA
	Pipeline.Initialise();			// Initialise graphics pipline class
	
	
	// Initialise Lighting
	// Three lights and Ambient light
	//							Direction vector				  Colour	
	Pipeline.SetLight1(Vector4( 0.0f, 0.5f, -1.0f, 0.0f),  Vector4( 0.0f, 0.0f, 128.0f, 0.0f));
	Pipeline.SetLight2(Vector4( 1.0f, -0.5f, -1.0f, 0.0f),  Vector4( 0.0f, 128.0f, 0.0f, 0.0f));
	Pipeline.SetLight3(Vector4( -1.0f, -0.5f, -1.0f, 0.0f), Vector4( 128.0f, 0.0f, 0.0f, 0.0f));
	//                            Colour
	Pipeline.SetAmbient(Vector4(50.0f,50.0f,50.0f,50.0f));
	
	// Terrain to render
	CTerrain Terrain;
	
	// Performance timer - call after SPS2Manager.Initialise()
	CTimer Timer;
	
	// Set up audio devices
	AudioDevice DSP0(0);
	// Set up music in sound buffer 0
	SoundSample music("go_cart", &DSP0);
	// Play the music!
	music.Play();
	
	// Initialise control pad 0
	if(!pad_init(PAD_0, PAD_INIT_LOCK | PAD_INIT_ANALOGUE | PAD_INIT_PRESSURE))
	{
		printf("Failed to initialise control pad\n");
		pad_cleanup(PAD_0);
		exit(0);
	}	
	enable_actuator(0, 1, 1);
	
	// Initialise the VU1 manager class
	CVU1MicroProgram VU1MicroCode(&VU_vu1code_start, &VU_vu1code_end);
	
	// Upload the microcode
	VU1MicroCode.Upload();

	// Register our signal function for every possible signal (i.e. ctrl + c)
	for(int sig=0; sig<128; sig++)
		signal(sig, sig_handle);
		
		
	// Set up the DMA packet to clear the screen. We want to clear to blue.
	SPS2Manager.InitScreenClear(0, 0x25, 0x50);
	
	// Set Up Camera --------------------------------------------------------------
	
	Pipeline.PositionCamera(Vector4(0.0f, 55.0f, 80.0f, 1.0f), Vector4(0.0f, 40.0f, 0.0f, 1.0f));
	
	// Load in texture and models ----------------------------------------------
	
	// Set up asset loader
	AssetManager assetManager;
	assetManager.Initialize();
	
	// Terrain texture
	CTexture* terrainTexture = assetManager.GetTexture("terrain");
	
	// Set up game manager
	GameManager* gameManager = new GameManager;
	gameManager->Initialize();
		
	// The main Render loop -------------------------------------------------------
	while(g_bLoop)
	{
		
		// Process Audio
		DSP0.HandleAudio();
		
		VIFDynamicDMA.Fire();
		
		// Update Control Pad
		pad_update(PAD_0);
		Pipeline.Update(0, 0, 0, 0, 0);
		
		// Logic
		g_bLoop = gameManager->Logic();
	
		// Render
		SPS2Manager.BeginScene();
		
		// Render terrain
		AssetManager::GetSingleton().LoadTexture(terrainTexture);
		Matrix4x4 matWorld, matTrans, matScale;
		matTrans.Translation(0.0f, -30.0f, 0.0f);
		matScale.Scaling(20.0f);
		matWorld =  matScale * matTrans;
		Terrain.SetWorldMatrix(matWorld);
		Terrain.Render();
		
		// Render scene
		gameManager->Render();
		SPS2Manager.EndScene();	
		
		// Dump screenshot if requested
		if(pad[0].pressed & PAD_R2)SPS2Manager.ScreenShot();		
	}

	// Shutdown Audio
	DSP0.Close();
	
	// Shutdown control pad
	set_actuator(0, 0, 0);
	pad_cleanup(PAD_0);
	
	// Shutdown game manager
	gameManager->Shutdown();
	
	// Shutdown asset manager
	assetManager.Shutdown();
	
	return 0;
}
Ejemplo n.º 27
0
void CPatchRData::BuildIndices()
{
	PROFILE3("build indices");

	CTerrain* terrain = m_Patch->m_Parent;

	ssize_t px = m_Patch->m_X * PATCH_SIZE;
	ssize_t pz = m_Patch->m_Z * PATCH_SIZE;

	// must have allocated some vertices before trying to build corresponding indices
	ENSURE(m_VBBase);

	// number of vertices in each direction in each patch
	ssize_t vsize=PATCH_SIZE+1;

	std::vector<unsigned short> indices;
	indices.reserve(PATCH_SIZE * PATCH_SIZE * 4);

	// release existing splats
	m_Splats.clear();

	// build grid of textures on this patch
	std::vector<CTerrainTextureEntry*> textures;
	CTerrainTextureEntry* texgrid[PATCH_SIZE][PATCH_SIZE];
	for (ssize_t j=0;j<PATCH_SIZE;j++) {
		for (ssize_t i=0;i<PATCH_SIZE;i++) {
			CTerrainTextureEntry* tex=m_Patch->m_MiniPatches[j][i].GetTextureEntry();
			texgrid[j][i]=tex;
			if (std::find(textures.begin(),textures.end(),tex)==textures.end()) {
				textures.push_back(tex);
			}
		}
	}

	// now build base splats from interior textures
	m_Splats.resize(textures.size());
	// build indices for base splats
	size_t base=m_VBBase->m_Index;
	ENSURE(base + vsize*vsize < 65536); // mustn't overflow u16 indexes
	for (size_t i=0;i<m_Splats.size();i++) {
		CTerrainTextureEntry* tex=textures[i];

		SSplat& splat=m_Splats[i];
		splat.m_Texture=tex;
		splat.m_IndexStart=indices.size();

		for (ssize_t j = 0; j < PATCH_SIZE; j++)
		{
			for (ssize_t i = 0; i < PATCH_SIZE; i++)
			{
				if (texgrid[j][i] == tex)
				{
					bool dir = terrain->GetTriangulationDir(px+i, pz+j);
					if (dir)
					{
						indices.push_back(u16(((j+0)*vsize+(i+0))+base));
						indices.push_back(u16(((j+0)*vsize+(i+1))+base));
						indices.push_back(u16(((j+1)*vsize+(i+0))+base));

						indices.push_back(u16(((j+0)*vsize+(i+1))+base));
						indices.push_back(u16(((j+1)*vsize+(i+1))+base));
						indices.push_back(u16(((j+1)*vsize+(i+0))+base));
					}
					else
					{
						indices.push_back(u16(((j+0)*vsize+(i+0))+base));
						indices.push_back(u16(((j+0)*vsize+(i+1))+base));
						indices.push_back(u16(((j+1)*vsize+(i+1))+base));

						indices.push_back(u16(((j+1)*vsize+(i+1))+base));
						indices.push_back(u16(((j+1)*vsize+(i+0))+base));
						indices.push_back(u16(((j+0)*vsize+(i+0))+base));
					}
				}
			}
		}
		splat.m_IndexCount=indices.size()-splat.m_IndexStart;
	}

	// Release existing vertex buffer chunk
	if (m_VBBaseIndices)
	{
		g_VBMan.Release(m_VBBaseIndices);
		m_VBBaseIndices = 0;
	}

	ENSURE(indices.size());

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