Index: ps/trunk/binaries/data/mods/public/shaders/arb/model_common.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/shaders/arb/model_common.xml (revision 11452)
+++ ps/trunk/binaries/data/mods/public/shaders/arb/model_common.xml (revision 11453)
@@ -1,28 +1,31 @@
-
-
-
-
-
+
+
+
+
+
+
+
+
Index: ps/trunk/binaries/data/mods/public/art/materials/playercolor_spec.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/art/materials/playercolor_spec.xml (nonexistent)
+++ ps/trunk/binaries/data/mods/public/art/materials/playercolor_spec.xml (revision 11453)
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
Index: ps/trunk/binaries/data/mods/public/art/materials/blend_spec.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/art/materials/blend_spec.xml (nonexistent)
+++ ps/trunk/binaries/data/mods/public/art/materials/blend_spec.xml (revision 11453)
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
Index: ps/trunk/binaries/data/mods/public/shaders/glsl/terrain_common.fs
===================================================================
--- ps/trunk/binaries/data/mods/public/shaders/glsl/terrain_common.fs (revision 11452)
+++ ps/trunk/binaries/data/mods/public/shaders/glsl/terrain_common.fs (revision 11453)
@@ -1,83 +1,102 @@
-#version 110
+#version 120
uniform sampler2D baseTex;
uniform sampler2D blendTex;
uniform sampler2D losTex;
-#ifdef USE_SHADOW
- #ifdef USE_SHADOW_SAMPLER
+#if USE_SHADOW
+ #if USE_SHADOW_SAMPLER
uniform sampler2DShadow shadowTex;
#else
uniform sampler2D shadowTex;
#endif
#endif
uniform vec3 shadingColor;
uniform vec3 ambient;
uniform vec4 shadowOffsets1;
uniform vec4 shadowOffsets2;
varying vec3 v_lighting;
varying vec2 v_tex;
varying vec4 v_shadow;
varying vec2 v_los;
varying vec2 v_blend;
+#if USE_SPECULAR
+ uniform float specularPower;
+ uniform vec3 specularColor;
+ varying vec3 v_normal;
+ varying vec3 v_half;
+#endif
+
float get_shadow()
{
- #ifdef USE_SHADOW
- #ifdef USE_SHADOW_SAMPLER
- #ifdef USE_SHADOW_PCF
+ #if USE_SHADOW
+ #if USE_SHADOW_SAMPLER
+ #if USE_SHADOW_PCF
return 0.25 * (
shadow2D(shadowTex, vec3(v_shadow.xy + shadowOffsets1.xy, v_shadow.z)).a +
shadow2D(shadowTex, vec3(v_shadow.xy + shadowOffsets1.zw, v_shadow.z)).a +
shadow2D(shadowTex, vec3(v_shadow.xy + shadowOffsets2.xy, v_shadow.z)).a +
shadow2D(shadowTex, vec3(v_shadow.xy + shadowOffsets2.zw, v_shadow.z)).a
);
#else
return shadow2D(shadowTex, v_shadow.xyz).a;
#endif
#else
if (v_shadow.z >= 1.0)
return 1.0;
- #ifdef USE_SHADOW_PCF
+ #if USE_SHADOW_PCF
return (
(v_shadow.z <= texture2D(shadowTex, v_shadow.xy + shadowOffsets1.xy).x ? 0.25 : 0.0) +
(v_shadow.z <= texture2D(shadowTex, v_shadow.xy + shadowOffsets1.zw).x ? 0.25 : 0.0) +
(v_shadow.z <= texture2D(shadowTex, v_shadow.xy + shadowOffsets2.xy).x ? 0.25 : 0.0) +
(v_shadow.z <= texture2D(shadowTex, v_shadow.xy + shadowOffsets2.zw).x ? 0.25 : 0.0)
);
#else
return (v_shadow.z <= texture2D(shadowTex, v_shadow.xy).x ? 1.0 : 0.0);
#endif
#endif
#else
return 1.0;
#endif
}
void main()
{
- #ifdef BLEND
+ #if BLEND
// Use alpha from blend texture
gl_FragColor.a = 1.0 - texture2D(blendTex, v_blend).a;
#endif
- // Load diffuse colour
- vec4 color = texture2D(baseTex, v_tex);
+ vec4 tex = texture2D(baseTex, v_tex);
- #ifdef DECAL
+ #if DECAL
// Use alpha from main texture
- gl_FragColor.a = color.a;
+ gl_FragColor.a = tex.a;
#endif
- color.rgb *= v_lighting * get_shadow() + ambient;
-
- color *= texture2D(losTex, v_los).a;
+ vec3 texdiffuse = tex.rgb;
+ vec3 sundiffuse = v_lighting;
+
+ #if USE_SPECULAR
+ // Interpolated v_normal needs to be re-normalized since it varies
+ // significantly between adjacenent vertexes;
+ // v_half changes very gradually so don't bother normalizing that
+ vec3 specular = specularColor * pow(max(0.0, dot(normalize(v_normal), v_half)), specularPower);
+ #else
+ vec3 specular = vec3(0.0);
+ #endif
+
+ vec3 color = (texdiffuse * sundiffuse + specular) * get_shadow() + texdiffuse * ambient;
+
+ float los = texture2D(losTex, v_los).a;
+ color *= los;
- #ifdef DECAL
- color.rgb *= shadingColor;
+ #if DECAL
+ color *= shadingColor;
#endif
- gl_FragColor.rgb = color.rgb;
+ gl_FragColor.rgb = color;
}
Index: ps/trunk/binaries/data/mods/public/shaders/glsl/model_common.fs
===================================================================
--- ps/trunk/binaries/data/mods/public/shaders/glsl/model_common.fs (revision 11452)
+++ ps/trunk/binaries/data/mods/public/shaders/glsl/model_common.fs (revision 11453)
@@ -1,98 +1,117 @@
-#version 110
+#version 120
uniform sampler2D baseTex;
uniform sampler2D losTex;
-#ifdef USE_SHADOW
- #ifdef USE_SHADOW_SAMPLER
+#if USE_SHADOW
+ #if USE_SHADOW_SAMPLER
uniform sampler2DShadow shadowTex;
#else
uniform sampler2D shadowTex;
#endif
#endif
-#ifdef USE_OBJECTCOLOR
+#if USE_OBJECTCOLOR
uniform vec3 objectColor;
#else
-#ifdef USE_PLAYERCOLOR
+#if USE_PLAYERCOLOR
uniform vec3 playerColor;
#endif
#endif
uniform vec3 shadingColor;
uniform vec3 ambient;
uniform vec4 shadowOffsets1;
uniform vec4 shadowOffsets2;
varying vec3 v_lighting;
varying vec2 v_tex;
varying vec4 v_shadow;
varying vec2 v_los;
+#if USE_SPECULAR
+ uniform float specularPower;
+ uniform vec3 specularColor;
+ varying vec3 v_normal;
+ varying vec3 v_half;
+#endif
+
float get_shadow()
{
- #ifdef USE_SHADOW
- #ifdef USE_SHADOW_SAMPLER
- #ifdef USE_SHADOW_PCF
+ #if USE_SHADOW
+ #if USE_SHADOW_SAMPLER
+ #if USE_SHADOW_PCF
return 0.25 * (
shadow2D(shadowTex, vec3(v_shadow.xy + shadowOffsets1.xy, v_shadow.z)).a +
shadow2D(shadowTex, vec3(v_shadow.xy + shadowOffsets1.zw, v_shadow.z)).a +
shadow2D(shadowTex, vec3(v_shadow.xy + shadowOffsets2.xy, v_shadow.z)).a +
shadow2D(shadowTex, vec3(v_shadow.xy + shadowOffsets2.zw, v_shadow.z)).a
);
#else
return shadow2D(shadowTex, v_shadow.xyz).a;
#endif
#else
if (v_shadow.z >= 1.0)
return 1.0;
- #ifdef USE_SHADOW_PCF
+ #if USE_SHADOW_PCF
return (
(v_shadow.z <= texture2D(shadowTex, v_shadow.xy + shadowOffsets1.xy).x ? 0.25 : 0.0) +
(v_shadow.z <= texture2D(shadowTex, v_shadow.xy + shadowOffsets1.zw).x ? 0.25 : 0.0) +
(v_shadow.z <= texture2D(shadowTex, v_shadow.xy + shadowOffsets2.xy).x ? 0.25 : 0.0) +
(v_shadow.z <= texture2D(shadowTex, v_shadow.xy + shadowOffsets2.zw).x ? 0.25 : 0.0)
);
#else
return (v_shadow.z <= texture2D(shadowTex, v_shadow.xy).x ? 1.0 : 0.0);
#endif
#endif
#else
return 1.0;
#endif
}
void main()
{
vec4 tex = texture2D(baseTex, v_tex);
- #ifdef USE_TRANSPARENT
+ #if USE_TRANSPARENT
gl_FragColor.a = tex.a;
#else
gl_FragColor.a = 1.0;
#endif
#ifdef REQUIRE_ALPHA_GREATER
if (gl_FragColor.a <= REQUIRE_ALPHA_GREATER)
discard;
#endif
- vec3 color = tex.rgb;
+ vec3 texdiffuse = tex.rgb;
// Apply-coloring based on texture alpha
- #ifdef USE_OBJECTCOLOR
- color *= mix(objectColor, vec3(1.0, 1.0, 1.0), tex.a);
+ #if USE_OBJECTCOLOR
+ texdiffuse *= mix(objectColor, vec3(1.0, 1.0, 1.0), tex.a);
#else
- #ifdef USE_PLAYERCOLOR
- color *= mix(playerColor, vec3(1.0, 1.0, 1.0), tex.a);
+ #if USE_PLAYERCOLOR
+ texdiffuse *= mix(playerColor, vec3(1.0, 1.0, 1.0), tex.a);
#endif
#endif
- color *= v_lighting * get_shadow() + ambient;
-
- color *= texture2D(losTex, v_los).a;
+ vec3 sundiffuse = v_lighting;
+
+ #if USE_SPECULAR
+ // Interpolated v_normal needs to be re-normalized since it varies
+ // significantly between adjacent vertexes;
+ // v_half changes very gradually so don't bother normalizing that
+ vec3 specular = specularColor * pow(max(0.0, dot(normalize(v_normal), v_half)), specularPower);
+ #else
+ vec3 specular = vec3(0.0);
+ #endif
+
+ vec3 color = (texdiffuse * sundiffuse + specular) * get_shadow() + texdiffuse * ambient;
+
+ float los = texture2D(losTex, v_los).a;
+ color *= los;
color *= shadingColor;
-
+
gl_FragColor.rgb = color;
}
Index: ps/trunk/binaries/data/mods/public/shaders/arb/model_common.vp
===================================================================
--- ps/trunk/binaries/data/mods/public/shaders/arb/model_common.vp (revision 11452)
+++ ps/trunk/binaries/data/mods/public/shaders/arb/model_common.vp (revision 11453)
@@ -1,54 +1,86 @@
!!ARBvp1.0
-PARAM sunDir = program.local[0];
-PARAM sunColor = program.local[1];
-PARAM losTransform = program.local[2];
-PARAM shadowTransform[4] = { program.local[3..6] };
+
+PARAM cameraPos = program.local[0];
+PARAM sunDir = program.local[1];
+PARAM sunColor = program.local[2];
+PARAM losTransform = program.local[3];
+PARAM shadowTransform[4] = { program.local[4..7] };
+#if USE_INSTANCING
+ PARAM instancingTransform[4] = { program.local[8..11] };
+#endif
+
+TEMP temp;
TEMP lighting;
+OUTPUT v_tex = result.texcoord[0];
+OUTPUT v_shadow = result.texcoord[1];
+OUTPUT v_los = result.texcoord[2];
+#if USE_SPECULAR
+ OUTPUT v_normal = result.texcoord[3];
+ OUTPUT v_half = result.texcoord[4];
+#endif
+
//// Compute position and normal:
-#ifdef USE_INSTANCING
- PARAM instancingTransform[4] = { program.local[7..10] };
+#if USE_INSTANCING
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;
+#if USE_SPECULAR
+ // eyeVec = normalize(cameraPos - position);
+ TEMP eyeVec;
+ SUB eyeVec.xyz, cameraPos, position;
+ DP3 eyeVec.w, eyeVec, eyeVec;
+ RSQ eyeVec.w, eyeVec.w;
+ MUL eyeVec.xyz, eyeVec, eyeVec.w;
+
+ // v_half = normalize(-sunDir + eyeVec);
+ TEMP half;
+ SUB half.xyz, eyeVec, sunDir;
+ DP3 half.w, half, half;
+ RSQ half.w, half.w;
+ MUL v_half.xyz, half, half.w;
+
+ MOV v_normal, normal;
+#endif
+
//// Texture coordinates:
-MOV result.texcoord[0], vertex.texcoord[0];
+MOV v_tex, 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;
+#if USE_SHADOW
+ DP4 v_shadow.x, shadowTransform[0], position;
+ DP4 v_shadow.y, shadowTransform[1], position;
+ DP4 v_shadow.z, shadowTransform[2], position;
+ DP4 v_shadow.w, shadowTransform[3], position;
#endif
-MAD result.texcoord[2], position.xzzz, losTransform.x, losTransform.y;
+MAD v_los, position.xzzz, losTransform.x, losTransform.y;
END
Index: ps/trunk/source/ps/CStrIntern.h
===================================================================
--- ps/trunk/source/ps/CStrIntern.h (revision 11452)
+++ ps/trunk/source/ps/CStrIntern.h (revision 11453)
@@ -1,81 +1,86 @@
/* 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 .
*/
#ifndef INCLUDED_CSTRINTERN
#define INCLUDED_CSTRINTERN
class CStrInternInternals;
/**
* Interned 8-bit strings.
* Each instance with the same string content is a pointer to the same piece of
* memory, allowing very fast string comparisons.
*
* Since a CStrIntern is just a dumb pointer, copying is very fast,
* and pass-by-value should be preferred over pass-by-reference.
*
* Memory allocated for strings will never be freed, so don't use this for
* unbounded numbers of strings (e.g. text rendered by gameplay scripts) -
* it's intended for a small number of short frequently-used strings.
*
* Not thread-safe - only allocate these strings from the main thread.
*/
class CStrIntern
{
public:
CStrIntern();
explicit CStrIntern(const char* str);
explicit CStrIntern(const std::string& str);
/**
* Returns cached FNV1-A hash of the string.
*/
u32 GetHash() const;
/**
* Returns null-terminated string.
*/
const char* c_str() const;
/**
+ * Returns length of string in bytes.
+ */
+ size_t length() const;
+
+ /**
* Returns as std::string.
*/
const std::string& string() const;
/**
* String equality.
*/
bool operator==(const CStrIntern& b) const
{
return m == b.m;
}
/**
* Compare with some arbitrary total order.
* (In particular, this is not alphabetic order,
* and is not consistent between runs of the game.)
*/
bool operator<(const CStrIntern& b) const
{
return m < b.m;
}
private:
CStrInternInternals* m;
};
#endif // INCLUDED_CSTRINTERN
\ No newline at end of file
Index: ps/trunk/source/ps/CStrIntern.cpp
===================================================================
--- ps/trunk/source/ps/CStrIntern.cpp (revision 11452)
+++ ps/trunk/source/ps/CStrIntern.cpp (revision 11453)
@@ -1,143 +1,148 @@
/* 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 .
*/
#include "precompiled.h"
#include "CStrIntern.h"
#include "lib/fnv_hash.h"
#include "ps/CLogger.h"
#include
class CStrInternInternals
{
public:
CStrInternInternals(const char* str, size_t len)
: data(str, str+len), hash(fnv_hash(str, len))
{
// LOGWARNING(L"New interned string '%hs'", data.c_str());
}
bool operator==(const CStrInternInternals& b) const
{
// Compare hash first for quick rejection of inequal strings
return (hash == b.hash && data == b.data);
}
const std::string data;
const u32 hash; // fnv_hash of data
private:
CStrInternInternals& operator=(const CStrInternInternals&);
};
// Interned strings are stored in a hash table, indexed by string:
typedef std::string StringsKey;
struct StringsKeyHash
{
size_t operator()(const StringsKey& key) const
{
return fnv_hash(key.c_str(), key.length());
}
};
// To avoid std::string memory allocations when GetString does lookups in the
// hash table of interned strings, we make use of boost::unordered_map's ability
// to do lookups with a functionally equivalent proxy object:
struct StringsKeyProxy
{
const char* str;
size_t len;
};
struct StringsKeyProxyHash
{
size_t operator()(const StringsKeyProxy& key) const
{
return fnv_hash(key.str, key.len);
}
};
struct StringsKeyProxyEq
{
bool operator()(const StringsKeyProxy& proxy, const StringsKey& key) const
{
return (proxy.len == key.length() && memcmp(proxy.str, key.c_str(), proxy.len) == 0);
}
};
static boost::unordered_map, StringsKeyHash> g_Strings;
static CStrInternInternals* GetString(const char* str, size_t len)
{
// g_Strings is not thread-safe, so complain if anyone is using this
// type in non-main threads. (If that's desired, g_Strings should be changed
// to be thread-safe, preferably without sacrificing performance.)
ENSURE(ThreadUtil::IsMainThread());
#if BOOST_VERSION >= 104200
StringsKeyProxy proxy = { str, len };
boost::unordered_map >::iterator it =
g_Strings.find(proxy, StringsKeyProxyHash(), StringsKeyProxyEq());
#else
// Boost <= 1.41 doesn't support the new find(), so do a slightly less efficient lookup
boost::unordered_map >::iterator it =
g_Strings.find(str);
#endif
if (it != g_Strings.end())
return it->second.get();
shared_ptr internals(new CStrInternInternals(str, len));
g_Strings.insert(std::make_pair(internals->data, internals));
return internals.get();
}
CStrIntern::CStrIntern()
{
m = GetString("", 0);
}
CStrIntern::CStrIntern(const char* str)
{
m = GetString(str, strlen(str));
}
CStrIntern::CStrIntern(const std::string& str)
{
m = GetString(str.c_str(), str.length());
}
u32 CStrIntern::GetHash() const
{
return m->hash;
}
const char* CStrIntern::c_str() const
{
return m->data.c_str();
}
+size_t CStrIntern::length() const
+{
+ return m->data.length();
+}
+
const std::string& CStrIntern::string() const
{
return m->data;
}
Index: ps/trunk/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Environment/Environment.cpp
===================================================================
--- ps/trunk/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Environment/Environment.cpp (revision 11452)
+++ ps/trunk/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Environment/Environment.cpp (revision 11453)
@@ -1,270 +1,269 @@
/* Copyright (C) 2009 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 .
*/
#include "precompiled.h"
#include "Environment.h"
#include "LightControl.h"
#include "GameInterface/Messages.h"
#include "ScenarioEditor/ScenarioEditor.h"
#include "General/Observable.h"
#include "CustomControls/ColourDialog/ColourDialog.h"
using AtlasMessage::Shareable;
static Observable g_EnvironmentSettings;
const float M_PIf = 3.14159265f;
//////////////////////////////////////////////////////////////////////////
class VariableSliderBox : public wxPanel
{
static const int range = 1024;
public:
VariableSliderBox(wxWindow* parent, const wxString& label, Shareable& var, float min, float max)
: wxPanel(parent),
m_Var(var), m_Min(min), m_Max(max)
{
m_Conn = g_EnvironmentSettings.RegisterObserver(0, &VariableSliderBox::OnSettingsChange, this);
m_Sizer = new wxStaticBoxSizer(wxVERTICAL, this, label);
SetSizer(m_Sizer);
m_Slider = new wxSlider(this, -1, 0, 0, range);
m_Sizer->Add(m_Slider, wxSizerFlags().Expand());
}
void OnSettingsChange(const AtlasMessage::sEnvironmentSettings& WXUNUSED(env))
{
m_Slider->SetValue((m_Var - m_Min) * (range / (m_Max - m_Min)));
}
void OnScroll(wxScrollEvent& evt)
{
m_Var = m_Min + (m_Max - m_Min)*(evt.GetInt() / (float)range);
g_EnvironmentSettings.NotifyObserversExcept(m_Conn);
}
private:
ObservableScopedConnection m_Conn;
wxStaticBoxSizer* m_Sizer;
wxSlider* m_Slider;
Shareable& m_Var;
float m_Min, m_Max;
DECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(VariableSliderBox, wxPanel)
EVT_SCROLL(VariableSliderBox::OnScroll)
END_EVENT_TABLE()
//////////////////////////////////////////////////////////////////////////
class VariableListBox : public wxPanel
{
public:
VariableListBox(wxWindow* parent, const wxString& label, Shareable& var)
: wxPanel(parent),
m_Var(var)
{
m_Conn = g_EnvironmentSettings.RegisterObserver(0, &VariableListBox::OnSettingsChange, this);
m_Sizer = new wxStaticBoxSizer(wxVERTICAL, this, label);
SetSizer(m_Sizer);
m_Combo = new wxComboBox(this, -1, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxArrayString(), wxCB_READONLY),
m_Sizer->Add(m_Combo, wxSizerFlags().Expand());
}
void SetChoices(const std::vector& choices)
{
wxArrayString choices_arraystr;
for (size_t i = 0; i < choices.size(); ++i)
choices_arraystr.Add(choices[i].c_str());
m_Combo->Clear();
m_Combo->Append(choices_arraystr);
m_Combo->SetValue(m_Var.c_str());
}
void OnSettingsChange(const AtlasMessage::sEnvironmentSettings& WXUNUSED(env))
{
m_Combo->SetValue(m_Var.c_str());
}
void OnSelect(wxCommandEvent& WXUNUSED(evt))
{
m_Var = std::wstring(m_Combo->GetValue().c_str());
g_EnvironmentSettings.NotifyObserversExcept(m_Conn);
}
private:
ObservableScopedConnection m_Conn;
wxStaticBoxSizer* m_Sizer;
wxComboBox* m_Combo;
Shareable& m_Var;
DECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(VariableListBox, wxPanel)
EVT_COMBOBOX(wxID_ANY, VariableListBox::OnSelect)
END_EVENT_TABLE()
//////////////////////////////////////////////////////////////////////////
class VariableColourBox : public wxPanel
{
public:
VariableColourBox(wxWindow* parent, const wxString& label, Shareable& colour)
: wxPanel(parent),
m_Colour(colour)
{
m_Conn = g_EnvironmentSettings.RegisterObserver(0, &VariableColourBox::OnSettingsChange, this);
m_Sizer = new wxStaticBoxSizer(wxVERTICAL, this, label);
SetSizer(m_Sizer);
m_Button = new wxButton(this, -1);
m_Sizer->Add(m_Button, wxSizerFlags().Expand());
}
void OnSettingsChange(const AtlasMessage::sEnvironmentSettings& WXUNUSED(env))
{
UpdateButton();
}
void OnClick(wxCommandEvent& WXUNUSED(evt))
{
ColourDialog dlg (this, _T("Scenario Editor/LightingColour"),
wxColour(m_Colour->r, m_Colour->g, m_Colour->b));
if (dlg.ShowModal() == wxID_OK)
{
wxColour& c = dlg.GetColourData().GetColour();
m_Colour = AtlasMessage::Colour(c.Red(), c.Green(), c.Blue());
UpdateButton();
g_EnvironmentSettings.NotifyObserversExcept(m_Conn);
}
}
void UpdateButton()
{
m_Button->SetBackgroundColour(wxColour(m_Colour->r, m_Colour->g, m_Colour->b));
m_Button->SetLabel(wxString::Format(_T("%02X %02X %02X"), m_Colour->r, m_Colour->g, m_Colour->b));
int y = 3*m_Colour->r + 6*m_Colour->g + 1*m_Colour->b;
if (y > 1280)
m_Button->SetForegroundColour(wxColour(0, 0, 0));
else
m_Button->SetForegroundColour(wxColour(255, 255, 255));
}
private:
ObservableScopedConnection m_Conn;
wxStaticBoxSizer* m_Sizer;
wxButton* m_Button;
Shareable& m_Colour;
DECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(VariableColourBox, wxPanel)
EVT_BUTTON(wxID_ANY, VariableColourBox::OnClick)
END_EVENT_TABLE()
//////////////////////////////////////////////////////////////////////////
static void SendToGame(const AtlasMessage::sEnvironmentSettings& settings)
{
POST_COMMAND(SetEnvironmentSettings, (settings));
}
EnvironmentSidebar::EnvironmentSidebar(ScenarioEditor& scenarioEditor, wxWindow* sidebarContainer, wxWindow* bottomBarContainer)
: Sidebar(scenarioEditor, sidebarContainer, bottomBarContainer)
{
wxSizer* waterSizer = new wxGridSizer(2);
m_MainSizer->Add(waterSizer, wxSizerFlags().Expand());
waterSizer->Add(new VariableSliderBox(this, _("Water height"), g_EnvironmentSettings.waterheight, 0.f, 1.2f), wxSizerFlags().Expand());
waterSizer->Add(new VariableSliderBox(this, _("Water shininess"), g_EnvironmentSettings.watershininess, 0.f, 250.f), wxSizerFlags().Expand());
waterSizer->Add(new VariableSliderBox(this, _("Water waviness"), g_EnvironmentSettings.waterwaviness, 0.f, 10.f), wxSizerFlags().Expand());
waterSizer->Add(new VariableSliderBox(this, _("Water murkiness"), g_EnvironmentSettings.watermurkiness, 0.f, 1.f), wxSizerFlags().Expand());
waterSizer->Add(new VariableColourBox(this, _("Water colour"), g_EnvironmentSettings.watercolour), wxSizerFlags().Expand());
waterSizer->Add(new VariableColourBox(this, _("Water tint"), g_EnvironmentSettings.watertint), wxSizerFlags().Expand());
waterSizer->Add(new VariableColourBox(this, _("Reflection tint"), g_EnvironmentSettings.waterreflectiontint), wxSizerFlags().Expand());
waterSizer->Add(new VariableSliderBox(this, _("Refl. tint strength"), g_EnvironmentSettings.waterreflectiontintstrength, 0.f, 1.f), wxSizerFlags().Expand());
wxSizer* sunSizer = new wxGridSizer(2);
m_MainSizer->Add(sunSizer, wxSizerFlags().Expand().Border(wxTOP, 8));
sunSizer->Add(new VariableSliderBox(this, _("Sun rotation"), g_EnvironmentSettings.sunrotation, -M_PIf, M_PIf), wxSizerFlags().Expand());
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), 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_Conn = g_EnvironmentSettings.RegisterObserver(0, &SendToGame);
}
void EnvironmentSidebar::OnFirstDisplay()
{
// Load the list of skies. (Can only be done now rather than in the constructor,
// after the game has been initialised.)
AtlasMessage::qGetSkySets qry_skysets;
qry_skysets.Post();
m_SkyList->SetChoices(*qry_skysets.skysets);
AtlasMessage::qGetEnvironmentSettings qry_env;
qry_env.Post();
g_EnvironmentSettings = qry_env.settings;
std::vector lightingModels;
- lightingModels.push_back(L"old");
lightingModels.push_back(L"standard");
m_LightingModelList->SetChoices(lightingModels);
g_EnvironmentSettings.NotifyObservers();
}
void EnvironmentSidebar::OnMapReload()
{
AtlasMessage::qGetEnvironmentSettings qry_env;
qry_env.Post();
g_EnvironmentSettings = qry_env.settings;
g_EnvironmentSettings.NotifyObservers();
}
Index: ps/trunk/source/graphics/Material.h
===================================================================
--- ps/trunk/source/graphics/Material.h (revision 11452)
+++ ps/trunk/source/graphics/Material.h (revision 11453)
@@ -1,64 +1,62 @@
/* 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 .
*/
#ifndef INCLUDED_MATERIAL
#define INCLUDED_MATERIAL
#include "graphics/ShaderDefines.h"
#include "graphics/Texture.h"
#include "ps/CStr.h"
#include "ps/CStrIntern.h"
#include "ps/Overlay.h"
#include "simulation2/helpers/Player.h"
class CMaterial
{
public:
CMaterial();
// Whether this material's shaders use alpha blending, in which case
// models using this material need to be rendered in a special order
// relative to the alpha-blended water plane
void SetUsesAlphaBlending(bool flag) { m_AlphaBlending = flag; }
bool UsesAlphaBlending() { return m_AlphaBlending; }
- // Color used for "objectColor" in shaders when USE_OBJECTCOLOR is set,
- // to allow e.g. variations in horse colorings
- void SetObjectColor(const CColor &colour);
- CColor GetObjectColor() { return m_ObjectColor; }
-
void SetDiffuseTexture(const CTexturePtr& texture);
const CTexturePtr& GetDiffuseTexture() const { return m_DiffuseTexture; }
void SetShaderEffect(const CStr& effect);
CStrIntern GetShaderEffect() const { return m_ShaderEffect; }
void AddShaderDefine(const char* key, const char* value);
const CShaderDefines& GetShaderDefines() const { return m_ShaderDefines; }
+ void AddStaticUniform(const char* key, const CVector4D& value);
+ const CShaderUniforms& GetStaticUniforms() const { return m_StaticUniforms; }
+
private:
CTexturePtr m_DiffuseTexture;
CStrIntern m_ShaderEffect;
CShaderDefines m_ShaderDefines;
+ CShaderUniforms m_StaticUniforms;
bool m_AlphaBlending;
player_id_t m_PlayerID;
- CColor m_ObjectColor;
};
#endif
Index: ps/trunk/source/graphics/ShaderProgram.cpp
===================================================================
--- ps/trunk/source/graphics/ShaderProgram.cpp (revision 11452)
+++ ps/trunk/source/graphics/ShaderProgram.cpp (revision 11453)
@@ -1,854 +1,863 @@
/* 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 .
*/
#include "precompiled.h"
#include "ShaderProgram.h"
#include "graphics/ShaderManager.h"
#include "graphics/TextureManager.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"
#if !CONFIG2_GLES
class CShaderProgramARB : public CShaderProgram
{
public:
CShaderProgramARB(const VfsPath& vertexFile, const VfsPath& fragmentFile,
const CShaderDefines& defines,
- const std::map& vertexIndexes, const std::map& fragmentIndexes,
+ const std::map& vertexIndexes, const std::map& 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);
}
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() + std::min((int)code.length(), 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;
- std::map definesMap = m_Defines.GetMap();
- for (std::map::const_iterator it = definesMap.begin(); it != definesMap.end(); ++it)
+ std::map definesMap = m_Defines.GetMap();
+ for (std::map::const_iterator it = definesMap.begin(); it != definesMap.end(); ++it)
preprocessor.Define(it->first.c_str(), it->first.length(), it->second.c_str(), it->second.length());
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);
BindClientStates();
}
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);
UnbindClientStates();
// TODO: should unbind textures, probably
}
- int GetUniformVertexIndex(uniform_id_t id)
+ int GetUniformVertexIndex(CStrIntern id)
{
- std::map::iterator it = m_VertexIndexes.find(id);
+ std::map::iterator it = m_VertexIndexes.find(id);
if (it == m_VertexIndexes.end())
return -1;
return it->second;
}
- int GetUniformFragmentIndex(uniform_id_t id)
+ int GetUniformFragmentIndex(CStrIntern id)
{
- std::map::iterator it = m_FragmentIndexes.find(id);
+ std::map::iterator it = m_FragmentIndexes.find(id);
if (it == m_FragmentIndexes.end())
return -1;
return it->second;
}
virtual Binding GetTextureBinding(texture_id_t id)
{
- int index = GetUniformFragmentIndex(id);
+ int index = GetUniformFragmentIndex(CStrIntern(id));
if (index == -1)
return Binding();
else
return Binding((int)GL_TEXTURE_2D, index);
}
virtual void BindTexture(texture_id_t id, Handle tex)
{
- int index = GetUniformFragmentIndex(id);
+ int index = GetUniformFragmentIndex(CStrIntern(id));
if (index != -1)
{
GLuint h;
ogl_tex_get_texture_id(tex, &h);
pglActiveTextureARB(GL_TEXTURE0+index);
glBindTexture(GL_TEXTURE_2D, h);
}
}
virtual void BindTexture(texture_id_t id, GLuint tex)
{
- int index = GetUniformFragmentIndex(id);
+ int index = GetUniformFragmentIndex(CStrIntern(id));
if (index != -1)
{
pglActiveTextureARB(GL_TEXTURE0+index);
glBindTexture(GL_TEXTURE_2D, tex);
}
}
virtual void BindTexture(Binding id, Handle tex)
{
int index = id.second;
if (index != -1)
ogl_tex_bind(tex, index);
}
virtual Binding GetUniformBinding(uniform_id_t id)
{
+ CStrIntern idIntern(id);
+ return Binding(GetUniformVertexIndex(idIntern), GetUniformFragmentIndex(idIntern));
+ }
+
+ virtual Binding GetUniformBinding(CStrIntern id)
+ {
return Binding(GetUniformVertexIndex(id), GetUniformFragmentIndex(id));
}
virtual void Uniform(Binding id, float v0, float v1, float v2, float v3)
{
if (id.first != -1)
pglProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, (GLuint)id.first, v0, v1, v2, v3);
if (id.second != -1)
pglProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, (GLuint)id.second, v0, v1, v2, v3);
}
virtual void Uniform(Binding id, const CMatrix3D& v)
{
if (id.first != -1)
{
pglProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, (GLuint)id.first+0, v._11, v._12, v._13, v._14);
pglProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, (GLuint)id.first+1, v._21, v._22, v._23, v._24);
pglProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, (GLuint)id.first+2, v._31, v._32, v._33, v._34);
pglProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, (GLuint)id.first+3, v._41, v._42, v._43, v._44);
}
if (id.second != -1)
{
pglProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, (GLuint)id.second+0, v._11, v._12, v._13, v._14);
pglProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, (GLuint)id.second+1, v._21, v._22, v._23, v._24);
pglProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, (GLuint)id.second+2, v._31, v._32, v._33, v._34);
pglProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, (GLuint)id.second+3, v._41, v._42, v._43, v._44);
}
}
private:
VfsPath m_VertexFile;
VfsPath m_FragmentFile;
CShaderDefines m_Defines;
GLuint m_VertexProgram;
GLuint m_FragmentProgram;
- std::map m_VertexIndexes;
- std::map m_FragmentIndexes;
+ std::map m_VertexIndexes;
+ std::map m_FragmentIndexes;
};
#endif // #if !CONFIG2_GLES
//////////////////////////////////////////////////////////////////////////
TIMER_ADD_CLIENT(tc_ShaderGLSLCompile);
TIMER_ADD_CLIENT(tc_ShaderGLSLLink);
class CShaderProgramGLSL : public CShaderProgram
{
public:
CShaderProgramGLSL(const VfsPath& vertexFile, const VfsPath& fragmentFile,
const CShaderDefines& defines,
- const std::map& vertexAttribs,
+ const std::map& vertexAttribs,
int streamflags) :
CShaderProgram(streamflags),
m_VertexFile(vertexFile), m_FragmentFile(fragmentFile),
m_Defines(defines),
m_VertexAttribs(vertexAttribs)
{
m_Program = 0;
m_VertexShader = pglCreateShaderObjectARB(GL_VERTEX_SHADER);
m_FragmentShader = pglCreateShaderObjectARB(GL_FRAGMENT_SHADER);
}
~CShaderProgramGLSL()
{
Unload();
pglDeleteShader(m_VertexShader);
pglDeleteShader(m_FragmentShader);
}
bool Compile(GLhandleARB shader, const VfsPath& file, const CStr& code)
{
TIMER_ACCRUE(tc_ShaderGLSLCompile);
ogl_WarnIfError();
const char* code_string = code.c_str();
GLint code_length = code.length();
pglShaderSourceARB(shader, 1, &code_string, &code_length);
pglCompileShaderARB(shader);
GLint ok = 0;
pglGetShaderiv(shader, GL_COMPILE_STATUS, &ok);
GLint length = 0;
pglGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
// Apparently sometimes GL_INFO_LOG_LENGTH is incorrectly reported as 0
// (http://code.google.com/p/android/issues/detail?id=9953)
if (!ok && length == 0)
length = 4096;
if (length > 1)
{
char* infolog = new char[length];
pglGetShaderInfoLog(shader, length, NULL, infolog);
if (ok)
LOGMESSAGE(L"Info when compiling shader '%ls':\n%hs", file.string().c_str(), infolog);
else
LOGERROR(L"Failed to compile shader '%ls':\n%hs", file.string().c_str(), infolog);
delete[] infolog;
}
ogl_WarnIfError();
return (ok ? true : false);
}
bool Link()
{
TIMER_ACCRUE(tc_ShaderGLSLLink);
ENSURE(!m_Program);
m_Program = pglCreateProgramObjectARB();
pglAttachObjectARB(m_Program, m_VertexShader);
ogl_WarnIfError();
pglAttachObjectARB(m_Program, m_FragmentShader);
ogl_WarnIfError();
// Set up the attribute bindings explicitly, since apparently drivers
// don't always pick the most efficient bindings automatically,
// and also this lets us hardcode indexes into VertexPointer etc
- for (std::map::iterator it = m_VertexAttribs.begin(); it != m_VertexAttribs.end(); ++it)
+ for (std::map::iterator it = m_VertexAttribs.begin(); it != m_VertexAttribs.end(); ++it)
pglBindAttribLocationARB(m_Program, it->second, it->first.c_str());
pglLinkProgramARB(m_Program);
GLint ok = 0;
pglGetProgramiv(m_Program, GL_LINK_STATUS, &ok);
GLint length = 0;
pglGetProgramiv(m_Program, GL_INFO_LOG_LENGTH, &length);
if (!ok && length == 0)
length = 4096;
if (length > 1)
{
char* infolog = new char[length];
pglGetProgramInfoLog(m_Program, length, NULL, infolog);
if (ok)
LOGMESSAGE(L"Info when linking program '%ls'+'%ls':\n%hs", m_VertexFile.string().c_str(), m_FragmentFile.string().c_str(), infolog);
else
LOGERROR(L"Failed to link program '%ls'+'%ls':\n%hs", m_VertexFile.string().c_str(), m_FragmentFile.string().c_str(), infolog);
delete[] infolog;
}
ogl_WarnIfError();
if (!ok)
return false;
- m_UniformLocations.clear();
- m_UniformTypes.clear();
+ m_Uniforms.clear();
m_Samplers.clear();
Bind();
ogl_WarnIfError();
GLint numUniforms = 0;
pglGetProgramiv(m_Program, GL_ACTIVE_UNIFORMS, &numUniforms);
ogl_WarnIfError();
for (GLint i = 0; i < numUniforms; ++i)
{
char name[256] = {0};
GLsizei nameLength = 0;
GLint size = 0;
GLenum type = 0;
pglGetActiveUniformARB(m_Program, i, ARRAY_SIZE(name), &nameLength, &size, &type, name);
ogl_WarnIfError();
GLint loc = pglGetUniformLocationARB(m_Program, name);
- m_UniformLocations[name] = loc;
- m_UniformTypes[name] = type;
+ CStrIntern nameIntern(name);
+ m_Uniforms[nameIntern] = std::make_pair(loc, type);
// Assign sampler uniforms to sequential texture units
if (type == GL_SAMPLER_2D
|| type == GL_SAMPLER_CUBE
#if !CONFIG2_GLES
|| type == GL_SAMPLER_2D_SHADOW
#endif
)
{
int unit = (int)m_Samplers.size();
- m_Samplers[name].first = (type == GL_SAMPLER_CUBE ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D);
- m_Samplers[name].second = unit;
+ m_Samplers[nameIntern].first = (type == GL_SAMPLER_CUBE ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D);
+ m_Samplers[nameIntern].second = unit;
pglUniform1iARB(loc, unit); // link uniform to unit
ogl_WarnIfError();
}
}
// TODO: verify that we're not using more samplers than is supported
Unbind();
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;
- std::map definesMap = m_Defines.GetMap();
- for (std::map::const_iterator it = definesMap.begin(); it != definesMap.end(); ++it)
+ std::map definesMap = m_Defines.GetMap();
+ for (std::map::const_iterator it = definesMap.begin(); it != definesMap.end(); ++it)
preprocessor.Define(it->first.c_str(), it->first.length(), it->second.c_str(), it->second.length());
#if CONFIG2_GLES
// GLES defines the macro "GL_ES" in its GLSL preprocessor,
// but since we run our own preprocessor first, we need to explicitly
// define it here
preprocessor.Define("GL_ES", "1");
#endif
CStr vertexCode = Preprocess(preprocessor, vertexFile.GetAsString());
CStr fragmentCode = Preprocess(preprocessor, fragmentFile.GetAsString());
#if CONFIG2_GLES
- // Ugly hack to replace desktop GLSL 1.10 with GLSL ES 1.00,
+ // Ugly hack to replace desktop GLSL 1.10/1.20 with GLSL ES 1.00,
// and also to set default float precision for fragment shaders
vertexCode.Replace("#version 110\n", "#version 100\n");
vertexCode.Replace("#version 110\r\n", "#version 100\n");
+ vertexCode.Replace("#version 120\n", "#version 100\n");
+ vertexCode.Replace("#version 120\r\n", "#version 100\n");
fragmentCode.Replace("#version 110\n", "#version 100\nprecision mediump float;\n");
fragmentCode.Replace("#version 110\r\n", "#version 100\nprecision mediump float;\n");
+ fragmentCode.Replace("#version 120\n", "#version 100\nprecision mediump float;\n");
+ fragmentCode.Replace("#version 120\r\n", "#version 100\nprecision mediump float;\n");
#endif
if (!Compile(m_VertexShader, m_VertexFile, vertexCode))
return;
if (!Compile(m_FragmentShader, m_FragmentFile, fragmentCode))
return;
if (!Link())
return;
m_IsValid = true;
}
void Unload()
{
m_IsValid = false;
if (m_Program)
pglDeleteProgram(m_Program);
m_Program = 0;
// The shader objects can be reused and don't need to be deleted here
}
virtual void Bind()
{
pglUseProgramObjectARB(m_Program);
- for (std::map::iterator it = m_VertexAttribs.begin(); it != m_VertexAttribs.end(); ++it)
+ for (std::map::iterator it = m_VertexAttribs.begin(); it != m_VertexAttribs.end(); ++it)
pglEnableVertexAttribArrayARB(it->second);
}
virtual void Unbind()
{
pglUseProgramObjectARB(0);
- for (std::map::iterator it = m_VertexAttribs.begin(); it != m_VertexAttribs.end(); ++it)
+ for (std::map::iterator it = m_VertexAttribs.begin(); it != m_VertexAttribs.end(); ++it)
pglDisableVertexAttribArrayARB(it->second);
// TODO: should unbind textures, probably
}
- int GetUniformLocation(uniform_id_t id)
- {
- std::map::iterator it = m_UniformLocations.find(id);
- if (it == m_UniformLocations.end())
- return -1;
- return it->second;
- }
-
virtual Binding GetTextureBinding(texture_id_t id)
{
- std::map >::iterator it = m_Samplers.find(id);
+ std::map >::iterator it = m_Samplers.find(CStrIntern(id));
if (it == m_Samplers.end())
return Binding();
else
return Binding((int)it->second.first, it->second.second);
}
virtual void BindTexture(texture_id_t id, Handle tex)
{
- std::map >::iterator it = m_Samplers.find(id);
+ std::map >::iterator it = m_Samplers.find(CStrIntern(id));
if (it == m_Samplers.end())
return;
GLuint h;
ogl_tex_get_texture_id(tex, &h);
pglActiveTextureARB(GL_TEXTURE0 + it->second.second);
glBindTexture(it->second.first, h);
}
virtual void BindTexture(texture_id_t id, GLuint tex)
{
- std::map >::iterator it = m_Samplers.find(id);
+ std::map >::iterator it = m_Samplers.find(CStrIntern(id));
if (it == m_Samplers.end())
return;
pglActiveTextureARB(GL_TEXTURE0 + it->second.second);
glBindTexture(it->second.first, tex);
}
virtual void BindTexture(Binding id, Handle tex)
{
if (id.second == -1)
return;
GLuint h;
ogl_tex_get_texture_id(tex, &h);
pglActiveTextureARB(GL_TEXTURE0 + id.second);
glBindTexture(id.first, h);
}
virtual Binding GetUniformBinding(uniform_id_t id)
{
- int loc = GetUniformLocation(id);
- if (loc == -1)
+ std::map >::iterator it = m_Uniforms.find(CStrIntern(id));
+ if (it == m_Uniforms.end())
+ return Binding();
+ else
+ return Binding(it->second.first, (int)it->second.second);
+ }
+
+ virtual Binding GetUniformBinding(CStrIntern id)
+ {
+ std::map >::iterator it = m_Uniforms.find(id);
+ if (it == m_Uniforms.end())
return Binding();
else
- return Binding(loc, m_UniformTypes[id]);
+ return Binding(it->second.first, (int)it->second.second);
}
virtual void Uniform(Binding id, float v0, float v1, float v2, float v3)
{
if (id.first != -1)
{
if (id.second == GL_FLOAT)
pglUniform1fARB(id.first, v0);
else if (id.second == GL_FLOAT_VEC2)
pglUniform2fARB(id.first, v0, v1);
else if (id.second == GL_FLOAT_VEC3)
pglUniform3fARB(id.first, v0, v1, v2);
else if (id.second == GL_FLOAT_VEC4)
pglUniform4fARB(id.first, v0, v1, v2, v3);
else
LOGERROR(L"CShaderProgramGLSL::Uniform(): Invalid uniform type (expected float, vec2, vec3, vec4)");
}
}
virtual void Uniform(Binding id, const CMatrix3D& v)
{
if (id.first != -1)
{
if (id.second == GL_FLOAT_MAT4)
pglUniformMatrix4fvARB(id.first, 1, GL_FALSE, &v._11);
else
LOGERROR(L"CShaderProgramGLSL::Uniform(): Invalid uniform type (expected mat4)");
}
}
// Map the various fixed-function Pointer functions onto generic vertex attributes
// (matching the attribute indexes from ShaderManager's ParseAttribSemantics):
virtual void VertexPointer(GLint size, GLenum type, GLsizei stride, void* pointer)
{
pglVertexAttribPointerARB(0, size, type, GL_FALSE, stride, pointer);
m_ValidStreams |= STREAM_POS;
}
virtual void NormalPointer(GLenum type, GLsizei stride, void* pointer)
{
pglVertexAttribPointerARB(2, 3, type, GL_TRUE, stride, pointer);
m_ValidStreams |= STREAM_NORMAL;
}
virtual void ColorPointer(GLint size, GLenum type, GLsizei stride, void* pointer)
{
pglVertexAttribPointerARB(3, size, type, GL_TRUE, stride, pointer);
m_ValidStreams |= STREAM_COLOR;
}
virtual void TexCoordPointer(GLenum texture, GLint size, GLenum type, GLsizei stride, void* pointer)
{
pglVertexAttribPointerARB(8 + texture - GL_TEXTURE0, size, type, GL_FALSE, stride, pointer);
m_ValidStreams |= STREAM_UV0 << (texture - GL_TEXTURE0);
}
private:
VfsPath m_VertexFile;
VfsPath m_FragmentFile;
CShaderDefines m_Defines;
- std::map m_VertexAttribs;
+ std::map m_VertexAttribs;
GLhandleARB m_Program;
GLhandleARB m_VertexShader;
GLhandleARB m_FragmentShader;
- std::map m_UniformTypes;
- std::map m_UniformLocations;
- std::map > m_Samplers; // texture target & unit chosen for each uniform sampler
+ std::map > m_Uniforms;
+ std::map > m_Samplers; // texture target & unit chosen for each uniform sampler
};
//////////////////////////////////////////////////////////////////////////
CShaderProgram::CShaderProgram(int streamflags)
: m_IsValid(false), m_StreamFlags(streamflags), m_ValidStreams(0)
{
}
#if CONFIG2_GLES
/*static*/ CShaderProgram* CShaderProgram::ConstructARB(const VfsPath& vertexFile, const VfsPath& fragmentFile,
const CShaderDefines& UNUSED(defines),
- const std::map& UNUSED(vertexIndexes), const std::map& UNUSED(fragmentIndexes),
+ const std::map& UNUSED(vertexIndexes), const std::map& UNUSED(fragmentIndexes),
int UNUSED(streamflags))
{
LOGERROR(L"CShaderProgram::ConstructARB: '%ls'+'%ls': ARB shaders not supported on this device",
vertexFile.string().c_str(), fragmentFile.string().c_str());
return NULL;
}
#else
/*static*/ CShaderProgram* CShaderProgram::ConstructARB(const VfsPath& vertexFile, const VfsPath& fragmentFile,
const CShaderDefines& defines,
- const std::map& vertexIndexes, const std::map& fragmentIndexes,
+ const std::map& vertexIndexes, const std::map& fragmentIndexes,
int streamflags)
{
return new CShaderProgramARB(vertexFile, fragmentFile, defines, vertexIndexes, fragmentIndexes, streamflags);
}
#endif
/*static*/ CShaderProgram* CShaderProgram::ConstructGLSL(const VfsPath& vertexFile, const VfsPath& fragmentFile,
const CShaderDefines& defines,
- const std::map& vertexAttribs,
+ const std::map& vertexAttribs,
int streamflags)
{
return new CShaderProgramGLSL(vertexFile, fragmentFile, defines, vertexAttribs, streamflags);
}
bool CShaderProgram::IsValid() const
{
return m_IsValid;
}
int CShaderProgram::GetStreamFlags() const
{
return m_StreamFlags;
}
void CShaderProgram::BindTexture(texture_id_t id, CTexturePtr tex)
{
BindTexture(id, tex->GetHandle());
}
void CShaderProgram::Uniform(Binding id, int v)
{
Uniform(id, (float)v, (float)v, (float)v, (float)v);
}
void CShaderProgram::Uniform(Binding id, float v)
{
Uniform(id, v, v, v, v);
}
void CShaderProgram::Uniform(Binding id, float v0, float v1)
{
Uniform(id, v0, v1, 0.0f, 0.0f);
}
void CShaderProgram::Uniform(Binding id, const CVector3D& v)
{
Uniform(id, v.X, v.Y, v.Z, 0.0f);
}
void CShaderProgram::Uniform(Binding id, const CColor& v)
{
Uniform(id, v.r, v.g, v.b, v.a);
}
void CShaderProgram::Uniform(uniform_id_t id, int v)
{
Uniform(GetUniformBinding(id), (float)v, (float)v, (float)v, (float)v);
}
void CShaderProgram::Uniform(uniform_id_t id, float v)
{
Uniform(GetUniformBinding(id), v, v, v, v);
}
void CShaderProgram::Uniform(uniform_id_t id, float v0, float v1)
{
Uniform(GetUniformBinding(id), v0, v1, 0.0f, 0.0f);
}
void CShaderProgram::Uniform(uniform_id_t id, const CVector3D& v)
{
Uniform(GetUniformBinding(id), v.X, v.Y, v.Z, 0.0f);
}
void CShaderProgram::Uniform(uniform_id_t id, const CColor& v)
{
Uniform(GetUniformBinding(id), v.r, v.g, v.b, v.a);
}
void CShaderProgram::Uniform(uniform_id_t id, float v0, float v1, float v2, float v3)
{
Uniform(GetUniformBinding(id), v0, v1, v2, v3);
}
void CShaderProgram::Uniform(uniform_id_t id, const CMatrix3D& v)
{
Uniform(GetUniformBinding(id), v);
}
CStr CShaderProgram::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;
}
#if CONFIG2_GLES
// These should all be overridden by CShaderProgramGLSL
void CShaderProgram::VertexPointer(GLint UNUSED(size), GLenum UNUSED(type), GLsizei UNUSED(stride), void* UNUSED(pointer))
{
debug_warn("CShaderProgram::VertexPointer should be overridden");
}
void CShaderProgram::NormalPointer(GLenum UNUSED(type), GLsizei UNUSED(stride), void* UNUSED(pointer))
{
debug_warn("CShaderProgram::NormalPointer should be overridden");
}
void CShaderProgram::ColorPointer(GLint UNUSED(size), GLenum UNUSED(type), GLsizei UNUSED(stride), void* UNUSED(pointer))
{
debug_warn("CShaderProgram::ColorPointer should be overridden");
}
void CShaderProgram::TexCoordPointer(GLenum UNUSED(texture), GLint UNUSED(size), GLenum UNUSED(type), GLsizei UNUSED(stride), void* UNUSED(pointer))
{
debug_warn("CShaderProgram::TexCoordPointer should be overridden");
}
#else
// These are overridden by CShaderProgramGLSL, but fixed-function and ARB shaders
// both use the fixed-function vertex attribute pointers:
void CShaderProgram::VertexPointer(GLint size, GLenum type, GLsizei stride, void* pointer)
{
glVertexPointer(size, type, stride, pointer);
m_ValidStreams |= STREAM_POS;
}
void CShaderProgram::NormalPointer(GLenum type, GLsizei stride, void* pointer)
{
glNormalPointer(type, stride, pointer);
m_ValidStreams |= STREAM_NORMAL;
}
void CShaderProgram::ColorPointer(GLint size, GLenum type, GLsizei stride, void* pointer)
{
glColorPointer(size, type, stride, pointer);
m_ValidStreams |= STREAM_COLOR;
}
void CShaderProgram::TexCoordPointer(GLenum texture, GLint size, GLenum type, GLsizei stride, void* pointer)
{
pglClientActiveTextureARB(texture);
glTexCoordPointer(size, type, stride, pointer);
pglClientActiveTextureARB(GL_TEXTURE0);
m_ValidStreams |= STREAM_UV0 << (texture - GL_TEXTURE0);
}
void CShaderProgram::BindClientStates()
{
ENSURE(m_StreamFlags == (m_StreamFlags & (STREAM_POS|STREAM_NORMAL|STREAM_COLOR|STREAM_UV0|STREAM_UV1)));
// Enable all the desired client states for non-GLSL rendering
if (m_StreamFlags & STREAM_POS) glEnableClientState(GL_VERTEX_ARRAY);
if (m_StreamFlags & STREAM_NORMAL) glEnableClientState(GL_NORMAL_ARRAY);
if (m_StreamFlags & STREAM_COLOR) glEnableClientState(GL_COLOR_ARRAY);
if (m_StreamFlags & STREAM_UV0)
{
pglClientActiveTextureARB(GL_TEXTURE0);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
}
if (m_StreamFlags & STREAM_UV1)
{
pglClientActiveTextureARB(GL_TEXTURE1);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
pglClientActiveTextureARB(GL_TEXTURE0);
}
// Rendering code must subsequently call VertexPointer etc for all of the streams
// that were activated in this function, else AssertPointersBound will complain
// that some arrays were unspecified
m_ValidStreams = 0;
}
void CShaderProgram::UnbindClientStates()
{
if (m_StreamFlags & STREAM_POS) glDisableClientState(GL_VERTEX_ARRAY);
if (m_StreamFlags & STREAM_NORMAL) glDisableClientState(GL_NORMAL_ARRAY);
if (m_StreamFlags & STREAM_COLOR) glDisableClientState(GL_COLOR_ARRAY);
if (m_StreamFlags & STREAM_UV0)
{
pglClientActiveTextureARB(GL_TEXTURE0);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
if (m_StreamFlags & STREAM_UV1)
{
pglClientActiveTextureARB(GL_TEXTURE1);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
pglClientActiveTextureARB(GL_TEXTURE0);
}
}
#endif // !CONFIG2_GLES
void CShaderProgram::AssertPointersBound()
{
ENSURE((m_StreamFlags & ~m_ValidStreams) == 0);
}
Index: ps/trunk/source/graphics/ShaderManager.cpp
===================================================================
--- ps/trunk/source/graphics/ShaderManager.cpp (revision 11452)
+++ ps/trunk/source/graphics/ShaderManager.cpp (revision 11453)
@@ -1,594 +1,594 @@
/* 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 .
*/
#include "precompiled.h"
#include "ShaderManager.h"
#include "graphics/ShaderTechnique.h"
#include "lib/timer.h"
#include "lib/utf8.h"
#include "ps/CLogger.h"
#include "ps/CStrIntern.h"
#include "ps/Filesystem.h"
#include "ps/Preprocessor.h"
#include "ps/Profile.h"
#include "ps/XML/Xeromyces.h"
#include "ps/XML/XMLWriter.h"
#include "renderer/Renderer.h"
TIMER_ADD_CLIENT(tc_ShaderValidation);
struct revcompare2nd
{
template bool operator()(const std::pair& a, const std::pair& b) const
{
return b.second < a.second;
}
};
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 CShaderDefines& defines)
{
CacheKey key = { name, defines };
std::map::iterator it = m_ProgramCache.find(key);
if (it != m_ProgramCache.end())
return it->second;
CShaderProgramPtr program;
if (!NewProgram(name, defines, program))
{
LOGERROR(L"Failed to load shader '%hs'", name);
program = CShaderProgramPtr();
}
m_ProgramCache[key] = program;
return program;
}
static GLenum ParseAttribSemantics(const CStr& str)
{
// Map known semantics onto the attribute locations documented by NVIDIA
if (str == "gl_Vertex") return 0;
if (str == "gl_Normal") return 2;
if (str == "gl_Color") return 3;
if (str == "gl_SecondaryColor") return 4;
if (str == "gl_FogCoord") return 5;
if (str == "gl_MultiTexCoord0") return 8;
if (str == "gl_MultiTexCoord1") return 9;
if (str == "gl_MultiTexCoord2") return 10;
if (str == "gl_MultiTexCoord3") return 11;
if (str == "gl_MultiTexCoord4") return 12;
if (str == "gl_MultiTexCoord5") return 13;
if (str == "gl_MultiTexCoord6") return 14;
if (str == "gl_MultiTexCoord7") return 15;
// TODO: support user-defined semantics somehow
debug_warn("Invalid attribute semantics");
return 0;
}
static bool CheckPreprocessorConditional(CPreprocessor& preprocessor, const CStr& expr)
{
// Construct a dummy program so we can trigger the preprocessor's expression
// code without modifying its public API.
// Be careful that the API buggily returns a statically allocated pointer
// (which we will try to free()) if the input just causes it to append a single
// sequence of newlines to the output; the "\n" after the "#endif" is enough
// to avoid this case.
CStr input = "#if ";
input += expr;
input += "\n1\n#endif\n";
size_t len = 0;
char* output = preprocessor.Parse(input.c_str(), input.size(), len);
if (!output)
{
LOGERROR(L"Failed to parse conditional expression '%hs'", expr.c_str());
return false;
}
bool ret = (memchr(output, '1', len) != NULL);
// 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 CShaderManager::NewProgram(const char* name, const CShaderDefines& baseDefines, CShaderProgramPtr& program)
{
PROFILE2("loading shader");
PROFILE2_ATTR("name: %s", name);
if (strncmp(name, "fixed:", 6) == 0)
{
program = CShaderProgramPtr(CShaderProgram::ConstructFFP(name+6, baseDefines));
if (!program)
return false;
program->Reload();
return true;
}
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(attrib);
EL(define);
EL(fragment);
EL(stream);
EL(uniform);
EL(vertex);
AT(file);
AT(if);
AT(loc);
AT(name);
AT(semantics);
AT(type);
AT(value);
#undef AT
#undef EL
CPreprocessor preprocessor;
- std::map baseDefinesMap = baseDefines.GetMap();
- for (std::map::const_iterator it = baseDefinesMap.begin(); it != baseDefinesMap.end(); ++it)
+ std::map baseDefinesMap = baseDefines.GetMap();
+ for (std::map::const_iterator it = baseDefinesMap.begin(); it != baseDefinesMap.end(); ++it)
preprocessor.Define(it->first.c_str(), it->first.length(), it->second.c_str(), it->second.length());
XMBElement Root = XeroFile.GetRoot();
bool isGLSL = (Root.GetAttributes().GetNamedItem(at_type) == "glsl");
VfsPath vertexFile;
VfsPath fragmentFile;
CShaderDefines defines = baseDefines;
- std::map vertexUniforms;
- std::map fragmentUniforms;
- std::map vertexAttribs;
+ std::map vertexUniforms;
+ std::map fragmentUniforms;
+ std::map vertexAttribs;
int streamFlags = 0;
XERO_ITER_EL(Root, Child)
{
if (Child.GetNodeName() == el_define)
{
defines.Add(Child.GetAttributes().GetNamedItem(at_name).c_str(), Child.GetAttributes().GetNamedItem(at_value).c_str());
}
else if (Child.GetNodeName() == el_vertex)
{
vertexFile = L"shaders/" + Child.GetAttributes().GetNamedItem(at_file).FromUTF8();
XERO_ITER_EL(Child, Param)
{
XMBAttributeList Attrs = Param.GetAttributes();
CStr cond = Attrs.GetNamedItem(at_if);
if (!cond.empty() && !CheckPreprocessorConditional(preprocessor, cond))
continue;
if (Param.GetNodeName() == el_uniform)
{
- vertexUniforms[Attrs.GetNamedItem(at_name)] = Attrs.GetNamedItem(at_loc).ToInt();
+ vertexUniforms[CStrIntern(Attrs.GetNamedItem(at_name))] = Attrs.GetNamedItem(at_loc).ToInt();
}
else if (Param.GetNodeName() == el_stream)
{
CStr StreamName = Attrs.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)
{
int attribLoc = ParseAttribSemantics(Attrs.GetNamedItem(at_semantics));
- vertexAttribs[Attrs.GetNamedItem(at_name)] = attribLoc;
+ vertexAttribs[CStrIntern(Attrs.GetNamedItem(at_name))] = attribLoc;
}
}
}
else if (Child.GetNodeName() == el_fragment)
{
fragmentFile = L"shaders/" + Child.GetAttributes().GetNamedItem(at_file).FromUTF8();
XERO_ITER_EL(Child, Param)
{
XMBAttributeList Attrs = Param.GetAttributes();
CStr cond = Attrs.GetNamedItem(at_if);
if (!cond.empty() && !CheckPreprocessorConditional(preprocessor, cond))
continue;
if (Param.GetNodeName() == el_uniform)
{
- fragmentUniforms[Attrs.GetNamedItem(at_name)] = Attrs.GetNamedItem(at_loc).ToInt();
+ fragmentUniforms[CStrIntern(Attrs.GetNamedItem(at_name))] = Attrs.GetNamedItem(at_loc).ToInt();
}
}
}
}
if (isGLSL)
program = CShaderProgramPtr(CShaderProgram::ConstructGLSL(vertexFile, fragmentFile, defines, vertexAttribs, streamFlags));
else
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 true;
}
static GLenum ParseComparisonFunc(const CStr& str)
{
if (str == "never")
return GL_NEVER;
if (str == "always")
return GL_ALWAYS;
if (str == "less")
return GL_LESS;
if (str == "lequal")
return GL_LEQUAL;
if (str == "equal")
return GL_EQUAL;
if (str == "gequal")
return GL_GEQUAL;
if (str == "greater")
return GL_GREATER;
if (str == "notequal")
return GL_NOTEQUAL;
debug_warn("Invalid comparison func");
return GL_ALWAYS;
}
static GLenum ParseBlendFunc(const CStr& str)
{
if (str == "zero")
return GL_ZERO;
if (str == "one")
return GL_ONE;
if (str == "src_color")
return GL_SRC_COLOR;
if (str == "one_minus_src_color")
return GL_ONE_MINUS_SRC_COLOR;
if (str == "dst_color")
return GL_DST_COLOR;
if (str == "one_minus_dst_color")
return GL_ONE_MINUS_DST_COLOR;
if (str == "src_alpha")
return GL_SRC_ALPHA;
if (str == "one_minus_src_alpha")
return GL_ONE_MINUS_SRC_ALPHA;
if (str == "dst_alpha")
return GL_DST_ALPHA;
if (str == "one_minus_dst_alpha")
return GL_ONE_MINUS_DST_ALPHA;
if (str == "constant_color")
return GL_CONSTANT_COLOR;
if (str == "one_minus_constant_color")
return GL_ONE_MINUS_CONSTANT_COLOR;
if (str == "constant_alpha")
return GL_CONSTANT_ALPHA;
if (str == "one_minus_constant_alpha")
return GL_ONE_MINUS_CONSTANT_ALPHA;
if (str == "src_alpha_saturate")
return GL_SRC_ALPHA_SATURATE;
debug_warn("Invalid blend func");
return GL_ZERO;
}
size_t CShaderManager::EffectCacheKeyHash::operator()(const EffectCacheKey& key) const
{
size_t hash = 0;
boost::hash_combine(hash, key.name.GetHash());
boost::hash_combine(hash, key.defines1.GetHash());
boost::hash_combine(hash, key.defines2.GetHash());
return hash;
}
bool CShaderManager::EffectCacheKey::operator==(const EffectCacheKey& b) const
{
return (name == b.name && defines1 == b.defines1 && defines2 == b.defines2);
}
CShaderTechniquePtr CShaderManager::LoadEffect(const char* name)
{
return LoadEffect(CStrIntern(name), CShaderDefines(), CShaderDefines());
}
CShaderTechniquePtr CShaderManager::LoadEffect(CStrIntern name, const CShaderDefines& defines1, const CShaderDefines& defines2)
{
// Return the cached effect, if there is one
EffectCacheKey key = { name, defines1, defines2 };
EffectCacheMap::iterator it = m_EffectCache.find(key);
if (it != m_EffectCache.end())
return it->second;
// First time we've seen this key, so construct a new effect:
// Merge the two sets of defines, so NewEffect doesn't have to care about the split
CShaderDefines defines(defines1);
- defines.Add(defines2);
+ defines.SetMany(defines2);
CShaderTechniquePtr tech(new CShaderTechnique());
if (!NewEffect(name.c_str(), defines, tech))
{
LOGERROR(L"Failed to load effect '%hs'", name.c_str());
tech = CShaderTechniquePtr();
}
m_EffectCache[key] = tech;
return tech;
}
bool CShaderManager::NewEffect(const char* name, const CShaderDefines& baseDefines, CShaderTechniquePtr& tech)
{
PROFILE2("loading effect");
PROFILE2_ATTR("name: %s", name);
// Shortcut syntax for effects that just contain a single shader
if (strncmp(name, "shader:", 7) == 0)
{
CShaderProgramPtr program = LoadProgram(name+7, baseDefines);
if (!program)
return false;
CShaderPass pass;
pass.SetShader(program);
tech->AddPass(pass);
return true;
}
VfsPath xmlFilename = L"shaders/effects/" + wstring_from_utf8(name) + L".xml";
CXeromyces XeroFile;
PSRETURN ret = XeroFile.Load(g_VFS, xmlFilename);
if (ret != PSRETURN_OK)
return false;
// 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(alpha);
EL(blend);
EL(define);
EL(depth);
EL(pass);
EL(require);
EL(sort_by_distance);
AT(context);
AT(dst);
AT(func);
AT(ref);
AT(shader);
AT(shaders);
AT(src);
AT(mask);
AT(name);
AT(value);
#undef AT
#undef EL
// Read some defines that influence how we pick techniques
bool hasARB = (baseDefines.GetInt("SYS_HAS_ARB") != 0);
bool hasGLSL = (baseDefines.GetInt("SYS_HAS_GLSL") != 0);
bool preferGLSL = (baseDefines.GetInt("SYS_PREFER_GLSL") != 0);
// Prepare the preprocessor for conditional tests
CPreprocessor preprocessor;
- std::map baseDefinesMap = baseDefines.GetMap();
- for (std::map::const_iterator it = baseDefinesMap.begin(); it != baseDefinesMap.end(); ++it)
+ std::map baseDefinesMap = baseDefines.GetMap();
+ for (std::map::const_iterator it = baseDefinesMap.begin(); it != baseDefinesMap.end(); ++it)
preprocessor.Define(it->first.c_str(), it->first.length(), it->second.c_str(), it->second.length());
XMBElement Root = XeroFile.GetRoot();
// Find all the techniques that we can use, and their preference
std::vector > usableTechs;
XERO_ITER_EL(Root, Technique)
{
int preference = 0;
bool isUsable = true;
XERO_ITER_EL(Technique, Child)
{
XMBAttributeList Attrs = Child.GetAttributes();
if (Child.GetNodeName() == el_require)
{
if (Attrs.GetNamedItem(at_shaders) == "fixed")
{
// FFP not supported by OpenGL ES
#if CONFIG2_GLES
isUsable = false;
#endif
}
else if (Attrs.GetNamedItem(at_shaders) == "arb")
{
if (!hasARB)
isUsable = false;
}
else if (Attrs.GetNamedItem(at_shaders) == "glsl")
{
if (!hasGLSL)
isUsable = false;
if (preferGLSL)
preference += 100;
else
preference -= 100;
}
else if (!Attrs.GetNamedItem(at_context).empty())
{
CStr cond = Attrs.GetNamedItem(at_context);
if (!CheckPreprocessorConditional(preprocessor, cond))
isUsable = false;
}
}
}
if (isUsable)
usableTechs.push_back(std::make_pair(Technique, preference));
}
if (usableTechs.empty())
{
debug_warn(L"Can't find a usable technique");
return false;
}
// Sort by preference, tie-break on order of specification
std::stable_sort(usableTechs.begin(), usableTechs.end(), revcompare2nd());
CShaderDefines techDefines = baseDefines;
XERO_ITER_EL(usableTechs[0].first, Child)
{
if (Child.GetNodeName() == el_define)
{
techDefines.Add(Child.GetAttributes().GetNamedItem(at_name).c_str(), Child.GetAttributes().GetNamedItem(at_value).c_str());
}
else if (Child.GetNodeName() == el_sort_by_distance)
{
tech->SetSortByDistance(true);
}
else if (Child.GetNodeName() == el_pass)
{
CShaderDefines passDefines = techDefines;
CShaderPass pass;
XERO_ITER_EL(Child, Element)
{
if (Element.GetNodeName() == el_define)
{
passDefines.Add(Element.GetAttributes().GetNamedItem(at_name).c_str(), Element.GetAttributes().GetNamedItem(at_value).c_str());
}
else if (Element.GetNodeName() == el_alpha)
{
GLenum func = ParseComparisonFunc(Element.GetAttributes().GetNamedItem(at_func));
float ref = Element.GetAttributes().GetNamedItem(at_ref).ToFloat();
pass.AlphaFunc(func, ref);
}
else if (Element.GetNodeName() == el_blend)
{
GLenum src = ParseBlendFunc(Element.GetAttributes().GetNamedItem(at_src));
GLenum dst = ParseBlendFunc(Element.GetAttributes().GetNamedItem(at_dst));
pass.BlendFunc(src, dst);
}
else if (Element.GetNodeName() == el_depth)
{
if (!Element.GetAttributes().GetNamedItem(at_func).empty())
pass.DepthFunc(ParseComparisonFunc(Element.GetAttributes().GetNamedItem(at_func)));
if (!Element.GetAttributes().GetNamedItem(at_mask).empty())
pass.DepthMask(Element.GetAttributes().GetNamedItem(at_mask) == "true" ? 1 : 0);
}
}
// Load the shader program after we've read all the possibly-relevant s
pass.SetShader(LoadProgram(Child.GetAttributes().GetNamedItem(at_shader).c_str(), passDefines));
tech->AddPass(pass);
}
}
return true;
}
size_t CShaderManager::GetNumEffectsLoaded()
{
return m_EffectCache.size();
}
/*static*/ Status CShaderManager::ReloadChangedFileCB(void* param, const VfsPath& path)
{
return static_cast(param)->ReloadChangedFile(path);
}
Status 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 >::iterator it = files->second.begin(); it != files->second.end(); ++it)
{
if (shared_ptr program = it->lock())
program->Reload();
}
}
// TODO: hotloading changes to shader XML files and effect XML files would be nice
return INFO::OK;
}
Index: ps/trunk/source/graphics/ShaderDefines.cpp
===================================================================
--- ps/trunk/source/graphics/ShaderDefines.cpp (revision 11452)
+++ ps/trunk/source/graphics/ShaderDefines.cpp (revision 11453)
@@ -1,159 +1,241 @@
/* 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 .
*/
#include "precompiled.h"
#include "ShaderDefines.h"
+#include "maths/Vector4D.h"
#include "ps/ThreadUtil.h"
-#include
+size_t hash_value(const CStrIntern& v)
+{
+ return v.GetHash();
+}
+
+size_t hash_value(const CVector4D& v)
+{
+ size_t hash = 0;
+ boost::hash_combine(hash, v.X);
+ boost::hash_combine(hash, v.Y);
+ boost::hash_combine(hash, v.Z);
+ boost::hash_combine(hash, v.W);
+ return hash;
+}
+
+size_t hash_value(const CShaderParams::SItems& items)
+{
+ return items.hash;
+}
-size_t hash_value(const CShaderDefines::SItems& items)
+size_t hash_value(const CShaderParams::SItems& items)
{
return items.hash;
}
-bool operator==(const CShaderDefines::SItems& a, const CShaderDefines::SItems& b)
+bool operator==(const CShaderParams::SItems& a, const CShaderParams::SItems& b)
{
return a.items == b.items;
}
+bool operator==(const CShaderParams::SItems& a, const CShaderParams::SItems& b)
+{
+ return a.items == b.items;
+}
+
+template
struct ItemNameCmp
{
- typedef CShaderDefines::SItems::Item first_argument_type;
- typedef CShaderDefines::SItems::Item second_argument_type;
- bool operator()(const CShaderDefines::SItems::Item& a, const CShaderDefines::SItems::Item& b) const
+ typedef typename CShaderParams::SItems::Item Item;
+
+ typedef Item first_argument_type;
+ typedef Item second_argument_type;
+ bool operator()(const Item& a, const Item& b) const
{
return a.first < b.first;
}
};
+template
struct ItemNameGeq
{
- bool operator()(const CShaderDefines::SItems::Item& a, const CShaderDefines::SItems::Item& b) const
+ typedef typename CShaderParams::SItems::Item Item;
+
+ bool operator()(const Item& a, const Item& b) const
{
return !(b.first < a.first);
}
};
-typedef boost::unordered_map > InternedItems_t;
-static InternedItems_t g_InternedItems;
-
-CShaderDefines::SItems* CShaderDefines::GetInterned(const SItems& items)
+template
+typename CShaderParams::SItems* CShaderParams::GetInterned(const SItems& items)
{
- ENSURE(ThreadUtil::IsMainThread()); // g_InternedItems is not thread-safe
+ ENSURE(ThreadUtil::IsMainThread()); // s_InternedItems is not thread-safe
- InternedItems_t::iterator it = g_InternedItems.find(items);
- if (it != g_InternedItems.end())
+ InternedItems_t::iterator it = s_InternedItems.find(items);
+ if (it != s_InternedItems.end())
return it->second.get();
// Sanity test: the items list is meant to be sorted by name.
// This is a reasonable place to verify that, since this will be called once per distinct SItems.
- ENSURE(std::adjacent_find(items.items.begin(), items.items.end(), std::binary_negate(ItemNameCmp())) == items.items.end());
+ typedef ItemNameCmp Cmp;
+ ENSURE(std::adjacent_find(items.items.begin(), items.items.end(), std::binary_negate(Cmp())) == items.items.end());
shared_ptr ptr(new SItems(items));
- g_InternedItems.insert(std::make_pair(items, ptr));
+ s_InternedItems.insert(std::make_pair(items, ptr));
return ptr.get();
}
-CShaderDefines::CShaderDefines()
+template
+CShaderParams::CShaderParams()
{
SItems items;
items.RecalcHash();
m_Items = GetInterned(items);
}
-void CShaderDefines::Add(const char* name, const char* value)
+template
+void CShaderParams::Set(CStrIntern name, const value_t& value)
{
SItems items = *m_Items;
- SItems::Item addedItem = std::make_pair(CStrIntern(name), CStrIntern(value));
+ SItems::Item addedItem = std::make_pair(name, value);
// Add the new item in a way that preserves the sortedness and uniqueness of item names
for (std::vector::iterator it = items.items.begin(); ; ++it)
{
if (it == items.items.end() || addedItem.first < it->first)
{
items.items.insert(it, addedItem);
break;
}
else if (addedItem.first == it->first)
{
it->second = addedItem.second;
break;
}
}
items.RecalcHash();
m_Items = GetInterned(items);
}
-void CShaderDefines::Add(const CShaderDefines& defines)
+template
+void CShaderParams::SetMany(const CShaderParams& params)
{
SItems items;
// set_union merges the two sorted lists into a new sorted list;
// if two items are equivalent (i.e. equal names, possibly different values)
// then the one from the first list is kept
std::set_union(
- defines.m_Items->items.begin(), defines.m_Items->items.end(),
+ params.m_Items->items.begin(), params.m_Items->items.end(),
m_Items->items.begin(), m_Items->items.end(),
std::inserter(items.items, items.items.begin()),
- ItemNameCmp());
+ ItemNameCmp());
items.RecalcHash();
m_Items = GetInterned(items);
}
-std::map CShaderDefines::GetMap() const
+template
+std::map CShaderParams::GetMap() const
{
- std::map ret;
+ std::map ret;
for (size_t i = 0; i < m_Items->items.size(); ++i)
- ret[m_Items->items[i].first.string()] = m_Items->items[i].second.string();
+ ret[m_Items->items[i].first] = m_Items->items[i].second;
return ret;
}
+template
+size_t CShaderParams::GetHash() const
+{
+ return m_Items->hash;
+}
+
+template
+void CShaderParams::SItems::RecalcHash()
+{
+ size_t h = 0;
+ for (size_t i = 0; i < items.size(); ++i)
+ {
+ boost::hash_combine(h, items[i].first);
+ boost::hash_combine(h, items[i].second);
+ }
+ hash = h;
+}
+
+
+void CShaderDefines::Add(const char* name, const char* value)
+{
+ Set(CStrIntern(name), CStrIntern(value));
+}
+
int CShaderDefines::GetInt(const char* name) const
{
CStrIntern nameIntern(name);
for (size_t i = 0; i < m_Items->items.size(); ++i)
{
if (m_Items->items[i].first == nameIntern)
{
int ret;
std::stringstream str(m_Items->items[i].second.c_str());
str >> ret;
return ret;
}
}
return 0;
}
-size_t CShaderDefines::GetHash() const
+
+void CShaderUniforms::Add(const char* name, const CVector4D& value)
{
- return m_Items->hash;
+ Set(CStrIntern(name), value);
}
-void CShaderDefines::SItems::RecalcHash()
+CVector4D CShaderUniforms::GetVector(const char* name) const
{
- size_t h = 0;
+ CStrIntern nameIntern(name);
+ for (size_t i = 0; i < m_Items->items.size(); ++i)
+ {
+ if (m_Items->items[i].first == nameIntern)
+ {
+ return m_Items->items[i].second;
+ }
+ }
+ return CVector4D();
+}
+
+void CShaderUniforms::BindUniforms(const CShaderProgramPtr& shader) const
+{
+ const std::vector& items = m_Items->items;
for (size_t i = 0; i < items.size(); ++i)
{
- boost::hash_combine(h, items[i].first.GetHash());
- boost::hash_combine(h, items[i].second.GetHash());
+ CShaderProgram::Binding binding = shader->GetUniformBinding(items[i].first);
+ if (binding.Active())
+ {
+ CVector4D v = items[i].second;
+ shader->Uniform(binding, v.X, v.Y, v.Z, v.W);
+ }
}
- hash = h;
}
+
+// Explicit instantiations:
+
+boost::unordered_map::SItems, shared_ptr::SItems> > CShaderParams::s_InternedItems;
+boost::unordered_map::SItems, shared_ptr::SItems> > CShaderParams::s_InternedItems;
+
+template class CShaderParams;
+template class CShaderParams;
Index: ps/trunk/source/graphics/CinemaTrack.cpp
===================================================================
--- ps/trunk/source/graphics/CinemaTrack.cpp (revision 11452)
+++ ps/trunk/source/graphics/CinemaTrack.cpp (revision 11453)
@@ -1,348 +1,348 @@
/* Copyright (C) 2009 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 .
*/
#include "precompiled.h"
#include
#include
#include "lib/ogl.h"
#include "CinemaTrack.h"
#include "ps/Game.h"
#include "GameView.h"
#include "maths/MathUtil.h"
#include "Camera.h"
#include "ps/CStr.h"
#include "maths/Vector3D.h"
#include "maths/Vector4D.h"
#include "maths/Quaternion.h"
CCinemaPath::CCinemaPath(const CCinemaData& data, const TNSpline& spline)
: CCinemaData(data), TNSpline(spline), m_TimeElapsed(0.f)
{
m_TimeElapsed = 0;
BuildSpline();
//Set distortion mode and style
switch(data.m_Mode)
{
case CCinemaPath::EM_IN:
DistModePtr = &CCinemaPath::EaseIn;
break;
case CCinemaPath::EM_OUT:
DistModePtr = &CCinemaPath::EaseOut;
break;
case CCinemaPath::EM_INOUT:
DistModePtr = &CCinemaPath::EaseInOut;
break;
case CCinemaPath::EM_OUTIN:
DistModePtr = &CCinemaPath::EaseOutIn;
break;
default:
debug_printf(L"Cinematic mode not found for %d ", data.m_Mode);
break;
}
switch (data.m_Style)
{
case CCinemaPath::ES_DEFAULT:
DistStylePtr = &CCinemaPath::EaseDefault;
break;
case CCinemaPath::ES_GROWTH:
DistStylePtr = &CCinemaPath::EaseGrowth;
break;
case CCinemaPath::ES_EXPO:
DistStylePtr = &CCinemaPath::EaseExpo;
break;
case CCinemaPath::ES_CIRCLE:
DistStylePtr = &CCinemaPath::EaseCircle;
break;
case CCinemaPath::ES_SINE:
DistStylePtr = &CCinemaPath::EaseSine;
break;
default:
debug_printf(L"Cinematic mode not found for %d !", data.m_Style);
break;
}
//UpdateDuration();
}
void CCinemaPath::DrawSpline(const CVector4D& RGBA, int smoothness, bool lines) const
{
if (NodeCount < 2 || DistModePtr == NULL)
return;
if ( NodeCount == 2 && lines )
smoothness = 2;
float start = MaxDistance / smoothness;
float time=0;
#if CONFIG2_GLES
#warning TODO: do something about CCinemaPath on GLES
#else
- glColor4f( RGBA.m_X, RGBA.m_Y, RGBA.m_Z, RGBA.m_W );
+ glColor4f( RGBA.X, RGBA.Y, RGBA.Z, RGBA.W );
if ( lines )
{
glLineWidth(1.8f);
glEnable(GL_LINE_SMOOTH);
glBegin(GL_LINE_STRIP);
for (int i=0; i<=smoothness; ++i)
{
//Find distorted time
time = start*i / MaxDistance;
CVector3D tmp = GetPosition(time);
glVertex3f( tmp.X, tmp.Y, tmp.Z );
}
glEnd();
glDisable(GL_LINE_SMOOTH);
glLineWidth(1.0f);
}
else
{
smoothness /= 2;
start = MaxDistance / smoothness;
glEnable(GL_POINT_SMOOTH);
glPointSize(3.0f);
glBegin(GL_POINTS);
for (int i=0; i<=smoothness; ++i)
{
//Find distorted time
time = (this->*DistModePtr)(start*i / MaxDistance);
CVector3D tmp = GetPosition(time);
glVertex3f( tmp.X, tmp.Y, tmp.Z );
}
glColor3f(1.0f, 1.0f, 0.0f); //yellow
for ( size_t i=0; iGetView()->GetCamera();
t = (this->*DistModePtr)(t);
CVector3D nodeRotation = Node[m_CurrentNode + 1].Rotation;
CQuaternion start, end;
start.FromEulerAngles(DEGTORAD(startRotation.X), DEGTORAD(startRotation.Y), DEGTORAD(startRotation.Z));
end.FromEulerAngles(DEGTORAD(nodeRotation.X), DEGTORAD(nodeRotation.Y), DEGTORAD(nodeRotation.Z));
start.Slerp(start, end, nodet);
CVector3D pos = GetPosition(t);
CQuaternion quat;
Cam->m_Orientation.SetIdentity();
Cam->m_Orientation.Rotate(start);
Cam->m_Orientation.Translate(pos);
Cam->UpdateFrustum();
}
//Distortion mode functions
float CCinemaPath::EaseIn(float t) const
{
return (this->*DistStylePtr)(t);
}
float CCinemaPath::EaseOut(float t) const
{
return 1.0f - EaseIn(1.0f-t);
}
float CCinemaPath::EaseInOut(float t) const
{
if (t < m_Switch)
return EaseIn(1.0f/m_Switch * t) * m_Switch;
return EaseOut(1.0f/m_Switch * (t-m_Switch)) * m_Switch + m_Switch;
}
float CCinemaPath::EaseOutIn(float t) const
{
if (t < m_Switch)
return EaseOut(1.0f/m_Switch * t) * m_Switch;
return EaseIn(1.0f/m_Switch * (t-m_Switch)) * m_Switch + m_Switch;
}
//Distortion style functions
float CCinemaPath::EaseDefault(float t) const
{
return t;
}
float CCinemaPath::EaseGrowth(float t) const
{
return pow(t, m_Growth);
}
float CCinemaPath::EaseExpo(float t) const
{
if(t == 0)
return t;
return powf(m_Growth, 10*(t-1.0f));
}
float CCinemaPath::EaseCircle(float t) const
{
t = -(sqrt(1.0f - t*t) - 1.0f);
if(m_GrowthCount > 1.0f)
{
m_GrowthCount--;
return (this->*DistStylePtr)(t);
}
return t;
}
float CCinemaPath::EaseSine(float t) const
{
t = 1.0f - cos(t * (float)M_PI/2);
if(m_GrowthCount > 1.0f)
{
m_GrowthCount--;
return (this->*DistStylePtr)(t);
}
return t;
}
bool CCinemaPath::Validate()
{
if ( m_TimeElapsed <= GetDuration() && m_TimeElapsed >= 0.0f )
{
//Find current node and past "node time"
float previousTime = 0.0f, cumulation = 0.0f;
//Ignore the last node, since it is a blank (node time values are shifted down one from interface)
for ( size_t i = 0; i < Node.size() - 1; ++i )
{
cumulation += Node[i].Distance;
if ( m_TimeElapsed <= cumulation )
{
m_PreviousNodeTime = previousTime;
m_PreviousRotation = Node[i].Rotation;
m_CurrentNode = i; //We're moving toward this next node, so use its rotation
return true;
}
else
previousTime += Node[i].Distance;
}
}
return false;
}
bool CCinemaPath::Play(float DeltaTime)
{
m_TimeElapsed += m_Timescale*DeltaTime;
if (!Validate())
{
m_TimeElapsed = 0.0f;
return false;
}
MoveToPointAt( m_TimeElapsed / GetDuration(), GetNodeFraction(), m_PreviousRotation );
return true;
}
CCinemaManager::CCinemaManager() : m_DrawCurrentSpline(false), m_Active(true), m_ValidCurrent(false)
{
m_CurrentPath = m_Paths.end();
}
void CCinemaManager::AddPath(CCinemaPath path, const CStrW& name)
{
ENSURE( m_Paths.find( name ) == m_Paths.end() );
m_Paths[name] = path;
}
void CCinemaManager::QueuePath(const CStrW& name, bool queue )
{
if (!m_PathQueue.empty() && queue == false)
{
return;
}
else
{
ENSURE(HasTrack(name));
m_PathQueue.push_back(m_Paths[name]);
}
}
void CCinemaManager::OverridePath(const CStrW& name)
{
m_PathQueue.clear();
ENSURE(HasTrack(name));
m_PathQueue.push_back( m_Paths[name] );
}
void CCinemaManager::SetAllPaths( const std::map& paths)
{
CStrW name;
m_Paths = paths;
}
void CCinemaManager::SetCurrentPath(const CStrW& name, bool current, bool drawLines)
{
if ( !HasTrack(name) )
m_ValidCurrent = false;
else
m_ValidCurrent = true;
m_CurrentPath = m_Paths.find(name);
m_DrawCurrentSpline = current;
m_DrawLines = drawLines;
DrawSpline();
}
bool CCinemaManager::HasTrack(const CStrW& name) const
{
return m_Paths.find(name) != m_Paths.end();
}
void CCinemaManager::DrawSpline() const
{
if ( !(m_DrawCurrentSpline && m_ValidCurrent) )
return;
static const int smoothness = 200;
m_CurrentPath->second.DrawSpline(CVector4D(0.f, 0.f, 1.f, 1.f), smoothness, m_DrawLines);
}
void CCinemaManager::MoveToPointAt(float time)
{
ENSURE(m_CurrentPath != m_Paths.end());
StopPlaying();
m_CurrentPath->second.m_TimeElapsed = time;
if ( !m_CurrentPath->second.Validate() )
return;
m_CurrentPath->second.MoveToPointAt(m_CurrentPath->second.m_TimeElapsed /
m_CurrentPath->second.GetDuration(), m_CurrentPath->second.GetNodeFraction(),
m_CurrentPath->second.m_PreviousRotation );
}
bool CCinemaManager::Update(float DeltaTime)
{
if (!m_PathQueue.front().Play(DeltaTime))
{
m_PathQueue.pop_front();
return false;
}
return true;
}
Index: ps/trunk/source/graphics/MaterialManager.h
===================================================================
--- ps/trunk/source/graphics/MaterialManager.h (revision 11452)
+++ ps/trunk/source/graphics/MaterialManager.h (revision 11453)
@@ -1,33 +1,34 @@
/* 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 .
*/
#ifndef INCLUDED_MATERIALMANAGER
#define INCLUDED_MATERIALMANAGER
#include