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