/indra/llprimitive/llvolumemessage.cpp

https://bitbucket.org/lindenlab/viewer-beta/ · C++ · 555 lines · 384 code · 105 blank · 66 comment · 13 complexity · cb335c8ff6f1b63e41504e7ab0b56955 MD5 · raw file

  1. /**
  2. * @file llvolumemessage.cpp
  3. * @brief LLVolumeMessage base class
  4. *
  5. * $LicenseInfo:firstyear=2001&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "linden_common.h"
  27. #include "message.h"
  28. #include "llvolumemessage.h"
  29. #include "lldatapacker.h"
  30. //============================================================================
  31. // LLVolumeMessage is just a wrapper class; all members are static
  32. //============================================================================
  33. bool LLVolumeMessage::packProfileParams(
  34. const LLProfileParams* params,
  35. LLMessageSystem *mesgsys)
  36. {
  37. // Default to cylinder
  38. static LLProfileParams defaultparams(LL_PCODE_PROFILE_CIRCLE, U16(0), U16(0), U16(0));
  39. if (!params)
  40. params = &defaultparams;
  41. U8 tempU8;
  42. U16 tempU16;
  43. tempU8 = params->getCurveType();
  44. mesgsys->addU8Fast(_PREHASH_ProfileCurve, tempU8);
  45. tempU16 = (U16) llround( params->getBegin() / CUT_QUANTA);
  46. mesgsys->addU16Fast(_PREHASH_ProfileBegin, tempU16);
  47. tempU16 = 50000 - (U16) llround(params->getEnd() / CUT_QUANTA);
  48. mesgsys->addU16Fast(_PREHASH_ProfileEnd, tempU16);
  49. tempU16 = (U16) llround(params->getHollow() / HOLLOW_QUANTA);
  50. mesgsys->addU16Fast(_PREHASH_ProfileHollow, tempU16);
  51. return true;
  52. }
  53. bool LLVolumeMessage::packProfileParams(
  54. const LLProfileParams* params,
  55. LLDataPacker &dp)
  56. {
  57. // Default to cylinder
  58. static LLProfileParams defaultparams(LL_PCODE_PROFILE_CIRCLE, U16(0), U16(0), U16(0));
  59. if (!params)
  60. params = &defaultparams;
  61. U8 tempU8;
  62. U16 tempU16;
  63. tempU8 = params->getCurveType();
  64. dp.packU8(tempU8, "Curve");
  65. tempU16 = (U16) llround( params->getBegin() / CUT_QUANTA);
  66. dp.packU16(tempU16, "Begin");
  67. tempU16 = 50000 - (U16) llround(params->getEnd() / CUT_QUANTA);
  68. dp.packU16(tempU16, "End");
  69. tempU16 = (U16) llround(params->getHollow() / HOLLOW_QUANTA);
  70. dp.packU16(tempU16, "Hollow");
  71. return true;
  72. }
  73. bool LLVolumeMessage::unpackProfileParams(
  74. LLProfileParams* params,
  75. LLMessageSystem* mesgsys,
  76. char const* block_name,
  77. S32 block_num)
  78. {
  79. bool ok = true;
  80. U8 temp_u8;
  81. U16 temp_u16;
  82. F32 temp_f32;
  83. mesgsys->getU8Fast(block_name, _PREHASH_ProfileCurve, temp_u8, block_num);
  84. params->setCurveType(temp_u8);
  85. mesgsys->getU16Fast(block_name, _PREHASH_ProfileBegin, temp_u16, block_num);
  86. temp_f32 = temp_u16 * CUT_QUANTA;
  87. if (temp_f32 > 1.f)
  88. {
  89. llwarns << "Profile begin out of range: " << temp_f32
  90. << ". Clamping to 0.0." << llendl;
  91. temp_f32 = 0.f;
  92. ok = false;
  93. }
  94. params->setBegin(temp_f32);
  95. mesgsys->getU16Fast(block_name, _PREHASH_ProfileEnd, temp_u16, block_num);
  96. temp_f32 = temp_u16 * CUT_QUANTA;
  97. if (temp_f32 > 1.f)
  98. {
  99. llwarns << "Profile end out of range: " << 1.f - temp_f32
  100. << ". Clamping to 1.0." << llendl;
  101. temp_f32 = 1.f;
  102. ok = false;
  103. }
  104. params->setEnd(1.f - temp_f32);
  105. mesgsys->getU16Fast(block_name, _PREHASH_ProfileHollow, temp_u16, block_num);
  106. temp_f32 = temp_u16 * HOLLOW_QUANTA;
  107. if (temp_f32 > 1.f)
  108. {
  109. llwarns << "Profile hollow out of range: " << temp_f32
  110. << ". Clamping to 0.0." << llendl;
  111. temp_f32 = 0.f;
  112. ok = false;
  113. }
  114. params->setHollow(temp_f32);
  115. /*
  116. llinfos << "Unpacking Profile Block " << block_num << llendl;
  117. llinfos << "Curve: " << (U32)getCurve() << llendl;
  118. llinfos << "Begin: " << getBegin() << llendl;
  119. llinfos << "End: " << getEnd() << llendl;
  120. llinfos << "Hollow: " << getHollow() << llendl;
  121. */
  122. return ok;
  123. }
  124. bool LLVolumeMessage::unpackProfileParams(
  125. LLProfileParams* params,
  126. LLDataPacker &dp)
  127. {
  128. bool ok = true;
  129. U8 temp_u8;
  130. U16 temp_u16;
  131. F32 temp_f32;
  132. dp.unpackU8(temp_u8, "Curve");
  133. params->setCurveType(temp_u8);
  134. dp.unpackU16(temp_u16, "Begin");
  135. temp_f32 = temp_u16 * CUT_QUANTA;
  136. if (temp_f32 > 1.f)
  137. {
  138. llwarns << "Profile begin out of range: " << temp_f32 << llendl;
  139. llwarns << "Clamping to 0.0" << llendl;
  140. temp_f32 = 0.f;
  141. ok = false;
  142. }
  143. params->setBegin(temp_f32);
  144. dp.unpackU16(temp_u16, "End");
  145. temp_f32 = temp_u16 * CUT_QUANTA;
  146. if (temp_f32 > 1.f)
  147. {
  148. llwarns << "Profile end out of range: " << 1.f - temp_f32 << llendl;
  149. llwarns << "Clamping to 1.0" << llendl;
  150. temp_f32 = 1.f;
  151. ok = false;
  152. }
  153. params->setEnd(1.f - temp_f32);
  154. dp.unpackU16(temp_u16, "Hollow");
  155. temp_f32 = temp_u16 * HOLLOW_QUANTA;
  156. if (temp_f32 > 1.f)
  157. {
  158. llwarns << "Profile hollow out of range: " << temp_f32 << llendl;
  159. llwarns << "Clamping to 0.0" << llendl;
  160. temp_f32 = 0.f;
  161. ok = false;
  162. }
  163. params->setHollow(temp_f32);
  164. return ok;
  165. }
  166. //============================================================================
  167. // Quantization:
  168. // For cut begin, range is 0 to 1, quanta is 0.005, 0 maps to 0
  169. // For cut end, range is 0 to 1, quanta is 0.005, 1 maps to 0
  170. // For scale, range is 0 to 1, quanta is 0.01, 0 maps to 0, 1 maps to 100
  171. // For shear, range is -0.5 to 0.5, quanta is 0.01, 0 maps to 0
  172. // For taper, range is -1 to 1, quanta is 0.01, 0 maps to 0
  173. bool LLVolumeMessage::packPathParams(
  174. const LLPathParams* params,
  175. LLMessageSystem *mesgsys)
  176. {
  177. // Default to cylinder with no cut, top same size as bottom, no shear, no twist
  178. static LLPathParams defaultparams(LL_PCODE_PATH_LINE, U8(0), U8(0), U8(0), U8(0), U8(0), U8(0), U8(0), U8(0), U8(0), U8(0), U8(0), U8(0), 0);
  179. if (!params)
  180. params = &defaultparams;
  181. U8 curve = params->getCurveType();
  182. mesgsys->addU8Fast(_PREHASH_PathCurve, curve);
  183. U16 begin = (U16) llround(params->getBegin() / CUT_QUANTA);
  184. mesgsys->addU16Fast(_PREHASH_PathBegin, begin);
  185. U16 end = 50000 - (U16) llround(params->getEnd() / CUT_QUANTA);
  186. mesgsys->addU16Fast(_PREHASH_PathEnd, end);
  187. // Avoid truncation problem with direct F32->U8 cast.
  188. // (e.g., (U8) (0.50 / 0.01) = (U8) 49.9999999 = 49 not 50.
  189. U8 pack_scale_x = 200 - (U8) llround(params->getScaleX() / SCALE_QUANTA);
  190. mesgsys->addU8Fast(_PREHASH_PathScaleX, pack_scale_x );
  191. U8 pack_scale_y = 200 - (U8) llround(params->getScaleY() / SCALE_QUANTA);
  192. mesgsys->addU8Fast(_PREHASH_PathScaleY, pack_scale_y );
  193. U8 pack_shear_x = (U8) llround(params->getShearX() / SHEAR_QUANTA);
  194. mesgsys->addU8Fast(_PREHASH_PathShearX, pack_shear_x );
  195. U8 pack_shear_y = (U8) llround(params->getShearY() / SHEAR_QUANTA);
  196. mesgsys->addU8Fast(_PREHASH_PathShearY, pack_shear_y );
  197. S8 twist = (S8) llround(params->getTwist() / SCALE_QUANTA);
  198. mesgsys->addS8Fast(_PREHASH_PathTwist, twist);
  199. S8 twist_begin = (S8) llround(params->getTwistBegin() / SCALE_QUANTA);
  200. mesgsys->addS8Fast(_PREHASH_PathTwistBegin, twist_begin);
  201. S8 radius_offset = (S8) llround(params->getRadiusOffset() / SCALE_QUANTA);
  202. mesgsys->addS8Fast(_PREHASH_PathRadiusOffset, radius_offset);
  203. S8 taper_x = (S8) llround(params->getTaperX() / TAPER_QUANTA);
  204. mesgsys->addS8Fast(_PREHASH_PathTaperX, taper_x);
  205. S8 taper_y = (S8) llround(params->getTaperY() / TAPER_QUANTA);
  206. mesgsys->addS8Fast(_PREHASH_PathTaperY, taper_y);
  207. U8 revolutions = (U8) llround( (params->getRevolutions() - 1.0f) / REV_QUANTA);
  208. mesgsys->addU8Fast(_PREHASH_PathRevolutions, revolutions);
  209. S8 skew = (S8) llround(params->getSkew() / SCALE_QUANTA);
  210. mesgsys->addS8Fast(_PREHASH_PathSkew, skew);
  211. return true;
  212. }
  213. bool LLVolumeMessage::packPathParams(
  214. const LLPathParams* params,
  215. LLDataPacker &dp)
  216. {
  217. // Default to cylinder with no cut, top same size as bottom, no shear, no twist
  218. static LLPathParams defaultparams(LL_PCODE_PATH_LINE, U8(0), U8(0), U8(0), U8(0), U8(0), U8(0), U8(0), U8(0), U8(0), U8(0), U8(0), U8(0), 0);
  219. if (!params)
  220. params = &defaultparams;
  221. U8 curve = params->getCurveType();
  222. dp.packU8(curve, "Curve");
  223. U16 begin = (U16) llround(params->getBegin() / CUT_QUANTA);
  224. dp.packU16(begin, "Begin");
  225. U16 end = 50000 - (U16) llround(params->getEnd() / CUT_QUANTA);
  226. dp.packU16(end, "End");
  227. // Avoid truncation problem with direct F32->U8 cast.
  228. // (e.g., (U8) (0.50 / 0.01) = (U8) 49.9999999 = 49 not 50.
  229. U8 pack_scale_x = 200 - (U8) llround(params->getScaleX() / SCALE_QUANTA);
  230. dp.packU8(pack_scale_x, "ScaleX");
  231. U8 pack_scale_y = 200 - (U8) llround(params->getScaleY() / SCALE_QUANTA);
  232. dp.packU8(pack_scale_y, "ScaleY");
  233. S8 pack_shear_x = (S8) llround(params->getShearX() / SHEAR_QUANTA);
  234. dp.packU8(*(U8 *)&pack_shear_x, "ShearX");
  235. S8 pack_shear_y = (S8) llround(params->getShearY() / SHEAR_QUANTA);
  236. dp.packU8(*(U8 *)&pack_shear_y, "ShearY");
  237. S8 twist = (S8) llround(params->getTwist() / SCALE_QUANTA);
  238. dp.packU8(*(U8 *)&twist, "Twist");
  239. S8 twist_begin = (S8) llround(params->getTwistBegin() / SCALE_QUANTA);
  240. dp.packU8(*(U8 *)&twist_begin, "TwistBegin");
  241. S8 radius_offset = (S8) llround(params->getRadiusOffset() / SCALE_QUANTA);
  242. dp.packU8(*(U8 *)&radius_offset, "RadiusOffset");
  243. S8 taper_x = (S8) llround(params->getTaperX() / TAPER_QUANTA);
  244. dp.packU8(*(U8 *)&taper_x, "TaperX");
  245. S8 taper_y = (S8) llround(params->getTaperY() / TAPER_QUANTA);
  246. dp.packU8(*(U8 *)&taper_y, "TaperY");
  247. U8 revolutions = (U8) llround( (params->getRevolutions() - 1.0f) / REV_QUANTA);
  248. dp.packU8(*(U8 *)&revolutions, "Revolutions");
  249. S8 skew = (S8) llround(params->getSkew() / SCALE_QUANTA);
  250. dp.packU8(*(U8 *)&skew, "Skew");
  251. return true;
  252. }
  253. bool LLVolumeMessage::unpackPathParams(
  254. LLPathParams* params,
  255. LLMessageSystem* mesgsys,
  256. char const* block_name,
  257. S32 block_num)
  258. {
  259. U8 curve;
  260. mesgsys->getU8Fast(block_name, _PREHASH_PathCurve, curve, block_num);
  261. params->setCurveType(curve);
  262. U16 begin;
  263. mesgsys->getU16Fast(block_name, _PREHASH_PathBegin, begin, block_num);
  264. params->setBegin((F32)(begin * CUT_QUANTA));
  265. U16 end;
  266. mesgsys->getU16Fast(block_name, _PREHASH_PathEnd, end, block_num);
  267. params->setEnd((F32)((50000 - end) * CUT_QUANTA));
  268. U8 pack_scale_x, pack_scale_y;
  269. mesgsys->getU8Fast(block_name, _PREHASH_PathScaleX, pack_scale_x, block_num);
  270. mesgsys->getU8Fast(block_name, _PREHASH_PathScaleY, pack_scale_y, block_num);
  271. F32 x = (F32) (200 - pack_scale_x) * SCALE_QUANTA;
  272. F32 y = (F32) (200 - pack_scale_y) * SCALE_QUANTA;
  273. params->setScale( x, y );
  274. S8 shear_x_quant, shear_y_quant;
  275. mesgsys->getS8Fast(block_name, _PREHASH_PathShearX, shear_x_quant, block_num);
  276. mesgsys->getS8Fast(block_name, _PREHASH_PathShearY, shear_y_quant, block_num);
  277. F32 shear_x = (F32) shear_x_quant * SHEAR_QUANTA;
  278. F32 shear_y = (F32) shear_y_quant * SHEAR_QUANTA;
  279. params->setShear( shear_x, shear_y );
  280. S8 twist;
  281. mesgsys->getS8Fast(block_name, _PREHASH_PathTwist, twist, block_num );
  282. params->setTwist((F32)(twist * SCALE_QUANTA));
  283. S8 twist_begin;
  284. mesgsys->getS8Fast(block_name, _PREHASH_PathTwistBegin, twist_begin, block_num );
  285. params->setTwistBegin((F32)(twist_begin * SCALE_QUANTA));
  286. S8 radius_offset;
  287. mesgsys->getS8Fast(block_name, _PREHASH_PathRadiusOffset, radius_offset, block_num );
  288. params->setRadiusOffset((F32)(radius_offset * SCALE_QUANTA));
  289. S8 taper_x_quant, taper_y_quant;
  290. mesgsys->getS8Fast(block_name, _PREHASH_PathTaperX, taper_x_quant, block_num );
  291. mesgsys->getS8Fast(block_name, _PREHASH_PathTaperY, taper_y_quant, block_num );
  292. F32 taper_x = (F32)(taper_x_quant * TAPER_QUANTA);
  293. F32 taper_y = (F32)(taper_y_quant * TAPER_QUANTA);
  294. params->setTaper( taper_x, taper_y );
  295. U8 revolutions;
  296. mesgsys->getU8Fast(block_name, _PREHASH_PathRevolutions, revolutions, block_num );
  297. params->setRevolutions((F32)(revolutions * REV_QUANTA + 1.0f));
  298. S8 skew;
  299. mesgsys->getS8Fast(block_name, _PREHASH_PathSkew, skew, block_num );
  300. params->setSkew((F32)(skew * SCALE_QUANTA));
  301. /*
  302. llinfos << "Unpacking Path Block " << block_num << llendl;
  303. llinfos << "Curve: " << (U32)params->getCurve() << llendl;
  304. llinfos << "Begin: " << params->getBegin() << llendl;
  305. llinfos << "End: " << params->getEnd() << llendl;
  306. llinfos << "Scale: " << params->getScale() << llendl;
  307. llinfos << "Twist: " << params->getTwist() << llendl;
  308. */
  309. return true;
  310. }
  311. bool LLVolumeMessage::unpackPathParams(LLPathParams* params, LLDataPacker &dp)
  312. {
  313. U8 value;
  314. S8 svalue;
  315. U16 temp_u16;
  316. dp.unpackU8(value, "Curve");
  317. params->setCurveType( value );
  318. dp.unpackU16(temp_u16, "Begin");
  319. params->setBegin((F32)(temp_u16 * CUT_QUANTA));
  320. dp.unpackU16(temp_u16, "End");
  321. params->setEnd((F32)((50000 - temp_u16) * CUT_QUANTA));
  322. dp.unpackU8(value, "ScaleX");
  323. F32 x = (F32) (200 - value) * SCALE_QUANTA;
  324. dp.unpackU8(value, "ScaleY");
  325. F32 y = (F32) (200 - value) * SCALE_QUANTA;
  326. params->setScale( x, y );
  327. dp.unpackU8(value, "ShearX");
  328. svalue = *(S8 *)&value;
  329. F32 shear_x = (F32) svalue * SHEAR_QUANTA;
  330. dp.unpackU8(value, "ShearY");
  331. svalue = *(S8 *)&value;
  332. F32 shear_y = (F32) svalue * SHEAR_QUANTA;
  333. params->setShear( shear_x, shear_y );
  334. dp.unpackU8(value, "Twist");
  335. svalue = *(S8 *)&value;
  336. params->setTwist((F32)(svalue * SCALE_QUANTA));
  337. dp.unpackU8(value, "TwistBegin");
  338. svalue = *(S8 *)&value;
  339. params->setTwistBegin((F32)(svalue * SCALE_QUANTA));
  340. dp.unpackU8(value, "RadiusOffset");
  341. svalue = *(S8 *)&value;
  342. params->setRadiusOffset((F32)(svalue * SCALE_QUANTA));
  343. dp.unpackU8(value, "TaperX");
  344. svalue = *(S8 *)&value;
  345. params->setTaperX((F32)(svalue * TAPER_QUANTA));
  346. dp.unpackU8(value, "TaperY");
  347. svalue = *(S8 *)&value;
  348. params->setTaperY((F32)(svalue * TAPER_QUANTA));
  349. dp.unpackU8(value, "Revolutions");
  350. params->setRevolutions((F32)(value * REV_QUANTA + 1.0f));
  351. dp.unpackU8(value, "Skew");
  352. svalue = *(S8 *)&value;
  353. params->setSkew((F32)(svalue * SCALE_QUANTA));
  354. return true;
  355. }
  356. //============================================================================
  357. // static
  358. bool LLVolumeMessage::constrainVolumeParams(LLVolumeParams& params)
  359. {
  360. U32 bad = 0;
  361. // This is called immediately after an unpack. feed the raw data
  362. // through the checked setters to constraint it to a valid set of
  363. // volume params.
  364. bad |= params.setType(params.getProfileParams().getCurveType(),
  365. params.getPathParams().getCurveType()) ? 0 : 1;
  366. bad |= params.setBeginAndEndS(params.getProfileParams().getBegin(),
  367. params.getProfileParams().getEnd()) ? 0 : 2;
  368. bad |= params.setBeginAndEndT(params.getPathParams().getBegin(),
  369. params.getPathParams().getEnd()) ? 0 : 4;
  370. bad |= params.setHollow(params.getProfileParams().getHollow()) ? 0 : 8;
  371. bad |= params.setTwistBegin(params.getPathParams().getTwistBegin()) ? 0 : 0x10;
  372. bad |= params.setTwistEnd(params.getPathParams().getTwistEnd()) ? 0 : 0x20;
  373. bad |= params.setRatio(params.getPathParams().getScaleX(),
  374. params.getPathParams().getScaleY()) ? 0 : 0x40;
  375. bad |= params.setShear(params.getPathParams().getShearX(),
  376. params.getPathParams().getShearY()) ? 0 : 0x80;
  377. bad |= params.setTaper(params.getPathParams().getTaperX(),
  378. params.getPathParams().getTaperY()) ? 0 : 0x100;
  379. bad |= params.setRevolutions(params.getPathParams().getRevolutions()) ? 0 : 0x200;
  380. bad |= params.setRadiusOffset(params.getPathParams().getRadiusOffset()) ? 0 : 0x400;
  381. bad |= params.setSkew(params.getPathParams().getSkew()) ? 0 : 0x800;
  382. if(bad)
  383. {
  384. llwarns << "LLVolumeMessage::constrainVolumeParams() - "
  385. << "forced to constrain incoming volume params: "
  386. << llformat("0x%04x",bad) << llendl;
  387. }
  388. return bad ? false : true;
  389. }
  390. bool LLVolumeMessage::packVolumeParams(const LLVolumeParams* params, LLMessageSystem *mesgsys)
  391. {
  392. // llinfos << "pack volume" << llendl;
  393. if (params)
  394. {
  395. packPathParams(&params->getPathParams(), mesgsys);
  396. packProfileParams(&params->getProfileParams(), mesgsys);
  397. }
  398. else
  399. {
  400. packPathParams(0, mesgsys);
  401. packProfileParams(0, mesgsys);
  402. }
  403. return true;
  404. }
  405. bool LLVolumeMessage::packVolumeParams(const LLVolumeParams* params, LLDataPacker &dp)
  406. {
  407. // llinfos << "pack volume" << llendl;
  408. if (params)
  409. {
  410. packPathParams(&params->getPathParams(), dp);
  411. packProfileParams(&params->getProfileParams(), dp);
  412. }
  413. else
  414. {
  415. packPathParams(0, dp);
  416. packProfileParams(0, dp);
  417. }
  418. return true;
  419. }
  420. bool LLVolumeMessage::unpackVolumeParams(
  421. LLVolumeParams* params,
  422. LLMessageSystem* mesgsys,
  423. char const* block_name,
  424. S32 block_num)
  425. {
  426. bool ok = true;
  427. ok &= unpackPathParams(
  428. &params->getPathParams(),
  429. mesgsys,
  430. block_name,
  431. block_num);
  432. ok &= unpackProfileParams(
  433. &params->getProfileParams(),
  434. mesgsys,
  435. block_name,
  436. block_num);
  437. ok &= constrainVolumeParams(*params);
  438. return ok;
  439. }
  440. bool LLVolumeMessage::unpackVolumeParams(
  441. LLVolumeParams* params,
  442. LLDataPacker &dp)
  443. {
  444. bool ok = true;
  445. ok &= unpackPathParams(&params->getPathParams(), dp);
  446. ok &= unpackProfileParams(&params->getProfileParams(), dp);
  447. ok &= constrainVolumeParams(*params);
  448. return ok;
  449. }
  450. //============================================================================