R_SEGS.C 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652
  1. //**************************************************************************
  2. //**
  3. //** r_segs.c : Heretic 2 : Raven Software, Corp.
  4. //**
  5. //** $RCSfile: r_segs.c,v $
  6. //** $Revision: 1.4 $
  7. //** $Date: 95/08/28 17:02:44 $
  8. //** $Author: cjr $
  9. //**
  10. //** This version has the tall-sector-crossing-precision-bug fixed.
  11. //**
  12. //**************************************************************************
  13. #include "h2def.h"
  14. #include "r_local.h"
  15. // OPTIMIZE: closed two sided lines as single sided
  16. boolean segtextured; // true if any of the segs textures might be vis
  17. boolean markfloor; // false if the back side is the same plane
  18. boolean markceiling;
  19. boolean maskedtexture;
  20. int toptexture, bottomtexture, midtexture;
  21. angle_t rw_normalangle;
  22. int rw_angle1; // angle to line origin
  23. //
  24. // wall
  25. //
  26. int rw_x;
  27. int rw_stopx;
  28. angle_t rw_centerangle;
  29. fixed_t rw_offset;
  30. fixed_t rw_distance;
  31. fixed_t rw_scale;
  32. fixed_t rw_scalestep;
  33. fixed_t rw_midtexturemid;
  34. fixed_t rw_toptexturemid;
  35. fixed_t rw_bottomtexturemid;
  36. int worldtop, worldbottom, worldhigh, worldlow;
  37. fixed_t pixhigh, pixlow;
  38. fixed_t pixhighstep, pixlowstep;
  39. fixed_t topfrac, topstep;
  40. fixed_t bottomfrac, bottomstep;
  41. lighttable_t **walllights;
  42. short *maskedtexturecol;
  43. /*
  44. ================
  45. =
  46. = R_RenderMaskedSegRange
  47. =
  48. ================
  49. */
  50. void R_RenderMaskedSegRange (drawseg_t *ds, int x1, int x2)
  51. {
  52. unsigned index;
  53. column_t *col;
  54. int lightnum;
  55. int texnum;
  56. //
  57. // calculate light table
  58. // use different light tables for horizontal / vertical / diagonal
  59. // OPTIMIZE: get rid of LIGHTSEGSHIFT globally
  60. curline = ds->curline;
  61. frontsector = curline->frontsector;
  62. backsector = curline->backsector;
  63. texnum = texturetranslation[curline->sidedef->midtexture];
  64. lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT)+extralight;
  65. //if (curline->v1->y == curline->v2->y)
  66. // lightnum--;
  67. //else if (curline->v1->x == curline->v2->x)
  68. // lightnum++;
  69. //if (lightnum < 0)
  70. // walllights = scalelight[0];
  71. if (lightnum >= LIGHTLEVELS)
  72. walllights = scalelight[LIGHTLEVELS-1];
  73. else
  74. walllights = scalelight[lightnum];
  75. maskedtexturecol = ds->maskedtexturecol;
  76. rw_scalestep = ds->scalestep;
  77. spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep;
  78. mfloorclip = ds->sprbottomclip;
  79. mceilingclip = ds->sprtopclip;
  80. //
  81. // find positioning
  82. //
  83. if (curline->linedef->flags & ML_DONTPEGBOTTOM)
  84. {
  85. dc_texturemid = frontsector->floorheight > backsector->floorheight
  86. ? frontsector->floorheight : backsector->floorheight;
  87. dc_texturemid = dc_texturemid + textureheight[texnum] - viewz;
  88. }
  89. else
  90. {
  91. dc_texturemid =frontsector->ceilingheight<backsector->ceilingheight
  92. ? frontsector->ceilingheight : backsector->ceilingheight;
  93. dc_texturemid = dc_texturemid - viewz;
  94. }
  95. dc_texturemid += curline->sidedef->rowoffset;
  96. if (fixedcolormap)
  97. dc_colormap = fixedcolormap;
  98. //
  99. // draw the columns
  100. //
  101. for (dc_x = x1 ; dc_x <= x2 ; dc_x++)
  102. {
  103. // calculate lighting
  104. if (maskedtexturecol[dc_x] != MAXSHORT)
  105. {
  106. if (!fixedcolormap)
  107. {
  108. index = spryscale>>LIGHTSCALESHIFT;
  109. if (index >= MAXLIGHTSCALE )
  110. index = MAXLIGHTSCALE-1;
  111. dc_colormap = walllights[index];
  112. }
  113. sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale);
  114. dc_iscale = 0xffffffffu / (unsigned)spryscale;
  115. //
  116. // draw the texture
  117. //
  118. col = (column_t *)(
  119. (byte *)R_GetColumn(texnum,maskedtexturecol[dc_x]) -3);
  120. R_DrawMaskedColumn (col, -1);
  121. maskedtexturecol[dc_x] = MAXSHORT;
  122. }
  123. spryscale += rw_scalestep;
  124. }
  125. }
  126. /*
  127. ================
  128. =
  129. = R_RenderSegLoop
  130. =
  131. = Draws zero, one, or two textures (and possibly a masked texture) for walls
  132. = Can draw or mark the starting pixel of floor and ceiling textures
  133. =
  134. = CALLED: CORE LOOPING ROUTINE
  135. ================
  136. */
  137. #define HEIGHTBITS 12
  138. #define HEIGHTUNIT (1<<HEIGHTBITS)
  139. void R_RenderSegLoop (void)
  140. {
  141. angle_t angle;
  142. unsigned index;
  143. int yl, yh, mid;
  144. fixed_t texturecolumn;
  145. int top, bottom;
  146. // texturecolumn = 0; // shut up compiler warning
  147. for ( ; rw_x < rw_stopx ; rw_x++)
  148. {
  149. //
  150. // mark floor / ceiling areas
  151. //
  152. yl = (topfrac+HEIGHTUNIT-1)>>HEIGHTBITS;
  153. if (yl < ceilingclip[rw_x]+1)
  154. yl = ceilingclip[rw_x]+1; // no space above wall
  155. if (markceiling)
  156. {
  157. top = ceilingclip[rw_x]+1;
  158. bottom = yl-1;
  159. if (bottom >= floorclip[rw_x])
  160. bottom = floorclip[rw_x]-1;
  161. if (top <= bottom)
  162. {
  163. ceilingplane->top[rw_x] = top;
  164. ceilingplane->bottom[rw_x] = bottom;
  165. }
  166. }
  167. yh = bottomfrac>>HEIGHTBITS;
  168. if (yh >= floorclip[rw_x])
  169. yh = floorclip[rw_x]-1;
  170. if (markfloor)
  171. {
  172. top = yh+1;
  173. bottom = floorclip[rw_x]-1;
  174. if (top <= ceilingclip[rw_x])
  175. top = ceilingclip[rw_x]+1;
  176. if (top <= bottom)
  177. {
  178. floorplane->top[rw_x] = top;
  179. floorplane->bottom[rw_x] = bottom;
  180. }
  181. }
  182. //
  183. // texturecolumn and lighting are independent of wall tiers
  184. //
  185. if (segtextured)
  186. {
  187. // calculate texture offset
  188. angle = (rw_centerangle + xtoviewangle[rw_x])>>ANGLETOFINESHIFT;
  189. texturecolumn = rw_offset-FixedMul(finetangent[angle],rw_distance);
  190. texturecolumn >>= FRACBITS;
  191. // calculate lighting
  192. index = rw_scale>>LIGHTSCALESHIFT;
  193. if (index >= MAXLIGHTSCALE )
  194. index = MAXLIGHTSCALE-1;
  195. dc_colormap = walllights[index];
  196. dc_x = rw_x;
  197. dc_iscale = 0xffffffffu / (unsigned)rw_scale;
  198. }
  199. //
  200. // draw the wall tiers
  201. //
  202. if (midtexture)
  203. { // single sided line
  204. dc_yl = yl;
  205. dc_yh = yh;
  206. dc_texturemid = rw_midtexturemid;
  207. dc_source = R_GetColumn(midtexture,texturecolumn);
  208. colfunc ();
  209. ceilingclip[rw_x] = viewheight;
  210. floorclip[rw_x] = -1;
  211. }
  212. else
  213. { // two sided line
  214. if (toptexture)
  215. { // top wall
  216. mid = pixhigh>>HEIGHTBITS;
  217. pixhigh += pixhighstep;
  218. if (mid >= floorclip[rw_x])
  219. mid = floorclip[rw_x]-1;
  220. if (mid >= yl)
  221. {
  222. dc_yl = yl;
  223. dc_yh = mid;
  224. dc_texturemid = rw_toptexturemid;
  225. dc_source = R_GetColumn(toptexture,texturecolumn);
  226. colfunc ();
  227. ceilingclip[rw_x] = mid;
  228. }
  229. else
  230. ceilingclip[rw_x] = yl-1;
  231. }
  232. else
  233. { // no top wall
  234. if (markceiling)
  235. ceilingclip[rw_x] = yl-1;
  236. }
  237. if (bottomtexture)
  238. { // bottom wall
  239. mid = (pixlow+HEIGHTUNIT-1)>>HEIGHTBITS;
  240. pixlow += pixlowstep;
  241. if (mid <= ceilingclip[rw_x])
  242. mid = ceilingclip[rw_x]+1; // no space above wall
  243. if (mid <= yh)
  244. {
  245. dc_yl = mid;
  246. dc_yh = yh;
  247. dc_texturemid = rw_bottomtexturemid;
  248. dc_source = R_GetColumn(bottomtexture,
  249. texturecolumn);
  250. colfunc ();
  251. floorclip[rw_x] = mid;
  252. }
  253. else
  254. floorclip[rw_x] = yh+1;
  255. }
  256. else
  257. { // no bottom wall
  258. if (markfloor)
  259. floorclip[rw_x] = yh+1;
  260. }
  261. if (maskedtexture)
  262. { // save texturecol for backdrawing of masked mid texture
  263. maskedtexturecol[rw_x] = texturecolumn;
  264. }
  265. }
  266. rw_scale += rw_scalestep;
  267. topfrac += topstep;
  268. bottomfrac += bottomstep;
  269. }
  270. }
  271. /*
  272. =====================
  273. =
  274. = R_StoreWallRange
  275. =
  276. = A wall segment will be drawn between start and stop pixels (inclusive)
  277. =
  278. ======================
  279. */
  280. void R_StoreWallRange (int start, int stop)
  281. {
  282. fixed_t hyp;
  283. fixed_t sineval;
  284. angle_t distangle, offsetangle;
  285. fixed_t vtop;
  286. int lightnum;
  287. if (ds_p == &drawsegs[MAXDRAWSEGS])
  288. return; // don't overflow and crash
  289. #ifdef RANGECHECK
  290. if (start >=viewwidth || start > stop)
  291. I_Error ("Bad R_RenderWallRange: %i to %i", start , stop);
  292. #endif
  293. #ifdef __NeXT__
  294. RD_DrawLine (curline);
  295. #endif
  296. sidedef = curline->sidedef;
  297. linedef = curline->linedef;
  298. // mark the segment as visible for auto map
  299. linedef->flags |= ML_MAPPED;
  300. //
  301. // calculate rw_distance for scale calculation
  302. //
  303. rw_normalangle = curline->angle + ANG90;
  304. offsetangle = abs(rw_normalangle-rw_angle1);
  305. if (offsetangle > ANG90)
  306. offsetangle = ANG90;
  307. distangle = ANG90 - offsetangle;
  308. hyp = R_PointToDist (curline->v1->x, curline->v1->y);
  309. sineval = finesine[distangle>>ANGLETOFINESHIFT];
  310. rw_distance = FixedMul (hyp, sineval);
  311. ds_p->x1 = rw_x = start;
  312. ds_p->x2 = stop;
  313. ds_p->curline = curline;
  314. rw_stopx = stop+1;
  315. //
  316. // calculate scale at both ends and step
  317. //
  318. ds_p->scale1 = rw_scale =
  319. R_ScaleFromGlobalAngle (viewangle + xtoviewangle[start]);
  320. if (stop > start )
  321. {
  322. ds_p->scale2 = R_ScaleFromGlobalAngle (viewangle + xtoviewangle[stop]);
  323. ds_p->scalestep = rw_scalestep =
  324. (ds_p->scale2 - rw_scale) / (stop-start);
  325. }
  326. else
  327. {
  328. //
  329. // try to fix the stretched line bug
  330. //
  331. #if 0
  332. if (rw_distance < FRACUNIT/2)
  333. {
  334. fixed_t trx,try;
  335. fixed_t gxt,gyt;
  336. trx = curline->v1->x - viewx;
  337. try = curline->v1->y - viewy;
  338. gxt = FixedMul(trx,viewcos);
  339. gyt = -FixedMul(try,viewsin);
  340. ds_p->scale1 = FixedDiv(projection, gxt-gyt);
  341. }
  342. #endif
  343. ds_p->scale2 = ds_p->scale1;
  344. }
  345. //
  346. // calculate texture boundaries and decide if floor / ceiling marks
  347. // are needed
  348. //
  349. worldtop = frontsector->ceilingheight - viewz;
  350. worldbottom = frontsector->floorheight - viewz;
  351. midtexture = toptexture = bottomtexture = maskedtexture = 0;
  352. ds_p->maskedtexturecol = NULL;
  353. if (!backsector)
  354. {
  355. //
  356. // single sided line
  357. //
  358. midtexture = texturetranslation[sidedef->midtexture];
  359. // a single sided line is terminal, so it must mark ends
  360. markfloor = markceiling = true;
  361. if (linedef->flags & ML_DONTPEGBOTTOM)
  362. {
  363. vtop = frontsector->floorheight +
  364. textureheight[sidedef->midtexture];
  365. rw_midtexturemid = vtop - viewz; // bottom of texture at bottom
  366. }
  367. else
  368. rw_midtexturemid = worldtop; // top of texture at top
  369. rw_midtexturemid += sidedef->rowoffset;
  370. ds_p->silhouette = SIL_BOTH;
  371. ds_p->sprtopclip = screenheightarray;
  372. ds_p->sprbottomclip = negonearray;
  373. ds_p->bsilheight = MAXINT;
  374. ds_p->tsilheight = MININT;
  375. }
  376. else
  377. {
  378. //
  379. // two sided line
  380. //
  381. ds_p->sprtopclip = ds_p->sprbottomclip = NULL;
  382. ds_p->silhouette = 0;
  383. if (frontsector->floorheight > backsector->floorheight)
  384. {
  385. ds_p->silhouette = SIL_BOTTOM;
  386. ds_p->bsilheight = frontsector->floorheight;
  387. }
  388. else if (backsector->floorheight > viewz)
  389. {
  390. ds_p->silhouette = SIL_BOTTOM;
  391. ds_p->bsilheight = MAXINT;
  392. // ds_p->sprbottomclip = negonearray;
  393. }
  394. if (frontsector->ceilingheight < backsector->ceilingheight)
  395. {
  396. ds_p->silhouette |= SIL_TOP;
  397. ds_p->tsilheight = frontsector->ceilingheight;
  398. }
  399. else if (backsector->ceilingheight < viewz)
  400. {
  401. ds_p->silhouette |= SIL_TOP;
  402. ds_p->tsilheight = MININT;
  403. // ds_p->sprtopclip = screenheightarray;
  404. }
  405. if (backsector->ceilingheight <= frontsector->floorheight)
  406. {
  407. ds_p->sprbottomclip = negonearray;
  408. ds_p->bsilheight = MAXINT;
  409. ds_p->silhouette |= SIL_BOTTOM;
  410. }
  411. if (backsector->floorheight >= frontsector->ceilingheight)
  412. {
  413. ds_p->sprtopclip = screenheightarray;
  414. ds_p->tsilheight = MININT;
  415. ds_p->silhouette |= SIL_TOP;
  416. }
  417. worldhigh = backsector->ceilingheight - viewz;
  418. worldlow = backsector->floorheight - viewz;
  419. // hack to allow height changes in outdoor areas
  420. if (frontsector->ceilingpic == skyflatnum
  421. && backsector->ceilingpic == skyflatnum)
  422. worldtop = worldhigh;
  423. if (worldlow != worldbottom
  424. || backsector->floorpic != frontsector->floorpic
  425. || backsector->lightlevel != frontsector->lightlevel
  426. || backsector->special != frontsector->special)
  427. markfloor = true;
  428. else
  429. markfloor = false; // same plane on both sides
  430. if (worldhigh != worldtop
  431. || backsector->ceilingpic != frontsector->ceilingpic
  432. || backsector->lightlevel != frontsector->lightlevel)
  433. markceiling = true;
  434. else
  435. markceiling = false; // same plane on both sides
  436. if (backsector->ceilingheight <= frontsector->floorheight
  437. || backsector->floorheight >= frontsector->ceilingheight)
  438. markceiling = markfloor = true; // closed door
  439. if (worldhigh < worldtop)
  440. { // top texture
  441. toptexture = texturetranslation[sidedef->toptexture];
  442. if (linedef->flags & ML_DONTPEGTOP)
  443. rw_toptexturemid = worldtop; // top of texture at top
  444. else
  445. {
  446. vtop = backsector->ceilingheight +
  447. textureheight[sidedef->toptexture];
  448. rw_toptexturemid = vtop - viewz; // bottom of texture
  449. }
  450. }
  451. if (worldlow > worldbottom)
  452. { // bottom texture
  453. bottomtexture = texturetranslation[sidedef->bottomtexture];
  454. if (linedef->flags & ML_DONTPEGBOTTOM )
  455. { // bottom of texture at bottom
  456. rw_bottomtexturemid = worldtop;// top of texture at top
  457. }
  458. else // top of texture at top
  459. rw_bottomtexturemid = worldlow;
  460. }
  461. rw_toptexturemid += sidedef->rowoffset;
  462. rw_bottomtexturemid += sidedef->rowoffset;
  463. //
  464. // allocate space for masked texture tables
  465. //
  466. if (sidedef->midtexture)
  467. { // masked midtexture
  468. maskedtexture = true;
  469. ds_p->maskedtexturecol = maskedtexturecol = lastopening - rw_x;
  470. lastopening += rw_stopx - rw_x;
  471. }
  472. }
  473. //
  474. // calculate rw_offset (only needed for textured lines)
  475. //
  476. segtextured = midtexture | toptexture | bottomtexture | maskedtexture;
  477. if (segtextured)
  478. {
  479. offsetangle = rw_normalangle-rw_angle1;
  480. if (offsetangle > ANG180)
  481. offsetangle = -offsetangle;
  482. if (offsetangle > ANG90)
  483. offsetangle = ANG90;
  484. sineval = finesine[offsetangle >>ANGLETOFINESHIFT];
  485. rw_offset = FixedMul (hyp, sineval);
  486. if (rw_normalangle-rw_angle1 < ANG180)
  487. rw_offset = -rw_offset;
  488. rw_offset += sidedef->textureoffset + curline->offset;
  489. rw_centerangle = ANG90 + viewangle - rw_normalangle;
  490. //
  491. // calculate light table
  492. // use different light tables for horizontal / vertical / diagonal
  493. // OPTIMIZE: get rid of LIGHTSEGSHIFT globally
  494. if (!fixedcolormap)
  495. {
  496. lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT)+extralight;
  497. //if (curline->v1->y == curline->v2->y)
  498. // lightnum--;
  499. //else if (curline->v1->x == curline->v2->x)
  500. // lightnum++;
  501. //if (lightnum < 0)
  502. // walllights = scalelight[0];
  503. if (lightnum >= LIGHTLEVELS)
  504. walllights = scalelight[LIGHTLEVELS-1];
  505. else
  506. walllights = scalelight[lightnum];
  507. }
  508. }
  509. //
  510. // if a floor / ceiling plane is on the wrong side of the view plane
  511. // it is definately invisible and doesn't need to be marked
  512. //
  513. if (frontsector->floorheight >= viewz)
  514. markfloor = false; // above view plane
  515. if (frontsector->ceilingheight <= viewz
  516. && frontsector->ceilingpic != skyflatnum)
  517. markceiling = false; // below view plane
  518. //
  519. // calculate incremental stepping values for texture edges
  520. //
  521. worldtop >>= 4;
  522. worldbottom >>= 4;
  523. topstep = -FixedMul (rw_scalestep, worldtop);
  524. topfrac = (centeryfrac>>4) - FixedMul (worldtop, rw_scale);
  525. bottomstep = -FixedMul (rw_scalestep,worldbottom);
  526. bottomfrac = (centeryfrac>>4) - FixedMul (worldbottom, rw_scale);
  527. if (backsector)
  528. {
  529. worldhigh >>= 4;
  530. worldlow >>= 4;
  531. if (worldhigh < worldtop)
  532. {
  533. pixhigh = (centeryfrac>>4) - FixedMul (worldhigh, rw_scale);
  534. pixhighstep = -FixedMul (rw_scalestep,worldhigh);
  535. }
  536. if (worldlow > worldbottom)
  537. {
  538. pixlow = (centeryfrac>>4) - FixedMul (worldlow, rw_scale);
  539. pixlowstep = -FixedMul (rw_scalestep,worldlow);
  540. }
  541. }
  542. //
  543. // render it
  544. //
  545. if (markceiling)
  546. ceilingplane = R_CheckPlane (ceilingplane, rw_x, rw_stopx-1);
  547. if (markfloor)
  548. floorplane = R_CheckPlane (floorplane, rw_x, rw_stopx-1);
  549. R_RenderSegLoop ();
  550. //
  551. // save sprite clipping info
  552. //
  553. if ( ((ds_p->silhouette & SIL_TOP) || maskedtexture) && !ds_p->sprtopclip)
  554. {
  555. memcpy (lastopening, ceilingclip+start, 2*(rw_stopx-start));
  556. ds_p->sprtopclip = lastopening - start;
  557. lastopening += rw_stopx - start;
  558. }
  559. if ( ((ds_p->silhouette & SIL_BOTTOM) || maskedtexture) && !ds_p->sprbottomclip)
  560. {
  561. memcpy (lastopening, floorclip+start, 2*(rw_stopx-start));
  562. ds_p->sprbottomclip = lastopening - start;
  563. lastopening += rw_stopx - start;
  564. }
  565. if (maskedtexture && !(ds_p->silhouette&SIL_TOP))
  566. {
  567. ds_p->silhouette |= SIL_TOP;
  568. ds_p->tsilheight = MININT;
  569. }
  570. if (maskedtexture && !(ds_p->silhouette&SIL_BOTTOM))
  571. {
  572. ds_p->silhouette |= SIL_BOTTOM;
  573. ds_p->bsilheight = MAXINT;
  574. }
  575. ds_p++;
  576. }