mapper.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982
  1. /*
  2. ** Command & Conquer Generals(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:: /VSS_Sync/ww3d2/mapper.cpp $*
  25. * *
  26. * $Author:: Vss_sync $*
  27. * *
  28. * $Modtime:: 8/30/01 1:38a $*
  29. * *
  30. * $Revision:: 31 $*
  31. * *
  32. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  33. #include "mapper.h"
  34. #include "ww3d.h"
  35. #include "ini.h"
  36. #include "chunkio.h"
  37. #include "w3derr.h"
  38. #include "meshmatdesc.h"
  39. #include "dx8wrapper.h"
  40. #include "wwdebug.h"
  41. #include "matinfo.h"
  42. #include "rendobj.h"
  43. #include "mesh.h"
  44. inline DWORD F2DW( FLOAT f ) { return *((DWORD*)&f); }
  45. // HY 1/26/01
  46. // Rewritten to use DX 8 texture matrices
  47. TextureMapperClass::TextureMapperClass(unsigned int stage)
  48. {
  49. Stage = stage;
  50. if (Stage >= MeshMatDescClass::MAX_TEX_STAGES) Stage = MeshMatDescClass::MAX_TEX_STAGES - 1;
  51. }
  52. LinearOffsetTextureMapperClass::LinearOffsetTextureMapperClass(const Vector2 &offset_per_sec, const Vector2 &scale, unsigned int stage) :
  53. ScaleTextureMapperClass(scale, stage),
  54. LastUsedSyncTime(WW3D::Get_Sync_Time())
  55. {
  56. CurrentUVOffset.X = 0.0f;
  57. CurrentUVOffset.Y = 0.0f;
  58. // HY 5/16/01
  59. // This is horrible disgusting legacy from the unmentionable API we used before
  60. // leaving it unchanged because the artists have worked around it
  61. UVOffsetDeltaPerMS = offset_per_sec * -0.001f;
  62. }
  63. LinearOffsetTextureMapperClass::LinearOffsetTextureMapperClass(const INIClass &ini, const char *section, unsigned int stage) :
  64. ScaleTextureMapperClass(ini,section,stage),
  65. LastUsedSyncTime(WW3D::Get_Sync_Time())
  66. {
  67. CurrentUVOffset.X = 0.0f;
  68. CurrentUVOffset.Y = 0.0f;
  69. float u_offset_per_sec = ini.Get_Float(section, "UPerSec", 0.0f);
  70. float v_offset_per_sec = ini.Get_Float(section, "VPerSec", 0.0f);
  71. UVOffsetDeltaPerMS = Vector2(u_offset_per_sec, v_offset_per_sec) * -0.001f;
  72. }
  73. LinearOffsetTextureMapperClass::LinearOffsetTextureMapperClass(const LinearOffsetTextureMapperClass & src) :
  74. ScaleTextureMapperClass(src),
  75. UVOffsetDeltaPerMS(src.UVOffsetDeltaPerMS),
  76. LastUsedSyncTime(WW3D::Get_Sync_Time())
  77. {
  78. CurrentUVOffset.X = 0.0f;
  79. CurrentUVOffset.Y = 0.0f;
  80. }
  81. void LinearOffsetTextureMapperClass::Apply(int uv_array_index)
  82. {
  83. unsigned int delta = WW3D::Get_Sync_Time() - LastUsedSyncTime;
  84. float del = (float)delta;
  85. float offset_u = CurrentUVOffset.X + UVOffsetDeltaPerMS.X * del;
  86. float offset_v = CurrentUVOffset.Y + UVOffsetDeltaPerMS.Y * del;
  87. // ensure both coordinates of offset are in [0, 1] range:
  88. offset_u = offset_u - WWMath::Floor(offset_u);
  89. offset_v = offset_v - WWMath::Floor(offset_v);
  90. // Set up the offset matrix
  91. Matrix3D m(true);
  92. // According to the docs this should work since its 2D
  93. // otherwise change to translate
  94. m[0].Z=offset_u;
  95. m[0].X=Scale.X;
  96. m[1].Z=offset_v;
  97. m[1].Y=Scale.Y;
  98. DX8Wrapper::Set_Transform((D3DTRANSFORMSTATETYPE) (D3DTS_TEXTURE0+Stage),m);
  99. // Disable Texgen
  100. DX8Wrapper::Set_DX8_Texture_Stage_State(Stage,D3DTSS_TEXCOORDINDEX,D3DTSS_TCI_PASSTHRU | uv_array_index);
  101. // Tell rasterizer to expect 2D texture coordinates
  102. DX8Wrapper::Set_DX8_Texture_Stage_State(Stage,D3DTSS_TEXTURETRANSFORMFLAGS,D3DTTFF_COUNT2);
  103. // Update state
  104. CurrentUVOffset.X = offset_u;
  105. CurrentUVOffset.Y = offset_v;
  106. LastUsedSyncTime = WW3D::Get_Sync_Time();
  107. }
  108. // Scale mapper
  109. // HY 5/16/01
  110. ScaleTextureMapperClass::ScaleTextureMapperClass(const Vector2 &scale, unsigned int stage) :
  111. TextureMapperClass(stage),
  112. Scale(scale)
  113. {
  114. }
  115. ScaleTextureMapperClass::ScaleTextureMapperClass(unsigned int stage) :
  116. TextureMapperClass(stage),
  117. Scale(1.0f,1.0f)
  118. {
  119. }
  120. ScaleTextureMapperClass::ScaleTextureMapperClass(const INIClass &ini, const char *section, unsigned int stage) :
  121. TextureMapperClass(stage)
  122. {
  123. Scale.U = ini.Get_Float(section, "UScale", 1.0f);
  124. Scale.V = ini.Get_Float(section, "VScale", 1.0f);
  125. }
  126. ScaleTextureMapperClass::ScaleTextureMapperClass(const ScaleTextureMapperClass & src) :
  127. TextureMapperClass(src),
  128. Scale(src.Scale)
  129. {
  130. }
  131. void ScaleTextureMapperClass::Apply(int uv_array_index)
  132. {
  133. // Set up the scale matrix
  134. Matrix3D m(true);
  135. m[0].X=Scale.U;
  136. m[1].Y=Scale.V;
  137. DX8Wrapper::Set_Transform((D3DTRANSFORMSTATETYPE) (D3DTS_TEXTURE0+Stage),m);
  138. // Disable Texgen
  139. DX8Wrapper::Set_DX8_Texture_Stage_State(Stage,D3DTSS_TEXCOORDINDEX,D3DTSS_TCI_PASSTHRU | uv_array_index);
  140. // Tell rasterizer to expect 2D texture coordinates
  141. DX8Wrapper::Set_DX8_Texture_Stage_State(Stage,D3DTSS_TEXTURETRANSFORMFLAGS,D3DTTFF_COUNT2);
  142. }
  143. // Grid Mapper
  144. // HY 5/16/01
  145. GridTextureMapperClass::GridTextureMapperClass(float fps, unsigned int gridwidth_log2, unsigned int stage) :
  146. TextureMapperClass(stage)
  147. {
  148. LastFrame = 0;
  149. initialize(fps, gridwidth_log2);
  150. }
  151. GridTextureMapperClass::GridTextureMapperClass(const INIClass &ini, const char *section, unsigned int stage) :
  152. TextureMapperClass(stage)
  153. {
  154. float fps = ini.Get_Float(section,"FPS", 1.0f);
  155. unsigned int gridwidth_log2 = ini.Get_Int(section,"Log2Width", 1);
  156. LastFrame=ini.Get_Int(section,"Last",0);
  157. initialize(fps, gridwidth_log2);
  158. }
  159. GridTextureMapperClass::GridTextureMapperClass(const GridTextureMapperClass & src) :
  160. TextureMapperClass(src),
  161. Sign(src.Sign),
  162. MSPerFrame(src.MSPerFrame),
  163. OOGridWidth(src.OOGridWidth),
  164. GridWidthLog2(src.GridWidthLog2),
  165. LastFrame(src.LastFrame)
  166. {
  167. Reset();
  168. }
  169. void GridTextureMapperClass::Apply(int uv_array_index)
  170. {
  171. update_temporal_state();
  172. float u_offset, v_offset;
  173. calculate_uv_offset(&u_offset, &v_offset);
  174. // Set up the offset matrix
  175. Matrix3D m(true);
  176. // According to the docs this should work since its 2D
  177. // otherwise change to translate
  178. m[0].Z = u_offset;
  179. m[1].Z = v_offset;
  180. DX8Wrapper::Set_Transform((D3DTRANSFORMSTATETYPE) (D3DTS_TEXTURE0+Stage), m);
  181. // Disable Texgen
  182. DX8Wrapper::Set_DX8_Texture_Stage_State(Stage, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_PASSTHRU | uv_array_index);
  183. // Tell rasterizer to expect 2D texture coordinates
  184. DX8Wrapper::Set_DX8_Texture_Stage_State(Stage, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2);
  185. }
  186. void GridTextureMapperClass::Reset(void)
  187. {
  188. Remainder = 0;
  189. CurrentFrame = Sign == -1 ? (1 << (GridWidthLog2 + GridWidthLog2)) - 1 : 0;
  190. LastUsedSyncTime = WW3D::Get_Sync_Time();
  191. }
  192. void GridTextureMapperClass::Set_Frame_Per_Second(float fps)
  193. {
  194. initialize(fps, GridWidthLog2);
  195. }
  196. void GridTextureMapperClass::initialize(float fps, unsigned int gridwidth_log2)
  197. {
  198. unsigned int grid_width = (1 << GridWidthLog2);
  199. if (LastFrame == 0) LastFrame = (grid_width * grid_width);
  200. LastUsedSyncTime = WW3D::Get_Sync_Time();
  201. GridWidthLog2 = gridwidth_log2;
  202. OOGridWidth = 1.0f / (float)(grid_width);
  203. if (fps == 0.0f) {
  204. // Value of MSPerFrame does not matter as long as it is not 0 - sign will multiply results,
  205. // zeroing them out.
  206. Sign = 0;
  207. MSPerFrame = 1;
  208. CurrentFrame = 0;
  209. } else if (fps < 0.0f) {
  210. Sign = -1;
  211. MSPerFrame = (unsigned int)(1000.0f / fabs(fps));
  212. CurrentFrame = LastFrame - 1;
  213. } else {
  214. Sign = 1;
  215. MSPerFrame = (unsigned int)(1000.0f / fabs(fps));
  216. CurrentFrame = 0;
  217. }
  218. Remainder = 0;
  219. }
  220. void GridTextureMapperClass::update_temporal_state(void)
  221. {
  222. unsigned int now = WW3D::Get_Sync_Time();
  223. unsigned int delta = now - LastUsedSyncTime;
  224. Remainder += delta;
  225. int new_frame = (int)CurrentFrame + ((int)(Remainder / MSPerFrame) * Sign);
  226. CurrentFrame = *((unsigned int *)&new_frame);
  227. LastUsedSyncTime = now;
  228. CurrentFrame = CurrentFrame % LastFrame;
  229. Remainder = Remainder % MSPerFrame;
  230. }
  231. void GridTextureMapperClass::calculate_uv_offset(float * u_offset, float * v_offset)
  232. {
  233. unsigned int row_mask = ~(0xFFFFFFFF << GridWidthLog2);
  234. unsigned int col_mask = row_mask << GridWidthLog2;
  235. unsigned int x = CurrentFrame & row_mask;
  236. unsigned int y = (CurrentFrame & col_mask) >> GridWidthLog2;
  237. *u_offset = x * OOGridWidth;
  238. *v_offset = y * OOGridWidth;
  239. }
  240. // Rotate Mapper
  241. // HY 5/16/01
  242. RotateTextureMapperClass::RotateTextureMapperClass(float rad_per_sec, const Vector2 &center, unsigned int stage) :
  243. ScaleTextureMapperClass(stage),
  244. LastUsedSyncTime(WW3D::Get_Sync_Time()),
  245. CurrentAngle(0.0f),
  246. RadiansPerSec(rad_per_sec),
  247. Center(center)
  248. {
  249. }
  250. RotateTextureMapperClass::RotateTextureMapperClass(const INIClass &ini, const char *section, unsigned int stage) :
  251. ScaleTextureMapperClass(ini,section,stage),
  252. LastUsedSyncTime(WW3D::Get_Sync_Time()),
  253. CurrentAngle(0.0f)
  254. {
  255. RadiansPerSec=2*WWMATH_PI*ini.Get_Float(section,"Speed",0.1f);
  256. Center.U=ini.Get_Float(section,"UCenter",0.0f);
  257. Center.V=ini.Get_Float(section,"VCenter",0.0f);
  258. }
  259. RotateTextureMapperClass::RotateTextureMapperClass(const RotateTextureMapperClass & src) :
  260. ScaleTextureMapperClass(src),
  261. LastUsedSyncTime(WW3D::Get_Sync_Time()),
  262. RadiansPerSec(src.RadiansPerSec),
  263. CurrentAngle(0.0f),
  264. Center(src.Center)
  265. {
  266. }
  267. void RotateTextureMapperClass::Apply(int uv_array_index)
  268. {
  269. unsigned int now = WW3D::Get_Sync_Time();
  270. unsigned int delta = now - LastUsedSyncTime;
  271. LastUsedSyncTime=now;
  272. CurrentAngle+=RadiansPerSec * delta / 1000.0f;
  273. CurrentAngle=fmodf(CurrentAngle,2*WWMATH_PI);
  274. if (CurrentAngle<0.0f) CurrentAngle+=2*WWMATH_PI;
  275. // Set up the rotation matrix
  276. float c,s;
  277. c=WWMath::Cos(CurrentAngle);
  278. s=WWMath::Sin(CurrentAngle);
  279. Matrix4 m(true);
  280. // subtract center
  281. // rotate
  282. // add center
  283. // then scale
  284. m[0].Set(Scale.X*c,-Scale.X*s,-Scale.X*(c*Center.U-s*Center.V-Center.U),0.0f);
  285. m[1].Set(Scale.Y*s,Scale.Y*c,-Scale.Y*(s*Center.U+c*Center.V-Center.V),0.0f);
  286. DX8Wrapper::Set_Transform((D3DTRANSFORMSTATETYPE) (D3DTS_TEXTURE0+Stage),m);
  287. // Disable Texgen
  288. DX8Wrapper::Set_DX8_Texture_Stage_State(Stage,D3DTSS_TEXCOORDINDEX,D3DTSS_TCI_PASSTHRU | uv_array_index);
  289. // Tell rasterizer to expect 2D texture coordinates
  290. DX8Wrapper::Set_DX8_Texture_Stage_State(Stage,D3DTSS_TEXTURETRANSFORMFLAGS,D3DTTFF_COUNT2);
  291. }
  292. // SineLinearOffset Mapper
  293. // HY 5/16/01
  294. SineLinearOffsetTextureMapperClass::SineLinearOffsetTextureMapperClass(const Vector3 &uafp, const Vector3 &vafp, unsigned int stage) :
  295. TextureMapperClass(stage),
  296. LastUsedSyncTime(WW3D::Get_Sync_Time()),
  297. UAFP(uafp),
  298. VAFP(vafp),
  299. CurrentAngle(0.0f)
  300. {
  301. }
  302. SineLinearOffsetTextureMapperClass::SineLinearOffsetTextureMapperClass(const INIClass &ini, const char *section, unsigned int stage) :
  303. TextureMapperClass(stage),
  304. LastUsedSyncTime(WW3D::Get_Sync_Time()),
  305. CurrentAngle(0.0f)
  306. {
  307. UAFP.X = ini.Get_Float(section, "UAmp", 1.0f);
  308. UAFP.Y = ini.Get_Float(section, "UFreq", 1.0f);
  309. UAFP.Z = ini.Get_Float(section, "UPhase", 0.0f);
  310. VAFP.X = ini.Get_Float(section, "VAmp", 1.0f);
  311. VAFP.Y = ini.Get_Float(section, "VFreq", 1.0f);
  312. VAFP.Z = ini.Get_Float(section, "VPhase", 0.0f);
  313. }
  314. SineLinearOffsetTextureMapperClass::SineLinearOffsetTextureMapperClass(const SineLinearOffsetTextureMapperClass & src) :
  315. TextureMapperClass(src),
  316. LastUsedSyncTime(WW3D::Get_Sync_Time()),
  317. UAFP(src.UAFP),
  318. VAFP(src.VAFP),
  319. CurrentAngle(0.0f)
  320. {
  321. }
  322. void SineLinearOffsetTextureMapperClass::Apply(int uv_array_index)
  323. {
  324. unsigned int now = WW3D::Get_Sync_Time();
  325. unsigned int delta = now - LastUsedSyncTime;
  326. LastUsedSyncTime=now;
  327. CurrentAngle+=(delta / 1000.0f)*WWMATH_PI*2;
  328. float offset_u=UAFP.X*sin(UAFP.Y*CurrentAngle+UAFP.Z*WWMATH_PI);
  329. float offset_v=VAFP.X*sin(VAFP.Y*CurrentAngle+VAFP.Z*WWMATH_PI);
  330. // ensure both coordinates of offset are in [0, 1] range:
  331. offset_u = offset_u - WWMath::Floor(offset_u);
  332. offset_v = offset_v - WWMath::Floor(offset_v);
  333. // Set up the offset matrix
  334. Matrix3D m(true);
  335. // According to the docs this should work since its 2D
  336. // otherwise change to translate
  337. m[0].Z=offset_u;
  338. m[1].Z=offset_v;
  339. DX8Wrapper::Set_Transform((D3DTRANSFORMSTATETYPE) (D3DTS_TEXTURE0+Stage),m);
  340. // Disable Texgen
  341. DX8Wrapper::Set_DX8_Texture_Stage_State(Stage,D3DTSS_TEXCOORDINDEX,D3DTSS_TCI_PASSTHRU | uv_array_index);
  342. // Tell rasterizer to expect 2D texture coordinates
  343. DX8Wrapper::Set_DX8_Texture_Stage_State(Stage,D3DTSS_TEXTURETRANSFORMFLAGS,D3DTTFF_COUNT2);
  344. }
  345. // StepLinearOffset Mapper
  346. // HY 5/16/01
  347. StepLinearOffsetTextureMapperClass::StepLinearOffsetTextureMapperClass(const Vector2 &step, float steps_per_sec, unsigned int stage) :
  348. TextureMapperClass(stage),
  349. LastUsedSyncTime(WW3D::Get_Sync_Time()),
  350. Step(step),
  351. StepsPerSec(steps_per_sec),
  352. CurrentStep(0.0f,0.0f)
  353. {
  354. }
  355. StepLinearOffsetTextureMapperClass::StepLinearOffsetTextureMapperClass(const INIClass &ini, const char *section, unsigned int stage) :
  356. TextureMapperClass(stage),
  357. LastUsedSyncTime(WW3D::Get_Sync_Time()),
  358. CurrentStep(0.0f,0.0f)
  359. {
  360. Step.U = ini.Get_Float(section, "UStep", 0.0f);
  361. Step.V = ini.Get_Float(section, "VStep", 0.0f);
  362. StepsPerSec = ini.Get_Float(section, "SPS", 0.0f);
  363. }
  364. StepLinearOffsetTextureMapperClass::StepLinearOffsetTextureMapperClass(const StepLinearOffsetTextureMapperClass & src) :
  365. TextureMapperClass(src),
  366. LastUsedSyncTime(WW3D::Get_Sync_Time()),
  367. Step(src.Step),
  368. StepsPerSec(src.StepsPerSec),
  369. CurrentStep(0.0f,0.0f)
  370. {
  371. }
  372. void StepLinearOffsetTextureMapperClass::Apply(int uv_array_index)
  373. {
  374. unsigned int now = WW3D::Get_Sync_Time();
  375. unsigned int delta = now - LastUsedSyncTime;
  376. float ms_per_step=1000.0f / StepsPerSec;
  377. if (delta>ms_per_step)
  378. {
  379. LastUsedSyncTime=now;
  380. CurrentStep+=Step*StepsPerSec;
  381. }
  382. // ensure both coordinates of offset are in [0, 1] range:
  383. CurrentStep.U -= WWMath::Floor(CurrentStep.U);
  384. CurrentStep.V -= WWMath::Floor(CurrentStep.V);
  385. // Set up the offset matrix
  386. Matrix3D m(true);
  387. // According to the docs this should work since its 2D
  388. // otherwise change to translate
  389. m[0].Z=CurrentStep.U;
  390. m[1].Z=CurrentStep.V;
  391. DX8Wrapper::Set_Transform((D3DTRANSFORMSTATETYPE) (D3DTS_TEXTURE0+Stage),m);
  392. // Disable Texgen
  393. DX8Wrapper::Set_DX8_Texture_Stage_State(Stage,D3DTSS_TEXCOORDINDEX,D3DTSS_TCI_PASSTHRU | uv_array_index);
  394. // Tell rasterizer to expect 2D texture coordinates
  395. DX8Wrapper::Set_DX8_Texture_Stage_State(Stage,D3DTSS_TEXTURETRANSFORMFLAGS,D3DTTFF_COUNT2);
  396. }
  397. void StepLinearOffsetTextureMapperClass::Reset(void)
  398. {
  399. LastUsedSyncTime = WW3D::Get_Sync_Time();
  400. CurrentStep.Set(0.0f,0.0f);
  401. }
  402. // ZigZagLinearOffset Mapper
  403. // HY 5/16/01
  404. ZigZagLinearOffsetTextureMapperClass::ZigZagLinearOffsetTextureMapperClass(const Vector2 &speed, float period, unsigned int stage) :
  405. TextureMapperClass(stage),
  406. LastUsedSyncTime(WW3D::Get_Sync_Time()),
  407. Speed(speed),
  408. Period(period)
  409. {
  410. }
  411. ZigZagLinearOffsetTextureMapperClass::ZigZagLinearOffsetTextureMapperClass(const INIClass &ini, const char *section, unsigned int stage) :
  412. TextureMapperClass(stage),
  413. LastUsedSyncTime(WW3D::Get_Sync_Time())
  414. {
  415. Speed.U = ini.Get_Float(section, "UPerSec", 0.0f);
  416. Speed.V = ini.Get_Float(section, "VPerSec", 0.0f);
  417. Period = ini.Get_Float(section, "Period", 0.0f);
  418. }
  419. ZigZagLinearOffsetTextureMapperClass::ZigZagLinearOffsetTextureMapperClass(const ZigZagLinearOffsetTextureMapperClass & src) :
  420. TextureMapperClass(src),
  421. LastUsedSyncTime(WW3D::Get_Sync_Time()),
  422. Speed(src.Speed),
  423. Period(src.Period)
  424. {
  425. }
  426. void ZigZagLinearOffsetTextureMapperClass::Apply(int uv_array_index)
  427. {
  428. unsigned int now = WW3D::Get_Sync_Time();
  429. unsigned int delta = now - LastUsedSyncTime;
  430. float time=delta/1000.0f;
  431. if (time>Period)
  432. {
  433. LastUsedSyncTime=now;
  434. }
  435. float offset_u,offset_v;
  436. float half_period=0.5f*Period;
  437. if (time<half_period)
  438. {
  439. offset_u=Speed.U * time;
  440. offset_v=Speed.V * time;
  441. } else
  442. {
  443. offset_u=Speed.U * (Period - time);
  444. offset_v=Speed.V * (Period - time);
  445. }
  446. // ensure both coordinates of offset are in [0, 1] range:
  447. offset_u = offset_u - WWMath::Floor(offset_u);
  448. offset_v = offset_v - WWMath::Floor(offset_v);
  449. // Set up the offset matrix
  450. Matrix3D m(true);
  451. // According to the docs this should work since its 2D
  452. // otherwise change to translate
  453. m[0].Z=offset_u;
  454. m[1].Z=offset_v;
  455. DX8Wrapper::Set_Transform((D3DTRANSFORMSTATETYPE) (D3DTS_TEXTURE0+Stage),m);
  456. // Disable Texgen
  457. DX8Wrapper::Set_DX8_Texture_Stage_State(Stage,D3DTSS_TEXCOORDINDEX,D3DTSS_TCI_PASSTHRU | uv_array_index);
  458. // Tell rasterizer to expect 2D texture coordinates
  459. DX8Wrapper::Set_DX8_Texture_Stage_State(Stage,D3DTSS_TEXTURETRANSFORMFLAGS,D3DTTFF_COUNT2);
  460. }
  461. void ZigZagLinearOffsetTextureMapperClass::Reset(void)
  462. {
  463. LastUsedSyncTime = WW3D::Get_Sync_Time();
  464. }
  465. // ----------------------------------------------------------------------------
  466. //
  467. // Environment mapper calculates the texture coordinates based on
  468. // transformed normals
  469. //
  470. // ----------------------------------------------------------------------------
  471. void ClassicEnvironmentMapperClass::Apply(int uv_array_index)
  472. {
  473. // The canonical environment map
  474. // scale the normal by (.5,.5) and add (.5,.5) to move it to (0,1) range
  475. // and ignore the Z component
  476. Matrix3D matenv( 0.5f, 0.0f, 0.0f, 0.5f,
  477. 0.0f, 0.5f, 0.0f, 0.5f,
  478. 0.0f, 0.0f, 1.0f, 0.0f );
  479. DX8Wrapper::Set_Transform((D3DTRANSFORMSTATETYPE) (D3DTS_TEXTURE0+Stage),matenv);
  480. // Get camera normals
  481. DX8Wrapper::Set_DX8_Texture_Stage_State(Stage,D3DTSS_TEXCOORDINDEX,D3DTSS_TCI_CAMERASPACENORMAL);
  482. // Tell rasterizer to expect 2D matrices
  483. DX8Wrapper::Set_DX8_Texture_Stage_State(Stage,D3DTSS_TEXTURETRANSFORMFLAGS,D3DTTFF_COUNT2);
  484. }
  485. void EnvironmentMapperClass::Apply(int uv_array_index)
  486. {
  487. // The canonical environment map
  488. // scale the normal by (.25,.25) and add (.5,.5) to move it to (0,1) range
  489. // the additional half is to fudge the 1+z normalization factor
  490. // and ignore the Z component
  491. Matrix3D matenv( 0.25f, 0.0f, 0.0f, 0.5f,
  492. 0.0f, 0.25f, 0.0f, 0.5f,
  493. 0.0f, 0.0f, 1.0f, 0.0f );
  494. DX8Wrapper::Set_Transform((D3DTRANSFORMSTATETYPE) (D3DTS_TEXTURE0+Stage),matenv);
  495. // Get camera reflection vector
  496. DX8Wrapper::Set_DX8_Texture_Stage_State(Stage,D3DTSS_TEXCOORDINDEX,D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR);
  497. // Tell rasterizer to expect 2D matrices
  498. DX8Wrapper::Set_DX8_Texture_Stage_State(Stage,D3DTSS_TEXTURETRANSFORMFLAGS,D3DTTFF_COUNT2);
  499. }
  500. EdgeMapperClass::EdgeMapperClass(unsigned int stage) :
  501. TextureMapperClass(stage),
  502. VSpeed(0.0f),
  503. UseReflect(false),
  504. LastUsedSyncTime(WW3D::Get_Sync_Time()),
  505. VOffset(0.0f)
  506. {
  507. }
  508. EdgeMapperClass::EdgeMapperClass(const INIClass &ini, const char *section, unsigned int stage) :
  509. TextureMapperClass(stage),
  510. VSpeed(0.0f),
  511. UseReflect(false),
  512. LastUsedSyncTime(WW3D::Get_Sync_Time()),
  513. VOffset(0.0f)
  514. {
  515. VSpeed=ini.Get_Float(section, "VPerSec", 0.0f);
  516. VOffset=ini.Get_Float(section, "VStart", 0.0f);
  517. UseReflect=ini.Get_Bool(section, "UseReflect", false);
  518. }
  519. EdgeMapperClass::EdgeMapperClass(const EdgeMapperClass & src):
  520. TextureMapperClass(src.Stage),
  521. VSpeed(src.VSpeed),
  522. UseReflect(src.UseReflect),
  523. VOffset(src.VOffset),
  524. LastUsedSyncTime(WW3D::Get_Sync_Time())
  525. {
  526. }
  527. void EdgeMapperClass::Apply(int uv_array_index)
  528. {
  529. unsigned int now=WW3D::Get_Sync_Time();
  530. float delta=(now-LastUsedSyncTime)*0.001f;
  531. LastUsedSyncTime=now;
  532. VOffset+=delta*VSpeed;
  533. VOffset-=WWMath::Floor(VOffset);
  534. // takes the Z component and
  535. // uses it to index the texture
  536. Matrix3D matenv( 0.0f, 0.0f, 0.5f, 0.5f,
  537. 0.0f, 0.0f, 0.0f, VOffset,
  538. 0.0f, 0.0f, 1.0f, 0.0f );
  539. DX8Wrapper::Set_Transform((D3DTRANSFORMSTATETYPE) (D3DTS_TEXTURE0+Stage),matenv);
  540. // Get camera reflection vector
  541. if (UseReflect)
  542. DX8Wrapper::Set_DX8_Texture_Stage_State(Stage,D3DTSS_TEXCOORDINDEX,D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR);
  543. else
  544. DX8Wrapper::Set_DX8_Texture_Stage_State(Stage,D3DTSS_TEXCOORDINDEX,D3DTSS_TCI_CAMERASPACENORMAL);
  545. // Tell rasterizer to expect 2D matrices
  546. DX8Wrapper::Set_DX8_Texture_Stage_State(Stage,D3DTSS_TEXTURETRANSFORMFLAGS,D3DTTFF_COUNT2);
  547. }
  548. void EdgeMapperClass::Reset(void)
  549. {
  550. LastUsedSyncTime = WW3D::Get_Sync_Time();
  551. VOffset = 0.0f;
  552. }
  553. void WSClassicEnvironmentMapperClass::Apply(int uv_array_index)
  554. {
  555. // The canonical environment map
  556. // scale the normal by (.5,.5) and add (.5,.5) to move it to (0,1) range
  557. // and ignore the Z component
  558. Matrix3D matenv( 0.5f, 0.0f, 0.0f, 0.5f,
  559. 0.0f, 0.5f, 0.0f, 0.5f,
  560. 0.0f, 0.0f, 1.0f, 0.0f );
  561. // multiply by inverse of view transform
  562. Matrix4 mat;
  563. DX8Wrapper::Get_Transform(D3DTS_VIEW,mat);
  564. Matrix3D mat2(mat[0].X,mat[1].X,mat[2].X,0.0f,
  565. mat[0].Y,mat[1].Y,mat[2].Y,0.0f,
  566. mat[0].Z,mat[1].Z,mat[2].Z,0.0f);
  567. #ifdef ALLOW_TEMPORARIES
  568. matenv=matenv*mat2;
  569. #else
  570. matenv.postMul(mat2);
  571. #endif
  572. DX8Wrapper::Set_Transform((D3DTRANSFORMSTATETYPE) (D3DTS_TEXTURE0+Stage),matenv);
  573. // Get camera normals
  574. DX8Wrapper::Set_DX8_Texture_Stage_State(Stage,D3DTSS_TEXCOORDINDEX,D3DTSS_TCI_CAMERASPACENORMAL);
  575. // Tell rasterizer to expect 2D matrices
  576. DX8Wrapper::Set_DX8_Texture_Stage_State(Stage,D3DTSS_TEXTURETRANSFORMFLAGS,D3DTTFF_COUNT2);
  577. }
  578. void WSEnvironmentMapperClass::Apply(int uv_array_index)
  579. {
  580. // The canonical environment map
  581. // scale the normal by (.25,.25) and add (.5,.5) to move it to (0,1) range
  582. // the additional half is to fudge the 1+z normalization factor
  583. // and ignore the Z component
  584. Matrix3D matenv( 0.25f, 0.0f, 0.0f, 0.5f,
  585. 0.0f, 0.25f, 0.0f, 0.5f,
  586. 0.0f, 0.0f, 1.0f, 0.0f );
  587. // multiply by inverse of view transform
  588. Matrix4 mat;
  589. DX8Wrapper::Get_Transform(D3DTS_VIEW,mat);
  590. Matrix3D mat2(mat[0].X,mat[1].X,mat[2].X,0.0f,
  591. mat[0].Y,mat[1].Y,mat[2].Y,0.0f,
  592. mat[0].Z,mat[1].Z,mat[2].Z,0.0f);
  593. #ifdef ALLOW_TEMPORARIES
  594. matenv=matenv*mat2;
  595. #else
  596. matenv.postMul(mat2);
  597. #endif
  598. DX8Wrapper::Set_Transform((D3DTRANSFORMSTATETYPE) (D3DTS_TEXTURE0+Stage),matenv);
  599. // Get camera reflection
  600. DX8Wrapper::Set_DX8_Texture_Stage_State(Stage,D3DTSS_TEXCOORDINDEX,D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR);
  601. // Tell rasterizer to expect 2D matrices
  602. DX8Wrapper::Set_DX8_Texture_Stage_State(Stage,D3DTSS_TEXTURETRANSFORMFLAGS,D3DTTFF_COUNT2);
  603. }
  604. void ScreenMapperClass::Apply(int uv_array_index)
  605. {
  606. unsigned int delta = WW3D::Get_Sync_Time() - LastUsedSyncTime;
  607. float del = (float)delta;
  608. float offset_u = CurrentUVOffset.X + UVOffsetDeltaPerMS.X * del;
  609. float offset_v = CurrentUVOffset.Y + UVOffsetDeltaPerMS.Y * del;
  610. // ensure both coordinates of offset are in [0, 1] range:
  611. offset_u = offset_u - WWMath::Floor(offset_u);
  612. offset_v = offset_v - WWMath::Floor(offset_v);
  613. // multiply by projection matrix
  614. // followed by scale and translation
  615. Matrix4 mat;
  616. DX8Wrapper::Get_Transform(D3DTS_PROJECTION,mat);
  617. mat[0]*=Scale.X; // entire row since we're pre-multiplying
  618. mat[1]*=Scale.Y;
  619. Vector4 last(mat[3]); // this gets the w
  620. last*=offset_u; // multiply by w because the projected flag will divide by w
  621. mat[0]+=last;
  622. last=mat[3];
  623. last*=offset_v;
  624. mat[1]+=last;
  625. DX8Wrapper::Set_Transform((D3DTRANSFORMSTATETYPE) (D3DTS_TEXTURE0+Stage),mat);
  626. // Get camera space position
  627. DX8Wrapper::Set_DX8_Texture_Stage_State(Stage,D3DTSS_TEXCOORDINDEX,D3DTSS_TCI_CAMERASPACEPOSITION);
  628. // Tell rasterizer what to expect
  629. DX8Wrapper::Set_DX8_Texture_Stage_State(Stage,D3DTSS_TEXTURETRANSFORMFLAGS,D3DTTFF_PROJECTED | D3DTTFF_COUNT3);
  630. // Update state
  631. CurrentUVOffset.X = offset_u;
  632. CurrentUVOffset.Y = offset_v;
  633. LastUsedSyncTime = WW3D::Get_Sync_Time();
  634. }
  635. void GridClassicEnvironmentMapperClass::Apply(int uv_array_index)
  636. {
  637. update_temporal_state();
  638. float u_offset, v_offset;
  639. calculate_uv_offset(&u_offset, &v_offset);
  640. float del = 0.5f * OOGridWidth;
  641. // Set up the offset matrix
  642. Matrix3D tform( del, 0.0f, 0.0f, u_offset + del,
  643. 0.0f, del, 0.0f, v_offset + del,
  644. 0.0f, 0.0f, 1.0f, 0.0f );
  645. DX8Wrapper::Set_Transform((D3DTRANSFORMSTATETYPE) (D3DTS_TEXTURE0+Stage),tform);
  646. // Get camera normals
  647. DX8Wrapper::Set_DX8_Texture_Stage_State(Stage,D3DTSS_TEXCOORDINDEX,D3DTSS_TCI_CAMERASPACENORMAL);
  648. // Tell rasterizer to expect 2D matrices
  649. DX8Wrapper::Set_DX8_Texture_Stage_State(Stage,D3DTSS_TEXTURETRANSFORMFLAGS,D3DTTFF_COUNT2);
  650. }
  651. void GridEnvironmentMapperClass::Apply(int uv_array_index)
  652. {
  653. update_temporal_state();
  654. float u_offset, v_offset;
  655. calculate_uv_offset(&u_offset, &v_offset);
  656. // Set up the offset matrix
  657. Matrix3D m(true);
  658. // According to the docs this should work since its 2D
  659. // otherwise change to translate
  660. m[0].Z = u_offset;
  661. m[1].Z = v_offset;
  662. float del=0.5f * OOGridWidth;
  663. // Set up the offset matrix
  664. Matrix3D tform( del, 0.0f, 0.0f, u_offset + del,
  665. 0.0f, del, 0.0f, v_offset + del,
  666. 0.0f, 0.0f, 1.0f, 0.0f );
  667. DX8Wrapper::Set_Transform((D3DTRANSFORMSTATETYPE) (D3DTS_TEXTURE0+Stage),tform);
  668. // Get camera space reflection
  669. DX8Wrapper::Set_DX8_Texture_Stage_State(Stage,D3DTSS_TEXCOORDINDEX,D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR);
  670. // Tell rasterizer to expect 2D matrices
  671. DX8Wrapper::Set_DX8_Texture_Stage_State(Stage,D3DTSS_TEXTURETRANSFORMFLAGS,D3DTTFF_COUNT2);
  672. }
  673. RandomTextureMapperClass::RandomTextureMapperClass(float fps, unsigned int stage):
  674. TextureMapperClass(stage),
  675. FPS(fps),
  676. LastUsedSyncTime(WW3D::Get_Sync_Time()),
  677. Speed(0.0f,0.0f)
  678. {
  679. CurrentAngle=WWMATH_PI*(rand() & 2047)/1024.0f;
  680. Center.U=(rand() & 2047)/2048.0f;
  681. Center.V=(rand() & 2047)/2048.0f;
  682. }
  683. RandomTextureMapperClass::RandomTextureMapperClass(const INIClass &ini, const char *section, unsigned int stage):
  684. TextureMapperClass(stage),
  685. LastUsedSyncTime(WW3D::Get_Sync_Time())
  686. {
  687. FPS = ini.Get_Float(section, "FPS", 0.0f);
  688. CurrentAngle=WWMATH_PI*(rand() & 2047)/1024.0f;
  689. Center.U=(rand() & 2047)/2048.0f;
  690. Center.V=(rand() & 2047)/2048.0f;
  691. Speed.U = ini.Get_Float(section, "UPerSec", 0.0f);
  692. Speed.V = ini.Get_Float(section, "VPerSec", 0.0f);
  693. }
  694. RandomTextureMapperClass::RandomTextureMapperClass(const RandomTextureMapperClass & src):
  695. TextureMapperClass(src),
  696. FPS(src.FPS),
  697. LastUsedSyncTime(WW3D::Get_Sync_Time()),
  698. Speed(src.Speed)
  699. {
  700. CurrentAngle=WWMATH_PI*(rand() & 2047)/1024.0f;
  701. Center.U=(rand() & 2047)/2048.0f;
  702. Center.V=(rand() & 2047)/2048.0f;
  703. }
  704. void RandomTextureMapperClass::Apply(int uv_array_index)
  705. {
  706. // Set up the random matrix
  707. Matrix3D m(true);
  708. unsigned int delta=0;
  709. if (FPS!=0.0f)
  710. {
  711. float ms_per_frame=1000/FPS;
  712. unsigned int now = WW3D::Get_Sync_Time();
  713. delta = now - LastUsedSyncTime;
  714. if (delta>ms_per_frame)
  715. {
  716. LastUsedSyncTime=now;
  717. CurrentAngle=WWMATH_PI*(rand() & 2047)/1024.0f;
  718. Center.U=(rand() & 2047)/2048.0f;
  719. Center.V=(rand() & 2047)/2048.0f;
  720. }
  721. }
  722. m.Rotate_Z(CurrentAngle);
  723. float uoff=Center.U + delta*Speed.U*0.001f;
  724. float voff=Center.V + delta*Speed.V*0.001f;
  725. uoff=fmodf(uoff,1.0f);
  726. voff=fmodf(voff,1.0f);
  727. m[0].Z=uoff;
  728. m[1].Z=voff;
  729. DX8Wrapper::Set_Transform((D3DTRANSFORMSTATETYPE) (D3DTS_TEXTURE0+Stage),m);
  730. // Disable Texgen
  731. DX8Wrapper::Set_DX8_Texture_Stage_State(Stage,D3DTSS_TEXCOORDINDEX,D3DTSS_TCI_PASSTHRU | uv_array_index);
  732. // Tell rasterizer to expect 2D texture coordinates
  733. DX8Wrapper::Set_DX8_Texture_Stage_State(Stage,D3DTSS_TEXTURETRANSFORMFLAGS,D3DTTFF_COUNT2);
  734. }
  735. // BumpEnv Mapper
  736. // GTH 8/22/01
  737. BumpEnvTextureMapperClass::BumpEnvTextureMapperClass(float rad_per_sec, float scale_factor, const Vector2 & offset_per_sec, const Vector2 &scale, unsigned int stage) :
  738. LinearOffsetTextureMapperClass(offset_per_sec,scale, stage),
  739. LastUsedSyncTime(WW3D::Get_Sync_Time()),
  740. CurrentAngle(0.0f),
  741. RadiansPerSecond(rad_per_sec),
  742. ScaleFactor(scale_factor)
  743. {
  744. }
  745. BumpEnvTextureMapperClass::BumpEnvTextureMapperClass(INIClass &ini, char *section, unsigned int stage) :
  746. LinearOffsetTextureMapperClass(ini,section,stage),
  747. LastUsedSyncTime(WW3D::Get_Sync_Time()),
  748. CurrentAngle(0.0f)
  749. {
  750. RadiansPerSecond = 2*WWMATH_PI*ini.Get_Float(section,"BumpRotation",0.0f);
  751. ScaleFactor = ini.Get_Float(section,"BumpScale",1.0f);
  752. }
  753. BumpEnvTextureMapperClass::BumpEnvTextureMapperClass(const BumpEnvTextureMapperClass & src) :
  754. LinearOffsetTextureMapperClass(src),
  755. LastUsedSyncTime(WW3D::Get_Sync_Time()),
  756. CurrentAngle(0.0f),
  757. RadiansPerSecond(src.RadiansPerSecond),
  758. ScaleFactor(src.ScaleFactor)
  759. {
  760. }
  761. void BumpEnvTextureMapperClass::Apply(int uv_array_index)
  762. {
  763. LinearOffsetTextureMapperClass::Apply(uv_array_index);
  764. unsigned int now = WW3D::Get_Sync_Time();
  765. unsigned int delta = now - LastUsedSyncTime;
  766. LastUsedSyncTime=now;
  767. CurrentAngle+=RadiansPerSecond * delta * 0.001f;
  768. CurrentAngle=fmodf(CurrentAngle,2*WWMATH_PI);
  769. // Compute the sine and cosine for the bump matrix
  770. float c,s;
  771. c=ScaleFactor * WWMath::Fast_Cos(CurrentAngle);
  772. s=ScaleFactor * WWMath::Fast_Sin(CurrentAngle);
  773. // Set the Bump Environment Matrix
  774. DX8Wrapper::Set_DX8_Texture_Stage_State(Stage,D3DTSS_BUMPENVMAT00, F2DW(c));
  775. DX8Wrapper::Set_DX8_Texture_Stage_State(Stage,D3DTSS_BUMPENVMAT01, F2DW(-s));
  776. DX8Wrapper::Set_DX8_Texture_Stage_State(Stage,D3DTSS_BUMPENVMAT10, F2DW(s));
  777. DX8Wrapper::Set_DX8_Texture_Stage_State(Stage,D3DTSS_BUMPENVMAT11, F2DW(c));
  778. }
  779. void RandomTextureMapperClass::Reset(void)
  780. {
  781. LastUsedSyncTime = WW3D::Get_Sync_Time();
  782. }
  783. /*
  784. ** Utility functions
  785. */
  786. void Reset_All_Texture_Mappers(RenderObjClass *robj, bool make_unique)
  787. {
  788. if (robj->Class_ID()==RenderObjClass::CLASSID_MESH) {
  789. MeshClass *mesh=(MeshClass*) robj;
  790. MaterialInfoClass *minfo = robj->Get_Material_Info();
  791. if (minfo && minfo->Has_Time_Variant_Texture_Mappers()) {
  792. if (make_unique) {
  793. mesh->Make_Unique();
  794. minfo->Make_Vertex_Materials_Unique();
  795. }
  796. minfo->Reset_Texture_Mappers();
  797. minfo->Release_Ref();
  798. }
  799. } else {
  800. int num_obj = robj->Get_Num_Sub_Objects();
  801. RenderObjClass *sub_obj;
  802. for (int i = 0; i < num_obj; i++) {
  803. sub_obj = robj->Get_Sub_Object(i);
  804. if (sub_obj) {
  805. Reset_All_Texture_Mappers(sub_obj, make_unique);
  806. sub_obj->Release_Ref();
  807. }
  808. }
  809. }
  810. }