Graphics optimisations and features from eihrul.
Add shadow filtering (PCF) option. Fix ugly shadow saturation in old lighting mode. Fix fancy water shader. Fix camera matrix computation. Support scissoring of camera frustum. Optimise vertex skinning. Inline various matrix functions. Support filtering of the list of submitted models before a rendering pass, for more precise culling. Optimise water renderer (fixes #721, based on patch by ortalo). Use scissoring when generating reflection/refraction textures. Skip reflection/refraction texture generation when no water is visible. Render alpha-blended objects differently (fixes #434). Reduce shadow swimming effects. This was SVN commit r9814.
This commit is contained in:
parent
5ada37e8fa
commit
b08e142193
@ -29,6 +29,7 @@ bpp = 0
|
||||
|
||||
fancywater = true
|
||||
shadows = true
|
||||
shadowpcf = true
|
||||
vsync = false
|
||||
|
||||
nos3tc = false
|
||||
|
@ -15,7 +15,7 @@ function openMenuDialog()
|
||||
function openSettingsDialog()
|
||||
{
|
||||
var settings = getGUIObjectByName("settingsDialogPanel");
|
||||
g_SessionDialog.open("Settings", null, settings, 340, 224, null);
|
||||
g_SessionDialog.open("Settings", null, settings, 340, 252, null);
|
||||
}
|
||||
|
||||
function openChat()
|
||||
|
@ -300,7 +300,7 @@
|
||||
<object name="settingsDialogPanel"
|
||||
sprite="genericPanel"
|
||||
type="image"
|
||||
size="50%-180 50%-200 50%+180 50%+50"
|
||||
size="80%-180 50%-200 50%+180 50%+50"
|
||||
hidden="true"
|
||||
z="30"
|
||||
>
|
||||
@ -310,23 +310,30 @@
|
||||
<action on="Load">if (renderer.shadows) this.checked = true; else this.checked = false;</action>
|
||||
<action on="Press">renderer.shadows = this.checked;</action>
|
||||
</object>
|
||||
|
||||
|
||||
<!-- Settings / Shadow PCF -->
|
||||
<object size="0 35 100%-80 60" type="text" style="settingsText" ghost="true">Enable Shadow Filtering</object>
|
||||
<object name="shadowPCFCheckbox" size="100%-56 40 100%-30 65" type="checkbox" style="wheatCrossBox" checked="true">
|
||||
<action on="Load">if (renderer.shadowPCF) this.checked = true; else this.checked = false;</action>
|
||||
<action on="Press">renderer.shadowPCF = this.checked;</action>
|
||||
</object>
|
||||
|
||||
<!-- Settings / Water -->
|
||||
<object size="0 35 100%-80 60" type="text" style="settingsText" ghost="true">Enable Water Reflections</object>
|
||||
<object name="fancyWaterCheckbox" size="100%-56 40 100%-30 65" type="checkbox" style="wheatCrossBox" checked="true">
|
||||
<object size="0 60 100%-80 85" type="text" style="settingsText" ghost="true">Enable Water Reflections</object>
|
||||
<object name="fancyWaterCheckbox" size="100%-56 65 100%-30 90" type="checkbox" style="wheatCrossBox" checked="true">
|
||||
<action on="Load">if (renderer.fancyWater) this.checked = true; else this.checked = false;</action>
|
||||
<action on="Press">renderer.fancyWater = this.checked;</action>
|
||||
</object>
|
||||
|
||||
<!-- Settings / Music-->
|
||||
<object size="0 60 100%-80 85" type="text" style="settingsText" ghost="true">Enable Music</object>
|
||||
<object size="100%-56 65 100%-30 90" type="checkbox" style="wheatCrossBox" checked="true">
|
||||
<object size="0 85 100%-80 110" type="text" style="settingsText" ghost="true">Enable Music</object>
|
||||
<object size="100%-56 90 100%-30 115" type="checkbox" style="wheatCrossBox" checked="true">
|
||||
<action on="Press">if (this.checked) startMusic(); else stopMusic();</action>
|
||||
</object>
|
||||
|
||||
<!-- Settings / Dev Overlay -->
|
||||
<object size="0 85 100%-80 110" type="text" style="settingsText" ghost="true">Developer Overlay</object>
|
||||
<object size="100%-56 90 100%-30 115" type="checkbox" style="wheatCrossBox" checked="false">
|
||||
<object size="0 110 100%-80 135" type="text" style="settingsText" ghost="true">Developer Overlay</object>
|
||||
<object size="100%-56 115 100%-30 140" type="checkbox" style="wheatCrossBox" checked="false">
|
||||
<action on="Press">toggleDeveloperOverlay();</action>
|
||||
</object>
|
||||
</object>
|
||||
|
@ -142,6 +142,7 @@ function RunDetection(settings)
|
||||
var disable_audio = undefined;
|
||||
var disable_s3tc = undefined;
|
||||
var disable_shadows = undefined;
|
||||
var disable_shadowpcf = undefined;
|
||||
var disable_fancywater = undefined;
|
||||
var override_renderpath = undefined;
|
||||
|
||||
@ -212,6 +213,7 @@ function RunDetection(settings)
|
||||
)
|
||||
{
|
||||
disable_shadows = true;
|
||||
disable_shadowpcf = true;
|
||||
}
|
||||
|
||||
// Fragment-shader water is really slow on most Intel devices,
|
||||
@ -222,6 +224,7 @@ function RunDetection(settings)
|
||||
)
|
||||
{
|
||||
disable_fancywater = true;
|
||||
disable_shadowpcf = true;
|
||||
}
|
||||
|
||||
// http://trac.wildfiregames.com/ticket/780
|
||||
@ -238,6 +241,7 @@ function RunDetection(settings)
|
||||
"disable_audio": disable_audio,
|
||||
"disable_s3tc": disable_s3tc,
|
||||
"disable_shadows": disable_shadows,
|
||||
"disable_shadowpcf": disable_shadowpcf,
|
||||
"disable_fancywater": disable_fancywater,
|
||||
"override_renderpath": override_renderpath,
|
||||
};
|
||||
@ -269,6 +273,9 @@ global.RunHardwareDetection = function(settings)
|
||||
if (output.disable_shadows !== undefined)
|
||||
Engine.SetDisableShadows(output.disable_shadows);
|
||||
|
||||
if (output.disable_shadowpcf !== undefined)
|
||||
Engine.SetDisableShadowPCF(output.disable_shadowpcf);
|
||||
|
||||
if (output.disable_fancywater !== undefined)
|
||||
Engine.SetDisableFancyWater(output.disable_fancywater);
|
||||
|
||||
|
@ -29,7 +29,7 @@ for each (var settings in hwdetectTestData)
|
||||
var os = (settings.os_linux ? "linux" : settings.os_macosx ? "macosx" : settings.os_win ? "win" : "???");
|
||||
|
||||
var disabled = [];
|
||||
for each (var d in ["disable_audio", "disable_s3tc", "disable_shadows", "disable_fancywater", "override_renderpath"])
|
||||
for each (var d in ["disable_audio", "disable_s3tc", "disable_shadows", "disable_shadowpcf", "disable_fancywater", "override_renderpath"])
|
||||
if (output[d] !== undefined)
|
||||
disabled.push(d+"="+output[d])
|
||||
|
||||
|
@ -20,6 +20,12 @@
|
||||
PARAM shadingColor = program.local[1];
|
||||
PARAM ambient = program.local[2];
|
||||
|
||||
#ifdef USE_SHADOW_PCF
|
||||
PARAM shadowOffsets1 = program.local[3];
|
||||
PARAM shadowOffsets2 = program.local[4];
|
||||
TEMP offset;
|
||||
#endif
|
||||
|
||||
TEMP tex;
|
||||
TEMP temp;
|
||||
TEMP diffuse;
|
||||
@ -42,14 +48,32 @@ TEX tex, fragment.texcoord[0], texture[0], 2D;
|
||||
// (diffuse is 2*fragment.color due to clamp-avoidance in the vertex program)
|
||||
#ifdef USE_SHADOW
|
||||
#ifdef USE_FP_SHADOW
|
||||
TEX temp, fragment.texcoord[1], texture[1], SHADOW2D;
|
||||
#ifdef USE_SHADOW_PCF
|
||||
MOV offset.zw, fragment.texcoord[1];
|
||||
ADD offset.xy, fragment.texcoord[1], shadowOffsets1;
|
||||
TEX temp.x, offset, texture[1], SHADOW2D;
|
||||
ADD offset.xy, fragment.texcoord[1], shadowOffsets1.zwzw;
|
||||
TEX temp.y, offset, texture[1], SHADOW2D;
|
||||
ADD offset.xy, fragment.texcoord[1], shadowOffsets2;
|
||||
TEX temp.z, offset, texture[1], SHADOW2D;
|
||||
ADD offset.xy, fragment.texcoord[1], shadowOffsets2.zwzw;
|
||||
TEX temp.w, offset, texture[1], SHADOW2D;
|
||||
DP4 temp, temp, 0.25;
|
||||
#else
|
||||
TEX temp, fragment.texcoord[1], texture[1], SHADOW2D;
|
||||
#endif
|
||||
#else
|
||||
TEX tex, fragment.texcoord[1], texture[1], 2D;
|
||||
MOV_SAT temp.z, fragment.texcoord[1].z;
|
||||
SGE temp, tex.x, temp.z;
|
||||
#endif
|
||||
MUL diffuse.rgb, fragment.color, 2.0;
|
||||
MAD_MAYBE_SAT temp.rgb, diffuse, temp, ambient;
|
||||
#ifdef CLAMP_LIGHTING
|
||||
MAD_SAT diffuse.rgb, fragment.color, 2.0, ambient;
|
||||
LRP temp.rgb, temp, diffuse, ambient;
|
||||
#else
|
||||
MUL diffuse.rgb, fragment.color, 2.0;
|
||||
MAD temp.rgb, diffuse, temp, ambient;
|
||||
#endif
|
||||
MUL color.rgb, color, temp;
|
||||
#else
|
||||
MAD_MAYBE_SAT temp.rgb, fragment.color, 2.0, ambient;
|
||||
|
@ -19,6 +19,8 @@
|
||||
<uniform name="objectColor" loc="0" type="vec3"/>
|
||||
<uniform name="shadingColor" loc="1" type="vec3"/>
|
||||
<uniform name="ambient" loc="2" type="vec3"/>
|
||||
<uniform name="shadowOffsets1" loc="3" type="vec4"/>
|
||||
<uniform name="shadowOffsets2" loc="4" type="vec4"/>
|
||||
</fragment>
|
||||
|
||||
</program>
|
||||
|
@ -22,6 +22,8 @@
|
||||
<uniform name="objectColor" loc="0" type="vec3"/>
|
||||
<uniform name="shadingColor" loc="1" type="vec3"/>
|
||||
<uniform name="ambient" loc="2" type="vec3"/>
|
||||
<uniform name="shadowOffsets1" loc="3" type="vec4"/>
|
||||
<uniform name="shadowOffsets2" loc="4" type="vec4"/>
|
||||
</fragment>
|
||||
|
||||
</program>
|
||||
|
@ -13,6 +13,8 @@
|
||||
<uniform name="losTex" loc="3" type="sampler2D"/>
|
||||
|
||||
<uniform name="ambient" loc="0" type="vec3"/>
|
||||
<uniform name="shadowOffsets1" loc="2" type="vec4"/>
|
||||
<uniform name="shadowOffsets2" loc="3" type="vec4"/>
|
||||
</fragment>
|
||||
|
||||
</program>
|
||||
|
@ -16,6 +16,8 @@
|
||||
<uniform name="losTex" loc="3" type="sampler2D"/>
|
||||
|
||||
<uniform name="ambient" loc="0" type="vec3"/>
|
||||
<uniform name="shadowOffsets1" loc="2" type="vec4"/>
|
||||
<uniform name="shadowOffsets2" loc="3" type="vec4"/>
|
||||
</fragment>
|
||||
|
||||
</program>
|
||||
|
@ -19,6 +19,12 @@ PARAM ambient = program.local[0];
|
||||
PARAM shadingColor = program.local[1];
|
||||
#endif
|
||||
|
||||
#ifdef USE_SHADOW_PCF
|
||||
PARAM shadowOffsets1 = program.local[2];
|
||||
PARAM shadowOffsets2 = program.local[3];
|
||||
TEMP offset;
|
||||
#endif
|
||||
|
||||
TEMP tex;
|
||||
TEMP temp;
|
||||
TEMP diffuse;
|
||||
@ -43,14 +49,32 @@ TEX color, fragment.texcoord[0], texture[0], 2D;
|
||||
// (diffuse is 2*fragment.color due to clamp-avoidance in the vertex program)
|
||||
#ifdef USE_SHADOW
|
||||
#ifdef USE_FP_SHADOW
|
||||
TEX temp, fragment.texcoord[2], texture[2], SHADOW2D;
|
||||
#ifdef USE_SHADOW_PCF
|
||||
MOV offset.zw, fragment.texcoord[2];
|
||||
ADD offset.xy, fragment.texcoord[2], shadowOffsets1;
|
||||
TEX temp.x, offset, texture[2], SHADOW2D;
|
||||
ADD offset.xy, fragment.texcoord[2], shadowOffsets1.zwzw;
|
||||
TEX temp.y, offset, texture[2], SHADOW2D;
|
||||
ADD offset.xy, fragment.texcoord[2], shadowOffsets2;
|
||||
TEX temp.z, offset, texture[2], SHADOW2D;
|
||||
ADD offset.xy, fragment.texcoord[2], shadowOffsets2.zwzw;
|
||||
TEX temp.w, offset, texture[2], SHADOW2D;
|
||||
DP4 temp, temp, 0.25;
|
||||
#else
|
||||
TEX temp, fragment.texcoord[2], texture[2], SHADOW2D;
|
||||
#endif
|
||||
#else
|
||||
TEX tex, fragment.texcoord[2], texture[2], 2D;
|
||||
MOV_SAT temp.z, fragment.texcoord[2].z;
|
||||
SGE temp, tex.x, temp.z;
|
||||
#endif
|
||||
MUL diffuse.rgb, fragment.color, 2.0;
|
||||
MAD_MAYBE_SAT temp.rgb, diffuse, temp, ambient;
|
||||
#ifdef CLAMP_LIGHTING
|
||||
MAD_SAT diffuse.rgb, fragment.color, 2.0, ambient;
|
||||
LRP temp.rgb, temp, diffuse, ambient;
|
||||
#else
|
||||
MUL diffuse.rgb, fragment.color, 2.0;
|
||||
MAD temp.rgb, diffuse, temp, ambient;
|
||||
#endif
|
||||
MUL color.rgb, color, temp;
|
||||
#else
|
||||
MAD_MAYBE_SAT temp.rgb, fragment.color, 2.0, ambient;
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
<uniform name="ambient" loc="0" type="vec3"/>
|
||||
<uniform name="shadingColor" loc="1" type="vec3"/>
|
||||
<uniform name="shadowOffsets1" loc="2" type="vec4"/>
|
||||
<uniform name="shadowOffsets2" loc="3" type="vec4"/>
|
||||
</fragment>
|
||||
|
||||
</program>
|
||||
|
@ -16,7 +16,6 @@ uniform vec3 reflectionTint; // Tint for reflection (used for really muddy water
|
||||
uniform float reflectionTintStrength; // Strength of reflection tint (how much of it to mix in)
|
||||
|
||||
varying vec3 worldPos;
|
||||
varying float w;
|
||||
varying float waterDepth;
|
||||
|
||||
void main()
|
||||
@ -24,7 +23,6 @@ void main()
|
||||
vec3 n, l, h, v; // Normal, light vector, half-vector and view vector (vector to eye)
|
||||
float ndotl, ndoth, ndotv;
|
||||
float fresnel;
|
||||
float myMurkiness; // Murkiness and tint at this pixel (tweaked based on lighting and depth)
|
||||
float t; // Temporary variable
|
||||
vec2 reflCoords, refrCoords;
|
||||
vec3 reflColor, refrColor, specular;
|
||||
@ -39,21 +37,16 @@ void main()
|
||||
ndoth = dot(n, h);
|
||||
ndotv = dot(n, v);
|
||||
|
||||
myMurkiness = murkiness * min(waterDepth / fullDepth, 1.0);
|
||||
|
||||
fresnel = pow(1.0 - ndotv, 0.8); // A rather random Fresnel approximation
|
||||
|
||||
refrCoords = 0.5 * (gl_TexCoord[2].xy / gl_TexCoord[2].w) + 0.5; // Unbias texture coords
|
||||
refrCoords -= 0.8 * waviness * n.xz / w; // Refractions can be slightly less wavy
|
||||
|
||||
reflCoords = 0.5 * (gl_TexCoord[1].xy / gl_TexCoord[1].w) + 0.5; // Unbias texture coords
|
||||
reflCoords += waviness * n.xz / w;
|
||||
refrCoords = (0.5*gl_TexCoord[2].xy - 0.8*waviness*n.xz) / gl_TexCoord[2].w + 0.5; // Unbias texture coords
|
||||
reflCoords = (0.5*gl_TexCoord[1].xy + waviness*n.xz) / gl_TexCoord[1].w + 0.5; // Unbias texture coords
|
||||
|
||||
reflColor = mix(texture2D(reflectionMap, reflCoords).rgb, sunColor * reflectionTint,
|
||||
reflectionTintStrength);
|
||||
|
||||
refrColor = (0.5 + 0.5*ndotl) * mix(texture2D(refractionMap, refrCoords).rgb, sunColor * tint,
|
||||
myMurkiness);
|
||||
murkiness * clamp(waterDepth / fullDepth, 0.0, 1.0)); // Murkiness and tint at this pixel (tweaked based on lighting and depth)
|
||||
|
||||
specular = pow(max(0.0, ndoth), shininess) * sunColor * specularStrength;
|
||||
|
||||
|
@ -1,22 +1,19 @@
|
||||
uniform mat4 reflectionMatrix;
|
||||
uniform mat4 refractionMatrix;
|
||||
uniform mat4 losMatrix;
|
||||
uniform vec4 translation;
|
||||
|
||||
attribute float vertexDepth;
|
||||
uniform float repeatScale;
|
||||
uniform vec2 translation;
|
||||
|
||||
varying vec3 worldPos;
|
||||
varying float w;
|
||||
varying float waterDepth;
|
||||
|
||||
void main()
|
||||
{
|
||||
worldPos = gl_Vertex.xyz;
|
||||
waterDepth = vertexDepth;
|
||||
gl_TexCoord[0] = gl_MultiTexCoord0 + translation;
|
||||
waterDepth = dot(gl_Color.xyz, vec3(255.0, -255.0, 1.0));
|
||||
gl_TexCoord[0].st = gl_Vertex.xz*repeatScale + translation;
|
||||
gl_TexCoord[1] = reflectionMatrix * gl_Vertex; // projective texturing
|
||||
gl_TexCoord[2] = reflectionMatrix * gl_Vertex;
|
||||
gl_TexCoord[2] = refractionMatrix * gl_Vertex;
|
||||
gl_TexCoord[3] = losMatrix * gl_Vertex;
|
||||
w = gl_TexCoord[1].w;
|
||||
gl_Position = ftransform();
|
||||
}
|
||||
|
@ -34,7 +34,7 @@
|
||||
#include "renderer/Renderer.h"
|
||||
#include "renderer/WaterManager.h"
|
||||
|
||||
CCamera::CCamera ()
|
||||
CCamera::CCamera()
|
||||
{
|
||||
// set viewport to something anything should handle, but should be initialised
|
||||
// to window size before use
|
||||
@ -44,38 +44,35 @@ CCamera::CCamera ()
|
||||
m_ViewPort.m_Height = 600;
|
||||
}
|
||||
|
||||
CCamera::~CCamera ()
|
||||
CCamera::~CCamera()
|
||||
{
|
||||
}
|
||||
|
||||
void CCamera::SetProjection (float nearp, float farp, float fov)
|
||||
void CCamera::SetProjection(float nearp, float farp, float fov)
|
||||
{
|
||||
m_NearPlane = nearp;
|
||||
m_FarPlane = farp;
|
||||
m_FOV = fov;
|
||||
|
||||
float Aspect = (float)m_ViewPort.m_Width/(float)m_ViewPort.m_Height;
|
||||
|
||||
float w = tanf (m_FOV*0.5f*Aspect);
|
||||
float h = tanf (m_FOV*0.5f);
|
||||
float aspect = (float)m_ViewPort.m_Width/(float)m_ViewPort.m_Height;
|
||||
float f = 1.0f/tanf(m_FOV/2);
|
||||
|
||||
m_ProjMat.SetZero ();
|
||||
m_ProjMat._11 = 1/w;
|
||||
m_ProjMat._22 = 1/h;
|
||||
m_ProjMat._33 = (m_FarPlane+m_NearPlane)/(m_FarPlane-m_NearPlane);
|
||||
m_ProjMat._34 = -2*m_FarPlane*m_NearPlane/(m_FarPlane-m_NearPlane);
|
||||
m_ProjMat._11 = f/aspect;
|
||||
m_ProjMat._22 = f;
|
||||
m_ProjMat._33 = -(m_FarPlane+m_NearPlane)/(m_NearPlane-m_FarPlane);
|
||||
m_ProjMat._34 = 2*m_FarPlane*m_NearPlane/(m_NearPlane-m_FarPlane);
|
||||
m_ProjMat._43 = 1.0f;
|
||||
}
|
||||
|
||||
void CCamera::SetProjectionTile (int tiles, int tile_x, int tile_y)
|
||||
void CCamera::SetProjectionTile(int tiles, int tile_x, int tile_y)
|
||||
{
|
||||
float Aspect = (float)m_ViewPort.m_Width/(float)m_ViewPort.m_Height;
|
||||
|
||||
float w = tanf (m_FOV*0.5f*Aspect) / tiles;
|
||||
float h = tanf (m_FOV*0.5f) / tiles;
|
||||
float aspect = (float)m_ViewPort.m_Width/(float)m_ViewPort.m_Height;
|
||||
float f = 1.0f/tanf(m_FOV/2);
|
||||
|
||||
m_ProjMat._11 = 1/w;
|
||||
m_ProjMat._22 = 1/h;
|
||||
m_ProjMat._11 = tiles*f/aspect;
|
||||
m_ProjMat._22 = tiles*f;
|
||||
m_ProjMat._13 = -(1-tiles + 2*tile_x);
|
||||
m_ProjMat._23 = -(1-tiles + 2*tile_y);
|
||||
}
|
||||
@ -83,7 +80,7 @@ void CCamera::SetProjectionTile (int tiles, int tile_x, int tile_y)
|
||||
//Updates the frustum planes. Should be called
|
||||
//everytime the view or projection matrices are
|
||||
//altered.
|
||||
void CCamera::UpdateFrustum ()
|
||||
void CCamera::UpdateFrustum(const CBound& scissor)
|
||||
{
|
||||
CMatrix3D MatFinal;
|
||||
CMatrix3D MatView;
|
||||
@ -92,46 +89,51 @@ void CCamera::UpdateFrustum ()
|
||||
|
||||
MatFinal = m_ProjMat * MatView;
|
||||
|
||||
//get the RIGHT plane
|
||||
m_ViewFrustum.SetNumPlanes (6);
|
||||
// get the RIGHT plane
|
||||
m_ViewFrustum.SetNumPlanes(6);
|
||||
|
||||
m_ViewFrustum.m_aPlanes[0].m_Norm.X = MatFinal._41-MatFinal._11;
|
||||
m_ViewFrustum.m_aPlanes[0].m_Norm.Y = MatFinal._42-MatFinal._12;
|
||||
m_ViewFrustum.m_aPlanes[0].m_Norm.Z = MatFinal._43-MatFinal._13;
|
||||
m_ViewFrustum.m_aPlanes[0].m_Dist = MatFinal._44-MatFinal._14;
|
||||
m_ViewFrustum.m_aPlanes[0].m_Norm.X = scissor[1].X*MatFinal._41 - MatFinal._11;
|
||||
m_ViewFrustum.m_aPlanes[0].m_Norm.Y = scissor[1].X*MatFinal._42 - MatFinal._12;
|
||||
m_ViewFrustum.m_aPlanes[0].m_Norm.Z = scissor[1].X*MatFinal._43 - MatFinal._13;
|
||||
m_ViewFrustum.m_aPlanes[0].m_Dist = scissor[1].X*MatFinal._44 - MatFinal._14;
|
||||
|
||||
//get the LEFT plane
|
||||
m_ViewFrustum.m_aPlanes[1].m_Norm.X = MatFinal._41+MatFinal._11;
|
||||
m_ViewFrustum.m_aPlanes[1].m_Norm.Y = MatFinal._42+MatFinal._12;
|
||||
m_ViewFrustum.m_aPlanes[1].m_Norm.Z = MatFinal._43+MatFinal._13;
|
||||
m_ViewFrustum.m_aPlanes[1].m_Dist = MatFinal._44+MatFinal._14;
|
||||
// get the LEFT plane
|
||||
m_ViewFrustum.m_aPlanes[1].m_Norm.X = -scissor[0].X*MatFinal._41 + MatFinal._11;
|
||||
m_ViewFrustum.m_aPlanes[1].m_Norm.Y = -scissor[0].X*MatFinal._42 + MatFinal._12;
|
||||
m_ViewFrustum.m_aPlanes[1].m_Norm.Z = -scissor[0].X*MatFinal._43 + MatFinal._13;
|
||||
m_ViewFrustum.m_aPlanes[1].m_Dist = -scissor[0].X*MatFinal._44 + MatFinal._14;
|
||||
|
||||
//get the BOTTOM plane
|
||||
m_ViewFrustum.m_aPlanes[2].m_Norm.X = MatFinal._41+MatFinal._21;
|
||||
m_ViewFrustum.m_aPlanes[2].m_Norm.Y = MatFinal._42+MatFinal._22;
|
||||
m_ViewFrustum.m_aPlanes[2].m_Norm.Z = MatFinal._43+MatFinal._23;
|
||||
m_ViewFrustum.m_aPlanes[2].m_Dist = MatFinal._44+MatFinal._24;
|
||||
// get the BOTTOM plane
|
||||
m_ViewFrustum.m_aPlanes[2].m_Norm.X = -scissor[0].Y*MatFinal._41 + MatFinal._21;
|
||||
m_ViewFrustum.m_aPlanes[2].m_Norm.Y = -scissor[0].Y*MatFinal._42 + MatFinal._22;
|
||||
m_ViewFrustum.m_aPlanes[2].m_Norm.Z = -scissor[0].Y*MatFinal._43 + MatFinal._23;
|
||||
m_ViewFrustum.m_aPlanes[2].m_Dist = -scissor[0].Y*MatFinal._44 + MatFinal._24;
|
||||
|
||||
//get the TOP plane
|
||||
m_ViewFrustum.m_aPlanes[3].m_Norm.X = MatFinal._41-MatFinal._21;
|
||||
m_ViewFrustum.m_aPlanes[3].m_Norm.Y = MatFinal._42-MatFinal._22;
|
||||
m_ViewFrustum.m_aPlanes[3].m_Norm.Z = MatFinal._43-MatFinal._23;
|
||||
m_ViewFrustum.m_aPlanes[3].m_Dist = MatFinal._44-MatFinal._24;
|
||||
// get the TOP plane
|
||||
m_ViewFrustum.m_aPlanes[3].m_Norm.X = scissor[1].Y*MatFinal._41 - MatFinal._21;
|
||||
m_ViewFrustum.m_aPlanes[3].m_Norm.Y = scissor[1].Y*MatFinal._42 - MatFinal._22;
|
||||
m_ViewFrustum.m_aPlanes[3].m_Norm.Z = scissor[1].Y*MatFinal._43 - MatFinal._23;
|
||||
m_ViewFrustum.m_aPlanes[3].m_Dist = scissor[1].Y*MatFinal._44 - MatFinal._24;
|
||||
|
||||
//get the FAR plane
|
||||
m_ViewFrustum.m_aPlanes[4].m_Norm.X = MatFinal._41-MatFinal._31;
|
||||
m_ViewFrustum.m_aPlanes[4].m_Norm.Y = MatFinal._42-MatFinal._32;
|
||||
m_ViewFrustum.m_aPlanes[4].m_Norm.Z = MatFinal._43-MatFinal._33;
|
||||
m_ViewFrustum.m_aPlanes[4].m_Dist = MatFinal._44-MatFinal._34;
|
||||
// get the FAR plane
|
||||
m_ViewFrustum.m_aPlanes[4].m_Norm.X = scissor[1].Z*MatFinal._41 - MatFinal._31;
|
||||
m_ViewFrustum.m_aPlanes[4].m_Norm.Y = scissor[1].Z*MatFinal._42 - MatFinal._32;
|
||||
m_ViewFrustum.m_aPlanes[4].m_Norm.Z = scissor[1].Z*MatFinal._43 - MatFinal._33;
|
||||
m_ViewFrustum.m_aPlanes[4].m_Dist = scissor[1].Z*MatFinal._44 - MatFinal._34;
|
||||
|
||||
//get the NEAR plane
|
||||
m_ViewFrustum.m_aPlanes[5].m_Norm.X = MatFinal._41+MatFinal._31;
|
||||
m_ViewFrustum.m_aPlanes[5].m_Norm.Y = MatFinal._42+MatFinal._32;
|
||||
m_ViewFrustum.m_aPlanes[5].m_Norm.Z = MatFinal._43+MatFinal._33;
|
||||
m_ViewFrustum.m_aPlanes[5].m_Dist = MatFinal._44+MatFinal._34;
|
||||
// get the NEAR plane
|
||||
m_ViewFrustum.m_aPlanes[5].m_Norm.X = -scissor[0].Z*MatFinal._41 + MatFinal._31;
|
||||
m_ViewFrustum.m_aPlanes[5].m_Norm.Y = -scissor[0].Z*MatFinal._42 + MatFinal._32;
|
||||
m_ViewFrustum.m_aPlanes[5].m_Norm.Z = -scissor[0].Z*MatFinal._43 + MatFinal._33;
|
||||
m_ViewFrustum.m_aPlanes[5].m_Dist = -scissor[0].Z*MatFinal._44 + MatFinal._34;
|
||||
}
|
||||
|
||||
void CCamera::SetViewPort (const SViewPort& viewport)
|
||||
void CCamera::ClipFrustum(const CPlane& clipPlane)
|
||||
{
|
||||
m_ViewFrustum.AddPlane(clipPlane);
|
||||
}
|
||||
|
||||
void CCamera::SetViewPort(const SViewPort& viewport)
|
||||
{
|
||||
m_ViewPort.m_X = viewport.m_X;
|
||||
m_ViewPort.m_Y = viewport.m_Y;
|
||||
|
@ -24,6 +24,7 @@
|
||||
#define INCLUDED_CAMERA
|
||||
|
||||
#include "Frustum.h"
|
||||
#include "maths/Bound.h"
|
||||
#include "maths/Matrix3D.h"
|
||||
|
||||
// view port
|
||||
@ -35,27 +36,32 @@ struct SViewPort
|
||||
size_t m_Height;
|
||||
};
|
||||
|
||||
|
||||
class CCamera
|
||||
{
|
||||
public:
|
||||
CCamera ();
|
||||
~CCamera ();
|
||||
CCamera();
|
||||
~CCamera();
|
||||
|
||||
// Methods for projection
|
||||
void SetProjection (float nearp, float farp, float fov);
|
||||
void SetProjectionTile (int tiles, int tile_x, int tile_y);
|
||||
CMatrix3D& GetProjection () { return m_ProjMat; }
|
||||
const CMatrix3D& GetProjection () const { return m_ProjMat; }
|
||||
void SetProjection(float nearp, float farp, float fov);
|
||||
void SetProjectionTile(int tiles, int tile_x, int tile_y);
|
||||
CMatrix3D& GetProjection() { return m_ProjMat; }
|
||||
const CMatrix3D& GetProjection() const { return m_ProjMat; }
|
||||
|
||||
CMatrix3D& GetOrientation() { return m_Orientation; }
|
||||
const CMatrix3D& GetOrientation() const { return m_Orientation; }
|
||||
|
||||
CMatrix3D GetViewProjection() { return m_ProjMat * m_Orientation.GetInverse(); }
|
||||
|
||||
// Updates the frustum planes. Should be called
|
||||
// everytime the view or projection matrices are
|
||||
// altered.
|
||||
void UpdateFrustum ();
|
||||
const CFrustum& GetFrustum () const { return m_ViewFrustum; }
|
||||
void UpdateFrustum(const CBound& scissor = CBound(CVector3D(-1.0f, -1.0f, -1.0f), CVector3D(1.0f, 1.0f, 1.0f)));
|
||||
void ClipFrustum(const CPlane& clipPlane);
|
||||
const CFrustum& GetFrustum() const { return m_ViewFrustum; }
|
||||
|
||||
void SetViewPort (const SViewPort& viewport);
|
||||
const SViewPort& GetViewPort () const { return m_ViewPort; }
|
||||
void SetViewPort(const SViewPort& viewport);
|
||||
const SViewPort& GetViewPort() const { return m_ViewPort; }
|
||||
|
||||
// getters
|
||||
float GetNearPlane() const { return m_NearPlane; }
|
||||
|
@ -49,6 +49,17 @@ void CFrustum::SetNumPlanes (size_t num)
|
||||
m_NumPlanes = MAX_NUM_FRUSTUM_PLANES-1;
|
||||
}
|
||||
|
||||
void CFrustum::AddPlane (const CPlane& plane)
|
||||
{
|
||||
if (m_NumPlanes >= MAX_NUM_FRUSTUM_PLANES)
|
||||
{
|
||||
debug_warn(L"CFrustum::AddPlane: Too many planes");
|
||||
return;
|
||||
}
|
||||
|
||||
m_aPlanes[m_NumPlanes++] = plane;
|
||||
}
|
||||
|
||||
bool CFrustum::IsPointVisible (const CVector3D &point) const
|
||||
{
|
||||
PLANESIDE Side;
|
||||
|
@ -48,6 +48,8 @@ public:
|
||||
|
||||
size_t GetNumPlanes() const { return m_NumPlanes; }
|
||||
|
||||
void AddPlane (const CPlane& plane);
|
||||
|
||||
//The following methods return true if the shape is
|
||||
//partially or completely in front of the frustum planes
|
||||
bool IsPointVisible (const CVector3D &point) const;
|
||||
|
@ -81,18 +81,21 @@ bool CModel::InitModel(const CModelDefPtr& modeldef)
|
||||
size_t numBones = modeldef->GetNumBones();
|
||||
if (numBones != 0)
|
||||
{
|
||||
size_t numBlends = modeldef->GetNumBlends();
|
||||
|
||||
// allocate matrices for bone transformations
|
||||
m_BoneMatrices = new CMatrix3D[numBones];
|
||||
m_BoneMatrices = new CMatrix3D[numBones + numBlends];
|
||||
for (size_t i = 0; i < numBones + numBlends; ++i)
|
||||
{
|
||||
m_BoneMatrices[i].SetIdentity();
|
||||
}
|
||||
|
||||
m_InverseBindBoneMatrices = new CMatrix3D[numBones];
|
||||
|
||||
// store default pose until animation assigned
|
||||
CBoneState* defpose = modeldef->GetBones();
|
||||
for (size_t i = 0; i < numBones; ++i)
|
||||
{
|
||||
m_BoneMatrices[i].SetIdentity();
|
||||
m_BoneMatrices[i].Rotate(defpose[i].m_Rotation);
|
||||
m_BoneMatrices[i].Translate(defpose[i].m_Translation);
|
||||
|
||||
m_InverseBindBoneMatrices[i].SetIdentity();
|
||||
m_InverseBindBoneMatrices[i].Translate(-defpose[i].m_Translation);
|
||||
m_InverseBindBoneMatrices[i].Rotate(defpose[i].m_Rotation.GetInverse());
|
||||
@ -100,7 +103,7 @@ bool CModel::InitModel(const CModelDefPtr& modeldef)
|
||||
}
|
||||
|
||||
m_PositionValid = true;
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -111,7 +114,10 @@ void CModel::CalcBounds()
|
||||
{
|
||||
// Need to calculate the object bounds first, if that hasn't already been done
|
||||
if (! (m_Anim && m_Anim->m_AnimDef))
|
||||
CalcObjectBounds();
|
||||
{
|
||||
if (m_ObjectBounds.IsEmpty())
|
||||
CalcObjectBounds();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_Anim->m_ObjectBounds.IsEmpty())
|
||||
@ -180,7 +186,7 @@ void CModel::CalcAnimatedObjectBound(CSkeletonAnimDef* anim,CBound& result)
|
||||
// extend bounds by vertex positions at the frame
|
||||
for (size_t i=0;i<numverts;i++)
|
||||
{
|
||||
result += CModelDef::SkinPoint(verts[i], GetAnimatedBoneMatrices(), GetInverseBindBoneMatrices());
|
||||
result += CModelDef::SkinPoint(verts[i], GetAnimatedBoneMatrices());
|
||||
}
|
||||
// advance to next frame
|
||||
m_AnimTime += anim->GetFrameTime();
|
||||
@ -322,6 +328,16 @@ void CModel::ValidatePosition()
|
||||
prop.m_Model->SetTransform(proptransform);
|
||||
prop.m_Model->ValidatePosition();
|
||||
}
|
||||
|
||||
if (m_BoneMatrices)
|
||||
{
|
||||
for (size_t i = 0; i < m_pModelDef->GetNumBones(); i++)
|
||||
{
|
||||
m_BoneMatrices[i] = m_BoneMatrices[i] * m_InverseBindBoneMatrices[i];
|
||||
}
|
||||
|
||||
m_pModelDef->BlendBoneMatrices(m_BoneMatrices);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -40,7 +40,7 @@ class CSkeletonAnimManager;
|
||||
#define MODELFLAG_NOLOOPANIMATION (1<<1)
|
||||
#define MODELFLAG_SILHOUETTE_DISPLAY (1<<2)
|
||||
#define MODELFLAG_SILHOUETTE_OCCLUDER (1<<3)
|
||||
|
||||
#define MODELFLAG_FILTERED (1<<4) // used internally by renderer
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CModel: basically, a mesh object - holds the texturing and skinning
|
||||
|
@ -27,24 +27,20 @@
|
||||
#include "maths/Vector4D.h"
|
||||
|
||||
CVector3D CModelDef::SkinPoint(const SModelVertex& vtx,
|
||||
const CMatrix3D newPoseMatrices[],
|
||||
const CMatrix3D inverseBindMatrices[])
|
||||
const CMatrix3D newPoseMatrices[])
|
||||
{
|
||||
CVector3D result (0, 0, 0);
|
||||
|
||||
for (int i = 0; i < SVertexBlend::SIZE && vtx.m_Blend.m_Bone[i] != 0xff; ++i)
|
||||
{
|
||||
CVector3D bindSpace = inverseBindMatrices[vtx.m_Blend.m_Bone[i]].Transform(vtx.m_Coords);
|
||||
CVector3D worldSpace = newPoseMatrices[vtx.m_Blend.m_Bone[i]].Transform(bindSpace);
|
||||
result += worldSpace * vtx.m_Blend.m_Weight[i];
|
||||
result += newPoseMatrices[vtx.m_Blend.m_Bone[i]].Transform(vtx.m_Coords) * vtx.m_Blend.m_Weight[i];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
CVector3D CModelDef::SkinNormal(const SModelVertex& vtx,
|
||||
const CMatrix3D newPoseMatrices[],
|
||||
const CMatrix3D inverseBindMatrices[])
|
||||
const CMatrix3D newPoseMatrices[])
|
||||
{
|
||||
// To be correct, the normal vectors apparently need to be multiplied by the
|
||||
// inverse of the transpose. Unfortunately inverses are slow.
|
||||
@ -73,9 +69,7 @@ CVector3D CModelDef::SkinNormal(const SModelVertex& vtx,
|
||||
|
||||
for (int i = 0; i < SVertexBlend::SIZE && vtx.m_Blend.m_Bone[i] != 0xff; ++i)
|
||||
{
|
||||
CVector3D bindSpace = inverseBindMatrices[vtx.m_Blend.m_Bone[i]].Rotate(vtx.m_Norm);
|
||||
CVector3D worldSpace = newPoseMatrices[vtx.m_Blend.m_Bone[i]].Rotate(bindSpace);
|
||||
result += worldSpace * vtx.m_Blend.m_Weight[i];
|
||||
result += newPoseMatrices[vtx.m_Blend.m_Bone[i]].Rotate(vtx.m_Norm) * vtx.m_Blend.m_Weight[i];
|
||||
}
|
||||
|
||||
// If there was more than one influence, the result is probably not going
|
||||
@ -94,27 +88,15 @@ void CModelDef::SkinPointsAndNormals(
|
||||
const VertexArrayIterator<CVector3D>& Position,
|
||||
const VertexArrayIterator<CVector3D>& Normal,
|
||||
const SModelVertex* vertices,
|
||||
const CMatrix3D newPoseMatrices[],
|
||||
const CMatrix3D inverseBindMatrices[])
|
||||
const size_t* blendIndices,
|
||||
const CMatrix3D newPoseMatrices[])
|
||||
{
|
||||
for (size_t j = 0; j < numVertices; ++j)
|
||||
{
|
||||
const SModelVertex vtx = vertices[j];
|
||||
const SModelVertex& vtx = vertices[j];
|
||||
|
||||
CVector3D pos(0, 0, 0);
|
||||
CVector3D normal(0, 0, 0);
|
||||
|
||||
for (int i = 0; i < SVertexBlend::SIZE && vtx.m_Blend.m_Bone[i] != 0xff; ++i)
|
||||
{
|
||||
CVector3D posBindSpace = inverseBindMatrices[vtx.m_Blend.m_Bone[i]].Transform(vtx.m_Coords);
|
||||
CVector3D normBindSpace = inverseBindMatrices[vtx.m_Blend.m_Bone[i]].Rotate(vtx.m_Norm);
|
||||
|
||||
CVector3D posWorldSpace = newPoseMatrices[vtx.m_Blend.m_Bone[i]].Transform(posBindSpace);
|
||||
CVector3D normWorldSpace = newPoseMatrices[vtx.m_Blend.m_Bone[i]].Rotate(normBindSpace);
|
||||
|
||||
pos += posWorldSpace * vtx.m_Blend.m_Weight[i];
|
||||
normal += normWorldSpace * vtx.m_Blend.m_Weight[i];
|
||||
}
|
||||
Position[j] = newPoseMatrices[blendIndices[j]].Transform(vtx.m_Coords);
|
||||
Normal[j] = newPoseMatrices[blendIndices[j]].Rotate(vtx.m_Norm);
|
||||
|
||||
// If there was more than one influence, the result is probably not going
|
||||
// to be of unit length (since it's a weighted sum of several independent
|
||||
@ -122,16 +104,30 @@ void CModelDef::SkinPointsAndNormals(
|
||||
// (It's fairly common to only have one influence, so it seems sensible to
|
||||
// optimise that case a bit.)
|
||||
if (vtx.m_Blend.m_Bone[1] != 0xff) // if more than one influence
|
||||
normal.Normalize();
|
||||
Normal[j].Normalize();
|
||||
}
|
||||
}
|
||||
|
||||
Position[j] = pos;
|
||||
Normal[j] = normal;
|
||||
void CModelDef::BlendBoneMatrices(
|
||||
CMatrix3D boneMatrices[])
|
||||
{
|
||||
for (size_t i = 0; i < m_NumBlends; ++i)
|
||||
{
|
||||
const SVertexBlend& blend = m_pBlends[i];
|
||||
CMatrix3D& boneMatrix = boneMatrices[m_NumBones + i];
|
||||
boneMatrix.Blend(boneMatrices[blend.m_Bone[0]], blend.m_Weight[0]);
|
||||
boneMatrix.AddBlend(boneMatrices[blend.m_Bone[1]], blend.m_Weight[1]);
|
||||
for (size_t j = 2; j < SVertexBlend::SIZE && blend.m_Bone[j] != 0xFF; ++j)
|
||||
{
|
||||
boneMatrix.AddBlend(boneMatrices[blend.m_Bone[j]], blend.m_Weight[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CModelDef Constructor
|
||||
CModelDef::CModelDef()
|
||||
: m_NumVertices(0), m_pVertices(0), m_NumFaces(0), m_pFaces(0), m_NumBones(0), m_Bones(0),
|
||||
CModelDef::CModelDef() :
|
||||
m_NumVertices(0), m_pVertices(0), m_NumFaces(0), m_pFaces(0), m_NumBones(0), m_Bones(0),
|
||||
m_NumBlends(0), m_pBlends(0), m_pBlendIndices(0),
|
||||
m_Name(L"[not loaded]")
|
||||
{
|
||||
}
|
||||
@ -144,6 +140,8 @@ CModelDef::~CModelDef()
|
||||
delete[] m_pVertices;
|
||||
delete[] m_pFaces;
|
||||
delete[] m_Bones;
|
||||
delete[] m_pBlends;
|
||||
delete[] m_pBlendIndices;
|
||||
}
|
||||
|
||||
// FindPropPoint: find and return pointer to prop point matching given name;
|
||||
@ -187,6 +185,34 @@ CModelDef* CModelDef::Load(const VfsPath& filename, const VfsPath& name)
|
||||
{
|
||||
mdef->m_Bones=new CBoneState[mdef->m_NumBones];
|
||||
unpacker.UnpackRaw(mdef->m_Bones,mdef->m_NumBones*sizeof(CBoneState));
|
||||
|
||||
mdef->m_pBlendIndices = new size_t[mdef->m_NumVertices];
|
||||
std::vector<SVertexBlend> blends;
|
||||
for (size_t i = 0; i < mdef->m_NumVertices; i++)
|
||||
{
|
||||
const SVertexBlend &blend = mdef->m_pVertices[i].m_Blend;
|
||||
if (blend.m_Bone[1] == 0xFF)
|
||||
{
|
||||
mdef->m_pBlendIndices[i] = blend.m_Bone[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
// If there's already a vertex using the same blend as this, then
|
||||
// reuse its entry from blends; otherwise add the new one to blends
|
||||
size_t j;
|
||||
for (j = 0; j < blends.size(); j++)
|
||||
{
|
||||
if (blend == blends[j]) break;
|
||||
}
|
||||
if (j >= blends.size())
|
||||
blends.push_back(blend);
|
||||
mdef->m_pBlendIndices[i] = mdef->m_NumBones + j;
|
||||
}
|
||||
}
|
||||
|
||||
mdef->m_NumBlends = blends.size();
|
||||
mdef->m_pBlends = new SVertexBlend[mdef->m_NumBlends];
|
||||
std::copy(blends.begin(), blends.end(), mdef->m_pBlends);
|
||||
}
|
||||
|
||||
if (unpacker.GetVersion() >= 2)
|
||||
@ -232,10 +258,6 @@ CModelDef* CModelDef::Load(const VfsPath& filename, const VfsPath& name)
|
||||
|
||||
if (mdef->m_NumBones) // only do skinned models
|
||||
{
|
||||
CMatrix3D identity;
|
||||
identity.SetIdentity();
|
||||
std::vector<CMatrix3D> identityBones (mdef->m_NumBones, identity);
|
||||
|
||||
std::vector<CMatrix3D> bindPose (mdef->m_NumBones);
|
||||
|
||||
for (size_t i = 0; i < mdef->m_NumBones; ++i)
|
||||
@ -247,8 +269,8 @@ CModelDef* CModelDef::Load(const VfsPath& filename, const VfsPath& name)
|
||||
|
||||
for (size_t i = 0; i < mdef->m_NumVertices; ++i)
|
||||
{
|
||||
mdef->m_pVertices[i].m_Coords = SkinPoint(mdef->m_pVertices[i], &bindPose[0], &identityBones[0]);
|
||||
mdef->m_pVertices[i].m_Norm = SkinNormal(mdef->m_pVertices[i], &bindPose[0], &identityBones[0]);
|
||||
mdef->m_pVertices[i].m_Coords = SkinPoint(mdef->m_pVertices[i], &bindPose[0]);
|
||||
mdef->m_pVertices[i].m_Norm = SkinNormal(mdef->m_pVertices[i], &bindPose[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "lib/file/vfs/vfs_path.h"
|
||||
#include "renderer/VertexArray.h"
|
||||
#include <map>
|
||||
#include <cstring>
|
||||
|
||||
class CBoneState;
|
||||
|
||||
@ -57,6 +58,11 @@ struct SVertexBlend
|
||||
u8 m_Bone[SIZE];
|
||||
// weight of the influence; all weights sum to 1
|
||||
float m_Weight[SIZE];
|
||||
|
||||
bool operator==(const SVertexBlend& o) const
|
||||
{
|
||||
return !memcmp(m_Bone, o.m_Bone, sizeof(m_Bone)) && !memcmp(m_Weight, o.m_Weight, sizeof(m_Weight));
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@ -124,17 +130,22 @@ public:
|
||||
|
||||
public:
|
||||
// accessor: get vertex data
|
||||
size_t GetNumVertices() const { return (size_t)m_NumVertices; }
|
||||
size_t GetNumVertices() const { return m_NumVertices; }
|
||||
SModelVertex* GetVertices() const { return m_pVertices; }
|
||||
|
||||
// accessor: get face data
|
||||
size_t GetNumFaces() const { return (size_t)m_NumFaces; }
|
||||
size_t GetNumFaces() const { return m_NumFaces; }
|
||||
SModelFace* GetFaces() const { return m_pFaces; }
|
||||
|
||||
// accessor: get bone data
|
||||
size_t GetNumBones() const { return (size_t)m_NumBones; }
|
||||
size_t GetNumBones() const { return m_NumBones; }
|
||||
CBoneState* GetBones() const { return m_Bones; }
|
||||
|
||||
// accessor: get blend data
|
||||
size_t GetNumBlends() const { return m_NumBlends; }
|
||||
SVertexBlend* GetBlends() const { return m_pBlends; }
|
||||
size_t* GetBlendIndices() const { return m_pBlendIndices; }
|
||||
|
||||
// find and return pointer to prop point matching given name; return
|
||||
// null if no match (case insensitive search)
|
||||
const SPropPoint* FindPropPoint(const char* name) const;
|
||||
@ -145,7 +156,7 @@ public:
|
||||
* @return new world-space vertex coordinates
|
||||
*/
|
||||
static CVector3D SkinPoint(const SModelVertex& vtx,
|
||||
const CMatrix3D newPoseMatrices[], const CMatrix3D inverseBindMatrices[]);
|
||||
const CMatrix3D newPoseMatrices[]);
|
||||
|
||||
/**
|
||||
* Transform the given vertex's normal from the bind pose into the new pose.
|
||||
@ -153,7 +164,7 @@ public:
|
||||
* @return new world-space vertex normal
|
||||
*/
|
||||
static CVector3D SkinNormal(const SModelVertex& vtx,
|
||||
const CMatrix3D newPoseMatrices[], const CMatrix3D inverseBindMatrices[]);
|
||||
const CMatrix3D newPoseMatrices[]);
|
||||
|
||||
/**
|
||||
* Transform vertices' positions and normals.
|
||||
@ -165,8 +176,13 @@ public:
|
||||
const VertexArrayIterator<CVector3D>& Position,
|
||||
const VertexArrayIterator<CVector3D>& Normal,
|
||||
const SModelVertex* vertices,
|
||||
const CMatrix3D newPoseMatrices[],
|
||||
const CMatrix3D inverseBindMatrices[]);
|
||||
const size_t* blendIndices,
|
||||
const CMatrix3D newPoseMatrices[]);
|
||||
|
||||
/**
|
||||
* Blend bone matrices together to fill bone palette.
|
||||
*/
|
||||
void BlendBoneMatrices(CMatrix3D boneMatrices[]);
|
||||
|
||||
/**
|
||||
* Register renderer private data. Use the key to
|
||||
@ -200,6 +216,10 @@ public:
|
||||
// bone data - default model pose
|
||||
size_t m_NumBones;
|
||||
CBoneState* m_Bones;
|
||||
// blend data
|
||||
size_t m_NumBlends;
|
||||
SVertexBlend *m_pBlends;
|
||||
size_t* m_pBlendIndices;
|
||||
// prop point data
|
||||
std::vector<SPropPoint> m_PropPoints;
|
||||
|
||||
|
@ -21,7 +21,7 @@
|
||||
|
||||
CShaderPass::CShaderPass(const CShaderProgramPtr& shader) :
|
||||
m_Shader(shader),
|
||||
m_HasAlpha(false), m_HasBlend(false), m_HasColorMask(false), m_HasDepthMask(false)
|
||||
m_HasAlpha(false), m_HasBlend(false), m_HasColorMask(false), m_HasDepthMask(false), m_HasDepthFunc(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -46,6 +46,9 @@ void CShaderPass::Bind()
|
||||
|
||||
if (m_HasDepthMask)
|
||||
glDepthMask(m_DepthMask);
|
||||
|
||||
if (m_HasDepthFunc)
|
||||
glDepthFunc(m_DepthFunc);
|
||||
}
|
||||
|
||||
void CShaderPass::Unbind()
|
||||
@ -67,6 +70,9 @@ void CShaderPass::Unbind()
|
||||
|
||||
if (m_HasDepthMask)
|
||||
glDepthMask(1);
|
||||
|
||||
if (m_HasDepthFunc)
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
}
|
||||
|
||||
void CShaderPass::AlphaFunc(GLenum func, GLclampf ref)
|
||||
@ -98,6 +104,12 @@ void CShaderPass::DepthMask(GLboolean mask)
|
||||
m_DepthMask = mask;
|
||||
}
|
||||
|
||||
void CShaderPass::DepthFunc(GLenum func)
|
||||
{
|
||||
m_HasDepthFunc = true;
|
||||
m_DepthFunc = func;
|
||||
}
|
||||
|
||||
|
||||
CShaderTechnique::CShaderTechnique(const CShaderPass& pass)
|
||||
{
|
||||
|
@ -33,6 +33,7 @@ public:
|
||||
void BlendFunc(GLenum src, GLenum dst);
|
||||
void ColorMask(GLboolean r, GLboolean g, GLboolean b, GLboolean a);
|
||||
void DepthMask(GLboolean mask);
|
||||
void DepthFunc(GLenum func);
|
||||
|
||||
/**
|
||||
* Set all the GL state that was previously specified on this pass.
|
||||
@ -65,6 +66,9 @@ private:
|
||||
|
||||
bool m_HasDepthMask;
|
||||
GLboolean m_DepthMask;
|
||||
|
||||
bool m_HasDepthFunc;
|
||||
GLenum m_DepthFunc;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -32,36 +32,6 @@
|
||||
#include "maths/Matrix3D.h"
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// operator+=: extend this bound to include given bound
|
||||
CBound& CBound::operator+=(const CBound& b)
|
||||
{
|
||||
#define CMPT(c) \
|
||||
if (b[0].c < m_Data[0].c) m_Data[0].c = b[0].c; \
|
||||
if (b[1].c > m_Data[1].c) m_Data[1].c = b[1].c
|
||||
CMPT(X);
|
||||
CMPT(Y);
|
||||
CMPT(Z);
|
||||
#undef CMPT
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// operator+=: extend this bound to include given point
|
||||
CBound& CBound::operator+=(const CVector3D& pt)
|
||||
{
|
||||
#define CMPT(c) \
|
||||
if (pt.c < m_Data[0].c) m_Data[0].c = pt.c; \
|
||||
if (pt.c > m_Data[1].c) m_Data[1].c = pt.c
|
||||
CMPT(X);
|
||||
CMPT(Y);
|
||||
CMPT(Z);
|
||||
#undef CMPT
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RayIntersect: intersect ray with this bound; return true
|
||||
// if ray hits (and store entry and exit times), or false
|
||||
@ -156,7 +126,7 @@ void CBound::SetEmpty()
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// IsEmpty: tests whether this bound is empty
|
||||
bool CBound::IsEmpty()
|
||||
bool CBound::IsEmpty() const
|
||||
{
|
||||
return (m_Data[0].X == FLT_MAX && m_Data[0].Y == FLT_MAX && m_Data[0].Z == FLT_MAX
|
||||
&& m_Data[1].X == -FLT_MAX && m_Data[1].Y == -FLT_MAX && m_Data[1].Z == -FLT_MAX);
|
||||
|
@ -44,17 +44,38 @@ public:
|
||||
const CVector3D& operator[](int index) const { return m_Data[index]; }
|
||||
|
||||
void SetEmpty();
|
||||
bool IsEmpty();
|
||||
bool IsEmpty() const;
|
||||
|
||||
CBound& operator+=(const CBound& b);
|
||||
CBound& operator+=(const CVector3D& pt);
|
||||
void Extend(const CVector3D& min, const CVector3D& max)
|
||||
{
|
||||
if (min.X < m_Data[0].X) m_Data[0].X = min.X;
|
||||
if (min.Y < m_Data[0].Y) m_Data[0].Y = min.Y;
|
||||
if (min.Z < m_Data[0].Z) m_Data[0].Z = min.Z;
|
||||
if (max.X > m_Data[1].X) m_Data[1].X = max.X;
|
||||
if (max.Y > m_Data[1].Y) m_Data[1].Y = max.Y;
|
||||
if (max.Z > m_Data[1].Z) m_Data[1].Z = max.Z;
|
||||
}
|
||||
|
||||
// operator+=: extend this bound to include given bound
|
||||
CBound& operator+=(const CBound& b)
|
||||
{
|
||||
Extend(b.m_Data[0], b.m_Data[1]);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// operator+=: extend this bound to include given point
|
||||
CBound& operator+=(const CVector3D& pt)
|
||||
{
|
||||
Extend(pt, pt);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool RayIntersect(const CVector3D& origin,const CVector3D& dir,float& tmin,float& tmax) const;
|
||||
|
||||
// return the volume of this bounding box
|
||||
float GetVolume() const {
|
||||
CVector3D v=m_Data[1]-m_Data[0];
|
||||
return v.X*v.Y*v.Z;
|
||||
return std::max(v.X, 0.0f)*std::max(v.Y, 0.0f)*std::max(v.Z, 0.0f);
|
||||
}
|
||||
|
||||
// return the centre of this bounding box
|
||||
|
@ -23,7 +23,7 @@
|
||||
#define SQR(x) ((x) * (x))
|
||||
|
||||
template <typename T>
|
||||
T Interpolate(const T& a, const T& b, float l)
|
||||
inline T Interpolate(const T& a, const T& b, float l)
|
||||
{
|
||||
return a + (b - a) * l;
|
||||
}
|
||||
|
@ -26,109 +26,6 @@
|
||||
#include "Quaternion.h"
|
||||
#include "Vector4D.h"
|
||||
|
||||
CMatrix3D::CMatrix3D ()
|
||||
{
|
||||
}
|
||||
|
||||
CMatrix3D::CMatrix3D(
|
||||
float a11, float a12, float a13, float a14,
|
||||
float a21, float a22, float a23, float a24,
|
||||
float a31, float a32, float a33, float a34,
|
||||
float a41, float a42, float a43, float a44) :
|
||||
_11(a11), _12(a12), _13(a13), _14(a14),
|
||||
_21(a21), _22(a22), _23(a23), _24(a24),
|
||||
_31(a31), _32(a32), _33(a33), _34(a34),
|
||||
_41(a41), _42(a42), _43(a43), _44(a44)
|
||||
{
|
||||
}
|
||||
|
||||
CMatrix3D::CMatrix3D(float data[])
|
||||
{
|
||||
for(int i=0; i<16; i++)
|
||||
{
|
||||
_data[i] = data[i];
|
||||
}
|
||||
}
|
||||
|
||||
//Matrix multiplication
|
||||
CMatrix3D CMatrix3D::operator*(const CMatrix3D& matrix) const
|
||||
{
|
||||
return CMatrix3D(
|
||||
_11*matrix._11 + _12*matrix._21 + _13*matrix._31 + _14*matrix._41,
|
||||
_11*matrix._12 + _12*matrix._22 + _13*matrix._32 + _14*matrix._42,
|
||||
_11*matrix._13 + _12*matrix._23 + _13*matrix._33 + _14*matrix._43,
|
||||
_11*matrix._14 + _12*matrix._24 + _13*matrix._34 + _14*matrix._44,
|
||||
|
||||
_21*matrix._11 + _22*matrix._21 + _23*matrix._31 + _24*matrix._41,
|
||||
_21*matrix._12 + _22*matrix._22 + _23*matrix._32 + _24*matrix._42,
|
||||
_21*matrix._13 + _22*matrix._23 + _23*matrix._33 + _24*matrix._43,
|
||||
_21*matrix._14 + _22*matrix._24 + _23*matrix._34 + _24*matrix._44,
|
||||
|
||||
_31*matrix._11 + _32*matrix._21 + _33*matrix._31 + _34*matrix._41,
|
||||
_31*matrix._12 + _32*matrix._22 + _33*matrix._32 + _34*matrix._42,
|
||||
_31*matrix._13 + _32*matrix._23 + _33*matrix._33 + _34*matrix._43,
|
||||
_31*matrix._14 + _32*matrix._24 + _33*matrix._34 + _34*matrix._44,
|
||||
|
||||
_41*matrix._11 + _42*matrix._21 + _43*matrix._31 + _44*matrix._41,
|
||||
_41*matrix._12 + _42*matrix._22 + _43*matrix._32 + _44*matrix._42,
|
||||
_41*matrix._13 + _42*matrix._23 + _43*matrix._33 + _44*matrix._43,
|
||||
_41*matrix._14 + _42*matrix._24 + _43*matrix._34 + _44*matrix._44
|
||||
);
|
||||
}
|
||||
|
||||
//Matrix multiplication/assignment
|
||||
CMatrix3D& CMatrix3D::operator*=(const CMatrix3D& matrix)
|
||||
{
|
||||
Concatenate(matrix);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//Matrix scaling
|
||||
CMatrix3D CMatrix3D::operator*(float f) const
|
||||
{
|
||||
CMatrix3D tmp;
|
||||
for (int i=0;i<16;i++) {
|
||||
tmp._data[i]=_data[i]*f;
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
//Matrix scaling/assignment
|
||||
CMatrix3D& CMatrix3D::operator*=(float f)
|
||||
{
|
||||
for (int i=0;i<16;i++) {
|
||||
_data[i]*=f;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
//Matrix addition
|
||||
CMatrix3D CMatrix3D::operator+(const CMatrix3D& m) const
|
||||
{
|
||||
CMatrix3D tmp;
|
||||
for (int i=0;i<16;i++) {
|
||||
tmp._data[i]=_data[i]+m._data[i];
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
//Matrix addition/assignment
|
||||
CMatrix3D& CMatrix3D::operator+=(const CMatrix3D& m)
|
||||
{
|
||||
for (int i=0;i<16;i++) {
|
||||
_data[i]+=m._data[i];
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool CMatrix3D::operator==(const CMatrix3D &matrix) const
|
||||
{
|
||||
for (int i = 0; i < 16; ++i)
|
||||
if (matrix._data[i] != _data[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
//Sets the identity matrix
|
||||
void CMatrix3D::SetIdentity ()
|
||||
{
|
||||
@ -275,11 +172,6 @@ void CMatrix3D::Translate(const CVector3D &vector)
|
||||
_34 += vector.Z;
|
||||
}
|
||||
|
||||
void CMatrix3D::Concatenate(const CMatrix3D& m)
|
||||
{
|
||||
(*this)=m*(*this);
|
||||
}
|
||||
|
||||
CVector3D CMatrix3D::GetTranslation() const
|
||||
{
|
||||
return CVector3D(_14, _24, _34);
|
||||
@ -343,22 +235,6 @@ CVector3D CMatrix3D::GetIn() const
|
||||
return CVector3D(_13, _23, _33);
|
||||
}
|
||||
|
||||
//Transform a vector by this matrix
|
||||
CVector4D CMatrix3D::Transform(const CVector4D &vector) const
|
||||
{
|
||||
CVector4D result;
|
||||
Transform(vector,result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void CMatrix3D::Transform(const CVector4D& vector,CVector4D& result) const
|
||||
{
|
||||
result[0] = _11*vector[0] + _12*vector[1] + _13*vector[2] + _14*vector[3];
|
||||
result[1] = _21*vector[0] + _22*vector[1] + _23*vector[2] + _24*vector[3];
|
||||
result[2] = _31*vector[0] + _32*vector[1] + _33*vector[2] + _34*vector[3];
|
||||
result[3] = _41*vector[0] + _42*vector[1] + _43*vector[2] + _44*vector[3];
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RotateTransposed: rotate a vector by the transpose of this matrix
|
||||
CVector3D CMatrix3D::RotateTransposed(const CVector3D& vector) const
|
||||
|
@ -24,8 +24,8 @@
|
||||
#define INCLUDED_MATRIX3D
|
||||
|
||||
#include "maths/Vector3D.h"
|
||||
#include "maths/Vector4D.h"
|
||||
|
||||
class CVector4D;
|
||||
class CQuaternion;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
@ -49,10 +49,29 @@ public:
|
||||
|
||||
public:
|
||||
// constructors
|
||||
CMatrix3D();
|
||||
CMatrix3D(float a11,float a12,float a13,float a14,float a21,float a22,float a23,float a24,
|
||||
float a31,float a32,float a33,float a34,float a41,float a42,float a43,float a44);
|
||||
CMatrix3D(float data[]);
|
||||
CMatrix3D ()
|
||||
{
|
||||
}
|
||||
|
||||
CMatrix3D(
|
||||
float a11, float a12, float a13, float a14,
|
||||
float a21, float a22, float a23, float a24,
|
||||
float a31, float a32, float a33, float a34,
|
||||
float a41, float a42, float a43, float a44) :
|
||||
_11(a11), _12(a12), _13(a13), _14(a14),
|
||||
_21(a21), _22(a22), _23(a23), _24(a24),
|
||||
_31(a31), _32(a32), _33(a33), _34(a34),
|
||||
_41(a41), _42(a42), _43(a43), _44(a44)
|
||||
{
|
||||
}
|
||||
|
||||
CMatrix3D(float data[]) :
|
||||
_11(data[0]), _21(data[1]), _31(data[2]), _41(data[3]),
|
||||
_12(data[4]), _22(data[5]), _32(data[6]), _42(data[7]),
|
||||
_13(data[8]), _23(data[9]), _33(data[10]), _43(data[11]),
|
||||
_14(data[12]), _24(data[13]), _34(data[14]), _44(data[15])
|
||||
{
|
||||
}
|
||||
|
||||
// accessors to individual elements of matrix
|
||||
float& operator()(int col,int row) {
|
||||
@ -63,20 +82,78 @@ public:
|
||||
}
|
||||
|
||||
// matrix multiplication
|
||||
CMatrix3D operator*(const CMatrix3D &matrix) const;
|
||||
CMatrix3D operator*(const CMatrix3D &matrix) const
|
||||
{
|
||||
return CMatrix3D(
|
||||
_11*matrix._11 + _12*matrix._21 + _13*matrix._31 + _14*matrix._41,
|
||||
_11*matrix._12 + _12*matrix._22 + _13*matrix._32 + _14*matrix._42,
|
||||
_11*matrix._13 + _12*matrix._23 + _13*matrix._33 + _14*matrix._43,
|
||||
_11*matrix._14 + _12*matrix._24 + _13*matrix._34 + _14*matrix._44,
|
||||
|
||||
_21*matrix._11 + _22*matrix._21 + _23*matrix._31 + _24*matrix._41,
|
||||
_21*matrix._12 + _22*matrix._22 + _23*matrix._32 + _24*matrix._42,
|
||||
_21*matrix._13 + _22*matrix._23 + _23*matrix._33 + _24*matrix._43,
|
||||
_21*matrix._14 + _22*matrix._24 + _23*matrix._34 + _24*matrix._44,
|
||||
|
||||
_31*matrix._11 + _32*matrix._21 + _33*matrix._31 + _34*matrix._41,
|
||||
_31*matrix._12 + _32*matrix._22 + _33*matrix._32 + _34*matrix._42,
|
||||
_31*matrix._13 + _32*matrix._23 + _33*matrix._33 + _34*matrix._43,
|
||||
_31*matrix._14 + _32*matrix._24 + _33*matrix._34 + _34*matrix._44,
|
||||
|
||||
_41*matrix._11 + _42*matrix._21 + _43*matrix._31 + _44*matrix._41,
|
||||
_41*matrix._12 + _42*matrix._22 + _43*matrix._32 + _44*matrix._42,
|
||||
_41*matrix._13 + _42*matrix._23 + _43*matrix._33 + _44*matrix._43,
|
||||
_41*matrix._14 + _42*matrix._24 + _43*matrix._34 + _44*matrix._44
|
||||
);
|
||||
}
|
||||
|
||||
// matrix multiplication/assignment
|
||||
CMatrix3D& operator*=(const CMatrix3D &matrix);
|
||||
CMatrix3D& operator*=(const CMatrix3D &matrix)
|
||||
{
|
||||
Concatenate(matrix);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// matrix scaling
|
||||
CMatrix3D operator*(float f) const;
|
||||
// matrix scaling/assignment
|
||||
CMatrix3D& operator*=(float f);
|
||||
CMatrix3D operator*(float f) const
|
||||
{
|
||||
return CMatrix3D(
|
||||
_11*f, _12*f, _13*f, _14*f,
|
||||
_21*f, _22*f, _23*f, _24*f,
|
||||
_31*f, _32*f, _33*f, _34*f,
|
||||
_41*f, _42*f, _43*f, _44*f
|
||||
);
|
||||
}
|
||||
|
||||
// matrix addition
|
||||
CMatrix3D operator+(const CMatrix3D &matrix) const;
|
||||
CMatrix3D operator+(const CMatrix3D &m) const
|
||||
{
|
||||
return CMatrix3D(
|
||||
_11+m._11, _12+m._12, _13+m._13, _14+m._14,
|
||||
_21+m._21, _22+m._22, _23+m._23, _24+m._24,
|
||||
_31+m._31, _32+m._32, _33+m._33, _34+m._34,
|
||||
_41+m._41, _42+m._42, _43+m._43, _44+m._44
|
||||
);
|
||||
}
|
||||
|
||||
// matrix addition/assignment
|
||||
CMatrix3D& operator+=(const CMatrix3D &matrix);
|
||||
CMatrix3D& operator+=(const CMatrix3D &m)
|
||||
{
|
||||
_11 += m._11; _21 += m._21; _31 += m._31; _41 += m._41;
|
||||
_12 += m._12; _22 += m._22; _32 += m._32; _42 += m._42;
|
||||
_13 += m._13; _23 += m._23; _33 += m._33; _43 += m._43;
|
||||
_14 += m._14; _24 += m._24; _34 += m._34; _44 += m._44;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// equality
|
||||
bool operator==(const CMatrix3D &matrix) const;
|
||||
bool operator==(const CMatrix3D &m) const
|
||||
{
|
||||
return _11 == m._11 && _21 == m._21 && _31 == m._31 && _41 == m._41 &&
|
||||
_12 == m._12 && _22 == m._22 && _32 == m._32 && _42 == m._42 &&
|
||||
_13 == m._13 && _23 == m._23 && _33 == m._33 && _43 == m._43 &&
|
||||
_14 == m._14 && _24 == m._24 && _34 == m._34 && _44 == m._44;
|
||||
}
|
||||
|
||||
// set this matrix to the identity matrix
|
||||
void SetIdentity();
|
||||
@ -84,7 +161,28 @@ public:
|
||||
void SetZero();
|
||||
|
||||
// concatenate arbitrary matrix onto this matrix
|
||||
void Concatenate(const CMatrix3D& m);
|
||||
void Concatenate(const CMatrix3D& m)
|
||||
{
|
||||
(*this) = m * (*this);
|
||||
}
|
||||
|
||||
// blend matrix using only 4x3 subset
|
||||
void Blend(const CMatrix3D& m, float f)
|
||||
{
|
||||
_11 = m._11*f; _21 = m._21*f; _31 = m._31*f;
|
||||
_12 = m._12*f; _22 = m._22*f; _32 = m._32*f;
|
||||
_13 = m._13*f; _23 = m._23*f; _33 = m._33*f;
|
||||
_14 = m._14*f; _24 = m._24*f; _34 = m._34*f;
|
||||
}
|
||||
|
||||
// blend matrix using only 4x3 and add onto existing blend
|
||||
void AddBlend(const CMatrix3D& m, float f)
|
||||
{
|
||||
_11 += m._11*f; _21 += m._21*f; _31 += m._31*f;
|
||||
_12 += m._12*f; _22 += m._22*f; _32 += m._32*f;
|
||||
_13 += m._13*f; _23 += m._23*f; _33 += m._33*f;
|
||||
_14 += m._14*f; _24 += m._24*f; _34 += m._34*f;
|
||||
}
|
||||
|
||||
// set this matrix to a rotation matrix for a rotation about X axis of given angle
|
||||
void SetXRotation(float angle);
|
||||
@ -144,7 +242,7 @@ public:
|
||||
float GetYRotation() const;
|
||||
|
||||
// transform a 3D vector by this matrix
|
||||
CVector3D Transform (const CVector3D &vector) const
|
||||
CVector3D Transform(const CVector3D &vector) const
|
||||
{
|
||||
CVector3D result;
|
||||
Transform(vector, result);
|
||||
@ -158,6 +256,22 @@ public:
|
||||
result.Z = _31*vector.X + _32*vector.Y + _33*vector.Z + _34;
|
||||
}
|
||||
|
||||
// transform a 4D vector by this matrix
|
||||
CVector4D Transform(const CVector4D &vector) const
|
||||
{
|
||||
CVector4D result;
|
||||
Transform(vector, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void Transform(const CVector4D& vector, CVector4D& result) const
|
||||
{
|
||||
result[0] = _11*vector[0] + _12*vector[1] + _13*vector[2] + _14*vector[3];
|
||||
result[1] = _21*vector[0] + _22*vector[1] + _23*vector[2] + _24*vector[3];
|
||||
result[2] = _31*vector[0] + _32*vector[1] + _33*vector[2] + _34*vector[3];
|
||||
result[3] = _41*vector[0] + _42*vector[1] + _43*vector[2] + _44*vector[3];
|
||||
}
|
||||
|
||||
// rotate a vector by this matrix
|
||||
CVector3D Rotate(const CVector3D& vector) const
|
||||
{
|
||||
@ -173,10 +287,6 @@ public:
|
||||
result.Z = _31*vector.X + _32*vector.Y + _33*vector.Z;
|
||||
}
|
||||
|
||||
// transform a 4D vector by this matrix
|
||||
void Transform(const CVector4D& vector,CVector4D& result) const;
|
||||
CVector4D Transform(const CVector4D& vector) const;
|
||||
|
||||
// rotate a vector by the transpose of this matrix
|
||||
void RotateTransposed(const CVector3D& vector,CVector3D& result) const;
|
||||
CVector3D RotateTransposed(const CVector3D& vector) const;
|
||||
|
@ -26,6 +26,7 @@
|
||||
#define INCLUDED_PLANE
|
||||
|
||||
#include "Vector3D.h"
|
||||
#include "Vector4D.h"
|
||||
|
||||
enum PLANESIDE
|
||||
{
|
||||
@ -38,6 +39,7 @@ class CPlane
|
||||
{
|
||||
public:
|
||||
CPlane ();
|
||||
CPlane (const CVector4D& coeffs) : m_Norm(coeffs[0], coeffs[1], coeffs[2]), m_Dist(coeffs[3]) { }
|
||||
|
||||
//sets the plane equation from 3 points on that plane
|
||||
void Set (const CVector3D &p1, const CVector3D &p2, const CVector3D &p3);
|
||||
|
@ -34,6 +34,7 @@ bool g_NoGLAutoMipmap = false;
|
||||
bool g_NoGLVBO = false;
|
||||
|
||||
bool g_Shadows = false;
|
||||
bool g_ShadowPCF = false;
|
||||
bool g_FancyWater = false;
|
||||
|
||||
float g_LodBias = 0.0f;
|
||||
@ -72,6 +73,7 @@ static void LoadGlobals()
|
||||
CFG_GET_USER_VAL("noautomipmap", Bool, g_NoGLAutoMipmap);
|
||||
CFG_GET_USER_VAL("novbo", Bool, g_NoGLVBO);
|
||||
CFG_GET_USER_VAL("shadows", Bool, g_Shadows);
|
||||
CFG_GET_USER_VAL("shadowpcf", Bool, g_ShadowPCF);
|
||||
CFG_GET_USER_VAL("fancywater", Bool, g_FancyWater);
|
||||
CFG_GET_USER_VAL("renderpath", String, g_RenderPath);
|
||||
|
||||
|
@ -45,6 +45,8 @@ extern bool g_NoGLVBO;
|
||||
extern bool g_Shadows;
|
||||
// flag to switch on reflective/refractive water
|
||||
extern bool g_FancyWater;
|
||||
// flag to switch on shadow PCF
|
||||
extern bool g_ShadowPCF;
|
||||
|
||||
extern float g_LodBias;
|
||||
extern float g_Gamma;
|
||||
|
@ -549,6 +549,7 @@ static void InitRenderer()
|
||||
g_Renderer.SetOptionBool(CRenderer::OPT_FANCYWATER,g_FancyWater);
|
||||
g_Renderer.SetRenderPath(CRenderer::GetRenderPathByName(g_RenderPath));
|
||||
g_Renderer.SetOptionFloat(CRenderer::OPT_LODBIAS, g_LodBias);
|
||||
g_Renderer.SetOptionBool(CRenderer::OPT_SHADOWPCF, g_ShadowPCF);
|
||||
|
||||
// create terrain related stuff
|
||||
new CTerrainTextureManager;
|
||||
|
@ -115,6 +115,12 @@ void SetDisableShadows(void* UNUSED(cbdata), bool disabled)
|
||||
g_Shadows = !disabled;
|
||||
}
|
||||
|
||||
void SetDisableShadowPCF(void* UNUSED(cbdata), bool disabled)
|
||||
{
|
||||
if (!IsOverridden("shadowpcf"))
|
||||
g_ShadowPCF = !disabled;
|
||||
}
|
||||
|
||||
void SetDisableFancyWater(void* UNUSED(cbdata), bool disabled)
|
||||
{
|
||||
if (!IsOverridden("fancywater"))
|
||||
@ -136,6 +142,7 @@ void RunHardwareDetection()
|
||||
scriptInterface.RegisterFunction<void, bool, &SetDisableAudio>("SetDisableAudio");
|
||||
scriptInterface.RegisterFunction<void, bool, &SetDisableS3TC>("SetDisableS3TC");
|
||||
scriptInterface.RegisterFunction<void, bool, &SetDisableShadows>("SetDisableShadows");
|
||||
scriptInterface.RegisterFunction<void, bool, &SetDisableShadowPCF>("SetDisableShadowPCF");
|
||||
scriptInterface.RegisterFunction<void, bool, &SetDisableFancyWater>("SetDisableFancyWater");
|
||||
scriptInterface.RegisterFunction<void, std::string, &SetRenderPath>("SetRenderPath");
|
||||
|
||||
|
@ -34,6 +34,8 @@ public:
|
||||
|
||||
void Render(const CShaderProgramPtr& shader);
|
||||
|
||||
CModelDecal* GetDecal() { return m_Decal; }
|
||||
|
||||
private:
|
||||
void BuildArrays();
|
||||
|
||||
|
@ -84,7 +84,7 @@ void ModelRenderer::BuildPositionAndNormals(
|
||||
return;
|
||||
}
|
||||
|
||||
CModelDef::SkinPointsAndNormals(numVertices, Position, Normal, vertices, model->GetAnimatedBoneMatrices(), model->GetInverseBindBoneMatrices());
|
||||
CModelDef::SkinPointsAndNormals(numVertices, Position, Normal, vertices, mdef->GetBlendIndices(), model->GetAnimatedBoneMatrices());
|
||||
|
||||
}
|
||||
else
|
||||
@ -253,6 +253,7 @@ struct BatchModelRendererInternals
|
||||
}
|
||||
|
||||
void RenderAllModels(const RenderModifierPtr& modifier, int filterflags, int pass, int streamflags);
|
||||
void FilterAllModels(CModelFilter& filter, int passed, int filterflags);
|
||||
};
|
||||
|
||||
BMRModelData::~BMRModelData()
|
||||
@ -442,7 +443,7 @@ void BatchModelRendererInternals::RenderAllModels(
|
||||
|
||||
ENSURE(bmrdata->GetKey() == this);
|
||||
|
||||
if (filterflags && !(model->GetFlags()&filterflags))
|
||||
if (filterflags && !(model->GetFlags() & filterflags))
|
||||
continue;
|
||||
|
||||
modifier->PrepareModel(pass, model);
|
||||
@ -452,4 +453,33 @@ void BatchModelRendererInternals::RenderAllModels(
|
||||
}
|
||||
}
|
||||
|
||||
void BatchModelRenderer::Filter(CModelFilter& filter, int passed, int flags)
|
||||
{
|
||||
if (!HaveSubmissions())
|
||||
return;
|
||||
|
||||
m->FilterAllModels(filter, passed, flags);
|
||||
}
|
||||
|
||||
// Recompute filter flags
|
||||
void BatchModelRendererInternals::FilterAllModels(CModelFilter& filter, int passed, int filterflags)
|
||||
{
|
||||
for(BMRModelDefTracker* mdeftracker = submissions; mdeftracker; mdeftracker = mdeftracker->m_Next)
|
||||
{
|
||||
for(size_t idx = 0; idx < mdeftracker->m_Slots; ++idx)
|
||||
{
|
||||
BMRModelData* bmrdata = mdeftracker->m_ModelSlots[idx];
|
||||
for(; bmrdata; bmrdata = bmrdata->m_Next)
|
||||
{
|
||||
CModel* model = bmrdata->GetModel();
|
||||
if (filterflags && !(model->GetFlags() & filterflags))
|
||||
continue;
|
||||
|
||||
if (filter.Filter(model))
|
||||
model->SetFlags(model->GetFlags() | passed);
|
||||
else
|
||||
model->SetFlags(model->GetFlags() & ~passed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -42,6 +42,12 @@ typedef shared_ptr<ModelVertexRenderer> ModelVertexRendererPtr;
|
||||
|
||||
class CModel;
|
||||
|
||||
class CModelFilter
|
||||
{
|
||||
public:
|
||||
virtual ~CModelFilter() {}
|
||||
virtual bool Filter(CModel* model) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Class CModelRData: Render data that is maintained per CModel.
|
||||
@ -168,6 +174,17 @@ public:
|
||||
*/
|
||||
virtual void Render(const RenderModifierPtr& modifier, int flags) = 0;
|
||||
|
||||
/**
|
||||
* Filter: Filter submitted models, setting the passed flags on any models
|
||||
* that pass the filter, and clearing them from models that fail.
|
||||
*
|
||||
* @param filter Filter to select a subset of models.
|
||||
* @param passed Flags to be set/cleared.
|
||||
* @param flags If non-zero, only models that contain @p flags
|
||||
* have the filter test applied.
|
||||
*/
|
||||
virtual void Filter(CModelFilter& filter, int passed, int flags = 0) = 0;
|
||||
|
||||
/**
|
||||
* CopyPositionAndNormals: Copy unanimated object-space vertices and
|
||||
* normals into the given vertex array.
|
||||
@ -268,6 +285,7 @@ public:
|
||||
virtual void EndFrame();
|
||||
virtual bool HaveSubmissions();
|
||||
virtual void Render(const RenderModifierPtr& modifier, int flags);
|
||||
virtual void Filter(CModelFilter& filter, int passed, int flags);
|
||||
|
||||
private:
|
||||
BatchModelRendererInternals* m;
|
||||
|
@ -57,7 +57,10 @@ const ssize_t BlendOffsets[9][2] = {
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// CPatchRData constructor
|
||||
CPatchRData::CPatchRData(CPatch* patch) :
|
||||
m_Patch(patch), m_VBSides(0), m_VBBase(0), m_VBBaseIndices(0), m_VBBlends(0), m_VBBlendIndices(0)
|
||||
m_Patch(patch), m_VBSides(0),
|
||||
m_VBBase(0), m_VBBaseIndices(0),
|
||||
m_VBBlends(0), m_VBBlendIndices(0),
|
||||
m_VBWater(0), m_VBWaterIndices(0)
|
||||
{
|
||||
ENSURE(patch);
|
||||
Build();
|
||||
@ -73,6 +76,8 @@ CPatchRData::~CPatchRData()
|
||||
if (m_VBBaseIndices) g_VBMan.Release(m_VBBaseIndices);
|
||||
if (m_VBBlends) g_VBMan.Release(m_VBBlends);
|
||||
if (m_VBBlendIndices) g_VBMan.Release(m_VBBlendIndices);
|
||||
if (m_VBWater) g_VBMan.Release(m_VBWater);
|
||||
if (m_VBWaterIndices) g_VBMan.Release(m_VBWaterIndices);
|
||||
}
|
||||
|
||||
const float uvFactor = 0.125f / sqrt(2.f);
|
||||
@ -645,6 +650,7 @@ void CPatchRData::Build()
|
||||
BuildSides();
|
||||
BuildIndices();
|
||||
BuildBlends();
|
||||
BuildWater();
|
||||
}
|
||||
|
||||
void CPatchRData::Update()
|
||||
@ -657,6 +663,7 @@ void CPatchRData::Update()
|
||||
BuildSides();
|
||||
BuildIndices();
|
||||
BuildBlends();
|
||||
BuildWater();
|
||||
|
||||
m_UpdateFlags=0;
|
||||
}
|
||||
@ -1127,3 +1134,166 @@ void CPatchRData::RenderPriorities()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Water build and rendering
|
||||
//
|
||||
|
||||
// Build vertex buffer for water vertices over our patch
|
||||
void CPatchRData::BuildWater()
|
||||
{
|
||||
// number of vertices in each direction in each patch
|
||||
ENSURE((PATCH_SIZE % water_cell_size) == 0);
|
||||
|
||||
if (m_VBWater)
|
||||
{
|
||||
g_VBMan.Release(m_VBWater);
|
||||
m_VBWater = 0;
|
||||
}
|
||||
if (m_VBWaterIndices)
|
||||
{
|
||||
g_VBMan.Release(m_VBWaterIndices);
|
||||
m_VBWaterIndices = 0;
|
||||
}
|
||||
m_WaterBounds.SetEmpty();
|
||||
|
||||
// We need to use this to access the water manager or we may not have the
|
||||
// actual values but some compiled-in defaults
|
||||
CmpPtr<ICmpWaterManager> cmpWaterManager(*g_Game->GetSimulation2(), SYSTEM_ENTITY);
|
||||
if (cmpWaterManager.null())
|
||||
return;
|
||||
|
||||
// Build data for water
|
||||
std::vector<SWaterVertex> water_vertex_data;
|
||||
std::vector<GLushort> water_indices;
|
||||
u16 water_index_map[PATCH_SIZE+1][PATCH_SIZE+1];
|
||||
memset(water_index_map, 0xFF, sizeof(water_index_map));
|
||||
|
||||
// TODO: This is not (yet) exported via the ICmp interface so... we stick to these values which can be compiled in defaults
|
||||
WaterManager* WaterMgr = g_Renderer.GetWaterManager();
|
||||
|
||||
CPatch* patch = m_Patch;
|
||||
CTerrain* terrain = patch->m_Parent;
|
||||
|
||||
ssize_t x1 = m_Patch->m_X*PATCH_SIZE;
|
||||
ssize_t z1 = m_Patch->m_Z*PATCH_SIZE;
|
||||
|
||||
// build vertices, uv, and shader varying
|
||||
for (ssize_t z = 0; z < PATCH_SIZE; z += water_cell_size)
|
||||
{
|
||||
for (ssize_t x = 0; x <= PATCH_SIZE; x += water_cell_size)
|
||||
{
|
||||
// Check that the edge at x is partially underwater
|
||||
float startTerrainHeight[2] = { terrain->GetVertexGroundLevel(x+x1, z+z1), terrain->GetVertexGroundLevel(x+x1, z+z1 + water_cell_size) };
|
||||
float startWaterHeight[2] = { cmpWaterManager->GetExactWaterLevel(x+x1, z+z1), cmpWaterManager->GetExactWaterLevel(x+x1, z+z1 + water_cell_size) };
|
||||
if (startTerrainHeight[0] >= startWaterHeight[0] && startTerrainHeight[1] >= startWaterHeight[1])
|
||||
continue;
|
||||
|
||||
// Move x back one cell (unless at start of patch), then scan rightwards
|
||||
bool belowWater = true;
|
||||
ssize_t stripStart;
|
||||
for (stripStart = x = std::max(x-water_cell_size, (ssize_t)0); x <= PATCH_SIZE; x += water_cell_size)
|
||||
{
|
||||
// If this edge is not underwater, and neither is the previous edge
|
||||
// (i.e. belowWater == false), then stop this strip since we've reached
|
||||
// a cell that's entirely above water
|
||||
float terrainHeight[2] = { terrain->GetVertexGroundLevel(x+x1, z+z1), terrain->GetVertexGroundLevel(x+x1, z+z1 + water_cell_size) };
|
||||
float waterHeight[2] = { cmpWaterManager->GetExactWaterLevel(x+x1, z+z1), cmpWaterManager->GetExactWaterLevel(x+x1, z+z1 + water_cell_size) };
|
||||
if (terrainHeight[0] >= waterHeight[0] && terrainHeight[1] >= waterHeight[1])
|
||||
{
|
||||
if (!belowWater)
|
||||
break;
|
||||
belowWater = false;
|
||||
}
|
||||
else
|
||||
belowWater = true;
|
||||
|
||||
// Edge (x,z)-(x,z+1) is at least partially underwater, so extend the water plane strip across it
|
||||
|
||||
// Compute vertex data for the 2 points on the edge
|
||||
for (int j = 0; j < 2; j++)
|
||||
{
|
||||
// Check if we already computed this vertex from an earlier strip
|
||||
if (water_index_map[z+j*water_cell_size][x] != 0xFFFF)
|
||||
continue;
|
||||
|
||||
SWaterVertex vertex;
|
||||
|
||||
terrain->CalcPosition(x+x1, z+z1 + j*water_cell_size, vertex.m_Position);
|
||||
float depth = waterHeight[j] - vertex.m_Position.Y;
|
||||
vertex.m_Position.Y = waterHeight[j];
|
||||
m_WaterBounds += vertex.m_Position;
|
||||
|
||||
// NB: Usually this factor is view dependent, but for performance reasons
|
||||
// we do not take it into account with basic non-shader based water.
|
||||
// Average constant Fresnel effect for non-fancy water
|
||||
float alpha = clamp(depth / WaterMgr->m_WaterFullDepth + WaterMgr->m_WaterAlphaOffset, WaterMgr->m_WaterAlphaOffset, WaterMgr->m_WaterMaxAlpha);
|
||||
|
||||
// Split the depth data across 24 bits, so the fancy-water shader can reconstruct
|
||||
// the depth value while the simple-water can just use the precomputed alpha
|
||||
float depthInt = floor(depth);
|
||||
float depthFrac = depth - depthInt;
|
||||
vertex.m_DepthData = SColor4ub(
|
||||
u8(clamp(depthInt, 0.0f, 255.0f)),
|
||||
u8(clamp(-depthInt, 0.0f, 255.0f)),
|
||||
u8(clamp(depthFrac*255.0f, 0.0f, 255.0f)),
|
||||
u8(clamp(alpha*255.0f, 0.0f, 255.0f)));
|
||||
|
||||
water_index_map[z+j*water_cell_size][x] = water_vertex_data.size();
|
||||
water_vertex_data.push_back(vertex);
|
||||
}
|
||||
|
||||
// If this was not the first x in the strip, then add a quad
|
||||
// using the computed vertex data
|
||||
|
||||
if (x <= stripStart)
|
||||
continue;
|
||||
|
||||
water_indices.push_back(water_index_map[z + water_cell_size][x - water_cell_size]);
|
||||
water_indices.push_back(water_index_map[z][x - water_cell_size]);
|
||||
water_indices.push_back(water_index_map[z][x]);
|
||||
water_indices.push_back(water_index_map[z + water_cell_size][x]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no vertex buffers if no data generated
|
||||
if (water_indices.size() == 0)
|
||||
return;
|
||||
|
||||
// allocate vertex buffer
|
||||
m_VBWater = g_VBMan.Allocate(sizeof(SWaterVertex), water_vertex_data.size(), GL_STATIC_DRAW, GL_ARRAY_BUFFER);
|
||||
m_VBWater->m_Owner->UpdateChunkVertices(m_VBWater, &water_vertex_data[0]);
|
||||
|
||||
// Construct indices buffer
|
||||
m_VBWaterIndices = g_VBMan.Allocate(sizeof(GLushort), water_indices.size(), GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER);
|
||||
m_VBWaterIndices->m_Owner->UpdateChunkVertices(m_VBWaterIndices, &water_indices[0]);
|
||||
}
|
||||
|
||||
void CPatchRData::RenderWater()
|
||||
{
|
||||
ASSERT(m_UpdateFlags==0);
|
||||
|
||||
if (!m_VBWater)
|
||||
return;
|
||||
|
||||
SWaterVertex *base=(SWaterVertex *)m_VBWater->m_Owner->Bind();
|
||||
|
||||
// setup data pointers
|
||||
GLsizei stride = sizeof(SWaterVertex);
|
||||
glColorPointer(4, GL_UNSIGNED_BYTE, stride, &base[m_VBWater->m_Index].m_DepthData);
|
||||
glVertexPointer(3, GL_FLOAT, stride, &base[m_VBWater->m_Index].m_Position);
|
||||
|
||||
// render
|
||||
if (!g_Renderer.m_SkipSubmit) {
|
||||
u8* indexBase = m_VBWaterIndices->m_Owner->Bind();
|
||||
glDrawElements(GL_QUADS, (GLsizei) m_VBWaterIndices->m_Count,
|
||||
GL_UNSIGNED_SHORT, indexBase + sizeof(u16)*(m_VBWaterIndices->m_Index));
|
||||
}
|
||||
|
||||
// bump stats
|
||||
g_Renderer.m_Stats.m_DrawCalls++;
|
||||
g_Renderer.m_Stats.m_WaterTris += m_VBWaterIndices->m_Count / 2;
|
||||
|
||||
CVertexBuffer::Unbind();
|
||||
}
|
||||
|
@ -41,12 +41,16 @@ public:
|
||||
void RenderSides();
|
||||
void RenderPriorities();
|
||||
|
||||
void RenderWater();
|
||||
|
||||
static void RenderBases(const std::vector<CPatchRData*>& patches);
|
||||
static void RenderBlends(const std::vector<CPatchRData*>& patches);
|
||||
static void RenderStreams(const std::vector<CPatchRData*>& patches, int streamflags);
|
||||
|
||||
CPatch* GetPatch() { return m_Patch; }
|
||||
|
||||
const CBound& GetWaterBounds() const { return m_WaterBounds; }
|
||||
|
||||
private:
|
||||
friend struct SBlendStackItem;
|
||||
|
||||
@ -93,6 +97,17 @@ private:
|
||||
};
|
||||
cassert(sizeof(SBlendVertex) == 32);
|
||||
|
||||
// Mixed Fancy/Simple water vertex description data structure
|
||||
struct SWaterVertex {
|
||||
// vertex position
|
||||
CVector3D m_Position;
|
||||
// (p,q,r, a) where
|
||||
// p*255 + q*-255 + r = depth of water
|
||||
// a = depth-dependent alpha
|
||||
SColor4ub m_DepthData;
|
||||
};
|
||||
cassert(sizeof(SWaterVertex) == 16);
|
||||
|
||||
// build this renderdata object
|
||||
void Build();
|
||||
|
||||
@ -128,6 +143,24 @@ private:
|
||||
|
||||
// splats used in blend pass
|
||||
std::vector<SSplat> m_BlendSplats;
|
||||
|
||||
// boundary of water in this patch
|
||||
CBound m_WaterBounds;
|
||||
|
||||
// Water vertex buffer
|
||||
CVertexBuffer::VBChunk* m_VBWater;
|
||||
|
||||
// Water indices buffer
|
||||
CVertexBuffer::VBChunk* m_VBWaterIndices;
|
||||
|
||||
// Build water vertices and indices (vertex buffer and data vector)
|
||||
void BuildWater();
|
||||
|
||||
// parameter allowing a varying number of triangles per patch for LOD
|
||||
// MUST be an exact divisor of PATCH_SIZE
|
||||
// compiled const for the moment until/if dynamic water LOD is offered
|
||||
// savings would be mostly beneficial for GPU or simple water
|
||||
static const ssize_t water_cell_size = 1;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -236,6 +236,10 @@ int ShaderRenderModifier::BeginPass(int pass)
|
||||
{
|
||||
shader->BindTexture("shadowTex", GetShadowMap()->GetTexture());
|
||||
shader->Uniform("shadowTransform", GetShadowMap()->GetTextureMatrix());
|
||||
|
||||
const float* offsets = GetShadowMap()->GetFilterOffsets();
|
||||
shader->Uniform("shadowOffsets1", offsets[0], offsets[1], offsets[2], offsets[3]);
|
||||
shader->Uniform("shadowOffsets2", offsets[4], offsets[5], offsets[6], offsets[7]);
|
||||
}
|
||||
|
||||
if (GetLightEnv())
|
||||
|
@ -104,6 +104,7 @@ private:
|
||||
enum {
|
||||
Row_DrawCalls = 0,
|
||||
Row_TerrainTris,
|
||||
Row_WaterTris,
|
||||
Row_ModelTris,
|
||||
Row_BlendSplats,
|
||||
Row_Particles,
|
||||
@ -162,6 +163,12 @@ CStr CRendererStatsTable::GetCellText(size_t row, size_t col)
|
||||
sprintf_s(buf, sizeof(buf), "%lu", (unsigned long)Stats.m_TerrainTris);
|
||||
return buf;
|
||||
|
||||
case Row_WaterTris:
|
||||
if (col == 0)
|
||||
return "# water tris";
|
||||
sprintf_s(buf, sizeof(buf), "%lu", (unsigned long)Stats.m_WaterTris);
|
||||
return buf;
|
||||
|
||||
case Row_ModelTris:
|
||||
if (col == 0)
|
||||
return "# model tris";
|
||||
@ -295,11 +302,15 @@ public:
|
||||
RenderModifierPtr ModSolidPlayer;
|
||||
RenderModifierPtr ModSolidPlayerInstancing;
|
||||
RenderModifierPtr ModTransparent;
|
||||
RenderModifierPtr ModTransparentOpaque;
|
||||
RenderModifierPtr ModTransparentBlend;
|
||||
|
||||
// Palette of available RenderModifiers
|
||||
RenderModifierPtr ModPlainUnlit;
|
||||
RenderModifierPtr ModPlayerUnlit;
|
||||
RenderModifierPtr ModTransparentUnlit;
|
||||
RenderModifierPtr ModTransparentOpaqueUnlit;
|
||||
RenderModifierPtr ModTransparentBlendUnlit;
|
||||
|
||||
RenderModifierPtr ModShaderSolidColor;
|
||||
RenderModifierPtr ModShaderSolidColorInstancing;
|
||||
@ -311,6 +322,8 @@ public:
|
||||
LitRenderModifierPtr ModShaderPlayer;
|
||||
LitRenderModifierPtr ModShaderPlayerInstancing;
|
||||
LitRenderModifierPtr ModShaderTransparent;
|
||||
LitRenderModifierPtr ModShaderTransparentOpaque;
|
||||
LitRenderModifierPtr ModShaderTransparentBlend;
|
||||
RenderModifierPtr ModShaderTransparentShadow;
|
||||
} Model;
|
||||
|
||||
@ -381,6 +394,20 @@ public:
|
||||
if (Model.Player != Model.PlayerInstancing)
|
||||
Model.PlayerInstancing->Render(modPlayerInstancing, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters all non-transparent models with the given modifiers.
|
||||
*/
|
||||
void FilterModels(CModelFilter& filter, int passed, int flags = 0)
|
||||
{
|
||||
Model.Normal->Filter(filter, passed, flags);
|
||||
if (Model.Normal != Model.NormalInstancing)
|
||||
Model.NormalInstancing->Filter(filter, passed, flags);
|
||||
|
||||
Model.Player->Filter(filter, passed, flags);
|
||||
if (Model.Player != Model.PlayerInstancing)
|
||||
Model.PlayerInstancing->Filter(filter, passed, flags);
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
@ -412,6 +439,7 @@ CRenderer::CRenderer()
|
||||
m_Options.m_Shadows = false;
|
||||
m_Options.m_ShadowAlphaFix = true;
|
||||
m_Options.m_ARBProgramShadow = true;
|
||||
m_Options.m_ShadowPCF = false;
|
||||
|
||||
m_ShadowZBias = 0.02f;
|
||||
m_ShadowMapSize = 0;
|
||||
@ -514,6 +542,8 @@ void CRenderer::ReloadShaders()
|
||||
defBasic["USE_SHADOW"] = "1";
|
||||
if (m_Caps.m_ARBProgramShadow && m_Options.m_ARBProgramShadow)
|
||||
defBasic["USE_FP_SHADOW"] = "1";
|
||||
if (m_Options.m_ShadowPCF)
|
||||
defBasic["USE_SHADOW_PCF"] = "1";
|
||||
}
|
||||
|
||||
if (m_LightEnv)
|
||||
@ -526,15 +556,20 @@ void CRenderer::ReloadShaders()
|
||||
defTransparent["USE_TRANSPARENT"] = "1";
|
||||
|
||||
// TODO: it'd be nicer to load this technique from an XML file or something
|
||||
CShaderPass passTransparent0(m->shaderManager.LoadProgram("solid_tex", defNull));
|
||||
passTransparent0.AlphaFunc(GL_GREATER, 0.975f);
|
||||
passTransparent0.ColorMask(0, 0, 0, 0);
|
||||
CShaderPass passTransparent1(m->shaderManager.LoadProgram("model_common", defTransparent));
|
||||
passTransparent1.AlphaFunc(GL_GREATER, 0.0f);
|
||||
passTransparent1.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
passTransparent1.DepthMask(0);
|
||||
CShaderTechnique techTransparent(passTransparent0);
|
||||
techTransparent.AddPass(passTransparent1);
|
||||
CShaderPass passTransparentOpaque(m->shaderManager.LoadProgram("model_common", defTransparent));
|
||||
passTransparentOpaque.AlphaFunc(GL_GREATER, 0.9375f);
|
||||
passTransparentOpaque.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
CShaderTechnique techTransparentOpaque(passTransparentOpaque);
|
||||
|
||||
CShaderPass passTransparentBlend(m->shaderManager.LoadProgram("model_common", defTransparent));
|
||||
passTransparentBlend.AlphaFunc(GL_GREATER, 0.0f);
|
||||
passTransparentBlend.DepthFunc(GL_LESS);
|
||||
passTransparentBlend.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
passTransparentBlend.DepthMask(0);
|
||||
CShaderTechnique techTransparentBlend(passTransparentBlend);
|
||||
|
||||
CShaderTechnique techTransparent(passTransparentOpaque);
|
||||
techTransparent.AddPass(passTransparentBlend);
|
||||
|
||||
CShaderPass passTransparentShadow(m->shaderManager.LoadProgram("solid_tex", defBasic));
|
||||
passTransparentShadow.AlphaFunc(GL_GREATER, 0.4f);
|
||||
@ -565,6 +600,10 @@ void CRenderer::ReloadShaders()
|
||||
|
||||
m->Model.ModShaderTransparent = LitRenderModifierPtr(new ShaderRenderModifier(
|
||||
techTransparent));
|
||||
m->Model.ModShaderTransparentOpaque = LitRenderModifierPtr(new ShaderRenderModifier(
|
||||
techTransparentOpaque));
|
||||
m->Model.ModShaderTransparentBlend = LitRenderModifierPtr(new ShaderRenderModifier(
|
||||
techTransparentBlend));
|
||||
m->Model.ModShaderTransparentShadow = LitRenderModifierPtr(new ShaderRenderModifier(
|
||||
techTransparentShadow));
|
||||
|
||||
@ -603,6 +642,8 @@ bool CRenderer::Open(int width, int height)
|
||||
m->Model.ModSolidColor = RenderModifierPtr(new SolidColorRenderModifier);
|
||||
m->Model.ModSolidPlayerColor = RenderModifierPtr(new SolidPlayerColorRender);
|
||||
m->Model.ModTransparentUnlit = RenderModifierPtr(new TransparentRenderModifier);
|
||||
m->Model.ModTransparentOpaqueUnlit = RenderModifierPtr(new TransparentOpaqueRenderModifier);
|
||||
m->Model.ModTransparentBlendUnlit = RenderModifierPtr(new TransparentBlendRenderModifier);
|
||||
m->Model.ModTransparentDepthShadow = RenderModifierPtr(new TransparentDepthShadowModifier);
|
||||
|
||||
// Dimensions
|
||||
@ -659,6 +700,9 @@ void CRenderer::SetOptionBool(enum Option opt,bool value)
|
||||
case OPT_FANCYWATER:
|
||||
m_Options.m_FancyWater=value;
|
||||
break;
|
||||
case OPT_SHADOWPCF:
|
||||
m_Options.m_ShadowPCF=value;
|
||||
break;
|
||||
default:
|
||||
debug_warn(L"CRenderer::SetOptionBool: unknown option");
|
||||
break;
|
||||
@ -676,6 +720,8 @@ bool CRenderer::GetOptionBool(enum Option opt) const
|
||||
return m_Options.m_Shadows;
|
||||
case OPT_FANCYWATER:
|
||||
return m_Options.m_FancyWater;
|
||||
case OPT_SHADOWPCF:
|
||||
return m_Options.m_ShadowPCF;
|
||||
default:
|
||||
debug_warn(L"CRenderer::GetOptionBool: unknown option");
|
||||
break;
|
||||
@ -812,6 +858,12 @@ void CRenderer::BeginFrame()
|
||||
m->Model.ModShaderTransparent->SetShadowMap(m->shadow);
|
||||
m->Model.ModShaderTransparent->SetLightEnv(m_LightEnv);
|
||||
|
||||
m->Model.ModShaderTransparentOpaque->SetShadowMap(m->shadow);
|
||||
m->Model.ModShaderTransparentOpaque->SetLightEnv(m_LightEnv);
|
||||
|
||||
m->Model.ModShaderTransparentBlend->SetShadowMap(m->shadow);
|
||||
m->Model.ModShaderTransparentBlend->SetLightEnv(m_LightEnv);
|
||||
|
||||
m->Model.ModNormal = m->Model.ModShaderNormal;
|
||||
m->Model.ModNormalInstancing = m->Model.ModShaderNormalInstancing;
|
||||
m->Model.ModPlayer = m->Model.ModShaderPlayer;
|
||||
@ -821,6 +873,8 @@ void CRenderer::BeginFrame()
|
||||
m->Model.ModSolidPlayer = m->Model.ModShaderSolidPlayerColor;
|
||||
m->Model.ModSolidPlayerInstancing = m->Model.ModShaderSolidPlayerColorInstancing;
|
||||
m->Model.ModTransparent = m->Model.ModShaderTransparent;
|
||||
m->Model.ModTransparentOpaque = m->Model.ModShaderTransparentOpaque;
|
||||
m->Model.ModTransparentBlend = m->Model.ModShaderTransparentBlend;
|
||||
|
||||
m->Model.Normal = m->Model.pal_NormalShader;
|
||||
m->Model.NormalInstancing = m->Model.pal_NormalInstancingShader;
|
||||
@ -837,6 +891,8 @@ void CRenderer::BeginFrame()
|
||||
m->Model.ModPlayer = m->Model.ModPlayerUnlit;
|
||||
m->Model.ModPlayerInstancing = m->Model.ModPlayerUnlit;
|
||||
m->Model.ModTransparent = m->Model.ModTransparentUnlit;
|
||||
m->Model.ModTransparentOpaque = m->Model.ModTransparentOpaqueUnlit;
|
||||
m->Model.ModTransparentBlend = m->Model.ModTransparentBlendUnlit;
|
||||
|
||||
m->Model.NormalInstancing = m->Model.pal_NormalFF;
|
||||
m->Model.Normal = m->Model.pal_NormalFF;
|
||||
@ -919,10 +975,19 @@ void CRenderer::RenderShadowMap()
|
||||
m->shadow->EndRender();
|
||||
}
|
||||
|
||||
void CRenderer::RenderPatches()
|
||||
void CRenderer::RenderPatches(const CFrustum* frustum)
|
||||
{
|
||||
PROFILE("render patches");
|
||||
|
||||
bool filtered = false;
|
||||
if (frustum)
|
||||
{
|
||||
if (!m->terrainRenderer->CullPatches(frustum))
|
||||
return;
|
||||
|
||||
filtered = true;
|
||||
}
|
||||
|
||||
// switch on wireframe if we need it
|
||||
if (m_TerrainRenderMode == WIREFRAME)
|
||||
{
|
||||
@ -931,9 +996,9 @@ void CRenderer::RenderPatches()
|
||||
|
||||
// render all the patches, including blend pass
|
||||
if (GetRenderPath() == RP_SHADER)
|
||||
m->terrainRenderer->RenderTerrainShader((m_Caps.m_Shadows && m_Options.m_Shadows) ? m->shadow : 0);
|
||||
m->terrainRenderer->RenderTerrainShader((m_Caps.m_Shadows && m_Options.m_Shadows) ? m->shadow : 0, filtered);
|
||||
else
|
||||
m->terrainRenderer->RenderTerrain();
|
||||
m->terrainRenderer->RenderTerrain(filtered);
|
||||
|
||||
|
||||
if (m_TerrainRenderMode == WIREFRAME)
|
||||
@ -953,14 +1018,14 @@ void CRenderer::RenderPatches()
|
||||
glLineWidth(2.0f);
|
||||
|
||||
// render tiles edges
|
||||
m->terrainRenderer->RenderPatches();
|
||||
m->terrainRenderer->RenderPatches(filtered);
|
||||
|
||||
// set color for outline
|
||||
glColor3f(0, 0, 1);
|
||||
glLineWidth(4.0f);
|
||||
|
||||
// render outline of each patch
|
||||
m->terrainRenderer->RenderOutlines();
|
||||
m->terrainRenderer->RenderOutlines(filtered);
|
||||
|
||||
// .. and restore the renderstates
|
||||
glLineWidth(1.0f);
|
||||
@ -968,17 +1033,39 @@ void CRenderer::RenderPatches()
|
||||
}
|
||||
}
|
||||
|
||||
void CRenderer::RenderModels()
|
||||
class CModelCuller : public CModelFilter
|
||||
{
|
||||
public:
|
||||
CModelCuller(const CFrustum& frustum) : m_Frustum(frustum) { }
|
||||
|
||||
bool Filter(CModel *model)
|
||||
{
|
||||
return m_Frustum.IsBoxVisible(CVector3D(0, 0, 0), model->GetBoundsRec());
|
||||
}
|
||||
|
||||
private:
|
||||
const CFrustum& m_Frustum;
|
||||
};
|
||||
|
||||
void CRenderer::RenderModels(const CFrustum* frustum)
|
||||
{
|
||||
PROFILE("render models");
|
||||
|
||||
int flags = 0;
|
||||
if (frustum)
|
||||
{
|
||||
flags = MODELFLAG_FILTERED;
|
||||
CModelCuller culler(*frustum);
|
||||
m->FilterModels(culler, flags);
|
||||
}
|
||||
|
||||
if (m_ModelRenderMode == WIREFRAME)
|
||||
{
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
}
|
||||
|
||||
m->CallModelRenderers(m->Model.ModNormal, m->Model.ModNormalInstancing,
|
||||
m->Model.ModPlayer, m->Model.ModPlayerInstancing, 0);
|
||||
m->Model.ModPlayer, m->Model.ModPlayerInstancing, flags);
|
||||
|
||||
if (m_ModelRenderMode == WIREFRAME)
|
||||
{
|
||||
@ -991,23 +1078,36 @@ void CRenderer::RenderModels()
|
||||
glColor3f(1.0f, 1.0f, 0.0f);
|
||||
|
||||
m->CallModelRenderers(m->Model.ModSolid, m->Model.ModSolidInstancing,
|
||||
m->Model.ModSolid, m->Model.ModSolidInstancing, 0);
|
||||
m->Model.ModSolid, m->Model.ModSolidInstancing, flags);
|
||||
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
}
|
||||
}
|
||||
|
||||
void CRenderer::RenderTransparentModels()
|
||||
void CRenderer::RenderTransparentModels(ETransparentMode transparentMode, const CFrustum* frustum)
|
||||
{
|
||||
PROFILE("render transparent models");
|
||||
|
||||
int flags = 0;
|
||||
if (frustum)
|
||||
{
|
||||
flags = MODELFLAG_FILTERED;
|
||||
CModelCuller culler(*frustum);
|
||||
m->Model.Transp->Filter(culler, flags);
|
||||
}
|
||||
|
||||
// switch on wireframe if we need it
|
||||
if (m_ModelRenderMode == WIREFRAME)
|
||||
{
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
}
|
||||
|
||||
m->Model.Transp->Render(m->Model.ModTransparent, 0);
|
||||
if (transparentMode == TRANSPARENT_OPAQUE)
|
||||
m->Model.Transp->Render(m->Model.ModTransparentOpaque, flags);
|
||||
else if (transparentMode == TRANSPARENT_BLEND)
|
||||
m->Model.Transp->Render(m->Model.ModTransparentBlend, flags);
|
||||
else
|
||||
m->Model.Transp->Render(m->Model.ModTransparent, flags);
|
||||
|
||||
if (m_ModelRenderMode == WIREFRAME)
|
||||
{
|
||||
@ -1020,7 +1120,7 @@ void CRenderer::RenderTransparentModels()
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glColor3f(1.0f, 0.0f, 0.0f);
|
||||
|
||||
m->Model.Transp->Render(m->Model.ModSolid, 0);
|
||||
m->Model.Transp->Render(m->Model.ModSolid, flags);
|
||||
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
}
|
||||
@ -1034,10 +1134,10 @@ CMatrix3D CRenderer::GetModelViewProjectionMatrix()
|
||||
CMatrix3D proj;
|
||||
CMatrix3D view;
|
||||
|
||||
glGetFloatv( GL_PROJECTION_MATRIX, &proj._11 );
|
||||
glGetFloatv( GL_MODELVIEW_MATRIX, &view._11 );
|
||||
glGetFloatv(GL_PROJECTION_MATRIX, &proj._11);
|
||||
glGetFloatv(GL_MODELVIEW_MATRIX, &view._11);
|
||||
|
||||
return( proj * view );
|
||||
return proj*view;
|
||||
}
|
||||
|
||||
|
||||
@ -1045,74 +1145,49 @@ CMatrix3D CRenderer::GetModelViewProjectionMatrix()
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// SetObliqueFrustumClipping: change the near plane to the given clip plane (in world space)
|
||||
// Based on code from Game Programming Gems 5, from http://www.terathon.com/code/oblique.html
|
||||
// - cp is a clip plane in camera space (cp.Dot(v) = 0 for any vector v on the plane)
|
||||
// - sign is 1 or -1, to specify the side to clip on
|
||||
void CRenderer::SetObliqueFrustumClipping(const CVector4D& cp, int sign)
|
||||
// - worldPlane is a clip plane in world space (worldPlane.Dot(v) >= 0 for any vector v passing the clipping test)
|
||||
void CRenderer::SetObliqueFrustumClipping(const CVector4D& worldPlane)
|
||||
{
|
||||
float matrix[16];
|
||||
CVector4D q;
|
||||
float matrix[16];
|
||||
CVector4D q;
|
||||
|
||||
// First, we'll convert the given clip plane to camera space, then we'll
|
||||
// Get the view matrix and normal matrix (top 3x3 part of view matrix)
|
||||
CMatrix3D viewMatrix;
|
||||
m_ViewCamera.m_Orientation.GetInverse(viewMatrix);
|
||||
CMatrix3D normalMatrix = viewMatrix;
|
||||
normalMatrix._14 = 0;
|
||||
normalMatrix._24 = 0;
|
||||
normalMatrix._34 = 0;
|
||||
normalMatrix._44 = 1;
|
||||
normalMatrix._41 = 0;
|
||||
normalMatrix._42 = 0;
|
||||
normalMatrix._43 = 0;
|
||||
CMatrix3D normalMatrix = m_ViewCamera.m_Orientation.GetTranspose();
|
||||
CVector4D camPlane = normalMatrix.Transform(worldPlane);
|
||||
|
||||
// Convert the normal to camera space
|
||||
CVector4D planeNormal(cp.m_X, cp.m_Y, cp.m_Z, 0);
|
||||
planeNormal = normalMatrix.Transform(planeNormal);
|
||||
planeNormal.Normalize();
|
||||
// Grab the current projection matrix from OpenGL
|
||||
glGetFloatv(GL_PROJECTION_MATRIX, matrix);
|
||||
|
||||
// Find a point on the plane: we'll take the normal times -D
|
||||
float oldD = cp.m_W;
|
||||
CVector4D pointOnPlane(-oldD * cp.m_X, -oldD * cp.m_Y, -oldD * cp.m_Z, 1);
|
||||
pointOnPlane = viewMatrix.Transform(pointOnPlane);
|
||||
float newD = -pointOnPlane.Dot(planeNormal);
|
||||
|
||||
// Now create a clip plane from the new normal and new D
|
||||
CVector4D camPlane = planeNormal;
|
||||
camPlane.m_W = newD;
|
||||
|
||||
// Grab the current projection matrix from OpenGL
|
||||
glGetFloatv(GL_PROJECTION_MATRIX, matrix);
|
||||
// Calculate the clip-space corner point opposite the clipping plane
|
||||
// as (sgn(camPlane.x), sgn(camPlane.y), 1, 1) and
|
||||
// transform it into camera space by multiplying it
|
||||
// by the inverse of the projection matrix
|
||||
|
||||
// Calculate the clip-space corner point opposite the clipping plane
|
||||
// as (sgn(camPlane.x), sgn(camPlane.y), 1, 1) and
|
||||
// transform it into camera space by multiplying it
|
||||
// by the inverse of the projection matrix
|
||||
|
||||
q.m_X = (sgn(camPlane.m_X) + matrix[8]) / matrix[0];
|
||||
q.m_Y = (sgn(camPlane.m_Y) + matrix[9]) / matrix[5];
|
||||
q.m_Z = -1.0f;
|
||||
q.m_W = (1.0f + matrix[10]) / matrix[14];
|
||||
|
||||
// Calculate the scaled plane vector
|
||||
CVector4D c = camPlane * (sign * 2.0f / camPlane.Dot(q));
|
||||
|
||||
// Replace the third row of the projection matrix
|
||||
matrix[2] = c.m_X;
|
||||
matrix[6] = c.m_Y;
|
||||
matrix[10] = c.m_Z + 1.0f;
|
||||
matrix[14] = c.m_W;
|
||||
q.m_X = (sgn(camPlane.m_X) - matrix[8]/matrix[11]) / matrix[0];
|
||||
q.m_Y = (sgn(camPlane.m_Y) - matrix[9]/matrix[11]) / matrix[5];
|
||||
q.m_Z = 1.0f/matrix[11];
|
||||
q.m_W = (1.0f - matrix[10]/matrix[11]) / matrix[14];
|
||||
|
||||
// Load it back into OpenGL
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadMatrixf(matrix);
|
||||
// Calculate the scaled plane vector
|
||||
CVector4D c = camPlane * (2.0f * matrix[11] / camPlane.Dot(q));
|
||||
|
||||
// Replace the third row of the projection matrix
|
||||
matrix[2] = c.m_X;
|
||||
matrix[6] = c.m_Y;
|
||||
matrix[10] = c.m_Z - matrix[11];
|
||||
matrix[14] = c.m_W;
|
||||
|
||||
// Load it back into OpenGL
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadMatrixf(matrix);
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// RenderReflections: render the water reflections to the reflection texture
|
||||
void CRenderer::RenderReflections()
|
||||
SScreenRect CRenderer::RenderReflections(const CBound& scissor)
|
||||
{
|
||||
PROFILE("render reflections");
|
||||
|
||||
@ -1126,9 +1201,11 @@ void CRenderer::RenderReflections()
|
||||
// water texture, stretch the image according to our aspect ratio so it covers
|
||||
// the whole screen despite being rendered into a square, and cover slightly more
|
||||
// of the view so we can see wavy reflections of slightly off-screen objects.
|
||||
m_ViewCamera.m_Orientation.Translate(0, -wm.m_WaterHeight, 0);
|
||||
m_ViewCamera.m_Orientation.Scale(1, -1, 1);
|
||||
m_ViewCamera.m_Orientation.Translate(0, wm.m_WaterHeight, 0);
|
||||
m_ViewCamera.m_Orientation.Translate(0, 2*wm.m_WaterHeight, 0);
|
||||
m_ViewCamera.UpdateFrustum(scissor);
|
||||
m_ViewCamera.ClipFrustum(CVector4D(0, 1, 0, -wm.m_WaterHeight));
|
||||
|
||||
SViewPort vp;
|
||||
vp.m_Height = wm.m_ReflectionTextureSize;
|
||||
vp.m_Width = wm.m_ReflectionTextureSize;
|
||||
@ -1143,52 +1220,61 @@ void CRenderer::RenderReflections()
|
||||
m->SetOpenGLCamera(m_ViewCamera);
|
||||
|
||||
CVector4D camPlane(0, 1, 0, -wm.m_WaterHeight);
|
||||
SetObliqueFrustumClipping(camPlane, -1);
|
||||
SetObliqueFrustumClipping(camPlane);
|
||||
|
||||
// Save the model-view-projection matrix so the shaders can use it for projective texturing
|
||||
wm.m_ReflectionMatrix = GetModelViewProjectionMatrix();
|
||||
|
||||
// Disable backface culling so trees render properly (it might also be possible to flip
|
||||
// the culling direction here, but this seems to lead to problems)
|
||||
glDisable(GL_CULL_FACE);
|
||||
SScreenRect screenScissor;
|
||||
screenScissor.x1 = (GLint)floor((scissor[0].X*0.5f+0.5f)*vp.m_Width);
|
||||
screenScissor.y1 = (GLint)floor((scissor[0].Y*0.5f+0.5f)*vp.m_Height);
|
||||
screenScissor.x2 = (GLint)ceil((scissor[1].X*0.5f+0.5f)*vp.m_Width);
|
||||
screenScissor.y2 = (GLint)ceil((scissor[1].Y*0.5f+0.5f)*vp.m_Height);
|
||||
|
||||
// Make the depth buffer work backwards; there seems to be some oddness with
|
||||
// oblique frustum clipping and the "sign" parameter here
|
||||
glClearDepth(0);
|
||||
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
glDepthFunc(GL_GEQUAL);
|
||||
if (screenScissor.x1 < screenScissor.x2 && screenScissor.y1 < screenScissor.y2)
|
||||
{
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glScissor(screenScissor.x1, screenScissor.y1, screenScissor.x2 - screenScissor.x1, screenScissor.y2 - screenScissor.y1);
|
||||
|
||||
// Render sky, terrain and models
|
||||
m->skyManager.RenderSky();
|
||||
ogl_WarnIfError();
|
||||
RenderPatches();
|
||||
ogl_WarnIfError();
|
||||
RenderModels();
|
||||
ogl_WarnIfError();
|
||||
RenderTransparentModels();
|
||||
ogl_WarnIfError();
|
||||
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
|
||||
// Copy the image to a texture
|
||||
pglActiveTextureARB(GL_TEXTURE0_ARB);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, wm.m_ReflectionTexture);
|
||||
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0,
|
||||
(GLsizei)wm.m_ReflectionTextureSize, (GLsizei)wm.m_ReflectionTextureSize);
|
||||
glFrontFace(GL_CW);
|
||||
|
||||
//Reset old camera and re-enable backface culling
|
||||
// Render sky, terrain and models
|
||||
m->skyManager.RenderSky();
|
||||
ogl_WarnIfError();
|
||||
RenderPatches(&m_ViewCamera.GetFrustum());
|
||||
ogl_WarnIfError();
|
||||
RenderModels(&m_ViewCamera.GetFrustum());
|
||||
ogl_WarnIfError();
|
||||
RenderTransparentModels(TRANSPARENT_BLEND, &m_ViewCamera.GetFrustum());
|
||||
ogl_WarnIfError();
|
||||
|
||||
glFrontFace(GL_CCW);
|
||||
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
|
||||
// Copy the image to a texture
|
||||
pglActiveTextureARB(GL_TEXTURE0_ARB);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, wm.m_ReflectionTexture);
|
||||
glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
|
||||
screenScissor.x1, screenScissor.y1,
|
||||
screenScissor.x1, screenScissor.y1,
|
||||
screenScissor.x2 - screenScissor.x1, screenScissor.y2 - screenScissor.y1);
|
||||
}
|
||||
|
||||
// Reset old camera
|
||||
m_ViewCamera = normalCamera;
|
||||
m->SetOpenGLCamera(m_ViewCamera);
|
||||
|
||||
glEnable(GL_CULL_FACE);
|
||||
//glClearDepth(1);
|
||||
//glClear(GL_DEPTH_BUFFER_BIT);
|
||||
//glDepthFunc(GL_LEQUAL);
|
||||
return screenScissor;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// RenderRefractions: render the water refractions to the refraction texture
|
||||
void CRenderer::RenderRefractions()
|
||||
SScreenRect CRenderer::RenderRefractions(const CBound &scissor)
|
||||
{
|
||||
PROFILE("render refractions");
|
||||
|
||||
@ -1201,6 +1287,9 @@ void CRenderer::RenderRefractions()
|
||||
// water texture, stretch the image according to our aspect ratio so it covers
|
||||
// the whole screen despite being rendered into a square, and cover slightly more
|
||||
// of the view so we can see wavy refractions of slightly off-screen objects.
|
||||
m_ViewCamera.UpdateFrustum(scissor);
|
||||
m_ViewCamera.ClipFrustum(CVector4D(0, -1, 0, wm.m_WaterHeight));
|
||||
|
||||
SViewPort vp;
|
||||
vp.m_Height = wm.m_RefractionTextureSize;
|
||||
vp.m_Width = wm.m_RefractionTextureSize;
|
||||
@ -1211,43 +1300,53 @@ void CRenderer::RenderRefractions()
|
||||
CMatrix3D scaleMat;
|
||||
scaleMat.SetScaling(m_Height/float(std::max(1, m_Width)), 1.0f, 1.0f);
|
||||
m_ViewCamera.m_ProjMat = scaleMat * m_ViewCamera.m_ProjMat;
|
||||
|
||||
m->SetOpenGLCamera(m_ViewCamera);
|
||||
|
||||
CVector4D camPlane(0, 1, 0, -wm.m_WaterHeight);
|
||||
SetObliqueFrustumClipping(camPlane, -1);
|
||||
CVector4D camPlane(0, -1, 0, wm.m_WaterHeight);
|
||||
SetObliqueFrustumClipping(camPlane);
|
||||
|
||||
// Save the model-view-projection matrix so the shaders can use it for projective texturing
|
||||
wm.m_RefractionMatrix = GetModelViewProjectionMatrix();
|
||||
|
||||
// Make the depth buffer work backwards; there seems to be some oddness with
|
||||
// oblique frustum clipping and the "sign" parameter here
|
||||
glClearDepth(0);
|
||||
glClearColor(0.5f, 0.5f, 0.5f, 1.0f); // a neutral gray to blend in with shores
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
glDepthFunc(GL_GEQUAL);
|
||||
SScreenRect screenScissor;
|
||||
screenScissor.x1 = (GLint)floor((scissor[0].X*0.5f+0.5f)*vp.m_Width);
|
||||
screenScissor.y1 = (GLint)floor((scissor[0].Y*0.5f+0.5f)*vp.m_Height);
|
||||
screenScissor.x2 = (GLint)ceil((scissor[1].X*0.5f+0.5f)*vp.m_Width);
|
||||
screenScissor.y2 = (GLint)ceil((scissor[1].Y*0.5f+0.5f)*vp.m_Height);
|
||||
if (screenScissor.x1 < screenScissor.x2 && screenScissor.y1 < screenScissor.y2)
|
||||
{
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glScissor(screenScissor.x1, screenScissor.y1, screenScissor.x2 - screenScissor.x1, screenScissor.y2 - screenScissor.y1);
|
||||
|
||||
// Render terrain and models
|
||||
RenderPatches();
|
||||
ogl_WarnIfError();
|
||||
RenderModels();
|
||||
ogl_WarnIfError();
|
||||
RenderTransparentModels();
|
||||
ogl_WarnIfError();
|
||||
glClearColor(0.5f, 0.5f, 0.5f, 1.0f); // a neutral gray to blend in with shores
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
|
||||
// Copy the image to a texture
|
||||
pglActiveTextureARB(GL_TEXTURE0_ARB);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, wm.m_RefractionTexture);
|
||||
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0,
|
||||
(GLsizei)wm.m_RefractionTextureSize, (GLsizei)wm.m_RefractionTextureSize);
|
||||
// Render terrain and models
|
||||
RenderPatches(&m_ViewCamera.GetFrustum());
|
||||
ogl_WarnIfError();
|
||||
RenderModels(&m_ViewCamera.GetFrustum());
|
||||
ogl_WarnIfError();
|
||||
RenderTransparentModels(TRANSPARENT_BLEND, &m_ViewCamera.GetFrustum());
|
||||
ogl_WarnIfError();
|
||||
|
||||
//Reset old camera and re-enable backface culling
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
|
||||
// Copy the image to a texture
|
||||
pglActiveTextureARB(GL_TEXTURE0_ARB);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, wm.m_RefractionTexture);
|
||||
glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
|
||||
screenScissor.x1, screenScissor.y1,
|
||||
screenScissor.x1, screenScissor.y1,
|
||||
screenScissor.x2 - screenScissor.x1, screenScissor.y2 - screenScissor.y1);
|
||||
}
|
||||
|
||||
// Reset old camera
|
||||
m_ViewCamera = normalCamera;
|
||||
m->SetOpenGLCamera(m_ViewCamera);
|
||||
|
||||
glEnable(GL_CULL_FACE);
|
||||
glClearDepth(1);
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
return screenScissor;
|
||||
}
|
||||
|
||||
|
||||
@ -1435,13 +1534,28 @@ void CRenderer::RenderSubmissions()
|
||||
|
||||
ogl_WarnIfError();
|
||||
|
||||
if (m_WaterManager->m_RenderWater && m_WaterManager->WillRenderFancyWater())
|
||||
CBound waterScissor;
|
||||
if (m_WaterManager->m_RenderWater)
|
||||
{
|
||||
// render reflected and refracted scenes, then re-clear the screen
|
||||
RenderReflections();
|
||||
RenderRefractions();
|
||||
glClearColor(m_ClearColor[0],m_ClearColor[1],m_ClearColor[2],m_ClearColor[3]);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
waterScissor = m->terrainRenderer->ScissorWater(m_ViewCamera.GetViewProjection());
|
||||
if (waterScissor.GetVolume() > 0 && m_WaterManager->WillRenderFancyWater())
|
||||
{
|
||||
SScreenRect reflectionScissor = RenderReflections(waterScissor);
|
||||
SScreenRect refractionScissor = RenderRefractions(waterScissor);
|
||||
SScreenRect dirty;
|
||||
dirty.x1 = std::min(reflectionScissor.x1, refractionScissor.x1);
|
||||
dirty.y1 = std::min(reflectionScissor.y1, refractionScissor.y1);
|
||||
dirty.x2 = std::max(reflectionScissor.x2, refractionScissor.x2);
|
||||
dirty.y2 = std::max(reflectionScissor.y2, refractionScissor.y2);
|
||||
if (dirty.x1 < dirty.x2 && dirty.y1 < dirty.y2)
|
||||
{
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glScissor(dirty.x1, dirty.y1, dirty.x2 - dirty.x1, dirty.y2 - dirty.y1);
|
||||
glClearColor(m_ClearColor[0], m_ClearColor[1], m_ClearColor[2], m_ClearColor[3]);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// render submitted patches and models
|
||||
@ -1467,27 +1581,25 @@ void CRenderer::RenderSubmissions()
|
||||
RenderModels();
|
||||
ogl_WarnIfError();
|
||||
|
||||
// render transparent stuff, so it can overlap models/terrain
|
||||
RenderTransparentModels();
|
||||
ogl_WarnIfError();
|
||||
|
||||
// render water
|
||||
if (m_WaterManager->m_RenderWater && g_Game)
|
||||
if (m_WaterManager->m_RenderWater && g_Game && waterScissor.GetVolume() > 0)
|
||||
{
|
||||
// render transparent stuff, but only the solid parts that can occlude block water
|
||||
RenderTransparentModels(TRANSPARENT_OPAQUE);
|
||||
ogl_WarnIfError();
|
||||
|
||||
m->terrainRenderer->RenderWater();
|
||||
ogl_WarnIfError();
|
||||
|
||||
// render transparent stuff again, so it can overlap the water
|
||||
RenderTransparentModels();
|
||||
|
||||
// render transparent stuff again, but only the blended parts that overlap water
|
||||
RenderTransparentModels(TRANSPARENT_BLEND);
|
||||
ogl_WarnIfError();
|
||||
}
|
||||
else
|
||||
{
|
||||
// render transparent stuff, so it can overlap models/terrain
|
||||
RenderTransparentModels(TRANSPARENT);
|
||||
ogl_WarnIfError();
|
||||
|
||||
// TODO: Maybe think of a better way to deal with transparent objects;
|
||||
// they can appear both under and above water (seaweed vs. trees), but doing
|
||||
// 2 renders causes (a) inefficiency and (b) darker over-water objects (e.g.
|
||||
// trees) than usual because the transparent bits get overwritten twice.
|
||||
// This doesn't look particularly bad, but it is noticeable if you try
|
||||
// turning the water off. On the other hand every user will have water
|
||||
// on all the time, so it might not be worth worrying about.
|
||||
}
|
||||
|
||||
// particles are transparent so render after water
|
||||
@ -1931,6 +2043,19 @@ void CRenderer::JSI_SetShadowAlphaFix(JSContext* ctx, jsval newval)
|
||||
m->shadow->RecreateTexture();
|
||||
}
|
||||
|
||||
jsval CRenderer::JSI_GetShadowPCF(JSContext*)
|
||||
{
|
||||
return ToJSVal(m_Options.m_ShadowPCF);
|
||||
}
|
||||
|
||||
void CRenderer::JSI_SetShadowPCF(JSContext* ctx, jsval newval)
|
||||
{
|
||||
if (!ToPrimitive(ctx, newval, m_Options.m_ShadowPCF))
|
||||
return;
|
||||
|
||||
ReloadShaders();
|
||||
}
|
||||
|
||||
jsval CRenderer::JSI_GetSky(JSContext*)
|
||||
{
|
||||
return ToJSVal(m->skyManager.GetSkySet());
|
||||
@ -1955,6 +2080,7 @@ void CRenderer::ScriptingInit()
|
||||
AddProperty(L"shadows", &CRenderer::JSI_GetShadows, &CRenderer::JSI_SetShadows);
|
||||
AddProperty(L"depthTextureBits", &CRenderer::JSI_GetDepthTextureBits, &CRenderer::JSI_SetDepthTextureBits);
|
||||
AddProperty(L"shadowAlphaFix", &CRenderer::JSI_GetShadowAlphaFix, &CRenderer::JSI_SetShadowAlphaFix);
|
||||
AddProperty(L"shadowPCF", &CRenderer::JSI_GetShadowPCF, &CRenderer::JSI_SetShadowPCF);
|
||||
AddProperty(L"skipSubmit", &CRenderer::m_SkipSubmit);
|
||||
AddProperty(L"skySet", &CRenderer::JSI_GetSky, &CRenderer::JSI_SetSky);
|
||||
|
||||
|
@ -49,6 +49,9 @@ class CParticleManager;
|
||||
// rendering modes
|
||||
enum ERenderMode { WIREFRAME, SOLID, EDGED_FACES };
|
||||
|
||||
// transparency modes
|
||||
enum ETransparentMode { TRANSPARENT, TRANSPARENT_OPAQUE, TRANSPARENT_BLEND };
|
||||
|
||||
// stream flags
|
||||
#define STREAM_POS (1 << 0)
|
||||
#define STREAM_NORMAL (1 << 1)
|
||||
@ -65,6 +68,11 @@ enum ERenderMode { WIREFRAME, SOLID, EDGED_FACES };
|
||||
// access to sole renderer object
|
||||
#define g_Renderer CRenderer::GetSingleton()
|
||||
|
||||
struct SScreenRect
|
||||
{
|
||||
GLint x1, y1, x2, y2;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CRenderer: base renderer class - primary interface to the rendering engine
|
||||
struct CRendererInternals;
|
||||
@ -81,7 +89,8 @@ public:
|
||||
OPT_NOVBO,
|
||||
OPT_SHADOWS,
|
||||
OPT_FANCYWATER,
|
||||
OPT_LODBIAS
|
||||
OPT_LODBIAS,
|
||||
OPT_SHADOWPCF
|
||||
};
|
||||
|
||||
enum RenderPath {
|
||||
@ -104,6 +113,8 @@ public:
|
||||
size_t m_DrawCalls;
|
||||
// number of terrain triangles drawn
|
||||
size_t m_TerrainTris;
|
||||
// number of water triangles drawn
|
||||
size_t m_WaterTris;
|
||||
// number of (non-transparent) model triangles drawn
|
||||
size_t m_ModelTris;
|
||||
// number of splat passes for alphamapping
|
||||
@ -121,6 +132,7 @@ public:
|
||||
RenderPath m_RenderPath;
|
||||
bool m_ShadowAlphaFix;
|
||||
bool m_ARBProgramShadow;
|
||||
bool m_ShadowPCF;
|
||||
} m_Options;
|
||||
|
||||
struct Caps {
|
||||
@ -315,6 +327,8 @@ protected:
|
||||
void JSI_SetShadows(JSContext* ctx, jsval newval);
|
||||
jsval JSI_GetShadowAlphaFix(JSContext*);
|
||||
void JSI_SetShadowAlphaFix(JSContext* ctx, jsval newval);
|
||||
jsval JSI_GetShadowPCF(JSContext*);
|
||||
void JSI_SetShadowPCF(JSContext* ctx, jsval newval);
|
||||
jsval JSI_GetSky(JSContext*);
|
||||
void JSI_SetSky(JSContext* ctx, jsval newval);
|
||||
|
||||
@ -331,11 +345,11 @@ protected:
|
||||
void RenderSubmissions();
|
||||
|
||||
// patch rendering stuff
|
||||
void RenderPatches();
|
||||
void RenderPatches(const CFrustum* frustum = 0);
|
||||
|
||||
// model rendering stuff
|
||||
void RenderModels();
|
||||
void RenderTransparentModels();
|
||||
void RenderModels(const CFrustum* frustum = 0);
|
||||
void RenderTransparentModels(ETransparentMode transparentMode, const CFrustum* frustum = 0);
|
||||
|
||||
void RenderSilhouettes();
|
||||
|
||||
@ -345,14 +359,14 @@ protected:
|
||||
void RenderShadowMap();
|
||||
|
||||
// render water reflection and refraction textures
|
||||
void RenderReflections();
|
||||
void RenderRefractions();
|
||||
SScreenRect RenderReflections(const CBound& scissor);
|
||||
SScreenRect RenderRefractions(const CBound& scissor);
|
||||
|
||||
// debugging
|
||||
void DisplayFrustum();
|
||||
|
||||
// enable oblique frustum clipping with the given clip plane
|
||||
void SetObliqueFrustumClipping(const CVector4D& clipPlane, int sign);
|
||||
void SetObliqueFrustumClipping(const CVector4D& clipPlane);
|
||||
|
||||
void ReloadShaders();
|
||||
|
||||
|
@ -78,6 +78,8 @@ struct ShadowMapInternals
|
||||
// alpha texture which is attached to the FBO as a workaround.
|
||||
GLuint DummyTexture;
|
||||
|
||||
float FilterOffsets[8];
|
||||
|
||||
// Helper functions
|
||||
void CalcShadowMatrices();
|
||||
void CreateTexture();
|
||||
@ -221,6 +223,13 @@ void ShadowMapInternals::CalcShadowMatrices()
|
||||
|
||||
ShadowBound.IntersectFrustumConservative(LightspaceCamera.GetFrustum());
|
||||
|
||||
// round off the shadow boundaries to sane increments to help reduce swim effect
|
||||
float boundInc = 16.0f;
|
||||
ShadowBound[0].X = floor(ShadowBound[0].X / boundInc) * boundInc;
|
||||
ShadowBound[0].Y = floor(ShadowBound[0].Y / boundInc) * boundInc;
|
||||
ShadowBound[1].X = ceil(ShadowBound[1].X / boundInc) * boundInc;
|
||||
ShadowBound[1].Y = ceil(ShadowBound[1].Y / boundInc) * boundInc;
|
||||
|
||||
// minimum Z bound must not be clipped too much, because objects that lie outside
|
||||
// the shadow bounds cannot cast shadows either
|
||||
// the 2.0 is rather arbitrary: it should be big enough so that we won't accidently miss
|
||||
@ -242,11 +251,15 @@ void ShadowMapInternals::CalcShadowMatrices()
|
||||
scale.Y = 2.0 / scale.Y;
|
||||
scale.Z = 2.0 / scale.Z;
|
||||
|
||||
// make sure a given world position falls on a consistent shadowmap texel fractional offset
|
||||
float offsetX = fmod(ShadowBound[0].X - LightTransform._14, 2.0f/(scale.X*EffectiveWidth));
|
||||
float offsetY = fmod(ShadowBound[0].Y - LightTransform._24, 2.0f/(scale.Y*EffectiveHeight));
|
||||
|
||||
LightProjection.SetZero();
|
||||
LightProjection._11 = scale.X;
|
||||
LightProjection._14 = shift.X * scale.X;
|
||||
LightProjection._14 = (shift.X + offsetX) * scale.X;
|
||||
LightProjection._22 = scale.Y;
|
||||
LightProjection._24 = shift.Y * scale.Y;
|
||||
LightProjection._24 = (shift.Y + offsetY) * scale.Y;
|
||||
LightProjection._33 = scale.Z;
|
||||
LightProjection._34 = shift.Z * scale.Z + renderer.m_ShadowZBias;
|
||||
LightProjection._44 = 1.0;
|
||||
@ -255,19 +268,15 @@ void ShadowMapInternals::CalcShadowMatrices()
|
||||
// Calculate texture matrix by creating the clip space to texture coordinate matrix
|
||||
// and then concatenating all matrices that have been calculated so far
|
||||
CMatrix3D lightToTex;
|
||||
float texscalex = (float)EffectiveWidth / (float)Width;
|
||||
float texscaley = (float)EffectiveHeight / (float)Height;
|
||||
float texscalez = 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);
|
||||
float texscalex = scale.X * 0.5f * (float)EffectiveWidth / (float)Width;
|
||||
float texscaley = scale.Y * 0.5f * (float)EffectiveHeight / (float)Height;
|
||||
float texscalez = scale.Z * 0.5f;
|
||||
|
||||
lightToTex.SetZero();
|
||||
lightToTex._11 = texscalex;
|
||||
lightToTex._14 = -ShadowBound[0].X * texscalex;
|
||||
lightToTex._14 = (offsetX - ShadowBound[0].X) * texscalex;
|
||||
lightToTex._22 = texscaley;
|
||||
lightToTex._24 = -ShadowBound[0].Y * texscaley;
|
||||
lightToTex._24 = (offsetY - ShadowBound[0].Y) * texscaley;
|
||||
lightToTex._33 = texscalez;
|
||||
lightToTex._34 = -ShadowBound[0].Z * texscalez;
|
||||
lightToTex._44 = 1.0;
|
||||
@ -359,7 +368,7 @@ void ShadowMapInternals::CreateTexture()
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, format, Width, Height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
|
||||
|
||||
@ -397,6 +406,18 @@ void ShadowMapInternals::CreateTexture()
|
||||
// Disable shadow rendering (but let the user try again if they want)
|
||||
g_Renderer.m_Options.m_Shadows = false;
|
||||
}
|
||||
|
||||
FilterOffsets[0] = -0.4f/Width;
|
||||
FilterOffsets[1] = 1.0f/Height;
|
||||
|
||||
FilterOffsets[2] = -1.0f/Width;
|
||||
FilterOffsets[3] = -0.4f/Height;
|
||||
|
||||
FilterOffsets[4] = 0.4f/Width;
|
||||
FilterOffsets[5] = -1.0f/Height;
|
||||
|
||||
FilterOffsets[6] = 1.0f/Width;
|
||||
FilterOffsets[7] = 0.4f/Height;
|
||||
}
|
||||
|
||||
|
||||
@ -496,6 +517,10 @@ void ShadowMap::SetDepthTextureBits(int bits)
|
||||
}
|
||||
}
|
||||
|
||||
const float* ShadowMap::GetFilterOffsets() const
|
||||
{
|
||||
return m->FilterOffsets;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// RenderDebugDisplay: debug visualizations
|
||||
|
@ -118,6 +118,11 @@ public:
|
||||
*/
|
||||
void RenderDebugDisplay();
|
||||
|
||||
/**
|
||||
* Get offsets for PCF filtering.
|
||||
*/
|
||||
const float* GetFilterOffsets() const;
|
||||
|
||||
private:
|
||||
ShadowMapInternals* m;
|
||||
};
|
||||
|
@ -76,9 +76,11 @@ struct TerrainRendererInternals
|
||||
|
||||
/// Patches that were submitted for this frame
|
||||
std::vector<CPatchRData*> visiblePatches;
|
||||
std::vector<CPatchRData*> filteredPatches;
|
||||
|
||||
/// Decals that were submitted for this frame
|
||||
std::vector<CDecalRData*> visibleDecals;
|
||||
std::vector<CDecalRData*> filteredDecals;
|
||||
|
||||
/// Fancy water shader
|
||||
Handle fancyWaterShader;
|
||||
@ -163,19 +165,45 @@ void TerrainRenderer::EndFrame()
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// Culls patches and decals against a frustum.
|
||||
bool TerrainRenderer::CullPatches(const CFrustum* frustum)
|
||||
{
|
||||
m->filteredPatches.clear();
|
||||
for (std::vector<CPatchRData*>::iterator it = m->visiblePatches.begin(); it != m->visiblePatches.end(); it++)
|
||||
{
|
||||
if (frustum->IsBoxVisible(CVector3D(0, 0, 0), (*it)->GetPatch()->GetBounds()))
|
||||
m->filteredPatches.push_back(*it);
|
||||
}
|
||||
|
||||
m->filteredDecals.clear();
|
||||
for (std::vector<CDecalRData*>::iterator it = m->visibleDecals.begin(); it != m->visibleDecals.end(); it++)
|
||||
{
|
||||
if (frustum->IsBoxVisible(CVector3D(0, 0, 0), (*it)->GetDecal()->GetBounds()))
|
||||
m->filteredDecals.push_back(*it);
|
||||
}
|
||||
|
||||
return !m->filteredPatches.empty() || !m->filteredDecals.empty();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// Full-featured terrain rendering with blending and everything
|
||||
void TerrainRenderer::RenderTerrain()
|
||||
void TerrainRenderer::RenderTerrain(bool filtered)
|
||||
{
|
||||
ENSURE(m->phase == Phase_Render);
|
||||
|
||||
std::vector<CPatchRData*>& visiblePatches = filtered ? m->filteredPatches : m->visiblePatches;
|
||||
std::vector<CDecalRData*>& visibleDecals = filtered ? m->filteredDecals : m->visibleDecals;
|
||||
if (visiblePatches.empty() && visibleDecals.empty())
|
||||
return;
|
||||
|
||||
// render the solid black sides of the map first
|
||||
g_Renderer.BindTexture(0, 0);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glColor3f(0, 0, 0);
|
||||
PROFILE_START("render terrain sides");
|
||||
for (size_t i = 0; i < m->visiblePatches.size(); ++i)
|
||||
m->visiblePatches[i]->RenderSides();
|
||||
for (size_t i = 0; i < visiblePatches.size(); ++i)
|
||||
visiblePatches[i]->RenderSides();
|
||||
PROFILE_END("render terrain sides");
|
||||
|
||||
// switch on required client states
|
||||
@ -198,7 +226,7 @@ void TerrainRenderer::RenderTerrain()
|
||||
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, one);
|
||||
|
||||
PROFILE_START("render terrain base");
|
||||
CPatchRData::RenderBases(m->visiblePatches);
|
||||
CPatchRData::RenderBases(visiblePatches);
|
||||
PROFILE_END("render terrain base");
|
||||
|
||||
// render blends
|
||||
@ -231,7 +259,7 @@ void TerrainRenderer::RenderTerrain()
|
||||
|
||||
// render blend passes for each patch
|
||||
PROFILE_START("render terrain blends");
|
||||
CPatchRData::RenderBlends(m->visiblePatches);
|
||||
CPatchRData::RenderBlends(visiblePatches);
|
||||
PROFILE_END("render terrain blends");
|
||||
|
||||
// Disable second texcoord array
|
||||
@ -255,8 +283,8 @@ void TerrainRenderer::RenderTerrain()
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
|
||||
|
||||
PROFILE_START("render terrain decals");
|
||||
for (size_t i = 0; i < m->visibleDecals.size(); ++i)
|
||||
m->visibleDecals[i]->Render(CShaderProgramPtr());
|
||||
for (size_t i = 0; i < visibleDecals.size(); ++i)
|
||||
visibleDecals[i]->Render(CShaderProgramPtr());
|
||||
PROFILE_END("render terrain decals");
|
||||
|
||||
|
||||
@ -323,7 +351,7 @@ void TerrainRenderer::RenderTerrain()
|
||||
pglClientActiveTextureARB(GL_TEXTURE0);
|
||||
|
||||
PROFILE_START("render terrain streams");
|
||||
CPatchRData::RenderStreams(m->visiblePatches, streamflags);
|
||||
CPatchRData::RenderStreams(visiblePatches, streamflags);
|
||||
PROFILE_END("render terrain streams");
|
||||
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
@ -363,6 +391,10 @@ void TerrainRenderer::PrepareShader(const CShaderProgramPtr& shader, ShadowMap*
|
||||
{
|
||||
shader->BindTexture("shadowTex", shadow->GetTexture());
|
||||
shader->Uniform("shadowTransform", shadow->GetTextureMatrix());
|
||||
|
||||
const float* offsets = shadow->GetFilterOffsets();
|
||||
shader->Uniform("shadowOffsets1", offsets[0], offsets[1], offsets[2], offsets[3]);
|
||||
shader->Uniform("shadowOffsets2", offsets[4], offsets[5], offsets[6], offsets[7]);
|
||||
}
|
||||
|
||||
CLOSTexture& los = g_Renderer.GetScene().GetLOSTexture();
|
||||
@ -373,10 +405,15 @@ void TerrainRenderer::PrepareShader(const CShaderProgramPtr& shader, ShadowMap*
|
||||
shader->Uniform("sunColor", lightEnv.m_SunColor);
|
||||
}
|
||||
|
||||
void TerrainRenderer::RenderTerrainShader(ShadowMap* shadow)
|
||||
void TerrainRenderer::RenderTerrainShader(ShadowMap* shadow, bool filtered)
|
||||
{
|
||||
ENSURE(m->phase == Phase_Render);
|
||||
|
||||
std::vector<CPatchRData*>& visiblePatches = filtered ? m->filteredPatches : m->visiblePatches;
|
||||
std::vector<CDecalRData*>& visibleDecals = filtered ? m->filteredDecals : m->visibleDecals;
|
||||
if (visiblePatches.empty() && visibleDecals.empty())
|
||||
return;
|
||||
|
||||
CShaderManager& shaderManager = g_Renderer.GetShaderManager();
|
||||
|
||||
typedef std::map<CStr, CStr> Defines;
|
||||
@ -386,6 +423,8 @@ void TerrainRenderer::RenderTerrainShader(ShadowMap* shadow)
|
||||
defBasic["USE_SHADOW"] = "1";
|
||||
if (g_Renderer.m_Caps.m_ARBProgramShadow && g_Renderer.m_Options.m_ARBProgramShadow)
|
||||
defBasic["USE_FP_SHADOW"] = "1";
|
||||
if (g_Renderer.m_Options.m_ShadowPCF)
|
||||
defBasic["USE_SHADOW_PCF"] = "1";
|
||||
}
|
||||
|
||||
defBasic["LIGHTING_MODEL_" + g_Renderer.GetLightEnv().GetLightingModel()] = "1";
|
||||
@ -399,8 +438,8 @@ void TerrainRenderer::RenderTerrainShader(ShadowMap* shadow)
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glColor3f(0, 0, 0);
|
||||
PROFILE_START("render terrain sides");
|
||||
for (size_t i = 0; i < m->visiblePatches.size(); ++i)
|
||||
m->visiblePatches[i]->RenderSides();
|
||||
for (size_t i = 0; i < visiblePatches.size(); ++i)
|
||||
visiblePatches[i]->RenderSides();
|
||||
PROFILE_END("render terrain sides");
|
||||
|
||||
// switch on required client states
|
||||
@ -411,7 +450,7 @@ void TerrainRenderer::RenderTerrainShader(ShadowMap* shadow)
|
||||
PrepareShader(shaderBase, shadow);
|
||||
|
||||
PROFILE_START("render terrain base");
|
||||
CPatchRData::RenderBases(m->visiblePatches);
|
||||
CPatchRData::RenderBases(visiblePatches);
|
||||
PROFILE_END("render terrain base");
|
||||
|
||||
shaderBase->Unbind();
|
||||
@ -437,7 +476,7 @@ void TerrainRenderer::RenderTerrainShader(ShadowMap* shadow)
|
||||
|
||||
// render blend passes for each patch
|
||||
PROFILE_START("render terrain blends");
|
||||
CPatchRData::RenderBlends(m->visiblePatches);
|
||||
CPatchRData::RenderBlends(visiblePatches);
|
||||
PROFILE_END("render terrain blends");
|
||||
|
||||
// Disable second texcoord array
|
||||
@ -456,8 +495,8 @@ void TerrainRenderer::RenderTerrainShader(ShadowMap* shadow)
|
||||
pglClientActiveTextureARB(GL_TEXTURE0);
|
||||
|
||||
PROFILE_START("render terrain decals");
|
||||
for (size_t i = 0; i < m->visibleDecals.size(); ++i)
|
||||
m->visibleDecals[i]->Render(shaderDecal);
|
||||
for (size_t i = 0; i < visibleDecals.size(); ++i)
|
||||
visibleDecals[i]->Render(shaderDecal);
|
||||
PROFILE_END("render terrain decals");
|
||||
|
||||
shaderDecal->Unbind();
|
||||
@ -480,56 +519,111 @@ void TerrainRenderer::RenderTerrainShader(ShadowMap* shadow)
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// Render un-textured patches as polygons
|
||||
void TerrainRenderer::RenderPatches()
|
||||
void TerrainRenderer::RenderPatches(bool filtered)
|
||||
{
|
||||
ENSURE(m->phase == Phase_Render);
|
||||
|
||||
std::vector<CPatchRData*>& visiblePatches = filtered ? m->filteredPatches : m->visiblePatches;
|
||||
if (visiblePatches.empty())
|
||||
return;
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
CPatchRData::RenderStreams(m->visiblePatches, STREAM_POS);
|
||||
CPatchRData::RenderStreams(visiblePatches, STREAM_POS);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// Render outlines of submitted patches as lines
|
||||
void TerrainRenderer::RenderOutlines()
|
||||
void TerrainRenderer::RenderOutlines(bool filtered)
|
||||
{
|
||||
ENSURE(m->phase == Phase_Render);
|
||||
|
||||
std::vector<CPatchRData*>& visiblePatches = filtered ? m->filteredPatches : m->visiblePatches;
|
||||
if (visiblePatches.empty())
|
||||
return;
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
for (size_t i = 0; i < m->visiblePatches.size(); ++i)
|
||||
m->visiblePatches[i]->RenderOutline();
|
||||
for (size_t i = 0; i < visiblePatches.size(); ++i)
|
||||
visiblePatches[i]->RenderOutline();
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// Render water that is part of the terrain
|
||||
void TerrainRenderer::RenderWater()
|
||||
// Scissor rectangle of water patches
|
||||
CBound TerrainRenderer::ScissorWater(const CMatrix3D &viewproj)
|
||||
{
|
||||
PROFILE( "render water" );
|
||||
CBound scissor;
|
||||
for (size_t i = 0; i < m->visiblePatches.size(); ++i)
|
||||
{
|
||||
CPatchRData* data = m->visiblePatches[i];
|
||||
const CBound& waterBounds = data->GetWaterBounds();
|
||||
if (waterBounds.IsEmpty())
|
||||
continue;
|
||||
|
||||
WaterManager* WaterMgr = g_Renderer.GetWaterManager();
|
||||
CVector4D v1 = viewproj.Transform(CVector4D(waterBounds[0].X, waterBounds[1].Y, waterBounds[0].Z, 1.0f));
|
||||
CVector4D v2 = viewproj.Transform(CVector4D(waterBounds[1].X, waterBounds[1].Y, waterBounds[0].Z, 1.0f));
|
||||
CVector4D v3 = viewproj.Transform(CVector4D(waterBounds[0].X, waterBounds[1].Y, waterBounds[1].Z, 1.0f));
|
||||
CVector4D v4 = viewproj.Transform(CVector4D(waterBounds[1].X, waterBounds[1].Y, waterBounds[1].Z, 1.0f));
|
||||
CBound screenBounds;
|
||||
#define ADDBOUND(v1, v2, v3, v4) \
|
||||
if (v1[2] >= -v1[3]) \
|
||||
screenBounds += CVector3D(v1[0], v1[1], v1[2]) * (1.0f / v1[3]); \
|
||||
else \
|
||||
{ \
|
||||
float t = v1[2] + v1[3]; \
|
||||
if (v2[2] > -v2[3]) \
|
||||
{ \
|
||||
CVector4D c2 = v1 + (v2 - v1) * (t / (t - (v2[2] + v2[3]))); \
|
||||
screenBounds += CVector3D(c2[0], c2[1], c2[2]) * (1.0f / c2[3]); \
|
||||
} \
|
||||
if (v3[2] > -v3[3]) \
|
||||
{ \
|
||||
CVector4D c3 = v1 + (v3 - v1) * (t / (t - (v3[2] + v3[3]))); \
|
||||
screenBounds += CVector3D(c3[0], c3[1], c3[2]) * (1.0f / c3[3]); \
|
||||
} \
|
||||
if (v4[2] > -v4[3]) \
|
||||
{ \
|
||||
CVector4D c4 = v1 + (v4 - v1) * (t / (t - (v4[2] + v4[3]))); \
|
||||
screenBounds += CVector3D(c4[0], c4[1], c4[2]) * (1.0f / c4[3]); \
|
||||
} \
|
||||
}
|
||||
ADDBOUND(v1, v2, v3, v4);
|
||||
ADDBOUND(v2, v1, v3, v4);
|
||||
ADDBOUND(v3, v1, v2, v4);
|
||||
ADDBOUND(v4, v1, v2, v3);
|
||||
#undef ADDBOUND
|
||||
if (screenBounds[0].X >= 1.0f || screenBounds[1].X <= -1.0f || screenBounds[0].Y >= 1.0f || screenBounds[1].Y <= -1.0f)
|
||||
continue;
|
||||
scissor += screenBounds;
|
||||
}
|
||||
return CBound(CVector3D(clamp(scissor[0].X, -1.0f, 1.0f), clamp(scissor[0].Y, -1.0f, 1.0f), -1.0f),
|
||||
CVector3D(clamp(scissor[1].X, -1.0f, 1.0f), clamp(scissor[1].Y, -1.0f, 1.0f), 1.0f));
|
||||
}
|
||||
|
||||
bool fancy = WaterMgr->WillRenderFancyWater();
|
||||
// Render fancy water
|
||||
bool TerrainRenderer::RenderFancyWater()
|
||||
{
|
||||
PROFILE("render fancy water");
|
||||
|
||||
// If we're using fancy water, make sure its shader is loaded
|
||||
if(fancy && !m->fancyWaterShader)
|
||||
if (!m->fancyWaterShader)
|
||||
{
|
||||
Handle h = ogl_program_load(g_VFS, L"shaders/water_high.xml");
|
||||
if (h < 0)
|
||||
{
|
||||
LOGERROR(L"Failed to load water shader. Falling back to non-fancy water.\n");
|
||||
g_Renderer.m_Options.m_FancyWater = false;
|
||||
fancy = false;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
m->fancyWaterShader = h;
|
||||
}
|
||||
}
|
||||
CTerrain* terrain = g_Game->GetWorld()->GetTerrain(); // TODO: stop using g_Game
|
||||
|
||||
WaterManager* WaterMgr = g_Renderer.GetWaterManager();
|
||||
CLOSTexture& losTexture = g_Renderer.GetScene().GetLOSTexture();
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
@ -538,58 +632,15 @@ void TerrainRenderer::RenderWater()
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
|
||||
double time = WaterMgr->m_WaterTexTimer;
|
||||
|
||||
double period = 1.6;
|
||||
int curTex = (int)(time*60/period) % 60;
|
||||
|
||||
if(fancy)
|
||||
{
|
||||
WaterMgr->m_NormalMap[curTex]->Bind();
|
||||
}
|
||||
else
|
||||
{
|
||||
WaterMgr->m_WaterTexture[curTex]->Bind();
|
||||
}
|
||||
WaterMgr->m_NormalMap[curTex]->Bind();
|
||||
|
||||
// Shift the texture coordinates by these amounts to make the water "flow"
|
||||
float tx = -fmod(time, 81.0)/81.0;
|
||||
float ty = -fmod(time, 34.0)/34.0;
|
||||
|
||||
if(!fancy)
|
||||
{
|
||||
// Perform the shifting by modifying the texture matrix
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
glLoadIdentity();
|
||||
glTranslatef(tx, ty, 0);
|
||||
|
||||
// Set up texture environment to multiply vertex RGB by texture RGB and use vertex alpha
|
||||
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_TEXTURE);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR_ARB);
|
||||
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_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());
|
||||
|
||||
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);
|
||||
}
|
||||
float repeatPeriod = WaterMgr->m_RepeatPeriod;
|
||||
|
||||
// Set the proper LOD bias
|
||||
glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, g_Renderer.m_Options.m_LodBias);
|
||||
@ -597,179 +648,200 @@ void TerrainRenderer::RenderWater()
|
||||
const CCamera& camera = g_Renderer.GetViewCamera();
|
||||
CVector3D camPos = camera.m_Orientation.GetTranslation();
|
||||
|
||||
GLint vertexDepth = 0; // water depth attribute, if using fancy water
|
||||
// Bind reflection and refraction textures on texture units 1 and 2
|
||||
pglActiveTextureARB(GL_TEXTURE1_ARB);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, WaterMgr->m_ReflectionTexture);
|
||||
pglActiveTextureARB(GL_TEXTURE2_ARB);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, WaterMgr->m_RefractionTexture);
|
||||
|
||||
if(fancy)
|
||||
losTexture.BindTexture(3);
|
||||
|
||||
// Bind water shader and set arguments
|
||||
ogl_program_use(m->fancyWaterShader);
|
||||
|
||||
GLint ambient = ogl_program_get_uniform_location(m->fancyWaterShader, "ambient");
|
||||
GLint sunDir = ogl_program_get_uniform_location(m->fancyWaterShader, "sunDir");
|
||||
GLint sunColor = ogl_program_get_uniform_location(m->fancyWaterShader, "sunColor");
|
||||
GLint cameraPos = ogl_program_get_uniform_location(m->fancyWaterShader, "cameraPos");
|
||||
GLint shininess = ogl_program_get_uniform_location(m->fancyWaterShader, "shininess");
|
||||
GLint specularStrength = ogl_program_get_uniform_location(m->fancyWaterShader, "specularStrength");
|
||||
GLint waviness = ogl_program_get_uniform_location(m->fancyWaterShader, "waviness");
|
||||
GLint murkiness = ogl_program_get_uniform_location(m->fancyWaterShader, "murkiness");
|
||||
GLint fullDepth = ogl_program_get_uniform_location(m->fancyWaterShader, "fullDepth");
|
||||
GLint tint = ogl_program_get_uniform_location(m->fancyWaterShader, "tint");
|
||||
GLint reflectionTint = ogl_program_get_uniform_location(m->fancyWaterShader, "reflectionTint");
|
||||
GLint reflectionTintStrength = ogl_program_get_uniform_location(m->fancyWaterShader, "reflectionTintStrength");
|
||||
GLint translation = ogl_program_get_uniform_location(m->fancyWaterShader, "translation");
|
||||
GLint repeatScale = ogl_program_get_uniform_location(m->fancyWaterShader, "repeatScale");
|
||||
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);
|
||||
pglUniform3fvARB(sunDir, 1, &lightEnv.GetSunDir().X);
|
||||
pglUniform3fvARB(sunColor, 1, &lightEnv.m_SunColor.X);
|
||||
pglUniform1fARB(shininess, WaterMgr->m_Shininess);
|
||||
pglUniform1fARB(specularStrength, WaterMgr->m_SpecularStrength);
|
||||
pglUniform1fARB(waviness, WaterMgr->m_Waviness);
|
||||
pglUniform1fARB(murkiness, WaterMgr->m_Murkiness);
|
||||
pglUniform1fARB(fullDepth, WaterMgr->m_WaterFullDepth);
|
||||
pglUniform3fvARB(tint, 1, WaterMgr->m_WaterTint.FloatArray());
|
||||
pglUniform1fARB(reflectionTintStrength, WaterMgr->m_ReflectionTintStrength);
|
||||
pglUniform3fvARB(reflectionTint, 1, WaterMgr->m_ReflectionTint.FloatArray());
|
||||
pglUniform2fARB(translation, tx, ty);
|
||||
pglUniform1fARB(repeatScale, 1.0f / repeatPeriod);
|
||||
pglUniformMatrix4fvARB(reflectionMatrix, 1, false, &WaterMgr->m_ReflectionMatrix._11);
|
||||
pglUniformMatrix4fvARB(refractionMatrix, 1, false, &WaterMgr->m_RefractionMatrix._11);
|
||||
pglUniformMatrix4fvARB(losMatrix, 1, false, losTexture.GetTextureMatrix());
|
||||
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);
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
|
||||
for (size_t i = 0; i < m->visiblePatches.size(); ++i)
|
||||
{
|
||||
// Bind reflection and refraction textures on texture units 1 and 2
|
||||
pglActiveTextureARB( GL_TEXTURE1_ARB );
|
||||
glEnable( GL_TEXTURE_2D );
|
||||
glBindTexture( GL_TEXTURE_2D, WaterMgr->m_ReflectionTexture );
|
||||
pglActiveTextureARB( GL_TEXTURE2_ARB );
|
||||
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 );
|
||||
|
||||
GLint ambient = ogl_program_get_uniform_location( m->fancyWaterShader, "ambient" );
|
||||
GLint sunDir = ogl_program_get_uniform_location( m->fancyWaterShader, "sunDir" );
|
||||
GLint sunColor = ogl_program_get_uniform_location( m->fancyWaterShader, "sunColor" );
|
||||
GLint cameraPos = ogl_program_get_uniform_location( m->fancyWaterShader, "cameraPos" );
|
||||
GLint shininess = ogl_program_get_uniform_location( m->fancyWaterShader, "shininess" );
|
||||
GLint specularStrength = ogl_program_get_uniform_location( m->fancyWaterShader, "specularStrength" );
|
||||
GLint waviness = ogl_program_get_uniform_location( m->fancyWaterShader, "waviness" );
|
||||
GLint murkiness = ogl_program_get_uniform_location( m->fancyWaterShader, "murkiness" );
|
||||
GLint fullDepth = ogl_program_get_uniform_location( m->fancyWaterShader, "fullDepth" );
|
||||
GLint tint = ogl_program_get_uniform_location( m->fancyWaterShader, "tint" );
|
||||
GLint reflectionTint = ogl_program_get_uniform_location( m->fancyWaterShader, "reflectionTint" );
|
||||
GLint reflectionTintStrength = ogl_program_get_uniform_location( m->fancyWaterShader, "reflectionTintStrength" );
|
||||
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 );
|
||||
pglUniform3fvARB( sunDir, 1, &lightEnv.GetSunDir().X );
|
||||
pglUniform3fvARB( sunColor, 1, &lightEnv.m_SunColor.X );
|
||||
pglUniform1fARB( shininess, WaterMgr->m_Shininess );
|
||||
pglUniform1fARB( specularStrength, WaterMgr->m_SpecularStrength );
|
||||
pglUniform1fARB( waviness, WaterMgr->m_Waviness );
|
||||
pglUniform1fARB( murkiness, WaterMgr->m_Murkiness );
|
||||
pglUniform1fARB( fullDepth, WaterMgr->m_WaterFullDepth );
|
||||
pglUniform3fvARB( tint, 1, WaterMgr->m_WaterTint.FloatArray() );
|
||||
pglUniform1fARB( reflectionTintStrength, WaterMgr->m_ReflectionTintStrength );
|
||||
pglUniform3fvARB( reflectionTint, 1, WaterMgr->m_ReflectionTint.FloatArray() );
|
||||
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() );
|
||||
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" );
|
||||
}
|
||||
|
||||
float repeatPeriod = (fancy ? WaterMgr->m_RepeatPeriod : 16.0f);
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
|
||||
for(size_t i=0; i<m->visiblePatches.size(); i++)
|
||||
{
|
||||
CPatch* patch = m->visiblePatches[i]->GetPatch();
|
||||
|
||||
for(ssize_t dx=0; dx<PATCH_SIZE; dx++)
|
||||
{
|
||||
for(ssize_t dz=0; dz<PATCH_SIZE; dz++)
|
||||
{
|
||||
ssize_t x = (patch->m_X*PATCH_SIZE + dx);
|
||||
ssize_t z = (patch->m_Z*PATCH_SIZE + dz);
|
||||
|
||||
// Some offsets used to go around counterclockwise while keeping code concise
|
||||
const int DX[] = {1,1,0,0};
|
||||
const int DZ[] = {0,1,1,0};
|
||||
|
||||
// is any corner of the tile below the water height? if not, no point rendering it
|
||||
bool shouldRender = false;
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
float terrainHeight = terrain->GetVertexGroundLevel(x + DX[j], z + DZ[j]);
|
||||
if (terrainHeight < WaterMgr->m_WaterHeight)
|
||||
{
|
||||
shouldRender = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!shouldRender)
|
||||
continue;
|
||||
|
||||
for (int j=0; j<4; j++)
|
||||
{
|
||||
ssize_t ix = x + DX[j];
|
||||
ssize_t iz = z + DZ[j];
|
||||
|
||||
float vertX = ix * CELL_SIZE;
|
||||
float vertZ = iz * CELL_SIZE;
|
||||
|
||||
float terrainHeight = terrain->GetVertexGroundLevel(ix, iz);
|
||||
|
||||
if (fancy)
|
||||
{
|
||||
pglVertexAttrib1fARB(vertexDepth, WaterMgr->m_WaterHeight - terrainHeight);
|
||||
pglMultiTexCoord2fARB(GL_TEXTURE0, vertX/repeatPeriod, vertZ/repeatPeriod);
|
||||
glVertex3f(vertX, WaterMgr->m_WaterHeight, vertZ);
|
||||
}
|
||||
else
|
||||
{
|
||||
float alpha = clamp( (WaterMgr->m_WaterHeight - terrainHeight) / WaterMgr->m_WaterFullDepth + WaterMgr->m_WaterAlphaOffset,
|
||||
WaterMgr->m_WaterAlphaOffset, WaterMgr->m_WaterMaxAlpha);
|
||||
|
||||
// (Crappy) fresnel effect
|
||||
CVector3D CamFaceVertex=CVector3D(vertX,WaterMgr->m_WaterHeight,vertZ)-camPos;
|
||||
CamFaceVertex.Normalize();
|
||||
float FresnelScalar = CamFaceVertex.Dot(CVector3D(0.0f, -1.0f, 0.0f));
|
||||
// Invert and set boundaries
|
||||
FresnelScalar = 1.f - (FresnelScalar * 0.6);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
} //end of x loop
|
||||
} //end of z loop
|
||||
}
|
||||
glEnd();
|
||||
|
||||
if (fancy)
|
||||
{
|
||||
// Unbind the LOS/refraction/reflection textures and the shader
|
||||
|
||||
g_Renderer.BindTexture(3, 0);
|
||||
g_Renderer.BindTexture(2, 0);
|
||||
g_Renderer.BindTexture(1, 0);
|
||||
|
||||
pglActiveTextureARB(GL_TEXTURE0_ARB);
|
||||
|
||||
ogl_program_use(0);
|
||||
CPatchRData* data = m->visiblePatches[i];
|
||||
data->RenderWater();
|
||||
}
|
||||
|
||||
if (!fancy)
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
// Unbind the LOS/refraction/reflection textures and the shader
|
||||
g_Renderer.BindTexture(3, 0);
|
||||
g_Renderer.BindTexture(2, 0);
|
||||
g_Renderer.BindTexture(1, 0);
|
||||
|
||||
pglActiveTextureARB(GL_TEXTURE0_ARB);
|
||||
|
||||
ogl_program_use(0);
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TerrainRenderer::RenderSimpleWater()
|
||||
{
|
||||
PROFILE("render simple water");
|
||||
|
||||
WaterManager* WaterMgr = g_Renderer.GetWaterManager();
|
||||
CLOSTexture& losTexture = g_Game->GetView()->GetLOSTexture();
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
|
||||
double time = WaterMgr->m_WaterTexTimer;
|
||||
double period = 1.6f;
|
||||
int curTex = (int)(time*60/period) % 60;
|
||||
|
||||
WaterMgr->m_WaterTexture[curTex]->Bind();
|
||||
|
||||
// Shift the texture coordinates by these amounts to make the water "flow"
|
||||
float tx = -fmod(time, 81.0)/81.0;
|
||||
float ty = -fmod(time, 34.0)/34.0;
|
||||
float repeatPeriod = 16.0f;
|
||||
|
||||
// Perform the shifting by using texture coordinate generation
|
||||
GLfloat texgenS0[4] = { 1/repeatPeriod, 0, 0, tx };
|
||||
GLfloat texgenT0[4] = { 0, 0, 1/repeatPeriod, ty };
|
||||
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
|
||||
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
|
||||
glTexGenfv(GL_S, GL_OBJECT_PLANE, texgenS0);
|
||||
glTexGenfv(GL_T, GL_OBJECT_PLANE, texgenT0);
|
||||
glEnable(GL_TEXTURE_GEN_S);
|
||||
glEnable(GL_TEXTURE_GEN_T);
|
||||
|
||||
// Set up texture environment to multiply vertex RGB by texture RGB and use vertex alpha
|
||||
GLfloat waterColor[4] = { WaterMgr->m_WaterColor.r, WaterMgr->m_WaterColor.g, WaterMgr->m_WaterColor.b, 1.0f };
|
||||
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, waterColor);
|
||||
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_TEXTURE);
|
||||
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_PRIMARY_COLOR_ARB);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
|
||||
|
||||
// Multiply by LOS texture
|
||||
losTexture.BindTexture(1);
|
||||
const float *losMatrix = losTexture.GetTextureMatrix();
|
||||
GLfloat texgenS1[4] = { losMatrix[0], losMatrix[4], losMatrix[8], losMatrix[12] };
|
||||
GLfloat texgenT1[4] = { losMatrix[1], losMatrix[5], losMatrix[9], losMatrix[13] };
|
||||
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
|
||||
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
|
||||
glTexGenfv(GL_S, GL_OBJECT_PLANE, texgenS1);
|
||||
glTexGenfv(GL_T, GL_OBJECT_PLANE, texgenT1);
|
||||
glEnable(GL_TEXTURE_GEN_S);
|
||||
glEnable(GL_TEXTURE_GEN_T);
|
||||
|
||||
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
|
||||
glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, g_Renderer.m_Options.m_LodBias);
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
|
||||
for (size_t i = 0; i < m->visiblePatches.size(); ++i)
|
||||
{
|
||||
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);
|
||||
CPatchRData* data = m->visiblePatches[i];
|
||||
data->RenderWater();
|
||||
}
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
g_Renderer.BindTexture(1, 0);
|
||||
|
||||
glDisable(GL_TEXTURE_GEN_S);
|
||||
glDisable(GL_TEXTURE_GEN_T);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
|
||||
pglActiveTextureARB(GL_TEXTURE0_ARB);
|
||||
|
||||
// Clean up the texture matrix and blend mode
|
||||
glDisable(GL_TEXTURE_GEN_S);
|
||||
glDisable(GL_TEXTURE_GEN_T);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// Render water that is part of the terrain
|
||||
void TerrainRenderer::RenderWater()
|
||||
{
|
||||
WaterManager* WaterMgr = g_Renderer.GetWaterManager();
|
||||
|
||||
if (!WaterMgr->WillRenderFancyWater() || !RenderFancyWater())
|
||||
RenderSimpleWater();
|
||||
}
|
||||
|
||||
void TerrainRenderer::RenderPriorities()
|
||||
{
|
||||
PROFILE("render priorities");
|
||||
|
@ -71,38 +71,52 @@ public:
|
||||
*/
|
||||
void EndFrame();
|
||||
|
||||
/**
|
||||
* CullPatches: Culls patches and decals against a frustum,
|
||||
* and stores the results in a special filtered list that
|
||||
* is used when calling render functions with @p filtered true.
|
||||
*/
|
||||
bool CullPatches(const CFrustum* frustum);
|
||||
|
||||
/**
|
||||
* RenderTerrain: Render textured terrain (including blends between
|
||||
* different terrain types).
|
||||
*
|
||||
* preconditions : PrepareForRendering must have been called this
|
||||
* frame before calling RenderTerrain.
|
||||
*
|
||||
* @param filtered If true then only render objects that passed CullPatches.
|
||||
*/
|
||||
void RenderTerrain();
|
||||
void RenderTerrain(bool filtered = false);
|
||||
|
||||
/**
|
||||
* Render textured terrain, as with RenderTerrain, but using shaders
|
||||
* instead of multitexturing.
|
||||
*
|
||||
* @param shadow A prepared shadow map, in case rendering with shadows is enabled.
|
||||
* @param filtered If true then only render objects that passed CullPatches.
|
||||
*/
|
||||
void RenderTerrainShader(ShadowMap* shadow);
|
||||
void RenderTerrainShader(ShadowMap* shadow, bool filtered = false);
|
||||
|
||||
/**
|
||||
* RenderPatches: Render all patches un-textured as polygons.
|
||||
*
|
||||
* preconditions : PrepareForRendering must have been called this
|
||||
* frame before calling RenderPatches.
|
||||
*
|
||||
* @param filtered If true then only render objects that passed CullPatches.
|
||||
*/
|
||||
void RenderPatches();
|
||||
void RenderPatches(bool filtered = false);
|
||||
|
||||
/**
|
||||
* RenderOutlines: Render the outline of patches as lines.
|
||||
*
|
||||
* preconditions : PrepareForRendering must have been called this
|
||||
* frame before calling RenderOutlines.
|
||||
*
|
||||
* @param filtered If true then only render objects that passed CullPatches.
|
||||
*/
|
||||
void RenderOutlines();
|
||||
void RenderOutlines(bool filtered = false);
|
||||
|
||||
/**
|
||||
* RenderWater: Render water for all patches that have been submitted
|
||||
@ -113,6 +127,11 @@ public:
|
||||
*/
|
||||
void RenderWater();
|
||||
|
||||
/**
|
||||
* Calculate a scissor rectangle for the visible water patches.
|
||||
*/
|
||||
CBound ScissorWater(const CMatrix3D& viewproj);
|
||||
|
||||
/**
|
||||
* Render priority text for all submitted patches, for debugging.
|
||||
*/
|
||||
@ -121,6 +140,17 @@ public:
|
||||
private:
|
||||
TerrainRendererInternals* m;
|
||||
|
||||
/**
|
||||
* RenderFancyWater: internal rendering method for fancy water.
|
||||
* Returns false if unable to render with fancy water.
|
||||
*/
|
||||
bool RenderFancyWater();
|
||||
|
||||
/**
|
||||
* RenderSimpleWater: internal rendering method for water
|
||||
*/
|
||||
void RenderSimpleWater();
|
||||
|
||||
void PrepareShader(const CShaderProgramPtr& shader, ShadowMap* shadow);
|
||||
};
|
||||
|
||||
|
@ -540,7 +540,21 @@ void SortModelRenderer::Render(const RenderModifierPtr& modifier, int flags)
|
||||
} while(!modifier->EndPass(pass++));
|
||||
}
|
||||
|
||||
void SortModelRenderer::Filter(CModelFilter& filter, int passed, int flags)
|
||||
{
|
||||
for (std::vector<SModel*>::iterator it = m->models.begin(); it != m->models.end(); ++it)
|
||||
{
|
||||
SModel* smdl = *it;
|
||||
CModel* mdl = smdl->GetModel();
|
||||
if (flags && !(mdl->GetFlags() & flags))
|
||||
continue;
|
||||
|
||||
if (filter.Filter(mdl))
|
||||
mdl->SetFlags(mdl->GetFlags() | passed);
|
||||
else
|
||||
mdl->SetFlags(mdl->GetFlags() & ~passed);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// TransparentRenderModifier implementation
|
||||
@ -555,67 +569,49 @@ TransparentRenderModifier::~TransparentRenderModifier()
|
||||
|
||||
int TransparentRenderModifier::BeginPass(int pass)
|
||||
{
|
||||
// First pass: opaque areas only.
|
||||
// Second pass: blended areas.
|
||||
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_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);
|
||||
|
||||
// just pass through texture's alpha
|
||||
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);
|
||||
|
||||
// Set the proper LOD bias
|
||||
glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, g_Renderer.m_Options.m_LodBias);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
glEnable(GL_ALPHA_TEST);
|
||||
if (pass == 0)
|
||||
{
|
||||
// First pass: Put down Z for opaque parts of the model,
|
||||
// don't touch the color buffer.
|
||||
|
||||
glDepthMask(1);
|
||||
|
||||
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_CONSTANT);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
|
||||
|
||||
// just pass through texture's alpha
|
||||
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);
|
||||
|
||||
// Set the proper LOD bias
|
||||
glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, g_Renderer.m_Options.m_LodBias);
|
||||
|
||||
glEnable(GL_ALPHA_TEST);
|
||||
glAlphaFunc(GL_GREATER,0.975f);
|
||||
|
||||
// render everything with color writes off to setup depth buffer correctly
|
||||
glColorMask(0,0,0,0);
|
||||
|
||||
return STREAM_POS|STREAM_UV0;
|
||||
glAlphaFunc(GL_GREATER, 0.9375f);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Second pass: Put down color, disable Z write
|
||||
glColorMask(1,1,1,1);
|
||||
|
||||
glAlphaFunc(GL_GREATER, 0.0f);
|
||||
glDepthFunc(GL_LESS);
|
||||
glDepthMask(0);
|
||||
|
||||
// setup texture environment to modulate diffuse color with texture color
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
|
||||
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);
|
||||
|
||||
glAlphaFunc(GL_GREATER,0);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
// Set the proper LOD bias
|
||||
glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, g_Renderer.m_Options.m_LodBias);
|
||||
|
||||
return STREAM_POS|STREAM_COLOR|STREAM_UV0;
|
||||
}
|
||||
|
||||
return STREAM_POS|STREAM_COLOR|STREAM_UV0;
|
||||
}
|
||||
|
||||
bool TransparentRenderModifier::EndPass(int pass)
|
||||
{
|
||||
if (pass == 0)
|
||||
return false; // multi-pass
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
glDisable(GL_ALPHA_TEST);
|
||||
if (pass == 0)
|
||||
return false;
|
||||
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
glDepthMask(1);
|
||||
|
||||
return true;
|
||||
@ -632,6 +628,129 @@ void TransparentRenderModifier::PrepareModel(int UNUSED(pass), CModel* UNUSED(mo
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// TransparentOpaqueRenderModifier implementation
|
||||
|
||||
TransparentOpaqueRenderModifier::TransparentOpaqueRenderModifier()
|
||||
{
|
||||
}
|
||||
|
||||
TransparentOpaqueRenderModifier::~TransparentOpaqueRenderModifier()
|
||||
{
|
||||
}
|
||||
|
||||
int TransparentOpaqueRenderModifier::BeginPass(int pass)
|
||||
{
|
||||
ENSURE(pass == 0);
|
||||
|
||||
// Put down opaque parts of the model only.
|
||||
|
||||
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_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);
|
||||
|
||||
// just pass through texture's alpha
|
||||
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);
|
||||
|
||||
// Set the proper LOD bias
|
||||
glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, g_Renderer.m_Options.m_LodBias);
|
||||
|
||||
glEnable(GL_ALPHA_TEST);
|
||||
glAlphaFunc(GL_GREATER, 0.9375f);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
return STREAM_POS|STREAM_COLOR|STREAM_UV0;
|
||||
}
|
||||
|
||||
bool TransparentOpaqueRenderModifier::EndPass(int UNUSED(pass))
|
||||
{
|
||||
glDisable(GL_ALPHA_TEST);
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TransparentOpaqueRenderModifier::PrepareTexture(int UNUSED(pass), CTexturePtr& texture)
|
||||
{
|
||||
texture->Bind(0);
|
||||
}
|
||||
|
||||
void TransparentOpaqueRenderModifier::PrepareModel(int UNUSED(pass), CModel* UNUSED(model))
|
||||
{
|
||||
// No per-model setup necessary
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// TransparentBlendRenderModifier implementation
|
||||
|
||||
TransparentBlendRenderModifier::TransparentBlendRenderModifier()
|
||||
{
|
||||
}
|
||||
|
||||
TransparentBlendRenderModifier::~TransparentBlendRenderModifier()
|
||||
{
|
||||
}
|
||||
|
||||
int TransparentBlendRenderModifier::BeginPass(int pass)
|
||||
{
|
||||
ENSURE(pass == 0);
|
||||
|
||||
// Put down blended parts of the model only.
|
||||
|
||||
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_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);
|
||||
|
||||
// just pass through texture's alpha
|
||||
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);
|
||||
|
||||
// Set the proper LOD bias
|
||||
glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, g_Renderer.m_Options.m_LodBias);
|
||||
|
||||
glEnable(GL_ALPHA_TEST);
|
||||
glAlphaFunc(GL_GREATER,0);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
glDepthFunc(GL_LESS);
|
||||
glDepthMask(0);
|
||||
|
||||
return STREAM_POS|STREAM_COLOR|STREAM_UV0;
|
||||
}
|
||||
|
||||
bool TransparentBlendRenderModifier::EndPass(int UNUSED(pass))
|
||||
{
|
||||
glDisable(GL_ALPHA_TEST);
|
||||
glDisable(GL_BLEND);
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
glDepthMask(1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TransparentBlendRenderModifier::PrepareTexture(int UNUSED(pass), CTexturePtr& texture)
|
||||
{
|
||||
texture->Bind(0);
|
||||
}
|
||||
|
||||
void TransparentBlendRenderModifier::PrepareModel(int UNUSED(pass), CModel* UNUSED(model))
|
||||
{
|
||||
// No per-model setup necessary
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// TransparentDepthShadowModifier implementation
|
||||
|
||||
|
@ -85,6 +85,7 @@ public:
|
||||
void EndFrame();
|
||||
bool HaveSubmissions();
|
||||
void Render(const RenderModifierPtr& modifier, int flags);
|
||||
void Filter(CModelFilter& filter, int passed, int flags);
|
||||
|
||||
private:
|
||||
SortModelRendererInternals* m;
|
||||
@ -106,9 +107,41 @@ public:
|
||||
bool EndPass(int pass);
|
||||
void PrepareTexture(int pass, CTexturePtr& texture);
|
||||
void PrepareModel(int pass, CModel* model);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Class TransparentOpaqueRenderModifier: Modifier for transparent models,
|
||||
* including alpha blending and lighting, Opaque pass only.
|
||||
*/
|
||||
class TransparentOpaqueRenderModifier : public RenderModifier
|
||||
{
|
||||
public:
|
||||
TransparentOpaqueRenderModifier();
|
||||
~TransparentOpaqueRenderModifier();
|
||||
|
||||
// Implementation
|
||||
int BeginPass(int pass);
|
||||
bool EndPass(int pass);
|
||||
void PrepareTexture(int pass, CTexturePtr& texture);
|
||||
void PrepareModel(int pass, CModel* model);
|
||||
};
|
||||
|
||||
/**
|
||||
* Class TransparentBlendRenderModifier: Modifier for transparent models,
|
||||
* including alpha blending and lighting. Blend pass only.
|
||||
*/
|
||||
class TransparentBlendRenderModifier : public RenderModifier
|
||||
{
|
||||
public:
|
||||
TransparentBlendRenderModifier();
|
||||
~TransparentBlendRenderModifier();
|
||||
|
||||
// Implementation
|
||||
int BeginPass(int pass);
|
||||
bool EndPass(int pass);
|
||||
void PrepareTexture(int pass, CTexturePtr& texture);
|
||||
void PrepareModel(int pass, CModel* model);
|
||||
};
|
||||
|
||||
/**
|
||||
* Class TransparentDepthShadowModifier: Use to render shadow data for
|
||||
|
Loading…
Reference in New Issue
Block a user