source: OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/src/OgreMaterialSerializer.cpp @ 768

Revision 768, 170.1 KB checked in by szirmay, 18 years ago (diff)
Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4(Object-oriented Graphics Rendering Engine)
5For the latest info, see http://ogre.sourceforge.net/
6
7Copyright (c) 2000-2005 The OGRE Team
8Also see acknowledgements in Readme.html
9
10This program is free software; you can redistribute it and/or modify it under
11the terms of the GNU Lesser General Public License as published by the Free Software
12Foundation; either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public License along with
20this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://www.gnu.org/copyleft/lesser.txt.
23-----------------------------------------------------------------------------
24*/
25#include "OgreStableHeaders.h"
26
27#include "OgreMaterialSerializer.h"
28#include "OgreStringConverter.h"
29#include "OgreLogManager.h"
30#include "OgreException.h"
31#include "OgreTechnique.h"
32#include "OgrePass.h"
33#include "OgreTextureUnitState.h"
34#include "OgreMaterialManager.h"
35#include "OgreGpuProgramManager.h"
36#include "OgreHighLevelGpuProgramManager.h"
37#include "OgreExternalTextureSourceManager.h"
38
39namespace Ogre
40{
41
42    //-----------------------------------------------------------------------
43    // Internal parser methods
44    //-----------------------------------------------------------------------
45    void logParseError(const String& error, const MaterialScriptContext& context)
46    {
47        // log material name only if filename not specified
48        if (context.filename.empty() && !context.material.isNull())
49        {
50            LogManager::getSingleton().logMessage(
51                "Error in material " + context.material->getName() +
52                " : " + error);
53        }
54        else
55        {
56            if (!context.material.isNull())
57            {
58                LogManager::getSingleton().logMessage(
59                    "Error in material " + context.material->getName() +
60                    " at line " + StringConverter::toString(context.lineNo) +
61                    " of " + context.filename + ": " + error);
62            }
63            else
64            {
65                LogManager::getSingleton().logMessage(
66                    "Error at line " + StringConverter::toString(context.lineNo) +
67                    " of " + context.filename + ": " + error);
68            }
69        }
70    }
71    //-----------------------------------------------------------------------
72    ColourValue _parseColourValue(StringVector& vecparams)
73    {
74        return ColourValue(
75            StringConverter::parseReal(vecparams[0]) ,
76            StringConverter::parseReal(vecparams[1]) ,
77            StringConverter::parseReal(vecparams[2]) ,
78            (vecparams.size()==4) ? StringConverter::parseReal(vecparams[3]) : 1.0f ) ;
79    }
80    //-----------------------------------------------------------------------
81    FilterOptions convertFiltering(const String& s)
82    {
83        if (s == "none")
84        {
85            return FO_NONE;
86        }
87        else if (s == "point")
88        {
89            return FO_POINT;
90        }
91        else if (s == "linear")
92        {
93            return FO_LINEAR;
94        }
95        else if (s == "anisotropic")
96        {
97            return FO_ANISOTROPIC;
98        }
99
100        return FO_POINT;
101    }
102    //-----------------------------------------------------------------------
103    bool parseAmbient(String& params, MaterialScriptContext& context)
104    {
105        StringVector vecparams = StringUtil::split(params, " \t");
106        // Must be 1, 3 or 4 parameters
107        if (vecparams.size() == 1) {
108            if(vecparams[0] == "vertexcolour") {
109               context.pass->setVertexColourTracking(context.pass->getVertexColourTracking() | TVC_AMBIENT);
110            } else {
111                logParseError(
112                    "Bad ambient attribute, single parameter flag must be 'vertexcolour'",
113                    context);
114            }
115        }
116        else if (vecparams.size() == 3 || vecparams.size() == 4)
117        {
118            context.pass->setAmbient( _parseColourValue(vecparams) );
119            context.pass->setVertexColourTracking(context.pass->getVertexColourTracking() & ~TVC_AMBIENT);
120        }
121        else
122        {
123            logParseError(
124                "Bad ambient attribute, wrong number of parameters (expected 1, 3 or 4)",
125                context);
126        }
127        return false;
128    }
129   //-----------------------------------------------------------------------
130    bool parseDiffuse(String& params, MaterialScriptContext& context)
131    {
132        StringVector vecparams = StringUtil::split(params, " \t");
133        // Must be 1, 3 or 4 parameters
134        if (vecparams.size() == 1) {
135            if(vecparams[0] == "vertexcolour") {
136               context.pass->setVertexColourTracking(context.pass->getVertexColourTracking() | TVC_DIFFUSE);
137            } else {
138                logParseError(
139                    "Bad diffuse attribute, single parameter flag must be 'vertexcolour'",
140                    context);
141            }
142        }
143        else if (vecparams.size() == 3 || vecparams.size() == 4)
144        {
145            context.pass->setDiffuse( _parseColourValue(vecparams) );
146            context.pass->setVertexColourTracking(context.pass->getVertexColourTracking() & ~TVC_DIFFUSE);
147        }
148        else
149        {
150            logParseError(
151                "Bad diffuse attribute, wrong number of parameters (expected 1, 3 or 4)",
152                context);
153        }        return false;
154    }
155    //-----------------------------------------------------------------------
156    bool parseSpecular(String& params, MaterialScriptContext& context)
157    {
158        StringVector vecparams = StringUtil::split(params, " \t");
159        // Must be 2, 4 or 5 parameters
160        if(vecparams.size() == 2)
161        {   
162            if(vecparams[0] == "vertexcolour") {
163                context.pass->setVertexColourTracking(context.pass->getVertexColourTracking() | TVC_SPECULAR);
164                context.pass->setShininess(StringConverter::parseReal(vecparams[1]) );
165            }
166            else
167            {
168                logParseError(
169                    "Bad specular attribute, double parameter statement must be 'vertexcolour <shininess>'",
170                    context);
171            }
172        }
173        else if(vecparams.size() == 4 || vecparams.size() == 5)
174        {
175            context.pass->setSpecular(
176                StringConverter::parseReal(vecparams[0]),
177                StringConverter::parseReal(vecparams[1]),
178                StringConverter::parseReal(vecparams[2]),
179                vecparams.size() == 5?
180                    StringConverter::parseReal(vecparams[3]) : 1.0f);
181            context.pass->setVertexColourTracking(context.pass->getVertexColourTracking() & ~TVC_SPECULAR);
182            context.pass->setShininess(
183                StringConverter::parseReal(vecparams[vecparams.size() - 1]) );
184        }
185        else
186        {
187            logParseError(
188                "Bad specular attribute, wrong number of parameters (expected 2, 4 or 5)",
189                context);
190        }
191        return false;
192    }
193    //-----------------------------------------------------------------------
194    bool parseEmissive(String& params, MaterialScriptContext& context)
195    {
196        StringVector vecparams = StringUtil::split(params, " \t");
197        // Must be 1, 3 or 4 parameters
198        if (vecparams.size() == 1) {
199            if(vecparams[0] == "vertexcolour") {
200               context.pass->setVertexColourTracking(context.pass->getVertexColourTracking() | TVC_EMISSIVE);
201            } else {
202                logParseError(
203                    "Bad emissive attribute, single parameter flag must be 'vertexcolour'",
204                    context);
205            }
206        }
207        else if (vecparams.size() == 3 || vecparams.size() == 4)
208        {
209            context.pass->setSelfIllumination( _parseColourValue(vecparams) );
210            context.pass->setVertexColourTracking(context.pass->getVertexColourTracking() & ~TVC_EMISSIVE);
211        }
212        else
213        {
214            logParseError(
215                "Bad emissive attribute, wrong number of parameters (expected 1, 3 or 4)",
216                context);
217        }
218        return false;
219    }
220    //-----------------------------------------------------------------------
221    SceneBlendFactor convertBlendFactor(const String& param)
222    {
223        if (param == "one")
224            return SBF_ONE;
225        else if (param == "zero")
226            return SBF_ZERO;
227        else if (param == "dest_colour")
228            return SBF_DEST_COLOUR;
229        else if (param == "src_colour")
230            return SBF_SOURCE_COLOUR;
231        else if (param == "one_minus_dest_colour")
232            return SBF_ONE_MINUS_DEST_COLOUR;
233        else if (param == "one_minus_src_colour")
234            return SBF_ONE_MINUS_SOURCE_COLOUR;
235        else if (param == "dest_alpha")
236            return SBF_DEST_ALPHA;
237        else if (param == "src_alpha")
238            return SBF_SOURCE_ALPHA;
239        else if (param == "one_minus_dest_alpha")
240            return SBF_ONE_MINUS_DEST_ALPHA;
241        else if (param == "one_minus_src_alpha")
242            return SBF_ONE_MINUS_SOURCE_ALPHA;
243        else
244        {
245            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Invalid blend factor.", "convertBlendFactor");
246        }
247
248
249    }
250    //-----------------------------------------------------------------------
251    bool parseSceneBlend(String& params, MaterialScriptContext& context)
252    {
253        StringUtil::toLowerCase(params);
254        StringVector vecparams = StringUtil::split(params, " \t");
255        // Should be 1 or 2 params
256        if (vecparams.size() == 1)
257        {
258            //simple
259            SceneBlendType stype;
260            if (vecparams[0] == "add")
261                stype = SBT_ADD;
262            else if (vecparams[0] == "modulate")
263                stype = SBT_MODULATE;
264                        else if (vecparams[0] == "colour_blend")
265                                stype = SBT_TRANSPARENT_COLOUR;
266            else if (vecparams[0] == "alpha_blend")
267                stype = SBT_TRANSPARENT_ALPHA;
268            else
269            {
270                logParseError(
271                    "Bad scene_blend attribute, unrecognised parameter '" + vecparams[0] + "'",
272                    context);
273                return false;
274            }
275            context.pass->setSceneBlending(stype);
276
277        }
278        else if (vecparams.size() == 2)
279        {
280            //src/dest
281            SceneBlendFactor src, dest;
282
283            try {
284                src = convertBlendFactor(vecparams[0]);
285                dest = convertBlendFactor(vecparams[1]);
286                context.pass->setSceneBlending(src,dest);
287            }
288            catch (Exception& e)
289            {
290                logParseError("Bad scene_blend attribute, " + e.getFullDescription(), context);
291            }
292
293        }
294        else
295        {
296            logParseError(
297                "Bad scene_blend attribute, wrong number of parameters (expected 1 or 2)",
298                context);
299        }
300
301        return false;
302
303    }
304    //-----------------------------------------------------------------------
305    CompareFunction convertCompareFunction(const String& param)
306    {
307        if (param == "always_fail")
308            return CMPF_ALWAYS_FAIL;
309        else if (param == "always_pass")
310            return CMPF_ALWAYS_PASS;
311        else if (param == "less")
312            return CMPF_LESS;
313        else if (param == "less_equal")
314            return CMPF_LESS_EQUAL;
315        else if (param == "equal")
316            return CMPF_EQUAL;
317        else if (param == "not_equal")
318            return CMPF_NOT_EQUAL;
319        else if (param == "greater_equal")
320            return CMPF_GREATER_EQUAL;
321        else if (param == "greater")
322            return CMPF_GREATER;
323        else
324            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Invalid compare function", "convertCompareFunction");
325
326    }
327    //-----------------------------------------------------------------------
328    bool parseDepthCheck(String& params, MaterialScriptContext& context)
329    {
330        StringUtil::toLowerCase(params);
331        if (params == "on")
332            context.pass->setDepthCheckEnabled(true);
333        else if (params == "off")
334            context.pass->setDepthCheckEnabled(false);
335        else
336            logParseError(
337            "Bad depth_check attribute, valid parameters are 'on' or 'off'.",
338            context);
339
340        return false;
341    }
342    //-----------------------------------------------------------------------
343    bool parseDepthWrite(String& params, MaterialScriptContext& context)
344    {
345        StringUtil::toLowerCase(params);
346        if (params == "on")
347            context.pass->setDepthWriteEnabled(true);
348        else if (params == "off")
349            context.pass->setDepthWriteEnabled(false);
350        else
351            logParseError(
352                "Bad depth_write attribute, valid parameters are 'on' or 'off'.",
353                context);
354        return false;
355    }
356
357    //-----------------------------------------------------------------------
358    bool parseDepthFunc(String& params, MaterialScriptContext& context)
359    {
360        StringUtil::toLowerCase(params);
361        try {
362            CompareFunction func = convertCompareFunction(params);
363            context.pass->setDepthFunction(func);
364        }
365        catch (...)
366        {
367            logParseError("Bad depth_func attribute, invalid function parameter.", context);
368        }
369
370        return false;
371    }
372    //-----------------------------------------------------------------------
373    bool parseColourWrite(String& params, MaterialScriptContext& context)
374    {
375        StringUtil::toLowerCase(params);
376        if (params == "on")
377            context.pass->setColourWriteEnabled(true);
378        else if (params == "off")
379            context.pass->setColourWriteEnabled(false);
380        else
381            logParseError(
382                "Bad colour_write attribute, valid parameters are 'on' or 'off'.",
383                context);
384        return false;
385    }
386
387    //-----------------------------------------------------------------------
388    bool parseCullHardware(String& params, MaterialScriptContext& context)
389    {
390        StringUtil::toLowerCase(params);
391        if (params=="none")
392            context.pass->setCullingMode(CULL_NONE);
393        else if (params=="anticlockwise")
394            context.pass->setCullingMode(CULL_ANTICLOCKWISE);
395        else if (params=="clockwise")
396            context.pass->setCullingMode(CULL_CLOCKWISE);
397        else
398            logParseError(
399                "Bad cull_hardware attribute, valid parameters are "
400                "'none', 'clockwise' or 'anticlockwise'.", context);
401        return false;
402    }
403    //-----------------------------------------------------------------------
404    bool parseCullSoftware(String& params, MaterialScriptContext& context)
405    {
406        StringUtil::toLowerCase(params);
407        if (params=="none")
408            context.pass->setManualCullingMode(MANUAL_CULL_NONE);
409        else if (params=="back")
410            context.pass->setManualCullingMode(MANUAL_CULL_BACK);
411        else if (params=="front")
412            context.pass->setManualCullingMode(MANUAL_CULL_FRONT);
413        else
414            logParseError(
415                "Bad cull_software attribute, valid parameters are 'none', "
416                "'front' or 'back'.", context);
417        return false;
418    }
419    //-----------------------------------------------------------------------
420    bool parseLighting(String& params, MaterialScriptContext& context)
421    {
422        StringUtil::toLowerCase(params);
423        if (params=="on")
424            context.pass->setLightingEnabled(true);
425        else if (params=="off")
426            context.pass->setLightingEnabled(false);
427        else
428            logParseError(
429                "Bad lighting attribute, valid parameters are 'on' or 'off'.", context);
430        return false;
431    }
432    //-----------------------------------------------------------------------
433    bool parseMaxLights(String& params, MaterialScriptContext& context)
434    {
435                context.pass->setMaxSimultaneousLights(StringConverter::parseInt(params));
436        return false;
437    }
438    //-----------------------------------------------------------------------
439    void parseIterationLightTypes(String& params, MaterialScriptContext& context)
440    {
441        // Parse light type
442        if (params == "directional")
443        {
444            context.pass->setIteratePerLight(true, true, Light::LT_DIRECTIONAL);
445        }
446        else if (params == "point")
447        {
448            context.pass->setIteratePerLight(true, true, Light::LT_POINT);
449        }
450        else if (params == "spot")
451        {
452            context.pass->setIteratePerLight(true, true, Light::LT_SPOTLIGHT);
453        }
454        else
455        {
456            logParseError("Bad iteration attribute, valid values for light type parameter "
457                "are 'point' or 'directional' or 'spot'.", context);
458        }
459
460    }
461    //-----------------------------------------------------------------------
462    bool parseIteration(String& params, MaterialScriptContext& context)
463    {
464        // we could have more than one parameter
465        /** combinations could be:
466            iteration once
467            iteration once_per_light [light type]
468            iteration <number>
469            iteration <number> [per_light] [light type]
470        */
471        StringUtil::toLowerCase(params);
472        StringVector vecparams = StringUtil::split(params, " \t");
473        if (vecparams.size() < 1 || vecparams.size() > 3)
474        {
475            logParseError("Bad iteration attribute, expected 1 to 3 parameters.", context);
476            return false;
477        }
478
479        if (vecparams[0]=="once")
480            context.pass->setIteratePerLight(false);
481        else if (vecparams[0]=="once_per_light")
482        {
483            if (vecparams.size() == 2)
484            {
485                parseIterationLightTypes(vecparams[1], context);
486            }
487            else
488            {
489                context.pass->setIteratePerLight(true, false);
490            }
491
492        }
493        else // could be using form: <number> [per_light] [light type]
494        {
495            int passIterationCount = StringConverter::parseInt(vecparams[0]);
496            if (passIterationCount > 0)
497            {
498                context.pass->setPassIterationCount(passIterationCount);
499                if (vecparams.size() > 1)
500                {
501                    if (vecparams[1] == "per_light")
502                    {
503                        if (vecparams.size() == 3)
504                        {
505                            parseIterationLightTypes(vecparams[2], context);
506                        }
507                        else
508                        {
509                            context.pass->setIteratePerLight(true, false);
510                        }
511                    }
512                    else
513                        logParseError(
514                            "Bad iteration attribute, valid parameters are <number> [per_light] [light type].", context);
515                }
516            }
517            else
518                logParseError(
519                    "Bad iteration attribute, valid parameters are 'once' or 'once_per_light' or <number> [per_light] [light type].", context);
520        }
521        return false;
522    }
523    //-----------------------------------------------------------------------
524    bool parsePointSize(String& params, MaterialScriptContext& context)
525    {
526        context.pass->setPointSize(StringConverter::parseReal(params));
527        return false;
528    }
529    //-----------------------------------------------------------------------
530    bool parsePointSprites(String& params, MaterialScriptContext& context)
531    {
532        if (params=="on")
533                context.pass->setPointSpritesEnabled(true);
534                else if (params=="off")
535                context.pass->setPointSpritesEnabled(false);
536                else
537            logParseError(
538                "Bad point_sprites attribute, valid parameters are 'on' or 'off'.", context);
539
540        return false;
541    }
542    //-----------------------------------------------------------------------
543        bool parsePointAttenuation(String& params, MaterialScriptContext& context)
544        {
545        StringVector vecparams = StringUtil::split(params, " \t");
546        if (vecparams.size() != 1 && vecparams.size() != 4)
547                {
548                        logParseError("Bad point_size_attenuation attribute, 1 or 4 parameters expected", context);
549                        return false;
550                }
551                if (vecparams[0] == "off")
552                {
553                        context.pass->setPointAttenuation(false);
554                }
555                else if (vecparams[0] == "on")
556                {
557                        if (vecparams.size() == 4)
558                        {
559                                context.pass->setPointAttenuation(true,
560                                        StringConverter::parseReal(vecparams[1]),
561                                        StringConverter::parseReal(vecparams[2]),
562                                        StringConverter::parseReal(vecparams[3]));
563                        }
564                        else
565                        {
566                                context.pass->setPointAttenuation(true);
567                        }
568                }
569               
570                return false;
571        }
572    //-----------------------------------------------------------------------
573        bool parsePointSizeMin(String& params, MaterialScriptContext& context)
574        {
575                context.pass->setPointMinSize(
576                        StringConverter::parseReal(params));
577                return false;
578        }
579    //-----------------------------------------------------------------------
580        bool parsePointSizeMax(String& params, MaterialScriptContext& context)
581        {
582                context.pass->setPointMaxSize(
583                        StringConverter::parseReal(params));
584                return false;
585        }
586    //-----------------------------------------------------------------------
587    bool parseFogging(String& params, MaterialScriptContext& context)
588    {
589        StringUtil::toLowerCase(params);
590        StringVector vecparams = StringUtil::split(params, " \t");
591        if (vecparams[0]=="true")
592        {
593            // if true, we need to see if they supplied all arguments, or just the 1... if just the one,
594            // Assume they want to disable the default fog from effecting this material.
595            if( vecparams.size() == 8 )
596            {
597                FogMode mFogtype;
598                if( vecparams[1] == "none" )
599                    mFogtype = FOG_NONE;
600                else if( vecparams[1] == "linear" )
601                    mFogtype = FOG_LINEAR;
602                else if( vecparams[1] == "exp" )
603                    mFogtype = FOG_EXP;
604                else if( vecparams[1] == "exp2" )
605                    mFogtype = FOG_EXP2;
606                else
607                {
608                    logParseError(
609                        "Bad fogging attribute, valid parameters are "
610                        "'none', 'linear', 'exp', or 'exp2'.", context);
611                    return false;
612                }
613
614                context.pass->setFog(
615                    true,
616                    mFogtype,
617                    ColourValue(
618                    StringConverter::parseReal(vecparams[2]),
619                    StringConverter::parseReal(vecparams[3]),
620                    StringConverter::parseReal(vecparams[4])),
621                    StringConverter::parseReal(vecparams[5]),
622                    StringConverter::parseReal(vecparams[6]),
623                    StringConverter::parseReal(vecparams[7])
624                    );
625            }
626            else
627            {
628                context.pass->setFog(true);
629            }
630        }
631        else if (vecparams[0]=="false")
632            context.pass->setFog(false);
633        else
634            logParseError(
635                "Bad fog_override attribute, valid parameters are 'true' or 'false'.",
636                context);
637
638        return false;
639    }
640    //-----------------------------------------------------------------------
641    bool parseShading(String& params, MaterialScriptContext& context)
642    {
643        StringUtil::toLowerCase(params);
644        if (params=="flat")
645            context.pass->setShadingMode(SO_FLAT);
646        else if (params=="gouraud")
647            context.pass->setShadingMode(SO_GOURAUD);
648        else if (params=="phong")
649            context.pass->setShadingMode(SO_PHONG);
650        else
651            logParseError("Bad shading attribute, valid parameters are 'flat', "
652                "'gouraud' or 'phong'.", context);
653
654        return false;
655    }
656        //-----------------------------------------------------------------------
657        bool parsePolygonMode(String& params, MaterialScriptContext& context)
658        {
659                StringUtil::toLowerCase(params);
660                if (params=="solid")
661                        context.pass->setPolygonMode(PM_SOLID);
662                else if (params=="wireframe")
663                        context.pass->setPolygonMode(PM_WIREFRAME);
664                else if (params=="points")
665                        context.pass->setPolygonMode(PM_POINTS);
666                else
667                        logParseError("Bad polygon_mode attribute, valid parameters are 'solid', "
668                        "'wireframe' or 'points'.", context);
669
670                return false;
671        }
672    //-----------------------------------------------------------------------
673    bool parseFiltering(String& params, MaterialScriptContext& context)
674    {
675        StringUtil::toLowerCase(params);
676        StringVector vecparams = StringUtil::split(params, " \t");
677        // Must be 1 or 3 parameters
678        if (vecparams.size() == 1)
679        {
680            // Simple format
681            if (vecparams[0]=="none")
682                context.textureUnit->setTextureFiltering(TFO_NONE);
683            else if (vecparams[0]=="bilinear")
684                context.textureUnit->setTextureFiltering(TFO_BILINEAR);
685            else if (vecparams[0]=="trilinear")
686                context.textureUnit->setTextureFiltering(TFO_TRILINEAR);
687            else if (vecparams[0]=="anisotropic")
688                context.textureUnit->setTextureFiltering(TFO_ANISOTROPIC);
689            else
690            {
691                logParseError("Bad filtering attribute, valid parameters for simple format are "
692                    "'none', 'bilinear', 'trilinear' or 'anisotropic'.", context);
693                return false;
694            }
695        }
696        else if (vecparams.size() == 3)
697        {
698            // Complex format
699            context.textureUnit->setTextureFiltering(
700                convertFiltering(vecparams[0]),
701                convertFiltering(vecparams[1]),
702                convertFiltering(vecparams[2]));
703
704
705        }
706        else
707        {
708            logParseError(
709                "Bad filtering attribute, wrong number of parameters (expected 1 or 3)",
710                context);
711        }
712
713        return false;
714    }
715    //-----------------------------------------------------------------------
716    // Texture layer attributes
717    bool parseTexture(String& params, MaterialScriptContext& context)
718    {
719        StringVector vecparams = StringUtil::split(params, " \t");
720        const size_t numParams = vecparams.size();
721        if (numParams > 4)
722        {
723            logParseError("Invalid texture attribute - expected only 1, 2, 3 or 4 parameters.",
724                context);
725        }
726        TextureType tt = TEX_TYPE_2D;
727                int mips = MIP_UNLIMITED; // When passed to TextureManager::load, this means default to default number of mipmaps
728        bool isAlpha = false;
729        if (numParams >= 2)
730        {
731            StringUtil::toLowerCase(vecparams[1]);
732            if (vecparams[1] == "1d")
733            {
734                tt = TEX_TYPE_1D;
735            }
736            else if (vecparams[1] == "2d")
737            {
738                tt = TEX_TYPE_2D;
739            }
740            else if (vecparams[1] == "3d")
741            {
742                tt = TEX_TYPE_3D;
743            }
744            else if (vecparams[1] == "cubic")
745            {
746                tt = TEX_TYPE_CUBE_MAP;
747            } 
748                        else
749                        {
750                                logParseError("Invalid texture type - "+vecparams[1]+".",
751                context);
752                        }
753        }
754                if (numParams >= 3)
755                {
756                        StringUtil::toLowerCase(vecparams[2]);
757                        if (vecparams[2] == "unlimited")
758            {
759                                mips = MIP_UNLIMITED;
760            }
761                        else
762                        {
763                                mips = StringConverter::parseInt(vecparams[2]);
764                        }
765        }
766        if (numParams >= 4)
767        {
768            StringUtil::toLowerCase(vecparams[3]);
769            if (vecparams[3] == "alpha")
770            {
771                isAlpha = true;
772            }
773        }
774        context.textureUnit->setTextureName(vecparams[0], tt, mips, isAlpha);
775        return false;
776    }
777    //-----------------------------------------------------------------------
778    bool parseAnimTexture(String& params, MaterialScriptContext& context)
779    {
780        StringVector vecparams = StringUtil::split(params, " \t");
781        size_t numParams = vecparams.size();
782        // Determine which form it is
783        // Must have at least 3 params though
784        if (numParams < 3)
785        {
786            logParseError("Bad anim_texture attribute, wrong number of parameters "
787                "(expected at least 3)", context);
788            return false;
789        }
790        if (numParams == 3 && StringConverter::parseInt(vecparams[1]) != 0 )
791        {
792            // First form using base name & number of frames
793            context.textureUnit->setAnimatedTextureName(
794                vecparams[0],
795                StringConverter::parseInt(vecparams[1]),
796                StringConverter::parseReal(vecparams[2]));
797        }
798        else
799        {
800            // Second form using individual names
801            context.textureUnit->setAnimatedTextureName(
802                (String*)&vecparams[0],
803                numParams-1,
804                StringConverter::parseReal(vecparams[numParams-1]));
805        }
806        return false;
807
808    }
809    //-----------------------------------------------------------------------
810    bool parseCubicTexture(String& params, MaterialScriptContext& context)
811    {
812
813        StringVector vecparams = StringUtil::split(params, " \t");
814        size_t numParams = vecparams.size();
815
816        // Get final param
817        bool useUVW;
818        String& uvOpt = vecparams[numParams-1];
819                StringUtil::toLowerCase(uvOpt);
820        if (uvOpt == "combineduvw")
821            useUVW = true;
822        else if (uvOpt == "separateuv")
823            useUVW = false;
824        else
825        {
826            logParseError("Bad cubic_texture attribute, final parameter must be "
827                "'combinedUVW' or 'separateUV'.", context);
828            return false;
829        }
830        // Determine which form it is
831        if (numParams == 2)
832        {
833            // First form using base name
834            context.textureUnit->setCubicTextureName(vecparams[0], useUVW);
835        }
836        else if (numParams == 7)
837        {
838            // Second form using individual names
839            // Can use vecparams[0] as array start point
840            context.textureUnit->setCubicTextureName((String*)&vecparams[0], useUVW);
841        }
842        else
843        {
844            logParseError(
845                "Bad cubic_texture attribute, wrong number of parameters (expected 2 or 7)",
846                context);
847            return false;
848        }
849
850        return false;
851    }
852    //-----------------------------------------------------------------------
853    bool parseTexCoord(String& params, MaterialScriptContext& context)
854    {
855        context.textureUnit->setTextureCoordSet(
856            StringConverter::parseInt(params));
857
858        return false;
859    }
860    //-----------------------------------------------------------------------
861        TextureUnitState::TextureAddressingMode convTexAddressMode(const String& params, MaterialScriptContext& context)
862        {
863                if (params=="wrap")
864                        return TextureUnitState::TAM_WRAP;
865                else if (params=="mirror")
866                        return TextureUnitState::TAM_MIRROR;
867                else if (params=="clamp")
868                        return TextureUnitState::TAM_CLAMP;
869                else if (params=="border")
870                        return TextureUnitState::TAM_BORDER;
871                else
872                        logParseError("Bad tex_address_mode attribute, valid parameters are "
873                                "'wrap', 'mirror', 'clamp' or 'border'.", context);
874                // default
875                return TextureUnitState::TAM_WRAP;
876        }
877    //-----------------------------------------------------------------------
878    bool parseTexAddressMode(String& params, MaterialScriptContext& context)
879    {
880        StringUtil::toLowerCase(params);
881
882        StringVector vecparams = StringUtil::split(params, " \t");
883        size_t numParams = vecparams.size();
884               
885                if (numParams > 3 || numParams < 1)
886                {
887                        logParseError("Invalid number of parameters to tex_address_mode"
888                                        " - must be between 1 and 3", context);
889                }
890                if (numParams == 1)
891                {
892                        // Single-parameter option
893                        context.textureUnit->setTextureAddressingMode(
894                                convTexAddressMode(vecparams[0], context));
895                }
896                else
897                {
898                        // 2-3 parameter option
899                        TextureUnitState::UVWAddressingMode uvw;
900                        uvw.u = convTexAddressMode(vecparams[0], context);
901                        uvw.v = convTexAddressMode(vecparams[1], context);
902                        if (numParams == 3)
903                        {
904                                // w
905                                uvw.w = convTexAddressMode(vecparams[2], context);
906                        }
907                        else
908                        {
909                                uvw.w = TextureUnitState::TAM_WRAP;
910                        }
911                        context.textureUnit->setTextureAddressingMode(uvw);
912                }
913        return false;
914    }
915    //-----------------------------------------------------------------------
916    bool parseTexBorderColour(String& params, MaterialScriptContext& context)
917    {
918        StringVector vecparams = StringUtil::split(params, " \t");
919        // Must be 3 or 4 parameters
920        if (vecparams.size() == 3 || vecparams.size() == 4)
921        {
922            context.textureUnit->setTextureBorderColour( _parseColourValue(vecparams) );
923        }
924        else
925        {
926            logParseError(
927                "Bad tex_border_colour attribute, wrong number of parameters (expected 3 or 4)",
928                context);
929        }
930        return false;
931    }
932    //-----------------------------------------------------------------------
933    bool parseColourOp(String& params, MaterialScriptContext& context)
934    {
935        StringUtil::toLowerCase(params);
936        if (params=="replace")
937            context.textureUnit->setColourOperation(LBO_REPLACE);
938        else if (params=="add")
939            context.textureUnit->setColourOperation(LBO_ADD);
940        else if (params=="modulate")
941            context.textureUnit->setColourOperation(LBO_MODULATE);
942        else if (params=="alpha_blend")
943            context.textureUnit->setColourOperation(LBO_ALPHA_BLEND);
944        else
945            logParseError("Bad colour_op attribute, valid parameters are "
946                "'replace', 'add', 'modulate' or 'alpha_blend'.", context);
947
948        return false;
949    }
950    //-----------------------------------------------------------------------
951    bool parseAlphaRejection(String& params, MaterialScriptContext& context)
952    {
953        StringUtil::toLowerCase(params);
954        StringVector vecparams = StringUtil::split(params, " \t");
955        if (vecparams.size() != 2)
956        {
957            logParseError(
958                "Bad alpha_rejection attribute, wrong number of parameters (expected 2)",
959                context);
960            return false;
961        }
962
963        CompareFunction cmp;
964        try {
965            cmp = convertCompareFunction(vecparams[0]);
966        }
967        catch (...)
968        {
969            logParseError("Bad alpha_rejection attribute, invalid compare function.", context);
970            return false;
971        }
972
973        context.pass->setAlphaRejectSettings(cmp, StringConverter::parseInt(vecparams[1]));
974
975        return false;
976    }
977    //-----------------------------------------------------------------------
978    LayerBlendOperationEx convertBlendOpEx(const String& param)
979    {
980        if (param == "source1")
981            return LBX_SOURCE1;
982        else if (param == "source2")
983            return LBX_SOURCE2;
984        else if (param == "modulate")
985            return LBX_MODULATE;
986        else if (param == "modulate_x2")
987            return LBX_MODULATE_X2;
988        else if (param == "modulate_x4")
989            return LBX_MODULATE_X4;
990        else if (param == "add")
991            return LBX_ADD;
992        else if (param == "add_signed")
993            return LBX_ADD_SIGNED;
994        else if (param == "add_smooth")
995            return LBX_ADD_SMOOTH;
996        else if (param == "subtract")
997            return LBX_SUBTRACT;
998        else if (param == "blend_diffuse_colour")
999            return LBX_BLEND_DIFFUSE_COLOUR;
1000        else if (param == "blend_diffuse_alpha")
1001            return LBX_BLEND_DIFFUSE_ALPHA;
1002        else if (param == "blend_texture_alpha")
1003            return LBX_BLEND_TEXTURE_ALPHA;
1004        else if (param == "blend_current_alpha")
1005            return LBX_BLEND_CURRENT_ALPHA;
1006        else if (param == "blend_manual")
1007            return LBX_BLEND_MANUAL;
1008        else if (param == "dotproduct")
1009            return LBX_DOTPRODUCT;
1010        else
1011            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Invalid blend function", "convertBlendOpEx");
1012    }
1013    //-----------------------------------------------------------------------
1014    LayerBlendSource convertBlendSource(const String& param)
1015    {
1016        if (param == "src_current")
1017            return LBS_CURRENT;
1018        else if (param == "src_texture")
1019            return LBS_TEXTURE;
1020        else if (param == "src_diffuse")
1021            return LBS_DIFFUSE;
1022        else if (param == "src_specular")
1023            return LBS_SPECULAR;
1024        else if (param == "src_manual")
1025            return LBS_MANUAL;
1026        else
1027            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Invalid blend source", "convertBlendSource");
1028    }
1029    //-----------------------------------------------------------------------
1030    bool parseColourOpEx(String& params, MaterialScriptContext& context)
1031    {
1032        StringUtil::toLowerCase(params);
1033        StringVector vecparams = StringUtil::split(params, " \t");
1034        size_t numParams = vecparams.size();
1035
1036        if (numParams < 3 || numParams > 10)
1037        {
1038            logParseError(
1039                "Bad colour_op_ex attribute, wrong number of parameters (expected 3 to 10)",
1040                context);
1041            return false;
1042        }
1043        LayerBlendOperationEx op;
1044        LayerBlendSource src1, src2;
1045        Real manual = 0.0;
1046        ColourValue colSrc1 = ColourValue::White;
1047        ColourValue colSrc2 = ColourValue::White;
1048
1049        try {
1050            op = convertBlendOpEx(vecparams[0]);
1051            src1 = convertBlendSource(vecparams[1]);
1052            src2 = convertBlendSource(vecparams[2]);
1053
1054            if (op == LBX_BLEND_MANUAL)
1055            {
1056                if (numParams < 4)
1057                {
1058                    logParseError("Bad colour_op_ex attribute, wrong number of parameters "
1059                        "(expected 4 for manual blend)", context);
1060                    return false;
1061                }
1062                manual = StringConverter::parseReal(vecparams[3]);
1063            }
1064
1065            if (src1 == LBS_MANUAL)
1066            {
1067                unsigned int parIndex = 3;
1068                if (op == LBX_BLEND_MANUAL)
1069                    parIndex++;
1070
1071                if (numParams < parIndex + 3)
1072                {
1073                    logParseError("Bad colour_op_ex attribute, wrong number of parameters "
1074                        "(expected " + StringConverter::toString(parIndex + 3) + ")", context);
1075                    return false;
1076                }
1077
1078                colSrc1.r = StringConverter::parseReal(vecparams[parIndex++]);
1079                colSrc1.g = StringConverter::parseReal(vecparams[parIndex++]);
1080                colSrc1.b = StringConverter::parseReal(vecparams[parIndex++]);
1081                if (numParams > parIndex)
1082                {
1083                    colSrc1.a = StringConverter::parseReal(vecparams[parIndex]);
1084                }
1085                else
1086                {
1087                    colSrc1.a = 1.0f;
1088                }
1089            }
1090
1091            if (src2 == LBS_MANUAL)
1092            {
1093                unsigned int parIndex = 3;
1094                if (op == LBX_BLEND_MANUAL)
1095                    parIndex++;
1096                if (src1 == LBS_MANUAL)
1097                    parIndex += 3;
1098
1099                if (numParams < parIndex + 3)
1100                {
1101                    logParseError("Bad colour_op_ex attribute, wrong number of parameters "
1102                        "(expected " + StringConverter::toString(parIndex + 3) + ")", context);
1103                    return false;
1104                }
1105
1106                colSrc2.r = StringConverter::parseReal(vecparams[parIndex++]);
1107                colSrc2.g = StringConverter::parseReal(vecparams[parIndex++]);
1108                colSrc2.b = StringConverter::parseReal(vecparams[parIndex++]);
1109                if (numParams > parIndex)
1110                {
1111                    colSrc2.a = StringConverter::parseReal(vecparams[parIndex]);
1112                }
1113                else
1114                {
1115                    colSrc2.a = 1.0f;
1116                }
1117            }
1118        }
1119        catch (Exception& e)
1120        {
1121            logParseError("Bad colour_op_ex attribute, " + e.getFullDescription(), context);
1122            return false;
1123        }
1124
1125        context.textureUnit->setColourOperationEx(op, src1, src2, colSrc1, colSrc2, manual);
1126        return false;
1127    }
1128    //-----------------------------------------------------------------------
1129    bool parseColourOpFallback(String& params, MaterialScriptContext& context)
1130    {
1131        StringUtil::toLowerCase(params);
1132        StringVector vecparams = StringUtil::split(params, " \t");
1133        if (vecparams.size() != 2)
1134        {
1135            logParseError("Bad colour_op_multipass_fallback attribute, wrong number "
1136                "of parameters (expected 2)", context);
1137            return false;
1138        }
1139
1140        //src/dest
1141        SceneBlendFactor src, dest;
1142
1143        try {
1144            src = convertBlendFactor(vecparams[0]);
1145            dest = convertBlendFactor(vecparams[1]);
1146            context.textureUnit->setColourOpMultipassFallback(src,dest);
1147        }
1148        catch (Exception& e)
1149        {
1150            logParseError("Bad colour_op_multipass_fallback attribute, "
1151                + e.getFullDescription(), context);
1152        }
1153        return false;
1154    }
1155    //-----------------------------------------------------------------------
1156    bool parseAlphaOpEx(String& params, MaterialScriptContext& context)
1157    {
1158        StringUtil::toLowerCase(params);
1159        StringVector vecparams = StringUtil::split(params, " \t");
1160        size_t numParams = vecparams.size();
1161        if (numParams < 3 || numParams > 6)
1162        {
1163            logParseError("Bad alpha_op_ex attribute, wrong number of parameters "
1164                "(expected 3 to 6)", context);
1165            return false;
1166        }
1167        LayerBlendOperationEx op;
1168        LayerBlendSource src1, src2;
1169        Real manual = 0.0;
1170        Real arg1 = 1.0, arg2 = 1.0;
1171
1172        try {
1173            op = convertBlendOpEx(vecparams[0]);
1174            src1 = convertBlendSource(vecparams[1]);
1175            src2 = convertBlendSource(vecparams[2]);
1176            if (op == LBX_BLEND_MANUAL)
1177            {
1178                if (numParams != 4)
1179                {
1180                    logParseError("Bad alpha_op_ex attribute, wrong number of parameters "
1181                        "(expected 4 for manual blend)", context);
1182                    return false;
1183                }
1184                manual = StringConverter::parseReal(vecparams[3]);
1185            }
1186            if (src1 == LBS_MANUAL)
1187            {
1188                unsigned int parIndex = 3;
1189                if (op == LBX_BLEND_MANUAL)
1190                    parIndex++;
1191
1192                if (numParams < parIndex)
1193                {
1194                    logParseError(
1195                        "Bad alpha_op_ex attribute, wrong number of parameters (expected " +
1196                        StringConverter::toString(parIndex - 1) + ")", context);
1197                    return false;
1198                }
1199
1200                arg1 = StringConverter::parseReal(vecparams[parIndex]);
1201            }
1202
1203            if (src2 == LBS_MANUAL)
1204            {
1205                unsigned int parIndex = 3;
1206                if (op == LBX_BLEND_MANUAL)
1207                    parIndex++;
1208                if (src1 == LBS_MANUAL)
1209                    parIndex++;
1210
1211                if (numParams < parIndex)
1212                {
1213                    logParseError(
1214                        "Bad alpha_op_ex attribute, wrong number of parameters "
1215                        "(expected " + StringConverter::toString(parIndex - 1) + ")", context);
1216                    return false;
1217                }
1218
1219                arg2 = StringConverter::parseReal(vecparams[parIndex]);
1220            }
1221        }
1222        catch (Exception& e)
1223        {
1224            logParseError("Bad alpha_op_ex attribute, " + e.getFullDescription(), context);
1225            return false;
1226        }
1227
1228        context.textureUnit->setAlphaOperation(op, src1, src2, arg1, arg2, manual);
1229        return false;
1230    }
1231    //-----------------------------------------------------------------------
1232    bool parseEnvMap(String& params, MaterialScriptContext& context)
1233    {
1234        StringUtil::toLowerCase(params);
1235        if (params=="off")
1236            context.textureUnit->setEnvironmentMap(false);
1237        else if (params=="spherical")
1238            context.textureUnit->setEnvironmentMap(true, TextureUnitState::ENV_CURVED);
1239        else if (params=="planar")
1240            context.textureUnit->setEnvironmentMap(true, TextureUnitState::ENV_PLANAR);
1241        else if (params=="cubic_reflection")
1242            context.textureUnit->setEnvironmentMap(true, TextureUnitState::ENV_REFLECTION);
1243        else if (params=="cubic_normal")
1244            context.textureUnit->setEnvironmentMap(true, TextureUnitState::ENV_NORMAL);
1245        else
1246            logParseError("Bad env_map attribute, valid parameters are 'off', "
1247                "'spherical', 'planar', 'cubic_reflection' and 'cubic_normal'.", context);
1248
1249        return false;
1250    }
1251    //-----------------------------------------------------------------------
1252    bool parseScroll(String& params, MaterialScriptContext& context)
1253    {
1254        StringVector vecparams = StringUtil::split(params, " \t");
1255        if (vecparams.size() != 2)
1256        {
1257            logParseError("Bad scroll attribute, wrong number of parameters (expected 2)", context);
1258            return false;
1259        }
1260        context.textureUnit->setTextureScroll(
1261            StringConverter::parseReal(vecparams[0]),
1262            StringConverter::parseReal(vecparams[1]));
1263
1264   
1265        return false;
1266    }
1267    //-----------------------------------------------------------------------
1268    bool parseScrollAnim(String& params, MaterialScriptContext& context)
1269    {
1270        StringVector vecparams = StringUtil::split(params, " \t");
1271        if (vecparams.size() != 2)
1272        {
1273            logParseError("Bad scroll_anim attribute, wrong number of "
1274                "parameters (expected 2)", context);
1275            return false;
1276        }
1277        context.textureUnit->setScrollAnimation(
1278            StringConverter::parseReal(vecparams[0]),
1279            StringConverter::parseReal(vecparams[1]));
1280
1281        return false;
1282    }
1283    //-----------------------------------------------------------------------
1284    bool parseRotate(String& params, MaterialScriptContext& context)
1285    {
1286        context.textureUnit->setTextureRotate(
1287            StringConverter::parseAngle(params));
1288
1289        return false;
1290    }
1291    //-----------------------------------------------------------------------
1292    bool parseRotateAnim(String& params, MaterialScriptContext& context)
1293    {
1294        context.textureUnit->setRotateAnimation(
1295            StringConverter::parseReal(params));
1296
1297        return false;
1298    }
1299    //-----------------------------------------------------------------------
1300    bool parseScale(String& params, MaterialScriptContext& context)
1301    {
1302        StringVector vecparams = StringUtil::split(params, " \t");
1303        if (vecparams.size() != 2)
1304        {
1305            logParseError("Bad scale attribute, wrong number of parameters (expected 2)", context);
1306            return false;
1307        }
1308        context.textureUnit->setTextureScale(
1309            StringConverter::parseReal(vecparams[0]),
1310            StringConverter::parseReal(vecparams[1]));
1311
1312        return false;
1313    }
1314    //-----------------------------------------------------------------------
1315    bool parseWaveXform(String& params, MaterialScriptContext& context)
1316    {
1317        StringUtil::toLowerCase(params);
1318        StringVector vecparams = StringUtil::split(params, " \t");
1319
1320        if (vecparams.size() != 6)
1321        {
1322            logParseError("Bad wave_xform attribute, wrong number of parameters "
1323                "(expected 6)", context);
1324            return false;
1325        }
1326        TextureUnitState::TextureTransformType ttype;
1327        WaveformType waveType;
1328        // Check transform type
1329        if (vecparams[0]=="scroll_x")
1330            ttype = TextureUnitState::TT_TRANSLATE_U;
1331        else if (vecparams[0]=="scroll_y")
1332            ttype = TextureUnitState::TT_TRANSLATE_V;
1333        else if (vecparams[0]=="rotate")
1334            ttype = TextureUnitState::TT_ROTATE;
1335        else if (vecparams[0]=="scale_x")
1336            ttype = TextureUnitState::TT_SCALE_U;
1337        else if (vecparams[0]=="scale_y")
1338            ttype = TextureUnitState::TT_SCALE_V;
1339        else
1340        {
1341            logParseError("Bad wave_xform attribute, parameter 1 must be 'scroll_x', "
1342                "'scroll_y', 'rotate', 'scale_x' or 'scale_y'", context);
1343            return false;
1344        }
1345        // Check wave type
1346        if (vecparams[1]=="sine")
1347            waveType = WFT_SINE;
1348        else if (vecparams[1]=="triangle")
1349            waveType = WFT_TRIANGLE;
1350        else if (vecparams[1]=="square")
1351            waveType = WFT_SQUARE;
1352        else if (vecparams[1]=="sawtooth")
1353            waveType = WFT_SAWTOOTH;
1354        else if (vecparams[1]=="inverse_sawtooth")
1355            waveType = WFT_INVERSE_SAWTOOTH;
1356        else
1357        {
1358            logParseError("Bad wave_xform attribute, parameter 2 must be 'sine', "
1359                "'triangle', 'square', 'sawtooth' or 'inverse_sawtooth'", context);
1360            return false;
1361        }
1362
1363        context.textureUnit->setTransformAnimation(
1364            ttype,
1365            waveType,
1366            StringConverter::parseReal(vecparams[2]),
1367            StringConverter::parseReal(vecparams[3]),
1368            StringConverter::parseReal(vecparams[4]),
1369            StringConverter::parseReal(vecparams[5]) );
1370
1371        return false;
1372    }
1373        //-----------------------------------------------------------------------
1374        bool parseTransform(String& params, MaterialScriptContext& context)
1375        {
1376                StringVector vecparams = StringUtil::split(params, " \t");
1377                if (vecparams.size() != 16)
1378                {
1379                        logParseError("Bad transform attribute, wrong number of parameters (expected 16)", context);
1380                        return false;
1381                }
1382                Matrix4 xform(
1383                        StringConverter::parseReal(vecparams[0]),
1384                        StringConverter::parseReal(vecparams[1]),
1385                        StringConverter::parseReal(vecparams[2]),
1386                        StringConverter::parseReal(vecparams[3]),
1387                        StringConverter::parseReal(vecparams[4]),
1388                        StringConverter::parseReal(vecparams[5]),
1389                        StringConverter::parseReal(vecparams[6]),
1390                        StringConverter::parseReal(vecparams[7]),
1391                        StringConverter::parseReal(vecparams[8]),
1392                        StringConverter::parseReal(vecparams[9]),
1393                        StringConverter::parseReal(vecparams[10]),
1394                        StringConverter::parseReal(vecparams[11]),
1395                        StringConverter::parseReal(vecparams[12]),
1396                        StringConverter::parseReal(vecparams[13]),
1397                        StringConverter::parseReal(vecparams[14]),
1398                        StringConverter::parseReal(vecparams[15]) );
1399                context.textureUnit->setTextureTransform(xform);
1400
1401
1402                return false;
1403        }
1404    //-----------------------------------------------------------------------
1405    bool parseDepthBias(String& params, MaterialScriptContext& context)
1406    {
1407        context.pass->setDepthBias(
1408            StringConverter::parseReal(params));
1409
1410        return false;
1411    }
1412    //-----------------------------------------------------------------------
1413    bool parseAnisotropy(String& params, MaterialScriptContext& context)
1414    {
1415        context.textureUnit->setTextureAnisotropy(
1416            StringConverter::parseInt(params));
1417
1418        return false;
1419    }
1420    //-----------------------------------------------------------------------
1421    bool parseTextureAlias(String& params, MaterialScriptContext& context)
1422    {
1423        context.textureUnit->setTextureNameAlias(params);
1424
1425        return false;
1426    }
1427    //-----------------------------------------------------------------------
1428    bool parseLodDistances(String& params, MaterialScriptContext& context)
1429    {
1430        StringVector vecparams = StringUtil::split(params, " \t");
1431
1432        // iterate over the parameters and parse distances out of them
1433        Material::LodDistanceList lodList;
1434        StringVector::iterator i, iend;
1435        iend = vecparams.end();
1436        for (i = vecparams.begin(); i != iend; ++i)
1437        {
1438            lodList.push_back(StringConverter::parseReal(*i));
1439        }
1440
1441        context.material->setLodLevels(lodList);
1442
1443        return false;
1444    }
1445    //-----------------------------------------------------------------------
1446    bool parseLodIndex(String& params, MaterialScriptContext& context)
1447    {
1448        context.technique->setLodIndex(StringConverter::parseInt(params));
1449        return false;
1450    }
1451        //-----------------------------------------------------------------------
1452        bool parseScheme(String& params, MaterialScriptContext& context)
1453        {
1454                context.technique->setSchemeName(params);
1455                return false;
1456        }
1457    //-----------------------------------------------------------------------
1458    bool parseSetTextureAlias(String& params, MaterialScriptContext& context)
1459    {
1460        StringVector vecparams = StringUtil::split(params, " \t");
1461        if (vecparams.size() != 2)
1462        {
1463            logParseError("Wrong number of parameters for texture_alias, expected 2", context);
1464            return false;
1465        }
1466        // first parameter is alias name and second paramater is texture name
1467        context.textureAliases[vecparams[0]] = vecparams[1];
1468
1469        return false;
1470    }
1471
1472    //-----------------------------------------------------------------------
1473    void processManualProgramParam(size_t index, const String& commandname,
1474        StringVector& vecparams, MaterialScriptContext& context)
1475    {
1476        // NB we assume that the first element of vecparams is taken up with either
1477        // the index or the parameter name, which we ignore
1478
1479        // Determine type
1480        size_t start, dims, roundedDims, i;
1481        bool isReal;
1482        bool isMatrix4x4 = false;
1483
1484        StringUtil::toLowerCase(vecparams[1]);
1485
1486        if (vecparams[1] == "matrix4x4")
1487        {
1488            dims = 16;
1489            isReal = true;
1490            isMatrix4x4 = true;
1491        }
1492        else if ((start = vecparams[1].find("float")) != String::npos)
1493        {
1494            // find the dimensionality
1495            start = vecparams[1].find_first_not_of("float");
1496            // Assume 1 if not specified
1497            if (start == String::npos)
1498            {
1499                dims = 1;
1500            }
1501            else
1502            {
1503                dims = StringConverter::parseInt(vecparams[1].substr(start));
1504            }
1505            isReal = true;
1506        }
1507        else if ((start = vecparams[1].find("int")) != String::npos)
1508        {
1509            // find the dimensionality
1510            start = vecparams[1].find_first_not_of("int");
1511            // Assume 1 if not specified
1512            if (start == String::npos)
1513            {
1514                dims = 1;
1515            }
1516            else
1517            {
1518                dims = StringConverter::parseInt(vecparams[1].substr(start));
1519            }
1520            isReal = false;
1521        }
1522        else
1523        {
1524            logParseError("Invalid " + commandname + " attribute - unrecognised "
1525                "parameter type " + vecparams[1], context);
1526            return;
1527        }
1528
1529        if (vecparams.size() != 2 + dims)
1530        {
1531            logParseError("Invalid " + commandname + " attribute - you need " +
1532                StringConverter::toString(2 + dims) + " parameters for a parameter of "
1533                "type " + vecparams[1], context);
1534        }
1535
1536        // Round dims to multiple of 4
1537        if (dims %4 != 0)
1538        {
1539            roundedDims = dims + 4 - (dims % 4);
1540        }
1541        else
1542        {
1543            roundedDims = dims;
1544        }
1545
1546        // set the name of the parameter if it exists
1547        String paramName = (commandname == "param_named") ? vecparams[0] : "";
1548
1549        // Now parse all the values
1550        if (isReal)
1551        {
1552            Real* realBuffer = new Real[roundedDims];
1553            // Do specified values
1554            for (i = 0; i < dims; ++i)
1555            {
1556                realBuffer[i] = StringConverter::parseReal(vecparams[i+2]);
1557            }
1558            // Fill up to multiple of 4 with zero
1559            for (; i < roundedDims; ++i)
1560            {
1561                realBuffer[i] = 0.0f;
1562
1563            }
1564
1565            if (isMatrix4x4)
1566            {
1567                // its a Matrix4x4 so pass as a Matrix4
1568                // use specialized setConstant that takes a matrix so matrix is transposed if required
1569                Matrix4 m4x4(
1570                    realBuffer[0],  realBuffer[1],  realBuffer[2],  realBuffer[3],
1571                    realBuffer[4],  realBuffer[5],  realBuffer[6],  realBuffer[7],
1572                    realBuffer[8],  realBuffer[9],  realBuffer[10], realBuffer[11],
1573                    realBuffer[12], realBuffer[13], realBuffer[14], realBuffer[15]
1574                    );
1575                context.programParams->setConstant(index, m4x4);
1576            }
1577            else
1578            {
1579                // Set
1580                context.programParams->setConstant(index, realBuffer, roundedDims * 0.25);
1581
1582            }
1583
1584           
1585            delete [] realBuffer;
1586            // log the parameter
1587            context.programParams->addConstantDefinition(paramName, index, dims, GpuProgramParameters::ET_REAL);
1588        }
1589        else
1590        {
1591            int* intBuffer = new int[roundedDims];
1592            // Do specified values
1593            for (i = 0; i < dims; ++i)
1594            {
1595                intBuffer[i] = StringConverter::parseInt(vecparams[i+2]);
1596            }
1597            // Fill to multiple of 4 with 0
1598            for (; i < roundedDims; ++i)
1599            {
1600                intBuffer[i] = 0;
1601            }
1602            // Set
1603            context.programParams->setConstant(index, intBuffer, roundedDims * 0.25);
1604            delete [] intBuffer;
1605            // log the parameter
1606            context.programParams->addConstantDefinition(paramName, index, dims, GpuProgramParameters::ET_INT);
1607        }
1608    }
1609    //-----------------------------------------------------------------------
1610    void processAutoProgramParam(size_t index, const String& commandname,
1611        StringVector& vecparams, MaterialScriptContext& context)
1612    {
1613        // NB we assume that the first element of vecparams is taken up with either
1614        // the index or the parameter name, which we ignore
1615
1616        // make sure param is in lower case
1617        StringUtil::toLowerCase(vecparams[1]);
1618
1619        // lookup the param to see if its a valid auto constant
1620        const GpuProgramParameters::AutoConstantDefinition* autoConstantDef =
1621            context.programParams->getAutoConstantDefinition(vecparams[1]);
1622
1623        // exit with error msg if the auto constant definition wasn't found
1624        if (!autoConstantDef)
1625                {
1626                        logParseError("Invalid " + commandname + " attribute - "
1627                                + vecparams[1], context);
1628                        return;
1629                }
1630
1631        // add AutoConstant based on the type of data it uses
1632        switch (autoConstantDef->dataType)
1633        {
1634        case GpuProgramParameters::ACDT_NONE:
1635            context.programParams->setAutoConstant(index, autoConstantDef->acType, 0);
1636            break;
1637
1638        case GpuProgramParameters::ACDT_INT:
1639            {
1640                                // Special case animation_parametric, we need to keep track of number of times used
1641                                if (autoConstantDef->acType == GpuProgramParameters::ACT_ANIMATION_PARAMETRIC)
1642                                {
1643                                        context.programParams->setAutoConstant(
1644                                                index, autoConstantDef->acType, context.numAnimationParametrics++);
1645                                }
1646                                else
1647                                {
1648
1649                                        if (vecparams.size() != 3)
1650                                        {
1651                                                logParseError("Invalid " + commandname + " attribute - "
1652                                                        "expected 3 parameters.", context);
1653                                                return;
1654                                        }
1655
1656                                        size_t extraParam = StringConverter::parseInt(vecparams[2]);
1657                                        context.programParams->setAutoConstant(
1658                                                index, autoConstantDef->acType, extraParam);
1659                                }
1660            }
1661            break;
1662
1663        case GpuProgramParameters::ACDT_REAL:
1664            {
1665                // special handling for time
1666                if (autoConstantDef->acType == GpuProgramParameters::ACT_TIME ||
1667                    autoConstantDef->acType == GpuProgramParameters::ACT_FRAME_TIME)
1668                {
1669                    Real factor = 1.0f;
1670                    if (vecparams.size() == 3)
1671                    {
1672                        factor = StringConverter::parseReal(vecparams[2]);
1673                    }
1674                   
1675                    context.programParams->setAutoConstantReal(index, autoConstantDef->acType, factor);
1676                }
1677                else // normal processing for auto constants that take an extra real value
1678                {
1679                    if (vecparams.size() != 3)
1680                    {
1681                        logParseError("Invalid " + commandname + " attribute - "
1682                            "expected 3 parameters.", context);
1683                        return;
1684                    }
1685
1686                                Real rData = StringConverter::parseReal(vecparams[2]);
1687                                context.programParams->setAutoConstantReal(index, autoConstantDef->acType, rData);
1688                }
1689            }
1690            break;
1691
1692        } // end switch
1693
1694        String paramName = (commandname == "param_named_auto") ? vecparams[0] : "";
1695        // add constant definition based on AutoConstant
1696        // make element count 0 so that proper allocation occurs when AutoState is set up
1697        size_t constantIndex = context.programParams->addConstantDefinition(
1698                        paramName, index, 0, autoConstantDef->elementType);
1699        // update constant definition auto settings
1700        // since an autoconstant was just added, its the last one in the container
1701        size_t autoIndex = context.programParams->getAutoConstantCount() - 1;
1702        // setup autoState which will allocate the proper amount of storage required by constant entries
1703        context.programParams->setConstantDefinitionAutoState(constantIndex, true, autoIndex);
1704       
1705    }
1706
1707    //-----------------------------------------------------------------------
1708    bool parseParamIndexed(String& params, MaterialScriptContext& context)
1709    {
1710        // NB skip this if the program is not supported or could not be found
1711        if (context.program.isNull() || !context.program->isSupported())
1712        {
1713            return false;
1714        }
1715
1716        StringUtil::toLowerCase(params);
1717        StringVector vecparams = StringUtil::split(params, " \t");
1718        if (vecparams.size() < 3)
1719        {
1720            logParseError("Invalid param_indexed attribute - expected at least 3 parameters.",
1721                context);
1722            return false;
1723        }
1724
1725        // Get start index
1726        size_t index = StringConverter::parseInt(vecparams[0]);
1727
1728        processManualProgramParam(index, "param_indexed", vecparams, context);
1729
1730        return false;
1731    }
1732    //-----------------------------------------------------------------------
1733    bool parseParamIndexedAuto(String& params, MaterialScriptContext& context)
1734    {
1735        // NB skip this if the program is not supported or could not be found
1736        if (context.program.isNull() || !context.program->isSupported())
1737        {
1738            return false;
1739        }
1740
1741        StringUtil::toLowerCase(params);
1742        StringVector vecparams = StringUtil::split(params, " \t");
1743        if (vecparams.size() != 2 && vecparams.size() != 3)
1744        {
1745            logParseError("Invalid param_indexed_auto attribute - expected 2 or 3 parameters.",
1746                context);
1747            return false;
1748        }
1749
1750        // Get start index
1751        size_t index = StringConverter::parseInt(vecparams[0]);
1752
1753        processAutoProgramParam(index, "param_indexed_auto", vecparams, context);
1754
1755        return false;
1756    }
1757    //-----------------------------------------------------------------------
1758    bool parseParamNamed(String& params, MaterialScriptContext& context)
1759    {
1760        // NB skip this if the program is not supported or could not be found
1761        if (context.program.isNull() || !context.program->isSupported())
1762        {
1763            return false;
1764        }
1765
1766        StringVector vecparams = StringUtil::split(params, " \t");
1767        if (vecparams.size() < 3)
1768        {
1769            logParseError("Invalid param_named attribute - expected at least 3 parameters.",
1770                context);
1771            return false;
1772        }
1773
1774        // Get start index from name
1775        size_t index;
1776        try {
1777            index = context.programParams->getParamIndex(vecparams[0]);
1778        }
1779        catch (Exception& e)
1780        {
1781            logParseError("Invalid param_named attribute - " + e.getFullDescription(), context);
1782            return false;
1783        }
1784
1785        // TEST
1786        /*
1787        LogManager::getSingleton().logMessage("SETTING PARAMETER " + vecparams[0] + " as index " +
1788            StringConverter::toString(index));
1789        */
1790        processManualProgramParam(index, "param_named", vecparams, context);
1791
1792        return false;
1793    }
1794    //-----------------------------------------------------------------------
1795    bool parseParamNamedAuto(String& params, MaterialScriptContext& context)
1796    {
1797        // NB skip this if the program is not supported or could not be found
1798        if (context.program.isNull() || !context.program->isSupported())
1799        {
1800            return false;
1801        }
1802
1803        StringVector vecparams = StringUtil::split(params, " \t");
1804        if (vecparams.size() != 2 && vecparams.size() != 3)
1805        {
1806            logParseError("Invalid param_indexed_auto attribute - expected 2 or 3 parameters.",
1807                context);
1808            return false;
1809        }
1810
1811        // Get start index from name
1812        size_t index;
1813        try {
1814            index = context.programParams->getParamIndex(vecparams[0]);
1815        }
1816        catch (Exception& e)
1817        {
1818            logParseError("Invalid param_named_auto attribute - " + e.getFullDescription(), context);
1819            return false;
1820        }
1821
1822        processAutoProgramParam(index, "param_named_auto", vecparams, context);
1823
1824        return false;
1825    }
1826    //-----------------------------------------------------------------------
1827    bool parseMaterial(String& params, MaterialScriptContext& context)
1828    {
1829        // nfz:
1830        // check params for reference to parent material to copy from
1831        // syntax: material name : parentMaterialName
1832        // check params for a colon after the first name and extract the parent name
1833        StringVector vecparams = StringUtil::split(params, ":", 1);
1834        MaterialPtr basematerial;
1835
1836        // Create a brand new material
1837        if (vecparams.size() >= 2)
1838        {
1839            // if a second parameter exists then assume its the name of the base material
1840            // that this new material should clone from
1841            StringUtil::trim(vecparams[1]);
1842            // make sure base material exists
1843            basematerial = MaterialManager::getSingleton().getByName(vecparams[1]);
1844            // if it doesn't exist then report error in log and just create a new material
1845            if (basematerial.isNull())
1846            {
1847                logParseError("parent material: " + vecparams[1] + " not found for new material:"
1848                    + vecparams[0], context);
1849            }
1850        }
1851
1852        // get rid of leading and trailing white space from material name
1853        StringUtil::trim(vecparams[0]);
1854
1855        context.material =
1856                        MaterialManager::getSingleton().create(vecparams[0], context.groupName);
1857
1858        if (!basematerial.isNull())
1859        {
1860            // copy parent material details to new material
1861            basematerial->copyDetailsTo(context.material);
1862        }
1863        else
1864        {
1865            // Remove pre-created technique from defaults
1866            context.material->removeAllTechniques();
1867        }
1868
1869                context.material->_notifyOrigin(context.filename);
1870
1871        // update section
1872        context.section = MSS_MATERIAL;
1873
1874        // Return TRUE because this must be followed by a {
1875        return true;
1876    }
1877    //-----------------------------------------------------------------------
1878    bool parseTechnique(String& params, MaterialScriptContext& context)
1879    {
1880
1881        // if params is not empty then see if the technique name already exists
1882        if (!params.empty() && (context.material->getNumTechniques() > 0))
1883        {
1884            // find the technique with name = params
1885            Technique * foundTechnique = context.material->getTechnique(params);
1886            if (foundTechnique)
1887            {
1888                // figure out technique index by iterating through technique container
1889                // would be nice if each technique remembered its index
1890                int count = 0;
1891                Material::TechniqueIterator i = context.material->getTechniqueIterator();
1892                while(i.hasMoreElements())
1893                {
1894                    if (foundTechnique == i.peekNext())
1895                        break;
1896                    i.moveNext();
1897                    ++count;
1898                }
1899
1900                context.techLev = count;
1901            }
1902            else
1903            {
1904                // name was not found so a new technique is needed
1905                // position technique level to the end index
1906                // a new technique will be created later on
1907                context.techLev = context.material->getNumTechniques();
1908            }
1909
1910        }
1911        else
1912        {
1913            // no name was given in the script so a new technique will be created
1914                    // Increase technique level depth
1915                    ++context.techLev;
1916        }
1917
1918        // Create a new technique if it doesn't already exist
1919        if (context.material->getNumTechniques() > context.techLev)
1920        {
1921            context.technique = context.material->getTechnique(context.techLev);
1922        }
1923        else
1924        {
1925            context.technique = context.material->createTechnique();
1926            if (!params.empty())
1927                context.technique->setName(params);
1928        }
1929
1930        // update section
1931        context.section = MSS_TECHNIQUE;
1932
1933        // Return TRUE because this must be followed by a {
1934        return true;
1935    }
1936    //-----------------------------------------------------------------------
1937    bool parsePass(String& params, MaterialScriptContext& context)
1938    {
1939        // if params is not empty then see if the pass name already exists
1940        if (!params.empty() && (context.technique->getNumPasses() > 0))
1941        {
1942            // find the pass with name = params
1943            Pass * foundPass = context.technique->getPass(params);
1944            if (foundPass)
1945            {
1946                context.passLev = foundPass->getIndex();
1947            }
1948            else
1949            {
1950                // name was not found so a new pass is needed
1951                // position pass level to the end index
1952                // a new pass will be created later on
1953                context.passLev = context.technique->getNumPasses();
1954            }
1955
1956        }
1957        else
1958        {
1959                    //Increase pass level depth
1960                    ++context.passLev;
1961        }
1962
1963        if (context.technique->getNumPasses() > context.passLev)
1964        {
1965            context.pass = context.technique->getPass(context.passLev);
1966        }
1967        else
1968        {
1969            // Create a new pass
1970            context.pass = context.technique->createPass();
1971            if (!params.empty())
1972                context.pass->setName(params);
1973        }
1974
1975        // update section
1976        context.section = MSS_PASS;
1977
1978        // Return TRUE because this must be followed by a {
1979        return true;
1980    }
1981    //-----------------------------------------------------------------------
1982    bool parseTextureUnit(String& params, MaterialScriptContext& context)
1983    {
1984        // if params is a name then see if that texture unit exists
1985        // if not then log the warning and just move on to the next TU from current
1986        if (!params.empty() && (context.pass->getNumTextureUnitStates() > 0))
1987        {
1988            // specifying a TUS name in the script for a TU means that a specific TU is being requested
1989            // try to get the specific TU
1990            // if the index requested is not valid, just creat a new TU
1991            // find the TUS with name = params
1992            TextureUnitState * foundTUS = context.pass->getTextureUnitState(params);
1993            if (foundTUS)
1994            {
1995                context.stateLev = context.pass->getTextureUnitStateIndex(foundTUS);
1996            }
1997            else
1998            {
1999                // name was not found so a new TUS is needed
2000                // position TUS level to the end index
2001                // a new TUS will be created later on
2002                context.stateLev = context.pass->getNumTextureUnitStates();
2003            }
2004        }
2005        else
2006        {
2007                    //Increase Texture Unit State level depth
2008                    ++context.stateLev;
2009        }
2010
2011        if (context.pass->getNumTextureUnitStates() > static_cast<size_t>(context.stateLev))
2012        {
2013            context.textureUnit = context.pass->getTextureUnitState(context.stateLev);
2014        }
2015        else
2016        {
2017            // Create a new texture unit
2018            context.textureUnit = context.pass->createTextureUnitState();
2019            if (!params.empty())
2020                context.textureUnit->setName(params);
2021        }
2022        // update section
2023        context.section = MSS_TEXTUREUNIT;
2024
2025        // Return TRUE because this must be followed by a {
2026        return true;
2027    }
2028
2029    //-----------------------------------------------------------------------
2030    bool parseVertexProgramRef(String& params, MaterialScriptContext& context)
2031    {
2032        // update section
2033        context.section = MSS_PROGRAM_REF;
2034
2035        // check if pass has a vertex program already
2036        if (context.pass->hasVertexProgram())
2037        {
2038            // if existing pass vertex program has same name as params
2039            // or params is empty then use current vertex program
2040            if (params.empty() || (context.pass->getVertexProgramName() == params))
2041            {
2042                context.program = context.pass->getVertexProgram();
2043            }
2044        }
2045
2046        // if context.program was not set then try to get the vertex program using the name
2047        // passed in params
2048        if (context.program.isNull())
2049        {
2050            context.program = GpuProgramManager::getSingleton().getByName(params);
2051            if (context.program.isNull())
2052            {
2053                // Unknown program
2054                logParseError("Invalid vertex_program_ref entry - vertex program "
2055                    + params + " has not been defined.", context);
2056                return true;
2057            }
2058
2059            context.isProgramShadowCaster = false;
2060            context.isVertexProgramShadowReceiver = false;
2061                        context.isFragmentProgramShadowReceiver = false;
2062           
2063            // Set the vertex program for this pass
2064            context.pass->setVertexProgram(params);
2065        }
2066
2067        // Create params? Skip this if program is not supported
2068        if (context.program->isSupported())
2069        {
2070            context.programParams = context.pass->getVertexProgramParameters();
2071                        context.numAnimationParametrics = 0;
2072        }
2073
2074        // Return TRUE because this must be followed by a {
2075        return true;
2076    }
2077    //-----------------------------------------------------------------------
2078    bool parseShadowCasterVertexProgramRef(String& params, MaterialScriptContext& context)
2079    {
2080        // update section
2081        context.section = MSS_PROGRAM_REF;
2082
2083        context.program = GpuProgramManager::getSingleton().getByName(params);
2084        if (context.program.isNull())
2085        {
2086            // Unknown program
2087            logParseError("Invalid shadow_caster_vertex_program_ref entry - vertex program "
2088                + params + " has not been defined.", context);
2089            return true;
2090        }
2091
2092        context.isProgramShadowCaster = true;
2093        context.isVertexProgramShadowReceiver = false;
2094                context.isFragmentProgramShadowReceiver = false;
2095
2096        // Set the vertex program for this pass
2097        context.pass->setShadowCasterVertexProgram(params);
2098
2099        // Create params? Skip this if program is not supported
2100        if (context.program->isSupported())
2101        {
2102            context.programParams = context.pass->getShadowCasterVertexProgramParameters();
2103                        context.numAnimationParametrics = 0;
2104        }
2105
2106        // Return TRUE because this must be followed by a {
2107        return true;
2108    }
2109    //-----------------------------------------------------------------------
2110    bool parseShadowReceiverVertexProgramRef(String& params, MaterialScriptContext& context)
2111    {
2112        // update section
2113        context.section = MSS_PROGRAM_REF;
2114
2115        context.program = GpuProgramManager::getSingleton().getByName(params);
2116        if (context.program.isNull())
2117        {
2118            // Unknown program
2119            logParseError("Invalid shadow_receiver_vertex_program_ref entry - vertex program "
2120                + params + " has not been defined.", context);
2121            return true;
2122        }
2123       
2124
2125        context.isProgramShadowCaster = false;
2126        context.isVertexProgramShadowReceiver = true;
2127                context.isFragmentProgramShadowReceiver = false;
2128
2129        // Set the vertex program for this pass
2130        context.pass->setShadowReceiverVertexProgram(params);
2131
2132        // Create params? Skip this if program is not supported
2133        if (context.program->isSupported())
2134        {
2135            context.programParams = context.pass->getShadowReceiverVertexProgramParameters();
2136                        context.numAnimationParametrics = 0;
2137        }
2138
2139        // Return TRUE because this must be followed by a {
2140        return true;
2141    }
2142        //-----------------------------------------------------------------------
2143        bool parseShadowReceiverFragmentProgramRef(String& params, MaterialScriptContext& context)
2144        {
2145                // update section
2146                context.section = MSS_PROGRAM_REF;
2147
2148                context.program = GpuProgramManager::getSingleton().getByName(params);
2149                if (context.program.isNull())
2150                {
2151                        // Unknown program
2152                        logParseError("Invalid shadow_receiver_fragment_program_ref entry - fragment program "
2153                                + params + " has not been defined.", context);
2154                        return true;
2155                }
2156
2157
2158                context.isProgramShadowCaster = false;
2159                context.isVertexProgramShadowReceiver = false;
2160                context.isFragmentProgramShadowReceiver = true;
2161
2162                // Set the vertex program for this pass
2163                context.pass->setShadowReceiverFragmentProgram(params);
2164
2165                // Create params? Skip this if program is not supported
2166                if (context.program->isSupported())
2167                {
2168                        context.programParams = context.pass->getShadowReceiverFragmentProgramParameters();
2169                        context.numAnimationParametrics = 0;
2170                }
2171
2172                // Return TRUE because this must be followed by a {
2173                return true;
2174        }
2175    //-----------------------------------------------------------------------
2176    bool parseFragmentProgramRef(String& params, MaterialScriptContext& context)
2177    {
2178        // update section
2179        context.section = MSS_PROGRAM_REF;
2180
2181        // check if pass has a fragment program already
2182        if (context.pass->hasFragmentProgram())
2183        {
2184            // if existing pass fragment program has same name as params
2185            // or params is empty then use current fragment program
2186            if (params.empty() || (context.pass->getFragmentProgramName() == params))
2187            {
2188                context.program = context.pass->getFragmentProgram();
2189            }
2190        }
2191
2192        // if context.program was not set then try to get the fragment program using the name
2193        // passed in params
2194        if (context.program.isNull())
2195        {
2196            context.program = GpuProgramManager::getSingleton().getByName(params);
2197            if (context.program.isNull())
2198            {
2199                // Unknown program
2200                logParseError("Invalid fragment_program_ref entry - fragment program "
2201                    + params + " has not been defined.", context);
2202                return true;
2203            }
2204           
2205            // Set the vertex program for this pass
2206            context.pass->setFragmentProgram(params);
2207        }
2208
2209        // Create params? Skip this if program is not supported
2210        if (context.program->isSupported())
2211        {
2212            context.programParams = context.pass->getFragmentProgramParameters();
2213                        context.numAnimationParametrics = 0;
2214        }
2215
2216        // Return TRUE because this must be followed by a {
2217        return true;
2218    }
2219    //-----------------------------------------------------------------------
2220    bool parseVertexProgram(String& params, MaterialScriptContext& context)
2221    {
2222        // update section
2223        context.section = MSS_PROGRAM;
2224
2225                // Create new program definition-in-progress
2226                context.programDef = new MaterialScriptProgramDefinition();
2227                context.programDef->progType = GPT_VERTEX_PROGRAM;
2228        context.programDef->supportsSkeletalAnimation = false;
2229                context.programDef->supportsMorphAnimation = false;
2230                context.programDef->supportsPoseAnimation = 0;
2231
2232                // Get name and language code
2233                StringVector vecparams = StringUtil::split(params, " \t");
2234                if (vecparams.size() != 2)
2235                {
2236            logParseError("Invalid vertex_program entry - expected "
2237                                "2 parameters.", context);
2238            return true;
2239                }
2240                // Name, preserve case
2241                context.programDef->name = vecparams[0];
2242                // language code, make lower case
2243                context.programDef->language = vecparams[1];
2244                StringUtil::toLowerCase(context.programDef->language);
2245
2246        // Return TRUE because this must be followed by a {
2247        return true;
2248        }
2249    //-----------------------------------------------------------------------
2250    bool parseFragmentProgram(String& params, MaterialScriptContext& context)
2251    {
2252        // update section
2253        context.section = MSS_PROGRAM;
2254
2255                // Create new program definition-in-progress
2256                context.programDef = new MaterialScriptProgramDefinition();
2257                context.programDef->progType = GPT_FRAGMENT_PROGRAM;
2258                context.programDef->supportsSkeletalAnimation = false;
2259                context.programDef->supportsMorphAnimation = false;
2260                context.programDef->supportsPoseAnimation = 0;
2261
2262                // Get name and language code
2263                StringVector vecparams = StringUtil::split(params, " \t");
2264                if (vecparams.size() != 2)
2265                {
2266            logParseError("Invalid fragment_program entry - expected "
2267                                "2 parameters.", context);
2268            return true;
2269                }
2270                // Name, preserve case
2271                context.programDef->name = vecparams[0];
2272                // language code, make lower case
2273                context.programDef->language = vecparams[1];
2274                StringUtil::toLowerCase(context.programDef->language);
2275
2276                // Return TRUE because this must be followed by a {
2277        return true;
2278       
2279        }
2280    //-----------------------------------------------------------------------
2281    bool parseProgramSource(String& params, MaterialScriptContext& context)
2282    {
2283                // Source filename, preserve case
2284                context.programDef->source = params;
2285
2286                return false;
2287        }
2288    //-----------------------------------------------------------------------
2289    bool parseProgramSkeletalAnimation(String& params, MaterialScriptContext& context)
2290    {
2291        // Source filename, preserve case
2292        context.programDef->supportsSkeletalAnimation
2293            = StringConverter::parseBool(params);
2294
2295        return false;
2296    }
2297        //-----------------------------------------------------------------------
2298        bool parseProgramMorphAnimation(String& params, MaterialScriptContext& context)
2299        {
2300                // Source filename, preserve case
2301                context.programDef->supportsMorphAnimation
2302                        = StringConverter::parseBool(params);
2303
2304                return false;
2305        }
2306        //-----------------------------------------------------------------------
2307        bool parseProgramPoseAnimation(String& params, MaterialScriptContext& context)
2308        {
2309                // Source filename, preserve case
2310                context.programDef->supportsPoseAnimation
2311                        = StringConverter::parseInt(params);
2312
2313                return false;
2314        }
2315    //-----------------------------------------------------------------------
2316    bool parseProgramSyntax(String& params, MaterialScriptContext& context)
2317    {
2318                // Syntax code, make lower case
2319        StringUtil::toLowerCase(params);
2320                context.programDef->syntax = params;
2321
2322                return false;
2323        }
2324    //-----------------------------------------------------------------------
2325    bool parseProgramCustomParameter(String& params, MaterialScriptContext& context)
2326    {
2327                // This params object does not have the command stripped
2328                // Lower case the command, but not the value incase it's relevant
2329                // Split only up to first delimiter, program deals with the rest
2330                StringVector vecparams = StringUtil::split(params, " \t", 1);
2331                if (vecparams.size() != 2)
2332                {
2333            logParseError("Invalid custom program parameter entry; "
2334                                "there must be a parameter name and at least one value.",
2335                                context);
2336            return false;
2337                }
2338
2339                context.programDef->customParameters[vecparams[0]] = vecparams[1];
2340
2341                return false;
2342        }
2343
2344        //-----------------------------------------------------------------------
2345    bool parseTextureSource(String& params, MaterialScriptContext& context)
2346    {
2347                StringUtil::toLowerCase(params);
2348        StringVector vecparams = StringUtil::split(params, " \t");
2349        if (vecparams.size() != 1)
2350                        logParseError("Invalid texture source attribute - expected 1 parameter.",                 context);
2351        //The only param should identify which ExternalTextureSource is needed
2352                ExternalTextureSourceManager::getSingleton().setCurrentPlugIn( vecparams[0] );
2353
2354                if(     ExternalTextureSourceManager::getSingleton().getCurrentPlugIn() != 0 )
2355                {
2356                        String tps;
2357                        tps = StringConverter::toString( context.techLev ) + " "
2358                                + StringConverter::toString( context.passLev ) + " "
2359                                + StringConverter::toString( context.stateLev);
2360
2361                        ExternalTextureSourceManager::getSingleton().getCurrentPlugIn()->setParameter( "set_T_P_S", tps );
2362                }
2363                       
2364        // update section
2365        context.section = MSS_TEXTURESOURCE;
2366        // Return TRUE because this must be followed by a {
2367        return true;
2368    }
2369
2370    //-----------------------------------------------------------------------
2371    bool parseTextureCustomParameter(String& params, MaterialScriptContext& context)
2372    {
2373                // This params object does not have the command stripped
2374                // Split only up to first delimiter, program deals with the rest
2375                StringVector vecparams = StringUtil::split(params, " \t", 1);
2376                if (vecparams.size() != 2)
2377                {
2378            logParseError("Invalid texture parameter entry; "
2379                                "there must be a parameter name and at least one value.",
2380                                context);
2381            return false;
2382                }
2383               
2384                if(     ExternalTextureSourceManager::getSingleton().getCurrentPlugIn() != 0 )
2385                        ////First is command, next could be a string with one or more values
2386                        ExternalTextureSourceManager::getSingleton().getCurrentPlugIn()->setParameter( vecparams[0], vecparams[1] );
2387               
2388                return false;
2389        }
2390    //-----------------------------------------------------------------------
2391    bool parseReceiveShadows(String& params, MaterialScriptContext& context)
2392    {
2393        StringUtil::toLowerCase(params);
2394        if (params == "on")
2395            context.material->setReceiveShadows(true);
2396        else if (params == "off")
2397            context.material->setReceiveShadows(false);
2398        else
2399            logParseError(
2400            "Bad receive_shadows attribute, valid parameters are 'on' or 'off'.",
2401            context);
2402
2403        return false;
2404
2405    }
2406    //-----------------------------------------------------------------------
2407    bool parseDefaultParams(String& params, MaterialScriptContext& context)
2408    {
2409        context.section = MSS_DEFAULT_PARAMETERS;
2410        // Should be a brace next
2411        return true;
2412    }
2413
2414        //-----------------------------------------------------------------------
2415        bool parseTransparencyCastsShadows(String& params, MaterialScriptContext& context)
2416        {
2417        StringUtil::toLowerCase(params);
2418                if (params == "on")
2419                        context.material->setTransparencyCastsShadows(true);
2420                else if (params == "off")
2421                        context.material->setTransparencyCastsShadows(false);
2422                else
2423                        logParseError(
2424                        "Bad transparency_casts_shadows attribute, valid parameters are 'on' or 'off'.",
2425                        context);
2426
2427                return false;
2428
2429        }
2430
2431#ifdef GAMETOOLS_ILLUMINATION_MODULE
2432        //-----------------------------------------------------------------------
2433    bool parseVertexTexture(String& params, MaterialScriptContext& context)
2434    {
2435        context.textureUnit->setVertexTexture(
2436                        StringConverter::parseBool(params));
2437
2438        return false;
2439    }
2440#endif
2441
2442        //-----------------------------------------------------------------------
2443    //-----------------------------------------------------------------------
2444    MaterialSerializer::MaterialSerializer()
2445    {
2446        // Set up root attribute parsers
2447        mRootAttribParsers.insert(AttribParserList::value_type("material", (ATTRIBUTE_PARSER)parseMaterial));
2448        mRootAttribParsers.insert(AttribParserList::value_type("vertex_program", (ATTRIBUTE_PARSER)parseVertexProgram));
2449        mRootAttribParsers.insert(AttribParserList::value_type("fragment_program", (ATTRIBUTE_PARSER)parseFragmentProgram));
2450
2451        // Set up material attribute parsers
2452        mMaterialAttribParsers.insert(AttribParserList::value_type("lod_distances", (ATTRIBUTE_PARSER)parseLodDistances));
2453        mMaterialAttribParsers.insert(AttribParserList::value_type("receive_shadows", (ATTRIBUTE_PARSER)parseReceiveShadows));
2454                mMaterialAttribParsers.insert(AttribParserList::value_type("transparency_casts_shadows", (ATTRIBUTE_PARSER)parseTransparencyCastsShadows));
2455        mMaterialAttribParsers.insert(AttribParserList::value_type("technique", (ATTRIBUTE_PARSER)parseTechnique));
2456        mMaterialAttribParsers.insert(AttribParserList::value_type("set_texture_alias", (ATTRIBUTE_PARSER)parseSetTextureAlias));
2457
2458        // Set up technique attribute parsers
2459        mTechniqueAttribParsers.insert(AttribParserList::value_type("lod_index", (ATTRIBUTE_PARSER)parseLodIndex));
2460                mTechniqueAttribParsers.insert(AttribParserList::value_type("scheme", (ATTRIBUTE_PARSER)parseScheme));
2461        mTechniqueAttribParsers.insert(AttribParserList::value_type("pass", (ATTRIBUTE_PARSER)parsePass));
2462
2463        // Set up pass attribute parsers
2464        mPassAttribParsers.insert(AttribParserList::value_type("ambient", (ATTRIBUTE_PARSER)parseAmbient));
2465        mPassAttribParsers.insert(AttribParserList::value_type("diffuse", (ATTRIBUTE_PARSER)parseDiffuse));
2466        mPassAttribParsers.insert(AttribParserList::value_type("specular", (ATTRIBUTE_PARSER)parseSpecular));
2467        mPassAttribParsers.insert(AttribParserList::value_type("emissive", (ATTRIBUTE_PARSER)parseEmissive));
2468        mPassAttribParsers.insert(AttribParserList::value_type("scene_blend", (ATTRIBUTE_PARSER)parseSceneBlend));
2469        mPassAttribParsers.insert(AttribParserList::value_type("depth_check", (ATTRIBUTE_PARSER)parseDepthCheck));
2470        mPassAttribParsers.insert(AttribParserList::value_type("depth_write", (ATTRIBUTE_PARSER)parseDepthWrite));
2471        mPassAttribParsers.insert(AttribParserList::value_type("depth_func", (ATTRIBUTE_PARSER)parseDepthFunc));
2472                mPassAttribParsers.insert(AttribParserList::value_type("alpha_rejection", (ATTRIBUTE_PARSER)parseAlphaRejection));
2473        mPassAttribParsers.insert(AttribParserList::value_type("colour_write", (ATTRIBUTE_PARSER)parseColourWrite));
2474        mPassAttribParsers.insert(AttribParserList::value_type("cull_hardware", (ATTRIBUTE_PARSER)parseCullHardware));
2475        mPassAttribParsers.insert(AttribParserList::value_type("cull_software", (ATTRIBUTE_PARSER)parseCullSoftware));
2476        mPassAttribParsers.insert(AttribParserList::value_type("lighting", (ATTRIBUTE_PARSER)parseLighting));
2477        mPassAttribParsers.insert(AttribParserList::value_type("fog_override", (ATTRIBUTE_PARSER)parseFogging));
2478        mPassAttribParsers.insert(AttribParserList::value_type("shading", (ATTRIBUTE_PARSER)parseShading));
2479                mPassAttribParsers.insert(AttribParserList::value_type("polygon_mode", (ATTRIBUTE_PARSER)parsePolygonMode));
2480        mPassAttribParsers.insert(AttribParserList::value_type("depth_bias", (ATTRIBUTE_PARSER)parseDepthBias));
2481        mPassAttribParsers.insert(AttribParserList::value_type("texture_unit", (ATTRIBUTE_PARSER)parseTextureUnit));
2482        mPassAttribParsers.insert(AttribParserList::value_type("vertex_program_ref", (ATTRIBUTE_PARSER)parseVertexProgramRef));
2483        mPassAttribParsers.insert(AttribParserList::value_type("shadow_caster_vertex_program_ref", (ATTRIBUTE_PARSER)parseShadowCasterVertexProgramRef));
2484        mPassAttribParsers.insert(AttribParserList::value_type("shadow_receiver_vertex_program_ref", (ATTRIBUTE_PARSER)parseShadowReceiverVertexProgramRef));
2485                mPassAttribParsers.insert(AttribParserList::value_type("shadow_receiver_fragment_program_ref", (ATTRIBUTE_PARSER)parseShadowReceiverFragmentProgramRef));
2486        mPassAttribParsers.insert(AttribParserList::value_type("fragment_program_ref", (ATTRIBUTE_PARSER)parseFragmentProgramRef));
2487        mPassAttribParsers.insert(AttribParserList::value_type("max_lights", (ATTRIBUTE_PARSER)parseMaxLights));
2488        mPassAttribParsers.insert(AttribParserList::value_type("iteration", (ATTRIBUTE_PARSER)parseIteration));
2489                mPassAttribParsers.insert(AttribParserList::value_type("point_size", (ATTRIBUTE_PARSER)parsePointSize));
2490                mPassAttribParsers.insert(AttribParserList::value_type("point_sprites", (ATTRIBUTE_PARSER)parsePointSprites));
2491                mPassAttribParsers.insert(AttribParserList::value_type("point_size_attenuation", (ATTRIBUTE_PARSER)parsePointAttenuation));
2492                mPassAttribParsers.insert(AttribParserList::value_type("point_size_min", (ATTRIBUTE_PARSER)parsePointSizeMin));
2493                mPassAttribParsers.insert(AttribParserList::value_type("point_size_max", (ATTRIBUTE_PARSER)parsePointSizeMax));
2494
2495        // Set up texture unit attribute parsers
2496                mTextureUnitAttribParsers.insert(AttribParserList::value_type("texture_source", (ATTRIBUTE_PARSER)parseTextureSource));
2497        mTextureUnitAttribParsers.insert(AttribParserList::value_type("texture", (ATTRIBUTE_PARSER)parseTexture));
2498        mTextureUnitAttribParsers.insert(AttribParserList::value_type("anim_texture", (ATTRIBUTE_PARSER)parseAnimTexture));
2499        mTextureUnitAttribParsers.insert(AttribParserList::value_type("cubic_texture", (ATTRIBUTE_PARSER)parseCubicTexture));
2500        mTextureUnitAttribParsers.insert(AttribParserList::value_type("tex_coord_set", (ATTRIBUTE_PARSER)parseTexCoord));
2501        mTextureUnitAttribParsers.insert(AttribParserList::value_type("tex_address_mode", (ATTRIBUTE_PARSER)parseTexAddressMode));
2502        mTextureUnitAttribParsers.insert(AttribParserList::value_type("tex_border_colour", (ATTRIBUTE_PARSER)parseTexBorderColour));
2503        mTextureUnitAttribParsers.insert(AttribParserList::value_type("colour_op", (ATTRIBUTE_PARSER)parseColourOp));
2504        mTextureUnitAttribParsers.insert(AttribParserList::value_type("colour_op_ex", (ATTRIBUTE_PARSER)parseColourOpEx));
2505        mTextureUnitAttribParsers.insert(AttribParserList::value_type("colour_op_multipass_fallback", (ATTRIBUTE_PARSER)parseColourOpFallback));
2506        mTextureUnitAttribParsers.insert(AttribParserList::value_type("alpha_op_ex", (ATTRIBUTE_PARSER)parseAlphaOpEx));
2507        mTextureUnitAttribParsers.insert(AttribParserList::value_type("env_map", (ATTRIBUTE_PARSER)parseEnvMap));
2508        mTextureUnitAttribParsers.insert(AttribParserList::value_type("scroll", (ATTRIBUTE_PARSER)parseScroll));
2509        mTextureUnitAttribParsers.insert(AttribParserList::value_type("scroll_anim", (ATTRIBUTE_PARSER)parseScrollAnim));
2510        mTextureUnitAttribParsers.insert(AttribParserList::value_type("rotate", (ATTRIBUTE_PARSER)parseRotate));
2511        mTextureUnitAttribParsers.insert(AttribParserList::value_type("rotate_anim", (ATTRIBUTE_PARSER)parseRotateAnim));
2512        mTextureUnitAttribParsers.insert(AttribParserList::value_type("scale", (ATTRIBUTE_PARSER)parseScale));
2513        mTextureUnitAttribParsers.insert(AttribParserList::value_type("wave_xform", (ATTRIBUTE_PARSER)parseWaveXform));
2514                mTextureUnitAttribParsers.insert(AttribParserList::value_type("transform", (ATTRIBUTE_PARSER)parseTransform));
2515        mTextureUnitAttribParsers.insert(AttribParserList::value_type("filtering", (ATTRIBUTE_PARSER)parseFiltering));
2516        mTextureUnitAttribParsers.insert(AttribParserList::value_type("max_anisotropy", (ATTRIBUTE_PARSER)parseAnisotropy));
2517        mTextureUnitAttribParsers.insert(AttribParserList::value_type("texture_alias", (ATTRIBUTE_PARSER)parseTextureAlias));
2518#ifdef  GAMETOOLS_ILLUMINATION_MODULE
2519                mTextureUnitAttribParsers.insert(AttribParserList::value_type("vertex_texture", (ATTRIBUTE_PARSER)parseVertexTexture));
2520#endif
2521        // Set up program reference attribute parsers
2522        mProgramRefAttribParsers.insert(AttribParserList::value_type("param_indexed", (ATTRIBUTE_PARSER)parseParamIndexed));
2523        mProgramRefAttribParsers.insert(AttribParserList::value_type("param_indexed_auto", (ATTRIBUTE_PARSER)parseParamIndexedAuto));
2524        mProgramRefAttribParsers.insert(AttribParserList::value_type("param_named", (ATTRIBUTE_PARSER)parseParamNamed));
2525        mProgramRefAttribParsers.insert(AttribParserList::value_type("param_named_auto", (ATTRIBUTE_PARSER)parseParamNamedAuto));
2526
2527        // Set up program definition attribute parsers
2528        mProgramAttribParsers.insert(AttribParserList::value_type("source", (ATTRIBUTE_PARSER)parseProgramSource));
2529        mProgramAttribParsers.insert(AttribParserList::value_type("syntax", (ATTRIBUTE_PARSER)parseProgramSyntax));
2530        mProgramAttribParsers.insert(AttribParserList::value_type("includes_skeletal_animation", (ATTRIBUTE_PARSER)parseProgramSkeletalAnimation));
2531                mProgramAttribParsers.insert(AttribParserList::value_type("includes_morph_animation", (ATTRIBUTE_PARSER)parseProgramMorphAnimation));
2532                mProgramAttribParsers.insert(AttribParserList::value_type("includes_pose_animation", (ATTRIBUTE_PARSER)parseProgramPoseAnimation));
2533        mProgramAttribParsers.insert(AttribParserList::value_type("default_params", (ATTRIBUTE_PARSER)parseDefaultParams));
2534               
2535        // Set up program default param attribute parsers
2536        mProgramDefaultParamAttribParsers.insert(AttribParserList::value_type("param_indexed", (ATTRIBUTE_PARSER)parseParamIndexed));
2537        mProgramDefaultParamAttribParsers.insert(AttribParserList::value_type("param_indexed_auto", (ATTRIBUTE_PARSER)parseParamIndexedAuto));
2538        mProgramDefaultParamAttribParsers.insert(AttribParserList::value_type("param_named", (ATTRIBUTE_PARSER)parseParamNamed));
2539        mProgramDefaultParamAttribParsers.insert(AttribParserList::value_type("param_named_auto", (ATTRIBUTE_PARSER)parseParamNamedAuto));
2540
2541        mScriptContext.section = MSS_NONE;
2542        mScriptContext.material.setNull();
2543        mScriptContext.technique = 0;
2544        mScriptContext.pass = 0;
2545        mScriptContext.textureUnit = 0;
2546        mScriptContext.program.setNull();
2547        mScriptContext.lineNo = 0;
2548        mScriptContext.filename = "";
2549                mScriptContext.techLev = -1;
2550                mScriptContext.passLev = -1;
2551                mScriptContext.stateLev = -1;
2552
2553        mBuffer = "";
2554    }
2555
2556    //-----------------------------------------------------------------------
2557    void MaterialSerializer::parseScript(DataStreamPtr& stream, const String& groupName)
2558    {
2559        String line;
2560        bool nextIsOpenBrace = false;
2561
2562        mScriptContext.section = MSS_NONE;
2563        mScriptContext.material.setNull();
2564        mScriptContext.technique = 0;
2565        mScriptContext.pass = 0;
2566        mScriptContext.textureUnit = 0;
2567        mScriptContext.program.setNull();
2568        mScriptContext.lineNo = 0;
2569                mScriptContext.techLev = -1;
2570                mScriptContext.passLev = -1;
2571                mScriptContext.stateLev = -1;
2572        mScriptContext.filename = stream->getName();
2573                mScriptContext.groupName = groupName;
2574        while(!stream->eof())
2575        {
2576            line = stream->getLine();
2577            mScriptContext.lineNo++;
2578           
2579            // DEBUG LINE
2580            // LogManager::getSingleton().logMessage("About to attempt line(#" +
2581            //    StringConverter::toString(mScriptContext.lineNo) + "): " + line);
2582
2583            // Ignore comments & blanks
2584            if (!(line.length() == 0 || line.substr(0,2) == "//"))
2585            {
2586                if (nextIsOpenBrace)
2587                {
2588                    // NB, parser will have changed context already
2589                    if (line != "{")
2590                    {
2591                        logParseError("Expecting '{' but got " +
2592                            line + " instead.", mScriptContext);
2593                    }
2594                    nextIsOpenBrace = false;
2595                }
2596                else
2597                {
2598                    nextIsOpenBrace = parseScriptLine(line);
2599                }
2600
2601            }
2602        }
2603
2604        // Check all braces were closed
2605        if (mScriptContext.section != MSS_NONE)
2606        {
2607            logParseError("Unexpected end of file.", mScriptContext);
2608        }
2609
2610                // Make sure we invalidate our context shared pointer (don't wanna hold on)
2611                mScriptContext.material.setNull();
2612
2613    }
2614    //-----------------------------------------------------------------------
2615    bool MaterialSerializer::parseScriptLine(String& line)
2616    {
2617        switch(mScriptContext.section)
2618        {
2619        case MSS_NONE:
2620            if (line == "}")
2621            {
2622                logParseError("Unexpected terminating brace.", mScriptContext);
2623                return false;
2624            }
2625            else
2626            {
2627                // find & invoke a parser
2628                return invokeParser(line, mRootAttribParsers);
2629            }
2630            break;
2631        case MSS_MATERIAL:
2632            if (line == "}")
2633            {
2634                // End of material
2635                // if texture aliases were found, pass them to the material
2636                // to update texture names used in Texture unit states
2637                if (!mScriptContext.textureAliases.empty())
2638                {
2639                    // request material to update all texture names in TUS's
2640                    // that use texture aliases in the list
2641                    mScriptContext.material->applyTextureAliases(mScriptContext.textureAliases);
2642                }
2643
2644                mScriptContext.section = MSS_NONE;
2645                mScriptContext.material.setNull();
2646                                //Reset all levels for next material
2647                                mScriptContext.passLev = -1;
2648                                mScriptContext.stateLev= -1;
2649                                mScriptContext.techLev = -1;
2650                mScriptContext.textureAliases.clear();
2651            }
2652            else
2653            {
2654                // find & invoke a parser
2655                return invokeParser(line, mMaterialAttribParsers);
2656            }
2657            break;
2658        case MSS_TECHNIQUE:
2659            if (line == "}")
2660            {
2661                // End of technique
2662                mScriptContext.section = MSS_MATERIAL;
2663                mScriptContext.technique = NULL;
2664                                mScriptContext.passLev = -1;    //Reset pass level (yes, the pass level)
2665            }
2666            else
2667            {
2668                // find & invoke a parser
2669                return invokeParser(line, mTechniqueAttribParsers);
2670            }
2671            break;
2672        case MSS_PASS:
2673            if (line == "}")
2674            {
2675                // End of pass
2676                mScriptContext.section = MSS_TECHNIQUE;
2677                mScriptContext.pass = NULL;
2678                                mScriptContext.stateLev = -1;   //Reset state level (yes, the state level)
2679            }
2680            else
2681            {
2682                // find & invoke a parser
2683                return invokeParser(line, mPassAttribParsers);
2684            }
2685            break;
2686        case MSS_TEXTUREUNIT:
2687            if (line == "}")
2688            {
2689                // End of texture unit
2690                mScriptContext.section = MSS_PASS;
2691                mScriptContext.textureUnit = NULL;
2692            }
2693            else
2694            {
2695                // find & invoke a parser
2696                return invokeParser(line, mTextureUnitAttribParsers);
2697            }
2698            break;
2699                case MSS_TEXTURESOURCE:
2700                        if( line == "}" )
2701                        {
2702                                //End texture source section
2703                                //Finish creating texture here
2704                                String sMaterialName = mScriptContext.material->getName();
2705                                if(     ExternalTextureSourceManager::getSingleton().getCurrentPlugIn() != 0)
2706                                        ExternalTextureSourceManager::getSingleton().getCurrentPlugIn()->
2707                                        createDefinedTexture( sMaterialName, mScriptContext.groupName );
2708                                //Revert back to texture unit
2709                                mScriptContext.section = MSS_TEXTUREUNIT;
2710                        }
2711                        else
2712                        {
2713                                // custom texture parameter, use original line
2714                                parseTextureCustomParameter(line, mScriptContext);
2715                        }
2716                        break;
2717        case MSS_PROGRAM_REF:
2718            if (line == "}")
2719            {
2720                // End of program
2721                mScriptContext.section = MSS_PASS;
2722                mScriptContext.program.setNull();
2723            }
2724            else
2725            {
2726                // find & invoke a parser
2727                return invokeParser(line, mProgramRefAttribParsers);
2728            }
2729            break;
2730        case MSS_PROGRAM:
2731                        // Program definitions are slightly different, they are deferred
2732                        // until all the information required is known
2733            if (line == "}")
2734            {
2735                // End of program
2736                                finishProgramDefinition();
2737                mScriptContext.section = MSS_NONE;
2738                delete mScriptContext.programDef;
2739                mScriptContext.defaultParamLines.clear();
2740                mScriptContext.programDef = NULL;
2741            }
2742            else
2743            {
2744                // find & invoke a parser
2745                                // do this manually because we want to call a custom
2746                                // routine when the parser is not found
2747                                // First, split line on first divisor only
2748                                StringVector splitCmd = StringUtil::split(line, " \t", 1);
2749                                // Find attribute parser
2750                                AttribParserList::iterator iparser = mProgramAttribParsers.find(splitCmd[0]);
2751                                if (iparser == mProgramAttribParsers.end())
2752                                {
2753                                        // custom parameter, use original line
2754                                        parseProgramCustomParameter(line, mScriptContext);
2755                                }
2756                                else
2757                                {
2758                    String cmd = splitCmd.size() >= 2? splitCmd[1]:StringUtil::BLANK;
2759                                        // Use parser with remainder
2760                    return iparser->second(cmd, mScriptContext );
2761                                }
2762                               
2763            }
2764            break;
2765        case MSS_DEFAULT_PARAMETERS:
2766            if (line == "}")
2767            {
2768                // End of default parameters
2769                mScriptContext.section = MSS_PROGRAM;
2770            }
2771            else
2772            {
2773                // Save default parameter lines up until we finalise the program
2774                mScriptContext.defaultParamLines.push_back(line);
2775            }
2776
2777
2778            break;
2779        };
2780
2781        return false;
2782    }
2783    //-----------------------------------------------------------------------
2784        void MaterialSerializer::finishProgramDefinition(void)
2785        {
2786                // Now it is time to create the program and propagate the parameters
2787                MaterialScriptProgramDefinition* def = mScriptContext.programDef;
2788        GpuProgramPtr gp;
2789                if (def->language == "asm")
2790                {
2791                        // Native assembler
2792                        // Validate
2793                        if (def->source.empty())
2794                        {
2795                                logParseError("Invalid program definition for " + def->name +
2796                                        ", you must specify a source file.", mScriptContext);
2797                        }
2798                        if (def->syntax.empty())
2799                        {
2800                                logParseError("Invalid program definition for " + def->name +
2801                                        ", you must specify a syntax code.", mScriptContext);
2802                        }
2803                        // Create
2804                        gp = GpuProgramManager::getSingleton().
2805                                createProgram(def->name, mScriptContext.groupName, def->source,
2806                    def->progType, def->syntax);
2807
2808                }
2809                else
2810                {
2811                        // High-level program
2812                        // Validate
2813                        if (def->source.empty())
2814                        {
2815                                logParseError("Invalid program definition for " + def->name +
2816                                        ", you must specify a source file.", mScriptContext);
2817                        }
2818                        // Create
2819            try
2820            {
2821                            HighLevelGpuProgramPtr hgp = HighLevelGpuProgramManager::getSingleton().
2822                                    createProgram(def->name, mScriptContext.groupName,
2823                        def->language, def->progType);
2824                // Assign to generalised version
2825                gp = hgp;
2826                // Set source file
2827                hgp->setSourceFile(def->source);
2828
2829                            // Set custom parameters
2830                            std::map<String, String>::const_iterator i, iend;
2831                            iend = def->customParameters.end();
2832                            for (i = def->customParameters.begin(); i != iend; ++i)
2833                            {
2834                                    if (!hgp->setParameter(i->first, i->second))
2835                                    {
2836                                            logParseError("Error in program " + def->name +
2837                                                    " parameter " + i->first + " is not valid.", mScriptContext);
2838                                    }
2839                            }
2840            }
2841            catch (Exception& e)
2842            {
2843                logParseError("Could not create GPU program '"
2844                    + def->name + "', error reported was: " + e.getFullDescription(), mScriptContext);
2845                                mScriptContext.program.setNull();
2846                mScriptContext.programParams.setNull();
2847                                return;
2848            }
2849        }
2850        // Set skeletal animation option
2851        gp->setSkeletalAnimationIncluded(def->supportsSkeletalAnimation);
2852                // Set morph animation option
2853                gp->setMorphAnimationIncluded(def->supportsMorphAnimation);
2854                // Set pose animation option
2855                gp->setPoseAnimationIncluded(def->supportsPoseAnimation);
2856                // set origin
2857                gp->_notifyOrigin(mScriptContext.filename);
2858
2859        // Set up to receive default parameters
2860        if (gp->isSupported()
2861            && !mScriptContext.defaultParamLines.empty())
2862        {
2863            mScriptContext.programParams = gp->getDefaultParameters();
2864                        mScriptContext.numAnimationParametrics = 0;
2865            mScriptContext.program = gp;
2866            StringVector::iterator i, iend;
2867            iend = mScriptContext.defaultParamLines.end();
2868            for (i = mScriptContext.defaultParamLines.begin();
2869                i != iend; ++i)
2870            {
2871                // find & invoke a parser
2872                // do this manually because we want to call a custom
2873                // routine when the parser is not found
2874                // First, split line on first divisor only
2875                StringVector splitCmd = StringUtil::split(*i, " \t", 1);
2876                // Find attribute parser
2877                AttribParserList::iterator iparser
2878                    = mProgramDefaultParamAttribParsers.find(splitCmd[0]);
2879                if (iparser != mProgramDefaultParamAttribParsers.end())
2880                {
2881                    String cmd = splitCmd.size() >= 2? splitCmd[1]:StringUtil::BLANK;
2882                    // Use parser with remainder
2883                    iparser->second(cmd, mScriptContext );
2884                }
2885
2886            }
2887            // Reset
2888            mScriptContext.program.setNull();
2889            mScriptContext.programParams.setNull();
2890        }
2891
2892        }
2893    //-----------------------------------------------------------------------
2894        bool MaterialSerializer::invokeParser(String& line, AttribParserList& parsers)
2895    {
2896        // First, split line on first divisor only
2897        StringVector splitCmd(StringUtil::split(line, " \t", 1));
2898
2899        // Find attribute parser
2900        AttribParserList::iterator iparser = parsers.find(splitCmd[0]);
2901        if (iparser == parsers.end())
2902        {
2903            // BAD command. BAD!
2904            logParseError("Unrecognised command: " + splitCmd[0], mScriptContext);
2905            return false;
2906        }
2907        else
2908        {
2909            String cmd;
2910            if(splitCmd.size() >= 2)
2911                cmd = splitCmd[1];
2912            // Use parser, make sure we have 2 params before using splitCmd[1]
2913            return iparser->second( cmd, mScriptContext );
2914        }
2915    }
2916    //-----------------------------------------------------------------------
2917    void MaterialSerializer::exportMaterial(const MaterialPtr& pMat, const String &fileName, bool exportDefaults,
2918        const bool includeProgDef, const String& programFilename)
2919    {
2920        clearQueue();
2921        mDefaults = exportDefaults;
2922        writeMaterial(pMat);
2923        exportQueued(fileName, includeProgDef, programFilename);
2924    }
2925    //-----------------------------------------------------------------------
2926    void MaterialSerializer::exportQueued(const String &fileName, const bool includeProgDef, const String& programFilename)
2927    {
2928        // write out gpu program definitions to the buffer
2929        writeGpuPrograms();
2930
2931        if (mBuffer == "")
2932            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Queue is empty !", "MaterialSerializer::exportQueued");
2933
2934        LogManager::getSingleton().logMessage("MaterialSerializer : writing material(s) to material script : " + fileName, LML_CRITICAL);
2935        FILE *fp;
2936        fp = fopen(fileName.c_str(), "w");
2937        if (!fp)
2938            OGRE_EXCEPT(Exception::ERR_CANNOT_WRITE_TO_FILE, "Cannot create material file.",
2939            "MaterialSerializer::export");
2940
2941        // output gpu program definitions to material script file if includeProgDef is true
2942        if (includeProgDef && !mGpuProgramBuffer.empty())
2943        {
2944            fputs(mGpuProgramBuffer.c_str(), fp);
2945        }
2946
2947        // output main buffer holding material script
2948        fputs(mBuffer.c_str(), fp);
2949        fclose(fp);
2950
2951        // write program script if program filename and program definitions
2952        // were not included in material script
2953        if (!includeProgDef && !mGpuProgramBuffer.empty() && !programFilename.empty())
2954        {
2955            FILE *fp;
2956            fp = fopen(programFilename.c_str(), "w");
2957            if (!fp)
2958                OGRE_EXCEPT(Exception::ERR_CANNOT_WRITE_TO_FILE, "Cannot create program material file.",
2959                "MaterialSerializer::export");
2960            fputs(mGpuProgramBuffer.c_str(), fp);
2961            fclose(fp);
2962        }
2963
2964        LogManager::getSingleton().logMessage("MaterialSerializer : done.", LML_CRITICAL);
2965        clearQueue();
2966    }
2967    //-----------------------------------------------------------------------
2968    void MaterialSerializer::queueForExport(const MaterialPtr& pMat,
2969                bool clearQueued, bool exportDefaults)
2970    {
2971        if (clearQueued)
2972            clearQueue();
2973
2974        mDefaults = exportDefaults;
2975        writeMaterial(pMat);
2976    }
2977    //-----------------------------------------------------------------------
2978    void MaterialSerializer::clearQueue()
2979    {
2980        mBuffer = "";
2981        mGpuProgramBuffer = "";
2982        mGpuProgramDefinitionContainer.clear();
2983    }
2984    //-----------------------------------------------------------------------
2985    const String &MaterialSerializer::getQueuedAsString() const
2986    {
2987        return mBuffer;
2988    }
2989    //-----------------------------------------------------------------------
2990    void MaterialSerializer::writeMaterial(const MaterialPtr& pMat)
2991    {
2992        LogManager::getSingleton().logMessage("MaterialSerializer : writing material " + pMat->getName() + " to queue.", LML_CRITICAL);
2993        // Material name
2994        writeAttribute(0, "material " + pMat->getName());
2995        beginSection(0);
2996        {
2997            // Write LOD information
2998            Material::LodDistanceIterator distIt = pMat->getLodDistanceIterator();
2999            // Skip zero value
3000            if (distIt.hasMoreElements())
3001                distIt.getNext();
3002            String attributeVal;
3003            while (distIt.hasMoreElements())
3004            {
3005                Real sqdist = distIt.getNext();
3006                attributeVal.append(StringConverter::toString(Math::Sqrt(sqdist)));
3007                if (distIt.hasMoreElements())
3008                    attributeVal.append(" ");
3009            }
3010            if (!attributeVal.empty())
3011            {
3012                writeAttribute(1, "lod_distances");
3013                writeValue(attributeVal);
3014            }
3015
3016
3017            // Shadow receive
3018            if (mDefaults ||
3019                pMat->getReceiveShadows() != true)
3020            {
3021                writeAttribute(1, "receive_shadows");
3022                writeValue(pMat->getReceiveShadows() ? "on" : "off");
3023            }
3024
3025                        // When rendering shadows, treat transparent things as opaque?
3026                        if (mDefaults ||
3027                                pMat->getTransparencyCastsShadows() == true)
3028                        {
3029                                writeAttribute(1, "transparency_casts_shadows");
3030                                writeValue(pMat->getTransparencyCastsShadows() ? "on" : "off");
3031                        }
3032
3033            // Iterate over techniques
3034            Material::TechniqueIterator it = pMat->getTechniqueIterator();
3035            while (it.hasMoreElements())
3036            {
3037                writeTechnique(it.getNext());
3038                mBuffer += "\n";
3039            }
3040        }
3041        endSection(0);
3042        mBuffer += "\n";
3043    }
3044    //-----------------------------------------------------------------------
3045    void MaterialSerializer::writeTechnique(const Technique* pTech)
3046    {
3047        // Technique header
3048        writeAttribute(1, "technique");
3049        // only output technique name if it exists.
3050        if (!pTech->getName().empty())
3051            writeValue(pTech->getName());
3052
3053        beginSection(1);
3054        {
3055                        // Lod index
3056                        if (mDefaults ||
3057                                pTech->getLodIndex() != 0)
3058                        {
3059                                writeAttribute(2, "lod_index");
3060                                writeValue(StringConverter::toString(pTech->getLodIndex()));
3061                        }
3062
3063                        // Scheme name
3064                        if (mDefaults ||
3065                                pTech->getSchemeName() != MaterialManager::DEFAULT_SCHEME_NAME)
3066                        {
3067                                writeAttribute(2, "scheme");
3068                                writeValue(pTech->getSchemeName());
3069                        }
3070
3071            // Iterate over passes
3072            Technique::PassIterator it = const_cast<Technique*>(pTech)->getPassIterator();
3073            while (it.hasMoreElements())
3074            {
3075                writePass(it.getNext());
3076                mBuffer += "\n";
3077            }
3078        }
3079        endSection(1);
3080
3081    }
3082    //-----------------------------------------------------------------------
3083    void MaterialSerializer::writePass(const Pass* pPass)
3084    {
3085        writeAttribute(2, "pass");
3086        // only output pass name if its not the default name
3087        if (pPass->getName() != StringConverter::toString(pPass->getIndex()))
3088            writeValue(pPass->getName());
3089
3090        beginSection(2);
3091        {
3092            //lighting
3093            if (mDefaults ||
3094                pPass->getLightingEnabled() != true)
3095            {
3096                writeAttribute(3, "lighting");
3097                writeValue(pPass->getLightingEnabled() ? "on" : "off");
3098            }
3099                        // max_lights
3100            if (mDefaults ||
3101                pPass->getMaxSimultaneousLights() != OGRE_MAX_SIMULTANEOUS_LIGHTS)
3102            {
3103                writeAttribute(3, "max_lights");
3104                writeValue(StringConverter::toString(pPass->getMaxSimultaneousLights()));
3105            }
3106                        // iteration
3107            if (mDefaults ||
3108                pPass->getIteratePerLight() || (pPass->getPassIterationCount() > 0))
3109            {
3110                writeAttribute(3, "iteration");
3111                // pass iteration count
3112                if (pPass->getPassIterationCount() > 0)
3113                {
3114                    writeValue(StringConverter::toString(pPass->getPassIterationCount()));
3115                    if (pPass->getIteratePerLight())
3116                        writeValue("per_light");
3117                }
3118                else
3119                {
3120                    writeValue(pPass->getIteratePerLight() ? "once_per_light" : "once");
3121                }
3122
3123                if (pPass->getIteratePerLight() && pPass->getRunOnlyForOneLightType())
3124                {
3125                    switch (pPass->getOnlyLightType())
3126                    {
3127                    case Light::LT_DIRECTIONAL:
3128                        writeValue("directional");
3129                        break;
3130                    case Light::LT_POINT:
3131                        writeValue("point");
3132                        break;
3133                    case Light::LT_SPOTLIGHT:
3134                        writeValue("spot");
3135                        break;
3136                    };
3137                }
3138            }
3139                       
3140
3141            if (pPass->getLightingEnabled())
3142            {
3143                // Ambient
3144                if (mDefaults ||
3145                    pPass->getAmbient().r != 1 ||
3146                    pPass->getAmbient().g != 1 ||
3147                    pPass->getAmbient().b != 1 ||
3148                    pPass->getAmbient().a != 1 ||
3149                    (pPass->getVertexColourTracking() & TVC_AMBIENT))
3150                {
3151                    writeAttribute(3, "ambient");
3152                    if (pPass->getVertexColourTracking() & TVC_AMBIENT)
3153                        writeValue("vertexcolour");
3154                    else
3155                        writeColourValue(pPass->getAmbient(), true);
3156                }
3157
3158                // Diffuse
3159                if (mDefaults ||
3160                    pPass->getDiffuse().r != 1 ||
3161                    pPass->getDiffuse().g != 1 ||
3162                    pPass->getDiffuse().b != 1 ||
3163                    pPass->getDiffuse().a != 1 ||
3164                    (pPass->getVertexColourTracking() & TVC_DIFFUSE))
3165                {
3166                    writeAttribute(3, "diffuse");
3167                    if (pPass->getVertexColourTracking() & TVC_DIFFUSE)
3168                        writeValue("vertexcolour");
3169                    else
3170                        writeColourValue(pPass->getDiffuse(), true);
3171                }
3172
3173                // Specular
3174                if (mDefaults ||
3175                    pPass->getSpecular().r != 0 ||
3176                    pPass->getSpecular().g != 0 ||
3177                    pPass->getSpecular().b != 0 ||
3178                    pPass->getSpecular().a != 1 ||
3179                    pPass->getShininess() != 0 ||
3180                    (pPass->getVertexColourTracking() & TVC_SPECULAR))
3181                {
3182                    writeAttribute(3, "specular");
3183                    if (pPass->getVertexColourTracking() & TVC_SPECULAR)
3184                    {
3185                        writeValue("vertexcolour");
3186                    }
3187                    else
3188                    {
3189                        writeColourValue(pPass->getSpecular(), true);
3190                    }
3191                    writeValue(StringConverter::toString(pPass->getShininess()));
3192
3193                }
3194
3195                // Emissive
3196                if (mDefaults ||
3197                    pPass->getSelfIllumination().r != 0 ||
3198                    pPass->getSelfIllumination().g != 0 ||
3199                    pPass->getSelfIllumination().b != 0 ||
3200                    pPass->getSelfIllumination().a != 1 ||
3201                    (pPass->getVertexColourTracking() & TVC_EMISSIVE))
3202                {
3203                    writeAttribute(3, "emissive");
3204                    if (pPass->getVertexColourTracking() & TVC_EMISSIVE)
3205                        writeValue("vertexcolour");
3206                    else
3207                        writeColourValue(pPass->getSelfIllumination(), true);
3208                }
3209            }
3210
3211            // Point size
3212            if (mDefaults ||
3213                pPass->getPointSize() != 1.0)
3214            {
3215                writeAttribute(3, "point_size");
3216                writeValue(StringConverter::toString(pPass->getPointSize()));
3217            }
3218
3219            // Point sprites
3220            if (mDefaults ||
3221                pPass->getPointSpritesEnabled())
3222            {
3223                writeAttribute(3, "point_sprites");
3224                writeValue(pPass->getPointSpritesEnabled() ? "on" : "off");
3225            }
3226
3227            // Point attenuation
3228            if (mDefaults ||
3229                pPass->isPointAttenuationEnabled())
3230            {
3231                writeAttribute(3, "point_size_attenuation");
3232                writeValue(pPass->isPointAttenuationEnabled() ? "on" : "off");
3233                if (pPass->isPointAttenuationEnabled() &&
3234                    (pPass->getPointAttenuationConstant() != 0.0 ||
3235                     pPass->getPointAttenuationLinear() != 1.0 ||
3236                     pPass->getPointAttenuationQuadratic() != 0.0))
3237                {
3238                    writeValue(StringConverter::toString(pPass->getPointAttenuationConstant()));
3239                    writeValue(StringConverter::toString(pPass->getPointAttenuationLinear()));
3240                    writeValue(StringConverter::toString(pPass->getPointAttenuationQuadratic()));
3241                }
3242            }
3243
3244            // Point min size
3245            if (mDefaults ||
3246                pPass->getPointMinSize() != 0.0)
3247            {
3248                writeAttribute(3, "point_size_min");
3249                writeValue(StringConverter::toString(pPass->getPointMinSize()));
3250            }
3251
3252            // Point max size
3253            if (mDefaults ||
3254                pPass->getPointMaxSize() != 0.0)
3255            {
3256                writeAttribute(3, "point_size_max");
3257                writeValue(StringConverter::toString(pPass->getPointMaxSize()));
3258            }
3259
3260            // scene blend factor
3261            if (mDefaults ||
3262                pPass->getSourceBlendFactor() != SBF_ONE ||
3263                pPass->getDestBlendFactor() != SBF_ZERO)
3264            {
3265                writeAttribute(3, "scene_blend");
3266                writeSceneBlendFactor(pPass->getSourceBlendFactor(), pPass->getDestBlendFactor());
3267            }
3268
3269
3270            //depth check
3271            if (mDefaults ||
3272                pPass->getDepthCheckEnabled() != true)
3273            {
3274                writeAttribute(3, "depth_check");
3275                writeValue(pPass->getDepthCheckEnabled() ? "on" : "off");
3276            }
3277                        // alpha_rejection
3278                        if (mDefaults ||
3279                                pPass->getAlphaRejectFunction() != CMPF_ALWAYS_PASS ||
3280                                pPass->getAlphaRejectValue() != 0)
3281                        {
3282                                writeAttribute(3, "alpha_rejection");
3283                                writeCompareFunction(pPass->getAlphaRejectFunction());
3284                                writeValue(StringConverter::toString(pPass->getAlphaRejectValue()));
3285                        }
3286
3287
3288            //depth write
3289            if (mDefaults ||
3290                pPass->getDepthWriteEnabled() != true)
3291            {
3292                writeAttribute(3, "depth_write");
3293                writeValue(pPass->getDepthWriteEnabled() ? "on" : "off");
3294            }
3295
3296            //depth function
3297            if (mDefaults ||
3298                pPass->getDepthFunction() != CMPF_LESS_EQUAL)
3299            {
3300                writeAttribute(3, "depth_func");
3301                writeCompareFunction(pPass->getDepthFunction());
3302            }
3303
3304            //depth bias
3305            if (mDefaults ||
3306                pPass->getDepthBias() != 0)
3307            {
3308                writeAttribute(3, "depth_bias");
3309                writeValue(StringConverter::toString(pPass->getDepthBias()));
3310            }
3311
3312            // hardware culling mode
3313            if (mDefaults ||
3314                pPass->getCullingMode() != CULL_CLOCKWISE)
3315            {
3316                CullingMode hcm = pPass->getCullingMode();
3317                writeAttribute(3, "cull_hardware");
3318                switch (hcm)
3319                {
3320                case CULL_NONE :
3321                    writeValue("none");
3322                    break;
3323                case CULL_CLOCKWISE :
3324                    writeValue("clockwise");
3325                    break;
3326                case CULL_ANTICLOCKWISE :
3327                    writeValue("anticlockwise");
3328                    break;
3329                }
3330            }
3331
3332            // software culling mode
3333            if (mDefaults ||
3334                pPass->getManualCullingMode() != MANUAL_CULL_BACK)
3335            {
3336                ManualCullingMode scm = pPass->getManualCullingMode();
3337                writeAttribute(3, "cull_software");
3338                switch (scm)
3339                {
3340                case MANUAL_CULL_NONE :
3341                    writeValue("none");
3342                    break;
3343                case MANUAL_CULL_BACK :
3344                    writeValue("back");
3345                    break;
3346                case MANUAL_CULL_FRONT :
3347                    writeValue("front");
3348                    break;
3349                }
3350            }
3351
3352            //shading
3353            if (mDefaults ||
3354                pPass->getShadingMode() != SO_GOURAUD)
3355            {
3356                writeAttribute(3, "shading");
3357                switch (pPass->getShadingMode())
3358                {
3359                case SO_FLAT:
3360                    writeValue("flat");
3361                    break;
3362                case SO_GOURAUD:
3363                    writeValue("gouraud");
3364                    break;
3365                case SO_PHONG:
3366                    writeValue("phong");
3367                    break;
3368                }
3369            }
3370
3371
3372                        if (mDefaults ||
3373                                pPass->getPolygonMode() != PM_SOLID)
3374                        {
3375                                writeAttribute(3, "polygon_mode");
3376                                switch (pPass->getPolygonMode())
3377                                {
3378                                case PM_POINTS:
3379                                        writeValue("points");
3380                                        break;
3381                                case PM_WIREFRAME:
3382                                        writeValue("wireframe");
3383                                        break;
3384                                case PM_SOLID:
3385                                        writeValue("solid");
3386                                        break;
3387                                }
3388                        }
3389
3390            //fog override
3391            if (mDefaults ||
3392                pPass->getFogOverride() != false)
3393            {
3394                writeAttribute(3, "fog_override");
3395                writeValue(pPass->getFogOverride() ? "true" : "false");
3396                if (pPass->getFogOverride())
3397                {
3398                    switch (pPass->getFogMode())
3399                    {
3400                    case FOG_NONE:
3401                        writeValue("none");
3402                        break;
3403                    case FOG_LINEAR:
3404                        writeValue("linear");
3405                        break;
3406                    case FOG_EXP2:
3407                        writeValue("exp2");
3408                        break;
3409                    case FOG_EXP:
3410                        writeValue("exp");
3411                        break;
3412                    }
3413
3414                    if (pPass->getFogMode() != FOG_NONE)
3415                    {
3416                        writeColourValue(pPass->getFogColour());
3417                        writeValue(StringConverter::toString(pPass->getFogDensity()));
3418                        writeValue(StringConverter::toString(pPass->getFogStart()));
3419                        writeValue(StringConverter::toString(pPass->getFogEnd()));
3420                    }
3421                }
3422            }
3423
3424            // nfz
3425
3426            //  GPU Vertex and Fragment program references and parameters
3427            if (pPass->hasVertexProgram())
3428            {
3429                writeVertexProgramRef(pPass);
3430            }
3431
3432            if (pPass->hasFragmentProgram())
3433            {
3434                writeFragmentProgramRef(pPass);
3435            }
3436
3437            if (pPass->hasShadowCasterVertexProgram())
3438            {
3439                writeShadowCasterVertexProgramRef(pPass);
3440            }
3441
3442            if (pPass->hasShadowReceiverVertexProgram())
3443            {
3444                writeShadowReceiverVertexProgramRef(pPass);
3445            }
3446
3447            if (pPass->hasShadowReceiverFragmentProgram())
3448            {
3449                writeShadowReceiverFragmentProgramRef(pPass);
3450            }
3451
3452            // Nested texture layers
3453            Pass::TextureUnitStateIterator it = const_cast<Pass*>(pPass)->getTextureUnitStateIterator();
3454            while(it.hasMoreElements())
3455            {
3456                writeTextureUnit(it.getNext());
3457            }
3458        }
3459        endSection(2);
3460        LogManager::getSingleton().logMessage("MaterialSerializer : done.", LML_CRITICAL);
3461    }
3462    //-----------------------------------------------------------------------
3463    String MaterialSerializer::convertFiltering(FilterOptions fo)
3464    {
3465        switch (fo)
3466        {
3467        case FO_NONE:
3468            return "none";
3469        case FO_POINT:
3470            return "point";
3471        case FO_LINEAR:
3472            return "linear";
3473        case FO_ANISOTROPIC:
3474            return "anisotropic";
3475        }
3476
3477        return "point";
3478    }
3479    //-----------------------------------------------------------------------
3480    String convertTexAddressMode(TextureUnitState::TextureAddressingMode tam)
3481        {
3482        switch (tam)
3483        {
3484        case TextureUnitState::TAM_BORDER:
3485            return "border";
3486        case TextureUnitState::TAM_CLAMP:
3487            return "clamp";
3488        case TextureUnitState::TAM_MIRROR:
3489            return "mirror";
3490        case TextureUnitState::TAM_WRAP:
3491            return "wrap";
3492        }
3493
3494        return "wrap";
3495        }
3496    //-----------------------------------------------------------------------
3497    void MaterialSerializer::writeTextureUnit(const TextureUnitState *pTex)
3498    {
3499        LogManager::getSingleton().logMessage("MaterialSerializer : parsing texture layer.", LML_CRITICAL);
3500        mBuffer += "\n";
3501        writeAttribute(3, "texture_unit");
3502        // only write out name if its not equal to the default name
3503        if (pTex->getName() != StringConverter::toString(pTex->getParent()->getTextureUnitStateIndex(pTex)))
3504            writeValue(pTex->getName());
3505
3506        beginSection(3);
3507        {
3508            // texture_alias
3509            if (!pTex->getTextureNameAlias().empty())
3510            {
3511                writeAttribute(4, "texture_alias");
3512                writeValue(pTex->getTextureNameAlias());
3513            }
3514
3515            //texture name
3516            if (pTex->getNumFrames() == 1 && pTex->getTextureName() != "" && !pTex->isCubic())
3517            {
3518                writeAttribute(4, "texture");
3519                writeValue(pTex->getTextureName());
3520
3521                switch (pTex->getTextureType())
3522                {
3523                case TEX_TYPE_1D:
3524                    writeValue("1d");
3525                    break;
3526                case TEX_TYPE_2D:
3527                    // nothing, this is the default
3528                    break;
3529                case TEX_TYPE_3D:
3530                    writeValue("3d");
3531                    break;
3532                case TEX_TYPE_CUBE_MAP:
3533                    // nothing, deal with this as cubic_texture since it copes with all variants
3534                    break;
3535                default:
3536                    break;
3537                };
3538            }
3539
3540            //anim. texture
3541            if (pTex->getNumFrames() > 1 && !pTex->isCubic())
3542            {
3543                writeAttribute(4, "anim_texture");
3544                for (unsigned int n = 0; n < pTex->getNumFrames(); n++)
3545                    writeValue(pTex->getFrameTextureName(n));
3546                writeValue(StringConverter::toString(pTex->getAnimationDuration()));
3547            }
3548
3549            //cubic texture
3550            if (pTex->isCubic())
3551            {
3552                writeAttribute(4, "cubic_texture");
3553                for (unsigned int n = 0; n < pTex->getNumFrames(); n++)
3554                    writeValue(pTex->getFrameTextureName(n));
3555
3556                //combinedUVW/separateUW
3557                if (pTex->getTextureType() == TEX_TYPE_CUBE_MAP)
3558                    writeValue("combinedUVW");
3559                else
3560                    writeValue("separateUV");
3561            }
3562
3563            //anisotropy level
3564            if (mDefaults ||
3565                pTex->getTextureAnisotropy() != 1)
3566            {
3567                writeAttribute(4, "max_anisotropy");
3568                writeValue(StringConverter::toString(pTex->getTextureAnisotropy()));
3569            }
3570
3571            //texture coordinate set
3572            if (mDefaults ||
3573                pTex->getTextureCoordSet() != 0)
3574            {
3575                writeAttribute(4, "tex_coord_set");
3576                writeValue(StringConverter::toString(pTex->getTextureCoordSet()));
3577            }
3578
3579            //addressing mode
3580                        const TextureUnitState::UVWAddressingMode& uvw =
3581                                pTex->getTextureAddressingMode();
3582            if (mDefaults ||
3583                uvw.u != Ogre::TextureUnitState::TAM_WRAP ||
3584                                uvw.v != Ogre::TextureUnitState::TAM_WRAP ||
3585                                uvw.w != Ogre::TextureUnitState::TAM_WRAP )
3586            {
3587                writeAttribute(4, "tex_address_mode");
3588                if (uvw.u == uvw.v && uvw.u == uvw.w)
3589                {
3590                    writeValue(convertTexAddressMode(uvw.u));
3591                }
3592                else
3593                {
3594                    writeValue(convertTexAddressMode(uvw.u));
3595                    writeValue(convertTexAddressMode(uvw.v));
3596                    if (uvw.w != TextureUnitState::TAM_WRAP)
3597                    {
3598                        writeValue(convertTexAddressMode(uvw.w));
3599                    }
3600                }
3601            }
3602
3603            //border colour
3604            const ColourValue& borderColour =
3605                pTex->getTextureBorderColour();
3606            if (mDefaults ||
3607                borderColour != ColourValue::Black)
3608            {
3609                writeAttribute(4, "tex_border_colour");
3610                writeColourValue(borderColour, true);
3611            }
3612
3613            //filtering
3614            if (mDefaults ||
3615                pTex->getTextureFiltering(FT_MIN) != FO_LINEAR ||
3616                pTex->getTextureFiltering(FT_MAG) != FO_LINEAR ||
3617                pTex->getTextureFiltering(FT_MIP) != FO_POINT)
3618            {
3619                writeAttribute(4, "filtering");
3620                writeValue(
3621                    convertFiltering(pTex->getTextureFiltering(FT_MIN))
3622                    + " "
3623                    + convertFiltering(pTex->getTextureFiltering(FT_MAG))
3624                    + " "
3625                    + convertFiltering(pTex->getTextureFiltering(FT_MIP)));
3626            }
3627
3628            // colour_op_ex
3629            if (mDefaults ||
3630                pTex->getColourBlendMode().operation != LBX_MODULATE ||
3631                pTex->getColourBlendMode().source1 != LBS_TEXTURE ||
3632                pTex->getColourBlendMode().source2 != LBS_CURRENT)
3633            {
3634                writeAttribute(4, "colour_op_ex");
3635                writeLayerBlendOperationEx(pTex->getColourBlendMode().operation);
3636                writeLayerBlendSource(pTex->getColourBlendMode().source1);
3637                writeLayerBlendSource(pTex->getColourBlendMode().source2);
3638                if (pTex->getColourBlendMode().operation == LBX_BLEND_MANUAL)
3639                    writeValue(StringConverter::toString(pTex->getColourBlendMode().factor));
3640                if (pTex->getColourBlendMode().source1 == LBS_MANUAL)
3641                    writeColourValue(pTex->getColourBlendMode().colourArg1, false);
3642                if (pTex->getColourBlendMode().source2 == LBS_MANUAL)
3643                    writeColourValue(pTex->getColourBlendMode().colourArg2, false);
3644
3645                //colour_op_multipass_fallback
3646                writeAttribute(4, "colour_op_multipass_fallback");
3647                writeSceneBlendFactor(pTex->getColourBlendFallbackSrc());
3648                writeSceneBlendFactor(pTex->getColourBlendFallbackDest());
3649            }
3650
3651            // alpha_op_ex
3652            if (mDefaults ||
3653                pTex->getAlphaBlendMode().operation != LBX_MODULATE ||
3654                pTex->getAlphaBlendMode().source1 != LBS_TEXTURE ||
3655                pTex->getAlphaBlendMode().source2 != LBS_CURRENT)
3656            {
3657                writeAttribute(4, "alpha_op_ex");
3658                writeLayerBlendOperationEx(pTex->getAlphaBlendMode().operation);
3659                writeLayerBlendSource(pTex->getAlphaBlendMode().source1);
3660                writeLayerBlendSource(pTex->getAlphaBlendMode().source2);
3661                if (pTex->getAlphaBlendMode().operation == LBX_BLEND_MANUAL)
3662                    writeValue(StringConverter::toString(pTex->getAlphaBlendMode().factor));
3663                else if (pTex->getAlphaBlendMode().source1 == LBS_MANUAL)
3664                    writeValue(StringConverter::toString(pTex->getAlphaBlendMode().alphaArg1));
3665                else if (pTex->getAlphaBlendMode().source2 == LBS_MANUAL)
3666                    writeValue(StringConverter::toString(pTex->getAlphaBlendMode().alphaArg2));
3667            }
3668
3669                        bool individualTransformElems = false;
3670            // rotate
3671            if (mDefaults ||
3672                pTex->getTextureRotate() != Radian(0))
3673            {
3674                writeAttribute(4, "rotate");
3675                writeValue(StringConverter::toString(pTex->getTextureRotate().valueDegrees()));
3676                                individualTransformElems = true;
3677            }
3678
3679            // scroll
3680            if (mDefaults ||
3681                pTex->getTextureUScroll() != 0 ||
3682                pTex->getTextureVScroll() != 0 )
3683            {
3684                writeAttribute(4, "scroll");
3685                writeValue(StringConverter::toString(pTex->getTextureUScroll()));
3686                writeValue(StringConverter::toString(pTex->getTextureVScroll()));
3687                                individualTransformElems = true;
3688            }
3689            // scale
3690            if (mDefaults ||
3691                pTex->getTextureUScale() != 1.0 ||
3692                pTex->getTextureVScale() != 1.0 )
3693            {
3694                writeAttribute(4, "scale");
3695                writeValue(StringConverter::toString(pTex->getTextureUScale()));
3696                writeValue(StringConverter::toString(pTex->getTextureVScale()));
3697                                individualTransformElems = true;
3698            }
3699
3700                        // free transform
3701                        if (!individualTransformElems &&
3702                                (mDefaults ||
3703                                pTex->getTextureTransform() != Matrix4::IDENTITY))
3704                        {
3705                                writeAttribute(4, "transform");
3706                                const Matrix4& xform = pTex->getTextureTransform();
3707                                for (int row = 0; row < 4; ++row)
3708                                {
3709                                        for (int col = 0; col < 4; ++col)
3710                                        {
3711                                                writeValue(StringConverter::toString(xform[row][col]));
3712                                        }
3713                                }
3714                        }
3715
3716                        // Used to store the u and v speeds of scroll animation effects
3717                        float scrollAnimU = 0;
3718                        float scrollAnimV = 0;
3719
3720            EffectMap m_ef = pTex->getEffects();
3721            if (!m_ef.empty())
3722            {
3723                EffectMap::const_iterator it;
3724                for (it = m_ef.begin(); it != m_ef.end(); ++it)
3725                {
3726                    const TextureUnitState::TextureEffect& ef = it->second;
3727                    switch (ef.type)
3728                    {
3729                    case TextureUnitState::ET_ENVIRONMENT_MAP :
3730                        writeEnvironmentMapEffect(ef, pTex);
3731                        break;
3732                    case TextureUnitState::ET_ROTATE :
3733                        writeRotationEffect(ef, pTex);
3734                        break;
3735                                        case TextureUnitState::ET_UVSCROLL :
3736                                                scrollAnimU = scrollAnimV = ef.arg1;
3737                                                break;
3738                    case TextureUnitState::ET_USCROLL :
3739                                                scrollAnimU = ef.arg1;
3740                                                break;
3741                                        case TextureUnitState::ET_VSCROLL :
3742                                                scrollAnimV = ef.arg1;                       
3743                        break;
3744                    case TextureUnitState::ET_TRANSFORM :
3745                        writeTransformEffect(ef, pTex);
3746                        break;
3747                    default:
3748                        break;
3749                    }
3750                }
3751            }
3752                       
3753                        // u and v scroll animation speeds merged, if present serialize scroll_anim
3754                        if(scrollAnimU || scrollAnimV) {
3755                                TextureUnitState::TextureEffect texEffect;
3756                                texEffect.arg1 = scrollAnimU;
3757                                texEffect.arg2 = scrollAnimV;
3758                                writeScrollEffect(texEffect, pTex);
3759                        }
3760        }
3761        endSection(3);
3762
3763    }
3764    //-----------------------------------------------------------------------
3765    void MaterialSerializer::writeEnvironmentMapEffect(const TextureUnitState::TextureEffect& effect, const TextureUnitState *pTex)
3766    {
3767        writeAttribute(4, "env_map");
3768        switch (effect.subtype)
3769        {
3770        case TextureUnitState::ENV_PLANAR:
3771            writeValue("planar");
3772            break;
3773        case TextureUnitState::ENV_CURVED:
3774            writeValue("spherical");
3775            break;
3776        case TextureUnitState::ENV_NORMAL:
3777            writeValue("cubic_normal");
3778            break;
3779        case TextureUnitState::ENV_REFLECTION:
3780            writeValue("cubic_reflection");
3781            break;
3782        }
3783    }
3784    //-----------------------------------------------------------------------
3785    void MaterialSerializer::writeRotationEffect(const TextureUnitState::TextureEffect& effect, const TextureUnitState *pTex)
3786    {
3787        if (effect.arg1)
3788        {
3789            writeAttribute(4, "rotate_anim");
3790            writeValue(StringConverter::toString(effect.arg1));
3791        }
3792    }
3793    //-----------------------------------------------------------------------
3794    void MaterialSerializer::writeTransformEffect(const TextureUnitState::TextureEffect& effect, const TextureUnitState *pTex)
3795    {
3796        writeAttribute(4, "wave_xform");
3797
3798        switch (effect.subtype)
3799        {
3800        case TextureUnitState::TT_ROTATE:
3801            writeValue("rotate");
3802            break;
3803        case TextureUnitState::TT_SCALE_U:
3804            writeValue("scale_x");
3805            break;
3806        case TextureUnitState::TT_SCALE_V:
3807            writeValue("scale_y");
3808            break;
3809        case TextureUnitState::TT_TRANSLATE_U:
3810            writeValue("scroll_x");
3811            break;
3812        case TextureUnitState::TT_TRANSLATE_V:
3813            writeValue("scroll_y");
3814            break;
3815        }
3816
3817        switch (effect.waveType)
3818        {
3819        case WFT_INVERSE_SAWTOOTH:
3820            writeValue("inverse_sawtooth");
3821            break;
3822        case WFT_SAWTOOTH:
3823            writeValue("sawtooth");
3824            break;
3825        case WFT_SINE:
3826            writeValue("sine");
3827            break;
3828        case WFT_SQUARE:
3829            writeValue("square");
3830            break;
3831        case WFT_TRIANGLE:
3832            writeValue("triangle");
3833            break;
3834        }
3835
3836        writeValue(StringConverter::toString(effect.base));
3837        writeValue(StringConverter::toString(effect.frequency));
3838        writeValue(StringConverter::toString(effect.phase));
3839        writeValue(StringConverter::toString(effect.amplitude));
3840    }
3841    //-----------------------------------------------------------------------
3842    void MaterialSerializer::writeScrollEffect(
3843                const TextureUnitState::TextureEffect& effect, const TextureUnitState *pTex)
3844    {
3845        if (effect.arg1 || effect.arg2)
3846        {
3847            writeAttribute(4, "scroll_anim");
3848            writeValue(StringConverter::toString(effect.arg1));
3849            writeValue(StringConverter::toString(effect.arg2));
3850        }
3851    }
3852    //-----------------------------------------------------------------------
3853    void MaterialSerializer::writeSceneBlendFactor(const SceneBlendFactor sbf)
3854    {
3855        switch (sbf)
3856        {
3857        case SBF_DEST_ALPHA:
3858            writeValue("dest_alpha");
3859            break;
3860        case SBF_DEST_COLOUR:
3861            writeValue("dest_colour");
3862            break;
3863        case SBF_ONE:
3864            writeValue("one");
3865            break;
3866        case SBF_ONE_MINUS_DEST_ALPHA:
3867            writeValue("one_minus_dest_alpha");
3868            break;
3869        case SBF_ONE_MINUS_DEST_COLOUR:
3870            writeValue("one_minus_dest_colour");
3871            break;
3872        case SBF_ONE_MINUS_SOURCE_ALPHA:
3873            writeValue("one_minus_src_alpha");
3874            break;
3875        case SBF_ONE_MINUS_SOURCE_COLOUR:
3876            writeValue("one_minus_src_colour");
3877            break;
3878        case SBF_SOURCE_ALPHA:
3879            writeValue("src_alpha");
3880            break;
3881        case SBF_SOURCE_COLOUR:
3882            writeValue("src_colour");
3883            break;
3884        case SBF_ZERO:
3885            writeValue("zero");
3886            break;
3887        }
3888    }
3889    //-----------------------------------------------------------------------
3890    void MaterialSerializer::writeSceneBlendFactor(const SceneBlendFactor sbf_src, const SceneBlendFactor sbf_dst)
3891    {
3892        if (sbf_src == SBF_ONE && sbf_dst == SBF_ONE )
3893            writeValue("add");
3894        else if (sbf_src == SBF_DEST_COLOUR && sbf_dst == SBF_ZERO)
3895            writeValue("modulate");
3896        else if (sbf_src == SBF_SOURCE_COLOUR && sbf_dst == SBF_ONE_MINUS_SOURCE_COLOUR)
3897            writeValue("colour_blend");
3898        else if (sbf_src == SBF_SOURCE_ALPHA && sbf_dst == SBF_ONE_MINUS_SOURCE_ALPHA)
3899            writeValue("alpha_blend");
3900        else
3901        {
3902            writeSceneBlendFactor(sbf_src);
3903            writeSceneBlendFactor(sbf_dst);
3904        }
3905    }
3906    //-----------------------------------------------------------------------
3907    void MaterialSerializer::writeCompareFunction(const CompareFunction cf)
3908    {
3909        switch (cf)
3910        {
3911        case CMPF_ALWAYS_FAIL:
3912            writeValue("always_fail");
3913            break;
3914        case CMPF_ALWAYS_PASS:
3915            writeValue("always_pass");
3916            break;
3917        case CMPF_EQUAL:
3918            writeValue("equal");
3919            break;
3920        case CMPF_GREATER:
3921            writeValue("greater");
3922            break;
3923        case CMPF_GREATER_EQUAL:
3924            writeValue("greater_equal");
3925            break;
3926        case CMPF_LESS:
3927            writeValue("less");
3928            break;
3929        case CMPF_LESS_EQUAL:
3930            writeValue("less_equal");
3931            break;
3932        case CMPF_NOT_EQUAL:
3933            writeValue("not_equal");
3934            break;
3935        }
3936    }
3937    //-----------------------------------------------------------------------
3938    void MaterialSerializer::writeColourValue(const ColourValue &colour, bool writeAlpha)
3939    {
3940        writeValue(StringConverter::toString(colour.r));
3941        writeValue(StringConverter::toString(colour.g));
3942        writeValue(StringConverter::toString(colour.b));
3943        if (writeAlpha)
3944            writeValue(StringConverter::toString(colour.a));
3945    }
3946    //-----------------------------------------------------------------------
3947    void MaterialSerializer::writeLayerBlendOperationEx(const LayerBlendOperationEx op)
3948    {
3949        switch (op)
3950        {
3951        case LBX_ADD:
3952            writeValue("add");
3953            break;
3954        case LBX_ADD_SIGNED:
3955            writeValue("add_signed");
3956            break;
3957        case LBX_ADD_SMOOTH:
3958            writeValue("add_smooth");
3959            break;
3960        case LBX_BLEND_CURRENT_ALPHA:
3961            writeValue("blend_current_alpha");
3962            break;
3963        case LBX_BLEND_DIFFUSE_COLOUR:
3964            writeValue("blend_diffuse_colour");
3965            break;
3966        case LBX_BLEND_DIFFUSE_ALPHA:
3967            writeValue("blend_diffuse_alpha");
3968            break;
3969        case LBX_BLEND_MANUAL:
3970            writeValue("blend_manual");
3971            break;
3972        case LBX_BLEND_TEXTURE_ALPHA:
3973            writeValue("blend_texture_alpha");
3974            break;
3975        case LBX_MODULATE:
3976            writeValue("modulate");
3977            break;
3978        case LBX_MODULATE_X2:
3979            writeValue("modulate_x2");
3980            break;
3981        case LBX_MODULATE_X4:
3982            writeValue("modulate_x4");
3983            break;
3984        case LBX_SOURCE1:
3985            writeValue("source1");
3986            break;
3987        case LBX_SOURCE2:
3988            writeValue("source2");
3989            break;
3990        case LBX_SUBTRACT:
3991            writeValue("subtract");
3992            break;
3993        case LBX_DOTPRODUCT:
3994            writeValue("dotproduct");
3995            break;
3996        }
3997    }
3998    //-----------------------------------------------------------------------
3999    void MaterialSerializer::writeLayerBlendSource(const LayerBlendSource lbs)
4000    {
4001        switch (lbs)
4002        {
4003        case LBS_CURRENT:
4004            writeValue("src_current");
4005            break;
4006        case LBS_DIFFUSE:
4007            writeValue("src_diffuse");
4008            break;
4009        case LBS_MANUAL:
4010            writeValue("src_manual");
4011            break;
4012        case LBS_SPECULAR:
4013            writeValue("src_specular");
4014            break;
4015        case LBS_TEXTURE:
4016            writeValue("src_texture");
4017            break;
4018        }
4019    }
4020
4021    // nfz
4022    //-----------------------------------------------------------------------
4023    void MaterialSerializer::writeVertexProgramRef(const Pass* pPass)
4024    {
4025        writeGpuProgramRef("vertex_program_ref",
4026            pPass->getVertexProgram(), pPass->getVertexProgramParameters());
4027    }
4028    //-----------------------------------------------------------------------
4029    void MaterialSerializer::writeShadowCasterVertexProgramRef(const Pass* pPass)
4030    {
4031        writeGpuProgramRef("shadow_caster_vertex_program_ref",
4032            pPass->getShadowCasterVertexProgram(), pPass->getShadowCasterVertexProgramParameters());
4033    }
4034    //-----------------------------------------------------------------------
4035    void MaterialSerializer::writeShadowReceiverVertexProgramRef(const Pass* pPass)
4036    {
4037        writeGpuProgramRef("shadow_receiver_vertex_program_ref",
4038            pPass->getShadowReceiverVertexProgram(), pPass->getShadowReceiverVertexProgramParameters());
4039    }
4040    //-----------------------------------------------------------------------
4041    void MaterialSerializer::writeShadowReceiverFragmentProgramRef(const Pass* pPass)
4042    {
4043        writeGpuProgramRef("shadow_receiver_fragment_program_ref",
4044            pPass->getShadowReceiverFragmentProgram(), pPass->getShadowReceiverFragmentProgramParameters());
4045    }
4046    //-----------------------------------------------------------------------
4047    void MaterialSerializer::writeFragmentProgramRef(const Pass* pPass)
4048    {
4049        writeGpuProgramRef("fragment_program_ref",
4050            pPass->getFragmentProgram(), pPass->getFragmentProgramParameters());
4051    }
4052    //-----------------------------------------------------------------------
4053    void MaterialSerializer::writeGpuProgramRef(const String& attrib,
4054        const GpuProgramPtr& program, const GpuProgramParametersSharedPtr& params)
4055    {
4056        mBuffer += "\n";
4057        writeAttribute(3, attrib);
4058        writeValue(program->getName());
4059        beginSection(3);
4060        {
4061            // write out paramters
4062            GpuProgramParameters* defaultParams= 0;
4063            // does the GPU program have default parameters?
4064            if (program->hasDefaultParameters())
4065                defaultParams = program->getDefaultParameters().getPointer();
4066
4067            writeGPUProgramParameters(params, defaultParams);
4068        }
4069        endSection(3);
4070
4071        // add to GpuProgram contatiner
4072        mGpuProgramDefinitionContainer.insert(program->getName());
4073    }
4074    //-----------------------------------------------------------------------
4075    static bool isConstantRealValsEqual(const GpuProgramParameters::RealConstantEntry* constEntry,
4076        const GpuProgramParameters::RealConstantEntry* defaultEntry, const size_t elementCount)
4077    {
4078        assert(constEntry && defaultEntry);
4079        // assume values are equal
4080        bool isEqual = false;
4081
4082        if (constEntry && defaultEntry)
4083        {
4084            // assume values are equal
4085            isEqual = true;
4086            size_t currentIndex = 0;
4087            // iterate through real constants
4088            while ((currentIndex < elementCount) && isEqual)
4089            {
4090                // compare the values within the constant entry
4091                size_t idx = 0;
4092                while ((idx < 4) && (currentIndex < elementCount) && isEqual)
4093                {
4094                    if (constEntry->val[idx] != defaultEntry->val[idx])
4095                        isEqual = false;
4096                    ++idx;
4097                    ++currentIndex;
4098                }
4099                ++constEntry;
4100                ++defaultEntry;
4101            }
4102
4103        }
4104
4105        return isEqual;
4106    }
4107
4108    //-----------------------------------------------------------------------
4109    static bool isConstantIntValsEqual(const GpuProgramParameters::IntConstantEntry* constEntry,
4110        const GpuProgramParameters::IntConstantEntry* defaultEntry, const size_t elementCount)
4111    {
4112        assert(constEntry && defaultEntry);
4113        // assume values are equal
4114        bool isEqual = false;
4115
4116        if (constEntry && defaultEntry)
4117        {
4118            // assume values are equal
4119            isEqual = true;
4120            size_t currentIndex = 0;
4121            // iterate through real constants
4122            while ((currentIndex < elementCount) && isEqual)
4123            {
4124                // compare the values within the constant entry
4125                size_t idx = 0;
4126                while ((idx < 4) && (currentIndex < elementCount) && isEqual)
4127                {
4128                    if (constEntry->val[idx] != defaultEntry->val[idx])
4129                        isEqual = false;
4130                    ++idx;
4131                    ++currentIndex;
4132                }
4133                ++constEntry;
4134                ++defaultEntry;
4135            }
4136
4137        }
4138
4139        return isEqual;
4140    }
4141
4142
4143    //-----------------------------------------------------------------------
4144    void MaterialSerializer::writeGPUProgramParameters(
4145                const GpuProgramParametersSharedPtr& params,
4146                GpuProgramParameters* defaultParams, const int level,
4147                const bool useMainBuffer)
4148    {
4149        // iterate through the constant definitions
4150        const size_t paramCount = params->getNumConstantDefinitions();
4151        size_t paramIndex = 0;
4152        while (paramIndex < paramCount)
4153        {
4154            // get the constant definition
4155            const GpuProgramParameters::ConstantDefinition* constDef =
4156                                params->getConstantDefinition(paramIndex);
4157            // only output if the constant definition exists and its actually being used
4158            // assume its being used if elementCount > 0
4159            if (constDef && constDef->elementCount)
4160            {
4161                // don't duplicate constants that are defined as a default parameter
4162                bool defaultExist = false;
4163                if (defaultParams)
4164                {
4165                    // find matching default parameter
4166                    const GpuProgramParameters::ConstantDefinition* defaultConstDef =
4167                        defaultParams->findMatchingConstantDefinition(
4168                                                        constDef->name, constDef->entryIndex, constDef->elementType);
4169
4170                    if (defaultConstDef)
4171                    {
4172                        // check all the elements for being equal
4173                        // auto settings must be the same to be equal
4174                        if ((defaultConstDef->isAuto && constDef->isAuto) &&
4175                                                        (defaultConstDef->autoIndex == constDef->autoIndex))
4176                        {
4177                            defaultExist = true;
4178                        }
4179                        else // check the values
4180                        {
4181                            if (constDef->elementType == GpuProgramParameters::ET_REAL)
4182                            {
4183                                const GpuProgramParameters::RealConstantEntry* constEntry =
4184                                    params->getRealConstantEntry(constDef->entryIndex);
4185
4186                                if (!constEntry)
4187                                    // no constant entry found so pretend default value exist and don't output anything
4188                                    defaultExist = true;
4189                                else
4190                                {
4191                                    const GpuProgramParameters::RealConstantEntry* defaultEntry =
4192                                        defaultParams->getRealConstantEntry(defaultConstDef->entryIndex);
4193                                    // compare current pass gpu parameter value with defualt entry parameter values
4194                                    // only ouput if they are different
4195                                    defaultExist = isConstantRealValsEqual(constEntry, defaultEntry, constDef->elementCount);
4196                                }
4197                            }
4198                            else // dealing with int
4199                            {
4200                                const GpuProgramParameters::IntConstantEntry* constEntry =
4201                                    params->getIntConstantEntry(constDef->entryIndex);
4202
4203                                if (!constEntry)
4204                                    // no constant entry found so pretend default value exist and don't output anything
4205                                    defaultExist = true;
4206                                else
4207                                {
4208                                    const GpuProgramParameters::IntConstantEntry* defaultEntry =
4209                                        defaultParams->getIntConstantEntry(defaultConstDef->entryIndex);
4210
4211                                    // compare current pass gpu parameter values with defualt entry parameter values
4212                                    // only ouput if they are different
4213                                    defaultExist = isConstantIntValsEqual(constEntry, defaultEntry, constDef->elementCount);
4214                                }
4215                            }
4216
4217                        }
4218                    }
4219
4220                }
4221
4222                if (!defaultExist)
4223                {
4224                    String label;
4225                    // is the param named
4226                    if (!constDef->name.empty())
4227                        label = "param_named";
4228                    else
4229                        label = "param_indexed";
4230                    // is it auto
4231                    if (constDef->isAuto)
4232                        label += "_auto";
4233
4234                    writeAttribute(level, label, useMainBuffer);
4235                    // output param name or index
4236                    if (!constDef->name.empty())
4237                        writeValue(constDef->name, useMainBuffer);
4238                    else
4239                        writeValue(StringConverter::toString(constDef->entryIndex), useMainBuffer);
4240
4241                    // if auto output auto type name and data if needed
4242                    if (constDef->isAuto)
4243                    {
4244                        // get the auto constant entry associated with this constant definition
4245                        const GpuProgramParameters::AutoConstantEntry* autoEntry =
4246                            params->getAutoConstantEntry(constDef->autoIndex);
4247
4248                        if (autoEntry)
4249                        {
4250                            const GpuProgramParameters::AutoConstantDefinition* autoConstDef =
4251                                GpuProgramParameters::getAutoConstantDefinition(autoEntry->paramType);
4252
4253                            assert(autoConstDef && "Bad auto constant Definition Table");
4254                            // output auto constant name
4255                            writeValue(autoConstDef->name, useMainBuffer);
4256                            // output data if it uses it
4257                            switch(autoConstDef->dataType)
4258                            {
4259                            case GpuProgramParameters::ACDT_REAL:
4260                                writeValue(StringConverter::toString(autoEntry->fData), useMainBuffer);
4261                                break;
4262
4263                            case GpuProgramParameters::ACDT_INT:
4264                                writeValue(StringConverter::toString(autoEntry->data), useMainBuffer);
4265                                break;
4266                            }
4267                        }
4268                    }
4269                    else // not auto so output all the values used
4270                    {
4271                        String countLabel;
4272                        const size_t elementCount = constDef->elementCount;
4273                        // get starting index for constant
4274                        size_t entryIndex = constDef->entryIndex;
4275                        size_t currentIndex = 0;
4276
4277                        // only write a number if > 1
4278                        if (elementCount > 1)
4279                            countLabel = StringConverter::toString(elementCount);
4280
4281                        if (constDef->elementType == GpuProgramParameters::ET_REAL)
4282                        {
4283                            writeValue("float" + countLabel, useMainBuffer);
4284                            // iterate through real constants
4285                            while (currentIndex < elementCount)
4286                            {
4287                                // get the constant entry
4288                                const GpuProgramParameters::RealConstantEntry* constEntry =
4289                                    params->getRealConstantEntry(entryIndex);
4290
4291                                // output the values within the constant entry
4292                                size_t idx = 0;
4293                                while ((idx < 4) && (currentIndex < elementCount))
4294                                {
4295                                    writeValue(StringConverter::toString(constEntry->val[idx]), useMainBuffer);
4296                                    ++idx;
4297                                    ++currentIndex;
4298                                }
4299                                ++entryIndex;
4300                            }
4301
4302                        }
4303                        else
4304                        {
4305                            writeValue("int" + countLabel, useMainBuffer);
4306                            // iterate through int constants
4307                            while (currentIndex < elementCount)
4308                            {
4309                                // get the constant entry
4310                                const GpuProgramParameters::IntConstantEntry* constEntry =
4311                                    params->getIntConstantEntry(entryIndex + currentIndex);
4312
4313                                // output the values within the constant entry
4314                                size_t idx = 0;
4315                                while ((idx < 4) && (currentIndex < elementCount))
4316                                {
4317                                    writeValue(StringConverter::toString(constEntry->val[idx]), useMainBuffer);
4318                                    ++idx;
4319                                    ++currentIndex;
4320                                }
4321                                ++entryIndex;
4322                            }
4323
4324                        }
4325                    }
4326                } // end if (!defaultExist)
4327
4328            } // end if
4329
4330            ++paramIndex;
4331
4332        } // end while
4333
4334    }
4335
4336    //-----------------------------------------------------------------------
4337    void MaterialSerializer::writeGpuPrograms(void)
4338    {
4339        // iterate through gpu program names in container
4340        GpuProgramDefIterator currentDef = mGpuProgramDefinitionContainer.begin();
4341        GpuProgramDefIterator endDef = mGpuProgramDefinitionContainer.end();
4342
4343        while (currentDef != endDef)
4344        {
4345            // get gpu program from gpu program manager
4346            GpuProgramPtr program = GpuProgramManager::getSingleton().getByName((*currentDef));
4347            // write gpu program definition type to buffer
4348            // check program type for vertex program
4349            // write program type
4350            mGpuProgramBuffer += "\n";
4351            writeAttribute(0, program->getParameter("type"), false);
4352
4353            // write program name
4354            writeValue( program->getName(), false);
4355            // write program language
4356            const String language = program->getLanguage();
4357            writeValue( language, false );
4358            // write opening braces
4359            beginSection(0, false);
4360            {
4361                // write program source + filenmae
4362                writeAttribute(1, "source", false);
4363                writeValue(program->getSourceFile(), false);
4364                // write special parameters based on language
4365                const ParameterList& params = program->getParameters();
4366                ParameterList::const_iterator currentParam = params.begin();
4367                ParameterList::const_iterator endParam = params.end();
4368
4369                while (currentParam != endParam)
4370                {
4371                    if (currentParam->name != "type")
4372                    {
4373                        String paramstr = program->getParameter(currentParam->name);
4374                        if ((currentParam->name == "includes_skeletal_animation")
4375                            && (paramstr == "false"))
4376                            paramstr = "";
4377                                                if ((currentParam->name == "includes_morph_animation")
4378                                                        && (paramstr == "false"))
4379                                                        paramstr = "";
4380
4381                        if ((language != "asm") && (currentParam->name == "syntax"))
4382                            paramstr = "";
4383
4384                        if (!paramstr.empty())
4385                        {
4386                            writeAttribute(1, currentParam->name, false);
4387                            writeValue(paramstr, false);
4388                        }
4389                    }
4390                    ++currentParam;
4391                }
4392
4393                // write default parameters
4394                if (program->hasDefaultParameters())
4395                {
4396                    mGpuProgramBuffer += "\n";
4397                    GpuProgramParametersSharedPtr gpuDefaultParams = program->getDefaultParameters();
4398                    writeAttribute(1, "default_params", false);
4399                    beginSection(1, false);
4400                    writeGPUProgramParameters(gpuDefaultParams, 0, 2, false);
4401                    endSection(1, false);
4402                }
4403            }
4404            // write closing braces
4405            endSection(0, false);
4406
4407            ++currentDef;
4408
4409        }
4410
4411        mGpuProgramBuffer += "\n";
4412    }
4413
4414
4415
4416}
Note: See TracBrowser for help on using the repository browser.