This repository has been archived on 2025-02-27. You can view files and clone it, but cannot push or open issues or pull requests.
CnC_Renegade/Code/ww3d2/hueshift/enbassetmgr.cpp

400 lines
12 KiB
C++
Raw Permalink Normal View History

/*
** 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 <http://www.gnu.org/licenses/>.
*/
/***********************************************************************************************
*** 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 <stdio.h>
//---------------------------------------------------------------------
// 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; 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 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<count; i++)
{
rgba=DX8Wrapper::Convert_Color(color[i]);
Recolor(reinterpret_cast<Vector3&>(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; 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 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<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 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;
}
}