Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

OgreMaterialSerializer.cpp

Go to the documentation of this file.
00001 /*
00002 -----------------------------------------------------------------------------
00003 This source file is part of OGRE
00004 (Object-oriented Graphics Rendering Engine)
00005 For the latest info, see http://ogre.sourceforge.net/
00006 
00007 Copyright © 2000-2002 The OGRE Team
00008 Also see acknowledgements in Readme.html
00009 
00010 This program is free software; you can redistribute it and/or modify it under
00011 the terms of the GNU Lesser General Public License as published by the Free Software
00012 Foundation; either version 2 of the License, or (at your option) any later
00013 version.
00014 
00015 This program is distributed in the hope that it will be useful, but WITHOUT
00016 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00017 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
00018 
00019 You should have received a copy of the GNU Lesser General Public License along with
00020 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
00021 Place - Suite 330, Boston, MA 02111-1307, USA, or go to
00022 http://www.gnu.org/copyleft/lesser.txt.
00023 -----------------------------------------------------------------------------
00024 */
00025 #include "OgreStableHeaders.h"
00026 
00027 #include "OgreMaterialSerializer.h"
00028 #include "OgreStringConverter.h"
00029 #include "OgreLogManager.h"
00030 #include "OgreException.h"
00031 #include "OgreTechnique.h"
00032 #include "OgrePass.h"
00033 #include "OgreTextureUnitState.h"
00034 #include "OgreMaterialManager.h"
00035 #include "OgreGpuProgramManager.h"
00036 #include "OgreHighLevelGpuProgramManager.h"
00037 #include "OgreExternalTextureSourceManager.h"
00038 
00039 namespace Ogre 
00040 {
00041 
00042     //-----------------------------------------------------------------------
00043     // Internal parser methods
00044     //-----------------------------------------------------------------------
00045     void logParseError(const String& error, const MaterialScriptContext& context)
00046     {
00047         // log material name only if filename not specified
00048         if (context.filename.empty() && context.material)
00049         {
00050             LogManager::getSingleton().logMessage(
00051                 "Error in material " + context.material->getName() + 
00052                 " : " + error);
00053         }
00054         else
00055         {
00056             if (context.material)
00057             {
00058                 LogManager::getSingleton().logMessage(
00059                     "Error in material " + context.material->getName() +
00060                     " at line " + StringConverter::toString(context.lineNo) + 
00061                     " of " + context.filename + ": " + error);
00062             }
00063             else
00064             {
00065                 LogManager::getSingleton().logMessage(
00066                     "Error at line " + StringConverter::toString(context.lineNo) + 
00067                     " of " + context.filename + ": " + error);
00068             }
00069         }
00070     }
00071     //-----------------------------------------------------------------------
00072     ColourValue _parseColourValue(StringVector& vecparams)
00073     {
00074         return ColourValue(
00075             StringConverter::parseReal(vecparams[0]) ,
00076             StringConverter::parseReal(vecparams[1]) ,
00077             StringConverter::parseReal(vecparams[2]) ,
00078             (vecparams.size()==4) ? StringConverter::parseReal(vecparams[3]) : 1.0f ) ;
00079     }
00080     //-----------------------------------------------------------------------
00081     FilterOptions convertFiltering(const String& s)
00082     {
00083         if (s == "none")
00084         {
00085             return FO_NONE;
00086         }
00087         else if (s == "point")
00088         {
00089             return FO_POINT;
00090         }
00091         else if (s == "linear")
00092         {
00093             return FO_LINEAR;
00094         }
00095         else if (s == "anisotropic")
00096         {
00097             return FO_ANISOTROPIC;
00098         }
00099 
00100         return FO_POINT;
00101     }
00102     //-----------------------------------------------------------------------
00103     bool parseAmbient(String& params, MaterialScriptContext& context)
00104     {
00105         StringVector vecparams = StringUtil::split(params, " \t");
00106         // Must be 3 or 4 parameters 
00107         if (vecparams.size() != 3 && vecparams.size() != 4)
00108         {
00109             logParseError(
00110                 "Bad ambient attribute, wrong number of parameters (expected 3 or 4)", 
00111                 context);
00112         }
00113         else
00114         {
00115             context.pass->setAmbient( _parseColourValue(vecparams) );
00116         }
00117         return false;
00118     }
00119     //-----------------------------------------------------------------------
00120     bool parseDiffuse(String& params, MaterialScriptContext& context)
00121     {
00122         StringVector vecparams = StringUtil::split(params, " \t");
00123         // Must be 3 or 4 parameters 
00124         if (vecparams.size() != 3 && vecparams.size() != 4)
00125         {
00126             logParseError(
00127                 "Bad diffuse attribute, wrong number of parameters (expected 3 or 4)", 
00128                 context);
00129         }
00130         else
00131         {
00132             context.pass->setDiffuse( _parseColourValue(vecparams) );
00133         }
00134         return false;
00135     }
00136     //-----------------------------------------------------------------------
00137     bool parseSpecular(String& params, MaterialScriptContext& context)
00138     {
00139         StringVector vecparams = StringUtil::split(params, " \t");
00140         // Must be 4 or 5 parameters 
00141         if (vecparams.size() != 4 && vecparams.size() != 5)
00142         {
00143             logParseError(
00144                 "Bad specular attribute, wrong number of parameters (expected 4 or 5)",
00145                 context);
00146         }
00147         else
00148         {
00149             context.pass->setSpecular(
00150                 StringConverter::parseReal(vecparams[0]), 
00151                 StringConverter::parseReal(vecparams[1]), 
00152                 StringConverter::parseReal(vecparams[2]), 
00153                 vecparams.size() == 5? 
00154                     StringConverter::parseReal(vecparams[3]) : 1.0f);
00155             context.pass->setShininess(
00156                 StringConverter::parseReal(vecparams[vecparams.size() - 1]) );
00157         }
00158         return false;
00159     }
00160     //-----------------------------------------------------------------------
00161     bool parseEmissive(String& params, MaterialScriptContext& context)
00162     {
00163         StringVector vecparams = StringUtil::split(params, " \t");
00164         // Must be 3 or 4 parameters 
00165         if (vecparams.size() != 3 && vecparams.size() != 4)
00166         {
00167             logParseError(
00168                 "Bad emissive attribute, wrong number of parameters (expected 3 or 4)", 
00169                 context);
00170         }
00171         else
00172         {
00173             context.pass->setSelfIllumination( _parseColourValue(vecparams) );
00174         }
00175         return false;
00176     }
00177     //-----------------------------------------------------------------------
00178     SceneBlendFactor convertBlendFactor(const String& param)
00179     {
00180         if (param == "one")
00181             return SBF_ONE;
00182         else if (param == "zero")
00183             return SBF_ZERO;
00184         else if (param == "dest_colour")
00185             return SBF_DEST_COLOUR;
00186         else if (param == "src_colour")
00187             return SBF_SOURCE_COLOUR;
00188         else if (param == "one_minus_dest_colour")
00189             return SBF_ONE_MINUS_DEST_COLOUR;
00190         else if (param == "one_minus_src_colour")
00191             return SBF_ONE_MINUS_SOURCE_COLOUR;
00192         else if (param == "dest_alpha")
00193             return SBF_DEST_ALPHA;
00194         else if (param == "src_alpha")
00195             return SBF_SOURCE_ALPHA;
00196         else if (param == "one_minus_dest_alpha")
00197             return SBF_ONE_MINUS_DEST_ALPHA;
00198         else if (param == "one_minus_src_alpha")
00199             return SBF_ONE_MINUS_SOURCE_ALPHA;
00200         else
00201         {
00202             Except(Exception::ERR_INVALIDPARAMS, "Invalid blend factor.", "convertBlendFactor");
00203         }
00204 
00205 
00206     }
00207     //-----------------------------------------------------------------------
00208     bool parseSceneBlend(String& params, MaterialScriptContext& context)
00209     {
00210         StringUtil::toLowerCase(params);
00211         StringVector vecparams = StringUtil::split(params, " \t");
00212         // Should be 1 or 2 params 
00213         if (vecparams.size() == 1)
00214         {
00215             //simple
00216             SceneBlendType stype;
00217             if (vecparams[0] == "add")
00218                 stype = SBT_ADD;
00219             else if (vecparams[0] == "modulate")
00220                 stype = SBT_TRANSPARENT_COLOUR;
00221             else if (vecparams[0] == "alpha_blend")
00222                 stype = SBT_TRANSPARENT_ALPHA;
00223             else
00224             {
00225                 logParseError(
00226                     "Bad scene_blend attribute, unrecognised parameter '" + vecparams[0] + "'",
00227                     context);
00228                 return false;
00229             }
00230             context.pass->setSceneBlending(stype);
00231 
00232         }
00233         else if (vecparams.size() == 2)
00234         {
00235             //src/dest
00236             SceneBlendFactor src, dest;
00237 
00238             try {
00239                 src = convertBlendFactor(vecparams[0]);
00240                 dest = convertBlendFactor(vecparams[1]);
00241                 context.pass->setSceneBlending(src,dest);
00242             }
00243             catch (Exception& e)
00244             {
00245                 logParseError("Bad scene_blend attribute, " + e.getFullDescription(), context);
00246             }
00247 
00248         }
00249         else
00250         {
00251             logParseError(
00252                 "Bad scene_blend attribute, wrong number of parameters (expected 1 or 2)", 
00253                 context);
00254         }
00255 
00256         return false;
00257 
00258     }
00259     //-----------------------------------------------------------------------
00260     CompareFunction convertCompareFunction(const String& param)
00261     {
00262         if (param == "always_fail")
00263             return CMPF_ALWAYS_FAIL;
00264         else if (param == "always_pass")
00265             return CMPF_ALWAYS_PASS;
00266         else if (param == "less")
00267             return CMPF_LESS;
00268         else if (param == "less_equal")
00269             return CMPF_LESS_EQUAL;
00270         else if (param == "equal")
00271             return CMPF_EQUAL;
00272         else if (param == "not_equal")
00273             return CMPF_NOT_EQUAL;
00274         else if (param == "greater_equal")
00275             return CMPF_GREATER_EQUAL;
00276         else if (param == "greater")
00277             return CMPF_GREATER;
00278         else
00279             Except(Exception::ERR_INVALIDPARAMS, "Invalid compare function", "convertCompareFunction");
00280 
00281     }
00282     //-----------------------------------------------------------------------
00283     bool parseDepthCheck(String& params, MaterialScriptContext& context)
00284     {
00285         StringUtil::toLowerCase(params);
00286         if (params == "on")
00287             context.pass->setDepthCheckEnabled(true);
00288         else if (params == "off")
00289             context.pass->setDepthCheckEnabled(false);
00290         else
00291             logParseError(
00292             "Bad depth_check attribute, valid parameters are 'on' or 'off'.", 
00293             context);
00294 
00295         return false;
00296     }
00297     //-----------------------------------------------------------------------
00298     bool parseDepthWrite(String& params, MaterialScriptContext& context)
00299     {
00300         StringUtil::toLowerCase(params);
00301         if (params == "on")
00302             context.pass->setDepthWriteEnabled(true);
00303         else if (params == "off")
00304             context.pass->setDepthWriteEnabled(false);
00305         else
00306             logParseError(
00307                 "Bad depth_write attribute, valid parameters are 'on' or 'off'.", 
00308                 context);
00309         return false;
00310     }
00311 
00312     //-----------------------------------------------------------------------
00313     bool parseDepthFunc(String& params, MaterialScriptContext& context)
00314     {
00315         StringUtil::toLowerCase(params);
00316         try {
00317             CompareFunction func = convertCompareFunction(params);
00318             context.pass->setDepthFunction(func);
00319         }
00320         catch (...)
00321         {
00322             logParseError("Bad depth_func attribute, invalid function parameter.", context);
00323         }
00324 
00325         return false;
00326     }
00327     //-----------------------------------------------------------------------
00328     bool parseColourWrite(String& params, MaterialScriptContext& context)
00329     {
00330         StringUtil::toLowerCase(params);
00331         if (params == "on")
00332             context.pass->setColourWriteEnabled(true);
00333         else if (params == "off")
00334             context.pass->setColourWriteEnabled(false);
00335         else
00336             logParseError(
00337                 "Bad colour_write attribute, valid parameters are 'on' or 'off'.", 
00338                 context);
00339         return false;
00340     }
00341 
00342     //-----------------------------------------------------------------------
00343     bool parseCullHardware(String& params, MaterialScriptContext& context)
00344     {
00345         StringUtil::toLowerCase(params);
00346         if (params=="none")
00347             context.pass->setCullingMode(CULL_NONE);
00348         else if (params=="anticlockwise")
00349             context.pass->setCullingMode(CULL_ANTICLOCKWISE);
00350         else if (params=="clockwise")
00351             context.pass->setCullingMode(CULL_CLOCKWISE);
00352         else
00353             logParseError(
00354                 "Bad cull_hardware attribute, valid parameters are "
00355                 "'none', 'clockwise' or 'anticlockwise'.", context);
00356         return false;
00357     }
00358     //-----------------------------------------------------------------------
00359     bool parseCullSoftware(String& params, MaterialScriptContext& context)
00360     {
00361         StringUtil::toLowerCase(params);
00362         if (params=="none")
00363             context.pass->setManualCullingMode(MANUAL_CULL_NONE);
00364         else if (params=="back")
00365             context.pass->setManualCullingMode(MANUAL_CULL_BACK);
00366         else if (params=="front")
00367             context.pass->setManualCullingMode(MANUAL_CULL_FRONT);
00368         else
00369             logParseError(
00370                 "Bad cull_software attribute, valid parameters are 'none', "
00371                 "'front' or 'back'.", context);
00372         return false;
00373     }
00374     //-----------------------------------------------------------------------
00375     bool parseLighting(String& params, MaterialScriptContext& context)
00376     {
00377         StringUtil::toLowerCase(params);
00378         if (params=="on")
00379             context.pass->setLightingEnabled(true);
00380         else if (params=="off")
00381             context.pass->setLightingEnabled(false);
00382         else
00383             logParseError(
00384                 "Bad lighting attribute, valid parameters are 'on' or 'off'.", context);
00385         return false;
00386     }
00387     //-----------------------------------------------------------------------
00388     bool parseMaxLights(String& params, MaterialScriptContext& context)
00389     {
00390         context.pass->setMaxSimultaneousLights(StringConverter::parseInt(params));
00391         return false;
00392     }
00393     //-----------------------------------------------------------------------
00394     bool parseIteration(String& params, MaterialScriptContext& context)
00395     {
00396         StringUtil::toLowerCase(params);
00397         StringVector vecparams = StringUtil::split(params, " \t");
00398         if (vecparams.size() != 1 && vecparams.size() != 2)
00399         {
00400             logParseError("Bad iteration attribute, expected 1 or 2 parameters.", context);
00401             return false;
00402         }
00403 
00404         if (vecparams[0]=="once")
00405             context.pass->setRunOncePerLight(false);
00406         else if (vecparams[0]=="once_per_light")
00407         {
00408             if (vecparams.size() == 2)
00409             {
00410                 // Parse light type
00411                 if (vecparams[1] == "directional")
00412                 {
00413                     context.pass->setRunOncePerLight(true, true, Light::LT_DIRECTIONAL);
00414                 }
00415                 else if (vecparams[1] == "point")
00416                 {
00417                     context.pass->setRunOncePerLight(true, true, Light::LT_POINT);
00418                 }
00419                 else if (vecparams[1] == "spot")
00420                 {
00421                     context.pass->setRunOncePerLight(true, true, Light::LT_SPOTLIGHT);
00422                 }
00423                 else
00424                 {
00425                     logParseError("Bad iteration attribute, valid values for second parameter "
00426                         "are 'point' or 'directional' or 'spot'.", context);
00427                 }
00428             }
00429             else
00430             {
00431                 context.pass->setRunOncePerLight(true, false);
00432             }
00433 
00434         }
00435         else
00436             logParseError(
00437                 "Bad iteration attribute, valid parameters are 'once' or 'once_per_light'.", context);
00438         return false;
00439     }
00440     //-----------------------------------------------------------------------
00441     bool parseFogging(String& params, MaterialScriptContext& context)
00442     {
00443         StringUtil::toLowerCase(params);
00444         StringVector vecparams = StringUtil::split(params, " \t");
00445         if (vecparams[0]=="true")
00446         {
00447             // if true, we need to see if they supplied all arguments, or just the 1... if just the one,
00448             // Assume they want to disable the default fog from effecting this material.
00449             if( vecparams.size() == 8 )
00450             {
00451                 FogMode mFogtype;
00452                 if( vecparams[1] == "none" )
00453                     mFogtype = FOG_NONE;
00454                 else if( vecparams[1] == "linear" )
00455                     mFogtype = FOG_LINEAR;
00456                 else if( vecparams[1] == "exp" )
00457                     mFogtype = FOG_EXP;
00458                 else if( vecparams[1] == "exp2" )
00459                     mFogtype = FOG_EXP2;
00460                 else
00461                 {
00462                     logParseError(
00463                         "Bad fogging attribute, valid parameters are "
00464                         "'none', 'linear', 'exp', or 'exp2'.", context);
00465                     return false;
00466                 }
00467 
00468                 context.pass->setFog(
00469                     true,
00470                     mFogtype,
00471                     ColourValue(
00472                     StringConverter::parseReal(vecparams[2]),
00473                     StringConverter::parseReal(vecparams[3]),
00474                     StringConverter::parseReal(vecparams[4])),
00475                     StringConverter::parseReal(vecparams[5]),
00476                     StringConverter::parseReal(vecparams[6]),
00477                     StringConverter::parseReal(vecparams[7])
00478                     );
00479             }
00480             else
00481             {
00482                 context.pass->setFog(true);
00483             }
00484         }
00485         else if (vecparams[0]=="false")
00486             context.pass->setFog(false);
00487         else
00488             logParseError(
00489                 "Bad fog_override attribute, valid parameters are 'true' or 'false'.", 
00490                 context);
00491 
00492         return false;
00493     }
00494     //-----------------------------------------------------------------------
00495     bool parseShading(String& params, MaterialScriptContext& context)
00496     {
00497         StringUtil::toLowerCase(params);
00498         if (params=="flat")
00499             context.pass->setShadingMode(SO_FLAT);
00500         else if (params=="gouraud")
00501             context.pass->setShadingMode(SO_GOURAUD);
00502         else if (params=="phong")
00503             context.pass->setShadingMode(SO_PHONG);
00504         else
00505             logParseError("Bad shading attribute, valid parameters are 'flat', "
00506                 "'gouraud' or 'phong'.", context);
00507 
00508         return false;
00509     }
00510     //-----------------------------------------------------------------------
00511     bool parseFiltering(String& params, MaterialScriptContext& context)
00512     {
00513         StringUtil::toLowerCase(params);
00514         StringVector vecparams = StringUtil::split(params, " \t");
00515         // Must be 1 or 3 parameters 
00516         if (vecparams.size() == 1)
00517         {
00518             // Simple format
00519             if (vecparams[0]=="none")
00520                 context.textureUnit->setTextureFiltering(TFO_NONE);
00521             else if (vecparams[0]=="bilinear")
00522                 context.textureUnit->setTextureFiltering(TFO_BILINEAR);
00523             else if (vecparams[0]=="trilinear")
00524                 context.textureUnit->setTextureFiltering(TFO_TRILINEAR);
00525             else if (vecparams[0]=="anisotropic")
00526                 context.textureUnit->setTextureFiltering(TFO_ANISOTROPIC);
00527             else
00528             {
00529                 logParseError("Bad filtering attribute, valid parameters for simple format are "
00530                     "'none', 'bilinear', 'trilinear' or 'anisotropic'.", context);
00531                 return false;
00532             }
00533         }
00534         else if (vecparams.size() == 3)
00535         {
00536             // Complex format
00537             context.textureUnit->setTextureFiltering(
00538                 convertFiltering(vecparams[0]), 
00539                 convertFiltering(vecparams[1]), 
00540                 convertFiltering(vecparams[2]));
00541 
00542 
00543         }
00544         else
00545         {
00546             logParseError(
00547                 "Bad filtering attribute, wrong number of parameters (expected 1 or 3)", 
00548                 context);
00549         }
00550 
00551         return false;
00552     }
00553     //-----------------------------------------------------------------------
00554     // Texture layer attributes
00555     bool parseTexture(String& params, MaterialScriptContext& context)
00556     {
00557         StringVector vecparams = StringUtil::split(params, " \t");
00558         if (vecparams.size() > 2)
00559         {
00560             logParseError("Invalid texture attribute - expected only 1 or 2 parameters.", 
00561                 context);
00562         }
00563         TextureType tt = TEX_TYPE_2D;
00564         if (vecparams.size() == 2)
00565         {
00566             StringUtil::toLowerCase(vecparams[1]);
00567             if (vecparams[1] == "1d")
00568             {
00569                 tt = TEX_TYPE_1D;
00570             }
00571             else if (vecparams[1] == "2d")
00572             {
00573                 tt = TEX_TYPE_2D;
00574             }
00575             else if (vecparams[1] == "3d")
00576             {
00577                 tt = TEX_TYPE_3D;
00578             }
00579             else if (vecparams[1] == "cubic")
00580             {
00581                 tt = TEX_TYPE_CUBE_MAP;
00582             }
00583         }
00584         context.textureUnit->setTextureName(vecparams[0], tt);
00585         return false;
00586     }
00587     //-----------------------------------------------------------------------
00588     bool parseAnimTexture(String& params, MaterialScriptContext& context)
00589     {
00590         StringVector vecparams = StringUtil::split(params, " \t");
00591         size_t numParams = vecparams.size();
00592         // Determine which form it is
00593         // Must have at least 3 params though
00594         if (numParams < 3)
00595         {
00596             logParseError("Bad anim_texture attribute, wrong number of parameters "
00597                 "(expected at least 3)", context);
00598             return false;
00599         }
00600         if (numParams == 3 && StringConverter::parseInt(vecparams[1]) != 0 )
00601         {
00602             // First form using base name & number of frames
00603             context.textureUnit->setAnimatedTextureName(
00604                 vecparams[0], 
00605                 StringConverter::parseInt(vecparams[1]), 
00606                 StringConverter::parseReal(vecparams[2]));
00607         }
00608         else
00609         {
00610             // Second form using individual names
00611             context.textureUnit->setAnimatedTextureName(
00612                 (String*)&vecparams[0], 
00613                 numParams-1, 
00614                 StringConverter::parseReal(vecparams[numParams-1]));
00615         }
00616         return false;
00617 
00618     }
00619     //-----------------------------------------------------------------------
00620     bool parseCubicTexture(String& params, MaterialScriptContext& context)
00621     {
00622 
00623         StringVector vecparams = StringUtil::split(params, " \t");
00624         size_t numParams = vecparams.size();
00625 
00626         // Get final param
00627         bool useUVW;
00628         String& uvOpt = vecparams[numParams-1];
00629         StringUtil::toLowerCase(uvOpt);
00630         if (uvOpt == "combineduvw")
00631             useUVW = true;
00632         else if (uvOpt == "separateuv")
00633             useUVW = false;
00634         else
00635         {
00636             logParseError("Bad cubic_texture attribute, final parameter must be "
00637                 "'combinedUVW' or 'separateUV'.", context);
00638             return false;
00639         }
00640         // Determine which form it is
00641         if (numParams == 2)
00642         {
00643             // First form using base name
00644             context.textureUnit->setCubicTextureName(vecparams[0], useUVW);
00645         }
00646         else if (numParams == 7)
00647         {
00648             // Second form using individual names
00649             // Can use vecparams[0] as array start point
00650             context.textureUnit->setCubicTextureName((String*)&vecparams[0], useUVW);
00651         }
00652         else
00653         {
00654             logParseError(
00655                 "Bad cubic_texture attribute, wrong number of parameters (expected 2 or 7)", 
00656                 context);
00657             return false;
00658         }
00659 
00660         return false;
00661     }
00662     //-----------------------------------------------------------------------
00663     bool parseTexCoord(String& params, MaterialScriptContext& context)
00664     {
00665         context.textureUnit->setTextureCoordSet(
00666             StringConverter::parseInt(params));
00667 
00668         return false;
00669     }
00670     //-----------------------------------------------------------------------
00671     bool parseTexAddressMode(String& params, MaterialScriptContext& context)
00672     {
00673         StringUtil::toLowerCase(params);
00674         if (params=="wrap")
00675             context.textureUnit->setTextureAddressingMode(TextureUnitState::TAM_WRAP);
00676         else if (params=="mirror")
00677             context.textureUnit->setTextureAddressingMode(TextureUnitState::TAM_MIRROR);
00678         else if (params=="clamp")
00679             context.textureUnit->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
00680         else
00681             logParseError("Bad tex_address_mode attribute, valid parameters are "
00682                 "'wrap', 'clamp' or 'mirror'.", context);
00683 
00684         return false;
00685     }
00686     //-----------------------------------------------------------------------
00687     bool parseColourOp(String& params, MaterialScriptContext& context)
00688     {
00689         StringUtil::toLowerCase(params);
00690         if (params=="replace")
00691             context.textureUnit->setColourOperation(LBO_REPLACE);
00692         else if (params=="add")
00693             context.textureUnit->setColourOperation(LBO_ADD);
00694         else if (params=="modulate")
00695             context.textureUnit->setColourOperation(LBO_MODULATE);
00696         else if (params=="alpha_blend")
00697             context.textureUnit->setColourOperation(LBO_ALPHA_BLEND);
00698         else
00699             logParseError("Bad colour_op attribute, valid parameters are "
00700                 "'replace', 'add', 'modulate' or 'alpha_blend'.", context);
00701 
00702         return false;
00703     }
00704     //-----------------------------------------------------------------------
00705     bool parseAlphaRejection(String& params, MaterialScriptContext& context)
00706     {
00707         StringUtil::toLowerCase(params);
00708         StringVector vecparams = StringUtil::split(params, " \t");
00709         if (vecparams.size() != 2)
00710         {
00711             logParseError(
00712                 "Bad alpha_rejection attribute, wrong number of parameters (expected 2)", 
00713                 context);
00714             return false;
00715         }
00716 
00717         CompareFunction cmp;
00718         try {
00719             cmp = convertCompareFunction(vecparams[0]);
00720         }
00721         catch (...)
00722         {
00723             logParseError("Bad alpha_rejection attribute, invalid compare function.", context);
00724             return false;
00725         }
00726 
00727         context.textureUnit->setAlphaRejectSettings(cmp, StringConverter::parseInt(vecparams[1]));
00728 
00729         return false;
00730     }
00731     //-----------------------------------------------------------------------
00732     LayerBlendOperationEx convertBlendOpEx(const String& param)
00733     {
00734         if (param == "source1")
00735             return LBX_SOURCE1;
00736         else if (param == "source2")
00737             return LBX_SOURCE2;
00738         else if (param == "modulate")
00739             return LBX_MODULATE;
00740         else if (param == "modulate_x2")
00741             return LBX_MODULATE_X2;
00742         else if (param == "modulate_x4")
00743             return LBX_MODULATE_X4;
00744         else if (param == "add")
00745             return LBX_ADD;
00746         else if (param == "add_signed")
00747             return LBX_ADD_SIGNED;
00748         else if (param == "add_smooth")
00749             return LBX_ADD_SMOOTH;
00750         else if (param == "subtract")
00751             return LBX_SUBTRACT;
00752         else if (param == "blend_diffuse_alpha")
00753             return LBX_BLEND_DIFFUSE_ALPHA;
00754         else if (param == "blend_texture_alpha")
00755             return LBX_BLEND_TEXTURE_ALPHA;
00756         else if (param == "blend_current_alpha")
00757             return LBX_BLEND_CURRENT_ALPHA;
00758         else if (param == "blend_manual")
00759             return LBX_BLEND_MANUAL;
00760         else if (param == "dotproduct")
00761             return LBX_DOTPRODUCT;
00762         else
00763             Except(Exception::ERR_INVALIDPARAMS, "Invalid blend function", "convertBlendOpEx");
00764     }
00765     //-----------------------------------------------------------------------
00766     LayerBlendSource convertBlendSource(const String& param)
00767     {
00768         if (param == "src_current")
00769             return LBS_CURRENT;
00770         else if (param == "src_texture")
00771             return LBS_TEXTURE;
00772         else if (param == "src_diffuse")
00773             return LBS_DIFFUSE;
00774         else if (param == "src_specular")
00775             return LBS_SPECULAR;
00776         else if (param == "src_manual")
00777             return LBS_MANUAL;
00778         else
00779             Except(Exception::ERR_INVALIDPARAMS, "Invalid blend source", "convertBlendSource");
00780     }
00781     //-----------------------------------------------------------------------
00782     bool parseColourOpEx(String& params, MaterialScriptContext& context)
00783     {
00784         StringUtil::toLowerCase(params);
00785         StringVector vecparams = StringUtil::split(params, " \t");
00786         size_t numParams = vecparams.size();
00787 
00788         if (numParams < 3 || numParams > 10)
00789         {
00790             logParseError(
00791                 "Bad colour_op_ex attribute, wrong number of parameters (expected 3 to 10)", 
00792                 context);
00793             return false;
00794         }
00795         LayerBlendOperationEx op;
00796         LayerBlendSource src1, src2;
00797         Real manual = 0.0;
00798         ColourValue colSrc1 = ColourValue::White;
00799         ColourValue colSrc2 = ColourValue::White;
00800 
00801         try {
00802             op = convertBlendOpEx(vecparams[0]);
00803             src1 = convertBlendSource(vecparams[1]);
00804             src2 = convertBlendSource(vecparams[2]);
00805 
00806             if (op == LBX_BLEND_MANUAL)
00807             {
00808                 if (numParams < 4)
00809                 {
00810                     logParseError("Bad colour_op_ex attribute, wrong number of parameters "
00811                         "(expected 4 for manual blend)", context);
00812                     return false;
00813                 }
00814                 manual = StringConverter::parseReal(vecparams[3]);
00815             }
00816 
00817             if (src1 == LBS_MANUAL)
00818             {
00819                 unsigned int parIndex = 3;
00820                 if (op == LBX_BLEND_MANUAL)
00821                     parIndex++;
00822 
00823                 if (numParams < parIndex + 3)
00824                 {
00825                     logParseError("Bad colour_op_ex attribute, wrong number of parameters "
00826                         "(expected " + StringConverter::toString(parIndex + 3) + ")", context);
00827                     return false;
00828                 }
00829 
00830                 colSrc1.r = StringConverter::parseReal(vecparams[parIndex++]);
00831                 colSrc1.g = StringConverter::parseReal(vecparams[parIndex++]);
00832                 colSrc1.b = StringConverter::parseReal(vecparams[parIndex++]);
00833                 if (numParams > parIndex)
00834                 {
00835                     colSrc1.a = StringConverter::parseReal(vecparams[parIndex]);
00836                 }
00837                 else
00838                 {
00839                     colSrc1.a = 1.0f;
00840                 }
00841             }
00842 
00843             if (src2 == LBS_MANUAL)
00844             {
00845                 unsigned int parIndex = 3;
00846                 if (op == LBX_BLEND_MANUAL)
00847                     parIndex++;
00848                 if (src1 == LBS_MANUAL)
00849                     parIndex += 3;
00850 
00851                 if (numParams < parIndex + 3)
00852                 {
00853                     logParseError("Bad colour_op_ex attribute, wrong number of parameters "
00854                         "(expected " + StringConverter::toString(parIndex + 3) + ")", context);
00855                     return false;
00856                 }
00857 
00858                 colSrc2.r = StringConverter::parseReal(vecparams[parIndex++]);
00859                 colSrc2.g = StringConverter::parseReal(vecparams[parIndex++]);
00860                 colSrc2.b = StringConverter::parseReal(vecparams[parIndex++]);
00861                 if (numParams > parIndex)
00862                 {
00863                     colSrc2.a = StringConverter::parseReal(vecparams[parIndex]);
00864                 }
00865                 else
00866                 {
00867                     colSrc2.a = 1.0f;
00868                 }
00869             }
00870         }
00871         catch (Exception& e)
00872         {
00873             logParseError("Bad colour_op_ex attribute, " + e.getFullDescription(), context);
00874             return false;
00875         }
00876 
00877         context.textureUnit->setColourOperationEx(op, src1, src2, colSrc1, colSrc2, manual);
00878         return false;
00879     }
00880     //-----------------------------------------------------------------------
00881     bool parseColourOpFallback(String& params, MaterialScriptContext& context)
00882     {
00883         StringUtil::toLowerCase(params);
00884         StringVector vecparams = StringUtil::split(params, " \t");
00885         if (vecparams.size() != 2)
00886         {
00887             logParseError("Bad colour_op_multipass_fallback attribute, wrong number "
00888                 "of parameters (expected 2)", context);
00889             return false;
00890         }
00891 
00892         //src/dest
00893         SceneBlendFactor src, dest;
00894 
00895         try {
00896             src = convertBlendFactor(vecparams[0]);
00897             dest = convertBlendFactor(vecparams[1]);
00898             context.textureUnit->setColourOpMultipassFallback(src,dest);
00899         }
00900         catch (Exception& e)
00901         {
00902             logParseError("Bad colour_op_multipass_fallback attribute, " 
00903                 + e.getFullDescription(), context);
00904         }
00905         return false;
00906     }
00907     //-----------------------------------------------------------------------
00908     bool parseAlphaOpEx(String& params, MaterialScriptContext& context)
00909     {
00910         StringUtil::toLowerCase(params);
00911         StringVector vecparams = StringUtil::split(params, " \t");
00912         size_t numParams = vecparams.size();
00913         if (numParams < 3 || numParams > 6)
00914         {
00915             logParseError("Bad alpha_op_ex attribute, wrong number of parameters "
00916                 "(expected 3 to 6)", context);
00917             return false;
00918         }
00919         LayerBlendOperationEx op;
00920         LayerBlendSource src1, src2;
00921         Real manual = 0.0;
00922         Real arg1 = 1.0, arg2 = 1.0;
00923 
00924         try {
00925             op = convertBlendOpEx(vecparams[0]);
00926             src1 = convertBlendSource(vecparams[1]);
00927             src2 = convertBlendSource(vecparams[2]);
00928             if (op == LBX_BLEND_MANUAL)
00929             {
00930                 if (numParams != 4)
00931                 {
00932                     logParseError("Bad alpha_op_ex attribute, wrong number of parameters "
00933                         "(expected 4 for manual blend)", context);
00934                     return false;
00935                 }
00936                 manual = StringConverter::parseReal(vecparams[4]);
00937             }
00938             if (src1 == LBS_MANUAL)
00939             {
00940                 unsigned int parIndex = 3;
00941                 if (op == LBX_BLEND_MANUAL)
00942                     parIndex++;
00943 
00944                 if (numParams < parIndex)
00945                 {
00946                     logParseError(
00947                         "Bad alpha_op_ex attribute, wrong number of parameters (expected " + 
00948                         StringConverter::toString(parIndex - 1) + ")", context);
00949                     return false;
00950                 }
00951 
00952                 arg1 = StringConverter::parseReal(vecparams[parIndex]);
00953             }
00954 
00955             if (src2 == LBS_MANUAL)
00956             {
00957                 unsigned int parIndex = 3;
00958                 if (op == LBX_BLEND_MANUAL)
00959                     parIndex++;
00960                 if (src1 == LBS_MANUAL)
00961                     parIndex++;
00962 
00963                 if (numParams < parIndex)
00964                 {
00965                     logParseError(
00966                         "Bad alpha_op_ex attribute, wrong number of parameters "
00967                         "(expected " + StringConverter::toString(parIndex - 1) + ")", context);
00968                     return false;
00969                 }
00970 
00971                 arg2 = StringConverter::parseReal(vecparams[parIndex]);
00972             }
00973         }
00974         catch (Exception& e)
00975         {
00976             logParseError("Bad alpha_op_ex attribute, " + e.getFullDescription(), context);
00977             return false;
00978         }
00979 
00980         context.textureUnit->setAlphaOperation(op, src1, src2, arg1, arg2, manual);
00981         return false;
00982     }
00983     //-----------------------------------------------------------------------
00984     bool parseEnvMap(String& params, MaterialScriptContext& context)
00985     {
00986         StringUtil::toLowerCase(params);
00987         if (params=="off")
00988             context.textureUnit->setEnvironmentMap(false);
00989         else if (params=="spherical")
00990             context.textureUnit->setEnvironmentMap(true, TextureUnitState::ENV_CURVED);
00991         else if (params=="planar")
00992             context.textureUnit->setEnvironmentMap(true, TextureUnitState::ENV_PLANAR);
00993         else if (params=="cubic_reflection")
00994             context.textureUnit->setEnvironmentMap(true, TextureUnitState::ENV_REFLECTION);
00995         else if (params=="cubic_normal")
00996             context.textureUnit->setEnvironmentMap(true, TextureUnitState::ENV_NORMAL);
00997         else
00998             logParseError("Bad env_map attribute, valid parameters are 'off', "
00999                 "'spherical', 'planar', 'cubic_reflection' and 'cubic_normal'.", context);
01000 
01001         return false;
01002     }
01003     //-----------------------------------------------------------------------
01004     bool parseScroll(String& params, MaterialScriptContext& context)
01005     {
01006         StringVector vecparams = StringUtil::split(params, " \t");
01007         if (vecparams.size() != 2)
01008         {
01009             logParseError("Bad scroll attribute, wrong number of parameters (expected 2)", context);
01010             return false;
01011         }
01012         context.textureUnit->setTextureScroll(
01013             StringConverter::parseReal(vecparams[0]), 
01014             StringConverter::parseReal(vecparams[1]));
01015 
01016     
01017         return false;
01018     }
01019     //-----------------------------------------------------------------------
01020     bool parseScrollAnim(String& params, MaterialScriptContext& context)
01021     {
01022         StringVector vecparams = StringUtil::split(params, " \t");
01023         if (vecparams.size() != 2)
01024         {
01025             logParseError("Bad scroll_anim attribute, wrong number of "
01026                 "parameters (expected 2)", context);
01027             return false;
01028         }
01029         context.textureUnit->setScrollAnimation(
01030             StringConverter::parseReal(vecparams[0]), 
01031             StringConverter::parseReal(vecparams[1]));
01032 
01033         return false;
01034     }
01035     //-----------------------------------------------------------------------
01036     bool parseRotate(String& params, MaterialScriptContext& context)
01037     {
01038         context.textureUnit->setTextureRotate(
01039             StringConverter::parseAngle(params));
01040 
01041         return false;
01042     }
01043     //-----------------------------------------------------------------------
01044     bool parseRotateAnim(String& params, MaterialScriptContext& context)
01045     {
01046         context.textureUnit->setRotateAnimation(
01047             StringConverter::parseReal(params));
01048 
01049         return false;
01050     }
01051     //-----------------------------------------------------------------------
01052     bool parseScale(String& params, MaterialScriptContext& context)
01053     {
01054         StringVector vecparams = StringUtil::split(params, " \t");
01055         if (vecparams.size() != 2)
01056         {
01057             logParseError("Bad scale attribute, wrong number of parameters (expected 2)", context);
01058             return false;
01059         }
01060         context.textureUnit->setTextureScale(
01061             StringConverter::parseReal(vecparams[0]), 
01062             StringConverter::parseReal(vecparams[1]));
01063 
01064         return false;
01065     }
01066     //-----------------------------------------------------------------------
01067     bool parseWaveXform(String& params, MaterialScriptContext& context)
01068     {
01069         StringUtil::toLowerCase(params);
01070         StringVector vecparams = StringUtil::split(params, " \t");
01071 
01072         if (vecparams.size() != 6)
01073         {
01074             logParseError("Bad wave_xform attribute, wrong number of parameters "
01075                 "(expected 6)", context);
01076             return false;
01077         }
01078         TextureUnitState::TextureTransformType ttype;
01079         WaveformType waveType;
01080         // Check transform type
01081         if (vecparams[0]=="scroll_x")
01082             ttype = TextureUnitState::TT_TRANSLATE_U;
01083         else if (vecparams[0]=="scroll_y")
01084             ttype = TextureUnitState::TT_TRANSLATE_V;
01085         else if (vecparams[0]=="rotate")
01086             ttype = TextureUnitState::TT_ROTATE;
01087         else if (vecparams[0]=="scale_x")
01088             ttype = TextureUnitState::TT_SCALE_U;
01089         else if (vecparams[0]=="scale_y")
01090             ttype = TextureUnitState::TT_SCALE_V;
01091         else
01092         {
01093             logParseError("Bad wave_xform attribute, parameter 1 must be 'scroll_x', "
01094                 "'scroll_y', 'rotate', 'scale_x' or 'scale_y'", context);
01095             return false;
01096         }
01097         // Check wave type
01098         if (vecparams[1]=="sine")
01099             waveType = WFT_SINE;
01100         else if (vecparams[1]=="triangle")
01101             waveType = WFT_TRIANGLE;
01102         else if (vecparams[1]=="square")
01103             waveType = WFT_SQUARE;
01104         else if (vecparams[1]=="sawtooth")
01105             waveType = WFT_SAWTOOTH;
01106         else if (vecparams[1]=="inverse_sawtooth")
01107             waveType = WFT_INVERSE_SAWTOOTH;
01108         else
01109         {
01110             logParseError("Bad wave_xform attribute, parameter 2 must be 'sine', "
01111                 "'triangle', 'square', 'sawtooth' or 'inverse_sawtooth'", context);
01112             return false;
01113         }
01114 
01115         context.textureUnit->setTransformAnimation(
01116             ttype, 
01117             waveType, 
01118             StringConverter::parseReal(vecparams[2]), 
01119             StringConverter::parseReal(vecparams[3]),
01120             StringConverter::parseReal(vecparams[4]), 
01121             StringConverter::parseReal(vecparams[5]) );
01122 
01123         return false;
01124     }
01125     //-----------------------------------------------------------------------
01126     bool parseDepthBias(String& params, MaterialScriptContext& context)
01127     {
01128         context.pass->setDepthBias(
01129             StringConverter::parseReal(params));
01130 
01131         return false;
01132     }
01133     //-----------------------------------------------------------------------
01134     bool parseAnisotropy(String& params, MaterialScriptContext& context)
01135     {
01136         context.textureUnit->setTextureAnisotropy(
01137             StringConverter::parseInt(params));
01138 
01139         return false;
01140     }
01141     //-----------------------------------------------------------------------
01142     bool parseLodDistances(String& params, MaterialScriptContext& context)
01143     {
01144         StringVector vecparams = StringUtil::split(params, " \t");
01145 
01146         // iterate over the parameters and parse distances out of them
01147         Material::LodDistanceList lodList;
01148         StringVector::iterator i, iend;
01149         iend = vecparams.end();
01150         for (i = vecparams.begin(); i != iend; ++i)
01151         {
01152             lodList.push_back(StringConverter::parseReal(*i));
01153         }
01154 
01155         context.material->setLodLevels(lodList);
01156 
01157         return false;
01158     }
01159     //-----------------------------------------------------------------------
01160     bool parseLodIndex(String& params, MaterialScriptContext& context)
01161     {
01162         context.technique->setLodIndex(StringConverter::parseInt(params));
01163         return false;
01164     }
01165     //-----------------------------------------------------------------------
01166     void processManualProgramParam(size_t index, const String& commandname, 
01167         StringVector& vecparams, MaterialScriptContext& context)
01168     {
01169         // NB we assume that the first element of vecparams is taken up with either 
01170         // the index or the parameter name, which we ignore
01171 
01172         // Determine type
01173         size_t start, dims, roundedDims, i;
01174         bool isReal;
01175 
01176         StringUtil::toLowerCase(vecparams[1]);
01177 
01178         if (vecparams[1] == "matrix4x4")
01179         {
01180             dims = 16;
01181             isReal = true;
01182         }
01183         else if ((start = vecparams[1].find("float")) != String::npos)
01184         {
01185             // find the dimensionality
01186             start = vecparams[1].find_first_not_of("float");
01187             // Assume 1 if not specified
01188             if (start == String::npos)
01189             {
01190                 dims = 1;
01191             }
01192             else
01193             {
01194                 dims = StringConverter::parseInt(vecparams[1].substr(start));
01195             }
01196             isReal = true;
01197         }
01198         else if ((start = vecparams[1].find("int")) != String::npos)
01199         {
01200             // find the dimensionality
01201             start = vecparams[1].find_first_not_of("int");
01202             // Assume 1 if not specified
01203             if (start == String::npos)
01204             {
01205                 dims = 1;
01206             }
01207             else
01208             {
01209                 dims = StringConverter::parseInt(vecparams[1].substr(start));
01210             }
01211             isReal = false;
01212         }
01213         else
01214         {
01215             logParseError("Invalid " + commandname + " attribute - unrecognised "
01216                 "parameter type " + vecparams[1], context);
01217             return;
01218         }
01219 
01220         if (vecparams.size() != 2 + dims)
01221         {
01222             logParseError("Invalid " + commandname + " attribute - you need " +
01223                 StringConverter::toString(2 + dims) + " parameters for a parameter of "
01224                 "type " + vecparams[1], context);
01225         }
01226 
01227         // Round dims to multiple of 4
01228         if (dims %4 != 0)
01229         {
01230             roundedDims = dims + 4 - (dims % 4);
01231         }
01232         else
01233         {
01234             roundedDims = dims;
01235         }
01236 
01237         // Now parse all the values
01238         if (isReal)
01239         {
01240             Real* realBuffer = new Real[roundedDims];
01241             // Do specified values
01242             for (i = 0; i < dims; ++i)
01243             {
01244                 realBuffer[i] = StringConverter::parseReal(vecparams[i+2]);
01245             }
01246             // Fill up to multiple of 4 with zero
01247             for (; i < roundedDims; ++i)
01248             {
01249                 realBuffer[i] = 0.0f;
01250             }
01251             // Set
01252             context.programParams->setConstant(index, realBuffer, roundedDims * 0.25);
01253             delete [] realBuffer;
01254         }
01255         else
01256         {
01257             int* intBuffer = new int[roundedDims];
01258             // Do specified values
01259             for (i = 0; i < dims; ++i)
01260             {
01261                 intBuffer[i] = StringConverter::parseInt(vecparams[i+2]);
01262             }
01263             // Fill to multiple of 4 with 0
01264             for (; i < roundedDims; ++i)
01265             {
01266                 intBuffer[i] = 0;
01267             }
01268             // Set
01269             context.programParams->setConstant(index, intBuffer, roundedDims * 0.25);
01270             delete [] intBuffer;
01271         }
01272     }
01273     //-----------------------------------------------------------------------
01274     void processAutoProgramParam(size_t index, const String& commandname, 
01275         StringVector& vecparams, MaterialScriptContext& context)
01276     {
01277         // NB we assume that the first element of vecparams is taken up with either 
01278         // the index or the parameter name, which we ignore
01279 
01280         bool extras = false;
01281         GpuProgramParameters::AutoConstantType acType;
01282 
01283         StringUtil::toLowerCase(vecparams[1]);
01284 
01285         if (vecparams[1] == "world_matrix")
01286         {
01287             acType = GpuProgramParameters::ACT_WORLD_MATRIX;
01288         }
01289         else if (vecparams[1] == "world_matrix_array")
01290         {
01291             acType = GpuProgramParameters::ACT_WORLD_MATRIX_ARRAY;
01292         }
01293         else if (vecparams[1] == "world_matrix_array_3x4")
01294         {
01295             acType = GpuProgramParameters::ACT_WORLD_MATRIX_ARRAY_3x4;
01296         }
01297         else if (vecparams[1] == "view_matrix")
01298         {
01299             acType = GpuProgramParameters::ACT_VIEW_MATRIX;
01300         }
01301         else if (vecparams[1] == "viewproj_matrix")
01302         {
01303             acType = GpuProgramParameters::ACT_VIEWPROJ_MATRIX;
01304         }
01305         else if (vecparams[1] == "worldview_matrix")
01306         {
01307             acType = GpuProgramParameters::ACT_WORLDVIEW_MATRIX;
01308         }
01309         else if (vecparams[1] == "worldviewproj_matrix")
01310         {
01311             acType = GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX;
01312         }
01313         else if (vecparams[1] == "inverse_world_matrix")
01314         {
01315             acType = GpuProgramParameters::ACT_INVERSE_WORLD_MATRIX;
01316         }
01317         else if (vecparams[1] == "inverse_worldview_matrix")
01318         {
01319             acType = GpuProgramParameters::ACT_INVERSE_WORLDVIEW_MATRIX;
01320         }
01321         else if (vecparams[1] == "light_diffuse_colour")
01322         {
01323             acType = GpuProgramParameters::ACT_LIGHT_DIFFUSE_COLOUR;
01324             extras = true;
01325         }
01326         else if (vecparams[1] == "light_specular_colour")
01327         {
01328             acType = GpuProgramParameters::ACT_LIGHT_SPECULAR_COLOUR;
01329             extras = true;
01330         }
01331         else if (vecparams[1] == "light_attenuation")
01332         {
01333             acType = GpuProgramParameters::ACT_LIGHT_ATTENUATION;
01334             extras = true;
01335         }
01336         else if (vecparams[1] == "light_position")
01337         {
01338             acType = GpuProgramParameters::ACT_LIGHT_POSITION;
01339             extras = true;
01340         }
01341         else if (vecparams[1] == "light_direction")
01342         {
01343             acType = GpuProgramParameters::ACT_LIGHT_DIRECTION;
01344             extras = true;
01345         }
01346         else if (vecparams[1] == "light_position_object_space")
01347         {
01348             acType = GpuProgramParameters::ACT_LIGHT_POSITION_OBJECT_SPACE;
01349             extras = true;
01350         }
01351         else if (vecparams[1] == "light_direction_object_space")
01352         {
01353             acType = GpuProgramParameters::ACT_LIGHT_DIRECTION_OBJECT_SPACE;
01354             extras = true;
01355         }
01356         else if (vecparams[1] == "ambient_light_colour")
01357         {
01358             acType = GpuProgramParameters::ACT_AMBIENT_LIGHT_COLOUR;
01359         }
01360         else if (vecparams[1] == "camera_position_object_space")
01361         {
01362             acType = GpuProgramParameters::ACT_CAMERA_POSITION_OBJECT_SPACE;
01363         }
01364         else if (vecparams[1] == "texture_viewproj_matrix")
01365         {
01366             acType = GpuProgramParameters::ACT_TEXTURE_VIEWPROJ_MATRIX;
01367         }
01368         else if (vecparams[1] == "time")
01369         {
01370             // Special case!
01371             Real factor = 1.0f;
01372             if (vecparams.size() == 3)
01373             {
01374                 factor = StringConverter::parseReal(vecparams[2]);
01375             }
01376             
01377             context.programParams->setConstantFromTime(index, factor);
01378             return;
01379         }
01380         else if (vecparams[1] == "custom")
01381         {
01382             acType = GpuProgramParameters::ACT_CUSTOM;
01383             extras = true;
01384         }
01385 
01386         // Do we need any extra parameters?
01387         size_t extraParam = 0;
01388         if (extras)
01389         {
01390             if (vecparams.size() != 3)
01391             {
01392                 logParseError("Invalid " + commandname + " attribute - "
01393                     "expected 3 parameters.", context);
01394                 return;
01395             }
01396             extraParam = StringConverter::parseInt(vecparams[2]);
01397         }
01398 
01399         context.programParams->setAutoConstant(index, acType, extraParam);
01400     }
01401     //-----------------------------------------------------------------------
01402     bool parseParamIndexed(String& params, MaterialScriptContext& context)
01403     {
01404         // NB skip this if the program is not supported or could not be found
01405         if (!context.program || !context.program->isSupported())
01406         {
01407             return false;
01408         }
01409 
01410         StringUtil::toLowerCase(params);
01411         StringVector vecparams = StringUtil::split(params, " \t");
01412         if (vecparams.size() < 3)
01413         {
01414             logParseError("Invalid param_indexed attribute - expected at least 3 parameters.", 
01415                 context);
01416             return false;
01417         }
01418 
01419         // Get start index
01420         size_t index = StringConverter::parseInt(vecparams[0]);
01421 
01422         processManualProgramParam(index, "param_indexed", vecparams, context);
01423 
01424         return false;
01425     }
01426     //-----------------------------------------------------------------------
01427     bool parseParamIndexedAuto(String& params, MaterialScriptContext& context)
01428     {
01429         // NB skip this if the program is not supported or could not be found
01430         if (!context.program || !context.program->isSupported())
01431         {
01432             return false;
01433         }
01434 
01435         StringUtil::toLowerCase(params);
01436         StringVector vecparams = StringUtil::split(params, " \t");
01437         if (vecparams.size() != 2 && vecparams.size() != 3)
01438         {
01439             logParseError("Invalid param_indexed_auto attribute - expected 2 or 3 parameters.", 
01440                 context);
01441             return false;
01442         }
01443 
01444         // Get start index
01445         size_t index = StringConverter::parseInt(vecparams[0]);
01446 
01447         processAutoProgramParam(index, "param_indexed_auto", vecparams, context);
01448 
01449         return false;
01450     }
01451     //-----------------------------------------------------------------------
01452     bool parseParamNamed(String& params, MaterialScriptContext& context)
01453     {
01454         // NB skip this if the program is not supported or could not be found
01455         if (!context.program || !context.program->isSupported())
01456         {
01457             return false;
01458         }
01459 
01460         StringVector vecparams = StringUtil::split(params, " \t");
01461         if (vecparams.size() < 3)
01462         {
01463             logParseError("Invalid param_named attribute - expected at least 3 parameters.", 
01464                 context);
01465             return false;
01466         }
01467 
01468         // Get start index from name
01469         size_t index;
01470         try {
01471             index = context.programParams->getParamIndex(vecparams[0]);
01472         }
01473         catch (Exception& e)
01474         {
01475             logParseError("Invalid param_named attribute - " + e.getFullDescription(), context);
01476             return false;
01477         }
01478 
01479         // TEST
01480         /*
01481         LogManager::getSingleton().logMessage("SETTING PARAMETER " + vecparams[0] + " as index " +
01482             StringConverter::toString(index));
01483         */
01484         processManualProgramParam(index, "param_named", vecparams, context);
01485 
01486         return false;
01487     }
01488     //-----------------------------------------------------------------------
01489     bool parseParamNamedAuto(String& params, MaterialScriptContext& context)
01490     {
01491         // NB skip this if the program is not supported or could not be found
01492         if (!context.program || !context.program->isSupported())
01493         {
01494             return false;
01495         }
01496 
01497         StringVector vecparams = StringUtil::split(params, " \t");
01498         if (vecparams.size() != 2 && vecparams.size() != 3)
01499         {
01500             logParseError("Invalid param_indexed_auto attribute - expected 2 or 3 parameters.", 
01501                 context);
01502             return false;
01503         }
01504 
01505         // Get start index from name
01506         size_t index;
01507         try {
01508             index = context.programParams->getParamIndex(vecparams[0]);
01509         }
01510         catch (Exception& e)
01511         {
01512             logParseError("Invalid param_named_auto attribute - " + e.getFullDescription(), context);
01513             return false;
01514         }
01515 
01516         processAutoProgramParam(index, "param_named_auto", vecparams, context);
01517 
01518         return false;
01519     }
01520     //-----------------------------------------------------------------------
01521     bool parseMaterial(String& params, MaterialScriptContext& context)
01522     {
01523         // Create a brand new material
01524         context.material = static_cast<Material*>(
01525             MaterialManager::getSingleton().create(params));
01526         // Remove pre-created technique from defaults
01527         context.material->removeAllTechniques();
01528 
01529         // update section
01530         context.section = MSS_MATERIAL;
01531 
01532         // Return TRUE because this must be followed by a {
01533         return true;
01534     }
01535     //-----------------------------------------------------------------------
01536     bool parseTechnique(String& params, MaterialScriptContext& context)
01537     {
01538         // Create a new technique
01539         context.technique = context.material->createTechnique();
01540 
01541         // update section
01542         context.section = MSS_TECHNIQUE;
01543 
01544         //Increase technique level depth
01545         context.techLev += 1;
01546 
01547         // Return TRUE because this must be followed by a {
01548         return true;
01549     }
01550     //-----------------------------------------------------------------------
01551     bool parsePass(String& params, MaterialScriptContext& context)
01552     {
01553         // Create a new pass
01554         context.pass = context.technique->createPass();
01555 
01556         // update section
01557         context.section = MSS_PASS;
01558 
01559         //Increase pass level depth
01560         context.passLev += 1;
01561 
01562         // Return TRUE because this must be followed by a {
01563         return true;
01564     }
01565     //-----------------------------------------------------------------------
01566     bool parseTextureUnit(String& params, MaterialScriptContext& context)
01567     {
01568         // Create a new texture unit
01569         context.textureUnit = context.pass->createTextureUnitState();
01570 
01571         // update section
01572         context.section = MSS_TEXTUREUNIT;
01573 
01574         // Increase texture unit depth
01575         context.stateLev += 1;
01576 
01577         // Return TRUE because this must be followed by a {
01578         return true;
01579     }
01580     //-----------------------------------------------------------------------
01581     bool parseVertexProgramRef(String& params, MaterialScriptContext& context)
01582     {
01583         // update section
01584         context.section = MSS_PROGRAM_REF;
01585 
01586         context.program = static_cast<GpuProgram*>(
01587             GpuProgramManager::getSingleton().getByName(params));
01588         if (context.program == 0)
01589         {
01590             // Unknown program
01591             logParseError("Invalid vertex_program_ref entry - vertex program " 
01592                 + params + " has not been defined.", context);
01593             return true;
01594         }
01595 
01596         context.isProgramShadowCaster = false;
01597         context.isProgramShadowReceiver = false;
01598         
01599         // Set the vertex program for this pass
01600         context.pass->setVertexProgram(params);
01601 
01602         // Create params? Skip this if program is not supported
01603         if (context.program->isSupported())
01604         {
01605             context.programParams = context.pass->getVertexProgramParameters();
01606         }
01607 
01608         // Return TRUE because this must be followed by a {
01609         return true;
01610     }
01611     //-----------------------------------------------------------------------
01612     bool parseShadowCasterVertexProgramRef(String& params, MaterialScriptContext& context)
01613     {
01614         // update section
01615         context.section = MSS_PROGRAM_REF;
01616 
01617         context.program = static_cast<GpuProgram*>(
01618             GpuProgramManager::getSingleton().getByName(params));
01619         if (context.program == 0)
01620         {
01621             // Unknown program
01622             logParseError("Invalid vertex_program_ref entry - vertex program " 
01623                 + params + " has not been defined.", context);
01624             return true;
01625         }
01626 
01627         context.isProgramShadowCaster = true;
01628         context.isProgramShadowReceiver = false;
01629 
01630         // Set the vertex program for this pass
01631         context.pass->setShadowCasterVertexProgram(params);
01632 
01633         // Create params? Skip this if program is not supported
01634         if (context.program->isSupported())
01635         {
01636             context.programParams = context.pass->getShadowCasterVertexProgramParameters();
01637         }
01638 
01639         // Return TRUE because this must be followed by a {
01640         return true;
01641     }
01642     //-----------------------------------------------------------------------
01643     bool parseShadowReceiverVertexProgramRef(String& params, MaterialScriptContext& context)
01644     {
01645         // update section
01646         context.section = MSS_PROGRAM_REF;
01647 
01648         context.program = static_cast<GpuProgram*>(
01649             GpuProgramManager::getSingleton().getByName(params));
01650         if (context.program == 0)
01651         {
01652             // Unknown program
01653             logParseError("Invalid vertex_program_ref entry - vertex program " 
01654                 + params + " has not been defined.", context);
01655             return true;
01656         }
01657 
01658         context.isProgramShadowCaster = false;
01659         context.isProgramShadowReceiver = true;
01660 
01661         // Set the vertex program for this pass
01662         context.pass->setShadowReceiverVertexProgram(params);
01663 
01664         // Create params? Skip this if program is not supported
01665         if (context.program->isSupported())
01666         {
01667             context.programParams = context.pass->getShadowReceiverVertexProgramParameters();
01668         }
01669 
01670         // Return TRUE because this must be followed by a {
01671         return true;
01672     }
01673     //-----------------------------------------------------------------------
01674     bool parseFragmentProgramRef(String& params, MaterialScriptContext& context)
01675     {
01676         // update section
01677         context.section = MSS_PROGRAM_REF;
01678 
01679         context.program = static_cast<GpuProgram*>(
01680             GpuProgramManager::getSingleton().getByName(params));
01681         if (context.program == 0)
01682         {
01683             // Unknown program
01684             logParseError("Invalid fragment_program_ref entry - fragment program " 
01685                 + params + " has not been defined.", context);
01686             return true;
01687         }
01688         
01689         // Set the vertex program for this pass
01690         context.pass->setFragmentProgram(params);
01691 
01692         // Create params? Skip this if program is not supported
01693         if (context.program->isSupported())
01694         {
01695             context.programParams = context.pass->getFragmentProgramParameters();
01696         }
01697 
01698         // Return TRUE because this must be followed by a {
01699         return true;
01700     }
01701     //-----------------------------------------------------------------------
01702     bool parseVertexProgram(String& params, MaterialScriptContext& context)
01703     {
01704         // update section
01705         context.section = MSS_PROGRAM;
01706 
01707         // Create new program definition-in-progress
01708         context.programDef = new MaterialScriptProgramDefinition();
01709         context.programDef->progType = GPT_VERTEX_PROGRAM;
01710         context.programDef->supportsSkeletalAnimation = false;
01711 
01712         // Get name and language code
01713         StringVector vecparams = StringUtil::split(params, " \t");
01714         if (vecparams.size() != 2)
01715         {
01716             logParseError("Invalid vertex_program entry - expected "
01717                 "2 parameters.", context);
01718             return true;
01719         }
01720         // Name, preserve case
01721         context.programDef->name = vecparams[0];
01722         // language code, make lower case
01723         context.programDef->language = vecparams[1];
01724         StringUtil::toLowerCase(context.programDef->language);
01725 
01726         // Return TRUE because this must be followed by a {
01727         return true;
01728     }
01729     //-----------------------------------------------------------------------
01730     bool parseFragmentProgram(String& params, MaterialScriptContext& context)
01731     {
01732         // update section
01733         context.section = MSS_PROGRAM;
01734 
01735         // Create new program definition-in-progress
01736         context.programDef = new MaterialScriptProgramDefinition();
01737         context.programDef->progType = GPT_FRAGMENT_PROGRAM;
01738         context.programDef->supportsSkeletalAnimation = false;
01739 
01740         // Get name and language code
01741         StringVector vecparams = StringUtil::split(params, " \t");
01742         if (vecparams.size() != 2)
01743         {
01744             logParseError("Invalid fragment_program entry - expected "
01745                 "2 parameters.", context);
01746             return true;
01747         }
01748         // Name, preserve case
01749         context.programDef->name = vecparams[0];
01750         // language code, make lower case
01751         context.programDef->language = vecparams[1];
01752         StringUtil::toLowerCase(context.programDef->language);
01753 
01754         // Return TRUE because this must be followed by a {
01755         return true;
01756     
01757     }
01758     //-----------------------------------------------------------------------
01759     bool parseProgramSource(String& params, MaterialScriptContext& context)
01760     {
01761         // Source filename, preserve case
01762         context.programDef->source = params;
01763 
01764         return false;
01765     }
01766     //-----------------------------------------------------------------------
01767     bool parseProgramSkeletalAnimation(String& params, MaterialScriptContext& context)
01768     {
01769         // Source filename, preserve case
01770         context.programDef->supportsSkeletalAnimation 
01771             = StringConverter::parseBool(params);
01772 
01773         return false;
01774     }
01775     //-----------------------------------------------------------------------
01776     bool parseProgramSyntax(String& params, MaterialScriptContext& context)
01777     {
01778         // Syntax code, make lower case
01779         StringUtil::toLowerCase(params);
01780         context.programDef->syntax = params;
01781 
01782         return false;
01783     }
01784     //-----------------------------------------------------------------------
01785     bool parseProgramCustomParameter(String& params, MaterialScriptContext& context)
01786     {
01787         // This params object does not have the command stripped
01788         // Lower case the command, but not the value incase it's relevant
01789         // Split only up to first delimiter, program deals with the rest
01790         StringVector vecparams = StringUtil::split(params, " \t", 1);
01791         if (vecparams.size() != 2)
01792         {
01793             logParseError("Invalid custom program parameter entry; "
01794                 "there must be a parameter name and at least one value.", 
01795                 context);
01796             return false;
01797         }
01798 
01799         context.programDef->customParameters[vecparams[0]] = vecparams[1];
01800 
01801         return false;
01802     }
01803 
01804     //-----------------------------------------------------------------------
01805     bool parseTextureSource(String& params, MaterialScriptContext& context)
01806     {
01807         StringUtil::toLowerCase(params);
01808         StringVector vecparams = StringUtil::split(params, " \t");
01809         if (vecparams.size() != 1)
01810             logParseError("Invalid texture source attribute - expected 1 parameter.",                 context);
01811         //The only param should identify which ExternalTextureSource is needed
01812         ExternalTextureSourceManager::getSingleton().SetCurrentPlugIn( vecparams[0] );
01813 
01814         if( ExternalTextureSourceManager::getSingleton().getCurrentPlugIn() != 0 )
01815         {
01816             String tps;
01817             tps = StringConverter::toString( context.techLev ) + " "
01818                 + StringConverter::toString( context.passLev ) + " "
01819                 + StringConverter::toString( context.stateLev);
01820 
01821             ExternalTextureSourceManager::getSingleton().getCurrentPlugIn()->setParameter( "set_T_P_S", tps );
01822         }
01823             
01824         // update section
01825         context.section = MSS_TEXTURESOURCE;
01826         // Return TRUE because this must be followed by a {
01827         return true;
01828     }
01829 
01830     //-----------------------------------------------------------------------
01831     bool parseTextureCustomParameter(String& params, MaterialScriptContext& context)
01832     {
01833         // This params object does not have the command stripped
01834         // Split only up to first delimiter, program deals with the rest
01835         StringVector vecparams = StringUtil::split(params, " \t", 1);
01836         if (vecparams.size() != 2)
01837         {
01838             logParseError("Invalid texture parameter entry; "
01839                 "there must be a parameter name and at least one value.", 
01840                 context);
01841             return false;
01842         }
01843         
01844         if( ExternalTextureSourceManager::getSingleton().getCurrentPlugIn() != 0 )
01846             ExternalTextureSourceManager::getSingleton().getCurrentPlugIn()->setParameter( vecparams[0], vecparams[1] );
01847         
01848         return false;
01849     }
01850     //-----------------------------------------------------------------------
01851     bool parseReceiveShadows(String& params, MaterialScriptContext& context)
01852     {
01853         StringUtil::toLowerCase(params);
01854         if (params == "on")
01855             context.material->setReceiveShadows(true);
01856         else if (params == "off")
01857             context.material->setReceiveShadows(false);
01858         else
01859             logParseError(
01860             "Bad receive_shadows attribute, valid parameters are 'on' or 'off'.", 
01861             context);
01862 
01863         return false;
01864 
01865     }
01866     //-----------------------------------------------------------------------
01867     bool parseDefaultParams(String& params, MaterialScriptContext& context)
01868     {
01869         context.section = MSS_DEFAULT_PARAMETERS;
01870         // Should be a brace next
01871         return true;
01872     }
01873 
01874     //-----------------------------------------------------------------------
01875     bool parseTransparencyCastsShadows(String& params, MaterialScriptContext& context)
01876     {
01877         StringUtil::toLowerCase(params);
01878         if (params == "on")
01879             context.material->setTransparencyCastsShadows(true);
01880         else if (params == "off")
01881             context.material->setTransparencyCastsShadows(false);
01882         else
01883             logParseError(
01884             "Bad transparency_casts_shadows attribute, valid parameters are 'on' or 'off'.", 
01885             context);
01886 
01887         return false;
01888 
01889     }
01890     //-----------------------------------------------------------------------
01891     //-----------------------------------------------------------------------
01892     MaterialSerializer::MaterialSerializer()
01893     {
01894         // Set up root attribute parsers
01895         mRootAttribParsers.insert(AttribParserList::value_type("material", (ATTRIBUTE_PARSER)parseMaterial));
01896         mRootAttribParsers.insert(AttribParserList::value_type("vertex_program", (ATTRIBUTE_PARSER)parseVertexProgram));
01897         mRootAttribParsers.insert(AttribParserList::value_type("fragment_program", (ATTRIBUTE_PARSER)parseFragmentProgram));
01898         // Set up material attribute parsers
01899         mMaterialAttribParsers.insert(AttribParserList::value_type("lod_distances", (ATTRIBUTE_PARSER)parseLodDistances));
01900         mMaterialAttribParsers.insert(AttribParserList::value_type("receive_shadows", (ATTRIBUTE_PARSER)parseReceiveShadows));
01901         mMaterialAttribParsers.insert(AttribParserList::value_type("transparency_casts_shadows", (ATTRIBUTE_PARSER)parseTransparencyCastsShadows));
01902         mMaterialAttribParsers.insert(AttribParserList::value_type("technique", (ATTRIBUTE_PARSER)parseTechnique));
01903         // Set up technique attribute parsers
01904         mTechniqueAttribParsers.insert(AttribParserList::value_type("lod_index", (ATTRIBUTE_PARSER)parseLodIndex));
01905         mTechniqueAttribParsers.insert(AttribParserList::value_type("pass", (ATTRIBUTE_PARSER)parsePass));
01906         // Set up pass attribute parsers
01907         mPassAttribParsers.insert(AttribParserList::value_type("ambient", (ATTRIBUTE_PARSER)parseAmbient));
01908         mPassAttribParsers.insert(AttribParserList::value_type("diffuse", (ATTRIBUTE_PARSER)parseDiffuse));
01909         mPassAttribParsers.insert(AttribParserList::value_type("specular", (ATTRIBUTE_PARSER)parseSpecular));
01910         mPassAttribParsers.insert(AttribParserList::value_type("emissive", (ATTRIBUTE_PARSER)parseEmissive));
01911         mPassAttribParsers.insert(AttribParserList::value_type("scene_blend", (ATTRIBUTE_PARSER)parseSceneBlend));
01912         mPassAttribParsers.insert(AttribParserList::value_type("depth_check", (ATTRIBUTE_PARSER)parseDepthCheck));
01913         mPassAttribParsers.insert(AttribParserList::value_type("depth_write", (ATTRIBUTE_PARSER)parseDepthWrite));
01914         mPassAttribParsers.insert(AttribParserList::value_type("depth_func", (ATTRIBUTE_PARSER)parseDepthFunc));
01915         mPassAttribParsers.insert(AttribParserList::value_type("colour_write", (ATTRIBUTE_PARSER)parseColourWrite));
01916         mPassAttribParsers.insert(AttribParserList::value_type("cull_hardware", (ATTRIBUTE_PARSER)parseCullHardware));
01917         mPassAttribParsers.insert(AttribParserList::value_type("cull_software", (ATTRIBUTE_PARSER)parseCullSoftware));
01918         mPassAttribParsers.insert(AttribParserList::value_type("lighting", (ATTRIBUTE_PARSER)parseLighting));
01919         mPassAttribParsers.insert(AttribParserList::value_type("fog_override", (ATTRIBUTE_PARSER)parseFogging));
01920         mPassAttribParsers.insert(AttribParserList::value_type("shading", (ATTRIBUTE_PARSER)parseShading));
01921         mPassAttribParsers.insert(AttribParserList::value_type("depth_bias", (ATTRIBUTE_PARSER)parseDepthBias));
01922         mPassAttribParsers.insert(AttribParserList::value_type("texture_unit", (ATTRIBUTE_PARSER)parseTextureUnit));
01923         mPassAttribParsers.insert(AttribParserList::value_type("vertex_program_ref", (ATTRIBUTE_PARSER)parseVertexProgramRef));
01924         mPassAttribParsers.insert(AttribParserList::value_type("shadow_caster_vertex_program_ref", (ATTRIBUTE_PARSER)parseShadowCasterVertexProgramRef));
01925         mPassAttribParsers.insert(AttribParserList::value_type("shadow_receiver_vertex_program_ref", (ATTRIBUTE_PARSER)parseShadowReceiverVertexProgramRef));
01926         mPassAttribParsers.insert(AttribParserList::value_type("fragment_program_ref", (ATTRIBUTE_PARSER)parseFragmentProgramRef));
01927         mPassAttribParsers.insert(AttribParserList::value_type("max_lights", (ATTRIBUTE_PARSER)parseMaxLights));
01928         mPassAttribParsers.insert(AttribParserList::value_type("iteration", (ATTRIBUTE_PARSER)parseIteration));
01929         mTextureUnitAttribParsers.insert(AttribParserList::value_type("texture_source", (ATTRIBUTE_PARSER)parseTextureSource));
01930 
01931         // Set up texture unit attribute parsers
01932         mTextureUnitAttribParsers.insert(AttribParserList::value_type("texture", (ATTRIBUTE_PARSER)parseTexture));
01933         mTextureUnitAttribParsers.insert(AttribParserList::value_type("anim_texture", (ATTRIBUTE_PARSER)parseAnimTexture));
01934         mTextureUnitAttribParsers.insert(AttribParserList::value_type("cubic_texture", (ATTRIBUTE_PARSER)parseCubicTexture));
01935         mTextureUnitAttribParsers.insert(AttribParserList::value_type("tex_coord_set", (ATTRIBUTE_PARSER)parseTexCoord));
01936         mTextureUnitAttribParsers.insert(AttribParserList::value_type("tex_address_mode", (ATTRIBUTE_PARSER)parseTexAddressMode));
01937         mTextureUnitAttribParsers.insert(AttribParserList::value_type("colour_op", (ATTRIBUTE_PARSER)parseColourOp));
01938         mTextureUnitAttribParsers.insert(AttribParserList::value_type("alpha_rejection", (ATTRIBUTE_PARSER)parseAlphaRejection));
01939         mTextureUnitAttribParsers.insert(AttribParserList::value_type("colour_op_ex", (ATTRIBUTE_PARSER)parseColourOpEx));
01940         mTextureUnitAttribParsers.insert(AttribParserList::value_type("colour_op_multipass_fallback", (ATTRIBUTE_PARSER)parseColourOpFallback));
01941         mTextureUnitAttribParsers.insert(AttribParserList::value_type("alpha_op_ex", (ATTRIBUTE_PARSER)parseAlphaOpEx));
01942         mTextureUnitAttribParsers.insert(AttribParserList::value_type("env_map", (ATTRIBUTE_PARSER)parseEnvMap));
01943         mTextureUnitAttribParsers.insert(AttribParserList::value_type("scroll", (ATTRIBUTE_PARSER)parseScroll));
01944         mTextureUnitAttribParsers.insert(AttribParserList::value_type("scroll_anim", (ATTRIBUTE_PARSER)parseScrollAnim));
01945         mTextureUnitAttribParsers.insert(AttribParserList::value_type("rotate", (ATTRIBUTE_PARSER)parseRotate));
01946         mTextureUnitAttribParsers.insert(AttribParserList::value_type("rotate_anim", (ATTRIBUTE_PARSER)parseRotateAnim));
01947         mTextureUnitAttribParsers.insert(AttribParserList::value_type("scale", (ATTRIBUTE_PARSER)parseScale));
01948         mTextureUnitAttribParsers.insert(AttribParserList::value_type("wave_xform", (ATTRIBUTE_PARSER)parseWaveXform));
01949         mTextureUnitAttribParsers.insert(AttribParserList::value_type("filtering", (ATTRIBUTE_PARSER)parseFiltering));
01950         mTextureUnitAttribParsers.insert(AttribParserList::value_type("max_anisotropy", (ATTRIBUTE_PARSER)parseAnisotropy));
01951 
01952         // Set up program reference attribute parsers
01953         mProgramRefAttribParsers.insert(AttribParserList::value_type("param_indexed", (ATTRIBUTE_PARSER)parseParamIndexed));
01954         mProgramRefAttribParsers.insert(AttribParserList::value_type("param_indexed_auto", (ATTRIBUTE_PARSER)parseParamIndexedAuto));
01955         mProgramRefAttribParsers.insert(AttribParserList::value_type("param_named", (ATTRIBUTE_PARSER)parseParamNamed));
01956         mProgramRefAttribParsers.insert(AttribParserList::value_type("param_named_auto", (ATTRIBUTE_PARSER)parseParamNamedAuto));
01957         mProgramRefAttribParsers.insert(AttribParserList::value_type("param_named", (ATTRIBUTE_PARSER)parseParamNamedAuto));
01958 
01959         // Set up program definition attribute parsers
01960         mProgramAttribParsers.insert(AttribParserList::value_type("source", (ATTRIBUTE_PARSER)parseProgramSource));
01961         mProgramAttribParsers.insert(AttribParserList::value_type("syntax", (ATTRIBUTE_PARSER)parseProgramSyntax));
01962         mProgramAttribParsers.insert(AttribParserList::value_type("includes_skeletal_animation", (ATTRIBUTE_PARSER)parseProgramSkeletalAnimation));
01963         mProgramAttribParsers.insert(AttribParserList::value_type("default_params", (ATTRIBUTE_PARSER)parseDefaultParams));
01964         
01965         // Set up program default param attribute parsers
01966         mProgramDefaultParamAttribParsers.insert(AttribParserList::value_type("param_indexed", (ATTRIBUTE_PARSER)parseParamIndexed));
01967         mProgramDefaultParamAttribParsers.insert(AttribParserList::value_type("param_indexed_auto", (ATTRIBUTE_PARSER)parseParamIndexedAuto));
01968         mProgramDefaultParamAttribParsers.insert(AttribParserList::value_type("param_named", (ATTRIBUTE_PARSER)parseParamNamed));
01969         mProgramDefaultParamAttribParsers.insert(AttribParserList::value_type("param_named_auto", (ATTRIBUTE_PARSER)parseParamNamedAuto));
01970         mProgramDefaultParamAttribParsers.insert(AttribParserList::value_type("param_named", (ATTRIBUTE_PARSER)parseParamNamedAuto));
01971 
01972         mScriptContext.section = MSS_NONE;
01973         mScriptContext.material = 0;
01974         mScriptContext.technique = 0;
01975         mScriptContext.pass = 0;
01976         mScriptContext.textureUnit = 0;
01977         mScriptContext.program = 0;
01978         mScriptContext.lineNo = 0;
01979         mScriptContext.filename = "";
01980         mScriptContext.techLev = -1;
01981         mScriptContext.passLev = -1;
01982         mScriptContext.stateLev = -1;
01983 
01984         mBuffer = "";
01985     }
01986 
01987     //-----------------------------------------------------------------------
01988     void MaterialSerializer::parseScript(DataChunk& chunk, const String& filename)
01989     {
01990         String line;
01991         bool nextIsOpenBrace = false;
01992 
01993         mScriptContext.section = MSS_NONE;
01994         mScriptContext.material = 0;
01995         mScriptContext.technique = 0;
01996         mScriptContext.pass = 0;
01997         mScriptContext.textureUnit = 0;
01998         mScriptContext.program = 0;
01999         mScriptContext.lineNo = 0;
02000         mScriptContext.techLev = -1;
02001         mScriptContext.passLev = -1;
02002         mScriptContext.stateLev = -1;
02003         mScriptContext.filename = filename;
02004         while(!chunk.isEOF())
02005         {
02006             line = chunk.getLine();
02007             mScriptContext.lineNo++;
02008             
02009             // DEBUG LINE
02010             //LogManager::getSingleton().logMessage("About to attempt line: " + 
02011             //    StringConverter::toString(mScriptContext.lineNo));
02012 
02013             // Ignore comments & blanks
02014             if (!(line.length() == 0 || line.substr(0,2) == "//"))
02015             {
02016                 if (nextIsOpenBrace)
02017                 {
02018                     // NB, parser will have changed context already
02019                     if (line != "{")
02020                     {
02021                         logParseError("Expecting '{' but got " +
02022                             line + " instead.", mScriptContext);
02023                     }
02024                     nextIsOpenBrace = false;
02025                 }
02026                 else
02027                 {
02028                     nextIsOpenBrace = parseScriptLine(line);
02029                 }
02030 
02031             }
02032         }
02033 
02034         // Check all braces were closed
02035         if (mScriptContext.section != MSS_NONE)
02036         {
02037             logParseError("Unexpected end of file.", mScriptContext);
02038         }
02039 
02040     }
02041     //-----------------------------------------------------------------------
02042     bool MaterialSerializer::parseScriptLine(String& line)
02043     {
02044         switch(mScriptContext.section)
02045         {
02046         case MSS_NONE:
02047             if (line == "}")
02048             {
02049                 logParseError("Unexpected terminating brace.", mScriptContext);
02050                 return false;
02051             }
02052             else
02053             {
02054                 // find & invoke a parser
02055                 return invokeParser(line, mRootAttribParsers); 
02056             }
02057             break;
02058         case MSS_MATERIAL:
02059             if (line == "}")
02060             {
02061                 // End of material
02062                 mScriptContext.section = MSS_NONE;
02063                 mScriptContext.material = NULL;
02064                 //Reset all levels for next material
02065                 mScriptContext.passLev = -1;
02066                 mScriptContext.stateLev= -1;
02067                 mScriptContext.techLev = -1;
02068             }
02069             else
02070             {
02071                 // find & invoke a parser
02072                 return invokeParser(line, mMaterialAttribParsers); 
02073             }
02074             break;
02075         case MSS_TECHNIQUE:
02076             if (line == "}")
02077             {
02078                 // End of technique
02079                 mScriptContext.section = MSS_MATERIAL;
02080                 mScriptContext.technique = NULL;
02081                 mScriptContext.passLev = -1;    //Reset pass level (yes, the pass level)
02082             }
02083             else
02084             {
02085                 // find & invoke a parser
02086                 return invokeParser(line, mTechniqueAttribParsers); 
02087             }
02088             break;
02089         case MSS_PASS:
02090             if (line == "}")
02091             {
02092                 // End of pass
02093                 mScriptContext.section = MSS_TECHNIQUE;
02094                 mScriptContext.pass = NULL;
02095                 mScriptContext.stateLev = -1;   //Reset state level (yes, the state level)
02096             }
02097             else
02098             {
02099                 // find & invoke a parser
02100                 return invokeParser(line, mPassAttribParsers); 
02101             }
02102             break;
02103         case MSS_TEXTUREUNIT:
02104             if (line == "}")
02105             {
02106                 // End of texture unit
02107                 mScriptContext.section = MSS_PASS;
02108                 mScriptContext.textureUnit = NULL;
02109             }
02110             else
02111             {
02112                 // find & invoke a parser
02113                 return invokeParser(line, mTextureUnitAttribParsers); 
02114             }
02115             break;
02116         case MSS_TEXTURESOURCE:
02117             if( line == "}" )
02118             {
02119                 //End texture source section
02120                 //Finish creating texture here
02121                 String sMaterialName = mScriptContext.material->getName();
02122                 if( ExternalTextureSourceManager::getSingleton().getCurrentPlugIn() != 0)
02123                     ExternalTextureSourceManager::getSingleton().getCurrentPlugIn()->createDefinedTexture( sMaterialName );
02124                 //Revert back to texture unit
02125                 mScriptContext.section = MSS_TEXTUREUNIT;
02126             }
02127             else
02128             {
02129                 // custom texture parameter, use original line
02130                 parseTextureCustomParameter(line, mScriptContext);
02131             }
02132             break;
02133         case MSS_PROGRAM_REF:
02134             if (line == "}")
02135             {
02136                 // End of program
02137                 mScriptContext.section = MSS_PASS;
02138                 mScriptContext.program = NULL;
02139             }
02140             else
02141             {
02142                 // find & invoke a parser
02143                 return invokeParser(line, mProgramRefAttribParsers); 
02144             }
02145             break;
02146         case MSS_PROGRAM:
02147             // Program definitions are slightly different, they are deferred
02148             // until all the information required is known
02149             if (line == "}")
02150             {
02151                 // End of program
02152                 finishProgramDefinition();
02153                 mScriptContext.section = MSS_NONE;
02154                 delete mScriptContext.programDef;
02155                 mScriptContext.defaultParamLines.clear();
02156                 mScriptContext.programDef = NULL;
02157             }
02158             else
02159             {
02160                 // find & invoke a parser
02161                 // do this manually because we want to call a custom
02162                 // routine when the parser is not found
02163                 // First, split line on first divisor only
02164                 StringVector splitCmd = StringUtil::split(line, " \t", 1);
02165                 // Find attribute parser
02166                 AttribParserList::iterator iparser = mProgramAttribParsers.find(splitCmd[0]);
02167                 if (iparser == mProgramAttribParsers.end())
02168                 {
02169                     // custom parameter, use original line
02170                     parseProgramCustomParameter(line, mScriptContext);
02171                 }
02172                 else
02173                 {
02174                     String cmd = splitCmd.size() >= 2? splitCmd[1]:StringUtil::BLANK;
02175                     // Use parser with remainder
02176                     return iparser->second(cmd, mScriptContext );
02177                 }
02178                 
02179             }
02180             break;
02181         case MSS_DEFAULT_PARAMETERS:
02182             if (line == "}")
02183             {
02184                 // End of default parameters
02185                 mScriptContext.section = MSS_PROGRAM;
02186             }
02187             else
02188             {
02189                 // Save default parameter lines up until we finalise the program
02190                 mScriptContext.defaultParamLines.push_back(line);
02191             }
02192 
02193 
02194             break;
02195         };
02196 
02197         return false;
02198     }
02199     //-----------------------------------------------------------------------
02200     void MaterialSerializer::finishProgramDefinition(void)
02201     {
02202         // Now it is time to create the program and propagate the parameters
02203         MaterialScriptProgramDefinition* def = mScriptContext.programDef;
02204         GpuProgram* gp = 0;
02205         if (def->language == "asm")
02206         {
02207             // Native assembler
02208             // Validate
02209             if (def->source.empty())
02210             {
02211                 logParseError("Invalid program definition for " + def->name +
02212                     ", you must specify a source file.", mScriptContext);
02213             }
02214             if (def->syntax.empty())
02215             {
02216                 logParseError("Invalid program definition for " + def->name +
02217                     ", you must specify a syntax code.", mScriptContext);
02218             }
02219             // Create
02220             gp = GpuProgramManager::getSingleton().
02221                 createProgram(def->name, def->source, def->progType, def->syntax);
02222 
02223         }
02224         else
02225         {
02226             // High-level program
02227             // Validate
02228             if (def->source.empty())
02229             {
02230                 logParseError("Invalid program definition for " + def->name +
02231                     ", you must specify a source file.", mScriptContext);
02232             }
02233             // Create
02234             try 
02235             {
02236                 HighLevelGpuProgram* hgp = HighLevelGpuProgramManager::getSingleton().
02237                     createProgram(def->name, def->language, def->progType);
02238                 gp = hgp;
02239                 // Set source file
02240                 hgp->setSourceFile(def->source);
02241 
02242                 // Set custom parameters
02243                 std::map<String, String>::const_iterator i, iend;
02244                 iend = def->customParameters.end();
02245                 for (i = def->customParameters.begin(); i != iend; ++i)
02246                 {
02247                     if (!hgp->setParameter(i->first, i->second))
02248                     {
02249                         logParseError("Error in program " + def->name + 
02250                             " parameter " + i->first + " is not valid.", mScriptContext);
02251                     }
02252                 }
02253             }
02254             catch (Exception& e)
02255             {
02256                 LogManager::getSingleton().logMessage("Could not create GPU program '"
02257                     + def->name + "', error reported was: " + e.getFullDescription());
02258             }
02259         }
02260         // Set skeletal animation option
02261         gp->setSkeletalAnimationIncluded(def->supportsSkeletalAnimation);
02262 
02263         // Set up to receive default parameters
02264         if (gp->isSupported() 
02265             && !mScriptContext.defaultParamLines.empty())
02266         {
02267             mScriptContext.programParams = gp->getDefaultParameters();
02268             mScriptContext.program = gp;
02269             StringVector::iterator i, iend;
02270             iend = mScriptContext.defaultParamLines.end();
02271             for (i = mScriptContext.defaultParamLines.begin();
02272                 i != iend; ++i)
02273             {
02274                 // find & invoke a parser
02275                 // do this manually because we want to call a custom
02276                 // routine when the parser is not found
02277                 // First, split line on first divisor only
02278                 StringVector splitCmd = StringUtil::split(*i, " \t", 1);
02279                 // Find attribute parser
02280                 AttribParserList::iterator iparser 
02281                     = mProgramDefaultParamAttribParsers.find(splitCmd[0]);
02282                 if (iparser != mProgramDefaultParamAttribParsers.end())
02283                 {
02284                     String cmd = splitCmd.size() >= 2? splitCmd[1]:StringUtil::BLANK;
02285                     // Use parser with remainder
02286                     iparser->second(cmd, mScriptContext );
02287                 }
02288 
02289             }
02290             // Reset
02291             mScriptContext.program = 0;
02292             mScriptContext.programParams.setNull();
02293         }
02294 
02295     }
02296     //-----------------------------------------------------------------------
02297     bool MaterialSerializer::invokeParser(String& line, AttribParserList& parsers)
02298     {
02299         // First, split line on first divisor only
02300         StringVector splitCmd(StringUtil::split(line, " \t", 1));
02301 
02302         // Find attribute parser
02303         AttribParserList::iterator iparser = parsers.find(splitCmd[0]);
02304         if (iparser == parsers.end())
02305         {
02306             // BAD command. BAD!
02307             logParseError("Unrecognised command: " + splitCmd[0], mScriptContext);
02308             return false;
02309         }
02310         else
02311         {
02312             String cmd;
02313             if(splitCmd.size() >= 2)
02314                 cmd = splitCmd[1];
02315             // Use parser, make sure we have 2 params before using splitCmd[1]
02316             return iparser->second( cmd, mScriptContext );
02317         }
02318     }
02319     //-----------------------------------------------------------------------
02320     void MaterialSerializer::exportMaterial(const Material *pMat, const String &fileName, bool exportDefaults)
02321     {
02322         clearQueue();
02323         mDefaults = exportDefaults;
02324         writeMaterial(pMat);
02325         exportQueued(fileName);
02326     }
02327     //-----------------------------------------------------------------------
02328     void MaterialSerializer::exportQueued(const String &fileName)
02329     {
02330         if (mBuffer == "")
02331             Except(Exception::ERR_INVALIDPARAMS, "Queue is empty !", "MaterialSerializer::exportQueued");
02332 
02333         LogManager::getSingleton().logMessage("MaterialSerializer : writing material(s) to material script : " + fileName, LML_CRITICAL);
02334         FILE *fp;
02335         fp = fopen(fileName.c_str(), "w");
02336         if (!fp)
02337             Except(Exception::ERR_CANNOT_WRITE_TO_FILE, "Cannot create material file.",
02338             "MaterialSerializer::export");
02339 
02340         fputs(mBuffer.c_str(), fp);
02341         fclose(fp);
02342         LogManager::getSingleton().logMessage("MaterialSerializer : done.", LML_CRITICAL);
02343         clearQueue();
02344     }
02345     //-----------------------------------------------------------------------
02346     void MaterialSerializer::queueForExport(const Material *pMat, bool clearQueued, bool exportDefaults)
02347     {
02348         if (clearQueued)
02349             clearQueue();
02350 
02351         mDefaults = exportDefaults;
02352         writeMaterial(pMat);
02353     }
02354     //-----------------------------------------------------------------------
02355     void MaterialSerializer::clearQueue()
02356     {
02357         mBuffer = "";
02358     }
02359     //-----------------------------------------------------------------------
02360     const String &MaterialSerializer::getQueuedAsString() const
02361     {
02362         return mBuffer;
02363     }
02364     //-----------------------------------------------------------------------
02365     void MaterialSerializer::writeMaterial(const Material *pMat)
02366     {
02367         LogManager::getSingleton().logMessage("MaterialSerializer : writing material " + pMat->getName() + " to queue.", LML_CRITICAL);
02368         // Material name
02369         writeAttribute(0, "material " + pMat->getName());
02370         beginSection(0);
02371         {
02372             // Write LOD information
02373             Material::LodDistanceIterator distIt = pMat->getLodDistanceIterator();
02374             // Skip zero value
02375             if (distIt.hasMoreElements())
02376                 distIt.getNext();
02377             String attributeVal;
02378             while (distIt.hasMoreElements())
02379             {
02380                 Real sqdist = distIt.getNext();
02381                 attributeVal.append(StringConverter::toString(Math::Sqrt(sqdist)));
02382                 if (distIt.hasMoreElements())
02383                     attributeVal.append(" ");
02384             }
02385             if (!attributeVal.empty())
02386             {
02387                 writeAttribute(1, "lod_distances");
02388                 writeValue(attributeVal);
02389             }
02390 
02391 
02392             // Shadow receive
02393             if (mDefaults || 
02394                 pMat->getReceiveShadows() != true)
02395             {
02396                 writeAttribute(1, "receive_shadows");
02397                 writeValue(pMat->getReceiveShadows() ? "on" : "off");
02398             }
02399 
02400             // When rendering shadows, treat transparent things as opaque?
02401             if (mDefaults || 
02402                 pMat->getTransparencyCastsShadows() == true)
02403             {
02404                 writeAttribute(1, "transparency_casts_shadows");
02405                 writeValue(pMat->getTransparencyCastsShadows() ? "on" : "off");
02406             }
02407 
02408             // Iterate over techniques
02409             Material::TechniqueIterator it = 
02410                 const_cast<Material*>(pMat)->getTechniqueIterator();
02411             while (it.hasMoreElements())
02412             {
02413                 writeTechnique(it.getNext());
02414             }
02415         }
02416         endSection(0);
02417     }
02418     //-----------------------------------------------------------------------
02419     void MaterialSerializer::writeTechnique(const Technique* pTech)
02420     {
02421         // Technique header
02422         writeAttribute(1, "technique");
02423         beginSection(1);
02424         {
02425             // Iterate over passes
02426             Technique::PassIterator it = const_cast<Technique*>(pTech)->getPassIterator();
02427             while (it.hasMoreElements())
02428             {
02429                 writePass(it.getNext());
02430             }
02431         }
02432         endSection(1);
02433 
02434     }
02435     //-----------------------------------------------------------------------
02436     void MaterialSerializer::writePass(const Pass* pPass)
02437     {
02438         writeAttribute(2, "pass");
02439         beginSection(2);
02440         {
02441             //lighting
02442             if (mDefaults || 
02443                 pPass->getLightingEnabled() != true)
02444             {
02445                 writeAttribute(3, "lighting");
02446                 writeValue(pPass->getLightingEnabled() ? "on" : "off");
02447             }
02448             // max_lights
02449             if (mDefaults || 
02450                 pPass->getMaxSimultaneousLights() != OGRE_MAX_SIMULTANEOUS_LIGHTS)
02451             {
02452                 writeAttribute(3, "max_lights");
02453                 writeValue(StringConverter::toString(pPass->getMaxSimultaneousLights()));
02454             }
02455             // iteration
02456             if (mDefaults || 
02457                 pPass->getRunOncePerLight())
02458             {
02459                 writeAttribute(3, "iteration");
02460                 writeValue(pPass->getRunOncePerLight() ? "once_per_light" : "once");
02461                 if (pPass->getRunOncePerLight() && pPass->getRunOnlyForOneLightType())
02462                 {
02463                     switch (pPass->getOnlyLightType())
02464                     {
02465                     case Light::LT_DIRECTIONAL:
02466                         writeValue("directional");
02467                         break;
02468                     case Light::LT_POINT:
02469                         writeValue("point");
02470                         break;
02471                     case Light::LT_SPOTLIGHT:
02472                         writeValue("spot");
02473                         break;
02474                     };
02475                 }
02476             }
02477             
02478 
02479             if (pPass->getLightingEnabled())
02480             {
02481                 // Ambient
02482                 if (mDefaults ||
02483                     pPass->getAmbient().r != 1 ||
02484                     pPass->getAmbient().g != 1 ||
02485                     pPass->getAmbient().b != 1 ||
02486                     pPass->getAmbient().a != 1)
02487                 {
02488                     writeAttribute(3, "ambient");
02489                     writeColourValue(pPass->getAmbient(), true);
02490                 }
02491 
02492                 // Diffuse
02493                 if (mDefaults ||
02494                     pPass->getDiffuse().r != 1 ||
02495                     pPass->getDiffuse().g != 1 ||
02496                     pPass->getDiffuse().b != 1 ||
02497                     pPass->getDiffuse().a != 1)
02498                 {
02499                     writeAttribute(3, "diffuse");
02500                     writeColourValue(pPass->getDiffuse(), true);
02501                 }
02502 
02503                 // Specular
02504                 if (mDefaults ||
02505                     pPass->getSpecular().r != 0 ||
02506                     pPass->getSpecular().g != 0 ||
02507                     pPass->getSpecular().b != 0 ||
02508                     pPass->getSpecular().a != 1 ||
02509                     pPass->getShininess() != 0)
02510                 {
02511                     writeAttribute(3, "specular");
02512                     writeColourValue(pPass->getSpecular(), true);
02513                     writeValue(StringConverter::toString(pPass->getShininess()));
02514                 }
02515 
02516                 // Emissive
02517                 if (mDefaults ||
02518                     pPass->getSelfIllumination().r != 0 ||
02519                     pPass->getSelfIllumination().g != 0 ||
02520                     pPass->getSelfIllumination().b != 0 ||
02521                     pPass->getSelfIllumination().a != 1)
02522                 {
02523                     writeAttribute(3, "emissive");
02524                     writeColourValue(pPass->getSelfIllumination(), true);
02525                 }
02526             }
02527 
02528             // scene blend factor
02529             if (mDefaults || 
02530                 pPass->getSourceBlendFactor() != SBF_ONE || 
02531                 pPass->getDestBlendFactor() != SBF_ZERO)
02532             {
02533                 writeAttribute(3, "scene_blend");
02534                 writeSceneBlendFactor(pPass->getSourceBlendFactor(), pPass->getDestBlendFactor());
02535             }
02536 
02537 
02538             //depth check
02539             if (mDefaults || 
02540                 pPass->getDepthCheckEnabled() != true)
02541             {
02542                 writeAttribute(3, "depth_check");
02543                 writeValue(pPass->getDepthCheckEnabled() ? "on" : "off");
02544             }
02545 
02546             //depth write
02547             if (mDefaults || 
02548                 pPass->getDepthWriteEnabled() != true)
02549             {
02550                 writeAttribute(3, "depth_write");
02551                 writeValue(pPass->getDepthWriteEnabled() ? "on" : "off");
02552             }
02553 
02554             //depth function
02555             if (mDefaults || 
02556                 pPass->getDepthFunction() != CMPF_LESS_EQUAL)
02557             {
02558                 writeAttribute(3, "depth_func");
02559                 writeCompareFunction(pPass->getDepthFunction());
02560             }
02561 
02562             //depth bias
02563             if (mDefaults || 
02564                 pPass->getDepthBias() != 0)
02565             {
02566                 writeAttribute(3, "depth_bias");
02567                 writeValue(StringConverter::toString(pPass->getDepthBias()));
02568             }
02569 
02570             // hardware culling mode
02571             if (mDefaults || 
02572                 pPass->getCullingMode() != CULL_CLOCKWISE)
02573             {
02574                 CullingMode hcm = pPass->getCullingMode();
02575                 writeAttribute(3, "cull_hardware");
02576                 switch (hcm)
02577                 {
02578                 case CULL_NONE :
02579                     writeValue("none");
02580                     break;
02581                 case CULL_CLOCKWISE :
02582                     writeValue("clockwise");
02583                     break;
02584                 case CULL_ANTICLOCKWISE :
02585                     writeValue("anticlockwise");
02586                     break;
02587                 }
02588             }
02589 
02590             // software culling mode
02591             if (mDefaults || 
02592                 pPass->getManualCullingMode() != MANUAL_CULL_BACK)
02593             {
02594                 ManualCullingMode scm = pPass->getManualCullingMode();
02595                 writeAttribute(3, "cull_software");
02596                 switch (scm)
02597                 {
02598                 case MANUAL_CULL_NONE :
02599                     writeValue("none");
02600                     break;
02601                 case MANUAL_CULL_BACK :
02602                     writeValue("back");
02603                     break;
02604                 case MANUAL_CULL_FRONT :
02605                     writeValue("front");
02606                     break;
02607                 }
02608             }
02609 
02610             //shading
02611             if (mDefaults || 
02612                 pPass->getShadingMode() != SO_GOURAUD)
02613             {
02614                 writeAttribute(3, "shading");
02615                 switch (pPass->getShadingMode())
02616                 {
02617                 case SO_FLAT:
02618                     writeValue("flat");
02619                     break;
02620                 case SO_GOURAUD:
02621                     writeValue("gouraud");
02622                     break;
02623                 case SO_PHONG:
02624                     writeValue("phong");
02625                     break;
02626                 }
02627             }
02628 
02629 
02630             //fog override
02631             if (mDefaults || 
02632                 pPass->getFogOverride() != false)
02633             {
02634                 writeAttribute(3, "fog_override");
02635                 writeValue(pPass->getFogOverride() ? "true" : "false");
02636                 if (pPass->getFogOverride())
02637                 {
02638                     switch (pPass->getFogMode())
02639                     {
02640                     case FOG_NONE:
02641                         writeValue("none");
02642                         break;
02643                     case FOG_LINEAR:
02644                         writeValue("linear");
02645                         break;
02646                     case FOG_EXP2:
02647                         writeValue("exp2");
02648                         break;
02649                     case FOG_EXP:
02650                         writeValue("exp");
02651                         break;
02652                     }
02653 
02654                     if (pPass->getFogMode() != FOG_NONE)
02655                     {
02656                         writeColourValue(pPass->getFogColour());
02657                         writeValue(StringConverter::toString(pPass->getFogDensity()));
02658                         writeValue(StringConverter::toString(pPass->getFogStart()));
02659                         writeValue(StringConverter::toString(pPass->getFogEnd()));
02660                     }
02661                 }
02662             }
02663 
02664             // Nested texture layers
02665             Pass::TextureUnitStateIterator it = const_cast<Pass*>(pPass)->getTextureUnitStateIterator();
02666             while(it.hasMoreElements())
02667             {
02668                 writeTextureUnit(it.getNext());
02669             }
02670         }
02671         endSection(2);
02672         LogManager::getSingleton().logMessage("MaterialSerializer : done.", LML_CRITICAL);
02673     }
02674     //-----------------------------------------------------------------------
02675     String MaterialSerializer::convertFiltering(FilterOptions fo)
02676     {
02677         switch (fo)
02678         {
02679         case FO_NONE:
02680             return "none";
02681         case FO_POINT:
02682             return "point";
02683         case FO_LINEAR:
02684             return "linear";
02685         case FO_ANISOTROPIC:
02686             return "anisotropic";
02687         }
02688 
02689         return "point";
02690     }
02691     //-----------------------------------------------------------------------
02692     void MaterialSerializer::writeTextureUnit(const TextureUnitState *pTex)
02693     {
02694         LogManager::getSingleton().logMessage("MaterialSerializer : parsing texture layer.", LML_CRITICAL);
02695         mBuffer += "\n";
02696         writeAttribute(3, "texture_unit");
02697         beginSection(3);
02698         {
02699             //texture name
02700             if (pTex->getNumFrames() == 1 && pTex->getTextureName() != "" && !pTex->isCubic())
02701             {
02702                 writeAttribute(4, "texture");
02703                 writeValue(pTex->getTextureName());
02704                 switch (pTex->getTextureType())
02705                 {
02706                 case TEX_TYPE_1D:
02707                     writeValue("1d");
02708                     break;
02709                 case TEX_TYPE_2D:
02710                     // nothing, this is the default
02711                     break;
02712                 case TEX_TYPE_3D:
02713                     writeValue("3d");
02714                     break;
02715                 case TEX_TYPE_CUBE_MAP:
02716                     // nothing, deal with this as cubic_texture since it copes with all variants
02717                     break;
02718                 default:
02719                     break;
02720                 };
02721             }
02722 
02723             //anim. texture
02724             if (pTex->getNumFrames() > 1 && !pTex->isCubic())
02725             {
02726                 writeAttribute(4, "anim_texture");
02727                 for (unsigned int n = 0; n < pTex->getNumFrames(); n++)
02728                     writeValue(pTex->getFrameTextureName(n));
02729                 writeValue(StringConverter::toString(pTex->getAnimationDuration()));
02730             }
02731 
02732             //cubic texture
02733             if (pTex->isCubic())
02734             {
02735                 writeAttribute(4, "cubic_texture");
02736                 for (unsigned int n = 0; n < pTex->getNumFrames(); n++)
02737                     writeValue(pTex->getFrameTextureName(n));
02738 
02739                 //combinedUVW/separateUW
02740                 if (pTex->getTextureType() == TEX_TYPE_CUBE_MAP)
02741                     writeValue("combinedUVW");
02742                 else
02743                     writeValue("separateUV");
02744             }
02745 
02746             //anisotropy level
02747             if (mDefaults || 
02748                 pTex->getTextureAnisotropy() != 1)
02749             {
02750                 writeAttribute(4, "max_anisotropy");
02751                 writeValue(StringConverter::toString(pTex->getTextureAnisotropy()));
02752             }
02753 
02754             //texture coordinate set
02755             if (mDefaults || 
02756                 pTex->getTextureCoordSet() != 0)
02757             {
02758                 writeAttribute(4, "tex_coord_set");
02759                 writeValue(StringConverter::toString(pTex->getTextureCoordSet()));
02760             }
02761 
02762             //addressing mode
02763             if (mDefaults || 
02764                 pTex->getTextureAddressingMode() != Ogre::TextureUnitState::TAM_WRAP)
02765             {
02766                 writeAttribute(4, "tex_address_mode");
02767                 switch (pTex->getTextureAddressingMode())
02768                 {
02769                 case Ogre::TextureUnitState::TAM_CLAMP:
02770                     writeValue("clamp");
02771                     break;
02772                 case Ogre::TextureUnitState::TAM_MIRROR:
02773                     writeValue("mirror");
02774                     break;
02775                 case Ogre::TextureUnitState::TAM_WRAP:
02776                     writeValue("wrap");
02777                     break;
02778                 }
02779             }
02780 
02781             //filtering
02782             if (mDefaults || 
02783                 pTex->getTextureFiltering(FT_MIN) != FO_LINEAR ||
02784                 pTex->getTextureFiltering(FT_MAG) != FO_LINEAR ||
02785                 pTex->getTextureFiltering(FT_MIP) != FO_POINT)
02786             {
02787                 writeAttribute(4, "filtering");
02788                 writeValue(
02789                     convertFiltering(pTex->getTextureFiltering(FT_MIN))
02790                     + " "
02791                     + convertFiltering(pTex->getTextureFiltering(FT_MAG))
02792                     + " "
02793                     + convertFiltering(pTex->getTextureFiltering(FT_MIP)));
02794             }
02795 
02796             // alpha_rejection
02797             if (mDefaults || 
02798                 pTex->getAlphaRejectFunction() != CMPF_ALWAYS_PASS ||
02799                 pTex->getAlphaRejectValue() != 0)
02800             {
02801                 writeAttribute(4, "alpha_rejection");
02802                 writeCompareFunction(pTex->getAlphaRejectFunction());
02803                 writeValue(StringConverter::toString(pTex->getAlphaRejectValue()));
02804             }
02805 
02806             // colour_op_ex
02807             if (mDefaults || 
02808                 pTex->getColourBlendMode().operation != LBX_MODULATE ||
02809                 pTex->getColourBlendMode().source1 != LBS_TEXTURE ||
02810                 pTex->getColourBlendMode().source2 != LBS_CURRENT)
02811             {
02812                 writeAttribute(4, "colour_op_ex");
02813                 writeLayerBlendOperationEx(pTex->getColourBlendMode().operation);
02814                 writeLayerBlendSource(pTex->getColourBlendMode().source1);
02815                 writeLayerBlendSource(pTex->getColourBlendMode().source2);
02816                 if (pTex->getColourBlendMode().operation == LBX_BLEND_MANUAL)
02817                     writeValue(StringConverter::toString(pTex->getColourBlendMode().factor));
02818                 if (pTex->getColourBlendMode().source1 == LBS_MANUAL)
02819                     writeColourValue(pTex->getColourBlendMode().colourArg1, false);
02820                 if (pTex->getColourBlendMode().source2 == LBS_MANUAL)
02821                     writeColourValue(pTex->getColourBlendMode().colourArg2, false);
02822 
02823                 //colour_op_multipass_fallback
02824                 writeAttribute(4, "colour_op_multipass_fallback");
02825                 writeSceneBlendFactor(pTex->getColourBlendFallbackSrc());
02826                 writeSceneBlendFactor(pTex->getColourBlendFallbackDest());
02827             }
02828 
02829             // alpha_op_ex
02830             if (mDefaults || 
02831                 pTex->getAlphaBlendMode().operation != LBX_MODULATE ||
02832                 pTex->getAlphaBlendMode().source1 != LBS_TEXTURE ||
02833                 pTex->getAlphaBlendMode().source2 != LBS_CURRENT)
02834             {
02835                 writeAttribute(4, "alpha_op_ex");
02836                 writeLayerBlendOperationEx(pTex->getAlphaBlendMode().operation);
02837                 writeLayerBlendSource(pTex->getAlphaBlendMode().source1);
02838                 writeLayerBlendSource(pTex->getAlphaBlendMode().source2);
02839                 if (pTex->getAlphaBlendMode().operation == LBX_BLEND_MANUAL)
02840                     writeValue(StringConverter::toString(pTex->getAlphaBlendMode().factor));
02841                 else if (pTex->getAlphaBlendMode().source1 == LBS_MANUAL)
02842                     writeValue(StringConverter::toString(pTex->getAlphaBlendMode().alphaArg1));
02843                 else if (pTex->getAlphaBlendMode().source2 == LBS_MANUAL)
02844                     writeValue(StringConverter::toString(pTex->getAlphaBlendMode().alphaArg2));
02845             }
02846 
02847             // rotate
02848             if (mDefaults ||
02849                 pTex->getTextureRotate() != Radian(0))
02850             {
02851                 writeAttribute(4, "rotate");
02852                 writeValue(StringConverter::toString(pTex->getTextureRotate().valueDegrees()));
02853             }
02854 
02855             // scroll
02856             if (mDefaults ||
02857                 pTex->getTextureUScroll() != 0 || 
02858                 pTex->getTextureVScroll() != 0 )
02859             {
02860                 writeAttribute(4, "scroll");
02861                 writeValue(StringConverter::toString(pTex->getTextureUScroll()));
02862                 writeValue(StringConverter::toString(pTex->getTextureVScroll()));
02863             }
02864             // scale
02865             if (mDefaults ||
02866                 pTex->getTextureUScale() != 1.0 || 
02867                 pTex->getTextureVScale() != 1.0 )
02868             {
02869                 writeAttribute(4, "scale");
02870                 writeValue(StringConverter::toString(pTex->getTextureUScale()));
02871                 writeValue(StringConverter::toString(pTex->getTextureVScale()));
02872             }
02873 
02874             EffectMap m_ef = pTex->getEffects();
02875             if (!m_ef.empty())
02876             {
02877                 EffectMap::const_iterator it;
02878                 for (it = m_ef.begin(); it != m_ef.end(); ++it)
02879                 {
02880                     const TextureUnitState::TextureEffect& ef = it->second;
02881                     switch (ef.type)
02882                     {
02883                     case TextureUnitState::ET_ENVIRONMENT_MAP :
02884                         writeEnvironmentMapEffect(ef, pTex);
02885                         break;
02886                     case TextureUnitState::ET_ROTATE :
02887                         writeRotationEffect(ef, pTex);
02888                         break;
02889                     case TextureUnitState::ET_SCROLL :
02890                         writeScrollEffect(ef, pTex);
02891                         break;
02892                     case TextureUnitState::ET_TRANSFORM :
02893                         writeTransformEffect(ef, pTex);
02894                         break;
02895                     default:
02896                         break;
02897                     }
02898                 }
02899             }
02900         }
02901         endSection(3);
02902 
02903     }
02904     //-----------------------------------------------------------------------
02905     void MaterialSerializer::writeEnvironmentMapEffect(const TextureUnitState::TextureEffect& effect, const TextureUnitState *pTex)
02906     {
02907         writeAttribute(4, "env_map");
02908         switch (effect.subtype)
02909         {
02910         case TextureUnitState::ENV_PLANAR:
02911             writeValue("planar");
02912             break;
02913         case TextureUnitState::ENV_CURVED:
02914             writeValue("spherical");
02915             break;
02916         case TextureUnitState::ENV_NORMAL:
02917             writeValue("cubic_normal");
02918             break;
02919         case TextureUnitState::ENV_REFLECTION:
02920             writeValue("cubic_reflection");
02921             break;
02922         }
02923     }
02924     //-----------------------------------------------------------------------
02925     void MaterialSerializer::writeRotationEffect(const TextureUnitState::TextureEffect& effect, const TextureUnitState *pTex)
02926     {
02927         if (effect.arg1)
02928         {
02929             writeAttribute(4, "rotate_anim");
02930             writeValue(StringConverter::toString(effect.arg1));
02931         }
02932     }
02933     //-----------------------------------------------------------------------
02934     void MaterialSerializer::writeTransformEffect(const TextureUnitState::TextureEffect& effect, const TextureUnitState *pTex)
02935     {
02936         writeAttribute(4, "wave_xform");
02937 
02938         switch (effect.subtype)
02939         {
02940         case TextureUnitState::TT_ROTATE:
02941             writeValue("rotate");
02942             break;
02943         case TextureUnitState::TT_SCALE_U:
02944             writeValue("scale_x");
02945             break;
02946         case TextureUnitState::TT_SCALE_V:
02947             writeValue("scale_y");
02948             break;
02949         case TextureUnitState::TT_TRANSLATE_U:
02950             writeValue("scroll_x");
02951             break;
02952         case TextureUnitState::TT_TRANSLATE_V:
02953             writeValue("scroll_y");
02954             break;
02955         }
02956 
02957         switch (effect.waveType)
02958         {
02959         case WFT_INVERSE_SAWTOOTH:
02960             writeValue("inverse_sawtooth");
02961             break;
02962         case WFT_SAWTOOTH:
02963             writeValue("sawtooth");
02964             break;
02965         case WFT_SINE:
02966             writeValue("sine");
02967             break;
02968         case WFT_SQUARE:
02969             writeValue("square");
02970             break;
02971         case WFT_TRIANGLE:
02972             writeValue("triangle");
02973             break;
02974         }
02975 
02976         writeValue(StringConverter::toString(effect.base));
02977         writeValue(StringConverter::toString(effect.frequency));
02978         writeValue(StringConverter::toString(effect.phase));
02979         writeValue(StringConverter::toString(effect.amplitude));
02980     }
02981     //-----------------------------------------------------------------------
02982     void MaterialSerializer::writeScrollEffect(const TextureUnitState::TextureEffect& effect, const TextureUnitState *pTex)
02983     {
02984         if (effect.arg1 || effect.arg2)
02985         {
02986             writeAttribute(4, "scroll_anim");
02987             writeValue(StringConverter::toString(effect.arg1));
02988             writeValue(StringConverter::toString(effect.arg2));
02989         }
02990     }
02991     //-----------------------------------------------------------------------
02992     void MaterialSerializer::writeSceneBlendFactor(const SceneBlendFactor sbf)
02993     {
02994         switch (sbf)
02995         {
02996         case SBF_DEST_ALPHA:
02997             writeValue("dest_alpha");
02998             break;
02999         case SBF_DEST_COLOUR:
03000             writeValue("dest_colour");
03001             break;
03002         case SBF_ONE:
03003             writeValue("one");
03004             break;
03005         case SBF_ONE_MINUS_DEST_ALPHA:
03006             writeValue("one_minus_dest_alpha");
03007             break;
03008         case SBF_ONE_MINUS_DEST_COLOUR:
03009             writeValue("one_minus_dest_colour");
03010             break;
03011         case SBF_ONE_MINUS_SOURCE_ALPHA:
03012             writeValue("one_minus_src_alpha");
03013             break;
03014         case SBF_ONE_MINUS_SOURCE_COLOUR:
03015             writeValue("one_minus_src_colour");
03016             break;
03017         case SBF_SOURCE_ALPHA:
03018             writeValue("src_alpha");
03019             break;
03020         case SBF_SOURCE_COLOUR:
03021             writeValue("src_colour");
03022             break;
03023         case SBF_ZERO:
03024             writeValue("zero");
03025             break;
03026         }
03027     }
03028     //-----------------------------------------------------------------------
03029     void MaterialSerializer::writeSceneBlendFactor(const SceneBlendFactor sbf_src, const SceneBlendFactor sbf_dst)
03030     {
03031         if (sbf_src == SBF_ONE && sbf_dst == SBF_ONE )
03032             writeValue("add");
03033         else if (sbf_src == SBF_SOURCE_COLOUR && sbf_dst == SBF_ONE_MINUS_SOURCE_COLOUR)
03034             writeValue("modulate");
03035         else if (sbf_src == SBF_SOURCE_ALPHA && sbf_dst == SBF_ONE_MINUS_SOURCE_ALPHA)
03036             writeValue("alpha_blend");
03037         else
03038         {
03039             writeSceneBlendFactor(sbf_src);
03040             writeSceneBlendFactor(sbf_dst);
03041         }
03042     }
03043     //-----------------------------------------------------------------------
03044     void MaterialSerializer::writeCompareFunction(const CompareFunction cf)
03045     {
03046         switch (cf)
03047         {
03048         case CMPF_ALWAYS_FAIL:
03049             writeValue("always_fail");
03050             break;
03051         case CMPF_ALWAYS_PASS:
03052             writeValue("always_pass");
03053             break;
03054         case CMPF_EQUAL:
03055             writeValue("equal");
03056             break;
03057         case CMPF_GREATER:
03058             writeValue("greater");
03059             break;
03060         case CMPF_GREATER_EQUAL:
03061             writeValue("greater_equal");
03062             break;
03063         case CMPF_LESS:
03064             writeValue("less");
03065             break;
03066         case CMPF_LESS_EQUAL:
03067             writeValue("less_equal");
03068             break;
03069         case CMPF_NOT_EQUAL:
03070             writeValue("not_equal");
03071             break;
03072         }
03073     }
03074     //-----------------------------------------------------------------------
03075     void MaterialSerializer::writeColourValue(const ColourValue &colour, bool writeAlpha)
03076     {
03077         writeValue(StringConverter::toString(colour.r));
03078         writeValue(StringConverter::toString(colour.g));
03079         writeValue(StringConverter::toString(colour.b));
03080         if (writeAlpha)
03081             writeValue(StringConverter::toString(colour.a));
03082     }
03083     //-----------------------------------------------------------------------
03084     void MaterialSerializer::writeLayerBlendOperationEx(const LayerBlendOperationEx op)
03085     {
03086         switch (op)
03087         {
03088         case LBX_ADD:
03089             writeValue("add");
03090             break;
03091         case LBX_ADD_SIGNED:
03092             writeValue("add_signed");
03093             break;
03094         case LBX_ADD_SMOOTH:
03095             writeValue("add_smooth");
03096             break;
03097         case LBX_BLEND_CURRENT_ALPHA:
03098             writeValue("blend_current_alpha");
03099             break;
03100         case LBX_BLEND_DIFFUSE_ALPHA:
03101             writeValue("blend_diffuse_alpha");
03102             break;
03103         case LBX_BLEND_MANUAL:
03104             writeValue("blend_manual");
03105             break;
03106         case LBX_BLEND_TEXTURE_ALPHA:
03107             writeValue("blend_texture_alpha");
03108             break;
03109         case LBX_MODULATE:
03110             writeValue("modulate");
03111             break;
03112         case LBX_MODULATE_X2:
03113             writeValue("modulate_x2");
03114             break;
03115         case LBX_MODULATE_X4:
03116             writeValue("modulate_x4");
03117             break;
03118         case LBX_SOURCE1:
03119             writeValue("source1");
03120             break;
03121         case LBX_SOURCE2:
03122             writeValue("source2");
03123             break;
03124         case LBX_SUBTRACT:
03125             writeValue("subtract");
03126             break;
03127         case LBX_DOTPRODUCT:
03128             writeValue("dotproduct");
03129             break;
03130         }
03131     }
03132     //-----------------------------------------------------------------------
03133     void MaterialSerializer::writeLayerBlendSource(const LayerBlendSource lbs)
03134     {
03135         switch (lbs)
03136         {
03137         case LBS_CURRENT:
03138             writeValue("src_current");
03139             break;
03140         case LBS_DIFFUSE:
03141             writeValue("src_diffuse");
03142             break;
03143         case LBS_MANUAL:
03144             writeValue("src_manual");
03145             break;
03146         case LBS_SPECULAR:
03147             writeValue("src_specular");
03148             break;
03149         case LBS_TEXTURE:
03150             writeValue("src_texture");
03151             break;
03152         }
03153     }
03154 }

Copyright © 2002-2003 by The OGRE Team
Last modified Sun Nov 28 19:48:32 2004