1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737 |
- /*
- ===========================================================================
- Doom 3 GPL Source Code
- Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
- Doom 3 Source Code is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- Doom 3 Source Code is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
- 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.
- 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.
- ===========================================================================
- */
- #include "../idlib/precompiled.h"
- #pragma hdrstop
- #include "tr_local.h"
- /*
- Any errors during parsing just set MF_DEFAULTED and return, rather than throwing
- a hard error. This will cause the material to fall back to default material,
- but otherwise let things continue.
- Each material may have a set of calculations that must be evaluated before
- drawing with it.
- Every expression that a material uses can be evaluated at one time, which
- will allow for perfect common subexpression removal when I get around to
- writing it.
- Without this, scrolling an entire surface could result in evaluating the
- same texture matrix calculations a half dozen times.
- Open question: should I allow arbitrary per-vertex color, texCoord, and vertex
- calculations to be specified in the material code?
- Every stage will definately have a valid image pointer.
- We might want the ability to change the sort value based on conditionals,
- but it could be a hassle to implement,
- */
- // keep all of these on the stack, when they are static it makes material parsing non-reentrant
- typedef struct mtrParsingData_s {
- bool registerIsTemporary[MAX_EXPRESSION_REGISTERS];
- float shaderRegisters[MAX_EXPRESSION_REGISTERS];
- expOp_t shaderOps[MAX_EXPRESSION_OPS];
- shaderStage_t parseStages[MAX_SHADER_STAGES];
- bool registersAreConstant;
- bool forceOverlays;
- } mtrParsingData_t;
- /*
- =============
- idMaterial::CommonInit
- =============
- */
- void idMaterial::CommonInit() {
- desc = "<none>";
- renderBump = "";
- contentFlags = CONTENTS_SOLID;
- surfaceFlags = SURFTYPE_NONE;
- materialFlags = 0;
- sort = SS_BAD;
- coverage = MC_BAD;
- cullType = CT_FRONT_SIDED;
- deform = DFRM_NONE;
- numOps = 0;
- ops = NULL;
- numRegisters = 0;
- expressionRegisters = NULL;
- constantRegisters = NULL;
- numStages = 0;
- numAmbientStages = 0;
- stages = NULL;
- editorImage = NULL;
- lightFalloffImage = NULL;
- shouldCreateBackSides = false;
- entityGui = 0;
- fogLight = false;
- blendLight = false;
- ambientLight = false;
- noFog = false;
- hasSubview = false;
- allowOverlays = true;
- unsmoothedTangents = false;
- gui = NULL;
- memset( deformRegisters, 0, sizeof( deformRegisters ) );
- editorAlpha = 1.0;
- spectrum = 0;
- polygonOffset = 0;
- suppressInSubview = false;
- refCount = 0;
- portalSky = false;
- decalInfo.stayTime = 10000;
- decalInfo.fadeTime = 4000;
- decalInfo.start[0] = 1;
- decalInfo.start[1] = 1;
- decalInfo.start[2] = 1;
- decalInfo.start[3] = 1;
- decalInfo.end[0] = 0;
- decalInfo.end[1] = 0;
- decalInfo.end[2] = 0;
- decalInfo.end[3] = 0;
- }
- /*
- =============
- idMaterial::idMaterial
- =============
- */
- idMaterial::idMaterial() {
- CommonInit();
- // we put this here instead of in CommonInit, because
- // we don't want it cleared when a material is purged
- surfaceArea = 0;
- }
- /*
- =============
- idMaterial::~idMaterial
- =============
- */
- idMaterial::~idMaterial() {
- }
- /*
- ===============
- idMaterial::FreeData
- ===============
- */
- void idMaterial::FreeData() {
- int i;
- if ( stages ) {
- // delete any idCinematic textures
- for ( i = 0; i < numStages; i++ ) {
- if ( stages[i].texture.cinematic != NULL ) {
- delete stages[i].texture.cinematic;
- stages[i].texture.cinematic = NULL;
- }
- if ( stages[i].newStage != NULL ) {
- Mem_Free( stages[i].newStage );
- stages[i].newStage = NULL;
- }
- }
- R_StaticFree( stages );
- stages = NULL;
- }
- if ( expressionRegisters != NULL ) {
- R_StaticFree( expressionRegisters );
- expressionRegisters = NULL;
- }
- if ( constantRegisters != NULL ) {
- R_StaticFree( constantRegisters );
- constantRegisters = NULL;
- }
- if ( ops != NULL ) {
- R_StaticFree( ops );
- ops = NULL;
- }
- }
- /*
- ==============
- idMaterial::GetEditorImage
- ==============
- */
- idImage *idMaterial::GetEditorImage( void ) const {
- if ( editorImage ) {
- return editorImage;
- }
- // if we don't have an editorImageName, use the first stage image
- if ( !editorImageName.Length()) {
- // _D3XP :: First check for a diffuse image, then use the first
- if ( numStages && stages ) {
- int i;
- for( i = 0; i < numStages; i++ ) {
- if ( stages[i].lighting == SL_DIFFUSE ) {
- editorImage = stages[i].texture.image;
- break;
- }
- }
- if ( !editorImage ) {
- editorImage = stages[0].texture.image;
- }
- } else {
- editorImage = globalImages->defaultImage;
- }
- } else {
- // look for an explicit one
- editorImage = globalImages->ImageFromFile( editorImageName, TF_DEFAULT, true, TR_REPEAT, TD_DEFAULT );
- }
- if ( !editorImage ) {
- editorImage = globalImages->defaultImage;
- }
- return editorImage;
- }
- // info parms
- typedef struct {
- char *name;
- int clearSolid, surfaceFlags, contents;
- } infoParm_t;
- static infoParm_t infoParms[] = {
- // game relevant attributes
- {"solid", 0, 0, CONTENTS_SOLID }, // may need to override a clearSolid
- {"water", 1, 0, CONTENTS_WATER }, // used for water
- {"playerclip", 0, 0, CONTENTS_PLAYERCLIP }, // solid to players
- {"monsterclip", 0, 0, CONTENTS_MONSTERCLIP }, // solid to monsters
- {"moveableclip",0, 0, CONTENTS_MOVEABLECLIP },// solid to moveable entities
- {"ikclip", 0, 0, CONTENTS_IKCLIP }, // solid to IK
- {"blood", 0, 0, CONTENTS_BLOOD }, // used to detect blood decals
- {"trigger", 0, 0, CONTENTS_TRIGGER }, // used for triggers
- {"aassolid", 0, 0, CONTENTS_AAS_SOLID }, // solid for AAS
- {"aasobstacle", 0, 0, CONTENTS_AAS_OBSTACLE },// used to compile an obstacle into AAS that can be enabled/disabled
- {"flashlight_trigger", 0, 0, CONTENTS_FLASHLIGHT_TRIGGER }, // used for triggers that are activated by the flashlight
- {"nonsolid", 1, 0, 0 }, // clears the solid flag
- {"nullNormal", 0, SURF_NULLNORMAL,0 }, // renderbump will draw as 0x80 0x80 0x80
- // utility relevant attributes
- {"areaportal", 1, 0, CONTENTS_AREAPORTAL }, // divides areas
- {"qer_nocarve", 1, 0, CONTENTS_NOCSG}, // don't cut brushes in editor
- {"discrete", 1, SURF_DISCRETE, 0 }, // surfaces should not be automatically merged together or
- // clipped to the world,
- // because they represent discrete objects like gui shaders
- // mirrors, or autosprites
- {"noFragment", 0, SURF_NOFRAGMENT, 0 },
- {"slick", 0, SURF_SLICK, 0 },
- {"collision", 0, SURF_COLLISION, 0 },
- {"noimpact", 0, SURF_NOIMPACT, 0 }, // don't make impact explosions or marks
- {"nodamage", 0, SURF_NODAMAGE, 0 }, // no falling damage when hitting
- {"ladder", 0, SURF_LADDER, 0 }, // climbable
- {"nosteps", 0, SURF_NOSTEPS, 0 }, // no footsteps
- // material types for particle, sound, footstep feedback
- {"metal", 0, SURFTYPE_METAL, 0 }, // metal
- {"stone", 0, SURFTYPE_STONE, 0 }, // stone
- {"flesh", 0, SURFTYPE_FLESH, 0 }, // flesh
- {"wood", 0, SURFTYPE_WOOD, 0 }, // wood
- {"cardboard", 0, SURFTYPE_CARDBOARD, 0 }, // cardboard
- {"liquid", 0, SURFTYPE_LIQUID, 0 }, // liquid
- {"glass", 0, SURFTYPE_GLASS, 0 }, // glass
- {"plastic", 0, SURFTYPE_PLASTIC, 0 }, // plastic
- {"ricochet", 0, SURFTYPE_RICOCHET, 0 }, // behaves like metal but causes a ricochet sound
- // unassigned surface types
- {"surftype10", 0, SURFTYPE_10, 0 },
- {"surftype11", 0, SURFTYPE_11, 0 },
- {"surftype12", 0, SURFTYPE_12, 0 },
- {"surftype13", 0, SURFTYPE_13, 0 },
- {"surftype14", 0, SURFTYPE_14, 0 },
- {"surftype15", 0, SURFTYPE_15, 0 },
- };
- static const int numInfoParms = sizeof(infoParms) / sizeof (infoParms[0]);
- /*
- ===============
- idMaterial::CheckSurfaceParm
- See if the current token matches one of the surface parm bit flags
- ===============
- */
- bool idMaterial::CheckSurfaceParm( idToken *token ) {
- for ( int i = 0 ; i < numInfoParms ; i++ ) {
- if ( !token->Icmp( infoParms[i].name ) ) {
- if ( infoParms[i].surfaceFlags & SURF_TYPE_MASK ) {
- // ensure we only have one surface type set
- surfaceFlags &= ~SURF_TYPE_MASK;
- }
- surfaceFlags |= infoParms[i].surfaceFlags;
- contentFlags |= infoParms[i].contents;
- if ( infoParms[i].clearSolid ) {
- contentFlags &= ~CONTENTS_SOLID;
- }
- return true;
- }
- }
- return false;
- }
- /*
- ===============
- idMaterial::MatchToken
- Sets defaultShader and returns false if the next token doesn't match
- ===============
- */
- bool idMaterial::MatchToken( idLexer &src, const char *match ) {
- if ( !src.ExpectTokenString( match ) ) {
- SetMaterialFlag( MF_DEFAULTED );
- return false;
- }
- return true;
- }
- /*
- =================
- idMaterial::ParseSort
- =================
- */
- void idMaterial::ParseSort( idLexer &src ) {
- idToken token;
- if ( !src.ReadTokenOnLine( &token ) ) {
- src.Warning( "missing sort parameter" );
- SetMaterialFlag( MF_DEFAULTED );
- return;
- }
- if ( !token.Icmp( "subview" ) ) {
- sort = SS_SUBVIEW;
- } else if ( !token.Icmp( "opaque" ) ) {
- sort = SS_OPAQUE;
- }else if ( !token.Icmp( "decal" ) ) {
- sort = SS_DECAL;
- } else if ( !token.Icmp( "far" ) ) {
- sort = SS_FAR;
- } else if ( !token.Icmp( "medium" ) ) {
- sort = SS_MEDIUM;
- } else if ( !token.Icmp( "close" ) ) {
- sort = SS_CLOSE;
- } else if ( !token.Icmp( "almostNearest" ) ) {
- sort = SS_ALMOST_NEAREST;
- } else if ( !token.Icmp( "nearest" ) ) {
- sort = SS_NEAREST;
- } else if ( !token.Icmp( "postProcess" ) ) {
- sort = SS_POST_PROCESS;
- } else if ( !token.Icmp( "portalSky" ) ) {
- sort = SS_PORTAL_SKY;
- } else {
- sort = atof( token );
- }
- }
- /*
- =================
- idMaterial::ParseDecalInfo
- =================
- */
- void idMaterial::ParseDecalInfo( idLexer &src ) {
- idToken token;
- decalInfo.stayTime = src.ParseFloat() * 1000;
- decalInfo.fadeTime = src.ParseFloat() * 1000;
- float start[4], end[4];
- src.Parse1DMatrix( 4, start );
- src.Parse1DMatrix( 4, end );
- for ( int i = 0 ; i < 4 ; i++ ) {
- decalInfo.start[i] = start[i];
- decalInfo.end[i] = end[i];
- }
- }
- /*
- =============
- idMaterial::GetExpressionConstant
- =============
- */
- int idMaterial::GetExpressionConstant( float f ) {
- int i;
- for ( i = EXP_REG_NUM_PREDEFINED ; i < numRegisters ; i++ ) {
- if ( !pd->registerIsTemporary[i] && pd->shaderRegisters[i] == f ) {
- return i;
- }
- }
- if ( numRegisters == MAX_EXPRESSION_REGISTERS ) {
- common->Warning( "GetExpressionConstant: material '%s' hit MAX_EXPRESSION_REGISTERS", GetName() );
- SetMaterialFlag( MF_DEFAULTED );
- return 0;
- }
- pd->registerIsTemporary[i] = false;
- pd->shaderRegisters[i] = f;
- numRegisters++;
- return i;
- }
- /*
- =============
- idMaterial::GetExpressionTemporary
- =============
- */
- int idMaterial::GetExpressionTemporary( void ) {
- if ( numRegisters == MAX_EXPRESSION_REGISTERS ) {
- common->Warning( "GetExpressionTemporary: material '%s' hit MAX_EXPRESSION_REGISTERS", GetName() );
- SetMaterialFlag( MF_DEFAULTED );
- return 0;
- }
- pd->registerIsTemporary[numRegisters] = true;
- numRegisters++;
- return numRegisters - 1;
- }
- /*
- =============
- idMaterial::GetExpressionOp
- =============
- */
- expOp_t *idMaterial::GetExpressionOp( void ) {
- if ( numOps == MAX_EXPRESSION_OPS ) {
- common->Warning( "GetExpressionOp: material '%s' hit MAX_EXPRESSION_OPS", GetName() );
- SetMaterialFlag( MF_DEFAULTED );
- return &pd->shaderOps[0];
- }
- return &pd->shaderOps[numOps++];
- }
- /*
- =================
- idMaterial::EmitOp
- =================
- */
- int idMaterial::EmitOp( int a, int b, expOpType_t opType ) {
- expOp_t *op;
- // optimize away identity operations
- if ( opType == OP_TYPE_ADD ) {
- if ( !pd->registerIsTemporary[a] && pd->shaderRegisters[a] == 0 ) {
- return b;
- }
- if ( !pd->registerIsTemporary[b] && pd->shaderRegisters[b] == 0 ) {
- return a;
- }
- if ( !pd->registerIsTemporary[a] && !pd->registerIsTemporary[b] ) {
- return GetExpressionConstant( pd->shaderRegisters[a] + pd->shaderRegisters[b] );
- }
- }
- if ( opType == OP_TYPE_MULTIPLY ) {
- if ( !pd->registerIsTemporary[a] && pd->shaderRegisters[a] == 1 ) {
- return b;
- }
- if ( !pd->registerIsTemporary[a] && pd->shaderRegisters[a] == 0 ) {
- return a;
- }
- if ( !pd->registerIsTemporary[b] && pd->shaderRegisters[b] == 1 ) {
- return a;
- }
- if ( !pd->registerIsTemporary[b] && pd->shaderRegisters[b] == 0 ) {
- return b;
- }
- if ( !pd->registerIsTemporary[a] && !pd->registerIsTemporary[b] ) {
- return GetExpressionConstant( pd->shaderRegisters[a] * pd->shaderRegisters[b] );
- }
- }
- op = GetExpressionOp();
- op->opType = opType;
- op->a = a;
- op->b = b;
- op->c = GetExpressionTemporary();
- return op->c;
- }
- /*
- =================
- idMaterial::ParseEmitOp
- =================
- */
- int idMaterial::ParseEmitOp( idLexer &src, int a, expOpType_t opType, int priority ) {
- int b;
- b = ParseExpressionPriority( src, priority );
- return EmitOp( a, b, opType );
- }
- /*
- =================
- idMaterial::ParseTerm
- Returns a register index
- =================
- */
- int idMaterial::ParseTerm( idLexer &src ) {
- idToken token;
- int a, b;
- src.ReadToken( &token );
- if ( token == "(" ) {
- a = ParseExpression( src );
- MatchToken( src, ")" );
- return a;
- }
- if ( !token.Icmp( "time" ) ) {
- pd->registersAreConstant = false;
- return EXP_REG_TIME;
- }
- if ( !token.Icmp( "parm0" ) ) {
- pd->registersAreConstant = false;
- return EXP_REG_PARM0;
- }
- if ( !token.Icmp( "parm1" ) ) {
- pd->registersAreConstant = false;
- return EXP_REG_PARM1;
- }
- if ( !token.Icmp( "parm2" ) ) {
- pd->registersAreConstant = false;
- return EXP_REG_PARM2;
- }
- if ( !token.Icmp( "parm3" ) ) {
- pd->registersAreConstant = false;
- return EXP_REG_PARM3;
- }
- if ( !token.Icmp( "parm4" ) ) {
- pd->registersAreConstant = false;
- return EXP_REG_PARM4;
- }
- if ( !token.Icmp( "parm5" ) ) {
- pd->registersAreConstant = false;
- return EXP_REG_PARM5;
- }
- if ( !token.Icmp( "parm6" ) ) {
- pd->registersAreConstant = false;
- return EXP_REG_PARM6;
- }
- if ( !token.Icmp( "parm7" ) ) {
- pd->registersAreConstant = false;
- return EXP_REG_PARM7;
- }
- if ( !token.Icmp( "parm8" ) ) {
- pd->registersAreConstant = false;
- return EXP_REG_PARM8;
- }
- if ( !token.Icmp( "parm9" ) ) {
- pd->registersAreConstant = false;
- return EXP_REG_PARM9;
- }
- if ( !token.Icmp( "parm10" ) ) {
- pd->registersAreConstant = false;
- return EXP_REG_PARM10;
- }
- if ( !token.Icmp( "parm11" ) ) {
- pd->registersAreConstant = false;
- return EXP_REG_PARM11;
- }
- if ( !token.Icmp( "global0" ) ) {
- pd->registersAreConstant = false;
- return EXP_REG_GLOBAL0;
- }
- if ( !token.Icmp( "global1" ) ) {
- pd->registersAreConstant = false;
- return EXP_REG_GLOBAL1;
- }
- if ( !token.Icmp( "global2" ) ) {
- pd->registersAreConstant = false;
- return EXP_REG_GLOBAL2;
- }
- if ( !token.Icmp( "global3" ) ) {
- pd->registersAreConstant = false;
- return EXP_REG_GLOBAL3;
- }
- if ( !token.Icmp( "global4" ) ) {
- pd->registersAreConstant = false;
- return EXP_REG_GLOBAL4;
- }
- if ( !token.Icmp( "global5" ) ) {
- pd->registersAreConstant = false;
- return EXP_REG_GLOBAL5;
- }
- if ( !token.Icmp( "global6" ) ) {
- pd->registersAreConstant = false;
- return EXP_REG_GLOBAL6;
- }
- if ( !token.Icmp( "global7" ) ) {
- pd->registersAreConstant = false;
- return EXP_REG_GLOBAL7;
- }
- if ( !token.Icmp( "fragmentPrograms" ) ) {
- return GetExpressionConstant( (float) glConfig.ARBFragmentProgramAvailable );
- }
- if ( !token.Icmp( "sound" ) ) {
- pd->registersAreConstant = false;
- return EmitOp( 0, 0, OP_TYPE_SOUND );
- }
- // parse negative numbers
- if ( token == "-" ) {
- src.ReadToken( &token );
- if ( token.type == TT_NUMBER || token == "." ) {
- return GetExpressionConstant( -(float) token.GetFloatValue() );
- }
- src.Warning( "Bad negative number '%s'", token.c_str() );
- SetMaterialFlag( MF_DEFAULTED );
- return 0;
- }
- if ( token.type == TT_NUMBER || token == "." || token == "-" ) {
- return GetExpressionConstant( (float) token.GetFloatValue() );
- }
- // see if it is a table name
- const idDeclTable *table = static_cast<const idDeclTable *>( declManager->FindType( DECL_TABLE, token.c_str(), false ) );
- if ( !table ) {
- src.Warning( "Bad term '%s'", token.c_str() );
- SetMaterialFlag( MF_DEFAULTED );
- return 0;
- }
- // parse a table expression
- MatchToken( src, "[" );
- b = ParseExpression( src );
- MatchToken( src, "]" );
- return EmitOp( table->Index(), b, OP_TYPE_TABLE );
- }
- /*
- =================
- idMaterial::ParseExpressionPriority
- Returns a register index
- =================
- */
- #define TOP_PRIORITY 4
- int idMaterial::ParseExpressionPriority( idLexer &src, int priority ) {
- idToken token;
- int a;
- if ( priority == 0 ) {
- return ParseTerm( src );
- }
- a = ParseExpressionPriority( src, priority - 1 );
- if ( TestMaterialFlag( MF_DEFAULTED ) ) { // we have a parse error
- return 0;
- }
- if ( !src.ReadToken( &token ) ) {
- // we won't get EOF in a real file, but we can
- // when parsing from generated strings
- return a;
- }
- if ( priority == 1 && token == "*" ) {
- return ParseEmitOp( src, a, OP_TYPE_MULTIPLY, priority );
- }
- if ( priority == 1 && token == "/" ) {
- return ParseEmitOp( src, a, OP_TYPE_DIVIDE, priority );
- }
- if ( priority == 1 && token == "%" ) { // implied truncate both to integer
- return ParseEmitOp( src, a, OP_TYPE_MOD, priority );
- }
- if ( priority == 2 && token == "+" ) {
- return ParseEmitOp( src, a, OP_TYPE_ADD, priority );
- }
- if ( priority == 2 && token == "-" ) {
- return ParseEmitOp( src, a, OP_TYPE_SUBTRACT, priority );
- }
- if ( priority == 3 && token == ">" ) {
- return ParseEmitOp( src, a, OP_TYPE_GT, priority );
- }
- if ( priority == 3 && token == ">=" ) {
- return ParseEmitOp( src, a, OP_TYPE_GE, priority );
- }
- if ( priority == 3 && token == "<" ) {
- return ParseEmitOp( src, a, OP_TYPE_LT, priority );
- }
- if ( priority == 3 && token == "<=" ) {
- return ParseEmitOp( src, a, OP_TYPE_LE, priority );
- }
- if ( priority == 3 && token == "==" ) {
- return ParseEmitOp( src, a, OP_TYPE_EQ, priority );
- }
- if ( priority == 3 && token == "!=" ) {
- return ParseEmitOp( src, a, OP_TYPE_NE, priority );
- }
- if ( priority == 4 && token == "&&" ) {
- return ParseEmitOp( src, a, OP_TYPE_AND, priority );
- }
- if ( priority == 4 && token == "||" ) {
- return ParseEmitOp( src, a, OP_TYPE_OR, priority );
- }
- // assume that anything else terminates the expression
- // not too robust error checking...
- src.UnreadToken( &token );
- return a;
- }
- /*
- =================
- idMaterial::ParseExpression
- Returns a register index
- =================
- */
- int idMaterial::ParseExpression( idLexer &src ) {
- return ParseExpressionPriority( src, TOP_PRIORITY );
- }
- /*
- ===============
- idMaterial::ClearStage
- ===============
- */
- void idMaterial::ClearStage( shaderStage_t *ss ) {
- ss->drawStateBits = 0;
- ss->conditionRegister = GetExpressionConstant( 1 );
- ss->color.registers[0] =
- ss->color.registers[1] =
- ss->color.registers[2] =
- ss->color.registers[3] = GetExpressionConstant( 1 );
- }
- /*
- ===============
- idMaterial::NameToSrcBlendMode
- ===============
- */
- int idMaterial::NameToSrcBlendMode( const idStr &name ) {
- if ( !name.Icmp( "GL_ONE" ) ) {
- return GLS_SRCBLEND_ONE;
- } else if ( !name.Icmp( "GL_ZERO" ) ) {
- return GLS_SRCBLEND_ZERO;
- } else if ( !name.Icmp( "GL_DST_COLOR" ) ) {
- return GLS_SRCBLEND_DST_COLOR;
- } else if ( !name.Icmp( "GL_ONE_MINUS_DST_COLOR" ) ) {
- return GLS_SRCBLEND_ONE_MINUS_DST_COLOR;
- } else if ( !name.Icmp( "GL_SRC_ALPHA" ) ) {
- return GLS_SRCBLEND_SRC_ALPHA;
- } else if ( !name.Icmp( "GL_ONE_MINUS_SRC_ALPHA" ) ) {
- return GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA;
- } else if ( !name.Icmp( "GL_DST_ALPHA" ) ) {
- return GLS_SRCBLEND_DST_ALPHA;
- } else if ( !name.Icmp( "GL_ONE_MINUS_DST_ALPHA" ) ) {
- return GLS_SRCBLEND_ONE_MINUS_DST_ALPHA;
- } else if ( !name.Icmp( "GL_SRC_ALPHA_SATURATE" ) ) {
- return GLS_SRCBLEND_ALPHA_SATURATE;
- }
- common->Warning( "unknown blend mode '%s' in material '%s'", name.c_str(), GetName() );
- SetMaterialFlag( MF_DEFAULTED );
- return GLS_SRCBLEND_ONE;
- }
- /*
- ===============
- idMaterial::NameToDstBlendMode
- ===============
- */
- int idMaterial::NameToDstBlendMode( const idStr &name ) {
- if ( !name.Icmp( "GL_ONE" ) ) {
- return GLS_DSTBLEND_ONE;
- } else if ( !name.Icmp( "GL_ZERO" ) ) {
- return GLS_DSTBLEND_ZERO;
- } else if ( !name.Icmp( "GL_SRC_ALPHA" ) ) {
- return GLS_DSTBLEND_SRC_ALPHA;
- } else if ( !name.Icmp( "GL_ONE_MINUS_SRC_ALPHA" ) ) {
- return GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;
- } else if ( !name.Icmp( "GL_DST_ALPHA" ) ) {
- return GLS_DSTBLEND_DST_ALPHA;
- } else if ( !name.Icmp( "GL_ONE_MINUS_DST_ALPHA" ) ) {
- return GLS_DSTBLEND_ONE_MINUS_DST_ALPHA;
- } else if ( !name.Icmp( "GL_SRC_COLOR" ) ) {
- return GLS_DSTBLEND_SRC_COLOR;
- } else if ( !name.Icmp( "GL_ONE_MINUS_SRC_COLOR" ) ) {
- return GLS_DSTBLEND_ONE_MINUS_SRC_COLOR;
- }
- common->Warning( "unknown blend mode '%s' in material '%s'", name.c_str(), GetName() );
- SetMaterialFlag( MF_DEFAULTED );
- return GLS_DSTBLEND_ONE;
- }
- /*
- ================
- idMaterial::ParseBlend
- ================
- */
- void idMaterial::ParseBlend( idLexer &src, shaderStage_t *stage ) {
- idToken token;
- int srcBlend, dstBlend;
- if ( !src.ReadToken( &token ) ) {
- return;
- }
- // blending combinations
- if ( !token.Icmp( "blend" ) ) {
- stage->drawStateBits = GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;
- return;
- }
- if ( !token.Icmp( "add" ) ) {
- stage->drawStateBits = GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE;
- return;
- }
- if ( !token.Icmp( "filter" ) || !token.Icmp( "modulate" ) ) {
- stage->drawStateBits = GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO;
- return;
- }
- if ( !token.Icmp( "none" ) ) {
- // none is used when defining an alpha mask that doesn't draw
- stage->drawStateBits = GLS_SRCBLEND_ZERO | GLS_DSTBLEND_ONE;
- return;
- }
- if ( !token.Icmp( "bumpmap" ) ) {
- stage->lighting = SL_BUMP;
- return;
- }
- if ( !token.Icmp( "diffusemap" ) ) {
- stage->lighting = SL_DIFFUSE;
- return;
- }
- if ( !token.Icmp( "specularmap" ) ) {
- stage->lighting = SL_SPECULAR;
- return;
- }
- srcBlend = NameToSrcBlendMode( token );
- MatchToken( src, "," );
- if ( !src.ReadToken( &token ) ) {
- return;
- }
- dstBlend = NameToDstBlendMode( token );
- stage->drawStateBits = srcBlend | dstBlend;
- }
- /*
- ================
- idMaterial::ParseVertexParm
- If there is a single value, it will be repeated across all elements
- If there are two values, 3 = 0.0, 4 = 1.0
- if there are three values, 4 = 1.0
- ================
- */
- void idMaterial::ParseVertexParm( idLexer &src, newShaderStage_t *newStage ) {
- idToken token;
- src.ReadTokenOnLine( &token );
- int parm = token.GetIntValue();
- if ( !token.IsNumeric() || parm < 0 || parm >= MAX_VERTEX_PARMS ) {
- common->Warning( "bad vertexParm number\n" );
- SetMaterialFlag( MF_DEFAULTED );
- return;
- }
- if ( parm >= newStage->numVertexParms ) {
- newStage->numVertexParms = parm+1;
- }
- newStage->vertexParms[parm][0] = ParseExpression( src );
- src.ReadTokenOnLine( &token );
- if ( !token[0] || token.Icmp( "," ) ) {
- newStage->vertexParms[parm][1] =
- newStage->vertexParms[parm][2] =
- newStage->vertexParms[parm][3] = newStage->vertexParms[parm][0];
- return;
- }
- newStage->vertexParms[parm][1] = ParseExpression( src );
- src.ReadTokenOnLine( &token );
- if ( !token[0] || token.Icmp( "," ) ) {
- newStage->vertexParms[parm][2] = GetExpressionConstant( 0 );
- newStage->vertexParms[parm][3] = GetExpressionConstant( 1 );
- return;
- }
- newStage->vertexParms[parm][2] = ParseExpression( src );
- src.ReadTokenOnLine( &token );
- if ( !token[0] || token.Icmp( "," ) ) {
- newStage->vertexParms[parm][3] = GetExpressionConstant( 1 );
- return;
- }
- newStage->vertexParms[parm][3] = ParseExpression( src );
- }
- /*
- ================
- idMaterial::ParseFragmentMap
- ================
- */
- void idMaterial::ParseFragmentMap( idLexer &src, newShaderStage_t *newStage ) {
- const char *str;
- textureFilter_t tf;
- textureRepeat_t trp;
- textureDepth_t td;
- cubeFiles_t cubeMap;
- bool allowPicmip;
- idToken token;
- tf = TF_DEFAULT;
- trp = TR_REPEAT;
- td = TD_DEFAULT;
- allowPicmip = true;
- cubeMap = CF_2D;
- src.ReadTokenOnLine( &token );
- int unit = token.GetIntValue();
- if ( !token.IsNumeric() || unit < 0 || unit >= MAX_FRAGMENT_IMAGES ) {
- common->Warning( "bad fragmentMap number\n" );
- SetMaterialFlag( MF_DEFAULTED );
- return;
- }
- // unit 1 is the normal map.. make sure it gets flagged as the proper depth
- if ( unit == 1 ) {
- td = TD_BUMP;
- }
- if ( unit >= newStage->numFragmentProgramImages ) {
- newStage->numFragmentProgramImages = unit+1;
- }
- while( 1 ) {
- src.ReadTokenOnLine( &token );
- if ( !token.Icmp( "cubeMap" ) ) {
- cubeMap = CF_NATIVE;
- continue;
- }
- if ( !token.Icmp( "cameraCubeMap" ) ) {
- cubeMap = CF_CAMERA;
- continue;
- }
- if ( !token.Icmp( "nearest" ) ) {
- tf = TF_NEAREST;
- continue;
- }
- if ( !token.Icmp( "linear" ) ) {
- tf = TF_LINEAR;
- continue;
- }
- if ( !token.Icmp( "clamp" ) ) {
- trp = TR_CLAMP;
- continue;
- }
- if ( !token.Icmp( "noclamp" ) ) {
- trp = TR_REPEAT;
- continue;
- }
- if ( !token.Icmp( "zeroclamp" ) ) {
- trp = TR_CLAMP_TO_ZERO;
- continue;
- }
- if ( !token.Icmp( "alphazeroclamp" ) ) {
- trp = TR_CLAMP_TO_ZERO_ALPHA;
- continue;
- }
- if ( !token.Icmp( "forceHighQuality" ) ) {
- td = TD_HIGH_QUALITY;
- continue;
- }
- if ( !token.Icmp( "uncompressed" ) || !token.Icmp( "highquality" ) ) {
- if ( !globalImages->image_ignoreHighQuality.GetInteger() ) {
- td = TD_HIGH_QUALITY;
- }
- continue;
- }
- if ( !token.Icmp( "nopicmip" ) ) {
- allowPicmip = false;
- continue;
- }
- // assume anything else is the image name
- src.UnreadToken( &token );
- break;
- }
- str = R_ParsePastImageProgram( src );
- newStage->fragmentProgramImages[unit] =
- globalImages->ImageFromFile( str, tf, allowPicmip, trp, td, cubeMap );
- if ( !newStage->fragmentProgramImages[unit] ) {
- newStage->fragmentProgramImages[unit] = globalImages->defaultImage;
- }
- }
- /*
- ===============
- idMaterial::MultiplyTextureMatrix
- ===============
- */
- void idMaterial::MultiplyTextureMatrix( textureStage_t *ts, int registers[2][3] ) {
- int old[2][3];
- if ( !ts->hasMatrix ) {
- ts->hasMatrix = true;
- memcpy( ts->matrix, registers, sizeof( ts->matrix ) );
- return;
- }
- memcpy( old, ts->matrix, sizeof( old ) );
- // multiply the two maticies
- ts->matrix[0][0] = EmitOp(
- EmitOp( old[0][0], registers[0][0], OP_TYPE_MULTIPLY ),
- EmitOp( old[0][1], registers[1][0], OP_TYPE_MULTIPLY ), OP_TYPE_ADD );
- ts->matrix[0][1] = EmitOp(
- EmitOp( old[0][0], registers[0][1], OP_TYPE_MULTIPLY ),
- EmitOp( old[0][1], registers[1][1], OP_TYPE_MULTIPLY ), OP_TYPE_ADD );
- ts->matrix[0][2] = EmitOp(
- EmitOp(
- EmitOp( old[0][0], registers[0][2], OP_TYPE_MULTIPLY ),
- EmitOp( old[0][1], registers[1][2], OP_TYPE_MULTIPLY ), OP_TYPE_ADD ),
- old[0][2], OP_TYPE_ADD );
- ts->matrix[1][0] = EmitOp(
- EmitOp( old[1][0], registers[0][0], OP_TYPE_MULTIPLY ),
- EmitOp( old[1][1], registers[1][0], OP_TYPE_MULTIPLY ), OP_TYPE_ADD );
- ts->matrix[1][1] = EmitOp(
- EmitOp( old[1][0], registers[0][1], OP_TYPE_MULTIPLY ),
- EmitOp( old[1][1], registers[1][1], OP_TYPE_MULTIPLY ), OP_TYPE_ADD );
- ts->matrix[1][2] = EmitOp(
- EmitOp(
- EmitOp( old[1][0], registers[0][2], OP_TYPE_MULTIPLY ),
- EmitOp( old[1][1], registers[1][2], OP_TYPE_MULTIPLY ), OP_TYPE_ADD ),
- old[1][2], OP_TYPE_ADD );
- }
- /*
- =================
- idMaterial::ParseStage
- An open brace has been parsed
- {
- if <expression>
- map <imageprogram>
- "nearest" "linear" "clamp" "zeroclamp" "uncompressed" "highquality" "nopicmip"
- scroll, scale, rotate
- }
- =================
- */
- void idMaterial::ParseStage( idLexer &src, const textureRepeat_t trpDefault ) {
- idToken token;
- const char *str;
- shaderStage_t *ss;
- textureStage_t *ts;
- textureFilter_t tf;
- textureRepeat_t trp;
- textureDepth_t td;
- cubeFiles_t cubeMap;
- bool allowPicmip;
- char imageName[MAX_IMAGE_NAME];
- int a, b;
- int matrix[2][3];
- newShaderStage_t newStage;
- if ( numStages >= MAX_SHADER_STAGES ) {
- SetMaterialFlag( MF_DEFAULTED );
- common->Warning( "material '%s' exceeded %i stages", GetName(), MAX_SHADER_STAGES );
- }
- tf = TF_DEFAULT;
- trp = trpDefault;
- td = TD_DEFAULT;
- allowPicmip = true;
- cubeMap = CF_2D;
- imageName[0] = 0;
- memset( &newStage, 0, sizeof( newStage ) );
- ss = &pd->parseStages[numStages];
- ts = &ss->texture;
- ClearStage( ss );
- while ( 1 ) {
- if ( TestMaterialFlag( MF_DEFAULTED ) ) { // we have a parse error
- return;
- }
- if ( !src.ExpectAnyToken( &token ) ) {
- SetMaterialFlag( MF_DEFAULTED );
- return;
- }
- // the close brace for the entire material ends the draw block
- if ( token == "}" ) {
- break;
- }
- //BSM Nerve: Added for stage naming in the material editor
- if( !token.Icmp( "name") ) {
- src.SkipRestOfLine();
- continue;
- }
- // image options
- if ( !token.Icmp( "blend" ) ) {
- ParseBlend( src, ss );
- continue;
- }
- if ( !token.Icmp( "map" ) ) {
- str = R_ParsePastImageProgram( src );
- idStr::Copynz( imageName, str, sizeof( imageName ) );
- continue;
- }
- if ( !token.Icmp( "remoteRenderMap" ) ) {
- ts->dynamic = DI_REMOTE_RENDER;
- ts->width = src.ParseInt();
- ts->height = src.ParseInt();
- continue;
- }
- if ( !token.Icmp( "mirrorRenderMap" ) ) {
- ts->dynamic = DI_MIRROR_RENDER;
- ts->width = src.ParseInt();
- ts->height = src.ParseInt();
- ts->texgen = TG_SCREEN;
- continue;
- }
- if ( !token.Icmp( "xrayRenderMap" ) ) {
- ts->dynamic = DI_XRAY_RENDER;
- ts->width = src.ParseInt();
- ts->height = src.ParseInt();
- ts->texgen = TG_SCREEN;
- continue;
- }
- if ( !token.Icmp( "screen" ) ) {
- ts->texgen = TG_SCREEN;
- continue;
- }
- if ( !token.Icmp( "screen2" ) ) {
- ts->texgen = TG_SCREEN2;
- continue;
- }
- if ( !token.Icmp( "glassWarp" ) ) {
- ts->texgen = TG_GLASSWARP;
- continue;
- }
- if ( !token.Icmp( "videomap" ) ) {
- // note that videomaps will always be in clamp mode, so texture
- // coordinates had better be in the 0 to 1 range
- if ( !src.ReadToken( &token ) ) {
- common->Warning( "missing parameter for 'videoMap' keyword in material '%s'", GetName() );
- continue;
- }
- bool loop = false;
- if ( !token.Icmp( "loop" ) ) {
- loop = true;
- if ( !src.ReadToken( &token ) ) {
- common->Warning( "missing parameter for 'videoMap' keyword in material '%s'", GetName() );
- continue;
- }
- }
- ts->cinematic = idCinematic::Alloc();
- ts->cinematic->InitFromFile( token.c_str(), loop );
- continue;
- }
- if ( !token.Icmp( "soundmap" ) ) {
- if ( !src.ReadToken( &token ) ) {
- common->Warning( "missing parameter for 'soundmap' keyword in material '%s'", GetName() );
- continue;
- }
- ts->cinematic = new idSndWindow();
- ts->cinematic->InitFromFile( token.c_str(), true );
- continue;
- }
- if ( !token.Icmp( "cubeMap" ) ) {
- str = R_ParsePastImageProgram( src );
- idStr::Copynz( imageName, str, sizeof( imageName ) );
- cubeMap = CF_NATIVE;
- continue;
- }
- if ( !token.Icmp( "cameraCubeMap" ) ) {
- str = R_ParsePastImageProgram( src );
- idStr::Copynz( imageName, str, sizeof( imageName ) );
- cubeMap = CF_CAMERA;
- continue;
- }
- if ( !token.Icmp( "ignoreAlphaTest" ) ) {
- ss->ignoreAlphaTest = true;
- continue;
- }
- if ( !token.Icmp( "nearest" ) ) {
- tf = TF_NEAREST;
- continue;
- }
- if ( !token.Icmp( "linear" ) ) {
- tf = TF_LINEAR;
- continue;
- }
- if ( !token.Icmp( "clamp" ) ) {
- trp = TR_CLAMP;
- continue;
- }
- if ( !token.Icmp( "noclamp" ) ) {
- trp = TR_REPEAT;
- continue;
- }
- if ( !token.Icmp( "zeroclamp" ) ) {
- trp = TR_CLAMP_TO_ZERO;
- continue;
- }
- if ( !token.Icmp( "alphazeroclamp" ) ) {
- trp = TR_CLAMP_TO_ZERO_ALPHA;
- continue;
- }
- if ( !token.Icmp( "uncompressed" ) || !token.Icmp( "highquality" ) ) {
- if ( !globalImages->image_ignoreHighQuality.GetInteger() ) {
- td = TD_HIGH_QUALITY;
- }
- continue;
- }
- if ( !token.Icmp( "forceHighQuality" ) ) {
- td = TD_HIGH_QUALITY;
- continue;
- }
- if ( !token.Icmp( "nopicmip" ) ) {
- allowPicmip = false;
- continue;
- }
- if ( !token.Icmp( "vertexColor" ) ) {
- ss->vertexColor = SVC_MODULATE;
- continue;
- }
- if ( !token.Icmp( "inverseVertexColor" ) ) {
- ss->vertexColor = SVC_INVERSE_MODULATE;
- continue;
- }
- // privatePolygonOffset
- else if ( !token.Icmp( "privatePolygonOffset" ) ) {
- if ( !src.ReadTokenOnLine( &token ) ) {
- ss->privatePolygonOffset = 1;
- continue;
- }
- // explict larger (or negative) offset
- src.UnreadToken( &token );
- ss->privatePolygonOffset = src.ParseFloat();
- continue;
- }
- // texture coordinate generation
- if ( !token.Icmp( "texGen" ) ) {
- src.ExpectAnyToken( &token );
- if ( !token.Icmp( "normal" ) ) {
- ts->texgen = TG_DIFFUSE_CUBE;
- } else if ( !token.Icmp( "reflect" ) ) {
- ts->texgen = TG_REFLECT_CUBE;
- } else if ( !token.Icmp( "skybox" ) ) {
- ts->texgen = TG_SKYBOX_CUBE;
- } else if ( !token.Icmp( "wobbleSky" ) ) {
- ts->texgen = TG_WOBBLESKY_CUBE;
- texGenRegisters[0] = ParseExpression( src );
- texGenRegisters[1] = ParseExpression( src );
- texGenRegisters[2] = ParseExpression( src );
- } else {
- common->Warning( "bad texGen '%s' in material %s", token.c_str(), GetName() );
- SetMaterialFlag( MF_DEFAULTED );
- }
- continue;
- }
- if ( !token.Icmp( "scroll" ) || !token.Icmp( "translate" ) ) {
- a = ParseExpression( src );
- MatchToken( src, "," );
- b = ParseExpression( src );
- matrix[0][0] = GetExpressionConstant( 1 );
- matrix[0][1] = GetExpressionConstant( 0 );
- matrix[0][2] = a;
- matrix[1][0] = GetExpressionConstant( 0 );
- matrix[1][1] = GetExpressionConstant( 1 );
- matrix[1][2] = b;
- MultiplyTextureMatrix( ts, matrix );
- continue;
- }
- if ( !token.Icmp( "scale" ) ) {
- a = ParseExpression( src );
- MatchToken( src, "," );
- b = ParseExpression( src );
- // this just scales without a centering
- matrix[0][0] = a;
- matrix[0][1] = GetExpressionConstant( 0 );
- matrix[0][2] = GetExpressionConstant( 0 );
- matrix[1][0] = GetExpressionConstant( 0 );
- matrix[1][1] = b;
- matrix[1][2] = GetExpressionConstant( 0 );
- MultiplyTextureMatrix( ts, matrix );
- continue;
- }
- if ( !token.Icmp( "centerScale" ) ) {
- a = ParseExpression( src );
- MatchToken( src, "," );
- b = ParseExpression( src );
- // this subtracts 0.5, then scales, then adds 0.5
- matrix[0][0] = a;
- matrix[0][1] = GetExpressionConstant( 0 );
- matrix[0][2] = EmitOp( GetExpressionConstant( 0.5 ), EmitOp( GetExpressionConstant( 0.5 ), a, OP_TYPE_MULTIPLY ), OP_TYPE_SUBTRACT );
- matrix[1][0] = GetExpressionConstant( 0 );
- matrix[1][1] = b;
- matrix[1][2] = EmitOp( GetExpressionConstant( 0.5 ), EmitOp( GetExpressionConstant( 0.5 ), b, OP_TYPE_MULTIPLY ), OP_TYPE_SUBTRACT );
- MultiplyTextureMatrix( ts, matrix );
- continue;
- }
- if ( !token.Icmp( "shear" ) ) {
- a = ParseExpression( src );
- MatchToken( src, "," );
- b = ParseExpression( src );
- // this subtracts 0.5, then shears, then adds 0.5
- matrix[0][0] = GetExpressionConstant( 1 );
- matrix[0][1] = a;
- matrix[0][2] = EmitOp( GetExpressionConstant( -0.5 ), a, OP_TYPE_MULTIPLY );
- matrix[1][0] = b;
- matrix[1][1] = GetExpressionConstant( 1 );
- matrix[1][2] = EmitOp( GetExpressionConstant( -0.5 ), b, OP_TYPE_MULTIPLY );
- MultiplyTextureMatrix( ts, matrix );
- continue;
- }
- if ( !token.Icmp( "rotate" ) ) {
- const idDeclTable *table;
- int sinReg, cosReg;
- // in cycles
- a = ParseExpression( src );
- table = static_cast<const idDeclTable *>( declManager->FindType( DECL_TABLE, "sinTable", false ) );
- if ( !table ) {
- common->Warning( "no sinTable for rotate defined" );
- SetMaterialFlag( MF_DEFAULTED );
- return;
- }
- sinReg = EmitOp( table->Index(), a, OP_TYPE_TABLE );
- table = static_cast<const idDeclTable *>( declManager->FindType( DECL_TABLE, "cosTable", false ) );
- if ( !table ) {
- common->Warning( "no cosTable for rotate defined" );
- SetMaterialFlag( MF_DEFAULTED );
- return;
- }
- cosReg = EmitOp( table->Index(), a, OP_TYPE_TABLE );
- // this subtracts 0.5, then rotates, then adds 0.5
- matrix[0][0] = cosReg;
- matrix[0][1] = EmitOp( GetExpressionConstant( 0 ), sinReg, OP_TYPE_SUBTRACT );
- matrix[0][2] = EmitOp( EmitOp( EmitOp( GetExpressionConstant( -0.5 ), cosReg, OP_TYPE_MULTIPLY ),
- EmitOp( GetExpressionConstant( 0.5 ), sinReg, OP_TYPE_MULTIPLY ), OP_TYPE_ADD ),
- GetExpressionConstant( 0.5 ), OP_TYPE_ADD );
- matrix[1][0] = sinReg;
- matrix[1][1] = cosReg;
- matrix[1][2] = EmitOp( EmitOp( EmitOp( GetExpressionConstant( -0.5 ), sinReg, OP_TYPE_MULTIPLY ),
- EmitOp( GetExpressionConstant( -0.5 ), cosReg, OP_TYPE_MULTIPLY ), OP_TYPE_ADD ),
- GetExpressionConstant( 0.5 ), OP_TYPE_ADD );
- MultiplyTextureMatrix( ts, matrix );
- continue;
- }
- // color mask options
- if ( !token.Icmp( "maskRed" ) ) {
- ss->drawStateBits |= GLS_REDMASK;
- continue;
- }
- if ( !token.Icmp( "maskGreen" ) ) {
- ss->drawStateBits |= GLS_GREENMASK;
- continue;
- }
- if ( !token.Icmp( "maskBlue" ) ) {
- ss->drawStateBits |= GLS_BLUEMASK;
- continue;
- }
- if ( !token.Icmp( "maskAlpha" ) ) {
- ss->drawStateBits |= GLS_ALPHAMASK;
- continue;
- }
- if ( !token.Icmp( "maskColor" ) ) {
- ss->drawStateBits |= GLS_COLORMASK;
- continue;
- }
- if ( !token.Icmp( "maskDepth" ) ) {
- ss->drawStateBits |= GLS_DEPTHMASK;
- continue;
- }
- if ( !token.Icmp( "alphaTest" ) ) {
- ss->hasAlphaTest = true;
- ss->alphaTestRegister = ParseExpression( src );
- coverage = MC_PERFORATED;
- continue;
- }
- // shorthand for 2D modulated
- if ( !token.Icmp( "colored" ) ) {
- ss->color.registers[0] = EXP_REG_PARM0;
- ss->color.registers[1] = EXP_REG_PARM1;
- ss->color.registers[2] = EXP_REG_PARM2;
- ss->color.registers[3] = EXP_REG_PARM3;
- pd->registersAreConstant = false;
- continue;
- }
- if ( !token.Icmp( "color" ) ) {
- ss->color.registers[0] = ParseExpression( src );
- MatchToken( src, "," );
- ss->color.registers[1] = ParseExpression( src );
- MatchToken( src, "," );
- ss->color.registers[2] = ParseExpression( src );
- MatchToken( src, "," );
- ss->color.registers[3] = ParseExpression( src );
- continue;
- }
- if ( !token.Icmp( "red" ) ) {
- ss->color.registers[0] = ParseExpression( src );
- continue;
- }
- if ( !token.Icmp( "green" ) ) {
- ss->color.registers[1] = ParseExpression( src );
- continue;
- }
- if ( !token.Icmp( "blue" ) ) {
- ss->color.registers[2] = ParseExpression( src );
- continue;
- }
- if ( !token.Icmp( "alpha" ) ) {
- ss->color.registers[3] = ParseExpression( src );
- continue;
- }
- if ( !token.Icmp( "rgb" ) ) {
- ss->color.registers[0] = ss->color.registers[1] =
- ss->color.registers[2] = ParseExpression( src );
- continue;
- }
- if ( !token.Icmp( "rgba" ) ) {
- ss->color.registers[0] = ss->color.registers[1] =
- ss->color.registers[2] = ss->color.registers[3] = ParseExpression( src );
- continue;
- }
- if ( !token.Icmp( "if" ) ) {
- ss->conditionRegister = ParseExpression( src );
- continue;
- }
- if ( !token.Icmp( "program" ) ) {
- if ( src.ReadTokenOnLine( &token ) ) {
- newStage.vertexProgram = R_FindARBProgram( GL_VERTEX_PROGRAM_ARB, token.c_str() );
- newStage.fragmentProgram = R_FindARBProgram( GL_FRAGMENT_PROGRAM_ARB, token.c_str() );
- }
- continue;
- }
- if ( !token.Icmp( "fragmentProgram" ) ) {
- if ( src.ReadTokenOnLine( &token ) ) {
- newStage.fragmentProgram = R_FindARBProgram( GL_FRAGMENT_PROGRAM_ARB, token.c_str() );
- }
- continue;
- }
- if ( !token.Icmp( "vertexProgram" ) ) {
- if ( src.ReadTokenOnLine( &token ) ) {
- newStage.vertexProgram = R_FindARBProgram( GL_VERTEX_PROGRAM_ARB, token.c_str() );
- }
- continue;
- }
- if ( !token.Icmp( "megaTexture" ) ) {
- if ( src.ReadTokenOnLine( &token ) ) {
- newStage.megaTexture = new idMegaTexture;
- if ( !newStage.megaTexture->InitFromMegaFile( token.c_str() ) ) {
- delete newStage.megaTexture;
- SetMaterialFlag( MF_DEFAULTED );
- continue;
- }
- newStage.vertexProgram = R_FindARBProgram( GL_VERTEX_PROGRAM_ARB, "megaTexture.vfp" );
- newStage.fragmentProgram = R_FindARBProgram( GL_FRAGMENT_PROGRAM_ARB, "megaTexture.vfp" );
- continue;
- }
- }
- if ( !token.Icmp( "vertexParm" ) ) {
- ParseVertexParm( src, &newStage );
- continue;
- }
- if ( !token.Icmp( "fragmentMap" ) ) {
- ParseFragmentMap( src, &newStage );
- continue;
- }
- common->Warning( "unknown token '%s' in material '%s'", token.c_str(), GetName() );
- SetMaterialFlag( MF_DEFAULTED );
- return;
- }
- // if we are using newStage, allocate a copy of it
- if ( newStage.fragmentProgram || newStage.vertexProgram ) {
- ss->newStage = (newShaderStage_t *)Mem_Alloc( sizeof( newStage ) );
- *(ss->newStage) = newStage;
- }
- // successfully parsed a stage
- numStages++;
- // select a compressed depth based on what the stage is
- if ( td == TD_DEFAULT ) {
- switch( ss->lighting ) {
- case SL_BUMP:
- td = TD_BUMP;
- break;
- case SL_DIFFUSE:
- td = TD_DIFFUSE;
- break;
- case SL_SPECULAR:
- td = TD_SPECULAR;
- break;
- default:
- break;
- }
- }
- // now load the image with all the parms we parsed
- if ( imageName[0] ) {
- ts->image = globalImages->ImageFromFile( imageName, tf, allowPicmip, trp, td, cubeMap );
- if ( !ts->image ) {
- ts->image = globalImages->defaultImage;
- }
- } else if ( !ts->cinematic && !ts->dynamic && !ss->newStage ) {
- common->Warning( "material '%s' had stage with no image", GetName() );
- ts->image = globalImages->defaultImage;
- }
- }
- /*
- ===============
- idMaterial::ParseDeform
- ===============
- */
- void idMaterial::ParseDeform( idLexer &src ) {
- idToken token;
- if ( !src.ExpectAnyToken( &token ) ) {
- return;
- }
- if ( !token.Icmp( "sprite" ) ) {
- deform = DFRM_SPRITE;
- cullType = CT_TWO_SIDED;
- SetMaterialFlag( MF_NOSHADOWS );
- return;
- }
- if ( !token.Icmp( "tube" ) ) {
- deform = DFRM_TUBE;
- cullType = CT_TWO_SIDED;
- SetMaterialFlag( MF_NOSHADOWS );
- return;
- }
- if ( !token.Icmp( "flare" ) ) {
- deform = DFRM_FLARE;
- cullType = CT_TWO_SIDED;
- deformRegisters[0] = ParseExpression( src );
- SetMaterialFlag( MF_NOSHADOWS );
- return;
- }
- if ( !token.Icmp( "expand" ) ) {
- deform = DFRM_EXPAND;
- deformRegisters[0] = ParseExpression( src );
- return;
- }
- if ( !token.Icmp( "move" ) ) {
- deform = DFRM_MOVE;
- deformRegisters[0] = ParseExpression( src );
- return;
- }
- if ( !token.Icmp( "turbulent" ) ) {
- deform = DFRM_TURB;
- if ( !src.ExpectAnyToken( &token ) ) {
- src.Warning( "deform particle missing particle name" );
- SetMaterialFlag( MF_DEFAULTED );
- return;
- }
- deformDecl = declManager->FindType( DECL_TABLE, token.c_str(), true );
- deformRegisters[0] = ParseExpression( src );
- deformRegisters[1] = ParseExpression( src );
- deformRegisters[2] = ParseExpression( src );
- return;
- }
- if ( !token.Icmp( "eyeBall" ) ) {
- deform = DFRM_EYEBALL;
- return;
- }
- if ( !token.Icmp( "particle" ) ) {
- deform = DFRM_PARTICLE;
- if ( !src.ExpectAnyToken( &token ) ) {
- src.Warning( "deform particle missing particle name" );
- SetMaterialFlag( MF_DEFAULTED );
- return;
- }
- deformDecl = declManager->FindType( DECL_PARTICLE, token.c_str(), true );
- return;
- }
- if ( !token.Icmp( "particle2" ) ) {
- deform = DFRM_PARTICLE2;
- if ( !src.ExpectAnyToken( &token ) ) {
- src.Warning( "deform particle missing particle name" );
- SetMaterialFlag( MF_DEFAULTED );
- return;
- }
- deformDecl = declManager->FindType( DECL_PARTICLE, token.c_str(), true );
- return;
- }
- src.Warning( "Bad deform type '%s'", token.c_str() );
- SetMaterialFlag( MF_DEFAULTED );
- }
- /*
- ==============
- idMaterial::AddImplicitStages
- If a material has diffuse or specular stages without any
- bump stage, add an implicit _flat bumpmap stage.
- If a material has a bump stage but no diffuse or specular
- stage, add a _white diffuse stage.
- It is valid to have either a diffuse or specular without the other.
- It is valid to have a reflection map and a bump map for bumpy reflection
- ==============
- */
- void idMaterial::AddImplicitStages( const textureRepeat_t trpDefault /* = TR_REPEAT */ ) {
- char buffer[1024];
- idLexer newSrc;
- bool hasDiffuse = false;
- bool hasSpecular = false;
- bool hasBump = false;
- bool hasReflection = false;
- for ( int i = 0 ; i < numStages ; i++ ) {
- if ( pd->parseStages[i].lighting == SL_BUMP ) {
- hasBump = true;
- }
- if ( pd->parseStages[i].lighting == SL_DIFFUSE ) {
- hasDiffuse = true;
- }
- if ( pd->parseStages[i].lighting == SL_SPECULAR ) {
- hasSpecular = true;
- }
- if ( pd->parseStages[i].texture.texgen == TG_REFLECT_CUBE ) {
- hasReflection = true;
- }
- }
- // if it doesn't have an interaction at all, don't add anything
- if ( !hasBump && !hasDiffuse && !hasSpecular ) {
- return;
- }
- if ( numStages == MAX_SHADER_STAGES ) {
- return;
- }
- if ( !hasBump ) {
- idStr::snPrintf( buffer, sizeof( buffer ), "blend bumpmap\nmap _flat\n}\n" );
- newSrc.LoadMemory( buffer, strlen(buffer), "bumpmap" );
- newSrc.SetFlags( LEXFL_NOFATALERRORS | LEXFL_NOSTRINGCONCAT | LEXFL_NOSTRINGESCAPECHARS | LEXFL_ALLOWPATHNAMES );
- ParseStage( newSrc, trpDefault );
- newSrc.FreeSource();
- }
- if ( !hasDiffuse && !hasSpecular && !hasReflection ) {
- idStr::snPrintf( buffer, sizeof( buffer ), "blend diffusemap\nmap _white\n}\n" );
- newSrc.LoadMemory( buffer, strlen(buffer), "diffusemap" );
- newSrc.SetFlags( LEXFL_NOFATALERRORS | LEXFL_NOSTRINGCONCAT | LEXFL_NOSTRINGESCAPECHARS | LEXFL_ALLOWPATHNAMES );
- ParseStage( newSrc, trpDefault );
- newSrc.FreeSource();
- }
- }
- /*
- ===============
- idMaterial::SortInteractionStages
- The renderer expects bump, then diffuse, then specular
- There can be multiple bump maps, followed by additional
- diffuse and specular stages, which allows cross-faded bump mapping.
- Ambient stages can be interspersed anywhere, but they are
- ignored during interactions, and all the interaction
- stages are ignored during ambient drawing.
- ===============
- */
- void idMaterial::SortInteractionStages() {
- int j;
- for ( int i = 0 ; i < numStages ; i = j ) {
- // find the next bump map
- for ( j = i + 1 ; j < numStages ; j++ ) {
- if ( pd->parseStages[j].lighting == SL_BUMP ) {
- // if the very first stage wasn't a bumpmap,
- // this bumpmap is part of the first group
- if ( pd->parseStages[i].lighting != SL_BUMP ) {
- continue;
- }
- break;
- }
- }
- // bubble sort everything bump / diffuse / specular
- for ( int l = 1 ; l < j-i ; l++ ) {
- for ( int k = i ; k < j-l ; k++ ) {
- if ( pd->parseStages[k].lighting > pd->parseStages[k+1].lighting ) {
- shaderStage_t temp;
- temp = pd->parseStages[k];
- pd->parseStages[k] = pd->parseStages[k+1];
- pd->parseStages[k+1] = temp;
- }
- }
- }
- }
- }
- /*
- =================
- idMaterial::ParseMaterial
- The current text pointer is at the explicit text definition of the
- Parse it into the global material variable. Later functions will optimize it.
- If there is any error during parsing, defaultShader will be set.
- =================
- */
- void idMaterial::ParseMaterial( idLexer &src ) {
- idToken token;
- int s;
- char buffer[1024];
- const char *str;
- idLexer newSrc;
- int i;
- s = 0;
- numOps = 0;
- numRegisters = EXP_REG_NUM_PREDEFINED; // leave space for the parms to be copied in
- for ( i = 0 ; i < numRegisters ; i++ ) {
- pd->registerIsTemporary[i] = true; // they aren't constants that can be folded
- }
- numStages = 0;
- textureRepeat_t trpDefault = TR_REPEAT; // allow a global setting for repeat
- while ( 1 ) {
- if ( TestMaterialFlag( MF_DEFAULTED ) ) { // we have a parse error
- return;
- }
- if ( !src.ExpectAnyToken( &token ) ) {
- SetMaterialFlag( MF_DEFAULTED );
- return;
- }
- // end of material definition
- if ( token == "}" ) {
- break;
- }
- else if ( !token.Icmp( "qer_editorimage") ) {
- src.ReadTokenOnLine( &token );
- editorImageName = token.c_str();
- src.SkipRestOfLine();
- continue;
- }
- // description
- else if ( !token.Icmp( "description") ) {
- src.ReadTokenOnLine( &token );
- desc = token.c_str();
- continue;
- }
- // check for the surface / content bit flags
- else if ( CheckSurfaceParm( &token ) ) {
- continue;
- }
- // polygonOffset
- else if ( !token.Icmp( "polygonOffset" ) ) {
- SetMaterialFlag( MF_POLYGONOFFSET );
- if ( !src.ReadTokenOnLine( &token ) ) {
- polygonOffset = 1;
- continue;
- }
- // explict larger (or negative) offset
- polygonOffset = token.GetFloatValue();
- continue;
- }
- // noshadow
- else if ( !token.Icmp( "noShadows" ) ) {
- SetMaterialFlag( MF_NOSHADOWS );
- continue;
- }
- else if ( !token.Icmp( "suppressInSubview" ) ) {
- suppressInSubview = true;
- continue;
- }
- else if ( !token.Icmp( "portalSky" ) ) {
- portalSky = true;
- continue;
- }
- // noSelfShadow
- else if ( !token.Icmp( "noSelfShadow" ) ) {
- SetMaterialFlag( MF_NOSELFSHADOW );
- continue;
- }
- // noPortalFog
- else if ( !token.Icmp( "noPortalFog" ) ) {
- SetMaterialFlag( MF_NOPORTALFOG );
- continue;
- }
- // forceShadows allows nodraw surfaces to cast shadows
- else if ( !token.Icmp( "forceShadows" ) ) {
- SetMaterialFlag( MF_FORCESHADOWS );
- continue;
- }
- // overlay / decal suppression
- else if ( !token.Icmp( "noOverlays" ) ) {
- allowOverlays = false;
- continue;
- }
- // moster blood overlay forcing for alpha tested or translucent surfaces
- else if ( !token.Icmp( "forceOverlays" ) ) {
- pd->forceOverlays = true;
- continue;
- }
- // translucent
- else if ( !token.Icmp( "translucent" ) ) {
- coverage = MC_TRANSLUCENT;
- continue;
- }
- // global zero clamp
- else if ( !token.Icmp( "zeroclamp" ) ) {
- trpDefault = TR_CLAMP_TO_ZERO;
- continue;
- }
- // global clamp
- else if ( !token.Icmp( "clamp" ) ) {
- trpDefault = TR_CLAMP;
- continue;
- }
- // global clamp
- else if ( !token.Icmp( "alphazeroclamp" ) ) {
- trpDefault = TR_CLAMP_TO_ZERO;
- continue;
- }
- // forceOpaque is used for skies-behind-windows
- else if ( !token.Icmp( "forceOpaque" ) ) {
- coverage = MC_OPAQUE;
- continue;
- }
- // twoSided
- else if ( !token.Icmp( "twoSided" ) ) {
- cullType = CT_TWO_SIDED;
- // twoSided implies no-shadows, because the shadow
- // volume would be coplanar with the surface, giving depth fighting
- // we could make this no-self-shadows, but it may be more important
- // to receive shadows from no-self-shadow monsters
- SetMaterialFlag( MF_NOSHADOWS );
- }
- // backSided
- else if ( !token.Icmp( "backSided" ) ) {
- cullType = CT_BACK_SIDED;
- // the shadow code doesn't handle this, so just disable shadows.
- // We could fix this in the future if there was a need.
- SetMaterialFlag( MF_NOSHADOWS );
- }
- // foglight
- else if ( !token.Icmp( "fogLight" ) ) {
- fogLight = true;
- continue;
- }
- // blendlight
- else if ( !token.Icmp( "blendLight" ) ) {
- blendLight = true;
- continue;
- }
- // ambientLight
- else if ( !token.Icmp( "ambientLight" ) ) {
- ambientLight = true;
- continue;
- }
- // mirror
- else if ( !token.Icmp( "mirror" ) ) {
- sort = SS_SUBVIEW;
- coverage = MC_OPAQUE;
- continue;
- }
- // noFog
- else if ( !token.Icmp( "noFog" ) ) {
- noFog = true;
- continue;
- }
- // unsmoothedTangents
- else if ( !token.Icmp( "unsmoothedTangents" ) ) {
- unsmoothedTangents = true;
- continue;
- }
- // lightFallofImage <imageprogram>
- // specifies the image to use for the third axis of projected
- // light volumes
- else if ( !token.Icmp( "lightFalloffImage" ) ) {
- str = R_ParsePastImageProgram( src );
- idStr copy;
- copy = str; // so other things don't step on it
- lightFalloffImage = globalImages->ImageFromFile( copy, TF_DEFAULT, false, TR_CLAMP /* TR_CLAMP_TO_ZERO */, TD_DEFAULT );
- continue;
- }
- // guisurf <guifile> | guisurf entity
- // an entity guisurf must have an idUserInterface
- // specified in the renderEntity
- else if ( !token.Icmp( "guisurf" ) ) {
- src.ReadTokenOnLine( &token );
- if ( !token.Icmp( "entity" ) ) {
- entityGui = 1;
- } else if ( !token.Icmp( "entity2" ) ) {
- entityGui = 2;
- } else if ( !token.Icmp( "entity3" ) ) {
- entityGui = 3;
- } else {
- gui = uiManager->FindGui( token.c_str(), true );
- }
- continue;
- }
- // sort
- else if ( !token.Icmp( "sort" ) ) {
- ParseSort( src );
- continue;
- }
- // spectrum <integer>
- else if ( !token.Icmp( "spectrum" ) ) {
- src.ReadTokenOnLine( &token );
- spectrum = atoi( token.c_str() );
- continue;
- }
- // deform < sprite | tube | flare >
- else if ( !token.Icmp( "deform" ) ) {
- ParseDeform( src );
- continue;
- }
- // decalInfo <staySeconds> <fadeSeconds> ( <start rgb> ) ( <end rgb> )
- else if ( !token.Icmp( "decalInfo" ) ) {
- ParseDecalInfo( src );
- continue;
- }
- // renderbump <args...>
- else if ( !token.Icmp( "renderbump") ) {
- src.ParseRestOfLine( renderBump );
- continue;
- }
- // diffusemap for stage shortcut
- else if ( !token.Icmp( "diffusemap" ) ) {
- str = R_ParsePastImageProgram( src );
- idStr::snPrintf( buffer, sizeof( buffer ), "blend diffusemap\nmap %s\n}\n", str );
- newSrc.LoadMemory( buffer, strlen(buffer), "diffusemap" );
- newSrc.SetFlags( LEXFL_NOFATALERRORS | LEXFL_NOSTRINGCONCAT | LEXFL_NOSTRINGESCAPECHARS | LEXFL_ALLOWPATHNAMES );
- ParseStage( newSrc, trpDefault );
- newSrc.FreeSource();
- continue;
- }
- // specularmap for stage shortcut
- else if ( !token.Icmp( "specularmap" ) ) {
- str = R_ParsePastImageProgram( src );
- idStr::snPrintf( buffer, sizeof( buffer ), "blend specularmap\nmap %s\n}\n", str );
- newSrc.LoadMemory( buffer, strlen(buffer), "specularmap" );
- newSrc.SetFlags( LEXFL_NOFATALERRORS | LEXFL_NOSTRINGCONCAT | LEXFL_NOSTRINGESCAPECHARS | LEXFL_ALLOWPATHNAMES );
- ParseStage( newSrc, trpDefault );
- newSrc.FreeSource();
- continue;
- }
- // normalmap for stage shortcut
- else if ( !token.Icmp( "bumpmap" ) ) {
- str = R_ParsePastImageProgram( src );
- idStr::snPrintf( buffer, sizeof( buffer ), "blend bumpmap\nmap %s\n}\n", str );
- newSrc.LoadMemory( buffer, strlen(buffer), "bumpmap" );
- newSrc.SetFlags( LEXFL_NOFATALERRORS | LEXFL_NOSTRINGCONCAT | LEXFL_NOSTRINGESCAPECHARS | LEXFL_ALLOWPATHNAMES );
- ParseStage( newSrc, trpDefault );
- newSrc.FreeSource();
- continue;
- }
- // DECAL_MACRO for backwards compatibility with the preprocessor macros
- else if ( !token.Icmp( "DECAL_MACRO" ) ) {
- // polygonOffset
- SetMaterialFlag( MF_POLYGONOFFSET );
- polygonOffset = 1;
- // discrete
- surfaceFlags |= SURF_DISCRETE;
- contentFlags &= ~CONTENTS_SOLID;
- // sort decal
- sort = SS_DECAL;
- // noShadows
- SetMaterialFlag( MF_NOSHADOWS );
- continue;
- }
- else if ( token == "{" ) {
- // create the new stage
- ParseStage( src, trpDefault );
- continue;
- }
- else {
- common->Warning( "unknown general material parameter '%s' in '%s'", token.c_str(), GetName() );
- SetMaterialFlag( MF_DEFAULTED );
- return;
- }
- }
- // add _flat or _white stages if needed
- AddImplicitStages();
- // order the diffuse / bump / specular stages properly
- SortInteractionStages();
- // if we need to do anything with normals (lighting or environment mapping)
- // and two sided lighting was asked for, flag
- // shouldCreateBackSides() and change culling back to single sided,
- // so we get proper tangent vectors on both sides
- // we can't just call ReceivesLighting(), because the stages are still
- // in temporary form
- if ( cullType == CT_TWO_SIDED ) {
- for ( i = 0 ; i < numStages ; i++ ) {
- if ( pd->parseStages[i].lighting != SL_AMBIENT || pd->parseStages[i].texture.texgen != TG_EXPLICIT ) {
- if ( cullType == CT_TWO_SIDED ) {
- cullType = CT_FRONT_SIDED;
- shouldCreateBackSides = true;
- }
- break;
- }
- }
- }
- // currently a surface can only have one unique texgen for all the stages on old hardware
- texgen_t firstGen = TG_EXPLICIT;
- for ( i = 0; i < numStages; i++ ) {
- if ( pd->parseStages[i].texture.texgen != TG_EXPLICIT ) {
- if ( firstGen == TG_EXPLICIT ) {
- firstGen = pd->parseStages[i].texture.texgen;
- } else if ( firstGen != pd->parseStages[i].texture.texgen ) {
- common->Warning( "material '%s' has multiple stages with a texgen", GetName() );
- break;
- }
- }
- }
- }
- /*
- =========================
- idMaterial::SetGui
- =========================
- */
- void idMaterial::SetGui( const char *_gui ) const {
- gui = uiManager->FindGui( _gui, true, false, true );
- }
- /*
- =========================
- idMaterial::Parse
- Parses the current material definition and finds all necessary images.
- =========================
- */
- bool idMaterial::Parse( const char *text, const int textLength ) {
- idLexer src;
- idToken token;
- mtrParsingData_t parsingData;
- src.LoadMemory( text, textLength, GetFileName(), GetLineNum() );
- src.SetFlags( DECL_LEXER_FLAGS );
- src.SkipUntilString( "{" );
- // reset to the unparsed state
- CommonInit();
- memset( &parsingData, 0, sizeof( parsingData ) );
- pd = &parsingData; // this is only valid during parse
- // parse it
- ParseMaterial( src );
- // if we are doing an fs_copyfiles, also reference the editorImage
- if ( cvarSystem->GetCVarInteger( "fs_copyFiles" ) ) {
- GetEditorImage();
- }
- //
- // count non-lit stages
- numAmbientStages = 0;
- int i;
- for ( i = 0 ; i < numStages ; i++ ) {
- if ( pd->parseStages[i].lighting == SL_AMBIENT ) {
- numAmbientStages++;
- }
- }
- // see if there is a subview stage
- if ( sort == SS_SUBVIEW ) {
- hasSubview = true;
- } else {
- hasSubview = false;
- for ( i = 0 ; i < numStages ; i++ ) {
- if ( pd->parseStages[i].texture.dynamic ) {
- hasSubview = true;
- }
- }
- }
- // automatically determine coverage if not explicitly set
- if ( coverage == MC_BAD ) {
- // automatically set MC_TRANSLUCENT if we don't have any interaction stages and
- // the first stage is blended and not an alpha test mask or a subview
- if ( !numStages ) {
- // non-visible
- coverage = MC_TRANSLUCENT;
- } else if ( numStages != numAmbientStages ) {
- // we have an interaction draw
- coverage = MC_OPAQUE;
- } else if (
- ( pd->parseStages[0].drawStateBits & GLS_DSTBLEND_BITS ) != GLS_DSTBLEND_ZERO ||
- ( pd->parseStages[0].drawStateBits & GLS_SRCBLEND_BITS ) == GLS_SRCBLEND_DST_COLOR ||
- ( pd->parseStages[0].drawStateBits & GLS_SRCBLEND_BITS ) == GLS_SRCBLEND_ONE_MINUS_DST_COLOR ||
- ( pd->parseStages[0].drawStateBits & GLS_SRCBLEND_BITS ) == GLS_SRCBLEND_DST_ALPHA ||
- ( pd->parseStages[0].drawStateBits & GLS_SRCBLEND_BITS ) == GLS_SRCBLEND_ONE_MINUS_DST_ALPHA
- ) {
- // blended with the destination
- coverage = MC_TRANSLUCENT;
- } else {
- coverage = MC_OPAQUE;
- }
- }
- // translucent automatically implies noshadows
- if ( coverage == MC_TRANSLUCENT ) {
- SetMaterialFlag( MF_NOSHADOWS );
- } else {
- // mark the contents as opaque
- contentFlags |= CONTENTS_OPAQUE;
- }
- // if we are translucent, draw with an alpha in the editor
- if ( coverage == MC_TRANSLUCENT ) {
- editorAlpha = 0.5;
- } else {
- editorAlpha = 1.0;
- }
- // the sorts can make reasonable defaults
- if ( sort == SS_BAD ) {
- if ( TestMaterialFlag(MF_POLYGONOFFSET) ) {
- sort = SS_DECAL;
- } else if ( coverage == MC_TRANSLUCENT ) {
- sort = SS_MEDIUM;
- } else {
- sort = SS_OPAQUE;
- }
- }
- // anything that references _currentRender will automatically get sort = SS_POST_PROCESS
- // and coverage = MC_TRANSLUCENT
- for ( i = 0 ; i < numStages ; i++ ) {
- shaderStage_t *pStage = &pd->parseStages[i];
- if ( pStage->texture.image == globalImages->currentRenderImage ) {
- if ( sort != SS_PORTAL_SKY ) {
- sort = SS_POST_PROCESS;
- coverage = MC_TRANSLUCENT;
- }
- break;
- }
- if ( pStage->newStage ) {
- for ( int j = 0 ; j < pStage->newStage->numFragmentProgramImages ; j++ ) {
- if ( pStage->newStage->fragmentProgramImages[j] == globalImages->currentRenderImage ) {
- if ( sort != SS_PORTAL_SKY ) {
- sort = SS_POST_PROCESS;
- coverage = MC_TRANSLUCENT;
- }
- i = numStages;
- break;
- }
- }
- }
- }
- // set the drawStateBits depth flags
- for ( i = 0 ; i < numStages ; i++ ) {
- shaderStage_t *pStage = &pd->parseStages[i];
- if ( sort == SS_POST_PROCESS ) {
- // post-process effects fill the depth buffer as they draw, so only the
- // topmost post-process effect is rendered
- pStage->drawStateBits |= GLS_DEPTHFUNC_LESS;
- } else if ( coverage == MC_TRANSLUCENT || pStage->ignoreAlphaTest ) {
- // translucent surfaces can extend past the exactly marked depth buffer
- pStage->drawStateBits |= GLS_DEPTHFUNC_LESS | GLS_DEPTHMASK;
- } else {
- // opaque and perforated surfaces must exactly match the depth buffer,
- // which gets alpha test correct
- pStage->drawStateBits |= GLS_DEPTHFUNC_EQUAL | GLS_DEPTHMASK;
- }
- }
- // determine if this surface will accept overlays / decals
- if ( pd->forceOverlays ) {
- // explicitly flaged in material definition
- allowOverlays = true;
- } else {
- if ( !IsDrawn() ) {
- allowOverlays = false;
- }
- if ( Coverage() != MC_OPAQUE ) {
- allowOverlays = false;
- }
- if ( GetSurfaceFlags() & SURF_NOIMPACT ) {
- allowOverlays = false;
- }
- }
- // add a tiny offset to the sort orders, so that different materials
- // that have the same sort value will at least sort consistantly, instead
- // of flickering back and forth
- /* this messed up in-game guis
- if ( sort != SS_SUBVIEW ) {
- int hash, l;
- l = name.Length();
- hash = 0;
- for ( int i = 0 ; i < l ; i++ ) {
- hash ^= name[i];
- }
- sort += hash * 0.01;
- }
- */
- if (numStages) {
- stages = (shaderStage_t *)R_StaticAlloc( numStages * sizeof( stages[0] ) );
- memcpy( stages, pd->parseStages, numStages * sizeof( stages[0] ) );
- }
- if ( numOps ) {
- ops = (expOp_t *)R_StaticAlloc( numOps * sizeof( ops[0] ) );
- memcpy( ops, pd->shaderOps, numOps * sizeof( ops[0] ) );
- }
- if ( numRegisters ) {
- expressionRegisters = (float *)R_StaticAlloc( numRegisters * sizeof( expressionRegisters[0] ) );
- memcpy( expressionRegisters, pd->shaderRegisters, numRegisters * sizeof( expressionRegisters[0] ) );
- }
- // see if the registers are completely constant, and don't need to be evaluated
- // per-surface
- CheckForConstantRegisters();
- pd = NULL; // the pointer will be invalid after exiting this function
- // finish things up
- if ( TestMaterialFlag( MF_DEFAULTED ) ) {
- MakeDefault();
- return false;
- }
- return true;
- }
- /*
- ===================
- idMaterial::Print
- ===================
- */
- char *opNames[] = {
- "OP_TYPE_ADD",
- "OP_TYPE_SUBTRACT",
- "OP_TYPE_MULTIPLY",
- "OP_TYPE_DIVIDE",
- "OP_TYPE_MOD",
- "OP_TYPE_TABLE",
- "OP_TYPE_GT",
- "OP_TYPE_GE",
- "OP_TYPE_LT",
- "OP_TYPE_LE",
- "OP_TYPE_EQ",
- "OP_TYPE_NE",
- "OP_TYPE_AND",
- "OP_TYPE_OR"
- };
- void idMaterial::Print() const {
- int i;
- for ( i = EXP_REG_NUM_PREDEFINED ; i < GetNumRegisters() ; i++ ) {
- common->Printf( "register %i: %f\n", i, expressionRegisters[i] );
- }
- common->Printf( "\n" );
- for ( i = 0 ; i < numOps ; i++ ) {
- const expOp_t *op = &ops[i];
- if ( op->opType == OP_TYPE_TABLE ) {
- common->Printf( "%i = %s[ %i ]\n", op->c, declManager->DeclByIndex( DECL_TABLE, op->a )->GetName(), op->b );
- } else {
- common->Printf( "%i = %i %s %i\n", op->c, op->a, opNames[ op->opType ], op->b );
- }
- }
- }
- /*
- ===============
- idMaterial::Save
- ===============
- */
- bool idMaterial::Save( const char *fileName ) {
- return ReplaceSourceFileText();
- }
- /*
- ===============
- idMaterial::AddReference
- ===============
- */
- void idMaterial::AddReference() {
- refCount++;
- for ( int i = 0; i < numStages; i++ ) {
- shaderStage_t *s = &stages[i];
- if ( s->texture.image ) {
- s->texture.image->AddReference();
- }
- }
- }
- /*
- ===============
- idMaterial::EvaluateRegisters
- Parameters are taken from the localSpace and the renderView,
- then all expressions are evaluated, leaving the material registers
- set to their apropriate values.
- ===============
- */
- void idMaterial::EvaluateRegisters( float *registers, const float shaderParms[MAX_ENTITY_SHADER_PARMS],
- const viewDef_t *view, idSoundEmitter *soundEmitter ) const {
- int i, b;
- expOp_t *op;
- // copy the material constants
- for ( i = EXP_REG_NUM_PREDEFINED ; i < numRegisters ; i++ ) {
- registers[i] = expressionRegisters[i];
- }
- // copy the local and global parameters
- registers[EXP_REG_TIME] = view->floatTime;
- registers[EXP_REG_PARM0] = shaderParms[0];
- registers[EXP_REG_PARM1] = shaderParms[1];
- registers[EXP_REG_PARM2] = shaderParms[2];
- registers[EXP_REG_PARM3] = shaderParms[3];
- registers[EXP_REG_PARM4] = shaderParms[4];
- registers[EXP_REG_PARM5] = shaderParms[5];
- registers[EXP_REG_PARM6] = shaderParms[6];
- registers[EXP_REG_PARM7] = shaderParms[7];
- registers[EXP_REG_PARM8] = shaderParms[8];
- registers[EXP_REG_PARM9] = shaderParms[9];
- registers[EXP_REG_PARM10] = shaderParms[10];
- registers[EXP_REG_PARM11] = shaderParms[11];
- registers[EXP_REG_GLOBAL0] = view->renderView.shaderParms[0];
- registers[EXP_REG_GLOBAL1] = view->renderView.shaderParms[1];
- registers[EXP_REG_GLOBAL2] = view->renderView.shaderParms[2];
- registers[EXP_REG_GLOBAL3] = view->renderView.shaderParms[3];
- registers[EXP_REG_GLOBAL4] = view->renderView.shaderParms[4];
- registers[EXP_REG_GLOBAL5] = view->renderView.shaderParms[5];
- registers[EXP_REG_GLOBAL6] = view->renderView.shaderParms[6];
- registers[EXP_REG_GLOBAL7] = view->renderView.shaderParms[7];
- op = ops;
- for ( i = 0 ; i < numOps ; i++, op++ ) {
- switch( op->opType ) {
- case OP_TYPE_ADD:
- registers[op->c] = registers[op->a] + registers[op->b];
- break;
- case OP_TYPE_SUBTRACT:
- registers[op->c] = registers[op->a] - registers[op->b];
- break;
- case OP_TYPE_MULTIPLY:
- registers[op->c] = registers[op->a] * registers[op->b];
- break;
- case OP_TYPE_DIVIDE:
- registers[op->c] = registers[op->a] / registers[op->b];
- break;
- case OP_TYPE_MOD:
- b = (int)registers[op->b];
- b = b != 0 ? b : 1;
- registers[op->c] = (int)registers[op->a] % b;
- break;
- case OP_TYPE_TABLE:
- {
- const idDeclTable *table = static_cast<const idDeclTable *>( declManager->DeclByIndex( DECL_TABLE, op->a ) );
- registers[op->c] = table->TableLookup( registers[op->b] );
- }
- break;
- case OP_TYPE_SOUND:
- if ( soundEmitter ) {
- registers[op->c] = soundEmitter->CurrentAmplitude();
- } else {
- registers[op->c] = 0;
- }
- break;
- case OP_TYPE_GT:
- registers[op->c] = registers[ op->a ] > registers[op->b];
- break;
- case OP_TYPE_GE:
- registers[op->c] = registers[ op->a ] >= registers[op->b];
- break;
- case OP_TYPE_LT:
- registers[op->c] = registers[ op->a ] < registers[op->b];
- break;
- case OP_TYPE_LE:
- registers[op->c] = registers[ op->a ] <= registers[op->b];
- break;
- case OP_TYPE_EQ:
- registers[op->c] = registers[ op->a ] == registers[op->b];
- break;
- case OP_TYPE_NE:
- registers[op->c] = registers[ op->a ] != registers[op->b];
- break;
- case OP_TYPE_AND:
- registers[op->c] = registers[ op->a ] && registers[op->b];
- break;
- case OP_TYPE_OR:
- registers[op->c] = registers[ op->a ] || registers[op->b];
- break;
- default:
- common->FatalError( "R_EvaluateExpression: bad opcode" );
- }
- }
- }
- /*
- =============
- idMaterial::Texgen
- =============
- */
- texgen_t idMaterial::Texgen() const {
- if ( stages ) {
- for ( int i = 0; i < numStages; i++ ) {
- if ( stages[ i ].texture.texgen != TG_EXPLICIT ) {
- return stages[ i ].texture.texgen;
- }
- }
- }
-
- return TG_EXPLICIT;
- }
- /*
- =============
- idMaterial::GetImageWidth
- =============
- */
- int idMaterial::GetImageWidth( void ) const {
- assert( GetStage(0) && GetStage(0)->texture.image );
- return GetStage(0)->texture.image->uploadWidth;
- }
- /*
- =============
- idMaterial::GetImageHeight
- =============
- */
- int idMaterial::GetImageHeight( void ) const {
- assert( GetStage(0) && GetStage(0)->texture.image );
- return GetStage(0)->texture.image->uploadHeight;
- }
- /*
- =============
- idMaterial::CinematicLength
- =============
- */
- int idMaterial::CinematicLength() const {
- if ( !stages || !stages[0].texture.cinematic ) {
- return 0;
- }
- return stages[0].texture.cinematic->AnimationLength();
- }
- /*
- =============
- idMaterial::UpdateCinematic
- =============
- */
- void idMaterial::UpdateCinematic( int time ) const {
- if ( !stages || !stages[0].texture.cinematic || !backEnd.viewDef ) {
- return;
- }
- stages[0].texture.cinematic->ImageForTime( tr.primaryRenderView.time );
- }
- /*
- =============
- idMaterial::CloseCinematic
- =============
- */
- void idMaterial::CloseCinematic( void ) const {
- for( int i = 0; i < numStages; i++ ) {
- if ( stages[i].texture.cinematic ) {
- stages[i].texture.cinematic->Close();
- delete stages[i].texture.cinematic;
- stages[i].texture.cinematic = NULL;
- }
- }
- }
- /*
- =============
- idMaterial::ResetCinematicTime
- =============
- */
- void idMaterial::ResetCinematicTime( int time ) const {
- for( int i = 0; i < numStages; i++ ) {
- if ( stages[i].texture.cinematic ) {
- stages[i].texture.cinematic->ResetTime( time );
- }
- }
- }
- /*
- =============
- idMaterial::ConstantRegisters
- =============
- */
- const float *idMaterial::ConstantRegisters() const {
- if ( !r_useConstantMaterials.GetBool() ) {
- return NULL;
- }
- return constantRegisters;
- }
- /*
- ==================
- idMaterial::CheckForConstantRegisters
- As of 5/2/03, about half of the unique materials loaded on typical
- maps are constant, but 2/3 of the surface references are.
- This is probably an optimization of dubious value.
- ==================
- */
- static int c_constant, c_variable;
- void idMaterial::CheckForConstantRegisters() {
- if ( !pd->registersAreConstant ) {
- return;
- }
- // evaluate the registers once, and save them
- constantRegisters = (float *)R_ClearedStaticAlloc( GetNumRegisters() * sizeof( float ) );
- float shaderParms[MAX_ENTITY_SHADER_PARMS];
- memset( shaderParms, 0, sizeof( shaderParms ) );
- viewDef_t viewDef;
- memset( &viewDef, 0, sizeof( viewDef ) );
- EvaluateRegisters( constantRegisters, shaderParms, &viewDef, 0 );
- }
- /*
- ===================
- idMaterial::ImageName
- ===================
- */
- const char *idMaterial::ImageName( void ) const {
- if ( numStages == 0 ) {
- return "_scratch";
- }
- idImage *image = stages[0].texture.image;
- if ( image ) {
- return image->imgName;
- }
- return "_scratch";
- }
- /*
- ===================
- idMaterial::SetImageClassifications
- Just for image resource tracking.
- ===================
- */
- void idMaterial::SetImageClassifications( int tag ) const {
- for ( int i = 0 ; i < numStages ; i++ ) {
- idImage *image = stages[i].texture.image;
- if ( image ) {
- image->SetClassification( tag );
- }
- }
- }
- /*
- =================
- idMaterial::Size
- =================
- */
- size_t idMaterial::Size( void ) const {
- return sizeof( idMaterial );
- }
- /*
- ===================
- idMaterial::SetDefaultText
- ===================
- */
- bool idMaterial::SetDefaultText( void ) {
- // if there exists an image with the same name
- if ( 1 ) { //fileSystem->ReadFile( GetName(), NULL ) != -1 ) {
- char generated[2048];
- idStr::snPrintf( generated, sizeof( generated ),
- "material %s // IMPLICITLY GENERATED\n"
- "{\n"
- "{\n"
- "blend blend\n"
- "colored\n"
- "map \"%s\"\n"
- "clamp\n"
- "}\n"
- "}\n", GetName(), GetName() );
- SetText( generated );
- return true;
- } else {
- return false;
- }
- }
- /*
- ===================
- idMaterial::DefaultDefinition
- ===================
- */
- const char *idMaterial::DefaultDefinition() const {
- return
- "{\n"
- "\t" "{\n"
- "\t\t" "blend\tblend\n"
- "\t\t" "map\t\t_default\n"
- "\t" "}\n"
- "}";
- }
- /*
- ===================
- idMaterial::GetBumpStage
- ===================
- */
- const shaderStage_t *idMaterial::GetBumpStage( void ) const {
- for ( int i = 0 ; i < numStages ; i++ ) {
- if ( stages[i].lighting == SL_BUMP ) {
- return &stages[i];
- }
- }
- return NULL;
- }
- /*
- ===================
- idMaterial::ReloadImages
- ===================
- */
- void idMaterial::ReloadImages( bool force ) const
- {
- for ( int i = 0 ; i < numStages ; i++ ) {
- if ( stages[i].newStage ) {
- for ( int j = 0 ; j < stages[i].newStage->numFragmentProgramImages ; j++ ) {
- if ( stages[i].newStage->fragmentProgramImages[j] ) {
- stages[i].newStage->fragmentProgramImages[j]->Reload( false, force );
- }
- }
- } else if ( stages[i].texture.image ) {
- stages[i].texture.image->Reload( false, force );
- }
- }
- }
|