scene.cpp 65 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996
  1. ////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright 2016 RWS Inc, All Rights Reserved
  4. //
  5. // This program is free software; you can redistribute it and/or modify
  6. // it under the terms of version 2 of the GNU General Public License as published by
  7. // the Free Software Foundation
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License along
  15. // with this program; if not, write to the Free Software Foundation, Inc.,
  16. // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. //
  18. // scene.cpp
  19. // Project: Nostril (aka Postal)
  20. //
  21. // This module impliments the CScene class
  22. //
  23. // History:
  24. // 01/05/97 MJR Started.
  25. //
  26. // 01/31/97 JMI Added cheezy alpha to Render().
  27. //
  28. // 02/06/97 JMI Added 3D transform and render to Render() for CSprite3's.
  29. // For now, the world transform is set up on each 3D render,
  30. // but I will fix that next to be affected once.
  31. //
  32. // 02/07/97 JMI Now uses m_transWorld member as the world transform.
  33. //
  34. // 02/07/97 JMI Added the alpha blit for alphable sprite.
  35. // May not work yet, but Jeff wants it anyways.
  36. //
  37. // 02/07/97 JMI Now it works, but there's some fudge in presuming the 3D
  38. // guy's diameter for the collision detection necessary for
  39. // the alpha X Ray.
  40. //
  41. // 02/07/97 JMI Now the scene has its own pipeline and CSprite3 does not.
  42. // B/c of this we no longer needed the m_transWorld, b/c we
  43. // could incorporate it right into the view.
  44. // Also, removed m_ppipe from CSprite3 and added m_sRadius
  45. // so the X Ray logic could do correct collision between
  46. // the X Rayee and X Rayables.
  47. // Also, added a function to initialize/create the pipeline.
  48. //
  49. // 02/10/97 JMI Changed the number of "Randy Units" represented by our
  50. // SCREEN_DIAMETER_FOR_3D to 25.5 (was 30.0).
  51. //
  52. // 02/10/97 JMI Added support for child objects of 3D sprites (CSprite3's).
  53. //
  54. // 02/11/97 JMI Changed 3D support to recursive inline so indefinite child
  55. // depths can be supported.
  56. //
  57. // 02/11/97 JMI Fixed bug in SetupPipeline() that was incorrectly trans-
  58. // lating the view transform along Z a distance of
  59. // dModelRadius. Now it transforms 0 along Z.
  60. // Also, changed MODEL_DIAMETER to the actual units used in
  61. // SoftImage and, consequently, set SCREEN_DIAMETER_FOR_3D
  62. // to the actual pixel size we want to use. I imagine we'll
  63. // have to make both of these larger eventually to fit all
  64. // the animations.
  65. //
  66. // 02/13/97 JMI Render() now uses the hood passed to it to get the lighting
  67. // effects. Render() now takes a CHood* as a parm.
  68. //
  69. // 02/13/97 JMI Render3D() now uses textures and fog.
  70. //
  71. // 02/14/97 JMI Render3D() now passes the CSprite3.m_psphere values to Jeff
  72. // who returns them and sizes an image. Currently, for
  73. // clipping purposes, the dude is rendered in the image and
  74. // then rspBlitT'd to the screen (so, if his textures all map
  75. // to 0, he won't show up b/c 0 is the transparent color pass-
  76. // ed to rspBlitT).
  77. // Also, CSprite3 now contains an m_psphere ptr which must be
  78. // set to the bounding sphere data for the CSprite3 frame (x, y,
  79. // z, w).
  80. // Also, added TransformPts() function which will map an array
  81. // of pts through the optionally provided transform and then
  82. // through the scenes transforms.
  83. //
  84. // 02/15/97 JMI Now there are 3 ways a 3D object is dealt with in Render3D:
  85. // 1) Not transformed or rendered -- it is entirely off the
  86. // destination region.
  87. // 2) Rendered into an intermediate buffer Jeff allocates and
  88. // then rspBlitT'ed to the destination buffer -- it is
  89. // partially off the destination region and, therefore,
  90. // requires clippage.
  91. // 3) Rendered directly into the destination region -- it is
  92. // entirely within the region.
  93. //
  94. // 02/14/97 JMI Added m_transNoZ which is a transform that is equivalent
  95. // to the scene's pipeline (m_pipeline), but does not scale
  96. // Z to the maximum value. It instead scales Z the same
  97. // as X and Y. This is now used by TransformPts().
  98. // 02/16/97 JMI Now the Render3D should clip to the bounding cube of the
  99. // points to efficientize the clippage further.
  100. // Need to clean up Render3D(). I feel like I'm doing a little
  101. // too much stuff.
  102. // 02/17/97 JMI Also, increased model diameter (MODEL_DAIMETER) to 30.0
  103. // since the dude was 10.0 off the origin (very close to
  104. // exceeding the Z buf height.
  105. // Also, Render3D() now uses brighter lighting for objects
  106. // that have the InHighIntensity flag set and also uses
  107. // the m_sBrightness flag as the center point for the fog.
  108. // Also, added TransformPtsToRealm() which translate points
  109. // through the specified transform, the scene's pipeline's
  110. // transforms, and finally maps them to Realm 3D coordinates.
  111. //
  112. // 02/17/97 JMI Now the alpha X Ray effect auto centers on 3D dudes.
  113. //
  114. // 02/19/97 JMI Now Alpha2d can handle sprites with no alpha.
  115. //
  116. // 02/19/97 JMI Now does not affect the passed in brightness in Render3D.
  117. //
  118. // 02/21/97 JMI Increased MODEL_DIAMETER to 50.0 to avoid problem with
  119. // children rigids exceeding the Z and clip buffers.
  120. //
  121. // 02/23/97 JMI Had forgotten to Make1() the NoZ* transforms in
  122. // SetupPipeline().
  123. //
  124. // 02/24/97 JMI Had forgotten to specify dest clipping rect for FSPR8 blit
  125. // of Alpha2d.
  126. //
  127. // 02/24/97 JMI Collapsed CAlphaSprite2 into CSprite2 and added
  128. // m_sAlphaLevel so a constant alpha level can be specified.
  129. // Using a constant alpha level is faster than using a mask.
  130. // Also, made it so the m_type field of the various sprites
  131. // are set automatically on construction so YOU SHOULD NO
  132. // LONGER SET THE CSprite*::m_type!
  133. //
  134. // 02/24/97 JMI Added homogeneous alpha blit but it is untested as far as
  135. // its use in this module.
  136. //
  137. // 02/25/97 JMI PATCHED FOR DEMO: Instead of ASSERTing in Render3D() when
  138. // a CSprite3 is hosed, it will try to detect and skip it
  139. // for now.
  140. //
  141. // 02/26/97 JMI Took out above patch.
  142. //
  143. // 03/05/97 JMI Added Render() function to render a 3D sprite into a
  144. // specified background.
  145. //
  146. // 03/21/97 JMI Added InDeleteOnRender flag and added support for new
  147. // CSpriteLine2d CSprite derived class.
  148. //
  149. // 03/27/97 JMI Added SCALE3D parameter to allow quick scaling.
  150. //
  151. // 03/28/97 JMI Put in VERY TEMP clippage to keep until the rspLine can
  152. // clip to a specified area (now clips to the destination).
  153. //
  154. // 04/02/97 JMI Now use slightly faster method to determine the blit
  155. // position for the sprite rendered into the clip buffer.
  156. // Changed MODEL_DIAMETER to 28.444444445 (from 50.0) so
  157. // we can divide it by 2 many times before getting errors
  158. // due to using integer division. The idea of that
  159. // particular number is to get a pixel size of the 3d world
  160. // of 128 which, of course, is a power of 2.
  161. //
  162. // 04/02/97 JMI Put MODEL_DIAMETER back to 50.0 b/c rocket man's rocket
  163. // is too far away from him when the animation starts.
  164. //
  165. // 04/02/97 JMI Put MODEL_DIAMETER back to 30.0. Now Render3D() checks
  166. // to make sure the item fits into the Z buffer and, instead
  167. // of ASSERTing like it used to, it just TRACEs and does not
  168. // do the render.
  169. //
  170. // 04/02/97 JMI In last fix, I used ||'s to separate newly combined ASSERTs
  171. // into an if (). It should've been &&'s. Fixed.
  172. //
  173. // 04/02/97 JMI Removed old, commented out ASSERT in Render3D(). Also,
  174. // made Render3D() aware of InHidden flag. Although the
  175. // loop in Render() takes care of the top-level objects'
  176. // InHidden flag, Render3D() was not, so child items that
  177. // were hidden would have been drawn, I think. Now they
  178. // definitely won't.
  179. //
  180. // 04/14/97 JMI Added use of TEMP flag m_bDontBlit to allow us to speed up
  181. // the Snap() call by not blitting.
  182. //
  183. // 04/29/97 JMI Made the child concept part of the base class sprite (was
  184. // part of the 3D sprite (CSprite3)) and added a parent
  185. // pointer.
  186. // Now that we have the parent sprite pointer, I was able to
  187. // make sure the sprites remove themselves from their parents
  188. // and remove their children when they are destroyed.
  189. // Also, added member functions to CScene to handle rendering
  190. // 2D sprites, 3D sprites, and 2D lines.
  191. //
  192. // 05/02/97 JMI If an alpha was 100 or over for a general alpha blit, it
  193. // was using the regular blit (opaque) instead of an rspBlitT
  194. // (transparent).
  195. //
  196. // 05/02/97 JMI Added CSpriteCylinder3d, a cylinder primitive.
  197. //
  198. // 05/13/97 JMI Now Render3D() tries to maximize the size of an object it
  199. // can render by centering top-level 3D objects in the 3D
  200. // screen based on their bounding sphere.
  201. // This change required additional fields in CSprite3.
  202. //
  203. // 05/13/97 JMI Casted instances of warning C4018 (signed/unsigned mismatch)
  204. // to make MSVC 4.1(Alpha) happy (these seem to fall under
  205. // Warning Level 3 in 4.1(Alpha) but not in 4.2(Intel)).
  206. //
  207. // 05/15/97 JMI I had thought that the max alpha (i.e., opaque) level was
  208. // 100 and was, therefore, checking to see if the level was
  209. // less than 100 before calling the alpha blit. As it turns
  210. // out, it is 255. Fixed.
  211. //
  212. // 05/15/97 JMI Now obeys g_GameSettings.m_sAlphaBlend and m_sXRayEffect.
  213. //
  214. // 05/16/97 JMI Code in Render3D() is set up so that no more than 1 level
  215. // deep of child will currently work for CSprite3. The
  216. // solution would be to add an m_transCumm to CSprite3 that
  217. // could accumulate the combined transforms as CSprite3's are
  218. // Render3D()'d.
  219. //
  220. // 05/19/97 JMI Now, by pointing mysprite.m_pszText at some text, you can
  221. // display text at the sprites m_sX2, m_sY2.
  222. //
  223. // 05/20/97 JMI Now DrawLine2D() uses rspLine() with a clip rect.
  224. //
  225. // 05/20/97 JMI Text (CSprite::m_pszText) drawn via ms_print is now clipped
  226. // to a column that is guaranteed to be within the clip rect.
  227. //
  228. // 05/22/97 JMI Now obeys g_GameSettings.m_s3dFog.
  229. //
  230. // 05/22/97 JMI Now the collision detection for the alpha affect is done
  231. // using the width and height of the xray mask instead of the
  232. // dude's xrayee's width and height.
  233. //
  234. // 06/05/97 JMI m_pipeline.m_pZB->Clear() was being called for top-level
  235. // 3D items even if they were OFFSCREEN. WHoopsee. Fixed.
  236. //
  237. // 06/05/97 JMI In Render3D(), the indirect render, when copying from the
  238. // temp (indirect) buf to the composite buffer, did not take
  239. // into account the fact that the center of the render may
  240. // not have been the center of the current renderee's bounding
  241. // sphere (which happens in the case of a child object (they
  242. // are blit relative to the center of the top-level parent's
  243. // bounding sphere) ).
  244. //
  245. // 06/10/97 JRD Returned lighting to non-adjusting because the spheres weren't
  246. // accurate enough. Luckily, the fix in the 3d export made the
  247. // non-adaptive lighting MUCH better.
  248. //
  249. // 06/10/97 JRD Updated to centered based adaptive lighting - a good compromise!
  250. //
  251. // 06/14/97 MJR Added g_bSceneDontBlit to replace the flag in gamesettings
  252. // that was being misused for that purpose.
  253. //
  254. // 06/16/97 JRD Shrunk Z-buffer from 30 to 16 Randy Units
  255. //
  256. // 06/25/97 JMI Added SetXRayAll() and m_bXRayAll which enable or disable
  257. // xraying of all 'alpha' _and_ 'opaque' layers.
  258. // Also, changed InXrayable to InAlpha and added InOpaque to
  259. // differentiate between these two types which are now, at
  260. // times, both xrayable.
  261. //
  262. // 06/26/97 JMI Now uses phood->Map3Dto2D() (was using the global
  263. // version defined in reality.h which is no more).
  264. //
  265. // 06/29/97 MJR Converted vector of layers into simple array of layers
  266. // (motivated by trying to get it to work on the mac).
  267. //
  268. // 07/01/97 JMI Added m_transScene2Realm which is used in
  269. // TransformPtsToRealm() to convert from the scene to the
  270. // realm. This value is set via the SetupPipeline() call.
  271. // Currently, the code exists but is commented out b/c it
  272. // does not seem to bridge the gap between scene and realm
  273. // coords correctly.
  274. //
  275. // 07/10/97 JMI Now Render2D() can uses an alpha mask with an alpha level
  276. // via the new rspGeneralAlphaBlit() which accepts a level.
  277. //
  278. // 07/17/97 JRD Moved the pipeline tranform so it would only be called
  279. // if a 3d object was on screen. (watch for side effects)
  280. //
  281. // 07/20/97 JMI Added some ASSERTs on m_sAlphaLevel in Render2D().
  282. //
  283. // 07/03/97 JRD Altered the load to update the pipeline based on the
  284. // 3d scale for that level.
  285. //
  286. // 08/04/97 JMI Now Render3D() verifies that a sprite has a valid m_pthing
  287. // before using it to display info on a sprite that could not
  288. // be drawn.
  289. //
  290. // 08/07/97 JMI Moved global single instance of gdSCALE3D defined in
  291. // scene.cpp into scene as an instantiable member, m_dScale3d.
  292. // Also, now SetupPipeline() does what UpdatePipeline() used
  293. // to (got rid of UpdatePipeline()).
  294. //
  295. // 08/18/97 JMI Added ASSERTs to make sure inserted sprite's layer number
  296. // is greater than or equal to 0.
  297. //
  298. // 08/18/97 JMI If the InDeleteOnRender flag was specified in a sprite,
  299. // it was removed from the scene list, deleted, and then its
  300. // flags were checked for the XRay bit which it usually had
  301. // because it was memset'ed to 0xdd on deletion. This caused
  302. // it to be the XRayee. Fixed.
  303. // Also, made the Render() call used for blitting things into
  304. // the background call the basic Render().
  305. // Also, increased MODEL_DIAMETER to 18.0 (was 16.0).
  306. //
  307. // 08/18/97 JMI Changed Render() used by dead things to update themselves
  308. // into the background to be called DeadRender3D() to better
  309. // describe what it does and differentiate it from the other
  310. // more generic Render()ers. Also, added two parameters so
  311. // it could call itself with 3D children.
  312. //
  313. // 08/23/97 JMI Now offsets child light offset by the parent's.
  314. //
  315. // 10/03/99 JMI Changed Render3D() to take a light scheme instead of a hood
  316. // to make it more general.
  317. //
  318. ////////////////////////////////////////////////////////////////////////////////
  319. #define SCENE_CPP
  320. #include "RSPiX.h"
  321. #include "scene.h"
  322. #include "game.h"
  323. #include "alphablitforpostal.h"
  324. #include "reality.h"
  325. ////////////////////////////////////////////////////////////////////////////////
  326. // Macros/types/etc.
  327. ////////////////////////////////////////////////////////////////////////////////
  328. #define SCREEN2MODEL_RATIO (4.5 * m_dScale3d)
  329. // This represents the number of "Randy units" represented by
  330. // SCREEN_DIAMETER_FOR_3D.
  331. #define MODEL_DIAMETER 20.0 // In "Randy Units".
  332. #define MODEL_ZSPAN 30.0 // must NEVER be exceeded or lighting is hosed
  333. // Diameter in pixels for screen for 3D objects.
  334. // Should be largest to hold largest 3D object.
  335. #define SCREEN_DIAMETER_FOR_3D (MODEL_DIAMETER * SCREEN2MODEL_RATIO)
  336. short gsGlobalBrightnessPerLightAttribute = 5;
  337. /* short gsGlobalLightingAdjustment = 128; /* neutral center */
  338. // NOTE: This max value completely depends on the actual lighting effect curve:
  339. // it should be set near the bright spot of the curve.
  340. short gsGlobalLightingAdjustment = 128; // NEUTRAL BABY!
  341. //160 /* Max White */ - 6 * gsGlobalBrightnessPerLightAttribute;
  342. // Used to control whether or not scene will actually blit. When set to true,
  343. // scene will execute quite a bit faster, except you won't see anything. :)
  344. bool g_bSceneDontBlit;
  345. // Font stuff.
  346. #define FONT_CELL_HEIGHT 15
  347. #define FONT_FORE_COLOR 250
  348. #define FONT_BACK_COLOR 0
  349. #define FONT_SHADOW_COLOR 0
  350. const double c_dMaxScale = 10.0;
  351. const double c_dMinScale = 0.2;
  352. ////////////////////////////////////////////////////////////////////////////////
  353. // Variables/data
  354. ////////////////////////////////////////////////////////////////////////////////
  355. // Used to draw within the scene.
  356. RPrint CScene::ms_print;
  357. ////////////////////////////////////////////////////////////////////////////////
  358. // Default (and only) constructor
  359. ////////////////////////////////////////////////////////////////////////////////
  360. CScene::CScene()
  361. {
  362. // No array of layers yet
  363. m_pLayers = 0;
  364. m_sNumLayers = 0;
  365. // This can fail, so I had wanted to put it in SetupPipeline(), but there's
  366. // not much difference really since that function does not return an error
  367. // either. Since this only needs to be done once, I decided to put it
  368. // here....let me know if you think it sucks.
  369. // Note that this function initializes m_dScale3d and other members.
  370. SetupPipeline();
  371. // If the static print has no font . . .
  372. if (ms_print.GetFont() == NULL)
  373. {
  374. ms_print.SetFont(FONT_CELL_HEIGHT, &g_fontBig);
  375. ms_print.SetColor(FONT_FORE_COLOR, FONT_BACK_COLOR, FONT_SHADOW_COLOR);
  376. ms_print.SetWordWrap(FALSE);
  377. }
  378. // Default to something (anything)
  379. m_bXRayAll = false;
  380. }
  381. ////////////////////////////////////////////////////////////////////////////////
  382. // Destructor
  383. ////////////////////////////////////////////////////////////////////////////////
  384. CScene::~CScene()
  385. {
  386. Clear();
  387. }
  388. ////////////////////////////////////////////////////////////////////////////////
  389. // Clear the scene (clears out all layers and sprites)
  390. ////////////////////////////////////////////////////////////////////////////////
  391. void CScene::Clear(void)
  392. {
  393. // Clear all sprites from all layers
  394. RemoveAllSprites();
  395. // Delete the layers
  396. delete []m_pLayers;
  397. m_pLayers = 0;
  398. m_sNumLayers = 0;
  399. }
  400. ////////////////////////////////////////////////////////////////////////////////
  401. // Remove all sprites (from all layers)
  402. ///////////////////////////////////////////////////////////////////////////////
  403. void CScene::RemoveAllSprites(void)
  404. {
  405. // Clear sprites from each layer
  406. for (short s = 0; s < m_sNumLayers; s++)
  407. RemoveSprites(s);
  408. }
  409. ////////////////////////////////////////////////////////////////////////////////
  410. // Remove sprites from specified layer
  411. ////////////////////////////////////////////////////////////////////////////////
  412. void CScene::RemoveSprites(
  413. short sLayer) // In: Layer number (0 to n-1)
  414. {
  415. // Get pointer to layer
  416. Layer* pLayer = &(m_pLayers[sLayer]);
  417. // Go through layer's collection of sprites
  418. for (msetSprites::iterator i = pLayer->m_sprites.begin(); i != pLayer->m_sprites.end(); i++)
  419. {
  420. // Get pointer to sprite
  421. CSprite* pSprite = *i;
  422. // Clear inserted flag
  423. pSprite->m_sPrivFlags &= ~CSprite::PrivInserted;
  424. // Delete sprite if delete-on-clear flag is set
  425. if (pSprite->m_sInFlags & CSprite::InDeleteOnClear)
  426. delete pSprite;
  427. }
  428. // Clear the sprite container
  429. #if _MSC_VER >= 1020
  430. pLayer->m_sprites.clear();
  431. #else
  432. pLayer->m_sprites.erase(pLayer->m_sprites.begin(), pLayer->m_sprites.end());
  433. #endif
  434. }
  435. ////////////////////////////////////////////////////////////////////////////////
  436. // Set number of layers (destroys any existing layers!)
  437. ////////////////////////////////////////////////////////////////////////////////
  438. void CScene::SetLayers(
  439. short sNumLayers) // In: Number of layers
  440. {
  441. // Validate parameters
  442. ASSERT(sNumLayers > 0);
  443. // Clear all layers (and sprites)
  444. Clear();
  445. // Create array of layers
  446. m_pLayers = new Layer[sNumLayers];
  447. m_sNumLayers = sNumLayers;
  448. }
  449. ////////////////////////////////////////////////////////////////////////////////
  450. // Update existing sprite or add new sprite
  451. ////////////////////////////////////////////////////////////////////////////////
  452. void CScene::UpdateSprite(
  453. CSprite* pSprite) // In: Sprite to add
  454. {
  455. ASSERT(pSprite != NULL);
  456. // Check if it's already in the scene
  457. if (pSprite->m_sPrivFlags & CSprite::PrivInserted)
  458. {
  459. // Check if layer has changed
  460. if (pSprite->m_sLayer != pSprite->m_sSavedLayer)
  461. {
  462. // Erase from old layer
  463. m_pLayers[pSprite->m_sSavedLayer].m_sprites.erase(pSprite->m_iter);
  464. // Add to specified layer and save iterator for fast access later on
  465. ASSERT(pSprite->m_sLayer < m_sNumLayers);
  466. ASSERT(pSprite->m_sLayer >= 0);
  467. pSprite->m_iter = m_pLayers[pSprite->m_sLayer].m_sprites.insert(pSprite);
  468. pSprite->m_sSavedLayer = pSprite->m_sLayer;
  469. }
  470. // Check if priority has changed
  471. if (pSprite->m_sPriority != pSprite->m_sSavedPriority)
  472. {
  473. // For now, just erase it and then re-insert it. There is definitely
  474. // a faster way to do this, but since we'll likely be revamping the
  475. // entire draw-order logic, I'll leave it like this.
  476. m_pLayers[pSprite->m_sSavedLayer].m_sprites.erase(pSprite->m_iter);
  477. pSprite->m_iter = m_pLayers[pSprite->m_sLayer].m_sprites.insert(pSprite);
  478. pSprite->m_sSavedPriority = pSprite->m_sPriority;
  479. }
  480. }
  481. else
  482. {
  483. // Add to specified layer and save iterator for fast access later on
  484. ASSERT(pSprite->m_sLayer < m_sNumLayers);
  485. ASSERT(pSprite->m_sLayer >= 0);
  486. pSprite->m_iter = m_pLayers[pSprite->m_sLayer].m_sprites.insert(pSprite);
  487. // Save layer and priority so we can detect changes to them
  488. pSprite->m_sSavedLayer = pSprite->m_sLayer;
  489. pSprite->m_sSavedPriority = pSprite->m_sPriority;
  490. // Set inserted flag
  491. pSprite->m_sPrivFlags |= CSprite::PrivInserted;
  492. }
  493. }
  494. ////////////////////////////////////////////////////////////////////////////////
  495. // Remove sprite (safe to call even if sprite isn't in scene).
  496. ////////////////////////////////////////////////////////////////////////////////
  497. void CScene::RemoveSprite(
  498. CSprite* pSprite) // In: Sprite to remove
  499. {
  500. ASSERT(pSprite != NULL);
  501. // Make sure sprite is currently inserted -- if not, skip it. This is
  502. // not treated as an error because there may be situations where the
  503. // caller doesn't know the sprite has already been removed from the layer,
  504. // such as when someone else has called Clear() or some similar function.
  505. if(pSprite->m_sPrivFlags & CSprite::PrivInserted)
  506. {
  507. // Erase sprite from layer. Knowing the iterator makes this very fast.
  508. ASSERT(pSprite->m_sSavedLayer < m_sNumLayers);
  509. m_pLayers[pSprite->m_sSavedLayer].m_sprites.erase(pSprite->m_iter);
  510. // Clear inserted flag
  511. pSprite->m_sPrivFlags &= ~CSprite::PrivInserted;
  512. }
  513. }
  514. ////////////////////////////////////////////////////////////////////////////////
  515. // Render a 3D sprite.
  516. //
  517. // See the Render3D(..., RAlpha*, ...) for details.
  518. //
  519. ////////////////////////////////////////////////////////////////////////////////
  520. void // Returns nothing.
  521. CScene::Render3D(
  522. RImage* pimDst, // Destination image.
  523. short sDstX, // Destination 2D x coord.
  524. short sDstY, // Destination 2D y coord.
  525. CSprite3* ps3Cur, // 3D sprite to render.
  526. CHood* phood, // Da hood, homey.
  527. RRect* prcDstClip) // Dst clip rect.
  528. {
  529. RAlpha* palphaLight;
  530. // If high intensity indicated . . .
  531. if (ps3Cur->m_sInFlags & CSprite::InHighIntensity)
  532. {
  533. // Use spot lighting.
  534. palphaLight = phood->m_pltSpot;
  535. }
  536. else
  537. {
  538. // Use ambient lighting.
  539. palphaLight = phood->m_pltAmbient;
  540. }
  541. Render3D( // Returns happy thoughts.
  542. pimDst, // Destination image.
  543. sDstX, // Destination 2D x coord.
  544. sDstY, // Destination 2D y coord.
  545. ps3Cur, // Tree of 3D sprites to render.
  546. palphaLight, // Da hood, homey.
  547. prcDstClip); // Dst clip rect.
  548. }
  549. ////////////////////////////////////////////////////////////////////////////////
  550. // Render a 3D sprite.
  551. //
  552. // This function will, for a top level 3D sprite:
  553. // 0) Clear the Z buffer.
  554. // 1) Transform the bounding sphere to screen coordinates.
  555. // 2) Ignore the sprite if the bounding sphere indicates the sprite is entirely
  556. // offscreen.
  557. // 3) Center the Render() on the bounding sphere to get maximum Z buffer room
  558. // on X/Z plane.
  559. // 4) Render into a clip image if the bounding sphere indicates the sprite is
  560. // partially offscreen. The clip image then gets rspBlitT'd to the composite
  561. // buffer with clipping.
  562. //
  563. // For a non-top level 3D sprite:
  564. // 1) Combine all parent transforms with this sprite's transform.
  565. // 2) Transform the bounding sphere to screen coordinates.
  566. // 3) Center the Render() on the top-level parent's bounding sphere so it matches
  567. // the parents' position(s).
  568. // 4) Render into a clip image if the bounding sphere indicates the sprite is
  569. // partially offscreen. The clip image then gets rspBlitT'd to the composite
  570. // buffer with clipping.
  571. //
  572. ////////////////////////////////////////////////////////////////////////////////
  573. void // Returns nothing.
  574. CScene::Render3D(
  575. RImage* pimDst, // Destination image.
  576. short sDstX, // Destination 2D x coord.
  577. short sDstY, // Destination 2D y coord.
  578. CSprite3* ps3Cur, // 3D sprite to render.
  579. RAlpha* plight, // Light to render with.
  580. RRect* prcDstClip) // Dst clip rect.
  581. {
  582. // This transform is the product of the parent and the
  583. // child's transform used to determine the position of
  584. // a child object absolutely.
  585. RTransform transChildAbs;
  586. RTransform* ptransRender; // The transform used.
  587. short sCurX;
  588. short sCurY;
  589. RP3d pt3dSrcCenter, pt3dSrcRadius; // Center and point on outside of bounding
  590. // sphere in "Randy" coords.
  591. short sClipLeft; // Amount clipped off left edge of dest region.
  592. short sClipTop; // Amount clipped off top edge of dest region.
  593. short sClipRight; // Amount clipped off right edge of dest region.
  594. short sClipBottom; // Amount clipped off bottom edge of dest region.
  595. short sRadius; // Radius of bounding sphere in pixels.
  596. short sDiameter; // Diameter of bounding sphere in pixels.
  597. short sCenterX; // Center of bounding sphere as screen coord.
  598. short sCenterY; // Center of bounding sphere as screen coord.
  599. RImage* pimRender; // Image to render into.
  600. bool bIndirectRender; // Rendering to intermediate buffer.
  601. short sIndirectRenderX; // Render coord when rendering to clip buffer.
  602. short sIndirectRenderY; // Render coord when rendering to clip buffer.
  603. short sDirectRenderZ; // Render Coord in either case
  604. short sDirectRenderX; // Render coord when rendering to pimDst buffer.
  605. short sDirectRenderY; // Render coord when rendering to pimDst buffer.
  606. short sRenderX; // Render coord passed to Render().
  607. short sRenderY; // Render coord passed to Render().
  608. short sBlitX; // Blit pos for 3D model.
  609. short sBlitY; // Biit pos for 3D model.
  610. short sRenderOffX; // Offset to Render().
  611. short sRenderOffY; // Offset to Render().
  612. ASSERT(ps3Cur->m_psop != NULL);
  613. ASSERT(ps3Cur->m_ptex != NULL);
  614. ASSERT(ps3Cur->m_pmesh != NULL);
  615. ASSERT(ps3Cur->m_ptrans != NULL);
  616. ASSERT(ps3Cur->m_psphere != NULL);
  617. // If there's a parent . . .
  618. if (ps3Cur->m_psprParent != NULL)
  619. {
  620. // NOTE: This does NOT work for more than 1 level of child depth.
  621. // To make that work, we must put a transform in the CSprite3.
  622. // Apply child and parent to transChildAbs.
  623. transChildAbs.Mul( ((CSprite3*)ps3Cur->m_psprParent)->m_ptrans->T, ps3Cur->m_ptrans->T);
  624. // Use transChildAbs.
  625. ptransRender = &transChildAbs;
  626. }
  627. else
  628. {
  629. // Use current top-level matrix.
  630. ptransRender = ps3Cur->m_ptrans;
  631. }
  632. // Here's the deal with m_pipeline. :
  633. // X == Origin.
  634. // @ == Center of sphere of points.
  635. // ________________m_pimClipBuf________________
  636. // | (m_sX, m_sY) (m_sX + m_sW, m_sY) |
  637. // | ___________ |
  638. // | | ooo | |
  639. // | | o\o/o | |
  640. // | | o*o | |
  641. // | | o | |
  642. // | |ooooo@ooooo| |
  643. // | | o | |
  644. // | | o o | |
  645. // | | o o | |
  646. // | |_oo__X__oo_| |
  647. // | (m_sX, m_sY + m_sH) (m_sX + m_sW, m_sY + m_sH)
  648. // | |
  649. // | |
  650. // | |
  651. // | |
  652. // | |
  653. // | |
  654. // | |
  655. // | |
  656. // | |
  657. // | |
  658. // |____________________________________________|
  659. // Get the bounding info.
  660. // Setup src pts.
  661. // Get current sphere.
  662. pt3dSrcCenter = *(ps3Cur->m_psphere);
  663. pt3dSrcRadius.x = pt3dSrcCenter.x + pt3dSrcCenter.w;
  664. pt3dSrcRadius.y = pt3dSrcCenter.y + pt3dSrcCenter.w;
  665. pt3dSrcRadius.z = pt3dSrcCenter.z + pt3dSrcCenter.w;
  666. pt3dSrcRadius.w = 1;
  667. pt3dSrcCenter.w = 1;
  668. // Let the pipeline know of the bounding sphere.
  669. m_pipeline.BoundingSphereToScreen(pt3dSrcCenter, pt3dSrcRadius, *ptransRender);
  670. // Check screen location:
  671. // Get radius of sphere of points (SphOP).
  672. sDiameter = MAX(m_pipeline.m_sW, m_pipeline.m_sH);
  673. sRadius = sDiameter / 2;
  674. // ****TEMP****
  675. if (g_bSceneDontBlit == false)
  676. {
  677. // ****END TEMP****
  678. // Determine destination of hotspot on screen relative to parent, if any.
  679. sCurX = ps3Cur->m_sX2 + sDstX;
  680. sCurY = ps3Cur->m_sY2 + sDstY;
  681. // Determine center of sphere of points relative to origin.
  682. short sOrgRelCenX = (m_pipeline.m_sCenX - (short)(SCREEN_DIAMETER_FOR_3D / 2));
  683. short sOrgRelCenY = (m_pipeline.m_sCenY - (short)(SCREEN_DIAMETER_FOR_3D / 2));
  684. // Determine center of sphere of points on screen.
  685. sCenterX = sCurX + sOrgRelCenX;
  686. sCenterY = sCurY + sOrgRelCenY;
  687. // Determine amount that is off of the clip rect.
  688. sClipLeft = prcDstClip->sX - (sCenterX - sRadius);
  689. sClipTop = prcDstClip->sY - (sCenterY - sRadius);
  690. sClipRight = (sCenterX + sRadius) - (prcDstClip->sX + prcDstClip->sW);
  691. sClipBottom = (sCenterY + sRadius) - (prcDstClip->sY + prcDstClip->sH);
  692. // If on screen at all . . .
  693. if (sClipLeft < sDiameter && sClipTop < sDiameter && sClipRight < sDiameter && sClipBottom < sDiameter)
  694. {
  695. // Transform pts through *ptransRender, view, and finally screen transforms.
  696. m_pipeline.Transform(
  697. ps3Cur->m_psop, // Sea of 3D points to form
  698. // mesh around.
  699. *ptransRender); // The transformation.
  700. // If there's no parent . . .
  701. if (ps3Cur->m_psprParent == NULL)
  702. {
  703. // Clear Z buffer for new 3D tree.
  704. m_pipeline.m_pZB->Clear();
  705. }
  706. // Determine destination for sprite on screen.
  707. // Get upper left hand corner by subtracting the radius from the screen center of points.
  708. sBlitX = sCenterX - sRadius;
  709. sBlitY = sCenterY - sRadius;
  710. //////////////////////////////////////////////////////////////////////////////
  711. // GLOBAL LIGHTING FACTOR: (ADAPTIVE)
  712. //////////////////////////////////////////////////////////////////////////////
  713. // Here we do dynamic light adjustment based on the current sphere.
  714. // Stage two aligns front of sphere:
  715. // *** RESTORING DO NON-ADJUSTMENT! ***
  716. // re-attempting center adjustment level
  717. short sLightOffset = 0; // Must be initialized here (the other assignments are +=).
  718. // - (m_pipeline.m_sCenZ + m_pipeline.m_sZ);
  719. // If no parent . . .
  720. if (ps3Cur->m_psprParent == NULL)
  721. {
  722. // For indirect Render:
  723. // Render so center of sphere is at center of clip image.
  724. sIndirectRenderX = 0;
  725. sIndirectRenderY = 0;
  726. // For direct Render:
  727. // Determine destination for render on screen.
  728. // The position you supply to Render() is one 3D screen radius
  729. // up and to the left.
  730. sDirectRenderX = sCenterX - (short)(SCREEN_DIAMETER_FOR_3D / 2);
  731. sDirectRenderY = sCenterY - (short)(SCREEN_DIAMETER_FOR_3D / 2);
  732. sDirectRenderZ = m_pipeline.m_sCenZ; // don't need to know
  733. // Offset by the center relative to the origin.
  734. sRenderOffX = -sOrgRelCenX;
  735. sRenderOffY = -sOrgRelCenY;
  736. }
  737. else
  738. {
  739. // MUST BE 3D PARENT!
  740. ASSERT(ps3Cur->m_psprParent->m_type == CSprite::Standard3d);
  741. CSprite3* ps3Parent = (CSprite3*)(ps3Cur->m_psprParent);
  742. // Use the position the parent rendered at.
  743. sDirectRenderX = ps3Parent->m_sDirectRenderX;
  744. sDirectRenderY = ps3Parent->m_sDirectRenderY;
  745. sDirectRenderZ = ps3Parent->m_sDirectRenderZ;
  746. sIndirectRenderX = ps3Parent->m_sIndirectRenderX;
  747. sIndirectRenderY = ps3Parent->m_sIndirectRenderY;
  748. // Offset by the amount the parent was offset.
  749. sRenderOffX = ps3Parent->m_sRenderOffX;
  750. sRenderOffY = ps3Parent->m_sRenderOffY;
  751. // Offset lighting by parent's offset.
  752. sLightOffset += ps3Parent->m_sBrightness;
  753. }
  754. // If this sprite has children . . .
  755. if (ps3Cur->m_psprHeadChild != NULL)
  756. {
  757. // Store Render() positions for children to use.
  758. ps3Cur->m_sDirectRenderX = sDirectRenderX;
  759. ps3Cur->m_sDirectRenderY = sDirectRenderY;
  760. ps3Cur->m_sDirectRenderZ = sDirectRenderZ;
  761. ps3Cur->m_sIndirectRenderX = sIndirectRenderX;
  762. ps3Cur->m_sIndirectRenderY = sIndirectRenderY;
  763. // Store Render() offsets for children to use.
  764. ps3Cur->m_sRenderOffX = sRenderOffX;
  765. ps3Cur->m_sRenderOffY = sRenderOffY;
  766. }
  767. // If only partially on screen . . .
  768. if (sClipLeft > 0 || sClipTop > 0 || sClipRight > 0 || sClipBottom > 0)
  769. {
  770. ASSERT(m_pipeline.m_pimClipBuf != NULL);
  771. // Use clip image.
  772. pimRender = m_pipeline.m_pimClipBuf;
  773. // Remember to blit to composite.
  774. bIndirectRender = true;
  775. // Use appropriate position.
  776. sRenderX = sIndirectRenderX;
  777. sRenderY = sIndirectRenderY;
  778. }
  779. else
  780. {
  781. // Use composite buffer.
  782. pimRender = pimDst;
  783. // Remember we don't need to blit to composite.
  784. bIndirectRender = false;
  785. // Use appropriate position.
  786. sRenderX = sDirectRenderX;
  787. sRenderY = sDirectRenderY;
  788. }
  789. // use either the current z center or parent to adjust:
  790. // Note that we've already offset this by the parent and that is why
  791. // we do a += (see above (search for sLightOffset) ).
  792. sLightOffset += ps3Cur->m_sBrightness + gsGlobalLightingAdjustment - sDirectRenderZ;
  793. // Make sure we don't overrun the Z buffer . . .
  794. // Note that m_pipeline.m_sCen? are in image coords (i.e., (0, 0) is
  795. // the upper, left hand corner and (SCREEN_DIAMETER_FOR_3D,
  796. // SCREEN_DIAMETER_FOR_3D) is the lower, right hand corner).
  797. if ( m_pipeline.m_sCenX - sRadius >= -sRenderOffX
  798. && m_pipeline.m_sCenX + sRadius < SCREEN_DIAMETER_FOR_3D - sRenderOffX
  799. && m_pipeline.m_sCenY - sRadius >= -sRenderOffY
  800. && m_pipeline.m_sCenY + sRadius < SCREEN_DIAMETER_FOR_3D - sRenderOffY)
  801. {
  802. // If fog enabled . . .
  803. if (g_GameSettings.m_s3dFog != FALSE)
  804. {
  805. // Render with textures and fog.
  806. m_pipeline.Render(
  807. pimRender, // Dst image.
  808. sRenderX, // 2D Dst coord.
  809. sRenderY, // 2D Dst coord.
  810. ps3Cur->m_pmesh, // Src mesh.
  811. m_pipeline.m_pZB, // Z buffer (use its own for now).
  812. ps3Cur->m_ptex, // Textures.
  813. sLightOffset, // Fog offset. Fogool?
  814. plight, // Ambient lighting schtuff.
  815. sRenderOffX, // Offset render/z-buffer to center of sphere of points.
  816. sRenderOffY); // Offset render/z-buffer to center of sphere of points.
  817. }
  818. else
  819. {
  820. // Render with textures, no fog.
  821. m_pipeline.Render(
  822. pimRender, // Dst image.
  823. sRenderX, // 2D Dst coord.
  824. sRenderY, // 2D Dst coord.
  825. ps3Cur->m_pmesh, // Src mesh.
  826. m_pipeline.m_pZB, // Z buffer (use its own for now).
  827. ps3Cur->m_ptex, // Textures.
  828. sRenderOffX, // Offset render/z-buffer to center of sphere of points.
  829. sRenderOffY); // Offset render/z-buffer to center of sphere of points.
  830. }
  831. // If we rendered into an intermediate buffer b/c of clipping . . .
  832. if (bIndirectRender == true)
  833. {
  834. // Get it into destination.
  835. rspBlitT(
  836. 0, // Transparent index.
  837. pimRender, // Src.
  838. pimDst, // Dst.
  839. m_pipeline.m_sCenX - sRadius + sRenderOffX, // Src.
  840. m_pipeline.m_sCenY - sRadius + sRenderOffY, // Src.
  841. sBlitX, // Dst.
  842. sBlitY, // Dst.
  843. m_pipeline.m_sW, // Both.
  844. m_pipeline.m_sH, // Both.
  845. prcDstClip, // Dst.
  846. NULL); // Src.
  847. m_pipeline.ClearClipBuffer();
  848. }
  849. else
  850. {
  851. // Already in pimDst.
  852. }
  853. #if 0 // Set to 1 to see origin target, center of points X,
  854. // rect for bounding cube, and rect for clip image.
  855. // Draw bounds.
  856. rspRect(
  857. 1,
  858. RSP_WHITE_INDEX,
  859. pimDst,
  860. sCenterX - sRadius,
  861. sCenterY - sRadius,
  862. sDiameter,
  863. sDiameter,
  864. prcDstClip);
  865. // Draw target at hotspot on screen.
  866. #define HOTSPOT_TARGET_LENGTH 5
  867. rspLine(
  868. RSP_WHITE_INDEX,
  869. pimDst,
  870. sCurX - HOTSPOT_TARGET_LENGTH / 2,
  871. sCurY,
  872. sCurX + HOTSPOT_TARGET_LENGTH / 2 + 1,
  873. sCurY);
  874. // prcDstClip);
  875. rspLine(RSP_WHITE_INDEX,
  876. pimDst,
  877. sCurX,
  878. sCurY - HOTSPOT_TARGET_LENGTH / 2,
  879. sCurX,
  880. sCurY + HOTSPOT_TARGET_LENGTH / 2 + 1);
  881. // prcDstClip);
  882. // Draw origin with X.
  883. #define ORIGIN_TARGET_LENGTH 6
  884. rspLine(
  885. 251/*Yellow*/,
  886. pimDst,
  887. sCenterX - ORIGIN_TARGET_LENGTH / 2,
  888. sCenterY - ORIGIN_TARGET_LENGTH / 2,
  889. sCenterX + ORIGIN_TARGET_LENGTH / 2 + 1,
  890. sCenterY + ORIGIN_TARGET_LENGTH / 2 + 1);
  891. // prcDstClip);
  892. rspLine(
  893. 251/*Yellow*/,
  894. pimDst,
  895. sCenterX + ORIGIN_TARGET_LENGTH / 2,
  896. sCenterY - ORIGIN_TARGET_LENGTH / 2,
  897. sCenterX - ORIGIN_TARGET_LENGTH / 2 - 1,
  898. sCenterY + ORIGIN_TARGET_LENGTH / 2 + 1);
  899. // prcDstClip);
  900. // Draw image.
  901. rspRect(1, RSP_WHITE_INDEX, pimDst,
  902. sCenterX - (short)(SCREEN_DIAMETER_FOR_3D / 2),
  903. sCenterY - (short)(SCREEN_DIAMETER_FOR_3D / 2),
  904. m_pipeline.m_pimClipBuf->m_sWidth,
  905. m_pipeline.m_pimClipBuf->m_sHeight,
  906. prcDstClip);
  907. // Note whether clipping.
  908. if (bIndirectRender == true)
  909. {
  910. rspLine(251/*Yellow*/, pimDst, sCenterX, sCenterY, 1, 1);
  911. }
  912. #endif
  913. }
  914. else
  915. {
  916. char szMsg[1024];
  917. if (ps3Cur->m_pthing)
  918. {
  919. sprintf(szMsg, "Render3D(): %s with ID %d",
  920. CThing::ms_aClassInfo[ps3Cur->m_pthing->GetClassID()].pszClassName,
  921. ps3Cur->m_pthing->GetInstanceID());
  922. }
  923. else
  924. {
  925. strcpy(szMsg, "Render3D(): Unknown class with unknown ID");
  926. }
  927. // If there's a parent . . .
  928. CSprite* psprParent = ps3Cur->m_psprParent;
  929. if (psprParent != NULL)
  930. {
  931. if (psprParent->m_pthing)
  932. {
  933. sprintf(szMsg, "%s, child of %s with ID %d,",
  934. szMsg,
  935. CThing::ms_aClassInfo[psprParent->m_pthing->GetClassID()].pszClassName,
  936. psprParent->m_pthing->GetInstanceID());
  937. }
  938. }
  939. strcat(szMsg, " would exceed the Z buffer, if rendered. Not gonna do it.\n");
  940. TRACE(szMsg);
  941. }
  942. }
  943. // ****TEMP****
  944. }
  945. // ****END TEMP****
  946. // Store this location (it is used by Render() to do collision circle for XRay).
  947. ps3Cur->m_sCenX = ps3Cur->m_sX2 + m_pipeline.m_sCenX - (short)(SCREEN_DIAMETER_FOR_3D / 2);
  948. ps3Cur->m_sCenY = ps3Cur->m_sY2 + m_pipeline.m_sCenY - (short)(SCREEN_DIAMETER_FOR_3D / 2);
  949. ps3Cur->m_sRadius = sRadius;
  950. }
  951. ////////////////////////////////////////////////////////////////////////////////
  952. // Line function until we have one that can clip to other than the dest image.
  953. ////////////////////////////////////////////////////////////////////////////////
  954. inline
  955. void DrawLine2d( // Returns nothing.
  956. U8 u8Color, // Color to draw line with.
  957. RImage* pimDst, // Destination image.
  958. short sDstX1, // Start pt.
  959. short sDstY1, // Start pt.
  960. short sDstX2, // End pt.
  961. short sDstY2, // End pt.
  962. RRect* prcDstClip) // Dst clip rect.
  963. {
  964. #if 0
  965. // If entirely on view . . .
  966. // *****VERY CHEESY, INCORRECT CLIP FOR LINE TOTALLY ON SCREEN****
  967. RRect rcClipPt1(sDstX1, sDstY1, 1, 1);
  968. RRect rcClipPt2(sDstX2, sDstY2, 1, 1);
  969. if ( rcClipPt1.ClipTo(prcDstClip) != -1
  970. && rcClipPt2.ClipTo(prcDstClip) != -1)
  971. {
  972. // Draw.
  973. rspLine(
  974. u8Color,
  975. pimDst,
  976. sDstX1,
  977. sDstY1,
  978. sDstX2,
  979. sDstY2);
  980. }
  981. #else
  982. // Draw.
  983. rspLine(
  984. u8Color,
  985. pimDst,
  986. sDstX1,
  987. sDstY1,
  988. sDstX2,
  989. sDstY2,
  990. prcDstClip);
  991. #endif
  992. }
  993. ////////////////////////////////////////////////////////////////////////////////
  994. // Line function for 3D line.
  995. ////////////////////////////////////////////////////////////////////////////////
  996. inline
  997. void DrawLine3d( // Returns nothing.
  998. U8 u8Color, // Color to draw line with.
  999. RImage* pimDst, // Destination image.
  1000. short sDstX1, // Start pt.
  1001. short sDstY1, // Start pt.
  1002. short sDstZ1, // Start pt.
  1003. short sDstX2, // End pt.
  1004. short sDstY2, // End pt.
  1005. short sDstZ2, // End pt.
  1006. CHood* phood, // Da hood, homey.
  1007. RRect* prcDstClip) // Dst clip rect.
  1008. {
  1009. short s2dX1, s2dY1;
  1010. phood->Map3Dto2D(sDstX1, sDstY1, sDstZ1, &s2dX1, &s2dY1);
  1011. short s2dX2, s2dY2;
  1012. phood->Map3Dto2D(sDstX2, sDstY2, sDstZ2, &s2dX2, &s2dY2);
  1013. DrawLine2d(u8Color, pimDst, s2dX1, s2dY1, s2dX2, s2dY2, prcDstClip);
  1014. }
  1015. ////////////////////////////////////////////////////////////////////////////////
  1016. // Draw a 2D line.
  1017. ////////////////////////////////////////////////////////////////////////////////
  1018. void CScene::Line2D( // Returns nothing.
  1019. RImage* pimDst, // Destination image.
  1020. short sDstX, // Destination 2D x coord.
  1021. short sDstY, // Destination 2D y coord.
  1022. CSpriteLine2d* psl2, // Tree of sprites to render.
  1023. RRect* prcDstClip) // Dst clip rect.
  1024. {
  1025. DrawLine2d(
  1026. psl2->m_u8Color,
  1027. pimDst,
  1028. psl2->m_sX2 + sDstX,
  1029. psl2->m_sY2 + sDstY,
  1030. psl2->m_sX2End + sDstX,
  1031. psl2->m_sY2End + sDstY,
  1032. prcDstClip);
  1033. }
  1034. ////////////////////////////////////////////////////////////////////////////////
  1035. // Draw a 3D (as if there were another kind) cylinder.
  1036. // Actually, it draws a box from a cylinder description.
  1037. ////////////////////////////////////////////////////////////////////////////////
  1038. void CScene::RenderCylinder3D( // Returns nothing.
  1039. RImage* pimDst, // Destination image.
  1040. short sDstX, // Destination 2D x coord.
  1041. short sDstY, // Destination 2D y coord.
  1042. CSpriteCylinder3d* psc3, // Cylinder sprite.
  1043. CHood* phood, // Da hood, homey.
  1044. RRect* prcDstClip) // Dst clip rect.
  1045. {
  1046. short sX = sDstX + psc3->m_sX2;
  1047. short sZ = sDstY + psc3->m_sY2;
  1048. // Determine points.
  1049. short sX1 = sX - psc3->m_sRadius;
  1050. short sX2 = sX + psc3->m_sRadius;
  1051. short sY1 = 0;
  1052. short sY2 = psc3->m_sHeight;
  1053. short sZ1 = sZ - psc3->m_sRadius;
  1054. short sZ2 = sZ + psc3->m_sRadius;
  1055. // Base box.
  1056. DrawLine3d(
  1057. psc3->m_u8Color,
  1058. pimDst,
  1059. sX,
  1060. sY1,
  1061. sZ1,
  1062. sX2,
  1063. sY1,
  1064. sZ,
  1065. phood,
  1066. prcDstClip);
  1067. DrawLine3d(
  1068. psc3->m_u8Color,
  1069. pimDst,
  1070. sX2,
  1071. sY1,
  1072. sZ,
  1073. sX,
  1074. sY1,
  1075. sZ2,
  1076. phood,
  1077. prcDstClip);
  1078. DrawLine3d(
  1079. psc3->m_u8Color,
  1080. pimDst,
  1081. sX,
  1082. sY1,
  1083. sZ2,
  1084. sX1,
  1085. sY1,
  1086. sZ,
  1087. phood,
  1088. prcDstClip);
  1089. DrawLine3d(
  1090. psc3->m_u8Color,
  1091. pimDst,
  1092. sX1,
  1093. sY1,
  1094. sZ,
  1095. sX,
  1096. sY1,
  1097. sZ1,
  1098. phood,
  1099. prcDstClip);
  1100. // Top box.
  1101. DrawLine3d(
  1102. psc3->m_u8Color,
  1103. pimDst,
  1104. sX,
  1105. sY2,
  1106. sZ1,
  1107. sX2,
  1108. sY2,
  1109. sZ,
  1110. phood,
  1111. prcDstClip);
  1112. DrawLine3d(
  1113. psc3->m_u8Color,
  1114. pimDst,
  1115. sX2,
  1116. sY2,
  1117. sZ,
  1118. sX,
  1119. sY2,
  1120. sZ2,
  1121. phood,
  1122. prcDstClip);
  1123. DrawLine3d(
  1124. psc3->m_u8Color,
  1125. pimDst,
  1126. sX,
  1127. sY2,
  1128. sZ2,
  1129. sX1,
  1130. sY2,
  1131. sZ,
  1132. phood,
  1133. prcDstClip);
  1134. DrawLine3d(
  1135. psc3->m_u8Color,
  1136. pimDst,
  1137. sX1,
  1138. sY2,
  1139. sZ,
  1140. sX,
  1141. sY2,
  1142. sZ1,
  1143. phood,
  1144. prcDstClip);
  1145. // Height edges.
  1146. DrawLine3d(
  1147. psc3->m_u8Color,
  1148. pimDst,
  1149. sX,
  1150. sY1,
  1151. sZ1,
  1152. sX,
  1153. sY2,
  1154. sZ1,
  1155. phood,
  1156. prcDstClip);
  1157. DrawLine3d(
  1158. psc3->m_u8Color,
  1159. pimDst,
  1160. sX2,
  1161. sY1,
  1162. sZ,
  1163. sX2,
  1164. sY2,
  1165. sZ,
  1166. phood,
  1167. prcDstClip);
  1168. DrawLine3d(
  1169. psc3->m_u8Color,
  1170. pimDst,
  1171. sX,
  1172. sY1,
  1173. sZ2,
  1174. sX,
  1175. sY2,
  1176. sZ2,
  1177. phood,
  1178. prcDstClip);
  1179. DrawLine3d(
  1180. psc3->m_u8Color,
  1181. pimDst,
  1182. sX1,
  1183. sY1,
  1184. sZ,
  1185. sX1,
  1186. sY2,
  1187. sZ,
  1188. phood,
  1189. prcDstClip);
  1190. }
  1191. ////////////////////////////////////////////////////////////////////////////////
  1192. // Render a 2D sprite.
  1193. ////////////////////////////////////////////////////////////////////////////////
  1194. void CScene::Render2D( // Returns nothing.
  1195. RImage* pimDst, // Destination image.
  1196. short sDstX, // Destination 2D x coord.
  1197. short sDstY, // Destination 2D y coord.
  1198. CSprite2* ps2Cur, // Tree of sprites to render.
  1199. CHood* phood, // Da hood, homey.
  1200. RRect* prcDstClip, // Dst clip rect.
  1201. CSprite* psprXRayee) // XRayee, if not NULL.
  1202. {
  1203. // Make sure the stuff we need is there.
  1204. ASSERT(ps2Cur->m_pImage != NULL);
  1205. ASSERT(ps2Cur->m_sAlphaLevel >= 0);
  1206. ASSERT(ps2Cur->m_sAlphaLevel <= 255);
  1207. if (ps2Cur->m_pimAlpha != NULL && g_GameSettings.m_sAlphaBlend != FALSE)
  1208. {
  1209. // If the alpha level is not opaque . . .
  1210. if (ps2Cur->m_sAlphaLevel < 255)
  1211. {
  1212. // Do the Alpha Mask with adaptable alpha level blit.
  1213. rspGeneralAlphaBlit(
  1214. ps2Cur->m_sAlphaLevel, // Adaptable alpha level.
  1215. phood->m_pmaTransparency, // Levels multialpha table.
  1216. ps2Cur->m_pimAlpha, // Alpha mask.
  1217. ps2Cur->m_pImage, // Src.
  1218. pimDst, // Dst.
  1219. ps2Cur->m_sX2 + sDstX, // 2D Dst coord.
  1220. ps2Cur->m_sY2 + sDstY, // 2D Dst coord.
  1221. *prcDstClip); // Dst clip.
  1222. }
  1223. else
  1224. {
  1225. // Do the Alpha Mask blit.
  1226. rspGeneralAlphaBlit(
  1227. phood->m_pmaTransparency, // Levels multialpha table.
  1228. ps2Cur->m_pimAlpha, // Alpha mask.
  1229. ps2Cur->m_pImage, // Src.
  1230. pimDst, // Dst.
  1231. ps2Cur->m_sX2 + sDstX, // 2D Dst coord.
  1232. ps2Cur->m_sY2 + sDstY, // 2D Dst coord.
  1233. *prcDstClip); // Dst clip.
  1234. }
  1235. }
  1236. else
  1237. {
  1238. // If the alpha level is not opaque . . .
  1239. if (ps2Cur->m_sAlphaLevel < 255 && g_GameSettings.m_sAlphaBlend != FALSE)
  1240. {
  1241. // Do Homogeneous Alpha blit.
  1242. rspAlphaBlitT(
  1243. ps2Cur->m_sAlphaLevel, // Homogeneous alpha level.
  1244. phood->m_pmaTransparency, // Levels multialpha table.
  1245. ps2Cur->m_pImage, // Src.
  1246. pimDst, // Dst.
  1247. ps2Cur->m_sX2 + sDstX, // 2D Dst coord.
  1248. ps2Cur->m_sY2 + sDstY, // 2D Dst coord.
  1249. prcDstClip); // Dst clip.
  1250. }
  1251. else
  1252. {
  1253. // Determine which BLiT to use based on image type
  1254. if (ps2Cur->m_pImage->m_type == RImage::FSPR8)
  1255. {
  1256. // If this item is alpha OR this item is an opaque and we are
  1257. // xraying opaques AND there is an xrayee AND the xray effect is enabled,
  1258. // we need to see if the xray should be used via collision detection.
  1259. short sNormalBlit = 1;
  1260. #if 0 // The math equiv which appears to be slower than the confusing but
  1261. // similar compares. Also, the math allows none of the short circuiting
  1262. // that the C++ compares do.
  1263. short sUseXRay
  1264. = ( (ps2Cur->m_sInFlags & CSprite::InAlpha)
  1265. + ( (ps2Cur->m_sInFlags & CSprite::InOpaque)
  1266. * m_bXRayAll
  1267. )
  1268. )
  1269. * (long)psprXRayee
  1270. * ( g_GameSettings.m_sXRayEffect
  1271. + m_bXRayAll
  1272. )
  1273. ;
  1274. if (sUseXRay)
  1275. #else
  1276. if ( ( (ps2Cur->m_sInFlags & CSprite::InAlpha)
  1277. || ( (ps2Cur->m_sInFlags & CSprite::InOpaque)
  1278. && m_bXRayAll == true
  1279. )
  1280. )
  1281. && psprXRayee
  1282. &&
  1283. ( g_GameSettings.m_sXRayEffect != FALSE
  1284. || m_bXRayAll == true)
  1285. )
  1286. #endif
  1287. {
  1288. // Check if this sprite collides with the xrayee sprite. If so,
  1289. // we need to do draw this sprite with the xray effect so the
  1290. // xrayee(s) can be seen through it.
  1291. short sXRayeeW = phood->m_pimXRayMask->m_sWidth;
  1292. short sXRayeeH = phood->m_pimXRayMask->m_sHeight;
  1293. short sXRayeeX = psprXRayee->m_sX2; // Default to 2D blit location.
  1294. short sXRayeeY = psprXRayee->m_sY2; // Default to 2D blit location.
  1295. switch (psprXRayee->m_type)
  1296. {
  1297. case CSprite::Standard2d:
  1298. // Use default sXRayeeX, sXRayeeY.
  1299. break;
  1300. case CSprite::Standard3d:
  1301. {
  1302. // For ease of access.
  1303. CSprite3* ps3XRayee = (CSprite3*)psprXRayee;
  1304. sXRayeeX = ps3XRayee->m_sCenX - sXRayeeW / 2;
  1305. sXRayeeY = ps3XRayee->m_sCenY - sXRayeeH / 2;
  1306. break;
  1307. }
  1308. }
  1309. // Do an exteremely cheesy collision detecting by clipping the two rects!!!!
  1310. RRect rect1(sXRayeeX, sXRayeeY, sXRayeeW, sXRayeeH);
  1311. RRect rect2(ps2Cur->m_sX2, ps2Cur->m_sY2, ps2Cur->m_pImage->m_sWidth, ps2Cur->m_pImage->m_sHeight);
  1312. if (rect2.ClipTo(&rect1) != -1)
  1313. {
  1314. // Clear flag so he doesn't get drawn by normal blit
  1315. sNormalBlit = 0;
  1316. // Get coordinate in BUILDING coordinates (i.e., coords inside/realtive-to the building)
  1317. // for the alpha effect.
  1318. short sAlphaX = (sXRayeeX + sXRayeeW / 2 - phood->m_pimXRayMask->m_sWidth / 2) - ps2Cur->m_sX2;
  1319. short sAlphaY = (sXRayeeY + sXRayeeH / 2 - phood->m_pimXRayMask->m_sHeight / 2) - ps2Cur->m_sY2;
  1320. // Set position of alpha effect.
  1321. g_alphaBlit(
  1322. ps2Cur->m_pImage, // Source image.
  1323. pimDst, // Destination image.
  1324. phood->m_pimXRayMask, // Mask of alphable area.
  1325. phood->m_pmaTransparency, // Table of alphas or something.
  1326. sAlphaX, // Source coordinate in pimSrc to start blit.
  1327. sAlphaY, // Source coordinate in pimSrc to start blit.
  1328. ps2Cur->m_sX2 + sDstX, // Destination coordinate in pimDst for pimSrc(0,0).
  1329. ps2Cur->m_sY2 + sDstY, // Destination coordinate in pimDst for pimSrc(0,0).
  1330. *prcDstClip); // Rectangle to clip Dst to.
  1331. }
  1332. }
  1333. if (sNormalBlit)
  1334. {
  1335. // Transparent BLiT
  1336. rspBlit(
  1337. ps2Cur->m_pImage, // src
  1338. pimDst, // dst
  1339. ps2Cur->m_sX2 + sDstX, // map x to dst image
  1340. ps2Cur->m_sY2 + sDstY, // map y to dst image
  1341. prcDstClip); // dst clip
  1342. }
  1343. }
  1344. else
  1345. {
  1346. // Non-alpha BLiT
  1347. rspBlitT(
  1348. 0, // Src.
  1349. ps2Cur->m_pImage, // src
  1350. pimDst, // dst
  1351. 0, // src x
  1352. 0, // src y
  1353. ps2Cur->m_sX2 + sDstX, // dst x
  1354. ps2Cur->m_sY2 + sDstY, // dst y
  1355. ps2Cur->m_pImage->m_sWidth, // width
  1356. ps2Cur->m_pImage->m_sHeight, // height
  1357. prcDstClip, // dst clip
  1358. NULL); // Src clip.
  1359. }
  1360. }
  1361. }
  1362. }
  1363. ////////////////////////////////////////////////////////////////////////////////
  1364. // Render a sprite tree.
  1365. ////////////////////////////////////////////////////////////////////////////////
  1366. void CScene::Render( // Returns nothing.
  1367. RImage* pimDst, // Destination image.
  1368. short sDstX, // Destination 2D x coord.
  1369. short sDstY, // Destination 2D y coord.
  1370. CSprite* pSprite, // Tree of sprites to render.
  1371. CHood* phood, // Da hood, homey.
  1372. RRect* prcDstClip, // Dst clip rect.
  1373. CSprite* psprXRayee) // XRayee, if not NULL.
  1374. {
  1375. while (pSprite != NULL)
  1376. {
  1377. // Make sure sprite isn't hidden (if it is, skip it)
  1378. if (!(pSprite->m_sInFlags & CSprite::InHidden))
  1379. {
  1380. // Set flag to indicate sprite was rendered. As of right now, the sprite WILL
  1381. // be rendered if we get this far, but if the logic changes, the setting of
  1382. // this flag might need to be moved to somewhere else.
  1383. pSprite->m_sOutFlags |= CSprite::OutRendered;
  1384. // Determine whether this is a 2d or 3d sprite
  1385. switch (pSprite->m_type)
  1386. {
  1387. case CSprite::Standard2d:
  1388. {
  1389. // ****TEMP****
  1390. if (g_bSceneDontBlit == false)
  1391. {
  1392. // ****END TEMP****
  1393. Render2D( // Returns nothing.
  1394. pimDst, // Destination image.
  1395. sDstX, // Destination 2D x coord.
  1396. sDstY, // Destination 2D y coord.
  1397. (CSprite2*)pSprite, // Tree of sprites to render.
  1398. phood, // Da hood, homey.
  1399. prcDstClip, // Dst clip rect.
  1400. psprXRayee); // XRayee, if not NULL.
  1401. // ****TEMP****
  1402. }
  1403. // ****END TEMP****
  1404. break; // CSprite::Standard2d.
  1405. }
  1406. case CSprite::Standard3d: // *** g_bSceneDontBlit is checked inside Render3D() 10/03/99 ***
  1407. Render3D( // Returns happy thoughts.
  1408. pimDst, // Destination image.
  1409. sDstX, // Destination 2D x coord.
  1410. sDstY, // Destination 2D y coord.
  1411. (CSprite3*)pSprite, // Tree of 3D sprites to render.
  1412. phood, // Da hood, homey.
  1413. prcDstClip); // Dst clip rect.
  1414. break; // CSprite::Standard3d.
  1415. case CSprite::Line2d:
  1416. {
  1417. // ****TEMP****
  1418. if (g_bSceneDontBlit == false)
  1419. {
  1420. // ****END TEMP****
  1421. Line2D( // Returns nothing.
  1422. pimDst, // Destination image.
  1423. sDstX, // Destination 2D x coord.
  1424. sDstY, // Destination 2D y coord.
  1425. (CSpriteLine2d*)pSprite, // Tree of sprites to render.
  1426. prcDstClip); // Dst clip rect.
  1427. // ****TEMP****
  1428. }
  1429. // ****END TEMP****
  1430. break;
  1431. }
  1432. case CSprite::Cylinder3d:
  1433. {
  1434. // ****TEMP****
  1435. if (g_bSceneDontBlit == false)
  1436. {
  1437. // ****END TEMP****
  1438. RenderCylinder3D( // Returns nothing.
  1439. pimDst, // Destination image.
  1440. sDstX, // Destination 2D x coord.
  1441. sDstY, // Destination 2D y coord.
  1442. (CSpriteCylinder3d*)pSprite, // Cylinder sprite.
  1443. phood, // Da hood, homey.
  1444. prcDstClip); // Dst clip rect.
  1445. // ****TEMP****
  1446. }
  1447. // ****END TEMP****
  1448. break;
  1449. }
  1450. }
  1451. // ****TEMP****
  1452. if (g_bSceneDontBlit == false)
  1453. {
  1454. // ****END TEMP****
  1455. // If there's some text . . .
  1456. if (pSprite->m_pszText != NULL)
  1457. {
  1458. // Bind it.
  1459. short sX = pSprite->m_sX2 + sDstX;
  1460. short sY = pSprite->m_sY2 + sDstY;
  1461. short sW = prcDstClip->sX + prcDstClip->sW - sX;
  1462. short sH = prcDstClip->sY + prcDstClip->sH - sY;
  1463. if (sW > 0 && sH > 0)
  1464. {
  1465. ms_print.SetColumn(
  1466. sX,
  1467. sY,
  1468. sW,
  1469. sH);
  1470. // Print it.
  1471. ms_print.print(
  1472. sX, sY,
  1473. "%s",
  1474. pSprite->m_pszText);
  1475. }
  1476. }
  1477. // ****TEMP****
  1478. }
  1479. // ****END TEMP****
  1480. // If this sprite has any children . . .
  1481. if (pSprite->m_psprHeadChild != NULL)
  1482. {
  1483. Render( // Returns nothing.
  1484. pimDst, // Destination image.
  1485. sDstX + pSprite->m_sX2, // Destination 2D x coord.
  1486. sDstY + pSprite->m_sY2, // Destination 2D y coord.
  1487. pSprite->m_psprHeadChild, // Tree of sprites to render.
  1488. phood, // Da hood, homey.
  1489. prcDstClip, // Dst clip rect.
  1490. psprXRayee); // XRayee, if not NULL.
  1491. }
  1492. }
  1493. // Get sibling.
  1494. pSprite = pSprite->m_psprNext;
  1495. }
  1496. }
  1497. ////////////////////////////////////////////////////////////////////////////////
  1498. // Render specified area of scene into specified image
  1499. ///////////////////////////////////////////////////////////////////////////////
  1500. void CScene::Render(
  1501. short sSrcX, // In: Source (scene) x coord
  1502. short sSrcY, // In: Source (scene) y coord
  1503. short sW, // In: Width
  1504. short sH, // In: Height
  1505. RImage* pimDst, // In: Destination image
  1506. short sDstX, // In: Destination (image) x coord
  1507. short sDstY, // In: Destination (image) y coord
  1508. CHood* phood) // In: The hood involved.
  1509. {
  1510. // Init dst clipping rect
  1511. RRect rDstClip(sDstX, sDstY, sW, sH);
  1512. // Clip the dst clipping rect to the image size (in case image is smaller)
  1513. RRect rImageSize(0, 0, pimDst->m_sWidth, pimDst->m_sHeight);
  1514. rDstClip.ClipTo(&rImageSize);
  1515. ms_print.SetDestination(pimDst, &rDstClip);
  1516. // Calculate mapping from scene to image coords
  1517. short sMapX = sSrcX - sDstX;
  1518. short sMapY = sSrcY - sDstY;
  1519. CSprite* psprXRayee = NULL; // XRayee when not NULL.
  1520. // Go through all the layers, back to front
  1521. for (short sLayer = 0; sLayer < m_sNumLayers; sLayer++)
  1522. {
  1523. // Get pointer to layer (more readable)
  1524. Layer* pLayer = &m_pLayers[sLayer];
  1525. // Make sure layer isn't hidden (if it is, skip it)
  1526. if (!(pLayer->m_bHidden))
  1527. {
  1528. // Go through all the sprites stored in this layer
  1529. for (msetSprites::iterator iSprite = pLayer->m_sprites.begin(); iSprite != pLayer->m_sprites.end(); )
  1530. {
  1531. // Get pointer to sprite (more readable than iterator dereference and may optimize better)
  1532. CSprite* pSprite = *iSprite;
  1533. Render( // Returns nothing.
  1534. pimDst, // Destination image.
  1535. -sMapX, // Destination 2D x coord.
  1536. -sMapY, // Destination 2D y coord.
  1537. pSprite, // Tree of sprites to render.
  1538. phood, // Da hood, homey.
  1539. &rDstClip, // Dst clip rect.
  1540. psprXRayee); // XRayee, if not NULL.
  1541. // Move to next item before deleting this one.
  1542. iSprite++;
  1543. // If this sprite wanted to be deleted after use . . .
  1544. if (pSprite->m_sInFlags & CSprite::InDeleteOnRender)
  1545. {
  1546. RemoveSprite(pSprite);
  1547. // Be gone, vile weed.
  1548. delete pSprite;
  1549. }
  1550. else
  1551. {
  1552. // If this sprite is an xrayee, add it to the container
  1553. if (pSprite->m_sInFlags & CSprite::InXrayee)
  1554. {
  1555. psprXRayee = pSprite;
  1556. }
  1557. }
  1558. }
  1559. }
  1560. }
  1561. }
  1562. ////////////////////////////////////////////////////////////////////////////////
  1563. // Setup render pipeline. Use this function to setup or alter the pipeline.
  1564. // This function DOES a Make1() and then multiplies by the supplied transform,
  1565. // if any. Any transforms that need to be applied after this setup can be
  1566. // done following a call to this function.
  1567. // The only sux is you cannot insert yourself into the middle of this function.
  1568. // If that's what you need, you should probably just do the entire setup for
  1569. // the pipe yourself or add a similar function to this one.
  1570. ////////////////////////////////////////////////////////////////////////////////
  1571. void CScene::SetupPipeline( // Returns nothing.
  1572. RTransform* ptrans /*= NULL*/, // Transform to apply before doing defaults.
  1573. RTransform* ptransScene2Realm /*= NULL*/, // Transform to convert from scene to realm.
  1574. double dScale3d /*= 0.0*/) // In: New scaling to apply to pipeline (see
  1575. // m_dScale3d declaration).
  1576. {
  1577. /////////////////////////////////////////////////////////////////////////////
  1578. // This portion was previously done in UpdatePipeline().
  1579. /////////////////////////////////////////////////////////////////////////////
  1580. // Adjust the current pipeline to account for the case when we've
  1581. // loaded a new hood which may have a different 3d scaling for
  1582. // the 3d characters. This effects both the pipeline and the
  1583. // smashatorium!
  1584. /////////////////////////////////////////////////////////////////////////////
  1585. // Some extra safety
  1586. if (dScale3d <= c_dMinScale) dScale3d = c_dMinScale;
  1587. if (dScale3d > c_dMaxScale) dScale3d = c_dMaxScale;
  1588. ASSERT( (dScale3d >= c_dMinScale) && (dScale3d <= c_dMaxScale) );
  1589. // Strap onto the old methods:
  1590. m_dScale3d = dScale3d;
  1591. // Use the built in adjustment features of the pipeline:
  1592. if (m_pipeline.Create(1000, SCREEN_DIAMETER_FOR_3D) != 0)
  1593. TRACE("SetupPipeline(): FONGOOL! m_pipeline.Create() failed! No 3D for you!\n");
  1594. /////////////////////////////////////////////////////////////////////////////
  1595. // End previously done in UpdatePipeline().
  1596. /////////////////////////////////////////////////////////////////////////////
  1597. // Re-init (Renit) the pipeline.
  1598. m_pipeline.m_tView.Make1(); // Identity.
  1599. m_pipeline.m_tScreen.Make1(); // Identity.
  1600. m_transNoZView.Make1(); // Identity.
  1601. m_transNoZScreen.Make1(); // Identity.
  1602. // If there is a user transform . . .
  1603. if (ptrans != NULL)
  1604. {
  1605. // Apply now. Ok. Close.
  1606. m_pipeline.m_tView.PreMulBy(ptrans->T);
  1607. }
  1608. // If there is a conversion transform . . .
  1609. if (ptransScene2Realm != NULL)
  1610. {
  1611. m_transScene2Realm = *ptransScene2Realm;
  1612. }
  1613. else
  1614. {
  1615. m_transScene2Realm.Make1();
  1616. }
  1617. ////////////////////////////////////////////////////////
  1618. // Stolen from the famous 3D e-letters by Jeff Diamond.
  1619. // We use this to get from SoftImage to Postal coord
  1620. // system.
  1621. ////////////////////////////////////////////////////////
  1622. // OK, this is a bit more professional way to do it:
  1623. short sScreenSize = SCREEN_DIAMETER_FOR_3D; // diameter in pixels;
  1624. // short sScreenRadius = sScreenSize>>1;
  1625. double dModelSize = MODEL_DIAMETER; // diameter in Randy's coordinates
  1626. double dModelRadius = 0.5 * dModelSize;
  1627. // Flipping the image in the view was a bad hack, bacause it
  1628. // changes the direction of rotation about the axis:
  1629. // m_pipe.m_tView.Scale(1.0,-1.0,1.0); // DON'T DO!
  1630. // Just put the Randy origin in the center of the cube:
  1631. m_pipeline.m_tView.Trans(dModelRadius, dModelRadius, 0.0);
  1632. // Mimic this in transform that contains no Z scaling.
  1633. m_transNoZView.Trans(dModelRadius, dModelRadius, 0.0);
  1634. // Then, to project to the screen, need to FIRST scale it,
  1635. // THEN flip it about y=0, and FINALLY slide it back down sp
  1636. // we can see it. (Luckily, when you're down it's still a single
  1637. // matrix, so it's no slower than anything else you might do.
  1638. // Also, stretch out the z-coordinate to take full advantage of the
  1639. // 16-bit z-buffer
  1640. //
  1641. m_pipeline.m_tScreen.Scale(
  1642. double(sScreenSize) / dModelSize,
  1643. double(sScreenSize) / dModelSize,
  1644. REAL(65535.0 / MODEL_ZSPAN)); // Use MODEL_ZSPAN for consistent fog thickness
  1645. // Mimic this in transform that contains no Z scaling.
  1646. m_transNoZScreen.Scale(
  1647. double(sScreenSize) / dModelSize,
  1648. double(sScreenSize) / dModelSize,
  1649. double(sScreenSize) / dModelSize);
  1650. // Now offset the image and flip the y-coordinate:
  1651. m_pipeline.m_tScreen.Scale(1.0,-1.0,1.0); // mirror vertically about (y=0)
  1652. // Mimic this in transform that contains no Z scaling.
  1653. m_transNoZScreen.Scale(1.0, -1.0, 1.0);
  1654. m_pipeline.m_tScreen.Trans(0.0,sScreenSize,0.0); // slide down the screen
  1655. // Mimic this in transform that contains no Z scaling.
  1656. m_transNoZScreen.Trans(0.0,sScreenSize,0.0);
  1657. ////////////////////////////////////////////////////////
  1658. // More transforms can be applied to either of the
  1659. // pipeline's transforms after this function exits, if
  1660. // so desired.
  1661. ////////////////////////////////////////////////////////
  1662. }
  1663. ////////////////////////////////////////////////////////////////////////////////
  1664. // Transform the given points through the CScene's pipeline with the
  1665. // supplied transform.
  1666. ////////////////////////////////////////////////////////////////////////////////
  1667. void CScene::TransformPts( // Returns nothing.
  1668. RTransform* ptrans, // In: Transformation to apply to CScene's before
  1669. // transforming pts.
  1670. RP3d* p3dPtsSrc, // In: Ptr to group of pts to transform from.
  1671. RP3d* p3dPtsDst, // Out: Ptr to group of pts to transform into.
  1672. short sNum) // In: The number of pts in p3dPtsSrc to transform.
  1673. {
  1674. // Let's try to be nice and let the user call us all the time.
  1675. // That is, check if there's anything to do before wasting any time . . .
  1676. if (sNum > 0)
  1677. {
  1678. RTransform transApplied; // Auto-identitied.
  1679. // If there is a user transformation . . .
  1680. if (ptrans != NULL)
  1681. {
  1682. // Create scene-user transform:
  1683. // Apply user to view.
  1684. transApplied.Mul(m_transNoZView.T, ptrans->T);
  1685. // Apply user-view to screen (store in user-view).
  1686. transApplied.PreMulBy(m_transNoZScreen.T);
  1687. }
  1688. else
  1689. {
  1690. // Create plain scene transform:
  1691. // Apply view to screen (store in scene transform).
  1692. transApplied.Mul(m_transNoZScreen.T, m_transNoZView.T);
  1693. }
  1694. // Translate points
  1695. short sCur;
  1696. // Note that this could save a fraction of a miniscule(sp?) moment by being
  1697. // a do { } while since we know sNum > 0, but fongooey.
  1698. for (sCur = 0; sCur < sNum; sCur++)
  1699. {
  1700. transApplied.TransformInto(*p3dPtsSrc++, *p3dPtsDst++);
  1701. }
  1702. }
  1703. }
  1704. ////////////////////////////////////////////////////////////////////////////////
  1705. // Transform the given points through the CScene's pipeline with the
  1706. // supplied transform and then map them to Realm 3D coordinates.
  1707. ////////////////////////////////////////////////////////////////////////////////
  1708. void CScene::TransformPtsToRealm( // Returns nothing.
  1709. RTransform* ptrans, // In: Transformation to apply to CScene's before
  1710. // transforming pts.
  1711. RP3d* p3dPtsSrc, // In: Ptr to group of pts to transform from.
  1712. RP3d* p3dPtsDst, // Out: Ptr to group of pts to transform into.
  1713. short sNum) // In: The number of pts in p3dPtsSrc to transform.
  1714. {
  1715. #if 0 // This doesn't work.
  1716. RTransform trans;
  1717. // If there is a user transform . . .
  1718. if (ptrans != NULL)
  1719. {
  1720. // Combine the caller's with the conversion.
  1721. trans.Mul(m_transScene2Realm.T, ptrans->T);
  1722. // Use new transform.
  1723. ptrans = &trans;
  1724. }
  1725. else
  1726. {
  1727. // Use the conversion transform.
  1728. ptrans = &m_transScene2Realm;
  1729. }
  1730. #endif
  1731. // Map to scene.
  1732. TransformPts(ptrans, p3dPtsSrc, p3dPtsDst, sNum);
  1733. // Translate to Postal Realm coords.
  1734. short i;
  1735. for (i = 0; i < sNum; i++)
  1736. {
  1737. p3dPtsDst->x -= SCREEN_DIAMETER_FOR_3D / 2;
  1738. p3dPtsDst->y = -(p3dPtsDst->y - SCREEN_DIAMETER_FOR_3D / 2);
  1739. // No Z mapping.
  1740. // p3dPtsDst->z = p3dPtsDst->z;
  1741. p3dPtsDst++;
  1742. }
  1743. }
  1744. ////////////////////////////////////////////////////////////////////////////////
  1745. // Render a 3D sprite tree into the specified image.
  1746. // Ignores non 3D sprites.
  1747. ////////////////////////////////////////////////////////////////////////////////
  1748. void CScene::DeadRender3D( // Returns nothing.
  1749. RImage* pimDst, // Destination image.
  1750. CSprite3* ps3, // Tree of 3D sprites to render.
  1751. CHood* phood, // Da hood, homey.
  1752. short sDstX /*= 0*/, // Destination 2D x coord.
  1753. short sDstY /*= 0*/, // Destination 2D y coord.
  1754. RRect* prcDstClip /*= NULL*/) // Dst clip rect.
  1755. {
  1756. // Make sure sprite isn't hidden (if it is, skip it)
  1757. if (!(ps3->m_sInFlags & CSprite::InHidden))
  1758. {
  1759. ASSERT(pimDst != NULL);
  1760. ASSERT(ps3 != NULL);
  1761. ASSERT(phood != NULL);
  1762. RRect rcClip;
  1763. // If no clipping rect specified . . .
  1764. if (prcDstClip == NULL)
  1765. {
  1766. prcDstClip = &rcClip;
  1767. rcClip.sX = 0;
  1768. rcClip.sY = 0;
  1769. rcClip.sW = pimDst->m_sWidth;
  1770. rcClip.sH = pimDst->m_sHeight;
  1771. }
  1772. #if 1
  1773. // Render.
  1774. Render3D(
  1775. pimDst, // Destination image.
  1776. sDstX, // Destination 2D x coord.
  1777. sDstY, // Destination 2D y coord.
  1778. ps3, // Tree of 3D sprites to render.
  1779. phood, // Da hood, homey.
  1780. prcDstClip); // Dst clip rect.
  1781. // Call for all children . . .
  1782. CSprite* psprite = ps3->m_psprHeadChild;
  1783. while (psprite)
  1784. {
  1785. // If 3D child and visible . . .
  1786. if (psprite->m_type == CSprite::Standard3d)
  1787. {
  1788. // Render 'em.
  1789. DeadRender3D(
  1790. pimDst,
  1791. (CSprite3*)psprite,
  1792. phood,
  1793. sDstX + ps3->m_sX2,
  1794. sDstY + ps3->m_sY2,
  1795. prcDstClip);
  1796. }
  1797. // Next, please.
  1798. psprite = psprite->m_psprNext;
  1799. }
  1800. #else
  1801. Render( // Returns nothing.
  1802. pimDst, // Destination image.
  1803. 0, // Destination 2D x coord.
  1804. 0, // Destination 2D y coord.
  1805. ps3, // Tree of sprites to render.
  1806. phood, // Da hood, homey.
  1807. prcDstClip, // Dst clip rect.
  1808. NULL); // XRayee, if not NULL.
  1809. #endif
  1810. }
  1811. }
  1812. ////////////////////////////////////////////////////////////////////////////////
  1813. // Set all 'alpha' _and_ 'opaque' layers to xray.
  1814. ////////////////////////////////////////////////////////////////////////////////
  1815. void CScene::SetXRayAll( // You see a door to the north. Returns nothing.
  1816. bool bXRayAll) // In: true to X Ray all 'alpha' _and_ 'opaque' layers.
  1817. {
  1818. m_bXRayAll = bXRayAll;
  1819. }
  1820. ////////////////////////////////////////////////////////////////////////////////
  1821. // EOF
  1822. ////////////////////////////////////////////////////////////////////////////////