Line data Source code
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 103 : 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 : {
39 : 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
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 :
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 )
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 : */
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 : {
158 : 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
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
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 : */
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 : {
362 : 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 : {
422 : 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 :
471 : 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 :
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 : //
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 :
547 : SVariable ( const c8 * n, const c8 *c = 0 ) : name ( n ), content (c) {}
548 : virtual ~SVariable () {}
549 :
550 : void clear ()
551 : {
552 : name = "";
553 : content = "";
554 : }
555 :
556 : 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 : {
577 : SVarGroup () { Variable.setAllocStrategy ( core::ALLOC_STRATEGY_SAFE ); }
578 : 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
596 : 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 : {
627 : SVarGroupList ()
628 : {
629 : VariableGroup.setAllocStrategy ( core::ALLOC_STRATEGY_SAFE );
630 : }
631 : virtual ~SVarGroupList () {}
632 :
633 : core::array < SVarGroup > VariableGroup;
634 : };
635 :
636 :
637 : //! A Parsed Shader Holding Variables ordered in Groups
638 : struct IShader
639 : {
640 : IShader ()
641 : : ID ( 0 ), VarGroup ( 0 ) {}
642 : 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 :
663 : u32 getGroupSize () const
664 : {
665 : if ( 0 == VarGroup )
666 : return 0;
667 : return VarGroup->VariableGroup.size ();
668 : }
669 :
670 : 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 : */
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 : */
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 :
|