MercuryMaterial.cpp

Go to the documentation of this file.
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         //repost the check shader message
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     //Destroy the previous shader if one exists
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     //try loading an image if the path does not end in ini which indicates
00082     //a material file
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 //      LOG.Log("Material file not an .ini:" + completePath);
00093         return false;
00094     }
00095 
00096     //continue the load process assuming a material ini file
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         //version 2
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         //version 1
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             //Make this much better when textures actually have more than 2
00170             //ways of mapping
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                 //Get the time the shader file was last modified. We can monitor this in
00196                 //realtime and reload as needed.
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                     //Register shader timestamp check
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     //Load Uniform values from INI
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             //Get Type
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  * Copyright (c) 2005-2006, Joshua Allen
00299  * All rights reserved.
00300  *
00301  * Redistribution and use in source and binary forms, with or
00302  * without modification, are permitted provided that the following
00303  * conditions are met:
00304  *  -   Redistributions of source code must retain the above
00305  *      copyright notice, this list of conditions and the following disclaimer.
00306  *  -   Redistributions in binary form must reproduce the above copyright
00307  *      notice, this list of conditions and the following disclaimer in
00308  *      the documentation and/or other materials provided with the distribution.
00309  *  -   Neither the name of the Mercury Engine nor the names of its
00310  *      contributors may be used to endorse or promote products derived from
00311  *      this software without specific prior written permission.
00312  *
00313  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00314  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00315  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00316  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
00317  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00318  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
00319  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00320  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00321  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
00322  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00323  */

Hosted by SourceForge.net Logo