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

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