DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

Material.cpp (76920B)


      1 /*
      2 ===========================================================================
      3 
      4 Doom 3 BFG Edition GPL Source Code
      5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 
      6 
      7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").  
      8 
      9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
     10 it under the terms of the GNU General Public License as published by
     11 the Free Software Foundation, either version 3 of the License, or
     12 (at your option) any later version.
     13 
     14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
     15 but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17 GNU General Public License for more details.
     18 
     19 You should have received a copy of the GNU General Public License
     20 along with Doom 3 BFG Edition Source Code.  If not, see <http://www.gnu.org/licenses/>.
     21 
     22 In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code.  If not, please request a copy in writing from id Software at the address below.
     23 
     24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
     25 
     26 ===========================================================================
     27 */
     28 
     29 #pragma hdrstop
     30 #include "../idlib/precompiled.h"
     31 
     32 
     33 #include "tr_local.h"
     34 
     35 /*
     36 
     37 Any errors during parsing just set MF_DEFAULTED and return, rather than throwing
     38 a hard error. This will cause the material to fall back to default material,
     39 but otherwise let things continue.
     40 
     41 Each material may have a set of calculations that must be evaluated before
     42 drawing with it.
     43 
     44 Every expression that a material uses can be evaluated at one time, which
     45 will allow for perfect common subexpression removal when I get around to
     46 writing it.
     47 
     48 Without this, scrolling an entire surface could result in evaluating the
     49 same texture matrix calculations a half dozen times.
     50 
     51   Open question: should I allow arbitrary per-vertex color, texCoord, and vertex
     52   calculations to be specified in the material code?
     53 
     54   Every stage will definately have a valid image pointer.
     55 
     56   We might want the ability to change the sort value based on conditionals,
     57   but it could be a hassle to implement,
     58 
     59 */
     60 
     61 // keep all of these on the stack, when they are static it makes material parsing non-reentrant
     62 typedef struct mtrParsingData_s {
     63 	bool			registerIsTemporary[MAX_EXPRESSION_REGISTERS];
     64 	float			shaderRegisters[MAX_EXPRESSION_REGISTERS];
     65 	expOp_t			shaderOps[MAX_EXPRESSION_OPS];
     66 	shaderStage_t	parseStages[MAX_SHADER_STAGES];
     67 
     68 	bool			registersAreConstant;
     69 	bool			forceOverlays;
     70 } mtrParsingData_t;
     71 
     72 idCVar r_forceSoundOpAmplitude( "r_forceSoundOpAmplitude", "0", CVAR_FLOAT, "Don't call into the sound system for amplitudes" );
     73 
     74 /*
     75 =============
     76 idMaterial::CommonInit
     77 =============
     78 */
     79 void idMaterial::CommonInit() {
     80 	desc = "<none>";
     81 	renderBump = "";
     82 	contentFlags = CONTENTS_SOLID;
     83 	surfaceFlags = SURFTYPE_NONE;
     84 	materialFlags = 0;
     85 	sort = SS_BAD;
     86 	stereoEye = 0;
     87 	coverage = MC_BAD;
     88 	cullType = CT_FRONT_SIDED;
     89 	deform = DFRM_NONE;
     90 	numOps = 0;
     91 	ops = NULL;
     92 	numRegisters = 0;
     93 	expressionRegisters = NULL;
     94 	constantRegisters = NULL;
     95 	numStages = 0;
     96 	numAmbientStages = 0;
     97 	stages = NULL;
     98 	editorImage = NULL;
     99 	lightFalloffImage = NULL;
    100 	shouldCreateBackSides = false;
    101 	entityGui = 0;
    102 	fogLight = false;
    103 	blendLight = false;
    104 	ambientLight = false;
    105 	noFog = false;
    106 	hasSubview = false;
    107 	allowOverlays = true;
    108 	unsmoothedTangents = false;
    109 	gui = NULL;
    110 	memset( deformRegisters, 0, sizeof( deformRegisters ) );
    111 	editorAlpha = 1.0;
    112 	spectrum = 0;
    113 	polygonOffset = 0;
    114 	suppressInSubview = false;
    115 	refCount = 0;
    116 	portalSky = false;
    117 	fastPathBumpImage = NULL;
    118 	fastPathDiffuseImage = NULL;
    119 	fastPathSpecularImage = NULL;
    120 	deformDecl = NULL;
    121 
    122 	decalInfo.stayTime = 10000;
    123 	decalInfo.fadeTime = 4000;
    124 	decalInfo.start[0] = 1;
    125 	decalInfo.start[1] = 1;
    126 	decalInfo.start[2] = 1;
    127 	decalInfo.start[3] = 1;
    128 	decalInfo.end[0] = 0;
    129 	decalInfo.end[1] = 0;
    130 	decalInfo.end[2] = 0;
    131 	decalInfo.end[3] = 0;
    132 }
    133 
    134 
    135 /*
    136 =============
    137 idMaterial::idMaterial
    138 =============
    139 */
    140 idMaterial::idMaterial() {
    141 	CommonInit();
    142 
    143 	// we put this here instead of in CommonInit, because
    144 	// we don't want it cleared when a material is purged
    145 	surfaceArea = 0;
    146 }
    147 
    148 /*
    149 =============
    150 idMaterial::~idMaterial
    151 =============
    152 */
    153 idMaterial::~idMaterial() {
    154 }
    155 
    156 /*
    157 ===============
    158 idMaterial::FreeData
    159 ===============
    160 */
    161 void idMaterial::FreeData() {
    162 	int i;
    163 
    164 	if ( stages ) {
    165 		// delete any idCinematic textures
    166 		for ( i = 0; i < numStages; i++ ) {
    167 			if ( stages[i].texture.cinematic != NULL ) {
    168 				delete stages[i].texture.cinematic;
    169 				stages[i].texture.cinematic = NULL;
    170 			}
    171 			if ( stages[i].newStage != NULL ) {
    172 				Mem_Free( stages[i].newStage );
    173 				stages[i].newStage = NULL;
    174 			}
    175 		}
    176 		R_StaticFree( stages );
    177 		stages = NULL;
    178 	}
    179 	if ( expressionRegisters != NULL ) {
    180 		R_StaticFree( expressionRegisters );
    181 		expressionRegisters = NULL;
    182 	}
    183 	if ( constantRegisters != NULL ) {
    184 		R_StaticFree( constantRegisters );
    185 		constantRegisters = NULL;
    186 	}
    187 	if ( ops != NULL ) {
    188 		R_StaticFree( ops );
    189 		ops = NULL;
    190 	}
    191 }
    192 
    193 /*
    194 ==============
    195 idMaterial::GetEditorImage
    196 ==============
    197 */
    198 idImage *idMaterial::GetEditorImage() const {
    199 	if ( editorImage ) {
    200 		return editorImage;
    201 	}
    202 
    203 	// if we don't have an editorImageName, use the first stage image
    204 	if ( !editorImageName.Length()) {
    205 		// _D3XP :: First check for a diffuse image, then use the first
    206 		if ( numStages && stages ) {
    207 			int i;
    208 			for( i = 0; i < numStages; i++ ) {
    209 				if ( stages[i].lighting == SL_DIFFUSE ) {
    210 					editorImage = stages[i].texture.image;
    211 					break;
    212 				}
    213 			}
    214 			if ( !editorImage ) {
    215 				editorImage = stages[0].texture.image;
    216 			}
    217 		} else {
    218 			editorImage = globalImages->defaultImage;
    219 		}
    220 	} else {
    221 		// look for an explicit one
    222 		editorImage = globalImages->ImageFromFile( editorImageName, TF_DEFAULT, TR_REPEAT, TD_DEFAULT );
    223 	}
    224 
    225 	if ( !editorImage ) {
    226 		editorImage = globalImages->defaultImage;
    227 	}
    228 
    229 	return editorImage;
    230 }
    231 
    232 
    233 // info parms
    234 typedef struct {
    235 	char	*name;
    236 	int		clearSolid, surfaceFlags, contents;
    237 } infoParm_t;
    238 
    239 static infoParm_t	infoParms[] = {
    240 	// game relevant attributes
    241 	{"solid",		0,	0,	CONTENTS_SOLID },		// may need to override a clearSolid
    242 	{"water",		1,	0,	CONTENTS_WATER },		// used for water
    243 	{"playerclip",	0,	0,	CONTENTS_PLAYERCLIP },	// solid to players
    244 	{"monsterclip",	0,	0,	CONTENTS_MONSTERCLIP },	// solid to monsters
    245 	{"moveableclip",0,	0,	CONTENTS_MOVEABLECLIP },// solid to moveable entities
    246 	{"ikclip",		0,	0,	CONTENTS_IKCLIP },		// solid to IK
    247 	{"blood",		0,	0,	CONTENTS_BLOOD },		// used to detect blood decals
    248 	{"trigger",		0,	0,	CONTENTS_TRIGGER },		// used for triggers
    249 	{"aassolid",	0,	0,	CONTENTS_AAS_SOLID },	// solid for AAS
    250 	{"aasobstacle",	0,	0,	CONTENTS_AAS_OBSTACLE },// used to compile an obstacle into AAS that can be enabled/disabled
    251 	{"flashlight_trigger",	0,	0,	CONTENTS_FLASHLIGHT_TRIGGER }, // used for triggers that are activated by the flashlight
    252 	{"nonsolid",	1,	0,	0 },					// clears the solid flag
    253 	{"nullNormal",	0,	SURF_NULLNORMAL,0 },		// renderbump will draw as 0x80 0x80 0x80
    254 
    255 	// utility relevant attributes
    256 	{"areaportal",	1,	0,	CONTENTS_AREAPORTAL },	// divides areas
    257 	{"qer_nocarve",	1,	0,	CONTENTS_NOCSG},		// don't cut brushes in editor
    258 
    259 	{"discrete",	1,	SURF_DISCRETE,	0 },		// surfaces should not be automatically merged together or
    260 													// clipped to the world,
    261 													// because they represent discrete objects like gui shaders
    262 													// mirrors, or autosprites
    263 	{"noFragment",	0,	SURF_NOFRAGMENT,	0 },
    264 
    265 	{"slick",		0,	SURF_SLICK,		0 },
    266 	{"collision",	0,	SURF_COLLISION,	0 },
    267 	{"noimpact",	0,	SURF_NOIMPACT,	0 },		// don't make impact explosions or marks
    268 	{"nodamage",	0,	SURF_NODAMAGE,	0 },		// no falling damage when hitting
    269 	{"ladder",		0,	SURF_LADDER,	0 },		// climbable
    270 	{"nosteps",		0,	SURF_NOSTEPS,	0 },		// no footsteps
    271 
    272 	// material types for particle, sound, footstep feedback
    273 	{"metal",		0,  SURFTYPE_METAL,		0 },	// metal
    274 	{"stone",		0,  SURFTYPE_STONE,		0 },	// stone
    275 	{"flesh",		0,  SURFTYPE_FLESH,		0 },	// flesh
    276 	{"wood",		0,  SURFTYPE_WOOD,		0 },	// wood
    277 	{"cardboard",	0,	SURFTYPE_CARDBOARD,	0 },	// cardboard
    278 	{"liquid",		0,	SURFTYPE_LIQUID,	0 },	// liquid
    279 	{"glass",		0,	SURFTYPE_GLASS,		0 },	// glass
    280 	{"plastic",		0,	SURFTYPE_PLASTIC,	0 },	// plastic
    281 	{"ricochet",	0,	SURFTYPE_RICOCHET,	0 },	// behaves like metal but causes a ricochet sound
    282 
    283 	// unassigned surface types
    284 	{"surftype10",	0,	SURFTYPE_10,	0 },
    285 	{"surftype11",	0,	SURFTYPE_11,	0 },
    286 	{"surftype12",	0,	SURFTYPE_12,	0 },
    287 	{"surftype13",	0,	SURFTYPE_13,	0 },
    288 	{"surftype14",	0,	SURFTYPE_14,	0 },
    289 	{"surftype15",	0,	SURFTYPE_15,	0 },
    290 };
    291 
    292 static const int numInfoParms = sizeof(infoParms) / sizeof (infoParms[0]);
    293 
    294 
    295 /*
    296 ===============
    297 idMaterial::CheckSurfaceParm
    298 
    299 See if the current token matches one of the surface parm bit flags
    300 ===============
    301 */
    302 bool idMaterial::CheckSurfaceParm( idToken *token ) {
    303 
    304 	for ( int i = 0 ; i < numInfoParms ; i++ ) {
    305 		if ( !token->Icmp( infoParms[i].name ) ) {
    306 			if ( infoParms[i].surfaceFlags & SURF_TYPE_MASK ) {
    307 				// ensure we only have one surface type set
    308 				surfaceFlags &= ~SURF_TYPE_MASK;
    309 			}
    310 			surfaceFlags |= infoParms[i].surfaceFlags;
    311 			contentFlags |= infoParms[i].contents;
    312 			if ( infoParms[i].clearSolid ) {
    313 				contentFlags &= ~CONTENTS_SOLID;
    314 			}
    315 			return true;
    316 		}
    317 	}
    318 	return false;
    319 }
    320 
    321 /*
    322 ===============
    323 idMaterial::MatchToken
    324 
    325 Sets defaultShader and returns false if the next token doesn't match
    326 ===============
    327 */
    328 bool idMaterial::MatchToken( idLexer &src, const char *match ) {
    329 	if ( !src.ExpectTokenString( match ) ) {
    330 		SetMaterialFlag( MF_DEFAULTED );
    331 		return false;
    332 	}
    333 	return true;
    334 }
    335 
    336 /*
    337 =================
    338 idMaterial::ParseSort
    339 =================
    340 */
    341 void idMaterial::ParseSort( idLexer &src ) {
    342 	idToken token;
    343 
    344 	if ( !src.ReadTokenOnLine( &token ) ) {
    345 		src.Warning( "missing sort parameter" );
    346 		SetMaterialFlag( MF_DEFAULTED );
    347 		return;
    348 	}
    349 
    350 	if ( !token.Icmp( "subview" ) ) {
    351 		sort = SS_SUBVIEW;
    352 	} else if ( !token.Icmp( "opaque" ) ) {
    353 		sort = SS_OPAQUE;
    354 	}else if ( !token.Icmp( "decal" ) ) {
    355 		sort = SS_DECAL;
    356 	} else if ( !token.Icmp( "far" ) ) {
    357 		sort = SS_FAR;
    358 	} else if ( !token.Icmp( "medium" ) ) {
    359 		sort = SS_MEDIUM;
    360 	} else if ( !token.Icmp( "close" ) ) {
    361 		sort = SS_CLOSE;
    362 	} else if ( !token.Icmp( "almostNearest" ) ) {
    363 		sort = SS_ALMOST_NEAREST;
    364 	} else if ( !token.Icmp( "nearest" ) ) {
    365 		sort = SS_NEAREST;
    366 	} else if ( !token.Icmp( "postProcess" ) ) {
    367 		sort = SS_POST_PROCESS;
    368 	} else if ( !token.Icmp( "portalSky" ) ) {
    369 		sort = SS_PORTAL_SKY;
    370 	} else {
    371 		sort = atof( token );
    372 	}
    373 }
    374 
    375 /*
    376 =================
    377 idMaterial::ParseStereoEye
    378 =================
    379 */
    380 void idMaterial::ParseStereoEye( idLexer &src ) {
    381 	idToken token;
    382 
    383 	if ( !src.ReadTokenOnLine( &token ) ) {
    384 		src.Warning( "missing eye parameter" );
    385 		SetMaterialFlag( MF_DEFAULTED );
    386 		return;
    387 	}
    388 
    389 	if ( !token.Icmp( "left" ) ) {
    390 		stereoEye = -1;
    391 	} else if ( !token.Icmp( "right" ) ) {
    392 		stereoEye = 1;
    393 	} else {
    394 		stereoEye = 0;
    395 	}
    396 }
    397 
    398 /*
    399 =================
    400 idMaterial::ParseDecalInfo
    401 =================
    402 */
    403 void idMaterial::ParseDecalInfo( idLexer &src ) {
    404 	idToken token;
    405 
    406 	decalInfo.stayTime = src.ParseFloat() * 1000;
    407 	decalInfo.fadeTime = src.ParseFloat() * 1000;
    408 	float	start[4], end[4];
    409 	src.Parse1DMatrix( 4, start );
    410 	src.Parse1DMatrix( 4, end );
    411 	for ( int i = 0 ; i < 4 ; i++ ) {
    412 		decalInfo.start[i] = start[i];
    413 		decalInfo.end[i] = end[i];
    414 	}
    415 }
    416 
    417 /*
    418 =============
    419 idMaterial::GetExpressionConstant
    420 =============
    421 */
    422 int idMaterial::GetExpressionConstant( float f ) {
    423 	int		i;
    424 
    425 	for ( i = EXP_REG_NUM_PREDEFINED ; i < numRegisters ; i++ ) {
    426 		if ( !pd->registerIsTemporary[i] && pd->shaderRegisters[i] == f ) {
    427 			return i;
    428 		}
    429 	}
    430 	if ( numRegisters == MAX_EXPRESSION_REGISTERS ) {
    431 		common->Warning( "GetExpressionConstant: material '%s' hit MAX_EXPRESSION_REGISTERS", GetName() );
    432 		SetMaterialFlag( MF_DEFAULTED );
    433 		return 0;
    434 	}
    435 	pd->registerIsTemporary[i] = false;
    436 	pd->shaderRegisters[i] = f;
    437 	numRegisters++;
    438 
    439 	return i;
    440 }
    441 
    442 /*
    443 =============
    444 idMaterial::GetExpressionTemporary
    445 =============
    446 */
    447 int idMaterial::GetExpressionTemporary() {
    448 	if ( numRegisters >= MAX_EXPRESSION_REGISTERS ) {
    449 		common->Warning( "GetExpressionTemporary: material '%s' hit MAX_EXPRESSION_REGISTERS", GetName() );
    450 		SetMaterialFlag( MF_DEFAULTED );
    451 		return 0;
    452 	}
    453 	pd->registerIsTemporary[numRegisters] = true;
    454 	numRegisters++;
    455 	return numRegisters - 1;
    456 }
    457 
    458 /*
    459 =============
    460 idMaterial::GetExpressionOp
    461 =============
    462 */
    463 expOp_t	*idMaterial::GetExpressionOp() {
    464 	if ( numOps == MAX_EXPRESSION_OPS ) {
    465 		common->Warning( "GetExpressionOp: material '%s' hit MAX_EXPRESSION_OPS", GetName() );
    466 		SetMaterialFlag( MF_DEFAULTED );
    467 		return &pd->shaderOps[0];
    468 	}
    469 
    470 	return &pd->shaderOps[numOps++];
    471 }
    472 
    473 /*
    474 =================
    475 idMaterial::EmitOp
    476 =================
    477 */
    478 int idMaterial::EmitOp( int a, int b, expOpType_t opType ) {
    479 	expOp_t	*op;
    480 
    481 	// optimize away identity operations
    482 	if ( opType == OP_TYPE_ADD ) {
    483 		if ( !pd->registerIsTemporary[a] && pd->shaderRegisters[a] == 0 ) {
    484 			return b;
    485 		}
    486 		if ( !pd->registerIsTemporary[b] && pd->shaderRegisters[b] == 0 ) {
    487 			return a;
    488 		}
    489 		if ( !pd->registerIsTemporary[a] && !pd->registerIsTemporary[b] ) {
    490 			return GetExpressionConstant( pd->shaderRegisters[a] + pd->shaderRegisters[b] );
    491 		}
    492 	}
    493 	if ( opType == OP_TYPE_MULTIPLY ) {
    494 		if ( !pd->registerIsTemporary[a] && pd->shaderRegisters[a] == 1 ) {
    495 			return b;
    496 		}
    497 		if ( !pd->registerIsTemporary[a] && pd->shaderRegisters[a] == 0 ) {
    498 			return a;
    499 		}
    500 		if ( !pd->registerIsTemporary[b] && pd->shaderRegisters[b] == 1 ) {
    501 			return a;
    502 		}
    503 		if ( !pd->registerIsTemporary[b] && pd->shaderRegisters[b] == 0 ) {
    504 			return b;
    505 		}
    506 		if ( !pd->registerIsTemporary[a] && !pd->registerIsTemporary[b] ) {
    507 			return GetExpressionConstant( pd->shaderRegisters[a] * pd->shaderRegisters[b] );
    508 		}
    509 	}
    510 
    511 	op = GetExpressionOp();
    512 	op->opType = opType;
    513 	op->a = a;
    514 	op->b = b;
    515 	op->c = GetExpressionTemporary();
    516 
    517 	return op->c;
    518 }
    519 
    520 /*
    521 =================
    522 idMaterial::ParseEmitOp
    523 =================
    524 */
    525 int idMaterial::ParseEmitOp( idLexer &src, int a, expOpType_t opType, int priority ) {
    526 	int		b;
    527 
    528 	b = ParseExpressionPriority( src, priority );
    529 	return EmitOp( a, b, opType );
    530 }
    531 
    532 /*
    533 =================
    534 idMaterial::ParseTerm
    535 
    536 Returns a register index
    537 =================
    538 */
    539 int idMaterial::ParseTerm( idLexer &src ) {
    540 	idToken token;
    541 	int		a, b;
    542 
    543 	src.ReadToken( &token );
    544 
    545 	if ( token == "(" ) {
    546 		a = ParseExpression( src );
    547 		MatchToken( src, ")" );
    548 		return a;
    549 	}
    550 
    551 	if ( !token.Icmp( "time" ) ) {
    552 		pd->registersAreConstant = false;
    553 		return EXP_REG_TIME;
    554 	}
    555 	if ( !token.Icmp( "parm0" ) ) {
    556 		pd->registersAreConstant = false;
    557 		return EXP_REG_PARM0;
    558 	}
    559 	if ( !token.Icmp( "parm1" ) ) {
    560 		pd->registersAreConstant = false;
    561 		return EXP_REG_PARM1;
    562 	}
    563 	if ( !token.Icmp( "parm2" ) ) {
    564 		pd->registersAreConstant = false;
    565 		return EXP_REG_PARM2;
    566 	}
    567 	if ( !token.Icmp( "parm3" ) ) {
    568 		pd->registersAreConstant = false;
    569 		return EXP_REG_PARM3;
    570 	}
    571 	if ( !token.Icmp( "parm4" ) ) {
    572 		pd->registersAreConstant = false;
    573 		return EXP_REG_PARM4;
    574 	}
    575 	if ( !token.Icmp( "parm5" ) ) {
    576 		pd->registersAreConstant = false;
    577 		return EXP_REG_PARM5;
    578 	}
    579 	if ( !token.Icmp( "parm6" ) ) {
    580 		pd->registersAreConstant = false;
    581 		return EXP_REG_PARM6;
    582 	}
    583 	if ( !token.Icmp( "parm7" ) ) {
    584 		pd->registersAreConstant = false;
    585 		return EXP_REG_PARM7;
    586 	}
    587 	if ( !token.Icmp( "parm8" ) ) {
    588 		pd->registersAreConstant = false;
    589 		return EXP_REG_PARM8;
    590 	}
    591 	if ( !token.Icmp( "parm9" ) ) {
    592 		pd->registersAreConstant = false;
    593 		return EXP_REG_PARM9;
    594 	}
    595 	if ( !token.Icmp( "parm10" ) ) {
    596 		pd->registersAreConstant = false;
    597 		return EXP_REG_PARM10;
    598 	}
    599 	if ( !token.Icmp( "parm11" ) ) {
    600 		pd->registersAreConstant = false;
    601 		return EXP_REG_PARM11;
    602 	}
    603 	if ( !token.Icmp( "global0" ) ) {
    604 		pd->registersAreConstant = false;
    605 		return EXP_REG_GLOBAL0;
    606 	}
    607 	if ( !token.Icmp( "global1" ) ) {
    608 		pd->registersAreConstant = false;
    609 		return EXP_REG_GLOBAL1;
    610 	}
    611 	if ( !token.Icmp( "global2" ) ) {
    612 		pd->registersAreConstant = false;
    613 		return EXP_REG_GLOBAL2;
    614 	}
    615 	if ( !token.Icmp( "global3" ) ) {
    616 		pd->registersAreConstant = false;
    617 		return EXP_REG_GLOBAL3;
    618 	}
    619 	if ( !token.Icmp( "global4" ) ) {
    620 		pd->registersAreConstant = false;
    621 		return EXP_REG_GLOBAL4;
    622 	}
    623 	if ( !token.Icmp( "global5" ) ) {
    624 		pd->registersAreConstant = false;
    625 		return EXP_REG_GLOBAL5;
    626 	}
    627 	if ( !token.Icmp( "global6" ) ) {
    628 		pd->registersAreConstant = false;
    629 		return EXP_REG_GLOBAL6;
    630 	}
    631 	if ( !token.Icmp( "global7" ) ) {
    632 		pd->registersAreConstant = false;
    633 		return EXP_REG_GLOBAL7;
    634 	}
    635 	if ( !token.Icmp( "fragmentPrograms" ) ) {
    636 		return 1.0f;
    637 	}
    638 
    639 	if ( !token.Icmp( "sound" ) ) {
    640 		pd->registersAreConstant = false;
    641 		return EmitOp( 0, 0, OP_TYPE_SOUND );
    642 	}
    643 
    644 	// parse negative numbers
    645 	if ( token == "-" ) {
    646 		src.ReadToken( &token );
    647 		if ( token.type == TT_NUMBER || token == "." ) {
    648 			return GetExpressionConstant( -(float) token.GetFloatValue() );
    649 		}
    650 		src.Warning( "Bad negative number '%s'", token.c_str() );
    651 		SetMaterialFlag( MF_DEFAULTED );
    652 		return 0;
    653 	}
    654 
    655 	if ( token.type == TT_NUMBER || token == "." || token == "-" ) {
    656 		return GetExpressionConstant( (float) token.GetFloatValue() );
    657 	}
    658 
    659 	// see if it is a table name
    660 	const idDeclTable *table = static_cast<const idDeclTable *>( declManager->FindType( DECL_TABLE, token.c_str(), false ) );
    661 	if ( !table ) {
    662 		src.Warning( "Bad term '%s'", token.c_str() );
    663 		SetMaterialFlag( MF_DEFAULTED );
    664 		return 0;
    665 	}
    666 
    667 	// parse a table expression
    668 	MatchToken( src, "[" );
    669 
    670 	b = ParseExpression( src );
    671 
    672 	MatchToken( src, "]" );
    673 
    674 	return EmitOp( table->Index(), b, OP_TYPE_TABLE );
    675 }
    676 
    677 /*
    678 =================
    679 idMaterial::ParseExpressionPriority
    680 
    681 Returns a register index
    682 =================
    683 */
    684 #define	TOP_PRIORITY 4
    685 int idMaterial::ParseExpressionPriority( idLexer &src, int priority ) {
    686 	idToken token;
    687 	int		a;
    688 
    689 	if ( priority == 0 ) {
    690 		return ParseTerm( src );
    691 	}
    692 
    693 	a = ParseExpressionPriority( src, priority - 1 );
    694 
    695 	if ( TestMaterialFlag( MF_DEFAULTED ) ) {	// we have a parse error
    696 		return 0;
    697 	}
    698 
    699 	if ( !src.ReadToken( &token ) ) {
    700 		// we won't get EOF in a real file, but we can
    701 		// when parsing from generated strings
    702 		return a;
    703 	}
    704 
    705 	if ( priority == 1 && token == "*" ) {
    706 		return ParseEmitOp( src, a, OP_TYPE_MULTIPLY, priority );
    707 	}
    708 	if ( priority == 1 && token == "/" ) {
    709 		return ParseEmitOp( src, a, OP_TYPE_DIVIDE, priority );
    710 	}
    711 	if ( priority == 1 && token == "%" ) {	// implied truncate both to integer
    712 		return ParseEmitOp( src, a, OP_TYPE_MOD, priority );
    713 	}
    714 	if ( priority == 2 && token == "+" ) {
    715 		return ParseEmitOp( src, a, OP_TYPE_ADD, priority );
    716 	}
    717 	if ( priority == 2 && token == "-" ) {
    718 		return ParseEmitOp( src, a, OP_TYPE_SUBTRACT, priority );
    719 	}
    720 	if ( priority == 3 && token == ">" ) {
    721 		return ParseEmitOp( src, a, OP_TYPE_GT, priority );
    722 	}
    723 	if ( priority == 3 && token == ">=" ) {
    724 		return ParseEmitOp( src, a, OP_TYPE_GE, priority );
    725 	}
    726 	if ( priority == 3 && token == "<" ) {
    727 		return ParseEmitOp( src, a, OP_TYPE_LT, priority );
    728 	}
    729 	if ( priority == 3 && token == "<=" ) {
    730 		return ParseEmitOp( src, a, OP_TYPE_LE, priority );
    731 	}
    732 	if ( priority == 3 && token == "==" ) {
    733 		return ParseEmitOp( src, a, OP_TYPE_EQ, priority );
    734 	}
    735 	if ( priority == 3 && token == "!=" ) {
    736 		return ParseEmitOp( src, a, OP_TYPE_NE, priority );
    737 	}
    738 	if ( priority == 4 && token == "&&" ) {
    739 		return ParseEmitOp( src, a, OP_TYPE_AND, priority );
    740 	}
    741 	if ( priority == 4 && token == "||" ) {
    742 		return ParseEmitOp( src, a, OP_TYPE_OR, priority );
    743 	}
    744 
    745 	// assume that anything else terminates the expression
    746 	// not too robust error checking...
    747 
    748 	src.UnreadToken( &token );
    749 
    750 	return a;
    751 }
    752 
    753 /*
    754 =================
    755 idMaterial::ParseExpression
    756 
    757 Returns a register index
    758 =================
    759 */
    760 int idMaterial::ParseExpression( idLexer &src ) {
    761 	return ParseExpressionPriority( src, TOP_PRIORITY );
    762 }
    763 
    764 
    765 /*
    766 ===============
    767 idMaterial::ClearStage
    768 ===============
    769 */
    770 void idMaterial::ClearStage( shaderStage_t *ss ) {
    771 	ss->drawStateBits = 0;
    772 	ss->conditionRegister = GetExpressionConstant( 1 );
    773 	ss->color.registers[0] =
    774 	ss->color.registers[1] =
    775 	ss->color.registers[2] =
    776 	ss->color.registers[3] = GetExpressionConstant( 1 );
    777 }
    778 
    779 /*
    780 ===============
    781 idMaterial::NameToSrcBlendMode
    782 ===============
    783 */
    784 int idMaterial::NameToSrcBlendMode( const idStr &name ) {
    785 	if ( !name.Icmp( "GL_ONE" ) ) {
    786 		return GLS_SRCBLEND_ONE;
    787 	} else if ( !name.Icmp( "GL_ZERO" ) ) {
    788 		return GLS_SRCBLEND_ZERO;
    789 	} else if ( !name.Icmp( "GL_DST_COLOR" ) ) {
    790 		return GLS_SRCBLEND_DST_COLOR;
    791 	} else if ( !name.Icmp( "GL_ONE_MINUS_DST_COLOR" ) ) {
    792 		return GLS_SRCBLEND_ONE_MINUS_DST_COLOR;
    793 	} else if ( !name.Icmp( "GL_SRC_ALPHA" ) ) {
    794 		return GLS_SRCBLEND_SRC_ALPHA;
    795 	} else if ( !name.Icmp( "GL_ONE_MINUS_SRC_ALPHA" ) ) {
    796 		return GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA;
    797 	} else if ( !name.Icmp( "GL_DST_ALPHA" ) ) {
    798 		return GLS_SRCBLEND_DST_ALPHA;
    799 	} else if ( !name.Icmp( "GL_ONE_MINUS_DST_ALPHA" ) ) {
    800 		return GLS_SRCBLEND_ONE_MINUS_DST_ALPHA;
    801 	} else if ( !name.Icmp( "GL_SRC_ALPHA_SATURATE" ) ) {
    802 		assert( 0 ); // FIX ME
    803 		return GLS_SRCBLEND_SRC_ALPHA;
    804 	}
    805 
    806 	common->Warning( "unknown blend mode '%s' in material '%s'", name.c_str(), GetName() );
    807 	SetMaterialFlag( MF_DEFAULTED );
    808 
    809 	return GLS_SRCBLEND_ONE;
    810 }
    811 
    812 /*
    813 ===============
    814 idMaterial::NameToDstBlendMode
    815 ===============
    816 */
    817 int idMaterial::NameToDstBlendMode( const idStr &name ) {
    818 	if ( !name.Icmp( "GL_ONE" ) ) {
    819 		return GLS_DSTBLEND_ONE;
    820 	} else if ( !name.Icmp( "GL_ZERO" ) ) {
    821 		return GLS_DSTBLEND_ZERO;
    822 	} else if ( !name.Icmp( "GL_SRC_ALPHA" ) ) {
    823 		return GLS_DSTBLEND_SRC_ALPHA;
    824 	} else if ( !name.Icmp( "GL_ONE_MINUS_SRC_ALPHA" ) ) {
    825 		return GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;
    826 	} else if ( !name.Icmp( "GL_DST_ALPHA" ) ) {
    827 		return GLS_DSTBLEND_DST_ALPHA;
    828 	} else if ( !name.Icmp( "GL_ONE_MINUS_DST_ALPHA" ) ) {
    829 		return GLS_DSTBLEND_ONE_MINUS_DST_ALPHA;
    830 	} else if ( !name.Icmp( "GL_SRC_COLOR" ) ) {
    831 		return GLS_DSTBLEND_SRC_COLOR;
    832 	} else if ( !name.Icmp( "GL_ONE_MINUS_SRC_COLOR" ) ) {
    833 		return GLS_DSTBLEND_ONE_MINUS_SRC_COLOR;
    834 	}
    835 
    836 	common->Warning( "unknown blend mode '%s' in material '%s'", name.c_str(), GetName() );
    837 	SetMaterialFlag( MF_DEFAULTED );
    838 
    839 	return GLS_DSTBLEND_ONE;
    840 }
    841 
    842 /*
    843 ================
    844 idMaterial::ParseBlend
    845 ================
    846 */
    847 void idMaterial::ParseBlend( idLexer &src, shaderStage_t *stage ) {
    848 	idToken token;
    849 	int		srcBlend, dstBlend;
    850 
    851 	if ( !src.ReadToken( &token ) ) {
    852 		return;
    853 	}
    854 
    855 	// blending combinations
    856 	if ( !token.Icmp( "blend" ) ) {
    857 		stage->drawStateBits = GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;
    858 		return;
    859 	}
    860 	if ( !token.Icmp( "add" ) ) {
    861 		stage->drawStateBits = GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE;
    862 		return;
    863 	}
    864 	if ( !token.Icmp( "filter" ) || !token.Icmp( "modulate" ) ) {
    865 		stage->drawStateBits = GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO;
    866 		return;
    867 	}
    868 	if (  !token.Icmp( "none" ) ) {
    869 		// none is used when defining an alpha mask that doesn't draw
    870 		stage->drawStateBits = GLS_SRCBLEND_ZERO | GLS_DSTBLEND_ONE;
    871 		return;
    872 	}
    873 	if ( !token.Icmp( "bumpmap" ) ) {
    874 		stage->lighting = SL_BUMP;
    875 		return;
    876 	}
    877 	if ( !token.Icmp( "diffusemap" ) ) {
    878 		stage->lighting = SL_DIFFUSE;
    879 		return;
    880 	}
    881 	if ( !token.Icmp( "specularmap" ) ) {
    882 		stage->lighting = SL_SPECULAR;
    883 		return;
    884 	}
    885 
    886 	srcBlend = NameToSrcBlendMode( token );
    887 
    888 	MatchToken( src, "," );
    889 	if ( !src.ReadToken( &token ) ) {
    890 		return;
    891 	}
    892 	dstBlend = NameToDstBlendMode( token );
    893 
    894 	stage->drawStateBits = srcBlend | dstBlend;
    895 }
    896 
    897 /*
    898 ================
    899 idMaterial::ParseVertexParm
    900 
    901 If there is a single value, it will be repeated across all elements
    902 If there are two values, 3 = 0.0, 4 = 1.0
    903 if there are three values, 4 = 1.0
    904 ================
    905 */
    906 void idMaterial::ParseVertexParm( idLexer &src, newShaderStage_t *newStage ) {
    907 	idToken				token;
    908 
    909 	src.ReadTokenOnLine( &token );
    910 	int	parm = token.GetIntValue();
    911 	if ( !token.IsNumeric() || parm < 0 || parm >= MAX_VERTEX_PARMS ) {
    912 		common->Warning( "bad vertexParm number\n" );
    913 		SetMaterialFlag( MF_DEFAULTED );
    914 		return;
    915 	}
    916 	if ( parm >= newStage->numVertexParms ) {
    917 		newStage->numVertexParms = parm+1;
    918 	}
    919 
    920 	newStage->vertexParms[parm][0] = ParseExpression( src );
    921 
    922 	src.ReadTokenOnLine( &token );
    923 	if ( !token[0] || token.Icmp( "," ) ) {
    924 		newStage->vertexParms[parm][1] =
    925 		newStage->vertexParms[parm][2] =
    926 		newStage->vertexParms[parm][3] = newStage->vertexParms[parm][0];
    927 		return;
    928 	}
    929 
    930 	newStage->vertexParms[parm][1] = ParseExpression( src );
    931 
    932 	src.ReadTokenOnLine( &token );
    933 	if ( !token[0] || token.Icmp( "," ) ) {
    934 		newStage->vertexParms[parm][2] = GetExpressionConstant( 0 );
    935 		newStage->vertexParms[parm][3] = GetExpressionConstant( 1 );
    936 		return;
    937 	}
    938 
    939 	newStage->vertexParms[parm][2] = ParseExpression( src );
    940 
    941 	src.ReadTokenOnLine( &token );
    942 	if ( !token[0] || token.Icmp( "," ) ) {
    943 		newStage->vertexParms[parm][3] = GetExpressionConstant( 1 );
    944 		return;
    945 	}
    946 
    947 	newStage->vertexParms[parm][3] = ParseExpression( src );
    948 }
    949 
    950 /*
    951 ================
    952 idMaterial::ParseVertexParm2
    953 ================
    954 */
    955 void idMaterial::ParseVertexParm2( idLexer &src, newShaderStage_t *newStage ) {
    956 	idToken	token;
    957 	src.ReadTokenOnLine( &token );
    958 	int	parm = token.GetIntValue();
    959 	if ( !token.IsNumeric() || parm < 0 || parm >= MAX_VERTEX_PARMS ) {
    960 		common->Warning( "bad vertexParm number\n" );
    961 		SetMaterialFlag( MF_DEFAULTED );
    962 		return;
    963 	}
    964 
    965 	if ( parm >= newStage->numVertexParms ) {
    966 		newStage->numVertexParms = parm+1;
    967 	}
    968 
    969 	newStage->vertexParms[parm][0] = ParseExpression( src );
    970 	MatchToken( src, "," );
    971 	newStage->vertexParms[parm][1] = ParseExpression( src );
    972 	MatchToken( src, "," );
    973 	newStage->vertexParms[parm][2] = ParseExpression( src );
    974 	MatchToken( src, "," );
    975 	newStage->vertexParms[parm][3] = ParseExpression( src );
    976 }
    977 
    978 
    979 /*
    980 ================
    981 idMaterial::ParseFragmentMap
    982 ================
    983 */
    984 void idMaterial::ParseFragmentMap( idLexer &src, newShaderStage_t *newStage ) {
    985 	const char			*str;
    986 	textureFilter_t		tf;
    987 	textureRepeat_t		trp;
    988 	textureUsage_t		td;
    989 	cubeFiles_t			cubeMap;
    990 	idToken				token;
    991 
    992 	tf = TF_DEFAULT;
    993 	trp = TR_REPEAT;
    994 	td = TD_DEFAULT;
    995 	cubeMap = CF_2D;
    996 
    997 	src.ReadTokenOnLine( &token );
    998 	int	unit = token.GetIntValue();
    999 	if ( !token.IsNumeric() || unit < 0 || unit >= MAX_FRAGMENT_IMAGES ) {
   1000 		common->Warning( "bad fragmentMap number\n" );
   1001 		SetMaterialFlag( MF_DEFAULTED );
   1002 		return;
   1003 	}
   1004 
   1005 	// unit 1 is the normal map.. make sure it gets flagged as the proper depth
   1006 	if ( unit == 1 ) {
   1007 		td = TD_BUMP;
   1008 	}
   1009 
   1010 	if ( unit >= newStage->numFragmentProgramImages ) {
   1011 		newStage->numFragmentProgramImages = unit+1;
   1012 	}
   1013 
   1014 	while( 1 ) {
   1015 		src.ReadTokenOnLine( &token );
   1016 
   1017 		if ( !token.Icmp( "cubeMap" ) ) {
   1018 			cubeMap = CF_NATIVE;
   1019 			continue;
   1020 		}
   1021 		if ( !token.Icmp( "cameraCubeMap" ) ) {
   1022 			cubeMap = CF_CAMERA;
   1023 			continue;
   1024 		}
   1025 		if ( !token.Icmp( "nearest" ) ) {
   1026 			tf = TF_NEAREST;
   1027 			continue;
   1028 		}
   1029 		if ( !token.Icmp( "linear" ) ) {
   1030 			tf = TF_LINEAR;
   1031 			continue;
   1032 		}
   1033 		if ( !token.Icmp( "clamp" ) ) {
   1034 			trp = TR_CLAMP;
   1035 			continue;
   1036 		}
   1037 		if ( !token.Icmp( "noclamp" ) ) {
   1038 			trp = TR_REPEAT;
   1039 			continue;
   1040 		}
   1041 		if ( !token.Icmp( "zeroclamp" ) ) {
   1042 			trp = TR_CLAMP_TO_ZERO;
   1043 			continue;
   1044 		}
   1045 		if ( !token.Icmp( "alphazeroclamp" ) ) {
   1046 			trp = TR_CLAMP_TO_ZERO_ALPHA;
   1047 			continue;
   1048 		}
   1049 		if ( !token.Icmp( "forceHighQuality" ) ) {
   1050 			continue;
   1051 		}
   1052 		if ( !token.Icmp( "highquality" ) ) {
   1053 			continue;
   1054 		}
   1055 		if ( !token.Icmp( "uncompressed" ) ) {
   1056 			continue;
   1057 		}
   1058 		if ( !token.Icmp( "nopicmip" ) ) {
   1059 			continue;
   1060 		}
   1061 
   1062 		// assume anything else is the image name
   1063 		src.UnreadToken( &token );
   1064 		break;
   1065 	}
   1066 	str = R_ParsePastImageProgram( src );
   1067 
   1068 	newStage->fragmentProgramImages[unit] = 
   1069 		globalImages->ImageFromFile( str, tf, trp, td, cubeMap );
   1070 	if ( !newStage->fragmentProgramImages[unit] ) {
   1071 		newStage->fragmentProgramImages[unit] = globalImages->defaultImage;
   1072 	}
   1073 }
   1074 
   1075 /*
   1076 ===============
   1077 idMaterial::MultiplyTextureMatrix
   1078 ===============
   1079 */
   1080 void idMaterial::MultiplyTextureMatrix( textureStage_t *ts, int registers[2][3] ) {
   1081 	int		old[2][3];
   1082 
   1083 	if ( !ts->hasMatrix ) {
   1084 		ts->hasMatrix = true;
   1085 		memcpy( ts->matrix, registers, sizeof( ts->matrix ) );
   1086 		return;
   1087 	}
   1088 
   1089 	memcpy( old, ts->matrix, sizeof( old ) );
   1090 
   1091 	// multiply the two maticies
   1092 	ts->matrix[0][0] = EmitOp(
   1093 							EmitOp( old[0][0], registers[0][0], OP_TYPE_MULTIPLY ),
   1094 							EmitOp( old[0][1], registers[1][0], OP_TYPE_MULTIPLY ), OP_TYPE_ADD );
   1095 	ts->matrix[0][1] = EmitOp(
   1096 							EmitOp( old[0][0], registers[0][1], OP_TYPE_MULTIPLY ),
   1097 							EmitOp( old[0][1], registers[1][1], OP_TYPE_MULTIPLY ), OP_TYPE_ADD );
   1098 	ts->matrix[0][2] = EmitOp( 
   1099 							EmitOp(
   1100 								EmitOp( old[0][0], registers[0][2], OP_TYPE_MULTIPLY ),
   1101 								EmitOp( old[0][1], registers[1][2], OP_TYPE_MULTIPLY ), OP_TYPE_ADD ),
   1102 							old[0][2], OP_TYPE_ADD );
   1103 
   1104 	ts->matrix[1][0] = EmitOp(
   1105 							EmitOp( old[1][0], registers[0][0], OP_TYPE_MULTIPLY ),
   1106 							EmitOp( old[1][1], registers[1][0], OP_TYPE_MULTIPLY ), OP_TYPE_ADD );
   1107 	ts->matrix[1][1] = EmitOp(
   1108 							EmitOp( old[1][0], registers[0][1], OP_TYPE_MULTIPLY ),
   1109 							EmitOp( old[1][1], registers[1][1], OP_TYPE_MULTIPLY ), OP_TYPE_ADD );
   1110 	ts->matrix[1][2] = EmitOp( 
   1111 							EmitOp(
   1112 								EmitOp( old[1][0], registers[0][2], OP_TYPE_MULTIPLY ),
   1113 								EmitOp( old[1][1], registers[1][2], OP_TYPE_MULTIPLY ), OP_TYPE_ADD ),
   1114 							old[1][2], OP_TYPE_ADD );
   1115 
   1116 }
   1117 
   1118 /*
   1119 =================
   1120 idMaterial::ParseStage
   1121 
   1122 An open brace has been parsed
   1123 
   1124 
   1125 {
   1126 	if <expression>
   1127 	map <imageprogram>
   1128 	"nearest" "linear" "clamp" "zeroclamp" "uncompressed" "highquality" "nopicmip"
   1129 	scroll, scale, rotate
   1130 }
   1131 
   1132 =================
   1133 */
   1134 void idMaterial::ParseStage( idLexer &src, const textureRepeat_t trpDefault ) {
   1135 	idToken				token;
   1136 	const char			*str;
   1137 	shaderStage_t		*ss;
   1138 	textureStage_t		*ts;
   1139 	textureFilter_t		tf;
   1140 	textureRepeat_t		trp;
   1141 	textureUsage_t		td;
   1142 	cubeFiles_t			cubeMap;
   1143 	char				imageName[MAX_IMAGE_NAME];
   1144 	int					a, b;
   1145 	int					matrix[2][3];
   1146 	newShaderStage_t	newStage;
   1147 
   1148 	if ( numStages >= MAX_SHADER_STAGES ) {
   1149 		SetMaterialFlag( MF_DEFAULTED );
   1150 		common->Warning( "material '%s' exceeded %i stages", GetName(), MAX_SHADER_STAGES );
   1151 	}
   1152 
   1153 	tf = TF_DEFAULT;
   1154 	trp = trpDefault;
   1155 	td = TD_DEFAULT;
   1156 	cubeMap = CF_2D;
   1157 
   1158 	imageName[0] = 0;
   1159 
   1160 	memset( &newStage, 0, sizeof( newStage ) );
   1161 	newStage.glslProgram = -1;
   1162 
   1163 	ss = &pd->parseStages[numStages];
   1164 	ts = &ss->texture;
   1165 
   1166 	ClearStage( ss );
   1167 
   1168 	while ( 1 ) {
   1169 		if ( TestMaterialFlag( MF_DEFAULTED ) ) {	// we have a parse error
   1170 			return;
   1171 		}
   1172 		if ( !src.ExpectAnyToken( &token ) ) {
   1173 			SetMaterialFlag( MF_DEFAULTED );
   1174 			return;
   1175 		}
   1176 
   1177 		// the close brace for the entire material ends the draw block
   1178 		if ( token == "}" ) {
   1179 			break;
   1180 		}
   1181 
   1182 		//BSM Nerve: Added for stage naming in the material editor
   1183 		if( !token.Icmp( "name") ) {
   1184 			src.SkipRestOfLine();
   1185 			continue;
   1186 		}
   1187 
   1188 		// image options
   1189 		if ( !token.Icmp( "blend" ) ) {
   1190 			ParseBlend( src, ss );
   1191 			continue;
   1192 		}
   1193 
   1194 		if (  !token.Icmp( "map" ) ) {
   1195 			str = R_ParsePastImageProgram( src );
   1196 			idStr::Copynz( imageName, str, sizeof( imageName ) );
   1197 			continue;
   1198 		}
   1199 
   1200 		if (  !token.Icmp( "remoteRenderMap" ) ) {
   1201 			ts->dynamic = DI_REMOTE_RENDER;
   1202 			ts->width = src.ParseInt();
   1203 			ts->height = src.ParseInt();
   1204 			continue;
   1205 		}
   1206 
   1207 		if (  !token.Icmp( "mirrorRenderMap" ) ) {
   1208 			ts->dynamic = DI_MIRROR_RENDER;
   1209 			ts->width = src.ParseInt();
   1210 			ts->height = src.ParseInt();
   1211 			ts->texgen = TG_SCREEN;
   1212 			continue;
   1213 		}
   1214 
   1215 		if (  !token.Icmp( "xrayRenderMap" ) ) {
   1216 			ts->dynamic = DI_XRAY_RENDER;
   1217 			ts->width = src.ParseInt();
   1218 			ts->height = src.ParseInt();
   1219 			ts->texgen = TG_SCREEN;
   1220 			continue;
   1221 		}
   1222 		if (  !token.Icmp( "screen" ) ) {
   1223 			ts->texgen = TG_SCREEN;
   1224 			continue;
   1225 		}
   1226 		if (  !token.Icmp( "screen2" ) ) {
   1227 			ts->texgen = TG_SCREEN2;
   1228 			continue;
   1229 		}
   1230 		if (  !token.Icmp( "glassWarp" ) ) {
   1231 			ts->texgen = TG_GLASSWARP;
   1232 			continue;
   1233 		}
   1234 
   1235 		if ( !token.Icmp( "videomap" ) ) {
   1236 			// note that videomaps will always be in clamp mode, so texture
   1237 			// coordinates had better be in the 0 to 1 range
   1238 			if ( !src.ReadToken( &token ) ) {
   1239 				common->Warning( "missing parameter for 'videoMap' keyword in material '%s'", GetName() );
   1240 				continue;
   1241 			}
   1242 			bool loop = false;
   1243 			if ( !token.Icmp( "loop" ) ) {
   1244 				loop = true;
   1245 				if ( !src.ReadToken( &token ) ) {
   1246 					common->Warning( "missing parameter for 'videoMap' keyword in material '%s'", GetName() );
   1247 					continue;
   1248 				}
   1249 			}
   1250 			ts->cinematic = idCinematic::Alloc();
   1251 			ts->cinematic->InitFromFile( token.c_str(), loop );
   1252 			continue;
   1253 		}
   1254 
   1255 		if ( !token.Icmp( "soundmap" ) ) {
   1256 			if ( !src.ReadToken( &token ) ) {
   1257 				common->Warning( "missing parameter for 'soundmap' keyword in material '%s'", GetName() );
   1258 				continue;
   1259 			}
   1260 			ts->cinematic = new (TAG_MATERIAL) idSndWindow();
   1261 			ts->cinematic->InitFromFile( token.c_str(), true );
   1262 			continue;
   1263 		}
   1264 
   1265 		if ( !token.Icmp( "cubeMap" ) ) {
   1266 			str = R_ParsePastImageProgram( src );
   1267 			idStr::Copynz( imageName, str, sizeof( imageName ) );
   1268 			cubeMap = CF_NATIVE;
   1269 			continue;
   1270 		}
   1271 
   1272 		if ( !token.Icmp( "cameraCubeMap" ) ) {
   1273 			str = R_ParsePastImageProgram( src );
   1274 			idStr::Copynz( imageName, str, sizeof( imageName ) );
   1275 			cubeMap = CF_CAMERA;
   1276 			continue;
   1277 		}
   1278 
   1279 		if ( !token.Icmp( "ignoreAlphaTest" ) ) {
   1280 			ss->ignoreAlphaTest = true;
   1281 			continue;
   1282 		}
   1283 		if ( !token.Icmp( "nearest" ) ) {
   1284 			tf = TF_NEAREST;
   1285 			continue;
   1286 		}
   1287 		if ( !token.Icmp( "linear" ) ) {
   1288 			tf = TF_LINEAR;
   1289 			continue;
   1290 		}
   1291 		if ( !token.Icmp( "clamp" ) ) {
   1292 			trp = TR_CLAMP;
   1293 			continue;
   1294 		}
   1295 		if ( !token.Icmp( "noclamp" ) ) {
   1296 			trp = TR_REPEAT;
   1297 			continue;
   1298 		}
   1299 		if ( !token.Icmp( "zeroclamp" ) ) {
   1300 			trp = TR_CLAMP_TO_ZERO;
   1301 			continue;
   1302 		}
   1303 		if ( !token.Icmp( "alphazeroclamp" ) ) {
   1304 			trp = TR_CLAMP_TO_ZERO_ALPHA;
   1305 			continue;
   1306 		}
   1307 		if ( !token.Icmp( "forceHighQuality" ) ) {
   1308 			continue;
   1309 		}
   1310 		if ( !token.Icmp( "highquality" ) ) {
   1311 			continue;
   1312 		}
   1313 		if ( !token.Icmp( "uncompressed" ) ) {
   1314 			continue;
   1315 		}
   1316 		if ( !token.Icmp( "nopicmip" ) ) {
   1317 			continue;
   1318 		}
   1319 		if ( !token.Icmp( "vertexColor" ) ) {
   1320 			ss->vertexColor = SVC_MODULATE;
   1321 			continue;
   1322 		}
   1323 		if ( !token.Icmp( "inverseVertexColor" ) ) {
   1324 			ss->vertexColor = SVC_INVERSE_MODULATE;
   1325 			continue;
   1326 		}
   1327 
   1328 		// privatePolygonOffset
   1329 		else if ( !token.Icmp( "privatePolygonOffset" ) ) {
   1330 			if ( !src.ReadTokenOnLine( &token ) ) {
   1331 				ss->privatePolygonOffset = 1;
   1332 				continue;
   1333 			}
   1334 			// explict larger (or negative) offset
   1335 			src.UnreadToken( &token );
   1336 			ss->privatePolygonOffset = src.ParseFloat();
   1337 			continue;
   1338 		}
   1339 
   1340 		// texture coordinate generation
   1341 		if ( !token.Icmp( "texGen" ) ) {
   1342 			src.ExpectAnyToken( &token );
   1343 			if ( !token.Icmp( "normal" ) ) {
   1344 				ts->texgen = TG_DIFFUSE_CUBE;
   1345 			} else if ( !token.Icmp( "reflect" ) ) {
   1346 				ts->texgen = TG_REFLECT_CUBE;
   1347 			} else if ( !token.Icmp( "skybox" ) ) {
   1348 				ts->texgen = TG_SKYBOX_CUBE;
   1349 			} else if ( !token.Icmp( "wobbleSky" ) ) {
   1350 				ts->texgen = TG_WOBBLESKY_CUBE;
   1351 				texGenRegisters[0] = ParseExpression( src );
   1352 				texGenRegisters[1] = ParseExpression( src );
   1353 				texGenRegisters[2] = ParseExpression( src );
   1354 			} else {
   1355 				common->Warning( "bad texGen '%s' in material %s", token.c_str(), GetName() );
   1356 				SetMaterialFlag( MF_DEFAULTED );
   1357 			}
   1358 			continue;
   1359 		}
   1360 		if ( !token.Icmp( "scroll" ) || !token.Icmp( "translate" ) ) {
   1361 			a = ParseExpression( src );
   1362 			MatchToken( src, "," );
   1363 			b = ParseExpression( src );
   1364 			matrix[0][0] = GetExpressionConstant( 1 );
   1365 			matrix[0][1] = GetExpressionConstant( 0 );
   1366 			matrix[0][2] = a;
   1367 			matrix[1][0] = GetExpressionConstant( 0 );
   1368 			matrix[1][1] = GetExpressionConstant( 1 );
   1369 			matrix[1][2] = b;
   1370 
   1371 			MultiplyTextureMatrix( ts, matrix );
   1372 			continue;
   1373 		}
   1374 		if ( !token.Icmp( "scale" ) ) {
   1375 			a = ParseExpression( src );
   1376 			MatchToken( src, "," );
   1377 			b = ParseExpression( src );
   1378 			// this just scales without a centering
   1379 			matrix[0][0] = a;
   1380 			matrix[0][1] = GetExpressionConstant( 0 );
   1381 			matrix[0][2] = GetExpressionConstant( 0 );
   1382 			matrix[1][0] = GetExpressionConstant( 0 );
   1383 			matrix[1][1] = b;
   1384 			matrix[1][2] = GetExpressionConstant( 0 );
   1385 
   1386 			MultiplyTextureMatrix( ts, matrix );
   1387 			continue;
   1388 		}
   1389 		if ( !token.Icmp( "centerScale" ) ) {
   1390 			a = ParseExpression( src );
   1391 			MatchToken( src, "," );
   1392 			b = ParseExpression( src );
   1393 			// this subtracts 0.5, then scales, then adds 0.5
   1394 			matrix[0][0] = a;
   1395 			matrix[0][1] = GetExpressionConstant( 0 );
   1396 			matrix[0][2] = EmitOp( GetExpressionConstant( 0.5 ), EmitOp( GetExpressionConstant( 0.5 ), a, OP_TYPE_MULTIPLY ), OP_TYPE_SUBTRACT );
   1397 			matrix[1][0] = GetExpressionConstant( 0 );
   1398 			matrix[1][1] = b;
   1399 			matrix[1][2] = EmitOp( GetExpressionConstant( 0.5 ), EmitOp( GetExpressionConstant( 0.5 ), b, OP_TYPE_MULTIPLY ), OP_TYPE_SUBTRACT );
   1400 
   1401 			MultiplyTextureMatrix( ts, matrix );
   1402 			continue;
   1403 		}
   1404 		if ( !token.Icmp( "shear" ) ) {
   1405 			a = ParseExpression( src );
   1406 			MatchToken( src, "," );
   1407 			b = ParseExpression( src );
   1408 			// this subtracts 0.5, then shears, then adds 0.5
   1409 			matrix[0][0] = GetExpressionConstant( 1 );
   1410 			matrix[0][1] = a;
   1411 			matrix[0][2] = EmitOp( GetExpressionConstant( -0.5 ), a, OP_TYPE_MULTIPLY );
   1412 			matrix[1][0] = b;
   1413 			matrix[1][1] = GetExpressionConstant( 1 );
   1414 			matrix[1][2] = EmitOp( GetExpressionConstant( -0.5 ), b, OP_TYPE_MULTIPLY );
   1415 
   1416 			MultiplyTextureMatrix( ts, matrix );
   1417 			continue;
   1418 		}
   1419 		if ( !token.Icmp( "rotate" ) ) {
   1420 			const idDeclTable *table;
   1421 			int		sinReg, cosReg;
   1422 
   1423 			// in cycles
   1424 			a = ParseExpression( src );
   1425 
   1426 			table = static_cast<const idDeclTable *>( declManager->FindType( DECL_TABLE, "sinTable", false ) );
   1427 			if ( !table ) {
   1428 				common->Warning( "no sinTable for rotate defined" );
   1429 				SetMaterialFlag( MF_DEFAULTED );
   1430 				return;
   1431 			}
   1432 			sinReg = EmitOp( table->Index(), a, OP_TYPE_TABLE );
   1433 
   1434 			table = static_cast<const idDeclTable *>( declManager->FindType( DECL_TABLE, "cosTable", false ) );
   1435 			if ( !table ) {
   1436 				common->Warning( "no cosTable for rotate defined" );
   1437 				SetMaterialFlag( MF_DEFAULTED );
   1438 				return;
   1439 			}
   1440 			cosReg = EmitOp( table->Index(), a, OP_TYPE_TABLE );
   1441 
   1442 			// this subtracts 0.5, then rotates, then adds 0.5
   1443 			matrix[0][0] = cosReg;
   1444 			matrix[0][1] = EmitOp( GetExpressionConstant( 0 ), sinReg, OP_TYPE_SUBTRACT );
   1445 			matrix[0][2] = EmitOp( EmitOp( EmitOp( GetExpressionConstant( -0.5 ), cosReg, OP_TYPE_MULTIPLY ), 
   1446 										EmitOp( GetExpressionConstant( 0.5 ), sinReg, OP_TYPE_MULTIPLY ), OP_TYPE_ADD ),
   1447 										GetExpressionConstant( 0.5 ), OP_TYPE_ADD );
   1448 
   1449 			matrix[1][0] = sinReg;
   1450 			matrix[1][1] = cosReg;
   1451 			matrix[1][2] = EmitOp( EmitOp( EmitOp( GetExpressionConstant( -0.5 ), sinReg, OP_TYPE_MULTIPLY ), 
   1452 										EmitOp( GetExpressionConstant( -0.5 ), cosReg, OP_TYPE_MULTIPLY ), OP_TYPE_ADD ),
   1453 										GetExpressionConstant( 0.5 ), OP_TYPE_ADD );
   1454 
   1455 			MultiplyTextureMatrix( ts, matrix );
   1456 			continue;
   1457 		}
   1458 
   1459 		// color mask options
   1460 		if ( !token.Icmp( "maskRed" ) ) {
   1461 			ss->drawStateBits |= GLS_REDMASK;
   1462 			continue;
   1463 		}		
   1464 		if ( !token.Icmp( "maskGreen" ) ) {
   1465 			ss->drawStateBits |= GLS_GREENMASK;
   1466 			continue;
   1467 		}		
   1468 		if ( !token.Icmp( "maskBlue" ) ) {
   1469 			ss->drawStateBits |= GLS_BLUEMASK;
   1470 			continue;
   1471 		}		
   1472 		if ( !token.Icmp( "maskAlpha" ) ) {
   1473 			ss->drawStateBits |= GLS_ALPHAMASK;
   1474 			continue;
   1475 		}		
   1476 		if ( !token.Icmp( "maskColor" ) ) {
   1477 			ss->drawStateBits |= GLS_COLORMASK;
   1478 			continue;
   1479 		}		
   1480 		if ( !token.Icmp( "maskDepth" ) ) {
   1481 			ss->drawStateBits |= GLS_DEPTHMASK;
   1482 			continue;
   1483 		}		
   1484 		if ( !token.Icmp( "alphaTest" ) ) {
   1485 			ss->hasAlphaTest = true;
   1486 			ss->alphaTestRegister = ParseExpression( src );
   1487 			coverage = MC_PERFORATED;
   1488 			continue;
   1489 		}		
   1490 
   1491 		// shorthand for 2D modulated
   1492 		if ( !token.Icmp( "colored" ) ) {
   1493 			ss->color.registers[0] = EXP_REG_PARM0;
   1494 			ss->color.registers[1] = EXP_REG_PARM1;
   1495 			ss->color.registers[2] = EXP_REG_PARM2;
   1496 			ss->color.registers[3] = EXP_REG_PARM3;
   1497 			pd->registersAreConstant = false;
   1498 			continue;
   1499 		}
   1500 
   1501 		if ( !token.Icmp( "color" ) ) {
   1502 			ss->color.registers[0] = ParseExpression( src );
   1503 			MatchToken( src, "," );
   1504 			ss->color.registers[1] = ParseExpression( src );
   1505 			MatchToken( src, "," );
   1506 			ss->color.registers[2] = ParseExpression( src );
   1507 			MatchToken( src, "," );
   1508 			ss->color.registers[3] = ParseExpression( src );
   1509 			continue;
   1510 		}
   1511 		if ( !token.Icmp( "red" ) ) {
   1512 			ss->color.registers[0] = ParseExpression( src );
   1513 			continue;
   1514 		}
   1515 		if ( !token.Icmp( "green" ) ) {
   1516 			ss->color.registers[1] = ParseExpression( src );
   1517 			continue;
   1518 		}
   1519 		if ( !token.Icmp( "blue" ) ) {
   1520 			ss->color.registers[2] = ParseExpression( src );
   1521 			continue;
   1522 		}
   1523 		if ( !token.Icmp( "alpha" ) ) {
   1524 			ss->color.registers[3] = ParseExpression( src );
   1525 			continue;
   1526 		}
   1527 		if ( !token.Icmp( "rgb" ) ) {
   1528 			ss->color.registers[0] = ss->color.registers[1] = 
   1529 				ss->color.registers[2] = ParseExpression( src );
   1530 			continue;
   1531 		}
   1532 		if ( !token.Icmp( "rgba" ) ) {
   1533 			ss->color.registers[0] = ss->color.registers[1] = 
   1534 				ss->color.registers[2] = ss->color.registers[3] = ParseExpression( src );
   1535 			continue;
   1536 		}
   1537 
   1538 		if ( !token.Icmp( "if" ) ) {
   1539 			ss->conditionRegister = ParseExpression( src );
   1540 			continue;
   1541 		}
   1542 		if ( !token.Icmp( "program" ) ) {
   1543 			if ( src.ReadTokenOnLine( &token ) ) {
   1544 				newStage.vertexProgram = renderProgManager.FindVertexShader( token.c_str() );
   1545 				newStage.fragmentProgram = renderProgManager.FindFragmentShader( token.c_str() );
   1546 			}
   1547 			continue;
   1548 		}
   1549 		if ( !token.Icmp( "fragmentProgram" ) ) {
   1550 			if ( src.ReadTokenOnLine( &token ) ) {
   1551 				newStage.fragmentProgram = renderProgManager.FindFragmentShader( token.c_str() );
   1552 			}
   1553 			continue;
   1554 		}
   1555 		if ( !token.Icmp( "vertexProgram" ) ) {
   1556 			if ( src.ReadTokenOnLine( &token ) ) {
   1557 				newStage.vertexProgram = renderProgManager.FindVertexShader( token.c_str() );
   1558 			}
   1559 			continue;
   1560 		}
   1561 
   1562 		if ( !token.Icmp( "vertexParm2" ) ) {
   1563 			ParseVertexParm2( src, &newStage );
   1564 			continue;
   1565 		}
   1566 
   1567 		if ( !token.Icmp( "vertexParm" ) ) {
   1568 			ParseVertexParm( src, &newStage );
   1569 			continue;
   1570 		}
   1571 
   1572 		if (  !token.Icmp( "fragmentMap" ) ) {	
   1573 			ParseFragmentMap( src, &newStage );
   1574 			continue;
   1575 		}
   1576 
   1577 
   1578 		common->Warning( "unknown token '%s' in material '%s'", token.c_str(), GetName() );
   1579 		SetMaterialFlag( MF_DEFAULTED );
   1580 		return;
   1581 	}
   1582 
   1583 
   1584 	// if we are using newStage, allocate a copy of it
   1585 	if ( newStage.fragmentProgram || newStage.vertexProgram ) {
   1586 		newStage.glslProgram = renderProgManager.FindGLSLProgram( GetName(), newStage.vertexProgram, newStage.fragmentProgram );
   1587 		ss->newStage = (newShaderStage_t *)Mem_Alloc( sizeof( newStage ), TAG_MATERIAL );
   1588 		*(ss->newStage) = newStage;
   1589 	}
   1590 
   1591 	// successfully parsed a stage
   1592 	numStages++;
   1593 
   1594 	// select a compressed depth based on what the stage is
   1595 	if ( td == TD_DEFAULT ) {
   1596 		switch( ss->lighting ) {
   1597 		case SL_BUMP:
   1598 			td = TD_BUMP;
   1599 			break;
   1600 		case SL_DIFFUSE:
   1601 			td = TD_DIFFUSE;
   1602 			break;
   1603 		case SL_SPECULAR:
   1604 			td = TD_SPECULAR;
   1605 			break;
   1606 		default:
   1607 			break;
   1608 		}
   1609 	}
   1610 
   1611 	// create a new coverage stage on the fly - copy all data from the current stage
   1612 	if ( ( td == TD_DIFFUSE ) && ss->hasAlphaTest ) {
   1613 		// create new coverage stage
   1614 		shaderStage_t* newCoverageStage = &pd->parseStages[numStages];
   1615 		numStages++;
   1616 		// copy it
   1617 		*newCoverageStage = *ss;
   1618 		// toggle alphatest off for the current stage so it doesn't get called during the depth fill pass
   1619 		ss->hasAlphaTest = false;
   1620 		// toggle alpha test on for the coverage stage
   1621 		newCoverageStage->hasAlphaTest = true;
   1622 		newCoverageStage->lighting = SL_COVERAGE;
   1623 		textureStage_t* coverageTS = &newCoverageStage->texture;
   1624 
   1625 		// now load the image with all the parms we parsed for the coverage stage
   1626 		if ( imageName[0] ) {
   1627 			coverageTS->image = globalImages->ImageFromFile( imageName, tf, trp, TD_COVERAGE, cubeMap );
   1628 			if ( !coverageTS->image ) {
   1629 				coverageTS->image = globalImages->defaultImage;
   1630 			}
   1631 		} else if ( !coverageTS->cinematic && !coverageTS->dynamic && !ss->newStage ) {
   1632 			common->Warning( "material '%s' had stage with no image", GetName() );
   1633 			coverageTS->image = globalImages->defaultImage;
   1634 		}
   1635 	}
   1636 
   1637 	// now load the image with all the parms we parsed
   1638 	if ( imageName[0] ) {
   1639 		ts->image = globalImages->ImageFromFile( imageName, tf, trp, td, cubeMap );
   1640 		if ( !ts->image ) {
   1641 			ts->image = globalImages->defaultImage;
   1642 		}
   1643 	} else if ( !ts->cinematic && !ts->dynamic && !ss->newStage ) {
   1644 		common->Warning( "material '%s' had stage with no image", GetName() );
   1645 		ts->image = globalImages->defaultImage;
   1646 	}
   1647 }
   1648 
   1649 /*
   1650 ===============
   1651 idMaterial::ParseDeform
   1652 ===============
   1653 */
   1654 void idMaterial::ParseDeform( idLexer &src ) {
   1655 	idToken token;
   1656 
   1657 	if ( !src.ExpectAnyToken( &token ) ) {
   1658 		return;
   1659 	}
   1660 
   1661 	if ( !token.Icmp( "sprite" ) ) {
   1662 		deform = DFRM_SPRITE;
   1663 		cullType = CT_TWO_SIDED;
   1664 		SetMaterialFlag( MF_NOSHADOWS );
   1665 		return;
   1666 	}
   1667 	if ( !token.Icmp( "tube" ) ) {
   1668 		deform = DFRM_TUBE;
   1669 		cullType = CT_TWO_SIDED;
   1670 		SetMaterialFlag( MF_NOSHADOWS );
   1671 		return;
   1672 	}
   1673 	if ( !token.Icmp( "flare" ) ) {
   1674 		deform = DFRM_FLARE;
   1675 		cullType = CT_TWO_SIDED;
   1676 		deformRegisters[0] = ParseExpression( src );
   1677 		SetMaterialFlag( MF_NOSHADOWS );
   1678 		return;
   1679 	}
   1680 	if ( !token.Icmp( "expand" ) ) {
   1681 		deform = DFRM_EXPAND;
   1682 		deformRegisters[0] = ParseExpression( src );
   1683 		return;
   1684 	}
   1685 	if ( !token.Icmp( "move" ) ) {
   1686 		deform = DFRM_MOVE;
   1687 		deformRegisters[0] = ParseExpression( src );
   1688 		return;
   1689 	}
   1690 	if ( !token.Icmp( "turbulent" ) ) {
   1691 		deform = DFRM_TURB;
   1692 
   1693 		if ( !src.ExpectAnyToken( &token ) ) {
   1694 			src.Warning( "deform particle missing particle name" );
   1695 			SetMaterialFlag( MF_DEFAULTED );
   1696 			return;
   1697 		}
   1698 		deformDecl = declManager->FindType( DECL_TABLE, token.c_str(), true );
   1699 
   1700 		deformRegisters[0] = ParseExpression( src );
   1701 		deformRegisters[1] = ParseExpression( src );
   1702 		deformRegisters[2] = ParseExpression( src );
   1703 		return;
   1704 	}
   1705 	if ( !token.Icmp( "eyeBall" ) ) {
   1706 		deform = DFRM_EYEBALL;
   1707 		return;
   1708 	}
   1709 	if ( !token.Icmp( "particle" ) ) {
   1710 		deform = DFRM_PARTICLE;
   1711 		if ( !src.ExpectAnyToken( &token ) ) {
   1712 			src.Warning( "deform particle missing particle name" );
   1713 			SetMaterialFlag( MF_DEFAULTED );
   1714 			return;
   1715 		}
   1716 		deformDecl = declManager->FindType( DECL_PARTICLE, token.c_str(), true );
   1717 		return;
   1718 	}
   1719 	if ( !token.Icmp( "particle2" ) ) {
   1720 		deform = DFRM_PARTICLE2;
   1721 		if ( !src.ExpectAnyToken( &token ) ) {
   1722 			src.Warning( "deform particle missing particle name" );
   1723 			SetMaterialFlag( MF_DEFAULTED );
   1724 			return;
   1725 		}
   1726 		deformDecl = declManager->FindType( DECL_PARTICLE, token.c_str(), true );
   1727 		return;
   1728 	}
   1729 	src.Warning( "Bad deform type '%s'", token.c_str() );
   1730 	SetMaterialFlag( MF_DEFAULTED );
   1731 }
   1732 
   1733 
   1734 /*
   1735 ==============
   1736 idMaterial::AddImplicitStages
   1737 
   1738 If a material has diffuse or specular stages without any
   1739 bump stage, add an implicit _flat bumpmap stage.
   1740 
   1741 If a material has a bump stage but no diffuse or specular
   1742 stage, add a _white diffuse stage.
   1743 
   1744 It is valid to have either a diffuse or specular without the other.
   1745 
   1746 It is valid to have a reflection map and a bump map for bumpy reflection
   1747 ==============
   1748 */
   1749 void idMaterial::AddImplicitStages( const textureRepeat_t trpDefault /* = TR_REPEAT  */ ) {
   1750 	char	buffer[1024];
   1751 	idLexer		newSrc;
   1752 	bool hasDiffuse = false;
   1753 	bool hasSpecular = false;
   1754 	bool hasBump = false;
   1755 	bool hasReflection = false;
   1756 
   1757 	for ( int i = 0 ; i < numStages ; i++ ) {
   1758 		if ( pd->parseStages[i].lighting == SL_BUMP ) {
   1759 			hasBump = true;
   1760 		}
   1761 		if ( pd->parseStages[i].lighting == SL_DIFFUSE ) {
   1762 			hasDiffuse = true;
   1763 		}
   1764 		if ( pd->parseStages[i].lighting == SL_SPECULAR ) {
   1765 			hasSpecular = true;
   1766 		}
   1767 		if ( pd->parseStages[i].texture.texgen == TG_REFLECT_CUBE ) {
   1768 			hasReflection = true;
   1769 		}
   1770 	}
   1771 
   1772 	// if it doesn't have an interaction at all, don't add anything
   1773 	if ( !hasBump && !hasDiffuse && !hasSpecular ) {
   1774 		return;
   1775 	}
   1776 
   1777 	if ( numStages == MAX_SHADER_STAGES ) {
   1778 		return;
   1779 	}
   1780 
   1781 	if ( !hasBump ) {
   1782 		idStr::snPrintf( buffer, sizeof( buffer ), "blend bumpmap\nmap _flat\n}\n" );
   1783 		newSrc.LoadMemory( buffer, strlen(buffer), "bumpmap" );
   1784 		newSrc.SetFlags( LEXFL_NOFATALERRORS | LEXFL_NOSTRINGCONCAT | LEXFL_NOSTRINGESCAPECHARS | LEXFL_ALLOWPATHNAMES );
   1785 		ParseStage( newSrc, trpDefault );
   1786 		newSrc.FreeSource();
   1787 	}
   1788 
   1789 	if ( !hasDiffuse && !hasSpecular && !hasReflection ) {
   1790 		idStr::snPrintf( buffer, sizeof( buffer ), "blend diffusemap\nmap _white\n}\n" );
   1791 		newSrc.LoadMemory( buffer, strlen(buffer), "diffusemap" );
   1792 		newSrc.SetFlags( LEXFL_NOFATALERRORS | LEXFL_NOSTRINGCONCAT | LEXFL_NOSTRINGESCAPECHARS | LEXFL_ALLOWPATHNAMES );
   1793 		ParseStage( newSrc, trpDefault );
   1794 		newSrc.FreeSource();
   1795 	}
   1796 
   1797 }
   1798 
   1799 /*
   1800 ===============
   1801 idMaterial::SortInteractionStages
   1802 
   1803 The renderer expects bump, then diffuse, then specular
   1804 There can be multiple bump maps, followed by additional
   1805 diffuse and specular stages, which allows cross-faded bump mapping.
   1806 
   1807 Ambient stages can be interspersed anywhere, but they are
   1808 ignored during interactions, and all the interaction
   1809 stages are ignored during ambient drawing.
   1810 ===============
   1811 */
   1812 void idMaterial::SortInteractionStages() {
   1813 	int		j;
   1814 
   1815 	for ( int i = 0 ; i < numStages ; i = j ) {
   1816 		// find the next bump map
   1817 		for ( j = i + 1 ; j < numStages ; j++ ) {
   1818 			if ( pd->parseStages[j].lighting == SL_BUMP ) {
   1819 				// if the very first stage wasn't a bumpmap,
   1820 				// this bumpmap is part of the first group
   1821 				if ( pd->parseStages[i].lighting != SL_BUMP ) {
   1822 					continue;
   1823 				}
   1824 				break;
   1825 			}
   1826 		}
   1827 
   1828 		// bubble sort everything bump / diffuse / specular
   1829 		for ( int l = 1 ; l < j-i ; l++ ) {
   1830 			for ( int k = i ; k < j-l ; k++ ) {
   1831 				if ( pd->parseStages[k].lighting > pd->parseStages[k+1].lighting ) {
   1832 					shaderStage_t	temp;
   1833 
   1834 					temp = pd->parseStages[k];
   1835 					pd->parseStages[k] = pd->parseStages[k+1];
   1836 					pd->parseStages[k+1] = temp;
   1837 				}
   1838 			}
   1839 		}
   1840 	}
   1841 }
   1842 
   1843 /*
   1844 =================
   1845 idMaterial::ParseMaterial
   1846 
   1847 The current text pointer is at the explicit text definition of the
   1848 Parse it into the global material variable. Later functions will optimize it.
   1849 
   1850 If there is any error during parsing, defaultShader will be set.
   1851 =================
   1852 */
   1853 void idMaterial::ParseMaterial( idLexer &src ) {
   1854 	idToken		token;
   1855 	int			s;
   1856 	char		buffer[1024];
   1857 	const char	*str;
   1858 	idLexer		newSrc;
   1859 	int			i;
   1860 
   1861 	s = 0;
   1862 
   1863 	numOps = 0;
   1864 	numRegisters = EXP_REG_NUM_PREDEFINED;	// leave space for the parms to be copied in
   1865 	for ( i = 0 ; i < numRegisters ; i++ ) {
   1866 		pd->registerIsTemporary[i] = true;		// they aren't constants that can be folded
   1867 	}
   1868 
   1869 	numStages = 0;
   1870 	pd->registersAreConstant = true;			// until shown otherwise
   1871 	textureRepeat_t	trpDefault = TR_REPEAT;		// allow a global setting for repeat
   1872 
   1873 	while ( 1 ) {
   1874 		if ( TestMaterialFlag( MF_DEFAULTED ) ) {	// we have a parse error
   1875 			return;
   1876 		}
   1877 		if ( !src.ExpectAnyToken( &token ) ) {
   1878 			SetMaterialFlag( MF_DEFAULTED );
   1879 			return;
   1880 		}
   1881 
   1882 		// end of material definition
   1883 		if ( token == "}" ) {
   1884 			break;
   1885 		}
   1886 		else if ( !token.Icmp( "qer_editorimage") ) {
   1887 			src.ReadTokenOnLine( &token );
   1888 			editorImageName = token.c_str();
   1889 			src.SkipRestOfLine();
   1890 			continue;
   1891 		}
   1892 		// description
   1893 		else if ( !token.Icmp( "description") ) {
   1894 			src.ReadTokenOnLine( &token );
   1895 			desc = token.c_str();
   1896 			continue;
   1897 		}
   1898 		// check for the surface / content bit flags
   1899 		else if ( CheckSurfaceParm( &token ) ) {
   1900 			continue;
   1901 		}
   1902 
   1903 
   1904 		// polygonOffset
   1905 		else if ( !token.Icmp( "polygonOffset" ) ) {
   1906 			SetMaterialFlag( MF_POLYGONOFFSET );
   1907 			if ( !src.ReadTokenOnLine( &token ) ) {
   1908 				polygonOffset = 1;
   1909 				continue;
   1910 			}
   1911 			// explict larger (or negative) offset
   1912 			polygonOffset = token.GetFloatValue();
   1913 			continue;
   1914 		}
   1915 		// noshadow
   1916 		else if ( !token.Icmp( "noShadows" ) ) {
   1917 			SetMaterialFlag( MF_NOSHADOWS );
   1918 			continue;
   1919 		}
   1920 		else if ( !token.Icmp( "suppressInSubview" ) ) {
   1921 			suppressInSubview = true;
   1922 			continue;
   1923 		}
   1924 		else if ( !token.Icmp( "portalSky" ) ) {
   1925 			portalSky = true;
   1926 			continue;
   1927 		}
   1928 		// noSelfShadow
   1929 		else if ( !token.Icmp( "noSelfShadow" ) ) {
   1930 			SetMaterialFlag( MF_NOSELFSHADOW );
   1931 			continue;
   1932 		}
   1933 		// noPortalFog
   1934 		else if ( !token.Icmp( "noPortalFog" ) ) {
   1935 			SetMaterialFlag( MF_NOPORTALFOG );
   1936 			continue;
   1937 		}
   1938 		// forceShadows allows nodraw surfaces to cast shadows
   1939 		else if ( !token.Icmp( "forceShadows" ) ) {
   1940 			SetMaterialFlag( MF_FORCESHADOWS );
   1941 			continue;
   1942 		}
   1943 		// overlay / decal suppression
   1944 		else if ( !token.Icmp( "noOverlays" ) ) {
   1945 			allowOverlays = false;
   1946 			continue;
   1947 		}
   1948 		// moster blood overlay forcing for alpha tested or translucent surfaces
   1949 		else if ( !token.Icmp( "forceOverlays" ) ) {
   1950 			pd->forceOverlays = true;
   1951 			continue;
   1952 		}
   1953 		// translucent
   1954 		else if ( !token.Icmp( "translucent" ) ) {
   1955 			coverage = MC_TRANSLUCENT;
   1956 			continue;
   1957 		}
   1958 		// global zero clamp
   1959 		else if ( !token.Icmp( "zeroclamp" ) ) {
   1960 			trpDefault = TR_CLAMP_TO_ZERO;
   1961 			continue;
   1962 		}
   1963 		// global clamp
   1964 		else if ( !token.Icmp( "clamp" ) ) {
   1965 			trpDefault = TR_CLAMP;
   1966 			continue;
   1967 		}
   1968 		// global clamp
   1969 		else if ( !token.Icmp( "alphazeroclamp" ) ) {
   1970 			trpDefault = TR_CLAMP_TO_ZERO;
   1971 			continue;
   1972 		}
   1973 		// forceOpaque is used for skies-behind-windows
   1974 		else if ( !token.Icmp( "forceOpaque" ) ) {
   1975 			coverage = MC_OPAQUE;
   1976 			continue;
   1977 		}
   1978 		// twoSided
   1979 		else if ( !token.Icmp( "twoSided" ) ) {
   1980 			cullType = CT_TWO_SIDED;
   1981 			// twoSided implies no-shadows, because the shadow
   1982 			// volume would be coplanar with the surface, giving depth fighting
   1983 			// we could make this no-self-shadows, but it may be more important
   1984 			// to receive shadows from no-self-shadow monsters
   1985 			SetMaterialFlag( MF_NOSHADOWS );
   1986 		}
   1987 		// backSided
   1988 		else if ( !token.Icmp( "backSided" ) ) {
   1989 			cullType = CT_BACK_SIDED;
   1990 			// the shadow code doesn't handle this, so just disable shadows.
   1991 			// We could fix this in the future if there was a need.
   1992 			SetMaterialFlag( MF_NOSHADOWS );
   1993 		}
   1994 		// foglight
   1995 		else if ( !token.Icmp( "fogLight" ) ) {
   1996 			fogLight = true;
   1997 			continue;
   1998 		}
   1999 		// blendlight
   2000 		else if ( !token.Icmp( "blendLight" ) ) {
   2001 			blendLight = true;
   2002 			continue;
   2003 		}
   2004 		// ambientLight
   2005 		else if ( !token.Icmp( "ambientLight" ) ) {
   2006 			ambientLight = true;
   2007 			continue;
   2008 		}
   2009 		// mirror
   2010 		else if ( !token.Icmp( "mirror" ) ) {
   2011 			sort = SS_SUBVIEW;
   2012 			coverage = MC_OPAQUE;
   2013 			continue;
   2014 		}
   2015 		// noFog
   2016 		else if ( !token.Icmp( "noFog" ) ) {
   2017 			noFog = true;
   2018 			continue;
   2019 		}
   2020 		// unsmoothedTangents
   2021 		else if ( !token.Icmp( "unsmoothedTangents" ) ) {
   2022 			unsmoothedTangents = true;
   2023 			continue;
   2024 		}
   2025 		// lightFallofImage <imageprogram>
   2026 		// specifies the image to use for the third axis of projected
   2027 		// light volumes
   2028 		else if ( !token.Icmp( "lightFalloffImage" ) ) {
   2029 			str = R_ParsePastImageProgram( src );
   2030 			idStr	copy;
   2031 
   2032 			copy = str;	// so other things don't step on it
   2033 			lightFalloffImage = globalImages->ImageFromFile( copy, TF_DEFAULT, TR_CLAMP /* TR_CLAMP_TO_ZERO */, TD_DEFAULT );
   2034 			continue;
   2035 		}
   2036 		// guisurf <guifile> | guisurf entity
   2037 		// an entity guisurf must have an idUserInterface
   2038 		// specified in the renderEntity
   2039 		else if ( !token.Icmp( "guisurf" ) ) {
   2040 			src.ReadTokenOnLine( &token );
   2041 			if ( !token.Icmp( "entity" ) ) {
   2042 				entityGui = 1;
   2043 			} else if ( !token.Icmp( "entity2" ) ) {
   2044 				entityGui = 2;
   2045 			} else if ( !token.Icmp( "entity3" ) ) {
   2046 				entityGui = 3;
   2047 			} else {
   2048 				gui = uiManager->FindGui( token.c_str(), true );
   2049 			}
   2050 			continue;
   2051 		}
   2052 		// sort
   2053 		else if ( !token.Icmp( "sort" ) ) {
   2054 			ParseSort( src );
   2055 			continue;
   2056 		}
   2057 		else if ( !token.Icmp( "stereoeye") ) {
   2058 			ParseStereoEye( src );
   2059 			continue;
   2060 		}
   2061 		// spectrum <integer>
   2062 		else if ( !token.Icmp( "spectrum" ) ) {
   2063 			src.ReadTokenOnLine( &token );
   2064 			spectrum = atoi( token.c_str() );
   2065 			continue;
   2066 		}
   2067 		// deform < sprite | tube | flare >
   2068 		else if ( !token.Icmp( "deform" ) ) {
   2069 			ParseDeform( src );
   2070 			continue;
   2071 		}
   2072 		// decalInfo <staySeconds> <fadeSeconds> ( <start rgb> ) ( <end rgb> )
   2073 		else if ( !token.Icmp( "decalInfo" ) ) {
   2074 			ParseDecalInfo( src );
   2075 			continue;
   2076 		}
   2077 		// renderbump <args...>
   2078 		else if ( !token.Icmp( "renderbump") ) {
   2079 			src.ParseRestOfLine( renderBump );
   2080 			continue;
   2081 		}
   2082 		// diffusemap for stage shortcut
   2083 		else if ( !token.Icmp( "diffusemap" ) ) {
   2084 			str = R_ParsePastImageProgram( src );
   2085 			idStr::snPrintf( buffer, sizeof( buffer ), "blend diffusemap\nmap %s\n}\n", str );
   2086 			newSrc.LoadMemory( buffer, strlen(buffer), "diffusemap" );
   2087 			newSrc.SetFlags( LEXFL_NOFATALERRORS | LEXFL_NOSTRINGCONCAT | LEXFL_NOSTRINGESCAPECHARS | LEXFL_ALLOWPATHNAMES );
   2088 			ParseStage( newSrc, trpDefault );
   2089 			newSrc.FreeSource();
   2090 			continue;
   2091 		}
   2092 		// specularmap for stage shortcut
   2093 		else if ( !token.Icmp( "specularmap" ) ) {
   2094 			str = R_ParsePastImageProgram( src );
   2095 			idStr::snPrintf( buffer, sizeof( buffer ), "blend specularmap\nmap %s\n}\n", str );
   2096 			newSrc.LoadMemory( buffer, strlen(buffer), "specularmap" );
   2097 			newSrc.SetFlags( LEXFL_NOFATALERRORS | LEXFL_NOSTRINGCONCAT | LEXFL_NOSTRINGESCAPECHARS | LEXFL_ALLOWPATHNAMES );
   2098 			ParseStage( newSrc, trpDefault );
   2099 			newSrc.FreeSource();
   2100 			continue;
   2101 		}
   2102 		// normalmap for stage shortcut
   2103 		else if ( !token.Icmp( "bumpmap" ) ) {
   2104 			str = R_ParsePastImageProgram( src );
   2105 			idStr::snPrintf( buffer, sizeof( buffer ), "blend bumpmap\nmap %s\n}\n", str );
   2106 			newSrc.LoadMemory( buffer, strlen(buffer), "bumpmap" );
   2107 			newSrc.SetFlags( LEXFL_NOFATALERRORS | LEXFL_NOSTRINGCONCAT | LEXFL_NOSTRINGESCAPECHARS | LEXFL_ALLOWPATHNAMES );
   2108 			ParseStage( newSrc, trpDefault );
   2109 			newSrc.FreeSource();
   2110 			continue;
   2111 		}
   2112 		// DECAL_MACRO for backwards compatibility with the preprocessor macros
   2113 		else if ( !token.Icmp( "DECAL_MACRO" ) ) {
   2114 			// polygonOffset
   2115 			SetMaterialFlag( MF_POLYGONOFFSET );
   2116 			polygonOffset = 1;
   2117 
   2118 			// discrete
   2119 			surfaceFlags |= SURF_DISCRETE;
   2120 			contentFlags &= ~CONTENTS_SOLID;
   2121 
   2122 			// sort decal
   2123 			sort = SS_DECAL;
   2124 
   2125 			// noShadows
   2126 			SetMaterialFlag( MF_NOSHADOWS );
   2127 			continue;
   2128 		}
   2129 		else if ( token == "{" ) {
   2130 			// create the new stage
   2131 			ParseStage( src, trpDefault );
   2132 			continue;
   2133 		}
   2134 		else {
   2135 			common->Warning( "unknown general material parameter '%s' in '%s'", token.c_str(), GetName() );
   2136 			SetMaterialFlag( MF_DEFAULTED );
   2137 			return;
   2138 		}
   2139 	}
   2140 
   2141 	// add _flat or _white stages if needed
   2142 	AddImplicitStages();
   2143 
   2144 	// order the diffuse / bump / specular stages properly
   2145 	SortInteractionStages();
   2146 
   2147 	// if we need to do anything with normals (lighting or environment mapping)
   2148 	// and two sided lighting was asked for, flag
   2149 	// shouldCreateBackSides() and change culling back to single sided,
   2150 	// so we get proper tangent vectors on both sides
   2151 
   2152 	// we can't just call ReceivesLighting(), because the stages are still
   2153 	// in temporary form
   2154 	if ( cullType == CT_TWO_SIDED ) {
   2155 		for ( i = 0 ; i < numStages ; i++ ) {
   2156 			if ( pd->parseStages[i].lighting != SL_AMBIENT || pd->parseStages[i].texture.texgen != TG_EXPLICIT ) {
   2157 				if ( cullType == CT_TWO_SIDED ) {
   2158 					cullType = CT_FRONT_SIDED;
   2159 					shouldCreateBackSides = true;
   2160 				}
   2161 				break;
   2162 			}
   2163 		}
   2164 	}
   2165 
   2166 	// currently a surface can only have one unique texgen for all the stages on old hardware
   2167 	texgen_t firstGen = TG_EXPLICIT;
   2168 	for ( i = 0; i < numStages; i++ ) {
   2169 		if ( pd->parseStages[i].texture.texgen != TG_EXPLICIT ) {
   2170 			if ( firstGen == TG_EXPLICIT ) {
   2171 				firstGen = pd->parseStages[i].texture.texgen;
   2172 			} else if ( firstGen != pd->parseStages[i].texture.texgen ) {
   2173 				common->Warning( "material '%s' has multiple stages with a texgen", GetName() );
   2174 				break;
   2175 			}
   2176 		}
   2177 	}
   2178 }
   2179 
   2180 /*
   2181 =========================
   2182 idMaterial::SetGui
   2183 =========================
   2184 */
   2185 void idMaterial::SetGui( const char *_gui ) const {
   2186 	gui = uiManager->FindGui( _gui, true, false, true );
   2187 }
   2188 
   2189 /*
   2190 =========================
   2191 idMaterial::Parse
   2192 
   2193 Parses the current material definition and finds all necessary images.
   2194 =========================
   2195 */
   2196 bool idMaterial::Parse( const char *text, const int textLength, bool allowBinaryVersion ) {
   2197 	idLexer	src;
   2198 	idToken	token;
   2199 	mtrParsingData_t parsingData;
   2200 
   2201 	src.LoadMemory( text, textLength, GetFileName(), GetLineNum() );
   2202 	src.SetFlags( DECL_LEXER_FLAGS );
   2203 	src.SkipUntilString( "{" );
   2204 
   2205 	// reset to the unparsed state
   2206 	CommonInit();
   2207 
   2208 	memset( &parsingData, 0, sizeof( parsingData ) );
   2209 
   2210 	pd = &parsingData;	// this is only valid during parse
   2211 
   2212 	// parse it
   2213 	ParseMaterial( src );
   2214 
   2215 	// if we are doing an fs_copyfiles, also reference the editorImage
   2216 	if ( cvarSystem->GetCVarInteger( "fs_copyFiles" ) ) {
   2217 		GetEditorImage();
   2218 	}
   2219 
   2220 	//
   2221 	// count non-lit stages
   2222 	numAmbientStages = 0;
   2223 	int i;
   2224 	for ( i = 0 ; i < numStages ; i++ ) {
   2225 		if ( pd->parseStages[i].lighting == SL_AMBIENT ) {
   2226 			numAmbientStages++;
   2227 		}
   2228 	}
   2229 
   2230 	// see if there is a subview stage
   2231 	if ( sort == SS_SUBVIEW ) {
   2232 		hasSubview = true;
   2233 	} else {
   2234 		hasSubview = false;
   2235 		for ( i = 0 ; i < numStages ; i++ ) {
   2236 			if ( pd->parseStages[i].texture.dynamic ) {
   2237 				hasSubview = true;
   2238 			}
   2239 		}
   2240 	}
   2241 
   2242 	// automatically determine coverage if not explicitly set
   2243 	if ( coverage == MC_BAD ) {
   2244 		// automatically set MC_TRANSLUCENT if we don't have any interaction stages and 
   2245 		// the first stage is blended and not an alpha test mask or a subview
   2246 		if ( !numStages ) {
   2247 			// non-visible
   2248 			coverage = MC_TRANSLUCENT;
   2249 		} else if ( numStages != numAmbientStages ) {
   2250 			// we have an interaction draw
   2251 			coverage = MC_OPAQUE;
   2252 		} else if ( 
   2253 			( pd->parseStages[0].drawStateBits & GLS_DSTBLEND_BITS ) != GLS_DSTBLEND_ZERO ||
   2254 			( pd->parseStages[0].drawStateBits & GLS_SRCBLEND_BITS ) == GLS_SRCBLEND_DST_COLOR ||
   2255 			( pd->parseStages[0].drawStateBits & GLS_SRCBLEND_BITS ) == GLS_SRCBLEND_ONE_MINUS_DST_COLOR ||
   2256 			( pd->parseStages[0].drawStateBits & GLS_SRCBLEND_BITS ) == GLS_SRCBLEND_DST_ALPHA ||
   2257 			( pd->parseStages[0].drawStateBits & GLS_SRCBLEND_BITS ) == GLS_SRCBLEND_ONE_MINUS_DST_ALPHA
   2258 			) {
   2259 			// blended with the destination
   2260 				coverage = MC_TRANSLUCENT;
   2261 		} else {
   2262 			coverage = MC_OPAQUE;
   2263 		}
   2264 	}
   2265 
   2266 	// translucent automatically implies noshadows
   2267 	if ( coverage == MC_TRANSLUCENT ) {
   2268 		SetMaterialFlag( MF_NOSHADOWS );
   2269 	} else {
   2270 		// mark the contents as opaque
   2271 		contentFlags |= CONTENTS_OPAQUE;
   2272 	}
   2273 
   2274 	// if we are translucent, draw with an alpha in the editor
   2275 	if ( coverage == MC_TRANSLUCENT ) {
   2276 		editorAlpha = 0.5;
   2277 	} else {
   2278 		editorAlpha = 1.0;
   2279 	}
   2280 
   2281 	// the sorts can make reasonable defaults
   2282 	if ( sort == SS_BAD ) {
   2283 		if ( TestMaterialFlag(MF_POLYGONOFFSET) ) {
   2284 			sort = SS_DECAL;
   2285 		} else if ( coverage == MC_TRANSLUCENT ) {
   2286 			sort = SS_MEDIUM;
   2287 		} else {
   2288 			sort = SS_OPAQUE;
   2289 		}
   2290 	}
   2291 
   2292 	// anything that references _currentRender will automatically get sort = SS_POST_PROCESS
   2293 	// and coverage = MC_TRANSLUCENT
   2294 
   2295 	for ( i = 0 ; i < numStages ; i++ ) {
   2296 		shaderStage_t	*pStage = &pd->parseStages[i];
   2297 		if ( pStage->texture.image == globalImages->originalCurrentRenderImage ) {
   2298 			if ( sort != SS_PORTAL_SKY ) {
   2299 				sort = SS_POST_PROCESS;
   2300 				coverage = MC_TRANSLUCENT;
   2301 			}
   2302 			break;
   2303 		}
   2304 		if ( pStage->newStage ) {
   2305 			for ( int j = 0 ; j < pStage->newStage->numFragmentProgramImages ; j++ ) {
   2306 				if ( pStage->newStage->fragmentProgramImages[j] == globalImages->originalCurrentRenderImage ) {
   2307 					if ( sort != SS_PORTAL_SKY ) {
   2308 						sort = SS_POST_PROCESS;
   2309 						coverage = MC_TRANSLUCENT;
   2310 					}
   2311 					i = numStages;
   2312 					break;
   2313 				}
   2314 			}
   2315 		}
   2316 	}
   2317 
   2318 	// set the drawStateBits depth flags
   2319 	for ( i = 0 ; i < numStages ; i++ ) {
   2320 		shaderStage_t	*pStage = &pd->parseStages[i];
   2321 		if ( sort == SS_POST_PROCESS ) {
   2322 			// post-process effects fill the depth buffer as they draw, so only the
   2323 			// topmost post-process effect is rendered
   2324 			pStage->drawStateBits |= GLS_DEPTHFUNC_LESS;
   2325 		} else if ( coverage == MC_TRANSLUCENT || pStage->ignoreAlphaTest ) {
   2326 			// translucent surfaces can extend past the exactly marked depth buffer
   2327 			pStage->drawStateBits |= GLS_DEPTHFUNC_LESS | GLS_DEPTHMASK;
   2328 		} else {
   2329 			// opaque and perforated surfaces must exactly match the depth buffer,
   2330 			// which gets alpha test correct
   2331 			pStage->drawStateBits |= GLS_DEPTHFUNC_EQUAL | GLS_DEPTHMASK;
   2332 		}
   2333 	}
   2334 
   2335 	// determine if this surface will accept overlays / decals
   2336 
   2337 	if ( pd->forceOverlays ) {
   2338 		// explicitly flaged in material definition
   2339 		allowOverlays = true;
   2340 	} else {
   2341 		if ( !IsDrawn() ) {
   2342 			allowOverlays = false;
   2343 		}
   2344 		if ( Coverage() != MC_OPAQUE ) {
   2345 			allowOverlays = false;
   2346 		}
   2347 		if ( GetSurfaceFlags() & SURF_NOIMPACT ) {
   2348 			allowOverlays = false;
   2349 		}
   2350 	}
   2351 
   2352 	// add a tiny offset to the sort orders, so that different materials
   2353 	// that have the same sort value will at least sort consistantly, instead
   2354 	// of flickering back and forth
   2355 /* this messed up in-game guis
   2356 	if ( sort != SS_SUBVIEW ) {
   2357 		int	hash, l;
   2358 
   2359 		l = name.Length();
   2360 		hash = 0;
   2361 		for ( int i = 0 ; i < l ; i++ ) {
   2362 			hash ^= name[i];
   2363 		}
   2364 		sort += hash * 0.01;
   2365 	}
   2366 */
   2367 
   2368 	if (numStages) {
   2369 		stages = (shaderStage_t *)R_StaticAlloc( numStages * sizeof( stages[0] ), TAG_MATERIAL );
   2370 		memcpy( stages, pd->parseStages, numStages * sizeof( stages[0] ) );
   2371 	}
   2372 
   2373 	if ( numOps ) {
   2374 		ops = (expOp_t *)R_StaticAlloc( numOps * sizeof( ops[0] ), TAG_MATERIAL );
   2375 		memcpy( ops, pd->shaderOps, numOps * sizeof( ops[0] ) );
   2376 	}
   2377 
   2378 	if ( numRegisters ) {
   2379 		expressionRegisters = (float *)R_StaticAlloc( numRegisters * sizeof( expressionRegisters[0] ), TAG_MATERIAL );
   2380 		memcpy( expressionRegisters, pd->shaderRegisters, numRegisters * sizeof( expressionRegisters[0] ) );
   2381 	}
   2382 
   2383 	// see if the registers are completely constant, and don't need to be evaluated
   2384 	// per-surface
   2385 	CheckForConstantRegisters();
   2386 
   2387 	// See if the material is trivial for the fast path
   2388 	SetFastPathImages();
   2389 
   2390 	pd = NULL;	// the pointer will be invalid after exiting this function
   2391 
   2392 	// finish things up
   2393 	if ( TestMaterialFlag( MF_DEFAULTED ) ) {
   2394 		MakeDefault();
   2395 		return false;
   2396 	}
   2397 	return true;
   2398 }
   2399 
   2400 /*
   2401 ===================
   2402 idMaterial::Print
   2403 ===================
   2404 */
   2405 char *opNames[] = {
   2406 	"OP_TYPE_ADD",
   2407 	"OP_TYPE_SUBTRACT",
   2408 	"OP_TYPE_MULTIPLY",
   2409 	"OP_TYPE_DIVIDE",
   2410 	"OP_TYPE_MOD",
   2411 	"OP_TYPE_TABLE",
   2412 	"OP_TYPE_GT",
   2413 	"OP_TYPE_GE",
   2414 	"OP_TYPE_LT",
   2415 	"OP_TYPE_LE",
   2416 	"OP_TYPE_EQ",
   2417 	"OP_TYPE_NE",
   2418 	"OP_TYPE_AND",
   2419 	"OP_TYPE_OR"
   2420 };
   2421 
   2422 void idMaterial::Print() const {
   2423 	int			i;
   2424 
   2425 	for ( i = EXP_REG_NUM_PREDEFINED ; i < GetNumRegisters() ; i++ ) {
   2426 		common->Printf( "register %i: %f\n", i, expressionRegisters[i] );
   2427 	}
   2428 	common->Printf( "\n" );
   2429 	for ( i = 0 ; i < numOps ; i++ ) {
   2430 		const expOp_t *op = &ops[i];
   2431 		if ( op->opType == OP_TYPE_TABLE ) {
   2432 			common->Printf( "%i = %s[ %i ]\n", op->c, declManager->DeclByIndex( DECL_TABLE, op->a )->GetName(), op->b );
   2433 		} else {
   2434 			common->Printf( "%i = %i %s %i\n", op->c, op->a, opNames[ op->opType ], op->b );
   2435 		}
   2436 	}
   2437 }
   2438 
   2439 /*
   2440 ===============
   2441 idMaterial::Save
   2442 ===============
   2443 */
   2444 bool idMaterial::Save( const char *fileName ) {
   2445 	return ReplaceSourceFileText();
   2446 }
   2447 
   2448 /*
   2449 ===============
   2450 idMaterial::AddReference
   2451 ===============
   2452 */
   2453 void idMaterial::AddReference() {
   2454 	refCount++;
   2455 
   2456 	for ( int i = 0; i < numStages; i++ ) {
   2457 		shaderStage_t *s = &stages[i];
   2458 
   2459 		if ( s->texture.image ) {
   2460 			s->texture.image->AddReference();
   2461 		}
   2462 	}
   2463 }
   2464 
   2465 /*
   2466 ===============
   2467 idMaterial::EvaluateRegisters
   2468 
   2469 Parameters are taken from the localSpace and the renderView,
   2470 then all expressions are evaluated, leaving the material registers
   2471 set to their apropriate values.
   2472 ===============
   2473 */
   2474 void idMaterial::EvaluateRegisters( 
   2475 	float *			registers, 
   2476 	const float		localShaderParms[MAX_ENTITY_SHADER_PARMS],
   2477 	const float		globalShaderParms[MAX_GLOBAL_SHADER_PARMS], 
   2478 	const float		floatTime, 
   2479 	idSoundEmitter *soundEmitter ) const {
   2480 
   2481 	int		i, b;
   2482 	expOp_t	*op;
   2483 
   2484 	// copy the material constants
   2485 	for ( i = EXP_REG_NUM_PREDEFINED ; i < numRegisters ; i++ ) {
   2486 		registers[i] = expressionRegisters[i];
   2487 	}
   2488 
   2489 	// copy the local and global parameters
   2490 	registers[EXP_REG_TIME] = floatTime;
   2491 	registers[EXP_REG_PARM0] = localShaderParms[0];
   2492 	registers[EXP_REG_PARM1] = localShaderParms[1];
   2493 	registers[EXP_REG_PARM2] = localShaderParms[2];
   2494 	registers[EXP_REG_PARM3] = localShaderParms[3];
   2495 	registers[EXP_REG_PARM4] = localShaderParms[4];
   2496 	registers[EXP_REG_PARM5] = localShaderParms[5];
   2497 	registers[EXP_REG_PARM6] = localShaderParms[6];
   2498 	registers[EXP_REG_PARM7] = localShaderParms[7];
   2499 	registers[EXP_REG_PARM8] = localShaderParms[8];
   2500 	registers[EXP_REG_PARM9] = localShaderParms[9];
   2501 	registers[EXP_REG_PARM10] = localShaderParms[10];
   2502 	registers[EXP_REG_PARM11] = localShaderParms[11];
   2503 	registers[EXP_REG_GLOBAL0] = globalShaderParms[0];
   2504 	registers[EXP_REG_GLOBAL1] = globalShaderParms[1];
   2505 	registers[EXP_REG_GLOBAL2] = globalShaderParms[2];
   2506 	registers[EXP_REG_GLOBAL3] = globalShaderParms[3];
   2507 	registers[EXP_REG_GLOBAL4] = globalShaderParms[4];
   2508 	registers[EXP_REG_GLOBAL5] = globalShaderParms[5];
   2509 	registers[EXP_REG_GLOBAL6] = globalShaderParms[6];
   2510 	registers[EXP_REG_GLOBAL7] = globalShaderParms[7];
   2511 
   2512 	op = ops;
   2513 	for ( i = 0 ; i < numOps ; i++, op++ ) {
   2514 		switch( op->opType ) {
   2515 		case OP_TYPE_ADD:
   2516 			registers[op->c] = registers[op->a] + registers[op->b];
   2517 			break;
   2518 		case OP_TYPE_SUBTRACT:
   2519 			registers[op->c] = registers[op->a] - registers[op->b];
   2520 			break;
   2521 		case OP_TYPE_MULTIPLY:
   2522 			registers[op->c] = registers[op->a] * registers[op->b];
   2523 			break;
   2524 		case OP_TYPE_DIVIDE:
   2525 			registers[op->c] = registers[op->a] / registers[op->b];
   2526 			break;
   2527 		case OP_TYPE_MOD:
   2528 			b = (int)registers[op->b];
   2529 			b = b != 0 ? b : 1;
   2530 			registers[op->c] = (int)registers[op->a] % b;
   2531 			break;
   2532 		case OP_TYPE_TABLE:
   2533 			{
   2534 				const idDeclTable *table = static_cast<const idDeclTable *>( declManager->DeclByIndex( DECL_TABLE, op->a ) );
   2535 				registers[op->c] = table->TableLookup( registers[op->b] );
   2536 			}
   2537 			break;
   2538 		case OP_TYPE_SOUND:
   2539 			if ( r_forceSoundOpAmplitude.GetFloat() > 0 ) {
   2540 				registers[op->c] = r_forceSoundOpAmplitude.GetFloat();
   2541 			} else if ( soundEmitter ) {
   2542 				registers[op->c] = soundEmitter->CurrentAmplitude();
   2543 			} else {
   2544 				registers[op->c] = 0;
   2545 			}
   2546 			break;
   2547 		case OP_TYPE_GT:
   2548 			registers[op->c] = registers[ op->a ] > registers[op->b];
   2549 			break;
   2550 		case OP_TYPE_GE:
   2551 			registers[op->c] = registers[ op->a ] >= registers[op->b];
   2552 			break;
   2553 		case OP_TYPE_LT:
   2554 			registers[op->c] = registers[ op->a ] < registers[op->b];
   2555 			break;
   2556 		case OP_TYPE_LE:
   2557 			registers[op->c] = registers[ op->a ] <= registers[op->b];
   2558 			break;
   2559 		case OP_TYPE_EQ:
   2560 			registers[op->c] = registers[ op->a ] == registers[op->b];
   2561 			break;
   2562 		case OP_TYPE_NE:
   2563 			registers[op->c] = registers[ op->a ] != registers[op->b];
   2564 			break;
   2565 		case OP_TYPE_AND:
   2566 			registers[op->c] = registers[ op->a ] && registers[op->b];
   2567 			break;
   2568 		case OP_TYPE_OR:
   2569 			registers[op->c] = registers[ op->a ] || registers[op->b];
   2570 			break;
   2571 		default:
   2572 			common->FatalError( "R_EvaluateExpression: bad opcode" );
   2573 		}
   2574 	}
   2575 
   2576 }
   2577 
   2578 /*
   2579 =============
   2580 idMaterial::Texgen
   2581 =============
   2582 */
   2583 texgen_t idMaterial::Texgen() const {
   2584 	if ( stages ) {
   2585 		for ( int i = 0; i < numStages; i++ ) {
   2586 			if ( stages[ i ].texture.texgen != TG_EXPLICIT ) {
   2587 				return stages[ i ].texture.texgen;
   2588 			}
   2589 		}
   2590 	}
   2591 	
   2592 	return TG_EXPLICIT;
   2593 }
   2594 
   2595 /*
   2596 =============
   2597 idMaterial::GetImageWidth
   2598 =============
   2599 */
   2600 int idMaterial::GetImageWidth() const {
   2601 	assert( GetStage(0) && GetStage(0)->texture.image );
   2602 	return GetStage(0)->texture.image->GetUploadWidth();
   2603 }
   2604 
   2605 /*
   2606 =============
   2607 idMaterial::GetImageHeight
   2608 =============
   2609 */
   2610 int idMaterial::GetImageHeight() const {
   2611 	assert( GetStage(0) && GetStage(0)->texture.image );
   2612 	return GetStage(0)->texture.image->GetUploadHeight();
   2613 }
   2614 
   2615 /*
   2616 =============
   2617 idMaterial::CinematicLength
   2618 =============
   2619 */
   2620 int	idMaterial::CinematicLength() const {
   2621 	if ( !stages || !stages[0].texture.cinematic ) {
   2622 		return 0;
   2623 	}
   2624 	return stages[0].texture.cinematic->AnimationLength();
   2625 }
   2626 
   2627 /*
   2628 =============
   2629 idMaterial::UpdateCinematic
   2630 =============
   2631 */
   2632 void idMaterial::UpdateCinematic( int time ) const {
   2633 }
   2634 
   2635 /*
   2636 =============
   2637 idMaterial::CloseCinematic
   2638 =============
   2639 */
   2640 void idMaterial::CloseCinematic() const {
   2641 	for( int i = 0; i < numStages; i++ ) {
   2642 		if ( stages[i].texture.cinematic ) {
   2643 			stages[i].texture.cinematic->Close();
   2644 			delete stages[i].texture.cinematic;
   2645 			stages[i].texture.cinematic = NULL;
   2646 		}
   2647 	}
   2648 }
   2649 
   2650 /*
   2651 =============
   2652 idMaterial::ResetCinematicTime
   2653 =============
   2654 */
   2655 void idMaterial::ResetCinematicTime( int time ) const {
   2656 	for( int i = 0; i < numStages; i++ ) {
   2657 		if ( stages[i].texture.cinematic ) {
   2658 			stages[i].texture.cinematic->ResetTime( time );
   2659 		}
   2660 	}
   2661 }
   2662 
   2663 /*
   2664 =============
   2665 idMaterial::GetCinematicStartTime
   2666 =============
   2667 */
   2668 int idMaterial::GetCinematicStartTime() const {
   2669 	for( int i = 0; i < numStages; i++ ) {
   2670 		if ( stages[i].texture.cinematic ) {
   2671 			return stages[i].texture.cinematic->GetStartTime();
   2672 		}
   2673 	}
   2674 	return -1;
   2675 }
   2676 
   2677 /*
   2678 ==================
   2679 idMaterial::CheckForConstantRegisters
   2680 
   2681 As of 5/2/03, about half of the unique materials loaded on typical
   2682 maps are constant, but 2/3 of the surface references are.
   2683 ==================
   2684 */
   2685 void idMaterial::CheckForConstantRegisters() {
   2686 	assert( constantRegisters == NULL );
   2687 
   2688 	if ( !pd->registersAreConstant ) {
   2689 		return;
   2690 	}
   2691 	if ( !r_useConstantMaterials.GetBool() ) {
   2692 		return;
   2693 	}
   2694 
   2695 	// evaluate the registers once, and save them 
   2696 	constantRegisters = (float *)R_ClearedStaticAlloc( GetNumRegisters() * sizeof( float ) );
   2697 
   2698 	float shaderParms[MAX_ENTITY_SHADER_PARMS];
   2699 	memset( shaderParms, 0, sizeof( shaderParms ) );
   2700 	viewDef_t	viewDef;
   2701 	memset( &viewDef, 0, sizeof( viewDef ) );
   2702 
   2703 	EvaluateRegisters( constantRegisters, shaderParms, viewDef.renderView.shaderParms, 0.0f, 0 );
   2704 }
   2705 
   2706 /*
   2707 ===================
   2708 idMaterial::ImageName
   2709 ===================
   2710 */
   2711 const char *idMaterial::ImageName() const {
   2712 	if ( numStages == 0 ) {
   2713 		return "_scratch";
   2714 	}
   2715 	idImage	*image = stages[0].texture.image;
   2716 	if ( image ) {
   2717 		return image->GetName();
   2718 	}
   2719 	return "_scratch";
   2720 }
   2721 
   2722 /*
   2723 =================
   2724 idMaterial::Size
   2725 =================
   2726 */
   2727 size_t idMaterial::Size() const {
   2728 	return sizeof( idMaterial );
   2729 }
   2730 
   2731 /*
   2732 ===================
   2733 idMaterial::SetDefaultText
   2734 ===================
   2735 */
   2736 bool idMaterial::SetDefaultText() {
   2737 	// if there exists an image with the same name
   2738 	if ( 1 ) { //fileSystem->ReadFile( GetName(), NULL ) != -1 ) {
   2739 		char generated[2048];
   2740 		idStr::snPrintf( generated, sizeof( generated ), 
   2741 						"material %s // IMPLICITLY GENERATED\n"
   2742 						"{\n"
   2743 						"{\n"
   2744 						"blend blend\n"
   2745 						"colored\n"
   2746 						"map \"%s\"\n"
   2747 						"clamp\n"
   2748 						"}\n"
   2749 						"}\n", GetName(), GetName() );
   2750 		SetText( generated );
   2751 		return true;
   2752 	} else {
   2753 		return false;
   2754 	}
   2755 }
   2756 
   2757 /*
   2758 ===================
   2759 idMaterial::DefaultDefinition
   2760 ===================
   2761 */
   2762 const char *idMaterial::DefaultDefinition() const {
   2763 	return
   2764 		"{\n"
   2765 	"\t"	"{\n"
   2766 	"\t\t"		"blend\tblend\n"
   2767 	"\t\t"		"map\t\t_default\n"
   2768 	"\t"	"}\n"
   2769 		"}";
   2770 }
   2771 
   2772 
   2773 /*
   2774 ===================
   2775 idMaterial::GetBumpStage
   2776 ===================
   2777 */
   2778 const shaderStage_t *idMaterial::GetBumpStage() const {
   2779 	for ( int i = 0 ; i < numStages ; i++ ) {
   2780 		if ( stages[i].lighting == SL_BUMP ) {
   2781 			return &stages[i];
   2782 		}
   2783 	}
   2784 	return NULL;
   2785 }
   2786 
   2787 /*
   2788 ===================
   2789 idMaterial::ReloadImages
   2790 ===================
   2791 */
   2792 void idMaterial::ReloadImages( bool force ) const {
   2793 	for ( int i = 0 ; i < numStages ; i++ ) {
   2794 		if ( stages[i].newStage ) {
   2795 			for ( int j = 0 ; j < stages[i].newStage->numFragmentProgramImages ; j++ ) {
   2796 				if ( stages[i].newStage->fragmentProgramImages[j] ) {
   2797 					stages[i].newStage->fragmentProgramImages[j]->Reload( force );
   2798 				}
   2799 			}
   2800 		} else if ( stages[i].texture.image ) {
   2801 			stages[i].texture.image->Reload( force );
   2802 		}
   2803 	}
   2804 }
   2805 
   2806 /*
   2807 =============
   2808 idMaterial::SetFastPathImages
   2809 
   2810 See if the material is trivial for the fast path
   2811 =============
   2812 */
   2813 void idMaterial::SetFastPathImages() {
   2814 	fastPathBumpImage = NULL;
   2815 	fastPathDiffuseImage = NULL;
   2816 	fastPathSpecularImage = NULL;
   2817 
   2818 	if ( constantRegisters == NULL ) {
   2819 		return;
   2820 	}
   2821 
   2822 	// go through the individual surface stages
   2823 	//
   2824 	// We also have the very rare case of some materials that have conditional interactions
   2825 	// for the "hell writing" that can be shined on them.
   2826 
   2827 	for ( int surfaceStageNum = 0; surfaceStageNum < GetNumStages(); surfaceStageNum++ ) {
   2828 		const shaderStage_t	*surfaceStage = GetStage( surfaceStageNum );
   2829 
   2830 		if ( surfaceStage->texture.hasMatrix ) {
   2831 			goto fail;
   2832 		}
   2833 
   2834 		// check for vertex coloring
   2835 		if ( surfaceStage->vertexColor != SVC_IGNORE ) {
   2836 			goto fail;
   2837 		}
   2838 
   2839 		// check for non-identity colors
   2840 		for ( int i = 0; i < 4; i++ ) {
   2841 			if ( idMath::Fabs( constantRegisters[surfaceStage->color.registers[i]] - 1.0f ) > 0.1f ) {
   2842 				goto fail;
   2843 			}
   2844 		}
   2845 
   2846 		switch( surfaceStage->lighting ) {
   2847 			case SL_COVERAGE:
   2848 			case SL_AMBIENT:
   2849 				break;
   2850 			case SL_BUMP: {
   2851 				if ( fastPathBumpImage ) {
   2852 					goto fail;
   2853 				}
   2854 				fastPathBumpImage = surfaceStage->texture.image;
   2855 				break;
   2856 			}
   2857 			case SL_DIFFUSE: {
   2858 				if ( fastPathDiffuseImage ) {
   2859 					goto fail;
   2860 				}
   2861 				fastPathDiffuseImage = surfaceStage->texture.image;
   2862 				break;
   2863 			}
   2864 			case SL_SPECULAR: {
   2865 				if ( fastPathSpecularImage ) {
   2866 					goto fail;
   2867 				}
   2868 				fastPathSpecularImage = surfaceStage->texture.image;
   2869 			}
   2870 		}
   2871 	}
   2872 	// need a bump image, but specular can default
   2873 	// we also need a diffuse image, because we can't get a pure black with our YCoCg conversion
   2874 	// from 565 DXT.  The general-path code also sets the diffuse color to 0 in the default case,
   2875 	// but the fast path can't.
   2876 	if ( fastPathBumpImage == NULL || fastPathDiffuseImage == NULL ) {
   2877 		goto fail;
   2878 	}
   2879 	if ( fastPathSpecularImage == NULL ) {
   2880 		fastPathSpecularImage = globalImages->blackImage;
   2881 	}
   2882 	return;
   2883 
   2884 fail:
   2885 	fastPathBumpImage = NULL;
   2886 	fastPathDiffuseImage = NULL;
   2887 	fastPathSpecularImage = NULL;
   2888 }