- Terrain self-shadows (only noticeable with a low angle of sun)

- explicitly split ambient and diffuse
- add renderer.shadowZBias to bias depths in the depth texture
  and avoid flickering artifacts caused by Z fighting
- cantabrian_generated uses new light values so that shadows aren't
pitch
  black

This was SVN commit r3508.
This commit is contained in:
prefect 2006-02-13 14:18:20 +00:00
parent 10d84599e9
commit 7dee30e24c
25 changed files with 459 additions and 503 deletions

Binary file not shown.

View File

@ -0,0 +1,11 @@
uniform vec3 ambient;
uniform vec3 sunDir;
uniform vec3 sunColor;
vec3 lighting(vec3 normal)
{
vec3 color = ambient;
float d = max(0.0, -dot(normal, sunDir));
color += d * sunColor;
return color;
}

View File

@ -4,6 +4,6 @@
<Shaders>
<Shader type="VERTEX_SHADER">shaders/instancing_light.vs</Shader>
<Shader type="VERTEX_SHADER">shaders/instancing_base.vs</Shader>
<Shader type="VERTEX_SHADER">shaders/shlight.vs</Shader>
<Shader type="VERTEX_SHADER">shaders/globallight.vs</Shader>
</Shaders>
</Program>

View File

@ -3,6 +3,6 @@
<Program>
<Shaders>
<Shader type="VERTEX_SHADER">shaders/model_light.vs</Shader>
<Shader type="VERTEX_SHADER">shaders/shlight.vs</Shader>
<Shader type="VERTEX_SHADER">shaders/globallight.vs</Shader>
</Shaders>
</Program>

View File

@ -1,16 +0,0 @@
uniform vec3 SHCoefficients[9];
vec3 lighting(vec3 normal)
{
vec3 color = SHCoefficients[0];
vec3 normalsq = normal*normal;
color += SHCoefficients[1]*normal.x;
color += SHCoefficients[2]*normal.y;
color += SHCoefficients[3]*normal.z;
color += SHCoefficients[4]*(normal.x*normal.z);
color += SHCoefficients[5]*(normal.z*normal.y);
color += SHCoefficients[6]*(normal.y*normal.x);
color += SHCoefficients[7]*(3.0*normalsq.z-1.0);
color += SHCoefficients[8]*(normalsq.x-normalsq.y);
return color;
}

View File

@ -13,7 +13,7 @@
#include "Vector4D.h"
#include "lib/types.h"
// simple defines for 3 and 4 component floating point colors - just map to
// simple defines for 3 and 4 component floating point colors - just map to
// corresponding vector types
typedef CVector3D RGBColor;
typedef CVector4D RGBAColor;
@ -33,6 +33,9 @@ struct SColor4ub
u8 G;
u8 B;
u8 A;
SColor4ub() { }
SColor4ub(u8 _r, u8 _g, u8 _b, u8 _a) : R(_r), G(_g), B(_b), A(_a) { }
};
extern u32 (*ConvertRGBColorTo4ub)(const RGBColor& src);

View File

@ -4,8 +4,8 @@
// Author: Rich Cross
// Contact: rich@wildfiregames.com
//
// Description: class describing current lighting environment -
// at the minute, this is only sunlight and ambient light
// Description: class describing current lighting environment -
// at the minute, this is only sunlight and ambient light
// parameters; will be extended to handle dynamic lights at some
// later date
//
@ -25,7 +25,7 @@ class CMainFrame;
class CLightSettingsDlg;
///////////////////////////////////////////////////////////////////////////////
// CLightEnv: description of a lighting environment - contains all the
// CLightEnv: description of a lighting environment - contains all the
// necessary parameters for representation of the lighting within a scenario
class CLightEnv
{
@ -67,6 +67,58 @@ public:
CalculateSunDirection();
}
/**
* EvaluateTerrain: Calculate brightness of a point of the terrain with the given normal
* vector.
* The resulting color contains both ambient and diffuse light.
*
* @param normal normal vector (must have length 1)
* @param color resulting color
*/
void EvaluateTerrain(const CVector3D& normal, RGBColor& color) const
{
float dot = -normal.Dot(m_SunDir);
color = m_TerrainAmbientColor;
if (dot > 0)
color += m_SunColor * dot;
}
/**
* EvaluateUnit: Calculate brightness of a point of a unit with the given normal
* vector.
* The resulting color contains both ambient and diffuse light.
*
* @param normal normal vector (must have length 1)
* @param color resulting color
*/
void EvaluateUnit(const CVector3D& normal, RGBColor& color) const
{
float dot = -normal.Dot(m_SunDir);
color = m_UnitsAmbientColor;
if (dot > 0)
color += m_SunColor * dot;
}
/**
* EvaluateDirect: Like EvaluateTerrain and EvaluateUnit, but return only the direct
* sunlight term without ambient.
*
* @param normal normal vector (must have length 1)
* @param color resulting color
*/
void EvaluateDirect(const CVector3D& normal, RGBColor& color) const
{
float dot = -normal.Dot(m_SunDir);
if (dot > 0)
color = m_SunColor * dot;
else
color = CVector3D(0,0,0);
}
private:
void CalculateSunDirection()
{
m_SunDir.Y=-float(sin(m_Elevation));

View File

@ -53,8 +53,8 @@ bool CTerrain::Initialize(u32 size,const u16* data)
// store terrain size
m_MapSize=(size*PATCH_SIZE)+1;
m_MapSizePatches=size;
WaterManager *WaterMgr = g_Renderer.GetWaterManager();
WaterMgr->InitWave();
//WaterManager *WaterMgr = g_Renderer.GetWaterManager();
//WaterMgr->InitWave();
// allocate data for new terrain
m_Heightmap=new u16[m_MapSize*m_MapSize];
m_Patches=new CPatch[m_MapSizePatches*m_MapSizePatches];
@ -94,12 +94,12 @@ void CTerrain::CalcPosition(i32 i, i32 j, CVector3D& pos) const
void CTerrain::CalcNormal(u32 i, u32 j, CVector3D& normal) const
{
CVector3D left, right, up, down;
left.Clear();
right.Clear();
up.Clear();
down.Clear();
// get position of vertex where normal is being evaluated
CVector3D basepos;
CalcPosition(i,j,basepos);
@ -128,7 +128,7 @@ void CTerrain::CalcNormal(u32 i, u32 j, CVector3D& normal) const
CVector3D n0 = up.Cross(left);
CVector3D n1 = left.Cross(down);
CVector3D n2 = down.Cross(right);
CVector3D n3 = right.Cross(up);
CVector3D n3 = right.Cross(up);
normal = n0 + n1 + n2 + n3;
float nlen=normal.GetLength();
@ -137,18 +137,18 @@ void CTerrain::CalcNormal(u32 i, u32 j, CVector3D& normal) const
///////////////////////////////////////////////////////////////////////////////
// GetPatch: return the patch at (x,z) in patch space, or null if the patch is
// GetPatch: return the patch at (x,z) in patch space, or null if the patch is
// out of bounds
CPatch* CTerrain::GetPatch(i32 x, i32 z) const
{
if (x<0 || x>=i32(m_MapSizePatches)) return 0;
if (z<0 || z>=i32(m_MapSizePatches)) return 0;
return &m_Patches[(z*m_MapSizePatches)+x];
return &m_Patches[(z*m_MapSizePatches)+x];
}
///////////////////////////////////////////////////////////////////////////////
// GetPatch: return the tile at (x,z) in tile space, or null if the tile is out
// GetPatch: return the tile at (x,z) in tile space, or null if the tile is out
// of bounds
CMiniPatch* CTerrain::GetTile(i32 x, i32 z) const
{
@ -160,7 +160,7 @@ CMiniPatch* CTerrain::GetTile(i32 x, i32 z) const
}
float CTerrain::getVertexGroundLevel(int x, int z) const
{
{
if (x < 0)
{
x = 0;
@ -266,7 +266,7 @@ void CTerrain::Resize(u32 size)
for (u32 i=0;i<newMapSize-m_MapSize;i++) {
*dst++=*(src-1);
}
}
}
}
@ -286,7 +286,7 @@ void CTerrain::Resize(u32 size)
// copy over texture data from existing tiles, if possible
if (i<m_MapSizePatches && j<m_MapSizePatches) {
memcpy2(newPatches[j*size+i].m_MiniPatches,m_Patches[j*m_MapSizePatches+i].m_MiniPatches,sizeof(CMiniPatch)*PATCH_SIZE*PATCH_SIZE);
}
}
}
if (j<m_MapSizePatches && size>m_MapSizePatches) {
@ -303,7 +303,7 @@ void CTerrain::Resize(u32 size)
}
}
}
if (size>m_MapSizePatches) {
// copy over the last tile from each column
CPatch* srcpatch=&newPatches[(m_MapSizePatches-1)*size];
@ -351,7 +351,7 @@ void CTerrain::InitialisePatches()
}
///////////////////////////////////////////////////////////////////////////////
// SetHeightMap: set up a new heightmap from 16-bit source data;
// SetHeightMap: set up a new heightmap from 16-bit source data;
// assumes heightmap matches current terrain size
void CTerrain::SetHeightMap(u16* heightmap)
{
@ -370,15 +370,15 @@ void CTerrain::SetHeightMap(u16* heightmap)
///////////////////////////////////////////////////////////////////////////////
// FlattenArea: flatten out an area of terrain (specified in world space
// FlattenArea: flatten out an area of terrain (specified in world space
// coords); return the average height of the flattened area
float CTerrain::FlattenArea(float x0,float x1,float z0,float z1)
{
u32 tx0=u32(clamp(int(float(x0/CELL_SIZE)),0,int(m_MapSize)));
u32 tx1=u32(clamp(int(float(x1/CELL_SIZE)+1.0f),0,int(m_MapSize)));
u32 tz0=u32(clamp(int(float(z0/CELL_SIZE)),0,int(m_MapSize)));
u32 tz1=u32(clamp(int(float(z1/CELL_SIZE)+1.0f),0,int(m_MapSize)));
u32 tx0=u32(clamp(int(float(x0/CELL_SIZE)),0,int(m_MapSize)));
u32 tx1=u32(clamp(int(float(x1/CELL_SIZE)+1.0f),0,int(m_MapSize)));
u32 tz0=u32(clamp(int(float(z0/CELL_SIZE)),0,int(m_MapSize)));
u32 tz1=u32(clamp(int(float(z1/CELL_SIZE)+1.0f),0,int(m_MapSize)));
u32 count=0;
u32 y=0;
for (u32 x=tx0;x<=tx1;x++) {

View File

@ -114,7 +114,7 @@ static int SetVideoMode(int w, int h, int bpp, bool fullscreen)
// (Note that atexit hooks are guarantueed to be called in reverse order of their registration.)
atexit(SDL_Quit);
// End work around.
glViewport(0, 0, w, h);
#ifndef NO_GUI
@ -255,7 +255,7 @@ void GUI_DisplayLoadProgress(int percent, const wchar_t* pending_task)
#ifndef NO_GUI
CStrW i18n_description = I18n::translate(pending_task);
JSString* js_desc = StringConvert::wstring_to_jsstring(g_ScriptingHost.getContext(), i18n_description);
g_ScriptingHost.SetGlobal("g_Progress", INT_TO_JSVAL(percent));
g_ScriptingHost.SetGlobal("g_Progress", INT_TO_JSVAL(percent));
g_ScriptingHost.SetGlobal("g_LoadDescription", STRING_TO_JSVAL(js_desc));
g_GUI.SendEventToAll("progress");
#endif
@ -331,7 +331,7 @@ void Render()
PROFILE_END( "render selection" );
PROFILE_START( "render building placement cursor" );
if( g_BuildingPlacer.m_active )
if( g_BuildingPlacer.m_active )
{
//glEnable( GL_DEPTH_TEST );
g_BuildingPlacer.render();
@ -339,7 +339,7 @@ void Render()
}
PROFILE_END( "render building placement cursor" );
PROFILE_START( "render health bars" );
glMatrixMode(GL_PROJECTION);
glPushMatrix();
@ -493,7 +493,7 @@ static void InitScripting()
CScriptEvent::ScriptingInit();
CJSProgressTimer::ScriptingInit();
CProjectile::ScriptingInit();
g_ScriptingHost.DefineConstant( "NOTIFY_GOTO", CEntityListener::NOTIFY_GOTO );
g_ScriptingHost.DefineConstant( "NOTIFY_RUN", CEntityListener::NOTIFY_RUN );
g_ScriptingHost.DefineConstant( "NOTIFY_FOLLOW", CEntityListener::NOTIFY_FOLLOW );
@ -605,7 +605,7 @@ static void InitInput()
in_add_handler(CProfileViewer::InputThunk);
in_add_handler(hotkeyInputHandler);
in_add_handler(hotkeyInputHandler);
in_add_handler(GlobalsInputHandler);
}
@ -666,7 +666,7 @@ static void InitRenderer()
g_LightEnv.m_SunColor=RGBColor(1,1,1);
g_LightEnv.SetRotation(DEGTORAD(270));
g_LightEnv.SetElevation(DEGTORAD(45));
g_LightEnv.m_TerrainAmbientColor=RGBColor(0,0,0);
g_LightEnv.m_TerrainAmbientColor=RGBColor(0.4f,0.4f,0.4f);
g_LightEnv.m_UnitsAmbientColor=RGBColor(0.4f,0.4f,0.4f);
g_Renderer.SetLightEnv(&g_LightEnv);
@ -843,7 +843,7 @@ void Init(int argc, char* argv[], uint flags)
// Query CPU capabilities, possibly set some CPU-dependent flags
cpu_init();
// Do this as soon as possible, because it chdirs
// and will mess up the error reporting if anything
// crashes before the working directory is set.
@ -1032,7 +1032,7 @@ void Init(int argc, char* argv[], uint flags)
// Code copied mostly from atlas/GameInterface/Handlers/Map.cpp -
// maybe should be refactored to avoid duplication
g_GameAttributes.m_MapFile = g_AutostartMap+".pmp";
for (int i=1; i<8; ++i)
for (int i=1; i<8; ++i)
g_GameAttributes.GetSlot(i)->AssignLocal();
g_GameAttributes.m_LOSSetting = 2;
g_Game = new CGame();

View File

@ -18,6 +18,7 @@
#include "ps/CLogger.h"
#include "graphics/Color.h"
#include "graphics/LightEnv.h"
#include "graphics/Model.h"
#include "graphics/ModelDef.h"
@ -25,7 +26,6 @@
#include "renderer/Renderer.h"
#include "renderer/RenderModifiers.h"
#include "renderer/RenderPathVertexShader.h"
#include "renderer/SHCoeffs.h"
#include "renderer/VertexArray.h"
@ -39,7 +39,7 @@ struct HWLModelDef : public CModelDefRPrivate
{
/// Indices are the same for all models, so share them
u16* m_Indices;
HWLModelDef(CModelDefPtr mdef);
~HWLModelDef() { delete[] m_Indices; }
@ -57,14 +57,14 @@ struct HWLModel
{
/// Dynamic per-CModel vertex array
VertexArray m_Array;
/// Position and normals are recalculated on CPU every frame
VertexArray::Attribute m_Position;
VertexArray::Attribute m_Normal;
/// UV is stored per-CModel in order to avoid space wastage due to alignment
VertexArray::Attribute m_UV;
HWLModel() : m_Array(true) { }
};
@ -73,7 +73,7 @@ struct HWLightingModelRendererInternals
{
/// Currently used RenderModifier
RenderModifierPtr modifier;
/// Previously prepared modeldef
HWLModelDef* hwlmodeldef;
};
@ -125,13 +125,13 @@ void* HWLightingModelRenderer::CreateModelData(CModel* model)
hwlmodel->m_Normal.type = GL_FLOAT;
hwlmodel->m_Normal.elems = 3;
hwlmodel->m_Array.AddAttribute(&hwlmodel->m_Normal);
hwlmodel->m_Array.SetNumVertices(mdef->GetNumVertices());
hwlmodel->m_Array.Layout();
// Fill in static UV coordinates
VertexArrayIterator<float[2]> UVit = hwlmodel->m_UV.GetIterator<float[2]>();
ModelRenderer::BuildUV(mdef, UVit);
return hwlmodel;
@ -142,17 +142,17 @@ void* HWLightingModelRenderer::CreateModelData(CModel* model)
void HWLightingModelRenderer::UpdateModelData(CModel* model, void* data, u32 updateflags)
{
HWLModel* hwlmodel = (HWLModel*)data;
if (updateflags & RENDERDATA_UPDATE_VERTICES)
{
CModelDefPtr mdef = model->GetModelDef();
// build vertices
VertexArrayIterator<CVector3D> Position = hwlmodel->m_Position.GetIterator<CVector3D>();
VertexArrayIterator<CVector3D> Normal = hwlmodel->m_Normal.GetIterator<CVector3D>();
ModelRenderer::BuildPositionAndNormals(model, Position, Normal);
// upload everything to vertex buffer
hwlmodel->m_Array.Upload();
}
@ -164,7 +164,7 @@ void HWLightingModelRenderer::UpdateModelData(CModel* model, void* data, u32 upd
void HWLightingModelRenderer::DestroyModelData(CModel* UNUSED(model), void* data)
{
HWLModel* hwlmodel = (HWLModel*)data;
delete hwlmodel;
}
@ -173,16 +173,20 @@ void HWLightingModelRenderer::DestroyModelData(CModel* UNUSED(model), void* data
void HWLightingModelRenderer::BeginPass(uint streamflags)
{
glEnableClientState(GL_VERTEX_ARRAY);
if (streamflags & STREAM_UV0) glEnableClientState(GL_TEXTURE_COORD_ARRAY);
if (streamflags & STREAM_COLOR)
{
const RGBColor* coeffs = g_Renderer.m_SHCoeffsUnits.GetCoefficients();
const CLightEnv& lightEnv = g_Renderer.GetLightEnv();
int idx;
ogl_program_use(g_Renderer.m_VertexShader->m_ModelLight);
idx = g_Renderer.m_VertexShader->m_ModelLight_SHCoefficients;
pglUniform3fvARB(idx, 9, (float*)coeffs);
idx = g_Renderer.m_VertexShader->m_ModelLight_Ambient;
pglUniform3fvARB(idx, 1, &lightEnv.m_UnitsAmbientColor.X);
idx = g_Renderer.m_VertexShader->m_ModelLight_SunDir;
pglUniform3fvARB(idx, 1, &lightEnv.m_SunDir.X);
idx = g_Renderer.m_VertexShader->m_ModelLight_SunColor;
pglUniform3fvARB(idx, 1, &lightEnv.m_SunColor.X);
glEnableClientState(GL_NORMAL_ARRAY);
}
@ -199,7 +203,7 @@ void HWLightingModelRenderer::EndPass(uint streamflags)
glDisableClientState(GL_NORMAL_ARRAY);
}
glDisableClientState(GL_VERTEX_ARRAY);
}
@ -208,7 +212,7 @@ void HWLightingModelRenderer::EndPass(uint streamflags)
void HWLightingModelRenderer::PrepareModelDef(uint UNUSED(streamflags), CModelDefPtr def)
{
m->hwlmodeldef = (HWLModelDef*)def->GetRenderData(m);
debug_assert(m->hwlmodeldef);
}
@ -218,16 +222,16 @@ void HWLightingModelRenderer::RenderModel(uint streamflags, CModel* model, void*
{
CModelDefPtr mdldef = model->GetModelDef();
HWLModel* hwlmodel = (HWLModel*)data;
u8* base = hwlmodel->m_Array.Bind();
GLsizei stride = (GLsizei)hwlmodel->m_Array.GetStride();
glVertexPointer(3, GL_FLOAT, stride, base + hwlmodel->m_Position.offset);
if (streamflags & STREAM_COLOR)
{
CColor sc = model->GetShadingColor();
glColor3f(sc.r, sc.g, sc.b);
glNormalPointer(GL_FLOAT, stride, base + hwlmodel->m_Normal.offset);
}
if (streamflags & STREAM_UV0)

View File

@ -18,6 +18,7 @@
#include "ps/CLogger.h"
#include "graphics/Color.h"
#include "graphics/LightEnv.h"
#include "graphics/Model.h"
#include "graphics/ModelDef.h"
@ -25,7 +26,6 @@
#include "renderer/Renderer.h"
#include "renderer/RenderModifiers.h"
#include "renderer/RenderPathVertexShader.h"
#include "renderer/SHCoeffs.h"
#include "renderer/VertexArray.h"
@ -39,15 +39,15 @@ struct IModelDef : public CModelDefRPrivate
{
/// Static per-CModel vertex array
VertexArray m_Array;
/// Position, normals and UV are all static
VertexArray::Attribute m_Position;
VertexArray::Attribute m_Normal;
VertexArray::Attribute m_UV;
/// Indices are the same for all models, so share them
u16* m_Indices;
IModelDef(CModelDefPtr mdef);
~IModelDef() { delete[] m_Indices; }
@ -58,32 +58,32 @@ IModelDef::IModelDef(CModelDefPtr mdef)
: m_Array(false)
{
size_t numVertices = mdef->GetNumVertices();
m_Position.type = GL_FLOAT;
m_Position.elems = 3;
m_Array.AddAttribute(&m_Position);
m_Normal.type = GL_FLOAT;
m_Normal.elems = 3;
m_Array.AddAttribute(&m_Normal);
m_UV.type = GL_FLOAT;
m_UV.elems = 2;
m_Array.AddAttribute(&m_UV);
m_Array.SetNumVertices(numVertices);
m_Array.Layout();
VertexArrayIterator<CVector3D> Position = m_Position.GetIterator<CVector3D>();
VertexArrayIterator<CVector3D> Normal = m_Normal.GetIterator<CVector3D>();
VertexArrayIterator<float[2]> UVit = m_UV.GetIterator<float[2]>();
ModelRenderer::CopyPositionAndNormals(mdef, Position, Normal);
ModelRenderer::BuildUV(mdef, UVit);
m_Array.Upload();
m_Array.FreeBackingStore();
m_Indices = new u16[mdef->GetNumFaces()*3];
ModelRenderer::BuildIndices(mdef, m_Indices);
}
@ -93,7 +93,7 @@ struct InstancingModelRendererInternals
{
/// Currently used RenderModifier
RenderModifierPtr modifier;
/// Previously prepared modeldef
IModelDef* imodeldef;
};
@ -126,13 +126,13 @@ void* InstancingModelRenderer::CreateModelData(CModel* model)
IModelDef* imodeldef = (IModelDef*)mdef->GetRenderData(m);
debug_assert(!model->GetBoneMatrices());
if (!imodeldef)
{
imodeldef = new IModelDef(mdef);
mdef->SetRenderData(m, imodeldef);
}
return NULL;
}
@ -153,16 +153,20 @@ void InstancingModelRenderer::DestroyModelData(CModel* UNUSED(model), void* UNUS
void InstancingModelRenderer::BeginPass(uint streamflags)
{
glEnableClientState(GL_VERTEX_ARRAY);
if (streamflags & STREAM_UV0) glEnableClientState(GL_TEXTURE_COORD_ARRAY);
if (streamflags & STREAM_COLOR)
{
const RGBColor* coeffs = g_Renderer.m_SHCoeffsUnits.GetCoefficients();
const CLightEnv& lightEnv = g_Renderer.GetLightEnv();
int idx;
ogl_program_use(g_Renderer.m_VertexShader->m_InstancingLight);
idx = g_Renderer.m_VertexShader->m_InstancingLight_SHCoefficients;
pglUniform3fvARB(idx, 9, (float*)coeffs);
idx = g_Renderer.m_VertexShader->m_InstancingLight_Ambient;
pglUniform3fvARB(idx, 1, &lightEnv.m_UnitsAmbientColor.X);
idx = g_Renderer.m_VertexShader->m_InstancingLight_SunDir;
pglUniform3fvARB(idx, 1, &lightEnv.m_SunDir.X);
idx = g_Renderer.m_VertexShader->m_InstancingLight_SunColor;
pglUniform3fvARB(idx, 1, &lightEnv.m_SunColor.X);
glEnableClientState(GL_NORMAL_ARRAY);
}
@ -187,12 +191,12 @@ void InstancingModelRenderer::EndPass(uint streamflags)
void InstancingModelRenderer::PrepareModelDef(uint streamflags, CModelDefPtr def)
{
m->imodeldef = (IModelDef*)def->GetRenderData(m);
debug_assert(m->imodeldef);
u8* base = m->imodeldef->m_Array.Bind();
GLsizei stride = (GLsizei)m->imodeldef->m_Array.GetStride();
glVertexPointer(3, GL_FLOAT, stride, base + m->imodeldef->m_Position.offset);
if (streamflags & STREAM_COLOR)
{
@ -211,12 +215,12 @@ void InstancingModelRenderer::RenderModel(uint streamflags, CModel* model, void*
CModelDefPtr mdldef = model->GetModelDef();
const CMatrix3D& mat = model->GetTransform();
RenderPathVertexShader* rpvs = g_Renderer.m_VertexShader;
if (streamflags & STREAM_COLOR)
{
CColor sc = model->GetShadingColor();
glColor3f(sc.r, sc.g, sc.b);
pglVertexAttrib4fARB(rpvs->m_InstancingLight_Instancing1, mat._11, mat._12, mat._13, mat._14);
pglVertexAttrib4fARB(rpvs->m_InstancingLight_Instancing2, mat._21, mat._22, mat._23, mat._24);
pglVertexAttrib4fARB(rpvs->m_InstancingLight_Instancing3, mat._31, mat._32, mat._33, mat._34);

View File

@ -18,6 +18,7 @@
#include "ps/Profile.h"
#include "graphics/Color.h"
#include "graphics/LightEnv.h"
#include "graphics/Model.h"
#include "graphics/ModelDef.h"
@ -25,7 +26,6 @@
#include "renderer/ModelVertexRenderer.h"
#include "renderer/Renderer.h"
#include "renderer/RenderModifiers.h"
#include "renderer/SHCoeffs.h"
#define LOG_CATEGORY "graphics"
@ -84,7 +84,7 @@ void ModelRenderer::CopyPositionAndNormals(
{
size_t numVertices = mdef->GetNumVertices();
SModelVertex* vertices = mdef->GetVertices();
for(size_t j = 0; j < numVertices; ++j)
{
Position[j] = vertices[j].m_Coords;
@ -101,14 +101,14 @@ void ModelRenderer::BuildPositionAndNormals(
CModelDefPtr mdef = model->GetModelDef();
size_t numVertices = mdef->GetNumVertices();
SModelVertex* vertices=mdef->GetVertices();
const CMatrix3D* bonematrices = model->GetBoneMatrices();
if (bonematrices)
{
// boned model - calculate skinned vertex positions/normals
PROFILE( "skinning bones" );
const CMatrix3D* invtranspbonematrices;
// Analytic geometry tells us that normal vectors need to be
// multiplied by the inverse of the transpose. However, calculating
// the inverse is slow, and analytic geometry also tells us that
@ -123,7 +123,7 @@ void ModelRenderer::BuildPositionAndNormals(
invtranspbonematrices = bonematrices;
else
invtranspbonematrices = model->GetInvTranspBoneMatrices();
for (size_t j=0; j<numVertices; j++)
{
SkinPoint(vertices[j],bonematrices,Position[j]);
@ -152,17 +152,19 @@ void ModelRenderer::BuildColor4ub(
VertexArrayIterator<SColor4ub> Color)
{
PROFILE( "lighting vertices" );
CModelDefPtr mdef = model->GetModelDef();
size_t numVertices = mdef->GetNumVertices();
CSHCoeffs& shcoeffs = g_Renderer.m_SHCoeffsUnits;
CColor sc = model->GetShadingColor();
RGBColor shadingcolor(sc.r, sc.g, sc.b);
const CLightEnv& lightEnv = g_Renderer.GetLightEnv();
CColor shadingColor = model->GetShadingColor();
RGBColor tempcolor;
for (uint j=0; j<numVertices; j++)
{
shcoeffs.Evaluate(Normal[j], tempcolor, shadingcolor);
lightEnv.EvaluateUnit(Normal[j], tempcolor);
tempcolor.X *= shadingColor.r;
tempcolor.Y *= shadingColor.g;
tempcolor.Z *= shadingColor.b;
*(u32*)&Color[j] = ConvertRGBColorTo4ub(tempcolor);
}
}
@ -175,7 +177,7 @@ void ModelRenderer::BuildUV(
{
size_t numVertices = mdef->GetNumVertices();
SModelVertex* vertices = mdef->GetVertices();
for (uint j=0; j < numVertices; ++j, ++UV)
{
(*UV)[0] = vertices[j].m_U;
@ -191,7 +193,7 @@ void ModelRenderer::BuildIndices(
{
u32 idxidx = 0;
SModelFace* faces = mdef->GetFaces();
for (size_t j = 0; j < mdef->GetNumFaces(); ++j) {
SModelFace& face=faces[j];
Indices[idxidx++]=face.m_Verts[0];
@ -210,7 +212,7 @@ void ModelRenderer::BuildIndices(
enum BMRPhase {
/// Currently allow calls to Submit and PrepareModels
BMRSubmit,
/// Allow calls to rendering and EndFrame
BMRRender
};
@ -224,13 +226,13 @@ struct BMRModelData : public CModelRData
BMRModelData(BatchModelRendererInternals* bmri, CModel* model)
: CModelRData(bmri, model), m_BMRI(bmri), m_Data(0), m_Next(0) { }
virtual ~BMRModelData();
/// Back-link to "our" modelrenderer
BatchModelRendererInternals* m_BMRI;
/// Private data created by derived class' CreateModelData
void* m_Data;
/// Next model in the per-ModelDefTracker-slot linked list.
BMRModelData* m_Next;
};
@ -238,7 +240,7 @@ struct BMRModelData : public CModelRData
/**
* Class BMRModelDefTracker: Per-CModelDef data used by the BatchModelRenderer.
*
*
* Note that classes that derive from BatchModelRenderer should use
* their own per-CModelDef data if necessary.
*/
@ -255,7 +257,7 @@ struct BMRModelDefTracker : public CModelDefRPrivate
/// Number of slots used in m_ModelSlots
uint m_Slots;
/// Each slot contains a linked list of model data objects, up to m_Slots-1
// At the end of the frame, m_Slots is reset to 0, but m_ModelSlots stays
// the same size (we assume the same number of slots is going to be used
@ -267,32 +269,32 @@ struct BMRModelDefTracker : public CModelDefRPrivate
/**
* Struct BatchModelRendererInternals: Internal data of the BatchModelRenderer
*
* Separated into the source file to increase implementation hiding (and to
*
* Separated into the source file to increase implementation hiding (and to
* avoid some causes of recompiles).
*/
struct BatchModelRendererInternals
{
BatchModelRendererInternals(BatchModelRenderer* r) : m_Renderer(r) { }
/// Back-link to "our" renderer
BatchModelRenderer* m_Renderer;
/// ModelVertexRenderer used for vertex transformations
ModelVertexRendererPtr vertexRenderer;
/// Track the current "phase" of the frame (only for debugging purposes)
BMRPhase phase;
/// Linked list of ModelDefTrackers that have submitted models
BMRModelDefTracker* submissions;
/// Helper functions
void ThunkDestroyModelData(CModel* model, void* data)
{
vertexRenderer->DestroyModelData(model, data);
}
void RenderAllModels(RenderModifierPtr modifier, u32 filterflags, uint pass, uint streamflags);
};
@ -320,19 +322,19 @@ BatchModelRenderer::~BatchModelRenderer()
void BatchModelRenderer::Submit(CModel* model)
{
debug_assert(m->phase == BMRSubmit);
CModelDefPtr mdef = model->GetModelDef();
BMRModelDefTracker* mdeftracker = (BMRModelDefTracker*)mdef->GetRenderData(m);
CModelRData* rdata = (CModelRData*)model->GetRenderData();
BMRModelData* bmrdata = 0;
// Ensure model def data and model data exist
if (!mdeftracker)
{
mdeftracker = new BMRModelDefTracker(mdef);
mdef->SetRenderData(m, mdeftracker);
}
if (rdata && rdata->GetKey() == m)
{
bmrdata = (BMRModelData*)rdata;
@ -357,15 +359,15 @@ void BatchModelRenderer::Submit(CModel* model)
// Add the bmrdata to the modeldef list
Handle htex = model->GetTexture()->GetHandle();
uint idx;
for(idx = 0; idx < mdeftracker->m_Slots; ++idx)
{
BMRModelData* in = mdeftracker->m_ModelSlots[idx];
if (in->GetModel()->GetTexture()->GetHandle() == htex)
break;
}
if (idx >= mdeftracker->m_Slots)
{
++mdeftracker->m_Slots;
@ -386,7 +388,7 @@ void BatchModelRenderer::Submit(CModel* model)
void BatchModelRenderer::PrepareModels()
{
debug_assert(m->phase == BMRSubmit);
for(BMRModelDefTracker* mdeftracker = m->submissions; mdeftracker; mdeftracker = mdeftracker->m_Next)
{
for(uint idx = 0; idx < mdeftracker->m_Slots; ++idx)
@ -394,9 +396,9 @@ void BatchModelRenderer::PrepareModels()
for(BMRModelData* bmrdata = mdeftracker->m_ModelSlots[idx]; bmrdata; bmrdata = bmrdata->m_Next)
{
CModel* model = bmrdata->GetModel();
debug_assert(model->GetRenderData() == bmrdata);
m->vertexRenderer->UpdateModelData(
model, bmrdata->m_Data,
bmrdata->m_UpdateFlags);
@ -404,7 +406,7 @@ void BatchModelRenderer::PrepareModels()
}
}
}
m->phase = BMRRender;
}
@ -413,7 +415,7 @@ void BatchModelRenderer::PrepareModels()
void BatchModelRenderer::EndFrame()
{
static uint mostslots = 1;
for(BMRModelDefTracker* mdeftracker = m->submissions; mdeftracker; mdeftracker = mdeftracker->m_Next)
{
if (mdeftracker->m_Slots > mostslots)
@ -424,7 +426,7 @@ void BatchModelRenderer::EndFrame()
mdeftracker->m_Slots = 0;
}
m->submissions = 0;
m->phase = BMRSubmit;
}
@ -440,18 +442,18 @@ bool BatchModelRenderer::HaveSubmissions()
void BatchModelRenderer::Render(RenderModifierPtr modifier, u32 flags)
{
debug_assert(m->phase == BMRRender);
if (!HaveSubmissions())
return;
uint pass = 0;
do
{
uint streamflags = modifier->BeginPass(pass);
m->vertexRenderer->BeginPass(streamflags);
m->RenderAllModels(modifier, flags, pass, streamflags);
m->vertexRenderer->EndPass(streamflags);
@ -467,7 +469,7 @@ void BatchModelRendererInternals::RenderAllModels(
for(BMRModelDefTracker* mdeftracker = submissions; mdeftracker; mdeftracker = mdeftracker->m_Next)
{
vertexRenderer->PrepareModelDef(streamflags, mdeftracker->m_ModelDef.lock());
for(uint idx = 0; idx < mdeftracker->m_Slots; ++idx)
{
BMRModelData* bmrdata = mdeftracker->m_ModelSlots[idx];
@ -477,12 +479,12 @@ void BatchModelRendererInternals::RenderAllModels(
for(; bmrdata; bmrdata = bmrdata->m_Next)
{
CModel* model = bmrdata->GetModel();
debug_assert(bmrdata->GetKey() == this);
if (filterflags && !(model->GetFlags()&filterflags))
continue;
modifier->PrepareModel(pass, model);
vertexRenderer->RenderModel(streamflags, model, bmrdata->m_Data);
}

View File

@ -15,6 +15,7 @@
#include "boost/shared_ptr.hpp"
#include "graphics/Color.h"
#include "graphics/MeshManager.h"
#include "graphics/RenderableObject.h"
#include "renderer/VertexArray.h"
@ -29,10 +30,10 @@ class CModel;
/**
* Class CModelRData: Render data that is maintained per CModel.
* Class CModelRData: Render data that is maintained per CModel.
* ModelRenderer implementations may derive from this class to store
* per-CModel data.
*
*
* The main purpose of this class over CRenderData is to track which
* ModelRenderer the render data belongs to (via the key that is passed
* to the constructor). When a model changes the renderer it uses
@ -60,11 +61,11 @@ public:
* @return The model pointer that was passed to the constructor.
*/
CModel* GetModel() const { return m_Model; }
private:
/// The key for model renderer identification
const void* m_Key;
/// The model this object was created for
CModel* m_Model;
};
@ -72,25 +73,25 @@ private:
/**
* Class ModelRenderer: Abstract base class for all model renders.
*
*
* A ModelRenderer manages a per-frame list of models.
*
*
* It is supposed to be derived in order to create new ways in which
* the per-frame list of models can be managed (for batching, for
* transparent rendering, etc.) or potentially for rarely used special
* effects.
*
*
* A typical ModelRenderer will delegate vertex transformation/setup
* to a ModelVertexRenderer.
* It will delegate fragment stage setup to a RenderModifier.
*
*
* For most purposes, you should use a BatchModelRenderer with
* specialized ModelVertexRenderer and RenderModifier implementations.
*
*
* It is suggested that a derived class implement the provided generic
* Render function, however in some cases it may be necessary to supply
* a Render function with a different prototype.
*
*
* ModelRenderer also contains a number of static helper functions
* for building vertex arrays.
*/
@ -99,7 +100,7 @@ class ModelRenderer
public:
ModelRenderer() { }
virtual ~ModelRenderer() { }
/**
* Submit: Submit a model for rendering this frame.
*
@ -111,7 +112,7 @@ public:
* submitted this frame.
*/
virtual void Submit(CModel* model) = 0;
/**
* PrepareModels: Calculate renderer data for all previously
* submitted models.
@ -120,25 +121,25 @@ public:
* for this frame have been submitted.
*/
virtual void PrepareModels() = 0;
/**
* EndFrame: Remove all models from the list of submitted
* models.
*/
virtual void EndFrame() = 0;
/**
* HaveSubmissions: Return whether any models have been submitted this frame.
*
* @return true if models have been submitted, false otherwise.
*/
virtual bool HaveSubmissions() = 0;
/**
* Render: Render submitted models, using the given RenderModifier to setup
* the fragment stage.
*
* @note It is suggested that derived model renderers implement and use
* @note It is suggested that derived model renderers implement and use
* this Render functions. However, a highly specialized model renderer
* may need to "disable" this function and provide its own Render function
* with a different prototype.
@ -152,7 +153,7 @@ public:
* CModel::GetFlags() are rendered.
*/
virtual void Render(RenderModifierPtr modifier, u32 flags) = 0;
/**
* CopyPositionAndNormals: Copy unanimated object-space vertices and
* normals into the given vertex array.
@ -169,9 +170,9 @@ public:
CModelDefPtr mdef,
VertexArrayIterator<CVector3D> Position,
VertexArrayIterator<CVector3D> Normal);
/**
* BuildPositionAndNormals: Build animated vertices and normals,
* BuildPositionAndNormals: Build animated vertices and normals,
* transformed into world space.
*
* @param model The model that is to be transformed.
@ -187,7 +188,7 @@ public:
CModel* model,
VertexArrayIterator<CVector3D> Position,
VertexArrayIterator<CVector3D> Normal);
/**
* BuildColor4ub: Build lighting colors for the given model,
* based on previously calculated world space normals.
@ -203,7 +204,7 @@ public:
CModel* model,
VertexArrayIterator<CVector3D> Normal,
VertexArrayIterator<SColor4ub> Color);
/**
* BuildUV: Copy UV coordinates into the given vertex array.
*
@ -220,7 +221,7 @@ public:
* BuildIndices: Create the indices array for the given CModelDef.
*
* @param mdef The model definition object.
* @param Indices The index array, must be able to hold
* @param Indices The index array, must be able to hold
* mdef->GetNumFaces()*3 elements.
*/
static void BuildIndices(
@ -235,14 +236,14 @@ struct BatchModelRendererInternals;
* Class BatchModelRenderer: Model renderer that sorts submitted models
* by CModelDef and texture for batching, and uses a ModelVertexRenderer
* (e.g. FixedFunctionModelRenderer) to manage model vertices.
*
*
* @note Deriving from this class is highly discouraged. Specialize
* using ModelVertexRendererPtr and RenderModifier instead.
*/
class BatchModelRenderer : public ModelRenderer
{
friend struct BatchModelRendererInternals;
public:
BatchModelRenderer(ModelVertexRendererPtr vertexrender);
virtual ~BatchModelRenderer();

View File

@ -5,6 +5,7 @@
#include <algorithm>
#include "Pyrogenesis.h"
#include "lib/res/graphics/ogl_tex.h"
#include "graphics/LightEnv.h"
#include "Renderer.h"
#include "renderer/PatchRData.h"
#include "AlphaMapCalculator.h"
@ -31,7 +32,7 @@ const int BlendOffsets[8][2] = {
///////////////////////////////////////////////////////////////////
// CPatchRData constructor
CPatchRData::CPatchRData(CPatch* patch) : m_Patch(patch), m_VBBase(0), m_VBBlends(0), m_Vertices(0), m_LightingColors(0)
CPatchRData::CPatchRData(CPatch* patch) : m_Patch(patch), m_VBBase(0), m_VBBlends(0), m_Vertices(0)
{
debug_assert(patch);
Build();
@ -39,11 +40,10 @@ CPatchRData::CPatchRData(CPatch* patch) : m_Patch(patch), m_VBBase(0), m_VBBlend
///////////////////////////////////////////////////////////////////
// CPatchRData destructor
CPatchRData::~CPatchRData()
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);
@ -104,7 +104,7 @@ void CPatchRData::BuildBlends()
// build list of textures of higher priority than current tile that are used by neighbouring tiles
std::vector<STex> neighbourTextures;
for (int m=-1;m<=1;m++) {
for (int m=-1;m<=1;m++) {
for (int k=-1;k<=1;k++) {
CMiniPatch* nmp=terrain->GetTile(gx+k,gz+m);
if (nmp && nmp->Tex1 != mp->Tex1) {
@ -127,13 +127,13 @@ void CPatchRData::BuildBlends()
uint count=(uint)neighbourTextures.size();
for (uint k=0;k<count;++k) {
// now build the grid of blends dependent on whether the tile adjacent to the current tile
// now build the grid of blends dependent on whether the tile adjacent to the current tile
// uses the current neighbour texture
BlendShape8 shape;
for (int m=0;m<8;m++) {
int ox=gx+BlendOffsets[m][1];
int oz=gz+BlendOffsets[m][0];
// get texture on adjacent tile
Handle atex=GetTerrainTileTexture(terrain,ox,oz);
// fill 0/1 into shape array
@ -155,18 +155,18 @@ void CPatchRData::BuildBlends()
float t=u0;
u0=u1;
u1=t;
}
}
if (alphamapflags & BLENDMAP_FLIPV) {
// flip v
float t=v0;
v0=v1;
v1=t;
}
}
int base=0;
if (alphamapflags & BLENDMAP_ROTATE90) {
// rotate 1
// rotate 1
base=1;
} else if (alphamapflags & BLENDMAP_ROTATE180) {
// rotate 2
@ -196,7 +196,7 @@ void CPatchRData::BuildBlends()
dst.m_UVs[1]=j*0.125f;
dst.m_AlphaUVs[0]=vtx[0].m_AlphaUVs[0];
dst.m_AlphaUVs[1]=vtx[0].m_AlphaUVs[1];
dst.m_Color=vtx0.m_Color;
dst.m_LOSColor=vtx0.m_LOSColor;
dst.m_Position=vtx0.m_Position;
m_BlendVertices.push_back(dst);
m_BlendVertexIndices.push_back((j*vsize)+i);
@ -206,7 +206,7 @@ void CPatchRData::BuildBlends()
dst.m_UVs[1]=j*0.125f;
dst.m_AlphaUVs[0]=vtx[1].m_AlphaUVs[0];
dst.m_AlphaUVs[1]=vtx[1].m_AlphaUVs[1];
dst.m_Color=vtx1.m_Color;
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);
@ -216,7 +216,7 @@ void CPatchRData::BuildBlends()
dst.m_UVs[1]=(j+1)*0.125f;
dst.m_AlphaUVs[0]=vtx[2].m_AlphaUVs[0];
dst.m_AlphaUVs[1]=vtx[2].m_AlphaUVs[1];
dst.m_Color=vtx2.m_Color;
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);
@ -226,7 +226,7 @@ void CPatchRData::BuildBlends()
dst.m_UVs[1]=(j+1)*0.125f;
dst.m_AlphaUVs[0]=vtx[3].m_AlphaUVs[0];
dst.m_AlphaUVs[1]=vtx[3].m_AlphaUVs[1];
dst.m_Color=vtx3.m_Color;
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);
@ -247,7 +247,7 @@ void CPatchRData::BuildBlends()
}
}
}
// build vertex data
if (m_VBBlends) {
// release existing vertex buffer chunk
@ -257,21 +257,21 @@ void CPatchRData::BuildBlends()
if (m_BlendVertices.size()) {
m_VBBlends=g_VBMan.Allocate(sizeof(SBlendVertex),m_BlendVertices.size(),true);
m_VBBlends->m_Owner->UpdateChunkVertices(m_VBBlends,&m_BlendVertices[0]);
// now build outgoing splats
m_BlendSplats.resize(splatTextures.size());
int splatCount=0;
debug_assert(m_VBBlends->m_Index < 65536);
unsigned short base = (unsigned short)m_VBBlends->m_Index;
std::set<Handle>::iterator iter=splatTextures.begin();
for (;iter!=splatTextures.end();++iter) {
Handle tex=*iter;
SSplat& splat=m_BlendSplats[splatCount];
splat.m_IndexStart=(u32)m_BlendIndices.size();
splat.m_Texture=tex;
for (uint k=0;k<(uint)splats.size();k++) {
if (splats[k].m_Texture==tex) {
m_BlendIndices.push_back(splats[k].m_Indices[0]+base);
@ -314,7 +314,7 @@ void CPatchRData::BuildIndices()
// now build base splats from interior textures
m_Splats.resize(textures.size());
// build indices for base splats
// build indices for base splats
u32 base=(u32)m_VBBase->m_Index;
for (uint i=0;i<(uint)m_Splats.size();i++) {
Handle h=textures[i];
@ -322,7 +322,7 @@ void CPatchRData::BuildIndices()
SSplat& splat=m_Splats[i];
splat.m_Texture=h;
splat.m_IndexStart=(u32)m_Indices.size();
for (int j=0;j<PATCH_SIZE;j++) {
for (int i=0;i<PATCH_SIZE;i++) {
if (texgrid[j][i]==h){
@ -335,7 +335,7 @@ void CPatchRData::BuildIndices()
}
splat.m_IndexCount=(u32)m_Indices.size()-splat.m_IndexStart;
}
// build indices for the shadow map pass
for (int j=0;j<PATCH_SIZE;j++) {
for (int i=0;i<PATCH_SIZE;i++) {
@ -356,19 +356,19 @@ void CPatchRData::BuildVertices()
// 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;
// get index of this patch
u32 px=m_Patch->m_X;
u32 pz=m_Patch->m_Z;
CTerrain* terrain=m_Patch->m_Parent;
const CLightEnv& lightEnv = g_Renderer.GetLightEnv();
// build vertices
for (int j=0;j<vsize;j++) {
@ -378,18 +378,22 @@ void CPatchRData::BuildVertices()
int v=(j*vsize)+i;
// calculate vertex data
terrain->CalcPosition(ix,iz,vertices[v].m_Position);
*(uint32_t*)&vertices[v].m_Color = 0; // will be set to the proper value in Update()
terrain->CalcPosition(ix,iz,vertices[v].m_Position);
*(uint32_t*)&vertices[v].m_LOSColor = 0; // will be set to the proper value in Update()
vertices[v].m_UVs[0]=i*0.125f;
vertices[v].m_UVs[1]=1 - j*0.125f;
// calculate lighting into the separate m_LightingColors array, which will
// be used to set the vertex colors in Update()
// Calculate diffuse lighting for this vertex
// Ambient is added by the lighting pass (since ambient is the same
// for all vertices, it need not be stored in the vertex structure)
terrain->CalcNormal(ix,iz,normal);
g_Renderer.m_SHCoeffsTerrain.Evaluate(normal, m_LightingColors[v]);
RGBColor diffuse;
lightEnv.EvaluateDirect(normal, diffuse);
*(u32*)&vertices[v].m_DiffuseColor = ConvertRGBColorTo4ub(diffuse);
}
}
// upload to vertex buffer
if (!m_VBBase) {
m_VBBase=g_VBMan.Allocate(sizeof(SBaseVertex),vsize*vsize,true);
@ -418,7 +422,7 @@ void CPatchRData::Update()
}
// Update vertex colors, which are affected by LOS
u32 px=m_Patch->m_X;
u32 pz=m_Patch->m_Z;
@ -436,7 +440,7 @@ void CPatchRData::Update()
const int DX[] = {1,1,0,0};
const int DZ[] = {0,1,1,0};
float losMod = 1.0f;
SColor4ub losMod(255, 255, 255, 255);
for(int k=0; k<4; k++)
{
@ -446,17 +450,14 @@ void CPatchRData::Update()
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;
if(s==LOS_EXPLORED && losMod.R > 178)
losMod = SColor4ub(178, 178, 178, 255);
else if(s==LOS_UNEXPLORED && losMod.R > 0)
losMod = SColor4ub(0, 0, 0, 255);
}
}
RGBColor c = m_LightingColors[v];
c *= losMod;
*(uint32_t*)&m_Vertices[v].m_Color = ConvertRGBColorTo4ub(c);
m_Vertices[v].m_LOSColor = losMod;
}
}
@ -464,9 +465,9 @@ void CPatchRData::Update()
m_VBBase->m_Owner->UpdateChunkVertices(m_VBBase,m_Vertices);
// update blend colors by copying them from vertex colors
for(uint i=0; i<m_BlendVertices.size(); i++)
for(uint i=0; i<m_BlendVertices.size(); i++)
{
m_BlendVertices[i].m_Color = m_Vertices[m_BlendVertexIndices[i]].m_Color;
m_BlendVertices[i].m_LOSColor = m_Vertices[m_BlendVertexIndices[i]].m_LOSColor;
}
// upload blend vertices into their vertex buffer too
@ -476,7 +477,7 @@ void CPatchRData::Update()
}
}
void CPatchRData::RenderBase()
void CPatchRData::RenderBase(bool losColor)
{
debug_assert(m_UpdateFlags==0);
@ -485,9 +486,9 @@ void CPatchRData::RenderBase()
// setup data pointers
u32 stride=sizeof(SBaseVertex);
glVertexPointer(3,GL_FLOAT,stride,&base->m_Position[0]);
glColorPointer(4,GL_UNSIGNED_BYTE,stride,&base->m_Color);
glColorPointer(4,GL_UNSIGNED_BYTE,stride,losColor ? &base->m_LOSColor : &base->m_DiffuseColor);
glTexCoordPointer(2,GL_FLOAT,stride,&base->m_UVs[0]);
// render each splat
for (uint i=0;i<(uint)m_Splats.size();i++) {
SSplat& splat=m_Splats[i];
@ -499,7 +500,7 @@ void CPatchRData::RenderBase()
}
}
void CPatchRData::RenderStreams(u32 streamflags)
void CPatchRData::RenderStreams(u32 streamflags, bool losColor)
{
debug_assert(m_UpdateFlags==0);
@ -513,7 +514,11 @@ void CPatchRData::RenderStreams(u32 streamflags)
} else if (streamflags & STREAM_POSTOUV0) {
glTexCoordPointer(3, GL_FLOAT, stride, &base->m_Position);
}
if (streamflags & STREAM_COLOR)
{
glColorPointer(4,GL_UNSIGNED_BYTE,stride,losColor ? &base->m_LOSColor : &base->m_DiffuseColor);
}
// render all base splats at once
glDrawElements(GL_QUADS,(GLsizei)m_Indices.size(),GL_UNSIGNED_SHORT,&m_Indices[0]);
@ -534,8 +539,8 @@ void CPatchRData::RenderBlends()
// setup data pointers
u32 stride=sizeof(SBlendVertex);
glVertexPointer(3,GL_FLOAT,stride,base+offsetof(SBlendVertex,m_Position));
glColorPointer(4,GL_UNSIGNED_BYTE,stride,base+offsetof(SBlendVertex,m_Color));
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

@ -19,14 +19,14 @@ public:
~CPatchRData();
void Update();
void RenderBase();
void RenderBase(bool losColor);
void RenderBlends();
void RenderOutline();
void RenderStreams(u32 streamflags);
void RenderStreams(u32 streamflags, bool losColor);
private:
struct SSplat {
SSplat() : m_Texture(0), m_IndexCount(0) {}
SSplat() : m_Texture(0), m_IndexCount(0) {}
// handle of texture to apply during splat
Handle m_Texture;
@ -39,22 +39,24 @@ private:
struct SBaseVertex {
// vertex position
CVector3D m_Position;
// vertex color
SColor4ub m_Color;
// diffuse color from sunlight
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;
// vertex color
SColor4ub m_Color;
// color modulation from LOS
SColor4ub m_LOSColor;
// vertex uvs for base texture
float m_UVs[2];
// vertex uvs for alpha texture
float m_AlphaUVs[2];
};
};
struct STex {
bool operator==(const STex& rhs) const { return m_Handle==rhs.m_Handle; }
@ -62,7 +64,7 @@ private:
Handle m_Handle;
int m_Priority;
};
// build this renderdata object
void Build();
@ -82,11 +84,6 @@ private:
// 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<unsigned short> m_Indices;

View File

@ -44,7 +44,7 @@ public:
* are required by the fragment stages (see STREAM_XYZ constants).
*/
virtual u32 BeginPass(uint pass) = 0;
/**
* EndPass: Cleanup OpenGL state after the given pass. This function
* may indicate that additional passes are needed.
@ -58,7 +58,7 @@ public:
* increased pass number.
*/
virtual bool EndPass(uint pass) = 0;
/**
* PrepareTexture: Called before rendering models that use the given
* texture.
@ -69,10 +69,10 @@ public:
* @param texture The texture used by subsequent models
*/
virtual void PrepareTexture(uint pass, CTexture* texture) = 0;
/**
* PrepareModel: Called before rendering the given model.
*
*
* Default behaviour does nothing.
*
* @param pass The current pass number (pass == 0 is the first pass)
@ -91,7 +91,6 @@ class RenderModifierRenderer : public ModelRenderer
public:
RenderModifierRenderer() { }
virtual ~RenderModifierRenderer();
};

View File

@ -12,10 +12,14 @@
RenderPathVertexShader::RenderPathVertexShader()
{
m_ModelLight = 0;
m_ModelLight_SHCoefficients = -1;
m_ModelLight_Ambient = -1;
m_ModelLight_SunDir = -1;
m_ModelLight_SunColor = -1;
m_InstancingLight = 0;
m_InstancingLight_SHCoefficients = -1;
m_InstancingLight_Ambient = -1;
m_InstancingLight_SunDir = -1;
m_InstancingLight_SunColor = -1;
m_InstancingLight_Instancing1 = -1;
m_InstancingLight_Instancing2 = -1;
m_InstancingLight_Instancing3 = -1;
@ -50,21 +54,21 @@ bool RenderPathVertexShader::Init()
LOG(WARNING, LOG_CATEGORY, "Failed to load shaders/model_light.xml: %i\n", (int)m_ModelLight);
return false;
}
m_InstancingLight = ogl_program_load("shaders/instancing_light.xml");
if (m_InstancingLight < 0)
{
LOG(WARNING, LOG_CATEGORY, "Failed to load shaders/instancing_light.xml: %i\n", (int)m_InstancingLight);
return false;
}
m_Instancing = ogl_program_load("shaders/instancing.xml");
if (m_Instancing < 0)
{
LOG(WARNING, LOG_CATEGORY, "Failed to load shaders/instancing.xml: %i\n", (int)m_Instancing);
return false;
}
return true;
}
@ -73,10 +77,16 @@ bool RenderPathVertexShader::Init()
// the uniform locations might have changed under us.
void RenderPathVertexShader::BeginFrame()
{
m_ModelLight_SHCoefficients = ogl_program_get_uniform_location(m_ModelLight, "SHCoefficients");
m_InstancingLight_SHCoefficients = ogl_program_get_uniform_location(
m_InstancingLight, "SHCoefficients");
m_ModelLight_Ambient = ogl_program_get_uniform_location(m_ModelLight, "ambient");
m_ModelLight_SunDir = ogl_program_get_uniform_location(m_ModelLight, "sunDir");
m_ModelLight_SunColor = ogl_program_get_uniform_location(m_ModelLight, "sunColor");
m_InstancingLight_Ambient = ogl_program_get_uniform_location(
m_InstancingLight, "ambient");
m_InstancingLight_SunDir = ogl_program_get_uniform_location(
m_InstancingLight, "sunDir");
m_InstancingLight_SunColor = ogl_program_get_uniform_location(
m_InstancingLight, "sunColor");
m_InstancingLight_Instancing1 = ogl_program_get_attrib_location(
m_InstancingLight, "Instancing1");
m_InstancingLight_Instancing2 = ogl_program_get_attrib_location(

View File

@ -6,7 +6,7 @@ class RenderPathVertexShader
public:
RenderPathVertexShader();
~RenderPathVertexShader();
// Initialize this render path.
bool Init();
@ -15,10 +15,14 @@ public:
public:
Handle m_ModelLight;
GLint m_ModelLight_SHCoefficients;
GLint m_ModelLight_Ambient;
GLint m_ModelLight_SunDir;
GLint m_ModelLight_SunColor;
Handle m_InstancingLight;
GLint m_InstancingLight_SHCoefficients;
GLint m_InstancingLight_Ambient;
GLint m_InstancingLight_SunDir;
GLint m_InstancingLight_SunColor;
GLint m_InstancingLight_Instancing1; // matrix rows
GLint m_InstancingLight_Instancing2;
GLint m_InstancingLight_Instancing3;

View File

@ -304,6 +304,8 @@ CRenderer::CRenderer()
m_Models.ModTransparentShadow = RenderModifierPtr(new TransparentShadowRenderModifier);
m_Models.ModTransparentDepthShadow = RenderModifierPtr(new TransparentDepthShadowModifier);
m_ShadowZBias = 0.001;
CEmitter *pEmitter = new CDefaultEmitter(1000, -1);
CParticleEngine::GetInstance()->addEmitter(pEmitter);
@ -584,18 +586,6 @@ void CRenderer::BeginFrame()
// zero out all the per-frame stats
m_Stats.Reset();
// calculate coefficients for terrain and unit lighting
m_SHCoeffsUnits.Clear();
m_SHCoeffsTerrain.Clear();
if (m_LightEnv) {
m_SHCoeffsUnits.AddDirectionalLight(m_LightEnv->m_SunDir, m_LightEnv->m_SunColor);
m_SHCoeffsTerrain.AddDirectionalLight(m_LightEnv->m_SunDir, m_LightEnv->m_SunColor);
m_SHCoeffsUnits.AddAmbientLight(m_LightEnv->m_UnitsAmbientColor);
m_SHCoeffsTerrain.AddAmbientLight(m_LightEnv->m_TerrainAmbientColor);
}
// init per frame stuff
m->shadow->SetupFrame(m_CullCamera, m_LightEnv->m_SunDir);
}
@ -618,6 +608,22 @@ void CRenderer::RenderShadowMap()
glColor4fv(m_Options.m_ShadowColor);
// Figure out transparent rendering strategy
RenderModifierPtr transparentShadows = m_Models.ModTransparentShadow;
if (m->shadow->GetUseDepthTexture())
transparentShadows = m_Models.ModTransparentDepthShadow;
// Render all closed models (i.e. models where rendering back faces will produce
// the correct result)
glCullFace(GL_FRONT);
if (m->shadow->GetUseDepthTexture())
m->terrainRenderer->RenderPatches();
glCullFace(GL_BACK);
// Render models that aren't closed
glDisable(GL_CULL_FACE);
m_Models.NormalFF->Render(m_Models.ModSolidColor, MODELFLAG_CASTSHADOWS);
@ -631,10 +637,6 @@ void CRenderer::RenderShadowMap()
if (m_Models.PlayerInstancing)
m_Models.PlayerInstancing->Render(m_Models.ModSolidColor, MODELFLAG_CASTSHADOWS);
RenderModifierPtr transparentShadows = m_Models.ModTransparentShadow;
if (m->shadow->GetUseDepthTexture())
transparentShadows = m_Models.ModTransparentDepthShadow;
m_Models.TranspFF->Render(transparentShadows, MODELFLAG_CASTSHADOWS);
if (m_Models.TranspHWLit)
@ -660,7 +662,7 @@ void CRenderer::RenderPatches()
// render all the patches, including blend pass
MICROLOG(L"render patch submissions");
m->terrainRenderer->RenderTerrain(m_Options.m_Shadows ? m->shadow : 0, m_Options.m_ShadowColor);
m->terrainRenderer->RenderTerrain(m_Options.m_Shadows ? m->shadow : 0);
if (m_TerrainRenderMode==WIREFRAME) {
// switch wireframe off again
@ -1290,6 +1292,7 @@ void CRenderer::ScriptingInit()
AddProperty(L"sortAllTransparent", &CRenderer::m_SortAllTransparent);
AddProperty(L"fastNormals", &CRenderer::m_FastNormals);
AddProperty(L"displayFrustum", &CRenderer::m_DisplayFrustum);
AddProperty(L"shadowZBias", &CRenderer::m_ShadowZBias);
CJSObject<CRenderer>::ScriptingInit("Renderer");
}

View File

@ -17,7 +17,6 @@
#include "ogl.h"
#include "Camera.h"
#include "Frustum.h"
#include "SHCoeffs.h"
#include "Terrain.h"
#include "Singleton.h"
#include "Overlay.h"
@ -368,10 +367,6 @@ protected:
std::vector<COverlay*> m_Overlays;
// current lighting setup
CLightEnv* m_LightEnv;
// current spherical harmonic coefficients (for unit lighting), derived from lightenv
CSHCoeffs m_SHCoeffsUnits;
// current spherical harmonic coefficients (for terrain lighting), derived from lightenv
CSHCoeffs m_SHCoeffsTerrain;
// ogl_tex handle of composite alpha map (all the alpha maps packed into one texture)
Handle m_hCompositeAlphaMap;
// coordinates of each (untransformed) alpha map within the packed texture
@ -450,6 +445,16 @@ protected:
RenderModifierPtr ModTransparentShadow;
RenderModifierPtr ModTransparentDepthShadow;
} m_Models;
public:
/**
* m_ShadowZBias: Z bias used when rendering shadows into a depth texture.
* This can be used to control shadowing artifacts.
*
* Can be accessed via JS as renderer.shadowZBias
* ShadowMap uses this for matrix calculation.
*/
float m_ShadowZBias;
};

View File

@ -1,85 +0,0 @@
//----------------------------------------------------------------
//
// Name: SHCoeffs.h
// Last Update: 25/11/03
// Author: Rich Cross
// Contact: rich@0ad.wildfiregames.com
//
// Description: implementation of 9 component spherical harmonic
// lighting
//----------------------------------------------------------------
#include "precompiled.h"
#include "SHCoeffs.h"
#include "MathUtil.h"
CSHCoeffs::CSHCoeffs()
{
Clear();
}
void CSHCoeffs::Clear()
{
for (int i=0;i<9;i++) {
_data[i].Clear();
}
}
void CSHCoeffs::AddAmbientLight(const RGBColor& color)
{
_data[0]+=color;
}
void CSHCoeffs::AddDirectionalLight(const CVector3D& lightDir,const RGBColor& lightColor)
{
CVector3D dirToLight(-lightDir.X,-lightDir.Y,-lightDir.Z);
const float normalisation = PI*16/17;
const float c1 = SQR(0.282095f) * normalisation * 1.0f;
const float c2 = SQR(0.488603f) * normalisation * (2.0f/3.0f);
const float c3 = SQR(1.092548f) * normalisation * (1.0f/4.0f);
const float c4 = SQR(0.315392f) * normalisation * (1.0f/4.0f);
const float c5 = SQR(0.546274f) * normalisation * (1.0f/4.0f);
_data[0]+=lightColor*c1;
_data[1]+=lightColor*c2*dirToLight.X;
_data[2]+=lightColor*c2*dirToLight.Y;
_data[3]+=lightColor*c2*dirToLight.Z;
_data[4]+=lightColor*c3*dirToLight.X*dirToLight.Z;
_data[5]+=lightColor*c3*dirToLight.Z*dirToLight.Y;
_data[6]+=lightColor*c3*dirToLight.Y*dirToLight.X;
_data[7]+=lightColor*c4*(3.0f*SQR(dirToLight.Z)-1.0f);
_data[8]+=lightColor*c5*(SQR(dirToLight.X)-SQR(dirToLight.Y));
}
void CSHCoeffs::Evaluate(const CVector3D& normal,RGBColor& color,RGBColor mod) const
{
#if 1
float c4=normal.X*normal.Z;
float c5=normal.Z*normal.Y;
float c6=normal.Y*normal.X;
float c7=(3*SQR(normal.Z)-1.0f);
float c8=(SQR(normal.X)-SQR(normal.Y));
#define DO(C) \
color.C = mod.C * (\
_data[0].C \
+ _data[1].C*normal.X \
+ _data[2].C*normal.Y \
+ _data[3].C*normal.Z \
+ _data[4].C*c4 \
+ _data[5].C*c5 \
+ _data[6].C*c6 \
+ _data[7].C*c7 \
+ _data[8].C*c8)
DO(X);
DO(Y);
DO(Z);
#undef DO
#else
// debug aid: output quantised normal
color=RGBColor((normal.X+1)*0.5,(normal.Y+1)*0.5,(normal.Z+1)*0.5);
#endif
}

View File

@ -1,36 +0,0 @@
//----------------------------------------------------------------
//
// Name: SHCoeffs.h
// Last Update: 25/11/03
// Author: Rich Cross
// Contact: rich@0ad.wildfiregames.com
//
// Description: implementation of 9 component spherical harmonic
// lighting
//----------------------------------------------------------------
#ifndef __SHCOEFFS_H
#define __SHCOEFFS_H
#include "Color.h"
class CSHCoeffs
{
public:
CSHCoeffs();
void Clear();
void AddAmbientLight(const RGBColor& color);
void AddDirectionalLight(const CVector3D& lightDir,const RGBColor& lightColor);
void Evaluate(const CVector3D& normal, RGBColor& color, RGBColor mod=RGBColor(1,1,1)) const;
const RGBColor* GetCoefficients() const { return _data; }
private:
RGBColor _data[9];
};
#endif

View File

@ -174,26 +174,31 @@ void ShadowMapInternals::CalcShadowMatrices()
LightProjection._22 = scale.Y;
LightProjection._24 = shift.Y * scale.Y;
LightProjection._33 = scale.Z;
LightProjection._34 = shift.Z * scale.Z;
LightProjection._34 = shift.Z * scale.Z + renderer.m_ShadowZBias;
LightProjection._44 = 1.0;
// Calculate texture matrix by creating the clip space to texture coordinate matrix
// and then concatenating all matrices that have been calculated so far
CMatrix3D clipToTex;
float texscalex = 0.5 * (float)renderer.GetWidth() / (float)Width;
float texscaley = 0.5 * (float)renderer.GetHeight() / (float)Height;
CMatrix3D lightToTex;
float texscalex = (float)renderer.GetWidth() / (float)Width;
float texscaley = (float)renderer.GetHeight() / (float)Height;
float texscalez = 1.0;
clipToTex.SetZero();
clipToTex._11 = texscalex;
clipToTex._14 = texscalex;
clipToTex._22 = texscaley;
clipToTex._24 = texscaley;
clipToTex._33 = 0.5; // translate -1..1 clip space Z values to tex Z values
clipToTex._34 = 0.5;
clipToTex._44 = 1.0;
texscalex = texscalex / (ShadowBound[1].X - ShadowBound[0].X);
texscaley = texscaley / (ShadowBound[1].Y - ShadowBound[0].Y);
texscalez = texscalez / (ShadowBound[1].Z - ShadowBound[0].Z);
TextureMatrix = clipToTex * LightProjection * LightTransform;
lightToTex.SetZero();
lightToTex._11 = texscalex;
lightToTex._14 = -ShadowBound[0].X * texscalex;
lightToTex._22 = texscaley;
lightToTex._24 = -ShadowBound[0].Y * texscaley;
lightToTex._33 = texscalez;
lightToTex._34 = -ShadowBound[0].Z * texscalez;
lightToTex._44 = 1.0;
TextureMatrix = lightToTex * LightTransform;
}
@ -224,7 +229,7 @@ void ShadowMapInternals::CreateTexture()
{
float* buf = new float[size];
for(uint i = 0; i < size; i++) buf[i] = 1.0;
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, Width, Height, 0,
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, Width, Height, 0,
GL_DEPTH_COMPONENT, GL_FLOAT, buf);
delete[] buf;
}

View File

@ -12,6 +12,7 @@
#include "precompiled.h"
#include "graphics/Camera.h"
#include "graphics/LightEnv.h"
#include "graphics/Patch.h"
#include "graphics/Terrain.h"
@ -57,9 +58,6 @@ struct TerrainRendererInternals
* @todo Merge this list with CPatchRData list
*/
std::vector<CPatch*> visiblePatches;
// Helper functions
void ApplyShadowMap(ShadowMap* shadow, const RGBAColor& shadowColor);
};
@ -128,7 +126,7 @@ bool TerrainRenderer::HaveSubmissions()
///////////////////////////////////////////////////////////////////
// Full-featured terrain rendering with blending and everything
void TerrainRenderer::RenderTerrain(ShadowMap* shadow, const RGBAColor& shadowColor)
void TerrainRenderer::RenderTerrain(ShadowMap* shadow)
{
debug_assert(m->phase == Phase_Render);
@ -137,7 +135,7 @@ void TerrainRenderer::RenderTerrain(ShadowMap* shadow, const RGBAColor& shadowCo
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
// render everything
// render everything fullbright
// set up texture environment for base pass
MICROLOG(L"base splat textures");
pglActiveTextureARB(GL_TEXTURE0);
@ -159,7 +157,7 @@ void TerrainRenderer::RenderTerrain(ShadowMap* shadow, const RGBAColor& shadowCo
for(uint i = 0; i < m->visiblePatches.size(); ++i)
{
CPatchRData* patchdata = (CPatchRData*)m->visiblePatches[i]->GetRenderData();
patchdata->RenderBase();
patchdata->RenderBase(true); // with LOS color
}
// render blends
@ -194,27 +192,87 @@ void TerrainRenderer::RenderTerrain(ShadowMap* shadow, const RGBAColor& shadowCo
patchdata->RenderBlends();
}
// restore OpenGL state
glDepthMask(1);
glDisable(GL_BLEND);
// Disable second texcoord array
pglClientActiveTextureARB(GL_TEXTURE1);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
// Now apply lighting
// Light color is Ambient + ShadowTerm * Diffuse
glBlendFunc(GL_DST_COLOR, GL_ZERO);
pglActiveTextureARB(GL_TEXTURE0); // Diffuse * Shadow
if (shadow)
glBindTexture(GL_TEXTURE_2D, shadow->GetTexture());
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_COLOR);
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);
pglActiveTextureARB(GL_TEXTURE1); // + Ambient
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);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_CONSTANT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
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);
const CLightEnv& lightEnv = g_Renderer.GetLightEnv();
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &lightEnv.m_TerrainAmbientColor.X);
pglActiveTextureARB(GL_TEXTURE0);
if (shadow)
{
const CMatrix3D& texturematrix = shadow->GetTextureMatrix();
glMatrixMode(GL_TEXTURE);
glLoadMatrixf(&texturematrix._11);
glMatrixMode(GL_MODELVIEW);
if (shadow->GetUseDepthTexture())
{
glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
}
}
else
{
glBindTexture(GL_TEXTURE_2D, 0);
}
pglClientActiveTextureARB(GL_TEXTURE0);
for (uint i = 0; i < m->visiblePatches.size(); ++i)
{
CPatchRData* patchdata = (CPatchRData*)m->visiblePatches[i]->GetRenderData();
patchdata->RenderStreams(STREAM_POS|STREAM_COLOR|STREAM_POSTOUV0, false);
}
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
// restore OpenGL state
g_Renderer.BindTexture(1,0);
pglClientActiveTextureARB(GL_TEXTURE0);
pglActiveTextureARB(GL_TEXTURE0);
// switch off all client states
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDepthMask(1);
glDisable(GL_BLEND);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
// Now render shadows as a second pass
if (shadow)
{
m->ApplyShadowMap(shadow, shadowColor);
}
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
@ -228,7 +286,7 @@ void TerrainRenderer::RenderPatches()
for(uint i = 0; i < m->visiblePatches.size(); ++i)
{
CPatchRData* patchdata = (CPatchRData*)m->visiblePatches[i]->GetRenderData();
patchdata->RenderStreams(STREAM_POS);
patchdata->RenderStreams(STREAM_POS, true);
}
glDisableClientState(GL_VERTEX_ARRAY);
}
@ -376,73 +434,3 @@ void TerrainRenderer::RenderWater()
glDisable(GL_TEXTURE_2D);
}
///////////////////////////////////////////////////////////////////
// ApplyShadowMap: add luminance map shadows after rendering the
// actual terrain
void TerrainRendererInternals::ApplyShadowMap(ShadowMap* shadow, const RGBAColor& shadowColor)
{
debug_assert(phase == Phase_Render);
const CMatrix3D& texturematrix = shadow->GetTextureMatrix();
GLuint shadowmap = shadow->GetTexture();
glMatrixMode(GL_TEXTURE);
glLoadMatrixf(&texturematrix._11);
glMatrixMode(GL_MODELVIEW);
g_Renderer.BindTexture(0, shadowmap);
if (shadow->GetUseDepthTexture())
{
glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_GREATER);
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_ONE_MINUS_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_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);
glColor4fv(shadowColor);
glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
}
else
{
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_TEXTURE);
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);
glColor3f(1,1,1);
glBlendFunc(GL_DST_COLOR,GL_ZERO);
}
glEnable(GL_BLEND);
glDepthMask(0);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
for (uint i = 0; i < visiblePatches.size(); ++i)
{
CPatchRData* patchdata = (CPatchRData*)visiblePatches[i]->GetRenderData();
patchdata->RenderStreams(STREAM_POS|STREAM_POSTOUV0);
}
glDepthMask(1);
glDisable(GL_BLEND);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
}

View File

@ -74,7 +74,7 @@ public:
* @param shadow a prepared shadow map, in case rendering with shadows is enabled
* @param shadowColor color of shadows
*/
void RenderTerrain(ShadowMap* shadow, const RGBAColor& shadowColor);
void RenderTerrain(ShadowMap* shadow);
/**
* RenderPatches: Render all patches un-textured as polygons.