r_plane.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. /* Emacs style mode select -*- C++ -*-
  2. *-----------------------------------------------------------------------------
  3. *
  4. *
  5. * PrBoom: a Doom port merged with LxDoom and LSDLDoom
  6. * based on BOOM, a modified and improved DOOM engine
  7. * Copyright (C) 1999 by
  8. * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
  9. * Copyright (C) 1999-2000 by
  10. * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
  11. * Copyright 2005, 2006 by
  12. * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
  13. *
  14. * This program is free software; you can redistribute it and/or
  15. * modify it under the terms of the GNU General Public License
  16. * as published by the Free Software Foundation; either version 2
  17. * of the License, or (at your option) any later version.
  18. *
  19. * This program is distributed in the hope that it will be useful,
  20. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. * GNU General Public License for more details.
  23. *
  24. * You should have received a copy of the GNU General Public License
  25. * along with this program; if not, write to the Free Software
  26. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  27. * 02111-1307, USA.
  28. *
  29. * DESCRIPTION:
  30. * Here is a core component: drawing the floors and ceilings,
  31. * while maintaining a per column clipping list only.
  32. * Moreover, the sky areas have to be determined.
  33. *
  34. * MAXVISPLANES is no longer a limit on the number of visplanes,
  35. * but a limit on the number of hash slots; larger numbers mean
  36. * better performance usually but after a point they are wasted,
  37. * and memory and time overheads creep in.
  38. *
  39. * For more information on visplanes, see:
  40. *
  41. * http://classicgaming.com/doom/editing/
  42. *
  43. * Lee Killough
  44. *
  45. *-----------------------------------------------------------------------------*/
  46. #ifdef HAVE_CONFIG_H
  47. #include "config.h"
  48. #endif
  49. #include "z_zone.h" /* memory allocation wrappers -- killough */
  50. #include "doomstat.h"
  51. #include "w_wad.h"
  52. #include "r_main.h"
  53. #include "r_draw.h"
  54. #include "r_things.h"
  55. #include "r_sky.h"
  56. #include "r_plane.h"
  57. #include "v_video.h"
  58. #include "lprintf.h"
  59. #define MAXVISPLANES 128 /* must be a power of 2 */
  60. static visplane_t *visplanes[MAXVISPLANES]; // killough
  61. static visplane_t *freetail; // killough
  62. static visplane_t **freehead = &freetail; // killough
  63. visplane_t *floorplane, *ceilingplane;
  64. // killough -- hash function for visplanes
  65. // Empirically verified to be fairly uniform:
  66. #define visplane_hash(picnum,lightlevel,height) \
  67. ((unsigned)((picnum)*3+(lightlevel)+(height)*7) & (MAXVISPLANES-1))
  68. size_t maxopenings;
  69. int *openings,*lastopening; // dropoff overflow
  70. // Clip values are the solid pixel bounding the range.
  71. // floorclip starts out SCREENHEIGHT
  72. // ceilingclip starts out -1
  73. int floorclip[MAX_SCREENWIDTH], ceilingclip[MAX_SCREENWIDTH]; // dropoff overflow
  74. // spanstart holds the start of a plane span; initialized to 0 at start
  75. static int spanstart[MAX_SCREENHEIGHT]; // killough 2/8/98
  76. //
  77. // texture mapping
  78. //
  79. static const lighttable_t **planezlight;
  80. static fixed_t planeheight;
  81. // killough 2/8/98: make variables static
  82. static fixed_t basexscale, baseyscale;
  83. static fixed_t cachedheight[MAX_SCREENHEIGHT];
  84. static fixed_t cacheddistance[MAX_SCREENHEIGHT];
  85. static fixed_t cachedxstep[MAX_SCREENHEIGHT];
  86. static fixed_t cachedystep[MAX_SCREENHEIGHT];
  87. static fixed_t xoffs,yoffs; // killough 2/28/98: flat offsets
  88. fixed_t yslope[MAX_SCREENHEIGHT], distscale[MAX_SCREENWIDTH];
  89. //
  90. // R_InitPlanes
  91. // Only at game startup.
  92. //
  93. void R_InitPlanes (void)
  94. {
  95. }
  96. //
  97. // R_MapPlane
  98. //
  99. // Uses global vars:
  100. // planeheight
  101. // dsvars.source
  102. // basexscale
  103. // baseyscale
  104. // viewx
  105. // viewy
  106. // xoffs
  107. // yoffs
  108. //
  109. // BASIC PRIMITIVE
  110. //
  111. static void R_MapPlane(int y, int x1, int x2, draw_span_vars_t *dsvars)
  112. {
  113. angle_t angle;
  114. fixed_t distance, length;
  115. unsigned index;
  116. #ifdef RANGECHECK
  117. if (x2 < x1 || x1<0 || x2>=viewwidth || (unsigned)y>(unsigned)viewheight)
  118. I_Error ("R_MapPlane: %i, %i at %i",x1,x2,y);
  119. #endif
  120. if (planeheight != cachedheight[y])
  121. {
  122. cachedheight[y] = planeheight;
  123. distance = cacheddistance[y] = FixedMul (planeheight, yslope[y]);
  124. dsvars->xstep = cachedxstep[y] = FixedMul (distance,basexscale);
  125. dsvars->ystep = cachedystep[y] = FixedMul (distance,baseyscale);
  126. }
  127. else
  128. {
  129. distance = cacheddistance[y];
  130. dsvars->xstep = cachedxstep[y];
  131. dsvars->ystep = cachedystep[y];
  132. }
  133. length = FixedMul (distance,distscale[x1]);
  134. angle = (viewangle + xtoviewangle[x1])>>ANGLETOFINESHIFT;
  135. // killough 2/28/98: Add offsets
  136. dsvars->xfrac = viewx + FixedMul(finecosine[angle], length) + xoffs;
  137. dsvars->yfrac = -viewy - FixedMul(finesine[angle], length) + yoffs;
  138. if (drawvars.filterfloor == RDRAW_FILTER_LINEAR) {
  139. dsvars->xfrac -= (FRACUNIT>>1);
  140. dsvars->yfrac -= (FRACUNIT>>1);
  141. }
  142. if (!(dsvars->colormap = fixedcolormap))
  143. {
  144. dsvars->z = distance;
  145. index = distance >> LIGHTZSHIFT;
  146. if (index >= MAXLIGHTZ )
  147. index = MAXLIGHTZ-1;
  148. dsvars->colormap = planezlight[index];
  149. dsvars->nextcolormap = planezlight[index+1 >= MAXLIGHTZ ? MAXLIGHTZ-1 : index+1];
  150. }
  151. else
  152. {
  153. dsvars->z = 0;
  154. }
  155. dsvars->y = y;
  156. dsvars->x1 = x1;
  157. dsvars->x2 = x2;
  158. if (V_GetMode() != VID_MODEGL)
  159. R_DrawSpan(dsvars);
  160. }
  161. //
  162. // R_ClearPlanes
  163. // At begining of frame.
  164. //
  165. void R_ClearPlanes(void)
  166. {
  167. int i;
  168. // opening / clipping determination
  169. for (i=0 ; i<viewwidth ; i++)
  170. floorclip[i] = viewheight, ceilingclip[i] = -1;
  171. for (i=0;i<MAXVISPLANES;i++) // new code -- killough
  172. for (*freehead = visplanes[i], visplanes[i] = NULL; *freehead; )
  173. freehead = &(*freehead)->next;
  174. lastopening = openings;
  175. // texture calculation
  176. memset (cachedheight, 0, sizeof(cachedheight));
  177. // scale will be unit scale at SCREENWIDTH/2 distance
  178. basexscale = FixedDiv (viewsin,projection);
  179. baseyscale = FixedDiv (viewcos,projection);
  180. }
  181. // New function, by Lee Killough
  182. static visplane_t *new_visplane(unsigned hash)
  183. {
  184. visplane_t *check = freetail;
  185. if (!check)
  186. check = calloc(1, sizeof *check);
  187. else
  188. if (!(freetail = freetail->next))
  189. freehead = &freetail;
  190. check->next = visplanes[hash];
  191. visplanes[hash] = check;
  192. return check;
  193. }
  194. /*
  195. * R_DupPlane
  196. *
  197. * cph 2003/04/18 - create duplicate of existing visplane and set initial range
  198. */
  199. visplane_t *R_DupPlane(const visplane_t *pl, int start, int stop)
  200. {
  201. unsigned hash = visplane_hash(pl->picnum, pl->lightlevel, pl->height);
  202. visplane_t *new_pl = new_visplane(hash);
  203. new_pl->height = pl->height;
  204. new_pl->picnum = pl->picnum;
  205. new_pl->lightlevel = pl->lightlevel;
  206. new_pl->xoffs = pl->xoffs; // killough 2/28/98
  207. new_pl->yoffs = pl->yoffs;
  208. new_pl->minx = start;
  209. new_pl->maxx = stop;
  210. memset(new_pl->top, 0xff, sizeof new_pl->top);
  211. return new_pl;
  212. }
  213. //
  214. // R_FindPlane
  215. //
  216. // killough 2/28/98: Add offsets
  217. visplane_t *R_FindPlane(fixed_t height, int picnum, int lightlevel,
  218. fixed_t xoffset, fixed_t yoffset)
  219. {
  220. visplane_t *check;
  221. unsigned hash; // killough
  222. if (picnum == skyflatnum || picnum & PL_SKYFLAT)
  223. height = lightlevel = 0; // killough 7/19/98: most skies map together
  224. // New visplane algorithm uses hash table -- killough
  225. hash = visplane_hash(picnum,lightlevel,height);
  226. for (check=visplanes[hash]; check; check=check->next) // killough
  227. if (height == check->height &&
  228. picnum == check->picnum &&
  229. lightlevel == check->lightlevel &&
  230. xoffset == check->xoffs && // killough 2/28/98: Add offset checks
  231. yoffset == check->yoffs)
  232. return check;
  233. check = new_visplane(hash); // killough
  234. check->height = height;
  235. check->picnum = picnum;
  236. check->lightlevel = lightlevel;
  237. check->minx = viewwidth; // Was SCREENWIDTH -- killough 11/98
  238. check->maxx = -1;
  239. check->xoffs = xoffset; // killough 2/28/98: Save offsets
  240. check->yoffs = yoffset;
  241. memset (check->top, 0xff, sizeof check->top);
  242. return check;
  243. }
  244. //
  245. // R_CheckPlane
  246. //
  247. visplane_t *R_CheckPlane(visplane_t *pl, int start, int stop)
  248. {
  249. int intrl, intrh, unionl, unionh, x;
  250. if (start < pl->minx)
  251. intrl = pl->minx, unionl = start;
  252. else
  253. unionl = pl->minx, intrl = start;
  254. if (stop > pl->maxx)
  255. intrh = pl->maxx, unionh = stop;
  256. else
  257. unionh = pl->maxx, intrh = stop;
  258. for (x=intrl ; x <= intrh && pl->top[x] == 0xffffffffu; x++) // dropoff overflow
  259. ;
  260. if (x > intrh) { /* Can use existing plane; extend range */
  261. pl->minx = unionl; pl->maxx = unionh;
  262. return pl;
  263. } else /* Cannot use existing plane; create a new one */
  264. return R_DupPlane(pl,start,stop);
  265. }
  266. //
  267. // R_MakeSpans
  268. //
  269. static void R_MakeSpans(int x, unsigned int t1, unsigned int b1,
  270. unsigned int t2, unsigned int b2,
  271. draw_span_vars_t *dsvars)
  272. {
  273. for (; t1 < t2 && t1 <= b1; t1++)
  274. R_MapPlane(t1, spanstart[t1], x-1, dsvars);
  275. for (; b1 > b2 && b1 >= t1; b1--)
  276. R_MapPlane(b1, spanstart[b1] ,x-1, dsvars);
  277. while (t2 < t1 && t2 <= b2)
  278. spanstart[t2++] = x;
  279. while (b2 > b1 && b2 >= t2)
  280. spanstart[b2--] = x;
  281. }
  282. // New function, by Lee Killough
  283. static void R_DoDrawPlane(visplane_t *pl)
  284. {
  285. register int x;
  286. draw_column_vars_t dcvars;
  287. R_DrawColumn_f colfunc = R_GetDrawColumnFunc(RDC_PIPELINE_STANDARD, drawvars.filterwall, drawvars.filterz);
  288. R_SetDefaultDrawColumnVars(&dcvars);
  289. if (pl->minx <= pl->maxx) {
  290. if (pl->picnum == skyflatnum || pl->picnum & PL_SKYFLAT) { // sky flat
  291. int texture;
  292. const rpatch_t *tex_patch;
  293. angle_t an, flip;
  294. // killough 10/98: allow skies to come from sidedefs.
  295. // Allows scrolling and/or animated skies, as well as
  296. // arbitrary multiple skies per level without having
  297. // to use info lumps.
  298. an = viewangle;
  299. if (pl->picnum & PL_SKYFLAT)
  300. {
  301. // Sky Linedef
  302. const line_t *l = &lines[pl->picnum & ~PL_SKYFLAT];
  303. // Sky transferred from first sidedef
  304. const side_t *s = *l->sidenum + sides;
  305. // Texture comes from upper texture of reference sidedef
  306. texture = texturetranslation[s->toptexture];
  307. // Horizontal offset is turned into an angle offset,
  308. // to allow sky rotation as well as careful positioning.
  309. // However, the offset is scaled very small, so that it
  310. // allows a long-period of sky rotation.
  311. an += s->textureoffset;
  312. // Vertical offset allows careful sky positioning.
  313. dcvars.texturemid = s->rowoffset - 28*FRACUNIT;
  314. // We sometimes flip the picture horizontally.
  315. //
  316. // Doom always flipped the picture, so we make it optional,
  317. // to make it easier to use the new feature, while to still
  318. // allow old sky textures to be used.
  319. flip = l->special==272 ? 0u : ~0u;
  320. }
  321. else
  322. { // Normal Doom sky, only one allowed per level
  323. dcvars.texturemid = skytexturemid; // Default y-offset
  324. texture = skytexture; // Default texture
  325. flip = 0; // Doom flips it
  326. }
  327. /* Sky is always drawn full bright, i.e. colormaps[0] is used.
  328. * Because of this hack, sky is not affected by INVUL inverse mapping.
  329. * Until Boom fixed this. Compat option added in MBF. */
  330. if (comp[comp_skymap] || !(dcvars.colormap = fixedcolormap))
  331. dcvars.colormap = fullcolormap; // killough 3/20/98
  332. dcvars.nextcolormap = dcvars.colormap; // for filtering -- POPE
  333. //dcvars.texturemid = skytexturemid;
  334. dcvars.texheight = textureheight[skytexture]>>FRACBITS; // killough
  335. // proff 09/21/98: Changed for high-res
  336. dcvars.iscale = FRACUNIT*200/viewheight;
  337. tex_patch = R_CacheTextureCompositePatchNum(texture);
  338. // killough 10/98: Use sky scrolling offset, and possibly flip picture
  339. for (x = pl->minx; (dcvars.x = x) <= pl->maxx; x++)
  340. if ((dcvars.yl = pl->top[x]) != -1 && dcvars.yl <= (dcvars.yh = pl->bottom[x])) // dropoff overflow
  341. {
  342. dcvars.source = R_GetTextureColumn(tex_patch, ((an + xtoviewangle[x])^flip) >> ANGLETOSKYSHIFT);
  343. dcvars.prevsource = R_GetTextureColumn(tex_patch, ((an + xtoviewangle[x-1])^flip) >> ANGLETOSKYSHIFT);
  344. dcvars.nextsource = R_GetTextureColumn(tex_patch, ((an + xtoviewangle[x+1])^flip) >> ANGLETOSKYSHIFT);
  345. colfunc(&dcvars);
  346. }
  347. R_UnlockTextureCompositePatchNum(texture);
  348. } else { // regular flat
  349. int stop, light;
  350. draw_span_vars_t dsvars;
  351. dsvars.source = W_CacheLumpNum(firstflat + flattranslation[pl->picnum]);
  352. xoffs = pl->xoffs; // killough 2/28/98: Add offsets
  353. yoffs = pl->yoffs;
  354. planeheight = D_abs(pl->height-viewz);
  355. light = (pl->lightlevel >> LIGHTSEGSHIFT) + extralight;
  356. if (light >= LIGHTLEVELS)
  357. light = LIGHTLEVELS-1;
  358. if (light < 0)
  359. light = 0;
  360. stop = pl->maxx + 1;
  361. planezlight = zlight[light];
  362. pl->top[pl->minx-1] = pl->top[stop] = 0xffffffffu; // dropoff overflow
  363. for (x = pl->minx ; x <= stop ; x++)
  364. R_MakeSpans(x,pl->top[x-1],pl->bottom[x-1],
  365. pl->top[x],pl->bottom[x], &dsvars);
  366. W_UnlockLumpNum(firstflat + flattranslation[pl->picnum]);
  367. }
  368. }
  369. }
  370. //
  371. // RDrawPlanes
  372. // At the end of each frame.
  373. //
  374. void R_DrawPlanes (void)
  375. {
  376. visplane_t *pl;
  377. int i;
  378. for (i=0;i<MAXVISPLANES;i++)
  379. for (pl=visplanes[i]; pl; pl=pl->next, rendered_visplanes++)
  380. R_DoDrawPlane(pl);
  381. }