W3DVolumetricShadow.cpp 135 KB

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