00001 #include "global.h"
00002 #include "MercuryDisplay.h"
00003 #include "MercuryMaterial.h"
00004 #include "MercuryINI.h"
00005 #include "MercuryTextureManager.h"
00006 #include "MercuryLog.h"
00007
00008 #define MC_SHADERCHECK 0
00009
00010 MercuryMaterial::~MercuryMaterial()
00011 {
00012 ClearTextures();
00013 if (m_iGLSLShaderID != -1)
00014 DISPLAY->DestroyShaderProgram(m_iGLSLShaderID);
00015 }
00016
00017 MercuryMaterial::MercuryMaterial()
00018 {
00019 m_shininess = 0;
00020 m_alpha = 0;
00021 m_iGLSLShaderID = -1;
00022 m_bHasRegistered = false;
00023 }
00024
00025 void MercuryMaterial::AddTexture(MercuryTexture* texture)
00026 {
00027 ASSERT(texture->IsInitalized());
00028 m_textures.push_back(texture);
00029 }
00030
00031 void MercuryMaterial::Message( int Message, PStack & data, const MString & name )
00032 {
00033 if ( Message == MC_SHADERCHECK )
00034 {
00035 MercuryFile * fx = FILEMAN.Open( m_GLSLFragmentFile );
00036 if( fx ) {
00037 unsigned thisTime = fx->GetModTime();
00038 if( m_iGLSLFragTime != thisTime )
00039 {
00040 BuildShader();
00041 m_iGLSLFragTime = thisTime;
00042 }
00043 SAFE_DELETE( fx );
00044 }
00045 fx = FILEMAN.Open( m_GLSLVertexFile );
00046 if( fx ) {
00047 unsigned thisTime = fx->GetModTime();
00048 if( m_iGLSLVertTime != thisTime )
00049 {
00050 BuildShader();
00051 m_iGLSLVertTime = thisTime;
00052 }
00053 SAFE_DELETE( fx );
00054 }
00055
00056 MESSAGEMAN->PostSystemMessage( ssprintf( "Material%pCheck", this ), PStack(), PREFSMAN->GetValueF( "Options", "CheckGLSL", -1, true ) );
00057 }
00058 }
00059
00060 void MercuryMaterial::BuildShader()
00061 {
00062 MString sFragment, sVertex;
00063 LOG.Info("Loading shader programs: " + m_GLSLVertexFile + ", " + m_GLSLVertexFile);
00064 FileToMString( m_GLSLFragmentFile, sFragment );
00065 FileToMString( m_GLSLVertexFile, sVertex );
00066
00067
00068 if (m_iGLSLShaderID != -1)
00069 DISPLAY->DestroyShaderProgram(m_iGLSLShaderID);
00070 m_iGLSLShaderID = DISPLAY->CompileShader( sVertex, sFragment );
00071 }
00072
00073 bool MercuryMaterial::LoadMaterial(const MString& filename, const MString& path)
00074 {
00075 MercuryINI f;
00076
00077 int version = 0;
00078 unsigned int numTextures = 0;
00079 m_completePath = path + filename;
00080
00081
00082
00083 if ( m_completePath.compare( m_completePath.length() - 3, 3, "ini" ) != 0 )
00084 {
00085 ClearTextures();
00086 MercuryTexture* texture = MercuryTextureManager::CreateTexture(m_completePath);
00087 if (texture)
00088 {
00089 AddTexture(texture);
00090 return true;
00091 }
00092
00093 return false;
00094 }
00095
00096
00097 if (!f.Open(m_completePath))
00098 {
00099 LOG.Log("Unable to open INI:" + m_completePath);
00100 return false;
00101 }
00102
00103 version = f.GetValueI("Material", "Version");
00104
00105 switch (version)
00106 {
00107 case 3:
00108 case 2:
00109
00110 m_diffuse.FromString(f.GetValueS("Material", "Diffuse"));
00111 m_ambient.FromString(f.GetValueS("Material", "Ambient"));
00112 m_specular.FromString(f.GetValueS("Material", "Specular"));
00113 m_emissive.FromString(f.GetValueS("Material", "Emissive"));
00114 m_shininess = f.GetValueF("Material", "Shine" );
00115 case 1:
00116
00117 m_name = f.GetValueS("Material", "Name");
00118 numTextures = f.GetValueI("Material", "NumTextures");
00119 ClearTextures();
00120 for (unsigned int i = 0; i < numTextures; ++i)
00121 {
00122 MercuryTexture* t;
00123 MString tpath;
00124 MString mapping;
00125 MercuryPoint p;
00126 MString tmp;
00127
00128 tpath = path + f.GetValueS("Material", ssprintf("Texture%d", i+1));
00129
00130 if ( tpath.empty() )
00131 continue;
00132
00133 t = MercuryTextureManager::CreateTexture(tpath);
00134 if (!t)
00135 {
00136 LOG.Log("Unable to load image: " + tpath);
00137 continue;
00138 }
00139
00140 mapping = f.GetValueS("Material", ssprintf("Texture%dMapping", i+1));
00141 if (mapping.empty())
00142 mapping = "standard";
00143
00144 t->SetMapMode(f.GetValueI("Material", ssprintf("Texture%dMapMode", i+1)));
00145
00146 tmp = f.GetValueS("Material", ssprintf("Texture%dScaleXYZ", i+1));
00147 if (tmp.empty())
00148 p.x = p.y = p.z = 1;
00149 else
00150 sscanf(f.GetValueS("Material", ssprintf("Texture%dScaleXYZ", i+1)), "%f,%f,%f", &p.x, &p.y, &p.z);
00151 t->SetScale(p);
00152
00153 tmp = f.GetValueS("Material", ssprintf("Texture%dOffsetXYZ", i+1));
00154 if (tmp.empty())
00155 p.x = p.y = p.z = 0;
00156 else
00157 sscanf(tmp, "%f,%f,%f", &p.x, &p.y, &p.z);
00158 t->SetPosition(p);
00159
00160 tmp = f.GetValueS("Material", ssprintf("Texture%dRotXYZ", i+1));
00161 if (tmp.empty())
00162 p.x = p.y = p.z = 0;
00163 else
00164 sscanf(tmp, "%f,%f,%f", &p.x, &p.y, &p.z);
00165 t->SetRot(p);
00166
00167 AddTexture(t);
00168
00169
00170
00171 if (mapping == "standard")
00172 t->SetMapping(STANDARD);
00173 else if(mapping == "sphere")
00174 t->SetMapping(SPHERE);
00175 else if (mapping == "cube")
00176 t->SetMapping(CUBE);
00177 else if (mapping == "dot3")
00178 t->SetMapping(DOT3);
00179 }
00180 }
00181
00182 m_GLSLFragmentFile = f.GetValueS("Material", "GLSLFragmentFile");
00183 m_GLSLVertexFile = f.GetValueS("Material", "GLSLVertexFile");
00184
00185 if( !m_GLSLFragmentFile.empty() && !m_GLSLVertexFile.empty() )
00186 {
00187 if( FileExists( m_GLSLFragmentFile ) && FileExists( m_GLSLVertexFile ) )
00188 {
00189 BuildShader();
00190
00191 if( PREFSMAN->GetValueF( "Options", "CheckGLSL", -1, true ) > 0 )
00192 {
00193 MercuryFile * fx = FILEMAN.Open( m_GLSLFragmentFile );
00194
00195
00196
00197 if( fx ) {
00198 m_iGLSLFragTime = fx->GetModTime();
00199 SAFE_DELETE( fx );
00200 }
00201
00202 fx = FILEMAN.Open( m_GLSLVertexFile );
00203 if( fx ) {
00204 m_iGLSLVertTime = fx->GetModTime();
00205 SAFE_DELETE( fx );
00206 }
00207 if ( !m_bHasRegistered )
00208 {
00209
00210 RegisterMessage( MC_SHADERCHECK, ssprintf( "Material%pCheck", this ) );
00211 MESSAGEMAN->PostSystemMessage( ssprintf( "Material%pCheck", this ), PStack(), PREFSMAN->GetValueF( "Options", "CheckGLSL", -1, true ) );
00212 m_bHasRegistered = true;
00213 }
00214 }
00215 }
00216 else
00217 {
00218 LOG.Warn( "Could not find shader(s) in: " + m_completePath );
00219 m_iGLSLShaderID = -1;
00220 }
00221 }
00222 else
00223 m_iGLSLShaderID = -1;
00224
00225
00226 if( m_iGLSLShaderID != -1 )
00227 {
00228 MString sAllParams = f.GetValueS( "Material", "GLSLUniforms" );
00229 SplitStrings( sAllParams, m_vUniformNames, ",", " ", 1, 1 );
00230 m_vUniformValues.resize( m_vUniformNames.size() );
00231 for( unsigned i = 0; i < m_vUniformNames.size(); i++ )
00232 {
00233 MString sVal = m_vUniformNames[i];
00234
00235 MString sTyp = f.GetValueS( "Material", "U" + sVal + "Type" );
00236 MString sDat = f.GetValueS( "Material", "U" + sVal );
00237
00238 MVector< MString > vDat;
00239 SplitStrings( sDat, vDat, ",", " ", 1, 1 );
00240
00241 if( sTyp == "int" )
00242 {
00243 for( unsigned j = 0; j < vDat.size(); j++ )
00244 m_vUniformValues[i].PushItemBack( PSElement( atoi( vDat[j] ) ) );
00245 }
00246 else
00247 {
00248 for( unsigned j = 0; j < vDat.size(); j++ )
00249 m_vUniformValues[i].PushItemBack( PSElement( (float)atof( vDat[j] ) ) );
00250 }
00251 }
00252 }
00253 return true;
00254 }
00255
00256 void MercuryMaterial::ClearTextures()
00257 {
00258 m_textures.clear();
00259 }
00260
00261 const MercuryMaterial& MercuryMaterial::operator=(const MercuryMaterial& m)
00262 {
00263 m_ambient = m.m_ambient;
00264 m_diffuse = m.m_diffuse;
00265 m_specular = m.m_specular;
00266 m_emissive = m.m_emissive;
00267 m_shininess = m.m_shininess;
00268 m_alpha = m.m_alpha;
00269
00270 m_textures = m.m_textures;
00271
00272 return *this;
00273 }
00274
00275 const MercuryMaterial MercuryMaterial::operator*(const MercuryMaterial& m)
00276 {
00277 MercuryMaterial r;
00278 r.m_ambient = m_ambient * m.m_ambient;
00279 r.m_diffuse = m_diffuse * m.m_diffuse;
00280 r.m_specular = m_specular * m.m_specular;
00281 r.m_emissive = m_emissive * m.m_emissive;
00282 r.m_shininess = m_shininess * m.m_shininess;
00283 r.m_alpha = m_alpha * m.m_alpha;
00284 return r;
00285 }
00286
00287 const MercuryMaterial& MercuryMaterial::operator*=(const MercuryMaterial& m)
00288 {
00289 m_ambient *= m.m_ambient;
00290 m_diffuse *= m.m_diffuse;
00291 m_specular *= m.m_specular;
00292 m_emissive *= m.m_emissive;
00293 m_shininess *= m.m_shininess;
00294 return *this;
00295 }
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323