2009-01-27 05:23:36 -08:00
|
|
|
// Copyright (C) 2006-2009 Nikolaus Gebhardt / Thomas Alten
|
2007-05-20 11:03:49 -07:00
|
|
|
// This file is part of the "Irrlicht Engine".
|
|
|
|
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
|
|
|
|
|
|
|
#ifndef __I_Q3_LEVEL_SHADER_H_INCLUDED__
|
|
|
|
#define __I_Q3_LEVEL_SHADER_H_INCLUDED__
|
|
|
|
|
|
|
|
#include "irrArray.h"
|
|
|
|
#include "fast_atof.h"
|
|
|
|
#include "IFileSystem.h"
|
|
|
|
#include "IVideoDriver.h"
|
|
|
|
#include "coreutil.h"
|
|
|
|
|
|
|
|
namespace irr
|
|
|
|
{
|
|
|
|
namespace scene
|
|
|
|
{
|
|
|
|
namespace quake3
|
|
|
|
{
|
|
|
|
|
2007-10-10 07:07:40 -07:00
|
|
|
static const core::stringc irrEmptyStringc("");
|
|
|
|
|
2007-05-20 11:03:49 -07:00
|
|
|
//! Hold the different Mesh Types used for getMesh
|
|
|
|
enum eQ3MeshIndex
|
|
|
|
{
|
|
|
|
E_Q3_MESH_GEOMETRY = 0,
|
|
|
|
E_Q3_MESH_ITEMS,
|
|
|
|
E_Q3_MESH_BILLBOARD,
|
|
|
|
E_Q3_MESH_SIZE
|
|
|
|
};
|
|
|
|
|
|
|
|
// we are not using gamma, so quake3 is very dark.
|
|
|
|
// define the standard multiplication for lightmaps and vertex colors
|
2007-11-13 06:35:29 -08:00
|
|
|
const video::E_MATERIAL_TYPE defaultMaterialType = video::EMT_LIGHTMAP_M4;
|
|
|
|
const video::E_MODULATE_FUNC defaultModulate = video::EMFN_MODULATE_4X;
|
2007-05-20 11:03:49 -07:00
|
|
|
|
|
|
|
// some useful typedefs
|
|
|
|
typedef core::array< core::stringc > tStringList;
|
|
|
|
typedef core::array< video::ITexture* > tTexArray;
|
|
|
|
|
|
|
|
// name = "a b c .."
|
|
|
|
struct SVariable
|
|
|
|
{
|
|
|
|
core::stringc name;
|
|
|
|
core::stringc content;
|
|
|
|
|
|
|
|
void clear ()
|
|
|
|
{
|
2007-10-10 07:07:40 -07:00
|
|
|
name = "";
|
|
|
|
content = "";
|
2007-05-20 11:03:49 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
s32 isValid () const
|
|
|
|
{
|
|
|
|
return name.size();
|
|
|
|
}
|
|
|
|
|
2007-06-27 22:10:23 -07:00
|
|
|
bool operator == ( const SVariable &other ) const
|
2007-05-20 11:03:49 -07:00
|
|
|
{
|
2007-06-27 22:10:23 -07:00
|
|
|
return name == other.name;
|
2007-05-20 11:03:49 -07:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// string helper.. TODO: move to generic files
|
|
|
|
inline s32 isEqual ( const core::stringc &string, u32 &pos, const c8 *list[], u32 listSize )
|
|
|
|
{
|
|
|
|
const char * in = string.c_str () + pos;
|
|
|
|
|
|
|
|
for ( u32 i = 0; i != listSize; ++i )
|
|
|
|
{
|
|
|
|
if (string.size() < pos)
|
|
|
|
return -2;
|
|
|
|
u32 len = (u32) strlen ( list[i] );
|
|
|
|
if (string.size() < pos+len)
|
|
|
|
continue;
|
|
|
|
if ( in [len] != 0 && in [len] != ' ' )
|
|
|
|
continue;
|
|
|
|
if ( strncmp ( in, list[i], len ) )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
pos += len + 1;
|
|
|
|
return (s32) i;
|
|
|
|
}
|
|
|
|
return -2;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline f32 getAsFloat ( const core::stringc &string, u32 &pos )
|
|
|
|
{
|
|
|
|
const char * in = string.c_str () + pos;
|
|
|
|
|
|
|
|
f32 value = 0.f;
|
|
|
|
pos += (u32) ( core::fast_atof_move ( in, value ) - in ) + 1;
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline core::vector3df getAsVector3df ( const core::stringc &string, u32 &pos )
|
|
|
|
{
|
|
|
|
core::vector3df v;
|
|
|
|
|
|
|
|
v.X = getAsFloat ( string, pos );
|
|
|
|
v.Z = getAsFloat ( string, pos );
|
|
|
|
v.Y = getAsFloat ( string, pos );
|
|
|
|
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
extract substrings
|
|
|
|
*/
|
|
|
|
inline void getAsStringList ( tStringList &list, s32 max, const core::stringc &string, u32 &startPos )
|
|
|
|
{
|
|
|
|
list.clear ();
|
|
|
|
|
|
|
|
s32 finish = 0;
|
|
|
|
s32 endPos;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
endPos = string.findNext ( ' ', startPos );
|
|
|
|
if ( endPos == -1 )
|
|
|
|
{
|
|
|
|
finish = 1;
|
|
|
|
endPos = string.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
list.push_back ( string.subString ( startPos, endPos - startPos ) );
|
|
|
|
startPos = endPos + 1;
|
|
|
|
|
|
|
|
if ( list.size() >= (u32) max )
|
|
|
|
finish = 1;
|
|
|
|
|
|
|
|
} while ( !finish );
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2008-05-22 04:51:37 -07:00
|
|
|
//! A blend function for a q3 shader.
|
2007-05-20 11:03:49 -07:00
|
|
|
struct SBlendFunc
|
|
|
|
{
|
2007-11-13 06:35:29 -08:00
|
|
|
SBlendFunc ()
|
2007-11-14 01:50:41 -08:00
|
|
|
: type ( video::EMT_SOLID ), modulate ( defaultModulate ), param ( 0.f ),
|
|
|
|
isTransparent ( false ) {}
|
2007-05-20 11:03:49 -07:00
|
|
|
|
|
|
|
video::E_MATERIAL_TYPE type;
|
2007-11-13 06:35:29 -08:00
|
|
|
video::E_MODULATE_FUNC modulate;
|
|
|
|
|
2007-05-20 11:03:49 -07:00
|
|
|
f32 param;
|
2007-11-14 01:50:41 -08:00
|
|
|
bool isTransparent;
|
2007-05-20 11:03:49 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
// parses the content of Variable cull
|
2007-11-13 06:35:29 -08:00
|
|
|
inline bool isDisabled ( const core::stringc &string )
|
2007-05-20 11:03:49 -07:00
|
|
|
{
|
|
|
|
if ( string.size() == 0 )
|
|
|
|
return true;
|
|
|
|
|
|
|
|
bool ret = true;
|
|
|
|
static const c8 * funclist[] = { "none", "disable" };
|
|
|
|
|
|
|
|
u32 pos = 0;
|
|
|
|
switch ( isEqual ( string, pos, funclist, 2 ) )
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
case 1:
|
|
|
|
ret = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// parses the content of Variable depthfunc
|
|
|
|
// return a z-test
|
|
|
|
inline u32 getDepthFunction ( const core::stringc &string )
|
|
|
|
{
|
|
|
|
if ( string.size() == 0 )
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
u32 ret = 1;
|
2008-05-22 04:51:37 -07:00
|
|
|
static const c8 * funclist[] = { "lequal","equal" };
|
2007-05-20 11:03:49 -07:00
|
|
|
|
|
|
|
u32 pos = 0;
|
|
|
|
switch ( isEqual ( string, pos, funclist, 2 ) )
|
|
|
|
{
|
|
|
|
case 0:
|
2009-01-27 05:23:36 -08:00
|
|
|
ret = video::ECFN_LESSEQUAL;
|
2007-05-20 11:03:49 -07:00
|
|
|
case 1:
|
2009-01-27 05:23:36 -08:00
|
|
|
ret = video::ECFN_EQUAL;
|
2007-05-20 11:03:49 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// parses the content of Variable blendfunc,alphafunc
|
|
|
|
inline static void getBlendFunc ( const core::stringc &string, SBlendFunc &blendfunc )
|
|
|
|
{
|
|
|
|
if ( string.size() == 0 )
|
|
|
|
return;
|
|
|
|
|
|
|
|
// maps to E_BLEND_FACTOR
|
|
|
|
static const c8 * funclist[] =
|
|
|
|
{
|
|
|
|
"gl_zero",
|
|
|
|
"gl_one",
|
|
|
|
"gl_dst_color",
|
|
|
|
"gl_one_minus_dst_color",
|
|
|
|
"gl_src_color",
|
|
|
|
"gl_one_minus_src_color",
|
|
|
|
"gl_src_alpha",
|
|
|
|
"gl_one_minus_src_alpha",
|
|
|
|
"gl_dst_alpha",
|
|
|
|
"gl_one_minus_dst_alpha",
|
|
|
|
"gl_src_alpha_sat",
|
|
|
|
|
|
|
|
"add",
|
|
|
|
"filter",
|
|
|
|
"blend",
|
|
|
|
|
|
|
|
"ge128",
|
|
|
|
"gt0"
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
u32 pos = 0;
|
|
|
|
s32 srcFact = isEqual ( string, pos, funclist, 16 );
|
|
|
|
|
|
|
|
if ( srcFact < 0 )
|
|
|
|
return;
|
|
|
|
|
|
|
|
u32 resolved = 0;
|
|
|
|
s32 dstFact = isEqual ( string, pos, funclist, 16 );
|
|
|
|
|
|
|
|
switch ( srcFact )
|
|
|
|
{
|
|
|
|
case video::EBF_ONE:
|
|
|
|
switch ( dstFact )
|
|
|
|
{
|
|
|
|
// gl_one gl_zero
|
|
|
|
case video::EBF_ZERO:
|
|
|
|
blendfunc.type = video::EMT_SOLID;
|
2007-11-13 06:35:29 -08:00
|
|
|
blendfunc.isTransparent = false;
|
2007-05-20 11:03:49 -07:00
|
|
|
resolved = 1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
// gl_one gl_one
|
|
|
|
case video::EBF_ONE:
|
|
|
|
blendfunc.type = video::EMT_TRANSPARENT_ADD_COLOR;
|
2007-11-13 06:35:29 -08:00
|
|
|
blendfunc.isTransparent = true;
|
2007-05-20 11:03:49 -07:00
|
|
|
resolved = 1;
|
|
|
|
break;
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case video::EBF_SRC_ALPHA:
|
|
|
|
switch ( dstFact )
|
|
|
|
{
|
|
|
|
// gl_src_alpha gl_one_minus_src_alpha
|
|
|
|
case video::EBF_ONE_MINUS_SRC_ALPHA:
|
|
|
|
blendfunc.type = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
|
|
|
|
blendfunc.param = 1.f / 255.f;
|
2007-11-13 06:35:29 -08:00
|
|
|
blendfunc.isTransparent = true;
|
2007-05-20 11:03:49 -07:00
|
|
|
resolved = 1;
|
|
|
|
break;
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case 11:
|
|
|
|
// add
|
|
|
|
blendfunc.type = video::EMT_TRANSPARENT_ADD_COLOR;
|
2007-11-13 06:35:29 -08:00
|
|
|
blendfunc.isTransparent = true;
|
2007-05-20 11:03:49 -07:00
|
|
|
resolved = 1;
|
|
|
|
break;
|
|
|
|
case 12:
|
|
|
|
// filter = gl_dst_color gl_zero
|
|
|
|
blendfunc.type = video::EMT_ONETEXTURE_BLEND;
|
|
|
|
blendfunc.param = video::pack_texureBlendFunc ( video::EBF_DST_COLOR, video::EBF_ZERO, defaultModulate );
|
2007-11-13 06:35:29 -08:00
|
|
|
blendfunc.isTransparent = false;
|
2007-05-20 11:03:49 -07:00
|
|
|
resolved = 1;
|
|
|
|
break;
|
|
|
|
case 13:
|
|
|
|
// blend
|
|
|
|
blendfunc.type = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
|
|
|
|
blendfunc.param = 1.f / 255.f;
|
2007-11-13 06:35:29 -08:00
|
|
|
blendfunc.isTransparent = true;
|
2007-05-20 11:03:49 -07:00
|
|
|
resolved = 1;
|
|
|
|
break;
|
|
|
|
case 14:
|
|
|
|
// alphafunc ge128
|
|
|
|
blendfunc.type = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
|
|
|
|
blendfunc.param = 0.5f;
|
2007-11-13 06:35:29 -08:00
|
|
|
blendfunc.isTransparent = true;
|
2007-05-20 11:03:49 -07:00
|
|
|
resolved = 1;
|
|
|
|
break;
|
|
|
|
case 15:
|
|
|
|
// alphafunc gt0
|
|
|
|
blendfunc.type = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
|
|
|
|
blendfunc.param = 1.f / 255.f;
|
2007-11-13 06:35:29 -08:00
|
|
|
blendfunc.isTransparent = true;
|
2007-05-20 11:03:49 -07:00
|
|
|
resolved = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// use the generic blender
|
|
|
|
if ( 0 == resolved )
|
|
|
|
{
|
|
|
|
blendfunc.type = video::EMT_ONETEXTURE_BLEND;
|
|
|
|
blendfunc.param = video::pack_texureBlendFunc (
|
|
|
|
(video::E_BLEND_FACTOR) srcFact,
|
|
|
|
(video::E_BLEND_FACTOR) dstFact,
|
2007-11-13 06:35:29 -08:00
|
|
|
blendfunc.modulate);
|
|
|
|
|
|
|
|
if (srcFact == video::EBF_SRC_COLOR && dstFact == video::EBF_ZERO)
|
|
|
|
{
|
|
|
|
blendfunc.isTransparent = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
blendfunc.isTransparent = true;
|
|
|
|
}
|
|
|
|
|
2007-05-20 11:03:49 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct SModifierFunction
|
|
|
|
{
|
|
|
|
SModifierFunction ()
|
2007-11-13 06:35:29 -08:00
|
|
|
: masterfunc0 ( -2 ), masterfunc1(0), func ( 0 ),
|
2007-05-20 11:03:49 -07:00
|
|
|
tcgen( 8 ), base ( 0 ), amp ( 1 ), phase ( 0 ), freq ( 1 ), wave(1) {}
|
|
|
|
|
|
|
|
// "tcmod","deformvertexes","rgbgen", "tcgen"
|
|
|
|
s32 masterfunc0;
|
|
|
|
// depends
|
|
|
|
s32 masterfunc1;
|
|
|
|
// depends
|
|
|
|
s32 func;
|
|
|
|
|
|
|
|
s32 tcgen;
|
|
|
|
|
|
|
|
union
|
|
|
|
{
|
|
|
|
f32 base;
|
|
|
|
f32 bulgewidth;
|
|
|
|
};
|
|
|
|
|
|
|
|
union
|
|
|
|
{
|
|
|
|
f32 amp;
|
|
|
|
f32 bulgeheight;
|
|
|
|
};
|
|
|
|
|
|
|
|
f32 phase;
|
|
|
|
|
|
|
|
union
|
|
|
|
{
|
|
|
|
f32 freq;
|
|
|
|
f32 bulgespeed;
|
|
|
|
};
|
|
|
|
|
|
|
|
f32 wave;
|
|
|
|
|
|
|
|
f32 evaluate ( f32 dt ) const
|
|
|
|
{
|
|
|
|
// phase in 0 and 1..
|
|
|
|
f32 x = core::fract( (dt + phase ) * freq );
|
|
|
|
f32 y = 0.f;
|
|
|
|
|
|
|
|
switch ( func )
|
|
|
|
{
|
|
|
|
// sin
|
|
|
|
case 0:
|
|
|
|
y = (f32) sin ( x * core::PI64 * 2.0 );
|
|
|
|
break;
|
|
|
|
// cos
|
|
|
|
case 1:
|
|
|
|
y = (f32) cos ( x * core::PI64 * 2.0 );
|
|
|
|
break;
|
|
|
|
// square
|
|
|
|
case 2:
|
|
|
|
y = x < 0.5f ? 1.f : -1.f;
|
|
|
|
break;
|
|
|
|
// triangle
|
|
|
|
case 3:
|
|
|
|
y = x < 0.5f ? ( 2.f * x ) - 1.f : ( -2.f * x ) + 2.f;
|
|
|
|
break;
|
|
|
|
// sawtooth:
|
|
|
|
case 4:
|
|
|
|
y = x;
|
|
|
|
break;
|
|
|
|
// inverse sawtooth:
|
|
|
|
case 5:
|
|
|
|
y = 1.f - x;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return base + ( y * amp );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
//
|
|
|
|
inline void getModifierFunc ( SModifierFunction& fill, const core::stringc &string, u32 &pos )
|
|
|
|
{
|
|
|
|
if ( string.size() == 0 )
|
|
|
|
return;
|
|
|
|
|
|
|
|
static const c8 * funclist[] =
|
|
|
|
{
|
|
|
|
"sin","cos","square", "triangle", "sawtooth","inversesawtooth"
|
|
|
|
};
|
|
|
|
|
|
|
|
fill.func = quake3::isEqual ( string,pos, funclist,6 );
|
|
|
|
if ( fill.func == -2 )
|
|
|
|
fill.func = 0;
|
|
|
|
|
|
|
|
fill.base = quake3::getAsFloat ( string, pos );
|
|
|
|
fill.amp = quake3::getAsFloat ( string, pos );
|
|
|
|
fill.phase = quake3::getAsFloat ( string, pos );
|
|
|
|
fill.freq = quake3::getAsFloat ( string, pos );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct SVarGroup
|
|
|
|
{
|
|
|
|
// simple assoziative array
|
|
|
|
s32 getIndex( const c8 * name ) const
|
|
|
|
{
|
|
|
|
SVariable search;
|
|
|
|
search.name = name;
|
|
|
|
|
|
|
|
return Variable.linear_search ( search );
|
|
|
|
}
|
|
|
|
|
|
|
|
// searches for Variable name and returns is content
|
|
|
|
// if Variable is not found a reference to an Empty String is returned
|
|
|
|
const core::stringc &get( const c8 * name ) const
|
|
|
|
{
|
|
|
|
s32 index = getIndex ( name );
|
|
|
|
if ( index < 0 )
|
2007-10-10 07:07:40 -07:00
|
|
|
return irrEmptyStringc;
|
2007-05-20 11:03:49 -07:00
|
|
|
|
|
|
|
return Variable [ index ].content;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isDefined ( const c8 * name, const c8 * content = 0 ) const
|
|
|
|
{
|
|
|
|
for ( u32 i = 0; i != Variable.size (); ++i )
|
|
|
|
{
|
|
|
|
if ( 0 == strcmp ( Variable[i].name.c_str(), name ) )
|
|
|
|
{
|
|
|
|
if ( 0 == content )
|
|
|
|
return true;
|
|
|
|
if ( 0 == strcmp ( Variable[i].content.c_str(), content ) )
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
core::array < SVariable > Variable;
|
|
|
|
};
|
|
|
|
|
2007-09-06 23:11:47 -07:00
|
|
|
struct SVarGroupList: public IReferenceCounted
|
2007-05-20 11:03:49 -07:00
|
|
|
{
|
|
|
|
SVarGroupList () {}
|
|
|
|
virtual ~SVarGroupList () {}
|
|
|
|
|
|
|
|
core::array < SVarGroup > VariableGroup;
|
|
|
|
};
|
|
|
|
|
2008-05-22 04:51:37 -07:00
|
|
|
|
2007-05-20 11:03:49 -07:00
|
|
|
//! A Parsed Shader Holding Variables ordered in Groups
|
|
|
|
class SShader
|
|
|
|
{
|
|
|
|
public:
|
2007-06-27 22:10:23 -07:00
|
|
|
bool operator == (const SShader &other ) const
|
|
|
|
{
|
|
|
|
return name == other.name;
|
|
|
|
}
|
|
|
|
|
2007-05-20 11:03:49 -07:00
|
|
|
bool operator < (const SShader &other ) const
|
|
|
|
{
|
2007-06-27 22:10:23 -07:00
|
|
|
return name < other.name;
|
2007-05-20 11:03:49 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
const SVarGroup * getGroup ( u32 stage ) const
|
|
|
|
{
|
|
|
|
if ( 0 == VarGroup || stage >= VarGroup->VariableGroup.size () )
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return &VarGroup->VariableGroup [ stage ];
|
|
|
|
}
|
|
|
|
|
|
|
|
// id
|
|
|
|
s32 id;
|
|
|
|
|
|
|
|
// Shader: shader name ( also first variable in first Vargroup )
|
|
|
|
// Entity: classname ( variable in Group(1) )
|
|
|
|
core::stringc name;
|
2008-05-22 04:51:37 -07:00
|
|
|
SVarGroupList *VarGroup; // reference
|
2007-05-20 11:03:49 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
typedef SShader SEntity;
|
|
|
|
|
|
|
|
typedef core::array < SEntity > tQ3EntityList;
|
|
|
|
|
|
|
|
/*
|
|
|
|
dump shader like original layout, regardless of internal data holding
|
|
|
|
no recursive folding..
|
|
|
|
*/
|
|
|
|
inline void dumpVarGroup ( core::stringc &dest, const SVarGroup * group, s32 stack )
|
|
|
|
{
|
|
|
|
core::stringc buf;
|
|
|
|
s32 i;
|
|
|
|
|
|
|
|
|
|
|
|
if ( stack > 0 )
|
|
|
|
{
|
|
|
|
buf = "";
|
|
|
|
for ( i = 0; i < stack - 1; ++i )
|
|
|
|
buf += '\t';
|
|
|
|
|
|
|
|
buf += "{\n";
|
|
|
|
dest.append ( buf );
|
|
|
|
}
|
|
|
|
|
|
|
|
for ( u32 g = 0; g != group->Variable.size(); ++g )
|
|
|
|
{
|
|
|
|
buf = "";
|
|
|
|
for ( i = 0; i < stack; ++i )
|
|
|
|
buf += '\t';
|
|
|
|
|
|
|
|
buf += group->Variable[g].name;
|
|
|
|
buf += " ";
|
|
|
|
buf += group->Variable[g].content;
|
|
|
|
buf += "\n";
|
|
|
|
dest.append ( buf );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( stack > 1 )
|
|
|
|
{
|
|
|
|
buf = "";
|
|
|
|
for ( i = 0; i < stack - 1; ++i )
|
|
|
|
buf += '\t';
|
|
|
|
|
|
|
|
buf += "}\n";
|
|
|
|
dest.append ( buf );
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
inline core::stringc & dumpShader ( core::stringc &dest, const SShader * shader )
|
|
|
|
{
|
|
|
|
dest = "";
|
|
|
|
if ( 0 == shader )
|
|
|
|
return dest;
|
|
|
|
|
|
|
|
const SVarGroup * group;
|
|
|
|
|
|
|
|
const u32 size = shader->VarGroup->VariableGroup.size ();
|
|
|
|
|
|
|
|
for ( u32 i = 0; i != size; ++i )
|
|
|
|
{
|
|
|
|
group = &shader->VarGroup->VariableGroup[ i ];
|
2007-12-03 02:10:13 -08:00
|
|
|
dumpVarGroup ( dest, group, core::clamp( (int)i, 0, 2 ) );
|
2007-05-20 11:03:49 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if ( size <= 1 )
|
|
|
|
{
|
|
|
|
dest.append ( "{\n" );
|
|
|
|
}
|
|
|
|
|
|
|
|
dest.append ( "}\n" );
|
|
|
|
return dest;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
quake3 doesn't care much about tga & jpg
|
|
|
|
load one or multiple files stored in name started at startPos to the texture array textures
|
|
|
|
if texture is not loaded 0 will be added ( to find missing textures easier)
|
|
|
|
*/
|
2008-05-22 04:51:37 -07:00
|
|
|
inline void getTextures(tTexArray &textures,
|
|
|
|
const core::stringc &name, u32 &startPos,
|
|
|
|
io::IFileSystem *fileSystem,
|
|
|
|
video::IVideoDriver* driver)
|
2007-05-20 11:03:49 -07:00
|
|
|
{
|
2008-05-22 04:51:37 -07:00
|
|
|
static const char * extension[2] =
|
2007-05-20 11:03:49 -07:00
|
|
|
{
|
|
|
|
".jpg",
|
|
|
|
".tga"
|
|
|
|
};
|
|
|
|
|
|
|
|
tStringList stringList;
|
|
|
|
getAsStringList ( stringList, -1, name, startPos );
|
|
|
|
|
|
|
|
textures.clear();
|
|
|
|
|
|
|
|
core::stringc loadFile;
|
|
|
|
for ( u32 i = 0; i!= stringList.size (); ++i )
|
|
|
|
{
|
|
|
|
video::ITexture* texture = 0;
|
|
|
|
for ( u32 g = 0; g != 2 ; ++g )
|
|
|
|
{
|
2007-09-19 07:08:28 -07:00
|
|
|
core::cutFilenameExtension ( loadFile, stringList[i] ).append ( extension[g] );
|
2007-05-20 11:03:49 -07:00
|
|
|
|
|
|
|
if ( fileSystem->existFile ( loadFile.c_str() ) )
|
|
|
|
{
|
|
|
|
texture = driver->getTexture( loadFile.c_str () );
|
|
|
|
if ( texture )
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// take 0 Texture
|
|
|
|
textures.push_back(texture);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-05-22 04:51:37 -07:00
|
|
|
//! Manages various Quake3 Shader Styles
|
2007-09-19 07:08:28 -07:00
|
|
|
class IShaderManager : public IReferenceCounted
|
2007-05-20 11:03:49 -07:00
|
|
|
{
|
|
|
|
};
|
|
|
|
|
|
|
|
} // end namespace quake3
|
|
|
|
} // end namespace scene
|
|
|
|
} // end namespace irr
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|