W3DProjectedShadow.cpp 83 KB

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