Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/OgreMain/src/OgreMaterialSerializer.cpp @ 3

Last change on this file since 3 was 3, checked in by anonymous, 17 years ago

=update

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