W3DAssetManager.cpp 54 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796
  1. /*
  2. ** Command & Conquer Generals Zero Hour(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. ////////////////////////////////////////////////////////////////////////////////
  19. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. /***********************************************************************************************
  24. *** 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 ***
  25. ***********************************************************************************************
  26. * *
  27. * Project Name : W3DAssetManager *
  28. * *
  29. * $Archive:: $*
  30. * *
  31. * Original Author:: Hector Yee (Enbassetmgr)
  32. * Added/Modified:: Mark Wilczynski
  33. * *
  34. * $Author:: $*
  35. * *
  36. * $Modtime:: $*
  37. * *
  38. * $Revision:: $*
  39. * *
  40. *---------------------------------------------------------------------------------------------*
  41. * Functions: *
  42. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  43. #include <always.h>
  44. #include "W3DDevice/GameClient/W3DAssetManager.h"
  45. #include "proto.h"
  46. #include "rendobj.h"
  47. #include <vector3.h>
  48. #include "mesh.h"
  49. #include "hlod.h"
  50. #include "matinfo.h"
  51. #include "meshmdl.h"
  52. #include "part_emt.h"
  53. #include "vertmaterial.h"
  54. #include "dx8wrapper.h"
  55. #include "texture.h"
  56. #include "surfaceclass.h"
  57. #include "textureloader.h"
  58. #include "ww3dformat.h"
  59. #include "colorspace.h"
  60. #include <wwprofile.h>
  61. #include "wwmemlog.h"
  62. #include "ffactory.h"
  63. #include "font3d.h"
  64. #include "render2dsentence.h"
  65. #include <stdio.h>
  66. #include "W3DDevice/GameClient/W3DGranny.h"
  67. #include "Common/PerfTimer.h"
  68. #include "Common/GlobalData.h"
  69. #include "Common/GameCommon.h"
  70. #ifdef _INTERNAL
  71. // for occasional debugging...
  72. //#pragma optimize("", off)
  73. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  74. #endif
  75. //---------------------------------------------------------------------
  76. // Constants
  77. //---------------------------------------------------------------------
  78. const float ident_scale(1.0f);
  79. const float scale_epsilon(0.01f);
  80. const Vector3 ident_HSV(0,0,0);
  81. const float H_epsilon(1.0f);
  82. const float S_epsilon(0.01f);
  83. const float V_epsilon(0.01f);
  84. //---------------------------------------------------------------------
  85. // Externs defined somewhere in W3D.
  86. //---------------------------------------------------------------------
  87. unsigned int PixelSize(const SurfaceClass::SurfaceDescription &sd);
  88. void Convert_Pixel(Vector3 &rgb, const SurfaceClass::SurfaceDescription &sd, const unsigned char * pixel);
  89. void Convert_Pixel(unsigned char * pixel,const SurfaceClass::SurfaceDescription &sd, const Vector3 &rgb);
  90. //---------------------------------------------------------------------
  91. // W3DPrototype
  92. //---------------------------------------------------------------------
  93. //---------------------------------------------------------------------
  94. class W3DPrototypeClass : public MemoryPoolObject, public PrototypeClass
  95. {
  96. MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE( W3DPrototypeClass, "W3DPrototypeClass" )
  97. public:
  98. W3DPrototypeClass(RenderObjClass * proto, const AsciiString& name);
  99. virtual const char* Get_Name(void) const { return Name.str(); }
  100. virtual int Get_Class_ID(void) const { return Proto->Class_ID(); }
  101. virtual RenderObjClass * Create(void);
  102. virtual void DeleteSelf() { deleteInstance(); }
  103. protected:
  104. //virtual ~W3DPrototypeClass(void);
  105. private:
  106. RenderObjClass * Proto;
  107. AsciiString Name;
  108. };
  109. //---------------------------------------------------------------------
  110. W3DPrototypeClass::W3DPrototypeClass(RenderObjClass * proto, const AsciiString& name) :
  111. Proto(proto),
  112. Name(name)
  113. {
  114. assert(Proto);
  115. Proto->Add_Ref();
  116. }
  117. //---------------------------------------------------------------------
  118. W3DPrototypeClass::~W3DPrototypeClass(void)
  119. {
  120. if (Proto) {
  121. Proto->Release_Ref();
  122. Proto = NULL;
  123. }
  124. }
  125. //---------------------------------------------------------------------
  126. RenderObjClass * W3DPrototypeClass::Create(void)
  127. {
  128. return (RenderObjClass *)( SET_REF_OWNER( Proto->Clone() ) );
  129. }
  130. //---------------------------------------------------------------------
  131. // W3DAssetManager
  132. //---------------------------------------------------------------------
  133. //---------------------------------------------------------------------
  134. W3DAssetManager::W3DAssetManager(void)
  135. {
  136. #ifdef INCLUDE_GRANNY_IN_BUILD
  137. m_GrannyAnimManager = NEW GrannyAnimManagerClass;
  138. #endif
  139. }
  140. //---------------------------------------------------------------------
  141. W3DAssetManager::~W3DAssetManager(void)
  142. {
  143. #ifdef INCLUDE_GRANNY_IN_BUILD
  144. delete m_GrannyAnimManager;
  145. #endif
  146. }
  147. #ifdef DUMP_PERF_STATS
  148. __int64 Total_Get_Texture_Time=0;
  149. #endif
  150. TextureClass * W3DAssetManager::Get_Texture
  151. (
  152. const char * filename,
  153. MipCountType mip_level_count,
  154. WW3DFormat texture_format,
  155. bool allow_compression,
  156. TextureBaseClass::TexAssetType type,
  157. bool allow_reduction
  158. )
  159. {
  160. //Just call the base implementation after adjusting reduction to deal
  161. //with our special types.
  162. if (filename && *filename && _strnicmp(filename,"ZHC",3) == 0)
  163. allow_reduction = false; //don't allow reduction on our infantry textures.
  164. return WW3DAssetManager::Get_Texture( filename,
  165. mip_level_count,
  166. texture_format,
  167. allow_compression,
  168. type,
  169. allow_reduction
  170. );
  171. }
  172. #if 0 //this function is obsolete in latest C&C3 drop. Use the one above.
  173. //---------------------------------------------------------------------
  174. TextureClass *W3DAssetManager::Get_Texture(
  175. const char * filename,
  176. MipCountType mip_level_count,
  177. WW3DFormat texture_format,
  178. bool allow_compression
  179. )
  180. {
  181. #ifdef DUMP_PERF_STATS
  182. __int64 startTime64,endTime64;
  183. GetPrecisionTimer(&startTime64);
  184. #endif
  185. WWPROFILE( "WW3DAssetManager::Get_Texture 1" );
  186. /*
  187. ** Bail if the user isn't really asking for anything
  188. */
  189. if (!filename || !*filename)
  190. {
  191. #ifdef DUMP_PERF_STATS
  192. GetPrecisionTimer(&endTime64);
  193. Total_Get_Texture_Time += endTime64-startTime64;
  194. #endif
  195. return NULL;
  196. }
  197. StringClass lower_case_name(filename,true);
  198. _strlwr(lower_case_name.Peek_Buffer());
  199. /*
  200. ** See if the texture has already been loaded.
  201. */
  202. TextureClass* tex = TextureHash.Get(lower_case_name);
  203. if (tex && texture_format != WW3D_FORMAT_UNKNOWN)
  204. {
  205. WWASSERT_PRINT(tex->Get_Texture_Format() == texture_format, ("Texture %s has already been loaded with different format",filename));
  206. }
  207. /*
  208. ** Didn't have it so we have to create a new texture
  209. */
  210. if (!tex)
  211. {
  212. tex = NEW_REF(TextureClass, (lower_case_name, NULL, mip_level_count, texture_format, allow_compression));
  213. TextureHash.Insert(tex->Get_Texture_Name(),tex);
  214. // if (TheGlobalData->m_preloadAssets)
  215. // {
  216. // extern std::vector<std::string> preloadTextureNamesGlobalHack;
  217. // preloadTextureNamesGlobalHack.push_back(tex->Get_Texture_Name());
  218. // }
  219. #if defined(_DEBUG) || defined(_INTERNAL) || defined(_ALLOW_DEBUG_CHEATS_IN_RELEASE)
  220. if (TheGlobalData->m_preloadReport)
  221. {
  222. //loading a new asset and app is requesting a log of all loaded assets.
  223. FILE *logfile=fopen("PreloadedAssets.txt","a+"); //append to log
  224. if (logfile)
  225. {
  226. fprintf(logfile,"TX: %s\n",tex->Get_Texture_Name());
  227. fclose(logfile);
  228. }
  229. }
  230. #endif
  231. }
  232. tex->Add_Ref();
  233. #ifdef DUMP_PERF_STATS
  234. GetPrecisionTimer(&endTime64);
  235. Total_Get_Texture_Time += endTime64-startTime64;
  236. #endif
  237. return tex;
  238. }
  239. #endif
  240. //---------------------------------------------------------------------
  241. RenderObjClass * W3DAssetManager::Create_Render_Obj(const char* name)
  242. {
  243. return WW3DAssetManager::Create_Render_Obj(name);
  244. }
  245. //---------------------------------------------------------------------
  246. /** 'Generals' specific munging to encode team color and scale in model name */
  247. static inline void Munge_Render_Obj_Name(char *newname, const char *oldname, float scale, const int color, const char *textureName)
  248. {
  249. char lower_case_name[255];
  250. strcpy(lower_case_name, oldname);
  251. _strlwr(lower_case_name);
  252. if (!textureName)
  253. textureName = "";
  254. sprintf(newname,"#%d!%g!%s#%s",color,scale,textureName,lower_case_name);
  255. }
  256. //---------------------------------------------------------------------
  257. static inline void Munge_Texture_Name(char *newname, const char *oldname, const int color)
  258. {
  259. char lower_case_name[255];
  260. strcpy(lower_case_name, oldname);
  261. _strlwr(lower_case_name);
  262. sprintf(newname,"#%d#%s", color, lower_case_name);
  263. }
  264. //---------------------------------------------------------------------
  265. int W3DAssetManager::replaceAssetTexture(RenderObjClass *robj, TextureClass *oldTex, TextureClass *newTex)
  266. {
  267. switch (robj->Class_ID()) {
  268. case RenderObjClass::CLASSID_MESH:
  269. return replaceMeshTexture(robj, oldTex, newTex);
  270. break;
  271. case RenderObjClass::CLASSID_HLOD:
  272. return replaceHLODTexture(robj, oldTex, newTex);
  273. break;
  274. }
  275. return 0;
  276. }
  277. //---------------------------------------------------------------------
  278. Int W3DAssetManager::replaceHLODTexture(RenderObjClass *robj, TextureClass *oldTex, TextureClass *newTex)
  279. {
  280. int didReplace=0;
  281. int num_sub = robj->Get_Num_Sub_Objects();
  282. for(int i = 0; i < num_sub; i++) {
  283. RenderObjClass *sub_obj = robj->Get_Sub_Object(i);
  284. didReplace |= replaceAssetTexture(sub_obj, oldTex, newTex);
  285. REF_PTR_RELEASE(sub_obj);
  286. }
  287. return didReplace;
  288. }
  289. //---------------------------------------------------------------------
  290. Int W3DAssetManager::replaceMeshTexture(RenderObjClass *robj, TextureClass *oldTex, TextureClass *newTex)
  291. {
  292. int i;
  293. int didReplace=0;
  294. MeshClass *mesh=(MeshClass*) robj;
  295. MeshModelClass * model = mesh->Get_Model();
  296. MaterialInfoClass *material = mesh->Get_Material_Info();
  297. for (i=0; i<material->Texture_Count(); i++)
  298. {
  299. if (material->Peek_Texture(i) == oldTex)
  300. {
  301. model->Replace_Texture(oldTex,newTex);
  302. material->Replace_Texture(i,newTex);
  303. didReplace=1;
  304. }
  305. }
  306. REF_PTR_RELEASE(material);
  307. REF_PTR_RELEASE(model);
  308. return didReplace;
  309. }
  310. //---------------------------------------------------------------------
  311. /** Replaces all references to old texture with new texture. Operation is performed on
  312. asset prototype so it will affect most instances of this object. Objects which have
  313. been customized with house color will not be affected unless they are created after
  314. this function is called.
  315. */
  316. int W3DAssetManager::replacePrototypeTexture(RenderObjClass *robj, const char * oldname, const char * newname)
  317. {
  318. //search model for old texture
  319. TextureClass *oldTex=Get_Texture(oldname);
  320. TextureClass *newTex=Get_Texture(newname);
  321. int retCode=replaceAssetTexture(robj,oldTex,newTex);
  322. REF_PTR_RELEASE(oldTex);
  323. REF_PTR_RELEASE(newTex);
  324. return retCode;
  325. }
  326. //---------------------------------------------------------------------
  327. /** Generals specific version that looks for a texture which has been house-color tinted.
  328. Don't use this unless you really need it. For normal textures, use Get_Texture().
  329. */
  330. TextureClass * W3DAssetManager::Find_Texture(const char * name, const int color)
  331. {
  332. char newname[512];
  333. Munge_Texture_Name(newname, name, color);
  334. // see if we have a cached copy
  335. TextureClass *newtex = TextureHash.Get(newname);
  336. if (newtex) {
  337. newtex->Add_Ref();
  338. }
  339. return newtex;
  340. }
  341. //---------------------------------------------------------------------
  342. TextureClass * W3DAssetManager::Recolor_Texture(TextureClass *texture, const int color)
  343. {
  344. const char *name=texture->Get_Texture_Name();
  345. TextureClass *newtex = Find_Texture(name, color);
  346. if (newtex) {
  347. return newtex;
  348. }
  349. return Recolor_Texture_One_Time(texture, color);
  350. }
  351. //---------------------------------------------------------------------
  352. const Int TEAM_COLOR_PALETTE_SIZE = 16;
  353. const UnsignedShort houseColorScale[TEAM_COLOR_PALETTE_SIZE] =
  354. {
  355. 255,239,223,211,195,174,167,151,135,123,107,91,79,63,47,35
  356. };
  357. //---------------------------------------------------------------------
  358. static void remapPalette16Bit(SurfaceClass::SurfaceDescription *sd, UnsignedShort *palette, unsigned int color)
  359. {
  360. UnsignedShort pal[TEAM_COLOR_PALETTE_SIZE];
  361. Vector3 rgb,v_color((float)((color>>16)&0xff)/255.0f/255.0f,(float)((color>>8)&0xff)/255.0f/255.0f,(float)(color&0xff)/255.0f/255.0f);
  362. //Generate a new color gradient palette based on reference color
  363. for (Int y=0; y<TEAM_COLOR_PALETTE_SIZE; y++)
  364. {
  365. rgb.X=(Real)houseColorScale[y]*v_color.X;
  366. rgb.Y=(Real)houseColorScale[y]*v_color.Y;
  367. rgb.Z=(Real)houseColorScale[y]*v_color.Z;
  368. pal[y]=0xffff; //preset alpha to known value
  369. Convert_Pixel((unsigned char *)&pal[y],*sd,rgb);
  370. }
  371. //check if this pixel is part of team color palette
  372. for (Int p=0; p<TEAM_COLOR_PALETTE_SIZE; p++)
  373. { palette[p]=pal[p]; //replace color with house color
  374. }
  375. }
  376. //---------------------------------------------------------------------
  377. static void remapTexture16Bit(Int dx, Int dy, Int pitch, SurfaceClass::SurfaceDescription *sd, UnsignedShort *palette, UnsignedShort *data, unsigned int color)
  378. {
  379. UnsignedShort pal[TEAM_COLOR_PALETTE_SIZE];
  380. Vector3 rgb,v_color((float)((color>>16)&0xff)/255.0f/255.0f,(float)((color>>8)&0xff)/255.0f/255.0f,(float)(color&0xff)/255.0f/255.0f);
  381. //Generate a new color gradient palette based on reference color
  382. for (Int y=0; y<TEAM_COLOR_PALETTE_SIZE; y++)
  383. {
  384. rgb.X=(Real)houseColorScale[y]*v_color.X;
  385. rgb.Y=(Real)houseColorScale[y]*v_color.Y;
  386. rgb.Z=(Real)houseColorScale[y]*v_color.Z;
  387. pal[y]=0xffff; //preset alpha to known value
  388. Convert_Pixel((unsigned char *)&pal[y],*sd,rgb);
  389. }
  390. for (y=0; y<dy; y++)
  391. { for (Int x=0; x<dx; x++)
  392. { //check if this pixel is part of team color palette
  393. for (Int p=0; p<TEAM_COLOR_PALETTE_SIZE; p++)
  394. { if (palette[p]==data[x])
  395. { data[x]=pal[p]; //replace color with house color
  396. break;
  397. }
  398. }
  399. }
  400. data += pitch;
  401. }
  402. }
  403. //Use hue shift instead of alpha blend to apply house color to textures
  404. #define DO_HUE_SHIFT
  405. //---------------------------------------------------------------------
  406. //Input texture is assumed to be in ARGB 4444 format.
  407. static void remapAlphaTexture16Bit(Int dx, Int dy, Int pitch, SurfaceClass::SurfaceDescription *sd, UnsignedShort *data, unsigned int color)
  408. {
  409. UnsignedShort pixel;
  410. UnsignedShort pixelAlpha;
  411. #ifndef DO_HUE_SHIFT
  412. float fpixelAlpha,fpixelAlphaInv;
  413. #endif
  414. Vector3 rgb,v_color((float)((color>>16)&0xff)/255.0f,(float)((color>>8)&0xff)/255.0f,(float)(color&0xff)/255.0f);
  415. Int x,y;
  416. #ifdef DO_HUE_SHIFT
  417. Vector3 hsv;
  418. Vector3 hsv_color;
  419. RGB_To_HSV(hsv_color,v_color);
  420. #endif
  421. for (y=0; y<dy; y++)
  422. {
  423. for (x=0; x<dx; x++)
  424. {
  425. pixel=data[x];
  426. pixelAlpha=15-(pixel>>12); //get alpha for house color
  427. if (pixelAlpha)
  428. { //some house color needs to show through
  429. ///@todo: optimize this alpha blend to use fixed point math.
  430. #ifdef DO_HUE_SHIFT
  431. RGB_To_HSV(hsv,Vector3(((pixel>>8)&0xf)/15.0f,((pixel>>4)&0xf)/15.0f,(pixel &0xf)/15.0f));
  432. hsv.X=hsv_color.X;
  433. hsv.Y*=hsv_color.Y;
  434. HSV_To_RGB(rgb,hsv);
  435. #else
  436. fpixelAlpha=pixelAlpha/15.0f;
  437. fpixelAlphaInv=1.0f-fpixelAlpha;
  438. rgb.X=fpixelAlpha * v_color.X + fpixelAlphaInv*(Real)((pixel>>8)&0xf)/15.0f; //red
  439. rgb.Y=fpixelAlpha * v_color.Y + fpixelAlphaInv*(Real)((pixel>>4)&0xf)/15.0f; //green
  440. rgb.Z=fpixelAlpha * v_color.Z + fpixelAlphaInv*(Real)(pixel&0xf)/15.0f; //blue
  441. #endif
  442. data[x] = REAL_TO_INT(rgb.X*15.0f)<<8 | REAL_TO_INT(rgb.Y*15.0f)<<4 | REAL_TO_INT(rgb.Z*15.0f);
  443. }
  444. data[x] |= 0xf000; //force alpha to opaque.
  445. }
  446. data += pitch;
  447. }
  448. }
  449. //---------------------------------------------------------------------
  450. static void remapPalette32Bit(SurfaceClass::SurfaceDescription *sd, UnsignedInt *palette, unsigned int color)
  451. {
  452. UnsignedInt pal[TEAM_COLOR_PALETTE_SIZE];
  453. Vector3 rgb,v_color((float)((color>>16)&0xff)/255.0f/255.0f,(float)((color>>8)&0xff)/255.0f/255.0f,(float)(color&0xff)/255.0f/255.0f);
  454. //Generate a new color gradient palette based on reference color
  455. for (Int y=0; y<TEAM_COLOR_PALETTE_SIZE; y++)
  456. {
  457. rgb.X=(Real)houseColorScale[y]*v_color.X;
  458. rgb.Y=(Real)houseColorScale[y]*v_color.Y;
  459. rgb.Z=(Real)houseColorScale[y]*v_color.Z;
  460. pal[y]=0xffffffff; //preset alpha to known value
  461. Convert_Pixel((unsigned char *)&pal[y],*sd,rgb);
  462. }
  463. //check if this pixel is part of team color palette
  464. for (Int p=0; p<TEAM_COLOR_PALETTE_SIZE; p++)
  465. { palette[p]=pal[p]; //replace color with house color
  466. }
  467. }
  468. //---------------------------------------------------------------------
  469. static void remapTexture32Bit(Int dx, Int dy, Int pitch, SurfaceClass::SurfaceDescription *sd, UnsignedInt *palette, UnsignedInt *data, unsigned int color)
  470. {
  471. UnsignedInt pal[TEAM_COLOR_PALETTE_SIZE];
  472. Vector3 rgb,v_color((float)((color>>16)&0xff)/255.0f/255.0f,(float)((color>>8)&0xff)/255.0f/255.0f,(float)(color&0xff)/255.0f/255.0f);
  473. //Generate a new color gradient palette based on reference color
  474. for (Int y=0; y<TEAM_COLOR_PALETTE_SIZE; y++)
  475. {
  476. rgb.X=(Real)houseColorScale[y]*v_color.X;
  477. rgb.Y=(Real)houseColorScale[y]*v_color.Y;
  478. rgb.Z=(Real)houseColorScale[y]*v_color.Z;
  479. pal[y]=0xffffffff; //preset alpha to known value
  480. Convert_Pixel((unsigned char *)&pal[y],*sd,rgb);
  481. }
  482. for (y=0; y<dy; y++)
  483. { for (Int x=0; x<dx; x++)
  484. { //check if this pixel is part of team color palette
  485. for (Int p=0; p<TEAM_COLOR_PALETTE_SIZE; p++)
  486. { if (palette[p]==data[x])
  487. { data[x]=pal[p]; //replace color with house color
  488. break;
  489. }
  490. }
  491. }
  492. data += pitch;
  493. }
  494. }
  495. //---------------------------------------------------------------------
  496. static void remapAlphaTexture32Bit(Int dx, Int dy, Int pitch, SurfaceClass::SurfaceDescription *sd, UnsignedInt *data, unsigned int color)
  497. {
  498. UnsignedInt pixel;
  499. UnsignedInt pixelAlpha;
  500. #ifndef DO_HUE_SHIFT
  501. float fpixelAlpha,fpixelAlphaInv;
  502. #endif
  503. Vector3 rgb,v_color((float)((color>>16)&0xff)/255.0f,(float)((color>>8)&0xff)/255.0f,(float)(color&0xff)/255.0f);
  504. Int x,y;
  505. #ifdef DO_HUE_SHIFT
  506. Vector3 hsv;
  507. Vector3 hsv_color;
  508. RGB_To_HSV(hsv_color,v_color);
  509. #endif
  510. for (y=0; y<dy; y++)
  511. { for (x=0; x<dx; x++)
  512. {
  513. pixel=data[x];
  514. pixelAlpha=255-(pixel>>24); //get alpha for house color
  515. if (pixelAlpha)
  516. { //some house color needs to show through
  517. #ifdef DO_HUE_SHIFT
  518. RGB_To_HSV(hsv,Vector3(((pixel>>16)&0xff)/255.0f,((pixel>>8)&0xff)/255.0f,(pixel &0xff)/255.0f));
  519. hsv.X=hsv_color.X;
  520. hsv.Y*=hsv_color.Y;
  521. HSV_To_RGB(rgb,hsv);
  522. #else
  523. ///@todo: optimize this alpha blend to use fixed point math.
  524. fpixelAlpha=pixelAlpha/255.0f;
  525. fpixelAlphaInv=1.0f-fpixelAlpha;
  526. rgb.X=fpixelAlpha * v_color.X + fpixelAlphaInv*(Real)((pixel>>16)&0xff)/255.0f; //red
  527. rgb.Y=fpixelAlpha * v_color.Y + fpixelAlphaInv*(Real)((pixel>>8)&0xff)/255.0f; //green
  528. rgb.Z=fpixelAlpha * v_color.Z + fpixelAlphaInv*(Real)(pixel&0xff)/255.0f; //blue
  529. #endif
  530. data[x] = REAL_TO_INT(rgb.X*255.0f)<<16 | REAL_TO_INT(rgb.Y*255.0f)<<8 | REAL_TO_INT(rgb.Z*255.0f);
  531. }
  532. data[x] |= 0xff000000; //force alpha to opaque.
  533. }
  534. data += pitch;
  535. }
  536. }
  537. //---------------------------------------------------------------------
  538. /** Surface is assumed to come in the following format:
  539. First 16 pixels are a palette composed of 24-Bit RGB values.
  540. Any pixels in remainder of image that use these 24-bit values
  541. will be remapped using a pre-defined formula.
  542. */
  543. void W3DAssetManager::Remap_Palette(SurfaceClass *surface, const int color, Bool doPaletteOnly, Bool useAlpha)
  544. {
  545. // unsigned int x;
  546. SurfaceClass::SurfaceDescription sd;
  547. surface->Get_Description(sd);
  548. int pitch,size;
  549. // UnsignedInt newPalette[TEAM_COLOR_PALETTE_SIZE];
  550. size=PixelSize(sd);
  551. unsigned char *bits=(unsigned char*) surface->Lock(&pitch);
  552. if (doPaletteOnly)
  553. { //only recolor the palette which is stored in top row. Model only references these pixels.
  554. if (size == 2)
  555. remapPalette16Bit(&sd, (UnsignedShort *)bits, color);
  556. else
  557. if (size == 4)
  558. remapPalette32Bit(&sd, (UnsignedInt *)bits,color);
  559. }
  560. else
  561. {
  562. if (useAlpha)
  563. {
  564. if (size == 2)
  565. remapAlphaTexture16Bit(sd.Width, sd.Height, pitch>>1, &sd, (UnsignedShort *)bits,color);
  566. else
  567. if (size == 4)
  568. remapAlphaTexture32Bit(sd.Width, sd.Height, pitch>>2, &sd, (UnsignedInt *)bits,color);
  569. }
  570. else
  571. { //Recolor the image using the palette stored in top row
  572. if (size == 2)
  573. remapTexture16Bit(sd.Width, sd.Height-1, pitch>>1, &sd, (UnsignedShort *)bits, (UnsignedShort *)(bits+pitch), color);
  574. else
  575. if (size == 4)
  576. remapTexture32Bit(sd.Width, sd.Height-1, pitch>>2, &sd, (UnsignedInt *)bits, (UnsignedInt *)(bits+pitch),color);
  577. }
  578. }
  579. surface->Unlock();
  580. }
  581. //---------------------------------------------------------------------
  582. TextureClass * W3DAssetManager::Recolor_Texture_One_Time(TextureClass *texture, const int color)
  583. {
  584. const char *name=texture->Get_Texture_Name();
  585. // if texture is procedural return NULL
  586. if (name && name[0]=='!') return NULL;
  587. // make sure texture is loaded
  588. if (!texture->Is_Initialized())
  589. TextureLoader::Request_Foreground_Loading(texture);
  590. SurfaceClass::SurfaceDescription desc;
  591. SurfaceClass *newsurf, *oldsurf;
  592. texture->Get_Level_Description(desc);
  593. Int psize;
  594. psize=PixelSize(desc);
  595. DEBUG_ASSERTCRASH( psize == 2 || psize == 4, ("Can't Recolor Texture %s", name) );
  596. oldsurf=texture->Get_Surface_Level();
  597. newsurf=NEW_REF(SurfaceClass,(desc.Width,desc.Height,desc.Format));
  598. newsurf->Copy(0,0,0,0,desc.Width,desc.Height,oldsurf);
  599. if (*(name+3) == 'D' || *(name+3) == 'd')
  600. Remap_Palette(newsurf,color, true, false ); //texture only contains a palette stored in top row.
  601. else
  602. if (*(name+3) == 'A' || *(name+3) == 'a')
  603. Remap_Palette(newsurf,color, false, true ); //texture only contains a palette stored in top row.
  604. TextureClass * newtex=NEW_REF(TextureClass,(newsurf,(MipCountType)texture->Get_Mip_Level_Count()));
  605. newtex->Get_Filter().Set_Mag_Filter(texture->Get_Filter().Get_Mag_Filter());
  606. newtex->Get_Filter().Set_Min_Filter(texture->Get_Filter().Get_Min_Filter());
  607. newtex->Get_Filter().Set_Mip_Mapping(texture->Get_Filter().Get_Mip_Mapping());
  608. newtex->Get_Filter().Set_U_Addr_Mode(texture->Get_Filter().Get_U_Addr_Mode());
  609. newtex->Get_Filter().Set_V_Addr_Mode(texture->Get_Filter().Get_V_Addr_Mode());
  610. char newname[512];
  611. Munge_Texture_Name(newname, name, color);
  612. newtex->Set_Texture_Name(newname);
  613. TextureHash.Insert(newtex->Get_Texture_Name(), newtex);
  614. newtex->Add_Ref();
  615. REF_PTR_RELEASE(oldsurf);
  616. REF_PTR_RELEASE(newsurf);
  617. return newtex;
  618. }
  619. #ifdef DUMP_PERF_STATS
  620. __int64 Total_Create_Render_Obj_Time=0;
  621. #endif
  622. //---------------------------------------------------------------------
  623. /** Generals specific code to generate customized render objects for each team color
  624. Scale==1.0, color==0x00000000, and oldTexure==NULL are defaults that do nothing.
  625. */
  626. RenderObjClass * W3DAssetManager::Create_Render_Obj(
  627. const char * name,
  628. float scale,
  629. const int color,
  630. const char *oldTexture,
  631. const char *newTexture
  632. )
  633. {
  634. #ifdef DUMP_PERF_STATS
  635. __int64 startTime64,endTime64;
  636. GetPrecisionTimer(&startTime64);
  637. #endif
  638. #ifdef INCLUDE_GRANNY_IN_BUILD
  639. Bool isGranny = false;
  640. char *pext=strrchr(name,'.'); //find file extension
  641. if (pext)
  642. isGranny=(strnicmp(pext,".GR2",4) == 0);
  643. #endif
  644. Bool reallyscale = (WWMath::Fabs(scale - ident_scale) > scale_epsilon);
  645. Bool reallycolor = (color & 0xFFFFFF) != 0; //black is not a valid color and assumes no custom coloring.
  646. Bool reallytexture = (oldTexture != NULL && newTexture != NULL);
  647. // base case, no scale or color
  648. if (!reallyscale && !reallycolor && !reallytexture)
  649. {
  650. RenderObjClass *robj=WW3DAssetManager::Create_Render_Obj(name);
  651. #ifdef DUMP_PERF_STATS
  652. GetPrecisionTimer(&endTime64);
  653. Total_Create_Render_Obj_Time += endTime64-startTime64;
  654. #endif
  655. return robj;
  656. }
  657. char newname[512];
  658. Munge_Render_Obj_Name(newname, name, scale, color, newTexture);
  659. // see if we got a cached version
  660. RenderObjClass *rendobj = NULL;
  661. #ifdef INCLUDE_GRANNY_IN_BUILD
  662. if (isGranny)
  663. { //Granny objects share the same prototype since they allow instance scaling.
  664. strcpy(newname,name); //use same name for all granny objects at any scale.
  665. }
  666. #endif
  667. Set_WW3D_Load_On_Demand(false); // munged name will never be found in a file.
  668. rendobj = WW3DAssetManager::Create_Render_Obj(newname);
  669. if (rendobj)
  670. { //store the color that we used to create asset so we can read it back out
  671. //when we need to save this render object to a file. Used during saving
  672. //of fog of war ghost objects.
  673. rendobj->Set_ObjectColor(color);
  674. #ifdef INCLUDE_GRANNY_IN_BUILD
  675. if (isGranny)
  676. ///@todo Granny objects are realtime scaled - fix to scale like W3D.
  677. rendobj->Set_ObjectScale(scale);
  678. #endif
  679. Set_WW3D_Load_On_Demand(true); // Auto Load.
  680. #ifdef DUMP_PERF_STATS
  681. GetPrecisionTimer(&endTime64);
  682. Total_Create_Render_Obj_Time += endTime64-startTime64;
  683. #endif
  684. return rendobj;
  685. }
  686. // create a new one based on exisiting prototype
  687. WWPROFILE( "WW3DAssetManager::Create_Render_Obj" );
  688. WWMEMLOG(MEM_GEOMETRY);
  689. // Try to find a prototype
  690. PrototypeClass * proto = Find_Prototype(name);
  691. Set_WW3D_Load_On_Demand(true); // Auto Load.
  692. if (WW3D_Load_On_Demand && proto == NULL)
  693. {
  694. // If we didn't find one, try to load on demand
  695. char filename [MAX_PATH];
  696. char *mesh_name = ::strchr (name, '.');
  697. if (mesh_name != NULL)
  698. {
  699. ::lstrcpyn(filename, name, ((int)mesh_name) - ((int)name) + 1);
  700. #ifdef INCLUDE_GRANNY_IN_BUILD
  701. if (isGranny)
  702. ::lstrcat(filename, ".gr2");
  703. else
  704. #endif
  705. ::lstrcat(filename, ".w3d");
  706. } else {
  707. sprintf( filename, "%s.w3d", name);
  708. }
  709. // If we can't find it, try the parent directory
  710. if ( Load_3D_Assets( filename ) == false )
  711. {
  712. StringClass new_filename = StringClass("..\\") + filename;
  713. if (Load_3D_Assets( new_filename ) == false)
  714. {
  715. #ifdef INCLUDE_GRANNY_IN_BUILD
  716. char *mesh_name = ::strchr (filename, '.');
  717. ::lstrcpyn (mesh_name, ".gr2",5);
  718. Load_3D_Assets( filename );
  719. isGranny=true;
  720. #endif
  721. }
  722. }
  723. proto = Find_Prototype(name); // try again
  724. }
  725. if (proto == NULL)
  726. {
  727. static int warning_count = 0;
  728. if (++warning_count <= 20)
  729. {
  730. WWDEBUG_SAY(("WARNING: Failed to create Render Object: %s\r\n",name));
  731. }
  732. #ifdef DUMP_PERF_STATS
  733. GetPrecisionTimer(&endTime64);
  734. Total_Create_Render_Obj_Time += endTime64-startTime64;
  735. #endif
  736. return NULL; // Failed to find a prototype
  737. }
  738. rendobj = proto->Create();
  739. if (!rendobj)
  740. {
  741. #ifdef DUMP_PERF_STATS
  742. GetPrecisionTimer(&endTime64);
  743. Total_Create_Render_Obj_Time += endTime64-startTime64;
  744. #endif
  745. return NULL;
  746. }
  747. #ifdef INCLUDE_GRANNY_IN_BUILD
  748. if (!isGranny)
  749. #endif
  750. {
  751. if (reallyscale)
  752. rendobj->Scale(scale); //this also makes it unique
  753. Make_Unique(rendobj,reallyscale,reallycolor);
  754. if (reallytexture)
  755. {
  756. TextureClass *oldTex = Get_Texture(oldTexture);
  757. TextureClass *newTex = Get_Texture(newTexture);
  758. replaceAssetTexture(rendobj,oldTex,newTex);
  759. REF_PTR_RELEASE(newTex);
  760. REF_PTR_RELEASE(oldTex);
  761. }
  762. if (reallycolor)
  763. Recolor_Asset(rendobj,color);
  764. }
  765. #ifdef INCLUDE_GRANNY_IN_BUILD
  766. else
  767. {
  768. ///@todo Granny objects are realtime scaled - fix to scale like W3D.
  769. rendobj->Set_ObjectScale(scale);
  770. return rendobj;
  771. }
  772. #endif
  773. W3DPrototypeClass *w3dproto = newInstance(W3DPrototypeClass)(rendobj, newname);
  774. rendobj->Release_Ref();
  775. Add_Prototype(w3dproto);
  776. rendobj = w3dproto->Create();
  777. rendobj->Set_ObjectColor(color);
  778. #ifdef DUMP_PERF_STATS
  779. GetPrecisionTimer(&endTime64);
  780. Total_Create_Render_Obj_Time += endTime64-startTime64;
  781. #endif
  782. return rendobj;
  783. }
  784. //---------------------------------------------------------------------
  785. /** Generals specific code to generate customized render objects for each team color
  786. */
  787. int W3DAssetManager::Recolor_Asset(RenderObjClass *robj, const int color)
  788. {
  789. switch (robj->Class_ID()) {
  790. case RenderObjClass::CLASSID_MESH:
  791. return Recolor_Mesh(robj,color);
  792. break;
  793. case RenderObjClass::CLASSID_HLOD:
  794. return Recolor_HLOD(robj,color);
  795. break;
  796. }
  797. return 0;
  798. }
  799. //---------------------------------------------------------------------
  800. /** Generals specific code to generate customized render objects for each team color
  801. */
  802. int W3DAssetManager::Recolor_Mesh(RenderObjClass *robj, const int color)
  803. {
  804. int i;
  805. int didRecolor=0;
  806. const char *meshName;
  807. MeshClass *mesh=(MeshClass*) robj;
  808. MeshModelClass * model = mesh->Get_Model();
  809. MaterialInfoClass *material = mesh->Get_Material_Info();
  810. // recolor vertex material (assuming mesh is housecolor)
  811. if ( (( (meshName=strchr(mesh->Get_Name(),'.') ) != 0 && *(meshName++)) || ( (meshName=mesh->Get_Name()) != NULL)) &&
  812. _strnicmp(meshName,"HOUSECOLOR", 10) == 0)
  813. { for (i=0; i<material->Vertex_Material_Count(); i++)
  814. Recolor_Vertex_Material(material->Peek_Vertex_Material(i),color);
  815. didRecolor=1;
  816. }
  817. // recolor textures
  818. TextureClass *newtex,*oldtex;
  819. for (i=0; i<material->Texture_Count(); i++)
  820. {
  821. oldtex=material->Peek_Texture(i);
  822. if (_strnicmp(oldtex->Get_Texture_Name(),"ZHC", 3) == 0)
  823. { //This texture needs to be adjusted for housecolor
  824. newtex=Recolor_Texture(oldtex,color);
  825. if (newtex)
  826. {
  827. model->Replace_Texture(oldtex,newtex);
  828. material->Replace_Texture(i,newtex);
  829. REF_PTR_RELEASE(newtex);
  830. didRecolor=1;
  831. }
  832. }
  833. }
  834. REF_PTR_RELEASE(material);
  835. REF_PTR_RELEASE(model);
  836. return didRecolor;
  837. }
  838. //---------------------------------------------------------------------
  839. /** Generals specific code to generate customized render objects for each team color
  840. */
  841. int W3DAssetManager::Recolor_HLOD(RenderObjClass *robj, const int color)
  842. {
  843. int didRecolor=0;
  844. int num_sub = robj->Get_Num_Sub_Objects();
  845. for(int i = 0; i < num_sub; i++) {
  846. RenderObjClass *sub_obj = robj->Get_Sub_Object(i);
  847. didRecolor |= Recolor_Asset(sub_obj,color);
  848. REF_PTR_RELEASE(sub_obj);
  849. }
  850. return didRecolor;
  851. }
  852. //---------------------------------------------------------------------
  853. /** Generals specific code to generate customized render objects for each team color
  854. */
  855. void W3DAssetManager::Recolor_Vertex_Material(VertexMaterialClass *vmat, const int color)
  856. {
  857. Vector3 rgb,rgb2;
  858. rgb.X = (Real)((color >> 16) & 0xff )/255.0f;
  859. rgb.Y = (Real)((color >> 8) & 0xff )/255.0f;
  860. rgb.Z = (Real)(color & 0xff)/255.0f;
  861. //We ignore the existing ambinent/diffuse and assume they were 1.0. We can change
  862. //to scaling them if required.
  863. // vmat->Get_Ambient(&rgb2);
  864. // Recolor(rgb,hsv_shift);
  865. rgb2.X = rgb.X; //scale colors
  866. rgb2.Y = rgb.Y; //scale colors
  867. rgb2.Z = rgb.Z; //scale colors
  868. vmat->Set_Ambient(rgb2);
  869. // vmat->Get_Diffuse(&rgb2);
  870. // Recolor(rgb,hsv_shift);
  871. rgb2.X = rgb.X; //scale colors
  872. rgb2.Y = rgb.Y; //scale colors
  873. rgb2.Z = rgb.Z; //scale colors
  874. vmat->Set_Diffuse(rgb2);
  875. }
  876. #ifdef DUMP_PERF_STATS
  877. __int64 Total_Load_3D_Assets=0;
  878. static Load_3D_Asset_Recursions=0;
  879. #endif
  880. //---------------------------------------------------------------------
  881. bool W3DAssetManager::Load_3D_Assets( const char * filename )
  882. {
  883. #ifdef DUMP_PERF_STATS
  884. Load_3D_Asset_Recursions++;
  885. __int64 startTime64,endTime64;
  886. GetPrecisionTimer(&startTime64);
  887. #endif
  888. #ifdef INCLUDE_GRANNY_IN_BUILD
  889. Bool isGranny = false;
  890. char *pext=strrchr(filename,'.'); //find file extension
  891. if (pext)
  892. isGranny=(strnicmp(pext,".GR2",4) == 0);
  893. if (!isGranny)
  894. #endif
  895. // Try to find an existing prototype
  896. char basename[512];
  897. strcpy(basename, filename);
  898. char *pext = strrchr(basename, '.'); //find file extension
  899. if (pext)
  900. *pext = '\0'; //drop the extension
  901. PrototypeClass * proto = Find_Prototype(basename);
  902. if (proto)
  903. {
  904. #ifdef DUMP_PERF_STATS
  905. if (Load_3D_Asset_Recursions == 1)
  906. { GetPrecisionTimer(&endTime64);
  907. Total_Load_3D_Assets += endTime64-startTime64;
  908. }
  909. Load_3D_Asset_Recursions--;
  910. #endif
  911. return TRUE; //this file has already been loaded.
  912. }
  913. bool result = WW3DAssetManager::Load_3D_Assets(filename);
  914. #if defined(_DEBUG) || defined(_INTERNAL)
  915. if (result && TheGlobalData->m_preloadReport)
  916. {
  917. //loading a new asset and app is requesting a log of all loaded assets.
  918. FILE *logfile=fopen("PreloadedAssets.txt","a+"); //append to log
  919. if (logfile)
  920. {
  921. StringClass lower_case_name(filename,true);
  922. _strlwr(lower_case_name.Peek_Buffer());
  923. fprintf(logfile,"3D: %s\n",lower_case_name.Peek_Buffer());
  924. fclose(logfile);
  925. }
  926. }
  927. #endif
  928. #ifdef DUMP_PERF_STATS
  929. if (Load_3D_Asset_Recursions == 1)
  930. { GetPrecisionTimer(&endTime64);
  931. Total_Load_3D_Assets += endTime64-startTime64;
  932. }
  933. Load_3D_Asset_Recursions--;
  934. #endif
  935. return result;
  936. #ifdef INCLUDE_GRANNY_IN_BUILD
  937. //Loading assets for Granny File
  938. PrototypeClass * newproto = NULL;
  939. newproto = _GrannyLoader.Load_W3D(filename);
  940. /*
  941. ** Now, see if the prototype that we loaded has a duplicate
  942. ** name with any of our currently loaded prototypes (can't have that!)
  943. */
  944. if (newproto != NULL) {
  945. if (!Render_Obj_Exists(newproto->Get_Name())) {
  946. /*
  947. ** Add the new, unique prototype to our list
  948. */
  949. Add_Prototype(newproto);
  950. } else {
  951. /*
  952. ** Warn the user about a name collision with this prototype
  953. ** and dump it
  954. */
  955. WWDEBUG_SAY(("Render Object Name Collision: %s\r\n",newproto->Get_Name()));
  956. delete newproto;
  957. newproto = NULL;
  958. return false;
  959. }
  960. } else {
  961. /*
  962. ** Warn user that a prototype was not generated from this
  963. ** chunk type
  964. */
  965. WWDEBUG_SAY(("Could not generate Granny prototype! File = %d\r\n",filename));
  966. return false;
  967. }
  968. return true;
  969. #endif
  970. }
  971. #ifdef DUMP_PERF_STATS
  972. __int64 Total_Get_HAnim_Time=0;
  973. static HAnim_Recursions=0;
  974. #endif
  975. //---------------------------------------------------------------------
  976. HAnimClass * W3DAssetManager::Get_HAnim(const char * name)
  977. {
  978. #ifdef DUMP_PERF_STATS
  979. HAnim_Recursions++;
  980. __int64 startTime64,endTime64;
  981. GetPrecisionTimer(&startTime64);
  982. #endif
  983. WWPROFILE( "WW3DAssetManager::Get_HAnim" );
  984. #ifdef INCLUDE_GRANNY_IN_BUILD
  985. Bool isGranny = false;
  986. char *pext=strrchr(name,'.'); //find file extension
  987. if (pext)
  988. isGranny=(strnicmp(pext,".GR2",4) == 0);
  989. if (!isGranny)
  990. #endif
  991. {
  992. HAnimClass *anim=WW3DAssetManager::Get_HAnim(name); //we only do custom granny processing.
  993. #ifdef DUMP_PERF_STATS
  994. if (HAnim_Recursions == 1)
  995. {
  996. GetPrecisionTimer(&endTime64);
  997. Total_Get_HAnim_Time += endTime64-startTime64;
  998. }
  999. HAnim_Recursions--;
  1000. #endif
  1001. return anim;
  1002. }
  1003. #ifdef INCLUDE_GRANNY_IN_BUILD
  1004. // Try to find the hanim
  1005. HAnimClass * anim = m_GrannyAnimManager->Get_Anim(name);
  1006. if (WW3D_Load_On_Demand && anim == NULL) { // If we didn't find it, try to load on demand
  1007. if ( !m_GrannyAnimManager->Is_Missing( name ) ) { // if this is NOT a known missing anim
  1008. // If we can't find it, try the parent directory
  1009. if ( m_GrannyAnimManager->Load_Anim(name) == 1 ) {
  1010. StringClass new_filename = StringClass("..\\") + name;
  1011. m_GrannyAnimManager->Load_Anim( new_filename );
  1012. }
  1013. anim = m_GrannyAnimManager->Get_Anim(name); // Try again
  1014. if (anim == NULL) {
  1015. // WWDEBUG_SAY(("WARNING: Animation %s not found!\n", name));
  1016. m_GrannyAnimManager->Register_Missing( name ); // This is now a KNOWN missing anim
  1017. }
  1018. }
  1019. }
  1020. return anim;
  1021. #endif
  1022. }
  1023. //---------------------------------------------------------------------
  1024. // Uniqing
  1025. //---------------------------------------------------------------------
  1026. //---------------------------------------------------------------------
  1027. /** Generals specific code to generate customized render objects for each team color
  1028. */
  1029. void W3DAssetManager::Make_HLOD_Unique(RenderObjClass *robj, Bool geometry, Bool colors)
  1030. {
  1031. int num_sub = robj->Get_Num_Sub_Objects();
  1032. for(int i = 0; i < num_sub; i++) {
  1033. RenderObjClass *sub_obj = robj->Get_Sub_Object(i);
  1034. Make_Unique(sub_obj, geometry, colors);
  1035. REF_PTR_RELEASE(sub_obj);
  1036. }
  1037. }
  1038. //---------------------------------------------------------------------
  1039. /** Generals specific code to generate customized render objects for each team color
  1040. */
  1041. void W3DAssetManager::Make_Unique(RenderObjClass *robj, Bool geometry, Bool colors)
  1042. {
  1043. switch (robj->Class_ID()) {
  1044. case RenderObjClass::CLASSID_MESH:
  1045. Make_Mesh_Unique(robj,geometry,colors);
  1046. break;
  1047. case RenderObjClass::CLASSID_HLOD:
  1048. Make_HLOD_Unique(robj,geometry,colors);
  1049. break;
  1050. }
  1051. }
  1052. //---------------------------------------------------------------------
  1053. /** Determine what method is used to apply house color to this mesh (if any) */
  1054. static Bool getMeshColorMethods(MeshClass *mesh, Bool &vertexColor, Bool &textureColor)
  1055. {
  1056. vertexColor = false;
  1057. textureColor = false;
  1058. //Check if mesh is using custom texture containing house color
  1059. MaterialInfoClass *material = mesh->Get_Material_Info();
  1060. if (material)
  1061. { for (int j=0; j<material->Texture_Count(); j++)
  1062. if (_strnicmp(material->Peek_Texture(j)->Get_Texture_Name(),"ZHC",3) == 0)
  1063. { textureColor = true;
  1064. break;
  1065. }
  1066. REF_PTR_RELEASE(material);
  1067. }
  1068. //Check if mesh is using a custom mesh which contains house color in material.
  1069. //Meshes which are part of another model have names in the form "name.name" while
  1070. //isolated meshes are just "name". We check for both starting with "HOUSECOLOR".
  1071. const char *meshName;
  1072. if ( ( (meshName=strchr(mesh->Get_Name(),'.') ) != 0 && *(meshName++)) || ( (meshName=mesh->Get_Name()) != NULL) )
  1073. { //Check if this object has housecolors on mesh
  1074. if ( _strnicmp(meshName,"HOUSECOLOR", 10) == 0)
  1075. vertexColor = true;
  1076. }
  1077. return (vertexColor || textureColor);
  1078. }
  1079. //---------------------------------------------------------------------
  1080. /** Generals specific code to generate customized render objects for each team color
  1081. */
  1082. void W3DAssetManager::Make_Mesh_Unique(RenderObjClass *robj, Bool geometry, Bool colors)
  1083. {
  1084. int i;
  1085. MeshClass *mesh=(MeshClass*) robj;
  1086. Bool isVertexColor, isTextureColor;
  1087. //figure out what type of coloring this mesh requires (if any)
  1088. if ((colors && getMeshColorMethods(mesh,isVertexColor,isTextureColor)) || geometry)
  1089. { //mesh has some house color applied so make those components unique to mesh.
  1090. //Create unique data for this mesh
  1091. if (!geometry) //scaling geometry automatically makes it unique so not needed here.
  1092. mesh->Make_Unique();
  1093. MeshModelClass * model = mesh->Get_Model();
  1094. if (colors && isVertexColor)
  1095. {
  1096. MaterialInfoClass *material=mesh->Get_Material_Info();
  1097. for (i=0; i<material->Vertex_Material_Count(); i++)
  1098. material->Peek_Vertex_Material(i)->Make_Unique();
  1099. REF_PTR_RELEASE(material);
  1100. }
  1101. REF_PTR_RELEASE(model);
  1102. }
  1103. }
  1104. //---------------------------------------------------------------------
  1105. /**Report prototypes that have all assets with reference count
  1106. equal to 1*/
  1107. void W3DAssetManager::Report_Used_Prototypes(void)
  1108. {
  1109. int count = Prototypes.Count();
  1110. while (count-- > 0) {
  1111. PrototypeClass * proto = Prototypes[count];
  1112. if (proto->Get_Class_ID() == RenderObjClass::CLASSID_HLOD || proto->Get_Class_ID() == RenderObjClass::CLASSID_MESH)
  1113. {
  1114. DEBUG_LOG(("**Unfreed Prototype On Map Reset: %s\n",proto->Get_Name()));
  1115. }
  1116. }
  1117. }
  1118. //---------------------------------------------------------------------
  1119. /**Report any assets with reference counts > 1. This means they are still
  1120. referenced by something besides the asset manager.*/
  1121. void W3DAssetManager::Report_Used_Assets(void)
  1122. {
  1123. Report_Used_Prototypes();
  1124. ///@todo: Report unfreed skeletons and animations
  1125. // HAnimManager.Free_All_Anims();
  1126. // HTreeManager.Free_All_Trees();
  1127. Report_Used_Textures();
  1128. Report_Used_Font3DDatas();
  1129. Report_Used_FontChars();
  1130. }
  1131. //---------------------------------------------------------------------
  1132. void W3DAssetManager::Report_Used_FontChars(void)
  1133. {
  1134. Int count=FontCharsList.Count();
  1135. while (count-- > 0)
  1136. {
  1137. if (FontCharsList[count]->Num_Refs() >= 1)
  1138. {
  1139. DEBUG_LOG(("**Unfreed FontChar On Map Reset: %s\n",FontCharsList[count]->Get_Name()));
  1140. //FontCharsList[count]->Release_Ref();
  1141. //FontCharsList.Delete(count);
  1142. }
  1143. }
  1144. }
  1145. //---------------------------------------------------------------------
  1146. /**Report all textures with refcounts >= 1*/
  1147. void W3DAssetManager::Report_Used_Textures(void)
  1148. {
  1149. /*
  1150. ** for each texture in the list, get it, check it's refcount, and and release ref it if the
  1151. ** refcount is one.
  1152. */
  1153. // unsigned count=0;
  1154. // TextureClass* temp_textures[256];
  1155. HashTemplateIterator<StringClass,TextureClass*> ite(TextureHash);
  1156. for (ite.First();!ite.Is_Done();ite.Next()) {
  1157. TextureClass* tex=ite.Peek_Value();
  1158. if (tex->Num_Refs() <= 1) {
  1159. /* temp_textures[count++]=tex;
  1160. if (count==256) {
  1161. for (unsigned i=0;i<256;++i) {
  1162. TextureHash.Remove(temp_textures[i]->Get_Texture_Name());
  1163. temp_textures[i]->Release_Ref();
  1164. }
  1165. count=0;
  1166. ite.First(); // iterator doesn't support modifying the hash table while iterating, so start from the
  1167. // beginning.
  1168. }*/
  1169. }
  1170. else
  1171. {
  1172. DEBUG_LOG(("**Texture \"%s\" referenced %d times on map reset\n",tex->Get_Texture_Name(),tex->Num_Refs()-1));
  1173. }
  1174. }
  1175. /* for (unsigned i=0;i<count;++i) {
  1176. TextureHash.Remove(temp_textures[i]->Get_Texture_Name());
  1177. temp_textures[i]->Release_Ref();
  1178. }*/
  1179. }
  1180. //---------------------------------------------------------------------
  1181. /**Report all used fonts*/
  1182. void W3DAssetManager::Report_Used_Font3DDatas( void )
  1183. {
  1184. /*
  1185. ** for each font data in the list, get it, check it's refcount, and and release ref it if the
  1186. ** refcount is one.
  1187. */
  1188. SLNode<Font3DDataClass> *node, * next;
  1189. for ( node = Font3DDatas.Head(); node; node = next) {
  1190. next = node->Next();
  1191. Font3DDataClass *font = node->Data();
  1192. if (font->Num_Refs() == 1) {
  1193. /* Font3DDatas.Remove(font);
  1194. font->Release_Ref();*/
  1195. }
  1196. else
  1197. {
  1198. DEBUG_LOG(("**Unfreed Font3DDatas On Map Reset: %s\n",font->Name));
  1199. }
  1200. }
  1201. }
  1202. //---------------------------------------------------------------------
  1203. // E&B Coloring Code
  1204. //---------------------------------------------------------------------
  1205. /*
  1206. //---------------------------------------------------------------------
  1207. // Uniqing
  1208. //---------------------------------------------------------------------
  1209. void W3DAssetManager::Make_Mesh_Unique(RenderObjClass *robj, Bool geometry, Bool colors)
  1210. {
  1211. int i;
  1212. MeshClass *mesh=(MeshClass*) robj;
  1213. mesh->Make_Unique();
  1214. MeshModelClass * model = mesh->Get_Model();
  1215. if (colors) {
  1216. // make all vertex materials unique
  1217. MaterialInfoClass *material = mesh->Get_Material_Info();
  1218. for (i=0; i<material->Vertex_Material_Count(); i++)
  1219. material->Peek_Vertex_Material(i)->Make_Unique();
  1220. REF_PTR_RELEASE(material);
  1221. // make all color arrays unique
  1222. model->Make_Color_Array_Unique(0);
  1223. model->Make_Color_Array_Unique(1);
  1224. // do not do textures yet
  1225. // because we want to do the color conversion
  1226. // for the top mip level and then
  1227. // mip filter instead of converting all mip levels
  1228. }
  1229. if (geometry) {
  1230. // make geometry unique
  1231. model->Make_Geometry_Unique();
  1232. }
  1233. REF_PTR_RELEASE(model);
  1234. }
  1235. void W3DAssetManager::Make_HLOD_Unique(RenderObjClass *robj, Bool geometry, Bool colors)
  1236. {
  1237. int num_sub = robj->Get_Num_Sub_Objects();
  1238. for(int i = 0; i < num_sub; i++) {
  1239. RenderObjClass *sub_obj = robj->Get_Sub_Object(i);
  1240. Make_Unique(sub_obj,geometry,colors);
  1241. REF_PTR_RELEASE(sub_obj);
  1242. }
  1243. }
  1244. void W3DAssetManager::Make_Unique(RenderObjClass *robj, Bool geometry, Bool colors)
  1245. {
  1246. switch (robj->Class_ID()) {
  1247. case RenderObjClass::CLASSID_MESH:
  1248. Make_Mesh_Unique(robj,geometry,colors);
  1249. break;
  1250. case RenderObjClass::CLASSID_HLOD:
  1251. Make_HLOD_Unique(robj,geometry,colors);
  1252. break;
  1253. }
  1254. }
  1255. static inline void Munge_Render_Obj_Name(char *newname, const char *oldname, float scale, const Vector3 &hsv_shift)
  1256. {
  1257. char lower_case_name[255];
  1258. strcpy(lower_case_name, oldname);
  1259. _strlwr(lower_case_name);
  1260. sprintf(newname,"#%s!%gH%gS%gV%g", lower_case_name, scale, hsv_shift.X, hsv_shift.Y, hsv_shift.Z);
  1261. }
  1262. static inline void Munge_Texture_Name(char *newname, const char *oldname, const Vector3 &hsv_shift)
  1263. {
  1264. char lower_case_name[255];
  1265. strcpy(lower_case_name, oldname);
  1266. _strlwr(lower_case_name);
  1267. sprintf(newname,"#%s!H%gS%gV%g", lower_case_name, hsv_shift.X, hsv_shift.Y, hsv_shift.Z);
  1268. }
  1269. RenderObjClass * W3DAssetManager::Create_Render_Obj(const char * name,float scale, const Vector3 &hsv_shift)
  1270. {
  1271. Bool isGranny = false;
  1272. #ifdef INCLUDE_GRANNY_IN_BUILD
  1273. char *pext=strrchr(name,'.'); //find file extension
  1274. if (pext)
  1275. isGranny=(strnicmp(pext,".GR2",4) == 0);
  1276. #endif
  1277. Bool reallyscale = (WWMath::Fabs(scale - ident_scale) > scale_epsilon);
  1278. Bool reallyhsv_shift = (WWMath::Fabs(hsv_shift.X - ident_HSV.X) > H_epsilon ||
  1279. WWMath::Fabs(hsv_shift.Y - ident_HSV.Y) > S_epsilon || WWMath::Fabs(hsv_shift.Z - ident_HSV.Z) > V_epsilon);
  1280. // base case, no scale or hue shifting
  1281. if (!reallyscale && !reallyhsv_shift) return WW3DAssetManager::Create_Render_Obj(name);
  1282. char newname[512];
  1283. Munge_Render_Obj_Name(newname, name, scale, hsv_shift);
  1284. // see if we got a cached version
  1285. RenderObjClass *rendobj=NULL;
  1286. if (isGranny)
  1287. { //Granny objects share the same prototype since they allow instance scaling.
  1288. strcpy(newname,name); //use same name for all granny objects at any scale.
  1289. }
  1290. Set_WW3D_Load_On_Demand(false); // munged name will never be found in a file.
  1291. rendobj=WW3DAssetManager::Create_Render_Obj(newname);
  1292. if (rendobj)
  1293. { if (isGranny)
  1294. ///@todo Granny objects are realtime scaled - fix to scale like W3D.
  1295. rendobj->Set_ObjectScale(scale);
  1296. Set_WW3D_Load_On_Demand(true); // Auto Load.
  1297. return rendobj;
  1298. }
  1299. // create a new one based on
  1300. // exisiting prototype
  1301. WWPROFILE( "WW3DAssetManager::Create_Render_Obj" );
  1302. WWMEMLOG(MEM_GEOMETRY);
  1303. // Try to find a prototype
  1304. PrototypeClass * proto = Find_Prototype(name);
  1305. Set_WW3D_Load_On_Demand(true); // Auto Load.
  1306. if (WW3D_Load_On_Demand && proto == NULL) { // If we didn't find one, try to load on demand
  1307. char filename [MAX_PATH];
  1308. char *mesh_name = ::strchr (name, '.');
  1309. if (mesh_name != NULL) {
  1310. ::lstrcpyn (filename, name, ((int)mesh_name) - ((int)name) + 1);
  1311. if (isGranny)
  1312. ::lstrcat (filename, ".gr2");
  1313. else
  1314. ::lstrcat (filename, ".w3d");
  1315. } else {
  1316. sprintf( filename, "%s.w3d", name);
  1317. }
  1318. // If we can't find it, try the parent directory
  1319. if ( Load_3D_Assets( filename ) == false ) {
  1320. StringClass new_filename = StringClass("..\\") + filename;
  1321. if (Load_3D_Assets( new_filename ) == false)
  1322. {
  1323. char *mesh_name = ::strchr (filename, '.');
  1324. ::lstrcpyn (mesh_name, ".gr2",5);
  1325. Load_3D_Assets( filename );
  1326. isGranny=true;
  1327. }
  1328. }
  1329. proto = Find_Prototype(name); // try again
  1330. }
  1331. if (proto == NULL) {
  1332. static int warning_count = 0;
  1333. if (++warning_count <= 20) {
  1334. WWDEBUG_SAY(("WARNING: Failed to create Render Object: %s\r\n",name));
  1335. }
  1336. return NULL; // Failed to find a prototype
  1337. }
  1338. rendobj=proto->Create();
  1339. if (!rendobj) return NULL;
  1340. if (!isGranny)
  1341. { Make_Unique(rendobj,reallyscale,reallyhsv_shift);
  1342. if (reallyscale) rendobj->Scale(scale);
  1343. if (reallyhsv_shift) Recolor_Asset(rendobj,hsv_shift);
  1344. }
  1345. else
  1346. { ///@todo Granny objects are realtime scaled - fix to scale like W3D.
  1347. rendobj->Set_ObjectScale(scale);
  1348. return rendobj;
  1349. }
  1350. W3DPrototypeClass *w3dproto=NEW W3DPrototypeClass(rendobj,newname);
  1351. rendobj->Release_Ref();
  1352. Add_Prototype(w3dproto);
  1353. return w3dproto->Create();
  1354. }
  1355. TextureClass * W3DAssetManager::Get_Texture_With_HSV_Shift(const char * filename, const Vector3 &hsv_shift, TextureClass::MipCountType mip_level_count)
  1356. {
  1357. WWPROFILE( "W3DAssetManager::Get_Texture with HSV shift" );
  1358. Bool is_hsv_shift = (WWMath::Fabs(hsv_shift.X - ident_HSV.X) > H_epsilon ||
  1359. WWMath::Fabs(hsv_shift.Y - ident_HSV.Y) > S_epsilon || WWMath::Fabs(hsv_shift.Z - ident_HSV.Z) > V_epsilon);
  1360. if (!is_hsv_shift) {
  1361. return Get_Texture(filename, mip_level_count);
  1362. } else {
  1363. //
  1364. // Bail if the user isn't really asking for anything
  1365. //
  1366. if ((filename == NULL) || (strlen(filename) == 0)) {
  1367. return NULL;
  1368. }
  1369. TextureClass *newtex = Find_Texture(filename, hsv_shift);
  1370. if (!newtex) {
  1371. // No cached texture - need to create
  1372. char lower_case_name[255];
  1373. strcpy(lower_case_name, filename);
  1374. _strlwr(lower_case_name);
  1375. TextureClass *oldtex = TextureHash.Get(lower_case_name);
  1376. if (!oldtex) {
  1377. oldtex = NEW_REF(TextureClass,(lower_case_name, NULL, mip_level_count));
  1378. TextureHash.Insert(oldtex->Get_Texture_Name(), oldtex);
  1379. }
  1380. newtex = Recolor_Texture_One_Time(oldtex, hsv_shift);
  1381. // If the recolorization failed, return the original texture
  1382. if (!newtex) {
  1383. newtex = oldtex;
  1384. newtex->Add_Ref();
  1385. }
  1386. }
  1387. return newtex;
  1388. }
  1389. }
  1390. void W3DAssetManager::Recolor_Vertex_Material(VertexMaterialClass *vmat, const Vector3 &hsv_shift)
  1391. {
  1392. Vector3 rgb;
  1393. vmat->Get_Ambient(&rgb);
  1394. Recolor(rgb,hsv_shift);
  1395. vmat->Set_Ambient(rgb);
  1396. vmat->Get_Diffuse(&rgb);
  1397. Recolor(rgb,hsv_shift);
  1398. vmat->Set_Diffuse(rgb);
  1399. vmat->Get_Emissive(&rgb);
  1400. Recolor(rgb,hsv_shift);
  1401. vmat->Set_Emissive(rgb);
  1402. vmat->Get_Specular(&rgb);
  1403. Recolor(rgb,hsv_shift);
  1404. vmat->Set_Specular(rgb);
  1405. }
  1406. void W3DAssetManager::Recolor_Vertices(unsigned int *color, int count, const Vector3 &hsv_shift)
  1407. {
  1408. int i;
  1409. Vector4 rgba;
  1410. for (i=0; i<count; i++)
  1411. {
  1412. rgba=DX8Wrapper::Convert_Color(color[i]);
  1413. Recolor(reinterpret_cast<Vector3&>(rgba),hsv_shift);
  1414. color[i]=DX8Wrapper::Convert_Color_Clamp(rgba);
  1415. }
  1416. }
  1417. TextureClass * W3DAssetManager::Recolor_Texture(TextureClass *texture, const Vector3 &hsv_shift)
  1418. {
  1419. const char *name=texture->Get_Texture_Name();
  1420. TextureClass *newtex = Find_Texture(name, hsv_shift);
  1421. if (newtex) {
  1422. return newtex;
  1423. }
  1424. return Recolor_Texture_One_Time(texture, hsv_shift);
  1425. }
  1426. TextureClass * W3DAssetManager::Recolor_Texture_One_Time(TextureClass *texture, const Vector3 &hsv_shift)
  1427. {
  1428. const char *name=texture->Get_Texture_Name();
  1429. // if texture is procedural return NULL
  1430. if (name && name[0]=='!') return NULL;
  1431. // make sure texture is loaded
  1432. if (!texture->Is_Initialized())
  1433. TextureLoader::Request_High_Priority_Loading(texture, (TextureClass::MipCountType)texture->Get_Mip_Level_Count());
  1434. SurfaceClass::SurfaceDescription desc;
  1435. SurfaceClass *newsurf, *oldsurf, *smallsurf;
  1436. texture->Get_Level_Description(desc);
  1437. // if texture is monochrome and no value shifting
  1438. // return NULL
  1439. smallsurf=texture->Get_Surface_Level((TextureClass::MipCountType)texture->Get_Mip_Level_Count()-1);
  1440. if (hsv_shift.Z==0.0f && smallsurf->Is_Monochrome())
  1441. {
  1442. REF_PTR_RELEASE(smallsurf);
  1443. return NULL;
  1444. }
  1445. REF_PTR_RELEASE(smallsurf);
  1446. oldsurf=texture->Get_Surface_Level();
  1447. newsurf=NEW_REF(SurfaceClass,(desc.Width,desc.Height,desc.Format));
  1448. newsurf->Copy(0,0,0,0,desc.Width,desc.Height,oldsurf);
  1449. newsurf->Hue_Shift(hsv_shift);
  1450. TextureClass * newtex=NEW_REF(TextureClass,(newsurf,(TextureClass::MipCountType)texture->Get_Mip_Level_Count()));
  1451. newtex->Set_Mag_Filter(texture->Get_Mag_Filter());
  1452. newtex->Set_Min_Filter(texture->Get_Min_Filter());
  1453. newtex->Set_Mip_Mapping(texture->Get_Mip_Mapping());
  1454. newtex->Set_U_Addr_Mode(texture->Get_U_Addr_Mode());
  1455. newtex->Set_V_Addr_Mode(texture->Get_V_Addr_Mode());
  1456. char newname[512];
  1457. Munge_Texture_Name(newname, name, hsv_shift);
  1458. newtex->Set_Texture_Name(newname);
  1459. TextureHash.Insert(newtex->Get_Texture_Name(), newtex);
  1460. newtex->Add_Ref();
  1461. REF_PTR_RELEASE(oldsurf);
  1462. REF_PTR_RELEASE(newsurf);
  1463. return newtex;
  1464. }
  1465. TextureClass * W3DAssetManager::Find_Texture(const char * name, const Vector3 &hsv_shift)
  1466. {
  1467. char newname[512];
  1468. Munge_Texture_Name(newname, name, hsv_shift);
  1469. // see if we have a cached copy
  1470. TextureClass *newtex = TextureHash.Get(newname);
  1471. if (newtex) {
  1472. newtex->Add_Ref();
  1473. }
  1474. return newtex;
  1475. }
  1476. void W3DAssetManager::Recolor_Mesh(RenderObjClass *robj, const Vector3 &hsv_shift)
  1477. {
  1478. int i;
  1479. MeshClass *mesh=(MeshClass*) robj;
  1480. MeshModelClass * model = mesh->Get_Model();
  1481. MaterialInfoClass *material = mesh->Get_Material_Info();
  1482. // recolor vertex material
  1483. for (i=0; i<material->Vertex_Material_Count(); i++)
  1484. Recolor_Vertex_Material(material->Peek_Vertex_Material(i),hsv_shift);
  1485. // recolor color arrays
  1486. unsigned int * color;
  1487. color=model->Get_Color_Array(0,false);
  1488. if (color) Recolor_Vertices(color,model->Get_Vertex_Count(),hsv_shift);
  1489. color=model->Get_Color_Array(1,false);
  1490. if (color) Recolor_Vertices(color,model->Get_Vertex_Count(),hsv_shift);
  1491. // recolor textures
  1492. TextureClass *newtex,*oldtex;
  1493. for (i=0; i<material->Texture_Count(); i++)
  1494. {
  1495. oldtex=material->Peek_Texture(i);
  1496. newtex=Recolor_Texture(oldtex,hsv_shift);
  1497. if (newtex)
  1498. {
  1499. model->Replace_Texture(oldtex,newtex);
  1500. material->Replace_Texture(i,newtex);
  1501. REF_PTR_RELEASE(newtex);
  1502. }
  1503. }
  1504. REF_PTR_RELEASE(material);
  1505. REF_PTR_RELEASE(model);
  1506. }
  1507. void W3DAssetManager::Recolor_HLOD(RenderObjClass *robj, const Vector3 &hsv_shift)
  1508. {
  1509. int num_sub = robj->Get_Num_Sub_Objects();
  1510. for(int i = 0; i < num_sub; i++) {
  1511. RenderObjClass *sub_obj = robj->Get_Sub_Object(i);
  1512. Recolor_Asset(sub_obj,hsv_shift);
  1513. REF_PTR_RELEASE(sub_obj);
  1514. }
  1515. }
  1516. void W3DAssetManager::Recolor_ParticleEmitter(RenderObjClass *robj, const Vector3 &hsv_shift)
  1517. {
  1518. unsigned int i;
  1519. ParticleEmitterClass* emit=(ParticleEmitterClass*) robj;
  1520. ParticlePropertyStruct<Vector3> colors;
  1521. emit->Get_Color_Key_Frames(colors);
  1522. Recolor(colors.Start,hsv_shift);
  1523. Recolor(colors.Rand,hsv_shift);
  1524. for (i=0; i<colors.NumKeyFrames; i++)
  1525. Recolor(colors.Values[i],hsv_shift);
  1526. emit->Reset_Colors(colors);
  1527. delete colors.Values;
  1528. delete colors.KeyTimes;
  1529. TextureClass *tex=emit->Get_Texture();
  1530. TextureClass *newtex=Recolor_Texture(tex,hsv_shift);
  1531. if (newtex)
  1532. {
  1533. emit->Set_Texture(newtex);
  1534. REF_PTR_RELEASE(newtex);
  1535. }
  1536. REF_PTR_RELEASE(tex);
  1537. }
  1538. void W3DAssetManager::Recolor_Asset(RenderObjClass *robj, const Vector3 &hsv_shift)
  1539. {
  1540. switch (robj->Class_ID()) {
  1541. case RenderObjClass::CLASSID_MESH:
  1542. Recolor_Mesh(robj,hsv_shift);
  1543. break;
  1544. case RenderObjClass::CLASSID_HLOD:
  1545. Recolor_HLOD(robj,hsv_shift);
  1546. break;
  1547. case RenderObjClass::CLASSID_PARTICLEEMITTER:
  1548. Recolor_ParticleEmitter(robj,hsv_shift);
  1549. break;
  1550. }
  1551. }
  1552. */