00001
00002
00003
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 const 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_SIZE
00030 };
00031
00032
00033
00034 const video::E_MATERIAL_TYPE defaultLightMap = video::EMT_LIGHTMAP_M2;
00035 const video::E_MODULATE_FUNC defaultModulate = video::EMFN_MODULATE_2X;
00036
00037
00038 typedef core::array< core::stringc > tStringList;
00039 typedef core::array< video::ITexture* > tTexArray;
00040
00041
00042 struct SVariable
00043 {
00044 core::stringc name;
00045 core::stringc content;
00046
00047 void clear ()
00048 {
00049 name = "";
00050 content = "";
00051 }
00052
00053 s32 isValid () const
00054 {
00055 return name.size();
00056 }
00057
00058 bool operator == ( const SVariable &other ) const
00059 {
00060 return name == other.name;
00061 }
00062 };
00063
00064
00065 inline s32 isEqual ( const core::stringc &string, u32 &pos, const c8 *list[], u32 listSize )
00066 {
00067 const char * in = string.c_str () + pos;
00068
00069 for ( u32 i = 0; i != listSize; ++i )
00070 {
00071 if (string.size() < pos)
00072 return -2;
00073 u32 len = (u32) strlen ( list[i] );
00074 if (string.size() < pos+len)
00075 continue;
00076 if ( in [len] != 0 && in [len] != ' ' )
00077 continue;
00078 if ( strncmp ( in, list[i], len ) )
00079 continue;
00080
00081 pos += len + 1;
00082 return (s32) i;
00083 }
00084 return -2;
00085 }
00086
00087 inline f32 getAsFloat ( const core::stringc &string, u32 &pos )
00088 {
00089 const char * in = string.c_str () + pos;
00090
00091 f32 value = 0.f;
00092 pos += (u32) ( core::fast_atof_move ( in, value ) - in ) + 1;
00093 return value;
00094 }
00095
00096 inline core::vector3df getAsVector3df ( const core::stringc &string, u32 &pos )
00097 {
00098 core::vector3df v;
00099
00100 v.X = getAsFloat ( string, pos );
00101 v.Z = getAsFloat ( string, pos );
00102 v.Y = getAsFloat ( string, pos );
00103
00104 return v;
00105 }
00106
00107
00108
00109
00110 inline void getAsStringList ( tStringList &list, s32 max, const core::stringc &string, u32 &startPos )
00111 {
00112 list.clear ();
00113
00114 s32 finish = 0;
00115 s32 endPos;
00116 do
00117 {
00118 endPos = string.findNext ( ' ', startPos );
00119 if ( endPos == -1 )
00120 {
00121 finish = 1;
00122 endPos = string.size();
00123 }
00124
00125 list.push_back ( string.subString ( startPos, endPos - startPos ) );
00126 startPos = endPos + 1;
00127
00128 if ( list.size() >= (u32) max )
00129 finish = 1;
00130
00131 } while ( !finish );
00132
00133 }
00134
00136 struct SBlendFunc
00137 {
00138 SBlendFunc () : type ( video::EMT_SOLID ), param ( 0.f ) {}
00139
00140 video::E_MATERIAL_TYPE type;
00141 f32 param;
00142 };
00143
00144
00145 inline bool getBackfaceCulling ( const core::stringc &string )
00146 {
00147 if ( string.size() == 0 )
00148 return true;
00149
00150 bool ret = true;
00151 static const c8 * funclist[] = { "none", "disable" };
00152
00153 u32 pos = 0;
00154 switch ( isEqual ( string, pos, funclist, 2 ) )
00155 {
00156 case 0:
00157 case 1:
00158 ret = false;
00159 break;
00160 }
00161 return ret;
00162 }
00163
00164
00165
00166 inline u32 getDepthFunction ( const core::stringc &string )
00167 {
00168 if ( string.size() == 0 )
00169 return 1;
00170
00171 u32 ret = 1;
00172 static const c8 * funclist[] = { "lequal","equal" };
00173
00174 u32 pos = 0;
00175 switch ( isEqual ( string, pos, funclist, 2 ) )
00176 {
00177 case 0:
00178 ret = 1;
00179 case 1:
00180 ret = 2;
00181 break;
00182 }
00183 return ret;
00184 }
00185
00186
00187
00188
00189 inline static void getBlendFunc ( const core::stringc &string, SBlendFunc &blendfunc )
00190 {
00191 if ( string.size() == 0 )
00192 return;
00193
00194
00195 static const c8 * funclist[] =
00196 {
00197 "gl_zero",
00198 "gl_one",
00199 "gl_dst_color",
00200 "gl_one_minus_dst_color",
00201 "gl_src_color",
00202 "gl_one_minus_src_color",
00203 "gl_src_alpha",
00204 "gl_one_minus_src_alpha",
00205 "gl_dst_alpha",
00206 "gl_one_minus_dst_alpha",
00207 "gl_src_alpha_sat",
00208
00209 "add",
00210 "filter",
00211 "blend",
00212
00213 "ge128",
00214 "gt0"
00215 };
00216
00217
00218 u32 pos = 0;
00219 s32 srcFact = isEqual ( string, pos, funclist, 16 );
00220
00221 if ( srcFact < 0 )
00222 return;
00223
00224 u32 resolved = 0;
00225 s32 dstFact = isEqual ( string, pos, funclist, 16 );
00226
00227 switch ( srcFact )
00228 {
00229 case video::EBF_ONE:
00230 switch ( dstFact )
00231 {
00232
00233 case video::EBF_ZERO:
00234 blendfunc.type = video::EMT_SOLID;
00235 resolved = 1;
00236 break;
00237
00238
00239 case video::EBF_ONE:
00240 blendfunc.type = video::EMT_TRANSPARENT_ADD_COLOR;
00241 resolved = 1;
00242 break;
00243 } break;
00244
00245 case video::EBF_SRC_ALPHA:
00246 switch ( dstFact )
00247 {
00248
00249 case video::EBF_ONE_MINUS_SRC_ALPHA:
00250 blendfunc.type = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
00251 blendfunc.param = 1.f / 255.f;
00252 resolved = 1;
00253 break;
00254 } break;
00255
00256 case 11:
00257
00258 blendfunc.type = video::EMT_TRANSPARENT_ADD_COLOR;
00259 resolved = 1;
00260 break;
00261 case 12:
00262
00263 blendfunc.type = video::EMT_ONETEXTURE_BLEND;
00264 blendfunc.param = video::pack_texureBlendFunc ( video::EBF_DST_COLOR, video::EBF_ZERO, defaultModulate );
00265 resolved = 1;
00266 break;
00267 case 13:
00268
00269 blendfunc.type = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
00270 blendfunc.param = 1.f / 255.f;
00271 resolved = 1;
00272 break;
00273 case 14:
00274
00275 blendfunc.type = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
00276 blendfunc.param = 0.5f;
00277 resolved = 1;
00278 break;
00279 case 15:
00280
00281 blendfunc.type = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
00282 blendfunc.param = 1.f / 255.f;
00283 resolved = 1;
00284 break;
00285 }
00286
00287
00288 if ( 0 == resolved )
00289 {
00290 blendfunc.type = video::EMT_ONETEXTURE_BLEND;
00291 blendfunc.param = video::pack_texureBlendFunc (
00292 (video::E_BLEND_FACTOR) srcFact,
00293 (video::E_BLEND_FACTOR) dstFact,
00294 defaultModulate);
00295 }
00296 }
00297
00298 struct SModifierFunction
00299 {
00300 SModifierFunction ()
00301 : masterfunc0 ( 0 ), masterfunc1(0), func ( 0 ),
00302 tcgen( 8 ), base ( 0 ), amp ( 1 ), phase ( 0 ), freq ( 1 ), wave(1) {}
00303
00304
00305 s32 masterfunc0;
00306
00307 s32 masterfunc1;
00308
00309 s32 func;
00310
00311 s32 tcgen;
00312
00313 union
00314 {
00315 f32 base;
00316 f32 bulgewidth;
00317 };
00318
00319 union
00320 {
00321 f32 amp;
00322 f32 bulgeheight;
00323 };
00324
00325 f32 phase;
00326
00327 union
00328 {
00329 f32 freq;
00330 f32 bulgespeed;
00331 };
00332
00333 f32 wave;
00334
00335 f32 evaluate ( f32 dt ) const
00336 {
00337
00338 f32 x = core::fract( (dt + phase ) * freq );
00339 f32 y = 0.f;
00340
00341 switch ( func )
00342 {
00343
00344 case 0:
00345 y = (f32) sin ( x * core::PI64 * 2.0 );
00346 break;
00347
00348 case 1:
00349 y = (f32) cos ( x * core::PI64 * 2.0 );
00350 break;
00351
00352 case 2:
00353 y = x < 0.5f ? 1.f : -1.f;
00354 break;
00355
00356 case 3:
00357 y = x < 0.5f ? ( 2.f * x ) - 1.f : ( -2.f * x ) + 2.f;
00358 break;
00359
00360 case 4:
00361 y = x;
00362 break;
00363
00364 case 5:
00365 y = 1.f - x;
00366 break;
00367 }
00368
00369 return base + ( y * amp );
00370 }
00371
00372
00373 };
00374
00375
00376 inline void getModifierFunc ( SModifierFunction& fill, const core::stringc &string, u32 &pos )
00377 {
00378 if ( string.size() == 0 )
00379 return;
00380
00381 static const c8 * funclist[] =
00382 {
00383 "sin","cos","square", "triangle", "sawtooth","inversesawtooth"
00384 };
00385
00386 fill.func = quake3::isEqual ( string,pos, funclist,6 );
00387 if ( fill.func == -2 )
00388 fill.func = 0;
00389
00390 fill.base = quake3::getAsFloat ( string, pos );
00391 fill.amp = quake3::getAsFloat ( string, pos );
00392 fill.phase = quake3::getAsFloat ( string, pos );
00393 fill.freq = quake3::getAsFloat ( string, pos );
00394 }
00395
00396
00397
00398 struct SVarGroup
00399 {
00400
00401 s32 getIndex( const c8 * name ) const
00402 {
00403 SVariable search;
00404 search.name = name;
00405
00406 return Variable.linear_search ( search );
00407 }
00408
00409
00410
00411 const core::stringc &get( const c8 * name ) const
00412 {
00413 s32 index = getIndex ( name );
00414 if ( index < 0 )
00415 return irrEmptyStringc;
00416
00417 return Variable [ index ].content;
00418 }
00419
00420 bool isDefined ( const c8 * name, const c8 * content = 0 ) const
00421 {
00422 for ( u32 i = 0; i != Variable.size (); ++i )
00423 {
00424 if ( 0 == strcmp ( Variable[i].name.c_str(), name ) )
00425 {
00426 if ( 0 == content )
00427 return true;
00428 if ( 0 == strcmp ( Variable[i].content.c_str(), content ) )
00429 return true;
00430 }
00431 }
00432 return false;
00433 }
00434
00435 core::array < SVariable > Variable;
00436 };
00437
00438 struct SVarGroupList: public IReferenceCounted
00439 {
00440 SVarGroupList () {}
00441 virtual ~SVarGroupList () {}
00442
00443 core::array < SVarGroup > VariableGroup;
00444 };
00445
00446
00448 class SShader
00449 {
00450 public:
00451 bool operator == (const SShader &other ) const
00452 {
00453 return name == other.name;
00454 }
00455
00456 bool operator < (const SShader &other ) const
00457 {
00458 return name < other.name;
00459 }
00460
00461 const SVarGroup * getGroup ( u32 stage ) const
00462 {
00463 if ( 0 == VarGroup || stage >= VarGroup->VariableGroup.size () )
00464 return 0;
00465
00466 return &VarGroup->VariableGroup [ stage ];
00467 }
00468
00469
00470 s32 id;
00471
00472
00473
00474 core::stringc name;
00475 SVarGroupList *VarGroup;
00476 };
00477
00478 typedef SShader SEntity;
00479
00480 typedef core::array < SEntity > tQ3EntityList;
00481
00482
00483
00484
00485
00486 inline void dumpVarGroup ( core::stringc &dest, const SVarGroup * group, s32 stack )
00487 {
00488 core::stringc buf;
00489 s32 i;
00490
00491
00492 if ( stack > 0 )
00493 {
00494 buf = "";
00495 for ( i = 0; i < stack - 1; ++i )
00496 buf += '\t';
00497
00498 buf += "{\n";
00499 dest.append ( buf );
00500 }
00501
00502 for ( u32 g = 0; g != group->Variable.size(); ++g )
00503 {
00504 buf = "";
00505 for ( i = 0; i < stack; ++i )
00506 buf += '\t';
00507
00508 buf += group->Variable[g].name;
00509 buf += " ";
00510 buf += group->Variable[g].content;
00511 buf += "\n";
00512 dest.append ( buf );
00513 }
00514
00515 if ( stack > 1 )
00516 {
00517 buf = "";
00518 for ( i = 0; i < stack - 1; ++i )
00519 buf += '\t';
00520
00521 buf += "}\n";
00522 dest.append ( buf );
00523 }
00524
00525 }
00526
00527 inline core::stringc & dumpShader ( core::stringc &dest, const SShader * shader )
00528 {
00529 dest = "";
00530 if ( 0 == shader )
00531 return dest;
00532
00533 const SVarGroup * group;
00534
00535 const u32 size = shader->VarGroup->VariableGroup.size ();
00536
00537 for ( u32 i = 0; i != size; ++i )
00538 {
00539 group = &shader->VarGroup->VariableGroup[ i ];
00540 dumpVarGroup ( dest, group, core::clamp ( (s32) i, 0, 2 ) );
00541 }
00542
00543 if ( size <= 1 )
00544 {
00545 dest.append ( "{\n" );
00546 }
00547
00548 dest.append ( "}\n" );
00549 return dest;
00550 }
00551
00552
00553
00554
00555
00556
00557
00558
00559 inline void getTextures(tTexArray &textures,
00560 const core::stringc &name, u32 &startPos,
00561 io::IFileSystem *fileSystem,
00562 video::IVideoDriver* driver)
00563 {
00564 static const char * extension[2] =
00565 {
00566 ".jpg",
00567 ".tga"
00568 };
00569
00570 tStringList stringList;
00571 getAsStringList ( stringList, -1, name, startPos );
00572
00573 textures.clear();
00574
00575 core::stringc loadFile;
00576 for ( u32 i = 0; i!= stringList.size (); ++i )
00577 {
00578 video::ITexture* texture = 0;
00579 for ( u32 g = 0; g != 2 ; ++g )
00580 {
00581 core::cutFilenameExtension ( loadFile, stringList[i] ).append ( extension[g] );
00582
00583 if ( fileSystem->existFile ( loadFile.c_str() ) )
00584 {
00585 texture = driver->getTexture( loadFile.c_str () );
00586 if ( texture )
00587 {
00588 break;
00589 }
00590 }
00591 }
00592
00593 textures.push_back(texture);
00594 }
00595 }
00596
00597
00599 class IShaderManager : public IReferenceCounted
00600 {
00601 };
00602
00603 }
00604 }
00605 }
00606
00607 #endif
00608