llpartdata.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. /**
  2. * @file llpartdata.cpp
  3. * @brief Particle system data packing
  4. *
  5. * $LicenseInfo:firstyear=2003&license=viewergpl$
  6. *
  7. * Copyright (c) 2003-2009, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #include "linden_common.h"
  33. #include "llpartdata.h"
  34. #include "lldatapacker.h"
  35. #include "llsdutil.h"
  36. #include "llsdutil_math.h"
  37. #include "llmessage.h"
  38. #include "llcolor4u.h"
  39. constexpr S32 PS_PART_DATA_GLOW_SIZE = 2;
  40. constexpr S32 PS_PART_DATA_BLEND_SIZE = 2;
  41. constexpr S32 PS_LEGACY_PART_DATA_BLOCK_SIZE = 4 + 2 + 4 + 4 + 2 + 2; // 18
  42. constexpr S32 PS_SYS_DATA_BLOCK_SIZE = 68;
  43. constexpr S32 PS_MAX_DATA_BLOCK_SIZE = PS_SYS_DATA_BLOCK_SIZE +
  44. PS_LEGACY_PART_DATA_BLOCK_SIZE +
  45. PS_PART_DATA_BLEND_SIZE +
  46. PS_PART_DATA_GLOW_SIZE +
  47. 8; // Two S32 size fields
  48. constexpr S32 PS_LEGACY_DATA_BLOCK_SIZE = PS_SYS_DATA_BLOCK_SIZE +
  49. PS_LEGACY_PART_DATA_BLOCK_SIZE;
  50. S32 LLPartData::getSize() const
  51. {
  52. S32 size = PS_LEGACY_PART_DATA_BLOCK_SIZE;
  53. if (hasGlow())
  54. {
  55. size += PS_PART_DATA_GLOW_SIZE;
  56. }
  57. if (hasBlendFunc())
  58. {
  59. size += PS_PART_DATA_BLEND_SIZE;
  60. }
  61. return size;
  62. }
  63. bool LLPartData::unpackLegacy(LLDataPacker& dp)
  64. {
  65. LLColor4U coloru;
  66. dp.unpackU32(mFlags, "pdflags");
  67. dp.unpackFixed(mMaxAge, "pdmaxage", false, 8, 8);
  68. dp.unpackColor4U(coloru, "pdstartcolor");
  69. mStartColor.set(coloru);
  70. dp.unpackColor4U(coloru, "pdendcolor");
  71. mEndColor.set(coloru);
  72. dp.unpackFixed(mStartScale.mV[0], "pdstartscalex", false, 3, 5);
  73. dp.unpackFixed(mStartScale.mV[1], "pdstartscaley", false, 3, 5);
  74. dp.unpackFixed(mEndScale.mV[0], "pdendscalex", false, 3, 5);
  75. dp.unpackFixed(mEndScale.mV[1], "pdendscaley", false, 3, 5);
  76. mStartGlow = 0.f;
  77. mEndGlow = 0.f;
  78. mBlendFuncSource = LL_PART_BF_SOURCE_ALPHA;
  79. mBlendFuncDest = LL_PART_BF_ONE_MINUS_SOURCE_ALPHA;
  80. return true;
  81. }
  82. bool LLPartData::unpack(LLDataPacker& dp)
  83. {
  84. S32 size = 0;
  85. dp.unpackS32(size, "partsize");
  86. unpackLegacy(dp);
  87. size -= PS_LEGACY_PART_DATA_BLOCK_SIZE;
  88. if (mFlags & LL_PART_DATA_GLOW)
  89. {
  90. if (size < PS_PART_DATA_GLOW_SIZE)
  91. {
  92. return false;
  93. }
  94. constexpr F32 scaler = 1.f / 255.f;
  95. U8 tmp_glow = 0;
  96. dp.unpackU8(tmp_glow, "pdstartglow");
  97. mStartGlow = tmp_glow * scaler;
  98. dp.unpackU8(tmp_glow, "pdendglow");
  99. mEndGlow = tmp_glow * scaler;
  100. size -= PS_PART_DATA_GLOW_SIZE;
  101. }
  102. else
  103. {
  104. mStartGlow = 0.f;
  105. mEndGlow = 0.f;
  106. }
  107. if (mFlags & LL_PART_DATA_BLEND)
  108. {
  109. if (size < PS_PART_DATA_BLEND_SIZE)
  110. {
  111. return false;
  112. }
  113. dp.unpackU8(mBlendFuncSource, "pdblendsource");
  114. dp.unpackU8(mBlendFuncDest, "pdblenddest");
  115. size -= PS_PART_DATA_BLEND_SIZE;
  116. }
  117. else
  118. {
  119. mBlendFuncSource = LL_PART_BF_SOURCE_ALPHA;
  120. mBlendFuncDest = LL_PART_BF_ONE_MINUS_SOURCE_ALPHA;
  121. }
  122. if (size > 0)
  123. {
  124. // Leftover bytes, unrecognized parameters
  125. U8 feh = 0;
  126. while (size > 0)
  127. {
  128. // Read remaining bytes in block
  129. dp.unpackU8(feh, "whippang");
  130. --size;
  131. }
  132. // This particle system wo uld not display properly, better to not show
  133. // anything
  134. return false;
  135. }
  136. return true;
  137. }
  138. LLPartSysData::LLPartSysData()
  139. {
  140. mCRC = 0;
  141. mFlags = 0;
  142. mPartData.mFlags = 0;
  143. mPartData.mStartColor = LLColor4(1.f, 1.f, 1.f, 1.f);
  144. mPartData.mEndColor = LLColor4(1.f, 1.f, 1.f, 1.f);
  145. mPartData.mStartScale = LLVector2(1.f, 1.f);
  146. mPartData.mEndScale = LLVector2(1.f, 1.f);
  147. mPartData.mMaxAge = 10.0;
  148. mPartData.mBlendFuncSource = LLPartData::LL_PART_BF_SOURCE_ALPHA;
  149. mPartData.mBlendFuncDest = LLPartData::LL_PART_BF_ONE_MINUS_SOURCE_ALPHA;
  150. mPartData.mStartGlow = 0.f;
  151. mPartData.mEndGlow = 0.f;
  152. mMaxAge = 0.0;
  153. mStartAge = 0.0;
  154. mPattern = LL_PART_SRC_PATTERN_DROP; // Pattern for particle velocity
  155. mInnerAngle = 0.0; // Inner angle of PATTERN_ANGLE_*
  156. mOuterAngle = 0.0; // Outer angle of PATTERN_ANGLE_*
  157. mBurstRate = 0.1f; // How often to do a burst of particles
  158. mBurstPartCount = 1; // How many particles in a burst
  159. mBurstSpeedMin = 1.f; // Minimum particle velocity
  160. mBurstSpeedMax = 1.f; // Maximum particle velocity
  161. mBurstRadius = 0.f;
  162. mNumParticles = 0;
  163. }
  164. bool LLPartSysData::unpackSystem(LLDataPacker& dp)
  165. {
  166. dp.unpackU32(mCRC, "pscrc");
  167. dp.unpackU32(mFlags, "psflags");
  168. dp.unpackU8(mPattern, "pspattern");
  169. dp.unpackFixed(mMaxAge, "psmaxage", false, 8, 8);
  170. dp.unpackFixed(mStartAge, "psstartage", false, 8, 8);
  171. dp.unpackFixed(mInnerAngle, "psinnerangle", false, 3, 5);
  172. dp.unpackFixed(mOuterAngle, "psouterangle", false, 3, 5);
  173. dp.unpackFixed(mBurstRate, "psburstrate", false, 8, 8);
  174. mBurstRate = llmax(0.01f, mBurstRate);
  175. dp.unpackFixed(mBurstRadius, "psburstradius", false, 8, 8);
  176. dp.unpackFixed(mBurstSpeedMin, "psburstspeedmin", false, 8, 8);
  177. dp.unpackFixed(mBurstSpeedMax, "psburstspeedmax", false, 8, 8);
  178. dp.unpackU8(mBurstPartCount, "psburstpartcount");
  179. dp.unpackFixed(mAngularVelocity.mV[0], "psangvelx", true, 8, 7);
  180. dp.unpackFixed(mAngularVelocity.mV[1], "psangvely", true, 8, 7);
  181. dp.unpackFixed(mAngularVelocity.mV[2], "psangvelz", true, 8, 7);
  182. dp.unpackFixed(mPartAccel.mV[0], "psaccelx", true, 8, 7);
  183. dp.unpackFixed(mPartAccel.mV[1], "psaccely", true, 8, 7);
  184. dp.unpackFixed(mPartAccel.mV[2], "psaccelz", true, 8, 7);
  185. dp.unpackUUID(mPartImageID, "psuuid");
  186. dp.unpackUUID(mTargetUUID, "pstargetuuid");
  187. return true;
  188. }
  189. bool LLPartSysData::unpackLegacy(LLDataPacker& dp)
  190. {
  191. unpackSystem(dp);
  192. mPartData.unpackLegacy(dp);
  193. return true;
  194. }
  195. bool LLPartSysData::unpack(LLDataPacker& dp)
  196. {
  197. // syssize is currently unused. Adding now when modifying the version to
  198. // make extensible in the future
  199. S32 size = 0;
  200. dp.unpackS32(size, "syssize");
  201. if (size != PS_SYS_DATA_BLOCK_SIZE)
  202. {
  203. // Unexpected size, this viewer does not know how to parse this
  204. // particle system.
  205. // Skip to LLPartData block
  206. U8 feh = 0;
  207. for (S32 i = 0; i < size; ++i)
  208. {
  209. dp.unpackU8(feh, "whippang");
  210. }
  211. dp.unpackS32(size, "partsize");
  212. // Skip LLPartData block
  213. for (S32 i = 0; i < size; ++i)
  214. {
  215. dp.unpackU8(feh, "whippang");
  216. }
  217. return false;
  218. }
  219. unpackSystem(dp);
  220. return mPartData.unpack(dp);
  221. }
  222. std::ostream& operator<<(std::ostream& s, const LLPartSysData& data)
  223. {
  224. s << "Flags: " << std::hex << data.mFlags << std::dec;
  225. s << " Pattern: " << std::hex << (U32)data.mPattern << std::dec << "\n";
  226. s << "Source age: [" << data.mStartAge << ", " << data.mMaxAge << "]\n";
  227. s << "Particle Age: " << data.mPartData.mMaxAge << "\n";
  228. s << "Angle: [" << data.mInnerAngle << ", " << data.mOuterAngle << "]\n";
  229. s << "Burst rate: " << data.mBurstRate << "\n";
  230. s << "Burst radius: " << data.mBurstRadius << "\n";
  231. s << "Burst speed: [" << data.mBurstSpeedMin << ", "
  232. << data.mBurstSpeedMax << "]\n";
  233. s << "Burst part count: " << std::hex << (U32)data.mBurstPartCount
  234. << std::dec << "\n";
  235. s << "Angular velocity: " << data.mAngularVelocity << "\n";
  236. s << "Accel: " << data.mPartAccel;
  237. return s;
  238. }
  239. bool LLPartSysData::isNullPS(S32 block_num)
  240. {
  241. LLMessageSystem* msg = gMessageSystemp;
  242. // Check size of block
  243. S32 size;
  244. size = msg->getSize("ObjectData", block_num, "PSBlock");
  245. if (size == 0)
  246. {
  247. return true; // Valid, null particle system
  248. }
  249. if (size < 0)
  250. {
  251. llwarns << "Error decoding ObjectData/PSBlock" << llendl;
  252. return true;
  253. }
  254. if (size > PS_MAX_DATA_BLOCK_SIZE)
  255. {
  256. llwarns_once << "PSBlock is wrong size for particle system data: "
  257. << " unknown/unsupported particle system." << llendl;
  258. return true; // Invalid particle system. Treat as null.
  259. }
  260. U8 ps_data_block[PS_MAX_DATA_BLOCK_SIZE];
  261. msg->getBinaryData("ObjectData", "PSBlock", ps_data_block, size,
  262. block_num, PS_MAX_DATA_BLOCK_SIZE);
  263. LLDataPackerBinaryBuffer dp(ps_data_block, size);
  264. if (size > PS_LEGACY_DATA_BLOCK_SIZE)
  265. {
  266. // non legacy systems pack a size before the CRC
  267. S32 tmp = 0;
  268. dp.unpackS32(tmp, "syssize");
  269. if (tmp > PS_SYS_DATA_BLOCK_SIZE)
  270. {
  271. // Unknown system data block size, do not know how to parse it,
  272. // treat as null.
  273. llwarns_once << "PSBlock is wrong size for particle system data: "
  274. << " unknown/unsupported particle system." << llendl;
  275. return true;
  276. }
  277. }
  278. U32 crc;
  279. dp.unpackU32(crc, "crc");
  280. return crc == 0;
  281. }
  282. bool LLPartSysData::unpackBlock(S32 block_num)
  283. {
  284. LLMessageSystem* msg = gMessageSystemp;
  285. U8 ps_data_block[PS_MAX_DATA_BLOCK_SIZE];
  286. // Check size of block
  287. S32 size = msg->getSize("ObjectData", block_num, "PSBlock");
  288. if (size <= 0)
  289. {
  290. llwarns << "Error decoding ObjectData/PSBlock" << llendl;
  291. return false;
  292. }
  293. if (size > PS_MAX_DATA_BLOCK_SIZE)
  294. {
  295. llwarns_once << "PSBlock is wrong size for particle system data: "
  296. << " unknown/unsupported particle system." << llendl;
  297. return false;
  298. }
  299. // Get from message
  300. msg->getBinaryData("ObjectData", "PSBlock", ps_data_block,
  301. size, block_num, PS_MAX_DATA_BLOCK_SIZE);
  302. LLDataPackerBinaryBuffer dp(ps_data_block, size);
  303. if (size == PS_LEGACY_DATA_BLOCK_SIZE)
  304. {
  305. return unpackLegacy(dp);
  306. }
  307. return unpack(dp);
  308. }
  309. void LLPartSysData::clampSourceParticleRate()
  310. {
  311. if (mBurstRate > 0.f) // Paranoia
  312. {
  313. F32 particle_rate = (F32)mBurstPartCount / mBurstRate;
  314. if (particle_rate > 256.f)
  315. {
  316. mBurstPartCount = llfloor((F32)mBurstPartCount * 256.f /
  317. particle_rate);
  318. }
  319. }
  320. }