texture.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062
  1. /*
  2. ** Command & Conquer Renegade(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:: /Commando/Code/ww3d2/texture.cpp $*
  25. * *
  26. * $Author:: Steve_t $*
  27. * *
  28. * $Modtime:: 1/09/02 2:57p $*
  29. * *
  30. * $Revision:: 83 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * FileListTextureClass::Load_Frame_Surface -- Load source texture *
  35. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  36. #include "texture.h"
  37. #include <d3d8.h>
  38. #include <stdio.h>
  39. #include <D3dx8core.h>
  40. #include "dx8wrapper.h"
  41. #include "targa.h"
  42. #include <nstrdup.h>
  43. #include "w3d_file.h"
  44. #include "assetmgr.h"
  45. #include "formconv.h"
  46. #include "textureloader.h"
  47. #include "missingtexture.h"
  48. #include "ffactory.h"
  49. #include "dx8caps.h"
  50. #include "dx8texman.h"
  51. #include "meshmatdesc.h"
  52. #include "texturethumbnail.h"
  53. const unsigned DEFAULT_INACTIVATION_TIME=20000;
  54. /*
  55. ** Definitions of static members:
  56. */
  57. static unsigned unused_texture_id;
  58. unsigned _MinTextureFilters[MAX_TEXTURE_STAGES][TextureClass::FILTER_TYPE_COUNT];
  59. unsigned _MagTextureFilters[MAX_TEXTURE_STAGES][TextureClass::FILTER_TYPE_COUNT];
  60. unsigned _MipMapFilters[MAX_TEXTURE_STAGES][TextureClass::FILTER_TYPE_COUNT];
  61. // ----------------------------------------------------------------------------
  62. static int Calculate_Texture_Memory_Usage(const TextureClass* texture,int red_factor=0)
  63. {
  64. // Set performance statistics
  65. int size=0;
  66. IDirect3DTexture8* d3d_texture=const_cast<TextureClass*>(texture)->Peek_DX8_Texture();
  67. if (!d3d_texture) return 0;
  68. for (unsigned i=red_factor;i<d3d_texture->GetLevelCount();++i) {
  69. D3DSURFACE_DESC desc;
  70. DX8_ErrorCode(d3d_texture->GetLevelDesc(i,&desc));
  71. size+=desc.Size;
  72. }
  73. return size;
  74. }
  75. /*************************************************************************
  76. ** TextureClass
  77. *************************************************************************/
  78. TextureClass::TextureClass(unsigned width, unsigned height, WW3DFormat format, MipCountType mip_level_count, PoolType pool,bool rendertarget)
  79. :
  80. D3DTexture(NULL),
  81. texture_id(unused_texture_id++),
  82. Initialized(true),
  83. TextureMinFilter(FILTER_TYPE_DEFAULT),
  84. TextureMagFilter(FILTER_TYPE_DEFAULT),
  85. MipMapFilter((mip_level_count!=MIP_LEVELS_1) ? FILTER_TYPE_DEFAULT : FILTER_TYPE_NONE),
  86. UAddressMode(TEXTURE_ADDRESS_REPEAT),
  87. VAddressMode(TEXTURE_ADDRESS_REPEAT),
  88. MipLevelCount(mip_level_count),
  89. Pool(pool),
  90. Dirty(false),
  91. IsLightmap(false),
  92. IsProcedural(true),
  93. Name(""),
  94. TextureFormat(format),
  95. IsCompressionAllowed(false),
  96. TextureLoadTask(NULL),
  97. ThumbnailLoadTask(NULL),
  98. Width(width),
  99. Height(height),
  100. InactivationTime(0), // Don't inactivate!
  101. ExtendedInactivationTime(0),
  102. LastInactivationSyncTime(0)
  103. {
  104. switch (format) {
  105. case WW3D_FORMAT_DXT1:
  106. case WW3D_FORMAT_DXT2:
  107. case WW3D_FORMAT_DXT3:
  108. case WW3D_FORMAT_DXT4:
  109. case WW3D_FORMAT_DXT5:
  110. IsCompressionAllowed=true;
  111. break;
  112. default:
  113. break;
  114. }
  115. D3DPOOL d3dpool=(D3DPOOL) 0;
  116. switch(pool)
  117. {
  118. case POOL_DEFAULT:
  119. d3dpool=D3DPOOL_DEFAULT;
  120. break;
  121. case POOL_MANAGED:
  122. d3dpool=D3DPOOL_MANAGED;
  123. break;
  124. case POOL_SYSTEMMEM:
  125. d3dpool=D3DPOOL_SYSTEMMEM;
  126. break;
  127. default:
  128. WWASSERT(0);
  129. }
  130. D3DTexture = DX8Wrapper::_Create_DX8_Texture(width, height, format, mip_level_count,d3dpool,rendertarget);
  131. if (pool==POOL_DEFAULT)
  132. {
  133. Dirty=true;
  134. DX8TextureTrackerClass *track=new
  135. DX8TextureTrackerClass(width, height, format, mip_level_count,rendertarget,
  136. this);
  137. DX8TextureManagerClass::Add(track);
  138. }
  139. LastAccessed=WW3D::Get_Sync_Time();
  140. }
  141. // ----------------------------------------------------------------------------
  142. TextureClass::TextureClass(
  143. const char *name,
  144. const char *full_path,
  145. MipCountType mip_level_count,
  146. WW3DFormat texture_format,
  147. bool allow_compression)
  148. :
  149. D3DTexture(NULL),
  150. texture_id(unused_texture_id++),
  151. Initialized(false),
  152. TextureMinFilter(FILTER_TYPE_DEFAULT),
  153. TextureMagFilter(FILTER_TYPE_DEFAULT),
  154. MipMapFilter((mip_level_count!=MIP_LEVELS_1) ? FILTER_TYPE_DEFAULT : FILTER_TYPE_NONE),
  155. UAddressMode(TEXTURE_ADDRESS_REPEAT),
  156. VAddressMode(TEXTURE_ADDRESS_REPEAT),
  157. MipLevelCount(mip_level_count),
  158. Pool(POOL_MANAGED),
  159. Dirty(false),
  160. IsLightmap(false),
  161. IsProcedural(false),
  162. TextureFormat(texture_format),
  163. IsCompressionAllowed(allow_compression),
  164. TextureLoadTask(NULL),
  165. ThumbnailLoadTask(NULL),
  166. Width(0),
  167. Height(0),
  168. InactivationTime(DEFAULT_INACTIVATION_TIME), // Default inactivation time 30 seconds
  169. ExtendedInactivationTime(0),
  170. LastInactivationSyncTime(0)
  171. {
  172. switch (TextureFormat) {
  173. case WW3D_FORMAT_DXT1:
  174. case WW3D_FORMAT_DXT2:
  175. case WW3D_FORMAT_DXT3:
  176. case WW3D_FORMAT_DXT4:
  177. case WW3D_FORMAT_DXT5:
  178. IsCompressionAllowed=true;
  179. break;
  180. case WW3D_FORMAT_U8V8: // Bumpmap
  181. case WW3D_FORMAT_L6V5U5: // Bumpmap
  182. case WW3D_FORMAT_X8L8V8U8: // Bumpmap
  183. // If requesting bumpmap format that isn't available we'll just return the surface in whatever color
  184. // format the texture file is in. (This is illegal case, the format support should always be queried
  185. // before creating a bump texture!)
  186. if (!DX8Wrapper::Is_Initted() || !DX8Wrapper::Get_Current_Caps()->Support_Texture_Format(TextureFormat)) {
  187. TextureFormat=WW3D_FORMAT_UNKNOWN;
  188. }
  189. // If bump format is valid, make sure compression is not allowed so that we don't even attempt to load
  190. // from a compressed file (quality isn't good enough for bump map). Also disable mipmapping.
  191. else {
  192. IsCompressionAllowed=false;
  193. MipLevelCount=MIP_LEVELS_1;
  194. MipMapFilter=FILTER_TYPE_NONE;
  195. }
  196. break;
  197. default:
  198. break;
  199. }
  200. WWASSERT_PRINT(name && name[0], "TextureClass CTor: NULL or empty texture name\n");
  201. int len=strlen(name);
  202. for (int i=0;i<len;++i) {
  203. if (name[i]=='+') {
  204. IsLightmap=true;
  205. // Set bilinear filtering for lightmaps (they are very stretched and
  206. // low detail so we don't care for anisotropic or trilinear filtering...)
  207. TextureMinFilter=FILTER_TYPE_FAST;
  208. TextureMagFilter=FILTER_TYPE_FAST;
  209. if (mip_level_count!=MIP_LEVELS_1) MipMapFilter=FILTER_TYPE_FAST;
  210. break;
  211. }
  212. }
  213. Set_Texture_Name(name);
  214. Set_Full_Path(full_path);
  215. WWASSERT(name[0]!='\0');
  216. if (!WW3D::Is_Texturing_Enabled()) {
  217. Initialized=true;
  218. D3DTexture=0;
  219. }
  220. // Find original size from the thumbnail (but don't create thumbnail texture yet!)
  221. ThumbnailClass* thumb=NULL;
  222. ThumbnailManagerClass* thumb_man=ThumbnailManagerClass::Peek_List().Head();
  223. while (thumb_man) {
  224. thumb=thumb_man->Peek_Thumbnail_Instance(Get_Full_Path());
  225. if (thumb) {
  226. Width=thumb->Get_Original_Texture_Width();
  227. Height=thumb->Get_Original_Texture_Height();
  228. break;
  229. }
  230. thumb_man=thumb_man->Succ();
  231. }
  232. LastAccessed=WW3D::Get_Sync_Time();
  233. // If the thumbnails are not enabled, init the texture at this point to avoid stalling when the
  234. // mesh is rendered.
  235. if (!WW3D::Get_Thumbnail_Enabled()) {
  236. if (TextureLoader::Is_DX8_Thread()) {
  237. Init();
  238. }
  239. }
  240. }
  241. // ----------------------------------------------------------------------------
  242. TextureClass::TextureClass(SurfaceClass *surface, MipCountType mip_level_count)
  243. :
  244. D3DTexture(NULL),
  245. texture_id(unused_texture_id++),
  246. Initialized(true),
  247. TextureMinFilter(FILTER_TYPE_DEFAULT),
  248. TextureMagFilter(FILTER_TYPE_DEFAULT),
  249. MipMapFilter((mip_level_count!=MIP_LEVELS_1) ? FILTER_TYPE_DEFAULT : FILTER_TYPE_NONE),
  250. UAddressMode(TEXTURE_ADDRESS_REPEAT),
  251. VAddressMode(TEXTURE_ADDRESS_REPEAT),
  252. MipLevelCount(mip_level_count),
  253. Pool(POOL_MANAGED),
  254. Dirty(false),
  255. IsLightmap(false),
  256. Name(""),
  257. IsProcedural(true),
  258. TextureFormat(surface->Get_Surface_Format()),
  259. IsCompressionAllowed(false),
  260. TextureLoadTask(NULL),
  261. ThumbnailLoadTask(NULL),
  262. Width(0),
  263. Height(0),
  264. InactivationTime(0), // Don't inactivate
  265. ExtendedInactivationTime(0),
  266. LastInactivationSyncTime(0)
  267. {
  268. SurfaceClass::SurfaceDescription sd;
  269. surface->Get_Description(sd);
  270. Width=sd.Width;
  271. Height=sd.Height;
  272. switch (sd.Format) {
  273. case WW3D_FORMAT_DXT1:
  274. case WW3D_FORMAT_DXT2:
  275. case WW3D_FORMAT_DXT3:
  276. case WW3D_FORMAT_DXT4:
  277. case WW3D_FORMAT_DXT5:
  278. IsCompressionAllowed=true;
  279. break;
  280. default:
  281. break;
  282. }
  283. D3DTexture = DX8Wrapper::_Create_DX8_Texture(surface->Peek_D3D_Surface(), mip_level_count);
  284. LastAccessed=WW3D::Get_Sync_Time();
  285. }
  286. // ----------------------------------------------------------------------------
  287. TextureClass::TextureClass(IDirect3DTexture8* d3d_texture)
  288. :
  289. D3DTexture(d3d_texture),
  290. texture_id(unused_texture_id++),
  291. Initialized(true),
  292. TextureMinFilter(FILTER_TYPE_DEFAULT),
  293. TextureMagFilter(FILTER_TYPE_DEFAULT),
  294. MipMapFilter((d3d_texture->GetLevelCount()!=1) ? FILTER_TYPE_DEFAULT : FILTER_TYPE_NONE),
  295. UAddressMode(TEXTURE_ADDRESS_REPEAT),
  296. VAddressMode(TEXTURE_ADDRESS_REPEAT),
  297. MipLevelCount((MipCountType)d3d_texture->GetLevelCount()),
  298. Pool(POOL_MANAGED),
  299. Dirty(false),
  300. IsLightmap(false),
  301. Name(""),
  302. IsProcedural(true),
  303. IsCompressionAllowed(false),
  304. TextureLoadTask(NULL),
  305. ThumbnailLoadTask(NULL),
  306. Width(0),
  307. Height(0),
  308. InactivationTime(0), // Don't inactivate!
  309. ExtendedInactivationTime(0),
  310. LastInactivationSyncTime(0)
  311. {
  312. D3DTexture->AddRef();
  313. IDirect3DSurface8* surface;
  314. DX8_ErrorCode(D3DTexture->GetSurfaceLevel(0,&surface));
  315. D3DSURFACE_DESC d3d_desc;
  316. ::ZeroMemory(&d3d_desc, sizeof(D3DSURFACE_DESC));
  317. DX8_ErrorCode(surface->GetDesc(&d3d_desc));
  318. Width=d3d_desc.Width;
  319. Height=d3d_desc.Height;
  320. TextureFormat=D3DFormat_To_WW3DFormat(d3d_desc.Format);
  321. switch (TextureFormat) {
  322. case WW3D_FORMAT_DXT1:
  323. case WW3D_FORMAT_DXT2:
  324. case WW3D_FORMAT_DXT3:
  325. case WW3D_FORMAT_DXT4:
  326. case WW3D_FORMAT_DXT5:
  327. IsCompressionAllowed=true;
  328. break;
  329. default:
  330. break;
  331. }
  332. LastAccessed=WW3D::Get_Sync_Time();
  333. }
  334. // ----------------------------------------------------------------------------
  335. TextureClass::~TextureClass(void)
  336. {
  337. delete TextureLoadTask;
  338. TextureLoadTask=NULL;
  339. delete ThumbnailLoadTask;
  340. ThumbnailLoadTask=NULL;
  341. if (D3DTexture) {
  342. D3DTexture->Release();
  343. D3DTexture = NULL;
  344. }
  345. DX8TextureManagerClass::Remove(this);
  346. }
  347. void TextureClass::Invalidate_Old_Unused_Textures(unsigned invalidation_time_override)
  348. {
  349. unsigned synctime=WW3D::Get_Sync_Time();
  350. HashTemplateIterator<StringClass,TextureClass*> ite(WW3DAssetManager::Get_Instance()->Texture_Hash());
  351. // Loop through all the textures in the manager
  352. for (ite.First ();!ite.Is_Done();ite.Next ()) {
  353. TextureClass* tex=ite.Peek_Value();
  354. // Consider invalidating if texture has been initialized and defines inactivation time
  355. if (tex->Initialized && tex->InactivationTime) {
  356. unsigned age=synctime-tex->LastAccessed;
  357. if (invalidation_time_override) {
  358. if (age>invalidation_time_override) {
  359. tex->Invalidate();
  360. tex->LastInactivationSyncTime=synctime;
  361. }
  362. }
  363. else {
  364. // Not used in the last n milliseconds?
  365. if (age>(tex->InactivationTime+tex->ExtendedInactivationTime)) {
  366. tex->Invalidate();
  367. tex->LastInactivationSyncTime=synctime;
  368. }
  369. }
  370. }
  371. }
  372. }
  373. // ----------------------------------------------------------------------------
  374. void TextureClass::Init()
  375. {
  376. // If the texture has already been initialised we should exit now
  377. if (Initialized) return;
  378. // If the texture has recently been inactivated, increase the inactivation time (this texture obviously
  379. // should not have been inactivated yet).
  380. if (InactivationTime && LastInactivationSyncTime) {
  381. if ((WW3D::Get_Sync_Time()-LastInactivationSyncTime)<InactivationTime) {
  382. ExtendedInactivationTime=3*InactivationTime;
  383. }
  384. LastInactivationSyncTime=0;
  385. }
  386. if (!D3DTexture) {
  387. if (!WW3D::Get_Thumbnail_Enabled() || MipLevelCount==MIP_LEVELS_1) {
  388. // if (MipLevelCount==MIP_LEVELS_1) {
  389. TextureLoader::Request_Foreground_Loading(this);
  390. }
  391. else {
  392. WW3DFormat format=TextureFormat;
  393. Load_Locked_Surface();
  394. TextureFormat=format;
  395. }
  396. }
  397. if (!Initialized) {
  398. TextureLoader::Request_Background_Loading(this);
  399. }
  400. LastAccessed=WW3D::Get_Sync_Time();
  401. }
  402. void TextureClass::Invalidate()
  403. {
  404. if (TextureLoadTask) {
  405. return;
  406. }
  407. if (ThumbnailLoadTask) {
  408. return;
  409. }
  410. // Don't invalidate procedural textures
  411. if (IsProcedural) {
  412. return;
  413. }
  414. if (D3DTexture) {
  415. D3DTexture->Release();
  416. D3DTexture = NULL;
  417. }
  418. Initialized=false;
  419. LastAccessed=WW3D::Get_Sync_Time();
  420. }
  421. // ----------------------------------------------------------------------------
  422. void TextureClass::Load_Locked_Surface()
  423. {
  424. if (D3DTexture) D3DTexture->Release();
  425. D3DTexture=0;
  426. TextureLoader::Request_Thumbnail(this);
  427. Initialized=false;
  428. }
  429. // ----------------------------------------------------------------------------
  430. bool TextureClass::Is_Missing_Texture()
  431. {
  432. bool flag = false;
  433. IDirect3DTexture8 *missing_texture = MissingTexture::_Get_Missing_Texture();
  434. if(D3DTexture == missing_texture)
  435. flag = true;
  436. if(missing_texture) {
  437. missing_texture->Release();
  438. }
  439. return flag;
  440. }
  441. // ----------------------------------------------------------------------------
  442. void TextureClass::Set_Texture_Name(const char * name)
  443. {
  444. Name=name;
  445. }
  446. // ----------------------------------------------------------------------------
  447. unsigned int TextureClass::Get_Mip_Level_Count(void)
  448. {
  449. if (!D3DTexture) {
  450. WWASSERT_PRINT(0, "Get_Mip_Level_Count: D3DTexture is NULL!\n");
  451. return 0;
  452. }
  453. return D3DTexture->GetLevelCount();
  454. }
  455. // ----------------------------------------------------------------------------
  456. SurfaceClass *TextureClass::Get_Surface_Level(unsigned int level)
  457. {
  458. if (!D3DTexture) {
  459. WWASSERT_PRINT(0, "Get_Surface_Level: D3DTexture is NULL!\n");
  460. return 0;
  461. }
  462. IDirect3DSurface8 *d3d_surface = NULL;
  463. DX8_ErrorCode(D3DTexture->GetSurfaceLevel(level, &d3d_surface));
  464. SurfaceClass *surface = new SurfaceClass(d3d_surface);
  465. d3d_surface->Release();
  466. return surface;
  467. }
  468. // ----------------------------------------------------------------------------
  469. IDirect3DSurface8 *TextureClass::Get_D3D_Surface_Level(unsigned int level)
  470. {
  471. if (!D3DTexture) {
  472. WWASSERT_PRINT(0, "Get_D3D_Surface_Level: D3DTexture is NULL!\n");
  473. return 0;
  474. }
  475. IDirect3DSurface8 *d3d_surface = NULL;
  476. DX8_ErrorCode(D3DTexture->GetSurfaceLevel(level, &d3d_surface));
  477. return d3d_surface;
  478. }
  479. // ----------------------------------------------------------------------------
  480. unsigned int TextureClass::Get_Priority(void)
  481. {
  482. if (!D3DTexture) {
  483. WWASSERT_PRINT(0, "Get_Priority: D3DTexture is NULL!\n");
  484. return 0;
  485. }
  486. return D3DTexture->GetPriority();
  487. }
  488. // ----------------------------------------------------------------------------
  489. unsigned int TextureClass::Set_Priority(unsigned int priority)
  490. {
  491. if (!D3DTexture) {
  492. WWASSERT_PRINT(0, "Set_Priority: D3DTexture is NULL!\n");
  493. return 0;
  494. }
  495. return D3DTexture->SetPriority(priority);
  496. }
  497. // ----------------------------------------------------------------------------
  498. void TextureClass::Set_Mip_Mapping(FilterType mipmap)
  499. {
  500. if (mipmap != FILTER_TYPE_NONE && Get_Mip_Level_Count() <= 1) {
  501. WWASSERT_PRINT(0, "Trying to enable MipMapping on texture w/o Mip levels!\n");
  502. return;
  503. }
  504. MipMapFilter=mipmap;
  505. }
  506. unsigned TextureClass::Get_Reduction() const
  507. {
  508. if (MipLevelCount==MIP_LEVELS_1) return 0;
  509. int reduction=WW3D::Get_Texture_Reduction();
  510. if (MipLevelCount && reduction>MipLevelCount) {
  511. reduction=MipLevelCount;
  512. }
  513. return reduction;
  514. }
  515. // ----------------------------------------------------------------------------
  516. void TextureClass::Apply(unsigned int stage)
  517. {
  518. if (!Initialized) {
  519. Init();
  520. }
  521. LastAccessed=WW3D::Get_Sync_Time();
  522. DX8_RECORD_TEXTURE(this);
  523. // Set texture itself
  524. if (WW3D::Is_Texturing_Enabled()) {
  525. DX8Wrapper::Set_DX8_Texture(stage, D3DTexture);
  526. } else {
  527. DX8Wrapper::Set_DX8_Texture(stage, NULL);
  528. }
  529. DX8Wrapper::Set_DX8_Texture_Stage_State(stage,D3DTSS_MINFILTER,_MinTextureFilters[stage][TextureMinFilter]);
  530. DX8Wrapper::Set_DX8_Texture_Stage_State(stage,D3DTSS_MAGFILTER,_MagTextureFilters[stage][TextureMagFilter]);
  531. DX8Wrapper::Set_DX8_Texture_Stage_State(stage,D3DTSS_MIPFILTER,_MipMapFilters[stage][MipMapFilter]);
  532. switch (Get_U_Addr_Mode()) {
  533. case TEXTURE_ADDRESS_REPEAT:
  534. DX8Wrapper::Set_DX8_Texture_Stage_State(stage, D3DTSS_ADDRESSU, D3DTADDRESS_WRAP);
  535. break;
  536. case TEXTURE_ADDRESS_CLAMP:
  537. DX8Wrapper::Set_DX8_Texture_Stage_State(stage, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP);
  538. break;
  539. }
  540. switch (Get_V_Addr_Mode()) {
  541. case TEXTURE_ADDRESS_REPEAT:
  542. DX8Wrapper::Set_DX8_Texture_Stage_State(stage, D3DTSS_ADDRESSV, D3DTADDRESS_WRAP);
  543. break;
  544. case TEXTURE_ADDRESS_CLAMP:
  545. DX8Wrapper::Set_DX8_Texture_Stage_State(stage, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP);
  546. break;
  547. }
  548. }
  549. // ----------------------------------------------------------------------------
  550. void TextureClass::Apply_Null(unsigned int stage)
  551. {
  552. // This function sets the render states for a "NULL" texture
  553. DX8Wrapper::Set_DX8_Texture(stage, NULL);
  554. }
  555. // ----------------------------------------------------------------------------
  556. void TextureClass::Apply_New_Surface(IDirect3DTexture8* d3d_texture,bool initialized)
  557. {
  558. if (D3DTexture) D3DTexture->Release();
  559. D3DTexture=d3d_texture;//TextureLoadTask->Peek_D3D_Texture();
  560. D3DTexture->AddRef();
  561. if (initialized) Initialized=true;
  562. WWASSERT(D3DTexture);
  563. IDirect3DSurface8* surface;
  564. DX8_ErrorCode(D3DTexture->GetSurfaceLevel(0,&surface));
  565. D3DSURFACE_DESC d3d_desc;
  566. ::ZeroMemory(&d3d_desc, sizeof(D3DSURFACE_DESC));
  567. DX8_ErrorCode(surface->GetDesc(&d3d_desc));
  568. if (initialized) {
  569. TextureFormat=D3DFormat_To_WW3DFormat(d3d_desc.Format);
  570. Width=d3d_desc.Width;
  571. Height=d3d_desc.Height;
  572. }
  573. surface->Release();
  574. }
  575. // ----------------------------------------------------------------------------
  576. unsigned TextureClass::Get_Texture_Memory_Usage() const
  577. {
  578. if (!Initialized) return Calculate_Texture_Memory_Usage(this,0);
  579. return Calculate_Texture_Memory_Usage(this,0);
  580. }
  581. // ----------------------------------------------------------------------------
  582. int TextureClass::_Get_Total_Locked_Surface_Size()
  583. {
  584. int total_locked_surface_size=0;
  585. HashTemplateIterator<StringClass,TextureClass*> ite(WW3DAssetManager::Get_Instance()->Texture_Hash());
  586. // Loop through all the textures in the manager
  587. for (ite.First ();!ite.Is_Done();ite.Next ()) {
  588. // Get the current texture
  589. TextureClass* tex=ite.Peek_Value();
  590. if (!tex->Initialized) {
  591. total_locked_surface_size+=tex->Get_Texture_Memory_Usage();
  592. }
  593. }
  594. return total_locked_surface_size;
  595. }
  596. // ----------------------------------------------------------------------------
  597. int TextureClass::_Get_Total_Texture_Size()
  598. {
  599. int total_texture_size=0;
  600. HashTemplateIterator<StringClass,TextureClass*> ite(WW3DAssetManager::Get_Instance()->Texture_Hash());
  601. // Loop through all the textures in the manager
  602. for (ite.First ();!ite.Is_Done();ite.Next ()) {
  603. // Get the current texture
  604. TextureClass* tex=ite.Peek_Value();
  605. total_texture_size+=tex->Get_Texture_Memory_Usage();
  606. }
  607. return total_texture_size;
  608. }
  609. // ----------------------------------------------------------------------------
  610. int TextureClass::_Get_Total_Lightmap_Texture_Size()
  611. {
  612. int total_texture_size=0;
  613. HashTemplateIterator<StringClass,TextureClass*> ite(WW3DAssetManager::Get_Instance()->Texture_Hash());
  614. // Loop through all the textures in the manager
  615. for (ite.First ();!ite.Is_Done();ite.Next ()) {
  616. // Get the current texture
  617. TextureClass* tex=ite.Peek_Value();
  618. if (tex->Is_Lightmap()) {
  619. total_texture_size+=tex->Get_Texture_Memory_Usage();
  620. }
  621. }
  622. return total_texture_size;
  623. }
  624. // ----------------------------------------------------------------------------
  625. int TextureClass::_Get_Total_Procedural_Texture_Size()
  626. {
  627. int total_texture_size=0;
  628. HashTemplateIterator<StringClass,TextureClass*> ite(WW3DAssetManager::Get_Instance()->Texture_Hash());
  629. // Loop through all the textures in the manager
  630. for (ite.First ();!ite.Is_Done();ite.Next ()) {
  631. // Get the current texture
  632. TextureClass* tex=ite.Peek_Value();
  633. if (tex->Is_Procedural()) {
  634. total_texture_size+=tex->Get_Texture_Memory_Usage();
  635. }
  636. }
  637. return total_texture_size;
  638. }
  639. // ----------------------------------------------------------------------------
  640. int TextureClass::_Get_Total_Texture_Count()
  641. {
  642. int texture_count=0;
  643. HashTemplateIterator<StringClass,TextureClass*> ite(WW3DAssetManager::Get_Instance()->Texture_Hash());
  644. // Loop through all the textures in the manager
  645. for (ite.First ();!ite.Is_Done();ite.Next ()) {
  646. texture_count++;
  647. }
  648. return texture_count;
  649. }
  650. // ----------------------------------------------------------------------------
  651. int TextureClass::_Get_Total_Lightmap_Texture_Count()
  652. {
  653. int texture_count=0;
  654. HashTemplateIterator<StringClass,TextureClass*> ite(WW3DAssetManager::Get_Instance()->Texture_Hash());
  655. // Loop through all the textures in the manager
  656. for (ite.First ();!ite.Is_Done();ite.Next ()) {
  657. if (ite.Peek_Value()->Is_Lightmap()) {
  658. texture_count++;
  659. }
  660. }
  661. return texture_count;
  662. }
  663. // ----------------------------------------------------------------------------
  664. int TextureClass::_Get_Total_Procedural_Texture_Count()
  665. {
  666. int texture_count=0;
  667. HashTemplateIterator<StringClass,TextureClass*> ite(WW3DAssetManager::Get_Instance()->Texture_Hash());
  668. // Loop through all the textures in the manager
  669. for (ite.First ();!ite.Is_Done();ite.Next ()) {
  670. if (ite.Peek_Value()->Is_Procedural()) {
  671. texture_count++;
  672. }
  673. }
  674. return texture_count;
  675. }
  676. // ----------------------------------------------------------------------------
  677. int TextureClass::_Get_Total_Locked_Surface_Count()
  678. {
  679. int texture_count=0;
  680. HashTemplateIterator<StringClass,TextureClass*> ite(WW3DAssetManager::Get_Instance()->Texture_Hash());
  681. // Loop through all the textures in the manager
  682. for (ite.First ();!ite.Is_Done();ite.Next ()) {
  683. // Get the current texture
  684. TextureClass* tex=ite.Peek_Value();
  685. if (!tex->Initialized) {
  686. texture_count++;
  687. }
  688. }
  689. return texture_count;
  690. }
  691. void TextureClass::_Init_Filters(TextureClass::TextureFilterMode filter_type)
  692. {
  693. const D3DCAPS8& dx8caps=DX8Wrapper::Get_Current_Caps()->Get_DX8_Caps();
  694. _MinTextureFilters[0][FILTER_TYPE_NONE]=D3DTEXF_POINT;
  695. _MagTextureFilters[0][FILTER_TYPE_NONE]=D3DTEXF_POINT;
  696. _MipMapFilters[0][FILTER_TYPE_NONE]=D3DTEXF_NONE;
  697. _MinTextureFilters[0][FILTER_TYPE_FAST]=D3DTEXF_LINEAR;
  698. _MagTextureFilters[0][FILTER_TYPE_FAST]=D3DTEXF_LINEAR;
  699. _MipMapFilters[0][FILTER_TYPE_FAST]=D3DTEXF_POINT;
  700. _MagTextureFilters[0][FILTER_TYPE_BEST]=D3DTEXF_POINT;
  701. _MinTextureFilters[0][FILTER_TYPE_BEST]=D3DTEXF_POINT;
  702. _MipMapFilters[0][FILTER_TYPE_BEST]=D3DTEXF_POINT;
  703. if (dx8caps.TextureFilterCaps&D3DPTFILTERCAPS_MAGFLINEAR) _MagTextureFilters[0][FILTER_TYPE_BEST]=D3DTEXF_LINEAR;
  704. if (dx8caps.TextureFilterCaps&D3DPTFILTERCAPS_MINFLINEAR) _MinTextureFilters[0][FILTER_TYPE_BEST]=D3DTEXF_LINEAR;
  705. // Set anisotropic filtering only if requested and available
  706. if (filter_type==TextureClass::TEXTURE_FILTER_ANISOTROPIC) {
  707. if (dx8caps.TextureFilterCaps&D3DPTFILTERCAPS_MAGFANISOTROPIC) _MagTextureFilters[0][FILTER_TYPE_BEST]=D3DTEXF_ANISOTROPIC;
  708. if (dx8caps.TextureFilterCaps&D3DPTFILTERCAPS_MINFANISOTROPIC) _MinTextureFilters[0][FILTER_TYPE_BEST]=D3DTEXF_ANISOTROPIC;
  709. }
  710. // Set linear mip filter only if requested trilinear or anisotropic, and linear available
  711. if (filter_type==TextureClass::TEXTURE_FILTER_ANISOTROPIC || filter_type==TextureClass::TEXTURE_FILTER_TRILINEAR) {
  712. if (dx8caps.TextureFilterCaps&D3DPTFILTERCAPS_MIPFLINEAR) _MipMapFilters[0][FILTER_TYPE_BEST]=D3DTEXF_LINEAR;
  713. }
  714. // For stages above zero, set best filter to the same as the stage zero, except if anisotropic
  715. for (int i=1;i<MAX_TEXTURE_STAGES;++i) {
  716. /* _MinTextureFilters[i][FILTER_TYPE_NONE]=D3DTEXF_POINT;
  717. _MagTextureFilters[i][FILTER_TYPE_NONE]=D3DTEXF_POINT;
  718. _MipMapFilters[i][FILTER_TYPE_NONE]=D3DTEXF_NONE;
  719. _MinTextureFilters[i][FILTER_TYPE_FAST]=D3DTEXF_LINEAR;
  720. _MagTextureFilters[i][FILTER_TYPE_FAST]=D3DTEXF_LINEAR;
  721. _MipMapFilters[i][FILTER_TYPE_FAST]=D3DTEXF_POINT;
  722. _MagTextureFilters[i][FILTER_TYPE_BEST]=D3DTEXF_LINEAR;
  723. _MinTextureFilters[i][FILTER_TYPE_BEST]=D3DTEXF_LINEAR;
  724. _MipMapFilters[i][FILTER_TYPE_BEST]=D3DTEXF_POINT;
  725. */
  726. _MinTextureFilters[i][FILTER_TYPE_NONE]=_MinTextureFilters[i-1][FILTER_TYPE_NONE];
  727. _MagTextureFilters[i][FILTER_TYPE_NONE]=_MagTextureFilters[i-1][FILTER_TYPE_NONE];
  728. _MipMapFilters[i][FILTER_TYPE_NONE]=_MipMapFilters[i-1][FILTER_TYPE_NONE];
  729. _MinTextureFilters[i][FILTER_TYPE_FAST]=_MinTextureFilters[i-1][FILTER_TYPE_FAST];
  730. _MagTextureFilters[i][FILTER_TYPE_FAST]=_MagTextureFilters[i-1][FILTER_TYPE_FAST];
  731. _MipMapFilters[i][FILTER_TYPE_FAST]=_MipMapFilters[i-1][FILTER_TYPE_FAST];
  732. if (_MagTextureFilters[i-1][FILTER_TYPE_BEST]==D3DTEXF_ANISOTROPIC) {
  733. _MagTextureFilters[i][FILTER_TYPE_BEST]=D3DTEXF_LINEAR;
  734. }
  735. else {
  736. _MagTextureFilters[i][FILTER_TYPE_BEST]=_MagTextureFilters[i-1][FILTER_TYPE_BEST];
  737. }
  738. if (_MinTextureFilters[i-1][FILTER_TYPE_BEST]==D3DTEXF_ANISOTROPIC) {
  739. _MinTextureFilters[i][FILTER_TYPE_BEST]=D3DTEXF_LINEAR;
  740. }
  741. else {
  742. _MinTextureFilters[i][FILTER_TYPE_BEST]=_MinTextureFilters[i-1][FILTER_TYPE_BEST];
  743. }
  744. _MipMapFilters[i][FILTER_TYPE_BEST]=_MipMapFilters[i-1][FILTER_TYPE_BEST];
  745. }
  746. // Set default to best. The level of best filter mode is controlled by the input parameter.
  747. for (i=0;i<MAX_TEXTURE_STAGES;++i) {
  748. _MinTextureFilters[i][FILTER_TYPE_DEFAULT]=_MinTextureFilters[i][FILTER_TYPE_BEST];
  749. _MagTextureFilters[i][FILTER_TYPE_DEFAULT]=_MagTextureFilters[i][FILTER_TYPE_BEST];
  750. _MipMapFilters[i][FILTER_TYPE_DEFAULT]=_MipMapFilters[i][FILTER_TYPE_BEST];
  751. DX8Wrapper::Set_DX8_Texture_Stage_State(i,D3DTSS_MAXANISOTROPY,2);
  752. }
  753. }
  754. void TextureClass::_Set_Default_Min_Filter(FilterType filter)
  755. {
  756. for (int i=0;i<MAX_TEXTURE_STAGES;++i) {
  757. _MinTextureFilters[i][FILTER_TYPE_DEFAULT]=_MinTextureFilters[i][filter];
  758. }
  759. }
  760. void TextureClass::_Set_Default_Mag_Filter(FilterType filter)
  761. {
  762. for (int i=0;i<MAX_TEXTURE_STAGES;++i) {
  763. _MagTextureFilters[i][FILTER_TYPE_DEFAULT]=_MagTextureFilters[i][filter];
  764. }
  765. }
  766. void TextureClass::_Set_Default_Mip_Filter(FilterType filter)
  767. {
  768. for (int i=0;i<MAX_TEXTURE_STAGES;++i) {
  769. _MipMapFilters[i][FILTER_TYPE_DEFAULT]=_MipMapFilters[i][filter];
  770. }
  771. }
  772. // Utility functions
  773. TextureClass *Load_Texture(ChunkLoadClass & cload)
  774. {
  775. // Assume failure
  776. TextureClass *newtex = NULL;
  777. char name[256];
  778. if (cload.Open_Chunk () && (cload.Cur_Chunk_ID () == W3D_CHUNK_TEXTURE)) {
  779. W3dTextureInfoStruct texinfo;
  780. bool hastexinfo = false;
  781. /*
  782. ** Read in the texture filename, and a possible texture info structure.
  783. */
  784. while (cload.Open_Chunk()) {
  785. switch (cload.Cur_Chunk_ID()) {
  786. case W3D_CHUNK_TEXTURE_NAME:
  787. cload.Read(&name,cload.Cur_Chunk_Length());
  788. break;
  789. case W3D_CHUNK_TEXTURE_INFO:
  790. cload.Read(&texinfo,sizeof(W3dTextureInfoStruct));
  791. hastexinfo = true;
  792. break;
  793. };
  794. cload.Close_Chunk();
  795. }
  796. cload.Close_Chunk();
  797. /*
  798. ** Get the texture from the asset manager
  799. */
  800. if (hastexinfo) {
  801. TextureClass::MipCountType mipcount;
  802. bool no_lod = ((texinfo.Attributes & W3DTEXTURE_NO_LOD) == W3DTEXTURE_NO_LOD);
  803. if (no_lod) {
  804. mipcount = TextureClass::MIP_LEVELS_1;
  805. } else {
  806. switch (texinfo.Attributes & W3DTEXTURE_MIP_LEVELS_MASK) {
  807. case W3DTEXTURE_MIP_LEVELS_ALL:
  808. mipcount = TextureClass::MIP_LEVELS_ALL;
  809. break;
  810. case W3DTEXTURE_MIP_LEVELS_2:
  811. mipcount = TextureClass::MIP_LEVELS_2;
  812. break;
  813. case W3DTEXTURE_MIP_LEVELS_3:
  814. mipcount = TextureClass::MIP_LEVELS_3;
  815. break;
  816. case W3DTEXTURE_MIP_LEVELS_4:
  817. mipcount = TextureClass::MIP_LEVELS_4;
  818. break;
  819. default:
  820. WWASSERT (false);
  821. mipcount = TextureClass::MIP_LEVELS_ALL;
  822. break;
  823. }
  824. }
  825. WW3DFormat format=WW3D_FORMAT_UNKNOWN;
  826. switch (texinfo.Attributes & W3DTEXTURE_TYPE_MASK) {
  827. case W3DTEXTURE_TYPE_COLORMAP:
  828. // Do nothing.
  829. break;
  830. case W3DTEXTURE_TYPE_BUMPMAP:
  831. {
  832. if (DX8Wrapper::Is_Initted() && DX8Wrapper::Get_Current_Caps()->Support_Bump_Envmap()) {
  833. // No mipmaps to bumpmap for now
  834. mipcount=TextureClass::MIP_LEVELS_1;
  835. if (DX8Wrapper::Get_Current_Caps()->Support_Texture_Format(WW3D_FORMAT_U8V8)) format=WW3D_FORMAT_U8V8;
  836. else if (DX8Wrapper::Get_Current_Caps()->Support_Texture_Format(WW3D_FORMAT_X8L8V8U8)) format=WW3D_FORMAT_X8L8V8U8;
  837. else if (DX8Wrapper::Get_Current_Caps()->Support_Texture_Format(WW3D_FORMAT_L6V5U5)) format=WW3D_FORMAT_L6V5U5;
  838. }
  839. break;
  840. }
  841. default:
  842. WWASSERT (false);
  843. break;
  844. }
  845. newtex = WW3DAssetManager::Get_Instance()->Get_Texture (name, mipcount, format);
  846. if (no_lod) {
  847. newtex->Set_Mip_Mapping(TextureClass::FILTER_TYPE_NONE);
  848. }
  849. bool u_clamp = ((texinfo.Attributes & W3DTEXTURE_CLAMP_U) != 0);
  850. newtex->Set_U_Addr_Mode(u_clamp ? TextureClass::TEXTURE_ADDRESS_CLAMP : TextureClass::TEXTURE_ADDRESS_REPEAT);
  851. bool v_clamp = ((texinfo.Attributes & W3DTEXTURE_CLAMP_V) != 0);
  852. newtex->Set_V_Addr_Mode(v_clamp ? TextureClass::TEXTURE_ADDRESS_CLAMP : TextureClass::TEXTURE_ADDRESS_REPEAT);
  853. } else {
  854. newtex = WW3DAssetManager::Get_Instance()->Get_Texture(name);
  855. }
  856. WWASSERT(newtex);
  857. }
  858. // Return a pointer to the new texture
  859. return newtex;
  860. }
  861. // Utility function used by Save_Texture
  862. void setup_texture_attributes(TextureClass * tex, W3dTextureInfoStruct * texinfo)
  863. {
  864. texinfo->Attributes = 0;
  865. if (tex->Get_Mip_Mapping() == TextureClass::FILTER_TYPE_NONE) texinfo->Attributes |= W3DTEXTURE_NO_LOD;
  866. if (tex->Get_U_Addr_Mode() == TextureClass::TEXTURE_ADDRESS_CLAMP) texinfo->Attributes |= W3DTEXTURE_CLAMP_U;
  867. if (tex->Get_V_Addr_Mode() == TextureClass::TEXTURE_ADDRESS_CLAMP) texinfo->Attributes |= W3DTEXTURE_CLAMP_V;
  868. }
  869. void Save_Texture(TextureClass * texture,ChunkSaveClass & csave)
  870. {
  871. const char * filename;
  872. W3dTextureInfoStruct texinfo;
  873. memset(&texinfo,0,sizeof(texinfo));
  874. filename = texture->Get_Full_Path();
  875. setup_texture_attributes(texture, &texinfo);
  876. csave.Begin_Chunk(W3D_CHUNK_TEXTURE_NAME);
  877. csave.Write(filename,strlen(filename)+1);
  878. csave.End_Chunk();
  879. if ((texinfo.Attributes != 0) || (texinfo.AnimType != 0) || (texinfo.FrameCount != 0)) {
  880. csave.Begin_Chunk(W3D_CHUNK_TEXTURE_INFO);
  881. csave.Write(&texinfo, sizeof(texinfo));
  882. csave.End_Chunk();
  883. }
  884. }