diff --git a/source/graphics/LightEnv.h b/source/graphics/LightEnv.h index 3a17efea14..a836b456ad 100755 --- a/source/graphics/LightEnv.h +++ b/source/graphics/LightEnv.h @@ -18,30 +18,56 @@ #include "Color.h" #include "Vector3D.h" +class CMapWriter; +class CMapReader; + /////////////////////////////////////////////////////////////////////////////// // CLightEnv: description of a lighting environment - contains all the // necessary parameters for representation of the lighting within a scenario -class CLightEnv +class CLightEnv { +friend class CMapWriter; +friend class CMapReader; +// wierd accessor order to preserve memory layout of the class public: RGBColor m_SunColor; +private: float m_Elevation; float m_Rotation; +public: RGBColor m_TerrainAmbientColor; RGBColor m_UnitsAmbientColor; + CVector3D m_SunDir; // get sun direction from a rotation and elevation; defined such that: // 0 rotation = (0,0,1) // PI/2 rotation = (-1,0,0) // 0 elevation = (0,0,0) // PI/2 elevation = (0,-1,0) - void GetSunDirection(CVector3D& lightdir) const { - lightdir.Y=-float(sin(m_Elevation)); - float scale=1+lightdir.Y; - lightdir.X=scale*float(sin(m_Rotation)); - lightdir.Z=scale*float(cos(m_Rotation)); - lightdir.Normalize(); - } + + float GetElevation() { return m_Elevation; } + float GetRotation() { return m_Rotation; } + + void SetElevation(float f) + { + m_Elevation = f; + CalculateSunDirection(); + } + + void SetRotation(float f) + { + m_Rotation = f; + CalculateSunDirection(); + } + + void CalculateSunDirection() + { + m_SunDir.Y=-float(sin(m_Elevation)); + float scale=1+m_SunDir.Y; + m_SunDir.X=scale*float(sin(m_Rotation)); + m_SunDir.Z=scale*float(cos(m_Rotation)); + m_SunDir.Normalize(); + } }; #endif diff --git a/source/graphics/MapReader.cpp b/source/graphics/MapReader.cpp index 4f6469f207..4151ada9b7 100755 --- a/source/graphics/MapReader.cpp +++ b/source/graphics/MapReader.cpp @@ -54,6 +54,7 @@ void CMapReader::UnpackLightEnv(CFileUnpacker& unpacker) unpacker.UnpackRaw(&m_LightEnv.m_Rotation,sizeof(m_LightEnv.m_Rotation)); unpacker.UnpackRaw(&m_LightEnv.m_TerrainAmbientColor,sizeof(m_LightEnv.m_TerrainAmbientColor)); unpacker.UnpackRaw(&m_LightEnv.m_UnitsAmbientColor,sizeof(m_LightEnv.m_UnitsAmbientColor)); + m_LightEnv.CalculateSunDirection(); } // UnpackObjects: unpack world objects from input stream diff --git a/source/graphics/Material.cpp b/source/graphics/Material.cpp index 81de0a835f..7eae68c91d 100755 --- a/source/graphics/Material.cpp +++ b/source/graphics/Material.cpp @@ -61,10 +61,10 @@ bool CMaterial::operator ==(const CMaterial &material) void CMaterial::Bind() { - glMaterialfv(GL_FRONT, GL_DIFFUSE, &m_Diffuse.data[0]); - glMaterialfv(GL_FRONT, GL_AMBIENT, &m_Ambient.data[0]); - glMaterialfv(GL_FRONT, GL_SPECULAR, &m_Specular.data[0]); - glMaterialfv(GL_FRONT, GL_EMISSION, &m_Emissive.data[0]); + glMaterialfv(GL_FRONT, GL_DIFFUSE, &m_Diffuse.r); + glMaterialfv(GL_FRONT, GL_AMBIENT, &m_Ambient.r); + glMaterialfv(GL_FRONT, GL_SPECULAR, &m_Specular.r); + glMaterialfv(GL_FRONT, GL_EMISSION, &m_Emissive.r); glMaterialf(GL_FRONT, GL_SHININESS, m_SpecularPower); oglCheck(); @@ -100,6 +100,18 @@ void CMaterial::SetTexture(const CStr &texture) ComputeHash(); } +void CMaterial::SetVertexProgram(const CStr &prog) +{ + m_VertexProgram = prog; + ComputeHash(); +} + +void CMaterial::SetFragmentProgram(const CStr &prog) +{ + m_FragmentProgram = prog; + ComputeHash(); +} + void CMaterial::SetDiffuse(const SMaterialColor &color) { m_Diffuse = color; @@ -144,5 +156,7 @@ void CMaterial::ComputeHash() m_Specular.Sum() + m_Emissive.Sum() + m_SpecularPower + - (float)m_Texture.GetHashCode(); + (float)m_Texture.GetHashCode() + + (float)m_VertexProgram.GetHashCode() + + (float)m_FragmentProgram.GetHashCode(); } diff --git a/source/graphics/Material.h b/source/graphics/Material.h index 3573231038..15bbdf409c 100755 --- a/source/graphics/Material.h +++ b/source/graphics/Material.h @@ -6,6 +6,11 @@ struct SMaterialColor { public: + float r; + float g; + float b; + float a; + SMaterialColor() { r = 0.0f; g = 0.0f; b = 0.0f; a = 1.0f; } SMaterialColor(float _r, float _g, float _b, float _a) { @@ -20,19 +25,7 @@ public: g = color.g; b = color.b; a = color.a; - } - - union - { - struct - { - float r; - float g; - float b; - float a; - }; - float data[4]; - }; + } void operator =(const SMaterialColor color) { @@ -69,6 +62,8 @@ public: float GetHash() { return m_Hash; } CStr GetTexture() { return m_Texture; } + CStr GetVertexProgram() { return m_VertexProgram; } + CStr GetFragmentProgram() { return m_FragmentProgram; } SMaterialColor GetDiffuse(); SMaterialColor GetAmbient(); SMaterialColor GetSpecular(); @@ -77,6 +72,8 @@ public: bool UsesAlpha() { return m_Alpha; } void SetTexture(const CStr &texture); + void SetVertexProgram(const CStr &prog); + void SetFragmentProgram(const CStr &prog); void SetDiffuse(const SMaterialColor &color); void SetAmbient(const SMaterialColor &color); void SetSpecular(const SMaterialColor &color); @@ -101,6 +98,10 @@ protected: // Path to the materials texture CStr m_Texture; + // Paths to vertex/fragment programs + CStr m_VertexProgram; + CStr m_FragmentProgram; + // Alpha required flag bool m_Alpha; }; diff --git a/source/graphics/MaterialManager.cpp b/source/graphics/MaterialManager.cpp index a3b751ee82..464974daa7 100755 --- a/source/graphics/MaterialManager.cpp +++ b/source/graphics/MaterialManager.cpp @@ -186,6 +186,8 @@ CMaterial &CMaterialManager::LoadMaterial(const char *file) #define EL(x) int el_##x = xeroFile.getElementID(#x) #define AT(x) int at_##x = xeroFile.getAttributeID(#x) EL(texture); + EL(vertexprogram); + EL(fragmentprogram); EL(colors); AT(diffuse); @@ -218,6 +220,16 @@ CMaterial &CMaterialManager::LoadMaterial(const char *file) CStr value(node.getText()); material->SetTexture(value); + } + else if(token == el_vertexprogram) + { + CStr value(node.getText()); + material->SetVertexProgram(value); + } + else if(token == el_fragmentprogram) + { + CStr value(node.getText()); + material->SetFragmentProgram(value); } else if(token == el_colors) { diff --git a/source/graphics/Model.cpp b/source/graphics/Model.cpp index b3c50176a0..493cfa42af 100755 --- a/source/graphics/Model.cpp +++ b/source/graphics/Model.cpp @@ -14,12 +14,14 @@ #include "SkeletonAnim.h" #include "SkeletonAnimDef.h" #include "SkeletonAnimManager.h" +#include "ProgramManager.h" ///////////////////////////////////////////////////////////////////////////////////////////////////////////// // Constructor CModel::CModel() : m_pModelDef(0), m_Flags(0), m_Anim(0), m_AnimTime(0), - m_BoneMatrices(0), m_InvBoneMatrices(0), m_BoneMatricesValid(false) + m_BoneMatrices(0), m_InvBoneMatrices(0), m_BoneMatricesValid(false), + m_VertexProgram(0) { } @@ -347,3 +349,13 @@ void CModel::SetTransform(const CMatrix3D& transform) prop.m_Model->SetTransform(proptransform); } } + +void CModel::SetMaterial(const CMaterial &material) +{ + m_Material = material; + if(m_Material.GetTexture().Trim(PS_TRIM_BOTH).Length() > 0) + { + } + if(m_Material.GetVertexProgram().Trim(PS_TRIM_BOTH).Length() > 0) + m_VertexProgram = g_ProgramManager.FindVertexProgram(m_Material.GetVertexProgram().Trim(PS_TRIM_BOTH).c_str()); +} diff --git a/source/graphics/Model.h b/source/graphics/Model.h index 5b58525085..3a5b2e6aee 100755 --- a/source/graphics/Model.h +++ b/source/graphics/Model.h @@ -16,6 +16,7 @@ #include "RenderableObject.h" #include "SkeletonAnim.h" #include "Material.h" +#include "renderer/VertexProgram.h" #define MODELFLAG_CASTSHADOWS (1<<0) @@ -51,7 +52,7 @@ public: // set the model's texture void SetTexture(const CTexture& tex) { m_Texture=tex; } // set the model's material - void SetMaterial(const CMaterial &material) { m_Material = material; } + void SetMaterial(const CMaterial &material); // get the model's texture CTexture* GetTexture() { return &m_Texture; } // get the models material @@ -121,6 +122,8 @@ private: u32 m_Flags; // texture used by model CTexture m_Texture; + // vertex program + CVertexProgram *m_VertexProgram; // model's material CMaterial m_Material; // pointer to the model's raw 3d data diff --git a/source/graphics/ProgramManager.cpp b/source/graphics/ProgramManager.cpp index 132c3ff3ff..6824027ce6 100755 --- a/source/graphics/ProgramManager.cpp +++ b/source/graphics/ProgramManager.cpp @@ -1,6 +1,9 @@ #include "precompiled.h" #include "graphics/ProgramManager.h" +#define SAFE_DELETE(x) \ + if((x)) { delete (x); (x) = NULL; } + CProgramManager::CProgramManager() { #ifdef BUILD_CG @@ -31,7 +34,9 @@ CVertexProgram *CProgramManager::FindVertexProgram(const char *file) if(prog && prog->IsValid()) m_VertexProgs[std::string(file)] = prog; else - prog = NULL; + { + SAFE_DELETE(prog); + } } return prog; diff --git a/source/graphics/ProgramManager.h b/source/graphics/ProgramManager.h index 2e52591da6..b4285f468c 100755 --- a/source/graphics/ProgramManager.h +++ b/source/graphics/ProgramManager.h @@ -21,6 +21,8 @@ public: void WritePPInfo(FILE *file); #ifdef BUILD_CG + CGprofile GetVPProfile() { return m_VPProfile; } + CGprofile GetFPProfile() { return m_FPProfile; } CGcontext GetContext() { return m_Context; } #endif private: diff --git a/source/main.cpp b/source/main.cpp index f15b4878b6..3a1253baa1 100755 --- a/source/main.cpp +++ b/source/main.cpp @@ -1000,8 +1000,8 @@ PREVTSC=CURTSC; // lighting environment through a pointer, this has to be done before // the first Frame. g_LightEnv.m_SunColor=RGBColor(1,1,1); - g_LightEnv.m_Rotation=DEGTORAD(270); - g_LightEnv.m_Elevation=DEGTORAD(45); + g_LightEnv.SetRotation(DEGTORAD(270)); + g_LightEnv.SetElevation(DEGTORAD(45)); g_LightEnv.m_TerrainAmbientColor=RGBColor(0,0,0); g_LightEnv.m_UnitsAmbientColor=RGBColor(0.4f,0.4f,0.4f); g_Renderer.SetLightEnv(&g_LightEnv); diff --git a/source/renderer/Renderer.cpp b/source/renderer/Renderer.cpp index 3096d9b918..7b8b96e1f9 100755 --- a/source/renderer/Renderer.cpp +++ b/source/renderer/Renderer.cpp @@ -276,11 +276,8 @@ void CRenderer::BeginFrame() m_SHCoeffsTerrain.Clear(); if (m_LightEnv) { - CVector3D dirlight; - m_LightEnv->GetSunDirection(dirlight); - - m_SHCoeffsUnits.AddDirectionalLight(dirlight,m_LightEnv->m_SunColor); - m_SHCoeffsTerrain.AddDirectionalLight(dirlight,m_LightEnv->m_SunColor); + m_SHCoeffsUnits.AddDirectionalLight(m_LightEnv->m_SunDir, m_LightEnv->m_SunColor); + m_SHCoeffsTerrain.AddDirectionalLight(m_LightEnv->m_SunDir, m_LightEnv->m_SunColor); m_SHCoeffsUnits.AddAmbientLight(m_LightEnv->m_UnitsAmbientColor); m_SHCoeffsTerrain.AddAmbientLight(m_LightEnv->m_TerrainAmbientColor); @@ -377,15 +374,11 @@ void CRenderer::CalcShadowMatrices() bounds.GetCentre(centre); // get sunlight direction - CVector3D lightdir; - // ??? RC using matrix rotation to get sun direction? - m_LightEnv->GetSunDirection(lightdir); - // ??? RC more optimal light placement? - CVector3D lightpos=centre-(lightdir*1000); + CVector3D lightpos=centre-(m_LightEnv->m_SunDir * 1000); // make light transformation matrix - ConstructLightTransform(lightpos,lightdir,m_LightTransform); + ConstructLightTransform(lightpos,m_LightEnv->m_SunDir,m_LightTransform); // transform shadow bounds to light space, calculate near and far bounds CVector3D vp[8]; diff --git a/source/renderer/Renderer.h b/source/renderer/Renderer.h index 3a4b50bc9b..1d2ab387d3 100755 --- a/source/renderer/Renderer.h +++ b/source/renderer/Renderer.h @@ -213,6 +213,8 @@ public: // return stats accumulated for current frame const Stats& GetStats() { return m_Stats; } + // return the current light environment + const CLightEnv &GetLightEnv() { return *m_LightEnv; } protected: friend class CVertexBuffer; friend class CPatchRData; diff --git a/source/renderer/VertexProgram.cpp b/source/renderer/VertexProgram.cpp index 65cb6dc87b..c627092096 100755 --- a/source/renderer/VertexProgram.cpp +++ b/source/renderer/VertexProgram.cpp @@ -3,6 +3,9 @@ #include "res/mem.h" #include "renderer/VertexProgram.h" #include "graphics/ProgramManager.h" +#include "renderer/Renderer.h" +#include "maths/Vector3D.h" +#include "graphics/LightEnv.h" #include "CLogger.h" #define LOG_CATEGORY "shaders" @@ -35,12 +38,8 @@ void CVertexProgram::Bind() if(!IsValid()) return; - CGparameter param = cgGetFirstParameter(m_Program, CG_PROGRAM); - while(param) - { - PushParameter(param); - param = cgGetNextParameter(param); - } + EnumParameters(CG_GLOBAL); + EnumParameters(CG_PROGRAM); if(!cgGLIsProgramLoaded(m_Program)) cgGLLoadProgram(m_Program); @@ -53,7 +52,7 @@ void CVertexProgram::Load(const char *file) { #ifdef BUILD_CG m_Program = NULL; - if(!file || !vfs_exists(file)) + if(!file || !vfs_exists(file) || g_ProgramManager.GetVPProfile() == CG_PROFILE_UNKNOWN) return; void *data; @@ -72,7 +71,7 @@ void CVertexProgram::Load(const char *file) g_ProgramManager.GetContext(), CG_SOURCE, src.c_str(), - CG_PROFILE_ARBVP1, + g_ProgramManager.GetVPProfile(), "main", NULL ); @@ -86,6 +85,16 @@ void CVertexProgram::Load(const char *file) #ifdef BUILD_CG +void CVertexProgram::EnumParameters(CGenum ns) +{ + CGparameter param = cgGetFirstParameter(m_Program, ns); + while(param) + { + PushParameter(param); + param = cgGetNextParameter(param); + } +} + void CVertexProgram::PushParameter(CGparameter param) { assert(param); @@ -99,6 +108,18 @@ void CVertexProgram::PushParameter(CGparameter param) cgGLSetStateMatrixParameter(param, CG_GL_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY); else if(name == "Texture") cgGLSetStateMatrixParameter(param, CG_GL_TEXTURE_MATRIX, CG_GL_MATRIX_IDENTITY); + else if(name == "SunDir") + { + cgGLSetParameterPointer( + param, sizeof(CVector3D), GL_FLOAT, sizeof(float), &g_Renderer.GetLightEnv().m_SunDir.X + ); + } + else if(name == "SunColor") + { + cgGLSetParameterPointer( + param, sizeof(CVector3D), GL_FLOAT, sizeof(float), &g_Renderer.GetLightEnv().m_SunColor.X + ); + } else LOG(WARNING, LOG_CATEGORY, "CVertexShader::LoadShader: Unknown parameter name: %s", name.c_str()); } diff --git a/source/renderer/VertexProgram.h b/source/renderer/VertexProgram.h index c602130476..a35ff1280c 100755 --- a/source/renderer/VertexProgram.h +++ b/source/renderer/VertexProgram.h @@ -26,6 +26,7 @@ private: void Bind(); void Load(const char *file); #ifdef BUILD_CG + void EnumParameters(CGenum ns); void PushParameter(CGparameter param); CGprogram m_Program; #endif