| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396 |
- /*
- ** 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 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 : G *
- * *
- * $Archive:: /Commando/Code/ww3d2/metalmap.cpp $*
- * *
- * $Author:: Hector_y $*
- * *
- * $Modtime:: 6/27/01 4:59p $*
- * *
- * $Revision:: 3 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * MMMC::MetalMapManagerClass -- Create metal map manager according to given metal parameters*
- * MMMC::MetalMapManagerClass -- Create metal map manager from INI *
- * MMMC::~MetalMapManagerClass -- MetalMapManagerClass destructor *
- * MMMC::Get_Metal_Map -- Get the texture for a metal map by id number *
- * MMMC::Metal_Map_Count -- Get the number of metal maps in the manager *
- * MMMC::Update_Lighting -- Update the lighting parameters used for generating the maps *
- * MMMC::Update_Textures -- Update metal map textures (call once/frame before rendering) *
- * MMMC::initialize_normal_table -- Utility function to initialize the normal table *
- * MMMC::initialize_metal_params -- Utility function (shared CTor code) *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #include "metalmap.h"
- #include "texture.h"
- #include "ww3dformat.h"
- #include <vp.h>
- #include <ini.h>
- #include <point.h>
- #include <stdio.h>
- #include <hashtemplate.h>
- #include <wwstring.h>
- /*
- ** Class static members:
- */
- Vector3 * MetalMapManagerClass::_NormalTable = 0;
- /***********************************************************************************************
- * MMMC::MetalMapManagerClass -- Create metal map manager from INI *
- * *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 11/23/1999 NH : Created. *
- *=============================================================================================*/
- MetalMapManagerClass::MetalMapManagerClass(INIClass &ini) :
- MapCount(0),
- Textures(0),
- MetalParameters(0),
- CurrentAmbient(0.0f, 0.0f, 0.0f),
- CurrentMainLightColor(0.0f, 0.0f, 0.0f),
- CurrentMainLightDir(1.0f, 0.0f, 0.0f),
- CurrentCameraDir(1.0f,0.0f,0.0f)
- {
- // If the static normal table has not been initialized yet, initialize it
- if (!_NormalTable) {
- initialize_normal_table();
- }
- // Determine how many metals are in this file
- char section[255];
- for (int lp = 0; ; lp++) {
- sprintf(section, "Metal%02d", lp);
- if (!ini.Find_Section(section)) {
- break; // NAK - Mar 8, 2000: changed to a break to fix off by one error in lp
- }
- }
- if (lp > 0) {
- // Create metal params structs and fill from INI:
- MetalParams *metal_params = W3DNEWARRAY MetalParams[lp];
- TPoint3D<float> white_tpoint(255.0f, 255.0f, 255.0f);
- Vector3 white(1.0f, 1.0f, 1.0f);
- Vector3 black(0.0f, 0.0f, 0.0f);
- for (int i = 0; i < lp; i++) {
- sprintf(section, "Metal%02d", i);
- static const float cf = 0.003921568627451f; // 1 / 255
- TPoint3D<float> color;
- color = ini.Get_Point(section, "AmbientColor", white_tpoint);
- metal_params[i].AmbientColor.Set(color.X * cf, color.Y * cf, color.Z * cf);
- metal_params[i].AmbientColor.Update_Min(white);
- metal_params[i].AmbientColor.Update_Max(black);
- color = ini.Get_Point(section, "DiffuseColor", white_tpoint);
- metal_params[i].DiffuseColor.Set(color.X * cf, color.Y * cf, color.Z * cf);
- metal_params[i].AmbientColor.Update_Min(white);
- metal_params[i].AmbientColor.Update_Max(black);
- color = ini.Get_Point(section, "SpecularColor", white_tpoint);
- metal_params[i].SpecularColor.Set(color.X * cf, color.Y * cf, color.Z * cf);
- metal_params[i].AmbientColor.Update_Min(white);
- metal_params[i].AmbientColor.Update_Max(black);
- float shininess = ini.Get_Float(section, "Shininess", 0.0f);
- metal_params[i].Shininess = WWMath::Clamp(shininess, 0.0f, 127.0f);
- }
- initialize_metal_params(lp, metal_params);
- delete [] metal_params;
- } else {
- assert(0);
- }
- for (int i = 0; i < lp; i++) {
- // Create texture. NOTE: we should add code here to ensure we use a native texture format
- Textures[i]=NEW_REF(TextureClass,(METALMAP_SIZE,METALMAP_SIZE,WW3D_FORMAT_A8R8G8B8,TextureClass::MIP_LEVELS_1));
- Textures[i]->Set_U_Addr_Mode(TextureClass::TEXTURE_ADDRESS_CLAMP);
- Textures[i]->Set_V_Addr_Mode(TextureClass::TEXTURE_ADDRESS_CLAMP);
- StringClass tex_name;
- tex_name.Format("!m%02d.tga", i);
- Textures[i]->Set_Texture_Name(tex_name);
- }
- }
- /***********************************************************************************************
- * MMMC::~MetalMapManagerClass -- MetalMapManagerClass destructor *
- * *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 11/19/1999 NH : Created. *
- *=============================================================================================*/
- MetalMapManagerClass::~MetalMapManagerClass(void)
- {
- if (Textures) {
- for (int i = 0; i < MapCount; i++) {
- REF_PTR_RELEASE(Textures[i]);
- }
- delete [] Textures;
- Textures = 0;
- }
- if (MetalParameters) {
- delete [] MetalParameters;
- MetalParameters = 0;
- }
- }
- /***********************************************************************************************
- * MMMC::Get_Metal_Map -- Get the texture for a metal map by id number *
- * *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 11/19/1999 NH : Created. *
- *=============================================================================================*/
- TextureClass * MetalMapManagerClass::Get_Metal_Map(int id)
- {
- if (id < 0 || id >= MapCount) return 0;
- Textures[id]->Add_Ref();
- return Textures[id];
- }
- /***********************************************************************************************
- * MMMC::Metal_Map_Count -- Get the number of metal maps in the manager *
- * *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 11/19/1999 NH : Created. *
- *=============================================================================================*/
- int MetalMapManagerClass::Metal_Map_Count(void)
- {
- return MapCount;
- }
- /***********************************************************************************************
- * MMMC::Update_Lighting -- Update the lighting parameters used for generating the maps *
- * *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 11/19/1999 NH : Created. *
- *=============================================================================================*/
- void MetalMapManagerClass::Update_Lighting(const Vector3& ambient, const Vector3& main_light_color,
- const Vector3& main_light_dir, const Vector3& camera_dir)
- {
- CurrentAmbient = ambient;
- CurrentMainLightColor = main_light_color;
- CurrentMainLightDir = main_light_dir;
- CurrentCameraDir= camera_dir;
- }
- /***********************************************************************************************
- * MMMC::Update_Textures -- Update metal map textures (call once/frame before rendering) *
- * *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 11/19/1999 NH : Created. *
- *=============================================================================================*/
- void MetalMapManagerClass::Update_Textures(void)
- {
- // Currently the lighting is done using a simple Phong (actually Blinn) model.
- Vector3 &l = CurrentMainLightDir;
- Vector3 &v = CurrentCameraDir;
- // Calculate halfway vector
- Vector3 h = l+v;
- h.Normalize();
- // NOTE: when our lighting equation gets more complicated we might want to do some testing to
- // detect zero components...
- // Calculate quantities which are the same for all metal maps
- float n_dot_l[METALMAP_SIZE_2];
- float n_dot_h[METALMAP_SIZE_2];
-
- VectorProcessorClass::DotProduct(n_dot_l,l,_NormalTable,METALMAP_SIZE_2);
- VectorProcessorClass::ClampMin(n_dot_l, n_dot_l, 0.0f, METALMAP_SIZE_2);
- VectorProcessorClass::DotProduct(n_dot_h,h,_NormalTable, METALMAP_SIZE_2);
- VectorProcessorClass::ClampMin(n_dot_h, n_dot_h, 0.0f, METALMAP_SIZE_2);
- // Loop over each metal map and update it
- for (int i = 0; i < MapCount; i++) {
- MetalParams &cur_params = MetalParameters[i];
- // If shinyness > 1, apply it to specular value array
- float *specular = 0;
- float temp_specular[METALMAP_SIZE_2];
- float shinyness = cur_params.Shininess;
- if (shinyness > 1.0f) {
- VectorProcessorClass::Power(temp_specular, n_dot_h, shinyness, METALMAP_SIZE_2);
- specular = &(temp_specular[0]);
- } else {
- specular = &(n_dot_h[0]);
- }
- // Generate metal map row by row
- Vector3 specular_color(cur_params.SpecularColor.X * CurrentMainLightColor.X,
- cur_params.SpecularColor.Y * CurrentMainLightColor.Y,
- cur_params.SpecularColor.Z * CurrentMainLightColor.Z);
- Vector3 diffuse_color(cur_params.DiffuseColor.X * CurrentMainLightColor.X,
- cur_params.DiffuseColor.Y * CurrentMainLightColor.Y,
- cur_params.DiffuseColor.Z * CurrentMainLightColor.Z);
- Vector3 ambient_color(cur_params.AmbientColor.X * CurrentAmbient.X,
- cur_params.AmbientColor.Y * CurrentAmbient.Y,
- cur_params.AmbientColor.Z * CurrentAmbient.Z);
- Vector3 white(1.0f, 1.0f, 1.0f);
- SurfaceClass * metal_map_surface = Textures[i]->Get_Surface_Level(0);
- int pitch;
- unsigned char *map=(unsigned char *) metal_map_surface->Lock(&pitch);
- int idx=0;
- for (int y = 0; y < METALMAP_SIZE; y++) {
- for (int x = 0; x < METALMAP_SIZE; x++) {
- Vector3 result = ambient_color + (diffuse_color * n_dot_l[idx]) + (specular_color * specular[idx]);
- result.Update_Min(white); // Clamp to white
-
- map[4*x] = (unsigned char)floor(result.Z * 255.99f); // B
- map[4*x+1] = (unsigned char)floor(result.Y * 255.99f); // G
- map[4*x+2] = (unsigned char)floor(result.X * 255.99f); // R
- map[4*x+3] = 0xFF; // A
- idx++;
- }
- map+=pitch;
- }
- metal_map_surface->Unlock();
- REF_PTR_RELEASE(metal_map_surface);
- } // for i
- }
- /***********************************************************************************************
- * MMMC::initialize_normal_table -- Utility function to initialize the normal table *
- * *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 11/19/1999 NH : Created. *
- *=============================================================================================*/
- void MetalMapManagerClass::initialize_normal_table(void)
- {
- // NOTE: changing the actual static _NormalTable member must be the last thing this function
- // does to avoid synchronization errors.
- static Vector3 _normal_table[METALMAP_SIZE_2];
- // Calculate vectors (area outside sphere should be filled with a radial fill of the vectors at
- // the sphere's edge to avoid aliasing artifacts)
- float step = 2.0f / (float)METALMAP_SIZE;
- int idx = 0;
- for (int y = 0; y < METALMAP_SIZE; y++) {
- for (int x = 0; x < METALMAP_SIZE; x++) {
- Vector3 &normal = _normal_table[idx];
- // Set vector to point to surface of unit sphere
- normal.Set((step * (float)x) - 1.0f, (step * (float)y) - 1.0f, 0.0f);
- float z2 = 1 - ((normal.X * normal.X) + (normal.Y * normal.Y));
- z2 = MAX(z2, 0.0f); // If outside the sphere, treat as if on its edge
- normal.Z = sqrt(z2);
- normal.Normalize(); // Needed for "outside sphere" case and for safety's sake
- idx++;
- }
- }
- _NormalTable = &(_normal_table[0]);
- }
- /***********************************************************************************************
- * MMMC::initialize_metal_params -- Utility function (shared CTor code) *
- * *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 11/23/1999 NH : Created. *
- *=============================================================================================*/
- void MetalMapManagerClass::initialize_metal_params(int map_count, MetalParams *metal_params)
- {
- MapCount = map_count;
- if (MapCount > 0) {
- Textures = W3DNEWARRAY TextureClass *[MapCount];
- MetalParameters = W3DNEWARRAY MetalParams[MapCount];
- for (int i = 0; i < MapCount; i++) {
- // Copy metal parameters (assert if invalid)
- MetalParameters[i] = metal_params[i];
- assert(MetalParameters[i].AmbientColor.X >= 0.0f && MetalParameters[i].AmbientColor.X <= 1.0f);
- assert(MetalParameters[i].AmbientColor.Y >= 0.0f && MetalParameters[i].AmbientColor.Y <= 1.0f);
- assert(MetalParameters[i].AmbientColor.Z >= 0.0f && MetalParameters[i].AmbientColor.Z <= 1.0f);
- assert(MetalParameters[i].DiffuseColor.X >= 0.0f && MetalParameters[i].DiffuseColor.X <= 1.0f);
- assert(MetalParameters[i].DiffuseColor.Y >= 0.0f && MetalParameters[i].DiffuseColor.Y <= 1.0f);
- assert(MetalParameters[i].DiffuseColor.Z >= 0.0f && MetalParameters[i].DiffuseColor.Z <= 1.0f);
- assert(MetalParameters[i].SpecularColor.X >= 0.0f && MetalParameters[i].SpecularColor.X <= 1.0f);
- assert(MetalParameters[i].SpecularColor.Y >= 0.0f && MetalParameters[i].SpecularColor.Y <= 1.0f);
- assert(MetalParameters[i].SpecularColor.Z >= 0.0f && MetalParameters[i].SpecularColor.Z <= 1.0f);
- assert(MetalParameters[i].Shininess > 0.0f);
- }
- }
- }
|