/* ** Command & Conquer Renegade(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 . */ /*********************************************************************************************** *** 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 : ENBAssetMgr * * * * $Archive:: /VSS_Sync/ww3d2/hueshift/enbassetmgr.cpp $* * * * Original Author:: Hector Yee * * * * $Author:: Vss_sync $* * * * $Modtime:: 8/29/01 10:35p $* * * * $Revision:: 1 $* * * *---------------------------------------------------------------------------------------------* * Functions: * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #include "always.h" #include "enbassetmgr.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 //--------------------------------------------------------------------- // Constants //--------------------------------------------------------------------- const float ident_scale(1.0f); const Vector3 ident_HSV(0,0,0); //--------------------------------------------------------------------- // ENBPrototype //--------------------------------------------------------------------- class ENBPrototypeClass : public PrototypeClass { public: ENBPrototypeClass(RenderObjClass * proto,const char* name); virtual ~ENBPrototypeClass(void); virtual const char * Get_Name(void) const; virtual int Get_Class_ID(void) const; virtual RenderObjClass * Create(void); RenderObjClass * Proto; char * Name; }; ENBPrototypeClass::ENBPrototypeClass(RenderObjClass * proto, const char *name) { Name=strdup(name); Proto = proto; assert(Proto); Proto->Add_Ref(); } ENBPrototypeClass::~ENBPrototypeClass(void) { delete [] Name; if (Proto) { Proto->Release_Ref(); } } const char * ENBPrototypeClass::Get_Name(void) const { return Name; } int ENBPrototypeClass::Get_Class_ID(void) const { return Proto->Class_ID(); } RenderObjClass * ENBPrototypeClass::Create(void) { return (RenderObjClass *)( SET_REF_OWNER( Proto->Clone() ) ); } //--------------------------------------------------------------------- // ENBAssetManager //--------------------------------------------------------------------- ENBAssetManager::ENBAssetManager(void) { } ENBAssetManager::~ENBAssetManager(void) { } RenderObjClass * ENBAssetManager::Create_Render_Obj(const char * name,float Scale,Vector3 &HSV_shift) { char newname[512]; bool scale,hsv_shift; scale=(Scale!=ident_scale); hsv_shift=(HSV_shift!=ident_HSV); // base case, no scale or hue shifting if (!scale && !hsv_shift) return WW3DAssetManager::Create_Render_Obj(name); sprintf(newname,"#%s!%gH%gS%gV%g",name,Scale,HSV_shift.X,HSV_shift.Y,HSV_shift.Z); // see if we got a cached version RenderObjClass *rendobj=NULL; rendobj=WW3DAssetManager::Create_Render_Obj(newname); if (rendobj) return rendobj; // create a new one based on // exisiting prototype rendobj=WW3DAssetManager::Create_Render_Obj(name); if (!rendobj) return NULL; Make_Unique(rendobj,scale,hsv_shift); if (scale) rendobj->Scale(Scale); if (hsv_shift) Recolor_Asset(rendobj,HSV_shift); ENBPrototypeClass *proto=new ENBPrototypeClass(rendobj,newname); Add_Prototype(proto); return rendobj; } //--------------------------------------------------------------------- // Uniqing //--------------------------------------------------------------------- void ENBAssetManager::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; iVertex_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 ENBAssetManager::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 ENBAssetManager::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; } } //--------------------------------------------------------------------- // Coloring //--------------------------------------------------------------------- void ENBAssetManager::Recolor_Vertex_Material(VertexMaterialClass *vmat,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 ENBAssetManager::Recolor_Vertices(unsigned int *color, int count, Vector3 &hsv_shift) { int i; Vector4 rgba; for (i=0; i(rgba),hsv_shift); color[i]=DX8Wrapper::Convert_Color_Clamp(rgba); } } TextureClass * ENBAssetManager::Recolor_Texture(TextureClass *texture, Vector3 &hsv_shift) { const char *name=texture->Get_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,0,(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(); // see if we have a cached copy char newname[512]; StringClass lower_case_name(texture->Get_Name(),true); _strlwr(lower_case_name.Peek_Buffer()); sprintf(newname,"#%s!H%gS%gV%g",lower_case_name,hsv_shift.X,hsv_shift.Y,hsv_shift.Z); TextureClass* newtex = TextureHash.Get(newname); if (newtex) { newtex->Add_Ref(); REF_PTR_RELEASE(oldsurf); return newtex; } // no cached copy, make new recolorized texture 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); 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_Name(newname); newtex->Set_U_Addr_Mode(texture->Get_U_Addr_Mode()); newtex->Set_V_Addr_Mode(texture->Get_V_Addr_Mode()); TextureHash.Insert(newname,newtex); newtex->Add_Ref(); REF_PTR_RELEASE(oldsurf); REF_PTR_RELEASE(newsurf); return newtex; } void ENBAssetManager::Recolor_Mesh(RenderObjClass *robj,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; iVertex_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; iTexture_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 ENBAssetManager::Recolor_HLOD(RenderObjClass *robj,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 ENBAssetManager::Recolor_ParticleEmitter(RenderObjClass *robj,Vector3 &hsv_shift) { unsigned int i; ParticleEmitterClass* emit=(ParticleEmitterClass*) robj; ParticlePropertyStruct colors; emit->Get_Color_Key_Frames(colors); Recolor(colors.Start,hsv_shift); Recolor(colors.Rand,hsv_shift); for (i=0; iReset_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 ENBAssetManager::Recolor_Asset(RenderObjClass *robj,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; } }