dx8wrapper.cpp 78 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655
  1. /*
  2. ** Command & Conquer Generals(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : WW3D *
  23. * *
  24. * $Archive:: /VSS_Sync/ww3d2/dx8wrapper.cpp $*
  25. * *
  26. * Original Author:: Jani Penttinen *
  27. * *
  28. * $Author:: Vss_sync $*
  29. * *
  30. * $Modtime:: 8/29/01 7:29p $*
  31. * *
  32. * $Revision:: 134 $*
  33. * *
  34. *---------------------------------------------------------------------------------------------*
  35. * Functions: *
  36. * DX8Wrapper::_Update_Texture -- Copies a texture from system memory to video memory *
  37. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  38. //#define CREATE_DX8_MULTI_THREADED
  39. #include "dx8wrapper.h"
  40. #include "dx8fvf.h"
  41. #include "dx8vertexbuffer.h"
  42. #include "dx8indexbuffer.h"
  43. #include "dx8renderer.h"
  44. #include "ww3d.h"
  45. #include "camera.h"
  46. #include "wwstring.h"
  47. #include "matrix4.h"
  48. #include "vertmaterial.h"
  49. #include "rddesc.h"
  50. #include "lightenvironment.h"
  51. #include "statistics.h"
  52. #include "registry.h"
  53. #include "boxrobj.h"
  54. #include "pointgr.h"
  55. #include "render2d.h"
  56. #include "sortingrenderer.h"
  57. #include "shattersystem.h"
  58. #include "light.h"
  59. #include "assetmgr.h"
  60. #include "textureloader.h"
  61. #include "missingtexture.h"
  62. #include "thread.h"
  63. #include <stdio.h>
  64. #include <D3dx8core.h>
  65. #include "pot.h"
  66. #include "wwprofile.h"
  67. #include "ffactory.h"
  68. #include "dx8caps.h"
  69. #include "formconv.h"
  70. #include "dx8texman.h"
  71. #include "bound.h"
  72. #include "dx8webbrowser.h"
  73. #define WW3D_DEVTYPE D3DDEVTYPE_HAL
  74. const int DEFAULT_RESOLUTION_WIDTH = 640;
  75. const int DEFAULT_RESOLUTION_HEIGHT = 480;
  76. const int DEFAULT_BIT_DEPTH = 32;
  77. const int DEFAULT_TEXTURE_BIT_DEPTH = 16;
  78. bool DX8Wrapper_IsWindowed = true;
  79. // FPU_PRESERVE
  80. int DX8Wrapper_PreserveFPU = 0;
  81. /***********************************************************************************
  82. **
  83. ** DX8Wrapper Static Variables
  84. **
  85. ***********************************************************************************/
  86. static HWND _Hwnd = NULL;
  87. bool DX8Wrapper::IsInitted = false;
  88. bool DX8Wrapper::_EnableTriangleDraw = true;
  89. int DX8Wrapper::CurRenderDevice = -1;
  90. int DX8Wrapper::ResolutionWidth = DEFAULT_RESOLUTION_WIDTH;
  91. int DX8Wrapper::ResolutionHeight = DEFAULT_RESOLUTION_HEIGHT;
  92. int DX8Wrapper::BitDepth = DEFAULT_BIT_DEPTH;
  93. int DX8Wrapper::TextureBitDepth = DEFAULT_TEXTURE_BIT_DEPTH;
  94. bool DX8Wrapper::IsWindowed = false;
  95. D3DFORMAT DX8Wrapper::DisplayFormat = D3DFMT_UNKNOWN;
  96. D3DMATRIX DX8Wrapper::old_world;
  97. D3DMATRIX DX8Wrapper::old_view;
  98. D3DMATRIX DX8Wrapper::old_prj;
  99. bool DX8Wrapper::world_identity;
  100. unsigned DX8Wrapper::RenderStates[256];
  101. unsigned DX8Wrapper::TextureStageStates[MAX_TEXTURE_STAGES][32];
  102. IDirect3DBaseTexture8 * DX8Wrapper::Textures[MAX_TEXTURE_STAGES];
  103. RenderStateStruct DX8Wrapper::render_state;
  104. unsigned DX8Wrapper::render_state_changed;
  105. bool DX8Wrapper::FogEnable = false;
  106. D3DCOLOR DX8Wrapper::FogColor = 0;
  107. IDirect3D8 * DX8Wrapper::D3DInterface = NULL;
  108. IDirect3DDevice8 * DX8Wrapper::D3DDevice = NULL;
  109. IDirect3DSurface8 * DX8Wrapper::CurrentRenderTarget = NULL;
  110. IDirect3DSurface8 * DX8Wrapper::DefaultRenderTarget = NULL;
  111. unsigned DX8Wrapper::matrix_changes = 0;
  112. unsigned DX8Wrapper::material_changes = 0;
  113. unsigned DX8Wrapper::vertex_buffer_changes = 0;
  114. unsigned DX8Wrapper::index_buffer_changes = 0;
  115. unsigned DX8Wrapper::light_changes = 0;
  116. unsigned DX8Wrapper::texture_changes = 0;
  117. unsigned DX8Wrapper::render_state_changes = 0;
  118. unsigned DX8Wrapper::texture_stage_state_changes = 0;
  119. unsigned DX8Wrapper::_MainThreadID = 0;
  120. bool DX8Wrapper::CurrentDX8LightEnables[4];
  121. D3DADAPTER_IDENTIFIER8 DX8Wrapper::CurrentAdapterIdentifier;
  122. unsigned long DX8Wrapper::FrameCount = 0;
  123. bool _DX8SingleThreaded = false;
  124. unsigned number_of_DX8_calls = 0;
  125. static unsigned last_frame_matrix_changes = 0;
  126. static unsigned last_frame_material_changes = 0;
  127. static unsigned last_frame_vertex_buffer_changes = 0;
  128. static unsigned last_frame_index_buffer_changes = 0;
  129. static unsigned last_frame_light_changes = 0;
  130. static unsigned last_frame_texture_changes = 0;
  131. static unsigned last_frame_render_state_changes = 0;
  132. static unsigned last_frame_texture_stage_state_changes = 0;
  133. static unsigned last_frame_number_of_DX8_calls = 0;
  134. static D3DPRESENT_PARAMETERS _PresentParameters;
  135. static DynamicVectorClass<StringClass> _RenderDeviceNameTable;
  136. static DynamicVectorClass<StringClass> _RenderDeviceShortNameTable;
  137. static DynamicVectorClass<RenderDeviceDescClass> _RenderDeviceDescriptionTable;
  138. /*
  139. ** Registry value names
  140. */
  141. #define VALUE_NAME_RENDER_DEVICE_NAME "RenderDeviceName"
  142. #define VALUE_NAME_RENDER_DEVICE_WIDTH "RenderDeviceWidth"
  143. #define VALUE_NAME_RENDER_DEVICE_HEIGHT "RenderDeviceHeight"
  144. #define VALUE_NAME_RENDER_DEVICE_DEPTH "RenderDeviceDepth"
  145. #define VALUE_NAME_RENDER_DEVICE_WINDOWED "RenderDeviceWindowed"
  146. #define VALUE_NAME_RENDER_DEVICE_TEXTURE_DEPTH "RenderDeviceTextureDepth"
  147. DX8_CleanupHook *DX8Wrapper::m_pCleanupHook=NULL;
  148. #ifdef EXTENDED_STATS
  149. DX8_Stats DX8Wrapper::stats;
  150. #endif
  151. /***********************************************************************************
  152. **
  153. ** DX8Wrapper Implementation
  154. **
  155. ***********************************************************************************/
  156. void Log_DX8_ErrorCode(unsigned res)
  157. {
  158. char tmp[256]="";
  159. HRESULT new_res=D3DXGetErrorStringA(
  160. res,
  161. tmp,
  162. sizeof(tmp));
  163. if (new_res==D3D_OK) {
  164. WWDEBUG_SAY((tmp));
  165. }
  166. WWASSERT(0);
  167. }
  168. void Non_Fatal_Log_DX8_ErrorCode(unsigned res,const char * file,int line)
  169. {
  170. char tmp[256]="";
  171. HRESULT new_res=D3DXGetErrorStringA(
  172. res,
  173. tmp,
  174. sizeof(tmp));
  175. if (new_res==D3D_OK) {
  176. WWDEBUG_SAY(("DX8 Error: %s, File: %s, Line: %d\n",tmp,file,line));
  177. }
  178. }
  179. bool DX8Wrapper::Init(void * hwnd)
  180. {
  181. WWASSERT(!IsInitted);
  182. /*
  183. ** Initialize all variables!
  184. */
  185. _Hwnd = (HWND)hwnd;
  186. _MainThreadID=ThreadClass::_Get_Current_Thread_ID();
  187. CurRenderDevice = -1;
  188. ResolutionWidth = DEFAULT_RESOLUTION_WIDTH;
  189. ResolutionHeight = DEFAULT_RESOLUTION_HEIGHT;
  190. // Initialize Render2DClass Screen Resolution
  191. Render2DClass::Set_Screen_Resolution( RectClass( 0, 0, ResolutionWidth, ResolutionHeight ) );
  192. BitDepth = DEFAULT_BIT_DEPTH;
  193. IsWindowed = false;
  194. DX8Wrapper_IsWindowed = false;
  195. for (int light=0;light<4;++light) CurrentDX8LightEnables[light]=false;
  196. ::ZeroMemory(&old_world, sizeof(D3DMATRIX));
  197. ::ZeroMemory(&old_view, sizeof(D3DMATRIX));
  198. ::ZeroMemory(&old_prj, sizeof(D3DMATRIX));
  199. //old_vertex_shader; TODO
  200. //old_sr_shader;
  201. //current_shader;
  202. //world_identity;
  203. //CurrentFogColor;
  204. D3DInterface = NULL;
  205. D3DDevice = NULL;
  206. Reset_Statistics();
  207. Invalidate_Cached_Render_States();
  208. /*
  209. ** Create the D3D interface object
  210. */
  211. D3DInterface = Direct3DCreate8(D3D_SDK_VERSION); // TODO: handle failure cases...
  212. if (!D3DInterface)
  213. return false;
  214. IsInitted = true;
  215. /*
  216. ** Enumerate the available devices
  217. */
  218. Enumerate_Devices();
  219. return true;
  220. }
  221. void DX8Wrapper::Shutdown(void)
  222. {
  223. if (D3DDevice) {
  224. Set_Render_Target ((IDirect3DSurface8 *)NULL);
  225. Release_Device();
  226. }
  227. for (int i = 0; i < MAX_TEXTURE_STAGES; i++) {
  228. if (Textures[i]) {
  229. Textures[i]->Release();
  230. Textures[i] = NULL;
  231. }
  232. }
  233. if (D3DInterface) {
  234. UINT newRefCount=D3DInterface->Release();
  235. D3DInterface=NULL;
  236. }
  237. _RenderDeviceNameTable.Clear(); // note - Delete_All() resizes the vector, causing a reallocation. Clear is better. jba.
  238. _RenderDeviceShortNameTable.Clear();
  239. _RenderDeviceDescriptionTable.Clear();
  240. IsInitted = false; // 010803 srj
  241. }
  242. void DX8Wrapper::Do_Onetime_Device_Dependent_Inits(void)
  243. {
  244. /*
  245. ** Set Global render states (some of which depend on caps)
  246. */
  247. Compute_Caps(DisplayFormat,_PresentParameters.AutoDepthStencilFormat);
  248. /*
  249. ** Initalize any other subsystems inside of WW3D
  250. */
  251. MissingTexture::_Init();
  252. TextureClass::_Init_Filters();
  253. TheDX8MeshRenderer.Init();
  254. BoxRenderObjClass::Init();
  255. VertexMaterialClass::Init();
  256. PointGroupClass::_Init(); // This needs the VertexMaterialClass to be initted
  257. ShatterSystem::Init();
  258. TextureLoader::Init();
  259. #ifdef WW3D_DX8
  260. // WW3DAssetManager::Get_Instance()->Open_Texture_File_Cache("cache_");
  261. /*
  262. ** Initialize the dazzle system
  263. */
  264. FileClass * dazzle_ini_file = _TheFileFactory->Get_File(DAZZLE_INI_FILENAME);
  265. if (dazzle_ini_file) {
  266. INIClass dazzle_ini(*dazzle_ini_file);
  267. DazzleRenderObjClass::Init_From_INI(&dazzle_ini);
  268. _TheFileFactory->Return_File(dazzle_ini_file);
  269. }
  270. #endif //WW3D_DX8
  271. Set_Default_Global_Render_States();
  272. }
  273. inline DWORD F2DW(float f) { return *((unsigned*)&f); }
  274. void DX8Wrapper::Set_Default_Global_Render_States(void)
  275. {
  276. DX8_THREAD_ASSERT();
  277. const D3DCAPS8 &caps = DX8Caps::Get_Default_Caps();
  278. Set_DX8_Render_State(D3DRS_RANGEFOGENABLE, (caps.RasterCaps & D3DPRASTERCAPS_FOGRANGE) ? TRUE : FALSE);
  279. Set_DX8_Render_State(D3DRS_FOGTABLEMODE, D3DFOG_NONE);
  280. Set_DX8_Render_State(D3DRS_FOGVERTEXMODE, D3DFOG_LINEAR);
  281. Set_DX8_Render_State(D3DRS_SPECULARMATERIALSOURCE, D3DMCS_MATERIAL);
  282. Set_DX8_Render_State(D3DRS_COLORVERTEX, TRUE);
  283. Set_DX8_Render_State(D3DRS_ZBIAS,0);
  284. Set_DX8_Texture_Stage_State(1, D3DTSS_BUMPENVLSCALE, F2DW(1.0f));
  285. Set_DX8_Texture_Stage_State(1, D3DTSS_BUMPENVLOFFSET, F2DW(0.0f));
  286. Set_DX8_Texture_Stage_State(0, D3DTSS_BUMPENVMAT00,F2DW(1.0f));
  287. Set_DX8_Texture_Stage_State(0, D3DTSS_BUMPENVMAT01,F2DW(0.0f));
  288. Set_DX8_Texture_Stage_State(0, D3DTSS_BUMPENVMAT10,F2DW(0.0f));
  289. Set_DX8_Texture_Stage_State(0, D3DTSS_BUMPENVMAT11,F2DW(1.0f));
  290. // Set_DX8_Render_State(D3DRS_CULLMODE, D3DCULL_CW);
  291. // Set dither mode here?
  292. }
  293. //MW: I added this for 'Generals'.
  294. bool DX8Wrapper::Validate_Device(void)
  295. { DWORD numPasses=0;
  296. HRESULT hRes;
  297. hRes=_Get_D3D_Device8()->ValidateDevice(&numPasses);
  298. return (hRes == D3D_OK);
  299. }
  300. void DX8Wrapper::Invalidate_Cached_Render_States(void)
  301. {
  302. render_state_changed = 0;
  303. int a;
  304. for (a=0;a<sizeof(RenderStates)/sizeof(unsigned);++a) {
  305. RenderStates[a]=0x12345678;
  306. }
  307. for (a=0;a<MAX_TEXTURE_STAGES;++a) {
  308. for (int b=0; b<32;b++) {
  309. TextureStageStates[a][b]=0x12345678;
  310. }
  311. //Need to explicitly set texture to NULL, otherwise app will not be able to
  312. //set it to null because of redundant state checker. MW
  313. if (_Get_D3D_Device8())
  314. _Get_D3D_Device8()->SetTexture(a,NULL);
  315. if (Textures[a] != NULL)
  316. Textures[a]->Release();
  317. Textures[a]=NULL;
  318. }
  319. ShaderClass::Invalidate();
  320. //Need to explicitly set render_state texture pointers to NULL. MW
  321. Release_Render_State();
  322. }
  323. void DX8Wrapper::Do_Onetime_Device_Dependent_Shutdowns(void)
  324. {
  325. /*
  326. ** Shutdown ww3d systems
  327. */
  328. if (render_state.vertex_buffer) render_state.vertex_buffer->Release_Engine_Ref();
  329. REF_PTR_RELEASE(render_state.vertex_buffer);
  330. if (render_state.index_buffer) render_state.index_buffer->Release_Engine_Ref();
  331. REF_PTR_RELEASE(render_state.index_buffer);
  332. REF_PTR_RELEASE(render_state.material);
  333. for (unsigned i=0;i<MAX_TEXTURE_STAGES;++i) REF_PTR_RELEASE(render_state.Textures[i]);
  334. #ifdef WW3D_DX8
  335. DazzleRenderObjClass::Deinit();
  336. #endif //WW3D_DX8
  337. TextureLoader::Deinit();
  338. SortingRendererClass::Deinit();
  339. DynamicVBAccessClass::_Deinit();
  340. DynamicIBAccessClass::_Deinit();
  341. ShatterSystem::Shutdown();
  342. PointGroupClass::_Shutdown();
  343. VertexMaterialClass::Shutdown();
  344. BoxRenderObjClass::Shutdown();
  345. TheDX8MeshRenderer.Shutdown();
  346. MissingTexture::_Deinit();
  347. }
  348. bool DX8Wrapper::Create_Device(void)
  349. {
  350. WWASSERT(D3DDevice == NULL); // for now, once you've created a device, you're stuck with it!
  351. D3DCAPS8 caps;
  352. if (FAILED( D3DInterface->GetDeviceCaps(
  353. CurRenderDevice,
  354. WW3D_DEVTYPE,
  355. &caps))) {
  356. return false;
  357. }
  358. ::ZeroMemory(&CurrentAdapterIdentifier, sizeof(D3DADAPTER_IDENTIFIER8));
  359. if (FAILED( D3DInterface->GetAdapterIdentifier(CurRenderDevice,D3DENUM_NO_WHQL_LEVEL,&CurrentAdapterIdentifier))) {
  360. return false;
  361. }
  362. unsigned vertex_processing_type=D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  363. if (caps.DevCaps&D3DDEVCAPS_HWTRANSFORMANDLIGHT) {
  364. vertex_processing_type=D3DCREATE_MIXED_VERTEXPROCESSING;
  365. }
  366. #ifdef CREATE_DX8_MULTI_THREADED
  367. vertex_processing_type|=D3DCREATE_MULTITHREADED;
  368. _DX8SingleThreaded=false;
  369. #else
  370. _DX8SingleThreaded=true;
  371. #endif
  372. if (DX8Wrapper_PreserveFPU)
  373. vertex_processing_type |= D3DCREATE_FPU_PRESERVE;
  374. if (FAILED( D3DInterface->CreateDevice(
  375. CurRenderDevice,
  376. WW3D_DEVTYPE,
  377. _Hwnd,
  378. vertex_processing_type,
  379. &_PresentParameters,
  380. &D3DDevice ) ) )
  381. {
  382. return false;
  383. }
  384. /*
  385. ** Initialize all subsystems
  386. */
  387. Do_Onetime_Device_Dependent_Inits();
  388. return true;
  389. }
  390. bool DX8Wrapper::Reset_Device(bool reload_assets)
  391. {
  392. DX8_THREAD_ASSERT();
  393. if ((IsInitted) && (D3DDevice != NULL)) {
  394. // Release all non-MANAGED stuff
  395. Set_Vertex_Buffer (NULL);
  396. Set_Index_Buffer (NULL, 0);
  397. if (m_pCleanupHook) {
  398. m_pCleanupHook->ReleaseResources();
  399. }
  400. DynamicVBAccessClass::_Deinit();
  401. DynamicIBAccessClass::_Deinit();
  402. DX8TextureManagerClass::Release_Textures();
  403. HRESULT hr=_Get_D3D_Device8()->TestCooperativeLevel();
  404. if (hr != D3DERR_DEVICELOST )
  405. { DX8CALL_HRES(Reset(&_PresentParameters),hr)
  406. if (hr != D3D_OK)
  407. return false; //reset failed.
  408. }
  409. else
  410. return false; //device is lost and can't be reset.
  411. if (reload_assets)
  412. {
  413. DX8TextureManagerClass::Recreate_Textures();
  414. if (m_pCleanupHook) {
  415. m_pCleanupHook->ReAcquireResources();
  416. }
  417. }
  418. Invalidate_Cached_Render_States();
  419. Set_Default_Global_Render_States();
  420. return true;
  421. }
  422. return false;
  423. }
  424. void DX8Wrapper::Release_Device(void)
  425. {
  426. if (D3DDevice) {
  427. for (int a=0;a<MAX_TEXTURE_STAGES;++a)
  428. { //release references to any textures that were used in last rendering call
  429. DX8CALL(SetTexture(a,NULL));
  430. }
  431. DX8CALL(SetStreamSource(0, NULL, 0)); //release reference count on last rendered vertex buffer
  432. DX8CALL(SetIndices(NULL,0)); //release reference count on last rendered index buffer
  433. /*
  434. ** Release the current vertex and index buffers
  435. */
  436. if (render_state.vertex_buffer) render_state.vertex_buffer->Release_Engine_Ref();
  437. REF_PTR_RELEASE(render_state.vertex_buffer);
  438. if (render_state.index_buffer) render_state.index_buffer->Release_Engine_Ref();
  439. REF_PTR_RELEASE(render_state.index_buffer);
  440. /*
  441. ** Shutdown all subsystems
  442. */
  443. Do_Onetime_Device_Dependent_Shutdowns();
  444. /*
  445. ** Release the device
  446. */
  447. D3DDevice->Release();
  448. D3DDevice=NULL;
  449. }
  450. }
  451. void DX8Wrapper::Enumerate_Devices()
  452. {
  453. DX8_Assert();
  454. int adapter_count = D3DInterface->GetAdapterCount();
  455. for (int adapter_index=0; adapter_index<adapter_count; adapter_index++) {
  456. D3DADAPTER_IDENTIFIER8 id;
  457. ::ZeroMemory(&id, sizeof(D3DADAPTER_IDENTIFIER8));
  458. HRESULT res = D3DInterface->GetAdapterIdentifier(adapter_index,D3DENUM_NO_WHQL_LEVEL,&id);
  459. if (res == D3D_OK) {
  460. /*
  461. ** Set up the device name
  462. */
  463. StringClass device_name = id.Description;
  464. _RenderDeviceNameTable.Add(device_name);
  465. _RenderDeviceShortNameTable.Add(device_name); // for now, just add the same name to the "pretty name table"
  466. /*
  467. ** Set up the render device description
  468. ** TODO: Fill in more fields of the render device description? (need some lookup tables)
  469. */
  470. RenderDeviceDescClass desc;
  471. desc.set_device_name(id.Description);
  472. desc.set_driver_name(id.Driver);
  473. char buf[64];
  474. sprintf(buf,"%d.%d.%d.%d", //"%04x.%04x.%04x.%04x",
  475. HIWORD(id.DriverVersion.HighPart),
  476. LOWORD(id.DriverVersion.HighPart),
  477. HIWORD(id.DriverVersion.LowPart),
  478. LOWORD(id.DriverVersion.LowPart));
  479. desc.set_driver_version(buf);
  480. /*
  481. ** Enumerate the resolutions
  482. */
  483. desc.reset_resolution_list();
  484. int mode_count = D3DInterface->GetAdapterModeCount(adapter_index);
  485. for (int mode_index=0; mode_index<mode_count; mode_index++) {
  486. D3DDISPLAYMODE d3dmode;
  487. ::ZeroMemory(&d3dmode, sizeof(D3DDISPLAYMODE));
  488. HRESULT res = D3DInterface->EnumAdapterModes(adapter_index,mode_index,&d3dmode);
  489. if (res == D3D_OK) {
  490. int bits = 0;
  491. switch (d3dmode.Format)
  492. {
  493. case D3DFMT_R8G8B8:
  494. case D3DFMT_A8R8G8B8:
  495. case D3DFMT_X8R8G8B8: bits = 32; break;
  496. case D3DFMT_R5G6B5:
  497. case D3DFMT_X1R5G5B5: bits = 16; break;
  498. }
  499. /*
  500. ** If we recognize the format, add it to the list
  501. ** TODO: should we handle more formats? will any cards report more than 24 or 16 bit?
  502. */
  503. if (bits != 0) {
  504. desc.add_resolution(d3dmode.Width,d3dmode.Height,bits);
  505. }
  506. }
  507. }
  508. /*
  509. ** Add the render device to our table
  510. */
  511. _RenderDeviceDescriptionTable.Add(desc);
  512. }
  513. }
  514. }
  515. bool DX8Wrapper::Set_Any_Render_Device(void)
  516. {
  517. // Try windowed first
  518. for (int dev_number = 0; dev_number < _RenderDeviceNameTable.Count(); dev_number++) {
  519. if (Set_Render_Device(dev_number,-1,-1,-1,1,false)) {
  520. return true;
  521. }
  522. }
  523. // Then fullscreen
  524. for (dev_number = 0; dev_number < _RenderDeviceNameTable.Count(); dev_number++) {
  525. if (Set_Render_Device(dev_number,-1,-1,-1,0,false)) {
  526. return true;
  527. }
  528. }
  529. return false;
  530. }
  531. bool DX8Wrapper::Set_Render_Device
  532. (
  533. const char * dev_name,
  534. int width,
  535. int height,
  536. int bits,
  537. int windowed,
  538. bool resize_window
  539. )
  540. {
  541. for ( int dev_number = 0; dev_number < _RenderDeviceNameTable.Count(); dev_number++) {
  542. if ( strcmp( dev_name, _RenderDeviceNameTable[dev_number]) == 0) {
  543. return Set_Render_Device( dev_number, width, height, bits, windowed, resize_window );
  544. }
  545. if ( strcmp( dev_name, _RenderDeviceShortNameTable[dev_number]) == 0) {
  546. return Set_Render_Device( dev_number, width, height, bits, windowed, resize_window );
  547. }
  548. }
  549. return false;
  550. }
  551. void DX8Wrapper::Get_Format_Name(unsigned int format, StringClass *tex_format)
  552. {
  553. *tex_format="Unknown";
  554. switch (format) {
  555. case D3DFMT_A8R8G8B8: *tex_format="D3DFMT_A8R8G8B8"; break;
  556. case D3DFMT_R8G8B8: *tex_format="D3DFMT_R8G8B8"; break;
  557. case D3DFMT_A4R4G4B4: *tex_format="D3DFMT_A4R4G4B4"; break;
  558. case D3DFMT_A1R5G5B5: *tex_format="D3DFMT_A1R5G5B5"; break;
  559. case D3DFMT_R5G6B5: *tex_format="D3DFMT_R5G6B5"; break;
  560. case D3DFMT_L8: *tex_format="D3DFMT_L8"; break;
  561. case D3DFMT_A8: *tex_format="D3DFMT_A8"; break;
  562. case D3DFMT_P8: *tex_format="D3DFMT_P8"; break;
  563. case D3DFMT_X8R8G8B8: *tex_format="D3DFMT_X8R8G8B8"; break;
  564. case D3DFMT_X1R5G5B5: *tex_format="D3DFMT_X1R5G5B5"; break;
  565. case D3DFMT_R3G3B2: *tex_format="D3DFMT_R3G3B2"; break;
  566. case D3DFMT_A8R3G3B2: *tex_format="D3DFMT_A8R3G3B2"; break;
  567. case D3DFMT_X4R4G4B4: *tex_format="D3DFMT_X4R4G4B4"; break;
  568. case D3DFMT_A8P8: *tex_format="D3DFMT_A8P8"; break;
  569. case D3DFMT_A8L8: *tex_format="D3DFMT_A8L8"; break;
  570. case D3DFMT_A4L4: *tex_format="D3DFMT_A4L4"; break;
  571. case D3DFMT_V8U8: *tex_format="D3DFMT_V8U8"; break;
  572. case D3DFMT_L6V5U5: *tex_format="D3DFMT_L6V5U5"; break;
  573. case D3DFMT_X8L8V8U8: *tex_format="D3DFMT_X8L8V8U8"; break;
  574. case D3DFMT_Q8W8V8U8: *tex_format="D3DFMT_Q8W8V8U8"; break;
  575. case D3DFMT_V16U16: *tex_format="D3DFMT_V16U16"; break;
  576. case D3DFMT_W11V11U10: *tex_format="D3DFMT_W11V11U10"; break;
  577. case D3DFMT_UYVY: *tex_format="D3DFMT_UYVY"; break;
  578. case D3DFMT_YUY2: *tex_format="D3DFMT_YUY2"; break;
  579. case D3DFMT_DXT1: *tex_format="D3DFMT_DXT1"; break;
  580. case D3DFMT_DXT2: *tex_format="D3DFMT_DXT2"; break;
  581. case D3DFMT_DXT3: *tex_format="D3DFMT_DXT3"; break;
  582. case D3DFMT_DXT4: *tex_format="D3DFMT_DXT4"; break;
  583. case D3DFMT_DXT5: *tex_format="D3DFMT_DXT5"; break;
  584. case D3DFMT_D16_LOCKABLE: *tex_format="D3DFMT_D16_LOCKABLE"; break;
  585. case D3DFMT_D32: *tex_format="D3DFMT_D32"; break;
  586. case D3DFMT_D15S1: *tex_format="D3DFMT_D15S1"; break;
  587. case D3DFMT_D24S8: *tex_format="D3DFMT_D24S8"; break;
  588. case D3DFMT_D16: *tex_format="D3DFMT_D16"; break;
  589. case D3DFMT_D24X8: *tex_format="D3DFMT_D24X8"; break;
  590. case D3DFMT_D24X4S4: *tex_format="D3DFMT_D24X4S4"; break;
  591. default: break;
  592. }
  593. }
  594. bool DX8Wrapper::Set_Render_Device(int dev, int width, int height, int bits, int windowed,
  595. bool resize_window,bool reset_device, bool restore_assets)
  596. {
  597. WWASSERT(IsInitted);
  598. WWASSERT(dev >= -1);
  599. WWASSERT(dev < _RenderDeviceNameTable.Count());
  600. /*
  601. ** If user has never selected a render device, start out with device 0
  602. */
  603. if ((CurRenderDevice == -1) && (dev == -1)) {
  604. CurRenderDevice = 0;
  605. } else if (dev != -1) {
  606. CurRenderDevice = dev;
  607. }
  608. /*
  609. ** If user doesn't want to change res, set the res variables to match the
  610. ** current resolution
  611. */
  612. if (width != -1) ResolutionWidth = width;
  613. if (height != -1) ResolutionHeight = height;
  614. // Initialize Render2DClass Screen Resolution
  615. Render2DClass::Set_Screen_Resolution( RectClass( 0, 0, ResolutionWidth, ResolutionHeight ) );
  616. if (bits != -1) BitDepth = bits;
  617. if (windowed != -1) IsWindowed = (windowed != 0);
  618. DX8Wrapper_IsWindowed = IsWindowed;
  619. WWDEBUG_SAY(("Attempting Set_Render_Device: name: %s (%s:%s), width: %d, height: %d, windowed: %d\n",
  620. _RenderDeviceNameTable[CurRenderDevice],_RenderDeviceDescriptionTable[CurRenderDevice].Get_Driver_Name(),
  621. _RenderDeviceDescriptionTable[CurRenderDevice].Get_Driver_Version(),ResolutionWidth,ResolutionHeight,(IsWindowed ? 1 : 0)));
  622. #ifdef _WINDOWS
  623. // PWG 4/13/2000 - changed so that if you say to resize the window it resizes
  624. // regardless of whether its windowed or not as OpenGL resizes its self around
  625. // the caption and edges of the window type you provide, so its important to
  626. // push the client area to be the size you really want.
  627. // if ( resize_window && windowed ) {
  628. if (resize_window) {
  629. // Get the current dimensions of the 'render area' of the window
  630. RECT rect = { 0 };
  631. ::GetClientRect (_Hwnd, &rect);
  632. // Is the window the correct size for this resolution?
  633. if ((rect.right-rect.left) != ResolutionWidth ||
  634. (rect.bottom-rect.top) != ResolutionHeight) {
  635. // Calculate what the main window's bounding rectangle should be to
  636. // accomodate this resolution
  637. rect.left = 0;
  638. rect.top = 0;
  639. rect.right = ResolutionWidth;
  640. rect.bottom = ResolutionHeight;
  641. DWORD dwstyle = ::GetWindowLong (_Hwnd, GWL_STYLE);
  642. AdjustWindowRect (&rect, dwstyle, FALSE);
  643. // Resize the window to fit this resolution
  644. if (!windowed)
  645. ::SetWindowPos(_Hwnd, HWND_TOPMOST, 0, 0, rect.right-rect.left, rect.bottom-rect.top,SWP_NOSIZE |SWP_NOMOVE);
  646. else
  647. ::SetWindowPos (_Hwnd,
  648. NULL,
  649. 0,
  650. 0,
  651. rect.right-rect.left,
  652. rect.bottom-rect.top,
  653. SWP_NOZORDER | SWP_NOMOVE);
  654. }
  655. }
  656. #endif
  657. //must be either resetting existing device or creating a new one.
  658. WWASSERT(reset_device || D3DDevice == NULL);
  659. /*
  660. ** Initialize values for D3DPRESENT_PARAMETERS members.
  661. */
  662. ::ZeroMemory(&_PresentParameters, sizeof(D3DPRESENT_PARAMETERS));
  663. _PresentParameters.BackBufferWidth = ResolutionWidth;
  664. _PresentParameters.BackBufferHeight = ResolutionHeight;
  665. _PresentParameters.BackBufferCount = IsWindowed ? 1 : 2;
  666. _PresentParameters.MultiSampleType = D3DMULTISAMPLE_NONE;
  667. _PresentParameters.SwapEffect = IsWindowed ? D3DSWAPEFFECT_DISCARD : D3DSWAPEFFECT_FLIP; // Shouldn't this be D3DSWAPEFFECT_FLIP?
  668. _PresentParameters.hDeviceWindow = _Hwnd;
  669. _PresentParameters.Windowed = IsWindowed;
  670. _PresentParameters.EnableAutoDepthStencil = TRUE; // Driver will attempt to match Z-buffer depth
  671. _PresentParameters.Flags=0; // We're not going to lock the backbuffer
  672. _PresentParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
  673. _PresentParameters.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
  674. /*
  675. ** Set up the buffer formats. Several issues here:
  676. ** - if in windowed mode, the backbuffer must use the current display format.
  677. ** - the depth buffer must use
  678. */
  679. if (IsWindowed) {
  680. D3DDISPLAYMODE desktop_mode;
  681. ::ZeroMemory(&desktop_mode, sizeof(D3DDISPLAYMODE));
  682. D3DInterface->GetAdapterDisplayMode( CurRenderDevice, &desktop_mode );
  683. DisplayFormat=_PresentParameters.BackBufferFormat = desktop_mode.Format;
  684. // In windowed mode, define the bitdepth from desktop mode (as it can't be changed)
  685. switch (_PresentParameters.BackBufferFormat) {
  686. case D3DFMT_X8R8G8B8:
  687. case D3DFMT_A8R8G8B8:
  688. case D3DFMT_R8G8B8: BitDepth=32; break;
  689. case D3DFMT_A4R4G4B4:
  690. case D3DFMT_A1R5G5B5:
  691. case D3DFMT_R5G6B5: BitDepth=16; break;
  692. case D3DFMT_L8:
  693. case D3DFMT_A8:
  694. case D3DFMT_P8: BitDepth=8; break;
  695. default:
  696. // Unknown backbuffer format probably means the device can't do windowed
  697. return false;
  698. }
  699. if (BitDepth==32 && D3DInterface->CheckDeviceType(0,D3DDEVTYPE_HAL,desktop_mode.Format,D3DFMT_A8R8G8B8, TRUE) == D3D_OK)
  700. { //promote 32-bit modes to include destination alpha
  701. _PresentParameters.BackBufferFormat = D3DFMT_A8R8G8B8;
  702. }
  703. /*
  704. ** Find a appropriate Z buffer
  705. */
  706. if (!Find_Z_Mode(DisplayFormat,_PresentParameters.BackBufferFormat,&_PresentParameters.AutoDepthStencilFormat))
  707. {
  708. // If opening 32 bit mode failed, try 16 bit, even if the desktop happens to be 32 bit
  709. if (BitDepth==32) {
  710. BitDepth=16;
  711. _PresentParameters.BackBufferFormat=D3DFMT_R5G6B5;
  712. if (!Find_Z_Mode(_PresentParameters.BackBufferFormat,_PresentParameters.BackBufferFormat,&_PresentParameters.AutoDepthStencilFormat)) {
  713. _PresentParameters.AutoDepthStencilFormat=D3DFMT_UNKNOWN;
  714. }
  715. }
  716. else {
  717. _PresentParameters.AutoDepthStencilFormat=D3DFMT_UNKNOWN;
  718. }
  719. }
  720. } else {
  721. /*
  722. ** Try to find a mode that matches the user's desired bit-depth.
  723. */
  724. Find_Color_And_Z_Mode(ResolutionWidth,ResolutionHeight,BitDepth,&DisplayFormat,
  725. &_PresentParameters.BackBufferFormat,&_PresentParameters.AutoDepthStencilFormat);
  726. }
  727. /*
  728. ** Time to actually create the device.
  729. */
  730. if (_PresentParameters.AutoDepthStencilFormat==D3DFMT_UNKNOWN) {
  731. if (BitDepth==32) {
  732. _PresentParameters.AutoDepthStencilFormat=D3DFMT_D32;
  733. }
  734. else {
  735. _PresentParameters.AutoDepthStencilFormat=D3DFMT_D16;
  736. }
  737. }
  738. StringClass displayFormat;
  739. StringClass backbufferFormat;
  740. Get_Format_Name(DisplayFormat,&displayFormat);
  741. Get_Format_Name(_PresentParameters.BackBufferFormat,&backbufferFormat);
  742. WWDEBUG_SAY(("Using Display/BackBuffer Formats: %s/%s\n",displayFormat,backbufferFormat));
  743. bool ret;
  744. if (reset_device)
  745. ret = Reset_Device(restore_assets); //reset device without restoring data - we're likely switching out of the app.
  746. else
  747. ret = Create_Device();
  748. WWDEBUG_SAY(("Reset/Create_Device done, reset_device=%d, restore_assets=%d\n", reset_device, restore_assets));
  749. return ret;
  750. }
  751. bool DX8Wrapper::Set_Next_Render_Device(void)
  752. {
  753. int new_dev = (CurRenderDevice + 1) % _RenderDeviceNameTable.Count();
  754. return Set_Render_Device(new_dev);
  755. }
  756. bool DX8Wrapper::Toggle_Windowed(void)
  757. {
  758. #ifdef WW3D_DX8
  759. // State OK?
  760. assert (IsInitted);
  761. if (IsInitted) {
  762. // Get information about the current render device's resolutions
  763. const RenderDeviceDescClass &render_device = Get_Render_Device_Desc ();
  764. const DynamicVectorClass<ResolutionDescClass> &resolutions = render_device.Enumerate_Resolutions ();
  765. // Loop through all the resolutions supported by the current device.
  766. // If we aren't currently running under one of these resolutions,
  767. // then we should probably to the closest resolution before
  768. // toggling the windowed state.
  769. int curr_res = -1;
  770. for (int res = 0;
  771. (res < resolutions.Count ()) && (curr_res == -1);
  772. res ++) {
  773. // Is this the resolution we are looking for?
  774. if ((resolutions[res].Width == ResolutionWidth) &&
  775. (resolutions[res].Height == ResolutionHeight) &&
  776. (resolutions[res].BitDepth == BitDepth)) {
  777. curr_res = res;
  778. }
  779. }
  780. if (curr_res == -1) {
  781. // We don't match any of the standard resolutions,
  782. // so set the first resolution and toggle the windowed state.
  783. return Set_Device_Resolution (resolutions[0].Width,
  784. resolutions[0].Height,
  785. resolutions[0].BitDepth,
  786. !IsWindowed, true);
  787. } else {
  788. // Toggle the windowed state
  789. return Set_Device_Resolution (-1, -1, -1, !IsWindowed, true);
  790. }
  791. }
  792. #endif //WW3D_DX8
  793. return false;
  794. }
  795. void DX8Wrapper::Set_Swap_Interval(int swap)
  796. {
  797. switch (swap) {
  798. case 0: _PresentParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; break;
  799. case 1: _PresentParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_ONE ; break;
  800. case 2: _PresentParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_TWO; break;
  801. case 3: _PresentParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_THREE; break;
  802. default: _PresentParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_ONE ; break;
  803. }
  804. Reset_Device();
  805. }
  806. int DX8Wrapper::Get_Swap_Interval(void)
  807. {
  808. return _PresentParameters.FullScreen_PresentationInterval;
  809. }
  810. bool DX8Wrapper::Has_Stencil(void)
  811. {
  812. bool has_stencil = (_PresentParameters.AutoDepthStencilFormat == D3DFMT_D24S8 ||
  813. _PresentParameters.AutoDepthStencilFormat == D3DFMT_D24X4S4);
  814. return has_stencil;
  815. }
  816. int DX8Wrapper::Get_Render_Device_Count(void)
  817. {
  818. return _RenderDeviceNameTable.Count();
  819. }
  820. int DX8Wrapper::Get_Render_Device(void)
  821. {
  822. assert(IsInitted);
  823. return CurRenderDevice;
  824. }
  825. const RenderDeviceDescClass & DX8Wrapper::Get_Render_Device_Desc(int deviceidx)
  826. {
  827. WWASSERT(IsInitted);
  828. if ((deviceidx == -1) && (CurRenderDevice == -1)) {
  829. CurRenderDevice = 0;
  830. }
  831. // if the device index is -1 then we want the current device
  832. if (deviceidx == -1) {
  833. WWASSERT(CurRenderDevice >= 0);
  834. WWASSERT(CurRenderDevice < _RenderDeviceNameTable.Count());
  835. return _RenderDeviceDescriptionTable[CurRenderDevice];
  836. }
  837. // We can only ask for multiple device information if the devices
  838. // have been detected.
  839. WWASSERT(deviceidx >= 0);
  840. WWASSERT(deviceidx < _RenderDeviceNameTable.Count());
  841. return _RenderDeviceDescriptionTable[deviceidx];
  842. }
  843. const char * DX8Wrapper::Get_Render_Device_Name(int device_index)
  844. {
  845. device_index = device_index % _RenderDeviceShortNameTable.Count();
  846. return _RenderDeviceShortNameTable[device_index];
  847. }
  848. bool DX8Wrapper::Set_Device_Resolution(int width,int height,int bits,int windowed, bool resize_window)
  849. {
  850. if (D3DDevice != NULL) {
  851. if (width != -1) {
  852. _PresentParameters.BackBufferWidth = ResolutionWidth = width;
  853. }
  854. if (height != -1) {
  855. _PresentParameters.BackBufferHeight = ResolutionHeight = height;
  856. }
  857. if (resize_window)
  858. {
  859. // Get the current dimensions of the 'render area' of the window
  860. RECT rect = { 0 };
  861. ::GetClientRect (_Hwnd, &rect);
  862. // Is the window the correct size for this resolution?
  863. if ((rect.right-rect.left) != ResolutionWidth ||
  864. (rect.bottom-rect.top) != ResolutionHeight)
  865. {
  866. // Calculate what the main window's bounding rectangle should be to
  867. // accomodate this resolution
  868. rect.left = 0;
  869. rect.top = 0;
  870. rect.right = ResolutionWidth;
  871. rect.bottom = ResolutionHeight;
  872. DWORD dwstyle = ::GetWindowLong (_Hwnd, GWL_STYLE);
  873. AdjustWindowRect (&rect, dwstyle, FALSE);
  874. // Resize the window to fit this resolution
  875. if (!windowed)
  876. ::SetWindowPos(_Hwnd, HWND_TOPMOST, 0, 0, rect.right-rect.left, rect.bottom-rect.top,SWP_NOSIZE |SWP_NOMOVE);
  877. else
  878. ::SetWindowPos (_Hwnd,
  879. NULL,
  880. 0,
  881. 0,
  882. rect.right-rect.left,
  883. rect.bottom-rect.top,
  884. SWP_NOZORDER | SWP_NOMOVE);
  885. }
  886. }
  887. #pragma message("TODO: support changing windowed status and changing the bit depth")
  888. return Reset_Device();
  889. } else {
  890. return false;
  891. }
  892. }
  893. void DX8Wrapper::Get_Device_Resolution(int & set_w,int & set_h,int & set_bits,bool & set_windowed)
  894. {
  895. WWASSERT(IsInitted);
  896. set_w = ResolutionWidth;
  897. set_h = ResolutionHeight;
  898. set_bits = BitDepth;
  899. set_windowed = IsWindowed;
  900. return ;
  901. }
  902. void DX8Wrapper::Get_Render_Target_Resolution(int & set_w,int & set_h,int & set_bits,bool & set_windowed)
  903. {
  904. WWASSERT(IsInitted);
  905. if (CurrentRenderTarget != NULL) {
  906. D3DSURFACE_DESC info;
  907. CurrentRenderTarget->GetDesc (&info);
  908. set_w = info.Width;
  909. set_h = info.Height;
  910. set_bits = BitDepth; // should we get the actual bit depth of the target?
  911. set_windowed = IsWindowed; // this doesn't really make sense for render targets (shouldn't matter)...
  912. } else {
  913. Get_Device_Resolution (set_w, set_h, set_bits, set_windowed);
  914. }
  915. return ;
  916. }
  917. bool DX8Wrapper::Registry_Save_Render_Device( const char * sub_key )
  918. {
  919. int width, height, depth;
  920. bool windowed;
  921. Get_Device_Resolution(width, height, depth, windowed);
  922. return Registry_Save_Render_Device(sub_key, CurRenderDevice, ResolutionWidth, ResolutionHeight, BitDepth, IsWindowed, TextureBitDepth);
  923. }
  924. bool DX8Wrapper::Registry_Save_Render_Device( const char *sub_key, int device, int width, int height, int depth, bool windowed, int texture_depth)
  925. {
  926. RegistryClass * registry = W3DNEW RegistryClass( sub_key );
  927. WWASSERT( registry );
  928. if ( !registry->Is_Valid() ) {
  929. delete registry;
  930. WWDEBUG_SAY(( "Error getting Registry\n" ));
  931. return false;
  932. }
  933. registry->Set_String( VALUE_NAME_RENDER_DEVICE_NAME,
  934. _RenderDeviceShortNameTable[device] );
  935. registry->Set_Int( VALUE_NAME_RENDER_DEVICE_WIDTH, width );
  936. registry->Set_Int( VALUE_NAME_RENDER_DEVICE_HEIGHT, height );
  937. registry->Set_Int( VALUE_NAME_RENDER_DEVICE_DEPTH, depth );
  938. registry->Set_Int( VALUE_NAME_RENDER_DEVICE_WINDOWED, windowed );
  939. registry->Set_Int( VALUE_NAME_RENDER_DEVICE_TEXTURE_DEPTH, texture_depth );
  940. delete registry;
  941. return true;
  942. }
  943. bool DX8Wrapper::Registry_Load_Render_Device( const char * sub_key, bool resize_window )
  944. {
  945. char name[ 200 ];
  946. int width,height,depth,windowed;
  947. if ( Registry_Load_Render_Device( sub_key,
  948. name,
  949. sizeof(name),
  950. width,
  951. height,
  952. depth,
  953. windowed,
  954. TextureBitDepth) &&
  955. (*name != 0))
  956. {
  957. WWDEBUG_SAY(( "Device %s (%d X %d) %d bit windowed:%d\n", name,width,height,depth,windowed));
  958. if (TextureBitDepth==16 || TextureBitDepth==32) {
  959. // WWDEBUG_SAY(( "Texture depth %d\n", TextureBitDepth));
  960. } else {
  961. WWDEBUG_SAY(( "Invalid texture depth %d, switching to 16 bits\n", TextureBitDepth));
  962. TextureBitDepth=16;
  963. }
  964. if ( Set_Render_Device( name, width,height,depth,windowed, resize_window ) != true) {
  965. return Set_Any_Render_Device();
  966. }
  967. return true;
  968. }
  969. WWDEBUG_SAY(( "Error getting Registry\n" ));
  970. return Set_Any_Render_Device();
  971. }
  972. bool DX8Wrapper::Registry_Load_Render_Device( const char * sub_key, char *device, int device_len, int &width, int &height, int &depth, int &windowed, int &texture_depth)
  973. {
  974. RegistryClass registry( sub_key );
  975. if ( registry.Is_Valid() ) {
  976. registry.Get_String( VALUE_NAME_RENDER_DEVICE_NAME,
  977. device, device_len);
  978. width = registry.Get_Int( VALUE_NAME_RENDER_DEVICE_WIDTH, -1 );
  979. height = registry.Get_Int( VALUE_NAME_RENDER_DEVICE_HEIGHT, -1 );
  980. depth = registry.Get_Int( VALUE_NAME_RENDER_DEVICE_DEPTH, -1 );
  981. windowed = registry.Get_Int( VALUE_NAME_RENDER_DEVICE_WINDOWED, -1 );
  982. texture_depth = registry.Get_Int( VALUE_NAME_RENDER_DEVICE_TEXTURE_DEPTH, -1 );
  983. return true;
  984. }
  985. return false;
  986. }
  987. bool DX8Wrapper::Find_Color_And_Z_Mode(int resx,int resy,int bitdepth,D3DFORMAT * set_colorbuffer,D3DFORMAT * set_backbuffer,D3DFORMAT * set_zmode)
  988. {
  989. static D3DFORMAT _formats16[] =
  990. {
  991. D3DFMT_R5G6B5,
  992. D3DFMT_X1R5G5B5,
  993. D3DFMT_A1R5G5B5
  994. };
  995. static D3DFORMAT _formats32[] =
  996. {
  997. D3DFMT_A8R8G8B8,
  998. D3DFMT_X8R8G8B8,
  999. D3DFMT_R8G8B8,
  1000. };
  1001. /*
  1002. ** Select the table that we're going to use to search for a valid backbuffer format
  1003. */
  1004. D3DFORMAT * format_table = NULL;
  1005. int format_count = 0;
  1006. if (BitDepth == 16) {
  1007. format_table = _formats16;
  1008. format_count = sizeof(_formats16) / sizeof(D3DFORMAT);
  1009. } else {
  1010. format_table = _formats32;
  1011. format_count = sizeof(_formats32) / sizeof(D3DFORMAT);
  1012. }
  1013. /*
  1014. ** now search for a valid format
  1015. */
  1016. bool found = false;
  1017. unsigned int mode = 0;
  1018. for (int format_index=0; format_index < format_count; format_index++) {
  1019. found |= Find_Color_Mode(format_table[format_index],resx,resy,&mode);
  1020. if (found) break;
  1021. }
  1022. if (!found) {
  1023. return false;
  1024. } else {
  1025. *set_backbuffer=*set_colorbuffer = format_table[format_index];
  1026. }
  1027. if (bitdepth==32 && *set_colorbuffer == D3DFMT_X8R8G8B8 && D3DInterface->CheckDeviceType(0,D3DDEVTYPE_HAL,*set_colorbuffer,D3DFMT_A8R8G8B8, TRUE) == D3D_OK)
  1028. { //promote 32-bit modes to include destination alpha when supported
  1029. *set_backbuffer = D3DFMT_A8R8G8B8;
  1030. }
  1031. /*
  1032. ** We found a backbuffer format, now find a zbuffer format
  1033. */
  1034. return Find_Z_Mode(*set_colorbuffer,*set_backbuffer, set_zmode);
  1035. };
  1036. // find the resolution mode with at least resx,resy with the highest supported
  1037. // refresh rate
  1038. bool DX8Wrapper::Find_Color_Mode(D3DFORMAT colorbuffer, int resx, int resy, UINT *mode)
  1039. {
  1040. UINT i,j,modemax;
  1041. UINT rx,ry;
  1042. D3DDISPLAYMODE dmode;
  1043. ::ZeroMemory(&dmode, sizeof(D3DDISPLAYMODE));
  1044. rx=(unsigned int) resx;
  1045. ry=(unsigned int) resy;
  1046. bool found=false;
  1047. modemax=D3DInterface->GetAdapterModeCount(D3DADAPTER_DEFAULT);
  1048. i=0;
  1049. while (i<modemax && !found)
  1050. {
  1051. D3DInterface->EnumAdapterModes(D3DADAPTER_DEFAULT, i, &dmode);
  1052. if (dmode.Width==rx && dmode.Height==ry && dmode.Format==colorbuffer)
  1053. found=true;
  1054. i++;
  1055. }
  1056. i--; // this is the first valid mode
  1057. // no match
  1058. if (!found) return false;
  1059. // go to the highest refresh rate in this mode
  1060. bool stillok=true;
  1061. j=i;
  1062. while (j<modemax && stillok)
  1063. {
  1064. D3DInterface->EnumAdapterModes(D3DADAPTER_DEFAULT, j, &dmode);
  1065. if (dmode.Width==rx && dmode.Height==ry && dmode.Format==colorbuffer)
  1066. stillok=true; else stillok=false;
  1067. j++;
  1068. }
  1069. if (stillok==false) *mode=j-2;
  1070. else *mode=i;
  1071. return true;
  1072. }
  1073. // Helper function to find a Z buffer mode for the colorbuffer
  1074. // Will look for greatest Z precision
  1075. bool DX8Wrapper::Find_Z_Mode(D3DFORMAT colorbuffer,D3DFORMAT backbuffer, D3DFORMAT *zmode)
  1076. {
  1077. //MW: Swapped the next 2 tests so that Stencil modes get tested first.
  1078. if (Test_Z_Mode(colorbuffer,backbuffer,D3DFMT_D24S8))
  1079. {
  1080. *zmode=D3DFMT_D24S8;
  1081. WWDEBUG_SAY(("Found zbuffer mode D3DFMT_D24S8\n"));
  1082. return true;
  1083. }
  1084. if (Test_Z_Mode(colorbuffer,backbuffer,D3DFMT_D32))
  1085. {
  1086. *zmode=D3DFMT_D32;
  1087. WWDEBUG_SAY(("Found zbuffer mode D3DFMT_D32\n"));
  1088. return true;
  1089. }
  1090. if (Test_Z_Mode(colorbuffer,backbuffer,D3DFMT_D24X8))
  1091. {
  1092. *zmode=D3DFMT_D24X8;
  1093. WWDEBUG_SAY(("Found zbuffer mode D3DFMT_D24X8\n"));
  1094. return true;
  1095. }
  1096. if (Test_Z_Mode(colorbuffer,backbuffer,D3DFMT_D24X4S4))
  1097. {
  1098. *zmode=D3DFMT_D24X4S4;
  1099. WWDEBUG_SAY(("Found zbuffer mode D3DFMT_D24X4S4\n"));
  1100. return true;
  1101. }
  1102. if (Test_Z_Mode(colorbuffer,backbuffer,D3DFMT_D16))
  1103. {
  1104. *zmode=D3DFMT_D16;
  1105. WWDEBUG_SAY(("Found zbuffer mode D3DFMT_D16\n"));
  1106. return true;
  1107. }
  1108. if (Test_Z_Mode(colorbuffer,backbuffer,D3DFMT_D15S1))
  1109. {
  1110. *zmode=D3DFMT_D15S1;
  1111. WWDEBUG_SAY(("Found zbuffer mode D3DFMT_D15S1\n"));
  1112. return true;
  1113. }
  1114. // can't find a match
  1115. return false;
  1116. }
  1117. bool DX8Wrapper::Test_Z_Mode(D3DFORMAT colorbuffer,D3DFORMAT backbuffer, D3DFORMAT zmode)
  1118. {
  1119. // See if we have this mode first
  1120. if (FAILED(D3DInterface->CheckDeviceFormat(D3DADAPTER_DEFAULT,WW3D_DEVTYPE,
  1121. colorbuffer,D3DUSAGE_DEPTHSTENCIL,D3DRTYPE_SURFACE,zmode)))
  1122. {
  1123. WWDEBUG_SAY(("CheckDeviceFormat failed. Colorbuffer format = %d Zbufferformat = %d\n",colorbuffer,zmode));
  1124. return false;
  1125. }
  1126. // Then see if it matches the color buffer
  1127. if(FAILED(D3DInterface->CheckDepthStencilMatch(D3DADAPTER_DEFAULT, WW3D_DEVTYPE,
  1128. colorbuffer,backbuffer,zmode)))
  1129. {
  1130. WWDEBUG_SAY(("CheckDepthStencilMatch failed. Colorbuffer format = %d Backbuffer format = %d Zbufferformat = %d\n",colorbuffer,backbuffer,zmode));
  1131. return false;
  1132. }
  1133. return true;
  1134. }
  1135. void DX8Wrapper::Reset_Statistics()
  1136. {
  1137. matrix_changes = 0;
  1138. material_changes = 0;
  1139. vertex_buffer_changes = 0;
  1140. index_buffer_changes = 0;
  1141. light_changes = 0;
  1142. texture_changes = 0;
  1143. render_state_changes =0;
  1144. texture_stage_state_changes =0;
  1145. number_of_DX8_calls = 0;
  1146. last_frame_matrix_changes = 0;
  1147. last_frame_material_changes = 0;
  1148. last_frame_vertex_buffer_changes = 0;
  1149. last_frame_index_buffer_changes = 0;
  1150. last_frame_light_changes = 0;
  1151. last_frame_texture_changes = 0;
  1152. last_frame_render_state_changes = 0;
  1153. last_frame_texture_stage_state_changes = 0;
  1154. last_frame_number_of_DX8_calls = 0;
  1155. }
  1156. void DX8Wrapper::Begin_Statistics()
  1157. {
  1158. matrix_changes=0;
  1159. material_changes=0;
  1160. vertex_buffer_changes=0;
  1161. index_buffer_changes=0;
  1162. light_changes=0;
  1163. texture_changes = 0;
  1164. render_state_changes =0;
  1165. texture_stage_state_changes =0;
  1166. number_of_DX8_calls=0;
  1167. }
  1168. void DX8Wrapper::End_Statistics()
  1169. {
  1170. last_frame_matrix_changes=matrix_changes;
  1171. last_frame_material_changes=material_changes;
  1172. last_frame_vertex_buffer_changes=vertex_buffer_changes;
  1173. last_frame_index_buffer_changes=index_buffer_changes;
  1174. last_frame_light_changes=light_changes;
  1175. last_frame_texture_changes = texture_changes;
  1176. last_frame_render_state_changes = render_state_changes;
  1177. last_frame_texture_stage_state_changes = texture_stage_state_changes;
  1178. last_frame_number_of_DX8_calls=number_of_DX8_calls;
  1179. }
  1180. unsigned DX8Wrapper::Get_Last_Frame_Matrix_Changes() { return last_frame_matrix_changes; }
  1181. unsigned DX8Wrapper::Get_Last_Frame_Material_Changes() { return last_frame_material_changes; }
  1182. unsigned DX8Wrapper::Get_Last_Frame_Vertex_Buffer_Changes() { return last_frame_vertex_buffer_changes; }
  1183. unsigned DX8Wrapper::Get_Last_Frame_Index_Buffer_Changes() { return last_frame_index_buffer_changes; }
  1184. unsigned DX8Wrapper::Get_Last_Frame_Light_Changes() { return last_frame_light_changes; }
  1185. unsigned DX8Wrapper::Get_Last_Frame_Texture_Changes() { return last_frame_texture_changes; }
  1186. unsigned DX8Wrapper::Get_Last_Frame_Render_State_Changes() { return last_frame_render_state_changes; }
  1187. unsigned DX8Wrapper::Get_Last_Frame_Texture_Stage_State_Changes() { return last_frame_texture_stage_state_changes; }
  1188. unsigned DX8Wrapper::Get_Last_Frame_DX8_Calls() { return last_frame_number_of_DX8_calls; }
  1189. unsigned long DX8Wrapper::Get_FrameCount(void) {return FrameCount;}
  1190. void DX8_Assert()
  1191. {
  1192. WWASSERT(DX8Wrapper::_Get_D3D8());
  1193. DX8_THREAD_ASSERT();
  1194. }
  1195. void DX8Wrapper::Begin_Scene(void)
  1196. {
  1197. DX8_THREAD_ASSERT();
  1198. DX8CALL(BeginScene());
  1199. DX8WebBrowser::Update();
  1200. }
  1201. void DX8Wrapper::End_Scene(bool flip_frames)
  1202. {
  1203. DX8_THREAD_ASSERT();
  1204. DX8CALL(EndScene());
  1205. DX8WebBrowser::Render(0);
  1206. if (flip_frames) {
  1207. DX8_Assert();
  1208. HRESULT hr=_Get_D3D_Device8()->Present(NULL, NULL, NULL, NULL);
  1209. number_of_DX8_calls++;
  1210. if (SUCCEEDED(hr)) {
  1211. #ifdef EXTENDED_STATS
  1212. if (stats.m_sleepTime) {
  1213. ::Sleep(stats.m_sleepTime);
  1214. }
  1215. #endif
  1216. FrameCount++;
  1217. }
  1218. // If the device was lost we need to check for cooperative level and possibly reset the device
  1219. if (hr==D3DERR_DEVICELOST) {
  1220. hr=_Get_D3D_Device8()->TestCooperativeLevel();
  1221. if (hr==D3DERR_DEVICENOTRESET) {
  1222. Reset_Device();
  1223. }
  1224. }
  1225. else {
  1226. DX8_ErrorCode(hr);
  1227. }
  1228. }
  1229. // Each frame, release all of the buffers and textures.
  1230. Set_Vertex_Buffer(NULL);
  1231. Set_Index_Buffer(NULL,0);
  1232. for (unsigned i=0;i<MAX_TEXTURE_STAGES;++i) Set_Texture(i,NULL);
  1233. Set_Material(NULL);
  1234. }
  1235. void DX8Wrapper::Flip_To_Primary(void)
  1236. {
  1237. // If we are fullscreen and the current frame is odd then we need
  1238. // to force a page flip to ensure that the first buffer in the flipping
  1239. // chain is the one visible.
  1240. if (!IsWindowed) {
  1241. DX8_Assert();
  1242. int numBuffers = (_PresentParameters.BackBufferCount + 1);
  1243. int visibleBuffer = (FrameCount % numBuffers);
  1244. int flipCount = ((numBuffers - visibleBuffer) % numBuffers);
  1245. int resetAttempts = 0;
  1246. while ((flipCount > 0) && (resetAttempts < 3)) {
  1247. HRESULT hr = _Get_D3D_Device8()->TestCooperativeLevel();
  1248. if (FAILED(hr)) {
  1249. WWDEBUG_SAY(("TestCooperativeLevel Failed!\n"));
  1250. if (D3DERR_DEVICELOST == hr) {
  1251. WWDEBUG_SAY(("DEVICELOST: Cannot flip to primary.\n"));
  1252. return;
  1253. }
  1254. if (D3DERR_DEVICENOTRESET == hr) {
  1255. WWDEBUG_SAY(("DEVICENOTRESET: Resetting device.\n"));
  1256. Reset_Device();
  1257. resetAttempts++;
  1258. }
  1259. } else {
  1260. WWDEBUG_SAY(("Flipping: %ld\n", FrameCount));
  1261. hr = _Get_D3D_Device8()->Present(NULL, NULL, NULL, NULL);
  1262. if (SUCCEEDED(hr)) {
  1263. FrameCount++;
  1264. WWDEBUG_SAY(("Flip to primary succeeded %ld\n", FrameCount));
  1265. }
  1266. }
  1267. --flipCount;
  1268. }
  1269. }
  1270. }
  1271. void DX8Wrapper::Clear(bool clear_color, bool clear_z_stencil, const Vector3 &color, float dest_alpha, float z, unsigned int stencil)
  1272. {
  1273. DX8_THREAD_ASSERT();
  1274. // If we try to clear a stencil buffer which is not there, the entire call will fail
  1275. bool has_stencil = ( _PresentParameters.AutoDepthStencilFormat == D3DFMT_D15S1 ||
  1276. _PresentParameters.AutoDepthStencilFormat == D3DFMT_D24S8 ||
  1277. _PresentParameters.AutoDepthStencilFormat == D3DFMT_D24X4S4);
  1278. DWORD flags = 0;
  1279. if (clear_color) flags |= D3DCLEAR_TARGET;
  1280. if (clear_z_stencil) flags |= D3DCLEAR_ZBUFFER;
  1281. if (clear_z_stencil && has_stencil) flags |= D3DCLEAR_STENCIL;
  1282. if (flags)
  1283. {
  1284. DX8CALL(Clear(0, NULL, flags, Convert_Color(color,dest_alpha), z, stencil));
  1285. }
  1286. }
  1287. void DX8Wrapper::Set_Viewport(CONST D3DVIEWPORT8* pViewport)
  1288. {
  1289. DX8_THREAD_ASSERT();
  1290. DX8CALL(SetViewport(pViewport));
  1291. }
  1292. // ----------------------------------------------------------------------------
  1293. //
  1294. // Set vertex buffer. A reference to previous vertex buffer is released and
  1295. // this one is assigned the current vertex buffer. The DX8 vertex buffer will
  1296. // actually be set in Apply() which is called by Draw_Indexed_Triangles().
  1297. //
  1298. // ----------------------------------------------------------------------------
  1299. void DX8Wrapper::Set_Vertex_Buffer(const VertexBufferClass* vb)
  1300. {
  1301. render_state.vba_offset=0;
  1302. render_state.vba_count=0;
  1303. if (render_state.vertex_buffer) {
  1304. render_state.vertex_buffer->Release_Engine_Ref();
  1305. }
  1306. REF_PTR_SET(render_state.vertex_buffer,const_cast<VertexBufferClass*>(vb));
  1307. if (vb) {
  1308. vb->Add_Engine_Ref();
  1309. render_state.vertex_buffer_type=vb->Type();
  1310. }
  1311. else {
  1312. render_state.index_buffer_type=BUFFER_TYPE_INVALID;
  1313. }
  1314. render_state_changed|=VERTEX_BUFFER_CHANGED;
  1315. }
  1316. // ----------------------------------------------------------------------------
  1317. //
  1318. // Set index buffer. A reference to previous index buffer is released and
  1319. // this one is assigned the current index buffer. The DX8 index buffer will
  1320. // actually be set in Apply() which is called by Draw_Indexed_Triangles().
  1321. //
  1322. // ----------------------------------------------------------------------------
  1323. void DX8Wrapper::Set_Index_Buffer(const IndexBufferClass* ib,unsigned short index_base_offset)
  1324. {
  1325. render_state.iba_offset=0;
  1326. if (render_state.index_buffer) {
  1327. render_state.index_buffer->Release_Engine_Ref();
  1328. }
  1329. REF_PTR_SET(render_state.index_buffer,const_cast<IndexBufferClass*>(ib));
  1330. render_state.index_base_offset=index_base_offset;
  1331. if (ib) {
  1332. ib->Add_Engine_Ref();
  1333. render_state.index_buffer_type=ib->Type();
  1334. }
  1335. else {
  1336. render_state.index_buffer_type=BUFFER_TYPE_INVALID;
  1337. }
  1338. render_state_changed|=INDEX_BUFFER_CHANGED;
  1339. }
  1340. // ----------------------------------------------------------------------------
  1341. //
  1342. // Set vertex buffer using dynamic access object.
  1343. //
  1344. // ----------------------------------------------------------------------------
  1345. void DX8Wrapper::Set_Vertex_Buffer(const DynamicVBAccessClass& vba_)
  1346. {
  1347. if (render_state.vertex_buffer) render_state.vertex_buffer->Release_Engine_Ref();
  1348. DynamicVBAccessClass& vba=const_cast<DynamicVBAccessClass&>(vba_);
  1349. render_state.vertex_buffer_type=vba.Get_Type();
  1350. render_state.vba_offset=vba.VertexBufferOffset;
  1351. render_state.vba_count=vba.Get_Vertex_Count();
  1352. REF_PTR_SET(render_state.vertex_buffer,vba.VertexBuffer);
  1353. render_state.vertex_buffer->Add_Engine_Ref();
  1354. render_state_changed|=VERTEX_BUFFER_CHANGED;
  1355. render_state_changed|=INDEX_BUFFER_CHANGED; // vba_offset changes so index buffer needs to be reset as well.
  1356. }
  1357. // ----------------------------------------------------------------------------
  1358. //
  1359. // Set index buffer using dynamic access object.
  1360. //
  1361. // ----------------------------------------------------------------------------
  1362. void DX8Wrapper::Set_Index_Buffer(const DynamicIBAccessClass& iba_,unsigned short index_base_offset)
  1363. {
  1364. if (render_state.index_buffer) render_state.index_buffer->Release_Engine_Ref();
  1365. DynamicIBAccessClass& iba=const_cast<DynamicIBAccessClass&>(iba_);
  1366. render_state.index_base_offset=index_base_offset;
  1367. render_state.index_buffer_type=iba.Get_Type();
  1368. render_state.iba_offset=iba.IndexBufferOffset;
  1369. REF_PTR_SET(render_state.index_buffer,iba.IndexBuffer);
  1370. render_state.index_buffer->Add_Engine_Ref();
  1371. render_state_changed|=INDEX_BUFFER_CHANGED;
  1372. }
  1373. // ----------------------------------------------------------------------------
  1374. //
  1375. // Private function for the special case of rendering polygons from sorting
  1376. // index and vertex buffers.
  1377. //
  1378. // ----------------------------------------------------------------------------
  1379. void DX8Wrapper::Draw_Sorting_IB_VB(
  1380. unsigned primitive_type,
  1381. unsigned short start_index,
  1382. unsigned short polygon_count,
  1383. unsigned short min_vertex_index,
  1384. unsigned short vertex_count)
  1385. {
  1386. WWASSERT(render_state.vertex_buffer_type==BUFFER_TYPE_SORTING || render_state.vertex_buffer_type==BUFFER_TYPE_DYNAMIC_SORTING);
  1387. WWASSERT(render_state.index_buffer_type==BUFFER_TYPE_SORTING || render_state.index_buffer_type==BUFFER_TYPE_DYNAMIC_SORTING);
  1388. // Fill dynamic vertex buffer with sorting vertex buffer vertices
  1389. DynamicVBAccessClass dyn_vb_access(BUFFER_TYPE_DYNAMIC_DX8,dynamic_fvf_type,vertex_count);
  1390. {
  1391. DynamicVBAccessClass::WriteLockClass lock(&dyn_vb_access);
  1392. VertexFormatXYZNDUV2* src = static_cast<SortingVertexBufferClass*>(render_state.vertex_buffer)->VertexBuffer;
  1393. VertexFormatXYZNDUV2* dest= lock.Get_Formatted_Vertex_Array();
  1394. src += render_state.vba_offset + render_state.index_base_offset + min_vertex_index;
  1395. unsigned size = dyn_vb_access.FVF_Info().Get_FVF_Size()*vertex_count/sizeof(unsigned);
  1396. unsigned *dest_u =(unsigned*) dest;
  1397. unsigned *src_u = (unsigned*) src;
  1398. for (unsigned i=0;i<size;++i) {
  1399. *dest_u++=*src_u++;
  1400. }
  1401. }
  1402. DX8CALL(SetStreamSource(
  1403. 0,
  1404. static_cast<DX8VertexBufferClass*>(dyn_vb_access.VertexBuffer)->Get_DX8_Vertex_Buffer(),
  1405. dyn_vb_access.FVF_Info().Get_FVF_Size()));
  1406. DX8CALL(SetVertexShader(dyn_vb_access.FVF_Info().Get_FVF()));
  1407. DX8_RECORD_VERTEX_BUFFER_CHANGE();
  1408. unsigned index_count=0;
  1409. switch (primitive_type) {
  1410. case D3DPT_TRIANGLELIST: index_count=polygon_count*3; break;
  1411. case D3DPT_TRIANGLESTRIP: index_count=polygon_count+2; break;
  1412. case D3DPT_TRIANGLEFAN: index_count=polygon_count+2; break;
  1413. default: WWASSERT(0); break; // Unsupported primitive type
  1414. }
  1415. // Fill dynamic index buffer with sorting index buffer vertices
  1416. DynamicIBAccessClass dyn_ib_access(BUFFER_TYPE_DYNAMIC_DX8,index_count);
  1417. {
  1418. DynamicIBAccessClass::WriteLockClass lock(&dyn_ib_access);
  1419. unsigned short* dest=lock.Get_Index_Array();
  1420. unsigned short* src=NULL;
  1421. src=static_cast<SortingIndexBufferClass*>(render_state.index_buffer)->index_buffer;
  1422. src+=render_state.iba_offset+start_index;
  1423. for (unsigned short i=0;i<index_count;++i) {
  1424. unsigned short index=*src++;
  1425. index-=min_vertex_index;
  1426. WWASSERT(index<vertex_count);
  1427. *dest++=index;
  1428. }
  1429. }
  1430. DX8CALL(SetIndices(
  1431. static_cast<DX8IndexBufferClass*>(dyn_ib_access.IndexBuffer)->Get_DX8_Index_Buffer(),
  1432. dyn_vb_access.VertexBufferOffset));
  1433. DX8_RECORD_INDEX_BUFFER_CHANGE();
  1434. DX8CALL(DrawIndexedPrimitive(
  1435. D3DPT_TRIANGLELIST,
  1436. 0, // start vertex
  1437. vertex_count,
  1438. dyn_ib_access.IndexBufferOffset,
  1439. polygon_count));
  1440. DX8_RECORD_RENDER(polygon_count,vertex_count,render_state.shader);
  1441. }
  1442. // ----------------------------------------------------------------------------
  1443. //
  1444. //
  1445. //
  1446. // ----------------------------------------------------------------------------
  1447. void DX8Wrapper::Draw(
  1448. unsigned primitive_type,
  1449. unsigned short start_index,
  1450. unsigned short polygon_count,
  1451. unsigned short min_vertex_index,
  1452. unsigned short vertex_count)
  1453. {
  1454. DX8_THREAD_ASSERT();
  1455. SNAPSHOT_SAY(("DX8 - draw\n"));
  1456. Apply_Render_State_Changes();
  1457. // Debug feature to disable triangle drawing...
  1458. if (!_Is_Triangle_Draw_Enabled()) return;
  1459. SNAPSHOT_SAY(("DX8 - draw %s polygons (%d vertices)\n",polygon_count,vertex_count));
  1460. if (vertex_count<3) {
  1461. min_vertex_index=0;
  1462. switch (render_state.vertex_buffer_type) {
  1463. case BUFFER_TYPE_DX8:
  1464. case BUFFER_TYPE_SORTING:
  1465. vertex_count=render_state.vertex_buffer->Get_Vertex_Count()-render_state.index_base_offset-render_state.vba_offset-min_vertex_index;
  1466. break;
  1467. case BUFFER_TYPE_DYNAMIC_DX8:
  1468. case BUFFER_TYPE_DYNAMIC_SORTING:
  1469. vertex_count=render_state.vba_count;
  1470. break;
  1471. }
  1472. }
  1473. switch (render_state.vertex_buffer_type) {
  1474. case BUFFER_TYPE_DX8:
  1475. case BUFFER_TYPE_DYNAMIC_DX8:
  1476. switch (render_state.index_buffer_type) {
  1477. case BUFFER_TYPE_DX8:
  1478. case BUFFER_TYPE_DYNAMIC_DX8:
  1479. {
  1480. /* if ((start_index+render_state.iba_offset+polygon_count*3) > render_state.index_buffer->Get_Index_Count())
  1481. { WWASSERT_PRINT(0,"OVERFLOWING INDEX BUFFER");
  1482. ///@todo: MUST FIND OUT WHY THIS HAPPENS WITH LOTS OF PARTICLES ON BIG FIGHT! -MW
  1483. break;
  1484. }*/
  1485. DX8_RECORD_RENDER(polygon_count,vertex_count,render_state.shader);
  1486. DX8CALL(DrawIndexedPrimitive(
  1487. (D3DPRIMITIVETYPE)primitive_type,
  1488. min_vertex_index,
  1489. vertex_count,
  1490. start_index+render_state.iba_offset,
  1491. polygon_count));
  1492. }
  1493. break;
  1494. case BUFFER_TYPE_SORTING:
  1495. case BUFFER_TYPE_DYNAMIC_SORTING:
  1496. WWASSERT_PRINT(0,"VB and IB must of same type (sorting or dx8)");
  1497. break;
  1498. case BUFFER_TYPE_INVALID:
  1499. WWASSERT(0);
  1500. break;
  1501. }
  1502. break;
  1503. case BUFFER_TYPE_SORTING:
  1504. case BUFFER_TYPE_DYNAMIC_SORTING:
  1505. switch (render_state.index_buffer_type) {
  1506. case BUFFER_TYPE_DX8:
  1507. case BUFFER_TYPE_DYNAMIC_DX8:
  1508. WWASSERT_PRINT(0,"VB and IB must of same type (sorting or dx8)");
  1509. break;
  1510. case BUFFER_TYPE_SORTING:
  1511. case BUFFER_TYPE_DYNAMIC_SORTING:
  1512. Draw_Sorting_IB_VB(primitive_type,start_index,polygon_count,min_vertex_index,vertex_count);
  1513. break;
  1514. case BUFFER_TYPE_INVALID:
  1515. WWASSERT(0);
  1516. break;
  1517. }
  1518. break;
  1519. case BUFFER_TYPE_INVALID:
  1520. WWASSERT(0);
  1521. break;
  1522. }
  1523. }
  1524. // ----------------------------------------------------------------------------
  1525. //
  1526. //
  1527. //
  1528. // ----------------------------------------------------------------------------
  1529. void DX8Wrapper::Draw_Triangles(
  1530. unsigned buffer_type,
  1531. unsigned short start_index,
  1532. unsigned short polygon_count,
  1533. unsigned short min_vertex_index,
  1534. unsigned short vertex_count)
  1535. {
  1536. if (buffer_type==BUFFER_TYPE_SORTING || buffer_type==BUFFER_TYPE_DYNAMIC_SORTING) {
  1537. SortingRendererClass::Insert_Triangles(start_index,polygon_count,min_vertex_index,vertex_count);
  1538. }
  1539. else {
  1540. Draw(D3DPT_TRIANGLELIST,start_index,polygon_count,min_vertex_index,vertex_count);
  1541. }
  1542. }
  1543. // ----------------------------------------------------------------------------
  1544. //
  1545. //
  1546. //
  1547. // ----------------------------------------------------------------------------
  1548. void DX8Wrapper::Draw_Triangles(
  1549. unsigned short start_index,
  1550. unsigned short polygon_count,
  1551. unsigned short min_vertex_index,
  1552. unsigned short vertex_count)
  1553. {
  1554. Draw(D3DPT_TRIANGLELIST,start_index,polygon_count,min_vertex_index,vertex_count);
  1555. }
  1556. // ----------------------------------------------------------------------------
  1557. //
  1558. //
  1559. //
  1560. // ----------------------------------------------------------------------------
  1561. void DX8Wrapper::Draw_Strip(
  1562. unsigned short start_index,
  1563. unsigned short polygon_count,
  1564. unsigned short min_vertex_index,
  1565. unsigned short vertex_count)
  1566. {
  1567. Draw(D3DPT_TRIANGLESTRIP,start_index,polygon_count,min_vertex_index,vertex_count);
  1568. }
  1569. // ----------------------------------------------------------------------------
  1570. //
  1571. //
  1572. //
  1573. // ----------------------------------------------------------------------------
  1574. void DX8Wrapper::Apply_Render_State_Changes()
  1575. {
  1576. if (!render_state_changed) return;
  1577. if (render_state_changed&SHADER_CHANGED) {
  1578. SNAPSHOT_SAY(("DX8 - apply shader\n"));
  1579. render_state.shader.Apply();
  1580. }
  1581. unsigned mask=TEXTURE0_CHANGED;
  1582. for (unsigned i=0;i<MAX_TEXTURE_STAGES;++i,mask<<=1) {
  1583. if (render_state_changed&mask) {
  1584. SNAPSHOT_SAY(("DX8 - apply texture %d\n",i));
  1585. if (render_state.Textures[i]) render_state.Textures[i]->Apply(i);
  1586. else TextureClass::Apply_Null(i);
  1587. }
  1588. }
  1589. if (render_state_changed&MATERIAL_CHANGED) {
  1590. SNAPSHOT_SAY(("DX8 - apply material\n"));
  1591. VertexMaterialClass* material=const_cast<VertexMaterialClass*>(render_state.material);
  1592. if (material) {
  1593. material->Apply();
  1594. }
  1595. else VertexMaterialClass::Apply_Null();
  1596. }
  1597. if (render_state_changed&LIGHTS_CHANGED)
  1598. {
  1599. unsigned mask=LIGHT0_CHANGED;
  1600. for (unsigned index=0;index<4;++index,mask<<=1) {
  1601. if (render_state_changed&mask) {
  1602. SNAPSHOT_SAY(("DX8 - apply light %d\n",index));
  1603. if (render_state.LightEnable[index]) {
  1604. Set_DX8_Light(index,&render_state.Lights[index]);
  1605. }
  1606. else {
  1607. Set_DX8_Light(index,NULL);
  1608. }
  1609. }
  1610. }
  1611. }
  1612. if (render_state_changed&WORLD_CHANGED) {
  1613. SNAPSHOT_SAY(("DX8 - apply world matrix\n"));
  1614. _Set_DX8_Transform(D3DTS_WORLD,render_state.world);
  1615. }
  1616. if (render_state_changed&VIEW_CHANGED) {
  1617. SNAPSHOT_SAY(("DX8 - apply view matrix\n"));
  1618. _Set_DX8_Transform(D3DTS_VIEW,render_state.view);
  1619. }
  1620. if (render_state_changed&VERTEX_BUFFER_CHANGED) {
  1621. SNAPSHOT_SAY(("DX8 - apply vb change\n"));
  1622. if (render_state.vertex_buffer) {
  1623. switch (render_state.vertex_buffer_type) {//->Type()) {
  1624. case BUFFER_TYPE_DX8:
  1625. case BUFFER_TYPE_DYNAMIC_DX8:
  1626. DX8CALL(SetStreamSource(
  1627. 0,
  1628. static_cast<DX8VertexBufferClass*>(render_state.vertex_buffer)->Get_DX8_Vertex_Buffer(),
  1629. render_state.vertex_buffer->FVF_Info().Get_FVF_Size()));
  1630. DX8_RECORD_VERTEX_BUFFER_CHANGE();
  1631. DX8CALL(SetVertexShader(render_state.vertex_buffer->FVF_Info().Get_FVF()));
  1632. break;
  1633. case BUFFER_TYPE_SORTING:
  1634. case BUFFER_TYPE_DYNAMIC_SORTING:
  1635. break;
  1636. default:
  1637. WWASSERT(0);
  1638. }
  1639. } else {
  1640. DX8CALL(SetStreamSource(0,NULL,0));
  1641. DX8_RECORD_VERTEX_BUFFER_CHANGE();
  1642. }
  1643. }
  1644. if (render_state_changed&INDEX_BUFFER_CHANGED) {
  1645. SNAPSHOT_SAY(("DX8 - apply ib change\n"));
  1646. if (render_state.index_buffer) {
  1647. switch (render_state.index_buffer_type) {//->Type()) {
  1648. case BUFFER_TYPE_DX8:
  1649. case BUFFER_TYPE_DYNAMIC_DX8:
  1650. DX8CALL(SetIndices(
  1651. static_cast<DX8IndexBufferClass*>(render_state.index_buffer)->Get_DX8_Index_Buffer(),
  1652. render_state.index_base_offset+render_state.vba_offset));
  1653. DX8_RECORD_INDEX_BUFFER_CHANGE();
  1654. break;
  1655. case BUFFER_TYPE_SORTING:
  1656. case BUFFER_TYPE_DYNAMIC_SORTING:
  1657. break;
  1658. default:
  1659. WWASSERT(0);
  1660. }
  1661. }
  1662. else {
  1663. DX8CALL(SetIndices(
  1664. NULL,
  1665. 0));
  1666. DX8_RECORD_INDEX_BUFFER_CHANGE();
  1667. }
  1668. }
  1669. render_state_changed&=((unsigned)WORLD_IDENTITY|(unsigned)VIEW_IDENTITY);
  1670. }
  1671. IDirect3DTexture8 * DX8Wrapper::_Create_DX8_Texture(
  1672. unsigned int width,
  1673. unsigned int height,
  1674. WW3DFormat format,
  1675. TextureClass::MipCountType mip_level_count,
  1676. D3DPOOL pool,
  1677. bool rendertarget)
  1678. {
  1679. DX8_THREAD_ASSERT();
  1680. DX8_Assert();
  1681. IDirect3DTexture8 *texture = NULL;
  1682. // Paletted textures not supported!
  1683. WWASSERT(format!=D3DFMT_P8);
  1684. // NOTE: If 'format' is not supported as a texture format, this function will find the closest
  1685. // format that is supported and use that instead.
  1686. // Render target may return NOTAVAILABLE, in
  1687. // which case we return NULL.
  1688. if (rendertarget) {
  1689. unsigned ret=D3DXCreateTexture(
  1690. DX8Wrapper::_Get_D3D_Device8(),
  1691. width,
  1692. height,
  1693. mip_level_count,
  1694. D3DUSAGE_RENDERTARGET,
  1695. WW3DFormat_To_D3DFormat(format),
  1696. pool,
  1697. &texture);
  1698. if (ret==D3DERR_NOTAVAILABLE) {
  1699. Non_Fatal_Log_DX8_ErrorCode(ret,__FILE__,__LINE__);
  1700. return NULL;
  1701. }
  1702. if (ret==D3DERR_OUTOFVIDEOMEMORY) {
  1703. Non_Fatal_Log_DX8_ErrorCode(ret,__FILE__,__LINE__);
  1704. return NULL;
  1705. }
  1706. DX8_ErrorCode(ret);
  1707. // Just return the texture, no reduction
  1708. // allowed for render targets.
  1709. return texture;
  1710. }
  1711. // Don't allow any errors in non-render target
  1712. // texture creation.
  1713. DX8_ErrorCode(D3DXCreateTexture(
  1714. DX8Wrapper::_Get_D3D_Device8(),
  1715. width,
  1716. height,
  1717. mip_level_count,
  1718. 0,
  1719. WW3DFormat_To_D3DFormat(format),
  1720. pool,
  1721. &texture));
  1722. // unsigned reduction=WW3D::Get_Texture_Reduction();
  1723. // unsigned level_count=texture->GetLevelCount();
  1724. // if (reduction>=level_count) reduction=level_count-1;
  1725. // texture->SetLOD(reduction);
  1726. return texture;
  1727. }
  1728. IDirect3DTexture8 * DX8Wrapper::_Create_DX8_Texture(
  1729. const char *filename,
  1730. TextureClass::MipCountType mip_level_count)
  1731. {
  1732. DX8_THREAD_ASSERT();
  1733. DX8_Assert();
  1734. IDirect3DTexture8 *texture = NULL;
  1735. // NOTE: If the original image format is not supported as a texture format, it will
  1736. // automatically be converted to an appropriate format.
  1737. // NOTE: It is possible to get the size and format of the original image file from this
  1738. // function as well, so if we later want to second-guess D3DX's format conversion decisions
  1739. // we can do so after this function is called..
  1740. unsigned result = D3DXCreateTextureFromFileExA(
  1741. _Get_D3D_Device8(),
  1742. filename,
  1743. D3DX_DEFAULT,
  1744. D3DX_DEFAULT,
  1745. mip_level_count,//create_mipmaps ? 0 : 1,
  1746. 0,
  1747. D3DFMT_UNKNOWN,
  1748. D3DPOOL_MANAGED,
  1749. D3DX_FILTER_BOX,
  1750. D3DX_FILTER_BOX,
  1751. 0,
  1752. NULL,
  1753. NULL,
  1754. &texture);
  1755. if (result != D3D_OK) {
  1756. return MissingTexture::_Get_Missing_Texture();
  1757. }
  1758. // Make sure texture wasn't paletted!
  1759. D3DSURFACE_DESC desc;
  1760. texture->GetLevelDesc(0,&desc);
  1761. if (desc.Format==D3DFMT_P8) {
  1762. texture->Release();
  1763. return MissingTexture::_Get_Missing_Texture();
  1764. }
  1765. else {
  1766. // unsigned reduction=WW3D::Get_Texture_Reduction();
  1767. // unsigned level_count=texture->GetLevelCount();
  1768. // if (reduction>=level_count) reduction=level_count-1;
  1769. // texture->SetLOD(reduction);
  1770. }
  1771. return texture;
  1772. }
  1773. IDirect3DTexture8 * DX8Wrapper::_Create_DX8_Texture(
  1774. IDirect3DSurface8 *surface,
  1775. TextureClass::MipCountType mip_level_count)
  1776. {
  1777. DX8_THREAD_ASSERT();
  1778. DX8_Assert();
  1779. IDirect3DTexture8 *texture = NULL;
  1780. D3DSURFACE_DESC surface_desc;
  1781. ::ZeroMemory(&surface_desc, sizeof(D3DSURFACE_DESC));
  1782. surface->GetDesc(&surface_desc);
  1783. // This function will create a texture with a different (but similar) format if the surface is
  1784. // not in a supported texture format.
  1785. WW3DFormat format=D3DFormat_To_WW3DFormat(surface_desc.Format);
  1786. texture = _Create_DX8_Texture(surface_desc.Width, surface_desc.Height, format, mip_level_count);
  1787. // Copy the surface to the texture
  1788. IDirect3DSurface8 *tex_surface = NULL;
  1789. texture->GetSurfaceLevel(0, &tex_surface);
  1790. DX8_ErrorCode(D3DXLoadSurfaceFromSurface(tex_surface, NULL, NULL, surface, NULL, NULL, D3DX_FILTER_BOX, 0));
  1791. tex_surface->Release();
  1792. // Create mipmaps if needed
  1793. if (mip_level_count!=TextureClass::MIP_LEVELS_1) {
  1794. DX8_ErrorCode(D3DXFilterTexture(texture, NULL, 0, D3DX_FILTER_BOX));
  1795. }
  1796. return texture;
  1797. }
  1798. IDirect3DSurface8 * DX8Wrapper::_Create_DX8_Surface(unsigned int width, unsigned int height, WW3DFormat format)
  1799. {
  1800. DX8_THREAD_ASSERT();
  1801. DX8_Assert();
  1802. IDirect3DSurface8 *surface = NULL;
  1803. // Paletted surfaces not supported!
  1804. WWASSERT(format!=D3DFMT_P8);
  1805. DX8CALL(CreateImageSurface(width, height, WW3DFormat_To_D3DFormat(format), &surface));
  1806. return surface;
  1807. }
  1808. IDirect3DSurface8 * DX8Wrapper::_Create_DX8_Surface(const char *filename_)
  1809. {
  1810. DX8_THREAD_ASSERT();
  1811. DX8_Assert();
  1812. // Note: Since there is no "D3DXCreateSurfaceFromFile" and no "GetSurfaceInfoFromFile" (the
  1813. // latter is supposed to be added to D3DX in a future version), we create a texture from the
  1814. // file (w/o mipmaps), check that its surface is equal to the original file data (which it
  1815. // will not be if the file is not in a texture-supported format or size). If so, copy its
  1816. // surface (we might be able to just get its surface and add a ref to it but I'm not sure so
  1817. // I'm not going to risk it) and release the texture. If not, create a surface according to
  1818. // the file data and use D3DXLoadSurfaceFromFile. This is a horrible hack, but it saves us
  1819. // having to write file loaders. Will fix this when D3DX provides us with the right functions.
  1820. // Create a surface the size of the file image data
  1821. IDirect3DSurface8 *surface = NULL;
  1822. {
  1823. file_auto_ptr myfile(_TheFileFactory,filename_);
  1824. // If file not found, create a surface with missing texture in it
  1825. if (!myfile->Is_Available()) {
  1826. return MissingTexture::_Create_Missing_Surface();
  1827. }
  1828. }
  1829. surface=TextureLoader::Load_Surface_Immediate(
  1830. filename_,
  1831. WW3D_FORMAT_UNKNOWN,
  1832. true);
  1833. return surface;
  1834. }
  1835. /***********************************************************************************************
  1836. * DX8Wrapper::_Update_Texture -- Copies a texture from system memory to video memory *
  1837. * *
  1838. * *
  1839. * *
  1840. * *
  1841. * INPUT: *
  1842. * *
  1843. * OUTPUT: *
  1844. * *
  1845. * WARNINGS: *
  1846. * *
  1847. * HISTORY: *
  1848. * 4/26/2001 hy : Created. *
  1849. *=============================================================================================*/
  1850. void DX8Wrapper::_Update_Texture(TextureClass *system, TextureClass *video)
  1851. {
  1852. WWASSERT(system);
  1853. WWASSERT(video);
  1854. WWASSERT(system->Pool==TextureClass::POOL_SYSTEMMEM);
  1855. WWASSERT(video->Pool==TextureClass::POOL_DEFAULT);
  1856. DX8CALL(UpdateTexture(system->D3DTexture,video->D3DTexture));
  1857. }
  1858. void DX8Wrapper::Compute_Caps(D3DFORMAT display_format,D3DFORMAT depth_stencil_format)
  1859. {
  1860. DX8_THREAD_ASSERT();
  1861. DX8_Assert();
  1862. DX8Caps::Compute_Caps(display_format,depth_stencil_format,D3DDevice);
  1863. }
  1864. void DX8Wrapper::Set_Light(unsigned index,const LightClass &light)
  1865. {
  1866. D3DLIGHT8 dlight;
  1867. Vector3 temp;
  1868. memset(&dlight,0,sizeof(D3DLIGHT8));
  1869. switch (light.Get_Type())
  1870. {
  1871. case LightClass::POINT:
  1872. {
  1873. dlight.Type=D3DLIGHT_POINT;
  1874. }
  1875. break;
  1876. case LightClass::DIRECTIONAL:
  1877. {
  1878. dlight.Type=D3DLIGHT_DIRECTIONAL;
  1879. }
  1880. break;
  1881. case LightClass::SPOT:
  1882. {
  1883. dlight.Type=D3DLIGHT_SPOT;
  1884. }
  1885. break;
  1886. }
  1887. light.Get_Diffuse(&temp);
  1888. temp*=light.Get_Intensity();
  1889. dlight.Diffuse.r=temp.X;
  1890. dlight.Diffuse.g=temp.Y;
  1891. dlight.Diffuse.b=temp.Z;
  1892. dlight.Diffuse.a=1.0f;
  1893. light.Get_Specular(&temp);
  1894. temp*=light.Get_Intensity();
  1895. dlight.Specular.r=temp.X;
  1896. dlight.Specular.g=temp.Y;
  1897. dlight.Specular.b=temp.Z;
  1898. dlight.Specular.a=1.0f;
  1899. light.Get_Ambient(&temp);
  1900. temp*=light.Get_Intensity();
  1901. dlight.Ambient.r=temp.X;
  1902. dlight.Ambient.g=temp.Y;
  1903. dlight.Ambient.b=temp.Z;
  1904. dlight.Ambient.a=1.0f;
  1905. temp=light.Get_Position();
  1906. dlight.Position=*(D3DVECTOR*) &temp;
  1907. light.Get_Spot_Direction(temp);
  1908. dlight.Direction=*(D3DVECTOR*) &temp;
  1909. dlight.Range=light.Get_Attenuation_Range();
  1910. dlight.Falloff=light.Get_Spot_Exponent();
  1911. dlight.Theta=light.Get_Spot_Angle();
  1912. dlight.Phi=light.Get_Spot_Angle();
  1913. // Inverse linear light 1/(1+D)
  1914. double a,b;
  1915. light.Get_Far_Attenuation_Range(a,b);
  1916. dlight.Attenuation0=1.0f;
  1917. if (fabs(a-b)<1e-5)
  1918. // if the attenuation range is too small assume uniform with cutoff
  1919. dlight.Attenuation1=0.0f;
  1920. else
  1921. // this will cause the light to drop to half intensity at the first far attenuation
  1922. dlight.Attenuation1=(float) 1.0/a;
  1923. dlight.Attenuation2=0.0f;
  1924. Set_Light(index,&dlight);
  1925. }
  1926. // ----------------------------------------------------------------------------
  1927. //
  1928. // Set the light environment. This is a lighting model which used up to four
  1929. // directional lights to produce the lighting.
  1930. //
  1931. // ----------------------------------------------------------------------------
  1932. void DX8Wrapper::Set_Light_Environment(LightEnvironmentClass* light_env)
  1933. {
  1934. if (light_env) {
  1935. int light_count = light_env->Get_Light_Count();
  1936. unsigned int color=Convert_Color(light_env->Get_Equivalent_Ambient(),0.0f);
  1937. if (RenderStates[D3DRS_AMBIENT]!=color)
  1938. {
  1939. Set_DX8_Render_State(D3DRS_AMBIENT,color);
  1940. //buggy Radeon 9700 driver doesn't apply new ambient unless the material also changes.
  1941. #if 1
  1942. render_state_changed|=MATERIAL_CHANGED;
  1943. #endif
  1944. }
  1945. D3DLIGHT8 light;
  1946. for (int l=0;l<light_count;++l) {
  1947. ::ZeroMemory(&light, sizeof(D3DLIGHT8));
  1948. light.Type=D3DLIGHT_DIRECTIONAL;
  1949. (Vector3&)light.Diffuse=light_env->Get_Light_Diffuse(l);
  1950. Vector3 dir=-light_env->Get_Light_Direction(l);
  1951. light.Direction=(const D3DVECTOR&)(dir);
  1952. if (light_env->isPointLight(l)) {
  1953. light.Type = D3DLIGHT_POINT;
  1954. (Vector3&)light.Diffuse=light_env->getPointDiffuse(l);
  1955. (Vector3&)light.Ambient=light_env->getPointAmbient(l);
  1956. light.Position = (const D3DVECTOR&)light_env->getPointCenter(l);
  1957. light.Range = light_env->getPointOrad(l);
  1958. // Inverse linear light 1/(1+D)
  1959. double a,b;
  1960. b = light_env->getPointOrad(l);
  1961. a = light_env->getPointIrad(l);
  1962. light.Attenuation0=0.01f;
  1963. if (fabs(a-b)<1e-5)
  1964. // if the attenuation range is too small assume uniform with cutoff
  1965. light.Attenuation1=0.0f;
  1966. else
  1967. // this will cause the light to drop to half intensity at the first far attenuation
  1968. light.Attenuation1=(float) 0.1/a;
  1969. light.Attenuation2=8.0f/(b*b);
  1970. }
  1971. Set_Light(l,&light);
  1972. }
  1973. for (;l<4;++l) {
  1974. Set_Light(l,NULL);
  1975. }
  1976. }
  1977. /* else {
  1978. for (int l=0;l<4;++l) {
  1979. Set_Light(l,NULL);
  1980. }
  1981. }
  1982. */
  1983. }
  1984. IDirect3DSurface8 * DX8Wrapper::_Get_DX8_Front_Buffer()
  1985. {
  1986. DX8_THREAD_ASSERT();
  1987. D3DDISPLAYMODE mode;
  1988. DX8CALL(GetDisplayMode(&mode));
  1989. IDirect3DSurface8 * fb=NULL;
  1990. DX8CALL(CreateImageSurface(mode.Width,mode.Height,D3DFMT_A8R8G8B8,&fb));
  1991. DX8CALL(GetFrontBuffer(fb));
  1992. return fb;
  1993. }
  1994. SurfaceClass * DX8Wrapper::_Get_DX8_Back_Buffer(unsigned int num)
  1995. {
  1996. DX8_THREAD_ASSERT();
  1997. IDirect3DSurface8 * bb;
  1998. SurfaceClass *surf=NULL;
  1999. DX8CALL(GetBackBuffer(num,D3DBACKBUFFER_TYPE_MONO,&bb));
  2000. if (bb)
  2001. {
  2002. surf=NEW_REF(SurfaceClass,(bb));
  2003. bb->Release();
  2004. }
  2005. return surf;
  2006. }
  2007. TextureClass *
  2008. DX8Wrapper::Create_Render_Target (int width, int height, bool alpha)
  2009. {
  2010. DX8_THREAD_ASSERT();
  2011. DX8_Assert();
  2012. const D3DCAPS8& dx8caps=DX8Caps::Get_Default_Caps();
  2013. //
  2014. // Note: We're going to force the width and height to be powers of two and equal
  2015. //
  2016. float poweroftwosize = width;
  2017. if (height > 0 && height < width) {
  2018. poweroftwosize = height;
  2019. }
  2020. poweroftwosize = ::Find_POT (poweroftwosize);
  2021. if (poweroftwosize>dx8caps.MaxTextureWidth) {
  2022. poweroftwosize=dx8caps.MaxTextureWidth;
  2023. }
  2024. if (poweroftwosize>dx8caps.MaxTextureHeight) {
  2025. poweroftwosize=dx8caps.MaxTextureHeight;
  2026. }
  2027. width = height = poweroftwosize;
  2028. //
  2029. // Get the current format of the display
  2030. //
  2031. D3DDISPLAYMODE mode;
  2032. DX8CALL(GetDisplayMode(&mode));
  2033. // If the user requested a render-target texture and this device does not support that
  2034. // feature, return NULL
  2035. HRESULT hr;
  2036. if (alpha)
  2037. {
  2038. //user wants a texture with destination alpha channel - only 1 such format
  2039. //ever exists on current hardware - D3DFMT_A8R8G8B8
  2040. hr = D3DInterface->CheckDeviceFormat( D3DADAPTER_DEFAULT,
  2041. WW3D_DEVTYPE,
  2042. mode.Format,
  2043. D3DUSAGE_RENDERTARGET,
  2044. D3DRTYPE_TEXTURE,
  2045. D3DFMT_A8R8G8B8 );
  2046. mode.Format=D3DFMT_A8R8G8B8;
  2047. }
  2048. else
  2049. {
  2050. hr = D3DInterface->CheckDeviceFormat( D3DADAPTER_DEFAULT,
  2051. WW3D_DEVTYPE,
  2052. mode.Format,
  2053. D3DUSAGE_RENDERTARGET,
  2054. D3DRTYPE_TEXTURE,
  2055. mode.Format );
  2056. }
  2057. number_of_DX8_calls++;
  2058. if (hr != D3D_OK) {
  2059. WWDEBUG_SAY(("DX8Wrapper - Driver cannot create render target!\n"));
  2060. return NULL;
  2061. }
  2062. //
  2063. // Attempt to create the render target
  2064. //
  2065. DX8_Assert();
  2066. WW3DFormat format=D3DFormat_To_WW3DFormat(mode.Format);
  2067. TextureClass * tex = NEW_REF(TextureClass,(width,height,format,TextureClass::MIP_LEVELS_1,TextureClass::POOL_DEFAULT,true));
  2068. // 3dfx drivers are lying in the CheckDeviceFormat call and claiming
  2069. // that they support render targets!
  2070. if (tex->Peek_DX8_Texture() == NULL) {
  2071. WWDEBUG_SAY(("DX8Wrapper - Render target creation failed!\n"));
  2072. REF_PTR_RELEASE(tex);
  2073. }
  2074. return tex;
  2075. }
  2076. void
  2077. DX8Wrapper::Set_Render_Target (TextureClass * texture)
  2078. {
  2079. WWASSERT(texture != NULL);
  2080. SurfaceClass * surf = texture->Get_Surface_Level();
  2081. WWASSERT(surf != NULL);
  2082. Set_Render_Target(surf->Peek_D3D_Surface());
  2083. REF_PTR_RELEASE(surf);
  2084. }
  2085. void
  2086. DX8Wrapper::Set_Render_Target(IDirect3DSwapChain8 *swap_chain)
  2087. {
  2088. DX8_THREAD_ASSERT();
  2089. WWASSERT (swap_chain != NULL);
  2090. //
  2091. // Get the back buffer for the swap chain
  2092. //
  2093. LPDIRECT3DSURFACE8 render_target = NULL;
  2094. swap_chain->GetBackBuffer (0, D3DBACKBUFFER_TYPE_MONO, &render_target);
  2095. //
  2096. // Set this back buffer as the render targer
  2097. //
  2098. Set_Render_Target (render_target);
  2099. //
  2100. // Release our hold on the back buffer
  2101. //
  2102. if (render_target != NULL) {
  2103. render_target->Release ();
  2104. render_target = NULL;
  2105. }
  2106. return ;
  2107. }
  2108. void
  2109. DX8Wrapper::Set_Render_Target(IDirect3DSurface8 *render_target)
  2110. {
  2111. DX8_THREAD_ASSERT();
  2112. DX8_Assert();
  2113. //
  2114. // We'll need the depth buffer later...
  2115. //
  2116. IDirect3DSurface8 *depth_buffer = NULL;
  2117. DX8CALL(GetDepthStencilSurface (&depth_buffer));
  2118. //
  2119. // Should we restore the default render target set a new one?
  2120. //
  2121. if (render_target == NULL || render_target == DefaultRenderTarget) {
  2122. //
  2123. // Restore the default render target
  2124. //
  2125. if (DefaultRenderTarget != NULL) {
  2126. DX8CALL(SetRenderTarget (DefaultRenderTarget, depth_buffer));
  2127. DefaultRenderTarget->Release ();
  2128. DefaultRenderTarget = NULL;
  2129. }
  2130. //
  2131. // Release our hold on the "current" render target
  2132. //
  2133. if (CurrentRenderTarget != NULL) {
  2134. CurrentRenderTarget->Release ();
  2135. CurrentRenderTarget = NULL;
  2136. }
  2137. } else if (render_target != CurrentRenderTarget) {
  2138. //
  2139. // Get a pointer to the default render target (if necessary)
  2140. //
  2141. if (DefaultRenderTarget == NULL) {
  2142. DX8CALL(GetRenderTarget (&DefaultRenderTarget));
  2143. }
  2144. //
  2145. // Release our hold on the old "current" render target
  2146. //
  2147. if (CurrentRenderTarget != NULL) {
  2148. CurrentRenderTarget->Release ();
  2149. CurrentRenderTarget = NULL;
  2150. }
  2151. //
  2152. // Keep a copy of the current render target (for housekeeping)
  2153. //
  2154. CurrentRenderTarget = render_target;
  2155. WWASSERT (CurrentRenderTarget != NULL);
  2156. if (CurrentRenderTarget != NULL) {
  2157. CurrentRenderTarget->AddRef ();
  2158. //
  2159. // Switch render targets
  2160. //
  2161. DX8CALL(SetRenderTarget (CurrentRenderTarget, depth_buffer));
  2162. }
  2163. }
  2164. //
  2165. // Free our hold on the depth buffer
  2166. //
  2167. if (depth_buffer != NULL) {
  2168. depth_buffer->Release ();
  2169. depth_buffer = NULL;
  2170. }
  2171. return ;
  2172. }
  2173. IDirect3DSwapChain8 *
  2174. DX8Wrapper::Create_Additional_Swap_Chain (HWND render_window)
  2175. {
  2176. DX8_Assert();
  2177. //
  2178. // Configure the presentation parameters for a windowed render target
  2179. //
  2180. D3DPRESENT_PARAMETERS params = { 0 };
  2181. params.BackBufferFormat = _PresentParameters.BackBufferFormat;
  2182. params.BackBufferCount = 1;
  2183. params.MultiSampleType = D3DMULTISAMPLE_NONE;
  2184. params.SwapEffect = D3DSWAPEFFECT_COPY_VSYNC;
  2185. params.hDeviceWindow = render_window;
  2186. params.Windowed = TRUE;
  2187. params.EnableAutoDepthStencil = TRUE;
  2188. params.AutoDepthStencilFormat = _PresentParameters.AutoDepthStencilFormat;
  2189. params.Flags = 0;
  2190. params.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
  2191. params.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
  2192. //
  2193. // Create the swap chain
  2194. //
  2195. IDirect3DSwapChain8 *swap_chain = NULL;
  2196. DX8CALL(CreateAdditionalSwapChain(&params, &swap_chain));
  2197. return swap_chain;
  2198. }
  2199. void DX8Wrapper::Flush_DX8_Resource_Manager(unsigned int bytes)
  2200. {
  2201. DX8_Assert();
  2202. DX8CALL(ResourceManagerDiscardBytes(bytes));
  2203. }
  2204. unsigned int DX8Wrapper::Get_Free_Texture_RAM()
  2205. {
  2206. DX8_Assert();
  2207. number_of_DX8_calls++;
  2208. return DX8Wrapper::_Get_D3D_Device8()->GetAvailableTextureMem();
  2209. }
  2210. // Converts a linear gamma ramp to one that is controlled by:
  2211. // Gamma - controls the curvature of the middle of the curve
  2212. // Bright - controls the minimum value of the curve
  2213. // Contrast - controls the difference between the maximum and the minimum of the curve
  2214. void DX8Wrapper::Set_Gamma(float gamma,float bright,float contrast,bool calibrate,bool uselimit)
  2215. {
  2216. gamma=Bound(gamma,0.6f,6.0f);
  2217. bright=Bound(bright,-0.5f,0.5f);
  2218. contrast=Bound(contrast,0.5f,2.0f);
  2219. float oo_gamma=1.0f/gamma;
  2220. DX8_Assert();
  2221. number_of_DX8_calls++;
  2222. DWORD flag=(calibrate?D3DSGR_CALIBRATE:D3DSGR_NO_CALIBRATION);
  2223. D3DGAMMARAMP ramp;
  2224. float limit;
  2225. // IML: I'm not really sure what the intent of the 'limit' variable is. It does not produce useful results for my purposes.
  2226. if (uselimit) {
  2227. limit=(contrast-1)/2*contrast;
  2228. } else {
  2229. limit = 0.0f;
  2230. }
  2231. // HY - arrived at this equation after much trial and error.
  2232. for (int i=0; i<256; i++) {
  2233. float in,out;
  2234. in=i/256.0f;
  2235. float x=in-limit;
  2236. x=Bound(x,0.0f,1.0f);
  2237. x=powf(x,oo_gamma);
  2238. out=contrast*x+bright;
  2239. out=Bound(out,0.0f,1.0f);
  2240. ramp.red[i]=(WORD) (out*65535);
  2241. ramp.green[i]=(WORD) (out*65535);
  2242. ramp.blue[i]=(WORD) (out*65535);
  2243. }
  2244. if (DX8Caps::Support_Gamma()) {
  2245. DX8Wrapper::_Get_D3D_Device8()->SetGammaRamp(flag,&ramp);
  2246. } else {
  2247. HWND hwnd = GetDesktopWindow();
  2248. HDC hdc = GetDC(hwnd);
  2249. if (hdc)
  2250. {
  2251. SetDeviceGammaRamp (hdc, &ramp);
  2252. ReleaseDC (hwnd, hdc);
  2253. }
  2254. }
  2255. }
  2256. //============================================================================
  2257. // DX8Wrapper::getBackBufferFormat
  2258. //============================================================================
  2259. WW3DFormat DX8Wrapper::getBackBufferFormat( void )
  2260. {
  2261. return D3DFormat_To_WW3DFormat( _PresentParameters.BackBufferFormat );
  2262. }