git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@6456 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 ),
 | 
						|
			patchTessellation ( 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 patchTessellation;
 | 
						|
		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
 |