1
0
forked from 0ad/0ad

Postproc manager

This was SVN commit r12755.
This commit is contained in:
myconid 2012-10-15 10:34:23 +00:00
parent 538286054a
commit 1fb7889539
40 changed files with 1235 additions and 42 deletions

View File

@ -79,6 +79,9 @@ gentangents = false
; Use smooth LOS interpolation; REQUIRES preferglsl=true.
smoothlos = false
; Use screen-space postprocessing filters (HDR, bloom, DOF, etc). Incompatible with fixed renderpath.
postproc = false
; Quality level of shader effects (set to 10 to display effects)
materialmgr.quality = 0.0

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<effect>
<technique>
<require shaders="glsl"/>
<pass shader="glsl/bloom"/>
</technique>
</effect>

View File

@ -89,7 +89,7 @@
<require shaders="arb"/>
<pass shader="arb/model_common">
<define name="USE_TRANSPARENT" value="1"/>
<define name="REQUIRE_ALPHA_GEQUAL" value="0.9375"/>
<define name="REQUIRE_ALPHA_GEQUAL" value="0.6375"/>
</pass>
</technique>
@ -98,7 +98,7 @@
<require shaders="glsl"/>
<pass shader="glsl/model_common">
<define name="USE_TRANSPARENT" value="1"/>
<define name="REQUIRE_ALPHA_GEQUAL" value="0.9375"/>
<define name="REQUIRE_ALPHA_GEQUAL" value="0.6375"/>
</pass>
</technique>
@ -106,7 +106,7 @@
<require context="ALPHABLEND_PASS_OPAQUE"/>
<require shaders="fixed"/>
<pass shader="fixed:model">
<alpha func="gequal" ref="0.9375"/>
<alpha func="gequal" ref="0.6375"/>
</pass>
</technique>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<effect>
<technique>
<require shaders="glsl"/>
<pass shader="glsl/dof">
<define name="BLUR_FOV" value="3"/>
</pass>
<pass shader="glsl/hdr"/>
</technique>
</effect>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<effect>
<technique>
<require shaders="glsl"/>
<pass shader="glsl/hdr"/>
</technique>
</effect>

View File

@ -0,0 +1,107 @@
#version 110
varying vec2 v_tex;
uniform sampler2D renderedTex;
uniform vec2 texSize;
void main()
{
#if BLOOM_NOP
gl_FragColor = texture2D(renderedTex, v_tex);
#endif
#if BLOOM_PASS_H
vec4 colour;
colour += texture2D(renderedTex, (gl_FragCoord.xy + vec2(-2.5, 0.0)) / texSize) * 0.05;
colour += texture2D(renderedTex, (gl_FragCoord.xy + vec2(-1.5, 0.0)) / texSize) * 0.1;
colour += texture2D(renderedTex, (gl_FragCoord.xy + vec2(-0.5, 0.0)) / texSize) * 0.2;
colour += texture2D(renderedTex, (gl_FragCoord.xy + vec2( 0.0, 0.0)) / texSize) * 0.3;
colour += texture2D(renderedTex, (gl_FragCoord.xy + vec2( 0.5, 0.0)) / texSize) * 0.2;
colour += texture2D(renderedTex, (gl_FragCoord.xy + vec2( 1.5, 0.0)) / texSize) * 0.1;
colour += texture2D(renderedTex, (gl_FragCoord.xy + vec2( 2.5, 0.0)) / texSize) * 0.05;
gl_FragColor.rgb = colour.rgb;
gl_FragColor.a = 1.0;
#endif
#if BLOOM_PASS_V
vec4 colour;
colour += texture2D(renderedTex, (gl_FragCoord.xy + vec2(0.0, -2.5)) / texSize) * 0.05;
colour += texture2D(renderedTex, (gl_FragCoord.xy + vec2(0.0, -1.5)) / texSize) * 0.1;
colour += texture2D(renderedTex, (gl_FragCoord.xy + vec2(0.0, -0.5)) / texSize) * 0.2;
colour += texture2D(renderedTex, (gl_FragCoord.xy + vec2(0.0, 0.0)) / texSize) * 0.3;
colour += texture2D(renderedTex, (gl_FragCoord.xy + vec2(0.0, 0.5)) / texSize) * 0.2;
colour += texture2D(renderedTex, (gl_FragCoord.xy + vec2(0.0, 1.5)) / texSize) * 0.1;
colour += texture2D(renderedTex, (gl_FragCoord.xy + vec2(0.0, 2.5)) / texSize) * 0.05;
gl_FragColor.rgb = colour.rgb;
gl_FragColor.a = 1.0;
#endif
}
/*varying vec2 v_tex;
uniform sampler2D bgl_RenderedTexture;
uniform sampler2D bgl_DepthTexture;
uniform sampler2D bgl_LuminanceTexture;
uniform float bgl_RenderedTextureWidth;
uniform float bgl_RenderedTextureHeight;
#define PI 3.14159265
float width = bgl_RenderedTextureWidth; //texture width
float height = bgl_RenderedTextureHeight; //texture height
vec2 texCoord = v_tex;
vec2 texcoord = v_tex;
float BRIGHT_PASS_THRESHOLD = 0.6;
float BRIGHT_PASS_OFFSET = 0.6;
#define blurclamp 0.0015
#define bias 0.01
#define KERNEL_SIZE 3.0
vec4 bright(vec2 coo)
{
vec4 color = texture2D(bgl_RenderedTexture, coo);
color = max(color - BRIGHT_PASS_THRESHOLD, 0.0);
return color / (color + BRIGHT_PASS_OFFSET);
}
void main0(void)
{
vec2 blur = vec2(clamp( bias, -blurclamp, blurclamp ));
vec4 col = vec4( 0, 0, 0, 0 );
for ( float x = -KERNEL_SIZE + 1.0; x < KERNEL_SIZE; x += 1.0 )
{
for ( float y = -KERNEL_SIZE + 1.0; y < KERNEL_SIZE; y += 1.0 )
{
col += bright( texcoord + vec2( blur.x * x, blur.y * y ) );
}
}
col /= ((KERNEL_SIZE+KERNEL_SIZE)-1.0)*((KERNEL_SIZE+KERNEL_SIZE)-1.0);
//gl_FragColor = col + texture2D(bgl_RenderedTexture, texcoord);
//col *= 0.9;
gl_FragColor = 1.0 - (1.0 - col) * (1.0 - texture2D(bgl_RenderedTexture, texcoord));
}*/

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<program type="glsl">
<vertex file="glsl/hdr.vs">
<stream name="pos"/>
<stream name="uv0"/>
</vertex>
<fragment file="glsl/bloom.fs"/>
</program>

View File

@ -0,0 +1,63 @@
#version 120
uniform sampler2D renderedTex;
uniform sampler2D depthTex;
uniform sampler2D blurTex2;
uniform sampler2D blurTex4;
uniform sampler2D blurTex8;
uniform float width;
uniform float height;
uniform float zNear;
uniform float zFar;
uniform float brightness;
uniform float hdr;
uniform float saturation;
uniform float bloom;
varying vec2 v_tex;
float linearizeDepth(float depth)
{
return -zFar * zNear / (depth * (zFar - zNear) - zFar);
}
void main(void)
{
vec3 colour = texture2D(renderedTex, v_tex).rgb;
vec3 blur2 = texture2D(blurTex2, v_tex).rgb;
vec3 blur4 = texture2D(blurTex4, v_tex).rgb;
vec3 blur8 = texture2D(blurTex8, v_tex).rgb;
float depth = texture2D(depthTex, v_tex).r;
float midDepth = texture2D(depthTex, vec2(0.5, 0.5)).r;
midDepth += texture2D(depthTex, vec2(0.4, 0.4)).r;
midDepth += texture2D(depthTex, vec2(0.4, 0.6)).r;
midDepth += texture2D(depthTex, vec2(0.6, 0.4)).r;
midDepth += texture2D(depthTex, vec2(0.6, 0.6)).r;
midDepth /= 5.0;
float lDepth = linearizeDepth(depth);
float lMidDepth = linearizeDepth(midDepth);
float amount = abs(lDepth - lMidDepth);
amount = clamp(amount / (lMidDepth * BLUR_FOV), 0.0, 1.0);
colour = (amount >= 0.0 && amount < 0.25) ? mix(colour, blur2, (amount - 0.0) / (0.25)) : colour;
colour = (amount >= 0.25 && amount < 0.50) ? mix(blur2, blur4, (amount - 0.25) / (0.25)) : colour;
colour = (amount >= 0.50 && amount < 0.75) ? mix(blur4, blur8, (amount - 0.50) / (0.25)) : colour;
colour = (amount >= 0.75 && amount <= 1.00) ? blur8 : colour;
gl_FragColor.rgb = colour;
gl_FragColor.a = 1.0;
}

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<program type="glsl">
<vertex file="glsl/hdr.vs">
<stream name="pos"/>
<stream name="uv0"/>
<attrib name="a_vertex" semantics="gl_Vertex"/>
<attrib name="a_uv0" semantics="gl_MultiTexCoord0"/>
</vertex>
<fragment file="glsl/dof.fs"/>
</program>

View File

@ -0,0 +1,50 @@
#version 120
uniform sampler2D renderedTex;
uniform sampler2D depthTex;
uniform sampler2D blurTex2;
uniform sampler2D blurTex4;
uniform sampler2D blurTex8;
uniform float width;
uniform float height;
uniform float brightness;
uniform float hdr;
uniform float saturation;
uniform float bloom;
varying vec2 v_tex;
void main(void)
{
vec3 colour = texture2D(renderedTex, v_tex).rgb;
vec3 bloomv2 = texture2D(blurTex2, v_tex).rgb;
vec3 bloomv4 = texture2D(blurTex4, v_tex).rgb;
vec3 bloomv8 = texture2D(blurTex8, v_tex).rgb;
bloomv2 = max(bloomv2 - bloom, vec3(0.0));
bloomv4 = max(bloomv4 - bloom, vec3(0.0));
bloomv8 = max(bloomv8 - bloom, vec3(0.0));
vec3 bloomv = (bloomv2 + bloomv4 + bloomv8) / 3.0;
colour = max(bloomv, colour);
colour += vec3(brightness);
colour -= vec3(0.5);
colour *= vec3(hdr);
colour += vec3(0.5);
colour = mix(vec3(dot(colour, vec3(0.299, 0.587, 0.114))), colour, saturation);
gl_FragColor.rgb = colour;
gl_FragColor.a = 1.0;
}

View File

@ -0,0 +1,10 @@
#version 110
varying vec2 v_tex;
void main()
{
gl_Position = gl_Vertex;
v_tex = vec2(gl_MultiTexCoord0);
}

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<program type="glsl">
<vertex file="glsl/hdr.vs">
<stream name="pos"/>
<stream name="uv0"/>
<attrib name="a_vertex" semantics="gl_Vertex"/>
<attrib name="a_uv0" semantics="gl_MultiTexCoord0"/>
</vertex>
<fragment file="glsl/hdr.fs"/>
</program>

View File

@ -31,6 +31,9 @@ uniform vec3 ambient;
uniform vec3 sunColor;
uniform vec3 sunDir;
uniform vec3 fogColor;
uniform vec2 fogParams;
varying vec4 v_lighting;
varying vec2 v_tex;
varying vec2 v_los;
@ -89,6 +92,22 @@ float get_shadow()
#endif
}
vec3 get_fog(vec3 color)
{
float density = fogParams.x;
float maxFog = fogParams.y;
const float LOG2 = 1.442695;
float z = gl_FragCoord.z / gl_FragCoord.w;
float fogFactor = exp2(-density * density * z * z * LOG2);
fogFactor = fogFactor * (1.0 - maxFog) + maxFog;
fogFactor = clamp(fogFactor, 0.0, 1.0);
return mix(fogColor, color, fogFactor);
}
void main()
{
vec2 coord = v_tex;
@ -244,6 +263,8 @@ void main()
color = mix(texdiffuse, color, specular.a);
#endif
color = get_fog(color);
#if !IGNORE_LOS
float los = texture2D(losTex, v_los).a;
los = los < 0.03 ? 0.0 : los;

View File

@ -22,6 +22,9 @@ uniform vec3 ambient;
uniform vec3 sunColor;
uniform vec3 sunDir;
uniform vec3 fogColor;
uniform vec2 fogParams;
uniform vec2 textureTransform;
varying vec3 v_lighting;
@ -140,6 +143,21 @@ vec4 triplanarNormals(sampler2D sampler, vec3 wpos)
}
#endif
vec3 get_fog(vec3 color)
{
float density = fogParams.x;
float maxFog = fogParams.y;
const float LOG2 = 1.442695;
float z = gl_FragCoord.z / gl_FragCoord.w;
float fogFactor = exp2(-density * density * z * z * LOG2);
fogFactor = fogFactor * (1.0 - maxFog) + maxFog;
fogFactor = clamp(fogFactor, 0.0, 1.0);
return mix(fogColor, color, fogFactor);
}
void main()
{
@ -218,6 +236,8 @@ void main()
color = mix(texdiffuse, color, specular.a);
#endif
color = get_fog(color);
float los = texture2D(losTex, v_los).a;
los = los < 0.03 ? 0.0 : los;
color *= los;

View File

@ -17,9 +17,28 @@ uniform float fullDepth; // Depth at which to use full murkiness (shallower wat
uniform vec3 reflectionTint; // Tint for reflection (used for really muddy water)
uniform float reflectionTintStrength; // Strength of reflection tint (how much of it to mix in)
uniform vec3 fogColor;
uniform vec2 fogParams;
varying vec3 worldPos;
varying float waterDepth;
vec3 get_fog(vec3 color)
{
float density = fogParams.x;
float maxFog = fogParams.y;
const float LOG2 = 1.442695;
float z = gl_FragCoord.z / gl_FragCoord.w;
float fogFactor = exp2(-density * density * z * z * LOG2);
fogFactor = fogFactor * (1.0 - maxFog) + maxFog;
fogFactor = clamp(fogFactor, 0.0, 1.0);
return mix(fogColor, color, fogFactor);
}
void main()
{
vec3 n, l, h, v; // Normal, light vector, half-vector and view vector (vector to eye)
@ -55,7 +74,11 @@ void main()
losMod = texture2D(losMap, gl_TexCoord[3].st).a;
losMod = losMod < 0.03 ? 0.0 : losMod;
gl_FragColor.rgb = mix(refrColor + 0.3*specular, reflColor + specular, fresnel) * losMod;
gl_FragColor.rgb = mix(refrColor + 0.3*specular, reflColor + specular, fresnel);
gl_FragColor.rgb = get_fog(gl_FragColor.rgb);
gl_FragColor.rgb *= losMod;
// Make alpha vary based on both depth (so it blends with the shore) and view angle (make it
// become opaque faster at lower view angles so we can't look "underneath" the water plane)

View File

@ -32,7 +32,11 @@ CLightEnv::CLightEnv()
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)
m_UnitsAmbientColor(0x80/255.f, 0x80/255.f, 0x80/255.f),
m_FogColor(0xCC/255.f, 0xCC/255.f, 0xE5/255.f),
m_FogFactor(0.000),
m_FogMax(0.5),
m_Brightness(0.0), m_Contrast(1.0), m_Saturation(0.99), m_Bloom(0.1999)
{
CalculateSunDirection();
}

View File

@ -69,6 +69,12 @@ public:
RGBColor m_SunColor;
RGBColor m_TerrainAmbientColor;
RGBColor m_UnitsAmbientColor;
RGBColor m_FogColor;
float m_FogFactor;
float m_FogMax;
float m_Brightness, m_Contrast, m_Saturation, m_Bloom;
public:
CLightEnv();
@ -134,7 +140,14 @@ public:
m_LightingModel == o.m_LightingModel &&
m_SunColor == o.m_SunColor &&
m_TerrainAmbientColor == o.m_TerrainAmbientColor &&
m_UnitsAmbientColor == o.m_UnitsAmbientColor;
m_UnitsAmbientColor == o.m_UnitsAmbientColor &&
m_FogColor == o.m_FogColor &&
m_FogFactor == o.m_FogFactor &&
m_FogMax == o.m_FogMax &&
m_Brightness == o.m_Brightness &&
m_Contrast == o.m_Contrast &&
m_Saturation == o.m_Saturation &&
m_Bloom == o.m_Bloom;
}
bool operator!=(const CLightEnv& o) const

View File

@ -36,6 +36,7 @@
#include "ps/LoaderThunks.h"
#include "ps/World.h"
#include "ps/XML/Xeromyces.h"
#include "renderer/PostprocManager.h"
#include "renderer/SkyManager.h"
#include "renderer/WaterManager.h"
#include "simulation2/Simulation2.h"
@ -56,13 +57,15 @@ CMapReader::CMapReader()
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");
//m_LightEnv.SetLightingModel("old");
//pPostproc->SetPostEffect(L"default");
}
// LoadMap: try to load the map from given file; reinitialise the scene to new data if successful
void CMapReader::LoadMap(const VfsPath& pathname, CTerrain *pTerrain_,
WaterManager* pWaterMan_, SkyManager* pSkyMan_,
CLightEnv *pLightEnv_, CGameView *pGameView_, CCinemaManager* pCinema_, CTriggerManager* pTrigMan_,
CLightEnv *pLightEnv_, CGameView *pGameView_, CCinemaManager* pCinema_, CTriggerManager* pTrigMan_, CPostprocManager* pPostproc_,
CSimulation2 *pSimulation2_, const CSimContext* pSimContext_, int playerID_, bool skipEntities)
{
// latch parameters (held until DelayedLoadFinished)
@ -73,6 +76,7 @@ void CMapReader::LoadMap(const VfsPath& pathname, CTerrain *pTerrain_,
pSkyMan = pSkyMan_;
pCinema = pCinema_;
pTrigMan = pTrigMan_;
pPostproc = pPostproc_;
pSimulation2 = pSimulation2_;
pSimContext = pSimContext_;
m_PlayerID = playerID_;
@ -106,6 +110,10 @@ void CMapReader::LoadMap(const VfsPath& pathname, CTerrain *pTerrain_,
// delete all existing entities
if (pSimulation2)
pSimulation2->ResetState();
// reset post effects
if (pPostproc)
pPostproc->SetPostEffect(L"default");
// load map settings script
RegMemFun(this, &CMapReader::LoadScriptSettings, L"CMapReader::LoadScriptSettings", 50);
@ -133,7 +141,7 @@ void CMapReader::LoadMap(const VfsPath& pathname, CTerrain *pTerrain_,
// LoadRandomMap: try to load the map data; reinitialise the scene to new data if successful
void CMapReader::LoadRandomMap(const CStrW& scriptFile, const CScriptValRooted& settings, CTerrain *pTerrain_,
WaterManager* pWaterMan_, SkyManager* pSkyMan_,
CLightEnv *pLightEnv_, CGameView *pGameView_, CCinemaManager* pCinema_, CTriggerManager* pTrigMan_,
CLightEnv *pLightEnv_, CGameView *pGameView_, CCinemaManager* pCinema_, CTriggerManager* pTrigMan_, CPostprocManager* pPostproc_,
CSimulation2 *pSimulation2_, int playerID_)
{
// latch parameters (held until DelayedLoadFinished)
@ -146,6 +154,7 @@ void CMapReader::LoadRandomMap(const CStrW& scriptFile, const CScriptValRooted&
pSkyMan = pSkyMan_;
pCinema = pCinema_;
pTrigMan = pTrigMan_;
pPostproc = pPostproc_;
pSimulation2 = pSimulation2_;
pSimContext = pSimulation2 ? &pSimulation2->GetSimContext() : NULL;
m_PlayerID = playerID_;
@ -558,6 +567,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(posteffect);
EL(skyset);
EL(suncolour);
EL(sunelevation);
@ -575,6 +585,15 @@ void CXMLReader::ReadEnvironment(XMBElement parent)
EL(tint);
EL(reflectiontint);
EL(reflectiontintstrength);
EL(fog);
EL(fogcolour);
EL(fogfactor);
EL(fogthickness);
EL(postproc);
EL(brightness);
EL(contrast);
EL(saturation);
EL(bloom);
AT(r); AT(g); AT(b);
#undef AT
#undef EL
@ -587,7 +606,7 @@ void CXMLReader::ReadEnvironment(XMBElement parent)
if (element_name == el_lightingmodel)
{
m_MapReader.m_LightEnv.SetLightingModel(element.GetText());
// NOP - obsolete.
}
else if (element_name == el_skyset)
{
@ -623,6 +642,56 @@ void CXMLReader::ReadEnvironment(XMBElement parent)
attrs.GetNamedItem(at_g).ToFloat(),
attrs.GetNamedItem(at_b).ToFloat());
}
else if (element_name == el_fog)
{
XERO_ITER_EL(element, fog)
{
int element_name = fog.GetNodeName();
if (element_name == el_fogcolour)
{
XMBAttributeList attrs = fog.GetAttributes();
m_MapReader.m_LightEnv.m_FogColor = RGBColor(
attrs.GetNamedItem(at_r).ToFloat(),
attrs.GetNamedItem(at_g).ToFloat(),
attrs.GetNamedItem(at_b).ToFloat());
}
else if (element_name == el_fogfactor)
{
m_MapReader.m_LightEnv.m_FogFactor = fog.GetText().ToFloat();
}
else if (element_name == el_fogthickness)
{
m_MapReader.m_LightEnv.m_FogMax = fog.GetText().ToFloat();
}
}
}
else if (element_name == el_postproc)
{
XERO_ITER_EL(element, postproc)
{
int element_name = postproc.GetNodeName();
if (element_name == el_brightness)
{
m_MapReader.m_LightEnv.m_Brightness = postproc.GetText().ToFloat();
}
else if (element_name == el_contrast)
{
m_MapReader.m_LightEnv.m_Contrast = postproc.GetText().ToFloat();
}
else if (element_name == el_saturation)
{
m_MapReader.m_LightEnv.m_Saturation = postproc.GetText().ToFloat();
}
else if (element_name == el_bloom)
{
m_MapReader.m_LightEnv.m_Bloom = postproc.GetText().ToFloat();
}
else if (element_name == el_posteffect)
{
m_MapReader.pPostproc->SetPostEffect(postproc.GetText().FromUTF8());
}
}
}
else if (element_name == el_water)
{
XERO_ITER_EL(element, waterbody)
@ -1321,7 +1390,9 @@ int CMapReader::ParseEnvironment()
return 0;
}
m_LightEnv.SetLightingModel("standard");
//m_LightEnv.SetLightingModel("standard");
if (pPostproc)
pPostproc->SetPostEffect(L"default");
std::wstring skySet;
GET_ENVIRONMENT_PROPERTY(envObj.get(), SkySet, skySet)

View File

@ -32,6 +32,7 @@ class WaterManager;
class SkyManager;
class CLightEnv;
class CCinemaManager;
class CPostprocManager;
class CTriggerManager;
class CSimulation2;
class CSimContext;
@ -53,10 +54,10 @@ public:
// LoadMap: try to load the map from given file; reinitialise the scene to new data if successful
void LoadMap(const VfsPath& pathname, CTerrain*, WaterManager*, SkyManager*, CLightEnv*, CGameView*,
CCinemaManager*, CTriggerManager*, CSimulation2*, const CSimContext*, int playerID, bool skipEntities);
CCinemaManager*, CTriggerManager*, CPostprocManager* pPostproc, CSimulation2*, const CSimContext*,
int playerID, bool skipEntities);
void LoadRandomMap(const CStrW& scriptFile, const CScriptValRooted& settings, CTerrain*, WaterManager*, SkyManager*, CLightEnv*, CGameView*,
CCinemaManager*, CTriggerManager*, CSimulation2*, int playerID);
void LoadRandomMap(const CStrW& scriptFile, const CScriptValRooted& settings, CTerrain*, WaterManager*, SkyManager*, CLightEnv*, CGameView*, CCinemaManager*, CTriggerManager*, CPostprocManager* pPostproc_, CSimulation2*, int playerID);
private:
// Load script settings for use by scripts
@ -129,6 +130,7 @@ private:
CTerrain* pTerrain;
WaterManager* pWaterMan;
SkyManager* pSkyMan;
CPostprocManager* pPostproc;
CLightEnv* pLightEnv;
CGameView* pGameView;
CCinemaManager* pCinema;

View File

@ -33,6 +33,7 @@
#include "ps/Loader.h"
#include "ps/Filesystem.h"
#include "ps/XML/XMLWriter.h"
#include "renderer/PostprocManager.h"
#include "renderer/SkyManager.h"
#include "renderer/WaterManager.h"
#include "simulation2/Simulation2.h"
@ -53,6 +54,7 @@ CMapWriter::CMapWriter()
void CMapWriter::SaveMap(const VfsPath& pathname, CTerrain* pTerrain,
WaterManager* pWaterMan, SkyManager* pSkyMan,
CLightEnv* pLightEnv, CCamera* pCamera, CCinemaManager* pCinema,
CPostprocManager* pPostproc,
CSimulation2* pSimulation2)
{
CFilePacker packer(FILE_VERSION, "PSMP");
@ -64,7 +66,7 @@ void CMapWriter::SaveMap(const VfsPath& pathname, CTerrain* pTerrain,
packer.Write(pathname);
VfsPath pathnameXML = pathname.ChangeExtension(L".xml");
WriteXML(pathnameXML, pWaterMan, pSkyMan, pLightEnv, pCamera, pCinema, pSimulation2);
WriteXML(pathnameXML, pWaterMan, pSkyMan, pLightEnv, pCamera, pCinema, pPostproc, pSimulation2);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
@ -173,6 +175,7 @@ void CMapWriter::PackTerrain(CFilePacker& packer, CTerrain* pTerrain)
void CMapWriter::WriteXML(const VfsPath& filename,
WaterManager* pWaterMan, SkyManager* pSkyMan,
CLightEnv* pLightEnv, CCamera* pCamera, CCinemaManager* pCinema,
CPostprocManager* pPostproc,
CSimulation2* pSimulation2)
{
XML_Start();
@ -190,7 +193,6 @@ void CMapWriter::WriteXML(const VfsPath& filename,
{
XML_Element("Environment");
XML_Setting("LightingModel", pLightEnv->GetLightingModel());
XML_Setting("SkySet", pSkyMan->GetSkySet());
{
XML_Element("SunColour");
@ -218,6 +220,17 @@ void CMapWriter::WriteXML(const VfsPath& filename,
XML_Attribute("g", pLightEnv->m_UnitsAmbientColor.Y);
XML_Attribute("b", pLightEnv->m_UnitsAmbientColor.Z);
}
{
XML_Element("Fog");
XML_Setting("FogFactor", pLightEnv->m_FogFactor);
XML_Setting("FogThickness", pLightEnv->m_FogMax);
{
XML_Element("FogColour");
XML_Attribute("r", pLightEnv->m_FogColor.X);
XML_Attribute("g", pLightEnv->m_FogColor.Y);
XML_Attribute("b", pLightEnv->m_FogColor.Z);
}
}
{
XML_Element("Water");
@ -251,6 +264,17 @@ void CMapWriter::WriteXML(const VfsPath& filename,
XML_Setting("ReflectionTintStrength", pWaterMan->m_ReflectionTintStrength);
}
}
{
XML_Element("Postproc");
{
XML_Setting("Brightness", pLightEnv->m_Brightness);
XML_Setting("Contrast", pLightEnv->m_Contrast);
XML_Setting("Saturation", pLightEnv->m_Saturation);
XML_Setting("Bloom", pLightEnv->m_Bloom);
XML_Setting("PostEffect", pPostproc->GetPostEffect());
}
}
}
{

View File

@ -29,6 +29,7 @@ class CLightEnv;
class CTerrain;
class CCamera;
class CCinemaManager;
class CPostprocManager;
class CTriggerManager;
class WaterManager;
class SkyManager;
@ -46,7 +47,8 @@ public:
void SaveMap(const VfsPath& pathname, CTerrain* pTerr,
WaterManager* pWaterMan, SkyManager* pSkyMan,
CLightEnv* pLightEnv, CCamera* pCamera,
CCinemaManager* pCinema, CSimulation2* pSimulation2);
CCinemaManager* pCinema, CPostprocManager* pPostproc,
CSimulation2* pSimulation2);
private:
// PackMap: pack the current world into a raw data stream
@ -62,7 +64,8 @@ private:
// WriteXML: output some other data (entities, etc) in XML format
void WriteXML(const VfsPath& pathname, WaterManager* pWaterMan,
SkyManager* pSkyMan, CLightEnv* pLightEnv, CCamera* pCamera,
CCinemaManager* pCinema, CSimulation2* pSimulation2);
CCinemaManager* pCinema, CPostprocManager* pPostproc,
CSimulation2* pSimulation2);
// void WriteTriggerGroup(XMLWriter_File& xml_file_, const MapTriggerGroup& group,
// const std::list<MapTriggerGroup>& groupList);
// void WriteTrigger(XMLWriter_File& xml_file_, const MapTrigger& trigger);

View File

@ -181,6 +181,8 @@ FUNC(void, glFramebufferTexture3DEXT, (GLenum target, GLenum attachment, GLenum
FUNC(void, glFramebufferRenderbufferEXT, (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer))
FUNC(void, glGetFramebufferAttachmentParameterivEXT, (GLenum target, GLenum attachment, GLenum pname, GLint *params))
FUNC(void, glGenerateMipmapEXT, (GLenum target))
FUNC(void, glBlitFramebufferEXT, (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter))
FUNC(void, glDrawBuffers, (GLsizei n, const GLenum *bufs))
// GL_ARB_vertex_program, GL_ARB_fragment_program
FUNC(void, glProgramStringARB, (GLenum target, GLenum format, GLsizei len, const GLvoid *string))

View File

@ -82,7 +82,8 @@ void CWorld::RegisterInit(const CStrW& mapFile, int playerID)
CRenderer::IsInitialised() ? g_Renderer.GetSkyManager() : NULL,
&g_LightEnv, m_pGame->GetView(),
m_pGame->GetView() ? m_pGame->GetView()->GetCinema() : NULL,
pTriggerManager, m_pGame->GetSimulation2(), &m_pGame->GetSimulation2()->GetSimContext(), playerID, false);
pTriggerManager, CRenderer::IsInitialised() ? &g_Renderer.GetPostprocManager() : NULL,
m_pGame->GetSimulation2(), &m_pGame->GetSimulation2()->GetSimContext(), playerID, false);
// fails immediately, or registers for delay loading
}
catch (PSERROR_File& err)
@ -106,7 +107,8 @@ void CWorld::RegisterInitRMS(const CStrW& scriptFile, const CScriptValRooted& se
CRenderer::IsInitialised() ? g_Renderer.GetSkyManager() : NULL,
&g_LightEnv, m_pGame->GetView(),
m_pGame->GetView() ? m_pGame->GetView()->GetCinema() : NULL,
pTriggerManager, m_pGame->GetSimulation2(), playerID);
pTriggerManager, CRenderer::IsInitialised() ? &g_Renderer.GetPostprocManager() : NULL,
m_pGame->GetSimulation2(), playerID);
// registers for delay loading
}

View File

@ -0,0 +1,488 @@
/* Copyright (C) 2012 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 "lib/ogl.h"
#include "maths/MathUtil.h"
#include "gui/GUIutil.h"
#include "lib/bits.h"
#include "ps/CLogger.h"
#include "ps/Filesystem.h"
#include "ps/Game.h"
#include "ps/World.h"
#include "graphics/GameView.h"
#include "graphics/LightEnv.h"
#include "graphics/ShaderManager.h"
#include "renderer/PostprocManager.h"
#include "renderer/Renderer.h"
CPostprocManager::CPostprocManager()
: m_IsInitialised(false), m_PingFbo(0), m_PongFbo(0), m_PostProcEffect(L"default"), m_ColourTex1(0), m_ColourTex2(0),
m_DepthTex(0), m_BloomFbo(0), m_BlurTex2a(0), m_BlurTex2b(0), m_BlurTex4a(0), m_BlurTex4b(0),
m_BlurTex8a(0), m_BlurTex8b(0), m_WhichBuffer(true)
{
}
CPostprocManager::~CPostprocManager()
{
Cleanup();
}
void CPostprocManager::Initialize()
{
RecreateBuffers();
m_IsInitialised = true;
SetPostEffect(L"default");
}
void CPostprocManager::Cleanup()
{
if (m_IsInitialised)
{
if (m_PingFbo) pglDeleteFramebuffersEXT(1, &m_PingFbo);
if (m_PongFbo) pglDeleteFramebuffersEXT(1, &m_PongFbo);
if (m_BloomFbo) pglDeleteFramebuffersEXT(1, &m_BloomFbo);
m_PingFbo = m_PongFbo = m_BloomFbo = 0;
if (m_ColourTex1) glDeleteTextures(1, &m_ColourTex1);
if (m_ColourTex2) glDeleteTextures(1, &m_ColourTex2);
if (m_DepthTex) glDeleteTextures(1, &m_DepthTex);
m_ColourTex1 = m_ColourTex2 = m_DepthTex = 0;
if (m_BlurTex2a) glDeleteTextures(1, &m_BlurTex2a);
if (m_BlurTex2b) glDeleteTextures(1, &m_BlurTex2b);
if (m_BlurTex4a) glDeleteTextures(1, &m_BlurTex4a);
if (m_BlurTex4b) glDeleteTextures(1, &m_BlurTex4b);
if (m_BlurTex8a) glDeleteTextures(1, &m_BlurTex8a);
if (m_BlurTex8b) glDeleteTextures(1, &m_BlurTex8b);
m_BlurTex2a = m_BlurTex2b = m_BlurTex4a = m_BlurTex4b = m_BlurTex8a = m_BlurTex8b = 0;
}
}
void CPostprocManager::RecreateBuffers()
{
Cleanup();
m_Width = g_Renderer.GetWidth();
m_Height = g_Renderer.GetHeight();
#define GEN_BUFFER_RGBA(name, w, h) \
glGenTextures(1, (GLuint*)&name); \
glBindTexture(GL_TEXTURE_2D, name); \
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, \
GL_UNSIGNED_BYTE, 0); \
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); \
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); \
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); \
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// Two fullscreen ping-pong textures.
GEN_BUFFER_RGBA(m_ColourTex1, m_Width, m_Height);
GEN_BUFFER_RGBA(m_ColourTex2, m_Width, m_Height);
// Textures for several blur sizes. It would be possible to reuse
// m_BlurTex2b, thus avoiding the need for m_BlurTex4b and m_BlurTex8b, though given
// that these are fairly small it's probably not worth complicating the coordinates passed
// to the blur helper functions.
GEN_BUFFER_RGBA(m_BlurTex2a, m_Width / 2, m_Height / 2);
GEN_BUFFER_RGBA(m_BlurTex2b, m_Width / 2, m_Height / 2);
GEN_BUFFER_RGBA(m_BlurTex4a, m_Width / 4, m_Height / 4);
GEN_BUFFER_RGBA(m_BlurTex4b, m_Width / 4, m_Height / 4);
GEN_BUFFER_RGBA(m_BlurTex8a, m_Width / 8, m_Height / 8);
GEN_BUFFER_RGBA(m_BlurTex8b, m_Width / 8, m_Height / 8);
#undef GEN_BUFFER_RGBA
// Allocate the Depth/Stencil texture.
glGenTextures(1, (GLuint*)&m_DepthTex);
glBindTexture(GL_TEXTURE_2D, m_DepthTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, m_Width, m_Height,
0, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE,
GL_NONE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_2D, 0);
// Set up the framebuffers with some initial textures.
pglGenFramebuffersEXT(1, &m_PingFbo);
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PingFbo);
pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_ColourTex1, 0);
pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_DepthTex, 0);
GLenum status = pglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
{
LOGWARNING(L"Framebuffer object incomplete (A): 0x%04X", status);
}
pglGenFramebuffersEXT(1, &m_PongFbo);
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PongFbo);
pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_ColourTex2, 0);
pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_DepthTex, 0);
status = pglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
{
LOGWARNING(L"Framebuffer object incomplete (B): 0x%04X", status);
}
pglGenFramebuffersEXT(1, &m_BloomFbo);
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_BloomFbo);
/*pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_BloomTex1, 0);
status = pglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
{
LOGWARNING(L"Framebuffer object incomplete (B): 0x%04X", status);
}*/
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}
void CPostprocManager::ApplyBlurDownscale2x(GLuint inTex, GLuint outTex, int inWidth, int inHeight)
{
// Bind inTex to framebuffer for rendering.
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_BloomFbo);
pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, outTex, 0);
// Get bloom shader with instructions to simply copy texels.
CShaderDefines defines;
defines.Add("BLOOM_NOP", "1");
CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(CStrIntern("bloom"),
g_Renderer.GetSystemShaderDefines(), defines);
tech->BeginPass();
CShaderProgramPtr shader = tech->GetShader();
GLuint renderedTex = inTex;
// Cheat by creating high quality mipmaps for inTex, so the copying operation actually
// produces good scaling due to hardware filtering.
glBindTexture(GL_TEXTURE_2D, renderedTex);
pglGenerateMipmapEXT(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
shader->BindTexture("renderedTex", renderedTex);
glPushAttrib(GL_VIEWPORT_BIT);
glViewport(0, 0, inWidth / 2, inHeight / 2);
glBegin(GL_QUADS);
glColor4f(1.f, 1.f, 1.f, 1.f);
glTexCoord2f(1.0, 1.0); glVertex2f(1,1);
glTexCoord2f(0.0, 1.0); glVertex2f(-1,1);
glTexCoord2f(0.0, 0.0); glVertex2f(-1,-1);
glTexCoord2f(1.0, 0.0); glVertex2f(1,-1);
glEnd();
glPopAttrib();
tech->EndPass();
}
void CPostprocManager::ApplyBlurGauss(GLuint inOutTex, GLuint tempTex, int inWidth, int inHeight)
{
// Set tempTex as our rendering target.
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_BloomFbo);
pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, tempTex, 0);
// Get bloom shader, for a horizontal Gaussian blur pass.
CShaderDefines defines2;
defines2.Add("BLOOM_PASS_H", "1");
CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(CStrIntern("bloom"),
g_Renderer.GetSystemShaderDefines(), defines2);
tech->BeginPass();
CShaderProgramPtr shader = tech->GetShader();
shader->BindTexture("renderedTex", inOutTex);
shader->Uniform("texSize", inWidth, inHeight, 0.0f, 0.0f);
glPushAttrib(GL_VIEWPORT_BIT);
glViewport(0, 0, inWidth, inHeight);
glBegin(GL_QUADS);
glColor4f(1.f, 1.f, 1.f, 1.f);
glTexCoord2f(1.0, 1.0); glVertex2f(1,1);
glTexCoord2f(0.0, 1.0); glVertex2f(-1,1);
glTexCoord2f(0.0, 0.0); glVertex2f(-1,-1);
glTexCoord2f(1.0, 0.0); glVertex2f(1,-1);
glEnd();
glPopAttrib();
tech->EndPass();
// Set result texture as our render target.
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_BloomFbo);
pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, inOutTex, 0);
// Get bloom shader, for a vertical Gaussian blur pass.
CShaderDefines defines3;
defines3.Add("BLOOM_PASS_V", "1");
tech = g_Renderer.GetShaderManager().LoadEffect(CStrIntern("bloom"),
g_Renderer.GetSystemShaderDefines(), defines3);
tech->BeginPass();
shader = tech->GetShader();
// Our input texture to the shader is the output of the horizontal pass.
shader->BindTexture("renderedTex", tempTex);
shader->Uniform("texSize", inWidth, inHeight, 0.0f, 0.0f);
glPushAttrib(GL_VIEWPORT_BIT);
glViewport(0, 0, inWidth, inHeight);
glBegin(GL_QUADS);
glColor4f(1.f, 1.f, 1.f, 1.f);
glTexCoord2f(1.0, 1.0); glVertex2f(1,1);
glTexCoord2f(0.0, 1.0); glVertex2f(-1,1);
glTexCoord2f(0.0, 0.0); glVertex2f(-1,-1);
glTexCoord2f(1.0, 0.0); glVertex2f(1,-1);
glEnd();
glPopAttrib();
tech->EndPass();
}
void CPostprocManager::ApplyBlur()
{
glDisable(GL_BLEND);
GLint originalFBO;
glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &originalFBO);
int width = m_Width, height = m_Height;
#define SCALE_AND_BLUR(tex1, tex2, temptex) \
ApplyBlurDownscale2x(tex1, tex2, width, height); \
width /= 2; \
height /= 2; \
ApplyBlurGauss(tex2, temptex, width, height);
// We do the same thing for each scale, incrementally adding more and more blur.
SCALE_AND_BLUR(m_WhichBuffer ? m_ColourTex1 : m_ColourTex2, m_BlurTex2a, m_BlurTex2b);
SCALE_AND_BLUR(m_BlurTex2a, m_BlurTex4a, m_BlurTex4b);
SCALE_AND_BLUR(m_BlurTex4a, m_BlurTex8a, m_BlurTex8b);
#undef SCALE_AND_BLUR
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, originalFBO);
}
void CPostprocManager::CaptureRenderOutput()
{
// clear both FBOs and leave m_PingFbo selected for rendering;
// m_WhichBuffer stays true at this point
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PongFbo);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };
pglDrawBuffers(1, buffers);
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PingFbo);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
pglDrawBuffers(1, buffers);
m_WhichBuffer = true;
}
void CPostprocManager::ReleaseRenderOutput()
{
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// we blit to screen from the previous active buffer
if (m_WhichBuffer)
pglBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_PingFbo);
else
pglBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_PongFbo);
pglBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
pglBlitFramebufferEXT(0, 0, m_Width, m_Height, 0, 0, m_Width, m_Height,
GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
pglBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}
void CPostprocManager::LoadEffect(CStrW &name)
{
if (!m_IsInitialised)
return;
if (name != L"default")
{
CStrW n = L"postproc/" + name;
m_PostProcTech = g_Renderer.GetShaderManager().LoadEffect(n.ToUTF8().c_str());
}
m_PostProcEffect = name;
}
void CPostprocManager::ApplyEffect(CShaderTechniquePtr &shaderTech1, int pass)
{
// select the other FBO for rendering
if (!m_WhichBuffer)
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PingFbo);
else
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PongFbo);
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
shaderTech1->BeginPass(pass);
CShaderProgramPtr shader = shaderTech1->GetShader(pass);
shader->Bind();
// Use the textures from the current FBO as input to the shader.
// We also bind a bunch of other textures and parameters, but since
// this only happens once per frame the overhead is negligible.
if (m_WhichBuffer)
shader->BindTexture("renderedTex", m_ColourTex1);
else
shader->BindTexture("renderedTex", m_ColourTex2);
shader->BindTexture("depthTex", m_DepthTex);
shader->BindTexture("blurTex2", m_BlurTex2a);
shader->BindTexture("blurTex4", m_BlurTex4a);
shader->BindTexture("blurTex8", m_BlurTex8a);
shader->Uniform("width", m_Width);
shader->Uniform("height", m_Height);
shader->Uniform("zNear", g_Game->GetView()->GetNear());
shader->Uniform("zFar", g_Game->GetView()->GetFar());
shader->Uniform("brightness", g_LightEnv.m_Brightness);
shader->Uniform("hdr", g_LightEnv.m_Contrast);
shader->Uniform("saturation", g_LightEnv.m_Saturation);
shader->Uniform("bloom", g_LightEnv.m_Bloom);
glBegin(GL_QUADS);
glColor4f(1.f, 1.f, 1.f, 1.f);
glTexCoord2f(1.0, 1.0); glVertex2f(1,1);
glTexCoord2f(0.0, 1.0); glVertex2f(-1,1);
glTexCoord2f(0.0, 0.0); glVertex2f(-1,-1);
glTexCoord2f(1.0, 0.0); glVertex2f(1,-1);
glEnd();
shader->Unbind();
shaderTech1->EndPass(pass);
glDepthMask(GL_TRUE);
glEnable(GL_DEPTH_TEST);
m_WhichBuffer = !m_WhichBuffer;
}
void CPostprocManager::ApplyPostproc()
{
if (!m_IsInitialised)
return;
// Don't do anything if we are using the default effect.
if (m_PostProcEffect == L"default")
{
return;
}
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PongFbo);
pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, 0, 0);
GLenum buffers[] = { GL_COLOR_ATTACHMENT0 };
pglDrawBuffers(1, buffers);
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PingFbo);
pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, 0, 0);
pglDrawBuffers(1, buffers);
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PongFbo);
pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PingFbo);
pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
// First render blur textures. Note that this only happens ONLY ONCE, before any effects are applied!
// (This may need to change depending on future usage, however that will have a fps hit)
ApplyBlur();
for (int pass = 0; pass < m_PostProcTech->GetNumPasses(); ++pass)
{
ApplyEffect(m_PostProcTech, pass);
}
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PongFbo);
pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_DepthTex, 0);
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PingFbo);
pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_DepthTex, 0);
}
// Generate list of available effect-sets
std::vector<CStrW> CPostprocManager::GetPostEffects() const
{
std::vector<CStrW> effects;
const VfsPath path(L"shaders/effects/postproc/");
VfsPaths pathnames;
if(vfs::GetPathnames(g_VFS, path, 0, pathnames) < 0)
{
LOGERROR(L"Error finding Post effects in '%ls'", path.string().c_str());
}
for(size_t i = 0; i < pathnames.size(); i++)
{
if (pathnames[i].Extension() != L".xml")
continue;
effects.push_back(pathnames[i].Basename().string());
}
// Add the default "null" effect to the list.
effects.push_back(L"default");
sort(effects.begin(), effects.end());
return effects;
}
void CPostprocManager::SetPostEffect(CStrW name)
{
LoadEffect(name);
}

View File

@ -0,0 +1,115 @@
/* Copyright (C) 2012 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_POSTPROCMANAGER
#define INCLUDED_POSTPROCMANAGER
#include "graphics/ShaderTechnique.h"
class CPostprocManager
{
private:
// Two framebuffers, that we flip between at each shader pass.
GLuint m_PingFbo, m_PongFbo;
// Unique colour textures for the framebuffers.
GLuint m_ColourTex1, m_ColourTex2;
// The framebuffers share a depth/stencil texture.
GLuint m_DepthTex;
// A framebuffer and textures x2 for each blur level we render.
GLuint m_BloomFbo, m_BlurTex2a, m_BlurTex2b, m_BlurTex4a, m_BlurTex4b, m_BlurTex8a, m_BlurTex8b;
// Indicates which of the ping-pong buffers is used for reading and which for drawing.
bool m_WhichBuffer;
// The name and shader technique we are using. "default" name means no technique is used
// (i.e. while we do allocate the buffers, no effects are rendered).
CStrW m_PostProcEffect;
CShaderTechniquePtr m_PostProcTech;
// The current screen dimensions in pixels.
int m_Width, m_Height;
// Is the postproc manager initialised? Buffers created? Default effect loaded?
bool m_IsInitialised;
// Creates blur textures at various scales, for bloom, DOF, etc.
void ApplyBlur();
// High quality GPU image scaling to half size. outTex must have exactly half the size
// of inTex. inWidth and inHeight are the dimensions of inTex in texels.
void ApplyBlurDownscale2x(GLuint inTex, GLuint outTex, int inWidth, int inHeight);
// GPU-based Gaussian blur in two passes. inOutTex contains the input image and will be filled
// with the blurred image. tempTex must have the same size as inOutTex.
// inWidth and inHeight are the dimensions of the images in texels.
void ApplyBlurGauss(GLuint inOutTex, GLuint tempTex, int inWidth, int inHeight);
// Applies a pass of a given effect to the entire current framebuffer. The shader is
// provided with a number of general-purpose variables, including the rendered screen so far,
// the depth buffer, a number of blur textures, the screen size, the zNear/zFar planes and
// some other parameters used by the optional bloom/HDR pass.
void ApplyEffect(CShaderTechniquePtr &shaderTech1, int pass);
public:
CPostprocManager();
~CPostprocManager();
// Create all buffers/textures in GPU memory and set default effect.
void Initialize();
// Delete all allocated buffers/textures from GPU memory.
void Cleanup();
// Delete existing buffers/textures and create them again, using a new screen size if needed.
// (the textures are also attached to the framebuffers)
void RecreateBuffers();
// Loads a new postproc effect. "default" effect does NOT load anything.
void LoadEffect(CStrW &name);
// Returns a list of xml files found in shaders/effects/postproc.
std::vector<CStrW> GetPostEffects() const;
// Returns the name of the current effect.
inline const CStrW& GetPostEffect() const
{
return m_PostProcEffect;
}
// Matching setter that calls LoadEffect.
void SetPostEffect(CStrW name);
// Clears the two colour buffers and depth buffer, and redirects all rendering
// to our textures instead of directly to the system framebuffer.
void CaptureRenderOutput();
// First renders blur textures, then calls ApplyEffect for each effect pass,
// ping-ponging the buffers at each step.
void ApplyPostproc();
// Blits the final postprocessed texture to the system framebuffer. The system framebuffer
// is selected as the output buffer. Should be called before silhouette rendering.
void ReleaseRenderOutput();
};
#endif //INCLUDED_POSTPROCMANAGER

View File

@ -90,6 +90,9 @@ void ShaderRenderModifier::BeginPass(const CShaderProgramPtr& shader)
shader->Uniform("ambient", GetLightEnv()->m_UnitsAmbientColor);
shader->Uniform("sunDir", GetLightEnv()->GetSunDir());
shader->Uniform("sunColor", GetLightEnv()->m_SunColor);
shader->Uniform("fogColor", GetLightEnv()->m_FogColor);
shader->Uniform("fogParams", GetLightEnv()->m_FogFactor, GetLightEnv()->m_FogMax, 0.f, 0.f);
}
if (shader->GetTextureBinding("losTex").Active())

View File

@ -276,6 +276,9 @@ public:
/// Shadow map
ShadowMap shadow;
/// Postprocessing effect manager
CPostprocManager postprocManager;
/// Various model renderers
struct Models
@ -437,6 +440,7 @@ CRenderer::CRenderer()
m_Options.m_GPUSkinning = false;
m_Options.m_GenTangents = false;
m_Options.m_SmoothLOS = false;
m_Options.m_Postproc = false;
m_Options.m_ShowSky = false;
// TODO: be more consistent in use of the config system
@ -445,6 +449,7 @@ CRenderer::CRenderer()
CFG_GET_USER_VAL("gpuskinning", Bool, m_Options.m_GPUSkinning);
CFG_GET_USER_VAL("gentangents", Bool, m_Options.m_GenTangents);
CFG_GET_USER_VAL("smoothlos", Bool, m_Options.m_SmoothLOS);
CFG_GET_USER_VAL("postproc", Bool, m_Options.m_Postproc);
#if CONFIG2_GLES
// Override config option since GLES only supports GLSL
@ -642,6 +647,9 @@ bool CRenderer::Open(int width, int height)
// Let component renderers perform one-time initialization after graphics capabilities and
// the shader path have been determined.
m->overlayRenderer.Initialize();
if (m_Options.m_Postproc)
m->postprocManager.Initialize();
return true;
}
@ -654,6 +662,9 @@ void CRenderer::Resize(int width,int height)
m_Width = width;
m_Height = height;
if (m_Options.m_Postproc)
m->postprocManager.RecreateBuffers();
}
//////////////////////////////////////////////////////////////////////////////////////////
@ -1376,6 +1387,9 @@ void CRenderer::RenderSubmissions()
PROFILE3("render submissions");
GetScene().GetLOSTexture().InterpolateLOS();
if (m_Options.m_Postproc)
m->postprocManager.CaptureRenderOutput();
CShaderDefines context = m->globalContext;
@ -1495,6 +1509,12 @@ void CRenderer::RenderSubmissions()
RenderParticles();
ogl_WarnIfError();
}
if (m_Options.m_Postproc)
{
m->postprocManager.ApplyPostproc();
m->postprocManager.ReleaseRenderOutput();
}
if (m_Options.m_Silhouettes)
{
@ -1519,6 +1539,7 @@ void CRenderer::RenderSubmissions()
// render overlays that should appear on top of all other objects
m->overlayRenderer.RenderForegroundOverlays(m_ViewCamera);
ogl_WarnIfError();
}
///////////////////////////////////////////////////////////////////////////////////////////////////
@ -2035,3 +2056,8 @@ CMaterialManager& CRenderer::GetMaterialManager()
{
return m->materialManager;
}
CPostprocManager& CRenderer::GetPostprocManager()
{
return m->postprocManager;
}

View File

@ -30,6 +30,7 @@
#include "ps/Singleton.h"
#include "scripting/ScriptableObject.h"
#include "renderer/PostprocManager.h"
#include "renderer/Scene.h"
#include "renderer/TimeManager.h"
@ -135,6 +136,7 @@ public:
bool m_GenTangents;
bool m_SmoothLOS;
bool m_ShowSky;
bool m_Postproc;
} m_Options;
struct Caps {
@ -291,6 +293,8 @@ public:
CShaderDefines GetSystemShaderDefines();
CTimeManager& GetTimeManager();
CPostprocManager& GetPostprocManager();
/**
* GetCapabilities: Return which OpenGL capabilities are available and enabled.

View File

@ -83,6 +83,9 @@ struct ShadowMapInternals
// Copy of renderer's standard view camera, saved between
// BeginRender and EndRender while we replace it with the shadow camera
CCamera SavedViewCamera;
// Save the caller's FBO so it can be restored
GLint SavedViewFBO;
// Helper functions
void CalcShadowMatrices();
@ -318,6 +321,9 @@ void ShadowMapInternals::CreateTexture()
pglDeleteFramebuffersEXT(1, &Framebuffer);
Framebuffer = 0;
}
// save the caller's FBO
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &SavedViewFBO);
pglGenFramebuffersEXT(1, &Framebuffer);
@ -433,7 +439,7 @@ void ShadowMapInternals::CreateTexture()
GLenum status = pglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, SavedViewFBO);
if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
{
@ -450,6 +456,9 @@ void ShadowMapInternals::CreateTexture()
void ShadowMap::BeginRender()
{
// HACK HACK: this depends in non-obvious ways on the behaviour of the caller
// save caller's FBO
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &m->SavedViewFBO);
// Calc remaining shadow matrices
m->CalcShadowMatrices();
@ -502,7 +511,7 @@ void ShadowMap::EndRender()
{
PROFILE("unbind framebuffer");
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m->SavedViewFBO);
}
glViewport(0, 0, g_Renderer.GetWidth(), g_Renderer.GetHeight());

View File

@ -487,6 +487,9 @@ void TerrainRenderer::PrepareShader(const CShaderProgramPtr& shader, ShadowMap*
shader->Uniform("ambient", lightEnv.m_TerrainAmbientColor);
shader->Uniform("sunColor", lightEnv.m_SunColor);
shader->Uniform("fogColor", lightEnv.m_FogColor);
shader->Uniform("fogParams", lightEnv.m_FogFactor, lightEnv.m_FogMax, 0.f, 0.f);
}
void TerrainRenderer::RenderTerrainShader(const CShaderDefines& context, ShadowMap* shadow, bool filtered)
@ -702,6 +705,8 @@ bool TerrainRenderer::RenderFancyWater()
m->fancyWaterShader->Uniform("refractionMatrix", WaterMgr->m_RefractionMatrix);
m->fancyWaterShader->Uniform("losMatrix", losTexture.GetTextureMatrix());
m->fancyWaterShader->Uniform("cameraPos", camPos);
m->fancyWaterShader->Uniform("fogColor", lightEnv.m_FogColor);
m->fancyWaterShader->Uniform("fogParams", lightEnv.m_FogFactor, lightEnv.m_FogMax, 0.f, 0.f);
for (size_t i = 0; i < m->visiblePatches.size(); ++i)
{

View File

@ -385,7 +385,7 @@ void CSimulation2Impl::Update(int turnLength, const std::vector<SimulationComman
VfsPath mapfilename(VfsPath("maps/scenarios") / (mapFile + L".pmp"));
mapReader->LoadMap(mapfilename, &secondaryTerrain, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, &secondaryContext, INVALID_PLAYER, true); // throws exception on failure
NULL, NULL, &secondaryContext, INVALID_PLAYER, true); // throws exception on failure
}
else
{

View File

@ -68,7 +68,7 @@ public:
CMapReader* mapReader = new CMapReader(); // it'll call "delete this" itself
LDR_BeginRegistering();
mapReader->LoadMap(L"maps/scenarios/Median Oasis.pmp", &terrain, NULL, NULL, NULL, NULL, NULL, NULL,
mapReader->LoadMap(L"maps/scenarios/Median Oasis.pmp", &terrain, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
&sim2, &sim2.GetSimContext(), -1, false);
LDR_EndRegistering();
TS_ASSERT_OK(LDR_NonprogressiveLoad());

View File

@ -506,7 +506,7 @@ public:
CMapReader* mapReader = new CMapReader(); // it'll call "delete this" itself
LDR_BeginRegistering();
mapReader->LoadMap(L"maps/scenarios/Latium.pmp", &terrain, NULL, NULL, NULL, NULL, NULL, NULL,
mapReader->LoadMap(L"maps/scenarios/Latium.pmp", &terrain, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
&sim2, &sim2.GetSimContext(), -1, false);
LDR_EndRegistering();
TS_ASSERT_OK(LDR_NonprogressiveLoad());

View File

@ -227,13 +227,29 @@ 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());
sunSizer->Add(m_PostEffectList = new VariableListBox(this, _("Post Effect"), g_EnvironmentSettings.posteffect), wxSizerFlags().Expand());
wxSizer* fogSizer = new wxGridSizer(2);
m_MainSizer->Add(fogSizer, wxSizerFlags().Expand().Border(wxTOP, 8));
fogSizer->Add(new VariableSliderBox(this, _("Fog Factor"), g_EnvironmentSettings.fogfactor, 0.0, 0.01), wxSizerFlags().Expand());
fogSizer->Add(new VariableSliderBox(this, _("Fog Thickness"), g_EnvironmentSettings.fogmax, 0.5, 0.0), 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), wxSizerFlags().Expand());
wxSizer* SSSizer = new wxGridSizer(2);
m_MainSizer->Add(SSSizer, wxSizerFlags().Expand().Border(wxTOP, 8));
SSSizer->Add(new VariableSliderBox(this, _("Brightness"), g_EnvironmentSettings.brightness, -0.5, 0.5), wxSizerFlags().Expand());
SSSizer->Add(new VariableSliderBox(this, _("Contrast (HDR)"), g_EnvironmentSettings.contrast, 0.5, 1.5), wxSizerFlags().Expand());
SSSizer->Add(new VariableSliderBox(this, _("Saturation"), g_EnvironmentSettings.saturation, 0.0, 1.0), wxSizerFlags().Expand());
SSSizer->Add(new VariableSliderBox(this, _("Bloom"), g_EnvironmentSettings.bloom, 0.2, 0.0), wxSizerFlags().Expand());
m_MainSizer->Add(new VariableColourBox(this, _("Sun colour"), g_EnvironmentSettings.suncolour), wxSizerFlags().Expand());
m_MainSizer->Add(new VariableColourBox(this, _("Terrain ambient colour"), g_EnvironmentSettings.terraincolour), wxSizerFlags().Expand());
m_MainSizer->Add(new VariableColourBox(this, _("Object ambient colour"), g_EnvironmentSettings.unitcolour), wxSizerFlags().Expand());
m_MainSizer->Add(new VariableColourBox(this, _("Fog colour"), g_EnvironmentSettings.fogcolour), wxSizerFlags().Expand());
m_Conn = g_EnvironmentSettings.RegisterObserver(0, &SendToGame);
}
@ -245,17 +261,15 @@ void EnvironmentSidebar::OnFirstDisplay()
AtlasMessage::qGetSkySets qry_skysets;
qry_skysets.Post();
m_SkyList->SetChoices(*qry_skysets.skysets);
AtlasMessage::qGetPostEffects qry_effects;
qry_effects.Post();
m_PostEffectList->SetChoices(*qry_effects.posteffects);
AtlasMessage::qGetEnvironmentSettings qry_env;
qry_env.Post();
g_EnvironmentSettings = qry_env.settings;
std::vector<std::wstring> lightingModels;
lightingModels.push_back(L"standard");
m_LightingModelList->SetChoices(lightingModels);
g_EnvironmentSettings.NotifyObservers();
}

View File

@ -32,7 +32,7 @@ protected:
virtual void OnFirstDisplay();
private:
VariableListBox* m_LightingModelList;
VariableListBox* m_PostEffectList;
VariableListBox* m_SkyList;
ObservableScopedConnection m_Conn;
};

View File

@ -61,10 +61,18 @@ sEnvironmentSettings GetSettings()
sunrotation -= (float)M_PI*2;
s.sunrotation = sunrotation;
s.sunelevation = g_LightEnv.GetElevation();
s.lightingmodel = CStr(g_LightEnv.GetLightingModel()).FromUTF8();
s.posteffect = g_Renderer.GetPostprocManager().GetPostEffect();
s.skyset = g_Renderer.GetSkyManager()->GetSkySet();
s.fogfactor = g_LightEnv.m_FogFactor;
s.fogmax = g_LightEnv.m_FogMax;
s.brightness = g_LightEnv.m_Brightness;
s.contrast = g_LightEnv.m_Contrast;
s.saturation = g_LightEnv.m_Saturation;
s.bloom = g_LightEnv.m_Bloom;
// RGBColor (CVector3D) colours
#define COLOUR(A, B) A = Colour((int)(B.X*255), (int)(B.Y*255), (int)(B.Z*255))
@ -78,6 +86,7 @@ sEnvironmentSettings GetSettings()
COLOUR(s.suncolour, g_LightEnv.m_SunColor);
COLOUR(s.terraincolour, g_LightEnv.m_TerrainAmbientColor);
COLOUR(s.unitcolour, g_LightEnv.m_UnitsAmbientColor);
COLOUR(s.fogcolour, g_LightEnv.m_FogColor);
#undef COLOUR
return s;
@ -104,19 +113,31 @@ void SetSettings(const sEnvironmentSettings& s)
g_LightEnv.SetRotation(s.sunrotation);
g_LightEnv.SetElevation(s.sunelevation);
g_LightEnv.SetLightingModel(CStrW(*s.lightingmodel).ToUTF8());
CStrW posteffect = *s.posteffect;
if (posteffect.length() == 0)
posteffect = L"default";
g_Renderer.GetPostprocManager().SetPostEffect(posteffect);
CStrW skySet = *s.skyset;
if (skySet.length() == 0)
skySet = L"default";
g_Renderer.GetSkyManager()->SetSkySet(skySet);
g_LightEnv.m_FogFactor = s.fogfactor;
g_LightEnv.m_FogMax = s.fogmax;
g_LightEnv.m_Brightness = s.brightness;
g_LightEnv.m_Contrast = s.contrast;
g_LightEnv.m_Saturation = s.saturation;
g_LightEnv.m_Bloom = s.bloom;
#define COLOUR(A, B) B = RGBColor(A->r/255.f, A->g/255.f, A->b/255.f)
COLOUR(s.suncolour, g_LightEnv.m_SunColor);
g_LightEnv.m_SunColor *= s.sunoverbrightness;
COLOUR(s.terraincolour, g_LightEnv.m_TerrainAmbientColor);
COLOUR(s.unitcolour, g_LightEnv.m_UnitsAmbientColor);
COLOUR(s.fogcolour, g_LightEnv.m_FogColor);
#undef COLOUR
}
@ -159,4 +180,11 @@ QUERYHANDLER(GetSkySets)
msg->skysets = std::vector<std::wstring>(skies.begin(), skies.end());
}
QUERYHANDLER(GetPostEffects)
{
std::vector<CStrW> effects = g_Renderer.GetPostprocManager().GetPostEffects();
msg->posteffects = std::vector<std::wstring>(effects.begin(), effects.end());
}
}

View File

@ -231,6 +231,7 @@ MESSAGEHANDLER(SaveMap)
g_Game->GetWorld()->GetTerrain(),
g_Renderer.GetWaterManager(), g_Renderer.GetSkyManager(),
&g_LightEnv, g_Game->GetView()->GetCamera(), g_Game->GetView()->GetCinema(),
&g_Renderer.GetPostprocManager(),
g_Game->GetSimulation2());
}

View File

@ -432,13 +432,22 @@ struct sEnvironmentSettings
// 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> posteffect;
Shareable<std::wstring> skyset;
Shareable<Colour> suncolour;
Shareable<Colour> terraincolour;
Shareable<Colour> unitcolour;
Shareable<Colour> fogcolour;
Shareable<float> fogfactor;
Shareable<float> fogmax;
Shareable<float> brightness;
Shareable<float> contrast;
Shareable<float> saturation;
Shareable<float> bloom;
};
SHAREABLE_STRUCT(sEnvironmentSettings);
#endif
@ -459,6 +468,12 @@ QUERY(GetSkySets,
((std::vector<std::wstring>, skysets))
);
QUERY(GetPostEffects,
// no inputs
,
((std::vector<std::wstring>, posteffects))
);
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////