afxZodiac.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  2. // Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
  3. // Copyright (C) 2015 Faust Logic, Inc.
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to
  7. // deal in the Software without restriction, including without limitation the
  8. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9. // sell copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  21. // IN THE SOFTWARE.
  22. //
  23. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  24. #include "afx/arcaneFX.h"
  25. #include "console/consoleTypes.h"
  26. #include "core/stream/bitStream.h"
  27. #include "core/frameAllocator.h"
  28. #include "terrain/terrRender.h"
  29. #include "gfx/primBuilder.h"
  30. #include "afx/ce/afxZodiac.h"
  31. GFX_ImplementTextureProfile(AFX_GFXZodiacTextureProfile,
  32. GFXTextureProfile::DiffuseMap,
  33. GFXTextureProfile::Static | GFXTextureProfile::NoMipmap | GFXTextureProfile::PreserveSize,
  34. GFXTextureProfile::NONE);
  35. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  36. void afxZodiacData::convertGradientRangeFromDegrees(Point2F& gradrange, const Point2F& gradrange_deg)
  37. {
  38. F32 x = mCos(mDegToRad(gradrange_deg.x));
  39. F32 y = mCos(mDegToRad(gradrange_deg.y));
  40. if (y > x)
  41. gradrange.set(x, y);
  42. else
  43. gradrange.set(y, x);
  44. }
  45. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  46. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  47. // afxZodiacData
  48. IMPLEMENT_CO_DATABLOCK_V1(afxZodiacData);
  49. ConsoleDocClass( afxZodiacData,
  50. "@brief A datablock that specifies a decal-like Zodiac effect.\n\n"
  51. "Zodiacs are special-purpose decal textures, often circular, that are always projected vertically onto the ground. Parameters "
  52. "control dynamic rotation and scale as well as texture, color, and blending style."
  53. "\n\n"
  54. "Zodiacs render on objects of type TerrainBlock, InteriorInstance, GroundPlane, MeshRoad, and TSStatic. They are very "
  55. "effective as spellcasting lighting rings, explosion shockwaves, scorched earth decals, and selection indicators."
  56. "\n\n"
  57. "@ingroup afxEffects\n"
  58. "@ingroup AFX\n"
  59. "@ingroup Datablocks\n"
  60. );
  61. StringTableEntry afxZodiacData::GradientRangeSlot;
  62. bool afxZodiacData::sPreferDestinationGradients = false;
  63. afxZodiacData::afxZodiacData()
  64. {
  65. INIT_ASSET(Texture);
  66. radius_xy = 1;
  67. vert_range.set(0.0f, 0.0f);
  68. start_ang = 0;
  69. ang_per_sec = 0;
  70. color.set(1,1,1,1);
  71. grow_in_time = 0.0f;
  72. shrink_out_time = 0.0f;
  73. growth_rate = 0.0f;
  74. blend_flags = BLEND_NORMAL;
  75. terrain_ok = true;
  76. interiors_ok = true;
  77. reflected_ok = false;
  78. non_reflected_ok = true;
  79. respect_ori_cons = false;
  80. scale_vert_range = true;
  81. interior_h_only = false;
  82. interior_v_ignore = false;
  83. interior_back_ignore = false;
  84. interior_opaque_ignore = false;
  85. interior_transp_ignore = true;
  86. altitude_max = 0.0f;
  87. altitude_falloff = 0.0f;
  88. altitude_shrinks = false;
  89. altitude_fades = false;
  90. distance_max = 75.0f;
  91. distance_falloff = 30.0f;
  92. use_grade_range = false;
  93. prefer_dest_grade = sPreferDestinationGradients;
  94. grade_range_user.set(0.0f, 45.0f);
  95. afxZodiacData::convertGradientRangeFromDegrees(grade_range, grade_range_user);
  96. inv_grade_range = false;
  97. zflags = 0;
  98. }
  99. afxZodiacData::afxZodiacData(const afxZodiacData& other, bool temp_clone) : GameBaseData(other, temp_clone)
  100. {
  101. CLONE_ASSET(Texture);
  102. radius_xy = other.radius_xy;
  103. vert_range = other.vert_range;
  104. start_ang = other.start_ang;
  105. ang_per_sec = other.ang_per_sec;
  106. grow_in_time = other.grow_in_time;
  107. shrink_out_time = other.shrink_out_time;
  108. growth_rate = other.growth_rate;
  109. color = other.color;
  110. altitude_max = other.altitude_max;
  111. altitude_falloff = other.altitude_falloff;
  112. altitude_shrinks = other.altitude_shrinks;
  113. altitude_fades = other.altitude_fades;
  114. distance_max = other.distance_max;
  115. distance_falloff = other.distance_falloff;
  116. use_grade_range = other.use_grade_range;
  117. prefer_dest_grade = other.prefer_dest_grade;
  118. grade_range = other.grade_range;
  119. inv_grade_range = other.inv_grade_range;
  120. zflags = other.zflags;
  121. expand_zflags();
  122. }
  123. ImplementEnumType( afxZodiac_BlendType, "Possible zodiac blend types.\n" "@ingroup afxZodiac\n\n" )
  124. { afxZodiacData::BLEND_NORMAL, "normal", "..." },
  125. { afxZodiacData::BLEND_ADDITIVE, "additive", "..." },
  126. { afxZodiacData::BLEND_SUBTRACTIVE, "subtractive", "..." },
  127. EndImplementEnumType;
  128. void afxZodiacData::initPersistFields()
  129. {
  130. INITPERSISTFIELD_IMAGEASSET(Texture, afxZodiacData, "An image to use as the zodiac's texture.");
  131. addField("radius", TypeF32, Offset(radius_xy, afxZodiacData),
  132. "The zodiac's radius in scene units.");
  133. addField("verticalRange", TypePoint2F, Offset(vert_range, afxZodiacData),
  134. "For interior zodiacs only, verticalRange specifies distances above and below the "
  135. "zodiac's position. If both values are 0.0, the radius is used.");
  136. addField("scaleVerticalRange", TypeBool, Offset(scale_vert_range, afxZodiacData),
  137. "Specifies if the zodiac's verticalRange should scale according to changes in the "
  138. "radius. When a zodiacs is used as an expanding shockwave, this value should be set "
  139. "to false, otherwise the zodiac can expand to cover an entire interior.");
  140. addField("startAngle", TypeF32, Offset(start_ang, afxZodiacData),
  141. "The starting angle in degrees of the zodiac's rotation.");
  142. addField("rotationRate", TypeF32, Offset(ang_per_sec, afxZodiacData),
  143. "The rate of rotation in degrees-per-second. Zodiacs with a positive rotationRate "
  144. "rotate clockwise, while those with negative values turn counter-clockwise.");
  145. addField("growInTime", TypeF32, Offset(grow_in_time, afxZodiacData),
  146. "A duration of time in seconds over which the zodiac grows from a zero size to its "
  147. "full size as specified by the radius.");
  148. addField("shrinkOutTime", TypeF32, Offset(shrink_out_time, afxZodiacData),
  149. "A duration of time in seconds over which the zodiac shrinks from full size to "
  150. "invisible.");
  151. addField("growthRate", TypeF32, Offset(growth_rate, afxZodiacData),
  152. "A rate in meters-per-second at which the zodiac grows in size. A negative value will "
  153. "shrink the zodiac.");
  154. addField("color", TypeColorF, Offset(color, afxZodiacData),
  155. "A color value for the zodiac.");
  156. addField("blend", TYPEID<BlendType>(), Offset(blend_flags, afxZodiacData),
  157. "A blending style for the zodiac. Possible values: normal, additive, or subtractive.");
  158. addField("showOnTerrain", TypeBool, Offset(terrain_ok, afxZodiacData),
  159. "Specifies if the zodiac should be rendered on terrain or terrain-like surfaces.");
  160. addField("showOnInteriors", TypeBool, Offset(interiors_ok, afxZodiacData),
  161. "Specifies if the zodiac should be rendered on interior or interior-like surfaces.");
  162. addField("showInReflections", TypeBool, Offset(reflected_ok, afxZodiacData),
  163. "Specifies if the zodiac should be rendered on the reflection rendering pass of the "
  164. "object it will be projected onto.");
  165. addField("showInNonReflections", TypeBool, Offset(non_reflected_ok, afxZodiacData),
  166. "Specifies if the zodiac should be rendered on the non-reflection rendering pass of "
  167. "the object it will be projected onto.");
  168. addField("trackOrientConstraint", TypeBool, Offset(respect_ori_cons, afxZodiacData),
  169. "Specifies if the zodiac's rotation should be defined by its constrained "
  170. "transformation.");
  171. addField("interiorHorizontalOnly", TypeBool, Offset(interior_h_only, afxZodiacData),
  172. "Specifies if interior zodiacs should be rendered exclusively on perfectly horizontal "
  173. "interior surfaces.");
  174. addField("interiorIgnoreVertical", TypeBool, Offset(interior_v_ignore, afxZodiacData),
  175. "Specifies if interior zodiacs should not be rendered on perfectly vertical interior "
  176. "surfaces.");
  177. addField("interiorIgnoreBackfaces", TypeBool, Offset(interior_back_ignore, afxZodiacData),
  178. "Specifies if interior zodiacs should not be rendered on interior surface which are "
  179. "backfacing to the zodiac's center.");
  180. addField("interiorIgnoreOpaque", TypeBool, Offset(interior_opaque_ignore, afxZodiacData),
  181. "");
  182. addField("interiorIgnoreTransparent", TypeBool, Offset(interior_transp_ignore, afxZodiacData),
  183. "");
  184. addField("altitudeMax", TypeF32, Offset(altitude_max, afxZodiacData),
  185. "The altitude at which zodiac becomes invisible as the result of fading out or "
  186. "becoming too small.");
  187. addField("altitudeFalloff", TypeF32, Offset(altitude_falloff, afxZodiacData),
  188. "The altitude at which zodiac begins to fade and/or shrink.");
  189. addField("altitudeShrinks", TypeBool, Offset(altitude_shrinks, afxZodiacData),
  190. "When true, zodiac becomes smaller as altitude increases.");
  191. addField("altitudeFades", TypeBool, Offset(altitude_fades, afxZodiacData),
  192. "When true, zodiac fades out as altitude increases.");
  193. addField("distanceMax", TypeF32, Offset(distance_max, afxZodiacData),
  194. "The distance from camera at which the zodiac becomes invisible as the result of "
  195. "fading out.");
  196. addField("distanceFalloff", TypeF32, Offset(distance_falloff, afxZodiacData),
  197. "The distance from camera at which the zodiac begins to fade out.");
  198. addField("useGradientRange", TypeBool, Offset(use_grade_range, afxZodiacData),
  199. "When true, gradientRange will be used to determine on which polygons the zodiac will "
  200. "render.");
  201. addField("preferDestinationGradients", TypeBool, Offset(prefer_dest_grade, afxZodiacData),
  202. "When true, a gradientRange specified on an InteriorInstance or TSStatic will be used "
  203. "instead of the zodiac's gradientRange.");
  204. addField("gradientRange", TypePoint2F, Offset(grade_range_user, afxZodiacData),
  205. "Zodiac will render on polygons with gradients within the range specified by "
  206. "gradientRange. 0 for floor polys, 90 for wall polys, 180 for ceiling polys.");
  207. addField("invertGradientRange", TypeBool, Offset(inv_grade_range, afxZodiacData),
  208. "When true, the zodiac will render on polygons with gradients outside of the range "
  209. "specified by gradientRange.");
  210. Parent::initPersistFields();
  211. GradientRangeSlot = StringTable->lookup("gradientRange");
  212. Con::addVariable("pref::afxZodiac::preferDestinationGradients", TypeBool, &sPreferDestinationGradients);
  213. }
  214. bool afxZodiacData::onAdd()
  215. {
  216. if (Parent::onAdd() == false)
  217. return false;
  218. if (altitude_falloff > altitude_max)
  219. altitude_falloff = altitude_max;
  220. if (distance_falloff > distance_max)
  221. distance_falloff = distance_max;
  222. return true;
  223. }
  224. void afxZodiacData::packData(BitStream* stream)
  225. {
  226. Parent::packData(stream);
  227. merge_zflags();
  228. PACKDATA_ASSET(Texture);
  229. stream->write(radius_xy);
  230. stream->write(vert_range.x);
  231. stream->write(vert_range.y);
  232. stream->write(grade_range.x);
  233. stream->write(grade_range.y);
  234. stream->write(start_ang);
  235. stream->write(ang_per_sec);
  236. stream->write(grow_in_time);
  237. stream->write(shrink_out_time);
  238. stream->write(growth_rate);
  239. stream->write(color);
  240. stream->write(zflags);
  241. stream->write(altitude_max);
  242. stream->write(altitude_falloff);
  243. stream->writeFlag(altitude_shrinks);
  244. stream->writeFlag(altitude_fades);
  245. stream->write(distance_max);
  246. stream->write(distance_falloff);
  247. }
  248. void afxZodiacData::unpackData(BitStream* stream)
  249. {
  250. Parent::unpackData(stream);
  251. UNPACKDATA_ASSET(Texture);
  252. stream->read(&radius_xy);
  253. stream->read(&vert_range.x);
  254. stream->read(&vert_range.y);
  255. stream->read(&grade_range.x);
  256. stream->read(&grade_range.y);
  257. stream->read(&start_ang);
  258. stream->read(&ang_per_sec);
  259. stream->read(&grow_in_time);
  260. stream->read(&shrink_out_time);
  261. stream->read(&growth_rate);
  262. stream->read(&color);
  263. stream->read(&zflags);
  264. stream->read(&altitude_max);
  265. stream->read(&altitude_falloff);
  266. altitude_shrinks = stream->readFlag();
  267. altitude_fades = stream->readFlag();
  268. stream->read(&distance_max);
  269. stream->read(&distance_falloff);
  270. expand_zflags();
  271. }
  272. bool afxZodiacData::preload(bool server, String &errorStr)
  273. {
  274. if (!Parent::preload(server, errorStr))
  275. return false;
  276. if (vert_range.x == 0.0f && vert_range.y == 0.0f)
  277. vert_range.x = vert_range.y = radius_xy;
  278. return true;
  279. }
  280. void afxZodiacData::onStaticModified(const char* slot, const char* newValue)
  281. {
  282. Parent::onStaticModified(slot, newValue);
  283. if (slot == GradientRangeSlot)
  284. {
  285. convertGradientRangeFromDegrees(grade_range, grade_range_user);
  286. return;
  287. }
  288. merge_zflags();
  289. }
  290. void afxZodiacData::onPerformSubstitutions()
  291. {
  292. if (mTextureAssetId != StringTable->EmptyString())
  293. {
  294. mTextureAsset = mTextureAssetId;
  295. if (mTextureAsset.notNull())
  296. {
  297. if (getTexture() != StringTable->EmptyString() && mTextureName != StringTable->insert("texhandle"))
  298. {
  299. if (mTextureAsset.notNull())
  300. {
  301. mTextureAsset->getChangedSignal().notify(this, &afxZodiacData::onImageChanged);
  302. }
  303. mTexture.set(getTexture(), mTextureProfile, avar("%s() - mTextureObject (line %d)", __FUNCTION__, __LINE__));
  304. }
  305. }
  306. }
  307. }
  308. F32 afxZodiacData::calcRotationAngle(F32 elapsed, F32 rate_factor)
  309. {
  310. F32 angle = start_ang + elapsed*ang_per_sec*rate_factor;
  311. angle = mFmod(angle, 360.0f);
  312. return angle;
  313. }
  314. void afxZodiacData::expand_zflags()
  315. {
  316. blend_flags = (zflags & BLEND_MASK);
  317. terrain_ok = ((zflags & SHOW_ON_TERRAIN) != 0);
  318. interiors_ok = ((zflags & SHOW_ON_INTERIORS) != 0);
  319. reflected_ok = ((zflags & SHOW_IN_REFLECTIONS) != 0);
  320. non_reflected_ok = ((zflags & SHOW_IN_NON_REFLECTIONS) != 0);
  321. respect_ori_cons = ((zflags & RESPECT_ORIENTATION) != 0);
  322. scale_vert_range = ((zflags & SCALE_VERT_RANGE) != 0);
  323. interior_h_only = ((zflags & INTERIOR_HORIZ_ONLY) != 0);
  324. interior_v_ignore = ((zflags & INTERIOR_VERT_IGNORE) != 0);
  325. interior_back_ignore = ((zflags & INTERIOR_BACK_IGNORE) != 0);
  326. interior_opaque_ignore = ((zflags & INTERIOR_OPAQUE_IGNORE) != 0);
  327. interior_transp_ignore = ((zflags & INTERIOR_TRANSP_IGNORE) != 0);
  328. use_grade_range = ((zflags & USE_GRADE_RANGE) != 0);
  329. prefer_dest_grade = ((zflags & PREFER_DEST_GRADE) != 0);
  330. inv_grade_range = ((zflags & INVERT_GRADE_RANGE) != 0);
  331. }
  332. void afxZodiacData::merge_zflags()
  333. {
  334. zflags = (blend_flags & BLEND_MASK);
  335. if (terrain_ok)
  336. zflags |= SHOW_ON_TERRAIN;
  337. if (interiors_ok)
  338. zflags |= SHOW_ON_INTERIORS;
  339. if (reflected_ok)
  340. zflags |= SHOW_IN_REFLECTIONS;
  341. if (non_reflected_ok)
  342. zflags |= SHOW_IN_NON_REFLECTIONS;
  343. if (respect_ori_cons)
  344. zflags |= RESPECT_ORIENTATION;
  345. if (scale_vert_range)
  346. zflags |= SCALE_VERT_RANGE;
  347. if (interior_h_only)
  348. zflags |= INTERIOR_HORIZ_ONLY;
  349. if (interior_v_ignore)
  350. zflags |= INTERIOR_VERT_IGNORE;
  351. if (interior_back_ignore)
  352. zflags |= INTERIOR_BACK_IGNORE;
  353. if (interior_opaque_ignore)
  354. zflags |= INTERIOR_OPAQUE_IGNORE;
  355. if (interior_transp_ignore)
  356. zflags |= INTERIOR_TRANSP_IGNORE;
  357. if (use_grade_range)
  358. zflags |= USE_GRADE_RANGE;
  359. if (prefer_dest_grade)
  360. zflags |= PREFER_DEST_GRADE;
  361. if (inv_grade_range)
  362. zflags |= INVERT_GRADE_RANGE;
  363. }
  364. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//