W3DProjectedShadow.cpp 81 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406
  1. /*
  2. ** Command & Conquer Generals(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. ;////////////////////////////////////////////////////////////////////////////////
  19. ;// //
  20. ;// (c) 2001-2003 Electronic Arts Inc. //
  21. ;// //
  22. ;////////////////////////////////////////////////////////////////////////////////
  23. // FILE: W3DTextureShadow.cpp ///////////////////////////////////////////////////////////
  24. //
  25. // Texture based shadow representation.
  26. //
  27. // Author: Mark Wilczynski, February 2002
  28. //
  29. //
  30. ///////////////////////////////////////////////////////////////////////////////
  31. // USER INCLUDES //////////////////////////////////////////////////////////////
  32. #include "always.h"
  33. #include "GameClient/View.h"
  34. #include "WW3D2/Camera.h"
  35. #include "WW3D2/Light.h"
  36. #include "WW3D2/DX8Wrapper.h"
  37. #include "WW3D2/HLod.h"
  38. #include "WW3D2/mesh.h"
  39. #include "WW3D2/meshmdl.h"
  40. #include "WW3D2/assetmgr.h"
  41. #include "WW3D2/texproject.h"
  42. #include "WW3D2/dx8renderer.h"
  43. #include "Lib/BaseType.h"
  44. #include "W3DDevice/GameClient/W3DGranny.h"
  45. #include "W3DDevice/GameClient/Heightmap.h"
  46. #include "D3dx8math.h"
  47. #include "common/GlobalData.h"
  48. #include "W3DDevice/GameClient/W3DProjectedShadow.h"
  49. #include "WW3D2/statistics.h"
  50. #include "Common/Debug.h"
  51. #include "GameLogic/Object.h"
  52. #include "GameLogic/PartitionManager.h"
  53. #include "GameLogic/TerrainLogic.h"
  54. #include "GameClient/drawable.h"
  55. #include "W3DDevice/GameClient/Module/W3DModelDraw.h"
  56. #include "W3DDevice/GameClient/W3DShadow.h"
  57. #include "W3DDevice/GameClient/Heightmap.h"
  58. #ifdef _INTERNAL
  59. // for occasional debugging...
  60. //#pragma optimize("", off)
  61. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  62. #endif
  63. /** @todo: We're going to have a pool of a couple rendertargets to use
  64. in rare cases when dynamic shadows need to be generated. Maybe we can
  65. even get away with a single one that gets used immediatly to render, then
  66. recycled. For most of the objects, we need to have a static texture that
  67. is reused for all instances on the level.
  68. Need to add support for loading textures from disk instead of generating them in
  69. code. Could allow for a single non-distinct blob to be used for everything.
  70. Instead of projecting onto arbitrary geometry, could allow for terrain only.
  71. Maybe project onto a deformed terrain patch that molds to trays/bibs.
  72. */
  73. #define DEFAULT_RENDER_TARGET_WIDTH 512
  74. #define DEFAULT_RENDER_TARGET_HEIGHT 512
  75. W3DProjectedShadowManager *TheW3DProjectedShadowManager=NULL; //global singleton
  76. ProjectedShadowManager *TheProjectedShadowManager; //global singleton with simpler interface.
  77. extern const FrustumClass *shadowCameraFrustum; //defined in W3DShadow.
  78. ///@todo: Externs from volumetric shadow renderer - these need to be moved into W3DBufferManager
  79. extern LPDIRECT3DVERTEXBUFFER8 shadowVertexBufferD3D; ///<D3D vertex buffer
  80. extern LPDIRECT3DINDEXBUFFER8 shadowIndexBufferD3D; ///<D3D index buffer
  81. extern int nShadowVertsInBuf; //model vetices in vertex buffer
  82. extern int nShadowStartBatchVertex;
  83. extern int nShadowIndicesInBuf; //model vetices in vertex buffer
  84. extern int nShadowStartBatchIndex;
  85. extern int SHADOW_VERTEX_SIZE;
  86. extern int SHADOW_INDEX_SIZE;
  87. //Bounding rectangle around rendered portion of terrain.
  88. static Int drawEdgeX=0;
  89. static Int drawEdgeY=0;
  90. static Int drawStartX=0;
  91. static Int drawStartY=0;
  92. //Global streaming vertex buffer with x,y,z,u,v type.
  93. struct SHADOW_DECAL_VERTEX //vertex structure passed to D3D
  94. {
  95. float x,y,z;
  96. DWORD diffuse;
  97. float u,v;
  98. };
  99. #define SHADOW_DECAL_FVF D3DFVF_XYZ|D3DFVF_TEX1|D3DFVF_DIFFUSE
  100. LPDIRECT3DVERTEXBUFFER8 shadowDecalVertexBufferD3D=NULL; ///<D3D vertex buffer
  101. LPDIRECT3DINDEXBUFFER8 shadowDecalIndexBufferD3D=NULL; ///<D3D index buffer
  102. int nShadowDecalVertsInBuf=0; //model vetices in vertex buffer
  103. int nShadowDecalStartBatchVertex=0;
  104. int nShadowDecalIndicesInBuf=0; //model vetices in vertex buffer
  105. int nShadowDecalStartBatchIndex=0;
  106. int nShadowDecalPolysInBatch=0;
  107. int nShadowDecalVertsInBatch=0;
  108. int SHADOW_DECAL_VERTEX_SIZE=32768;
  109. int SHADOW_DECAL_INDEX_SIZE=65536;
  110. class W3DShadowTexture; //forward reference
  111. class W3DShadowTextureManager; //forward reference
  112. /** Object for maintaining and updating an object's shadow texture.
  113. */
  114. class W3DProjectedShadow : public Shadow
  115. {
  116. friend class W3DProjectedShadowManager;
  117. public:
  118. W3DProjectedShadow(void);
  119. ~W3DProjectedShadow(void);
  120. void setRenderObject( RenderObjClass *robj) {m_robj=robj;}
  121. void setObjPosHistory(Vector3 &pos) {m_lastObjPosition=pos;} ///<position of object when projection matrix was updated.
  122. void setTexture(Int lightIndex,W3DShadowTexture *texture) {m_shadowTexture[lightIndex]=texture;} ///<textur with light's shadow
  123. void update(void); ///<updates the texture and/or projection parameters when the object or light moves.
  124. void init(void); ///<allocates local member variables used for projection
  125. void updateTexture(Vector3 &lightPos); ///<updates the shadow texture image using render object and given light position.
  126. void updateProjectionParameters(const Matrix3D &cameraXform); ///<recompute projection matrix - needed when light or object moves.
  127. TexProjectClass *getShadowProjector(void) {return m_shadowProjector;}
  128. #if defined(_DEBUG) || defined(_INTERNAL)
  129. virtual void getRenderCost(RenderCost & rc) const;
  130. #endif
  131. protected:
  132. W3DShadowTexture *m_shadowTexture[MAX_SHADOW_LIGHTS]; ///<cached shadow data
  133. TexProjectClass *m_shadowProjector; ///<object used to generate texture and projection matrix.
  134. RenderObjClass *m_robj; ///<render object used to cast the shadow.
  135. Vector3 m_lastObjPosition; ///<position of object at time of projection matrix update.
  136. W3DProjectedShadow *m_next; /// for the shadow manager list
  137. Bool m_allowWorldAlign; /// wrap shadow around world geometry - else align perpendicular to local z-axis.
  138. Real m_decalOffsetU; /// texture coordinate offset so not centered at object origin.
  139. Real m_decalOffsetV; /// texture coordinate offset so not centered at object origin.
  140. Int m_flags; /// custom rendering flags
  141. virtual void release(void) {TheW3DProjectedShadowManager->removeShadow(this);} ///<release shadow from manager
  142. };
  143. /** This class will manage shadow textures for each render object. Shadow textures may
  144. be based on render geometry but don't need to be. This allows lower detail 'blob' textures
  145. to be substituted to improve performance.*/
  146. class W3DShadowTextureManager
  147. {
  148. public:
  149. W3DShadowTextureManager(void);
  150. ~W3DShadowTextureManager(void);
  151. int createTexture(RenderObjClass *robj, const char *name);
  152. W3DShadowTexture * getTexture(const char * name);
  153. W3DShadowTexture * peekTexture(const char * name);
  154. Bool addTexture(W3DShadowTexture *new_texture);
  155. void freeAllTextures(void);
  156. void invalidateCachedLightPositions(void);
  157. void registerMissing( const char * name );
  158. Bool isMissing( const char * name );
  159. void resetMissing( void );
  160. private:
  161. HashTableClass * texturePtrTable;
  162. HashTableClass * missingTextureTable;
  163. friend class W3DShadowTextureManagerIterator;
  164. };
  165. class W3DShadowTexture : public RefCountClass, public HashableClass
  166. {
  167. public:
  168. W3DShadowTexture( void )
  169. { m_lastLightPosition.Set(0,0,0); m_lastObjectOrientation.Make_Identity();
  170. m_shadowUV[0].Set(1.0f,0.0f,0.0f); //u runs along world x axis
  171. m_shadowUV[1].Set(0.0f,-1.0f,0.0f); //v runs along world -y axis
  172. }
  173. ~W3DShadowTexture( void ) { REF_PTR_RELEASE(m_texture);}
  174. virtual const char * Get_Key( void ) { return m_namebuf; }
  175. Int init (RenderObjClass *robj);
  176. const char * Get_Name(void) const { return m_namebuf;}
  177. void Set_Name(const char *name)
  178. { memset(m_namebuf,0,sizeof(m_namebuf)); //pad with zero so always ends with null character.
  179. strncpy(m_namebuf,name,sizeof(m_namebuf)-1);
  180. }
  181. TextureClass *getTexture(void) { return m_texture;}
  182. void setTexture(TextureClass *texture) {m_texture = texture;}
  183. void setLightPosHistory(Vector3 &pos) {m_lastLightPosition=pos;} ///<updates the last position of light
  184. Vector3& getLightPosHistory(void) {return m_lastLightPosition;}
  185. void setObjectOrientationHistory(Matrix3 &mat) {m_lastObjectOrientation=mat;} ///<updates the last position of light
  186. Matrix3& getObjectOrientationHistory(void) {return m_lastObjectOrientation;}
  187. SphereClass& getBoundingSphere(void) {return m_areaEffectSphere;}
  188. AABoxClass& getBoundingBox(void) {return m_areaEffectBox;}
  189. void setBoundingSphere(SphereClass &sphere) {m_areaEffectSphere=sphere;}
  190. void setBoundingBox(AABoxClass &box) {m_areaEffectBox=box;}
  191. void updateBounds(Vector3 &lightPos, RenderObjClass *robj); ///<update extent of shadow
  192. void setDecalUVAxis(Vector3 &u, Vector3 &v) { m_shadowUV[0]=u; m_shadowUV[1]=v;}
  193. void getDecalUVAxis(Vector3 *u, Vector3 *v) { *u=m_shadowUV[0]; *v=m_shadowUV[1];}
  194. private:
  195. char m_namebuf[2*W3D_NAME_LEN]; ///<name of model hierarchy
  196. TextureClass *m_texture; ///<texture holding the shadow for this renderobject
  197. Vector3 m_lastLightPosition; ///<position of light source at time of last texture update.
  198. Matrix3 m_lastObjectOrientation; ///<orientation of shadow casting object when texture was generated.
  199. AABoxClass m_areaEffectBox; ///<boundary defining object-space volume affected by shadow.
  200. SphereClass m_areaEffectSphere; ///<boundary defining object-space volume affected by shadow.
  201. Vector3 m_shadowUV[2]; ///world-space vectors defining the u and v texture coordinate axis.
  202. };
  203. /*
  204. ** An Iterator to get to all loaded W3DShadowGeometries in a W3DShadowGeometryManager
  205. */
  206. class W3DShadowTextureManagerIterator : public HashTableIteratorClass {
  207. public:
  208. W3DShadowTextureManagerIterator( W3DShadowTextureManager & manager ) : HashTableIteratorClass( *manager.texturePtrTable ) {}
  209. W3DShadowTexture * getCurrentTexture( void ) { return (W3DShadowTexture *)Get_Current();}
  210. };
  211. /******************** Start of W3DProjectedShadowManager implementation ***********************/
  212. W3DProjectedShadowManager::W3DProjectedShadowManager(void)
  213. {
  214. m_shadowList = NULL;
  215. m_decalList = NULL;
  216. m_numDecalShadows = 0;
  217. m_numProjectionShadows = 0;
  218. m_W3DShadowTextureManager = NULL;
  219. m_shadowCamera = NULL;
  220. m_shadowContext= NULL;
  221. }
  222. W3DProjectedShadowManager::~W3DProjectedShadowManager(void)
  223. {
  224. ReleaseResources();
  225. m_dynamicRenderTarget = NULL;
  226. m_renderTargetHasAlpha = FALSE;
  227. delete m_shadowContext;
  228. REF_PTR_RELEASE(m_shadowCamera);
  229. delete m_W3DShadowTextureManager;
  230. m_W3DShadowTextureManager = NULL;
  231. //all shadows should be freed up at this point but check anyway
  232. DEBUG_ASSERTCRASH(m_shadowList == NULL, ("Destroy of non-empty projected shadow list"));
  233. DEBUG_ASSERTCRASH(m_decalList == NULL, ("Destroy of non-empty projected decal list"));
  234. }
  235. void W3DProjectedShadowManager::reset( void )
  236. {
  237. DEBUG_ASSERTCRASH(m_shadowList == NULL, ("Reset of non-empty projected shadow list"));
  238. DEBUG_ASSERTCRASH(m_decalList == NULL, ("Reset of non-empty projected decal list"));
  239. m_W3DShadowTextureManager->freeAllTextures();
  240. } // end Reset
  241. Bool W3DProjectedShadowManager::init( void )
  242. {
  243. m_W3DShadowTextureManager = NEW W3DShadowTextureManager;
  244. m_shadowCamera = NEW_REF( CameraClass, () );
  245. m_shadowContext= NEW SpecialRenderInfoClass(*m_shadowCamera,SpecialRenderInfoClass::RENDER_SHADOW);
  246. m_shadowContext->light_environment = &m_shadowLightEnv;
  247. return TRUE;
  248. }
  249. Bool W3DProjectedShadowManager::ReAcquireResources(void)
  250. {
  251. //grab assets which don't survive a device reset and need
  252. //to be present for duration of game.
  253. ///@todo: We should allocate our render target pool here.
  254. DEBUG_ASSERTCRASH(m_dynamicRenderTarget == NULL, ("Acquire of existing shadow render target"));
  255. m_renderTargetHasAlpha=TRUE;
  256. if ((m_dynamicRenderTarget=DX8Wrapper::Create_Render_Target (DEFAULT_RENDER_TARGET_WIDTH, DEFAULT_RENDER_TARGET_HEIGHT, true)) == NULL)
  257. {
  258. m_renderTargetHasAlpha=FALSE;
  259. //failed to get a render target with alpha.
  260. //try again without.
  261. m_dynamicRenderTarget=DX8Wrapper::Create_Render_Target (DEFAULT_RENDER_TARGET_WIDTH, DEFAULT_RENDER_TARGET_HEIGHT);
  262. }
  263. LPDIRECT3DDEVICE8 m_pDev=DX8Wrapper::_Get_D3D_Device8();
  264. DEBUG_ASSERTCRASH(m_pDev, ("Trying to ReAquireResources on W3DProjectedShadowManager without device"));
  265. DEBUG_ASSERTCRASH(shadowDecalIndexBufferD3D == NULL && shadowDecalIndexBufferD3D == NULL, ("ReAquireResources not released in W3DProjectedShadowManager"));
  266. if (FAILED(m_pDev->CreateIndexBuffer
  267. (
  268. SHADOW_DECAL_INDEX_SIZE*sizeof(WORD),
  269. D3DUSAGE_WRITEONLY|D3DUSAGE_DYNAMIC,
  270. D3DFMT_INDEX16,
  271. D3DPOOL_DEFAULT,
  272. &shadowDecalIndexBufferD3D
  273. )))
  274. return FALSE;
  275. if (shadowDecalVertexBufferD3D == NULL)
  276. { // Create vertex buffer
  277. if (FAILED(m_pDev->CreateVertexBuffer
  278. (
  279. SHADOW_DECAL_VERTEX_SIZE*sizeof(SHADOW_DECAL_VERTEX),
  280. D3DUSAGE_WRITEONLY|D3DUSAGE_DYNAMIC,
  281. 0,
  282. D3DPOOL_DEFAULT,
  283. &shadowDecalVertexBufferD3D
  284. )))
  285. return FALSE;
  286. }
  287. return TRUE;
  288. }
  289. void W3DProjectedShadowManager::ReleaseResources(void)
  290. {
  291. invalidateCachedLightPositions(); //textures need to be updated
  292. REF_PTR_RELEASE(m_dynamicRenderTarget); //need to create a new render target
  293. if (shadowDecalIndexBufferD3D)
  294. shadowDecalIndexBufferD3D->Release();
  295. if (shadowDecalVertexBufferD3D)
  296. shadowDecalVertexBufferD3D->Release();
  297. shadowDecalIndexBufferD3D=NULL;
  298. shadowDecalVertexBufferD3D=NULL;
  299. }
  300. void W3DProjectedShadowManager::invalidateCachedLightPositions(void)
  301. {
  302. m_W3DShadowTextureManager->invalidateCachedLightPositions();
  303. }
  304. void W3DProjectedShadowManager::updateRenderTargetTextures(void)
  305. {
  306. ///@todo: Don't update texture for shadows that can't be seen!!
  307. W3DProjectedShadow *shadow;
  308. if (!m_shadowList)
  309. return; //there are no shadows to render.
  310. if (!TheGlobalData->m_useShadowDecals)
  311. return;
  312. if (m_numProjectionShadows)
  313. for( shadow = m_shadowList; shadow; shadow = shadow->m_next )
  314. { //decals don't need any updates on a per-frame basis since
  315. //the image never changes.
  316. if (shadow->m_type != SHADOW_DECAL)
  317. shadow->update();
  318. }
  319. }
  320. ///Renders shadow on part of terrain covered by world-space bounding box.
  321. Int W3DProjectedShadowManager::renderProjectedTerrainShadow(W3DProjectedShadow *shadow, AABoxClass &box)
  322. {
  323. static Matrix4 mWorld(true); //initialize to identity matrix
  324. struct SHADOW_VOLUME_VERTEX //vertex structure passed to D3D
  325. {
  326. float x,y,z;
  327. };
  328. Int i,j,k;
  329. UnsignedByte alpha[4];
  330. float UA[4], VA[4];
  331. Bool flipForBlend;
  332. #define SHADOW_VOLUME_FVF D3DFVF_XYZ
  333. if (TheTerrainRenderObject)
  334. {
  335. WorldHeightMap *hmap=TheTerrainRenderObject->getMap();
  336. //Find size of heightmap sub-rectangle affected by shadow
  337. Real cx=box.Center.X;
  338. Real cy=box.Center.Y;
  339. Real dx=box.Extent.X;
  340. Real dy=box.Extent.Y;
  341. Real mapScaleInv=1.0f/MAP_XY_FACTOR;
  342. SHADOW_VOLUME_VERTEX* pvVertices;
  343. UnsignedShort *pvIndices;
  344. LPDIRECT3DDEVICE8 m_pDev=DX8Wrapper::_Get_D3D_Device8();
  345. if (!m_pDev) return 0;
  346. //Get terrain cell index for area with shadow
  347. Int startX=REAL_TO_INT_FLOOR(((cx - dx)*mapScaleInv));
  348. Int endX=REAL_TO_INT_CEIL(((cx + dx)*mapScaleInv));
  349. Int startY=REAL_TO_INT_FLOOR(((cy - dy)*mapScaleInv));
  350. Int endY=REAL_TO_INT_CEIL(((cy + dy)*mapScaleInv));
  351. //clip bounds to extents of heightmap
  352. startX = __max(startX,0);
  353. endX = __min(endX,hmap->getXExtent()-1);
  354. startY = __max(startY,0);
  355. endY = __min(endY,hmap->getYExtent()-1);
  356. Int vertsPerRow=endX - startX+1; //number of cells +1
  357. Int vertsPerColumn=endY-startY+1; //number of cells +1
  358. if (vertsPerRow == 1 || vertsPerColumn == 1)
  359. return 0; //nothing to render
  360. Int numVerts = vertsPerRow *vertsPerColumn; //number of terrain vertices
  361. if (nShadowVertsInBuf > (SHADOW_VERTEX_SIZE-numVerts)) //check if room for model verts
  362. { //flush the buffer by drawing the contents and re-locking again
  363. if (shadowVertexBufferD3D->Lock(0,numVerts*sizeof(SHADOW_VOLUME_VERTEX),(unsigned char**)&pvVertices,D3DLOCK_DISCARD) != D3D_OK)
  364. return 0;
  365. nShadowVertsInBuf=0;
  366. nShadowStartBatchVertex=0;
  367. }
  368. else
  369. { if (shadowVertexBufferD3D->Lock(nShadowVertsInBuf*sizeof(SHADOW_VOLUME_VERTEX),numVerts*sizeof(SHADOW_VOLUME_VERTEX), (unsigned char**)&pvVertices,D3DLOCK_NOOVERWRITE) != D3D_OK)
  370. return 0;
  371. }
  372. if(pvVertices)
  373. {
  374. //insert each cell's bottom/left edge vertex
  375. for (j=startY; j <= endY; j++)
  376. {
  377. float ycoord = (float)j * MAP_XY_FACTOR;
  378. for (i=startX; i <= endX; i++)
  379. {
  380. pvVertices->x=(float)i*MAP_XY_FACTOR;
  381. pvVertices->y=ycoord;
  382. pvVertices->z=(float)hmap->getHeight(i,j)*MAP_HEIGHT_SCALE;
  383. pvVertices++;
  384. }
  385. }
  386. }
  387. shadowVertexBufferD3D->Unlock();
  388. Int numIndex=(endX - startX) * (endY-startY)*6; //6 indices per terrain cell (2 triangles).
  389. if (nShadowIndicesInBuf > (SHADOW_INDEX_SIZE-numIndex)) //check if room for model verts
  390. { //flush the buffer by drawing the contents and re-locking again
  391. if (shadowIndexBufferD3D->Lock(0,numIndex*sizeof(short),(unsigned char**)&pvIndices,D3DLOCK_DISCARD) != D3D_OK)
  392. return 0;
  393. nShadowIndicesInBuf=0;
  394. nShadowStartBatchIndex=0;
  395. }
  396. else
  397. { if (shadowIndexBufferD3D->Lock(nShadowIndicesInBuf*sizeof(short),numIndex*sizeof(short), (unsigned char**)&pvIndices,D3DLOCK_NOOVERWRITE) != D3D_OK)
  398. return 0;
  399. }
  400. if(pvIndices)
  401. { //fill each cell's vertex indices
  402. Int rowStart;
  403. for (j=startY,rowStart=0; j<endY; j++,rowStart+=vertsPerRow)
  404. {
  405. for (i=rowStart,k=startX; k<endX; i++,k++)
  406. { ///@todo: Fix this to deal with flipped triangles
  407. hmap->getAlphaUVData(k, j, UA, VA, alpha, &flipForBlend, false);
  408. /* if (flipForBlend)
  409. { pvIndices[0]=i;
  410. pvIndices[1]=i+1;
  411. pvIndices[2]=i+vertsPerRow;
  412. pvIndices[3]=i+vertsPerRow;
  413. pvIndices[4]=i+1;
  414. pvIndices[5]=i+vertsPerRow+1;
  415. }
  416. else
  417. { pvIndices[0]=i+vertsPerRow;
  418. pvIndices[4]=pvIndices[1]=i;
  419. pvIndices[3]=pvIndices[2]=i+vertsPerRow+1;
  420. pvIndices[5]=i+1;
  421. }*/
  422. ///@todo: fix the winding order in heightmap to be in strip order like above!
  423. if (flipForBlend)
  424. { pvIndices[0]=i+1;
  425. pvIndices[1]=i+vertsPerRow;
  426. pvIndices[2]=i;
  427. pvIndices[3]=i+1;
  428. pvIndices[4]=i+1+vertsPerRow;
  429. pvIndices[5]=i+vertsPerRow;
  430. }
  431. else
  432. { pvIndices[0]=i;
  433. pvIndices[1]=i+1+vertsPerRow;
  434. pvIndices[2]=i+vertsPerRow;
  435. pvIndices[3]=i;
  436. pvIndices[4]=i+1;
  437. pvIndices[5]=i+1+vertsPerRow;
  438. }
  439. pvIndices += 6;
  440. }
  441. }
  442. }
  443. shadowIndexBufferD3D->Unlock();
  444. m_pDev->SetIndices(shadowIndexBufferD3D,nShadowStartBatchVertex);
  445. m_pDev->SetTransform(D3DTS_WORLD,(_D3DMATRIX *)&mWorld);
  446. m_pDev->SetStreamSource(0,shadowVertexBufferD3D,sizeof(SHADOW_VOLUME_VERTEX));
  447. m_pDev->SetVertexShader(SHADOW_VOLUME_FVF);
  448. Int numPolys = (endX - startX)*(endY - startY)*2; //2 triangles per cell
  449. m_pDev->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE); //should reject background pixels
  450. m_pDev->SetRenderState( D3DRS_STENCILENABLE, TRUE );
  451. m_pDev->SetRenderState( D3DRS_STENCILFUNC, D3DCMP_ALWAYS );
  452. m_pDev->SetRenderState( D3DRS_STENCILREF, 0x1 );
  453. m_pDev->SetRenderState( D3DRS_STENCILMASK, 0xffffffff );
  454. m_pDev->SetRenderState( D3DRS_STENCILWRITEMASK,0xffffffff );
  455. m_pDev->SetRenderState( D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP );
  456. m_pDev->SetRenderState( D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP );
  457. m_pDev->SetRenderState( D3DRS_STENCILPASS, D3DSTENCILOP_INCR );
  458. // m_pDev->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE ); //useful to see bounds
  459. m_pDev->SetRenderState( D3DRS_LIGHTING, FALSE);
  460. m_pDev->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_DESTCOLOR);
  461. m_pDev->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ZERO );
  462. if (DX8Wrapper::_Is_Triangle_Draw_Enabled())
  463. {
  464. Debug_Statistics::Record_DX8_Polys_And_Vertices(numPolys,numVerts,ShaderClass::_PresetOpaqueShader);
  465. m_pDev->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,numVerts,nShadowStartBatchIndex,numPolys);
  466. }
  467. m_pDev->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); //should reject background pixels
  468. m_pDev->SetRenderState( D3DRS_STENCILENABLE, FALSE );
  469. // m_pDev->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
  470. m_pDev->SetRenderState( D3DRS_LIGHTING, TRUE);
  471. nShadowVertsInBuf += numVerts;
  472. nShadowStartBatchVertex=nShadowVertsInBuf;
  473. nShadowIndicesInBuf += numIndex;
  474. nShadowStartBatchIndex=nShadowIndicesInBuf;
  475. return 1;
  476. }
  477. return 0;
  478. }
  479. #if 0
  480. TextureClass *snow=NULL;
  481. TextureClass *grass=NULL;
  482. TextureClass *ground=NULL;
  483. #define V_COUNT (4*4) //4 vertices per cell
  484. #define I_COUNT (4*6) //6 indices per cell
  485. #define TILE_HEIGHT 10.1f
  486. #define TILE_DIFFUSE 0x00b4b0a5
  487. enum BlendDirection
  488. { B_A, //visible on all sides
  489. B_R, //visible on right
  490. B_L, //visible on left
  491. B_T, //visible on top
  492. B_B, //visble on bottom
  493. B_TL, //visible on top/left
  494. B_BR, //visible on bottom/right
  495. B_TR, //visible on top/right
  496. B_BL //visilbe on bottom/left
  497. };
  498. //Vertex alpha values for each blend direction assuming tile vertices
  499. //start at top left corner and continue counter-clockwise
  500. DWORD BDToVA[9][4]=
  501. {
  502. {0xff000000,0xff000000,0xff000000,0xff000000},
  503. {0,0,0xff000000,0xff000000},
  504. {0xff000000,0xff000000,0,0},
  505. {0xff000000,0,0,0xff000000},
  506. {0,0xff000000,0xff000000,0},
  507. {0xff000000,0,0,0},
  508. {0,0,0xff000000,0},
  509. {0,0,0,0xff000000},
  510. {0,0xff000000,0,0}
  511. };
  512. static void RenderVBTile(TextureClass *text, Real ox, Real oy, Real ou, Real ov, BlendDirection bd=B_A)
  513. {
  514. DynamicVBAccessClass vb_access(BUFFER_TYPE_DYNAMIC_DX8,DX8_FVF_XYZNDUV2,4);
  515. DynamicIBAccessClass ib_access(BUFFER_TYPE_DYNAMIC_DX8,6);
  516. DynamicVBAccessClass::WriteLockClass lock(&vb_access);
  517. VertexFormatXYZNDUV2* vb= lock.Get_Formatted_Vertex_Array();
  518. DynamicIBAccessClass::WriteLockClass lockib(&ib_access);
  519. if (!vb) return;
  520. UnsignedShort *ib=lockib.Get_Index_Array();
  521. vb->x=ox;
  522. vb->y=oy;
  523. vb->z=TILE_HEIGHT;
  524. vb->diffuse=TILE_DIFFUSE|BDToVA[bd][0];
  525. vb->u1=ou;
  526. vb->v1=ov;
  527. vb++;
  528. vb->x=ox;
  529. vb->y=oy-10.0f;
  530. vb->z=TILE_HEIGHT;
  531. vb->diffuse=TILE_DIFFUSE|BDToVA[bd][1];
  532. vb->u1=ou;
  533. vb->v1=ov+0.25f;
  534. vb++;
  535. vb->x=ox+10.0f;
  536. vb->y=oy-10.0f;
  537. vb->z=TILE_HEIGHT;
  538. vb->diffuse=TILE_DIFFUSE|BDToVA[bd][2];
  539. vb->u1=ou+0.25f;
  540. vb->v1=ov+0.25f;
  541. vb++;
  542. vb->x=ox+10.0f;
  543. vb->y=oy;
  544. vb->z=TILE_HEIGHT;
  545. vb->diffuse=TILE_DIFFUSE|BDToVA[bd][3];
  546. vb->u1=ou+0.25f;
  547. vb->v1=ov;
  548. vb++;
  549. ib[0]=0;
  550. ib[1]=1;
  551. ib[2]=3;
  552. ib[3]=3;
  553. ib[4]=1;
  554. ib[5]=2;
  555. if (bd == B_TR || bd == B_BL)
  556. { //need to flip triangles so alpha gradient doesn't follow diagonal edge
  557. ib[2]=2;
  558. ib[4]=0;
  559. }
  560. DX8Wrapper::Set_Index_Buffer(ib_access,0);
  561. DX8Wrapper::Set_Vertex_Buffer(vb_access);
  562. DX8Wrapper::Set_Texture(0, text);
  563. DX8Wrapper::Set_DX8_Render_State(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
  564. DX8Wrapper::Set_DX8_Render_State(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
  565. DX8Wrapper::Set_DX8_Render_State(D3DRS_ALPHABLENDENABLE, TRUE );
  566. ShaderClass::Invalidate(); //invalidate to force shader to reset since we directly changed states
  567. DX8Wrapper::Draw_Triangles( 0,2, 0, 4); //draw a quad, 2 triangles, 4 verts
  568. }
  569. //Debug code used to draw some dummy polygons.
  570. void TestBlendRender(RenderInfoClass & rinfo)
  571. {
  572. static Int doInit=1;
  573. if (doInit)
  574. { doInit = 0;
  575. snow = WW3DAssetManager::Get_Instance()->Get_Texture("TXSnow04a.tga");
  576. grass = WW3DAssetManager::Get_Instance()->Get_Texture("TMGras23a.tga");
  577. ground = WW3DAssetManager::Get_Instance()->Get_Texture("TXAsph01a.tga");
  578. }
  579. VertexMaterialClass *vmat=VertexMaterialClass::Get_Preset(VertexMaterialClass::PRELIT_DIFFUSE);
  580. DX8Wrapper::Set_Material(vmat);
  581. REF_PTR_RELEASE(vmat);
  582. DX8Wrapper::Set_Shader(ShaderClass::_PresetOpaqueShader);
  583. Matrix3D tm(1); //identity
  584. DX8Wrapper::Set_Transform(D3DTS_WORLD,tm);
  585. //grass
  586. RenderVBTile(grass,580.0f,480.0f,0.0f,0.0f); RenderVBTile(grass,590.0f,480.0f,0.25f,0.0f);
  587. RenderVBTile(grass,580.0f,470.0f,0.0f,0.25f); RenderVBTile(grass,590.0f,470.0f,0.25f,0.25f);
  588. RenderVBTile(grass,580.0f,460.0f,0.0f,0.5f); RenderVBTile(grass,590.0f,460.0f,0.25f,0.5f,B_L);
  589. RenderVBTile(grass,580.0f,450.0f,0.0f,0.75f); RenderVBTile(grass,590.0f,450.0f,0.25f,0.75f,B_L);
  590. RenderVBTile(grass,580.0f,440.0f,0.0f,0.0f); RenderVBTile(grass,590.0f,440.0f,0.25f,0.0f,B_L);
  591. RenderVBTile(grass,610.0f,460.0f,0.0f,0.5f, B_B);
  592. RenderVBTile(grass,610.0f,450.0f,0.0f,0.75f);
  593. RenderVBTile(grass,610.0f,440.0f,0.0f,0.0f);
  594. //snow
  595. RenderVBTile(snow,590.0f,480.0f,0.0f,0.0f, B_R); RenderVBTile(snow,600.0f,480.0f,0.25f,0.0f); RenderVBTile(snow,610.0f,480.0f,0.5f,0.0f);
  596. RenderVBTile(snow,590.0f,470.0f,0.0f,0.25f, B_R); RenderVBTile(snow,600.0f,470.0f,0.25f,0.25f); RenderVBTile(snow,610.0f,470.0f,0.5f,0.25f);
  597. RenderVBTile(snow,590.0f,460.0f,0.0f,0.5f, B_TR); RenderVBTile(snow,600.0f,460.0f,0.25f,0.5f,B_T); RenderVBTile(snow,610.0f,460.0f,0.5f,0.5f,B_T);
  598. }
  599. #endif
  600. void W3DProjectedShadowManager::flushDecals(W3DShadowTexture *texture, ShadowType type)
  601. {
  602. static Matrix4 mWorld(true); //initialize to identity matrix
  603. if (nShadowDecalVertsInBatch == 0 && nShadowDecalPolysInBatch == 0)
  604. { //nothing to render
  605. return;
  606. }
  607. LPDIRECT3DDEVICE8 m_pDev=DX8Wrapper::_Get_D3D_Device8();
  608. if (!m_pDev) return; //no D3D Device to render
  609. VertexMaterialClass *vmat=VertexMaterialClass::Get_Preset(VertexMaterialClass::PRELIT_DIFFUSE);
  610. DX8Wrapper::Set_Material(vmat);
  611. REF_PTR_RELEASE(vmat);
  612. DX8Wrapper::Set_Texture(0,texture->getTexture());
  613. // DX8Wrapper::Set_Shader(ShaderClass::_PresetOpaqueShader); //good for debugging, draws without alpha
  614. switch (type)
  615. {
  616. case SHADOW_DECAL:
  617. DX8Wrapper::Set_Shader(ShaderClass::_PresetMultiplicativeShader);
  618. break;
  619. case SHADOW_ALPHA_DECAL:
  620. DX8Wrapper::Set_Shader(ShaderClass::_PresetAlphaShader);
  621. break;
  622. case SHADOW_ADDITIVE_DECAL:
  623. DX8Wrapper::Set_Shader(ShaderClass::_PresetAdditiveShader);
  624. break;
  625. }
  626. // DX8Wrapper::Set_DX8_Render_State(D3DRS_ALPHAREF,0x60);
  627. // DX8Wrapper::Set_DX8_Render_State(D3DRS_ALPHAFUNC,D3DCMP_GREATEREQUAL);
  628. //_PresetAlphaSpriteShader
  629. DX8Wrapper::Apply_Render_State_Changes(); //force update of view and projection matrices
  630. //Alpha Blended Shadows
  631. // m_pDev->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
  632. // m_pDev->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
  633. /* UnsignedInt color=TheW3DShadowManager->getShadowColor();
  634. m_pDev->SetRenderState( D3DRS_TEXTUREFACTOR, 0xff000000 | color);
  635. m_pDev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
  636. m_pDev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
  637. m_pDev->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_TFACTOR);
  638. m_pDev->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
  639. m_pDev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
  640. m_pDev->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_TFACTOR);
  641. */
  642. m_pDev->SetIndices(shadowDecalIndexBufferD3D,nShadowDecalStartBatchVertex);
  643. m_pDev->SetTransform(D3DTS_WORLD,(_D3DMATRIX *)&mWorld);
  644. m_pDev->SetStreamSource(0,shadowDecalVertexBufferD3D,sizeof(SHADOW_DECAL_VERTEX));
  645. m_pDev->SetVertexShader(SHADOW_DECAL_FVF);
  646. //Hard Shadows using stencil
  647. /* m_pDev->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ZERO);
  648. m_pDev->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );
  649. m_pDev->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE); //should reject background pixels
  650. m_pDev->SetRenderState( D3DRS_STENCILENABLE, TRUE );
  651. */
  652. /* m_pDev->SetRenderState( D3DRS_STENCILFUNC, D3DCMP_ALWAYS );
  653. m_pDev->SetRenderState( D3DRS_STENCILREF, 0x1 );
  654. m_pDev->SetRenderState( D3DRS_STENCILMASK, 0xffffffff );
  655. m_pDev->SetRenderState( D3DRS_STENCILWRITEMASK,0xffffffff );
  656. m_pDev->SetRenderState( D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP );
  657. m_pDev->SetRenderState( D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP );
  658. m_pDev->SetRenderState( D3DRS_STENCILPASS, D3DSTENCILOP_INCR );
  659. */
  660. //m_pDev->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE ); //useful to see bounds
  661. if (DX8Wrapper::_Is_Triangle_Draw_Enabled())
  662. {
  663. Debug_Statistics::Record_DX8_Polys_And_Vertices(nShadowDecalPolysInBatch,nShadowDecalVertsInBatch,ShaderClass::_PresetOpaqueShader);
  664. m_pDev->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,nShadowDecalVertsInBatch,nShadowDecalStartBatchIndex,nShadowDecalPolysInBatch);
  665. }
  666. // m_pDev->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); //should reject background pixels
  667. // m_pDev->SetRenderState( D3DRS_STENCILENABLE, FALSE );
  668. //m_pDev->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
  669. //Restore multiplicative sprite shader
  670. // m_pDev->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_SRCCOLOR); //restore W3D state
  671. // m_pDev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);
  672. /* m_pDev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
  673. m_pDev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
  674. m_pDev->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT);
  675. m_pDev->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
  676. m_pDev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
  677. m_pDev->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_CURRENT);
  678. */
  679. nShadowDecalStartBatchVertex=nShadowDecalVertsInBuf;
  680. nShadowDecalStartBatchIndex=nShadowDecalIndicesInBuf;
  681. nShadowDecalPolysInBatch=0; //reset number of polys in texture batch
  682. nShadowDecalVertsInBatch=0;
  683. }
  684. /*
  685. void testShadowDecal(void)
  686. {
  687. Shadow::ShadowTypeInfo decalInfo;
  688. decalInfo.allowUpdates = FALSE; //shadow image will never update
  689. decalInfo.allowWorldAlign = TRUE; //shadow image will wrap around world objects
  690. decalInfo.m_type = SHADOW_ALPHA_DECAL;
  691. strcpy(decalInfo.m_ShadowName,"exwave256");
  692. decalInfo.m_sizeX = 1280.0f;
  693. decalInfo.m_sizeY = 1280.0f;
  694. decalInfo.m_offsetX = 0;
  695. decalInfo.m_offsetY = 0;
  696. Shadow *shadow=TheProjectedShadowManager->addDecal(&decalInfo);
  697. shadow->setPosition(600,600,600);
  698. shadow->setAngle(0.0f);
  699. shadow->setColor(0xffff0000);
  700. }
  701. */
  702. #define BRIDGE_OFFSET_FACTOR 1.5f
  703. /**Decals have a low poly count so its better to render large numbers at once. This system will queue them
  704. up until the buffers fill up. It will then flush the buffer (draw decals) and be ready for new decals. This
  705. is an optimized system that only uses the render objects bounding box to determine shadow visibility.
  706. */
  707. void W3DProjectedShadowManager::queueDecal(W3DProjectedShadow *shadow)
  708. {
  709. int i,j,k;
  710. Vector3 hmapVertex,objPos;
  711. AABoxClass box;
  712. Matrix3D objXform(1);
  713. Real cx,cy,dx,dy;
  714. Real mapScaleInv=1.0f/MAP_XY_FACTOR;
  715. static Vector3 objCenter(0,0,0);
  716. Vector3 uVector,vVector;
  717. Real uOffset,vOffset,vecLength;
  718. Int borderSize;
  719. RenderObjClass *robj=shadow->m_robj;
  720. Real layerHeight=0;
  721. if (TheTerrainRenderObject)
  722. {
  723. LPDIRECT3DDEVICE8 m_pDev=DX8Wrapper::_Get_D3D_Device8();
  724. if (!m_pDev) return; //no D3D Device to render
  725. WorldHeightMap *hmap=TheTerrainRenderObject->getMap();
  726. borderSize=hmap->getBorderSize();
  727. if (robj)
  728. {
  729. objPos=robj->Get_Position();
  730. objXform=robj->Get_Transform();
  731. if (robj->Get_User_Data())
  732. {
  733. Drawable *draw=((DrawableInfo *)robj->Get_User_Data())->m_drawable;
  734. const Object *object=draw->getObject();
  735. PathfindLayerEnum objectLayer;
  736. if (object && (objectLayer=object->getLayer()) != LAYER_GROUND)
  737. { //check if object that this decal belongs to is not on the ground (bridge?)
  738. layerHeight=BRIDGE_OFFSET_FACTOR+TheTerrainLogic->getLayerHeight(objPos.X,objPos.Y,objectLayer);
  739. }
  740. }
  741. }
  742. else
  743. { //no render object so use shadow's local position and default orientation
  744. objPos.Set(shadow->m_x,shadow->m_y,shadow->m_z);
  745. objXform.Rotate_Z(shadow->m_localAngle);
  746. }
  747. //Find size of heightmap sub-rectangle affected by shadow
  748. //If user supplied size values, ignore bounding box
  749. objPos.Z=0.0f; //we don't care about object height since shadows project top-down
  750. uVector=objXform.Get_X_Vector();
  751. uVector.Z=0.0f;
  752. vecLength=uVector.Length();
  753. if (vecLength != 0.0f) //prevent divide by zero
  754. { uVector *= 1.0f/vecLength;
  755. vVector = uVector;
  756. vVector.Rotate_Z(-1.0f,0.0f); //rotate u vector by -90 degress to get v vector.
  757. }
  758. else
  759. {
  760. vVector=objXform.Get_Y_Vector();
  761. vVector.Z=0.0f;
  762. vecLength=vVector.Length();
  763. if (vecLength != 0.0f) //prevent divide by zero
  764. vVector *= 1.0f/vecLength;
  765. else
  766. vVector.Set(0.0f,-1.0f,0.0f); //Point uvector in default direction
  767. uVector = vVector;
  768. uVector.Rotate_Z(1.0f,0.0f); //rotate v vector by 90 degress to get u vector.
  769. }
  770. //Compute bounding box of projection
  771. Vector3 boxCorners[4]; //top-left, top-right, bottom-right, bottom-left
  772. dx = shadow->m_decalSizeX;
  773. dy = shadow->m_decalSizeY;
  774. Vector3 left_x=-dx * (uVector * (0.5f + shadow->m_decalOffsetU));
  775. Vector3 right_x = dx * (uVector * (0.5f - shadow->m_decalOffsetU));
  776. Vector3 top_y = -dy * (vVector * (0.5f + shadow->m_decalOffsetV));
  777. Vector3 bottom_y = dy * (vVector * (0.5f - shadow->m_decalOffsetV));
  778. ///@todo: Optimize this bounding box calculation to use transformed extents
  779. //Also skip bounding box calculation if object has not moved.
  780. boxCorners[0] = left_x + top_y;
  781. boxCorners[1] = right_x + top_y;
  782. boxCorners[2] = right_x + bottom_y;
  783. boxCorners[3] = left_x + bottom_y;
  784. Real min_x,max_x,min_y,max_y;
  785. max_x=min_x=boxCorners[0].X;
  786. max_y=min_y=boxCorners[0].Y;
  787. for (Int bi=1; bi<4; bi++)
  788. { max_x = __max(max_x,boxCorners[bi].X);
  789. min_x = __min(min_x,boxCorners[bi].X);
  790. max_y = __max(max_y,boxCorners[bi].Y);
  791. min_y = __min(min_y,boxCorners[bi].Y);
  792. }
  793. uVector *= shadow->m_oowDecalSizeX;
  794. vVector *= shadow->m_oowDecalSizeY;
  795. uOffset = shadow->m_decalOffsetU + 0.5f;
  796. vOffset = shadow->m_decalOffsetV + 0.5f;
  797. /* { //This version will stretch to fit orientation of object
  798. ///@todo: Most of the values below can be cached in shadow object
  799. shadow->m_robj->Get_Obj_Space_Bounding_Box(box);
  800. decalSizeX=box.Extent.X*2.0f; //use local space bounding box to determine shadow size
  801. decalSizeY=box.Extent.Y*2.0f;
  802. // box=shadow->m_robj->Get_Bounding_Box(); //get world-space bounding box
  803. objPos = box.Center;
  804. box.Init(objCenter,Vector3(decalSizeX*0.5f,decalSizeY*0.5f,1.0f));
  805. box.Transform(objXform); //transform box from object space to world space
  806. box.Translate(objPos=objXform.Rotate_Vector(objPos));
  807. objPos += shadow->m_robj->Get_Position();
  808. }
  809. */
  810. // Experimental code to try and get a better fitting bounding box around shadow
  811. /* Experimental code to try and get a better fitting bounding box around shadow
  812. { //use the object's bounding box to determine shadow extent
  813. ///@todo: Most of the values below can be cached in shadow object
  814. uVector=objXform.Get_X_Vector();
  815. uVector.Z=0;
  816. uVector.Normalize();
  817. vVector=objXform.Get_Y_Vector(); //invert direction since v axis runs right relative to u.
  818. vVector.Z=0;
  819. vVector.Normalize();
  820. shadow->m_robj->Get_Obj_Space_Bounding_Box(box);
  821. decalSizeX = box.Extent.X * 2.0f;
  822. decalSizeY = box.Extent.Y * 2.0f;
  823. Real newExtentX = fabs(uVector * box.Extent) + fabs(uVector * box.Center); //get new extent for object orientation
  824. Real newExtentY = fabs(vVector * box.Extent) + fabs(vVector * box.Center); //get new extent for object orientation
  825. objPos += uVector * box.Center.X;
  826. objPos += vVector * box.Center.Y;
  827. // objPos.Y = objPos.Y + vVector * box.Center;
  828. objPos.Z = 0.0f;
  829. //set new oriented bounding box extents
  830. box.Extent.Set(newExtentX, newExtentY, 0);
  831. box.Center.Set(objPos.X,objPos.Y,objPos.Z);
  832. }
  833. */
  834. cx=box.Center.X;
  835. cy=box.Center.Y;
  836. dx=box.Extent.X;
  837. dy=box.Extent.Y;
  838. //Get terrain cell index for area with shadow
  839. Int startX=REAL_TO_INT_FLOOR(((objPos.X+min_x)*mapScaleInv)) + borderSize;
  840. Int endX=REAL_TO_INT_CEIL(((objPos.X+max_x)*mapScaleInv)) + borderSize;
  841. Int startY=REAL_TO_INT_FLOOR(((objPos.Y+min_y)*mapScaleInv)) + borderSize;
  842. Int endY=REAL_TO_INT_CEIL(((objPos.Y+max_y)*mapScaleInv)) + borderSize;
  843. startX = __max(startX,drawStartX);
  844. startX = __min(startX,drawEdgeX);
  845. startY = __max(startY,drawStartY);
  846. startY = __min(startY,drawEdgeY);
  847. endX = __max(endX,drawStartX);
  848. endX = __min(endX,drawEdgeX);
  849. endY = __max(endY,drawStartY);
  850. endY = __min(endY,drawEdgeY);
  851. //Check if decal too large to fit inside 65536 index buffer.
  852. //try clipping each direction to < 104 since that's more than
  853. //enough to cover typical map.
  854. Int numExtraX=(endX - startX+1)-104;
  855. if (numExtraX > 0)
  856. { //figure out how much to clip out at each edge of decal
  857. Int numStartExtraX=REAL_TO_INT_FLOOR((float)numExtraX/2.0f);
  858. Int numEdgeExtraX=numExtraX-numStartExtraX;
  859. startX+=numStartExtraX;
  860. endX-=numEdgeExtraX;
  861. }
  862. Int numExtraY=(endY - startY+1)-104;
  863. if (numExtraY > 0)
  864. {
  865. Int numStartExtraY=REAL_TO_INT_FLOOR((float)numExtraY/2.0f);
  866. Int numEdgeExtraY=numExtraY-numStartExtraY;
  867. startY+=numStartExtraY;
  868. endY-=numEdgeExtraY;
  869. }
  870. Int vertsPerRow=endX - startX+1; //number of cells +1
  871. Int vertsPerColumn=endY-startY+1; //number of cells +1
  872. if (vertsPerRow <= 1 || vertsPerColumn <= 1)
  873. return; //nothing to render
  874. Int numVerts = vertsPerRow *vertsPerColumn; //number of terrain vertices
  875. Int numIndex=(endX - startX) * (endY-startY)*6; //6 indices per terrain cell (2 triangles).
  876. SHADOW_DECAL_VERTEX* pvVertices;
  877. UnsignedShort *pvIndices;
  878. if (nShadowDecalVertsInBuf > (SHADOW_DECAL_VERTEX_SIZE-numVerts)) //check if room for model verts
  879. { //flush the buffer by drawing the contents and re-locking again
  880. flushDecals(shadow->m_shadowTexture[0], shadow->m_type);
  881. if (shadowDecalVertexBufferD3D->Lock(0,numVerts*sizeof(SHADOW_DECAL_VERTEX),(unsigned char**)&pvVertices,D3DLOCK_DISCARD) != D3D_OK)
  882. return;
  883. nShadowDecalStartBatchVertex=0;
  884. nShadowDecalPolysInBatch=0; //reset number of polys in texture batch
  885. nShadowDecalVertsInBatch=0;
  886. nShadowDecalVertsInBuf=0;
  887. }
  888. else
  889. { if (shadowDecalVertexBufferD3D->Lock(nShadowDecalVertsInBuf*sizeof(SHADOW_DECAL_VERTEX),numVerts*sizeof(SHADOW_DECAL_VERTEX), (unsigned char**)&pvVertices,D3DLOCK_NOOVERWRITE) != D3D_OK)
  890. return;
  891. }
  892. //code to deal with rotated shadows based on sun direction, fix this later. For now shadow rotates with object rotation.
  893. //shadow->m_shadowTexture[0]->getDecalUVAxis(&uVector,&vVector);
  894. //uVector *= 20.0f/dx;//shadow->m_decalRadius; //scale texture to fit object
  895. //vVector *= 20.0f/dy;//1.2f;//shadow->m_decalRadius; //scale texture to fit object
  896. /* uVector=objXform.Get_X_Vector();
  897. uVector.Normalize();
  898. uVector /= decalSizeX + (1.0f+4.0f/64.0f); //texture has 1 pixel transparent border so we strtech up to make sure solid pixels reach extent..
  899. vVector=objXform.Get_Y_Vector() * -1.0f; //invert direction since v axis runs right relative to u.
  900. vVector.Normalize();
  901. vVector /= decalSizeY + (1.0f+4.0f/64.0f);
  902. */
  903. DEBUG_ASSERTCRASH(numVerts == ((endY-startY+1)*(endX-startX+1)), ("queueDecal VB size mismatch"));
  904. if(pvVertices)
  905. {
  906. if (layerHeight)
  907. for (j=startY; j <= endY; j++)
  908. {
  909. hmapVertex.Y=(float)(j-borderSize) * MAP_XY_FACTOR;
  910. for (i=startX; i <= endX; i++)
  911. {
  912. hmapVertex.X=(float)(i-borderSize)*MAP_XY_FACTOR;
  913. hmapVertex.Z=__max((float)hmap->getHeight(i,j)*MAP_HEIGHT_SCALE,layerHeight);
  914. pvVertices->x=hmapVertex.X;
  915. pvVertices->y=hmapVertex.Y;
  916. pvVertices->z=hmapVertex.Z;
  917. pvVertices->diffuse=shadow->m_diffuse;
  918. pvVertices->u=Vector3::Dot_Product(uVector, (hmapVertex-objPos))+uOffset;
  919. pvVertices->v=Vector3::Dot_Product(vVector, (hmapVertex-objPos))+vOffset;
  920. pvVertices++;
  921. }
  922. }
  923. else
  924. //insert each cell's bottom/left edge vertex
  925. for (j=startY; j <= endY; j++)
  926. {
  927. hmapVertex.Y=(float)(j-borderSize) * MAP_XY_FACTOR;
  928. for (i=startX; i <= endX; i++)
  929. {
  930. hmapVertex.X=(float)(i-borderSize)*MAP_XY_FACTOR;
  931. hmapVertex.Z=(float)hmap->getHeight(i,j)*MAP_HEIGHT_SCALE+0.01f * MAP_XY_FACTOR;
  932. pvVertices->x=hmapVertex.X;
  933. pvVertices->y=hmapVertex.Y;
  934. pvVertices->z=hmapVertex.Z;
  935. pvVertices->diffuse=shadow->m_diffuse;
  936. pvVertices->u=Vector3::Dot_Product(uVector, (hmapVertex-objPos))+uOffset;
  937. pvVertices->v=Vector3::Dot_Product(vVector, (hmapVertex-objPos))+vOffset;
  938. pvVertices++;
  939. }
  940. }
  941. }
  942. shadowDecalVertexBufferD3D->Unlock();
  943. if (nShadowDecalIndicesInBuf > (SHADOW_DECAL_INDEX_SIZE-numIndex)) //check if room for model verts
  944. { //flush the buffer by drawing the contents and re-locking again
  945. flushDecals(shadow->m_shadowTexture[0], shadow->m_type);
  946. if (shadowDecalIndexBufferD3D->Lock(0,numIndex*sizeof(short),(unsigned char**)&pvIndices,D3DLOCK_DISCARD) != D3D_OK)
  947. return;
  948. nShadowDecalStartBatchIndex=0;
  949. nShadowDecalPolysInBatch=0; //reset number of polys in texture batch
  950. nShadowDecalVertsInBatch=0;
  951. nShadowDecalIndicesInBuf=0;
  952. }
  953. else
  954. { if (shadowDecalIndexBufferD3D->Lock(nShadowDecalIndicesInBuf*sizeof(short),numIndex*sizeof(short), (unsigned char**)&pvIndices,D3DLOCK_NOOVERWRITE) != D3D_OK)
  955. return;
  956. }
  957. if(pvIndices)
  958. { //fill each cell's vertex indices
  959. Int rowStart;
  960. for (j=startY,rowStart=0; j<endY; j++,rowStart+=vertsPerRow)
  961. {
  962. for (i=rowStart,k=startX; k<endX; i++,k++)
  963. {
  964. ///@todo: fix the winding order in heightmap to be in strip order like above!
  965. if (hmap->getFlipState(k,j))
  966. { pvIndices[0]=i+1+nShadowDecalVertsInBatch;
  967. pvIndices[1]=i+vertsPerRow+nShadowDecalVertsInBatch;
  968. pvIndices[2]=i+nShadowDecalVertsInBatch;
  969. pvIndices[3]=i+1+nShadowDecalVertsInBatch;
  970. pvIndices[4]=i+1+vertsPerRow+nShadowDecalVertsInBatch;
  971. pvIndices[5]=i+vertsPerRow+nShadowDecalVertsInBatch;
  972. }
  973. else
  974. { pvIndices[0]=i+nShadowDecalVertsInBatch;
  975. pvIndices[1]=i+1+vertsPerRow+nShadowDecalVertsInBatch;
  976. pvIndices[2]=i+vertsPerRow+nShadowDecalVertsInBatch;
  977. pvIndices[3]=i+nShadowDecalVertsInBatch;
  978. pvIndices[4]=i+1+nShadowDecalVertsInBatch;
  979. pvIndices[5]=i+1+vertsPerRow+nShadowDecalVertsInBatch;
  980. }
  981. pvIndices += 6;
  982. }
  983. }
  984. }
  985. shadowDecalIndexBufferD3D->Unlock();
  986. Int numPolys = (endX - startX)*(endY - startY)*2; //2 triangles per cell
  987. nShadowDecalPolysInBatch += numPolys;
  988. nShadowDecalVertsInBuf += numVerts;
  989. nShadowDecalVertsInBatch += numVerts;
  990. // nShadowDecalStartBatchVertex=nShadowDecalVertsInBuf;
  991. nShadowDecalIndicesInBuf += numIndex;
  992. // nShadowDecalStartBatchIndex=nShadowDecalIndicesInBuf;
  993. return;
  994. }
  995. }
  996. /**Simpler/faster decal system that always uses 2 triangles that are roughly oriented
  997. to terrain. Since they are not projected onto terrain, there may be clipping
  998. artifacts in certain situations.
  999. TODO: Too much clipping. Need to check terrain heights at all 4 corners and adjust tilt to match*/
  1000. ///@todo: We should have a pre-made static filled index buffer since we always send down 2 triangles.
  1001. void W3DProjectedShadowManager::queueSimpleDecal(W3DProjectedShadow *shadow)
  1002. {
  1003. Vector3 objPos;
  1004. Matrix3D objXform;
  1005. Vector3 uVector,vVector;
  1006. Coord3D normal;
  1007. if (TheTerrainRenderObject)
  1008. {
  1009. LPDIRECT3DDEVICE8 m_pDev=DX8Wrapper::_Get_D3D_Device8();
  1010. if (!m_pDev) return; //no D3D Device to render
  1011. objPos=shadow->m_robj->Get_Position();
  1012. objXform=shadow->m_robj->Get_Transform();
  1013. Real groundHeight=TheTerrainRenderObject->getHeightMapHeight(objPos.X, objPos.Y, &normal);
  1014. Vector3 groundNormal(normal.x,normal.y,normal.z);
  1015. //Find new tu vector parallel to terrain by projecting existing x_vector onto
  1016. //terrain normal and subtracting the result.
  1017. uVector=objXform.Get_X_Vector();
  1018. Real uVectorAlongNormal = Vector3::Dot_Product(uVector,groundNormal);
  1019. uVector -= uVectorAlongNormal * groundNormal;
  1020. uVector.Normalize();
  1021. //Find new tv vector parallel to terrain by crossing new tu vector with terrain normal.
  1022. Vector3::Cross_Product(uVector,groundNormal,&vVector);
  1023. Int numVerts = 4; //number of decal vertices
  1024. Int numIndex=6; //(2 triangles).
  1025. SHADOW_DECAL_VERTEX* pvVertices;
  1026. UnsignedShort *pvIndices;
  1027. if (nShadowDecalVertsInBuf > (SHADOW_DECAL_VERTEX_SIZE-numVerts)) //check if room for model verts
  1028. { //flush the buffer by drawing the contents and re-locking again
  1029. flushDecals(shadow->m_shadowTexture[0], shadow->m_type);
  1030. if (shadowDecalVertexBufferD3D->Lock(0,numVerts*sizeof(SHADOW_DECAL_VERTEX),(unsigned char**)&pvVertices,D3DLOCK_DISCARD) != D3D_OK)
  1031. return;
  1032. nShadowDecalStartBatchVertex=0;
  1033. nShadowDecalPolysInBatch=0; //reset number of polys in texture batch
  1034. nShadowDecalVertsInBatch=0;
  1035. nShadowDecalVertsInBuf=0;
  1036. }
  1037. else
  1038. { if (shadowDecalVertexBufferD3D->Lock(nShadowDecalVertsInBuf*sizeof(SHADOW_DECAL_VERTEX),numVerts*sizeof(SHADOW_DECAL_VERTEX), (unsigned char**)&pvVertices,D3DLOCK_NOOVERWRITE) != D3D_OK)
  1039. return;
  1040. }
  1041. objPos.Z=groundHeight; //force decal to ground level
  1042. objPos += groundNormal * 1.0f; //offset decal slightly above terrain to reduce z-fighting.
  1043. Vector3 vertex;
  1044. if(pvVertices)
  1045. {
  1046. //Top-left
  1047. vertex = objPos + vVector * shadow->m_decalSizeY * -0.5f - uVector * shadow->m_decalSizeX * 0.5f;
  1048. pvVertices->x=vertex.X;
  1049. pvVertices->y=vertex.Y;
  1050. pvVertices->z=vertex.Z;
  1051. pvVertices->u=0.0f;
  1052. pvVertices->v=0.0f;
  1053. pvVertices++;
  1054. //Bottom-left
  1055. vertex += vVector * shadow->m_decalSizeY;
  1056. pvVertices->x=vertex.X;
  1057. pvVertices->y=vertex.Y;
  1058. pvVertices->z=vertex.Z;
  1059. pvVertices->u=0.0f;
  1060. pvVertices->v=1.0f;
  1061. pvVertices++;
  1062. //Bottom-right
  1063. vertex += uVector * shadow->m_decalSizeX;
  1064. pvVertices->x=vertex.X;
  1065. pvVertices->y=vertex.Y;
  1066. pvVertices->z=vertex.Z;
  1067. pvVertices->u=1.0f;
  1068. pvVertices->v=1.0f;
  1069. pvVertices++;
  1070. //Top-right
  1071. vertex -= vVector * shadow->m_decalSizeY;
  1072. pvVertices->x=vertex.X;
  1073. pvVertices->y=vertex.Y;
  1074. pvVertices->z=vertex.Z;
  1075. pvVertices->u=1.0f;
  1076. pvVertices->v=0.0f;
  1077. pvVertices++;
  1078. }
  1079. shadowDecalVertexBufferD3D->Unlock();
  1080. if (nShadowDecalIndicesInBuf > (SHADOW_DECAL_INDEX_SIZE-numIndex)) //check if room for model verts
  1081. { //flush the buffer by drawing the contents and re-locking again
  1082. flushDecals(shadow->m_shadowTexture[0],shadow->m_type);
  1083. if (shadowDecalIndexBufferD3D->Lock(0,numIndex*sizeof(short),(unsigned char**)&pvIndices,D3DLOCK_DISCARD) != D3D_OK)
  1084. return;
  1085. nShadowDecalStartBatchIndex=0;
  1086. nShadowDecalPolysInBatch=0; //reset number of polys in texture batch
  1087. nShadowDecalVertsInBatch=0;
  1088. nShadowDecalIndicesInBuf=0;
  1089. }
  1090. else
  1091. { if (shadowDecalIndexBufferD3D->Lock(nShadowDecalIndicesInBuf*sizeof(short),numIndex*sizeof(short), (unsigned char**)&pvIndices,D3DLOCK_NOOVERWRITE) != D3D_OK)
  1092. return;
  1093. }
  1094. if(pvIndices)
  1095. { pvIndices[0]=nShadowDecalVertsInBatch;
  1096. pvIndices[1]=nShadowDecalVertsInBatch+1;
  1097. pvIndices[2]=nShadowDecalVertsInBatch+2;
  1098. pvIndices[3]=nShadowDecalVertsInBatch;
  1099. pvIndices[4]=nShadowDecalVertsInBatch+2;
  1100. pvIndices[5]=nShadowDecalVertsInBatch+3;
  1101. pvIndices += 6;
  1102. }
  1103. shadowDecalIndexBufferD3D->Unlock();
  1104. Int numPolys = 2; //2 triangles per decal
  1105. nShadowDecalPolysInBatch += numPolys;
  1106. nShadowDecalVertsInBuf += numVerts;
  1107. nShadowDecalVertsInBatch += numVerts;
  1108. nShadowDecalIndicesInBuf += numIndex;
  1109. return;
  1110. }
  1111. }
  1112. Int W3DProjectedShadowManager::renderShadows(RenderInfoClass & rinfo)
  1113. {
  1114. ///@todo: implement this method.
  1115. W3DProjectedShadow *shadow;
  1116. static AABoxClass aaBox;
  1117. static SphereClass sphere;
  1118. Int projectionCount=0;
  1119. if (!m_shadowList && !m_decalList)
  1120. return projectionCount; //there are no shadows to render.
  1121. //Find extents of visible terrain
  1122. if (TheTerrainRenderObject)
  1123. {
  1124. WorldHeightMap *hmap=TheTerrainRenderObject->getMap();
  1125. drawEdgeY=hmap->getDrawOrgY()+hmap->getDrawHeight()-1;
  1126. drawEdgeX=hmap->getDrawOrgX()+hmap->getDrawWidth()-1;
  1127. if (drawEdgeX > (hmap->getXExtent()-1))
  1128. drawEdgeX = hmap->getXExtent()-1;
  1129. if (drawEdgeY > (hmap->getYExtent()-1))
  1130. drawEdgeY = hmap->getYExtent()-1;
  1131. drawStartX=hmap->getDrawOrgX();
  1132. drawStartY=hmap->getDrawOrgY();
  1133. }
  1134. else
  1135. return projectionCount;
  1136. //According to Nvidia there's a D3D bug that happens if you don't start with a
  1137. //new dynamic VB each frame - so we force a DISCARD by overflowing the counter.
  1138. nShadowDecalVertsInBuf = 0xffff;
  1139. nShadowDecalIndicesInBuf = 0xffff;
  1140. if (TheGlobalData->m_useShadowDecals)
  1141. {
  1142. // Render the object
  1143. TheDX8MeshRenderer.Set_Camera(&rinfo.Camera);
  1144. //keep track of active decal texture so we can render all decals at once.
  1145. W3DShadowTexture *lastShadowDecalTexture=NULL;
  1146. ShadowType lastShadowType = SHADOW_NONE;
  1147. for( shadow = m_shadowList; shadow; shadow = shadow->m_next )
  1148. {
  1149. if (shadow->m_isEnabled && !shadow->m_isInvisibleEnabled)
  1150. {
  1151. if (shadow->m_type & SHADOW_DECAL)
  1152. {
  1153. if (lastShadowDecalTexture == NULL)
  1154. lastShadowDecalTexture=m_shadowList->m_shadowTexture[0];
  1155. if (lastShadowType == SHADOW_NONE)
  1156. lastShadowType = m_shadowList->m_type;
  1157. if (shadow->m_shadowTexture[0] != lastShadowDecalTexture ||
  1158. shadow->m_type != lastShadowType)
  1159. { flushDecals(lastShadowDecalTexture,lastShadowType); //switched to a new texture, need to render polys using last texture.
  1160. lastShadowDecalTexture=shadow->m_shadowTexture[0];
  1161. lastShadowType=shadow->m_type;
  1162. }
  1163. ///@todo: may need to fix this if shadows are large enough to be seen while object is not visible
  1164. if (shadow->m_robj->Is_Really_Visible())
  1165. { //queueSimpleDecal(shadow);
  1166. queueDecal(shadow); //only draw shadow if casting object is visible
  1167. projectionCount++;
  1168. }
  1169. continue;
  1170. }
  1171. //First test if shadow is visible on screen
  1172. sphere=shadow->m_shadowTexture[0]->getBoundingSphere();
  1173. sphere.Center += shadow->m_robj->Get_Position();
  1174. CollisionMath::OverlapType result=CollisionMath::Overlap_Test(*shadowCameraFrustum,sphere);
  1175. if (result == CollisionMath::OVERLAPPED)
  1176. { //do a more accurate test against bounding box.
  1177. aaBox=shadow->m_shadowTexture[0]->getBoundingBox();
  1178. aaBox.Translate(shadow->m_robj->Get_Position()); //translate bounding box to world space.
  1179. if (CollisionMath::Overlap_Test(*shadowCameraFrustum,aaBox) == CollisionMath::OUTSIDE)
  1180. continue;
  1181. }
  1182. else
  1183. if (result == CollisionMath::OUTSIDE)
  1184. continue;
  1185. //Shadow is visible on screen. Figure out which visible objects it may affect.
  1186. //Check if bounding sphere was inside so bounding box never initialized
  1187. if (result == CollisionMath::INSIDE)
  1188. { aaBox=shadow->m_shadowTexture[0]->getBoundingBox();
  1189. aaBox.Translate(shadow->m_robj->Get_Position()); //translate bounding box to world space.
  1190. }
  1191. if (shadow->m_type == SHADOW_PROJECTION)
  1192. {
  1193. //build inverse camera/view transforms needed for projection
  1194. shadow->updateProjectionParameters(rinfo.Camera.Get_Transform());
  1195. TexProjectClass *projector=shadow->getShadowProjector();
  1196. //terrain is always visible and affected by all shadows so must render
  1197. projector->Peek_Material_Pass()->Install_Materials();
  1198. DX8Wrapper::Apply_Render_State_Changes(); //force update of view and projection matrices
  1199. if (renderProjectedTerrainShadow(shadow, aaBox))
  1200. projectionCount++;
  1201. projector->Peek_Material_Pass()->UnInstall_Materials();
  1202. SimpleObjectIterator *iter;
  1203. Object *obj;
  1204. iter = ThePartitionManager->iterateObjectsInRange((const Coord3D*)&sphere.Center,sphere.Radius, FROM_CENTER_3D);
  1205. MemoryPoolObjectHolder hold( iter );
  1206. AABoxIntersectionTestClass boxtest(aaBox,COLLISION_TYPE_ALL);
  1207. for( obj = iter->first(); obj; obj = iter->next() )
  1208. {
  1209. Drawable *draw = obj->getDrawable();
  1210. for (DrawModule ** dm = draw->getDrawModules(); *dm; ++dm)
  1211. {
  1212. const ObjectDrawInterface* di = (*dm)->getObjectDrawInterface();
  1213. if (di)
  1214. {
  1215. W3DModelDraw *w3dDraw= (W3DModelDraw *)di;
  1216. RenderObjClass *robj=NULL;
  1217. ///@todo: don't apply shadows to translcuent objects unless they are MOBILE - hack to get tanks to work.
  1218. if ((robj=w3dDraw->getRenderObject()) != 0 && (!robj->Is_Alpha() || !obj->isKindOf(KINDOF_IMMOBILE)) && robj != shadow->m_robj && robj->Is_Really_Visible())
  1219. {
  1220. //do a more accurate test against W3D render bounding boxes.
  1221. if (robj->Intersect_AABox(boxtest))
  1222. {
  1223. //Shadow reached a visible object so it needs to be rendered with shadow applied.
  1224. rinfo.Push_Material_Pass(projector->Peek_Material_Pass());
  1225. rinfo.Push_Override_Flags(RenderInfoClass::RINFO_OVERRIDE_ADDITIONAL_PASSES_ONLY);
  1226. robj->Render(rinfo); //WW3D::Render(*robj,rinfo);
  1227. rinfo.Pop_Override_Flags();
  1228. rinfo.Pop_Material_Pass();
  1229. projectionCount++; //keep track of number of shadow projections
  1230. }
  1231. }//robj
  1232. }//di
  1233. } // end for drawmodule
  1234. } // end for obj
  1235. }
  1236. }//shadow is enabled
  1237. }
  1238. flushDecals(lastShadowDecalTexture,lastShadowType); //make sure there are not any unrendered decals left over.
  1239. TheDX8MeshRenderer.Flush(); //draw all the shadow receiving objects
  1240. }//rendering shadows
  1241. if (m_decalList)
  1242. {
  1243. //keep track of active decal texture so we can render all decals at once.
  1244. W3DShadowTexture *lastShadowDecalTexture=NULL;
  1245. ShadowType lastShadowType = SHADOW_NONE;
  1246. for( shadow = m_decalList; shadow; shadow = shadow->m_next )
  1247. {
  1248. if (shadow->m_isEnabled && !shadow->m_isInvisibleEnabled)
  1249. {
  1250. if (lastShadowDecalTexture == NULL)
  1251. lastShadowDecalTexture=m_decalList->m_shadowTexture[0];
  1252. if (lastShadowType == SHADOW_NONE)
  1253. lastShadowType = m_decalList->m_type;
  1254. if (shadow->m_shadowTexture[0] != lastShadowDecalTexture ||
  1255. shadow->m_type != lastShadowType)
  1256. { flushDecals(lastShadowDecalTexture,lastShadowType); //switched to a new texture, need to render polys using last texture.
  1257. lastShadowDecalTexture=shadow->m_shadowTexture[0];
  1258. lastShadowType=shadow->m_type;
  1259. }
  1260. ///@todo: may need to fix this if shadows are large enough to be seen while object is not visible
  1261. if (!(shadow->m_robj && !shadow->m_robj->Is_Really_Visible()))
  1262. { //queueSimpleDecal(shadow);
  1263. queueDecal(shadow); //only draw shadow if casting object is visible
  1264. projectionCount++;
  1265. }
  1266. }//shadow is enabled
  1267. }
  1268. flushDecals(lastShadowDecalTexture,lastShadowType); //make sure there are not any unrendered decals left over.
  1269. }
  1270. return projectionCount;
  1271. }
  1272. /** Generic function which can be used to create arbitrary decals that don't have to be used for shadows.
  1273. Some examples: Scorch marks, blood, stains, selection/status indicators, etc.*/
  1274. Shadow* W3DProjectedShadowManager::addDecal(Shadow::ShadowTypeInfo *shadowInfo)
  1275. {
  1276. W3DShadowTexture *st=NULL;
  1277. ShadowType shadowType=SHADOW_NONE; /// type of projection
  1278. Bool allowWorldAlign=FALSE; /// wrap shadow around world geometry - else align perpendicular to local z-axis.
  1279. Real decalSizeX=0.0f;
  1280. Real decalSizeY=0.0f;
  1281. Bool allowSunDirection=FALSE;
  1282. Char texture_name[64];
  1283. Int nameLen;
  1284. if (!shadowInfo)
  1285. return NULL; //right now we require hardware render-to-texture support
  1286. //simple decal using the premade texture specified.
  1287. //can be always perpendicular to model's z-axis or projected
  1288. //onto world geometry.
  1289. nameLen=strlen(shadowInfo->m_ShadowName);
  1290. strncpy(texture_name,shadowInfo->m_ShadowName,nameLen);
  1291. strcpy(texture_name+nameLen,".tga"); //append texture extension
  1292. //Check if we previously added a decal using this texture
  1293. st=m_W3DShadowTextureManager->getTexture(texture_name);
  1294. if (st == NULL)
  1295. {
  1296. //Adding a new decal texture
  1297. TextureClass *w3dTexture=WW3DAssetManager::Get_Instance()->Get_Texture(texture_name);
  1298. w3dTexture->Set_U_Addr_Mode(TextureClass::TEXTURE_ADDRESS_CLAMP);
  1299. w3dTexture->Set_V_Addr_Mode(TextureClass::TEXTURE_ADDRESS_CLAMP);
  1300. w3dTexture->Set_Mip_Mapping(TextureClass::FILTER_TYPE_NONE);
  1301. DEBUG_ASSERTCRASH(w3dTexture != NULL, ("Could not load decal texture: %s\n",texture_name));
  1302. if (!w3dTexture)
  1303. return NULL;
  1304. st = NEW W3DShadowTexture; // poolify
  1305. SET_REF_OWNER( st );
  1306. st->Set_Name(texture_name);
  1307. m_W3DShadowTextureManager->addTexture( st );
  1308. st->setTexture(w3dTexture);
  1309. }
  1310. shadowType=shadowInfo->m_type;
  1311. allowWorldAlign=shadowInfo->allowWorldAlign;
  1312. allowSunDirection=shadowInfo->m_type & SHADOW_DIRECTIONAL_PROJECTION;
  1313. decalSizeX=shadowInfo->m_sizeX;
  1314. decalSizeY=shadowInfo->m_sizeY;
  1315. W3DProjectedShadow *shadow = NEW W3DProjectedShadow; // poolify
  1316. // sanity
  1317. if( shadow == NULL )
  1318. return NULL;
  1319. shadow->setRenderObject(NULL);
  1320. shadow->setTexture(0,st); ///@todo: Fix projected shadows to allow multiple lights
  1321. shadow->m_type = shadowType; /// type of projection
  1322. shadow->m_allowWorldAlign=allowWorldAlign; /// wrap shadow around world geometry - else align perpendicular to local z-axis.
  1323. shadow->m_oowDecalSizeX = 1.0f/decalSizeX; //one over width
  1324. shadow->m_oowDecalSizeY = 1.0f/decalSizeY; //one over height
  1325. //Prestore some values used during projection to optimize out division.
  1326. shadow->m_decalSizeX = decalSizeX; //width
  1327. shadow->m_decalSizeY = decalSizeY; //height
  1328. shadow->m_decalOffsetU=0;
  1329. shadow->m_decalOffsetV=0;
  1330. shadow->m_flags = allowSunDirection;
  1331. shadow->init();
  1332. // add to our shadow list through the shadow next links, insert next to other shadows using same texture
  1333. W3DProjectedShadow *nextShadow=NULL,*prevShadow=NULL;
  1334. for( nextShadow = m_decalList; nextShadow; prevShadow=nextShadow,nextShadow = nextShadow->m_next )
  1335. {
  1336. if (nextShadow->m_shadowTexture[0]==st)
  1337. { //found start of other shadows using same texture, insert new shadow here.
  1338. shadow->m_next=nextShadow;
  1339. if (prevShadow)
  1340. { prevShadow->m_next=shadow;
  1341. }
  1342. else
  1343. m_decalList=shadow;
  1344. break;
  1345. }
  1346. }
  1347. if (nextShadow==NULL)
  1348. { //shadow with new texture. Add to top of list.
  1349. shadow->m_next = m_decalList;
  1350. m_decalList = shadow;
  1351. }
  1352. switch (shadow->m_type)
  1353. {
  1354. case SHADOW_DECAL:
  1355. case SHADOW_ALPHA_DECAL:
  1356. case SHADOW_ADDITIVE_DECAL:
  1357. m_numDecalShadows++;
  1358. break;
  1359. case SHADOW_PROJECTION:
  1360. m_numProjectionShadows++;
  1361. default:
  1362. break;
  1363. }
  1364. return shadow;
  1365. }
  1366. /** Generic function which can be used to create arbitrary decals that follow the renderObject but don't have to be used for shadows.
  1367. Some examples: Scorch marks, blood, stains, selection/status indicators, etc.*/
  1368. Shadow* W3DProjectedShadowManager::addDecal(RenderObjClass *robj, Shadow::ShadowTypeInfo *shadowInfo)
  1369. {
  1370. W3DShadowTexture *st=NULL;
  1371. ShadowType shadowType=SHADOW_NONE; /// type of projection
  1372. Bool allowWorldAlign=FALSE; /// wrap shadow around world geometry - else align perpendicular to local z-axis.
  1373. Real decalSizeX=0.0f;
  1374. Real decalSizeY=0.0f;
  1375. Real decalOffsetX=0.0f;
  1376. Real decalOffsetY=0.0f;
  1377. Bool allowSunDirection=FALSE;
  1378. Char texture_name[64];
  1379. Int nameLen;
  1380. if (!robj || !shadowInfo)
  1381. return NULL; //right now we require hardware render-to-texture support
  1382. //simple decal using the premade texture specified.
  1383. //can be always perpendicular to model's z-axis or projected
  1384. //onto world geometry.
  1385. nameLen=strlen(shadowInfo->m_ShadowName);
  1386. strncpy(texture_name,shadowInfo->m_ShadowName,nameLen);
  1387. strcpy(texture_name+nameLen,".tga"); //append texture extension
  1388. //Check if we previously added a decal using this texture
  1389. st=m_W3DShadowTextureManager->getTexture(texture_name);
  1390. if (st == NULL)
  1391. {
  1392. //Adding a new decal texture
  1393. TextureClass *w3dTexture=WW3DAssetManager::Get_Instance()->Get_Texture(texture_name);
  1394. w3dTexture->Set_U_Addr_Mode(TextureClass::TEXTURE_ADDRESS_CLAMP);
  1395. w3dTexture->Set_V_Addr_Mode(TextureClass::TEXTURE_ADDRESS_CLAMP);
  1396. w3dTexture->Set_Mip_Mapping(TextureClass::FILTER_TYPE_NONE);
  1397. DEBUG_ASSERTCRASH(w3dTexture != NULL, ("Could not load decal texture: %s\n",texture_name));
  1398. if (!w3dTexture)
  1399. return NULL;
  1400. st = NEW W3DShadowTexture;
  1401. SET_REF_OWNER( st );
  1402. st->Set_Name(texture_name);
  1403. m_W3DShadowTextureManager->addTexture( st );
  1404. st->setTexture(w3dTexture);
  1405. }
  1406. shadowType=shadowInfo->m_type;
  1407. allowWorldAlign=shadowInfo->allowWorldAlign;
  1408. allowSunDirection=shadowInfo->m_type & SHADOW_DIRECTIONAL_PROJECTION;
  1409. decalSizeX=shadowInfo->m_sizeX;
  1410. decalSizeY=shadowInfo->m_sizeY;
  1411. decalOffsetX=shadowInfo->m_offsetX;
  1412. decalOffsetY=shadowInfo->m_offsetY;
  1413. W3DProjectedShadow *shadow = NEW W3DProjectedShadow;
  1414. // sanity
  1415. if( shadow == NULL )
  1416. return NULL;
  1417. shadow->setRenderObject(robj);
  1418. shadow->setTexture(0,st); ///@todo: Fix projected shadows to allow multiple lights
  1419. shadow->m_type = shadowType; /// type of projection
  1420. shadow->m_allowWorldAlign=allowWorldAlign; /// wrap shadow around world geometry - else align perpendicular to local z-axis.
  1421. AABoxClass box;
  1422. robj->Get_Obj_Space_Bounding_Box(box);
  1423. //Check if app is overriding any of the default texture stretch factors.
  1424. if (!decalSizeX)
  1425. decalSizeX=box.Extent.X*2.0f;//use bounding box to determine size
  1426. shadow->m_oowDecalSizeX = 1.0f/decalSizeX; //one over width
  1427. if (!decalSizeY)
  1428. decalSizeY=box.Extent.Y*2.0f;//world space distance to stretch full texture
  1429. shadow->m_oowDecalSizeY = 1.0f/decalSizeY; //one over height
  1430. if (decalOffsetX)
  1431. decalOffsetX=decalOffsetX*shadow->m_oowDecalSizeX;
  1432. if (decalOffsetY)
  1433. decalOffsetY=decalOffsetY*shadow->m_oowDecalSizeY;
  1434. //Prestore some values used during projection to optimize out division.
  1435. shadow->m_decalSizeX = decalSizeX; //width
  1436. shadow->m_decalSizeY = decalSizeY; //height
  1437. shadow->m_decalOffsetU= decalOffsetX;
  1438. shadow->m_decalOffsetV= decalOffsetY;
  1439. shadow->m_flags = allowSunDirection;
  1440. shadow->init();
  1441. // add to our shadow list through the shadow next links, insert next to other shadows using same texture
  1442. W3DProjectedShadow *nextShadow=NULL,*prevShadow=NULL;
  1443. for( nextShadow = m_decalList; nextShadow; prevShadow=nextShadow,nextShadow = nextShadow->m_next )
  1444. {
  1445. if (nextShadow->m_shadowTexture[0]==st)
  1446. { //found start of other shadows using same texture, insert new shadow here.
  1447. shadow->m_next=nextShadow;
  1448. if (prevShadow)
  1449. { prevShadow->m_next=shadow;
  1450. }
  1451. else
  1452. m_decalList=shadow;
  1453. break;
  1454. }
  1455. }
  1456. if (nextShadow==NULL)
  1457. { //shadow with new texture. Add to top of list.
  1458. shadow->m_next = m_decalList;
  1459. m_decalList = shadow;
  1460. }
  1461. switch (shadow->m_type)
  1462. {
  1463. case SHADOW_DECAL:
  1464. case SHADOW_ALPHA_DECAL:
  1465. case SHADOW_ADDITIVE_DECAL:
  1466. m_numDecalShadows++;
  1467. break;
  1468. case SHADOW_PROJECTION:
  1469. m_numProjectionShadows++;
  1470. default:
  1471. break;
  1472. }
  1473. return shadow;
  1474. }
  1475. W3DProjectedShadow* W3DProjectedShadowManager::addShadow(RenderObjClass *robj, Shadow::ShadowTypeInfo *shadowInfo, Drawable *draw)
  1476. {
  1477. W3DShadowTexture *st=NULL;
  1478. static char defaultDecalName[]={"shadow.tga"};
  1479. ShadowType shadowType=SHADOW_NONE; /// type of projection
  1480. Bool allowWorldAlign=FALSE; /// wrap shadow around world geometry - else align perpendicular to local z-axis.
  1481. Real decalSizeX=0.0f;
  1482. Real decalSizeY=0.0f;
  1483. Real decalOffsetX=0.0f;
  1484. Real decalOffsetY=0.0f;
  1485. Bool allowSunDirection=FALSE;
  1486. Char texture_name[64];
  1487. Int nameLen;
  1488. if (!m_dynamicRenderTarget || !robj || !TheGlobalData->m_useShadowDecals)
  1489. return NULL; //right now we require hardware render-to-texture support
  1490. if (shadowInfo)
  1491. {
  1492. //determine what kind of shadow is needed
  1493. if (shadowInfo->m_type==SHADOW_DECAL)
  1494. { //simple decal using the premade texture specified.
  1495. //can be always perpendicular to model's z-axis or projected
  1496. //onto world geometry.
  1497. nameLen=strlen(shadowInfo->m_ShadowName);
  1498. if (nameLen <= 1) //no texture name given, use same as object
  1499. { strcpy(texture_name,defaultDecalName);
  1500. }
  1501. else
  1502. { strncpy(texture_name,shadowInfo->m_ShadowName,nameLen);
  1503. strcpy(texture_name+nameLen,".tga"); //append texture extension
  1504. }
  1505. st=m_W3DShadowTextureManager->getTexture(texture_name);
  1506. if (st == NULL)
  1507. {
  1508. //need to add this texture without creating it from a real renderobject
  1509. TextureClass *w3dTexture=WW3DAssetManager::Get_Instance()->Get_Texture(texture_name);
  1510. w3dTexture->Set_U_Addr_Mode(TextureClass::TEXTURE_ADDRESS_CLAMP);
  1511. w3dTexture->Set_V_Addr_Mode(TextureClass::TEXTURE_ADDRESS_CLAMP);
  1512. w3dTexture->Set_Mip_Mapping(TextureClass::FILTER_TYPE_NONE);
  1513. DEBUG_ASSERTCRASH(w3dTexture != NULL, ("Could not load decal texture"));
  1514. if (!w3dTexture)
  1515. return NULL;
  1516. st = NEW W3DShadowTexture; // poolify
  1517. SET_REF_OWNER( st );
  1518. st->Set_Name(texture_name);
  1519. m_W3DShadowTextureManager->addTexture( st );
  1520. st->setTexture(w3dTexture);
  1521. }
  1522. shadowType=SHADOW_DECAL;
  1523. allowSunDirection=shadowInfo->m_type & SHADOW_DIRECTIONAL_PROJECTION;
  1524. decalSizeX=shadowInfo->m_sizeX;
  1525. decalSizeY=shadowInfo->m_sizeY;
  1526. decalOffsetX=shadowInfo->m_offsetX;
  1527. decalOffsetY=shadowInfo->m_offsetY;
  1528. }
  1529. else
  1530. if (shadowInfo->m_type==SHADOW_PROJECTION)
  1531. { //projection of object geometry into a texture.
  1532. //can be applied on a plane horizontal to model's z-axis or
  1533. //projected onto world geometry.
  1534. if (shadowInfo->m_ShadowName[0] != '\0')
  1535. { //the shadow will be based on another render object
  1536. //to allow multiple models to share same shadow - for
  1537. //example, all trees could use same shadow even if slightly
  1538. //different color, etc.
  1539. strcpy(texture_name,shadowInfo->m_ShadowName);
  1540. }
  1541. else
  1542. strcpy(texture_name,robj->Get_Name()); //not texture name give, assume model name.
  1543. st=m_W3DShadowTextureManager->getTexture(texture_name);
  1544. if (st == NULL)
  1545. { //texture doesn't exist, use current render object to create it
  1546. m_W3DShadowTextureManager->createTexture(robj,texture_name);
  1547. //try loading again
  1548. st=m_W3DShadowTextureManager->getTexture(texture_name);
  1549. DEBUG_ASSERTCRASH(st != NULL, ("Could not create shadow texture"));
  1550. if (st==NULL)
  1551. return NULL; //could not create the shadow texture
  1552. }
  1553. shadowType=SHADOW_PROJECTION;
  1554. }//SHADOW_PROJECTION
  1555. }
  1556. else
  1557. { //no shadow info, assume user wants a projected shadow
  1558. strcpy(texture_name,robj->Get_Name());
  1559. st=m_W3DShadowTextureManager->getTexture(texture_name);
  1560. if (st==NULL)
  1561. { //did not find a cached copy of the shadow geometry, create a new one
  1562. m_W3DShadowTextureManager->createTexture(robj,texture_name);
  1563. //try loading again
  1564. st=m_W3DShadowTextureManager->getTexture(texture_name);
  1565. if (st==NULL)
  1566. return NULL; //could not create the shadow texture
  1567. }
  1568. shadowType=SHADOW_PROJECTION;
  1569. }
  1570. W3DProjectedShadow *shadow = NEW W3DProjectedShadow;
  1571. // sanity
  1572. if( shadow == NULL )
  1573. return NULL;
  1574. shadow->setRenderObject(robj);
  1575. shadow->setTexture(0,st); ///@todo: Fix projected shadows to allow multiple lights
  1576. shadow->m_type = shadowType; /// type of projection
  1577. shadow->m_allowWorldAlign=allowWorldAlign; /// wrap shadow around world geometry - else align perpendicular to local z-axis.
  1578. AABoxClass box;
  1579. robj->Get_Obj_Space_Bounding_Box(box);
  1580. //Check if app is overriding any of the default texture stretch factors.
  1581. if (decalSizeX)
  1582. decalSizeX=1.0f/decalSizeX; //world space distance to stretch full texture scale
  1583. else
  1584. decalSizeX=1.0f/(box.Extent.X*2.0f);//use bounding box to determine size
  1585. if (decalSizeY)
  1586. decalSizeY=-1.0f/decalSizeY;
  1587. else
  1588. decalSizeY=-1.0f/(box.Extent.Y*2.0f);//world space distance to stretch full texture
  1589. if (decalOffsetX)
  1590. decalOffsetX=-decalOffsetX*decalSizeX;
  1591. else
  1592. decalOffsetX=0.0f;//-box.Center.X*decalSizeX;
  1593. if (decalOffsetY)
  1594. decalOffsetY=-decalOffsetY*decalSizeY;
  1595. else
  1596. decalOffsetY=0.0f;//-box.Center.Y*decalSizeY;
  1597. //Prestore some values used during projection to optimize out division.
  1598. shadow->m_oowDecalSizeX = decalSizeX; //one over width
  1599. shadow->m_oowDecalSizeY = decalSizeY; //one over height
  1600. shadow->m_decalSizeX = 1.0f/decalSizeX; //width
  1601. shadow->m_decalSizeY = 1.0f/decalSizeY; //height
  1602. shadow->m_decalOffsetU= decalOffsetX;
  1603. shadow->m_decalOffsetV= decalOffsetY;
  1604. shadow->m_flags = allowSunDirection;
  1605. shadow->init();
  1606. // add to our shadow list through the shadow next links, insert next to other shadows using same texture
  1607. W3DProjectedShadow *nextShadow=NULL,*prevShadow=NULL;
  1608. for( nextShadow = m_shadowList; nextShadow; prevShadow=nextShadow,nextShadow = nextShadow->m_next )
  1609. {
  1610. if (nextShadow->m_shadowTexture[0]==st)
  1611. { //found start of other shadows using same texture, insert new shadow here.
  1612. shadow->m_next=nextShadow;
  1613. if (prevShadow)
  1614. { prevShadow->m_next=shadow;
  1615. }
  1616. else
  1617. m_shadowList=shadow;
  1618. break;
  1619. }
  1620. }
  1621. if (nextShadow==NULL)
  1622. { //shadow with new texture. Add to top of list.
  1623. shadow->m_next = m_shadowList;
  1624. m_shadowList = shadow;
  1625. }
  1626. switch (shadow->m_type)
  1627. {
  1628. case SHADOW_DECAL:
  1629. m_numDecalShadows++;
  1630. break;
  1631. case SHADOW_PROJECTION:
  1632. m_numProjectionShadows++;
  1633. default:
  1634. break;
  1635. }
  1636. return shadow;
  1637. }
  1638. void W3DProjectedShadowManager::removeShadow (W3DProjectedShadow *shadow)
  1639. {
  1640. W3DProjectedShadow *prev_shadow=NULL;
  1641. W3DProjectedShadow *next_shadow=NULL;
  1642. if (shadow->m_type & (SHADOW_ALPHA_DECAL|SHADOW_ADDITIVE_DECAL))
  1643. {
  1644. for( next_shadow = m_decalList; next_shadow; prev_shadow=next_shadow, next_shadow = next_shadow->m_next )
  1645. {
  1646. if (next_shadow == shadow)
  1647. {
  1648. if (prev_shadow)
  1649. prev_shadow->m_next=shadow->m_next;
  1650. else
  1651. m_decalList=shadow->m_next;
  1652. switch (shadow->m_type)
  1653. {
  1654. case SHADOW_DECAL:
  1655. m_numDecalShadows--;
  1656. break;
  1657. case SHADOW_PROJECTION:
  1658. m_numProjectionShadows--;
  1659. default:
  1660. break;
  1661. }
  1662. delete shadow;
  1663. return;
  1664. }
  1665. } // end for
  1666. }
  1667. //search for this shadow
  1668. for( next_shadow = m_shadowList; next_shadow; prev_shadow=next_shadow, next_shadow = next_shadow->m_next )
  1669. {
  1670. if (next_shadow == shadow)
  1671. {
  1672. if (prev_shadow)
  1673. prev_shadow->m_next=shadow->m_next;
  1674. else
  1675. m_shadowList=shadow->m_next;
  1676. switch (shadow->m_type)
  1677. {
  1678. case SHADOW_DECAL:
  1679. m_numDecalShadows--;
  1680. break;
  1681. case SHADOW_PROJECTION:
  1682. m_numProjectionShadows--;
  1683. default:
  1684. break;
  1685. }
  1686. delete shadow;
  1687. return;
  1688. }
  1689. } // end for
  1690. }
  1691. void W3DProjectedShadowManager::removeAllShadows(void)
  1692. {
  1693. W3DProjectedShadow *cur_shadow=NULL;
  1694. W3DProjectedShadow *next_shadow=m_shadowList;
  1695. m_shadowList = NULL;
  1696. m_numDecalShadows = 0;
  1697. m_numProjectionShadows = 0;
  1698. //search for this shadow
  1699. for( cur_shadow = next_shadow; cur_shadow; cur_shadow = next_shadow )
  1700. {
  1701. next_shadow = cur_shadow->m_next;
  1702. cur_shadow->m_next = NULL;
  1703. delete cur_shadow;
  1704. } // end for
  1705. next_shadow=m_decalList;
  1706. cur_shadow=NULL;
  1707. m_decalList=NULL;
  1708. for( cur_shadow = next_shadow; cur_shadow; cur_shadow = next_shadow )
  1709. {
  1710. next_shadow = cur_shadow->m_next;
  1711. cur_shadow->m_next = NULL;
  1712. delete cur_shadow;
  1713. } // end for
  1714. }
  1715. #if defined(_DEBUG) || defined(_INTERNAL)
  1716. void W3DProjectedShadow::getRenderCost(RenderCost & rc) const
  1717. {
  1718. if (TheGlobalData->m_useShadowDecals && m_isEnabled && !m_isInvisibleEnabled)
  1719. rc.addShadowDrawCalls(1);
  1720. }
  1721. #endif
  1722. W3DProjectedShadow::W3DProjectedShadow(void)
  1723. {
  1724. m_diffuse=0xffffffff;
  1725. m_shadowProjector=NULL;
  1726. m_lastObjPosition.Set(0,0,0);
  1727. m_type = SHADOW_NONE; /// type of projection
  1728. m_allowWorldAlign = FALSE; /// wrap shadow around world geometry - else align perpendicular to local z-axis.
  1729. m_isEnabled = TRUE;
  1730. m_isInvisibleEnabled = FALSE;
  1731. for (Int i=0; i<MAX_SHADOW_LIGHTS; i++)
  1732. m_shadowTexture[i]=NULL;
  1733. }
  1734. W3DProjectedShadow::~W3DProjectedShadow(void)
  1735. {
  1736. REF_PTR_RELEASE(m_shadowProjector);
  1737. for (Int i=0; i<MAX_SHADOW_LIGHTS; i++)
  1738. REF_PTR_RELEASE(m_shadowTexture[i]);
  1739. }
  1740. void W3DProjectedShadow::init(void)
  1741. {
  1742. DEBUG_ASSERTCRASH(m_shadowProjector == NULL, ("Init of existing shadow projector"));
  1743. if (m_type == SHADOW_PROJECTION)
  1744. {
  1745. m_shadowProjector = NEW_REF(TexProjectClass,());
  1746. m_shadowProjector->Set_Intensity(0.4f,true);
  1747. m_shadowProjector->Set_Texture(m_shadowTexture[0]->getTexture());
  1748. }
  1749. }
  1750. #define DECAL_TEXELS_PER_WORLD_UNIT (64.0f/20.0f) //64 texels per 2 terrain cells (20 units)
  1751. void W3DProjectedShadow::updateTexture(Vector3 &lightPos)
  1752. {
  1753. SpecialRenderInfoClass *context;
  1754. //default uv coordinates before rotation starting at top/left going clockwise
  1755. static Vector2 uvData[4]={Vector2(-0.5,-0.5f),Vector2(-0.5,0.5f),Vector2(0.5f,0.5f),Vector2(-0.5f,0.5f)};
  1756. //force light always 2000 units from object - for some reason projection fails if
  1757. //light is too far.
  1758. ///@todo: See why infinite light sources don't project shadows correctly.
  1759. if (m_type == SHADOW_PROJECTION)
  1760. { //projected shadows use custom runtime generated textures based on object geometry
  1761. Vector3 objPos=m_robj->Get_Position();
  1762. if (objPos == Vector3(0,0,0))
  1763. return; //render object does not have a valid position (never rendered).
  1764. Vector3 objToLight=lightPos - objPos;
  1765. objToLight.Normalize();
  1766. objToLight = objPos + objToLight * 2000.0f;
  1767. m_shadowProjector->Compute_Perspective_Projection(m_robj,objToLight);
  1768. m_shadowProjector->Set_Render_Target(TheW3DProjectedShadowManager->getRenderTarget());
  1769. //Set ambient to 0, so we get a black shadow on solid backgroud
  1770. context=TheW3DProjectedShadowManager->getRenderContext();
  1771. context->light_environment->Reset(m_robj->Get_Position(), Vector3(0,0,0));
  1772. m_shadowProjector->Compute_Texture(m_robj,context);
  1773. //Need to copy generated texture into permanent texture.
  1774. SurfaceClass *oldSurface=m_shadowTexture[0]->getTexture()->Get_Surface_Level();
  1775. SurfaceClass *newSurface=TheW3DProjectedShadowManager->getRenderTarget()->Get_Surface_Level();
  1776. //Copy shadow from temporary video-memory surface into a permanent texture
  1777. oldSurface->Copy(0,0,0,0,DEFAULT_RENDER_TARGET_WIDTH,DEFAULT_RENDER_TARGET_HEIGHT,newSurface);
  1778. REF_PTR_RELEASE(newSurface);
  1779. REF_PTR_RELEASE(oldSurface);
  1780. m_shadowTexture[0]->updateBounds(TheW3DShadowManager->getLightPosWorld(0),m_robj); //update local shadow bounds
  1781. }
  1782. else
  1783. if (m_type == SHADOW_DECAL)
  1784. { //decal shadows use artist supplied textures. We just need to tweak the uv coordinates to match
  1785. //the light direction.
  1786. Vector3 objPos=m_robj->Get_Position();
  1787. Vector3 objectToLight;
  1788. if (m_flags & SHADOW_DIRECTIONAL_PROJECTION)
  1789. { objectToLight=lightPos-objPos;
  1790. //we're ignoring sun's distance from horizon, so drop vertical component
  1791. objectToLight.Z=0;
  1792. objectToLight.Normalize();
  1793. }
  1794. else
  1795. objectToLight.Set(1.0f,0.0f,0.0f);
  1796. SurfaceClass::SurfaceDescription surface_desc;
  1797. m_shadowTexture[0]->getTexture()->Get_Level_Description(surface_desc);
  1798. //default shadow texture points along world -x axis (west). Rotate uv coordinates to fit actual light direction
  1799. Vector3 uVec = objectToLight * DECAL_TEXELS_PER_WORLD_UNIT / (float)surface_desc.Width;
  1800. objectToLight.Rotate_Z(-1.0f,0.0f); //rotate u vector by -90 degress to get v vector.
  1801. Vector3 vVec = objectToLight * DECAL_TEXELS_PER_WORLD_UNIT / (float)surface_desc.Height;
  1802. m_shadowTexture[0]->setDecalUVAxis(uVec, vVec);
  1803. ///@todo: tweak decal bounding volumes to something sensible
  1804. AABoxClass box;
  1805. SphereClass sphere;
  1806. m_robj->Get_Obj_Space_Bounding_Box(box); //shadow uses same bounding box as object
  1807. m_robj->Get_Obj_Space_Bounding_Sphere(sphere);
  1808. m_shadowTexture[0]->setBoundingSphere(sphere);
  1809. m_shadowTexture[0]->setBoundingBox(box);
  1810. }
  1811. m_shadowTexture[0]->setLightPosHistory(lightPos); //store position of light at time of texture update.
  1812. }
  1813. void W3DProjectedShadow::updateProjectionParameters(const Matrix3D &cameraXform)
  1814. {
  1815. m_shadowProjector->Pre_Render_Update(cameraXform);
  1816. }
  1817. void W3DProjectedShadow::update(void)
  1818. {
  1819. if (m_shadowTexture[0]->getLightPosHistory() != TheW3DShadowManager->getLightPosWorld(0))
  1820. { //light has moved since last time this shadow was calculated. Need update
  1821. updateTexture(TheW3DShadowManager->getLightPosWorld(0));
  1822. }
  1823. if (m_lastObjPosition != m_robj->Get_Position())
  1824. { //object has moved. Texture stays the same but projection matrix needs updating.
  1825. //force light always 2000 units from object - for some reason projection fails if
  1826. //light is too far.
  1827. ///@todo: See why infinite light sources don't project shadows correctly.
  1828. if (m_type == SHADOW_PROJECTION)
  1829. {
  1830. Vector3 objToLight=TheW3DShadowManager->getLightPosWorld(0) - m_robj->Get_Position();
  1831. objToLight.Normalize();
  1832. objToLight = m_robj->Get_Position() + objToLight * 2000.0f;
  1833. m_shadowProjector->Compute_Perspective_Projection(m_robj,objToLight);
  1834. }
  1835. setObjPosHistory(m_robj->Get_Position());
  1836. }
  1837. }
  1838. Int W3DShadowTexture::init(RenderObjClass *robj)
  1839. {
  1840. ///@todo: implement this function
  1841. SurfaceClass::SurfaceDescription surface_desc;
  1842. TheW3DProjectedShadowManager->getRenderTarget()->Get_Level_Description(surface_desc);
  1843. TextureClass *new_texture = MSGNEW("TextureClass") TextureClass(surface_desc.Width,surface_desc.Height,surface_desc.Format,TextureClass::MIP_LEVELS_1);
  1844. setTexture(new_texture);
  1845. return TRUE;
  1846. }
  1847. void W3DShadowTexture::updateBounds(Vector3 &lightPos, RenderObjClass *robj)
  1848. {
  1849. AABoxClass &box=m_areaEffectBox; ///@todo: fix for multiple lights
  1850. Vector3 objPos;
  1851. Vector3 Corners[8];
  1852. Vector3 lightRay;
  1853. Real floorZ;
  1854. Real vectorScale,vectorScaleTemp, vectorScaleMax,length;
  1855. //calculate local bounding box of shadow projection
  1856. objPos=robj->Get_Position();
  1857. box=robj->Get_Bounding_Box();
  1858. floorZ = objPos.Z - 2.0f; //lower slightly so shadows go under ground.
  1859. //project each box corner to base of object to determine rough extent of shadow
  1860. //Get vertices of top of bounding box
  1861. Corners[0]=box.Center+box.Extent; //top right corner
  1862. Corners[1]=Corners[0];
  1863. Corners[1].X -= 2.0f*box.Extent.X; //top left corner
  1864. Corners[2]=Corners[1];
  1865. Corners[2].Y -= 2.0f*box.Extent.Y; //bottom left corner
  1866. Corners[3]=Corners[2];
  1867. Corners[3].X += 2.0f*box.Extent.X; //bottom right corner
  1868. //Project top volume corners onto ground plane
  1869. lightRay = Corners[0] - lightPos; //vector light to corner
  1870. length= 1.0f/lightRay.Length();
  1871. lightRay *= length;
  1872. vectorScaleMax=vectorScale=(Real)fabs((Corners[0].Z-floorZ)/lightRay.Z); //length of vector from top corner to ground.
  1873. Corners[4]=Corners[0]+lightRay*vectorScale;
  1874. vectorScaleMax *= length;
  1875. lightRay = Corners[1] - lightPos; //vector light to corner
  1876. length= 1.0f/lightRay.Length();
  1877. lightRay *= length;
  1878. vectorScaleTemp=(Real)fabs((Corners[1].Z-floorZ)/lightRay.Z); //length of vector from top corner to ground.
  1879. Corners[5]=Corners[1]+lightRay*vectorScaleTemp;
  1880. vectorScaleTemp *= length;
  1881. if (vectorScaleTemp > vectorScaleMax)
  1882. vectorScaleMax=vectorScaleTemp; //keep track of maximum required extrusion length.
  1883. lightRay = Corners[2] - lightPos; //vector light to corner
  1884. length= 1.0f/lightRay.Length();
  1885. lightRay *= length;
  1886. vectorScale=(Real)fabs((Corners[2].Z-floorZ)/lightRay.Z); //length of vector from top corner to ground.
  1887. Corners[6]=Corners[2]+lightRay*vectorScale;
  1888. vectorScale *= length;
  1889. if (vectorScale > vectorScaleMax)
  1890. vectorScaleMax=vectorScale; //keep track of maximum required extrusion length.
  1891. lightRay = Corners[3] - lightPos; //vector light to corner
  1892. length= 1.0f/lightRay.Length();
  1893. lightRay *= length;
  1894. vectorScaleTemp=(Real)fabs((Corners[3].Z-floorZ)/lightRay.Z); //length of vector from top corner to ground.
  1895. Corners[7]=Corners[3]+lightRay*vectorScaleTemp;
  1896. vectorScaleTemp *= length;
  1897. if (vectorScaleTemp > vectorScaleMax)
  1898. vectorScaleMax=vectorScaleTemp; //keep track of maximum required extrusion length.
  1899. box.Init(Corners, 8); //generate a new bounding box to fit the shadow projection
  1900. m_areaEffectSphere.Init(box.Center,box.Extent.Length());
  1901. m_areaEffectSphere.Center -= objPos; //translate sphere to object space.
  1902. box.Translate(-objPos); //translate box to object space.
  1903. }
  1904. W3DShadowTextureManager::W3DShadowTextureManager(void)
  1905. {
  1906. // Create the hash tables
  1907. texturePtrTable = NEW HashTableClass( 2048 );
  1908. missingTextureTable = NEW HashTableClass( 2048 );
  1909. }
  1910. W3DShadowTextureManager::~W3DShadowTextureManager(void)
  1911. {
  1912. freeAllTextures();
  1913. delete texturePtrTable;
  1914. texturePtrTable = NULL;
  1915. delete missingTextureTable;
  1916. missingTextureTable = NULL;
  1917. }
  1918. /** Release all loaded textures */
  1919. void W3DShadowTextureManager::freeAllTextures(void)
  1920. {
  1921. // Make an iterator, and release all ptrs
  1922. W3DShadowTextureManagerIterator it( *this );
  1923. for( it.First(); !it.Is_Done(); it.Next() ) {
  1924. W3DShadowTexture *text = it.getCurrentTexture();
  1925. text->Release_Ref();
  1926. }
  1927. // Then clear the table
  1928. texturePtrTable->Reset();
  1929. }
  1930. /** Find texture in cache */
  1931. W3DShadowTexture * W3DShadowTextureManager::peekTexture(const char * name)
  1932. {
  1933. return (W3DShadowTexture*)texturePtrTable->Find( name );
  1934. }
  1935. /** Get texture from cache and increment its reference count */
  1936. W3DShadowTexture * W3DShadowTextureManager::getTexture(const char * name)
  1937. {
  1938. W3DShadowTexture * text = peekTexture( name );
  1939. if ( text != NULL ) {
  1940. text->Add_Ref();
  1941. }
  1942. return text;
  1943. }
  1944. /** Add texture to cache */
  1945. Bool W3DShadowTextureManager::addTexture(W3DShadowTexture *newTexture)
  1946. {
  1947. WWASSERT (newTexture != NULL);
  1948. // Increment the refcount on the new texture and add it to our table.
  1949. newTexture->Add_Ref ();
  1950. texturePtrTable->Add( newTexture );
  1951. return true;
  1952. }
  1953. void W3DShadowTextureManager::invalidateCachedLightPositions(void)
  1954. {
  1955. // step through each of our shadow textures and update previous light position.
  1956. Vector3 idVec(0,0,0);
  1957. W3DShadowTextureManagerIterator it( *this );
  1958. for( it.First(); !it.Is_Done(); it.Next() )
  1959. {
  1960. W3DShadowTexture *text = it.getCurrentTexture();
  1961. text->setLightPosHistory(idVec);
  1962. }
  1963. }
  1964. /*
  1965. ** An entry for a table of textures not found, so we can quickly determine their loss
  1966. */
  1967. class MissingTextureClass : public HashableClass {
  1968. public:
  1969. MissingTextureClass( const char * name ) : Name( name ) {}
  1970. virtual ~MissingTextureClass( void ) {}
  1971. virtual const char * Get_Key( void ) { return Name; }
  1972. private:
  1973. StringClass Name;
  1974. };
  1975. /*
  1976. ** Missing Textures
  1977. **
  1978. ** The idea here, allow the system to register which textures are determined to be missing
  1979. ** so that if they are asked for again, we can quickly return NULL, without searching again.
  1980. */
  1981. void W3DShadowTextureManager::registerMissing( const char * name )
  1982. {
  1983. missingTextureTable->Add( NEW MissingTextureClass( name ) );
  1984. }
  1985. Bool W3DShadowTextureManager::isMissing( const char * name )
  1986. {
  1987. return ( missingTextureTable->Find( name ) != NULL );
  1988. }
  1989. /** Create shadow geometry from a reference W3D RenderObject*/
  1990. int W3DShadowTextureManager::createTexture(RenderObjClass *robj, const char *name)
  1991. {
  1992. Bool res=FALSE;
  1993. W3DShadowTexture * newTexture = NEW W3DShadowTexture;
  1994. if (newTexture == NULL) {
  1995. goto Error;
  1996. }
  1997. SET_REF_OWNER( newTexture );
  1998. newTexture->Set_Name(name);
  1999. res=newTexture->init(robj);
  2000. if (res != TRUE)
  2001. { // load failed!
  2002. newTexture->Release_Ref();
  2003. goto Error;
  2004. } else if (peekTexture(newTexture->Get_Name()) != NULL)
  2005. { // duplicate exists!
  2006. newTexture->Release_Ref(); // Release the one we just loaded
  2007. goto Error;
  2008. } else
  2009. { addTexture( newTexture );
  2010. newTexture->Release_Ref();
  2011. }
  2012. return 0;
  2013. Error:
  2014. return 1;
  2015. }