1 // Copyright (C) 2006-2012 Nikolaus Gebhardt / Thomas Alten 2 // This file is part of the "Irrlicht Engine". 3 // For conditions of distribution and use, see copyright notice in irrlicht.h 4 5 #ifndef __I_Q3_LEVEL_SHADER_H_INCLUDED__ 6 #define __I_Q3_LEVEL_SHADER_H_INCLUDED__ 7 8 #include "irrArray.h" 9 #include "fast_atof.h" 10 #include "IFileSystem.h" 11 #include "IVideoDriver.h" 12 #include "coreutil.h" 13 14 namespace irr 15 { 16 namespace scene 17 { 18 namespace quake3 19 { 20 21 static core::stringc irrEmptyStringc(""); 22 23 //! Hold the different Mesh Types used for getMesh 24 enum eQ3MeshIndex 25 { 26 E_Q3_MESH_GEOMETRY = 0, 27 E_Q3_MESH_ITEMS, 28 E_Q3_MESH_BILLBOARD, 29 E_Q3_MESH_FOG, 30 E_Q3_MESH_UNRESOLVED, 31 E_Q3_MESH_SIZE 32 }; 33 34 /*! used to customize Quake3 BSP Loader 35 */ 36 37 struct Q3LevelLoadParameter 38 { Q3LevelLoadParameterQ3LevelLoadParameter39 Q3LevelLoadParameter () 40 :defaultLightMapMaterial ( video::EMT_LIGHTMAP_M4 ), 41 defaultModulate ( video::EMFN_MODULATE_4X ), 42 defaultFilter ( video::EMF_BILINEAR_FILTER ), 43 patchTesselation ( 8 ), 44 verbose ( 0 ), 45 startTime ( 0 ), endTime ( 0 ), 46 mergeShaderBuffer ( 1 ), 47 cleanUnResolvedMeshes ( 1 ), 48 loadAllShaders ( 0 ), 49 loadSkyShader ( 0 ), 50 alpharef ( 1 ), 51 swapLump ( 0 ), 52 #ifdef __BIG_ENDIAN__ 53 swapHeader ( 1 ) 54 #else 55 swapHeader ( 0 ) 56 #endif 57 { 58 memcpy ( scriptDir, "scripts\x0", 8 ); 59 } 60 61 video::E_MATERIAL_TYPE defaultLightMapMaterial; 62 video::E_MODULATE_FUNC defaultModulate; 63 video::E_MATERIAL_FLAG defaultFilter; 64 s32 patchTesselation; 65 s32 verbose; 66 u32 startTime; 67 u32 endTime; 68 s32 mergeShaderBuffer; 69 s32 cleanUnResolvedMeshes; 70 s32 loadAllShaders; 71 s32 loadSkyShader; 72 s32 alpharef; 73 s32 swapLump; 74 s32 swapHeader; 75 c8 scriptDir [ 64 ]; 76 }; 77 78 // some useful typedefs 79 typedef core::array< core::stringc > tStringList; 80 typedef core::array< video::ITexture* > tTexArray; 81 82 // string helper.. TODO: move to generic files isEqual(const core::stringc & string,u32 & pos,const c8 * list[],u16 listSize)83 inline s16 isEqual ( const core::stringc &string, u32 &pos, const c8 *list[], u16 listSize ) 84 { 85 const char * in = string.c_str () + pos; 86 87 for ( u16 i = 0; i != listSize; ++i ) 88 { 89 if (string.size() < pos) 90 return -2; 91 u32 len = (u32) strlen ( list[i] ); 92 if (string.size() < pos+len) 93 continue; 94 if ( in [len] != 0 && in [len] != ' ' ) 95 continue; 96 if ( strncmp ( in, list[i], len ) ) 97 continue; 98 99 pos += len + 1; 100 return (s16) i; 101 } 102 return -2; 103 } 104 getAsFloat(const core::stringc & string,u32 & pos)105 inline f32 getAsFloat ( const core::stringc &string, u32 &pos ) 106 { 107 const char * in = string.c_str () + pos; 108 109 f32 value = 0.f; 110 pos += (u32) ( core::fast_atof_move ( in, value ) - in ) + 1; 111 return value; 112 } 113 114 //! get a quake3 vector translated to irrlicht position (x,-z,y ) getAsVector3df(const core::stringc & string,u32 & pos)115 inline core::vector3df getAsVector3df ( const core::stringc &string, u32 &pos ) 116 { 117 core::vector3df v; 118 119 v.X = getAsFloat ( string, pos ); 120 v.Z = getAsFloat ( string, pos ); 121 v.Y = getAsFloat ( string, pos ); 122 123 return v; 124 } 125 126 127 /* 128 extract substrings 129 */ getAsStringList(tStringList & list,s32 max,const core::stringc & string,u32 & startPos)130 inline void getAsStringList ( tStringList &list, s32 max, const core::stringc &string, u32 &startPos ) 131 { 132 list.clear (); 133 134 s32 finish = 0; 135 s32 endPos; 136 do 137 { 138 endPos = string.findNext ( ' ', startPos ); 139 if ( endPos == -1 ) 140 { 141 finish = 1; 142 endPos = string.size(); 143 } 144 145 list.push_back ( string.subString ( startPos, endPos - startPos ) ); 146 startPos = endPos + 1; 147 148 if ( list.size() >= (u32) max ) 149 finish = 1; 150 151 } while ( !finish ); 152 153 } 154 155 //! A blend function for a q3 shader. 156 struct SBlendFunc 157 { SBlendFuncSBlendFunc158 SBlendFunc ( video::E_MODULATE_FUNC mod ) 159 : type ( video::EMT_SOLID ), modulate ( mod ), 160 param0( 0.f ), 161 isTransparent ( 0 ) {} 162 163 video::E_MATERIAL_TYPE type; 164 video::E_MODULATE_FUNC modulate; 165 166 f32 param0; 167 u32 isTransparent; 168 }; 169 170 // parses the content of Variable cull getCullingFunction(const core::stringc & cull)171 inline bool getCullingFunction ( const core::stringc &cull ) 172 { 173 if ( cull.size() == 0 ) 174 return true; 175 176 bool ret = true; 177 static const c8 * funclist[] = { "none", "disable", "twosided" }; 178 179 u32 pos = 0; 180 switch ( isEqual ( cull, pos, funclist, 3 ) ) 181 { 182 case 0: 183 case 1: 184 case 2: 185 ret = false; 186 break; 187 } 188 return ret; 189 } 190 191 // parses the content of Variable depthfunc 192 // return a z-test getDepthFunction(const core::stringc & string)193 inline u8 getDepthFunction ( const core::stringc &string ) 194 { 195 u8 ret = video::ECFN_LESSEQUAL; 196 197 if ( string.size() == 0 ) 198 return ret; 199 200 static const c8 * funclist[] = { "lequal","equal" }; 201 202 u32 pos = 0; 203 switch ( isEqual ( string, pos, funclist, 2 ) ) 204 { 205 case 0: 206 ret = video::ECFN_LESSEQUAL; 207 break; 208 case 1: 209 ret = video::ECFN_EQUAL; 210 break; 211 } 212 return ret; 213 } 214 215 216 /*! 217 parses the content of Variable blendfunc,alphafunc 218 it also make a hint for rendering as transparent or solid node. 219 220 we assume a typical quake scene would look like this.. 221 1) Big Static Mesh ( solid ) 222 2) static scene item ( may use transparency ) but rendered in the solid pass 223 3) additional transparency item in the transparent pass 224 225 it's not 100% accurate! it just empirical.. 226 */ getBlendFunc(const core::stringc & string,SBlendFunc & blendfunc)227 inline static void getBlendFunc ( const core::stringc &string, SBlendFunc &blendfunc ) 228 { 229 if ( string.size() == 0 ) 230 return; 231 232 // maps to E_BLEND_FACTOR 233 static const c8 * funclist[] = 234 { 235 "gl_zero", 236 "gl_one", 237 "gl_dst_color", 238 "gl_one_minus_dst_color", 239 "gl_src_color", 240 "gl_one_minus_src_color", 241 "gl_src_alpha", 242 "gl_one_minus_src_alpha", 243 "gl_dst_alpha", 244 "gl_one_minus_dst_alpha", 245 "gl_src_alpha_sat", 246 247 "add", 248 "filter", 249 "blend", 250 251 "ge128", 252 "gt0", 253 }; 254 255 256 u32 pos = 0; 257 s32 srcFact = isEqual ( string, pos, funclist, 16 ); 258 259 if ( srcFact < 0 ) 260 return; 261 262 u32 resolved = 0; 263 s32 dstFact = isEqual ( string, pos, funclist, 16 ); 264 265 switch ( srcFact ) 266 { 267 case video::EBF_ZERO: 268 switch ( dstFact ) 269 { 270 // gl_zero gl_src_color == gl_dst_color gl_zero 271 case video::EBF_SRC_COLOR: 272 blendfunc.type = video::EMT_ONETEXTURE_BLEND; 273 blendfunc.param0 = video::pack_textureBlendFunc ( video::EBF_DST_COLOR, video::EBF_ZERO, blendfunc.modulate ); 274 blendfunc.isTransparent = 1; 275 resolved = 1; 276 break; 277 } break; 278 279 case video::EBF_ONE: 280 switch ( dstFact ) 281 { 282 // gl_one gl_zero 283 case video::EBF_ZERO: 284 blendfunc.type = video::EMT_SOLID; 285 blendfunc.isTransparent = 0; 286 resolved = 1; 287 break; 288 289 // gl_one gl_one 290 case video::EBF_ONE: 291 blendfunc.type = video::EMT_TRANSPARENT_ADD_COLOR; 292 blendfunc.isTransparent = 1; 293 resolved = 1; 294 break; 295 } break; 296 297 case video::EBF_SRC_ALPHA: 298 switch ( dstFact ) 299 { 300 // gl_src_alpha gl_one_minus_src_alpha 301 case video::EBF_ONE_MINUS_SRC_ALPHA: 302 blendfunc.type = video::EMT_TRANSPARENT_ALPHA_CHANNEL; 303 blendfunc.param0 = 1.f/255.f; 304 blendfunc.isTransparent = 1; 305 resolved = 1; 306 break; 307 } break; 308 309 case 11: 310 // add 311 blendfunc.type = video::EMT_TRANSPARENT_ADD_COLOR; 312 blendfunc.isTransparent = 1; 313 resolved = 1; 314 break; 315 case 12: 316 // filter = gl_dst_color gl_zero or gl_zero gl_src_color 317 blendfunc.type = video::EMT_ONETEXTURE_BLEND; 318 blendfunc.param0 = video::pack_textureBlendFunc ( video::EBF_DST_COLOR, video::EBF_ZERO, blendfunc.modulate ); 319 blendfunc.isTransparent = 1; 320 resolved = 1; 321 break; 322 case 13: 323 // blend = gl_src_alpha gl_one_minus_src_alpha 324 blendfunc.type = video::EMT_TRANSPARENT_ALPHA_CHANNEL; 325 blendfunc.param0 = 1.f/255.f; 326 blendfunc.isTransparent = 1; 327 resolved = 1; 328 break; 329 case 14: 330 // alphafunc ge128 331 blendfunc.type = video::EMT_TRANSPARENT_ALPHA_CHANNEL; 332 blendfunc.param0 = 0.5f; 333 blendfunc.isTransparent = 1; 334 resolved = 1; 335 break; 336 case 15: 337 // alphafunc gt0 338 blendfunc.type = video::EMT_TRANSPARENT_ALPHA_CHANNEL; 339 blendfunc.param0 = 1.f / 255.f; 340 blendfunc.isTransparent = 1; 341 resolved = 1; 342 break; 343 344 } 345 346 // use the generic blender 347 if ( 0 == resolved ) 348 { 349 blendfunc.type = video::EMT_ONETEXTURE_BLEND; 350 blendfunc.param0 = video::pack_textureBlendFunc ( 351 (video::E_BLEND_FACTOR) srcFact, 352 (video::E_BLEND_FACTOR) dstFact, 353 blendfunc.modulate); 354 355 blendfunc.isTransparent = 1; 356 } 357 } 358 359 // random noise [-1;1] 360 struct Noiser 361 { getNoiser362 static f32 get () 363 { 364 static u32 RandomSeed = 0x69666966; 365 RandomSeed = (RandomSeed * 3631 + 1); 366 367 f32 value = ( (f32) (RandomSeed & 0x7FFF ) * (1.0f / (f32)(0x7FFF >> 1) ) ) - 1.f; 368 return value; 369 } 370 }; 371 372 enum eQ3ModifierFunction 373 { 374 TCMOD = 0, 375 DEFORMVERTEXES = 1, 376 RGBGEN = 2, 377 TCGEN = 3, 378 MAP = 4, 379 ALPHAGEN = 5, 380 381 FUNCTION2 = 0x10, 382 SCROLL = FUNCTION2 + 1, 383 SCALE = FUNCTION2 + 2, 384 ROTATE = FUNCTION2 + 3, 385 STRETCH = FUNCTION2 + 4, 386 TURBULENCE = FUNCTION2 + 5, 387 WAVE = FUNCTION2 + 6, 388 389 IDENTITY = FUNCTION2 + 7, 390 VERTEX = FUNCTION2 + 8, 391 TEXTURE = FUNCTION2 + 9, 392 LIGHTMAP = FUNCTION2 + 10, 393 ENVIRONMENT = FUNCTION2 + 11, 394 DOLLAR_LIGHTMAP = FUNCTION2 + 12, 395 BULGE = FUNCTION2 + 13, 396 AUTOSPRITE = FUNCTION2 + 14, 397 AUTOSPRITE2 = FUNCTION2 + 15, 398 TRANSFORM = FUNCTION2 + 16, 399 EXACTVERTEX = FUNCTION2 + 17, 400 CONSTANT = FUNCTION2 + 18, 401 LIGHTINGSPECULAR = FUNCTION2 + 19, 402 MOVE = FUNCTION2 + 20, 403 NORMAL = FUNCTION2 + 21, 404 IDENTITYLIGHTING = FUNCTION2 + 22, 405 406 WAVE_MODIFIER_FUNCTION = 0x30, 407 SINUS = WAVE_MODIFIER_FUNCTION + 1, 408 COSINUS = WAVE_MODIFIER_FUNCTION + 2, 409 SQUARE = WAVE_MODIFIER_FUNCTION + 3, 410 TRIANGLE = WAVE_MODIFIER_FUNCTION + 4, 411 SAWTOOTH = WAVE_MODIFIER_FUNCTION + 5, 412 SAWTOOTH_INVERSE = WAVE_MODIFIER_FUNCTION + 6, 413 NOISE = WAVE_MODIFIER_FUNCTION + 7, 414 415 416 UNKNOWN = -2 417 418 }; 419 420 struct SModifierFunction 421 { SModifierFunctionSModifierFunction422 SModifierFunction () 423 : masterfunc0 ( UNKNOWN ), masterfunc1( UNKNOWN ), func ( SINUS ), 424 tcgen( TEXTURE ), rgbgen ( IDENTITY ), alphagen ( UNKNOWN ), 425 base ( 0 ), amp ( 1 ), phase ( 0 ), frequency ( 1 ), 426 wave ( 1 ), 427 x ( 0 ), y ( 0 ), z( 0 ), count( 0 ) {} 428 429 // "tcmod","deformvertexes","rgbgen", "tcgen" 430 eQ3ModifierFunction masterfunc0; 431 // depends 432 eQ3ModifierFunction masterfunc1; 433 // depends 434 eQ3ModifierFunction func; 435 436 eQ3ModifierFunction tcgen; 437 eQ3ModifierFunction rgbgen; 438 eQ3ModifierFunction alphagen; 439 440 union 441 { 442 f32 base; 443 f32 bulgewidth; 444 }; 445 446 union 447 { 448 f32 amp; 449 f32 bulgeheight; 450 }; 451 452 f32 phase; 453 454 union 455 { 456 f32 frequency; 457 f32 bulgespeed; 458 }; 459 460 union 461 { 462 f32 wave; 463 f32 div; 464 }; 465 466 f32 x; 467 f32 y; 468 f32 z; 469 u32 count; 470 evaluateSModifierFunction471 f32 evaluate ( f32 dt ) const 472 { 473 // phase in 0 and 1.. 474 f32 x = core::fract( (dt + phase ) * frequency ); 475 f32 y = 0.f; 476 477 switch ( func ) 478 { 479 case SINUS: 480 y = sinf ( x * core::PI * 2.f ); 481 break; 482 case COSINUS: 483 y = cosf ( x * core::PI * 2.f ); 484 break; 485 case SQUARE: 486 y = x < 0.5f ? 1.f : -1.f; 487 break; 488 case TRIANGLE: 489 y = x < 0.5f ? ( 4.f * x ) - 1.f : ( -4.f * x ) + 3.f; 490 break; 491 case SAWTOOTH: 492 y = x; 493 break; 494 case SAWTOOTH_INVERSE: 495 y = 1.f - x; 496 break; 497 case NOISE: 498 y = Noiser::get(); 499 break; 500 default: 501 break; 502 } 503 504 return base + ( y * amp ); 505 } 506 507 508 }; 509 getMD3Normal(u32 i,u32 j)510 inline core::vector3df getMD3Normal ( u32 i, u32 j ) 511 { 512 const f32 lng = i * 2.0f * core::PI / 255.0f; 513 const f32 lat = j * 2.0f * core::PI / 255.0f; 514 return core::vector3df(cosf ( lat ) * sinf ( lng ), 515 sinf ( lat ) * sinf ( lng ), 516 cosf ( lng )); 517 } 518 519 // getModifierFunc(SModifierFunction & fill,const core::stringc & string,u32 & pos)520 inline void getModifierFunc ( SModifierFunction& fill, const core::stringc &string, u32 &pos ) 521 { 522 if ( string.size() == 0 ) 523 return; 524 525 static const c8 * funclist[] = 526 { 527 "sin","cos","square", 528 "triangle", "sawtooth","inversesawtooth", "noise" 529 }; 530 531 fill.func = (eQ3ModifierFunction) isEqual ( string,pos, funclist,7 ); 532 fill.func = fill.func == UNKNOWN ? SINUS : (eQ3ModifierFunction) ((u32) fill.func + WAVE_MODIFIER_FUNCTION + 1); 533 534 fill.base = getAsFloat ( string, pos ); 535 fill.amp = getAsFloat ( string, pos ); 536 fill.phase = getAsFloat ( string, pos ); 537 fill.frequency = getAsFloat ( string, pos ); 538 } 539 540 541 // name = "a b c .." 542 struct SVariable 543 { 544 core::stringc name; 545 core::stringc content; 546 nameSVariable547 SVariable ( const c8 * n, const c8 *c = 0 ) : name ( n ), content (c) {} ~SVariableSVariable548 virtual ~SVariable () {} 549 clearSVariable550 void clear () 551 { 552 name = ""; 553 content = ""; 554 } 555 isValidSVariable556 s32 isValid () const 557 { 558 return name.size(); 559 } 560 561 bool operator == ( const SVariable &other ) const 562 { 563 return 0 == strcmp ( name.c_str(), other.name.c_str () ); 564 } 565 566 bool operator < ( const SVariable &other ) const 567 { 568 return 0 > strcmp ( name.c_str(), other.name.c_str () ); 569 } 570 571 }; 572 573 574 // string database. "a" = "Hello", "b" = "1234.6" 575 struct SVarGroup 576 { SVarGroupSVarGroup577 SVarGroup () { Variable.setAllocStrategy ( core::ALLOC_STRATEGY_SAFE ); } ~SVarGroupSVarGroup578 virtual ~SVarGroup () {} 579 580 u32 isDefined ( const c8 * name, const c8 * content = 0 ) const 581 { 582 for ( u32 i = 0; i != Variable.size (); ++i ) 583 { 584 if ( 0 == strcmp ( Variable[i].name.c_str(), name ) && 585 ( 0 == content || strstr ( Variable[i].content.c_str(), content ) ) 586 ) 587 { 588 return i + 1; 589 } 590 } 591 return 0; 592 } 593 594 // searches for Variable name and returns is content 595 // if Variable is not found a reference to an Empty String is returned getSVarGroup596 const core::stringc &get( const c8 * name ) const 597 { 598 SVariable search ( name ); 599 s32 index = Variable.linear_search ( search ); 600 if ( index < 0 ) 601 return irrEmptyStringc; 602 603 return Variable [ index ].content; 604 } 605 606 // set the Variable name 607 void set ( const c8 * name, const c8 * content = 0 ) 608 { 609 u32 index = isDefined ( name, 0 ); 610 if ( 0 == index ) 611 { 612 Variable.push_back ( SVariable ( name, content ) ); 613 } 614 else 615 { 616 Variable [ index ].content = content; 617 } 618 } 619 620 621 core::array < SVariable > Variable; 622 }; 623 624 //! holding a group a variable 625 struct SVarGroupList: public IReferenceCounted 626 { SVarGroupListSVarGroupList627 SVarGroupList () 628 { 629 VariableGroup.setAllocStrategy ( core::ALLOC_STRATEGY_SAFE ); 630 } ~SVarGroupListSVarGroupList631 virtual ~SVarGroupList () {} 632 633 core::array < SVarGroup > VariableGroup; 634 }; 635 636 637 //! A Parsed Shader Holding Variables ordered in Groups 638 struct IShader 639 { IShaderIShader640 IShader () 641 : ID ( 0 ), VarGroup ( 0 ) {} ~IShaderIShader642 virtual ~IShader () {} 643 644 void operator = (const IShader &other ) 645 { 646 ID = other.ID; 647 VarGroup = other.VarGroup; 648 name = other.name; 649 } 650 651 bool operator == (const IShader &other ) const 652 { 653 return 0 == strcmp ( name.c_str(), other.name.c_str () ); 654 //return name == other.name; 655 } 656 657 bool operator < (const IShader &other ) const 658 { 659 return strcmp ( name.c_str(), other.name.c_str () ) < 0; 660 //return name < other.name; 661 } 662 getGroupSizeIShader663 u32 getGroupSize () const 664 { 665 if ( 0 == VarGroup ) 666 return 0; 667 return VarGroup->VariableGroup.size (); 668 } 669 getGroupIShader670 const SVarGroup * getGroup ( u32 stage ) const 671 { 672 if ( 0 == VarGroup || stage >= VarGroup->VariableGroup.size () ) 673 return 0; 674 675 return &VarGroup->VariableGroup [ stage ]; 676 } 677 678 // id 679 s32 ID; 680 SVarGroupList *VarGroup; // reference 681 682 // Shader: shader name ( also first variable in first Vargroup ) 683 // Entity: classname ( variable in Group(1) ) 684 core::stringc name; 685 }; 686 687 typedef IShader IEntity; 688 689 typedef core::array < IEntity > tQ3EntityList; 690 691 /* 692 dump shader like original layout, regardless of internal data holding 693 no recursive folding.. 694 */ dumpVarGroup(core::stringc & dest,const SVarGroup * group,s32 stack)695 inline void dumpVarGroup ( core::stringc &dest, const SVarGroup * group, s32 stack ) 696 { 697 core::stringc buf; 698 s32 i; 699 700 701 if ( stack > 0 ) 702 { 703 buf = ""; 704 for ( i = 0; i < stack - 1; ++i ) 705 buf += '\t'; 706 707 buf += "{\n"; 708 dest.append ( buf ); 709 } 710 711 for ( u32 g = 0; g != group->Variable.size(); ++g ) 712 { 713 buf = ""; 714 for ( i = 0; i < stack; ++i ) 715 buf += '\t'; 716 717 buf += group->Variable[g].name; 718 buf += " "; 719 buf += group->Variable[g].content; 720 buf += "\n"; 721 dest.append ( buf ); 722 } 723 724 if ( stack > 1 ) 725 { 726 buf = ""; 727 for ( i = 0; i < stack - 1; ++i ) 728 buf += '\t'; 729 730 buf += "}\n"; 731 dest.append ( buf ); 732 } 733 734 } 735 736 /*! 737 dump a Shader or an Entity 738 */ 739 inline core::stringc & dumpShader ( core::stringc &dest, const IShader * shader, bool entity = false ) 740 { 741 if ( 0 == shader ) 742 return dest; 743 744 const SVarGroup * group; 745 746 const u32 size = shader->VarGroup->VariableGroup.size (); 747 for ( u32 i = 0; i != size; ++i ) 748 { 749 group = &shader->VarGroup->VariableGroup[ i ]; 750 dumpVarGroup ( dest, group, core::clamp( (int)i, 0, 2 ) ); 751 } 752 753 if ( !entity ) 754 { 755 if ( size <= 1 ) 756 { 757 dest.append ( "{\n" ); 758 } 759 dest.append ( "}\n" ); 760 } 761 return dest; 762 } 763 764 765 /* 766 quake3 doesn't care much about tga & jpg 767 load one or multiple files stored in name started at startPos to the texture array textures 768 if texture is not loaded 0 will be added ( to find missing textures easier) 769 */ getTextures(tTexArray & textures,const core::stringc & name,u32 & startPos,io::IFileSystem * fileSystem,video::IVideoDriver * driver)770 inline void getTextures(tTexArray &textures, 771 const core::stringc &name, u32 &startPos, 772 io::IFileSystem *fileSystem, 773 video::IVideoDriver* driver) 774 { 775 static const char* extension[] = 776 { 777 ".jpg", 778 ".jpeg", 779 ".png", 780 ".dds", 781 ".tga", 782 ".bmp", 783 ".pcx" 784 }; 785 786 tStringList stringList; 787 getAsStringList(stringList, -1, name, startPos); 788 789 textures.clear(); 790 791 io::path loadFile; 792 for ( u32 i = 0; i!= stringList.size (); ++i ) 793 { 794 video::ITexture* texture = 0; 795 for (u32 g = 0; g != 7 ; ++g) 796 { 797 core::cutFilenameExtension ( loadFile, stringList[i] ); 798 799 if ( loadFile == "$whiteimage" ) 800 { 801 texture = driver->getTexture( "$whiteimage" ); 802 if ( 0 == texture ) 803 { 804 core::dimension2du s ( 2, 2 ); 805 u32 image[4] = { 0xFFFFFFFF, 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF }; 806 video::IImage* w = driver->createImageFromData ( video::ECF_A8R8G8B8, s,&image ); 807 texture = driver->addTexture( "$whiteimage", w ); 808 w->drop (); 809 } 810 811 } 812 else 813 if ( loadFile == "$redimage" ) 814 { 815 texture = driver->getTexture( "$redimage" ); 816 if ( 0 == texture ) 817 { 818 core::dimension2du s ( 2, 2 ); 819 u32 image[4] = { 0xFFFF0000, 0xFFFF0000,0xFFFF0000,0xFFFF0000 }; 820 video::IImage* w = driver->createImageFromData ( video::ECF_A8R8G8B8, s,&image ); 821 texture = driver->addTexture( "$redimage", w ); 822 w->drop (); 823 } 824 } 825 else 826 if ( loadFile == "$blueimage" ) 827 { 828 texture = driver->getTexture( "$blueimage" ); 829 if ( 0 == texture ) 830 { 831 core::dimension2du s ( 2, 2 ); 832 u32 image[4] = { 0xFF0000FF, 0xFF0000FF,0xFF0000FF,0xFF0000FF }; 833 video::IImage* w = driver->createImageFromData ( video::ECF_A8R8G8B8, s,&image ); 834 texture = driver->addTexture( "$blueimage", w ); 835 w->drop (); 836 } 837 } 838 else 839 if ( loadFile == "$checkerimage" ) 840 { 841 texture = driver->getTexture( "$checkerimage" ); 842 if ( 0 == texture ) 843 { 844 core::dimension2du s ( 2, 2 ); 845 u32 image[4] = { 0xFFFFFFFF, 0xFF000000,0xFF000000,0xFFFFFFFF }; 846 video::IImage* w = driver->createImageFromData ( video::ECF_A8R8G8B8, s,&image ); 847 texture = driver->addTexture( "$checkerimage", w ); 848 w->drop (); 849 } 850 } 851 else 852 if ( loadFile == "$lightmap" ) 853 { 854 texture = 0; 855 } 856 else 857 { 858 loadFile.append ( extension[g] ); 859 } 860 861 if ( fileSystem->existFile ( loadFile ) ) 862 { 863 texture = driver->getTexture( loadFile ); 864 if ( texture ) 865 break; 866 texture = 0; 867 } 868 } 869 // take 0 Texture 870 textures.push_back(texture); 871 } 872 } 873 874 875 //! Manages various Quake3 Shader Styles 876 class IShaderManager : public IReferenceCounted 877 { 878 }; 879 880 } // end namespace quake3 881 } // end namespace scene 882 } // end namespace irr 883 884 #endif 885 886