W3DAssetManager.cpp 53 KB

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