summaryrefslogtreecommitdiff
path: root/include/IQ3Shader.h
diff options
context:
space:
mode:
authorMirrorbot <mirrorbot@cogarr.net>2025-12-27 17:53:06 -0600
committerMirrorbot <mirrorbot@cogarr.net>2025-12-27 17:53:06 -0600
commit71e94ee161447b84c0eaabf6567f8fa62262cd3e (patch)
tree391064cc6173a6fe75069af2fdc1978af12f623e /include/IQ3Shader.h
downloadirrlicht-master.tar.gz
irrlicht-master.tar.bz2
irrlicht-master.zip
Inital commitHEADmaster
Diffstat (limited to 'include/IQ3Shader.h')
-rw-r--r--include/IQ3Shader.h885
1 files changed, 885 insertions, 0 deletions
diff --git a/include/IQ3Shader.h b/include/IQ3Shader.h
new file mode 100644
index 0000000..7dc15e5
--- /dev/null
+++ b/include/IQ3Shader.h
@@ -0,0 +1,885 @@
+// Copyright (C) 2006-2012 Nikolaus Gebhardt / Thomas Alten
+// This file is part of the "Irrlicht Engine".
+// For conditions of distribution and use, see copyright notice in irrlicht.h
+
+#ifndef __I_Q3_LEVEL_SHADER_H_INCLUDED__
+#define __I_Q3_LEVEL_SHADER_H_INCLUDED__
+
+#include "irrArray.h"
+#include "fast_atof.h"
+#include "IFileSystem.h"
+#include "IVideoDriver.h"
+#include "coreutil.h"
+
+namespace irr
+{
+namespace scene
+{
+namespace quake3
+{
+
+ static core::stringc irrEmptyStringc("");
+
+ //! Hold the different Mesh Types used for getMesh
+ enum eQ3MeshIndex
+ {
+ E_Q3_MESH_GEOMETRY = 0,
+ E_Q3_MESH_ITEMS,
+ E_Q3_MESH_BILLBOARD,
+ E_Q3_MESH_FOG,
+ E_Q3_MESH_UNRESOLVED,
+ E_Q3_MESH_SIZE
+ };
+
+ /*! used to customize Quake3 BSP Loader
+ */
+
+ struct Q3LevelLoadParameter
+ {
+ Q3LevelLoadParameter ()
+ :defaultLightMapMaterial ( video::EMT_LIGHTMAP_M4 ),
+ defaultModulate ( video::EMFN_MODULATE_4X ),
+ defaultFilter ( video::EMF_BILINEAR_FILTER ),
+ patchTesselation ( 8 ),
+ verbose ( 0 ),
+ startTime ( 0 ), endTime ( 0 ),
+ mergeShaderBuffer ( 1 ),
+ cleanUnResolvedMeshes ( 1 ),
+ loadAllShaders ( 0 ),
+ loadSkyShader ( 0 ),
+ alpharef ( 1 ),
+ swapLump ( 0 ),
+ #ifdef __BIG_ENDIAN__
+ swapHeader ( 1 )
+ #else
+ swapHeader ( 0 )
+ #endif
+ {
+ memcpy ( scriptDir, "scripts\x0", 8 );
+ }
+
+ video::E_MATERIAL_TYPE defaultLightMapMaterial;
+ video::E_MODULATE_FUNC defaultModulate;
+ video::E_MATERIAL_FLAG defaultFilter;
+ s32 patchTesselation;
+ s32 verbose;
+ u32 startTime;
+ u32 endTime;
+ s32 mergeShaderBuffer;
+ s32 cleanUnResolvedMeshes;
+ s32 loadAllShaders;
+ s32 loadSkyShader;
+ s32 alpharef;
+ s32 swapLump;
+ s32 swapHeader;
+ c8 scriptDir [ 64 ];
+ };
+
+ // some useful typedefs
+ typedef core::array< core::stringc > tStringList;
+ typedef core::array< video::ITexture* > tTexArray;
+
+ // string helper.. TODO: move to generic files
+ inline s16 isEqual ( const core::stringc &string, u32 &pos, const c8 *list[], u16 listSize )
+ {
+ const char * in = string.c_str () + pos;
+
+ for ( u16 i = 0; i != listSize; ++i )
+ {
+ if (string.size() < pos)
+ return -2;
+ u32 len = (u32) strlen ( list[i] );
+ if (string.size() < pos+len)
+ continue;
+ if ( in [len] != 0 && in [len] != ' ' )
+ continue;
+ if ( strncmp ( in, list[i], len ) )
+ continue;
+
+ pos += len + 1;
+ return (s16) i;
+ }
+ return -2;
+ }
+
+ inline f32 getAsFloat ( const core::stringc &string, u32 &pos )
+ {
+ const char * in = string.c_str () + pos;
+
+ f32 value = 0.f;
+ pos += (u32) ( core::fast_atof_move ( in, value ) - in ) + 1;
+ return value;
+ }
+
+ //! get a quake3 vector translated to irrlicht position (x,-z,y )
+ inline core::vector3df getAsVector3df ( const core::stringc &string, u32 &pos )
+ {
+ core::vector3df v;
+
+ v.X = getAsFloat ( string, pos );
+ v.Z = getAsFloat ( string, pos );
+ v.Y = getAsFloat ( string, pos );
+
+ return v;
+ }
+
+
+ /*
+ extract substrings
+ */
+ inline void getAsStringList ( tStringList &list, s32 max, const core::stringc &string, u32 &startPos )
+ {
+ list.clear ();
+
+ s32 finish = 0;
+ s32 endPos;
+ do
+ {
+ endPos = string.findNext ( ' ', startPos );
+ if ( endPos == -1 )
+ {
+ finish = 1;
+ endPos = string.size();
+ }
+
+ list.push_back ( string.subString ( startPos, endPos - startPos ) );
+ startPos = endPos + 1;
+
+ if ( list.size() >= (u32) max )
+ finish = 1;
+
+ } while ( !finish );
+
+ }
+
+ //! A blend function for a q3 shader.
+ struct SBlendFunc
+ {
+ SBlendFunc ( video::E_MODULATE_FUNC mod )
+ : type ( video::EMT_SOLID ), modulate ( mod ),
+ param0( 0.f ),
+ isTransparent ( 0 ) {}
+
+ video::E_MATERIAL_TYPE type;
+ video::E_MODULATE_FUNC modulate;
+
+ f32 param0;
+ u32 isTransparent;
+ };
+
+ // parses the content of Variable cull
+ inline bool getCullingFunction ( const core::stringc &cull )
+ {
+ if ( cull.size() == 0 )
+ return true;
+
+ bool ret = true;
+ static const c8 * funclist[] = { "none", "disable", "twosided" };
+
+ u32 pos = 0;
+ switch ( isEqual ( cull, pos, funclist, 3 ) )
+ {
+ case 0:
+ case 1:
+ case 2:
+ ret = false;
+ break;
+ }
+ return ret;
+ }
+
+ // parses the content of Variable depthfunc
+ // return a z-test
+ inline u8 getDepthFunction ( const core::stringc &string )
+ {
+ u8 ret = video::ECFN_LESSEQUAL;
+
+ if ( string.size() == 0 )
+ return ret;
+
+ static const c8 * funclist[] = { "lequal","equal" };
+
+ u32 pos = 0;
+ switch ( isEqual ( string, pos, funclist, 2 ) )
+ {
+ case 0:
+ ret = video::ECFN_LESSEQUAL;
+ break;
+ case 1:
+ ret = video::ECFN_EQUAL;
+ break;
+ }
+ return ret;
+ }
+
+
+ /*!
+ parses the content of Variable blendfunc,alphafunc
+ it also make a hint for rendering as transparent or solid node.
+
+ we assume a typical quake scene would look like this..
+ 1) Big Static Mesh ( solid )
+ 2) static scene item ( may use transparency ) but rendered in the solid pass
+ 3) additional transparency item in the transparent pass
+
+ it's not 100% accurate! it just empirical..
+ */
+ inline static void getBlendFunc ( const core::stringc &string, SBlendFunc &blendfunc )
+ {
+ if ( string.size() == 0 )
+ return;
+
+ // maps to E_BLEND_FACTOR
+ static const c8 * funclist[] =
+ {
+ "gl_zero",
+ "gl_one",
+ "gl_dst_color",
+ "gl_one_minus_dst_color",
+ "gl_src_color",
+ "gl_one_minus_src_color",
+ "gl_src_alpha",
+ "gl_one_minus_src_alpha",
+ "gl_dst_alpha",
+ "gl_one_minus_dst_alpha",
+ "gl_src_alpha_sat",
+
+ "add",
+ "filter",
+ "blend",
+
+ "ge128",
+ "gt0",
+ };
+
+
+ u32 pos = 0;
+ s32 srcFact = isEqual ( string, pos, funclist, 16 );
+
+ if ( srcFact < 0 )
+ return;
+
+ u32 resolved = 0;
+ s32 dstFact = isEqual ( string, pos, funclist, 16 );
+
+ switch ( srcFact )
+ {
+ case video::EBF_ZERO:
+ switch ( dstFact )
+ {
+ // gl_zero gl_src_color == gl_dst_color gl_zero
+ case video::EBF_SRC_COLOR:
+ blendfunc.type = video::EMT_ONETEXTURE_BLEND;
+ blendfunc.param0 = video::pack_textureBlendFunc ( video::EBF_DST_COLOR, video::EBF_ZERO, blendfunc.modulate );
+ blendfunc.isTransparent = 1;
+ resolved = 1;
+ break;
+ } break;
+
+ case video::EBF_ONE:
+ switch ( dstFact )
+ {
+ // gl_one gl_zero
+ case video::EBF_ZERO:
+ blendfunc.type = video::EMT_SOLID;
+ blendfunc.isTransparent = 0;
+ resolved = 1;
+ break;
+
+ // gl_one gl_one
+ case video::EBF_ONE:
+ blendfunc.type = video::EMT_TRANSPARENT_ADD_COLOR;
+ blendfunc.isTransparent = 1;
+ resolved = 1;
+ break;
+ } break;
+
+ case video::EBF_SRC_ALPHA:
+ switch ( dstFact )
+ {
+ // gl_src_alpha gl_one_minus_src_alpha
+ case video::EBF_ONE_MINUS_SRC_ALPHA:
+ blendfunc.type = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
+ blendfunc.param0 = 1.f/255.f;
+ blendfunc.isTransparent = 1;
+ resolved = 1;
+ break;
+ } break;
+
+ case 11:
+ // add
+ blendfunc.type = video::EMT_TRANSPARENT_ADD_COLOR;
+ blendfunc.isTransparent = 1;
+ resolved = 1;
+ break;
+ case 12:
+ // filter = gl_dst_color gl_zero or gl_zero gl_src_color
+ blendfunc.type = video::EMT_ONETEXTURE_BLEND;
+ blendfunc.param0 = video::pack_textureBlendFunc ( video::EBF_DST_COLOR, video::EBF_ZERO, blendfunc.modulate );
+ blendfunc.isTransparent = 1;
+ resolved = 1;
+ break;
+ case 13:
+ // blend = gl_src_alpha gl_one_minus_src_alpha
+ blendfunc.type = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
+ blendfunc.param0 = 1.f/255.f;
+ blendfunc.isTransparent = 1;
+ resolved = 1;
+ break;
+ case 14:
+ // alphafunc ge128
+ blendfunc.type = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
+ blendfunc.param0 = 0.5f;
+ blendfunc.isTransparent = 1;
+ resolved = 1;
+ break;
+ case 15:
+ // alphafunc gt0
+ blendfunc.type = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
+ blendfunc.param0 = 1.f / 255.f;
+ blendfunc.isTransparent = 1;
+ resolved = 1;
+ break;
+
+ }
+
+ // use the generic blender
+ if ( 0 == resolved )
+ {
+ blendfunc.type = video::EMT_ONETEXTURE_BLEND;
+ blendfunc.param0 = video::pack_textureBlendFunc (
+ (video::E_BLEND_FACTOR) srcFact,
+ (video::E_BLEND_FACTOR) dstFact,
+ blendfunc.modulate);
+
+ blendfunc.isTransparent = 1;
+ }
+ }
+
+ // random noise [-1;1]
+ struct Noiser
+ {
+ static f32 get ()
+ {
+ static u32 RandomSeed = 0x69666966;
+ RandomSeed = (RandomSeed * 3631 + 1);
+
+ f32 value = ( (f32) (RandomSeed & 0x7FFF ) * (1.0f / (f32)(0x7FFF >> 1) ) ) - 1.f;
+ return value;
+ }
+ };
+
+ enum eQ3ModifierFunction
+ {
+ TCMOD = 0,
+ DEFORMVERTEXES = 1,
+ RGBGEN = 2,
+ TCGEN = 3,
+ MAP = 4,
+ ALPHAGEN = 5,
+
+ FUNCTION2 = 0x10,
+ SCROLL = FUNCTION2 + 1,
+ SCALE = FUNCTION2 + 2,
+ ROTATE = FUNCTION2 + 3,
+ STRETCH = FUNCTION2 + 4,
+ TURBULENCE = FUNCTION2 + 5,
+ WAVE = FUNCTION2 + 6,
+
+ IDENTITY = FUNCTION2 + 7,
+ VERTEX = FUNCTION2 + 8,
+ TEXTURE = FUNCTION2 + 9,
+ LIGHTMAP = FUNCTION2 + 10,
+ ENVIRONMENT = FUNCTION2 + 11,
+ DOLLAR_LIGHTMAP = FUNCTION2 + 12,
+ BULGE = FUNCTION2 + 13,
+ AUTOSPRITE = FUNCTION2 + 14,
+ AUTOSPRITE2 = FUNCTION2 + 15,
+ TRANSFORM = FUNCTION2 + 16,
+ EXACTVERTEX = FUNCTION2 + 17,
+ CONSTANT = FUNCTION2 + 18,
+ LIGHTINGSPECULAR = FUNCTION2 + 19,
+ MOVE = FUNCTION2 + 20,
+ NORMAL = FUNCTION2 + 21,
+ IDENTITYLIGHTING = FUNCTION2 + 22,
+
+ WAVE_MODIFIER_FUNCTION = 0x30,
+ SINUS = WAVE_MODIFIER_FUNCTION + 1,
+ COSINUS = WAVE_MODIFIER_FUNCTION + 2,
+ SQUARE = WAVE_MODIFIER_FUNCTION + 3,
+ TRIANGLE = WAVE_MODIFIER_FUNCTION + 4,
+ SAWTOOTH = WAVE_MODIFIER_FUNCTION + 5,
+ SAWTOOTH_INVERSE = WAVE_MODIFIER_FUNCTION + 6,
+ NOISE = WAVE_MODIFIER_FUNCTION + 7,
+
+
+ UNKNOWN = -2
+
+ };
+
+ struct SModifierFunction
+ {
+ SModifierFunction ()
+ : masterfunc0 ( UNKNOWN ), masterfunc1( UNKNOWN ), func ( SINUS ),
+ tcgen( TEXTURE ), rgbgen ( IDENTITY ), alphagen ( UNKNOWN ),
+ base ( 0 ), amp ( 1 ), phase ( 0 ), frequency ( 1 ),
+ wave ( 1 ),
+ x ( 0 ), y ( 0 ), z( 0 ), count( 0 ) {}
+
+ // "tcmod","deformvertexes","rgbgen", "tcgen"
+ eQ3ModifierFunction masterfunc0;
+ // depends
+ eQ3ModifierFunction masterfunc1;
+ // depends
+ eQ3ModifierFunction func;
+
+ eQ3ModifierFunction tcgen;
+ eQ3ModifierFunction rgbgen;
+ eQ3ModifierFunction alphagen;
+
+ union
+ {
+ f32 base;
+ f32 bulgewidth;
+ };
+
+ union
+ {
+ f32 amp;
+ f32 bulgeheight;
+ };
+
+ f32 phase;
+
+ union
+ {
+ f32 frequency;
+ f32 bulgespeed;
+ };
+
+ union
+ {
+ f32 wave;
+ f32 div;
+ };
+
+ f32 x;
+ f32 y;
+ f32 z;
+ u32 count;
+
+ f32 evaluate ( f32 dt ) const
+ {
+ // phase in 0 and 1..
+ f32 x = core::fract( (dt + phase ) * frequency );
+ f32 y = 0.f;
+
+ switch ( func )
+ {
+ case SINUS:
+ y = sinf ( x * core::PI * 2.f );
+ break;
+ case COSINUS:
+ y = cosf ( x * core::PI * 2.f );
+ break;
+ case SQUARE:
+ y = x < 0.5f ? 1.f : -1.f;
+ break;
+ case TRIANGLE:
+ y = x < 0.5f ? ( 4.f * x ) - 1.f : ( -4.f * x ) + 3.f;
+ break;
+ case SAWTOOTH:
+ y = x;
+ break;
+ case SAWTOOTH_INVERSE:
+ y = 1.f - x;
+ break;
+ case NOISE:
+ y = Noiser::get();
+ break;
+ default:
+ break;
+ }
+
+ return base + ( y * amp );
+ }
+
+
+ };
+
+ inline core::vector3df getMD3Normal ( u32 i, u32 j )
+ {
+ const f32 lng = i * 2.0f * core::PI / 255.0f;
+ const f32 lat = j * 2.0f * core::PI / 255.0f;
+ return core::vector3df(cosf ( lat ) * sinf ( lng ),
+ sinf ( lat ) * sinf ( lng ),
+ cosf ( lng ));
+ }
+
+ //
+ inline void getModifierFunc ( SModifierFunction& fill, const core::stringc &string, u32 &pos )
+ {
+ if ( string.size() == 0 )
+ return;
+
+ static const c8 * funclist[] =
+ {
+ "sin","cos","square",
+ "triangle", "sawtooth","inversesawtooth", "noise"
+ };
+
+ fill.func = (eQ3ModifierFunction) isEqual ( string,pos, funclist,7 );
+ fill.func = fill.func == UNKNOWN ? SINUS : (eQ3ModifierFunction) ((u32) fill.func + WAVE_MODIFIER_FUNCTION + 1);
+
+ fill.base = getAsFloat ( string, pos );
+ fill.amp = getAsFloat ( string, pos );
+ fill.phase = getAsFloat ( string, pos );
+ fill.frequency = getAsFloat ( string, pos );
+ }
+
+
+ // name = "a b c .."
+ struct SVariable
+ {
+ core::stringc name;
+ core::stringc content;
+
+ SVariable ( const c8 * n, const c8 *c = 0 ) : name ( n ), content (c) {}
+ virtual ~SVariable () {}
+
+ void clear ()
+ {
+ name = "";
+ content = "";
+ }
+
+ s32 isValid () const
+ {
+ return name.size();
+ }
+
+ bool operator == ( const SVariable &other ) const
+ {
+ return 0 == strcmp ( name.c_str(), other.name.c_str () );
+ }
+
+ bool operator < ( const SVariable &other ) const
+ {
+ return 0 > strcmp ( name.c_str(), other.name.c_str () );
+ }
+
+ };
+
+
+ // string database. "a" = "Hello", "b" = "1234.6"
+ struct SVarGroup
+ {
+ SVarGroup () { Variable.setAllocStrategy ( core::ALLOC_STRATEGY_SAFE ); }
+ virtual ~SVarGroup () {}
+
+ u32 isDefined ( const c8 * name, const c8 * content = 0 ) const
+ {
+ for ( u32 i = 0; i != Variable.size (); ++i )
+ {
+ if ( 0 == strcmp ( Variable[i].name.c_str(), name ) &&
+ ( 0 == content || strstr ( Variable[i].content.c_str(), content ) )
+ )
+ {
+ return i + 1;
+ }
+ }
+ return 0;
+ }
+
+ // searches for Variable name and returns is content
+ // if Variable is not found a reference to an Empty String is returned
+ const core::stringc &get( const c8 * name ) const
+ {
+ SVariable search ( name );
+ s32 index = Variable.linear_search ( search );
+ if ( index < 0 )
+ return irrEmptyStringc;
+
+ return Variable [ index ].content;
+ }
+
+ // set the Variable name
+ void set ( const c8 * name, const c8 * content = 0 )
+ {
+ u32 index = isDefined ( name, 0 );
+ if ( 0 == index )
+ {
+ Variable.push_back ( SVariable ( name, content ) );
+ }
+ else
+ {
+ Variable [ index ].content = content;
+ }
+ }
+
+
+ core::array < SVariable > Variable;
+ };
+
+ //! holding a group a variable
+ struct SVarGroupList: public IReferenceCounted
+ {
+ SVarGroupList ()
+ {
+ VariableGroup.setAllocStrategy ( core::ALLOC_STRATEGY_SAFE );
+ }
+ virtual ~SVarGroupList () {}
+
+ core::array < SVarGroup > VariableGroup;
+ };
+
+
+ //! A Parsed Shader Holding Variables ordered in Groups
+ struct IShader
+ {
+ IShader ()
+ : ID ( 0 ), VarGroup ( 0 ) {}
+ virtual ~IShader () {}
+
+ void operator = (const IShader &other )
+ {
+ ID = other.ID;
+ VarGroup = other.VarGroup;
+ name = other.name;
+ }
+
+ bool operator == (const IShader &other ) const
+ {
+ return 0 == strcmp ( name.c_str(), other.name.c_str () );
+ //return name == other.name;
+ }
+
+ bool operator < (const IShader &other ) const
+ {
+ return strcmp ( name.c_str(), other.name.c_str () ) < 0;
+ //return name < other.name;
+ }
+
+ u32 getGroupSize () const
+ {
+ if ( 0 == VarGroup )
+ return 0;
+ return VarGroup->VariableGroup.size ();
+ }
+
+ const SVarGroup * getGroup ( u32 stage ) const
+ {
+ if ( 0 == VarGroup || stage >= VarGroup->VariableGroup.size () )
+ return 0;
+
+ return &VarGroup->VariableGroup [ stage ];
+ }
+
+ // id
+ s32 ID;
+ SVarGroupList *VarGroup; // reference
+
+ // Shader: shader name ( also first variable in first Vargroup )
+ // Entity: classname ( variable in Group(1) )
+ core::stringc name;
+ };
+
+ typedef IShader IEntity;
+
+ typedef core::array < IEntity > tQ3EntityList;
+
+ /*
+ dump shader like original layout, regardless of internal data holding
+ no recursive folding..
+ */
+ inline void dumpVarGroup ( core::stringc &dest, const SVarGroup * group, s32 stack )
+ {
+ core::stringc buf;
+ s32 i;
+
+
+ if ( stack > 0 )
+ {
+ buf = "";
+ for ( i = 0; i < stack - 1; ++i )
+ buf += '\t';
+
+ buf += "{\n";
+ dest.append ( buf );
+ }
+
+ for ( u32 g = 0; g != group->Variable.size(); ++g )
+ {
+ buf = "";
+ for ( i = 0; i < stack; ++i )
+ buf += '\t';
+
+ buf += group->Variable[g].name;
+ buf += " ";
+ buf += group->Variable[g].content;
+ buf += "\n";
+ dest.append ( buf );
+ }
+
+ if ( stack > 1 )
+ {
+ buf = "";
+ for ( i = 0; i < stack - 1; ++i )
+ buf += '\t';
+
+ buf += "}\n";
+ dest.append ( buf );
+ }
+
+ }
+
+ /*!
+ dump a Shader or an Entity
+ */
+ inline core::stringc & dumpShader ( core::stringc &dest, const IShader * shader, bool entity = false )
+ {
+ if ( 0 == shader )
+ return dest;
+
+ const SVarGroup * group;
+
+ const u32 size = shader->VarGroup->VariableGroup.size ();
+ for ( u32 i = 0; i != size; ++i )
+ {
+ group = &shader->VarGroup->VariableGroup[ i ];
+ dumpVarGroup ( dest, group, core::clamp( (int)i, 0, 2 ) );
+ }
+
+ if ( !entity )
+ {
+ if ( size <= 1 )
+ {
+ dest.append ( "{\n" );
+ }
+ dest.append ( "}\n" );
+ }
+ return dest;
+ }
+
+
+ /*
+ quake3 doesn't care much about tga & jpg
+ load one or multiple files stored in name started at startPos to the texture array textures
+ if texture is not loaded 0 will be added ( to find missing textures easier)
+ */
+ inline void getTextures(tTexArray &textures,
+ const core::stringc &name, u32 &startPos,
+ io::IFileSystem *fileSystem,
+ video::IVideoDriver* driver)
+ {
+ static const char* extension[] =
+ {
+ ".jpg",
+ ".jpeg",
+ ".png",
+ ".dds",
+ ".tga",
+ ".bmp",
+ ".pcx"
+ };
+
+ tStringList stringList;
+ getAsStringList(stringList, -1, name, startPos);
+
+ textures.clear();
+
+ io::path loadFile;
+ for ( u32 i = 0; i!= stringList.size (); ++i )
+ {
+ video::ITexture* texture = 0;
+ for (u32 g = 0; g != 7 ; ++g)
+ {
+ core::cutFilenameExtension ( loadFile, stringList[i] );
+
+ if ( loadFile == "$whiteimage" )
+ {
+ texture = driver->getTexture( "$whiteimage" );
+ if ( 0 == texture )
+ {
+ core::dimension2du s ( 2, 2 );
+ u32 image[4] = { 0xFFFFFFFF, 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF };
+ video::IImage* w = driver->createImageFromData ( video::ECF_A8R8G8B8, s,&image );
+ texture = driver->addTexture( "$whiteimage", w );
+ w->drop ();
+ }
+
+ }
+ else
+ if ( loadFile == "$redimage" )
+ {
+ texture = driver->getTexture( "$redimage" );
+ if ( 0 == texture )
+ {
+ core::dimension2du s ( 2, 2 );
+ u32 image[4] = { 0xFFFF0000, 0xFFFF0000,0xFFFF0000,0xFFFF0000 };
+ video::IImage* w = driver->createImageFromData ( video::ECF_A8R8G8B8, s,&image );
+ texture = driver->addTexture( "$redimage", w );
+ w->drop ();
+ }
+ }
+ else
+ if ( loadFile == "$blueimage" )
+ {
+ texture = driver->getTexture( "$blueimage" );
+ if ( 0 == texture )
+ {
+ core::dimension2du s ( 2, 2 );
+ u32 image[4] = { 0xFF0000FF, 0xFF0000FF,0xFF0000FF,0xFF0000FF };
+ video::IImage* w = driver->createImageFromData ( video::ECF_A8R8G8B8, s,&image );
+ texture = driver->addTexture( "$blueimage", w );
+ w->drop ();
+ }
+ }
+ else
+ if ( loadFile == "$checkerimage" )
+ {
+ texture = driver->getTexture( "$checkerimage" );
+ if ( 0 == texture )
+ {
+ core::dimension2du s ( 2, 2 );
+ u32 image[4] = { 0xFFFFFFFF, 0xFF000000,0xFF000000,0xFFFFFFFF };
+ video::IImage* w = driver->createImageFromData ( video::ECF_A8R8G8B8, s,&image );
+ texture = driver->addTexture( "$checkerimage", w );
+ w->drop ();
+ }
+ }
+ else
+ if ( loadFile == "$lightmap" )
+ {
+ texture = 0;
+ }
+ else
+ {
+ loadFile.append ( extension[g] );
+ }
+
+ if ( fileSystem->existFile ( loadFile ) )
+ {
+ texture = driver->getTexture( loadFile );
+ if ( texture )
+ break;
+ texture = 0;
+ }
+ }
+ // take 0 Texture
+ textures.push_back(texture);
+ }
+ }
+
+
+ //! Manages various Quake3 Shader Styles
+ class IShaderManager : public IReferenceCounted
+ {
+ };
+
+} // end namespace quake3
+} // end namespace scene
+} // end namespace irr
+
+#endif
+