renderbump.cpp 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642
  1. /*
  2. ===========================================================================
  3. Doom 3 GPL Source Code
  4. Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
  6. Doom 3 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 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 Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
  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. #include "../../../idlib/precompiled.h"
  21. #pragma hdrstop
  22. #ifdef WIN32
  23. #include <windows.h>
  24. #include <GL/gl.h>
  25. #include <GL/glu.h>
  26. #include "../../../sys/win32/win_local.h"
  27. #endif
  28. #include "../../../renderer/tr_local.h"
  29. /*
  30. render a normalmap tga file from an ase model for bump mapping
  31. To make ray-tracing into the high poly mesh efficient, we preconstruct
  32. a 3D hash table of the triangles that need to be tested for a given source
  33. point.
  34. This task is easier than a general ray tracing optimization, because we
  35. known that all of the triangles are going to be "near" the source point.
  36. TraceFraction determines the maximum distance in any direction that
  37. a trace will go. It is expressed as a fraction of the largest axis of
  38. the bounding box, so it doesn't matter what units are used for modeling.
  39. */
  40. #define MAX_QPATH 256
  41. #define DEFAULT_TRACE_FRACTION 0.05
  42. #define INITIAL_TRI_TO_LINK_EXPANSION 16 // can grow as needed
  43. #define HASH_AXIS_BINS 100
  44. typedef struct {
  45. int faceNum;
  46. int nextLink;
  47. } triLink_t;
  48. typedef struct {
  49. int triLink;
  50. int rayNumber; // don't need to test again if still on same ray
  51. } binLink_t;
  52. #define MAX_LINKS_PER_BLOCK 0x100000
  53. #define MAX_LINK_BLOCKS 0x100
  54. typedef struct {
  55. idBounds bounds;
  56. float binSize[3];
  57. int numLinkBlocks;
  58. triLink_t *linkBlocks[MAX_LINK_BLOCKS];
  59. binLink_t binLinks[HASH_AXIS_BINS][HASH_AXIS_BINS][HASH_AXIS_BINS];
  60. } triHash_t;
  61. typedef struct {
  62. char outputName[MAX_QPATH];
  63. char highName[MAX_QPATH];
  64. byte *localPic;
  65. byte *globalPic;
  66. byte *colorPic;
  67. float *edgeDistances; // starts out -1 for untraced, for each texel, 0 = true interior, >0 = off-edge rasterization
  68. int width, height;
  69. int antiAlias;
  70. int outline;
  71. bool saveGlobalMap;
  72. bool saveColorMap;
  73. float traceFrac;
  74. float traceDist;
  75. srfTriangles_t *mesh; // high poly mesh
  76. idRenderModel *highModel;
  77. triHash_t *hash;
  78. } renderBump_t;
  79. static float traceFraction;
  80. static int rayNumber; // for avoiding retests of bins and faces
  81. static int oldWidth, oldHeight;
  82. /*
  83. ===============
  84. SaveWindow
  85. ===============
  86. */
  87. static void SaveWindow( void ) {
  88. oldWidth = glConfig.vidWidth;
  89. oldHeight = glConfig.vidHeight;
  90. }
  91. /*
  92. ===============
  93. ResizeWindow
  94. ===============
  95. */
  96. static void ResizeWindow( int width, int height ) {
  97. #ifdef WIN32
  98. int winWidth, winHeight;
  99. if ( glConfig.isFullscreen ) {
  100. winWidth = width;
  101. winHeight = height;
  102. } else {
  103. RECT r;
  104. // adjust width and height for window border
  105. r.bottom = height;
  106. r.left = 0;
  107. r.top = 0;
  108. r.right = width;
  109. AdjustWindowRect (&r, WINDOW_STYLE|WS_SYSMENU, FALSE);
  110. winHeight = r.bottom - r.top;
  111. winWidth = r.right - r.left;
  112. }
  113. SetWindowPos( win32.hWnd, HWND_TOP, 0, 0, winWidth, winHeight, SWP_SHOWWINDOW );
  114. qwglMakeCurrent( win32.hDC, win32.hGLRC );
  115. #endif
  116. }
  117. /*
  118. ===============
  119. RestoreWindow
  120. ===============
  121. */
  122. static void RestoreWindow( void ) {
  123. #ifdef WIN32
  124. int winWidth, winHeight;
  125. if ( glConfig.isFullscreen ) {
  126. winWidth = oldWidth;
  127. winHeight = oldHeight;
  128. } else {
  129. RECT r;
  130. // adjust width and height for window border
  131. r.bottom = oldHeight;
  132. r.left = 0;
  133. r.top = 0;
  134. r.right = oldWidth;
  135. AdjustWindowRect (&r, WINDOW_STYLE|WS_SYSMENU, FALSE);
  136. winHeight = r.bottom - r.top;
  137. winWidth = r.right - r.left;
  138. }
  139. SetWindowPos( win32.hWnd, HWND_TOP, 0, 0, winWidth, winHeight, SWP_SHOWWINDOW );
  140. #endif
  141. }
  142. /*
  143. ================
  144. OutlineNormalMap
  145. Puts a single pixel border around all non-empty pixels
  146. Does NOT copy the alpha channel, so it can be used as
  147. an alpha test map.
  148. ================
  149. */
  150. static void OutlineNormalMap( byte *data, int width, int height, int emptyR, int emptyG, int emptyB ) {
  151. byte *orig;
  152. int i, j, k, l;
  153. idVec3 normal;
  154. byte *out;
  155. orig = (byte *)Mem_Alloc( width * height * 4 );
  156. memcpy( orig, data, width * height * 4 );
  157. for ( i = 0 ; i < width ; i++ ) {
  158. for ( j = 0 ; j < height ; j++ ) {
  159. out = data + ( j * width + i ) * 4;
  160. if ( out[0] != emptyR || out[1] != emptyG || out[2] != emptyB ) {
  161. continue;
  162. }
  163. normal = vec3_origin;
  164. for ( k = -1 ; k < 2 ; k++ ) {
  165. for ( l = -1 ; l < 2 ; l++ ) {
  166. byte *in;
  167. in = orig + ( ((j+l)&(height-1))*width + ((i+k)&(width-1)) ) * 4;
  168. if ( in[0] == emptyR && in[1] == emptyG && in[2] == emptyB ) {
  169. continue;
  170. }
  171. normal[0] += ( in[0] - 128 );
  172. normal[1] += ( in[1] - 128 );
  173. normal[2] += ( in[2] - 128 );
  174. }
  175. }
  176. if ( normal.Normalize() < 0.5 ) {
  177. continue; // no valid samples
  178. }
  179. out[0] = 128 + 127 * normal[0];
  180. out[1] = 128 + 127 * normal[1];
  181. out[2] = 128 + 127 * normal[2];
  182. }
  183. }
  184. Mem_Free( orig );
  185. }
  186. /*
  187. ================
  188. OutlineColorMap
  189. Puts a single pixel border around all non-empty pixels
  190. Does NOT copy the alpha channel, so it can be used as
  191. an alpha test map.
  192. ================
  193. */
  194. static void OutlineColorMap( byte *data, int width, int height, int emptyR, int emptyG, int emptyB ) {
  195. byte *orig;
  196. int i, j, k, l;
  197. idVec3 normal;
  198. byte *out;
  199. orig = (byte *)Mem_Alloc( width * height * 4 );
  200. memcpy( orig, data, width * height * 4 );
  201. for ( i = 0 ; i < width ; i++ ) {
  202. for ( j = 0 ; j < height ; j++ ) {
  203. out = data + ( j * width + i ) * 4;
  204. if ( out[0] != emptyR || out[1] != emptyG || out[2] != emptyB ) {
  205. continue;
  206. }
  207. normal = vec3_origin;
  208. int count = 0;
  209. for ( k = -1 ; k < 2 ; k++ ) {
  210. for ( l = -1 ; l < 2 ; l++ ) {
  211. byte *in;
  212. in = orig + ( ((j+l)&(height-1))*width + ((i+k)&(width-1)) ) * 4;
  213. if ( in[0] == emptyR && in[1] == emptyG && in[2] == emptyB ) {
  214. continue;
  215. }
  216. normal[0] += in[0];
  217. normal[1] += in[1];
  218. normal[2] += in[2];
  219. count++;
  220. }
  221. }
  222. if ( !count ) {
  223. continue;
  224. }
  225. normal *= (1.0 / count );
  226. out[0] = normal[0];
  227. out[1] = normal[1];
  228. out[2] = normal[2];
  229. }
  230. }
  231. Mem_Free( orig );
  232. }
  233. /*
  234. ================
  235. FreeTriHash
  236. ================
  237. */
  238. static void FreeTriHash( triHash_t *hash ) {
  239. for ( int i = 0 ; i < hash->numLinkBlocks ; i++ ) {
  240. Mem_Free( hash->linkBlocks[i] );
  241. }
  242. Mem_Free( hash );
  243. }
  244. /*
  245. ================
  246. CreateTriHash
  247. ================
  248. */
  249. static triHash_t *CreateTriHash( const srfTriangles_t *highMesh ) {
  250. triHash_t *hash;
  251. int i, j, k, l;
  252. idBounds bounds, triBounds;
  253. int iBounds[2][3];
  254. int maxLinks, numLinks;
  255. hash = (triHash_t *)Mem_Alloc( sizeof( *hash ) );
  256. memset( hash, 0, sizeof( *hash ) );
  257. // find the bounding volume for the mesh
  258. bounds.Clear();
  259. for ( i = 0 ; i < highMesh->numVerts ; i++ ) {
  260. bounds.AddPoint( highMesh->verts[i].xyz );
  261. }
  262. hash->bounds = bounds;
  263. // divide each axis as needed
  264. for ( i = 0 ; i < 3 ; i++ ) {
  265. hash->binSize[i] = ( bounds[1][i] - bounds[0][i] ) / HASH_AXIS_BINS;
  266. if ( hash->binSize[i] <= 0 ) {
  267. common->FatalError( "CreateTriHash: bad bounds: (%f %f %f) to (%f %f %f)",
  268. bounds[0][0],bounds[0][1],bounds[0][2],
  269. bounds[1][0],bounds[1][1],bounds[1][2] );
  270. }
  271. }
  272. // a -1 link number terminated the link chain
  273. memset( hash->binLinks, -1, sizeof( hash->binLinks ) );
  274. numLinks = 0;
  275. hash->linkBlocks[hash->numLinkBlocks] = (triLink_t *)Mem_Alloc( MAX_LINKS_PER_BLOCK * sizeof( triLink_t ) );
  276. hash->numLinkBlocks++;
  277. maxLinks = hash->numLinkBlocks * MAX_LINKS_PER_BLOCK;
  278. // for each triangle, place a triLink in each bin that might reference it
  279. for ( i = 0 ; i < highMesh->numIndexes ; i+=3 ) {
  280. // determine which hash bins the triangle will need to be in
  281. triBounds.Clear();
  282. for ( j = 0 ; j < 3 ; j++ ) {
  283. triBounds.AddPoint( highMesh->verts[ highMesh->indexes[i+j] ].xyz );
  284. }
  285. for ( j = 0 ; j < 3 ; j++ ) {
  286. iBounds[0][j] = ( triBounds[0][j] - hash->bounds[0][j] ) / hash->binSize[j];
  287. iBounds[0][j] -= 0.001; // epsilon
  288. if ( iBounds[0][j] < 0 ) {
  289. iBounds[0][j] = 0;
  290. } else if ( iBounds[0][j] >= HASH_AXIS_BINS ) {
  291. iBounds[0][j] = HASH_AXIS_BINS-1;
  292. }
  293. iBounds[1][j] = ( triBounds[1][j] - hash->bounds[0][j] ) / hash->binSize[j];
  294. iBounds[0][j] += 0.001; // epsilon
  295. if ( iBounds[1][j] < 0 ) {
  296. iBounds[1][j] = 0;
  297. } else if ( iBounds[1][j] >= HASH_AXIS_BINS ) {
  298. iBounds[1][j] = HASH_AXIS_BINS-1;
  299. }
  300. }
  301. // add the links
  302. for ( j = iBounds[0][0] ; j <= iBounds[1][0] ; j++ ) {
  303. for ( k = iBounds[0][1] ; k <= iBounds[1][1] ; k++ ) {
  304. for ( l = iBounds[0][2] ; l <= iBounds[1][2] ; l++ ) {
  305. if ( numLinks == maxLinks ) {
  306. hash->linkBlocks[hash->numLinkBlocks] = (triLink_t *)Mem_Alloc( MAX_LINKS_PER_BLOCK * sizeof( triLink_t ) );
  307. hash->numLinkBlocks++;
  308. maxLinks = hash->numLinkBlocks * MAX_LINKS_PER_BLOCK;
  309. }
  310. triLink_t *link = &hash->linkBlocks[ numLinks / MAX_LINKS_PER_BLOCK ][ numLinks % MAX_LINKS_PER_BLOCK ];
  311. link->faceNum = i / 3;
  312. link->nextLink = hash->binLinks[j][k][l].triLink;
  313. hash->binLinks[j][k][l].triLink = numLinks;
  314. numLinks++;
  315. }
  316. }
  317. }
  318. }
  319. common->Printf( "%i triangles made %i links\n", highMesh->numIndexes / 3, numLinks );
  320. return hash;
  321. }
  322. /*
  323. =================
  324. TraceToMeshFace
  325. Returns the distance from the point to the intersection, or DIST_NO_INTERSECTION
  326. =================
  327. */
  328. #define DIST_NO_INTERSECTION -999999999.0f
  329. static float TraceToMeshFace( const srfTriangles_t *highMesh, int faceNum,
  330. float minDist, float maxDist,
  331. const idVec3 &point, const idVec3 &normal, idVec3 &sampledNormal,
  332. byte sampledColor[4] ) {
  333. int j;
  334. float dist;
  335. const idVec3 *v[3];
  336. const idPlane *plane;
  337. idVec3 edge;
  338. float d;
  339. idVec3 dir[3];
  340. float baseArea;
  341. float bary[3];
  342. idVec3 testVert;
  343. v[0] = &highMesh->verts[ highMesh->indexes[ faceNum * 3 + 0 ] ].xyz;
  344. v[1] = &highMesh->verts[ highMesh->indexes[ faceNum * 3 + 1 ] ].xyz;
  345. v[2] = &highMesh->verts[ highMesh->indexes[ faceNum * 3 + 2 ] ].xyz;
  346. plane = highMesh->facePlanes + faceNum;
  347. // only test against planes facing the same direction as our normal
  348. d = plane->Normal() * normal;
  349. if ( d <= 0.0001f ) {
  350. return DIST_NO_INTERSECTION;
  351. }
  352. // find the point of impact on the plane
  353. dist = plane->Distance( point );
  354. dist /= -d;
  355. testVert = point + dist * normal;
  356. // if this would be beyond our requested trace distance,
  357. // don't even check it
  358. if ( dist > maxDist ) {
  359. return DIST_NO_INTERSECTION;
  360. }
  361. if ( dist < minDist ) {
  362. return DIST_NO_INTERSECTION;
  363. }
  364. // if normal is inside all edge planes, this face is hit
  365. VectorSubtract( *v[0], point, dir[0] );
  366. VectorSubtract( *v[1], point, dir[1] );
  367. edge = dir[0].Cross( dir[1] );
  368. d = DotProduct( normal, edge );
  369. if ( d > 0.0f ) {
  370. return DIST_NO_INTERSECTION;
  371. }
  372. VectorSubtract( *v[2], point, dir[2] );
  373. edge = dir[1].Cross( dir[2] );
  374. d = DotProduct( normal, edge );
  375. if ( d > 0.0f ) {
  376. return DIST_NO_INTERSECTION;
  377. }
  378. edge = dir[2].Cross( dir[0] );
  379. d = DotProduct( normal, edge );
  380. if ( d > 0.0f ) {
  381. return DIST_NO_INTERSECTION;
  382. }
  383. // calculate barycentric coordinates of the impact point
  384. // on the high poly triangle
  385. bary[0] = idWinding::TriangleArea( testVert, *v[1], *v[2] );
  386. bary[1] = idWinding::TriangleArea( *v[0], testVert, *v[2] );
  387. bary[2] = idWinding::TriangleArea( *v[0], *v[1], testVert );
  388. baseArea = idWinding::TriangleArea( *v[0], *v[1], *v[2] );
  389. bary[0] /= baseArea;
  390. bary[1] /= baseArea;
  391. bary[2] /= baseArea;
  392. if ( bary[0] + bary[1] + bary[2] > 1.1 ) {
  393. bary[0] = bary[0];
  394. return DIST_NO_INTERSECTION;
  395. }
  396. // triangularly interpolate the normals to the sample point
  397. sampledNormal = vec3_origin;
  398. for ( j = 0 ; j < 3 ; j++ ) {
  399. sampledNormal += bary[j] * highMesh->verts[ highMesh->indexes[ faceNum * 3 + j ] ].normal;
  400. }
  401. sampledNormal.Normalize();
  402. sampledColor[0] = sampledColor[1] = sampledColor[2] = sampledColor[3] = 0;
  403. for ( int i = 0 ; i < 4 ; i++ ) {
  404. float color = 0.0f;
  405. for ( j = 0 ; j < 3 ; j++ ) {
  406. color += bary[j] * highMesh->verts[ highMesh->indexes[ faceNum * 3 + j ] ].color[i];
  407. }
  408. sampledColor[i] = color;
  409. }
  410. return dist;
  411. }
  412. /*
  413. ================
  414. SampleHighMesh
  415. Find the best surface normal in the high poly mesh
  416. for a ray coming from the surface of the low poly mesh
  417. Returns false if the trace doesn't hit anything
  418. ================
  419. */
  420. static bool SampleHighMesh( const renderBump_t *rb,
  421. const idVec3 &point, const idVec3 &direction, idVec3 &sampledNormal,
  422. byte sampledColor[4] ) {
  423. idVec3 p;
  424. binLink_t *bl;
  425. int linkNum;
  426. int faceNum;
  427. float dist, bestDist;
  428. int block[3];
  429. float maxDist;
  430. int c_hits;
  431. int i;
  432. idVec3 normal;
  433. // we allow non-normalized directions on input
  434. normal = direction;
  435. normal.Normalize();
  436. // increment our uniqueness counter (FIXME: make thread safe?)
  437. rayNumber++;
  438. // the max distance will be the traceFrac times the longest axis of the high poly model
  439. bestDist = -rb->traceDist;
  440. maxDist = rb->traceDist;
  441. sampledNormal = vec3_origin;
  442. c_hits = 0;
  443. // this is a pretty damn lazy way to walk through a 3D grid, and has a (very slight)
  444. // chance of missing a triangle in a corner crossing case
  445. #define RAY_STEPS 100
  446. for ( i = 0 ; i < RAY_STEPS ; i++ ) {
  447. p = point - rb->hash->bounds[0] + normal * ( -1.0 + 2.0 * i / RAY_STEPS ) * rb->traceDist;
  448. block[0] = floor( p[0] / rb->hash->binSize[0] );
  449. block[1] = floor( p[1] / rb->hash->binSize[1] );
  450. block[2] = floor( p[2] / rb->hash->binSize[2] );
  451. if ( block[0] < 0 || block[0] >= HASH_AXIS_BINS ) {
  452. continue;
  453. }
  454. if ( block[1] < 0 || block[1] >= HASH_AXIS_BINS ) {
  455. continue;
  456. }
  457. if ( block[2] < 0 || block[2] >= HASH_AXIS_BINS ) {
  458. continue;
  459. }
  460. // FIXME: casting away const
  461. bl = (binLink_t *)&rb->hash->binLinks[block[0]][block[1]][block[2]];
  462. if ( bl->rayNumber == rayNumber ) {
  463. continue; // already tested this block
  464. }
  465. bl->rayNumber = rayNumber;
  466. linkNum = bl->triLink;
  467. triLink_t *link;
  468. for ( ; linkNum != -1 ; linkNum = link->nextLink ) {
  469. link = &rb->hash->linkBlocks[ linkNum / MAX_LINKS_PER_BLOCK ][ linkNum % MAX_LINKS_PER_BLOCK ];
  470. faceNum = link->faceNum;
  471. dist = TraceToMeshFace( rb->mesh, faceNum,
  472. bestDist, maxDist, point, normal, sampledNormal, sampledColor );
  473. if ( dist == DIST_NO_INTERSECTION ) {
  474. continue;
  475. }
  476. c_hits++;
  477. // continue looking for a better match
  478. bestDist = dist;
  479. }
  480. }
  481. return (bool)( bestDist > -rb->traceDist );
  482. }
  483. /*
  484. =============
  485. TriTextureArea
  486. This may be negatove
  487. =============
  488. */
  489. static float TriTextureArea( const float a[2], const float b[2], const float c[2] ) {
  490. idVec3 d1, d2;
  491. idVec3 cross;
  492. float area;
  493. d1[0] = b[0] - a[0];
  494. d1[1] = b[1] - a[1];
  495. d1[2] = 0;
  496. d2[0] = c[0] - a[0];
  497. d2[1] = c[1] - a[1];
  498. d2[2] = 0;
  499. cross = d1.Cross( d2 );
  500. area = 0.5 * cross.Length();
  501. if ( cross[2] < 0 ) {
  502. return -area;
  503. } else {
  504. return area;
  505. }
  506. }
  507. /*
  508. ================
  509. RasterizeTriangle
  510. It is ok for the texcoords to wrap around, the rasterization
  511. will deal with it properly.
  512. ================
  513. */
  514. static void RasterizeTriangle( const srfTriangles_t *lowMesh, const idVec3 *lowMeshNormals, int lowFaceNum,
  515. renderBump_t *rb ) {
  516. int i, j, k;
  517. float bounds[2][2];
  518. float ibounds[2][2];
  519. float verts[3][2];
  520. float testVert[2];
  521. float bary[3];
  522. byte *localDest, *globalDest, *colorDest;
  523. float edge[3][3];
  524. idVec3 sampledNormal;
  525. byte sampledColor[4];
  526. idVec3 point, normal, traceNormal, tangents[2];
  527. float baseArea, totalArea;
  528. int r, g, b;
  529. idVec3 localNormal;
  530. // this is a brain-dead rasterizer, but compared to the ray trace,
  531. // nothing we do here is going to matter performance-wise
  532. // adjust for resolution and texel centers
  533. verts[0][0] = lowMesh->verts[ lowMesh->indexes[lowFaceNum*3+0] ].st[0] * rb->width - 0.5;
  534. verts[1][0] = lowMesh->verts[ lowMesh->indexes[lowFaceNum*3+1] ].st[0] * rb->width - 0.5;
  535. verts[2][0] = lowMesh->verts[ lowMesh->indexes[lowFaceNum*3+2] ].st[0] * rb->width - 0.5;
  536. verts[0][1] = lowMesh->verts[ lowMesh->indexes[lowFaceNum*3+0] ].st[1] * rb->height - 0.5;
  537. verts[1][1] = lowMesh->verts[ lowMesh->indexes[lowFaceNum*3+1] ].st[1] * rb->height - 0.5;
  538. verts[2][1] = lowMesh->verts[ lowMesh->indexes[lowFaceNum*3+2] ].st[1] * rb->height - 0.5;
  539. // find the texcoord bounding box
  540. bounds[0][0] = 99999;
  541. bounds[0][1] = 99999;
  542. bounds[1][0] = -99999;
  543. bounds[1][1] = -99999;
  544. for ( i = 0 ; i < 2 ; i++ ) {
  545. for ( j = 0 ; j < 3 ; j++ ) {
  546. if ( verts[j][i] < bounds[0][i] ) {
  547. bounds[0][i] = verts[j][i];
  548. }
  549. if ( verts[j][i] > bounds[1][i] ) {
  550. bounds[1][i] = verts[j][i];
  551. }
  552. }
  553. }
  554. // we intentionally rasterize somewhat outside the triangles, so
  555. // the bilerp support texels (which may be anti-aliased down)
  556. // are not just duplications of what is on the interior
  557. const float edgeOverlap = 4.0;
  558. ibounds[0][0] = floor( bounds[0][0] - edgeOverlap );
  559. ibounds[1][0] = ceil( bounds[1][0] + edgeOverlap );
  560. ibounds[0][1] = floor( bounds[0][1] - edgeOverlap );
  561. ibounds[1][1] = ceil( bounds[1][1] + edgeOverlap );
  562. // calculate edge vectors
  563. for ( i = 0 ; i < 3 ; i++ ) {
  564. float *v1, *v2;
  565. v1 = verts[i];
  566. v2 = verts[(i+1)%3];
  567. edge[i][0] = v2[1] - v1[1];
  568. edge[i][1] = v1[0] - v2[0];
  569. float len = sqrt( edge[i][0] * edge[i][0] + edge[i][1] * edge[i][1] );
  570. edge[i][0] /= len;
  571. edge[i][1] /= len;
  572. edge[i][2] = -( v1[0] * edge[i][0] + v1[1] * edge[i][1] );
  573. }
  574. // itterate over the bounding box, testing against edge vectors
  575. for ( i = ibounds[0][1] ; i < ibounds[1][1] ; i++ ) {
  576. for ( j = ibounds[0][0] ; j < ibounds[1][0] ; j++ ) {
  577. float dists[3];
  578. k = ( ( i & (rb->height-1) ) * rb->width + ( j & (rb->width-1) ) ) * 4;
  579. colorDest = &rb->colorPic[k];
  580. localDest = &rb->localPic[k];
  581. globalDest = &rb->globalPic[k];
  582. #define SKIP_MIRRORS
  583. float *edgeDistance = &rb->edgeDistances[k/4];
  584. #ifdef SKIP_MIRRORS
  585. // if this texel has already been filled by a true interior pixel, don't overwrite it
  586. if ( *edgeDistance == 0 ) {
  587. continue;
  588. }
  589. #endif
  590. // check against the three edges to see if the pixel is inside the triangle
  591. for ( k = 0 ; k < 3 ; k++ ) {
  592. float v;
  593. v = i * edge[k][1] + j * edge[k][0] + edge[k][2];
  594. dists[k] = v;
  595. }
  596. // the edge polarities might be either way
  597. if ( ! ( ( dists[0] >= -edgeOverlap && dists[1] >= -edgeOverlap && dists[2] >= -edgeOverlap )
  598. || ( dists[0] <= edgeOverlap && dists[1] <= edgeOverlap && dists[2] <= edgeOverlap ) ) ) {
  599. continue;
  600. }
  601. bool edgeTexel;
  602. if ( ( dists[0] >= 0 && dists[1] >= 0 && dists[2] >= 0 )
  603. || ( dists[0] <= 0 && dists[1] <= 0 && dists[2] <= 0 ) ) {
  604. edgeTexel = false;
  605. } else {
  606. edgeTexel = true;
  607. #ifdef SKIP_MIRRORS
  608. // if this texel has already been filled by another edge pixel, don't overwrite it
  609. if ( *edgeDistance == 1 ) {
  610. continue;
  611. }
  612. #endif
  613. }
  614. // calculate the barycentric coordinates in the triangle for this sample
  615. testVert[0] = j;
  616. testVert[1] = i;
  617. baseArea = TriTextureArea( verts[0], verts[1], verts[2] );
  618. bary[0] = TriTextureArea( testVert, verts[1], verts[2] ) / baseArea;
  619. bary[1] = TriTextureArea( verts[0], testVert, verts[2] ) / baseArea;
  620. bary[2] = TriTextureArea( verts[0], verts[1], testVert ) / baseArea;
  621. totalArea = bary[0] + bary[1] + bary[2];
  622. if ( totalArea < 0.99 || totalArea > 1.01 ) {
  623. continue; // should never happen
  624. }
  625. // calculate the interpolated xyz, normal, and tangents of this sample
  626. point = vec3_origin;
  627. traceNormal = vec3_origin;
  628. normal = vec3_origin;
  629. tangents[0] = vec3_origin;
  630. tangents[1] = vec3_origin;
  631. for ( k = 0 ; k < 3 ; k++ ) {
  632. int index;
  633. index = lowMesh->indexes[lowFaceNum*3+k];
  634. point += bary[k] * lowMesh->verts[ index ].xyz;
  635. // traceNormal will differ from normal if the surface uses unsmoothedTangents
  636. traceNormal += bary[k] * lowMeshNormals[ index ];
  637. normal += bary[k] * lowMesh->verts[ index ].normal;
  638. tangents[0] += bary[k] * lowMesh->verts[ index ].tangents[0];
  639. tangents[1] += bary[k] * lowMesh->verts[ index ].tangents[1];
  640. }
  641. #if 0
  642. // this doesn't seem to make much difference
  643. // an argument can be made that these should not be normalized, because the interpolation
  644. // of the light position at rasterization time will be linear, not spherical
  645. normal.Normalize();
  646. tangents[0].Normalize();
  647. tangents[1].Normalize();
  648. #endif
  649. // find the best triangle in the high poly model for this
  650. // sampledNormal will normalized
  651. if ( !SampleHighMesh( rb, point, traceNormal, sampledNormal, sampledColor ) ) {
  652. #if 0
  653. // put bright red where all traces missed for debugging.
  654. // for production use, it is better to leave it blank so
  655. // the outlining fills it in
  656. globalDest[0] = 255;
  657. globalDest[1] = 0;
  658. globalDest[2] = 0;
  659. globalDest[3] = 255;
  660. localDest[0] = 255;
  661. localDest[1] = 0;
  662. localDest[2] = 0;
  663. localDest[3] = 255;
  664. #endif
  665. continue;
  666. }
  667. // mark whether this is an interior or edge texel
  668. *edgeDistance = ( edgeTexel ? 1.0 : 0 );
  669. // fill the object space normal map spot
  670. r = 128 + 127 * sampledNormal[0];
  671. g = 128 + 127 * sampledNormal[1];
  672. b = 128 + 127 * sampledNormal[2];
  673. globalDest[0] = r;
  674. globalDest[1] = g;
  675. globalDest[2] = b;
  676. globalDest[3] = 255;
  677. // transform to local tangent space
  678. idMat3 mat;
  679. mat[0] = tangents[0];
  680. mat[1] = tangents[1];
  681. mat[2] = normal;
  682. mat.InverseSelf();
  683. localNormal = mat * sampledNormal;
  684. localNormal.Normalize();
  685. r = 128 + 127 * localNormal[0];
  686. g = 128 + 127 * localNormal[1];
  687. b = 128 + 127 * localNormal[2];
  688. localDest[0] = r;
  689. localDest[1] = g;
  690. localDest[2] = b;
  691. localDest[3] = 255;
  692. colorDest[0] = sampledColor[0];
  693. colorDest[1] = sampledColor[1];
  694. colorDest[2] = sampledColor[2];
  695. colorDest[3] = sampledColor[3];
  696. }
  697. }
  698. }
  699. /*
  700. ================
  701. CombineModelSurfaces
  702. Frees the model and returns a new model with all triangles combined
  703. into one surface
  704. ================
  705. */
  706. static idRenderModel *CombineModelSurfaces( idRenderModel *model ) {
  707. int totalVerts;
  708. int totalIndexes;
  709. int numIndexes;
  710. int numVerts;
  711. int i, j;
  712. totalVerts = 0;
  713. totalIndexes = 0;
  714. for ( i = 0 ; i < model->NumSurfaces() ; i++ ) {
  715. const modelSurface_t *surf = model->Surface(i);
  716. totalVerts += surf->geometry->numVerts;
  717. totalIndexes += surf->geometry->numIndexes;
  718. }
  719. srfTriangles_t *newTri = R_AllocStaticTriSurf();
  720. R_AllocStaticTriSurfVerts( newTri, totalVerts );
  721. R_AllocStaticTriSurfIndexes( newTri, totalIndexes );
  722. newTri->numVerts = totalVerts;
  723. newTri->numIndexes = totalIndexes;
  724. newTri->bounds.Clear();
  725. idDrawVert *verts = newTri->verts;
  726. glIndex_t *indexes = newTri->indexes;
  727. numIndexes = 0;
  728. numVerts = 0;
  729. for ( i = 0 ; i < model->NumSurfaces() ; i++ ) {
  730. const modelSurface_t *surf = model->Surface(i);
  731. const srfTriangles_t *tri = surf->geometry;
  732. memcpy( verts + numVerts, tri->verts, tri->numVerts * sizeof( tri->verts[0] ) );
  733. for ( j = 0 ; j < tri->numIndexes ; j++ ) {
  734. indexes[numIndexes+j] = numVerts + tri->indexes[j];
  735. }
  736. newTri->bounds.AddBounds( tri->bounds );
  737. numIndexes += tri->numIndexes;
  738. numVerts += tri->numVerts;
  739. }
  740. modelSurface_t surf;
  741. surf.id = 0;
  742. surf.geometry = newTri;
  743. surf.shader = tr.defaultMaterial;
  744. idRenderModel *newModel = renderModelManager->AllocModel();
  745. newModel->AddSurface( surf );
  746. renderModelManager->FreeModel( model );
  747. return newModel;
  748. }
  749. /*
  750. ==============
  751. RenderBumpTriangles
  752. ==============
  753. */
  754. static void RenderBumpTriangles( srfTriangles_t *lowMesh, renderBump_t *rb ) {
  755. int i, j;
  756. RB_SetGL2D();
  757. qglDisable( GL_CULL_FACE );
  758. qglColor3f( 1, 1, 1 );
  759. qglMatrixMode( GL_PROJECTION );
  760. qglLoadIdentity();
  761. qglOrtho( 0, 1, 1, 0, -1, 1 );
  762. qglDisable( GL_BLEND );
  763. qglMatrixMode( GL_MODELVIEW );
  764. qglLoadIdentity();
  765. qglDisable( GL_DEPTH_TEST );
  766. qglClearColor(1,0,0,1);
  767. qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
  768. qglColor3f( 1, 1, 1 );
  769. // create smoothed normals for the surface, which might be
  770. // different than the normals at the vertexes if the
  771. // surface uses unsmoothedNormals, which only takes the
  772. // normal from a single triangle. We need properly smoothed
  773. // normals to make sure that the traces always go off normal
  774. // to the true surface.
  775. idVec3 *lowMeshNormals = (idVec3 *)Mem_ClearedAlloc( lowMesh->numVerts * sizeof( *lowMeshNormals ) );
  776. R_DeriveFacePlanes( lowMesh );
  777. R_CreateSilIndexes( lowMesh ); // recreate, merging the mirrored verts back together
  778. const idPlane *planes = lowMesh->facePlanes;
  779. for ( i = 0 ; i < lowMesh->numIndexes ; i += 3, planes++ ) {
  780. for ( j = 0 ; j < 3 ; j++ ) {
  781. int index;
  782. index = lowMesh->silIndexes[i+j];
  783. lowMeshNormals[index] += (*planes).Normal();
  784. }
  785. }
  786. // normalize and replicate from silIndexes to all indexes
  787. for ( i = 0 ; i < lowMesh->numIndexes ; i++ ) {
  788. lowMeshNormals[lowMesh->indexes[i]] = lowMeshNormals[lowMesh->silIndexes[i]];
  789. lowMeshNormals[lowMesh->indexes[i]].Normalize();
  790. }
  791. // rasterize each low poly face
  792. for ( j = 0 ; j < lowMesh->numIndexes ; j+=3 ) {
  793. // pump the event loop so the window can be dragged around
  794. Sys_GenerateEvents();
  795. RasterizeTriangle( lowMesh, lowMeshNormals, j/3, rb );
  796. qglClearColor(1,0,0,1);
  797. qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
  798. qglRasterPos2f( 0, 1 );
  799. qglPixelZoom( glConfig.vidWidth / (float)rb->width, glConfig.vidHeight / (float)rb->height );
  800. qglDrawPixels( rb->width, rb->height, GL_RGBA, GL_UNSIGNED_BYTE, rb->localPic );
  801. qglPixelZoom( 1, 1 );
  802. qglFlush();
  803. GLimp_SwapBuffers();
  804. }
  805. Mem_Free( lowMeshNormals );
  806. }
  807. /*
  808. ==============
  809. WriteRenderBump
  810. ==============
  811. */
  812. static void WriteRenderBump( renderBump_t *rb, int outLinePixels ) {
  813. int width, height;
  814. int i;
  815. idStr filename;
  816. renderModelManager->FreeModel( rb->highModel );
  817. FreeTriHash( rb->hash );
  818. width = rb->width;
  819. height = rb->height;
  820. #if 0
  821. // save the non-outlined version
  822. filename = source;
  823. filename.setFileExtension();
  824. filename.append( "_nooutline.tga" );
  825. common->Printf( "writing %s\n", filename.c_str() );
  826. WriteTGA( filename, globalPic, width, height );
  827. #endif
  828. // outline the image several times to help bilinear filtering across disconnected
  829. // edges, and mip-mapping
  830. for ( i = 0 ; i < outLinePixels ; i++ ) {
  831. OutlineNormalMap( rb->localPic, width, height, 128, 128, 128 );
  832. OutlineNormalMap( rb->globalPic, width, height, 128, 128, 128 );
  833. OutlineColorMap( rb->colorPic, width, height, 128, 128, 128 );
  834. }
  835. // filter down if we are anti-aliasing
  836. for ( i = 0 ; i < rb->antiAlias ; i++ ) {
  837. byte *old;
  838. old = rb->localPic;
  839. rb->localPic = R_MipMap( rb->localPic, width, height, false );
  840. Mem_Free( old );
  841. old = rb->globalPic;
  842. rb->globalPic = R_MipMap( rb->globalPic, width, height, false );
  843. Mem_Free( old );
  844. old = rb->colorPic;
  845. rb->colorPic = R_MipMap( rb->colorPic, width, height, false );
  846. Mem_Free( old );
  847. width >>= 1;
  848. height >>= 1;
  849. }
  850. // write out the local map
  851. filename = rb->outputName;
  852. filename.SetFileExtension( ".tga" );
  853. common->Printf( "writing %s (%i,%i)\n", filename.c_str(), width, height );
  854. R_WriteTGA( filename, rb->localPic, width, height );
  855. if ( rb->saveGlobalMap ) {
  856. filename = rb->outputName;
  857. filename.StripFileExtension();
  858. filename.Append( "_global.tga" );
  859. common->Printf( "writing %s (%i,%i)\n", filename.c_str(), width, height );
  860. R_WriteTGA( filename, rb->globalPic, width, height );
  861. }
  862. if ( rb->saveColorMap ) {
  863. filename = rb->outputName;
  864. filename.StripFileExtension();
  865. filename.Append( "_color.tga" );
  866. common->Printf( "writing %s (%i,%i)\n", filename.c_str(), width, height );
  867. R_WriteTGA( filename, rb->colorPic, width, height );
  868. }
  869. Mem_Free( rb->localPic );
  870. Mem_Free( rb->globalPic );
  871. Mem_Free( rb->colorPic );
  872. Mem_Free( rb->edgeDistances );
  873. }
  874. /*
  875. ===============
  876. InitRenderBump
  877. ===============
  878. */
  879. static void InitRenderBump( renderBump_t *rb ) {
  880. srfTriangles_t *mesh;
  881. idBounds bounds;
  882. int i, c;
  883. // load the ase file
  884. common->Printf( "loading %s...\n", rb->highName );
  885. rb->highModel = renderModelManager->AllocModel();
  886. rb->highModel->PartialInitFromFile( rb->highName );
  887. if ( !rb->highModel ) {
  888. common->Error( "failed to load %s", rb->highName );
  889. }
  890. // combine the high poly model into a single polyset
  891. if ( rb->highModel->NumSurfaces() != 1 ) {
  892. rb->highModel = CombineModelSurfaces( rb->highModel );
  893. }
  894. const modelSurface_t *surf = rb->highModel->Surface( 0 );
  895. mesh = surf->geometry;
  896. rb->mesh = mesh;
  897. R_DeriveFacePlanes( mesh );
  898. // create a face hash table to accelerate the tracing
  899. rb->hash = CreateTriHash( mesh );
  900. // bound the entire file
  901. R_BoundTriSurf( mesh );
  902. bounds = mesh->bounds;
  903. // the traceDist will be the traceFrac times the larges bounds axis
  904. rb->traceDist = 0;
  905. for ( i = 0 ; i < 3 ; i++ ) {
  906. float d;
  907. d = rb->traceFrac * ( bounds[1][i] - bounds[0][i] );
  908. if ( d > rb->traceDist ) {
  909. rb->traceDist = d;
  910. }
  911. }
  912. common->Printf( "trace fraction %4.2f = %6.2f model units\n", rb->traceFrac, rb->traceDist );
  913. c = rb->width * rb->height * 4;
  914. // local normal map
  915. rb->localPic = (byte *)Mem_Alloc( c );
  916. // global (object space, not surface space) normal map
  917. rb->globalPic = (byte *)Mem_Alloc( c );
  918. // color pic for artist reference
  919. rb->colorPic = (byte *)Mem_Alloc( c );
  920. // edgeDistance for marking outside-the-triangle traces
  921. rb->edgeDistances = (float *)Mem_Alloc( c );
  922. for ( i = 0 ; i < c ; i+=4 ) {
  923. rb->localPic[i+0] = 128;
  924. rb->localPic[i+1] = 128;
  925. rb->localPic[i+2] = 128;
  926. rb->localPic[i+3] = 0; // the artists use this for masking traced pixels sometimes
  927. rb->globalPic[i+0] = 128;
  928. rb->globalPic[i+1] = 128;
  929. rb->globalPic[i+2] = 128;
  930. rb->globalPic[i+3] = 0;
  931. rb->colorPic[i+0] = 128;
  932. rb->colorPic[i+1] = 128;
  933. rb->colorPic[i+2] = 128;
  934. rb->colorPic[i+3] = 0;
  935. rb->edgeDistances[i/4] = -1; // not traced yet
  936. }
  937. }
  938. /*
  939. ==============
  940. RenderBump_f
  941. ==============
  942. */
  943. void RenderBump_f( const idCmdArgs &args ) {
  944. idRenderModel *lowPoly;
  945. idStr source;
  946. int i, j;
  947. const char *cmdLine;
  948. int numRenderBumps;
  949. renderBump_t *renderBumps, *rb;
  950. renderBump_t opt;
  951. int startTime, endTime;
  952. // update the screen as we print
  953. common->SetRefreshOnPrint( true );
  954. // there should be a single parameter, the filename for a game loadable low-poly model
  955. if ( args.Argc() != 2 ) {
  956. common->Error( "Usage: renderbump <lowPolyModel>" );
  957. }
  958. common->Printf( "----- Renderbump %s -----\n", args.Argv( 1 ) );
  959. startTime = Sys_Milliseconds();
  960. // get the lowPoly model
  961. source = args.Argv( 1 );
  962. lowPoly = renderModelManager->CheckModel( source );
  963. if ( !lowPoly ) {
  964. common->Error( "Can't load model %s", source.c_str() );
  965. }
  966. renderBumps = (renderBump_t *)R_StaticAlloc( lowPoly->NumSurfaces() * sizeof( *renderBumps ) );
  967. numRenderBumps = 0;
  968. for ( i = 0 ; i < lowPoly->NumSurfaces() ; i++ ) {
  969. const modelSurface_t *ms = lowPoly->Surface( i );
  970. // default options
  971. memset( &opt, 0, sizeof( opt ) );
  972. opt.width = 512;
  973. opt.height = 512;
  974. opt.antiAlias = 1;
  975. opt.outline = 8;
  976. opt.traceFrac = 0.05f;
  977. // parse the renderbump parameters for this surface
  978. cmdLine = ms->shader->GetRenderBump();
  979. common->Printf( "surface %i, shader %s\nrenderBump = %s ", i,
  980. ms->shader->GetName(), cmdLine );
  981. if ( !ms->geometry ) {
  982. common->Printf( "(no geometry)\n" );
  983. continue;
  984. }
  985. idCmdArgs localArgs;
  986. localArgs.TokenizeString( cmdLine, false );
  987. if ( localArgs.Argc() < 2 ) {
  988. common->Printf( "(no action)\n" );
  989. continue;
  990. }
  991. common->Printf( "(rendering)\n" );
  992. for ( j = 0 ; j < localArgs.Argc() - 2; j++ ) {
  993. const char *s;
  994. s = localArgs.Argv( j );
  995. if ( s[0] == '-' ) {
  996. j++;
  997. s = localArgs.Argv( j );
  998. if ( s[0] == '\0' ) {
  999. continue;
  1000. }
  1001. }
  1002. if ( !idStr::Icmp( s, "size" ) ) {
  1003. if ( j + 2 >= localArgs.Argc() ) {
  1004. j = localArgs.Argc();
  1005. break;
  1006. }
  1007. opt.width = atoi( localArgs.Argv( j + 1 ) );
  1008. opt.height = atoi( localArgs.Argv( j + 2 ) );
  1009. j += 2;
  1010. } else if ( !idStr::Icmp( s, "trace" ) ) {
  1011. opt.traceFrac = atof( localArgs.Argv( j + 1 ) );
  1012. j += 1;
  1013. } else if ( !idStr::Icmp( s, "globalMap" ) ) {
  1014. opt.saveGlobalMap = true;
  1015. } else if ( !idStr::Icmp( s, "colorMap" ) ) {
  1016. opt.saveColorMap = true;
  1017. } else if ( !idStr::Icmp( s, "outline" ) ) {
  1018. opt.outline = atoi( localArgs.Argv( j + 1 ) );
  1019. j += 1;
  1020. } else if ( !idStr::Icmp( s, "aa" ) ) {
  1021. opt.antiAlias = atoi( localArgs.Argv( j + 1 ) );
  1022. j += 1;
  1023. } else {
  1024. common->Printf( "WARNING: Unknown option \"%s\"\n", s );
  1025. break;
  1026. }
  1027. }
  1028. if ( j != ( localArgs.Argc() - 2 ) ) {
  1029. common->Error( "usage: renderBump [-size width height] [-aa <1-2>] [globalMap] [colorMap] [-trace <0.01 - 1.0>] normalMapImageFile highPolyAseFile" );
  1030. }
  1031. idStr::Copynz( opt.outputName, localArgs.Argv( j ), sizeof( opt.outputName ) );
  1032. idStr::Copynz( opt.highName, localArgs.Argv( j + 1 ), sizeof( opt.highName ) );
  1033. // adjust size for anti-aliasing
  1034. opt.width <<= opt.antiAlias;
  1035. opt.height <<= opt.antiAlias;
  1036. // see if we already have a renderbump going for another surface that this should use
  1037. for ( j = 0 ; j < numRenderBumps ; j++ ) {
  1038. rb = &renderBumps[j];
  1039. if ( idStr::Icmp( rb->outputName, opt.outputName ) ) {
  1040. continue;
  1041. }
  1042. // all the other parameters must match, or it is an error
  1043. if ( idStr::Icmp( rb->highName, opt.highName) || rb->width != opt.width ||
  1044. rb->height != opt.height || rb->antiAlias != opt.antiAlias ||
  1045. rb->traceFrac != opt.traceFrac ) {
  1046. common->Error( "mismatched renderbump parameters on image %s", rb->outputName );
  1047. continue;
  1048. }
  1049. // saveGlobalMap will be a sticky option
  1050. rb->saveGlobalMap = rb->saveGlobalMap | opt.saveGlobalMap;
  1051. break;
  1052. }
  1053. // create a new renderbump if needed
  1054. if ( j == numRenderBumps ) {
  1055. numRenderBumps++;
  1056. rb = &renderBumps[j];
  1057. *rb = opt;
  1058. InitRenderBump( rb );
  1059. }
  1060. // render the triangles for this surface
  1061. RenderBumpTriangles( ms->geometry, rb );
  1062. }
  1063. //
  1064. // anti-alias and write out all renderbumps that we have completed
  1065. //
  1066. for ( i = 0 ; i < numRenderBumps ; i++ ) {
  1067. WriteRenderBump( &renderBumps[i], opt.outline << opt.antiAlias );
  1068. }
  1069. R_StaticFree( renderBumps );
  1070. endTime = Sys_Milliseconds();
  1071. common->Printf( "%5.2f seconds for renderBump\n", ( endTime - startTime ) / 1000.0 );
  1072. common->Printf( "---------- RenderBump Completed ----------\n" );
  1073. // stop updating the screen as we print
  1074. common->SetRefreshOnPrint( false );
  1075. }
  1076. /*
  1077. ==================================================================================
  1078. FLAT
  1079. The flat case is trivial, and accomplished with hardware rendering
  1080. ==================================================================================
  1081. */
  1082. /*
  1083. ==============
  1084. RenderBumpFlat_f
  1085. ==============
  1086. */
  1087. void RenderBumpFlat_f( const idCmdArgs &args ) {
  1088. int width, height;
  1089. idStr source;
  1090. int i;
  1091. idBounds bounds;
  1092. srfTriangles_t *mesh;
  1093. float boundsScale;
  1094. // update the screen as we print
  1095. common->SetRefreshOnPrint( true );
  1096. width = height = 256;
  1097. boundsScale = 0;
  1098. // check options
  1099. for ( i = 1 ; i < args.Argc() - 1; i++ ) {
  1100. const char *s;
  1101. s = args.Argv( i );
  1102. if ( s[0] == '-' ) {
  1103. i++;
  1104. s = args.Argv( i );
  1105. }
  1106. if ( !idStr::Icmp( s, "size" ) ) {
  1107. if ( i + 2 >= args.Argc() ) {
  1108. i = args.Argc();
  1109. break;
  1110. }
  1111. width = atoi( args.Argv( i + 1 ) );
  1112. height = atoi( args.Argv( i + 2 ) );
  1113. i += 2;
  1114. } else {
  1115. common->Printf( "WARNING: Unknown option \"%s\"\n", s );
  1116. break;
  1117. }
  1118. }
  1119. if ( i != ( args.Argc() - 1 ) ) {
  1120. common->Error( "usage: renderBumpFlat [-size width height] asefile" );
  1121. }
  1122. common->Printf( "Final image size: %i, %i\n", width, height );
  1123. // load the source in "fastload" mode, because we don't
  1124. // need tangent and shadow information
  1125. source = args.Argv( i );
  1126. idRenderModel *highPolyModel = renderModelManager->AllocModel();
  1127. highPolyModel->PartialInitFromFile( source );
  1128. if ( highPolyModel->IsDefaultModel() ) {
  1129. common->Error( "failed to load %s", source.c_str() );
  1130. }
  1131. // combine the high poly model into a single polyset
  1132. if ( highPolyModel->NumSurfaces() != 1 ) {
  1133. highPolyModel = CombineModelSurfaces( highPolyModel );
  1134. }
  1135. // create normals if not present in file
  1136. const modelSurface_t *surf = highPolyModel->Surface( 0 );
  1137. mesh = surf->geometry;
  1138. // bound the entire file
  1139. R_BoundTriSurf( mesh );
  1140. bounds = mesh->bounds;
  1141. SaveWindow();
  1142. ResizeWindow( width, height );
  1143. // for small images, the viewport may be less than the minimum window
  1144. qglViewport( 0, 0, width, height );
  1145. qglEnable( GL_CULL_FACE );
  1146. qglCullFace( GL_FRONT );
  1147. qglDisable( GL_STENCIL_TEST );
  1148. qglDisable( GL_SCISSOR_TEST );
  1149. qglDisable( GL_ALPHA_TEST );
  1150. qglDisable( GL_BLEND );
  1151. qglEnable( GL_DEPTH_TEST );
  1152. qglDisable( GL_TEXTURE_2D );
  1153. qglDepthMask( GL_TRUE );
  1154. qglDepthFunc( GL_LEQUAL );
  1155. qglColor3f( 1, 1, 1 );
  1156. qglMatrixMode( GL_PROJECTION );
  1157. qglLoadIdentity();
  1158. qglOrtho( bounds[0][0], bounds[1][0], bounds[0][2],
  1159. bounds[1][2], -( bounds[0][1] - 1 ), -( bounds[1][1] + 1 ) );
  1160. qglMatrixMode( GL_MODELVIEW );
  1161. qglLoadIdentity();
  1162. // flat maps are automatically anti-aliased
  1163. idStr filename;
  1164. int j, k, c;
  1165. byte *buffer;
  1166. int *sumBuffer, *colorSumBuffer;
  1167. bool flat;
  1168. int sample;
  1169. sumBuffer = (int *)Mem_Alloc( width * height * 4 * 4 );
  1170. memset( sumBuffer, 0, width * height * 4 * 4 );
  1171. buffer = (byte *)Mem_Alloc( width * height * 4 );
  1172. colorSumBuffer = (int *)Mem_Alloc( width * height * 4 * 4 );
  1173. memset( sumBuffer, 0, width * height * 4 * 4 );
  1174. flat = false;
  1175. //flat = true;
  1176. for ( sample = 0 ; sample < 16 ; sample++ ) {
  1177. float xOff, yOff;
  1178. xOff = ( ( sample & 3 ) / 4.0 ) * ( bounds[1][0] - bounds[0][0] ) / width;
  1179. yOff = ( ( sample / 4 ) / 4.0 ) * ( bounds[1][2] - bounds[0][2] ) / height;
  1180. for ( int colorPass = 0 ; colorPass < 2 ; colorPass++ ) {
  1181. qglClearColor(0.5,0.5,0.5,0);
  1182. qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
  1183. qglBegin( GL_TRIANGLES );
  1184. for ( i = 0 ; i < highPolyModel->NumSurfaces() ; i++ ) {
  1185. const modelSurface_t *surf = highPolyModel->Surface( i );
  1186. mesh = surf->geometry;
  1187. if ( colorPass ) {
  1188. // just render the surface color for artist visualization
  1189. for ( j = 0 ; j < mesh->numIndexes ; j+=3 ) {
  1190. for ( k = 0 ; k < 3 ; k++ ) {
  1191. int v;
  1192. float *a;
  1193. v = mesh->indexes[j+k];
  1194. qglColor3ubv( mesh->verts[v].color );
  1195. a = mesh->verts[v].xyz.ToFloatPtr();
  1196. qglVertex3f( a[0] + xOff, a[2] + yOff, a[1] );
  1197. }
  1198. }
  1199. } else {
  1200. // render as normal map
  1201. // we can either flat shade from the plane,
  1202. // or smooth shade from the vertex normals
  1203. for ( j = 0 ; j < mesh->numIndexes ; j+=3 ) {
  1204. if ( flat ) {
  1205. idPlane plane;
  1206. idVec3 *a, *b, *c;
  1207. int v1, v2, v3;
  1208. v1 = mesh->indexes[j+0];
  1209. v2 = mesh->indexes[j+1];
  1210. v3 = mesh->indexes[j+2];
  1211. a = &mesh->verts[ v1 ].xyz;
  1212. b = &mesh->verts[ v2 ].xyz;
  1213. c = &mesh->verts[ v3 ].xyz;
  1214. plane.FromPoints( *a, *b, *c );
  1215. // NULLNORMAL is used by the artists to force an area to reflect no
  1216. // light at all
  1217. if ( surf->shader->GetSurfaceFlags() & SURF_NULLNORMAL ) {
  1218. qglColor3f( 0.5, 0.5, 0.5 );
  1219. } else {
  1220. qglColor3f( 0.5 + 0.5*plane[0], 0.5 - 0.5*plane[2], 0.5 - 0.5*plane[1] );
  1221. }
  1222. qglVertex3f( (*a)[0] + xOff, (*a)[2] + yOff, (*a)[1] );
  1223. qglVertex3f( (*b)[0] + xOff, (*b)[2] + yOff, (*b)[1] );
  1224. qglVertex3f( (*c)[0] + xOff, (*c)[2] + yOff, (*c)[1] );
  1225. } else {
  1226. for ( k = 0 ; k < 3 ; k++ ) {
  1227. int v;
  1228. float *n;
  1229. float *a;
  1230. v = mesh->indexes[j+k];
  1231. n = mesh->verts[v].normal.ToFloatPtr();
  1232. // NULLNORMAL is used by the artists to force an area to reflect no
  1233. // light at all
  1234. if ( surf->shader->GetSurfaceFlags() & SURF_NULLNORMAL ) {
  1235. qglColor3f( 0.5, 0.5, 0.5 );
  1236. } else {
  1237. // we are going to flip the normal Z direction
  1238. qglColor3f( 0.5 + 0.5*n[0], 0.5 - 0.5*n[2], 0.5 - 0.5*n[1] );
  1239. }
  1240. a = mesh->verts[v].xyz.ToFloatPtr();
  1241. qglVertex3f( a[0] + xOff, a[2] + yOff, a[1] );
  1242. }
  1243. }
  1244. }
  1245. }
  1246. }
  1247. qglEnd();
  1248. qglFlush();
  1249. GLimp_SwapBuffers();
  1250. qglReadPixels( 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer );
  1251. if ( colorPass ) {
  1252. // add to the sum buffer
  1253. for ( i = 0 ; i < c ; i++ ) {
  1254. colorSumBuffer[i*4+0] += buffer[i*4+0];
  1255. colorSumBuffer[i*4+1] += buffer[i*4+1];
  1256. colorSumBuffer[i*4+2] += buffer[i*4+2];
  1257. colorSumBuffer[i*4+3] += buffer[i*4+3];
  1258. }
  1259. } else {
  1260. // normalize
  1261. c = width * height;
  1262. for ( i = 0 ; i < c ; i++ ) {
  1263. idVec3 v;
  1264. v[0] = ( buffer[i*4+0] - 128 ) / 127.0;
  1265. v[1] = ( buffer[i*4+1] - 128 ) / 127.0;
  1266. v[2] = ( buffer[i*4+2] - 128 ) / 127.0;
  1267. v.Normalize();
  1268. buffer[i*4+0] = 128 + 127 * v[0];
  1269. buffer[i*4+1] = 128 + 127 * v[1];
  1270. buffer[i*4+2] = 128 + 127 * v[2];
  1271. }
  1272. // outline into non-drawn areas
  1273. for ( i = 0 ; i < 8 ; i++ ) {
  1274. OutlineNormalMap( buffer, width, height, 128, 128, 128 );
  1275. }
  1276. // add to the sum buffer
  1277. for ( i = 0 ; i < c ; i++ ) {
  1278. sumBuffer[i*4+0] += buffer[i*4+0];
  1279. sumBuffer[i*4+1] += buffer[i*4+1];
  1280. sumBuffer[i*4+2] += buffer[i*4+2];
  1281. sumBuffer[i*4+3] += buffer[i*4+3];
  1282. }
  1283. }
  1284. }
  1285. }
  1286. c = width * height;
  1287. // save out the color map
  1288. for ( i = 0 ; i < c ; i++ ) {
  1289. buffer[i*4+0] = colorSumBuffer[i*4+0] / 16;
  1290. buffer[i*4+1] = colorSumBuffer[i*4+1] / 16;
  1291. buffer[i*4+2] = colorSumBuffer[i*4+2] / 16;
  1292. buffer[i*4+3] = colorSumBuffer[i*4+3] / 16;
  1293. }
  1294. filename = source;
  1295. filename.StripFileExtension();
  1296. filename.Append( "_color.tga" );
  1297. R_VerticalFlip( buffer, width, height );
  1298. R_WriteTGA( filename, buffer, width, height );
  1299. // save out the local map
  1300. // scale the sum buffer back down to the sample buffer
  1301. // we allow this to denormalize
  1302. for ( i = 0 ; i < c ; i++ ) {
  1303. buffer[i*4+0] = sumBuffer[i*4+0] / 16;
  1304. buffer[i*4+1] = sumBuffer[i*4+1] / 16;
  1305. buffer[i*4+2] = sumBuffer[i*4+2] / 16;
  1306. buffer[i*4+3] = sumBuffer[i*4+3] / 16;
  1307. }
  1308. filename = source;
  1309. filename.StripFileExtension();
  1310. filename.Append( "_local.tga" );
  1311. common->Printf( "writing %s (%i,%i)\n", filename.c_str(), width, height );
  1312. R_VerticalFlip( buffer, width, height );
  1313. R_WriteTGA( filename, buffer, width, height );
  1314. // free the model
  1315. renderModelManager->FreeModel( highPolyModel );
  1316. // free our work buffer
  1317. Mem_Free( buffer );
  1318. Mem_Free( sumBuffer );
  1319. Mem_Free( colorSumBuffer );
  1320. RestoreWindow();
  1321. // stop updating the screen as we print
  1322. common->SetRefreshOnPrint( false );
  1323. common->Error( "Completed." );
  1324. }