RENDER.C 61 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266
  1. /*
  2. THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
  3. SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
  4. END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
  5. ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
  6. IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
  7. SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
  8. FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
  9. CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
  10. AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
  11. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
  12. */
  13. /*
  14. * $Source: f:/miner/source/main/rcs/render.c $
  15. * $Revision: 2.5 $
  16. * $Author: john $
  17. * $Date: 1995/12/19 15:31:36 $
  18. *
  19. * Sample setup for RCS header
  20. *
  21. * $Log: render.c $
  22. * Revision 2.5 1995/12/19 15:31:36 john
  23. * Made stereo mode only record 1 eye in demo.
  24. *
  25. * Revision 2.4 1995/03/20 18:15:53 john
  26. * Added code to not store the normals in the segment structure.
  27. *
  28. * Revision 2.3 1995/03/13 16:11:05 john
  29. * Maybe fixed bug that lighting didn't work with vr helmets.
  30. *
  31. * Revision 2.2 1995/03/09 15:33:49 john
  32. * Fixed bug with iglasses timeout too long, and objects
  33. * disappearing from left eye.
  34. *
  35. * Revision 2.1 1995/03/06 15:23:59 john
  36. * New screen techniques.
  37. *
  38. * Revision 2.0 1995/02/27 11:31:01 john
  39. * New version 2.0, which has no anonymous unions, builds with
  40. * Watcom 10.0, and doesn't require parsing BITMAPS.TBL.
  41. *
  42. * Revision 1.252 1995/02/22 13:49:38 allender
  43. * remove anonymous unions from object structure
  44. *
  45. * Revision 1.251 1995/02/11 15:07:26 matt
  46. * Took out code which was mostly intended as part of a larger renderer
  47. * change which never happened. This new code was causing problems with
  48. * the level 4 control center.
  49. *
  50. * Revision 1.250 1995/02/07 16:28:53 matt
  51. * Fixed problem with new code
  52. *
  53. * Revision 1.249 1995/02/06 14:38:58 matt
  54. * Took out some code that didn't compile when editor in
  55. *
  56. * Revision 1.248 1995/02/06 13:45:25 matt
  57. * Structural changes, plus small sorting improvements
  58. *
  59. * Revision 1.247 1995/02/02 15:59:26 matt
  60. * Changed assert to int3.
  61. *
  62. * Revision 1.246 1995/02/01 21:02:27 matt
  63. * Added partial fix for rendering bugs
  64. * Ripped out laser hack system
  65. *
  66. * Revision 1.245 1995/01/20 15:14:30 matt
  67. * Added parens to fix precedence bug
  68. *
  69. * Revision 1.244 1995/01/14 19:16:59 john
  70. * First version of new bitmap paging code.
  71. *
  72. * Revision 1.243 1995/01/03 20:19:25 john
  73. * Pretty good working version of game save.
  74. *
  75. * Revision 1.242 1994/12/29 13:51:05 john
  76. * Made the floating reticle draw in the spot
  77. * regardless of the eye offset.
  78. *
  79. * Revision 1.241 1994/12/23 15:02:55 john
  80. * Tweaked floating reticle.
  81. *
  82. * Revision 1.240 1994/12/23 14:27:45 john
  83. * Changed offset of floating reticle to line up with
  84. * lasers a bit better.
  85. *
  86. * Revision 1.239 1994/12/23 14:22:50 john
  87. * Added floating reticle for VR helments.
  88. *
  89. * Revision 1.238 1994/12/13 14:07:50 matt
  90. * Fixed tmap_num2 bug in search mode
  91. *
  92. * Revision 1.237 1994/12/11 00:45:53 matt
  93. * Fixed problem when object sort buffer got full
  94. *
  95. * Revision 1.236 1994/12/09 18:46:06 matt
  96. * Added a little debugging
  97. *
  98. * Revision 1.235 1994/12/09 14:59:16 matt
  99. * Added system to attach a fireball to another object for rendering purposes,
  100. * so the fireball always renders on top of (after) the object.
  101. *
  102. * Revision 1.234 1994/12/08 15:46:54 matt
  103. * Fixed buffer overflow that caused seg depth screwup
  104. *
  105. * Revision 1.233 1994/12/08 11:51:53 matt
  106. * Took out some unused stuff
  107. *
  108. * Revision 1.232 1994/12/06 16:31:48 mike
  109. * fix detriangulation problems.
  110. *
  111. * Revision 1.231 1994/12/05 15:32:51 matt
  112. * Changed an assert to an int3 & return
  113. *
  114. * Revision 1.230 1994/12/04 17:28:04 matt
  115. * Got rid of unused no_render_flag array, and took out box clear when searching
  116. *
  117. * Revision 1.229 1994/12/04 15:51:14 matt
  118. * Fixed linear tmap transition for objects
  119. *
  120. * Revision 1.228 1994/12/03 20:16:50 matt
  121. * Turn off window clip for objects
  122. *
  123. * Revision 1.227 1994/12/03 14:48:00 matt
  124. * Restored some default settings
  125. *
  126. * Revision 1.226 1994/12/03 14:44:32 matt
  127. * Fixed another difficult bug in the window clip system
  128. *
  129. * Revision 1.225 1994/12/02 13:19:56 matt
  130. * Fixed rect clears at terminus of rendering
  131. * Made a bunch of debug code compile out
  132. *
  133. * Revision 1.224 1994/12/02 11:58:21 matt
  134. * Fixed window clip bug
  135. *
  136. * Revision 1.223 1994/11/28 21:50:42 mike
  137. * optimizations.
  138. *
  139. * Revision 1.222 1994/11/28 01:32:15 mike
  140. * turn off window clearing.
  141. *
  142. * Revision 1.221 1994/11/27 23:11:52 matt
  143. * Made changes for new mprintf calling convention
  144. *
  145. * Revision 1.220 1994/11/20 15:58:55 matt
  146. * Don't migrate the control center, since it doesn't move out of its segment
  147. *
  148. * Revision 1.219 1994/11/19 23:54:36 mike
  149. * change window colors.
  150. *
  151. * Revision 1.218 1994/11/19 15:20:25 mike
  152. * rip out unused code and data
  153. *
  154. * Revision 1.217 1994/11/18 13:21:24 mike
  155. * Clear only view portals into rest of world based on value of Clear_window.
  156. *
  157. * Revision 1.216 1994/11/15 17:02:10 matt
  158. * Re-added accidentally deleted variable
  159. *
  160. * Revision 1.215 1994/11/15 16:51:50 matt
  161. * Made rear view only switch to rear cockpit if cockpit on in front view
  162. *
  163. * Revision 1.214 1994/11/14 20:47:57 john
  164. * Attempted to strip out all the code in the game
  165. * directory that uses any ui code.
  166. *
  167. * Revision 1.213 1994/11/11 15:37:07 mike
  168. * write orange for background to show render bugs.
  169. *
  170. * Revision 1.212 1994/11/09 22:57:18 matt
  171. * Keep tract of depth of segments rendered, for detail level optimization
  172. *
  173. * Revision 1.211 1994/11/01 23:40:14 matt
  174. * Elegantly handler buffer getting full
  175. *
  176. * Revision 1.210 1994/10/31 22:28:13 mike
  177. * Fix detriangulation bug.
  178. *
  179. * Revision 1.209 1994/10/31 11:48:56 mike
  180. * Optimize detriangulation, speedup of about 4% in many cases, 0% in many.
  181. *
  182. * Revision 1.208 1994/10/30 20:08:34 matt
  183. * For endlevel: added big explosion at tunnel exit; made lights in tunnel
  184. * go out; made more explosions on walls.
  185. *
  186. * Revision 1.207 1994/10/27 14:14:35 matt
  187. * Don't do light flash during endlevel sequence
  188. *
  189. * Revision 1.206 1994/10/11 12:05:42 mike
  190. * Improve detriangulation.
  191. *
  192. * Revision 1.205 1994/10/07 15:27:00 john
  193. * Commented out the code that moves your eye
  194. * forward.
  195. *
  196. * Revision 1.204 1994/10/05 16:07:38 mike
  197. * Don't detriangulate sides if in player's segment. Prevents player going behind a wall,
  198. * though there are cases in which it would be ok to detriangulate these.
  199. *
  200. * Revision 1.203 1994/10/03 12:44:05 matt
  201. * Took out unreferenced code
  202. *
  203. * Revision 1.202 1994/09/28 14:08:45 john
  204. * Added Zoom stuff back in, but ifdef'd it out.
  205. *
  206. * Revision 1.201 1994/09/25 23:41:49 matt
  207. * Changed the object load & save code to read/write the structure fields one
  208. * at a time (rather than the whole structure at once). This mean that the
  209. * object structure can be changed without breaking the load/save functions.
  210. * As a result of this change, the local_object data can be and has been
  211. * incorporated into the object array. Also, timeleft is now a property
  212. * of all objects, and the object structure has been otherwise cleaned up.
  213. *
  214. * Revision 1.200 1994/09/25 15:50:10 mike
  215. * Integrate my debug changes which shows how many textures were rendered
  216. * this frame.
  217. *
  218. * Revision 1.199 1994/09/25 15:45:22 matt
  219. * Added OBJ_LIGHT, a type of object that casts light
  220. * Added generalized lifeleft, and moved it to local_object
  221. *
  222. * Revision 1.198 1994/09/15 21:23:32 matt
  223. * Changed system to keep track of whether & what cockpit is up
  224. *
  225. * Revision 1.197 1994/09/15 16:30:12 mike
  226. * Comment out call to object_render_targets, which did nothing.
  227. *
  228. * Revision 1.196 1994/09/07 22:25:51 matt
  229. * Don't migrate through semi-transparent walls
  230. *
  231. * Revision 1.195 1994/09/07 19:16:21 mike
  232. * Homing missile.
  233. *
  234. * Revision 1.194 1994/08/31 20:54:17 matt
  235. * Don't do flash effect while whiting out
  236. *
  237. * Revision 1.193 1994/08/23 17:20:12 john
  238. * Added rear-view cockpit.
  239. *
  240. * Revision 1.192 1994/08/22 14:36:35 john
  241. * Made R key make a "reverse" view render.
  242. *
  243. * Revision 1.191 1994/08/19 20:09:26 matt
  244. * Added end-of-level cut scene with external scene
  245. *
  246. * Revision 1.190 1994/08/10 19:56:17 john
  247. * Changed font stuff; Took out old menu; messed up lots of
  248. * other stuff like game sequencing messages, etc.
  249. *
  250. * Revision 1.189 1994/08/10 14:45:05 john
  251. * *** empty log message ***
  252. *
  253. * Revision 1.188 1994/08/09 16:04:06 john
  254. * Added network players to editor.
  255. *
  256. * Revision 1.187 1994/08/05 17:07:05 john
  257. * Made lasers be two objects, one drawing after the other
  258. * all the time.
  259. *
  260. * Revision 1.186 1994/08/05 10:07:57 matt
  261. * Disable window check checking (i.e., always use window check)
  262. *
  263. * Revision 1.185 1994/08/04 19:11:30 matt
  264. * Changed a bunch of vecmat calls to use multiple-function routines, and to
  265. * allow the use of C macros for some functions
  266. *
  267. * Revision 1.184 1994/08/04 00:21:14 matt
  268. * Cleaned up fvi & physics error handling; put in code to make sure objects
  269. * are in correct segment; simplified segment finding for objects and points
  270. *
  271. * Revision 1.183 1994/08/02 19:04:28 matt
  272. * Cleaned up vertex list functions
  273. *
  274. * Revision 1.182 1994/07/29 15:13:33 matt
  275. * When window check turned off, cut render depth in half
  276. *
  277. * Revision 1.181 1994/07/29 11:03:50 matt
  278. * Use highest_segment_index instead of num_segments so render works from
  279. * the editor
  280. *
  281. * Revision 1.180 1994/07/29 10:04:34 mike
  282. * Update Cursegp when an object is selected.
  283. *
  284. * Revision 1.179 1994/07/25 00:02:50 matt
  285. * Various changes to accomodate new 3d, which no longer takes point numbers
  286. * as parms, and now only takes pointers to points.
  287. *
  288. * Revision 1.178 1994/07/24 14:37:49 matt
  289. * Added angles for player head
  290. *
  291. * Revision 1.177 1994/07/20 19:08:07 matt
  292. * If in editor, don't move eye from center of viewer object
  293. *
  294. *
  295. */
  296. #pragma off (unreferenced)
  297. static char rcsid[] = "$Id: render.c 2.5 1995/12/19 15:31:36 john Exp $";
  298. #pragma on (unreferenced)
  299. #include <stdlib.h>
  300. #include <string.h>
  301. #include "inferno.h"
  302. #include "segment.h"
  303. #include "error.h"
  304. #include "bm.h"
  305. #include "texmap.h"
  306. #include "mono.h"
  307. #include "render.h"
  308. #include "game.h"
  309. #include "object.h"
  310. #include "laser.h"
  311. #include "textures.h"
  312. #include "screens.h"
  313. #include "segpoint.h"
  314. #include "wall.h"
  315. #include "texmerge.h"
  316. #include "physics.h"
  317. #include "3d.h"
  318. #include "gameseg.h"
  319. #include "vclip.h"
  320. #include "lighting.h"
  321. #include "fuelcen.h"
  322. #include "newdemo.h"
  323. #include "automap.h"
  324. #include "endlevel.h"
  325. #include "key.h"
  326. #include "newmenu.h"
  327. #include "mem.h"
  328. #include "piggy.h"
  329. #define INITIAL_LOCAL_LIGHT (F1_0/4) // local light value in segment of occurence (of light emission)
  330. #ifdef EDITOR
  331. #include "editor\editor.h"
  332. #endif
  333. //used for checking if points have been rotated
  334. int Clear_window_color=-1;
  335. int Clear_window=2; // 1 = Clear whole background window, 2 = clear view portals into rest of world, 0 = no clear
  336. int RL_framecount=-1;
  337. short Rotated_last[MAX_VERTICES];
  338. // When any render function needs to know what's looking at it, it should
  339. // access Viewer members.
  340. object * Viewer = NULL;
  341. vms_vector Viewer_eye; //valid during render
  342. int N_render_segs;
  343. fix Render_zoom = 0x9000; //the player's zoom factor
  344. #ifndef NDEBUG
  345. ubyte object_rendered[MAX_OBJECTS];
  346. #endif
  347. #define DEFAULT_RENDER_DEPTH 16
  348. int Render_depth=DEFAULT_RENDER_DEPTH; //how many segments deep to render
  349. int Detriangulation_on = 1; // 1 = allow rendering of triangulated side as a quad, 0 = don't allow
  350. #ifdef EDITOR
  351. int Render_only_bottom=0;
  352. int Bottom_bitmap_num = 9;
  353. #endif
  354. fix Face_reflectivity = (F1_0/2);
  355. #if 0 //this stuff could probably just be deleted
  356. int inc_render_depth(void)
  357. {
  358. return ++Render_depth;
  359. }
  360. int dec_render_depth(void)
  361. {
  362. return Render_depth==1?Render_depth:--Render_depth;
  363. }
  364. int reset_render_depth(void)
  365. {
  366. return Render_depth = DEFAULT_RENDER_DEPTH;
  367. }
  368. #endif
  369. #ifdef EDITOR
  370. int _search_mode = 0; //true if looking for curseg,side,face
  371. short _search_x,_search_y; //pixel we're looking at
  372. int found_seg,found_side,found_face,found_poly;
  373. #else
  374. #define _search_mode 0
  375. #endif
  376. #ifdef NDEBUG //if no debug code, set these vars to constants
  377. #define Outline_mode 0
  378. #define Show_only_curside 0
  379. #else
  380. int Outline_mode=0,Show_only_curside=0;
  381. int toggle_outline_mode(void)
  382. {
  383. return Outline_mode = !Outline_mode;
  384. }
  385. int toggle_show_only_curside(void)
  386. {
  387. return Show_only_curside = !Show_only_curside;
  388. }
  389. draw_outline(int nverts,g3s_point **pointlist)
  390. {
  391. int i;
  392. gr_setcolor(BM_XRGB(63,63,63));
  393. for (i=0;i<nverts-1;i++)
  394. g3_draw_line(pointlist[i],pointlist[i+1]);
  395. g3_draw_line(pointlist[i],pointlist[0]);
  396. }
  397. #endif
  398. grs_canvas * reticle_canvas = NULL;
  399. void free_reticle_canvas()
  400. {
  401. if (reticle_canvas) {
  402. free( reticle_canvas->cv_bitmap.bm_data );
  403. free( reticle_canvas );
  404. reticle_canvas = NULL;
  405. }
  406. }
  407. extern void show_reticle(int force_big);
  408. // Draw the reticle in 3D for head tracking
  409. void draw_3d_reticle(fix eye_offset)
  410. {
  411. g3s_point reticle_points[4];
  412. g3s_uvl uvl[4];
  413. g3s_point *pointlist[4];
  414. int i;
  415. vms_vector v1, v2;
  416. grs_canvas *saved_canvas;
  417. int saved_interp_method;
  418. // if (!Use_player_head_angles) return;
  419. for (i=0; i<4; i++ ) {
  420. pointlist[i] = &reticle_points[i];
  421. uvl[i].l = MAX_LIGHT;
  422. }
  423. uvl[0].u = 0; uvl[0].v = 0;
  424. uvl[1].u = F1_0; uvl[1].v = 0;
  425. uvl[2].u = F1_0; uvl[2].v = F1_0;
  426. uvl[3].u = 0; uvl[3].v = F1_0;
  427. vm_vec_scale_add( &v1, &Viewer->pos, &Viewer->orient.fvec, F1_0*4 );
  428. vm_vec_scale_add2(&v1,&Viewer->orient.rvec,eye_offset);
  429. vm_vec_scale_add( &v2, &v1, &Viewer->orient.rvec, -F1_0*1 );
  430. vm_vec_scale_add2( &v2, &Viewer->orient.uvec, F1_0*1 );
  431. g3_rotate_point(&reticle_points[0],&v2);
  432. vm_vec_scale_add( &v2, &v1, &Viewer->orient.rvec, +F1_0*1 );
  433. vm_vec_scale_add2( &v2, &Viewer->orient.uvec, F1_0*1 );
  434. g3_rotate_point(&reticle_points[1],&v2);
  435. vm_vec_scale_add( &v2, &v1, &Viewer->orient.rvec, +F1_0*1 );
  436. vm_vec_scale_add2( &v2, &Viewer->orient.uvec, -F1_0*1 );
  437. g3_rotate_point(&reticle_points[2],&v2);
  438. vm_vec_scale_add( &v2, &v1, &Viewer->orient.rvec, -F1_0*1 );
  439. vm_vec_scale_add2( &v2, &Viewer->orient.uvec, -F1_0*1 );
  440. g3_rotate_point(&reticle_points[3],&v2);
  441. if ( reticle_canvas == NULL ) {
  442. reticle_canvas = gr_create_canvas(64,64);
  443. if ( !reticle_canvas )
  444. Error( "Couldn't malloc reticle_canvas" );
  445. atexit( free_reticle_canvas );
  446. reticle_canvas->cv_bitmap.bm_selector = 0;
  447. reticle_canvas->cv_bitmap.bm_flags = BM_FLAG_TRANSPARENT;
  448. }
  449. saved_canvas = grd_curcanv;
  450. gr_set_current_canvas(reticle_canvas);
  451. gr_clear_canvas( 255 ); // Clear to Xparent
  452. show_reticle(1);
  453. gr_set_current_canvas(saved_canvas);
  454. saved_interp_method=Interpolation_method;
  455. Interpolation_method = 3; // The best, albiet slowest.
  456. g3_draw_tmap(4,pointlist,uvl,&reticle_canvas->cv_bitmap);
  457. Interpolation_method = saved_interp_method;
  458. }
  459. fix flash_scale;
  460. #define FLASH_CYCLE_RATE f1_0
  461. fix flash_rate = FLASH_CYCLE_RATE;
  462. //cycle the flashing light for when mine destroyed
  463. flash_frame()
  464. {
  465. static fixang flash_ang=0;
  466. if (!Fuelcen_control_center_destroyed)
  467. return;
  468. if (Endlevel_sequence)
  469. return;
  470. if (PaletteBlueAdd > 10 ) //whiting out
  471. return;
  472. // flash_ang += fixmul(FLASH_CYCLE_RATE,FrameTime);
  473. flash_ang += fixmul(flash_rate,FrameTime);
  474. fix_fastsincos(flash_ang,&flash_scale,NULL);
  475. flash_scale = (flash_scale + f1_0)/2;
  476. }
  477. // -----------------------------------------------------------------------------------
  478. // Render a face.
  479. // It would be nice to not have to pass in segnum and sidenum, but they are used for our
  480. // hideously hacked in headlight system.
  481. // vp is a pointer to vertex ids.
  482. // tmap1, tmap2 are texture map ids. tmap2 is the pasty one.
  483. void render_face(int segnum, int sidenum, int nv, short *vp, int tmap1, int tmap2, uvl *uvlp, vms_vector *norm)
  484. {
  485. fix face_light;
  486. grs_bitmap *bm;
  487. fix reflect;
  488. uvl uvl_copy[8];
  489. int i;
  490. g3s_point *pointlist[8];
  491. Assert(nv <= 8);
  492. for (i=0; i<nv; i++) {
  493. uvl_copy[i] = uvlp[i];
  494. pointlist[i] = &Segment_points[vp[i]];
  495. }
  496. face_light = -vm_vec_dot(&Viewer->orient.fvec,norm);
  497. if (tmap1 >= NumTextures) {
  498. mprintf((0,"Invalid tmap number %d, NumTextures=%d, changing to 0\n",tmap1,NumTextures));
  499. Int3();
  500. Segments[segnum].sides[sidenum].tmap_num = 0;
  501. }
  502. // New code for overlapping textures...
  503. if (tmap2 != 0)
  504. bm = texmerge_get_cached_bitmap( tmap1, tmap2 );
  505. else {
  506. bm = &GameBitmaps[Textures[tmap1].index];
  507. PIGGY_PAGE_IN(Textures[tmap1]);
  508. }
  509. Assert( !(bm->bm_flags & BM_FLAG_PAGED_OUT) );
  510. //reflect = fl2f((1.0-TmapInfo[p->tmap_num].reflect)/2.0 + 0.5);
  511. //reflect = fl2f((1.0-TmapInfo[p->tmap_num].reflect));
  512. reflect = Face_reflectivity; // f1_0; //until we figure this stuff out...
  513. //set light values for each vertex & build pointlist
  514. {
  515. int i;
  516. face_light = fixmul(face_light,reflect);
  517. for (i=0;i<nv;i++) {
  518. //the uvl struct has static light already in it
  519. //scale static light for destruction effect
  520. if (Fuelcen_control_center_destroyed) //make lights flash
  521. uvl_copy[i].l = fixmul(flash_scale,uvl_copy[i].l);
  522. //add in dynamic light (from explosions, etc.)
  523. uvl_copy[i].l += Dynamic_light[vp[i]];
  524. //add in light from player's headlight
  525. uvl_copy[i].l += compute_headlight_light(&Segment_points[vp[i]].p3_vec,face_light);
  526. //saturate at max value
  527. if (uvl_copy[i].l > MAX_LIGHT)
  528. uvl_copy[i].l = MAX_LIGHT;
  529. }
  530. }
  531. #ifdef EDITOR
  532. if ((Render_only_bottom) && (sidenum == WBOTTOM))
  533. g3_draw_tmap(nv,pointlist,(g3s_uvl *) uvl_copy,&GameBitmaps[Textures[Bottom_bitmap_num].index]);
  534. else
  535. #endif
  536. g3_draw_tmap(nv,pointlist,(g3s_uvl *) uvl_copy,bm);
  537. #ifndef NDEBUG
  538. if (Outline_mode) draw_outline(nv, pointlist);
  539. #endif
  540. }
  541. #ifdef EDITOR
  542. // -----------------------------------------------------------------------------------
  543. // Only called if editor active.
  544. // Used to determine which face was clicked on.
  545. void check_face(int segnum, int sidenum, int facenum, int nv, short *vp, int tmap1, int tmap2, uvl *uvlp)
  546. {
  547. int i;
  548. if (_search_mode) {
  549. int save_lighting;
  550. grs_bitmap *bm;
  551. uvl uvl_copy[8];
  552. g3s_point *pointlist[4];
  553. if (tmap2 > 0 )
  554. bm = texmerge_get_cached_bitmap( tmap1, tmap2 );
  555. else
  556. bm = &GameBitmaps[Textures[tmap1].index];
  557. for (i=0; i<nv; i++) {
  558. uvl_copy[i] = uvlp[i];
  559. pointlist[i] = &Segment_points[vp[i]];
  560. }
  561. gr_setcolor(0);
  562. gr_pixel(_search_x,_search_y); //set our search pixel to color zero
  563. gr_setcolor(1); //and render in color one
  564. save_lighting = Lighting_on;
  565. Lighting_on = 2;
  566. //g3_draw_poly(nv,vp);
  567. g3_draw_tmap(nv,pointlist, uvl_copy, bm);
  568. Lighting_on = save_lighting;
  569. if (gr_ugpixel(&grd_curcanv->cv_bitmap,_search_x,_search_y) == 1) {
  570. found_seg = segnum;
  571. found_side = sidenum;
  572. found_face = facenum;
  573. }
  574. }
  575. }
  576. #endif
  577. fix Tulate_min_dot = (F1_0/4);
  578. //--unused-- fix Tulate_min_ratio = (2*F1_0);
  579. fix Min_n0_n1_dot = (F1_0*15/16);
  580. // -----------------------------------------------------------------------------------
  581. // Render a side.
  582. // Check for normal facing. If so, render faces on side dictated by sidep->type.
  583. void render_side(segment *segp, int sidenum)
  584. {
  585. short vertnum_list[4];
  586. side *sidep = &segp->sides[sidenum];
  587. vms_vector tvec;
  588. fix v_dot_n0, v_dot_n1;
  589. uvl temp_uvls[3];
  590. fix min_dot, max_dot;
  591. vms_vector normals[2];
  592. if (!(WALL_IS_DOORWAY(segp,sidenum) & WID_RENDER_FLAG)) //if (WALL_IS_DOORWAY(segp, sidenum) == WID_NO_WALL)
  593. return;
  594. #ifdef COMPACT_SEGS
  595. get_side_normals(segp, sidenum, &normals[0], &normals[1] );
  596. #else
  597. normals[0] = segp->sides[sidenum].normals[0];
  598. normals[1] = segp->sides[sidenum].normals[1];
  599. #endif
  600. // Regardless of whether this side is comprised of a single quad, or two triangles, we need to know one normal, so
  601. // deal with it, get the dot product.
  602. if (sidep->type == SIDE_IS_TRI_13)
  603. vm_vec_normalized_dir(&tvec, &Viewer_eye, &Vertices[segp->verts[Side_to_verts[sidenum][1]]]);
  604. else
  605. vm_vec_normalized_dir(&tvec, &Viewer_eye, &Vertices[segp->verts[Side_to_verts[sidenum][0]]]);
  606. get_side_verts(vertnum_list,segp-Segments,sidenum);
  607. v_dot_n0 = vm_vec_dot(&tvec, &normals[0]);
  608. if (sidep->type == SIDE_IS_QUAD) {
  609. if (v_dot_n0 >= 0) {
  610. render_face(segp-Segments, sidenum, 4, vertnum_list, sidep->tmap_num, sidep->tmap_num2, sidep->uvls, &normals[0]);
  611. #ifdef EDITOR
  612. check_face(segp-Segments, sidenum, 0, 4, vertnum_list, sidep->tmap_num, sidep->tmap_num2, sidep->uvls);
  613. #endif
  614. }
  615. } else {
  616. // Although this side has been triangulated, because it is not planar, see if it is acceptable
  617. // to render it as a single quadrilateral. This is a function of how far away the viewer is, how non-planar
  618. // the face is, how normal to the surfaces the view is.
  619. // Now, if both dot products are close to 1.0, then render two triangles as a single quad.
  620. v_dot_n1 = vm_vec_dot(&tvec, &normals[1]);
  621. if (v_dot_n0 < v_dot_n1) {
  622. min_dot = v_dot_n0;
  623. max_dot = v_dot_n1;
  624. } else {
  625. min_dot = v_dot_n1;
  626. max_dot = v_dot_n0;
  627. }
  628. // Determine whether to detriangulate side: (speed hack, assumes Tulate_min_ratio == F1_0*2, should fixmul(min_dot, Tulate_min_ratio))
  629. if (Detriangulation_on && ((min_dot+F1_0/256 > max_dot) || ((Viewer->segnum != segp-Segments) && (min_dot > Tulate_min_dot) && (max_dot < min_dot*2)))) {
  630. fix n0_dot_n1;
  631. // The other detriangulation code doesn't deal well with badly non-planar sides.
  632. n0_dot_n1 = vm_vec_dot(&normals[0], &normals[1]);
  633. if (n0_dot_n1 < Min_n0_n1_dot)
  634. goto im_so_ashamed;
  635. render_face(segp-Segments, sidenum, 4, vertnum_list, sidep->tmap_num, sidep->tmap_num2, sidep->uvls, &normals[0]);
  636. #ifdef EDITOR
  637. check_face(segp-Segments, sidenum, 0, 4, vertnum_list, sidep->tmap_num, sidep->tmap_num2, sidep->uvls);
  638. #endif
  639. } else {
  640. im_so_ashamed: ;
  641. if (sidep->type == SIDE_IS_TRI_02) {
  642. if (v_dot_n0 >= 0) {
  643. render_face(segp-Segments, sidenum, 3, vertnum_list, sidep->tmap_num, sidep->tmap_num2, sidep->uvls, &normals[0]);
  644. #ifdef EDITOR
  645. check_face(segp-Segments, sidenum, 0, 3, vertnum_list, sidep->tmap_num, sidep->tmap_num2, sidep->uvls);
  646. #endif
  647. }
  648. if (v_dot_n1 >= 0) {
  649. temp_uvls[0] = sidep->uvls[0]; temp_uvls[1] = sidep->uvls[2]; temp_uvls[2] = sidep->uvls[3];
  650. vertnum_list[1] = vertnum_list[2]; vertnum_list[2] = vertnum_list[3]; // want to render from vertices 0, 2, 3 on side
  651. render_face(segp-Segments, sidenum, 3, &vertnum_list[0], sidep->tmap_num, sidep->tmap_num2, temp_uvls, &normals[1]);
  652. #ifdef EDITOR
  653. check_face(segp-Segments, sidenum, 1, 3, vertnum_list, sidep->tmap_num, sidep->tmap_num2, sidep->uvls);
  654. #endif
  655. }
  656. } else if (sidep->type == SIDE_IS_TRI_13) {
  657. if (v_dot_n1 >= 0) {
  658. render_face(segp-Segments, sidenum, 3, &vertnum_list[1], sidep->tmap_num, sidep->tmap_num2, &sidep->uvls[1], &normals[1]); // rendering 1,2,3, so just skip 0
  659. #ifdef EDITOR
  660. check_face(segp-Segments, sidenum, 1, 3, &vertnum_list[1], sidep->tmap_num, sidep->tmap_num2, sidep->uvls);
  661. #endif
  662. }
  663. if (v_dot_n0 >= 0) {
  664. temp_uvls[0] = sidep->uvls[0]; temp_uvls[1] = sidep->uvls[1]; temp_uvls[2] = sidep->uvls[3];
  665. vertnum_list[2] = vertnum_list[3]; // want to render from vertices 0,1,3
  666. render_face(segp-Segments, sidenum, 3, vertnum_list, sidep->tmap_num, sidep->tmap_num2, temp_uvls, &normals[0]);
  667. #ifdef EDITOR
  668. check_face(segp-Segments, sidenum, 0, 3, vertnum_list, sidep->tmap_num, sidep->tmap_num2, sidep->uvls);
  669. #endif
  670. }
  671. } else
  672. Error("Illegal side type in render_side, type = %i, segment # = %i, side # = %i\n", sidep->type, segp-Segments, sidenum);
  673. }
  674. }
  675. }
  676. #ifdef EDITOR
  677. render_object_search(object *obj)
  678. {
  679. int changed=0;
  680. //note that we draw each pixel object twice, since we cannot control
  681. //what color the object draws in, so we try color 0, then color 1,
  682. //in case the object itself is rendering color 0
  683. gr_setcolor(0);
  684. gr_pixel(_search_x,_search_y); //set our search pixel to color zero
  685. render_object(obj);
  686. if (gr_ugpixel(&grd_curcanv->cv_bitmap,_search_x,_search_y) != 0)
  687. changed=1;
  688. gr_setcolor(1);
  689. gr_pixel(_search_x,_search_y); //set our search pixel to color zero
  690. render_object(obj);
  691. if (gr_ugpixel(&grd_curcanv->cv_bitmap,_search_x,_search_y) != 1)
  692. changed=1;
  693. if (changed) {
  694. if (obj->segnum != -1)
  695. Cursegp = &Segments[obj->segnum];
  696. found_seg = -(obj-Objects+1);
  697. }
  698. }
  699. #endif
  700. do_render_object(int objnum)
  701. {
  702. #ifdef EDITOR
  703. int save_3d_outline;
  704. #endif
  705. object *obj = &Objects[objnum];
  706. int count = 0;
  707. int n;
  708. Assert(objnum < MAX_OBJECTS);
  709. #ifndef NDEBUG
  710. if (object_rendered[objnum]) { //already rendered this...
  711. Int3(); //get Matt!!!
  712. return;
  713. }
  714. object_rendered[objnum] = 1;
  715. #endif
  716. // Added by MK on 09/07/94 (at about 5:28 pm, CDT, on a beautiful, sunny late summer day!) so
  717. // that the guided missile system will know what objects to look at.
  718. if ((Objects[objnum].type == OBJ_ROBOT) || (Objects[objnum].type == OBJ_PLAYER)) {
  719. //Assert(Num_rendered_objects < MAX_RENDERED_OBJECTS);
  720. // This peculiar piece of code makes us keep track of the most recently rendered objects, which
  721. // are probably the higher priority objects, without overflowing the buffer
  722. if (Num_rendered_objects >= MAX_RENDERED_OBJECTS) {
  723. Int3();
  724. Num_rendered_objects /= 2;
  725. }
  726. Ordered_rendered_object_list[Num_rendered_objects++] = objnum;
  727. }
  728. if ((count++ > MAX_OBJECTS) || (obj->next == objnum)) {
  729. Int3(); // infinite loop detected
  730. obj->next = -1; // won't this clean things up?
  731. return; // get out of this infinite loop!
  732. }
  733. //g3_draw_object(obj->class_id,&obj->pos,&obj->orient,obj->size);
  734. //check for editor object
  735. #ifdef EDITOR
  736. if (Function_mode==FMODE_EDITOR && objnum==Cur_object_index) {
  737. save_3d_outline = g3d_interp_outline;
  738. g3d_interp_outline=1;
  739. }
  740. #endif
  741. #ifdef EDITOR
  742. if (_search_mode)
  743. render_object_search(obj);
  744. else
  745. #endif
  746. //NOTE LINK TO ABOVE
  747. render_object(obj);
  748. for (n=obj->attached_obj;n!=-1;n=Objects[n].ctype.expl_info.next_attach) {
  749. Assert(Objects[n].type == OBJ_FIREBALL);
  750. Assert(Objects[n].control_type == CT_EXPLOSION);
  751. Assert(Objects[n].flags & OF_ATTACHED);
  752. render_object(&Objects[n]);
  753. }
  754. #ifdef EDITOR
  755. if (Function_mode==FMODE_EDITOR && objnum==Cur_object_index)
  756. g3d_interp_outline = save_3d_outline;
  757. #endif
  758. //DEBUG mprintf( (0, "%d ", objnum ));
  759. }
  760. #ifndef NDEBUG
  761. int draw_boxes=0;
  762. int window_check=1,draw_edges=0,new_seg_sorting=1,pre_draw_segs=0;
  763. int no_migrate_segs=1,migrate_objects=1,behind_check=1;
  764. int check_window_check=0;
  765. #else
  766. #define draw_boxes 0
  767. #define window_check 1
  768. #define draw_edges 0
  769. #define new_seg_sorting 1
  770. #define pre_draw_segs 0
  771. #define no_migrate_segs 1
  772. #define migrate_objects 1
  773. #define behind_check 1
  774. #define check_window_check 0
  775. #endif
  776. //increment counter for checking if points rotated
  777. //This must be called at the start of the frame if rotate_list() will be used
  778. void render_start_frame()
  779. {
  780. RL_framecount++;
  781. if (RL_framecount==0) { //wrap!
  782. memset(Rotated_last,0,sizeof(Rotated_last)); //clear all to zero
  783. RL_framecount=1; //and set this frame to 1
  784. }
  785. }
  786. //Given a lit of point numbers, rotate any that haven't been rotated this frame
  787. g3s_codes rotate_list(int nv,short *pointnumlist)
  788. {
  789. int i,pnum;
  790. g3s_point *pnt;
  791. g3s_codes cc;
  792. cc.and = 0xff; cc.or = 0;
  793. for (i=0;i<nv;i++) {
  794. pnum = pointnumlist[i];
  795. pnt = &Segment_points[pnum];
  796. if (Rotated_last[pnum] != RL_framecount) {
  797. g3_rotate_point(pnt,&Vertices[pnum]);
  798. Rotated_last[pnum] = RL_framecount;
  799. }
  800. cc.and &= pnt->p3_codes;
  801. cc.or |= pnt->p3_codes;
  802. }
  803. return cc;
  804. }
  805. //Given a lit of point numbers, project any that haven't been projected
  806. void project_list(int nv,short *pointnumlist)
  807. {
  808. int i,pnum;
  809. for (i=0;i<nv;i++) {
  810. pnum = pointnumlist[i];
  811. if (!(Segment_points[pnum].p3_flags & PF_PROJECTED))
  812. g3_project_point(&Segment_points[pnum]);
  813. }
  814. }
  815. // -----------------------------------------------------------------------------------
  816. void render_segment(int segnum)
  817. {
  818. segment *seg = &Segments[segnum];
  819. g3s_codes cc;
  820. int sn;
  821. Assert(segnum!=-1 && segnum<=Highest_segment_index);
  822. cc=rotate_list(8,&seg->verts);
  823. if (! cc.and) { //all off screen?
  824. //mprintf( (0, "!"));
  825. //DEBUG mprintf( (0, "[Segment %d: ", segnum ));
  826. // set_segment_local_light_value(segnum,INITIAL_LOCAL_LIGHT);
  827. Automap_visited[segnum]=1;
  828. for (sn=0; sn<MAX_SIDES_PER_SEGMENT; sn++)
  829. render_side(seg, sn);
  830. }
  831. //draw any objects that happen to be in this segment
  832. //sort objects!
  833. //object_sort_segment_objects( seg );
  834. #ifndef NDEBUG
  835. if (!migrate_objects) {
  836. int objnum;
  837. for (objnum=seg->objects;objnum!=-1;objnum=Objects[objnum].next)
  838. do_render_object(objnum);
  839. }
  840. #endif
  841. //DEBUG mprintf( (0, "]\n", segnum ));
  842. }
  843. // ----- This used to be called when Show_only_curside was set.
  844. // ----- It is wholly and superiorly replaced by render_side.
  845. // -- //render one side of one segment
  846. // -- void render_seg_side(segment *seg,int _side)
  847. // -- {
  848. // -- g3s_codes cc;
  849. // -- short vertnum_list[4];
  850. // --
  851. // -- cc=g3_rotate_list(8,&seg->verts);
  852. // --
  853. // -- if (! cc.and) { //all off screen?
  854. // -- int fn,pn,i;
  855. // -- side *s;
  856. // -- face *f;
  857. // -- poly *p;
  858. // --
  859. // -- s=&seg->sides[_side];
  860. // --
  861. // -- for (f=s->faces,fn=s->num_faces;fn;fn--,f++)
  862. // -- for (p=f->polys,pn=f->num_polys;pn;pn--,p++) {
  863. // -- grs_bitmap *tmap;
  864. // --
  865. // -- for (i=0;i<p->num_vertices;i++) vertnum_list[i] = seg->verts[p->verts[i]];
  866. // --
  867. // -- if (p->tmap_num >= NumTextures) {
  868. // -- Warning("Invalid tmap number %d, NumTextures=%d\n...Changing in poly structure to tmap 0",p->tmap_num,NumTextures);
  869. // -- p->tmap_num = 0; //change it permanantly
  870. // -- }
  871. // --
  872. // -- tmap = Textures[p->tmap_num];
  873. // --
  874. // -- g3_check_and_draw_tmap(p->num_vertices,vertnum_list,(g3s_uvl *) &p->uvls,tmap,&f->normal);
  875. // --
  876. // -- if (Outline_mode) draw_outline(p->num_vertices,vertnum_list);
  877. // -- }
  878. // -- }
  879. // --
  880. // -- }
  881. #define CROSS_WIDTH i2f(8)
  882. #define CROSS_HEIGHT i2f(8)
  883. #ifndef NDEBUG
  884. //draw outline for curside
  885. outline_seg_side(segment *seg,int _side,int edge,int vert)
  886. {
  887. g3s_codes cc;
  888. cc=rotate_list(8,&seg->verts);
  889. if (! cc.and) { //all off screen?
  890. side *s;
  891. g3s_point *pnt;
  892. s=&seg->sides[_side];
  893. //render curedge of curside of curseg in green
  894. gr_setcolor(BM_XRGB(0,63,0));
  895. g3_draw_line(&Segment_points[seg->verts[Side_to_verts[_side][edge]]],&Segment_points[seg->verts[Side_to_verts[_side][(edge+1)%4]]]);
  896. //draw a little cross at the current vert
  897. pnt = &Segment_points[seg->verts[Side_to_verts[_side][vert]]];
  898. g3_project_point(pnt); //make sure projected
  899. // gr_setcolor(BM_XRGB(0,0,63));
  900. // gr_line(pnt->p3_sx-CROSS_WIDTH,pnt->p3_sy,pnt->p3_sx+CROSS_WIDTH,pnt->p3_sy);
  901. // gr_line(pnt->p3_sx,pnt->p3_sy-CROSS_HEIGHT,pnt->p3_sx,pnt->p3_sy+CROSS_HEIGHT);
  902. gr_line(pnt->p3_sx-CROSS_WIDTH,pnt->p3_sy,pnt->p3_sx,pnt->p3_sy-CROSS_HEIGHT);
  903. gr_line(pnt->p3_sx,pnt->p3_sy-CROSS_HEIGHT,pnt->p3_sx+CROSS_WIDTH,pnt->p3_sy);
  904. gr_line(pnt->p3_sx+CROSS_WIDTH,pnt->p3_sy,pnt->p3_sx,pnt->p3_sy+CROSS_HEIGHT);
  905. gr_line(pnt->p3_sx,pnt->p3_sy+CROSS_HEIGHT,pnt->p3_sx-CROSS_WIDTH,pnt->p3_sy);
  906. }
  907. }
  908. #endif
  909. #if 0 //this stuff could probably just be deleted
  910. #define DEFAULT_PERSPECTIVE_DEPTH 6
  911. int Perspective_depth=DEFAULT_PERSPECTIVE_DEPTH; //how many levels deep to render in perspective
  912. int inc_perspective_depth(void)
  913. {
  914. return ++Perspective_depth;
  915. }
  916. int dec_perspective_depth(void)
  917. {
  918. return Perspective_depth==1?Perspective_depth:--Perspective_depth;
  919. }
  920. int reset_perspective_depth(void)
  921. {
  922. return Perspective_depth = DEFAULT_PERSPECTIVE_DEPTH;
  923. }
  924. #endif
  925. typedef struct window {
  926. short left,top,right,bot;
  927. } window;
  928. ubyte code_window_point(fix x,fix y,window *w)
  929. {
  930. ubyte code=0;
  931. if (x <= w->left) code |= 1;
  932. if (x >= w->right) code |= 2;
  933. if (y <= w->top) code |= 4;
  934. if (y >= w->bot) code |= 8;
  935. return code;
  936. }
  937. #ifndef NDEBUG
  938. draw_window_box(int color,short left,short top,short right,short bot)
  939. {
  940. short l,t,r,b;
  941. gr_setcolor(color);
  942. l=left; t=top; r=right; b=bot;
  943. if ( r<0 || b<0 || l>=grd_curcanv->cv_bitmap.bm_w || t>=grd_curcanv->cv_bitmap.bm_h && b>=grd_curcanv->cv_bitmap.bm_h)
  944. return;
  945. if (l<0) l=0;
  946. if (t<0) t=0;
  947. if (r>=grd_curcanv->cv_bitmap.bm_w) r=grd_curcanv->cv_bitmap.bm_w-1;
  948. if (b>=grd_curcanv->cv_bitmap.bm_h) b=grd_curcanv->cv_bitmap.bm_h-1;
  949. gr_line(i2f(l),i2f(t),i2f(r),i2f(t));
  950. gr_line(i2f(r),i2f(t),i2f(r),i2f(b));
  951. gr_line(i2f(r),i2f(b),i2f(l),i2f(b));
  952. gr_line(i2f(l),i2f(b),i2f(l),i2f(t));
  953. }
  954. #endif
  955. int matt_find_connect_side(int seg0,int seg1);
  956. #ifndef NDEBUG
  957. char visited2[MAX_SEGMENTS];
  958. #endif
  959. char visited[MAX_SEGMENTS];
  960. short Render_list[MAX_RENDER_SEGS];
  961. short Seg_depth[MAX_RENDER_SEGS]; //depth for each seg in Render_list
  962. ubyte processed[MAX_RENDER_SEGS]; //whether each entry has been processed
  963. int lcnt_save,scnt_save;
  964. //@@short *persp_ptr;
  965. short render_pos[MAX_SEGMENTS]; //where in render_list does this segment appear?
  966. //ubyte no_render_flag[MAX_RENDER_SEGS];
  967. window render_windows[MAX_RENDER_SEGS];
  968. short render_obj_list[MAX_RENDER_SEGS+N_EXTRA_OBJ_LISTS][OBJS_PER_SEG];
  969. //for objects
  970. #define RED BM_XRGB(63,0,0)
  971. #define WHITE BM_XRGB(63,63,63)
  972. //Global vars for window clip test
  973. int Window_clip_left,Window_clip_top,Window_clip_right,Window_clip_bot;
  974. //Given two sides of segment, tell the two verts which form the
  975. //edge between them
  976. Two_sides_to_edge[6][6][2] = {
  977. { {-1,-1}, {3,7}, {-1,-1}, {2,6}, {6,7}, {2,3} },
  978. { {3,7}, {-1,-1}, {0,4}, {-1,-1}, {4,7}, {0,3} },
  979. { {-1,-1}, {0,4}, {-1,-1}, {1,5}, {4,5}, {0,1} },
  980. { {2,6}, {-1,-1}, {1,5}, {-1,-1}, {5,6}, {1,2} },
  981. { {6,7}, {4,7}, {4,5}, {5,6}, {-1,-1}, {-1,-1} },
  982. { {2,3}, {0,3}, {0,1}, {1,2}, {-1,-1}, {-1,-1} }
  983. };
  984. //given an edge specified by two verts, give the two sides on that edge
  985. Edge_to_sides[8][8][2] = {
  986. { {-1,-1}, {2,5}, {-1,-1}, {1,5}, {1,2}, {-1,-1}, {-1,-1}, {-1,-1} },
  987. { {2,5}, {-1,-1}, {3,5}, {-1,-1}, {-1,-1}, {2,3}, {-1,-1}, {-1,-1} },
  988. { {-1,-1}, {3,5}, {-1,-1}, {0,5}, {-1,-1}, {-1,-1}, {0,3}, {-1,-1} },
  989. { {1,5}, {-1,-1}, {0,5}, {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, {0,1} },
  990. { {1,2}, {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, {2,4}, {-1,-1}, {1,4} },
  991. { {-1,-1}, {2,3}, {-1,-1}, {-1,-1}, {2,4}, {-1,-1}, {3,4}, {-1,-1} },
  992. { {-1,-1}, {-1,-1}, {0,3}, {-1,-1}, {-1,-1}, {3,4}, {-1,-1}, {0,4} },
  993. { {-1,-1}, {-1,-1}, {-1,-1}, {0,1}, {1,4}, {-1,-1}, {0,4}, {-1,-1} },
  994. };
  995. //@@//perform simple check on tables
  996. //@@check_check()
  997. //@@{
  998. //@@ int i,j;
  999. //@@
  1000. //@@ for (i=0;i<8;i++)
  1001. //@@ for (j=0;j<8;j++)
  1002. //@@ Assert(Edge_to_sides[i][j][0] == Edge_to_sides[j][i][0] &&
  1003. //@@ Edge_to_sides[i][j][1] == Edge_to_sides[j][i][1]);
  1004. //@@
  1005. //@@ for (i=0;i<6;i++)
  1006. //@@ for (j=0;j<6;j++)
  1007. //@@ Assert(Two_sides_to_edge[i][j][0] == Two_sides_to_edge[j][i][0] &&
  1008. //@@ Two_sides_to_edge[i][j][1] == Two_sides_to_edge[j][i][1]);
  1009. //@@
  1010. //@@
  1011. //@@}
  1012. //given an edge, tell what side is on that edge
  1013. find_seg_side(segment *seg,short *verts,int notside)
  1014. {
  1015. int i;
  1016. int vv0=-1,vv1=-1;
  1017. int side0,side1;
  1018. int *eptr;
  1019. int v0,v1;
  1020. short *vp;
  1021. //@@ check_check();
  1022. v0 = verts[0];
  1023. v1 = verts[1];
  1024. vp = seg->verts;
  1025. for (i=0; i<8; i++) {
  1026. int svv = *vp++; // seg->verts[i];
  1027. if (vv0==-1 && svv == v0) {
  1028. vv0 = i;
  1029. if (vv1 != -1)
  1030. break;
  1031. }
  1032. if (vv1==-1 && svv == v1) {
  1033. vv1 = i;
  1034. if (vv0 != -1)
  1035. break;
  1036. }
  1037. }
  1038. Assert(vv0!=-1 && vv1!=-1);
  1039. eptr = Edge_to_sides[vv0][vv1];
  1040. side0 = eptr[0];
  1041. side1 = eptr[1];
  1042. Assert(side0!=-1 && side1!=-1);
  1043. if (side0 != notside) {
  1044. Assert(side1==notside);
  1045. return side0;
  1046. }
  1047. else {
  1048. Assert(side0==notside);
  1049. return side1;
  1050. }
  1051. }
  1052. //find the two segments that join a given seg though two sides, and
  1053. //the sides of those segments the abut.
  1054. find_joining_side_norms(vms_vector *norm0_0,vms_vector *norm0_1,vms_vector *norm1_0,vms_vector *norm1_1,vms_vector **pnt0,vms_vector **pnt1,segment *seg,int s0,int s1)
  1055. {
  1056. segment *seg0,*seg1;
  1057. short edge_verts[2];
  1058. int notside0,notside1;
  1059. int edgeside0,edgeside1;
  1060. Assert(s0!=-1 && s1!=-1);
  1061. seg0 = &Segments[seg->children[s0]];
  1062. seg1 = &Segments[seg->children[s1]];
  1063. edge_verts[0] = seg->verts[Two_sides_to_edge[s0][s1][0]];
  1064. edge_verts[1] = seg->verts[Two_sides_to_edge[s0][s1][1]];
  1065. Assert(edge_verts[0]!=-1 && edge_verts[1]!=-1);
  1066. notside0 = find_connect_side(seg,seg0);
  1067. Assert(notside0 != -1);
  1068. notside1 = find_connect_side(seg,seg1);
  1069. Assert(notside1 != -1);
  1070. edgeside0 = find_seg_side(seg0,edge_verts,notside0);
  1071. edgeside1 = find_seg_side(seg1,edge_verts,notside1);
  1072. //deal with the case where an edge is shared by more than two segments
  1073. //@@ if (IS_CHILD(seg0->children[edgeside0])) {
  1074. //@@ segment *seg00;
  1075. //@@ int notside00;
  1076. //@@
  1077. //@@ seg00 = &Segments[seg0->children[edgeside0]];
  1078. //@@
  1079. //@@ if (seg00 != seg1) {
  1080. //@@
  1081. //@@ notside00 = find_connect_side(seg0,seg00);
  1082. //@@ Assert(notside00 != -1);
  1083. //@@
  1084. //@@ edgeside0 = find_seg_side(seg00,edge_verts,notside00);
  1085. //@@ seg0 = seg00;
  1086. //@@ }
  1087. //@@
  1088. //@@ }
  1089. //@@
  1090. //@@ if (IS_CHILD(seg1->children[edgeside1])) {
  1091. //@@ segment *seg11;
  1092. //@@ int notside11;
  1093. //@@
  1094. //@@ seg11 = &Segments[seg1->children[edgeside1]];
  1095. //@@
  1096. //@@ if (seg11 != seg0) {
  1097. //@@ notside11 = find_connect_side(seg1,seg11);
  1098. //@@ Assert(notside11 != -1);
  1099. //@@
  1100. //@@ edgeside1 = find_seg_side(seg11,edge_verts,notside11);
  1101. //@@ seg1 = seg11;
  1102. //@@ }
  1103. //@@ }
  1104. // if ( IS_CHILD(seg0->children[edgeside0]) ||
  1105. // IS_CHILD(seg1->children[edgeside1]))
  1106. // return 0;
  1107. #ifdef COMPACT_SEGS
  1108. get_side_normals(seg0, edgeside0, norm0_0, norm0_1 );
  1109. get_side_normals(seg1, edgeside1, norm1_0, norm1_1 );
  1110. #else
  1111. *norm0_0 = seg0->sides[edgeside0].normals[0];
  1112. *norm0_1 = seg0->sides[edgeside0].normals[1];
  1113. *norm1_0 = seg1->sides[edgeside1].normals[0];
  1114. *norm1_1 = seg1->sides[edgeside1].normals[1];
  1115. #endif
  1116. *pnt0 = &Vertices[seg0->verts[Side_to_verts[edgeside0][seg0->sides[edgeside0].type==3?1:0]]];
  1117. *pnt1 = &Vertices[seg1->verts[Side_to_verts[edgeside1][seg1->sides[edgeside1].type==3?1:0]]];
  1118. return 1;
  1119. }
  1120. //see if the order matters for these two children.
  1121. //returns 0 if order doesn't matter, 1 if c0 before c1, -1 if c1 before c0
  1122. compare_children(segment *seg,short c0,short c1)
  1123. {
  1124. vms_vector norm0_0,norm0_1,*pnt0,temp;
  1125. vms_vector norm1_0,norm1_1,*pnt1;
  1126. fix d0_0,d0_1,d1_0,d1_1,d0,d1;
  1127. int t;
  1128. if (Side_opposite[c0] == c1) return 0;
  1129. Assert(c0!=-1 && c1!=-1);
  1130. //find normals of adjoining sides
  1131. t = find_joining_side_norms(&norm0_0,&norm0_1,&norm1_0,&norm1_1,&pnt0,&pnt1,seg,c0,c1);
  1132. //if (!t)
  1133. // return 0;
  1134. vm_vec_sub(&temp,&Viewer_eye,pnt0);
  1135. d0_0 = vm_vec_dot(&norm0_0,&temp);
  1136. d0_1 = vm_vec_dot(&norm0_1,&temp);
  1137. vm_vec_sub(&temp,&Viewer_eye,pnt1);
  1138. d1_0 = vm_vec_dot(&norm1_0,&temp);
  1139. d1_1 = vm_vec_dot(&norm1_1,&temp);
  1140. d0 = (d0_0 < 0 || d0_1 < 0)?-1:1;
  1141. d1 = (d1_0 < 0 || d1_1 < 0)?-1:1;
  1142. if (d0 < 0 && d1 < 0)
  1143. return 0;
  1144. if (d0 < 0)
  1145. return 1;
  1146. else if (d1 < 0)
  1147. return -1;
  1148. else
  1149. return 0;
  1150. }
  1151. int ssc_total=0,ssc_swaps=0;
  1152. //short the children of segment to render in the correct order
  1153. //returns non-zero if swaps were made
  1154. int sort_seg_children(segment *seg,int n_children,short *child_list)
  1155. {
  1156. int i,j;
  1157. int r;
  1158. int made_swaps,count;
  1159. if (n_children == 0) return 0;
  1160. ssc_total++;
  1161. //for each child, compare with other children and see if order matters
  1162. //if order matters, fix if wrong
  1163. count = 0;
  1164. do {
  1165. made_swaps = 0;
  1166. for (i=0;i<n_children-1;i++)
  1167. for (j=i+1;child_list[i]!=-1 && j<n_children;j++)
  1168. if (child_list[j]!=-1) {
  1169. r = compare_children(seg,child_list[i],child_list[j]);
  1170. if (r == 1) {
  1171. int temp = child_list[i];
  1172. child_list[i] = child_list[j];
  1173. child_list[j] = temp;
  1174. made_swaps=1;
  1175. }
  1176. }
  1177. } while (made_swaps && ++count<n_children);
  1178. if (count)
  1179. ssc_swaps++;
  1180. return count;
  1181. }
  1182. add_obj_to_seglist(int objnum,int listnum)
  1183. {
  1184. int i,checkn,marker;
  1185. checkn = listnum;
  1186. //first, find a slot
  1187. //mprintf((0,"adding obj %d to %d",objnum,listnum));
  1188. do {
  1189. for (i=0;render_obj_list[checkn][i] >= 0;i++);
  1190. Assert(i < OBJS_PER_SEG);
  1191. marker = render_obj_list[checkn][i];
  1192. if (marker != -1) {
  1193. checkn = -marker;
  1194. //Assert(checkn < MAX_RENDER_SEGS+N_EXTRA_OBJ_LISTS);
  1195. if (checkn >= MAX_RENDER_SEGS+N_EXTRA_OBJ_LISTS) {
  1196. Int3();
  1197. return;
  1198. }
  1199. }
  1200. } while (marker != -1);
  1201. //mprintf((0," slot %d,%d",checkn,i));
  1202. //now we have found a slot. put object in it
  1203. if (i != OBJS_PER_SEG-1) {
  1204. render_obj_list[checkn][i] = objnum;
  1205. render_obj_list[checkn][i+1] = -1;
  1206. }
  1207. else { //chain to additional list
  1208. int lookn;
  1209. //find an available sublist
  1210. for (lookn=MAX_RENDER_SEGS;render_obj_list[lookn][0]!=-1 && lookn<MAX_RENDER_SEGS+N_EXTRA_OBJ_LISTS;lookn++);
  1211. //Assert(lookn<MAX_RENDER_SEGS+N_EXTRA_OBJ_LISTS);
  1212. if (lookn >= MAX_RENDER_SEGS+N_EXTRA_OBJ_LISTS) {
  1213. Int3();
  1214. return;
  1215. }
  1216. render_obj_list[checkn][i] = -lookn;
  1217. render_obj_list[lookn][0] = objnum;
  1218. render_obj_list[lookn][1] = -1;
  1219. }
  1220. //mprintf((0," added!\n"));
  1221. }
  1222. #define SORT_LIST_SIZE 50
  1223. typedef struct sort_item {
  1224. int objnum;
  1225. fix dist;
  1226. } sort_item;
  1227. sort_item sort_list[SORT_LIST_SIZE];
  1228. int n_sort_items;
  1229. //compare function for object sort.
  1230. int sort_func(sort_item *a,sort_item *b)
  1231. {
  1232. fix delta_dist;
  1233. object *obj_a,*obj_b;
  1234. delta_dist = a->dist - b->dist;
  1235. obj_a = &Objects[a->objnum];
  1236. obj_b = &Objects[b->objnum];
  1237. if (abs(delta_dist) < (obj_a->size + obj_b->size)) { //same position
  1238. //these two objects are in the same position. see if one is a fireball
  1239. //or laser or something that should plot on top
  1240. if (obj_a->type == OBJ_WEAPON || obj_a->type == OBJ_FIREBALL)
  1241. if (!(obj_b->type == OBJ_WEAPON || obj_b->type == OBJ_FIREBALL))
  1242. return -1; //a is weapon, b is not, so say a is closer
  1243. else; //both are weapons
  1244. else
  1245. if (obj_b->type == OBJ_WEAPON || obj_b->type == OBJ_FIREBALL)
  1246. return 1; //b is weapon, a is not, so say a is farther
  1247. //no special case, fall through to normal return
  1248. }
  1249. return delta_dist; //return distance
  1250. }
  1251. build_object_lists(int n_segs)
  1252. {
  1253. int nn;
  1254. //mprintf((0,"build n_segs=%d",n_segs));
  1255. for (nn=0;nn<MAX_RENDER_SEGS+N_EXTRA_OBJ_LISTS;nn++)
  1256. render_obj_list[nn][0] = -1;
  1257. for (nn=0;nn<n_segs;nn++) {
  1258. int segnum;
  1259. segnum = Render_list[nn];
  1260. //mprintf((0,"nn=%d seg=%d ",nn,segnum));
  1261. if (segnum != -1) {
  1262. int objnum;
  1263. object *obj;
  1264. for (objnum=Segments[segnum].objects;objnum!=-1;objnum = obj->next) {
  1265. int new_segnum,did_migrate,list_pos;
  1266. obj = &Objects[objnum];
  1267. Assert( obj->segnum == segnum );
  1268. if (obj->flags & OF_ATTACHED)
  1269. continue; //ignore this object
  1270. new_segnum = segnum;
  1271. list_pos = nn;
  1272. //mprintf((0,"objnum=%d ",objnum));
  1273. if (obj->type != OBJ_CNTRLCEN) //don't migrate controlcen
  1274. do {
  1275. segmasks m;
  1276. did_migrate = 0;
  1277. m = get_seg_masks(&obj->pos,new_segnum,obj->size);
  1278. if (m.sidemask) {
  1279. int sn,sf;
  1280. for (sn=0,sf=1;sn<6;sn++,sf<<=1)
  1281. if (m.sidemask & sf) {
  1282. segment *seg = &Segments[obj->segnum];
  1283. if (WALL_IS_DOORWAY(seg,sn) & WID_FLY_FLAG) { //can explosion migrate through
  1284. int child = seg->children[sn];
  1285. int checknp;
  1286. for (checknp=list_pos;checknp--;)
  1287. if (Render_list[checknp] == child) {
  1288. //mprintf((0,"mig from %d to %d ",new_segnum,child));
  1289. new_segnum = child;
  1290. list_pos = checknp;
  1291. did_migrate = 1;
  1292. }
  1293. }
  1294. }
  1295. }
  1296. } while (did_migrate);
  1297. add_obj_to_seglist(objnum,list_pos);
  1298. }
  1299. }
  1300. }
  1301. //mprintf((0,"done build "));
  1302. //now that there's a list for each segment, sort the items in those lists
  1303. for (nn=0;nn<n_segs;nn++) {
  1304. int segnum;
  1305. segnum = Render_list[nn];
  1306. //mprintf((0,"nn=%d seg=%d ",nn,segnum));
  1307. if (segnum != -1) {
  1308. int t,lookn,i,n;
  1309. //first count the number of objects & copy into sort list
  1310. lookn = nn;
  1311. i = n_sort_items = 0;
  1312. while ((t=render_obj_list[lookn][i++])!=-1)
  1313. if (t<0)
  1314. {lookn = -t; i=0;}
  1315. else
  1316. if (n_sort_items < SORT_LIST_SIZE-1) { //add if room
  1317. sort_list[n_sort_items].objnum = t;
  1318. //NOTE: maybe use depth, not dist - quicker computation
  1319. sort_list[n_sort_items].dist = vm_vec_dist_quick(&Objects[t].pos,&Viewer_eye);
  1320. n_sort_items++;
  1321. }
  1322. //now call qsort
  1323. qsort(sort_list,n_sort_items,sizeof(*sort_list),sort_func);
  1324. //now copy back into list
  1325. lookn = nn;
  1326. i = 0;
  1327. n = n_sort_items;
  1328. while ((t=render_obj_list[lookn][i])!=-1 && n>0)
  1329. if (t<0)
  1330. {lookn = -t; i=0;}
  1331. else
  1332. render_obj_list[lookn][i++] = sort_list[--n].objnum;
  1333. render_obj_list[lookn][i] = -1; //mark (possibly new) end
  1334. }
  1335. }
  1336. }
  1337. int Use_player_head_angles = 0;
  1338. vms_angvec Player_head_angles;
  1339. extern int Num_tmaps_drawn;
  1340. extern int Total_pixels;
  1341. //--unused-- int Total_num_tmaps_drawn=0;
  1342. int Rear_view=0;
  1343. #ifdef JOHN_ZOOM
  1344. fix Zoom_factor=F1_0;
  1345. #endif
  1346. //renders onto current canvas
  1347. void render_frame(fix eye_offset)
  1348. {
  1349. int start_seg_num;
  1350. //Total_num_tmaps_drawn += Num_tmaps_drawn;
  1351. //if ((FrameCount > 0) && (Total_num_tmaps_drawn))
  1352. // mprintf((0, "Frame: %4i, total = %6i, Avg = %7.3f, Avgpix=%7.3f\n", Num_tmaps_drawn, Total_num_tmaps_drawn, (float) Total_num_tmaps_drawn/FrameCount, (float) Total_pixels/Total_num_tmaps_drawn));
  1353. //Num_tmaps_drawn = 0;
  1354. if (Endlevel_sequence) {
  1355. render_endlevel_frame(eye_offset);
  1356. FrameCount++;
  1357. return;
  1358. }
  1359. #ifdef NEWDEMO
  1360. if ( Newdemo_state == ND_STATE_RECORDING ) {
  1361. if (eye_offset >= 0 ) {
  1362. newdemo_record_start_frame(FrameCount, FrameTime );
  1363. newdemo_record_viewer_object(Viewer);
  1364. }
  1365. }
  1366. #endif
  1367. g3_start_frame();
  1368. Viewer_eye = Viewer->pos;
  1369. // if (Viewer->type == OBJ_PLAYER && (Cockpit_mode!=CM_REAR_VIEW))
  1370. // vm_vec_scale_add2(&Viewer_eye,&Viewer->orient.fvec,(Viewer->size*3)/4);
  1371. if (eye_offset) {
  1372. vm_vec_scale_add2(&Viewer_eye,&Viewer->orient.rvec,eye_offset);
  1373. }
  1374. #ifdef EDITOR
  1375. if (Function_mode==FMODE_EDITOR)
  1376. Viewer_eye = Viewer->pos;
  1377. #endif
  1378. start_seg_num = find_point_seg(&Viewer_eye,Viewer->segnum);
  1379. if (start_seg_num==-1)
  1380. start_seg_num = Viewer->segnum;
  1381. if (Viewer==ConsoleObject && Use_player_head_angles) {
  1382. vms_matrix headm,viewm;
  1383. vm_angles_2_matrix(&headm,&Player_head_angles);
  1384. vm_matrix_x_matrix(&viewm,&Viewer->orient,&headm);
  1385. g3_set_view_matrix(&Viewer_eye,&viewm,Render_zoom);
  1386. //@@} else if ((Cockpit_mode==CM_REAR_VIEW) && (Viewer==ConsoleObject)) {
  1387. } else if (Rear_view && (Viewer==ConsoleObject)) {
  1388. vms_matrix headm,viewm;
  1389. Player_head_angles.p = Player_head_angles.b = 0;
  1390. Player_head_angles.h = 0x7fff;
  1391. vm_angles_2_matrix(&headm,&Player_head_angles);
  1392. vm_matrix_x_matrix(&viewm,&Viewer->orient,&headm);
  1393. g3_set_view_matrix(&Viewer_eye,&viewm,Render_zoom);
  1394. } else {
  1395. #ifdef JOHN_ZOOM
  1396. if (keyd_pressed[KEY_RSHIFT] ) {
  1397. Zoom_factor += FrameTime*4;
  1398. if (Zoom_factor > F1_0*5 ) Zoom_factor=F1_0*5;
  1399. } else {
  1400. Zoom_factor -= FrameTime*4;
  1401. if (Zoom_factor < F1_0 ) Zoom_factor = F1_0;
  1402. }
  1403. g3_set_view_matrix(&Viewer_eye,&Viewer->orient,fixdiv(Render_zoom,Zoom_factor));
  1404. #else
  1405. g3_set_view_matrix(&Viewer_eye,&Viewer->orient,Render_zoom);
  1406. #endif
  1407. }
  1408. if (Clear_window == 1) {
  1409. if (Clear_window_color == -1)
  1410. Clear_window_color = BM_XRGB(0, 0, 0); //BM_XRGB(31, 15, 7);
  1411. gr_clear_canvas(Clear_window_color);
  1412. }
  1413. render_mine(start_seg_num,eye_offset);
  1414. if (Use_player_head_angles )
  1415. draw_3d_reticle(eye_offset);
  1416. g3_end_frame();
  1417. FrameCount++; //we have rendered a frame
  1418. }
  1419. int first_terminal_seg;
  1420. //build a list of segments to be rendered
  1421. //fills in Render_list & N_render_segs
  1422. build_segment_list(int start_seg_num)
  1423. {
  1424. int lcnt,scnt,ecnt;
  1425. int l,c;
  1426. int ch;
  1427. memset(visited, 0, sizeof(visited[0])*(Highest_segment_index+1));
  1428. memset(render_pos, -1, sizeof(render_pos[0])*(Highest_segment_index+1));
  1429. //memset(no_render_flag, 0, sizeof(no_render_flag[0])*(MAX_RENDER_SEGS));
  1430. memset(processed, 0, sizeof(processed));
  1431. #ifndef NDEBUG
  1432. memset(visited2, 0, sizeof(visited2[0])*(Highest_segment_index+1));
  1433. #endif
  1434. lcnt = scnt = 0;
  1435. Render_list[lcnt] = start_seg_num; visited[start_seg_num]=1;
  1436. Seg_depth[lcnt] = 0;
  1437. lcnt++;
  1438. ecnt = lcnt;
  1439. render_pos[start_seg_num] = 0;
  1440. #ifndef NDEBUG
  1441. if (pre_draw_segs)
  1442. render_segment(start_seg_num);
  1443. #endif
  1444. render_windows[0].left=render_windows[0].top=0;
  1445. render_windows[0].right=grd_curcanv->cv_bitmap.bm_w-1;
  1446. render_windows[0].bot=grd_curcanv->cv_bitmap.bm_h-1;
  1447. //breadth-first renderer
  1448. //build list
  1449. for (l=0;l<Render_depth;l++) {
  1450. //while (scnt < ecnt) {
  1451. for (scnt=0;scnt < ecnt;scnt++) {
  1452. int rotated,segnum;
  1453. window *check_w;
  1454. short child_list[MAX_SIDES_PER_SEGMENT]; //list of ordered sides to process
  1455. int n_children; //how many sides in child_list
  1456. segment *seg;
  1457. if (processed[scnt])
  1458. continue;
  1459. processed[scnt]=1;
  1460. segnum = Render_list[scnt];
  1461. check_w = &render_windows[scnt];
  1462. #ifndef NDEBUG
  1463. if (draw_boxes)
  1464. draw_window_box(RED,check_w->left,check_w->top,check_w->right,check_w->bot);
  1465. #endif
  1466. if (segnum == -1) continue;
  1467. seg = &Segments[segnum];
  1468. rotated=0;
  1469. //look at all sides of this segment.
  1470. //tricky code to look at sides in correct order follows
  1471. for (c=n_children=0;c<MAX_SIDES_PER_SEGMENT;c++) { //build list of sides
  1472. int wid;
  1473. wid = WALL_IS_DOORWAY(seg, c);
  1474. ch=seg->children[c];
  1475. if ( (window_check || !visited[ch]) && (wid & WID_RENDPAST_FLAG) ) {
  1476. if (behind_check) {
  1477. byte *sv = Side_to_verts[c];
  1478. ubyte codes_and=0xff;
  1479. int i;
  1480. rotate_list(8,&seg->verts);
  1481. rotated=1;
  1482. for (i=0;i<4;i++)
  1483. codes_and &= Segment_points[seg->verts[sv[i]]].p3_codes;
  1484. if (codes_and & CC_BEHIND) continue;
  1485. }
  1486. child_list[n_children++] = c;
  1487. }
  1488. }
  1489. //now order the sides in some magical way
  1490. if (new_seg_sorting)
  1491. sort_seg_children(seg,n_children,child_list);
  1492. //for (c=0;c<MAX_SIDES_PER_SEGMENT;c++) {
  1493. // ch=seg->children[c];
  1494. for (c=0;c<n_children;c++) {
  1495. int siden;
  1496. siden = child_list[c];
  1497. ch=seg->children[siden];
  1498. //if ( (window_check || !visited[ch])&& (WALL_IS_DOORWAY(seg, c))) {
  1499. {
  1500. if (window_check) {
  1501. int i;
  1502. ubyte codes_and_3d,codes_and_2d;
  1503. short _x,_y,min_x=32767,max_x=-32767,min_y=32767,max_y=-32767;
  1504. int no_proj_flag=0; //a point wasn't projected
  1505. if (rotated<2) {
  1506. if (!rotated)
  1507. rotate_list(8,&seg->verts);
  1508. project_list(8,&seg->verts);
  1509. rotated=2;
  1510. }
  1511. for (i=0,codes_and_3d=codes_and_2d=0xff;i<4;i++) {
  1512. int p = seg->verts[Side_to_verts[siden][i]];
  1513. g3s_point *pnt = &Segment_points[p];
  1514. if (! (pnt->p3_flags&PF_PROJECTED)) {no_proj_flag=1; break;}
  1515. _x = f2i(pnt->p3_sx);
  1516. _y = f2i(pnt->p3_sy);
  1517. codes_and_3d &= pnt->p3_codes;
  1518. codes_and_2d &= code_window_point(_x,_y,check_w);
  1519. #ifndef NDEBUG
  1520. if (draw_edges) {
  1521. gr_setcolor(BM_XRGB(31,0,31));
  1522. gr_line(pnt->p3_sx,pnt->p3_sy,
  1523. Segment_points[seg->verts[Side_to_verts[siden][(i+1)%4]]].p3_sx,
  1524. Segment_points[seg->verts[Side_to_verts[siden][(i+1)%4]]].p3_sy);
  1525. }
  1526. #endif
  1527. if (_x < min_x) min_x = _x;
  1528. if (_x > max_x) max_x = _x;
  1529. if (_y < min_y) min_y = _y;
  1530. if (_y > max_y) max_y = _y;
  1531. }
  1532. #ifndef NDEBUG
  1533. if (draw_boxes)
  1534. draw_window_box(WHITE,min_x,min_y,max_x,max_y);
  1535. #endif
  1536. if (no_proj_flag || (!codes_and_3d && !codes_and_2d)) { //maybe add this segment
  1537. int rp = render_pos[ch];
  1538. window *new_w = &render_windows[lcnt];
  1539. if (no_proj_flag) *new_w = *check_w;
  1540. else {
  1541. new_w->left = max(check_w->left,min_x);
  1542. new_w->right = min(check_w->right,max_x);
  1543. new_w->top = max(check_w->top,min_y);
  1544. new_w->bot = min(check_w->bot,max_y);
  1545. }
  1546. //see if this seg already visited, and if so, does current window
  1547. //expand the old window?
  1548. if (rp != -1) {
  1549. if (new_w->left < render_windows[rp].left ||
  1550. new_w->top < render_windows[rp].top ||
  1551. new_w->right > render_windows[rp].right ||
  1552. new_w->bot > render_windows[rp].bot) {
  1553. new_w->left = min(new_w->left,render_windows[rp].left);
  1554. new_w->right = max(new_w->right,render_windows[rp].right);
  1555. new_w->top = min(new_w->top,render_windows[rp].top);
  1556. new_w->bot = max(new_w->bot,render_windows[rp].bot);
  1557. if (no_migrate_segs) {
  1558. //no_render_flag[lcnt] = 1;
  1559. Render_list[lcnt] = -1;
  1560. render_windows[rp] = *new_w; //get updated window
  1561. processed[rp] = 0; //force reprocess
  1562. goto no_add;
  1563. }
  1564. else
  1565. Render_list[rp]=-1;
  1566. }
  1567. else goto no_add;
  1568. }
  1569. #ifndef NDEBUG
  1570. if (draw_boxes)
  1571. draw_window_box(5,new_w->left,new_w->top,new_w->right,new_w->bot);
  1572. #endif
  1573. render_pos[ch] = lcnt;
  1574. Render_list[lcnt] = ch;
  1575. Seg_depth[lcnt] = l;
  1576. lcnt++;
  1577. if (lcnt >= MAX_RENDER_SEGS) {mprintf((0,"Too many segs in render list!!\n")); goto done_list;}
  1578. visited[ch] = 1;
  1579. #ifndef NDEBUG
  1580. if (pre_draw_segs)
  1581. render_segment(ch);
  1582. #endif
  1583. no_add:
  1584. ;
  1585. }
  1586. }
  1587. else {
  1588. Render_list[lcnt] = ch;
  1589. Seg_depth[lcnt] = l;
  1590. lcnt++;
  1591. if (lcnt >= MAX_RENDER_SEGS) {mprintf((0,"Too many segs in render list!!\n")); goto done_list;}
  1592. visited[ch] = 1;
  1593. }
  1594. }
  1595. }
  1596. }
  1597. scnt = ecnt;
  1598. ecnt = lcnt;
  1599. }
  1600. done_list:
  1601. lcnt_save = lcnt;
  1602. scnt_save = scnt;
  1603. first_terminal_seg = scnt;
  1604. N_render_segs = lcnt;
  1605. }
  1606. //renders onto current canvas
  1607. void render_mine(int start_seg_num,fix eye_offset)
  1608. {
  1609. int i;
  1610. int nn;
  1611. // Initialize number of objects (actually, robots!) rendered this frame.
  1612. Num_rendered_objects = 0;
  1613. #ifdef LASER_HACK
  1614. Hack_nlasers = 0;
  1615. #endif
  1616. #ifndef NDEBUG
  1617. for (i=0;i<=Highest_object_index;i++)
  1618. object_rendered[i] = 0;
  1619. #endif
  1620. //set up for rendering
  1621. render_start_frame();
  1622. #if defined(EDITOR) && !defined(NDEUBG)
  1623. if (Show_only_curside) {
  1624. rotate_list(8,&Cursegp->verts);
  1625. render_side(Cursegp,Curside);
  1626. goto done_rendering;
  1627. }
  1628. #endif
  1629. #ifdef EDITOR
  1630. if (_search_mode || eye_offset>0) {
  1631. //lcnt = lcnt_save;
  1632. //scnt = scnt_save;
  1633. }
  1634. else
  1635. #endif
  1636. //NOTE LINK TO ABOVE!!
  1637. build_segment_list(start_seg_num); //fills in Render_list & N_render_segs
  1638. //render away
  1639. #ifndef NDEBUG
  1640. if (!window_check) {
  1641. Window_clip_left = Window_clip_top = 0;
  1642. Window_clip_right = grd_curcanv->cv_bitmap.bm_w-1;
  1643. Window_clip_bot = grd_curcanv->cv_bitmap.bm_h-1;
  1644. }
  1645. #endif
  1646. #ifndef NDEBUG
  1647. if (!(_search_mode || eye_offset>0)) {
  1648. int i;
  1649. for (i=0;i<N_render_segs;i++) {
  1650. int segnum;
  1651. segnum = Render_list[i];
  1652. if (segnum != -1)
  1653. if (visited2[segnum])
  1654. Int3(); //get Matt
  1655. else
  1656. visited2[segnum] = 1;
  1657. }
  1658. }
  1659. #endif
  1660. // if (!(_search_mode || eye_offset>0) && migrate_objects)
  1661. if (!(_search_mode))
  1662. build_object_lists(N_render_segs);
  1663. if (eye_offset<=0) // Do for left eye or zero.
  1664. set_dynamic_light();
  1665. if (!_search_mode && Clear_window == 2) {
  1666. if (first_terminal_seg < N_render_segs) {
  1667. int i;
  1668. if (Clear_window_color == -1)
  1669. Clear_window_color = BM_XRGB(0, 0, 0); //BM_XRGB(31, 15, 7);
  1670. gr_setcolor(Clear_window_color);
  1671. for (i=first_terminal_seg; i<N_render_segs; i++) {
  1672. if (Render_list[i] != -1) {
  1673. #ifndef NDEBUG
  1674. if ((render_windows[i].left == -1) || (render_windows[i].top == -1) || (render_windows[i].right == -1) || (render_windows[i].bot == -1))
  1675. Int3();
  1676. else
  1677. #endif
  1678. //NOTE LINK TO ABOVE!
  1679. gr_rect(render_windows[i].left, render_windows[i].top, render_windows[i].right, render_windows[i].bot);
  1680. }
  1681. }
  1682. }
  1683. }
  1684. for (nn=N_render_segs;nn--;) {
  1685. int segnum;
  1686. int objnp;
  1687. // Interpolation_method = 0;
  1688. segnum = Render_list[nn];
  1689. Current_seg_depth = Seg_depth[nn];
  1690. //if (!no_render_flag[nn])
  1691. if (segnum!=-1 && (_search_mode || eye_offset>0 || visited[segnum]!=255)) {
  1692. //set global render window vars
  1693. if (window_check) {
  1694. Window_clip_left = render_windows[nn].left;
  1695. Window_clip_top = render_windows[nn].top;
  1696. Window_clip_right = render_windows[nn].right;
  1697. Window_clip_bot = render_windows[nn].bot;
  1698. }
  1699. //mprintf((0," %d",segnum));
  1700. render_segment(segnum);
  1701. visited[segnum]=255;
  1702. if (window_check) { //reset for objects
  1703. Window_clip_left = Window_clip_top = 0;
  1704. Window_clip_right = grd_curcanv->cv_bitmap.bm_w-1;
  1705. Window_clip_bot = grd_curcanv->cv_bitmap.bm_h-1;
  1706. }
  1707. if (migrate_objects) {
  1708. //int n_expl_objs=0,expl_objs[5],i;
  1709. int listnum;
  1710. int save_linear_depth = Max_linear_depth;
  1711. Max_linear_depth = Max_linear_depth_objects;
  1712. listnum = nn;
  1713. //mprintf((0,"render objs seg %d",segnum));
  1714. for (objnp=0;render_obj_list[listnum][objnp]!=-1;) {
  1715. int ObjNumber = render_obj_list[listnum][objnp];
  1716. if (ObjNumber >= 0) {
  1717. //mprintf( (0, "Type: %d\n", Objects[ObjNumber].type ));
  1718. //if (Objects[ObjNumber].type == OBJ_FIREBALL && n_expl_objs<5) {
  1719. // expl_objs[n_expl_objs++] = ObjNumber;
  1720. //} else
  1721. #ifdef LASER_HACK
  1722. if ( (Objects[ObjNumber].type==OBJ_WEAPON) && //if its a weapon
  1723. (Objects[ObjNumber].lifeleft==Laser_max_time ) && // and its in it's first frame
  1724. (Hack_nlasers< MAX_HACKED_LASERS) && // and we have space for it
  1725. (Objects[ObjNumber].laser_info.parent_num>-1) && // and it has a parent
  1726. ((Viewer-Objects)==Objects[ObjNumber].laser_info.parent_num) // and it's parent is the viewer
  1727. ) {
  1728. Hack_laser_list[Hack_nlasers++] = ObjNumber; //then make it draw after everything else.
  1729. //mprintf( (0, "O%d ", ObjNumber ));
  1730. } else
  1731. #endif
  1732. do_render_object(ObjNumber); // note link to above else
  1733. objnp++;
  1734. }
  1735. else {
  1736. listnum = -ObjNumber;
  1737. objnp = 0;
  1738. }
  1739. }
  1740. //for (i=0;i<n_expl_objs;i++)
  1741. // do_render_object(expl_objs[i]);
  1742. //mprintf((0,"done seg %d\n",segnum));
  1743. Max_linear_depth = save_linear_depth;
  1744. }
  1745. }
  1746. }
  1747. //mprintf((0,"\n"));
  1748. #ifdef LASER_HACK
  1749. // Draw the hacked lasers last
  1750. for (i=0; i < Hack_nlasers; i++ ) {
  1751. //mprintf( (0, "D%d ", Hack_laser_list[i] ));
  1752. do_render_object(Hack_laser_list[i]);
  1753. }
  1754. #endif
  1755. // -- commented out by mk on 09/14/94...did i do a good thing?? object_render_targets();
  1756. #ifdef EDITOR
  1757. #ifndef NDEUBG
  1758. //draw curedge stuff
  1759. if (Outline_mode) outline_seg_side(Cursegp,Curside,Curedge,Curvert);
  1760. #endif
  1761. done_rendering:
  1762. ;
  1763. #endif
  1764. }
  1765. #ifdef EDITOR
  1766. extern int render_3d_in_big_window;
  1767. //finds what segment is at a given x&y - seg,side,face are filled in
  1768. //works on last frame rendered. returns true if found
  1769. //if seg<0, then an object was found, and the object number is -seg-1
  1770. int find_seg_side_face(short x,short y,int *seg,int *side,int *face,int *poly)
  1771. {
  1772. _search_mode = -1;
  1773. _search_x = x; _search_y = y;
  1774. found_seg = -1;
  1775. if (render_3d_in_big_window) {
  1776. grs_canvas temp_canvas;
  1777. gr_init_sub_canvas(&temp_canvas,canv_offscreen,0,0,
  1778. LargeView.ev_canv->cv_bitmap.bm_w,LargeView.ev_canv->cv_bitmap.bm_h);
  1779. gr_set_current_canvas(&temp_canvas);
  1780. render_frame(0);
  1781. }
  1782. else {
  1783. gr_set_current_canvas(&VR_render_sub_buffer[0]); //render off-screen
  1784. render_frame(0);
  1785. }
  1786. _search_mode = 0;
  1787. *seg = found_seg;
  1788. *side = found_side;
  1789. *face = found_face;
  1790. *poly = found_poly;
  1791. // mprintf((0,"found seg=%d, side=%d, face=%d, poly=%d\n",found_seg,found_side,found_face,found_poly));
  1792. return (found_seg!=-1);
  1793. }
  1794. #endif
  1795.