mirror of
https://github.com/minetest/irrlicht.git
synced 2024-12-25 02:00:30 +01:00
77d5df9b1b
I had somewhat rashly removed operator = in [r6280] But since c++11 implicit defined copy assignment operator is deprecated when a user-declared destructor exists. Still... alternative would be adding copy assignment operator but neither that nor the virtual destructor seem to be needed. So rather removind destructor which seems to add an unnecessary virtual function table for it (seems to be just used like a POD throughout the code) git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@6362 dfc29bdd-3216-0410-991c-e03cc46cb475
874 lines
20 KiB
C++
874 lines
20 KiB
C++
// Copyright (C) 2006-2012 Nikolaus Gebhardt / Thomas Alten
|
|
// This file is part of the "Irrlicht Engine".
|
|
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
|
|
|
#ifndef IRR_I_Q3_LEVEL_SHADER_H_INCLUDED
|
|
#define IRR_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
|
|
{
|
|
|
|
static core::stringc irrEmptyStringc("");
|
|
|
|
//! 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_FOG,
|
|
E_Q3_MESH_UNRESOLVED,
|
|
E_Q3_MESH_SIZE
|
|
};
|
|
|
|
/*! used to customize Quake3 BSP Loader
|
|
*/
|
|
|
|
struct Q3LevelLoadParameter
|
|
{
|
|
Q3LevelLoadParameter ()
|
|
:defaultLightMapMaterial ( video::EMT_LIGHTMAP_M4 ),
|
|
defaultModulate ( video::EMFN_MODULATE_4X ),
|
|
defaultFilter ( video::EMF_BILINEAR_FILTER ),
|
|
patchTesselation ( 8 ),
|
|
verbose ( 0 ),
|
|
startTime ( 0 ), endTime ( 0 ),
|
|
mergeShaderBuffer ( 1 ),
|
|
cleanUnResolvedMeshes ( 1 ),
|
|
loadAllShaders ( 0 ),
|
|
loadSkyShader ( 0 ),
|
|
alpharef ( 1 ),
|
|
swapLump ( 0 ),
|
|
#ifdef __BIG_ENDIAN__
|
|
swapHeader ( 1 )
|
|
#else
|
|
swapHeader ( 0 )
|
|
#endif
|
|
{
|
|
memcpy ( scriptDir, "scripts\x0", 8 );
|
|
}
|
|
|
|
video::E_MATERIAL_TYPE defaultLightMapMaterial;
|
|
video::E_MODULATE_FUNC defaultModulate;
|
|
video::E_MATERIAL_FLAG defaultFilter;
|
|
s32 patchTesselation;
|
|
s32 verbose;
|
|
u32 startTime;
|
|
u32 endTime;
|
|
s32 mergeShaderBuffer;
|
|
s32 cleanUnResolvedMeshes;
|
|
s32 loadAllShaders;
|
|
s32 loadSkyShader;
|
|
s32 alpharef;
|
|
s32 swapLump;
|
|
s32 swapHeader;
|
|
c8 scriptDir [ 64 ];
|
|
};
|
|
|
|
// some useful typedefs
|
|
typedef core::array< core::stringc > tStringList;
|
|
typedef core::array< video::ITexture* > tTexArray;
|
|
|
|
// string helper.. TODO: move to generic files
|
|
inline s16 isEqual ( const core::stringc &string, u32 &pos, const c8 * const list[], u16 listSize )
|
|
{
|
|
const char * in = string.c_str () + pos;
|
|
|
|
for ( u16 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 (s16) 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;
|
|
}
|
|
|
|
//! get a quake3 vector translated to irrlicht position (x,-z,y )
|
|
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 );
|
|
|
|
}
|
|
|
|
//! A blend function for a q3 shader.
|
|
struct SBlendFunc
|
|
{
|
|
SBlendFunc ( video::E_MODULATE_FUNC mod )
|
|
: type ( video::EMT_SOLID ), modulate ( mod ),
|
|
param0( 0.f ),
|
|
isTransparent ( 0 ) {}
|
|
|
|
video::E_MATERIAL_TYPE type;
|
|
video::E_MODULATE_FUNC modulate;
|
|
|
|
f32 param0;
|
|
u32 isTransparent;
|
|
};
|
|
|
|
// parses the content of Variable cull
|
|
inline bool getCullingFunction ( const core::stringc &cull )
|
|
{
|
|
if ( cull.size() == 0 )
|
|
return true;
|
|
|
|
bool ret = true;
|
|
static const c8 * funclist[] = { "none", "disable", "twosided" };
|
|
|
|
u32 pos = 0;
|
|
switch ( isEqual ( cull, pos, funclist, 3 ) )
|
|
{
|
|
case 0:
|
|
case 1:
|
|
case 2:
|
|
ret = false;
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// parses the content of Variable depthfunc
|
|
// return a z-test
|
|
inline u8 getDepthFunction ( const core::stringc &string )
|
|
{
|
|
u8 ret = video::ECFN_LESSEQUAL;
|
|
|
|
if ( string.size() == 0 )
|
|
return ret;
|
|
|
|
static const c8 * funclist[] = { "lequal","equal" };
|
|
|
|
u32 pos = 0;
|
|
switch ( isEqual ( string, pos, funclist, 2 ) )
|
|
{
|
|
case 0:
|
|
ret = video::ECFN_LESSEQUAL;
|
|
break;
|
|
case 1:
|
|
ret = video::ECFN_EQUAL;
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*!
|
|
parses the content of Variable blendfunc,alphafunc
|
|
it also make a hint for rendering as transparent or solid node.
|
|
|
|
we assume a typical quake scene would look like this..
|
|
1) Big Static Mesh ( solid )
|
|
2) static scene item ( may use transparency ) but rendered in the solid pass
|
|
3) additional transparency item in the transparent pass
|
|
|
|
it's not 100% accurate! it just empirical..
|
|
*/
|
|
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_ZERO:
|
|
switch ( dstFact )
|
|
{
|
|
// gl_zero gl_src_color == gl_dst_color gl_zero
|
|
case video::EBF_SRC_COLOR:
|
|
blendfunc.type = video::EMT_ONETEXTURE_BLEND;
|
|
blendfunc.param0 = video::pack_textureBlendFunc ( video::EBF_DST_COLOR, video::EBF_ZERO, blendfunc.modulate );
|
|
blendfunc.isTransparent = 1;
|
|
resolved = 1;
|
|
break;
|
|
} break;
|
|
|
|
case video::EBF_ONE:
|
|
switch ( dstFact )
|
|
{
|
|
// gl_one gl_zero
|
|
case video::EBF_ZERO:
|
|
blendfunc.type = video::EMT_SOLID;
|
|
blendfunc.isTransparent = 0;
|
|
resolved = 1;
|
|
break;
|
|
|
|
// gl_one gl_one
|
|
case video::EBF_ONE:
|
|
blendfunc.type = video::EMT_TRANSPARENT_ADD_COLOR;
|
|
blendfunc.isTransparent = 1;
|
|
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.param0 = 1.f/255.f;
|
|
blendfunc.isTransparent = 1;
|
|
resolved = 1;
|
|
break;
|
|
} break;
|
|
|
|
case 11:
|
|
// add
|
|
blendfunc.type = video::EMT_TRANSPARENT_ADD_COLOR;
|
|
blendfunc.isTransparent = 1;
|
|
resolved = 1;
|
|
break;
|
|
case 12:
|
|
// filter = gl_dst_color gl_zero or gl_zero gl_src_color
|
|
blendfunc.type = video::EMT_ONETEXTURE_BLEND;
|
|
blendfunc.param0 = video::pack_textureBlendFunc ( video::EBF_DST_COLOR, video::EBF_ZERO, blendfunc.modulate );
|
|
blendfunc.isTransparent = 1;
|
|
resolved = 1;
|
|
break;
|
|
case 13:
|
|
// blend = gl_src_alpha gl_one_minus_src_alpha
|
|
blendfunc.type = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
|
|
blendfunc.param0 = 1.f/255.f;
|
|
blendfunc.isTransparent = 1;
|
|
resolved = 1;
|
|
break;
|
|
case 14:
|
|
// alphafunc ge128
|
|
blendfunc.type = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
|
|
blendfunc.param0 = 0.5f;
|
|
blendfunc.isTransparent = 1;
|
|
resolved = 1;
|
|
break;
|
|
case 15:
|
|
// alphafunc gt0
|
|
blendfunc.type = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
|
|
blendfunc.param0 = 1.f / 255.f;
|
|
blendfunc.isTransparent = 1;
|
|
resolved = 1;
|
|
break;
|
|
|
|
}
|
|
|
|
// use the generic blender
|
|
if ( 0 == resolved )
|
|
{
|
|
blendfunc.type = video::EMT_ONETEXTURE_BLEND;
|
|
blendfunc.param0 = video::pack_textureBlendFunc (
|
|
(video::E_BLEND_FACTOR) srcFact,
|
|
(video::E_BLEND_FACTOR) dstFact,
|
|
blendfunc.modulate);
|
|
|
|
blendfunc.isTransparent = 1;
|
|
}
|
|
}
|
|
|
|
// random noise [-1;1]
|
|
struct Noiser
|
|
{
|
|
static f32 get ()
|
|
{
|
|
static u32 RandomSeed = 0x69666966;
|
|
RandomSeed = (RandomSeed * 3631 + 1);
|
|
|
|
f32 value = ( (f32) (RandomSeed & 0x7FFF ) * (1.0f / (f32)(0x7FFF >> 1) ) ) - 1.f;
|
|
return value;
|
|
}
|
|
};
|
|
|
|
enum eQ3ModifierFunction
|
|
{
|
|
TCMOD = 0,
|
|
DEFORMVERTEXES = 1,
|
|
RGBGEN = 2,
|
|
TCGEN = 3,
|
|
MAP = 4,
|
|
ALPHAGEN = 5,
|
|
|
|
FUNCTION2 = 0x10,
|
|
SCROLL = FUNCTION2 + 1,
|
|
SCALE = FUNCTION2 + 2,
|
|
ROTATE = FUNCTION2 + 3,
|
|
STRETCH = FUNCTION2 + 4,
|
|
TURBULENCE = FUNCTION2 + 5,
|
|
WAVE = FUNCTION2 + 6,
|
|
|
|
IDENTITY = FUNCTION2 + 7,
|
|
VERTEX = FUNCTION2 + 8,
|
|
TEXTURE = FUNCTION2 + 9,
|
|
LIGHTMAP = FUNCTION2 + 10,
|
|
ENVIRONMENT = FUNCTION2 + 11,
|
|
DOLLAR_LIGHTMAP = FUNCTION2 + 12,
|
|
BULGE = FUNCTION2 + 13,
|
|
AUTOSPRITE = FUNCTION2 + 14,
|
|
AUTOSPRITE2 = FUNCTION2 + 15,
|
|
TRANSFORM = FUNCTION2 + 16,
|
|
EXACTVERTEX = FUNCTION2 + 17,
|
|
CONSTANT = FUNCTION2 + 18,
|
|
LIGHTINGSPECULAR = FUNCTION2 + 19,
|
|
MOVE = FUNCTION2 + 20,
|
|
NORMAL = FUNCTION2 + 21,
|
|
IDENTITYLIGHTING = FUNCTION2 + 22,
|
|
|
|
WAVE_MODIFIER_FUNCTION = 0x30,
|
|
SINUS = WAVE_MODIFIER_FUNCTION + 1,
|
|
COSINUS = WAVE_MODIFIER_FUNCTION + 2,
|
|
SQUARE = WAVE_MODIFIER_FUNCTION + 3,
|
|
TRIANGLE = WAVE_MODIFIER_FUNCTION + 4,
|
|
SAWTOOTH = WAVE_MODIFIER_FUNCTION + 5,
|
|
SAWTOOTH_INVERSE = WAVE_MODIFIER_FUNCTION + 6,
|
|
NOISE = WAVE_MODIFIER_FUNCTION + 7,
|
|
|
|
UNKNOWN = -2
|
|
};
|
|
|
|
struct SModifierFunction
|
|
{
|
|
SModifierFunction ()
|
|
: masterfunc0 ( UNKNOWN ), masterfunc1( UNKNOWN ), func ( SINUS ),
|
|
tcgen( TEXTURE ), rgbgen ( IDENTITY ), alphagen ( UNKNOWN ),
|
|
base ( 0 ), amp ( 1 ), phase ( 0 ), frequency ( 1 ),
|
|
wave ( 1 ),
|
|
x ( 0 ), y ( 0 ), z( 0 ), count( 0 ) {}
|
|
|
|
// "tcmod","deformvertexes","rgbgen", "tcgen"
|
|
eQ3ModifierFunction masterfunc0;
|
|
// depends
|
|
eQ3ModifierFunction masterfunc1;
|
|
// depends
|
|
eQ3ModifierFunction func;
|
|
|
|
eQ3ModifierFunction tcgen;
|
|
eQ3ModifierFunction rgbgen;
|
|
eQ3ModifierFunction alphagen;
|
|
|
|
union
|
|
{
|
|
f32 base;
|
|
f32 bulgewidth;
|
|
};
|
|
|
|
union
|
|
{
|
|
f32 amp;
|
|
f32 bulgeheight;
|
|
};
|
|
|
|
f32 phase;
|
|
|
|
union
|
|
{
|
|
f32 frequency;
|
|
f32 bulgespeed;
|
|
};
|
|
|
|
union
|
|
{
|
|
f32 wave;
|
|
f32 div;
|
|
};
|
|
|
|
f32 x;
|
|
f32 y;
|
|
f32 z;
|
|
u32 count;
|
|
|
|
f32 evaluate ( f32 dt ) const
|
|
{
|
|
// phase in 0 and 1..
|
|
f32 x = core::fract( (dt + phase ) * frequency );
|
|
f32 y = 0.f;
|
|
|
|
switch ( func )
|
|
{
|
|
case SINUS:
|
|
y = sinf ( x * core::PI * 2.f );
|
|
break;
|
|
case COSINUS:
|
|
y = cosf ( x * core::PI * 2.f );
|
|
break;
|
|
case SQUARE:
|
|
y = x < 0.5f ? 1.f : -1.f;
|
|
break;
|
|
case TRIANGLE:
|
|
y = x < 0.5f ? ( 4.f * x ) - 1.f : ( -4.f * x ) + 3.f;
|
|
break;
|
|
case SAWTOOTH:
|
|
y = x;
|
|
break;
|
|
case SAWTOOTH_INVERSE:
|
|
y = 1.f - x;
|
|
break;
|
|
case NOISE:
|
|
y = Noiser::get();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return base + ( y * amp );
|
|
}
|
|
|
|
|
|
};
|
|
|
|
inline core::vector3df getMD3Normal ( u32 i, u32 j )
|
|
{
|
|
const f32 lng = i * 2.0f * core::PI / 255.0f;
|
|
const f32 lat = j * 2.0f * core::PI / 255.0f;
|
|
return core::vector3df(cosf ( lat ) * sinf ( lng ),
|
|
sinf ( lat ) * sinf ( lng ),
|
|
cosf ( lng ));
|
|
}
|
|
|
|
//
|
|
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", "noise"
|
|
};
|
|
|
|
fill.func = (eQ3ModifierFunction) isEqual ( string,pos, funclist,7 );
|
|
fill.func = fill.func == UNKNOWN ? SINUS : (eQ3ModifierFunction) ((u32) fill.func + WAVE_MODIFIER_FUNCTION + 1);
|
|
|
|
fill.base = getAsFloat ( string, pos );
|
|
fill.amp = getAsFloat ( string, pos );
|
|
fill.phase = getAsFloat ( string, pos );
|
|
fill.frequency = getAsFloat ( string, pos );
|
|
}
|
|
|
|
|
|
// name = "a b c .."
|
|
struct SVariable
|
|
{
|
|
core::stringc name;
|
|
core::stringc content;
|
|
|
|
SVariable ( const c8 * n, const c8 *c = 0 ) : name ( n ), content (c) {}
|
|
virtual ~SVariable () {}
|
|
|
|
void clear ()
|
|
{
|
|
name = "";
|
|
content = "";
|
|
}
|
|
|
|
s32 isValid () const
|
|
{
|
|
return name.size();
|
|
}
|
|
|
|
bool operator == ( const SVariable &other ) const
|
|
{
|
|
return 0 == strcmp ( name.c_str(), other.name.c_str () );
|
|
}
|
|
|
|
bool operator < ( const SVariable &other ) const
|
|
{
|
|
return 0 > strcmp ( name.c_str(), other.name.c_str () );
|
|
}
|
|
|
|
};
|
|
|
|
|
|
// string database. "a" = "Hello", "b" = "1234.6"
|
|
struct SVarGroup
|
|
{
|
|
SVarGroup () { Variable.setAllocStrategy ( core::ALLOC_STRATEGY_SAFE ); }
|
|
virtual ~SVarGroup () {}
|
|
|
|
u32 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 ) &&
|
|
( 0 == content || strstr ( Variable[i].content.c_str(), content ) )
|
|
)
|
|
{
|
|
return i + 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// 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
|
|
{
|
|
SVariable search ( name );
|
|
s32 index = Variable.linear_search ( search );
|
|
if ( index < 0 )
|
|
return irrEmptyStringc;
|
|
|
|
return Variable [ index ].content;
|
|
}
|
|
|
|
// set the Variable name
|
|
void set ( const c8 * name, const c8 * content = 0 )
|
|
{
|
|
u32 index = isDefined ( name, 0 );
|
|
if ( 0 == index )
|
|
{
|
|
Variable.push_back ( SVariable ( name, content ) );
|
|
}
|
|
else
|
|
{
|
|
Variable [ index ].content = content;
|
|
}
|
|
}
|
|
|
|
|
|
core::array < SVariable > Variable;
|
|
};
|
|
|
|
//! holding a group a variable
|
|
struct SVarGroupList: public IReferenceCounted
|
|
{
|
|
SVarGroupList ()
|
|
{
|
|
VariableGroup.setAllocStrategy ( core::ALLOC_STRATEGY_SAFE );
|
|
}
|
|
virtual ~SVarGroupList () {}
|
|
|
|
core::array < SVarGroup > VariableGroup;
|
|
};
|
|
|
|
|
|
//! A Parsed Shader Holding Variables ordered in Groups
|
|
struct IShader
|
|
{
|
|
IShader ()
|
|
: ID ( 0 ), VarGroup ( 0 ) {}
|
|
|
|
bool operator == (const IShader &other ) const
|
|
{
|
|
return 0 == strcmp ( name.c_str(), other.name.c_str () );
|
|
//return name == other.name;
|
|
}
|
|
|
|
bool operator < (const IShader &other ) const
|
|
{
|
|
return strcmp ( name.c_str(), other.name.c_str () ) < 0;
|
|
//return name < other.name;
|
|
}
|
|
|
|
u32 getGroupSize () const
|
|
{
|
|
if ( 0 == VarGroup )
|
|
return 0;
|
|
return VarGroup->VariableGroup.size ();
|
|
}
|
|
|
|
const SVarGroup * getGroup ( u32 stage ) const
|
|
{
|
|
if ( 0 == VarGroup || stage >= VarGroup->VariableGroup.size () )
|
|
return 0;
|
|
|
|
return &VarGroup->VariableGroup [ stage ];
|
|
}
|
|
|
|
// id
|
|
s32 ID;
|
|
SVarGroupList *VarGroup; // reference
|
|
|
|
// Shader: shader name ( also first variable in first Vargroup )
|
|
// Entity: classname ( variable in Group(1) )
|
|
core::stringc name;
|
|
};
|
|
|
|
typedef IShader IEntity;
|
|
|
|
typedef core::array < IEntity > 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;
|
|
|
|
if ( stack > 0 )
|
|
{
|
|
buf = "";
|
|
for (s32 i = 0; i < stack - 1; ++i )
|
|
buf += '\t';
|
|
|
|
buf += "{\n";
|
|
dest.append ( buf );
|
|
}
|
|
|
|
for ( u32 g = 0; g != group->Variable.size(); ++g )
|
|
{
|
|
buf = "";
|
|
for (s32 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 (s32 i = 0; i < stack - 1; ++i )
|
|
buf += '\t';
|
|
|
|
buf += "}\n";
|
|
dest.append ( buf );
|
|
}
|
|
}
|
|
|
|
/*!
|
|
dump a Shader or an Entity
|
|
*/
|
|
inline core::stringc & dumpShader ( core::stringc &dest, const IShader * shader, bool entity = false )
|
|
{
|
|
if ( 0 == shader )
|
|
return dest;
|
|
|
|
const u32 size = shader->VarGroup->VariableGroup.size ();
|
|
for ( u32 i = 0; i != size; ++i )
|
|
{
|
|
const SVarGroup * group = &shader->VarGroup->VariableGroup[ i ];
|
|
dumpVarGroup ( dest, group, core::clamp( (int)i, 0, 2 ) );
|
|
}
|
|
|
|
if ( !entity )
|
|
{
|
|
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)
|
|
*/
|
|
inline void getTextures(tTexArray &textures,
|
|
const core::stringc &name, u32 &startPos,
|
|
const io::IFileSystem *fileSystem,
|
|
video::IVideoDriver* driver)
|
|
{
|
|
static const char * const extension[] =
|
|
{
|
|
".jpg",
|
|
".jpeg",
|
|
".png",
|
|
".dds",
|
|
".tga",
|
|
".bmp",
|
|
".pcx"
|
|
};
|
|
|
|
tStringList stringList;
|
|
getAsStringList(stringList, -1, name, startPos);
|
|
|
|
textures.clear();
|
|
|
|
io::path loadFile;
|
|
for ( u32 i = 0; i!= stringList.size (); ++i )
|
|
{
|
|
video::ITexture* texture = 0;
|
|
for (u32 g = 0; g != 7; ++g)
|
|
{
|
|
core::cutFilenameExtension ( loadFile, stringList[i] );
|
|
|
|
if ( loadFile == "$whiteimage" )
|
|
{
|
|
texture = driver->getTexture( "$whiteimage" );
|
|
if ( 0 == texture )
|
|
{
|
|
core::dimension2du s ( 2, 2 );
|
|
u32 image[4] = { 0xFFFFFFFF, 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF };
|
|
video::IImage* w = driver->createImageFromData ( video::ECF_A8R8G8B8, s,&image );
|
|
texture = driver->addTexture( "$whiteimage", w );
|
|
w->drop ();
|
|
}
|
|
|
|
}
|
|
else
|
|
if ( loadFile == "$redimage" )
|
|
{
|
|
texture = driver->getTexture( "$redimage" );
|
|
if ( 0 == texture )
|
|
{
|
|
core::dimension2du s ( 2, 2 );
|
|
u32 image[4] = { 0xFFFF0000, 0xFFFF0000,0xFFFF0000,0xFFFF0000 };
|
|
video::IImage* w = driver->createImageFromData ( video::ECF_A8R8G8B8, s,&image );
|
|
texture = driver->addTexture( "$redimage", w );
|
|
w->drop ();
|
|
}
|
|
}
|
|
else
|
|
if ( loadFile == "$blueimage" )
|
|
{
|
|
texture = driver->getTexture( "$blueimage" );
|
|
if ( 0 == texture )
|
|
{
|
|
core::dimension2du s ( 2, 2 );
|
|
u32 image[4] = { 0xFF0000FF, 0xFF0000FF,0xFF0000FF,0xFF0000FF };
|
|
video::IImage* w = driver->createImageFromData ( video::ECF_A8R8G8B8, s,&image );
|
|
texture = driver->addTexture( "$blueimage", w );
|
|
w->drop ();
|
|
}
|
|
}
|
|
else
|
|
if ( loadFile == "$checkerimage" )
|
|
{
|
|
texture = driver->getTexture( "$checkerimage" );
|
|
if ( 0 == texture )
|
|
{
|
|
core::dimension2du s ( 2, 2 );
|
|
u32 image[4] = { 0xFFFFFFFF, 0xFF000000,0xFF000000,0xFFFFFFFF };
|
|
video::IImage* w = driver->createImageFromData ( video::ECF_A8R8G8B8, s,&image );
|
|
texture = driver->addTexture( "$checkerimage", w );
|
|
w->drop ();
|
|
}
|
|
}
|
|
else
|
|
if ( loadFile == "$lightmap" )
|
|
{
|
|
texture = 0;
|
|
}
|
|
else
|
|
{
|
|
loadFile.append ( extension[g] );
|
|
}
|
|
|
|
texture = driver->findTexture( loadFile );
|
|
if ( texture )
|
|
break;
|
|
|
|
if ( fileSystem->existFile ( loadFile ) )
|
|
{
|
|
texture = driver->getTexture( loadFile );
|
|
if ( texture )
|
|
break;
|
|
texture = 0;
|
|
}
|
|
}
|
|
// take 0 Texture
|
|
textures.push_back(texture);
|
|
}
|
|
}
|
|
|
|
|
|
//! Manages various Quake3 Shader Styles
|
|
class IShaderManager : public IReferenceCounted
|
|
{
|
|
};
|
|
|
|
} // end namespace quake3
|
|
} // end namespace scene
|
|
} // end namespace irr
|
|
|
|
#endif
|