Home | Namespaces | Hierarchy | Alphabetical List | Class list | Files | Namespace Members | Class members | File members

IQ3Shader.h

Go to the documentation of this file.
00001 // Copyright (C) 2006-2008 Nikolaus Gebhardt / Thomas Alten
00002 // This file is part of the "Irrlicht Engine".
00003 // For conditions of distribution and use, see copyright notice in irrlicht.h
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         // we are not using gamma, so quake3 is very dark.
00033         // define the standard multiplication for lightmaps and vertex colors
00034         const video::E_MATERIAL_TYPE defaultLightMap = video::EMT_LIGHTMAP_M2;
00035         const video::E_MODULATE_FUNC defaultModulate = video::EMFN_MODULATE_2X;
00036 
00037         // some useful typedefs
00038         typedef core::array< core::stringc > tStringList;
00039         typedef core::array< video::ITexture* > tTexArray;
00040 
00041         // name = "a b c .."
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         // string helper.. TODO: move to generic files
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                 extract substrings
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         // parses the content of Variable cull
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         // parses the content of Variable depthfunc
00165         // return a z-test
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         // parses the content of Variable blendfunc,alphafunc
00189         inline static void getBlendFunc ( const core::stringc &string, SBlendFunc &blendfunc )
00190         {
00191                 if ( string.size() == 0 )
00192                         return;
00193 
00194                 // maps to E_BLEND_FACTOR
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                                         // gl_one gl_zero
00233                                         case video::EBF_ZERO:
00234                                                 blendfunc.type = video::EMT_SOLID;
00235                                                 resolved = 1;
00236                                                 break;
00237 
00238                                         // gl_one gl_one
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                                         // gl_src_alpha gl_one_minus_src_alpha
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                                 // add
00258                                 blendfunc.type = video::EMT_TRANSPARENT_ADD_COLOR;
00259                                 resolved = 1;
00260                                 break;
00261                         case 12:
00262                                 // filter = gl_dst_color gl_zero
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                                 // blend
00269                                 blendfunc.type = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
00270                                 blendfunc.param = 1.f / 255.f;
00271                                 resolved = 1;
00272                                 break;
00273                         case 14:
00274                                 // alphafunc ge128
00275                                 blendfunc.type = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
00276                                 blendfunc.param = 0.5f;
00277                                 resolved = 1;
00278                                 break;
00279                         case 15:
00280                                 // alphafunc gt0
00281                                 blendfunc.type = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
00282                                 blendfunc.param = 1.f / 255.f;
00283                                 resolved = 1;
00284                                 break;
00285                 }
00286 
00287                 // use the generic blender
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                 // "tcmod","deformvertexes","rgbgen", "tcgen"
00305                 s32 masterfunc0;
00306                 // depends
00307                 s32 masterfunc1;
00308                 // depends
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                         // phase in 0 and 1..
00338                         f32 x = core::fract( (dt + phase ) * freq );
00339                         f32 y = 0.f;
00340 
00341                         switch ( func )
00342                         {
00343                                 // sin
00344                                 case 0:
00345                                         y = (f32) sin ( x * core::PI64 * 2.0 );
00346                                         break;
00347                                 // cos
00348                                 case 1:
00349                                         y = (f32) cos ( x * core::PI64 * 2.0 );
00350                                         break;
00351                                 // square
00352                                 case 2:
00353                                         y = x < 0.5f ? 1.f : -1.f;
00354                                         break;
00355                                 // triangle
00356                                 case 3:
00357                                         y = x < 0.5f ? ( 2.f * x ) - 1.f : ( -2.f * x ) + 2.f;
00358                                         break;
00359                                 // sawtooth:
00360                                 case 4:
00361                                         y = x;
00362                                         break;
00363                                 // inverse sawtooth:
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                 // simple assoziative array
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                 // searches for Variable name and returns is content
00410                 // if Variable is not found a reference to an Empty String is returned
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                         // id
00470                         s32 id;
00471 
00472                         // Shader: shader name ( also first variable in first Vargroup )
00473                         // Entity: classname ( variable in Group(1) )
00474                         core::stringc name;
00475                         SVarGroupList *VarGroup; // reference
00476         };
00477 
00478         typedef SShader SEntity;
00479 
00480         typedef core::array < SEntity > tQ3EntityList;
00481 
00482         /*
00483                 dump shader like original layout, regardless of internal data holding
00484                 no recursive folding..
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                 quake3 doesn't care much about tga & jpg
00556                 load one or multiple files stored in name started at startPos to the texture array textures
00557                 if texture is not loaded 0 will be added ( to find missing textures easier)
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                         // take 0 Texture
00593                         textures.push_back(texture);
00594                 }
00595         }
00596 
00597 
00599         class IShaderManager : public IReferenceCounted
00600         {
00601         };
00602 
00603 } // end namespace quake3
00604 } // end namespace scene
00605 } // end namespace irr
00606 
00607 #endif
00608 

The Irrlicht Engine
The Irrlicht Engine Documentation © 2003-2008 by Nikolaus Gebhardt. Generated on Sun Jun 1 07:59:08 2008 by Doxygen (1.4.2)