Explorar o código

Refactored shader loading. A binary format is now used instead of XML data.
PixelShader and VertexShader classes replaced with Shader and ShaderProgram.

Lasse Öörni %!s(int64=14) %!d(string=hai) anos
pai
achega
3ca3f84df9

+ 3 - 3
CMakeLists.txt

@@ -88,18 +88,18 @@ endmacro ()
 # Macro for shader asset compilation
 macro (add_shader NAME)
     add_custom_command (
-        OUTPUT ../../Bin/CoreData/Shaders/SM2/${NAME}.xml
+        OUTPUT ../../Bin/CoreData/Shaders/SM2/${NAME}.vs2
         COMMAND ../../Bin/ShaderCompiler ${NAME}.xml ../../Bin/CoreData/Shaders/SM2 SM2
         DEPENDS ShaderCompiler Common.hlsl ${NAME}.hlsl ${NAME}.xml
     )
 
     add_custom_command (
-        OUTPUT ../../Bin/CoreData/Shaders/SM3/${NAME}.xml
+        OUTPUT ../../Bin/CoreData/Shaders/SM3/${NAME}.vs3
         COMMAND ../../Bin/ShaderCompiler ${NAME}.xml ../../Bin/CoreData/Shaders/SM3 SM3
         DEPENDS ShaderCompiler Common.hlsl ${NAME}.hlsl ${NAME}.xml
     )
 
-    set (ALL_SHADERS ${ALL_SHADERS} ../../Bin/CoreData/Shaders/SM2/${NAME}.xml ../../Bin/CoreData/Shaders/SM3/${NAME}.xml)
+    set (ALL_SHADERS ${ALL_SHADERS} ../../Bin/CoreData/Shaders/SM2/${NAME}.vs2 ../../Bin/CoreData/Shaders/SM3/${NAME}.vs3)
 endmacro ()
 
 # Add projects

+ 32 - 3
Docs/Reference.dox

@@ -1074,15 +1074,15 @@ The texconv tool from the DirectX SDK needs to be available through the system P
 
 This tool generates HLSL shader permutations using an XML definition file that describes the permutations, and their associated HLSL preprocessor defines.
 
-The output consists of shader bytecode for each permutation, as well as an output XML file that describes the constant parameters and texture units (for pixel shaders only) used by each.
+The output consists of shader bytecode for each permutation, as well as information of the constant parameters and texture units used. See \ref FileFormats_Shader "Binary shader format" for details.
 
 Usage:
 
 \verbatim
 ShaderCompiler <definitionfile> <outputpath> [SM3] [define1] [define2] ..
 
-HLSL files will be loaded from definition file directory, and binary code will
-be output to same directory as the output file.
+HLSL files will be loaded from definition file directory, and binary files will
+be output to the output path, preserving the subdirectory structure.
 \endverbatim
 
 It is possible to give additional defines from the command line. These will then be present in each permutation. SM3 is a special define which enables compilation of VS3.0 and PS3.0 code, otherwise VS2.0 and PS2.0 code is generated.
@@ -1197,6 +1197,35 @@ uint       Number of tracks
 
 Note: animations are stored using absolute bone transformations. Therefore only lerp-blending between animations is supported; additive pose modification is not.
 
+\section FileFormats_Shader Binary shader format (.vs2, .ps2, .vs3, .ps3)
+
+\verbatim
+byte[4]    Identifier "USHD"
+
+short      Shader type (0 = vertex, 1 = pixel)
+short      Shader model (2 or 3)
+
+uint       Number of constant parameters
+
+    For each constant parameter:
+    cstring    Parameter name
+    byte       Hardware register index
+
+uint       Number of texture units (0 for vertex shaders)
+
+    For each texture unit:
+    cstring    Texture unit name
+    byte       Hardware sampler index
+
+uint       Number of shader variations
+
+    For each variation:
+    cstring    Variation name
+    bool[]     Use flags for constants
+    bool[]     Use flags for texture units
+    uint       Bytecode size
+    byte[]     Bytecode
+\endverbatim
 
 \page CodingConventions Coding conventions
 

+ 16 - 18
Engine/Engine/GraphicsAPI.cpp

@@ -239,20 +239,20 @@ static void RegisterTextures(asIScriptEngine* engine)
     engine->RegisterObjectMethod("TextureCube", "RenderSurface@+ get_renderSurface(CubeMapFace) const", asMETHOD(TextureCube, GetRenderSurface), asCALL_THISCALL);
 }
 
-static Vector4 MaterialGetVertexShaderParameter(VSParameter parameter, Material* ptr)
+static Vector4 MaterialGetVertexShaderParameter(ShaderParameter parameter, Material* ptr)
 {
-    const Map<VSParameter, Vector4>& parameters = ptr->GetVertexShaderParameters();
-    Map<VSParameter, Vector4>::ConstIterator i = parameters.Find(parameter);
+    const Map<ShaderParameter, Vector4>& parameters = ptr->GetVertexShaderParameters();
+    Map<ShaderParameter, Vector4>::ConstIterator i = parameters.Find(parameter);
     if (i == parameters.End())
         return Vector4::ZERO;
     else
         return i->second_;
 }
 
-static Vector4 MaterialGetPixelShaderParameter(PSParameter parameter, Material* ptr)
+static Vector4 MaterialGetPixelShaderParameter(ShaderParameter parameter, Material* ptr)
 {
-    const Map<PSParameter, Vector4>& parameters = ptr->GetPixelShaderParameters();
-    Map<PSParameter, Vector4>::ConstIterator i = parameters.Find(parameter);
+    const Map<ShaderParameter, Vector4>& parameters = ptr->GetPixelShaderParameters();
+    Map<ShaderParameter, Vector4>::ConstIterator i = parameters.Find(parameter);
     if (i == parameters.End())
         return Vector4::ZERO;
     else
@@ -270,14 +270,12 @@ static Material* MaterialClone(const String& cloneName, Material* ptr)
 
 static void RegisterMaterial(asIScriptEngine* engine)
 {
-    engine->RegisterEnum("VSParameter");
-    engine->RegisterEnumValue("VSParameter", "VSP_UOFFSET", VSP_UOFFSET);
-    engine->RegisterEnumValue("VSParameter", "VSP_VOFFSET", VSP_VOFFSET);
-    
-    engine->RegisterEnum("PSParameter");
-    engine->RegisterEnumValue("PSParameter", "PSP_MATDIFFCOLOR", PSP_MATDIFFCOLOR);
-    engine->RegisterEnumValue("PSParameter", "PSP_MATEMISSIVECOLOR", PSP_MATEMISSIVECOLOR);
-    engine->RegisterEnumValue("PSParameter", "PSP_MATSPECPROPERTIES", PSP_MATSPECPROPERTIES);
+    engine->RegisterEnum("ShaderParameter");
+    engine->RegisterEnumValue("ShaderParameter", "VSP_UOFFSET", VSP_UOFFSET);
+    engine->RegisterEnumValue("ShaderParameter", "VSP_VOFFSET", VSP_VOFFSET);
+    engine->RegisterEnumValue("ShaderParameter", "PSP_MATDIFFCOLOR", PSP_MATDIFFCOLOR);
+    engine->RegisterEnumValue("ShaderParameter", "PSP_MATEMISSIVECOLOR", PSP_MATEMISSIVECOLOR);
+    engine->RegisterEnumValue("ShaderParameter", "PSP_MATSPECPROPERTIES", PSP_MATSPECPROPERTIES);
     
     engine->RegisterEnum("TextureUnit");
     engine->RegisterEnumValue("TextureUnit", "TU_DIFFUSE", TU_DIFFUSE);
@@ -354,10 +352,10 @@ static void RegisterMaterial(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Material", "void set_numTechniques(uint)", asMETHOD(Material, SetNumTechniques), asCALL_THISCALL);
     engine->RegisterObjectMethod("Material", "uint get_numTechniques() const", asMETHOD(Material, GetNumTechniques), asCALL_THISCALL);
     engine->RegisterObjectMethod("Material", "Technique@+ get_technique(uint)", asMETHOD(Material, GetTechnique), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Material", "void set_vertexShaderParameter(VSParameter, const Vector4&in)", asMETHOD(Material, SetVertexShaderParameter), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Material", "Vector4 get_vertexShaderParameter(VSParameter) const", asFUNCTION(MaterialGetVertexShaderParameter), asCALL_CDECL_OBJLAST);
-    engine->RegisterObjectMethod("Material", "void set_pixelShaderParameter(PSParameter, const Vector4&in)", asMETHOD(Material, SetPixelShaderParameter), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Material", "Vector4 get_pixelShaderParameter(VSParameter) const", asFUNCTION(MaterialGetPixelShaderParameter), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectMethod("Material", "void set_vertexShaderParameter(ShaderParameter, const Vector4&in)", asMETHOD(Material, SetVertexShaderParameter), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Material", "Vector4 get_vertexShaderParameter(ShaderParameter) const", asFUNCTION(MaterialGetVertexShaderParameter), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectMethod("Material", "void set_pixelShaderParameter(ShaderParameter, const Vector4&in)", asMETHOD(Material, SetPixelShaderParameter), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Material", "Vector4 get_pixelShaderParameter(ShaderParameter) const", asFUNCTION(MaterialGetPixelShaderParameter), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("Material", "void set_texture(TextureUnit, Texture@+)", asMETHOD(Material, SetTexture), asCALL_THISCALL);
     engine->RegisterObjectMethod("Material", "Texture@+ get_texture(TextureUnit) const", asMETHOD(Material, GetTexture), asCALL_THISCALL);
     engine->RegisterObjectMethod("Material", "bool get_occlusion()", asMETHOD(Material, GetOcclusion), asCALL_THISCALL);

+ 7 - 8
Engine/Graphics/Batch.cpp

@@ -29,13 +29,12 @@
 #include "Light.h"
 #include "Material.h"
 #include "Renderer.h"
-#include "PixelShader.h"
 #include "Profiler.h"
+#include "ShaderProgram.h"
 #include "Sort.h"
 #include "Technique.h"
 #include "Texture2D.h"
 #include "VertexBuffer.h"
-#include "VertexShader.h"
 
 #include "DebugNew.h"
 
@@ -200,8 +199,8 @@ void Batch::Prepare(Graphics* graphics, bool SetModelTransform) const
     // Set material's vertex shader parameters
     if (material_)
     {
-        const Map<VSParameter, Vector4>& parameters = material_->GetVertexShaderParameters();
-        for (Map<VSParameter, Vector4>::ConstIterator i = parameters.Begin(); i != parameters.End(); ++i)
+        const Map<ShaderParameter, Vector4>& parameters = material_->GetVertexShaderParameters();
+        for (Map<ShaderParameter, Vector4>::ConstIterator i = parameters.Begin(); i != parameters.End(); ++i)
         {
             if (vertexShader_->NeedParameterUpdate(i->first_, material_))
                 graphics->SetVertexShaderParameter(i->first_, i->second_);
@@ -279,8 +278,8 @@ void Batch::Prepare(Graphics* graphics, bool SetModelTransform) const
     // Set material's pixel shader parameters
     if (material_)
     {
-        const Map<PSParameter, Vector4>& parameters = material_->GetPixelShaderParameters();
-        for (Map<PSParameter, Vector4>::ConstIterator i = parameters.Begin(); i != parameters.End(); ++i)
+        const Map<ShaderParameter, Vector4>& parameters = material_->GetPixelShaderParameters();
+        for (Map<ShaderParameter, Vector4>::ConstIterator i = parameters.Begin(); i != parameters.End(); ++i)
         {
             if (pixelShader_->NeedParameterUpdate(i->first_, material_))
                 graphics->SetPixelShaderParameter(i->first_, i->second_);
@@ -408,8 +407,8 @@ void BatchGroup::Draw(Graphics* graphics, VertexBuffer* buffer) const
     {
         // Switch to the instancing vertex shader
         // The indexing is different in the forward lit passes
-        Vector<SharedPtr<VertexShader> >& vertexShaders = pass_->GetVertexShaders();
-        Vector<SharedPtr<PixelShader> >& pixelShaders = pass_->GetPixelShaders();
+        Vector<SharedPtr<ShaderProgram> >& vertexShaders = pass_->GetVertexShaders();
+        Vector<SharedPtr<ShaderProgram> >& pixelShaders = pass_->GetPixelShaders();
         PassType type = pass_->GetType();
         if ((type != PASS_LITBASE) && (type != PASS_LIGHT))
             batch.vertexShader_ = vertexShaders[vertexShaderIndex_ + GEOM_INSTANCED];

+ 6 - 7
Engine/Graphics/Batch.h

@@ -30,14 +30,13 @@
 class Camera;
 class Drawable;
 class Geometry;
+class Graphics;
 class Light;
 class Material;
 class Pass;
 class Matrix4x3;
-class PixelShader;
-class Graphics;
+class ShaderProgram;
 class VertexBuffer;
-class VertexShader;
 
 /// Description of a 3D geometry draw call
 struct Batch
@@ -69,9 +68,9 @@ struct Batch
     /// Material pass
     Pass* pass_;
     /// Vertex shader
-    VertexShader* vertexShader_;
+    ShaderProgram* vertexShader_;
     /// Pixel shader
-    PixelShader* pixelShader_;
+    ShaderProgram* pixelShader_;
     /// Camera
     Camera* camera_;
     /// Light that affects the geometry, if any
@@ -143,9 +142,9 @@ struct BatchGroup
     /// Material pass
     Pass* pass_;
     /// Vertex shader
-    VertexShader* vertexShader_;
+    ShaderProgram* vertexShader_;
     /// Pixel shader
-    PixelShader* pixelShader_;
+    ShaderProgram* pixelShader_;
     /// Camera
     Camera* camera_;
     /// Light that affects the geometry, if any

+ 1 - 2
Engine/Graphics/DebugRenderer.cpp

@@ -30,11 +30,10 @@
 #include "DebugRenderer.h"
 #include "Graphics.h"
 #include "Light.h"
-#include "PixelShader.h"
 #include "Profiler.h"
 #include "Renderer.h"
 #include "ResourceCache.h"
-#include "VertexShader.h"
+#include "ShaderProgram.h"
 
 #include "DebugNew.h"
 

+ 96 - 120
Engine/Graphics/Graphics.cpp

@@ -38,15 +38,15 @@
 #include "Material.h"
 #include "Octree.h"
 #include "ParticleEmitter.h"
-#include "PixelShader.h"
 #include "Profiler.h"
+#include "Shader.h"
+#include "ShaderProgram.h"
 #include "Skybox.h"
 #include "Technique.h"
 #include "Texture2D.h"
 #include "TextureCube.h"
 #include "VertexBuffer.h"
 #include "VertexDeclaration.h"
-#include "VertexShader.h"
 #include "Zone.h"
 
 #include "DebugNew.h"
@@ -907,11 +907,11 @@ void Graphics::SetIndexBuffer(IndexBuffer* buffer)
     }
 }
 
-void Graphics::SetShaders(VertexShader* vs, PixelShader* ps)
+void Graphics::SetShaders(ShaderProgram* vs, ShaderProgram* ps)
 {
     if (vs != vertexShader_)
     {
-        if (vs)
+        if ((vs) && (vs->GetShaderType() == VS))
             impl_->device_->SetVertexShader((IDirect3DVertexShader9*)vs->GetGPUObject());
         else
             impl_->device_->SetVertexShader(0);
@@ -921,7 +921,7 @@ void Graphics::SetShaders(VertexShader* vs, PixelShader* ps)
     
     if (ps != pixelShader_)
     {
-        if (ps)
+        if ((ps) && (ps->GetShaderType() == PS))
             impl_->device_->SetPixelShader((IDirect3DPixelShader9*)ps->GetGPUObject());
         else
             impl_->device_->SetPixelShader(0);
@@ -930,36 +930,36 @@ void Graphics::SetShaders(VertexShader* vs, PixelShader* ps)
     }
 }
 
-void Graphics::SetVertexShaderParameter(VSParameter param, const bool* data, unsigned count)
+void Graphics::SetVertexShaderParameter(ShaderParameter param, const bool* data, unsigned count)
 {
-    unsigned index = vsRegisters_[param];
+    unsigned index = shaderRegisters_[param];
     if (index >= MAX_CONSTANT_REGISTERS)
         return;
     
     impl_->device_->SetVertexShaderConstantB(index, (const BOOL*)data, count);
 }
 
-void Graphics::SetVertexShaderParameter(VSParameter param, const float* data, unsigned count)
+void Graphics::SetVertexShaderParameter(ShaderParameter param, const float* data, unsigned count)
 {
-    unsigned index = vsRegisters_[param];
+    unsigned index = shaderRegisters_[param];
     if (index >= MAX_CONSTANT_REGISTERS)
         return;
     
     impl_->device_->SetVertexShaderConstantF(index, data, count / 4);
 }
 
-void Graphics::SetVertexShaderParameter(VSParameter param, const int* data, unsigned count)
+void Graphics::SetVertexShaderParameter(ShaderParameter param, const int* data, unsigned count)
 {
-    unsigned index = vsRegisters_[param];
+    unsigned index = shaderRegisters_[param];
     if (index >= MAX_CONSTANT_REGISTERS)
         return;
     
     impl_->device_->SetVertexShaderConstantI(index, data, count / 4);
 }
 
-void Graphics::SetVertexShaderParameter(VSParameter param, float value)
+void Graphics::SetVertexShaderParameter(ShaderParameter param, float value)
 {
-    unsigned index = vsRegisters_[param];
+    unsigned index = shaderRegisters_[param];
     if (index >= MAX_CONSTANT_REGISTERS)
         return;
     
@@ -976,18 +976,18 @@ void Graphics::SetVertexShaderParameter(VSParameter param, float value)
     impl_->device_->SetVertexShaderConstantF(index, &data[0], 1);
 }
 
-void Graphics::SetVertexShaderParameter(VSParameter param, const Color& color)
+void Graphics::SetVertexShaderParameter(ShaderParameter param, const Color& color)
 {
-    unsigned index = vsRegisters_[param];
+    unsigned index = shaderRegisters_[param];
     if (index >= MAX_CONSTANT_REGISTERS)
         return;
     
     impl_->device_->SetVertexShaderConstantF(index, color.GetData(), 1);
 }
 
-void Graphics::SetVertexShaderParameter(VSParameter param, const Matrix3& matrix)
+void Graphics::SetVertexShaderParameter(ShaderParameter param, const Matrix3& matrix)
 {
-    unsigned index = vsRegisters_[param];
+    unsigned index = shaderRegisters_[param];
     if (index >= MAX_CONSTANT_REGISTERS)
         return;
     
@@ -1009,9 +1009,9 @@ void Graphics::SetVertexShaderParameter(VSParameter param, const Matrix3& matrix
     impl_->device_->SetVertexShaderConstantF(index, &data[0], 3);
 }
 
-void Graphics::SetVertexShaderParameter(VSParameter param, const Vector3& vector)
+void Graphics::SetVertexShaderParameter(ShaderParameter param, const Vector3& vector)
 {
-    unsigned index = vsRegisters_[param];
+    unsigned index = shaderRegisters_[param];
     if (index >= MAX_CONSTANT_REGISTERS)
         return;
     
@@ -1030,63 +1030,63 @@ void Graphics::SetVertexShaderParameter(VSParameter param, const Vector3& vector
     impl_->device_->SetVertexShaderConstantF(index, &data[0], 1);
 }
 
-void Graphics::SetVertexShaderParameter(VSParameter param, const Matrix4& matrix)
+void Graphics::SetVertexShaderParameter(ShaderParameter param, const Matrix4& matrix)
 {
-    unsigned index = vsRegisters_[param];
+    unsigned index = shaderRegisters_[param];
     if (index >= MAX_CONSTANT_REGISTERS)
         return;
     
     impl_->device_->SetVertexShaderConstantF(index, matrix.GetData(), 4);
 }
 
-void Graphics::SetVertexShaderParameter(VSParameter param, const Vector4& vector)
+void Graphics::SetVertexShaderParameter(ShaderParameter param, const Vector4& vector)
 {
-    unsigned index = vsRegisters_[param];
+    unsigned index = shaderRegisters_[param];
     if (index >= MAX_CONSTANT_REGISTERS)
         return;
     
     impl_->device_->SetVertexShaderConstantF(index, vector.GetData(), 1);
 }
 
-void Graphics::SetVertexShaderParameter(VSParameter param, const Matrix4x3& matrix)
+void Graphics::SetVertexShaderParameter(ShaderParameter param, const Matrix4x3& matrix)
 {
-    unsigned index = vsRegisters_[param];
+    unsigned index = shaderRegisters_[param];
     if (index >= MAX_CONSTANT_REGISTERS)
         return;
     
     impl_->device_->SetVertexShaderConstantF(index, matrix.GetData(), 3);
 }
 
-void Graphics::SetPixelShaderParameter(PSParameter param, const bool* data, unsigned count)
+void Graphics::SetPixelShaderParameter(ShaderParameter param, const bool* data, unsigned count)
 {
-    unsigned index = psRegisters_[param];
+    unsigned index = shaderRegisters_[param];
     if (index >= MAX_CONSTANT_REGISTERS)
         return;
     
     impl_->device_->SetPixelShaderConstantB(index, (const BOOL*)data, count);
 }
 
-void Graphics::SetPixelShaderParameter(PSParameter param, const float* data, unsigned count)
+void Graphics::SetPixelShaderParameter(ShaderParameter param, const float* data, unsigned count)
 {
-    unsigned index = psRegisters_[param];
+    unsigned index = shaderRegisters_[param];
     if (index >= MAX_CONSTANT_REGISTERS)
         return;
     
     impl_->device_->SetPixelShaderConstantF(index, data, count / 4);
 }
 
-void Graphics::SetPixelShaderParameter(PSParameter param, const int* data, unsigned count)
+void Graphics::SetPixelShaderParameter(ShaderParameter param, const int* data, unsigned count)
 {
-    unsigned index = psRegisters_[param];
+    unsigned index = shaderRegisters_[param];
     if (index >= MAX_CONSTANT_REGISTERS)
         return;
     
     impl_->device_->SetPixelShaderConstantI(index, data, count / 4);
 }
 
-void Graphics::SetPixelShaderParameter(PSParameter param, float value)
+void Graphics::SetPixelShaderParameter(ShaderParameter param, float value)
 {
-    unsigned index = psRegisters_[param];
+    unsigned index = shaderRegisters_[param];
     if (index >= MAX_CONSTANT_REGISTERS)
         return;
     
@@ -1103,18 +1103,18 @@ void Graphics::SetPixelShaderParameter(PSParameter param, float value)
     impl_->device_->SetPixelShaderConstantF(index, &data[0], 1);
 }
 
-void Graphics::SetPixelShaderParameter(PSParameter param, const Color& color)
+void Graphics::SetPixelShaderParameter(ShaderParameter param, const Color& color)
 {
-    unsigned index = psRegisters_[param];
+    unsigned index = shaderRegisters_[param];
     if (index >= MAX_CONSTANT_REGISTERS)
         return;
     
     impl_->device_->SetPixelShaderConstantF(index, color.GetData(), 1);
 }
 
-void Graphics::SetPixelShaderParameter(PSParameter param, const Matrix3& matrix)
+void Graphics::SetPixelShaderParameter(ShaderParameter param, const Matrix3& matrix)
 {
-    unsigned index = psRegisters_[param];
+    unsigned index = shaderRegisters_[param];
     if (index >= MAX_CONSTANT_REGISTERS)
         return;
     
@@ -1136,9 +1136,9 @@ void Graphics::SetPixelShaderParameter(PSParameter param, const Matrix3& matrix)
     impl_->device_->SetPixelShaderConstantF(index, &data[0], 3);
 }
 
-void Graphics::SetPixelShaderParameter(PSParameter param, const Vector3& vector)
+void Graphics::SetPixelShaderParameter(ShaderParameter param, const Vector3& vector)
 {
-    unsigned index = psRegisters_[param];
+    unsigned index = shaderRegisters_[param];
     if (index >= MAX_CONSTANT_REGISTERS)
         return;
     
@@ -1157,27 +1157,27 @@ void Graphics::SetPixelShaderParameter(PSParameter param, const Vector3& vector)
     impl_->device_->SetPixelShaderConstantF(index, &data[0], 1);
 }
 
-void Graphics::SetPixelShaderParameter(PSParameter param, const Matrix4& matrix)
+void Graphics::SetPixelShaderParameter(ShaderParameter param, const Matrix4& matrix)
 {
-    unsigned index = psRegisters_[param];
+    unsigned index = shaderRegisters_[param];
     if (index >= MAX_CONSTANT_REGISTERS)
         return;
     
     impl_->device_->SetPixelShaderConstantF(index, matrix.GetData(), 4);
 }
 
-void Graphics::SetPixelShaderParameter(PSParameter param, const Vector4& vector)
+void Graphics::SetPixelShaderParameter(ShaderParameter param, const Vector4& vector)
 {
-    unsigned index = psRegisters_[param];
+    unsigned index = shaderRegisters_[param];
     if (index >= MAX_CONSTANT_REGISTERS)
         return;
     
     impl_->device_->SetPixelShaderConstantF(index, vector.GetData(), 1);
 }
 
-void Graphics::SetPixelShaderParameter(PSParameter param, const Matrix4x3& matrix)
+void Graphics::SetPixelShaderParameter(ShaderParameter param, const Matrix4x3& matrix)
 {
-    unsigned index = psRegisters_[param];
+    unsigned index = shaderRegisters_[param];
     if (index >= MAX_CONSTANT_REGISTERS)
         return;
     
@@ -1186,16 +1186,14 @@ void Graphics::SetPixelShaderParameter(PSParameter param, const Matrix4x3& matri
 
 void Graphics::ClearLastParameterSources()
 {
-    for (unsigned i = 0; i < MAX_VS_PARAMETERS; ++i)
-        lastVSParameterSources_[i] = (const void*)M_MAX_UNSIGNED;
-    for (unsigned i = 0; i < MAX_PS_PARAMETERS; ++i)
-        lastPSParameterSources_[i] = (const void*)M_MAX_UNSIGNED;
+    for (unsigned i = 0; i < MAX_SHADER_PARAMETERS; ++i)
+        lastShaderParameterSources_[i] = (const void*)M_MAX_UNSIGNED;
 }
 
 void Graphics::ClearTransformSources()
 {
-    lastVSParameterSources_[VSP_MODEL] = (const void*)M_MAX_UNSIGNED;
-    lastVSParameterSources_[VSP_VIEWPROJ] = (const void*)M_MAX_UNSIGNED;
+    lastShaderParameterSources_[VSP_MODEL] = (const void*)M_MAX_UNSIGNED;
+    lastShaderParameterSources_[VSP_VIEWPROJ] = (const void*)M_MAX_UNSIGNED;
 }
 
 void Graphics::SetTexture(unsigned index, Texture* texture)
@@ -1954,22 +1952,13 @@ VertexBuffer* Graphics::GetVertexBuffer(unsigned index) const
     return index < MAX_VERTEX_STREAMS ? vertexBuffer_[index] : 0;
 }
 
-VSParameter Graphics::GetVSParameter(const String& name)
+ShaderParameter Graphics::GetShaderParameter(const String& name)
 {
-    Map<String, VSParameter>::Iterator i = vsParameters_.Find(name);
-    if (i != vsParameters_.End())
+    Map<String, ShaderParameter>::Iterator i = shaderParameters_.Find(name);
+    if (i != shaderParameters_.End())
         return i->second_;
     else
-        return MAX_VS_PARAMETERS;
-}
-
-PSParameter Graphics::GetPSParameter(const String& name)
-{
-    Map<String, PSParameter>::Iterator i = psParameters_.Find(name);
-    if (i != psParameters_.End())
-        return i->second_;
-    else
-        return MAX_PS_PARAMETERS;
+        return MAX_SHADER_PARAMETERS;
 }
 
 TextureUnit Graphics::GetTextureUnit(const String& name)
@@ -1981,19 +1970,9 @@ TextureUnit Graphics::GetTextureUnit(const String& name)
         return MAX_TEXTURE_UNITS;
 }
 
-const String& Graphics::GetVSParameterName(VSParameter parameter)
-{
-    for (Map<String, VSParameter>::Iterator i = vsParameters_.Begin(); i != vsParameters_.End(); ++i)
-    {
-        if (i->second_ == parameter)
-            return i->first_;
-    }
-    return noParameter;
-}
-
-const String& Graphics::GetPSParameterName(PSParameter parameter)
+const String& Graphics::GetShaderParameterName(ShaderParameter parameter)
 {
-    for (Map<String, PSParameter>::Iterator i = psParameters_.Begin(); i != psParameters_.End(); ++i)
+    for (Map<String, ShaderParameter>::Iterator i = shaderParameters_.Begin(); i != shaderParameters_.End(); ++i)
     {
         if (i->second_ == parameter)
             return i->first_;
@@ -2409,50 +2388,48 @@ void Graphics::ResetCachedState()
 void Graphics::InitializeShaderParameters()
 {
     // Initialize all parameters as unknown
-    for (unsigned i = 0; i < MAX_VS_PARAMETERS; ++i)
-        vsRegisters_[i] = MAX_CONSTANT_REGISTERS;
-    for (unsigned i = 0; i < MAX_PS_PARAMETERS; ++i)
-        psRegisters_[i] = MAX_CONSTANT_REGISTERS;
+    for (unsigned i = 0; i < MAX_SHADER_PARAMETERS; ++i)
+        shaderRegisters_[i] = MAX_CONSTANT_REGISTERS;
     
     // Map parameter names
-    vsParameters_["CameraPos"] = VSP_CAMERAPOS;
-    vsParameters_["CameraRot"] = VSP_CAMERAROT;
-    vsParameters_["DepthMode"] = VSP_DEPTHMODE;
-    vsParameters_["ElapsedTime"] = VSP_ELAPSEDTIME;
-    vsParameters_["FrustumSize"] = VSP_FRUSTUMSIZE;
-    vsParameters_["GBufferOffsets"] = VSP_GBUFFEROFFSETS;
-    vsParameters_["Model"] = VSP_MODEL;
-    vsParameters_["ShadowProj"] = VSP_SHADOWPROJ;
-    vsParameters_["SpotProj"] = VSP_SPOTPROJ;
-    vsParameters_["ViewProj"] = VSP_VIEWPROJ;
-    vsParameters_["UOffset"] = VSP_UOFFSET;
-    vsParameters_["VOffset"] = VSP_VOFFSET;
-    vsParameters_["ViewRightVector"] = VSP_VIEWRIGHTVECTOR;
-    vsParameters_["ViewUpVector"] = VSP_VIEWUPVECTOR;
-    vsParameters_["SkinMatrices"] = VSP_SKINMATRICES;
-    
-    psParameters_["AmbientColor"] = PSP_AMBIENTCOLOR;
-    psParameters_["AntiAliasWeights"] = PSP_ANTIALIASWEIGHTS;
-    psParameters_["CameraPosPS"] = PSP_CAMERAPOS;
-    psParameters_["ElapsedTimePS"] = PSP_ELAPSEDTIME;
-    psParameters_["FogColor"] = PSP_FOGCOLOR;
-    psParameters_["FogParams"] = PSP_FOGPARAMS;
-    psParameters_["GBufferOffsetsPS"] = PSP_GBUFFEROFFSETS;
-    psParameters_["GBufferViewport"] = PSP_GBUFFERVIEWPORT;
-    psParameters_["LightAtten"] = PSP_LIGHTATTEN;
-    psParameters_["LightColor"] = PSP_LIGHTCOLOR;
-    psParameters_["LightDir"] = PSP_LIGHTDIR;
-    psParameters_["LightPos"] = PSP_LIGHTPOS;
-    psParameters_["LightSplits"] = PSP_LIGHTSPLITS;
-    psParameters_["LightVecRot"] = PSP_LIGHTVECROT;
-    psParameters_["MatDiffColor"] = PSP_MATDIFFCOLOR;
-    psParameters_["MatEmissiveColor"] = PSP_MATEMISSIVECOLOR;
-    psParameters_["MatSpecProperties"] = PSP_MATSPECPROPERTIES;
-    psParameters_["SampleOffsets"] = PSP_SAMPLEOFFSETS;
-    psParameters_["ShadowIntensity"] = PSP_SHADOWINTENSITY;
-    psParameters_["ShadowProjPS"] = PSP_SHADOWPROJ;
-    psParameters_["SpotProjPS"] = PSP_SPOTPROJ;
-    psParameters_["ViewProjPS"] = PSP_VIEWPROJ;
+    shaderParameters_["CameraPos"] = VSP_CAMERAPOS;
+    shaderParameters_["CameraRot"] = VSP_CAMERAROT;
+    shaderParameters_["DepthMode"] = VSP_DEPTHMODE;
+    shaderParameters_["ElapsedTime"] = VSP_ELAPSEDTIME;
+    shaderParameters_["FrustumSize"] = VSP_FRUSTUMSIZE;
+    shaderParameters_["GBufferOffsets"] = VSP_GBUFFEROFFSETS;
+    shaderParameters_["Model"] = VSP_MODEL;
+    shaderParameters_["ShadowProj"] = VSP_SHADOWPROJ;
+    shaderParameters_["SpotProj"] = VSP_SPOTPROJ;
+    shaderParameters_["ViewProj"] = VSP_VIEWPROJ;
+    shaderParameters_["UOffset"] = VSP_UOFFSET;
+    shaderParameters_["VOffset"] = VSP_VOFFSET;
+    shaderParameters_["ViewRightVector"] = VSP_VIEWRIGHTVECTOR;
+    shaderParameters_["ViewUpVector"] = VSP_VIEWUPVECTOR;
+    shaderParameters_["SkinMatrices"] = VSP_SKINMATRICES;
+    
+    shaderParameters_["AmbientColor"] = PSP_AMBIENTCOLOR;
+    shaderParameters_["AntiAliasWeights"] = PSP_ANTIALIASWEIGHTS;
+    shaderParameters_["CameraPosPS"] = PSP_CAMERAPOS;
+    shaderParameters_["ElapsedTimePS"] = PSP_ELAPSEDTIME;
+    shaderParameters_["FogColor"] = PSP_FOGCOLOR;
+    shaderParameters_["FogParams"] = PSP_FOGPARAMS;
+    shaderParameters_["GBufferOffsetsPS"] = PSP_GBUFFEROFFSETS;
+    shaderParameters_["GBufferViewport"] = PSP_GBUFFERVIEWPORT;
+    shaderParameters_["LightAtten"] = PSP_LIGHTATTEN;
+    shaderParameters_["LightColor"] = PSP_LIGHTCOLOR;
+    shaderParameters_["LightDir"] = PSP_LIGHTDIR;
+    shaderParameters_["LightPos"] = PSP_LIGHTPOS;
+    shaderParameters_["LightSplits"] = PSP_LIGHTSPLITS;
+    shaderParameters_["LightVecRot"] = PSP_LIGHTVECROT;
+    shaderParameters_["MatDiffColor"] = PSP_MATDIFFCOLOR;
+    shaderParameters_["MatEmissiveColor"] = PSP_MATEMISSIVECOLOR;
+    shaderParameters_["MatSpecProperties"] = PSP_MATSPECPROPERTIES;
+    shaderParameters_["SampleOffsets"] = PSP_SAMPLEOFFSETS;
+    shaderParameters_["ShadowIntensity"] = PSP_SHADOWINTENSITY;
+    shaderParameters_["ShadowProjPS"] = PSP_SHADOWPROJ;
+    shaderParameters_["SpotProjPS"] = PSP_SPOTPROJ;
+    shaderParameters_["ViewProjPS"] = PSP_VIEWPROJ;
     
     // Map texture units
     textureUnits_["NormalMap"] = TU_NORMAL;
@@ -2521,8 +2498,7 @@ void RegisterGraphicsLibrary(Context* context)
     Animation::RegisterObject(context);
     Material::RegisterObject(context);
     Model::RegisterObject(context);
-    PixelShader::RegisterObject(context);
-    VertexShader::RegisterObject(context);
+    Shader::RegisterObject(context);
     Technique::RegisterObject(context);
     Texture2D::RegisterObject(context);
     TextureCube::RegisterObject(context);

+ 43 - 60
Engine/Graphics/Graphics.h

@@ -33,10 +33,10 @@ class IndexBuffer;
 class Matrix3;
 class Matrix4;
 class Matrix4x3;
-class PixelShader;
 class GPUObject;
 class GraphicsImpl;
 class RenderSurface;
+class ShaderProgram;
 class Texture;
 class Texture2D;
 class TextureCube;
@@ -44,7 +44,6 @@ class Vector3;
 class Vector4;
 class VertexBuffer;
 class VertexDeclaration;
-class VertexShader;
 
 static const int IMMEDIATE_BUFFER_DEFAULT_SIZE = 1024;
 static const int NUM_SCREEN_BUFFERS = 2;
@@ -100,55 +99,51 @@ public:
     /// Set index buffer
     void SetIndexBuffer(IndexBuffer* buffer);
     /// Set shaders
-    void SetShaders(VertexShader* vs, PixelShader* ps);
+    void SetShaders(ShaderProgram* vs, ShaderProgram* ps);
     /// Set vertex shader bool parameter
-    void SetVertexShaderParameter(VSParameter param, const bool* data, unsigned count);
+    void SetVertexShaderParameter(ShaderParameter param, const bool* data, unsigned count);
     /// Set vertex shader float constants
-    void SetVertexShaderParameter(VSParameter param, const float* data, unsigned count);
+    void SetVertexShaderParameter(ShaderParameter param, const float* data, unsigned count);
     /// Set vertex shader int constants
-    void SetVertexShaderParameter(VSParameter param, const int* data, unsigned count);
+    void SetVertexShaderParameter(ShaderParameter param, const int* data, unsigned count);
     /// Set vertex shader float constant
-    void SetVertexShaderParameter(VSParameter param, float value);
+    void SetVertexShaderParameter(ShaderParameter param, float value);
     /// Set vertex shader color constant
-    void SetVertexShaderParameter(VSParameter param, const Color& color);
+    void SetVertexShaderParameter(ShaderParameter param, const Color& color);
     /// Set vertex shader 3x3 matrix constant
-    void SetVertexShaderParameter(VSParameter param, const Matrix3& matrix);
+    void SetVertexShaderParameter(ShaderParameter param, const Matrix3& matrix);
     /// Set vertex shader 3D vector constant
-    void SetVertexShaderParameter(VSParameter param, const Vector3& vector);
+    void SetVertexShaderParameter(ShaderParameter param, const Vector3& vector);
     /// Set vertex shader 4x4 matrix constant
-    void SetVertexShaderParameter(VSParameter param, const Matrix4& matrix);
+    void SetVertexShaderParameter(ShaderParameter param, const Matrix4& matrix);
     /// Set vertex shader 4D vector constant
-    void SetVertexShaderParameter(VSParameter param, const Vector4& vector);
+    void SetVertexShaderParameter(ShaderParameter param, const Vector4& vector);
     /// Set vertex shader 4x3 matrix constant
-    void SetVertexShaderParameter(VSParameter param, const Matrix4x3& matrix);
+    void SetVertexShaderParameter(ShaderParameter param, const Matrix4x3& matrix);
     /// Set pixel shader bool constants
-    void SetPixelShaderParameter(PSParameter param, const bool* data, unsigned count);
+    void SetPixelShaderParameter(ShaderParameter param, const bool* data, unsigned count);
     /// Set pixel shader float constants
-    void SetPixelShaderParameter(PSParameter param, const float* data, unsigned count);
+    void SetPixelShaderParameter(ShaderParameter param, const float* data, unsigned count);
     /// Set pixel shader int constants
-    void SetPixelShaderParameter(PSParameter param, const int* data, unsigned count);
+    void SetPixelShaderParameter(ShaderParameter param, const int* data, unsigned count);
     /// Set pixel shader float constant
-    void SetPixelShaderParameter(PSParameter param, float value);
+    void SetPixelShaderParameter(ShaderParameter param, float value);
     /// Set pixel shader color constant
-    void SetPixelShaderParameter(PSParameter param, const Color& color);
+    void SetPixelShaderParameter(ShaderParameter param, const Color& color);
     /// Set pixel shader 3x3 matrix constant
-    void SetPixelShaderParameter(PSParameter param, const Matrix3& matrix);
+    void SetPixelShaderParameter(ShaderParameter param, const Matrix3& matrix);
     /// Set pixel shader 3D vector constant
-    void SetPixelShaderParameter(PSParameter param, const Vector3& vector);
+    void SetPixelShaderParameter(ShaderParameter param, const Vector3& vector);
      /// Set pixel shader 4x4 matrix constant
-    void SetPixelShaderParameter(PSParameter param, const Matrix4& matrix);
+    void SetPixelShaderParameter(ShaderParameter param, const Matrix4& matrix);
     /// Set pixel shader 3D vector constant
-    void SetPixelShaderParameter(PSParameter param, const Vector4& vector);
+    void SetPixelShaderParameter(ShaderParameter param, const Vector4& vector);
     /// Set pixel shader 4x3 matrix constant
-    void SetPixelShaderParameter(PSParameter param, const Matrix4x3& matrix);
+    void SetPixelShaderParameter(ShaderParameter param, const Matrix4x3& matrix);
     /// Set vertex shader parameter source. Called by VertexShader
-    void SetVSParameterSource(VSParameter param, const void* source) { lastVSParameterSources_[param] = source; }
-    /// Set pixel shader parameter source. Called by PixelShader
-    void SetPSParameterSource(PSParameter param, const void* source) { lastPSParameterSources_[param] = source; }
-    /// Map vertex shader parameter to a constant Register. Called by VertexShader
-    void SetVSRegister(VSParameter param, unsigned index) { vsRegisters_[param] = index; }
-    /// Map pixel shader parameter to a constant Register. Called by PixelShader
-    void SetPSRegister(PSParameter param, unsigned index) { psRegisters_[param] = index; }
+    void SetShaderParameterSource(ShaderParameter param, const void* source) { lastShaderParameterSources_[param] = source; }
+    /// Map shader parameter to a constant register. Called by Shader
+    void SetShaderRegister(ShaderParameter param, unsigned index) { shaderRegisters_[param] = index; }
     /// Clear remembered shader parameter sources
     void ClearLastParameterSources();
     /// Clear remembered transform shader parameter sources
@@ -279,29 +274,23 @@ public:
     /// Return vertex declaration
     VertexDeclaration* GetVertexDeclaration() const { return vertexDeclaration_; }
     /// Return vertex shader
-    VertexShader* GetVertexShader() const { return vertexShader_; }
+    ShaderProgram* GetVertexShader() const { return vertexShader_; }
     /// Return pixel shader
-    PixelShader* GetPixelShader() const { return pixelShader_; }
-    /// Return vertex shader parameter index by name
-    VSParameter GetVSParameter(const String& name);
-    /// Return pixel shader parameter index by name
-    PSParameter GetPSParameter(const String& name);
+    ShaderProgram* GetPixelShader() const { return pixelShader_; }
+    /// Return shader parameter index by name
+    ShaderParameter GetShaderParameter(const String& name);
     /// Return texture unit index by name
     TextureUnit GetTextureUnit(const String& name);
-    /// Return vertex shader parameter name by index
-    const String& GetVSParameterName(VSParameter parameter);
-    /// Return vertex pixel parameter name by index
-    const String& GetPSParameterName(PSParameter parameter);
+    /// Return shader parameter name by index
+    const String& GetShaderParameterName(ShaderParameter parameter);
     /// Return texture unit name by index
     const String& GetTextureUnitName(TextureUnit unit);
     /// Return vertex shader constant register by parameter index
-    unsigned GetVSRegister(VSParameter param) { return vsRegisters_[param]; }
+    unsigned GetVSRegister(ShaderParameter param) { return shaderRegisters_[param]; }
     /// Return pixel shader constant register by parameter index
-    unsigned GetPSRegister(PSParameter param) { return psRegisters_[param]; }
-    /// Return last vertex shader parameter source
-    const void* GetVSParameterSource(VSParameter param) { return lastVSParameterSources_[param]; }
-    /// Return last pixel shader parameter source
-    const void* GetPSParameterSource(PSParameter param) { return lastPSParameterSources_[param]; }
+    unsigned GetPSRegister(ShaderParameter param) { return shaderRegisters_[param]; }
+    /// Return last shader parameter source
+    const void* GetShaderParameterSource(ShaderParameter param) { return lastShaderParameterSources_[param]; }
     /// Return texture by texture unit index
     Texture* GetTexture(unsigned index) const;
     /// Return the "view texture"
@@ -485,21 +474,15 @@ private:
     /// Vertex declaration in use
     VertexDeclaration* vertexDeclaration_;
     /// Vertex shader in use
-    VertexShader* vertexShader_;
+    ShaderProgram* vertexShader_;
     /// Pixel shader in use
-    PixelShader* pixelShader_;
-    /// Vertex shader parameter mappings
-    Map<String, VSParameter> vsParameters_;
-    /// Pixel shader parameter mappings
-    Map<String, PSParameter> psParameters_;
-    /// Vertex shader constant register mappings
-    unsigned vsRegisters_[MAX_VS_PARAMETERS];
-    /// Pixel shader constant register mappings
-    unsigned psRegisters_[MAX_PS_PARAMETERS];
-    /// Last vertex shader parameter sources per parameter
-    const void* lastVSParameterSources_[MAX_VS_PARAMETERS];
-    /// Last pixel shader parameter sources per parameter
-    const void* lastPSParameterSources_[MAX_PS_PARAMETERS];
+    ShaderProgram* pixelShader_;
+    /// Shader parameter mappings
+    Map<String, ShaderParameter> shaderParameters_;
+    /// Shader constant register mappings
+    unsigned shaderRegisters_[MAX_SHADER_PARAMETERS];
+    /// Last shader parameter sources per parameter
+    const void* lastShaderParameterSources_[MAX_SHADER_PARAMETERS];
     /// Textures in use
     Texture* texture_[MAX_TEXTURE_UNITS];
     /// "View texture" to prevent sampling the destination render target

+ 11 - 10
Engine/Graphics/GraphicsDefs.h

@@ -193,8 +193,15 @@ enum CubeMapFace
     MAX_CUBEMAP_FACES
 };
 
-/// Vertex shader parameters
-enum VSParameter
+/// Shader types
+enum ShaderType
+{
+    VS = 0,
+    PS,
+};
+
+/// Shader parameters
+enum ShaderParameter
 {
     VSP_CAMERAPOS,
     VSP_CAMERAROT,
@@ -211,13 +218,7 @@ enum VSParameter
     VSP_VIEWRIGHTVECTOR,
     VSP_VIEWUPVECTOR,
     VSP_SKINMATRICES,
-    MAX_VS_PARAMETERS
-};
-
-/// Pixel shader parameters
-enum PSParameter
-{
-    PSP_AMBIENTCOLOR = 0,
+    PSP_AMBIENTCOLOR,
     PSP_ANTIALIASWEIGHTS,
     PSP_CAMERAPOS,
     PSP_ELAPSEDTIME,
@@ -239,7 +240,7 @@ enum PSParameter
     PSP_SHADOWPROJ,
     PSP_SPOTPROJ,
     PSP_VIEWPROJ,
-    MAX_PS_PARAMETERS
+    MAX_SHADER_PARAMETERS
 };
 
 /// Texture units

+ 15 - 18
Engine/Graphics/Material.cpp

@@ -174,17 +174,14 @@ bool Material::Load(Deserializer& source)
     {
         String name = parameterElem.GetString("name");
         Vector4 value = parameterElem.GetVector("value");
-        VSParameter vsParam = graphics->GetVSParameter(name);
-        if (vsParam != MAX_VS_PARAMETERS)
-            SetVertexShaderParameter(vsParam, value);
+        ShaderParameter param = graphics->GetShaderParameter(name);
+        // Check whether a VS or PS parameter
+        if (param < PSP_AMBIENTCOLOR)
+            SetVertexShaderParameter(param, value);
+        else if (param != MAX_SHADER_PARAMETERS)
+            SetPixelShaderParameter(param, value);
         else
-        {
-            PSParameter psParam = graphics->GetPSParameter(name);
-            if (psParam != MAX_PS_PARAMETERS)
-                SetPixelShaderParameter(psParam, value);
-            else
-                LOGERROR("Unknown shader parameter " + name);
-        }
+            LOGERROR("Unknown shader parameter " + name);
         
         parameterElem = parameterElem.GetNextElement("parameter");
     }
@@ -202,8 +199,8 @@ bool Material::Load(Deserializer& source)
     memoryUse += sizeof(Material);
     memoryUse += techniques_.Size() * sizeof(TechniqueEntry);
     memoryUse += textures_.Size() * sizeof(SharedPtr<Texture>);
-    memoryUse += vsParameters_.Size() * (sizeof(VSParameter) + sizeof(Vector4));
-    memoryUse += psParameters_.Size() * (sizeof(PSParameter) + sizeof(Vector4));
+    memoryUse += vsParameters_.Size() * (sizeof(ShaderParameter) + sizeof(Vector4));
+    memoryUse += psParameters_.Size() * (sizeof(ShaderParameter) + sizeof(Vector4));
     
     SetMemoryUse(memoryUse);
     Update();
@@ -245,16 +242,16 @@ bool Material::Save(Serializer& dest)
     }
     
     // Write shader parameters
-    for (Map<VSParameter, Vector4>::ConstIterator j = vsParameters_.Begin(); j != vsParameters_.End(); ++j)
+    for (Map<ShaderParameter, Vector4>::ConstIterator j = vsParameters_.Begin(); j != vsParameters_.End(); ++j)
     {
         XMLElement parameterElem = materialElem.CreateChildElement("parameter");
-        parameterElem.SetString("name", graphics->GetVSParameterName(j->first_));
+        parameterElem.SetString("name", graphics->GetShaderParameterName(j->first_));
         parameterElem.SetVector4("value", j->second_);
     }
-    for (Map<PSParameter, Vector4>::ConstIterator j = psParameters_.Begin(); j != psParameters_.End(); ++j)
+    for (Map<ShaderParameter, Vector4>::ConstIterator j = psParameters_.Begin(); j != psParameters_.End(); ++j)
     {
         XMLElement parameterElem = materialElem.CreateChildElement("parameter");
-        parameterElem.SetString("name", graphics->GetPSParameterName(j->first_));
+        parameterElem.SetString("name", graphics->GetShaderParameterName(j->first_));
         parameterElem.SetVector4("value", j->second_);
     }
     
@@ -278,12 +275,12 @@ void Material::SetTechnique(unsigned index, Technique* technique, unsigned quali
     Update();
 }
 
-void Material::SetVertexShaderParameter(VSParameter parameter, const Vector4& value)
+void Material::SetVertexShaderParameter(ShaderParameter parameter, const Vector4& value)
 {
     vsParameters_[parameter] = value;
 }
 
-void Material::SetPixelShaderParameter(PSParameter parameter, const Vector4& value)
+void Material::SetPixelShaderParameter(ShaderParameter parameter, const Vector4& value)
 {
     psParameters_[parameter] = value;
 }

+ 6 - 8
Engine/Graphics/Material.h

@@ -74,9 +74,9 @@ public:
     /// Set technique
     void SetTechnique(unsigned index, Technique* technique, unsigned qualityLevel = 0, float lodDistance = 0.0f);
     /// Set vertex shader parameter
-    void SetVertexShaderParameter(VSParameter parameter, const Vector4& value);
+    void SetVertexShaderParameter(ShaderParameter parameter, const Vector4& value);
     /// Set pixel shader parameter
-    void SetPixelShaderParameter(PSParameter parameter, const Vector4& value);
+    void SetPixelShaderParameter(ShaderParameter parameter, const Vector4& value);
     /// Set texture
     void SetTexture(TextureUnit unit, Texture* texture);
     /// Set texture coordinate transform
@@ -87,8 +87,6 @@ public:
     void SetCullMode(CullMode mode);
     /// Set culling mode for shadows
     void SetShadowCullMode(CullMode mode);
-    /// Mark needing shadow casting and occlusion re-evaluation
-    void SetDirty();
     /// Reset all shader pointers
     void ReleaseShaders();
     /// Clone material
@@ -111,9 +109,9 @@ public:
     /// Return texture by unit
     Texture* GetTexture(TextureUnit unit) const;
     /// Return all vertex shader parameters
-    const Map<VSParameter, Vector4>& GetVertexShaderParameters() const { return vsParameters_; }
+    const Map<ShaderParameter, Vector4>& GetVertexShaderParameters() const { return vsParameters_; }
     /// Return all pixel shader parameters
-    const Map<PSParameter, Vector4>& GetPixelShaderParameters() const { return psParameters_; }
+    const Map<ShaderParameter, Vector4>& GetPixelShaderParameters() const { return psParameters_; }
     /// Return normal culling mode
     CullMode GetCullMode() const { return cullMode_; }
     /// Return culling mode for shadows
@@ -135,9 +133,9 @@ private:
     /// Textures
     Vector<SharedPtr<Texture> > textures_;
     /// Vertex shader parameters
-    Map<VSParameter, Vector4> vsParameters_;
+    Map<ShaderParameter, Vector4> vsParameters_;
     /// Pixel shader parameters
-    Map<PSParameter, Vector4> psParameters_;
+    Map<ShaderParameter, Vector4> psParameters_;
     /// Normal culling mode
     CullMode cullMode_;
     /// Culling mode for shadow rendering

+ 0 - 201
Engine/Graphics/PixelShader.cpp

@@ -1,201 +0,0 @@
-//
-// Urho3D Engine
-// Copyright (c) 2008-2011 Lasse Öörni
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-//
-
-#include "Precompiled.h"
-#include "Context.h"
-#include "FileSystem.h"
-#include "Graphics.h"
-#include "GraphicsImpl.h"
-#include "Log.h"
-#include "PixelShader.h"
-#include "Profiler.h"
-#include "ResourceCache.h"
-#include "SharedArrayPtr.h"
-#include "XMLFile.h"
-
-#include <ctype.h>
-
-#include "DebugNew.h"
-
-OBJECTTYPESTATIC(PixelShader);
-
-PixelShader::PixelShader(Context* context) :
-    Resource(context),
-    GPUObject(GetSubsystem<Graphics>()),
-    isSM3_(false)
-{
-    ClearParameters();
-}
-
-PixelShader::~PixelShader()
-{
-    Release();
-}
-
-void PixelShader::RegisterObject(Context* context)
-{
-    context->RegisterFactory<PixelShader>();
-}
-
-bool PixelShader::Load(Deserializer& source)
-{
-    PROFILE(LoadPixelShader);
-    
-    Release();
-    
-    if (!graphics_)
-        return false;
-    
-    unsigned dataSize = source.GetSize();
-    SharedArrayPtr<unsigned char> buffer(new unsigned char[dataSize]);
-    source.Read((void*)buffer.GetPtr(), dataSize);
-    
-    IDirect3DDevice9* device = graphics_->GetImpl()->GetDevice();
-    if ((!device) || (FAILED(device->CreatePixelShader(
-        (const DWORD*)buffer.GetPtr(),
-        (IDirect3DPixelShader9**)&object_))))
-    {
-        LOGERROR("Could not create pixel shader " + GetName());
-        return false;
-    }
-    
-    SetMemoryUse(dataSize);
-    LoadParameters();
-    return true;
-}
-
-bool PixelShader::NeedParameterUpdate(PSParameter parameter, const void* source)
-{
-    if ((useParameter_[parameter]) && (graphics_->GetPSParameterSource(parameter) != source))
-    {
-        graphics_->SetPSParameterSource(parameter, source);
-        return true;
-    }
-    return false;
-}
-
-void PixelShader::Release()
-{
-    if (object_)
-    {
-        if (!graphics_)
-            return;
-        
-        if (graphics_->GetPixelShader() == this)
-            graphics_->SetShaders(0, 0);
-        
-        ((IDirect3DPixelShader9*)object_)->Release();
-        object_ = 0;
-        
-        SetMemoryUse(0);
-    }
-}
-
-void PixelShader::LoadParameters()
-{
-    ResourceCache* cache = GetSubsystem<ResourceCache>();
-    
-    ClearParameters();
-    
-    String shaderPath, shaderName, shaderExt;
-    SplitPath(GetName(), shaderPath, shaderName, shaderExt);
-    
-    isSM3_ = (shaderExt.Find('3') != String::NPOS);
-    
-    // Take the first part of the shader name (shader group)
-    unsigned index = 2;
-    while ((index < shaderName.Length()) && (shaderName[index] != '_'))
-        ++index;
-    String shaderGroup = shaderName.Substring(0, index);
-    
-    // Load shader information XML file
-    XMLFile* file = cache->GetResource<XMLFile>(shaderPath + shaderGroup + ".xml");
-    if (!file)
-        return;
-    
-    // Update (global) parameter register mappings
-    XMLElement shadersElem = file->GetRootElement();
-    XMLElement paramsElem = shadersElem.GetChildElement("psparameters");
-    XMLElement paramElem = paramsElem.GetChildElement("parameter");
-    
-    while (paramElem)
-    {
-        String name = paramElem.GetString("name");
-        PSParameter param = graphics_->GetPSParameter(name);
-        if (param != MAX_PS_PARAMETERS)
-            graphics_->SetPSRegister(param, paramElem.GetInt("index"));
-        else
-            LOGERROR("Unknown pixel shader parameter " + name + " in " + GetName());
-        
-        paramElem = paramElem.GetNextElement("parameter");
-    }
-    
-    // Get parameters and texture units used by this shader
-    XMLElement shaderElem = shadersElem.GetChildElement("shader");
-    while (shaderElem)
-    {
-        String name = shaderElem.GetString("name");
-        String type = shaderElem.GetStringLower("type");
-        
-        if ((name == shaderName) && (type == "ps"))
-        {
-            XMLElement shaderParamElem = shaderElem.GetChildElement("parameter");
-            while (shaderParamElem)
-            {
-                String name = shaderParamElem.GetString("name");
-                PSParameter param = graphics_->GetPSParameter(name);
-                if (param != MAX_PS_PARAMETERS)
-                    useParameter_[param] = true;
-                
-                shaderParamElem = shaderParamElem.GetNextElement("parameter");
-            }
-            
-            XMLElement textureElem = shaderElem.GetChildElement("textureunit");
-            while (textureElem)
-            {
-                String name = textureElem.GetString("name");
-                TextureUnit unit = graphics_->GetTextureUnit(name);
-                if (unit != MAX_TEXTURE_UNITS)
-                    useTextureUnit_[unit] = true;
-                else
-                    LOGERROR("Unknown texture unit " + name + " in " + GetName());
-                
-                textureElem = textureElem.GetNextElement("textureunit");
-            }
-            
-            return;
-        }
-        
-        shaderElem = shaderElem.GetNextElement("shader");
-    }
-    
-    LOGERROR("Shader " + shaderName + " not found in shader description XML file");
-}
-
-void PixelShader::ClearParameters()
-{
-    for (unsigned i = 0; i < MAX_PS_PARAMETERS; ++i)
-        useParameter_[i] = false;
-    for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
-        useTextureUnit_[i] = false;
-}

+ 0 - 72
Engine/Graphics/PixelShader.h

@@ -1,72 +0,0 @@
-//
-// Urho3D Engine
-// Copyright (c) 2008-2011 Lasse Öörni
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-//
-
-#pragma once
-
-#include "GPUObject.h"
-#include "GraphicsDefs.h"
-#include "Resource.h"
-
-class Deserializer;
-
-/// Pixel shader resource
-class PixelShader : public Resource, public GPUObject
-{
-    OBJECT(PixelShader);
-    
-public:
-    /// Construct
-    PixelShader(Context* context);
-    /// Destruct
-    virtual ~PixelShader();
-    /// Register object factory
-    static void RegisterObject(Context* context);
-    
-    /// Load resource. Return true if successful
-    virtual bool Load(Deserializer& source);
-    /// Release shader
-    virtual void Release();
-    
-    /// Return whether uses a specific shader parameter
-    bool HasParameter(PSParameter parameter) const { return useParameter_[parameter]; }
-    /// Return whether uses a texture unit
-    bool HasTextureUnit(TextureUnit unit) const { return useTextureUnit_[unit]; }
-    /// Return whether is Shader Model 3 format
-    bool IsSM3() const { return isSM3_; }
-    
-    /// Check whether a shader parameter needs update
-    bool NeedParameterUpdate(PSParameter parameter, const void* source);
-    
-private:
-    /// Load parameters from an XML file
-    void LoadParameters();
-    /// Clear parameter and texture unit use flags
-    void ClearParameters();
-    
-    /// Parameter use flags
-    bool useParameter_[MAX_PS_PARAMETERS];
-    /// Texture unit use flags
-    bool useTextureUnit_[MAX_TEXTURE_UNITS];
-    /// Shader Model 3 flag
-    bool isSM3_;
-};

+ 41 - 34
Engine/Graphics/Renderer.cpp

@@ -36,16 +36,16 @@
 #include "OcclusionBuffer.h"
 #include "Octree.h"
 #include "OctreeQuery.h"
-#include "PixelShader.h"
 #include "Profiler.h"
 #include "Renderer.h"
 #include "ResourceCache.h"
 #include "Scene.h"
+#include "Shader.h"
+#include "ShaderProgram.h"
 #include "Technique.h"
 #include "Texture2D.h"
 #include "TextureCube.h"
 #include "VertexBuffer.h"
-#include "VertexShader.h"
 #include "View.h"
 #include "XMLFile.h"
 #include "Zone.h"
@@ -439,30 +439,14 @@ const Viewport& Renderer::GetViewport(unsigned index) const
     return index < viewports_.Size() ? viewports_[index] : noViewport;
 }
 
-VertexShader* Renderer::GetVertexShader(const String& name, bool checkExists) const
+ShaderProgram* Renderer::GetVertexShader(const String& name, bool checkExists) const
 {
-    // Check for extra underscore with no variations and remove
-    String fullName = (shaderPath_ + name + vsFormat_);
-    fullName.Replace("_.", ".");
-    if (checkExists)
-    {
-        if (!cache_->Exists(fullName))
-            return 0;
-    }
-    return cache_->GetResource<VertexShader>(fullName);
+    return GetShader(name, vsFormat_, checkExists);
 }
 
-PixelShader* Renderer::GetPixelShader(const String& name, bool checkExists) const
+ShaderProgram* Renderer::GetPixelShader(const String& name, bool checkExists) const
 {
-    // Check for extra underscore with no variations and remove
-    String fullName = (shaderPath_ + name + psFormat_);
-    fullName.Replace("_.", ".");
-    if (checkExists)
-    {
-        if (!cache_->Exists(fullName))
-            return 0;
-    }
-    return cache_->GetResource<PixelShader>(fullName);
+    return GetShader(name, psFormat_, checkExists);
 }
 
 unsigned Renderer::GetNumGeometries(bool allViews) const
@@ -843,13 +827,40 @@ void Renderer::ResetShadowMapUseCount()
         shadowMapUseCount_[i] = 0;
 }
 
-void Renderer::setBatchShaders(Batch& batch, Technique* technique, Pass* pass, bool allowShadows)
+ShaderProgram* Renderer::GetShader(const String& name, const String& extension, bool checkExists) const
+{
+    String shaderName = shaderPath_;
+    String variationName;
+    
+    unsigned split = name.Find('_');
+    if (split != String::NPOS)
+    {
+        shaderName += name.Substring(0, split) + extension;
+        variationName = name.Substring(split + 1);
+    }
+    else
+        shaderName += name + extension;
+    
+    if (checkExists)
+    {
+        if (!cache_->Exists(shaderName))
+            return 0;
+    }
+    
+    Shader* shader = cache_->GetResource<Shader>(shaderName);
+    if (shader)
+        return shader->GetVariation(variationName);
+    else
+        return 0;
+}
+
+void Renderer::SetBatchShaders(Batch& batch, Technique* technique, Pass* pass, bool allowShadows)
 {
     batch.pass_ = pass;
     
     // Check if shaders are unloaded or need reloading
-    Vector<SharedPtr<VertexShader> >& vertexShaders = pass->GetVertexShaders();
-    Vector<SharedPtr<PixelShader> >& pixelShaders = pass->GetPixelShaders();
+    Vector<SharedPtr<ShaderProgram> >& vertexShaders = pass->GetVertexShaders();
+    Vector<SharedPtr<ShaderProgram> >& pixelShaders = pass->GetPixelShaders();
     if ((!vertexShaders.Size()) || (!pixelShaders.Size()) || (technique->GetShadersLoadedFrameNumber() !=
         shadersChangedFrameNumber_))
     {
@@ -1014,8 +1025,7 @@ void Renderer::LoadShaders()
     }
     
     // Remove shaders that are no longer referenced from the cache
-    cache_->ReleaseResources(VertexShader::GetTypeStatic());
-    cache_->ReleaseResources(PixelShader::GetTypeStatic());
+    cache_->ReleaseResources(Shader::GetTypeStatic());
     
     shadersDirty_ = false;
 }
@@ -1076,8 +1086,8 @@ void Renderer::LoadPassShaders(Technique* technique, PassType pass, bool allowSh
     
     unsigned hwShadows = graphics_->GetHardwareShadowSupport() ? 1 : 0;
     
-    Vector<SharedPtr<VertexShader> >& vertexShaders = i->second_.GetVertexShaders();
-    Vector<SharedPtr<PixelShader> >& pixelShaders = i->second_.GetPixelShaders();
+    Vector<SharedPtr<ShaderProgram> >& vertexShaders = i->second_.GetVertexShaders();
+    Vector<SharedPtr<ShaderProgram> >& pixelShaders = i->second_.GetPixelShaders();
     
     // Forget all the old shaders
     vertexShaders.Clear();
@@ -1138,10 +1148,7 @@ void Renderer::ReleaseMaterialShaders()
     cache_->GetResources<Material>(materials);
     
     for (unsigned i = 0; i < materials.Size(); ++i)
-    {
-        for (unsigned j = 0; j < materials[i]->GetNumTechniques(); ++j)
-            materials[i]->ReleaseShaders();
-    }
+        materials[i]->ReleaseShaders();
 }
 
 void Renderer::ReloadTextures()
@@ -1439,7 +1446,7 @@ void Renderer::SetupLightBatch(Batch& batch)
     }
 }
 
-void Renderer::DrawFullScreenQuad(Camera& camera, VertexShader* vs, PixelShader* ps, bool nearQuad)
+void Renderer::DrawFullScreenQuad(Camera& camera, ShaderProgram* vs, ShaderProgram* ps, bool nearQuad)
 {
     graphics_->ClearTransformSources();
     

+ 10 - 8
Engine/Graphics/Renderer.h

@@ -238,9 +238,9 @@ public:
     /// Return the default spotlight attenuation texture
     Texture2D* GetDefaultLightSpot() const { return defaultLightSpot; }
     /// Return a vertex shader by name
-    VertexShader* GetVertexShader(const String& name, bool checkExists = false) const;
+    ShaderProgram* GetVertexShader(const String& name, bool checkExists = false) const;
     /// Return a pixel shader by name
-    PixelShader* GetPixelShader(const String& name, bool checkExists = false) const;
+    ShaderProgram* GetPixelShader(const String& name, bool checkExists = false) const;
     /// Return the frame update parameters
     const FrameInfo& GetFrameInfo() { return frame_; }
     
@@ -266,8 +266,10 @@ private:
     Texture2D* GetShadowMap(float resolution);
     /// Reset shadow map use count
     void ResetShadowMapUseCount();
+    /// Get a shader program
+    ShaderProgram* GetShader(const String& name, const String& extension, bool checkExists) const;
     /// Choose shaders for a batch
-    void setBatchShaders(Batch& batch, Technique* technique, Pass* pass, bool allowShadows = true);
+    void SetBatchShaders(Batch& batch, Technique* technique, Pass* pass, bool allowShadows = true);
     /// Choose light volume shaders for a batch
     void SetLightVolumeShaders(Batch& batch);
     /// Reload shaders
@@ -299,7 +301,7 @@ private:
     /// Set up a light volume rendering batch
     void SetupLightBatch(Batch& batch);
     /// Draw a full screen quad (either near or far)
-    void DrawFullScreenQuad(Camera& camera, VertexShader* vs, PixelShader* ps, bool nearQuad);
+    void DrawFullScreenQuad(Camera& camera, ShaderProgram* vs, ShaderProgram* ps, bool nearQuad);
     /// Handle screen mode event
     void HandleScreenMode(StringHash eventType, VariantMap& eventData);
     /// Handle render update event
@@ -332,13 +334,13 @@ private:
     /// Shadow map use count if reusing is disabled. Is reset for each view
     unsigned shadowMapUseCount_[NUM_SHADOWMAP_RESOLUTIONS];
     /// Stencil rendering vertex shader
-    SharedPtr<VertexShader> stencilVS_;
+    SharedPtr<ShaderProgram> stencilVS_;
     /// Stencil rendering pixel shader
-    SharedPtr<PixelShader> stencilPS_;
+    SharedPtr<ShaderProgram> stencilPS_;
     /// Light vertex shaders
-    Vector<SharedPtr<VertexShader> > lightVS_;
+    Vector<SharedPtr<ShaderProgram> > lightVS_;
     /// Light pixel shaders
-    Vector<SharedPtr<PixelShader> > lightPS_;
+    Vector<SharedPtr<ShaderProgram> > lightPS_;
     /// Reusable shadow cameras
     Vector<SharedPtr<Camera> > shadowCameraStore_;
     /// Reusable split lights

+ 185 - 0
Engine/Graphics/Shader.cpp

@@ -0,0 +1,185 @@
+//
+// Urho3D Engine
+// Copyright (c) 2008-2011 Lasse Öörni
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#include "Precompiled.h"
+#include "Context.h"
+#include "Deserializer.h"
+#include "Graphics.h"
+#include "GraphicsImpl.h"
+#include "Log.h"
+#include "Profiler.h"
+#include "Shader.h"
+#include "ShaderProgram.h"
+
+/// Shader parameter structure for loading
+struct Parameter
+{
+    /// Parameter name
+    String name_;
+    /// Constant register or sampler
+    unsigned register_;
+};
+
+OBJECTTYPESTATIC(Shader);
+
+Shader::Shader(Context* context) :
+    Resource(context),
+    shaderType_(VS),
+    isSM3_(false)
+{
+}
+
+Shader::~Shader()
+{
+}
+
+void Shader::RegisterObject(Context* context)
+{
+    context->RegisterFactory<Shader>();
+}
+
+bool Shader::Load(Deserializer& source)
+{
+    PROFILE(LoadShader);
+    
+    variations_.Clear();
+    
+    Graphics* graphics = GetSubsystem<Graphics>();
+    if (!graphics)
+        return false;
+    
+    // Check ID
+    if (source.ReadID() != "USHD")
+    {
+        LOGERROR(source.GetName() + " is not a valid shader file");
+        return false;
+    }
+    
+    shaderType_ = (ShaderType)source.ReadShort();
+    isSM3_ = (source.ReadShort() == 3);
+    
+    Vector<Parameter> parameters;
+    Vector<Parameter> textureUnits;
+    
+    // Read the parameters and texture units used by this shader; use information is specified in terms of them
+    unsigned numParameters = source.ReadUInt();
+    for (unsigned i = 0; i < numParameters; ++i)
+    {
+        Parameter newParameter;
+        newParameter.name_ = source.ReadString();
+        newParameter.register_ = source.ReadUByte();
+        parameters.Push(newParameter);
+        
+        ShaderParameter paramIndex = graphics->GetShaderParameter(newParameter.name_);
+        if (paramIndex != MAX_SHADER_PARAMETERS)
+            graphics->SetShaderRegister(paramIndex, newParameter.register_);
+        else
+            LOGWARNING("Unknown shader parameter " + newParameter.name_);
+    }
+    
+    unsigned numTextureUnits = source.ReadUInt();
+    for (unsigned i = 0; i < numTextureUnits; ++i)
+    {
+        Parameter newTextureUnit;
+        newTextureUnit.name_ = source.ReadString();
+        newTextureUnit.register_ = source.ReadUByte();
+        textureUnits.Push(newTextureUnit);
+        
+        TextureUnit tuIndex = graphics->GetTextureUnit(newTextureUnit.name_);
+        if (tuIndex == MAX_TEXTURE_UNITS)
+            LOGWARNING("Unknown texture unit " + newTextureUnit.name_);
+    }
+    
+    // Read the variations
+    unsigned numVariations = source.ReadUInt();
+    for (unsigned i = 0; i < numVariations; ++i)
+    {
+        SharedPtr<ShaderProgram> variation(new ShaderProgram(this, shaderType_, isSM3_));
+        variation->SetName(source.ReadString());
+        
+        // Fill the parameter & texture unit use information
+        for (unsigned j = 0; j < numParameters; ++j)
+        {
+            if (source.ReadBool())
+            {
+                ShaderParameter paramIndex = graphics->GetShaderParameter(parameters[j].name_);
+                if (paramIndex != MAX_SHADER_PARAMETERS)
+                    variation->SetUseParameter(paramIndex, true);
+            }
+        }
+        
+        for (unsigned j = 0; j < numTextureUnits; ++j)
+        {
+            if (source.ReadBool())
+            {
+                TextureUnit tuIndex = graphics->GetTextureUnit(textureUnits[j].name_);
+                if (tuIndex != MAX_TEXTURE_UNITS)
+                    variation->SetUseTextureUnit(tuIndex, true);
+            }
+        }
+        
+        // Read the bytecode
+        unsigned dataSize = source.ReadUInt();
+        if (dataSize)
+        {
+            SharedArrayPtr<unsigned char> byteCode(new unsigned char[dataSize]);
+            source.Read(byteCode.GetPtr(), dataSize);
+            variation->SetByteCode(byteCode);
+        }
+        
+        // Store the variation
+        variations_[StringHash(variation->GetName())] = variation;
+    }
+    
+    // This is not exactly accurate, but a reasonable estimate
+    SetMemoryUse(source.GetSize());
+    return true;
+}
+
+ShaderProgram* Shader::GetVariation(const String& name)
+{
+    return GetVariation(StringHash(name));
+}
+
+ShaderProgram* Shader::GetVariation(StringHash nameHash)
+{
+    Map<StringHash, SharedPtr<ShaderProgram> >::Iterator i = variations_.Find(nameHash);
+    if (i == variations_.End())
+        return 0;
+    ShaderProgram* variation = i->second_;
+    
+    // Create shader object now if not yet created. If fails, remove the variation
+    if (!variation->GetGPUObject())
+    {
+        PROFILE(CreateShaderProgram);
+        bool success = variation->Create();
+        if (!success)
+        {
+            LOGERROR("Failed to create variation " + variation->GetName() + " of shader " + GetName());
+            variations_.Erase(i);
+            return 0;
+        }
+    }
+    
+    return variation;
+}

+ 22 - 24
Engine/Graphics/VertexShader.h → Engine/Graphics/Shader.h

@@ -23,47 +23,45 @@
 
 #pragma once
 
-#include "GPUObject.h"
 #include "Resource.h"
 
-class Deserializer;
+class ShaderProgram;
 
-/// Vertex shader resource
-class VertexShader : public Resource, public GPUObject
+/// Shader resource consisting of several shader variations
+class Shader : public Resource
 {
-    OBJECT(VertexShader);
-    
-    friend unsigned GetVSRegister(VSParameter param);
+    OBJECT(Shader);
     
 public:
     /// Construct
-    VertexShader(Context* context);
+    Shader(Context* context);
     /// Destruct
-    virtual ~VertexShader();
+    virtual ~Shader();
     /// Register object factory
     static void RegisterObject(Context* context);
     
     /// Load resource. Return true if successful
     virtual bool Load(Deserializer& source);
-    /// Release shader
-    virtual void Release();
     
-    /// Return whether uses a specific shader parameter
-    bool HasParameter(VSParameter parameter) const { return useParameter_[parameter]; }
-    /// Return whether is Shader Model 3 format
-    bool IsSM3() const { return isSM3_; }
+    /// Get a named variation. Return null if not found or could not be created
+    ShaderProgram* GetVariation(const String& name);
+    /// Get a named variation. Return null if not found or could not be created
+    ShaderProgram* GetVariation(StringHash nameHash);
+    /// Release (unload) all variations
+    void ReleaseAll();
     
-    /// Check whether a shader parameter needs update
-    bool NeedParameterUpdate(VSParameter parameter, const void* source);
+    /// Return shader type
+    ShaderType GetShaderType() const { return shaderType_; }
+    /// Return whether requires Shader Model 3
+    bool IsSM3() const { return isSM3_; }
+    /// Return number of variations
+    unsigned GetNumVariations() const { return variations_.Size(); }
     
 private:
-    /// Load parameters from an XML file
-    void LoadParameters();
-    /// Clear parameter use flags
-    void ClearParameters();
-    
-    /// Parameter use flags
-    bool useParameter_[MAX_VS_PARAMETERS];
+    /// Shader type
+    ShaderType shaderType_;
     /// Shader Model 3 flag
     bool isSM3_;
+    /// Shader variations. Will be in an unloaded state until requested
+    Map<StringHash, SharedPtr<ShaderProgram> > variations_;
 };

+ 147 - 0
Engine/Graphics/ShaderProgram.cpp

@@ -0,0 +1,147 @@
+//
+// Urho3D Engine
+// Copyright (c) 2008-2011 Lasse Öörni
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#include "Precompiled.h"
+#include "Graphics.h"
+#include "GraphicsImpl.h"
+#include "Shader.h"
+#include "ShaderProgram.h"
+
+#include <ctype.h>
+
+#include "DebugNew.h"
+
+OBJECTTYPESTATIC(ShaderProgram);
+
+ShaderProgram::ShaderProgram(Shader* shader, ShaderType type, bool isSM3) :
+    GPUObject(shader->GetSubsystem<Graphics>()),
+    shader_(shader),
+    shaderType_(type),
+    isSM3_(isSM3)
+{
+    ClearParameters();
+}
+
+ShaderProgram::~ShaderProgram()
+{
+    Release();
+}
+
+bool ShaderProgram::Create()
+{
+    Release();
+    
+    if ((!graphics_) || (!byteCode_))
+        return false;
+    
+    IDirect3DDevice9* device = graphics_->GetImpl()->GetDevice();
+    if (shaderType_ == VS)
+    {
+        if ((!device) || (FAILED(device->CreateVertexShader(
+            (const DWORD*)byteCode_.GetPtr(),
+            (IDirect3DVertexShader9**)&object_))))
+            return false;
+    }
+    else
+    {
+        if ((!device) || (FAILED(device->CreatePixelShader(
+            (const DWORD*)byteCode_.GetPtr(),
+            (IDirect3DPixelShader9**)&object_))))
+            return false;
+    }
+    
+    return true;
+}
+
+void ShaderProgram::Release()
+{
+    if (object_)
+    {
+        if (!graphics_)
+            return;
+        
+        if (shaderType_ == VS)
+        {
+            if (graphics_->GetPixelShader() == this)
+                graphics_->SetShaders(0, 0);
+            
+            ((IDirect3DVertexShader9*)object_)->Release();
+        }
+        else
+        {
+            if (graphics_->GetVertexShader() == this)
+                graphics_->SetShaders(0, 0);
+            
+            ((IDirect3DPixelShader9*)object_)->Release();
+        }
+        
+        object_ = 0;
+    }
+}
+
+void ShaderProgram::SetName(const String& name)
+{
+    name_ = name;
+}
+
+void ShaderProgram::SetByteCode(const SharedArrayPtr<unsigned char>& byteCode)
+{
+    byteCode_ = byteCode;
+    
+    // Recreate object if already created from previous bytecode
+    if (object_)
+        Create();
+}
+
+void ShaderProgram::SetUseParameter(ShaderParameter param, bool enable)
+{
+    useParameter_[param] = enable;
+}
+
+void ShaderProgram::SetUseTextureUnit(TextureUnit unit, bool enable)
+{
+    useTextureUnit_[unit] = enable;
+}
+
+void ShaderProgram::ClearParameters()
+{
+    for (unsigned i = 0; i < MAX_SHADER_PARAMETERS; ++i)
+        useParameter_[i] = false;
+    for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
+        useTextureUnit_[i] = false;
+}
+
+bool ShaderProgram::NeedParameterUpdate(ShaderParameter parameter, const void* source)
+{
+    if ((useParameter_[parameter]) && (graphics_) && (graphics_->GetShaderParameterSource(parameter) != source))
+    {
+        graphics_->SetShaderParameterSource(parameter, source);
+        return true;
+    }
+    return false;
+}
+
+Shader* ShaderProgram::GetShader() const
+{
+    return shader_;
+}

+ 118 - 0
Engine/Graphics/ShaderProgram.h

@@ -0,0 +1,118 @@
+//
+// Urho3D Engine
+// Copyright (c) 2008-2011 Lasse Öörni
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#pragma once
+
+#include "GPUObject.h"
+#include "GraphicsDefs.h"
+#include "Resource.h"
+//
+// Urho3D Engine
+// Copyright (c) 2008-2011 Lasse Öörni
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#pragma once
+
+#include "GPUObject.h"
+#include "GraphicsDefs.h"
+#include "RefCounted.h"
+#include "SharedArrayPtr.h"
+
+class Shader;
+
+/// Shader program on the GPU
+class ShaderProgram : public RefCounted, public GPUObject
+{
+    OBJECT(ShaderProgram);
+    
+public:
+    /// Construct
+    ShaderProgram(Shader* shader, ShaderType type, bool isSM3);
+    /// Destruct
+    virtual ~ShaderProgram();
+    
+    /// Create the shader program. Return true if successful
+    bool Create();
+    /// Release shader
+    virtual void Release();
+    
+    /// Set name
+    void SetName(const String& name);
+    /// Set bytecode
+    void SetByteCode(const SharedArrayPtr<unsigned char>& byteCode);
+    /// Set to use a parameter
+    void SetUseParameter(ShaderParameter param, bool enable);
+    /// Set to use a texture unit
+    void SetUseTextureUnit(TextureUnit unit, bool enable);
+    /// Clear parameter and texture unit use flags
+    void ClearParameters();
+    
+    /// Return parent shader
+    Shader* GetShader() const;
+    /// Return shader type
+    ShaderType GetShaderType() const { return shaderType_; }
+    /// Return variation name
+    const String& GetName() const { return name_; }
+    /// Return whether requires Shader Model 3
+    bool IsSM3() const { return isSM3_; }
+    /// Return whether uses a specific shader parameter
+    bool HasParameter(ShaderParameter parameter) const { return useParameter_[parameter]; }
+    /// Return whether uses a texture unit (only for pixel shaders)
+    bool HasTextureUnit(TextureUnit unit) const { return useTextureUnit_[unit]; }
+    /// Check whether a shader parameter needs update
+    bool NeedParameterUpdate(ShaderParameter parameter, const void* source);
+    
+private:
+    /// Parent shader
+    WeakPtr<Shader> shader_;
+    /// Shader bytecode
+    SharedArrayPtr<unsigned char> byteCode_;
+    /// Shader type
+    ShaderType shaderType_;
+    /// Variation name
+    String name_;
+    /// Shader Model 3 flag
+    bool isSM3_;
+    /// Parameter use flags
+    bool useParameter_[MAX_SHADER_PARAMETERS];
+    /// Texture unit use flags
+    bool useTextureUnit_[MAX_TEXTURE_UNITS];
+};

+ 1 - 2
Engine/Graphics/Technique.cpp

@@ -25,11 +25,10 @@
 #include "Context.h"
 #include "Log.h"
 #include "Technique.h"
-#include "PixelShader.h"
 #include "Profiler.h"
 #include "ResourceCache.h"
+#include "ShaderProgram.h"
 #include "StringUtils.h"
-#include "VertexShader.h"
 #include "XMLFile.h"
 
 static const String passNames[] =

+ 5 - 6
Engine/Graphics/Technique.h

@@ -26,8 +26,7 @@
 #include "GraphicsDefs.h"
 #include "Resource.h"
 
-class PixelShader;
-class VertexShader;
+class ShaderProgram;
 
 /// Material rendering pass, which defines shaders and render state
 class Pass
@@ -74,9 +73,9 @@ public:
     /// Return pixel shader name
     const String& GetPixelShaderName() const { return pixelShaderName_; }
     /// Return vertex shaders
-    Vector<SharedPtr<VertexShader> >& GetVertexShaders() { return vertexShaders_; }
+    Vector<SharedPtr<ShaderProgram> >& GetVertexShaders() { return vertexShaders_; }
     /// Return pixel shaders
-    Vector<SharedPtr<PixelShader> >& GetPixelShaders() { return pixelShaders_; }
+    Vector<SharedPtr<ShaderProgram> >& GetPixelShaders() { return pixelShaders_; }
     
 private:
     /// Pass type
@@ -96,9 +95,9 @@ private:
     /// Pixel shader name
     String pixelShaderName_;
     /// Vertex shaders
-    Vector<SharedPtr<VertexShader> > vertexShaders_;
+    Vector<SharedPtr<ShaderProgram> > vertexShaders_;
     /// Pixel shaders
-    Vector<SharedPtr<PixelShader> > pixelShaders_;
+    Vector<SharedPtr<ShaderProgram> > pixelShaders_;
 };
 
 /// Material technique. Consists of several passes

+ 0 - 187
Engine/Graphics/VertexShader.cpp

@@ -1,187 +0,0 @@
-//
-// Urho3D Engine
-// Copyright (c) 2008-2011 Lasse Öörni
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-//
-
-#include "Precompiled.h"
-#include "Context.h"
-#include "FileSystem.h"
-#include "Graphics.h"
-#include "GraphicsImpl.h"
-#include "Log.h"
-#include "Profiler.h"
-#include "ResourceCache.h"
-#include "SharedArrayPtr.h"
-#include "VertexShader.h"
-#include "XMLFile.h"
-
-#include <ctype.h>
-
-#include "DebugNew.h"
-
-OBJECTTYPESTATIC(VertexShader);
-
-VertexShader::VertexShader(Context* context) :
-    Resource(context),
-    GPUObject(GetSubsystem<Graphics>()),
-    isSM3_(false)
-{
-    ClearParameters();
-}
-
-VertexShader::~VertexShader()
-{
-    Release();
-}
-
-void VertexShader::RegisterObject(Context* context)
-{
-    context->RegisterFactory<VertexShader>();
-}
-
-bool VertexShader::Load(Deserializer& source)
-{
-    PROFILE(LoadVertexShader);
-    
-    Release();
-    
-    if (!graphics_)
-        return false;
-    
-    unsigned dataSize = source.GetSize();
-    
-    SharedArrayPtr<unsigned char> buffer(new unsigned char[dataSize]);
-    source.Read((void*)buffer.GetPtr(), dataSize);
-    
-    IDirect3DDevice9* device = graphics_->GetImpl()->GetDevice();
-    if ((!device) || (FAILED(graphics_->GetImpl()->GetDevice()->CreateVertexShader(
-        (const DWORD*)buffer.GetPtr(),
-        (IDirect3DVertexShader9**)&object_))))
-    {
-        LOGERROR("Could not create vertex shader " + GetName());
-        return false;
-    }
-    
-    SetMemoryUse(dataSize);
-    LoadParameters();
-    return true;
-}
-
-bool VertexShader::NeedParameterUpdate(VSParameter parameter, const void* source)
-{
-    if ((useParameter_[parameter]) && (graphics_->GetVSParameterSource(parameter) != source))
-    {
-        graphics_->SetVSParameterSource(parameter, source);
-        return true;
-    }
-    return false;
-}
-
-void VertexShader::Release()
-{
-    if (object_)
-    {
-        if (!graphics_)
-            return;
-        
-        if (graphics_->GetVertexShader() == this)
-            graphics_->SetShaders(0, 0);
-        
-        ((IDirect3DVertexShader9*)object_)->Release();
-        object_ = 0;
-        
-        SetMemoryUse(0);
-    }
-}
-
-void VertexShader::LoadParameters()
-{
-    ResourceCache* cache = GetSubsystem<ResourceCache>();
-    
-    ClearParameters();
-    
-    String shaderPath, shaderName, shaderExt;
-    SplitPath(GetName(), shaderPath, shaderName, shaderExt);
-    
-    isSM3_ = (shaderExt.Find('3') != String::NPOS);
-    
-    // Take the first part of the shader name (shader group)
-    unsigned index = 2;
-    while ((index < shaderName.Length()) && (shaderName[index] != '_'))
-        ++index;
-    String shaderGroup = shaderName.Substring(0, index);
-    
-    // Load shader information XML file
-    XMLFile* file = cache->GetResource<XMLFile>(shaderPath + shaderGroup + ".xml");
-    if (!file)
-        return;
-    
-    // Update (global) parameter register mappings
-    XMLElement shadersElem = file->GetRootElement();
-    XMLElement paramsElem = shadersElem.GetChildElement("vsparameters");
-    XMLElement paramElem = paramsElem.GetChildElement("parameter");
-    
-    while (paramElem)
-    {
-        String name = paramElem.GetString("name");
-        VSParameter param = graphics_->GetVSParameter(name);
-        if (param != MAX_VS_PARAMETERS)
-            graphics_->SetVSRegister(param, paramElem.GetInt("index"));
-        else
-            LOGERROR("Unknown vertex shader parameter " + name + " in " + GetName());
-        
-        paramElem = paramElem.GetNextElement("parameter");
-    }
-    
-    // Get parameters used by this shader
-    XMLElement shaderElem = shadersElem.GetChildElement("shader");
-    while (shaderElem)
-    {
-        String name = shaderElem.GetString("name");
-        String type = shaderElem.GetStringLower("type");
-        
-        if ((name == shaderName) && (type == "vs"))
-        {
-            XMLElement shaderParamElem = shaderElem.GetChildElement("parameter");
-            while (shaderParamElem)
-            {
-                String name = shaderParamElem.GetString("name");
-                VSParameter param = graphics_->GetVSParameter(name);
-                if (param != MAX_VS_PARAMETERS)
-                    useParameter_[param] = true;
-                
-                shaderParamElem = shaderParamElem.GetNextElement("parameter");
-            }
-            
-            return;
-        }
-        
-        shaderElem = shaderElem.GetNextElement("shader");
-    }
-    
-    LOGERROR("Shader " + shaderName + " not found in shader description XML file");
-}
-
-void VertexShader::ClearParameters()
-{
-    for (unsigned i = 0; i < MAX_VS_PARAMETERS; ++i)
-        useParameter_[i] = false;
-}

+ 9 - 10
Engine/Graphics/View.cpp

@@ -33,15 +33,14 @@
 #include "Octree.h"
 #include "OctreeQuery.h"
 #include "Renderer.h"
-#include "PixelShader.h"
 #include "Profiler.h"
 #include "Scene.h"
+#include "ShaderProgram.h"
 #include "Technique.h"
 #include "Texture2D.h"
 #include "TextureCube.h"
 #include "Time.h"
 #include "VertexBuffer.h"
-#include "VertexShader.h"
 #include "View.h"
 #include "Zone.h"
 
@@ -450,7 +449,7 @@ void View::GetBatches()
                         shadowBatch.light_ = SplitLight;
                         shadowBatch.hasPriority_ = (!pass->GetAlphaTest()) && (!pass->GetAlphaMask());
                         
-                        renderer_->setBatchShaders(shadowBatch, tech, pass);
+                        renderer_->SetBatchShaders(shadowBatch, tech, pass);
                         lightQueue.shadowBatches_.AddBatch(shadowBatch);
                     }
                 }
@@ -580,7 +579,7 @@ void View::GetBatches()
                     pass = tech->GetPass(gBufferPass);
                     if (pass)
                     {
-                        renderer_->setBatchShaders(baseBatch, tech, pass);
+                        renderer_->SetBatchShaders(baseBatch, tech, pass);
                         baseBatch.hasPriority_ = (!pass->GetAlphaTest()) && (!pass->GetAlphaMask());
                         gBufferQueue_.AddBatch(baseBatch);
                         
@@ -588,7 +587,7 @@ void View::GetBatches()
                         pass = tech->GetPass(additionalPass);
                         if (pass)
                         {
-                            renderer_->setBatchShaders(baseBatch, tech, pass);
+                            renderer_->SetBatchShaders(baseBatch, tech, pass);
                             baseQueue_.AddBatch(baseBatch);
                         }
                         
@@ -600,7 +599,7 @@ void View::GetBatches()
                 pass = tech->GetPass(PASS_BASE);
                 if (pass)
                 {
-                    renderer_->setBatchShaders(baseBatch, tech, pass);
+                    renderer_->SetBatchShaders(baseBatch, tech, pass);
                     if (pass->GetBlendMode() == BLEND_REPLACE)
                     {
                         baseBatch.hasPriority_ = (!pass->GetAlphaTest()) && (!pass->GetAlphaMask());
@@ -620,7 +619,7 @@ void View::GetBatches()
                     if (pass)
                     {
                         baseBatch.hasPriority_ = false;
-                        renderer_->setBatchShaders(baseBatch, tech, pass);
+                        renderer_->SetBatchShaders(baseBatch, tech, pass);
                         extraQueue_.AddBatch(baseBatch);
                     }
                 }
@@ -691,13 +690,13 @@ void View::GetLitBatches(Drawable* drawable, Light* light, Light* SplitLight, Li
             {
                 if (lightQueue)
                 {
-                    renderer_->setBatchShaders(litBatch, tech, pass);
+                    renderer_->SetBatchShaders(litBatch, tech, pass);
                     lightQueue->litBatches_.AddBatch(litBatch);
                 }
             }
             else
             {
-                renderer_->setBatchShaders(litBatch, tech, pass, allowShadows);
+                renderer_->SetBatchShaders(litBatch, tech, pass, allowShadows);
                 baseQueue_.AddBatch(litBatch);
             }
         }
@@ -714,7 +713,7 @@ void View::GetLitBatches(Drawable* drawable, Light* light, Light* SplitLight, Li
                 litTransparencies.Insert(check);
             }
             
-            renderer_->setBatchShaders(litBatch, tech, pass, allowShadows);
+            renderer_->SetBatchShaders(litBatch, tech, pass, allowShadows);
             transparentQueue_.AddBatch(litBatch, true);
         }
     }

+ 15 - 9
Engine/UI/UI.cpp

@@ -37,17 +37,17 @@
 #include "ListView.h"
 #include "Log.h"
 #include "Matrix4x3.h"
-#include "PixelShader.h"
 #include "Profiler.h"
 #include "ResourceCache.h"
 #include "ScrollBar.h"
+#include "Shader.h"
+#include "ShaderProgram.h"
 #include "Slider.h"
 #include "Text.h"
 #include "Texture2D.h"
 #include "Time.h"
 #include "UI.h"
 #include "UIEvents.h"
-#include "VertexShader.h"
 #include "Window.h"
 
 #include "Sort.h"
@@ -255,8 +255,8 @@ void UI::Render()
     graphics_->SetVertexShaderParameter(VSP_VIEWPROJ, projection);
     graphics_->SetPixelShaderParameter(PSP_MATDIFFCOLOR, Color(1.0f, 1.0f, 1.0f, 1.0f));
     
-    PixelShader* ps = 0;
-    VertexShader* vs = 0;
+    ShaderProgram* ps = 0;
+    ShaderProgram* vs = 0;
     
     for (unsigned i = 0; i < batches_.Size(); ++i)
     {
@@ -399,11 +399,17 @@ void UI::Initialize()
     rootElement_ = new UIElement(context_);
     rootElement_->SetSize(graphics->GetWidth(), graphics->GetHeight());
     
-    noTextureVS_ = cache->GetResource<VertexShader>("Shaders/SM2/Basic_VCol.vs2");
-    diffTextureVS_ = cache->GetResource<VertexShader>("Shaders/SM2/Basic_DiffVCol.vs2");
-    noTexturePS_ = cache->GetResource<PixelShader>("Shaders/SM2/Basic_VCol.ps2");
-    diffTexturePS_ = cache->GetResource<PixelShader>("Shaders/SM2/Basic_DiffVCol.ps2");
-    alphaTexturePS_ = cache->GetResource<PixelShader>("Shaders/SM2/Basic_AlphaVCol.ps2");
+    Shader* basicVS = cache->GetResource<Shader>("Shaders/SM2/Basic.vs2");
+    Shader* basicPS = cache->GetResource<Shader>("Shaders/SM2/Basic.ps2");
+    
+    if ((basicVS) && (basicPS))
+    {
+        noTextureVS_ = basicVS->GetVariation("VCol");
+        diffTextureVS_ = basicVS->GetVariation("DiffVCol");
+        noTexturePS_ = basicPS->GetVariation("VCol");
+        diffTexturePS_ = basicPS->GetVariation("DiffVCol");
+        alphaTexturePS_ = basicPS->GetVariation("AlphaVCol");
+    }
     
     LOGINFO("Initialized user interface");
     initialized_ = true;

+ 5 - 5
Engine/UI/UI.h

@@ -114,15 +114,15 @@ private:
     /// Resource cache
     WeakPtr<ResourceCache> cache_;
     /// Vertex shader for no texture
-    SharedPtr<VertexShader> noTextureVS_;
+    SharedPtr<ShaderProgram> noTextureVS_;
     /// Vertex shader for diffuse texture
-    SharedPtr<VertexShader> diffTextureVS_;
+    SharedPtr<ShaderProgram> diffTextureVS_;
     /// Pixel shader for no texture
-    SharedPtr<PixelShader> noTexturePS_;
+    SharedPtr<ShaderProgram> noTexturePS_;
     /// Pixel shader for diffuse texture
-    SharedPtr<PixelShader> diffTexturePS_;
+    SharedPtr<ShaderProgram> diffTexturePS_;
     /// Pixel shader for alpha texture
-    SharedPtr<PixelShader> alphaTexturePS_;
+    SharedPtr<ShaderProgram> alphaTexturePS_;
     /// UI root element
     SharedPtr<UIElement> rootElement_;
     /// Cursor

+ 2 - 3
Engine/UI/UIBatch.cpp

@@ -23,10 +23,9 @@
 
 #include "Precompiled.h"
 #include "Graphics.h"
-#include "PixelShader.h"
+#include "ShaderProgram.h"
 #include "Texture.h"
 #include "UIElement.h"
-#include "VertexShader.h"
 
 #include "DebugNew.h"
 
@@ -166,7 +165,7 @@ bool UIBatch::Merge(const UIBatch& batch)
     return true;
 }
 
-void UIBatch::Draw(Graphics* graphics, VertexShader* vs, PixelShader* ps) const
+void UIBatch::Draw(Graphics* graphics, ShaderProgram* vs, ShaderProgram* ps) const
 {
     if ((!quads_) || (!quadCount_))
         return;

+ 2 - 2
Engine/UI/UIBatch.h

@@ -29,9 +29,9 @@
 
 class PixelShader;
 class Graphics;
+class ShaderProgram;
 class Texture;
 class UIElement;
-class VertexShader;
 
 /// UI rendering quad
 struct UIQuad
@@ -86,7 +86,7 @@ public:
     /// Merge with another batch
     bool Merge(const UIBatch& batch);
     /// Draw
-    void Draw(Graphics* graphics, VertexShader* vs, PixelShader* ps) const;
+    void Draw(Graphics* graphics, ShaderProgram* vs, ShaderProgram* ps) const;
     
     /// Add or merge a batch
     static void AddOrMerge(const UIBatch& batch, PODVector<UIBatch>& batches);

+ 109 - 185
Tools/ShaderCompiler/ShaderCompiler.cpp

@@ -42,7 +42,7 @@
 
 enum ShaderType
 {
-    VS,
+    VS = 0,
     PS,
     Both
 };
@@ -60,17 +60,36 @@ struct Parameter
     {
     }
     
+    bool operator < (const Parameter& rhs) const
+    {
+        if (index_ != rhs.index_)
+            return index_ < rhs.index_;
+        else
+            return name_ < rhs.name_;
+    }
+    
+    bool operator > (const Parameter& rhs) const
+    {
+        if (index_ != rhs.index_)
+            return index_ > rhs.index_;
+        else
+            return name_ > rhs.name_;
+    }
+    
+    bool operator == (const Parameter& rhs) const
+    {
+        return (index_ == rhs.index_) && (name_ == rhs.name_);
+    }
+    
+    bool operator != (const Parameter& rhs) const
+    {
+        return (index_ != rhs.index_) || (name_ != rhs.name_);
+    }
+    
     String name_;
     unsigned index_;
 };
 
-struct Parameters
-{
-    Vector<Parameter> vsParams_;
-    Vector<Parameter> psParams_;
-    Vector<Parameter> textureUnits_;
-};
-
 struct Variation
 {
     Variation()
@@ -97,7 +116,9 @@ struct CompiledVariation
     String name_;
     Vector<String> defines_;
     PODVector<unsigned char> byteCode_;
-    Parameters parameters_;
+    unsigned byteCodeOffset_;
+    Set<Parameter> constants_;
+    Set<Parameter> textureUnits_;
     String errorMsg_;
 };
 
@@ -120,9 +141,8 @@ SharedPtr<FileSystem> fileSystem_(new FileSystem(context_));
 String inDir_;
 String inFile_;
 String outDir_;
-Map<String, unsigned> vsParams_;
-Map<String, unsigned> psParams_;
-Map<String, unsigned> textureUnits_;
+Set<Parameter> constants_;
+Set<Parameter> textureUnits_;
 Vector<String> defines_;
 bool useSM3_ = false;
 volatile bool compileFailed_ = false;
@@ -151,7 +171,10 @@ public:
                 {
                     workItem = workList_.Front();
                     workList_.Erase(workList_.Begin());
-                    PrintLine("Compiling shader " + workItem->name_);
+                    if (!workItem->name_.Empty())
+                        PrintLine("Compiling shader variation " + workItem->name_);
+                    else
+                        PrintLine("Compiling base shader variation");
                 }
             }
             if (!workItem)
@@ -210,8 +233,8 @@ void Run(const Vector<String>& arguments)
     {
         ErrorExit(
             "Usage: ShaderCompiler <definitionfile> <outputpath> [SM3] [define1] [define2]\n\n"
-            "HLSL files will be loaded from definition file directory, and binary code will\n"
-            "be output to same directory as the output file.\n"
+            "HLSL files will be loaded from definition file directory, and binary files will\n"
+            "be output to the output path, preserving the subdirectory structure.\n"
         );
     }
     
@@ -259,10 +282,10 @@ void Run(const Vector<String>& arguments)
     XMLElement shader = shaders.GetChildElement("shader");
     while (shader)
     {
-        bool writeOutput = false;
+        constants_.Clear();
+        textureUnits_.Clear();
         
         String source = shader.GetString("name");
-        
         ShaderType compileType = Both;
         String type = shader.GetString("type");
         if ((type == "VS") || (type == "vs"))
@@ -270,10 +293,6 @@ void Run(const Vector<String>& arguments)
         if ((type == "PS") || (type == "ps"))
             compileType = PS;
         
-        // If both VS & PS are defined separately, we should only write output once both have been compiled
-        if (compileType != VS)
-            writeOutput = true;
-        
         Shader baseShader(source, compileType);
         
         XMLElement variation = shader.GetChildElement("");
@@ -346,68 +365,6 @@ void Run(const Vector<String>& arguments)
             CompileVariations(baseShader, outShaders);
         }
         
-        if (writeOutput)
-        {
-            String outFileName = outDir_ + inDir_ + source + ".xml";
-            
-            // Add global parameter & texture sampler definitions
-            {
-                XMLElement parameters = outShaders.CreateChildElement("vsparameters");
-                Map<unsigned, Vector<String> > sorted;
-                for (Map<String, unsigned>::ConstIterator i = vsParams_.Begin(); i != vsParams_.End(); ++i)
-                    sorted[i->second_].Push(i->first_);
-                
-                for (Map<unsigned, Vector<String> >::ConstIterator i = sorted.Begin(); i != sorted.End(); ++i)
-                {
-                    for (unsigned j = 0; j < i->second_.Size(); ++j)
-                    {
-                        XMLElement param = parameters.CreateChildElement("parameter");
-                        param.SetString("name", i->second_[j]);
-                        param.SetInt("index", i->first_);
-                    }
-                }
-            }
-            
-            {
-                XMLElement parameters = outShaders.CreateChildElement("psparameters");
-                Map<unsigned, Vector<String> > sorted;
-                for (Map<String, unsigned>::ConstIterator i = psParams_.Begin(); i != psParams_.End(); ++i)
-                    sorted[i->second_].Push(i->first_);
-                
-                for (Map<unsigned, Vector<String> >::ConstIterator i = sorted.Begin(); i != sorted.End(); ++i)
-                {
-                    for (unsigned j = 0; j < i->second_.Size(); ++j)
-                    {
-                        XMLElement param = parameters.CreateChildElement("parameter");
-                        param.SetString("name", i->second_[j]);
-                        param.SetInt("index", i->first_);
-                    }
-                }
-            }
-            
-            {
-                XMLElement parameters = outShaders.CreateChildElement("textureunits");
-                Map<unsigned, Vector<String> > sorted;
-                for (Map<String, unsigned>::ConstIterator i = textureUnits_.Begin(); i != textureUnits_.End(); ++i)
-                    sorted[i->second_].Push(i->first_);
-                
-                for (Map<unsigned, Vector<String> >::ConstIterator i = sorted.Begin(); i != sorted.End(); ++i)
-                {
-                    for (unsigned j = 0; j < i->second_.Size(); ++j)
-                    {
-                        XMLElement param = parameters.CreateChildElement("parameter");
-                        param.SetString("name", i->second_[j]);
-                        param.SetInt("index", i->first_);
-                    }
-                }
-            }
-            
-            File outFile(context_);
-            outFile.Open(outFileName, FILE_WRITE);
-            if (!outDoc.Save(outFile))
-                ErrorExit("Could not save output file " + outFileName);
-        }
-        
         shader = shader.GetNextElement("shader");
     }
 }
@@ -416,9 +373,9 @@ void CompileVariations(const Shader& baseShader, XMLElement& shaders)
 {
     unsigned combinations = 1;
     PODVector<unsigned> usedCombinations;
-    bool hasVariations = false;
     Map<String, unsigned> nameToIndex;
     Vector<CompiledVariation> compiledVariations;
+    bool hasVariations = false;
     
     const Vector<Variation>& variations = baseShader.variations_;
     
@@ -541,25 +498,15 @@ void CompileVariations(const Shader& baseShader, XMLElement& shaders)
         
         if (unique)
         {
-            bool firstSuffix = true;
-            
-            // Build output shader filename & defines from active variations
-            String outName  = baseShader.name_;
+            // Build shader variation name & defines active variations
+            String outName;
             Vector<String> defines;
             for (unsigned j = 0; j < variations.Size(); ++j)
             {
                 if (active & (1 << j))
                 {
                     if (variations[j].name_.Length())
-                    {
-                        if (firstSuffix)
-                        {
-                            outName = outName + "_" + variations[j].name_;
-                            firstSuffix = false;
-                        }
-                        else
-                            outName = outName + variations[j].name_;
-                    }
+                        outName += variations[j].name_;
                     for (unsigned k = 0; k < variations[j].defines_.Size(); ++k)
                         defines.Push(variations[j].defines_[k]);
                 }
@@ -580,9 +527,13 @@ void CompileVariations(const Shader& baseShader, XMLElement& shaders)
     for (unsigned i = 0; i < compiledVariations.Size(); ++i)
         workList_.Push(&compiledVariations[i]);
     
-    // Create and start worker threads
+    // Create and start worker threads. Use all cores except one to not lock up the computer completely
+    unsigned numWorkerThreads = GetNumCPUCores() - 1;
+    if (!numWorkerThreads)
+        numWorkerThreads = 1;
+    
     Vector<SharedPtr<WorkerThread> > workerThreads;
-    workerThreads.Resize(GetNumCPUCores());
+    workerThreads.Resize(numWorkerThreads);
     for (unsigned i = 0; i < workerThreads.Size(); ++i)
     {
         workerThreads[i] = new WorkerThread();
@@ -592,41 +543,63 @@ void CompileVariations(const Shader& baseShader, XMLElement& shaders)
     for (unsigned i = 0; i < workerThreads.Size(); ++i)
         workerThreads[i]->Stop();
     
-    // Build the XML output
+    // Check that all shaders compiled
     for (unsigned i = 0; i < compiledVariations.Size(); ++i)
     {
         if (!compiledVariations[i].errorMsg_.Empty())
-            ErrorExit("Failed to compile shader " + compiledVariations[i].name_ + ": " + compiledVariations[i].errorMsg_);
-        
-        Parameters& params = compiledVariations[i].parameters_;
+            ErrorExit("Failed to compile shader " + baseShader.name_ + "_" + compiledVariations[i].name_ + ": " + compiledVariations[i].errorMsg_);
+    }
+    
+    // Build the output file
+    String outFileName = outDir_ + inDir_ + baseShader.name_;
+    outFileName += (baseShader.type_ == VS) ? ".vs" : ".ps";
+    outFileName += (useSM3_) ? "3" : "2";
+    
+    File outFile(context_, outFileName, FILE_WRITE);
+    if (!outFile.IsOpen())
+        ErrorExit("Could not open output file " + outFileName);
+    
+    // Convert the global parameters to vectors for index based search
+    Vector<Parameter> constants;
+    Vector<Parameter> textureUnits;
+    
+    for (Set<Parameter>::ConstIterator i = constants_.Begin(); i != constants_.End(); ++i)
+        constants.Push(*i);
+    for (Set<Parameter>::ConstIterator i = textureUnits_.Begin(); i != textureUnits_.End(); ++i)
+        textureUnits.Push(*i);
+    
+    outFile.WriteID("USHD");
+    outFile.WriteShort(baseShader.type_);
+    outFile.WriteShort(useSM3_ ? 3 : 2);
+    
+    outFile.WriteUInt(constants.Size());
+    for (unsigned i = 0; i < constants.Size(); ++i)
+    {
+        outFile.WriteString(constants[i].name_);
+        outFile.WriteUByte(constants[i].index_);
+    }
+    
+    outFile.WriteUInt(textureUnits.Size());
+    for (unsigned i = 0; i < textureUnits.Size(); ++i)
+    {
+        outFile.WriteString(textureUnits[i].name_);
+        outFile.WriteUByte(textureUnits[i].index_);
+    }
+    
+    outFile.WriteUInt(compiledVariations.Size());
+    for (unsigned i = 0; i < compiledVariations.Size(); ++i)
+    {
+        CompiledVariation& variation = compiledVariations[i];
+        outFile.WriteString(variation.name_);
+        for (unsigned j = 0; j < constants.Size(); ++j)
+            outFile.WriteBool(variation.constants_.Find(constants[j]) != variation.constants_.End());
+        for (unsigned j = 0; j < textureUnits.Size(); ++j)
+            outFile.WriteBool(variation.textureUnits_.Find(textureUnits[j]) != variation.textureUnits_.End());
         
-        XMLElement shader = shaders.CreateChildElement("shader");
-        shader.SetString("name", compiledVariations[i].name_);
-        switch (baseShader.type_)
-        {
-        case VS:
-            shader.SetString("type", "vs");
-            for (unsigned j = 0; j < params.vsParams_.Size(); ++j)
-            {
-                XMLElement vsParam = shader.CreateChildElement("parameter");
-                vsParam.SetString("name", params.vsParams_[j].name_);
-            }
-            break;
-            
-        case PS:
-            shader.SetString("type", "ps");
-            for (unsigned j = 0; j < params.psParams_.Size(); ++j)
-            {
-                XMLElement psParam = shader.CreateChildElement("parameter");
-                psParam.SetString("name", params.psParams_[j].name_);
-            }
-            for (unsigned j = 0; j < params.textureUnits_.Size(); ++j)
-            {
-                XMLElement texture = shader.CreateChildElement("textureunit");
-                texture.SetString("name", params.textureUnits_[j].name_);
-            }
-            break;
-        }
+        unsigned dataSize = variation.byteCode_.Size();
+        outFile.WriteUInt(dataSize);
+        if (dataSize)
+            outFile.Write(&variation.byteCode_[0], dataSize);
     }
 }
 
@@ -662,7 +635,6 @@ void Compile(CompiledVariation* variation)
     
     // Set the profile, entrypoint and flags according to the shader being compiled
     String profile;
-    String extension;
     String entryPoint;
     unsigned flags = 0;
     
@@ -670,34 +642,22 @@ void Compile(CompiledVariation* variation)
     {
         entryPoint = "VS";
         if (!useSM3_)
-        {
             profile = "vs_2_0";
-            extension = ".vs2";
-        }
         else
-        {
             profile = "vs_3_0";
-            extension = ".vs3";
-        }
     }
     else
     {
         entryPoint = "PS";
         if (!useSM3_)
-        {
             profile = "ps_2_0";
-            extension = ".ps2";
-        }
         else
         {
             profile = "ps_3_0";
-            extension = ".ps3";
             flags |= D3DXSHADER_PREFER_FLOW_CONTROL;
         }
     }
     
-    String outFileName = outDir_ + inDir_ + variation->name_ + extension;
-    
     // Compile using D3DX
     HRESULT hr = D3DXCompileShader(hlslCode_.CString(), hlslCode_.Length(), &macros.Front(), &includeHandler, 
         entryPoint.CString(), profile.CString(), flags, &shaderCode, &errorMsgs, &constantTable);
@@ -714,15 +674,6 @@ void Compile(CompiledVariation* variation)
             variation->byteCode_.Resize(dataSize);
             memcpy(&variation->byteCode_[0], shaderCode->GetBufferPointer(), dataSize);
         }
-        
-        File outFile(context_, outFileName, FILE_WRITE);
-        if (outFile.IsOpen())
-            outFile.Write(shaderCode->GetBufferPointer(), dataSize);
-        else
-        {
-            variation->errorMsg_ = "Failed to write output file " + outFileName;
-            compileFailed_ = true;
-        }
     }
     
     // Parse the constant table for constants and texture units
@@ -749,43 +700,16 @@ void Compile(CompiledVariation* variation)
             // Skip if it's a G-buffer sampler
             if (name.Find("Buffer") == String::NPOS)
             {
-                variation->parameters_.textureUnits_.Push(Parameter(name, index));
-                
-                if (textureUnits_.Find(name) != textureUnits_.End())
-                {
-                    unsigned oldIndex = textureUnits_[name];
-                    if (oldIndex != index)
-                        ErrorExit("Texture " + name + " bound to several sampler registers");
-                }
-                textureUnits_[name] = index;
+                Parameter newTextureUnit(name, index);
+                variation->textureUnits_.Insert(newTextureUnit);
+                textureUnits_.Insert(newTextureUnit);
             }
         }
         else
         {
-            if (variation->type_ == VS)
-            {
-                variation->parameters_.vsParams_.Push(Parameter(name, index));
-                
-                if (vsParams_.Find(name) != vsParams_.End())
-                {
-                    unsigned oldIndex = vsParams_[name];
-                    if (oldIndex != index)
-                        ErrorExit("Parameter " + name + " bound to several constant registers");
-                }
-                vsParams_[name] = index;
-            }
-            else
-            {
-                variation->parameters_.psParams_.Push(Parameter(name, index));
-                
-                if (psParams_.Find(name) != psParams_.End())
-                {
-                    unsigned oldIndex = psParams_[name];
-                    if (oldIndex != index)
-                        ErrorExit("Parameter " + name + " bound to several constant registers");
-                }
-                psParams_[name] = index;
-            }
+            Parameter newParam(name, index);
+            variation->constants_.Insert(newParam);
+            constants_.Insert(newParam);
         }
     }