Material.cpp 75 KB

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