| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769 |
- /*
- ** Command & Conquer Generals(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program is free software: you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation, either version 3 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- ////////////////////////////////////////////////////////////////////////////////
- // //
- // (c) 2001-2003 Electronic Arts Inc. //
- // //
- ////////////////////////////////////////////////////////////////////////////////
- /***********************************************************************************************
- *** 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 ***
- ***********************************************************************************************
- * *
- * Project Name : W3DAssetManager *
- * *
- * $Archive:: $*
- * *
- * Original Author:: Hector Yee (Enbassetmgr)
- * Added/Modified:: Mark Wilczynski
- * *
- * $Author:: $*
- * *
- * $Modtime:: $*
- * *
- * $Revision:: $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #include <always.h>
- #include "W3DDevice/GameClient/W3DAssetManager.h"
- #include "proto.h"
- #include "rendobj.h"
- #include <vector3.h>
- #include "mesh.h"
- #include "hlod.h"
- #include "matinfo.h"
- #include "meshmdl.h"
- #include "part_emt.h"
- #include "vertmaterial.h"
- #include "dx8wrapper.h"
- #include "texture.h"
- #include "surfaceclass.h"
- #include "textureloader.h"
- #include "ww3dformat.h"
- #include "colorspace.h"
- #include <wwprofile.h>
- #include "wwmemlog.h"
- #include "ffactory.h"
- #include "font3d.h"
- #include "render2dsentence.h"
- #include <stdio.h>
- #include "W3DDevice/GameClient/W3DGranny.h"
- #include "Common/PerfTimer.h"
- #include "Common/GlobalData.h"
- #ifdef _INTERNAL
- // for occasional debugging...
- //#pragma optimize("", off)
- //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
- #endif
- //---------------------------------------------------------------------
- // Constants
- //---------------------------------------------------------------------
- const float ident_scale(1.0f);
- const float scale_epsilon(0.01f);
- const Vector3 ident_HSV(0,0,0);
- const float H_epsilon(1.0f);
- const float S_epsilon(0.01f);
- const float V_epsilon(0.01f);
- //---------------------------------------------------------------------
- // Externs defined somewhere in W3D.
- //---------------------------------------------------------------------
- unsigned int PixelSize(const SurfaceClass::SurfaceDescription &sd);
- void Convert_Pixel(Vector3 &rgb, const SurfaceClass::SurfaceDescription &sd, const unsigned char * pixel);
- void Convert_Pixel(unsigned char * pixel,const SurfaceClass::SurfaceDescription &sd, const Vector3 &rgb);
- //---------------------------------------------------------------------
- // W3DPrototype
- //---------------------------------------------------------------------
- //---------------------------------------------------------------------
- class W3DPrototypeClass : public MemoryPoolObject, public PrototypeClass
- {
- MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE( W3DPrototypeClass, "W3DPrototypeClass" )
- public:
- W3DPrototypeClass(RenderObjClass * proto, const AsciiString& name);
- virtual const char* Get_Name(void) const { return Name.str(); }
- virtual int Get_Class_ID(void) const { return Proto->Class_ID(); }
- virtual RenderObjClass * Create(void);
- virtual void DeleteSelf() { deleteInstance(); }
- protected:
- //virtual ~W3DPrototypeClass(void);
- private:
- RenderObjClass * Proto;
- AsciiString Name;
- };
- //---------------------------------------------------------------------
- W3DPrototypeClass::W3DPrototypeClass(RenderObjClass * proto, const AsciiString& name) :
- Proto(proto),
- Name(name)
- {
- assert(Proto);
- Proto->Add_Ref();
- }
- //---------------------------------------------------------------------
- W3DPrototypeClass::~W3DPrototypeClass(void)
- {
- if (Proto) {
- Proto->Release_Ref();
- Proto = NULL;
- }
- }
- //---------------------------------------------------------------------
- RenderObjClass * W3DPrototypeClass::Create(void)
- {
- return (RenderObjClass *)( SET_REF_OWNER( Proto->Clone() ) );
- }
-
- //---------------------------------------------------------------------
- // W3DAssetManager
- //---------------------------------------------------------------------
- //---------------------------------------------------------------------
- W3DAssetManager::W3DAssetManager(void)
- {
- #ifdef INCLUDE_GRANNY_IN_BUILD
- m_GrannyAnimManager = NEW GrannyAnimManagerClass;
- #endif
- }
- //---------------------------------------------------------------------
- W3DAssetManager::~W3DAssetManager(void)
- {
- #ifdef INCLUDE_GRANNY_IN_BUILD
- delete m_GrannyAnimManager;
- #endif
- }
- #ifdef DUMP_PERF_STATS
- __int64 Total_Get_Texture_Time=0;
- #endif
- //---------------------------------------------------------------------
- TextureClass *W3DAssetManager::Get_Texture(
- const char * filename,
- TextureClass::MipCountType mip_level_count,
- WW3DFormat texture_format,
- bool allow_compression
- )
- {
- #ifdef DUMP_PERF_STATS
- __int64 startTime64,endTime64;
- GetPrecisionTimer(&startTime64);
- #endif
- WWPROFILE( "WW3DAssetManager::Get_Texture 1" );
- /*
- ** Bail if the user isn't really asking for anything
- */
- if (!filename || !*filename)
- {
- #ifdef DUMP_PERF_STATS
- GetPrecisionTimer(&endTime64);
- Total_Get_Texture_Time += endTime64-startTime64;
- #endif
- return NULL;
- }
- StringClass lower_case_name(filename,true);
- _strlwr(lower_case_name.Peek_Buffer());
- /*
- ** See if the texture has already been loaded.
- */
- TextureClass* tex = TextureHash.Get(lower_case_name);
- if (tex && texture_format != WW3D_FORMAT_UNKNOWN)
- {
- WWASSERT_PRINT(tex->Get_Texture_Format() == texture_format, ("Texture %s has already been loaded with different format",filename));
- }
- /*
- ** Didn't have it so we have to create a new texture
- */
- if (!tex)
- {
- tex = NEW_REF(TextureClass, (lower_case_name, NULL, mip_level_count, texture_format, allow_compression));
- TextureHash.Insert(tex->Get_Texture_Name(),tex);
- // if (TheGlobalData->m_preloadAssets)
- // {
- // extern std::vector<std::string> preloadTextureNamesGlobalHack;
- // preloadTextureNamesGlobalHack.push_back(tex->Get_Texture_Name());
- // }
- #if defined(_DEBUG) || defined(_INTERNAL)
- if (TheGlobalData->m_preloadReport)
- {
- //loading a new asset and app is requesting a log of all loaded assets.
- FILE *logfile=fopen("PreloadedAssets.txt","a+"); //append to log
- if (logfile)
- {
- fprintf(logfile,"TX: %s\n",tex->Get_Texture_Name());
- fclose(logfile);
- }
- }
- #endif
- }
- tex->Add_Ref();
- #ifdef DUMP_PERF_STATS
- GetPrecisionTimer(&endTime64);
- Total_Get_Texture_Time += endTime64-startTime64;
- #endif
- return tex;
- }
- //---------------------------------------------------------------------
- RenderObjClass * W3DAssetManager::Create_Render_Obj(const char* name)
- {
- return WW3DAssetManager::Create_Render_Obj(name);
- }
- //---------------------------------------------------------------------
- /** 'Generals' specific munging to encode team color and scale in model name */
- static inline void Munge_Render_Obj_Name(char *newname, const char *oldname, float scale, const int color, const char *textureName)
- {
- char lower_case_name[255];
- strcpy(lower_case_name, oldname);
- _strlwr(lower_case_name);
- if (!textureName)
- textureName = "";
- sprintf(newname,"#%d!%g!%s#%s",color,scale,textureName,lower_case_name);
- }
- //---------------------------------------------------------------------
- static inline void Munge_Texture_Name(char *newname, const char *oldname, const int color)
- {
- char lower_case_name[255];
- strcpy(lower_case_name, oldname);
- _strlwr(lower_case_name);
- sprintf(newname,"#%d#%s", color, lower_case_name);
- }
- //---------------------------------------------------------------------
- int W3DAssetManager::replaceAssetTexture(RenderObjClass *robj, TextureClass *oldTex, TextureClass *newTex)
- {
- switch (robj->Class_ID()) {
- case RenderObjClass::CLASSID_MESH:
- return replaceMeshTexture(robj, oldTex, newTex);
- break;
- case RenderObjClass::CLASSID_HLOD:
- return replaceHLODTexture(robj, oldTex, newTex);
- break;
- }
- return 0;
- }
- //---------------------------------------------------------------------
- Int W3DAssetManager::replaceHLODTexture(RenderObjClass *robj, TextureClass *oldTex, TextureClass *newTex)
- {
- int didReplace=0;
- int num_sub = robj->Get_Num_Sub_Objects();
- for(int i = 0; i < num_sub; i++) {
- RenderObjClass *sub_obj = robj->Get_Sub_Object(i);
- didReplace |= replaceAssetTexture(sub_obj, oldTex, newTex);
- REF_PTR_RELEASE(sub_obj);
- }
- return didReplace;
- }
- //---------------------------------------------------------------------
- Int W3DAssetManager::replaceMeshTexture(RenderObjClass *robj, TextureClass *oldTex, TextureClass *newTex)
- {
- int i;
- int didReplace=0;
- MeshClass *mesh=(MeshClass*) robj;
- MeshModelClass * model = mesh->Get_Model();
- MaterialInfoClass *material = mesh->Get_Material_Info();
- for (i=0; i<material->Texture_Count(); i++)
- {
- if (material->Peek_Texture(i) == oldTex)
- {
- model->Replace_Texture(oldTex,newTex);
- material->Replace_Texture(i,newTex);
- didReplace=1;
- }
- }
- REF_PTR_RELEASE(material);
- REF_PTR_RELEASE(model);
- return didReplace;
- }
- //---------------------------------------------------------------------
- /** Replaces all references to old texture with new texture. Operation is performed on
- asset prototype so it will affect most instances of this object. Objects which have
- been customized with house color will not be affected unless they are created after
- this function is called.
- */
- int W3DAssetManager::replacePrototypeTexture(RenderObjClass *robj, const char * oldname, const char * newname)
- {
- //search model for old texture
- TextureClass *oldTex=Get_Texture(oldname);
- TextureClass *newTex=Get_Texture(newname);
- int retCode=replaceAssetTexture(robj,oldTex,newTex);
- REF_PTR_RELEASE(oldTex);
- REF_PTR_RELEASE(newTex);
- return retCode;
- }
- //---------------------------------------------------------------------
- /** Generals specific version that looks for a texture which has been house-color tinted.
- Don't use this unless you really need it. For normal textures, use Get_Texture().
- */
- TextureClass * W3DAssetManager::Find_Texture(const char * name, const int color)
- {
- char newname[512];
- Munge_Texture_Name(newname, name, color);
- // see if we have a cached copy
- TextureClass *newtex = TextureHash.Get(newname);
- if (newtex) {
- newtex->Add_Ref();
- }
- return newtex;
- }
- //---------------------------------------------------------------------
- TextureClass * W3DAssetManager::Recolor_Texture(TextureClass *texture, const int color)
- {
- const char *name=texture->Get_Texture_Name();
- TextureClass *newtex = Find_Texture(name, color);
- if (newtex) {
- return newtex;
- }
- return Recolor_Texture_One_Time(texture, color);
- }
- //---------------------------------------------------------------------
- const Int TEAM_COLOR_PALETTE_SIZE = 16;
- const UnsignedShort houseColorScale[TEAM_COLOR_PALETTE_SIZE] =
- {
- 255,239,223,211,195,174,167,151,135,123,107,91,79,63,47,35
- };
- //---------------------------------------------------------------------
- static void remapPalette16Bit(SurfaceClass::SurfaceDescription *sd, UnsignedShort *palette, unsigned int color)
- {
- UnsignedShort pal[TEAM_COLOR_PALETTE_SIZE];
- 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);
- //Generate a new color gradient palette based on reference color
- for (Int y=0; y<TEAM_COLOR_PALETTE_SIZE; y++)
- {
- rgb.X=(Real)houseColorScale[y]*v_color.X;
- rgb.Y=(Real)houseColorScale[y]*v_color.Y;
- rgb.Z=(Real)houseColorScale[y]*v_color.Z;
- pal[y]=0xffff; //preset alpha to known value
- Convert_Pixel((unsigned char *)&pal[y],*sd,rgb);
- }
- //check if this pixel is part of team color palette
- for (Int p=0; p<TEAM_COLOR_PALETTE_SIZE; p++)
- { palette[p]=pal[p]; //replace color with house color
- }
- }
- //---------------------------------------------------------------------
- static void remapTexture16Bit(Int dx, Int dy, Int pitch, SurfaceClass::SurfaceDescription *sd, UnsignedShort *palette, UnsignedShort *data, unsigned int color)
- {
- UnsignedShort pal[TEAM_COLOR_PALETTE_SIZE];
- 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);
- //Generate a new color gradient palette based on reference color
- for (Int y=0; y<TEAM_COLOR_PALETTE_SIZE; y++)
- {
- rgb.X=(Real)houseColorScale[y]*v_color.X;
- rgb.Y=(Real)houseColorScale[y]*v_color.Y;
- rgb.Z=(Real)houseColorScale[y]*v_color.Z;
- pal[y]=0xffff; //preset alpha to known value
- Convert_Pixel((unsigned char *)&pal[y],*sd,rgb);
- }
- for (y=0; y<dy; y++)
- { for (Int x=0; x<dx; x++)
- { //check if this pixel is part of team color palette
- for (Int p=0; p<TEAM_COLOR_PALETTE_SIZE; p++)
- { if (palette[p]==data[x])
- { data[x]=pal[p]; //replace color with house color
- break;
- }
- }
- }
- data += pitch;
- }
- }
- //Use hue shift instead of alpha blend to apply house color to textures
- #define DO_HUE_SHIFT
- //---------------------------------------------------------------------
- //Input texture is assumed to be in ARGB 4444 format.
- static void remapAlphaTexture16Bit(Int dx, Int dy, Int pitch, SurfaceClass::SurfaceDescription *sd, UnsignedShort *data, unsigned int color)
- {
- UnsignedShort pixel;
- UnsignedShort pixelAlpha;
- #ifndef DO_HUE_SHIFT
- float fpixelAlpha,fpixelAlphaInv;
- #endif
- Vector3 rgb,v_color((float)((color>>16)&0xff)/255.0f,(float)((color>>8)&0xff)/255.0f,(float)(color&0xff)/255.0f);
- Int x,y;
- #ifdef DO_HUE_SHIFT
- Vector3 hsv;
- Vector3 hsv_color;
- RGB_To_HSV(hsv_color,v_color);
- #endif
- for (y=0; y<dy; y++)
- {
- for (x=0; x<dx; x++)
- {
- pixel=data[x];
- pixelAlpha=15-(pixel>>12); //get alpha for house color
- if (pixelAlpha)
- { //some house color needs to show through
- ///@todo: optimize this alpha blend to use fixed point math.
- #ifdef DO_HUE_SHIFT
- RGB_To_HSV(hsv,Vector3(((pixel>>8)&0xf)/15.0f,((pixel>>4)&0xf)/15.0f,(pixel &0xf)/15.0f));
- hsv.X=hsv_color.X;
- hsv.Y*=hsv_color.Y;
- HSV_To_RGB(rgb,hsv);
- #else
- fpixelAlpha=pixelAlpha/15.0f;
- fpixelAlphaInv=1.0f-fpixelAlpha;
- rgb.X=fpixelAlpha * v_color.X + fpixelAlphaInv*(Real)((pixel>>8)&0xf)/15.0f; //red
- rgb.Y=fpixelAlpha * v_color.Y + fpixelAlphaInv*(Real)((pixel>>4)&0xf)/15.0f; //green
- rgb.Z=fpixelAlpha * v_color.Z + fpixelAlphaInv*(Real)(pixel&0xf)/15.0f; //blue
- #endif
- 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);
- }
- data[x] |= 0xf000; //force alpha to opaque.
- }
- data += pitch;
- }
- }
- //---------------------------------------------------------------------
- static void remapPalette32Bit(SurfaceClass::SurfaceDescription *sd, UnsignedInt *palette, unsigned int color)
- {
- UnsignedInt pal[TEAM_COLOR_PALETTE_SIZE];
- 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);
- //Generate a new color gradient palette based on reference color
- for (Int y=0; y<TEAM_COLOR_PALETTE_SIZE; y++)
- {
- rgb.X=(Real)houseColorScale[y]*v_color.X;
- rgb.Y=(Real)houseColorScale[y]*v_color.Y;
- rgb.Z=(Real)houseColorScale[y]*v_color.Z;
- pal[y]=0xffffffff; //preset alpha to known value
- Convert_Pixel((unsigned char *)&pal[y],*sd,rgb);
- }
- //check if this pixel is part of team color palette
- for (Int p=0; p<TEAM_COLOR_PALETTE_SIZE; p++)
- { palette[p]=pal[p]; //replace color with house color
- }
- }
- //---------------------------------------------------------------------
- static void remapTexture32Bit(Int dx, Int dy, Int pitch, SurfaceClass::SurfaceDescription *sd, UnsignedInt *palette, UnsignedInt *data, unsigned int color)
- {
- UnsignedInt pal[TEAM_COLOR_PALETTE_SIZE];
- 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);
- //Generate a new color gradient palette based on reference color
- for (Int y=0; y<TEAM_COLOR_PALETTE_SIZE; y++)
- {
- rgb.X=(Real)houseColorScale[y]*v_color.X;
- rgb.Y=(Real)houseColorScale[y]*v_color.Y;
- rgb.Z=(Real)houseColorScale[y]*v_color.Z;
- pal[y]=0xffffffff; //preset alpha to known value
- Convert_Pixel((unsigned char *)&pal[y],*sd,rgb);
- }
- for (y=0; y<dy; y++)
- { for (Int x=0; x<dx; x++)
- { //check if this pixel is part of team color palette
- for (Int p=0; p<TEAM_COLOR_PALETTE_SIZE; p++)
- { if (palette[p]==data[x])
- { data[x]=pal[p]; //replace color with house color
- break;
- }
- }
- }
- data += pitch;
- }
- }
- //---------------------------------------------------------------------
- static void remapAlphaTexture32Bit(Int dx, Int dy, Int pitch, SurfaceClass::SurfaceDescription *sd, UnsignedInt *data, unsigned int color)
- {
- UnsignedInt pixel;
- UnsignedInt pixelAlpha;
- #ifndef DO_HUE_SHIFT
- float fpixelAlpha,fpixelAlphaInv;
- #endif
- Vector3 rgb,v_color((float)((color>>16)&0xff)/255.0f,(float)((color>>8)&0xff)/255.0f,(float)(color&0xff)/255.0f);
- Int x,y;
- #ifdef DO_HUE_SHIFT
- Vector3 hsv;
- Vector3 hsv_color;
- RGB_To_HSV(hsv_color,v_color);
- #endif
- for (y=0; y<dy; y++)
- { for (x=0; x<dx; x++)
- {
- pixel=data[x];
- pixelAlpha=255-(pixel>>24); //get alpha for house color
- if (pixelAlpha)
- { //some house color needs to show through
- #ifdef DO_HUE_SHIFT
- RGB_To_HSV(hsv,Vector3(((pixel>>16)&0xff)/255.0f,((pixel>>8)&0xff)/255.0f,(pixel &0xff)/255.0f));
- hsv.X=hsv_color.X;
- hsv.Y*=hsv_color.Y;
- HSV_To_RGB(rgb,hsv);
- #else
- ///@todo: optimize this alpha blend to use fixed point math.
- fpixelAlpha=pixelAlpha/255.0f;
- fpixelAlphaInv=1.0f-fpixelAlpha;
- rgb.X=fpixelAlpha * v_color.X + fpixelAlphaInv*(Real)((pixel>>16)&0xff)/255.0f; //red
- rgb.Y=fpixelAlpha * v_color.Y + fpixelAlphaInv*(Real)((pixel>>8)&0xff)/255.0f; //green
- rgb.Z=fpixelAlpha * v_color.Z + fpixelAlphaInv*(Real)(pixel&0xff)/255.0f; //blue
- #endif
- 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);
- }
- data[x] |= 0xff000000; //force alpha to opaque.
- }
- data += pitch;
- }
- }
- //---------------------------------------------------------------------
- /** Surface is assumed to come in the following format:
- First 16 pixels are a palette composed of 24-Bit RGB values.
- Any pixels in remainder of image that use these 24-bit values
- will be remapped using a pre-defined formula.
- */
- void W3DAssetManager::Remap_Palette(SurfaceClass *surface, const int color, Bool doPaletteOnly, Bool useAlpha)
- {
- // unsigned int x;
- SurfaceClass::SurfaceDescription sd;
- surface->Get_Description(sd);
- int pitch,size;
- // UnsignedInt newPalette[TEAM_COLOR_PALETTE_SIZE];
- size=PixelSize(sd);
- unsigned char *bits=(unsigned char*) surface->Lock(&pitch);
- if (doPaletteOnly)
- { //only recolor the palette which is stored in top row. Model only references these pixels.
- if (size == 2)
- remapPalette16Bit(&sd, (UnsignedShort *)bits, color);
- else
- if (size == 4)
- remapPalette32Bit(&sd, (UnsignedInt *)bits,color);
- }
- else
- {
- if (useAlpha)
- {
- if (size == 2)
- remapAlphaTexture16Bit(sd.Width, sd.Height, pitch>>1, &sd, (UnsignedShort *)bits,color);
- else
- if (size == 4)
- remapAlphaTexture32Bit(sd.Width, sd.Height, pitch>>2, &sd, (UnsignedInt *)bits,color);
- }
- else
- { //Recolor the image using the palette stored in top row
- if (size == 2)
- remapTexture16Bit(sd.Width, sd.Height-1, pitch>>1, &sd, (UnsignedShort *)bits, (UnsignedShort *)(bits+pitch), color);
- else
- if (size == 4)
- remapTexture32Bit(sd.Width, sd.Height-1, pitch>>2, &sd, (UnsignedInt *)bits, (UnsignedInt *)(bits+pitch),color);
- }
- }
- surface->Unlock();
- }
- //---------------------------------------------------------------------
- TextureClass * W3DAssetManager::Recolor_Texture_One_Time(TextureClass *texture, const int color)
- {
- const char *name=texture->Get_Texture_Name();
- // if texture is procedural return NULL
- if (name && name[0]=='!') return NULL;
- // make sure texture is loaded
- if (!texture->Is_Initialized())
- TextureLoader::Request_High_Priority_Loading(texture, (TextureClass::MipCountType)texture->Get_Mip_Level_Count());
- SurfaceClass::SurfaceDescription desc;
- SurfaceClass *newsurf, *oldsurf;
- texture->Get_Level_Description(desc);
- Int psize;
- psize=PixelSize(desc);
- DEBUG_ASSERTCRASH( psize == 2 || psize == 4, ("Can't Recolor Texture %s", name) );
- oldsurf=texture->Get_Surface_Level();
- newsurf=NEW_REF(SurfaceClass,(desc.Width,desc.Height,desc.Format));
- newsurf->Copy(0,0,0,0,desc.Width,desc.Height,oldsurf);
- if (*(name+3) == 'D' || *(name+3) == 'd')
- Remap_Palette(newsurf,color, true, false ); //texture only contains a palette stored in top row.
- else
- if (*(name+3) == 'A' || *(name+3) == 'a')
- Remap_Palette(newsurf,color, false, true ); //texture only contains a palette stored in top row.
- TextureClass * newtex=NEW_REF(TextureClass,(newsurf,(TextureClass::MipCountType)texture->Get_Mip_Level_Count()));
- newtex->Set_Mag_Filter(texture->Get_Mag_Filter());
- newtex->Set_Min_Filter(texture->Get_Min_Filter());
- newtex->Set_Mip_Mapping(texture->Get_Mip_Mapping());
- newtex->Set_U_Addr_Mode(texture->Get_U_Addr_Mode());
- newtex->Set_V_Addr_Mode(texture->Get_V_Addr_Mode());
- char newname[512];
- Munge_Texture_Name(newname, name, color);
- newtex->Set_Texture_Name(newname);
- TextureHash.Insert(newtex->Get_Texture_Name(), newtex);
- newtex->Add_Ref();
- REF_PTR_RELEASE(oldsurf);
- REF_PTR_RELEASE(newsurf);
- return newtex;
- }
- #ifdef DUMP_PERF_STATS
- __int64 Total_Create_Render_Obj_Time=0;
- #endif
- //---------------------------------------------------------------------
- /** Generals specific code to generate customized render objects for each team color
- Scale==1.0, color==0x00000000, and oldTexure==NULL are defaults that do nothing.
- */
- RenderObjClass * W3DAssetManager::Create_Render_Obj(
- const char * name,
- float scale,
- const int color,
- const char *oldTexture,
- const char *newTexture
- )
- {
- #ifdef DUMP_PERF_STATS
- __int64 startTime64,endTime64;
- GetPrecisionTimer(&startTime64);
- #endif
- #ifdef INCLUDE_GRANNY_IN_BUILD
- Bool isGranny = false;
- char *pext=strrchr(name,'.'); //find file extension
- if (pext)
- isGranny=(strnicmp(pext,".GR2",4) == 0);
- #endif
- Bool reallyscale = (WWMath::Fabs(scale - ident_scale) > scale_epsilon);
- Bool reallycolor = (color & 0xFFFFFF) != 0; //black is not a valid color and assumes no custom coloring.
- Bool reallytexture = (oldTexture != NULL && newTexture != NULL);
- // base case, no scale or color
- if (!reallyscale && !reallycolor && !reallytexture)
- {
- RenderObjClass *robj=WW3DAssetManager::Create_Render_Obj(name);
- #ifdef DUMP_PERF_STATS
- GetPrecisionTimer(&endTime64);
- Total_Create_Render_Obj_Time += endTime64-startTime64;
- #endif
- return robj;
- }
- char newname[512];
- Munge_Render_Obj_Name(newname, name, scale, color, newTexture);
- // see if we got a cached version
- RenderObjClass *rendobj = NULL;
- #ifdef INCLUDE_GRANNY_IN_BUILD
- if (isGranny)
- { //Granny objects share the same prototype since they allow instance scaling.
- strcpy(newname,name); //use same name for all granny objects at any scale.
- }
- #endif
- Set_WW3D_Load_On_Demand(false); // munged name will never be found in a file.
- rendobj = WW3DAssetManager::Create_Render_Obj(newname);
- if (rendobj)
- { //store the color that we used to create asset so we can read it back out
- //when we need to save this render object to a file. Used during saving
- //of fog of war ghost objects.
- rendobj->Set_ObjectColor(color);
- #ifdef INCLUDE_GRANNY_IN_BUILD
- if (isGranny)
- ///@todo Granny objects are realtime scaled - fix to scale like W3D.
- rendobj->Set_ObjectScale(scale);
- #endif
- Set_WW3D_Load_On_Demand(true); // Auto Load.
- #ifdef DUMP_PERF_STATS
- GetPrecisionTimer(&endTime64);
- Total_Create_Render_Obj_Time += endTime64-startTime64;
- #endif
- return rendobj;
- }
- // create a new one based on exisiting prototype
- WWPROFILE( "WW3DAssetManager::Create_Render_Obj" );
- WWMEMLOG(MEM_GEOMETRY);
- // Try to find a prototype
- PrototypeClass * proto = Find_Prototype(name);
- Set_WW3D_Load_On_Demand(true); // Auto Load.
- if (WW3D_Load_On_Demand && proto == NULL)
- {
- // If we didn't find one, try to load on demand
- char filename [MAX_PATH];
- char *mesh_name = ::strchr (name, '.');
- if (mesh_name != NULL)
- {
- ::lstrcpyn(filename, name, ((int)mesh_name) - ((int)name) + 1);
- #ifdef INCLUDE_GRANNY_IN_BUILD
- if (isGranny)
- ::lstrcat(filename, ".gr2");
- else
- #endif
- ::lstrcat(filename, ".w3d");
- } else {
- sprintf( filename, "%s.w3d", name);
- }
- // If we can't find it, try the parent directory
- if ( Load_3D_Assets( filename ) == false )
- {
- StringClass new_filename = StringClass("..\\") + filename;
- if (Load_3D_Assets( new_filename ) == false)
- {
- #ifdef INCLUDE_GRANNY_IN_BUILD
- char *mesh_name = ::strchr (filename, '.');
- ::lstrcpyn (mesh_name, ".gr2",5);
- Load_3D_Assets( filename );
- isGranny=true;
- #endif
- }
- }
- proto = Find_Prototype(name); // try again
- }
- if (proto == NULL)
- {
- static int warning_count = 0;
- if (++warning_count <= 20)
- {
- WWDEBUG_SAY(("WARNING: Failed to create Render Object: %s\r\n",name));
- }
- #ifdef DUMP_PERF_STATS
- GetPrecisionTimer(&endTime64);
- Total_Create_Render_Obj_Time += endTime64-startTime64;
- #endif
- return NULL; // Failed to find a prototype
- }
- rendobj = proto->Create();
- if (!rendobj)
- {
- #ifdef DUMP_PERF_STATS
- GetPrecisionTimer(&endTime64);
- Total_Create_Render_Obj_Time += endTime64-startTime64;
- #endif
- return NULL;
- }
- #ifdef INCLUDE_GRANNY_IN_BUILD
- if (!isGranny)
- #endif
- {
- Make_Unique(rendobj,reallyscale,reallycolor);
- if (reallytexture)
- {
- TextureClass *oldTex = Get_Texture(oldTexture);
- TextureClass *newTex = Get_Texture(newTexture);
- replaceAssetTexture(rendobj,oldTex,newTex);
- REF_PTR_RELEASE(newTex);
- REF_PTR_RELEASE(oldTex);
- }
- if (reallyscale)
- rendobj->Scale(scale);
- if (reallycolor)
- Recolor_Asset(rendobj,color);
- }
- #ifdef INCLUDE_GRANNY_IN_BUILD
- else
- {
- ///@todo Granny objects are realtime scaled - fix to scale like W3D.
- rendobj->Set_ObjectScale(scale);
- return rendobj;
- }
- #endif
- W3DPrototypeClass *w3dproto = newInstance(W3DPrototypeClass)(rendobj, newname);
- rendobj->Release_Ref();
- Add_Prototype(w3dproto);
- rendobj = w3dproto->Create();
- rendobj->Set_ObjectColor(color);
- #ifdef DUMP_PERF_STATS
- GetPrecisionTimer(&endTime64);
- Total_Create_Render_Obj_Time += endTime64-startTime64;
- #endif
- return rendobj;
- }
- //---------------------------------------------------------------------
- /** Generals specific code to generate customized render objects for each team color
- */
- int W3DAssetManager::Recolor_Asset(RenderObjClass *robj, const int color)
- {
- switch (robj->Class_ID()) {
- case RenderObjClass::CLASSID_MESH:
- return Recolor_Mesh(robj,color);
- break;
- case RenderObjClass::CLASSID_HLOD:
- return Recolor_HLOD(robj,color);
- break;
- }
- return 0;
- }
- //---------------------------------------------------------------------
- /** Generals specific code to generate customized render objects for each team color
- */
- int W3DAssetManager::Recolor_Mesh(RenderObjClass *robj, const int color)
- {
- int i;
- int didRecolor=0;
- const char *meshName;
- MeshClass *mesh=(MeshClass*) robj;
- MeshModelClass * model = mesh->Get_Model();
- MaterialInfoClass *material = mesh->Get_Material_Info();
- // recolor vertex material (assuming mesh is housecolor)
- if ( (( (meshName=strchr(mesh->Get_Name(),'.') ) != 0 && *(meshName++)) || ( (meshName=mesh->Get_Name()) != NULL)) &&
- _strnicmp(meshName,"HOUSECOLOR", 10) == 0)
- { for (i=0; i<material->Vertex_Material_Count(); i++)
- Recolor_Vertex_Material(material->Peek_Vertex_Material(i),color);
- didRecolor=1;
- }
- // recolor textures
- TextureClass *newtex,*oldtex;
- for (i=0; i<material->Texture_Count(); i++)
- {
- oldtex=material->Peek_Texture(i);
- if (_strnicmp(oldtex->Get_Texture_Name(),"ZHC", 3) == 0)
- { //This texture needs to be adjusted for housecolor
- newtex=Recolor_Texture(oldtex,color);
- if (newtex)
- {
- model->Replace_Texture(oldtex,newtex);
- material->Replace_Texture(i,newtex);
- REF_PTR_RELEASE(newtex);
- didRecolor=1;
- }
- }
- }
- REF_PTR_RELEASE(material);
- REF_PTR_RELEASE(model);
- return didRecolor;
- }
- //---------------------------------------------------------------------
- /** Generals specific code to generate customized render objects for each team color
- */
- int W3DAssetManager::Recolor_HLOD(RenderObjClass *robj, const int color)
- {
- int didRecolor=0;
- int num_sub = robj->Get_Num_Sub_Objects();
- for(int i = 0; i < num_sub; i++) {
- RenderObjClass *sub_obj = robj->Get_Sub_Object(i);
- didRecolor |= Recolor_Asset(sub_obj,color);
- REF_PTR_RELEASE(sub_obj);
- }
- return didRecolor;
- }
- //---------------------------------------------------------------------
- /** Generals specific code to generate customized render objects for each team color
- */
- void W3DAssetManager::Recolor_Vertex_Material(VertexMaterialClass *vmat, const int color)
- {
- Vector3 rgb,rgb2;
- rgb.X = (Real)((color >> 16) & 0xff )/255.0f;
- rgb.Y = (Real)((color >> 8) & 0xff )/255.0f;
- rgb.Z = (Real)(color & 0xff)/255.0f;
- //We ignore the existing ambinent/diffuse and assume they were 1.0. We can change
- //to scaling them if required.
- // vmat->Get_Ambient(&rgb2);
- // Recolor(rgb,hsv_shift);
- rgb2.X = rgb.X; //scale colors
- rgb2.Y = rgb.Y; //scale colors
- rgb2.Z = rgb.Z; //scale colors
- vmat->Set_Ambient(rgb2);
- // vmat->Get_Diffuse(&rgb2);
- // Recolor(rgb,hsv_shift);
- rgb2.X = rgb.X; //scale colors
- rgb2.Y = rgb.Y; //scale colors
- rgb2.Z = rgb.Z; //scale colors
- vmat->Set_Diffuse(rgb2);
- }
- #ifdef DUMP_PERF_STATS
- __int64 Total_Load_3D_Assets=0;
- static Load_3D_Asset_Recursions=0;
- #endif
- //---------------------------------------------------------------------
- bool W3DAssetManager::Load_3D_Assets( const char * filename )
- {
- #ifdef DUMP_PERF_STATS
- Load_3D_Asset_Recursions++;
- __int64 startTime64,endTime64;
- GetPrecisionTimer(&startTime64);
- #endif
- #ifdef INCLUDE_GRANNY_IN_BUILD
- Bool isGranny = false;
- char *pext=strrchr(filename,'.'); //find file extension
- if (pext)
- isGranny=(strnicmp(pext,".GR2",4) == 0);
- if (!isGranny)
- #endif
- // Try to find an existing prototype
- char basename[512];
- strcpy(basename, filename);
- char *pext = strrchr(basename, '.'); //find file extension
- if (pext)
- *pext = '\0'; //drop the extension
- PrototypeClass * proto = Find_Prototype(basename);
- if (proto)
- {
- #ifdef DUMP_PERF_STATS
- if (Load_3D_Asset_Recursions == 1)
- { GetPrecisionTimer(&endTime64);
- Total_Load_3D_Assets += endTime64-startTime64;
- }
- Load_3D_Asset_Recursions--;
- #endif
- return TRUE; //this file has already been loaded.
- }
- bool result = WW3DAssetManager::Load_3D_Assets(filename);
- #if defined(_DEBUG) || defined(_INTERNAL)
- if (result && TheGlobalData->m_preloadReport)
- {
- //loading a new asset and app is requesting a log of all loaded assets.
- FILE *logfile=fopen("PreloadedAssets.txt","a+"); //append to log
- if (logfile)
- {
- StringClass lower_case_name(filename,true);
- _strlwr(lower_case_name.Peek_Buffer());
- fprintf(logfile,"3D: %s\n",lower_case_name.Peek_Buffer());
- fclose(logfile);
- }
- }
- #endif
- #ifdef DUMP_PERF_STATS
- if (Load_3D_Asset_Recursions == 1)
- { GetPrecisionTimer(&endTime64);
- Total_Load_3D_Assets += endTime64-startTime64;
- }
- Load_3D_Asset_Recursions--;
- #endif
- return result;
- #ifdef INCLUDE_GRANNY_IN_BUILD
- //Loading assets for Granny File
- PrototypeClass * newproto = NULL;
- newproto = _GrannyLoader.Load_W3D(filename);
- /*
- ** Now, see if the prototype that we loaded has a duplicate
- ** name with any of our currently loaded prototypes (can't have that!)
- */
- if (newproto != NULL) {
- if (!Render_Obj_Exists(newproto->Get_Name())) {
- /*
- ** Add the new, unique prototype to our list
- */
- Add_Prototype(newproto);
- } else {
- /*
- ** Warn the user about a name collision with this prototype
- ** and dump it
- */
- WWDEBUG_SAY(("Render Object Name Collision: %s\r\n",newproto->Get_Name()));
- delete newproto;
- newproto = NULL;
- return false;
- }
- } else {
- /*
- ** Warn user that a prototype was not generated from this
- ** chunk type
- */
- WWDEBUG_SAY(("Could not generate Granny prototype! File = %d\r\n",filename));
- return false;
- }
- return true;
- #endif
- }
- #ifdef DUMP_PERF_STATS
- __int64 Total_Get_HAnim_Time=0;
- static HAnim_Recursions=0;
- #endif
- //---------------------------------------------------------------------
- HAnimClass * W3DAssetManager::Get_HAnim(const char * name)
- {
- #ifdef DUMP_PERF_STATS
- HAnim_Recursions++;
- __int64 startTime64,endTime64;
- GetPrecisionTimer(&startTime64);
- #endif
- WWPROFILE( "WW3DAssetManager::Get_HAnim" );
- #ifdef INCLUDE_GRANNY_IN_BUILD
- Bool isGranny = false;
- char *pext=strrchr(name,'.'); //find file extension
- if (pext)
- isGranny=(strnicmp(pext,".GR2",4) == 0);
- if (!isGranny)
- #endif
- {
- HAnimClass *anim=WW3DAssetManager::Get_HAnim(name); //we only do custom granny processing.
- #ifdef DUMP_PERF_STATS
- if (HAnim_Recursions == 1)
- {
- GetPrecisionTimer(&endTime64);
- Total_Get_HAnim_Time += endTime64-startTime64;
- }
- HAnim_Recursions--;
- #endif
- return anim;
- }
- #ifdef INCLUDE_GRANNY_IN_BUILD
- // Try to find the hanim
- HAnimClass * anim = m_GrannyAnimManager->Get_Anim(name);
- if (WW3D_Load_On_Demand && anim == NULL) { // If we didn't find it, try to load on demand
- if ( !m_GrannyAnimManager->Is_Missing( name ) ) { // if this is NOT a known missing anim
- // If we can't find it, try the parent directory
- if ( m_GrannyAnimManager->Load_Anim(name) == 1 ) {
- StringClass new_filename = StringClass("..\\") + name;
- m_GrannyAnimManager->Load_Anim( new_filename );
- }
- anim = m_GrannyAnimManager->Get_Anim(name); // Try again
- if (anim == NULL) {
- // WWDEBUG_SAY(("WARNING: Animation %s not found!\n", name));
- m_GrannyAnimManager->Register_Missing( name ); // This is now a KNOWN missing anim
- }
- }
- }
- return anim;
- #endif
- }
- //---------------------------------------------------------------------
- // Uniqing
- //---------------------------------------------------------------------
- //---------------------------------------------------------------------
- /** Generals specific code to generate customized render objects for each team color
- */
- void W3DAssetManager::Make_HLOD_Unique(RenderObjClass *robj, Bool geometry, Bool colors)
- {
- int num_sub = robj->Get_Num_Sub_Objects();
- for(int i = 0; i < num_sub; i++) {
- RenderObjClass *sub_obj = robj->Get_Sub_Object(i);
- Make_Unique(sub_obj, geometry, colors);
- REF_PTR_RELEASE(sub_obj);
- }
- }
- //---------------------------------------------------------------------
- /** Generals specific code to generate customized render objects for each team color
- */
- void W3DAssetManager::Make_Unique(RenderObjClass *robj, Bool geometry, Bool colors)
- {
- switch (robj->Class_ID()) {
- case RenderObjClass::CLASSID_MESH:
- Make_Mesh_Unique(robj,geometry,colors);
- break;
- case RenderObjClass::CLASSID_HLOD:
- Make_HLOD_Unique(robj,geometry,colors);
- break;
- }
- }
- //---------------------------------------------------------------------
- /** Determine what method is used to apply house color to this mesh (if any) */
- static Bool getMeshColorMethods(MeshClass *mesh, Bool &vertexColor, Bool &textureColor)
- {
- vertexColor = false;
- textureColor = false;
- //Check if mesh is using custom texture containing house color
- MaterialInfoClass *material = mesh->Get_Material_Info();
- if (material)
- { for (int j=0; j<material->Texture_Count(); j++)
- if (_strnicmp(material->Peek_Texture(j)->Get_Texture_Name(),"ZHC",3) == 0)
- { textureColor = true;
- break;
- }
- REF_PTR_RELEASE(material);
- }
- //Check if mesh is using a custom mesh which contains house color in material.
- //Meshes which are part of another model have names in the form "name.name" while
- //isolated meshes are just "name". We check for both starting with "HOUSECOLOR".
- const char *meshName;
- if ( ( (meshName=strchr(mesh->Get_Name(),'.') ) != 0 && *(meshName++)) || ( (meshName=mesh->Get_Name()) != NULL) )
- { //Check if this object has housecolors on mesh
- if ( _strnicmp(meshName,"HOUSECOLOR", 10) == 0)
- vertexColor = true;
- }
- return (vertexColor || textureColor);
- }
- //---------------------------------------------------------------------
- /** Generals specific code to generate customized render objects for each team color
- */
- void W3DAssetManager::Make_Mesh_Unique(RenderObjClass *robj, Bool geometry, Bool colors)
- {
- int i;
- MeshClass *mesh=(MeshClass*) robj;
- Bool isVertexColor, isTextureColor;
- //figure out what type of coloring this mesh requires (if any)
- if ((colors && getMeshColorMethods(mesh,isVertexColor,isTextureColor)) || geometry)
- { //mesh has some house color applied so make those components unique to mesh.
- //Create unique data for this mesh
- mesh->Make_Unique();
-
- MeshModelClass * model = mesh->Get_Model();
- if (colors && isVertexColor)
- {
- MaterialInfoClass *material=mesh->Get_Material_Info();
- for (i=0; i<material->Vertex_Material_Count(); i++)
- material->Peek_Vertex_Material(i)->Make_Unique();
- REF_PTR_RELEASE(material);
- }
- if (geometry)
- {
- // make geometry unique
- model->Make_Geometry_Unique();
- }
- REF_PTR_RELEASE(model);
- }
- }
- //---------------------------------------------------------------------
- /**Report prototypes that have all assets with reference count
- equal to 1*/
- void W3DAssetManager::Report_Used_Prototypes(void)
- {
- int count = Prototypes.Count();
- while (count-- > 0) {
- PrototypeClass * proto = Prototypes[count];
- if (proto->Get_Class_ID() == RenderObjClass::CLASSID_HLOD || proto->Get_Class_ID() == RenderObjClass::CLASSID_MESH)
- {
- DEBUG_LOG(("**Unfreed Prototype On Map Reset: %s\n",proto->Get_Name()));
- }
- }
- }
- //---------------------------------------------------------------------
- /**Report any assets with reference counts > 1. This means they are still
- referenced by something besides the asset manager.*/
- void W3DAssetManager::Report_Used_Assets(void)
- {
- Report_Used_Prototypes();
- ///@todo: Report unfreed skeletons and animations
- // HAnimManager.Free_All_Anims();
- // HTreeManager.Free_All_Trees();
- Report_Used_Textures();
- Report_Used_Font3DDatas();
- Report_Used_FontChars();
- }
- //---------------------------------------------------------------------
- void W3DAssetManager::Report_Used_FontChars(void)
- {
- Int count=FontCharsList.Count();
- while (count-- > 0)
- {
- if (FontCharsList[count]->Num_Refs() >= 1)
- {
- DEBUG_LOG(("**Unfreed FontChar On Map Reset: %s\n",FontCharsList[count]->Get_Name()));
- //FontCharsList[count]->Release_Ref();
- //FontCharsList.Delete(count);
- }
- }
- }
- //---------------------------------------------------------------------
- /**Report all textures with refcounts >= 1*/
- void W3DAssetManager::Report_Used_Textures(void)
- {
- /*
- ** for each texture in the list, get it, check it's refcount, and and release ref it if the
- ** refcount is one.
- */
- // unsigned count=0;
- // TextureClass* temp_textures[256];
- HashTemplateIterator<StringClass,TextureClass*> ite(TextureHash);
- for (ite.First();!ite.Is_Done();ite.Next()) {
- TextureClass* tex=ite.Peek_Value();
- if (tex->Num_Refs() <= 1) {
- /* temp_textures[count++]=tex;
- if (count==256) {
- for (unsigned i=0;i<256;++i) {
- TextureHash.Remove(temp_textures[i]->Get_Texture_Name());
- temp_textures[i]->Release_Ref();
- }
- count=0;
- ite.First(); // iterator doesn't support modifying the hash table while iterating, so start from the
- // beginning.
- }*/
- }
- else
- {
- DEBUG_LOG(("**Texture \"%s\" referenced %d times on map reset\n",tex->Get_Texture_Name(),tex->Num_Refs()-1));
- }
- }
- /* for (unsigned i=0;i<count;++i) {
- TextureHash.Remove(temp_textures[i]->Get_Texture_Name());
- temp_textures[i]->Release_Ref();
- }*/
- }
- //---------------------------------------------------------------------
- /**Report all used fonts*/
- void W3DAssetManager::Report_Used_Font3DDatas( void )
- {
- /*
- ** for each font data in the list, get it, check it's refcount, and and release ref it if the
- ** refcount is one.
- */
- SLNode<Font3DDataClass> *node, * next;
- for ( node = Font3DDatas.Head(); node; node = next) {
- next = node->Next();
- Font3DDataClass *font = node->Data();
- if (font->Num_Refs() == 1) {
- /* Font3DDatas.Remove(font);
- font->Release_Ref();*/
- }
- else
- {
- DEBUG_LOG(("**Unfreed Font3DDatas On Map Reset: %s\n",font->Name));
- }
- }
- }
- //---------------------------------------------------------------------
- // E&B Coloring Code
- //---------------------------------------------------------------------
- /*
- //---------------------------------------------------------------------
- // Uniqing
- //---------------------------------------------------------------------
- void W3DAssetManager::Make_Mesh_Unique(RenderObjClass *robj, Bool geometry, Bool colors)
- {
- int i;
- MeshClass *mesh=(MeshClass*) robj;
- mesh->Make_Unique();
- MeshModelClass * model = mesh->Get_Model();
- if (colors) {
- // make all vertex materials unique
- MaterialInfoClass *material = mesh->Get_Material_Info();
- for (i=0; i<material->Vertex_Material_Count(); i++)
- material->Peek_Vertex_Material(i)->Make_Unique();
- REF_PTR_RELEASE(material);
- // make all color arrays unique
- model->Make_Color_Array_Unique(0);
- model->Make_Color_Array_Unique(1);
- // do not do textures yet
- // because we want to do the color conversion
- // for the top mip level and then
- // mip filter instead of converting all mip levels
- }
-
- if (geometry) {
- // make geometry unique
- model->Make_Geometry_Unique();
- }
- REF_PTR_RELEASE(model);
- }
- void W3DAssetManager::Make_HLOD_Unique(RenderObjClass *robj, Bool geometry, Bool colors)
- {
- int num_sub = robj->Get_Num_Sub_Objects();
- for(int i = 0; i < num_sub; i++) {
- RenderObjClass *sub_obj = robj->Get_Sub_Object(i);
- Make_Unique(sub_obj,geometry,colors);
- REF_PTR_RELEASE(sub_obj);
- }
- }
- void W3DAssetManager::Make_Unique(RenderObjClass *robj, Bool geometry, Bool colors)
- {
- switch (robj->Class_ID()) {
- case RenderObjClass::CLASSID_MESH:
- Make_Mesh_Unique(robj,geometry,colors);
- break;
- case RenderObjClass::CLASSID_HLOD:
- Make_HLOD_Unique(robj,geometry,colors);
- break;
- }
- }
- static inline void Munge_Render_Obj_Name(char *newname, const char *oldname, float scale, const Vector3 &hsv_shift)
- {
- char lower_case_name[255];
- strcpy(lower_case_name, oldname);
- _strlwr(lower_case_name);
- sprintf(newname,"#%s!%gH%gS%gV%g", lower_case_name, scale, hsv_shift.X, hsv_shift.Y, hsv_shift.Z);
- }
- static inline void Munge_Texture_Name(char *newname, const char *oldname, const Vector3 &hsv_shift)
- {
- char lower_case_name[255];
- strcpy(lower_case_name, oldname);
- _strlwr(lower_case_name);
- sprintf(newname,"#%s!H%gS%gV%g", lower_case_name, hsv_shift.X, hsv_shift.Y, hsv_shift.Z);
- }
- RenderObjClass * W3DAssetManager::Create_Render_Obj(const char * name,float scale, const Vector3 &hsv_shift)
- {
- Bool isGranny = false;
- #ifdef INCLUDE_GRANNY_IN_BUILD
- char *pext=strrchr(name,'.'); //find file extension
- if (pext)
- isGranny=(strnicmp(pext,".GR2",4) == 0);
- #endif
- Bool reallyscale = (WWMath::Fabs(scale - ident_scale) > scale_epsilon);
- Bool reallyhsv_shift = (WWMath::Fabs(hsv_shift.X - ident_HSV.X) > H_epsilon ||
- WWMath::Fabs(hsv_shift.Y - ident_HSV.Y) > S_epsilon || WWMath::Fabs(hsv_shift.Z - ident_HSV.Z) > V_epsilon);
- // base case, no scale or hue shifting
- if (!reallyscale && !reallyhsv_shift) return WW3DAssetManager::Create_Render_Obj(name);
- char newname[512];
- Munge_Render_Obj_Name(newname, name, scale, hsv_shift);
- // see if we got a cached version
- RenderObjClass *rendobj=NULL;
- if (isGranny)
- { //Granny objects share the same prototype since they allow instance scaling.
- strcpy(newname,name); //use same name for all granny objects at any scale.
- }
- Set_WW3D_Load_On_Demand(false); // munged name will never be found in a file.
- rendobj=WW3DAssetManager::Create_Render_Obj(newname);
- if (rendobj)
- { if (isGranny)
- ///@todo Granny objects are realtime scaled - fix to scale like W3D.
- rendobj->Set_ObjectScale(scale);
- Set_WW3D_Load_On_Demand(true); // Auto Load.
- return rendobj;
- }
- // create a new one based on
- // exisiting prototype
- WWPROFILE( "WW3DAssetManager::Create_Render_Obj" );
- WWMEMLOG(MEM_GEOMETRY);
- // Try to find a prototype
- PrototypeClass * proto = Find_Prototype(name);
- Set_WW3D_Load_On_Demand(true); // Auto Load.
- if (WW3D_Load_On_Demand && proto == NULL) { // If we didn't find one, try to load on demand
- char filename [MAX_PATH];
- char *mesh_name = ::strchr (name, '.');
- if (mesh_name != NULL) {
- ::lstrcpyn (filename, name, ((int)mesh_name) - ((int)name) + 1);
- if (isGranny)
- ::lstrcat (filename, ".gr2");
- else
- ::lstrcat (filename, ".w3d");
- } else {
- sprintf( filename, "%s.w3d", name);
- }
- // If we can't find it, try the parent directory
- if ( Load_3D_Assets( filename ) == false ) {
- StringClass new_filename = StringClass("..\\") + filename;
- if (Load_3D_Assets( new_filename ) == false)
- {
- char *mesh_name = ::strchr (filename, '.');
- ::lstrcpyn (mesh_name, ".gr2",5);
- Load_3D_Assets( filename );
- isGranny=true;
- }
- }
- proto = Find_Prototype(name); // try again
- }
- if (proto == NULL) {
- static int warning_count = 0;
- if (++warning_count <= 20) {
- WWDEBUG_SAY(("WARNING: Failed to create Render Object: %s\r\n",name));
- }
- return NULL; // Failed to find a prototype
- }
- rendobj=proto->Create();
- if (!rendobj) return NULL;
-
- if (!isGranny)
- { Make_Unique(rendobj,reallyscale,reallyhsv_shift);
- if (reallyscale) rendobj->Scale(scale);
- if (reallyhsv_shift) Recolor_Asset(rendobj,hsv_shift);
- }
- else
- { ///@todo Granny objects are realtime scaled - fix to scale like W3D.
- rendobj->Set_ObjectScale(scale);
- return rendobj;
- }
- W3DPrototypeClass *w3dproto=NEW W3DPrototypeClass(rendobj,newname);
- rendobj->Release_Ref();
- Add_Prototype(w3dproto);
- return w3dproto->Create();
- }
- TextureClass * W3DAssetManager::Get_Texture_With_HSV_Shift(const char * filename, const Vector3 &hsv_shift, TextureClass::MipCountType mip_level_count)
- {
- WWPROFILE( "W3DAssetManager::Get_Texture with HSV shift" );
- Bool is_hsv_shift = (WWMath::Fabs(hsv_shift.X - ident_HSV.X) > H_epsilon ||
- WWMath::Fabs(hsv_shift.Y - ident_HSV.Y) > S_epsilon || WWMath::Fabs(hsv_shift.Z - ident_HSV.Z) > V_epsilon);
- if (!is_hsv_shift) {
- return Get_Texture(filename, mip_level_count);
- } else {
- //
- // Bail if the user isn't really asking for anything
- //
- if ((filename == NULL) || (strlen(filename) == 0)) {
- return NULL;
- }
- TextureClass *newtex = Find_Texture(filename, hsv_shift);
- if (!newtex) {
-
- // No cached texture - need to create
- char lower_case_name[255];
- strcpy(lower_case_name, filename);
- _strlwr(lower_case_name);
- TextureClass *oldtex = TextureHash.Get(lower_case_name);
- if (!oldtex) {
- oldtex = NEW_REF(TextureClass,(lower_case_name, NULL, mip_level_count));
- TextureHash.Insert(oldtex->Get_Texture_Name(), oldtex);
- }
- newtex = Recolor_Texture_One_Time(oldtex, hsv_shift);
- // If the recolorization failed, return the original texture
- if (!newtex) {
- newtex = oldtex;
- newtex->Add_Ref();
- }
- }
- return newtex;
- }
- }
- void W3DAssetManager::Recolor_Vertex_Material(VertexMaterialClass *vmat, const Vector3 &hsv_shift)
- {
- Vector3 rgb;
- vmat->Get_Ambient(&rgb);
- Recolor(rgb,hsv_shift);
- vmat->Set_Ambient(rgb);
- vmat->Get_Diffuse(&rgb);
- Recolor(rgb,hsv_shift);
- vmat->Set_Diffuse(rgb);
- vmat->Get_Emissive(&rgb);
- Recolor(rgb,hsv_shift);
- vmat->Set_Emissive(rgb);
- vmat->Get_Specular(&rgb);
- Recolor(rgb,hsv_shift);
- vmat->Set_Specular(rgb);
- }
- void W3DAssetManager::Recolor_Vertices(unsigned int *color, int count, const Vector3 &hsv_shift)
- {
- int i;
- Vector4 rgba;
- for (i=0; i<count; i++)
- {
- rgba=DX8Wrapper::Convert_Color(color[i]);
- Recolor(reinterpret_cast<Vector3&>(rgba),hsv_shift);
- color[i]=DX8Wrapper::Convert_Color_Clamp(rgba);
- }
- }
- TextureClass * W3DAssetManager::Recolor_Texture(TextureClass *texture, const Vector3 &hsv_shift)
- {
- const char *name=texture->Get_Texture_Name();
- TextureClass *newtex = Find_Texture(name, hsv_shift);
- if (newtex) {
- return newtex;
- }
- return Recolor_Texture_One_Time(texture, hsv_shift);
- }
- TextureClass * W3DAssetManager::Recolor_Texture_One_Time(TextureClass *texture, const Vector3 &hsv_shift)
- {
- const char *name=texture->Get_Texture_Name();
- // if texture is procedural return NULL
- if (name && name[0]=='!') return NULL;
- // make sure texture is loaded
- if (!texture->Is_Initialized())
- TextureLoader::Request_High_Priority_Loading(texture, (TextureClass::MipCountType)texture->Get_Mip_Level_Count());
- SurfaceClass::SurfaceDescription desc;
- SurfaceClass *newsurf, *oldsurf, *smallsurf;
- texture->Get_Level_Description(desc);
- // if texture is monochrome and no value shifting
- // return NULL
- smallsurf=texture->Get_Surface_Level((TextureClass::MipCountType)texture->Get_Mip_Level_Count()-1);
- if (hsv_shift.Z==0.0f && smallsurf->Is_Monochrome())
- {
- REF_PTR_RELEASE(smallsurf);
- return NULL;
- }
- REF_PTR_RELEASE(smallsurf);
- oldsurf=texture->Get_Surface_Level();
- newsurf=NEW_REF(SurfaceClass,(desc.Width,desc.Height,desc.Format));
- newsurf->Copy(0,0,0,0,desc.Width,desc.Height,oldsurf);
- newsurf->Hue_Shift(hsv_shift);
- TextureClass * newtex=NEW_REF(TextureClass,(newsurf,(TextureClass::MipCountType)texture->Get_Mip_Level_Count()));
- newtex->Set_Mag_Filter(texture->Get_Mag_Filter());
- newtex->Set_Min_Filter(texture->Get_Min_Filter());
- newtex->Set_Mip_Mapping(texture->Get_Mip_Mapping());
- newtex->Set_U_Addr_Mode(texture->Get_U_Addr_Mode());
- newtex->Set_V_Addr_Mode(texture->Get_V_Addr_Mode());
- char newname[512];
- Munge_Texture_Name(newname, name, hsv_shift);
- newtex->Set_Texture_Name(newname);
- TextureHash.Insert(newtex->Get_Texture_Name(), newtex);
- newtex->Add_Ref();
- REF_PTR_RELEASE(oldsurf);
- REF_PTR_RELEASE(newsurf);
- return newtex;
- }
- TextureClass * W3DAssetManager::Find_Texture(const char * name, const Vector3 &hsv_shift)
- {
- char newname[512];
- Munge_Texture_Name(newname, name, hsv_shift);
- // see if we have a cached copy
- TextureClass *newtex = TextureHash.Get(newname);
- if (newtex) {
- newtex->Add_Ref();
- }
- return newtex;
- }
- void W3DAssetManager::Recolor_Mesh(RenderObjClass *robj, const Vector3 &hsv_shift)
- {
- int i;
- MeshClass *mesh=(MeshClass*) robj;
- MeshModelClass * model = mesh->Get_Model();
- MaterialInfoClass *material = mesh->Get_Material_Info();
- // recolor vertex material
- for (i=0; i<material->Vertex_Material_Count(); i++)
- Recolor_Vertex_Material(material->Peek_Vertex_Material(i),hsv_shift);
- // recolor color arrays
- unsigned int * color;
- color=model->Get_Color_Array(0,false);
- if (color) Recolor_Vertices(color,model->Get_Vertex_Count(),hsv_shift);
- color=model->Get_Color_Array(1,false);
- if (color) Recolor_Vertices(color,model->Get_Vertex_Count(),hsv_shift);
- // recolor textures
- TextureClass *newtex,*oldtex;
- for (i=0; i<material->Texture_Count(); i++)
- {
- oldtex=material->Peek_Texture(i);
- newtex=Recolor_Texture(oldtex,hsv_shift);
- if (newtex)
- {
- model->Replace_Texture(oldtex,newtex);
- material->Replace_Texture(i,newtex);
- REF_PTR_RELEASE(newtex);
- }
- }
- REF_PTR_RELEASE(material);
- REF_PTR_RELEASE(model);
- }
- void W3DAssetManager::Recolor_HLOD(RenderObjClass *robj, const Vector3 &hsv_shift)
- {
- int num_sub = robj->Get_Num_Sub_Objects();
- for(int i = 0; i < num_sub; i++) {
- RenderObjClass *sub_obj = robj->Get_Sub_Object(i);
- Recolor_Asset(sub_obj,hsv_shift);
- REF_PTR_RELEASE(sub_obj);
- }
- }
- void W3DAssetManager::Recolor_ParticleEmitter(RenderObjClass *robj, const Vector3 &hsv_shift)
- {
- unsigned int i;
- ParticleEmitterClass* emit=(ParticleEmitterClass*) robj;
- ParticlePropertyStruct<Vector3> colors;
- emit->Get_Color_Key_Frames(colors);
- Recolor(colors.Start,hsv_shift);
- Recolor(colors.Rand,hsv_shift);
- for (i=0; i<colors.NumKeyFrames; i++)
- Recolor(colors.Values[i],hsv_shift);
- emit->Reset_Colors(colors);
- delete colors.Values;
- delete colors.KeyTimes;
- TextureClass *tex=emit->Get_Texture();
- TextureClass *newtex=Recolor_Texture(tex,hsv_shift);
- if (newtex)
- {
- emit->Set_Texture(newtex);
- REF_PTR_RELEASE(newtex);
- }
- REF_PTR_RELEASE(tex);
- }
- void W3DAssetManager::Recolor_Asset(RenderObjClass *robj, const Vector3 &hsv_shift)
- {
- switch (robj->Class_ID()) {
- case RenderObjClass::CLASSID_MESH:
- Recolor_Mesh(robj,hsv_shift);
- break;
- case RenderObjClass::CLASSID_HLOD:
- Recolor_HLOD(robj,hsv_shift);
- break;
- case RenderObjClass::CLASSID_PARTICLEEMITTER:
- Recolor_ParticleEmitter(robj,hsv_shift);
- break;
- }
- }
- */
|