/** * @file llvolumemessage.cpp * @brief LLVolumeMessage base class * * $LicenseInfo:firstyear=2001&license=viewergpl$ * * Copyright (c) 2001-2009, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab * to you under the terms of the GNU General Public License, version 2.0 * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or * online at * http://secondlifegrid.net/programs/open_source/licensing/flossexception * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, * and agree to abide by those obligations. * * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, * COMPLETENESS OR PERFORMANCE. * $/LicenseInfo$ */ #include "linden_common.h" #include "llvolumemessage.h" #include "lldatapacker.h" #include "llmessage.h" //static bool LLVolumeMessage::sIgnoreBadRatio = false; //static bool LLVolumeMessage::packProfileParams(const LLProfileParams* params, LLMessageSystem* mesgsys) { // Default to cylinder static LLProfileParams defaultparams(LL_PCODE_PROFILE_CIRCLE, U16(0), U16(0), U16(0)); if (!params) { params = &defaultparams; } U8 tempU8 = params->getCurveType(); mesgsys->addU8Fast(_PREHASH_ProfileCurve, tempU8); U16 tempU16 = (U16)ll_round(params->getBegin() / CUT_QUANTA); mesgsys->addU16Fast(_PREHASH_ProfileBegin, tempU16); tempU16 = 50000 - (U16)ll_round(params->getEnd() / CUT_QUANTA); mesgsys->addU16Fast(_PREHASH_ProfileEnd, tempU16); tempU16 = (U16)ll_round(params->getHollow() / HOLLOW_QUANTA); mesgsys->addU16Fast(_PREHASH_ProfileHollow, tempU16); return true; } //static bool LLVolumeMessage::packProfileParams(const LLProfileParams* params, LLDataPacker& dp) { // Default to cylinder static LLProfileParams defaultparams(LL_PCODE_PROFILE_CIRCLE, U16(0), U16(0), U16(0)); if (!params) { params = &defaultparams; } U8 tempU8 = params->getCurveType(); dp.packU8(tempU8, "Curve"); U16 tempU16 = (U16)ll_round(params->getBegin() / CUT_QUANTA); dp.packU16(tempU16, "Begin"); tempU16 = 50000 - (U16)ll_round(params->getEnd() / CUT_QUANTA); dp.packU16(tempU16, "End"); tempU16 = (U16)ll_round(params->getHollow() / HOLLOW_QUANTA); dp.packU16(tempU16, "Hollow"); return true; } //static bool LLVolumeMessage::unpackProfileParams(LLProfileParams* params, LLMessageSystem* mesgsys, char const* block_name, S32 block_num) { bool ok = true; U8 temp_u8; mesgsys->getU8Fast(block_name, _PREHASH_ProfileCurve, temp_u8, block_num); params->setCurveType(temp_u8); U16 temp_u16; mesgsys->getU16Fast(block_name, _PREHASH_ProfileBegin, temp_u16, block_num); F32 temp_f32 = temp_u16 * CUT_QUANTA; if (temp_f32 > 1.f) { llwarns << "Profile begin out of range: " << temp_f32 << ". Clamping to 0.0." << llendl; temp_f32 = 0.f; ok = false; } params->setBegin(temp_f32); mesgsys->getU16Fast(block_name, _PREHASH_ProfileEnd, temp_u16, block_num); temp_f32 = temp_u16 * CUT_QUANTA; if (temp_f32 > 1.f) { llwarns << "Profile end out of range: " << 1.f - temp_f32 << ". Clamping to 1.0." << llendl; temp_f32 = 1.f; ok = false; } params->setEnd(1.f - temp_f32); mesgsys->getU16Fast(block_name, _PREHASH_ProfileHollow, temp_u16, block_num); temp_f32 = temp_u16 * HOLLOW_QUANTA; if (temp_f32 > 1.f) { llwarns << "Profile hollow out of range: " << temp_f32 << ". Clamping to 0.0." << llendl; temp_f32 = 0.f; ok = false; } params->setHollow(temp_f32); return ok; } //static bool LLVolumeMessage::unpackProfileParams(LLProfileParams* params, LLDataPacker& dp) { bool ok = true; U8 temp_u8; dp.unpackU8(temp_u8, "Curve"); params->setCurveType(temp_u8); U16 temp_u16; dp.unpackU16(temp_u16, "Begin"); F32 temp_f32 = temp_u16 * CUT_QUANTA; if (temp_f32 > 1.f) { llwarns << "Profile begin out of range: " << temp_f32 << llendl; llwarns << "Clamping to 0.0" << llendl; temp_f32 = 0.f; ok = false; } params->setBegin(temp_f32); dp.unpackU16(temp_u16, "End"); temp_f32 = temp_u16 * CUT_QUANTA; if (temp_f32 > 1.f) { llwarns << "Profile end out of range: " << 1.f - temp_f32 << llendl; llwarns << "Clamping to 1.0" << llendl; temp_f32 = 1.f; ok = false; } params->setEnd(1.f - temp_f32); dp.unpackU16(temp_u16, "Hollow"); temp_f32 = temp_u16 * HOLLOW_QUANTA; if (temp_f32 > 1.f) { llwarns << "Profile hollow out of range: " << temp_f32 << llendl; llwarns << "Clamping to 0.0" << llendl; temp_f32 = 0.f; ok = false; } params->setHollow(temp_f32); return ok; } // Quantization: // For cut begin, range is 0 to 1, quanta is 0.005, 0 maps to 0 // For cut end, range is 0 to 1, quanta is 0.005, 1 maps to 0 // For scale, range is 0 to 1, quanta is 0.01, 0 maps to 0, 1 maps to 100 // For shear, range is -0.5 to 0.5, quanta is 0.01, 0 maps to 0 // For taper, range is -1 to 1, quanta is 0.01, 0 maps to 0 //static bool LLVolumeMessage::packPathParams(const LLPathParams* params, LLMessageSystem* mesgsys) { // Default to cylinder with no cut, top same size as bottom, no shear, no // twist 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); if (!params) { params = &defaultparams; } U8 curve = params->getCurveType(); mesgsys->addU8Fast(_PREHASH_PathCurve, curve); U16 begin = (U16)ll_round(params->getBegin() / CUT_QUANTA); mesgsys->addU16Fast(_PREHASH_PathBegin, begin); U16 end = 50000 - (U16)ll_round(params->getEnd() / CUT_QUANTA); mesgsys->addU16Fast(_PREHASH_PathEnd, end); // Avoid truncation problem with direct F32->U8 cast. // (e.g., (U8) (0.50 / 0.01) = (U8) 49.9999999 = 49 not 50. U8 pack_scale_x = 200 - (U8)ll_round(params->getScaleX() / SCALE_QUANTA); mesgsys->addU8Fast(_PREHASH_PathScaleX, pack_scale_x); U8 pack_scale_y = 200 - (U8)ll_round(params->getScaleY() / SCALE_QUANTA); mesgsys->addU8Fast(_PREHASH_PathScaleY, pack_scale_y); U8 pack_shear_x = (U8)ll_round(params->getShearX() / SHEAR_QUANTA); mesgsys->addU8Fast(_PREHASH_PathShearX, pack_shear_x); U8 pack_shear_y = (U8)ll_round(params->getShearY() / SHEAR_QUANTA); mesgsys->addU8Fast(_PREHASH_PathShearY, pack_shear_y); S8 twist = (S8)ll_round(params->getTwistEnd() / SCALE_QUANTA); mesgsys->addS8Fast(_PREHASH_PathTwist, twist); S8 twist_begin = (S8)ll_round(params->getTwistBegin() / SCALE_QUANTA); mesgsys->addS8Fast(_PREHASH_PathTwistBegin, twist_begin); S8 radius_offset = (S8)ll_round(params->getRadiusOffset() / SCALE_QUANTA); mesgsys->addS8Fast(_PREHASH_PathRadiusOffset, radius_offset); S8 taper_x = (S8)ll_round(params->getTaperX() / TAPER_QUANTA); mesgsys->addS8Fast(_PREHASH_PathTaperX, taper_x); S8 taper_y = (S8)ll_round(params->getTaperY() / TAPER_QUANTA); mesgsys->addS8Fast(_PREHASH_PathTaperY, taper_y); U8 revolutions = (U8)ll_round((params->getRevolutions() - 1.0f) / REV_QUANTA); mesgsys->addU8Fast(_PREHASH_PathRevolutions, revolutions); S8 skew = (S8)ll_round(params->getSkew() / SCALE_QUANTA); mesgsys->addS8Fast(_PREHASH_PathSkew, skew); return true; } //static bool LLVolumeMessage::packPathParams(const LLPathParams* params, LLDataPacker& dp) { // Default to cylinder with no cut, top same size as bottom, no shear, no // twist 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); if (!params) { params = &defaultparams; } U8 curve = params->getCurveType(); dp.packU8(curve, "Curve"); U16 begin = (U16)ll_round(params->getBegin() / CUT_QUANTA); dp.packU16(begin, "Begin"); U16 end = 50000 - (U16)ll_round(params->getEnd() / CUT_QUANTA); dp.packU16(end, "End"); // Avoid truncation problem with direct F32->U8 cast. // (e.g., (U8) (0.50 / 0.01) = (U8) 49.9999999 = 49 not 50. U8 pack_scale_x = 200 - (U8)ll_round(params->getScaleX() / SCALE_QUANTA); dp.packU8(pack_scale_x, "ScaleX"); U8 pack_scale_y = 200 - (U8)ll_round(params->getScaleY() / SCALE_QUANTA); dp.packU8(pack_scale_y, "ScaleY"); S8 pack_shear_x = (S8)ll_round(params->getShearX() / SHEAR_QUANTA); dp.packU8(*(U8*)&pack_shear_x, "ShearX"); S8 pack_shear_y = (S8)ll_round(params->getShearY() / SHEAR_QUANTA); dp.packU8(*(U8*)&pack_shear_y, "ShearY"); S8 twist = (S8)ll_round(params->getTwistEnd() / SCALE_QUANTA); dp.packU8(*(U8*)&twist, "Twist"); S8 twist_begin = (S8)ll_round(params->getTwistBegin() / SCALE_QUANTA); dp.packU8(*(U8*)&twist_begin, "TwistBegin"); S8 radius_offset = (S8)ll_round(params->getRadiusOffset() / SCALE_QUANTA); dp.packU8(*(U8*)&radius_offset, "RadiusOffset"); S8 taper_x = (S8)ll_round(params->getTaperX() / TAPER_QUANTA); dp.packU8(*(U8*)&taper_x, "TaperX"); S8 taper_y = (S8)ll_round(params->getTaperY() / TAPER_QUANTA); dp.packU8(*(U8*)&taper_y, "TaperY"); U8 revolutions = (U8)ll_round((params->getRevolutions() - 1.0f) / REV_QUANTA); dp.packU8(*(U8*)&revolutions, "Revolutions"); S8 skew = (S8)ll_round(params->getSkew() / SCALE_QUANTA); dp.packU8(*(U8*)&skew, "Skew"); return true; } //static bool LLVolumeMessage::unpackPathParams(LLPathParams* params, LLMessageSystem* mesgsys, char const* block_name, S32 block_num) { U8 curve; mesgsys->getU8Fast(block_name, _PREHASH_PathCurve, curve, block_num); params->setCurveType(curve); U16 begin; mesgsys->getU16Fast(block_name, _PREHASH_PathBegin, begin, block_num); params->setBegin((F32)(begin * CUT_QUANTA)); U16 end; mesgsys->getU16Fast(block_name, _PREHASH_PathEnd, end, block_num); params->setEnd((F32)((50000 - end) * CUT_QUANTA)); U8 pack_scale_x, pack_scale_y; mesgsys->getU8Fast(block_name, _PREHASH_PathScaleX, pack_scale_x, block_num); mesgsys->getU8Fast(block_name, _PREHASH_PathScaleY, pack_scale_y, block_num); F32 x = (F32)(200 - pack_scale_x) * SCALE_QUANTA; F32 y = (F32)(200 - pack_scale_y) * SCALE_QUANTA; params->setScale(x, y); S8 shear_x_quant, shear_y_quant; mesgsys->getS8Fast(block_name, _PREHASH_PathShearX, shear_x_quant, block_num); mesgsys->getS8Fast(block_name, _PREHASH_PathShearY, shear_y_quant, block_num); F32 shear_x = (F32)shear_x_quant * SHEAR_QUANTA; F32 shear_y = (F32)shear_y_quant * SHEAR_QUANTA; params->setShear(shear_x, shear_y); S8 twist; mesgsys->getS8Fast(block_name, _PREHASH_PathTwist, twist, block_num); params->setTwistEnd((F32)(twist * SCALE_QUANTA)); S8 twist_begin; mesgsys->getS8Fast(block_name, _PREHASH_PathTwistBegin, twist_begin, block_num); params->setTwistBegin((F32)(twist_begin * SCALE_QUANTA)); S8 radius_offset; mesgsys->getS8Fast(block_name, _PREHASH_PathRadiusOffset, radius_offset, block_num); params->setRadiusOffset((F32)(radius_offset * SCALE_QUANTA)); S8 taper_x_quant, taper_y_quant; mesgsys->getS8Fast(block_name, _PREHASH_PathTaperX, taper_x_quant, block_num); mesgsys->getS8Fast(block_name, _PREHASH_PathTaperY, taper_y_quant, block_num); F32 taper_x = (F32)(taper_x_quant * TAPER_QUANTA); F32 taper_y = (F32)(taper_y_quant * TAPER_QUANTA); params->setTaper(taper_x, taper_y); U8 revolutions; mesgsys->getU8Fast(block_name, _PREHASH_PathRevolutions, revolutions, block_num); params->setRevolutions((F32)(revolutions * REV_QUANTA + 1.0f)); S8 skew; mesgsys->getS8Fast(block_name, _PREHASH_PathSkew, skew, block_num); params->setSkew((F32)(skew * SCALE_QUANTA)); return true; } //static bool LLVolumeMessage::unpackPathParams(LLPathParams* params, LLDataPacker& dp) { U8 value; dp.unpackU8(value, "Curve"); params->setCurveType(value); U16 temp_u16; dp.unpackU16(temp_u16, "Begin"); params->setBegin((F32)(temp_u16 * CUT_QUANTA)); dp.unpackU16(temp_u16, "End"); params->setEnd((F32)((50000 - temp_u16) * CUT_QUANTA)); dp.unpackU8(value, "ScaleX"); F32 x = (F32)(200 - value) * SCALE_QUANTA; dp.unpackU8(value, "ScaleY"); F32 y = (F32)(200 - value) * SCALE_QUANTA; params->setScale(x, y); dp.unpackU8(value, "ShearX"); S8 svalue = *(S8*)&value; F32 shear_x = (F32)svalue * SHEAR_QUANTA; dp.unpackU8(value, "ShearY"); svalue = *(S8*)&value; F32 shear_y = (F32)svalue * SHEAR_QUANTA; params->setShear(shear_x, shear_y); dp.unpackU8(value, "Twist"); svalue = *(S8*)&value; params->setTwistEnd((F32)(svalue * SCALE_QUANTA)); dp.unpackU8(value, "TwistBegin"); svalue = *(S8*)&value; params->setTwistBegin((F32)(svalue * SCALE_QUANTA)); dp.unpackU8(value, "RadiusOffset"); svalue = *(S8*)&value; params->setRadiusOffset((F32)(svalue * SCALE_QUANTA)); dp.unpackU8(value, "TaperX"); svalue = *(S8*)&value; params->setTaperX((F32)(svalue * TAPER_QUANTA)); dp.unpackU8(value, "TaperY"); svalue = *(S8*)&value; params->setTaperY((F32)(svalue * TAPER_QUANTA)); dp.unpackU8(value, "Revolutions"); params->setRevolutions((F32)(value * REV_QUANTA + 1.0f)); dp.unpackU8(value, "Skew"); svalue = *(S8*)&value; params->setSkew((F32)(svalue * SCALE_QUANTA)); return true; } //static bool LLVolumeMessage::constrainVolumeParams(LLVolumeParams& params) { // This is called immediately after an unpack. feed the raw data through // the checked setters to constraint it to a valid set of volume params. U32 bad = params.setType(params.getProfileParams().getCurveType(), params.getPathParams().getCurveType()) ? 0 : 1; bad |= params.setBeginAndEndS(params.getProfileParams().getBegin(), params.getProfileParams().getEnd()) ? 0 : 2; bad |= params.setBeginAndEndT(params.getPathParams().getBegin(), params.getPathParams().getEnd()) ? 0 : 4; bad |= params.setHollow(params.getProfileParams().getHollow()) ? 0 : 8; bad |= params.setTwistBegin(params.getPathParams().getTwistBegin()) ? 0 : 0x10; bad |= params.setTwistEnd(params.getPathParams().getTwistEnd()) ? 0 : 0x20; bad |= params.setRatio(params.getPathParams().getScaleX(), params.getPathParams().getScaleY()) ? 0 : 0x40; bad |= params.setShear(params.getPathParams().getShearX(), params.getPathParams().getShearY()) ? 0 : 0x80; bad |= params.setTaper(params.getPathParams().getTaperX(), params.getPathParams().getTaperY()) ? 0 : 0x100; bad |= params.setRevolutions(params.getPathParams().getRevolutions()) ? 0 : 0x200; bad |= params.setRadiusOffset(params.getPathParams().getRadiusOffset()) ? 0 : 0x400; bad |= params.setSkew(params.getPathParams().getSkew()) ? 0 : 0x800; if (bad) { LL_DEBUGS("VolumeMessage") << "Forced to constrain bad incoming volume param: " << llformat("0x%04x", bad) << LL_ENDL; } return bad == 0 || (sIgnoreBadRatio && bad == 0x40); } //static bool LLVolumeMessage::packVolumeParams(const LLVolumeParams* params, LLMessageSystem* mesgsys) { if (params) { packPathParams(¶ms->getPathParams(), mesgsys); packProfileParams(¶ms->getProfileParams(), mesgsys); } else { packPathParams(0, mesgsys); packProfileParams(0, mesgsys); } return true; } //static bool LLVolumeMessage::packVolumeParams(const LLVolumeParams* params, LLDataPacker& dp) { if (params) { packPathParams(¶ms->getPathParams(), dp); packProfileParams(¶ms->getProfileParams(), dp); } else { packPathParams(0, dp); packProfileParams(0, dp); } return true; } //static bool LLVolumeMessage::unpackVolumeParams(LLVolumeParams* params, LLMessageSystem* mesgsys, char const* block_name, S32 block_num) { bool ok = unpackPathParams(¶ms->getPathParams(), mesgsys, block_name, block_num); ok &= unpackProfileParams(¶ms->getProfileParams(), mesgsys, block_name, block_num); ok &= constrainVolumeParams(*params); return ok; } //static bool LLVolumeMessage::unpackVolumeParams(LLVolumeParams* params, LLDataPacker& dp) { bool ok = unpackPathParams(¶ms->getPathParams(), dp); ok &= unpackProfileParams(¶ms->getProfileParams(), dp); ok &= constrainVolumeParams(*params); return ok; }