W3DVolumetricShadow.cpp 131 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952
  1. /*
  2. ** Command & Conquer Generals(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. ////////////////////////////////////////////////////////////////////////////////
  19. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. // FILE: W3DVolumetricShadow.cpp ///////////////////////////////////////////////////////////
  24. //
  25. // Real time shadow volume representations
  26. //
  27. // Author: Colin Day, January 2001
  28. // Adapted for W3D: Mark Wilczynski October 2001
  29. //
  30. //
  31. ///////////////////////////////////////////////////////////////////////////////
  32. ///@todo: Must cap shadow volumes if we ever allow camera inside the volumes.
  33. ///@todo: Find better way to determine when shadow volumes need updating - lights move, objects move.
  34. // SYSTEM INCLUDES ////////////////////////////////////////////////////////////
  35. #include <assert.h>
  36. // USER INCLUDES //////////////////////////////////////////////////////////////
  37. #include "always.h"
  38. #include "GameClient/View.h"
  39. #include "WW3D2/Camera.h"
  40. #include "WW3D2/Light.h"
  41. #include "WW3D2/DX8Wrapper.h"
  42. #include "WW3D2/HLod.h"
  43. #include "WW3D2/mesh.h"
  44. #include "WW3D2/meshmdl.h"
  45. #include "Lib/BaseType.h"
  46. #include "W3DDevice/GameClient/W3DGranny.h"
  47. #include "W3DDevice/GameClient/Heightmap.h"
  48. #include "D3dx8math.h"
  49. #include "common/GlobalData.h"
  50. #include "common/drawmodule.h"
  51. #include "W3DDevice/GameClient/W3DVolumetricShadow.h"
  52. #include "W3DDevice/GameClient/W3DShadow.h"
  53. #include "WW3D2/statistics.h"
  54. #include "GameLogic/TerrainLogic.h"
  55. #include "WW3D2/DX8Caps.h"
  56. #include "GameClient/Drawable.h"
  57. #ifdef _INTERNAL
  58. // for occasional debugging...
  59. //#pragma optimize("", off)
  60. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  61. #endif
  62. // Global Variables and Functions /////////////////////////////////////////////
  63. W3DVolumetricShadowManager *TheW3DVolumetricShadowManager=NULL;
  64. extern const FrustumClass *shadowCameraFrustum; //defined in W3DShadow.
  65. ///////////////////////////////////////////////////////////////////////////////
  66. // DEFINITIONS ////////////////////////////////////////////////////////////////
  67. ///////////////////////////////////////////////////////////////////////////////
  68. // when the change in angle from the object to the light source
  69. // (represented in degrees in the first number below)
  70. // is large enough the shadow info will be reconstructed
  71. const Real cosAngleToCare = cos ((0.2 * PI) / 180.0); //1.5 degree difference
  72. #define MAX_SILHOUETTE_EDGES 1024 //maximum number of shadov volume sides or edges in silhoutte
  73. #define SHADOW_EXTRUSION_BUFFER 0.1f //amount to extend shadow volume beyond what's required to hit ground.
  74. #define AIRBORNE_UNIT_GROUND_DELTA 2.0f
  75. #define MAX_SHADOW_LENGTH_SCALE_FACTOR 1.0f //amount shadow can extend beyond the objects normal bounding sphere
  76. #define MAX_SHADOW_LENGTH_EXTRA_AIRBORNE_SCALE_FACTOR 1.5f //scales MAX_SHADOW_LENGTH_SCALE_FACTOR a little more for flying units
  77. #define MAX_EXTRUSION_LENGTH (512.0f*MAP_XY_FACTOR) //maximum length of a shadow extrusion - assumed as 512x512 cell map for now.
  78. #define MAX_SHADOW_EXTRUSION_UNDER_OBJECT_BEFORE_CLAMP 5.0f //maximum amount that shadow can reach below object base (z-position) before we clamp it's length to reduce artifacts.
  79. #define SHADOW_SAMPLING_INTERVAL (MAP_XY_FACTOR * 2.0f) //stepsize along ray used to find lowest point on terrain within shadow's reach.
  80. #define OVERHANGING_OBJECT_CLAMP_ANGLE (80.0f/180.0f*PI) //for objects that are right on a cliff edge, clamp light angle to cast a nearly vertical shadow.
  81. //#define SV_DEBUG
  82. //#define SV_DEBUG_BOUNDS
  83. struct SHADOW_STATIC_VOLUME_VERTEX //vertex structure passed to D3D
  84. {
  85. float x,y,z;
  86. };
  87. #define SHADOW_STATIC_VOLUME_FVF D3DFVF_XYZ
  88. #ifdef SV_DEBUG //in debug mode, dynamic shadows are rendered with random diffuse color
  89. struct SHADOW_DYNAMIC_VOLUME_VERTEX //vertex structure passed to D3D
  90. {
  91. float x,y,z;
  92. DWORD diffuse;
  93. };
  94. #define SHADOW_DYNAMIC_VOLUME_FVF D3DFVF_XYZ|D3DFVF_DIFFUSE
  95. #else
  96. typedef struct SHADOW_STATIC_VOLUME_VERTEX SHADOW_DYNAMIC_VOLUME_VERTEX;
  97. #define SHADOW_DYNAMIC_VOLUME_FVF D3DFVF_XYZ
  98. #endif
  99. LPDIRECT3DVERTEXBUFFER8 shadowVertexBufferD3D=NULL; ///<D3D vertex buffer
  100. LPDIRECT3DINDEXBUFFER8 shadowIndexBufferD3D=NULL; ///<D3D index buffer
  101. int nShadowVertsInBuf=0; //model vetices in vertex buffer
  102. int nShadowStartBatchVertex=0;
  103. int nShadowIndicesInBuf=0; //model vetices in vertex buffer
  104. int nShadowStartBatchIndex=0;
  105. int SHADOW_VERTEX_SIZE=4096;
  106. int SHADOW_INDEX_SIZE=8192;
  107. //Rough bounding box around visible portion of the terrain
  108. //useful for quick culling
  109. static Real bcX;
  110. static Real bcY;
  111. static Real bcZ;
  112. static Real beX;
  113. static Real beY;
  114. static Real beZ;
  115. static LPDIRECT3DVERTEXBUFFER8 lastActiveVertexBuffer=NULL;
  116. /** A simple structure to hold random geometry (vertices, polygons, etc.). We'll use this
  117. * to store shadow volumes. */
  118. struct Geometry
  119. {
  120. enum VisibleState {
  121. STATE_UNKNOWN = CollisionMath::BOTH,
  122. STATE_VISIBLE = CollisionMath::INSIDE,
  123. STATE_INVISIBLE = CollisionMath::OUTSIDE,
  124. };
  125. Geometry(void) : m_verts(NULL),m_indices(NULL),m_numPolygon(0),m_numVertex(0),m_flags(0) {}
  126. ~Geometry(void) { Release();}
  127. Int Create( Int numVertices, Int numPolygons )
  128. {
  129. if (numVertices)
  130. if((m_verts=NEW Vector3[numVertices]) == 0)
  131. return FALSE;
  132. if (numPolygons)
  133. if((m_indices=NEW UnsignedShort[numPolygons*3]) == 0)
  134. return FALSE;
  135. m_numPolygon=numPolygons;
  136. m_numVertex=numVertices;
  137. m_numActivePolygon=0;
  138. m_numActiveVertex=0;
  139. return TRUE;
  140. }
  141. void Release(void)
  142. { if (m_verts)
  143. { delete [] m_verts;
  144. m_verts=NULL;
  145. }
  146. if (m_indices)
  147. { delete [] m_indices;
  148. m_indices=NULL;
  149. }
  150. m_numActivePolygon=m_numPolygon=0;
  151. m_numActiveVertex=m_numVertex=0;
  152. }
  153. Int GetFlags (void) { return m_flags;}
  154. void SetFlags (Int flags) { m_flags = flags;}
  155. Int GetNumPolygon (void) { return m_numPolygon;}
  156. Int GetNumVertex (void) { return m_numVertex;}
  157. Int GetNumActivePolygon (void) { return m_numActivePolygon;}
  158. Int GetNumActiveVertex (void) { return m_numActiveVertex;}
  159. Int SetNumActivePolygon (Int numPolygons) { return m_numActivePolygon=numPolygons;}
  160. Int SetNumActiveVertex (Int numVertices) { return m_numActiveVertex=numVertices;}
  161. UnsignedShort *GetPolygonIndex (long dwPolyId, short *psIndexList, int dwNSize) const
  162. {
  163. *psIndexList++ = m_indices[dwPolyId*3];
  164. *psIndexList++ = m_indices[dwPolyId*3+1];
  165. *psIndexList++ = m_indices[dwPolyId*3+2];
  166. return &m_indices[dwPolyId];
  167. }
  168. Int SetPolygonIndex (long dwPolyId, short *psIndexList, int dwNSize)
  169. {
  170. m_indices[dwPolyId*3]=psIndexList[0];
  171. m_indices[dwPolyId*3+1]=psIndexList[1];
  172. m_indices[dwPolyId*3+2]=psIndexList[2];
  173. return 3;
  174. }
  175. Vector3 *GetVertex (int dwVertId)
  176. {
  177. return &m_verts[dwVertId];
  178. }
  179. Vector3 *SetVertex (int dwVertId, Vector3 *pvVertex)
  180. {
  181. m_verts[dwVertId]=*pvVertex;
  182. return pvVertex;
  183. }
  184. ///Find a vertex within given range
  185. Int FindVertexInRange (Int start, Int end, Vector3 *pvVertex)
  186. {
  187. for (Int i=start; i<end; i++)
  188. {
  189. if ((m_verts[i]-*pvVertex).Length2() == 0)
  190. return i;
  191. }
  192. return -1;
  193. }
  194. AABoxClass &getBoundingBox(void) {return m_boundingBox;}
  195. void setBoundingBox(const AABoxClass &box) {m_boundingBox=box;}
  196. void setBoundingSphere(const SphereClass &sphere) {m_boundingSphere=sphere;}
  197. SphereClass &getBoundingSphere(void) {return m_boundingSphere;}
  198. void setVisibleState(VisibleState state) {m_visibleState=state;}
  199. VisibleState getVisibleState(void) {return m_visibleState;}
  200. private:
  201. Vector3 *m_verts;
  202. UnsignedShort *m_indices;
  203. Int m_numPolygon;
  204. Int m_numVertex;
  205. Int m_numActivePolygon; ///<number of polygons filled with valid data
  206. Int m_numActiveVertex; ///<number of vertices filled with valid data
  207. Int m_flags; ///<geometry attribute flags - static vs. dynamic, etc.
  208. AABoxClass m_boundingBox; ///<object space bounding box of shadow volume
  209. SphereClass m_boundingSphere; ///<object space bounding sphere of shadow volume
  210. VisibleState m_visibleState; ///<flag if this geometry was visible in this frame.
  211. };
  212. // CONST //////////////////////////////////////////////////////////////////////
  213. const Int MAX_POLYGON_NEIGHBORS = 3; // we use nothing but triangles for
  214. // geometry polygons so we have at
  215. // most 3 neighbors
  216. const Int NO_NEIGHBOR = -1; // entry value for neighbor when there isn't one
  217. const Byte POLY_VISIBLE = 0x01; // polygon is visible from light
  218. const Byte POLY_PROCESSED = 0x02; // this poly has been processed
  219. // STRUCT /////////////////////////////////////////////////////////////////////
  220. // NeighborEdge ---------------------------------------------------------------
  221. typedef struct _NeighborEdge
  222. {
  223. Short neighborIndex; // index of polygon who is our neighbor, if there is
  224. // not a neighbor it contains NO_NEIGHBOR
  225. Short neighborEdgeIndex[ 2 ]; // the two vertex indices that represent the
  226. // shared edge
  227. } NeighborEdge;
  228. // PolygonNeighbor ------------------------------------------------------------
  229. struct PolyNeighbor
  230. {
  231. Short myIndex; // our polygon index so we know who we are
  232. Byte status; // status flags used when processing neighbors
  233. NeighborEdge neighbor[ MAX_POLYGON_NEIGHBORS ];
  234. };
  235. /**This class holds original mesh specific data and geometry. The meshes stored in this
  236. class have been cleaned to remove replicated vertices and also cache mesh data needed for
  237. faster silhouette computation. A model can contain many meshes for which we need to store
  238. separate data so they can move relative to each other.*/
  239. class W3DShadowGeometryMesh
  240. {
  241. //for the sake of speed, give direct access to classes that need this data.
  242. friend class W3DShadowGeometry;
  243. friend class W3DVolumetricShadow;
  244. public:
  245. W3DShadowGeometryMesh::W3DShadowGeometryMesh( void );
  246. W3DShadowGeometryMesh::~W3DShadowGeometryMesh( void );
  247. /// @todo: Cache/Store face normals someplace so they are not recomputed when lights move.
  248. Vector3 *GetPolygonNormal (long dwPolyNormId, Vector3 *pvNorm)
  249. {
  250. if (m_polygonNormals)
  251. return &(*pvNorm=m_polygonNormals[dwPolyNormId]);
  252. short indexList[3];
  253. Vector3 vertexList[3];
  254. //get vertex indices for this polygon
  255. GetPolygonIndex(dwPolyNormId,indexList,3);
  256. //get the vertices
  257. GetVertex(indexList[0],&vertexList[0]);
  258. GetVertex(indexList[1],&vertexList[1]);
  259. GetVertex(indexList[2],&vertexList[2]);
  260. //compute triangle normal by crossing 2 edges
  261. Vector3 edge1=vertexList[1]-vertexList[0];
  262. Vector3 edge2=vertexList[1]-vertexList[2];
  263. #ifdef ALLOW_TEMPORARIES
  264. *pvNorm=Vector3::Cross_Product(edge2,edge1);
  265. pvNorm->Normalize();
  266. #else
  267. Vector3::Normalized_Cross_Product(edge2,edge1, pvNorm);
  268. #endif
  269. return pvNorm;
  270. }
  271. int GetNumPolygon (void) const {return m_numPolygons;}
  272. /// given loaded geometry this builds the polygon neighbor information
  273. void buildPolygonNeighbors( void );
  274. void buildPolygonNormals(void)
  275. {
  276. if (!m_polygonNormals)
  277. { //need to allocate storage
  278. Vector3 *tempVec = NEW Vector3[m_numPolygons];
  279. for (int i=0; i<m_numPolygons; i++)
  280. {
  281. GetPolygonNormal(i,&tempVec[i]);
  282. }
  283. m_polygonNormals = tempVec;
  284. }
  285. }
  286. protected:
  287. /// creating and deleting storage for the polygon neighbors
  288. Bool allocateNeighbors( Int numPolys );
  289. void deleteNeighbors( void );
  290. // geometry shadow data access
  291. PolyNeighbor *GetPolyNeighbor( Int polyIndex );
  292. int GetNumVertex (void) { return m_numVerts;}
  293. ///Get indices to the 3 vertices of this face.
  294. virtual int GetPolygonIndex (long dwPolyId, short *psIndexList, int dwNSize) const
  295. { const Vector3i *polyi=&m_polygons[dwPolyId];
  296. *psIndexList++ = m_parentVerts[polyi->I];
  297. *psIndexList++ = m_parentVerts[polyi->J];
  298. *psIndexList++ = m_parentVerts[polyi->K];
  299. return 3;
  300. }
  301. virtual Vector3 *GetVertex (int dwVertId, Vector3 *pvVertex)
  302. {
  303. *pvVertex=m_verts[dwVertId];
  304. return pvVertex;
  305. }
  306. MeshClass *m_mesh; ///< W3D mesh for this geometry
  307. Int m_meshRobjIndex; ///<index of this mesh within hlod robj
  308. const Vector3 *m_verts; ///<array of vertices
  309. Vector3 *m_polygonNormals; ///<array of face normals
  310. Int m_numVerts; ///< number of actual vertices after duplicates are removed.
  311. Int m_numPolygons; ///<number of polygons in source geometry
  312. const Vector3i *m_polygons; ///<array of 3 vertex indices per face
  313. UnsignedShort *m_parentVerts; ///<array of parent vertex indices for each vertex.
  314. /// the neighbor info indexed by polygon id
  315. PolyNeighbor *m_polyNeighbors;
  316. Int m_numPolyNeighbors; // length of m_polyNeighbors and the number of polygons
  317. // in our current geometry.
  318. W3DShadowGeometry *m_parentGeometry; // mesh hierarchy containing this mesh.
  319. }; //end of meshInfo
  320. #ifdef DO_TERRAIN_SHADOW_VOLUMES
  321. //Custom version of W3DShadowGeometryMesh for meshes stored as heightmap
  322. class W3DShadowGeometryHeightmapMesh : public W3DShadowGeometryMesh
  323. {
  324. public:
  325. virtual int GetPolygonIndex (long dwPolyId, short *psIndexList, int dwNSize) const;
  326. virtual Vector3 *GetVertex (int dwVertId, Vector3 *pvVertex);
  327. W3DShadowGeometryHeightmapMesh(void) : m_patchOriginX(0),m_patchOriginY(0) { }
  328. void setPatchOrigin(Int x, Int y) {m_patchOriginX=x; m_patchOriginY=y;}
  329. void getPatchOrigin(Int *x, Int *y) {*x=m_patchOriginX; *y=m_patchOriginY;}
  330. void setPatchSize(Int size) {m_width=size; m_numPolygons=(size-1)*(size-1)*2;}
  331. Int getPatchSize(void) {return m_width;}
  332. protected:
  333. Int m_heightmapPitch; ///<width of full heightmap of which this mesh is a sub-rectangle
  334. Int m_width; ///<patch width
  335. Int m_patchOriginX; ///<location of patch within parent heightmap
  336. Int m_patchOriginY; ///<location of patch within parent heightmap
  337. };
  338. int W3DShadowGeometryHeightmapMesh::GetPolygonIndex (long dwPolyId, short *psIndexList, int dwNSize) const
  339. {
  340. //Find top left vertex of cell containing polygon
  341. WorldHeightMap *map=NULL;
  342. if (TheTerrainRenderObject)
  343. map=TheTerrainRenderObject->getMap();
  344. if (!map)
  345. return 0;
  346. Int row=dwPolyId/((m_width-1)<<1);
  347. Int column=(dwPolyId>>1)-row*((m_width-1));
  348. #ifdef FLIP_TRIANGLES
  349. UnsignedByte alpha[4];
  350. float UA[4], VA[4];
  351. Bool flipForBlend;
  352. map->getAlphaUVData(column+m_patchOriginX, row+m_patchOriginY, UA, VA, alpha, &flipForBlend, false);
  353. if (flipForBlend)
  354. {
  355. if (dwPolyId &1)
  356. { psIndexList[0]=row*m_width+column+1;
  357. psIndexList[1]=(row+1)*m_width+column+1;
  358. psIndexList[2]=(row+1)*m_width+column;
  359. }
  360. else
  361. { psIndexList[0]=row*m_width+column;
  362. psIndexList[1]=row*m_width+column+1;
  363. psIndexList[2]=(row+1)*m_width+column;
  364. }
  365. }
  366. else
  367. #endif
  368. { if (dwPolyId &1)
  369. { psIndexList[0]=row*m_width+column;
  370. psIndexList[1]=row*m_width+column+1;
  371. psIndexList[2]=(row+1)*m_width+column+1;
  372. }
  373. else
  374. { psIndexList[0]=row*m_width+column;
  375. psIndexList[1]=(row+1)*m_width+column+1;
  376. psIndexList[2]=(row+1)*m_width+column;
  377. }
  378. }
  379. return 3;
  380. }
  381. Vector3 *W3DShadowGeometryHeightmapMesh::GetVertex (int dwVertId, Vector3 *pvVertex)
  382. {
  383. WorldHeightMap *map=NULL;
  384. if (TheTerrainRenderObject)
  385. map=TheTerrainRenderObject->getMap();
  386. if (!map)
  387. return NULL;
  388. Int row=dwVertId/m_width;
  389. Int column=dwVertId-row*m_width;
  390. UnsignedByte *data=map->getDataPtr();
  391. pvVertex->X=(m_patchOriginX+column)*MAP_XY_FACTOR;
  392. pvVertex->Y=(m_patchOriginY+row)*MAP_XY_FACTOR;
  393. pvVertex->Z=(Real)data[(m_patchOriginX+column)+(m_patchOriginY+row)*map->getXExtent()]*MAP_HEIGHT_SCALE;
  394. return pvVertex;
  395. }
  396. Bool isPatchShadowed(W3DShadowGeometryHeightmapMesh *hm_mesh)
  397. {
  398. WorldHeightMap *map=NULL;
  399. Short poly[ 3 ];
  400. Vector3 vertex;
  401. Vector3 normal,lightVector;
  402. Int firstVisible=0;
  403. Int testVisible;
  404. if (TheTerrainRenderObject)
  405. map=TheTerrainRenderObject->getMap();
  406. if (!map)
  407. return NULL;
  408. hm_mesh->GetPolygonNormal( 0, &normal );
  409. // get the vertex indices at this polygon
  410. hm_mesh->GetPolygonIndex( 0, poly, 3 );
  411. //
  412. // find out "lightVector" to this polygon
  413. //
  414. // since our light source could be very close to the object and that
  415. // would change the shadow we are going to say that the light vector
  416. // is from the light position to one of the vertices in the polygon.
  417. // To be more correct we should use the center of the polygon but
  418. // this is a good approximation ... an ever broader approximation that
  419. // we could use would be the object center
  420. //
  421. hm_mesh->GetVertex( poly[ 0 ], &vertex );
  422. lightVector= vertex - LightPosWorld[0];
  423. //
  424. // dot the light vector with the normal of the polygon to see if the
  425. // poly is visible from this location
  426. //
  427. if( Vector3::Dot_Product( lightVector, normal ) < 0.0f )
  428. firstVisible=1;
  429. for (Int i=1; i<hm_mesh->GetNumPolygon(); i++)
  430. {
  431. hm_mesh->GetPolygonNormal( i, &normal );
  432. // get the vertex indices at this polygon
  433. hm_mesh->GetPolygonIndex( i, poly, 3 );
  434. //
  435. // find out "lightVector" to this polygon
  436. //
  437. // since our light source could be very close to the object and that
  438. // would change the shadow we are going to say that the light vector
  439. // is from the light position to one of the vertices in the polygon.
  440. // To be more correct we should use the center of the polygon but
  441. // this is a good approximation ... an ever broader approximation that
  442. // we could use would be the object center
  443. //
  444. hm_mesh->GetVertex( poly[ 0 ], &vertex );
  445. lightVector= vertex - LightPosWorld[0];
  446. //
  447. // dot the light vector with the normal of the polygon to see if the
  448. // poly is visible from this location
  449. //
  450. testVisible=0;
  451. if( Vector3::Dot_Product( lightVector, normal ) < 0.0f )
  452. testVisible=1;
  453. // if (testVisible ^ firstVisible)
  454. // return TRUE; //found polys facing different directions to sun, will cast shadow
  455. if (!testVisible)
  456. return TRUE; //some part of mesh not facing light, so it could cast a shadow
  457. }
  458. return FALSE;
  459. }
  460. #define SV_MAX_TERRAIN_MESHES 16
  461. static W3DShadowGeometryHeightmapMesh terrainMeshes[SV_MAX_TERRAIN_MESHES];
  462. static Int numTerrainMeshes=0;
  463. void W3DVolumetricShadowManager::loadTerrainShadows(void)
  464. {
  465. WorldHeightMap *map=NULL;
  466. Int patchSize=3;
  467. if (TheTerrainRenderObject)
  468. map=TheTerrainRenderObject->getMap();
  469. if (!map)
  470. return;
  471. for (Int y=0; y<map->getYExtent(); y += patchSize-1)
  472. {
  473. for (Int x=0; x<map->getXExtent(); x += patchSize-1)
  474. {
  475. W3DShadowGeometryHeightmapMesh *hm_mesh=&terrainMeshes[numTerrainMeshes];
  476. hm_mesh->setPatchOrigin(x,y);
  477. hm_mesh->setPatchSize(patchSize);
  478. if(isPatchShadowed(hm_mesh))
  479. { //some polygons in this patch cast shadows, need to generate a mesh
  480. hm_mesh->buildPolygonNeighbors();
  481. numTerrainMeshes++;
  482. }
  483. }
  484. }
  485. /* W3DShadowGeometryHeightmapMesh hm_mesh;
  486. short indexList[3];
  487. Vector3 vertexList[3];
  488. */
  489. /* W3DShadow *shadow = NEW W3DShadow;
  490. // add to our shadow list through the shadow next links
  491. shadow->m_next = m_shadowList;
  492. m_shadowList = shadow;
  493. */
  494. }
  495. #endif //DO_TERRAIN_SHADOW_VOLUMES
  496. /** This class will wrap any shadow casting geometry with additional
  497. data needed for efficient shadow volume generation. The W3DVolumetricShadowManager
  498. will allocate these structures and hash them for quick re-use on other
  499. models sharing the same geometry.*/
  500. class W3DShadowGeometry : public RefCountClass, public HashableClass
  501. {
  502. public:
  503. W3DShadowGeometry( void ) { };
  504. ~W3DShadowGeometry( void ) { };
  505. virtual const char * Get_Key( void ) { return m_namebuf; }
  506. Int init (RenderObjClass *robj);
  507. Int initFromHLOD (RenderObjClass *robj); ///<initialize the geometry from a W3D HLOD object.
  508. Int initFromMesh (RenderObjClass *robj);///<initialize the geometry from a W3D Mesh object.
  509. const char * Get_Name(void) const { return m_namebuf;}
  510. void Set_Name(const char *name)
  511. { memset(m_namebuf,0,sizeof(m_namebuf)); //pad with zero so always ends with null character.
  512. strncpy(m_namebuf,name,sizeof(m_namebuf)-1);
  513. }
  514. Int getMeshCount(void) { return m_meshCount;}
  515. W3DShadowGeometryMesh *getMesh(Int index) { return &m_meshList[index];}
  516. int GetNumTotalVertex (void) { return m_numTotalsVerts;} ///<total number of vertices in all meshes of this geometry
  517. private:
  518. char m_namebuf[2*W3D_NAME_LEN]; ///<name of model hierarchy
  519. W3DShadowGeometryMesh m_meshList[MAX_SHADOW_CASTER_MESHES]; ///<collection of meshes for this geometry.
  520. Int m_meshCount; ///<number of meshes in hierarchy
  521. Int m_numTotalsVerts; ///<number of verts in entire hierarchy
  522. };
  523. #define MAX_SHADOW_VOLUME_VERTS 16384
  524. Int W3DShadowGeometry::initFromHLOD(RenderObjClass *robj)
  525. {
  526. HLodClass *hlod=(HLodClass *)robj;
  527. //locations of parent vertices inside the vertex array after duplicate
  528. //vertices are removed.
  529. UnsignedShort vertParent[MAX_SHADOW_VOLUME_VERTS];
  530. Int i,j,k,newVertexCount;
  531. Int top = hlod->Get_LOD_Count()-1;
  532. W3DShadowGeometryMesh *geomMesh=&m_meshList[m_meshCount];
  533. m_numTotalsVerts=0;
  534. for (i = 0; i < hlod->Get_Lod_Model_Count(top); i++)
  535. {
  536. if (hlod->Peek_Lod_Model(top,i) && hlod->Peek_Lod_Model(top,i)->Class_ID() == RenderObjClass::CLASSID_MESH)
  537. {
  538. DEBUG_ASSERTCRASH(m_meshCount < MAX_SHADOW_CASTER_MESHES, ("Too many shadow sub-meshes"));
  539. geomMesh->m_mesh = (MeshClass *)hlod->Peek_Lod_Model(top,i);
  540. geomMesh->m_meshRobjIndex=i;
  541. if ((geomMesh->m_mesh->Is_Alpha() || geomMesh->m_mesh->Is_Translucent()) && !geomMesh->m_mesh->Peek_Model()->Get_Flag(MeshGeometryClass::CAST_SHADOW))
  542. continue; //transparent meshes that don't have forced shadows will not cast volumetric shadows
  543. MeshModelClass *mm = geomMesh->m_mesh->Peek_Model();
  544. geomMesh->m_numVerts=mm->Get_Vertex_Count();
  545. geomMesh->m_verts=mm->Get_Vertex_Array();
  546. geomMesh->m_numPolygons=mm->Get_Polygon_Count();
  547. geomMesh->m_polygons=mm->Get_Polygon_Array();
  548. if (geomMesh->m_numVerts > MAX_SHADOW_VOLUME_VERTS)
  549. return FALSE; //too many vertices to process
  550. //reset index of all vertices
  551. memset(vertParent,0xffffffff,sizeof(vertParent));
  552. newVertexCount=geomMesh->m_numVerts;
  553. //Find all duplicated vertices.
  554. for (j=0; j<geomMesh->m_numVerts; j++)
  555. {
  556. if (vertParent[j] != 0xffff)
  557. continue; //this vertex has already been processed
  558. const Vector3 *v_curr=&geomMesh->m_verts[j];
  559. for (k=j+1; k<geomMesh->m_numVerts; k++)
  560. {
  561. Vector3 len(*v_curr - geomMesh->m_verts[k]);
  562. if (len.Length2() == 0)
  563. { //found duplicate vertex
  564. vertParent[k]=j;
  565. newVertexCount--; //decrease total vertices since duplicate found.
  566. }
  567. }
  568. vertParent[j]=j; //first instance of new vertex
  569. }
  570. geomMesh->m_parentVerts = NEW UnsignedShort[geomMesh->m_numVerts];
  571. memcpy(geomMesh->m_parentVerts,vertParent,sizeof(UnsignedShort)*geomMesh->m_numVerts);
  572. geomMesh->m_numVerts=newVertexCount; //adjust actual vertex count to ignore duplicates
  573. m_numTotalsVerts += newVertexCount;
  574. geomMesh->m_parentGeometry = this;
  575. // build our neighboring polygon information
  576. geomMesh->buildPolygonNeighbors();
  577. geomMesh++;
  578. m_meshCount++;
  579. }
  580. }
  581. // for (i = 0; i < AdditionalModels.Count(); i++) {
  582. // res |= AdditionalModels[i].Model->Cast_Ray(raytest);
  583. // }
  584. return m_meshCount != 0;
  585. }
  586. Int W3DShadowGeometry::initFromMesh(RenderObjClass *robj)
  587. {
  588. //locations of parent vertices inside the vertex array after duplicate
  589. //vertices are removed.
  590. UnsignedShort vertParent[MAX_SHADOW_VOLUME_VERTS];
  591. Int j,k,newVertexCount;
  592. W3DShadowGeometryMesh *geomMesh=&m_meshList[m_meshCount];
  593. assert (m_meshCount < MAX_SHADOW_CASTER_MESHES);
  594. geomMesh->m_mesh = (MeshClass *)robj;
  595. geomMesh->m_meshRobjIndex = -1; //robj is the mesh so no index needed.
  596. if (((geomMesh->m_mesh->Is_Alpha() || geomMesh->m_mesh->Is_Translucent()) && !geomMesh->m_mesh->Peek_Model()->Get_Flag(MeshGeometryClass::CAST_SHADOW)))
  597. return FALSE; //transparent meshes that don't have forced shadows will not cast volumetric shadows
  598. MeshModelClass *mm = geomMesh->m_mesh->Peek_Model();
  599. geomMesh->m_numVerts=mm->Get_Vertex_Count();
  600. geomMesh->m_verts=mm->Get_Vertex_Array();
  601. geomMesh->m_numPolygons=mm->Get_Polygon_Count();
  602. geomMesh->m_polygons=mm->Get_Polygon_Array();
  603. if (geomMesh->m_numVerts > MAX_SHADOW_VOLUME_VERTS)
  604. return FALSE; //too many vertices to process
  605. //reset index of all vertices
  606. memset(vertParent,0xffffffff,sizeof(vertParent));
  607. newVertexCount=geomMesh->m_numVerts;
  608. //Find all duplicated vertices.
  609. for (j=0; j<geomMesh->m_numVerts; j++)
  610. {
  611. if (vertParent[j] != 0xffff)
  612. continue; //this vertex has already been processed
  613. const Vector3 *v_curr=&geomMesh->m_verts[j];
  614. for (k=j+1; k<geomMesh->m_numVerts; k++)
  615. {
  616. Vector3 len(*v_curr - geomMesh->m_verts[k]);
  617. if (len.Length2() == 0)
  618. { //found duplicate vertex
  619. vertParent[k]=j;
  620. newVertexCount--; //decrease total vertices since duplicate found.
  621. }
  622. }
  623. vertParent[j]=j; //first instance of new vertex
  624. }
  625. geomMesh->m_parentVerts = NEW UnsignedShort[geomMesh->m_numVerts];
  626. memcpy(geomMesh->m_parentVerts,vertParent,sizeof(UnsignedShort)*geomMesh->m_numVerts);
  627. geomMesh->m_numVerts=newVertexCount; //adjust actual vertex count to ignore duplicates
  628. geomMesh->m_parentGeometry = this;
  629. m_meshCount=1;
  630. m_numTotalsVerts=newVertexCount;
  631. // build our neighboring polygon information
  632. geomMesh->buildPolygonNeighbors();
  633. return TRUE;
  634. }
  635. Int W3DShadowGeometry::init(RenderObjClass *robj)
  636. {
  637. return TRUE;
  638. // m_robj=robj;
  639. /* //code to deal with granny - don't think we'll use shadow volumes on these!?
  640. granny_file *fileInfo=robj->getPrototype().m_file;
  641. for (Int modelIndex=0; modelIndex<fileInfo->ModelCount; modelIndex++)
  642. {
  643. granny_model *sourceModel = fileInfo->Models[modelIndex];
  644. if (stricmp(sourceModel->Name,"AABOX") == 0)
  645. { //found a collision box, copy out data
  646. int MeshCount = sourceModel->MeshBindingCount;
  647. if (MeshCount==1)
  648. {
  649. granny_mesh *sourceMesh = sourceModel->MeshBindings[0].Mesh;
  650. granny_pn33_vertex *Vertices = (granny_pn33_vertex *)sourceMesh->PrimaryVertexData->Vertices;
  651. Vector3 points[24];
  652. assert (sourceMesh->PrimaryVertexData->VertexCount <= 24);
  653. for (Int boxVertex=0; boxVertex<sourceMesh->PrimaryVertexData->VertexCount; boxVertex++)
  654. { points[boxVertex].Set(Vertices[boxVertex].Position[0],
  655. Vertices[boxVertex].Position[1],
  656. Vertices[boxVertex].Position[2]);
  657. }
  658. box.Init(points,sourceMesh->PrimaryVertexData->VertexCount);
  659. }
  660. }
  661. else
  662. { //mesh is part of model
  663. int meshCount = sourceModel->MeshBindingCount;
  664. for (Int meshIndex=0; meshIndex<meshCount; meshIndex++)
  665. {
  666. granny_mesh *sourceMesh = sourceModel->MeshBindings[meshIndex].Mesh;
  667. if (sourceMesh->PrimaryVertexData)
  668. vertexCount+=sourceMesh->PrimaryVertexData->VertexCount;
  669. }
  670. }
  671. }*/
  672. }
  673. ///////////////////////////////////////////////////////////////////////////////
  674. // MEMBER DEFINITIONS /////////////////////////////////////////////////////////
  675. ///////////////////////////////////////////////////////////////////////////////
  676. // W3DShadowGeometry =============================================================
  677. // ============================================================================
  678. W3DShadowGeometryMesh::W3DShadowGeometryMesh( void )
  679. {
  680. // init polygon neighbor information
  681. m_polyNeighbors = NULL;
  682. m_numPolyNeighbors = 0;
  683. m_parentVerts = NULL;
  684. m_polygonNormals = NULL;
  685. } // end W3DShadowGeometry
  686. // ~W3DShadowGeometry ============================================================
  687. // ============================================================================
  688. W3DShadowGeometryMesh::~W3DShadowGeometryMesh( void )
  689. {
  690. // remove our neighbor list information allocated
  691. deleteNeighbors();
  692. if (m_parentVerts) {
  693. delete [] m_parentVerts;
  694. }
  695. if (m_polygonNormals)
  696. delete [] m_polygonNormals;
  697. } // end ~W3DShadowGeometry
  698. // GetPolyNeighbor ============================================================
  699. // Return the poly neighbor structure at the given index
  700. // ============================================================================
  701. PolyNeighbor *W3DShadowGeometryMesh::GetPolyNeighbor( Int polyIndex )
  702. {
  703. // sanity
  704. if( polyIndex < 0 || polyIndex >= m_numPolyNeighbors )
  705. {
  706. // DBGPRINTF(( "Invalid neighbor index '%d'\n", polyIndex ));
  707. assert( 0 );
  708. return NULL;
  709. } // en dif
  710. return &m_polyNeighbors[ polyIndex ];
  711. } // end GetPolyNeighbor
  712. // buildPolygonNeighbors ======================================================
  713. // Whenever we set a new geometry we want to build some information about
  714. // the faces in the new geometry so that we can efficienty traverse across
  715. // the surface to neighboring polygons
  716. // ============================================================================
  717. void W3DShadowGeometryMesh::buildPolygonNeighbors( void )
  718. {
  719. Int numPolys;
  720. Int i, j;
  721. // how many polygons are in our geometry
  722. numPolys = GetNumPolygon();
  723. //
  724. // if there are no polygons for this geometry then we should have no
  725. // neighbor information
  726. //
  727. if( numPolys == 0 )
  728. {
  729. //
  730. // if our geometry has somehow deformed and we used to have polygon
  731. // neighbor information we should delete it before we bail
  732. //
  733. if( m_numPolyNeighbors != 0 )
  734. deleteNeighbors();
  735. return; // nothing to see here people, move along
  736. } // end if
  737. //
  738. // in the event that this geometry can deform on the fly or we are
  739. // building our neighbor information for the very first time ...
  740. // if our current geometry has a different number of polygons than
  741. // we had previously calculated we need to delete and reallocate a
  742. // new storate space for the neighbor information
  743. //
  744. if( numPolys != m_numPolyNeighbors )
  745. {
  746. // delete the old neighbor storage
  747. deleteNeighbors();
  748. // allocate a new pool for neighbor information
  749. if( allocateNeighbors( numPolys ) == FALSE )
  750. return;
  751. } // end if
  752. //
  753. // initialize all polygon neighbor information to none and assign our
  754. // own reference to myIndex so we know who we are
  755. //
  756. for( i = 0; i < m_numPolyNeighbors; i++ )
  757. {
  758. // assign our own identification
  759. m_polyNeighbors[ i ].myIndex = i;
  760. // assign our neighbors to none
  761. for( j = 0; j < MAX_POLYGON_NEIGHBORS; j++ )
  762. m_polyNeighbors[ i ].neighbor[ j ].neighborIndex = NO_NEIGHBOR;
  763. } // end for i
  764. // assign polygon data for each of our polygons
  765. for( i = 0; i < m_numPolyNeighbors; i++ )
  766. {
  767. Short poly[ 3 ]; // vertex indices for this polygon
  768. Short otherPoly[ 3 ]; // vertex indices for other polygon
  769. Vector3 vNorm;
  770. // get the indices of the three triangle points for this polygon
  771. GetPolygonIndex( i, poly, 3 );
  772. GetPolygonNormal(i,&vNorm);
  773. // find the neighbors of this polygon
  774. for( j = 0; j < m_numPolyNeighbors; j++ )
  775. {
  776. Int a, b;
  777. Int index1, index2;
  778. Int index1Pos[2]; //positions of shared edge vertices in triangle list. (0,1 or 2)
  779. Int diff1,diff2;
  780. // ignore our own polygon
  781. if( i == j )
  782. continue;
  783. // get the vertex index information for this other polygon
  784. GetPolygonIndex( j, otherPoly, 3 );
  785. //
  786. // if 2 of the 3 vertex indices are the same then these polygons
  787. // are neighbors
  788. //
  789. //Also check if winding order of vertices on edge is opposite.
  790. //If vertices are in same order as our polygon, then it's
  791. //not a valid edge because the neighbor is flipped.
  792. index1 = -1;
  793. index2 = -1;
  794. for( a = 0; a < 3; a++ )
  795. for( b = 0; b < 3; b++ )
  796. if( poly[ a ] == otherPoly[ b ] )
  797. {
  798. if( index1 == -1 )
  799. { index1 = poly[ a ]; // record matching index1
  800. index1Pos[0]=a;
  801. index1Pos[1]=b;
  802. }
  803. else if( index2 == -1 )
  804. { //Check direction of edge in each polygon. If they are same direction skip it.
  805. diff1 = a-index1Pos[0];
  806. diff2 = b-index1Pos[1];
  807. if ( ((diff1&0x80000000)^((abs(diff1)&2)<<30)) != ((diff2&0x80000000)^((abs(diff2)&2)<<30)))
  808. { Vector3 vOtherNorm;
  809. GetPolygonNormal(j,&vOtherNorm);
  810. //Check if the 2 polygons face in exactly opposite directions - don't allow this type of neighbor.
  811. if (fabs(Vector3::Dot_Product(vOtherNorm,vNorm) + 1.0f) <= 0.01f)
  812. continue;
  813. index2 = poly[ a ]; // record matching index2
  814. }
  815. else
  816. continue;
  817. }
  818. else
  819. {//This is the same poly facing opposite direction. //assert( 0 ); // should never match 3 vertices!
  820. index1=index2=-1;
  821. continue;
  822. }
  823. } // end if
  824. if( index1 != -1 && index2 != -1 )
  825. {
  826. //
  827. // the polygon j is a neighbor of our polygon i, put the j
  828. // index into the first free neighbor slot for polygon i
  829. //
  830. for( a = 0; a < MAX_POLYGON_NEIGHBORS; a++ )
  831. if( m_polyNeighbors[ i ].neighbor[ a ].neighborIndex == NO_NEIGHBOR )
  832. {
  833. // record the neighbor index
  834. m_polyNeighbors[ i ].neighbor[ a ].neighborIndex = j;
  835. // record the sharded edge vertex indices
  836. m_polyNeighbors[ i ].neighbor[ a ].neighborEdgeIndex[ 0 ] = index1;
  837. m_polyNeighbors[ i ].neighbor[ a ].neighborEdgeIndex[ 1 ] = index2;
  838. break; // exit for a
  839. } // end if
  840. //
  841. // error condition, if our counter a is at the max number
  842. // of neighbors, which is 3 for a triangle mesh, we did something
  843. // wrong here because that would mean we found a 4th match!
  844. //
  845. if (a == MAX_POLYGON_NEIGHBORS)
  846. {
  847. Vector3 pv[3];
  848. // char errorText[255];
  849. GetVertex (poly[0], &pv[0]);
  850. GetVertex (poly[1], &pv[1]);
  851. GetVertex (poly[2], &pv[2]);
  852. pv[0] = pv[0] + pv[1] + pv[2];
  853. pv[0] /= 3.0f; //find center of polygon
  854. // sprintf(errorText,"%s: Shadow Polygon with too many neighbors at %f,%f,%f",m_parentGeometry->Get_Name(),pv[0].X,pv[0].Y,pv[0].Z);
  855. // DEBUG_LOG(("****%s Shadow Polygon with too many neighbors at %f,%f,%f\n",m_parentGeometry->Get_Name(),pv[0].X,pv[0].Y,pv[0].Z));
  856. // DEBUG_ASSERTCRASH(a != MAX_POLYGON_NEIGHBORS,(errorText));
  857. }
  858. } // end if
  859. } // end for j
  860. } // end for i
  861. } // end buildPolygonNeighbors
  862. // allocateNeighbors ==========================================================
  863. // Allocate storage for the polygon neighbors and record its size
  864. // ============================================================================
  865. Bool W3DShadowGeometryMesh::allocateNeighbors( Int numPolys )
  866. {
  867. // assure we're not re-allocating without deleting
  868. assert( m_numPolyNeighbors == 0 );
  869. assert( m_polyNeighbors == NULL );
  870. // allocate the list
  871. m_polyNeighbors = NEW PolyNeighbor[ numPolys ];
  872. if( m_polyNeighbors == NULL )
  873. {
  874. // DBGPRINTF(( "Unable to allocate polygon neighbors\n" ));
  875. assert( 0 );
  876. return FALSE;
  877. } // end if
  878. // list is now acutally allocated
  879. m_numPolyNeighbors = numPolys;
  880. return TRUE; // success!
  881. } // end allocateNeighbors
  882. // deleteNeighbors ============================================================
  883. // Delete all polygon neighbor storage and information
  884. // ============================================================================
  885. void W3DShadowGeometryMesh::deleteNeighbors( void )
  886. {
  887. // delete list
  888. if( m_polyNeighbors )
  889. {
  890. delete [] m_polyNeighbors;
  891. m_polyNeighbors = NULL;
  892. m_numPolyNeighbors = 0;
  893. } // end if
  894. // sanity error checking
  895. assert( m_numPolyNeighbors == 0 );
  896. assert( m_polyNeighbors == NULL );
  897. } // end deleteNeighbors
  898. //#include "Common/ThingTemplate.h"
  899. // updateOptimalExtrusionPadding ==============================================
  900. // Use raycasting to figure out a shadow extrusion length that guarantees that
  901. // the highest point of the object is extruded long enough to hit some ground.
  902. // This is a very slow operation so only do once for static non-moving objects.
  903. // ============================================================================
  904. void W3DVolumetricShadow::updateOptimalExtrusionPadding(void)
  905. {
  906. if (m_robj)
  907. {
  908. // DrawableInfo *drawInfo=(DrawableInfo *)m_robj->Get_User_Data();
  909. // Drawable *draw = drawInfo->m_drawable;
  910. // if (strstr(draw->getTemplate()->getName().str(),"Right02") != 0)
  911. // draw = draw; //debug code for China06 wacky bridge shadow
  912. // get the light
  913. Vector3 lightPosWorld=TheW3DShadowManager->getLightPosWorld(0);
  914. // check if object has a limit/clamp on shadow length and adjust light
  915. // position of necessary.
  916. if (m_shadowLengthScale)
  917. { //Find light's distance from origin in xy plane
  918. Real lightXYDistance = sqrt(lightPosWorld.X*lightPosWorld.X + lightPosWorld.Y * lightPosWorld.Y);
  919. Real newZ=lightXYDistance*m_shadowLengthScale;
  920. if (newZ > lightPosWorld.Z)
  921. { //clamped z component is higher than actual light position allows so adjust it.
  922. lightPosWorld.Z = newZ;
  923. }
  924. }
  925. // find maximum shadow length which will not cause any corners of the object's bounding box
  926. // to cast shadows that drop significantly below the object's base. This will help avoid
  927. // artifacts when we have an object on a cliff/hill casting shadows onto the ground below.
  928. // We need this hack because the terrain does not cast shadows and looks weird when objects
  929. // sitting on an incline cast shadows down below.
  930. Vector3 objPos=m_robj->Get_Position();
  931. Vector3 lastValidTerrainPoint = objPos;
  932. Real baseGroundHeight=objPos.Z;
  933. const AABoxClass &box=m_robj->Get_Bounding_Box();
  934. Vector3 lightRay,shadowRay;
  935. LineSegClass lineseg;
  936. CastResultStruct result;
  937. Vector3 Corners[4];
  938. RayCollisionTestClass raytest(lineseg,&result);
  939. //Get vertices of top of bounding box since they will generate the longest shadow
  940. Corners[0]=box.Center+box.Extent; //top right corner
  941. Corners[1]=Corners[0];
  942. Corners[1].X -= 2.0f*box.Extent.X; //top left corner
  943. Corners[2]=Corners[1];
  944. Corners[2].Y -= 2.0f*box.Extent.Y; //bottom left corner
  945. Corners[3]=Corners[2];
  946. Corners[3].X += 2.0f*box.Extent.X; //bottom right corner
  947. //find the corner that causes the longest shadow projection
  948. //and clamp light position to make sure it falls on even ground about
  949. //the same height as the object's base.
  950. for (Int i=0; i<4; i++)
  951. {
  952. //Cast ray from top volume corners onto ground plane
  953. lightRay = Corners[i] - lightPosWorld; //vector light to corner
  954. lightRay.Normalize();
  955. raytest.Ray.Set(Corners[i],Corners[i]+lightRay*MAX_EXTRUSION_LENGTH);
  956. result.Reset();
  957. //find out where this ray intersects terrain.
  958. if (TheTerrainRenderObject->Cast_Ray(raytest) && !raytest.Result->StartBad)
  959. { //Found intersection point where shadow has its maximum length. Do a quick
  960. //search to see if terrain falls significantly below the height of the object
  961. //anywhere between the base and the intersection point. If so, we either need
  962. //to extend shadow extrusion or make the light angle more vertical.
  963. shadowRay.Set(result.ContactPoint-Corners[i]); //vector from object corner to terrain intersection.
  964. shadowRay.Z = 0; //remove z-component since we'll be sampling along the xy plane.
  965. //walk along the shadow/light direction vector looking for large dips - indicating object
  966. //is on hill or cliff.
  967. Real len=shadowRay.Length();
  968. Int numSteps=REAL_TO_INT_CEIL(len/SHADOW_SAMPLING_INTERVAL);
  969. Real stepSize = 1.0f/(Real)numSteps;
  970. Vector3 terrainPoint;
  971. Real t=stepSize;
  972. for (Int j=0; j<numSteps; j++)
  973. {
  974. terrainPoint = Corners[i] + shadowRay*t;
  975. terrainPoint.Z=0; //ignore height
  976. Real terrainHeight=TheTerrainRenderObject->getHeightMapHeight(terrainPoint.X,terrainPoint.Y,NULL);
  977. if (terrainHeight < (objPos.Z - MAX_SHADOW_EXTRUSION_UNDER_OBJECT_BEFORE_CLAMP)) //check if terrain dips more than 10 units under object.
  978. {
  979. if (j == 0) //this is the initial point so object must be right on the edge of a cliff.
  980. { baseGroundHeight = terrainHeight; //force extrusion all the way down cliff.
  981. Real tanAngle=tan(OVERHANGING_OBJECT_CLAMP_ANGLE); //clamp to about 89 degrees or close to vertical lightpos.
  982. setShadowLengthScale(tanAngle); //update the clamp angle to shorted shadow enough so this corner on flat ground.
  983. break;
  984. }
  985. //Find ray from last valid terrain contact point to object box corner.
  986. Vector3 clampRay(Corners[i]-lastValidTerrainPoint);
  987. Real clampAngle=asin(clampRay.Z/clampRay.Length());
  988. if (clampAngle >= (PI/2.0f) || clampAngle <= 0)
  989. clampAngle = OVERHANGING_OBJECT_CLAMP_ANGLE; //clamp to about 89 degrees or close to vertical lightpos.
  990. Real tanAngle=tan(clampAngle);
  991. if (tanAngle > m_shadowLengthScale)
  992. setShadowLengthScale(tanAngle); //update the clamp angle to shorted shadow enough so this corner on flat ground.
  993. break;
  994. }
  995. if (terrainHeight < baseGroundHeight)
  996. { baseGroundHeight = terrainHeight; //point was below object but within safety margin so record it's position.
  997. lastValidTerrainPoint = terrainPoint;
  998. lastValidTerrainPoint.Z = baseGroundHeight;
  999. }
  1000. t+=stepSize;
  1001. }
  1002. }
  1003. }
  1004. m_extraExtrusionPadding = objPos.Z - baseGroundHeight + SHADOW_EXTRUSION_BUFFER;
  1005. DEBUG_ASSERTCRASH(m_extraExtrusionPadding <= (255.0f*MAP_HEIGHT_SCALE),("Warning: Volumetric Shadow UpdateOptimalExtrusionPadding too large"));
  1006. }
  1007. }
  1008. // getRenderCost ============================================================
  1009. // Returns number of draw calls for this shadow.
  1010. // ============================================================================
  1011. #if defined(_DEBUG) || defined(_INTERNAL)
  1012. void W3DVolumetricShadow::getRenderCost(RenderCost & rc) const
  1013. {
  1014. Int drawCount = 0;
  1015. if (m_geometry && m_isEnabled && !m_isInvisibleEnabled && TheGlobalData->m_useShadowVolumes)
  1016. {
  1017. Int i,j;
  1018. HLodClass *hlod=(HLodClass *)m_robj;
  1019. MeshClass *mesh;
  1020. Int meshIndex;
  1021. for( i = 0; i < MAX_SHADOW_LIGHTS; i++ )
  1022. {
  1023. for (j=0; j<m_geometry->getMeshCount(); j++)
  1024. {
  1025. meshIndex=m_geometry->getMesh(j)->m_meshRobjIndex;
  1026. if (meshIndex >= 0)
  1027. mesh = (MeshClass *)hlod->Peek_Lod_Model(0,meshIndex);
  1028. else
  1029. mesh = (MeshClass *)m_robj;
  1030. if (mesh && mesh->Is_Not_Hidden_At_All())
  1031. drawCount++;
  1032. }
  1033. }
  1034. }
  1035. rc.addShadowDrawCalls(drawCount*2);
  1036. }
  1037. #endif
  1038. /************************************ New Buffered Rendering Code ************************/
  1039. void W3DVolumetricShadow::RenderVolume(Int meshIndex, Int lightIndex)
  1040. {
  1041. HLodClass *hlod=(HLodClass *)m_robj;
  1042. MeshClass *mesh=NULL;
  1043. Int meshRobjIndex=m_geometry->getMesh(meshIndex)->m_meshRobjIndex;
  1044. if (meshRobjIndex >= 0)
  1045. mesh = (MeshClass *)hlod->Peek_Lod_Model(0,meshRobjIndex);
  1046. else
  1047. mesh = (MeshClass *)m_robj;
  1048. if (mesh)
  1049. {
  1050. #ifdef SV_DEBUG_BOUNDS
  1051. RenderMeshVolumeBounds(meshIndex,lightIndex, &mesh->Get_Transform());
  1052. #endif
  1053. if (m_shadowVolume[0][ meshIndex ]->GetFlags() & SHADOW_DYNAMIC)
  1054. RenderDynamicMeshVolume(meshIndex,lightIndex,&mesh->Get_Transform());
  1055. else
  1056. RenderMeshVolume(meshIndex,lightIndex,&mesh->Get_Transform());
  1057. }
  1058. }
  1059. void W3DVolumetricShadow::RenderMeshVolume(Int meshIndex, Int lightIndex, const Matrix3D *meshXform)
  1060. {
  1061. Geometry *geometry;
  1062. Int numVerts, numPolys, numIndex;
  1063. //Get D3D Device used by W3D for quicker access.
  1064. LPDIRECT3DDEVICE8 m_pDev=DX8Wrapper::_Get_D3D_Device8();
  1065. if (!m_pDev)
  1066. return;
  1067. geometry = m_shadowVolume[lightIndex][ meshIndex ];
  1068. //
  1069. // if our count is out of sync with our geometry data something
  1070. // is wrong here
  1071. //
  1072. assert( geometry );
  1073. // get geometry requirements
  1074. numVerts = geometry->GetNumActiveVertex();
  1075. numPolys = geometry->GetNumActivePolygon();
  1076. numIndex = numPolys * 3;
  1077. // reject shadows with no data
  1078. if( numVerts == 0 || numPolys == 0 )
  1079. return;
  1080. Matrix4 mWorld(*meshXform);
  1081. ///@todo: W3D always does transpose on all of matrix sets. Slow??? Better to hack view matrix.
  1082. m_pDev->SetTransform(D3DTS_WORLD,(_D3DMATRIX *)&mWorld.Transpose());
  1083. W3DBufferManager::W3DVertexBufferSlot *vbSlot=m_shadowVolumeVB[lightIndex][ meshIndex ];
  1084. if (!vbSlot)
  1085. return;
  1086. if (vbSlot->m_VB->m_DX8VertexBuffer->Get_DX8_Vertex_Buffer() != lastActiveVertexBuffer)
  1087. { lastActiveVertexBuffer=vbSlot->m_VB->m_DX8VertexBuffer->Get_DX8_Vertex_Buffer();
  1088. m_pDev->SetStreamSource(0,lastActiveVertexBuffer,
  1089. vbSlot->m_VB->m_DX8VertexBuffer->FVF_Info().Get_FVF_Size()); //12 bytes per vertex.
  1090. }
  1091. DEBUG_ASSERTCRASH(vbSlot->m_size >= numVerts,("Overflowing Shadow Vertex Buffer Slot"));
  1092. W3DBufferManager::W3DIndexBufferSlot *ibSlot=m_shadowVolumeIB[lightIndex][ meshIndex ];
  1093. if (!ibSlot)
  1094. return;
  1095. DEBUG_ASSERTCRASH(ibSlot->m_size >= numIndex,("Overflowing Shadow Index Buffer Slot"));
  1096. m_pDev->SetIndices(ibSlot->m_IB->m_DX8IndexBuffer->Get_DX8_Index_Buffer(),vbSlot->m_start);
  1097. if (DX8Wrapper::_Is_Triangle_Draw_Enabled())
  1098. {
  1099. Debug_Statistics::Record_DX8_Polys_And_Vertices(numPolys,numVerts,ShaderClass::_PresetOpaqueShader);
  1100. m_pDev->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,numVerts,ibSlot->m_start,numPolys);
  1101. }
  1102. }
  1103. void W3DVolumetricShadow::RenderDynamicMeshVolume(Int meshIndex, Int lightIndex, const Matrix3D *meshXform)
  1104. {
  1105. Geometry *geometry;
  1106. Int numVerts, numPolys, numIndex;
  1107. SHADOW_DYNAMIC_VOLUME_VERTEX* pvVertices;
  1108. UnsignedShort *pvIndices;
  1109. //Get D3D Device used by W3D for quicker access.
  1110. LPDIRECT3DDEVICE8 m_pDev=DX8Wrapper::_Get_D3D_Device8();
  1111. if (!m_pDev)
  1112. return;
  1113. geometry = m_shadowVolume[lightIndex][ meshIndex ];
  1114. //
  1115. // if our count is out of sync with our geometry data something
  1116. // is wrong here
  1117. //
  1118. assert( geometry );
  1119. // get geometry requirements
  1120. numVerts = geometry->GetNumActiveVertex();
  1121. numPolys = geometry->GetNumActivePolygon();
  1122. numIndex = numPolys * 3;
  1123. // reject shadows with no data
  1124. if( numVerts == 0 || numPolys == 0 )
  1125. return;
  1126. if (nShadowVertsInBuf > (SHADOW_VERTEX_SIZE-numVerts)) //check if room for model verts
  1127. { //flush the buffer by drawing the contents and re-locking again
  1128. if (shadowVertexBufferD3D->Lock(0,numVerts*sizeof(SHADOW_DYNAMIC_VOLUME_VERTEX),(unsigned char**)&pvVertices,D3DLOCK_DISCARD) != D3D_OK)
  1129. return;
  1130. nShadowVertsInBuf=0;
  1131. nShadowStartBatchVertex=0;
  1132. }
  1133. else
  1134. { if (shadowVertexBufferD3D->Lock(nShadowVertsInBuf*sizeof(SHADOW_DYNAMIC_VOLUME_VERTEX),numVerts*sizeof(SHADOW_DYNAMIC_VOLUME_VERTEX), (unsigned char**)&pvVertices,D3DLOCK_NOOVERWRITE) != D3D_OK)
  1135. return;
  1136. }
  1137. #ifdef SV_DEBUG
  1138. srand(0x1345465);
  1139. #endif
  1140. if(pvVertices)
  1141. {
  1142. #ifdef SV_DEBUG
  1143. for (Int i=0; i<numVerts; i++)
  1144. {
  1145. (*((Vector3 *)pvVertices))=*geometry->GetVertex(i); //cast is valid since both start with xyz
  1146. pvVertices->diffuse=(rand()%255) | ((rand()%255)<<8) | ((rand()%255)<<16);
  1147. pvVertices++;
  1148. }
  1149. #else
  1150. memcpy(pvVertices,geometry->GetVertex(0),numVerts*sizeof(SHADOW_DYNAMIC_VOLUME_VERTEX));
  1151. #endif
  1152. }
  1153. shadowVertexBufferD3D->Unlock();
  1154. if (nShadowIndicesInBuf > (SHADOW_INDEX_SIZE-numIndex)) //check if room for model verts
  1155. { //flush the buffer by drawing the contents and re-locking again
  1156. if (shadowIndexBufferD3D->Lock(0,numIndex*sizeof(short),(unsigned char**)&pvIndices,D3DLOCK_DISCARD) != D3D_OK)
  1157. return;
  1158. nShadowIndicesInBuf=0;
  1159. nShadowStartBatchIndex=0;
  1160. }
  1161. else
  1162. { if (shadowIndexBufferD3D->Lock(nShadowIndicesInBuf*sizeof(short),numIndex*sizeof(short), (unsigned char**)&pvIndices,D3DLOCK_NOOVERWRITE) != D3D_OK)
  1163. return;
  1164. }
  1165. if(pvIndices)
  1166. {
  1167. memcpy(pvIndices,geometry->GetPolygonIndex(0,(short *)pvIndices,3),numPolys*3*sizeof(short));
  1168. }
  1169. shadowIndexBufferD3D->Unlock();
  1170. m_pDev->SetIndices(shadowIndexBufferD3D,nShadowStartBatchVertex);
  1171. Matrix4 mWorld(*meshXform);
  1172. m_pDev->SetTransform(D3DTS_WORLD,(_D3DMATRIX *)&mWorld.Transpose());
  1173. if (shadowVertexBufferD3D != lastActiveVertexBuffer)
  1174. { m_pDev->SetStreamSource(0,shadowVertexBufferD3D,sizeof(SHADOW_DYNAMIC_VOLUME_VERTEX));
  1175. lastActiveVertexBuffer = shadowVertexBufferD3D;
  1176. }
  1177. if (DX8Wrapper::_Is_Triangle_Draw_Enabled())
  1178. {
  1179. Debug_Statistics::Record_DX8_Polys_And_Vertices(numPolys,numVerts,ShaderClass::_PresetOpaqueShader);
  1180. m_pDev->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,numVerts,nShadowStartBatchIndex,numPolys);
  1181. }
  1182. nShadowVertsInBuf += numVerts;
  1183. nShadowStartBatchVertex=nShadowVertsInBuf;
  1184. nShadowIndicesInBuf += numIndex;
  1185. nShadowStartBatchIndex=nShadowIndicesInBuf;
  1186. }
  1187. /** Debug function to draw bounding boxes around shadow volumes */
  1188. void W3DVolumetricShadow::RenderMeshVolumeBounds(Int meshIndex, Int lightIndex, const Matrix3D *meshXform)
  1189. {
  1190. Geometry *geometry;
  1191. Int numVerts, numPolys, numIndex;
  1192. SHADOW_DYNAMIC_VOLUME_VERTEX* pvVertices;
  1193. UnsignedShort *pvIndices;
  1194. // Vertex Positions as a function of the box extents
  1195. static Vector3 _BoxVerts[8] =
  1196. {
  1197. Vector3( 1.0f, 1.0f, 1.0f ), // +z ring of 4 verts
  1198. Vector3( -1.0f, 1.0f, 1.0f ),
  1199. Vector3( -1.0f,-1.0f, 1.0f ),
  1200. Vector3( 1.0f,-1.0f, 1.0f ),
  1201. Vector3( 1.0f, 1.0f,-1.0f ), // -z ring of 4 verts;
  1202. Vector3( -1.0f, 1.0f,-1.0f ),
  1203. Vector3( -1.0f,-1.0f,-1.0f ),
  1204. Vector3( 1.0f,-1.0f,-1.0f ),
  1205. };
  1206. // Face Connectivity
  1207. static Vector3i _BoxFaces[12] =
  1208. {
  1209. Vector3i( 0,1,2 ), // +z faces
  1210. Vector3i( 0,2,3 ),
  1211. Vector3i( 4,7,6 ), // -z faces
  1212. Vector3i( 4,6,5 ),
  1213. Vector3i( 0,3,7 ), // +x faces
  1214. Vector3i( 0,7,4 ),
  1215. Vector3i( 1,5,6 ), // -x faces
  1216. Vector3i( 1,6,2 ),
  1217. Vector3i( 4,5,1 ), // +y faces
  1218. Vector3i( 4,1,0 ),
  1219. Vector3i( 3,2,6 ), // -y faces
  1220. Vector3i( 3,6,7 )
  1221. };
  1222. static Vector3 verts[8];
  1223. //Get D3D Device used by W3D for quicker access.
  1224. LPDIRECT3DDEVICE8 m_pDev=DX8Wrapper::_Get_D3D_Device8();
  1225. if (!m_pDev)
  1226. return;
  1227. Vector3 meshPosition;
  1228. meshXform->Get_Translation(&meshPosition); //current mesh position
  1229. geometry = m_shadowVolume[lightIndex][ meshIndex ];
  1230. AABoxClass &aab=geometry->getBoundingBox();
  1231. // compute the vertex positions
  1232. meshPosition += aab.Center; //get world space position of bounding box
  1233. for (int ivert=0; ivert<8; ivert++)
  1234. {
  1235. verts[ivert].X = meshPosition.X + _BoxVerts[ivert][0] * aab.Extent.X;
  1236. verts[ivert].Y = meshPosition.Y + _BoxVerts[ivert][1] * aab.Extent.Y;
  1237. verts[ivert].Z = meshPosition.Z + _BoxVerts[ivert][2] * aab.Extent.Z;
  1238. }
  1239. //
  1240. // if our count is out of sync with our geometry data something
  1241. // is wrong here
  1242. //
  1243. assert( geometry );
  1244. // get geometry requirements
  1245. numVerts = 8;
  1246. numPolys = 12;
  1247. numIndex = numPolys * 3;
  1248. // reject shadows with no data
  1249. if( numVerts == 0 || numPolys == 0 )
  1250. return;
  1251. if (nShadowVertsInBuf > (SHADOW_VERTEX_SIZE-numVerts)) //check if room for model verts
  1252. { //flush the buffer by drawing the contents and re-locking again
  1253. if (shadowVertexBufferD3D->Lock(0,numVerts*sizeof(SHADOW_DYNAMIC_VOLUME_VERTEX),(unsigned char**)&pvVertices,D3DLOCK_DISCARD) != D3D_OK)
  1254. return;
  1255. nShadowVertsInBuf=0;
  1256. nShadowStartBatchVertex=0;
  1257. }
  1258. else
  1259. { if (shadowVertexBufferD3D->Lock(nShadowVertsInBuf*sizeof(SHADOW_DYNAMIC_VOLUME_VERTEX),numVerts*sizeof(SHADOW_DYNAMIC_VOLUME_VERTEX), (unsigned char**)&pvVertices,D3DLOCK_NOOVERWRITE) != D3D_OK)
  1260. return;
  1261. }
  1262. srand(0x1345465);
  1263. if(pvVertices)
  1264. { for (Int i=0; i<8; i++)
  1265. {
  1266. pvVertices->x=verts[i][0];
  1267. pvVertices->y=verts[i][1];
  1268. pvVertices->z=verts[i][2];
  1269. #ifdef SV_DEBUG
  1270. pvVertices->diffuse=(rand()%255) | ((rand()%255)<<8) | ((rand()%255)<<16);
  1271. #endif
  1272. pvVertices++;
  1273. }
  1274. }
  1275. shadowVertexBufferD3D->Unlock();
  1276. if (nShadowIndicesInBuf > (SHADOW_INDEX_SIZE-numIndex)) //check if room for model verts
  1277. { //flush the buffer by drawing the contents and re-locking again
  1278. if (shadowIndexBufferD3D->Lock(0,numIndex*sizeof(short),(unsigned char**)&pvIndices,D3DLOCK_DISCARD) != D3D_OK)
  1279. return;;
  1280. nShadowIndicesInBuf=0;
  1281. nShadowStartBatchIndex=0;
  1282. }
  1283. else
  1284. { if (shadowIndexBufferD3D->Lock(nShadowIndicesInBuf*sizeof(short),numIndex*sizeof(short), (unsigned char**)&pvIndices,D3DLOCK_NOOVERWRITE) != D3D_OK)
  1285. return;
  1286. }
  1287. if(pvIndices)
  1288. {
  1289. for (Int i=0; i<numPolys; i++,pvIndices+=3)
  1290. {
  1291. pvIndices[0] = _BoxFaces[i][0];
  1292. pvIndices[1] = _BoxFaces[i][1];
  1293. pvIndices[2] = _BoxFaces[i][2];
  1294. }
  1295. }
  1296. shadowIndexBufferD3D->Unlock();
  1297. m_pDev->SetIndices(shadowIndexBufferD3D,nShadowStartBatchVertex);
  1298. //todo: replace this with mesh transform
  1299. Matrix4 mWorld(1); //identity since boxes are pre-transformed to world space.
  1300. m_pDev->SetTransform(D3DTS_WORLD,(_D3DMATRIX *)&mWorld.Transpose());
  1301. m_pDev->SetStreamSource(0,shadowVertexBufferD3D,sizeof(SHADOW_DYNAMIC_VOLUME_VERTEX));
  1302. m_pDev->SetVertexShader(SHADOW_DYNAMIC_VOLUME_FVF);
  1303. m_pDev->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,numVerts,nShadowStartBatchIndex,numPolys);
  1304. nShadowVertsInBuf += numVerts;
  1305. nShadowStartBatchVertex=nShadowVertsInBuf;
  1306. nShadowIndicesInBuf += numIndex;
  1307. nShadowStartBatchIndex=nShadowIndicesInBuf;
  1308. }
  1309. // Shadow =====================================================================
  1310. // Shadow default constructor
  1311. // ============================================================================
  1312. W3DVolumetricShadow::W3DVolumetricShadow( void )
  1313. {
  1314. Int i,j;
  1315. m_next = NULL;
  1316. m_geometry = NULL;
  1317. m_shadowLengthScale = 0.0f;
  1318. m_extraExtrusionPadding = 0.0f;
  1319. m_robj = NULL;
  1320. m_isEnabled = TRUE;
  1321. m_isInvisibleEnabled = FALSE;
  1322. for (j=0; j < MAX_SHADOW_CASTER_MESHES; j++)
  1323. { m_numSilhouetteIndices[j] = 0;
  1324. m_maxSilhouetteEntries[j] = 0;
  1325. m_silhouetteIndex[j] = NULL;
  1326. m_shadowVolumeCount[j] = 0;
  1327. }
  1328. for( i = 0; i < MAX_SHADOW_LIGHTS; i++ )
  1329. {
  1330. for (j=0; j < MAX_SHADOW_CASTER_MESHES; j++)
  1331. {
  1332. m_shadowVolume[ i ][j] = NULL;
  1333. m_shadowVolumeVB[i][j] = NULL;
  1334. m_shadowVolumeIB[i][j] = NULL;
  1335. m_shadowVolumeRenderTask[i][j].m_parentShadow = this;
  1336. m_shadowVolumeRenderTask[i][j].m_meshIndex = (UnsignedByte)j;
  1337. m_shadowVolumeRenderTask[i][j].m_lightIndex = (UnsignedByte)i;
  1338. m_objectXformHistory[ i ][j].Make_Identity();
  1339. m_lightPosHistory[ i ][j] = Vector3(0,0,0);
  1340. }
  1341. } // end for i
  1342. } // end W3DVolumetricShadow
  1343. // ~W3DVolumetricShadow ====================================================================
  1344. // W3DVolumetricShadow destructor
  1345. // ============================================================================
  1346. W3DVolumetricShadow::~W3DVolumetricShadow( void )
  1347. {
  1348. Int i,j;
  1349. // we must free any silhouette data allocated
  1350. for (j = 0; j < MAX_SHADOW_CASTER_MESHES; j++)
  1351. deleteSilhouette(j);
  1352. // free any shadow volume data
  1353. for( i = 0; i < MAX_SHADOW_LIGHTS; i++ )
  1354. { for (j = 0; j < MAX_SHADOW_CASTER_MESHES; j++)
  1355. { if( m_shadowVolume[ i ][j] )
  1356. delete m_shadowVolume[ i ][j];
  1357. if( m_shadowVolumeVB[i][j])
  1358. TheW3DBufferManager->releaseSlot(m_shadowVolumeVB[i][j]);
  1359. if( m_shadowVolumeIB[i][j])
  1360. TheW3DBufferManager->releaseSlot(m_shadowVolumeIB[i][j]);
  1361. }
  1362. }
  1363. if (m_geometry)
  1364. REF_PTR_RELEASE(m_geometry);
  1365. m_geometry=NULL;
  1366. m_robj=NULL;
  1367. } // end ~W3DVolumetricShadow
  1368. void W3DVolumetricShadow::SetGeometry( W3DShadowGeometry *geometry )
  1369. {
  1370. Short numPrevVertices = 0;
  1371. Short numNewVertices = 0;
  1372. //
  1373. // our geometry has changed, we need to allocate enough memory for the
  1374. // silhouette data. If silhouette data is present it must be reallocated
  1375. // to accomoddate the new size if smaller
  1376. //
  1377. // if we had previous geometry how many vertices did it have
  1378. for (Int i=0; i<MAX_SHADOW_CASTER_MESHES; i++)
  1379. {
  1380. if( m_geometry )
  1381. numPrevVertices = m_geometry->getMesh(i)->GetNumVertex();
  1382. // now many vertices does our new geometry have
  1383. if( geometry )
  1384. numNewVertices = geometry->getMesh(i)->GetNumVertex();
  1385. //
  1386. // TODO: Colin, may want to change this in the future
  1387. // if our new geometry requires more memory allocate it, if it requires
  1388. // less we'll leave it around for future switches in geometry
  1389. //
  1390. if( numNewVertices > numPrevVertices )
  1391. {
  1392. deleteSilhouette(i);
  1393. if( allocateSilhouette(i, numNewVertices ) == FALSE )
  1394. return;
  1395. } // end if
  1396. }
  1397. // assign the new geometry, possible over an old geometry
  1398. m_geometry = geometry;
  1399. } // end SetGeometry
  1400. /**Called once per frame for each object, when necessary it will reconstruct
  1401. the shadow volume for this shadow from the silhouette of the geometry
  1402. and any light sources
  1403. */
  1404. void W3DVolumetricShadow::Update()
  1405. {
  1406. static Int currentTime, lastTime, delay = 0;
  1407. // OBJECT_PILE
  1408. // static Vector3 originCompareVector(0,0,9999);
  1409. static Vector3 originCompareVector(0,0,0);
  1410. Vector3 pos;
  1411. // sanity
  1412. if( m_geometry == NULL)
  1413. return;
  1414. //
  1415. // for now we will just rebuild a shadow volume every so often, this
  1416. // should be changed to be built only when the light angle sufficiently
  1417. // changes or when the object rotation sufficiently changes
  1418. //
  1419. // currentTime = timeGetTime();
  1420. // if( currentTime - lastTime >= delay )
  1421. {
  1422. pos=m_robj->Get_Position();
  1423. if (pos == originCompareVector)
  1424. { //the transform on this object was never set so we can't make any determination
  1425. //if it's visible or what the shadow looks like.
  1426. return;
  1427. }
  1428. //Check if this is a "flying" unit. Flying units are defined as anything that moves more than
  1429. //AIRBORNE_UNIT_GROUND_DELTA world units above ground. This will allow "jumping" units like rocket
  1430. //buggies from being flagged as "flying". We minimize the number of flying units because their shadow
  1431. //volumes are extruded longer to reach the lowest point on the map. Regular shadows only extend far
  1432. //enough to reach the base of the model (presumes base is already touching the ground).
  1433. Real groundHeight;
  1434. if (TheTerrainLogic)
  1435. groundHeight=TheTerrainLogic->getGroundHeight(pos.X,pos.Y); //logic knows about bridges so use if available.
  1436. else
  1437. groundHeight=TheTerrainRenderObject->getHeightMapHeight(pos.X,pos.Y, NULL);
  1438. if (fabs(pos.Z - groundHeight) >= AIRBORNE_UNIT_GROUND_DELTA)
  1439. {
  1440. Real extent = MAX_SHADOW_LENGTH_EXTRA_AIRBORNE_SCALE_FACTOR * m_robjExtent;
  1441. if (WWMath::Fabs(pos.X - bcX) > (beX + extent) ||
  1442. WWMath::Fabs(pos.Y - bcY) > (beY + extent) ||
  1443. WWMath::Fabs(pos.Z - bcZ) > (beZ + extent))
  1444. return; //shadow can't be visible so no point in updating.
  1445. //this unit is above ground, extend shadow volume to reach lowest point on the terrain plus extra bit to make
  1446. //sure shadow goes under ground.
  1447. updateVolumes(fabs(pos.Z - TheTerrainRenderObject->getMinHeight()) + SHADOW_EXTRUSION_BUFFER);
  1448. }
  1449. else
  1450. { //normal object that is not floating above ground so we don't need to extend the shadow lower than the object's
  1451. //base since it should be sitting directly at ground level.
  1452. if (WWMath::Fabs(pos.X - bcX) > (beX + m_robjExtent) ||
  1453. WWMath::Fabs(pos.Y - bcY) > (beY + m_robjExtent) ||
  1454. WWMath::Fabs(pos.Z - bcZ) > (beZ + m_robjExtent))
  1455. return; //shadow can't be visible so no point in updating.
  1456. //check if this object has never had it's extrusion length updated. Will only be true for
  1457. //immobile objects because finding an optimal extrusion length is expensive.
  1458. if (!m_extraExtrusionPadding)
  1459. updateOptimalExtrusionPadding();
  1460. updateVolumes(m_extraExtrusionPadding);
  1461. }
  1462. // floorZ = 2.0f; //lower slightly so shadows go under ground.
  1463. // update delay time
  1464. lastTime = currentTime;
  1465. } // end if
  1466. } // end Update
  1467. /** Update shadow volumes belonging to all meshes of this shadow caster.
  1468. * Use zoffset to extend shadows below object's base by given amount.
  1469. */
  1470. void W3DVolumetricShadow::updateVolumes(Real zoffset)
  1471. {
  1472. Int i,j;
  1473. HLodClass *hlod=(HLodClass *)m_robj;
  1474. MeshClass *mesh;
  1475. static AABoxClass aaBox;
  1476. static SphereClass sphere;
  1477. Int meshIndex;
  1478. DEBUG_ASSERTCRASH(hlod != NULL,("updateVolumes : hlod is NULL!"));
  1479. Bool parentVis=m_robj->Is_Really_Visible();
  1480. for( i = 0; i < MAX_SHADOW_LIGHTS; i++ )
  1481. {
  1482. for (j=0; j<m_geometry->getMeshCount(); j++)
  1483. {
  1484. meshIndex=m_geometry->getMesh(j)->m_meshRobjIndex;
  1485. if (meshIndex >= 0)
  1486. mesh = (MeshClass *)hlod->Peek_Lod_Model(0,meshIndex);
  1487. else
  1488. mesh = (MeshClass *)m_robj;
  1489. if (mesh)
  1490. {
  1491. if (!mesh->Is_Not_Hidden_At_All())
  1492. continue;
  1493. /**@todo: Getting the transform of the mesh may be forcing a full hierarchy evaluation.
  1494. Expensive for off-screen models... do we really need this? */
  1495. //Extend floor of model by 'zoffset' to compensate for flying units.
  1496. updateMeshVolume(j, i, &mesh->Get_Transform(), mesh->Get_Bounding_Box(),m_robj->Get_Position().Z - zoffset);
  1497. //update visibility if not set yet
  1498. if (m_shadowVolume[i][j])
  1499. {
  1500. if(m_shadowVolume[i][j]->getVisibleState() == Geometry::STATE_UNKNOWN)
  1501. { //Updating the mesh volume didn't update the visibility, must do it here.
  1502. //First check against bounding sphere
  1503. if (parentVis)
  1504. { //parent is visible so most likely all sub_objects are also visible so probably all shadows also visible.
  1505. //skip additional visibility tests
  1506. m_shadowVolume[i][j]->setVisibleState(Geometry::STATE_VISIBLE);
  1507. }
  1508. else
  1509. { sphere=m_shadowVolume[i][j]->getBoundingSphere();
  1510. sphere.Center += mesh->Get_Transform().Get_Translation();
  1511. CollisionMath::OverlapType result=CollisionMath::Overlap_Test(*shadowCameraFrustum,sphere);
  1512. if (result == CollisionMath::OVERLAPPED)
  1513. { //do a more accurate test against bounding box.
  1514. aaBox=m_shadowVolume[i][j]->getBoundingBox();
  1515. aaBox.Translate(mesh->Get_Transform().Get_Translation()); //translate bounding box to world space.
  1516. if (CollisionMath::Overlap_Test(*shadowCameraFrustum,aaBox) != CollisionMath::OUTSIDE)
  1517. m_shadowVolume[i][j]->setVisibleState(Geometry::STATE_VISIBLE);
  1518. else
  1519. m_shadowVolume[i][j]->setVisibleState(Geometry::STATE_INVISIBLE);
  1520. }
  1521. else
  1522. m_shadowVolume[i][j]->setVisibleState((Geometry::VisibleState)result);
  1523. }
  1524. }
  1525. if (m_shadowVolume[i][j]->getVisibleState() == Geometry::STATE_VISIBLE)
  1526. { //shadow volume is visible. Add it to list of rendertasks.
  1527. W3DBufferManager::W3DVertexBufferSlot *vbSlot=m_shadowVolumeVB[i][j];
  1528. if (vbSlot)
  1529. { //add to static mesh volume list.
  1530. W3DBufferManager::W3DRenderTask *oldTask=vbSlot->m_VB->m_renderTaskList;
  1531. vbSlot->m_VB->m_renderTaskList=&m_shadowVolumeRenderTask[i][j];
  1532. vbSlot->m_VB->m_renderTaskList->m_nextTask=oldTask;
  1533. }
  1534. else
  1535. {
  1536. TheW3DVolumetricShadowManager->addDynamicShadowTask(&m_shadowVolumeRenderTask[i][j]);
  1537. }
  1538. }
  1539. }
  1540. }
  1541. } // end for j
  1542. } // end for, i
  1543. }
  1544. /*floorZ is the assumed ground height below the model. The code will try to extrude shadows just long enough to hit this point in order
  1545. to reduce fill rate usage.*/
  1546. void W3DVolumetricShadow::updateMeshVolume(Int meshIndex, Int lightIndex, const Matrix3D *meshXform, const AABoxClass &meshBox, float floorZ )
  1547. {
  1548. Vector3 lightPosObject;
  1549. Matrix4 worldToObject;
  1550. Vector3 objectCenter;
  1551. Vector3 toLight;
  1552. Vector3 toPrevLight;
  1553. Vector3 prevPosToLight;
  1554. Vector3 lightPosWorld;
  1555. Vector3 prevObjPosition;
  1556. //Figuring out if mesh has rotated is cheaper (no normalization) than figuring out if light angle has changed.
  1557. //So we divide the 2 tests. Also, our light (sun) almost never moves so no second test needed at all.
  1558. Bool isMeshRotating = false; //flag if mesh has rotated since last update. Translation doesn't matter for infinite light source.
  1559. Bool isLightMoving = false; //flag if light has moved since last update.
  1560. Matrix4 objectToWorld(*meshXform);
  1561. Matrix4 *prevXForm=&m_objectXformHistory[ lightIndex ][meshIndex];
  1562. //
  1563. // build the shadow silhouette and construct shadow volume from
  1564. // this light location. The for loop wrapped around this is
  1565. // theoretical code for future enhancements of multiple lights that
  1566. // cast shadows
  1567. //
  1568. #ifdef ASSUME_NEAR_LIGHTSOURCE
  1569. if (memcmp(&objectToWorld,prevXForm,sizeof(objectToWorld)))
  1570. isMeshRotating = true; //mesh transform has not changed since last update.
  1571. #else
  1572. //When dealing with infinite light sources, we can assume that the shadow doesn't
  1573. //change much based on object position. Only the orientation to light matters.
  1574. Real cosAngle = fabs (Vector3::Dot_Product((Vector3 &)(prevXForm->operator [](0)),(Vector3 &)(objectToWorld.operator [](0))));
  1575. if (cosAngle >= cosAngleToCare)
  1576. { cosAngle = fabs (Vector3::Dot_Product((Vector3 &)(prevXForm->operator [](1)),(Vector3 &)(objectToWorld.operator [](1))));
  1577. if (cosAngle >= cosAngleToCare)
  1578. {
  1579. cosAngle = fabs (Vector3::Dot_Product((Vector3 &)(prevXForm->operator [](2)),(Vector3 &)(objectToWorld.operator [](2))));
  1580. if (cosAngle < cosAngleToCare)
  1581. isMeshRotating=true;
  1582. }
  1583. else
  1584. isMeshRotating =true;
  1585. }
  1586. else
  1587. isMeshRotating =true;
  1588. #endif
  1589. // get the light
  1590. lightPosWorld = TheW3DShadowManager->getLightPosWorld(lightIndex);
  1591. // get the object
  1592. meshXform->Get_Translation(&objectCenter); //current mesh position
  1593. // check if object has a limit/clamp on shadow length and adjust light
  1594. // position of necessary.
  1595. if (m_shadowLengthScale)
  1596. { //Find light's distance from origin in xy plane
  1597. Real lightXYDistance = sqrt(lightPosWorld.X*lightPosWorld.X + lightPosWorld.Y * lightPosWorld.Y);
  1598. Real newZ=lightXYDistance*m_shadowLengthScale;
  1599. if (newZ > lightPosWorld.Z)
  1600. { //clamped z component is higher than actual light position allows so adjust it.
  1601. lightPosWorld.Z = newZ;
  1602. }
  1603. }
  1604. if (lightPosWorld != m_lightPosHistory[ lightIndex ][meshIndex])
  1605. { //Light position has moved, see if enough to matter
  1606. // compute vector from the light to the current object position
  1607. toLight = objectCenter - lightPosWorld;
  1608. toLight.Normalize();
  1609. // compute vector from the previous light to the object position
  1610. toPrevLight = objectCenter - m_lightPosHistory[ lightIndex ][meshIndex];
  1611. toPrevLight.Normalize();
  1612. Real cosAngle = fabs (Vector3::Dot_Product(toLight,toPrevLight));
  1613. if (cosAngle < cosAngleToCare) //less than 45 degree change
  1614. isLightMoving =true;
  1615. }
  1616. else
  1617. ///@todo: Find a better way to deal with this - use maximum extrusion once! Also avoid hit for units climbing hills.
  1618. if (fabs(objectCenter.Z - prevXForm->operator [](2).W) > SHADOW_EXTRUSION_BUFFER)
  1619. isLightMoving = true; //treat model rising just like rotation since volume needs update for longer extrusion.
  1620. // reconstruct if needed
  1621. if (isLightMoving || isMeshRotating)
  1622. {
  1623. //
  1624. // transform the light in the world to object space, we
  1625. // care only about the rotation of components for the coordinate
  1626. // system change, not the translations
  1627. //
  1628. Real det;
  1629. D3DXMatrixInverse((D3DXMATRIX*)&worldToObject, &det, (D3DXMATRIX*)&objectToWorld);
  1630. // find out light position in object space
  1631. Matrix4::Transform_Vector(worldToObject,lightPosWorld,&lightPosObject);
  1632. //Updating shadow volumes is expensive, so verify that this volume is even visible.
  1633. //Generate bounding box around shadow volume by extruding AABB corners
  1634. AABoxClass box(meshBox); //copy current mesh bounding box (will be smaller than shadow box).
  1635. SphereClass sphere; //rough bounding sphere of shadow volume - based on box.
  1636. Vector3 Corners[8];
  1637. Vector3 lightRay;
  1638. Real vectorScale,vectorScaleTemp, vectorScaleMax;
  1639. Real length;
  1640. //Get vertices of top of bounding box
  1641. Corners[0]=box.Center+box.Extent; //top right corner
  1642. Corners[1]=Corners[0];
  1643. Corners[1].X -= 2.0f*box.Extent.X; //top left corner
  1644. Corners[2]=Corners[1];
  1645. Corners[2].Y -= 2.0f*box.Extent.Y; //bottom left corner
  1646. Corners[3]=Corners[2];
  1647. Corners[3].X += 2.0f*box.Extent.X; //bottom right corner
  1648. //Project top volume corners onto ground plane
  1649. lightRay = Corners[0] - lightPosWorld; //vector light to corner
  1650. length= 1.0f/lightRay.Length();
  1651. lightRay *= length;
  1652. vectorScaleMax=vectorScale=(Real)fabs((Corners[0].Z-floorZ)/lightRay.Z); //length of vector from top corner to ground.
  1653. Corners[4]=Corners[0]+lightRay*vectorScale;
  1654. vectorScaleMax *= length;
  1655. lightRay = Corners[1] - lightPosWorld; //vector light to corner
  1656. length= 1.0f/lightRay.Length();
  1657. lightRay *= length;
  1658. vectorScaleTemp=(Real)fabs((Corners[1].Z-floorZ)/lightRay.Z); //length of vector from top corner to ground.
  1659. Corners[5]=Corners[1]+lightRay*vectorScaleTemp;
  1660. vectorScaleTemp *= length;
  1661. if (vectorScaleTemp > vectorScaleMax)
  1662. vectorScaleMax=vectorScaleTemp; //keep track of maximum required extrusion length.
  1663. lightRay = Corners[2] - lightPosWorld; //vector light to corner
  1664. length= 1.0f/lightRay.Length();
  1665. lightRay *= length;
  1666. vectorScale=(Real)fabs((Corners[2].Z-floorZ)/lightRay.Z); //length of vector from top corner to ground.
  1667. Corners[6]=Corners[2]+lightRay*vectorScale;
  1668. vectorScale *= length;
  1669. if (vectorScale > vectorScaleMax)
  1670. vectorScaleMax=vectorScale; //keep track of maximum required extrusion length.
  1671. lightRay = Corners[3] - lightPosWorld; //vector light to corner
  1672. length= 1.0f/lightRay.Length();
  1673. lightRay *= length;
  1674. vectorScaleTemp=(Real)fabs((Corners[3].Z-floorZ)/lightRay.Z); //length of vector from top corner to ground.
  1675. Corners[7]=Corners[3]+lightRay*vectorScaleTemp;
  1676. vectorScaleTemp *= length;
  1677. if (vectorScaleTemp > vectorScaleMax)
  1678. vectorScaleMax=vectorScaleTemp; //keep track of maximum required extrusion length.
  1679. box.Init(Corners, 8); //generate a new bounding box
  1680. sphere.Init(box.Center,box.Extent.Length()); //generate object space bounding sphere containing box.
  1681. CollisionMath::OverlapType result=CollisionMath::Overlap_Test(*shadowCameraFrustum,sphere);
  1682. if (result == CollisionMath::OVERLAPPED) //do a more accurate test
  1683. result=CollisionMath::Overlap_Test(*shadowCameraFrustum, box);
  1684. if (result != CollisionMath::OUTSIDE)
  1685. {
  1686. //
  1687. // reset the silhouette data and build a new one from this light
  1688. // source perspective
  1689. //
  1690. if (m_numSilhouetteIndices[meshIndex] != 0)
  1691. { //this silhouette was built before and is being updated.
  1692. //this probably means it will change again in the future.
  1693. //make future updates faster by pre-caching face normals.
  1694. m_geometry->getMesh(meshIndex)->buildPolygonNormals();
  1695. }
  1696. resetSilhouette(meshIndex);
  1697. buildSilhouette(meshIndex, &lightPosObject);
  1698. //
  1699. // in a multiple shadow situation we would be allocating a volume
  1700. // for this current shadow light, not the 0 index volume all the time
  1701. //
  1702. if (!m_shadowVolume[ lightIndex ][meshIndex])
  1703. allocateShadowVolume( lightIndex,meshIndex );
  1704. if( m_shadowVolumeVB[ lightIndex ][meshIndex] )
  1705. { //Updating an existing vertex buffer shadow volume. This means we're
  1706. //probably dealing with an animated mesh. Update flags to reflect this fact.
  1707. if (isMeshRotating || isLightMoving)
  1708. {
  1709. if (isMeshRotating)
  1710. { //rotating meshes will most likely need updates each frame, so stop using static vertex buffers.
  1711. m_shadowVolume[ lightIndex ][meshIndex]->SetFlags(
  1712. m_shadowVolume[ lightIndex ][meshIndex]->GetFlags() | SHADOW_DYNAMIC);
  1713. }
  1714. //release memory used to store vertices/polygons
  1715. resetShadowVolume( lightIndex,meshIndex ); //free vertex buffers since not used for dynamic.
  1716. //Resize the shadow volume since we'll need room to store the vertices in memory instead of VB.
  1717. allocateShadowVolume( lightIndex,meshIndex );
  1718. }
  1719. }
  1720. //
  1721. // construct the shadow volume at this light position in the
  1722. // passed shadow volume geometry index
  1723. //
  1724. if (m_shadowVolume[ lightIndex ][meshIndex]->GetFlags() & SHADOW_DYNAMIC)
  1725. constructVolume( &lightPosObject, vectorScaleMax, lightIndex, meshIndex );
  1726. else
  1727. constructVolumeVB( &lightPosObject, vectorScaleMax, lightIndex, meshIndex );
  1728. //
  1729. // store the current light position and orientation that
  1730. // we constructed shadow info at
  1731. //
  1732. m_objectXformHistory[ lightIndex ][meshIndex] = objectToWorld;
  1733. m_lightPosHistory[lightIndex][meshIndex] = lightPosWorld;
  1734. box.Translate(-objectCenter); //translate box to object space.
  1735. m_shadowVolume[ lightIndex ][meshIndex]->setBoundingBox(box);
  1736. sphere.Center -= objectCenter;
  1737. m_shadowVolume[ lightIndex ][meshIndex]->setBoundingSphere(sphere);
  1738. m_shadowVolume[ lightIndex ][meshIndex]->setVisibleState(Geometry::STATE_VISIBLE); //this volume needs rendering.
  1739. }//end if inside view frustum
  1740. else
  1741. if (m_shadowVolume[ lightIndex ][meshIndex])
  1742. { //outside view frustum, shadow wasn't updated.
  1743. box.Translate(-objectCenter); //translate box to object space.
  1744. m_shadowVolume[ lightIndex ][meshIndex]->setBoundingBox(box);
  1745. sphere.Center -= objectCenter;
  1746. m_shadowVolume[ lightIndex ][meshIndex]->setBoundingSphere(sphere);
  1747. m_shadowVolume[ lightIndex ][meshIndex]->setVisibleState(Geometry::STATE_INVISIBLE);
  1748. }
  1749. } // end if
  1750. else
  1751. { //not reconstructing volume, so don't know if visible or not.
  1752. if (m_shadowVolume[ lightIndex ][meshIndex])
  1753. m_shadowVolume[ lightIndex ][meshIndex]->setVisibleState(Geometry::STATE_UNKNOWN);
  1754. }
  1755. }
  1756. // addSilhouetteEdge ==========================================================
  1757. // It has been determined that the polygon neighbor in the "neighborIndex"
  1758. // of "visible" needs to be added to the silhouette. We will add those two
  1759. // vertex indices to the silhouette in the order they were specified in
  1760. // "visible" to assure that the constructed edge is in counter clockwise order
  1761. // ============================================================================
  1762. void W3DVolumetricShadow::addSilhouetteEdge(Int meshIndex, PolyNeighbor *visible, PolyNeighbor *hidden )
  1763. {
  1764. Int i;
  1765. Int neighborIndex = 0;
  1766. Short visibleIndexList[ 3 ];
  1767. Short edgeStart, edgeEnd;
  1768. W3DShadowGeometryMesh *geomMesh=m_geometry->getMesh(meshIndex);
  1769. // sanity
  1770. assert( visible && hidden );
  1771. //
  1772. // which index in the neighbor list of "visible" refers to the
  1773. // polygon "hidden"
  1774. //
  1775. for( i = 0; i < MAX_POLYGON_NEIGHBORS; i++ )
  1776. {
  1777. if( visible->neighbor[ i ].neighborIndex == hidden->myIndex )
  1778. {
  1779. neighborIndex = i;
  1780. break; // exit for
  1781. } // end if
  1782. } // end for i
  1783. // get the three vertex indices of "visible"
  1784. geomMesh->GetPolygonIndex( visible->myIndex, visibleIndexList, 3 );
  1785. //
  1786. // we know that 2 of the 3 vertex indices will be present in the edge.
  1787. // will construct the edge as follows to ensure we have counter
  1788. // clockwise order. note that this assumes the vertices of the
  1789. // polygons specified in the geometry are in counter clockwise order,
  1790. // which they are
  1791. //
  1792. // 1) [ v1 Absent, v2 Present, v3 Present ] -> edge = (v2, v3)
  1793. // 2) [ v1 Present, v2 Absent, v3 Present ] -> edge = (v3, v1)
  1794. // 3) [ v1 Present, v2 Present, v3 Absent ] -> edge = (v1, v2)
  1795. //
  1796. if( (visibleIndexList[ 0 ] !=
  1797. visible->neighbor[ neighborIndex ].neighborEdgeIndex[ 0 ]) &&
  1798. (visibleIndexList[ 0 ] !=
  1799. visible->neighbor[ neighborIndex ].neighborEdgeIndex[ 1 ]) )
  1800. {
  1801. // case 1 above
  1802. edgeStart = visibleIndexList[ 1 ];
  1803. edgeEnd = visibleIndexList[ 2 ];
  1804. } // end if
  1805. else if( (visibleIndexList[ 1 ] !=
  1806. visible->neighbor[ neighborIndex ].neighborEdgeIndex[ 0 ]) &&
  1807. (visibleIndexList[ 1 ] !=
  1808. visible->neighbor[ neighborIndex ].neighborEdgeIndex[ 1 ]) )
  1809. {
  1810. // case 2 above
  1811. edgeStart = visibleIndexList[ 2 ];
  1812. edgeEnd = visibleIndexList[ 0 ];
  1813. } // end if
  1814. else
  1815. {
  1816. // case 3 above
  1817. edgeStart = visibleIndexList[ 0 ];
  1818. edgeEnd = visibleIndexList[ 1 ];
  1819. } // end if
  1820. // add to silhouette edge list
  1821. addSilhouetteIndices(meshIndex, edgeStart, edgeEnd );
  1822. } // end addSilhouetteEdge
  1823. // addNeighborlessEdges =======================================================
  1824. // Given a polygon neighbor information, it has been determined that this
  1825. // polygon is visible and has edges which are not connected to other
  1826. // polygons, these edges need to be added to the silhouette. The edge(s)
  1827. // must be added in such an order that we create silhouette edges in a
  1828. // counter clockwise order.
  1829. // ============================================================================
  1830. void W3DVolumetricShadow::addNeighborlessEdges(Int meshIndex, PolyNeighbor *us )
  1831. {
  1832. Short vertexIndexList[ 3 ];
  1833. Int i, j;
  1834. Short edgeStart, edgeEnd;
  1835. Bool addEdge;
  1836. // sanity
  1837. assert( us );
  1838. W3DShadowGeometryMesh *geomMesh = m_geometry->getMesh(meshIndex);
  1839. // get the vertex index list from the geometry
  1840. geomMesh->GetPolygonIndex( us->myIndex, vertexIndexList, 3 );
  1841. //
  1842. // go through each edge, if these indices to NOT appear TOGETHER in
  1843. // neighbor list then we must add it.
  1844. //
  1845. for( i = 0; i < 3; i++ )
  1846. {
  1847. // get the edge start and end vertex indices
  1848. edgeStart = vertexIndexList[ i ];
  1849. if( i == 2 )
  1850. edgeEnd = vertexIndexList[ 0 ]; // wraps to begging of list
  1851. else
  1852. edgeEnd = vertexIndexList[ i + 1 ];
  1853. // do these two vertices appear in a neighbor list of the poly?
  1854. addEdge = TRUE;
  1855. for( j = 0; j < MAX_POLYGON_NEIGHBORS; j++ )
  1856. {
  1857. if( us->neighbor[ j ].neighborIndex != NO_NEIGHBOR )
  1858. {
  1859. if( (us->neighbor[ j ].neighborEdgeIndex[ 0 ] == edgeStart &&
  1860. us->neighbor[ j ].neighborEdgeIndex[ 1 ] == edgeEnd) ||
  1861. (us->neighbor[ j ].neighborEdgeIndex[ 1 ] == edgeStart &&
  1862. us->neighbor[ j ].neighborEdgeIndex[ 0 ] == edgeEnd) )
  1863. {
  1864. addEdge = FALSE;
  1865. break; // exit for j, no need to search on
  1866. } // end if
  1867. } // end if
  1868. } // end for j
  1869. // add the edge if no neighbors have that edge
  1870. if( addEdge == TRUE )
  1871. {
  1872. addSilhouetteIndices(meshIndex, edgeStart, edgeEnd );
  1873. } // end if
  1874. } // end for i
  1875. } // end addNeighborlessEdges
  1876. // addSilhouetteIndices =======================================================
  1877. // Add these two indices to the silhouette data
  1878. // ============================================================================
  1879. void W3DVolumetricShadow::addSilhouetteIndices(Int meshIndex, Short edgeStart, Short edgeEnd )
  1880. {
  1881. // DBGPRINTF(( "addSilhouetteIndices: Adding (%d,%d), the storage before the add is = (%d/%d)\n",
  1882. // edgeStart, edgeEnd, m_numSilhouetteIndices, m_maxSilhouetteEntries ));
  1883. // add to silhouette edge list
  1884. assert( m_numSilhouetteIndices[meshIndex] < m_maxSilhouetteEntries[meshIndex] );
  1885. m_silhouetteIndex[meshIndex][ m_numSilhouetteIndices[meshIndex]++ ] = edgeStart;
  1886. assert( m_numSilhouetteIndices[meshIndex] < m_maxSilhouetteEntries[meshIndex] );
  1887. m_silhouetteIndex[meshIndex][ m_numSilhouetteIndices[meshIndex]++ ] = edgeEnd;
  1888. } // end if
  1889. // buildSilhouette ============================================================
  1890. // Given a light position, and our polygon neighbor information this will
  1891. // build the silhouette of the object edges from the given light position
  1892. // ============================================================================
  1893. void W3DVolumetricShadow::buildSilhouette(Int meshIndex, Vector3 *lightPosObject)
  1894. {
  1895. PolyNeighbor *polyNeighbor; // the poly we're looking at right now
  1896. Vector3 normal; // normal of current polygon
  1897. Vector3 lightVector; // vector from light to polygon
  1898. Bool visibleNeighborless;
  1899. Int numPolys; // number of polys in our geometry
  1900. W3DShadowGeometryMesh *geomMesh;
  1901. Int i, j;
  1902. Int meshEdgeStart=0; //index to first edge contributed by specific mesh
  1903. //
  1904. // go through each of our shadow geometry polygon info and find out
  1905. // which polys are visible from this light source and which ones are not
  1906. //
  1907. geomMesh = m_geometry->getMesh(meshIndex);
  1908. //record where this meshes indices will begin.
  1909. meshEdgeStart=m_numSilhouetteIndices[meshIndex];
  1910. numPolys = geomMesh->GetNumPolygon();
  1911. for( i = 0; i < numPolys; i++ )
  1912. {
  1913. Short poly[ 3 ];
  1914. Vector3 vertex;
  1915. // get this polygon neighbor information
  1916. polyNeighbor = geomMesh->GetPolyNeighbor( i );
  1917. // take this opportunity to initialize our processing flags to zero
  1918. polyNeighbor->status = 0;
  1919. // get the normal for this polygon
  1920. geomMesh->GetPolygonNormal( i, &normal );
  1921. // get the vertex indices at this polygon
  1922. geomMesh->GetPolygonIndex( i, poly, 3 );
  1923. //
  1924. // find out "lightVector" to this polygon
  1925. //
  1926. // since our light source could be very close to the object and that
  1927. // would change the shadow we are going to say that the light vector
  1928. // is from the light position to one of the vertices in the polygon.
  1929. // To be more correct we should use the center of the polygon but
  1930. // this is a good approximation ... an ever broader approximation that
  1931. // we could use would be the object center
  1932. //
  1933. geomMesh->GetVertex( poly[ 0 ], &vertex );
  1934. lightVector= vertex - *lightPosObject;
  1935. //
  1936. // dot the light vector with the normal of the polygon to see if the
  1937. // poly is visible from this location
  1938. //
  1939. if( Vector3::Dot_Product( lightVector, normal ) < 0.0f )
  1940. BitSet( polyNeighbor->status, POLY_VISIBLE );
  1941. } // end for i
  1942. //
  1943. // check all our polys using our poly neighbors, where one poly neighbor
  1944. // is not the same visible status as a neighbor that represents a
  1945. // silhouette edge
  1946. //
  1947. for( i = 0; i < numPolys; i++ )
  1948. {
  1949. PolyNeighbor *otherNeighbor;
  1950. // get this poly neighbor ... this is "us"
  1951. polyNeighbor = geomMesh->GetPolyNeighbor( i );
  1952. // initialize ourselves to not be a visible edge
  1953. visibleNeighborless = FALSE;
  1954. // check our 3 potential neighbors
  1955. for( j = 0; j < MAX_POLYGON_NEIGHBORS; j++ )
  1956. {
  1957. // initialize this neighbor to nuttin
  1958. otherNeighbor = NULL;
  1959. // get our neighbor if present and cull them if processed
  1960. if( polyNeighbor->neighbor[ j ].neighborIndex != NO_NEIGHBOR )
  1961. {
  1962. // get the jth polygon neighbor ... this is "them"
  1963. otherNeighbor =
  1964. geomMesh->GetPolyNeighbor(
  1965. polyNeighbor->neighbor[ j ].neighborIndex );
  1966. //
  1967. // ignore neighbors that are marked as processed as those
  1968. // onces have already detected edges if present
  1969. //
  1970. if( BitTest( otherNeighbor->status, POLY_PROCESSED ) )
  1971. continue; // for j
  1972. } // end if
  1973. //
  1974. // finally, if our own visible status is different from our
  1975. // neighbor visible status then that defines an edge we must
  1976. // add to the silhouette. Also, a visible polygon that has
  1977. // no neighbor automatically makes a silhouette edge. Note that
  1978. // if we have no neighbor we just record the fact that we have
  1979. // real model end edges to add after this inner j loop;
  1980. //
  1981. if( BitTest( polyNeighbor->status, POLY_VISIBLE ) )
  1982. {
  1983. // check for no neighbor edges
  1984. if( otherNeighbor == NULL )
  1985. {
  1986. visibleNeighborless = TRUE;
  1987. } // end if
  1988. else if( BitTest( otherNeighbor->status, POLY_VISIBLE ) == FALSE )
  1989. {
  1990. // "we" are visible and "they" are not
  1991. addSilhouetteEdge(meshIndex, polyNeighbor, otherNeighbor );
  1992. } // end if
  1993. } // end if
  1994. else if( otherNeighbor != NULL &&
  1995. BitTest( otherNeighbor->status, POLY_VISIBLE ) )
  1996. {
  1997. // "they" are visible and "we" are not
  1998. addSilhouetteEdge(meshIndex, otherNeighbor, polyNeighbor );
  1999. } // end else
  2000. } // end for j
  2001. //
  2002. // if this polygon is visible, add any edges that are not
  2003. // neighbors of adjacent polygons.
  2004. //
  2005. if( visibleNeighborless == TRUE )
  2006. {
  2007. addNeighborlessEdges(meshIndex, polyNeighbor );
  2008. } // end if
  2009. //
  2010. // this polyNeighbor is now considered "processed", any other
  2011. // polygons that reference back to this one can ignore their
  2012. // processing cause any edges were already detected
  2013. //
  2014. BitSet( polyNeighbor->status, POLY_PROCESSED );
  2015. } // end for i
  2016. //record number of edge indices contrinuted by this mesh
  2017. m_numIndicesPerMesh[meshIndex]=m_numSilhouetteIndices[meshIndex]-meshEdgeStart;
  2018. } // end buildSilhouette
  2019. // constructVolume ============================================================
  2020. // Given a fresh new geometry class called "shadowVolume" to hold the actual
  2021. // shadow volume data, this method will create the shadow volume polygons
  2022. // given the information in the current silhouette of this Shadow and the
  2023. // light source position.
  2024. //
  2025. // The light source should be in object space and the shadow volume polygon
  2026. // data is also constructed in object space.
  2027. //
  2028. // The polygon we will create for a given edge will be that edge extruded
  2029. // out in the direction away from the light source. This conceptual 4 sided
  2030. // polygon is however broken up into two triangles for storage.
  2031. //
  2032. // This version is designed to construct the volume inside a system memory
  2033. // buffer - to be rendered via a dynamic vertex buffer.
  2034. //
  2035. // ============================================================================
  2036. void W3DVolumetricShadow::constructVolume( Vector3 *lightPosObject,Real shadowExtrudeDistance, Int volumeIndex, Int meshIndex )
  2037. {
  2038. Geometry *shadowVolume;
  2039. Vector3 extrude2; // the polypoints extruded from edge and light
  2040. Vector3 edgeVertex2; // second edge of silhouette
  2041. Short indexList[ 3 ];
  2042. Int i,k;
  2043. Int vertexCount;
  2044. Int polygonCount;
  2045. Int indicesPerMesh;
  2046. W3DShadowGeometryMesh *geomMesh;
  2047. // sanity
  2048. if( volumeIndex < 0 ||
  2049. volumeIndex >= MAX_SHADOW_LIGHTS ||
  2050. lightPosObject == NULL )
  2051. {
  2052. assert( 0 );
  2053. return;
  2054. } // end if
  2055. // get the geometry struct we're storing the actual shadow volume data in
  2056. shadowVolume = m_shadowVolume[ volumeIndex ][meshIndex];
  2057. if( shadowVolume == NULL )
  2058. {
  2059. // DBGPRINTF(( "No volume allocated at index '%d'\n", volumeIndex ));
  2060. assert( 0 );
  2061. return;
  2062. } // end if
  2063. // step through each of the silhouette pairs
  2064. vertexCount = 0;
  2065. polygonCount = 0;
  2066. indicesPerMesh=m_numIndicesPerMesh[meshIndex];
  2067. if (!indicesPerMesh)
  2068. return; //nothing to draw
  2069. geomMesh = m_geometry->getMesh(meshIndex);
  2070. shadowVolume->SetNumActivePolygon(0);
  2071. shadowVolume->SetNumActiveVertex(0);
  2072. #ifdef RECORD_SHADOW_STRIP_STATS
  2073. Int numStrips=0; //keeps track of number of strips generated.
  2074. Int stripLength=1; //keeps track of segments in strip (each being 2 triangles).
  2075. Int maxStripLength=0; //keeps track of longest strip generated.
  2076. #endif
  2077. Short *silhouetteIndices=m_silhouetteIndex[meshIndex];
  2078. //Initialize first strip info
  2079. Short stripStartIndex=silhouetteIndices[ 0 ];
  2080. Short stripStartVertex=0;
  2081. //Insert the first vertex and extrusion into strip.
  2082. // get edge point
  2083. geomMesh->GetVertex( silhouetteIndices[ 0 ], &edgeVertex2 );
  2084. // take one edge point and extrude away from the light
  2085. extrude2 = edgeVertex2 - *lightPosObject;
  2086. extrude2 *= shadowExtrudeDistance;
  2087. extrude2 += edgeVertex2;
  2088. shadowVolume->SetVertex( vertexCount, &edgeVertex2 );
  2089. shadowVolume->SetVertex( vertexCount + 1, &extrude2 );
  2090. vertexCount=2;
  2091. Int lastEdgeVertex2Index=0;
  2092. Int lastExtrude2Index=1;
  2093. for( i = 0; i < indicesPerMesh; i += 2 )
  2094. {
  2095. Short currentEdgeEnd=silhouetteIndices[i+1];
  2096. //look for edge connected to this one and move it next to this edge
  2097. //in index list. Rendering edges back-to-back improves vertex cache usage.
  2098. for (k=i+2; k<indicesPerMesh; k+=2)
  2099. if (silhouetteIndices[k]==currentEdgeEnd)
  2100. { //swap the two edges
  2101. Int tempIndex=*(Int *)(&silhouetteIndices[i+2]);
  2102. *(Int *)&silhouetteIndices[i+2]=*(Int *)&silhouetteIndices[k];
  2103. *(Int *)&silhouetteIndices[k]=tempIndex;
  2104. break;
  2105. }
  2106. if (k >= indicesPerMesh)
  2107. { //reached end of strip. Insert final edge.
  2108. //Check if last edge wraps around to start.
  2109. if (currentEdgeEnd == stripStartIndex)
  2110. { //add end of strip that wraps around to start (forming closed cylinder/shape)
  2111. //
  2112. // add the polygon consisting of the two edge vertices and the
  2113. // first extruded point
  2114. //
  2115. indexList[ 0 ] = lastEdgeVertex2Index; // lastedgeVertex2 index
  2116. indexList[ 1 ] = lastExtrude2Index; // lastextrude2 index
  2117. indexList[ 2 ] = stripStartVertex; // edgeVertex2 index
  2118. shadowVolume->SetPolygonIndex( polygonCount, indexList, 3 );
  2119. indexList[ 0 ] = stripStartVertex; // edgeVertex2 index
  2120. indexList[ 1 ] = lastExtrude2Index; // extrude1 index
  2121. indexList[ 2 ] = stripStartVertex+1; // extrude2 index
  2122. shadowVolume->SetPolygonIndex( polygonCount + 1, indexList, 3 );
  2123. }
  2124. else
  2125. { //add end of strip. Finishes the last 2 polygons.
  2126. geomMesh->GetVertex( currentEdgeEnd, &edgeVertex2 );
  2127. shadowVolume->SetVertex( vertexCount, &edgeVertex2 );
  2128. //
  2129. // add the polygon consisting of the two edge vertices and the
  2130. // first extruded point
  2131. //
  2132. indexList[ 0 ] = lastEdgeVertex2Index; // lastedgeVertex2 index
  2133. indexList[ 1 ] = lastExtrude2Index; // lastextrude2 index
  2134. indexList[ 2 ] = vertexCount; // edgeVertex2 index
  2135. shadowVolume->SetPolygonIndex( polygonCount, indexList, 3 );
  2136. // take the other edge point and extrude away from light
  2137. extrude2 = edgeVertex2 - *lightPosObject;
  2138. extrude2 *= shadowExtrudeDistance;
  2139. extrude2 += edgeVertex2;
  2140. // add the one new vertex
  2141. shadowVolume->SetVertex( vertexCount + 1, &extrude2 );
  2142. indexList[ 0 ] = vertexCount; // edgeVertex2 index
  2143. indexList[ 1 ] = lastExtrude2Index; // extrude1 index
  2144. indexList[ 2 ] = vertexCount+1; // extrude2 index
  2145. shadowVolume->SetPolygonIndex( polygonCount + 1, indexList, 3 );
  2146. lastEdgeVertex2Index=vertexCount;
  2147. lastExtrude2Index=vertexCount+1;
  2148. vertexCount += 2;
  2149. }
  2150. if ((i+2) >= indicesPerMesh)
  2151. { //finished with all silhouette edges
  2152. polygonCount += 2;
  2153. #ifdef RECORD_SHADOW_STRIP_STATS
  2154. numStrips++;
  2155. #endif
  2156. break; //reached end of all edges
  2157. }
  2158. //Start a new strip by adding first vertex and extrusion.
  2159. geomMesh->GetVertex( silhouetteIndices[ i+2 ], &edgeVertex2 );
  2160. // take one edge point and extrude away from the light
  2161. extrude2 = edgeVertex2 - *lightPosObject;
  2162. extrude2 *= shadowExtrudeDistance;
  2163. extrude2 += edgeVertex2;
  2164. lastEdgeVertex2Index=vertexCount;
  2165. lastExtrude2Index=vertexCount + 1;
  2166. //record start of new strip info
  2167. stripStartIndex=silhouetteIndices[ i+2 ];
  2168. stripStartVertex=lastEdgeVertex2Index;
  2169. shadowVolume->SetVertex( lastEdgeVertex2Index, &edgeVertex2 );
  2170. shadowVolume->SetVertex( lastExtrude2Index, &extrude2 );
  2171. vertexCount += 2;
  2172. polygonCount += 2;
  2173. #ifdef RECORD_SHADOW_STRIP_STATS
  2174. numStrips++;
  2175. stripLength=1;
  2176. #endif
  2177. continue;
  2178. }
  2179. else
  2180. { //continue existing strip by adding extra vertex and extrusion
  2181. geomMesh->GetVertex( currentEdgeEnd, &edgeVertex2 );
  2182. shadowVolume->SetVertex( vertexCount, &edgeVertex2 );
  2183. //
  2184. // add the polygon consisting of the two edge vertices and the
  2185. // first extruded point
  2186. //
  2187. indexList[ 0 ] = lastEdgeVertex2Index; // lastedgeVertex2 index
  2188. indexList[ 1 ] = lastExtrude2Index; // lastextrude2 index
  2189. indexList[ 2 ] = vertexCount; // edgeVertex2 index
  2190. shadowVolume->SetPolygonIndex( polygonCount, indexList, 3 );
  2191. // take the other edge point and extrude away from light
  2192. extrude2 = edgeVertex2 - *lightPosObject;
  2193. extrude2 *= shadowExtrudeDistance;
  2194. extrude2 += edgeVertex2;
  2195. // add the one new vertex
  2196. shadowVolume->SetVertex( vertexCount + 1, &extrude2 );
  2197. indexList[ 0 ] = vertexCount; // edgeVertex2 index
  2198. indexList[ 1 ] = lastExtrude2Index; // extrude1 index
  2199. indexList[ 2 ] = vertexCount+1; // extrude2 index
  2200. shadowVolume->SetPolygonIndex( polygonCount + 1, indexList, 3 );
  2201. lastEdgeVertex2Index=vertexCount;
  2202. lastExtrude2Index=vertexCount+1;
  2203. vertexCount += 2;
  2204. polygonCount += 2;
  2205. }
  2206. #ifdef RECORD_SHADOW_STRIP_STATS
  2207. //Continuing strip.
  2208. stripLength++;
  2209. maxStripLength=__max(maxStripLength,stripLength);
  2210. #endif
  2211. }
  2212. shadowVolume->SetNumActivePolygon(polygonCount);
  2213. shadowVolume->SetNumActiveVertex(vertexCount);
  2214. } // end constructVolume
  2215. // constructVolumeVB ==========================================================
  2216. // Given a fresh new geometry class called "shadowVolume" to hold the actual
  2217. // shadow volume data, this method will create the shadow volume polygons
  2218. // given the information in the current silhouette of this Shadow and the
  2219. // light source position.
  2220. //
  2221. // The light source should be in object space and the shadow volume polygon
  2222. // data is also constructed in object space.
  2223. //
  2224. // The polygon we will create for a given edge will be that edge extruded
  2225. // out in the direction away from the light source. This conceptual 4 sided
  2226. // polygon is however broken up into two triangles for storage.
  2227. //
  2228. // This version is designed to construct the volume directly inside a vertex
  2229. // buffer so it's optimal for static geometry. Since it's assumed to be called
  2230. // only once per model, we can use some more expensive computations to generate
  2231. // the volume.
  2232. //
  2233. // ============================================================================
  2234. void W3DVolumetricShadow::constructVolumeVB( Vector3 *lightPosObject,Real shadowExtrudeDistance, Int volumeIndex, Int meshIndex )
  2235. {
  2236. Geometry *shadowVolume;
  2237. Vector3 extrude2; // the polypoints extruded from edge and light
  2238. Vector3 edgeVertex2; // second edge of silhouette
  2239. Int i,k;
  2240. Int vertexCount;
  2241. Int polygonCount;
  2242. Int indicesPerMesh;
  2243. W3DShadowGeometryMesh *geomMesh;
  2244. W3DBufferManager::W3DVertexBufferSlot *vbSlot;
  2245. W3DBufferManager::W3DIndexBufferSlot *ibSlot;
  2246. // sanity
  2247. if( volumeIndex < 0 ||
  2248. volumeIndex >= MAX_SHADOW_LIGHTS ||
  2249. lightPosObject == NULL )
  2250. {
  2251. assert( 0 );
  2252. return;
  2253. } // end if
  2254. // get the geometry struct we're storing the actual shadow volume data in
  2255. shadowVolume = m_shadowVolume[ volumeIndex ][meshIndex];
  2256. if( shadowVolume == NULL )
  2257. {
  2258. // DBGPRINTF(( "No volume allocated at index '%d'\n", volumeIndex ));
  2259. assert( 0 );
  2260. return;
  2261. } // end if
  2262. //*****************************************************************************************/
  2263. //Do an initial pass through silhouette data to determine the actual vertex/polygon counts.
  2264. //This number can't be determined any other way since it depends on degree of vertex sharing
  2265. //in model. We don't want to overallocate because vertex buffer space is limited.
  2266. //This pass is also used to sort the edges so they are all connected in strip order.
  2267. {
  2268. #ifdef RECORD_SHADOW_STRIP_STATS
  2269. Int numStrips=0; //keeps track of number of strips generated.
  2270. Int stripLength=1; //keeps track of segments in strip (each being 2 triangles).
  2271. Int maxStripLength=0; //keeps track of longest strip generated.
  2272. #endif
  2273. // step through each of the silhouette pairs
  2274. vertexCount = 0;
  2275. polygonCount = 0;
  2276. indicesPerMesh=m_numIndicesPerMesh[meshIndex];
  2277. if (!indicesPerMesh)
  2278. return; //nothing to draw
  2279. Short *silhouetteIndices=m_silhouetteIndex[meshIndex];
  2280. //Initialize first strip info
  2281. Short stripStartIndex=silhouetteIndices[ 0 ];
  2282. Short stripStartVertex=0;
  2283. vertexCount=2;
  2284. Int lastEdgeVertex2Index=0;
  2285. Int lastExtrude2Index=1;
  2286. for( i = 0; i < indicesPerMesh; i += 2 )
  2287. {
  2288. Short currentEdgeEnd=silhouetteIndices[i+1];
  2289. //look for edge connected to this one and move it next to this edge
  2290. //in index list. Rendering edges back-to-back improves vertex cache usage.
  2291. for (k=i+2; k<indicesPerMesh; k+=2)
  2292. if (silhouetteIndices[k]==currentEdgeEnd)
  2293. { //swap the two edges
  2294. Int tempIndex=*(Int *)(&silhouetteIndices[i+2]);
  2295. *(Int *)&silhouetteIndices[i+2]=*(Int *)&silhouetteIndices[k];
  2296. *(Int *)&silhouetteIndices[k]=tempIndex;
  2297. break;
  2298. }
  2299. if (k >= indicesPerMesh)
  2300. { //reached end of strip. Insert final edge.
  2301. //Check if last edge wraps around to start.
  2302. if (currentEdgeEnd == stripStartIndex)
  2303. { //add end of strip that wraps around to start (forming closed cylinder/shape)
  2304. //
  2305. // add the polygon consisting of the two edge vertices and the
  2306. // first extruded point
  2307. //
  2308. }
  2309. else
  2310. { //add end of strip. Finishes the last 2 polygons.
  2311. lastEdgeVertex2Index=vertexCount;
  2312. lastExtrude2Index=vertexCount+1;
  2313. vertexCount += 2;
  2314. }
  2315. if ((i+2) >= indicesPerMesh)
  2316. { //finished with all silhouette edges
  2317. polygonCount += 2;
  2318. #ifdef RECORD_SHADOW_STRIP_STATS
  2319. numStrips++;
  2320. #endif
  2321. break; //reached end of all edges
  2322. }
  2323. lastEdgeVertex2Index=vertexCount;
  2324. lastExtrude2Index=vertexCount + 1;
  2325. //record start of new strip info
  2326. stripStartIndex=silhouetteIndices[ i+2 ];
  2327. stripStartVertex=lastEdgeVertex2Index;
  2328. vertexCount += 2;
  2329. polygonCount += 2;
  2330. #ifdef RECORD_SHADOW_STRIP_STATS
  2331. numStrips++;
  2332. stripLength=1;
  2333. #endif
  2334. continue;
  2335. }
  2336. else
  2337. { //continue existing strip by adding extra vertex and extrusion
  2338. lastEdgeVertex2Index=vertexCount;
  2339. lastExtrude2Index=vertexCount+1;
  2340. vertexCount += 2;
  2341. polygonCount += 2;
  2342. }
  2343. #ifdef RECORD_SHADOW_STRIP_STATS
  2344. //Continuing strip.
  2345. stripLength++;
  2346. maxStripLength=__max(maxStripLength,stripLength);
  2347. #endif
  2348. }
  2349. } //initial pass to determine vertex/polygon counts.
  2350. //***********************************************************************************************
  2351. DEBUG_ASSERTCRASH(m_shadowVolumeVB[ volumeIndex ][meshIndex] == NULL,("Updating Existing Static Vertex Buffer Shadow"));
  2352. vbSlot=m_shadowVolumeVB[ volumeIndex ][meshIndex] = TheW3DBufferManager->getSlot(W3DBufferManager::VBM_FVF_XYZ,
  2353. vertexCount);
  2354. DEBUG_ASSERTCRASH(vbSlot != NULL, ("Can't allocate vertex buffer slot for shadow volume"));
  2355. DEBUG_ASSERTCRASH(vbSlot->m_size >= vertexCount,("Overflowing Shadow Vertex Buffer Slot"));
  2356. DEBUG_ASSERTCRASH(m_shadowVolume[ volumeIndex ][meshIndex]->GetNumPolygon() == 0,("Updating Existing Static Shadow Volume"));
  2357. DEBUG_ASSERTCRASH(m_shadowVolumeIB[ volumeIndex ][meshIndex] == NULL,("Updating Existing Static Index Buffer Shadow"));
  2358. ibSlot=m_shadowVolumeIB[ volumeIndex ][meshIndex] = TheW3DBufferManager->getSlot(polygonCount*3);
  2359. DEBUG_ASSERTCRASH(ibSlot != NULL, ("Can't allocate index buffer slot for shadow volume"));
  2360. DEBUG_ASSERTCRASH(ibSlot->m_size >= (polygonCount*3),("Overflowing Shadow Index Buffer Slot"));
  2361. if (!ibSlot || !vbSlot)
  2362. { //could not allocate storage to hold buffers
  2363. if (ibSlot)
  2364. TheW3DBufferManager->releaseSlot(ibSlot);
  2365. if (vbSlot)
  2366. TheW3DBufferManager->releaseSlot(vbSlot);
  2367. m_shadowVolumeIB[ volumeIndex ][meshIndex]=NULL;
  2368. m_shadowVolumeVB[ volumeIndex ][meshIndex]=NULL;
  2369. return;
  2370. }
  2371. geomMesh = m_geometry->getMesh(meshIndex);
  2372. DX8VertexBufferClass::AppendLockClass lockVtxBuffer(vbSlot->m_VB->m_DX8VertexBuffer,vbSlot->m_start,vertexCount);
  2373. VertexFormatXYZ *vb = (VertexFormatXYZ*)lockVtxBuffer.Get_Vertex_Array();
  2374. if (vb == NULL)
  2375. return;
  2376. DX8IndexBufferClass::AppendLockClass lockIdxBuffer(ibSlot->m_IB->m_DX8IndexBuffer,ibSlot->m_start,polygonCount*3);
  2377. UnsignedShort *ib = (UnsignedShort*)lockIdxBuffer.Get_Index_Array();
  2378. if (ib == NULL)
  2379. return;
  2380. shadowVolume->SetNumActivePolygon(polygonCount);
  2381. shadowVolume->SetNumActiveVertex(vertexCount);
  2382. Short *silhouetteIndices=m_silhouetteIndex[meshIndex];
  2383. //Initialize first strip info
  2384. Short stripStartIndex=silhouetteIndices[ 0 ];
  2385. Short stripStartVertex=0;
  2386. //Insert the first vertex and extrusion into strip.
  2387. // get edge point
  2388. geomMesh->GetVertex( silhouetteIndices[ 0 ], &edgeVertex2 );
  2389. // take one edge point and extrude away from the light
  2390. extrude2 = edgeVertex2 - *lightPosObject;
  2391. extrude2 *= shadowExtrudeDistance;
  2392. extrude2 += edgeVertex2;
  2393. *vb++ = *(VertexFormatXYZ *)&edgeVertex2;
  2394. *vb++ = *(VertexFormatXYZ *)&extrude2;
  2395. vertexCount=2;
  2396. polygonCount=0;
  2397. Int lastEdgeVertex2Index=0;
  2398. Int lastExtrude2Index=1;
  2399. for( i = 0; i < indicesPerMesh; i += 2 )
  2400. {
  2401. Short currentEdgeEnd=silhouetteIndices[i+1];
  2402. //Check if another edge is connected to this one, edges were sorted in initial
  2403. //pass so only need to check the next one.
  2404. if (((i+2) >= indicesPerMesh) || silhouetteIndices[i+2] != currentEdgeEnd)
  2405. { //reached end of strip. Insert final edge.
  2406. //Check if last edge wraps around to start.
  2407. if (currentEdgeEnd == stripStartIndex)
  2408. { //add end of strip that wraps around to start (forming closed cylinder/shape)
  2409. //
  2410. // add the polygon consisting of the two edge vertices and the
  2411. // first extruded point
  2412. //
  2413. ib[ 0 ] = lastEdgeVertex2Index; // lastedgeVertex2 index
  2414. ib[ 4 ] = ib[ 1 ] = lastExtrude2Index; // lastextrude2 index
  2415. ib[ 3 ] = ib[ 2 ] = stripStartVertex; // edgeVertex2 index
  2416. ib[ 5 ] = stripStartVertex+1; // extrude2 index
  2417. ib += 6; //skip past 2 triangles just added.
  2418. }
  2419. else
  2420. { //add end of strip. Finishes the last 2 polygons.
  2421. geomMesh->GetVertex( currentEdgeEnd, &edgeVertex2 );
  2422. *vb++ = *(VertexFormatXYZ *)&edgeVertex2;
  2423. //
  2424. // add the polygon consisting of the two edge vertices and the
  2425. // first extruded point
  2426. //
  2427. ib[ 0 ] = lastEdgeVertex2Index; // lastedgeVertex2 index
  2428. ib[ 4 ] = ib[ 1 ] = lastExtrude2Index; // lastextrude2 index
  2429. ib[ 3 ] = ib[ 2 ] = vertexCount; // edgeVertex2 index
  2430. ib[ 5 ] = vertexCount+1; // extrude2 index
  2431. ib += 6; //skip past 2 triangles just added.
  2432. // take the other edge point and extrude away from light
  2433. extrude2 = edgeVertex2 - *lightPosObject;
  2434. extrude2 *= shadowExtrudeDistance;
  2435. extrude2 += edgeVertex2;
  2436. // add the one new vertex
  2437. *vb++ = *(VertexFormatXYZ *)&extrude2;
  2438. lastEdgeVertex2Index=vertexCount;
  2439. lastExtrude2Index=vertexCount+1;
  2440. vertexCount += 2;
  2441. }
  2442. if ((i+2) >= indicesPerMesh)
  2443. { //finished with all silhouette edges
  2444. polygonCount += 2;
  2445. break; //reached end of all edges
  2446. }
  2447. //Start a new strip by adding first vertex and extrusion.
  2448. geomMesh->GetVertex( silhouetteIndices[ i+2 ], &edgeVertex2 );
  2449. // take one edge point and extrude away from the light
  2450. extrude2 = edgeVertex2 - *lightPosObject;
  2451. extrude2 *= shadowExtrudeDistance;
  2452. extrude2 += edgeVertex2;
  2453. lastEdgeVertex2Index=vertexCount;
  2454. lastExtrude2Index=vertexCount + 1;
  2455. //record start of new strip info
  2456. stripStartIndex=silhouetteIndices[ i+2 ];
  2457. stripStartVertex=lastEdgeVertex2Index;
  2458. *vb++ = *(VertexFormatXYZ *)&edgeVertex2;
  2459. *vb++ = *(VertexFormatXYZ *)&extrude2;
  2460. vertexCount += 2;
  2461. polygonCount += 2;
  2462. continue;
  2463. }
  2464. else
  2465. { //continue existing strip by adding extra vertex and extrusion
  2466. geomMesh->GetVertex( currentEdgeEnd, &edgeVertex2 );
  2467. *vb++ = *(VertexFormatXYZ *)&edgeVertex2;
  2468. //
  2469. // add the polygon consisting of the two edge vertices and the
  2470. // first extruded point
  2471. //
  2472. ib[ 0 ] = lastEdgeVertex2Index; // lastedgeVertex2 index
  2473. ib[ 4 ] = ib[ 1 ] = lastExtrude2Index; // lastextrude2 index
  2474. ib[ 3 ] = ib[ 2 ] = vertexCount; // edgeVertex2 index
  2475. ib[ 5 ] = vertexCount+1; // extrude2 index
  2476. ib += 6; //skip past 2 triangles just added
  2477. // take the other edge point and extrude away from light
  2478. extrude2 = edgeVertex2 - *lightPosObject;
  2479. extrude2 *= shadowExtrudeDistance;
  2480. extrude2 += edgeVertex2;
  2481. // add the one new vertex
  2482. *vb++ = *(VertexFormatXYZ *)&extrude2;
  2483. lastEdgeVertex2Index=vertexCount;
  2484. lastExtrude2Index=vertexCount+1;
  2485. vertexCount += 2;
  2486. polygonCount += 2;
  2487. }
  2488. }
  2489. // DEBUG_ASSERTLOG(polygonCount == vertexCount, ("WARNING***Shadow volume mesh not optimal: %s\n",m_geometry->Get_Name()));
  2490. } // end constructVolume
  2491. // allocateShadowVolume =======================================================
  2492. // Allocate a space for us to construct the shadow volume in
  2493. // ============================================================================
  2494. Bool W3DVolumetricShadow::allocateShadowVolume( Int volumeIndex, Int meshIndex )
  2495. {
  2496. Int numVertices, numPolygons;
  2497. Geometry *shadowVolume;
  2498. // sanity
  2499. if( volumeIndex < 0 || volumeIndex >= MAX_SHADOW_LIGHTS )
  2500. {
  2501. // DBGPRINTF(( "Illegal allocate shadow volume index '%d'\n", volumeIndex ));
  2502. assert( 0 );
  2503. return FALSE;
  2504. } // end if
  2505. if ((shadowVolume = m_shadowVolume[ volumeIndex ][meshIndex]) == 0)
  2506. {
  2507. // poolify
  2508. shadowVolume = NEW Geometry; // create the new geometry
  2509. // we now have one more valid geometry volume
  2510. m_shadowVolumeCount[meshIndex]++;
  2511. }
  2512. if( shadowVolume == NULL )
  2513. {
  2514. // DBGPRINTF(( "Unable to allocate '%d' shadow volume\n", volumeIndex ));
  2515. assert( 0 );
  2516. // we now have one more valid geometry volume
  2517. m_shadowVolumeCount[meshIndex]--;
  2518. return FALSE;
  2519. } // end if
  2520. // assign to list
  2521. m_shadowVolume[ volumeIndex ][meshIndex] = shadowVolume;
  2522. //
  2523. // polygons are determined from the edges extruded from the light.
  2524. // since we have a list of disjoint edge pairs we will have a 4 sided
  2525. // polygon for each edge pair, however we will be splitting the
  2526. // 4 sided polys into 2 triangles so it just works out that num polys
  2527. // is the number of silhouette indices
  2528. //
  2529. numPolygons = m_maxSilhouetteEntries[meshIndex];
  2530. //
  2531. // vertices are an extrusion of the edges, and since we have disjoint
  2532. // pairs of edge indices we will have num indices * 2 actual vertex
  2533. // points. it may be a good future optimization to not duplicate
  2534. // any vertices that appear twice here, but then again the cost over
  2535. // optimizing this routine over the rendering and transformation
  2536. // optimization may not be worth it
  2537. //
  2538. numVertices = m_maxSilhouetteEntries[meshIndex] * 2;
  2539. //Only allocate space here for dynamic shadows. Shadows for static/non-animated
  2540. //models will be stored in vertex buffers which are allocated once exact size
  2541. //is known.
  2542. if (shadowVolume->GetFlags() & SHADOW_DYNAMIC)
  2543. {
  2544. //for dynamic shadow casters, we need to allocate the maximum amount of vertices that could ever be required.
  2545. // if (m_shadowVolumeVB[ volumeIndex ][meshIndex])
  2546. // TheW3DBufferManager->releaseSlot(m_shadowVolumeVB[ volumeIndex ][meshIndex]);
  2547. // m_shadowVolumeVB[ volumeIndex ][meshIndex] = TheW3DVertexBufferManager->getSlot(W3DVertexBufferManager::VBM_FVF_XYZ, numVertices);
  2548. // allocate memory for the vertices and polygons
  2549. if( shadowVolume->Create( numVertices, numPolygons ) == FALSE )
  2550. {
  2551. // DBGPRINTF(( "Unable to create shadow volume\n" ));
  2552. assert( 0 );
  2553. delete shadowVolume;
  2554. return FALSE;
  2555. } // end if
  2556. }
  2557. return TRUE; // success
  2558. } // end allocateShadowVolume
  2559. // deleteShadowVolume =========================================================
  2560. // Free all resources allocated to the shadow volume(s)
  2561. // ============================================================================
  2562. void W3DVolumetricShadow::deleteShadowVolume( Int volumeIndex )
  2563. {
  2564. // sanity
  2565. if( volumeIndex < 0 || volumeIndex >= MAX_SHADOW_LIGHTS )
  2566. {
  2567. // DBGPRINTF(( "Illegal delete shadow volume index '%d'\n", volumeIndex ));
  2568. assert( 0 );
  2569. return;
  2570. } // end if
  2571. // delete it!
  2572. for (Int meshIndex=0; meshIndex<MAX_SHADOW_CASTER_MESHES; meshIndex++)
  2573. {
  2574. if( m_shadowVolume[ volumeIndex ][meshIndex] )
  2575. {
  2576. delete m_shadowVolume[ volumeIndex ][meshIndex];
  2577. m_shadowVolume[ volumeIndex ][meshIndex] = NULL;
  2578. // we now have one less shadow volume
  2579. m_shadowVolumeCount[meshIndex]--;
  2580. } // end if
  2581. }
  2582. } // end deleteShadowVolume
  2583. // resetShadowVolume ==========================================================
  2584. // Reset the contents of the shadow volume information. Since we're using
  2585. // a geometry class it would be ideal if these structures had a reset
  2586. // option where their resoures were released back to a pool rather than
  2587. // delete and allocate new storage space
  2588. // ============================================================================
  2589. void W3DVolumetricShadow::resetShadowVolume( Int volumeIndex, Int meshIndex )
  2590. {
  2591. Geometry *geometry;
  2592. // sanity
  2593. if( volumeIndex < 0 || volumeIndex >= MAX_SHADOW_LIGHTS )
  2594. {
  2595. // DBGPRINTF(( "Illegal reset shadow volume index '%d'\n", volumeIndex ));
  2596. assert( 0 );
  2597. return;
  2598. } // end if
  2599. geometry = m_shadowVolume[ volumeIndex ][meshIndex];
  2600. //Release buffers used to hold shadow volume geometry
  2601. if (geometry)
  2602. { if (m_shadowVolumeVB[volumeIndex][meshIndex])
  2603. { TheW3DBufferManager->releaseSlot(m_shadowVolumeVB[volumeIndex][meshIndex]);
  2604. m_shadowVolumeVB[volumeIndex][meshIndex]=NULL;
  2605. }
  2606. if (m_shadowVolumeIB[ volumeIndex ][meshIndex])
  2607. { TheW3DBufferManager->releaseSlot(m_shadowVolumeIB[volumeIndex][meshIndex]);
  2608. m_shadowVolumeIB[volumeIndex][meshIndex]=NULL;
  2609. }
  2610. geometry->Release();
  2611. }
  2612. } // end resetShadowVolume
  2613. // allocateSilhouette =========================================================
  2614. // Allocate space for new silhouette storage, the number of vertices passed
  2615. // in is the total vertices in the model, a silhouette must be able to
  2616. // accomodate that as a series of disjoint edge pairs, otherwise known
  2617. // as numVertices * 2
  2618. // ============================================================================
  2619. Bool W3DVolumetricShadow::allocateSilhouette(Int meshIndex, Int numVertices )
  2620. {
  2621. Int numEntries = numVertices * 5; ///@todo: HACK, HACK... Should be 2!
  2622. // sanity
  2623. assert( m_silhouetteIndex[meshIndex] == NULL &&
  2624. m_numSilhouetteIndices[meshIndex] == 0 &&
  2625. numEntries > 0 );
  2626. // allocate memory
  2627. m_silhouetteIndex[meshIndex] = NEW short[ numEntries ];
  2628. if( m_silhouetteIndex[meshIndex] == NULL )
  2629. {
  2630. // DBGPRINTF(( "Unable to allcoate silhouette storage '%d'\n", numEntries ));
  2631. assert( 0 );
  2632. return FALSE;
  2633. } // end if
  2634. // set our list to empty just to be clean
  2635. m_numSilhouetteIndices[meshIndex] = 0;
  2636. // save the size of our silhouette list
  2637. m_maxSilhouetteEntries[meshIndex] = numEntries;
  2638. return TRUE; // success
  2639. } // end allocateSilhouette
  2640. // deleteSilhouette ===========================================================
  2641. // Delete all silhouette data and memory allocated
  2642. // ============================================================================
  2643. void W3DVolumetricShadow::deleteSilhouette( Int meshIndex )
  2644. {
  2645. if( m_silhouetteIndex[meshIndex])
  2646. delete [] m_silhouetteIndex[meshIndex];
  2647. m_silhouetteIndex[meshIndex] = NULL;
  2648. m_numSilhouetteIndices[meshIndex] = 0;
  2649. } // end deletesilhouette
  2650. // resetSilhouette ============================================================
  2651. // Resets the silhouette to empty, it does NOT free any of the memory
  2652. // allocated for silhouette data
  2653. // ============================================================================
  2654. void W3DVolumetricShadow::resetSilhouette( Int meshIndex )
  2655. {
  2656. m_numSilhouetteIndices[meshIndex] = 0;
  2657. } // end resetSilhouette
  2658. // renderStencilShadows =======================================================
  2659. // The stencil buffer now has our shadow information in it, take that
  2660. // info and draw a big transparent rectangle over the screen for the final
  2661. // shadow pass wherever there is data in the stencil buffer
  2662. // ============================================================================
  2663. void W3DVolumetricShadowManager::renderStencilShadows( void )
  2664. {
  2665. LPDIRECT3DDEVICE8 m_pDev=DX8Wrapper::_Get_D3D_Device8();
  2666. if (!m_pDev)
  2667. return; //need device to render anything.
  2668. struct _TRANSLITVERTEX {
  2669. D3DXVECTOR4 p;
  2670. DWORD color; // diffuse color
  2671. } v[4];
  2672. Int xpos, ypos, width, height;
  2673. TheTacticalView->getOrigin(&xpos,&ypos);
  2674. width=TheTacticalView->getWidth();
  2675. height=TheTacticalView->getHeight();
  2676. v[0].p = D3DXVECTOR4( xpos+width, ypos+height, 0.0f, 1.0f );
  2677. v[1].p = D3DXVECTOR4( xpos+width, 0, 0.0f, 1.0f );
  2678. v[2].p = D3DXVECTOR4( xpos, ypos+height, 0.0f, 1.0f );
  2679. v[3].p = D3DXVECTOR4( xpos, 0, 0.0f, 1.0f );
  2680. v[0].color = TheW3DShadowManager->getShadowColor();
  2681. v[1].color = TheW3DShadowManager->getShadowColor();
  2682. v[2].color = TheW3DShadowManager->getShadowColor();
  2683. v[3].color = TheW3DShadowManager->getShadowColor();
  2684. //draw polygons like this is very inefficient but for only 2 triangles, it's
  2685. //not worth bothering with index/vertex buffers.
  2686. m_pDev->SetVertexShader(D3DFVF_XYZRHW | D3DFVF_DIFFUSE);
  2687. // Use alpha blending to draw the transparent shadow
  2688. m_pDev->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
  2689. // m_pDev->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
  2690. // m_pDev->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
  2691. m_pDev->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_DESTCOLOR);
  2692. m_pDev->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ZERO );
  2693. // Set stencil states
  2694. m_pDev->SetRenderState( D3DRS_ZENABLE, TRUE );
  2695. m_pDev->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);
  2696. // Only write where stencil val >= 1 (count indicates # of shadows that
  2697. // overlap that pixel)
  2698. m_pDev->SetRenderState( D3DRS_STENCILENABLE, TRUE );
  2699. m_pDev->SetRenderState( D3DRS_STENCILFUNC, D3DCMP_LESSEQUAL ); //reference value is less or equal to stencil
  2700. m_pDev->SetRenderState( D3DRS_STENCILPASS, D3DSTENCILOP_KEEP );
  2701. //Upper bits of stencil could be used for storing occluded models which are player colored. So we mask out those
  2702. //pixels and only use the lower bits for shadow calculations.
  2703. m_pDev->SetRenderState( D3DRS_STENCILMASK, ~TheW3DShadowManager->getStencilShadowMask());
  2704. m_pDev->SetRenderState( D3DRS_STENCILREF, 0x1 );
  2705. m_pDev->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_FLAT);
  2706. if (DX8Wrapper::_Is_Triangle_Draw_Enabled())
  2707. m_pDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, v, sizeof(_TRANSLITVERTEX));
  2708. m_pDev->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
  2709. m_pDev->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
  2710. // turn off the stencil buffer
  2711. m_pDev->SetRenderState( D3DRS_STENCILENABLE, FALSE );
  2712. } // end renderStencilShadows
  2713. void W3DVolumetricShadowManager::renderShadows( Bool forceStencilFill )
  2714. {
  2715. W3DVolumetricShadow *shadow;
  2716. Int numRenderedShadows = 0;
  2717. AABoxClass bbox;
  2718. SphereClass bsphere;
  2719. //Get a bounding box around our visible universe. Bounded by terrain and the sky
  2720. //so much tighter fitting volume than what's actually visible. This will cull
  2721. //particles falling under the ground.
  2722. TheTerrainRenderObject->getMaximumVisibleBox(*shadowCameraFrustum, &bbox, TRUE);
  2723. bcX = bbox.Center.X;
  2724. bcY = bbox.Center.Y;
  2725. bcZ = bbox.Center.Z;
  2726. beX = bbox.Extent.X;
  2727. beY = bbox.Extent.Y;
  2728. beZ = bbox.Extent.Z;
  2729. if (m_shadowList && TheGlobalData->m_useShadowVolumes)
  2730. {
  2731. LPDIRECT3DDEVICE8 m_pDev=DX8Wrapper::_Get_D3D_Device8();
  2732. if (!m_pDev)
  2733. return; //need device to render anything.
  2734. //According to Nvidia there's a D3D bug that happens if you don't start with a
  2735. //new dynamic VB each frame - so we force a DISCARD by overflowing the counter.
  2736. nShadowIndicesInBuf = 0xffff;
  2737. nShadowVertsInBuf = 0xffff;
  2738. //Set W3D to some known state
  2739. VertexMaterialClass *vmat=VertexMaterialClass::Get_Preset(VertexMaterialClass::PRELIT_DIFFUSE);
  2740. DX8Wrapper::Set_Material(vmat);
  2741. REF_PTR_RELEASE(vmat);
  2742. DX8Wrapper::Set_Shader(ShaderClass::_PresetOpaqueShader);
  2743. DX8Wrapper::Set_Texture(0,NULL); //turn off textures
  2744. DX8Wrapper::Set_Texture(1,NULL); //turn off textures
  2745. DX8Wrapper::Apply_Render_State_Changes(); //force update of view and projection matrices
  2746. // turn off z writing
  2747. m_pDev->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL);
  2748. m_pDev->SetRenderState( D3DRS_ZENABLE, TRUE );
  2749. m_pDev->SetRenderState(D3DRS_ZWRITEENABLE , FALSE);
  2750. m_pDev->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
  2751. m_pDev->SetRenderState(D3DRS_FOGENABLE, FALSE);
  2752. // setup the TMU to default
  2753. m_pDev->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_FLAT);
  2754. m_pDev->SetRenderState(D3DRS_LIGHTING, FALSE);
  2755. m_pDev->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
  2756. m_pDev->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
  2757. m_pDev->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG2);
  2758. m_pDev->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_DISABLE );
  2759. m_pDev->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0 );
  2760. m_pDev->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE);
  2761. m_pDev->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE );
  2762. m_pDev->SetTextureStageState( 1, D3DTSS_TEXCOORDINDEX, 1 );
  2763. m_pDev->SetTexture(0,NULL);
  2764. m_pDev->SetTexture(1,NULL);
  2765. DWORD oldColorWriteEnable=0x12345678;
  2766. #ifdef SV_DEBUG
  2767. m_pDev->SetRenderState(D3DRS_ALPHABLENDENABLE , TRUE);
  2768. m_pDev->SetRenderState( D3DRS_STENCILENABLE, FALSE );
  2769. m_pDev->SetRenderState( D3DRS_SRCBLEND, /*D3DBLEND_DESTCOLOR*/D3DBLEND_ONE );
  2770. m_pDev->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ZERO );
  2771. m_pDev->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL);
  2772. #else
  2773. //disable writes to color buffer
  2774. if (DX8Caps::Get_Default_Caps().PrimitiveMiscCaps & D3DPMISCCAPS_COLORWRITEENABLE)
  2775. { DX8Wrapper::_Get_D3D_Device8()->GetRenderState(D3DRS_COLORWRITEENABLE, &oldColorWriteEnable);
  2776. DX8Wrapper::Set_DX8_Render_State(D3DRS_COLORWRITEENABLE,0);
  2777. }
  2778. else
  2779. { //device does not support disabling writes to color buffer so fake it through alpha blending
  2780. m_pDev->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ZERO );
  2781. m_pDev->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );
  2782. m_pDev->SetRenderState(D3DRS_ALPHABLENDENABLE , TRUE);
  2783. }
  2784. m_pDev->SetRenderState( D3DRS_STENCILENABLE, TRUE );
  2785. #endif
  2786. //Any pixels with stencil already set to 128 contains a potential occluder. If this pixels also has any of the player
  2787. //color stencil bits also set, it means that it's an occluded player color and we need to NOT render shadows here. We
  2788. //do this determination by comparing the value in the combined bits against a value containing only a potential occluder.
  2789. //If the value of just the potential occluder bit is >= than the combined bits, then we know none of the player color
  2790. //bits were set and it's okay to render shadow.
  2791. if (TheW3DShadowManager->getStencilShadowMask() == 0x80808080)
  2792. m_pDev->SetRenderState( D3DRS_STENCILFUNC, D3DCMP_NOTEQUAL ); //in this mode, MSB indicates occluded player pixels.
  2793. else
  2794. m_pDev->SetRenderState( D3DRS_STENCILFUNC, D3DCMP_GREATEREQUAL ); //in this mode, multiple bits indicate occluded player pixels.
  2795. m_pDev->SetRenderState( D3DRS_STENCILREF, 0x80808080 ); //isolate MSB, it's used to indicate pixels containing potential occluders.
  2796. m_pDev->SetRenderState( D3DRS_STENCILMASK, TheW3DShadowManager->getStencilShadowMask()); //isolate upper bits containing PotentialOccluderBit|PlayerColorBits
  2797. m_pDev->SetRenderState( D3DRS_STENCILWRITEMASK,0xffffffff );
  2798. m_pDev->SetRenderState( D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP );
  2799. m_pDev->SetRenderState( D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP );
  2800. m_pDev->SetRenderState( D3DRS_STENCILPASS, D3DSTENCILOP_INCR );
  2801. m_pDev->SetVertexShader(SHADOW_DYNAMIC_VOLUME_FVF);
  2802. m_pDev->SetRenderState(D3DRS_CULLMODE,D3DCULL_CW);
  2803. // m_pDev->SetRenderState(D3DRS_ZBIAS,1); ///@todo: See if this helps or makes things worse.
  2804. //m_pDev->SetRenderState(D3DRS_FILLMODE,D3DFILL_WIREFRAME);
  2805. lastActiveVertexBuffer=NULL; //reset
  2806. m_dynamicShadowVolumesToRender=NULL; //clear list of pending dynamic shadows
  2807. W3DVolumetricShadowRenderTask *shadowDynamicTasksStart,*shadowDynamicTask;
  2808. // step through each of our shadows and render
  2809. for( shadow = m_shadowList; shadow; shadow = shadow->m_next )
  2810. {
  2811. if (shadow->m_isEnabled && !shadow->m_isInvisibleEnabled)
  2812. {
  2813. //Record last added task
  2814. shadowDynamicTasksStart=m_dynamicShadowVolumesToRender;
  2815. shadow->Update();
  2816. shadowDynamicTask=m_dynamicShadowVolumesToRender;
  2817. while (shadowDynamicTask != shadowDynamicTasksStart)
  2818. { //update() added a dynamic shadow
  2819. //dynamic shadow columes don't need to wait in queue since they
  2820. //all use the same vertex buffer. Flush them ASAP.
  2821. shadow->RenderVolume(shadowDynamicTask->m_meshIndex,shadowDynamicTask->m_lightIndex);
  2822. //move to next dynamic task
  2823. shadowDynamicTask=(W3DVolumetricShadowRenderTask *)shadowDynamicTask->m_nextTask;
  2824. numRenderedShadows++;
  2825. }
  2826. }
  2827. } // end for
  2828. // Set vertex format to that used by static shadow volumes
  2829. m_pDev->SetVertexShader(W3DBufferManager::getDX8Format(W3DBufferManager::VBM_FVF_XYZ));
  2830. //Empty queue of static shadow volumes to render.
  2831. W3DBufferManager::W3DVertexBuffer *nextVb;
  2832. W3DVolumetricShadowRenderTask *nextTask;
  2833. for (nextVb=TheW3DBufferManager->getNextVertexBuffer(NULL,W3DBufferManager::VBM_FVF_XYZ);nextVb != NULL; nextVb=TheW3DBufferManager->getNextVertexBuffer(nextVb,W3DBufferManager::VBM_FVF_XYZ))
  2834. {
  2835. nextTask=(W3DVolumetricShadowRenderTask *)nextVb->m_renderTaskList;
  2836. while (nextTask)
  2837. {
  2838. nextTask->m_parentShadow->RenderVolume(nextTask->m_meshIndex,nextTask->m_lightIndex);
  2839. nextTask=(W3DVolumetricShadowRenderTask *)nextTask->m_nextTask;
  2840. numRenderedShadows++;
  2841. }
  2842. }
  2843. // change the stencil op to decrement
  2844. m_pDev->SetRenderState( D3DRS_STENCILPASS, D3DSTENCILOP_DECRSAT);
  2845. //
  2846. // invert normals of shadow volumes so we can decrement in the
  2847. // stencil buffer and render
  2848. //
  2849. m_pDev->SetRenderState(D3DRS_CULLMODE,D3DCULL_CCW);
  2850. for (nextVb=TheW3DBufferManager->getNextVertexBuffer(NULL,W3DBufferManager::VBM_FVF_XYZ);nextVb != NULL; nextVb=TheW3DBufferManager->getNextVertexBuffer(nextVb,W3DBufferManager::VBM_FVF_XYZ))
  2851. {
  2852. nextTask=(W3DVolumetricShadowRenderTask *)nextVb->m_renderTaskList;
  2853. while (nextTask)
  2854. {
  2855. nextTask->m_parentShadow->RenderVolume(nextTask->m_meshIndex,nextTask->m_lightIndex);
  2856. nextTask=(W3DVolumetricShadowRenderTask *)nextTask->m_nextTask;
  2857. }
  2858. }
  2859. m_pDev->SetVertexShader(SHADOW_DYNAMIC_VOLUME_FVF);
  2860. //flush any dynamic shadow volumes
  2861. shadowDynamicTask=m_dynamicShadowVolumesToRender;
  2862. while (shadowDynamicTask)
  2863. { //dynamic shadow columes don't need to wait in queue since they
  2864. //all use the same vertex buffer. Flush them ASAP.
  2865. shadowDynamicTask->m_parentShadow->RenderVolume(shadowDynamicTask->m_meshIndex,shadowDynamicTask->m_lightIndex);
  2866. shadowDynamicTask=(W3DVolumetricShadowRenderTask *)shadowDynamicTask->m_nextTask;
  2867. }
  2868. //Reset all render tasks for next frame.
  2869. for (nextVb=TheW3DBufferManager->getNextVertexBuffer(NULL,W3DBufferManager::VBM_FVF_XYZ);nextVb != NULL; nextVb=TheW3DBufferManager->getNextVertexBuffer(nextVb,W3DBufferManager::VBM_FVF_XYZ))
  2870. {
  2871. nextVb->m_renderTaskList=NULL;
  2872. }
  2873. m_pDev->SetRenderState(D3DRS_CULLMODE,D3DCULL_CW);
  2874. // m_pDev->SetRenderState(D3DRS_ZBIAS,0); ///@todo: See if this helps or makes things worse.
  2875. //m_pDev->SetRenderState(D3DRS_FILLMODE,D3DFILL_SOLID);
  2876. if (oldColorWriteEnable != 0x12345678)
  2877. DX8Wrapper::Set_DX8_Render_State(D3DRS_COLORWRITEENABLE,oldColorWriteEnable);
  2878. //
  2879. // render the big transparent square of shadows in the stencil buffer
  2880. // to the screen
  2881. //
  2882. ///@todo: Put this check back in after water is fixed so it doesn't require shadow rendering to fix alpha.
  2883. // if (numRenderedShadows)
  2884. renderStencilShadows();
  2885. m_pDev->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
  2886. m_pDev->SetRenderState(D3DRS_ALPHABLENDENABLE , FALSE);
  2887. m_pDev->SetRenderState(D3DRS_LIGHTING, FALSE);
  2888. DX8Wrapper::Invalidate_Cached_Render_States();
  2889. }
  2890. else
  2891. if (forceStencilFill)
  2892. { //no shadows to render, but still need to fill stencil buffer
  2893. //for other effects.
  2894. //Set W3D to some known state
  2895. VertexMaterialClass *vmat=VertexMaterialClass::Get_Preset(VertexMaterialClass::PRELIT_DIFFUSE);
  2896. DX8Wrapper::Set_Material(vmat);
  2897. REF_PTR_RELEASE(vmat);
  2898. DX8Wrapper::Set_Shader(ShaderClass::_PresetOpaqueShader);
  2899. DX8Wrapper::Set_Texture(0,NULL);
  2900. DX8Wrapper::Apply_Render_State_Changes(); //force update of view and projection matrices
  2901. renderStencilShadows();
  2902. DX8Wrapper::Invalidate_Cached_Render_States();
  2903. }
  2904. } // end RenderShadows
  2905. /** This class will manage shadow geometry for each render object. Shadow geometry may
  2906. be the same as render geometry but doesn't need to be. This allows lower LOD versions of
  2907. the geometry to be used in shadow calculations. Shadow geometry also keeps extended vertex
  2908. connectivity information that's not used during rendering.
  2909. */
  2910. class W3DShadowGeometryManager
  2911. {
  2912. public:
  2913. W3DShadowGeometryManager(void);
  2914. ~W3DShadowGeometryManager(void);
  2915. int Load_Geom(RenderObjClass *robj, const char *name);
  2916. W3DShadowGeometry * Get_Geom(const char * name);
  2917. W3DShadowGeometry * Peek_Geom(const char * name);
  2918. Bool Add_Geom(W3DShadowGeometry *new_anim);
  2919. void Free_All_Geoms(void);
  2920. void Register_Missing( const char * name );
  2921. Bool Is_Missing( const char * name );
  2922. void Reset_Missing( void );
  2923. private:
  2924. HashTableClass * GeomPtrTable;
  2925. HashTableClass * MissingGeomTable;
  2926. friend class W3DShadowGeometryManagerIterator;
  2927. };
  2928. /*
  2929. ** An Iterator to get to all loaded W3DShadowGeometries in a W3DShadowGeometryManager
  2930. */
  2931. class W3DShadowGeometryManagerIterator : public HashTableIteratorClass {
  2932. public:
  2933. W3DShadowGeometryManagerIterator( W3DShadowGeometryManager & manager ) : HashTableIteratorClass( *manager.GeomPtrTable ) {}
  2934. W3DShadowGeometry * Get_Current_Geom( void );
  2935. };
  2936. /** Used to cause a rebuild of all shadow volumes*/
  2937. void W3DVolumetricShadowManager::invalidateCachedLightPositions(void)
  2938. {
  2939. if (!m_shadowList)
  2940. return; //there are no shadows to render.
  2941. W3DVolumetricShadow *shadow;
  2942. Vector3 vec(0,0,0);
  2943. // step through each of our shadows and update previous light position.
  2944. for( shadow = m_shadowList; shadow; shadow = shadow->m_next )
  2945. {
  2946. for(Int i = 0; i < MAX_SHADOW_LIGHTS; i++ )
  2947. {
  2948. for (Int meshIndex=0; meshIndex<MAX_SHADOW_CASTER_MESHES; meshIndex++)
  2949. {
  2950. shadow->setLightPosHistory(i,meshIndex,vec);
  2951. }
  2952. }
  2953. } // end for
  2954. }
  2955. // W3DVolumetricShadowManager =============================================================
  2956. // ============================================================================
  2957. W3DVolumetricShadowManager::W3DVolumetricShadowManager( void )
  2958. {
  2959. m_shadowList = NULL;
  2960. m_W3DShadowGeometryManager = NEW W3DShadowGeometryManager;
  2961. TheW3DBufferManager = NEW W3DBufferManager;
  2962. } // end ShadowManager
  2963. // ~W3DVolumetricShadowManager ============================================================
  2964. // ============================================================================
  2965. W3DVolumetricShadowManager::~W3DVolumetricShadowManager( void )
  2966. {
  2967. ReleaseResources();
  2968. delete m_W3DShadowGeometryManager;
  2969. m_W3DShadowGeometryManager = NULL;
  2970. delete TheW3DBufferManager;
  2971. TheW3DBufferManager=NULL;
  2972. //all shadows should be freed up at this point but check anyway
  2973. assert(m_shadowList==NULL);
  2974. } // end ~W3DVolumetricShadowManager
  2975. /** Releases all W3D/D3D assets before a reset.. */
  2976. void W3DVolumetricShadowManager::ReleaseResources(void)
  2977. {
  2978. if (shadowIndexBufferD3D)
  2979. shadowIndexBufferD3D->Release();
  2980. if (shadowVertexBufferD3D)
  2981. shadowVertexBufferD3D->Release();
  2982. shadowIndexBufferD3D=NULL;
  2983. shadowVertexBufferD3D=NULL;
  2984. if (TheW3DBufferManager)
  2985. { TheW3DBufferManager->ReleaseResources();
  2986. invalidateCachedLightPositions(); //vertex buffers need to be refilled.
  2987. }
  2988. }
  2989. /** (Re)allocates all W3D/D3D assets after a reset.. */
  2990. Bool W3DVolumetricShadowManager::ReAcquireResources(void)
  2991. {
  2992. ReleaseResources();
  2993. LPDIRECT3DDEVICE8 m_pDev=DX8Wrapper::_Get_D3D_Device8();
  2994. DEBUG_ASSERTCRASH(m_pDev, ("Trying to ReAquireResources on W3DVolumetricShadowManager without device"));
  2995. if (FAILED(m_pDev->CreateIndexBuffer
  2996. (
  2997. SHADOW_INDEX_SIZE*sizeof(WORD),
  2998. D3DUSAGE_WRITEONLY|D3DUSAGE_DYNAMIC,
  2999. D3DFMT_INDEX16,
  3000. D3DPOOL_DEFAULT,
  3001. &shadowIndexBufferD3D
  3002. )))
  3003. return FALSE;
  3004. if (shadowVertexBufferD3D == NULL)
  3005. { // Create vertex buffer
  3006. if (FAILED(m_pDev->CreateVertexBuffer
  3007. (
  3008. SHADOW_VERTEX_SIZE*sizeof(SHADOW_DYNAMIC_VOLUME_VERTEX),
  3009. D3DUSAGE_WRITEONLY|D3DUSAGE_DYNAMIC,
  3010. 0,
  3011. D3DPOOL_DEFAULT,
  3012. &shadowVertexBufferD3D
  3013. )))
  3014. return FALSE;
  3015. }
  3016. if (TheW3DBufferManager)
  3017. if (!TheW3DBufferManager->ReAcquireResources())
  3018. return FALSE;
  3019. return TRUE;
  3020. }
  3021. // Init =======================================================================
  3022. // User called initialization
  3023. // ============================================================================
  3024. Bool W3DVolumetricShadowManager::init( void )
  3025. {
  3026. return TRUE;
  3027. } // end Init
  3028. // Reset ======================================================================
  3029. // Reset our list of shadows to empty
  3030. // ============================================================================
  3031. void W3DVolumetricShadowManager::reset( void )
  3032. {
  3033. assert (m_shadowList == NULL);
  3034. m_W3DShadowGeometryManager->Free_All_Geoms();
  3035. TheW3DBufferManager->freeAllBuffers();
  3036. } // end Reset
  3037. // addShadow ==================================================================
  3038. // Add the shadows for this hierarchy to the shadow management for
  3039. // rendering.
  3040. // ============================================================================
  3041. W3DVolumetricShadow* W3DVolumetricShadowManager::addShadow(RenderObjClass *robj, Shadow::ShadowTypeInfo *shadowInfo, Drawable *draw)
  3042. {
  3043. if (!DX8Wrapper::Has_Stencil() || !robj || !TheGlobalData->m_useShadowVolumes)
  3044. return NULL; //right now we require a stencil buffer
  3045. W3DShadowGeometry *sg=NULL;
  3046. if (!robj)
  3047. return NULL; //must have a render object in order to read shadow geometry
  3048. const char *name=robj->Get_Name();
  3049. if (!name)
  3050. return NULL;
  3051. sg=m_W3DShadowGeometryManager->Get_Geom(name);
  3052. if (sg==NULL)
  3053. { //did not find a cached copy of the shadow geometry, create a new one
  3054. m_W3DShadowGeometryManager->Load_Geom(robj,name);
  3055. //try loading again
  3056. sg=m_W3DShadowGeometryManager->Get_Geom(name);
  3057. if (sg==NULL)
  3058. return NULL; //could not create the shadow geometry
  3059. }
  3060. W3DVolumetricShadow *shadow = NEW W3DVolumetricShadow; // poolify
  3061. // sanity
  3062. if( shadow == NULL )
  3063. return NULL;
  3064. shadow->setRenderObject(robj);
  3065. shadow->SetGeometry(sg);
  3066. SphereClass sphere;
  3067. robj->Get_Obj_Space_Bounding_Sphere(sphere);
  3068. shadow->setRenderObjExtent(sphere.Radius*MAX_SHADOW_LENGTH_SCALE_FACTOR);
  3069. Real sunElevationAngleTan = 0;
  3070. if (shadowInfo->m_sizeX)
  3071. { //need to adjust sun elevation for this model in order to limit shadow length
  3072. sunElevationAngleTan=tan(shadowInfo->m_sizeX/180.0f*PI);
  3073. }
  3074. shadow->setShadowLengthScale(sunElevationAngleTan);
  3075. if (!draw || !draw->isKindOf(KINDOF_IMMOBILE))
  3076. shadow->setOptimalExtrusionPadding(SHADOW_EXTRUSION_BUFFER);
  3077. // add to our shadow list through the shadow next links
  3078. shadow->m_next = m_shadowList;
  3079. m_shadowList = shadow;
  3080. return shadow;
  3081. }
  3082. /** removeShadow ===========================================================
  3083. Removes the shadows for this hierarchy from the shadow manger. No further
  3084. shadows from this caster will be rendered.
  3085. ===========================================================================
  3086. */
  3087. void W3DVolumetricShadowManager::removeShadow(W3DVolumetricShadow *shadow)
  3088. {
  3089. W3DVolumetricShadow *prev_shadow=NULL;
  3090. W3DVolumetricShadow *next_shadow=NULL;
  3091. //search for this shadow
  3092. for( next_shadow = m_shadowList; next_shadow; prev_shadow=next_shadow, next_shadow = next_shadow->m_next )
  3093. {
  3094. if (next_shadow == shadow)
  3095. {
  3096. if (prev_shadow)
  3097. prev_shadow->m_next=shadow->m_next;
  3098. else
  3099. m_shadowList=shadow->m_next;
  3100. delete shadow;
  3101. break;
  3102. }
  3103. } // end for
  3104. }
  3105. /** removeAllShadows ===========================================================
  3106. Removes all shadows from the shadow manger. No further
  3107. shadows will be rendered.
  3108. ===========================================================================
  3109. */
  3110. void W3DVolumetricShadowManager::removeAllShadows(void)
  3111. {
  3112. W3DVolumetricShadow *cur_shadow=NULL;
  3113. W3DVolumetricShadow *next_shadow=m_shadowList;
  3114. m_shadowList = NULL;
  3115. //search for this shadow
  3116. for( cur_shadow = next_shadow; cur_shadow; cur_shadow = next_shadow )
  3117. {
  3118. next_shadow = cur_shadow->m_next;
  3119. cur_shadow->m_next = NULL;
  3120. delete cur_shadow;
  3121. } // end for
  3122. }
  3123. W3DShadowGeometryManager::W3DShadowGeometryManager(void)
  3124. {
  3125. // Create the hash tables
  3126. GeomPtrTable = NEW HashTableClass( 2048 );
  3127. MissingGeomTable = NEW HashTableClass( 2048 );
  3128. }
  3129. W3DShadowGeometryManager::~W3DShadowGeometryManager(void)
  3130. {
  3131. Free_All_Geoms();
  3132. delete GeomPtrTable;
  3133. GeomPtrTable = NULL;
  3134. delete MissingGeomTable;
  3135. MissingGeomTable = NULL;
  3136. }
  3137. /** Release all loaded animations */
  3138. void W3DShadowGeometryManager::Free_All_Geoms(void)
  3139. {
  3140. // Make an iterator, and release all ptrs
  3141. W3DShadowGeometryManagerIterator it( *this );
  3142. for( it.First(); !it.Is_Done(); it.Next() ) {
  3143. W3DShadowGeometry *geom = it.Get_Current_Geom();
  3144. geom->Release_Ref();
  3145. }
  3146. // Then clear the table
  3147. GeomPtrTable->Reset();
  3148. }
  3149. /** Find animation in cache */
  3150. W3DShadowGeometry * W3DShadowGeometryManager::Peek_Geom(const char * name)
  3151. {
  3152. return (W3DShadowGeometry*)GeomPtrTable->Find( name );
  3153. }
  3154. /** Get animation from cache and increment its reference count */
  3155. W3DShadowGeometry * W3DShadowGeometryManager::Get_Geom(const char * name)
  3156. {
  3157. W3DShadowGeometry * geom = Peek_Geom( name );
  3158. if ( geom != NULL ) {
  3159. geom->Add_Ref();
  3160. }
  3161. return geom;
  3162. }
  3163. /** Add animation to cache */
  3164. Bool W3DShadowGeometryManager::Add_Geom(W3DShadowGeometry *new_geom)
  3165. {
  3166. WWASSERT (new_geom != NULL);
  3167. // Increment the refcount on the new animation and add it to our table.
  3168. new_geom->Add_Ref ();
  3169. GeomPtrTable->Add( new_geom );
  3170. return true;
  3171. }
  3172. /*
  3173. ** An entry for a table of anims not found, so we can quickly determine their loss
  3174. */
  3175. class MissingGeomClass : public HashableClass {
  3176. public:
  3177. MissingGeomClass( const char * name ) : Name( name ) {}
  3178. virtual ~MissingGeomClass( void ) {}
  3179. virtual const char * Get_Key( void ) { return Name; }
  3180. private:
  3181. StringClass Name;
  3182. };
  3183. /*
  3184. ** Missing Geoms
  3185. **
  3186. ** The idea here, allow the system to register which anims are determined to be missing
  3187. ** so that if they are asked for again, we can quickly return NULL, without searching the
  3188. ** disk again.
  3189. */
  3190. void W3DShadowGeometryManager::Register_Missing( const char * name )
  3191. {
  3192. MissingGeomTable->Add( NEW MissingGeomClass( name ) );
  3193. }
  3194. Bool W3DShadowGeometryManager::Is_Missing( const char * name )
  3195. {
  3196. return ( MissingGeomTable->Find( name ) != NULL );
  3197. }
  3198. /** Create shadow geometry from a reference W3D RenderObject*/
  3199. int W3DShadowGeometryManager::Load_Geom(RenderObjClass *robj, const char *name)
  3200. {
  3201. Bool res=FALSE;
  3202. W3DShadowGeometry * newgeom = NEW W3DShadowGeometry;
  3203. if (newgeom == NULL) {
  3204. goto Error;
  3205. }
  3206. SET_REF_OWNER( newgeom );
  3207. newgeom->Set_Name(name);
  3208. switch (robj->Class_ID())
  3209. {
  3210. case RenderObjClass::CLASSID_HLOD:
  3211. res=newgeom->initFromHLOD(robj);
  3212. break;
  3213. case RenderObjClass::CLASSID_MESH:
  3214. res=newgeom->initFromMesh(robj);
  3215. break;
  3216. default:
  3217. break; //unknown render object type
  3218. };
  3219. if (res != TRUE)
  3220. { // load failed!
  3221. newgeom->Release_Ref();
  3222. //DEBUG_LOG(("****Shadow Volume Creation Failed on %s\n",name));
  3223. goto Error;
  3224. } else if (Peek_Geom(newgeom->Get_Name()) != NULL)
  3225. { // duplicate exists!
  3226. newgeom->Release_Ref(); // Release the one we just loaded
  3227. goto Error;
  3228. } else
  3229. { Add_Geom( newgeom );
  3230. newgeom->Release_Ref();
  3231. }
  3232. return 0;
  3233. Error:
  3234. return 1;
  3235. }
  3236. /*
  3237. ** Iterator converter from HashableClass to GrannyAnimClass
  3238. */
  3239. W3DShadowGeometry * W3DShadowGeometryManagerIterator::Get_Current_Geom( void )
  3240. {
  3241. return (W3DShadowGeometry *)Get_Current();
  3242. }