source: OGRE/trunk/ogrenew/OgreMain/src/OgreMaterialSerializer.cpp @ 692

Revision 692, 169.6 KB checked in by mattausch, 18 years ago (diff)

adding ogre 1.2 and dependencies

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