PageRenderTime 29ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 0ms

/legacy/trunk/video/hardware/hw_trick.cpp

#
C++ | 997 lines | 686 code | 154 blank | 157 comment | 175 complexity | b996bb7bad73d3566db680ea5a62b17d MD5 | raw file
Possible License(s): GPL-2.0
  1. // Emacs style mode select -*- C++ -*-
  2. //-----------------------------------------------------------------------------
  3. //
  4. // $Id: hw_trick.cpp 452 2007-05-17 17:11:02Z smite-meister $
  5. //
  6. // Copyright (C) 1998-2004 by DooM Legacy Team.
  7. //
  8. // This program is free software; you can redistribute it and/or
  9. // modify it under the terms of the GNU General Public License
  10. // as published by the Free Software Foundation; either version 2
  11. // of the License, or (at your option) any later version.
  12. //
  13. // This program is distributed in the hope that it will be useful,
  14. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. // GNU General Public License for more details.
  17. //
  18. //
  19. //-----------------------------------------------------------------------------
  20. /// \file
  21. /// \brief Trick routines to make some SW tricks look OK with HW rendering
  22. ///
  23. /// This includes:
  24. /// - deepwatereffect (e.g. tnt/map02)
  25. /// - invisible staircase (e.g. eternal/map02)
  26. /// - floating ceilings (e.g. eternal/map03)
  27. ///
  28. /// It is not guaranteed that it looks identical to the SW mode,
  29. /// but it looks in most of the cases far better than having
  30. /// holes in the architecture, HOM, etc.
  31. ///
  32. /// It fixes as well missing textures, which are replaced by either
  33. /// a default texture or the midtexture.
  34. ///
  35. /// words of notice:
  36. /// pseudosectors, as mentioned in this file, are sectors where both
  37. /// sidedefs point to the same sector. This expression is also used
  38. /// for sectors which are enclosed by another sector but have no
  39. /// correct sidedefs at all
  40. ///
  41. /// if a vertex is inside a poly is determined by the angles between
  42. /// this vertex and all angles on the linedefs (imagine walking along
  43. /// a circle always facing a certain point inside/outside the circle;
  44. /// if inside, angle have taken all values [0..\pi), otherwise the
  45. /// range was < \pi/2
  46. #include <math.h>
  47. #include "doomdef.h"
  48. #include "command.h"
  49. #include "g_game.h"
  50. #include "r_render.h"
  51. #include "r_data.h"
  52. #include "i_system.h"
  53. #ifndef M_PI
  54. # define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h
  55. #endif
  56. /// For creating a chain with the lines around a sector
  57. struct linechain_t
  58. {
  59. line_t *line;
  60. linechain_t *next;
  61. };
  62. //
  63. // add a line to a sectors list of lines
  64. //
  65. static void addLineToChain(sector_t *sector, line_t *line)
  66. {
  67. linechain_t *thisElem, *nextElem;
  68. if(NULL == sector)
  69. return;
  70. thisElem = NULL;
  71. nextElem = sector->sectorLines;
  72. while(NULL != nextElem) // walk through chain
  73. {
  74. thisElem = nextElem;
  75. nextElem = thisElem->next;
  76. }
  77. // add a new element into the chain
  78. if(thisElem)
  79. {
  80. thisElem->next = (linechain_t *)malloc(sizeof(linechain_t));
  81. if(thisElem->next)
  82. {
  83. thisElem->next->line = line;
  84. thisElem->next->next = NULL;
  85. }
  86. else
  87. {
  88. I_Error("Out of memory in addLineToChain(.)\n");
  89. }
  90. }
  91. else // first element in chain
  92. {
  93. sector->sectorLines = (linechain_t *)malloc(sizeof(linechain_t));
  94. if(sector->sectorLines)
  95. {
  96. sector->sectorLines->line = line;
  97. sector->sectorLines->next = NULL;
  98. }
  99. else
  100. {
  101. I_Error("Out of memory in addLineToChain(.)\n");
  102. }
  103. }
  104. }
  105. //
  106. // We don´t want a memory hole, do we? ;-)
  107. //
  108. void Rend::releaseLineChains()
  109. {
  110. linechain_t *thisElem, *nextElem;
  111. sector_t *sector;
  112. int i;
  113. for(i=0; i<numsectors; i++)
  114. {
  115. sector = &sectors[i];
  116. nextElem = sector->sectorLines;
  117. while(NULL != nextElem)
  118. {
  119. thisElem = nextElem;
  120. nextElem = thisElem->next;
  121. free(thisElem);
  122. }
  123. sector->sectorLines = NULL;
  124. }
  125. }
  126. //
  127. // check if a pseudo sector is valid by checking all it´s linedefs
  128. //
  129. static bool isPSectorValid(sector_t *sector)
  130. {
  131. linechain_t *thisElem, *nextElem;
  132. if(!sector->pseudoSector) // check only pseudosectors, others don´t care
  133. {
  134. #ifdef PARANOIA
  135. CONS_Printf("Alert! non-pseudosector fed to isPSectorClosed()\n");
  136. #endif
  137. return false;
  138. }
  139. nextElem = sector->sectorLines;
  140. while(NULL != nextElem)
  141. {
  142. thisElem = nextElem;
  143. nextElem = thisElem->next;
  144. if(thisElem->line->frontsector != thisElem->line->backsector)
  145. return false;
  146. }
  147. return true;
  148. }
  149. //
  150. // angles are always phiMax-phiMin [0...2\pi)
  151. //
  152. static double phiDiff(double phiMin, double phiMax)
  153. {
  154. double result;
  155. result = phiMax-phiMin;
  156. if (result < 0.0)
  157. {
  158. result += 2.0*M_PI;
  159. }
  160. return result;
  161. }
  162. //
  163. // sort phi's so that enclosed angle < \pi
  164. //
  165. static void sortPhi(double phi1, double phi2, double *phiMin, double *phiMax)
  166. {
  167. if(phiDiff(phi1, phi2) < M_PI)
  168. {
  169. *phiMin = phi1;
  170. *phiMax = phi2;
  171. }
  172. else
  173. {
  174. *phiMin = phi2;
  175. *phiMax = phi1;
  176. }
  177. }
  178. //
  179. // return if angle(phi1, phi2) is bigger than \pi
  180. // if so, the vertex lies inside the poly
  181. //
  182. static bool biggerThanPi(double phi1, double phi2)
  183. {
  184. if(phiDiff(phi1, phi2) > M_PI)
  185. return true;
  186. return false;
  187. }
  188. #define DELTAPHI (M_PI/100.0) // some small phi << \pi
  189. //
  190. // calculate bounds for minimum angle
  191. //
  192. void phiBounds(double phi1, double phi2, double *phiMin, double *phiMax)
  193. {
  194. double phi1Tmp, phi2Tmp;
  195. double psi1, psi2, psi3, psi4, psi5, psi6, psi7; // for optimization
  196. sortPhi(phi1, phi2, &phi1Tmp, &phi2Tmp);
  197. phi1 = phi1Tmp;
  198. phi2 = phi2Tmp;
  199. // check start condition
  200. if(*phiMin > M_PI || *phiMax > M_PI)
  201. {
  202. *phiMin = phi1;
  203. *phiMax = phi2;
  204. return;
  205. }
  206. // 6 cases:
  207. // new angles inbetween phiMin, phiMax -> forget it
  208. // new angles enclose phiMin -> set phiMin
  209. // new angles enclose phiMax -> set phiMax
  210. // new angles completely outside phiMin, phiMax -> leave largest area free
  211. // new angles close the range completely!
  212. // new angles enlarges range on both sides
  213. psi1 = phiDiff(*phiMin, phi1);
  214. psi2 = phiDiff(*phiMin, phi2);
  215. psi3 = phiDiff(*phiMax, phi1);
  216. psi4 = phiDiff(*phiMax, phi2);
  217. psi5 = phiDiff(*phiMin, *phiMax);
  218. psi6 = 2.0*M_PI - psi5; // phiDiff(*phiMax, *phiMin);
  219. psi7 = 2.0*M_PI - psi2; // phiDiff(phi2, *phiMin);
  220. // case 1 & 5!
  221. if((psi1 <= psi5) && (psi2 <= psi5))
  222. {
  223. if(psi1 <= psi2) // case 1
  224. {
  225. return;
  226. }
  227. else // case 5
  228. {
  229. // create some artificial interval here not to get into numerical trouble
  230. // in fact we know now the sector is completely enclosed -> base for computational optimization
  231. *phiMax = 0.0;
  232. *phiMin = DELTAPHI;
  233. return;
  234. }
  235. }
  236. // case 2
  237. if((psi1 >= psi5) && (psi2 <= psi5))
  238. {
  239. *phiMin = phi1;
  240. return;
  241. }
  242. // case 3
  243. if((psi3 >= psi6) && (psi4 <= psi6))
  244. {
  245. *phiMax = phi2;
  246. return;
  247. }
  248. // case 4 & 6
  249. #ifdef PARANOIA
  250. if((psi3 <= psi6) && (psi4 <= psi6)) // FIXME: isn't this case implicitly true anyway??
  251. #endif
  252. {
  253. if(psi3 <= psi4) //case 4
  254. {
  255. if(psi3 >= psi7)
  256. {
  257. *phiMin = phi1;
  258. return;
  259. }
  260. else
  261. {
  262. *phiMax = phi2;
  263. return;
  264. }
  265. }
  266. else // case 6
  267. {
  268. *phiMin = phi1;
  269. *phiMax = phi2;
  270. return;
  271. }
  272. }
  273. I_OutputMsg("phiMin = %f, phiMax = %f, phi1 = %f, phi2 = %f\n", *phiMin, *phiMax, phi1, phi2);
  274. I_Error("Holy shit, phiBounds() freaked out\n");
  275. }
  276. //
  277. // Check if a vertex lies inside a sector
  278. // This works for "well-behaved" convex polygons
  279. // If we need it mathematically correct, we need to sort the
  280. // linedefs first so we have them in a row, then walk along the linedefs,
  281. // but this is a bit overdone
  282. //
  283. bool isVertexInside(vertex_t *vertex, sector_t *sector)
  284. {
  285. double xa, ya, xe, ye;
  286. linechain_t *chain;
  287. double phiMin, phiMax;
  288. double phi1, phi2;
  289. chain = sector->sectorLines;
  290. phiMin = phiMax = 10.0*M_PI; // some value > \pi
  291. while(chain)
  292. {
  293. // start and end vertex
  294. xa = chain->line->v1->x.Float() - vertex->x.Float();
  295. ya = chain->line->v1->y.Float() - vertex->y.Float();
  296. xe = chain->line->v2->x.Float() - vertex->x.Float();
  297. ye = chain->line->v2->y.Float() - vertex->y.Float();
  298. // angle phi of connection between the vertices and the x-axis
  299. phi1 = atan2(ya, xa);
  300. phi2 = atan2(ye, xe);
  301. // if we have just started, we can have to create start bounds for phi
  302. phiBounds(phi1, phi2, &phiMin, &phiMax);
  303. chain = chain->next;
  304. }
  305. return biggerThanPi(phiMin, phiMax);
  306. }
  307. #define MAXSTACK 256 // Not more than 256 polys in each other?
  308. //
  309. // generate a list of sectors which enclose the given sector
  310. //
  311. void Rend::generateStacklist(sector_t *thisSector)
  312. {
  313. int i;
  314. int stackCnt;
  315. sector_t *locStacklist[MAXSTACK];
  316. sector_t *checkSector;
  317. stackCnt = 0;
  318. for(i=0; i<numsectors; i++)
  319. {
  320. checkSector = &sectors[i];
  321. if(checkSector == thisSector) // don´t check self
  322. continue;
  323. // buggy sector?
  324. if(NULL == thisSector->sectorLines)
  325. continue;
  326. // check if an arbitrary vertex of thisSector lies inside the checkSector
  327. if(isVertexInside(thisSector->sectorLines->line->v1, checkSector))
  328. {
  329. // if so, the thisSector lies inside the checkSector
  330. locStacklist[stackCnt] = checkSector;
  331. stackCnt++;
  332. if(MAXSTACK-1 == stackCnt) // beware of the SIGSEGV! and consider terminating NULL!
  333. break;
  334. }
  335. }
  336. thisSector->stackList = (sector_t **)malloc(sizeof(sector_t*) * (stackCnt+1));
  337. if(NULL == thisSector->stackList)
  338. {
  339. I_Error("Out of memory error in generateStacklist()");
  340. }
  341. locStacklist[stackCnt] = NULL; // terminating NULL
  342. memcpy(thisSector->stackList, locStacklist, sizeof(sector_t*) * (stackCnt+1));
  343. }
  344. //
  345. // Bubble sort the stacklist with rising lineoutlengths
  346. //
  347. static void sortStacklist(sector_t *sector)
  348. {
  349. sector_t **list;
  350. sector_t *sec1, *sec2;
  351. bool finished;
  352. int i;
  353. list = sector->stackList;
  354. finished = false;
  355. if(NULL == *list)
  356. return; // nothing to sort
  357. while(!finished)
  358. {
  359. i=0;
  360. finished = true;
  361. while(NULL != *(list+i+1))
  362. {
  363. sec1 = *(list+i);
  364. sec2 = *(list+i+1);
  365. if(sec1->lineoutLength > sec2->lineoutLength)
  366. {
  367. *(list+i) = sec2;
  368. *(list+i+1) = sec1;
  369. finished = false;
  370. }
  371. i++;
  372. }
  373. }
  374. }
  375. //
  376. // length of a line in euclidian sense
  377. //
  378. static double lineLength(line_t *line)
  379. {
  380. double dx, dy, length;
  381. dx = line->v1->x.Float() - line->v2->x.Float();
  382. dy = line->v1->y.Float() - line->v2->y.Float();
  383. length = sqrt(dx*dx + dy*dy);
  384. return length;
  385. }
  386. //
  387. // length of the sector lineout
  388. //
  389. static double calcLineoutLength(sector_t *sector)
  390. {
  391. linechain_t *chain;
  392. double length;
  393. length = 0.0;
  394. chain = sector->sectorLines;
  395. while(NULL != chain) // sum up lengths of all lines
  396. {
  397. length += lineLength(chain->line);
  398. chain = chain->next;
  399. }
  400. return length;
  401. }
  402. //
  403. // Calculate length of the sectors lineout
  404. //
  405. static void calcLineouts(sector_t *sector)
  406. {
  407. sector_t *encSector;
  408. int secCount;
  409. secCount = 0;
  410. encSector = *(sector->stackList);
  411. while(NULL != encSector)
  412. {
  413. if(encSector->lineoutLength < 0.0) // if length has not yet been calculated
  414. {
  415. encSector->lineoutLength = calcLineoutLength(encSector);
  416. }
  417. secCount++;
  418. encSector = *((sector->stackList) + secCount);
  419. }
  420. }
  421. //
  422. // Free Stacklists of all sectors
  423. //
  424. void Rend::freeStacklists()
  425. {
  426. int i;
  427. for(i=0; i<numsectors; i++)
  428. {
  429. if(sectors[i].stackList)
  430. {
  431. free(sectors[i].stackList);
  432. sectors[i].stackList = NULL;
  433. }
  434. }
  435. }
  436. //
  437. // if more than half of the toptextures are missing
  438. //
  439. bool Rend::areToptexturesMissing(sector_t *thisSector)
  440. {
  441. linechain_t *thisElem, *nextElem;
  442. sector_t *frontSector, *backSector;
  443. int nomiss;
  444. side_t *sdl, *sdr;
  445. thisElem = NULL;
  446. nextElem = thisSector->sectorLines;
  447. nomiss = 0;
  448. while(NULL != nextElem) // walk through chain
  449. {
  450. thisElem = nextElem;
  451. nextElem = thisElem->next;
  452. frontSector = thisElem->line->frontsector;
  453. backSector = thisElem->line->backsector;
  454. if(frontSector == backSector) // skip damn renderer tricks here
  455. {
  456. continue;
  457. }
  458. if(frontSector == NULL || backSector == NULL)
  459. {
  460. continue;
  461. }
  462. sdr = thisElem->line->sideptr[0];
  463. sdl = thisElem->line->sideptr[1];
  464. if(backSector->ceilingheight < frontSector->ceilingheight)
  465. {
  466. if(sdr->toptexture != 0)
  467. {
  468. nomiss++;
  469. break; // we can stop here if decision criterium is ==0
  470. }
  471. }
  472. else if(backSector->ceilingheight > frontSector->ceilingheight)
  473. {
  474. if(sdl->toptexture != 0)
  475. {
  476. nomiss++;
  477. break; // we can stop here if decision criterium is ==0
  478. }
  479. }
  480. }
  481. return nomiss == 0;
  482. }
  483. //
  484. // are more textures missing than present?
  485. //
  486. bool Rend::areBottomtexturesMissing(sector_t *thisSector)
  487. {
  488. linechain_t *thisElem, *nextElem;
  489. sector_t *frontSector, *backSector;
  490. int nomiss;
  491. side_t *sdl, *sdr;
  492. thisElem = NULL;
  493. nextElem = thisSector->sectorLines;
  494. nomiss = 0;
  495. while(NULL != nextElem) // walk through chain
  496. {
  497. thisElem = nextElem;
  498. nextElem = thisElem->next;
  499. frontSector = thisElem->line->frontsector;
  500. backSector = thisElem->line->backsector;
  501. if(frontSector == backSector) // skip damn renderer tricks here
  502. {
  503. continue;
  504. }
  505. if(frontSector == NULL || backSector == NULL)
  506. {
  507. continue;
  508. }
  509. sdr = thisElem->line->sideptr[0];
  510. sdl = thisElem->line->sideptr[1];
  511. if(backSector->floorheight > frontSector->floorheight)
  512. {
  513. if(sdr->bottomtexture != 0)
  514. {
  515. nomiss++;
  516. break; // we can stop here if decision criterium is ==0
  517. }
  518. }
  519. else if(backSector->floorheight < frontSector->floorheight)
  520. {
  521. if(sdl->bottomtexture != 0)
  522. {
  523. nomiss++;
  524. break; // we can stop here if decision criterium is ==0
  525. }
  526. }
  527. }
  528. // return missing >= nomiss;
  529. return nomiss == 0;
  530. }
  531. //
  532. // check if no adjacent sector has same ceiling height
  533. //
  534. static bool isCeilingFloating(sector_t *thisSector)
  535. {
  536. sector_t *adjSector, *refSector, *frontSector, *backSector;
  537. bool floating = true;
  538. linechain_t *thisElem, *nextElem;
  539. if(NULL == thisSector)
  540. return false;
  541. refSector = NULL;
  542. thisElem = NULL;
  543. nextElem = thisSector->sectorLines;
  544. while(NULL != nextElem) // walk through chain
  545. {
  546. thisElem = nextElem;
  547. nextElem = thisElem->next;
  548. frontSector = thisElem->line->frontsector;
  549. backSector = thisElem->line->backsector;
  550. if(frontSector == thisSector)
  551. adjSector = backSector;
  552. else
  553. adjSector = frontSector;
  554. if(NULL == adjSector) // assume floating sectors have surrounding sectors
  555. {
  556. floating = false;
  557. break;
  558. }
  559. if(NULL == refSector)
  560. {
  561. refSector = adjSector;
  562. continue;
  563. }
  564. // if adjacent sector has same height or more than one adjacent sector exists -> stop
  565. if(thisSector->ceilingheight == adjSector->ceilingheight ||
  566. refSector != adjSector)
  567. {
  568. floating = false;
  569. break;
  570. }
  571. }
  572. // now check for walltextures
  573. if(floating)
  574. {
  575. if(!R.areToptexturesMissing(thisSector))
  576. {
  577. floating = false;
  578. }
  579. }
  580. return floating;
  581. }
  582. //
  583. // check if no adjacent sector has same ceiling height
  584. // FIXME: throw that together with isCeilingFloating??
  585. //
  586. static bool isFloorFloating(sector_t *thisSector)
  587. {
  588. sector_t *adjSector, *refSector, *frontSector, *backSector;
  589. bool floating = true;
  590. linechain_t *thisElem, *nextElem;
  591. if(NULL == thisSector)
  592. return false;
  593. refSector = NULL;
  594. thisElem = NULL;
  595. nextElem = thisSector->sectorLines;
  596. while(NULL != nextElem) // walk through chain
  597. {
  598. thisElem = nextElem;
  599. nextElem = thisElem->next;
  600. frontSector = thisElem->line->frontsector;
  601. backSector = thisElem->line->backsector;
  602. if(frontSector == thisSector)
  603. adjSector = backSector;
  604. else
  605. adjSector = frontSector;
  606. if(NULL == adjSector) // assume floating sectors have surrounding sectors
  607. {
  608. floating = false;
  609. break;
  610. }
  611. if(NULL == refSector)
  612. {
  613. refSector = adjSector;
  614. continue;
  615. }
  616. // if adjacent sector has same height or more than one adjacent sector exists -> stop
  617. if(thisSector->floorheight == adjSector->floorheight ||
  618. refSector != adjSector)
  619. {
  620. floating = false;
  621. break;
  622. }
  623. }
  624. // now check for walltextures
  625. if(floating)
  626. {
  627. if(!R.areBottomtexturesMissing(thisSector))
  628. {
  629. floating = false;
  630. }
  631. }
  632. return floating;
  633. }
  634. //
  635. // estimate ceilingheight according to height of adjacent sector
  636. //
  637. static fixed_t estimateCeilHeight(sector_t *thisSector)
  638. {
  639. sector_t *adjSector;
  640. if(NULL == thisSector ||
  641. NULL == thisSector->sectorLines ||
  642. NULL == thisSector->sectorLines->line)
  643. return 0;
  644. adjSector = thisSector->sectorLines->line->frontsector;
  645. if(adjSector == thisSector)
  646. adjSector = thisSector->sectorLines->line->backsector;
  647. if(NULL == adjSector)
  648. return 0;
  649. return adjSector->ceilingheight;
  650. }
  651. //
  652. // estimate ceilingheight according to height of adjacent sector
  653. //
  654. static fixed_t estimateFloorHeight(sector_t *thisSector)
  655. {
  656. sector_t *adjSector;
  657. if(NULL == thisSector ||
  658. NULL == thisSector->sectorLines ||
  659. NULL == thisSector->sectorLines->line)
  660. return 0;
  661. adjSector = thisSector->sectorLines->line->frontsector;
  662. if(adjSector == thisSector)
  663. adjSector = thisSector->sectorLines->line->backsector;
  664. if(NULL == adjSector)
  665. return 0;
  666. return adjSector->floorheight;
  667. }
  668. #define CORRECT_FLOAT_EXPERIMENTAL
  669. // --------------------------------------------------------------------------
  670. // Some levels have missing sidedefs, which produces HOM, so let´s try to compensate for that
  671. // and some levels have deep water trick, invisible staircases etc.
  672. // --------------------------------------------------------------------------
  673. // FIXME: put some nice default texture in legacy.wad and use it
  674. void Rend::HWR_CorrectSWTricks()
  675. {
  676. #ifndef NO_OPENGL
  677. extern consvar_t cv_grcorrecttricks;
  678. int i, k;
  679. line_t *ld;
  680. side_t *sdl = NULL, *sdr;
  681. sector_t *secl, *secr;
  682. sector_t **sectorList;
  683. sector_t *outSector;
  684. if ((0 == cv_grcorrecttricks.value) || game.mode >= gm_heretic)
  685. return;
  686. // determine lines for sectors
  687. for(i=0; i<numlines; i++)
  688. {
  689. ld = &lines[i];
  690. secr = ld->frontsector;
  691. secl = ld->backsector;
  692. if(secr == secl)
  693. {
  694. secr->pseudoSector = true; // special renderer trick?
  695. addLineToChain(secr, ld);
  696. }
  697. else
  698. {
  699. addLineToChain(secr, ld);
  700. addLineToChain(secl, ld);
  701. }
  702. }
  703. // preprocessing
  704. for(i=0; i<numsectors; i++)
  705. {
  706. sector_t *checkSector;
  707. checkSector = &sectors[i];
  708. // identify real pseudosectors first
  709. if(checkSector->pseudoSector)
  710. {
  711. if(!isPSectorValid(checkSector)) // drop invalid pseudo sectors
  712. {
  713. checkSector->pseudoSector = false;
  714. }
  715. }
  716. // determine enclosing sectors for pseudosectors ... used later
  717. if(checkSector->pseudoSector)
  718. {
  719. generateStacklist(checkSector);
  720. calcLineouts(checkSector);
  721. sortStacklist(checkSector);
  722. }
  723. }
  724. // set virtual floor heights for pseudo sectors
  725. // required for deep water effect e.g.
  726. for(i=0; i<numsectors; i++)
  727. {
  728. if(sectors[i].pseudoSector)
  729. {
  730. sectorList = sectors[i].stackList;
  731. k = 0;
  732. while(*(sectorList+k))
  733. {
  734. outSector = *(sectorList+k);
  735. if(!outSector->pseudoSector)
  736. {
  737. sectors[i].virtualFloorheight = outSector->floorheight;
  738. sectors[i].virtualCeilingheight = outSector->ceilingheight;
  739. break;
  740. }
  741. k++;
  742. }
  743. if(*(sectorList+k) == NULL) // sorry, did not work :(
  744. {
  745. sectors[i].virtualFloorheight = sectors[i].floorheight;
  746. sectors[i].virtualCeilingheight = sectors[i].ceilingheight;
  747. }
  748. }
  749. }
  750. #ifdef CORRECT_FLOAT_EXPERIMENTAL
  751. // correct ceiling/floor heights of totally floating sectors
  752. for(i=0; i<numsectors; i++)
  753. {
  754. sector_t *floatSector;
  755. floatSector = &sectors[i];
  756. // correct height of floating sectors
  757. if(isCeilingFloating(floatSector))
  758. {
  759. fixed_t corrheight;
  760. corrheight = estimateCeilHeight(floatSector);
  761. floatSector->virtualCeilingheight = corrheight;
  762. floatSector->virtualCeiling = true;
  763. }
  764. if(isFloorFloating(floatSector))
  765. {
  766. fixed_t corrheight;
  767. corrheight = estimateFloorHeight(floatSector);
  768. floatSector->virtualFloorheight = corrheight;
  769. floatSector->virtualFloor = true;
  770. }
  771. }
  772. #endif
  773. // now for the missing textures
  774. for(i=0; i<numlines; i++)
  775. {
  776. ld = &lines[i];
  777. sdr = ld->sideptr[0];
  778. sdl = ld->sideptr[1];
  779. secr = ld->frontsector;
  780. secl = ld->backsector;
  781. if(secr == secl) // special renderer trick
  782. continue; // we can´t correct missing textures here
  783. if(NULL != secl) // only if there is a backsector
  784. {
  785. if(secr->pseudoSector || secl->pseudoSector)
  786. continue;
  787. if(!secr->virtualFloor && !secl->virtualFloor)
  788. {
  789. if(secl->floorheight > secr->floorheight)
  790. {
  791. // now check if r-sidedef is correct
  792. if(sdr->bottomtexture == 0)
  793. {
  794. if(sdr->midtexture == 0)
  795. sdr->bottomtexture = materials.Get("STONE2", TEX_wall);
  796. else
  797. sdr->bottomtexture = sdr->midtexture;
  798. }
  799. }
  800. else if(secl->floorheight < secr->floorheight)
  801. {
  802. // now check if l-sidedef is correct
  803. if(sdl->bottomtexture == 0)
  804. {
  805. if(sdl->midtexture == 0)
  806. sdl->bottomtexture = materials.Get("STONE2", TEX_wall);
  807. else
  808. sdl->bottomtexture = sdl->midtexture;
  809. }
  810. }
  811. }
  812. if(!secr->virtualCeiling && !secl->virtualCeiling)
  813. {
  814. if(secl->ceilingheight < secr->ceilingheight)
  815. {
  816. // now check if r-sidedef is correct
  817. if(sdr->toptexture == 0)
  818. {
  819. if(sdr->midtexture == 0)
  820. sdr->toptexture = materials.Get("STONE2", TEX_wall);
  821. else
  822. sdr->toptexture = sdr->midtexture;
  823. }
  824. }
  825. else if(secl->ceilingheight > secr->ceilingheight)
  826. {
  827. // now check if l-sidedef is correct
  828. if(sdl->toptexture == 0)
  829. {
  830. if(sdl->midtexture == 0)
  831. sdl->toptexture = materials.Get("STONE2", TEX_wall);
  832. else
  833. sdl->toptexture = sdl->midtexture;
  834. }
  835. }
  836. }
  837. } // if(NULL != secl)
  838. } // for(i=0; i<numlines; i++)
  839. // release all linechains
  840. releaseLineChains();
  841. freeStacklists();
  842. #endif // NO_OPENGL
  843. }