r_surf.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652
  1. /*
  2. Copyright (C) 1997-2001 Id Software, Inc.
  3. This program is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU General Public License
  5. as published by the Free Software Foundation; either version 2
  6. of the License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. See the GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  14. */
  15. // r_surf.c: surface-related refresh code
  16. #include "r_local.h"
  17. drawsurf_t r_drawsurf;
  18. int lightleft, sourcesstep, blocksize, sourcetstep;
  19. int lightdelta, lightdeltastep;
  20. int lightright, lightleftstep, lightrightstep, blockdivshift;
  21. unsigned blockdivmask;
  22. void *prowdestbase;
  23. unsigned char *pbasesource;
  24. int surfrowbytes; // used by ASM files
  25. unsigned *r_lightptr;
  26. int r_stepback;
  27. int r_lightwidth;
  28. int r_numhblocks, r_numvblocks;
  29. unsigned char *r_source, *r_sourcemax;
  30. void R_DrawSurfaceBlock8_mip0 (void);
  31. void R_DrawSurfaceBlock8_mip1 (void);
  32. void R_DrawSurfaceBlock8_mip2 (void);
  33. void R_DrawSurfaceBlock8_mip3 (void);
  34. static void (*surfmiptable[4])(void) = {
  35. R_DrawSurfaceBlock8_mip0,
  36. R_DrawSurfaceBlock8_mip1,
  37. R_DrawSurfaceBlock8_mip2,
  38. R_DrawSurfaceBlock8_mip3
  39. };
  40. void R_BuildLightMap (void);
  41. extern unsigned blocklights[1024]; // allow some very large lightmaps
  42. float surfscale;
  43. qboolean r_cache_thrash; // set if surface cache is thrashing
  44. int sc_size;
  45. surfcache_t *sc_rover, *sc_base;
  46. /*
  47. ===============
  48. R_TextureAnimation
  49. Returns the proper texture for a given time and base texture
  50. ===============
  51. */
  52. image_t *R_TextureAnimation (mtexinfo_t *tex)
  53. {
  54. int c;
  55. if (!tex->next)
  56. return tex->image;
  57. c = currententity->frame % tex->numframes;
  58. while (c)
  59. {
  60. tex = tex->next;
  61. c--;
  62. }
  63. return tex->image;
  64. }
  65. /*
  66. ===============
  67. R_DrawSurface
  68. ===============
  69. */
  70. void R_DrawSurface (void)
  71. {
  72. unsigned char *basetptr;
  73. int smax, tmax, twidth;
  74. int u;
  75. int soffset, basetoffset, texwidth;
  76. int horzblockstep;
  77. unsigned char *pcolumndest;
  78. void (*pblockdrawer)(void);
  79. image_t *mt;
  80. surfrowbytes = r_drawsurf.rowbytes;
  81. mt = r_drawsurf.image;
  82. r_source = mt->pixels[r_drawsurf.surfmip];
  83. // the fractional light values should range from 0 to (VID_GRADES - 1) << 16
  84. // from a source range of 0 - 255
  85. texwidth = mt->width >> r_drawsurf.surfmip;
  86. blocksize = 16 >> r_drawsurf.surfmip;
  87. blockdivshift = 4 - r_drawsurf.surfmip;
  88. blockdivmask = (1 << blockdivshift) - 1;
  89. r_lightwidth = (r_drawsurf.surf->extents[0]>>4)+1;
  90. r_numhblocks = r_drawsurf.surfwidth >> blockdivshift;
  91. r_numvblocks = r_drawsurf.surfheight >> blockdivshift;
  92. //==============================
  93. pblockdrawer = surfmiptable[r_drawsurf.surfmip];
  94. // TODO: only needs to be set when there is a display settings change
  95. horzblockstep = blocksize;
  96. smax = mt->width >> r_drawsurf.surfmip;
  97. twidth = texwidth;
  98. tmax = mt->height >> r_drawsurf.surfmip;
  99. sourcetstep = texwidth;
  100. r_stepback = tmax * twidth;
  101. r_sourcemax = r_source + (tmax * smax);
  102. soffset = r_drawsurf.surf->texturemins[0];
  103. basetoffset = r_drawsurf.surf->texturemins[1];
  104. // << 16 components are to guarantee positive values for %
  105. soffset = ((soffset >> r_drawsurf.surfmip) + (smax << 16)) % smax;
  106. basetptr = &r_source[((((basetoffset >> r_drawsurf.surfmip)
  107. + (tmax << 16)) % tmax) * twidth)];
  108. pcolumndest = r_drawsurf.surfdat;
  109. for (u=0 ; u<r_numhblocks; u++)
  110. {
  111. r_lightptr = blocklights + u;
  112. prowdestbase = pcolumndest;
  113. pbasesource = basetptr + soffset;
  114. (*pblockdrawer)();
  115. soffset = soffset + blocksize;
  116. if (soffset >= smax)
  117. soffset = 0;
  118. pcolumndest += horzblockstep;
  119. }
  120. }
  121. //=============================================================================
  122. #if !id386
  123. /*
  124. ================
  125. R_DrawSurfaceBlock8_mip0
  126. ================
  127. */
  128. void R_DrawSurfaceBlock8_mip0 (void)
  129. {
  130. int v, i, b, lightstep, lighttemp, light;
  131. unsigned char pix, *psource, *prowdest;
  132. psource = pbasesource;
  133. prowdest = prowdestbase;
  134. for (v=0 ; v<r_numvblocks ; v++)
  135. {
  136. // FIXME: make these locals?
  137. // FIXME: use delta rather than both right and left, like ASM?
  138. lightleft = r_lightptr[0];
  139. lightright = r_lightptr[1];
  140. r_lightptr += r_lightwidth;
  141. lightleftstep = (r_lightptr[0] - lightleft) >> 4;
  142. lightrightstep = (r_lightptr[1] - lightright) >> 4;
  143. for (i=0 ; i<16 ; i++)
  144. {
  145. lighttemp = lightleft - lightright;
  146. lightstep = lighttemp >> 4;
  147. light = lightright;
  148. for (b=15; b>=0; b--)
  149. {
  150. pix = psource[b];
  151. prowdest[b] = ((unsigned char *)vid.colormap)
  152. [(light & 0xFF00) + pix];
  153. light += lightstep;
  154. }
  155. psource += sourcetstep;
  156. lightright += lightrightstep;
  157. lightleft += lightleftstep;
  158. prowdest += surfrowbytes;
  159. }
  160. if (psource >= r_sourcemax)
  161. psource -= r_stepback;
  162. }
  163. }
  164. /*
  165. ================
  166. R_DrawSurfaceBlock8_mip1
  167. ================
  168. */
  169. void R_DrawSurfaceBlock8_mip1 (void)
  170. {
  171. int v, i, b, lightstep, lighttemp, light;
  172. unsigned char pix, *psource, *prowdest;
  173. psource = pbasesource;
  174. prowdest = prowdestbase;
  175. for (v=0 ; v<r_numvblocks ; v++)
  176. {
  177. // FIXME: make these locals?
  178. // FIXME: use delta rather than both right and left, like ASM?
  179. lightleft = r_lightptr[0];
  180. lightright = r_lightptr[1];
  181. r_lightptr += r_lightwidth;
  182. lightleftstep = (r_lightptr[0] - lightleft) >> 3;
  183. lightrightstep = (r_lightptr[1] - lightright) >> 3;
  184. for (i=0 ; i<8 ; i++)
  185. {
  186. lighttemp = lightleft - lightright;
  187. lightstep = lighttemp >> 3;
  188. light = lightright;
  189. for (b=7; b>=0; b--)
  190. {
  191. pix = psource[b];
  192. prowdest[b] = ((unsigned char *)vid.colormap)
  193. [(light & 0xFF00) + pix];
  194. light += lightstep;
  195. }
  196. psource += sourcetstep;
  197. lightright += lightrightstep;
  198. lightleft += lightleftstep;
  199. prowdest += surfrowbytes;
  200. }
  201. if (psource >= r_sourcemax)
  202. psource -= r_stepback;
  203. }
  204. }
  205. /*
  206. ================
  207. R_DrawSurfaceBlock8_mip2
  208. ================
  209. */
  210. void R_DrawSurfaceBlock8_mip2 (void)
  211. {
  212. int v, i, b, lightstep, lighttemp, light;
  213. unsigned char pix, *psource, *prowdest;
  214. psource = pbasesource;
  215. prowdest = prowdestbase;
  216. for (v=0 ; v<r_numvblocks ; v++)
  217. {
  218. // FIXME: make these locals?
  219. // FIXME: use delta rather than both right and left, like ASM?
  220. lightleft = r_lightptr[0];
  221. lightright = r_lightptr[1];
  222. r_lightptr += r_lightwidth;
  223. lightleftstep = (r_lightptr[0] - lightleft) >> 2;
  224. lightrightstep = (r_lightptr[1] - lightright) >> 2;
  225. for (i=0 ; i<4 ; i++)
  226. {
  227. lighttemp = lightleft - lightright;
  228. lightstep = lighttemp >> 2;
  229. light = lightright;
  230. for (b=3; b>=0; b--)
  231. {
  232. pix = psource[b];
  233. prowdest[b] = ((unsigned char *)vid.colormap)
  234. [(light & 0xFF00) + pix];
  235. light += lightstep;
  236. }
  237. psource += sourcetstep;
  238. lightright += lightrightstep;
  239. lightleft += lightleftstep;
  240. prowdest += surfrowbytes;
  241. }
  242. if (psource >= r_sourcemax)
  243. psource -= r_stepback;
  244. }
  245. }
  246. /*
  247. ================
  248. R_DrawSurfaceBlock8_mip3
  249. ================
  250. */
  251. void R_DrawSurfaceBlock8_mip3 (void)
  252. {
  253. int v, i, b, lightstep, lighttemp, light;
  254. unsigned char pix, *psource, *prowdest;
  255. psource = pbasesource;
  256. prowdest = prowdestbase;
  257. for (v=0 ; v<r_numvblocks ; v++)
  258. {
  259. // FIXME: make these locals?
  260. // FIXME: use delta rather than both right and left, like ASM?
  261. lightleft = r_lightptr[0];
  262. lightright = r_lightptr[1];
  263. r_lightptr += r_lightwidth;
  264. lightleftstep = (r_lightptr[0] - lightleft) >> 1;
  265. lightrightstep = (r_lightptr[1] - lightright) >> 1;
  266. for (i=0 ; i<2 ; i++)
  267. {
  268. lighttemp = lightleft - lightright;
  269. lightstep = lighttemp >> 1;
  270. light = lightright;
  271. for (b=1; b>=0; b--)
  272. {
  273. pix = psource[b];
  274. prowdest[b] = ((unsigned char *)vid.colormap)
  275. [(light & 0xFF00) + pix];
  276. light += lightstep;
  277. }
  278. psource += sourcetstep;
  279. lightright += lightrightstep;
  280. lightleft += lightleftstep;
  281. prowdest += surfrowbytes;
  282. }
  283. if (psource >= r_sourcemax)
  284. psource -= r_stepback;
  285. }
  286. }
  287. #endif
  288. //============================================================================
  289. /*
  290. ================
  291. R_InitCaches
  292. ================
  293. */
  294. void R_InitCaches (void)
  295. {
  296. int size;
  297. int pix;
  298. // calculate size to allocate
  299. if (sw_surfcacheoverride->value)
  300. {
  301. size = sw_surfcacheoverride->value;
  302. }
  303. else
  304. {
  305. size = SURFCACHE_SIZE_AT_320X240;
  306. pix = vid.width*vid.height;
  307. if (pix > 64000)
  308. size += (pix-64000)*3;
  309. }
  310. // round up to page size
  311. size = (size + 8191) & ~8191;
  312. ri.Con_Printf (PRINT_ALL,"%ik surface cache\n", size/1024);
  313. sc_size = size;
  314. sc_base = (surfcache_t *)malloc(size);
  315. sc_rover = sc_base;
  316. sc_base->next = NULL;
  317. sc_base->owner = NULL;
  318. sc_base->size = sc_size;
  319. }
  320. /*
  321. ==================
  322. D_FlushCaches
  323. ==================
  324. */
  325. void D_FlushCaches (void)
  326. {
  327. surfcache_t *c;
  328. if (!sc_base)
  329. return;
  330. for (c = sc_base ; c ; c = c->next)
  331. {
  332. if (c->owner)
  333. *c->owner = NULL;
  334. }
  335. sc_rover = sc_base;
  336. sc_base->next = NULL;
  337. sc_base->owner = NULL;
  338. sc_base->size = sc_size;
  339. }
  340. /*
  341. =================
  342. D_SCAlloc
  343. =================
  344. */
  345. surfcache_t *D_SCAlloc (int width, int size)
  346. {
  347. surfcache_t *new;
  348. qboolean wrapped_this_time;
  349. if ((width < 0) || (width > 256))
  350. ri.Sys_Error (ERR_FATAL,"D_SCAlloc: bad cache width %d\n", width);
  351. if ((size <= 0) || (size > 0x10000))
  352. ri.Sys_Error (ERR_FATAL,"D_SCAlloc: bad cache size %d\n", size);
  353. size = (int)&((surfcache_t *)0)->data[size];
  354. size = (size + 3) & ~3;
  355. if (size > sc_size)
  356. ri.Sys_Error (ERR_FATAL,"D_SCAlloc: %i > cache size of %i",size, sc_size);
  357. // if there is not size bytes after the rover, reset to the start
  358. wrapped_this_time = false;
  359. if ( !sc_rover || (byte *)sc_rover - (byte *)sc_base > sc_size - size)
  360. {
  361. if (sc_rover)
  362. {
  363. wrapped_this_time = true;
  364. }
  365. sc_rover = sc_base;
  366. }
  367. // colect and free surfcache_t blocks until the rover block is large enough
  368. new = sc_rover;
  369. if (sc_rover->owner)
  370. *sc_rover->owner = NULL;
  371. while (new->size < size)
  372. {
  373. // free another
  374. sc_rover = sc_rover->next;
  375. if (!sc_rover)
  376. ri.Sys_Error (ERR_FATAL,"D_SCAlloc: hit the end of memory");
  377. if (sc_rover->owner)
  378. *sc_rover->owner = NULL;
  379. new->size += sc_rover->size;
  380. new->next = sc_rover->next;
  381. }
  382. // create a fragment out of any leftovers
  383. if (new->size - size > 256)
  384. {
  385. sc_rover = (surfcache_t *)( (byte *)new + size);
  386. sc_rover->size = new->size - size;
  387. sc_rover->next = new->next;
  388. sc_rover->width = 0;
  389. sc_rover->owner = NULL;
  390. new->next = sc_rover;
  391. new->size = size;
  392. }
  393. else
  394. sc_rover = new->next;
  395. new->width = width;
  396. // DEBUG
  397. if (width > 0)
  398. new->height = (size - sizeof(*new) + sizeof(new->data)) / width;
  399. new->owner = NULL; // should be set properly after return
  400. if (d_roverwrapped)
  401. {
  402. if (wrapped_this_time || (sc_rover >= d_initial_rover))
  403. r_cache_thrash = true;
  404. }
  405. else if (wrapped_this_time)
  406. {
  407. d_roverwrapped = true;
  408. }
  409. return new;
  410. }
  411. /*
  412. =================
  413. D_SCDump
  414. =================
  415. */
  416. void D_SCDump (void)
  417. {
  418. surfcache_t *test;
  419. for (test = sc_base ; test ; test = test->next)
  420. {
  421. if (test == sc_rover)
  422. ri.Con_Printf (PRINT_ALL,"ROVER:\n");
  423. ri.Con_Printf (PRINT_ALL,"%p : %i bytes %i width\n",test, test->size, test->width);
  424. }
  425. }
  426. //=============================================================================
  427. // if the num is not a power of 2, assume it will not repeat
  428. int MaskForNum (int num)
  429. {
  430. if (num==128)
  431. return 127;
  432. if (num==64)
  433. return 63;
  434. if (num==32)
  435. return 31;
  436. if (num==16)
  437. return 15;
  438. return 255;
  439. }
  440. int D_log2 (int num)
  441. {
  442. int c;
  443. c = 0;
  444. while (num>>=1)
  445. c++;
  446. return c;
  447. }
  448. //=============================================================================
  449. /*
  450. ================
  451. D_CacheSurface
  452. ================
  453. */
  454. surfcache_t *D_CacheSurface (msurface_t *surface, int miplevel)
  455. {
  456. surfcache_t *cache;
  457. //
  458. // if the surface is animating or flashing, flush the cache
  459. //
  460. r_drawsurf.image = R_TextureAnimation (surface->texinfo);
  461. r_drawsurf.lightadj[0] = r_newrefdef.lightstyles[surface->styles[0]].white*128;
  462. r_drawsurf.lightadj[1] = r_newrefdef.lightstyles[surface->styles[1]].white*128;
  463. r_drawsurf.lightadj[2] = r_newrefdef.lightstyles[surface->styles[2]].white*128;
  464. r_drawsurf.lightadj[3] = r_newrefdef.lightstyles[surface->styles[3]].white*128;
  465. //
  466. // see if the cache holds apropriate data
  467. //
  468. cache = surface->cachespots[miplevel];
  469. if (cache && !cache->dlight && surface->dlightframe != r_framecount
  470. && cache->image == r_drawsurf.image
  471. && cache->lightadj[0] == r_drawsurf.lightadj[0]
  472. && cache->lightadj[1] == r_drawsurf.lightadj[1]
  473. && cache->lightadj[2] == r_drawsurf.lightadj[2]
  474. && cache->lightadj[3] == r_drawsurf.lightadj[3] )
  475. return cache;
  476. //
  477. // determine shape of surface
  478. //
  479. surfscale = 1.0 / (1<<miplevel);
  480. r_drawsurf.surfmip = miplevel;
  481. r_drawsurf.surfwidth = surface->extents[0] >> miplevel;
  482. r_drawsurf.rowbytes = r_drawsurf.surfwidth;
  483. r_drawsurf.surfheight = surface->extents[1] >> miplevel;
  484. //
  485. // allocate memory if needed
  486. //
  487. if (!cache) // if a texture just animated, don't reallocate it
  488. {
  489. cache = D_SCAlloc (r_drawsurf.surfwidth,
  490. r_drawsurf.surfwidth * r_drawsurf.surfheight);
  491. surface->cachespots[miplevel] = cache;
  492. cache->owner = &surface->cachespots[miplevel];
  493. cache->mipscale = surfscale;
  494. }
  495. if (surface->dlightframe == r_framecount)
  496. cache->dlight = 1;
  497. else
  498. cache->dlight = 0;
  499. r_drawsurf.surfdat = (pixel_t *)cache->data;
  500. cache->image = r_drawsurf.image;
  501. cache->lightadj[0] = r_drawsurf.lightadj[0];
  502. cache->lightadj[1] = r_drawsurf.lightadj[1];
  503. cache->lightadj[2] = r_drawsurf.lightadj[2];
  504. cache->lightadj[3] = r_drawsurf.lightadj[3];
  505. //
  506. // draw and light the surface texture
  507. //
  508. r_drawsurf.surf = surface;
  509. c_surf++;
  510. // calculate the lightings
  511. R_BuildLightMap ();
  512. // rasterize the surface into the cache
  513. R_DrawSurface ();
  514. return cache;
  515. }