# Add new renderer mode based on GL_ARB_fragment_program.
Change lighting model for new maps to allow better overbrightness. Cache player colours instead of loading from scripts every time the renderer wants them. This was SVN commit r9123.
This commit is contained in:
parent
8b11b73226
commit
d295dacb9b
BIN
binaries/data/mods/public/maps/scenarios/_default.xml
(Stored with Git LFS)
BIN
binaries/data/mods/public/maps/scenarios/_default.xml
(Stored with Git LFS)
Binary file not shown.
64
binaries/data/mods/public/shaders/model_common.fp
Normal file
64
binaries/data/mods/public/shaders/model_common.fp
Normal file
@ -0,0 +1,64 @@
|
||||
!!ARBfp1.0
|
||||
#ifdef USE_FP_SHADOW
|
||||
OPTION ARB_fragment_program_shadow;
|
||||
#endif
|
||||
|
||||
#ifdef LIGHTING_MODEL_old
|
||||
#define CLAMP_LIGHTING
|
||||
#endif
|
||||
|
||||
#ifdef CLAMP_LIGHTING // for compat with old scenarios that expect clamped lighting
|
||||
#define MAD_MAYBE_SAT MAD_SAT
|
||||
#else
|
||||
#define MAD_MAYBE_SAT MAD
|
||||
#endif
|
||||
|
||||
#ifdef USE_OBJECTCOLOR
|
||||
PARAM objectColor = program.local[0];
|
||||
#endif
|
||||
|
||||
PARAM ambient = program.local[1];
|
||||
|
||||
TEMP tex;
|
||||
TEMP temp;
|
||||
TEMP diffuse;
|
||||
TEMP color;
|
||||
|
||||
TEX tex, fragment.texcoord[0], texture[0], 2D;
|
||||
#ifdef USE_TRANSPARENT
|
||||
MOV result.color.a, tex;
|
||||
#endif
|
||||
|
||||
// Apply player-coloring based on texture alpha
|
||||
#ifdef USE_OBJECTCOLOR
|
||||
LRP temp.rgb, objectColor, 1.0, tex.a;
|
||||
MUL color.rgb, tex, temp;
|
||||
#else
|
||||
MOV color.rgb, tex;
|
||||
#endif
|
||||
|
||||
// Compute color = texture * (ambient + diffuse*shadow)
|
||||
// (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;
|
||||
#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;
|
||||
MUL color.rgb, color, temp;
|
||||
#else
|
||||
MAD_MAYBE_SAT temp.rgb, fragment.color, 2.0, ambient;
|
||||
MUL color.rgb, color, temp;
|
||||
#endif
|
||||
|
||||
// Multiply everything by the LOS texture
|
||||
TEX tex.a, fragment.texcoord[2], texture[2], 2D;
|
||||
MUL color.rgb, color, tex.a;
|
||||
|
||||
MOV result.color.rgb, color;
|
||||
|
||||
END
|
54
binaries/data/mods/public/shaders/model_common.vp
Normal file
54
binaries/data/mods/public/shaders/model_common.vp
Normal file
@ -0,0 +1,54 @@
|
||||
!!ARBvp1.0
|
||||
PARAM sunDir = program.local[0];
|
||||
PARAM sunColor = program.local[1];
|
||||
PARAM losTransform = program.local[2];
|
||||
PARAM shadowTransform[4] = { program.local[3..6] };
|
||||
TEMP lighting;
|
||||
|
||||
//// Compute position and normal:
|
||||
|
||||
#ifdef USE_INSTANCING
|
||||
PARAM instancingTransform[4] = { program.local[7..10] };
|
||||
TEMP position;
|
||||
TEMP normal;
|
||||
DP4 position.x, instancingTransform[0], vertex.position;
|
||||
DP4 position.y, instancingTransform[1], vertex.position;
|
||||
DP4 position.z, instancingTransform[2], vertex.position;
|
||||
MOV position.w, 1.0;
|
||||
DP3 normal.x, instancingTransform[0], vertex.normal;
|
||||
DP3 normal.y, instancingTransform[1], vertex.normal;
|
||||
DP3 normal.z, instancingTransform[2], vertex.normal;
|
||||
#else
|
||||
ATTRIB position = vertex.position;
|
||||
ATTRIB normal = vertex.normal;
|
||||
#endif
|
||||
|
||||
DP4 result.position.x, state.matrix.mvp.row[0], position;
|
||||
DP4 result.position.y, state.matrix.mvp.row[1], position;
|
||||
DP4 result.position.z, state.matrix.mvp.row[2], position;
|
||||
DP4 result.position.w, state.matrix.mvp.row[3], position;
|
||||
|
||||
//// Compute lighting:
|
||||
|
||||
// Diffuse factor
|
||||
DP3 lighting, normal, -sunDir;
|
||||
MAX lighting, 0.0, lighting;
|
||||
// Scale diffuse to allow overbrightness (since result.color will be clamped to [0, 1])
|
||||
MUL lighting, lighting, 0.5;
|
||||
// Apply light colour
|
||||
MUL result.color, lighting, sunColor;
|
||||
|
||||
//// Texture coordinates:
|
||||
|
||||
MOV result.texcoord[0], vertex.texcoord[0];
|
||||
|
||||
#ifdef USE_SHADOW
|
||||
DP4 result.texcoord[1].x, shadowTransform[0], position;
|
||||
DP4 result.texcoord[1].y, shadowTransform[1], position;
|
||||
DP4 result.texcoord[1].z, shadowTransform[2], position;
|
||||
DP4 result.texcoord[1].w, shadowTransform[3], position;
|
||||
#endif
|
||||
|
||||
MAD result.texcoord[2], position.xzzz, losTransform.x, losTransform.y;
|
||||
|
||||
END
|
23
binaries/data/mods/public/shaders/model_common.xml
Normal file
23
binaries/data/mods/public/shaders/model_common.xml
Normal file
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<program type="arb">
|
||||
|
||||
<vertex file="model_common.vp">
|
||||
<uniform name="sunDir" loc="0" type="vec3"/>
|
||||
<uniform name="sunColor" loc="1" type="vec3"/>
|
||||
<uniform name="losTransform" loc="2" type="vec2"/>
|
||||
<uniform name="shadowTransform" loc="3" type="mat4"/>
|
||||
<stream name="pos"/>
|
||||
<stream name="normal"/>
|
||||
<stream name="uv0"/>
|
||||
</vertex>
|
||||
|
||||
<fragment file="model_common.fp">
|
||||
<uniform name="baseTex" loc="0" type="sampler2D"/>
|
||||
<uniform name="shadowTex" loc="1" type="sampler2DShadow"/>
|
||||
<uniform name="losTex" loc="2" type="sampler2D"/>
|
||||
|
||||
<uniform name="objectColor" loc="0" type="vec3"/>
|
||||
<uniform name="ambient" loc="1" type="vec3"/>
|
||||
</fragment>
|
||||
|
||||
</program>
|
@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<program type="arb">
|
||||
|
||||
<define name="USE_INSTANCING" value="1"/>
|
||||
|
||||
<vertex file="model_common.vp">
|
||||
<uniform name="sunDir" loc="0" type="vec3"/>
|
||||
<uniform name="sunColor" loc="1" type="vec3"/>
|
||||
<uniform name="losTransform" loc="2" type="vec2"/>
|
||||
<uniform name="shadowTransform" loc="3" type="mat4"/>
|
||||
<uniform name="instancingTransform" loc="7" type="mat4"/>
|
||||
<stream name="pos"/>
|
||||
<stream name="normal"/>
|
||||
<stream name="uv0"/>
|
||||
</vertex>
|
||||
|
||||
<fragment file="model_common.fp">
|
||||
<uniform name="baseTex" loc="0" type="sampler2D"/>
|
||||
<uniform name="shadowTex" loc="1" type="sampler2DShadow"/>
|
||||
<uniform name="losTex" loc="2" type="sampler2D"/>
|
||||
|
||||
<uniform name="objectColor" loc="0" type="vec3"/>
|
||||
<uniform name="ambient" loc="1" type="vec3"/>
|
||||
</fragment>
|
||||
|
||||
</program>
|
76
binaries/data/mods/public/shaders/program.rng
Normal file
76
binaries/data/mods/public/shaders/program.rng
Normal file
@ -0,0 +1,76 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
|
||||
<start>
|
||||
<element name="program">
|
||||
<attribute name="type">
|
||||
<choice>
|
||||
<value>arb</value>
|
||||
<value>glsl</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
|
||||
<zeroOrMore>
|
||||
<element name="define">
|
||||
<attribute name="name"><text/></attribute>
|
||||
<attribute name="value"><text/></attribute>
|
||||
</element>
|
||||
</zeroOrMore>
|
||||
|
||||
<element name="vertex">
|
||||
<attribute name="file"><text/></attribute>
|
||||
<zeroOrMore>
|
||||
<choice>
|
||||
<ref name="uniformContent"/>
|
||||
<element name="attrib">
|
||||
<attribute name="name"><text/></attribute>
|
||||
<attribute name="loc"><data type="integer"/></attribute>
|
||||
</element>
|
||||
<element name="stream">
|
||||
<attribute name="name">
|
||||
<choice>
|
||||
<value>pos</value>
|
||||
<value>normal</value>
|
||||
<value>color</value>
|
||||
<value>uv0</value>
|
||||
<value>uv1</value>
|
||||
<value>uv2</value>
|
||||
<value>uv3</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</element>
|
||||
</choice>
|
||||
</zeroOrMore>
|
||||
</element>
|
||||
|
||||
<element name="fragment">
|
||||
<attribute name="file"><text/></attribute>
|
||||
<zeroOrMore>
|
||||
<ref name="uniformContent"/>
|
||||
</zeroOrMore>
|
||||
</element>
|
||||
|
||||
</element>
|
||||
</start>
|
||||
|
||||
<define name="uniformContent">
|
||||
<element name="uniform">
|
||||
<attribute name="name"><text/></attribute>
|
||||
<attribute name="loc"><data type="integer"/></attribute>
|
||||
<attribute name="type">
|
||||
<choice>
|
||||
<value>float</value>
|
||||
<value>vec2</value>
|
||||
<value>vec3</value>
|
||||
<value>vec4</value>
|
||||
<value>mat2</value>
|
||||
<value>mat3</value>
|
||||
<value>mat4</value>
|
||||
<value>sampler2D</value>
|
||||
<value>sampler2DShadow</value>
|
||||
<value>samplerCube</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</element>
|
||||
</define>
|
||||
|
||||
</grammar>
|
3
binaries/data/mods/public/shaders/solid.fp
Normal file
3
binaries/data/mods/public/shaders/solid.fp
Normal file
@ -0,0 +1,3 @@
|
||||
!!ARBfp1.0
|
||||
MOV result.color, fragment.color;
|
||||
END
|
20
binaries/data/mods/public/shaders/solid.vp
Normal file
20
binaries/data/mods/public/shaders/solid.vp
Normal file
@ -0,0 +1,20 @@
|
||||
!!ARBvp1.0
|
||||
#ifdef USE_INSTANCING
|
||||
PARAM instancingTransform[4] = { program.local[0..3] };
|
||||
TEMP position;
|
||||
DP4 position.x, instancingTransform[0], vertex.position;
|
||||
DP4 position.y, instancingTransform[1], vertex.position;
|
||||
DP4 position.z, instancingTransform[2], vertex.position;
|
||||
MOV position.w, 1.0;
|
||||
#else
|
||||
ATTRIB position = vertex.position;
|
||||
#endif
|
||||
|
||||
DP4 result.position.x, state.matrix.mvp.row[0], position;
|
||||
DP4 result.position.y, state.matrix.mvp.row[1], position;
|
||||
DP4 result.position.z, state.matrix.mvp.row[2], position;
|
||||
DP4 result.position.w, state.matrix.mvp.row[3], position;
|
||||
|
||||
MOV result.color, vertex.color;
|
||||
|
||||
END
|
10
binaries/data/mods/public/shaders/solid.xml
Normal file
10
binaries/data/mods/public/shaders/solid.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<program type="arb">
|
||||
|
||||
<vertex file="solid.vp">
|
||||
<stream name="pos"/>
|
||||
</vertex>
|
||||
|
||||
<fragment file="solid.fp"/>
|
||||
|
||||
</program>
|
3
binaries/data/mods/public/shaders/solid_color.fp
Normal file
3
binaries/data/mods/public/shaders/solid_color.fp
Normal file
@ -0,0 +1,3 @@
|
||||
!!ARBfp1.0
|
||||
MOV result.color, program.local[0];
|
||||
END
|
13
binaries/data/mods/public/shaders/solid_instancing.xml
Normal file
13
binaries/data/mods/public/shaders/solid_instancing.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<program type="arb">
|
||||
|
||||
<define name="USE_INSTANCING" value="1"/>
|
||||
|
||||
<vertex file="solid.vp">
|
||||
<uniform name="instancingTransform" loc="0" type="mat4"/>
|
||||
<stream name="pos"/>
|
||||
</vertex>
|
||||
|
||||
<fragment file="solid.fp"/>
|
||||
|
||||
</program>
|
12
binaries/data/mods/public/shaders/solid_player.xml
Normal file
12
binaries/data/mods/public/shaders/solid_player.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<program type="arb">
|
||||
|
||||
<vertex file="solid.vp">
|
||||
<stream name="pos"/>
|
||||
</vertex>
|
||||
|
||||
<fragment file="solid_color.fp">
|
||||
<uniform name="playerColor" loc="0" type="vec3"/>
|
||||
</fragment>
|
||||
|
||||
</program>
|
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<program type="arb">
|
||||
|
||||
<define name="USE_INSTANCING" value="1"/>
|
||||
|
||||
<vertex file="solid.vp">
|
||||
<uniform name="instancingTransform" loc="0" type="mat4"/>
|
||||
<stream name="pos"/>
|
||||
</vertex>
|
||||
|
||||
<fragment file="solid_color.fp">
|
||||
<uniform name="playerColor" loc="0" type="vec3"/>
|
||||
</fragment>
|
||||
|
||||
</program>
|
3
binaries/data/mods/public/shaders/solid_tex.fp
Normal file
3
binaries/data/mods/public/shaders/solid_tex.fp
Normal file
@ -0,0 +1,3 @@
|
||||
!!ARBfp1.0
|
||||
TEX result.color, fragment.texcoord[0], texture[0], 2D;
|
||||
END
|
18
binaries/data/mods/public/shaders/solid_tex.vp
Normal file
18
binaries/data/mods/public/shaders/solid_tex.vp
Normal file
@ -0,0 +1,18 @@
|
||||
!!ARBvp1.0
|
||||
#ifdef USE_INSTANCING
|
||||
PARAM instancingTransform[4] = { program.local[0..3] };
|
||||
TEMP position;
|
||||
DP4 position.x, instancingTransform[0], vertex.position;
|
||||
DP4 position.y, instancingTransform[1], vertex.position;
|
||||
DP4 position.z, instancingTransform[2], vertex.position;
|
||||
MOV position.w, 1.0;
|
||||
#else
|
||||
ATTRIB position = vertex.position;
|
||||
#endif
|
||||
|
||||
DP4 result.position.x, state.matrix.mvp.row[0], position;
|
||||
DP4 result.position.y, state.matrix.mvp.row[1], position;
|
||||
DP4 result.position.z, state.matrix.mvp.row[2], position;
|
||||
DP4 result.position.w, state.matrix.mvp.row[3], position;
|
||||
MOV result.texcoord[0], vertex.texcoord[0];
|
||||
END
|
13
binaries/data/mods/public/shaders/solid_tex.xml
Normal file
13
binaries/data/mods/public/shaders/solid_tex.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<program type="arb">
|
||||
|
||||
<vertex file="solid_tex.vp">
|
||||
<stream name="pos"/>
|
||||
<stream name="uv0"/>
|
||||
</vertex>
|
||||
|
||||
<fragment file="solid_tex.fp">
|
||||
<uniform name="baseTex" loc="0" type="sampler2D"/>
|
||||
</fragment>
|
||||
|
||||
</program>
|
18
binaries/data/mods/public/shaders/terrain_base.xml
Normal file
18
binaries/data/mods/public/shaders/terrain_base.xml
Normal file
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<program type="arb">
|
||||
|
||||
<vertex file="terrain_common.vp">
|
||||
<uniform name="sunColor" loc="0" type="vec3"/>
|
||||
<uniform name="losTransform" loc="1" type="vec2"/>
|
||||
<uniform name="shadowTransform" loc="2" type="mat4"/>
|
||||
</vertex>
|
||||
|
||||
<fragment file="terrain_common.fp">
|
||||
<uniform name="baseTex" loc="0" type="sampler2D"/>
|
||||
<uniform name="shadowTex" loc="2" type="sampler2DShadow"/>
|
||||
<uniform name="losTex" loc="3" type="sampler2D"/>
|
||||
|
||||
<uniform name="ambient" loc="0" type="vec3"/>
|
||||
</fragment>
|
||||
|
||||
</program>
|
21
binaries/data/mods/public/shaders/terrain_blend.xml
Normal file
21
binaries/data/mods/public/shaders/terrain_blend.xml
Normal file
@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<program type="arb">
|
||||
|
||||
<define name="BLEND" value="1"/>
|
||||
|
||||
<vertex file="terrain_common.vp">
|
||||
<uniform name="sunColor" loc="0" type="vec3"/>
|
||||
<uniform name="losTransform" loc="1" type="vec2"/>
|
||||
<uniform name="shadowTransform" loc="2" type="mat4"/>
|
||||
</vertex>
|
||||
|
||||
<fragment file="terrain_common.fp">
|
||||
<uniform name="baseTex" loc="0" type="sampler2D"/>
|
||||
<uniform name="blendTex" loc="1" type="sampler2D"/>
|
||||
<uniform name="shadowTex" loc="2" type="sampler2DShadow"/>
|
||||
<uniform name="losTex" loc="3" type="sampler2D"/>
|
||||
|
||||
<uniform name="ambient" loc="0" type="vec3"/>
|
||||
</fragment>
|
||||
|
||||
</program>
|
62
binaries/data/mods/public/shaders/terrain_common.fp
Normal file
62
binaries/data/mods/public/shaders/terrain_common.fp
Normal file
@ -0,0 +1,62 @@
|
||||
!!ARBfp1.0
|
||||
#ifdef USE_FP_SHADOW
|
||||
OPTION ARB_fragment_program_shadow;
|
||||
#endif
|
||||
|
||||
#ifdef LIGHTING_MODEL_old
|
||||
#define CLAMP_LIGHTING
|
||||
#endif
|
||||
|
||||
#ifdef CLAMP_LIGHTING // for compat with old scenarios that expect clamped lighting
|
||||
#define MAD_MAYBE_SAT MAD_SAT
|
||||
#else
|
||||
#define MAD_MAYBE_SAT MAD
|
||||
#endif
|
||||
|
||||
PARAM ambient = program.local[0];
|
||||
|
||||
TEMP tex;
|
||||
TEMP temp;
|
||||
TEMP diffuse;
|
||||
TEMP color;
|
||||
|
||||
#ifdef BLEND
|
||||
// Use alpha from blend texture
|
||||
// TODO: maybe we should invert the texture instead of doing SUB here?
|
||||
TEX tex.a, fragment.texcoord[1], texture[1], 2D;
|
||||
SUB result.color.a, 1.0, tex.a;
|
||||
#endif
|
||||
|
||||
// Load diffuse colour
|
||||
TEX color, fragment.texcoord[0], texture[0], 2D;
|
||||
|
||||
#ifdef DECAL
|
||||
// Use alpha from main texture
|
||||
MOV result.color.a, color;
|
||||
#endif
|
||||
|
||||
// Compute color = texture * (ambient + diffuse*shadow)
|
||||
// (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;
|
||||
#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;
|
||||
MUL color.rgb, color, temp;
|
||||
#else
|
||||
MAD_MAYBE_SAT temp.rgb, fragment.color, 2.0, ambient;
|
||||
MUL color.rgb, color, temp;
|
||||
#endif
|
||||
|
||||
// Multiply everything by the LOS texture
|
||||
TEX tex.a, fragment.texcoord[3], texture[3], 2D;
|
||||
MUL color.rgb, color, tex.a;
|
||||
|
||||
MOV result.color.rgb, color;
|
||||
|
||||
END
|
42
binaries/data/mods/public/shaders/terrain_common.vp
Normal file
42
binaries/data/mods/public/shaders/terrain_common.vp
Normal file
@ -0,0 +1,42 @@
|
||||
!!ARBvp1.0
|
||||
PARAM sunColor = program.local[0];
|
||||
PARAM losTransform = program.local[1];
|
||||
PARAM shadowTransform[4] = { program.local[2..5] };
|
||||
|
||||
TEMP lighting;
|
||||
|
||||
//// Compute position and normal:
|
||||
|
||||
ATTRIB position = vertex.position;
|
||||
|
||||
DP4 result.position.x, state.matrix.mvp.row[0], position;
|
||||
DP4 result.position.y, state.matrix.mvp.row[1], position;
|
||||
DP4 result.position.z, state.matrix.mvp.row[2], position;
|
||||
DP4 result.position.w, state.matrix.mvp.row[3], position;
|
||||
|
||||
//// Compute lighting:
|
||||
|
||||
// Diffuse factor is precomputed in vertex attribute
|
||||
// Scale diffuse to allow overbrightness (since result.color will be clamped to [0, 1])
|
||||
MUL lighting, vertex.color, 0.5;
|
||||
// Apply light colour
|
||||
MUL result.color, lighting, sunColor;
|
||||
|
||||
//// Texture coordinates:
|
||||
|
||||
MOV result.texcoord[0], vertex.texcoord[0];
|
||||
|
||||
#ifdef BLEND
|
||||
MOV result.texcoord[1], vertex.texcoord[1];
|
||||
#endif
|
||||
|
||||
#ifdef USE_SHADOW
|
||||
DP4 result.texcoord[2].x, shadowTransform[0], position;
|
||||
DP4 result.texcoord[2].y, shadowTransform[1], position;
|
||||
DP4 result.texcoord[2].z, shadowTransform[2], position;
|
||||
DP4 result.texcoord[2].w, shadowTransform[3], position;
|
||||
#endif
|
||||
|
||||
MAD result.texcoord[3], position.xzzz, losTransform.x, losTransform.y;
|
||||
|
||||
END
|
20
binaries/data/mods/public/shaders/terrain_decal.xml
Normal file
20
binaries/data/mods/public/shaders/terrain_decal.xml
Normal file
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<program type="arb">
|
||||
|
||||
<define name="DECAL" value="1"/>
|
||||
|
||||
<vertex file="terrain_common.vp">
|
||||
<uniform name="sunColor" loc="0" type="vec3"/>
|
||||
<uniform name="losTransform" loc="1" type="vec2"/>
|
||||
<uniform name="shadowTransform" loc="2" type="mat4"/>
|
||||
</vertex>
|
||||
|
||||
<fragment file="terrain_common.fp">
|
||||
<uniform name="baseTex" loc="0" type="sampler2D"/>
|
||||
<uniform name="shadowTex" loc="2" type="sampler2DShadow"/>
|
||||
<uniform name="losTex" loc="3" type="sampler2D"/>
|
||||
|
||||
<uniform name="ambient" loc="0" type="vec3"/>
|
||||
</fragment>
|
||||
|
||||
</program>
|
@ -442,7 +442,7 @@ void CGameView::RegisterInit()
|
||||
}
|
||||
|
||||
|
||||
void CGameView::Render()
|
||||
void CGameView::BeginFrame()
|
||||
{
|
||||
if (m->LockCullCamera == false)
|
||||
{
|
||||
@ -462,6 +462,11 @@ void CGameView::Render()
|
||||
|
||||
CheckLightEnv();
|
||||
|
||||
m->Game->CachePlayerColours();
|
||||
}
|
||||
|
||||
void CGameView::Render()
|
||||
{
|
||||
g_Renderer.RenderScene(this);
|
||||
}
|
||||
|
||||
@ -548,6 +553,9 @@ void CGameView::CheckLightEnv()
|
||||
if (m->CachedLightEnv == g_LightEnv)
|
||||
return;
|
||||
|
||||
if (m->CachedLightEnv.GetLightingModel() != g_LightEnv.GetLightingModel())
|
||||
g_Renderer.MakeShadersDirty();
|
||||
|
||||
m->CachedLightEnv = g_LightEnv;
|
||||
CTerrain* pTerrain = m->Game->GetWorld()->GetTerrain();
|
||||
|
||||
|
@ -78,7 +78,7 @@ public:
|
||||
// *presentation*
|
||||
void Update(float DeltaTime);
|
||||
|
||||
// Render: Render the World
|
||||
void BeginFrame();
|
||||
void Render();
|
||||
|
||||
InReaction HandleEvent(const SDL_Event_* ev);
|
||||
|
@ -77,6 +77,17 @@ void CLOSTexture::BindTexture(int unit)
|
||||
g_Renderer.BindTexture(unit, m_Texture);
|
||||
}
|
||||
|
||||
GLuint CLOSTexture::GetTexture()
|
||||
{
|
||||
if (m_Dirty)
|
||||
{
|
||||
RecomputeTexture(0);
|
||||
m_Dirty = false;
|
||||
}
|
||||
|
||||
return m_Texture;
|
||||
}
|
||||
|
||||
const float* CLOSTexture::GetTextureMatrix()
|
||||
{
|
||||
debug_assert(!m_Dirty);
|
||||
|
@ -47,6 +47,13 @@ public:
|
||||
*/
|
||||
void BindTexture(int unit);
|
||||
|
||||
/**
|
||||
* Recomputes the LOS texture if necessary, and returns the texture handle.
|
||||
* Also potentially switches the current active texture unit, and enables texturing on it.
|
||||
* The texture is in 8-bit ALPHA format.
|
||||
*/
|
||||
GLuint GetTexture();
|
||||
|
||||
/**
|
||||
* Returns a matrix to map (x,y,z) world coordinates onto (u,v) LOS texture
|
||||
* coordinates, in the form expected by glLoadMatrixf.
|
||||
|
@ -30,6 +30,7 @@ CLightEnv::CLightEnv()
|
||||
: m_Elevation(DEGTORAD(45)),
|
||||
m_Rotation(DEGTORAD(315)),
|
||||
m_TerrainShadowTransparency(0.0),
|
||||
m_LightingModel("standard"),
|
||||
m_SunColor(1.5, 1.5, 1.5),
|
||||
m_TerrainAmbientColor(0x50/255.f, 0x60/255.f, 0x85/255.f),
|
||||
m_UnitsAmbientColor(0x80/255.f, 0x80/255.f, 0x80/255.f)
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
/* Copyright (C) 2011 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -22,7 +22,8 @@
|
||||
#ifndef INCLUDED_LIGHTENV
|
||||
#define INCLUDED_LIGHTENV
|
||||
|
||||
#include "Color.h"
|
||||
#include "graphics/Color.h"
|
||||
#include "maths/MathUtil.h"
|
||||
#include "maths/Vector3D.h"
|
||||
|
||||
class CMapWriter;
|
||||
@ -56,11 +57,18 @@ private:
|
||||
* m_TerrainShadowTransparency: Fraction of diffuse light that reaches shadowed terrain.
|
||||
* A value of 0.0 means shadowed polygons get only ambient light, while a value of 1.0
|
||||
* means shadows don't have any effect at all.
|
||||
* TODO: probably delete this, since it's never used and always set to 0.0.
|
||||
*/
|
||||
float m_TerrainShadowTransparency;
|
||||
|
||||
CVector3D m_SunDir;
|
||||
|
||||
/**
|
||||
* A string that shaders use to determine what lighting model to implement.
|
||||
* Current recognised values are "old" and "standard".
|
||||
*/
|
||||
std::string m_LightingModel;
|
||||
|
||||
public:
|
||||
RGBColor m_SunColor;
|
||||
RGBColor m_TerrainAmbientColor;
|
||||
@ -73,12 +81,15 @@ public:
|
||||
float GetRotation() const { return m_Rotation; }
|
||||
const CVector3D& GetSunDir() const { return m_SunDir; }
|
||||
float GetTerrainShadowTransparency() const { return m_TerrainShadowTransparency; }
|
||||
const std::string& GetLightingModel() const { return m_LightingModel; }
|
||||
|
||||
void SetElevation(float f);
|
||||
void SetRotation(float f);
|
||||
|
||||
void SetTerrainShadowTransparency(float f);
|
||||
|
||||
void SetLightingModel(const std::string& model) { m_LightingModel = model; }
|
||||
|
||||
/**
|
||||
* EvaluateTerrain: Calculate brightness of a point of the terrain with the given normal
|
||||
* vector.
|
||||
@ -130,12 +141,37 @@ public:
|
||||
color = CVector3D(0,0,0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the diffuse sun lighting.
|
||||
* If @p includeSunColor is set, the return value includes the sun color.
|
||||
* (If sun overbrightness is enabled, this might result in clamping).
|
||||
* Otherwise it returns a factor that the sun color should be multiplied by.
|
||||
*/
|
||||
SColor4ub EvaluateDiffuse(const CVector3D& normal, bool includeSunColor) const
|
||||
{
|
||||
float dot = -normal.Dot(m_SunDir);
|
||||
|
||||
if (dot <= 0)
|
||||
return SColor4ub(0, 0, 0, 255);
|
||||
|
||||
if (includeSunColor)
|
||||
{
|
||||
return ConvertRGBColorTo4ub(m_SunColor * dot);
|
||||
}
|
||||
else
|
||||
{
|
||||
int c = clamp((int)(dot * 255), 0, 255);
|
||||
return SColor4ub(c, c, c, 255);
|
||||
}
|
||||
}
|
||||
|
||||
// Comparison operators
|
||||
bool operator==(const CLightEnv& o) const
|
||||
{
|
||||
return m_Elevation == o.m_Elevation &&
|
||||
m_Rotation == o.m_Rotation &&
|
||||
m_TerrainShadowTransparency == o.m_TerrainShadowTransparency &&
|
||||
m_LightingModel == o.m_LightingModel &&
|
||||
m_SunColor == o.m_SunColor &&
|
||||
m_TerrainAmbientColor == o.m_TerrainAmbientColor &&
|
||||
m_UnitsAmbientColor == o.m_UnitsAmbientColor;
|
||||
|
@ -51,6 +51,9 @@ CMapReader::CMapReader()
|
||||
: xml_reader(0), m_PatchesPerSide(0)
|
||||
{
|
||||
cur_terrain_tex = 0; // important - resets generator state
|
||||
|
||||
// Maps that don't override the default probably want the old lighting model
|
||||
m_LightEnv.SetLightingModel("old");
|
||||
}
|
||||
|
||||
// LoadMap: try to load the map from given file; reinitialise the scene to new data if successful
|
||||
@ -538,6 +541,7 @@ void CXMLReader::ReadEnvironment(XMBElement parent)
|
||||
{
|
||||
#define EL(x) int el_##x = xmb_file.GetElementID(#x)
|
||||
#define AT(x) int at_##x = xmb_file.GetAttributeID(#x)
|
||||
EL(lightingmodel);
|
||||
EL(skyset);
|
||||
EL(suncolour);
|
||||
EL(sunelevation);
|
||||
@ -566,7 +570,11 @@ void CXMLReader::ReadEnvironment(XMBElement parent)
|
||||
|
||||
XMBAttributeList attrs = element.GetAttributes();
|
||||
|
||||
if (element_name == el_skyset)
|
||||
if (element_name == el_lightingmodel)
|
||||
{
|
||||
m_MapReader.m_LightEnv.SetLightingModel(element.GetText());
|
||||
}
|
||||
else if (element_name == el_skyset)
|
||||
{
|
||||
if (m_MapReader.pSkyMan)
|
||||
m_MapReader.pSkyMan->SetSkySet(element.GetText().FromUTF8());
|
||||
@ -1213,6 +1221,8 @@ int CMapReader::ParseEnvironment()
|
||||
return 0;
|
||||
}
|
||||
|
||||
m_LightEnv.SetLightingModel("standard");
|
||||
|
||||
std::wstring skySet;
|
||||
GET_ENVIRONMENT_PROPERTY(envObj.get(), SkySet, skySet)
|
||||
pSkyMan->SetSkySet(skySet);
|
||||
|
@ -189,6 +189,7 @@ void CMapWriter::WriteXML(const VfsPath& filename,
|
||||
{
|
||||
XML_Element("Environment");
|
||||
|
||||
XML_Setting("LightingModel", pLightEnv->GetLightingModel());
|
||||
XML_Setting("SkySet", pSkyMan->GetSkySet());
|
||||
{
|
||||
XML_Element("SunColour");
|
||||
|
@ -87,9 +87,6 @@ SMaterialColor CMaterial::GetObjectColor()
|
||||
if (m_UseTextureColor)
|
||||
return m_TextureColor;
|
||||
|
||||
debug_assert(m_UsePlayerColor);
|
||||
// this should never be called unless IsPlayer returned true
|
||||
|
||||
return GetPlayerColor();
|
||||
}
|
||||
|
||||
|
@ -19,29 +19,12 @@
|
||||
#define INCLUDED_MATERIAL
|
||||
|
||||
#include "ps/CStr.h"
|
||||
#include "ps/Overlay.h"
|
||||
#include "simulation2/helpers/Player.h"
|
||||
|
||||
// FIXME: This material system is almost entirely unused and probably broken
|
||||
|
||||
struct CColor;
|
||||
|
||||
struct SMaterialColor
|
||||
{
|
||||
public:
|
||||
float r;
|
||||
float g;
|
||||
float b;
|
||||
float a;
|
||||
|
||||
SMaterialColor() : r(0.0f), g(0.0f), b(0.0f), a(1.0f) {}
|
||||
SMaterialColor(float _r, float _g, float _b, float _a)
|
||||
{
|
||||
r = _r;
|
||||
g = _g;
|
||||
b = _b;
|
||||
a = _a;
|
||||
}
|
||||
};
|
||||
typedef CColor SMaterialColor;
|
||||
|
||||
class CMaterial
|
||||
{
|
||||
|
210
source/graphics/ShaderManager.cpp
Normal file
210
source/graphics/ShaderManager.cpp
Normal file
@ -0,0 +1,210 @@
|
||||
/* Copyright (C) 2011 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "ShaderManager.h"
|
||||
|
||||
#include "lib/timer.h"
|
||||
#include "lib/utf8.h"
|
||||
#include "ps/CLogger.h"
|
||||
#include "ps/Filesystem.h"
|
||||
#include "ps/XML/Xeromyces.h"
|
||||
#include "ps/XML/XMLWriter.h"
|
||||
#include "renderer/Renderer.h"
|
||||
|
||||
TIMER_ADD_CLIENT(tc_ShaderValidation);
|
||||
|
||||
CShaderManager::CShaderManager()
|
||||
{
|
||||
#if USE_SHADER_XML_VALIDATION
|
||||
{
|
||||
TIMER_ACCRUE(tc_ShaderValidation);
|
||||
CVFSFile grammar;
|
||||
if (grammar.Load(g_VFS, L"shaders/program.rng") != PSRETURN_OK)
|
||||
LOGERROR(L"Failed to read grammar shaders/program.rng");
|
||||
else
|
||||
{
|
||||
if (!m_Validator.LoadGrammar(grammar.GetAsString()))
|
||||
LOGERROR(L"Failed to load grammar shaders/program.rng");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Allow hotloading of textures
|
||||
RegisterFileReloadFunc(ReloadChangedFileCB, this);
|
||||
}
|
||||
|
||||
CShaderManager::~CShaderManager()
|
||||
{
|
||||
UnregisterFileReloadFunc(ReloadChangedFileCB, this);
|
||||
}
|
||||
|
||||
CShaderProgramPtr CShaderManager::LoadProgram(const char* name, const std::map<CStr, CStr>& defines)
|
||||
{
|
||||
CacheKey key = { name, defines };
|
||||
std::map<CacheKey, CShaderProgramPtr>::iterator it = m_Cache.find(key);
|
||||
if (it != m_Cache.end())
|
||||
return it->second;
|
||||
|
||||
CShaderProgramPtr program;
|
||||
if (NewProgram(name, defines, program) != PSRETURN_OK)
|
||||
{
|
||||
LOGERROR(L"Failed to load shader '%hs'", name);
|
||||
program = CShaderProgramPtr();
|
||||
}
|
||||
|
||||
m_Cache[key] = program;
|
||||
return program;
|
||||
}
|
||||
|
||||
bool CShaderManager::NewProgram(const char* name, const std::map<CStr, CStr>& baseDefines, CShaderProgramPtr& program)
|
||||
{
|
||||
VfsPath xmlFilename = L"shaders/" + wstring_from_utf8(name) + L".xml";
|
||||
|
||||
CXeromyces XeroFile;
|
||||
PSRETURN ret = XeroFile.Load(g_VFS, xmlFilename);
|
||||
if (ret != PSRETURN_OK)
|
||||
return false;
|
||||
|
||||
#if USE_SHADER_XML_VALIDATION
|
||||
{
|
||||
TIMER_ACCRUE(tc_ShaderValidation);
|
||||
|
||||
// Serialize the XMB data and pass it to the validator
|
||||
XML_Start();
|
||||
XML_SetPrettyPrint(false);
|
||||
XML_WriteXMB(XeroFile);
|
||||
bool ok = m_Validator.ValidateEncoded(wstring_from_utf8(name), XML_GetOutput());
|
||||
if (!ok)
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Define all the elements and attributes used in the XML file
|
||||
#define EL(x) int el_##x = XeroFile.GetElementID(#x)
|
||||
#define AT(x) int at_##x = XeroFile.GetAttributeID(#x)
|
||||
EL(vertex);
|
||||
EL(fragment);
|
||||
EL(define);
|
||||
EL(uniform);
|
||||
EL(attrib);
|
||||
EL(stream);
|
||||
AT(type);
|
||||
AT(file);
|
||||
AT(name);
|
||||
AT(value);
|
||||
AT(loc);
|
||||
#undef AT
|
||||
#undef EL
|
||||
|
||||
XMBElement Root = XeroFile.GetRoot();
|
||||
|
||||
bool isGLSL = (Root.GetAttributes().GetNamedItem(at_type) == "glsl");
|
||||
VfsPath vertexFile;
|
||||
VfsPath fragmentFile;
|
||||
std::map<CStr, CStr> defines = baseDefines;
|
||||
std::map<CStr, int> vertexUniforms;
|
||||
std::map<CStr, int> fragmentUniforms;
|
||||
int streamFlags = 0;
|
||||
|
||||
XERO_ITER_EL(Root, Child)
|
||||
{
|
||||
if (Child.GetNodeName() == el_define)
|
||||
{
|
||||
defines[Child.GetAttributes().GetNamedItem(at_name)] = Child.GetAttributes().GetNamedItem(at_value);
|
||||
}
|
||||
else if (Child.GetNodeName() == el_vertex)
|
||||
{
|
||||
vertexFile = L"shaders/" + Child.GetAttributes().GetNamedItem(at_file).FromUTF8();
|
||||
|
||||
XERO_ITER_EL(Child, Param)
|
||||
{
|
||||
if (Param.GetNodeName() == el_uniform)
|
||||
{
|
||||
vertexUniforms[Param.GetAttributes().GetNamedItem(at_name)] = Param.GetAttributes().GetNamedItem(at_loc).ToInt();
|
||||
}
|
||||
else if (Param.GetNodeName() == el_stream)
|
||||
{
|
||||
CStr StreamName = Param.GetAttributes().GetNamedItem(at_name);
|
||||
if (StreamName == "pos")
|
||||
streamFlags |= STREAM_POS;
|
||||
else if (StreamName == "normal")
|
||||
streamFlags |= STREAM_NORMAL;
|
||||
else if (StreamName == "color")
|
||||
streamFlags |= STREAM_COLOR;
|
||||
else if (StreamName == "uv0")
|
||||
streamFlags |= STREAM_UV0;
|
||||
else if (StreamName == "uv1")
|
||||
streamFlags |= STREAM_UV1;
|
||||
else if (StreamName == "uv2")
|
||||
streamFlags |= STREAM_UV2;
|
||||
else if (StreamName == "uv3")
|
||||
streamFlags |= STREAM_UV3;
|
||||
}
|
||||
else if (Param.GetNodeName() == el_attrib)
|
||||
{
|
||||
// TODO: add support for vertex attributes
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (Child.GetNodeName() == el_fragment)
|
||||
{
|
||||
fragmentFile = L"shaders/" + Child.GetAttributes().GetNamedItem(at_file).FromUTF8();
|
||||
|
||||
XERO_ITER_EL(Child, Param)
|
||||
{
|
||||
if (Param.GetNodeName() == el_uniform)
|
||||
fragmentUniforms[Param.GetAttributes().GetNamedItem(at_name)] = Param.GetAttributes().GetNamedItem(at_loc).ToInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: add GLSL support
|
||||
debug_assert(!isGLSL);
|
||||
|
||||
program = CShaderProgramPtr(CShaderProgram::ConstructARB(vertexFile, fragmentFile, defines, vertexUniforms, fragmentUniforms, streamFlags));
|
||||
program->Reload();
|
||||
|
||||
// m_HotloadFiles[xmlFilename].insert(program); // TODO: should reload somehow when the XML changes
|
||||
m_HotloadFiles[vertexFile].insert(program);
|
||||
m_HotloadFiles[fragmentFile].insert(program);
|
||||
|
||||
return PSRETURN_OK;
|
||||
}
|
||||
|
||||
/*static*/ LibError CShaderManager::ReloadChangedFileCB(void* param, const VfsPath& path)
|
||||
{
|
||||
return static_cast<CShaderManager*>(param)->ReloadChangedFile(path);
|
||||
}
|
||||
|
||||
LibError CShaderManager::ReloadChangedFile(const VfsPath& path)
|
||||
{
|
||||
// Find all shaders using this file
|
||||
HotloadFilesMap::iterator files = m_HotloadFiles.find(path);
|
||||
if (files != m_HotloadFiles.end())
|
||||
{
|
||||
// Reload all shaders using this file
|
||||
for (std::set<boost::weak_ptr<CShaderProgram> >::iterator it = files->second.begin(); it != files->second.end(); ++it)
|
||||
{
|
||||
if (shared_ptr<CShaderProgram> program = it->lock())
|
||||
program->Reload();
|
||||
}
|
||||
}
|
||||
|
||||
return INFO::OK;
|
||||
}
|
79
source/graphics/ShaderManager.h
Normal file
79
source/graphics/ShaderManager.h
Normal file
@ -0,0 +1,79 @@
|
||||
/* Copyright (C) 2011 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_SHADERMANAGER
|
||||
#define INCLUDED_SHADERMANAGER
|
||||
|
||||
#define USE_SHADER_XML_VALIDATION 1
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/weak_ptr.hpp>
|
||||
|
||||
#include "graphics/ShaderProgram.h"
|
||||
|
||||
#if USE_SHADER_XML_VALIDATION
|
||||
# include "ps/XML/RelaxNG.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Shader manager: loads and caches shader programs.
|
||||
*/
|
||||
class CShaderManager
|
||||
{
|
||||
public:
|
||||
CShaderManager();
|
||||
~CShaderManager();
|
||||
|
||||
/**
|
||||
* Load a shader program.
|
||||
* @param name name of shader XML specification (file is loaded from shaders/${name}.xml)
|
||||
* @param defines key/value set of preprocessor definitions
|
||||
* @return loaded program, or null pointer on error
|
||||
*/
|
||||
CShaderProgramPtr LoadProgram(const char* name, const std::map<CStr, CStr>& defines);
|
||||
|
||||
private:
|
||||
bool NewProgram(const char* name, const std::map<CStr, CStr>& defines, CShaderProgramPtr& program);
|
||||
|
||||
static LibError ReloadChangedFileCB(void* param, const VfsPath& path);
|
||||
LibError ReloadChangedFile(const VfsPath& path);
|
||||
|
||||
struct CacheKey
|
||||
{
|
||||
std::string name;
|
||||
std::map<CStr, CStr> defines;
|
||||
|
||||
bool operator<(const CacheKey& k) const
|
||||
{
|
||||
if (name < k.name) return true;
|
||||
if (k.name < name) return false;
|
||||
return defines < k.defines;
|
||||
}
|
||||
};
|
||||
|
||||
std::map<CacheKey, CShaderProgramPtr> m_Cache;
|
||||
|
||||
// Store the set of shaders that need to be reloaded when the given file is modified
|
||||
typedef boost::unordered_map<VfsPath, std::set<boost::weak_ptr<CShaderProgram> > > HotloadFilesMap;
|
||||
HotloadFilesMap m_HotloadFiles;
|
||||
|
||||
#if USE_SHADER_XML_VALIDATION
|
||||
RelaxNGValidator m_Validator;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // INCLUDED_SHADERMANAGER
|
313
source/graphics/ShaderProgram.cpp
Normal file
313
source/graphics/ShaderProgram.cpp
Normal file
@ -0,0 +1,313 @@
|
||||
/* Copyright (C) 2011 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "ShaderProgram.h"
|
||||
|
||||
#include "lib/res/graphics/ogl_tex.h"
|
||||
#include "maths/Matrix3D.h"
|
||||
#include "maths/Vector3D.h"
|
||||
#include "ps/CLogger.h"
|
||||
#include "ps/Filesystem.h"
|
||||
#include "ps/Overlay.h"
|
||||
#include "ps/Preprocessor.h"
|
||||
|
||||
class CShaderProgramARB : public CShaderProgram
|
||||
{
|
||||
public:
|
||||
CShaderProgramARB(const VfsPath& vertexFile, const VfsPath& fragmentFile,
|
||||
const std::map<CStr, CStr>& defines,
|
||||
const std::map<CStr, int>& vertexIndexes, const std::map<CStr, int>& fragmentIndexes,
|
||||
int streamflags) :
|
||||
CShaderProgram(streamflags),
|
||||
m_VertexFile(vertexFile), m_FragmentFile(fragmentFile),
|
||||
m_Defines(defines),
|
||||
m_VertexIndexes(vertexIndexes), m_FragmentIndexes(fragmentIndexes)
|
||||
{
|
||||
pglGenProgramsARB(1, &m_VertexProgram);
|
||||
pglGenProgramsARB(1, &m_FragmentProgram);
|
||||
}
|
||||
|
||||
~CShaderProgramARB()
|
||||
{
|
||||
Unload();
|
||||
|
||||
pglDeleteProgramsARB(1, &m_VertexProgram);
|
||||
pglDeleteProgramsARB(1, &m_FragmentProgram);
|
||||
}
|
||||
|
||||
CStr Preprocess(CPreprocessor& preprocessor, const CStr& input)
|
||||
{
|
||||
size_t len = 0;
|
||||
char* output = preprocessor.Parse(input.c_str(), input.size(), len);
|
||||
|
||||
if (!output)
|
||||
{
|
||||
LOGERROR(L"Shader preprocessing failed");
|
||||
return "";
|
||||
}
|
||||
|
||||
CStr ret(output, len);
|
||||
|
||||
// Free output if it's not inside the source string
|
||||
if (!(output >= input.c_str() && output < input.c_str() + input.size()))
|
||||
free(output);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Compile(GLuint target, const char* targetName, GLuint program, const VfsPath& file, const CStr& code)
|
||||
{
|
||||
ogl_WarnIfError();
|
||||
|
||||
pglBindProgramARB(target, program);
|
||||
|
||||
ogl_WarnIfError();
|
||||
|
||||
pglProgramStringARB(target, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)code.length(), code.c_str());
|
||||
|
||||
if (ogl_SquelchError(GL_INVALID_OPERATION))
|
||||
{
|
||||
GLint errPos = 0;
|
||||
glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errPos);
|
||||
int errLine = std::count(code.begin(), code.begin() + errPos + 1, '\n') + 1;
|
||||
char* errStr = (char*)glGetString(GL_PROGRAM_ERROR_STRING_ARB);
|
||||
LOGERROR(L"Failed to compile %hs program '%ls' (line %d):\n%hs", targetName, file.string().c_str(), errLine, errStr);
|
||||
return false;
|
||||
}
|
||||
|
||||
pglBindProgramARB(target, 0);
|
||||
|
||||
ogl_WarnIfError();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void Reload()
|
||||
{
|
||||
Unload();
|
||||
|
||||
CVFSFile vertexFile;
|
||||
if (vertexFile.Load(g_VFS, m_VertexFile) != PSRETURN_OK)
|
||||
return;
|
||||
|
||||
CVFSFile fragmentFile;
|
||||
if (fragmentFile.Load(g_VFS, m_FragmentFile) != PSRETURN_OK)
|
||||
return;
|
||||
|
||||
CPreprocessor preprocessor;
|
||||
for (std::map<CStr, CStr>::iterator it = m_Defines.begin(); it != m_Defines.end(); ++it)
|
||||
preprocessor.Define(it->first.c_str(), it->second.c_str());
|
||||
|
||||
CStr vertexCode = Preprocess(preprocessor, vertexFile.GetAsString());
|
||||
CStr fragmentCode = Preprocess(preprocessor, fragmentFile.GetAsString());
|
||||
|
||||
// printf(">>>\n%s<<<\n", vertexCode.c_str());
|
||||
// printf(">>>\n%s<<<\n", fragmentCode.c_str());
|
||||
|
||||
if (!Compile(GL_VERTEX_PROGRAM_ARB, "vertex", m_VertexProgram, m_VertexFile, vertexCode))
|
||||
return;
|
||||
|
||||
if (!Compile(GL_FRAGMENT_PROGRAM_ARB, "fragment", m_FragmentProgram, m_FragmentFile, fragmentCode))
|
||||
return;
|
||||
|
||||
m_IsValid = true;
|
||||
}
|
||||
|
||||
void Unload()
|
||||
{
|
||||
m_IsValid = false;
|
||||
}
|
||||
|
||||
virtual void Bind()
|
||||
{
|
||||
glEnable(GL_VERTEX_PROGRAM_ARB);
|
||||
glEnable(GL_FRAGMENT_PROGRAM_ARB);
|
||||
pglBindProgramARB(GL_VERTEX_PROGRAM_ARB, m_VertexProgram);
|
||||
pglBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_FragmentProgram);
|
||||
}
|
||||
|
||||
virtual void Unbind()
|
||||
{
|
||||
glDisable(GL_VERTEX_PROGRAM_ARB);
|
||||
glDisable(GL_FRAGMENT_PROGRAM_ARB);
|
||||
pglBindProgramARB(GL_VERTEX_PROGRAM_ARB, 0);
|
||||
pglBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0);
|
||||
|
||||
// TODO: should unbind textures, probably
|
||||
}
|
||||
|
||||
int GetUniformVertexIndex(uniform_id_t id)
|
||||
{
|
||||
std::map<CStr, int>::iterator it = m_VertexIndexes.find(id);
|
||||
if (it == m_VertexIndexes.end())
|
||||
return -1;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
int GetUniformFragmentIndex(uniform_id_t id)
|
||||
{
|
||||
std::map<CStr, int>::iterator it = m_FragmentIndexes.find(id);
|
||||
if (it == m_FragmentIndexes.end())
|
||||
return -1;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
virtual bool HasTexture(texture_id_t id)
|
||||
{
|
||||
if (GetUniformFragmentIndex(id) != -1)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void BindTexture(texture_id_t id, Handle tex)
|
||||
{
|
||||
int index = GetUniformFragmentIndex(id);
|
||||
if (index != -1)
|
||||
ogl_tex_bind(tex, index);
|
||||
}
|
||||
|
||||
virtual void BindTexture(texture_id_t id, GLuint tex)
|
||||
{
|
||||
int index = GetUniformFragmentIndex(id);
|
||||
if (index != -1)
|
||||
{
|
||||
pglActiveTextureARB((int)(GL_TEXTURE0+index));
|
||||
glBindTexture(GL_TEXTURE_2D, tex);
|
||||
}
|
||||
}
|
||||
|
||||
virtual Binding GetUniformBinding(uniform_id_t id)
|
||||
{
|
||||
return Binding(GetUniformVertexIndex(id), GetUniformFragmentIndex(id));
|
||||
}
|
||||
|
||||
virtual void Uniform(uniform_id_t id, int v)
|
||||
{
|
||||
Uniform(Binding(GetUniformVertexIndex(id), GetUniformFragmentIndex(id)), (float)v, (float)v, (float)v, (float)v);
|
||||
}
|
||||
|
||||
virtual void Uniform(Binding id, int v)
|
||||
{
|
||||
Uniform(id, (float)v, (float)v, (float)v, (float)v);
|
||||
}
|
||||
|
||||
virtual void Uniform(uniform_id_t id, float v)
|
||||
{
|
||||
Uniform(Binding(GetUniformVertexIndex(id), GetUniformFragmentIndex(id)), v, v, v, v);
|
||||
}
|
||||
|
||||
virtual void Uniform(Binding id, float v)
|
||||
{
|
||||
Uniform(id, v, v, v, v);
|
||||
}
|
||||
|
||||
virtual void Uniform(uniform_id_t id, float v0, float v1, float v2, float v3)
|
||||
{
|
||||
Uniform(Binding(GetUniformVertexIndex(id), GetUniformFragmentIndex(id)), v0, v1, v2, v3);
|
||||
}
|
||||
|
||||
virtual void Uniform(Binding id, float v0, float v1, float v2, float v3)
|
||||
{
|
||||
if (id.vertex != -1)
|
||||
pglProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, (GLuint)id.vertex, v0, v1, v2, v3);
|
||||
|
||||
if (id.fragment != -1)
|
||||
pglProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, (GLuint)id.fragment, v0, v1, v2, v3);
|
||||
}
|
||||
|
||||
virtual void Uniform(uniform_id_t id, const CVector3D& v)
|
||||
{
|
||||
Uniform(Binding(GetUniformVertexIndex(id), GetUniformFragmentIndex(id)), v.X, v.Y, v.Z, 0.0f);
|
||||
}
|
||||
|
||||
virtual void Uniform(Binding id, const CVector3D& v)
|
||||
{
|
||||
Uniform(id, v.X, v.Y, v.Z, 0.0f);
|
||||
}
|
||||
|
||||
virtual void Uniform(uniform_id_t id, const CColor& v)
|
||||
{
|
||||
Uniform(Binding(GetUniformVertexIndex(id), GetUniformFragmentIndex(id)), v.r, v.g, v.b, v.a);
|
||||
}
|
||||
|
||||
virtual void Uniform(Binding id, const CColor& v)
|
||||
{
|
||||
Uniform(id, v.r, v.g, v.b, v.a);
|
||||
}
|
||||
|
||||
virtual void Uniform(uniform_id_t id, const CMatrix3D& v)
|
||||
{
|
||||
Uniform(Binding(GetUniformVertexIndex(id), GetUniformFragmentIndex(id)), v);
|
||||
}
|
||||
|
||||
virtual void Uniform(Binding id, const CMatrix3D& v)
|
||||
{
|
||||
if (id.vertex != -1)
|
||||
{
|
||||
pglProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, (GLuint)id.vertex+0, v._11, v._12, v._13, v._14);
|
||||
pglProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, (GLuint)id.vertex+1, v._21, v._22, v._23, v._24);
|
||||
pglProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, (GLuint)id.vertex+2, v._31, v._32, v._33, v._34);
|
||||
pglProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, (GLuint)id.vertex+3, v._41, v._42, v._43, v._44);
|
||||
}
|
||||
|
||||
if (id.fragment != -1)
|
||||
{
|
||||
pglProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, (GLuint)id.fragment+0, v._11, v._12, v._13, v._14);
|
||||
pglProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, (GLuint)id.fragment+1, v._21, v._22, v._23, v._24);
|
||||
pglProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, (GLuint)id.fragment+2, v._31, v._32, v._33, v._34);
|
||||
pglProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, (GLuint)id.fragment+3, v._41, v._42, v._43, v._44);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
VfsPath m_VertexFile;
|
||||
VfsPath m_FragmentFile;
|
||||
std::map<CStr, CStr> m_Defines;
|
||||
|
||||
GLuint m_VertexProgram;
|
||||
GLuint m_FragmentProgram;
|
||||
|
||||
std::map<CStr, int> m_VertexIndexes;
|
||||
std::map<CStr, int> m_FragmentIndexes;
|
||||
};
|
||||
|
||||
|
||||
|
||||
CShaderProgram::CShaderProgram(int streamflags)
|
||||
: m_IsValid(false), m_StreamFlags(streamflags)
|
||||
{
|
||||
}
|
||||
|
||||
/*static*/ CShaderProgram* CShaderProgram::ConstructARB(const VfsPath& vertexFile, const VfsPath& fragmentFile,
|
||||
const std::map<CStr, CStr>& defines,
|
||||
const std::map<CStr, int>& vertexIndexes, const std::map<CStr, int>& fragmentIndexes,
|
||||
int streamflags)
|
||||
{
|
||||
return new CShaderProgramARB(vertexFile, fragmentFile, defines, vertexIndexes, fragmentIndexes, streamflags);
|
||||
}
|
||||
|
||||
bool CShaderProgram::IsValid() const
|
||||
{
|
||||
return m_IsValid;
|
||||
}
|
||||
|
||||
int CShaderProgram::GetStreamFlags() const
|
||||
{
|
||||
return m_StreamFlags;
|
||||
}
|
140
source/graphics/ShaderProgram.h
Normal file
140
source/graphics/ShaderProgram.h
Normal file
@ -0,0 +1,140 @@
|
||||
/* Copyright (C) 2011 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_SHADERPROGRAM
|
||||
#define INCLUDED_SHADERPROGRAM
|
||||
|
||||
#include "lib/ogl.h"
|
||||
#include "lib/file/vfs/vfs_path.h"
|
||||
#include "lib/res/handle.h"
|
||||
#include "ps/CStr.h"
|
||||
|
||||
class CColor;
|
||||
class CMatrix3D;
|
||||
class CVector3D;
|
||||
|
||||
/**
|
||||
* A compiled vertex+fragment shader program.
|
||||
* The implementation may use GL_ARB_{vertex,fragment}_program (assembly syntax)
|
||||
* or GL_ARB_{vertex,fragment}_shader (GLSL); the difference is hidden from the caller.
|
||||
*
|
||||
* Texture/uniform IDs are typically strings, corresponding to the names defined
|
||||
* in the shader .xml file. Alternatively (and more efficiently, if used extremely
|
||||
* frequently), call GetUniformBinding and pass its return value as the ID.
|
||||
* Setting uniforms that the shader .xml doesn't support is harmless.
|
||||
*/
|
||||
class CShaderProgram
|
||||
{
|
||||
NONCOPYABLE(CShaderProgram);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Construct based on ARB vertex/fragment program files.
|
||||
*/
|
||||
static CShaderProgram* ConstructARB(const VfsPath& vertexFile, const VfsPath& fragmentFile,
|
||||
const std::map<CStr, CStr>& defines,
|
||||
const std::map<CStr, int>& vertexIndexes, const std::map<CStr, int>& fragmentIndexes,
|
||||
int streamflags);
|
||||
|
||||
typedef const char* attrib_id_t;
|
||||
typedef const char* texture_id_t;
|
||||
typedef const char* uniform_id_t;
|
||||
|
||||
/**
|
||||
* Represents a uniform attribute binding.
|
||||
*/
|
||||
struct Binding
|
||||
{
|
||||
friend class CShaderProgramARB;
|
||||
private:
|
||||
Binding(int v, int f) : vertex(v), fragment(f) { }
|
||||
i16 vertex;
|
||||
i16 fragment;
|
||||
public:
|
||||
Binding() : vertex(-1), fragment(-1) { }
|
||||
|
||||
/**
|
||||
* Returns whether this uniform attribute is active in the shader.
|
||||
* If not then there's no point calling Uniform() to set its value.
|
||||
*/
|
||||
bool Active() { return vertex != -1 || fragment != -1; }
|
||||
};
|
||||
|
||||
virtual ~CShaderProgram() { }
|
||||
|
||||
virtual void Reload() = 0;
|
||||
|
||||
/**
|
||||
* Returns whether this shader was successfully loaded.
|
||||
*/
|
||||
bool IsValid() const;
|
||||
|
||||
/**
|
||||
* Binds the shader into the GL context. Call this before calling Uniform()
|
||||
* or trying to render with it.
|
||||
*/
|
||||
virtual void Bind() = 0;
|
||||
|
||||
/**
|
||||
* Unbinds the shader from the GL context. Call this after rendering with it.
|
||||
*/
|
||||
virtual void Unbind() = 0;
|
||||
|
||||
/**
|
||||
* Returns bitset of STREAM_* value, indicating what vertex data streams the
|
||||
* vertex shader needs.
|
||||
*/
|
||||
int GetStreamFlags() const;
|
||||
|
||||
// TODO: implement vertex attributes
|
||||
GLuint GetAttribIndex(attrib_id_t id);
|
||||
|
||||
/**
|
||||
* Returns whether the shader needs the texture with the given name.
|
||||
*/
|
||||
virtual bool HasTexture(texture_id_t id) = 0;
|
||||
|
||||
virtual void BindTexture(texture_id_t id, Handle tex) = 0;
|
||||
|
||||
virtual void BindTexture(texture_id_t id, GLuint tex) = 0;
|
||||
|
||||
virtual Binding GetUniformBinding(uniform_id_t id) = 0;
|
||||
|
||||
virtual void Uniform(uniform_id_t id, int v) = 0;
|
||||
virtual void Uniform(uniform_id_t id, float v) = 0;
|
||||
virtual void Uniform(uniform_id_t id, float v0, float v1, float v2, float v3) = 0;
|
||||
virtual void Uniform(uniform_id_t id, const CVector3D& v) = 0;
|
||||
virtual void Uniform(uniform_id_t id, const CColor& v) = 0;
|
||||
virtual void Uniform(uniform_id_t id, const CMatrix3D& v) = 0;
|
||||
|
||||
virtual void Uniform(Binding id, int v) = 0;
|
||||
virtual void Uniform(Binding id, float v) = 0;
|
||||
virtual void Uniform(Binding id, float v0, float v1, float v2, float v3) = 0;
|
||||
virtual void Uniform(Binding id, const CVector3D& v) = 0;
|
||||
virtual void Uniform(Binding id, const CColor& v) = 0;
|
||||
virtual void Uniform(Binding id, const CMatrix3D& v) = 0;
|
||||
|
||||
protected:
|
||||
CShaderProgram(int streamflags);
|
||||
|
||||
bool m_IsValid;
|
||||
int m_StreamFlags;
|
||||
};
|
||||
|
||||
typedef shared_ptr<CShaderProgram> CShaderProgramPtr;
|
||||
|
||||
#endif // INCLUDED_SHADERPROGRAM
|
134
source/graphics/ShaderTechnique.cpp
Normal file
134
source/graphics/ShaderTechnique.cpp
Normal file
@ -0,0 +1,134 @@
|
||||
/* Copyright (C) 2011 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "ShaderTechnique.h"
|
||||
|
||||
CShaderPass::CShaderPass(const CShaderProgramPtr& shader) :
|
||||
m_Shader(shader),
|
||||
m_HasAlpha(false), m_HasBlend(false), m_HasColorMask(false), m_HasDepthMask(false)
|
||||
{
|
||||
}
|
||||
|
||||
void CShaderPass::Bind()
|
||||
{
|
||||
m_Shader->Bind();
|
||||
|
||||
if (m_HasAlpha)
|
||||
{
|
||||
glEnable(GL_ALPHA_TEST);
|
||||
glAlphaFunc(m_AlphaFunc, m_AlphaRef);
|
||||
}
|
||||
|
||||
if (m_HasBlend)
|
||||
{
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(m_BlendSrc, m_BlendDst);
|
||||
}
|
||||
|
||||
if (m_HasColorMask)
|
||||
glColorMask(m_ColorMaskR, m_ColorMaskG, m_ColorMaskB, m_ColorMaskA);
|
||||
|
||||
if (m_HasDepthMask)
|
||||
glDepthMask(m_DepthMask);
|
||||
}
|
||||
|
||||
void CShaderPass::Unbind()
|
||||
{
|
||||
m_Shader->Unbind();
|
||||
|
||||
if (m_HasAlpha)
|
||||
{
|
||||
glDisable(GL_ALPHA_TEST);
|
||||
}
|
||||
|
||||
if (m_HasBlend)
|
||||
{
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
|
||||
if (m_HasColorMask)
|
||||
glColorMask(1, 1, 1, 1);
|
||||
|
||||
if (m_HasDepthMask)
|
||||
glDepthMask(1);
|
||||
}
|
||||
|
||||
void CShaderPass::AlphaFunc(GLenum func, GLclampf ref)
|
||||
{
|
||||
m_HasAlpha = true;
|
||||
m_AlphaFunc = func;
|
||||
m_AlphaRef = ref;
|
||||
}
|
||||
|
||||
void CShaderPass::BlendFunc(GLenum src, GLenum dst)
|
||||
{
|
||||
m_HasBlend = true;
|
||||
m_BlendSrc = src;
|
||||
m_BlendDst = dst;
|
||||
}
|
||||
|
||||
void CShaderPass::ColorMask(GLboolean r, GLboolean g, GLboolean b, GLboolean a)
|
||||
{
|
||||
m_HasColorMask = true;
|
||||
m_ColorMaskR = r;
|
||||
m_ColorMaskG = g;
|
||||
m_ColorMaskB = b;
|
||||
m_ColorMaskA = a;
|
||||
}
|
||||
|
||||
void CShaderPass::DepthMask(GLboolean mask)
|
||||
{
|
||||
m_HasDepthMask = true;
|
||||
m_DepthMask = mask;
|
||||
}
|
||||
|
||||
|
||||
CShaderTechnique::CShaderTechnique(const CShaderPass& pass)
|
||||
{
|
||||
m_Passes.push_back(pass);
|
||||
}
|
||||
|
||||
void CShaderTechnique::AddPass(const CShaderPass& pass)
|
||||
{
|
||||
m_Passes.push_back(pass);
|
||||
}
|
||||
|
||||
int CShaderTechnique::GetNumPasses()
|
||||
{
|
||||
return m_Passes.size();
|
||||
}
|
||||
|
||||
void CShaderTechnique::BeginPass(int pass)
|
||||
{
|
||||
debug_assert(0 <= pass && pass < (int)m_Passes.size());
|
||||
m_Passes[pass].Bind();
|
||||
}
|
||||
|
||||
void CShaderTechnique::EndPass(int pass)
|
||||
{
|
||||
debug_assert(0 <= pass && pass < (int)m_Passes.size());
|
||||
m_Passes[pass].Unbind();
|
||||
}
|
||||
|
||||
CShaderProgramPtr CShaderTechnique::GetShader(int pass)
|
||||
{
|
||||
debug_assert(0 <= pass && pass < (int)m_Passes.size());
|
||||
return m_Passes[pass].GetShader();
|
||||
|
||||
}
|
91
source/graphics/ShaderTechnique.h
Normal file
91
source/graphics/ShaderTechnique.h
Normal file
@ -0,0 +1,91 @@
|
||||
/* Copyright (C) 2011 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_SHADERTECHNIQUE
|
||||
#define INCLUDED_SHADERTECHNIQUE
|
||||
|
||||
#include "graphics/ShaderProgram.h"
|
||||
|
||||
/**
|
||||
* Implements a render pass consisting of various GL state changes and a shader.
|
||||
*/
|
||||
class CShaderPass
|
||||
{
|
||||
public:
|
||||
CShaderPass(const CShaderProgramPtr& shader);
|
||||
|
||||
// Add various bits of GL state to the pass:
|
||||
void AlphaFunc(GLenum func, GLclampf ref);
|
||||
void BlendFunc(GLenum src, GLenum dst);
|
||||
void ColorMask(GLboolean r, GLboolean g, GLboolean b, GLboolean a);
|
||||
void DepthMask(GLboolean mask);
|
||||
|
||||
/**
|
||||
* Set all the GL state that was previously specified on this pass.
|
||||
*/
|
||||
void Bind();
|
||||
|
||||
/**
|
||||
* Reset the GL state to the default.
|
||||
*/
|
||||
void Unbind();
|
||||
|
||||
CShaderProgramPtr GetShader() { return m_Shader; }
|
||||
|
||||
private:
|
||||
CShaderProgramPtr m_Shader;
|
||||
|
||||
bool m_HasAlpha;
|
||||
GLenum m_AlphaFunc;
|
||||
GLclampf m_AlphaRef;
|
||||
|
||||
bool m_HasBlend;
|
||||
GLenum m_BlendSrc;
|
||||
GLenum m_BlendDst;
|
||||
|
||||
bool m_HasColorMask;
|
||||
GLboolean m_ColorMaskR;
|
||||
GLboolean m_ColorMaskG;
|
||||
GLboolean m_ColorMaskB;
|
||||
GLboolean m_ColorMaskA;
|
||||
|
||||
bool m_HasDepthMask;
|
||||
GLboolean m_DepthMask;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements a render technique consisting of a sequence of passes.
|
||||
* In theory these should probably be loaded from an XML file or something,
|
||||
* but currently you have to construct them manually.
|
||||
*/
|
||||
class CShaderTechnique
|
||||
{
|
||||
public:
|
||||
CShaderTechnique(const CShaderPass& pass);
|
||||
void AddPass(const CShaderPass& pass);
|
||||
|
||||
int GetNumPasses();
|
||||
|
||||
void BeginPass(int pass);
|
||||
void EndPass(int pass);
|
||||
CShaderProgramPtr GetShader(int pass);
|
||||
|
||||
private:
|
||||
std::vector<CShaderPass> m_Passes;
|
||||
};
|
||||
|
||||
#endif // INCLUDED_SHADERTECHNIQUE
|
@ -512,6 +512,11 @@ CTexture::~CTexture()
|
||||
}
|
||||
|
||||
void CTexture::Bind(size_t unit)
|
||||
{
|
||||
ogl_tex_bind(GetHandle(), unit);
|
||||
}
|
||||
|
||||
Handle CTexture::GetHandle()
|
||||
{
|
||||
// TODO: TryLoad might call ogl_tex_upload which enables GL_TEXTURE_2D
|
||||
// on texture unit 0, regardless of 'unit', which callers might
|
||||
@ -519,7 +524,7 @@ void CTexture::Bind(size_t unit)
|
||||
|
||||
TryLoad();
|
||||
|
||||
ogl_tex_bind(m_Handle, unit);
|
||||
return m_Handle;
|
||||
}
|
||||
|
||||
bool CTexture::TryLoad()
|
||||
|
@ -225,6 +225,11 @@ public:
|
||||
*/
|
||||
void Bind(size_t unit = 0);
|
||||
|
||||
/**
|
||||
* Returns a ogl_tex handle, for later binding. See comments from Bind().
|
||||
*/
|
||||
Handle GetHandle();
|
||||
|
||||
/**
|
||||
* Attempt to load the texture data quickly, as with Bind().
|
||||
* Returns whether the texture data is currently loaded.
|
||||
|
@ -114,7 +114,25 @@ FUNC(void, glGetFramebufferAttachmentParameterivEXT, (GLenum target, GLenum atta
|
||||
FUNC(void, glGenerateMipmapEXT, (GLenum target))
|
||||
|
||||
// GL_ARB_vertex_program, GL_ARB_fragment_program
|
||||
FUNC(void, glProgramStringARB, (GLenum target, GLenum format, GLsizei len, const GLvoid *string))
|
||||
FUNC(void, glBindProgramARB, (GLenum target, GLuint program))
|
||||
FUNC(void, glDeleteProgramsARB, (GLsizei n, const GLuint *programs))
|
||||
FUNC(void, glGenProgramsARB, (GLsizei n, GLuint *programs))
|
||||
FUNC(void, glProgramEnvParameter4dARB, (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w))
|
||||
FUNC(void, glProgramEnvParameter4dvARB, (GLenum target, GLuint index, const GLdouble *params))
|
||||
FUNC(void, glProgramEnvParameter4fARB, (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w))
|
||||
FUNC(void, glProgramEnvParameter4fvARB, (GLenum target, GLuint index, const GLfloat *params))
|
||||
FUNC(void, glProgramLocalParameter4dARB, (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w))
|
||||
FUNC(void, glProgramLocalParameter4dvARB, (GLenum target, GLuint index, const GLdouble *params))
|
||||
FUNC(void, glProgramLocalParameter4fARB, (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w))
|
||||
FUNC(void, glProgramLocalParameter4fvARB, (GLenum target, GLuint index, const GLfloat *params))
|
||||
FUNC(void, glGetProgramEnvParameterdvARB, (GLenum target, GLuint index, GLdouble *params))
|
||||
FUNC(void, glGetProgramEnvParameterfvARB, (GLenum target, GLuint index, GLfloat *params))
|
||||
FUNC(void, glGetProgramLocalParameterdvARB, (GLenum target, GLuint index, GLdouble *params))
|
||||
FUNC(void, glGetProgramLocalParameterfvARB, (GLenum target, GLuint index, GLfloat *params))
|
||||
FUNC(void, glGetProgramivARB, (GLenum target, GLenum pname, GLint *params))
|
||||
FUNC(void, glGetProgramStringARB, (GLenum target, GLenum pname, GLvoid *string))
|
||||
FUNC(GLboolean, glIsProgramARB, (GLuint program))
|
||||
|
||||
// GL_ARB_shader_objects
|
||||
// (NOTE: Many of these have "Object" in their ARB names, but "Program" or "Shader" in their core names.
|
||||
|
@ -279,14 +279,35 @@ void CGame::Interpolate(float frameLength)
|
||||
m_TurnManager->Interpolate(frameLength);
|
||||
}
|
||||
|
||||
|
||||
static CColor BrokenColor(0.3f, 0.3f, 0.3f, 1.0f);
|
||||
CColor CGame::GetPlayerColour(int player) const
|
||||
|
||||
void CGame::CachePlayerColours()
|
||||
{
|
||||
m_PlayerColours.clear();
|
||||
|
||||
CmpPtr<ICmpPlayerManager> cmpPlayerManager(*m_Simulation2, SYSTEM_ENTITY);
|
||||
if (cmpPlayerManager.null())
|
||||
return BrokenColor;
|
||||
CmpPtr<ICmpPlayer> cmpPlayer(*m_Simulation2, cmpPlayerManager->GetPlayerByID(player));
|
||||
if (cmpPlayer.null())
|
||||
return BrokenColor;
|
||||
return cmpPlayer->GetColour();
|
||||
return;
|
||||
|
||||
int numPlayers = cmpPlayerManager->GetNumPlayers();
|
||||
m_PlayerColours.resize(numPlayers);
|
||||
|
||||
for (int i = 0; i < numPlayers; ++i)
|
||||
{
|
||||
CmpPtr<ICmpPlayer> cmpPlayer(*m_Simulation2, cmpPlayerManager->GetPlayerByID(i));
|
||||
if (cmpPlayer.null())
|
||||
m_PlayerColours[i] = BrokenColor;
|
||||
else
|
||||
m_PlayerColours[i] = cmpPlayer->GetColour();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CColor CGame::GetPlayerColour(int player) const
|
||||
{
|
||||
if (player < 0 || player >= (int)m_PlayerColours.size())
|
||||
return BrokenColor;
|
||||
|
||||
return m_PlayerColours[player];
|
||||
}
|
||||
|
@ -92,6 +92,14 @@ public:
|
||||
int GetPlayerID();
|
||||
void SetPlayerID(int playerID);
|
||||
|
||||
/**
|
||||
* Retrieving player colours from scripts is slow, so this updates an
|
||||
* internal cache of all players' colours.
|
||||
* Call this just before rendering, so it will always have the latest
|
||||
* colours.
|
||||
*/
|
||||
void CachePlayerColours();
|
||||
|
||||
CColor GetPlayerColour(int player) const;
|
||||
|
||||
/**
|
||||
@ -155,6 +163,8 @@ private:
|
||||
void RegisterInit(const CScriptValRooted& attribs);
|
||||
IReplayLogger* m_ReplayLogger;
|
||||
CScriptValRooted m_RegisteredAttribs;
|
||||
|
||||
std::vector<CColor> m_PlayerColours;
|
||||
};
|
||||
|
||||
extern CGame *g_Game;
|
||||
|
@ -199,15 +199,17 @@ void Render()
|
||||
GUI<CColor>::ParseString(skystring.FromUTF8(), skycol);
|
||||
g_Renderer.SetClearColor(skycol.AsSColor4ub());
|
||||
|
||||
// prepare before starting the renderer frame
|
||||
if (g_Game && g_Game->IsGameStarted())
|
||||
g_Game->GetView()->BeginFrame();
|
||||
|
||||
// start new frame
|
||||
g_Renderer.BeginFrame();
|
||||
|
||||
ogl_WarnIfError();
|
||||
|
||||
if (g_Game && g_Game->IsGameStarted())
|
||||
{
|
||||
g_Game->GetView()->Render();
|
||||
}
|
||||
|
||||
ogl_WarnIfError();
|
||||
|
||||
|
@ -58,6 +58,13 @@ bool RelaxNGValidator::LoadGrammar(const std::string& grammar)
|
||||
}
|
||||
|
||||
bool RelaxNGValidator::Validate(const std::wstring& filename, const std::wstring& document)
|
||||
{
|
||||
std::string docutf8 = "<?xml version='1.0' encoding='utf-8'?>" + utf8_from_wstring(document);
|
||||
|
||||
return ValidateEncoded(filename, docutf8);
|
||||
}
|
||||
|
||||
bool RelaxNGValidator::ValidateEncoded(const std::wstring& filename, const std::string& document)
|
||||
{
|
||||
TIMER_ACCRUE(xml_validation);
|
||||
|
||||
@ -67,9 +74,7 @@ bool RelaxNGValidator::Validate(const std::wstring& filename, const std::wstring
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string docutf8 = "<?xml version='1.0' encoding='utf-8'?>" + utf8_from_wstring(document);
|
||||
|
||||
xmlDocPtr doc = xmlReadMemory(docutf8.c_str(), (int)docutf8.size(), utf8_from_wstring(filename).c_str(), NULL, XML_PARSE_NONET);
|
||||
xmlDocPtr doc = xmlReadMemory(document.c_str(), (int)document.size(), utf8_from_wstring(filename).c_str(), NULL, XML_PARSE_NONET);
|
||||
if (doc == NULL)
|
||||
{
|
||||
LOGERROR(L"RelaxNGValidator: Failed to parse document");
|
||||
|
@ -31,6 +31,8 @@ public:
|
||||
|
||||
bool Validate(const std::wstring& filename, const std::wstring& document);
|
||||
|
||||
bool ValidateEncoded(const std::wstring& filename, const std::string& document);
|
||||
|
||||
private:
|
||||
xmlRelaxNGPtr m_Schema;
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
/* Copyright (C) 2011 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -21,6 +21,7 @@
|
||||
|
||||
#include "ps/CLogger.h"
|
||||
#include "ps/Filesystem.h"
|
||||
#include "ps/XML/Xeromyces.h"
|
||||
#include "lib/utf8.h"
|
||||
#include "lib/sysdep/cpu.h"
|
||||
#include "maths/Fixed.h"
|
||||
@ -111,6 +112,22 @@ const CStr& XMLWriter_File::GetOutput()
|
||||
}
|
||||
|
||||
|
||||
void XMLWriter_File::XMB(const XMBFile& file)
|
||||
{
|
||||
ElementXMB(file, file.GetRoot());
|
||||
}
|
||||
|
||||
void XMLWriter_File::ElementXMB(const XMBFile& file, XMBElement el)
|
||||
{
|
||||
XMLWriter_Element writer(*this, file.GetElementString(el.GetNodeName()).c_str());
|
||||
|
||||
XERO_ITER_ATTR(el, attr)
|
||||
writer.Attribute(file.GetAttributeString(attr.Name).c_str(), attr.Value);
|
||||
|
||||
XERO_ITER_EL(el, child)
|
||||
ElementXMB(file, child);
|
||||
}
|
||||
|
||||
void XMLWriter_File::Comment(const char* text)
|
||||
{
|
||||
ElementStart(NULL, "!-- ");
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
/* Copyright (C) 2011 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -91,6 +91,8 @@ end of XMLWriter.cpp.
|
||||
// Add a 'setting': <name>value</name>
|
||||
#define XML_Setting(name, value) xml_element_.Setting(name, value)
|
||||
|
||||
#define XML_WriteXMB(xero) xml_file_.XMB(xero)
|
||||
|
||||
// Create a VFS file from the XML data.
|
||||
// Returns true on success, false (and logs an error) on failure.
|
||||
#define XML_StoreVFS(vfs, pathname) xml_file_.StoreVFS(vfs, pathname)
|
||||
@ -103,6 +105,8 @@ end of XMLWriter.cpp.
|
||||
#include "ps/CStr.h"
|
||||
#include "lib/file/vfs/vfs.h"
|
||||
|
||||
class XMBElement;
|
||||
class XMBFile;
|
||||
class XMLWriter_Element;
|
||||
|
||||
class XMLWriter_File
|
||||
@ -114,6 +118,8 @@ public:
|
||||
|
||||
void Comment(const char* text);
|
||||
|
||||
void XMB(const XMBFile& file);
|
||||
|
||||
bool StoreVFS(const PIVFS& vfs, const VfsPath& pathname);
|
||||
const CStr& GetOutput();
|
||||
|
||||
@ -121,6 +127,8 @@ private:
|
||||
|
||||
friend class XMLWriter_Element;
|
||||
|
||||
void ElementXMB(const XMBFile& file, XMBElement el);
|
||||
|
||||
void ElementStart(XMLWriter_Element* element, const char* name);
|
||||
void ElementText(const char* text, bool cdata);
|
||||
template <typename T> void ElementAttribute(const char* name, const T& value, bool newelement);
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "DecalRData.h"
|
||||
|
||||
#include "graphics/Decal.h"
|
||||
#include "graphics/LightEnv.h"
|
||||
#include "graphics/Model.h"
|
||||
#include "graphics/Terrain.h"
|
||||
#include "graphics/TextureManager.h"
|
||||
@ -41,6 +42,10 @@ CDecalRData::CDecalRData(CModelDecal* decal)
|
||||
m_Position.elems = 3;
|
||||
m_Array.AddAttribute(&m_Position);
|
||||
|
||||
m_DiffuseColor.type = GL_UNSIGNED_BYTE;
|
||||
m_DiffuseColor.elems = 4;
|
||||
m_Array.AddAttribute(&m_DiffuseColor);
|
||||
|
||||
m_UV.type = GL_FLOAT;
|
||||
m_UV.elems = 2;
|
||||
m_Array.AddAttribute(&m_UV);
|
||||
@ -81,9 +86,12 @@ void CDecalRData::Render()
|
||||
|
||||
u8* indexBase = m_IndexArray.Bind();
|
||||
|
||||
// TODO: make the shading color available to shader-based rendering
|
||||
// (which uses the color array) too
|
||||
glColor3fv(m_Decal->GetShadingColor().FloatArray());
|
||||
|
||||
glVertexPointer(3, GL_FLOAT, stride, base + m_Position.offset);
|
||||
glColorPointer(4, GL_UNSIGNED_BYTE, stride, base + m_DiffuseColor.offset);
|
||||
glTexCoordPointer(2, GL_FLOAT, stride, base + m_UV.offset);
|
||||
|
||||
if (!g_Renderer.m_SkipSubmit)
|
||||
@ -118,8 +126,11 @@ void CDecalRData::BuildArrays()
|
||||
m_Array.SetNumVertices((i1-i0+1)*(j1-j0+1));
|
||||
m_Array.Layout();
|
||||
VertexArrayIterator<CVector3D> Position = m_Position.GetIterator<CVector3D>();
|
||||
VertexArrayIterator<SColor4ub> DiffuseColor = m_DiffuseColor.GetIterator<SColor4ub>();
|
||||
VertexArrayIterator<float[2]> UV = m_UV.GetIterator<float[2]>();
|
||||
|
||||
bool includeSunColor = (g_Renderer.GetRenderPath() != CRenderer::RP_SHADER);
|
||||
|
||||
for (ssize_t j = j0; j <= j1; ++j)
|
||||
{
|
||||
for (ssize_t i = i0; i <= i1; ++i)
|
||||
@ -133,6 +144,11 @@ void CDecalRData::BuildArrays()
|
||||
*Position = pos;
|
||||
++Position;
|
||||
|
||||
CVector3D normal;
|
||||
m_Decal->m_Terrain->CalcNormal(i, j, normal);
|
||||
*DiffuseColor = g_Renderer.GetLightEnv().EvaluateDiffuse(normal, includeSunColor);
|
||||
++DiffuseColor;
|
||||
|
||||
// Map from world space back into decal texture space
|
||||
CVector3D inv = m_Decal->GetInvTransform().Transform(pos);
|
||||
(*UV)[0] = 0.5f + (inv.X - decal.m_OffsetX) / decal.m_SizeX;
|
||||
|
@ -40,6 +40,7 @@ private:
|
||||
|
||||
VertexArray m_Array;
|
||||
VertexArray::Attribute m_Position;
|
||||
VertexArray::Attribute m_DiffuseColor;
|
||||
VertexArray::Attribute m_UV;
|
||||
|
||||
CModelDecal* m_Decal;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
/* Copyright (C) 2011 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -26,8 +26,6 @@
|
||||
#include "maths/Vector3D.h"
|
||||
#include "maths/Vector4D.h"
|
||||
|
||||
#include "ps/CLogger.h"
|
||||
|
||||
#include "graphics/Color.h"
|
||||
#include "graphics/LightEnv.h"
|
||||
#include "graphics/Model.h"
|
||||
@ -81,9 +79,6 @@ struct HWLModel
|
||||
|
||||
struct HWLightingModelRendererInternals
|
||||
{
|
||||
/// Currently used RenderModifier
|
||||
RenderModifierPtr modifier;
|
||||
|
||||
/// Previously prepared modeldef
|
||||
HWLModelDef* hwlmodeldef;
|
||||
|
||||
@ -331,4 +326,71 @@ void HWLightingModelRenderer::RenderModel(int streamflags, CModel* model, void*
|
||||
g_Renderer.m_Stats.m_ModelTris += numFaces;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ShaderModelRenderer implementation
|
||||
|
||||
ShaderModelRenderer::ShaderModelRenderer() :
|
||||
HWLightingModelRenderer(false)
|
||||
{
|
||||
}
|
||||
|
||||
void ShaderModelRenderer::BeginPass(int streamflags, const CMatrix3D* UNUSED(texturematrix))
|
||||
{
|
||||
debug_assert(streamflags == (streamflags & (STREAM_POS|STREAM_NORMAL|STREAM_UV0)));
|
||||
|
||||
if (streamflags & STREAM_POS)
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
if (streamflags & STREAM_NORMAL)
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
|
||||
if (streamflags & STREAM_UV0)
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
}
|
||||
|
||||
void ShaderModelRenderer::EndPass(int streamflags)
|
||||
{
|
||||
if (streamflags & STREAM_POS)
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
if (streamflags & STREAM_NORMAL)
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
|
||||
if (streamflags & STREAM_UV0)
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
|
||||
CVertexBuffer::Unbind();
|
||||
}
|
||||
|
||||
void ShaderModelRenderer::RenderModel(int streamflags, CModel* model, void* data)
|
||||
{
|
||||
CModelDefPtr mdldef = model->GetModelDef();
|
||||
HWLModel* hwlmodel = (HWLModel*)data;
|
||||
|
||||
u8* base = hwlmodel->m_Array.Bind();
|
||||
GLsizei stride = (GLsizei)hwlmodel->m_Array.GetStride();
|
||||
|
||||
u8* indexBase = m->hwlmodeldef->m_IndexArray.Bind();
|
||||
|
||||
if (streamflags & STREAM_POS)
|
||||
glVertexPointer(3, GL_FLOAT, stride, base + hwlmodel->m_Position.offset);
|
||||
|
||||
if (streamflags & STREAM_NORMAL)
|
||||
glNormalPointer(GL_FLOAT, stride, base + hwlmodel->m_Normal.offset);
|
||||
|
||||
if (streamflags & STREAM_UV0)
|
||||
glTexCoordPointer(2, GL_FLOAT, stride, base + hwlmodel->m_UV.offset);
|
||||
|
||||
// render the lot
|
||||
size_t numFaces = mdldef->GetNumFaces();
|
||||
|
||||
if (!g_Renderer.m_SkipSubmit)
|
||||
{
|
||||
pglDrawRangeElementsEXT(GL_TRIANGLES, 0, (GLuint)mdldef->GetNumVertices()-1,
|
||||
(GLsizei)numFaces*3, GL_UNSIGNED_SHORT, indexBase);
|
||||
}
|
||||
|
||||
// bump stats
|
||||
g_Renderer.m_Stats.m_DrawCalls++;
|
||||
g_Renderer.m_Stats.m_ModelTris += numFaces;
|
||||
}
|
||||
|
@ -68,9 +68,24 @@ public:
|
||||
*/
|
||||
static bool IsAvailable();
|
||||
|
||||
private:
|
||||
protected:
|
||||
HWLightingModelRendererInternals* m;
|
||||
};
|
||||
|
||||
/**
|
||||
* Render animated models using a ShaderRenderModifier.
|
||||
* This just passes through the vertex data directly; the modifier is responsible
|
||||
* for setting any shader uniforms etc.
|
||||
*/
|
||||
class ShaderModelRenderer : public HWLightingModelRenderer
|
||||
{
|
||||
public:
|
||||
ShaderModelRenderer();
|
||||
|
||||
void BeginPass(int streamflags, const CMatrix3D* texturematrix);
|
||||
void EndPass(int streamflags);
|
||||
void RenderModel(int streamflags, CModel* model, void* data);
|
||||
};
|
||||
|
||||
|
||||
#endif // INCLUDED_HWLIGHTINGMODELRENDERER
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
/* Copyright (C) 2011 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -289,4 +289,78 @@ void InstancingModelRenderer::RenderModel(int streamflags, CModel* model, void*
|
||||
g_Renderer.m_Stats.m_ModelTris += numFaces;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ShaderInstancingModelRenderer implementation
|
||||
|
||||
ShaderInstancingModelRenderer::ShaderInstancingModelRenderer() :
|
||||
InstancingModelRenderer(false)
|
||||
{
|
||||
}
|
||||
|
||||
void ShaderInstancingModelRenderer::BeginPass(int streamflags, const CMatrix3D* UNUSED(texturematrix))
|
||||
{
|
||||
debug_assert(streamflags == (streamflags & (STREAM_POS|STREAM_NORMAL|STREAM_UV0)));
|
||||
|
||||
if (streamflags & STREAM_POS)
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
if (streamflags & STREAM_NORMAL)
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
|
||||
if (streamflags & STREAM_UV0)
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
}
|
||||
|
||||
void ShaderInstancingModelRenderer::EndPass(int streamflags)
|
||||
{
|
||||
if (streamflags & STREAM_POS)
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
if (streamflags & STREAM_NORMAL)
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
|
||||
if (streamflags & STREAM_UV0)
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
|
||||
CVertexBuffer::Unbind();
|
||||
}
|
||||
|
||||
void ShaderInstancingModelRenderer::PrepareModelDef(int streamflags, const CModelDefPtr& def)
|
||||
{
|
||||
m->imodeldef = (IModelDef*)def->GetRenderData(m);
|
||||
|
||||
debug_assert(m->imodeldef);
|
||||
|
||||
u8* base = m->imodeldef->m_Array.Bind();
|
||||
GLsizei stride = (GLsizei)m->imodeldef->m_Array.GetStride();
|
||||
|
||||
m->imodeldefIndexBase = m->imodeldef->m_IndexArray.Bind();
|
||||
|
||||
if (streamflags & STREAM_POS)
|
||||
glVertexPointer(3, GL_FLOAT, stride, base + m->imodeldef->m_Position.offset);
|
||||
|
||||
if (streamflags & STREAM_NORMAL)
|
||||
glNormalPointer(GL_FLOAT, stride, base + m->imodeldef->m_Normal.offset);
|
||||
|
||||
if (streamflags & STREAM_UV0)
|
||||
glTexCoordPointer(2, GL_FLOAT, stride, base + m->imodeldef->m_UV.offset);
|
||||
}
|
||||
|
||||
void ShaderInstancingModelRenderer::RenderModel(int UNUSED(streamflags), CModel* model, void* UNUSED(data))
|
||||
{
|
||||
CModelDefPtr mdldef = model->GetModelDef();
|
||||
|
||||
// render the lot
|
||||
size_t numFaces = mdldef->GetNumFaces();
|
||||
|
||||
if (!g_Renderer.m_SkipSubmit)
|
||||
{
|
||||
pglDrawRangeElementsEXT(GL_TRIANGLES, 0, (GLuint)mdldef->GetNumVertices()-1,
|
||||
(GLsizei)numFaces*3, GL_UNSIGNED_SHORT, m->imodeldefIndexBase);
|
||||
}
|
||||
|
||||
// bump stats
|
||||
g_Renderer.m_Stats.m_DrawCalls++;
|
||||
g_Renderer.m_Stats.m_ModelTris += numFaces;
|
||||
|
||||
}
|
||||
|
@ -68,9 +68,24 @@ public:
|
||||
*/
|
||||
static bool IsAvailable();
|
||||
|
||||
private:
|
||||
protected:
|
||||
InstancingModelRendererInternals* m;
|
||||
};
|
||||
|
||||
/**
|
||||
* Render non-animated (but potentially moving) models using a ShaderRenderModifier.
|
||||
* This just passes through the vertex data directly; the modifier is responsible
|
||||
* for setting any shader uniforms etc (including the instancing transform).
|
||||
*/
|
||||
class ShaderInstancingModelRenderer : public InstancingModelRenderer
|
||||
{
|
||||
public:
|
||||
ShaderInstancingModelRenderer();
|
||||
|
||||
void BeginPass(int streamflags, const CMatrix3D* texturematrix);
|
||||
void EndPass(int streamflags);
|
||||
void PrepareModelDef(int streamflags, const CModelDefPtr& def);
|
||||
void RenderModel(int streamflags, CModel* model, void* data);
|
||||
};
|
||||
|
||||
#endif // INCLUDED_INSTANCINGMODELRENDERER
|
||||
|
@ -358,28 +358,41 @@ void CPatchRData::AddBlend(std::vector<SBlendVertex>& blendVertices, std::vector
|
||||
|
||||
SBlendVertex dst;
|
||||
|
||||
const CLightEnv& lightEnv = g_Renderer.GetLightEnv();
|
||||
CVector3D normal;
|
||||
|
||||
bool includeSunColor = (g_Renderer.GetRenderPath() != CRenderer::RP_SHADER);
|
||||
|
||||
size_t index = blendVertices.size();
|
||||
|
||||
CalculateUV(dst.m_UVs, gx, gz);
|
||||
terrain->CalcPosition(gx, gz, dst.m_Position);
|
||||
terrain->CalcNormal(gx, gz, normal);
|
||||
dst.m_DiffuseColor = lightEnv.EvaluateDiffuse(normal, includeSunColor);
|
||||
dst.m_AlphaUVs[0] = vtx[0].m_AlphaUVs[0];
|
||||
dst.m_AlphaUVs[1] = vtx[0].m_AlphaUVs[1];
|
||||
blendVertices.push_back(dst);
|
||||
|
||||
CalculateUV(dst.m_UVs, gx + 1, gz);
|
||||
terrain->CalcPosition(gx + 1, gz, dst.m_Position);
|
||||
terrain->CalcNormal(gx + 1, gz, normal);
|
||||
dst.m_DiffuseColor = lightEnv.EvaluateDiffuse(normal, includeSunColor);
|
||||
dst.m_AlphaUVs[0] = vtx[1].m_AlphaUVs[0];
|
||||
dst.m_AlphaUVs[1] = vtx[1].m_AlphaUVs[1];
|
||||
blendVertices.push_back(dst);
|
||||
|
||||
CalculateUV(dst.m_UVs, gx + 1, gz + 1);
|
||||
terrain->CalcPosition(gx + 1, gz + 1, dst.m_Position);
|
||||
terrain->CalcNormal(gx + 1, gz + 1, normal);
|
||||
dst.m_DiffuseColor = lightEnv.EvaluateDiffuse(normal, includeSunColor);
|
||||
dst.m_AlphaUVs[0] = vtx[2].m_AlphaUVs[0];
|
||||
dst.m_AlphaUVs[1] = vtx[2].m_AlphaUVs[1];
|
||||
blendVertices.push_back(dst);
|
||||
|
||||
CalculateUV(dst.m_UVs, gx, gz + 1);
|
||||
terrain->CalcPosition(gx, gz + 1, dst.m_Position);
|
||||
terrain->CalcNormal(gx, gz + 1, normal);
|
||||
dst.m_DiffuseColor = lightEnv.EvaluateDiffuse(normal, includeSunColor);
|
||||
dst.m_AlphaUVs[0] = vtx[3].m_AlphaUVs[0];
|
||||
dst.m_AlphaUVs[1] = vtx[3].m_AlphaUVs[1];
|
||||
blendVertices.push_back(dst);
|
||||
@ -516,6 +529,8 @@ void CPatchRData::BuildVertices()
|
||||
CTerrain* terrain=m_Patch->m_Parent;
|
||||
const CLightEnv& lightEnv = g_Renderer.GetLightEnv();
|
||||
|
||||
bool includeSunColor = (g_Renderer.GetRenderPath() != CRenderer::RP_SHADER);
|
||||
|
||||
// build vertices
|
||||
for (ssize_t j=0;j<vsize;j++) {
|
||||
for (ssize_t i=0;i<vsize;i++) {
|
||||
@ -533,9 +548,7 @@ void CPatchRData::BuildVertices()
|
||||
CVector3D normal;
|
||||
terrain->CalcNormal(ix,iz,normal);
|
||||
|
||||
RGBColor diffuse;
|
||||
lightEnv.EvaluateDirect(normal, diffuse);
|
||||
vertices[v].m_DiffuseColor = ConvertRGBColorTo4ub(diffuse);
|
||||
vertices[v].m_DiffuseColor = lightEnv.EvaluateDiffuse(normal, includeSunColor);
|
||||
}
|
||||
}
|
||||
|
||||
@ -836,6 +849,8 @@ void CPatchRData::RenderBlends(const std::vector<CPatchRData*>& patches)
|
||||
|
||||
glVertexPointer(3, GL_FLOAT, stride, &base->m_Position[0]);
|
||||
|
||||
glColorPointer(4, GL_UNSIGNED_BYTE, stride, &base->m_DiffuseColor);
|
||||
|
||||
pglClientActiveTextureARB(GL_TEXTURE0);
|
||||
glTexCoordPointer(2, GL_FLOAT, stride, &base->m_UVs[0]);
|
||||
|
||||
|
@ -82,12 +82,12 @@ private:
|
||||
struct SBlendVertex {
|
||||
// vertex position
|
||||
CVector3D m_Position;
|
||||
// diffuse color from sunlight
|
||||
SColor4ub m_DiffuseColor;
|
||||
// vertex uvs for base texture
|
||||
float m_UVs[2];
|
||||
// vertex uvs for alpha texture
|
||||
float m_AlphaUVs[2];
|
||||
// add some padding
|
||||
u32 m_Padding[1];
|
||||
};
|
||||
cassert(sizeof(SBlendVertex) == 32);
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
/* Copyright (C) 2011 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -24,10 +24,13 @@
|
||||
#include "lib/ogl.h"
|
||||
#include "maths/Vector3D.h"
|
||||
#include "maths/Vector4D.h"
|
||||
|
||||
#include "maths/Matrix3D.h"
|
||||
|
||||
#include "ps/Game.h"
|
||||
|
||||
#include "graphics/GameView.h"
|
||||
#include "graphics/LightEnv.h"
|
||||
#include "graphics/LOSTexture.h"
|
||||
#include "graphics/Model.h"
|
||||
#include "graphics/TextureManager.h"
|
||||
|
||||
@ -35,7 +38,7 @@
|
||||
#include "renderer/Renderer.h"
|
||||
#include "renderer/ShadowMap.h"
|
||||
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// RenderModifier implementation
|
||||
@ -299,3 +302,82 @@ void SolidColorRenderModifier::PrepareTexture(int UNUSED(pass), CTexturePtr& UNU
|
||||
void SolidColorRenderModifier::PrepareModel(int UNUSED(pass), CModel* UNUSED(model))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ShaderRenderModifier implementation
|
||||
|
||||
ShaderRenderModifier::ShaderRenderModifier(const CShaderTechnique& technique) :
|
||||
m_Technique(technique)
|
||||
{
|
||||
}
|
||||
|
||||
ShaderRenderModifier::~ShaderRenderModifier()
|
||||
{
|
||||
}
|
||||
|
||||
int ShaderRenderModifier::BeginPass(int pass)
|
||||
{
|
||||
m_Technique.BeginPass(pass);
|
||||
|
||||
CShaderProgramPtr shader = m_Technique.GetShader(pass);
|
||||
|
||||
if (GetShadowMap() && shader->HasTexture("shadowTex"))
|
||||
{
|
||||
shader->BindTexture("shadowTex", GetShadowMap()->GetTexture());
|
||||
shader->Uniform("shadowTransform", GetShadowMap()->GetTextureMatrix());
|
||||
}
|
||||
|
||||
if (GetLightEnv())
|
||||
{
|
||||
shader->Uniform("ambient", GetLightEnv()->m_UnitsAmbientColor);
|
||||
shader->Uniform("sunDir", GetLightEnv()->GetSunDir());
|
||||
shader->Uniform("sunColor", GetLightEnv()->m_SunColor);
|
||||
}
|
||||
|
||||
if (shader->HasTexture("losTex"))
|
||||
{
|
||||
CLOSTexture& los = g_Game->GetView()->GetLOSTexture();
|
||||
shader->BindTexture("losTex", los.GetTexture());
|
||||
// Don't bother sending the whole matrix, we just need two floats (scale and translation)
|
||||
shader->Uniform("losTransform", los.GetTextureMatrix()[0], los.GetTextureMatrix()[12], 0.f, 0.f);
|
||||
}
|
||||
|
||||
m_BindingInstancingTransform = shader->GetUniformBinding("instancingTransform");
|
||||
m_BindingShadingColor = shader->GetUniformBinding("shadingColor");
|
||||
m_BindingObjectColor = shader->GetUniformBinding("objectColor");
|
||||
m_BindingPlayerColor = shader->GetUniformBinding("playerColor");
|
||||
|
||||
return shader->GetStreamFlags();
|
||||
}
|
||||
|
||||
bool ShaderRenderModifier::EndPass(int pass)
|
||||
{
|
||||
m_Technique.EndPass(pass);
|
||||
|
||||
return (pass >= m_Technique.GetNumPasses()-1);
|
||||
}
|
||||
|
||||
void ShaderRenderModifier::PrepareTexture(int pass, CTexturePtr& texture)
|
||||
{
|
||||
CShaderProgramPtr shader = m_Technique.GetShader(pass);
|
||||
|
||||
shader->BindTexture("baseTex", texture->GetHandle());
|
||||
}
|
||||
|
||||
void ShaderRenderModifier::PrepareModel(int pass, CModel* model)
|
||||
{
|
||||
CShaderProgramPtr shader = m_Technique.GetShader(pass);
|
||||
|
||||
if (m_BindingInstancingTransform.Active())
|
||||
shader->Uniform(m_BindingInstancingTransform, model->GetTransform());
|
||||
|
||||
if (m_BindingShadingColor.Active())
|
||||
shader->Uniform(m_BindingShadingColor, model->GetShadingColor());
|
||||
|
||||
if (m_BindingObjectColor.Active())
|
||||
shader->Uniform(m_BindingObjectColor, model->GetMaterial().GetObjectColor());
|
||||
|
||||
if (m_BindingPlayerColor.Active())
|
||||
shader->Uniform(m_BindingPlayerColor, model->GetMaterial().GetPlayerColor());
|
||||
}
|
||||
|
@ -25,6 +25,7 @@
|
||||
#define INCLUDED_RENDERMODIFIERS
|
||||
|
||||
#include "ModelRenderer.h"
|
||||
#include "graphics/ShaderTechnique.h"
|
||||
#include "graphics/Texture.h"
|
||||
|
||||
class CLightEnv;
|
||||
@ -230,4 +231,28 @@ public:
|
||||
void PrepareModel(int pass, CModel* model);
|
||||
};
|
||||
|
||||
/**
|
||||
* A RenderModifier that can be used with any CShaderTechnique.
|
||||
* Uniforms and textures get set appropriately.
|
||||
*/
|
||||
class ShaderRenderModifier : public LitRenderModifier
|
||||
{
|
||||
public:
|
||||
ShaderRenderModifier(const CShaderTechnique& technique);
|
||||
~ShaderRenderModifier();
|
||||
|
||||
// Implementation
|
||||
int BeginPass(int pass);
|
||||
bool EndPass(int pass);
|
||||
void PrepareTexture(int pass, CTexturePtr& texture);
|
||||
void PrepareModel(int pass, CModel* model);
|
||||
|
||||
private:
|
||||
CShaderTechnique m_Technique;
|
||||
CShaderProgram::Binding m_BindingInstancingTransform;
|
||||
CShaderProgram::Binding m_BindingShadingColor;
|
||||
CShaderProgram::Binding m_BindingObjectColor;
|
||||
CShaderProgram::Binding m_BindingPlayerColor;
|
||||
};
|
||||
|
||||
#endif // INCLUDED_RENDERMODIFIERS
|
||||
|
@ -42,15 +42,17 @@
|
||||
#include "ps/Loader.h"
|
||||
#include "ps/ProfileViewer.h"
|
||||
#include "graphics/Camera.h"
|
||||
#include "graphics/Texture.h"
|
||||
#include "graphics/TextureManager.h"
|
||||
#include "graphics/DefaultEmitter.h"
|
||||
#include "graphics/GameView.h"
|
||||
#include "graphics/LightEnv.h"
|
||||
#include "graphics/Terrain.h"
|
||||
#include "graphics/Model.h"
|
||||
#include "graphics/ModelDef.h"
|
||||
#include "graphics/GameView.h"
|
||||
#include "graphics/ParticleEngine.h"
|
||||
#include "graphics/DefaultEmitter.h"
|
||||
#include "graphics/ShaderManager.h"
|
||||
#include "graphics/ShaderTechnique.h"
|
||||
#include "graphics/Terrain.h"
|
||||
#include "graphics/Texture.h"
|
||||
#include "graphics/TextureManager.h"
|
||||
#include "renderer/FixedFunctionModelRenderer.h"
|
||||
#include "renderer/HWLightingModelRenderer.h"
|
||||
#include "renderer/InstancingModelRenderer.h"
|
||||
@ -222,9 +224,15 @@ public:
|
||||
/// true if CRenderer::Open has been called
|
||||
bool IsOpen;
|
||||
|
||||
/// true if shaders need to be reloaded
|
||||
bool ShadersDirty;
|
||||
|
||||
/// Table to display renderer stats in-game via profile system
|
||||
CRendererStatsTable profileTable;
|
||||
|
||||
/// Shader manager
|
||||
CShaderManager shaderManager;
|
||||
|
||||
/// Water manager
|
||||
WaterManager waterManager;
|
||||
|
||||
@ -266,10 +274,18 @@ public:
|
||||
ModelRenderer* pal_TranspHWLit[NumVertexTypes];
|
||||
ModelRenderer* pal_TranspSortAll;
|
||||
|
||||
ModelRenderer* pal_NormalShader;
|
||||
ModelRenderer* pal_NormalInstancingShader;
|
||||
ModelRenderer* pal_PlayerShader;
|
||||
ModelRenderer* pal_PlayerInstancingShader;
|
||||
ModelRenderer* pal_TranspShader;
|
||||
|
||||
ModelVertexRendererPtr VertexFF[NumVertexTypes];
|
||||
ModelVertexRendererPtr VertexHWLit[NumVertexTypes];
|
||||
ModelVertexRendererPtr VertexInstancing[NumVertexTypes];
|
||||
ModelVertexRendererPtr VertexPolygonSort;
|
||||
ModelVertexRendererPtr VertexRendererShader;
|
||||
ModelVertexRendererPtr VertexInstancingShader;
|
||||
|
||||
// generic RenderModifiers that are supposed to be used directly
|
||||
RenderModifierPtr ModWireframe;
|
||||
@ -280,7 +296,13 @@ public:
|
||||
|
||||
// RenderModifiers that are selected from the palette below
|
||||
RenderModifierPtr ModNormal;
|
||||
RenderModifierPtr ModNormalInstancing;
|
||||
RenderModifierPtr ModPlayer;
|
||||
RenderModifierPtr ModPlayerInstancing;
|
||||
RenderModifierPtr ModSolid;
|
||||
RenderModifierPtr ModSolidInstancing;
|
||||
RenderModifierPtr ModSolidPlayer;
|
||||
RenderModifierPtr ModSolidPlayerInstancing;
|
||||
RenderModifierPtr ModTransparent;
|
||||
|
||||
// Palette of available RenderModifiers
|
||||
@ -290,11 +312,23 @@ public:
|
||||
LitRenderModifierPtr ModPlayerLit;
|
||||
RenderModifierPtr ModTransparentUnlit;
|
||||
LitRenderModifierPtr ModTransparentLit;
|
||||
|
||||
RenderModifierPtr ModShaderSolidColor;
|
||||
RenderModifierPtr ModShaderSolidColorInstancing;
|
||||
RenderModifierPtr ModShaderSolidPlayerColor;
|
||||
RenderModifierPtr ModShaderSolidPlayerColorInstancing;
|
||||
RenderModifierPtr ModShaderSolidTex;
|
||||
LitRenderModifierPtr ModShaderNormal;
|
||||
LitRenderModifierPtr ModShaderNormalInstancing;
|
||||
LitRenderModifierPtr ModShaderPlayer;
|
||||
LitRenderModifierPtr ModShaderPlayerInstancing;
|
||||
LitRenderModifierPtr ModShaderTransparent;
|
||||
RenderModifierPtr ModShaderTransparentShadow;
|
||||
} Model;
|
||||
|
||||
|
||||
CRendererInternals()
|
||||
: IsOpen(false), profileTable(g_Renderer.m_Stats), textureManager(g_VFS, false, false)
|
||||
: IsOpen(false), ShadersDirty(true), profileTable(g_Renderer.m_Stats), textureManager(g_VFS, false, false)
|
||||
{
|
||||
terrainRenderer = new TerrainRenderer();
|
||||
shadow = new ShadowMap();
|
||||
@ -312,6 +346,12 @@ public:
|
||||
}
|
||||
Model.pal_TranspSortAll = 0;
|
||||
|
||||
Model.pal_NormalShader = 0;
|
||||
Model.pal_NormalInstancingShader = 0;
|
||||
Model.pal_PlayerShader = 0;
|
||||
Model.pal_PlayerInstancingShader = 0;
|
||||
Model.pal_TranspShader = 0;
|
||||
|
||||
Model.Normal = 0;
|
||||
Model.NormalInstancing = 0;
|
||||
Model.Player = 0;
|
||||
@ -360,15 +400,18 @@ public:
|
||||
/**
|
||||
* Renders all non-transparent models with the given modifiers.
|
||||
*/
|
||||
void CallModelRenderers(const RenderModifierPtr& modNormal, const RenderModifierPtr& modPlayer, int flags)
|
||||
void CallModelRenderers(
|
||||
const RenderModifierPtr& modNormal, const RenderModifierPtr& modNormalInstancing,
|
||||
const RenderModifierPtr& modPlayer, const RenderModifierPtr& modPlayerInstancing,
|
||||
int flags)
|
||||
{
|
||||
Model.Normal->Render(modNormal, flags);
|
||||
if (Model.Normal != Model.NormalInstancing)
|
||||
Model.NormalInstancing->Render(modNormal, flags);
|
||||
Model.NormalInstancing->Render(modNormalInstancing, flags);
|
||||
|
||||
Model.Player->Render(modPlayer, flags);
|
||||
if (Model.Player != Model.PlayerInstancing)
|
||||
Model.PlayerInstancing->Render(modPlayer, flags);
|
||||
Model.PlayerInstancing->Render(modPlayerInstancing, flags);
|
||||
}
|
||||
};
|
||||
|
||||
@ -403,13 +446,15 @@ CRenderer::CRenderer()
|
||||
m_Options.m_FancyWater = false;
|
||||
m_Options.m_Shadows = false;
|
||||
m_Options.m_ShadowAlphaFix = true;
|
||||
m_Options.m_ARBProgramShadow = true;
|
||||
|
||||
m_ShadowZBias = 0.02f;
|
||||
m_ShadowMapSize = 0;
|
||||
|
||||
m_LightEnv = NULL;
|
||||
|
||||
m_hCompositeAlphaMap = 0;
|
||||
|
||||
AddLocalProperty(L"shadows", &m_Options.m_Shadows, false);
|
||||
AddLocalProperty(L"fancyWater", &m_Options.m_FancyWater, false);
|
||||
AddLocalProperty(L"horizonHeight", &m->skyManager.m_HorizonHeight, false);
|
||||
AddLocalProperty(L"waterMurkiness", &m->waterManager.m_Murkiness, false);
|
||||
@ -442,6 +487,12 @@ CRenderer::~CRenderer()
|
||||
}
|
||||
delete m->Model.pal_TranspSortAll;
|
||||
|
||||
delete m->Model.pal_NormalShader;
|
||||
delete m->Model.pal_NormalInstancingShader;
|
||||
delete m->Model.pal_PlayerShader;
|
||||
delete m->Model.pal_PlayerInstancingShader;
|
||||
delete m->Model.pal_TranspShader;
|
||||
|
||||
// general
|
||||
delete m_VertexShader;
|
||||
m_VertexShader = 0;
|
||||
@ -461,6 +512,8 @@ void CRenderer::EnumCaps()
|
||||
{
|
||||
// assume support for nothing
|
||||
m_Caps.m_VBO = false;
|
||||
m_Caps.m_ARBProgram = false;
|
||||
m_Caps.m_ARBProgramShadow = false;
|
||||
m_Caps.m_VertexShader = false;
|
||||
m_Caps.m_FragmentShader = false;
|
||||
m_Caps.m_Shadows = false;
|
||||
@ -474,12 +527,19 @@ void CRenderer::EnumCaps()
|
||||
}
|
||||
}
|
||||
|
||||
if (0 == ogl_HaveExtensions(0, "GL_ARB_vertex_program", "GL_ARB_fragment_program", NULL))
|
||||
{
|
||||
m_Caps.m_ARBProgram = true;
|
||||
if (ogl_HaveExtension("GL_ARB_fragment_program_shadow"))
|
||||
m_Caps.m_ARBProgramShadow = true;
|
||||
}
|
||||
|
||||
if (0 == ogl_HaveExtensions(0, "GL_ARB_shader_objects", "GL_ARB_shading_language_100", NULL))
|
||||
{
|
||||
if (ogl_HaveExtension("GL_ARB_vertex_shader"))
|
||||
m_Caps.m_VertexShader=true;
|
||||
m_Caps.m_VertexShader = true;
|
||||
if (ogl_HaveExtension("GL_ARB_fragment_shader"))
|
||||
m_Caps.m_FragmentShader=true;
|
||||
m_Caps.m_FragmentShader = true;
|
||||
}
|
||||
|
||||
if (ogl_max_tex_units >= 3)
|
||||
@ -507,6 +567,74 @@ void CRenderer::EnumCaps()
|
||||
}
|
||||
}
|
||||
|
||||
void CRenderer::ReloadShaders()
|
||||
{
|
||||
typedef std::map<CStr, CStr> Defines;
|
||||
|
||||
Defines defNull;
|
||||
|
||||
Defines defBasic;
|
||||
if (m_Options.m_Shadows)
|
||||
{
|
||||
defBasic["USE_SHADOW"] = "1";
|
||||
if (m_Caps.m_ARBProgramShadow && m_Options.m_ARBProgramShadow)
|
||||
defBasic["USE_FP_SHADOW"] = "1";
|
||||
}
|
||||
|
||||
if (m_LightEnv)
|
||||
defBasic["LIGHTING_MODEL_" + m_LightEnv->GetLightingModel()] = "1";
|
||||
|
||||
Defines defColored = defBasic;
|
||||
defColored["USE_OBJECTCOLOR"] = "1";
|
||||
|
||||
Defines defTransparent = defBasic;
|
||||
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 passTransparentShadow(m->shaderManager.LoadProgram("solid_tex", defBasic));
|
||||
passTransparentShadow.AlphaFunc(GL_GREATER, 0.4f);
|
||||
CShaderTechnique techTransparentShadow(passTransparentShadow);
|
||||
|
||||
m->Model.ModShaderSolidColor = RenderModifierPtr(new ShaderRenderModifier(CShaderTechnique(m->shaderManager.LoadProgram(
|
||||
"solid", defNull))));
|
||||
m->Model.ModShaderSolidColorInstancing = RenderModifierPtr(new ShaderRenderModifier(CShaderTechnique(m->shaderManager.LoadProgram(
|
||||
"solid_instancing", defNull))));
|
||||
|
||||
m->Model.ModShaderSolidPlayerColor = RenderModifierPtr(new ShaderRenderModifier(CShaderTechnique(m->shaderManager.LoadProgram(
|
||||
"solid_player", defNull))));
|
||||
m->Model.ModShaderSolidPlayerColorInstancing = RenderModifierPtr(new ShaderRenderModifier(CShaderTechnique(m->shaderManager.LoadProgram(
|
||||
"solid_player_instancing", defNull))));
|
||||
|
||||
m->Model.ModShaderSolidTex = RenderModifierPtr(new ShaderRenderModifier(CShaderTechnique(m->shaderManager.LoadProgram(
|
||||
"solid_tex", defNull))));
|
||||
|
||||
m->Model.ModShaderNormal = LitRenderModifierPtr(new ShaderRenderModifier(CShaderTechnique(m->shaderManager.LoadProgram(
|
||||
"model_common", defBasic))));
|
||||
m->Model.ModShaderNormalInstancing = LitRenderModifierPtr(new ShaderRenderModifier(CShaderTechnique(m->shaderManager.LoadProgram(
|
||||
"model_common_instancing", defBasic))));
|
||||
|
||||
m->Model.ModShaderPlayer = LitRenderModifierPtr(new ShaderRenderModifier(CShaderTechnique(m->shaderManager.LoadProgram(
|
||||
"model_common", defColored))));
|
||||
m->Model.ModShaderPlayerInstancing = LitRenderModifierPtr(new ShaderRenderModifier(CShaderTechnique(m->shaderManager.LoadProgram(
|
||||
"model_common_instancing", defColored))));
|
||||
|
||||
m->Model.ModShaderTransparent = LitRenderModifierPtr(new ShaderRenderModifier(
|
||||
techTransparent));
|
||||
m->Model.ModShaderTransparentShadow = LitRenderModifierPtr(new ShaderRenderModifier(
|
||||
techTransparentShadow));
|
||||
|
||||
m->ShadersDirty = false;
|
||||
}
|
||||
|
||||
bool CRenderer::Open(int width, int height)
|
||||
{
|
||||
@ -524,6 +652,7 @@ bool CRenderer::Open(int width, int height)
|
||||
m_VertexShader = 0;
|
||||
}
|
||||
|
||||
|
||||
// model rendering
|
||||
m->Model.VertexFF[AmbientDiffuse] = ModelVertexRendererPtr(new FixedFunctionModelRenderer(false));
|
||||
m->Model.VertexFF[OnlyDiffuse] = ModelVertexRendererPtr(new FixedFunctionModelRenderer(true));
|
||||
@ -538,6 +667,8 @@ bool CRenderer::Open(int width, int height)
|
||||
m->Model.VertexInstancing[OnlyDiffuse] = ModelVertexRendererPtr(new InstancingModelRenderer(true));
|
||||
}
|
||||
m->Model.VertexPolygonSort = ModelVertexRendererPtr(new PolygonSortModelRenderer);
|
||||
m->Model.VertexRendererShader = ModelVertexRendererPtr(new ShaderModelRenderer);
|
||||
m->Model.VertexInstancingShader = ModelVertexRendererPtr(new ShaderInstancingModelRenderer);
|
||||
|
||||
for(int vertexType = 0; vertexType < NumVertexTypes; ++vertexType)
|
||||
{
|
||||
@ -559,6 +690,12 @@ bool CRenderer::Open(int width, int height)
|
||||
|
||||
m->Model.pal_TranspSortAll = new SortModelRenderer(m->Model.VertexPolygonSort);
|
||||
|
||||
m->Model.pal_NormalShader = new BatchModelRenderer(m->Model.VertexRendererShader);
|
||||
m->Model.pal_NormalInstancingShader = new BatchModelRenderer(m->Model.VertexInstancingShader);
|
||||
m->Model.pal_PlayerShader = new BatchModelRenderer(m->Model.VertexRendererShader);
|
||||
m->Model.pal_PlayerInstancingShader = new BatchModelRenderer(m->Model.VertexInstancingShader);
|
||||
m->Model.pal_TranspShader = new SortModelRenderer(m->Model.VertexRendererShader);
|
||||
|
||||
m->Model.ModWireframe = RenderModifierPtr(new WireframeRenderModifier);
|
||||
m->Model.ModPlain = RenderModifierPtr(new PlainRenderModifier);
|
||||
m->Model.ModPlainLit = LitRenderModifierPtr(new PlainLitRenderModifier);
|
||||
@ -628,6 +765,7 @@ void CRenderer::SetOptionBool(enum Option opt,bool value)
|
||||
break;
|
||||
case OPT_SHADOWS:
|
||||
m_Options.m_Shadows=value;
|
||||
ReloadShaders();
|
||||
break;
|
||||
case OPT_FANCYWATER:
|
||||
m_Options.m_FancyWater=value;
|
||||
@ -688,8 +826,8 @@ void CRenderer::SetRenderPath(RenderPath rp)
|
||||
// Renderer has been opened, so validate the selected renderpath
|
||||
if (rp == RP_DEFAULT)
|
||||
{
|
||||
if (m->CanUseRenderPathVertexShader())
|
||||
rp = RP_VERTEXSHADER;
|
||||
if (m_Caps.m_ARBProgram)
|
||||
rp = RP_SHADER;
|
||||
else
|
||||
rp = RP_FIXED;
|
||||
}
|
||||
@ -703,7 +841,20 @@ void CRenderer::SetRenderPath(RenderPath rp)
|
||||
}
|
||||
}
|
||||
|
||||
if (rp == RP_SHADER)
|
||||
{
|
||||
if (!m_Caps.m_ARBProgram)
|
||||
{
|
||||
LOGWARNING(L"Falling back to fixed function\n");
|
||||
rp = RP_FIXED;
|
||||
}
|
||||
}
|
||||
|
||||
m_Options.m_RenderPath = rp;
|
||||
|
||||
// We might need to regenerate some render data after changing path
|
||||
if (g_Game)
|
||||
g_Game->GetWorld()->GetTerrain()->MakeDirty(RENDERDATA_UPDATE_COLOR);
|
||||
}
|
||||
|
||||
|
||||
@ -713,6 +864,7 @@ CStr CRenderer::GetRenderPathName(RenderPath rp)
|
||||
case RP_DEFAULT: return "default";
|
||||
case RP_FIXED: return "fixed";
|
||||
case RP_VERTEXSHADER: return "vertexshader";
|
||||
case RP_SHADER: return "shader";
|
||||
default: return "(invalid)";
|
||||
}
|
||||
}
|
||||
@ -723,6 +875,8 @@ CRenderer::RenderPath CRenderer::GetRenderPathByName(const CStr& name)
|
||||
return RP_FIXED;
|
||||
if (name == "vertexshader")
|
||||
return RP_VERTEXSHADER;
|
||||
if (name == "shader")
|
||||
return RP_SHADER;
|
||||
if (name == "default")
|
||||
return RP_DEFAULT;
|
||||
|
||||
@ -758,12 +912,54 @@ void CRenderer::BeginFrame()
|
||||
{
|
||||
PROFILE("begin frame");
|
||||
|
||||
if (m_VertexShader)
|
||||
m_VertexShader->BeginFrame();
|
||||
|
||||
// zero out all the per-frame stats
|
||||
m_Stats.Reset();
|
||||
|
||||
// handle the new shader-based approach
|
||||
if (m_Options.m_RenderPath == RP_SHADER)
|
||||
{
|
||||
if (m->ShadersDirty)
|
||||
ReloadShaders();
|
||||
|
||||
m->Model.ModShaderNormal->SetShadowMap(m->shadow);
|
||||
m->Model.ModShaderNormal->SetLightEnv(m_LightEnv);
|
||||
|
||||
m->Model.ModShaderNormalInstancing->SetShadowMap(m->shadow);
|
||||
m->Model.ModShaderNormalInstancing->SetLightEnv(m_LightEnv);
|
||||
|
||||
m->Model.ModShaderPlayer->SetShadowMap(m->shadow);
|
||||
m->Model.ModShaderPlayer->SetLightEnv(m_LightEnv);
|
||||
|
||||
m->Model.ModShaderPlayerInstancing->SetShadowMap(m->shadow);
|
||||
m->Model.ModShaderPlayerInstancing->SetLightEnv(m_LightEnv);
|
||||
|
||||
m->Model.ModShaderTransparent->SetShadowMap(m->shadow);
|
||||
m->Model.ModShaderTransparent->SetLightEnv(m_LightEnv);
|
||||
|
||||
m->Model.ModNormal = m->Model.ModShaderNormal;
|
||||
m->Model.ModNormalInstancing = m->Model.ModShaderNormalInstancing;
|
||||
m->Model.ModPlayer = m->Model.ModShaderPlayer;
|
||||
m->Model.ModPlayerInstancing = m->Model.ModShaderPlayerInstancing;
|
||||
m->Model.ModSolid = m->Model.ModShaderSolidColor;
|
||||
m->Model.ModSolidInstancing = m->Model.ModShaderSolidColorInstancing;
|
||||
m->Model.ModSolidPlayer = m->Model.ModShaderSolidPlayerColor;
|
||||
m->Model.ModSolidPlayerInstancing = m->Model.ModShaderSolidPlayerColorInstancing;
|
||||
m->Model.ModTransparent = m->Model.ModShaderTransparent;
|
||||
|
||||
m->Model.Normal = m->Model.pal_NormalShader;
|
||||
m->Model.NormalInstancing = m->Model.pal_NormalInstancingShader;
|
||||
|
||||
m->Model.Player = m->Model.pal_PlayerShader;
|
||||
m->Model.PlayerInstancing = m->Model.pal_PlayerInstancingShader;
|
||||
|
||||
m->Model.Transp = m->Model.pal_TranspShader;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_VertexShader)
|
||||
m_VertexShader->BeginFrame();
|
||||
|
||||
// choose model renderers for this frame
|
||||
int vertexType;
|
||||
|
||||
@ -771,10 +967,12 @@ void CRenderer::BeginFrame()
|
||||
{
|
||||
vertexType = OnlyDiffuse;
|
||||
m->Model.ModNormal = m->Model.ModPlainLit;
|
||||
m->Model.ModNormalInstancing = m->Model.ModPlainLit;
|
||||
m->Model.ModPlainLit->SetShadowMap(m->shadow);
|
||||
m->Model.ModPlainLit->SetLightEnv(m_LightEnv);
|
||||
|
||||
m->Model.ModPlayer = m->Model.ModPlayerLit;
|
||||
m->Model.ModPlayerInstancing = m->Model.ModPlayerLit;
|
||||
m->Model.ModPlayerLit->SetShadowMap(m->shadow);
|
||||
m->Model.ModPlayerLit->SetLightEnv(m_LightEnv);
|
||||
|
||||
@ -786,7 +984,9 @@ void CRenderer::BeginFrame()
|
||||
{
|
||||
vertexType = AmbientDiffuse;
|
||||
m->Model.ModNormal = m->Model.ModPlain;
|
||||
m->Model.ModNormalInstancing = m->Model.ModPlain;
|
||||
m->Model.ModPlayer = m->Model.ModPlayerUnlit;
|
||||
m->Model.ModPlayerInstancing = m->Model.ModPlayerUnlit;
|
||||
m->Model.ModTransparent = m->Model.ModTransparentUnlit;
|
||||
}
|
||||
|
||||
@ -815,6 +1015,11 @@ void CRenderer::BeginFrame()
|
||||
m->Model.Player = m->Model.pal_PlayerFF[vertexType];
|
||||
}
|
||||
|
||||
m->Model.ModSolid = m->Model.ModSolidColor;
|
||||
m->Model.ModSolidInstancing = m->Model.ModSolidColor;
|
||||
m->Model.ModSolidPlayer = m->Model.ModSolidPlayerColor;
|
||||
m->Model.ModSolidPlayerInstancing = m->Model.ModSolidPlayerColor;
|
||||
|
||||
if (m_SortAllTransparent)
|
||||
m->Model.Transp = m->Model.pal_TranspSortAll;
|
||||
else if (m_Options.m_RenderPath == RP_VERTEXSHADER)
|
||||
@ -835,7 +1040,7 @@ void CRenderer::SetClearColor(SColor4ub color)
|
||||
|
||||
void CRenderer::RenderShadowMap()
|
||||
{
|
||||
PROFILE( "render shadow map" );
|
||||
PROFILE("render shadow map");
|
||||
|
||||
m->shadow->BeginRender();
|
||||
|
||||
@ -843,10 +1048,19 @@ void CRenderer::RenderShadowMap()
|
||||
glColor3f(shadowTransp, shadowTransp, shadowTransp);
|
||||
|
||||
// Figure out transparent rendering strategy
|
||||
RenderModifierPtr transparentShadows = m->Model.ModTransparentShadow;
|
||||
RenderModifierPtr transparentShadows;
|
||||
if (GetRenderPath() == RP_SHADER)
|
||||
{
|
||||
transparentShadows = m->Model.ModShaderTransparentShadow;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m->shadow->GetUseDepthTexture())
|
||||
transparentShadows = m->Model.ModTransparentDepthShadow;
|
||||
else
|
||||
transparentShadows = m->Model.ModTransparentShadow;
|
||||
}
|
||||
|
||||
if (m->shadow->GetUseDepthTexture())
|
||||
transparentShadows = m->Model.ModTransparentDepthShadow;
|
||||
|
||||
// Render all closed models (i.e. models where rendering back faces will produce
|
||||
// the correct result)
|
||||
@ -865,7 +1079,8 @@ void CRenderer::RenderShadowMap()
|
||||
|
||||
{
|
||||
PROFILE("render models");
|
||||
m->CallModelRenderers(m->Model.ModSolidColor, m->Model.ModSolidColor, MODELFLAG_CASTSHADOWS);
|
||||
m->CallModelRenderers(m->Model.ModSolid, m->Model.ModSolidInstancing,
|
||||
m->Model.ModSolid, m->Model.ModSolidInstancing, MODELFLAG_CASTSHADOWS);
|
||||
}
|
||||
|
||||
{
|
||||
@ -882,88 +1097,108 @@ void CRenderer::RenderShadowMap()
|
||||
|
||||
void CRenderer::RenderPatches()
|
||||
{
|
||||
PROFILE( "render patches" );
|
||||
PROFILE("render patches");
|
||||
|
||||
// switch on wireframe if we need it
|
||||
if (m_TerrainRenderMode==WIREFRAME) {
|
||||
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
|
||||
if (m_TerrainRenderMode == WIREFRAME)
|
||||
{
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
}
|
||||
|
||||
// render all the patches, including blend pass
|
||||
m->terrainRenderer->RenderTerrain((m_Caps.m_Shadows && m_Options.m_Shadows) ? m->shadow : 0);
|
||||
if (GetRenderPath() == RP_SHADER)
|
||||
m->terrainRenderer->RenderTerrainShader((m_Caps.m_Shadows && m_Options.m_Shadows) ? m->shadow : 0);
|
||||
else
|
||||
m->terrainRenderer->RenderTerrain((m_Caps.m_Shadows && m_Options.m_Shadows) ? m->shadow : 0);
|
||||
|
||||
if (m_TerrainRenderMode==WIREFRAME) {
|
||||
|
||||
if (m_TerrainRenderMode == WIREFRAME)
|
||||
{
|
||||
// switch wireframe off again
|
||||
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
|
||||
} else if (m_TerrainRenderMode==EDGED_FACES) {
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
}
|
||||
else if (m_TerrainRenderMode == EDGED_FACES)
|
||||
{
|
||||
// edged faces: need to make a second pass over the data:
|
||||
// first switch on wireframe
|
||||
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
|
||||
|
||||
// setup some renderstate ..
|
||||
glDepthMask(0);
|
||||
ogl_tex_bind(0, 0);
|
||||
glColor4f(1,1,1,0.35f);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glColor3f(0.5f, 0.5f, 1.0f);
|
||||
glLineWidth(2.0f);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
// render tiles edges
|
||||
m->terrainRenderer->RenderPatches();
|
||||
|
||||
// set color for outline
|
||||
glColor3f(0,0,1);
|
||||
glColor3f(0, 0, 1);
|
||||
glLineWidth(4.0f);
|
||||
|
||||
// render outline of each patch
|
||||
m->terrainRenderer->RenderOutlines();
|
||||
|
||||
// .. and restore the renderstates
|
||||
glDisable(GL_BLEND);
|
||||
glDepthMask(1);
|
||||
|
||||
// restore fill mode, and we're done
|
||||
glLineWidth(1.0f);
|
||||
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
}
|
||||
}
|
||||
|
||||
void CRenderer::RenderModels()
|
||||
{
|
||||
PROFILE( "render models ");
|
||||
PROFILE("render models");
|
||||
|
||||
// switch on wireframe if we need it
|
||||
if (m_ModelRenderMode==WIREFRAME) {
|
||||
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
|
||||
if (m_ModelRenderMode == WIREFRAME)
|
||||
{
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
}
|
||||
|
||||
m->CallModelRenderers(m->Model.ModNormal, m->Model.ModPlayer, 0);
|
||||
m->CallModelRenderers(m->Model.ModNormal, m->Model.ModNormalInstancing,
|
||||
m->Model.ModPlayer, m->Model.ModPlayerInstancing, 0);
|
||||
|
||||
if (m_ModelRenderMode==WIREFRAME) {
|
||||
// switch wireframe off again
|
||||
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
|
||||
} else if (m_ModelRenderMode==EDGED_FACES) {
|
||||
m->CallModelRenderers(m->Model.ModWireframe, m->Model.ModWireframe, 0);
|
||||
if (m_ModelRenderMode == WIREFRAME)
|
||||
{
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
}
|
||||
else if (m_ModelRenderMode == EDGED_FACES)
|
||||
{
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glColor3f(1.0f, 1.0f, 0.0f);
|
||||
|
||||
m->CallModelRenderers(m->Model.ModSolid, m->Model.ModSolidInstancing,
|
||||
m->Model.ModSolid, m->Model.ModSolidInstancing, 0);
|
||||
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
}
|
||||
}
|
||||
|
||||
void CRenderer::RenderTransparentModels()
|
||||
{
|
||||
PROFILE( "render transparent models ");
|
||||
PROFILE("render transparent models");
|
||||
|
||||
// switch on wireframe if we need it
|
||||
if (m_ModelRenderMode==WIREFRAME) {
|
||||
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
|
||||
if (m_ModelRenderMode == WIREFRAME)
|
||||
{
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
}
|
||||
|
||||
m->Model.Transp->Render(m->Model.ModTransparent, 0);
|
||||
|
||||
if (m_ModelRenderMode==WIREFRAME) {
|
||||
if (m_ModelRenderMode == WIREFRAME)
|
||||
{
|
||||
// switch wireframe off again
|
||||
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
|
||||
} else if (m_ModelRenderMode==EDGED_FACES) {
|
||||
m->Model.Transp->Render(m->Model.ModWireframe, 0);
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
}
|
||||
else if (m_ModelRenderMode == EDGED_FACES)
|
||||
{
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glColor3f(1.0f, 0.0f, 0.0f);
|
||||
|
||||
m->Model.Transp->Render(m->Model.ModSolid, 0);
|
||||
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1229,13 +1464,24 @@ void CRenderer::RenderSilhouettes()
|
||||
|
||||
{
|
||||
PROFILE("render model occluders");
|
||||
m->CallModelRenderers(m->Model.ModSolidColor, m->Model.ModSolidColor, MODELFLAG_SILHOUETTE_OCCLUDER);
|
||||
m->CallModelRenderers(m->Model.ModSolid, m->Model.ModSolidInstancing,
|
||||
m->Model.ModSolid, m->Model.ModSolidInstancing, MODELFLAG_SILHOUETTE_OCCLUDER);
|
||||
}
|
||||
|
||||
{
|
||||
PROFILE("render transparent occluders");
|
||||
// Reuse the depth shadow modifier to get alpha-tested rendering
|
||||
m->Model.Transp->Render(m->Model.ModTransparentDepthShadow, MODELFLAG_SILHOUETTE_OCCLUDER);
|
||||
if (GetRenderPath() == RP_SHADER)
|
||||
{
|
||||
glEnable(GL_ALPHA_TEST);
|
||||
glAlphaFunc(GL_GREATER, 0.4f);
|
||||
m->Model.Transp->Render(m->Model.ModShaderSolidTex, MODELFLAG_SILHOUETTE_OCCLUDER);
|
||||
glDisable(GL_ALPHA_TEST);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Reuse the depth shadow modifier to get alpha-tested rendering
|
||||
m->Model.Transp->Render(m->Model.ModTransparentDepthShadow, MODELFLAG_SILHOUETTE_OCCLUDER);
|
||||
}
|
||||
}
|
||||
|
||||
glDepthFunc(GL_GEQUAL);
|
||||
@ -1269,7 +1515,8 @@ void CRenderer::RenderSilhouettes()
|
||||
|
||||
{
|
||||
PROFILE("render models");
|
||||
m->CallModelRenderers(m->Model.ModSolidPlayerColor, m->Model.ModSolidPlayerColor, MODELFLAG_SILHOUETTE_DISPLAY);
|
||||
m->CallModelRenderers(m->Model.ModSolidPlayer, m->Model.ModSolidPlayerInstancing,
|
||||
m->Model.ModSolidPlayer, m->Model.ModSolidPlayerInstancing, MODELFLAG_SILHOUETTE_DISPLAY);
|
||||
// (This won't render transparent objects with SILHOUETTE_DISPLAY - will
|
||||
// we have any units that need that?)
|
||||
}
|
||||
@ -1738,6 +1985,11 @@ LibError CRenderer::ReloadChangedFileCB(void* param, const VfsPath& path)
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
void CRenderer::MakeShadersDirty()
|
||||
{
|
||||
m->ShadersDirty = true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Scripting Interface
|
||||
|
||||
@ -1801,6 +2053,19 @@ void CRenderer::JSI_SetDepthTextureBits(JSContext* ctx, jsval newval)
|
||||
m->shadow->SetDepthTextureBits(depthTextureBits);
|
||||
}
|
||||
|
||||
jsval CRenderer::JSI_GetShadows(JSContext*)
|
||||
{
|
||||
return ToJSVal(m_Options.m_Shadows);
|
||||
}
|
||||
|
||||
void CRenderer::JSI_SetShadows(JSContext* ctx, jsval newval)
|
||||
{
|
||||
if (!ToPrimitive(ctx, newval, m_Options.m_Shadows))
|
||||
return;
|
||||
|
||||
ReloadShaders();
|
||||
}
|
||||
|
||||
jsval CRenderer::JSI_GetShadowAlphaFix(JSContext*)
|
||||
{
|
||||
return ToJSVal(m_Options.m_ShadowAlphaFix);
|
||||
@ -1836,6 +2101,7 @@ void CRenderer::ScriptingInit()
|
||||
AddProperty(L"shadowZBias", &CRenderer::m_ShadowZBias);
|
||||
AddProperty(L"shadowMapSize", &CRenderer::m_ShadowMapSize);
|
||||
AddProperty(L"disableCopyShadow", &CRenderer::m_DisableCopyShadow);
|
||||
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"skipSubmit", &CRenderer::m_SkipSubmit);
|
||||
@ -1849,3 +2115,8 @@ CTextureManager& CRenderer::GetTextureManager()
|
||||
{
|
||||
return m->textureManager;
|
||||
}
|
||||
|
||||
CShaderManager& CRenderer::GetShaderManager()
|
||||
{
|
||||
return m->shaderManager;
|
||||
}
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
#include "graphics/Camera.h"
|
||||
#include "graphics/SColor.h"
|
||||
#include "graphics/ShaderProgram.h"
|
||||
#include "lib/ogl.h"
|
||||
#include "lib/res/handle.h"
|
||||
#include "ps/Singleton.h"
|
||||
@ -42,6 +43,7 @@ class RenderPathVertexShader;
|
||||
class WaterManager;
|
||||
class SkyManager;
|
||||
class CTextureManager;
|
||||
class CShaderManager;
|
||||
|
||||
// rendering modes
|
||||
enum ERenderMode { WIREFRAME, SOLID, EDGED_FACES };
|
||||
@ -60,24 +62,6 @@ enum ERenderMode { WIREFRAME, SOLID, EDGED_FACES };
|
||||
#define STREAM_POSTOUV3 (1 << 10)
|
||||
#define STREAM_TEXGENTOUV1 (1 << 11)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// SVertex3D: simple 3D vertex declaration
|
||||
struct SVertex3D
|
||||
{
|
||||
float m_Position[3];
|
||||
float m_TexCoords[2];
|
||||
unsigned int m_Color;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// SVertex2D: simple 2D vertex declaration
|
||||
struct SVertex2D
|
||||
{
|
||||
float m_Position[2];
|
||||
float m_TexCoords[2];
|
||||
unsigned int m_Color;
|
||||
};
|
||||
|
||||
// access to sole renderer object
|
||||
#define g_Renderer CRenderer::GetSingleton()
|
||||
|
||||
@ -110,7 +94,10 @@ public:
|
||||
RP_FIXED,
|
||||
|
||||
// Use (GL 2.0) vertex shaders for T&L when possible.
|
||||
RP_VERTEXSHADER
|
||||
RP_VERTEXSHADER,
|
||||
|
||||
// Use new ARB/GLSL system
|
||||
RP_SHADER
|
||||
};
|
||||
|
||||
// stats class - per frame counts of number of draw calls, poly counts etc
|
||||
@ -147,10 +134,13 @@ public:
|
||||
float m_LodBias;
|
||||
RenderPath m_RenderPath;
|
||||
bool m_ShadowAlphaFix;
|
||||
bool m_ARBProgramShadow;
|
||||
} m_Options;
|
||||
|
||||
struct Caps {
|
||||
bool m_VBO;
|
||||
bool m_ARBProgram;
|
||||
bool m_ARBProgramShadow;
|
||||
bool m_VertexShader;
|
||||
bool m_FragmentShader;
|
||||
bool m_Shadows;
|
||||
@ -193,6 +183,9 @@ public:
|
||||
// set color used to clear screen in BeginFrame()
|
||||
void SetClearColor(SColor4ub color);
|
||||
|
||||
// trigger a reload of shaders (when parameters they depend on have changed)
|
||||
void MakeShadersDirty();
|
||||
|
||||
/**
|
||||
* Set up the camera used for rendering the next scene; this includes
|
||||
* setting OpenGL state like viewport, projection and modelview matrices.
|
||||
@ -277,6 +270,8 @@ public:
|
||||
|
||||
CTextureManager& GetTextureManager();
|
||||
|
||||
CShaderManager& GetShaderManager();
|
||||
|
||||
/**
|
||||
* SetFastPlayerColor: Tell the renderer which path to take for
|
||||
* player colored models. Both paths should provide the same visual
|
||||
@ -310,7 +305,9 @@ protected:
|
||||
friend class SortModelRenderer;
|
||||
friend class RenderPathVertexShader;
|
||||
friend class HWLightingModelRenderer;
|
||||
friend class ShaderModelRenderer;
|
||||
friend class InstancingModelRenderer;
|
||||
friend class ShaderInstancingModelRenderer;
|
||||
friend class TerrainRenderer;
|
||||
|
||||
// scripting
|
||||
@ -324,6 +321,8 @@ protected:
|
||||
void JSI_SetUseDepthTexture(JSContext* ctx, jsval newval);
|
||||
jsval JSI_GetDepthTextureBits(JSContext*);
|
||||
void JSI_SetDepthTextureBits(JSContext* ctx, jsval newval);
|
||||
jsval JSI_GetShadows(JSContext*);
|
||||
void JSI_SetShadows(JSContext* ctx, jsval newval);
|
||||
jsval JSI_GetShadowAlphaFix(JSContext*);
|
||||
void JSI_SetShadowAlphaFix(JSContext* ctx, jsval newval);
|
||||
jsval JSI_GetSky(JSContext*);
|
||||
@ -362,6 +361,8 @@ protected:
|
||||
// enable oblique frustum clipping with the given clip plane
|
||||
void SetObliqueFrustumClipping(const CVector4D& clipPlane, int sign);
|
||||
|
||||
void ReloadShaders();
|
||||
|
||||
// hotloading
|
||||
static LibError ReloadChangedFileCB(void* param, const VfsPath& path);
|
||||
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "graphics/Terrain.h"
|
||||
#include "graphics/GameView.h"
|
||||
#include "graphics/Model.h"
|
||||
#include "graphics/ShaderManager.h"
|
||||
|
||||
#include "maths/MathUtil.h"
|
||||
|
||||
@ -225,6 +226,9 @@ void TerrainRenderer::RenderTerrain(ShadowMap* shadow)
|
||||
// no need to write to the depth buffer a second time
|
||||
glDepthMask(0);
|
||||
|
||||
// The decal color array contains lighting data, which we don't want in this non-shader mode
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
|
||||
// render blend passes for each patch
|
||||
PROFILE_START("render terrain blends");
|
||||
CPatchRData::RenderBlends(m->visiblePatches);
|
||||
@ -497,6 +501,134 @@ void TerrainRenderer::RenderTerrain(ShadowMap* shadow)
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Set up all the uniforms for a shader pass.
|
||||
*/
|
||||
void TerrainRenderer::PrepareShader(const CShaderProgramPtr& shader, ShadowMap* shadow)
|
||||
{
|
||||
const CLightEnv& lightEnv = g_Renderer.GetLightEnv();
|
||||
|
||||
if (shadow)
|
||||
{
|
||||
shader->BindTexture("shadowTex", shadow->GetTexture());
|
||||
shader->Uniform("shadowTransform", shadow->GetTextureMatrix());
|
||||
}
|
||||
|
||||
CLOSTexture& los = g_Game->GetView()->GetLOSTexture();
|
||||
shader->BindTexture("losTex", los.GetTexture());
|
||||
shader->Uniform("losTransform", los.GetTextureMatrix()[0], los.GetTextureMatrix()[12], 0.f, 0.f);
|
||||
|
||||
shader->Uniform("ambient", lightEnv.m_TerrainAmbientColor);
|
||||
shader->Uniform("sunColor", lightEnv.m_SunColor);
|
||||
}
|
||||
|
||||
void TerrainRenderer::RenderTerrainShader(ShadowMap* shadow)
|
||||
{
|
||||
debug_assert(m->phase == Phase_Render);
|
||||
|
||||
CShaderManager& shaderManager = g_Renderer.GetShaderManager();
|
||||
|
||||
typedef std::map<CStr, CStr> Defines;
|
||||
Defines defBasic;
|
||||
if (shadow)
|
||||
{
|
||||
defBasic["USE_SHADOW"] = "1";
|
||||
if (g_Renderer.m_Caps.m_ARBProgramShadow && g_Renderer.m_Options.m_ARBProgramShadow)
|
||||
defBasic["USE_FP_SHADOW"] = "1";
|
||||
}
|
||||
|
||||
defBasic["LIGHTING_MODEL_" + g_Renderer.GetLightEnv().GetLightingModel()] = "1";
|
||||
|
||||
CShaderProgramPtr shaderBase(shaderManager.LoadProgram("terrain_base", defBasic));
|
||||
CShaderProgramPtr shaderBlend(shaderManager.LoadProgram("terrain_blend", defBasic));
|
||||
CShaderProgramPtr shaderDecal(shaderManager.LoadProgram("terrain_decal", defBasic));
|
||||
|
||||
// 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();
|
||||
PROFILE_END("render terrain sides");
|
||||
|
||||
// switch on required client states
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glEnableClientState(GL_COLOR_ARRAY); // diffuse lighting colours
|
||||
|
||||
shaderBase->Bind();
|
||||
PrepareShader(shaderBase, shadow);
|
||||
|
||||
PROFILE_START("render terrain base");
|
||||
CPatchRData::RenderBases(m->visiblePatches);
|
||||
PROFILE_END("render terrain base");
|
||||
|
||||
shaderBase->Unbind();
|
||||
|
||||
// render blends
|
||||
|
||||
shaderBlend->Bind();
|
||||
PrepareShader(shaderBlend, shadow);
|
||||
|
||||
// switch on the composite alpha map texture
|
||||
(void)ogl_tex_bind(g_Renderer.m_hCompositeAlphaMap, 1);
|
||||
|
||||
// switch on second uv set
|
||||
pglClientActiveTextureARB(GL_TEXTURE1);
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
|
||||
// switch on blending
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
// no need to write to the depth buffer a second time
|
||||
glDepthMask(0);
|
||||
|
||||
// render blend passes for each patch
|
||||
PROFILE_START("render terrain blends");
|
||||
CPatchRData::RenderBlends(m->visiblePatches);
|
||||
PROFILE_END("render terrain blends");
|
||||
|
||||
// Disable second texcoord array
|
||||
pglClientActiveTextureARB(GL_TEXTURE1);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
|
||||
shaderBlend->Unbind();
|
||||
|
||||
// Render terrain decals
|
||||
|
||||
shaderDecal->Bind();
|
||||
PrepareShader(shaderDecal, shadow);
|
||||
|
||||
g_Renderer.BindTexture(1, 0);
|
||||
pglActiveTextureARB(GL_TEXTURE0);
|
||||
pglClientActiveTextureARB(GL_TEXTURE0);
|
||||
|
||||
PROFILE_START("render terrain decals");
|
||||
for (size_t i = 0; i < m->visibleDecals.size(); ++i)
|
||||
m->visibleDecals[i]->Render();
|
||||
PROFILE_END("render terrain decals");
|
||||
|
||||
shaderDecal->Unbind();
|
||||
|
||||
// restore OpenGL state
|
||||
g_Renderer.BindTexture(1, 0);
|
||||
g_Renderer.BindTexture(2, 0);
|
||||
g_Renderer.BindTexture(3, 0);
|
||||
|
||||
pglClientActiveTextureARB(GL_TEXTURE0);
|
||||
pglActiveTextureARB(GL_TEXTURE0);
|
||||
glDepthMask(1);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glDisable(GL_BLEND);
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// Render un-textured patches as polygons
|
||||
void TerrainRenderer::RenderPatches()
|
||||
|
@ -82,6 +82,12 @@ public:
|
||||
*/
|
||||
void RenderTerrain(ShadowMap* shadow);
|
||||
|
||||
/**
|
||||
* Render textured terrain, as with RenderTerrain, but using shaders
|
||||
* instead of multitexturing.
|
||||
*/
|
||||
void RenderTerrainShader(ShadowMap* shadow);
|
||||
|
||||
/**
|
||||
* RenderPatches: Render all patches un-textured as polygons.
|
||||
*
|
||||
@ -114,6 +120,8 @@ public:
|
||||
|
||||
private:
|
||||
TerrainRendererInternals* m;
|
||||
|
||||
void PrepareShader(const CShaderProgramPtr& shader, ShadowMap* shadow);
|
||||
};
|
||||
|
||||
#endif // INCLUDED_TERRAINRENDERER
|
||||
|
@ -35,6 +35,11 @@ public:
|
||||
m_Script.CallVoid("AddPlayer", (int)ent);
|
||||
}
|
||||
|
||||
virtual int32_t GetNumPlayers()
|
||||
{
|
||||
return m_Script.Call<int32_t>("GetNumPlayers");
|
||||
}
|
||||
|
||||
virtual entity_id_t GetPlayerByID(int32_t id)
|
||||
{
|
||||
return m_Script.Call<entity_id_t>("GetPlayerByID", (int)id);
|
||||
|
@ -28,6 +28,8 @@ class ICmpPlayerManager : public IComponent
|
||||
public:
|
||||
virtual void AddPlayer(entity_id_t ent) = 0;
|
||||
|
||||
virtual int32_t GetNumPlayers() = 0;
|
||||
|
||||
virtual entity_id_t GetPlayerByID(int32_t id) = 0;
|
||||
|
||||
DECLARE_INTERFACE_TYPE(PlayerManager)
|
||||
|
@ -311,6 +311,9 @@ enum
|
||||
ID_Screenshot,
|
||||
ID_JavaScript,
|
||||
ID_CameraReset,
|
||||
ID_RenderPathFixed,
|
||||
ID_RenderPathVertexShader,
|
||||
ID_RenderPathShader,
|
||||
|
||||
ID_Toolbar // must be last in the list
|
||||
};
|
||||
@ -334,6 +337,9 @@ BEGIN_EVENT_TABLE(ScenarioEditor, wxFrame)
|
||||
EVT_MENU(ID_Screenshot, ScenarioEditor::OnScreenshot)
|
||||
EVT_MENU(ID_JavaScript, ScenarioEditor::OnJavaScript)
|
||||
EVT_MENU(ID_CameraReset, ScenarioEditor::OnCameraReset)
|
||||
EVT_MENU(ID_RenderPathFixed, ScenarioEditor::OnRenderPath)
|
||||
EVT_MENU(ID_RenderPathVertexShader, ScenarioEditor::OnRenderPath)
|
||||
EVT_MENU(ID_RenderPathShader, ScenarioEditor::OnRenderPath)
|
||||
|
||||
EVT_IDLE(ScenarioEditor::OnIdle)
|
||||
END_EVENT_TABLE()
|
||||
@ -480,6 +486,12 @@ ScenarioEditor::ScenarioEditor(wxWindow* parent, ScriptInterface& scriptInterfac
|
||||
menuMisc->Append(ID_Screenshot, _("&Screenshot"));
|
||||
menuMisc->Append(ID_JavaScript, _("&JS console"));
|
||||
menuMisc->Append(ID_CameraReset, _("&Reset camera"));
|
||||
|
||||
wxMenu *menuRP = new wxMenu;
|
||||
menuMisc->AppendSubMenu(menuRP, _("Render &path"));
|
||||
menuRP->Append(ID_RenderPathFixed, _("&Fixed function"));
|
||||
menuRP->Append(ID_RenderPathVertexShader, _("&Vertex shader (old)"));
|
||||
menuRP->Append(ID_RenderPathShader, _("&Shader (new)"));
|
||||
}
|
||||
|
||||
m_FileHistory.Load(*wxConfigBase::Get());
|
||||
@ -771,6 +783,22 @@ void ScenarioEditor::OnCameraReset(wxCommandEvent& WXUNUSED(event))
|
||||
POST_MESSAGE(CameraReset, ());
|
||||
}
|
||||
|
||||
void ScenarioEditor::OnRenderPath(wxCommandEvent& event)
|
||||
{
|
||||
switch (event.GetId())
|
||||
{
|
||||
case ID_RenderPathFixed:
|
||||
POST_MESSAGE(SetViewParamS, (eRenderView::GAME, L"renderpath", L"fixed"));
|
||||
break;
|
||||
case ID_RenderPathVertexShader:
|
||||
POST_MESSAGE(SetViewParamS, (eRenderView::GAME, L"renderpath", L"vertexshader"));
|
||||
break;
|
||||
case ID_RenderPathShader:
|
||||
POST_MESSAGE(SetViewParamS, (eRenderView::GAME, L"renderpath", L"shader"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Position::Position(const wxPoint& pt)
|
||||
|
@ -51,6 +51,7 @@ public:
|
||||
void OnMediaPlayer(wxCommandEvent& event);
|
||||
void OnJavaScript(wxCommandEvent& event);
|
||||
void OnCameraReset(wxCommandEvent& event);
|
||||
void OnRenderPath(wxCommandEvent& event);
|
||||
|
||||
void OpenFile(const wxString& name);
|
||||
|
||||
|
@ -227,6 +227,8 @@ EnvironmentSidebar::EnvironmentSidebar(ScenarioEditor& scenarioEditor, wxWindow*
|
||||
sunSizer->Add(new VariableSliderBox(this, _("Sun elevation"), g_EnvironmentSettings.sunelevation, -M_PIf/2, M_PIf/2), wxSizerFlags().Expand());
|
||||
sunSizer->Add(new VariableSliderBox(this, _("Sun overbrightness"), g_EnvironmentSettings.sunoverbrightness, 1.0f, 3.0f), wxSizerFlags().Expand());
|
||||
|
||||
sunSizer->Add(m_LightingModelList = new VariableListBox(this, _("Light model"), g_EnvironmentSettings.lightingmodel), wxSizerFlags().Expand());
|
||||
|
||||
m_MainSizer->Add(new LightControl(this, wxSize(150, 150), g_EnvironmentSettings));
|
||||
m_MainSizer->Add(m_SkyList = new VariableListBox(this, _("Sky set"), g_EnvironmentSettings.skyset));
|
||||
m_MainSizer->Add(new VariableColourBox(this, _("Sun colour"), g_EnvironmentSettings.suncolour));
|
||||
@ -248,6 +250,13 @@ void EnvironmentSidebar::OnFirstDisplay()
|
||||
qry_env.Post();
|
||||
g_EnvironmentSettings = qry_env.settings;
|
||||
|
||||
|
||||
std::vector<std::wstring> lightingModels;
|
||||
lightingModels.push_back(L"old");
|
||||
lightingModels.push_back(L"standard");
|
||||
m_LightingModelList->SetChoices(lightingModels);
|
||||
|
||||
|
||||
g_EnvironmentSettings.NotifyObservers();
|
||||
// TODO: reupdate everything when loading a new map...
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ protected:
|
||||
virtual void OnFirstDisplay();
|
||||
|
||||
private:
|
||||
VariableListBox* m_LightingModelList;
|
||||
VariableListBox* m_SkyList;
|
||||
ObservableScopedConnection m_Conn;
|
||||
};
|
||||
|
@ -62,6 +62,8 @@ sEnvironmentSettings GetSettings()
|
||||
s.sunrotation = sunrotation;
|
||||
s.sunelevation = g_LightEnv.GetElevation();
|
||||
|
||||
s.lightingmodel = CStr(g_LightEnv.GetLightingModel()).FromUTF8();
|
||||
|
||||
s.skyset = g_Renderer.GetSkyManager()->GetSkySet();
|
||||
|
||||
// RGBColor (CVector3D) colours
|
||||
@ -103,6 +105,8 @@ void SetSettings(const sEnvironmentSettings& s)
|
||||
g_LightEnv.SetRotation(s.sunrotation);
|
||||
g_LightEnv.SetElevation(s.sunelevation);
|
||||
|
||||
g_LightEnv.SetLightingModel(CStrW(*s.lightingmodel).ToUTF8());
|
||||
|
||||
CStrW skySet = *s.skyset;
|
||||
if (skySet.length() == 0)
|
||||
skySet = L"default";
|
||||
|
@ -345,6 +345,10 @@ struct sEnvironmentSettings
|
||||
// (struct Colour stores as normal u8, 0..255)
|
||||
Shareable<float> sunoverbrightness; // range 1..3
|
||||
|
||||
// support different lighting models ("old" for the version compatible with old scenarios,
|
||||
// "standard" for the new normal model that supports much brighter lighting)
|
||||
Shareable<std::wstring> lightingmodel;
|
||||
|
||||
Shareable<std::wstring> skyset;
|
||||
|
||||
Shareable<Colour> suncolour;
|
||||
|
@ -260,6 +260,10 @@ void ViewGame::SetParam(const std::wstring& name, const std::wstring& value)
|
||||
if (!cmpPathfinder.null())
|
||||
cmpPathfinder->SetDebugOverlay(!value.empty());
|
||||
}
|
||||
else if (name == L"renderpath")
|
||||
{
|
||||
g_Renderer.SetRenderPath(g_Renderer.GetRenderPathByName(CStrW(value).ToUTF8()));
|
||||
}
|
||||
}
|
||||
|
||||
CCamera& ViewGame::GetCamera()
|
||||
|
Loading…
Reference in New Issue
Block a user