metalmap.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. /*
  2. ** Command & Conquer Generals Zero Hour(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** 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 ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : G *
  23. * *
  24. * $Archive:: /Commando/Code/ww3d2/metalmap.cpp $*
  25. * *
  26. * $Org Author:: Hector_y $*
  27. * *
  28. * $Author:: Kenny_m $*
  29. * *
  30. * $Modtime:: 08/05/02 10:44a $*
  31. * *
  32. * $Revision:: 4 $*
  33. * *
  34. * 08/05/02 KM Texture class redesign
  35. *---------------------------------------------------------------------------------------------*
  36. * Functions: *
  37. * MMMC::MetalMapManagerClass -- Create metal map manager according to given metal parameters*
  38. * MMMC::MetalMapManagerClass -- Create metal map manager from INI *
  39. * MMMC::~MetalMapManagerClass -- MetalMapManagerClass destructor *
  40. * MMMC::Get_Metal_Map -- Get the texture for a metal map by id number *
  41. * MMMC::Metal_Map_Count -- Get the number of metal maps in the manager *
  42. * MMMC::Update_Lighting -- Update the lighting parameters used for generating the maps *
  43. * MMMC::Update_Textures -- Update metal map textures (call once/frame before rendering) *
  44. * MMMC::initialize_normal_table -- Utility function to initialize the normal table *
  45. * MMMC::initialize_metal_params -- Utility function (shared CTor code) *
  46. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  47. #include "metalmap.h"
  48. #include "texture.h"
  49. #include "ww3dformat.h"
  50. #include "ww3d.h"
  51. #include <vp.h>
  52. #include <ini.h>
  53. #include <point.h>
  54. #include <stdio.h>
  55. #include <hashtemplate.h>
  56. #include <wwstring.h>
  57. #include <wwmath.h>
  58. /*
  59. ** Class static members:
  60. */
  61. Vector3 * MetalMapManagerClass::_NormalTable = 0;
  62. /***********************************************************************************************
  63. * MMMC::MetalMapManagerClass -- Create metal map manager from INI *
  64. * *
  65. * *
  66. * INPUT: *
  67. * *
  68. * OUTPUT: *
  69. * *
  70. * WARNINGS: *
  71. * *
  72. * HISTORY: *
  73. * 11/23/1999 NH : Created. *
  74. *=============================================================================================*/
  75. MetalMapManagerClass::MetalMapManagerClass(INIClass &ini) :
  76. MapCount(0),
  77. Textures(0),
  78. MetalParameters(0),
  79. CurrentAmbient(0.0f, 0.0f, 0.0f),
  80. CurrentMainLightColor(0.0f, 0.0f, 0.0f),
  81. CurrentMainLightDir(1.0f, 0.0f, 0.0f),
  82. CurrentCameraDir(1.0f,0.0f,0.0f),
  83. Use16Bit(false)
  84. {
  85. // If the static normal table has not been initialized yet, initialize it
  86. if (!_NormalTable) {
  87. initialize_normal_table();
  88. }
  89. // Determine how many metals are in this file
  90. char section[255];
  91. for (int lp = 0; ; lp++) {
  92. sprintf(section, "Metal%02d", lp);
  93. if (!ini.Find_Section(section)) {
  94. break; // NAK - Mar 8, 2000: changed to a break to fix off by one error in lp
  95. }
  96. }
  97. if (lp > 0) {
  98. // Create metal params structs and fill from INI:
  99. MetalParams *metal_params = W3DNEWARRAY MetalParams[lp];
  100. TPoint3D<float> white_tpoint(255.0f, 255.0f, 255.0f);
  101. Vector3 white(1.0f, 1.0f, 1.0f);
  102. Vector3 black(0.0f, 0.0f, 0.0f);
  103. for (int i = 0; i < lp; i++) {
  104. sprintf(section, "Metal%02d", i);
  105. static const float cf = 0.003921568627451f; // 1 / 255
  106. TPoint3D<float> color;
  107. color = ini.Get_Point(section, "AmbientColor", white_tpoint);
  108. metal_params[i].AmbientColor.Set(color.X * cf, color.Y * cf, color.Z * cf);
  109. metal_params[i].AmbientColor.Update_Min(white);
  110. metal_params[i].AmbientColor.Update_Max(black);
  111. color = ini.Get_Point(section, "DiffuseColor", white_tpoint);
  112. metal_params[i].DiffuseColor.Set(color.X * cf, color.Y * cf, color.Z * cf);
  113. metal_params[i].AmbientColor.Update_Min(white);
  114. metal_params[i].AmbientColor.Update_Max(black);
  115. color = ini.Get_Point(section, "SpecularColor", white_tpoint);
  116. metal_params[i].SpecularColor.Set(color.X * cf, color.Y * cf, color.Z * cf);
  117. metal_params[i].AmbientColor.Update_Min(white);
  118. metal_params[i].AmbientColor.Update_Max(black);
  119. float shininess = ini.Get_Float(section, "Shininess", 0.0f);
  120. metal_params[i].Shininess = WWMath::Clamp(shininess, 0.0f, 127.0f);
  121. }
  122. initialize_metal_params(lp, metal_params);
  123. delete [] metal_params;
  124. } else {
  125. assert(0);
  126. }
  127. int w,h,bits;
  128. bool windowed;
  129. WW3D::Get_Device_Resolution(w,h,bits,windowed);
  130. Use16Bit=(bits<=16);
  131. WW3DFormat format=(Use16Bit?WW3D_FORMAT_A4R4G4B4:WW3D_FORMAT_A8R8G8B8);
  132. for (int i = 0; i < lp; i++) {
  133. Textures[i]=NEW_REF(TextureClass,(METALMAP_SIZE,METALMAP_SIZE,format,MIP_LEVELS_1));
  134. Textures[i]->Get_Filter().Set_U_Addr_Mode(TextureFilterClass::TEXTURE_ADDRESS_CLAMP);
  135. Textures[i]->Get_Filter().Set_V_Addr_Mode(TextureFilterClass::TEXTURE_ADDRESS_CLAMP);
  136. StringClass tex_name;
  137. tex_name.Format("!m%02d.tga", i);
  138. Textures[i]->Set_Texture_Name(tex_name);
  139. }
  140. }
  141. /***********************************************************************************************
  142. * MMMC::~MetalMapManagerClass -- MetalMapManagerClass destructor *
  143. * *
  144. * *
  145. * INPUT: *
  146. * *
  147. * OUTPUT: *
  148. * *
  149. * WARNINGS: *
  150. * *
  151. * HISTORY: *
  152. * 11/19/1999 NH : Created. *
  153. *=============================================================================================*/
  154. MetalMapManagerClass::~MetalMapManagerClass(void)
  155. {
  156. if (Textures) {
  157. for (int i = 0; i < MapCount; i++) {
  158. REF_PTR_RELEASE(Textures[i]);
  159. }
  160. delete [] Textures;
  161. Textures = 0;
  162. }
  163. if (MetalParameters) {
  164. delete [] MetalParameters;
  165. MetalParameters = 0;
  166. }
  167. }
  168. /***********************************************************************************************
  169. * MMMC::Get_Metal_Map -- Get the texture for a metal map by id number *
  170. * *
  171. * *
  172. * INPUT: *
  173. * *
  174. * OUTPUT: *
  175. * *
  176. * WARNINGS: *
  177. * *
  178. * HISTORY: *
  179. * 11/19/1999 NH : Created. *
  180. *=============================================================================================*/
  181. TextureClass * MetalMapManagerClass::Get_Metal_Map(int id)
  182. {
  183. if (id < 0 || id >= MapCount) return 0;
  184. Textures[id]->Add_Ref();
  185. return Textures[id];
  186. }
  187. /***********************************************************************************************
  188. * MMMC::Metal_Map_Count -- Get the number of metal maps in the manager *
  189. * *
  190. * *
  191. * INPUT: *
  192. * *
  193. * OUTPUT: *
  194. * *
  195. * WARNINGS: *
  196. * *
  197. * HISTORY: *
  198. * 11/19/1999 NH : Created. *
  199. *=============================================================================================*/
  200. int MetalMapManagerClass::Metal_Map_Count(void)
  201. {
  202. return MapCount;
  203. }
  204. /***********************************************************************************************
  205. * MMMC::Update_Lighting -- Update the lighting parameters used for generating the maps *
  206. * *
  207. * *
  208. * INPUT: *
  209. * *
  210. * OUTPUT: *
  211. * *
  212. * WARNINGS: *
  213. * *
  214. * HISTORY: *
  215. * 11/19/1999 NH : Created. *
  216. *=============================================================================================*/
  217. void MetalMapManagerClass::Update_Lighting(const Vector3& ambient, const Vector3& main_light_color,
  218. const Vector3& main_light_dir, const Vector3& camera_dir)
  219. {
  220. CurrentAmbient = ambient;
  221. CurrentMainLightColor = main_light_color;
  222. CurrentMainLightDir = main_light_dir;
  223. CurrentCameraDir= camera_dir;
  224. }
  225. /***********************************************************************************************
  226. * MMMC::Update_Textures -- Update metal map textures (call once/frame before rendering) *
  227. * *
  228. * *
  229. * INPUT: *
  230. * *
  231. * OUTPUT: *
  232. * *
  233. * WARNINGS: *
  234. * *
  235. * HISTORY: *
  236. * 11/19/1999 NH : Created. *
  237. *=============================================================================================*/
  238. void MetalMapManagerClass::Update_Textures(void)
  239. {
  240. // Currently the lighting is done using a simple Phong (actually Blinn) model.
  241. Vector3 &l = CurrentMainLightDir;
  242. Vector3 &v = CurrentCameraDir;
  243. // Calculate halfway vector
  244. Vector3 h = l+v;
  245. h.Normalize();
  246. // NOTE: when our lighting equation gets more complicated we might want to do some testing to
  247. // detect zero components...
  248. // Calculate quantities which are the same for all metal maps
  249. float n_dot_l[METALMAP_SIZE_2];
  250. float n_dot_h[METALMAP_SIZE_2];
  251. VectorProcessorClass::DotProduct(n_dot_l,l,_NormalTable,METALMAP_SIZE_2);
  252. VectorProcessorClass::ClampMin(n_dot_l, n_dot_l, 0.0f, METALMAP_SIZE_2);
  253. VectorProcessorClass::DotProduct(n_dot_h,h,_NormalTable, METALMAP_SIZE_2);
  254. VectorProcessorClass::ClampMin(n_dot_h, n_dot_h, 0.0f, METALMAP_SIZE_2);
  255. // Loop over each metal map and update it
  256. for (int i = 0; i < MapCount; i++) {
  257. MetalParams &cur_params = MetalParameters[i];
  258. // If shinyness > 1, apply it to specular value array
  259. float *specular = 0;
  260. float temp_specular[METALMAP_SIZE_2];
  261. float shinyness = cur_params.Shininess;
  262. if (shinyness > 1.0f) {
  263. VectorProcessorClass::Power(temp_specular, n_dot_h, shinyness, METALMAP_SIZE_2);
  264. specular = &(temp_specular[0]);
  265. } else {
  266. specular = &(n_dot_h[0]);
  267. }
  268. // Generate metal map row by row
  269. Vector3 specular_color(cur_params.SpecularColor.X * CurrentMainLightColor.X,
  270. cur_params.SpecularColor.Y * CurrentMainLightColor.Y,
  271. cur_params.SpecularColor.Z * CurrentMainLightColor.Z);
  272. Vector3 diffuse_color(cur_params.DiffuseColor.X * CurrentMainLightColor.X,
  273. cur_params.DiffuseColor.Y * CurrentMainLightColor.Y,
  274. cur_params.DiffuseColor.Z * CurrentMainLightColor.Z);
  275. Vector3 ambient_color(cur_params.AmbientColor.X * CurrentAmbient.X,
  276. cur_params.AmbientColor.Y * CurrentAmbient.Y,
  277. cur_params.AmbientColor.Z * CurrentAmbient.Z);
  278. Vector3 white(1.0f, 1.0f, 1.0f);
  279. SurfaceClass * metal_map_surface = Textures[i]->Get_Surface_Level(0);
  280. int pitch;
  281. unsigned char *map=(unsigned char *) metal_map_surface->Lock(&pitch);
  282. int idx=0;
  283. for (int y = 0; y < METALMAP_SIZE; y++) {
  284. for (int x = 0; x < METALMAP_SIZE; x++) {
  285. Vector3 result = ambient_color + (diffuse_color * n_dot_l[idx]) + (specular_color * specular[idx]);
  286. result.Update_Min(white); // Clamp to white
  287. unsigned char b,g,r,a;
  288. b= (unsigned char)WWMath::Floor(result.Z * 255.99f); // B
  289. g= (unsigned char)WWMath::Floor(result.Y * 255.99f); // G
  290. r= (unsigned char)WWMath::Floor(result.X * 255.99f); // R
  291. a= 0xFF; // A
  292. if (Use16Bit) {
  293. unsigned short tmp;
  294. tmp=(a&0xf0)<<8;
  295. tmp|=(r&0xf0)<<4;
  296. tmp|=(g&0xf0);
  297. tmp|=(b&0xf0)>>4;
  298. *(unsigned short*)&map[2*x]=tmp;
  299. } else {
  300. map[4*x]=b;
  301. map[4*x+1]=g;
  302. map[4*x+2]=r;
  303. map[4*x+3]=a;
  304. }
  305. idx++;
  306. }
  307. map+=pitch;
  308. }
  309. metal_map_surface->Unlock();
  310. REF_PTR_RELEASE(metal_map_surface);
  311. } // for i
  312. }
  313. /***********************************************************************************************
  314. * MMMC::initialize_normal_table -- Utility function to initialize the normal table *
  315. * *
  316. * *
  317. * INPUT: *
  318. * *
  319. * OUTPUT: *
  320. * *
  321. * WARNINGS: *
  322. * *
  323. * HISTORY: *
  324. * 11/19/1999 NH : Created. *
  325. *=============================================================================================*/
  326. void MetalMapManagerClass::initialize_normal_table(void)
  327. {
  328. // NOTE: changing the actual static _NormalTable member must be the last thing this function
  329. // does to avoid synchronization errors.
  330. static Vector3 _normal_table[METALMAP_SIZE_2];
  331. // Calculate vectors (area outside sphere should be filled with a radial fill of the vectors at
  332. // the sphere's edge to avoid aliasing artifacts)
  333. float step = 2.0f / (float)METALMAP_SIZE;
  334. int idx = 0;
  335. for (int y = 0; y < METALMAP_SIZE; y++) {
  336. for (int x = 0; x < METALMAP_SIZE; x++) {
  337. Vector3 &normal = _normal_table[idx];
  338. // Set vector to point to surface of unit sphere
  339. normal.Set((step * (float)x) - 1.0f, (step * (float)y) - 1.0f, 0.0f);
  340. float z2 = 1 - ((normal.X * normal.X) + (normal.Y * normal.Y));
  341. z2 = MAX(z2, 0.0f); // If outside the sphere, treat as if on its edge
  342. normal.Z = sqrt(z2);
  343. normal.Normalize(); // Needed for "outside sphere" case and for safety's sake
  344. idx++;
  345. }
  346. }
  347. _NormalTable = &(_normal_table[0]);
  348. }
  349. /***********************************************************************************************
  350. * MMMC::initialize_metal_params -- Utility function (shared CTor code) *
  351. * *
  352. * *
  353. * INPUT: *
  354. * *
  355. * OUTPUT: *
  356. * *
  357. * WARNINGS: *
  358. * *
  359. * HISTORY: *
  360. * 11/23/1999 NH : Created. *
  361. *=============================================================================================*/
  362. void MetalMapManagerClass::initialize_metal_params(int map_count, MetalParams *metal_params)
  363. {
  364. MapCount = map_count;
  365. if (MapCount > 0) {
  366. Textures = W3DNEWARRAY TextureClass *[MapCount];
  367. MetalParameters = W3DNEWARRAY MetalParams[MapCount];
  368. for (int i = 0; i < MapCount; i++) {
  369. // Copy metal parameters (assert if invalid)
  370. MetalParameters[i] = metal_params[i];
  371. assert(MetalParameters[i].AmbientColor.X >= 0.0f && MetalParameters[i].AmbientColor.X <= 1.0f);
  372. assert(MetalParameters[i].AmbientColor.Y >= 0.0f && MetalParameters[i].AmbientColor.Y <= 1.0f);
  373. assert(MetalParameters[i].AmbientColor.Z >= 0.0f && MetalParameters[i].AmbientColor.Z <= 1.0f);
  374. assert(MetalParameters[i].DiffuseColor.X >= 0.0f && MetalParameters[i].DiffuseColor.X <= 1.0f);
  375. assert(MetalParameters[i].DiffuseColor.Y >= 0.0f && MetalParameters[i].DiffuseColor.Y <= 1.0f);
  376. assert(MetalParameters[i].DiffuseColor.Z >= 0.0f && MetalParameters[i].DiffuseColor.Z <= 1.0f);
  377. assert(MetalParameters[i].SpecularColor.X >= 0.0f && MetalParameters[i].SpecularColor.X <= 1.0f);
  378. assert(MetalParameters[i].SpecularColor.Y >= 0.0f && MetalParameters[i].SpecularColor.Y <= 1.0f);
  379. assert(MetalParameters[i].SpecularColor.Z >= 0.0f && MetalParameters[i].SpecularColor.Z <= 1.0f);
  380. assert(MetalParameters[i].Shininess > 0.0f);
  381. }
  382. }
  383. }