diff --git a/source/graphics/GameView.cpp b/source/graphics/GameView.cpp index 9e82ac2839..562b45f738 100755 --- a/source/graphics/GameView.cpp +++ b/source/graphics/GameView.cpp @@ -172,16 +172,19 @@ void CGameView::RenderModels(CUnitManager *pUnitMan, CProjectileManager *pProjec if (frustum.IsBoxVisible(CVector3D(0,0,0), units[i]->GetModel()->GetBounds()) && status != UNIT_HIDDEN) { - CColor color; - if(status == UNIT_VISIBLE) + if(units[i] != g_BuildingPlacer.m_actor) { - color = CColor(1.0f, 1.0f, 1.0f, 1.0f); + CColor color; + if(status == UNIT_VISIBLE) + { + color = CColor(1.0f, 1.0f, 1.0f, 1.0f); + } + else // status == UNIT_REMEMBERED + { + color = CColor(0.7f, 0.7f, 0.7f, 1.0f); + } + units[i]->GetModel()->SetShadingColor(color); } - else // status == UNIT_REMEMBERED - { - color = CColor(0.7f, 0.7f, 0.7f, 1.0f); - } - units[i]->GetModel()->SetShadingColor(color); PROFILE( "submit models" ); SubmitModelRecursive(units[i]->GetModel()); diff --git a/source/renderer/PatchRData.cpp b/source/renderer/PatchRData.cpp index 3e4c21c80a..938aaf668e 100755 --- a/source/renderer/PatchRData.cpp +++ b/source/renderer/PatchRData.cpp @@ -47,7 +47,7 @@ static SColor4ub ConvertColor(const RGBColor& src) /////////////////////////////////////////////////////////////////// // CPatchRData constructor -CPatchRData::CPatchRData(CPatch* patch) : m_Patch(patch), m_VBBase(0), m_VBBlends(0), m_Vertices(0) +CPatchRData::CPatchRData(CPatch* patch) : m_Patch(patch), m_VBBase(0), m_VBBlends(0), m_Vertices(0), m_LightingColors(0) { debug_assert(patch); Build(); @@ -59,6 +59,7 @@ CPatchRData::~CPatchRData() { // delete copy of vertex data delete[] m_Vertices; + delete[] m_LightingColors; // release vertex buffer chunks if (m_VBBase) g_VBMan.Release(m_VBBase); if (m_VBBlends) g_VBMan.Release(m_VBBlends); @@ -213,6 +214,7 @@ void CPatchRData::BuildBlends() dst.m_Color=vtx0.m_Color; dst.m_Position=vtx0.m_Position; m_BlendVertices.push_back(dst); + m_BlendVertexIndices.push_back((j*vsize)+i); const SBaseVertex& vtx1=m_Vertices[(j*vsize)+i+1]; dst.m_UVs[0]=(i+1)*0.125f; @@ -222,6 +224,7 @@ void CPatchRData::BuildBlends() dst.m_Color=vtx1.m_Color; dst.m_Position=vtx1.m_Position; m_BlendVertices.push_back(dst); + m_BlendVertexIndices.push_back((j*vsize)+i+1); const SBaseVertex& vtx2=m_Vertices[((j+1)*vsize)+i+1]; dst.m_UVs[0]=(i+1)*0.125f; @@ -231,6 +234,7 @@ void CPatchRData::BuildBlends() dst.m_Color=vtx2.m_Color; dst.m_Position=vtx2.m_Position; m_BlendVertices.push_back(dst); + m_BlendVertexIndices.push_back(((j+1)*vsize)+i+1); const SBaseVertex& vtx3=m_Vertices[((j+1)*vsize)+i]; dst.m_UVs[0]=i*0.125f; @@ -240,6 +244,7 @@ void CPatchRData::BuildBlends() dst.m_Color=vtx3.m_Color; dst.m_Position=vtx3.m_Position; m_BlendVertices.push_back(dst); + m_BlendVertexIndices.push_back(((j+1)*vsize)+i); // build a splat for this quad STmpSplat splat; @@ -360,14 +365,17 @@ void CPatchRData::BuildIndices() void CPatchRData::BuildVertices() { + // create both vertices and lighting colors + CVector3D normal; - RGBColor c; + SColor4ub black = ConvertColor(RGBColor(0,0,0)); // number of vertices in each direction in each patch int vsize=PATCH_SIZE+1; if (!m_Vertices) { m_Vertices=new SBaseVertex[vsize*vsize]; + m_LightingColors=new RGBColor[vsize*vsize]; } SBaseVertex* vertices=m_Vertices; @@ -377,9 +385,6 @@ void CPatchRData::BuildVertices() u32 pz=m_Patch->m_Z; CTerrain* terrain=m_Patch->m_Parent; - int mapSize=terrain->GetVerticesPerSide(); - - CLOSManager* losMgr = g_Game->GetWorld()->GetLOSManager(); // build vertices for (int j=0;jCalcPosition(ix,iz,vertices[v].m_Position); - terrain->CalcNormal(ix,iz,normal); - - const int DX[] = {1,1,0,0}; - const int DZ[] = {0,1,1,0}; - float losMod = 1.0f; - for(int k=0; k<4; k++) - { - int tx = ix - DX[k]; - int tz = iz - DZ[k]; - - if(tx >= 0 && tz >= 0 && tx <= mapSize-2 && tz <= mapSize-2) - { - ELOSStatus s = losMgr->GetStatus(tx, tz, g_Game->GetLocalPlayer()); - if(s==LOS_EXPLORED && losMod > 0.7f) - losMod = 0.7f; - else if(s==LOS_UNEXPLORED && losMod > 0.0f) - losMod = 0.0f; - } - } - RGBColor losModColor(losMod, losMod, losMod); - - g_Renderer.m_SHCoeffsTerrain.Evaluate(normal, c, losModColor); - - vertices[v].m_Color=ConvertColor(c); - + // calculate vertex data + terrain->CalcPosition(ix,iz,vertices[v].m_Position); + vertices[v].m_Color=black; // will be set to the proper value in Update() vertices[v].m_UVs[0]=i*0.125f; vertices[v].m_UVs[1]=j*0.125f; + + // calculate lighting into the separate m_LightingColors array, which will + // be used to set the vertex colors in Update() + terrain->CalcNormal(ix,iz,normal); + g_Renderer.m_SHCoeffsTerrain.Evaluate(normal, m_LightingColors[v]); } } + // upload to vertex buffer if (!m_VBBase) { m_VBBase=g_VBMan.Allocate(sizeof(SBaseVertex),vsize*vsize,false); } @@ -438,16 +426,69 @@ void CPatchRData::Update() // TODO,RC 11/04/04 - need to only rebuild necessary bits of renderdata rather // than everything; it's complicated slightly because the blends are dependent // on both vertex and index data - //BuildVertices(); + BuildVertices(); BuildIndices(); - ///BuildBlends(); + BuildBlends(); m_UpdateFlags=0; } - // Always build vertices (due to LOS) - BuildVertices(); - BuildBlends(); + // Update vertex colors, which are affected by LOS + + u32 px=m_Patch->m_X; + u32 pz=m_Patch->m_Z; + + CTerrain* terrain=m_Patch->m_Parent; + int mapSize=terrain->GetVerticesPerSide(); + CLOSManager* losMgr = g_Game->GetWorld()->GetLOSManager(); + int vsize=PATCH_SIZE+1; + + // this is very similar to BuildVertices(), but just for color + for (int j=0;j= 0 && tz >= 0 && tx <= mapSize-2 && tz <= mapSize-2) + { + ELOSStatus s = losMgr->GetStatus(tx, tz, g_Game->GetLocalPlayer()); + if(s==LOS_EXPLORED && losMod > 0.7f) + losMod = 0.7f; + else if(s==LOS_UNEXPLORED && losMod > 0.0f) + losMod = 0.0f; + } + } + + RGBColor c = m_LightingColors[v]; + c *= losMod; + + m_Vertices[v].m_Color=ConvertColor(c); + } + } + + // upload base vertices into their vertex buffer + m_VBBase->m_Owner->UpdateChunkVertices(m_VBBase,m_Vertices); + + // update blend colors by copying them from vertex colors + for(uint i=0; im_Owner->UpdateChunkVertices(m_VBBlends,&m_BlendVertices[0]); + } } void CPatchRData::RenderBase() diff --git a/source/renderer/PatchRData.h b/source/renderer/PatchRData.h index 088629f94b..7d11b0bde8 100755 --- a/source/renderer/PatchRData.h +++ b/source/renderer/PatchRData.h @@ -87,7 +87,6 @@ private: Handle m_Handle; int m_Priority; }; - // build this renderdata object void Build(); @@ -98,26 +97,46 @@ private: // owner patch CPatch* m_Patch; + // vertex buffer handle for base vertices CVertexBuffer::VBChunk* m_VBBase; + // vertex buffer handle for blend vertices CVertexBuffer::VBChunk* m_VBBlends; + // patch render vertices SBaseVertex* m_Vertices; + + // precomputed lighting colors at each vertex; these are the multiplied by a LOS modifier + // (black for shroud of darkness, half-darkened for fog of war), to compute the colors in + // m_Vertices, which are passed to the graphics card + RGBColor* m_LightingColors; + // indices into base vertices for the base splats std::vector m_Indices; + // indices into base vertices for the shadow map pass std::vector m_ShadowMapIndices; + // list of base splats to apply to this patch std::vector m_Splats; + // vertices to use for blending transition texture passes std::vector m_BlendVertices; + + // remembers the index in the m_Vertices array of each blend vertex, so that we can + // properly update its color for fog of war and shroud of darkness + std::vector m_BlendVertexIndices; + // indices into blend vertices for the blend splats std::vector m_BlendIndices; + // splats used in blend pass std::vector m_BlendSplats; + // index of the next blend splat to render u32 m_NextBlendSplat; + // list of all submitted patches static std::vector m_Patches; }; diff --git a/source/simulation/LOSManager.cpp b/source/simulation/LOSManager.cpp index c720f4ee3e..ade5875a2e 100644 --- a/source/simulation/LOSManager.cpp +++ b/source/simulation/LOSManager.cpp @@ -151,9 +151,15 @@ EUnitLOSStatus CLOSManager::GetUnitStatus(CUnit* unit, CPlayer* player) } else if(status == LOS_EXPLORED) { - if(unit->GetEntity() != 0 && unit->GetEntity()->m_permanent) + if(unit->GetEntity() == 0 || unit->GetEntity()->m_permanent) { + // both actors (which are usually for decoration) and units with the + // permanent flag should be remembered return UNIT_REMEMBERED; + + // TODO: the unit status system will have to be replaced with a "ghost actor" + // system so that we can't remember units that we haven't seen and so we can + // see permanent units that have died but that we haven't been near lately } else { diff --git a/source/simulation/LOSManager.h b/source/simulation/LOSManager.h index 9ca5a9b6b2..000964edd5 100644 --- a/source/simulation/LOSManager.h +++ b/source/simulation/LOSManager.h @@ -5,7 +5,12 @@ // Maintains and updates line of sight data (including Shroud of Darkness // and Fog of War). // -// Usage: Doesn't do anything useful right now. +// Usage: +// - Initialize() is called when the game is started to allocate the visibility arrays +// - Update() is called each frame by CSimulation::Update() to update the visibility arrays +// - m_MapRevealed can be set to true to reveal the entire map (remove both LOS and FOW) +// - GetStatus can be used to obtain the LOS status of a tile or a world-space point +// - GetUnitStatus returns the LOS status of an entity or actor #ifndef LOS_MANAGER_INCLUDED