1
0
forked from 0ad/0ad

# Rewrite fog-of-war rendering.

Disable shadows when only 2 TMUs available.
Clean up some other rendering code.

This was SVN commit r8882.
This commit is contained in:
Ykkrosh 2011-02-03 01:12:24 +00:00
parent 1e02fe70a7
commit fe21c5e023
18 changed files with 680 additions and 283 deletions

View File

@ -5,6 +5,7 @@ uniform vec3 cameraPos;
uniform sampler2D normalMap;
uniform sampler2D reflectionMap;
uniform sampler2D refractionMap;
uniform sampler2D losMap;
uniform float shininess; // Blinn-Phong specular strength
uniform float specularStrength; // Scaling for specular reflection (specular color is (this,this,this))
uniform float waviness; // "Wildness" of the reflections and refractions; choose based on texture
@ -17,7 +18,6 @@ uniform float reflectionTintStrength; // Strength of reflection tint (how much o
varying vec3 worldPos;
varying float w;
varying float waterDepth;
varying float losMod;
void main()
{
@ -28,7 +28,8 @@ void main()
float t; // Temporary variable
vec2 reflCoords, refrCoords;
vec3 reflColor, refrColor, specular;
float losMod;
n = normalize(texture2D(normalMap, gl_TexCoord[0].st).xzy - vec3(0.5, 0.5, 0.5));
l = -sunDir;
v = normalize(cameraPos - worldPos);
@ -55,7 +56,9 @@ void main()
myMurkiness);
specular = pow(max(0.0, ndoth), shininess) * sunColor * specularStrength;
losMod = texture2D(losMap, gl_TexCoord[3].st).a;
gl_FragColor.rgb = mix(refrColor + 0.3*specular, reflColor + specular, fresnel) * losMod;
// Make alpha vary based on both depth (so it blends with the shore) and view angle (make it

View File

@ -1,23 +1,22 @@
uniform mat4 reflectionMatrix;
uniform mat4 refractionMatrix;
uniform mat4 losMatrix;
uniform vec4 translation;
attribute float vertexDepth;
attribute float losMultiplier;
varying vec3 worldPos;
varying float w;
varying float waterDepth;
varying float losMod;
void main()
{
worldPos = gl_Vertex.xyz;
waterDepth = vertexDepth;
losMod = losMultiplier;
gl_TexCoord[0] = gl_MultiTexCoord0 + translation;
gl_TexCoord[1] = reflectionMatrix * gl_Vertex; // projective texturing
gl_TexCoord[2] = reflectionMatrix * gl_Vertex;
gl_TexCoord[3] = losMatrix * gl_Vertex;
w = gl_TexCoord[1].w;
gl_Position = ftransform();
}

View File

@ -24,6 +24,7 @@
#include "graphics/ColladaManager.h"
#include "graphics/HFTracer.h"
#include "graphics/LightEnv.h"
#include "graphics/LOSTexture.h"
#include "graphics/Model.h"
#include "graphics/ObjectManager.h"
#include "graphics/Patch.h"
@ -198,6 +199,7 @@ public:
CMeshManager MeshManager;
CSkeletonAnimManager SkeletonAnimManager;
CObjectManager ObjectManager;
CLOSTexture LOSTexture;
/**
* this camera controls the eye position when rendering
@ -354,12 +356,10 @@ CCinemaManager* CGameView::GetCinema()
return &m->TrackManager;
};
/*
void CGameView::AttachToUnit(CEntity* target)
CLOSTexture& CGameView::GetLOSTexture()
{
m->UnitAttach = target;
return m->LOSTexture;
}
*/
void CGameViewImpl::ScriptingInit()

View File

@ -31,6 +31,7 @@ class CGame;
class CObjectManager;
class CCamera;
class CCinemaManager;
class CLOSTexture;
class CVector3D;
struct SViewPort;
@ -90,6 +91,7 @@ public:
CCamera *GetCamera();
CCinemaManager* GetCinema();
CLOSTexture& GetLOSTexture();
JSObject* GetScript();
static void ScriptingInit();

View File

@ -0,0 +1,244 @@
/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.h"
#include "LOSTexture.h"
#include "graphics/Terrain.h"
#include "lib/bits.h"
#include "ps/Game.h"
#include "ps/Profile.h"
#include "ps/World.h"
#include "renderer/Renderer.h"
#include "simulation2/Simulation2.h"
#include "simulation2/components/ICmpRangeManager.h"
/*
The LOS bitmap is computed with one value per map vertex, based on
CCmpRangeManager's visibility information.
The bitmap is then blurred using an NxN box filter (i.e. convolution
with (1 1 1; 1 1 1; 1 1 1) etc). To implement the blur efficiently without
using extra memory for a second copy of the bitmap, we generate the bitmap
with (N-1)/2 pixels of padding on each side, then the blur shifts the
image back into the corner.
The blurred bitmap is then uploaded into a GL texture for use by the renderer.
*/
// Blur with a NxN box filter, where N = g_BlurSize must be an odd number.
static const size_t g_BlurSize = 5;
CLOSTexture::CLOSTexture() :
m_Dirty(true), m_Texture(0), m_MapSize(0), m_TextureSize(0)
{
}
CLOSTexture::~CLOSTexture()
{
if (m_Texture)
{
glDeleteTextures(1, &m_Texture);
m_Texture = 0;
}
}
void CLOSTexture::MakeDirty()
{
m_Dirty = true;
}
void CLOSTexture::BindTexture(int unit)
{
if (m_Dirty)
{
RecomputeTexture(unit);
m_Dirty = false;
}
g_Renderer.BindTexture(unit, m_Texture);
}
CMatrix3D CLOSTexture::GetTextureMatrix()
{
debug_assert(m_MapSize);
// We want to map
// world pos (0, y, 0) (i.e. first vertex)
// onto texcoord (0.5/texsize, 0.5/texsize) (i.e. middle of first texel);
// world pos ((mapsize-1)*cellsize, y, (mapsize-1)*cellsize) (i.e. last vertex)
// onto texcoord ((mapsize-0.5) / texsize, (mapsize-0.5) / texsize) (i.e. middle of last texel)
// so construct an appropriate matrix:
float s = (m_MapSize-1) / (float)(m_TextureSize * (m_MapSize-1) * CELL_SIZE);
float t = 0.5f / m_TextureSize;
CMatrix3D m;
m.SetZero();
m._11 = s;
m._23 = s;
m._14 = t;
m._24 = t;
m._44 = 1;
return m;
}
CMatrix3D CLOSTexture::GetMinimapTextureMatrix()
{
debug_assert(m_MapSize);
// We want to map UV (0,0)-(1,1) onto (0,0)-(mapsize/texsize, mapsize/texsize)
float s = m_MapSize / (float)m_TextureSize;
CMatrix3D m;
m.SetZero();
m._11 = s;
m._22 = s;
m._44 = 1;
return m;
}
void CLOSTexture::ConstructTexture(int unit)
{
CTerrain* terrain = g_Game->GetWorld()->GetTerrain();
m_MapSize = terrain->GetVerticesPerSide();
m_TextureSize = (GLsizei)round_up_to_pow2((size_t)m_MapSize + g_BlurSize - 1);
glGenTextures(1, &m_Texture);
g_Renderer.BindTexture(unit, m_Texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA8, m_TextureSize, m_TextureSize, 0, GL_ALPHA, GL_UNSIGNED_BYTE, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
void CLOSTexture::RecomputeTexture(int unit)
{
if (!m_Texture)
ConstructTexture(unit);
PROFILE("recompute LOS texture");
std::vector<u8> losData;
losData.resize(GetBitmapSize(m_MapSize, m_MapSize));
CmpPtr<ICmpRangeManager> cmpRangeManager(*g_Game->GetSimulation2(), SYSTEM_ENTITY);
if (cmpRangeManager.null())
return;
ICmpRangeManager::CLosQuerier los (cmpRangeManager->GetLosQuerier(g_Game->GetPlayerID()));
GenerateBitmap(los, &losData[0], m_MapSize, m_MapSize);
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]);
}
size_t CLOSTexture::GetBitmapSize(size_t w, size_t h)
{
return (w + g_BlurSize - 1) * (h + g_BlurSize - 1);
}
void CLOSTexture::GenerateBitmap(ICmpRangeManager::CLosQuerier los, u8* losData, size_t w, size_t h)
{
const size_t rowSize = w + g_BlurSize-1; // size of losData rows
u8 *dataPtr = losData;
// Initialise the top padding
for (size_t j = 0; j < g_BlurSize/2; ++j)
for (size_t i = 0; i < rowSize; ++i)
*dataPtr++ = 0;
for (size_t j = 0; j < h; ++j)
{
// Initialise the left padding
for (size_t i = 0; i < g_BlurSize/2; ++i)
*dataPtr++ = 0;
// Fill in the visibility data
for (size_t i = 0; i < w; ++i)
{
if (los.IsVisible(i, j))
*dataPtr++ = 255;
else if (los.IsExplored(i, j))
*dataPtr++ = 127;
else
*dataPtr++ = 0;
}
// Initialise the right padding
for (size_t i = 0; i < g_BlurSize/2; ++i)
*dataPtr++ = 0;
}
// Initialise the bottom padding
for (size_t j = 0; j < g_BlurSize/2; ++j)
for (size_t i = 0; i < rowSize; ++i)
*dataPtr++ = 0;
// Horizontal blur:
for (size_t j = g_BlurSize/2; j < h + g_BlurSize/2; ++j)
{
u32 accum = 0; // sum of values in the sliding Nx1 window
// Initialise the filter window for the first output pixel
// (Start i at the first of the non-padding pixels, since the
// padding was set to 0)
for (size_t i = g_BlurSize/2; i < g_BlurSize-1; ++i)
accum += losData[i+j*rowSize];
// For each pixel, update the sliding window and store the average
// of the window's sum
for (size_t i = 0; i < w; ++i)
{
accum += losData[i+g_BlurSize-1+j*rowSize];
u8 old = losData[i+j*rowSize];
losData[i+j*rowSize] = accum / g_BlurSize;
accum -= old;
}
}
// Vertical blur:
for (size_t i = 0; i < w; ++i)
{
u32 accum = 0;
for (size_t j = g_BlurSize/2; j < g_BlurSize-1; ++j)
accum += losData[i+j*rowSize];
for (size_t j = 0; j < h; ++j)
{
accum += losData[i+(j+g_BlurSize-1)*rowSize];
u8 old = losData[i+j*rowSize];
losData[i+j*rowSize] = accum / g_BlurSize;
accum -= old;
}
}
}

View File

@ -0,0 +1,78 @@
/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#include "lib/ogl.h"
#include "simulation2/components/ICmpRangeManager.h"
class CMatrix3D;
/**
* Maintains the LOS (fog-of-war / shroud-of-darkness) texture, used for
* rendering and for the minimap.
*/
class CLOSTexture
{
NONCOPYABLE(CLOSTexture);
friend class TestLOSTexture;
public:
CLOSTexture();
~CLOSTexture();
/**
* Marks the LOS texture as needing recomputation. Call this after each
* simulation update, to ensure responsive updates.
*/
void MakeDirty();
/**
* Recomputes the LOS texture if necessary, and binds it to the requested
* texture unit.
* Also switches the current active texture unit, and enables texturing on it.
* The texture is in 8-bit ALPHA format.
*/
void BindTexture(int unit);
/**
* Returns a matrix to map (x,y,z) world coordinates onto (u,v) LOS texture
* coordinates.
* This must only be called after BindTexture.
*/
CMatrix3D GetTextureMatrix();
/**
* Returns a matrix to map (0,0)-(1,1) texture coordinates onto LOS texture
* coordinates.
* This must only be called after BindTexture.
*/
CMatrix3D GetMinimapTextureMatrix();
private:
void ConstructTexture(int unit);
void RecomputeTexture(int unit);
size_t GetBitmapSize(size_t w, size_t h);
void GenerateBitmap(ICmpRangeManager::CLosQuerier los, u8* losData, size_t w, size_t h);
bool m_Dirty;
GLuint m_Texture;
ssize_t m_MapSize; // vertexes per side
GLsizei m_TextureSize; // texels per side
};

View File

@ -0,0 +1,78 @@
/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#include "lib/self_test.h"
#include "graphics/LOSTexture.h"
#include "lib/timer.h"
class TestLOSTexture : public CxxTest::TestSuite
{
public:
void test_basic()
{
CLOSTexture tex;
const ssize_t size = 8;
u32 inputData[size*size] = {
2, 2, 2, 0, 0, 0, 0, 0,
2, 2, 2, 0, 0, 0, 0, 0,
2, 2, 2, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 2
};
std::vector<u32> inputDataVec(inputData, inputData+size*size);
ICmpRangeManager::CLosQuerier los(1, inputDataVec, size);
std::vector<u8> losData;
losData.resize(tex.GetBitmapSize(size, size));
tex.GenerateBitmap(los, &losData[0], size, size);
// for (size_t i = 0; i < losData.size(); ++i)
// printf("%s %3d", i % (size_t)sqrt(losData.size()) ? "" : "\n", losData[i]);
TS_ASSERT_EQUALS(losData[0], 91);
}
void test_perf_DISABLED()
{
CLOSTexture tex;
const ssize_t size = 257;
std::vector<u32> inputDataVec;
inputDataVec.resize(size*size);
ICmpRangeManager::CLosQuerier los(1, inputDataVec, size);
size_t reps = 128;
double t = timer_Time();
for (size_t i = 0; i < reps; ++i)
{
std::vector<u8> losData;
losData.resize(tex.GetBitmapSize(size, size));
tex.GenerateBitmap(los, &losData[0], size, size);
}
double dt = timer_Time() - t;
printf("\n# %f secs\n", dt/reps);
}
};

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010 Wildfire Games.
/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -22,6 +22,7 @@
#include "MiniMap.h"
#include "graphics/GameView.h"
#include "graphics/LOSTexture.h"
#include "graphics/MiniPatch.h"
#include "graphics/Terrain.h"
#include "graphics/TerrainTextureEntry.h"
@ -39,7 +40,6 @@
#include "scriptinterface/ScriptInterface.h"
#include "simulation2/Simulation2.h"
#include "simulation2/components/ICmpMinimap.h"
#include "simulation2/components/ICmpRangeManager.h"
bool g_GameRestarted = false;
@ -51,9 +51,8 @@ static unsigned int ScaleColor(unsigned int color, float x)
return (0xff000000 | r | g<<8 | b<<16);
}
CMiniMap::CMiniMap()
: m_TerrainTexture(0), m_TerrainData(0), m_MapSize(0), m_Terrain(0),
m_LOSTexture(0), m_TerrainDirty(true)
CMiniMap::CMiniMap() :
m_TerrainTexture(0), m_TerrainData(0), m_MapSize(0), m_Terrain(0), m_TerrainDirty(true)
{
AddSetting(GUIST_CColor, "fov_wedge_color");
AddSetting(GUIST_bool, "circular");
@ -61,8 +60,6 @@ CMiniMap::CMiniMap()
AddSetting(GUIST_CStr, "tooltip_style");
m_Clicking = false;
m_Hovering = false;
m_LOSScale = 2;
}
CMiniMap::~CMiniMap()
@ -279,9 +276,7 @@ void CMiniMap::Draw()
m_Width = (u32)(m_CachedActualSize.right - m_CachedActualSize.left);
m_Height = (u32)(m_CachedActualSize.bottom - m_CachedActualSize.top);
m_MapSize = m_Terrain->GetVerticesPerSide();
m_LOSMapSize = (m_MapSize + m_LOSScale - 1) / m_LOSScale; // divide and round upwards
m_TextureSize = (GLsizei)round_up_to_pow2((size_t)m_MapSize);
m_LOSTextureSize = (GLsizei)round_up_to_pow2((size_t)m_LOSMapSize);
if(!m_TerrainTexture || g_GameRestarted)
CreateTextures();
@ -298,16 +293,12 @@ void CMiniMap::Draw()
if(m_TerrainDirty)
RebuildTerrainTexture();
RebuildLOSTexture();
}
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 losTexCoordMax = (float)(m_LOSMapSize - 1) / (float)m_LOSTextureSize;
const float angle = GetAngle();
// Draw the main textured quad
@ -371,20 +362,29 @@ void CMiniMap::Draw()
*/
// Draw the LOS quad in black, using alpha values from the LOS texture
g_Renderer.BindTexture(0, m_LOSTexture);
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_SRC_ALPHA);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
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);
DrawTexture(losTexCoordMax, angle, x, y, x2, y2, z);
glMatrixMode(GL_TEXTURE);
glLoadMatrixf(&losTexture.GetMinimapTextureMatrix()._11);
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
@ -463,22 +463,11 @@ void CMiniMap::CreateTextures()
m_TerrainData = new u32[(m_MapSize - 1) * (m_MapSize - 1)];
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
// Create LOS texture
glGenTextures(1, &m_LOSTexture);
g_Renderer.BindTexture(0, m_LOSTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA8, m_LOSTextureSize, m_LOSTextureSize, 0, GL_ALPHA, GL_UNSIGNED_BYTE, 0);
m_LOSData.resize(m_LOSMapSize * m_LOSMapSize);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
// Rebuild and upload both of them
RebuildTerrainTexture();
RebuildLOSTexture();
}
@ -539,44 +528,6 @@ void CMiniMap::RebuildTerrainTexture()
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_MapSize - 1, m_MapSize - 1, GL_BGRA_EXT, GL_UNSIGNED_BYTE, m_TerrainData);
}
void CMiniMap::RebuildLOSTexture()
{
PROFILE("rebuild minimap: los");
ssize_t w = m_MapSize;
ssize_t h = m_MapSize;
CmpPtr<ICmpRangeManager> cmpRangeManager(*g_Game->GetSimulation2(), SYSTEM_ENTITY);
if (cmpRangeManager.null() || cmpRangeManager->GetLosRevealAll(g_Game->GetPlayerID()))
{
memset(&m_LOSData[0], 0, m_LOSData.size());
}
else
{
ICmpRangeManager::CLosQuerier los (cmpRangeManager->GetLosQuerier(g_Game->GetPlayerID()));
u8 *dataPtr = &m_LOSData[0];
for (ssize_t j = 0; j < h; j += m_LOSScale)
{
for (ssize_t i = 0; i < w; i += m_LOSScale)
{
if (los.IsVisible(i, j))
*dataPtr++ = 0;
else if (los.IsExplored(i, j))
*dataPtr++ = 76;
else
*dataPtr++ = 255;
}
}
}
// Upload the texture
g_Renderer.BindTexture(0, m_LOSTexture);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_LOSMapSize, m_LOSMapSize, GL_ALPHA, GL_UNSIGNED_BYTE, &m_LOSData[0]);
}
void CMiniMap::Destroy()
{
if(m_TerrainTexture)
@ -585,11 +536,6 @@ void CMiniMap::Destroy()
m_TerrainTexture = 0;
}
if(m_LOSTexture)
{
glDeleteTextures(1, &m_LOSTexture);
m_LOSTexture = 0;
}
delete[] m_TerrainData; m_TerrainData = 0;
delete[] m_TerrainData;
m_TerrainData = 0;
}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010 Wildfire Games.
/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -40,9 +40,6 @@ protected:
// rebuild the terrain texture map
void RebuildTerrainTexture();
// rebuild the LOS map
void RebuildLOSTexture();
// destroy and free any memory and textures
void Destroy();
@ -61,15 +58,9 @@ protected:
// minimap texture handles
GLuint m_TerrainTexture;
GLuint m_LOSTexture;
// number of vertexes per LOS-texture texel
u8 m_LOSScale;
ssize_t m_LOSMapSize;
// texture data
u32* m_TerrainData;
std::vector<u8> m_LOSData;
// whether we need to regenerate the terrain texture
bool m_TerrainDirty;
@ -81,7 +72,6 @@ protected:
// texture size
GLsizei m_TextureSize;
GLsizei m_LOSTextureSize;
void DrawTexture(float coordMax, float angle, float x, float y, float x2, float y2, float z);

View File

@ -65,6 +65,7 @@ FUNC2(void, glDrawRangeElementsEXT, glDrawRangeElements, "1.2", (GLenum, GLuint,
// GL_ARB_multitexture / GL1.3:
FUNC2(void, glMultiTexCoord2fARB, glMultiTexCoord2f, "1.3", (int, float, float))
FUNC2(void, glMultiTexCoord3fARB, glMultiTexCoord3f, "1.3", (int, float, float, float))
FUNC2(void, glActiveTextureARB, glActiveTexture, "1.3", (int))
FUNC2(void, glClientActiveTextureARB, glClientActiveTexture, "1.3", (int))

View File

@ -20,6 +20,7 @@
#include "Game.h"
#include "graphics/GameView.h"
#include "graphics/LOSTexture.h"
#include "graphics/UnitManager.h"
#include "lib/timer.h"
#include "network/NetClient.h"
@ -234,7 +235,10 @@ bool CGame::Update(double deltaTime, bool doInterpolate)
PROFILE("update");
if (m_TurnManager->Update(deltaTime, maxTurns))
{
g_GUI->SendEventToAll("SimulationUpdate");
GetView()->GetLOSTexture().MakeDirty();
}
}
if (doInterpolate)

View File

@ -137,7 +137,6 @@ void CPatchRData::BuildBlends()
{
m_BlendSplats.clear();
m_BlendVertices.clear();
m_BlendVertexIndices.clear();
CTerrain* terrain = m_Patch->m_Parent;
@ -348,37 +347,29 @@ void CPatchRData::AddBlend(u16 i, u16 j, u8 shape)
CalculateUV(dst.m_UVs, gx, gz);
dst.m_AlphaUVs[0] = vtx[0].m_AlphaUVs[0];
dst.m_AlphaUVs[1] = vtx[0].m_AlphaUVs[1];
dst.m_LOSColor = vtx0.m_LOSColor;
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];
CalculateUV(dst.m_UVs, gx + 1, gz);
dst.m_AlphaUVs[0] = vtx[1].m_AlphaUVs[0];
dst.m_AlphaUVs[1] = vtx[1].m_AlphaUVs[1];
dst.m_LOSColor = vtx1.m_LOSColor;
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];
CalculateUV(dst.m_UVs, gx + 1, gz + 1);
dst.m_AlphaUVs[0] = vtx[2].m_AlphaUVs[0];
dst.m_AlphaUVs[1] = vtx[2].m_AlphaUVs[1];
dst.m_LOSColor = vtx2.m_LOSColor;
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];
CalculateUV(dst.m_UVs, gx, gz + 1);
dst.m_AlphaUVs[0] = vtx[3].m_AlphaUVs[0];
dst.m_AlphaUVs[1] = vtx[3].m_AlphaUVs[1];
dst.m_LOSColor = vtx3.m_LOSColor;
dst.m_Position = vtx3.m_Position;
m_BlendVertices.push_back(dst);
m_BlendVertexIndices.push_back(((j + 1) * vsize) + i);
}
void CPatchRData::BuildIndices()
@ -391,7 +382,6 @@ void CPatchRData::BuildIndices()
// release existing indices and bins
m_Indices.clear();
m_ShadowMapIndices.clear();
m_Splats.clear();
// build grid of textures on this patch and boundaries of adjacent patches
@ -430,16 +420,6 @@ void CPatchRData::BuildIndices()
}
splat.m_IndexCount=m_Indices.size()-splat.m_IndexStart;
}
// build indices for the shadow map pass
for (ssize_t j=0;j<PATCH_SIZE;j++) {
for (ssize_t i=0;i<PATCH_SIZE;i++) {
m_ShadowMapIndices.push_back(u16(((j+0)*vsize+(i+0))+base));
m_ShadowMapIndices.push_back(u16(((j+0)*vsize+(i+1))+base));
m_ShadowMapIndices.push_back(u16(((j+1)*vsize+(i+1))+base));
m_ShadowMapIndices.push_back(u16(((j+1)*vsize+(i+0))+base));
}
}
}
@ -474,7 +454,6 @@ void CPatchRData::BuildVertices()
// calculate vertex data
terrain->CalcPosition(ix,iz,vertices[v].m_Position);
vertices[v].m_LOSColor = SColor4ub(0, 0, 0, 0); // will be set to the proper value in Update()
CalculateUV(vertices[v].m_UVs, ix, iz);
// Calculate diffuse lighting for this vertex
@ -514,81 +493,19 @@ void CPatchRData::Update()
m_UpdateFlags=0;
}
// Update vertex colors, which are affected by LOS
ssize_t px=m_Patch->m_X;
ssize_t pz=m_Patch->m_Z;
CTerrain* terrain=m_Patch->m_Parent;
ssize_t vsize=PATCH_SIZE+1;
SColor4ub baseColour = terrain->GetBaseColour();
CmpPtr<ICmpRangeManager> cmpRangeManager(*g_Game->GetSimulation2(), SYSTEM_ENTITY);
if (cmpRangeManager.null())
{
for (ssize_t j = 0; j < vsize; ++j)
{
for (ssize_t i = 0; i < vsize; ++i)
{
ssize_t v = (j*vsize)+i;
m_Vertices[v].m_LOSColor = baseColour;
}
}
}
else
{
ICmpRangeManager::CLosQuerier los (cmpRangeManager->GetLosQuerier(g_Game->GetPlayerID()));
// this is very similar to BuildVertices(), but just for color
for (ssize_t j = 0; j < vsize; j++)
{
for (ssize_t i = 0; i < vsize; i++)
{
ssize_t ix = px * PATCH_SIZE + i;
ssize_t iz = pz * PATCH_SIZE + j;
ssize_t v = (j * vsize) + i;
SColor4ub losMod;
if (los.IsVisible(ix, iz))
losMod = baseColour;
else if (los.IsExplored(ix, iz))
losMod = SColor4ub(178, 178, 178, 255);
else
losMod = SColor4ub(0, 0, 0, 255);
m_Vertices[v].m_LOSColor = losMod;
}
}
}
// 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(size_t i=0; i<m_BlendVertices.size(); i++)
{
m_BlendVertices[i].m_LOSColor = m_Vertices[m_BlendVertexIndices[i]].m_LOSColor;
}
// upload blend vertices into their vertex buffer too
if(m_BlendVertices.size())
{
m_VBBlends->m_Owner->UpdateChunkVertices(m_VBBlends,&m_BlendVertices[0]);
}
}
void CPatchRData::RenderBase(bool losColor)
void CPatchRData::RenderBase()
{
debug_assert(m_UpdateFlags==0);
SBaseVertex *base=(SBaseVertex *)m_VBBase->m_Owner->Bind();
// setup data pointers
GLsizei stride=sizeof(SBaseVertex);
glVertexPointer(3,GL_FLOAT,stride,&base->m_Position[0]);
glColorPointer(4,GL_UNSIGNED_BYTE,stride,losColor ? &base->m_LOSColor : &base->m_DiffuseColor);
glTexCoordPointer(2,GL_FLOAT,stride,&base->m_UVs[0]);
GLsizei stride = sizeof(SBaseVertex);
glVertexPointer(3, GL_FLOAT, stride, &base->m_Position[0]);
glColorPointer(4, GL_UNSIGNED_BYTE, stride, &base->m_DiffuseColor);
glTexCoordPointer(2, GL_FLOAT, stride, &base->m_UVs[0]);
// render each splat
for (size_t i=0;i<m_Splats.size();i++) {
@ -612,23 +529,44 @@ void CPatchRData::RenderBase(bool losColor)
CVertexBuffer::Unbind();
}
void CPatchRData::RenderStreams(int streamflags, bool losColor)
void CPatchRData::RenderStreams(int streamflags)
{
debug_assert(m_UpdateFlags==0);
SBaseVertex* base=(SBaseVertex *)m_VBBase->m_Owner->Bind();
// setup data pointers
GLsizei stride=sizeof(SBaseVertex);
GLsizei stride = sizeof(SBaseVertex);
glVertexPointer(3, GL_FLOAT, stride, &base->m_Position);
if (streamflags & STREAM_UV0) {
if (streamflags & STREAM_UV0)
{
glTexCoordPointer(2, GL_FLOAT, stride, &base->m_UVs);
} else if (streamflags & STREAM_POSTOUV0) {
}
else if (streamflags & STREAM_POSTOUV0)
{
glTexCoordPointer(3, GL_FLOAT, stride, &base->m_Position);
}
if (streamflags & STREAM_POSTOUV1)
{
pglClientActiveTextureARB(GL_TEXTURE1);
glTexCoordPointer(3, GL_FLOAT, stride, &base->m_Position);
pglClientActiveTextureARB(GL_TEXTURE0);
}
if (streamflags & STREAM_POSTOUV2)
{
pglClientActiveTextureARB(GL_TEXTURE2);
glTexCoordPointer(3, GL_FLOAT, stride, &base->m_Position);
pglClientActiveTextureARB(GL_TEXTURE0);
}
if (streamflags & STREAM_POSTOUV3)
{
pglClientActiveTextureARB(GL_TEXTURE3);
glTexCoordPointer(3, GL_FLOAT, stride, &base->m_Position);
pglClientActiveTextureARB(GL_TEXTURE0);
}
if (streamflags & STREAM_COLOR)
{
glColorPointer(4,GL_UNSIGNED_BYTE,stride,losColor ? &base->m_LOSColor : &base->m_DiffuseColor);
glColorPointer(4, GL_UNSIGNED_BYTE, stride, &base->m_DiffuseColor);
}
// render all base splats at once
@ -660,7 +598,6 @@ void CPatchRData::RenderBlends()
// invalid - see http://gcc.gnu.org/ml/gcc/2003-11/msg00281.html - but it
// doesn't seem to be worth changing this code since it works anyway.))
glVertexPointer(3,GL_FLOAT,stride,base+offsetof(SBlendVertex,m_Position));
glColorPointer(4,GL_UNSIGNED_BYTE,stride,base+offsetof(SBlendVertex,m_LOSColor));
pglClientActiveTextureARB(GL_TEXTURE0);
glTexCoordPointer(2,GL_FLOAT,stride,base+offsetof(SBlendVertex,m_UVs[0]));

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2009 Wildfire Games.
/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -37,10 +37,10 @@ public:
~CPatchRData();
void Update();
void RenderBase(bool losColor);
void RenderBase();
void RenderBlends();
void RenderOutline();
void RenderStreams(int streamflags, bool losColor);
void RenderStreams(int streamflags);
void RenderPriorities();
private:
@ -62,15 +62,11 @@ private:
SColor4ub m_DiffuseColor;
// vertex uvs for base texture
float m_UVs[2];
// color modulation from LOS
SColor4ub m_LOSColor;
};
struct SBlendVertex {
// vertex position
CVector3D m_Position;
// color modulation from LOS
SColor4ub m_LOSColor;
// vertex uvs for base texture
float m_UVs[2];
// vertex uvs for alpha texture
@ -108,19 +104,12 @@ private:
// indices into base vertices for the base splats
std::vector<unsigned short> m_Indices;
// indices into base vertices for the shadow map pass
std::vector<unsigned short> m_ShadowMapIndices;
// list of base splats to apply to this patch
std::vector<SSplat> m_Splats;
// vertices to use for blending transition texture passes
std::vector<SBlendVertex> 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<size_t> m_BlendVertexIndices;
// splats used in blend pass
std::vector<SSplat> m_BlendSplats;
};

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010 Wildfire Games.
/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -434,11 +434,12 @@ CRenderer::~CRenderer()
void CRenderer::EnumCaps()
{
// assume support for nothing
m_Caps.m_VBO=false;
m_Caps.m_TextureBorderClamp=false;
m_Caps.m_GenerateMipmaps=false;
m_Caps.m_VertexShader=false;
m_Caps.m_FragmentShader=false;
m_Caps.m_VBO = false;
m_Caps.m_TextureBorderClamp = false;
m_Caps.m_GenerateMipmaps = false;
m_Caps.m_VertexShader = false;
m_Caps.m_FragmentShader = false;
m_Caps.m_Shadows = false;
m_Caps.m_DepthTextureShadows = false;
m_Caps.m_FramebufferObject = false;
@ -448,12 +449,15 @@ void CRenderer::EnumCaps()
m_Caps.m_VBO=true;
}
}
if (ogl_HaveExtension("GL_ARB_texture_border_clamp")) {
m_Caps.m_TextureBorderClamp=true;
}
if (ogl_HaveExtension("GL_SGIS_generate_mipmap")) {
m_Caps.m_GenerateMipmaps=true;
}
if (0 == ogl_HaveExtensions(0, "GL_ARB_shader_objects", "GL_ARB_shading_language_100", NULL))
{
if (ogl_HaveExtension("GL_ARB_vertex_shader"))
@ -462,6 +466,15 @@ void CRenderer::EnumCaps()
m_Caps.m_FragmentShader=true;
}
if (ogl_max_tex_units >= 3)
{
// To render shadows plus fog-of-war in a single lighting pass (see
// TerrainRenderer.cpp) we need >= 3 TMUs. Only really ancient hardware
// doesn't support that, so instead of implementing a compatible fallback
// we'll just disable shadows entirely unless there's enough TMUs.
m_Caps.m_Shadows = true;
}
if (0 == ogl_HaveExtensions(0, "GL_ARB_shadow", "GL_ARB_depth_texture", NULL)) {
// According to Delphi3d.net, all relevant graphics chips that support depth textures
// (i.e. Geforce3+, Radeon9500+, even i915) also have >= 4 TMUs, so this restriction
@ -470,6 +483,7 @@ void CRenderer::EnumCaps()
if (ogl_max_tex_units >= 4)
m_Caps.m_DepthTextureShadows = true;
}
if (!m_Options.m_NoFramebufferObject)
{
if (ogl_HaveExtension("GL_EXT_framebuffer_object"))
@ -764,7 +778,7 @@ void CRenderer::BeginFrame()
// choose model renderers for this frame
int vertexType;
if (m_Options.m_Shadows && m->shadow->GetUseDepthTexture())
if (m_Caps.m_Shadows && m_Options.m_Shadows && m->shadow->GetUseDepthTexture())
{
vertexType = OnlyDiffuse;
m->Model.ModNormal = m->Model.ModPlainLit;
@ -884,7 +898,7 @@ void CRenderer::RenderPatches()
}
// render all the patches, including blend pass
m->terrainRenderer->RenderTerrain(m_Options.m_Shadows ? m->shadow : 0);
m->terrainRenderer->RenderTerrain((m_Caps.m_Shadows && m_Options.m_Shadows) ? m->shadow : 0);
if (m_TerrainRenderMode==WIREFRAME) {
// switch wireframe off again
@ -1224,7 +1238,7 @@ void CRenderer::RenderSubmissions()
m->overlayRenderer.PrepareForRendering();
PROFILE_END("prepare overlays");
if (m_Options.m_Shadows)
if (m_Caps.m_Shadows && m_Options.m_Shadows)
{
RenderShadowMap();
}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2009 Wildfire Games.
/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -47,15 +47,18 @@ class CTextureManager;
enum ERenderMode { WIREFRAME, SOLID, EDGED_FACES };
// stream flags
#define STREAM_POS 0x01
#define STREAM_NORMAL 0x02
#define STREAM_COLOR 0x04
#define STREAM_UV0 0x08
#define STREAM_UV1 0x10
#define STREAM_UV2 0x20
#define STREAM_UV3 0x40
#define STREAM_POSTOUV0 0x80
#define STREAM_TEXGENTOUV1 0x100
#define STREAM_POS (1 << 0)
#define STREAM_NORMAL (1 << 1)
#define STREAM_COLOR (1 << 2)
#define STREAM_UV0 (1 << 3)
#define STREAM_UV1 (1 << 4)
#define STREAM_UV2 (1 << 5)
#define STREAM_UV3 (1 << 6)
#define STREAM_POSTOUV0 (1 << 7)
#define STREAM_POSTOUV1 (1 << 8)
#define STREAM_POSTOUV2 (1 << 9)
#define STREAM_POSTOUV3 (1 << 10)
#define STREAM_TEXGENTOUV1 (1 << 11)
//////////////////////////////////////////////////////////////////////////////////////////
// SVertex3D: simple 3D vertex declaration
@ -152,6 +155,7 @@ public:
bool m_GenerateMipmaps;
bool m_VertexShader;
bool m_FragmentShader;
bool m_Shadows;
bool m_DepthTextureShadows;
bool m_FramebufferObject;
};

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010 Wildfire Games.
/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -24,6 +24,7 @@
#include "graphics/Camera.h"
#include "graphics/LightEnv.h"
#include "graphics/LOSTexture.h"
#include "graphics/Patch.h"
#include "graphics/Terrain.h"
#include "graphics/GameView.h"
@ -37,9 +38,6 @@
#include "ps/Profile.h"
#include "ps/World.h"
#include "simulation2/Simulation2.h"
#include "simulation2/components/ICmpRangeManager.h"
#include "renderer/PatchRData.h"
#include "renderer/Renderer.h"
#include "renderer/ShadowMap.h"
@ -159,7 +157,6 @@ void TerrainRenderer::RenderTerrain(ShadowMap* shadow)
// switch on required client states
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
// render everything fullbright
@ -167,11 +164,9 @@ void TerrainRenderer::RenderTerrain(ShadowMap* shadow)
pglActiveTextureARB(GL_TEXTURE0);
pglClientActiveTextureARB(GL_TEXTURE0);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
// Set alpha to 1.0
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
@ -183,7 +178,7 @@ void TerrainRenderer::RenderTerrain(ShadowMap* shadow)
for(size_t i = 0; i < m->visiblePatches.size(); ++i)
{
CPatchRData* patchdata = (CPatchRData*)m->visiblePatches[i]->GetRenderData();
patchdata->RenderBase(true); // with LOS color
patchdata->RenderBase();
}
// render blends
@ -225,6 +220,9 @@ void TerrainRenderer::RenderTerrain(ShadowMap* shadow)
// Now apply lighting
const CLightEnv& lightEnv = g_Renderer.GetLightEnv();
pglClientActiveTextureARB(GL_TEXTURE0);
glEnableClientState(GL_COLOR_ARRAY); // diffuse lighting colours
glBlendFunc(GL_DST_COLOR, GL_ZERO);
// GL_TEXTURE_ENV_COLOR requires four floats, so we shouldn't use the RGBColor directly
@ -234,6 +232,10 @@ void TerrainRenderer::RenderTerrain(ShadowMap* shadow)
lightEnv.m_TerrainAmbientColor.Z,
1.f
};
CLOSTexture& losTexture = g_Game->GetView()->GetLOSTexture();
int streamflags = STREAM_POS|STREAM_COLOR|STREAM_POSTOUV0;
if (!shadow)
{
@ -244,7 +246,7 @@ void TerrainRenderer::RenderTerrain(ShadowMap* shadow)
// so assume that's still valid to use.
// (TODO: That's a bit of an ugly hack.)
// Shadow rendering disabled: Ambient + Diffuse
// Shadow rendering disabled: (Ambient + Diffuse) * LOS
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_ADD);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
@ -256,7 +258,25 @@ void TerrainRenderer::RenderTerrain(ShadowMap* shadow)
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, terrainAmbientColor);
losTexture.BindTexture(1);
pglClientActiveTextureARB(GL_TEXTURE1);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
streamflags |= STREAM_POSTOUV1;
glMatrixMode(GL_TEXTURE);
glLoadMatrixf(&losTexture.GetTextureMatrix()._11);
glMatrixMode(GL_MODELVIEW);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_ALPHA);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
}
else
{
@ -271,7 +291,7 @@ void TerrainRenderer::RenderTerrain(ShadowMap* shadow)
if (shadow->GetUseDepthTexture())
{
// Ambient + ShTranslucency * Diffuse * (1 - Shadow) + Diffuse * Shadow
// (Ambient + ShTranslucency * Diffuse * (1 - Shadow) + Diffuse * Shadow) * LOS
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR);
@ -313,11 +333,29 @@ void TerrainRenderer::RenderTerrain(ShadowMap* shadow)
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, terrainAmbientColor);
losTexture.BindTexture(3);
pglClientActiveTextureARB(GL_TEXTURE3);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
streamflags |= STREAM_POSTOUV3;
glMatrixMode(GL_TEXTURE);
glLoadMatrixf(&losTexture.GetTextureMatrix()._11);
glMatrixMode(GL_MODELVIEW);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_ALPHA);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
}
else
{
// Ambient + Diffuse * Shadow
// (Ambient + Diffuse * Shadow) * LOS
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
@ -341,6 +379,24 @@ void TerrainRenderer::RenderTerrain(ShadowMap* shadow)
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, terrainAmbientColor);
losTexture.BindTexture(2);
pglClientActiveTextureARB(GL_TEXTURE2);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
streamflags |= STREAM_POSTOUV2;
glMatrixMode(GL_TEXTURE);
glLoadMatrixf(&losTexture.GetTextureMatrix()._11);
glMatrixMode(GL_MODELVIEW);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_ALPHA);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
}
}
@ -350,25 +406,52 @@ void TerrainRenderer::RenderTerrain(ShadowMap* shadow)
for (size_t i = 0; i < m->visiblePatches.size(); ++i)
{
CPatchRData* patchdata = (CPatchRData*)m->visiblePatches[i]->GetRenderData();
patchdata->RenderStreams(STREAM_POS|STREAM_COLOR|STREAM_POSTOUV0, false);
patchdata->RenderStreams(streamflags);
}
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
// restore OpenGL state
if (shadow)
g_Renderer.BindTexture(1, 0);
if (!shadow)
{
pglClientActiveTextureARB(GL_TEXTURE1);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
}
else
{
if (shadow->GetUseDepthTexture())
g_Renderer.BindTexture(2,0);
{
g_Renderer.BindTexture(2, 0);
g_Renderer.BindTexture(3, 0);
pglClientActiveTextureARB(GL_TEXTURE3);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
}
else
{
g_Renderer.BindTexture(2, 0);
pglClientActiveTextureARB(GL_TEXTURE2);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
}
}
g_Renderer.BindTexture(1,0);
pglClientActiveTextureARB(GL_TEXTURE0);
pglActiveTextureARB(GL_TEXTURE0);
glDepthMask(1);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_BLEND);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
@ -386,7 +469,7 @@ void TerrainRenderer::RenderPatches()
for(size_t i = 0; i < m->visiblePatches.size(); ++i)
{
CPatchRData* patchdata = (CPatchRData*)m->visiblePatches[i]->GetRenderData();
patchdata->RenderStreams(STREAM_POS, true);
patchdata->RenderStreams(STREAM_POS);
}
glDisableClientState(GL_VERTEX_ARRAY);
}
@ -435,9 +518,7 @@ void TerrainRenderer::RenderWater()
}
CTerrain* terrain = g_Game->GetWorld()->GetTerrain();
CmpPtr<ICmpRangeManager> cmpRangeManager(*g_Game->GetSimulation2(), SYSTEM_ENTITY);
debug_assert(!cmpRangeManager.null());
ICmpRangeManager::CLosQuerier los (cmpRangeManager->GetLosQuerier(g_Game->GetPlayerID()));
CLOSTexture& losTexture = g_Game->GetView()->GetLOSTexture();
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
@ -479,6 +560,23 @@ void TerrainRenderer::RenderWater()
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PRIMARY_COLOR_ARB);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
// Multiply by LOS texture
losTexture.BindTexture(1);
pglClientActiveTextureARB(GL_TEXTURE1);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glLoadMatrixf(&losTexture.GetTextureMatrix()._11);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_ALPHA);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
}
// Set the proper LOD bias
@ -488,7 +586,6 @@ void TerrainRenderer::RenderWater()
CVector3D camPos = camera.m_Orientation.GetTranslation();
GLint vertexDepth = 0; // water depth attribute, if using fancy water
GLint losMultiplier = 0; // LOS multiplier, if using fancy water
if(fancy)
{
@ -500,6 +597,8 @@ void TerrainRenderer::RenderWater()
glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D, WaterMgr->m_RefractionTexture );
losTexture.BindTexture(3);
// Bind water shader and set arguments
ogl_program_use( m->fancyWaterShader );
@ -518,9 +617,11 @@ void TerrainRenderer::RenderWater()
GLint translation = ogl_program_get_uniform_location( m->fancyWaterShader, "translation" );
GLint reflectionMatrix = ogl_program_get_uniform_location( m->fancyWaterShader, "reflectionMatrix" );
GLint refractionMatrix = ogl_program_get_uniform_location( m->fancyWaterShader, "refractionMatrix" );
GLint losMatrix = ogl_program_get_uniform_location( m->fancyWaterShader, "losMatrix" );
GLint normalMap = ogl_program_get_uniform_location( m->fancyWaterShader, "normalMap" );
GLint reflectionMap = ogl_program_get_uniform_location( m->fancyWaterShader, "reflectionMap" );
GLint refractionMap = ogl_program_get_uniform_location( m->fancyWaterShader, "refractionMap" );
GLint losMap = ogl_program_get_uniform_location( m->fancyWaterShader, "losMap" );
const CLightEnv& lightEnv = g_Renderer.GetLightEnv();
pglUniform3fvARB( ambient, 1, &lightEnv.m_TerrainAmbientColor.X );
@ -537,13 +638,14 @@ void TerrainRenderer::RenderWater()
pglUniform4fARB( translation, tx, ty, 0, 0 );
pglUniformMatrix4fvARB( reflectionMatrix, 1, false, &WaterMgr->m_ReflectionMatrix._11 );
pglUniformMatrix4fvARB( refractionMatrix, 1, false, &WaterMgr->m_RefractionMatrix._11 );
pglUniformMatrix4fvARB( losMatrix, 1, false, &losTexture.GetTextureMatrix()._11 );
pglUniform1iARB( normalMap, 0 ); // texture unit 0
pglUniform1iARB( reflectionMap, 1 ); // texture unit 1
pglUniform1iARB( refractionMap, 2 ); // texture unit 2
pglUniform1iARB( losMap, 3 ); // texture unit 3
pglUniform3fvARB( cameraPos, 1, &camPos.X );
vertexDepth = ogl_program_get_attrib_location( m->fancyWaterShader, "vertexDepth" );
losMultiplier = ogl_program_get_attrib_location( m->fancyWaterShader, "losMultiplier" );
}
float repeatPeriod = (fancy ? WaterMgr->m_RepeatPeriod : 16.0f);
@ -589,18 +691,9 @@ void TerrainRenderer::RenderWater()
float terrainHeight = terrain->GetVertexGroundLevel(ix, iz);
float losMod;
if (los.IsVisible(ix, iz))
losMod = 1.0f;
else if (los.IsExplored(ix, iz))
losMod = 0.7f;
else
losMod = 0.0f;
if (fancy)
{
pglVertexAttrib1fARB(vertexDepth, WaterMgr->m_WaterHeight - terrainHeight);
pglVertexAttrib1fARB(losMultiplier, losMod);
pglMultiTexCoord2fARB(GL_TEXTURE0, vertX/repeatPeriod, vertZ/repeatPeriod);
glVertex3f(vertX, WaterMgr->m_WaterHeight, vertZ);
}
@ -616,11 +709,12 @@ void TerrainRenderer::RenderWater()
// Invert and set boundaries
FresnelScalar = 1.f - (FresnelScalar * 0.6);
glColor4f(WaterMgr->m_WaterColor.r*losMod,
WaterMgr->m_WaterColor.g*losMod,
WaterMgr->m_WaterColor.b*losMod,
glColor4f(WaterMgr->m_WaterColor.r,
WaterMgr->m_WaterColor.g,
WaterMgr->m_WaterColor.b,
alpha * FresnelScalar);
pglMultiTexCoord2fARB(GL_TEXTURE0, vertX/repeatPeriod, vertZ/repeatPeriod);
pglMultiTexCoord3fARB(GL_TEXTURE1, vertX, WaterMgr->m_WaterHeight, vertZ);
glVertex3f(vertX, WaterMgr->m_WaterHeight, vertZ);
}
@ -630,25 +724,30 @@ void TerrainRenderer::RenderWater()
}
glEnd();
if(fancy)
if (fancy)
{
// Unbind the refraction/reflection textures and the shader
// Unbind the LOS/refraction/reflection textures and the shader
pglActiveTextureARB( GL_TEXTURE1_ARB );
glBindTexture( GL_TEXTURE_2D, 0 );
glDisable( GL_TEXTURE_2D );
g_Renderer.BindTexture(3, 0);
g_Renderer.BindTexture(2, 0);
g_Renderer.BindTexture(1, 0);
pglActiveTextureARB( GL_TEXTURE2_ARB );
glBindTexture( GL_TEXTURE_2D, 0 );
glDisable( GL_TEXTURE_2D );
pglActiveTextureARB( GL_TEXTURE0_ARB );
pglActiveTextureARB(GL_TEXTURE0_ARB);
ogl_program_use( 0 );
ogl_program_use(0);
}
if(!fancy)
if (!fancy)
{
g_Renderer.BindTexture(1, 0);
pglClientActiveTextureARB(GL_TEXTURE1_ARB);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glLoadIdentity();
pglActiveTextureARB(GL_TEXTURE0_ARB);
pglClientActiveTextureARB(GL_TEXTURE0_ARB);
// Clean up the texture matrix and blend mode
glLoadIdentity();
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

View File

@ -882,6 +882,8 @@ public:
*/
inline bool LosIsOffWorld(ssize_t i, ssize_t j)
{
const ssize_t edgeSize = 3; // number of vertexes around the edge that will be off-world
if (m_LosCircular)
{
// With a circular map, vertex is off-world if hypot(i - size/2, j - size/2) >= size/2:
@ -889,13 +891,19 @@ public:
ssize_t dist2 = (i - m_TerrainVerticesPerSide/2)*(i - m_TerrainVerticesPerSide/2)
+ (j - m_TerrainVerticesPerSide/2)*(j - m_TerrainVerticesPerSide/2);
if (dist2 >= (m_TerrainVerticesPerSide/2)*(m_TerrainVerticesPerSide/2))
return true;
ssize_t r = m_TerrainVerticesPerSide/2 - edgeSize + 1;
// subtract a bit from the radius to ensure nice
// SoD blurring around the edges of the map
return (dist2 >= r*r);
}
else
{
// With a square map, the outermost edge of the map should be off-world,
// so the SoD texture blends out nicely
// With a square map, nothing is off-world
return false;
return (i < edgeSize || j < edgeSize || i >= m_TerrainVerticesPerSide-edgeSize || j >= m_TerrainVerticesPerSide-edgeSize);
}
}
/**

View File

@ -169,9 +169,10 @@ public:
{
private:
friend class CCmpRangeManager;
friend class TestLOSTexture;
CLosQuerier(int player, const std::vector<u32>& data, ssize_t verticesPerSide) :
m_Data(data), m_VerticesPerSide(verticesPerSide)
m_Data(&data[0]), m_VerticesPerSide(verticesPerSide)
{
if (player > 0 && player <= 16)
m_PlayerMask = LOS_MASK << (2*(player-1));
@ -192,7 +193,7 @@ public:
debug_assert(i >= 0 && j >= 0 && i < m_VerticesPerSide && j < m_VerticesPerSide);
#endif
// Check high bit of each bit-pair
if ((m_Data.at(j*m_VerticesPerSide + i) & m_PlayerMask) & 0xAAAAAAAAu)
if ((m_Data[j*m_VerticesPerSide + i] & m_PlayerMask) & 0xAAAAAAAAu)
return true;
else
return false;
@ -208,7 +209,7 @@ public:
debug_assert(i >= 0 && j >= 0 && i < m_VerticesPerSide && j < m_VerticesPerSide);
#endif
// Check low bit of each bit-pair
if ((m_Data.at(j*m_VerticesPerSide + i) & m_PlayerMask) & 0x55555555u)
if ((m_Data[j*m_VerticesPerSide + i] & m_PlayerMask) & 0x55555555u)
return true;
else
return false;
@ -216,7 +217,7 @@ public:
private:
u32 m_PlayerMask;
const std::vector<u32>& m_Data;
const u32* m_Data;
ssize_t m_VerticesPerSide;
};