textureloader.cpp 72 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824
  1. /*
  2. ** Command & Conquer Generals Zero Hour(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** 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 : DX8 Texture Manager *
  23. * *
  24. * $Archive:: /Commando/Code/ww3d2/textureloader.h $*
  25. * *
  26. * Original Author:: vss_sync *
  27. * *
  28. * Author : Kenny Mitchell *
  29. * *
  30. * $Modtime:: 08/05/02 10:03a $*
  31. * *
  32. * $Revision:: 3 $*
  33. * *
  34. * 06/27/02 KM Texture class abstraction *
  35. * 08/05/02 KM Texture class redesign (revisited)
  36. *---------------------------------------------------------------------------------------------*
  37. * Functions: *
  38. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  39. #include "textureloader.h"
  40. #include "mutex.h"
  41. #include "thread.h"
  42. #include "wwdebug.h"
  43. #include "texture.h"
  44. #include "ffactory.h"
  45. #include "wwstring.h"
  46. #include "bufffile.h"
  47. #include "ww3d.h"
  48. #include "texfcach.h"
  49. #include "assetmgr.h"
  50. #include "dx8wrapper.h"
  51. #include "dx8caps.h"
  52. #include "missingtexture.h"
  53. #include "targa.h"
  54. #include <D3dx8tex.h>
  55. #include <cstdio>
  56. #include "wwmemlog.h"
  57. #include "texture.h"
  58. #include "formconv.h"
  59. #include "texturethumbnail.h"
  60. #include "ddsfile.h"
  61. #include "bitmaphandler.h"
  62. #include "wwprofile.h"
  63. //#pragma optimize("", off)
  64. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  65. bool TextureLoader::TextureLoadSuspended;
  66. int TextureLoader::TextureInactiveOverrideTime = 0;
  67. #define USE_MANAGED_TEXTURES
  68. ////////////////////////////////////////////////////////////////////////////////
  69. //
  70. // TextureLoadTaskListClass implementation
  71. //
  72. ////////////////////////////////////////////////////////////////////////////////
  73. TextureLoadTaskListClass::TextureLoadTaskListClass(void)
  74. : Root()
  75. {
  76. Root.Next = Root.Prev = &Root;
  77. }
  78. void TextureLoadTaskListClass::Push_Front (TextureLoadTaskClass *task)
  79. {
  80. // task should non-null and not on any list
  81. WWASSERT(task != NULL && task->Next == NULL && task->Prev == NULL);
  82. // update inserted task to point to list
  83. task->Next = Root.Next;
  84. task->Prev = &Root;
  85. task->List = this;
  86. // update list to point to inserted task
  87. Root.Next->Prev = task;
  88. Root.Next = task;
  89. }
  90. void TextureLoadTaskListClass::Push_Back(TextureLoadTaskClass *task)
  91. {
  92. // task should be non-null and not on any list
  93. WWASSERT(task != NULL && task->Next == NULL && task->Prev == NULL);
  94. // update inserted task to point to list
  95. task->Next = &Root;
  96. task->Prev = Root.Prev;
  97. task->List = this;
  98. // update list to point to inserted task
  99. Root.Prev->Next = task;
  100. Root.Prev = task;
  101. }
  102. TextureLoadTaskClass *TextureLoadTaskListClass::Pop_Front(void)
  103. {
  104. // exit early if list is empty
  105. if (Is_Empty()) {
  106. return 0;
  107. }
  108. // otherwise, grab first task and remove it.
  109. TextureLoadTaskClass *task = (TextureLoadTaskClass *)Root.Next;
  110. Remove(task);
  111. return task;
  112. }
  113. TextureLoadTaskClass *TextureLoadTaskListClass::Pop_Back(void)
  114. {
  115. // exit early if list is empty
  116. if (Is_Empty()) {
  117. return 0;
  118. }
  119. // otherwise, grab last task and remove it.
  120. TextureLoadTaskClass *task = (TextureLoadTaskClass *)Root.Prev;
  121. Remove(task);
  122. return task;
  123. }
  124. void TextureLoadTaskListClass::Remove(TextureLoadTaskClass *task)
  125. {
  126. // exit early if task is not on this list.
  127. if (task->List != this) {
  128. return;
  129. }
  130. // update list to skip task
  131. task->Prev->Next = task->Next;
  132. task->Next->Prev = task->Prev;
  133. // update task to no longer point at list
  134. task->Prev = 0;
  135. task->Next = 0;
  136. task->List = 0;
  137. }
  138. ////////////////////////////////////////////////////////////////////////////////
  139. //
  140. // SynchronizedTextureLoadTaskListClass implementation
  141. //
  142. ////////////////////////////////////////////////////////////////////////////////
  143. SynchronizedTextureLoadTaskListClass::SynchronizedTextureLoadTaskListClass(void)
  144. : TextureLoadTaskListClass(),
  145. CriticalSection()
  146. {
  147. }
  148. void SynchronizedTextureLoadTaskListClass::Push_Front(TextureLoadTaskClass *task)
  149. {
  150. FastCriticalSectionClass::LockClass lock(CriticalSection);
  151. TextureLoadTaskListClass::Push_Front(task);
  152. }
  153. void SynchronizedTextureLoadTaskListClass::Push_Back(TextureLoadTaskClass *task)
  154. {
  155. FastCriticalSectionClass::LockClass lock(CriticalSection);
  156. TextureLoadTaskListClass::Push_Back(task);
  157. }
  158. TextureLoadTaskClass *SynchronizedTextureLoadTaskListClass::Pop_Front(void)
  159. {
  160. // this duplicates code inside base class, but saves us an unnecessary lock.
  161. if (Is_Empty()) {
  162. return 0;
  163. }
  164. FastCriticalSectionClass::LockClass lock(CriticalSection);
  165. return TextureLoadTaskListClass::Pop_Front();
  166. }
  167. TextureLoadTaskClass *SynchronizedTextureLoadTaskListClass::Pop_Back(void)
  168. {
  169. // this duplicates code inside base class, but saves us an unnecessary lock.
  170. if (Is_Empty()) {
  171. return 0;
  172. }
  173. FastCriticalSectionClass::LockClass lock(CriticalSection);
  174. return TextureLoadTaskListClass::Pop_Back();
  175. }
  176. void SynchronizedTextureLoadTaskListClass::Remove(TextureLoadTaskClass *task)
  177. {
  178. FastCriticalSectionClass::LockClass lock(CriticalSection);
  179. TextureLoadTaskListClass::Remove(task);
  180. }
  181. // Locks
  182. // To prevent deadlock, threads should acquire locks in the order in which
  183. // they are defined below. No ordering is necessary for the task list locks,
  184. // since one thread can never hold two at once.
  185. static FastCriticalSectionClass _ForegroundCriticalSection;
  186. static FastCriticalSectionClass _BackgroundCriticalSection;
  187. // Lists
  188. static SynchronizedTextureLoadTaskListClass _ForegroundQueue;
  189. static SynchronizedTextureLoadTaskListClass _BackgroundQueue;
  190. static TextureLoadTaskListClass _TexLoadFreeList;
  191. static TextureLoadTaskListClass _CubeTexLoadFreeList;
  192. static TextureLoadTaskListClass _VolTexLoadFreeList;
  193. // The background texture loading thread.
  194. static class LoaderThreadClass : public ThreadClass
  195. {
  196. public:
  197. #ifdef Exception_Handler
  198. LoaderThreadClass(const char *thread_name = "Texture loader thread") : ThreadClass(thread_name, &Exception_Handler) {}
  199. #else
  200. LoaderThreadClass(const char *thread_name = "Texture loader thread") : ThreadClass(thread_name) {}
  201. #endif
  202. void Thread_Function();
  203. } _TextureLoadThread;
  204. // TODO: Legacy - remove this call!
  205. IDirect3DTexture8* Load_Compressed_Texture(
  206. const StringClass& filename,
  207. unsigned reduction_factor,
  208. MipCountType mip_level_count,
  209. WW3DFormat dest_format)
  210. {
  211. // If DDS file isn't available, use TGA file to convert to DDS.
  212. DDSFileClass dds_file(filename,reduction_factor);
  213. if (!dds_file.Is_Available()) return NULL;
  214. if (!dds_file.Load()) return NULL;
  215. unsigned width=dds_file.Get_Width(0);
  216. unsigned height=dds_file.Get_Height(0);
  217. unsigned mips=dds_file.Get_Mip_Level_Count();
  218. // If format isn't defined get the nearest valid texture format to the compressed file format
  219. // Note that the nearest valid format could be anything, even uncompressed.
  220. if (dest_format==WW3D_FORMAT_UNKNOWN) dest_format=Get_Valid_Texture_Format(dds_file.Get_Format(),true);
  221. IDirect3DTexture8* d3d_texture = DX8Wrapper::_Create_DX8_Texture
  222. (
  223. width,
  224. height,
  225. dest_format,
  226. (MipCountType)mips
  227. );
  228. for (unsigned level=0;level<mips;++level) {
  229. IDirect3DSurface8* d3d_surface=NULL;
  230. WWASSERT(d3d_texture);
  231. DX8_ErrorCode(d3d_texture->GetSurfaceLevel(level/*-reduction_factor*/,&d3d_surface));
  232. dds_file.Copy_Level_To_Surface(level,d3d_surface);
  233. d3d_surface->Release();
  234. }
  235. return d3d_texture;
  236. }
  237. static bool Is_Format_Compressed(WW3DFormat texture_format,bool allow_compression)
  238. {
  239. // Verify that the user isn't requesting compressed texture without hardware support
  240. bool compressed=false;
  241. if (texture_format!=WW3D_FORMAT_UNKNOWN) {
  242. if (!DX8Wrapper::Get_Current_Caps()->Support_DXTC() || !allow_compression) {
  243. WWASSERT(texture_format!=WW3D_FORMAT_DXT1);
  244. WWASSERT(texture_format!=WW3D_FORMAT_DXT2);
  245. WWASSERT(texture_format!=WW3D_FORMAT_DXT3);
  246. WWASSERT(texture_format!=WW3D_FORMAT_DXT4);
  247. WWASSERT(texture_format!=WW3D_FORMAT_DXT5);
  248. }
  249. if (texture_format==WW3D_FORMAT_DXT1 ||
  250. texture_format==WW3D_FORMAT_DXT2 ||
  251. texture_format==WW3D_FORMAT_DXT3 ||
  252. texture_format==WW3D_FORMAT_DXT4 ||
  253. texture_format==WW3D_FORMAT_DXT5) {
  254. compressed=true;
  255. }
  256. }
  257. // If hardware supports DXTC compression, load a compressed texture. Proceed only if the texture format hasn't been
  258. // defined as non-compressed.
  259. compressed|=(
  260. texture_format==WW3D_FORMAT_UNKNOWN &&
  261. DX8Wrapper::Get_Current_Caps()->Support_DXTC() &&
  262. allow_compression);
  263. return compressed;
  264. }
  265. ////////////////////////////////////////////////////////////////////////////////
  266. //
  267. // TextureLoader implementation
  268. //
  269. ////////////////////////////////////////////////////////////////////////////////
  270. void TextureLoader::Init()
  271. {
  272. WWASSERT(!_TextureLoadThread.Is_Running());
  273. ThumbnailManagerClass::Init();
  274. _TextureLoadThread.Execute();
  275. _TextureLoadThread.Set_Priority(-4);
  276. TextureInactiveOverrideTime = 0;
  277. }
  278. void TextureLoader::Deinit()
  279. {
  280. FastCriticalSectionClass::LockClass lock(_BackgroundCriticalSection);
  281. _TextureLoadThread.Stop();
  282. ThumbnailManagerClass::Deinit();
  283. TextureLoadTaskClass::Delete_Free_Pool();
  284. }
  285. bool TextureLoader::Is_DX8_Thread(void)
  286. {
  287. return (ThreadClass::_Get_Current_Thread_ID() == DX8Wrapper::_Get_Main_Thread_ID());
  288. }
  289. // ----------------------------------------------------------------------------
  290. //
  291. // Modify given texture size to nearest valid size on current hardware.
  292. //
  293. // ----------------------------------------------------------------------------
  294. void TextureLoader::Validate_Texture_Size
  295. (
  296. unsigned& width,
  297. unsigned& height,
  298. unsigned& depth
  299. )
  300. {
  301. const D3DCAPS8& dx8caps=DX8Wrapper::Get_Current_Caps()->Get_DX8_Caps();
  302. unsigned poweroftwowidth = 1;
  303. while (poweroftwowidth < width)
  304. {
  305. poweroftwowidth <<= 1;
  306. }
  307. unsigned poweroftwoheight = 1;
  308. while (poweroftwoheight < height)
  309. {
  310. poweroftwoheight <<= 1;
  311. }
  312. unsigned poweroftwodepth = 1;
  313. while (poweroftwodepth< depth)
  314. {
  315. poweroftwodepth <<= 1;
  316. }
  317. if (poweroftwowidth>dx8caps.MaxTextureWidth)
  318. {
  319. poweroftwowidth=dx8caps.MaxTextureWidth;
  320. }
  321. if (poweroftwoheight>dx8caps.MaxTextureHeight)
  322. {
  323. poweroftwoheight=dx8caps.MaxTextureHeight;
  324. }
  325. if (poweroftwodepth>dx8caps.MaxVolumeExtent)
  326. {
  327. poweroftwodepth=dx8caps.MaxVolumeExtent;
  328. }
  329. if (poweroftwowidth>poweroftwoheight)
  330. {
  331. while (poweroftwowidth/poweroftwoheight>8)
  332. {
  333. poweroftwoheight*=2;
  334. }
  335. }
  336. else
  337. {
  338. while (poweroftwoheight/poweroftwowidth>8)
  339. {
  340. poweroftwowidth*=2;
  341. }
  342. }
  343. width=poweroftwowidth;
  344. height=poweroftwoheight;
  345. depth=poweroftwodepth;
  346. }
  347. IDirect3DTexture8* TextureLoader::Load_Thumbnail(const StringClass& filename, const Vector3& hsv_shift)//,WW3DFormat texture_format)
  348. {
  349. WWASSERT(Is_DX8_Thread());
  350. ThumbnailClass* thumb=NULL;
  351. thumb=ThumbnailManagerClass::Peek_Thumbnail_Instance_From_Any_Manager(filename);
  352. // If no thumb is found return a missing texture
  353. if (!thumb) {
  354. return MissingTexture::_Get_Missing_Texture();
  355. }
  356. WWASSERT(thumb->Get_Format()==WW3D_FORMAT_A4R4G4B4);
  357. unsigned src_pitch=thumb->Get_Width()*2; // Thumbs are always 16 bits
  358. WW3DFormat dest_format;
  359. WW3DFormat texture_format=WW3D_FORMAT_UNKNOWN;
  360. if (texture_format==WW3D_FORMAT_UNKNOWN) {
  361. dest_format=Get_Valid_Texture_Format(WW3D_FORMAT_A4R4G4B4,false); // no compressed formats please
  362. }
  363. else {
  364. dest_format=Get_Valid_Texture_Format(texture_format,false); // no compressed formats please
  365. WWASSERT(dest_format==texture_format);
  366. }
  367. IDirect3DTexture8* sysmem_texture = DX8Wrapper::_Create_DX8_Texture(
  368. thumb->Get_Width(),
  369. thumb->Get_Height(),
  370. dest_format,
  371. MIP_LEVELS_ALL,
  372. #ifdef USE_MANAGED_TEXTURES
  373. D3DPOOL_MANAGED);
  374. #else
  375. D3DPOOL_SYSTEMMEM);
  376. #endif
  377. unsigned level=0;
  378. D3DLOCKED_RECT locked_rects[12];
  379. WWASSERT(sysmem_texture->GetLevelCount()<=12);
  380. // Lock all surfaces
  381. for (level=0;level<sysmem_texture->GetLevelCount();++level) {
  382. DX8_ErrorCode(
  383. sysmem_texture->LockRect(
  384. level,
  385. &locked_rects[level],
  386. NULL,
  387. 0));
  388. }
  389. unsigned char* src_surface=thumb->Peek_Bitmap();
  390. WW3DFormat src_format=thumb->Get_Format();
  391. unsigned width=thumb->Get_Width();
  392. unsigned height=thumb->Get_Height();
  393. Vector3 hsv=hsv_shift;
  394. for (level=0;level<sysmem_texture->GetLevelCount()-1;++level) {
  395. BitmapHandlerClass::Copy_Image_Generate_Mipmap(
  396. width,
  397. height,
  398. (unsigned char*)locked_rects[level].pBits,
  399. locked_rects[level].Pitch,
  400. dest_format,
  401. src_surface,
  402. src_pitch,
  403. src_format,
  404. (unsigned char*)locked_rects[level+1].pBits, // mipmap
  405. locked_rects[level+1].Pitch,
  406. hsv);
  407. hsv=Vector3(0.0f,0.0f,0.0f); // Only do the shift for the first level, as the mipmaps are based on it.
  408. src_format=dest_format;
  409. src_surface=(unsigned char*)locked_rects[level].pBits;
  410. src_pitch=locked_rects[level].Pitch;
  411. width>>=1;
  412. height>>=1;
  413. }
  414. // Unlock all surfaces
  415. for (level=0;level<sysmem_texture->GetLevelCount();++level) {
  416. DX8_ErrorCode(sysmem_texture->UnlockRect(level));
  417. }
  418. #ifdef USE_MANAGED_TEXTURES
  419. return sysmem_texture;
  420. #else
  421. IDirect3DTexture8* d3d_texture = DX8Wrapper::_Create_DX8_Texture(
  422. thumb->Get_Width(),
  423. thumb->Get_Height(),
  424. dest_format,
  425. TextureBaseClass::MIP_LEVELS_ALL,
  426. D3DPOOL_DEFAULT);
  427. DX8CALL(UpdateTexture(sysmem_texture,d3d_texture));
  428. sysmem_texture->Release();
  429. WWDEBUG_SAY(("Created non-managed texture (%s)\n",filename));
  430. return d3d_texture;
  431. #endif
  432. }
  433. // ----------------------------------------------------------------------------
  434. //
  435. // Load image to a surface. The function tries to create texture that matches
  436. // targa format. If suitable format is not available, it selects closest matching
  437. // format and performs color space conversion.
  438. //
  439. // ----------------------------------------------------------------------------
  440. IDirect3DSurface8* TextureLoader::Load_Surface_Immediate(
  441. const StringClass& filename,
  442. WW3DFormat texture_format,
  443. bool allow_compression)
  444. {
  445. WWASSERT(Is_DX8_Thread());
  446. bool compressed=Is_Format_Compressed(texture_format,allow_compression);
  447. if (compressed) {
  448. IDirect3DTexture8* comp_tex=Load_Compressed_Texture(filename,0,MIP_LEVELS_1,WW3D_FORMAT_UNKNOWN);
  449. if (comp_tex) {
  450. IDirect3DSurface8* d3d_surface=NULL;
  451. DX8_ErrorCode(comp_tex->GetSurfaceLevel(0,&d3d_surface));
  452. comp_tex->Release();
  453. return d3d_surface;
  454. }
  455. }
  456. // Make sure the file can be opened. If not, return missing texture.
  457. Targa targa;
  458. if (TARGA_ERROR_HANDLER(targa.Open(filename, TGA_READMODE),filename)) return MissingTexture::_Create_Missing_Surface();
  459. // DX8 uses image upside down compared to TGA
  460. targa.Header.ImageDescriptor ^= TGAIDF_YORIGIN;
  461. WW3DFormat src_format,dest_format;
  462. unsigned src_bpp=0;
  463. Get_WW3D_Format(dest_format,src_format,src_bpp,targa);
  464. if (texture_format!=WW3D_FORMAT_UNKNOWN) {
  465. dest_format=texture_format;
  466. }
  467. // Destination size will be the next power of two square from the larger width and height...
  468. unsigned width, height;
  469. width=targa.Header.Width;
  470. height=targa.Header.Height;
  471. unsigned src_width=targa.Header.Width;
  472. unsigned src_height=targa.Header.Height;
  473. // NOTE: We load the palette but we do not yet support paletted textures!
  474. char palette[256*4];
  475. targa.SetPalette(palette);
  476. if (TARGA_ERROR_HANDLER(targa.Load(filename, TGAF_IMAGE, false),filename)) return MissingTexture::_Create_Missing_Surface();
  477. unsigned char* src_surface=(unsigned char*)targa.GetImage();
  478. // No paletted destination format allowed
  479. unsigned char* converted_surface=NULL;
  480. if (src_format==WW3D_FORMAT_A1R5G5B5 || src_format==WW3D_FORMAT_R5G6B5 || src_format==WW3D_FORMAT_A4R4G4B4 ||
  481. src_format==WW3D_FORMAT_P8 || src_format==WW3D_FORMAT_L8 || src_width!=width || src_height!=height) {
  482. converted_surface=W3DNEWARRAY unsigned char[width*height*4];
  483. dest_format=Get_Valid_Texture_Format(WW3D_FORMAT_A8R8G8B8,false);
  484. BitmapHandlerClass::Copy_Image(
  485. converted_surface,
  486. width,
  487. height,
  488. width*4,
  489. WW3D_FORMAT_A8R8G8B8,//dest_format,
  490. src_surface,
  491. src_width,
  492. src_height,
  493. src_width*src_bpp,
  494. src_format,
  495. (unsigned char*)targa.GetPalette(),
  496. targa.Header.CMapDepth>>3,
  497. false);
  498. src_surface=converted_surface;
  499. src_format=WW3D_FORMAT_A8R8G8B8;//dest_format;
  500. src_width=width;
  501. src_height=height;
  502. src_bpp=Get_Bytes_Per_Pixel(src_format);
  503. }
  504. unsigned src_pitch=src_width*src_bpp;
  505. IDirect3DSurface8* d3d_surface = DX8Wrapper::_Create_DX8_Surface(width,height,dest_format);
  506. WWASSERT(d3d_surface);
  507. D3DLOCKED_RECT locked_rect;
  508. DX8_ErrorCode(
  509. d3d_surface->LockRect(
  510. &locked_rect,
  511. NULL,
  512. 0));
  513. BitmapHandlerClass::Copy_Image(
  514. (unsigned char*)locked_rect.pBits,
  515. width,
  516. height,
  517. locked_rect.Pitch,
  518. dest_format,
  519. src_surface,
  520. src_width,
  521. src_height,
  522. src_pitch,
  523. src_format,
  524. (unsigned char*)targa.GetPalette(),
  525. targa.Header.CMapDepth>>3,
  526. false); // No mipmap
  527. DX8_ErrorCode(d3d_surface->UnlockRect());
  528. if (converted_surface) delete[] converted_surface;
  529. return d3d_surface;
  530. }
  531. void TextureLoader::Request_Thumbnail(TextureBaseClass *tc)
  532. {
  533. // Grab the foreground lock. This prevents the foreground thread
  534. // from retiring any tasks related to this texture. It also
  535. // serializes calls to Request_Thumbnail from multiple threads.
  536. FastCriticalSectionClass::LockClass lock(_ForegroundCriticalSection);
  537. // Has a Direct3D texture already been loaded?
  538. if (tc->Peek_D3D_Base_Texture()) {
  539. return;
  540. }
  541. TextureLoadTaskClass *task = tc->ThumbnailLoadTask;
  542. if (Is_DX8_Thread()) {
  543. // load the thumbnail immediately
  544. TextureLoader::Load_Thumbnail(tc);
  545. // clear any pending thumbnail load
  546. if (task) {
  547. _ForegroundQueue.Remove(task);
  548. task->Destroy();
  549. }
  550. } else {
  551. TextureLoadTaskClass *load_task = tc->TextureLoadTask;
  552. // if texture is not already loading a thumbnail and there is no
  553. // background load near completion. (a background load waiting
  554. // to be applied will be ready at the same time as a queued thumbnail.
  555. // Why do the extra work?)
  556. if (!task && (!load_task || load_task->Get_State() < TextureLoadTaskClass::STATE_LOAD_MIPMAP)) {
  557. // create a thumbnail load task and add to foreground queue.
  558. task = TextureLoadTaskClass::Create(tc, TextureLoadTaskClass::TASK_THUMBNAIL, TextureLoadTaskClass::PRIORITY_LOW);
  559. _ForegroundQueue.Push_Back(task);
  560. }
  561. }
  562. }
  563. void TextureLoader::Request_Background_Loading(TextureBaseClass *tc)
  564. {
  565. WWPROFILE(("TextureLoader::Request_Background_Loading()"));
  566. // Grab the foreground lock. This prevents the foreground thread
  567. // from retiring any tasks related to this texture. It also
  568. // serializes calls to Request_Background_Loading from other
  569. // threads.
  570. FastCriticalSectionClass::LockClass foreground_lock(_ForegroundCriticalSection);
  571. // Has the texture already been loaded?
  572. if (tc->Is_Initialized()) {
  573. return;
  574. }
  575. TextureLoadTaskClass *task = tc->TextureLoadTask;
  576. // if texture already has a load task, we don't need to create another one.
  577. if (task) {
  578. return;
  579. }
  580. task = TextureLoadTaskClass::Create(tc, TextureLoadTaskClass::TASK_LOAD, TextureLoadTaskClass::PRIORITY_LOW);
  581. if (Is_DX8_Thread()) {
  582. Begin_Load_And_Queue(task);
  583. } else {
  584. _ForegroundQueue.Push_Back(task);
  585. }
  586. }
  587. void TextureLoader::Request_Foreground_Loading(TextureBaseClass *tc)
  588. {
  589. WWPROFILE(("TextureLoader::Request_Foreground_Loading()"));
  590. // Grab the foreground lock. This prevents the foreground thread
  591. // from retiring the load tasks for this texture. It also
  592. // serializes calls to Request_Foreground_Loading from other
  593. // threads.
  594. FastCriticalSectionClass::LockClass foreground_lock(_ForegroundCriticalSection);
  595. // Has the texture already been loaded?
  596. if (tc->Is_Initialized()) {
  597. return;
  598. }
  599. TextureLoadTaskClass *task = tc->TextureLoadTask;
  600. TextureLoadTaskClass *task_thumb = tc->ThumbnailLoadTask;
  601. if (Is_DX8_Thread()) {
  602. // since we're in the DX8 thread, we can load the entire
  603. // texture right now.
  604. // if we have a thumbnail task waiting, kill it.
  605. if (task_thumb) {
  606. _ForegroundQueue.Remove(task_thumb);
  607. task_thumb->Destroy();
  608. }
  609. if (task) {
  610. // we need to remove the task from any queue, since we're going
  611. // to finish it up right now.
  612. // halt background thread. After we're holding this lock,
  613. // we know the background thread cannot begin loading
  614. // mipmap levels for this texture.
  615. FastCriticalSectionClass::LockClass background_lock(_BackgroundCriticalSection);
  616. _ForegroundQueue.Remove(task);
  617. _BackgroundQueue.Remove(task);
  618. } else {
  619. // Since the task manages all the state associated with loading
  620. // a texture, we temporarily create one.
  621. task = TextureLoadTaskClass::Create(tc, TextureLoadTaskClass::TASK_LOAD, TextureLoadTaskClass::PRIORITY_HIGH);
  622. }
  623. // finish loading the task and destroy it.
  624. task->Finish_Load();
  625. task->Destroy();
  626. } else {
  627. // we are not in the DX8 thread. We need to add a high-priority loading
  628. // task to the foreground queue.
  629. // Grab the background lock. After we're holding this lock, we
  630. // know the background thread cannot begin loading mipmap levels
  631. // for this texture.
  632. FastCriticalSectionClass::LockClass background_lock(_BackgroundCriticalSection);
  633. // if we have a thumbnail task, we should cancel it. Since we are not
  634. // the foreground thread, we are not allowed to call Destroy(). Instead,
  635. // leave it queued in the completed state so it will be destroyed by Update().
  636. if (task_thumb) {
  637. task_thumb->Set_State(TextureLoadTaskClass::STATE_COMPLETE);
  638. }
  639. if (task) {
  640. // if a load task is waiting on the background queue, we need to
  641. // move it to the foreground queue.
  642. if (task->Get_List() == &_BackgroundQueue) {
  643. // remove task from list
  644. _BackgroundQueue.Remove(task);
  645. // add to foreground queue.
  646. _ForegroundQueue.Push_Back(task);
  647. }
  648. // upgrade the task priority
  649. task->Set_Priority(TextureLoadTaskClass::PRIORITY_HIGH);
  650. } else {
  651. // allocate high priority load task
  652. task = TextureLoadTaskClass::Create(tc, TextureLoadTaskClass::TASK_LOAD, TextureLoadTaskClass::PRIORITY_HIGH);
  653. // add to back of foreground queue.
  654. _ForegroundQueue.Push_Back(task);
  655. }
  656. }
  657. }
  658. void TextureLoader::Flush_Pending_Load_Tasks(void)
  659. {
  660. // This function can only be called from the main thread.
  661. // (Only the main thread can make the DX8 calls necessary
  662. // to complete texture loading. If we wanted to flush
  663. // the pending tasks from another thread, we'd probably
  664. // want to set a bool that is checked by Update().
  665. WWASSERT(Is_DX8_Thread());
  666. for (;;) {
  667. bool done = false;
  668. {
  669. // we have no pending load tasks when both queues are empty
  670. // and the background thread is not processing a texture.
  671. // Grab the background lock. Once we're holding it, we
  672. // know that the background thread is not processing any
  673. // textures.
  674. // NOTE: It's important that we do only hold on to the background
  675. // lock while we check for completion. Otherwise, we will either
  676. // violate the lock order when we call Update() (which grabs
  677. // the foreground lock) or never give the background thread
  678. // a chance to empty its queue.
  679. FastCriticalSectionClass::LockClass background_lock(_BackgroundCriticalSection);
  680. done = _BackgroundQueue.Is_Empty() && _ForegroundQueue.Is_Empty();
  681. }
  682. // exit loop if no entries in list
  683. if (done) {
  684. break;
  685. }
  686. Update();
  687. ThreadClass::Switch_Thread();
  688. }
  689. }
  690. // Nework update macro for texture loader.
  691. #pragma warning(disable:4201) // warning C4201: nonstandard extension used : nameless struct/union
  692. #include <mmsystem.h>
  693. #define UPDATE_NETWORK \
  694. if (network_callback) { \
  695. unsigned long time2 = timeGetTime(); \
  696. if (time2 - time > 20) { \
  697. network_callback(); \
  698. time = time2; \
  699. } \
  700. } \
  701. void TextureLoader::Update(void (*network_callback)(void))
  702. {
  703. WWASSERT_PRINT(Is_DX8_Thread(), "TextureLoader::Update must be called from the main thread!");
  704. if (TextureLoadSuspended) {
  705. return;
  706. }
  707. // grab foreground lock to prevent any other thread from
  708. // modifying texture tasks.
  709. FastCriticalSectionClass::LockClass lock(_ForegroundCriticalSection);
  710. unsigned long time = timeGetTime();
  711. // while we have tasks on the foreground queue
  712. while (TextureLoadTaskClass *task = _ForegroundQueue.Pop_Front()) {
  713. UPDATE_NETWORK;
  714. // dispatch to proper task handler
  715. switch (task->Get_Type()) {
  716. case TextureLoadTaskClass::TASK_THUMBNAIL:
  717. Process_Foreground_Thumbnail(task);
  718. break;
  719. case TextureLoadTaskClass::TASK_LOAD:
  720. Process_Foreground_Load(task);
  721. break;
  722. }
  723. }
  724. TextureBaseClass::Invalidate_Old_Unused_Textures(TextureInactiveOverrideTime);
  725. }
  726. void TextureLoader::Suspend_Texture_Load()
  727. {
  728. WWASSERT_PRINT(Is_DX8_Thread(),"TextureLoader::Suspend_Texture_Load must be called from the main thread!");
  729. TextureLoadSuspended=true;
  730. }
  731. void TextureLoader::Continue_Texture_Load()
  732. {
  733. WWASSERT_PRINT(Is_DX8_Thread(),"TextureLoader::Continue_Texture_Load must be called from the main thread!");
  734. TextureLoadSuspended=false;
  735. }
  736. void TextureLoader::Process_Foreground_Thumbnail(TextureLoadTaskClass *task)
  737. {
  738. switch (task->Get_State()) {
  739. case TextureLoadTaskClass::STATE_NONE:
  740. Load_Thumbnail(task->Peek_Texture());
  741. // NOTE: fall-through is intentional
  742. case TextureLoadTaskClass::STATE_COMPLETE:
  743. task->Destroy();
  744. break;
  745. }
  746. }
  747. void TextureLoader::Process_Foreground_Load(TextureLoadTaskClass *task)
  748. {
  749. // Is high-priority task?
  750. if (task->Get_Priority() == TextureLoadTaskClass::PRIORITY_HIGH) {
  751. task->Finish_Load();
  752. task->Destroy();
  753. return;
  754. }
  755. // otherwise, must be a low-priority task.
  756. switch (task->Get_State()) {
  757. case TextureLoadTaskClass::STATE_NONE:
  758. Begin_Load_And_Queue(task);
  759. break;
  760. case TextureLoadTaskClass::STATE_LOAD_MIPMAP:
  761. task->End_Load();
  762. task->Destroy();
  763. break;
  764. }
  765. }
  766. void TextureLoader::Begin_Load_And_Queue(TextureLoadTaskClass *task)
  767. {
  768. // should only be called from the DX8 thread.
  769. WWASSERT(Is_DX8_Thread());
  770. if (task->Begin_Load()) {
  771. // add to front of background queue. This means the
  772. // background load thread will service tasks in LIFO
  773. // (last in, first out) order.
  774. // NOTE: this was how the old code did it, with a
  775. // comment that mentioned good reasons for doing so,
  776. // without actually listing the reasons. I suspect
  777. // it has something to do with visually important textures,
  778. // like those in the foreground, starting their load last.
  779. _BackgroundQueue.Push_Front(task);
  780. } else {
  781. // unable to load.
  782. task->Apply_Missing_Texture();
  783. task->Destroy();
  784. }
  785. }
  786. void TextureLoader::Load_Thumbnail(TextureBaseClass *tc)
  787. {
  788. // All D3D operations must run from main thread
  789. WWASSERT(Is_DX8_Thread());
  790. // load thumbnail texture
  791. IDirect3DTexture8 *d3d_texture = Load_Thumbnail(tc->Get_Full_Path(),tc->Get_HSV_Shift());
  792. // apply thumbnail to texture
  793. if (tc->Get_Asset_Type()==TextureBaseClass::TEX_REGULAR)
  794. {
  795. tc->Apply_New_Surface(d3d_texture, false);
  796. }
  797. // release our reference to thumbnail texture
  798. d3d_texture->Release();
  799. d3d_texture = 0;
  800. }
  801. void LoaderThreadClass::Thread_Function(void)
  802. {
  803. while (running) {
  804. // if there are no tasks on the background queue, no need to grab background lock.
  805. if (!_BackgroundQueue.Is_Empty()) {
  806. // Grab background load so other threads know we could be
  807. // loading a texture.
  808. FastCriticalSectionClass::LockClass lock(_BackgroundCriticalSection);
  809. // try to remove a task from the background queue. This could fail
  810. // if another thread modified the queue between our test above and
  811. // grabbing the lock.
  812. TextureLoadTaskClass* task = _BackgroundQueue.Pop_Front();
  813. if (task) {
  814. // verify task is in proper state for background processing.
  815. WWASSERT(task->Get_Type() == TextureLoadTaskClass::TASK_LOAD);
  816. WWASSERT(task->Get_State() == TextureLoadTaskClass::STATE_LOAD_BEGUN);
  817. // load mip map levels and return to foreground queue for final step.
  818. task->Load();
  819. _ForegroundQueue.Push_Back(task);
  820. }
  821. }
  822. Switch_Thread();
  823. }
  824. }
  825. ////////////////////////////////////////////////////////////////////////////////
  826. //
  827. // TextureLoaderTaskClass implementation
  828. //
  829. ////////////////////////////////////////////////////////////////////////////////
  830. TextureLoadTaskClass::TextureLoadTaskClass()
  831. : Texture (0),
  832. D3DTexture (0),
  833. Format (WW3D_FORMAT_UNKNOWN),
  834. Width (0),
  835. Height (0),
  836. MipLevelCount (0),
  837. Reduction (0),
  838. Type (TASK_NONE),
  839. Priority (PRIORITY_LOW),
  840. State (STATE_NONE),
  841. HSVShift (0.0f,0.0f,0.0f)
  842. {
  843. // because texture load tasks are pooled, the constructor and destructor
  844. // don't need to do much. The work of attaching a task to a texture is
  845. // is done by Init() and Deinit().
  846. for (int i = 0; i < MIP_LEVELS_MAX; ++i) {
  847. LockedSurfacePtr[i] = NULL;
  848. LockedSurfacePitch[i] = 0;
  849. }
  850. }
  851. TextureLoadTaskClass::~TextureLoadTaskClass(void)
  852. {
  853. Deinit();
  854. }
  855. TextureLoadTaskClass *TextureLoadTaskClass::Create(TextureBaseClass *tc, TaskType type, PriorityType priority)
  856. {
  857. // recycle or create a new texture load task with the given type
  858. // and priority, then associate the texture with the task.
  859. // pull a load task from front of free list
  860. TextureLoadTaskClass *task = NULL;
  861. switch (tc->Get_Asset_Type())
  862. {
  863. case TextureBaseClass::TEX_REGULAR : task=_TexLoadFreeList.Pop_Front(); break;
  864. case TextureBaseClass::TEX_CUBEMAP : task=_CubeTexLoadFreeList.Pop_Front(); break;
  865. case TextureBaseClass::TEX_VOLUME : task=_VolTexLoadFreeList.Pop_Front(); break;
  866. default : WWASSERT(0);
  867. };
  868. // if no tasks on free list, allocate a new task
  869. if (!task)
  870. {
  871. switch (tc->Get_Asset_Type())
  872. {
  873. case TextureBaseClass::TEX_REGULAR : task=new TextureLoadTaskClass; break;
  874. case TextureBaseClass::TEX_CUBEMAP : task=new CubeTextureLoadTaskClass; break;
  875. case TextureBaseClass::TEX_VOLUME : task=new VolumeTextureLoadTaskClass; break;
  876. default : WWASSERT(0);
  877. }
  878. }
  879. task->Init(tc, type, priority);
  880. return task;
  881. }
  882. void TextureLoadTaskClass::Destroy(void)
  883. {
  884. // detach the task from its texture, and return to free pool.
  885. Deinit();
  886. _TexLoadFreeList.Push_Front(this);
  887. }
  888. void TextureLoadTaskClass::Delete_Free_Pool(void)
  889. {
  890. // (gth) We should probably just MEMPool these task objects...
  891. while (TextureLoadTaskClass *task = _TexLoadFreeList.Pop_Front()) {
  892. delete task;
  893. }
  894. while (TextureLoadTaskClass *task = _CubeTexLoadFreeList.Pop_Front()) {
  895. delete task;
  896. }
  897. while (TextureLoadTaskClass *task = _VolTexLoadFreeList.Pop_Front()) {
  898. delete task;
  899. }
  900. }
  901. void TextureLoadTaskClass::Init(TextureBaseClass* tc, TaskType type, PriorityType priority)
  902. {
  903. WWASSERT(tc);
  904. // NOTE: we must be in the main thread to avoid corrupting the texture's refcount.
  905. WWASSERT(TextureLoader::Is_DX8_Thread());
  906. REF_PTR_SET(Texture, tc);
  907. // Make sure texture has a filename.
  908. WWASSERT(Texture->Get_Full_Path() != "");
  909. Type = type;
  910. Priority = priority;
  911. State = STATE_NONE;
  912. D3DTexture = 0;
  913. TextureClass* tex=Texture->As_TextureClass();
  914. if (tex)
  915. {
  916. Format = tex->Get_Texture_Format(); // don't assume format yet KM
  917. }
  918. else
  919. {
  920. Format = WW3D_FORMAT_UNKNOWN;
  921. }
  922. Width = 0;
  923. Height = 0;
  924. MipLevelCount = Texture->MipLevelCount;
  925. Reduction = Texture->Get_Reduction();
  926. HSVShift = Texture->Get_HSV_Shift();
  927. for (int i = 0; i < MIP_LEVELS_MAX; ++i)
  928. {
  929. LockedSurfacePtr[i] = NULL;
  930. LockedSurfacePitch[i] = 0;
  931. }
  932. switch (Type)
  933. {
  934. case TASK_THUMBNAIL:
  935. WWASSERT(Texture->ThumbnailLoadTask == NULL);
  936. Texture->ThumbnailLoadTask = this;
  937. break;
  938. case TASK_LOAD:
  939. WWASSERT(Texture->TextureLoadTask == NULL);
  940. Texture->TextureLoadTask = this;
  941. break;
  942. }
  943. }
  944. void TextureLoadTaskClass::Deinit()
  945. {
  946. // task should not be on any list when it is being detached from texture.
  947. WWASSERT(Next == NULL);
  948. WWASSERT(Prev == NULL);
  949. WWASSERT(D3DTexture == NULL);
  950. for (int i = 0; i < MIP_LEVELS_MAX; ++i) {
  951. WWASSERT(LockedSurfacePtr[i] == NULL);
  952. }
  953. if (Texture) {
  954. switch (Type) {
  955. case TASK_THUMBNAIL:
  956. WWASSERT(Texture->ThumbnailLoadTask == this);
  957. Texture->ThumbnailLoadTask = NULL;
  958. break;
  959. case TASK_LOAD:
  960. WWASSERT(Texture->TextureLoadTask == this);
  961. Texture->TextureLoadTask = NULL;
  962. break;
  963. }
  964. // NOTE: we must be in main thread to avoid corrupting Texture's refcount.
  965. WWASSERT(TextureLoader::Is_DX8_Thread());
  966. REF_PTR_RELEASE(Texture);
  967. }
  968. }
  969. bool TextureLoadTaskClass::Begin_Load(void)
  970. {
  971. WWASSERT(TextureLoader::Is_DX8_Thread());
  972. bool loaded = false;
  973. // if allowed, begin a compressed load
  974. if (Texture->Is_Compression_Allowed()) {
  975. loaded = Begin_Compressed_Load();
  976. }
  977. // otherwise, begin an uncompressed load
  978. if (!loaded) {
  979. loaded = Begin_Uncompressed_Load();
  980. }
  981. // if not loaded, abort.
  982. if (!loaded) {
  983. return false;
  984. }
  985. // lock surfaces in preparation for copy
  986. Lock_Surfaces();
  987. State = STATE_LOAD_BEGUN;
  988. return true;
  989. }
  990. // ----------------------------------------------------------------------------
  991. //
  992. // Load mipmap levels to a pre-generated and locked texture object based on
  993. // information in load task object. Try loading from a DDS file first and if
  994. // that fails try a TGA.
  995. //
  996. // ----------------------------------------------------------------------------
  997. bool TextureLoadTaskClass::Load(void)
  998. {
  999. WWMEMLOG(MEM_TEXTURE);
  1000. WWASSERT(Peek_D3D_Texture());
  1001. bool loaded = false;
  1002. // if allowed, try to load compressed mipmaps
  1003. if (Texture->Is_Compression_Allowed()) {
  1004. loaded = Load_Compressed_Mipmap();
  1005. }
  1006. // otherwise, load uncompressed mipmaps
  1007. if (!loaded) {
  1008. loaded = Load_Uncompressed_Mipmap();
  1009. }
  1010. State = STATE_LOAD_MIPMAP;
  1011. return loaded;
  1012. }
  1013. void TextureLoadTaskClass::End_Load(void)
  1014. {
  1015. WWASSERT(TextureLoader::Is_DX8_Thread());
  1016. Unlock_Surfaces();
  1017. Apply(true);
  1018. State = STATE_LOAD_COMPLETE;
  1019. }
  1020. void TextureLoadTaskClass::Finish_Load(void)
  1021. {
  1022. switch (State) {
  1023. // NOTE: fall-through below is intentional.
  1024. case STATE_NONE:
  1025. if (!Begin_Load()) {
  1026. Apply_Missing_Texture();
  1027. break;
  1028. }
  1029. case STATE_LOAD_BEGUN:
  1030. Load();
  1031. case STATE_LOAD_MIPMAP:
  1032. End_Load();
  1033. default:
  1034. break;
  1035. }
  1036. }
  1037. void TextureLoadTaskClass::Apply_Missing_Texture(void)
  1038. {
  1039. WWASSERT(TextureLoader::Is_DX8_Thread());
  1040. WWASSERT(!D3DTexture);
  1041. D3DTexture = MissingTexture::_Get_Missing_Texture();
  1042. Apply(true);
  1043. }
  1044. void TextureLoadTaskClass::Apply(bool initialize)
  1045. {
  1046. WWASSERT(D3DTexture);
  1047. // Verify that none of the mip levels are locked
  1048. for (unsigned i=0;i<MipLevelCount;++i) {
  1049. WWASSERT(LockedSurfacePtr[i]==NULL);
  1050. }
  1051. Texture->Apply_New_Surface(D3DTexture, initialize);
  1052. D3DTexture->Release();
  1053. D3DTexture = NULL;
  1054. }
  1055. static bool Get_Texture_Information
  1056. (
  1057. const char* filename,
  1058. unsigned& reduction,
  1059. unsigned& w,
  1060. unsigned& h,
  1061. unsigned& d,
  1062. WW3DFormat& format,
  1063. unsigned& mip_count,
  1064. bool compressed
  1065. )
  1066. {
  1067. ThumbnailClass* thumb=ThumbnailManagerClass::Peek_Thumbnail_Instance_From_Any_Manager(filename);
  1068. if (!thumb)
  1069. {
  1070. if (compressed)
  1071. {
  1072. DDSFileClass dds_file(filename, 0);
  1073. if (!dds_file.Is_Available()) return false;
  1074. // Destination size will be the next power of two square from the larger width and height...
  1075. w = dds_file.Get_Width(0);
  1076. h = dds_file.Get_Height(0);
  1077. d = dds_file.Get_Depth(0);
  1078. format = dds_file.Get_Format();
  1079. mip_count = dds_file.Get_Mip_Level_Count();
  1080. //Figure out correct reduction
  1081. int reqReduction=WW3D::Get_Texture_Reduction(); //requested reduction
  1082. if (reqReduction >= mip_count)
  1083. reqReduction=mip_count-1; //leave only the lowest level
  1084. //Clamp reduction
  1085. int curReduction=0;
  1086. int curWidth=w;
  1087. int curHeight=h;
  1088. int minDim=WW3D::Get_Texture_Min_Dimension();
  1089. while (curReduction < reqReduction && curWidth > minDim && curHeight > minDim)
  1090. { curWidth >>=1; //keep dividing
  1091. curHeight >>=1;
  1092. curReduction++;
  1093. }
  1094. reduction=curReduction;
  1095. return true;
  1096. }
  1097. Targa targa;
  1098. if (TARGA_ERROR_HANDLER(targa.Open(filename, TGA_READMODE), filename))
  1099. {
  1100. return false;
  1101. }
  1102. unsigned int bpp;
  1103. WW3DFormat dest_format;
  1104. Get_WW3D_Format(dest_format,format,bpp,targa);
  1105. mip_count = 0;
  1106. //Figure out how many mip levels this texture will occupy
  1107. for (int i=targa.Header.Width, j=targa.Header.Height; i > 0 && j > 0; i>>=1, j>>=1)
  1108. mip_count++;
  1109. //Figure out correct reduction
  1110. int reqReduction=WW3D::Get_Texture_Reduction(); //requested reduction
  1111. if (reqReduction >= mip_count)
  1112. reqReduction=mip_count-1; //leave only the lowest level
  1113. //Clamp reduction
  1114. int curReduction=0;
  1115. int curWidth=targa.Header.Width;
  1116. int curHeight=targa.Header.Height;
  1117. int minDim=WW3D::Get_Texture_Min_Dimension();
  1118. while (curReduction < reqReduction && curWidth > minDim && curHeight > minDim)
  1119. { curWidth >>=1; //keep dividing
  1120. curHeight >>=1;
  1121. curReduction++;
  1122. }
  1123. reduction=curReduction;
  1124. // Destination size will be the next power of two square from the larger width and height...
  1125. w = targa.Header.Width;
  1126. h = targa.Header.Height;
  1127. d = 1;
  1128. return true;
  1129. }
  1130. if (compressed &&
  1131. thumb->Get_Original_Texture_Format()!=WW3D_FORMAT_DXT1 &&
  1132. thumb->Get_Original_Texture_Format()!=WW3D_FORMAT_DXT2 &&
  1133. thumb->Get_Original_Texture_Format()!=WW3D_FORMAT_DXT3 &&
  1134. thumb->Get_Original_Texture_Format()!=WW3D_FORMAT_DXT4 &&
  1135. thumb->Get_Original_Texture_Format()!=WW3D_FORMAT_DXT5) {
  1136. return false;
  1137. }
  1138. w=thumb->Get_Original_Texture_Width() >> reduction;
  1139. h=thumb->Get_Original_Texture_Height() >> reduction;
  1140. //d=thumb->Get_Original_Texture_Depth() >> reduction; // need to a volume texture support to thumbnails...maybe
  1141. mip_count=thumb->Get_Original_Texture_Mip_Level_Count();
  1142. format=thumb->Get_Original_Texture_Format();
  1143. return true;
  1144. }
  1145. bool TextureLoadTaskClass::Begin_Compressed_Load(void)
  1146. {
  1147. unsigned orig_w,orig_h,orig_d,orig_mip_count,reduction;
  1148. WW3DFormat orig_format;
  1149. if (!Get_Texture_Information
  1150. (
  1151. Texture->Get_Full_Path(),
  1152. reduction,
  1153. orig_w,
  1154. orig_h,
  1155. orig_d,
  1156. orig_format,
  1157. orig_mip_count,
  1158. true
  1159. )
  1160. )
  1161. {
  1162. return false;
  1163. }
  1164. // Destination size will be the next power of two square from the larger width and height...
  1165. unsigned int width = orig_w;
  1166. unsigned int height = orig_h;
  1167. TextureLoader::Validate_Texture_Size(width, height,orig_d);
  1168. // If the size doesn't match, try and see if texture reduction would help... (mainly for
  1169. // cases where loaded texture is larger than hardware limit)
  1170. if (width != orig_w || height != orig_h)
  1171. {
  1172. for (unsigned int i = 1; i < orig_mip_count; ++i)
  1173. {
  1174. unsigned w=orig_w>>i;
  1175. if (w<4) w=4;
  1176. unsigned h=orig_h>>i;
  1177. if (h<4) h=4;
  1178. unsigned tmp_w=w;
  1179. unsigned tmp_h=h;
  1180. TextureLoader::Validate_Texture_Size(w,h,orig_d);
  1181. if (w == tmp_w && h == tmp_h)
  1182. {
  1183. Reduction += i;
  1184. width = w;
  1185. height = h;
  1186. break;
  1187. }
  1188. }
  1189. }
  1190. Width = width;
  1191. Height = height;
  1192. Format = Get_Valid_Texture_Format(orig_format, Texture->Is_Compression_Allowed());
  1193. Reduction = reduction;
  1194. if (!Texture->Is_Reducible() || Texture->MipLevelCount == MIP_LEVELS_1)
  1195. Reduction = 0; //app doesn't want this texture to ever be reduced.
  1196. else
  1197. //Make sure we don't reduce below the level requested by the app
  1198. if (Texture->MipLevelCount != MIP_LEVELS_ALL && (Texture->MipLevelCount - Reduction) < 1)
  1199. Reduction = Texture->MipLevelCount - 1;
  1200. //Another sanity check
  1201. if (Reduction >= orig_mip_count)
  1202. Reduction = 0; //should not be possible to get here, but check just in case.
  1203. unsigned int mip_level_count = Get_Mip_Level_Count();
  1204. int reducedWidth=Width;
  1205. int reducedHeight=Height;
  1206. // If texture wants all mip levels, take as many as the file contains (not necessarily all)
  1207. // Otherwise take as many mip levels as the texture wants, not to exceed the count in file...
  1208. if (!mip_level_count)
  1209. {
  1210. reducedWidth >>= Reduction;
  1211. reducedHeight >>= Reduction;
  1212. mip_level_count = orig_mip_count-Reduction;//dds_file.Get_Mip_Level_Count();
  1213. if (mip_level_count < 1)
  1214. mip_level_count = 1; //sanity check to make sure something gets loaded.
  1215. }
  1216. else
  1217. {
  1218. if (mip_level_count > orig_mip_count)
  1219. { //dds_file.Get_Mip_Level_Count()) {
  1220. mip_level_count = orig_mip_count;//dds_file.Get_Mip_Level_Count();
  1221. }
  1222. if (Reduction)
  1223. { reducedWidth >>= Reduction;
  1224. reducedHeight >>= Reduction;
  1225. mip_level_count -= Reduction; //reduced requested number by those removed.
  1226. }
  1227. }
  1228. // Once more, verify that the mip level count is correct (in case it was changed here it might not
  1229. // match the size...well actually it doesn't have to match but it can't be bigger than the size)
  1230. unsigned int max_mip_level_count = 1;
  1231. unsigned int w = 4;
  1232. unsigned int h = 4;
  1233. while (w < Width && h < Height)
  1234. {
  1235. w += w;
  1236. h += h;
  1237. max_mip_level_count++;
  1238. }
  1239. if (mip_level_count > max_mip_level_count)
  1240. {
  1241. mip_level_count = max_mip_level_count;
  1242. }
  1243. D3DTexture = DX8Wrapper::_Create_DX8_Texture
  1244. (
  1245. reducedWidth,
  1246. reducedHeight,
  1247. Format,
  1248. (MipCountType)mip_level_count,
  1249. #ifdef USE_MANAGED_TEXTURES
  1250. D3DPOOL_MANAGED
  1251. #else
  1252. D3DPOOL_SYSTEMMEM
  1253. #endif
  1254. );
  1255. MipLevelCount = mip_level_count;
  1256. return true;
  1257. }
  1258. bool TextureLoadTaskClass::Begin_Uncompressed_Load(void)
  1259. {
  1260. unsigned width,height,depth,orig_mip_count,reduction;
  1261. WW3DFormat orig_format;
  1262. if (!Get_Texture_Information
  1263. (
  1264. Texture->Get_Full_Path(),
  1265. reduction,
  1266. width,
  1267. height,
  1268. depth,
  1269. orig_format,
  1270. orig_mip_count,
  1271. false
  1272. )
  1273. )
  1274. {
  1275. return false;
  1276. }
  1277. WW3DFormat src_format=orig_format;
  1278. WW3DFormat dest_format=src_format;
  1279. dest_format=Get_Valid_Texture_Format(dest_format,false); // No compressed destination format if reading from targa...
  1280. if ( src_format != WW3D_FORMAT_A8R8G8B8
  1281. && src_format != WW3D_FORMAT_R8G8B8
  1282. && src_format != WW3D_FORMAT_X8R8G8B8 )
  1283. {
  1284. WWDEBUG_SAY(("Invalid TGA format used in %s - only 24 and 32 bit formats should be used!\n", Texture->Get_Full_Path()));
  1285. }
  1286. // Destination size will be the next power of two square from the larger width and height...
  1287. unsigned ow = width;
  1288. unsigned oh = height;
  1289. TextureLoader::Validate_Texture_Size(width, height,depth);
  1290. if (width != ow || height != oh)
  1291. {
  1292. WWDEBUG_SAY(("Invalid texture size, scaling required. Texture: %s, size: %d x %d -> %d x %d\n", Texture->Get_Full_Path(), ow, oh, width, height));
  1293. }
  1294. Width = width;
  1295. Height = height;
  1296. Reduction = reduction;
  1297. if (!Texture->Is_Reducible() || Texture->MipLevelCount == MIP_LEVELS_1)
  1298. Reduction = 0; //app doesn't want this texture to ever be reduced.
  1299. else
  1300. //Make sure we don't reduce below the level requested by the app
  1301. if (Texture->MipLevelCount != MIP_LEVELS_ALL && (Texture->MipLevelCount - Reduction) < 1)
  1302. Reduction = Texture->MipLevelCount - 1;
  1303. //Another sanity check
  1304. if (Reduction >= orig_mip_count)
  1305. Reduction = 0; //should not be possible to get here, but check just in case.
  1306. if (Format == WW3D_FORMAT_UNKNOWN)
  1307. {
  1308. Format=dest_format;
  1309. // Format = Get_Valid_Texture_Format(dest_format, false); validated above
  1310. }
  1311. else
  1312. {
  1313. Format = Get_Valid_Texture_Format(Format, false);
  1314. }
  1315. int reducedWidth=Width;
  1316. int reducedHeight=Height;
  1317. int reducedMipCount=Texture->MipLevelCount;
  1318. if (Reduction)
  1319. { //we don't care about specific levels so reduce them if needed.
  1320. reducedWidth >>= Reduction;
  1321. reducedHeight >>= Reduction;
  1322. if (reducedMipCount != MIP_LEVELS_ALL)
  1323. reducedMipCount -= Reduction;
  1324. }
  1325. D3DTexture = DX8Wrapper::_Create_DX8_Texture
  1326. (
  1327. reducedWidth,
  1328. reducedHeight,
  1329. Format,
  1330. (MipCountType)reducedMipCount,
  1331. #ifdef USE_MANAGED_TEXTURES
  1332. D3DPOOL_MANAGED
  1333. #else
  1334. D3DPOOL_SYSTEMMEM
  1335. #endif
  1336. );
  1337. return true;
  1338. }
  1339. /*
  1340. bool TextureLoadTaskClass::Begin_Compressed_Load(void)
  1341. {
  1342. DDSFileClass dds_file(Texture->Get_Full_Path(), Get_Reduction());
  1343. if (!dds_file.Is_Available()) {
  1344. return false;
  1345. }
  1346. // Destination size will be the next power of two square from the larger width and height...
  1347. unsigned int width = dds_file.Get_Width(0);
  1348. unsigned int height = dds_file.Get_Height(0);
  1349. TextureLoader::Validate_Texture_Size(width, height);
  1350. // If the size doesn't match, try and see if texture reduction would help... (mainly for
  1351. // cases where loaded texture is larger than hardware limit)
  1352. if (width != dds_file.Get_Width(0) || height != dds_file.Get_Height(0)) {
  1353. for (unsigned int i = 1; i < dds_file.Get_Mip_Level_Count(); ++i) {
  1354. unsigned int w = dds_file.Get_Width(i);
  1355. unsigned int h = dds_file.Get_Height(i);
  1356. TextureLoader::Validate_Texture_Size(w,h);
  1357. if (w == dds_file.Get_Width(i) && h == dds_file.Get_Height(i)) {
  1358. Reduction += i;
  1359. width = w;
  1360. height = h;
  1361. break;
  1362. }
  1363. }
  1364. }
  1365. Width = width;
  1366. Height = height;
  1367. Format = Get_Valid_Texture_Format(dds_file.Get_Format(), Texture->Is_Compression_Allowed());
  1368. unsigned int mip_level_count = Get_Mip_Level_Count();
  1369. // If texture wants all mip levels, take as many as the file contains (not necessarily all)
  1370. // Otherwise take as many mip levels as the texture wants, not to exceed the count in file...
  1371. if (!mip_level_count) {
  1372. mip_level_count = dds_file.Get_Mip_Level_Count();
  1373. } else if (mip_level_count > dds_file.Get_Mip_Level_Count()) {
  1374. mip_level_count = dds_file.Get_Mip_Level_Count();
  1375. }
  1376. // Once more, verify that the mip level count is correct (in case it was changed here it might not
  1377. // match the size...well actually it doesn't have to match but it can't be bigger than the size)
  1378. unsigned int max_mip_level_count = 1;
  1379. unsigned int w = 4;
  1380. unsigned int h = 4;
  1381. while (w < Width && h < Height) {
  1382. w += w;
  1383. h += h;
  1384. max_mip_level_count++;
  1385. }
  1386. if (mip_level_count > max_mip_level_count) {
  1387. mip_level_count = max_mip_level_count;
  1388. }
  1389. D3DTexture = DX8Wrapper::_Create_DX8_Texture(
  1390. Width,
  1391. Height,
  1392. Format,
  1393. (TextureBaseClass::MipCountType)mip_level_count,
  1394. #ifdef USE_MANAGED_TEXTURES
  1395. D3DPOOL_MANAGED);
  1396. #else
  1397. D3DPOOL_SYSTEMMEM);
  1398. #endif
  1399. MipLevelCount = mip_level_count;
  1400. return true;
  1401. }
  1402. bool TextureLoadTaskClass::Begin_Uncompressed_Load(void)
  1403. {
  1404. Targa targa;
  1405. if (TARGA_ERROR_HANDLER(targa.Open(Texture->Get_Full_Path(), TGA_READMODE), Texture->Get_Full_Path())) {
  1406. return false;
  1407. }
  1408. unsigned int bpp;
  1409. WW3DFormat src_format, dest_format;
  1410. Get_WW3D_Format(dest_format,src_format,bpp,targa);
  1411. if ( src_format != WW3D_FORMAT_A8R8G8B8
  1412. && src_format != WW3D_FORMAT_R8G8B8
  1413. && src_format != WW3D_FORMAT_X8R8G8B8) {
  1414. WWDEBUG_SAY(("Invalid TGA format used in %s - only 24 and 32 bit formats should be used!\n", Texture->Get_Full_Path()));
  1415. }
  1416. // Destination size will be the next power of two square from the larger width and height...
  1417. unsigned width=targa.Header.Width, height=targa.Header.Height;
  1418. int ReductionFactor=Get_Reduction();
  1419. int MipLevels=0;
  1420. //Figure out how many mip levels this texture will occupy
  1421. for (int i=width, j=height; i > 0 && j > 0; i>>=1, j>>=1)
  1422. MipLevels++;
  1423. //Adjust the reduction factor to keep textures above some minimum dimensions
  1424. if (MipLevels <= WW3D::Get_Texture_Min_Mip_Levels())
  1425. ReductionFactor=0;
  1426. else
  1427. { int mipToDrop=MipLevels-WW3D::Get_Texture_Min_Mip_Levels();
  1428. if (ReductionFactor >= mipToDrop)
  1429. ReductionFactor=mipToDrop;
  1430. }
  1431. width=targa.Header.Width>>ReductionFactor;
  1432. height=targa.Header.Height>>ReductionFactor;
  1433. unsigned ow = width;
  1434. unsigned oh = height;
  1435. TextureLoader::Validate_Texture_Size(width, height);
  1436. if (width != ow || height != oh) {
  1437. WWDEBUG_SAY(("Invalid texture size, scaling required. Texture: %s, size: %d x %d -> %d x %d\n", Texture->Get_Full_Path(), ow, oh, width, height));
  1438. }
  1439. Width = width;
  1440. Height = height;
  1441. // changed because format was being read from previous loading task?! KJM
  1442. Format=dest_format;
  1443. //if (Format == WW3D_FORMAT_UNKNOWN) {
  1444. // Format = Get_Valid_Texture_Format(dest_format, false);
  1445. //} else {
  1446. // Format = Get_Valid_Texture_Format(Format, false);
  1447. //}
  1448. D3DTexture = DX8Wrapper::_Create_DX8_Texture
  1449. (
  1450. Width,
  1451. Height,
  1452. Format,
  1453. Texture->MipLevelCount,
  1454. #ifdef USE_MANAGED_TEXTURES
  1455. D3DPOOL_MANAGED);
  1456. #else
  1457. D3DPOOL_SYSTEMMEM);
  1458. #endif
  1459. return true;
  1460. }
  1461. */
  1462. void TextureLoadTaskClass::Lock_Surfaces(void)
  1463. {
  1464. MipLevelCount = D3DTexture->GetLevelCount();
  1465. for (unsigned int i = 0; i < MipLevelCount; ++i)
  1466. {
  1467. D3DLOCKED_RECT locked_rect;
  1468. DX8_ErrorCode
  1469. (
  1470. Peek_D3D_Texture()->LockRect
  1471. (
  1472. i,
  1473. &locked_rect,
  1474. NULL,
  1475. 0
  1476. )
  1477. );
  1478. LockedSurfacePtr[i] = (unsigned char *)locked_rect.pBits;
  1479. LockedSurfacePitch[i] = locked_rect.Pitch;
  1480. }
  1481. }
  1482. void TextureLoadTaskClass::Unlock_Surfaces(void)
  1483. {
  1484. for (unsigned int i = 0; i < MipLevelCount; ++i)
  1485. {
  1486. if (LockedSurfacePtr[i])
  1487. {
  1488. WWASSERT(ThreadClass::_Get_Current_Thread_ID() == DX8Wrapper::_Get_Main_Thread_ID());
  1489. DX8_ErrorCode(Peek_D3D_Texture()->UnlockRect(i));
  1490. }
  1491. LockedSurfacePtr[i] = NULL;
  1492. }
  1493. #ifndef USE_MANAGED_TEXTURES
  1494. IDirect3DTexture8* tex = DX8Wrapper::_Create_DX8_Texture(Width, Height, Format, Texture->MipLevelCount,D3DPOOL_DEFAULT);
  1495. DX8CALL(UpdateTexture(Peek_D3D_Texture(),tex));
  1496. Peek_D3D_Texture()->Release();
  1497. D3DTexture=tex;
  1498. WWDEBUG_SAY(("Created non-managed texture (%s)\n",Texture->Get_Full_Path()));
  1499. #endif
  1500. }
  1501. bool TextureLoadTaskClass::Load_Compressed_Mipmap(void)
  1502. {
  1503. DDSFileClass dds_file(Texture->Get_Full_Path(), Get_Reduction());
  1504. // if we can't load from file, indicate rror.
  1505. if (!dds_file.Is_Available() || !dds_file.Load())
  1506. {
  1507. return false;
  1508. }
  1509. // regular 2d texture
  1510. unsigned int width = Get_Width();
  1511. unsigned int height = Get_Height();
  1512. if (Reduction)
  1513. { for (unsigned int level = 0; level < Reduction; ++level) {
  1514. width >>= 1;
  1515. height >>= 1;
  1516. }
  1517. }
  1518. for (unsigned int level = 0; level < Get_Mip_Level_Count(); ++level)
  1519. {
  1520. WWASSERT(width && height);
  1521. dds_file.Copy_Level_To_Surface
  1522. (
  1523. level,
  1524. Get_Format(),
  1525. width,
  1526. height,
  1527. Get_Locked_Surface_Ptr(level),
  1528. Get_Locked_Surface_Pitch(level),
  1529. HSVShift
  1530. );
  1531. width >>= 1;
  1532. height >>= 1;
  1533. }
  1534. return true;
  1535. }
  1536. bool TextureLoadTaskClass::Load_Uncompressed_Mipmap(void)
  1537. {
  1538. if (!Get_Mip_Level_Count())
  1539. {
  1540. return false;
  1541. }
  1542. Targa targa;
  1543. if (TARGA_ERROR_HANDLER(targa.Open(Texture->Get_Full_Path(), TGA_READMODE), Texture->Get_Full_Path())) {
  1544. return false;
  1545. }
  1546. // DX8 uses image upside down compared to TGA
  1547. targa.Header.ImageDescriptor ^= TGAIDF_YORIGIN;
  1548. WW3DFormat src_format;
  1549. WW3DFormat dest_format;
  1550. unsigned int src_bpp = 0;
  1551. Get_WW3D_Format(dest_format,src_format,src_bpp,targa);
  1552. if (src_format==WW3D_FORMAT_UNKNOWN) return false;
  1553. dest_format = Get_Format(); // Texture can be requested in different format than the most obvious from the TGA
  1554. char palette[256*4];
  1555. targa.SetPalette(palette);
  1556. unsigned int src_width = targa.Header.Width;
  1557. unsigned int src_height = targa.Header.Height;
  1558. unsigned int width = Get_Width();
  1559. unsigned int height = Get_Height();
  1560. // NOTE: We load the palette but we do not yet support paletted textures!
  1561. if (TARGA_ERROR_HANDLER(targa.Load(Texture->Get_Full_Path(), TGAF_IMAGE, false), Texture->Get_Full_Path())) {
  1562. return false;
  1563. }
  1564. unsigned char * src_surface = (unsigned char*)targa.GetImage();
  1565. unsigned char * converted_surface = NULL;
  1566. // No paletted format allowed when generating mipmaps
  1567. Vector3 hsv_shift=HSVShift;
  1568. if ( src_format == WW3D_FORMAT_A1R5G5B5
  1569. || src_format == WW3D_FORMAT_R5G6B5
  1570. || src_format == WW3D_FORMAT_A4R4G4B4
  1571. || src_format == WW3D_FORMAT_P8
  1572. || src_format == WW3D_FORMAT_L8
  1573. || src_width != width
  1574. || src_height != height) {
  1575. converted_surface = new unsigned char[width*height*4];
  1576. dest_format = Get_Valid_Texture_Format(WW3D_FORMAT_A8R8G8B8, false);
  1577. BitmapHandlerClass::Copy_Image(
  1578. converted_surface,
  1579. width,
  1580. height,
  1581. width*4,
  1582. WW3D_FORMAT_A8R8G8B8, //dest_format,
  1583. src_surface,
  1584. src_width,
  1585. src_height,
  1586. src_width*src_bpp,
  1587. src_format,
  1588. (unsigned char*)targa.GetPalette(),
  1589. targa.Header.CMapDepth>>3,
  1590. false,
  1591. hsv_shift);
  1592. hsv_shift=Vector3(0.0f,0.0f,0.0f);
  1593. src_surface = converted_surface;
  1594. src_format = WW3D_FORMAT_A8R8G8B8; //dest_format;
  1595. src_width = width;
  1596. src_height = height;
  1597. src_bpp = Get_Bytes_Per_Pixel(src_format);
  1598. }
  1599. unsigned src_pitch = src_width * src_bpp;
  1600. if (Reduction)
  1601. { //texture needs to be reduced so allocate storage for full-sized version.
  1602. unsigned char * destination_surface = new unsigned char[width*height*4];
  1603. //generate upper mip-levels that will be dropped in final texture
  1604. for (unsigned int level = 0; level < Reduction; ++level) {
  1605. BitmapHandlerClass::Copy_Image(
  1606. (unsigned char *)destination_surface,
  1607. width,
  1608. height,
  1609. src_pitch,
  1610. Get_Format(),
  1611. src_surface,
  1612. src_width,
  1613. src_height,
  1614. src_pitch,
  1615. src_format,
  1616. NULL,
  1617. 0,
  1618. true,
  1619. hsv_shift);
  1620. width >>= 1;
  1621. height >>= 1;
  1622. src_width >>= 1;
  1623. src_height >>= 1;
  1624. }
  1625. delete [] destination_surface;
  1626. }
  1627. for (unsigned int level = 0; level < Get_Mip_Level_Count(); ++level) {
  1628. WWASSERT(Get_Locked_Surface_Ptr(level));
  1629. BitmapHandlerClass::Copy_Image(
  1630. Get_Locked_Surface_Ptr(level),
  1631. width,
  1632. height,
  1633. Get_Locked_Surface_Pitch(level),
  1634. Get_Format(),
  1635. src_surface,
  1636. src_width,
  1637. src_height,
  1638. src_pitch,
  1639. src_format,
  1640. NULL,
  1641. 0,
  1642. true,
  1643. hsv_shift);
  1644. hsv_shift=Vector3(0.0f,0.0f,0.0f);
  1645. width >>= 1;
  1646. height >>= 1;
  1647. src_width >>= 1;
  1648. src_height >>= 1;
  1649. if (!width || !height || !src_width || !src_height) {
  1650. break;
  1651. }
  1652. }
  1653. if (converted_surface) {
  1654. delete[] converted_surface;
  1655. }
  1656. return true;
  1657. }
  1658. unsigned char * TextureLoadTaskClass::Get_Locked_Surface_Ptr(unsigned int level)
  1659. {
  1660. WWASSERT(level<MipLevelCount);
  1661. WWASSERT(LockedSurfacePtr[level]);
  1662. return LockedSurfacePtr[level];
  1663. }
  1664. // ----------------------------------------------------------------------------
  1665. //
  1666. // Return locked surface pitch (in bytes) at a specific level. The call will
  1667. // assert if level is greater or equal to the number of mip levels or if the
  1668. // requested level has not been locked.
  1669. //
  1670. // ----------------------------------------------------------------------------
  1671. unsigned int TextureLoadTaskClass::Get_Locked_Surface_Pitch(unsigned int level) const
  1672. {
  1673. WWASSERT(level<MipLevelCount);
  1674. WWASSERT(LockedSurfacePtr[level]);
  1675. return LockedSurfacePitch[level];
  1676. }
  1677. // CubeTextureLoadTaskClass
  1678. CubeTextureLoadTaskClass::CubeTextureLoadTaskClass()
  1679. : TextureLoadTaskClass()
  1680. {
  1681. // because texture load tasks are pooled, the constructor and destructor
  1682. // don't need to do much. The work of attaching a task to a texture is
  1683. // is done by Init() and Deinit().
  1684. for (int f=0;f<6;f++)
  1685. {
  1686. for (int i = 0; i < MIP_LEVELS_MAX; ++i)
  1687. {
  1688. LockedCubeSurfacePtr[f][i] = NULL;
  1689. LockedCubeSurfacePitch[f][i] = 0;
  1690. }
  1691. }
  1692. }
  1693. void CubeTextureLoadTaskClass::Destroy(void)
  1694. {
  1695. // detach the task from its texture, and return to free pool.
  1696. Deinit();
  1697. _CubeTexLoadFreeList.Push_Front(this);
  1698. }
  1699. void CubeTextureLoadTaskClass::Init(TextureBaseClass* tc, TaskType type, PriorityType priority)
  1700. {
  1701. WWASSERT(tc);
  1702. // NOTE: we must be in the main thread to avoid corrupting the texture's refcount.
  1703. WWASSERT(TextureLoader::Is_DX8_Thread());
  1704. REF_PTR_SET(Texture, tc);
  1705. // Make sure texture has a filename.
  1706. WWASSERT(Texture->Get_Full_Path() != "");
  1707. Type = type;
  1708. Priority = priority;
  1709. State = STATE_NONE;
  1710. D3DTexture = 0;
  1711. CubeTextureClass* tex=Texture->As_CubeTextureClass();
  1712. if (tex)
  1713. {
  1714. Format = tex->Get_Texture_Format(); // don't assume format yet KM
  1715. }
  1716. else
  1717. {
  1718. Format = WW3D_FORMAT_UNKNOWN;
  1719. }
  1720. Width = 0;
  1721. Height = 0;
  1722. MipLevelCount = Texture->MipLevelCount;
  1723. Reduction = Texture->Get_Reduction();
  1724. HSVShift = Texture->Get_HSV_Shift();
  1725. for (int f=0; f<6; f++)
  1726. {
  1727. for (int i = 0; i < MIP_LEVELS_MAX; ++i)
  1728. {
  1729. LockedCubeSurfacePtr[f][i] = NULL;
  1730. LockedCubeSurfacePitch[f][i] = 0;
  1731. }
  1732. }
  1733. switch (Type)
  1734. {
  1735. case TASK_THUMBNAIL:
  1736. WWASSERT(Texture->ThumbnailLoadTask == NULL);
  1737. Texture->ThumbnailLoadTask = this;
  1738. break;
  1739. case TASK_LOAD:
  1740. WWASSERT(Texture->TextureLoadTask == NULL);
  1741. Texture->TextureLoadTask = this;
  1742. break;
  1743. }
  1744. }
  1745. void CubeTextureLoadTaskClass::Deinit()
  1746. {
  1747. // task should not be on any list when it is being detached from texture.
  1748. WWASSERT(Next == NULL);
  1749. WWASSERT(Prev == NULL);
  1750. WWASSERT(D3DTexture == NULL);
  1751. for (int f=0; f<6; f++)
  1752. {
  1753. for (int i = 0; i < MIP_LEVELS_MAX; ++i)
  1754. {
  1755. WWASSERT(LockedCubeSurfacePtr[f][i] == NULL);
  1756. }
  1757. }
  1758. if (Texture)
  1759. {
  1760. switch (Type)
  1761. {
  1762. case TASK_THUMBNAIL:
  1763. WWASSERT(Texture->ThumbnailLoadTask == this);
  1764. Texture->ThumbnailLoadTask = NULL;
  1765. break;
  1766. case TASK_LOAD:
  1767. WWASSERT(Texture->TextureLoadTask == this);
  1768. Texture->TextureLoadTask = NULL;
  1769. break;
  1770. }
  1771. // NOTE: we must be in main thread to avoid corrupting Texture's refcount.
  1772. WWASSERT(TextureLoader::Is_DX8_Thread());
  1773. REF_PTR_RELEASE(Texture);
  1774. }
  1775. }
  1776. void CubeTextureLoadTaskClass::Lock_Surfaces(void)
  1777. {
  1778. for (unsigned int f=0; f<6; f++)
  1779. {
  1780. for (unsigned int i=0; i<MipLevelCount; i++)
  1781. {
  1782. D3DLOCKED_RECT locked_rect;
  1783. DX8_ErrorCode
  1784. (
  1785. Peek_D3D_Cube_Texture()->LockRect
  1786. (
  1787. (D3DCUBEMAP_FACES)f,
  1788. i,
  1789. &locked_rect,
  1790. NULL,
  1791. 0
  1792. )
  1793. );
  1794. LockedCubeSurfacePtr[f][i] = (unsigned char *)locked_rect.pBits;
  1795. LockedCubeSurfacePitch[f][i]= locked_rect.Pitch;
  1796. }
  1797. }
  1798. }
  1799. void CubeTextureLoadTaskClass::Unlock_Surfaces(void)
  1800. {
  1801. for (unsigned int f=0; f<6; f++)
  1802. {
  1803. for (unsigned int i = 0; i < MipLevelCount; ++i)
  1804. {
  1805. if (LockedCubeSurfacePtr[f][i])
  1806. {
  1807. WWASSERT(ThreadClass::_Get_Current_Thread_ID() == DX8Wrapper::_Get_Main_Thread_ID());
  1808. DX8_ErrorCode
  1809. (
  1810. Peek_D3D_Cube_Texture()->UnlockRect((D3DCUBEMAP_FACES)f,i)
  1811. );
  1812. }
  1813. LockedCubeSurfacePtr[f][i] = NULL;
  1814. }
  1815. }
  1816. #ifndef USE_MANAGED_TEXTURES
  1817. IDirect3DCubeTexture8* tex = DX8Wrapper::_Create_DX8_Cube_Texture
  1818. (
  1819. Width,
  1820. Height,
  1821. Format,
  1822. Texture->MipLevelCount,
  1823. D3DPOOL_DEFAULT
  1824. );
  1825. DX8CALL(UpdateTexture(Peek_D3D_Volume_Texture(),tex));
  1826. Peek_D3D_Volume_Texture()->Release();
  1827. D3DTexture=tex;
  1828. WWDEBUG_SAY(("Created non-managed texture (%s)\n",Texture->Get_Full_Path()));
  1829. #endif
  1830. }
  1831. bool CubeTextureLoadTaskClass::Begin_Compressed_Load()
  1832. {
  1833. unsigned orig_w,orig_h,orig_d,orig_mip_count,reduction;
  1834. WW3DFormat orig_format;
  1835. if (!Get_Texture_Information
  1836. (
  1837. Texture->Get_Full_Path(),
  1838. reduction,
  1839. orig_w,
  1840. orig_h,
  1841. orig_d,
  1842. orig_format,
  1843. orig_mip_count,
  1844. true
  1845. )
  1846. )
  1847. {
  1848. return false;
  1849. }
  1850. // Destination size will be the next power of two square from the larger width and height...
  1851. unsigned int width = orig_w;
  1852. unsigned int height = orig_h;
  1853. TextureLoader::Validate_Texture_Size(width, height,orig_d);
  1854. // If the size doesn't match, try and see if texture reduction would help... (mainly for
  1855. // cases where loaded texture is larger than hardware limit)
  1856. if (width != orig_w || height != orig_h)
  1857. {
  1858. for (unsigned int i = 1; i < orig_mip_count; ++i)
  1859. {
  1860. unsigned w=orig_w>>i;
  1861. if (w<4) w=4;
  1862. unsigned h=orig_h>>i;
  1863. if (h<4) h=4;
  1864. unsigned tmp_w=w;
  1865. unsigned tmp_h=h;
  1866. TextureLoader::Validate_Texture_Size(w,h,orig_d);
  1867. if (w == tmp_w && h == tmp_h)
  1868. {
  1869. Reduction += i;
  1870. width = w;
  1871. height = h;
  1872. break;
  1873. }
  1874. }
  1875. }
  1876. Width = width;
  1877. Height = height;
  1878. Format = Get_Valid_Texture_Format(orig_format, Texture->Is_Compression_Allowed());
  1879. unsigned int mip_level_count = Get_Mip_Level_Count();
  1880. // If texture wants all mip levels, take as many as the file contains (not necessarily all)
  1881. // Otherwise take as many mip levels as the texture wants, not to exceed the count in file...
  1882. if (!mip_level_count)
  1883. {
  1884. mip_level_count = orig_mip_count;//dds_file.Get_Mip_Level_Count();
  1885. }
  1886. else if (mip_level_count > orig_mip_count)
  1887. {//dds_file.Get_Mip_Level_Count()) {
  1888. mip_level_count = orig_mip_count;//dds_file.Get_Mip_Level_Count();
  1889. }
  1890. // Once more, verify that the mip level count is correct (in case it was changed here it might not
  1891. // match the size...well actually it doesn't have to match but it can't be bigger than the size)
  1892. unsigned int max_mip_level_count = 1;
  1893. unsigned int w = 4;
  1894. unsigned int h = 4;
  1895. while (w < Width && h < Height)
  1896. {
  1897. w += w;
  1898. h += h;
  1899. max_mip_level_count++;
  1900. }
  1901. if (mip_level_count > max_mip_level_count)
  1902. {
  1903. mip_level_count = max_mip_level_count;
  1904. }
  1905. D3DTexture = DX8Wrapper::_Create_DX8_Cube_Texture
  1906. (
  1907. Width,
  1908. Height,
  1909. Format,
  1910. (MipCountType)mip_level_count,
  1911. #ifdef USE_MANAGED_TEXTURES
  1912. D3DPOOL_MANAGED
  1913. #else
  1914. D3DPOOL_SYSTEMMEM
  1915. #endif
  1916. );
  1917. MipLevelCount = mip_level_count;
  1918. return true;
  1919. }
  1920. bool CubeTextureLoadTaskClass::Begin_Uncompressed_Load(void)
  1921. {
  1922. unsigned width,height,depth,orig_mip_count,reduction;
  1923. WW3DFormat orig_format;
  1924. if (!Get_Texture_Information
  1925. (
  1926. Texture->Get_Full_Path(),
  1927. reduction,
  1928. width,
  1929. height,
  1930. depth,
  1931. orig_format,
  1932. orig_mip_count,
  1933. false
  1934. )
  1935. )
  1936. {
  1937. return false;
  1938. }
  1939. WW3DFormat src_format=orig_format;
  1940. WW3DFormat dest_format=src_format;
  1941. dest_format=Get_Valid_Texture_Format(dest_format,false); // No compressed destination format if reading from targa...
  1942. if ( src_format != WW3D_FORMAT_A8R8G8B8
  1943. && src_format != WW3D_FORMAT_R8G8B8
  1944. && src_format != WW3D_FORMAT_X8R8G8B8 )
  1945. {
  1946. WWDEBUG_SAY(("Invalid TGA format used in %s - only 24 and 32 bit formats should be used!\n", Texture->Get_Full_Path()));
  1947. }
  1948. // Destination size will be the next power of two square from the larger width and height...
  1949. unsigned ow = width;
  1950. unsigned oh = height;
  1951. TextureLoader::Validate_Texture_Size(width, height,depth);
  1952. if (width != ow || height != oh)
  1953. {
  1954. WWDEBUG_SAY(("Invalid texture size, scaling required. Texture: %s, size: %d x %d -> %d x %d\n", Texture->Get_Full_Path(), ow, oh, width, height));
  1955. }
  1956. Width = width;
  1957. Height = height;
  1958. if (Format == WW3D_FORMAT_UNKNOWN)
  1959. {
  1960. Format=dest_format;
  1961. }
  1962. else
  1963. {
  1964. Format = Get_Valid_Texture_Format(Format, false);
  1965. }
  1966. D3DTexture = DX8Wrapper::_Create_DX8_Cube_Texture
  1967. (
  1968. Width,
  1969. Height,
  1970. Format,
  1971. Texture->MipLevelCount,
  1972. #ifdef USE_MANAGED_TEXTURES
  1973. D3DPOOL_MANAGED
  1974. #else
  1975. D3DPOOL_SYSTEMMEM
  1976. #endif
  1977. );
  1978. return true;
  1979. }
  1980. bool CubeTextureLoadTaskClass::Load_Compressed_Mipmap(void)
  1981. {
  1982. DDSFileClass dds_file(Texture->Get_Full_Path(), Get_Reduction());
  1983. // if we can't load from file, indicate rror.
  1984. if (!dds_file.Is_Available() || !dds_file.Load())
  1985. {
  1986. return false;
  1987. }
  1988. // load cube map faces
  1989. for (unsigned int face=0; face<6; face++)
  1990. {
  1991. unsigned int width = Get_Width();
  1992. unsigned int height = Get_Height();
  1993. for (unsigned int level=0; level<Get_Mip_Level_Count(); level++)
  1994. {
  1995. WWASSERT(width && height);
  1996. // get cube map surface
  1997. dds_file.Copy_CubeMap_Level_To_Surface
  1998. (
  1999. face,
  2000. level,
  2001. Get_Format(),
  2002. width,
  2003. height,
  2004. Get_Locked_CubeMap_Surface_Pointer(face,level),
  2005. Get_Locked_CubeMap_Surface_Pitch(face,level),
  2006. HSVShift
  2007. );
  2008. width>>=1;
  2009. height>>=1;
  2010. }
  2011. }
  2012. return true;
  2013. }
  2014. unsigned char* CubeTextureLoadTaskClass::Get_Locked_CubeMap_Surface_Pointer(unsigned int face, unsigned int level)
  2015. {
  2016. WWASSERT(face<6 && level<MipLevelCount);
  2017. WWASSERT(LockedCubeSurfacePtr[face][level]);
  2018. return LockedCubeSurfacePtr[face][level];
  2019. }
  2020. unsigned int CubeTextureLoadTaskClass::Get_Locked_CubeMap_Surface_Pitch(unsigned int face, unsigned int level) const
  2021. {
  2022. WWASSERT(face<6 && level<MipLevelCount);
  2023. WWASSERT(LockedCubeSurfacePitch[face][level]);
  2024. return LockedCubeSurfacePitch[face][level];
  2025. }
  2026. // VolumeTextureLoadTaskClass
  2027. VolumeTextureLoadTaskClass::VolumeTextureLoadTaskClass()
  2028. : TextureLoadTaskClass()
  2029. {
  2030. // because texture load tasks are pooled, the constructor and destructor
  2031. // don't need to do much. The work of attaching a task to a texture is
  2032. // is done by Init() and Deinit().
  2033. for (int i = 0; i < MIP_LEVELS_MAX; ++i)
  2034. {
  2035. LockedSurfacePtr[i] = NULL;
  2036. LockedSurfacePitch[i] = 0;
  2037. LockedSurfaceSlicePitch[i] = 0;
  2038. }
  2039. }
  2040. void VolumeTextureLoadTaskClass::Destroy(void)
  2041. {
  2042. // detach the task from its texture, and return to free pool.
  2043. Deinit();
  2044. _VolTexLoadFreeList.Push_Front(this);
  2045. }
  2046. void VolumeTextureLoadTaskClass::Init(TextureBaseClass* tc, TaskType type, PriorityType priority)
  2047. {
  2048. WWASSERT(tc);
  2049. // NOTE: we must be in the main thread to avoid corrupting the texture's refcount.
  2050. WWASSERT(TextureLoader::Is_DX8_Thread());
  2051. REF_PTR_SET(Texture, tc);
  2052. // Make sure texture has a filename.
  2053. WWASSERT(Texture->Get_Full_Path() != "");
  2054. Type = type;
  2055. Priority = priority;
  2056. State = STATE_NONE;
  2057. D3DTexture = 0;
  2058. VolumeTextureClass* tex=Texture->As_VolumeTextureClass();
  2059. if (tex)
  2060. {
  2061. Format = tex->Get_Texture_Format(); // don't assume format yet KM
  2062. }
  2063. else
  2064. {
  2065. Format = WW3D_FORMAT_UNKNOWN;
  2066. }
  2067. Width = 0;
  2068. Height = 0;
  2069. Depth = 0;
  2070. MipLevelCount = Texture->MipLevelCount;
  2071. Reduction = Texture->Get_Reduction();
  2072. HSVShift = Texture->Get_HSV_Shift();
  2073. for (int i = 0; i < MIP_LEVELS_MAX; ++i)
  2074. {
  2075. LockedSurfacePtr[i] = NULL;
  2076. LockedSurfacePitch[i] = 0;
  2077. LockedSurfaceSlicePitch[i] = 0;
  2078. }
  2079. switch (Type)
  2080. {
  2081. case TASK_THUMBNAIL:
  2082. WWASSERT(Texture->ThumbnailLoadTask == NULL);
  2083. Texture->ThumbnailLoadTask = this;
  2084. break;
  2085. case TASK_LOAD:
  2086. WWASSERT(Texture->TextureLoadTask == NULL);
  2087. Texture->TextureLoadTask = this;
  2088. break;
  2089. }
  2090. }
  2091. void VolumeTextureLoadTaskClass::Lock_Surfaces()
  2092. {
  2093. for (unsigned int i=0; i<MipLevelCount; i++)
  2094. {
  2095. D3DLOCKED_BOX locked_box;
  2096. DX8_ErrorCode
  2097. (
  2098. Peek_D3D_Volume_Texture()->LockBox
  2099. (
  2100. i,
  2101. &locked_box,
  2102. NULL,
  2103. 0
  2104. )
  2105. );
  2106. LockedSurfacePtr[i] = (unsigned char *)locked_box.pBits;
  2107. LockedSurfacePitch[i] = locked_box.RowPitch;
  2108. LockedSurfaceSlicePitch[i] = locked_box.SlicePitch;
  2109. }
  2110. }
  2111. void VolumeTextureLoadTaskClass::Unlock_Surfaces()
  2112. {
  2113. for (unsigned int i = 0; i < MipLevelCount; ++i)
  2114. {
  2115. if (LockedSurfacePtr[i])
  2116. {
  2117. WWASSERT(ThreadClass::_Get_Current_Thread_ID() == DX8Wrapper::_Get_Main_Thread_ID());
  2118. DX8_ErrorCode
  2119. (
  2120. Peek_D3D_Volume_Texture()->UnlockBox(i)
  2121. );
  2122. }
  2123. LockedSurfacePtr[i] = NULL;
  2124. }
  2125. #ifndef USE_MANAGED_TEXTURES
  2126. IDirect3DTexture8* tex = DX8Wrapper::_Create_DX8_Volume_Texture(Width, Height, Depth, Format, Texture->MipLevelCount,D3DPOOL_DEFAULT);
  2127. DX8CALL(UpdateTexture(Peek_D3D_Volume_Texture(),tex));
  2128. Peek_D3D_Volume_Texture()->Release();
  2129. D3DTexture=tex;
  2130. WWDEBUG_SAY(("Created non-managed texture (%s)\n",Texture->Get_Full_Path()));
  2131. #endif
  2132. }
  2133. bool VolumeTextureLoadTaskClass::Begin_Compressed_Load()
  2134. {
  2135. unsigned orig_w,orig_h,orig_d,orig_mip_count,reduction;
  2136. WW3DFormat orig_format;
  2137. if (!Get_Texture_Information
  2138. (
  2139. Texture->Get_Full_Path(),
  2140. reduction,
  2141. orig_w,
  2142. orig_h,
  2143. orig_d,
  2144. orig_format,
  2145. orig_mip_count,
  2146. true
  2147. )
  2148. )
  2149. {
  2150. return false;
  2151. }
  2152. // Destination size will be the next power of two square from the larger width and height...
  2153. unsigned int width = orig_w;
  2154. unsigned int height = orig_h;
  2155. unsigned int depth = orig_d;
  2156. TextureLoader::Validate_Texture_Size(width, height, depth);
  2157. // If the size doesn't match, try and see if texture reduction would help... (mainly for
  2158. // cases where loaded texture is larger than hardware limit)
  2159. if (width != orig_w || height != orig_h || depth != orig_d)
  2160. {
  2161. for (unsigned int i = 1; i < orig_mip_count; ++i)
  2162. {
  2163. unsigned w=orig_w>>i;
  2164. if (w<4) w=4;
  2165. unsigned h=orig_h>>i;
  2166. if (h<4) h=4;
  2167. unsigned d=orig_d>>i;
  2168. if (d<1) d=1;
  2169. unsigned tmp_w=w;
  2170. unsigned tmp_h=h;
  2171. unsigned tmp_d=d;
  2172. TextureLoader::Validate_Texture_Size(w,h,d);
  2173. if (w == tmp_w && h == tmp_h && d== tmp_d)
  2174. {
  2175. Reduction += i;
  2176. width = w;
  2177. height = h;
  2178. depth = d;
  2179. break;
  2180. }
  2181. }
  2182. }
  2183. Width = width;
  2184. Height = height;
  2185. Depth = depth;
  2186. Format = Get_Valid_Texture_Format(orig_format, Texture->Is_Compression_Allowed());
  2187. unsigned int mip_level_count = Get_Mip_Level_Count();
  2188. // If texture wants all mip levels, take as many as the file contains (not necessarily all)
  2189. // Otherwise take as many mip levels as the texture wants, not to exceed the count in file...
  2190. if (!mip_level_count)
  2191. {
  2192. mip_level_count = orig_mip_count;//dds_file.Get_Mip_Level_Count();
  2193. }
  2194. else if (mip_level_count > orig_mip_count)
  2195. {//dds_file.Get_Mip_Level_Count()) {
  2196. mip_level_count = orig_mip_count;//dds_file.Get_Mip_Level_Count();
  2197. }
  2198. // Once more, verify that the mip level count is correct (in case it was changed here it might not
  2199. // match the size...well actually it doesn't have to match but it can't be bigger than the size)
  2200. unsigned int max_mip_level_count = 1;
  2201. unsigned int w = 4;
  2202. unsigned int h = 4;
  2203. while (w < Width && h < Height)
  2204. {
  2205. w += w;
  2206. h += h;
  2207. max_mip_level_count++;
  2208. }
  2209. if (mip_level_count > max_mip_level_count)
  2210. {
  2211. mip_level_count = max_mip_level_count;
  2212. }
  2213. D3DTexture = DX8Wrapper::_Create_DX8_Volume_Texture
  2214. (
  2215. Width,
  2216. Height,
  2217. Depth,
  2218. Format,
  2219. (MipCountType)mip_level_count,
  2220. #ifdef USE_MANAGED_TEXTURES
  2221. D3DPOOL_MANAGED
  2222. #else
  2223. D3DPOOL_SYSTEMMEM
  2224. #endif
  2225. );
  2226. MipLevelCount = mip_level_count;
  2227. return true;
  2228. }
  2229. bool VolumeTextureLoadTaskClass::Begin_Uncompressed_Load(void)
  2230. {
  2231. unsigned width,height,depth,orig_mip_count,reduction;
  2232. WW3DFormat orig_format;
  2233. if (!Get_Texture_Information
  2234. (
  2235. Texture->Get_Full_Path(),
  2236. reduction,
  2237. width,
  2238. height,
  2239. depth,
  2240. orig_format,
  2241. orig_mip_count,
  2242. false
  2243. )
  2244. )
  2245. {
  2246. return false;
  2247. }
  2248. WW3DFormat src_format=orig_format;
  2249. WW3DFormat dest_format=src_format;
  2250. dest_format=Get_Valid_Texture_Format(dest_format,false); // No compressed destination format if reading from targa...
  2251. if ( src_format != WW3D_FORMAT_A8R8G8B8
  2252. && src_format != WW3D_FORMAT_R8G8B8
  2253. && src_format != WW3D_FORMAT_X8R8G8B8 )
  2254. {
  2255. WWDEBUG_SAY(("Invalid TGA format used in %s - only 24 and 32 bit formats should be used!\n", Texture->Get_Full_Path()));
  2256. }
  2257. // Destination size will be the next power of two square from the larger width and height...
  2258. unsigned ow = width;
  2259. unsigned oh = height;
  2260. unsigned od = depth;
  2261. TextureLoader::Validate_Texture_Size(width, height, depth);
  2262. if (width != ow || height != oh || depth != od)
  2263. {
  2264. WWDEBUG_SAY(("Invalid texture size, scaling required. Texture: %s, size: %d x %d -> %d x %d\n", Texture->Get_Full_Path(), ow, oh, width, height));
  2265. }
  2266. Width = width;
  2267. Height = height;
  2268. Depth = depth;
  2269. if (Format == WW3D_FORMAT_UNKNOWN)
  2270. {
  2271. Format=dest_format;
  2272. }
  2273. else
  2274. {
  2275. Format = Get_Valid_Texture_Format(Format, false);
  2276. }
  2277. D3DTexture = DX8Wrapper::_Create_DX8_Volume_Texture
  2278. (
  2279. Width,
  2280. Height,
  2281. Depth,
  2282. Format,
  2283. Texture->MipLevelCount,
  2284. #ifdef USE_MANAGED_TEXTURES
  2285. D3DPOOL_MANAGED
  2286. #else
  2287. D3DPOOL_SYSTEMMEM
  2288. #endif
  2289. );
  2290. return true;
  2291. }
  2292. bool VolumeTextureLoadTaskClass::Load_Compressed_Mipmap(void)
  2293. {
  2294. DDSFileClass dds_file(Texture->Get_Full_Path(), Get_Reduction());
  2295. // if we can't load from file, indicate rror.
  2296. if (!dds_file.Is_Available() || !dds_file.Load())
  2297. {
  2298. return false;
  2299. }
  2300. // load volume
  2301. unsigned int depth=dds_file.Get_Depth(0);
  2302. unsigned int width=Get_Width();
  2303. unsigned int height=Get_Height();
  2304. WWASSERT(width && height && depth);
  2305. for (unsigned int level=0; level<Get_Mip_Level_Count(); level++)
  2306. {
  2307. if (width<1) width=1;
  2308. if (height<1) height=1;
  2309. if (depth<1) depth=1;
  2310. // get volume
  2311. dds_file.Copy_Volume_Level_To_Surface
  2312. (
  2313. level,
  2314. depth,
  2315. Get_Format(),
  2316. width,
  2317. height,
  2318. Get_Locked_Volume_Pointer(level),
  2319. Get_Locked_Volume_Row_Pitch(level),
  2320. Get_Locked_Volume_Slice_Pitch(level),
  2321. HSVShift
  2322. );
  2323. width>>=1;
  2324. height>>=1;
  2325. depth>>=1;
  2326. }
  2327. return true;
  2328. }
  2329. unsigned char* VolumeTextureLoadTaskClass::Get_Locked_Volume_Pointer(unsigned int level)
  2330. {
  2331. WWASSERT(level<MipLevelCount);
  2332. WWASSERT(LockedSurfacePtr[level]);
  2333. return LockedSurfacePtr[level];
  2334. }
  2335. unsigned int VolumeTextureLoadTaskClass::Get_Locked_Volume_Row_Pitch(unsigned int level)
  2336. {
  2337. WWASSERT(level<MipLevelCount);
  2338. WWASSERT(LockedSurfacePtr[level]);
  2339. return LockedSurfacePitch[level];
  2340. }
  2341. unsigned int VolumeTextureLoadTaskClass::Get_Locked_Volume_Slice_Pitch(unsigned int level)
  2342. {
  2343. WWASSERT(level<MipLevelCount);
  2344. WWASSERT(LockedSurfacePtr[level]);
  2345. return LockedSurfaceSlicePitch[level];
  2346. }