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

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