Irrlicht 3D Engine
IQ3Shader.h
Go to the documentation of this file.
00001 // Copyright (C) 2006-2012 Nikolaus Gebhardt / Thomas Alten
00002 // This file is part of the "Irrlicht Engine".
00003 // For conditions of distribution and use, see copyright notice in irrlicht.h
00004 
00005 #ifndef __I_Q3_LEVEL_SHADER_H_INCLUDED__
00006 #define __I_Q3_LEVEL_SHADER_H_INCLUDED__
00007 
00008 #include "irrArray.h"
00009 #include "fast_atof.h"
00010 #include "IFileSystem.h"
00011 #include "IVideoDriver.h"
00012 #include "coreutil.h"
00013 
00014 namespace irr
00015 {
00016 namespace scene
00017 {
00018 namespace quake3
00019 {
00020 
00021     static core::stringc irrEmptyStringc("");
00022 
00024     enum eQ3MeshIndex
00025     {
00026         E_Q3_MESH_GEOMETRY = 0,
00027         E_Q3_MESH_ITEMS,
00028         E_Q3_MESH_BILLBOARD,
00029         E_Q3_MESH_FOG,
00030         E_Q3_MESH_UNRESOLVED,
00031         E_Q3_MESH_SIZE
00032     };
00033 
00037     struct Q3LevelLoadParameter
00038     {
00039         Q3LevelLoadParameter ()
00040             :defaultLightMapMaterial ( video::EMT_LIGHTMAP_M4 ),
00041             defaultModulate ( video::EMFN_MODULATE_4X ),
00042             defaultFilter ( video::EMF_BILINEAR_FILTER ),
00043             patchTesselation ( 8 ),
00044             verbose ( 0 ),
00045             startTime ( 0 ), endTime ( 0 ),
00046             mergeShaderBuffer ( 1 ),
00047             cleanUnResolvedMeshes ( 1 ),
00048             loadAllShaders ( 0 ),
00049             loadSkyShader ( 0 ),
00050             alpharef ( 1 ),
00051             swapLump ( 0 ),
00052     #ifdef __BIG_ENDIAN__
00053             swapHeader ( 1 )
00054     #else
00055             swapHeader ( 0 )
00056     #endif
00057             {
00058                 memcpy ( scriptDir, "scripts\x0", 8 );
00059             }
00060 
00061         video::E_MATERIAL_TYPE defaultLightMapMaterial;
00062         video::E_MODULATE_FUNC defaultModulate;
00063         video::E_MATERIAL_FLAG defaultFilter;
00064         s32 patchTesselation;
00065         s32 verbose;
00066         u32 startTime;
00067         u32 endTime;
00068         s32 mergeShaderBuffer;
00069         s32 cleanUnResolvedMeshes;
00070         s32 loadAllShaders;
00071         s32 loadSkyShader;
00072         s32 alpharef;
00073         s32 swapLump;
00074         s32 swapHeader;
00075         c8 scriptDir [ 64 ];
00076     };
00077 
00078     // some useful typedefs
00079     typedef core::array< core::stringc > tStringList;
00080     typedef core::array< video::ITexture* > tTexArray;
00081 
00082     // string helper.. TODO: move to generic files
00083     inline s16 isEqual ( const core::stringc &string, u32 &pos, const c8 *list[], u16 listSize )
00084     {
00085         const char * in = string.c_str () + pos;
00086 
00087         for ( u16 i = 0; i != listSize; ++i )
00088         {
00089             if (string.size() < pos)
00090                 return -2;
00091             u32 len = (u32) strlen ( list[i] );
00092             if (string.size() < pos+len)
00093                 continue;
00094             if ( in [len] != 0 && in [len] != ' ' )
00095                 continue;
00096             if ( strncmp ( in, list[i], len ) )
00097                 continue;
00098 
00099             pos += len + 1;
00100             return (s16) i;
00101         }
00102         return -2;
00103     }
00104 
00105     inline f32 getAsFloat ( const core::stringc &string, u32 &pos )
00106     {
00107         const char * in = string.c_str () + pos;
00108 
00109         f32 value = 0.f;
00110         pos += (u32) ( core::fast_atof_move ( in, value ) - in ) + 1;
00111         return value;
00112     }
00113 
00115     inline core::vector3df getAsVector3df ( const core::stringc &string, u32 &pos )
00116     {
00117         core::vector3df v;
00118 
00119         v.X = getAsFloat ( string, pos );
00120         v.Z = getAsFloat ( string, pos );
00121         v.Y = getAsFloat ( string, pos );
00122 
00123         return v;
00124     }
00125 
00126 
00127     /*
00128         extract substrings
00129     */
00130     inline void getAsStringList ( tStringList &list, s32 max, const core::stringc &string, u32 &startPos )
00131     {
00132         list.clear ();
00133 
00134         s32 finish = 0;
00135         s32 endPos;
00136         do
00137         {
00138             endPos = string.findNext ( ' ', startPos );
00139             if ( endPos == -1 )
00140             {
00141                 finish = 1;
00142                 endPos = string.size();
00143             }
00144 
00145             list.push_back ( string.subString ( startPos, endPos - startPos ) );
00146             startPos = endPos + 1;
00147 
00148             if ( list.size() >= (u32) max )
00149                 finish = 1;
00150 
00151         } while ( !finish );
00152 
00153     }
00154 
00156     struct SBlendFunc
00157     {
00158         SBlendFunc ( video::E_MODULATE_FUNC mod )
00159             : type ( video::EMT_SOLID ), modulate ( mod ),
00160                 param0( 0.f ),
00161             isTransparent ( 0 ) {}
00162 
00163         video::E_MATERIAL_TYPE type;
00164         video::E_MODULATE_FUNC modulate;
00165 
00166         f32 param0;
00167         u32 isTransparent;
00168     };
00169 
00170     // parses the content of Variable cull
00171     inline bool getCullingFunction ( const core::stringc &cull )
00172     {
00173         if ( cull.size() == 0 )
00174             return true;
00175 
00176         bool ret = true;
00177         static const c8 * funclist[] = { "none", "disable", "twosided" };
00178 
00179         u32 pos = 0;
00180         switch ( isEqual ( cull, pos, funclist, 3 ) )
00181         {
00182             case 0:
00183             case 1:
00184             case 2:
00185                 ret = false;
00186                 break;
00187         }
00188         return ret;
00189     }
00190 
00191     // parses the content of Variable depthfunc
00192     // return a z-test
00193     inline u8 getDepthFunction ( const core::stringc &string )
00194     {
00195         u8 ret = video::ECFN_LESSEQUAL;
00196 
00197         if ( string.size() == 0 )
00198             return ret;
00199 
00200         static const c8 * funclist[] = { "lequal","equal" };
00201 
00202         u32 pos = 0;
00203         switch ( isEqual ( string, pos, funclist, 2 ) )
00204         {
00205             case 0:
00206                 ret = video::ECFN_LESSEQUAL;
00207                 break;
00208             case 1:
00209                 ret = video::ECFN_EQUAL;
00210                 break;
00211         }
00212         return ret;
00213     }
00214 
00215 
00227     inline static void getBlendFunc ( const core::stringc &string, SBlendFunc &blendfunc )
00228     {
00229         if ( string.size() == 0 )
00230             return;
00231 
00232         // maps to E_BLEND_FACTOR
00233         static const c8 * funclist[] =
00234         {
00235             "gl_zero",
00236             "gl_one",
00237             "gl_dst_color",
00238             "gl_one_minus_dst_color",
00239             "gl_src_color",
00240             "gl_one_minus_src_color",
00241             "gl_src_alpha",
00242             "gl_one_minus_src_alpha",
00243             "gl_dst_alpha",
00244             "gl_one_minus_dst_alpha",
00245             "gl_src_alpha_sat",
00246 
00247             "add",
00248             "filter",
00249             "blend",
00250 
00251             "ge128",
00252             "gt0",
00253         };
00254 
00255 
00256         u32 pos = 0;
00257         s32 srcFact = isEqual ( string, pos, funclist, 16 );
00258 
00259         if ( srcFact < 0 )
00260             return;
00261 
00262         u32 resolved = 0;
00263         s32 dstFact = isEqual ( string, pos, funclist, 16 );
00264 
00265         switch ( srcFact )
00266         {
00267             case video::EBF_ZERO:
00268                 switch ( dstFact )
00269                 {
00270                     // gl_zero gl_src_color == gl_dst_color gl_zero
00271                     case video::EBF_SRC_COLOR:
00272                         blendfunc.type = video::EMT_ONETEXTURE_BLEND;
00273                         blendfunc.param0 = video::pack_textureBlendFunc ( video::EBF_DST_COLOR, video::EBF_ZERO, blendfunc.modulate );
00274                         blendfunc.isTransparent = 1;
00275                         resolved = 1;
00276                         break;
00277                 } break;
00278 
00279             case video::EBF_ONE:
00280                 switch ( dstFact )
00281                 {
00282                     // gl_one gl_zero
00283                     case video::EBF_ZERO:
00284                         blendfunc.type = video::EMT_SOLID;
00285                         blendfunc.isTransparent = 0;
00286                         resolved = 1;
00287                         break;
00288 
00289                     // gl_one gl_one
00290                     case video::EBF_ONE:
00291                         blendfunc.type = video::EMT_TRANSPARENT_ADD_COLOR;
00292                         blendfunc.isTransparent = 1;
00293                         resolved = 1;
00294                         break;
00295                 } break;
00296 
00297             case video::EBF_SRC_ALPHA:
00298                 switch ( dstFact )
00299                 {
00300                     // gl_src_alpha gl_one_minus_src_alpha
00301                     case video::EBF_ONE_MINUS_SRC_ALPHA:
00302                         blendfunc.type = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
00303                         blendfunc.param0 = 1.f/255.f;
00304                         blendfunc.isTransparent = 1;
00305                         resolved = 1;
00306                         break;
00307                 } break;
00308 
00309             case 11:
00310                 // add
00311                 blendfunc.type = video::EMT_TRANSPARENT_ADD_COLOR;
00312                 blendfunc.isTransparent = 1;
00313                 resolved = 1;
00314                 break;
00315             case 12:
00316                 // filter = gl_dst_color gl_zero or gl_zero gl_src_color
00317                 blendfunc.type = video::EMT_ONETEXTURE_BLEND;
00318                 blendfunc.param0 = video::pack_textureBlendFunc ( video::EBF_DST_COLOR, video::EBF_ZERO, blendfunc.modulate );
00319                 blendfunc.isTransparent = 1;
00320                 resolved = 1;
00321                 break;
00322             case 13:
00323                 // blend = gl_src_alpha gl_one_minus_src_alpha
00324                 blendfunc.type = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
00325                 blendfunc.param0 = 1.f/255.f;
00326                 blendfunc.isTransparent = 1;
00327                 resolved = 1;
00328                 break;
00329             case 14:
00330                 // alphafunc ge128
00331                 blendfunc.type = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
00332                 blendfunc.param0 = 0.5f;
00333                 blendfunc.isTransparent = 1;
00334                 resolved = 1;
00335                 break;
00336             case 15:
00337                 // alphafunc gt0
00338                 blendfunc.type = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
00339                 blendfunc.param0 = 1.f / 255.f;
00340                 blendfunc.isTransparent = 1;
00341                 resolved = 1;
00342                 break;
00343 
00344         }
00345 
00346         // use the generic blender
00347         if ( 0 == resolved )
00348         {
00349             blendfunc.type = video::EMT_ONETEXTURE_BLEND;
00350             blendfunc.param0 = video::pack_textureBlendFunc (
00351                     (video::E_BLEND_FACTOR) srcFact,
00352                     (video::E_BLEND_FACTOR) dstFact,
00353                     blendfunc.modulate);
00354 
00355             blendfunc.isTransparent = 1;
00356         }
00357     }
00358 
00359     // random noise [-1;1]
00360     struct Noiser
00361     {
00362         static f32 get ()
00363         {
00364             static u32 RandomSeed = 0x69666966;
00365             RandomSeed = (RandomSeed * 3631 + 1);
00366 
00367             f32 value = ( (f32) (RandomSeed & 0x7FFF ) * (1.0f / (f32)(0x7FFF >> 1) ) ) - 1.f;
00368             return value;
00369         }
00370     };
00371 
00372     enum eQ3ModifierFunction
00373     {
00374         TCMOD               = 0,
00375         DEFORMVERTEXES      = 1,
00376         RGBGEN              = 2,
00377         TCGEN               = 3,
00378         MAP                 = 4,
00379         ALPHAGEN            = 5,
00380 
00381         FUNCTION2           = 0x10,
00382         SCROLL              = FUNCTION2 + 1,
00383         SCALE               = FUNCTION2 + 2,
00384         ROTATE              = FUNCTION2 + 3,
00385         STRETCH             = FUNCTION2 + 4,
00386         TURBULENCE          = FUNCTION2 + 5,
00387         WAVE                = FUNCTION2 + 6,
00388 
00389         IDENTITY            = FUNCTION2 + 7,
00390         VERTEX              = FUNCTION2 + 8,
00391         TEXTURE             = FUNCTION2 + 9,
00392         LIGHTMAP            = FUNCTION2 + 10,
00393         ENVIRONMENT         = FUNCTION2 + 11,
00394         DOLLAR_LIGHTMAP     = FUNCTION2 + 12,
00395         BULGE               = FUNCTION2 + 13,
00396         AUTOSPRITE          = FUNCTION2 + 14,
00397         AUTOSPRITE2         = FUNCTION2 + 15,
00398         TRANSFORM           = FUNCTION2 + 16,
00399         EXACTVERTEX         = FUNCTION2 + 17,
00400         CONSTANT            = FUNCTION2 + 18,
00401         LIGHTINGSPECULAR    = FUNCTION2 + 19,
00402         MOVE                = FUNCTION2 + 20,
00403         NORMAL              = FUNCTION2 + 21,
00404         IDENTITYLIGHTING    = FUNCTION2 + 22,
00405 
00406         WAVE_MODIFIER_FUNCTION  = 0x30,
00407         SINUS               = WAVE_MODIFIER_FUNCTION + 1,
00408         COSINUS             = WAVE_MODIFIER_FUNCTION + 2,
00409         SQUARE              = WAVE_MODIFIER_FUNCTION + 3,
00410         TRIANGLE            = WAVE_MODIFIER_FUNCTION + 4,
00411         SAWTOOTH            = WAVE_MODIFIER_FUNCTION + 5,
00412         SAWTOOTH_INVERSE    = WAVE_MODIFIER_FUNCTION + 6,
00413         NOISE               = WAVE_MODIFIER_FUNCTION + 7,
00414 
00415 
00416         UNKNOWN             = -2
00417 
00418     };
00419 
00420     struct SModifierFunction
00421     {
00422         SModifierFunction ()
00423             : masterfunc0 ( UNKNOWN ), masterfunc1( UNKNOWN ), func ( SINUS ),
00424             tcgen( TEXTURE ), rgbgen ( IDENTITY ), alphagen ( UNKNOWN ),
00425             base ( 0 ), amp ( 1 ), phase ( 0 ), frequency ( 1 ),
00426             wave ( 1 ),
00427             x ( 0 ), y ( 0 ), z( 0 ), count( 0 ) {}
00428 
00429         // "tcmod","deformvertexes","rgbgen", "tcgen"
00430         eQ3ModifierFunction masterfunc0;
00431         // depends
00432         eQ3ModifierFunction masterfunc1;
00433         // depends
00434         eQ3ModifierFunction func;
00435 
00436         eQ3ModifierFunction tcgen;
00437         eQ3ModifierFunction rgbgen;
00438         eQ3ModifierFunction alphagen;
00439 
00440         union
00441         {
00442             f32 base;
00443             f32 bulgewidth;
00444         };
00445 
00446         union
00447         {
00448             f32 amp;
00449             f32 bulgeheight;
00450         };
00451 
00452         f32 phase;
00453 
00454         union
00455         {
00456             f32 frequency;
00457             f32 bulgespeed;
00458         };
00459 
00460         union
00461         {
00462             f32 wave;
00463             f32 div;
00464         };
00465 
00466         f32 x;
00467         f32 y;
00468         f32 z;
00469         u32 count;
00470 
00471         f32 evaluate ( f32 dt ) const
00472         {
00473             // phase in 0 and 1..
00474             f32 x = core::fract( (dt + phase ) * frequency );
00475             f32 y = 0.f;
00476 
00477             switch ( func )
00478             {
00479                 case SINUS:
00480                     y = sinf ( x * core::PI * 2.f );
00481                     break;
00482                 case COSINUS:
00483                     y = cosf ( x * core::PI * 2.f );
00484                     break;
00485                 case SQUARE:
00486                     y = x < 0.5f ? 1.f : -1.f;
00487                     break;
00488                 case TRIANGLE:
00489                     y = x < 0.5f ? ( 4.f * x ) - 1.f : ( -4.f * x ) + 3.f;
00490                     break;
00491                 case SAWTOOTH:
00492                     y = x;
00493                     break;
00494                 case SAWTOOTH_INVERSE:
00495                     y = 1.f - x;
00496                     break;
00497                 case NOISE:
00498                     y = Noiser::get();
00499                     break;
00500                 default:
00501                     break;
00502             }
00503 
00504             return base + ( y * amp );
00505         }
00506 
00507 
00508     };
00509 
00510     inline core::vector3df getMD3Normal ( u32 i, u32 j )
00511     {
00512         const f32 lng = i * 2.0f * core::PI / 255.0f;
00513         const f32 lat = j * 2.0f * core::PI / 255.0f;
00514         return core::vector3df(cosf ( lat ) * sinf ( lng ),
00515                 sinf ( lat ) * sinf ( lng ),
00516                 cosf ( lng ));
00517     }
00518 
00519     //
00520     inline void getModifierFunc ( SModifierFunction& fill, const core::stringc &string, u32 &pos )
00521     {
00522         if ( string.size() == 0 )
00523             return;
00524 
00525         static const c8 * funclist[] =
00526         {
00527             "sin","cos","square",
00528             "triangle", "sawtooth","inversesawtooth", "noise"
00529         };
00530 
00531         fill.func = (eQ3ModifierFunction) isEqual ( string,pos, funclist,7 );
00532         fill.func = fill.func == UNKNOWN ? SINUS : (eQ3ModifierFunction) ((u32) fill.func + WAVE_MODIFIER_FUNCTION + 1);
00533 
00534         fill.base = getAsFloat ( string, pos );
00535         fill.amp = getAsFloat ( string, pos );
00536         fill.phase = getAsFloat ( string, pos );
00537         fill.frequency = getAsFloat ( string, pos );
00538     }
00539 
00540 
00541     // name = "a b c .."
00542     struct SVariable
00543     {
00544         core::stringc name;
00545         core::stringc content;
00546 
00547         SVariable ( const c8 * n, const c8 *c = 0 ) : name ( n ), content (c) {}
00548         virtual ~SVariable () {}
00549 
00550         void clear ()
00551         {
00552             name = "";
00553             content = "";
00554         }
00555 
00556         s32 isValid () const
00557         {
00558             return name.size();
00559         }
00560 
00561         bool operator == ( const SVariable &other ) const
00562         {
00563             return 0 == strcmp ( name.c_str(), other.name.c_str () );
00564         }
00565 
00566         bool operator < ( const SVariable &other ) const
00567         {
00568             return 0 > strcmp ( name.c_str(), other.name.c_str () );
00569         }
00570 
00571     };
00572 
00573 
00574     // string database. "a" = "Hello", "b" = "1234.6"
00575     struct SVarGroup
00576     {
00577         SVarGroup () { Variable.setAllocStrategy ( core::ALLOC_STRATEGY_SAFE ); }
00578         virtual ~SVarGroup () {}
00579 
00580         u32 isDefined ( const c8 * name, const c8 * content = 0 ) const
00581         {
00582             for ( u32 i = 0; i != Variable.size (); ++i )
00583             {
00584                 if ( 0 == strcmp ( Variable[i].name.c_str(), name ) &&
00585                     (  0 == content || strstr ( Variable[i].content.c_str(), content ) )
00586                     )
00587                 {
00588                     return i + 1;
00589                 }
00590             }
00591             return 0;
00592         }
00593 
00594         // searches for Variable name and returns is content
00595         // if Variable is not found a reference to an Empty String is returned
00596         const core::stringc &get( const c8 * name ) const
00597         {
00598             SVariable search ( name );
00599             s32 index = Variable.linear_search ( search );
00600             if ( index < 0 )
00601                 return irrEmptyStringc;
00602 
00603             return Variable [ index ].content;
00604         }
00605 
00606         // set the Variable name
00607         void set ( const c8 * name, const c8 * content = 0 )
00608         {
00609             u32 index = isDefined ( name, 0 );
00610             if ( 0 == index )
00611             {
00612                 Variable.push_back ( SVariable ( name, content ) );
00613             }
00614             else
00615             {
00616                 Variable [ index ].content = content;
00617             }
00618         }
00619 
00620 
00621         core::array < SVariable > Variable;
00622     };
00623 
00625     struct SVarGroupList: public IReferenceCounted
00626     {
00627         SVarGroupList ()
00628         {
00629             VariableGroup.setAllocStrategy ( core::ALLOC_STRATEGY_SAFE );
00630         }
00631         virtual ~SVarGroupList () {}
00632 
00633         core::array < SVarGroup > VariableGroup;
00634     };
00635 
00636 
00638     struct IShader
00639     {
00640         IShader ()
00641             : ID ( 0 ), VarGroup ( 0 )  {}
00642         virtual ~IShader () {}
00643 
00644         void operator = (const IShader &other )
00645         {
00646             ID = other.ID;
00647             VarGroup = other.VarGroup;
00648             name = other.name;
00649         }
00650 
00651         bool operator == (const IShader &other ) const
00652         {
00653             return 0 == strcmp ( name.c_str(), other.name.c_str () );
00654             //return name == other.name;
00655         }
00656 
00657         bool operator < (const IShader &other ) const
00658         {
00659             return strcmp ( name.c_str(), other.name.c_str () ) < 0;
00660             //return name < other.name;
00661         }
00662 
00663         u32 getGroupSize () const
00664         {
00665             if ( 0 == VarGroup )
00666                 return 0;
00667             return VarGroup->VariableGroup.size ();
00668         }
00669 
00670         const SVarGroup * getGroup ( u32 stage ) const
00671         {
00672             if ( 0 == VarGroup || stage >= VarGroup->VariableGroup.size () )
00673                 return 0;
00674 
00675             return &VarGroup->VariableGroup [ stage ];
00676         }
00677 
00678         // id
00679         s32 ID;
00680         SVarGroupList *VarGroup; // reference
00681 
00682         // Shader: shader name ( also first variable in first Vargroup )
00683         // Entity: classname ( variable in Group(1) )
00684         core::stringc name;
00685     };
00686 
00687     typedef IShader IEntity;
00688 
00689     typedef core::array < IEntity > tQ3EntityList;
00690 
00691     /*
00692         dump shader like original layout, regardless of internal data holding
00693         no recursive folding..
00694     */
00695     inline void dumpVarGroup ( core::stringc &dest, const SVarGroup * group, s32 stack )
00696     {
00697         core::stringc buf;
00698         s32 i;
00699 
00700 
00701         if ( stack > 0 )
00702         {
00703             buf = "";
00704             for ( i = 0; i < stack - 1; ++i )
00705                 buf += '\t';
00706 
00707             buf += "{\n";
00708             dest.append ( buf );
00709         }
00710 
00711         for ( u32 g = 0; g != group->Variable.size(); ++g )
00712         {
00713             buf = "";
00714             for ( i = 0; i < stack; ++i )
00715                 buf += '\t';
00716 
00717             buf += group->Variable[g].name;
00718             buf += " ";
00719             buf += group->Variable[g].content;
00720             buf += "\n";
00721             dest.append ( buf );
00722         }
00723 
00724         if ( stack > 1 )
00725         {
00726             buf = "";
00727             for ( i = 0; i < stack - 1; ++i )
00728                 buf += '\t';
00729 
00730             buf += "}\n";
00731             dest.append ( buf );
00732         }
00733 
00734     }
00735 
00739     inline core::stringc & dumpShader ( core::stringc &dest, const IShader * shader, bool entity = false )
00740     {
00741         if ( 0 == shader )
00742             return dest;
00743 
00744         const SVarGroup * group;
00745 
00746         const u32 size = shader->VarGroup->VariableGroup.size ();
00747         for ( u32 i = 0; i != size; ++i )
00748         {
00749             group = &shader->VarGroup->VariableGroup[ i ];
00750             dumpVarGroup ( dest, group, core::clamp( (int)i, 0, 2 ) );
00751         }
00752 
00753         if ( !entity )
00754         {
00755             if ( size <= 1 )
00756             {
00757                 dest.append ( "{\n" );
00758             }
00759             dest.append ( "}\n" );
00760         }
00761         return dest;
00762     }
00763 
00764 
00765     /*
00766         quake3 doesn't care much about tga & jpg
00767         load one or multiple files stored in name started at startPos to the texture array textures
00768         if texture is not loaded 0 will be added ( to find missing textures easier)
00769     */
00770     inline void getTextures(tTexArray &textures,
00771                 const core::stringc &name, u32 &startPos,
00772                 io::IFileSystem *fileSystem,
00773                 video::IVideoDriver* driver)
00774     {
00775         static const char* extension[] =
00776         {
00777             ".jpg",
00778             ".jpeg",
00779             ".png",
00780             ".dds",
00781             ".tga",
00782             ".bmp",
00783             ".pcx"
00784         };
00785 
00786         tStringList stringList;
00787         getAsStringList(stringList, -1, name, startPos);
00788 
00789         textures.clear();
00790 
00791         io::path loadFile;
00792         for ( u32 i = 0; i!= stringList.size (); ++i )
00793         {
00794             video::ITexture* texture = 0;
00795             for (u32 g = 0; g != 7 ; ++g)
00796             {
00797                 core::cutFilenameExtension ( loadFile, stringList[i] );
00798 
00799                 if ( loadFile == "$whiteimage" )
00800                 {
00801                     texture = driver->getTexture( "$whiteimage" );
00802                     if ( 0 == texture )
00803                     {
00804                         core::dimension2du s ( 2, 2 );
00805                         u32 image[4] = { 0xFFFFFFFF, 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF };
00806                         video::IImage* w = driver->createImageFromData ( video::ECF_A8R8G8B8, s,&image );
00807                         texture = driver->addTexture( "$whiteimage", w );
00808                         w->drop ();
00809                     }
00810 
00811                 }
00812                 else
00813                 if ( loadFile == "$redimage" )
00814                 {
00815                     texture = driver->getTexture( "$redimage" );
00816                     if ( 0 == texture )
00817                     {
00818                         core::dimension2du s ( 2, 2 );
00819                         u32 image[4] = { 0xFFFF0000, 0xFFFF0000,0xFFFF0000,0xFFFF0000 };
00820                         video::IImage* w = driver->createImageFromData ( video::ECF_A8R8G8B8, s,&image );
00821                         texture = driver->addTexture( "$redimage", w );
00822                         w->drop ();
00823                     }
00824                 }
00825                 else
00826                 if ( loadFile == "$blueimage" )
00827                 {
00828                     texture = driver->getTexture( "$blueimage" );
00829                     if ( 0 == texture )
00830                     {
00831                         core::dimension2du s ( 2, 2 );
00832                         u32 image[4] = { 0xFF0000FF, 0xFF0000FF,0xFF0000FF,0xFF0000FF };
00833                         video::IImage* w = driver->createImageFromData ( video::ECF_A8R8G8B8, s,&image );
00834                         texture = driver->addTexture( "$blueimage", w );
00835                         w->drop ();
00836                     }
00837                 }
00838                 else
00839                 if ( loadFile == "$checkerimage" )
00840                 {
00841                     texture = driver->getTexture( "$checkerimage" );
00842                     if ( 0 == texture )
00843                     {
00844                         core::dimension2du s ( 2, 2 );
00845                         u32 image[4] = { 0xFFFFFFFF, 0xFF000000,0xFF000000,0xFFFFFFFF };
00846                         video::IImage* w = driver->createImageFromData ( video::ECF_A8R8G8B8, s,&image );
00847                         texture = driver->addTexture( "$checkerimage", w );
00848                         w->drop ();
00849                     }
00850                 }
00851                 else
00852                 if ( loadFile == "$lightmap" )
00853                 {
00854                     texture = 0;
00855                 }
00856                 else
00857                 {
00858                     loadFile.append ( extension[g] );
00859                 }
00860 
00861                 if ( fileSystem->existFile ( loadFile ) )
00862                 {
00863                     texture = driver->getTexture( loadFile );
00864                     if ( texture )
00865                         break;
00866                     texture = 0;
00867                 }
00868             }
00869             // take 0 Texture
00870             textures.push_back(texture);
00871         }
00872     }
00873 
00874 
00876     class IShaderManager : public IReferenceCounted
00877     {
00878     };
00879 
00880 } // end namespace quake3
00881 } // end namespace scene
00882 } // end namespace irr
00883 
00884 #endif
00885