Beispiel #1
0
	virtual void ReloadTerrain()
	{
		// TODO: should refactor this code to be nicer

		u16 tiles = GetTilesPerSide();
		u16 vertices = GetVerticesPerSide();

		CmpPtr<ICmpObstructionManager> cmpObstructionManager(GetSystemEntity());
		if (cmpObstructionManager)
		{
			cmpObstructionManager->SetBounds(entity_pos_t::Zero(), entity_pos_t::Zero(),
					entity_pos_t::FromInt(tiles*(int)TERRAIN_TILE_SIZE),
					entity_pos_t::FromInt(tiles*(int)TERRAIN_TILE_SIZE));
		}

		CmpPtr<ICmpRangeManager> cmpRangeManager(GetSystemEntity());
		if (cmpRangeManager)
		{
			cmpRangeManager->SetBounds(entity_pos_t::Zero(), entity_pos_t::Zero(),
					entity_pos_t::FromInt(tiles*(int)TERRAIN_TILE_SIZE),
					entity_pos_t::FromInt(tiles*(int)TERRAIN_TILE_SIZE),
					vertices);
		}
		
		if (CRenderer::IsInitialised())
			g_Renderer.GetWaterManager()->SetMapSize(vertices);

		MakeDirty(0, 0, tiles+1, tiles+1);
	}
Beispiel #2
0
std::vector<entity_id_t> EntitySelection::PickEntitiesInRect(CSimulation2& simulation, const CCamera& camera, int sx0, int sy0, int sx1, int sy1, player_id_t owner, bool allowEditorSelectables)
{
	PROFILE2("PickEntitiesInRect");
	// Make sure sx0 <= sx1, and sy0 <= sy1
	if (sx0 > sx1)
		std::swap(sx0, sx1);
	if (sy0 > sy1)
		std::swap(sy0, sy1);

	CmpPtr<ICmpRangeManager> cmpRangeManager(simulation, SYSTEM_ENTITY);
	ENSURE(cmpRangeManager);

	std::vector<entity_id_t> hitEnts;

	const CSimulation2::InterfaceListUnordered& ents = simulation.GetEntitiesWithInterfaceUnordered(IID_Selectable);
	for (CSimulation2::InterfaceListUnordered::const_iterator it = ents.begin(); it != ents.end(); ++it)
	{
		entity_id_t ent = it->first;
		CEntityHandle handle = it->second->GetEntityHandle();

		// Check if this entity is only selectable in Atlas
		if (static_cast<ICmpSelectable*>(it->second)->IsEditorOnly() && !allowEditorSelectables)
			continue;

		// Ignore entities hidden by LOS (or otherwise hidden, e.g. when not IsInWorld)
		if (cmpRangeManager->GetLosVisibility(handle, owner) == ICmpRangeManager::VIS_HIDDEN)
			continue;

		// Ignore entities not owned by 'owner'
		CmpPtr<ICmpOwnership> cmpOwnership(handle);
		if (owner != INVALID_PLAYER && (!cmpOwnership || cmpOwnership->GetOwner() != owner))
			continue;

		// Find the current interpolated model position.
		// (We just use the centre position and not the whole bounding box, because maybe
		// that's better for users trying to select objects in busy areas)

		CmpPtr<ICmpVisual> cmpVisual(handle);
		if (!cmpVisual)
			continue;

		CVector3D position = cmpVisual->GetPosition();

		// Reject if it's not on-screen (e.g. it's behind the camera)
		if (!camera.GetFrustum().IsPointVisible(position))
			continue;

		// Compare screen-space coordinates
		float x, y;
		camera.GetScreenCoordinates(position, x, y);
		int ix = (int)x;
		int iy = (int)y;
		if (sx0 <= ix && ix <= sx1 && sy0 <= iy && iy <= sy1)
			hitEnts.push_back(ent);
	}

	return hitEnts;
}
Beispiel #3
0
std::vector<entity_id_t> EntitySelection::PickSimilarEntities(CSimulation2& simulation, const CCamera& camera, const std::string& templateName, int owner, bool includeOffScreen, bool matchRank)
{
	CmpPtr<ICmpTemplateManager> cmpTemplateManager(simulation, SYSTEM_ENTITY);
	CmpPtr<ICmpRangeManager> cmpRangeManager(simulation, SYSTEM_ENTITY);

	std::vector<entity_id_t> hitEnts;

 	const CSimulation2::InterfaceListUnordered& ents = simulation.GetEntitiesWithInterfaceUnordered(IID_Selectable);
	for (CSimulation2::InterfaceListUnordered::const_iterator it = ents.begin(); it != ents.end(); ++it)
	{
 		entity_id_t ent = it->first;

		if (matchRank)
		{
			// Exact template name matching
			if (cmpTemplateManager->GetCurrentTemplateName(ent) != templateName)
				continue;
		}

		// Ignore entities hidden by LOS (or otherwise hidden, e.g. when not IsInWorld)
		// In this case, the checking is done to avoid selecting garrisoned units
		if (cmpRangeManager->GetLosVisibility(ent, owner) == ICmpRangeManager::VIS_HIDDEN)
			continue;

 		// Ignore entities not owned by 'owner'
 		CmpPtr<ICmpOwnership> cmpOwnership(simulation.GetSimContext(), ent);
 		if (!cmpOwnership || cmpOwnership->GetOwner() != owner)
 			continue;

		// Ignore off screen entities
 		if (!includeOffScreen)
 		{
 			// Find the current interpolated model position.
			CmpPtr<ICmpVisual> cmpVisual(simulation.GetSimContext(), ent);
			if (!cmpVisual)
				continue;
			CVector3D position = cmpVisual->GetPosition();

			// Reject if it's not on-screen (e.g. it's behind the camera)
			if (!camera.GetFrustum().IsPointVisible(position))
				continue;
 		}

		if (!matchRank)
		{
			// Match by selection group name
			// (This is relatively expensive since it involves script calls, so do it after all other tests)
			CmpPtr<ICmpIdentity> cmpIdentity(simulation.GetSimContext(), ent);
			if (!cmpIdentity || cmpIdentity->GetSelectionGroupName() != templateName)
				continue;
		}

 		hitEnts.push_back(ent);
 	}

 	return hitEnts;
}
Beispiel #4
0
ActorViewer::ActorViewer()
	: m(*new ActorViewerImpl())
{
	m.WalkEnabled = false;
	m.GroundEnabled = true;
	m.WaterEnabled = false;
	m.ShadowsEnabled = g_Renderer.GetOptionBool(CRenderer::OPT_SHADOWS);
	m.SelectionBoxEnabled = false;
	m.AxesMarkerEnabled = false;
	m.PropPointsMode = 0;
	m.Background = SColor4ub(0, 0, 0, 255);

	// Create a tiny empty piece of terrain, just so we can put shadows
	// on it without having to think too hard
	m.Terrain.Initialize(2, NULL);
	CTerrainTextureEntry* tex = g_TexMan.FindTexture("whiteness");
	if (tex)
	{
		for (ssize_t pi = 0; pi < m.Terrain.GetPatchesPerSide(); ++pi)
		{
			for (ssize_t pj = 0; pj < m.Terrain.GetPatchesPerSide(); ++pj)
			{
				CPatch* patch = m.Terrain.GetPatch(pi, pj);
				for (ssize_t i = 0; i < PATCH_SIZE; ++i)
				{
					for (ssize_t j = 0; j < PATCH_SIZE; ++j)
					{
						CMiniPatch& mp = patch->m_MiniPatches[i][j];
						mp.Tex = tex;
						mp.Priority = 0;
					}
				}
			}
		}
	}
	else
	{
		debug_warn(L"Failed to load whiteness texture");
	}

	// Start the simulation
	m.Simulation2.LoadDefaultScripts();
	m.Simulation2.ResetState();

	// Tell the simulation we've already loaded the terrain
	CmpPtr<ICmpTerrain> cmpTerrain(m.Simulation2, SYSTEM_ENTITY);
	if (cmpTerrain)
		cmpTerrain->ReloadTerrain(false);

	// Remove FOW since we're in Atlas
	CmpPtr<ICmpRangeManager> cmpRangeManager(m.Simulation2, SYSTEM_ENTITY);
	if (cmpRangeManager)
		cmpRangeManager->SetLosRevealAll(-1, true);
}
Beispiel #5
0
std::vector<entity_id_t> EntitySelection::PickEntitiesInRect(CSimulation2& simulation, const CCamera& camera, int sx0, int sy0, int sx1, int sy1, int owner)
{
    // Make sure sx0 <= sx1, and sy0 <= sy1
    if (sx0 > sx1)
        std::swap(sx0, sx1);
    if (sy0 > sy1)
        std::swap(sy0, sy1);

    CmpPtr<ICmpRangeManager> cmpRangeManager(simulation, SYSTEM_ENTITY);
    ENSURE(!cmpRangeManager.null());

    std::vector<entity_id_t> hitEnts;

    const CSimulation2::InterfaceListUnordered& ents = simulation.GetEntitiesWithInterfaceUnordered(IID_Selectable);
    for (CSimulation2::InterfaceListUnordered::const_iterator it = ents.begin(); it != ents.end(); ++it)
    {
        entity_id_t ent = it->first;

        // Ignore entities hidden by LOS (or otherwise hidden, e.g. when not IsInWorld)
        if (cmpRangeManager->GetLosVisibility(ent, owner) == ICmpRangeManager::VIS_HIDDEN)
            continue;

        // Ignore entities not owned by 'owner'
        CmpPtr<ICmpOwnership> cmpOwnership(simulation.GetSimContext(), ent);
        if (cmpOwnership.null() || cmpOwnership->GetOwner() != owner)
            continue;

        // Find the current interpolated model position.
        // (We just use the centre position and not the whole bounding box, because maybe
        // that's better for users trying to select objects in busy areas)

        CmpPtr<ICmpVisual> cmpVisual(simulation.GetSimContext(), ent);
        if (cmpVisual.null())
            continue;

        CVector3D position = cmpVisual->GetPosition();

        // Reject if it's not on-screen (e.g. it's behind the camera)

        if (!camera.GetFrustum().IsPointVisible(position))
            continue;

        // Compare screen-space coordinates
        float x, y;
        camera.GetScreenCoordinates(position, x, y);
        int ix = (int)x;
        int iy = (int)y;
        if (sx0 <= ix && ix <= sx1 && sy0 <= iy && iy <= sy1)
            hitEnts.push_back(ent);
    }

    return hitEnts;
}
Beispiel #6
0
std::vector<entity_id_t> EntitySelection::PickEntitiesAtPoint(CSimulation2& simulation, const CCamera& camera, int screenX, int screenY, int player)
{
    CVector3D origin, dir;
    camera.BuildCameraRay(screenX, screenY, origin, dir);

    CmpPtr<ICmpRangeManager> cmpRangeManager(simulation, SYSTEM_ENTITY);
    ENSURE(!cmpRangeManager.null());

    std::vector<std::pair<float, entity_id_t> > hits; // (dist^2, entity) pairs

    const CSimulation2::InterfaceListUnordered& ents = simulation.GetEntitiesWithInterfaceUnordered(IID_Selectable);
    for (CSimulation2::InterfaceListUnordered::const_iterator it = ents.begin(); it != ents.end(); ++it)
    {
        entity_id_t ent = it->first;

        // Ignore entities hidden by LOS (or otherwise hidden, e.g. when not IsInWorld)
        if (cmpRangeManager->GetLosVisibility(ent, player) == ICmpRangeManager::VIS_HIDDEN)
            continue;

        CmpPtr<ICmpVisual> cmpVisual(simulation.GetSimContext(), ent);
        if (cmpVisual.null())
            continue;

        CBound bounds = cmpVisual->GetBounds();

        float tmin, tmax;
        if (!bounds.RayIntersect(origin, dir, tmin, tmax))
            continue;

        // Find the perpendicular distance from the object's centre to the picker ray

        CVector3D centre;
        bounds.GetCentre(centre);

        CVector3D closest = origin + dir * (centre - origin).Dot(dir);
        float dist2 = (closest - centre).LengthSquared();

        hits.push_back(std::make_pair(dist2, ent));
    }

    // Sort hits by distance
    std::sort(hits.begin(), hits.end()); // lexicographic comparison

    // Extract the entity IDs
    std::vector<entity_id_t> hitEnts;
    hitEnts.reserve(hits.size());
    for (size_t i = 0; i < hits.size(); ++i)
        hitEnts.push_back(hits[i].second);
    return hitEnts;
}
Beispiel #7
0
    virtual void PlaySoundGroup(std::wstring name, entity_id_t source)
    {
#if CONFIG2_AUDIO
        // Make sure the sound group is loaded
        CSoundGroup* group;
        if (m_SoundGroups.find(name) == m_SoundGroups.end())
        {
            group = new CSoundGroup();
            if (!group->LoadSoundGroup(L"audio/" + name))
            {
                LOGERROR(L"Failed to load sound group '%ls'", name.c_str());
                delete group;
                group = NULL;
            }
            // Cache the sound group (or the null, if it failed)
            m_SoundGroups[name] = group;
        }
        else
        {
            group = m_SoundGroups[name];
        }

        // Failed to load group -> do nothing
        if (!group)
            return;

        // Only play the sound if the entity is visible
        CmpPtr<ICmpRangeManager> cmpRangeManager(GetSimContext(), SYSTEM_ENTITY);
        ICmpRangeManager::ELosVisibility vis = cmpRangeManager->GetLosVisibility(source, GetSimContext().GetCurrentDisplayedPlayer());

        if (vis == ICmpRangeManager::VIS_VISIBLE)
        {
            // Find the source's position, if possible
            // (TODO: we should do something more sensible if there's no position available)
            CVector3D sourcePos(0, 0, 0);
            if (source != INVALID_ENTITY)
            {
                CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), source);
                if (cmpPosition && cmpPosition->IsInWorld())
                    sourcePos = CVector3D(cmpPosition->GetPosition());
            }

            group->PlayNext(sourcePos);
        }
#else // !CONFIG2_AUDIO
        UNUSED2(name);
        UNUSED2(source);
#endif // !CONFIG2_AUDIO
    }
Beispiel #8
0
void CCinemaManager::SetEnabled(bool enabled)
{
	// TODO: maybe assert?
	if (m_CinematicSimulationData.m_PathQueue.empty() && enabled)
	{
		enabled = false;
		m_CinematicSimulationData.m_Paused = true;
	}

	if (m_CinematicSimulationData.m_Enabled == enabled)
		return;

	// TODO: Enabling/Disabling does not work if the session GUI page is not the top page.
	// This can happen in various situations, for example when the player wins/looses the game
	// while the cinematic is running (a message box is the top page in this case). 
	// It might be better to disable the whole GUI during the cinematic instead of a specific 
	// GUI object.
	
	// sn - session gui object
	IGUIObject *sn = g_GUI->FindObjectByName("sn");
	CmpPtr<ICmpRangeManager> cmpRangeManager(g_Game->GetSimulation2()->GetSimContext().GetSystemEntity());
	CmpPtr<ICmpTerritoryManager> cmpTerritoryManager(g_Game->GetSimulation2()->GetSimContext().GetSystemEntity());

	// GUI visibility
	if (sn)
	{
		if (enabled)
			sn->SetSetting("hidden", L"true");
		else
			sn->SetSetting("hidden", L"false");
	}

	// Overlay visibility
	g_Renderer.SetOptionBool(CRenderer::Option::OPT_SILHOUETTES, !enabled);
	if (cmpRangeManager)
	{
		if (enabled)
			m_CinematicSimulationData.m_MapRevealed = cmpRangeManager->GetLosRevealAll(-1);
		// TODO: improve m_MapRevealed state and without fade in
		cmpRangeManager->SetLosRevealAll(-1, enabled);
	}
	if (cmpTerritoryManager)
		cmpTerritoryManager->SetVisibility(!enabled);
	ICmpSelectable::SetOverrideVisibility(!enabled);
	ICmpOverlayRenderer::SetOverrideVisibility(!enabled);

	m_CinematicSimulationData.m_Enabled = enabled;
}
Beispiel #9
0
void CLOSTexture::RecomputeTexture(int unit)
{
	// If the map was resized, delete and regenerate the texture
	if (m_Texture)
	{
		CmpPtr<ICmpTerrain> cmpTerrain(m_Simulation, SYSTEM_ENTITY);
		if (cmpTerrain && m_MapSize != (ssize_t)cmpTerrain->GetVerticesPerSide())
			DeleteTexture();
	}

	bool recreated = false;
	if (!m_Texture)
	{
		ConstructTexture(unit);
		recreated = true;
	}

	PROFILE("recompute LOS texture");

	std::vector<u8> losData;
	losData.resize(GetBitmapSize(m_MapSize, m_MapSize));

	CmpPtr<ICmpRangeManager> cmpRangeManager(m_Simulation, SYSTEM_ENTITY);
	if (!cmpRangeManager)
		return;

	ICmpRangeManager::CLosQuerier los(cmpRangeManager->GetLosQuerier(g_Game->GetPlayerID()));

	GenerateBitmap(los, &losData[0], m_MapSize, m_MapSize);

	if (CRenderer::IsInitialised() && g_Renderer.m_Options.m_SmoothLOS && recreated)
	{
		g_Renderer.BindTexture(unit, m_TextureSmooth1);		
		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_MapSize + g_BlurSize - 1, m_MapSize + g_BlurSize - 1, GL_ALPHA, GL_UNSIGNED_BYTE, &losData[0]);
		g_Renderer.BindTexture(unit, m_TextureSmooth2);		
		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_MapSize + g_BlurSize - 1, m_MapSize + g_BlurSize - 1, GL_ALPHA, GL_UNSIGNED_BYTE, &losData[0]);
	}

	g_Renderer.BindTexture(unit, m_Texture);
	glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_MapSize + g_BlurSize - 1, m_MapSize + g_BlurSize - 1, GL_ALPHA, GL_UNSIGNED_BYTE, &losData[0]);
}
Beispiel #10
0
	virtual void ReloadTerrain()
	{
		// TODO: should refactor this code to be nicer

		CmpPtr<ICmpObstructionManager> cmpObstructionManager(GetSimContext(), SYSTEM_ENTITY);
		if (!cmpObstructionManager.null())
		{
			cmpObstructionManager->SetBounds(entity_pos_t::Zero(), entity_pos_t::Zero(),
					entity_pos_t::FromInt(m_Terrain->GetTilesPerSide()*CELL_SIZE),
					entity_pos_t::FromInt(m_Terrain->GetTilesPerSide()*CELL_SIZE));
		}

		CmpPtr<ICmpRangeManager> cmpRangeManager(GetSimContext(), SYSTEM_ENTITY);
		if (!cmpRangeManager.null())
		{
			cmpRangeManager->SetBounds(entity_pos_t::Zero(), entity_pos_t::Zero(),
					entity_pos_t::FromInt(m_Terrain->GetTilesPerSide()*CELL_SIZE),
					entity_pos_t::FromInt(m_Terrain->GetTilesPerSide()*CELL_SIZE),
					m_Terrain->GetVerticesPerSide());
		}

		MakeDirty(0, 0, m_Terrain->GetTilesPerSide()+1, m_Terrain->GetTilesPerSide()+1);
	}
Beispiel #11
0
	virtual void PlaySoundGroup(const std::wstring& name, entity_id_t source)
	{
		if ( ! g_SoundManager || (source == INVALID_ENTITY) )
			return;

		CmpPtr<ICmpRangeManager> cmpRangeManager(GetSystemEntity());
		int currentPlayer = GetSimContext().GetCurrentDisplayedPlayer();

		if ( !cmpRangeManager || 
				( cmpRangeManager->GetLosVisibility(source, currentPlayer) != ICmpRangeManager::VIS_VISIBLE ) )
			return;

		CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), source);
		if (cmpPosition && cmpPosition->IsInWorld())
		{
			bool playerOwned = false;
			CmpPtr<ICmpOwnership> cmpOwnership( GetSimContext(), source);
			if (cmpOwnership)
				playerOwned = cmpOwnership->GetOwner() == currentPlayer;

			CVector3D sourcePos = CVector3D(cmpPosition->GetPosition());
			g_SoundManager->PlayAsGroup(name, sourcePos, source, playerOwned);
		}
	}
Beispiel #12
0
std::vector<entity_id_t> EntitySelection::PickEntitiesAtPoint(CSimulation2& simulation, const CCamera& camera, int screenX, int screenY, player_id_t player, bool allowEditorSelectables)
{
	CVector3D origin, dir;
	camera.BuildCameraRay(screenX, screenY, origin, dir);

	CmpPtr<ICmpRangeManager> cmpRangeManager(simulation, SYSTEM_ENTITY);
	ENSURE(cmpRangeManager);

	std::vector<std::pair<float, entity_id_t> > hits; // (dist^2, entity) pairs

	const CSimulation2::InterfaceListUnordered& ents = simulation.GetEntitiesWithInterfaceUnordered(IID_Selectable);
	for (CSimulation2::InterfaceListUnordered::const_iterator it = ents.begin(); it != ents.end(); ++it)
	{
		entity_id_t ent = it->first;

		// Check if this entity is only selectable in Atlas
		if (!allowEditorSelectables && static_cast<ICmpSelectable*>(it->second)->IsEditorOnly())
			continue;

		// Ignore entities hidden by LOS (or otherwise hidden, e.g. when not IsInWorld)
		if (cmpRangeManager->GetLosVisibility(ent, player) == ICmpRangeManager::VIS_HIDDEN)
			continue;

		CmpPtr<ICmpVisual> cmpVisual(simulation.GetSimContext(), ent);
		if (!cmpVisual)
			continue;

		CVector3D center;
		float tmin, tmax;

		CBoundingBoxOriented selectionBox = cmpVisual->GetSelectionBox();
		if (selectionBox.IsEmpty())
		{
			if (!allowEditorSelectables)
				continue;

			// Fall back to using old AABB selection method for decals
			//	see: http://trac.wildfiregames.com/ticket/1032
			CBoundingBoxAligned aABBox = cmpVisual->GetBounds();
			if (aABBox.IsEmpty())
				continue;

			if (!aABBox.RayIntersect(origin, dir, tmin, tmax))
				continue;

			aABBox.GetCentre(center);
		}
		else
		{
			if (!selectionBox.RayIntersect(origin, dir, tmin, tmax))
				continue;

			center = selectionBox.m_Center;
		}

		// Find the perpendicular distance from the object's centre to the picker ray

		float dist2;
		CVector3D closest = origin + dir * (center - origin).Dot(dir);
		dist2 = (closest - center).LengthSquared();

		hits.push_back(std::make_pair(dist2, ent));
	}

	// Sort hits by distance
	std::sort(hits.begin(), hits.end()); // lexicographic comparison

	// Extract the entity IDs
	std::vector<entity_id_t> hitEnts;
	hitEnts.reserve(hits.size());
	for (size_t i = 0; i < hits.size(); ++i)
		hitEnts.push_back(hits[i].second);
	return hitEnts;
}
Beispiel #13
0
std::vector<entity_id_t> EntitySelection::PickEntitiesAtPoint(CSimulation2& simulation, const CCamera& camera, int screenX, int screenY, player_id_t player, bool allowEditorSelectables, int range)
{
	PROFILE2("PickEntitiesAtPoint");
	CVector3D origin, dir;
	camera.BuildCameraRay(screenX, screenY, origin, dir);

	CmpPtr<ICmpRangeManager> cmpRangeManager(simulation, SYSTEM_ENTITY);
	ENSURE(cmpRangeManager);

	/* We try to approximate where the mouse is hovering by drawing a ray from
	 * the center of the camera and through the mouse then taking the position
	 * at which the ray intersects the terrain.                               */
	// TODO: Do this smarter without being slow.
	CVector3D pos3d = camera.GetWorldCoordinates(screenX, screenY, true);
	// Change the position to 2D by removing the terrain height.
	CFixedVector2D pos(fixed::FromFloat(pos3d.X), fixed::FromFloat(pos3d.Z));

	// Get a rough group of entities using our approximated origin.
	SpatialQueryArray ents;
	cmpRangeManager->GetSubdivision()->GetNear(ents, pos, entity_pos_t::FromInt(range));

	// Filter for relevent entities and calculate precise distances.
	std::vector<std::pair<float, entity_id_t> > hits; // (dist^2, entity) pairs
	for (int i = 0; i < ents.size(); ++i)
	{
		CmpPtr<ICmpSelectable> cmpSelectable(simulation, ents[i]);
		if (!cmpSelectable)
			continue;

		CEntityHandle handle = cmpSelectable->GetEntityHandle();

		// Check if this entity is only selectable in Atlas
		if (!allowEditorSelectables && cmpSelectable->IsEditorOnly())
			continue;

		// Ignore entities hidden by LOS (or otherwise hidden, e.g. when not IsInWorld)
		if (cmpRangeManager->GetLosVisibility(handle, player) == ICmpRangeManager::VIS_HIDDEN)
			continue;

		CmpPtr<ICmpVisual> cmpVisual(handle);
		if (!cmpVisual)
			continue;

		CVector3D center;
		float tmin, tmax;

		CBoundingBoxOriented selectionBox = cmpVisual->GetSelectionBox();
		if (selectionBox.IsEmpty())
		{
			if (!allowEditorSelectables)
				continue;

			// Fall back to using old AABB selection method for decals
			//	see: http://trac.wildfiregames.com/ticket/1032
			CBoundingBoxAligned aABBox = cmpVisual->GetBounds();
			if (aABBox.IsEmpty())
				continue;

			if (!aABBox.RayIntersect(origin, dir, tmin, tmax))
				continue;

			aABBox.GetCentre(center);
		}
		else
		{
			if (!selectionBox.RayIntersect(origin, dir, tmin, tmax))
				continue;

			center = selectionBox.m_Center;
		}

		// Find the perpendicular distance from the object's centre to the picker ray
		float dist2;
		CVector3D closest = origin + dir * (center - origin).Dot(dir);
		dist2 = (closest - center).LengthSquared();

		hits.push_back(std::make_pair(dist2, ents[i]));
	}

	// Sort hits by distance
	std::sort(hits.begin(), hits.end()); // lexicographic comparison

	// Extract the entity IDs
	std::vector<entity_id_t> hitEnts;
	hitEnts.reserve(hits.size());
	for (size_t i = 0; i < hits.size(); ++i)
		hitEnts.push_back(hits[i].second);
	return hitEnts;
}
Beispiel #14
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]);
 */
}
Beispiel #15
0
// TODO: render the minimap in a framebuffer and just draw the frambuffer texture
//	most of the time, updating the framebuffer twice a frame.
// Here it updates as ping-pong either texture or vertex array each sec to lower gpu stalling
// (those operations cause a gpu sync, which slows down the way gpu works)
void CMiniMap::Draw()
{
	PROFILE3("render minimap");

	// The terrain isn't actually initialized until the map is loaded, which
	// happens when the game is started, so abort until then.
	if (!(GetGUI() && g_Game && g_Game->IsGameStarted()))
		return;

	CSimulation2* sim = g_Game->GetSimulation2();
	CmpPtr<ICmpRangeManager> cmpRangeManager(*sim, SYSTEM_ENTITY);
	ENSURE(cmpRangeManager);

	// Set our globals in case they hadn't been set before
	m_Camera = g_Game->GetView()->GetCamera();
	m_Terrain = g_Game->GetWorld()->GetTerrain();
	m_Width  = (u32)(m_CachedActualSize.right - m_CachedActualSize.left);
	m_Height = (u32)(m_CachedActualSize.bottom - m_CachedActualSize.top);
	m_MapSize = m_Terrain->GetVerticesPerSide();
	m_TextureSize = (GLsizei)round_up_to_pow2((size_t)m_MapSize);
	m_MapScale = (cmpRangeManager->GetLosCircular() ? 1.f : 1.414f);

	if (!m_TerrainTexture || g_GameRestarted)
		CreateTextures();


	// only update 2x / second
	// (note: since units only move a few pixels per second on the minimap,
	// we can get away with infrequent updates; this is slow)
	// TODO: Update all but camera at same speed as simulation
	static double last_time;
	const double cur_time = timer_Time();
	const bool doUpdate = cur_time - last_time > 0.5;
	if (doUpdate)
	{
		last_time = cur_time;
		if (m_TerrainDirty)
			RebuildTerrainTexture();
	}

	const float x = m_CachedActualSize.left, y = m_CachedActualSize.bottom;
	const float x2 = m_CachedActualSize.right, y2 = m_CachedActualSize.top;
	const float z = GetBufferedZ();
	const float texCoordMax = (float)(m_MapSize - 1) / (float)m_TextureSize;
	const float angle = GetAngle();
	const float unitScale = (cmpRangeManager->GetLosCircular() ? 1.f : m_MapScale/2.f);

	// Disable depth updates to prevent apparent z-fighting-related issues
	//  with some drivers causing units to get drawn behind the texture.
	glDepthMask(0);

	CShaderProgramPtr shader;
	CShaderTechniquePtr tech;

	CShaderDefines baseDefines;
	baseDefines.Add(str_MINIMAP_BASE, str_1);
	tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), baseDefines);
	tech->BeginPass();
	shader = tech->GetShader();

	// Draw the main textured quad
	shader->BindTexture(str_baseTex, m_TerrainTexture);
	const CMatrix3D baseTransform = GetDefaultGuiMatrix();
	CMatrix3D baseTextureTransform;
	baseTextureTransform.SetIdentity();
	shader->Uniform(str_transform, baseTransform);
	shader->Uniform(str_textureTransform, baseTextureTransform);

	DrawTexture(shader, texCoordMax, angle, x, y, x2, y2, z);

	// Draw territory boundaries
	glEnable(GL_BLEND);

	CTerritoryTexture& territoryTexture = g_Game->GetView()->GetTerritoryTexture();

	shader->BindTexture(str_baseTex, territoryTexture.GetTexture());
	const CMatrix3D* territoryTransform = territoryTexture.GetMinimapTextureMatrix();
	shader->Uniform(str_transform, baseTransform);
	shader->Uniform(str_textureTransform, *territoryTransform);

	DrawTexture(shader, 1.0f, angle, x, y, x2, y2, z);
	tech->EndPass();

	// Draw the LOS quad in black, using alpha values from the LOS texture
	CLOSTexture& losTexture = g_Game->GetView()->GetLOSTexture();

	CShaderDefines losDefines;
	losDefines.Add(str_MINIMAP_LOS, str_1);
	tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), losDefines);
	tech->BeginPass();
	shader = tech->GetShader();
	shader->BindTexture(str_baseTex, losTexture.GetTexture());

	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	const CMatrix3D* losTransform = losTexture.GetMinimapTextureMatrix();
	shader->Uniform(str_transform, baseTransform);
	shader->Uniform(str_textureTransform, *losTransform);

	DrawTexture(shader, 1.0f, angle, x, y, x2, y2, z);
	tech->EndPass();

	glDisable(GL_BLEND);

	PROFILE_START("minimap units");

	CShaderDefines pointDefines;
	pointDefines.Add(str_MINIMAP_POINT, str_1);
	tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), pointDefines);
	tech->BeginPass();
	shader = tech->GetShader();
	shader->Uniform(str_transform, baseTransform);
	shader->Uniform(str_pointSize, 3.f);

	CMatrix3D unitMatrix;
	unitMatrix.SetIdentity();
	// Center the minimap on the origin of the axis of rotation.
	unitMatrix.Translate(-(x2 - x) / 2.f, -(y2 - y) / 2.f, 0.f);
	// Rotate the map.
	unitMatrix.RotateZ(angle);
	// Scale square maps to fit.
	unitMatrix.Scale(unitScale, unitScale, 1.f);
	// Move the minimap back to it's starting position.
	unitMatrix.Translate((x2 - x) / 2.f, (y2 - y) / 2.f, 0.f);
	// Move the minimap to it's final location.
	unitMatrix.Translate(x, y, z);
	// Apply the gui matrix.
	unitMatrix *= GetDefaultGuiMatrix();
	// Load the transform into the shader.
	shader->Uniform(str_transform, unitMatrix);

	const float sx = (float)m_Width / ((m_MapSize - 1) * TERRAIN_TILE_SIZE);
	const float sy = (float)m_Height / ((m_MapSize - 1) * TERRAIN_TILE_SIZE);

	CSimulation2::InterfaceList ents = sim->GetEntitiesWithInterface(IID_Minimap);

	if (doUpdate)
	{
		VertexArrayIterator<float[2]> attrPos = m_AttributePos.GetIterator<float[2]>();
		VertexArrayIterator<u8[4]> attrColor = m_AttributeColor.GetIterator<u8[4]>();

		m_EntitiesDrawn = 0;
		MinimapUnitVertex v;
		std::vector<MinimapUnitVertex> pingingVertices;
		pingingVertices.reserve(MAX_ENTITIES_DRAWN / 2);

		if (cur_time > m_NextBlinkTime)
		{
			m_BlinkState = !m_BlinkState;
			m_NextBlinkTime = cur_time + m_HalfBlinkDuration;
		}

		entity_pos_t posX, posZ;
		for (CSimulation2::InterfaceList::const_iterator it = ents.begin(); it != ents.end(); ++it)
		{
			ICmpMinimap* cmpMinimap = static_cast<ICmpMinimap*>(it->second);
			if (cmpMinimap->GetRenderData(v.r, v.g, v.b, posX, posZ))
			{
				ICmpRangeManager::ELosVisibility vis = cmpRangeManager->GetLosVisibility(it->first, g_Game->GetPlayerID());
				if (vis != ICmpRangeManager::VIS_HIDDEN)
				{
					v.a = 255;
					v.x = posX.ToFloat() * sx;
					v.y = -posZ.ToFloat() * sy;

					// Check minimap pinging to indicate something
					if (m_BlinkState && cmpMinimap->CheckPing(cur_time, m_PingDuration))
					{
						v.r = 255; // ping color is white
						v.g = 255;
						v.b = 255;
						pingingVertices.push_back(v);
					}
					else
					{
						addVertex(v, attrColor, attrPos);
						++m_EntitiesDrawn;
					}
				}
			}
		}

		// Add the pinged vertices at the end, so they are drawn on top
		for (size_t v = 0; v < pingingVertices.size(); ++v)
		{
			addVertex(pingingVertices[v], attrColor, attrPos);
			++m_EntitiesDrawn;
		}

		ENSURE(m_EntitiesDrawn < MAX_ENTITIES_DRAWN);
		m_VertexArray.Upload();
	}

	m_VertexArray.PrepareForRendering();

	if (m_EntitiesDrawn > 0)
	{
#if !CONFIG2_GLES
		if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER)
			glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
#endif

		u8* indexBase = m_IndexArray.Bind();
		u8* base = m_VertexArray.Bind();
		const GLsizei stride = (GLsizei)m_VertexArray.GetStride();

		shader->VertexPointer(2, GL_FLOAT, stride, base + m_AttributePos.offset);
		shader->ColorPointer(4, GL_UNSIGNED_BYTE, stride, base + m_AttributeColor.offset);
		shader->AssertPointersBound();

		if (!g_Renderer.m_SkipSubmit)
			glDrawElements(GL_POINTS, (GLsizei)(m_EntitiesDrawn), GL_UNSIGNED_SHORT, indexBase);

		g_Renderer.GetStats().m_DrawCalls++;
		CVertexBuffer::Unbind();

#if !CONFIG2_GLES
		if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER)
			glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
#endif
	}

	tech->EndPass();

	DrawViewRect(unitMatrix);

	PROFILE_END("minimap units");

	// Reset depth mask
	glDepthMask(1);
}
Beispiel #16
0
void CMiniMap::Draw()
{
	PROFILE3("render minimap");

	// The terrain isn't actually initialized until the map is loaded, which
	// happens when the game is started, so abort until then.
	if(!(GetGUI() && g_Game && g_Game->IsGameStarted()))
		return;

	CSimulation2* sim = g_Game->GetSimulation2();
	CmpPtr<ICmpRangeManager> cmpRangeManager(*sim, SYSTEM_ENTITY);
	ENSURE(cmpRangeManager);

	// Set our globals in case they hadn't been set before
	m_Camera      = g_Game->GetView()->GetCamera();
	m_Terrain     = g_Game->GetWorld()->GetTerrain();
	m_Width  = (u32)(m_CachedActualSize.right - m_CachedActualSize.left);
	m_Height = (u32)(m_CachedActualSize.bottom - m_CachedActualSize.top);
	m_MapSize = m_Terrain->GetVerticesPerSide();
	m_TextureSize = (GLsizei)round_up_to_pow2((size_t)m_MapSize);
	m_MapScale = (cmpRangeManager->GetLosCircular() ? 1.f : 1.414f);

	if(!m_TerrainTexture || g_GameRestarted)
		CreateTextures();


	// only update 2x / second
	// (note: since units only move a few pixels per second on the minimap,
	// we can get away with infrequent updates; this is slow)
	static double last_time;
	const double cur_time = timer_Time();
	if(cur_time - last_time > 0.5)
	{
		last_time = cur_time;

		if(m_TerrainDirty)
			RebuildTerrainTexture();
	}

	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glLoadIdentity();
	glMatrixMode(GL_MODELVIEW);
	glPushMatrix();
	CMatrix3D matrix = GetDefaultGuiMatrix();
	glLoadMatrixf(&matrix._11);

	// Disable depth updates to prevent apparent z-fighting-related issues
	// with some drivers causing units to get drawn behind the texture
	glDepthMask(0);

	const float x = m_CachedActualSize.left, y = m_CachedActualSize.bottom;
	const float x2 = m_CachedActualSize.right, y2 = m_CachedActualSize.top;
	const float z = GetBufferedZ();
	const float texCoordMax = (float)(m_MapSize - 1) / (float)m_TextureSize;
	const float angle = GetAngle();

	// Draw the main textured quad
	g_Renderer.BindTexture(0, m_TerrainTexture);
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	DrawTexture(texCoordMax, angle, x, y, x2, y2, z);


	// Draw territory boundaries
	CTerritoryTexture& territoryTexture = g_Game->GetView()->GetTerritoryTexture();
	territoryTexture.BindTexture(0);
	glEnable(GL_BLEND);
	glMatrixMode(GL_TEXTURE);
	glLoadMatrixf(territoryTexture.GetMinimapTextureMatrix());
	glMatrixMode(GL_MODELVIEW);

	DrawTexture(1.0f, angle, x, y, x2, y2, z);

	glMatrixMode(GL_TEXTURE);
	glLoadIdentity();
	glMatrixMode(GL_MODELVIEW);
	glDisable(GL_BLEND);


	// Draw the LOS quad in black, using alpha values from the LOS texture
	CLOSTexture& losTexture = g_Game->GetView()->GetLOSTexture();
	losTexture.BindTexture(0);
	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
	glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR_ARB);
	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
	glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_ONE_MINUS_SRC_ALPHA);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glColor3f(0.0f, 0.0f, 0.0f);

	glMatrixMode(GL_TEXTURE);
	glLoadMatrixf(losTexture.GetMinimapTextureMatrix());
	glMatrixMode(GL_MODELVIEW);

	DrawTexture(1.0f, angle, x, y, x2, y2, z);

	glMatrixMode(GL_TEXTURE);
	glLoadIdentity();
	glMatrixMode(GL_MODELVIEW);

	glDisable(GL_BLEND);

	// Set up the matrix for drawing points and lines
	glPushMatrix();
	glTranslatef(x, y, z);
	// Rotate around the center of the map
	glTranslatef((x2-x)/2.f, (y2-y)/2.f, 0.f);
	// Scale square maps to fit in circular minimap area
	float unitScale = (cmpRangeManager->GetLosCircular() ? 1.f : m_MapScale/2.f);
	glScalef(unitScale, unitScale, 1.f);
	glRotatef(angle * 180.f/M_PI, 0.f, 0.f, 1.f);
	glTranslatef(-(x2-x)/2.f, -(y2-y)/2.f, 0.f);

	PROFILE_START("minimap units");

	// Don't enable GL_POINT_SMOOTH because it's far too slow
	// (~70msec/frame on a GF4 rendering a thousand points)
	glPointSize(3.f);

	float sx = (float)m_Width / ((m_MapSize - 1) * TERRAIN_TILE_SIZE);
	float sy = (float)m_Height / ((m_MapSize - 1) * TERRAIN_TILE_SIZE);

	CSimulation2::InterfaceList ents = sim->GetEntitiesWithInterface(IID_Minimap);

	std::vector<MinimapUnitVertex> vertexArray;
	vertexArray.reserve(ents.size());

	for (CSimulation2::InterfaceList::const_iterator it = ents.begin(); it != ents.end(); ++it)
	{
		MinimapUnitVertex v;
		ICmpMinimap* cmpMinimap = static_cast<ICmpMinimap*>(it->second);
		entity_pos_t posX, posZ;
		if (cmpMinimap->GetRenderData(v.r, v.g, v.b, posX, posZ))
		{
			ICmpRangeManager::ELosVisibility vis = cmpRangeManager->GetLosVisibility(it->first, g_Game->GetPlayerID());
			if (vis != ICmpRangeManager::VIS_HIDDEN)
			{
				v.a = 255;
				v.x = posX.ToFloat()*sx;
				v.y = -posZ.ToFloat()*sy;
				vertexArray.push_back(v);
			}
		}
	}

	if (!vertexArray.empty())
	{
		glEnableClientState(GL_VERTEX_ARRAY);
		glEnableClientState(GL_COLOR_ARRAY);
		glVertexPointer(2, GL_FLOAT, sizeof(MinimapUnitVertex), &vertexArray[0].x);
		glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(MinimapUnitVertex), &vertexArray[0].r);

		glDrawArrays(GL_POINTS, 0, (GLsizei)vertexArray.size());

		glDisableClientState(GL_COLOR_ARRAY);
		glDisableClientState(GL_VERTEX_ARRAY);
	}

	PROFILE_END("minimap units");

	DrawViewRect();

	glPopMatrix();


	glMatrixMode(GL_PROJECTION);
	glPopMatrix();
	glMatrixMode(GL_MODELVIEW);
	glPopMatrix();

	// Reset everything back to normal
	glPointSize(1.0f);
	glEnable(GL_TEXTURE_2D);
	glDepthMask(1);
}
Beispiel #17
0
// TODO: render the minimap in a framebuffer and just draw the frambuffer texture
//	most of the time, updating the framebuffer twice a frame.
// Here it updates as ping-pong either texture or vertex array each sec to lower gpu stalling
// (those operations cause a gpu sync, which slows down the way gpu works)
void CMiniMap::Draw()
{
	PROFILE3("render minimap");

	// The terrain isn't actually initialized until the map is loaded, which
	// happens when the game is started, so abort until then.
	if(!(GetGUI() && g_Game && g_Game->IsGameStarted()))
		return;

	CSimulation2* sim = g_Game->GetSimulation2();
	CmpPtr<ICmpRangeManager> cmpRangeManager(*sim, SYSTEM_ENTITY);
	ENSURE(cmpRangeManager);

	// Set our globals in case they hadn't been set before
	m_Camera      = g_Game->GetView()->GetCamera();
	m_Terrain     = g_Game->GetWorld()->GetTerrain();
	m_Width  = (u32)(m_CachedActualSize.right - m_CachedActualSize.left);
	m_Height = (u32)(m_CachedActualSize.bottom - m_CachedActualSize.top);
	m_MapSize = m_Terrain->GetVerticesPerSide();
	m_TextureSize = (GLsizei)round_up_to_pow2((size_t)m_MapSize);
	m_MapScale = (cmpRangeManager->GetLosCircular() ? 1.f : 1.414f);

	if(!m_TerrainTexture || g_GameRestarted)
		CreateTextures();


	// only update 2x / second
	// (note: since units only move a few pixels per second on the minimap,
	// we can get away with infrequent updates; this is slow)
	// TODO: store frequency in a config file?
	static double last_time;
	const double cur_time = timer_Time();
	const bool doUpdate = cur_time - last_time > 0.5;
	if(doUpdate)
	{	
		last_time = cur_time;
		if(m_TerrainDirty)
			RebuildTerrainTexture();
	}

	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glLoadIdentity();
	glMatrixMode(GL_MODELVIEW);
	glPushMatrix();
	CMatrix3D matrix = GetDefaultGuiMatrix();
	glLoadMatrixf(&matrix._11);

	// Disable depth updates to prevent apparent z-fighting-related issues
	// with some drivers causing units to get drawn behind the texture
	glDepthMask(0);
	
	CShaderProgramPtr shader;
	CShaderTechniquePtr tech;
	
	if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER)
	{
		CShaderDefines defines;
		defines.Add(str_MINIMAP_BASE, str_1);
		tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), defines);
		tech->BeginPass();
		shader = tech->GetShader();
	}

	const float x = m_CachedActualSize.left, y = m_CachedActualSize.bottom;
	const float x2 = m_CachedActualSize.right, y2 = m_CachedActualSize.top;
	const float z = GetBufferedZ();
	const float texCoordMax = (float)(m_MapSize - 1) / (float)m_TextureSize;
	const float angle = GetAngle();

	// Draw the main textured quad
	if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER)
		shader->BindTexture(str_baseTex, m_TerrainTexture);
	else
		g_Renderer.BindTexture(0, m_TerrainTexture);
	
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	DrawTexture(shader, texCoordMax, angle, x, y, x2, y2, z);


	// Draw territory boundaries
	CTerritoryTexture& territoryTexture = g_Game->GetView()->GetTerritoryTexture();
	
	if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER)
		shader->BindTexture(str_baseTex, territoryTexture.GetTexture());
	else
		territoryTexture.BindTexture(0);
	
	glEnable(GL_BLEND);
	glMatrixMode(GL_TEXTURE);
	glLoadMatrixf(territoryTexture.GetMinimapTextureMatrix());
	glMatrixMode(GL_MODELVIEW);

	DrawTexture(shader, 1.0f, angle, x, y, x2, y2, z);

	glMatrixMode(GL_TEXTURE);
	glLoadIdentity();
	glMatrixMode(GL_MODELVIEW);
	glDisable(GL_BLEND);


	// Draw the LOS quad in black, using alpha values from the LOS texture
	CLOSTexture& losTexture = g_Game->GetView()->GetLOSTexture();
	
	if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER)
	{
		tech->EndPass();

		CShaderDefines defines;
		defines.Add(str_MINIMAP_LOS, str_1);
		tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), defines);
		tech->BeginPass();
		shader = tech->GetShader();
		shader->BindTexture(str_baseTex, losTexture.GetTexture());
	}
	else
	{
		losTexture.BindTexture(0);
	}
	
	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
	glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR_ARB);
	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
	glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_ONE_MINUS_SRC_ALPHA);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glColor3f(0.0f, 0.0f, 0.0f);

	glMatrixMode(GL_TEXTURE);
	glLoadMatrixf(losTexture.GetMinimapTextureMatrix());
	glMatrixMode(GL_MODELVIEW);

	DrawTexture(shader, 1.0f, angle, x, y, x2, y2, z);

	glMatrixMode(GL_TEXTURE);
	glLoadIdentity();
	glMatrixMode(GL_MODELVIEW);

	glDisable(GL_BLEND);
	
	if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER)
	{
		tech->EndPass();

		CShaderDefines defines;
		defines.Add(str_MINIMAP_POINT, str_1);
		tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), defines);
		tech->BeginPass();
		shader = tech->GetShader();
	}
	
	// Set up the matrix for drawing points and lines
	glPushMatrix();
	glTranslatef(x, y, z);
	// Rotate around the center of the map
	glTranslatef((x2-x)/2.f, (y2-y)/2.f, 0.f);
	// Scale square maps to fit in circular minimap area
	float unitScale = (cmpRangeManager->GetLosCircular() ? 1.f : m_MapScale/2.f);
	glScalef(unitScale, unitScale, 1.f);
	glRotatef(angle * 180.f/M_PI, 0.f, 0.f, 1.f);
	glTranslatef(-(x2-x)/2.f, -(y2-y)/2.f, 0.f);

	PROFILE_START("minimap units");


	const float sx = (float)m_Width / ((m_MapSize - 1) * TERRAIN_TILE_SIZE);
	const float sy = (float)m_Height / ((m_MapSize - 1) * TERRAIN_TILE_SIZE);

	CSimulation2::InterfaceList ents = sim->GetEntitiesWithInterface(IID_Minimap);

	if (doUpdate)
	{

		VertexArrayIterator<float[2]> attrPos = m_AttributePos.GetIterator<float[2]>();
		VertexArrayIterator<u8[4]> attrColor = m_AttributeColor.GetIterator<u8[4]>();

		m_EntitiesDrawn = 0;
		MinimapUnitVertex v;
		std::vector<MinimapUnitVertex> pingingVertices;
		pingingVertices.reserve(MAX_ENTITIES_DRAWN/2);

		const double time = timer_Time();

		if (time > m_NextBlinkTime)
		{
			m_BlinkState = !m_BlinkState;
			m_NextBlinkTime = time + m_HalfBlinkDuration;
		}

		entity_pos_t posX, posZ;
		for (CSimulation2::InterfaceList::const_iterator it = ents.begin(); it != ents.end(); ++it)
		{
			ICmpMinimap* cmpMinimap = static_cast<ICmpMinimap*>(it->second);
			if (cmpMinimap->GetRenderData(v.r, v.g, v.b, posX, posZ))
			{
				ICmpRangeManager::ELosVisibility vis = cmpRangeManager->GetLosVisibility(it->first, g_Game->GetPlayerID());
				if (vis != ICmpRangeManager::VIS_HIDDEN)
				{
					v.a = 255;
					v.x = posX.ToFloat()*sx;
					v.y = -posZ.ToFloat()*sy;
					
					// Check minimap pinging to indicate something
					if (m_BlinkState && cmpMinimap->CheckPing(time, m_PingDuration))
					{
						v.r = 255; // ping color is white
						v.g = 255;
						v.b = 255;

						pingingVertices.push_back(v);
					}
					else
					{
						addVertex(v, attrColor, attrPos);
						++m_EntitiesDrawn;
					}
				}
			}
		}

		// Add the pinged vertices at the end, so they are drawn on top
		for (size_t v = 0; v < pingingVertices.size(); ++v)
		{
			addVertex(pingingVertices[v], attrColor, attrPos);
			++m_EntitiesDrawn;
		}

		ENSURE(m_EntitiesDrawn < MAX_ENTITIES_DRAWN);
		m_VertexArray.Upload();
	}

	if (m_EntitiesDrawn > 0)
	{		
		// Don't enable GL_POINT_SMOOTH because it's far too slow
		// (~70msec/frame on a GF4 rendering a thousand points)
		glPointSize(3.f);

		u8* indexBase = m_IndexArray.Bind();
		u8* base = m_VertexArray.Bind();
		const GLsizei stride = (GLsizei)m_VertexArray.GetStride();

		if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER)
		{
			shader->VertexPointer(2, GL_FLOAT, stride, base + m_AttributePos.offset);
			shader->ColorPointer(4, GL_UNSIGNED_BYTE, stride, base + m_AttributeColor.offset);
			shader->AssertPointersBound();
		}
		else
		{	
			glEnableClientState(GL_VERTEX_ARRAY);
			glEnableClientState(GL_COLOR_ARRAY);

			glDisable(GL_TEXTURE_2D);
			glVertexPointer(2, GL_FLOAT, stride, base + m_AttributePos.offset);
			glColorPointer(4, GL_UNSIGNED_BYTE, stride, base + m_AttributeColor.offset);
		}
		
		if (!g_Renderer.m_SkipSubmit)
		{
			glDrawElements(GL_POINTS, (GLsizei)(m_EntitiesDrawn), GL_UNSIGNED_SHORT, indexBase);
		}

		
		g_Renderer.GetStats().m_DrawCalls++;
		CVertexBuffer::Unbind();
	}

	PROFILE_END("minimap units");

	if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER)
	{
		tech->EndPass();

		CShaderDefines defines;
		defines.Add(str_MINIMAP_LINE, str_1);
		tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), defines);
		tech->BeginPass();
		shader = tech->GetShader();
	}
	else
	{
		glEnable(GL_TEXTURE_2D);
		glDisableClientState(GL_VERTEX_ARRAY);
		glDisableClientState(GL_COLOR_ARRAY);
	}

	DrawViewRect();

	glPopMatrix();
	
	glMatrixMode(GL_PROJECTION);
	glPopMatrix();
	glMatrixMode(GL_MODELVIEW);
	glPopMatrix();
	
	if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER)
	{
		tech->EndPass();
	}

	// Reset everything back to normal
	glPointSize(1.0f);
	glEnable(GL_TEXTURE_2D);
	glDepthMask(1);
}
Beispiel #18
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();
}
Beispiel #19
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]);
}
Beispiel #20
0
std::vector<entity_id_t> EntitySelection::PickSimilarEntities(CSimulation2& simulation, const CCamera& camera, 
	const std::string& templateName, player_id_t owner, bool includeOffScreen, bool matchRank,
	bool allowEditorSelectables, bool allowFoundations)
{
	PROFILE2("PickSimilarEntities");
	CmpPtr<ICmpTemplateManager> cmpTemplateManager(simulation, SYSTEM_ENTITY);
	CmpPtr<ICmpRangeManager> cmpRangeManager(simulation, SYSTEM_ENTITY);

	std::vector<entity_id_t> hitEnts;

 	const CSimulation2::InterfaceListUnordered& ents = simulation.GetEntitiesWithInterfaceUnordered(IID_Selectable);
	for (CSimulation2::InterfaceListUnordered::const_iterator it = ents.begin(); it != ents.end(); ++it)
	{
 		entity_id_t ent = it->first;
		CEntityHandle handle = it->second->GetEntityHandle();

		// Check if this entity is only selectable in Atlas
		if (static_cast<ICmpSelectable*>(it->second)->IsEditorOnly() && !allowEditorSelectables)
			continue;

		if (matchRank)
		{
			// Exact template name matching, optionally also allowing foundations
			std::string curTemplateName = cmpTemplateManager->GetCurrentTemplateName(ent);
			bool matches = (curTemplateName == templateName ||
			                (allowFoundations && curTemplateName.substr(0, 11) == "foundation|" && curTemplateName.substr(11) == templateName));
			if (!matches)
				continue;
		}

		// Ignore entities hidden by LOS (or otherwise hidden, e.g. when not IsInWorld)
		// In this case, the checking is done to avoid selecting garrisoned units
		if (cmpRangeManager->GetLosVisibility(handle, owner) == ICmpRangeManager::VIS_HIDDEN)
			continue;

		// Ignore entities not owned by 'owner'
		CmpPtr<ICmpOwnership> cmpOwnership(simulation.GetSimContext(), ent);
		if (owner != INVALID_PLAYER && (!cmpOwnership || cmpOwnership->GetOwner() != owner))
			continue;

		// Ignore off screen entities
		if (!includeOffScreen)
		{
 			// Find the current interpolated model position.
			CmpPtr<ICmpVisual> cmpVisual(simulation.GetSimContext(), ent);
			if (!cmpVisual)
				continue;
			CVector3D position = cmpVisual->GetPosition();

			// Reject if it's not on-screen (e.g. it's behind the camera)
			if (!camera.GetFrustum().IsPointVisible(position))
				continue;
		}

		if (!matchRank)
		{
			// Match by selection group name
			// (This is relatively expensive since it involves script calls, so do it after all other tests)
			CmpPtr<ICmpIdentity> cmpIdentity(simulation.GetSimContext(), ent);
			if (!cmpIdentity || cmpIdentity->GetSelectionGroupName() != templateName)
				continue;
		}

 		hitEnts.push_back(ent);
 	}

 	return hitEnts;
}