Home | Namespaces | Hierarchy | Alphabetical List | Class list | Files | Namespace Members | Class members | File members | Tutorials
IQ3Shader.h
Go to the documentation of this file.
1 // Copyright (C) 2006-2010 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 
25  {
32  };
33 
38  {
43  patchTesselation ( 8 ),
44  verbose ( 0 ),
45  startTime ( 0 ), endTime ( 0 ),
46  mergeShaderBuffer ( 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 
75  c8 scriptDir [ 64 ];
76  };
77 
78  // some useful typedefs
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 
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 
156  struct SBlendFunc
157  {
159  : type ( video::EMT_SOLID ), modulate ( mod ),
160  param0( 0.f ),
161  isTransparent ( 0 ) {}
162 
165 
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  {
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  case 1:
208  ret = video::ECFN_EQUAL;
209  break;
210  }
211  return ret;
212  }
213 
214 
226  inline static void getBlendFunc ( const core::stringc &string, SBlendFunc &blendfunc )
227  {
228  if ( string.size() == 0 )
229  return;
230 
231  // maps to E_BLEND_FACTOR
232  static const c8 * funclist[] =
233  {
234  "gl_zero",
235  "gl_one",
236  "gl_dst_color",
237  "gl_one_minus_dst_color",
238  "gl_src_color",
239  "gl_one_minus_src_color",
240  "gl_src_alpha",
241  "gl_one_minus_src_alpha",
242  "gl_dst_alpha",
243  "gl_one_minus_dst_alpha",
244  "gl_src_alpha_sat",
245 
246  "add",
247  "filter",
248  "blend",
249 
250  "ge128",
251  "gt0",
252  };
253 
254 
255  u32 pos = 0;
256  s32 srcFact = isEqual ( string, pos, funclist, 16 );
257 
258  if ( srcFact < 0 )
259  return;
260 
261  u32 resolved = 0;
262  s32 dstFact = isEqual ( string, pos, funclist, 16 );
263 
264  switch ( srcFact )
265  {
266  case video::EBF_ZERO:
267  switch ( dstFact )
268  {
269  // gl_zero gl_src_color == gl_dst_color gl_zero
271  blendfunc.type = video::EMT_ONETEXTURE_BLEND;
272  blendfunc.param0 = video::pack_texureBlendFunc ( video::EBF_DST_COLOR, video::EBF_ZERO, blendfunc.modulate );
273  blendfunc.isTransparent = 1;
274  resolved = 1;
275  break;
276  } break;
277 
278  case video::EBF_ONE:
279  switch ( dstFact )
280  {
281  // gl_one gl_zero
282  case video::EBF_ZERO:
283  blendfunc.type = video::EMT_SOLID;
284  blendfunc.isTransparent = 0;
285  resolved = 1;
286  break;
287 
288  // gl_one gl_one
289  case video::EBF_ONE:
290  blendfunc.type = video::EMT_TRANSPARENT_ADD_COLOR;
291  blendfunc.isTransparent = 1;
292  resolved = 1;
293  break;
294  } break;
295 
297  switch ( dstFact )
298  {
299  // gl_src_alpha gl_one_minus_src_alpha
301  blendfunc.type = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
302  blendfunc.param0 = 1.f/255.f;
303  blendfunc.isTransparent = 1;
304  resolved = 1;
305  break;
306  } break;
307 
308  case 11:
309  // add
310  blendfunc.type = video::EMT_TRANSPARENT_ADD_COLOR;
311  blendfunc.isTransparent = 1;
312  resolved = 1;
313  break;
314  case 12:
315  // filter = gl_dst_color gl_zero or gl_zero gl_src_color
316  blendfunc.type = video::EMT_ONETEXTURE_BLEND;
317  blendfunc.param0 = video::pack_texureBlendFunc ( video::EBF_DST_COLOR, video::EBF_ZERO, blendfunc.modulate );
318  blendfunc.isTransparent = 1;
319  resolved = 1;
320  break;
321  case 13:
322  // blend = gl_src_alpha gl_one_minus_src_alpha
323  blendfunc.type = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
324  blendfunc.param0 = 1.f/255.f;
325  blendfunc.isTransparent = 1;
326  resolved = 1;
327  break;
328  case 14:
329  // alphafunc ge128
330  blendfunc.type = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
331  blendfunc.param0 = 0.5f;
332  blendfunc.isTransparent = 1;
333  resolved = 1;
334  break;
335  case 15:
336  // alphafunc gt0
337  blendfunc.type = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
338  blendfunc.param0 = 1.f / 255.f;
339  blendfunc.isTransparent = 1;
340  resolved = 1;
341  break;
342 
343  }
344 
345  // use the generic blender
346  if ( 0 == resolved )
347  {
348  blendfunc.type = video::EMT_ONETEXTURE_BLEND;
349  blendfunc.param0 = video::pack_texureBlendFunc (
350  (video::E_BLEND_FACTOR) srcFact,
351  (video::E_BLEND_FACTOR) dstFact,
352  blendfunc.modulate);
353 
354  blendfunc.isTransparent = 1;
355  }
356  }
357 
358  // random noise [-1;1]
359  struct Noiser
360  {
361  static f32 get ()
362  {
363  static u32 RandomSeed = 0x69666966;
364  RandomSeed = (RandomSeed * 3631 + 1);
365 
366  f32 value = ( (f32) (RandomSeed & 0x7FFF ) * (1.0f / (f32)(0x7FFF >> 1) ) ) - 1.f;
367  return value;
368  }
369  };
370 
372  {
373  TCMOD = 0,
375  RGBGEN = 2,
376  TCGEN = 3,
377  MAP = 4,
378  ALPHAGEN = 5,
379 
380  FUNCTION2 = 0x10,
387 
394  BULGE = FUNCTION2 + 13,
401  MOVE = FUNCTION2 + 20,
404 
413 
414 
415  UNKNOWN = -2
416 
417  };
418 
420  {
424  base ( 0 ), amp ( 1 ), phase ( 0 ), frequency ( 1 ),
425  wave ( 1 ),
426  x ( 0 ), y ( 0 ), z( 0 ), count( 0 ) {}
427 
428  // "tcmod","deformvertexes","rgbgen", "tcgen"
430  // depends
432  // depends
434 
438 
439  union
440  {
443  };
444 
445  union
446  {
449  };
450 
452 
453  union
454  {
457  };
458 
459  union
460  {
463  };
464 
469 
470  f32 evaluate ( f32 dt ) const
471  {
472  // phase in 0 and 1..
473  f32 x = core::fract( (dt + phase ) * frequency );
474  f32 y = 0.f;
475 
476  switch ( func )
477  {
478  case SINUS:
479  y = sinf ( x * core::PI * 2.f );
480  break;
481  case COSINUS:
482  y = cosf ( x * core::PI * 2.f );
483  break;
484  case SQUARE:
485  y = x < 0.5f ? 1.f : -1.f;
486  break;
487  case TRIANGLE:
488  y = x < 0.5f ? ( 4.f * x ) - 1.f : ( -4.f * x ) + 3.f;
489  break;
490  case SAWTOOTH:
491  y = x;
492  break;
493  case SAWTOOTH_INVERSE:
494  y = 1.f - x;
495  break;
496  case NOISE:
497  y = Noiser::get();
498  break;
499  default:
500  break;
501  }
502 
503  return base + ( y * amp );
504  }
505 
506 
507  };
508 
510  {
511  const f32 lng = i * 2.0f * core::PI / 255.0f;
512  const f32 lat = j * 2.0f * core::PI / 255.0f;
513  return core::vector3df(cosf ( lat ) * sinf ( lng ),
514  sinf ( lat ) * sinf ( lng ),
515  cosf ( lng ));
516  }
517 
518  //
519  inline void getModifierFunc ( SModifierFunction& fill, const core::stringc &string, u32 &pos )
520  {
521  if ( string.size() == 0 )
522  return;
523 
524  static const c8 * funclist[] =
525  {
526  "sin","cos","square",
527  "triangle", "sawtooth","inversesawtooth", "noise"
528  };
529 
530  fill.func = (eQ3ModifierFunction) isEqual ( string,pos, funclist,7 );
531  fill.func = fill.func == UNKNOWN ? SINUS : (eQ3ModifierFunction) ((u32) fill.func + WAVE_MODIFIER_FUNCTION + 1);
532 
533  fill.base = getAsFloat ( string, pos );
534  fill.amp = getAsFloat ( string, pos );
535  fill.phase = getAsFloat ( string, pos );
536  fill.frequency = getAsFloat ( string, pos );
537  }
538 
539 
540  // name = "a b c .."
541  struct SVariable
542  {
545 
546  SVariable ( const c8 * n, const c8 *c = 0 ) : name ( n ), content (c) {}
547  virtual ~SVariable () {}
548 
549  void clear ()
550  {
551  name = "";
552  content = "";
553  }
554 
555  s32 isValid () const
556  {
557  return name.size();
558  }
559 
560  bool operator == ( const SVariable &other ) const
561  {
562  return 0 == strcmp ( name.c_str(), other.name.c_str () );
563  }
564 
565  bool operator < ( const SVariable &other ) const
566  {
567  return 0 > strcmp ( name.c_str(), other.name.c_str () );
568  }
569 
570  };
571 
572 
573  // string database. "a" = "Hello", "b" = "1234.6"
574  struct SVarGroup
575  {
577  virtual ~SVarGroup () {}
578 
579  u32 isDefined ( const c8 * name, const c8 * content = 0 ) const
580  {
581  for ( u32 i = 0; i != Variable.size (); ++i )
582  {
583  if ( 0 == strcmp ( Variable[i].name.c_str(), name ) &&
584  ( 0 == content || strstr ( Variable[i].content.c_str(), content ) )
585  )
586  {
587  return i + 1;
588  }
589  }
590  return 0;
591  }
592 
593  // searches for Variable name and returns is content
594  // if Variable is not found a reference to an Empty String is returned
595  const core::stringc &get( const c8 * name ) const
596  {
597  SVariable search ( name );
598  s32 index = Variable.linear_search ( search );
599  if ( index < 0 )
600  return irrEmptyStringc;
601 
602  return Variable [ index ].content;
603  }
604 
605  // set the Variable name
606  void set ( const c8 * name, const c8 * content = 0 )
607  {
608  u32 index = isDefined ( name, 0 );
609  if ( 0 == index )
610  {
611  Variable.push_back ( SVariable ( name, content ) );
612  }
613  else
614  {
615  Variable [ index ].content = content;
616  }
617  }
618 
619 
621  };
622 
625  {
627  {
629  }
630  virtual ~SVarGroupList () {}
631 
633  };
634 
635 
637  struct IShader
638  {
640  : ID ( 0 ), VarGroup ( 0 ) {}
641  virtual ~IShader () {}
642 
643  void operator = (const IShader &other )
644  {
645  ID = other.ID;
646  VarGroup = other.VarGroup;
647  name = other.name;
648  }
649 
650  bool operator == (const IShader &other ) const
651  {
652  return 0 == strcmp ( name.c_str(), other.name.c_str () );
653  //return name == other.name;
654  }
655 
656  bool operator < (const IShader &other ) const
657  {
658  return strcmp ( name.c_str(), other.name.c_str () ) < 0;
659  //return name < other.name;
660  }
661 
662  u32 getGroupSize () const
663  {
664  if ( 0 == VarGroup )
665  return 0;
666  return VarGroup->VariableGroup.size ();
667  }
668 
669  const SVarGroup * getGroup ( u32 stage ) const
670  {
671  if ( 0 == VarGroup || stage >= VarGroup->VariableGroup.size () )
672  return 0;
673 
674  return &VarGroup->VariableGroup [ stage ];
675  }
676 
677  // id
679  SVarGroupList *VarGroup; // reference
680 
681  // Shader: shader name ( also first variable in first Vargroup )
682  // Entity: classname ( variable in Group(1) )
684  };
685 
686  typedef IShader IEntity;
687 
689 
690  /*
691  dump shader like original layout, regardless of internal data holding
692  no recursive folding..
693  */
694  inline void dumpVarGroup ( core::stringc &dest, const SVarGroup * group, s32 stack )
695  {
696  core::stringc buf;
697  s32 i;
698 
699 
700  if ( stack > 0 )
701  {
702  buf = "";
703  for ( i = 0; i < stack - 1; ++i )
704  buf += '\t';
705 
706  buf += "{\n";
707  dest.append ( buf );
708  }
709 
710  for ( u32 g = 0; g != group->Variable.size(); ++g )
711  {
712  buf = "";
713  for ( i = 0; i < stack; ++i )
714  buf += '\t';
715 
716  buf += group->Variable[g].name;
717  buf += " ";
718  buf += group->Variable[g].content;
719  buf += "\n";
720  dest.append ( buf );
721  }
722 
723  if ( stack > 1 )
724  {
725  buf = "";
726  for ( i = 0; i < stack - 1; ++i )
727  buf += '\t';
728 
729  buf += "}\n";
730  dest.append ( buf );
731  }
732 
733  }
734 
738  inline core::stringc & dumpShader ( core::stringc &dest, const IShader * shader, bool entity = false )
739  {
740  if ( 0 == shader )
741  return dest;
742 
743  const SVarGroup * group;
744 
745  const u32 size = shader->VarGroup->VariableGroup.size ();
746  for ( u32 i = 0; i != size; ++i )
747  {
748  group = &shader->VarGroup->VariableGroup[ i ];
749  dumpVarGroup ( dest, group, core::clamp( (int)i, 0, 2 ) );
750  }
751 
752  if ( !entity )
753  {
754  if ( size <= 1 )
755  {
756  dest.append ( "{\n" );
757  }
758  dest.append ( "}\n" );
759  }
760  return dest;
761  }
762 
763 
764  /*
765  quake3 doesn't care much about tga & jpg
766  load one or multiple files stored in name started at startPos to the texture array textures
767  if texture is not loaded 0 will be added ( to find missing textures easier)
768  */
769  inline void getTextures(tTexArray &textures,
770  const core::stringc &name, u32 &startPos,
771  io::IFileSystem *fileSystem,
772  video::IVideoDriver* driver)
773  {
774  static const char* extension[] =
775  {
776  ".jpg",
777  ".jpeg",
778  ".png",
779  ".dds",
780  ".tga",
781  ".bmp",
782  ".pcx"
783  };
784 
785  tStringList stringList;
786  getAsStringList(stringList, -1, name, startPos);
787 
788  textures.clear();
789 
790  io::path loadFile;
791  for ( u32 i = 0; i!= stringList.size (); ++i )
792  {
793  video::ITexture* texture = 0;
794  for (u32 g = 0; g != 7 ; ++g)
795  {
796  core::cutFilenameExtension ( loadFile, stringList[i] );
797 
798  if ( loadFile == "$whiteimage" )
799  {
800  texture = driver->getTexture( "$whiteimage" );
801  if ( 0 == texture )
802  {
803  core::dimension2du s ( 2, 2 );
804  u32 image[4] = { 0xFFFFFFFF, 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF };
805  video::IImage* w = driver->createImageFromData ( video::ECF_A8R8G8B8, s,&image );
806  texture = driver->addTexture( "$whiteimage", w );
807  w->drop ();
808  }
809 
810  }
811  else
812  if ( loadFile == "$redimage" )
813  {
814  texture = driver->getTexture( "$redimage" );
815  if ( 0 == texture )
816  {
817  core::dimension2du s ( 2, 2 );
818  u32 image[4] = { 0xFFFF0000, 0xFFFF0000,0xFFFF0000,0xFFFF0000 };
819  video::IImage* w = driver->createImageFromData ( video::ECF_A8R8G8B8, s,&image );
820  texture = driver->addTexture( "$redimage", w );
821  w->drop ();
822  }
823  }
824  else
825  if ( loadFile == "$blueimage" )
826  {
827  texture = driver->getTexture( "$blueimage" );
828  if ( 0 == texture )
829  {
830  core::dimension2du s ( 2, 2 );
831  u32 image[4] = { 0xFF0000FF, 0xFF0000FF,0xFF0000FF,0xFF0000FF };
832  video::IImage* w = driver->createImageFromData ( video::ECF_A8R8G8B8, s,&image );
833  texture = driver->addTexture( "$blueimage", w );
834  w->drop ();
835  }
836  }
837  else
838  if ( loadFile == "$checkerimage" )
839  {
840  texture = driver->getTexture( "$checkerimage" );
841  if ( 0 == texture )
842  {
843  core::dimension2du s ( 2, 2 );
844  u32 image[4] = { 0xFFFFFFFF, 0xFF000000,0xFF000000,0xFFFFFFFF };
845  video::IImage* w = driver->createImageFromData ( video::ECF_A8R8G8B8, s,&image );
846  texture = driver->addTexture( "$checkerimage", w );
847  w->drop ();
848  }
849  }
850  else
851  if ( loadFile == "$lightmap" )
852  {
853  texture = 0;
854  }
855  else
856  {
857  loadFile.append ( extension[g] );
858  }
859 
860  if ( fileSystem->existFile ( loadFile ) )
861  {
862  texture = driver->getTexture( loadFile );
863  if ( texture )
864  break;
865  texture = 0;
866  }
867  }
868  // take 0 Texture
869  textures.push_back(texture);
870  }
871  }
872 
873 
876  {
877  };
878 
879 } // end namespace quake3
880 } // end namespace scene
881 } // end namespace irr
882 
883 #endif
884 

The Irrlicht Engine
The Irrlicht Engine Documentation © 2003-2010 by Nikolaus Gebhardt. Generated on Tue Jun 5 2012 17:57:12 by Doxygen (1.8.1)