From 71de5f622a7917f78823a7e7840194e1b0f8f070 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Thu, 26 Aug 2010 14:23:12 -0500 Subject: Add missing files from viewer-experimental --- indra/newview/llfloatermodelpreview.cpp | 3382 +++++++++++++++++++++++++++++++ 1 file changed, 3382 insertions(+) create mode 100644 indra/newview/llfloatermodelpreview.cpp (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp new file mode 100644 index 0000000000..5dd983d818 --- /dev/null +++ b/indra/newview/llfloatermodelpreview.cpp @@ -0,0 +1,3382 @@ +/** + * @file llfloatermodelpreview.cpp + * @brief LLFloaterModelPreview class implementation + * + * $LicenseInfo:firstyear=2004&license=viewergpl$ + * + * Copyright (c) 2004-2007, 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://secondlife.com/developers/opensource/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://secondlife.com/developers/opensource/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 "llviewerprecompiledheaders.h" + +#include "dae.h" +//#include "dom.h" +#include "dom/domAsset.h" +#include "dom/domBind_material.h" +#include "dom/domCOLLADA.h" +#include "dom/domConstants.h" +#include "dom/domController.h" +#include "dom/domEffect.h" +#include "dom/domGeometry.h" +#include "dom/domInstance_geometry.h" +#include "dom/domInstance_material.h" +#include "dom/domInstance_node.h" +#include "dom/domInstance_effect.h" +#include "dom/domMaterial.h" +#include "dom/domMatrix.h" +#include "dom/domNode.h" +#include "dom/domProfile_COMMON.h" +#include "dom/domRotate.h" +#include "dom/domScale.h" +#include "dom/domTranslate.h" +#include "dom/domVisual_scene.h" + +#include "llfloatermodelpreview.h" + +#include "llfilepicker.h" +#include "llimagebmp.h" +#include "llimagetga.h" +#include "llimagejpeg.h" +#include "llimagepng.h" + +#include "llagent.h" +#include "llbutton.h" +#include "llcombobox.h" +#include "lldatapacker.h" +#include "lldrawable.h" +#include "lldrawpoolavatar.h" +#include "llrender.h" +#include "llface.h" +#include "lleconomy.h" +#include "llfocusmgr.h" +#include "llfloaterperms.h" +#include "llmatrix4a.h" +#include "llmeshrepository.h" +#include "llsdutil_math.h" +#include "lltextbox.h" +#include "lltoolmgr.h" +#include "llui.h" +#include "llvector4a.h" +#include "llviewercamera.h" +#include "llviewerwindow.h" +#include "llvoavatar.h" +#include "llvoavatarself.h" +#include "pipeline.h" +#include "lluictrlfactory.h" +#include "llviewermenufile.h" +#include "llviewerregion.h" +#include "llstring.h" +#include "llbutton.h" +#include "llcheckboxctrl.h" +#include "llsliderctrl.h" +#include "llspinctrl.h" +#include "llvfile.h" +#include "llvfs.h" + + +#include "glod/glod.h" + + +#if LL_MESH_ENABLED + +//static +S32 LLFloaterModelPreview::sUploadAmount = 10; +LLFloaterModelPreview* LLFloaterModelPreview::sInstance = NULL; + +const S32 PREVIEW_BORDER_WIDTH = 2; +const S32 PREVIEW_RESIZE_HANDLE_SIZE = S32(RESIZE_HANDLE_WIDTH * OO_SQRT2) + PREVIEW_BORDER_WIDTH; +const S32 PREVIEW_HPAD = PREVIEW_RESIZE_HANDLE_SIZE; +const S32 PREF_BUTTON_HEIGHT = 16 + 7 + 16; +const S32 PREVIEW_TEXTURE_HEIGHT = 300; + +void drawBoxOutline(const LLVector3& pos, const LLVector3& size); + +std::string limit_name[] = +{ + "lowest limit", + "low limit", + "medium limit", + "high limit", + "physics limit", + + "I went off the end of the limit_name array. Me so smart." +}; + +std::string info_name[] = +{ + "lowest info", + "low info", + "medium info", + "high info", + "physics info", + + "I went off the end of the info_name array. Me so smart." +}; + +bool validate_face(const LLVolumeFace& face) +{ + for (U32 i = 0; i < face.mNumIndices; ++i) + { + if (face.mIndices[i] >= face.mNumVertices) + { + llwarns << "Face has invalid index." << llendl; + return false; + } + } + + return true; +} + +bool validate_model(const LLModel* mdl) +{ + if (mdl->getNumVolumeFaces() == 0) + { + llwarns << "Model has no faces!" << llendl; + return false; + } + + for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) + { + if (mdl->getVolumeFace(i).mNumVertices == 0) + { + llwarns << "Face has no vertices." << llendl; + return false; + } + + if (mdl->getVolumeFace(i).mNumIndices == 0) + { + llwarns << "Face has no indices." << llendl; + return false; + } + + if (!validate_face(mdl->getVolumeFace(i))) + { + return false; + } + } + + return true; +} + +BOOL stop_gloderror() +{ + GLuint error = glodGetError(); + + if (error != GLOD_NO_ERROR) + { + llwarns << "GLOD error detected, cannot generate LOD: " << std::hex << error << llendl; + return TRUE; + } + + return FALSE; +} + +LLPhysicsDecompFloater::LLPhysicsDecompFloater(LLSD& key) +: LLFloater(key) +{ + +} + +LLPhysicsDecompFloater::~LLPhysicsDecompFloater() +{ + if (LLFloaterModelPreview::sInstance && LLFloaterModelPreview::sInstance->mDecompFloater) + { + LLFloaterModelPreview::sInstance->mDecompFloater = NULL; + } +} + +class LLMeshFilePicker : public LLFilePickerThread +{ +public: + LLFloaterModelPreview* mFMP; + S32 mLOD; + + LLMeshFilePicker(LLFloaterModelPreview* fmp, S32 lod) + : LLFilePickerThread(LLFilePicker::FFLOAD_COLLADA) + { + mFMP = fmp; + mLOD = lod; + } + + virtual void notify(const std::string& filename) + { + mFMP->mModelPreview->loadModel(mFile, mLOD); + } +}; + + +//----------------------------------------------------------------------------- +// LLFloaterModelPreview() +//----------------------------------------------------------------------------- +LLFloaterModelPreview::LLFloaterModelPreview(const LLSD& key) : + LLFloater(key) +{ + sInstance = this; + mLastMouseX = 0; + mLastMouseY = 0; + mGLName = 0; + mLoading = FALSE; + mDecompFloater = NULL; +} + +//----------------------------------------------------------------------------- +// postBuild() +//----------------------------------------------------------------------------- +BOOL LLFloaterModelPreview::postBuild() +{ + if (!LLFloater::postBuild()) + { + return FALSE; + } + + childSetCommitCallback("high detail combo", onHighLODCommit, this); + childSetCommitCallback("medium detail combo", onMediumLODCommit, this); + childSetCommitCallback("low detail combo", onLowLODCommit, this); + childSetCommitCallback("lowest detail combo", onLowestLODCommit, this); + childSetCommitCallback("physics detail combo", onPhysicsLODCommit, this); + + + childSetCommitCallback("high limit", onHighLimitCommit, this); + childSetCommitCallback("medium limit", onMediumLimitCommit, this); + childSetCommitCallback("low limit", onLowLimitCommit, this); + childSetCommitCallback("lowest limit", onLowestLimitCommit, this); + childSetCommitCallback("physics limit", onPhysicsLimitCommit, this); + + childSetCommitCallback("smooth normals", onSmoothNormalsCommit, this); + + childSetCommitCallback("show edges", onShowEdgesCommit, this); + childSetCommitCallback("auto fill", onAutoFillCommit, this); + + childSetCommitCallback("explode", onExplodeCommit, this); + + childSetTextArg("status", "[STATUS]", getString("status_idle")); + + for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) + { + if (lod == LLModel::LOD_PHYSICS) + { + childSetTextArg(info_name[lod], "[HULLS]", std::string("0")); + childSetTextArg(info_name[lod], "[POINTS]", std::string("0")); + } + else + { + childSetTextArg(info_name[lod], "[TRIANGLES]", std::string("0")); + childSetTextArg(info_name[lod], "[VERTICES]", std::string("0")); + childSetTextArg(info_name[lod], "[SUBMESHES]", std::string("0")); + std::string msg = getString("required"); + childSetTextArg(info_name[lod], "[MESSAGE]", msg); + } + + childSetVisible(limit_name[lod], FALSE); + } + + //childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d",sUploadAmount)); + childSetAction("ok_btn", onUpload, this); + + childSetAction("consolidate", onConsolidate, this); + childSetAction("scrub materials", onScrubMaterials, this); + + childSetAction("decompose_btn", onDecompose, this); + + childSetCommitCallback("preview_lod_combo", onPreviewLODCommit, this); + + const U32 width = 512; + const U32 height = 512; + + mPreviewRect.set(getRect().getWidth()-PREVIEW_HPAD-width, + PREVIEW_HPAD+height, + getRect().getWidth()-PREVIEW_HPAD, + PREVIEW_HPAD); + + mModelPreview = new LLModelPreview(512, 512, this); + mModelPreview->setPreviewTarget(16.f); + + return TRUE; +} + +//----------------------------------------------------------------------------- +// LLFloaterModelPreview() +//----------------------------------------------------------------------------- +LLFloaterModelPreview::~LLFloaterModelPreview() +{ + sInstance = NULL; + + delete mModelPreview; + + if (mGLName) + { + LLImageGL::deleteTextures(1, &mGLName ); + } + + if (mDecompFloater) + { + mDecompFloater->closeFloater(); + mDecompFloater = NULL; + } +} + +void LLFloaterModelPreview::loadModel(S32 lod) +{ + mLoading = TRUE; + + (new LLMeshFilePicker(this, lod))->getFile(); +} + +void LLFloaterModelPreview::setLODMode(S32 lod, S32 mode) +{ + if (mode == 0) + { + loadModel(lod); + } + else if (mode != mModelPreview->mLODMode[lod]) + { + mModelPreview->mLODMode[lod] = mode; + mModelPreview->genLODs(lod); + } + + mModelPreview->setPreviewLOD(lod); + + + LLSpinCtrl* lim = getChild(limit_name[lod], TRUE); + + if (mode == 1) //triangle count + { + U32 tri_count = 0; + for (LLModelLoader::model_list::iterator iter = mModelPreview->mBaseModel.begin(); + iter != mModelPreview->mBaseModel.end(); ++iter) + { + tri_count += (*iter)->getNumTriangles(); + } + + lim->setMaxValue(tri_count); + lim->setVisible(TRUE); + } + else + { + lim->setVisible(FALSE); + } +} + +void LLFloaterModelPreview::setLimit(S32 lod, S32 limit) +{ + if (limit != mModelPreview->mLimit[lod]) + { + mModelPreview->mLimit[lod] = limit; + mModelPreview->genLODs(lod); + mModelPreview->setPreviewLOD(lod); + } +} + +void LLFloaterModelPreview::onPreviewLODCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; + + if (!fp->mModelPreview) + { + return; + } + + S32 which_mode = 0; + + LLCtrlSelectionInterface* iface = fp->childGetSelectionInterface("preview_lod_combo"); + if (iface) + { + which_mode = iface->getFirstSelectedIndex(); + } + fp->mModelPreview->setPreviewLOD(which_mode); +} + +//static +void LLFloaterModelPreview::setLODMode(S32 lod, void* userdata) +{ + LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; + + if (!fp->mModelPreview) + { + return; + } + + S32 which_mode = 0; + + std::string combo_name[] = + { + "lowest detail combo", + "low detail combo", + "medium detail combo", + "high detail combo", + "physics detail combo", + + "I went off the end of the combo_name array. Me so smart." + }; + + LLCtrlSelectionInterface* iface = fp->childGetSelectionInterface(combo_name[lod]); + if (iface) + { + which_mode = iface->getFirstSelectedIndex(); + } + + fp->setLODMode(lod, which_mode); +} + +//static +void LLFloaterModelPreview::onHighLODCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview::setLODMode(3, userdata); +} + +//static +void LLFloaterModelPreview::onMediumLODCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview::setLODMode(2, userdata); +} + +//static +void LLFloaterModelPreview::onLowLODCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview::setLODMode(1, userdata); +} + +//static +void LLFloaterModelPreview::onLowestLODCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview::setLODMode(0, userdata); +} + +//static +void LLFloaterModelPreview::onPhysicsLODCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview::setLODMode(4, userdata); +} + +//static +void LLFloaterModelPreview::setLimit(S32 lod, void* userdata) +{ + LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; + + if (!fp->mModelPreview) + { + return; + } + + S32 limit = fp->childGetValue(limit_name[lod]).asInteger(); + + + fp->setLimit(lod, limit); +} + +//static +void LLFloaterModelPreview::onHighLimitCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview::setLimit(3, userdata); +} + +//static +void LLFloaterModelPreview::onMediumLimitCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview::setLimit(2, userdata); +} + +//static +void LLFloaterModelPreview::onLowLimitCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview::setLimit(1, userdata); +} + +//static +void LLFloaterModelPreview::onLowestLimitCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview::setLimit(0, userdata); +} + +//static +void LLFloaterModelPreview::onPhysicsLimitCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview::setLimit(4, userdata); +} + +//static +void LLFloaterModelPreview::onSmoothNormalsCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; + + fp->mModelPreview->smoothNormals(); +} + +//static +void LLFloaterModelPreview::onShowEdgesCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; + + fp->mModelPreview->refresh(); +} + +//static +void LLFloaterModelPreview::onExplodeCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; + + fp->mModelPreview->refresh(); +} + +//static +void LLFloaterModelPreview::onAutoFillCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; + + fp->mModelPreview->genLODs(); +} + + +//----------------------------------------------------------------------------- +// draw() +//----------------------------------------------------------------------------- +void LLFloaterModelPreview::draw() +{ + LLFloater::draw(); + LLRect r = getRect(); + + if (!mLoading) + { + childSetTextArg("status", "[STATUS]", getString("status_idle")); + } + + childSetTextArg("description_label", "[PRIM_COST]", llformat("%d", mModelPreview->mResourceCost)); + childSetTextArg("description_label", "[TEXTURES]", llformat("%d", mModelPreview->mTextureSet.size())); + + if (mDecompFloater) + { + mDecompFloater->childSetText("status", gMeshRepo.mDecompThread->mStatus); + } + + U32 resource_cost = mModelPreview->mResourceCost*10; + + if (childGetValue("upload_textures").asBoolean()) + { + resource_cost += mModelPreview->mTextureSet.size()*10; + } + + childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d", resource_cost)); + + if (mModelPreview) + { + gGL.color3f(1.f, 1.f, 1.f); + + gGL.getTexUnit(0)->bind(mModelPreview); + + gGL.begin( LLRender::QUADS ); + { + gGL.texCoord2f(0.f, 1.f); + gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mTop); + gGL.texCoord2f(0.f, 0.f); + gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mBottom); + gGL.texCoord2f(1.f, 0.f); + gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mBottom); + gGL.texCoord2f(1.f, 1.f); + gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mTop); + } + gGL.end(); + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + } +} + +//----------------------------------------------------------------------------- +// handleMouseDown() +//----------------------------------------------------------------------------- +BOOL LLFloaterModelPreview::handleMouseDown(S32 x, S32 y, MASK mask) +{ + if (mPreviewRect.pointInRect(x, y)) + { + bringToFront( x, y ); + gFocusMgr.setMouseCapture(this); + gViewerWindow->hideCursor(); + mLastMouseX = x; + mLastMouseY = y; + return TRUE; + } + + return LLFloater::handleMouseDown(x, y, mask); +} + +//----------------------------------------------------------------------------- +// handleMouseUp() +//----------------------------------------------------------------------------- +BOOL LLFloaterModelPreview::handleMouseUp(S32 x, S32 y, MASK mask) +{ + gFocusMgr.setMouseCapture(FALSE); + gViewerWindow->showCursor(); + return LLFloater::handleMouseUp(x, y, mask); +} + +//----------------------------------------------------------------------------- +// handleHover() +//----------------------------------------------------------------------------- +BOOL LLFloaterModelPreview::handleHover (S32 x, S32 y, MASK mask) +{ + MASK local_mask = mask & ~MASK_ALT; + + if (mModelPreview && hasMouseCapture()) + { + if (local_mask == MASK_PAN) + { + // pan here + mModelPreview->pan((F32)(x - mLastMouseX) * -0.005f, (F32)(y - mLastMouseY) * -0.005f); + } + else if (local_mask == MASK_ORBIT) + { + F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f; + F32 pitch_radians = (F32)(y - mLastMouseY) * 0.02f; + + mModelPreview->rotate(yaw_radians, pitch_radians); + } + else + { + + F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f; + F32 zoom_amt = (F32)(y - mLastMouseY) * 0.02f; + + mModelPreview->rotate(yaw_radians, 0.f); + mModelPreview->zoom(zoom_amt); + } + + + mModelPreview->refresh(); + + LLUI::setMousePositionLocal(this, mLastMouseX, mLastMouseY); + } + + if (!mPreviewRect.pointInRect(x, y) || !mModelPreview) + { + return LLFloater::handleHover(x, y, mask); + } + else if (local_mask == MASK_ORBIT) + { + gViewerWindow->setCursor(UI_CURSOR_TOOLCAMERA); + } + else if (local_mask == MASK_PAN) + { + gViewerWindow->setCursor(UI_CURSOR_TOOLPAN); + } + else + { + gViewerWindow->setCursor(UI_CURSOR_TOOLZOOMIN); + } + + return TRUE; +} + +//----------------------------------------------------------------------------- +// handleScrollWheel() +//----------------------------------------------------------------------------- +BOOL LLFloaterModelPreview::handleScrollWheel(S32 x, S32 y, S32 clicks) +{ + if (mPreviewRect.pointInRect(x, y) && mModelPreview) + { + mModelPreview->zoom((F32)clicks * -0.2f); + mModelPreview->refresh(); + } + + return TRUE; +} + +//static +void LLFloaterModelPreview::onPhysicsParamCommit(LLUICtrl* ctrl, void* data) +{ + LLCDParam* param = (LLCDParam*) data; + + LLCDResult ret = LLCD_OK; + + if (LLConvexDecomposition::getInstance() == NULL) + { + llinfos << "convex decomposition tool is a stub on this platform. cannot get decomp." << llendl; + return; + } + + if (param->mType == LLCDParam::LLCD_FLOAT) + { + ret = LLConvexDecomposition::getInstance()->setParam(param->mName, (F32) ctrl->getValue().asReal()); + } + else if (param->mType == LLCDParam::LLCD_INTEGER || + param->mType == LLCDParam::LLCD_ENUM) + { + ret = LLConvexDecomposition::getInstance()->setParam(param->mName, ctrl->getValue().asInteger()); + } + else if (param->mType == LLCDParam::LLCD_BOOLEAN) + { + ret = LLConvexDecomposition::getInstance()->setParam(param->mName, ctrl->getValue().asBoolean()); + } + + if (ret) + { + llerrs << "WTF?" << llendl; + } +} + +//static +void LLFloaterModelPreview::onPhysicsStageExecute(LLUICtrl* ctrl, void* data) +{ + LLCDStageData* stage = (LLCDStageData*) data; + + LLModel* mdl = NULL; + + if (sInstance) + { + if (sInstance->mModelPreview) + { + if (sInstance->mDecompFloater) + { + S32 idx = sInstance->mDecompFloater->childGetValue("model").asInteger(); + if (idx >= 0 && idx < sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS].size()) + { + mdl = sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS][idx]; + } + } + } + } + + if (mdl) + { + gMeshRepo.mDecompThread->execute(stage->mName, mdl); + } +} + +//static +void LLFloaterModelPreview::onPhysicsStageCancel(LLUICtrl* ctrl, void*data) +{ + gMeshRepo.mDecompThread->cancel(); +} + +void LLFloaterModelPreview::showDecompFloater() +{ + if (!mDecompFloater) + { + LLSD key; + mDecompFloater = new LLPhysicsDecompFloater(key); + + S32 left = 20; + S32 right = 270; + + S32 cur_y = 30; + + { + //add status text + LLTextBox::Params p; + p.name("status"); + p.rect(LLRect(left, cur_y, right-80, cur_y-20)); + mDecompFloater->addChild(LLUICtrlFactory::create(p)); + } + + + { //add cancel button + LLButton::Params p; + p.name("Cancel"); + p.label("Cancel"); + p.rect(LLRect(right-80, cur_y, right, cur_y-20)); + LLButton* button = LLUICtrlFactory::create(p); + button->setCommitCallback(onPhysicsStageCancel, NULL); + mDecompFloater->addChild(button); + } + + cur_y += 30; + + + const LLCDStageData* stage; + S32 stage_count = 0; + if (LLConvexDecomposition::getInstance() != NULL) + { + stage_count = LLConvexDecomposition::getInstance()->getStages(&stage); + } + + const LLCDParam* param; + S32 param_count = 0; + if (LLConvexDecomposition::getInstance() != NULL) + { + param_count = LLConvexDecomposition::getInstance()->getParameters(¶m); + } + + for (S32 j = stage_count-1; j >= 0; --j) + { + LLButton::Params p; + p.name(stage[j].mName); + p.label(stage[j].mName); + p.rect(LLRect(left, cur_y, right, cur_y-20)); + LLButton* button = LLUICtrlFactory::create(p); + button->setCommitCallback(onPhysicsStageExecute, (void*) &stage[j]); + mDecompFloater->addChild(button); + gMeshRepo.mDecompThread->mStageID[stage[j].mName] = j; + cur_y += 30; + // protected against stub by stage_count being 0 for stub above + LLConvexDecomposition::getInstance()->registerCallback(j, LLPhysicsDecomp::llcdCallback); + + for (S32 i = 0; i < param_count; ++i) + { + if (param[i].mStage != j) + { + continue; + } + + if (param[i].mType == LLCDParam::LLCD_FLOAT) + { + LLSliderCtrl::Params p; + p.name(param[i].mName); + p.label(param[i].mName); + p.rect(LLRect(left, cur_y, right, cur_y-20)); + p.min_value(param[i].mDetails.mRange.mLow.mFloat); + p.max_value(param[i].mDetails.mRange.mHigh.mFloat); + p.increment(param[i].mDetails.mRange.mDelta.mFloat); + p.decimal_digits(3); + p.initial_value(param[i].mDefault.mFloat); + LLSliderCtrl* slider = LLUICtrlFactory::create(p); + slider->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); + mDecompFloater->addChild(slider); + cur_y += 30; + } + else if (param[i].mType == LLCDParam::LLCD_INTEGER) + { + LLSliderCtrl::Params p; + p.name(param[i].mName); + p.label(param[i].mName); + p.rect(LLRect(left, cur_y, right, cur_y-20)); + p.min_value(param[i].mDetails.mRange.mLow.mIntOrEnumValue); + p.max_value(param[i].mDetails.mRange.mHigh.mIntOrEnumValue); + p.increment(param[i].mDetails.mRange.mDelta.mIntOrEnumValue); + p.initial_value(param[i].mDefault.mIntOrEnumValue); + LLSliderCtrl* slider = LLUICtrlFactory::create(p); + slider->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); + mDecompFloater->addChild(slider); + cur_y += 30; + } + else if (param[i].mType == LLCDParam::LLCD_BOOLEAN) + { + LLCheckBoxCtrl::Params p; + p.rect(LLRect(left, cur_y, right, cur_y-20)); + p.name(param[i].mName); + p.label(param[i].mName); + p.initial_value(param[i].mDefault.mBool); + LLCheckBoxCtrl* check_box = LLUICtrlFactory::create(p); + check_box->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); + mDecompFloater->addChild(check_box); + cur_y += 30; + } + else if (param[i].mType == LLCDParam::LLCD_ENUM) + { + LLComboBox::Params p; + p.rect(LLRect(left, cur_y, right/3, cur_y-20)); + p.name(param[i].mName); + p.label(param[i].mName); + LLComboBox* combo_box = LLUICtrlFactory::create(p); + for (S32 k = 0; k < param[i].mDetails.mEnumValues.mNumEnums; ++k) + { + combo_box->add(param[i].mDetails.mEnumValues.mEnumsArray[k].mName, + LLSD::Integer(param[i].mDetails.mEnumValues.mEnumsArray[k].mValue)); + } + combo_box->setValue(param[i].mDefault.mIntOrEnumValue); + combo_box->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); + mDecompFloater->addChild(combo_box); + cur_y += 30; + } + } + } + + //mesh render checkbox + { + LLCheckBoxCtrl::Params p; + p.label("Mesh: "); + p.name("render_mesh"); + p.rect(LLRect(left, cur_y, right/4, cur_y-20)); + LLCheckBoxCtrl* check = LLUICtrlFactory::create(p); + check->setValue(true); + mDecompFloater->addChild(check); + } + + //hull render checkbox + { + LLCheckBoxCtrl::Params p; + p.label("Hull: "); + p.name("render_hull"); + p.rect(LLRect(right/4, cur_y, right/2, cur_y-20)); + LLCheckBoxCtrl* check = LLUICtrlFactory::create(p); + check->setValue(true); + mDecompFloater->addChild(check); + } + + { //submesh combo box label + LLTextBox::Params p; + p.label("Model"); + p.name("model label"); + p.rect(LLRect(right/3, cur_y, right/2, cur_y-20)); + LLTextBox* text_box = LLUICtrlFactory::create(p); + text_box->setValue("Model"); + mDecompFloater->addChild(text_box); + } + { + //add submesh combo box + LLComboBox::Params p; + p.rect(LLRect(right/2, cur_y, right, cur_y-20)); + p.name("model"); + LLComboBox* combo_box = LLUICtrlFactory::create(p); + for (S32 i = 0; i < mModelPreview->mBaseModel.size(); ++i) + { + LLModel* mdl = mModelPreview->mBaseModel[i]; + combo_box->add(mdl->mLabel, i); + } + combo_box->setValue(0); + mDecompFloater->addChild(combo_box); + cur_y += 30; + } + + mDecompFloater->childSetCommitCallback("model", LLFloaterModelPreview::refresh, LLFloaterModelPreview::sInstance); + mDecompFloater->childSetCommitCallback("render_mesh", LLFloaterModelPreview::refresh, LLFloaterModelPreview::sInstance); + mDecompFloater->childSetCommitCallback("render_hull", LLFloaterModelPreview::refresh, LLFloaterModelPreview::sInstance); + + mDecompFloater->setRect(LLRect(10, cur_y+20, right+20, 10)); + } + + mDecompFloater->openFloater(); +} + +//----------------------------------------------------------------------------- +// onMouseCaptureLost() +//----------------------------------------------------------------------------- +// static +void LLFloaterModelPreview::onMouseCaptureLostModelPreview(LLMouseHandler* handler) +{ + gViewerWindow->showCursor(); +} + +//----------------------------------------------------------------------------- +// LLModelLoader +//----------------------------------------------------------------------------- +LLModelLoader::LLModelLoader(std::string filename, S32 lod, LLModelPreview* preview) +: LLThread("Model Loader"), mFilename(filename), mLod(lod), mPreview(preview), mState(STARTING), mFirstTransform(TRUE) +{ + mJointMap["mPelvis"] = "mPelvis"; + mJointMap["mTorso"] = "mTorso"; + mJointMap["mChest"] = "mChest"; + mJointMap["mNeck"] = "mNeck"; + mJointMap["mHead"] = "mHead"; + mJointMap["mSkull"] = "mSkull"; + mJointMap["mEyeRight"] = "mEyeRight"; + mJointMap["mEyeLeft"] = "mEyeLeft"; + mJointMap["mCollarLeft"] = "mCollarLeft"; + mJointMap["mShoulderLeft"] = "mShoulderLeft"; + mJointMap["mElbowLeft"] = "mElbowLeft"; + mJointMap["mWristLeft"] = "mWristLeft"; + mJointMap["mCollarRight"] = "mCollarRight"; + mJointMap["mShoulderRight"] = "mShoulderRight"; + mJointMap["mElbowRight"] = "mElbowRight"; + mJointMap["mWristRight"] = "mWristRight"; + mJointMap["mHipRight"] = "mHipRight"; + mJointMap["mKneeRight"] = "mKneeRight"; + mJointMap["mAnkleRight"] = "mAnkleRight"; + mJointMap["mFootRight"] = "mFootRight"; + mJointMap["mToeRight"] = "mToeRight"; + mJointMap["mHipLeft"] = "mHipLeft"; + mJointMap["mKneeLeft"] = "mKneeLeft"; + mJointMap["mAnkleLeft"] = "mAnkleLeft"; + mJointMap["mFootLeft"] = "mFootLeft"; + mJointMap["mToeLeft"] = "mToeLeft"; + + mJointMap["avatar_mPelvis"] = "mPelvis"; + mJointMap["avatar_mTorso"] = "mTorso"; + mJointMap["avatar_mChest"] = "mChest"; + mJointMap["avatar_mNeck"] = "mNeck"; + mJointMap["avatar_mHead"] = "mHead"; + mJointMap["avatar_mSkull"] = "mSkull"; + mJointMap["avatar_mEyeRight"] = "mEyeRight"; + mJointMap["avatar_mEyeLeft"] = "mEyeLeft"; + mJointMap["avatar_mCollarLeft"] = "mCollarLeft"; + mJointMap["avatar_mShoulderLeft"] = "mShoulderLeft"; + mJointMap["avatar_mElbowLeft"] = "mElbowLeft"; + mJointMap["avatar_mWristLeft"] = "mWristLeft"; + mJointMap["avatar_mCollarRight"] = "mCollarRight"; + mJointMap["avatar_mShoulderRight"] = "mShoulderRight"; + mJointMap["avatar_mElbowRight"] = "mElbowRight"; + mJointMap["avatar_mWristRight"] = "mWristRight"; + mJointMap["avatar_mHipRight"] = "mHipRight"; + mJointMap["avatar_mKneeRight"] = "mKneeRight"; + mJointMap["avatar_mAnkleRight"] = "mAnkleRight"; + mJointMap["avatar_mFootRight"] = "mFootRight"; + mJointMap["avatar_mToeRight"] = "mToeRight"; + mJointMap["avatar_mHipLeft"] = "mHipLeft"; + mJointMap["avatar_mKneeLeft"] = "mKneeLeft"; + mJointMap["avatar_mAnkleLeft"] = "mAnkleLeft"; + mJointMap["avatar_mFootLeft"] = "mFootLeft"; + mJointMap["avatar_mToeLeft"] = "mToeLeft"; + + + mJointMap["hip"] = "mPelvis"; + mJointMap["abdomen"] = "mTorso"; + mJointMap["chest"] = "mChest"; + mJointMap["neck"] = "mNeck"; + mJointMap["head"] = "mHead"; + mJointMap["figureHair"] = "mSkull"; + mJointMap["lCollar"] = "mCollarLeft"; + mJointMap["lShldr"] = "mShoulderLeft"; + mJointMap["lForeArm"] = "mElbowLeft"; + mJointMap["lHand"] = "mWristLeft"; + mJointMap["rCollar"] = "mCollarRight"; + mJointMap["rShldr"] = "mShoulderRight"; + mJointMap["rForeArm"] = "mElbowRight"; + mJointMap["rHand"] = "mWristRight"; + mJointMap["rThigh"] = "mHipRight"; + mJointMap["rShin"] = "mKneeRight"; + mJointMap["rFoot"] = "mFootRight"; + mJointMap["lThigh"] = "mHipLeft"; + mJointMap["lShin"] = "mKneeLeft"; + mJointMap["lFoot"] = "mFootLeft"; +} + +void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, BOOL& first_transform) +{ + LLVector4a box[] = + { + LLVector4a(-1, 1,-1), + LLVector4a(-1, 1, 1), + LLVector4a(-1,-1,-1), + LLVector4a(-1,-1, 1), + LLVector4a( 1, 1,-1), + LLVector4a( 1, 1, 1), + LLVector4a( 1,-1,-1), + LLVector4a( 1,-1, 1), + }; + + for (S32 j = 0; j < model->getNumVolumeFaces(); ++j) + { + const LLVolumeFace& face = model->getVolumeFace(j); + + LLVector4a center; + center.setAdd(face.mExtents[0], face.mExtents[1]); + center.mul(0.5f); + LLVector4a size; + size.setSub(face.mExtents[1],face.mExtents[0]); + size.mul(0.5f); + + for (U32 i = 0; i < 8; i++) + { + LLVector4a t; + t.setMul(size, box[i]); + t.add(center); + + LLVector4a v; + + mat.affineTransform(t, v); + + if (first_transform) + { + first_transform = FALSE; + min = max = v; + } + else + { + update_min_max(min, max, v); + } + } + } +} + +void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& max, BOOL& first_transform) +{ + LLVector4a mina, maxa; + LLMatrix4a mata; + + mata.loadu(mat); + mina.load3(min.mV); + maxa.load3(max.mV); + + stretch_extents(model, mata, mina, maxa, first_transform); + + min.set(mina.getF32ptr()); + max.set(maxa.getF32ptr()); +} + +void LLModelLoader::run() +{ + DAE dae; + domCOLLADA* dom = dae.open(mFilename); + + if (dom) + { + daeDatabase* db = dae.getDatabase(); + + daeInt count = db->getElementCount(NULL, COLLADA_TYPE_MESH); + + daeDocument* doc = dae.getDoc(mFilename); + if (!doc) + { + llwarns << "can't find internal doc" << llendl; + return; + } + + daeElement* root = doc->getDomRoot(); + if (!root) + { + llwarns << "document has no root" << llendl; + return; + } + + //get unit scale + mTransform.setIdentity(); + + domAsset::domUnit* unit = daeSafeCast(root->getDescendant(daeElement::matchType(domAsset::domUnit::ID()))); + + if (unit) + { + F32 meter = unit->getMeter(); + mTransform.mMatrix[0][0] = meter; + mTransform.mMatrix[1][1] = meter; + mTransform.mMatrix[2][2] = meter; + } + + //get up axis rotation + LLMatrix4 rotation; + + domUpAxisType up = UPAXISTYPE_Y_UP; // default is Y_UP + domAsset::domUp_axis* up_axis = + daeSafeCast(root->getDescendant(daeElement::matchType(domAsset::domUp_axis::ID()))); + + if (up_axis) + { + up = up_axis->getValue(); + } + + if (up == UPAXISTYPE_X_UP) + { + rotation.initRotation(0.0f, 90.0f * DEG_TO_RAD, 0.0f); + } + else if (up == UPAXISTYPE_Y_UP) + { + rotation.initRotation(90.0f * DEG_TO_RAD, 0.0f, 0.0f); + } + + rotation *= mTransform; + mTransform = rotation; + + + for (daeInt idx = 0; idx < count; ++idx) + { //build map of domEntities to LLModel + domMesh* mesh = NULL; + db->getElement((daeElement**) &mesh, idx, NULL, COLLADA_TYPE_MESH); + + if (mesh) + { + LLPointer model = LLModel::loadModelFromDomMesh(mesh); + + if (model.notNull() && validate_model(model)) + { + mModelList.push_back(model); + mModel[mesh] = model; + } + } + } + + count = db->getElementCount(NULL, COLLADA_TYPE_SKIN); + for (daeInt idx = 0; idx < count; ++idx) + { //add skinned meshes as instances + domSkin* skin = NULL; + db->getElement((daeElement**) &skin, idx, NULL, COLLADA_TYPE_SKIN); + + if (skin) + { + domGeometry* geom = daeSafeCast(skin->getSource().getElement()); + + if (geom) + { + domMesh* mesh = geom->getMesh(); + if (mesh) + { + LLModel* model = mModel[mesh]; + if (model) + { + LLVector3 mesh_scale_vector; + LLVector3 mesh_translation_vector; + model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); + + LLMatrix4 normalized_transformation; + normalized_transformation.setTranslation(mesh_translation_vector); + + LLMatrix4 mesh_scale; + mesh_scale.initScale(mesh_scale_vector); + mesh_scale *= normalized_transformation; + normalized_transformation = mesh_scale; + + glh::matrix4f inv_mat((F32*) normalized_transformation.mMatrix); + inv_mat = inv_mat.inverse(); + LLMatrix4 inverse_normalized_transformation(inv_mat.m); + + domSkin::domBind_shape_matrix* bind_mat = skin->getBind_shape_matrix(); + + if (bind_mat) + { //get bind shape matrix + domFloat4x4& dom_value = bind_mat->getValue(); + + for (int i = 0; i < 4; i++) + { + for(int j = 0; j < 4; j++) + { + model->mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j*4]; + } + } + + LLMatrix4 trans = normalized_transformation; + trans *= model->mBindShapeMatrix; + model->mBindShapeMatrix = trans; + + } + + /*{ + LLMatrix4 rotation; + if (up == UPAXISTYPE_X_UP) + { + rotation.initRotation(0.0f, 90.0f * DEG_TO_RAD, 0.0f); + } + else if (up == UPAXISTYPE_Z_UP) + { + rotation.initRotation(90.0f * DEG_TO_RAD, 90.0f * DEG_TO_RAD, 0.0f); + } + + rotation *= model->mBindShapeMatrix; + model->mBindShapeMatrix = rotation; + }*/ + + + domSkin::domJoints* joints = skin->getJoints(); + + domInputLocal_Array& joint_input = joints->getInput_array(); + + for (size_t i = 0; i < joint_input.getCount(); ++i) + { + domInputLocal* input = joint_input.get(i); + xsNMTOKEN semantic = input->getSemantic(); + + if (strcmp(semantic, COMMON_PROFILE_INPUT_JOINT) == 0) + { //found joint source, fill model->mJointMap and model->mJointList + daeElement* elem = input->getSource().getElement(); + + domSource* source = daeSafeCast(elem); + if (source) + { + + + domName_array* names_source = source->getName_array(); + + if (names_source) + { + domListOfNames &names = names_source->getValue(); + + for (size_t j = 0; j < names.getCount(); ++j) + { + std::string name(names.get(j)); + if (mJointMap.find(name) != mJointMap.end()) + { + name = mJointMap[name]; + } + model->mJointList.push_back(name); + model->mJointMap[name] = j; + } + } + else + { + domIDREF_array* names_source = source->getIDREF_array(); + if (names_source) + { + xsIDREFS& names = names_source->getValue(); + + for (size_t j = 0; j < names.getCount(); ++j) + { + std::string name(names.get(j).getID()); + if (mJointMap.find(name) != mJointMap.end()) + { + name = mJointMap[name]; + } + model->mJointList.push_back(name); + model->mJointMap[name] = j; + } + } + } + } + } + else if (strcmp(semantic, COMMON_PROFILE_INPUT_INV_BIND_MATRIX) == 0) + { //found inv_bind_matrix array, fill model->mInvBindMatrix + domSource* source = daeSafeCast(input->getSource().getElement()); + if (source) + { + domFloat_array* t = source->getFloat_array(); + if (t) + { + domListOfFloats& transform = t->getValue(); + S32 count = transform.getCount()/16; + + for (S32 k = 0; k < count; ++k) + { + LLMatrix4 mat; + + for (int i = 0; i < 4; i++) + { + for(int j = 0; j < 4; j++) + { + mat.mMatrix[i][j] = transform[k*16 + i + j*4]; + } + } + + model->mInvBindMatrix.push_back(mat); + } + } + } + } + } + + + //grab raw position array + + domVertices* verts = mesh->getVertices(); + if (verts) + { + domInputLocal_Array& inputs = verts->getInput_array(); + for (size_t i = 0; i < inputs.getCount() && model->mPosition.empty(); ++i) + { + if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_POSITION) == 0) + { + domSource* pos_source = daeSafeCast(inputs[i]->getSource().getElement()); + if (pos_source) + { + domFloat_array* pos_array = pos_source->getFloat_array(); + if (pos_array) + { + domListOfFloats& pos = pos_array->getValue(); + + for (size_t j = 0; j < pos.getCount(); j += 3) + { + if (pos.getCount() <= j+2) + { + llerrs << "WTF?" << llendl; + } + + LLVector3 v(pos[j], pos[j+1], pos[j+2]); + + //transform from COLLADA space to volume space + v = v * inverse_normalized_transformation; + + model->mPosition.push_back(v); + } + } + } + } + } + } + + //grab skin weights array + domSkin::domVertex_weights* weights = skin->getVertex_weights(); + if (weights) + { + domInputLocalOffset_Array& inputs = weights->getInput_array(); + domFloat_array* vertex_weights = NULL; + for (size_t i = 0; i < inputs.getCount(); ++i) + { + if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_WEIGHT) == 0) + { + domSource* weight_source = daeSafeCast(inputs[i]->getSource().getElement()); + if (weight_source) + { + vertex_weights = weight_source->getFloat_array(); + } + } + } + + if (vertex_weights) + { + domListOfFloats& w = vertex_weights->getValue(); + domListOfUInts& vcount = weights->getVcount()->getValue(); + domListOfInts& v = weights->getV()->getValue(); + + U32 c_idx = 0; + for (size_t vc_idx = 0; vc_idx < vcount.getCount(); ++vc_idx) + { //for each vertex + daeUInt count = vcount[vc_idx]; + + //create list of weights that influence this vertex + LLModel::weight_list weight_list; + + for (daeUInt i = 0; i < count; ++i) + { //for each weight + daeInt joint_idx = v[c_idx++]; + daeInt weight_idx = v[c_idx++]; + + if (joint_idx == -1) + { + //ignore bindings to bind_shape_matrix + continue; + } + + F32 weight_value = w[weight_idx]; + + weight_list.push_back(LLModel::JointWeight(joint_idx, weight_value)); + } + + //sort by joint weight + std::sort(weight_list.begin(), weight_list.end(), LLModel::CompareWeightGreater()); + + std::vector wght; + + F32 total = 0.f; + + for (U32 i = 0; i < llmin((U32) 4, (U32) weight_list.size()); ++i) + { //take up to 4 most significant weights + if (weight_list[i].mWeight > 0.f) + { + wght.push_back( weight_list[i] ); + total += weight_list[i].mWeight; + } + } + + F32 scale = 1.f/total; + if (scale != 1.f) + { //normalize weights + for (U32 i = 0; i < wght.size(); ++i) + { + wght[i].mWeight *= scale; + } + } + + model->mSkinWeights[model->mPosition[vc_idx]] = wght; + } + + //add instance to scene for this model + + LLMatrix4 transform; + std::vector materials; + materials.resize(model->getNumVolumeFaces()); + mScene[transform].push_back(LLModelInstance(model, transform, materials)); + stretch_extents(model, transform, mExtents[0], mExtents[1], mFirstTransform); + } + } + } + } + } + } + } + + daeElement* scene = root->getDescendant("visual_scene"); + if (!scene) + { + llwarns << "document has no visual_scene" << llendl; + return; + } + + processElement(scene); + + mPreview->loadModelCallback(mLod); + } +} + +void LLModelLoader::processElement(daeElement* element) +{ + LLMatrix4 saved_transform = mTransform; + + domTranslate* translate = daeSafeCast(element); + if (translate) + { + domFloat3 dom_value = translate->getValue(); + + LLMatrix4 translation; + translation.setTranslation(LLVector3(dom_value[0], dom_value[1], dom_value[2])); + + translation *= mTransform; + mTransform = translation; + } + + domRotate* rotate = daeSafeCast(element); + if (rotate) + { + domFloat4 dom_value = rotate->getValue(); + + LLMatrix4 rotation; + rotation.initRotTrans(dom_value[3] * DEG_TO_RAD, LLVector3(dom_value[0], dom_value[1], dom_value[2]), LLVector3(0, 0, 0)); + + rotation *= mTransform; + mTransform = rotation; + } + + domScale* scale = daeSafeCast(element); + if (scale) + { + domFloat3 dom_value = scale->getValue(); + + LLMatrix4 scaling; + scaling.initScale(LLVector3(dom_value[0], dom_value[1], dom_value[2])); + + scaling *= mTransform; + mTransform = scaling; + } + + domMatrix* matrix = daeSafeCast(element); + if (matrix) + { + domFloat4x4 dom_value = matrix->getValue(); + + LLMatrix4 matrix_transform; + + for (int i = 0; i < 4; i++) + { + for(int j = 0; j < 4; j++) + { + matrix_transform.mMatrix[i][j] = dom_value[i + j*4]; + } + } + + matrix_transform *= mTransform; + mTransform = matrix_transform; + } + + domInstance_geometry* instance_geo = daeSafeCast(element); + if (instance_geo) + { + domGeometry* geo = daeSafeCast(instance_geo->getUrl().getElement()); + if (geo) + { + domMesh* mesh = daeSafeCast(geo->getDescendant(daeElement::matchType(domMesh::ID()))); + if (mesh) + { + LLModel* model = mModel[mesh]; + if (model) + { + LLMatrix4 transformation = mTransform; + + std::vector materials = getMaterials(model, instance_geo); + + // adjust the transformation to compensate for mesh normalization + LLVector3 mesh_scale_vector; + LLVector3 mesh_translation_vector; + model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); + + LLMatrix4 mesh_translation; + mesh_translation.setTranslation(mesh_translation_vector); + mesh_translation *= transformation; + transformation = mesh_translation; + + LLMatrix4 mesh_scale; + mesh_scale.initScale(mesh_scale_vector); + mesh_scale *= transformation; + transformation = mesh_scale; + + mScene[transformation].push_back(LLModelInstance(model, transformation, materials)); + + stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); + } + } + } + } + + domInstance_node* instance_node = daeSafeCast(element); + if (instance_node) + { + daeElement* instance = instance_node->getUrl().getElement(); + if (instance) + { + processElement(instance); + } + } + + //process children + daeTArray< daeSmartRef > children = element->getChildren(); + for (S32 i = 0; i < children.getCount(); i++) + { + processElement(children[i]); + } + + domNode* node = daeSafeCast(element); + if (node) + { //this element was a node, restore transform before processiing siblings + mTransform = saved_transform; + } +} + +std::vector LLModelLoader::getMaterials(LLModel* model, domInstance_geometry* instance_geo) +{ + std::vector materials; + for (int i = 0; i < model->mMaterialList.size(); i++) + { + LLImportMaterial import_material; + + domInstance_material* instance_mat = NULL; + + domBind_material::domTechnique_common* technique = + daeSafeCast(instance_geo->getDescendant(daeElement::matchType(domBind_material::domTechnique_common::ID()))); + + if (technique) + { + daeTArray< daeSmartRef > inst_materials = technique->getChildrenByType(); + for (int j = 0; j < inst_materials.getCount(); j++) + { + std::string symbol(inst_materials[j]->getSymbol()); + + if (symbol == model->mMaterialList[i]) // found the binding + { + instance_mat = inst_materials[j]; + } + } + } + + if (instance_mat) + { + domMaterial* material = daeSafeCast(instance_mat->getTarget().getElement()); + if (material) + { + domInstance_effect* instance_effect = + daeSafeCast(material->getDescendant(daeElement::matchType(domInstance_effect::ID()))); + if (instance_effect) + { + domEffect* effect = daeSafeCast(instance_effect->getUrl().getElement()); + if (effect) + { + domProfile_COMMON* profile = + daeSafeCast(effect->getDescendant(daeElement::matchType(domProfile_COMMON::ID()))); + if (profile) + { + import_material = profileToMaterial(profile); + } + } + } + } + } + + materials.push_back(import_material); + } + + return materials; +} + +LLImportMaterial LLModelLoader::profileToMaterial(domProfile_COMMON* material) +{ + LLImportMaterial mat; + mat.mFullbright = FALSE; + + daeElement* diffuse = material->getDescendant("diffuse"); + if (diffuse) + { + domCommon_color_or_texture_type_complexType::domTexture* texture = + daeSafeCast(diffuse->getDescendant("texture")); + if (texture) + { + domCommon_newparam_type_Array newparams = material->getNewparam_array(); + for (S32 i = 0; i < newparams.getCount(); i++) + { + domFx_surface_common* surface = newparams[i]->getSurface(); + if (surface) + { + domFx_surface_init_common* init = surface->getFx_surface_init_common(); + if (init) + { + domFx_surface_init_from_common_Array init_from = init->getInit_from_array(); + + if (init_from.getCount() > i) + { + domImage* image = daeSafeCast(init_from[i]->getValue().getElement()); + if (image) + { + // we only support init_from now - embedded data will come later + domImage::domInit_from* init = image->getInit_from(); + if (init) + { + std::string filename = cdom::uriToNativePath(init->getValue().str()); + + mat.mDiffuseMap = LLViewerTextureManager::getFetchedTextureFromUrl("file://" + filename, TRUE, LLViewerTexture::BOOST_PREVIEW); + mat.mDiffuseMap->setLoadedCallback(LLModelPreview::textureLoadedCallback, 0, TRUE, FALSE, this->mPreview, NULL, NULL); + + mat.mDiffuseMap->forceToSaveRawImage(); + mat.mDiffuseMapFilename = filename; + mat.mDiffuseMapLabel = getElementLabel(material); + } + } + } + } + } + } + } + + domCommon_color_or_texture_type_complexType::domColor* color = + daeSafeCast(diffuse->getDescendant("color")); + if (color) + { + domFx_color_common domfx_color = color->getValue(); + LLColor4 value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]); + mat.mDiffuseColor = value; + } + } + + daeElement* emission = material->getDescendant("emission"); + if (emission) + { + LLColor4 emission_color = getDaeColor(emission); + if (((emission_color[0] + emission_color[1] + emission_color[2]) / 3.0) > 0.25) + { + mat.mFullbright = TRUE; + } + } + + return mat; +} + +// try to get a decent label for this element +std::string LLModelLoader::getElementLabel(daeElement *element) +{ + // if we have a name attribute, use it + std::string name = element->getAttribute("name"); + if (name.length()) + { + return name; + } + + // if we have an ID attribute, use it + if (element->getID()) + { + return std::string(element->getID()); + } + + // if we have a parent, use it + daeElement* parent = element->getParent(); + if (parent) + { + // if parent has a name, use it + std::string name = parent->getAttribute("name"); + if (name.length()) + { + return name; + } + + // if parent has an ID, use it + if (parent->getID()) + { + return std::string(parent->getID()); + } + } + + // try to use our type + daeString element_name = element->getElementName(); + if (element_name) + { + return std::string(element_name); + } + + // if all else fails, use "object" + return std::string("object"); +} + +LLColor4 LLModelLoader::getDaeColor(daeElement* element) +{ + LLColor4 value; + domCommon_color_or_texture_type_complexType::domColor* color = + daeSafeCast(element->getDescendant("color")); + if (color) + { + domFx_color_common domfx_color = color->getValue(); + value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]); + } + + return value; +} + +//----------------------------------------------------------------------------- +// LLModelPreview +//----------------------------------------------------------------------------- + +LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloaterModelPreview* fmp) +: LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE), LLMutex(NULL) +{ + mNeedsUpdate = TRUE; + mCameraDistance = 0.f; + mCameraYaw = 0.f; + mCameraPitch = 0.f; + mCameraZoom = 1.f; + mTextureName = 0; + mPreviewLOD = 3; + mModelLoader = NULL; + + mLODMode[0] = 0; + + for (U32 i = 1; i < LLModel::NUM_LODS; i++) + { + mLODMode[i] = 1; + mLimit[i] = 0; + } + + mFMP = fmp; + + glodInit(); +} + +LLModelPreview::~LLModelPreview() +{ + if (mModelLoader) + { + delete mModelLoader; + mModelLoader = NULL; + } + + //*HACK : *TODO : turn this back on when we understand why this crashes + //glodShutdown(); +} + +U32 LLModelPreview::calcResourceCost() +{ + rebuildUploadData(); + + U32 cost = 0; + std::set accounted; + U32 num_points = 0; + U32 num_hulls = 0; + + for (U32 i = 0; i < mUploadData.size(); ++i) + { + LLModelInstance& instance = mUploadData[i]; + + if (accounted.find(instance.mModel) == accounted.end()) + { + accounted.insert(instance.mModel); + + LLModel::physics_shape& physics_shape = instance.mLOD[LLModel::LOD_PHYSICS] ? instance.mLOD[LLModel::LOD_PHYSICS]->mPhysicsShape : instance.mModel->mPhysicsShape; + + LLSD ret = LLModel::writeModel("", + instance.mLOD[4], + instance.mLOD[3], + instance.mLOD[2], + instance.mLOD[1], + instance.mLOD[0], + physics_shape, + TRUE); + cost += gMeshRepo.calcResourceCost(ret); + + + num_hulls += physics_shape.size(); + for (U32 i = 0; i < physics_shape.size(); ++i) + { + num_points += physics_shape[i].size(); + } + } + } + + mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[HULLS]", llformat("%d",num_hulls)); + mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[POINTS]", llformat("%d",num_points)); + + updateStatusMessages(); + + return cost; +} + +void LLModelPreview::rebuildUploadData() +{ + mUploadData.clear(); + mTextureSet.clear(); + + //fill uploaddata instance vectors from scene data + + for (LLModelLoader::scene::iterator iter = mBaseScene.begin(); iter != mBaseScene.end(); ++iter) + { //for each transform in scene + for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) + { //for each instance with said transform applied + LLModelInstance& instance = *model_iter; + + LLModel* base_model = instance.mModel; + + S32 idx = 0; + for (idx = 0; idx < mBaseModel.size(); ++idx) + { //find reference instance for this model + if (mBaseModel[idx] == base_model) + { + break; + } + } + + for (U32 i = 0; i < LLModel::NUM_LODS; i++) + { //fill LOD slots based on reference model index + if (!mModel[i].empty()) + { + instance.mLOD[i] = mModel[i][idx]; + } + else + { + instance.mLOD[i] = NULL; + } + } + + mUploadData.push_back(instance); + } + } +} + + +void LLModelPreview::loadModel(std::string filename, S32 lod) +{ + LLMutexLock lock(this); + + if (mModelLoader) + { + delete mModelLoader; + mModelLoader = NULL; + } + + if (filename.empty() && mBaseModel.empty()) + { + mFMP->closeFloater(false); + return; + } + + if (lod == 3 && !mGroup.empty()) + { + for (std::map::iterator iter = mGroup.begin(); iter != mGroup.end(); ++iter) + { + glodDeleteGroup(iter->second); + stop_gloderror(); + } + + for (std::map::iterator iter = mObject.begin(); iter != mObject.end(); ++iter) + { + glodDeleteObject(iter->second); + stop_gloderror(); + } + + mGroup.clear(); + mObject.clear(); + } + + mModelLoader = new LLModelLoader(filename, lod, this); + + mModelLoader->start(); + + mFMP->childSetTextArg("status", "[STATUS]", mFMP->getString("status_reading_file")); + + if (mFMP->childGetValue("description_form").asString().empty()) + { + std::string name = gDirUtilp->getBaseFileName(filename, true); + mFMP->childSetValue("description_form", name); + } + + mFMP->openFloater(); +} + +void LLModelPreview::clearIncompatible(S32 lod) +{ + for (U32 i = 0; i <= LLModel::LOD_HIGH; i++) + { //clear out any entries that aren't compatible with this model + if (i != lod) + { + if (mModel[i].size() != mModel[lod].size()) + { + mModel[i].clear(); + mScene[i].clear(); + mVertexBuffer[i].clear(); + + if (i == LLModel::LOD_HIGH) + { + mBaseModel = mModel[lod]; + mBaseScene = mScene[lod]; + mVertexBuffer[5].clear(); + } + } + } + } +} + +void LLModelPreview::loadModelCallback(S32 lod) +{ //NOT the main thread + LLMutexLock lock(this); + if (!mModelLoader) + { + return; + } + + mModel[lod] = mModelLoader->mModelList; + mScene[lod] = mModelLoader->mScene; + mVertexBuffer[lod].clear(); + + setPreviewLOD(lod); + + + if (lod == LLModel::LOD_HIGH) + { //save a copy of the highest LOD for automatic LOD manipulation + mBaseModel = mModel[lod]; + mBaseScene = mScene[lod]; + mVertexBuffer[5].clear(); + //mModel[lod] = NULL; + } + + clearIncompatible(lod); + + mResourceCost = calcResourceCost(); + + mPreviewTarget = (mModelLoader->mExtents[0] + mModelLoader->mExtents[1]) * 0.5f; + mPreviewScale = (mModelLoader->mExtents[1] - mModelLoader->mExtents[0]) * 0.5f; + setPreviewTarget(mPreviewScale.magVec()*2.f); + + mFMP->mLoading = FALSE; + refresh(); +} + +void LLModelPreview::smoothNormals() +{ + S32 which_lod = mPreviewLOD; + + + if (which_lod > 4 || which_lod < 0 || + mModel[which_lod].empty()) + { + return; + } + + F32 angle_cutoff = mFMP->childGetValue("edge threshold").asReal(); + + angle_cutoff *= DEG_TO_RAD; + + if (which_lod == 3 && !mBaseModel.empty()) + { + for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) + { + (*iter)->smoothNormals(angle_cutoff); + } + + mVertexBuffer[5].clear(); + } + + for (LLModelLoader::model_list::iterator iter = mModel[which_lod].begin(); iter != mModel[which_lod].end(); ++iter) + { + (*iter)->smoothNormals(angle_cutoff); + } + + mVertexBuffer[which_lod].clear(); + refresh(); + +} + +void LLModelPreview::consolidate() +{ + std::map > composite; + + LLMatrix4 identity; + + //bake out each node in current scene to composite + for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) + { //for each transform in current scene + LLMatrix4 mat = iter->first; + glh::matrix4f inv_trans = glh::matrix4f((F32*) mat.mMatrix).inverse().transpose(); + LLMatrix4 norm_mat(inv_trans.m); + + for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) + { //for each instance with that transform + LLModelInstance& source_instance = *model_iter; + LLModel* source = source_instance.mModel; + + if (!validate_model(source)) + { + llerrs << "Invalid model found!" << llendl; + } + + for (S32 i = 0; i < source->getNumVolumeFaces(); ++i) + { //for each face in instance + const LLVolumeFace& src_face = source->getVolumeFace(i); + LLImportMaterial& source_material = source_instance.mMaterial[i]; + + //get model in composite that is composite for this material + LLModel* model = NULL; + + if (composite.find(source_material) != composite.end()) + { + model = composite[source_material].rbegin()->mModel; + if (model->getVolumeFace(0).mNumVertices + src_face.mNumVertices > 65535) + { + model = NULL; + } + } + + if (model == NULL) + { //no model found, make new model + std::vector materials; + materials.push_back(source_material); + LLVolumeParams volume_params; + volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); + model = new LLModel(volume_params, 0.f); + model->mLabel = source->mLabel; + model->setNumVolumeFaces(0); + composite[source_material].push_back(LLModelInstance(model, identity, materials)); + } + + model->appendFace(src_face, source->mMaterialList[i], mat, norm_mat); + } + } + } + + + //condense composite into as few LLModel instances as possible + LLModelLoader::model_list new_model; + std::vector instance_list; + + LLVolumeParams volume_params; + volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); + + std::vector empty_material; + LLModelInstance cur_instance(new LLModel(volume_params, 0.f), identity, empty_material); + cur_instance.mModel->setNumVolumeFaces(0); + + BOOL first_transform = TRUE; + + LLModelLoader::scene new_scene; + LLVector3 min,max; + + for (std::map >::iterator iter = composite.begin(); + iter != composite.end(); + ++iter) + { + std::map >::iterator next_iter = iter; ++next_iter; + + for (std::vector::iterator instance_iter = iter->second.begin(); + instance_iter != iter->second.end(); + ++instance_iter) + { + LLModel* source = instance_iter->mModel; + + if (instance_iter->mMaterial.size() != 1) + { + llerrs << "WTF?" << llendl; + } + + if (source->getNumVolumeFaces() != 1) + { + llerrs << "WTF?" << llendl; + } + + if (source->mMaterialList.size() != 1) + { + llerrs << "WTF?" << llendl; + } + + cur_instance.mModel->addFace(source->getVolumeFace(0)); + cur_instance.mMaterial.push_back(instance_iter->mMaterial[0]); + cur_instance.mModel->mMaterialList.push_back(source->mMaterialList[0]); + + BOOL last_model = FALSE; + + std::vector::iterator next_instance = instance_iter; ++next_instance; + + if (next_iter == composite.end() && + next_instance == iter->second.end()) + { + last_model = TRUE; + } + + if (last_model || cur_instance.mModel->getNumVolumeFaces() >= MAX_MODEL_FACES) + { + cur_instance.mModel->mLabel = source->mLabel; + + cur_instance.mModel->optimizeVolumeFaces(); + cur_instance.mModel->normalizeVolumeFaces(); + + if (!validate_model(cur_instance.mModel)) + { + llerrs << "Invalid model detected." << llendl; + } + + new_model.push_back(cur_instance.mModel); + + LLMatrix4 transformation = LLMatrix4(); + + // adjust the transformation to compensate for mesh normalization + LLVector3 mesh_scale_vector; + LLVector3 mesh_translation_vector; + cur_instance.mModel->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); + + LLMatrix4 mesh_translation; + mesh_translation.setTranslation(mesh_translation_vector); + mesh_translation *= transformation; + transformation = mesh_translation; + + LLMatrix4 mesh_scale; + mesh_scale.initScale(mesh_scale_vector); + mesh_scale *= transformation; + transformation = mesh_scale; + + cur_instance.mTransform = transformation; + + new_scene[transformation].push_back(cur_instance); + stretch_extents(cur_instance.mModel, transformation, min, max, first_transform); + + if (!last_model) + { + cur_instance = LLModelInstance(new LLModel(volume_params, 0.f), identity, empty_material); + cur_instance.mModel->setNumVolumeFaces(0); + } + } + } + } + + mScene[mPreviewLOD] = new_scene; + mModel[mPreviewLOD] = new_model; + mVertexBuffer[mPreviewLOD].clear(); + + if (mPreviewLOD == LLModel::LOD_HIGH) + { + mBaseScene = new_scene; + mBaseModel = new_model; + mVertexBuffer[5].clear(); + } + + mPreviewTarget = (min+max)*0.5f; + mPreviewScale = (max-min)*0.5f; + setPreviewTarget(mPreviewScale.magVec()*2.f); + + clearIncompatible(mPreviewLOD); + + mResourceCost = calcResourceCost(); + refresh(); +} + +void LLModelPreview::scrubMaterials() +{ + for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) + { //for each transform in current scene + for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) + { //for each instance with that transform + LLModelInstance& source_instance = *model_iter; + LLModel* source = source_instance.mModel; + + for (S32 i = 0; i < source->getNumVolumeFaces(); ++i) + { //for each face in instance + LLImportMaterial& source_material = source_instance.mMaterial[i]; + + //clear material info + source_material.mDiffuseColor = LLColor4(1,1,1,1); + source_material.mDiffuseMap = NULL; + source_material.mDiffuseMapFilename.clear(); + source_material.mDiffuseMapLabel.clear(); + source_material.mFullbright = false; + } + } + } + + + mVertexBuffer[mPreviewLOD].clear(); + + if (mPreviewLOD == LLModel::LOD_HIGH) + { + mBaseScene = mScene[mPreviewLOD]; + mBaseModel = mModel[mPreviewLOD]; + mVertexBuffer[5].clear(); + } + + mResourceCost = calcResourceCost(); + refresh(); +} + +void LLModelPreview::genLODs(S32 which_lod) +{ + if (mBaseModel.empty()) + { + return; + } + + LLVertexBuffer::unbind(); + + stop_gloderror(); + static U32 cur_name = 1; + + S32 limit = -1; + + if (which_lod != -1) + { + limit = mLimit[which_lod]; + } + + U32 triangle_count = 0; + + for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) + { + LLModel* mdl = *iter; + for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) + { + triangle_count += mdl->getVolumeFace(i).mNumIndices/3; + } + } + + U32 base_triangle_count = triangle_count; + + U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; + + for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) + { //build GLOD objects for each model in base model list + LLModel* mdl = *iter; + if (mGroup[mdl] == 0) + { + mGroup[mdl] = cur_name++; + mObject[mdl] = cur_name++; + + glodNewGroup(mGroup[mdl]); + stop_gloderror(); + + glodGroupParameteri(mGroup[mdl], GLOD_ADAPT_MODE, GLOD_TRIANGLE_BUDGET); + stop_gloderror(); + + glodGroupParameteri(mGroup[mdl], GLOD_ERROR_MODE, GLOD_OBJECT_SPACE_ERROR); + stop_gloderror(); + + glodGroupParameterf(mGroup[mdl], GLOD_OBJECT_SPACE_ERROR_THRESHOLD, 0.025f); + stop_gloderror(); + + glodNewObject(mObject[mdl], mGroup[mdl], GLOD_DISCRETE); + stop_gloderror(); + + if (iter == mBaseModel.begin() && !mdl->mSkinWeights.empty()) + { //regenerate vertex buffer for skinned models to prevent animation feedback during LOD generation + mVertexBuffer[5].clear(); + } + + if (mVertexBuffer[5].empty()) + { + genBuffers(5); + } + + U32 tri_count = 0; + for (U32 i = 0; i < mVertexBuffer[5][mdl].size(); ++i) + { + mVertexBuffer[5][mdl][i]->setBuffer(type_mask); + U32 num_indices = mVertexBuffer[5][mdl][i]->getNumIndices(); + if (num_indices > 2) + { + glodInsertElements(mObject[mdl], i, GL_TRIANGLES, num_indices, GL_UNSIGNED_SHORT, mVertexBuffer[5][mdl][i]->getIndicesPointer(), 0, 0.f); + } + tri_count += num_indices/3; + stop_gloderror(); + } + + //store what percentage of total model (in terms of triangle count) this model makes up + mPercentage[mdl] = (F32) tri_count / (F32) base_triangle_count; + + //build glodobject + glodBuildObject(mObject[mdl]); + if (stop_gloderror()) + { + glodDeleteGroup(mGroup[mdl]); + stop_gloderror(); + glodDeleteObject(mObject[mdl]); + stop_gloderror(); + + mGroup[mdl] = 0; + mObject[mdl] = 0; + + if (which_lod == -1) + { + mModel[LLModel::LOD_HIGH] = mBaseModel; + } + + return; + } + + } + + if (which_lod == -1 || mLODMode[which_lod] == 1) + { + //generating LODs for all entries, or this entry has a triangle budget + glodGroupParameteri(mGroup[mdl], GLOD_ADAPT_MODE, GLOD_TRIANGLE_BUDGET); + stop_gloderror(); + } + else + { + //this entry uses error mode + glodGroupParameteri(mGroup[mdl], GLOD_ADAPT_MODE, GLOD_OBJECT_SPACE_ERROR); + stop_gloderror(); + } + + if (which_lod != -1 && mLODMode[which_lod] == 2) + { + glodGroupParameterf(mGroup[mdl], GLOD_OBJECT_SPACE_ERROR_THRESHOLD, llmax(limit/100.f, 0.01f)); + stop_gloderror(); + } + else + { + glodGroupParameterf(mGroup[mdl], GLOD_OBJECT_SPACE_ERROR_THRESHOLD, 0.025f); + stop_gloderror(); + } + } + + + S32 start = LLModel::LOD_HIGH; + S32 end = 0; + + BOOL error_mode = FALSE; + + if (which_lod != -1) + { + start = end = which_lod; + + if (mLODMode[which_lod] == 2) + { + error_mode = TRUE; + } + } + + + for (S32 lod = start; lod >= end; --lod) + { + if (!error_mode) + { + if (which_lod == -1) + { + if (lod < start) + { + triangle_count /= 3; + } + } + else + { + triangle_count = limit; + } + } + + mModel[lod].clear(); + mModel[lod].resize(mBaseModel.size()); + mVertexBuffer[lod].clear(); + + U32 actual_tris = 0; + U32 actual_verts = 0; + U32 submeshes = 0; + + for (U32 mdl_idx = 0; mdl_idx < mBaseModel.size(); ++mdl_idx) + { + LLModel* base = mBaseModel[mdl_idx]; + + U32 target_count = U32(mPercentage[base]*triangle_count); + + if (error_mode) + { + target_count = base->getNumTriangles(); + } + + if (target_count < 4) + { + target_count = 4; + } + + if (which_lod == -1 || mLODMode[which_lod] == 1) + { + glodGroupParameteri(mGroup[base], GLOD_MAX_TRIANGLES, target_count); + stop_gloderror(); + } + + glodAdaptGroup(mGroup[base]); + stop_gloderror(); + + GLint patch_count = 0; + glodGetObjectParameteriv(mObject[base], GLOD_NUM_PATCHES, &patch_count); + stop_gloderror(); + + LLVolumeParams volume_params; + volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); + mModel[lod][mdl_idx] = new LLModel(volume_params, 0.f); + + GLint* sizes = new GLint[patch_count*2]; + glodGetObjectParameteriv(mObject[base], GLOD_PATCH_SIZES, sizes); + stop_gloderror(); + + GLint* names = new GLint[patch_count]; + glodGetObjectParameteriv(mObject[base], GLOD_PATCH_NAMES, names); + stop_gloderror(); + + mModel[lod][mdl_idx]->setNumVolumeFaces(patch_count); + + LLModel* target_model = mModel[lod][mdl_idx]; + + for (GLint i = 0; i < patch_count; ++i) + { + LLPointer buff = new LLVertexBuffer(type_mask, 0); + + if (sizes[i*2+1] > 0 && sizes[i*2] > 0) + { + buff->allocateBuffer(sizes[i*2+1], sizes[i*2], true); + buff->setBuffer(type_mask); + glodFillElements(mObject[base], names[i], GL_UNSIGNED_SHORT, buff->getIndicesPointer()); + stop_gloderror(); + } + else + { //this face was eliminated, create a dummy triangle (one vertex, 3 indices, all 0) + buff->allocateBuffer(1, 3, true); + memset(buff->getMappedData(), 0, buff->getSize()); + memset(buff->getIndicesPointer(), 0, buff->getIndicesSize()); + } + + buff->validateRange(0, buff->getNumVerts()-1, buff->getNumIndices(), 0); + + LLStrider pos; + LLStrider norm; + LLStrider tc; + LLStrider index; + + buff->getVertexStrider(pos); + buff->getNormalStrider(norm); + buff->getTexCoord0Strider(tc); + buff->getIndexStrider(index); + + + target_model->setVolumeFaceData(names[i], pos, norm, tc, index, buff->getNumVerts(), buff->getNumIndices()); + actual_tris += buff->getNumIndices()/3; + actual_verts += buff->getNumVerts(); + ++submeshes; + + if (!validate_face(target_model->getVolumeFace(names[i]))) + { + llerrs << "Invalid face generated during LOD generation." << llendl; + } + } + + //blind copy skin weights and just take closest skin weight to point on + //decimated mesh for now (auto-generating LODs with skin weights is still a bit + //of an open problem). + target_model->mPosition = base->mPosition; + target_model->mSkinWeights = base->mSkinWeights; + target_model->mJointMap = base->mJointMap; + target_model->mJointList = base->mJointList; + target_model->mInvBindMatrix = base->mInvBindMatrix; + target_model->mBindShapeMatrix = base->mBindShapeMatrix; + + if (!validate_model(target_model)) + { + llerrs << "Invalid model generated when creating LODs" << llendl; + } + + delete [] sizes; + delete [] names; + } + + //rebuild scene based on mBaseScene + mScene[lod].clear(); + mScene[lod] = mBaseScene; + + for (U32 i = 0; i < mBaseModel.size(); ++i) + { + LLModel* mdl = mBaseModel[i]; + LLModel* target = mModel[lod][i]; + if (target) + { + for (LLModelLoader::scene::iterator iter = mScene[lod].begin(); iter != mScene[lod].end(); ++iter) + { + for (U32 j = 0; j < iter->second.size(); ++j) + { + if (iter->second[j].mModel == mdl) + { + iter->second[j].mModel = target; + } + } + } + } + } + + mResourceCost = calcResourceCost(); + } +} + +void LLModelPreview::updateStatusMessages() +{ + //triangle/vertex/submesh count for each mesh asset for each lod + std::vector tris[LLModel::NUM_LODS]; + std::vector verts[LLModel::NUM_LODS]; + std::vector submeshes[LLModel::NUM_LODS]; + + //total triangle/vertex/submesh count for each lod + S32 total_tris[LLModel::NUM_LODS]; + S32 total_verts[LLModel::NUM_LODS]; + S32 total_submeshes[LLModel::NUM_LODS]; + + for (S32 lod = 0; lod <= LLModel::LOD_HIGH; ++lod) + { + //initialize total for this lod to 0 + total_tris[lod] = total_verts[lod] = total_submeshes[lod] = 0; + + for (U32 i = 0; i < mModel[lod].size(); ++i) + { //for each model in the lod + S32 cur_tris = 0; + S32 cur_verts = 0; + S32 cur_submeshes = mModel[lod][i]->getNumVolumeFaces(); + + for (S32 j = 0; j < cur_submeshes; ++j) + { //for each submesh (face), add triangles and vertices to current total + const LLVolumeFace& face = mModel[lod][i]->getVolumeFace(j); + cur_tris += face.mNumIndices/3; + cur_verts += face.mNumVertices; + } + + //add this model to the lod total + total_tris[lod] += cur_tris; + total_verts[lod] += cur_verts; + total_submeshes[lod] += cur_submeshes; + + //store this model's counts to asset data + tris[lod].push_back(cur_tris); + verts[lod].push_back(cur_verts); + submeshes[lod].push_back(cur_submeshes); + } + } + + + std::string upload_message; + + for (S32 lod = 0; lod <= LLModel::LOD_HIGH; ++lod) + { + mFMP->childSetTextArg(info_name[lod], "[TRIANGLES]", llformat("%d", total_tris[lod])); + mFMP->childSetTextArg(info_name[lod], "[VERTICES]", llformat("%d", total_verts[lod])); + mFMP->childSetTextArg(info_name[lod], "[SUBMESHES]", llformat("%d", total_submeshes[lod])); + + std::string message = "good"; + + const U32 lod_high = LLModel::LOD_HIGH; + + if (lod != lod_high) + { + if (total_submeshes[lod] == 0) + { //no model loaded for this lod, see if one is required + for (U32 i = 0; i < verts[lod_high].size(); ++i) + { + const F32 ratio = 0.5f; + const S32 required_verts = 128; + + F32 scaler = powf(0.5f, lod_high-lod); + S32 max_verts = verts[lod_high][i]*scaler; + + if (max_verts > required_verts) + { //some model in this slot might have more than 128 vertices + + //if any model higher up the chain has more than 128 vertices, + // lod is required here + for (S32 j = lod+1; j <= LLModel::LOD_HIGH; ++j) + { + if (verts[j].size() > i && verts[j][i] > 128) + { + message = "required"; + upload_message = "missing_lod"; + } + } + } + } + } + else if (total_submeshes[lod] != total_submeshes[lod_high]) + { + message = "mesh_mismatch"; + upload_message = "bad_lod"; + } + else if (tris[lod].size() != tris[lod_high].size()) + { + message = "model_mismatch"; + upload_message = "bad_lod"; + } + else + { + for (U32 i = 0; i < verts[lod].size(); ++i) + { + const F32 ratio = 0.5f; + + F32 scaler = powf(0.5f, lod_high-lod); + S32 max_verts = verts[lod_high][i]*scaler; + + if (verts[lod][i] > max_verts) + { + message = "too_heavy"; + upload_message = "bad_lod"; + } + } + } + } + + mFMP->childSetTextArg(info_name[lod], "[MESSAGE]", mFMP->getString(message)); + } + + if (upload_message.empty()) + { + mFMP->childSetTextArg("upload_message", "[MESSAGE]", std::string("")); + mFMP->childEnable("ok_btn"); + } + else + { + mFMP->childSetTextArg("upload_message", "[MESSAGE]", mFMP->getString(upload_message)); + mFMP->childDisable("ok_btn"); + } +} + +void LLModelPreview::setPreviewTarget(F32 distance) +{ + mCameraDistance = distance; + mCameraZoom = 1.f; + mCameraPitch = 0.f; + mCameraYaw = 0.f; + mCameraOffset.clearVec(); +} + +void LLModelPreview::genBuffers(S32 lod) +{ + U32 tri_count = 0; + U32 vertex_count = 0; + U32 mesh_count = 0; + + LLModelLoader::model_list* model = NULL; + + if (lod < 0 || lod > 4) + { + model = &mBaseModel; + lod = 5; + } + else + { + model = &(mModel[lod]); + } + + if (!mVertexBuffer[lod].empty()) + { + mVertexBuffer[lod].clear(); + } + + mVertexBuffer[lod].clear(); + + LLModelLoader::model_list::iterator base_iter = mBaseModel.begin(); + + for (LLModelLoader::model_list::iterator iter = model->begin(); iter != model->end(); ++iter) + { + LLModel* mdl = *iter; + if (!mdl) + { + continue; + } + + LLModel* base_mdl = *base_iter; + base_iter++; + + for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) + { + const LLVolumeFace &vf = mdl->getVolumeFace(i); + U32 num_vertices = vf.mNumVertices; + U32 num_indices = vf.mNumIndices; + + if (!num_vertices || ! num_indices) + { + continue; + } + + LLVertexBuffer* vb = NULL; + + bool skinned = !mdl->mSkinWeights.empty(); + + U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; + + if (skinned) + { + mask |= LLVertexBuffer::MAP_WEIGHT4; + } + + vb = new LLVertexBuffer(mask, 0); + + vb->allocateBuffer(num_vertices, num_indices, TRUE); + + LLStrider vertex_strider; + LLStrider normal_strider; + LLStrider tc_strider; + LLStrider index_strider; + LLStrider weights_strider; + + vb->getVertexStrider(vertex_strider); + vb->getNormalStrider(normal_strider); + vb->getTexCoord0Strider(tc_strider); + vb->getIndexStrider(index_strider); + + if (skinned) + { + vb->getWeight4Strider(weights_strider); + } + + LLVector4a::memcpyNonAliased16((F32*) vertex_strider.get(), (F32*) vf.mPositions, num_vertices*4*sizeof(F32)); + LLVector4a::memcpyNonAliased16((F32*) tc_strider.get(), (F32*) vf.mTexCoords, num_vertices*2*sizeof(F32)); + LLVector4a::memcpyNonAliased16((F32*) normal_strider.get(), (F32*) vf.mNormals, num_vertices*4*sizeof(F32)); + + if (skinned) + { + // build vertices and normals + for (U32 i = 0; i < num_vertices; i++) + { + //find closest weight to vf.mVertices[i].mPosition + LLVector3 pos(vf.mPositions[i].getF32ptr()); + + LLModel::weight_list weight_list = base_mdl->getJointInfluences(pos); + + LLVector4 w(0,0,0,0); + if (weight_list.size() > 4) + { + llerrs << "WTF?" << llendl; + } + + for (U32 i = 0; i < weight_list.size(); ++i) + { + F32 wght = llmin(weight_list[i].mWeight, 0.999999f); + F32 joint = (F32) weight_list[i].mJointIdx; + w.mV[i] = joint + wght; + } + + *(weights_strider++) = w; + } + } + + // build indices + for (U32 i = 0; i < num_indices; i++) + { + *(index_strider++) = vf.mIndices[i]; + } + + mVertexBuffer[lod][mdl].push_back(vb); + + vertex_count += num_vertices; + tri_count += num_indices/3; + ++mesh_count; + + } + } + + if (lod == 4) + { + for (U32 i = 0; i < 4; i++) + { + LLSpinCtrl* lim = mFMP->getChild(limit_name[i], TRUE); + + lim->setMaxValue(tri_count); + } + } +} + +//----------------------------------------------------------------------------- +// render() +//----------------------------------------------------------------------------- +BOOL LLModelPreview::render() +{ + LLMutexLock lock(this); + mNeedsUpdate = FALSE; + + S32 width = getWidth(); + S32 height = getHeight(); + + LLGLSUIDefault def; + LLGLDisable no_blend(GL_BLEND); + LLGLEnable cull(GL_CULL_FACE); + LLGLDepthTest depth(GL_TRUE); + LLGLDisable fog(GL_FOG); + + glMatrixMode(GL_PROJECTION); + gGL.pushMatrix(); + glLoadIdentity(); + glOrtho(0.0f, width, 0.0f, height, -1.0f, 1.0f); + + glMatrixMode(GL_MODELVIEW); + gGL.pushMatrix(); + glLoadIdentity(); + + gGL.color4f(0.15f, 0.2f, 0.3f, 1.f); + + gl_rect_2d_simple( width, height ); + + bool avatar_preview = false; + for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) + { + for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) + { + LLModelInstance& instance = *model_iter; + LLModel* model = instance.mModel; + if (!model->mSkinWeights.empty()) + { + avatar_preview = true; + } + } + } + + mFMP->childSetEnabled("consolidate", !avatar_preview); + + F32 explode = mFMP->childGetValue("explode").asReal(); + + glMatrixMode(GL_PROJECTION); + gGL.popMatrix(); + + glMatrixMode(GL_MODELVIEW); + gGL.popMatrix(); + + glClear(GL_DEPTH_BUFFER_BIT); + + LLViewerCamera::getInstance()->setAspect((F32) width / height ); + LLViewerCamera::getInstance()->setView(LLViewerCamera::getInstance()->getDefaultFOV() / mCameraZoom); + + LLVector3 target_pos = mPreviewTarget; + LLVector3 offset = mCameraOffset; + + F32 z_near = llmax(mCameraDistance-mPreviewScale.magVec(), 0.001f); + F32 z_far = mCameraDistance+mPreviewScale.magVec(); + + if (avatar_preview) + { + target_pos = gAgentAvatarp->getPositionAgent(); + z_near = 0.01f; + z_far = 1024.f; + mCameraDistance = 16.f; + + //render avatar previews every frame + refresh(); + } + + LLQuaternion camera_rot = LLQuaternion(mCameraPitch, LLVector3::y_axis) * + LLQuaternion(mCameraYaw, LLVector3::z_axis); + + LLQuaternion av_rot = camera_rot; + LLViewerCamera::getInstance()->setOriginAndLookAt( + target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + offset) * av_rot), // camera + LLVector3::z_axis, // up + target_pos); // point of interest + + + LLViewerCamera::getInstance()->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, width, height, FALSE, z_near, z_far); + + stop_glerror(); + + gPipeline.enableLightsAvatar(); + + gGL.pushMatrix(); + const F32 BRIGHTNESS = 0.9f; + gGL.color3f(BRIGHTNESS, BRIGHTNESS, BRIGHTNESS); + + LLGLEnable normalize(GL_NORMALIZE); + + if (!mBaseModel.empty() && mVertexBuffer[5].empty()) + { + genBuffers(-1); + genBuffers(3); + //genLODs(); + } + + bool physics = (mPreviewLOD == LLModel::LOD_PHYSICS); + + S32 physics_idx = -1; + + bool render_mesh = true; + bool render_hull = false; + + if (physics && mFMP->mDecompFloater) + { + physics_idx = mFMP->mDecompFloater->childGetValue("model").asInteger(); + render_mesh = mFMP->mDecompFloater->childGetValue("render_mesh").asBoolean(); + render_hull = mFMP->mDecompFloater->childGetValue("render_hull").asBoolean(); + } + + if (!mModel[mPreviewLOD].empty()) + { + if (mVertexBuffer[mPreviewLOD].empty()) + { + genBuffers(mPreviewLOD); + } + + if (!avatar_preview) + { + for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) + { + gGL.pushMatrix(); + LLMatrix4 mat = iter->first; + + glMultMatrixf((GLfloat*) mat.mMatrix); + + for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) + { + LLModelInstance& instance = *model_iter; + LLModel* model = instance.mModel; + + if (instance.mTransform != mat) + { + llerrs << "WTF?" << llendl; + } + + if (render_mesh) + { + for (U32 i = 0; i < mVertexBuffer[mPreviewLOD][model].size(); ++i) + { + LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; + + buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); + if (physics) + { + if (physics_idx > -1 && model == mModel[mPreviewLOD][physics_idx]) + { + glColor4f(1,0,0,1); + } + else + { + glColor4f(0.75f, 0.75f, 0.75f, 1.f); + } + } + else + { + glColor4fv(instance.mMaterial[i].mDiffuseColor.mV); + if (i < instance.mMaterial.size() && instance.mMaterial[i].mDiffuseMap.notNull()) + { + gGL.getTexUnit(0)->bind(instance.mMaterial[i].mDiffuseMap, true); + if (instance.mMaterial[i].mDiffuseMap->getDiscardLevel() > -1) + { + mTextureSet.insert(instance.mMaterial[i].mDiffuseMap); + } + } + } + + buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + glColor3f(0.4f, 0.4f, 0.4f); + + if (mFMP->childGetValue("show edges").asBoolean()) + { + glLineWidth(3.f); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glLineWidth(1.f); + } + } + } + + if (render_hull) + { + LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread; + if (decomp) + { + LLMutexLock(decomp->mMutex); + + std::map > >::iterator iter = + mPhysicsMesh.find(model); + if (iter != mPhysicsMesh.end()) + { + for (U32 i = 0; i < iter->second.size(); ++i) + { + if (explode > 0.f) + { + gGL.pushMatrix(); + + LLVector3 offset = model->mHullCenter[i]-model->mPhysicsCenter; + offset *= explode; + + gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]); + } + + static std::vector hull_colors; + + if (i+1 >= hull_colors.size()) + { + hull_colors.push_back(LLColor4U(rand()%128+127, rand()%128+127, rand()%128+127, 255)); + } + + LLVertexBuffer* buff = iter->second[i]; + if (buff) + { + buff->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL); + + glColor4ubv(hull_colors[i].mV); + buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts()); + + if (mFMP->childGetValue("show edges").asBoolean()) + { + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + glLineWidth(3.f); + glColor4ub(hull_colors[i].mV[0]/2, hull_colors[i].mV[1]/2, hull_colors[i].mV[2]/2, 255); + buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts()); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glLineWidth(1.f); + } + } + + if (explode > 0.f) + { + gGL.popMatrix(); + } + } + } + } + + //mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[HULLS]", llformat("%d",decomp->mHulls.size())); + //mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[POINTS]", llformat("%d",decomp->mTotalPoints)); + } + } + + gGL.popMatrix(); + } + + if (physics) + { + mPreviewLOD = LLModel::LOD_PHYSICS; + } + } + else + { + LLVOAvatarSelf* avatar = gAgentAvatarp; + target_pos = avatar->getPositionAgent(); + + LLViewerCamera::getInstance()->setOriginAndLookAt( + target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + offset) * av_rot), // camera + LLVector3::z_axis, // up + target_pos); // point of interest + + avatar->renderCollisionVolumes(); + + for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) + { + for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) + { + LLModelInstance& instance = *model_iter; + LLModel* model = instance.mModel; + + if (!model->mSkinWeights.empty()) + { + for (U32 i = 0; i < mVertexBuffer[mPreviewLOD][model].size(); ++i) + { + LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; + + const LLVolumeFace& face = model->getVolumeFace(i); + + LLStrider position; + buffer->getVertexStrider(position); + + LLStrider weight; + buffer->getWeight4Strider(weight); + + //quick 'n dirty software vertex skinning + + //build matrix palette + LLMatrix4 mat[64]; + for (U32 j = 0; j < model->mJointList.size(); ++j) + { + LLJoint* joint = avatar->getJoint(model->mJointList[j]); + if (joint) + { + mat[j] = model->mInvBindMatrix[j]; + mat[j] *= joint->getWorldMatrix(); + } + } + + for (U32 j = 0; j < buffer->getRequestedVerts(); ++j) + { + LLMatrix4 final_mat; + final_mat.mMatrix[0][0] = final_mat.mMatrix[1][1] = final_mat.mMatrix[2][2] = final_mat.mMatrix[3][3] = 0.f; + + LLVector4 wght; + S32 idx[4]; + + F32 scale = 0.f; + for (U32 k = 0; k < 4; k++) + { + F32 w = weight[j].mV[k]; + + idx[k] = (S32) floorf(w); + wght.mV[k] = w - floorf(w); + scale += wght.mV[k]; + } + + wght *= 1.f/scale; + + for (U32 k = 0; k < 4; k++) + { + F32* src = (F32*) mat[idx[k]].mMatrix; + F32* dst = (F32*) final_mat.mMatrix; + + F32 w = wght.mV[k]; + + for (U32 l = 0; l < 16; l++) + { + dst[l] += src[l]*w; + } + } + + //VECTORIZE THIS + LLVector3 v(face.mPositions[j].getF32ptr()); + + v = v * model->mBindShapeMatrix; + v = v * final_mat; + + position[j] = v; + } + + buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); + glColor4fv(instance.mMaterial[i].mDiffuseColor.mV); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); + glColor3f(0.4f, 0.4f, 0.4f); + + if (mFMP->childGetValue("show edges").asBoolean()) + { + glLineWidth(3.f); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glLineWidth(1.f); + } + } + } + } + } + } + } + + gGL.popMatrix(); + + return TRUE; +} + +//----------------------------------------------------------------------------- +// refresh() +//----------------------------------------------------------------------------- +void LLModelPreview::refresh() +{ + mNeedsUpdate = TRUE; +} + +//----------------------------------------------------------------------------- +// rotate() +//----------------------------------------------------------------------------- +void LLModelPreview::rotate(F32 yaw_radians, F32 pitch_radians) +{ + mCameraYaw = mCameraYaw + yaw_radians; + + mCameraPitch = llclamp(mCameraPitch + pitch_radians, F_PI_BY_TWO * -0.8f, F_PI_BY_TWO * 0.8f); +} + +//----------------------------------------------------------------------------- +// zoom() +//----------------------------------------------------------------------------- +void LLModelPreview::zoom(F32 zoom_amt) +{ + F32 new_zoom = mCameraZoom+zoom_amt; + + mCameraZoom = llclamp(new_zoom, 1.f, 10.f); +} + +void LLModelPreview::pan(F32 right, F32 up) +{ + mCameraOffset.mV[VY] = llclamp(mCameraOffset.mV[VY] + right * mCameraDistance / mCameraZoom, -1.f, 1.f); + mCameraOffset.mV[VZ] = llclamp(mCameraOffset.mV[VZ] + up * mCameraDistance / mCameraZoom, -1.f, 1.f); +} + +void LLModelPreview::setPreviewLOD(S32 lod) +{ + mPreviewLOD = llclamp(lod, 0, 4); + refresh(); +} + +//static +void LLFloaterModelPreview::onBrowseHighLOD(void* data) +{ + LLFloaterModelPreview* mp = (LLFloaterModelPreview*) data; + mp->loadModel(3); +} + +//static +void LLFloaterModelPreview::onBrowseMediumLOD(void* data) +{ + LLFloaterModelPreview* mp = (LLFloaterModelPreview*) data; + mp->loadModel(2); +} + +//static +void LLFloaterModelPreview::onBrowseLowLOD(void* data) +{ + LLFloaterModelPreview* mp = (LLFloaterModelPreview*) data; + mp->loadModel(1); +} + +//static +void LLFloaterModelPreview::onBrowseLowestLOD(void* data) +{ + LLFloaterModelPreview* mp = (LLFloaterModelPreview*) data; + mp->loadModel(0); +} + +//static +void LLFloaterModelPreview::onUpload(void* user_data) +{ + LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; + + if (mp->mDecompFloater) + { + mp->mDecompFloater->closeFloater(); + } + + mp->mModelPreview->rebuildUploadData(); + + gMeshRepo.uploadModel(mp->mModelPreview->mUploadData, mp->mModelPreview->mPreviewScale, mp->childGetValue("upload_textures").asBoolean()); + + mp->closeFloater(false); +} + +//static +void LLFloaterModelPreview::onConsolidate(void* user_data) +{ + LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; + mp->mModelPreview->consolidate(); +} + +//static +void LLFloaterModelPreview::onScrubMaterials(void* user_data) +{ + LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; + mp->mModelPreview->scrubMaterials(); +} + +//static +void LLFloaterModelPreview::onDecompose(void* user_data) +{ + LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; + mp->showDecompFloater(); +} + +//static +void LLFloaterModelPreview::onModelDecompositionComplete(LLModel* model, std::vector >& physics_mesh) +{ + if (sInstance && sInstance->mModelPreview) + { + sInstance->mModelPreview->mPhysicsMesh[model] = physics_mesh; + + sInstance->mModelPreview->mResourceCost = sInstance->mModelPreview->calcResourceCost(); + } +} + + +//static +void LLFloaterModelPreview::refresh(LLUICtrl* ctrl, void* user_data) +{ + LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; + mp->mModelPreview->refresh(); +} + +void LLFloaterModelPreview::updateResourceCost() +{ + U32 cost = mModelPreview->mResourceCost; + childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d",cost)); +} + +//static +void LLModelPreview::textureLoadedCallback( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata ) +{ + LLModelPreview* preview = (LLModelPreview*) userdata; + preview->refresh(); +} + +#endif + -- cgit v1.2.3 From 054e8fbde325c03bc8f9a7c10aa8bb9319d501ba Mon Sep 17 00:00:00 2001 From: "Nyx (Neal Orman)" Date: Thu, 26 Aug 2010 16:52:32 -0400 Subject: buildfix: fixing linux build to handle new SSE2 architecture code reviewed by davep and falcon --- indra/newview/llfloatermodelpreview.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 5dd983d818..91dfb9fc1c 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -2656,8 +2656,8 @@ void LLModelPreview::updateStatusMessages() const F32 ratio = 0.5f; const S32 required_verts = 128; - F32 scaler = powf(0.5f, lod_high-lod); - S32 max_verts = verts[lod_high][i]*scaler; + F32 scaler = powf(ratio, lod_high-lod); + S32 max_verts = (S32)(verts[lod_high][i]*scaler); if (max_verts > required_verts) { //some model in this slot might have more than 128 vertices @@ -2691,8 +2691,8 @@ void LLModelPreview::updateStatusMessages() { const F32 ratio = 0.5f; - F32 scaler = powf(0.5f, lod_high-lod); - S32 max_verts = verts[lod_high][i]*scaler; + F32 scaler = powf(ratio, lod_high-lod); + S32 max_verts = (S32)(verts[lod_high][i]*scaler); if (verts[lod][i] > max_verts) { -- cgit v1.2.3 From 1eeeada0f7c20f190032daa651f884a4a1525df1 Mon Sep 17 00:00:00 2001 From: "Nyx (Neal Orman)" Date: Thu, 26 Aug 2010 18:09:17 -0400 Subject: buildfix - replaced NULL with FALSE gcc doesn't like passing NULL where you mean FALSE. This unsticks the linux build. de-minimis change, no review. --- indra/newview/llfloatermodelpreview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 91dfb9fc1c..a283be7aa7 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1703,7 +1703,7 @@ LLImportMaterial LLModelLoader::profileToMaterial(domProfile_COMMON* material) std::string filename = cdom::uriToNativePath(init->getValue().str()); mat.mDiffuseMap = LLViewerTextureManager::getFetchedTextureFromUrl("file://" + filename, TRUE, LLViewerTexture::BOOST_PREVIEW); - mat.mDiffuseMap->setLoadedCallback(LLModelPreview::textureLoadedCallback, 0, TRUE, FALSE, this->mPreview, NULL, NULL); + mat.mDiffuseMap->setLoadedCallback(LLModelPreview::textureLoadedCallback, 0, TRUE, FALSE, this->mPreview, NULL, FALSE); mat.mDiffuseMap->forceToSaveRawImage(); mat.mDiffuseMapFilename = filename; -- cgit v1.2.3 From 7399c39a2fef7ffaa232047bf2ea16ebef682506 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Thu, 2 Sep 2010 19:13:48 -0500 Subject: Fix for crash when loading models (Don't hit UI from the main thread). Added asserts to LLFastTimer to verify main thread use only. --- indra/newview/llfloatermodelpreview.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index a283be7aa7..b0cde6962b 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -557,6 +557,8 @@ void LLFloaterModelPreview::draw() LLFloater::draw(); LLRect r = getRect(); + mModelPreview->update(); + if (!mLoading) { childSetTextArg("status", "[STATUS]", getString("status_idle")); @@ -1813,6 +1815,7 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloaterModelPreview* fmp mTextureName = 0; mPreviewLOD = 3; mModelLoader = NULL; + mDirty = false; mLODMode[0] = 0; @@ -1881,7 +1884,7 @@ U32 LLModelPreview::calcResourceCost() mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[POINTS]", llformat("%d",num_points)); updateStatusMessages(); - + return cost; } @@ -2024,8 +2027,8 @@ void LLModelPreview::loadModelCallback(S32 lod) clearIncompatible(lod); - mResourceCost = calcResourceCost(); - + mDirty = true; + mPreviewTarget = (mModelLoader->mExtents[0] + mModelLoader->mExtents[1]) * 0.5f; mPreviewScale = (mModelLoader->mExtents[1] - mModelLoader->mExtents[0]) * 0.5f; setPreviewTarget(mPreviewScale.magVec()*2.f); @@ -2864,6 +2867,15 @@ void LLModelPreview::genBuffers(S32 lod) } } +void LLModelPreview::update() +{ + if (mDirty) + { + mDirty = false; + mResourceCost = calcResourceCost(); + } +} + //----------------------------------------------------------------------------- // render() //----------------------------------------------------------------------------- -- cgit v1.2.3 From 4a0f245d3e3c7805aadb571388ceffcc0a7e6085 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Thu, 9 Sep 2010 16:57:23 -0500 Subject: Massage importer UI --- indra/newview/llfloatermodelpreview.cpp | 96 ++++++++++++++++++++++++--------- 1 file changed, 70 insertions(+), 26 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index b0cde6962b..a78d0075c2 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -269,8 +269,6 @@ BOOL LLFloaterModelPreview::postBuild() childSetCommitCallback("show edges", onShowEdgesCommit, this); childSetCommitCallback("auto fill", onAutoFillCommit, this); - childSetCommitCallback("explode", onExplodeCommit, this); - childSetTextArg("status", "[STATUS]", getString("status_idle")); for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) @@ -535,7 +533,7 @@ void LLFloaterModelPreview::onShowEdgesCommit(LLUICtrl* ctrl, void* userdata) //static void LLFloaterModelPreview::onExplodeCommit(LLUICtrl* ctrl, void* userdata) { - LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; + LLFloaterModelPreview* fp = LLFloaterModelPreview::sInstance; fp->mModelPreview->refresh(); } @@ -778,7 +776,7 @@ void LLFloaterModelPreview::showDecompFloater() mDecompFloater = new LLPhysicsDecompFloater(key); S32 left = 20; - S32 right = 270; + S32 right = 320; S32 cur_y = 30; @@ -839,15 +837,19 @@ void LLFloaterModelPreview::showDecompFloater() continue; } + std::string name(param[i].mName ? param[i].mName : ""); + std::string description(param[i].mDescription ? param[i].mDescription : ""); + if (param[i].mType == LLCDParam::LLCD_FLOAT) { LLSliderCtrl::Params p; - p.name(param[i].mName); - p.label(param[i].mName); + p.name(name); + p.label(name); p.rect(LLRect(left, cur_y, right, cur_y-20)); p.min_value(param[i].mDetails.mRange.mLow.mFloat); p.max_value(param[i].mDetails.mRange.mHigh.mFloat); p.increment(param[i].mDetails.mRange.mDelta.mFloat); + p.tool_tip(description); p.decimal_digits(3); p.initial_value(param[i].mDefault.mFloat); LLSliderCtrl* slider = LLUICtrlFactory::create(p); @@ -858,12 +860,13 @@ void LLFloaterModelPreview::showDecompFloater() else if (param[i].mType == LLCDParam::LLCD_INTEGER) { LLSliderCtrl::Params p; - p.name(param[i].mName); - p.label(param[i].mName); + p.name(name); + p.label(name); p.rect(LLRect(left, cur_y, right, cur_y-20)); p.min_value(param[i].mDetails.mRange.mLow.mIntOrEnumValue); p.max_value(param[i].mDetails.mRange.mHigh.mIntOrEnumValue); p.increment(param[i].mDetails.mRange.mDelta.mIntOrEnumValue); + p.tool_tip(description); p.initial_value(param[i].mDefault.mIntOrEnumValue); LLSliderCtrl* slider = LLUICtrlFactory::create(p); slider->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); @@ -874,9 +877,10 @@ void LLFloaterModelPreview::showDecompFloater() { LLCheckBoxCtrl::Params p; p.rect(LLRect(left, cur_y, right, cur_y-20)); - p.name(param[i].mName); - p.label(param[i].mName); + p.name(name); + p.label(name); p.initial_value(param[i].mDefault.mBool); + p.tool_tip(description); LLCheckBoxCtrl* check_box = LLUICtrlFactory::create(p); check_box->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); mDecompFloater->addChild(check_box); @@ -884,24 +888,61 @@ void LLFloaterModelPreview::showDecompFloater() } else if (param[i].mType == LLCDParam::LLCD_ENUM) { - LLComboBox::Params p; - p.rect(LLRect(left, cur_y, right/3, cur_y-20)); - p.name(param[i].mName); - p.label(param[i].mName); - LLComboBox* combo_box = LLUICtrlFactory::create(p); - for (S32 k = 0; k < param[i].mDetails.mEnumValues.mNumEnums; ++k) - { - combo_box->add(param[i].mDetails.mEnumValues.mEnumsArray[k].mName, - LLSD::Integer(param[i].mDetails.mEnumValues.mEnumsArray[k].mValue)); + S32 cur_x = left; + + { //add label + LLTextBox::Params p; + const LLFontGL* font = (LLFontGL*) p.font(); + + p.rect(LLRect(left, cur_y, left+font->getWidth(name), cur_y-20)); + p.name(name); + p.label(name); + p.initial_value(name); + LLTextBox* text_box = LLUICtrlFactory::create(p); + mDecompFloater->addChild(text_box); + cur_x += text_box->getRect().getWidth(); + } + + { //add combo_box + LLComboBox::Params p; + p.rect(LLRect(cur_x, cur_y, right-right/4, cur_y-20)); + p.name(name); + p.label(name); + p.tool_tip(description); + + LLComboBox* combo_box = LLUICtrlFactory::create(p); + for (S32 k = 0; k < param[i].mDetails.mEnumValues.mNumEnums; ++k) + { + combo_box->add(param[i].mDetails.mEnumValues.mEnumsArray[k].mName, + LLSD::Integer(param[i].mDetails.mEnumValues.mEnumsArray[k].mValue)); + } + combo_box->setValue(param[i].mDefault.mIntOrEnumValue); + combo_box->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); + mDecompFloater->addChild(combo_box); + cur_y += 30; } - combo_box->setValue(param[i].mDefault.mIntOrEnumValue); - combo_box->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); - mDecompFloater->addChild(combo_box); - cur_y += 30; } } } + cur_y += 30; + //explode slider + { + LLSliderCtrl::Params p; + p.initial_value(0); + p.min_value(0); + p.max_value(1); + p.decimal_digits(2); + p.increment(0.05f); + p.label("Explode"); + p.name("explode"); + p.rect(LLRect(left, cur_y, right, cur_y-20)); + LLSliderCtrl* slider = LLUICtrlFactory::create(p); + + mDecompFloater->addChild(slider); + cur_y += 30; + } + //mesh render checkbox { LLCheckBoxCtrl::Params p; @@ -928,15 +969,16 @@ void LLFloaterModelPreview::showDecompFloater() LLTextBox::Params p; p.label("Model"); p.name("model label"); - p.rect(LLRect(right/3, cur_y, right/2, cur_y-20)); + p.rect(LLRect(right/2, cur_y, right-right/3, cur_y-20)); LLTextBox* text_box = LLUICtrlFactory::create(p); text_box->setValue("Model"); mDecompFloater->addChild(text_box); } + { //add submesh combo box LLComboBox::Params p; - p.rect(LLRect(right/2, cur_y, right, cur_y-20)); + p.rect(LLRect(right-right/2+p.font()->getWidth("Model"), cur_y, right, cur_y-20)); p.name("model"); LLComboBox* combo_box = LLUICtrlFactory::create(p); for (S32 i = 0; i < mModelPreview->mBaseModel.size(); ++i) @@ -956,6 +998,8 @@ void LLFloaterModelPreview::showDecompFloater() mDecompFloater->setRect(LLRect(10, cur_y+20, right+20, 10)); } + mDecompFloater->childSetCommitCallback("explode", LLFloaterModelPreview::onExplodeCommit, this); + mDecompFloater->openFloater(); } @@ -2922,7 +2966,7 @@ BOOL LLModelPreview::render() mFMP->childSetEnabled("consolidate", !avatar_preview); - F32 explode = mFMP->childGetValue("explode").asReal(); + F32 explode = mFMP->mDecompFloater ? mFMP->mDecompFloater->childGetValue("explode").asReal() : 0.f; glMatrixMode(GL_PROJECTION); gGL.popMatrix(); -- cgit v1.2.3 From c7624892b25824e80c79a9c5d7c3ae3f23410fc6 Mon Sep 17 00:00:00 2001 From: "Matthew Breindel (Falcon)" Date: Wed, 15 Sep 2010 13:24:15 -0700 Subject: Fixed threading-related crash that would occur when decomposition completed. --- indra/newview/llfloatermodelpreview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index a78d0075c2..85035fb961 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -3409,7 +3409,7 @@ void LLFloaterModelPreview::onModelDecompositionComplete(LLModel* model, std::ve { sInstance->mModelPreview->mPhysicsMesh[model] = physics_mesh; - sInstance->mModelPreview->mResourceCost = sInstance->mModelPreview->calcResourceCost(); + sInstance->mModelPreview->mDirty = true; } } -- cgit v1.2.3 From d670fdac295629c1afb0bf2bcda50261d053eb5b Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Mon, 20 Sep 2010 21:56:16 -0500 Subject: SH-113 Fix for crash on consolidate after generating LOD. --- indra/newview/llfloatermodelpreview.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 85035fb961..3ef892f739 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -2603,6 +2603,9 @@ void LLModelPreview::genLODs(S32 which_lod) target_model->mInvBindMatrix = base->mInvBindMatrix; target_model->mBindShapeMatrix = base->mBindShapeMatrix; + //copy material list + target_model->mMaterialList = base->mMaterialList; + if (!validate_model(target_model)) { llerrs << "Invalid model generated when creating LODs" << llendl; -- cgit v1.2.3 From 90e3d83a5cb35e98a02a3017dd79ebc272bbfe85 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Tue, 21 Sep 2010 13:26:52 -0400 Subject: Fix for build failures - disabling tcmalloc for now --- indra/newview/llfloatermodelpreview.cpp | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 indra/newview/llfloatermodelpreview.cpp (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp old mode 100644 new mode 100755 -- cgit v1.2.3 From cf09d6c58a741263cddcf338c2f79836873475b1 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 22 Sep 2010 03:04:21 -0500 Subject: Remove LL_MESH_ENABLED macros (fixes drag and drop). Add mesh stitching type back into tools floater. --- indra/newview/llfloatermodelpreview.cpp | 5 ----- 1 file changed, 5 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 3ef892f739..088c9e6546 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -98,9 +98,6 @@ #include "glod/glod.h" - -#if LL_MESH_ENABLED - //static S32 LLFloaterModelPreview::sUploadAmount = 10; LLFloaterModelPreview* LLFloaterModelPreview::sInstance = NULL; @@ -3437,5 +3434,3 @@ void LLModelPreview::textureLoadedCallback( BOOL success, LLViewerFetchedTexture preview->refresh(); } -#endif - -- cgit v1.2.3 From 7b44a8ee8de662355c8f5c8091ab25dccce494e5 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 22 Sep 2010 15:58:35 -0500 Subject: SH-110 Fix for viewer crash when checking HULL in decomposition window... converted various maps to use smart pointers for keys instead of naked pointers, properly clear maps on various operations. --- indra/newview/llfloatermodelpreview.cpp | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 088c9e6546..8be56009aa 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1989,13 +1989,13 @@ void LLModelPreview::loadModel(std::string filename, S32 lod) if (lod == 3 && !mGroup.empty()) { - for (std::map::iterator iter = mGroup.begin(); iter != mGroup.end(); ++iter) + for (std::map, U32>::iterator iter = mGroup.begin(); iter != mGroup.end(); ++iter) { glodDeleteGroup(iter->second); stop_gloderror(); } - for (std::map::iterator iter = mObject.begin(); iter != mObject.end(); ++iter) + for (std::map, U32>::iterator iter = mObject.begin(); iter != mObject.end(); ++iter) { glodDeleteObject(iter->second); stop_gloderror(); @@ -2055,6 +2055,11 @@ void LLModelPreview::loadModelCallback(S32 lod) mScene[lod] = mModelLoader->mScene; mVertexBuffer[lod].clear(); + if (lod == LLModel::LOD_PHYSICS) + { + mPhysicsMesh.clear(); + } + setPreviewLOD(lod); @@ -2338,6 +2343,11 @@ void LLModelPreview::genLODs(S32 which_lod) return; } + if (which_lod == LLModel::LOD_PHYSICS) + { //clear physics mesh map + mPhysicsMesh.clear(); + } + LLVertexBuffer::unbind(); stop_gloderror(); @@ -2365,6 +2375,14 @@ void LLModelPreview::genLODs(S32 which_lod) U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; + if (mGroup[mBaseModel[0]] == 0) + { //clear LOD maps + mGroup.clear(); + mObject.clear(); + mPercentage.clear(); + mPatch.clear(); + } + for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) { //build GLOD objects for each model in base model list LLModel* mdl = *iter; @@ -3118,7 +3136,7 @@ BOOL LLModelPreview::render() { LLMutexLock(decomp->mMutex); - std::map > >::iterator iter = + std::map, std::vector > >::iterator iter = mPhysicsMesh.find(model); if (iter != mPhysicsMesh.end()) { @@ -3406,7 +3424,7 @@ void LLFloaterModelPreview::onDecompose(void* user_data) void LLFloaterModelPreview::onModelDecompositionComplete(LLModel* model, std::vector >& physics_mesh) { if (sInstance && sInstance->mModelPreview) - { + { sInstance->mModelPreview->mPhysicsMesh[model] = physics_mesh; sInstance->mModelPreview->mDirty = true; -- cgit v1.2.3 From bc488500962f75ac6d5dcdac4db4f2d7f293bf89 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Thu, 23 Sep 2010 01:18:44 -0500 Subject: SH-176 Fix for physics triangle limit limiting high LOD triangle limit. --- indra/newview/llfloatermodelpreview.cpp | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 8be56009aa..1796f76f03 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -2917,16 +2917,6 @@ void LLModelPreview::genBuffers(S32 lod) } } - - if (lod == 4) - { - for (U32 i = 0; i < 4; i++) - { - LLSpinCtrl* lim = mFMP->getChild(limit_name[i], TRUE); - - lim->setMaxValue(tri_count); - } - } } void LLModelPreview::update() -- cgit v1.2.3 From c7f5a9419b4b93efdc04ebfbb8e05a2ef0e09142 Mon Sep 17 00:00:00 2001 From: prep linden Date: Fri, 24 Sep 2010 13:11:53 -0400 Subject: Added support for joint offsets --- indra/newview/llfloatermodelpreview.cpp | 127 +++++++++++++++++++++++++++++++- 1 file changed, 126 insertions(+), 1 deletion(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 1796f76f03..3fe5d08bb3 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -318,6 +318,8 @@ LLFloaterModelPreview::~LLFloaterModelPreview() { sInstance = NULL; + gAgentAvatarp->resetJointPositions(); + delete mModelPreview; if (mGLName) @@ -1304,6 +1306,106 @@ void LLModelLoader::run() model->mBindShapeMatrix = rotation; }*/ + //The joint transfom map that we'll populate below + std::map jointTransforms; + jointTransforms.clear(); + + //Some collada setup for accessing the skeleton + daeElement* pElement = 0; + dae.getDatabase()->getElement( &pElement, 0, 0, "skeleton" ); + domInstance_controller::domSkeleton* pSkeleton = daeSafeCast( pElement ); + if ( pSkeleton ) + { + //Get the root node of the skeleton + daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement(); + if ( pSkeletonRootNode ) + { + //Once we have the root node - start acccessing it's joint components + static const int jointCnt = mJointMap.size(); + std::map :: const_iterator jointIt = mJointMap.begin(); + bool missingID = false; + //Loop over all the possible joints within the .dae - using the allowed joint list in the ctor. + for ( int i=0; i(resolver.getElement()); + if ( pJoint ) + { + //Pull out the translate id and store it in the jointTranslations map + daeSIDResolver jointResolver( pJoint, "./translate" ); + domTranslate* pTranslate = daeSafeCast( jointResolver.getElement() ); + + LLMatrix4 workingTransform; + + //Translation + if ( pTranslate ) + { + domFloat3 jointTrans = pTranslate->getValue(); + LLVector3 singleJointTranslation( jointTrans[0], jointTrans[1], jointTrans[2] ); + workingTransform.setTranslation( singleJointTranslation ); + } + else + { + missingID = true; + llwarns<< "No translation sid!" << llendl; + } + //Store the joint transform w/respect to it's name. + jointTransforms[(*jointIt).second.c_str()] = workingTransform; + + } + else + { + missingID = true; + llwarns<< "Missing joint." << llendl; + } + } + + //If anything failed in regards to extracting the skeleton, joints or translation id, + //mention it + if ( missingID ) + { + llwarns<< "Partial jointmap found in asset - did you mean to just have a partial map?" << llendl; + } + + //Set the joint translations on the avatar + //The joints are reset in the dtor + jointIt = mJointMap.begin(); + for ( int i=0; igetJoint( lookingForJoint ); + if ( pJoint ) + { + pJoint->storeCurrentXform( jointTransform.getTranslation() ); + } + else + { + //Most likely an error in the asset. + llwarns<<"Tried to apply joint position from .dae, but it did not exist in the avatar rig." << llendl; + } + } + } + } + else + { + llwarns<<"No root node in this skeleton" << llendl; + } + } + else + { + llwarns<<"No skeleton in this asset" << llendl; + } domSkin::domJoints* joints = skin->getJoints(); @@ -1391,6 +1493,29 @@ void LLModelLoader::run() } } + //We need to construct the alternate bind matrix (which contains the new joint positions) + //in the same order as they were stored in the joint buffer. The joints associated + //with the skeleton are not stored in the same order as they are in the exported joint buffer. + //This remaps the skeletal joints to be in the same order as the joints stored in the model. + std::vector :: const_iterator jointIt = model->mJointList.begin(); + static const int jointCnt = model->mJointList.size(); + for ( int i=0; imInvBindMatrix[i]; + newInverse.setTranslation( jointTransforms[lookingForJoint].getTranslation() ); + model->mAlternateBindMatrix.push_back( newInverse ); + } + else + { + llwarns<<"Possibly misnamed/missing joint [" <mJointList = base->mJointList; target_model->mInvBindMatrix = base->mInvBindMatrix; target_model->mBindShapeMatrix = base->mBindShapeMatrix; - + target_model->mAlternateBindMatrix = base->mAlternateBindMatrix; //copy material list target_model->mMaterialList = base->mMaterialList; -- cgit v1.2.3 From 40150f31ce9b0af4b58c2bd195c9cf571fb5b549 Mon Sep 17 00:00:00 2001 From: prep linden Date: Fri, 24 Sep 2010 17:19:44 -0400 Subject: Fixed a mesh upload issue where if the asset did not contain a rig the avatar would disappear for the current session. --- indra/newview/llfloatermodelpreview.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 3fe5d08bb3..0cdd5b9898 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -318,7 +318,10 @@ LLFloaterModelPreview::~LLFloaterModelPreview() { sInstance = NULL; - gAgentAvatarp->resetJointPositions(); + if ( mModelPreview->containsRiggedAsset() ) + { + gAgentAvatarp->resetJointPositions(); + } delete mModelPreview; @@ -2461,6 +2464,21 @@ void LLModelPreview::scrubMaterials() refresh(); } +bool LLModelPreview::containsRiggedAsset( void ) +{ + //loop through the models and determine if any of them contained a rigged asset, and if so + //return true. + //This is used to cleanup the joint positions after a preview. + for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) + { + LLModel* pModel = *iter; + if ( pModel->mAlternateBindMatrix.size() > 0 ) + { + return true; + } + } + return false; +} void LLModelPreview::genLODs(S32 which_lod) { if (mBaseModel.empty()) -- cgit v1.2.3 From 613894c8cca25f9fa86da7056da3594fe8771d46 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 28 Sep 2010 13:45:42 -0500 Subject: SH-238 Add check boxes to upload skin weights (or not) and/or joint positions (or not). Remove llfloaterimportcollada Reviewed by Prep. --- indra/newview/llfloatermodelpreview.cpp | 114 ++++++++++++++++++++++++++++---- 1 file changed, 100 insertions(+), 14 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 0cdd5b9898..f995ddd6d0 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -297,6 +297,12 @@ BOOL LLFloaterModelPreview::postBuild() childSetCommitCallback("preview_lod_combo", onPreviewLODCommit, this); + childSetCommitCallback("upload_skin", onUploadSkinCommit, this); + childSetCommitCallback("upload_joints", onUploadJointsCommit, this); + + childDisable("upload_skin"); + childDisable("upload_joints"); + const U32 width = 512; const U32 height = 512; @@ -389,6 +395,35 @@ void LLFloaterModelPreview::setLimit(S32 lod, S32 limit) } } +//static +void LLFloaterModelPreview::onUploadJointsCommit(LLUICtrl*,void* userdata) +{ + LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; + + if (!fp->mModelPreview) + { + return; + } + + fp->mModelPreview->refresh(); +} + +//static +void LLFloaterModelPreview::onUploadSkinCommit(LLUICtrl*,void* userdata) +{ + LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; + + if (!fp->mModelPreview) + { + return; + } + + fp->mModelPreview->refresh(); + fp->mModelPreview->resetPreviewTarget(); + fp->mModelPreview->clearBuffers(); +} + +//static void LLFloaterModelPreview::onPreviewLODCommit(LLUICtrl* ctrl, void* userdata) { LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; @@ -2031,13 +2066,15 @@ U32 LLModelPreview::calcResourceCost() LLModel::physics_shape& physics_shape = instance.mLOD[LLModel::LOD_PHYSICS] ? instance.mLOD[LLModel::LOD_PHYSICS]->mPhysicsShape : instance.mModel->mPhysicsShape; LLSD ret = LLModel::writeModel("", - instance.mLOD[4], + instance.mLOD[4], instance.mLOD[3], instance.mLOD[2], instance.mLOD[1], instance.mLOD[0], physics_shape, - TRUE); + mFMP->childGetValue("upload_skin").asBoolean(), + mFMP->childGetValue("upload_joints").asBoolean(), + true); cost += gMeshRepo.calcResourceCost(ret); @@ -2203,12 +2240,17 @@ void LLModelPreview::loadModelCallback(S32 lod) mDirty = true; + resetPreviewTarget(); + + mFMP->mLoading = FALSE; + refresh(); +} + +void LLModelPreview::resetPreviewTarget() +{ mPreviewTarget = (mModelLoader->mExtents[0] + mModelLoader->mExtents[1]) * 0.5f; mPreviewScale = (mModelLoader->mExtents[1] - mModelLoader->mExtents[0]) * 0.5f; setPreviewTarget(mPreviewScale.magVec()*2.f); - - mFMP->mLoading = FALSE; - refresh(); } void LLModelPreview::smoothNormals() @@ -2556,7 +2598,7 @@ void LLModelPreview::genLODs(S32 which_lod) if (mVertexBuffer[5].empty()) { - genBuffers(5); + genBuffers(5, false); } U32 tri_count = 0; @@ -2935,7 +2977,15 @@ void LLModelPreview::setPreviewTarget(F32 distance) mCameraOffset.clearVec(); } -void LLModelPreview::genBuffers(S32 lod) +void LLModelPreview::clearBuffers() +{ + for (U32 i = 0; i < 6; i++) + { + mVertexBuffer[i].clear(); + } +} + +void LLModelPreview::genBuffers(S32 lod, bool avatar_preview) { U32 tri_count = 0; U32 vertex_count = 0; @@ -2986,7 +3036,7 @@ void LLModelPreview::genBuffers(S32 lod) LLVertexBuffer* vb = NULL; - bool skinned = !mdl->mSkinWeights.empty(); + bool skinned = avatar_preview && !mdl->mSkinWeights.empty(); U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; @@ -3021,13 +3071,12 @@ void LLModelPreview::genBuffers(S32 lod) if (skinned) { - // build vertices and normals for (U32 i = 0; i < num_vertices; i++) { //find closest weight to vf.mVertices[i].mPosition LLVector3 pos(vf.mPositions[i].getF32ptr()); - LLModel::weight_list weight_list = base_mdl->getJointInfluences(pos); + const LLModel::weight_list& weight_list = base_mdl->getJointInfluences(pos); LLVector4 w(0,0,0,0); if (weight_list.size() > 4) @@ -3102,6 +3151,9 @@ BOOL LLModelPreview::render() gl_rect_2d_simple( width, height ); bool avatar_preview = false; + bool upload_skin = mFMP->childGetValue("upload_skin").asBoolean(); + bool upload_joints = mFMP->childGetValue("upload_joints").asBoolean(); + for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) { for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) @@ -3115,6 +3167,39 @@ BOOL LLModelPreview::render() } } + if (upload_skin && !avatar_preview) + { + mFMP->childSetValue("upload_skin", false); + upload_skin = false; + } + + if (!upload_skin && upload_joints) + { + mFMP->childSetValue("upload_joints", false); + upload_joints = false; + } + + if (!avatar_preview) + { + mFMP->childDisable("upload_skin"); + } + else + { + mFMP->childEnable("upload_skin"); + } + + if (!upload_skin) + { + mFMP->childDisable("upload_joints"); + } + else + { + mFMP->childEnable("upload_joints"); + } + + avatar_preview = avatar_preview && upload_skin; + + mFMP->childSetEnabled("consolidate", !avatar_preview); F32 explode = mFMP->mDecompFloater ? mFMP->mDecompFloater->childGetValue("explode").asReal() : 0.f; @@ -3171,8 +3256,8 @@ BOOL LLModelPreview::render() if (!mBaseModel.empty() && mVertexBuffer[5].empty()) { - genBuffers(-1); - genBuffers(3); + genBuffers(-1, avatar_preview); + //genBuffers(3); //genLODs(); } @@ -3194,7 +3279,7 @@ BOOL LLModelPreview::render() { if (mVertexBuffer[mPreviewLOD].empty()) { - genBuffers(mPreviewLOD); + genBuffers(mPreviewLOD, avatar_preview); } if (!avatar_preview) @@ -3527,7 +3612,8 @@ void LLFloaterModelPreview::onUpload(void* user_data) mp->mModelPreview->rebuildUploadData(); - gMeshRepo.uploadModel(mp->mModelPreview->mUploadData, mp->mModelPreview->mPreviewScale, mp->childGetValue("upload_textures").asBoolean()); + gMeshRepo.uploadModel(mp->mModelPreview->mUploadData, mp->mModelPreview->mPreviewScale, + mp->childGetValue("upload_textures").asBoolean(), mp->childGetValue("upload_skin"), mp->childGetValue("upload_joints")); mp->closeFloater(false); } -- cgit v1.2.3 From 0c93da0501ab1debd6fa11af29a215be81f7b803 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 29 Sep 2010 16:09:21 -0500 Subject: SH-224 Add new streaming cost algorithm debug displays to viewer. Add the ability to clear LOD slots. Make triangle count UI more responsive to Generate LOD button. Add triangle count debug display for current selection. Reviewed by Nyx --- indra/newview/llfloatermodelpreview.cpp | 161 +++++++++++++++++++++----------- 1 file changed, 108 insertions(+), 53 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index f995ddd6d0..f98a708dae 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -300,6 +300,8 @@ BOOL LLFloaterModelPreview::postBuild() childSetCommitCallback("upload_skin", onUploadSkinCommit, this); childSetCommitCallback("upload_joints", onUploadJointsCommit, this); + childSetCommitCallback("debug scale", onDebugScaleCommit, this); + childDisable("upload_skin"); childDisable("upload_joints"); @@ -353,6 +355,23 @@ void LLFloaterModelPreview::loadModel(S32 lod) void LLFloaterModelPreview::setLODMode(S32 lod, S32 mode) { if (mode == 0) + { + if (lod != LLModel::LOD_PHYSICS) + { + for (S32 i = lod; i > 0; i--) + { + mModelPreview->clearModel(lod); + } + } + else + { + mModelPreview->clearModel(lod); + } + + mModelPreview->refresh(); + mModelPreview->calcResourceCost(); + } + else if (mode == 1) { loadModel(lod); } @@ -367,7 +386,7 @@ void LLFloaterModelPreview::setLODMode(S32 lod, S32 mode) LLSpinCtrl* lim = getChild(limit_name[lod], TRUE); - if (mode == 1) //triangle count + if (mode == 2) //triangle count { U32 tri_count = 0; for (LLModelLoader::model_list::iterator iter = mModelPreview->mBaseModel.begin(); @@ -395,6 +414,19 @@ void LLFloaterModelPreview::setLimit(S32 lod, S32 limit) } } +//static +void LLFloaterModelPreview::onDebugScaleCommit(LLUICtrl*,void* userdata) +{ + LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; + + if (!fp->mModelPreview) + { + return; + } + + fp->mModelPreview->calcResourceCost(); +} + //static void LLFloaterModelPreview::onUploadJointsCommit(LLUICtrl*,void* userdata) { @@ -2055,6 +2087,10 @@ U32 LLModelPreview::calcResourceCost() U32 num_points = 0; U32 num_hulls = 0; + F32 debug_scale = mFMP->childGetValue("debug scale").asReal(); + + F32 streaming_cost = 0.f; + for (U32 i = 0; i < mUploadData.size(); ++i) { LLModelInstance& instance = mUploadData[i]; @@ -2076,18 +2112,35 @@ U32 LLModelPreview::calcResourceCost() mFMP->childGetValue("upload_joints").asBoolean(), true); cost += gMeshRepo.calcResourceCost(ret); - num_hulls += physics_shape.size(); for (U32 i = 0; i < physics_shape.size(); ++i) { num_points += physics_shape[i].size(); } + + //calculate streaming cost + LLMatrix4 transformation = instance.mTransform; + + LLVector3 position = LLVector3(0, 0, 0) * transformation; + + LLVector3 x_transformed = LLVector3(1, 0, 0) * transformation - position; + LLVector3 y_transformed = LLVector3(0, 1, 0) * transformation - position; + LLVector3 z_transformed = LLVector3(0, 0, 1) * transformation - position; + F32 x_length = x_transformed.normalize(); + F32 y_length = y_transformed.normalize(); + F32 z_length = z_transformed.normalize(); + LLVector3 scale = LLVector3(x_length, y_length, z_length); + + F32 radius = scale.length()*debug_scale; + + streaming_cost += LLMeshRepository::getStreamingCost(ret, radius); } } mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[HULLS]", llformat("%d",num_hulls)); mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[POINTS]", llformat("%d",num_points)); + mFMP->childSetTextArg("streaming cost", "[COST]", llformat("%.3f", streaming_cost)); updateStatusMessages(); @@ -2136,6 +2189,18 @@ void LLModelPreview::rebuildUploadData() } +void LLModelPreview::clearModel(S32 lod) +{ + if (lod < 0 || lod > LLModel::LOD_PHYSICS) + { + return; + } + + mVertexBuffer[lod].clear(); + mModel[lod].clear(); + mScene[lod].clear(); +} + void LLModelPreview::loadModel(std::string filename, S32 lod) { LLMutexLock lock(this); @@ -2639,65 +2704,63 @@ void LLModelPreview::genLODs(S32 which_lod) } - if (which_lod == -1 || mLODMode[which_lod] == 1) - { - //generating LODs for all entries, or this entry has a triangle budget - glodGroupParameteri(mGroup[mdl], GLOD_ADAPT_MODE, GLOD_TRIANGLE_BUDGET); - stop_gloderror(); - } - else - { - //this entry uses error mode - glodGroupParameteri(mGroup[mdl], GLOD_ADAPT_MODE, GLOD_OBJECT_SPACE_ERROR); - stop_gloderror(); - } - - if (which_lod != -1 && mLODMode[which_lod] == 2) - { - glodGroupParameterf(mGroup[mdl], GLOD_OBJECT_SPACE_ERROR_THRESHOLD, llmax(limit/100.f, 0.01f)); - stop_gloderror(); - } - else - { - glodGroupParameterf(mGroup[mdl], GLOD_OBJECT_SPACE_ERROR_THRESHOLD, 0.025f); - stop_gloderror(); - } + //generating LODs for all entries, or this entry has a triangle budget + glodGroupParameteri(mGroup[mdl], GLOD_ADAPT_MODE, GLOD_TRIANGLE_BUDGET); + stop_gloderror(); + + glodGroupParameterf(mGroup[mdl], GLOD_OBJECT_SPACE_ERROR_THRESHOLD, 0.025f); + stop_gloderror(); } S32 start = LLModel::LOD_HIGH; S32 end = 0; - BOOL error_mode = FALSE; - if (which_lod != -1) { start = end = which_lod; - - if (mLODMode[which_lod] == 2) - { - error_mode = TRUE; - } } + std::string combo_name[] = + { + "lowest detail combo", + "low detail combo", + "medium detail combo", + "high detail combo", + "physics detail combo" + }; + + std::string limit_name[] = + { + "lowest limit", + "low limit", + "medium limit", + "high limit", + "physics limit" + }; + for (S32 lod = start; lod >= end; --lod) { - if (!error_mode) + if (which_lod == -1) { - if (which_lod == -1) + if (lod < start) { - if (lod < start) - { - triangle_count /= 3; - } - } - else - { - triangle_count = limit; + triangle_count /= 3; } } + else + { + triangle_count = limit; + } + LLComboBox* combo_box = mFMP->findChild(combo_name[lod]); + combo_box->setCurrentByIndex(2); + + LLSpinCtrl* lim = mFMP->getChild(limit_name[lod], TRUE); + lim->setMaxValue(base_triangle_count); + lim->setVisible(true); + mModel[lod].clear(); mModel[lod].resize(mBaseModel.size()); mVertexBuffer[lod].clear(); @@ -2712,22 +2775,14 @@ void LLModelPreview::genLODs(S32 which_lod) U32 target_count = U32(mPercentage[base]*triangle_count); - if (error_mode) - { - target_count = base->getNumTriangles(); - } - if (target_count < 4) { target_count = 4; } - if (which_lod == -1 || mLODMode[which_lod] == 1) - { - glodGroupParameteri(mGroup[base], GLOD_MAX_TRIANGLES, target_count); - stop_gloderror(); - } - + glodGroupParameteri(mGroup[base], GLOD_MAX_TRIANGLES, target_count); + stop_gloderror(); + glodAdaptGroup(mGroup[base]); stop_gloderror(); -- cgit v1.2.3 From eb3a78ebe4c58cceea485697d58df7d4796c0a1f Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Fri, 1 Oct 2010 17:41:58 -0500 Subject: remove lod requirements check from model importer. --- indra/newview/llfloatermodelpreview.cpp | 36 +++++---------------------------- 1 file changed, 5 insertions(+), 31 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index f98a708dae..02e76d8b17 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -2954,50 +2954,24 @@ void LLModelPreview::updateStatusMessages() if (lod != lod_high) { - if (total_submeshes[lod] == 0) - { //no model loaded for this lod, see if one is required - for (U32 i = 0; i < verts[lod_high].size(); ++i) - { - const F32 ratio = 0.5f; - const S32 required_verts = 128; - - F32 scaler = powf(ratio, lod_high-lod); - S32 max_verts = (S32)(verts[lod_high][i]*scaler); - - if (max_verts > required_verts) - { //some model in this slot might have more than 128 vertices - - //if any model higher up the chain has more than 128 vertices, - // lod is required here - for (S32 j = lod+1; j <= LLModel::LOD_HIGH; ++j) - { - if (verts[j].size() > i && verts[j][i] > 128) - { - message = "required"; - upload_message = "missing_lod"; - } - } - } - } - } - else if (total_submeshes[lod] != total_submeshes[lod_high]) + if (total_submeshes[lod] && total_submeshes[lod] != total_submeshes[lod_high]) { message = "mesh_mismatch"; upload_message = "bad_lod"; } - else if (tris[lod].size() != tris[lod_high].size()) + else if (!tris[lod].empty() && tris[lod].size() != tris[lod_high].size()) { message = "model_mismatch"; upload_message = "bad_lod"; } - else + else if (!verts[lod].empty()) { for (U32 i = 0; i < verts[lod].size(); ++i) { const F32 ratio = 0.5f; - F32 scaler = powf(ratio, lod_high-lod); - S32 max_verts = (S32)(verts[lod_high][i]*scaler); + F32 scaler = 1.f; + S32 max_verts = (S32)(verts[lod+1][i]*scaler); if (verts[lod][i] > max_verts) { -- cgit v1.2.3 From 9ee06f2f90fd4350676c1d62cabdcc647efe7e7a Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Sat, 2 Oct 2010 13:26:14 -0500 Subject: Remove unused variables. --- indra/newview/llfloatermodelpreview.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 02e76d8b17..1336043b7f 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -2968,10 +2968,7 @@ void LLModelPreview::updateStatusMessages() { for (U32 i = 0; i < verts[lod].size(); ++i) { - const F32 ratio = 0.5f; - - F32 scaler = 1.f; - S32 max_verts = (S32)(verts[lod+1][i]*scaler); + S32 max_verts = verts[lod+1][i]; if (verts[lod][i] > max_verts) { -- cgit v1.2.3 From 4fd10e42383aba2eb9e68ff837c8eacb9cee3e83 Mon Sep 17 00:00:00 2001 From: "Nyx (Neal Orman)" Date: Mon, 4 Oct 2010 17:56:00 -0400 Subject: SH-79 FIX upload window shows status "loading" if file selection canceled Extended the current filename checking to handle the case where we have a user cancel a selection of an LOD file beyond the first. mLoading is made false in either case, but the dialog is closed if a file has not been chosen for the highest LOD. --- indra/newview/llfloatermodelpreview.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index f98a708dae..6e051c66a9 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -2211,9 +2211,16 @@ void LLModelPreview::loadModel(std::string filename, S32 lod) mModelLoader = NULL; } - if (filename.empty() && mBaseModel.empty()) + if (filename.empty()) { - mFMP->closeFloater(false); + if (mBaseModel.empty()) + { + // this is the initial file picking. Close the whole floater + // if we don't have a base model to show for high LOD. + mFMP->closeFloater(false); + } + + mFMP->mLoading = false; return; } -- cgit v1.2.3 From 87a9f475756d54d9d98c8cbb6395f89d6fc4606a Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 5 Oct 2010 16:49:05 -0500 Subject: Rewrite LLPhysicsDecomp to have a more generic callback system. Reviewed by prep. --- indra/newview/llfloatermodelpreview.cpp | 147 ++++++++++++++++++++++++-------- 1 file changed, 110 insertions(+), 37 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 1336043b7f..69e641c074 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -636,7 +636,15 @@ void LLFloaterModelPreview::draw() if (mDecompFloater) { - mDecompFloater->childSetText("status", gMeshRepo.mDecompThread->mStatus); + if (mCurRequest.notNull()) + { + mDecompFloater->childSetText("status", mCurRequest->mStatusMessage); + } + else + { + const std::string idle("Idle."); + mDecompFloater->childSetText("status", std::string("Idle.")); + } } U32 resource_cost = mModelPreview->mResourceCost*10; @@ -773,34 +781,20 @@ BOOL LLFloaterModelPreview::handleScrollWheel(S32 x, S32 y, S32 clicks) //static void LLFloaterModelPreview::onPhysicsParamCommit(LLUICtrl* ctrl, void* data) { - LLCDParam* param = (LLCDParam*) data; - - LLCDResult ret = LLCD_OK; - if (LLConvexDecomposition::getInstance() == NULL) { llinfos << "convex decomposition tool is a stub on this platform. cannot get decomp." << llendl; return; } - if (param->mType == LLCDParam::LLCD_FLOAT) - { - ret = LLConvexDecomposition::getInstance()->setParam(param->mName, (F32) ctrl->getValue().asReal()); - } - else if (param->mType == LLCDParam::LLCD_INTEGER || - param->mType == LLCDParam::LLCD_ENUM) - { - ret = LLConvexDecomposition::getInstance()->setParam(param->mName, ctrl->getValue().asInteger()); - } - else if (param->mType == LLCDParam::LLCD_BOOLEAN) + if (sInstance) { - ret = LLConvexDecomposition::getInstance()->setParam(param->mName, ctrl->getValue().asBoolean()); + LLCDResult ret = LLCD_OK; + LLCDParam* param = (LLCDParam*) data; + sInstance->mDecompParams[param->mName] = ctrl->getValue(); } - if (ret) - { - llerrs << "WTF?" << llendl; - } + } //static @@ -812,6 +806,12 @@ void LLFloaterModelPreview::onPhysicsStageExecute(LLUICtrl* ctrl, void* data) if (sInstance) { + if (sInstance->mCurRequest.notNull()) + { + llinfos << "Decomposition request still pending." << llendl; + return; + } + if (sInstance->mModelPreview) { if (sInstance->mDecompFloater) @@ -827,14 +827,18 @@ void LLFloaterModelPreview::onPhysicsStageExecute(LLUICtrl* ctrl, void* data) if (mdl) { - gMeshRepo.mDecompThread->execute(stage->mName, mdl); + sInstance->mCurRequest = new DecompRequest(stage->mName, mdl); + gMeshRepo.mDecompThread->submitRequest(sInstance->mCurRequest); } } //static void LLFloaterModelPreview::onPhysicsStageCancel(LLUICtrl* ctrl, void*data) { - gMeshRepo.mDecompThread->cancel(); + if (sInstance && sInstance->mCurRequest.notNull()) + { + sInstance->mCurRequest->mContinue = 0; + } } void LLFloaterModelPreview::showDecompFloater() @@ -899,6 +903,8 @@ void LLFloaterModelPreview::showDecompFloater() // protected against stub by stage_count being 0 for stub above LLConvexDecomposition::getInstance()->registerCallback(j, LLPhysicsDecomp::llcdCallback); + llinfos << "Physics decomp stage " << j << " parameters:" << llendl; + for (S32 i = 0; i < param_count; ++i) { if (param[i].mStage != j) @@ -909,8 +915,11 @@ void LLFloaterModelPreview::showDecompFloater() std::string name(param[i].mName ? param[i].mName : ""); std::string description(param[i].mDescription ? param[i].mDescription : ""); + llinfos << name << " - " << description << llendl; + if (param[i].mType == LLCDParam::LLCD_FLOAT) { + mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mFloat); LLSliderCtrl::Params p; p.name(name); p.label(name); @@ -928,6 +937,7 @@ void LLFloaterModelPreview::showDecompFloater() } else if (param[i].mType == LLCDParam::LLCD_INTEGER) { + mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue); LLSliderCtrl::Params p; p.name(name); p.label(name); @@ -944,6 +954,7 @@ void LLFloaterModelPreview::showDecompFloater() } else if (param[i].mType == LLCDParam::LLCD_BOOLEAN) { + mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mBool); LLCheckBoxCtrl::Params p; p.rect(LLRect(left, cur_y, right, cur_y-20)); p.name(name); @@ -958,7 +969,7 @@ void LLFloaterModelPreview::showDecompFloater() else if (param[i].mType == LLCDParam::LLCD_ENUM) { S32 cur_x = left; - + mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue); { //add label LLTextBox::Params p; const LLFontGL* font = (LLFontGL*) p.font(); @@ -2892,9 +2903,20 @@ void LLModelPreview::genLODs(S32 which_lod) } } } - - mResourceCost = calcResourceCost(); } + + mResourceCost = calcResourceCost(); + + /*if (which_lod == -1 && mScene[LLModel::LOD_PHYSICS].empty()) + { //build physics scene + mScene[LLModel::LOD_PHYSICS] = mScene[LLModel::LOD_LOW]; + mModel[LLModel::LOD_PHYSICS] = mModel[LLModel::LOD_LOW]; + + for (U32 i = 1; i < mModel[LLModel::LOD_PHYSICS].size(); ++i) + { + mPhysicsQ.push(mModel[LLModel::LOD_PHYSICS][i]); + } + }*/ } void LLModelPreview::updateStatusMessages() @@ -3665,18 +3687,6 @@ void LLFloaterModelPreview::onDecompose(void* user_data) mp->showDecompFloater(); } -//static -void LLFloaterModelPreview::onModelDecompositionComplete(LLModel* model, std::vector >& physics_mesh) -{ - if (sInstance && sInstance->mModelPreview) - { - sInstance->mModelPreview->mPhysicsMesh[model] = physics_mesh; - - sInstance->mModelPreview->mDirty = true; - } -} - - //static void LLFloaterModelPreview::refresh(LLUICtrl* ctrl, void* user_data) { @@ -3697,3 +3707,66 @@ void LLModelPreview::textureLoadedCallback( BOOL success, LLViewerFetchedTexture preview->refresh(); } +LLFloaterModelPreview::DecompRequest::DecompRequest(const std::string& stage, LLModel* mdl) +{ + mStage = stage; + mContinue = 1; + mModel = mdl; + mParams = sInstance->mDecompParams; + + //copy out positions and indices + if (mdl) + { + U16 index_offset = 0; + + mPositions.clear(); + mIndices.clear(); + + //queue up vertex positions and indices + for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) + { + const LLVolumeFace& face = mdl->getVolumeFace(i); + if (mPositions.size() + face.mNumVertices > 65535) + { + continue; + } + + for (U32 j = 0; j < face.mNumVertices; ++j) + { + mPositions.push_back(LLVector3(face.mPositions[j].getF32ptr())); + } + + for (U32 j = 0; j < face.mNumIndices; ++j) + { + mIndices.push_back(face.mIndices[j]+index_offset); + } + + index_offset += face.mNumVertices; + } + } +} + +S32 LLFloaterModelPreview::DecompRequest::statusCallback(const char* status, S32 p1, S32 p2) +{ + setStatusMessage(llformat("%s: %d/%d", status, p1, p2)); + return mContinue; +} + +void LLFloaterModelPreview::DecompRequest::completed() +{ + mModel->setPhysicsShape(mHull); + + if (sInstance) + { + if (sInstance->mModelPreview) + { + sInstance->mModelPreview->mPhysicsMesh[mModel] = mHullMesh; + sInstance->mModelPreview->mDirty = true; + LLFloaterModelPreview::sInstance->mModelPreview->refresh(); + } + + sInstance->mCurRequest = NULL; + } +} + + -- cgit v1.2.3 From 1f00747cd2accbe1b243e5c23f6e74a061a22bfa Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 5 Oct 2010 16:55:19 -0500 Subject: Post review cleanup. --- indra/newview/llfloatermodelpreview.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 69e641c074..d939d27fa9 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -643,7 +643,7 @@ void LLFloaterModelPreview::draw() else { const std::string idle("Idle."); - mDecompFloater->childSetText("status", std::string("Idle.")); + mDecompFloater->childSetText("status", idle); } } @@ -789,12 +789,9 @@ void LLFloaterModelPreview::onPhysicsParamCommit(LLUICtrl* ctrl, void* data) if (sInstance) { - LLCDResult ret = LLCD_OK; LLCDParam* param = (LLCDParam*) data; sInstance->mDecompParams[param->mName] = ctrl->getValue(); } - - } //static -- cgit v1.2.3 From 24e0d62a5eb3299a877d7a6b37e1881ec3d1ca0c Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 6 Oct 2010 01:17:12 -0500 Subject: Added mandatory single hull simplification to mesh upload. --- indra/newview/llfloatermodelpreview.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 82d3a07345..deb2eff351 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -900,7 +900,8 @@ void LLFloaterModelPreview::showDecompFloater() // protected against stub by stage_count being 0 for stub above LLConvexDecomposition::getInstance()->registerCallback(j, LLPhysicsDecomp::llcdCallback); - llinfos << "Physics decomp stage " << j << " parameters:" << llendl; + llinfos << "Physics decomp stage " << stage[j].mName << " (" << j << ") parameters:" << llendl; + llinfos << "------------------------------------" << llendl; for (S32 i = 0; i < param_count; ++i) { @@ -912,11 +913,15 @@ void LLFloaterModelPreview::showDecompFloater() std::string name(param[i].mName ? param[i].mName : ""); std::string description(param[i].mDescription ? param[i].mDescription : ""); + std::string type = "unknown"; + llinfos << name << " - " << description << llendl; if (param[i].mType == LLCDParam::LLCD_FLOAT) { mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mFloat); + llinfos << "Type: float, Default: " << param[i].mDefault.mFloat << llendl; + LLSliderCtrl::Params p; p.name(name); p.label(name); @@ -935,6 +940,7 @@ void LLFloaterModelPreview::showDecompFloater() else if (param[i].mType == LLCDParam::LLCD_INTEGER) { mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue); + llinfos << "Type: integer, Default: " << param[i].mDefault.mIntOrEnumValue << llendl; LLSliderCtrl::Params p; p.name(name); p.label(name); @@ -952,6 +958,8 @@ void LLFloaterModelPreview::showDecompFloater() else if (param[i].mType == LLCDParam::LLCD_BOOLEAN) { mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mBool); + llinfos << "Type: boolean, Default: " << (param[i].mDefault.mBool ? "True" : "False") << llendl; + LLCheckBoxCtrl::Params p; p.rect(LLRect(left, cur_y, right, cur_y-20)); p.name(name); @@ -967,6 +975,8 @@ void LLFloaterModelPreview::showDecompFloater() { S32 cur_x = left; mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue); + llinfos << "Type: enum, Default: " << param[i].mDefault.mIntOrEnumValue << llendl; + { //add label LLTextBox::Params p; const LLFontGL* font = (LLFontGL*) p.font(); @@ -987,9 +997,13 @@ void LLFloaterModelPreview::showDecompFloater() p.label(name); p.tool_tip(description); + llinfos << "Accepted values: " << llendl; LLComboBox* combo_box = LLUICtrlFactory::create(p); for (S32 k = 0; k < param[i].mDetails.mEnumValues.mNumEnums; ++k) { + llinfos << param[i].mDetails.mEnumValues.mEnumsArray[k].mValue + << " - " << param[i].mDetails.mEnumValues.mEnumsArray[k].mName << llendl; + combo_box->add(param[i].mDetails.mEnumValues.mEnumsArray[k].mName, LLSD::Integer(param[i].mDetails.mEnumValues.mEnumsArray[k].mValue)); } @@ -997,8 +1011,12 @@ void LLFloaterModelPreview::showDecompFloater() combo_box->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); mDecompFloater->addChild(combo_box); cur_y += 30; + } + + llinfos << "----" << llendl; } + llinfos << "-----------------------------" << llendl; } } -- cgit v1.2.3 From 0ff0dd72d6e0c009aebb85dfe5c0bc6c7075578d Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Thu, 7 Oct 2010 23:11:08 -0500 Subject: Prep loves to type static const int --- indra/newview/llfloatermodelpreview.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index deb2eff351..161b8ed9c8 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1417,7 +1417,7 @@ void LLModelLoader::run() if ( pSkeletonRootNode ) { //Once we have the root node - start acccessing it's joint components - static const int jointCnt = mJointMap.size(); + const int jointCnt = mJointMap.size(); std::map :: const_iterator jointIt = mJointMap.begin(); bool missingID = false; //Loop over all the possible joints within the .dae - using the allowed joint list in the ctor. @@ -1594,7 +1594,7 @@ void LLModelLoader::run() //with the skeleton are not stored in the same order as they are in the exported joint buffer. //This remaps the skeletal joints to be in the same order as the joints stored in the model. std::vector :: const_iterator jointIt = model->mJointList.begin(); - static const int jointCnt = model->mJointList.size(); + const int jointCnt = model->mJointList.size(); for ( int i=0; i Date: Fri, 8 Oct 2010 00:11:22 -0500 Subject: Fix for bad labels on physics shape in importer. Fix for crash due to race condition when uploading meshes. --- indra/newview/llfloatermodelpreview.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 161b8ed9c8..fdf781ae0b 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -272,6 +272,7 @@ BOOL LLFloaterModelPreview::postBuild() { if (lod == LLModel::LOD_PHYSICS) { + childSetTextArg(info_name[lod], "[TRIANGLES]", std::string("0")); childSetTextArg(info_name[lod], "[HULLS]", std::string("0")); childSetTextArg(info_name[lod], "[POINTS]", std::string("0")); } @@ -2953,7 +2954,7 @@ void LLModelPreview::updateStatusMessages() S32 total_verts[LLModel::NUM_LODS]; S32 total_submeshes[LLModel::NUM_LODS]; - for (S32 lod = 0; lod <= LLModel::LOD_HIGH; ++lod) + for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) { //initialize total for this lod to 0 total_tris[lod] = total_verts[lod] = total_submeshes[lod] = 0; @@ -2986,6 +2987,8 @@ void LLModelPreview::updateStatusMessages() std::string upload_message; + mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[TRIANGLES]", llformat("%d", total_tris[LLModel::LOD_PHYSICS])); + for (S32 lod = 0; lod <= LLModel::LOD_HIGH; ++lod) { mFMP->childSetTextArg(info_name[lod], "[TRIANGLES]", llformat("%d", total_tris[lod])); -- cgit v1.2.3 From 83f7f37d8a1391761fb951c5aff2e93cfbb1f7ff Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 12 Oct 2010 15:28:09 -0500 Subject: SH-264 Fix for lowest lod defaulting to a huge number of triangles when choosing "Triangle Limit" --- indra/newview/llfloatermodelpreview.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index fdf781ae0b..6365803554 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -2080,14 +2080,14 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloaterModelPreview* fmp mModelLoader = NULL; mDirty = false; - mLODMode[0] = 0; - - for (U32 i = 1; i < LLModel::NUM_LODS; i++) + for (U32 i = 0; i < LLModel::NUM_LODS; i++) { mLODMode[i] = 1; mLimit[i] = 0; } + mLODMode[0] = 0; + mFMP = fmp; glodInit(); -- cgit v1.2.3 From 6cbe04a1fb7ce5704c8a16f05a21940a134d6d4c Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 12 Oct 2010 17:05:33 -0500 Subject: SH-320 Make "scale" spinner actually work and show dimensions of current model. --- indra/newview/llfloatermodelpreview.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 6365803554..1d325448c4 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -2168,6 +2168,10 @@ U32 LLModelPreview::calcResourceCost() mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[HULLS]", llformat("%d",num_hulls)); mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[POINTS]", llformat("%d",num_points)); mFMP->childSetTextArg("streaming cost", "[COST]", llformat("%.3f", streaming_cost)); + F32 scale = mFMP->childGetValue("debug scale").asReal(); + mFMP->childSetTextArg("dimensions", "[X]", llformat("%.3f", mPreviewScale[0]*scale)); + mFMP->childSetTextArg("dimensions", "[Y]", llformat("%.3f", mPreviewScale[1]*scale)); + mFMP->childSetTextArg("dimensions", "[Z]", llformat("%.3f", mPreviewScale[2]*scale)); updateStatusMessages(); @@ -2181,11 +2185,19 @@ void LLModelPreview::rebuildUploadData() //fill uploaddata instance vectors from scene data + F32 scale = mFMP->childGetValue("debug scale").asReal(); + + LLMatrix4 scale_mat; + scale_mat.initScale(LLVector3(scale, scale, scale)); + for (LLModelLoader::scene::iterator iter = mBaseScene.begin(); iter != mBaseScene.end(); ++iter) { //for each transform in scene + LLMatrix4 mat = iter->first; + mat *= scale_mat; + for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) { //for each instance with said transform applied - LLModelInstance& instance = *model_iter; + LLModelInstance instance = *model_iter; LLModel* base_model = instance.mModel; @@ -2210,6 +2222,7 @@ void LLModelPreview::rebuildUploadData() } } + instance.mTransform = mat; mUploadData.push_back(instance); } } -- cgit v1.2.3 From a5619d16f74863168f45b04b37cc6383e1a92263 Mon Sep 17 00:00:00 2001 From: Oz Linden Date: Wed, 13 Oct 2010 07:24:37 -0400 Subject: correct licenses (fix problem with license change merge) --- indra/newview/llfloatermodelpreview.cpp | 35 ++++++++++++++------------------- 1 file changed, 15 insertions(+), 20 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 1d325448c4..a235f9398a 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -2,30 +2,25 @@ * @file llfloatermodelpreview.cpp * @brief LLFloaterModelPreview class implementation * - * $LicenseInfo:firstyear=2004&license=viewergpl$ - * - * Copyright (c) 2004-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * 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://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * 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://secondlife.com/developers/opensource/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * 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. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ -- cgit v1.2.3 From e5943ac8d1d013ac558a30f9288d79fcb2b2b441 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Thu, 14 Oct 2010 15:36:49 -0500 Subject: SH-324 Clamp models to 64m on upload. --- indra/newview/llfloatermodelpreview.cpp | 38 ++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 1d325448c4..a5fe2aa1c6 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -2168,7 +2168,7 @@ U32 LLModelPreview::calcResourceCost() mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[HULLS]", llformat("%d",num_hulls)); mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[POINTS]", llformat("%d",num_points)); mFMP->childSetTextArg("streaming cost", "[COST]", llformat("%.3f", streaming_cost)); - F32 scale = mFMP->childGetValue("debug scale").asReal(); + F32 scale = mFMP->childGetValue("debug scale").asReal()*2.f; mFMP->childSetTextArg("dimensions", "[X]", llformat("%.3f", mPreviewScale[0]*scale)); mFMP->childSetTextArg("dimensions", "[Y]", llformat("%.3f", mPreviewScale[1]*scale)); mFMP->childSetTextArg("dimensions", "[Z]", llformat("%.3f", mPreviewScale[2]*scale)); @@ -2185,16 +2185,39 @@ void LLModelPreview::rebuildUploadData() //fill uploaddata instance vectors from scene data - F32 scale = mFMP->childGetValue("debug scale").asReal(); + LLSpinCtrl* scale_spinner = mFMP->getChild("debug scale"); + + if (!scale_spinner) + { + llerrs << "floater_model_preview.xml MUST contain debug scale spinner." << llendl; + } + + F32 scale = scale_spinner->getValue().asReal(); LLMatrix4 scale_mat; scale_mat.initScale(LLVector3(scale, scale, scale)); + F32 max_scale = 0.f; + for (LLModelLoader::scene::iterator iter = mBaseScene.begin(); iter != mBaseScene.end(); ++iter) { //for each transform in scene LLMatrix4 mat = iter->first; - mat *= scale_mat; + // compute position + LLVector3 position = LLVector3(0, 0, 0) * mat; + + // compute scale + LLVector3 x_transformed = LLVector3(1, 0, 0) * mat - position; + LLVector3 y_transformed = LLVector3(0, 1, 0) * mat - position; + LLVector3 z_transformed = LLVector3(0, 0, 1) * mat - position; + F32 x_length = x_transformed.normalize(); + F32 y_length = y_transformed.normalize(); + F32 z_length = z_transformed.normalize(); + + max_scale = llmax(llmax(llmax(max_scale, x_length), y_length), z_length); + + mat *= scale_mat; + for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) { //for each instance with said transform applied LLModelInstance instance = *model_iter; @@ -2226,6 +2249,15 @@ void LLModelPreview::rebuildUploadData() mUploadData.push_back(instance); } } + + F32 max_import_scale = DEFAULT_MAX_PRIM_SCALE/max_scale; + + scale_spinner->setMaxValue(max_import_scale); + + if (max_import_scale < scale) + { + scale_spinner->setValue(max_import_scale); + } } -- cgit v1.2.3 From 2357233ab6fe095b5fef42ff1e0bd2311eb2efcd Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Fri, 15 Oct 2010 14:04:13 -0500 Subject: SH-338 Fix for crash when setting medium LOD to none. --- indra/newview/llfloatermodelpreview.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 652a97162b..258da7b406 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -354,9 +354,9 @@ void LLFloaterModelPreview::setLODMode(S32 lod, S32 mode) { if (lod != LLModel::LOD_PHYSICS) { - for (S32 i = lod; i > 0; i--) + for (S32 i = lod; i >= 0; i--) { - mModelPreview->clearModel(lod); + mModelPreview->clearModel(i); } } else -- cgit v1.2.3 From 997d66d348b3c6a19ecd2f5b092f68f645712eb1 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Fri, 15 Oct 2010 16:33:22 -0500 Subject: Fix for various crashes on exit and leaks when using convex decomposition. Make rendering of convex hullified prims work in physics shape display. Reviewed by Falcon. --- indra/newview/llfloatermodelpreview.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 258da7b406..d067970806 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -868,16 +868,17 @@ void LLFloaterModelPreview::showDecompFloater() cur_y += 30; - const LLCDStageData* stage; - S32 stage_count = 0; - if (LLConvexDecomposition::getInstance() != NULL) + static const LLCDStageData* stage = NULL; + static S32 stage_count = 0; + + if (!stage && LLConvexDecomposition::getInstance() != NULL) { stage_count = LLConvexDecomposition::getInstance()->getStages(&stage); } - const LLCDParam* param; - S32 param_count = 0; - if (LLConvexDecomposition::getInstance() != NULL) + static const LLCDParam* param = NULL; + static S32 param_count = 0; + if (!param && LLConvexDecomposition::getInstance() != NULL) { param_count = LLConvexDecomposition::getInstance()->getParameters(¶m); } -- cgit v1.2.3 From 256c6e6a252feaa7ae50f81778aab1e0246a526a Mon Sep 17 00:00:00 2001 From: Jonathan Wolk Date: Tue, 19 Oct 2010 11:29:42 -0700 Subject: Moved retry logic for certain mesh header fetches to help with SH-323 'Some mesh objects fail to load data for valid meshes'. Renamed some variables to be more clear. --- indra/newview/llfloatermodelpreview.cpp | 40 ++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 18 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index d067970806..1e87e84eb2 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -2122,24 +2122,28 @@ U32 LLModelPreview::calcResourceCost() { accounted.insert(instance.mModel); - LLModel::physics_shape& physics_shape = instance.mLOD[LLModel::LOD_PHYSICS] ? instance.mLOD[LLModel::LOD_PHYSICS]->mPhysicsShape : instance.mModel->mPhysicsShape; - - LLSD ret = LLModel::writeModel("", - instance.mLOD[4], - instance.mLOD[3], - instance.mLOD[2], - instance.mLOD[1], - instance.mLOD[0], - physics_shape, - mFMP->childGetValue("upload_skin").asBoolean(), - mFMP->childGetValue("upload_joints").asBoolean(), - true); + LLModel::convex_hull_decomposition& decomp = + instance.mLOD[LLModel::LOD_PHYSICS] ? + instance.mLOD[LLModel::LOD_PHYSICS]->mConvexHullDecomp : + instance.mModel->mConvexHullDecomp; + + LLSD ret = LLModel::writeModel( + "", + instance.mLOD[4], + instance.mLOD[3], + instance.mLOD[2], + instance.mLOD[1], + instance.mLOD[0], + decomp, + mFMP->childGetValue("upload_skin").asBoolean(), + mFMP->childGetValue("upload_joints").asBoolean(), + TRUE); cost += gMeshRepo.calcResourceCost(ret); - num_hulls += physics_shape.size(); - for (U32 i = 0; i < physics_shape.size(); ++i) + num_hulls += decomp.size(); + for (U32 i = 0; i < decomp.size(); ++i) { - num_points += physics_shape[i].size(); + num_points += decomp[i].size(); } //calculate streaming cost @@ -2771,7 +2775,7 @@ void LLModelPreview::genLODs(S32 which_lod) if (which_lod == -1) { - mModel[LLModel::LOD_HIGH] = mBaseModel; + mModel[LLModel::LOD_HIGH] = mBaseModel; } return; @@ -3478,7 +3482,7 @@ BOOL LLModelPreview::render() { gGL.pushMatrix(); - LLVector3 offset = model->mHullCenter[i]-model->mPhysicsCenter; + LLVector3 offset = model->mHullCenter[i]-model->mCenterOfHullCenters; offset *= explode; gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]); @@ -3820,7 +3824,7 @@ S32 LLFloaterModelPreview::DecompRequest::statusCallback(const char* status, S32 void LLFloaterModelPreview::DecompRequest::completed() { - mModel->setPhysicsShape(mHull); + mModel->setConvexHullDecomposition(mHull); if (sInstance) { -- cgit v1.2.3 From 8d8860d5b2b15c72655ddd2b3f99ccb809171425 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 19 Oct 2010 14:16:00 -0500 Subject: Make preview render match what will be uploaded (exposes transform changes between LODs) --- indra/newview/llfloatermodelpreview.cpp | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index d067970806..bdccb09d88 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -3398,23 +3398,31 @@ BOOL LLModelPreview::render() if (!avatar_preview) { - for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) + //for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) + for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) { + LLModelInstance& instance = *iter; + gGL.pushMatrix(); - LLMatrix4 mat = iter->first; + LLMatrix4 mat = instance.mTransform; glMultMatrixf((GLfloat*) mat.mMatrix); - for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) + //for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) { - LLModelInstance& instance = *model_iter; - LLModel* model = instance.mModel; + //LLModelInstance& instance = *model_iter; + LLModel* model = instance.mLOD[mPreviewLOD]; - if (instance.mTransform != mat) + if (!model) { - llerrs << "WTF?" << llendl; + continue; } + //if (instance.mTransform != mat) + //{ + // llerrs << "WTF?" << llendl; + //} + if (render_mesh) { for (U32 i = 0; i < mVertexBuffer[mPreviewLOD][model].size(); ++i) -- cgit v1.2.3 From 53d5fd1e9bb59868b793f9bef0529cd62ca70126 Mon Sep 17 00:00:00 2001 From: prep Date: Thu, 28 Oct 2010 13:40:15 -0400 Subject: - Pelvis offsets are now preserved - Fix for CTS-261 --- indra/newview/llfloatermodelpreview.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 73707ad2f1..1c73a6cb31 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1487,6 +1487,14 @@ void LLModelLoader::run() //Most likely an error in the asset. llwarns<<"Tried to apply joint position from .dae, but it did not exist in the avatar rig." << llendl; } + //Reposition the avatars pelvis (avPos+offset) + //if ( !strcmp( (*jointIt).first.c_str(),"mPelvis" ) ) + if ( lookingForJoint == "mPelvis" ) + { + const LLVector3& pos = gAgentAvatarp->getCharacterPosition(); + gAgentAvatarp->setPelvisOffset( true, jointTransform.getTranslation() ); + gAgentAvatarp->setPosition( pos + jointTransform.getTranslation() ); + } } } } -- cgit v1.2.3 From 4733f2c4380991865b4b74f519a3a94a99550661 Mon Sep 17 00:00:00 2001 From: prep Date: Mon, 15 Nov 2010 13:22:04 -0500 Subject: Implemented support for getting at the child translational element if the SID fails to resolved. --- indra/newview/llfloatermodelpreview.cpp | 7734 ++++++++++++++++--------------- 1 file changed, 3876 insertions(+), 3858 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 1c73a6cb31..2e011a55e7 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1,3858 +1,3876 @@ -/** - * @file llfloatermodelpreview.cpp - * @brief LLFloaterModelPreview class implementation - * - * $LicenseInfo:firstyear=2004&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "dae.h" -//#include "dom.h" -#include "dom/domAsset.h" -#include "dom/domBind_material.h" -#include "dom/domCOLLADA.h" -#include "dom/domConstants.h" -#include "dom/domController.h" -#include "dom/domEffect.h" -#include "dom/domGeometry.h" -#include "dom/domInstance_geometry.h" -#include "dom/domInstance_material.h" -#include "dom/domInstance_node.h" -#include "dom/domInstance_effect.h" -#include "dom/domMaterial.h" -#include "dom/domMatrix.h" -#include "dom/domNode.h" -#include "dom/domProfile_COMMON.h" -#include "dom/domRotate.h" -#include "dom/domScale.h" -#include "dom/domTranslate.h" -#include "dom/domVisual_scene.h" - -#include "llfloatermodelpreview.h" - -#include "llfilepicker.h" -#include "llimagebmp.h" -#include "llimagetga.h" -#include "llimagejpeg.h" -#include "llimagepng.h" - -#include "llagent.h" -#include "llbutton.h" -#include "llcombobox.h" -#include "lldatapacker.h" -#include "lldrawable.h" -#include "lldrawpoolavatar.h" -#include "llrender.h" -#include "llface.h" -#include "lleconomy.h" -#include "llfocusmgr.h" -#include "llfloaterperms.h" -#include "llmatrix4a.h" -#include "llmeshrepository.h" -#include "llsdutil_math.h" -#include "lltextbox.h" -#include "lltoolmgr.h" -#include "llui.h" -#include "llvector4a.h" -#include "llviewercamera.h" -#include "llviewerwindow.h" -#include "llvoavatar.h" -#include "llvoavatarself.h" -#include "pipeline.h" -#include "lluictrlfactory.h" -#include "llviewermenufile.h" -#include "llviewerregion.h" -#include "llstring.h" -#include "llbutton.h" -#include "llcheckboxctrl.h" -#include "llsliderctrl.h" -#include "llspinctrl.h" -#include "llvfile.h" -#include "llvfs.h" - - -#include "glod/glod.h" - -//static -S32 LLFloaterModelPreview::sUploadAmount = 10; -LLFloaterModelPreview* LLFloaterModelPreview::sInstance = NULL; - -const S32 PREVIEW_BORDER_WIDTH = 2; -const S32 PREVIEW_RESIZE_HANDLE_SIZE = S32(RESIZE_HANDLE_WIDTH * OO_SQRT2) + PREVIEW_BORDER_WIDTH; -const S32 PREVIEW_HPAD = PREVIEW_RESIZE_HANDLE_SIZE; -const S32 PREF_BUTTON_HEIGHT = 16 + 7 + 16; -const S32 PREVIEW_TEXTURE_HEIGHT = 300; - -void drawBoxOutline(const LLVector3& pos, const LLVector3& size); - -std::string limit_name[] = -{ - "lowest limit", - "low limit", - "medium limit", - "high limit", - "physics limit", - - "I went off the end of the limit_name array. Me so smart." -}; - -std::string info_name[] = -{ - "lowest info", - "low info", - "medium info", - "high info", - "physics info", - - "I went off the end of the info_name array. Me so smart." -}; - -bool validate_face(const LLVolumeFace& face) -{ - for (U32 i = 0; i < face.mNumIndices; ++i) - { - if (face.mIndices[i] >= face.mNumVertices) - { - llwarns << "Face has invalid index." << llendl; - return false; - } - } - - return true; -} - -bool validate_model(const LLModel* mdl) -{ - if (mdl->getNumVolumeFaces() == 0) - { - llwarns << "Model has no faces!" << llendl; - return false; - } - - for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) - { - if (mdl->getVolumeFace(i).mNumVertices == 0) - { - llwarns << "Face has no vertices." << llendl; - return false; - } - - if (mdl->getVolumeFace(i).mNumIndices == 0) - { - llwarns << "Face has no indices." << llendl; - return false; - } - - if (!validate_face(mdl->getVolumeFace(i))) - { - return false; - } - } - - return true; -} - -BOOL stop_gloderror() -{ - GLuint error = glodGetError(); - - if (error != GLOD_NO_ERROR) - { - llwarns << "GLOD error detected, cannot generate LOD: " << std::hex << error << llendl; - return TRUE; - } - - return FALSE; -} - -LLPhysicsDecompFloater::LLPhysicsDecompFloater(LLSD& key) -: LLFloater(key) -{ - -} - -LLPhysicsDecompFloater::~LLPhysicsDecompFloater() -{ - if (LLFloaterModelPreview::sInstance && LLFloaterModelPreview::sInstance->mDecompFloater) - { - LLFloaterModelPreview::sInstance->mDecompFloater = NULL; - } -} - -class LLMeshFilePicker : public LLFilePickerThread -{ -public: - LLFloaterModelPreview* mFMP; - S32 mLOD; - - LLMeshFilePicker(LLFloaterModelPreview* fmp, S32 lod) - : LLFilePickerThread(LLFilePicker::FFLOAD_COLLADA) - { - mFMP = fmp; - mLOD = lod; - } - - virtual void notify(const std::string& filename) - { - mFMP->mModelPreview->loadModel(mFile, mLOD); - } -}; - - -//----------------------------------------------------------------------------- -// LLFloaterModelPreview() -//----------------------------------------------------------------------------- -LLFloaterModelPreview::LLFloaterModelPreview(const LLSD& key) : - LLFloater(key) -{ - sInstance = this; - mLastMouseX = 0; - mLastMouseY = 0; - mGLName = 0; - mLoading = FALSE; - mDecompFloater = NULL; -} - -//----------------------------------------------------------------------------- -// postBuild() -//----------------------------------------------------------------------------- -BOOL LLFloaterModelPreview::postBuild() -{ - if (!LLFloater::postBuild()) - { - return FALSE; - } - - childSetCommitCallback("high detail combo", onHighLODCommit, this); - childSetCommitCallback("medium detail combo", onMediumLODCommit, this); - childSetCommitCallback("low detail combo", onLowLODCommit, this); - childSetCommitCallback("lowest detail combo", onLowestLODCommit, this); - childSetCommitCallback("physics detail combo", onPhysicsLODCommit, this); - - - childSetCommitCallback("high limit", onHighLimitCommit, this); - childSetCommitCallback("medium limit", onMediumLimitCommit, this); - childSetCommitCallback("low limit", onLowLimitCommit, this); - childSetCommitCallback("lowest limit", onLowestLimitCommit, this); - childSetCommitCallback("physics limit", onPhysicsLimitCommit, this); - - childSetCommitCallback("smooth normals", onSmoothNormalsCommit, this); - - childSetCommitCallback("show edges", onShowEdgesCommit, this); - childSetCommitCallback("auto fill", onAutoFillCommit, this); - - childSetTextArg("status", "[STATUS]", getString("status_idle")); - - for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) - { - if (lod == LLModel::LOD_PHYSICS) - { - childSetTextArg(info_name[lod], "[TRIANGLES]", std::string("0")); - childSetTextArg(info_name[lod], "[HULLS]", std::string("0")); - childSetTextArg(info_name[lod], "[POINTS]", std::string("0")); - } - else - { - childSetTextArg(info_name[lod], "[TRIANGLES]", std::string("0")); - childSetTextArg(info_name[lod], "[VERTICES]", std::string("0")); - childSetTextArg(info_name[lod], "[SUBMESHES]", std::string("0")); - std::string msg = getString("required"); - childSetTextArg(info_name[lod], "[MESSAGE]", msg); - } - - childSetVisible(limit_name[lod], FALSE); - } - - //childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d",sUploadAmount)); - childSetAction("ok_btn", onUpload, this); - - childSetAction("consolidate", onConsolidate, this); - childSetAction("scrub materials", onScrubMaterials, this); - - childSetAction("decompose_btn", onDecompose, this); - - childSetCommitCallback("preview_lod_combo", onPreviewLODCommit, this); - - childSetCommitCallback("upload_skin", onUploadSkinCommit, this); - childSetCommitCallback("upload_joints", onUploadJointsCommit, this); - - childSetCommitCallback("debug scale", onDebugScaleCommit, this); - - childDisable("upload_skin"); - childDisable("upload_joints"); - - const U32 width = 512; - const U32 height = 512; - - mPreviewRect.set(getRect().getWidth()-PREVIEW_HPAD-width, - PREVIEW_HPAD+height, - getRect().getWidth()-PREVIEW_HPAD, - PREVIEW_HPAD); - - mModelPreview = new LLModelPreview(512, 512, this); - mModelPreview->setPreviewTarget(16.f); - - return TRUE; -} - -//----------------------------------------------------------------------------- -// LLFloaterModelPreview() -//----------------------------------------------------------------------------- -LLFloaterModelPreview::~LLFloaterModelPreview() -{ - sInstance = NULL; - - if ( mModelPreview->containsRiggedAsset() ) - { - gAgentAvatarp->resetJointPositions(); - } - - delete mModelPreview; - - if (mGLName) - { - LLImageGL::deleteTextures(1, &mGLName ); - } - - if (mDecompFloater) - { - mDecompFloater->closeFloater(); - mDecompFloater = NULL; - } -} - -void LLFloaterModelPreview::loadModel(S32 lod) -{ - mLoading = TRUE; - - (new LLMeshFilePicker(this, lod))->getFile(); -} - -void LLFloaterModelPreview::setLODMode(S32 lod, S32 mode) -{ - if (mode == 0) - { - if (lod != LLModel::LOD_PHYSICS) - { - for (S32 i = lod; i >= 0; i--) - { - mModelPreview->clearModel(i); - } - } - else - { - mModelPreview->clearModel(lod); - } - - mModelPreview->refresh(); - mModelPreview->calcResourceCost(); - } - else if (mode == 1) - { - loadModel(lod); - } - else if (mode != mModelPreview->mLODMode[lod]) - { - mModelPreview->mLODMode[lod] = mode; - mModelPreview->genLODs(lod); - } - - mModelPreview->setPreviewLOD(lod); - - - LLSpinCtrl* lim = getChild(limit_name[lod], TRUE); - - if (mode == 2) //triangle count - { - U32 tri_count = 0; - for (LLModelLoader::model_list::iterator iter = mModelPreview->mBaseModel.begin(); - iter != mModelPreview->mBaseModel.end(); ++iter) - { - tri_count += (*iter)->getNumTriangles(); - } - - lim->setMaxValue(tri_count); - lim->setVisible(TRUE); - } - else - { - lim->setVisible(FALSE); - } -} - -void LLFloaterModelPreview::setLimit(S32 lod, S32 limit) -{ - if (limit != mModelPreview->mLimit[lod]) - { - mModelPreview->mLimit[lod] = limit; - mModelPreview->genLODs(lod); - mModelPreview->setPreviewLOD(lod); - } -} - -//static -void LLFloaterModelPreview::onDebugScaleCommit(LLUICtrl*,void* userdata) -{ - LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; - - if (!fp->mModelPreview) - { - return; - } - - fp->mModelPreview->calcResourceCost(); -} - -//static -void LLFloaterModelPreview::onUploadJointsCommit(LLUICtrl*,void* userdata) -{ - LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; - - if (!fp->mModelPreview) - { - return; - } - - fp->mModelPreview->refresh(); -} - -//static -void LLFloaterModelPreview::onUploadSkinCommit(LLUICtrl*,void* userdata) -{ - LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; - - if (!fp->mModelPreview) - { - return; - } - - fp->mModelPreview->refresh(); - fp->mModelPreview->resetPreviewTarget(); - fp->mModelPreview->clearBuffers(); -} - -//static -void LLFloaterModelPreview::onPreviewLODCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; - - if (!fp->mModelPreview) - { - return; - } - - S32 which_mode = 0; - - LLCtrlSelectionInterface* iface = fp->childGetSelectionInterface("preview_lod_combo"); - if (iface) - { - which_mode = iface->getFirstSelectedIndex(); - } - fp->mModelPreview->setPreviewLOD(which_mode); -} - -//static -void LLFloaterModelPreview::setLODMode(S32 lod, void* userdata) -{ - LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; - - if (!fp->mModelPreview) - { - return; - } - - S32 which_mode = 0; - - std::string combo_name[] = - { - "lowest detail combo", - "low detail combo", - "medium detail combo", - "high detail combo", - "physics detail combo", - - "I went off the end of the combo_name array. Me so smart." - }; - - LLCtrlSelectionInterface* iface = fp->childGetSelectionInterface(combo_name[lod]); - if (iface) - { - which_mode = iface->getFirstSelectedIndex(); - } - - fp->setLODMode(lod, which_mode); -} - -//static -void LLFloaterModelPreview::onHighLODCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview::setLODMode(3, userdata); -} - -//static -void LLFloaterModelPreview::onMediumLODCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview::setLODMode(2, userdata); -} - -//static -void LLFloaterModelPreview::onLowLODCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview::setLODMode(1, userdata); -} - -//static -void LLFloaterModelPreview::onLowestLODCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview::setLODMode(0, userdata); -} - -//static -void LLFloaterModelPreview::onPhysicsLODCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview::setLODMode(4, userdata); -} - -//static -void LLFloaterModelPreview::setLimit(S32 lod, void* userdata) -{ - LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; - - if (!fp->mModelPreview) - { - return; - } - - S32 limit = fp->childGetValue(limit_name[lod]).asInteger(); - - - fp->setLimit(lod, limit); -} - -//static -void LLFloaterModelPreview::onHighLimitCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview::setLimit(3, userdata); -} - -//static -void LLFloaterModelPreview::onMediumLimitCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview::setLimit(2, userdata); -} - -//static -void LLFloaterModelPreview::onLowLimitCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview::setLimit(1, userdata); -} - -//static -void LLFloaterModelPreview::onLowestLimitCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview::setLimit(0, userdata); -} - -//static -void LLFloaterModelPreview::onPhysicsLimitCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview::setLimit(4, userdata); -} - -//static -void LLFloaterModelPreview::onSmoothNormalsCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; - - fp->mModelPreview->smoothNormals(); -} - -//static -void LLFloaterModelPreview::onShowEdgesCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; - - fp->mModelPreview->refresh(); -} - -//static -void LLFloaterModelPreview::onExplodeCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview* fp = LLFloaterModelPreview::sInstance; - - fp->mModelPreview->refresh(); -} - -//static -void LLFloaterModelPreview::onAutoFillCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; - - fp->mModelPreview->genLODs(); -} - - -//----------------------------------------------------------------------------- -// draw() -//----------------------------------------------------------------------------- -void LLFloaterModelPreview::draw() -{ - LLFloater::draw(); - LLRect r = getRect(); - - mModelPreview->update(); - - if (!mLoading) - { - childSetTextArg("status", "[STATUS]", getString("status_idle")); - } - - childSetTextArg("description_label", "[PRIM_COST]", llformat("%d", mModelPreview->mResourceCost)); - childSetTextArg("description_label", "[TEXTURES]", llformat("%d", mModelPreview->mTextureSet.size())); - - if (mDecompFloater) - { - if (mCurRequest.notNull()) - { - mDecompFloater->childSetText("status", mCurRequest->mStatusMessage); - } - else - { - const std::string idle("Idle."); - mDecompFloater->childSetText("status", idle); - } - } - - U32 resource_cost = mModelPreview->mResourceCost*10; - - if (childGetValue("upload_textures").asBoolean()) - { - resource_cost += mModelPreview->mTextureSet.size()*10; - } - - childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d", resource_cost)); - - if (mModelPreview) - { - gGL.color3f(1.f, 1.f, 1.f); - - gGL.getTexUnit(0)->bind(mModelPreview); - - gGL.begin( LLRender::QUADS ); - { - gGL.texCoord2f(0.f, 1.f); - gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mTop); - gGL.texCoord2f(0.f, 0.f); - gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mBottom); - gGL.texCoord2f(1.f, 0.f); - gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mBottom); - gGL.texCoord2f(1.f, 1.f); - gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mTop); - } - gGL.end(); - - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - } -} - -//----------------------------------------------------------------------------- -// handleMouseDown() -//----------------------------------------------------------------------------- -BOOL LLFloaterModelPreview::handleMouseDown(S32 x, S32 y, MASK mask) -{ - if (mPreviewRect.pointInRect(x, y)) - { - bringToFront( x, y ); - gFocusMgr.setMouseCapture(this); - gViewerWindow->hideCursor(); - mLastMouseX = x; - mLastMouseY = y; - return TRUE; - } - - return LLFloater::handleMouseDown(x, y, mask); -} - -//----------------------------------------------------------------------------- -// handleMouseUp() -//----------------------------------------------------------------------------- -BOOL LLFloaterModelPreview::handleMouseUp(S32 x, S32 y, MASK mask) -{ - gFocusMgr.setMouseCapture(FALSE); - gViewerWindow->showCursor(); - return LLFloater::handleMouseUp(x, y, mask); -} - -//----------------------------------------------------------------------------- -// handleHover() -//----------------------------------------------------------------------------- -BOOL LLFloaterModelPreview::handleHover (S32 x, S32 y, MASK mask) -{ - MASK local_mask = mask & ~MASK_ALT; - - if (mModelPreview && hasMouseCapture()) - { - if (local_mask == MASK_PAN) - { - // pan here - mModelPreview->pan((F32)(x - mLastMouseX) * -0.005f, (F32)(y - mLastMouseY) * -0.005f); - } - else if (local_mask == MASK_ORBIT) - { - F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f; - F32 pitch_radians = (F32)(y - mLastMouseY) * 0.02f; - - mModelPreview->rotate(yaw_radians, pitch_radians); - } - else - { - - F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f; - F32 zoom_amt = (F32)(y - mLastMouseY) * 0.02f; - - mModelPreview->rotate(yaw_radians, 0.f); - mModelPreview->zoom(zoom_amt); - } - - - mModelPreview->refresh(); - - LLUI::setMousePositionLocal(this, mLastMouseX, mLastMouseY); - } - - if (!mPreviewRect.pointInRect(x, y) || !mModelPreview) - { - return LLFloater::handleHover(x, y, mask); - } - else if (local_mask == MASK_ORBIT) - { - gViewerWindow->setCursor(UI_CURSOR_TOOLCAMERA); - } - else if (local_mask == MASK_PAN) - { - gViewerWindow->setCursor(UI_CURSOR_TOOLPAN); - } - else - { - gViewerWindow->setCursor(UI_CURSOR_TOOLZOOMIN); - } - - return TRUE; -} - -//----------------------------------------------------------------------------- -// handleScrollWheel() -//----------------------------------------------------------------------------- -BOOL LLFloaterModelPreview::handleScrollWheel(S32 x, S32 y, S32 clicks) -{ - if (mPreviewRect.pointInRect(x, y) && mModelPreview) - { - mModelPreview->zoom((F32)clicks * -0.2f); - mModelPreview->refresh(); - } - - return TRUE; -} - -//static -void LLFloaterModelPreview::onPhysicsParamCommit(LLUICtrl* ctrl, void* data) -{ - if (LLConvexDecomposition::getInstance() == NULL) - { - llinfos << "convex decomposition tool is a stub on this platform. cannot get decomp." << llendl; - return; - } - - if (sInstance) - { - LLCDParam* param = (LLCDParam*) data; - sInstance->mDecompParams[param->mName] = ctrl->getValue(); - } -} - -//static -void LLFloaterModelPreview::onPhysicsStageExecute(LLUICtrl* ctrl, void* data) -{ - LLCDStageData* stage = (LLCDStageData*) data; - - LLModel* mdl = NULL; - - if (sInstance) - { - if (sInstance->mCurRequest.notNull()) - { - llinfos << "Decomposition request still pending." << llendl; - return; - } - - if (sInstance->mModelPreview) - { - if (sInstance->mDecompFloater) - { - S32 idx = sInstance->mDecompFloater->childGetValue("model").asInteger(); - if (idx >= 0 && idx < sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS].size()) - { - mdl = sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS][idx]; - } - } - } - } - - if (mdl) - { - sInstance->mCurRequest = new DecompRequest(stage->mName, mdl); - gMeshRepo.mDecompThread->submitRequest(sInstance->mCurRequest); - } -} - -//static -void LLFloaterModelPreview::onPhysicsStageCancel(LLUICtrl* ctrl, void*data) -{ - if (sInstance && sInstance->mCurRequest.notNull()) - { - sInstance->mCurRequest->mContinue = 0; - } -} - -void LLFloaterModelPreview::showDecompFloater() -{ - if (!mDecompFloater) - { - LLSD key; - mDecompFloater = new LLPhysicsDecompFloater(key); - - S32 left = 20; - S32 right = 320; - - S32 cur_y = 30; - - { - //add status text - LLTextBox::Params p; - p.name("status"); - p.rect(LLRect(left, cur_y, right-80, cur_y-20)); - mDecompFloater->addChild(LLUICtrlFactory::create(p)); - } - - - { //add cancel button - LLButton::Params p; - p.name("Cancel"); - p.label("Cancel"); - p.rect(LLRect(right-80, cur_y, right, cur_y-20)); - LLButton* button = LLUICtrlFactory::create(p); - button->setCommitCallback(onPhysicsStageCancel, NULL); - mDecompFloater->addChild(button); - } - - cur_y += 30; - - - static const LLCDStageData* stage = NULL; - static S32 stage_count = 0; - - if (!stage && LLConvexDecomposition::getInstance() != NULL) - { - stage_count = LLConvexDecomposition::getInstance()->getStages(&stage); - } - - static const LLCDParam* param = NULL; - static S32 param_count = 0; - if (!param && LLConvexDecomposition::getInstance() != NULL) - { - param_count = LLConvexDecomposition::getInstance()->getParameters(¶m); - } - - for (S32 j = stage_count-1; j >= 0; --j) - { - LLButton::Params p; - p.name(stage[j].mName); - p.label(stage[j].mName); - p.rect(LLRect(left, cur_y, right, cur_y-20)); - LLButton* button = LLUICtrlFactory::create(p); - button->setCommitCallback(onPhysicsStageExecute, (void*) &stage[j]); - mDecompFloater->addChild(button); - gMeshRepo.mDecompThread->mStageID[stage[j].mName] = j; - cur_y += 30; - // protected against stub by stage_count being 0 for stub above - LLConvexDecomposition::getInstance()->registerCallback(j, LLPhysicsDecomp::llcdCallback); - - llinfos << "Physics decomp stage " << stage[j].mName << " (" << j << ") parameters:" << llendl; - llinfos << "------------------------------------" << llendl; - - for (S32 i = 0; i < param_count; ++i) - { - if (param[i].mStage != j) - { - continue; - } - - std::string name(param[i].mName ? param[i].mName : ""); - std::string description(param[i].mDescription ? param[i].mDescription : ""); - - std::string type = "unknown"; - - llinfos << name << " - " << description << llendl; - - if (param[i].mType == LLCDParam::LLCD_FLOAT) - { - mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mFloat); - llinfos << "Type: float, Default: " << param[i].mDefault.mFloat << llendl; - - LLSliderCtrl::Params p; - p.name(name); - p.label(name); - p.rect(LLRect(left, cur_y, right, cur_y-20)); - p.min_value(param[i].mDetails.mRange.mLow.mFloat); - p.max_value(param[i].mDetails.mRange.mHigh.mFloat); - p.increment(param[i].mDetails.mRange.mDelta.mFloat); - p.tool_tip(description); - p.decimal_digits(3); - p.initial_value(param[i].mDefault.mFloat); - LLSliderCtrl* slider = LLUICtrlFactory::create(p); - slider->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); - mDecompFloater->addChild(slider); - cur_y += 30; - } - else if (param[i].mType == LLCDParam::LLCD_INTEGER) - { - mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue); - llinfos << "Type: integer, Default: " << param[i].mDefault.mIntOrEnumValue << llendl; - LLSliderCtrl::Params p; - p.name(name); - p.label(name); - p.rect(LLRect(left, cur_y, right, cur_y-20)); - p.min_value(param[i].mDetails.mRange.mLow.mIntOrEnumValue); - p.max_value(param[i].mDetails.mRange.mHigh.mIntOrEnumValue); - p.increment(param[i].mDetails.mRange.mDelta.mIntOrEnumValue); - p.tool_tip(description); - p.initial_value(param[i].mDefault.mIntOrEnumValue); - LLSliderCtrl* slider = LLUICtrlFactory::create(p); - slider->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); - mDecompFloater->addChild(slider); - cur_y += 30; - } - else if (param[i].mType == LLCDParam::LLCD_BOOLEAN) - { - mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mBool); - llinfos << "Type: boolean, Default: " << (param[i].mDefault.mBool ? "True" : "False") << llendl; - - LLCheckBoxCtrl::Params p; - p.rect(LLRect(left, cur_y, right, cur_y-20)); - p.name(name); - p.label(name); - p.initial_value(param[i].mDefault.mBool); - p.tool_tip(description); - LLCheckBoxCtrl* check_box = LLUICtrlFactory::create(p); - check_box->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); - mDecompFloater->addChild(check_box); - cur_y += 30; - } - else if (param[i].mType == LLCDParam::LLCD_ENUM) - { - S32 cur_x = left; - mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue); - llinfos << "Type: enum, Default: " << param[i].mDefault.mIntOrEnumValue << llendl; - - { //add label - LLTextBox::Params p; - const LLFontGL* font = (LLFontGL*) p.font(); - - p.rect(LLRect(left, cur_y, left+font->getWidth(name), cur_y-20)); - p.name(name); - p.label(name); - p.initial_value(name); - LLTextBox* text_box = LLUICtrlFactory::create(p); - mDecompFloater->addChild(text_box); - cur_x += text_box->getRect().getWidth(); - } - - { //add combo_box - LLComboBox::Params p; - p.rect(LLRect(cur_x, cur_y, right-right/4, cur_y-20)); - p.name(name); - p.label(name); - p.tool_tip(description); - - llinfos << "Accepted values: " << llendl; - LLComboBox* combo_box = LLUICtrlFactory::create(p); - for (S32 k = 0; k < param[i].mDetails.mEnumValues.mNumEnums; ++k) - { - llinfos << param[i].mDetails.mEnumValues.mEnumsArray[k].mValue - << " - " << param[i].mDetails.mEnumValues.mEnumsArray[k].mName << llendl; - - combo_box->add(param[i].mDetails.mEnumValues.mEnumsArray[k].mName, - LLSD::Integer(param[i].mDetails.mEnumValues.mEnumsArray[k].mValue)); - } - combo_box->setValue(param[i].mDefault.mIntOrEnumValue); - combo_box->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); - mDecompFloater->addChild(combo_box); - cur_y += 30; - - } - - llinfos << "----" << llendl; - } - llinfos << "-----------------------------" << llendl; - } - } - - cur_y += 30; - //explode slider - { - LLSliderCtrl::Params p; - p.initial_value(0); - p.min_value(0); - p.max_value(1); - p.decimal_digits(2); - p.increment(0.05f); - p.label("Explode"); - p.name("explode"); - p.rect(LLRect(left, cur_y, right, cur_y-20)); - LLSliderCtrl* slider = LLUICtrlFactory::create(p); - - mDecompFloater->addChild(slider); - cur_y += 30; - } - - //mesh render checkbox - { - LLCheckBoxCtrl::Params p; - p.label("Mesh: "); - p.name("render_mesh"); - p.rect(LLRect(left, cur_y, right/4, cur_y-20)); - LLCheckBoxCtrl* check = LLUICtrlFactory::create(p); - check->setValue(true); - mDecompFloater->addChild(check); - } - - //hull render checkbox - { - LLCheckBoxCtrl::Params p; - p.label("Hull: "); - p.name("render_hull"); - p.rect(LLRect(right/4, cur_y, right/2, cur_y-20)); - LLCheckBoxCtrl* check = LLUICtrlFactory::create(p); - check->setValue(true); - mDecompFloater->addChild(check); - } - - { //submesh combo box label - LLTextBox::Params p; - p.label("Model"); - p.name("model label"); - p.rect(LLRect(right/2, cur_y, right-right/3, cur_y-20)); - LLTextBox* text_box = LLUICtrlFactory::create(p); - text_box->setValue("Model"); - mDecompFloater->addChild(text_box); - } - - { - //add submesh combo box - LLComboBox::Params p; - p.rect(LLRect(right-right/2+p.font()->getWidth("Model"), cur_y, right, cur_y-20)); - p.name("model"); - LLComboBox* combo_box = LLUICtrlFactory::create(p); - for (S32 i = 0; i < mModelPreview->mBaseModel.size(); ++i) - { - LLModel* mdl = mModelPreview->mBaseModel[i]; - combo_box->add(mdl->mLabel, i); - } - combo_box->setValue(0); - mDecompFloater->addChild(combo_box); - cur_y += 30; - } - - mDecompFloater->childSetCommitCallback("model", LLFloaterModelPreview::refresh, LLFloaterModelPreview::sInstance); - mDecompFloater->childSetCommitCallback("render_mesh", LLFloaterModelPreview::refresh, LLFloaterModelPreview::sInstance); - mDecompFloater->childSetCommitCallback("render_hull", LLFloaterModelPreview::refresh, LLFloaterModelPreview::sInstance); - - mDecompFloater->setRect(LLRect(10, cur_y+20, right+20, 10)); - } - - mDecompFloater->childSetCommitCallback("explode", LLFloaterModelPreview::onExplodeCommit, this); - - mDecompFloater->openFloater(); -} - -//----------------------------------------------------------------------------- -// onMouseCaptureLost() -//----------------------------------------------------------------------------- -// static -void LLFloaterModelPreview::onMouseCaptureLostModelPreview(LLMouseHandler* handler) -{ - gViewerWindow->showCursor(); -} - -//----------------------------------------------------------------------------- -// LLModelLoader -//----------------------------------------------------------------------------- -LLModelLoader::LLModelLoader(std::string filename, S32 lod, LLModelPreview* preview) -: LLThread("Model Loader"), mFilename(filename), mLod(lod), mPreview(preview), mState(STARTING), mFirstTransform(TRUE) -{ - mJointMap["mPelvis"] = "mPelvis"; - mJointMap["mTorso"] = "mTorso"; - mJointMap["mChest"] = "mChest"; - mJointMap["mNeck"] = "mNeck"; - mJointMap["mHead"] = "mHead"; - mJointMap["mSkull"] = "mSkull"; - mJointMap["mEyeRight"] = "mEyeRight"; - mJointMap["mEyeLeft"] = "mEyeLeft"; - mJointMap["mCollarLeft"] = "mCollarLeft"; - mJointMap["mShoulderLeft"] = "mShoulderLeft"; - mJointMap["mElbowLeft"] = "mElbowLeft"; - mJointMap["mWristLeft"] = "mWristLeft"; - mJointMap["mCollarRight"] = "mCollarRight"; - mJointMap["mShoulderRight"] = "mShoulderRight"; - mJointMap["mElbowRight"] = "mElbowRight"; - mJointMap["mWristRight"] = "mWristRight"; - mJointMap["mHipRight"] = "mHipRight"; - mJointMap["mKneeRight"] = "mKneeRight"; - mJointMap["mAnkleRight"] = "mAnkleRight"; - mJointMap["mFootRight"] = "mFootRight"; - mJointMap["mToeRight"] = "mToeRight"; - mJointMap["mHipLeft"] = "mHipLeft"; - mJointMap["mKneeLeft"] = "mKneeLeft"; - mJointMap["mAnkleLeft"] = "mAnkleLeft"; - mJointMap["mFootLeft"] = "mFootLeft"; - mJointMap["mToeLeft"] = "mToeLeft"; - - mJointMap["avatar_mPelvis"] = "mPelvis"; - mJointMap["avatar_mTorso"] = "mTorso"; - mJointMap["avatar_mChest"] = "mChest"; - mJointMap["avatar_mNeck"] = "mNeck"; - mJointMap["avatar_mHead"] = "mHead"; - mJointMap["avatar_mSkull"] = "mSkull"; - mJointMap["avatar_mEyeRight"] = "mEyeRight"; - mJointMap["avatar_mEyeLeft"] = "mEyeLeft"; - mJointMap["avatar_mCollarLeft"] = "mCollarLeft"; - mJointMap["avatar_mShoulderLeft"] = "mShoulderLeft"; - mJointMap["avatar_mElbowLeft"] = "mElbowLeft"; - mJointMap["avatar_mWristLeft"] = "mWristLeft"; - mJointMap["avatar_mCollarRight"] = "mCollarRight"; - mJointMap["avatar_mShoulderRight"] = "mShoulderRight"; - mJointMap["avatar_mElbowRight"] = "mElbowRight"; - mJointMap["avatar_mWristRight"] = "mWristRight"; - mJointMap["avatar_mHipRight"] = "mHipRight"; - mJointMap["avatar_mKneeRight"] = "mKneeRight"; - mJointMap["avatar_mAnkleRight"] = "mAnkleRight"; - mJointMap["avatar_mFootRight"] = "mFootRight"; - mJointMap["avatar_mToeRight"] = "mToeRight"; - mJointMap["avatar_mHipLeft"] = "mHipLeft"; - mJointMap["avatar_mKneeLeft"] = "mKneeLeft"; - mJointMap["avatar_mAnkleLeft"] = "mAnkleLeft"; - mJointMap["avatar_mFootLeft"] = "mFootLeft"; - mJointMap["avatar_mToeLeft"] = "mToeLeft"; - - - mJointMap["hip"] = "mPelvis"; - mJointMap["abdomen"] = "mTorso"; - mJointMap["chest"] = "mChest"; - mJointMap["neck"] = "mNeck"; - mJointMap["head"] = "mHead"; - mJointMap["figureHair"] = "mSkull"; - mJointMap["lCollar"] = "mCollarLeft"; - mJointMap["lShldr"] = "mShoulderLeft"; - mJointMap["lForeArm"] = "mElbowLeft"; - mJointMap["lHand"] = "mWristLeft"; - mJointMap["rCollar"] = "mCollarRight"; - mJointMap["rShldr"] = "mShoulderRight"; - mJointMap["rForeArm"] = "mElbowRight"; - mJointMap["rHand"] = "mWristRight"; - mJointMap["rThigh"] = "mHipRight"; - mJointMap["rShin"] = "mKneeRight"; - mJointMap["rFoot"] = "mFootRight"; - mJointMap["lThigh"] = "mHipLeft"; - mJointMap["lShin"] = "mKneeLeft"; - mJointMap["lFoot"] = "mFootLeft"; -} - -void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, BOOL& first_transform) -{ - LLVector4a box[] = - { - LLVector4a(-1, 1,-1), - LLVector4a(-1, 1, 1), - LLVector4a(-1,-1,-1), - LLVector4a(-1,-1, 1), - LLVector4a( 1, 1,-1), - LLVector4a( 1, 1, 1), - LLVector4a( 1,-1,-1), - LLVector4a( 1,-1, 1), - }; - - for (S32 j = 0; j < model->getNumVolumeFaces(); ++j) - { - const LLVolumeFace& face = model->getVolumeFace(j); - - LLVector4a center; - center.setAdd(face.mExtents[0], face.mExtents[1]); - center.mul(0.5f); - LLVector4a size; - size.setSub(face.mExtents[1],face.mExtents[0]); - size.mul(0.5f); - - for (U32 i = 0; i < 8; i++) - { - LLVector4a t; - t.setMul(size, box[i]); - t.add(center); - - LLVector4a v; - - mat.affineTransform(t, v); - - if (first_transform) - { - first_transform = FALSE; - min = max = v; - } - else - { - update_min_max(min, max, v); - } - } - } -} - -void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& max, BOOL& first_transform) -{ - LLVector4a mina, maxa; - LLMatrix4a mata; - - mata.loadu(mat); - mina.load3(min.mV); - maxa.load3(max.mV); - - stretch_extents(model, mata, mina, maxa, first_transform); - - min.set(mina.getF32ptr()); - max.set(maxa.getF32ptr()); -} - -void LLModelLoader::run() -{ - DAE dae; - domCOLLADA* dom = dae.open(mFilename); - - if (dom) - { - daeDatabase* db = dae.getDatabase(); - - daeInt count = db->getElementCount(NULL, COLLADA_TYPE_MESH); - - daeDocument* doc = dae.getDoc(mFilename); - if (!doc) - { - llwarns << "can't find internal doc" << llendl; - return; - } - - daeElement* root = doc->getDomRoot(); - if (!root) - { - llwarns << "document has no root" << llendl; - return; - } - - //get unit scale - mTransform.setIdentity(); - - domAsset::domUnit* unit = daeSafeCast(root->getDescendant(daeElement::matchType(domAsset::domUnit::ID()))); - - if (unit) - { - F32 meter = unit->getMeter(); - mTransform.mMatrix[0][0] = meter; - mTransform.mMatrix[1][1] = meter; - mTransform.mMatrix[2][2] = meter; - } - - //get up axis rotation - LLMatrix4 rotation; - - domUpAxisType up = UPAXISTYPE_Y_UP; // default is Y_UP - domAsset::domUp_axis* up_axis = - daeSafeCast(root->getDescendant(daeElement::matchType(domAsset::domUp_axis::ID()))); - - if (up_axis) - { - up = up_axis->getValue(); - } - - if (up == UPAXISTYPE_X_UP) - { - rotation.initRotation(0.0f, 90.0f * DEG_TO_RAD, 0.0f); - } - else if (up == UPAXISTYPE_Y_UP) - { - rotation.initRotation(90.0f * DEG_TO_RAD, 0.0f, 0.0f); - } - - rotation *= mTransform; - mTransform = rotation; - - - for (daeInt idx = 0; idx < count; ++idx) - { //build map of domEntities to LLModel - domMesh* mesh = NULL; - db->getElement((daeElement**) &mesh, idx, NULL, COLLADA_TYPE_MESH); - - if (mesh) - { - LLPointer model = LLModel::loadModelFromDomMesh(mesh); - - if (model.notNull() && validate_model(model)) - { - mModelList.push_back(model); - mModel[mesh] = model; - } - } - } - - count = db->getElementCount(NULL, COLLADA_TYPE_SKIN); - for (daeInt idx = 0; idx < count; ++idx) - { //add skinned meshes as instances - domSkin* skin = NULL; - db->getElement((daeElement**) &skin, idx, NULL, COLLADA_TYPE_SKIN); - - if (skin) - { - domGeometry* geom = daeSafeCast(skin->getSource().getElement()); - - if (geom) - { - domMesh* mesh = geom->getMesh(); - if (mesh) - { - LLModel* model = mModel[mesh]; - if (model) - { - LLVector3 mesh_scale_vector; - LLVector3 mesh_translation_vector; - model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); - - LLMatrix4 normalized_transformation; - normalized_transformation.setTranslation(mesh_translation_vector); - - LLMatrix4 mesh_scale; - mesh_scale.initScale(mesh_scale_vector); - mesh_scale *= normalized_transformation; - normalized_transformation = mesh_scale; - - glh::matrix4f inv_mat((F32*) normalized_transformation.mMatrix); - inv_mat = inv_mat.inverse(); - LLMatrix4 inverse_normalized_transformation(inv_mat.m); - - domSkin::domBind_shape_matrix* bind_mat = skin->getBind_shape_matrix(); - - if (bind_mat) - { //get bind shape matrix - domFloat4x4& dom_value = bind_mat->getValue(); - - for (int i = 0; i < 4; i++) - { - for(int j = 0; j < 4; j++) - { - model->mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j*4]; - } - } - - LLMatrix4 trans = normalized_transformation; - trans *= model->mBindShapeMatrix; - model->mBindShapeMatrix = trans; - - } - - /*{ - LLMatrix4 rotation; - if (up == UPAXISTYPE_X_UP) - { - rotation.initRotation(0.0f, 90.0f * DEG_TO_RAD, 0.0f); - } - else if (up == UPAXISTYPE_Z_UP) - { - rotation.initRotation(90.0f * DEG_TO_RAD, 90.0f * DEG_TO_RAD, 0.0f); - } - - rotation *= model->mBindShapeMatrix; - model->mBindShapeMatrix = rotation; - }*/ - - //The joint transfom map that we'll populate below - std::map jointTransforms; - jointTransforms.clear(); - - //Some collada setup for accessing the skeleton - daeElement* pElement = 0; - dae.getDatabase()->getElement( &pElement, 0, 0, "skeleton" ); - domInstance_controller::domSkeleton* pSkeleton = daeSafeCast( pElement ); - if ( pSkeleton ) - { - //Get the root node of the skeleton - daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement(); - if ( pSkeletonRootNode ) - { - //Once we have the root node - start acccessing it's joint components - const int jointCnt = mJointMap.size(); - std::map :: const_iterator jointIt = mJointMap.begin(); - bool missingID = false; - //Loop over all the possible joints within the .dae - using the allowed joint list in the ctor. - for ( int i=0; i(resolver.getElement()); - if ( pJoint ) - { - //Pull out the translate id and store it in the jointTranslations map - daeSIDResolver jointResolver( pJoint, "./translate" ); - domTranslate* pTranslate = daeSafeCast( jointResolver.getElement() ); - - LLMatrix4 workingTransform; - - //Translation - if ( pTranslate ) - { - domFloat3 jointTrans = pTranslate->getValue(); - LLVector3 singleJointTranslation( jointTrans[0], jointTrans[1], jointTrans[2] ); - workingTransform.setTranslation( singleJointTranslation ); - } - else - { - missingID = true; - llwarns<< "No translation sid!" << llendl; - } - //Store the joint transform w/respect to it's name. - jointTransforms[(*jointIt).second.c_str()] = workingTransform; - - } - else - { - missingID = true; - llwarns<< "Missing joint." << llendl; - } - } - - //If anything failed in regards to extracting the skeleton, joints or translation id, - //mention it - if ( missingID ) - { - llwarns<< "Partial jointmap found in asset - did you mean to just have a partial map?" << llendl; - } - - //Set the joint translations on the avatar - //The joints are reset in the dtor - jointIt = mJointMap.begin(); - for ( int i=0; igetJoint( lookingForJoint ); - if ( pJoint ) - { - pJoint->storeCurrentXform( jointTransform.getTranslation() ); - } - else - { - //Most likely an error in the asset. - llwarns<<"Tried to apply joint position from .dae, but it did not exist in the avatar rig." << llendl; - } - //Reposition the avatars pelvis (avPos+offset) - //if ( !strcmp( (*jointIt).first.c_str(),"mPelvis" ) ) - if ( lookingForJoint == "mPelvis" ) - { - const LLVector3& pos = gAgentAvatarp->getCharacterPosition(); - gAgentAvatarp->setPelvisOffset( true, jointTransform.getTranslation() ); - gAgentAvatarp->setPosition( pos + jointTransform.getTranslation() ); - } - } - } - } - else - { - llwarns<<"No root node in this skeleton" << llendl; - } - } - else - { - llwarns<<"No skeleton in this asset" << llendl; - } - - domSkin::domJoints* joints = skin->getJoints(); - - domInputLocal_Array& joint_input = joints->getInput_array(); - - for (size_t i = 0; i < joint_input.getCount(); ++i) - { - domInputLocal* input = joint_input.get(i); - xsNMTOKEN semantic = input->getSemantic(); - - if (strcmp(semantic, COMMON_PROFILE_INPUT_JOINT) == 0) - { //found joint source, fill model->mJointMap and model->mJointList - daeElement* elem = input->getSource().getElement(); - - domSource* source = daeSafeCast(elem); - if (source) - { - - - domName_array* names_source = source->getName_array(); - - if (names_source) - { - domListOfNames &names = names_source->getValue(); - - for (size_t j = 0; j < names.getCount(); ++j) - { - std::string name(names.get(j)); - if (mJointMap.find(name) != mJointMap.end()) - { - name = mJointMap[name]; - } - model->mJointList.push_back(name); - model->mJointMap[name] = j; - } - } - else - { - domIDREF_array* names_source = source->getIDREF_array(); - if (names_source) - { - xsIDREFS& names = names_source->getValue(); - - for (size_t j = 0; j < names.getCount(); ++j) - { - std::string name(names.get(j).getID()); - if (mJointMap.find(name) != mJointMap.end()) - { - name = mJointMap[name]; - } - model->mJointList.push_back(name); - model->mJointMap[name] = j; - } - } - } - } - } - else if (strcmp(semantic, COMMON_PROFILE_INPUT_INV_BIND_MATRIX) == 0) - { //found inv_bind_matrix array, fill model->mInvBindMatrix - domSource* source = daeSafeCast(input->getSource().getElement()); - if (source) - { - domFloat_array* t = source->getFloat_array(); - if (t) - { - domListOfFloats& transform = t->getValue(); - S32 count = transform.getCount()/16; - - for (S32 k = 0; k < count; ++k) - { - LLMatrix4 mat; - - for (int i = 0; i < 4; i++) - { - for(int j = 0; j < 4; j++) - { - mat.mMatrix[i][j] = transform[k*16 + i + j*4]; - } - } - - model->mInvBindMatrix.push_back(mat); - } - } - } - } - } - - //We need to construct the alternate bind matrix (which contains the new joint positions) - //in the same order as they were stored in the joint buffer. The joints associated - //with the skeleton are not stored in the same order as they are in the exported joint buffer. - //This remaps the skeletal joints to be in the same order as the joints stored in the model. - std::vector :: const_iterator jointIt = model->mJointList.begin(); - const int jointCnt = model->mJointList.size(); - for ( int i=0; imInvBindMatrix[i]; - newInverse.setTranslation( jointTransforms[lookingForJoint].getTranslation() ); - model->mAlternateBindMatrix.push_back( newInverse ); - } - else - { - llwarns<<"Possibly misnamed/missing joint [" <getVertices(); - if (verts) - { - domInputLocal_Array& inputs = verts->getInput_array(); - for (size_t i = 0; i < inputs.getCount() && model->mPosition.empty(); ++i) - { - if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_POSITION) == 0) - { - domSource* pos_source = daeSafeCast(inputs[i]->getSource().getElement()); - if (pos_source) - { - domFloat_array* pos_array = pos_source->getFloat_array(); - if (pos_array) - { - domListOfFloats& pos = pos_array->getValue(); - - for (size_t j = 0; j < pos.getCount(); j += 3) - { - if (pos.getCount() <= j+2) - { - llerrs << "WTF?" << llendl; - } - - LLVector3 v(pos[j], pos[j+1], pos[j+2]); - - //transform from COLLADA space to volume space - v = v * inverse_normalized_transformation; - - model->mPosition.push_back(v); - } - } - } - } - } - } - - //grab skin weights array - domSkin::domVertex_weights* weights = skin->getVertex_weights(); - if (weights) - { - domInputLocalOffset_Array& inputs = weights->getInput_array(); - domFloat_array* vertex_weights = NULL; - for (size_t i = 0; i < inputs.getCount(); ++i) - { - if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_WEIGHT) == 0) - { - domSource* weight_source = daeSafeCast(inputs[i]->getSource().getElement()); - if (weight_source) - { - vertex_weights = weight_source->getFloat_array(); - } - } - } - - if (vertex_weights) - { - domListOfFloats& w = vertex_weights->getValue(); - domListOfUInts& vcount = weights->getVcount()->getValue(); - domListOfInts& v = weights->getV()->getValue(); - - U32 c_idx = 0; - for (size_t vc_idx = 0; vc_idx < vcount.getCount(); ++vc_idx) - { //for each vertex - daeUInt count = vcount[vc_idx]; - - //create list of weights that influence this vertex - LLModel::weight_list weight_list; - - for (daeUInt i = 0; i < count; ++i) - { //for each weight - daeInt joint_idx = v[c_idx++]; - daeInt weight_idx = v[c_idx++]; - - if (joint_idx == -1) - { - //ignore bindings to bind_shape_matrix - continue; - } - - F32 weight_value = w[weight_idx]; - - weight_list.push_back(LLModel::JointWeight(joint_idx, weight_value)); - } - - //sort by joint weight - std::sort(weight_list.begin(), weight_list.end(), LLModel::CompareWeightGreater()); - - std::vector wght; - - F32 total = 0.f; - - for (U32 i = 0; i < llmin((U32) 4, (U32) weight_list.size()); ++i) - { //take up to 4 most significant weights - if (weight_list[i].mWeight > 0.f) - { - wght.push_back( weight_list[i] ); - total += weight_list[i].mWeight; - } - } - - F32 scale = 1.f/total; - if (scale != 1.f) - { //normalize weights - for (U32 i = 0; i < wght.size(); ++i) - { - wght[i].mWeight *= scale; - } - } - - model->mSkinWeights[model->mPosition[vc_idx]] = wght; - } - - //add instance to scene for this model - - LLMatrix4 transform; - std::vector materials; - materials.resize(model->getNumVolumeFaces()); - mScene[transform].push_back(LLModelInstance(model, transform, materials)); - stretch_extents(model, transform, mExtents[0], mExtents[1], mFirstTransform); - } - } - } - } - } - } - } - - daeElement* scene = root->getDescendant("visual_scene"); - if (!scene) - { - llwarns << "document has no visual_scene" << llendl; - return; - } - - processElement(scene); - - mPreview->loadModelCallback(mLod); - } -} - -void LLModelLoader::processElement(daeElement* element) -{ - LLMatrix4 saved_transform = mTransform; - - domTranslate* translate = daeSafeCast(element); - if (translate) - { - domFloat3 dom_value = translate->getValue(); - - LLMatrix4 translation; - translation.setTranslation(LLVector3(dom_value[0], dom_value[1], dom_value[2])); - - translation *= mTransform; - mTransform = translation; - } - - domRotate* rotate = daeSafeCast(element); - if (rotate) - { - domFloat4 dom_value = rotate->getValue(); - - LLMatrix4 rotation; - rotation.initRotTrans(dom_value[3] * DEG_TO_RAD, LLVector3(dom_value[0], dom_value[1], dom_value[2]), LLVector3(0, 0, 0)); - - rotation *= mTransform; - mTransform = rotation; - } - - domScale* scale = daeSafeCast(element); - if (scale) - { - domFloat3 dom_value = scale->getValue(); - - LLMatrix4 scaling; - scaling.initScale(LLVector3(dom_value[0], dom_value[1], dom_value[2])); - - scaling *= mTransform; - mTransform = scaling; - } - - domMatrix* matrix = daeSafeCast(element); - if (matrix) - { - domFloat4x4 dom_value = matrix->getValue(); - - LLMatrix4 matrix_transform; - - for (int i = 0; i < 4; i++) - { - for(int j = 0; j < 4; j++) - { - matrix_transform.mMatrix[i][j] = dom_value[i + j*4]; - } - } - - matrix_transform *= mTransform; - mTransform = matrix_transform; - } - - domInstance_geometry* instance_geo = daeSafeCast(element); - if (instance_geo) - { - domGeometry* geo = daeSafeCast(instance_geo->getUrl().getElement()); - if (geo) - { - domMesh* mesh = daeSafeCast(geo->getDescendant(daeElement::matchType(domMesh::ID()))); - if (mesh) - { - LLModel* model = mModel[mesh]; - if (model) - { - LLMatrix4 transformation = mTransform; - - std::vector materials = getMaterials(model, instance_geo); - - // adjust the transformation to compensate for mesh normalization - LLVector3 mesh_scale_vector; - LLVector3 mesh_translation_vector; - model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); - - LLMatrix4 mesh_translation; - mesh_translation.setTranslation(mesh_translation_vector); - mesh_translation *= transformation; - transformation = mesh_translation; - - LLMatrix4 mesh_scale; - mesh_scale.initScale(mesh_scale_vector); - mesh_scale *= transformation; - transformation = mesh_scale; - - mScene[transformation].push_back(LLModelInstance(model, transformation, materials)); - - stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); - } - } - } - } - - domInstance_node* instance_node = daeSafeCast(element); - if (instance_node) - { - daeElement* instance = instance_node->getUrl().getElement(); - if (instance) - { - processElement(instance); - } - } - - //process children - daeTArray< daeSmartRef > children = element->getChildren(); - for (S32 i = 0; i < children.getCount(); i++) - { - processElement(children[i]); - } - - domNode* node = daeSafeCast(element); - if (node) - { //this element was a node, restore transform before processiing siblings - mTransform = saved_transform; - } -} - -std::vector LLModelLoader::getMaterials(LLModel* model, domInstance_geometry* instance_geo) -{ - std::vector materials; - for (int i = 0; i < model->mMaterialList.size(); i++) - { - LLImportMaterial import_material; - - domInstance_material* instance_mat = NULL; - - domBind_material::domTechnique_common* technique = - daeSafeCast(instance_geo->getDescendant(daeElement::matchType(domBind_material::domTechnique_common::ID()))); - - if (technique) - { - daeTArray< daeSmartRef > inst_materials = technique->getChildrenByType(); - for (int j = 0; j < inst_materials.getCount(); j++) - { - std::string symbol(inst_materials[j]->getSymbol()); - - if (symbol == model->mMaterialList[i]) // found the binding - { - instance_mat = inst_materials[j]; - } - } - } - - if (instance_mat) - { - domMaterial* material = daeSafeCast(instance_mat->getTarget().getElement()); - if (material) - { - domInstance_effect* instance_effect = - daeSafeCast(material->getDescendant(daeElement::matchType(domInstance_effect::ID()))); - if (instance_effect) - { - domEffect* effect = daeSafeCast(instance_effect->getUrl().getElement()); - if (effect) - { - domProfile_COMMON* profile = - daeSafeCast(effect->getDescendant(daeElement::matchType(domProfile_COMMON::ID()))); - if (profile) - { - import_material = profileToMaterial(profile); - } - } - } - } - } - - materials.push_back(import_material); - } - - return materials; -} - -LLImportMaterial LLModelLoader::profileToMaterial(domProfile_COMMON* material) -{ - LLImportMaterial mat; - mat.mFullbright = FALSE; - - daeElement* diffuse = material->getDescendant("diffuse"); - if (diffuse) - { - domCommon_color_or_texture_type_complexType::domTexture* texture = - daeSafeCast(diffuse->getDescendant("texture")); - if (texture) - { - domCommon_newparam_type_Array newparams = material->getNewparam_array(); - for (S32 i = 0; i < newparams.getCount(); i++) - { - domFx_surface_common* surface = newparams[i]->getSurface(); - if (surface) - { - domFx_surface_init_common* init = surface->getFx_surface_init_common(); - if (init) - { - domFx_surface_init_from_common_Array init_from = init->getInit_from_array(); - - if (init_from.getCount() > i) - { - domImage* image = daeSafeCast(init_from[i]->getValue().getElement()); - if (image) - { - // we only support init_from now - embedded data will come later - domImage::domInit_from* init = image->getInit_from(); - if (init) - { - std::string filename = cdom::uriToNativePath(init->getValue().str()); - - mat.mDiffuseMap = LLViewerTextureManager::getFetchedTextureFromUrl("file://" + filename, TRUE, LLViewerTexture::BOOST_PREVIEW); - mat.mDiffuseMap->setLoadedCallback(LLModelPreview::textureLoadedCallback, 0, TRUE, FALSE, this->mPreview, NULL, FALSE); - - mat.mDiffuseMap->forceToSaveRawImage(); - mat.mDiffuseMapFilename = filename; - mat.mDiffuseMapLabel = getElementLabel(material); - } - } - } - } - } - } - } - - domCommon_color_or_texture_type_complexType::domColor* color = - daeSafeCast(diffuse->getDescendant("color")); - if (color) - { - domFx_color_common domfx_color = color->getValue(); - LLColor4 value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]); - mat.mDiffuseColor = value; - } - } - - daeElement* emission = material->getDescendant("emission"); - if (emission) - { - LLColor4 emission_color = getDaeColor(emission); - if (((emission_color[0] + emission_color[1] + emission_color[2]) / 3.0) > 0.25) - { - mat.mFullbright = TRUE; - } - } - - return mat; -} - -// try to get a decent label for this element -std::string LLModelLoader::getElementLabel(daeElement *element) -{ - // if we have a name attribute, use it - std::string name = element->getAttribute("name"); - if (name.length()) - { - return name; - } - - // if we have an ID attribute, use it - if (element->getID()) - { - return std::string(element->getID()); - } - - // if we have a parent, use it - daeElement* parent = element->getParent(); - if (parent) - { - // if parent has a name, use it - std::string name = parent->getAttribute("name"); - if (name.length()) - { - return name; - } - - // if parent has an ID, use it - if (parent->getID()) - { - return std::string(parent->getID()); - } - } - - // try to use our type - daeString element_name = element->getElementName(); - if (element_name) - { - return std::string(element_name); - } - - // if all else fails, use "object" - return std::string("object"); -} - -LLColor4 LLModelLoader::getDaeColor(daeElement* element) -{ - LLColor4 value; - domCommon_color_or_texture_type_complexType::domColor* color = - daeSafeCast(element->getDescendant("color")); - if (color) - { - domFx_color_common domfx_color = color->getValue(); - value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]); - } - - return value; -} - -//----------------------------------------------------------------------------- -// LLModelPreview -//----------------------------------------------------------------------------- - -LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloaterModelPreview* fmp) -: LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE), LLMutex(NULL) -{ - mNeedsUpdate = TRUE; - mCameraDistance = 0.f; - mCameraYaw = 0.f; - mCameraPitch = 0.f; - mCameraZoom = 1.f; - mTextureName = 0; - mPreviewLOD = 3; - mModelLoader = NULL; - mDirty = false; - - for (U32 i = 0; i < LLModel::NUM_LODS; i++) - { - mLODMode[i] = 1; - mLimit[i] = 0; - } - - mLODMode[0] = 0; - - mFMP = fmp; - - glodInit(); -} - -LLModelPreview::~LLModelPreview() -{ - if (mModelLoader) - { - delete mModelLoader; - mModelLoader = NULL; - } - - //*HACK : *TODO : turn this back on when we understand why this crashes - //glodShutdown(); -} - -U32 LLModelPreview::calcResourceCost() -{ - rebuildUploadData(); - - U32 cost = 0; - std::set accounted; - U32 num_points = 0; - U32 num_hulls = 0; - - F32 debug_scale = mFMP->childGetValue("debug scale").asReal(); - - F32 streaming_cost = 0.f; - - for (U32 i = 0; i < mUploadData.size(); ++i) - { - LLModelInstance& instance = mUploadData[i]; - - if (accounted.find(instance.mModel) == accounted.end()) - { - accounted.insert(instance.mModel); - - LLModel::convex_hull_decomposition& decomp = - instance.mLOD[LLModel::LOD_PHYSICS] ? - instance.mLOD[LLModel::LOD_PHYSICS]->mConvexHullDecomp : - instance.mModel->mConvexHullDecomp; - - LLSD ret = LLModel::writeModel( - "", - instance.mLOD[4], - instance.mLOD[3], - instance.mLOD[2], - instance.mLOD[1], - instance.mLOD[0], - decomp, - mFMP->childGetValue("upload_skin").asBoolean(), - mFMP->childGetValue("upload_joints").asBoolean(), - TRUE); - cost += gMeshRepo.calcResourceCost(ret); - - num_hulls += decomp.size(); - for (U32 i = 0; i < decomp.size(); ++i) - { - num_points += decomp[i].size(); - } - - //calculate streaming cost - LLMatrix4 transformation = instance.mTransform; - - LLVector3 position = LLVector3(0, 0, 0) * transformation; - - LLVector3 x_transformed = LLVector3(1, 0, 0) * transformation - position; - LLVector3 y_transformed = LLVector3(0, 1, 0) * transformation - position; - LLVector3 z_transformed = LLVector3(0, 0, 1) * transformation - position; - F32 x_length = x_transformed.normalize(); - F32 y_length = y_transformed.normalize(); - F32 z_length = z_transformed.normalize(); - LLVector3 scale = LLVector3(x_length, y_length, z_length); - - F32 radius = scale.length()*debug_scale; - - streaming_cost += LLMeshRepository::getStreamingCost(ret, radius); - } - } - - mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[HULLS]", llformat("%d",num_hulls)); - mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[POINTS]", llformat("%d",num_points)); - mFMP->childSetTextArg("streaming cost", "[COST]", llformat("%.3f", streaming_cost)); - F32 scale = mFMP->childGetValue("debug scale").asReal()*2.f; - mFMP->childSetTextArg("dimensions", "[X]", llformat("%.3f", mPreviewScale[0]*scale)); - mFMP->childSetTextArg("dimensions", "[Y]", llformat("%.3f", mPreviewScale[1]*scale)); - mFMP->childSetTextArg("dimensions", "[Z]", llformat("%.3f", mPreviewScale[2]*scale)); - - updateStatusMessages(); - - return cost; -} - -void LLModelPreview::rebuildUploadData() -{ - mUploadData.clear(); - mTextureSet.clear(); - - //fill uploaddata instance vectors from scene data - - LLSpinCtrl* scale_spinner = mFMP->getChild("debug scale"); - - if (!scale_spinner) - { - llerrs << "floater_model_preview.xml MUST contain debug scale spinner." << llendl; - } - - F32 scale = scale_spinner->getValue().asReal(); - - LLMatrix4 scale_mat; - scale_mat.initScale(LLVector3(scale, scale, scale)); - - F32 max_scale = 0.f; - - for (LLModelLoader::scene::iterator iter = mBaseScene.begin(); iter != mBaseScene.end(); ++iter) - { //for each transform in scene - LLMatrix4 mat = iter->first; - - // compute position - LLVector3 position = LLVector3(0, 0, 0) * mat; - - // compute scale - LLVector3 x_transformed = LLVector3(1, 0, 0) * mat - position; - LLVector3 y_transformed = LLVector3(0, 1, 0) * mat - position; - LLVector3 z_transformed = LLVector3(0, 0, 1) * mat - position; - F32 x_length = x_transformed.normalize(); - F32 y_length = y_transformed.normalize(); - F32 z_length = z_transformed.normalize(); - - max_scale = llmax(llmax(llmax(max_scale, x_length), y_length), z_length); - - mat *= scale_mat; - - for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) - { //for each instance with said transform applied - LLModelInstance instance = *model_iter; - - LLModel* base_model = instance.mModel; - - S32 idx = 0; - for (idx = 0; idx < mBaseModel.size(); ++idx) - { //find reference instance for this model - if (mBaseModel[idx] == base_model) - { - break; - } - } - - for (U32 i = 0; i < LLModel::NUM_LODS; i++) - { //fill LOD slots based on reference model index - if (!mModel[i].empty()) - { - instance.mLOD[i] = mModel[i][idx]; - } - else - { - instance.mLOD[i] = NULL; - } - } - - instance.mTransform = mat; - mUploadData.push_back(instance); - } - } - - F32 max_import_scale = DEFAULT_MAX_PRIM_SCALE/max_scale; - - scale_spinner->setMaxValue(max_import_scale); - - if (max_import_scale < scale) - { - scale_spinner->setValue(max_import_scale); - } -} - - -void LLModelPreview::clearModel(S32 lod) -{ - if (lod < 0 || lod > LLModel::LOD_PHYSICS) - { - return; - } - - mVertexBuffer[lod].clear(); - mModel[lod].clear(); - mScene[lod].clear(); -} - -void LLModelPreview::loadModel(std::string filename, S32 lod) -{ - LLMutexLock lock(this); - - if (mModelLoader) - { - delete mModelLoader; - mModelLoader = NULL; - } - - if (filename.empty()) - { - if (mBaseModel.empty()) - { - // this is the initial file picking. Close the whole floater - // if we don't have a base model to show for high LOD. - mFMP->closeFloater(false); - } - - mFMP->mLoading = false; - return; - } - - if (lod == 3 && !mGroup.empty()) - { - for (std::map, U32>::iterator iter = mGroup.begin(); iter != mGroup.end(); ++iter) - { - glodDeleteGroup(iter->second); - stop_gloderror(); - } - - for (std::map, U32>::iterator iter = mObject.begin(); iter != mObject.end(); ++iter) - { - glodDeleteObject(iter->second); - stop_gloderror(); - } - - mGroup.clear(); - mObject.clear(); - } - - mModelLoader = new LLModelLoader(filename, lod, this); - - mModelLoader->start(); - - mFMP->childSetTextArg("status", "[STATUS]", mFMP->getString("status_reading_file")); - - if (mFMP->childGetValue("description_form").asString().empty()) - { - std::string name = gDirUtilp->getBaseFileName(filename, true); - mFMP->childSetValue("description_form", name); - } - - mFMP->openFloater(); -} - -void LLModelPreview::clearIncompatible(S32 lod) -{ - for (U32 i = 0; i <= LLModel::LOD_HIGH; i++) - { //clear out any entries that aren't compatible with this model - if (i != lod) - { - if (mModel[i].size() != mModel[lod].size()) - { - mModel[i].clear(); - mScene[i].clear(); - mVertexBuffer[i].clear(); - - if (i == LLModel::LOD_HIGH) - { - mBaseModel = mModel[lod]; - mBaseScene = mScene[lod]; - mVertexBuffer[5].clear(); - } - } - } - } -} - -void LLModelPreview::loadModelCallback(S32 lod) -{ //NOT the main thread - LLMutexLock lock(this); - if (!mModelLoader) - { - return; - } - - mModel[lod] = mModelLoader->mModelList; - mScene[lod] = mModelLoader->mScene; - mVertexBuffer[lod].clear(); - - if (lod == LLModel::LOD_PHYSICS) - { - mPhysicsMesh.clear(); - } - - setPreviewLOD(lod); - - - if (lod == LLModel::LOD_HIGH) - { //save a copy of the highest LOD for automatic LOD manipulation - mBaseModel = mModel[lod]; - mBaseScene = mScene[lod]; - mVertexBuffer[5].clear(); - //mModel[lod] = NULL; - } - - clearIncompatible(lod); - - mDirty = true; - - resetPreviewTarget(); - - mFMP->mLoading = FALSE; - refresh(); -} - -void LLModelPreview::resetPreviewTarget() -{ - mPreviewTarget = (mModelLoader->mExtents[0] + mModelLoader->mExtents[1]) * 0.5f; - mPreviewScale = (mModelLoader->mExtents[1] - mModelLoader->mExtents[0]) * 0.5f; - setPreviewTarget(mPreviewScale.magVec()*2.f); -} - -void LLModelPreview::smoothNormals() -{ - S32 which_lod = mPreviewLOD; - - - if (which_lod > 4 || which_lod < 0 || - mModel[which_lod].empty()) - { - return; - } - - F32 angle_cutoff = mFMP->childGetValue("edge threshold").asReal(); - - angle_cutoff *= DEG_TO_RAD; - - if (which_lod == 3 && !mBaseModel.empty()) - { - for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) - { - (*iter)->smoothNormals(angle_cutoff); - } - - mVertexBuffer[5].clear(); - } - - for (LLModelLoader::model_list::iterator iter = mModel[which_lod].begin(); iter != mModel[which_lod].end(); ++iter) - { - (*iter)->smoothNormals(angle_cutoff); - } - - mVertexBuffer[which_lod].clear(); - refresh(); - -} - -void LLModelPreview::consolidate() -{ - std::map > composite; - - LLMatrix4 identity; - - //bake out each node in current scene to composite - for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) - { //for each transform in current scene - LLMatrix4 mat = iter->first; - glh::matrix4f inv_trans = glh::matrix4f((F32*) mat.mMatrix).inverse().transpose(); - LLMatrix4 norm_mat(inv_trans.m); - - for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) - { //for each instance with that transform - LLModelInstance& source_instance = *model_iter; - LLModel* source = source_instance.mModel; - - if (!validate_model(source)) - { - llerrs << "Invalid model found!" << llendl; - } - - for (S32 i = 0; i < source->getNumVolumeFaces(); ++i) - { //for each face in instance - const LLVolumeFace& src_face = source->getVolumeFace(i); - LLImportMaterial& source_material = source_instance.mMaterial[i]; - - //get model in composite that is composite for this material - LLModel* model = NULL; - - if (composite.find(source_material) != composite.end()) - { - model = composite[source_material].rbegin()->mModel; - if (model->getVolumeFace(0).mNumVertices + src_face.mNumVertices > 65535) - { - model = NULL; - } - } - - if (model == NULL) - { //no model found, make new model - std::vector materials; - materials.push_back(source_material); - LLVolumeParams volume_params; - volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); - model = new LLModel(volume_params, 0.f); - model->mLabel = source->mLabel; - model->setNumVolumeFaces(0); - composite[source_material].push_back(LLModelInstance(model, identity, materials)); - } - - model->appendFace(src_face, source->mMaterialList[i], mat, norm_mat); - } - } - } - - - //condense composite into as few LLModel instances as possible - LLModelLoader::model_list new_model; - std::vector instance_list; - - LLVolumeParams volume_params; - volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); - - std::vector empty_material; - LLModelInstance cur_instance(new LLModel(volume_params, 0.f), identity, empty_material); - cur_instance.mModel->setNumVolumeFaces(0); - - BOOL first_transform = TRUE; - - LLModelLoader::scene new_scene; - LLVector3 min,max; - - for (std::map >::iterator iter = composite.begin(); - iter != composite.end(); - ++iter) - { - std::map >::iterator next_iter = iter; ++next_iter; - - for (std::vector::iterator instance_iter = iter->second.begin(); - instance_iter != iter->second.end(); - ++instance_iter) - { - LLModel* source = instance_iter->mModel; - - if (instance_iter->mMaterial.size() != 1) - { - llerrs << "WTF?" << llendl; - } - - if (source->getNumVolumeFaces() != 1) - { - llerrs << "WTF?" << llendl; - } - - if (source->mMaterialList.size() != 1) - { - llerrs << "WTF?" << llendl; - } - - cur_instance.mModel->addFace(source->getVolumeFace(0)); - cur_instance.mMaterial.push_back(instance_iter->mMaterial[0]); - cur_instance.mModel->mMaterialList.push_back(source->mMaterialList[0]); - - BOOL last_model = FALSE; - - std::vector::iterator next_instance = instance_iter; ++next_instance; - - if (next_iter == composite.end() && - next_instance == iter->second.end()) - { - last_model = TRUE; - } - - if (last_model || cur_instance.mModel->getNumVolumeFaces() >= MAX_MODEL_FACES) - { - cur_instance.mModel->mLabel = source->mLabel; - - cur_instance.mModel->optimizeVolumeFaces(); - cur_instance.mModel->normalizeVolumeFaces(); - - if (!validate_model(cur_instance.mModel)) - { - llerrs << "Invalid model detected." << llendl; - } - - new_model.push_back(cur_instance.mModel); - - LLMatrix4 transformation = LLMatrix4(); - - // adjust the transformation to compensate for mesh normalization - LLVector3 mesh_scale_vector; - LLVector3 mesh_translation_vector; - cur_instance.mModel->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); - - LLMatrix4 mesh_translation; - mesh_translation.setTranslation(mesh_translation_vector); - mesh_translation *= transformation; - transformation = mesh_translation; - - LLMatrix4 mesh_scale; - mesh_scale.initScale(mesh_scale_vector); - mesh_scale *= transformation; - transformation = mesh_scale; - - cur_instance.mTransform = transformation; - - new_scene[transformation].push_back(cur_instance); - stretch_extents(cur_instance.mModel, transformation, min, max, first_transform); - - if (!last_model) - { - cur_instance = LLModelInstance(new LLModel(volume_params, 0.f), identity, empty_material); - cur_instance.mModel->setNumVolumeFaces(0); - } - } - } - } - - mScene[mPreviewLOD] = new_scene; - mModel[mPreviewLOD] = new_model; - mVertexBuffer[mPreviewLOD].clear(); - - if (mPreviewLOD == LLModel::LOD_HIGH) - { - mBaseScene = new_scene; - mBaseModel = new_model; - mVertexBuffer[5].clear(); - } - - mPreviewTarget = (min+max)*0.5f; - mPreviewScale = (max-min)*0.5f; - setPreviewTarget(mPreviewScale.magVec()*2.f); - - clearIncompatible(mPreviewLOD); - - mResourceCost = calcResourceCost(); - refresh(); -} - -void LLModelPreview::scrubMaterials() -{ - for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) - { //for each transform in current scene - for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) - { //for each instance with that transform - LLModelInstance& source_instance = *model_iter; - LLModel* source = source_instance.mModel; - - for (S32 i = 0; i < source->getNumVolumeFaces(); ++i) - { //for each face in instance - LLImportMaterial& source_material = source_instance.mMaterial[i]; - - //clear material info - source_material.mDiffuseColor = LLColor4(1,1,1,1); - source_material.mDiffuseMap = NULL; - source_material.mDiffuseMapFilename.clear(); - source_material.mDiffuseMapLabel.clear(); - source_material.mFullbright = false; - } - } - } - - - mVertexBuffer[mPreviewLOD].clear(); - - if (mPreviewLOD == LLModel::LOD_HIGH) - { - mBaseScene = mScene[mPreviewLOD]; - mBaseModel = mModel[mPreviewLOD]; - mVertexBuffer[5].clear(); - } - - mResourceCost = calcResourceCost(); - refresh(); -} - -bool LLModelPreview::containsRiggedAsset( void ) -{ - //loop through the models and determine if any of them contained a rigged asset, and if so - //return true. - //This is used to cleanup the joint positions after a preview. - for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) - { - LLModel* pModel = *iter; - if ( pModel->mAlternateBindMatrix.size() > 0 ) - { - return true; - } - } - return false; -} -void LLModelPreview::genLODs(S32 which_lod) -{ - if (mBaseModel.empty()) - { - return; - } - - if (which_lod == LLModel::LOD_PHYSICS) - { //clear physics mesh map - mPhysicsMesh.clear(); - } - - LLVertexBuffer::unbind(); - - stop_gloderror(); - static U32 cur_name = 1; - - S32 limit = -1; - - if (which_lod != -1) - { - limit = mLimit[which_lod]; - } - - U32 triangle_count = 0; - - for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) - { - LLModel* mdl = *iter; - for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) - { - triangle_count += mdl->getVolumeFace(i).mNumIndices/3; - } - } - - U32 base_triangle_count = triangle_count; - - U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; - - if (mGroup[mBaseModel[0]] == 0) - { //clear LOD maps - mGroup.clear(); - mObject.clear(); - mPercentage.clear(); - mPatch.clear(); - } - - for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) - { //build GLOD objects for each model in base model list - LLModel* mdl = *iter; - if (mGroup[mdl] == 0) - { - mGroup[mdl] = cur_name++; - mObject[mdl] = cur_name++; - - glodNewGroup(mGroup[mdl]); - stop_gloderror(); - - glodGroupParameteri(mGroup[mdl], GLOD_ADAPT_MODE, GLOD_TRIANGLE_BUDGET); - stop_gloderror(); - - glodGroupParameteri(mGroup[mdl], GLOD_ERROR_MODE, GLOD_OBJECT_SPACE_ERROR); - stop_gloderror(); - - glodGroupParameterf(mGroup[mdl], GLOD_OBJECT_SPACE_ERROR_THRESHOLD, 0.025f); - stop_gloderror(); - - glodNewObject(mObject[mdl], mGroup[mdl], GLOD_DISCRETE); - stop_gloderror(); - - if (iter == mBaseModel.begin() && !mdl->mSkinWeights.empty()) - { //regenerate vertex buffer for skinned models to prevent animation feedback during LOD generation - mVertexBuffer[5].clear(); - } - - if (mVertexBuffer[5].empty()) - { - genBuffers(5, false); - } - - U32 tri_count = 0; - for (U32 i = 0; i < mVertexBuffer[5][mdl].size(); ++i) - { - mVertexBuffer[5][mdl][i]->setBuffer(type_mask); - U32 num_indices = mVertexBuffer[5][mdl][i]->getNumIndices(); - if (num_indices > 2) - { - glodInsertElements(mObject[mdl], i, GL_TRIANGLES, num_indices, GL_UNSIGNED_SHORT, mVertexBuffer[5][mdl][i]->getIndicesPointer(), 0, 0.f); - } - tri_count += num_indices/3; - stop_gloderror(); - } - - //store what percentage of total model (in terms of triangle count) this model makes up - mPercentage[mdl] = (F32) tri_count / (F32) base_triangle_count; - - //build glodobject - glodBuildObject(mObject[mdl]); - if (stop_gloderror()) - { - glodDeleteGroup(mGroup[mdl]); - stop_gloderror(); - glodDeleteObject(mObject[mdl]); - stop_gloderror(); - - mGroup[mdl] = 0; - mObject[mdl] = 0; - - if (which_lod == -1) - { - mModel[LLModel::LOD_HIGH] = mBaseModel; - } - - return; - } - - } - - //generating LODs for all entries, or this entry has a triangle budget - glodGroupParameteri(mGroup[mdl], GLOD_ADAPT_MODE, GLOD_TRIANGLE_BUDGET); - stop_gloderror(); - - glodGroupParameterf(mGroup[mdl], GLOD_OBJECT_SPACE_ERROR_THRESHOLD, 0.025f); - stop_gloderror(); - } - - - S32 start = LLModel::LOD_HIGH; - S32 end = 0; - - if (which_lod != -1) - { - start = end = which_lod; - } - - - std::string combo_name[] = - { - "lowest detail combo", - "low detail combo", - "medium detail combo", - "high detail combo", - "physics detail combo" - }; - - std::string limit_name[] = - { - "lowest limit", - "low limit", - "medium limit", - "high limit", - "physics limit" - }; - - for (S32 lod = start; lod >= end; --lod) - { - if (which_lod == -1) - { - if (lod < start) - { - triangle_count /= 3; - } - } - else - { - triangle_count = limit; - } - - LLComboBox* combo_box = mFMP->findChild(combo_name[lod]); - combo_box->setCurrentByIndex(2); - - LLSpinCtrl* lim = mFMP->getChild(limit_name[lod], TRUE); - lim->setMaxValue(base_triangle_count); - lim->setVisible(true); - - mModel[lod].clear(); - mModel[lod].resize(mBaseModel.size()); - mVertexBuffer[lod].clear(); - - U32 actual_tris = 0; - U32 actual_verts = 0; - U32 submeshes = 0; - - for (U32 mdl_idx = 0; mdl_idx < mBaseModel.size(); ++mdl_idx) - { - LLModel* base = mBaseModel[mdl_idx]; - - U32 target_count = U32(mPercentage[base]*triangle_count); - - if (target_count < 4) - { - target_count = 4; - } - - glodGroupParameteri(mGroup[base], GLOD_MAX_TRIANGLES, target_count); - stop_gloderror(); - - glodAdaptGroup(mGroup[base]); - stop_gloderror(); - - GLint patch_count = 0; - glodGetObjectParameteriv(mObject[base], GLOD_NUM_PATCHES, &patch_count); - stop_gloderror(); - - LLVolumeParams volume_params; - volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); - mModel[lod][mdl_idx] = new LLModel(volume_params, 0.f); - - GLint* sizes = new GLint[patch_count*2]; - glodGetObjectParameteriv(mObject[base], GLOD_PATCH_SIZES, sizes); - stop_gloderror(); - - GLint* names = new GLint[patch_count]; - glodGetObjectParameteriv(mObject[base], GLOD_PATCH_NAMES, names); - stop_gloderror(); - - mModel[lod][mdl_idx]->setNumVolumeFaces(patch_count); - - LLModel* target_model = mModel[lod][mdl_idx]; - - for (GLint i = 0; i < patch_count; ++i) - { - LLPointer buff = new LLVertexBuffer(type_mask, 0); - - if (sizes[i*2+1] > 0 && sizes[i*2] > 0) - { - buff->allocateBuffer(sizes[i*2+1], sizes[i*2], true); - buff->setBuffer(type_mask); - glodFillElements(mObject[base], names[i], GL_UNSIGNED_SHORT, buff->getIndicesPointer()); - stop_gloderror(); - } - else - { //this face was eliminated, create a dummy triangle (one vertex, 3 indices, all 0) - buff->allocateBuffer(1, 3, true); - memset(buff->getMappedData(), 0, buff->getSize()); - memset(buff->getIndicesPointer(), 0, buff->getIndicesSize()); - } - - buff->validateRange(0, buff->getNumVerts()-1, buff->getNumIndices(), 0); - - LLStrider pos; - LLStrider norm; - LLStrider tc; - LLStrider index; - - buff->getVertexStrider(pos); - buff->getNormalStrider(norm); - buff->getTexCoord0Strider(tc); - buff->getIndexStrider(index); - - - target_model->setVolumeFaceData(names[i], pos, norm, tc, index, buff->getNumVerts(), buff->getNumIndices()); - actual_tris += buff->getNumIndices()/3; - actual_verts += buff->getNumVerts(); - ++submeshes; - - if (!validate_face(target_model->getVolumeFace(names[i]))) - { - llerrs << "Invalid face generated during LOD generation." << llendl; - } - } - - //blind copy skin weights and just take closest skin weight to point on - //decimated mesh for now (auto-generating LODs with skin weights is still a bit - //of an open problem). - target_model->mPosition = base->mPosition; - target_model->mSkinWeights = base->mSkinWeights; - target_model->mJointMap = base->mJointMap; - target_model->mJointList = base->mJointList; - target_model->mInvBindMatrix = base->mInvBindMatrix; - target_model->mBindShapeMatrix = base->mBindShapeMatrix; - target_model->mAlternateBindMatrix = base->mAlternateBindMatrix; - //copy material list - target_model->mMaterialList = base->mMaterialList; - - if (!validate_model(target_model)) - { - llerrs << "Invalid model generated when creating LODs" << llendl; - } - - delete [] sizes; - delete [] names; - } - - //rebuild scene based on mBaseScene - mScene[lod].clear(); - mScene[lod] = mBaseScene; - - for (U32 i = 0; i < mBaseModel.size(); ++i) - { - LLModel* mdl = mBaseModel[i]; - LLModel* target = mModel[lod][i]; - if (target) - { - for (LLModelLoader::scene::iterator iter = mScene[lod].begin(); iter != mScene[lod].end(); ++iter) - { - for (U32 j = 0; j < iter->second.size(); ++j) - { - if (iter->second[j].mModel == mdl) - { - iter->second[j].mModel = target; - } - } - } - } - } - } - - mResourceCost = calcResourceCost(); - - /*if (which_lod == -1 && mScene[LLModel::LOD_PHYSICS].empty()) - { //build physics scene - mScene[LLModel::LOD_PHYSICS] = mScene[LLModel::LOD_LOW]; - mModel[LLModel::LOD_PHYSICS] = mModel[LLModel::LOD_LOW]; - - for (U32 i = 1; i < mModel[LLModel::LOD_PHYSICS].size(); ++i) - { - mPhysicsQ.push(mModel[LLModel::LOD_PHYSICS][i]); - } - }*/ -} - -void LLModelPreview::updateStatusMessages() -{ - //triangle/vertex/submesh count for each mesh asset for each lod - std::vector tris[LLModel::NUM_LODS]; - std::vector verts[LLModel::NUM_LODS]; - std::vector submeshes[LLModel::NUM_LODS]; - - //total triangle/vertex/submesh count for each lod - S32 total_tris[LLModel::NUM_LODS]; - S32 total_verts[LLModel::NUM_LODS]; - S32 total_submeshes[LLModel::NUM_LODS]; - - for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) - { - //initialize total for this lod to 0 - total_tris[lod] = total_verts[lod] = total_submeshes[lod] = 0; - - for (U32 i = 0; i < mModel[lod].size(); ++i) - { //for each model in the lod - S32 cur_tris = 0; - S32 cur_verts = 0; - S32 cur_submeshes = mModel[lod][i]->getNumVolumeFaces(); - - for (S32 j = 0; j < cur_submeshes; ++j) - { //for each submesh (face), add triangles and vertices to current total - const LLVolumeFace& face = mModel[lod][i]->getVolumeFace(j); - cur_tris += face.mNumIndices/3; - cur_verts += face.mNumVertices; - } - - //add this model to the lod total - total_tris[lod] += cur_tris; - total_verts[lod] += cur_verts; - total_submeshes[lod] += cur_submeshes; - - //store this model's counts to asset data - tris[lod].push_back(cur_tris); - verts[lod].push_back(cur_verts); - submeshes[lod].push_back(cur_submeshes); - } - } - - - std::string upload_message; - - mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[TRIANGLES]", llformat("%d", total_tris[LLModel::LOD_PHYSICS])); - - for (S32 lod = 0; lod <= LLModel::LOD_HIGH; ++lod) - { - mFMP->childSetTextArg(info_name[lod], "[TRIANGLES]", llformat("%d", total_tris[lod])); - mFMP->childSetTextArg(info_name[lod], "[VERTICES]", llformat("%d", total_verts[lod])); - mFMP->childSetTextArg(info_name[lod], "[SUBMESHES]", llformat("%d", total_submeshes[lod])); - - std::string message = "good"; - - const U32 lod_high = LLModel::LOD_HIGH; - - if (lod != lod_high) - { - if (total_submeshes[lod] && total_submeshes[lod] != total_submeshes[lod_high]) - { - message = "mesh_mismatch"; - upload_message = "bad_lod"; - } - else if (!tris[lod].empty() && tris[lod].size() != tris[lod_high].size()) - { - message = "model_mismatch"; - upload_message = "bad_lod"; - } - else if (!verts[lod].empty()) - { - for (U32 i = 0; i < verts[lod].size(); ++i) - { - S32 max_verts = verts[lod+1][i]; - - if (verts[lod][i] > max_verts) - { - message = "too_heavy"; - upload_message = "bad_lod"; - } - } - } - } - - mFMP->childSetTextArg(info_name[lod], "[MESSAGE]", mFMP->getString(message)); - } - - if (upload_message.empty()) - { - mFMP->childSetTextArg("upload_message", "[MESSAGE]", std::string("")); - mFMP->childEnable("ok_btn"); - } - else - { - mFMP->childSetTextArg("upload_message", "[MESSAGE]", mFMP->getString(upload_message)); - mFMP->childDisable("ok_btn"); - } -} - -void LLModelPreview::setPreviewTarget(F32 distance) -{ - mCameraDistance = distance; - mCameraZoom = 1.f; - mCameraPitch = 0.f; - mCameraYaw = 0.f; - mCameraOffset.clearVec(); -} - -void LLModelPreview::clearBuffers() -{ - for (U32 i = 0; i < 6; i++) - { - mVertexBuffer[i].clear(); - } -} - -void LLModelPreview::genBuffers(S32 lod, bool avatar_preview) -{ - U32 tri_count = 0; - U32 vertex_count = 0; - U32 mesh_count = 0; - - LLModelLoader::model_list* model = NULL; - - if (lod < 0 || lod > 4) - { - model = &mBaseModel; - lod = 5; - } - else - { - model = &(mModel[lod]); - } - - if (!mVertexBuffer[lod].empty()) - { - mVertexBuffer[lod].clear(); - } - - mVertexBuffer[lod].clear(); - - LLModelLoader::model_list::iterator base_iter = mBaseModel.begin(); - - for (LLModelLoader::model_list::iterator iter = model->begin(); iter != model->end(); ++iter) - { - LLModel* mdl = *iter; - if (!mdl) - { - continue; - } - - LLModel* base_mdl = *base_iter; - base_iter++; - - for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) - { - const LLVolumeFace &vf = mdl->getVolumeFace(i); - U32 num_vertices = vf.mNumVertices; - U32 num_indices = vf.mNumIndices; - - if (!num_vertices || ! num_indices) - { - continue; - } - - LLVertexBuffer* vb = NULL; - - bool skinned = avatar_preview && !mdl->mSkinWeights.empty(); - - U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; - - if (skinned) - { - mask |= LLVertexBuffer::MAP_WEIGHT4; - } - - vb = new LLVertexBuffer(mask, 0); - - vb->allocateBuffer(num_vertices, num_indices, TRUE); - - LLStrider vertex_strider; - LLStrider normal_strider; - LLStrider tc_strider; - LLStrider index_strider; - LLStrider weights_strider; - - vb->getVertexStrider(vertex_strider); - vb->getNormalStrider(normal_strider); - vb->getTexCoord0Strider(tc_strider); - vb->getIndexStrider(index_strider); - - if (skinned) - { - vb->getWeight4Strider(weights_strider); - } - - LLVector4a::memcpyNonAliased16((F32*) vertex_strider.get(), (F32*) vf.mPositions, num_vertices*4*sizeof(F32)); - LLVector4a::memcpyNonAliased16((F32*) tc_strider.get(), (F32*) vf.mTexCoords, num_vertices*2*sizeof(F32)); - LLVector4a::memcpyNonAliased16((F32*) normal_strider.get(), (F32*) vf.mNormals, num_vertices*4*sizeof(F32)); - - if (skinned) - { - for (U32 i = 0; i < num_vertices; i++) - { - //find closest weight to vf.mVertices[i].mPosition - LLVector3 pos(vf.mPositions[i].getF32ptr()); - - const LLModel::weight_list& weight_list = base_mdl->getJointInfluences(pos); - - LLVector4 w(0,0,0,0); - if (weight_list.size() > 4) - { - llerrs << "WTF?" << llendl; - } - - for (U32 i = 0; i < weight_list.size(); ++i) - { - F32 wght = llmin(weight_list[i].mWeight, 0.999999f); - F32 joint = (F32) weight_list[i].mJointIdx; - w.mV[i] = joint + wght; - } - - *(weights_strider++) = w; - } - } - - // build indices - for (U32 i = 0; i < num_indices; i++) - { - *(index_strider++) = vf.mIndices[i]; - } - - mVertexBuffer[lod][mdl].push_back(vb); - - vertex_count += num_vertices; - tri_count += num_indices/3; - ++mesh_count; - - } - } -} - -void LLModelPreview::update() -{ - if (mDirty) - { - mDirty = false; - mResourceCost = calcResourceCost(); - } -} - -//----------------------------------------------------------------------------- -// render() -//----------------------------------------------------------------------------- -BOOL LLModelPreview::render() -{ - LLMutexLock lock(this); - mNeedsUpdate = FALSE; - - S32 width = getWidth(); - S32 height = getHeight(); - - LLGLSUIDefault def; - LLGLDisable no_blend(GL_BLEND); - LLGLEnable cull(GL_CULL_FACE); - LLGLDepthTest depth(GL_TRUE); - LLGLDisable fog(GL_FOG); - - glMatrixMode(GL_PROJECTION); - gGL.pushMatrix(); - glLoadIdentity(); - glOrtho(0.0f, width, 0.0f, height, -1.0f, 1.0f); - - glMatrixMode(GL_MODELVIEW); - gGL.pushMatrix(); - glLoadIdentity(); - - gGL.color4f(0.15f, 0.2f, 0.3f, 1.f); - - gl_rect_2d_simple( width, height ); - - bool avatar_preview = false; - bool upload_skin = mFMP->childGetValue("upload_skin").asBoolean(); - bool upload_joints = mFMP->childGetValue("upload_joints").asBoolean(); - - for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) - { - for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) - { - LLModelInstance& instance = *model_iter; - LLModel* model = instance.mModel; - if (!model->mSkinWeights.empty()) - { - avatar_preview = true; - } - } - } - - if (upload_skin && !avatar_preview) - { - mFMP->childSetValue("upload_skin", false); - upload_skin = false; - } - - if (!upload_skin && upload_joints) - { - mFMP->childSetValue("upload_joints", false); - upload_joints = false; - } - - if (!avatar_preview) - { - mFMP->childDisable("upload_skin"); - } - else - { - mFMP->childEnable("upload_skin"); - } - - if (!upload_skin) - { - mFMP->childDisable("upload_joints"); - } - else - { - mFMP->childEnable("upload_joints"); - } - - avatar_preview = avatar_preview && upload_skin; - - - mFMP->childSetEnabled("consolidate", !avatar_preview); - - F32 explode = mFMP->mDecompFloater ? mFMP->mDecompFloater->childGetValue("explode").asReal() : 0.f; - - glMatrixMode(GL_PROJECTION); - gGL.popMatrix(); - - glMatrixMode(GL_MODELVIEW); - gGL.popMatrix(); - - glClear(GL_DEPTH_BUFFER_BIT); - - LLViewerCamera::getInstance()->setAspect((F32) width / height ); - LLViewerCamera::getInstance()->setView(LLViewerCamera::getInstance()->getDefaultFOV() / mCameraZoom); - - LLVector3 target_pos = mPreviewTarget; - LLVector3 offset = mCameraOffset; - - F32 z_near = llmax(mCameraDistance-mPreviewScale.magVec(), 0.001f); - F32 z_far = mCameraDistance+mPreviewScale.magVec(); - - if (avatar_preview) - { - target_pos = gAgentAvatarp->getPositionAgent(); - z_near = 0.01f; - z_far = 1024.f; - mCameraDistance = 16.f; - - //render avatar previews every frame - refresh(); - } - - LLQuaternion camera_rot = LLQuaternion(mCameraPitch, LLVector3::y_axis) * - LLQuaternion(mCameraYaw, LLVector3::z_axis); - - LLQuaternion av_rot = camera_rot; - LLViewerCamera::getInstance()->setOriginAndLookAt( - target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + offset) * av_rot), // camera - LLVector3::z_axis, // up - target_pos); // point of interest - - - LLViewerCamera::getInstance()->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, width, height, FALSE, z_near, z_far); - - stop_glerror(); - - gPipeline.enableLightsAvatar(); - - gGL.pushMatrix(); - const F32 BRIGHTNESS = 0.9f; - gGL.color3f(BRIGHTNESS, BRIGHTNESS, BRIGHTNESS); - - LLGLEnable normalize(GL_NORMALIZE); - - if (!mBaseModel.empty() && mVertexBuffer[5].empty()) - { - genBuffers(-1, avatar_preview); - //genBuffers(3); - //genLODs(); - } - - bool physics = (mPreviewLOD == LLModel::LOD_PHYSICS); - - S32 physics_idx = -1; - - bool render_mesh = true; - bool render_hull = false; - - if (physics && mFMP->mDecompFloater) - { - physics_idx = mFMP->mDecompFloater->childGetValue("model").asInteger(); - render_mesh = mFMP->mDecompFloater->childGetValue("render_mesh").asBoolean(); - render_hull = mFMP->mDecompFloater->childGetValue("render_hull").asBoolean(); - } - - if (!mModel[mPreviewLOD].empty()) - { - if (mVertexBuffer[mPreviewLOD].empty()) - { - genBuffers(mPreviewLOD, avatar_preview); - } - - if (!avatar_preview) - { - //for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) - for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) - { - LLModelInstance& instance = *iter; - - gGL.pushMatrix(); - LLMatrix4 mat = instance.mTransform; - - glMultMatrixf((GLfloat*) mat.mMatrix); - - //for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) - { - //LLModelInstance& instance = *model_iter; - LLModel* model = instance.mLOD[mPreviewLOD]; - - if (!model) - { - continue; - } - - //if (instance.mTransform != mat) - //{ - // llerrs << "WTF?" << llendl; - //} - - if (render_mesh) - { - for (U32 i = 0; i < mVertexBuffer[mPreviewLOD][model].size(); ++i) - { - LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; - - buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); - if (physics) - { - if (physics_idx > -1 && model == mModel[mPreviewLOD][physics_idx]) - { - glColor4f(1,0,0,1); - } - else - { - glColor4f(0.75f, 0.75f, 0.75f, 1.f); - } - } - else - { - glColor4fv(instance.mMaterial[i].mDiffuseColor.mV); - if (i < instance.mMaterial.size() && instance.mMaterial[i].mDiffuseMap.notNull()) - { - gGL.getTexUnit(0)->bind(instance.mMaterial[i].mDiffuseMap, true); - if (instance.mMaterial[i].mDiffuseMap->getDiscardLevel() > -1) - { - mTextureSet.insert(instance.mMaterial[i].mDiffuseMap); - } - } - } - - buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - glColor3f(0.4f, 0.4f, 0.4f); - - if (mFMP->childGetValue("show edges").asBoolean()) - { - glLineWidth(3.f); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glLineWidth(1.f); - } - } - } - - if (render_hull) - { - LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread; - if (decomp) - { - LLMutexLock(decomp->mMutex); - - std::map, std::vector > >::iterator iter = - mPhysicsMesh.find(model); - if (iter != mPhysicsMesh.end()) - { - for (U32 i = 0; i < iter->second.size(); ++i) - { - if (explode > 0.f) - { - gGL.pushMatrix(); - - LLVector3 offset = model->mHullCenter[i]-model->mCenterOfHullCenters; - offset *= explode; - - gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]); - } - - static std::vector hull_colors; - - if (i+1 >= hull_colors.size()) - { - hull_colors.push_back(LLColor4U(rand()%128+127, rand()%128+127, rand()%128+127, 255)); - } - - LLVertexBuffer* buff = iter->second[i]; - if (buff) - { - buff->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL); - - glColor4ubv(hull_colors[i].mV); - buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts()); - - if (mFMP->childGetValue("show edges").asBoolean()) - { - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - glLineWidth(3.f); - glColor4ub(hull_colors[i].mV[0]/2, hull_colors[i].mV[1]/2, hull_colors[i].mV[2]/2, 255); - buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts()); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glLineWidth(1.f); - } - } - - if (explode > 0.f) - { - gGL.popMatrix(); - } - } - } - } - - //mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[HULLS]", llformat("%d",decomp->mHulls.size())); - //mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[POINTS]", llformat("%d",decomp->mTotalPoints)); - } - } - - gGL.popMatrix(); - } - - if (physics) - { - mPreviewLOD = LLModel::LOD_PHYSICS; - } - } - else - { - LLVOAvatarSelf* avatar = gAgentAvatarp; - target_pos = avatar->getPositionAgent(); - - LLViewerCamera::getInstance()->setOriginAndLookAt( - target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + offset) * av_rot), // camera - LLVector3::z_axis, // up - target_pos); // point of interest - - avatar->renderCollisionVolumes(); - - for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) - { - for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) - { - LLModelInstance& instance = *model_iter; - LLModel* model = instance.mModel; - - if (!model->mSkinWeights.empty()) - { - for (U32 i = 0; i < mVertexBuffer[mPreviewLOD][model].size(); ++i) - { - LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; - - const LLVolumeFace& face = model->getVolumeFace(i); - - LLStrider position; - buffer->getVertexStrider(position); - - LLStrider weight; - buffer->getWeight4Strider(weight); - - //quick 'n dirty software vertex skinning - - //build matrix palette - LLMatrix4 mat[64]; - for (U32 j = 0; j < model->mJointList.size(); ++j) - { - LLJoint* joint = avatar->getJoint(model->mJointList[j]); - if (joint) - { - mat[j] = model->mInvBindMatrix[j]; - mat[j] *= joint->getWorldMatrix(); - } - } - - for (U32 j = 0; j < buffer->getRequestedVerts(); ++j) - { - LLMatrix4 final_mat; - final_mat.mMatrix[0][0] = final_mat.mMatrix[1][1] = final_mat.mMatrix[2][2] = final_mat.mMatrix[3][3] = 0.f; - - LLVector4 wght; - S32 idx[4]; - - F32 scale = 0.f; - for (U32 k = 0; k < 4; k++) - { - F32 w = weight[j].mV[k]; - - idx[k] = (S32) floorf(w); - wght.mV[k] = w - floorf(w); - scale += wght.mV[k]; - } - - wght *= 1.f/scale; - - for (U32 k = 0; k < 4; k++) - { - F32* src = (F32*) mat[idx[k]].mMatrix; - F32* dst = (F32*) final_mat.mMatrix; - - F32 w = wght.mV[k]; - - for (U32 l = 0; l < 16; l++) - { - dst[l] += src[l]*w; - } - } - - //VECTORIZE THIS - LLVector3 v(face.mPositions[j].getF32ptr()); - - v = v * model->mBindShapeMatrix; - v = v * final_mat; - - position[j] = v; - } - - buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); - glColor4fv(instance.mMaterial[i].mDiffuseColor.mV); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); - glColor3f(0.4f, 0.4f, 0.4f); - - if (mFMP->childGetValue("show edges").asBoolean()) - { - glLineWidth(3.f); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glLineWidth(1.f); - } - } - } - } - } - } - } - - gGL.popMatrix(); - - return TRUE; -} - -//----------------------------------------------------------------------------- -// refresh() -//----------------------------------------------------------------------------- -void LLModelPreview::refresh() -{ - mNeedsUpdate = TRUE; -} - -//----------------------------------------------------------------------------- -// rotate() -//----------------------------------------------------------------------------- -void LLModelPreview::rotate(F32 yaw_radians, F32 pitch_radians) -{ - mCameraYaw = mCameraYaw + yaw_radians; - - mCameraPitch = llclamp(mCameraPitch + pitch_radians, F_PI_BY_TWO * -0.8f, F_PI_BY_TWO * 0.8f); -} - -//----------------------------------------------------------------------------- -// zoom() -//----------------------------------------------------------------------------- -void LLModelPreview::zoom(F32 zoom_amt) -{ - F32 new_zoom = mCameraZoom+zoom_amt; - - mCameraZoom = llclamp(new_zoom, 1.f, 10.f); -} - -void LLModelPreview::pan(F32 right, F32 up) -{ - mCameraOffset.mV[VY] = llclamp(mCameraOffset.mV[VY] + right * mCameraDistance / mCameraZoom, -1.f, 1.f); - mCameraOffset.mV[VZ] = llclamp(mCameraOffset.mV[VZ] + up * mCameraDistance / mCameraZoom, -1.f, 1.f); -} - -void LLModelPreview::setPreviewLOD(S32 lod) -{ - mPreviewLOD = llclamp(lod, 0, 4); - refresh(); -} - -//static -void LLFloaterModelPreview::onBrowseHighLOD(void* data) -{ - LLFloaterModelPreview* mp = (LLFloaterModelPreview*) data; - mp->loadModel(3); -} - -//static -void LLFloaterModelPreview::onBrowseMediumLOD(void* data) -{ - LLFloaterModelPreview* mp = (LLFloaterModelPreview*) data; - mp->loadModel(2); -} - -//static -void LLFloaterModelPreview::onBrowseLowLOD(void* data) -{ - LLFloaterModelPreview* mp = (LLFloaterModelPreview*) data; - mp->loadModel(1); -} - -//static -void LLFloaterModelPreview::onBrowseLowestLOD(void* data) -{ - LLFloaterModelPreview* mp = (LLFloaterModelPreview*) data; - mp->loadModel(0); -} - -//static -void LLFloaterModelPreview::onUpload(void* user_data) -{ - LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; - - if (mp->mDecompFloater) - { - mp->mDecompFloater->closeFloater(); - } - - mp->mModelPreview->rebuildUploadData(); - - gMeshRepo.uploadModel(mp->mModelPreview->mUploadData, mp->mModelPreview->mPreviewScale, - mp->childGetValue("upload_textures").asBoolean(), mp->childGetValue("upload_skin"), mp->childGetValue("upload_joints")); - - mp->closeFloater(false); -} - -//static -void LLFloaterModelPreview::onConsolidate(void* user_data) -{ - LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; - mp->mModelPreview->consolidate(); -} - -//static -void LLFloaterModelPreview::onScrubMaterials(void* user_data) -{ - LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; - mp->mModelPreview->scrubMaterials(); -} - -//static -void LLFloaterModelPreview::onDecompose(void* user_data) -{ - LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; - mp->showDecompFloater(); -} - -//static -void LLFloaterModelPreview::refresh(LLUICtrl* ctrl, void* user_data) -{ - LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; - mp->mModelPreview->refresh(); -} - -void LLFloaterModelPreview::updateResourceCost() -{ - U32 cost = mModelPreview->mResourceCost; - childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d",cost)); -} - -//static -void LLModelPreview::textureLoadedCallback( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata ) -{ - LLModelPreview* preview = (LLModelPreview*) userdata; - preview->refresh(); -} - -LLFloaterModelPreview::DecompRequest::DecompRequest(const std::string& stage, LLModel* mdl) -{ - mStage = stage; - mContinue = 1; - mModel = mdl; - mParams = sInstance->mDecompParams; - - //copy out positions and indices - if (mdl) - { - U16 index_offset = 0; - - mPositions.clear(); - mIndices.clear(); - - //queue up vertex positions and indices - for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) - { - const LLVolumeFace& face = mdl->getVolumeFace(i); - if (mPositions.size() + face.mNumVertices > 65535) - { - continue; - } - - for (U32 j = 0; j < face.mNumVertices; ++j) - { - mPositions.push_back(LLVector3(face.mPositions[j].getF32ptr())); - } - - for (U32 j = 0; j < face.mNumIndices; ++j) - { - mIndices.push_back(face.mIndices[j]+index_offset); - } - - index_offset += face.mNumVertices; - } - } -} - -S32 LLFloaterModelPreview::DecompRequest::statusCallback(const char* status, S32 p1, S32 p2) -{ - setStatusMessage(llformat("%s: %d/%d", status, p1, p2)); - return mContinue; -} - -void LLFloaterModelPreview::DecompRequest::completed() -{ - mModel->setConvexHullDecomposition(mHull); - - if (sInstance) - { - if (sInstance->mModelPreview) - { - sInstance->mModelPreview->mPhysicsMesh[mModel] = mHullMesh; - sInstance->mModelPreview->mDirty = true; - LLFloaterModelPreview::sInstance->mModelPreview->refresh(); - } - - sInstance->mCurRequest = NULL; - } -} - - +/** + * @file llfloatermodelpreview.cpp + * @brief LLFloaterModelPreview class implementation + * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "dae.h" +//#include "dom.h" +#include "dom/domAsset.h" +#include "dom/domBind_material.h" +#include "dom/domCOLLADA.h" +#include "dom/domConstants.h" +#include "dom/domController.h" +#include "dom/domEffect.h" +#include "dom/domGeometry.h" +#include "dom/domInstance_geometry.h" +#include "dom/domInstance_material.h" +#include "dom/domInstance_node.h" +#include "dom/domInstance_effect.h" +#include "dom/domMaterial.h" +#include "dom/domMatrix.h" +#include "dom/domNode.h" +#include "dom/domProfile_COMMON.h" +#include "dom/domRotate.h" +#include "dom/domScale.h" +#include "dom/domTranslate.h" +#include "dom/domVisual_scene.h" + +#include "llfloatermodelpreview.h" + +#include "llfilepicker.h" +#include "llimagebmp.h" +#include "llimagetga.h" +#include "llimagejpeg.h" +#include "llimagepng.h" + +#include "llagent.h" +#include "llbutton.h" +#include "llcombobox.h" +#include "lldatapacker.h" +#include "lldrawable.h" +#include "lldrawpoolavatar.h" +#include "llrender.h" +#include "llface.h" +#include "lleconomy.h" +#include "llfocusmgr.h" +#include "llfloaterperms.h" +#include "llmatrix4a.h" +#include "llmeshrepository.h" +#include "llsdutil_math.h" +#include "lltextbox.h" +#include "lltoolmgr.h" +#include "llui.h" +#include "llvector4a.h" +#include "llviewercamera.h" +#include "llviewerwindow.h" +#include "llvoavatar.h" +#include "llvoavatarself.h" +#include "pipeline.h" +#include "lluictrlfactory.h" +#include "llviewermenufile.h" +#include "llviewerregion.h" +#include "llstring.h" +#include "llbutton.h" +#include "llcheckboxctrl.h" +#include "llsliderctrl.h" +#include "llspinctrl.h" +#include "llvfile.h" +#include "llvfs.h" + + +#include "glod/glod.h" + +//static +S32 LLFloaterModelPreview::sUploadAmount = 10; +LLFloaterModelPreview* LLFloaterModelPreview::sInstance = NULL; + +const S32 PREVIEW_BORDER_WIDTH = 2; +const S32 PREVIEW_RESIZE_HANDLE_SIZE = S32(RESIZE_HANDLE_WIDTH * OO_SQRT2) + PREVIEW_BORDER_WIDTH; +const S32 PREVIEW_HPAD = PREVIEW_RESIZE_HANDLE_SIZE; +const S32 PREF_BUTTON_HEIGHT = 16 + 7 + 16; +const S32 PREVIEW_TEXTURE_HEIGHT = 300; + +void drawBoxOutline(const LLVector3& pos, const LLVector3& size); + +std::string limit_name[] = +{ + "lowest limit", + "low limit", + "medium limit", + "high limit", + "physics limit", + + "I went off the end of the limit_name array. Me so smart." +}; + +std::string info_name[] = +{ + "lowest info", + "low info", + "medium info", + "high info", + "physics info", + + "I went off the end of the info_name array. Me so smart." +}; + +bool validate_face(const LLVolumeFace& face) +{ + for (U32 i = 0; i < face.mNumIndices; ++i) + { + if (face.mIndices[i] >= face.mNumVertices) + { + llwarns << "Face has invalid index." << llendl; + return false; + } + } + + return true; +} + +bool validate_model(const LLModel* mdl) +{ + if (mdl->getNumVolumeFaces() == 0) + { + llwarns << "Model has no faces!" << llendl; + return false; + } + + for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) + { + if (mdl->getVolumeFace(i).mNumVertices == 0) + { + llwarns << "Face has no vertices." << llendl; + return false; + } + + if (mdl->getVolumeFace(i).mNumIndices == 0) + { + llwarns << "Face has no indices." << llendl; + return false; + } + + if (!validate_face(mdl->getVolumeFace(i))) + { + return false; + } + } + + return true; +} + +BOOL stop_gloderror() +{ + GLuint error = glodGetError(); + + if (error != GLOD_NO_ERROR) + { + llwarns << "GLOD error detected, cannot generate LOD: " << std::hex << error << llendl; + return TRUE; + } + + return FALSE; +} + +LLPhysicsDecompFloater::LLPhysicsDecompFloater(LLSD& key) +: LLFloater(key) +{ + +} + +LLPhysicsDecompFloater::~LLPhysicsDecompFloater() +{ + if (LLFloaterModelPreview::sInstance && LLFloaterModelPreview::sInstance->mDecompFloater) + { + LLFloaterModelPreview::sInstance->mDecompFloater = NULL; + } +} + +class LLMeshFilePicker : public LLFilePickerThread +{ +public: + LLFloaterModelPreview* mFMP; + S32 mLOD; + + LLMeshFilePicker(LLFloaterModelPreview* fmp, S32 lod) + : LLFilePickerThread(LLFilePicker::FFLOAD_COLLADA) + { + mFMP = fmp; + mLOD = lod; + } + + virtual void notify(const std::string& filename) + { + mFMP->mModelPreview->loadModel(mFile, mLOD); + } +}; + + +//----------------------------------------------------------------------------- +// LLFloaterModelPreview() +//----------------------------------------------------------------------------- +LLFloaterModelPreview::LLFloaterModelPreview(const LLSD& key) : + LLFloater(key) +{ + sInstance = this; + mLastMouseX = 0; + mLastMouseY = 0; + mGLName = 0; + mLoading = FALSE; + mDecompFloater = NULL; +} + +//----------------------------------------------------------------------------- +// postBuild() +//----------------------------------------------------------------------------- +BOOL LLFloaterModelPreview::postBuild() +{ + if (!LLFloater::postBuild()) + { + return FALSE; + } + + childSetCommitCallback("high detail combo", onHighLODCommit, this); + childSetCommitCallback("medium detail combo", onMediumLODCommit, this); + childSetCommitCallback("low detail combo", onLowLODCommit, this); + childSetCommitCallback("lowest detail combo", onLowestLODCommit, this); + childSetCommitCallback("physics detail combo", onPhysicsLODCommit, this); + + + childSetCommitCallback("high limit", onHighLimitCommit, this); + childSetCommitCallback("medium limit", onMediumLimitCommit, this); + childSetCommitCallback("low limit", onLowLimitCommit, this); + childSetCommitCallback("lowest limit", onLowestLimitCommit, this); + childSetCommitCallback("physics limit", onPhysicsLimitCommit, this); + + childSetCommitCallback("smooth normals", onSmoothNormalsCommit, this); + + childSetCommitCallback("show edges", onShowEdgesCommit, this); + childSetCommitCallback("auto fill", onAutoFillCommit, this); + + childSetTextArg("status", "[STATUS]", getString("status_idle")); + + for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) + { + if (lod == LLModel::LOD_PHYSICS) + { + childSetTextArg(info_name[lod], "[TRIANGLES]", std::string("0")); + childSetTextArg(info_name[lod], "[HULLS]", std::string("0")); + childSetTextArg(info_name[lod], "[POINTS]", std::string("0")); + } + else + { + childSetTextArg(info_name[lod], "[TRIANGLES]", std::string("0")); + childSetTextArg(info_name[lod], "[VERTICES]", std::string("0")); + childSetTextArg(info_name[lod], "[SUBMESHES]", std::string("0")); + std::string msg = getString("required"); + childSetTextArg(info_name[lod], "[MESSAGE]", msg); + } + + childSetVisible(limit_name[lod], FALSE); + } + + //childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d",sUploadAmount)); + childSetAction("ok_btn", onUpload, this); + + childSetAction("consolidate", onConsolidate, this); + childSetAction("scrub materials", onScrubMaterials, this); + + childSetAction("decompose_btn", onDecompose, this); + + childSetCommitCallback("preview_lod_combo", onPreviewLODCommit, this); + + childSetCommitCallback("upload_skin", onUploadSkinCommit, this); + childSetCommitCallback("upload_joints", onUploadJointsCommit, this); + + childSetCommitCallback("debug scale", onDebugScaleCommit, this); + + childDisable("upload_skin"); + childDisable("upload_joints"); + + const U32 width = 512; + const U32 height = 512; + + mPreviewRect.set(getRect().getWidth()-PREVIEW_HPAD-width, + PREVIEW_HPAD+height, + getRect().getWidth()-PREVIEW_HPAD, + PREVIEW_HPAD); + + mModelPreview = new LLModelPreview(512, 512, this); + mModelPreview->setPreviewTarget(16.f); + + return TRUE; +} + +//----------------------------------------------------------------------------- +// LLFloaterModelPreview() +//----------------------------------------------------------------------------- +LLFloaterModelPreview::~LLFloaterModelPreview() +{ + sInstance = NULL; + + if ( mModelPreview->containsRiggedAsset() ) + { + gAgentAvatarp->resetJointPositions(); + } + + delete mModelPreview; + + if (mGLName) + { + LLImageGL::deleteTextures(1, &mGLName ); + } + + if (mDecompFloater) + { + mDecompFloater->closeFloater(); + mDecompFloater = NULL; + } +} + +void LLFloaterModelPreview::loadModel(S32 lod) +{ + mLoading = TRUE; + + (new LLMeshFilePicker(this, lod))->getFile(); +} + +void LLFloaterModelPreview::setLODMode(S32 lod, S32 mode) +{ + if (mode == 0) + { + if (lod != LLModel::LOD_PHYSICS) + { + for (S32 i = lod; i >= 0; i--) + { + mModelPreview->clearModel(i); + } + } + else + { + mModelPreview->clearModel(lod); + } + + mModelPreview->refresh(); + mModelPreview->calcResourceCost(); + } + else if (mode == 1) + { + loadModel(lod); + } + else if (mode != mModelPreview->mLODMode[lod]) + { + mModelPreview->mLODMode[lod] = mode; + mModelPreview->genLODs(lod); + } + + mModelPreview->setPreviewLOD(lod); + + + LLSpinCtrl* lim = getChild(limit_name[lod], TRUE); + + if (mode == 2) //triangle count + { + U32 tri_count = 0; + for (LLModelLoader::model_list::iterator iter = mModelPreview->mBaseModel.begin(); + iter != mModelPreview->mBaseModel.end(); ++iter) + { + tri_count += (*iter)->getNumTriangles(); + } + + lim->setMaxValue(tri_count); + lim->setVisible(TRUE); + } + else + { + lim->setVisible(FALSE); + } +} + +void LLFloaterModelPreview::setLimit(S32 lod, S32 limit) +{ + if (limit != mModelPreview->mLimit[lod]) + { + mModelPreview->mLimit[lod] = limit; + mModelPreview->genLODs(lod); + mModelPreview->setPreviewLOD(lod); + } +} + +//static +void LLFloaterModelPreview::onDebugScaleCommit(LLUICtrl*,void* userdata) +{ + LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; + + if (!fp->mModelPreview) + { + return; + } + + fp->mModelPreview->calcResourceCost(); +} + +//static +void LLFloaterModelPreview::onUploadJointsCommit(LLUICtrl*,void* userdata) +{ + LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; + + if (!fp->mModelPreview) + { + return; + } + + fp->mModelPreview->refresh(); +} + +//static +void LLFloaterModelPreview::onUploadSkinCommit(LLUICtrl*,void* userdata) +{ + LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; + + if (!fp->mModelPreview) + { + return; + } + + fp->mModelPreview->refresh(); + fp->mModelPreview->resetPreviewTarget(); + fp->mModelPreview->clearBuffers(); +} + +//static +void LLFloaterModelPreview::onPreviewLODCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; + + if (!fp->mModelPreview) + { + return; + } + + S32 which_mode = 0; + + LLCtrlSelectionInterface* iface = fp->childGetSelectionInterface("preview_lod_combo"); + if (iface) + { + which_mode = iface->getFirstSelectedIndex(); + } + fp->mModelPreview->setPreviewLOD(which_mode); +} + +//static +void LLFloaterModelPreview::setLODMode(S32 lod, void* userdata) +{ + LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; + + if (!fp->mModelPreview) + { + return; + } + + S32 which_mode = 0; + + std::string combo_name[] = + { + "lowest detail combo", + "low detail combo", + "medium detail combo", + "high detail combo", + "physics detail combo", + + "I went off the end of the combo_name array. Me so smart." + }; + + LLCtrlSelectionInterface* iface = fp->childGetSelectionInterface(combo_name[lod]); + if (iface) + { + which_mode = iface->getFirstSelectedIndex(); + } + + fp->setLODMode(lod, which_mode); +} + +//static +void LLFloaterModelPreview::onHighLODCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview::setLODMode(3, userdata); +} + +//static +void LLFloaterModelPreview::onMediumLODCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview::setLODMode(2, userdata); +} + +//static +void LLFloaterModelPreview::onLowLODCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview::setLODMode(1, userdata); +} + +//static +void LLFloaterModelPreview::onLowestLODCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview::setLODMode(0, userdata); +} + +//static +void LLFloaterModelPreview::onPhysicsLODCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview::setLODMode(4, userdata); +} + +//static +void LLFloaterModelPreview::setLimit(S32 lod, void* userdata) +{ + LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; + + if (!fp->mModelPreview) + { + return; + } + + S32 limit = fp->childGetValue(limit_name[lod]).asInteger(); + + + fp->setLimit(lod, limit); +} + +//static +void LLFloaterModelPreview::onHighLimitCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview::setLimit(3, userdata); +} + +//static +void LLFloaterModelPreview::onMediumLimitCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview::setLimit(2, userdata); +} + +//static +void LLFloaterModelPreview::onLowLimitCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview::setLimit(1, userdata); +} + +//static +void LLFloaterModelPreview::onLowestLimitCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview::setLimit(0, userdata); +} + +//static +void LLFloaterModelPreview::onPhysicsLimitCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview::setLimit(4, userdata); +} + +//static +void LLFloaterModelPreview::onSmoothNormalsCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; + + fp->mModelPreview->smoothNormals(); +} + +//static +void LLFloaterModelPreview::onShowEdgesCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; + + fp->mModelPreview->refresh(); +} + +//static +void LLFloaterModelPreview::onExplodeCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview* fp = LLFloaterModelPreview::sInstance; + + fp->mModelPreview->refresh(); +} + +//static +void LLFloaterModelPreview::onAutoFillCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; + + fp->mModelPreview->genLODs(); +} + + +//----------------------------------------------------------------------------- +// draw() +//----------------------------------------------------------------------------- +void LLFloaterModelPreview::draw() +{ + LLFloater::draw(); + LLRect r = getRect(); + + mModelPreview->update(); + + if (!mLoading) + { + childSetTextArg("status", "[STATUS]", getString("status_idle")); + } + + childSetTextArg("description_label", "[PRIM_COST]", llformat("%d", mModelPreview->mResourceCost)); + childSetTextArg("description_label", "[TEXTURES]", llformat("%d", mModelPreview->mTextureSet.size())); + + if (mDecompFloater) + { + if (mCurRequest.notNull()) + { + mDecompFloater->childSetText("status", mCurRequest->mStatusMessage); + } + else + { + const std::string idle("Idle."); + mDecompFloater->childSetText("status", idle); + } + } + + U32 resource_cost = mModelPreview->mResourceCost*10; + + if (childGetValue("upload_textures").asBoolean()) + { + resource_cost += mModelPreview->mTextureSet.size()*10; + } + + childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d", resource_cost)); + + if (mModelPreview) + { + gGL.color3f(1.f, 1.f, 1.f); + + gGL.getTexUnit(0)->bind(mModelPreview); + + gGL.begin( LLRender::QUADS ); + { + gGL.texCoord2f(0.f, 1.f); + gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mTop); + gGL.texCoord2f(0.f, 0.f); + gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mBottom); + gGL.texCoord2f(1.f, 0.f); + gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mBottom); + gGL.texCoord2f(1.f, 1.f); + gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mTop); + } + gGL.end(); + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + } +} + +//----------------------------------------------------------------------------- +// handleMouseDown() +//----------------------------------------------------------------------------- +BOOL LLFloaterModelPreview::handleMouseDown(S32 x, S32 y, MASK mask) +{ + if (mPreviewRect.pointInRect(x, y)) + { + bringToFront( x, y ); + gFocusMgr.setMouseCapture(this); + gViewerWindow->hideCursor(); + mLastMouseX = x; + mLastMouseY = y; + return TRUE; + } + + return LLFloater::handleMouseDown(x, y, mask); +} + +//----------------------------------------------------------------------------- +// handleMouseUp() +//----------------------------------------------------------------------------- +BOOL LLFloaterModelPreview::handleMouseUp(S32 x, S32 y, MASK mask) +{ + gFocusMgr.setMouseCapture(FALSE); + gViewerWindow->showCursor(); + return LLFloater::handleMouseUp(x, y, mask); +} + +//----------------------------------------------------------------------------- +// handleHover() +//----------------------------------------------------------------------------- +BOOL LLFloaterModelPreview::handleHover (S32 x, S32 y, MASK mask) +{ + MASK local_mask = mask & ~MASK_ALT; + + if (mModelPreview && hasMouseCapture()) + { + if (local_mask == MASK_PAN) + { + // pan here + mModelPreview->pan((F32)(x - mLastMouseX) * -0.005f, (F32)(y - mLastMouseY) * -0.005f); + } + else if (local_mask == MASK_ORBIT) + { + F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f; + F32 pitch_radians = (F32)(y - mLastMouseY) * 0.02f; + + mModelPreview->rotate(yaw_radians, pitch_radians); + } + else + { + + F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f; + F32 zoom_amt = (F32)(y - mLastMouseY) * 0.02f; + + mModelPreview->rotate(yaw_radians, 0.f); + mModelPreview->zoom(zoom_amt); + } + + + mModelPreview->refresh(); + + LLUI::setMousePositionLocal(this, mLastMouseX, mLastMouseY); + } + + if (!mPreviewRect.pointInRect(x, y) || !mModelPreview) + { + return LLFloater::handleHover(x, y, mask); + } + else if (local_mask == MASK_ORBIT) + { + gViewerWindow->setCursor(UI_CURSOR_TOOLCAMERA); + } + else if (local_mask == MASK_PAN) + { + gViewerWindow->setCursor(UI_CURSOR_TOOLPAN); + } + else + { + gViewerWindow->setCursor(UI_CURSOR_TOOLZOOMIN); + } + + return TRUE; +} + +//----------------------------------------------------------------------------- +// handleScrollWheel() +//----------------------------------------------------------------------------- +BOOL LLFloaterModelPreview::handleScrollWheel(S32 x, S32 y, S32 clicks) +{ + if (mPreviewRect.pointInRect(x, y) && mModelPreview) + { + mModelPreview->zoom((F32)clicks * -0.2f); + mModelPreview->refresh(); + } + + return TRUE; +} + +//static +void LLFloaterModelPreview::onPhysicsParamCommit(LLUICtrl* ctrl, void* data) +{ + if (LLConvexDecomposition::getInstance() == NULL) + { + llinfos << "convex decomposition tool is a stub on this platform. cannot get decomp." << llendl; + return; + } + + if (sInstance) + { + LLCDParam* param = (LLCDParam*) data; + sInstance->mDecompParams[param->mName] = ctrl->getValue(); + } +} + +//static +void LLFloaterModelPreview::onPhysicsStageExecute(LLUICtrl* ctrl, void* data) +{ + LLCDStageData* stage = (LLCDStageData*) data; + + LLModel* mdl = NULL; + + if (sInstance) + { + if (sInstance->mCurRequest.notNull()) + { + llinfos << "Decomposition request still pending." << llendl; + return; + } + + if (sInstance->mModelPreview) + { + if (sInstance->mDecompFloater) + { + S32 idx = sInstance->mDecompFloater->childGetValue("model").asInteger(); + if (idx >= 0 && idx < sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS].size()) + { + mdl = sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS][idx]; + } + } + } + } + + if (mdl) + { + sInstance->mCurRequest = new DecompRequest(stage->mName, mdl); + gMeshRepo.mDecompThread->submitRequest(sInstance->mCurRequest); + } +} + +//static +void LLFloaterModelPreview::onPhysicsStageCancel(LLUICtrl* ctrl, void*data) +{ + if (sInstance && sInstance->mCurRequest.notNull()) + { + sInstance->mCurRequest->mContinue = 0; + } +} + +void LLFloaterModelPreview::showDecompFloater() +{ + if (!mDecompFloater) + { + LLSD key; + mDecompFloater = new LLPhysicsDecompFloater(key); + + S32 left = 20; + S32 right = 320; + + S32 cur_y = 30; + + { + //add status text + LLTextBox::Params p; + p.name("status"); + p.rect(LLRect(left, cur_y, right-80, cur_y-20)); + mDecompFloater->addChild(LLUICtrlFactory::create(p)); + } + + + { //add cancel button + LLButton::Params p; + p.name("Cancel"); + p.label("Cancel"); + p.rect(LLRect(right-80, cur_y, right, cur_y-20)); + LLButton* button = LLUICtrlFactory::create(p); + button->setCommitCallback(onPhysicsStageCancel, NULL); + mDecompFloater->addChild(button); + } + + cur_y += 30; + + + static const LLCDStageData* stage = NULL; + static S32 stage_count = 0; + + if (!stage && LLConvexDecomposition::getInstance() != NULL) + { + stage_count = LLConvexDecomposition::getInstance()->getStages(&stage); + } + + static const LLCDParam* param = NULL; + static S32 param_count = 0; + if (!param && LLConvexDecomposition::getInstance() != NULL) + { + param_count = LLConvexDecomposition::getInstance()->getParameters(¶m); + } + + for (S32 j = stage_count-1; j >= 0; --j) + { + LLButton::Params p; + p.name(stage[j].mName); + p.label(stage[j].mName); + p.rect(LLRect(left, cur_y, right, cur_y-20)); + LLButton* button = LLUICtrlFactory::create(p); + button->setCommitCallback(onPhysicsStageExecute, (void*) &stage[j]); + mDecompFloater->addChild(button); + gMeshRepo.mDecompThread->mStageID[stage[j].mName] = j; + cur_y += 30; + // protected against stub by stage_count being 0 for stub above + LLConvexDecomposition::getInstance()->registerCallback(j, LLPhysicsDecomp::llcdCallback); + + llinfos << "Physics decomp stage " << stage[j].mName << " (" << j << ") parameters:" << llendl; + llinfos << "------------------------------------" << llendl; + + for (S32 i = 0; i < param_count; ++i) + { + if (param[i].mStage != j) + { + continue; + } + + std::string name(param[i].mName ? param[i].mName : ""); + std::string description(param[i].mDescription ? param[i].mDescription : ""); + + std::string type = "unknown"; + + llinfos << name << " - " << description << llendl; + + if (param[i].mType == LLCDParam::LLCD_FLOAT) + { + mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mFloat); + llinfos << "Type: float, Default: " << param[i].mDefault.mFloat << llendl; + + LLSliderCtrl::Params p; + p.name(name); + p.label(name); + p.rect(LLRect(left, cur_y, right, cur_y-20)); + p.min_value(param[i].mDetails.mRange.mLow.mFloat); + p.max_value(param[i].mDetails.mRange.mHigh.mFloat); + p.increment(param[i].mDetails.mRange.mDelta.mFloat); + p.tool_tip(description); + p.decimal_digits(3); + p.initial_value(param[i].mDefault.mFloat); + LLSliderCtrl* slider = LLUICtrlFactory::create(p); + slider->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); + mDecompFloater->addChild(slider); + cur_y += 30; + } + else if (param[i].mType == LLCDParam::LLCD_INTEGER) + { + mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue); + llinfos << "Type: integer, Default: " << param[i].mDefault.mIntOrEnumValue << llendl; + LLSliderCtrl::Params p; + p.name(name); + p.label(name); + p.rect(LLRect(left, cur_y, right, cur_y-20)); + p.min_value(param[i].mDetails.mRange.mLow.mIntOrEnumValue); + p.max_value(param[i].mDetails.mRange.mHigh.mIntOrEnumValue); + p.increment(param[i].mDetails.mRange.mDelta.mIntOrEnumValue); + p.tool_tip(description); + p.initial_value(param[i].mDefault.mIntOrEnumValue); + LLSliderCtrl* slider = LLUICtrlFactory::create(p); + slider->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); + mDecompFloater->addChild(slider); + cur_y += 30; + } + else if (param[i].mType == LLCDParam::LLCD_BOOLEAN) + { + mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mBool); + llinfos << "Type: boolean, Default: " << (param[i].mDefault.mBool ? "True" : "False") << llendl; + + LLCheckBoxCtrl::Params p; + p.rect(LLRect(left, cur_y, right, cur_y-20)); + p.name(name); + p.label(name); + p.initial_value(param[i].mDefault.mBool); + p.tool_tip(description); + LLCheckBoxCtrl* check_box = LLUICtrlFactory::create(p); + check_box->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); + mDecompFloater->addChild(check_box); + cur_y += 30; + } + else if (param[i].mType == LLCDParam::LLCD_ENUM) + { + S32 cur_x = left; + mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue); + llinfos << "Type: enum, Default: " << param[i].mDefault.mIntOrEnumValue << llendl; + + { //add label + LLTextBox::Params p; + const LLFontGL* font = (LLFontGL*) p.font(); + + p.rect(LLRect(left, cur_y, left+font->getWidth(name), cur_y-20)); + p.name(name); + p.label(name); + p.initial_value(name); + LLTextBox* text_box = LLUICtrlFactory::create(p); + mDecompFloater->addChild(text_box); + cur_x += text_box->getRect().getWidth(); + } + + { //add combo_box + LLComboBox::Params p; + p.rect(LLRect(cur_x, cur_y, right-right/4, cur_y-20)); + p.name(name); + p.label(name); + p.tool_tip(description); + + llinfos << "Accepted values: " << llendl; + LLComboBox* combo_box = LLUICtrlFactory::create(p); + for (S32 k = 0; k < param[i].mDetails.mEnumValues.mNumEnums; ++k) + { + llinfos << param[i].mDetails.mEnumValues.mEnumsArray[k].mValue + << " - " << param[i].mDetails.mEnumValues.mEnumsArray[k].mName << llendl; + + combo_box->add(param[i].mDetails.mEnumValues.mEnumsArray[k].mName, + LLSD::Integer(param[i].mDetails.mEnumValues.mEnumsArray[k].mValue)); + } + combo_box->setValue(param[i].mDefault.mIntOrEnumValue); + combo_box->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); + mDecompFloater->addChild(combo_box); + cur_y += 30; + + } + + llinfos << "----" << llendl; + } + llinfos << "-----------------------------" << llendl; + } + } + + cur_y += 30; + //explode slider + { + LLSliderCtrl::Params p; + p.initial_value(0); + p.min_value(0); + p.max_value(1); + p.decimal_digits(2); + p.increment(0.05f); + p.label("Explode"); + p.name("explode"); + p.rect(LLRect(left, cur_y, right, cur_y-20)); + LLSliderCtrl* slider = LLUICtrlFactory::create(p); + + mDecompFloater->addChild(slider); + cur_y += 30; + } + + //mesh render checkbox + { + LLCheckBoxCtrl::Params p; + p.label("Mesh: "); + p.name("render_mesh"); + p.rect(LLRect(left, cur_y, right/4, cur_y-20)); + LLCheckBoxCtrl* check = LLUICtrlFactory::create(p); + check->setValue(true); + mDecompFloater->addChild(check); + } + + //hull render checkbox + { + LLCheckBoxCtrl::Params p; + p.label("Hull: "); + p.name("render_hull"); + p.rect(LLRect(right/4, cur_y, right/2, cur_y-20)); + LLCheckBoxCtrl* check = LLUICtrlFactory::create(p); + check->setValue(true); + mDecompFloater->addChild(check); + } + + { //submesh combo box label + LLTextBox::Params p; + p.label("Model"); + p.name("model label"); + p.rect(LLRect(right/2, cur_y, right-right/3, cur_y-20)); + LLTextBox* text_box = LLUICtrlFactory::create(p); + text_box->setValue("Model"); + mDecompFloater->addChild(text_box); + } + + { + //add submesh combo box + LLComboBox::Params p; + p.rect(LLRect(right-right/2+p.font()->getWidth("Model"), cur_y, right, cur_y-20)); + p.name("model"); + LLComboBox* combo_box = LLUICtrlFactory::create(p); + for (S32 i = 0; i < mModelPreview->mBaseModel.size(); ++i) + { + LLModel* mdl = mModelPreview->mBaseModel[i]; + combo_box->add(mdl->mLabel, i); + } + combo_box->setValue(0); + mDecompFloater->addChild(combo_box); + cur_y += 30; + } + + mDecompFloater->childSetCommitCallback("model", LLFloaterModelPreview::refresh, LLFloaterModelPreview::sInstance); + mDecompFloater->childSetCommitCallback("render_mesh", LLFloaterModelPreview::refresh, LLFloaterModelPreview::sInstance); + mDecompFloater->childSetCommitCallback("render_hull", LLFloaterModelPreview::refresh, LLFloaterModelPreview::sInstance); + + mDecompFloater->setRect(LLRect(10, cur_y+20, right+20, 10)); + } + + mDecompFloater->childSetCommitCallback("explode", LLFloaterModelPreview::onExplodeCommit, this); + + mDecompFloater->openFloater(); +} + +//----------------------------------------------------------------------------- +// onMouseCaptureLost() +//----------------------------------------------------------------------------- +// static +void LLFloaterModelPreview::onMouseCaptureLostModelPreview(LLMouseHandler* handler) +{ + gViewerWindow->showCursor(); +} + +//----------------------------------------------------------------------------- +// LLModelLoader +//----------------------------------------------------------------------------- +LLModelLoader::LLModelLoader(std::string filename, S32 lod, LLModelPreview* preview) +: LLThread("Model Loader"), mFilename(filename), mLod(lod), mPreview(preview), mState(STARTING), mFirstTransform(TRUE) +{ + mJointMap["mPelvis"] = "mPelvis"; + mJointMap["mTorso"] = "mTorso"; + mJointMap["mChest"] = "mChest"; + mJointMap["mNeck"] = "mNeck"; + mJointMap["mHead"] = "mHead"; + mJointMap["mSkull"] = "mSkull"; + mJointMap["mEyeRight"] = "mEyeRight"; + mJointMap["mEyeLeft"] = "mEyeLeft"; + mJointMap["mCollarLeft"] = "mCollarLeft"; + mJointMap["mShoulderLeft"] = "mShoulderLeft"; + mJointMap["mElbowLeft"] = "mElbowLeft"; + mJointMap["mWristLeft"] = "mWristLeft"; + mJointMap["mCollarRight"] = "mCollarRight"; + mJointMap["mShoulderRight"] = "mShoulderRight"; + mJointMap["mElbowRight"] = "mElbowRight"; + mJointMap["mWristRight"] = "mWristRight"; + mJointMap["mHipRight"] = "mHipRight"; + mJointMap["mKneeRight"] = "mKneeRight"; + mJointMap["mAnkleRight"] = "mAnkleRight"; + mJointMap["mFootRight"] = "mFootRight"; + mJointMap["mToeRight"] = "mToeRight"; + mJointMap["mHipLeft"] = "mHipLeft"; + mJointMap["mKneeLeft"] = "mKneeLeft"; + mJointMap["mAnkleLeft"] = "mAnkleLeft"; + mJointMap["mFootLeft"] = "mFootLeft"; + mJointMap["mToeLeft"] = "mToeLeft"; + + mJointMap["avatar_mPelvis"] = "mPelvis"; + mJointMap["avatar_mTorso"] = "mTorso"; + mJointMap["avatar_mChest"] = "mChest"; + mJointMap["avatar_mNeck"] = "mNeck"; + mJointMap["avatar_mHead"] = "mHead"; + mJointMap["avatar_mSkull"] = "mSkull"; + mJointMap["avatar_mEyeRight"] = "mEyeRight"; + mJointMap["avatar_mEyeLeft"] = "mEyeLeft"; + mJointMap["avatar_mCollarLeft"] = "mCollarLeft"; + mJointMap["avatar_mShoulderLeft"] = "mShoulderLeft"; + mJointMap["avatar_mElbowLeft"] = "mElbowLeft"; + mJointMap["avatar_mWristLeft"] = "mWristLeft"; + mJointMap["avatar_mCollarRight"] = "mCollarRight"; + mJointMap["avatar_mShoulderRight"] = "mShoulderRight"; + mJointMap["avatar_mElbowRight"] = "mElbowRight"; + mJointMap["avatar_mWristRight"] = "mWristRight"; + mJointMap["avatar_mHipRight"] = "mHipRight"; + mJointMap["avatar_mKneeRight"] = "mKneeRight"; + mJointMap["avatar_mAnkleRight"] = "mAnkleRight"; + mJointMap["avatar_mFootRight"] = "mFootRight"; + mJointMap["avatar_mToeRight"] = "mToeRight"; + mJointMap["avatar_mHipLeft"] = "mHipLeft"; + mJointMap["avatar_mKneeLeft"] = "mKneeLeft"; + mJointMap["avatar_mAnkleLeft"] = "mAnkleLeft"; + mJointMap["avatar_mFootLeft"] = "mFootLeft"; + mJointMap["avatar_mToeLeft"] = "mToeLeft"; + + + mJointMap["hip"] = "mPelvis"; + mJointMap["abdomen"] = "mTorso"; + mJointMap["chest"] = "mChest"; + mJointMap["neck"] = "mNeck"; + mJointMap["head"] = "mHead"; + mJointMap["figureHair"] = "mSkull"; + mJointMap["lCollar"] = "mCollarLeft"; + mJointMap["lShldr"] = "mShoulderLeft"; + mJointMap["lForeArm"] = "mElbowLeft"; + mJointMap["lHand"] = "mWristLeft"; + mJointMap["rCollar"] = "mCollarRight"; + mJointMap["rShldr"] = "mShoulderRight"; + mJointMap["rForeArm"] = "mElbowRight"; + mJointMap["rHand"] = "mWristRight"; + mJointMap["rThigh"] = "mHipRight"; + mJointMap["rShin"] = "mKneeRight"; + mJointMap["rFoot"] = "mFootRight"; + mJointMap["lThigh"] = "mHipLeft"; + mJointMap["lShin"] = "mKneeLeft"; + mJointMap["lFoot"] = "mFootLeft"; +} + +void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, BOOL& first_transform) +{ + LLVector4a box[] = + { + LLVector4a(-1, 1,-1), + LLVector4a(-1, 1, 1), + LLVector4a(-1,-1,-1), + LLVector4a(-1,-1, 1), + LLVector4a( 1, 1,-1), + LLVector4a( 1, 1, 1), + LLVector4a( 1,-1,-1), + LLVector4a( 1,-1, 1), + }; + + for (S32 j = 0; j < model->getNumVolumeFaces(); ++j) + { + const LLVolumeFace& face = model->getVolumeFace(j); + + LLVector4a center; + center.setAdd(face.mExtents[0], face.mExtents[1]); + center.mul(0.5f); + LLVector4a size; + size.setSub(face.mExtents[1],face.mExtents[0]); + size.mul(0.5f); + + for (U32 i = 0; i < 8; i++) + { + LLVector4a t; + t.setMul(size, box[i]); + t.add(center); + + LLVector4a v; + + mat.affineTransform(t, v); + + if (first_transform) + { + first_transform = FALSE; + min = max = v; + } + else + { + update_min_max(min, max, v); + } + } + } +} + +void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& max, BOOL& first_transform) +{ + LLVector4a mina, maxa; + LLMatrix4a mata; + + mata.loadu(mat); + mina.load3(min.mV); + maxa.load3(max.mV); + + stretch_extents(model, mata, mina, maxa, first_transform); + + min.set(mina.getF32ptr()); + max.set(maxa.getF32ptr()); +} + +void LLModelLoader::run() +{ + DAE dae; + domCOLLADA* dom = dae.open(mFilename); + + if (dom) + { + daeDatabase* db = dae.getDatabase(); + + daeInt count = db->getElementCount(NULL, COLLADA_TYPE_MESH); + + daeDocument* doc = dae.getDoc(mFilename); + if (!doc) + { + llwarns << "can't find internal doc" << llendl; + return; + } + + daeElement* root = doc->getDomRoot(); + if (!root) + { + llwarns << "document has no root" << llendl; + return; + } + + //get unit scale + mTransform.setIdentity(); + + domAsset::domUnit* unit = daeSafeCast(root->getDescendant(daeElement::matchType(domAsset::domUnit::ID()))); + + if (unit) + { + F32 meter = unit->getMeter(); + mTransform.mMatrix[0][0] = meter; + mTransform.mMatrix[1][1] = meter; + mTransform.mMatrix[2][2] = meter; + } + + //get up axis rotation + LLMatrix4 rotation; + + domUpAxisType up = UPAXISTYPE_Y_UP; // default is Y_UP + domAsset::domUp_axis* up_axis = + daeSafeCast(root->getDescendant(daeElement::matchType(domAsset::domUp_axis::ID()))); + + if (up_axis) + { + up = up_axis->getValue(); + } + + if (up == UPAXISTYPE_X_UP) + { + rotation.initRotation(0.0f, 90.0f * DEG_TO_RAD, 0.0f); + } + else if (up == UPAXISTYPE_Y_UP) + { + rotation.initRotation(90.0f * DEG_TO_RAD, 0.0f, 0.0f); + } + + rotation *= mTransform; + mTransform = rotation; + + + for (daeInt idx = 0; idx < count; ++idx) + { //build map of domEntities to LLModel + domMesh* mesh = NULL; + db->getElement((daeElement**) &mesh, idx, NULL, COLLADA_TYPE_MESH); + + if (mesh) + { + LLPointer model = LLModel::loadModelFromDomMesh(mesh); + + if (model.notNull() && validate_model(model)) + { + mModelList.push_back(model); + mModel[mesh] = model; + } + } + } + + count = db->getElementCount(NULL, COLLADA_TYPE_SKIN); + for (daeInt idx = 0; idx < count; ++idx) + { //add skinned meshes as instances + domSkin* skin = NULL; + db->getElement((daeElement**) &skin, idx, NULL, COLLADA_TYPE_SKIN); + + if (skin) + { + domGeometry* geom = daeSafeCast(skin->getSource().getElement()); + + if (geom) + { + domMesh* mesh = geom->getMesh(); + if (mesh) + { + LLModel* model = mModel[mesh]; + if (model) + { + LLVector3 mesh_scale_vector; + LLVector3 mesh_translation_vector; + model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); + + LLMatrix4 normalized_transformation; + normalized_transformation.setTranslation(mesh_translation_vector); + + LLMatrix4 mesh_scale; + mesh_scale.initScale(mesh_scale_vector); + mesh_scale *= normalized_transformation; + normalized_transformation = mesh_scale; + + glh::matrix4f inv_mat((F32*) normalized_transformation.mMatrix); + inv_mat = inv_mat.inverse(); + LLMatrix4 inverse_normalized_transformation(inv_mat.m); + + domSkin::domBind_shape_matrix* bind_mat = skin->getBind_shape_matrix(); + + if (bind_mat) + { //get bind shape matrix + domFloat4x4& dom_value = bind_mat->getValue(); + + for (int i = 0; i < 4; i++) + { + for(int j = 0; j < 4; j++) + { + model->mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j*4]; + } + } + + LLMatrix4 trans = normalized_transformation; + trans *= model->mBindShapeMatrix; + model->mBindShapeMatrix = trans; + + } + + /*{ + LLMatrix4 rotation; + if (up == UPAXISTYPE_X_UP) + { + rotation.initRotation(0.0f, 90.0f * DEG_TO_RAD, 0.0f); + } + else if (up == UPAXISTYPE_Z_UP) + { + rotation.initRotation(90.0f * DEG_TO_RAD, 90.0f * DEG_TO_RAD, 0.0f); + } + + rotation *= model->mBindShapeMatrix; + model->mBindShapeMatrix = rotation; + }*/ + + //The joint transfom map that we'll populate below + std::map jointTransforms; + jointTransforms.clear(); + + //Some collada setup for accessing the skeleton + daeElement* pElement = 0; + dae.getDatabase()->getElement( &pElement, 0, 0, "skeleton" ); + domInstance_controller::domSkeleton* pSkeleton = daeSafeCast( pElement ); + if ( pSkeleton ) + { + //Get the root node of the skeleton + daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement(); + if ( pSkeletonRootNode ) + { + //Once we have the root node - start acccessing it's joint components + const int jointCnt = mJointMap.size(); + std::map :: const_iterator jointIt = mJointMap.begin(); + bool missingID = false; + //Loop over all the possible joints within the .dae - using the allowed joint list in the ctor. + for ( int i=0; i( resolver.getElement() ); + if ( pJoint ) + { + //Pull out the translate id and store it in the jointTranslations map + daeSIDResolver jointResolver( pJoint, "./translate" ); + domTranslate* pTranslate = daeSafeCast( jointResolver.getElement() ); + + LLMatrix4 workingTransform; + + //Translation via SID + if ( pTranslate ) + { + domFloat3 jointTrans = pTranslate->getValue(); + LLVector3 singleJointTranslation( jointTrans[0], jointTrans[1], jointTrans[2] ); + workingTransform.setTranslation( singleJointTranslation ); + } + else + { + //Translation via child from element + daeElement* pTranslateElement = getChildFromElement( pJoint, "translate" ); + if ( pTranslateElement && pTranslateElement->typeID() != domTranslate::ID() ) + { + llwarns<< "The found element is not a translate node" <( pTranslateElement ); + domFloat3 translateChild = pTranslateChild->getValue(); + LLVector3 singleJointTranslation( translateChild[0], translateChild[1], translateChild[2] ); + workingTransform.setTranslation( singleJointTranslation ); + } + } + //Store the joint transform w/respect to it's name. + jointTransforms[(*jointIt).second.c_str()] = workingTransform; + } + } + + //If anything failed in regards to extracting the skeleton, joints or translation id, + //mention it + if ( missingID ) + { + llwarns<< "Partial jointmap found in asset - did you mean to just have a partial map?" << llendl; + } + + //Set the joint translations on the avatar + //The joints are reset in the dtor + jointIt = mJointMap.begin(); + for ( int i=0; igetJoint( lookingForJoint ); + if ( pJoint ) + { + pJoint->storeCurrentXform( jointTransform.getTranslation() ); + } + else + { + //Most likely an error in the asset. + llwarns<<"Tried to apply joint position from .dae, but it did not exist in the avatar rig." << llendl; + } + //Reposition the avatars pelvis (avPos+offset) + //if ( !strcmp( (*jointIt).first.c_str(),"mPelvis" ) ) + if ( lookingForJoint == "mPelvis" ) + { + const LLVector3& pos = gAgentAvatarp->getCharacterPosition(); + gAgentAvatarp->setPelvisOffset( true, jointTransform.getTranslation() ); + gAgentAvatarp->setPosition( pos + jointTransform.getTranslation() ); + } + } + } + } + else + { + llwarns<<"No root node in this skeleton" << llendl; + } + } + else + { + llwarns<<"No skeleton in this asset" << llendl; + } + + domSkin::domJoints* joints = skin->getJoints(); + + domInputLocal_Array& joint_input = joints->getInput_array(); + + for (size_t i = 0; i < joint_input.getCount(); ++i) + { + domInputLocal* input = joint_input.get(i); + xsNMTOKEN semantic = input->getSemantic(); + + if (strcmp(semantic, COMMON_PROFILE_INPUT_JOINT) == 0) + { //found joint source, fill model->mJointMap and model->mJointList + daeElement* elem = input->getSource().getElement(); + + domSource* source = daeSafeCast(elem); + if (source) + { + + + domName_array* names_source = source->getName_array(); + + if (names_source) + { + domListOfNames &names = names_source->getValue(); + + for (size_t j = 0; j < names.getCount(); ++j) + { + std::string name(names.get(j)); + if (mJointMap.find(name) != mJointMap.end()) + { + name = mJointMap[name]; + } + model->mJointList.push_back(name); + model->mJointMap[name] = j; + } + } + else + { + domIDREF_array* names_source = source->getIDREF_array(); + if (names_source) + { + xsIDREFS& names = names_source->getValue(); + + for (size_t j = 0; j < names.getCount(); ++j) + { + std::string name(names.get(j).getID()); + if (mJointMap.find(name) != mJointMap.end()) + { + name = mJointMap[name]; + } + model->mJointList.push_back(name); + model->mJointMap[name] = j; + } + } + } + } + } + else if (strcmp(semantic, COMMON_PROFILE_INPUT_INV_BIND_MATRIX) == 0) + { //found inv_bind_matrix array, fill model->mInvBindMatrix + domSource* source = daeSafeCast(input->getSource().getElement()); + if (source) + { + domFloat_array* t = source->getFloat_array(); + if (t) + { + domListOfFloats& transform = t->getValue(); + S32 count = transform.getCount()/16; + + for (S32 k = 0; k < count; ++k) + { + LLMatrix4 mat; + + for (int i = 0; i < 4; i++) + { + for(int j = 0; j < 4; j++) + { + mat.mMatrix[i][j] = transform[k*16 + i + j*4]; + } + } + + model->mInvBindMatrix.push_back(mat); + } + } + } + } + } + + //We need to construct the alternate bind matrix (which contains the new joint positions) + //in the same order as they were stored in the joint buffer. The joints associated + //with the skeleton are not stored in the same order as they are in the exported joint buffer. + //This remaps the skeletal joints to be in the same order as the joints stored in the model. + std::vector :: const_iterator jointIt = model->mJointList.begin(); + const int jointCnt = model->mJointList.size(); + for ( int i=0; imInvBindMatrix[i]; + newInverse.setTranslation( jointTransforms[lookingForJoint].getTranslation() ); + model->mAlternateBindMatrix.push_back( newInverse ); + } + else + { + llwarns<<"Possibly misnamed/missing joint [" <getVertices(); + if (verts) + { + domInputLocal_Array& inputs = verts->getInput_array(); + for (size_t i = 0; i < inputs.getCount() && model->mPosition.empty(); ++i) + { + if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_POSITION) == 0) + { + domSource* pos_source = daeSafeCast(inputs[i]->getSource().getElement()); + if (pos_source) + { + domFloat_array* pos_array = pos_source->getFloat_array(); + if (pos_array) + { + domListOfFloats& pos = pos_array->getValue(); + + for (size_t j = 0; j < pos.getCount(); j += 3) + { + if (pos.getCount() <= j+2) + { + llerrs << "WTF?" << llendl; + } + + LLVector3 v(pos[j], pos[j+1], pos[j+2]); + + //transform from COLLADA space to volume space + v = v * inverse_normalized_transformation; + + model->mPosition.push_back(v); + } + } + } + } + } + } + + //grab skin weights array + domSkin::domVertex_weights* weights = skin->getVertex_weights(); + if (weights) + { + domInputLocalOffset_Array& inputs = weights->getInput_array(); + domFloat_array* vertex_weights = NULL; + for (size_t i = 0; i < inputs.getCount(); ++i) + { + if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_WEIGHT) == 0) + { + domSource* weight_source = daeSafeCast(inputs[i]->getSource().getElement()); + if (weight_source) + { + vertex_weights = weight_source->getFloat_array(); + } + } + } + + if (vertex_weights) + { + domListOfFloats& w = vertex_weights->getValue(); + domListOfUInts& vcount = weights->getVcount()->getValue(); + domListOfInts& v = weights->getV()->getValue(); + + U32 c_idx = 0; + for (size_t vc_idx = 0; vc_idx < vcount.getCount(); ++vc_idx) + { //for each vertex + daeUInt count = vcount[vc_idx]; + + //create list of weights that influence this vertex + LLModel::weight_list weight_list; + + for (daeUInt i = 0; i < count; ++i) + { //for each weight + daeInt joint_idx = v[c_idx++]; + daeInt weight_idx = v[c_idx++]; + + if (joint_idx == -1) + { + //ignore bindings to bind_shape_matrix + continue; + } + + F32 weight_value = w[weight_idx]; + + weight_list.push_back(LLModel::JointWeight(joint_idx, weight_value)); + } + + //sort by joint weight + std::sort(weight_list.begin(), weight_list.end(), LLModel::CompareWeightGreater()); + + std::vector wght; + + F32 total = 0.f; + + for (U32 i = 0; i < llmin((U32) 4, (U32) weight_list.size()); ++i) + { //take up to 4 most significant weights + if (weight_list[i].mWeight > 0.f) + { + wght.push_back( weight_list[i] ); + total += weight_list[i].mWeight; + } + } + + F32 scale = 1.f/total; + if (scale != 1.f) + { //normalize weights + for (U32 i = 0; i < wght.size(); ++i) + { + wght[i].mWeight *= scale; + } + } + + model->mSkinWeights[model->mPosition[vc_idx]] = wght; + } + + //add instance to scene for this model + + LLMatrix4 transform; + std::vector materials; + materials.resize(model->getNumVolumeFaces()); + mScene[transform].push_back(LLModelInstance(model, transform, materials)); + stretch_extents(model, transform, mExtents[0], mExtents[1], mFirstTransform); + } + } + } + } + } + } + } + + daeElement* scene = root->getDescendant("visual_scene"); + if (!scene) + { + llwarns << "document has no visual_scene" << llendl; + return; + } + + processElement(scene); + + mPreview->loadModelCallback(mLod); + } +} + +daeElement* LLModelLoader::getChildFromElement( daeElement* pElement, std::string const & name ) +{ + daeElement* pChildOfElement = pElement->getChild( name.c_str() ); + if ( pChildOfElement ) + { + return pChildOfElement; + } + llwarns<< "Could not find a child [" << name << "] for the element: \"" << pElement->getAttribute("id") << "\"" << llendl; + return NULL; +} + +void LLModelLoader::processElement(daeElement* element) +{ + LLMatrix4 saved_transform = mTransform; + + domTranslate* translate = daeSafeCast(element); + if (translate) + { + domFloat3 dom_value = translate->getValue(); + + LLMatrix4 translation; + translation.setTranslation(LLVector3(dom_value[0], dom_value[1], dom_value[2])); + + translation *= mTransform; + mTransform = translation; + } + + domRotate* rotate = daeSafeCast(element); + if (rotate) + { + domFloat4 dom_value = rotate->getValue(); + + LLMatrix4 rotation; + rotation.initRotTrans(dom_value[3] * DEG_TO_RAD, LLVector3(dom_value[0], dom_value[1], dom_value[2]), LLVector3(0, 0, 0)); + + rotation *= mTransform; + mTransform = rotation; + } + + domScale* scale = daeSafeCast(element); + if (scale) + { + domFloat3 dom_value = scale->getValue(); + + LLMatrix4 scaling; + scaling.initScale(LLVector3(dom_value[0], dom_value[1], dom_value[2])); + + scaling *= mTransform; + mTransform = scaling; + } + + domMatrix* matrix = daeSafeCast(element); + if (matrix) + { + domFloat4x4 dom_value = matrix->getValue(); + + LLMatrix4 matrix_transform; + + for (int i = 0; i < 4; i++) + { + for(int j = 0; j < 4; j++) + { + matrix_transform.mMatrix[i][j] = dom_value[i + j*4]; + } + } + + matrix_transform *= mTransform; + mTransform = matrix_transform; + } + + domInstance_geometry* instance_geo = daeSafeCast(element); + if (instance_geo) + { + domGeometry* geo = daeSafeCast(instance_geo->getUrl().getElement()); + if (geo) + { + domMesh* mesh = daeSafeCast(geo->getDescendant(daeElement::matchType(domMesh::ID()))); + if (mesh) + { + LLModel* model = mModel[mesh]; + if (model) + { + LLMatrix4 transformation = mTransform; + + std::vector materials = getMaterials(model, instance_geo); + + // adjust the transformation to compensate for mesh normalization + LLVector3 mesh_scale_vector; + LLVector3 mesh_translation_vector; + model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); + + LLMatrix4 mesh_translation; + mesh_translation.setTranslation(mesh_translation_vector); + mesh_translation *= transformation; + transformation = mesh_translation; + + LLMatrix4 mesh_scale; + mesh_scale.initScale(mesh_scale_vector); + mesh_scale *= transformation; + transformation = mesh_scale; + + mScene[transformation].push_back(LLModelInstance(model, transformation, materials)); + + stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); + } + } + } + } + + domInstance_node* instance_node = daeSafeCast(element); + if (instance_node) + { + daeElement* instance = instance_node->getUrl().getElement(); + if (instance) + { + processElement(instance); + } + } + + //process children + daeTArray< daeSmartRef > children = element->getChildren(); + for (S32 i = 0; i < children.getCount(); i++) + { + processElement(children[i]); + } + + domNode* node = daeSafeCast(element); + if (node) + { //this element was a node, restore transform before processiing siblings + mTransform = saved_transform; + } +} + +std::vector LLModelLoader::getMaterials(LLModel* model, domInstance_geometry* instance_geo) +{ + std::vector materials; + for (int i = 0; i < model->mMaterialList.size(); i++) + { + LLImportMaterial import_material; + + domInstance_material* instance_mat = NULL; + + domBind_material::domTechnique_common* technique = + daeSafeCast(instance_geo->getDescendant(daeElement::matchType(domBind_material::domTechnique_common::ID()))); + + if (technique) + { + daeTArray< daeSmartRef > inst_materials = technique->getChildrenByType(); + for (int j = 0; j < inst_materials.getCount(); j++) + { + std::string symbol(inst_materials[j]->getSymbol()); + + if (symbol == model->mMaterialList[i]) // found the binding + { + instance_mat = inst_materials[j]; + } + } + } + + if (instance_mat) + { + domMaterial* material = daeSafeCast(instance_mat->getTarget().getElement()); + if (material) + { + domInstance_effect* instance_effect = + daeSafeCast(material->getDescendant(daeElement::matchType(domInstance_effect::ID()))); + if (instance_effect) + { + domEffect* effect = daeSafeCast(instance_effect->getUrl().getElement()); + if (effect) + { + domProfile_COMMON* profile = + daeSafeCast(effect->getDescendant(daeElement::matchType(domProfile_COMMON::ID()))); + if (profile) + { + import_material = profileToMaterial(profile); + } + } + } + } + } + + materials.push_back(import_material); + } + + return materials; +} + +LLImportMaterial LLModelLoader::profileToMaterial(domProfile_COMMON* material) +{ + LLImportMaterial mat; + mat.mFullbright = FALSE; + + daeElement* diffuse = material->getDescendant("diffuse"); + if (diffuse) + { + domCommon_color_or_texture_type_complexType::domTexture* texture = + daeSafeCast(diffuse->getDescendant("texture")); + if (texture) + { + domCommon_newparam_type_Array newparams = material->getNewparam_array(); + for (S32 i = 0; i < newparams.getCount(); i++) + { + domFx_surface_common* surface = newparams[i]->getSurface(); + if (surface) + { + domFx_surface_init_common* init = surface->getFx_surface_init_common(); + if (init) + { + domFx_surface_init_from_common_Array init_from = init->getInit_from_array(); + + if (init_from.getCount() > i) + { + domImage* image = daeSafeCast(init_from[i]->getValue().getElement()); + if (image) + { + // we only support init_from now - embedded data will come later + domImage::domInit_from* init = image->getInit_from(); + if (init) + { + std::string filename = cdom::uriToNativePath(init->getValue().str()); + + mat.mDiffuseMap = LLViewerTextureManager::getFetchedTextureFromUrl("file://" + filename, TRUE, LLViewerTexture::BOOST_PREVIEW); + mat.mDiffuseMap->setLoadedCallback(LLModelPreview::textureLoadedCallback, 0, TRUE, FALSE, this->mPreview, NULL, FALSE); + + mat.mDiffuseMap->forceToSaveRawImage(); + mat.mDiffuseMapFilename = filename; + mat.mDiffuseMapLabel = getElementLabel(material); + } + } + } + } + } + } + } + + domCommon_color_or_texture_type_complexType::domColor* color = + daeSafeCast(diffuse->getDescendant("color")); + if (color) + { + domFx_color_common domfx_color = color->getValue(); + LLColor4 value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]); + mat.mDiffuseColor = value; + } + } + + daeElement* emission = material->getDescendant("emission"); + if (emission) + { + LLColor4 emission_color = getDaeColor(emission); + if (((emission_color[0] + emission_color[1] + emission_color[2]) / 3.0) > 0.25) + { + mat.mFullbright = TRUE; + } + } + + return mat; +} + +// try to get a decent label for this element +std::string LLModelLoader::getElementLabel(daeElement *element) +{ + // if we have a name attribute, use it + std::string name = element->getAttribute("name"); + if (name.length()) + { + return name; + } + + // if we have an ID attribute, use it + if (element->getID()) + { + return std::string(element->getID()); + } + + // if we have a parent, use it + daeElement* parent = element->getParent(); + if (parent) + { + // if parent has a name, use it + std::string name = parent->getAttribute("name"); + if (name.length()) + { + return name; + } + + // if parent has an ID, use it + if (parent->getID()) + { + return std::string(parent->getID()); + } + } + + // try to use our type + daeString element_name = element->getElementName(); + if (element_name) + { + return std::string(element_name); + } + + // if all else fails, use "object" + return std::string("object"); +} + +LLColor4 LLModelLoader::getDaeColor(daeElement* element) +{ + LLColor4 value; + domCommon_color_or_texture_type_complexType::domColor* color = + daeSafeCast(element->getDescendant("color")); + if (color) + { + domFx_color_common domfx_color = color->getValue(); + value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]); + } + + return value; +} + +//----------------------------------------------------------------------------- +// LLModelPreview +//----------------------------------------------------------------------------- + +LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloaterModelPreview* fmp) +: LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE), LLMutex(NULL) +{ + mNeedsUpdate = TRUE; + mCameraDistance = 0.f; + mCameraYaw = 0.f; + mCameraPitch = 0.f; + mCameraZoom = 1.f; + mTextureName = 0; + mPreviewLOD = 3; + mModelLoader = NULL; + mDirty = false; + + for (U32 i = 0; i < LLModel::NUM_LODS; i++) + { + mLODMode[i] = 1; + mLimit[i] = 0; + } + + mLODMode[0] = 0; + + mFMP = fmp; + + glodInit(); +} + +LLModelPreview::~LLModelPreview() +{ + if (mModelLoader) + { + delete mModelLoader; + mModelLoader = NULL; + } + + //*HACK : *TODO : turn this back on when we understand why this crashes + //glodShutdown(); +} + +U32 LLModelPreview::calcResourceCost() +{ + rebuildUploadData(); + + U32 cost = 0; + std::set accounted; + U32 num_points = 0; + U32 num_hulls = 0; + + F32 debug_scale = mFMP->childGetValue("debug scale").asReal(); + + F32 streaming_cost = 0.f; + + for (U32 i = 0; i < mUploadData.size(); ++i) + { + LLModelInstance& instance = mUploadData[i]; + + if (accounted.find(instance.mModel) == accounted.end()) + { + accounted.insert(instance.mModel); + + LLModel::convex_hull_decomposition& decomp = + instance.mLOD[LLModel::LOD_PHYSICS] ? + instance.mLOD[LLModel::LOD_PHYSICS]->mConvexHullDecomp : + instance.mModel->mConvexHullDecomp; + + LLSD ret = LLModel::writeModel( + "", + instance.mLOD[4], + instance.mLOD[3], + instance.mLOD[2], + instance.mLOD[1], + instance.mLOD[0], + decomp, + mFMP->childGetValue("upload_skin").asBoolean(), + mFMP->childGetValue("upload_joints").asBoolean(), + TRUE); + cost += gMeshRepo.calcResourceCost(ret); + + num_hulls += decomp.size(); + for (U32 i = 0; i < decomp.size(); ++i) + { + num_points += decomp[i].size(); + } + + //calculate streaming cost + LLMatrix4 transformation = instance.mTransform; + + LLVector3 position = LLVector3(0, 0, 0) * transformation; + + LLVector3 x_transformed = LLVector3(1, 0, 0) * transformation - position; + LLVector3 y_transformed = LLVector3(0, 1, 0) * transformation - position; + LLVector3 z_transformed = LLVector3(0, 0, 1) * transformation - position; + F32 x_length = x_transformed.normalize(); + F32 y_length = y_transformed.normalize(); + F32 z_length = z_transformed.normalize(); + LLVector3 scale = LLVector3(x_length, y_length, z_length); + + F32 radius = scale.length()*debug_scale; + + streaming_cost += LLMeshRepository::getStreamingCost(ret, radius); + } + } + + mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[HULLS]", llformat("%d",num_hulls)); + mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[POINTS]", llformat("%d",num_points)); + mFMP->childSetTextArg("streaming cost", "[COST]", llformat("%.3f", streaming_cost)); + F32 scale = mFMP->childGetValue("debug scale").asReal()*2.f; + mFMP->childSetTextArg("dimensions", "[X]", llformat("%.3f", mPreviewScale[0]*scale)); + mFMP->childSetTextArg("dimensions", "[Y]", llformat("%.3f", mPreviewScale[1]*scale)); + mFMP->childSetTextArg("dimensions", "[Z]", llformat("%.3f", mPreviewScale[2]*scale)); + + updateStatusMessages(); + + return cost; +} + +void LLModelPreview::rebuildUploadData() +{ + mUploadData.clear(); + mTextureSet.clear(); + + //fill uploaddata instance vectors from scene data + + LLSpinCtrl* scale_spinner = mFMP->getChild("debug scale"); + + if (!scale_spinner) + { + llerrs << "floater_model_preview.xml MUST contain debug scale spinner." << llendl; + } + + F32 scale = scale_spinner->getValue().asReal(); + + LLMatrix4 scale_mat; + scale_mat.initScale(LLVector3(scale, scale, scale)); + + F32 max_scale = 0.f; + + for (LLModelLoader::scene::iterator iter = mBaseScene.begin(); iter != mBaseScene.end(); ++iter) + { //for each transform in scene + LLMatrix4 mat = iter->first; + + // compute position + LLVector3 position = LLVector3(0, 0, 0) * mat; + + // compute scale + LLVector3 x_transformed = LLVector3(1, 0, 0) * mat - position; + LLVector3 y_transformed = LLVector3(0, 1, 0) * mat - position; + LLVector3 z_transformed = LLVector3(0, 0, 1) * mat - position; + F32 x_length = x_transformed.normalize(); + F32 y_length = y_transformed.normalize(); + F32 z_length = z_transformed.normalize(); + + max_scale = llmax(llmax(llmax(max_scale, x_length), y_length), z_length); + + mat *= scale_mat; + + for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) + { //for each instance with said transform applied + LLModelInstance instance = *model_iter; + + LLModel* base_model = instance.mModel; + + S32 idx = 0; + for (idx = 0; idx < mBaseModel.size(); ++idx) + { //find reference instance for this model + if (mBaseModel[idx] == base_model) + { + break; + } + } + + for (U32 i = 0; i < LLModel::NUM_LODS; i++) + { //fill LOD slots based on reference model index + if (!mModel[i].empty()) + { + instance.mLOD[i] = mModel[i][idx]; + } + else + { + instance.mLOD[i] = NULL; + } + } + + instance.mTransform = mat; + mUploadData.push_back(instance); + } + } + + F32 max_import_scale = DEFAULT_MAX_PRIM_SCALE/max_scale; + + scale_spinner->setMaxValue(max_import_scale); + + if (max_import_scale < scale) + { + scale_spinner->setValue(max_import_scale); + } +} + + +void LLModelPreview::clearModel(S32 lod) +{ + if (lod < 0 || lod > LLModel::LOD_PHYSICS) + { + return; + } + + mVertexBuffer[lod].clear(); + mModel[lod].clear(); + mScene[lod].clear(); +} + +void LLModelPreview::loadModel(std::string filename, S32 lod) +{ + LLMutexLock lock(this); + + if (mModelLoader) + { + delete mModelLoader; + mModelLoader = NULL; + } + + if (filename.empty()) + { + if (mBaseModel.empty()) + { + // this is the initial file picking. Close the whole floater + // if we don't have a base model to show for high LOD. + mFMP->closeFloater(false); + } + + mFMP->mLoading = false; + return; + } + + if (lod == 3 && !mGroup.empty()) + { + for (std::map, U32>::iterator iter = mGroup.begin(); iter != mGroup.end(); ++iter) + { + glodDeleteGroup(iter->second); + stop_gloderror(); + } + + for (std::map, U32>::iterator iter = mObject.begin(); iter != mObject.end(); ++iter) + { + glodDeleteObject(iter->second); + stop_gloderror(); + } + + mGroup.clear(); + mObject.clear(); + } + + mModelLoader = new LLModelLoader(filename, lod, this); + + mModelLoader->start(); + + mFMP->childSetTextArg("status", "[STATUS]", mFMP->getString("status_reading_file")); + + if (mFMP->childGetValue("description_form").asString().empty()) + { + std::string name = gDirUtilp->getBaseFileName(filename, true); + mFMP->childSetValue("description_form", name); + } + + mFMP->openFloater(); +} + +void LLModelPreview::clearIncompatible(S32 lod) +{ + for (U32 i = 0; i <= LLModel::LOD_HIGH; i++) + { //clear out any entries that aren't compatible with this model + if (i != lod) + { + if (mModel[i].size() != mModel[lod].size()) + { + mModel[i].clear(); + mScene[i].clear(); + mVertexBuffer[i].clear(); + + if (i == LLModel::LOD_HIGH) + { + mBaseModel = mModel[lod]; + mBaseScene = mScene[lod]; + mVertexBuffer[5].clear(); + } + } + } + } +} + +void LLModelPreview::loadModelCallback(S32 lod) +{ //NOT the main thread + LLMutexLock lock(this); + if (!mModelLoader) + { + return; + } + + mModel[lod] = mModelLoader->mModelList; + mScene[lod] = mModelLoader->mScene; + mVertexBuffer[lod].clear(); + + if (lod == LLModel::LOD_PHYSICS) + { + mPhysicsMesh.clear(); + } + + setPreviewLOD(lod); + + + if (lod == LLModel::LOD_HIGH) + { //save a copy of the highest LOD for automatic LOD manipulation + mBaseModel = mModel[lod]; + mBaseScene = mScene[lod]; + mVertexBuffer[5].clear(); + //mModel[lod] = NULL; + } + + clearIncompatible(lod); + + mDirty = true; + + resetPreviewTarget(); + + mFMP->mLoading = FALSE; + refresh(); +} + +void LLModelPreview::resetPreviewTarget() +{ + mPreviewTarget = (mModelLoader->mExtents[0] + mModelLoader->mExtents[1]) * 0.5f; + mPreviewScale = (mModelLoader->mExtents[1] - mModelLoader->mExtents[0]) * 0.5f; + setPreviewTarget(mPreviewScale.magVec()*2.f); +} + +void LLModelPreview::smoothNormals() +{ + S32 which_lod = mPreviewLOD; + + + if (which_lod > 4 || which_lod < 0 || + mModel[which_lod].empty()) + { + return; + } + + F32 angle_cutoff = mFMP->childGetValue("edge threshold").asReal(); + + angle_cutoff *= DEG_TO_RAD; + + if (which_lod == 3 && !mBaseModel.empty()) + { + for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) + { + (*iter)->smoothNormals(angle_cutoff); + } + + mVertexBuffer[5].clear(); + } + + for (LLModelLoader::model_list::iterator iter = mModel[which_lod].begin(); iter != mModel[which_lod].end(); ++iter) + { + (*iter)->smoothNormals(angle_cutoff); + } + + mVertexBuffer[which_lod].clear(); + refresh(); + +} + +void LLModelPreview::consolidate() +{ + std::map > composite; + + LLMatrix4 identity; + + //bake out each node in current scene to composite + for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) + { //for each transform in current scene + LLMatrix4 mat = iter->first; + glh::matrix4f inv_trans = glh::matrix4f((F32*) mat.mMatrix).inverse().transpose(); + LLMatrix4 norm_mat(inv_trans.m); + + for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) + { //for each instance with that transform + LLModelInstance& source_instance = *model_iter; + LLModel* source = source_instance.mModel; + + if (!validate_model(source)) + { + llerrs << "Invalid model found!" << llendl; + } + + for (S32 i = 0; i < source->getNumVolumeFaces(); ++i) + { //for each face in instance + const LLVolumeFace& src_face = source->getVolumeFace(i); + LLImportMaterial& source_material = source_instance.mMaterial[i]; + + //get model in composite that is composite for this material + LLModel* model = NULL; + + if (composite.find(source_material) != composite.end()) + { + model = composite[source_material].rbegin()->mModel; + if (model->getVolumeFace(0).mNumVertices + src_face.mNumVertices > 65535) + { + model = NULL; + } + } + + if (model == NULL) + { //no model found, make new model + std::vector materials; + materials.push_back(source_material); + LLVolumeParams volume_params; + volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); + model = new LLModel(volume_params, 0.f); + model->mLabel = source->mLabel; + model->setNumVolumeFaces(0); + composite[source_material].push_back(LLModelInstance(model, identity, materials)); + } + + model->appendFace(src_face, source->mMaterialList[i], mat, norm_mat); + } + } + } + + + //condense composite into as few LLModel instances as possible + LLModelLoader::model_list new_model; + std::vector instance_list; + + LLVolumeParams volume_params; + volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); + + std::vector empty_material; + LLModelInstance cur_instance(new LLModel(volume_params, 0.f), identity, empty_material); + cur_instance.mModel->setNumVolumeFaces(0); + + BOOL first_transform = TRUE; + + LLModelLoader::scene new_scene; + LLVector3 min,max; + + for (std::map >::iterator iter = composite.begin(); + iter != composite.end(); + ++iter) + { + std::map >::iterator next_iter = iter; ++next_iter; + + for (std::vector::iterator instance_iter = iter->second.begin(); + instance_iter != iter->second.end(); + ++instance_iter) + { + LLModel* source = instance_iter->mModel; + + if (instance_iter->mMaterial.size() != 1) + { + llerrs << "WTF?" << llendl; + } + + if (source->getNumVolumeFaces() != 1) + { + llerrs << "WTF?" << llendl; + } + + if (source->mMaterialList.size() != 1) + { + llerrs << "WTF?" << llendl; + } + + cur_instance.mModel->addFace(source->getVolumeFace(0)); + cur_instance.mMaterial.push_back(instance_iter->mMaterial[0]); + cur_instance.mModel->mMaterialList.push_back(source->mMaterialList[0]); + + BOOL last_model = FALSE; + + std::vector::iterator next_instance = instance_iter; ++next_instance; + + if (next_iter == composite.end() && + next_instance == iter->second.end()) + { + last_model = TRUE; + } + + if (last_model || cur_instance.mModel->getNumVolumeFaces() >= MAX_MODEL_FACES) + { + cur_instance.mModel->mLabel = source->mLabel; + + cur_instance.mModel->optimizeVolumeFaces(); + cur_instance.mModel->normalizeVolumeFaces(); + + if (!validate_model(cur_instance.mModel)) + { + llerrs << "Invalid model detected." << llendl; + } + + new_model.push_back(cur_instance.mModel); + + LLMatrix4 transformation = LLMatrix4(); + + // adjust the transformation to compensate for mesh normalization + LLVector3 mesh_scale_vector; + LLVector3 mesh_translation_vector; + cur_instance.mModel->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); + + LLMatrix4 mesh_translation; + mesh_translation.setTranslation(mesh_translation_vector); + mesh_translation *= transformation; + transformation = mesh_translation; + + LLMatrix4 mesh_scale; + mesh_scale.initScale(mesh_scale_vector); + mesh_scale *= transformation; + transformation = mesh_scale; + + cur_instance.mTransform = transformation; + + new_scene[transformation].push_back(cur_instance); + stretch_extents(cur_instance.mModel, transformation, min, max, first_transform); + + if (!last_model) + { + cur_instance = LLModelInstance(new LLModel(volume_params, 0.f), identity, empty_material); + cur_instance.mModel->setNumVolumeFaces(0); + } + } + } + } + + mScene[mPreviewLOD] = new_scene; + mModel[mPreviewLOD] = new_model; + mVertexBuffer[mPreviewLOD].clear(); + + if (mPreviewLOD == LLModel::LOD_HIGH) + { + mBaseScene = new_scene; + mBaseModel = new_model; + mVertexBuffer[5].clear(); + } + + mPreviewTarget = (min+max)*0.5f; + mPreviewScale = (max-min)*0.5f; + setPreviewTarget(mPreviewScale.magVec()*2.f); + + clearIncompatible(mPreviewLOD); + + mResourceCost = calcResourceCost(); + refresh(); +} + +void LLModelPreview::scrubMaterials() +{ + for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) + { //for each transform in current scene + for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) + { //for each instance with that transform + LLModelInstance& source_instance = *model_iter; + LLModel* source = source_instance.mModel; + + for (S32 i = 0; i < source->getNumVolumeFaces(); ++i) + { //for each face in instance + LLImportMaterial& source_material = source_instance.mMaterial[i]; + + //clear material info + source_material.mDiffuseColor = LLColor4(1,1,1,1); + source_material.mDiffuseMap = NULL; + source_material.mDiffuseMapFilename.clear(); + source_material.mDiffuseMapLabel.clear(); + source_material.mFullbright = false; + } + } + } + + + mVertexBuffer[mPreviewLOD].clear(); + + if (mPreviewLOD == LLModel::LOD_HIGH) + { + mBaseScene = mScene[mPreviewLOD]; + mBaseModel = mModel[mPreviewLOD]; + mVertexBuffer[5].clear(); + } + + mResourceCost = calcResourceCost(); + refresh(); +} + +bool LLModelPreview::containsRiggedAsset( void ) +{ + //loop through the models and determine if any of them contained a rigged asset, and if so + //return true. + //This is used to cleanup the joint positions after a preview. + for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) + { + LLModel* pModel = *iter; + if ( pModel->mAlternateBindMatrix.size() > 0 ) + { + return true; + } + } + return false; +} +void LLModelPreview::genLODs(S32 which_lod) +{ + if (mBaseModel.empty()) + { + return; + } + + if (which_lod == LLModel::LOD_PHYSICS) + { //clear physics mesh map + mPhysicsMesh.clear(); + } + + LLVertexBuffer::unbind(); + + stop_gloderror(); + static U32 cur_name = 1; + + S32 limit = -1; + + if (which_lod != -1) + { + limit = mLimit[which_lod]; + } + + U32 triangle_count = 0; + + for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) + { + LLModel* mdl = *iter; + for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) + { + triangle_count += mdl->getVolumeFace(i).mNumIndices/3; + } + } + + U32 base_triangle_count = triangle_count; + + U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; + + if (mGroup[mBaseModel[0]] == 0) + { //clear LOD maps + mGroup.clear(); + mObject.clear(); + mPercentage.clear(); + mPatch.clear(); + } + + for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) + { //build GLOD objects for each model in base model list + LLModel* mdl = *iter; + if (mGroup[mdl] == 0) + { + mGroup[mdl] = cur_name++; + mObject[mdl] = cur_name++; + + glodNewGroup(mGroup[mdl]); + stop_gloderror(); + + glodGroupParameteri(mGroup[mdl], GLOD_ADAPT_MODE, GLOD_TRIANGLE_BUDGET); + stop_gloderror(); + + glodGroupParameteri(mGroup[mdl], GLOD_ERROR_MODE, GLOD_OBJECT_SPACE_ERROR); + stop_gloderror(); + + glodGroupParameterf(mGroup[mdl], GLOD_OBJECT_SPACE_ERROR_THRESHOLD, 0.025f); + stop_gloderror(); + + glodNewObject(mObject[mdl], mGroup[mdl], GLOD_DISCRETE); + stop_gloderror(); + + if (iter == mBaseModel.begin() && !mdl->mSkinWeights.empty()) + { //regenerate vertex buffer for skinned models to prevent animation feedback during LOD generation + mVertexBuffer[5].clear(); + } + + if (mVertexBuffer[5].empty()) + { + genBuffers(5, false); + } + + U32 tri_count = 0; + for (U32 i = 0; i < mVertexBuffer[5][mdl].size(); ++i) + { + mVertexBuffer[5][mdl][i]->setBuffer(type_mask); + U32 num_indices = mVertexBuffer[5][mdl][i]->getNumIndices(); + if (num_indices > 2) + { + glodInsertElements(mObject[mdl], i, GL_TRIANGLES, num_indices, GL_UNSIGNED_SHORT, mVertexBuffer[5][mdl][i]->getIndicesPointer(), 0, 0.f); + } + tri_count += num_indices/3; + stop_gloderror(); + } + + //store what percentage of total model (in terms of triangle count) this model makes up + mPercentage[mdl] = (F32) tri_count / (F32) base_triangle_count; + + //build glodobject + glodBuildObject(mObject[mdl]); + if (stop_gloderror()) + { + glodDeleteGroup(mGroup[mdl]); + stop_gloderror(); + glodDeleteObject(mObject[mdl]); + stop_gloderror(); + + mGroup[mdl] = 0; + mObject[mdl] = 0; + + if (which_lod == -1) + { + mModel[LLModel::LOD_HIGH] = mBaseModel; + } + + return; + } + + } + + //generating LODs for all entries, or this entry has a triangle budget + glodGroupParameteri(mGroup[mdl], GLOD_ADAPT_MODE, GLOD_TRIANGLE_BUDGET); + stop_gloderror(); + + glodGroupParameterf(mGroup[mdl], GLOD_OBJECT_SPACE_ERROR_THRESHOLD, 0.025f); + stop_gloderror(); + } + + + S32 start = LLModel::LOD_HIGH; + S32 end = 0; + + if (which_lod != -1) + { + start = end = which_lod; + } + + + std::string combo_name[] = + { + "lowest detail combo", + "low detail combo", + "medium detail combo", + "high detail combo", + "physics detail combo" + }; + + std::string limit_name[] = + { + "lowest limit", + "low limit", + "medium limit", + "high limit", + "physics limit" + }; + + for (S32 lod = start; lod >= end; --lod) + { + if (which_lod == -1) + { + if (lod < start) + { + triangle_count /= 3; + } + } + else + { + triangle_count = limit; + } + + LLComboBox* combo_box = mFMP->findChild(combo_name[lod]); + combo_box->setCurrentByIndex(2); + + LLSpinCtrl* lim = mFMP->getChild(limit_name[lod], TRUE); + lim->setMaxValue(base_triangle_count); + lim->setVisible(true); + + mModel[lod].clear(); + mModel[lod].resize(mBaseModel.size()); + mVertexBuffer[lod].clear(); + + U32 actual_tris = 0; + U32 actual_verts = 0; + U32 submeshes = 0; + + for (U32 mdl_idx = 0; mdl_idx < mBaseModel.size(); ++mdl_idx) + { + LLModel* base = mBaseModel[mdl_idx]; + + U32 target_count = U32(mPercentage[base]*triangle_count); + + if (target_count < 4) + { + target_count = 4; + } + + glodGroupParameteri(mGroup[base], GLOD_MAX_TRIANGLES, target_count); + stop_gloderror(); + + glodAdaptGroup(mGroup[base]); + stop_gloderror(); + + GLint patch_count = 0; + glodGetObjectParameteriv(mObject[base], GLOD_NUM_PATCHES, &patch_count); + stop_gloderror(); + + LLVolumeParams volume_params; + volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); + mModel[lod][mdl_idx] = new LLModel(volume_params, 0.f); + + GLint* sizes = new GLint[patch_count*2]; + glodGetObjectParameteriv(mObject[base], GLOD_PATCH_SIZES, sizes); + stop_gloderror(); + + GLint* names = new GLint[patch_count]; + glodGetObjectParameteriv(mObject[base], GLOD_PATCH_NAMES, names); + stop_gloderror(); + + mModel[lod][mdl_idx]->setNumVolumeFaces(patch_count); + + LLModel* target_model = mModel[lod][mdl_idx]; + + for (GLint i = 0; i < patch_count; ++i) + { + LLPointer buff = new LLVertexBuffer(type_mask, 0); + + if (sizes[i*2+1] > 0 && sizes[i*2] > 0) + { + buff->allocateBuffer(sizes[i*2+1], sizes[i*2], true); + buff->setBuffer(type_mask); + glodFillElements(mObject[base], names[i], GL_UNSIGNED_SHORT, buff->getIndicesPointer()); + stop_gloderror(); + } + else + { //this face was eliminated, create a dummy triangle (one vertex, 3 indices, all 0) + buff->allocateBuffer(1, 3, true); + memset(buff->getMappedData(), 0, buff->getSize()); + memset(buff->getIndicesPointer(), 0, buff->getIndicesSize()); + } + + buff->validateRange(0, buff->getNumVerts()-1, buff->getNumIndices(), 0); + + LLStrider pos; + LLStrider norm; + LLStrider tc; + LLStrider index; + + buff->getVertexStrider(pos); + buff->getNormalStrider(norm); + buff->getTexCoord0Strider(tc); + buff->getIndexStrider(index); + + + target_model->setVolumeFaceData(names[i], pos, norm, tc, index, buff->getNumVerts(), buff->getNumIndices()); + actual_tris += buff->getNumIndices()/3; + actual_verts += buff->getNumVerts(); + ++submeshes; + + if (!validate_face(target_model->getVolumeFace(names[i]))) + { + llerrs << "Invalid face generated during LOD generation." << llendl; + } + } + + //blind copy skin weights and just take closest skin weight to point on + //decimated mesh for now (auto-generating LODs with skin weights is still a bit + //of an open problem). + target_model->mPosition = base->mPosition; + target_model->mSkinWeights = base->mSkinWeights; + target_model->mJointMap = base->mJointMap; + target_model->mJointList = base->mJointList; + target_model->mInvBindMatrix = base->mInvBindMatrix; + target_model->mBindShapeMatrix = base->mBindShapeMatrix; + target_model->mAlternateBindMatrix = base->mAlternateBindMatrix; + //copy material list + target_model->mMaterialList = base->mMaterialList; + + if (!validate_model(target_model)) + { + llerrs << "Invalid model generated when creating LODs" << llendl; + } + + delete [] sizes; + delete [] names; + } + + //rebuild scene based on mBaseScene + mScene[lod].clear(); + mScene[lod] = mBaseScene; + + for (U32 i = 0; i < mBaseModel.size(); ++i) + { + LLModel* mdl = mBaseModel[i]; + LLModel* target = mModel[lod][i]; + if (target) + { + for (LLModelLoader::scene::iterator iter = mScene[lod].begin(); iter != mScene[lod].end(); ++iter) + { + for (U32 j = 0; j < iter->second.size(); ++j) + { + if (iter->second[j].mModel == mdl) + { + iter->second[j].mModel = target; + } + } + } + } + } + } + + mResourceCost = calcResourceCost(); + + /*if (which_lod == -1 && mScene[LLModel::LOD_PHYSICS].empty()) + { //build physics scene + mScene[LLModel::LOD_PHYSICS] = mScene[LLModel::LOD_LOW]; + mModel[LLModel::LOD_PHYSICS] = mModel[LLModel::LOD_LOW]; + + for (U32 i = 1; i < mModel[LLModel::LOD_PHYSICS].size(); ++i) + { + mPhysicsQ.push(mModel[LLModel::LOD_PHYSICS][i]); + } + }*/ +} + +void LLModelPreview::updateStatusMessages() +{ + //triangle/vertex/submesh count for each mesh asset for each lod + std::vector tris[LLModel::NUM_LODS]; + std::vector verts[LLModel::NUM_LODS]; + std::vector submeshes[LLModel::NUM_LODS]; + + //total triangle/vertex/submesh count for each lod + S32 total_tris[LLModel::NUM_LODS]; + S32 total_verts[LLModel::NUM_LODS]; + S32 total_submeshes[LLModel::NUM_LODS]; + + for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) + { + //initialize total for this lod to 0 + total_tris[lod] = total_verts[lod] = total_submeshes[lod] = 0; + + for (U32 i = 0; i < mModel[lod].size(); ++i) + { //for each model in the lod + S32 cur_tris = 0; + S32 cur_verts = 0; + S32 cur_submeshes = mModel[lod][i]->getNumVolumeFaces(); + + for (S32 j = 0; j < cur_submeshes; ++j) + { //for each submesh (face), add triangles and vertices to current total + const LLVolumeFace& face = mModel[lod][i]->getVolumeFace(j); + cur_tris += face.mNumIndices/3; + cur_verts += face.mNumVertices; + } + + //add this model to the lod total + total_tris[lod] += cur_tris; + total_verts[lod] += cur_verts; + total_submeshes[lod] += cur_submeshes; + + //store this model's counts to asset data + tris[lod].push_back(cur_tris); + verts[lod].push_back(cur_verts); + submeshes[lod].push_back(cur_submeshes); + } + } + + + std::string upload_message; + + mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[TRIANGLES]", llformat("%d", total_tris[LLModel::LOD_PHYSICS])); + + for (S32 lod = 0; lod <= LLModel::LOD_HIGH; ++lod) + { + mFMP->childSetTextArg(info_name[lod], "[TRIANGLES]", llformat("%d", total_tris[lod])); + mFMP->childSetTextArg(info_name[lod], "[VERTICES]", llformat("%d", total_verts[lod])); + mFMP->childSetTextArg(info_name[lod], "[SUBMESHES]", llformat("%d", total_submeshes[lod])); + + std::string message = "good"; + + const U32 lod_high = LLModel::LOD_HIGH; + + if (lod != lod_high) + { + if (total_submeshes[lod] && total_submeshes[lod] != total_submeshes[lod_high]) + { + message = "mesh_mismatch"; + upload_message = "bad_lod"; + } + else if (!tris[lod].empty() && tris[lod].size() != tris[lod_high].size()) + { + message = "model_mismatch"; + upload_message = "bad_lod"; + } + else if (!verts[lod].empty()) + { + for (U32 i = 0; i < verts[lod].size(); ++i) + { + S32 max_verts = verts[lod+1][i]; + + if (verts[lod][i] > max_verts) + { + message = "too_heavy"; + upload_message = "bad_lod"; + } + } + } + } + + mFMP->childSetTextArg(info_name[lod], "[MESSAGE]", mFMP->getString(message)); + } + + if (upload_message.empty()) + { + mFMP->childSetTextArg("upload_message", "[MESSAGE]", std::string("")); + mFMP->childEnable("ok_btn"); + } + else + { + mFMP->childSetTextArg("upload_message", "[MESSAGE]", mFMP->getString(upload_message)); + mFMP->childDisable("ok_btn"); + } +} + +void LLModelPreview::setPreviewTarget(F32 distance) +{ + mCameraDistance = distance; + mCameraZoom = 1.f; + mCameraPitch = 0.f; + mCameraYaw = 0.f; + mCameraOffset.clearVec(); +} + +void LLModelPreview::clearBuffers() +{ + for (U32 i = 0; i < 6; i++) + { + mVertexBuffer[i].clear(); + } +} + +void LLModelPreview::genBuffers(S32 lod, bool avatar_preview) +{ + U32 tri_count = 0; + U32 vertex_count = 0; + U32 mesh_count = 0; + + LLModelLoader::model_list* model = NULL; + + if (lod < 0 || lod > 4) + { + model = &mBaseModel; + lod = 5; + } + else + { + model = &(mModel[lod]); + } + + if (!mVertexBuffer[lod].empty()) + { + mVertexBuffer[lod].clear(); + } + + mVertexBuffer[lod].clear(); + + LLModelLoader::model_list::iterator base_iter = mBaseModel.begin(); + + for (LLModelLoader::model_list::iterator iter = model->begin(); iter != model->end(); ++iter) + { + LLModel* mdl = *iter; + if (!mdl) + { + continue; + } + + LLModel* base_mdl = *base_iter; + base_iter++; + + for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) + { + const LLVolumeFace &vf = mdl->getVolumeFace(i); + U32 num_vertices = vf.mNumVertices; + U32 num_indices = vf.mNumIndices; + + if (!num_vertices || ! num_indices) + { + continue; + } + + LLVertexBuffer* vb = NULL; + + bool skinned = avatar_preview && !mdl->mSkinWeights.empty(); + + U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; + + if (skinned) + { + mask |= LLVertexBuffer::MAP_WEIGHT4; + } + + vb = new LLVertexBuffer(mask, 0); + + vb->allocateBuffer(num_vertices, num_indices, TRUE); + + LLStrider vertex_strider; + LLStrider normal_strider; + LLStrider tc_strider; + LLStrider index_strider; + LLStrider weights_strider; + + vb->getVertexStrider(vertex_strider); + vb->getNormalStrider(normal_strider); + vb->getTexCoord0Strider(tc_strider); + vb->getIndexStrider(index_strider); + + if (skinned) + { + vb->getWeight4Strider(weights_strider); + } + + LLVector4a::memcpyNonAliased16((F32*) vertex_strider.get(), (F32*) vf.mPositions, num_vertices*4*sizeof(F32)); + LLVector4a::memcpyNonAliased16((F32*) tc_strider.get(), (F32*) vf.mTexCoords, num_vertices*2*sizeof(F32)); + LLVector4a::memcpyNonAliased16((F32*) normal_strider.get(), (F32*) vf.mNormals, num_vertices*4*sizeof(F32)); + + if (skinned) + { + for (U32 i = 0; i < num_vertices; i++) + { + //find closest weight to vf.mVertices[i].mPosition + LLVector3 pos(vf.mPositions[i].getF32ptr()); + + const LLModel::weight_list& weight_list = base_mdl->getJointInfluences(pos); + + LLVector4 w(0,0,0,0); + if (weight_list.size() > 4) + { + llerrs << "WTF?" << llendl; + } + + for (U32 i = 0; i < weight_list.size(); ++i) + { + F32 wght = llmin(weight_list[i].mWeight, 0.999999f); + F32 joint = (F32) weight_list[i].mJointIdx; + w.mV[i] = joint + wght; + } + + *(weights_strider++) = w; + } + } + + // build indices + for (U32 i = 0; i < num_indices; i++) + { + *(index_strider++) = vf.mIndices[i]; + } + + mVertexBuffer[lod][mdl].push_back(vb); + + vertex_count += num_vertices; + tri_count += num_indices/3; + ++mesh_count; + + } + } +} + +void LLModelPreview::update() +{ + if (mDirty) + { + mDirty = false; + mResourceCost = calcResourceCost(); + } +} + +//----------------------------------------------------------------------------- +// render() +//----------------------------------------------------------------------------- +BOOL LLModelPreview::render() +{ + LLMutexLock lock(this); + mNeedsUpdate = FALSE; + + S32 width = getWidth(); + S32 height = getHeight(); + + LLGLSUIDefault def; + LLGLDisable no_blend(GL_BLEND); + LLGLEnable cull(GL_CULL_FACE); + LLGLDepthTest depth(GL_TRUE); + LLGLDisable fog(GL_FOG); + + glMatrixMode(GL_PROJECTION); + gGL.pushMatrix(); + glLoadIdentity(); + glOrtho(0.0f, width, 0.0f, height, -1.0f, 1.0f); + + glMatrixMode(GL_MODELVIEW); + gGL.pushMatrix(); + glLoadIdentity(); + + gGL.color4f(0.15f, 0.2f, 0.3f, 1.f); + + gl_rect_2d_simple( width, height ); + + bool avatar_preview = false; + bool upload_skin = mFMP->childGetValue("upload_skin").asBoolean(); + bool upload_joints = mFMP->childGetValue("upload_joints").asBoolean(); + + for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) + { + for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) + { + LLModelInstance& instance = *model_iter; + LLModel* model = instance.mModel; + if (!model->mSkinWeights.empty()) + { + avatar_preview = true; + } + } + } + + if (upload_skin && !avatar_preview) + { + mFMP->childSetValue("upload_skin", false); + upload_skin = false; + } + + if (!upload_skin && upload_joints) + { + mFMP->childSetValue("upload_joints", false); + upload_joints = false; + } + + if (!avatar_preview) + { + mFMP->childDisable("upload_skin"); + } + else + { + mFMP->childEnable("upload_skin"); + } + + if (!upload_skin) + { + mFMP->childDisable("upload_joints"); + } + else + { + mFMP->childEnable("upload_joints"); + } + + avatar_preview = avatar_preview && upload_skin; + + + mFMP->childSetEnabled("consolidate", !avatar_preview); + + F32 explode = mFMP->mDecompFloater ? mFMP->mDecompFloater->childGetValue("explode").asReal() : 0.f; + + glMatrixMode(GL_PROJECTION); + gGL.popMatrix(); + + glMatrixMode(GL_MODELVIEW); + gGL.popMatrix(); + + glClear(GL_DEPTH_BUFFER_BIT); + + LLViewerCamera::getInstance()->setAspect((F32) width / height ); + LLViewerCamera::getInstance()->setView(LLViewerCamera::getInstance()->getDefaultFOV() / mCameraZoom); + + LLVector3 target_pos = mPreviewTarget; + LLVector3 offset = mCameraOffset; + + F32 z_near = llmax(mCameraDistance-mPreviewScale.magVec(), 0.001f); + F32 z_far = mCameraDistance+mPreviewScale.magVec(); + + if (avatar_preview) + { + target_pos = gAgentAvatarp->getPositionAgent(); + z_near = 0.01f; + z_far = 1024.f; + mCameraDistance = 16.f; + + //render avatar previews every frame + refresh(); + } + + LLQuaternion camera_rot = LLQuaternion(mCameraPitch, LLVector3::y_axis) * + LLQuaternion(mCameraYaw, LLVector3::z_axis); + + LLQuaternion av_rot = camera_rot; + LLViewerCamera::getInstance()->setOriginAndLookAt( + target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + offset) * av_rot), // camera + LLVector3::z_axis, // up + target_pos); // point of interest + + + LLViewerCamera::getInstance()->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, width, height, FALSE, z_near, z_far); + + stop_glerror(); + + gPipeline.enableLightsAvatar(); + + gGL.pushMatrix(); + const F32 BRIGHTNESS = 0.9f; + gGL.color3f(BRIGHTNESS, BRIGHTNESS, BRIGHTNESS); + + LLGLEnable normalize(GL_NORMALIZE); + + if (!mBaseModel.empty() && mVertexBuffer[5].empty()) + { + genBuffers(-1, avatar_preview); + //genBuffers(3); + //genLODs(); + } + + bool physics = (mPreviewLOD == LLModel::LOD_PHYSICS); + + S32 physics_idx = -1; + + bool render_mesh = true; + bool render_hull = false; + + if (physics && mFMP->mDecompFloater) + { + physics_idx = mFMP->mDecompFloater->childGetValue("model").asInteger(); + render_mesh = mFMP->mDecompFloater->childGetValue("render_mesh").asBoolean(); + render_hull = mFMP->mDecompFloater->childGetValue("render_hull").asBoolean(); + } + + if (!mModel[mPreviewLOD].empty()) + { + if (mVertexBuffer[mPreviewLOD].empty()) + { + genBuffers(mPreviewLOD, avatar_preview); + } + + if (!avatar_preview) + { + //for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) + for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) + { + LLModelInstance& instance = *iter; + + gGL.pushMatrix(); + LLMatrix4 mat = instance.mTransform; + + glMultMatrixf((GLfloat*) mat.mMatrix); + + //for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) + { + //LLModelInstance& instance = *model_iter; + LLModel* model = instance.mLOD[mPreviewLOD]; + + if (!model) + { + continue; + } + + //if (instance.mTransform != mat) + //{ + // llerrs << "WTF?" << llendl; + //} + + if (render_mesh) + { + for (U32 i = 0; i < mVertexBuffer[mPreviewLOD][model].size(); ++i) + { + LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; + + buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); + if (physics) + { + if (physics_idx > -1 && model == mModel[mPreviewLOD][physics_idx]) + { + glColor4f(1,0,0,1); + } + else + { + glColor4f(0.75f, 0.75f, 0.75f, 1.f); + } + } + else + { + glColor4fv(instance.mMaterial[i].mDiffuseColor.mV); + if (i < instance.mMaterial.size() && instance.mMaterial[i].mDiffuseMap.notNull()) + { + gGL.getTexUnit(0)->bind(instance.mMaterial[i].mDiffuseMap, true); + if (instance.mMaterial[i].mDiffuseMap->getDiscardLevel() > -1) + { + mTextureSet.insert(instance.mMaterial[i].mDiffuseMap); + } + } + } + + buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + glColor3f(0.4f, 0.4f, 0.4f); + + if (mFMP->childGetValue("show edges").asBoolean()) + { + glLineWidth(3.f); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glLineWidth(1.f); + } + } + } + + if (render_hull) + { + LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread; + if (decomp) + { + LLMutexLock(decomp->mMutex); + + std::map, std::vector > >::iterator iter = + mPhysicsMesh.find(model); + if (iter != mPhysicsMesh.end()) + { + for (U32 i = 0; i < iter->second.size(); ++i) + { + if (explode > 0.f) + { + gGL.pushMatrix(); + + LLVector3 offset = model->mHullCenter[i]-model->mCenterOfHullCenters; + offset *= explode; + + gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]); + } + + static std::vector hull_colors; + + if (i+1 >= hull_colors.size()) + { + hull_colors.push_back(LLColor4U(rand()%128+127, rand()%128+127, rand()%128+127, 255)); + } + + LLVertexBuffer* buff = iter->second[i]; + if (buff) + { + buff->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL); + + glColor4ubv(hull_colors[i].mV); + buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts()); + + if (mFMP->childGetValue("show edges").asBoolean()) + { + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + glLineWidth(3.f); + glColor4ub(hull_colors[i].mV[0]/2, hull_colors[i].mV[1]/2, hull_colors[i].mV[2]/2, 255); + buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts()); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glLineWidth(1.f); + } + } + + if (explode > 0.f) + { + gGL.popMatrix(); + } + } + } + } + + //mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[HULLS]", llformat("%d",decomp->mHulls.size())); + //mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[POINTS]", llformat("%d",decomp->mTotalPoints)); + } + } + + gGL.popMatrix(); + } + + if (physics) + { + mPreviewLOD = LLModel::LOD_PHYSICS; + } + } + else + { + LLVOAvatarSelf* avatar = gAgentAvatarp; + target_pos = avatar->getPositionAgent(); + + LLViewerCamera::getInstance()->setOriginAndLookAt( + target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + offset) * av_rot), // camera + LLVector3::z_axis, // up + target_pos); // point of interest + + avatar->renderCollisionVolumes(); +/* + for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) + { + for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) + { + LLModelInstance& instance = *model_iter; + LLModel* model = instance.mModel; + + if (!model->mSkinWeights.empty()) + { + for (U32 i = 0; i < mVertexBuffer[mPreviewLOD][model].size(); ++i) + { + LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; + + const LLVolumeFace& face = model->getVolumeFace(i); + + LLStrider position; + buffer->getVertexStrider(position); + + LLStrider weight; + buffer->getWeight4Strider(weight); + + //quick 'n dirty software vertex skinning + + //build matrix palette + LLMatrix4 mat[64]; + for (U32 j = 0; j < model->mJointList.size(); ++j) + { + LLJoint* joint = avatar->getJoint(model->mJointList[j]); + if (joint) + { + mat[j] = model->mInvBindMatrix[j]; + mat[j] *= joint->getWorldMatrix(); + } + } + + for (U32 j = 0; j < buffer->getRequestedVerts(); ++j) + { + LLMatrix4 final_mat; + final_mat.mMatrix[0][0] = final_mat.mMatrix[1][1] = final_mat.mMatrix[2][2] = final_mat.mMatrix[3][3] = 0.f; + + LLVector4 wght; + S32 idx[4]; + + F32 scale = 0.f; + for (U32 k = 0; k < 4; k++) + { + F32 w = weight[j].mV[k]; + + idx[k] = (S32) floorf(w); + wght.mV[k] = w - floorf(w); + scale += wght.mV[k]; + } + + wght *= 1.f/scale; + + for (U32 k = 0; k < 4; k++) + { + F32* src = (F32*) mat[idx[k]].mMatrix; + F32* dst = (F32*) final_mat.mMatrix; + + F32 w = wght.mV[k]; + + for (U32 l = 0; l < 16; l++) + { + dst[l] += src[l]*w; + } + } + + //VECTORIZE THIS + LLVector3 v(face.mPositions[j].getF32ptr()); + + v = v * model->mBindShapeMatrix; + v = v * final_mat; + + position[j] = v; + } + + buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); + glColor4fv(instance.mMaterial[i].mDiffuseColor.mV); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); + glColor3f(0.4f, 0.4f, 0.4f); + + if (mFMP->childGetValue("show edges").asBoolean()) + { + glLineWidth(3.f); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glLineWidth(1.f); + } + } + } + } + } + */ + } + } + + gGL.popMatrix(); + + return TRUE; +} + +//----------------------------------------------------------------------------- +// refresh() +//----------------------------------------------------------------------------- +void LLModelPreview::refresh() +{ + mNeedsUpdate = TRUE; +} + +//----------------------------------------------------------------------------- +// rotate() +//----------------------------------------------------------------------------- +void LLModelPreview::rotate(F32 yaw_radians, F32 pitch_radians) +{ + mCameraYaw = mCameraYaw + yaw_radians; + + mCameraPitch = llclamp(mCameraPitch + pitch_radians, F_PI_BY_TWO * -0.8f, F_PI_BY_TWO * 0.8f); +} + +//----------------------------------------------------------------------------- +// zoom() +//----------------------------------------------------------------------------- +void LLModelPreview::zoom(F32 zoom_amt) +{ + F32 new_zoom = mCameraZoom+zoom_amt; + + mCameraZoom = llclamp(new_zoom, 1.f, 10.f); +} + +void LLModelPreview::pan(F32 right, F32 up) +{ + mCameraOffset.mV[VY] = llclamp(mCameraOffset.mV[VY] + right * mCameraDistance / mCameraZoom, -1.f, 1.f); + mCameraOffset.mV[VZ] = llclamp(mCameraOffset.mV[VZ] + up * mCameraDistance / mCameraZoom, -1.f, 1.f); +} + +void LLModelPreview::setPreviewLOD(S32 lod) +{ + mPreviewLOD = llclamp(lod, 0, 4); + refresh(); +} + +//static +void LLFloaterModelPreview::onBrowseHighLOD(void* data) +{ + LLFloaterModelPreview* mp = (LLFloaterModelPreview*) data; + mp->loadModel(3); +} + +//static +void LLFloaterModelPreview::onBrowseMediumLOD(void* data) +{ + LLFloaterModelPreview* mp = (LLFloaterModelPreview*) data; + mp->loadModel(2); +} + +//static +void LLFloaterModelPreview::onBrowseLowLOD(void* data) +{ + LLFloaterModelPreview* mp = (LLFloaterModelPreview*) data; + mp->loadModel(1); +} + +//static +void LLFloaterModelPreview::onBrowseLowestLOD(void* data) +{ + LLFloaterModelPreview* mp = (LLFloaterModelPreview*) data; + mp->loadModel(0); +} + +//static +void LLFloaterModelPreview::onUpload(void* user_data) +{ + LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; + + if (mp->mDecompFloater) + { + mp->mDecompFloater->closeFloater(); + } + + mp->mModelPreview->rebuildUploadData(); + + gMeshRepo.uploadModel(mp->mModelPreview->mUploadData, mp->mModelPreview->mPreviewScale, + mp->childGetValue("upload_textures").asBoolean(), mp->childGetValue("upload_skin"), mp->childGetValue("upload_joints")); + + mp->closeFloater(false); +} + +//static +void LLFloaterModelPreview::onConsolidate(void* user_data) +{ + LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; + mp->mModelPreview->consolidate(); +} + +//static +void LLFloaterModelPreview::onScrubMaterials(void* user_data) +{ + LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; + mp->mModelPreview->scrubMaterials(); +} + +//static +void LLFloaterModelPreview::onDecompose(void* user_data) +{ + LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; + mp->showDecompFloater(); +} + +//static +void LLFloaterModelPreview::refresh(LLUICtrl* ctrl, void* user_data) +{ + LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; + mp->mModelPreview->refresh(); +} + +void LLFloaterModelPreview::updateResourceCost() +{ + U32 cost = mModelPreview->mResourceCost; + childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d",cost)); +} + +//static +void LLModelPreview::textureLoadedCallback( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata ) +{ + LLModelPreview* preview = (LLModelPreview*) userdata; + preview->refresh(); +} + +LLFloaterModelPreview::DecompRequest::DecompRequest(const std::string& stage, LLModel* mdl) +{ + mStage = stage; + mContinue = 1; + mModel = mdl; + mParams = sInstance->mDecompParams; + + //copy out positions and indices + if (mdl) + { + U16 index_offset = 0; + + mPositions.clear(); + mIndices.clear(); + + //queue up vertex positions and indices + for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) + { + const LLVolumeFace& face = mdl->getVolumeFace(i); + if (mPositions.size() + face.mNumVertices > 65535) + { + continue; + } + + for (U32 j = 0; j < face.mNumVertices; ++j) + { + mPositions.push_back(LLVector3(face.mPositions[j].getF32ptr())); + } + + for (U32 j = 0; j < face.mNumIndices; ++j) + { + mIndices.push_back(face.mIndices[j]+index_offset); + } + + index_offset += face.mNumVertices; + } + } +} + +S32 LLFloaterModelPreview::DecompRequest::statusCallback(const char* status, S32 p1, S32 p2) +{ + setStatusMessage(llformat("%s: %d/%d", status, p1, p2)); + return mContinue; +} + +void LLFloaterModelPreview::DecompRequest::completed() +{ + mModel->setConvexHullDecomposition(mHull); + + if (sInstance) + { + if (sInstance->mModelPreview) + { + sInstance->mModelPreview->mPhysicsMesh[mModel] = mHullMesh; + sInstance->mModelPreview->mDirty = true; + LLFloaterModelPreview::sInstance->mModelPreview->refresh(); + } + + sInstance->mCurRequest = NULL; + } +} + + -- cgit v1.2.3 From 26b3b37e87da0dae46d5e12a9ab4cae809df22de Mon Sep 17 00:00:00 2001 From: prep Date: Mon, 15 Nov 2010 13:25:59 -0500 Subject: Backed out changeset: 1c9c6cdcccde --- indra/newview/llfloatermodelpreview.cpp | 7734 +++++++++++++++---------------- 1 file changed, 3858 insertions(+), 3876 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 2e011a55e7..1c73a6cb31 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1,3876 +1,3858 @@ -/** - * @file llfloatermodelpreview.cpp - * @brief LLFloaterModelPreview class implementation - * - * $LicenseInfo:firstyear=2004&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "dae.h" -//#include "dom.h" -#include "dom/domAsset.h" -#include "dom/domBind_material.h" -#include "dom/domCOLLADA.h" -#include "dom/domConstants.h" -#include "dom/domController.h" -#include "dom/domEffect.h" -#include "dom/domGeometry.h" -#include "dom/domInstance_geometry.h" -#include "dom/domInstance_material.h" -#include "dom/domInstance_node.h" -#include "dom/domInstance_effect.h" -#include "dom/domMaterial.h" -#include "dom/domMatrix.h" -#include "dom/domNode.h" -#include "dom/domProfile_COMMON.h" -#include "dom/domRotate.h" -#include "dom/domScale.h" -#include "dom/domTranslate.h" -#include "dom/domVisual_scene.h" - -#include "llfloatermodelpreview.h" - -#include "llfilepicker.h" -#include "llimagebmp.h" -#include "llimagetga.h" -#include "llimagejpeg.h" -#include "llimagepng.h" - -#include "llagent.h" -#include "llbutton.h" -#include "llcombobox.h" -#include "lldatapacker.h" -#include "lldrawable.h" -#include "lldrawpoolavatar.h" -#include "llrender.h" -#include "llface.h" -#include "lleconomy.h" -#include "llfocusmgr.h" -#include "llfloaterperms.h" -#include "llmatrix4a.h" -#include "llmeshrepository.h" -#include "llsdutil_math.h" -#include "lltextbox.h" -#include "lltoolmgr.h" -#include "llui.h" -#include "llvector4a.h" -#include "llviewercamera.h" -#include "llviewerwindow.h" -#include "llvoavatar.h" -#include "llvoavatarself.h" -#include "pipeline.h" -#include "lluictrlfactory.h" -#include "llviewermenufile.h" -#include "llviewerregion.h" -#include "llstring.h" -#include "llbutton.h" -#include "llcheckboxctrl.h" -#include "llsliderctrl.h" -#include "llspinctrl.h" -#include "llvfile.h" -#include "llvfs.h" - - -#include "glod/glod.h" - -//static -S32 LLFloaterModelPreview::sUploadAmount = 10; -LLFloaterModelPreview* LLFloaterModelPreview::sInstance = NULL; - -const S32 PREVIEW_BORDER_WIDTH = 2; -const S32 PREVIEW_RESIZE_HANDLE_SIZE = S32(RESIZE_HANDLE_WIDTH * OO_SQRT2) + PREVIEW_BORDER_WIDTH; -const S32 PREVIEW_HPAD = PREVIEW_RESIZE_HANDLE_SIZE; -const S32 PREF_BUTTON_HEIGHT = 16 + 7 + 16; -const S32 PREVIEW_TEXTURE_HEIGHT = 300; - -void drawBoxOutline(const LLVector3& pos, const LLVector3& size); - -std::string limit_name[] = -{ - "lowest limit", - "low limit", - "medium limit", - "high limit", - "physics limit", - - "I went off the end of the limit_name array. Me so smart." -}; - -std::string info_name[] = -{ - "lowest info", - "low info", - "medium info", - "high info", - "physics info", - - "I went off the end of the info_name array. Me so smart." -}; - -bool validate_face(const LLVolumeFace& face) -{ - for (U32 i = 0; i < face.mNumIndices; ++i) - { - if (face.mIndices[i] >= face.mNumVertices) - { - llwarns << "Face has invalid index." << llendl; - return false; - } - } - - return true; -} - -bool validate_model(const LLModel* mdl) -{ - if (mdl->getNumVolumeFaces() == 0) - { - llwarns << "Model has no faces!" << llendl; - return false; - } - - for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) - { - if (mdl->getVolumeFace(i).mNumVertices == 0) - { - llwarns << "Face has no vertices." << llendl; - return false; - } - - if (mdl->getVolumeFace(i).mNumIndices == 0) - { - llwarns << "Face has no indices." << llendl; - return false; - } - - if (!validate_face(mdl->getVolumeFace(i))) - { - return false; - } - } - - return true; -} - -BOOL stop_gloderror() -{ - GLuint error = glodGetError(); - - if (error != GLOD_NO_ERROR) - { - llwarns << "GLOD error detected, cannot generate LOD: " << std::hex << error << llendl; - return TRUE; - } - - return FALSE; -} - -LLPhysicsDecompFloater::LLPhysicsDecompFloater(LLSD& key) -: LLFloater(key) -{ - -} - -LLPhysicsDecompFloater::~LLPhysicsDecompFloater() -{ - if (LLFloaterModelPreview::sInstance && LLFloaterModelPreview::sInstance->mDecompFloater) - { - LLFloaterModelPreview::sInstance->mDecompFloater = NULL; - } -} - -class LLMeshFilePicker : public LLFilePickerThread -{ -public: - LLFloaterModelPreview* mFMP; - S32 mLOD; - - LLMeshFilePicker(LLFloaterModelPreview* fmp, S32 lod) - : LLFilePickerThread(LLFilePicker::FFLOAD_COLLADA) - { - mFMP = fmp; - mLOD = lod; - } - - virtual void notify(const std::string& filename) - { - mFMP->mModelPreview->loadModel(mFile, mLOD); - } -}; - - -//----------------------------------------------------------------------------- -// LLFloaterModelPreview() -//----------------------------------------------------------------------------- -LLFloaterModelPreview::LLFloaterModelPreview(const LLSD& key) : - LLFloater(key) -{ - sInstance = this; - mLastMouseX = 0; - mLastMouseY = 0; - mGLName = 0; - mLoading = FALSE; - mDecompFloater = NULL; -} - -//----------------------------------------------------------------------------- -// postBuild() -//----------------------------------------------------------------------------- -BOOL LLFloaterModelPreview::postBuild() -{ - if (!LLFloater::postBuild()) - { - return FALSE; - } - - childSetCommitCallback("high detail combo", onHighLODCommit, this); - childSetCommitCallback("medium detail combo", onMediumLODCommit, this); - childSetCommitCallback("low detail combo", onLowLODCommit, this); - childSetCommitCallback("lowest detail combo", onLowestLODCommit, this); - childSetCommitCallback("physics detail combo", onPhysicsLODCommit, this); - - - childSetCommitCallback("high limit", onHighLimitCommit, this); - childSetCommitCallback("medium limit", onMediumLimitCommit, this); - childSetCommitCallback("low limit", onLowLimitCommit, this); - childSetCommitCallback("lowest limit", onLowestLimitCommit, this); - childSetCommitCallback("physics limit", onPhysicsLimitCommit, this); - - childSetCommitCallback("smooth normals", onSmoothNormalsCommit, this); - - childSetCommitCallback("show edges", onShowEdgesCommit, this); - childSetCommitCallback("auto fill", onAutoFillCommit, this); - - childSetTextArg("status", "[STATUS]", getString("status_idle")); - - for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) - { - if (lod == LLModel::LOD_PHYSICS) - { - childSetTextArg(info_name[lod], "[TRIANGLES]", std::string("0")); - childSetTextArg(info_name[lod], "[HULLS]", std::string("0")); - childSetTextArg(info_name[lod], "[POINTS]", std::string("0")); - } - else - { - childSetTextArg(info_name[lod], "[TRIANGLES]", std::string("0")); - childSetTextArg(info_name[lod], "[VERTICES]", std::string("0")); - childSetTextArg(info_name[lod], "[SUBMESHES]", std::string("0")); - std::string msg = getString("required"); - childSetTextArg(info_name[lod], "[MESSAGE]", msg); - } - - childSetVisible(limit_name[lod], FALSE); - } - - //childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d",sUploadAmount)); - childSetAction("ok_btn", onUpload, this); - - childSetAction("consolidate", onConsolidate, this); - childSetAction("scrub materials", onScrubMaterials, this); - - childSetAction("decompose_btn", onDecompose, this); - - childSetCommitCallback("preview_lod_combo", onPreviewLODCommit, this); - - childSetCommitCallback("upload_skin", onUploadSkinCommit, this); - childSetCommitCallback("upload_joints", onUploadJointsCommit, this); - - childSetCommitCallback("debug scale", onDebugScaleCommit, this); - - childDisable("upload_skin"); - childDisable("upload_joints"); - - const U32 width = 512; - const U32 height = 512; - - mPreviewRect.set(getRect().getWidth()-PREVIEW_HPAD-width, - PREVIEW_HPAD+height, - getRect().getWidth()-PREVIEW_HPAD, - PREVIEW_HPAD); - - mModelPreview = new LLModelPreview(512, 512, this); - mModelPreview->setPreviewTarget(16.f); - - return TRUE; -} - -//----------------------------------------------------------------------------- -// LLFloaterModelPreview() -//----------------------------------------------------------------------------- -LLFloaterModelPreview::~LLFloaterModelPreview() -{ - sInstance = NULL; - - if ( mModelPreview->containsRiggedAsset() ) - { - gAgentAvatarp->resetJointPositions(); - } - - delete mModelPreview; - - if (mGLName) - { - LLImageGL::deleteTextures(1, &mGLName ); - } - - if (mDecompFloater) - { - mDecompFloater->closeFloater(); - mDecompFloater = NULL; - } -} - -void LLFloaterModelPreview::loadModel(S32 lod) -{ - mLoading = TRUE; - - (new LLMeshFilePicker(this, lod))->getFile(); -} - -void LLFloaterModelPreview::setLODMode(S32 lod, S32 mode) -{ - if (mode == 0) - { - if (lod != LLModel::LOD_PHYSICS) - { - for (S32 i = lod; i >= 0; i--) - { - mModelPreview->clearModel(i); - } - } - else - { - mModelPreview->clearModel(lod); - } - - mModelPreview->refresh(); - mModelPreview->calcResourceCost(); - } - else if (mode == 1) - { - loadModel(lod); - } - else if (mode != mModelPreview->mLODMode[lod]) - { - mModelPreview->mLODMode[lod] = mode; - mModelPreview->genLODs(lod); - } - - mModelPreview->setPreviewLOD(lod); - - - LLSpinCtrl* lim = getChild(limit_name[lod], TRUE); - - if (mode == 2) //triangle count - { - U32 tri_count = 0; - for (LLModelLoader::model_list::iterator iter = mModelPreview->mBaseModel.begin(); - iter != mModelPreview->mBaseModel.end(); ++iter) - { - tri_count += (*iter)->getNumTriangles(); - } - - lim->setMaxValue(tri_count); - lim->setVisible(TRUE); - } - else - { - lim->setVisible(FALSE); - } -} - -void LLFloaterModelPreview::setLimit(S32 lod, S32 limit) -{ - if (limit != mModelPreview->mLimit[lod]) - { - mModelPreview->mLimit[lod] = limit; - mModelPreview->genLODs(lod); - mModelPreview->setPreviewLOD(lod); - } -} - -//static -void LLFloaterModelPreview::onDebugScaleCommit(LLUICtrl*,void* userdata) -{ - LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; - - if (!fp->mModelPreview) - { - return; - } - - fp->mModelPreview->calcResourceCost(); -} - -//static -void LLFloaterModelPreview::onUploadJointsCommit(LLUICtrl*,void* userdata) -{ - LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; - - if (!fp->mModelPreview) - { - return; - } - - fp->mModelPreview->refresh(); -} - -//static -void LLFloaterModelPreview::onUploadSkinCommit(LLUICtrl*,void* userdata) -{ - LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; - - if (!fp->mModelPreview) - { - return; - } - - fp->mModelPreview->refresh(); - fp->mModelPreview->resetPreviewTarget(); - fp->mModelPreview->clearBuffers(); -} - -//static -void LLFloaterModelPreview::onPreviewLODCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; - - if (!fp->mModelPreview) - { - return; - } - - S32 which_mode = 0; - - LLCtrlSelectionInterface* iface = fp->childGetSelectionInterface("preview_lod_combo"); - if (iface) - { - which_mode = iface->getFirstSelectedIndex(); - } - fp->mModelPreview->setPreviewLOD(which_mode); -} - -//static -void LLFloaterModelPreview::setLODMode(S32 lod, void* userdata) -{ - LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; - - if (!fp->mModelPreview) - { - return; - } - - S32 which_mode = 0; - - std::string combo_name[] = - { - "lowest detail combo", - "low detail combo", - "medium detail combo", - "high detail combo", - "physics detail combo", - - "I went off the end of the combo_name array. Me so smart." - }; - - LLCtrlSelectionInterface* iface = fp->childGetSelectionInterface(combo_name[lod]); - if (iface) - { - which_mode = iface->getFirstSelectedIndex(); - } - - fp->setLODMode(lod, which_mode); -} - -//static -void LLFloaterModelPreview::onHighLODCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview::setLODMode(3, userdata); -} - -//static -void LLFloaterModelPreview::onMediumLODCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview::setLODMode(2, userdata); -} - -//static -void LLFloaterModelPreview::onLowLODCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview::setLODMode(1, userdata); -} - -//static -void LLFloaterModelPreview::onLowestLODCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview::setLODMode(0, userdata); -} - -//static -void LLFloaterModelPreview::onPhysicsLODCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview::setLODMode(4, userdata); -} - -//static -void LLFloaterModelPreview::setLimit(S32 lod, void* userdata) -{ - LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; - - if (!fp->mModelPreview) - { - return; - } - - S32 limit = fp->childGetValue(limit_name[lod]).asInteger(); - - - fp->setLimit(lod, limit); -} - -//static -void LLFloaterModelPreview::onHighLimitCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview::setLimit(3, userdata); -} - -//static -void LLFloaterModelPreview::onMediumLimitCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview::setLimit(2, userdata); -} - -//static -void LLFloaterModelPreview::onLowLimitCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview::setLimit(1, userdata); -} - -//static -void LLFloaterModelPreview::onLowestLimitCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview::setLimit(0, userdata); -} - -//static -void LLFloaterModelPreview::onPhysicsLimitCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview::setLimit(4, userdata); -} - -//static -void LLFloaterModelPreview::onSmoothNormalsCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; - - fp->mModelPreview->smoothNormals(); -} - -//static -void LLFloaterModelPreview::onShowEdgesCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; - - fp->mModelPreview->refresh(); -} - -//static -void LLFloaterModelPreview::onExplodeCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview* fp = LLFloaterModelPreview::sInstance; - - fp->mModelPreview->refresh(); -} - -//static -void LLFloaterModelPreview::onAutoFillCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; - - fp->mModelPreview->genLODs(); -} - - -//----------------------------------------------------------------------------- -// draw() -//----------------------------------------------------------------------------- -void LLFloaterModelPreview::draw() -{ - LLFloater::draw(); - LLRect r = getRect(); - - mModelPreview->update(); - - if (!mLoading) - { - childSetTextArg("status", "[STATUS]", getString("status_idle")); - } - - childSetTextArg("description_label", "[PRIM_COST]", llformat("%d", mModelPreview->mResourceCost)); - childSetTextArg("description_label", "[TEXTURES]", llformat("%d", mModelPreview->mTextureSet.size())); - - if (mDecompFloater) - { - if (mCurRequest.notNull()) - { - mDecompFloater->childSetText("status", mCurRequest->mStatusMessage); - } - else - { - const std::string idle("Idle."); - mDecompFloater->childSetText("status", idle); - } - } - - U32 resource_cost = mModelPreview->mResourceCost*10; - - if (childGetValue("upload_textures").asBoolean()) - { - resource_cost += mModelPreview->mTextureSet.size()*10; - } - - childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d", resource_cost)); - - if (mModelPreview) - { - gGL.color3f(1.f, 1.f, 1.f); - - gGL.getTexUnit(0)->bind(mModelPreview); - - gGL.begin( LLRender::QUADS ); - { - gGL.texCoord2f(0.f, 1.f); - gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mTop); - gGL.texCoord2f(0.f, 0.f); - gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mBottom); - gGL.texCoord2f(1.f, 0.f); - gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mBottom); - gGL.texCoord2f(1.f, 1.f); - gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mTop); - } - gGL.end(); - - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - } -} - -//----------------------------------------------------------------------------- -// handleMouseDown() -//----------------------------------------------------------------------------- -BOOL LLFloaterModelPreview::handleMouseDown(S32 x, S32 y, MASK mask) -{ - if (mPreviewRect.pointInRect(x, y)) - { - bringToFront( x, y ); - gFocusMgr.setMouseCapture(this); - gViewerWindow->hideCursor(); - mLastMouseX = x; - mLastMouseY = y; - return TRUE; - } - - return LLFloater::handleMouseDown(x, y, mask); -} - -//----------------------------------------------------------------------------- -// handleMouseUp() -//----------------------------------------------------------------------------- -BOOL LLFloaterModelPreview::handleMouseUp(S32 x, S32 y, MASK mask) -{ - gFocusMgr.setMouseCapture(FALSE); - gViewerWindow->showCursor(); - return LLFloater::handleMouseUp(x, y, mask); -} - -//----------------------------------------------------------------------------- -// handleHover() -//----------------------------------------------------------------------------- -BOOL LLFloaterModelPreview::handleHover (S32 x, S32 y, MASK mask) -{ - MASK local_mask = mask & ~MASK_ALT; - - if (mModelPreview && hasMouseCapture()) - { - if (local_mask == MASK_PAN) - { - // pan here - mModelPreview->pan((F32)(x - mLastMouseX) * -0.005f, (F32)(y - mLastMouseY) * -0.005f); - } - else if (local_mask == MASK_ORBIT) - { - F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f; - F32 pitch_radians = (F32)(y - mLastMouseY) * 0.02f; - - mModelPreview->rotate(yaw_radians, pitch_radians); - } - else - { - - F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f; - F32 zoom_amt = (F32)(y - mLastMouseY) * 0.02f; - - mModelPreview->rotate(yaw_radians, 0.f); - mModelPreview->zoom(zoom_amt); - } - - - mModelPreview->refresh(); - - LLUI::setMousePositionLocal(this, mLastMouseX, mLastMouseY); - } - - if (!mPreviewRect.pointInRect(x, y) || !mModelPreview) - { - return LLFloater::handleHover(x, y, mask); - } - else if (local_mask == MASK_ORBIT) - { - gViewerWindow->setCursor(UI_CURSOR_TOOLCAMERA); - } - else if (local_mask == MASK_PAN) - { - gViewerWindow->setCursor(UI_CURSOR_TOOLPAN); - } - else - { - gViewerWindow->setCursor(UI_CURSOR_TOOLZOOMIN); - } - - return TRUE; -} - -//----------------------------------------------------------------------------- -// handleScrollWheel() -//----------------------------------------------------------------------------- -BOOL LLFloaterModelPreview::handleScrollWheel(S32 x, S32 y, S32 clicks) -{ - if (mPreviewRect.pointInRect(x, y) && mModelPreview) - { - mModelPreview->zoom((F32)clicks * -0.2f); - mModelPreview->refresh(); - } - - return TRUE; -} - -//static -void LLFloaterModelPreview::onPhysicsParamCommit(LLUICtrl* ctrl, void* data) -{ - if (LLConvexDecomposition::getInstance() == NULL) - { - llinfos << "convex decomposition tool is a stub on this platform. cannot get decomp." << llendl; - return; - } - - if (sInstance) - { - LLCDParam* param = (LLCDParam*) data; - sInstance->mDecompParams[param->mName] = ctrl->getValue(); - } -} - -//static -void LLFloaterModelPreview::onPhysicsStageExecute(LLUICtrl* ctrl, void* data) -{ - LLCDStageData* stage = (LLCDStageData*) data; - - LLModel* mdl = NULL; - - if (sInstance) - { - if (sInstance->mCurRequest.notNull()) - { - llinfos << "Decomposition request still pending." << llendl; - return; - } - - if (sInstance->mModelPreview) - { - if (sInstance->mDecompFloater) - { - S32 idx = sInstance->mDecompFloater->childGetValue("model").asInteger(); - if (idx >= 0 && idx < sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS].size()) - { - mdl = sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS][idx]; - } - } - } - } - - if (mdl) - { - sInstance->mCurRequest = new DecompRequest(stage->mName, mdl); - gMeshRepo.mDecompThread->submitRequest(sInstance->mCurRequest); - } -} - -//static -void LLFloaterModelPreview::onPhysicsStageCancel(LLUICtrl* ctrl, void*data) -{ - if (sInstance && sInstance->mCurRequest.notNull()) - { - sInstance->mCurRequest->mContinue = 0; - } -} - -void LLFloaterModelPreview::showDecompFloater() -{ - if (!mDecompFloater) - { - LLSD key; - mDecompFloater = new LLPhysicsDecompFloater(key); - - S32 left = 20; - S32 right = 320; - - S32 cur_y = 30; - - { - //add status text - LLTextBox::Params p; - p.name("status"); - p.rect(LLRect(left, cur_y, right-80, cur_y-20)); - mDecompFloater->addChild(LLUICtrlFactory::create(p)); - } - - - { //add cancel button - LLButton::Params p; - p.name("Cancel"); - p.label("Cancel"); - p.rect(LLRect(right-80, cur_y, right, cur_y-20)); - LLButton* button = LLUICtrlFactory::create(p); - button->setCommitCallback(onPhysicsStageCancel, NULL); - mDecompFloater->addChild(button); - } - - cur_y += 30; - - - static const LLCDStageData* stage = NULL; - static S32 stage_count = 0; - - if (!stage && LLConvexDecomposition::getInstance() != NULL) - { - stage_count = LLConvexDecomposition::getInstance()->getStages(&stage); - } - - static const LLCDParam* param = NULL; - static S32 param_count = 0; - if (!param && LLConvexDecomposition::getInstance() != NULL) - { - param_count = LLConvexDecomposition::getInstance()->getParameters(¶m); - } - - for (S32 j = stage_count-1; j >= 0; --j) - { - LLButton::Params p; - p.name(stage[j].mName); - p.label(stage[j].mName); - p.rect(LLRect(left, cur_y, right, cur_y-20)); - LLButton* button = LLUICtrlFactory::create(p); - button->setCommitCallback(onPhysicsStageExecute, (void*) &stage[j]); - mDecompFloater->addChild(button); - gMeshRepo.mDecompThread->mStageID[stage[j].mName] = j; - cur_y += 30; - // protected against stub by stage_count being 0 for stub above - LLConvexDecomposition::getInstance()->registerCallback(j, LLPhysicsDecomp::llcdCallback); - - llinfos << "Physics decomp stage " << stage[j].mName << " (" << j << ") parameters:" << llendl; - llinfos << "------------------------------------" << llendl; - - for (S32 i = 0; i < param_count; ++i) - { - if (param[i].mStage != j) - { - continue; - } - - std::string name(param[i].mName ? param[i].mName : ""); - std::string description(param[i].mDescription ? param[i].mDescription : ""); - - std::string type = "unknown"; - - llinfos << name << " - " << description << llendl; - - if (param[i].mType == LLCDParam::LLCD_FLOAT) - { - mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mFloat); - llinfos << "Type: float, Default: " << param[i].mDefault.mFloat << llendl; - - LLSliderCtrl::Params p; - p.name(name); - p.label(name); - p.rect(LLRect(left, cur_y, right, cur_y-20)); - p.min_value(param[i].mDetails.mRange.mLow.mFloat); - p.max_value(param[i].mDetails.mRange.mHigh.mFloat); - p.increment(param[i].mDetails.mRange.mDelta.mFloat); - p.tool_tip(description); - p.decimal_digits(3); - p.initial_value(param[i].mDefault.mFloat); - LLSliderCtrl* slider = LLUICtrlFactory::create(p); - slider->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); - mDecompFloater->addChild(slider); - cur_y += 30; - } - else if (param[i].mType == LLCDParam::LLCD_INTEGER) - { - mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue); - llinfos << "Type: integer, Default: " << param[i].mDefault.mIntOrEnumValue << llendl; - LLSliderCtrl::Params p; - p.name(name); - p.label(name); - p.rect(LLRect(left, cur_y, right, cur_y-20)); - p.min_value(param[i].mDetails.mRange.mLow.mIntOrEnumValue); - p.max_value(param[i].mDetails.mRange.mHigh.mIntOrEnumValue); - p.increment(param[i].mDetails.mRange.mDelta.mIntOrEnumValue); - p.tool_tip(description); - p.initial_value(param[i].mDefault.mIntOrEnumValue); - LLSliderCtrl* slider = LLUICtrlFactory::create(p); - slider->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); - mDecompFloater->addChild(slider); - cur_y += 30; - } - else if (param[i].mType == LLCDParam::LLCD_BOOLEAN) - { - mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mBool); - llinfos << "Type: boolean, Default: " << (param[i].mDefault.mBool ? "True" : "False") << llendl; - - LLCheckBoxCtrl::Params p; - p.rect(LLRect(left, cur_y, right, cur_y-20)); - p.name(name); - p.label(name); - p.initial_value(param[i].mDefault.mBool); - p.tool_tip(description); - LLCheckBoxCtrl* check_box = LLUICtrlFactory::create(p); - check_box->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); - mDecompFloater->addChild(check_box); - cur_y += 30; - } - else if (param[i].mType == LLCDParam::LLCD_ENUM) - { - S32 cur_x = left; - mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue); - llinfos << "Type: enum, Default: " << param[i].mDefault.mIntOrEnumValue << llendl; - - { //add label - LLTextBox::Params p; - const LLFontGL* font = (LLFontGL*) p.font(); - - p.rect(LLRect(left, cur_y, left+font->getWidth(name), cur_y-20)); - p.name(name); - p.label(name); - p.initial_value(name); - LLTextBox* text_box = LLUICtrlFactory::create(p); - mDecompFloater->addChild(text_box); - cur_x += text_box->getRect().getWidth(); - } - - { //add combo_box - LLComboBox::Params p; - p.rect(LLRect(cur_x, cur_y, right-right/4, cur_y-20)); - p.name(name); - p.label(name); - p.tool_tip(description); - - llinfos << "Accepted values: " << llendl; - LLComboBox* combo_box = LLUICtrlFactory::create(p); - for (S32 k = 0; k < param[i].mDetails.mEnumValues.mNumEnums; ++k) - { - llinfos << param[i].mDetails.mEnumValues.mEnumsArray[k].mValue - << " - " << param[i].mDetails.mEnumValues.mEnumsArray[k].mName << llendl; - - combo_box->add(param[i].mDetails.mEnumValues.mEnumsArray[k].mName, - LLSD::Integer(param[i].mDetails.mEnumValues.mEnumsArray[k].mValue)); - } - combo_box->setValue(param[i].mDefault.mIntOrEnumValue); - combo_box->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); - mDecompFloater->addChild(combo_box); - cur_y += 30; - - } - - llinfos << "----" << llendl; - } - llinfos << "-----------------------------" << llendl; - } - } - - cur_y += 30; - //explode slider - { - LLSliderCtrl::Params p; - p.initial_value(0); - p.min_value(0); - p.max_value(1); - p.decimal_digits(2); - p.increment(0.05f); - p.label("Explode"); - p.name("explode"); - p.rect(LLRect(left, cur_y, right, cur_y-20)); - LLSliderCtrl* slider = LLUICtrlFactory::create(p); - - mDecompFloater->addChild(slider); - cur_y += 30; - } - - //mesh render checkbox - { - LLCheckBoxCtrl::Params p; - p.label("Mesh: "); - p.name("render_mesh"); - p.rect(LLRect(left, cur_y, right/4, cur_y-20)); - LLCheckBoxCtrl* check = LLUICtrlFactory::create(p); - check->setValue(true); - mDecompFloater->addChild(check); - } - - //hull render checkbox - { - LLCheckBoxCtrl::Params p; - p.label("Hull: "); - p.name("render_hull"); - p.rect(LLRect(right/4, cur_y, right/2, cur_y-20)); - LLCheckBoxCtrl* check = LLUICtrlFactory::create(p); - check->setValue(true); - mDecompFloater->addChild(check); - } - - { //submesh combo box label - LLTextBox::Params p; - p.label("Model"); - p.name("model label"); - p.rect(LLRect(right/2, cur_y, right-right/3, cur_y-20)); - LLTextBox* text_box = LLUICtrlFactory::create(p); - text_box->setValue("Model"); - mDecompFloater->addChild(text_box); - } - - { - //add submesh combo box - LLComboBox::Params p; - p.rect(LLRect(right-right/2+p.font()->getWidth("Model"), cur_y, right, cur_y-20)); - p.name("model"); - LLComboBox* combo_box = LLUICtrlFactory::create(p); - for (S32 i = 0; i < mModelPreview->mBaseModel.size(); ++i) - { - LLModel* mdl = mModelPreview->mBaseModel[i]; - combo_box->add(mdl->mLabel, i); - } - combo_box->setValue(0); - mDecompFloater->addChild(combo_box); - cur_y += 30; - } - - mDecompFloater->childSetCommitCallback("model", LLFloaterModelPreview::refresh, LLFloaterModelPreview::sInstance); - mDecompFloater->childSetCommitCallback("render_mesh", LLFloaterModelPreview::refresh, LLFloaterModelPreview::sInstance); - mDecompFloater->childSetCommitCallback("render_hull", LLFloaterModelPreview::refresh, LLFloaterModelPreview::sInstance); - - mDecompFloater->setRect(LLRect(10, cur_y+20, right+20, 10)); - } - - mDecompFloater->childSetCommitCallback("explode", LLFloaterModelPreview::onExplodeCommit, this); - - mDecompFloater->openFloater(); -} - -//----------------------------------------------------------------------------- -// onMouseCaptureLost() -//----------------------------------------------------------------------------- -// static -void LLFloaterModelPreview::onMouseCaptureLostModelPreview(LLMouseHandler* handler) -{ - gViewerWindow->showCursor(); -} - -//----------------------------------------------------------------------------- -// LLModelLoader -//----------------------------------------------------------------------------- -LLModelLoader::LLModelLoader(std::string filename, S32 lod, LLModelPreview* preview) -: LLThread("Model Loader"), mFilename(filename), mLod(lod), mPreview(preview), mState(STARTING), mFirstTransform(TRUE) -{ - mJointMap["mPelvis"] = "mPelvis"; - mJointMap["mTorso"] = "mTorso"; - mJointMap["mChest"] = "mChest"; - mJointMap["mNeck"] = "mNeck"; - mJointMap["mHead"] = "mHead"; - mJointMap["mSkull"] = "mSkull"; - mJointMap["mEyeRight"] = "mEyeRight"; - mJointMap["mEyeLeft"] = "mEyeLeft"; - mJointMap["mCollarLeft"] = "mCollarLeft"; - mJointMap["mShoulderLeft"] = "mShoulderLeft"; - mJointMap["mElbowLeft"] = "mElbowLeft"; - mJointMap["mWristLeft"] = "mWristLeft"; - mJointMap["mCollarRight"] = "mCollarRight"; - mJointMap["mShoulderRight"] = "mShoulderRight"; - mJointMap["mElbowRight"] = "mElbowRight"; - mJointMap["mWristRight"] = "mWristRight"; - mJointMap["mHipRight"] = "mHipRight"; - mJointMap["mKneeRight"] = "mKneeRight"; - mJointMap["mAnkleRight"] = "mAnkleRight"; - mJointMap["mFootRight"] = "mFootRight"; - mJointMap["mToeRight"] = "mToeRight"; - mJointMap["mHipLeft"] = "mHipLeft"; - mJointMap["mKneeLeft"] = "mKneeLeft"; - mJointMap["mAnkleLeft"] = "mAnkleLeft"; - mJointMap["mFootLeft"] = "mFootLeft"; - mJointMap["mToeLeft"] = "mToeLeft"; - - mJointMap["avatar_mPelvis"] = "mPelvis"; - mJointMap["avatar_mTorso"] = "mTorso"; - mJointMap["avatar_mChest"] = "mChest"; - mJointMap["avatar_mNeck"] = "mNeck"; - mJointMap["avatar_mHead"] = "mHead"; - mJointMap["avatar_mSkull"] = "mSkull"; - mJointMap["avatar_mEyeRight"] = "mEyeRight"; - mJointMap["avatar_mEyeLeft"] = "mEyeLeft"; - mJointMap["avatar_mCollarLeft"] = "mCollarLeft"; - mJointMap["avatar_mShoulderLeft"] = "mShoulderLeft"; - mJointMap["avatar_mElbowLeft"] = "mElbowLeft"; - mJointMap["avatar_mWristLeft"] = "mWristLeft"; - mJointMap["avatar_mCollarRight"] = "mCollarRight"; - mJointMap["avatar_mShoulderRight"] = "mShoulderRight"; - mJointMap["avatar_mElbowRight"] = "mElbowRight"; - mJointMap["avatar_mWristRight"] = "mWristRight"; - mJointMap["avatar_mHipRight"] = "mHipRight"; - mJointMap["avatar_mKneeRight"] = "mKneeRight"; - mJointMap["avatar_mAnkleRight"] = "mAnkleRight"; - mJointMap["avatar_mFootRight"] = "mFootRight"; - mJointMap["avatar_mToeRight"] = "mToeRight"; - mJointMap["avatar_mHipLeft"] = "mHipLeft"; - mJointMap["avatar_mKneeLeft"] = "mKneeLeft"; - mJointMap["avatar_mAnkleLeft"] = "mAnkleLeft"; - mJointMap["avatar_mFootLeft"] = "mFootLeft"; - mJointMap["avatar_mToeLeft"] = "mToeLeft"; - - - mJointMap["hip"] = "mPelvis"; - mJointMap["abdomen"] = "mTorso"; - mJointMap["chest"] = "mChest"; - mJointMap["neck"] = "mNeck"; - mJointMap["head"] = "mHead"; - mJointMap["figureHair"] = "mSkull"; - mJointMap["lCollar"] = "mCollarLeft"; - mJointMap["lShldr"] = "mShoulderLeft"; - mJointMap["lForeArm"] = "mElbowLeft"; - mJointMap["lHand"] = "mWristLeft"; - mJointMap["rCollar"] = "mCollarRight"; - mJointMap["rShldr"] = "mShoulderRight"; - mJointMap["rForeArm"] = "mElbowRight"; - mJointMap["rHand"] = "mWristRight"; - mJointMap["rThigh"] = "mHipRight"; - mJointMap["rShin"] = "mKneeRight"; - mJointMap["rFoot"] = "mFootRight"; - mJointMap["lThigh"] = "mHipLeft"; - mJointMap["lShin"] = "mKneeLeft"; - mJointMap["lFoot"] = "mFootLeft"; -} - -void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, BOOL& first_transform) -{ - LLVector4a box[] = - { - LLVector4a(-1, 1,-1), - LLVector4a(-1, 1, 1), - LLVector4a(-1,-1,-1), - LLVector4a(-1,-1, 1), - LLVector4a( 1, 1,-1), - LLVector4a( 1, 1, 1), - LLVector4a( 1,-1,-1), - LLVector4a( 1,-1, 1), - }; - - for (S32 j = 0; j < model->getNumVolumeFaces(); ++j) - { - const LLVolumeFace& face = model->getVolumeFace(j); - - LLVector4a center; - center.setAdd(face.mExtents[0], face.mExtents[1]); - center.mul(0.5f); - LLVector4a size; - size.setSub(face.mExtents[1],face.mExtents[0]); - size.mul(0.5f); - - for (U32 i = 0; i < 8; i++) - { - LLVector4a t; - t.setMul(size, box[i]); - t.add(center); - - LLVector4a v; - - mat.affineTransform(t, v); - - if (first_transform) - { - first_transform = FALSE; - min = max = v; - } - else - { - update_min_max(min, max, v); - } - } - } -} - -void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& max, BOOL& first_transform) -{ - LLVector4a mina, maxa; - LLMatrix4a mata; - - mata.loadu(mat); - mina.load3(min.mV); - maxa.load3(max.mV); - - stretch_extents(model, mata, mina, maxa, first_transform); - - min.set(mina.getF32ptr()); - max.set(maxa.getF32ptr()); -} - -void LLModelLoader::run() -{ - DAE dae; - domCOLLADA* dom = dae.open(mFilename); - - if (dom) - { - daeDatabase* db = dae.getDatabase(); - - daeInt count = db->getElementCount(NULL, COLLADA_TYPE_MESH); - - daeDocument* doc = dae.getDoc(mFilename); - if (!doc) - { - llwarns << "can't find internal doc" << llendl; - return; - } - - daeElement* root = doc->getDomRoot(); - if (!root) - { - llwarns << "document has no root" << llendl; - return; - } - - //get unit scale - mTransform.setIdentity(); - - domAsset::domUnit* unit = daeSafeCast(root->getDescendant(daeElement::matchType(domAsset::domUnit::ID()))); - - if (unit) - { - F32 meter = unit->getMeter(); - mTransform.mMatrix[0][0] = meter; - mTransform.mMatrix[1][1] = meter; - mTransform.mMatrix[2][2] = meter; - } - - //get up axis rotation - LLMatrix4 rotation; - - domUpAxisType up = UPAXISTYPE_Y_UP; // default is Y_UP - domAsset::domUp_axis* up_axis = - daeSafeCast(root->getDescendant(daeElement::matchType(domAsset::domUp_axis::ID()))); - - if (up_axis) - { - up = up_axis->getValue(); - } - - if (up == UPAXISTYPE_X_UP) - { - rotation.initRotation(0.0f, 90.0f * DEG_TO_RAD, 0.0f); - } - else if (up == UPAXISTYPE_Y_UP) - { - rotation.initRotation(90.0f * DEG_TO_RAD, 0.0f, 0.0f); - } - - rotation *= mTransform; - mTransform = rotation; - - - for (daeInt idx = 0; idx < count; ++idx) - { //build map of domEntities to LLModel - domMesh* mesh = NULL; - db->getElement((daeElement**) &mesh, idx, NULL, COLLADA_TYPE_MESH); - - if (mesh) - { - LLPointer model = LLModel::loadModelFromDomMesh(mesh); - - if (model.notNull() && validate_model(model)) - { - mModelList.push_back(model); - mModel[mesh] = model; - } - } - } - - count = db->getElementCount(NULL, COLLADA_TYPE_SKIN); - for (daeInt idx = 0; idx < count; ++idx) - { //add skinned meshes as instances - domSkin* skin = NULL; - db->getElement((daeElement**) &skin, idx, NULL, COLLADA_TYPE_SKIN); - - if (skin) - { - domGeometry* geom = daeSafeCast(skin->getSource().getElement()); - - if (geom) - { - domMesh* mesh = geom->getMesh(); - if (mesh) - { - LLModel* model = mModel[mesh]; - if (model) - { - LLVector3 mesh_scale_vector; - LLVector3 mesh_translation_vector; - model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); - - LLMatrix4 normalized_transformation; - normalized_transformation.setTranslation(mesh_translation_vector); - - LLMatrix4 mesh_scale; - mesh_scale.initScale(mesh_scale_vector); - mesh_scale *= normalized_transformation; - normalized_transformation = mesh_scale; - - glh::matrix4f inv_mat((F32*) normalized_transformation.mMatrix); - inv_mat = inv_mat.inverse(); - LLMatrix4 inverse_normalized_transformation(inv_mat.m); - - domSkin::domBind_shape_matrix* bind_mat = skin->getBind_shape_matrix(); - - if (bind_mat) - { //get bind shape matrix - domFloat4x4& dom_value = bind_mat->getValue(); - - for (int i = 0; i < 4; i++) - { - for(int j = 0; j < 4; j++) - { - model->mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j*4]; - } - } - - LLMatrix4 trans = normalized_transformation; - trans *= model->mBindShapeMatrix; - model->mBindShapeMatrix = trans; - - } - - /*{ - LLMatrix4 rotation; - if (up == UPAXISTYPE_X_UP) - { - rotation.initRotation(0.0f, 90.0f * DEG_TO_RAD, 0.0f); - } - else if (up == UPAXISTYPE_Z_UP) - { - rotation.initRotation(90.0f * DEG_TO_RAD, 90.0f * DEG_TO_RAD, 0.0f); - } - - rotation *= model->mBindShapeMatrix; - model->mBindShapeMatrix = rotation; - }*/ - - //The joint transfom map that we'll populate below - std::map jointTransforms; - jointTransforms.clear(); - - //Some collada setup for accessing the skeleton - daeElement* pElement = 0; - dae.getDatabase()->getElement( &pElement, 0, 0, "skeleton" ); - domInstance_controller::domSkeleton* pSkeleton = daeSafeCast( pElement ); - if ( pSkeleton ) - { - //Get the root node of the skeleton - daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement(); - if ( pSkeletonRootNode ) - { - //Once we have the root node - start acccessing it's joint components - const int jointCnt = mJointMap.size(); - std::map :: const_iterator jointIt = mJointMap.begin(); - bool missingID = false; - //Loop over all the possible joints within the .dae - using the allowed joint list in the ctor. - for ( int i=0; i( resolver.getElement() ); - if ( pJoint ) - { - //Pull out the translate id and store it in the jointTranslations map - daeSIDResolver jointResolver( pJoint, "./translate" ); - domTranslate* pTranslate = daeSafeCast( jointResolver.getElement() ); - - LLMatrix4 workingTransform; - - //Translation via SID - if ( pTranslate ) - { - domFloat3 jointTrans = pTranslate->getValue(); - LLVector3 singleJointTranslation( jointTrans[0], jointTrans[1], jointTrans[2] ); - workingTransform.setTranslation( singleJointTranslation ); - } - else - { - //Translation via child from element - daeElement* pTranslateElement = getChildFromElement( pJoint, "translate" ); - if ( pTranslateElement && pTranslateElement->typeID() != domTranslate::ID() ) - { - llwarns<< "The found element is not a translate node" <( pTranslateElement ); - domFloat3 translateChild = pTranslateChild->getValue(); - LLVector3 singleJointTranslation( translateChild[0], translateChild[1], translateChild[2] ); - workingTransform.setTranslation( singleJointTranslation ); - } - } - //Store the joint transform w/respect to it's name. - jointTransforms[(*jointIt).second.c_str()] = workingTransform; - } - } - - //If anything failed in regards to extracting the skeleton, joints or translation id, - //mention it - if ( missingID ) - { - llwarns<< "Partial jointmap found in asset - did you mean to just have a partial map?" << llendl; - } - - //Set the joint translations on the avatar - //The joints are reset in the dtor - jointIt = mJointMap.begin(); - for ( int i=0; igetJoint( lookingForJoint ); - if ( pJoint ) - { - pJoint->storeCurrentXform( jointTransform.getTranslation() ); - } - else - { - //Most likely an error in the asset. - llwarns<<"Tried to apply joint position from .dae, but it did not exist in the avatar rig." << llendl; - } - //Reposition the avatars pelvis (avPos+offset) - //if ( !strcmp( (*jointIt).first.c_str(),"mPelvis" ) ) - if ( lookingForJoint == "mPelvis" ) - { - const LLVector3& pos = gAgentAvatarp->getCharacterPosition(); - gAgentAvatarp->setPelvisOffset( true, jointTransform.getTranslation() ); - gAgentAvatarp->setPosition( pos + jointTransform.getTranslation() ); - } - } - } - } - else - { - llwarns<<"No root node in this skeleton" << llendl; - } - } - else - { - llwarns<<"No skeleton in this asset" << llendl; - } - - domSkin::domJoints* joints = skin->getJoints(); - - domInputLocal_Array& joint_input = joints->getInput_array(); - - for (size_t i = 0; i < joint_input.getCount(); ++i) - { - domInputLocal* input = joint_input.get(i); - xsNMTOKEN semantic = input->getSemantic(); - - if (strcmp(semantic, COMMON_PROFILE_INPUT_JOINT) == 0) - { //found joint source, fill model->mJointMap and model->mJointList - daeElement* elem = input->getSource().getElement(); - - domSource* source = daeSafeCast(elem); - if (source) - { - - - domName_array* names_source = source->getName_array(); - - if (names_source) - { - domListOfNames &names = names_source->getValue(); - - for (size_t j = 0; j < names.getCount(); ++j) - { - std::string name(names.get(j)); - if (mJointMap.find(name) != mJointMap.end()) - { - name = mJointMap[name]; - } - model->mJointList.push_back(name); - model->mJointMap[name] = j; - } - } - else - { - domIDREF_array* names_source = source->getIDREF_array(); - if (names_source) - { - xsIDREFS& names = names_source->getValue(); - - for (size_t j = 0; j < names.getCount(); ++j) - { - std::string name(names.get(j).getID()); - if (mJointMap.find(name) != mJointMap.end()) - { - name = mJointMap[name]; - } - model->mJointList.push_back(name); - model->mJointMap[name] = j; - } - } - } - } - } - else if (strcmp(semantic, COMMON_PROFILE_INPUT_INV_BIND_MATRIX) == 0) - { //found inv_bind_matrix array, fill model->mInvBindMatrix - domSource* source = daeSafeCast(input->getSource().getElement()); - if (source) - { - domFloat_array* t = source->getFloat_array(); - if (t) - { - domListOfFloats& transform = t->getValue(); - S32 count = transform.getCount()/16; - - for (S32 k = 0; k < count; ++k) - { - LLMatrix4 mat; - - for (int i = 0; i < 4; i++) - { - for(int j = 0; j < 4; j++) - { - mat.mMatrix[i][j] = transform[k*16 + i + j*4]; - } - } - - model->mInvBindMatrix.push_back(mat); - } - } - } - } - } - - //We need to construct the alternate bind matrix (which contains the new joint positions) - //in the same order as they were stored in the joint buffer. The joints associated - //with the skeleton are not stored in the same order as they are in the exported joint buffer. - //This remaps the skeletal joints to be in the same order as the joints stored in the model. - std::vector :: const_iterator jointIt = model->mJointList.begin(); - const int jointCnt = model->mJointList.size(); - for ( int i=0; imInvBindMatrix[i]; - newInverse.setTranslation( jointTransforms[lookingForJoint].getTranslation() ); - model->mAlternateBindMatrix.push_back( newInverse ); - } - else - { - llwarns<<"Possibly misnamed/missing joint [" <getVertices(); - if (verts) - { - domInputLocal_Array& inputs = verts->getInput_array(); - for (size_t i = 0; i < inputs.getCount() && model->mPosition.empty(); ++i) - { - if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_POSITION) == 0) - { - domSource* pos_source = daeSafeCast(inputs[i]->getSource().getElement()); - if (pos_source) - { - domFloat_array* pos_array = pos_source->getFloat_array(); - if (pos_array) - { - domListOfFloats& pos = pos_array->getValue(); - - for (size_t j = 0; j < pos.getCount(); j += 3) - { - if (pos.getCount() <= j+2) - { - llerrs << "WTF?" << llendl; - } - - LLVector3 v(pos[j], pos[j+1], pos[j+2]); - - //transform from COLLADA space to volume space - v = v * inverse_normalized_transformation; - - model->mPosition.push_back(v); - } - } - } - } - } - } - - //grab skin weights array - domSkin::domVertex_weights* weights = skin->getVertex_weights(); - if (weights) - { - domInputLocalOffset_Array& inputs = weights->getInput_array(); - domFloat_array* vertex_weights = NULL; - for (size_t i = 0; i < inputs.getCount(); ++i) - { - if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_WEIGHT) == 0) - { - domSource* weight_source = daeSafeCast(inputs[i]->getSource().getElement()); - if (weight_source) - { - vertex_weights = weight_source->getFloat_array(); - } - } - } - - if (vertex_weights) - { - domListOfFloats& w = vertex_weights->getValue(); - domListOfUInts& vcount = weights->getVcount()->getValue(); - domListOfInts& v = weights->getV()->getValue(); - - U32 c_idx = 0; - for (size_t vc_idx = 0; vc_idx < vcount.getCount(); ++vc_idx) - { //for each vertex - daeUInt count = vcount[vc_idx]; - - //create list of weights that influence this vertex - LLModel::weight_list weight_list; - - for (daeUInt i = 0; i < count; ++i) - { //for each weight - daeInt joint_idx = v[c_idx++]; - daeInt weight_idx = v[c_idx++]; - - if (joint_idx == -1) - { - //ignore bindings to bind_shape_matrix - continue; - } - - F32 weight_value = w[weight_idx]; - - weight_list.push_back(LLModel::JointWeight(joint_idx, weight_value)); - } - - //sort by joint weight - std::sort(weight_list.begin(), weight_list.end(), LLModel::CompareWeightGreater()); - - std::vector wght; - - F32 total = 0.f; - - for (U32 i = 0; i < llmin((U32) 4, (U32) weight_list.size()); ++i) - { //take up to 4 most significant weights - if (weight_list[i].mWeight > 0.f) - { - wght.push_back( weight_list[i] ); - total += weight_list[i].mWeight; - } - } - - F32 scale = 1.f/total; - if (scale != 1.f) - { //normalize weights - for (U32 i = 0; i < wght.size(); ++i) - { - wght[i].mWeight *= scale; - } - } - - model->mSkinWeights[model->mPosition[vc_idx]] = wght; - } - - //add instance to scene for this model - - LLMatrix4 transform; - std::vector materials; - materials.resize(model->getNumVolumeFaces()); - mScene[transform].push_back(LLModelInstance(model, transform, materials)); - stretch_extents(model, transform, mExtents[0], mExtents[1], mFirstTransform); - } - } - } - } - } - } - } - - daeElement* scene = root->getDescendant("visual_scene"); - if (!scene) - { - llwarns << "document has no visual_scene" << llendl; - return; - } - - processElement(scene); - - mPreview->loadModelCallback(mLod); - } -} - -daeElement* LLModelLoader::getChildFromElement( daeElement* pElement, std::string const & name ) -{ - daeElement* pChildOfElement = pElement->getChild( name.c_str() ); - if ( pChildOfElement ) - { - return pChildOfElement; - } - llwarns<< "Could not find a child [" << name << "] for the element: \"" << pElement->getAttribute("id") << "\"" << llendl; - return NULL; -} - -void LLModelLoader::processElement(daeElement* element) -{ - LLMatrix4 saved_transform = mTransform; - - domTranslate* translate = daeSafeCast(element); - if (translate) - { - domFloat3 dom_value = translate->getValue(); - - LLMatrix4 translation; - translation.setTranslation(LLVector3(dom_value[0], dom_value[1], dom_value[2])); - - translation *= mTransform; - mTransform = translation; - } - - domRotate* rotate = daeSafeCast(element); - if (rotate) - { - domFloat4 dom_value = rotate->getValue(); - - LLMatrix4 rotation; - rotation.initRotTrans(dom_value[3] * DEG_TO_RAD, LLVector3(dom_value[0], dom_value[1], dom_value[2]), LLVector3(0, 0, 0)); - - rotation *= mTransform; - mTransform = rotation; - } - - domScale* scale = daeSafeCast(element); - if (scale) - { - domFloat3 dom_value = scale->getValue(); - - LLMatrix4 scaling; - scaling.initScale(LLVector3(dom_value[0], dom_value[1], dom_value[2])); - - scaling *= mTransform; - mTransform = scaling; - } - - domMatrix* matrix = daeSafeCast(element); - if (matrix) - { - domFloat4x4 dom_value = matrix->getValue(); - - LLMatrix4 matrix_transform; - - for (int i = 0; i < 4; i++) - { - for(int j = 0; j < 4; j++) - { - matrix_transform.mMatrix[i][j] = dom_value[i + j*4]; - } - } - - matrix_transform *= mTransform; - mTransform = matrix_transform; - } - - domInstance_geometry* instance_geo = daeSafeCast(element); - if (instance_geo) - { - domGeometry* geo = daeSafeCast(instance_geo->getUrl().getElement()); - if (geo) - { - domMesh* mesh = daeSafeCast(geo->getDescendant(daeElement::matchType(domMesh::ID()))); - if (mesh) - { - LLModel* model = mModel[mesh]; - if (model) - { - LLMatrix4 transformation = mTransform; - - std::vector materials = getMaterials(model, instance_geo); - - // adjust the transformation to compensate for mesh normalization - LLVector3 mesh_scale_vector; - LLVector3 mesh_translation_vector; - model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); - - LLMatrix4 mesh_translation; - mesh_translation.setTranslation(mesh_translation_vector); - mesh_translation *= transformation; - transformation = mesh_translation; - - LLMatrix4 mesh_scale; - mesh_scale.initScale(mesh_scale_vector); - mesh_scale *= transformation; - transformation = mesh_scale; - - mScene[transformation].push_back(LLModelInstance(model, transformation, materials)); - - stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); - } - } - } - } - - domInstance_node* instance_node = daeSafeCast(element); - if (instance_node) - { - daeElement* instance = instance_node->getUrl().getElement(); - if (instance) - { - processElement(instance); - } - } - - //process children - daeTArray< daeSmartRef > children = element->getChildren(); - for (S32 i = 0; i < children.getCount(); i++) - { - processElement(children[i]); - } - - domNode* node = daeSafeCast(element); - if (node) - { //this element was a node, restore transform before processiing siblings - mTransform = saved_transform; - } -} - -std::vector LLModelLoader::getMaterials(LLModel* model, domInstance_geometry* instance_geo) -{ - std::vector materials; - for (int i = 0; i < model->mMaterialList.size(); i++) - { - LLImportMaterial import_material; - - domInstance_material* instance_mat = NULL; - - domBind_material::domTechnique_common* technique = - daeSafeCast(instance_geo->getDescendant(daeElement::matchType(domBind_material::domTechnique_common::ID()))); - - if (technique) - { - daeTArray< daeSmartRef > inst_materials = technique->getChildrenByType(); - for (int j = 0; j < inst_materials.getCount(); j++) - { - std::string symbol(inst_materials[j]->getSymbol()); - - if (symbol == model->mMaterialList[i]) // found the binding - { - instance_mat = inst_materials[j]; - } - } - } - - if (instance_mat) - { - domMaterial* material = daeSafeCast(instance_mat->getTarget().getElement()); - if (material) - { - domInstance_effect* instance_effect = - daeSafeCast(material->getDescendant(daeElement::matchType(domInstance_effect::ID()))); - if (instance_effect) - { - domEffect* effect = daeSafeCast(instance_effect->getUrl().getElement()); - if (effect) - { - domProfile_COMMON* profile = - daeSafeCast(effect->getDescendant(daeElement::matchType(domProfile_COMMON::ID()))); - if (profile) - { - import_material = profileToMaterial(profile); - } - } - } - } - } - - materials.push_back(import_material); - } - - return materials; -} - -LLImportMaterial LLModelLoader::profileToMaterial(domProfile_COMMON* material) -{ - LLImportMaterial mat; - mat.mFullbright = FALSE; - - daeElement* diffuse = material->getDescendant("diffuse"); - if (diffuse) - { - domCommon_color_or_texture_type_complexType::domTexture* texture = - daeSafeCast(diffuse->getDescendant("texture")); - if (texture) - { - domCommon_newparam_type_Array newparams = material->getNewparam_array(); - for (S32 i = 0; i < newparams.getCount(); i++) - { - domFx_surface_common* surface = newparams[i]->getSurface(); - if (surface) - { - domFx_surface_init_common* init = surface->getFx_surface_init_common(); - if (init) - { - domFx_surface_init_from_common_Array init_from = init->getInit_from_array(); - - if (init_from.getCount() > i) - { - domImage* image = daeSafeCast(init_from[i]->getValue().getElement()); - if (image) - { - // we only support init_from now - embedded data will come later - domImage::domInit_from* init = image->getInit_from(); - if (init) - { - std::string filename = cdom::uriToNativePath(init->getValue().str()); - - mat.mDiffuseMap = LLViewerTextureManager::getFetchedTextureFromUrl("file://" + filename, TRUE, LLViewerTexture::BOOST_PREVIEW); - mat.mDiffuseMap->setLoadedCallback(LLModelPreview::textureLoadedCallback, 0, TRUE, FALSE, this->mPreview, NULL, FALSE); - - mat.mDiffuseMap->forceToSaveRawImage(); - mat.mDiffuseMapFilename = filename; - mat.mDiffuseMapLabel = getElementLabel(material); - } - } - } - } - } - } - } - - domCommon_color_or_texture_type_complexType::domColor* color = - daeSafeCast(diffuse->getDescendant("color")); - if (color) - { - domFx_color_common domfx_color = color->getValue(); - LLColor4 value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]); - mat.mDiffuseColor = value; - } - } - - daeElement* emission = material->getDescendant("emission"); - if (emission) - { - LLColor4 emission_color = getDaeColor(emission); - if (((emission_color[0] + emission_color[1] + emission_color[2]) / 3.0) > 0.25) - { - mat.mFullbright = TRUE; - } - } - - return mat; -} - -// try to get a decent label for this element -std::string LLModelLoader::getElementLabel(daeElement *element) -{ - // if we have a name attribute, use it - std::string name = element->getAttribute("name"); - if (name.length()) - { - return name; - } - - // if we have an ID attribute, use it - if (element->getID()) - { - return std::string(element->getID()); - } - - // if we have a parent, use it - daeElement* parent = element->getParent(); - if (parent) - { - // if parent has a name, use it - std::string name = parent->getAttribute("name"); - if (name.length()) - { - return name; - } - - // if parent has an ID, use it - if (parent->getID()) - { - return std::string(parent->getID()); - } - } - - // try to use our type - daeString element_name = element->getElementName(); - if (element_name) - { - return std::string(element_name); - } - - // if all else fails, use "object" - return std::string("object"); -} - -LLColor4 LLModelLoader::getDaeColor(daeElement* element) -{ - LLColor4 value; - domCommon_color_or_texture_type_complexType::domColor* color = - daeSafeCast(element->getDescendant("color")); - if (color) - { - domFx_color_common domfx_color = color->getValue(); - value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]); - } - - return value; -} - -//----------------------------------------------------------------------------- -// LLModelPreview -//----------------------------------------------------------------------------- - -LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloaterModelPreview* fmp) -: LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE), LLMutex(NULL) -{ - mNeedsUpdate = TRUE; - mCameraDistance = 0.f; - mCameraYaw = 0.f; - mCameraPitch = 0.f; - mCameraZoom = 1.f; - mTextureName = 0; - mPreviewLOD = 3; - mModelLoader = NULL; - mDirty = false; - - for (U32 i = 0; i < LLModel::NUM_LODS; i++) - { - mLODMode[i] = 1; - mLimit[i] = 0; - } - - mLODMode[0] = 0; - - mFMP = fmp; - - glodInit(); -} - -LLModelPreview::~LLModelPreview() -{ - if (mModelLoader) - { - delete mModelLoader; - mModelLoader = NULL; - } - - //*HACK : *TODO : turn this back on when we understand why this crashes - //glodShutdown(); -} - -U32 LLModelPreview::calcResourceCost() -{ - rebuildUploadData(); - - U32 cost = 0; - std::set accounted; - U32 num_points = 0; - U32 num_hulls = 0; - - F32 debug_scale = mFMP->childGetValue("debug scale").asReal(); - - F32 streaming_cost = 0.f; - - for (U32 i = 0; i < mUploadData.size(); ++i) - { - LLModelInstance& instance = mUploadData[i]; - - if (accounted.find(instance.mModel) == accounted.end()) - { - accounted.insert(instance.mModel); - - LLModel::convex_hull_decomposition& decomp = - instance.mLOD[LLModel::LOD_PHYSICS] ? - instance.mLOD[LLModel::LOD_PHYSICS]->mConvexHullDecomp : - instance.mModel->mConvexHullDecomp; - - LLSD ret = LLModel::writeModel( - "", - instance.mLOD[4], - instance.mLOD[3], - instance.mLOD[2], - instance.mLOD[1], - instance.mLOD[0], - decomp, - mFMP->childGetValue("upload_skin").asBoolean(), - mFMP->childGetValue("upload_joints").asBoolean(), - TRUE); - cost += gMeshRepo.calcResourceCost(ret); - - num_hulls += decomp.size(); - for (U32 i = 0; i < decomp.size(); ++i) - { - num_points += decomp[i].size(); - } - - //calculate streaming cost - LLMatrix4 transformation = instance.mTransform; - - LLVector3 position = LLVector3(0, 0, 0) * transformation; - - LLVector3 x_transformed = LLVector3(1, 0, 0) * transformation - position; - LLVector3 y_transformed = LLVector3(0, 1, 0) * transformation - position; - LLVector3 z_transformed = LLVector3(0, 0, 1) * transformation - position; - F32 x_length = x_transformed.normalize(); - F32 y_length = y_transformed.normalize(); - F32 z_length = z_transformed.normalize(); - LLVector3 scale = LLVector3(x_length, y_length, z_length); - - F32 radius = scale.length()*debug_scale; - - streaming_cost += LLMeshRepository::getStreamingCost(ret, radius); - } - } - - mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[HULLS]", llformat("%d",num_hulls)); - mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[POINTS]", llformat("%d",num_points)); - mFMP->childSetTextArg("streaming cost", "[COST]", llformat("%.3f", streaming_cost)); - F32 scale = mFMP->childGetValue("debug scale").asReal()*2.f; - mFMP->childSetTextArg("dimensions", "[X]", llformat("%.3f", mPreviewScale[0]*scale)); - mFMP->childSetTextArg("dimensions", "[Y]", llformat("%.3f", mPreviewScale[1]*scale)); - mFMP->childSetTextArg("dimensions", "[Z]", llformat("%.3f", mPreviewScale[2]*scale)); - - updateStatusMessages(); - - return cost; -} - -void LLModelPreview::rebuildUploadData() -{ - mUploadData.clear(); - mTextureSet.clear(); - - //fill uploaddata instance vectors from scene data - - LLSpinCtrl* scale_spinner = mFMP->getChild("debug scale"); - - if (!scale_spinner) - { - llerrs << "floater_model_preview.xml MUST contain debug scale spinner." << llendl; - } - - F32 scale = scale_spinner->getValue().asReal(); - - LLMatrix4 scale_mat; - scale_mat.initScale(LLVector3(scale, scale, scale)); - - F32 max_scale = 0.f; - - for (LLModelLoader::scene::iterator iter = mBaseScene.begin(); iter != mBaseScene.end(); ++iter) - { //for each transform in scene - LLMatrix4 mat = iter->first; - - // compute position - LLVector3 position = LLVector3(0, 0, 0) * mat; - - // compute scale - LLVector3 x_transformed = LLVector3(1, 0, 0) * mat - position; - LLVector3 y_transformed = LLVector3(0, 1, 0) * mat - position; - LLVector3 z_transformed = LLVector3(0, 0, 1) * mat - position; - F32 x_length = x_transformed.normalize(); - F32 y_length = y_transformed.normalize(); - F32 z_length = z_transformed.normalize(); - - max_scale = llmax(llmax(llmax(max_scale, x_length), y_length), z_length); - - mat *= scale_mat; - - for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) - { //for each instance with said transform applied - LLModelInstance instance = *model_iter; - - LLModel* base_model = instance.mModel; - - S32 idx = 0; - for (idx = 0; idx < mBaseModel.size(); ++idx) - { //find reference instance for this model - if (mBaseModel[idx] == base_model) - { - break; - } - } - - for (U32 i = 0; i < LLModel::NUM_LODS; i++) - { //fill LOD slots based on reference model index - if (!mModel[i].empty()) - { - instance.mLOD[i] = mModel[i][idx]; - } - else - { - instance.mLOD[i] = NULL; - } - } - - instance.mTransform = mat; - mUploadData.push_back(instance); - } - } - - F32 max_import_scale = DEFAULT_MAX_PRIM_SCALE/max_scale; - - scale_spinner->setMaxValue(max_import_scale); - - if (max_import_scale < scale) - { - scale_spinner->setValue(max_import_scale); - } -} - - -void LLModelPreview::clearModel(S32 lod) -{ - if (lod < 0 || lod > LLModel::LOD_PHYSICS) - { - return; - } - - mVertexBuffer[lod].clear(); - mModel[lod].clear(); - mScene[lod].clear(); -} - -void LLModelPreview::loadModel(std::string filename, S32 lod) -{ - LLMutexLock lock(this); - - if (mModelLoader) - { - delete mModelLoader; - mModelLoader = NULL; - } - - if (filename.empty()) - { - if (mBaseModel.empty()) - { - // this is the initial file picking. Close the whole floater - // if we don't have a base model to show for high LOD. - mFMP->closeFloater(false); - } - - mFMP->mLoading = false; - return; - } - - if (lod == 3 && !mGroup.empty()) - { - for (std::map, U32>::iterator iter = mGroup.begin(); iter != mGroup.end(); ++iter) - { - glodDeleteGroup(iter->second); - stop_gloderror(); - } - - for (std::map, U32>::iterator iter = mObject.begin(); iter != mObject.end(); ++iter) - { - glodDeleteObject(iter->second); - stop_gloderror(); - } - - mGroup.clear(); - mObject.clear(); - } - - mModelLoader = new LLModelLoader(filename, lod, this); - - mModelLoader->start(); - - mFMP->childSetTextArg("status", "[STATUS]", mFMP->getString("status_reading_file")); - - if (mFMP->childGetValue("description_form").asString().empty()) - { - std::string name = gDirUtilp->getBaseFileName(filename, true); - mFMP->childSetValue("description_form", name); - } - - mFMP->openFloater(); -} - -void LLModelPreview::clearIncompatible(S32 lod) -{ - for (U32 i = 0; i <= LLModel::LOD_HIGH; i++) - { //clear out any entries that aren't compatible with this model - if (i != lod) - { - if (mModel[i].size() != mModel[lod].size()) - { - mModel[i].clear(); - mScene[i].clear(); - mVertexBuffer[i].clear(); - - if (i == LLModel::LOD_HIGH) - { - mBaseModel = mModel[lod]; - mBaseScene = mScene[lod]; - mVertexBuffer[5].clear(); - } - } - } - } -} - -void LLModelPreview::loadModelCallback(S32 lod) -{ //NOT the main thread - LLMutexLock lock(this); - if (!mModelLoader) - { - return; - } - - mModel[lod] = mModelLoader->mModelList; - mScene[lod] = mModelLoader->mScene; - mVertexBuffer[lod].clear(); - - if (lod == LLModel::LOD_PHYSICS) - { - mPhysicsMesh.clear(); - } - - setPreviewLOD(lod); - - - if (lod == LLModel::LOD_HIGH) - { //save a copy of the highest LOD for automatic LOD manipulation - mBaseModel = mModel[lod]; - mBaseScene = mScene[lod]; - mVertexBuffer[5].clear(); - //mModel[lod] = NULL; - } - - clearIncompatible(lod); - - mDirty = true; - - resetPreviewTarget(); - - mFMP->mLoading = FALSE; - refresh(); -} - -void LLModelPreview::resetPreviewTarget() -{ - mPreviewTarget = (mModelLoader->mExtents[0] + mModelLoader->mExtents[1]) * 0.5f; - mPreviewScale = (mModelLoader->mExtents[1] - mModelLoader->mExtents[0]) * 0.5f; - setPreviewTarget(mPreviewScale.magVec()*2.f); -} - -void LLModelPreview::smoothNormals() -{ - S32 which_lod = mPreviewLOD; - - - if (which_lod > 4 || which_lod < 0 || - mModel[which_lod].empty()) - { - return; - } - - F32 angle_cutoff = mFMP->childGetValue("edge threshold").asReal(); - - angle_cutoff *= DEG_TO_RAD; - - if (which_lod == 3 && !mBaseModel.empty()) - { - for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) - { - (*iter)->smoothNormals(angle_cutoff); - } - - mVertexBuffer[5].clear(); - } - - for (LLModelLoader::model_list::iterator iter = mModel[which_lod].begin(); iter != mModel[which_lod].end(); ++iter) - { - (*iter)->smoothNormals(angle_cutoff); - } - - mVertexBuffer[which_lod].clear(); - refresh(); - -} - -void LLModelPreview::consolidate() -{ - std::map > composite; - - LLMatrix4 identity; - - //bake out each node in current scene to composite - for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) - { //for each transform in current scene - LLMatrix4 mat = iter->first; - glh::matrix4f inv_trans = glh::matrix4f((F32*) mat.mMatrix).inverse().transpose(); - LLMatrix4 norm_mat(inv_trans.m); - - for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) - { //for each instance with that transform - LLModelInstance& source_instance = *model_iter; - LLModel* source = source_instance.mModel; - - if (!validate_model(source)) - { - llerrs << "Invalid model found!" << llendl; - } - - for (S32 i = 0; i < source->getNumVolumeFaces(); ++i) - { //for each face in instance - const LLVolumeFace& src_face = source->getVolumeFace(i); - LLImportMaterial& source_material = source_instance.mMaterial[i]; - - //get model in composite that is composite for this material - LLModel* model = NULL; - - if (composite.find(source_material) != composite.end()) - { - model = composite[source_material].rbegin()->mModel; - if (model->getVolumeFace(0).mNumVertices + src_face.mNumVertices > 65535) - { - model = NULL; - } - } - - if (model == NULL) - { //no model found, make new model - std::vector materials; - materials.push_back(source_material); - LLVolumeParams volume_params; - volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); - model = new LLModel(volume_params, 0.f); - model->mLabel = source->mLabel; - model->setNumVolumeFaces(0); - composite[source_material].push_back(LLModelInstance(model, identity, materials)); - } - - model->appendFace(src_face, source->mMaterialList[i], mat, norm_mat); - } - } - } - - - //condense composite into as few LLModel instances as possible - LLModelLoader::model_list new_model; - std::vector instance_list; - - LLVolumeParams volume_params; - volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); - - std::vector empty_material; - LLModelInstance cur_instance(new LLModel(volume_params, 0.f), identity, empty_material); - cur_instance.mModel->setNumVolumeFaces(0); - - BOOL first_transform = TRUE; - - LLModelLoader::scene new_scene; - LLVector3 min,max; - - for (std::map >::iterator iter = composite.begin(); - iter != composite.end(); - ++iter) - { - std::map >::iterator next_iter = iter; ++next_iter; - - for (std::vector::iterator instance_iter = iter->second.begin(); - instance_iter != iter->second.end(); - ++instance_iter) - { - LLModel* source = instance_iter->mModel; - - if (instance_iter->mMaterial.size() != 1) - { - llerrs << "WTF?" << llendl; - } - - if (source->getNumVolumeFaces() != 1) - { - llerrs << "WTF?" << llendl; - } - - if (source->mMaterialList.size() != 1) - { - llerrs << "WTF?" << llendl; - } - - cur_instance.mModel->addFace(source->getVolumeFace(0)); - cur_instance.mMaterial.push_back(instance_iter->mMaterial[0]); - cur_instance.mModel->mMaterialList.push_back(source->mMaterialList[0]); - - BOOL last_model = FALSE; - - std::vector::iterator next_instance = instance_iter; ++next_instance; - - if (next_iter == composite.end() && - next_instance == iter->second.end()) - { - last_model = TRUE; - } - - if (last_model || cur_instance.mModel->getNumVolumeFaces() >= MAX_MODEL_FACES) - { - cur_instance.mModel->mLabel = source->mLabel; - - cur_instance.mModel->optimizeVolumeFaces(); - cur_instance.mModel->normalizeVolumeFaces(); - - if (!validate_model(cur_instance.mModel)) - { - llerrs << "Invalid model detected." << llendl; - } - - new_model.push_back(cur_instance.mModel); - - LLMatrix4 transformation = LLMatrix4(); - - // adjust the transformation to compensate for mesh normalization - LLVector3 mesh_scale_vector; - LLVector3 mesh_translation_vector; - cur_instance.mModel->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); - - LLMatrix4 mesh_translation; - mesh_translation.setTranslation(mesh_translation_vector); - mesh_translation *= transformation; - transformation = mesh_translation; - - LLMatrix4 mesh_scale; - mesh_scale.initScale(mesh_scale_vector); - mesh_scale *= transformation; - transformation = mesh_scale; - - cur_instance.mTransform = transformation; - - new_scene[transformation].push_back(cur_instance); - stretch_extents(cur_instance.mModel, transformation, min, max, first_transform); - - if (!last_model) - { - cur_instance = LLModelInstance(new LLModel(volume_params, 0.f), identity, empty_material); - cur_instance.mModel->setNumVolumeFaces(0); - } - } - } - } - - mScene[mPreviewLOD] = new_scene; - mModel[mPreviewLOD] = new_model; - mVertexBuffer[mPreviewLOD].clear(); - - if (mPreviewLOD == LLModel::LOD_HIGH) - { - mBaseScene = new_scene; - mBaseModel = new_model; - mVertexBuffer[5].clear(); - } - - mPreviewTarget = (min+max)*0.5f; - mPreviewScale = (max-min)*0.5f; - setPreviewTarget(mPreviewScale.magVec()*2.f); - - clearIncompatible(mPreviewLOD); - - mResourceCost = calcResourceCost(); - refresh(); -} - -void LLModelPreview::scrubMaterials() -{ - for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) - { //for each transform in current scene - for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) - { //for each instance with that transform - LLModelInstance& source_instance = *model_iter; - LLModel* source = source_instance.mModel; - - for (S32 i = 0; i < source->getNumVolumeFaces(); ++i) - { //for each face in instance - LLImportMaterial& source_material = source_instance.mMaterial[i]; - - //clear material info - source_material.mDiffuseColor = LLColor4(1,1,1,1); - source_material.mDiffuseMap = NULL; - source_material.mDiffuseMapFilename.clear(); - source_material.mDiffuseMapLabel.clear(); - source_material.mFullbright = false; - } - } - } - - - mVertexBuffer[mPreviewLOD].clear(); - - if (mPreviewLOD == LLModel::LOD_HIGH) - { - mBaseScene = mScene[mPreviewLOD]; - mBaseModel = mModel[mPreviewLOD]; - mVertexBuffer[5].clear(); - } - - mResourceCost = calcResourceCost(); - refresh(); -} - -bool LLModelPreview::containsRiggedAsset( void ) -{ - //loop through the models and determine if any of them contained a rigged asset, and if so - //return true. - //This is used to cleanup the joint positions after a preview. - for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) - { - LLModel* pModel = *iter; - if ( pModel->mAlternateBindMatrix.size() > 0 ) - { - return true; - } - } - return false; -} -void LLModelPreview::genLODs(S32 which_lod) -{ - if (mBaseModel.empty()) - { - return; - } - - if (which_lod == LLModel::LOD_PHYSICS) - { //clear physics mesh map - mPhysicsMesh.clear(); - } - - LLVertexBuffer::unbind(); - - stop_gloderror(); - static U32 cur_name = 1; - - S32 limit = -1; - - if (which_lod != -1) - { - limit = mLimit[which_lod]; - } - - U32 triangle_count = 0; - - for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) - { - LLModel* mdl = *iter; - for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) - { - triangle_count += mdl->getVolumeFace(i).mNumIndices/3; - } - } - - U32 base_triangle_count = triangle_count; - - U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; - - if (mGroup[mBaseModel[0]] == 0) - { //clear LOD maps - mGroup.clear(); - mObject.clear(); - mPercentage.clear(); - mPatch.clear(); - } - - for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) - { //build GLOD objects for each model in base model list - LLModel* mdl = *iter; - if (mGroup[mdl] == 0) - { - mGroup[mdl] = cur_name++; - mObject[mdl] = cur_name++; - - glodNewGroup(mGroup[mdl]); - stop_gloderror(); - - glodGroupParameteri(mGroup[mdl], GLOD_ADAPT_MODE, GLOD_TRIANGLE_BUDGET); - stop_gloderror(); - - glodGroupParameteri(mGroup[mdl], GLOD_ERROR_MODE, GLOD_OBJECT_SPACE_ERROR); - stop_gloderror(); - - glodGroupParameterf(mGroup[mdl], GLOD_OBJECT_SPACE_ERROR_THRESHOLD, 0.025f); - stop_gloderror(); - - glodNewObject(mObject[mdl], mGroup[mdl], GLOD_DISCRETE); - stop_gloderror(); - - if (iter == mBaseModel.begin() && !mdl->mSkinWeights.empty()) - { //regenerate vertex buffer for skinned models to prevent animation feedback during LOD generation - mVertexBuffer[5].clear(); - } - - if (mVertexBuffer[5].empty()) - { - genBuffers(5, false); - } - - U32 tri_count = 0; - for (U32 i = 0; i < mVertexBuffer[5][mdl].size(); ++i) - { - mVertexBuffer[5][mdl][i]->setBuffer(type_mask); - U32 num_indices = mVertexBuffer[5][mdl][i]->getNumIndices(); - if (num_indices > 2) - { - glodInsertElements(mObject[mdl], i, GL_TRIANGLES, num_indices, GL_UNSIGNED_SHORT, mVertexBuffer[5][mdl][i]->getIndicesPointer(), 0, 0.f); - } - tri_count += num_indices/3; - stop_gloderror(); - } - - //store what percentage of total model (in terms of triangle count) this model makes up - mPercentage[mdl] = (F32) tri_count / (F32) base_triangle_count; - - //build glodobject - glodBuildObject(mObject[mdl]); - if (stop_gloderror()) - { - glodDeleteGroup(mGroup[mdl]); - stop_gloderror(); - glodDeleteObject(mObject[mdl]); - stop_gloderror(); - - mGroup[mdl] = 0; - mObject[mdl] = 0; - - if (which_lod == -1) - { - mModel[LLModel::LOD_HIGH] = mBaseModel; - } - - return; - } - - } - - //generating LODs for all entries, or this entry has a triangle budget - glodGroupParameteri(mGroup[mdl], GLOD_ADAPT_MODE, GLOD_TRIANGLE_BUDGET); - stop_gloderror(); - - glodGroupParameterf(mGroup[mdl], GLOD_OBJECT_SPACE_ERROR_THRESHOLD, 0.025f); - stop_gloderror(); - } - - - S32 start = LLModel::LOD_HIGH; - S32 end = 0; - - if (which_lod != -1) - { - start = end = which_lod; - } - - - std::string combo_name[] = - { - "lowest detail combo", - "low detail combo", - "medium detail combo", - "high detail combo", - "physics detail combo" - }; - - std::string limit_name[] = - { - "lowest limit", - "low limit", - "medium limit", - "high limit", - "physics limit" - }; - - for (S32 lod = start; lod >= end; --lod) - { - if (which_lod == -1) - { - if (lod < start) - { - triangle_count /= 3; - } - } - else - { - triangle_count = limit; - } - - LLComboBox* combo_box = mFMP->findChild(combo_name[lod]); - combo_box->setCurrentByIndex(2); - - LLSpinCtrl* lim = mFMP->getChild(limit_name[lod], TRUE); - lim->setMaxValue(base_triangle_count); - lim->setVisible(true); - - mModel[lod].clear(); - mModel[lod].resize(mBaseModel.size()); - mVertexBuffer[lod].clear(); - - U32 actual_tris = 0; - U32 actual_verts = 0; - U32 submeshes = 0; - - for (U32 mdl_idx = 0; mdl_idx < mBaseModel.size(); ++mdl_idx) - { - LLModel* base = mBaseModel[mdl_idx]; - - U32 target_count = U32(mPercentage[base]*triangle_count); - - if (target_count < 4) - { - target_count = 4; - } - - glodGroupParameteri(mGroup[base], GLOD_MAX_TRIANGLES, target_count); - stop_gloderror(); - - glodAdaptGroup(mGroup[base]); - stop_gloderror(); - - GLint patch_count = 0; - glodGetObjectParameteriv(mObject[base], GLOD_NUM_PATCHES, &patch_count); - stop_gloderror(); - - LLVolumeParams volume_params; - volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); - mModel[lod][mdl_idx] = new LLModel(volume_params, 0.f); - - GLint* sizes = new GLint[patch_count*2]; - glodGetObjectParameteriv(mObject[base], GLOD_PATCH_SIZES, sizes); - stop_gloderror(); - - GLint* names = new GLint[patch_count]; - glodGetObjectParameteriv(mObject[base], GLOD_PATCH_NAMES, names); - stop_gloderror(); - - mModel[lod][mdl_idx]->setNumVolumeFaces(patch_count); - - LLModel* target_model = mModel[lod][mdl_idx]; - - for (GLint i = 0; i < patch_count; ++i) - { - LLPointer buff = new LLVertexBuffer(type_mask, 0); - - if (sizes[i*2+1] > 0 && sizes[i*2] > 0) - { - buff->allocateBuffer(sizes[i*2+1], sizes[i*2], true); - buff->setBuffer(type_mask); - glodFillElements(mObject[base], names[i], GL_UNSIGNED_SHORT, buff->getIndicesPointer()); - stop_gloderror(); - } - else - { //this face was eliminated, create a dummy triangle (one vertex, 3 indices, all 0) - buff->allocateBuffer(1, 3, true); - memset(buff->getMappedData(), 0, buff->getSize()); - memset(buff->getIndicesPointer(), 0, buff->getIndicesSize()); - } - - buff->validateRange(0, buff->getNumVerts()-1, buff->getNumIndices(), 0); - - LLStrider pos; - LLStrider norm; - LLStrider tc; - LLStrider index; - - buff->getVertexStrider(pos); - buff->getNormalStrider(norm); - buff->getTexCoord0Strider(tc); - buff->getIndexStrider(index); - - - target_model->setVolumeFaceData(names[i], pos, norm, tc, index, buff->getNumVerts(), buff->getNumIndices()); - actual_tris += buff->getNumIndices()/3; - actual_verts += buff->getNumVerts(); - ++submeshes; - - if (!validate_face(target_model->getVolumeFace(names[i]))) - { - llerrs << "Invalid face generated during LOD generation." << llendl; - } - } - - //blind copy skin weights and just take closest skin weight to point on - //decimated mesh for now (auto-generating LODs with skin weights is still a bit - //of an open problem). - target_model->mPosition = base->mPosition; - target_model->mSkinWeights = base->mSkinWeights; - target_model->mJointMap = base->mJointMap; - target_model->mJointList = base->mJointList; - target_model->mInvBindMatrix = base->mInvBindMatrix; - target_model->mBindShapeMatrix = base->mBindShapeMatrix; - target_model->mAlternateBindMatrix = base->mAlternateBindMatrix; - //copy material list - target_model->mMaterialList = base->mMaterialList; - - if (!validate_model(target_model)) - { - llerrs << "Invalid model generated when creating LODs" << llendl; - } - - delete [] sizes; - delete [] names; - } - - //rebuild scene based on mBaseScene - mScene[lod].clear(); - mScene[lod] = mBaseScene; - - for (U32 i = 0; i < mBaseModel.size(); ++i) - { - LLModel* mdl = mBaseModel[i]; - LLModel* target = mModel[lod][i]; - if (target) - { - for (LLModelLoader::scene::iterator iter = mScene[lod].begin(); iter != mScene[lod].end(); ++iter) - { - for (U32 j = 0; j < iter->second.size(); ++j) - { - if (iter->second[j].mModel == mdl) - { - iter->second[j].mModel = target; - } - } - } - } - } - } - - mResourceCost = calcResourceCost(); - - /*if (which_lod == -1 && mScene[LLModel::LOD_PHYSICS].empty()) - { //build physics scene - mScene[LLModel::LOD_PHYSICS] = mScene[LLModel::LOD_LOW]; - mModel[LLModel::LOD_PHYSICS] = mModel[LLModel::LOD_LOW]; - - for (U32 i = 1; i < mModel[LLModel::LOD_PHYSICS].size(); ++i) - { - mPhysicsQ.push(mModel[LLModel::LOD_PHYSICS][i]); - } - }*/ -} - -void LLModelPreview::updateStatusMessages() -{ - //triangle/vertex/submesh count for each mesh asset for each lod - std::vector tris[LLModel::NUM_LODS]; - std::vector verts[LLModel::NUM_LODS]; - std::vector submeshes[LLModel::NUM_LODS]; - - //total triangle/vertex/submesh count for each lod - S32 total_tris[LLModel::NUM_LODS]; - S32 total_verts[LLModel::NUM_LODS]; - S32 total_submeshes[LLModel::NUM_LODS]; - - for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) - { - //initialize total for this lod to 0 - total_tris[lod] = total_verts[lod] = total_submeshes[lod] = 0; - - for (U32 i = 0; i < mModel[lod].size(); ++i) - { //for each model in the lod - S32 cur_tris = 0; - S32 cur_verts = 0; - S32 cur_submeshes = mModel[lod][i]->getNumVolumeFaces(); - - for (S32 j = 0; j < cur_submeshes; ++j) - { //for each submesh (face), add triangles and vertices to current total - const LLVolumeFace& face = mModel[lod][i]->getVolumeFace(j); - cur_tris += face.mNumIndices/3; - cur_verts += face.mNumVertices; - } - - //add this model to the lod total - total_tris[lod] += cur_tris; - total_verts[lod] += cur_verts; - total_submeshes[lod] += cur_submeshes; - - //store this model's counts to asset data - tris[lod].push_back(cur_tris); - verts[lod].push_back(cur_verts); - submeshes[lod].push_back(cur_submeshes); - } - } - - - std::string upload_message; - - mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[TRIANGLES]", llformat("%d", total_tris[LLModel::LOD_PHYSICS])); - - for (S32 lod = 0; lod <= LLModel::LOD_HIGH; ++lod) - { - mFMP->childSetTextArg(info_name[lod], "[TRIANGLES]", llformat("%d", total_tris[lod])); - mFMP->childSetTextArg(info_name[lod], "[VERTICES]", llformat("%d", total_verts[lod])); - mFMP->childSetTextArg(info_name[lod], "[SUBMESHES]", llformat("%d", total_submeshes[lod])); - - std::string message = "good"; - - const U32 lod_high = LLModel::LOD_HIGH; - - if (lod != lod_high) - { - if (total_submeshes[lod] && total_submeshes[lod] != total_submeshes[lod_high]) - { - message = "mesh_mismatch"; - upload_message = "bad_lod"; - } - else if (!tris[lod].empty() && tris[lod].size() != tris[lod_high].size()) - { - message = "model_mismatch"; - upload_message = "bad_lod"; - } - else if (!verts[lod].empty()) - { - for (U32 i = 0; i < verts[lod].size(); ++i) - { - S32 max_verts = verts[lod+1][i]; - - if (verts[lod][i] > max_verts) - { - message = "too_heavy"; - upload_message = "bad_lod"; - } - } - } - } - - mFMP->childSetTextArg(info_name[lod], "[MESSAGE]", mFMP->getString(message)); - } - - if (upload_message.empty()) - { - mFMP->childSetTextArg("upload_message", "[MESSAGE]", std::string("")); - mFMP->childEnable("ok_btn"); - } - else - { - mFMP->childSetTextArg("upload_message", "[MESSAGE]", mFMP->getString(upload_message)); - mFMP->childDisable("ok_btn"); - } -} - -void LLModelPreview::setPreviewTarget(F32 distance) -{ - mCameraDistance = distance; - mCameraZoom = 1.f; - mCameraPitch = 0.f; - mCameraYaw = 0.f; - mCameraOffset.clearVec(); -} - -void LLModelPreview::clearBuffers() -{ - for (U32 i = 0; i < 6; i++) - { - mVertexBuffer[i].clear(); - } -} - -void LLModelPreview::genBuffers(S32 lod, bool avatar_preview) -{ - U32 tri_count = 0; - U32 vertex_count = 0; - U32 mesh_count = 0; - - LLModelLoader::model_list* model = NULL; - - if (lod < 0 || lod > 4) - { - model = &mBaseModel; - lod = 5; - } - else - { - model = &(mModel[lod]); - } - - if (!mVertexBuffer[lod].empty()) - { - mVertexBuffer[lod].clear(); - } - - mVertexBuffer[lod].clear(); - - LLModelLoader::model_list::iterator base_iter = mBaseModel.begin(); - - for (LLModelLoader::model_list::iterator iter = model->begin(); iter != model->end(); ++iter) - { - LLModel* mdl = *iter; - if (!mdl) - { - continue; - } - - LLModel* base_mdl = *base_iter; - base_iter++; - - for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) - { - const LLVolumeFace &vf = mdl->getVolumeFace(i); - U32 num_vertices = vf.mNumVertices; - U32 num_indices = vf.mNumIndices; - - if (!num_vertices || ! num_indices) - { - continue; - } - - LLVertexBuffer* vb = NULL; - - bool skinned = avatar_preview && !mdl->mSkinWeights.empty(); - - U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; - - if (skinned) - { - mask |= LLVertexBuffer::MAP_WEIGHT4; - } - - vb = new LLVertexBuffer(mask, 0); - - vb->allocateBuffer(num_vertices, num_indices, TRUE); - - LLStrider vertex_strider; - LLStrider normal_strider; - LLStrider tc_strider; - LLStrider index_strider; - LLStrider weights_strider; - - vb->getVertexStrider(vertex_strider); - vb->getNormalStrider(normal_strider); - vb->getTexCoord0Strider(tc_strider); - vb->getIndexStrider(index_strider); - - if (skinned) - { - vb->getWeight4Strider(weights_strider); - } - - LLVector4a::memcpyNonAliased16((F32*) vertex_strider.get(), (F32*) vf.mPositions, num_vertices*4*sizeof(F32)); - LLVector4a::memcpyNonAliased16((F32*) tc_strider.get(), (F32*) vf.mTexCoords, num_vertices*2*sizeof(F32)); - LLVector4a::memcpyNonAliased16((F32*) normal_strider.get(), (F32*) vf.mNormals, num_vertices*4*sizeof(F32)); - - if (skinned) - { - for (U32 i = 0; i < num_vertices; i++) - { - //find closest weight to vf.mVertices[i].mPosition - LLVector3 pos(vf.mPositions[i].getF32ptr()); - - const LLModel::weight_list& weight_list = base_mdl->getJointInfluences(pos); - - LLVector4 w(0,0,0,0); - if (weight_list.size() > 4) - { - llerrs << "WTF?" << llendl; - } - - for (U32 i = 0; i < weight_list.size(); ++i) - { - F32 wght = llmin(weight_list[i].mWeight, 0.999999f); - F32 joint = (F32) weight_list[i].mJointIdx; - w.mV[i] = joint + wght; - } - - *(weights_strider++) = w; - } - } - - // build indices - for (U32 i = 0; i < num_indices; i++) - { - *(index_strider++) = vf.mIndices[i]; - } - - mVertexBuffer[lod][mdl].push_back(vb); - - vertex_count += num_vertices; - tri_count += num_indices/3; - ++mesh_count; - - } - } -} - -void LLModelPreview::update() -{ - if (mDirty) - { - mDirty = false; - mResourceCost = calcResourceCost(); - } -} - -//----------------------------------------------------------------------------- -// render() -//----------------------------------------------------------------------------- -BOOL LLModelPreview::render() -{ - LLMutexLock lock(this); - mNeedsUpdate = FALSE; - - S32 width = getWidth(); - S32 height = getHeight(); - - LLGLSUIDefault def; - LLGLDisable no_blend(GL_BLEND); - LLGLEnable cull(GL_CULL_FACE); - LLGLDepthTest depth(GL_TRUE); - LLGLDisable fog(GL_FOG); - - glMatrixMode(GL_PROJECTION); - gGL.pushMatrix(); - glLoadIdentity(); - glOrtho(0.0f, width, 0.0f, height, -1.0f, 1.0f); - - glMatrixMode(GL_MODELVIEW); - gGL.pushMatrix(); - glLoadIdentity(); - - gGL.color4f(0.15f, 0.2f, 0.3f, 1.f); - - gl_rect_2d_simple( width, height ); - - bool avatar_preview = false; - bool upload_skin = mFMP->childGetValue("upload_skin").asBoolean(); - bool upload_joints = mFMP->childGetValue("upload_joints").asBoolean(); - - for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) - { - for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) - { - LLModelInstance& instance = *model_iter; - LLModel* model = instance.mModel; - if (!model->mSkinWeights.empty()) - { - avatar_preview = true; - } - } - } - - if (upload_skin && !avatar_preview) - { - mFMP->childSetValue("upload_skin", false); - upload_skin = false; - } - - if (!upload_skin && upload_joints) - { - mFMP->childSetValue("upload_joints", false); - upload_joints = false; - } - - if (!avatar_preview) - { - mFMP->childDisable("upload_skin"); - } - else - { - mFMP->childEnable("upload_skin"); - } - - if (!upload_skin) - { - mFMP->childDisable("upload_joints"); - } - else - { - mFMP->childEnable("upload_joints"); - } - - avatar_preview = avatar_preview && upload_skin; - - - mFMP->childSetEnabled("consolidate", !avatar_preview); - - F32 explode = mFMP->mDecompFloater ? mFMP->mDecompFloater->childGetValue("explode").asReal() : 0.f; - - glMatrixMode(GL_PROJECTION); - gGL.popMatrix(); - - glMatrixMode(GL_MODELVIEW); - gGL.popMatrix(); - - glClear(GL_DEPTH_BUFFER_BIT); - - LLViewerCamera::getInstance()->setAspect((F32) width / height ); - LLViewerCamera::getInstance()->setView(LLViewerCamera::getInstance()->getDefaultFOV() / mCameraZoom); - - LLVector3 target_pos = mPreviewTarget; - LLVector3 offset = mCameraOffset; - - F32 z_near = llmax(mCameraDistance-mPreviewScale.magVec(), 0.001f); - F32 z_far = mCameraDistance+mPreviewScale.magVec(); - - if (avatar_preview) - { - target_pos = gAgentAvatarp->getPositionAgent(); - z_near = 0.01f; - z_far = 1024.f; - mCameraDistance = 16.f; - - //render avatar previews every frame - refresh(); - } - - LLQuaternion camera_rot = LLQuaternion(mCameraPitch, LLVector3::y_axis) * - LLQuaternion(mCameraYaw, LLVector3::z_axis); - - LLQuaternion av_rot = camera_rot; - LLViewerCamera::getInstance()->setOriginAndLookAt( - target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + offset) * av_rot), // camera - LLVector3::z_axis, // up - target_pos); // point of interest - - - LLViewerCamera::getInstance()->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, width, height, FALSE, z_near, z_far); - - stop_glerror(); - - gPipeline.enableLightsAvatar(); - - gGL.pushMatrix(); - const F32 BRIGHTNESS = 0.9f; - gGL.color3f(BRIGHTNESS, BRIGHTNESS, BRIGHTNESS); - - LLGLEnable normalize(GL_NORMALIZE); - - if (!mBaseModel.empty() && mVertexBuffer[5].empty()) - { - genBuffers(-1, avatar_preview); - //genBuffers(3); - //genLODs(); - } - - bool physics = (mPreviewLOD == LLModel::LOD_PHYSICS); - - S32 physics_idx = -1; - - bool render_mesh = true; - bool render_hull = false; - - if (physics && mFMP->mDecompFloater) - { - physics_idx = mFMP->mDecompFloater->childGetValue("model").asInteger(); - render_mesh = mFMP->mDecompFloater->childGetValue("render_mesh").asBoolean(); - render_hull = mFMP->mDecompFloater->childGetValue("render_hull").asBoolean(); - } - - if (!mModel[mPreviewLOD].empty()) - { - if (mVertexBuffer[mPreviewLOD].empty()) - { - genBuffers(mPreviewLOD, avatar_preview); - } - - if (!avatar_preview) - { - //for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) - for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) - { - LLModelInstance& instance = *iter; - - gGL.pushMatrix(); - LLMatrix4 mat = instance.mTransform; - - glMultMatrixf((GLfloat*) mat.mMatrix); - - //for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) - { - //LLModelInstance& instance = *model_iter; - LLModel* model = instance.mLOD[mPreviewLOD]; - - if (!model) - { - continue; - } - - //if (instance.mTransform != mat) - //{ - // llerrs << "WTF?" << llendl; - //} - - if (render_mesh) - { - for (U32 i = 0; i < mVertexBuffer[mPreviewLOD][model].size(); ++i) - { - LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; - - buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); - if (physics) - { - if (physics_idx > -1 && model == mModel[mPreviewLOD][physics_idx]) - { - glColor4f(1,0,0,1); - } - else - { - glColor4f(0.75f, 0.75f, 0.75f, 1.f); - } - } - else - { - glColor4fv(instance.mMaterial[i].mDiffuseColor.mV); - if (i < instance.mMaterial.size() && instance.mMaterial[i].mDiffuseMap.notNull()) - { - gGL.getTexUnit(0)->bind(instance.mMaterial[i].mDiffuseMap, true); - if (instance.mMaterial[i].mDiffuseMap->getDiscardLevel() > -1) - { - mTextureSet.insert(instance.mMaterial[i].mDiffuseMap); - } - } - } - - buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - glColor3f(0.4f, 0.4f, 0.4f); - - if (mFMP->childGetValue("show edges").asBoolean()) - { - glLineWidth(3.f); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glLineWidth(1.f); - } - } - } - - if (render_hull) - { - LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread; - if (decomp) - { - LLMutexLock(decomp->mMutex); - - std::map, std::vector > >::iterator iter = - mPhysicsMesh.find(model); - if (iter != mPhysicsMesh.end()) - { - for (U32 i = 0; i < iter->second.size(); ++i) - { - if (explode > 0.f) - { - gGL.pushMatrix(); - - LLVector3 offset = model->mHullCenter[i]-model->mCenterOfHullCenters; - offset *= explode; - - gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]); - } - - static std::vector hull_colors; - - if (i+1 >= hull_colors.size()) - { - hull_colors.push_back(LLColor4U(rand()%128+127, rand()%128+127, rand()%128+127, 255)); - } - - LLVertexBuffer* buff = iter->second[i]; - if (buff) - { - buff->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL); - - glColor4ubv(hull_colors[i].mV); - buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts()); - - if (mFMP->childGetValue("show edges").asBoolean()) - { - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - glLineWidth(3.f); - glColor4ub(hull_colors[i].mV[0]/2, hull_colors[i].mV[1]/2, hull_colors[i].mV[2]/2, 255); - buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts()); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glLineWidth(1.f); - } - } - - if (explode > 0.f) - { - gGL.popMatrix(); - } - } - } - } - - //mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[HULLS]", llformat("%d",decomp->mHulls.size())); - //mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[POINTS]", llformat("%d",decomp->mTotalPoints)); - } - } - - gGL.popMatrix(); - } - - if (physics) - { - mPreviewLOD = LLModel::LOD_PHYSICS; - } - } - else - { - LLVOAvatarSelf* avatar = gAgentAvatarp; - target_pos = avatar->getPositionAgent(); - - LLViewerCamera::getInstance()->setOriginAndLookAt( - target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + offset) * av_rot), // camera - LLVector3::z_axis, // up - target_pos); // point of interest - - avatar->renderCollisionVolumes(); -/* - for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) - { - for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) - { - LLModelInstance& instance = *model_iter; - LLModel* model = instance.mModel; - - if (!model->mSkinWeights.empty()) - { - for (U32 i = 0; i < mVertexBuffer[mPreviewLOD][model].size(); ++i) - { - LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; - - const LLVolumeFace& face = model->getVolumeFace(i); - - LLStrider position; - buffer->getVertexStrider(position); - - LLStrider weight; - buffer->getWeight4Strider(weight); - - //quick 'n dirty software vertex skinning - - //build matrix palette - LLMatrix4 mat[64]; - for (U32 j = 0; j < model->mJointList.size(); ++j) - { - LLJoint* joint = avatar->getJoint(model->mJointList[j]); - if (joint) - { - mat[j] = model->mInvBindMatrix[j]; - mat[j] *= joint->getWorldMatrix(); - } - } - - for (U32 j = 0; j < buffer->getRequestedVerts(); ++j) - { - LLMatrix4 final_mat; - final_mat.mMatrix[0][0] = final_mat.mMatrix[1][1] = final_mat.mMatrix[2][2] = final_mat.mMatrix[3][3] = 0.f; - - LLVector4 wght; - S32 idx[4]; - - F32 scale = 0.f; - for (U32 k = 0; k < 4; k++) - { - F32 w = weight[j].mV[k]; - - idx[k] = (S32) floorf(w); - wght.mV[k] = w - floorf(w); - scale += wght.mV[k]; - } - - wght *= 1.f/scale; - - for (U32 k = 0; k < 4; k++) - { - F32* src = (F32*) mat[idx[k]].mMatrix; - F32* dst = (F32*) final_mat.mMatrix; - - F32 w = wght.mV[k]; - - for (U32 l = 0; l < 16; l++) - { - dst[l] += src[l]*w; - } - } - - //VECTORIZE THIS - LLVector3 v(face.mPositions[j].getF32ptr()); - - v = v * model->mBindShapeMatrix; - v = v * final_mat; - - position[j] = v; - } - - buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); - glColor4fv(instance.mMaterial[i].mDiffuseColor.mV); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); - glColor3f(0.4f, 0.4f, 0.4f); - - if (mFMP->childGetValue("show edges").asBoolean()) - { - glLineWidth(3.f); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glLineWidth(1.f); - } - } - } - } - } - */ - } - } - - gGL.popMatrix(); - - return TRUE; -} - -//----------------------------------------------------------------------------- -// refresh() -//----------------------------------------------------------------------------- -void LLModelPreview::refresh() -{ - mNeedsUpdate = TRUE; -} - -//----------------------------------------------------------------------------- -// rotate() -//----------------------------------------------------------------------------- -void LLModelPreview::rotate(F32 yaw_radians, F32 pitch_radians) -{ - mCameraYaw = mCameraYaw + yaw_radians; - - mCameraPitch = llclamp(mCameraPitch + pitch_radians, F_PI_BY_TWO * -0.8f, F_PI_BY_TWO * 0.8f); -} - -//----------------------------------------------------------------------------- -// zoom() -//----------------------------------------------------------------------------- -void LLModelPreview::zoom(F32 zoom_amt) -{ - F32 new_zoom = mCameraZoom+zoom_amt; - - mCameraZoom = llclamp(new_zoom, 1.f, 10.f); -} - -void LLModelPreview::pan(F32 right, F32 up) -{ - mCameraOffset.mV[VY] = llclamp(mCameraOffset.mV[VY] + right * mCameraDistance / mCameraZoom, -1.f, 1.f); - mCameraOffset.mV[VZ] = llclamp(mCameraOffset.mV[VZ] + up * mCameraDistance / mCameraZoom, -1.f, 1.f); -} - -void LLModelPreview::setPreviewLOD(S32 lod) -{ - mPreviewLOD = llclamp(lod, 0, 4); - refresh(); -} - -//static -void LLFloaterModelPreview::onBrowseHighLOD(void* data) -{ - LLFloaterModelPreview* mp = (LLFloaterModelPreview*) data; - mp->loadModel(3); -} - -//static -void LLFloaterModelPreview::onBrowseMediumLOD(void* data) -{ - LLFloaterModelPreview* mp = (LLFloaterModelPreview*) data; - mp->loadModel(2); -} - -//static -void LLFloaterModelPreview::onBrowseLowLOD(void* data) -{ - LLFloaterModelPreview* mp = (LLFloaterModelPreview*) data; - mp->loadModel(1); -} - -//static -void LLFloaterModelPreview::onBrowseLowestLOD(void* data) -{ - LLFloaterModelPreview* mp = (LLFloaterModelPreview*) data; - mp->loadModel(0); -} - -//static -void LLFloaterModelPreview::onUpload(void* user_data) -{ - LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; - - if (mp->mDecompFloater) - { - mp->mDecompFloater->closeFloater(); - } - - mp->mModelPreview->rebuildUploadData(); - - gMeshRepo.uploadModel(mp->mModelPreview->mUploadData, mp->mModelPreview->mPreviewScale, - mp->childGetValue("upload_textures").asBoolean(), mp->childGetValue("upload_skin"), mp->childGetValue("upload_joints")); - - mp->closeFloater(false); -} - -//static -void LLFloaterModelPreview::onConsolidate(void* user_data) -{ - LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; - mp->mModelPreview->consolidate(); -} - -//static -void LLFloaterModelPreview::onScrubMaterials(void* user_data) -{ - LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; - mp->mModelPreview->scrubMaterials(); -} - -//static -void LLFloaterModelPreview::onDecompose(void* user_data) -{ - LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; - mp->showDecompFloater(); -} - -//static -void LLFloaterModelPreview::refresh(LLUICtrl* ctrl, void* user_data) -{ - LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; - mp->mModelPreview->refresh(); -} - -void LLFloaterModelPreview::updateResourceCost() -{ - U32 cost = mModelPreview->mResourceCost; - childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d",cost)); -} - -//static -void LLModelPreview::textureLoadedCallback( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata ) -{ - LLModelPreview* preview = (LLModelPreview*) userdata; - preview->refresh(); -} - -LLFloaterModelPreview::DecompRequest::DecompRequest(const std::string& stage, LLModel* mdl) -{ - mStage = stage; - mContinue = 1; - mModel = mdl; - mParams = sInstance->mDecompParams; - - //copy out positions and indices - if (mdl) - { - U16 index_offset = 0; - - mPositions.clear(); - mIndices.clear(); - - //queue up vertex positions and indices - for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) - { - const LLVolumeFace& face = mdl->getVolumeFace(i); - if (mPositions.size() + face.mNumVertices > 65535) - { - continue; - } - - for (U32 j = 0; j < face.mNumVertices; ++j) - { - mPositions.push_back(LLVector3(face.mPositions[j].getF32ptr())); - } - - for (U32 j = 0; j < face.mNumIndices; ++j) - { - mIndices.push_back(face.mIndices[j]+index_offset); - } - - index_offset += face.mNumVertices; - } - } -} - -S32 LLFloaterModelPreview::DecompRequest::statusCallback(const char* status, S32 p1, S32 p2) -{ - setStatusMessage(llformat("%s: %d/%d", status, p1, p2)); - return mContinue; -} - -void LLFloaterModelPreview::DecompRequest::completed() -{ - mModel->setConvexHullDecomposition(mHull); - - if (sInstance) - { - if (sInstance->mModelPreview) - { - sInstance->mModelPreview->mPhysicsMesh[mModel] = mHullMesh; - sInstance->mModelPreview->mDirty = true; - LLFloaterModelPreview::sInstance->mModelPreview->refresh(); - } - - sInstance->mCurRequest = NULL; - } -} - - +/** + * @file llfloatermodelpreview.cpp + * @brief LLFloaterModelPreview class implementation + * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "dae.h" +//#include "dom.h" +#include "dom/domAsset.h" +#include "dom/domBind_material.h" +#include "dom/domCOLLADA.h" +#include "dom/domConstants.h" +#include "dom/domController.h" +#include "dom/domEffect.h" +#include "dom/domGeometry.h" +#include "dom/domInstance_geometry.h" +#include "dom/domInstance_material.h" +#include "dom/domInstance_node.h" +#include "dom/domInstance_effect.h" +#include "dom/domMaterial.h" +#include "dom/domMatrix.h" +#include "dom/domNode.h" +#include "dom/domProfile_COMMON.h" +#include "dom/domRotate.h" +#include "dom/domScale.h" +#include "dom/domTranslate.h" +#include "dom/domVisual_scene.h" + +#include "llfloatermodelpreview.h" + +#include "llfilepicker.h" +#include "llimagebmp.h" +#include "llimagetga.h" +#include "llimagejpeg.h" +#include "llimagepng.h" + +#include "llagent.h" +#include "llbutton.h" +#include "llcombobox.h" +#include "lldatapacker.h" +#include "lldrawable.h" +#include "lldrawpoolavatar.h" +#include "llrender.h" +#include "llface.h" +#include "lleconomy.h" +#include "llfocusmgr.h" +#include "llfloaterperms.h" +#include "llmatrix4a.h" +#include "llmeshrepository.h" +#include "llsdutil_math.h" +#include "lltextbox.h" +#include "lltoolmgr.h" +#include "llui.h" +#include "llvector4a.h" +#include "llviewercamera.h" +#include "llviewerwindow.h" +#include "llvoavatar.h" +#include "llvoavatarself.h" +#include "pipeline.h" +#include "lluictrlfactory.h" +#include "llviewermenufile.h" +#include "llviewerregion.h" +#include "llstring.h" +#include "llbutton.h" +#include "llcheckboxctrl.h" +#include "llsliderctrl.h" +#include "llspinctrl.h" +#include "llvfile.h" +#include "llvfs.h" + + +#include "glod/glod.h" + +//static +S32 LLFloaterModelPreview::sUploadAmount = 10; +LLFloaterModelPreview* LLFloaterModelPreview::sInstance = NULL; + +const S32 PREVIEW_BORDER_WIDTH = 2; +const S32 PREVIEW_RESIZE_HANDLE_SIZE = S32(RESIZE_HANDLE_WIDTH * OO_SQRT2) + PREVIEW_BORDER_WIDTH; +const S32 PREVIEW_HPAD = PREVIEW_RESIZE_HANDLE_SIZE; +const S32 PREF_BUTTON_HEIGHT = 16 + 7 + 16; +const S32 PREVIEW_TEXTURE_HEIGHT = 300; + +void drawBoxOutline(const LLVector3& pos, const LLVector3& size); + +std::string limit_name[] = +{ + "lowest limit", + "low limit", + "medium limit", + "high limit", + "physics limit", + + "I went off the end of the limit_name array. Me so smart." +}; + +std::string info_name[] = +{ + "lowest info", + "low info", + "medium info", + "high info", + "physics info", + + "I went off the end of the info_name array. Me so smart." +}; + +bool validate_face(const LLVolumeFace& face) +{ + for (U32 i = 0; i < face.mNumIndices; ++i) + { + if (face.mIndices[i] >= face.mNumVertices) + { + llwarns << "Face has invalid index." << llendl; + return false; + } + } + + return true; +} + +bool validate_model(const LLModel* mdl) +{ + if (mdl->getNumVolumeFaces() == 0) + { + llwarns << "Model has no faces!" << llendl; + return false; + } + + for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) + { + if (mdl->getVolumeFace(i).mNumVertices == 0) + { + llwarns << "Face has no vertices." << llendl; + return false; + } + + if (mdl->getVolumeFace(i).mNumIndices == 0) + { + llwarns << "Face has no indices." << llendl; + return false; + } + + if (!validate_face(mdl->getVolumeFace(i))) + { + return false; + } + } + + return true; +} + +BOOL stop_gloderror() +{ + GLuint error = glodGetError(); + + if (error != GLOD_NO_ERROR) + { + llwarns << "GLOD error detected, cannot generate LOD: " << std::hex << error << llendl; + return TRUE; + } + + return FALSE; +} + +LLPhysicsDecompFloater::LLPhysicsDecompFloater(LLSD& key) +: LLFloater(key) +{ + +} + +LLPhysicsDecompFloater::~LLPhysicsDecompFloater() +{ + if (LLFloaterModelPreview::sInstance && LLFloaterModelPreview::sInstance->mDecompFloater) + { + LLFloaterModelPreview::sInstance->mDecompFloater = NULL; + } +} + +class LLMeshFilePicker : public LLFilePickerThread +{ +public: + LLFloaterModelPreview* mFMP; + S32 mLOD; + + LLMeshFilePicker(LLFloaterModelPreview* fmp, S32 lod) + : LLFilePickerThread(LLFilePicker::FFLOAD_COLLADA) + { + mFMP = fmp; + mLOD = lod; + } + + virtual void notify(const std::string& filename) + { + mFMP->mModelPreview->loadModel(mFile, mLOD); + } +}; + + +//----------------------------------------------------------------------------- +// LLFloaterModelPreview() +//----------------------------------------------------------------------------- +LLFloaterModelPreview::LLFloaterModelPreview(const LLSD& key) : + LLFloater(key) +{ + sInstance = this; + mLastMouseX = 0; + mLastMouseY = 0; + mGLName = 0; + mLoading = FALSE; + mDecompFloater = NULL; +} + +//----------------------------------------------------------------------------- +// postBuild() +//----------------------------------------------------------------------------- +BOOL LLFloaterModelPreview::postBuild() +{ + if (!LLFloater::postBuild()) + { + return FALSE; + } + + childSetCommitCallback("high detail combo", onHighLODCommit, this); + childSetCommitCallback("medium detail combo", onMediumLODCommit, this); + childSetCommitCallback("low detail combo", onLowLODCommit, this); + childSetCommitCallback("lowest detail combo", onLowestLODCommit, this); + childSetCommitCallback("physics detail combo", onPhysicsLODCommit, this); + + + childSetCommitCallback("high limit", onHighLimitCommit, this); + childSetCommitCallback("medium limit", onMediumLimitCommit, this); + childSetCommitCallback("low limit", onLowLimitCommit, this); + childSetCommitCallback("lowest limit", onLowestLimitCommit, this); + childSetCommitCallback("physics limit", onPhysicsLimitCommit, this); + + childSetCommitCallback("smooth normals", onSmoothNormalsCommit, this); + + childSetCommitCallback("show edges", onShowEdgesCommit, this); + childSetCommitCallback("auto fill", onAutoFillCommit, this); + + childSetTextArg("status", "[STATUS]", getString("status_idle")); + + for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) + { + if (lod == LLModel::LOD_PHYSICS) + { + childSetTextArg(info_name[lod], "[TRIANGLES]", std::string("0")); + childSetTextArg(info_name[lod], "[HULLS]", std::string("0")); + childSetTextArg(info_name[lod], "[POINTS]", std::string("0")); + } + else + { + childSetTextArg(info_name[lod], "[TRIANGLES]", std::string("0")); + childSetTextArg(info_name[lod], "[VERTICES]", std::string("0")); + childSetTextArg(info_name[lod], "[SUBMESHES]", std::string("0")); + std::string msg = getString("required"); + childSetTextArg(info_name[lod], "[MESSAGE]", msg); + } + + childSetVisible(limit_name[lod], FALSE); + } + + //childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d",sUploadAmount)); + childSetAction("ok_btn", onUpload, this); + + childSetAction("consolidate", onConsolidate, this); + childSetAction("scrub materials", onScrubMaterials, this); + + childSetAction("decompose_btn", onDecompose, this); + + childSetCommitCallback("preview_lod_combo", onPreviewLODCommit, this); + + childSetCommitCallback("upload_skin", onUploadSkinCommit, this); + childSetCommitCallback("upload_joints", onUploadJointsCommit, this); + + childSetCommitCallback("debug scale", onDebugScaleCommit, this); + + childDisable("upload_skin"); + childDisable("upload_joints"); + + const U32 width = 512; + const U32 height = 512; + + mPreviewRect.set(getRect().getWidth()-PREVIEW_HPAD-width, + PREVIEW_HPAD+height, + getRect().getWidth()-PREVIEW_HPAD, + PREVIEW_HPAD); + + mModelPreview = new LLModelPreview(512, 512, this); + mModelPreview->setPreviewTarget(16.f); + + return TRUE; +} + +//----------------------------------------------------------------------------- +// LLFloaterModelPreview() +//----------------------------------------------------------------------------- +LLFloaterModelPreview::~LLFloaterModelPreview() +{ + sInstance = NULL; + + if ( mModelPreview->containsRiggedAsset() ) + { + gAgentAvatarp->resetJointPositions(); + } + + delete mModelPreview; + + if (mGLName) + { + LLImageGL::deleteTextures(1, &mGLName ); + } + + if (mDecompFloater) + { + mDecompFloater->closeFloater(); + mDecompFloater = NULL; + } +} + +void LLFloaterModelPreview::loadModel(S32 lod) +{ + mLoading = TRUE; + + (new LLMeshFilePicker(this, lod))->getFile(); +} + +void LLFloaterModelPreview::setLODMode(S32 lod, S32 mode) +{ + if (mode == 0) + { + if (lod != LLModel::LOD_PHYSICS) + { + for (S32 i = lod; i >= 0; i--) + { + mModelPreview->clearModel(i); + } + } + else + { + mModelPreview->clearModel(lod); + } + + mModelPreview->refresh(); + mModelPreview->calcResourceCost(); + } + else if (mode == 1) + { + loadModel(lod); + } + else if (mode != mModelPreview->mLODMode[lod]) + { + mModelPreview->mLODMode[lod] = mode; + mModelPreview->genLODs(lod); + } + + mModelPreview->setPreviewLOD(lod); + + + LLSpinCtrl* lim = getChild(limit_name[lod], TRUE); + + if (mode == 2) //triangle count + { + U32 tri_count = 0; + for (LLModelLoader::model_list::iterator iter = mModelPreview->mBaseModel.begin(); + iter != mModelPreview->mBaseModel.end(); ++iter) + { + tri_count += (*iter)->getNumTriangles(); + } + + lim->setMaxValue(tri_count); + lim->setVisible(TRUE); + } + else + { + lim->setVisible(FALSE); + } +} + +void LLFloaterModelPreview::setLimit(S32 lod, S32 limit) +{ + if (limit != mModelPreview->mLimit[lod]) + { + mModelPreview->mLimit[lod] = limit; + mModelPreview->genLODs(lod); + mModelPreview->setPreviewLOD(lod); + } +} + +//static +void LLFloaterModelPreview::onDebugScaleCommit(LLUICtrl*,void* userdata) +{ + LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; + + if (!fp->mModelPreview) + { + return; + } + + fp->mModelPreview->calcResourceCost(); +} + +//static +void LLFloaterModelPreview::onUploadJointsCommit(LLUICtrl*,void* userdata) +{ + LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; + + if (!fp->mModelPreview) + { + return; + } + + fp->mModelPreview->refresh(); +} + +//static +void LLFloaterModelPreview::onUploadSkinCommit(LLUICtrl*,void* userdata) +{ + LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; + + if (!fp->mModelPreview) + { + return; + } + + fp->mModelPreview->refresh(); + fp->mModelPreview->resetPreviewTarget(); + fp->mModelPreview->clearBuffers(); +} + +//static +void LLFloaterModelPreview::onPreviewLODCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; + + if (!fp->mModelPreview) + { + return; + } + + S32 which_mode = 0; + + LLCtrlSelectionInterface* iface = fp->childGetSelectionInterface("preview_lod_combo"); + if (iface) + { + which_mode = iface->getFirstSelectedIndex(); + } + fp->mModelPreview->setPreviewLOD(which_mode); +} + +//static +void LLFloaterModelPreview::setLODMode(S32 lod, void* userdata) +{ + LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; + + if (!fp->mModelPreview) + { + return; + } + + S32 which_mode = 0; + + std::string combo_name[] = + { + "lowest detail combo", + "low detail combo", + "medium detail combo", + "high detail combo", + "physics detail combo", + + "I went off the end of the combo_name array. Me so smart." + }; + + LLCtrlSelectionInterface* iface = fp->childGetSelectionInterface(combo_name[lod]); + if (iface) + { + which_mode = iface->getFirstSelectedIndex(); + } + + fp->setLODMode(lod, which_mode); +} + +//static +void LLFloaterModelPreview::onHighLODCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview::setLODMode(3, userdata); +} + +//static +void LLFloaterModelPreview::onMediumLODCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview::setLODMode(2, userdata); +} + +//static +void LLFloaterModelPreview::onLowLODCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview::setLODMode(1, userdata); +} + +//static +void LLFloaterModelPreview::onLowestLODCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview::setLODMode(0, userdata); +} + +//static +void LLFloaterModelPreview::onPhysicsLODCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview::setLODMode(4, userdata); +} + +//static +void LLFloaterModelPreview::setLimit(S32 lod, void* userdata) +{ + LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; + + if (!fp->mModelPreview) + { + return; + } + + S32 limit = fp->childGetValue(limit_name[lod]).asInteger(); + + + fp->setLimit(lod, limit); +} + +//static +void LLFloaterModelPreview::onHighLimitCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview::setLimit(3, userdata); +} + +//static +void LLFloaterModelPreview::onMediumLimitCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview::setLimit(2, userdata); +} + +//static +void LLFloaterModelPreview::onLowLimitCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview::setLimit(1, userdata); +} + +//static +void LLFloaterModelPreview::onLowestLimitCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview::setLimit(0, userdata); +} + +//static +void LLFloaterModelPreview::onPhysicsLimitCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview::setLimit(4, userdata); +} + +//static +void LLFloaterModelPreview::onSmoothNormalsCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; + + fp->mModelPreview->smoothNormals(); +} + +//static +void LLFloaterModelPreview::onShowEdgesCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; + + fp->mModelPreview->refresh(); +} + +//static +void LLFloaterModelPreview::onExplodeCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview* fp = LLFloaterModelPreview::sInstance; + + fp->mModelPreview->refresh(); +} + +//static +void LLFloaterModelPreview::onAutoFillCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; + + fp->mModelPreview->genLODs(); +} + + +//----------------------------------------------------------------------------- +// draw() +//----------------------------------------------------------------------------- +void LLFloaterModelPreview::draw() +{ + LLFloater::draw(); + LLRect r = getRect(); + + mModelPreview->update(); + + if (!mLoading) + { + childSetTextArg("status", "[STATUS]", getString("status_idle")); + } + + childSetTextArg("description_label", "[PRIM_COST]", llformat("%d", mModelPreview->mResourceCost)); + childSetTextArg("description_label", "[TEXTURES]", llformat("%d", mModelPreview->mTextureSet.size())); + + if (mDecompFloater) + { + if (mCurRequest.notNull()) + { + mDecompFloater->childSetText("status", mCurRequest->mStatusMessage); + } + else + { + const std::string idle("Idle."); + mDecompFloater->childSetText("status", idle); + } + } + + U32 resource_cost = mModelPreview->mResourceCost*10; + + if (childGetValue("upload_textures").asBoolean()) + { + resource_cost += mModelPreview->mTextureSet.size()*10; + } + + childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d", resource_cost)); + + if (mModelPreview) + { + gGL.color3f(1.f, 1.f, 1.f); + + gGL.getTexUnit(0)->bind(mModelPreview); + + gGL.begin( LLRender::QUADS ); + { + gGL.texCoord2f(0.f, 1.f); + gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mTop); + gGL.texCoord2f(0.f, 0.f); + gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mBottom); + gGL.texCoord2f(1.f, 0.f); + gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mBottom); + gGL.texCoord2f(1.f, 1.f); + gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mTop); + } + gGL.end(); + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + } +} + +//----------------------------------------------------------------------------- +// handleMouseDown() +//----------------------------------------------------------------------------- +BOOL LLFloaterModelPreview::handleMouseDown(S32 x, S32 y, MASK mask) +{ + if (mPreviewRect.pointInRect(x, y)) + { + bringToFront( x, y ); + gFocusMgr.setMouseCapture(this); + gViewerWindow->hideCursor(); + mLastMouseX = x; + mLastMouseY = y; + return TRUE; + } + + return LLFloater::handleMouseDown(x, y, mask); +} + +//----------------------------------------------------------------------------- +// handleMouseUp() +//----------------------------------------------------------------------------- +BOOL LLFloaterModelPreview::handleMouseUp(S32 x, S32 y, MASK mask) +{ + gFocusMgr.setMouseCapture(FALSE); + gViewerWindow->showCursor(); + return LLFloater::handleMouseUp(x, y, mask); +} + +//----------------------------------------------------------------------------- +// handleHover() +//----------------------------------------------------------------------------- +BOOL LLFloaterModelPreview::handleHover (S32 x, S32 y, MASK mask) +{ + MASK local_mask = mask & ~MASK_ALT; + + if (mModelPreview && hasMouseCapture()) + { + if (local_mask == MASK_PAN) + { + // pan here + mModelPreview->pan((F32)(x - mLastMouseX) * -0.005f, (F32)(y - mLastMouseY) * -0.005f); + } + else if (local_mask == MASK_ORBIT) + { + F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f; + F32 pitch_radians = (F32)(y - mLastMouseY) * 0.02f; + + mModelPreview->rotate(yaw_radians, pitch_radians); + } + else + { + + F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f; + F32 zoom_amt = (F32)(y - mLastMouseY) * 0.02f; + + mModelPreview->rotate(yaw_radians, 0.f); + mModelPreview->zoom(zoom_amt); + } + + + mModelPreview->refresh(); + + LLUI::setMousePositionLocal(this, mLastMouseX, mLastMouseY); + } + + if (!mPreviewRect.pointInRect(x, y) || !mModelPreview) + { + return LLFloater::handleHover(x, y, mask); + } + else if (local_mask == MASK_ORBIT) + { + gViewerWindow->setCursor(UI_CURSOR_TOOLCAMERA); + } + else if (local_mask == MASK_PAN) + { + gViewerWindow->setCursor(UI_CURSOR_TOOLPAN); + } + else + { + gViewerWindow->setCursor(UI_CURSOR_TOOLZOOMIN); + } + + return TRUE; +} + +//----------------------------------------------------------------------------- +// handleScrollWheel() +//----------------------------------------------------------------------------- +BOOL LLFloaterModelPreview::handleScrollWheel(S32 x, S32 y, S32 clicks) +{ + if (mPreviewRect.pointInRect(x, y) && mModelPreview) + { + mModelPreview->zoom((F32)clicks * -0.2f); + mModelPreview->refresh(); + } + + return TRUE; +} + +//static +void LLFloaterModelPreview::onPhysicsParamCommit(LLUICtrl* ctrl, void* data) +{ + if (LLConvexDecomposition::getInstance() == NULL) + { + llinfos << "convex decomposition tool is a stub on this platform. cannot get decomp." << llendl; + return; + } + + if (sInstance) + { + LLCDParam* param = (LLCDParam*) data; + sInstance->mDecompParams[param->mName] = ctrl->getValue(); + } +} + +//static +void LLFloaterModelPreview::onPhysicsStageExecute(LLUICtrl* ctrl, void* data) +{ + LLCDStageData* stage = (LLCDStageData*) data; + + LLModel* mdl = NULL; + + if (sInstance) + { + if (sInstance->mCurRequest.notNull()) + { + llinfos << "Decomposition request still pending." << llendl; + return; + } + + if (sInstance->mModelPreview) + { + if (sInstance->mDecompFloater) + { + S32 idx = sInstance->mDecompFloater->childGetValue("model").asInteger(); + if (idx >= 0 && idx < sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS].size()) + { + mdl = sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS][idx]; + } + } + } + } + + if (mdl) + { + sInstance->mCurRequest = new DecompRequest(stage->mName, mdl); + gMeshRepo.mDecompThread->submitRequest(sInstance->mCurRequest); + } +} + +//static +void LLFloaterModelPreview::onPhysicsStageCancel(LLUICtrl* ctrl, void*data) +{ + if (sInstance && sInstance->mCurRequest.notNull()) + { + sInstance->mCurRequest->mContinue = 0; + } +} + +void LLFloaterModelPreview::showDecompFloater() +{ + if (!mDecompFloater) + { + LLSD key; + mDecompFloater = new LLPhysicsDecompFloater(key); + + S32 left = 20; + S32 right = 320; + + S32 cur_y = 30; + + { + //add status text + LLTextBox::Params p; + p.name("status"); + p.rect(LLRect(left, cur_y, right-80, cur_y-20)); + mDecompFloater->addChild(LLUICtrlFactory::create(p)); + } + + + { //add cancel button + LLButton::Params p; + p.name("Cancel"); + p.label("Cancel"); + p.rect(LLRect(right-80, cur_y, right, cur_y-20)); + LLButton* button = LLUICtrlFactory::create(p); + button->setCommitCallback(onPhysicsStageCancel, NULL); + mDecompFloater->addChild(button); + } + + cur_y += 30; + + + static const LLCDStageData* stage = NULL; + static S32 stage_count = 0; + + if (!stage && LLConvexDecomposition::getInstance() != NULL) + { + stage_count = LLConvexDecomposition::getInstance()->getStages(&stage); + } + + static const LLCDParam* param = NULL; + static S32 param_count = 0; + if (!param && LLConvexDecomposition::getInstance() != NULL) + { + param_count = LLConvexDecomposition::getInstance()->getParameters(¶m); + } + + for (S32 j = stage_count-1; j >= 0; --j) + { + LLButton::Params p; + p.name(stage[j].mName); + p.label(stage[j].mName); + p.rect(LLRect(left, cur_y, right, cur_y-20)); + LLButton* button = LLUICtrlFactory::create(p); + button->setCommitCallback(onPhysicsStageExecute, (void*) &stage[j]); + mDecompFloater->addChild(button); + gMeshRepo.mDecompThread->mStageID[stage[j].mName] = j; + cur_y += 30; + // protected against stub by stage_count being 0 for stub above + LLConvexDecomposition::getInstance()->registerCallback(j, LLPhysicsDecomp::llcdCallback); + + llinfos << "Physics decomp stage " << stage[j].mName << " (" << j << ") parameters:" << llendl; + llinfos << "------------------------------------" << llendl; + + for (S32 i = 0; i < param_count; ++i) + { + if (param[i].mStage != j) + { + continue; + } + + std::string name(param[i].mName ? param[i].mName : ""); + std::string description(param[i].mDescription ? param[i].mDescription : ""); + + std::string type = "unknown"; + + llinfos << name << " - " << description << llendl; + + if (param[i].mType == LLCDParam::LLCD_FLOAT) + { + mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mFloat); + llinfos << "Type: float, Default: " << param[i].mDefault.mFloat << llendl; + + LLSliderCtrl::Params p; + p.name(name); + p.label(name); + p.rect(LLRect(left, cur_y, right, cur_y-20)); + p.min_value(param[i].mDetails.mRange.mLow.mFloat); + p.max_value(param[i].mDetails.mRange.mHigh.mFloat); + p.increment(param[i].mDetails.mRange.mDelta.mFloat); + p.tool_tip(description); + p.decimal_digits(3); + p.initial_value(param[i].mDefault.mFloat); + LLSliderCtrl* slider = LLUICtrlFactory::create(p); + slider->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); + mDecompFloater->addChild(slider); + cur_y += 30; + } + else if (param[i].mType == LLCDParam::LLCD_INTEGER) + { + mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue); + llinfos << "Type: integer, Default: " << param[i].mDefault.mIntOrEnumValue << llendl; + LLSliderCtrl::Params p; + p.name(name); + p.label(name); + p.rect(LLRect(left, cur_y, right, cur_y-20)); + p.min_value(param[i].mDetails.mRange.mLow.mIntOrEnumValue); + p.max_value(param[i].mDetails.mRange.mHigh.mIntOrEnumValue); + p.increment(param[i].mDetails.mRange.mDelta.mIntOrEnumValue); + p.tool_tip(description); + p.initial_value(param[i].mDefault.mIntOrEnumValue); + LLSliderCtrl* slider = LLUICtrlFactory::create(p); + slider->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); + mDecompFloater->addChild(slider); + cur_y += 30; + } + else if (param[i].mType == LLCDParam::LLCD_BOOLEAN) + { + mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mBool); + llinfos << "Type: boolean, Default: " << (param[i].mDefault.mBool ? "True" : "False") << llendl; + + LLCheckBoxCtrl::Params p; + p.rect(LLRect(left, cur_y, right, cur_y-20)); + p.name(name); + p.label(name); + p.initial_value(param[i].mDefault.mBool); + p.tool_tip(description); + LLCheckBoxCtrl* check_box = LLUICtrlFactory::create(p); + check_box->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); + mDecompFloater->addChild(check_box); + cur_y += 30; + } + else if (param[i].mType == LLCDParam::LLCD_ENUM) + { + S32 cur_x = left; + mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue); + llinfos << "Type: enum, Default: " << param[i].mDefault.mIntOrEnumValue << llendl; + + { //add label + LLTextBox::Params p; + const LLFontGL* font = (LLFontGL*) p.font(); + + p.rect(LLRect(left, cur_y, left+font->getWidth(name), cur_y-20)); + p.name(name); + p.label(name); + p.initial_value(name); + LLTextBox* text_box = LLUICtrlFactory::create(p); + mDecompFloater->addChild(text_box); + cur_x += text_box->getRect().getWidth(); + } + + { //add combo_box + LLComboBox::Params p; + p.rect(LLRect(cur_x, cur_y, right-right/4, cur_y-20)); + p.name(name); + p.label(name); + p.tool_tip(description); + + llinfos << "Accepted values: " << llendl; + LLComboBox* combo_box = LLUICtrlFactory::create(p); + for (S32 k = 0; k < param[i].mDetails.mEnumValues.mNumEnums; ++k) + { + llinfos << param[i].mDetails.mEnumValues.mEnumsArray[k].mValue + << " - " << param[i].mDetails.mEnumValues.mEnumsArray[k].mName << llendl; + + combo_box->add(param[i].mDetails.mEnumValues.mEnumsArray[k].mName, + LLSD::Integer(param[i].mDetails.mEnumValues.mEnumsArray[k].mValue)); + } + combo_box->setValue(param[i].mDefault.mIntOrEnumValue); + combo_box->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); + mDecompFloater->addChild(combo_box); + cur_y += 30; + + } + + llinfos << "----" << llendl; + } + llinfos << "-----------------------------" << llendl; + } + } + + cur_y += 30; + //explode slider + { + LLSliderCtrl::Params p; + p.initial_value(0); + p.min_value(0); + p.max_value(1); + p.decimal_digits(2); + p.increment(0.05f); + p.label("Explode"); + p.name("explode"); + p.rect(LLRect(left, cur_y, right, cur_y-20)); + LLSliderCtrl* slider = LLUICtrlFactory::create(p); + + mDecompFloater->addChild(slider); + cur_y += 30; + } + + //mesh render checkbox + { + LLCheckBoxCtrl::Params p; + p.label("Mesh: "); + p.name("render_mesh"); + p.rect(LLRect(left, cur_y, right/4, cur_y-20)); + LLCheckBoxCtrl* check = LLUICtrlFactory::create(p); + check->setValue(true); + mDecompFloater->addChild(check); + } + + //hull render checkbox + { + LLCheckBoxCtrl::Params p; + p.label("Hull: "); + p.name("render_hull"); + p.rect(LLRect(right/4, cur_y, right/2, cur_y-20)); + LLCheckBoxCtrl* check = LLUICtrlFactory::create(p); + check->setValue(true); + mDecompFloater->addChild(check); + } + + { //submesh combo box label + LLTextBox::Params p; + p.label("Model"); + p.name("model label"); + p.rect(LLRect(right/2, cur_y, right-right/3, cur_y-20)); + LLTextBox* text_box = LLUICtrlFactory::create(p); + text_box->setValue("Model"); + mDecompFloater->addChild(text_box); + } + + { + //add submesh combo box + LLComboBox::Params p; + p.rect(LLRect(right-right/2+p.font()->getWidth("Model"), cur_y, right, cur_y-20)); + p.name("model"); + LLComboBox* combo_box = LLUICtrlFactory::create(p); + for (S32 i = 0; i < mModelPreview->mBaseModel.size(); ++i) + { + LLModel* mdl = mModelPreview->mBaseModel[i]; + combo_box->add(mdl->mLabel, i); + } + combo_box->setValue(0); + mDecompFloater->addChild(combo_box); + cur_y += 30; + } + + mDecompFloater->childSetCommitCallback("model", LLFloaterModelPreview::refresh, LLFloaterModelPreview::sInstance); + mDecompFloater->childSetCommitCallback("render_mesh", LLFloaterModelPreview::refresh, LLFloaterModelPreview::sInstance); + mDecompFloater->childSetCommitCallback("render_hull", LLFloaterModelPreview::refresh, LLFloaterModelPreview::sInstance); + + mDecompFloater->setRect(LLRect(10, cur_y+20, right+20, 10)); + } + + mDecompFloater->childSetCommitCallback("explode", LLFloaterModelPreview::onExplodeCommit, this); + + mDecompFloater->openFloater(); +} + +//----------------------------------------------------------------------------- +// onMouseCaptureLost() +//----------------------------------------------------------------------------- +// static +void LLFloaterModelPreview::onMouseCaptureLostModelPreview(LLMouseHandler* handler) +{ + gViewerWindow->showCursor(); +} + +//----------------------------------------------------------------------------- +// LLModelLoader +//----------------------------------------------------------------------------- +LLModelLoader::LLModelLoader(std::string filename, S32 lod, LLModelPreview* preview) +: LLThread("Model Loader"), mFilename(filename), mLod(lod), mPreview(preview), mState(STARTING), mFirstTransform(TRUE) +{ + mJointMap["mPelvis"] = "mPelvis"; + mJointMap["mTorso"] = "mTorso"; + mJointMap["mChest"] = "mChest"; + mJointMap["mNeck"] = "mNeck"; + mJointMap["mHead"] = "mHead"; + mJointMap["mSkull"] = "mSkull"; + mJointMap["mEyeRight"] = "mEyeRight"; + mJointMap["mEyeLeft"] = "mEyeLeft"; + mJointMap["mCollarLeft"] = "mCollarLeft"; + mJointMap["mShoulderLeft"] = "mShoulderLeft"; + mJointMap["mElbowLeft"] = "mElbowLeft"; + mJointMap["mWristLeft"] = "mWristLeft"; + mJointMap["mCollarRight"] = "mCollarRight"; + mJointMap["mShoulderRight"] = "mShoulderRight"; + mJointMap["mElbowRight"] = "mElbowRight"; + mJointMap["mWristRight"] = "mWristRight"; + mJointMap["mHipRight"] = "mHipRight"; + mJointMap["mKneeRight"] = "mKneeRight"; + mJointMap["mAnkleRight"] = "mAnkleRight"; + mJointMap["mFootRight"] = "mFootRight"; + mJointMap["mToeRight"] = "mToeRight"; + mJointMap["mHipLeft"] = "mHipLeft"; + mJointMap["mKneeLeft"] = "mKneeLeft"; + mJointMap["mAnkleLeft"] = "mAnkleLeft"; + mJointMap["mFootLeft"] = "mFootLeft"; + mJointMap["mToeLeft"] = "mToeLeft"; + + mJointMap["avatar_mPelvis"] = "mPelvis"; + mJointMap["avatar_mTorso"] = "mTorso"; + mJointMap["avatar_mChest"] = "mChest"; + mJointMap["avatar_mNeck"] = "mNeck"; + mJointMap["avatar_mHead"] = "mHead"; + mJointMap["avatar_mSkull"] = "mSkull"; + mJointMap["avatar_mEyeRight"] = "mEyeRight"; + mJointMap["avatar_mEyeLeft"] = "mEyeLeft"; + mJointMap["avatar_mCollarLeft"] = "mCollarLeft"; + mJointMap["avatar_mShoulderLeft"] = "mShoulderLeft"; + mJointMap["avatar_mElbowLeft"] = "mElbowLeft"; + mJointMap["avatar_mWristLeft"] = "mWristLeft"; + mJointMap["avatar_mCollarRight"] = "mCollarRight"; + mJointMap["avatar_mShoulderRight"] = "mShoulderRight"; + mJointMap["avatar_mElbowRight"] = "mElbowRight"; + mJointMap["avatar_mWristRight"] = "mWristRight"; + mJointMap["avatar_mHipRight"] = "mHipRight"; + mJointMap["avatar_mKneeRight"] = "mKneeRight"; + mJointMap["avatar_mAnkleRight"] = "mAnkleRight"; + mJointMap["avatar_mFootRight"] = "mFootRight"; + mJointMap["avatar_mToeRight"] = "mToeRight"; + mJointMap["avatar_mHipLeft"] = "mHipLeft"; + mJointMap["avatar_mKneeLeft"] = "mKneeLeft"; + mJointMap["avatar_mAnkleLeft"] = "mAnkleLeft"; + mJointMap["avatar_mFootLeft"] = "mFootLeft"; + mJointMap["avatar_mToeLeft"] = "mToeLeft"; + + + mJointMap["hip"] = "mPelvis"; + mJointMap["abdomen"] = "mTorso"; + mJointMap["chest"] = "mChest"; + mJointMap["neck"] = "mNeck"; + mJointMap["head"] = "mHead"; + mJointMap["figureHair"] = "mSkull"; + mJointMap["lCollar"] = "mCollarLeft"; + mJointMap["lShldr"] = "mShoulderLeft"; + mJointMap["lForeArm"] = "mElbowLeft"; + mJointMap["lHand"] = "mWristLeft"; + mJointMap["rCollar"] = "mCollarRight"; + mJointMap["rShldr"] = "mShoulderRight"; + mJointMap["rForeArm"] = "mElbowRight"; + mJointMap["rHand"] = "mWristRight"; + mJointMap["rThigh"] = "mHipRight"; + mJointMap["rShin"] = "mKneeRight"; + mJointMap["rFoot"] = "mFootRight"; + mJointMap["lThigh"] = "mHipLeft"; + mJointMap["lShin"] = "mKneeLeft"; + mJointMap["lFoot"] = "mFootLeft"; +} + +void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, BOOL& first_transform) +{ + LLVector4a box[] = + { + LLVector4a(-1, 1,-1), + LLVector4a(-1, 1, 1), + LLVector4a(-1,-1,-1), + LLVector4a(-1,-1, 1), + LLVector4a( 1, 1,-1), + LLVector4a( 1, 1, 1), + LLVector4a( 1,-1,-1), + LLVector4a( 1,-1, 1), + }; + + for (S32 j = 0; j < model->getNumVolumeFaces(); ++j) + { + const LLVolumeFace& face = model->getVolumeFace(j); + + LLVector4a center; + center.setAdd(face.mExtents[0], face.mExtents[1]); + center.mul(0.5f); + LLVector4a size; + size.setSub(face.mExtents[1],face.mExtents[0]); + size.mul(0.5f); + + for (U32 i = 0; i < 8; i++) + { + LLVector4a t; + t.setMul(size, box[i]); + t.add(center); + + LLVector4a v; + + mat.affineTransform(t, v); + + if (first_transform) + { + first_transform = FALSE; + min = max = v; + } + else + { + update_min_max(min, max, v); + } + } + } +} + +void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& max, BOOL& first_transform) +{ + LLVector4a mina, maxa; + LLMatrix4a mata; + + mata.loadu(mat); + mina.load3(min.mV); + maxa.load3(max.mV); + + stretch_extents(model, mata, mina, maxa, first_transform); + + min.set(mina.getF32ptr()); + max.set(maxa.getF32ptr()); +} + +void LLModelLoader::run() +{ + DAE dae; + domCOLLADA* dom = dae.open(mFilename); + + if (dom) + { + daeDatabase* db = dae.getDatabase(); + + daeInt count = db->getElementCount(NULL, COLLADA_TYPE_MESH); + + daeDocument* doc = dae.getDoc(mFilename); + if (!doc) + { + llwarns << "can't find internal doc" << llendl; + return; + } + + daeElement* root = doc->getDomRoot(); + if (!root) + { + llwarns << "document has no root" << llendl; + return; + } + + //get unit scale + mTransform.setIdentity(); + + domAsset::domUnit* unit = daeSafeCast(root->getDescendant(daeElement::matchType(domAsset::domUnit::ID()))); + + if (unit) + { + F32 meter = unit->getMeter(); + mTransform.mMatrix[0][0] = meter; + mTransform.mMatrix[1][1] = meter; + mTransform.mMatrix[2][2] = meter; + } + + //get up axis rotation + LLMatrix4 rotation; + + domUpAxisType up = UPAXISTYPE_Y_UP; // default is Y_UP + domAsset::domUp_axis* up_axis = + daeSafeCast(root->getDescendant(daeElement::matchType(domAsset::domUp_axis::ID()))); + + if (up_axis) + { + up = up_axis->getValue(); + } + + if (up == UPAXISTYPE_X_UP) + { + rotation.initRotation(0.0f, 90.0f * DEG_TO_RAD, 0.0f); + } + else if (up == UPAXISTYPE_Y_UP) + { + rotation.initRotation(90.0f * DEG_TO_RAD, 0.0f, 0.0f); + } + + rotation *= mTransform; + mTransform = rotation; + + + for (daeInt idx = 0; idx < count; ++idx) + { //build map of domEntities to LLModel + domMesh* mesh = NULL; + db->getElement((daeElement**) &mesh, idx, NULL, COLLADA_TYPE_MESH); + + if (mesh) + { + LLPointer model = LLModel::loadModelFromDomMesh(mesh); + + if (model.notNull() && validate_model(model)) + { + mModelList.push_back(model); + mModel[mesh] = model; + } + } + } + + count = db->getElementCount(NULL, COLLADA_TYPE_SKIN); + for (daeInt idx = 0; idx < count; ++idx) + { //add skinned meshes as instances + domSkin* skin = NULL; + db->getElement((daeElement**) &skin, idx, NULL, COLLADA_TYPE_SKIN); + + if (skin) + { + domGeometry* geom = daeSafeCast(skin->getSource().getElement()); + + if (geom) + { + domMesh* mesh = geom->getMesh(); + if (mesh) + { + LLModel* model = mModel[mesh]; + if (model) + { + LLVector3 mesh_scale_vector; + LLVector3 mesh_translation_vector; + model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); + + LLMatrix4 normalized_transformation; + normalized_transformation.setTranslation(mesh_translation_vector); + + LLMatrix4 mesh_scale; + mesh_scale.initScale(mesh_scale_vector); + mesh_scale *= normalized_transformation; + normalized_transformation = mesh_scale; + + glh::matrix4f inv_mat((F32*) normalized_transformation.mMatrix); + inv_mat = inv_mat.inverse(); + LLMatrix4 inverse_normalized_transformation(inv_mat.m); + + domSkin::domBind_shape_matrix* bind_mat = skin->getBind_shape_matrix(); + + if (bind_mat) + { //get bind shape matrix + domFloat4x4& dom_value = bind_mat->getValue(); + + for (int i = 0; i < 4; i++) + { + for(int j = 0; j < 4; j++) + { + model->mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j*4]; + } + } + + LLMatrix4 trans = normalized_transformation; + trans *= model->mBindShapeMatrix; + model->mBindShapeMatrix = trans; + + } + + /*{ + LLMatrix4 rotation; + if (up == UPAXISTYPE_X_UP) + { + rotation.initRotation(0.0f, 90.0f * DEG_TO_RAD, 0.0f); + } + else if (up == UPAXISTYPE_Z_UP) + { + rotation.initRotation(90.0f * DEG_TO_RAD, 90.0f * DEG_TO_RAD, 0.0f); + } + + rotation *= model->mBindShapeMatrix; + model->mBindShapeMatrix = rotation; + }*/ + + //The joint transfom map that we'll populate below + std::map jointTransforms; + jointTransforms.clear(); + + //Some collada setup for accessing the skeleton + daeElement* pElement = 0; + dae.getDatabase()->getElement( &pElement, 0, 0, "skeleton" ); + domInstance_controller::domSkeleton* pSkeleton = daeSafeCast( pElement ); + if ( pSkeleton ) + { + //Get the root node of the skeleton + daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement(); + if ( pSkeletonRootNode ) + { + //Once we have the root node - start acccessing it's joint components + const int jointCnt = mJointMap.size(); + std::map :: const_iterator jointIt = mJointMap.begin(); + bool missingID = false; + //Loop over all the possible joints within the .dae - using the allowed joint list in the ctor. + for ( int i=0; i(resolver.getElement()); + if ( pJoint ) + { + //Pull out the translate id and store it in the jointTranslations map + daeSIDResolver jointResolver( pJoint, "./translate" ); + domTranslate* pTranslate = daeSafeCast( jointResolver.getElement() ); + + LLMatrix4 workingTransform; + + //Translation + if ( pTranslate ) + { + domFloat3 jointTrans = pTranslate->getValue(); + LLVector3 singleJointTranslation( jointTrans[0], jointTrans[1], jointTrans[2] ); + workingTransform.setTranslation( singleJointTranslation ); + } + else + { + missingID = true; + llwarns<< "No translation sid!" << llendl; + } + //Store the joint transform w/respect to it's name. + jointTransforms[(*jointIt).second.c_str()] = workingTransform; + + } + else + { + missingID = true; + llwarns<< "Missing joint." << llendl; + } + } + + //If anything failed in regards to extracting the skeleton, joints or translation id, + //mention it + if ( missingID ) + { + llwarns<< "Partial jointmap found in asset - did you mean to just have a partial map?" << llendl; + } + + //Set the joint translations on the avatar + //The joints are reset in the dtor + jointIt = mJointMap.begin(); + for ( int i=0; igetJoint( lookingForJoint ); + if ( pJoint ) + { + pJoint->storeCurrentXform( jointTransform.getTranslation() ); + } + else + { + //Most likely an error in the asset. + llwarns<<"Tried to apply joint position from .dae, but it did not exist in the avatar rig." << llendl; + } + //Reposition the avatars pelvis (avPos+offset) + //if ( !strcmp( (*jointIt).first.c_str(),"mPelvis" ) ) + if ( lookingForJoint == "mPelvis" ) + { + const LLVector3& pos = gAgentAvatarp->getCharacterPosition(); + gAgentAvatarp->setPelvisOffset( true, jointTransform.getTranslation() ); + gAgentAvatarp->setPosition( pos + jointTransform.getTranslation() ); + } + } + } + } + else + { + llwarns<<"No root node in this skeleton" << llendl; + } + } + else + { + llwarns<<"No skeleton in this asset" << llendl; + } + + domSkin::domJoints* joints = skin->getJoints(); + + domInputLocal_Array& joint_input = joints->getInput_array(); + + for (size_t i = 0; i < joint_input.getCount(); ++i) + { + domInputLocal* input = joint_input.get(i); + xsNMTOKEN semantic = input->getSemantic(); + + if (strcmp(semantic, COMMON_PROFILE_INPUT_JOINT) == 0) + { //found joint source, fill model->mJointMap and model->mJointList + daeElement* elem = input->getSource().getElement(); + + domSource* source = daeSafeCast(elem); + if (source) + { + + + domName_array* names_source = source->getName_array(); + + if (names_source) + { + domListOfNames &names = names_source->getValue(); + + for (size_t j = 0; j < names.getCount(); ++j) + { + std::string name(names.get(j)); + if (mJointMap.find(name) != mJointMap.end()) + { + name = mJointMap[name]; + } + model->mJointList.push_back(name); + model->mJointMap[name] = j; + } + } + else + { + domIDREF_array* names_source = source->getIDREF_array(); + if (names_source) + { + xsIDREFS& names = names_source->getValue(); + + for (size_t j = 0; j < names.getCount(); ++j) + { + std::string name(names.get(j).getID()); + if (mJointMap.find(name) != mJointMap.end()) + { + name = mJointMap[name]; + } + model->mJointList.push_back(name); + model->mJointMap[name] = j; + } + } + } + } + } + else if (strcmp(semantic, COMMON_PROFILE_INPUT_INV_BIND_MATRIX) == 0) + { //found inv_bind_matrix array, fill model->mInvBindMatrix + domSource* source = daeSafeCast(input->getSource().getElement()); + if (source) + { + domFloat_array* t = source->getFloat_array(); + if (t) + { + domListOfFloats& transform = t->getValue(); + S32 count = transform.getCount()/16; + + for (S32 k = 0; k < count; ++k) + { + LLMatrix4 mat; + + for (int i = 0; i < 4; i++) + { + for(int j = 0; j < 4; j++) + { + mat.mMatrix[i][j] = transform[k*16 + i + j*4]; + } + } + + model->mInvBindMatrix.push_back(mat); + } + } + } + } + } + + //We need to construct the alternate bind matrix (which contains the new joint positions) + //in the same order as they were stored in the joint buffer. The joints associated + //with the skeleton are not stored in the same order as they are in the exported joint buffer. + //This remaps the skeletal joints to be in the same order as the joints stored in the model. + std::vector :: const_iterator jointIt = model->mJointList.begin(); + const int jointCnt = model->mJointList.size(); + for ( int i=0; imInvBindMatrix[i]; + newInverse.setTranslation( jointTransforms[lookingForJoint].getTranslation() ); + model->mAlternateBindMatrix.push_back( newInverse ); + } + else + { + llwarns<<"Possibly misnamed/missing joint [" <getVertices(); + if (verts) + { + domInputLocal_Array& inputs = verts->getInput_array(); + for (size_t i = 0; i < inputs.getCount() && model->mPosition.empty(); ++i) + { + if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_POSITION) == 0) + { + domSource* pos_source = daeSafeCast(inputs[i]->getSource().getElement()); + if (pos_source) + { + domFloat_array* pos_array = pos_source->getFloat_array(); + if (pos_array) + { + domListOfFloats& pos = pos_array->getValue(); + + for (size_t j = 0; j < pos.getCount(); j += 3) + { + if (pos.getCount() <= j+2) + { + llerrs << "WTF?" << llendl; + } + + LLVector3 v(pos[j], pos[j+1], pos[j+2]); + + //transform from COLLADA space to volume space + v = v * inverse_normalized_transformation; + + model->mPosition.push_back(v); + } + } + } + } + } + } + + //grab skin weights array + domSkin::domVertex_weights* weights = skin->getVertex_weights(); + if (weights) + { + domInputLocalOffset_Array& inputs = weights->getInput_array(); + domFloat_array* vertex_weights = NULL; + for (size_t i = 0; i < inputs.getCount(); ++i) + { + if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_WEIGHT) == 0) + { + domSource* weight_source = daeSafeCast(inputs[i]->getSource().getElement()); + if (weight_source) + { + vertex_weights = weight_source->getFloat_array(); + } + } + } + + if (vertex_weights) + { + domListOfFloats& w = vertex_weights->getValue(); + domListOfUInts& vcount = weights->getVcount()->getValue(); + domListOfInts& v = weights->getV()->getValue(); + + U32 c_idx = 0; + for (size_t vc_idx = 0; vc_idx < vcount.getCount(); ++vc_idx) + { //for each vertex + daeUInt count = vcount[vc_idx]; + + //create list of weights that influence this vertex + LLModel::weight_list weight_list; + + for (daeUInt i = 0; i < count; ++i) + { //for each weight + daeInt joint_idx = v[c_idx++]; + daeInt weight_idx = v[c_idx++]; + + if (joint_idx == -1) + { + //ignore bindings to bind_shape_matrix + continue; + } + + F32 weight_value = w[weight_idx]; + + weight_list.push_back(LLModel::JointWeight(joint_idx, weight_value)); + } + + //sort by joint weight + std::sort(weight_list.begin(), weight_list.end(), LLModel::CompareWeightGreater()); + + std::vector wght; + + F32 total = 0.f; + + for (U32 i = 0; i < llmin((U32) 4, (U32) weight_list.size()); ++i) + { //take up to 4 most significant weights + if (weight_list[i].mWeight > 0.f) + { + wght.push_back( weight_list[i] ); + total += weight_list[i].mWeight; + } + } + + F32 scale = 1.f/total; + if (scale != 1.f) + { //normalize weights + for (U32 i = 0; i < wght.size(); ++i) + { + wght[i].mWeight *= scale; + } + } + + model->mSkinWeights[model->mPosition[vc_idx]] = wght; + } + + //add instance to scene for this model + + LLMatrix4 transform; + std::vector materials; + materials.resize(model->getNumVolumeFaces()); + mScene[transform].push_back(LLModelInstance(model, transform, materials)); + stretch_extents(model, transform, mExtents[0], mExtents[1], mFirstTransform); + } + } + } + } + } + } + } + + daeElement* scene = root->getDescendant("visual_scene"); + if (!scene) + { + llwarns << "document has no visual_scene" << llendl; + return; + } + + processElement(scene); + + mPreview->loadModelCallback(mLod); + } +} + +void LLModelLoader::processElement(daeElement* element) +{ + LLMatrix4 saved_transform = mTransform; + + domTranslate* translate = daeSafeCast(element); + if (translate) + { + domFloat3 dom_value = translate->getValue(); + + LLMatrix4 translation; + translation.setTranslation(LLVector3(dom_value[0], dom_value[1], dom_value[2])); + + translation *= mTransform; + mTransform = translation; + } + + domRotate* rotate = daeSafeCast(element); + if (rotate) + { + domFloat4 dom_value = rotate->getValue(); + + LLMatrix4 rotation; + rotation.initRotTrans(dom_value[3] * DEG_TO_RAD, LLVector3(dom_value[0], dom_value[1], dom_value[2]), LLVector3(0, 0, 0)); + + rotation *= mTransform; + mTransform = rotation; + } + + domScale* scale = daeSafeCast(element); + if (scale) + { + domFloat3 dom_value = scale->getValue(); + + LLMatrix4 scaling; + scaling.initScale(LLVector3(dom_value[0], dom_value[1], dom_value[2])); + + scaling *= mTransform; + mTransform = scaling; + } + + domMatrix* matrix = daeSafeCast(element); + if (matrix) + { + domFloat4x4 dom_value = matrix->getValue(); + + LLMatrix4 matrix_transform; + + for (int i = 0; i < 4; i++) + { + for(int j = 0; j < 4; j++) + { + matrix_transform.mMatrix[i][j] = dom_value[i + j*4]; + } + } + + matrix_transform *= mTransform; + mTransform = matrix_transform; + } + + domInstance_geometry* instance_geo = daeSafeCast(element); + if (instance_geo) + { + domGeometry* geo = daeSafeCast(instance_geo->getUrl().getElement()); + if (geo) + { + domMesh* mesh = daeSafeCast(geo->getDescendant(daeElement::matchType(domMesh::ID()))); + if (mesh) + { + LLModel* model = mModel[mesh]; + if (model) + { + LLMatrix4 transformation = mTransform; + + std::vector materials = getMaterials(model, instance_geo); + + // adjust the transformation to compensate for mesh normalization + LLVector3 mesh_scale_vector; + LLVector3 mesh_translation_vector; + model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); + + LLMatrix4 mesh_translation; + mesh_translation.setTranslation(mesh_translation_vector); + mesh_translation *= transformation; + transformation = mesh_translation; + + LLMatrix4 mesh_scale; + mesh_scale.initScale(mesh_scale_vector); + mesh_scale *= transformation; + transformation = mesh_scale; + + mScene[transformation].push_back(LLModelInstance(model, transformation, materials)); + + stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); + } + } + } + } + + domInstance_node* instance_node = daeSafeCast(element); + if (instance_node) + { + daeElement* instance = instance_node->getUrl().getElement(); + if (instance) + { + processElement(instance); + } + } + + //process children + daeTArray< daeSmartRef > children = element->getChildren(); + for (S32 i = 0; i < children.getCount(); i++) + { + processElement(children[i]); + } + + domNode* node = daeSafeCast(element); + if (node) + { //this element was a node, restore transform before processiing siblings + mTransform = saved_transform; + } +} + +std::vector LLModelLoader::getMaterials(LLModel* model, domInstance_geometry* instance_geo) +{ + std::vector materials; + for (int i = 0; i < model->mMaterialList.size(); i++) + { + LLImportMaterial import_material; + + domInstance_material* instance_mat = NULL; + + domBind_material::domTechnique_common* technique = + daeSafeCast(instance_geo->getDescendant(daeElement::matchType(domBind_material::domTechnique_common::ID()))); + + if (technique) + { + daeTArray< daeSmartRef > inst_materials = technique->getChildrenByType(); + for (int j = 0; j < inst_materials.getCount(); j++) + { + std::string symbol(inst_materials[j]->getSymbol()); + + if (symbol == model->mMaterialList[i]) // found the binding + { + instance_mat = inst_materials[j]; + } + } + } + + if (instance_mat) + { + domMaterial* material = daeSafeCast(instance_mat->getTarget().getElement()); + if (material) + { + domInstance_effect* instance_effect = + daeSafeCast(material->getDescendant(daeElement::matchType(domInstance_effect::ID()))); + if (instance_effect) + { + domEffect* effect = daeSafeCast(instance_effect->getUrl().getElement()); + if (effect) + { + domProfile_COMMON* profile = + daeSafeCast(effect->getDescendant(daeElement::matchType(domProfile_COMMON::ID()))); + if (profile) + { + import_material = profileToMaterial(profile); + } + } + } + } + } + + materials.push_back(import_material); + } + + return materials; +} + +LLImportMaterial LLModelLoader::profileToMaterial(domProfile_COMMON* material) +{ + LLImportMaterial mat; + mat.mFullbright = FALSE; + + daeElement* diffuse = material->getDescendant("diffuse"); + if (diffuse) + { + domCommon_color_or_texture_type_complexType::domTexture* texture = + daeSafeCast(diffuse->getDescendant("texture")); + if (texture) + { + domCommon_newparam_type_Array newparams = material->getNewparam_array(); + for (S32 i = 0; i < newparams.getCount(); i++) + { + domFx_surface_common* surface = newparams[i]->getSurface(); + if (surface) + { + domFx_surface_init_common* init = surface->getFx_surface_init_common(); + if (init) + { + domFx_surface_init_from_common_Array init_from = init->getInit_from_array(); + + if (init_from.getCount() > i) + { + domImage* image = daeSafeCast(init_from[i]->getValue().getElement()); + if (image) + { + // we only support init_from now - embedded data will come later + domImage::domInit_from* init = image->getInit_from(); + if (init) + { + std::string filename = cdom::uriToNativePath(init->getValue().str()); + + mat.mDiffuseMap = LLViewerTextureManager::getFetchedTextureFromUrl("file://" + filename, TRUE, LLViewerTexture::BOOST_PREVIEW); + mat.mDiffuseMap->setLoadedCallback(LLModelPreview::textureLoadedCallback, 0, TRUE, FALSE, this->mPreview, NULL, FALSE); + + mat.mDiffuseMap->forceToSaveRawImage(); + mat.mDiffuseMapFilename = filename; + mat.mDiffuseMapLabel = getElementLabel(material); + } + } + } + } + } + } + } + + domCommon_color_or_texture_type_complexType::domColor* color = + daeSafeCast(diffuse->getDescendant("color")); + if (color) + { + domFx_color_common domfx_color = color->getValue(); + LLColor4 value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]); + mat.mDiffuseColor = value; + } + } + + daeElement* emission = material->getDescendant("emission"); + if (emission) + { + LLColor4 emission_color = getDaeColor(emission); + if (((emission_color[0] + emission_color[1] + emission_color[2]) / 3.0) > 0.25) + { + mat.mFullbright = TRUE; + } + } + + return mat; +} + +// try to get a decent label for this element +std::string LLModelLoader::getElementLabel(daeElement *element) +{ + // if we have a name attribute, use it + std::string name = element->getAttribute("name"); + if (name.length()) + { + return name; + } + + // if we have an ID attribute, use it + if (element->getID()) + { + return std::string(element->getID()); + } + + // if we have a parent, use it + daeElement* parent = element->getParent(); + if (parent) + { + // if parent has a name, use it + std::string name = parent->getAttribute("name"); + if (name.length()) + { + return name; + } + + // if parent has an ID, use it + if (parent->getID()) + { + return std::string(parent->getID()); + } + } + + // try to use our type + daeString element_name = element->getElementName(); + if (element_name) + { + return std::string(element_name); + } + + // if all else fails, use "object" + return std::string("object"); +} + +LLColor4 LLModelLoader::getDaeColor(daeElement* element) +{ + LLColor4 value; + domCommon_color_or_texture_type_complexType::domColor* color = + daeSafeCast(element->getDescendant("color")); + if (color) + { + domFx_color_common domfx_color = color->getValue(); + value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]); + } + + return value; +} + +//----------------------------------------------------------------------------- +// LLModelPreview +//----------------------------------------------------------------------------- + +LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloaterModelPreview* fmp) +: LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE), LLMutex(NULL) +{ + mNeedsUpdate = TRUE; + mCameraDistance = 0.f; + mCameraYaw = 0.f; + mCameraPitch = 0.f; + mCameraZoom = 1.f; + mTextureName = 0; + mPreviewLOD = 3; + mModelLoader = NULL; + mDirty = false; + + for (U32 i = 0; i < LLModel::NUM_LODS; i++) + { + mLODMode[i] = 1; + mLimit[i] = 0; + } + + mLODMode[0] = 0; + + mFMP = fmp; + + glodInit(); +} + +LLModelPreview::~LLModelPreview() +{ + if (mModelLoader) + { + delete mModelLoader; + mModelLoader = NULL; + } + + //*HACK : *TODO : turn this back on when we understand why this crashes + //glodShutdown(); +} + +U32 LLModelPreview::calcResourceCost() +{ + rebuildUploadData(); + + U32 cost = 0; + std::set accounted; + U32 num_points = 0; + U32 num_hulls = 0; + + F32 debug_scale = mFMP->childGetValue("debug scale").asReal(); + + F32 streaming_cost = 0.f; + + for (U32 i = 0; i < mUploadData.size(); ++i) + { + LLModelInstance& instance = mUploadData[i]; + + if (accounted.find(instance.mModel) == accounted.end()) + { + accounted.insert(instance.mModel); + + LLModel::convex_hull_decomposition& decomp = + instance.mLOD[LLModel::LOD_PHYSICS] ? + instance.mLOD[LLModel::LOD_PHYSICS]->mConvexHullDecomp : + instance.mModel->mConvexHullDecomp; + + LLSD ret = LLModel::writeModel( + "", + instance.mLOD[4], + instance.mLOD[3], + instance.mLOD[2], + instance.mLOD[1], + instance.mLOD[0], + decomp, + mFMP->childGetValue("upload_skin").asBoolean(), + mFMP->childGetValue("upload_joints").asBoolean(), + TRUE); + cost += gMeshRepo.calcResourceCost(ret); + + num_hulls += decomp.size(); + for (U32 i = 0; i < decomp.size(); ++i) + { + num_points += decomp[i].size(); + } + + //calculate streaming cost + LLMatrix4 transformation = instance.mTransform; + + LLVector3 position = LLVector3(0, 0, 0) * transformation; + + LLVector3 x_transformed = LLVector3(1, 0, 0) * transformation - position; + LLVector3 y_transformed = LLVector3(0, 1, 0) * transformation - position; + LLVector3 z_transformed = LLVector3(0, 0, 1) * transformation - position; + F32 x_length = x_transformed.normalize(); + F32 y_length = y_transformed.normalize(); + F32 z_length = z_transformed.normalize(); + LLVector3 scale = LLVector3(x_length, y_length, z_length); + + F32 radius = scale.length()*debug_scale; + + streaming_cost += LLMeshRepository::getStreamingCost(ret, radius); + } + } + + mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[HULLS]", llformat("%d",num_hulls)); + mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[POINTS]", llformat("%d",num_points)); + mFMP->childSetTextArg("streaming cost", "[COST]", llformat("%.3f", streaming_cost)); + F32 scale = mFMP->childGetValue("debug scale").asReal()*2.f; + mFMP->childSetTextArg("dimensions", "[X]", llformat("%.3f", mPreviewScale[0]*scale)); + mFMP->childSetTextArg("dimensions", "[Y]", llformat("%.3f", mPreviewScale[1]*scale)); + mFMP->childSetTextArg("dimensions", "[Z]", llformat("%.3f", mPreviewScale[2]*scale)); + + updateStatusMessages(); + + return cost; +} + +void LLModelPreview::rebuildUploadData() +{ + mUploadData.clear(); + mTextureSet.clear(); + + //fill uploaddata instance vectors from scene data + + LLSpinCtrl* scale_spinner = mFMP->getChild("debug scale"); + + if (!scale_spinner) + { + llerrs << "floater_model_preview.xml MUST contain debug scale spinner." << llendl; + } + + F32 scale = scale_spinner->getValue().asReal(); + + LLMatrix4 scale_mat; + scale_mat.initScale(LLVector3(scale, scale, scale)); + + F32 max_scale = 0.f; + + for (LLModelLoader::scene::iterator iter = mBaseScene.begin(); iter != mBaseScene.end(); ++iter) + { //for each transform in scene + LLMatrix4 mat = iter->first; + + // compute position + LLVector3 position = LLVector3(0, 0, 0) * mat; + + // compute scale + LLVector3 x_transformed = LLVector3(1, 0, 0) * mat - position; + LLVector3 y_transformed = LLVector3(0, 1, 0) * mat - position; + LLVector3 z_transformed = LLVector3(0, 0, 1) * mat - position; + F32 x_length = x_transformed.normalize(); + F32 y_length = y_transformed.normalize(); + F32 z_length = z_transformed.normalize(); + + max_scale = llmax(llmax(llmax(max_scale, x_length), y_length), z_length); + + mat *= scale_mat; + + for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) + { //for each instance with said transform applied + LLModelInstance instance = *model_iter; + + LLModel* base_model = instance.mModel; + + S32 idx = 0; + for (idx = 0; idx < mBaseModel.size(); ++idx) + { //find reference instance for this model + if (mBaseModel[idx] == base_model) + { + break; + } + } + + for (U32 i = 0; i < LLModel::NUM_LODS; i++) + { //fill LOD slots based on reference model index + if (!mModel[i].empty()) + { + instance.mLOD[i] = mModel[i][idx]; + } + else + { + instance.mLOD[i] = NULL; + } + } + + instance.mTransform = mat; + mUploadData.push_back(instance); + } + } + + F32 max_import_scale = DEFAULT_MAX_PRIM_SCALE/max_scale; + + scale_spinner->setMaxValue(max_import_scale); + + if (max_import_scale < scale) + { + scale_spinner->setValue(max_import_scale); + } +} + + +void LLModelPreview::clearModel(S32 lod) +{ + if (lod < 0 || lod > LLModel::LOD_PHYSICS) + { + return; + } + + mVertexBuffer[lod].clear(); + mModel[lod].clear(); + mScene[lod].clear(); +} + +void LLModelPreview::loadModel(std::string filename, S32 lod) +{ + LLMutexLock lock(this); + + if (mModelLoader) + { + delete mModelLoader; + mModelLoader = NULL; + } + + if (filename.empty()) + { + if (mBaseModel.empty()) + { + // this is the initial file picking. Close the whole floater + // if we don't have a base model to show for high LOD. + mFMP->closeFloater(false); + } + + mFMP->mLoading = false; + return; + } + + if (lod == 3 && !mGroup.empty()) + { + for (std::map, U32>::iterator iter = mGroup.begin(); iter != mGroup.end(); ++iter) + { + glodDeleteGroup(iter->second); + stop_gloderror(); + } + + for (std::map, U32>::iterator iter = mObject.begin(); iter != mObject.end(); ++iter) + { + glodDeleteObject(iter->second); + stop_gloderror(); + } + + mGroup.clear(); + mObject.clear(); + } + + mModelLoader = new LLModelLoader(filename, lod, this); + + mModelLoader->start(); + + mFMP->childSetTextArg("status", "[STATUS]", mFMP->getString("status_reading_file")); + + if (mFMP->childGetValue("description_form").asString().empty()) + { + std::string name = gDirUtilp->getBaseFileName(filename, true); + mFMP->childSetValue("description_form", name); + } + + mFMP->openFloater(); +} + +void LLModelPreview::clearIncompatible(S32 lod) +{ + for (U32 i = 0; i <= LLModel::LOD_HIGH; i++) + { //clear out any entries that aren't compatible with this model + if (i != lod) + { + if (mModel[i].size() != mModel[lod].size()) + { + mModel[i].clear(); + mScene[i].clear(); + mVertexBuffer[i].clear(); + + if (i == LLModel::LOD_HIGH) + { + mBaseModel = mModel[lod]; + mBaseScene = mScene[lod]; + mVertexBuffer[5].clear(); + } + } + } + } +} + +void LLModelPreview::loadModelCallback(S32 lod) +{ //NOT the main thread + LLMutexLock lock(this); + if (!mModelLoader) + { + return; + } + + mModel[lod] = mModelLoader->mModelList; + mScene[lod] = mModelLoader->mScene; + mVertexBuffer[lod].clear(); + + if (lod == LLModel::LOD_PHYSICS) + { + mPhysicsMesh.clear(); + } + + setPreviewLOD(lod); + + + if (lod == LLModel::LOD_HIGH) + { //save a copy of the highest LOD for automatic LOD manipulation + mBaseModel = mModel[lod]; + mBaseScene = mScene[lod]; + mVertexBuffer[5].clear(); + //mModel[lod] = NULL; + } + + clearIncompatible(lod); + + mDirty = true; + + resetPreviewTarget(); + + mFMP->mLoading = FALSE; + refresh(); +} + +void LLModelPreview::resetPreviewTarget() +{ + mPreviewTarget = (mModelLoader->mExtents[0] + mModelLoader->mExtents[1]) * 0.5f; + mPreviewScale = (mModelLoader->mExtents[1] - mModelLoader->mExtents[0]) * 0.5f; + setPreviewTarget(mPreviewScale.magVec()*2.f); +} + +void LLModelPreview::smoothNormals() +{ + S32 which_lod = mPreviewLOD; + + + if (which_lod > 4 || which_lod < 0 || + mModel[which_lod].empty()) + { + return; + } + + F32 angle_cutoff = mFMP->childGetValue("edge threshold").asReal(); + + angle_cutoff *= DEG_TO_RAD; + + if (which_lod == 3 && !mBaseModel.empty()) + { + for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) + { + (*iter)->smoothNormals(angle_cutoff); + } + + mVertexBuffer[5].clear(); + } + + for (LLModelLoader::model_list::iterator iter = mModel[which_lod].begin(); iter != mModel[which_lod].end(); ++iter) + { + (*iter)->smoothNormals(angle_cutoff); + } + + mVertexBuffer[which_lod].clear(); + refresh(); + +} + +void LLModelPreview::consolidate() +{ + std::map > composite; + + LLMatrix4 identity; + + //bake out each node in current scene to composite + for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) + { //for each transform in current scene + LLMatrix4 mat = iter->first; + glh::matrix4f inv_trans = glh::matrix4f((F32*) mat.mMatrix).inverse().transpose(); + LLMatrix4 norm_mat(inv_trans.m); + + for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) + { //for each instance with that transform + LLModelInstance& source_instance = *model_iter; + LLModel* source = source_instance.mModel; + + if (!validate_model(source)) + { + llerrs << "Invalid model found!" << llendl; + } + + for (S32 i = 0; i < source->getNumVolumeFaces(); ++i) + { //for each face in instance + const LLVolumeFace& src_face = source->getVolumeFace(i); + LLImportMaterial& source_material = source_instance.mMaterial[i]; + + //get model in composite that is composite for this material + LLModel* model = NULL; + + if (composite.find(source_material) != composite.end()) + { + model = composite[source_material].rbegin()->mModel; + if (model->getVolumeFace(0).mNumVertices + src_face.mNumVertices > 65535) + { + model = NULL; + } + } + + if (model == NULL) + { //no model found, make new model + std::vector materials; + materials.push_back(source_material); + LLVolumeParams volume_params; + volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); + model = new LLModel(volume_params, 0.f); + model->mLabel = source->mLabel; + model->setNumVolumeFaces(0); + composite[source_material].push_back(LLModelInstance(model, identity, materials)); + } + + model->appendFace(src_face, source->mMaterialList[i], mat, norm_mat); + } + } + } + + + //condense composite into as few LLModel instances as possible + LLModelLoader::model_list new_model; + std::vector instance_list; + + LLVolumeParams volume_params; + volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); + + std::vector empty_material; + LLModelInstance cur_instance(new LLModel(volume_params, 0.f), identity, empty_material); + cur_instance.mModel->setNumVolumeFaces(0); + + BOOL first_transform = TRUE; + + LLModelLoader::scene new_scene; + LLVector3 min,max; + + for (std::map >::iterator iter = composite.begin(); + iter != composite.end(); + ++iter) + { + std::map >::iterator next_iter = iter; ++next_iter; + + for (std::vector::iterator instance_iter = iter->second.begin(); + instance_iter != iter->second.end(); + ++instance_iter) + { + LLModel* source = instance_iter->mModel; + + if (instance_iter->mMaterial.size() != 1) + { + llerrs << "WTF?" << llendl; + } + + if (source->getNumVolumeFaces() != 1) + { + llerrs << "WTF?" << llendl; + } + + if (source->mMaterialList.size() != 1) + { + llerrs << "WTF?" << llendl; + } + + cur_instance.mModel->addFace(source->getVolumeFace(0)); + cur_instance.mMaterial.push_back(instance_iter->mMaterial[0]); + cur_instance.mModel->mMaterialList.push_back(source->mMaterialList[0]); + + BOOL last_model = FALSE; + + std::vector::iterator next_instance = instance_iter; ++next_instance; + + if (next_iter == composite.end() && + next_instance == iter->second.end()) + { + last_model = TRUE; + } + + if (last_model || cur_instance.mModel->getNumVolumeFaces() >= MAX_MODEL_FACES) + { + cur_instance.mModel->mLabel = source->mLabel; + + cur_instance.mModel->optimizeVolumeFaces(); + cur_instance.mModel->normalizeVolumeFaces(); + + if (!validate_model(cur_instance.mModel)) + { + llerrs << "Invalid model detected." << llendl; + } + + new_model.push_back(cur_instance.mModel); + + LLMatrix4 transformation = LLMatrix4(); + + // adjust the transformation to compensate for mesh normalization + LLVector3 mesh_scale_vector; + LLVector3 mesh_translation_vector; + cur_instance.mModel->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); + + LLMatrix4 mesh_translation; + mesh_translation.setTranslation(mesh_translation_vector); + mesh_translation *= transformation; + transformation = mesh_translation; + + LLMatrix4 mesh_scale; + mesh_scale.initScale(mesh_scale_vector); + mesh_scale *= transformation; + transformation = mesh_scale; + + cur_instance.mTransform = transformation; + + new_scene[transformation].push_back(cur_instance); + stretch_extents(cur_instance.mModel, transformation, min, max, first_transform); + + if (!last_model) + { + cur_instance = LLModelInstance(new LLModel(volume_params, 0.f), identity, empty_material); + cur_instance.mModel->setNumVolumeFaces(0); + } + } + } + } + + mScene[mPreviewLOD] = new_scene; + mModel[mPreviewLOD] = new_model; + mVertexBuffer[mPreviewLOD].clear(); + + if (mPreviewLOD == LLModel::LOD_HIGH) + { + mBaseScene = new_scene; + mBaseModel = new_model; + mVertexBuffer[5].clear(); + } + + mPreviewTarget = (min+max)*0.5f; + mPreviewScale = (max-min)*0.5f; + setPreviewTarget(mPreviewScale.magVec()*2.f); + + clearIncompatible(mPreviewLOD); + + mResourceCost = calcResourceCost(); + refresh(); +} + +void LLModelPreview::scrubMaterials() +{ + for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) + { //for each transform in current scene + for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) + { //for each instance with that transform + LLModelInstance& source_instance = *model_iter; + LLModel* source = source_instance.mModel; + + for (S32 i = 0; i < source->getNumVolumeFaces(); ++i) + { //for each face in instance + LLImportMaterial& source_material = source_instance.mMaterial[i]; + + //clear material info + source_material.mDiffuseColor = LLColor4(1,1,1,1); + source_material.mDiffuseMap = NULL; + source_material.mDiffuseMapFilename.clear(); + source_material.mDiffuseMapLabel.clear(); + source_material.mFullbright = false; + } + } + } + + + mVertexBuffer[mPreviewLOD].clear(); + + if (mPreviewLOD == LLModel::LOD_HIGH) + { + mBaseScene = mScene[mPreviewLOD]; + mBaseModel = mModel[mPreviewLOD]; + mVertexBuffer[5].clear(); + } + + mResourceCost = calcResourceCost(); + refresh(); +} + +bool LLModelPreview::containsRiggedAsset( void ) +{ + //loop through the models and determine if any of them contained a rigged asset, and if so + //return true. + //This is used to cleanup the joint positions after a preview. + for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) + { + LLModel* pModel = *iter; + if ( pModel->mAlternateBindMatrix.size() > 0 ) + { + return true; + } + } + return false; +} +void LLModelPreview::genLODs(S32 which_lod) +{ + if (mBaseModel.empty()) + { + return; + } + + if (which_lod == LLModel::LOD_PHYSICS) + { //clear physics mesh map + mPhysicsMesh.clear(); + } + + LLVertexBuffer::unbind(); + + stop_gloderror(); + static U32 cur_name = 1; + + S32 limit = -1; + + if (which_lod != -1) + { + limit = mLimit[which_lod]; + } + + U32 triangle_count = 0; + + for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) + { + LLModel* mdl = *iter; + for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) + { + triangle_count += mdl->getVolumeFace(i).mNumIndices/3; + } + } + + U32 base_triangle_count = triangle_count; + + U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; + + if (mGroup[mBaseModel[0]] == 0) + { //clear LOD maps + mGroup.clear(); + mObject.clear(); + mPercentage.clear(); + mPatch.clear(); + } + + for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) + { //build GLOD objects for each model in base model list + LLModel* mdl = *iter; + if (mGroup[mdl] == 0) + { + mGroup[mdl] = cur_name++; + mObject[mdl] = cur_name++; + + glodNewGroup(mGroup[mdl]); + stop_gloderror(); + + glodGroupParameteri(mGroup[mdl], GLOD_ADAPT_MODE, GLOD_TRIANGLE_BUDGET); + stop_gloderror(); + + glodGroupParameteri(mGroup[mdl], GLOD_ERROR_MODE, GLOD_OBJECT_SPACE_ERROR); + stop_gloderror(); + + glodGroupParameterf(mGroup[mdl], GLOD_OBJECT_SPACE_ERROR_THRESHOLD, 0.025f); + stop_gloderror(); + + glodNewObject(mObject[mdl], mGroup[mdl], GLOD_DISCRETE); + stop_gloderror(); + + if (iter == mBaseModel.begin() && !mdl->mSkinWeights.empty()) + { //regenerate vertex buffer for skinned models to prevent animation feedback during LOD generation + mVertexBuffer[5].clear(); + } + + if (mVertexBuffer[5].empty()) + { + genBuffers(5, false); + } + + U32 tri_count = 0; + for (U32 i = 0; i < mVertexBuffer[5][mdl].size(); ++i) + { + mVertexBuffer[5][mdl][i]->setBuffer(type_mask); + U32 num_indices = mVertexBuffer[5][mdl][i]->getNumIndices(); + if (num_indices > 2) + { + glodInsertElements(mObject[mdl], i, GL_TRIANGLES, num_indices, GL_UNSIGNED_SHORT, mVertexBuffer[5][mdl][i]->getIndicesPointer(), 0, 0.f); + } + tri_count += num_indices/3; + stop_gloderror(); + } + + //store what percentage of total model (in terms of triangle count) this model makes up + mPercentage[mdl] = (F32) tri_count / (F32) base_triangle_count; + + //build glodobject + glodBuildObject(mObject[mdl]); + if (stop_gloderror()) + { + glodDeleteGroup(mGroup[mdl]); + stop_gloderror(); + glodDeleteObject(mObject[mdl]); + stop_gloderror(); + + mGroup[mdl] = 0; + mObject[mdl] = 0; + + if (which_lod == -1) + { + mModel[LLModel::LOD_HIGH] = mBaseModel; + } + + return; + } + + } + + //generating LODs for all entries, or this entry has a triangle budget + glodGroupParameteri(mGroup[mdl], GLOD_ADAPT_MODE, GLOD_TRIANGLE_BUDGET); + stop_gloderror(); + + glodGroupParameterf(mGroup[mdl], GLOD_OBJECT_SPACE_ERROR_THRESHOLD, 0.025f); + stop_gloderror(); + } + + + S32 start = LLModel::LOD_HIGH; + S32 end = 0; + + if (which_lod != -1) + { + start = end = which_lod; + } + + + std::string combo_name[] = + { + "lowest detail combo", + "low detail combo", + "medium detail combo", + "high detail combo", + "physics detail combo" + }; + + std::string limit_name[] = + { + "lowest limit", + "low limit", + "medium limit", + "high limit", + "physics limit" + }; + + for (S32 lod = start; lod >= end; --lod) + { + if (which_lod == -1) + { + if (lod < start) + { + triangle_count /= 3; + } + } + else + { + triangle_count = limit; + } + + LLComboBox* combo_box = mFMP->findChild(combo_name[lod]); + combo_box->setCurrentByIndex(2); + + LLSpinCtrl* lim = mFMP->getChild(limit_name[lod], TRUE); + lim->setMaxValue(base_triangle_count); + lim->setVisible(true); + + mModel[lod].clear(); + mModel[lod].resize(mBaseModel.size()); + mVertexBuffer[lod].clear(); + + U32 actual_tris = 0; + U32 actual_verts = 0; + U32 submeshes = 0; + + for (U32 mdl_idx = 0; mdl_idx < mBaseModel.size(); ++mdl_idx) + { + LLModel* base = mBaseModel[mdl_idx]; + + U32 target_count = U32(mPercentage[base]*triangle_count); + + if (target_count < 4) + { + target_count = 4; + } + + glodGroupParameteri(mGroup[base], GLOD_MAX_TRIANGLES, target_count); + stop_gloderror(); + + glodAdaptGroup(mGroup[base]); + stop_gloderror(); + + GLint patch_count = 0; + glodGetObjectParameteriv(mObject[base], GLOD_NUM_PATCHES, &patch_count); + stop_gloderror(); + + LLVolumeParams volume_params; + volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); + mModel[lod][mdl_idx] = new LLModel(volume_params, 0.f); + + GLint* sizes = new GLint[patch_count*2]; + glodGetObjectParameteriv(mObject[base], GLOD_PATCH_SIZES, sizes); + stop_gloderror(); + + GLint* names = new GLint[patch_count]; + glodGetObjectParameteriv(mObject[base], GLOD_PATCH_NAMES, names); + stop_gloderror(); + + mModel[lod][mdl_idx]->setNumVolumeFaces(patch_count); + + LLModel* target_model = mModel[lod][mdl_idx]; + + for (GLint i = 0; i < patch_count; ++i) + { + LLPointer buff = new LLVertexBuffer(type_mask, 0); + + if (sizes[i*2+1] > 0 && sizes[i*2] > 0) + { + buff->allocateBuffer(sizes[i*2+1], sizes[i*2], true); + buff->setBuffer(type_mask); + glodFillElements(mObject[base], names[i], GL_UNSIGNED_SHORT, buff->getIndicesPointer()); + stop_gloderror(); + } + else + { //this face was eliminated, create a dummy triangle (one vertex, 3 indices, all 0) + buff->allocateBuffer(1, 3, true); + memset(buff->getMappedData(), 0, buff->getSize()); + memset(buff->getIndicesPointer(), 0, buff->getIndicesSize()); + } + + buff->validateRange(0, buff->getNumVerts()-1, buff->getNumIndices(), 0); + + LLStrider pos; + LLStrider norm; + LLStrider tc; + LLStrider index; + + buff->getVertexStrider(pos); + buff->getNormalStrider(norm); + buff->getTexCoord0Strider(tc); + buff->getIndexStrider(index); + + + target_model->setVolumeFaceData(names[i], pos, norm, tc, index, buff->getNumVerts(), buff->getNumIndices()); + actual_tris += buff->getNumIndices()/3; + actual_verts += buff->getNumVerts(); + ++submeshes; + + if (!validate_face(target_model->getVolumeFace(names[i]))) + { + llerrs << "Invalid face generated during LOD generation." << llendl; + } + } + + //blind copy skin weights and just take closest skin weight to point on + //decimated mesh for now (auto-generating LODs with skin weights is still a bit + //of an open problem). + target_model->mPosition = base->mPosition; + target_model->mSkinWeights = base->mSkinWeights; + target_model->mJointMap = base->mJointMap; + target_model->mJointList = base->mJointList; + target_model->mInvBindMatrix = base->mInvBindMatrix; + target_model->mBindShapeMatrix = base->mBindShapeMatrix; + target_model->mAlternateBindMatrix = base->mAlternateBindMatrix; + //copy material list + target_model->mMaterialList = base->mMaterialList; + + if (!validate_model(target_model)) + { + llerrs << "Invalid model generated when creating LODs" << llendl; + } + + delete [] sizes; + delete [] names; + } + + //rebuild scene based on mBaseScene + mScene[lod].clear(); + mScene[lod] = mBaseScene; + + for (U32 i = 0; i < mBaseModel.size(); ++i) + { + LLModel* mdl = mBaseModel[i]; + LLModel* target = mModel[lod][i]; + if (target) + { + for (LLModelLoader::scene::iterator iter = mScene[lod].begin(); iter != mScene[lod].end(); ++iter) + { + for (U32 j = 0; j < iter->second.size(); ++j) + { + if (iter->second[j].mModel == mdl) + { + iter->second[j].mModel = target; + } + } + } + } + } + } + + mResourceCost = calcResourceCost(); + + /*if (which_lod == -1 && mScene[LLModel::LOD_PHYSICS].empty()) + { //build physics scene + mScene[LLModel::LOD_PHYSICS] = mScene[LLModel::LOD_LOW]; + mModel[LLModel::LOD_PHYSICS] = mModel[LLModel::LOD_LOW]; + + for (U32 i = 1; i < mModel[LLModel::LOD_PHYSICS].size(); ++i) + { + mPhysicsQ.push(mModel[LLModel::LOD_PHYSICS][i]); + } + }*/ +} + +void LLModelPreview::updateStatusMessages() +{ + //triangle/vertex/submesh count for each mesh asset for each lod + std::vector tris[LLModel::NUM_LODS]; + std::vector verts[LLModel::NUM_LODS]; + std::vector submeshes[LLModel::NUM_LODS]; + + //total triangle/vertex/submesh count for each lod + S32 total_tris[LLModel::NUM_LODS]; + S32 total_verts[LLModel::NUM_LODS]; + S32 total_submeshes[LLModel::NUM_LODS]; + + for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) + { + //initialize total for this lod to 0 + total_tris[lod] = total_verts[lod] = total_submeshes[lod] = 0; + + for (U32 i = 0; i < mModel[lod].size(); ++i) + { //for each model in the lod + S32 cur_tris = 0; + S32 cur_verts = 0; + S32 cur_submeshes = mModel[lod][i]->getNumVolumeFaces(); + + for (S32 j = 0; j < cur_submeshes; ++j) + { //for each submesh (face), add triangles and vertices to current total + const LLVolumeFace& face = mModel[lod][i]->getVolumeFace(j); + cur_tris += face.mNumIndices/3; + cur_verts += face.mNumVertices; + } + + //add this model to the lod total + total_tris[lod] += cur_tris; + total_verts[lod] += cur_verts; + total_submeshes[lod] += cur_submeshes; + + //store this model's counts to asset data + tris[lod].push_back(cur_tris); + verts[lod].push_back(cur_verts); + submeshes[lod].push_back(cur_submeshes); + } + } + + + std::string upload_message; + + mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[TRIANGLES]", llformat("%d", total_tris[LLModel::LOD_PHYSICS])); + + for (S32 lod = 0; lod <= LLModel::LOD_HIGH; ++lod) + { + mFMP->childSetTextArg(info_name[lod], "[TRIANGLES]", llformat("%d", total_tris[lod])); + mFMP->childSetTextArg(info_name[lod], "[VERTICES]", llformat("%d", total_verts[lod])); + mFMP->childSetTextArg(info_name[lod], "[SUBMESHES]", llformat("%d", total_submeshes[lod])); + + std::string message = "good"; + + const U32 lod_high = LLModel::LOD_HIGH; + + if (lod != lod_high) + { + if (total_submeshes[lod] && total_submeshes[lod] != total_submeshes[lod_high]) + { + message = "mesh_mismatch"; + upload_message = "bad_lod"; + } + else if (!tris[lod].empty() && tris[lod].size() != tris[lod_high].size()) + { + message = "model_mismatch"; + upload_message = "bad_lod"; + } + else if (!verts[lod].empty()) + { + for (U32 i = 0; i < verts[lod].size(); ++i) + { + S32 max_verts = verts[lod+1][i]; + + if (verts[lod][i] > max_verts) + { + message = "too_heavy"; + upload_message = "bad_lod"; + } + } + } + } + + mFMP->childSetTextArg(info_name[lod], "[MESSAGE]", mFMP->getString(message)); + } + + if (upload_message.empty()) + { + mFMP->childSetTextArg("upload_message", "[MESSAGE]", std::string("")); + mFMP->childEnable("ok_btn"); + } + else + { + mFMP->childSetTextArg("upload_message", "[MESSAGE]", mFMP->getString(upload_message)); + mFMP->childDisable("ok_btn"); + } +} + +void LLModelPreview::setPreviewTarget(F32 distance) +{ + mCameraDistance = distance; + mCameraZoom = 1.f; + mCameraPitch = 0.f; + mCameraYaw = 0.f; + mCameraOffset.clearVec(); +} + +void LLModelPreview::clearBuffers() +{ + for (U32 i = 0; i < 6; i++) + { + mVertexBuffer[i].clear(); + } +} + +void LLModelPreview::genBuffers(S32 lod, bool avatar_preview) +{ + U32 tri_count = 0; + U32 vertex_count = 0; + U32 mesh_count = 0; + + LLModelLoader::model_list* model = NULL; + + if (lod < 0 || lod > 4) + { + model = &mBaseModel; + lod = 5; + } + else + { + model = &(mModel[lod]); + } + + if (!mVertexBuffer[lod].empty()) + { + mVertexBuffer[lod].clear(); + } + + mVertexBuffer[lod].clear(); + + LLModelLoader::model_list::iterator base_iter = mBaseModel.begin(); + + for (LLModelLoader::model_list::iterator iter = model->begin(); iter != model->end(); ++iter) + { + LLModel* mdl = *iter; + if (!mdl) + { + continue; + } + + LLModel* base_mdl = *base_iter; + base_iter++; + + for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) + { + const LLVolumeFace &vf = mdl->getVolumeFace(i); + U32 num_vertices = vf.mNumVertices; + U32 num_indices = vf.mNumIndices; + + if (!num_vertices || ! num_indices) + { + continue; + } + + LLVertexBuffer* vb = NULL; + + bool skinned = avatar_preview && !mdl->mSkinWeights.empty(); + + U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; + + if (skinned) + { + mask |= LLVertexBuffer::MAP_WEIGHT4; + } + + vb = new LLVertexBuffer(mask, 0); + + vb->allocateBuffer(num_vertices, num_indices, TRUE); + + LLStrider vertex_strider; + LLStrider normal_strider; + LLStrider tc_strider; + LLStrider index_strider; + LLStrider weights_strider; + + vb->getVertexStrider(vertex_strider); + vb->getNormalStrider(normal_strider); + vb->getTexCoord0Strider(tc_strider); + vb->getIndexStrider(index_strider); + + if (skinned) + { + vb->getWeight4Strider(weights_strider); + } + + LLVector4a::memcpyNonAliased16((F32*) vertex_strider.get(), (F32*) vf.mPositions, num_vertices*4*sizeof(F32)); + LLVector4a::memcpyNonAliased16((F32*) tc_strider.get(), (F32*) vf.mTexCoords, num_vertices*2*sizeof(F32)); + LLVector4a::memcpyNonAliased16((F32*) normal_strider.get(), (F32*) vf.mNormals, num_vertices*4*sizeof(F32)); + + if (skinned) + { + for (U32 i = 0; i < num_vertices; i++) + { + //find closest weight to vf.mVertices[i].mPosition + LLVector3 pos(vf.mPositions[i].getF32ptr()); + + const LLModel::weight_list& weight_list = base_mdl->getJointInfluences(pos); + + LLVector4 w(0,0,0,0); + if (weight_list.size() > 4) + { + llerrs << "WTF?" << llendl; + } + + for (U32 i = 0; i < weight_list.size(); ++i) + { + F32 wght = llmin(weight_list[i].mWeight, 0.999999f); + F32 joint = (F32) weight_list[i].mJointIdx; + w.mV[i] = joint + wght; + } + + *(weights_strider++) = w; + } + } + + // build indices + for (U32 i = 0; i < num_indices; i++) + { + *(index_strider++) = vf.mIndices[i]; + } + + mVertexBuffer[lod][mdl].push_back(vb); + + vertex_count += num_vertices; + tri_count += num_indices/3; + ++mesh_count; + + } + } +} + +void LLModelPreview::update() +{ + if (mDirty) + { + mDirty = false; + mResourceCost = calcResourceCost(); + } +} + +//----------------------------------------------------------------------------- +// render() +//----------------------------------------------------------------------------- +BOOL LLModelPreview::render() +{ + LLMutexLock lock(this); + mNeedsUpdate = FALSE; + + S32 width = getWidth(); + S32 height = getHeight(); + + LLGLSUIDefault def; + LLGLDisable no_blend(GL_BLEND); + LLGLEnable cull(GL_CULL_FACE); + LLGLDepthTest depth(GL_TRUE); + LLGLDisable fog(GL_FOG); + + glMatrixMode(GL_PROJECTION); + gGL.pushMatrix(); + glLoadIdentity(); + glOrtho(0.0f, width, 0.0f, height, -1.0f, 1.0f); + + glMatrixMode(GL_MODELVIEW); + gGL.pushMatrix(); + glLoadIdentity(); + + gGL.color4f(0.15f, 0.2f, 0.3f, 1.f); + + gl_rect_2d_simple( width, height ); + + bool avatar_preview = false; + bool upload_skin = mFMP->childGetValue("upload_skin").asBoolean(); + bool upload_joints = mFMP->childGetValue("upload_joints").asBoolean(); + + for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) + { + for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) + { + LLModelInstance& instance = *model_iter; + LLModel* model = instance.mModel; + if (!model->mSkinWeights.empty()) + { + avatar_preview = true; + } + } + } + + if (upload_skin && !avatar_preview) + { + mFMP->childSetValue("upload_skin", false); + upload_skin = false; + } + + if (!upload_skin && upload_joints) + { + mFMP->childSetValue("upload_joints", false); + upload_joints = false; + } + + if (!avatar_preview) + { + mFMP->childDisable("upload_skin"); + } + else + { + mFMP->childEnable("upload_skin"); + } + + if (!upload_skin) + { + mFMP->childDisable("upload_joints"); + } + else + { + mFMP->childEnable("upload_joints"); + } + + avatar_preview = avatar_preview && upload_skin; + + + mFMP->childSetEnabled("consolidate", !avatar_preview); + + F32 explode = mFMP->mDecompFloater ? mFMP->mDecompFloater->childGetValue("explode").asReal() : 0.f; + + glMatrixMode(GL_PROJECTION); + gGL.popMatrix(); + + glMatrixMode(GL_MODELVIEW); + gGL.popMatrix(); + + glClear(GL_DEPTH_BUFFER_BIT); + + LLViewerCamera::getInstance()->setAspect((F32) width / height ); + LLViewerCamera::getInstance()->setView(LLViewerCamera::getInstance()->getDefaultFOV() / mCameraZoom); + + LLVector3 target_pos = mPreviewTarget; + LLVector3 offset = mCameraOffset; + + F32 z_near = llmax(mCameraDistance-mPreviewScale.magVec(), 0.001f); + F32 z_far = mCameraDistance+mPreviewScale.magVec(); + + if (avatar_preview) + { + target_pos = gAgentAvatarp->getPositionAgent(); + z_near = 0.01f; + z_far = 1024.f; + mCameraDistance = 16.f; + + //render avatar previews every frame + refresh(); + } + + LLQuaternion camera_rot = LLQuaternion(mCameraPitch, LLVector3::y_axis) * + LLQuaternion(mCameraYaw, LLVector3::z_axis); + + LLQuaternion av_rot = camera_rot; + LLViewerCamera::getInstance()->setOriginAndLookAt( + target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + offset) * av_rot), // camera + LLVector3::z_axis, // up + target_pos); // point of interest + + + LLViewerCamera::getInstance()->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, width, height, FALSE, z_near, z_far); + + stop_glerror(); + + gPipeline.enableLightsAvatar(); + + gGL.pushMatrix(); + const F32 BRIGHTNESS = 0.9f; + gGL.color3f(BRIGHTNESS, BRIGHTNESS, BRIGHTNESS); + + LLGLEnable normalize(GL_NORMALIZE); + + if (!mBaseModel.empty() && mVertexBuffer[5].empty()) + { + genBuffers(-1, avatar_preview); + //genBuffers(3); + //genLODs(); + } + + bool physics = (mPreviewLOD == LLModel::LOD_PHYSICS); + + S32 physics_idx = -1; + + bool render_mesh = true; + bool render_hull = false; + + if (physics && mFMP->mDecompFloater) + { + physics_idx = mFMP->mDecompFloater->childGetValue("model").asInteger(); + render_mesh = mFMP->mDecompFloater->childGetValue("render_mesh").asBoolean(); + render_hull = mFMP->mDecompFloater->childGetValue("render_hull").asBoolean(); + } + + if (!mModel[mPreviewLOD].empty()) + { + if (mVertexBuffer[mPreviewLOD].empty()) + { + genBuffers(mPreviewLOD, avatar_preview); + } + + if (!avatar_preview) + { + //for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) + for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) + { + LLModelInstance& instance = *iter; + + gGL.pushMatrix(); + LLMatrix4 mat = instance.mTransform; + + glMultMatrixf((GLfloat*) mat.mMatrix); + + //for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) + { + //LLModelInstance& instance = *model_iter; + LLModel* model = instance.mLOD[mPreviewLOD]; + + if (!model) + { + continue; + } + + //if (instance.mTransform != mat) + //{ + // llerrs << "WTF?" << llendl; + //} + + if (render_mesh) + { + for (U32 i = 0; i < mVertexBuffer[mPreviewLOD][model].size(); ++i) + { + LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; + + buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); + if (physics) + { + if (physics_idx > -1 && model == mModel[mPreviewLOD][physics_idx]) + { + glColor4f(1,0,0,1); + } + else + { + glColor4f(0.75f, 0.75f, 0.75f, 1.f); + } + } + else + { + glColor4fv(instance.mMaterial[i].mDiffuseColor.mV); + if (i < instance.mMaterial.size() && instance.mMaterial[i].mDiffuseMap.notNull()) + { + gGL.getTexUnit(0)->bind(instance.mMaterial[i].mDiffuseMap, true); + if (instance.mMaterial[i].mDiffuseMap->getDiscardLevel() > -1) + { + mTextureSet.insert(instance.mMaterial[i].mDiffuseMap); + } + } + } + + buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + glColor3f(0.4f, 0.4f, 0.4f); + + if (mFMP->childGetValue("show edges").asBoolean()) + { + glLineWidth(3.f); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glLineWidth(1.f); + } + } + } + + if (render_hull) + { + LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread; + if (decomp) + { + LLMutexLock(decomp->mMutex); + + std::map, std::vector > >::iterator iter = + mPhysicsMesh.find(model); + if (iter != mPhysicsMesh.end()) + { + for (U32 i = 0; i < iter->second.size(); ++i) + { + if (explode > 0.f) + { + gGL.pushMatrix(); + + LLVector3 offset = model->mHullCenter[i]-model->mCenterOfHullCenters; + offset *= explode; + + gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]); + } + + static std::vector hull_colors; + + if (i+1 >= hull_colors.size()) + { + hull_colors.push_back(LLColor4U(rand()%128+127, rand()%128+127, rand()%128+127, 255)); + } + + LLVertexBuffer* buff = iter->second[i]; + if (buff) + { + buff->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL); + + glColor4ubv(hull_colors[i].mV); + buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts()); + + if (mFMP->childGetValue("show edges").asBoolean()) + { + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + glLineWidth(3.f); + glColor4ub(hull_colors[i].mV[0]/2, hull_colors[i].mV[1]/2, hull_colors[i].mV[2]/2, 255); + buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts()); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glLineWidth(1.f); + } + } + + if (explode > 0.f) + { + gGL.popMatrix(); + } + } + } + } + + //mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[HULLS]", llformat("%d",decomp->mHulls.size())); + //mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[POINTS]", llformat("%d",decomp->mTotalPoints)); + } + } + + gGL.popMatrix(); + } + + if (physics) + { + mPreviewLOD = LLModel::LOD_PHYSICS; + } + } + else + { + LLVOAvatarSelf* avatar = gAgentAvatarp; + target_pos = avatar->getPositionAgent(); + + LLViewerCamera::getInstance()->setOriginAndLookAt( + target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + offset) * av_rot), // camera + LLVector3::z_axis, // up + target_pos); // point of interest + + avatar->renderCollisionVolumes(); + + for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) + { + for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) + { + LLModelInstance& instance = *model_iter; + LLModel* model = instance.mModel; + + if (!model->mSkinWeights.empty()) + { + for (U32 i = 0; i < mVertexBuffer[mPreviewLOD][model].size(); ++i) + { + LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; + + const LLVolumeFace& face = model->getVolumeFace(i); + + LLStrider position; + buffer->getVertexStrider(position); + + LLStrider weight; + buffer->getWeight4Strider(weight); + + //quick 'n dirty software vertex skinning + + //build matrix palette + LLMatrix4 mat[64]; + for (U32 j = 0; j < model->mJointList.size(); ++j) + { + LLJoint* joint = avatar->getJoint(model->mJointList[j]); + if (joint) + { + mat[j] = model->mInvBindMatrix[j]; + mat[j] *= joint->getWorldMatrix(); + } + } + + for (U32 j = 0; j < buffer->getRequestedVerts(); ++j) + { + LLMatrix4 final_mat; + final_mat.mMatrix[0][0] = final_mat.mMatrix[1][1] = final_mat.mMatrix[2][2] = final_mat.mMatrix[3][3] = 0.f; + + LLVector4 wght; + S32 idx[4]; + + F32 scale = 0.f; + for (U32 k = 0; k < 4; k++) + { + F32 w = weight[j].mV[k]; + + idx[k] = (S32) floorf(w); + wght.mV[k] = w - floorf(w); + scale += wght.mV[k]; + } + + wght *= 1.f/scale; + + for (U32 k = 0; k < 4; k++) + { + F32* src = (F32*) mat[idx[k]].mMatrix; + F32* dst = (F32*) final_mat.mMatrix; + + F32 w = wght.mV[k]; + + for (U32 l = 0; l < 16; l++) + { + dst[l] += src[l]*w; + } + } + + //VECTORIZE THIS + LLVector3 v(face.mPositions[j].getF32ptr()); + + v = v * model->mBindShapeMatrix; + v = v * final_mat; + + position[j] = v; + } + + buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); + glColor4fv(instance.mMaterial[i].mDiffuseColor.mV); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); + glColor3f(0.4f, 0.4f, 0.4f); + + if (mFMP->childGetValue("show edges").asBoolean()) + { + glLineWidth(3.f); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glLineWidth(1.f); + } + } + } + } + } + } + } + + gGL.popMatrix(); + + return TRUE; +} + +//----------------------------------------------------------------------------- +// refresh() +//----------------------------------------------------------------------------- +void LLModelPreview::refresh() +{ + mNeedsUpdate = TRUE; +} + +//----------------------------------------------------------------------------- +// rotate() +//----------------------------------------------------------------------------- +void LLModelPreview::rotate(F32 yaw_radians, F32 pitch_radians) +{ + mCameraYaw = mCameraYaw + yaw_radians; + + mCameraPitch = llclamp(mCameraPitch + pitch_radians, F_PI_BY_TWO * -0.8f, F_PI_BY_TWO * 0.8f); +} + +//----------------------------------------------------------------------------- +// zoom() +//----------------------------------------------------------------------------- +void LLModelPreview::zoom(F32 zoom_amt) +{ + F32 new_zoom = mCameraZoom+zoom_amt; + + mCameraZoom = llclamp(new_zoom, 1.f, 10.f); +} + +void LLModelPreview::pan(F32 right, F32 up) +{ + mCameraOffset.mV[VY] = llclamp(mCameraOffset.mV[VY] + right * mCameraDistance / mCameraZoom, -1.f, 1.f); + mCameraOffset.mV[VZ] = llclamp(mCameraOffset.mV[VZ] + up * mCameraDistance / mCameraZoom, -1.f, 1.f); +} + +void LLModelPreview::setPreviewLOD(S32 lod) +{ + mPreviewLOD = llclamp(lod, 0, 4); + refresh(); +} + +//static +void LLFloaterModelPreview::onBrowseHighLOD(void* data) +{ + LLFloaterModelPreview* mp = (LLFloaterModelPreview*) data; + mp->loadModel(3); +} + +//static +void LLFloaterModelPreview::onBrowseMediumLOD(void* data) +{ + LLFloaterModelPreview* mp = (LLFloaterModelPreview*) data; + mp->loadModel(2); +} + +//static +void LLFloaterModelPreview::onBrowseLowLOD(void* data) +{ + LLFloaterModelPreview* mp = (LLFloaterModelPreview*) data; + mp->loadModel(1); +} + +//static +void LLFloaterModelPreview::onBrowseLowestLOD(void* data) +{ + LLFloaterModelPreview* mp = (LLFloaterModelPreview*) data; + mp->loadModel(0); +} + +//static +void LLFloaterModelPreview::onUpload(void* user_data) +{ + LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; + + if (mp->mDecompFloater) + { + mp->mDecompFloater->closeFloater(); + } + + mp->mModelPreview->rebuildUploadData(); + + gMeshRepo.uploadModel(mp->mModelPreview->mUploadData, mp->mModelPreview->mPreviewScale, + mp->childGetValue("upload_textures").asBoolean(), mp->childGetValue("upload_skin"), mp->childGetValue("upload_joints")); + + mp->closeFloater(false); +} + +//static +void LLFloaterModelPreview::onConsolidate(void* user_data) +{ + LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; + mp->mModelPreview->consolidate(); +} + +//static +void LLFloaterModelPreview::onScrubMaterials(void* user_data) +{ + LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; + mp->mModelPreview->scrubMaterials(); +} + +//static +void LLFloaterModelPreview::onDecompose(void* user_data) +{ + LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; + mp->showDecompFloater(); +} + +//static +void LLFloaterModelPreview::refresh(LLUICtrl* ctrl, void* user_data) +{ + LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; + mp->mModelPreview->refresh(); +} + +void LLFloaterModelPreview::updateResourceCost() +{ + U32 cost = mModelPreview->mResourceCost; + childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d",cost)); +} + +//static +void LLModelPreview::textureLoadedCallback( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata ) +{ + LLModelPreview* preview = (LLModelPreview*) userdata; + preview->refresh(); +} + +LLFloaterModelPreview::DecompRequest::DecompRequest(const std::string& stage, LLModel* mdl) +{ + mStage = stage; + mContinue = 1; + mModel = mdl; + mParams = sInstance->mDecompParams; + + //copy out positions and indices + if (mdl) + { + U16 index_offset = 0; + + mPositions.clear(); + mIndices.clear(); + + //queue up vertex positions and indices + for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) + { + const LLVolumeFace& face = mdl->getVolumeFace(i); + if (mPositions.size() + face.mNumVertices > 65535) + { + continue; + } + + for (U32 j = 0; j < face.mNumVertices; ++j) + { + mPositions.push_back(LLVector3(face.mPositions[j].getF32ptr())); + } + + for (U32 j = 0; j < face.mNumIndices; ++j) + { + mIndices.push_back(face.mIndices[j]+index_offset); + } + + index_offset += face.mNumVertices; + } + } +} + +S32 LLFloaterModelPreview::DecompRequest::statusCallback(const char* status, S32 p1, S32 p2) +{ + setStatusMessage(llformat("%s: %d/%d", status, p1, p2)); + return mContinue; +} + +void LLFloaterModelPreview::DecompRequest::completed() +{ + mModel->setConvexHullDecomposition(mHull); + + if (sInstance) + { + if (sInstance->mModelPreview) + { + sInstance->mModelPreview->mPhysicsMesh[mModel] = mHullMesh; + sInstance->mModelPreview->mDirty = true; + LLFloaterModelPreview::sInstance->mModelPreview->refresh(); + } + + sInstance->mCurRequest = NULL; + } +} + + -- cgit v1.2.3 From f9a35fc4c622cf5b151900dd4590818d965a506b Mon Sep 17 00:00:00 2001 From: prep Date: Mon, 15 Nov 2010 14:02:03 -0500 Subject: Implemented support for getting at the child translational element if the SID fails to resolved. --- indra/newview/llfloatermodelpreview.cpp | 85 ++++++++++++++++++++------------- 1 file changed, 52 insertions(+), 33 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 1c73a6cb31..a37469422d 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1424,41 +1424,49 @@ void LLModelLoader::run() char str[64]={0}; sprintf(str,"./%s",(*jointIt).second.c_str() ); //llwarns<<"Joint "<< str <( resolver.getElement() ); + if ( pJoint ) + { + //Pull out the translate id and store it in the jointTranslations map + daeSIDResolver jointResolver( pJoint, "./translate" ); + domTranslate* pTranslate = daeSafeCast( jointResolver.getElement() ); + + LLMatrix4 workingTransform; + + //Translation via SID + if ( pTranslate ) + { + domFloat3 jointTrans = pTranslate->getValue(); + LLVector3 singleJointTranslation( jointTrans[0], jointTrans[1], jointTrans[2] ); + workingTransform.setTranslation( singleJointTranslation ); + } + else + { + //Translation via child from element + daeElement* pTranslateElement = getChildFromElement( pJoint, "translate" ); + if ( pTranslateElement && pTranslateElement->typeID() != domTranslate::ID() ) + { + llwarns<< "The found element is not a translate node" <( pTranslateElement ); + domFloat3 translateChild = pTranslateChild->getValue(); + LLVector3 singleJointTranslation( translateChild[0], translateChild[1], translateChild[2] ); + workingTransform.setTranslation( singleJointTranslation ); + } + } + //Store the joint transform w/respect to it's name. + jointTransforms[(*jointIt).second.c_str()] = workingTransform; + } - //Setup the resolver - daeSIDResolver resolver( pSkeletonRootNode, str ); - //Look for the joint - domNode* pJoint = daeSafeCast(resolver.getElement()); - if ( pJoint ) - { - //Pull out the translate id and store it in the jointTranslations map - daeSIDResolver jointResolver( pJoint, "./translate" ); - domTranslate* pTranslate = daeSafeCast( jointResolver.getElement() ); - - LLMatrix4 workingTransform; - - //Translation - if ( pTranslate ) - { - domFloat3 jointTrans = pTranslate->getValue(); - LLVector3 singleJointTranslation( jointTrans[0], jointTrans[1], jointTrans[2] ); - workingTransform.setTranslation( singleJointTranslation ); - } - else - { - missingID = true; - llwarns<< "No translation sid!" << llendl; - } - //Store the joint transform w/respect to it's name. - jointTransforms[(*jointIt).second.c_str()] = workingTransform; - - } - else - { - missingID = true; - llwarns<< "Missing joint." << llendl; - } } //If anything failed in regards to extracting the skeleton, joints or translation id, @@ -1759,6 +1767,17 @@ void LLModelLoader::run() mPreview->loadModelCallback(mLod); } } + +daeElement* LLModelLoader::getChildFromElement( daeElement* pElement, std::string const & name ) +{ + daeElement* pChildOfElement = pElement->getChild( name.c_str() ); + if ( pChildOfElement ) + { + return pChildOfElement; + } + llwarns<< "Could not find a child [" << name << "] for the element: \"" << pElement->getAttribute("id") << "\"" << llendl; + return NULL; +} void LLModelLoader::processElement(daeElement* element) { -- cgit v1.2.3 From 47a5f12ce05ed08aa9bc5599dfff9e4cf9b83e44 Mon Sep 17 00:00:00 2001 From: prep linden Date: Wed, 17 Nov 2010 12:41:04 -0500 Subject: Implemented support for parsing bone offsets from a Collada file when no skeletal node is present. --- indra/newview/llfloatermodelpreview.cpp | 1383 +++++++++++++++++-------------- 1 file changed, 740 insertions(+), 643 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index a37469422d..d3da7533ec 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -112,7 +112,7 @@ std::string limit_name[] = "medium limit", "high limit", "physics limit", - + "I went off the end of the limit_name array. Me so smart." }; @@ -123,7 +123,7 @@ std::string info_name[] = "medium info", "high info", "physics info", - + "I went off the end of the info_name array. Me so smart." }; @@ -137,7 +137,7 @@ bool validate_face(const LLVolumeFace& face) return false; } } - + return true; } @@ -156,39 +156,39 @@ bool validate_model(const LLModel* mdl) llwarns << "Face has no vertices." << llendl; return false; } - + if (mdl->getVolumeFace(i).mNumIndices == 0) { llwarns << "Face has no indices." << llendl; return false; } - + if (!validate_face(mdl->getVolumeFace(i))) { return false; } } - + return true; } BOOL stop_gloderror() { GLuint error = glodGetError(); - + if (error != GLOD_NO_ERROR) { llwarns << "GLOD error detected, cannot generate LOD: " << std::hex << error << llendl; return TRUE; } - + return FALSE; } LLPhysicsDecompFloater::LLPhysicsDecompFloater(LLSD& key) : LLFloater(key) { - + } LLPhysicsDecompFloater::~LLPhysicsDecompFloater() @@ -204,14 +204,14 @@ class LLMeshFilePicker : public LLFilePickerThread public: LLFloaterModelPreview* mFMP; S32 mLOD; - + LLMeshFilePicker(LLFloaterModelPreview* fmp, S32 lod) - : LLFilePickerThread(LLFilePicker::FFLOAD_COLLADA) + : LLFilePickerThread(LLFilePicker::FFLOAD_COLLADA) { mFMP = fmp; mLOD = lod; } - + virtual void notify(const std::string& filename) { mFMP->mModelPreview->loadModel(mFile, mLOD); @@ -223,7 +223,7 @@ public: // LLFloaterModelPreview() //----------------------------------------------------------------------------- LLFloaterModelPreview::LLFloaterModelPreview(const LLSD& key) : - LLFloater(key) +LLFloater(key) { sInstance = this; mLastMouseX = 0; @@ -242,27 +242,27 @@ BOOL LLFloaterModelPreview::postBuild() { return FALSE; } - + childSetCommitCallback("high detail combo", onHighLODCommit, this); childSetCommitCallback("medium detail combo", onMediumLODCommit, this); childSetCommitCallback("low detail combo", onLowLODCommit, this); childSetCommitCallback("lowest detail combo", onLowestLODCommit, this); childSetCommitCallback("physics detail combo", onPhysicsLODCommit, this); - - + + childSetCommitCallback("high limit", onHighLimitCommit, this); childSetCommitCallback("medium limit", onMediumLimitCommit, this); childSetCommitCallback("low limit", onLowLimitCommit, this); childSetCommitCallback("lowest limit", onLowestLimitCommit, this); childSetCommitCallback("physics limit", onPhysicsLimitCommit, this); - + childSetCommitCallback("smooth normals", onSmoothNormalsCommit, this); - + childSetCommitCallback("show edges", onShowEdgesCommit, this); childSetCommitCallback("auto fill", onAutoFillCommit, this); - + childSetTextArg("status", "[STATUS]", getString("status_idle")); - + for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) { if (lod == LLModel::LOD_PHYSICS) @@ -279,36 +279,36 @@ BOOL LLFloaterModelPreview::postBuild() std::string msg = getString("required"); childSetTextArg(info_name[lod], "[MESSAGE]", msg); } - + childSetVisible(limit_name[lod], FALSE); } - + //childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d",sUploadAmount)); childSetAction("ok_btn", onUpload, this); - + childSetAction("consolidate", onConsolidate, this); childSetAction("scrub materials", onScrubMaterials, this); - + childSetAction("decompose_btn", onDecompose, this); - + childSetCommitCallback("preview_lod_combo", onPreviewLODCommit, this); childSetCommitCallback("upload_skin", onUploadSkinCommit, this); childSetCommitCallback("upload_joints", onUploadJointsCommit, this); - + childSetCommitCallback("debug scale", onDebugScaleCommit, this); - + childDisable("upload_skin"); childDisable("upload_joints"); - + const U32 width = 512; const U32 height = 512; - + mPreviewRect.set(getRect().getWidth()-PREVIEW_HPAD-width, - PREVIEW_HPAD+height, - getRect().getWidth()-PREVIEW_HPAD, - PREVIEW_HPAD); - + PREVIEW_HPAD+height, + getRect().getWidth()-PREVIEW_HPAD, + PREVIEW_HPAD); + mModelPreview = new LLModelPreview(512, 512, this); mModelPreview->setPreviewTarget(16.f); @@ -321,7 +321,7 @@ BOOL LLFloaterModelPreview::postBuild() LLFloaterModelPreview::~LLFloaterModelPreview() { sInstance = NULL; - + if ( mModelPreview->containsRiggedAsset() ) { gAgentAvatarp->resetJointPositions(); @@ -333,7 +333,7 @@ LLFloaterModelPreview::~LLFloaterModelPreview() { LLImageGL::deleteTextures(1, &mGLName ); } - + if (mDecompFloater) { mDecompFloater->closeFloater(); @@ -344,7 +344,7 @@ LLFloaterModelPreview::~LLFloaterModelPreview() void LLFloaterModelPreview::loadModel(S32 lod) { mLoading = TRUE; - + (new LLMeshFilePicker(this, lod))->getFile(); } @@ -363,7 +363,7 @@ void LLFloaterModelPreview::setLODMode(S32 lod, S32 mode) { mModelPreview->clearModel(lod); } - + mModelPreview->refresh(); mModelPreview->calcResourceCost(); } @@ -376,21 +376,21 @@ void LLFloaterModelPreview::setLODMode(S32 lod, S32 mode) mModelPreview->mLODMode[lod] = mode; mModelPreview->genLODs(lod); } - + mModelPreview->setPreviewLOD(lod); LLSpinCtrl* lim = getChild(limit_name[lod], TRUE); - + if (mode == 2) //triangle count { U32 tri_count = 0; for (LLModelLoader::model_list::iterator iter = mModelPreview->mBaseModel.begin(); - iter != mModelPreview->mBaseModel.end(); ++iter) + iter != mModelPreview->mBaseModel.end(); ++iter) { tri_count += (*iter)->getNumTriangles(); } - + lim->setMaxValue(tri_count); lim->setVisible(TRUE); } @@ -419,7 +419,7 @@ void LLFloaterModelPreview::onDebugScaleCommit(LLUICtrl*,void* userdata) { return; } - + fp->mModelPreview->calcResourceCost(); } @@ -432,7 +432,7 @@ void LLFloaterModelPreview::onUploadJointsCommit(LLUICtrl*,void* userdata) { return; } - + fp->mModelPreview->refresh(); } @@ -445,12 +445,12 @@ void LLFloaterModelPreview::onUploadSkinCommit(LLUICtrl*,void* userdata) { return; } - + fp->mModelPreview->refresh(); fp->mModelPreview->resetPreviewTarget(); fp->mModelPreview->clearBuffers(); } - + //static void LLFloaterModelPreview::onPreviewLODCommit(LLUICtrl* ctrl, void* userdata) { @@ -460,9 +460,9 @@ void LLFloaterModelPreview::onPreviewLODCommit(LLUICtrl* ctrl, void* userdata) { return; } - + S32 which_mode = 0; - + LLCtrlSelectionInterface* iface = fp->childGetSelectionInterface("preview_lod_combo"); if (iface) { @@ -480,9 +480,9 @@ void LLFloaterModelPreview::setLODMode(S32 lod, void* userdata) { return; } - + S32 which_mode = 0; - + std::string combo_name[] = { "lowest detail combo", @@ -490,16 +490,16 @@ void LLFloaterModelPreview::setLODMode(S32 lod, void* userdata) "medium detail combo", "high detail combo", "physics detail combo", - + "I went off the end of the combo_name array. Me so smart." }; - + LLCtrlSelectionInterface* iface = fp->childGetSelectionInterface(combo_name[lod]); if (iface) { which_mode = iface->getFirstSelectedIndex(); } - + fp->setLODMode(lod, which_mode); } @@ -542,9 +542,9 @@ void LLFloaterModelPreview::setLimit(S32 lod, void* userdata) { return; } - + S32 limit = fp->childGetValue(limit_name[lod]).asInteger(); - + fp->setLimit(lod, limit); } @@ -583,7 +583,7 @@ void LLFloaterModelPreview::onPhysicsLimitCommit(LLUICtrl* ctrl, void* userdata) void LLFloaterModelPreview::onSmoothNormalsCommit(LLUICtrl* ctrl, void* userdata) { LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; - + fp->mModelPreview->smoothNormals(); } @@ -591,7 +591,7 @@ void LLFloaterModelPreview::onSmoothNormalsCommit(LLUICtrl* ctrl, void* userdata void LLFloaterModelPreview::onShowEdgesCommit(LLUICtrl* ctrl, void* userdata) { LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; - + fp->mModelPreview->refresh(); } @@ -599,7 +599,7 @@ void LLFloaterModelPreview::onShowEdgesCommit(LLUICtrl* ctrl, void* userdata) void LLFloaterModelPreview::onExplodeCommit(LLUICtrl* ctrl, void* userdata) { LLFloaterModelPreview* fp = LLFloaterModelPreview::sInstance; - + fp->mModelPreview->refresh(); } @@ -607,7 +607,7 @@ void LLFloaterModelPreview::onExplodeCommit(LLUICtrl* ctrl, void* userdata) void LLFloaterModelPreview::onAutoFillCommit(LLUICtrl* ctrl, void* userdata) { LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; - + fp->mModelPreview->genLODs(); } @@ -619,7 +619,7 @@ void LLFloaterModelPreview::draw() { LLFloater::draw(); LLRect r = getRect(); - + mModelPreview->update(); if (!mLoading) @@ -629,7 +629,7 @@ void LLFloaterModelPreview::draw() childSetTextArg("description_label", "[PRIM_COST]", llformat("%d", mModelPreview->mResourceCost)); childSetTextArg("description_label", "[TEXTURES]", llformat("%d", mModelPreview->mTextureSet.size())); - + if (mDecompFloater) { if (mCurRequest.notNull()) @@ -642,9 +642,9 @@ void LLFloaterModelPreview::draw() mDecompFloater->childSetText("status", idle); } } - + U32 resource_cost = mModelPreview->mResourceCost*10; - + if (childGetValue("upload_textures").asBoolean()) { resource_cost += mModelPreview->mTextureSet.size()*10; @@ -655,7 +655,7 @@ void LLFloaterModelPreview::draw() if (mModelPreview) { gGL.color3f(1.f, 1.f, 1.f); - + gGL.getTexUnit(0)->bind(mModelPreview); gGL.begin( LLRender::QUADS ); @@ -670,7 +670,7 @@ void LLFloaterModelPreview::draw() gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mTop); } gGL.end(); - + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); } } @@ -689,7 +689,7 @@ BOOL LLFloaterModelPreview::handleMouseDown(S32 x, S32 y, MASK mask) mLastMouseY = y; return TRUE; } - + return LLFloater::handleMouseDown(x, y, mask); } @@ -709,7 +709,7 @@ BOOL LLFloaterModelPreview::handleMouseUp(S32 x, S32 y, MASK mask) BOOL LLFloaterModelPreview::handleHover (S32 x, S32 y, MASK mask) { MASK local_mask = mask & ~MASK_ALT; - + if (mModelPreview && hasMouseCapture()) { if (local_mask == MASK_PAN) @@ -726,20 +726,20 @@ BOOL LLFloaterModelPreview::handleHover (S32 x, S32 y, MASK mask) } else { - + F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f; F32 zoom_amt = (F32)(y - mLastMouseY) * 0.02f; mModelPreview->rotate(yaw_radians, 0.f); mModelPreview->zoom(zoom_amt); } - + mModelPreview->refresh(); LLUI::setMousePositionLocal(this, mLastMouseX, mLastMouseY); } - + if (!mPreviewRect.pointInRect(x, y) || !mModelPreview) { return LLFloater::handleHover(x, y, mask); @@ -756,7 +756,7 @@ BOOL LLFloaterModelPreview::handleHover (S32 x, S32 y, MASK mask) { gViewerWindow->setCursor(UI_CURSOR_TOOLZOOMIN); } - + return TRUE; } @@ -770,7 +770,7 @@ BOOL LLFloaterModelPreview::handleScrollWheel(S32 x, S32 y, S32 clicks) mModelPreview->zoom((F32)clicks * -0.2f); mModelPreview->refresh(); } - + return TRUE; } @@ -782,7 +782,7 @@ void LLFloaterModelPreview::onPhysicsParamCommit(LLUICtrl* ctrl, void* data) llinfos << "convex decomposition tool is a stub on this platform. cannot get decomp." << llendl; return; } - + if (sInstance) { LLCDParam* param = (LLCDParam*) data; @@ -796,7 +796,7 @@ void LLFloaterModelPreview::onPhysicsStageExecute(LLUICtrl* ctrl, void* data) LLCDStageData* stage = (LLCDStageData*) data; LLModel* mdl = NULL; - + if (sInstance) { if (sInstance->mCurRequest.notNull()) @@ -804,7 +804,7 @@ void LLFloaterModelPreview::onPhysicsStageExecute(LLUICtrl* ctrl, void* data) llinfos << "Decomposition request still pending." << llendl; return; } - + if (sInstance->mModelPreview) { if (sInstance->mDecompFloater) @@ -840,12 +840,12 @@ void LLFloaterModelPreview::showDecompFloater() { LLSD key; mDecompFloater = new LLPhysicsDecompFloater(key); - + S32 left = 20; S32 right = 320; - + S32 cur_y = 30; - + { //add status text LLTextBox::Params p; @@ -853,8 +853,8 @@ void LLFloaterModelPreview::showDecompFloater() p.rect(LLRect(left, cur_y, right-80, cur_y-20)); mDecompFloater->addChild(LLUICtrlFactory::create(p)); } - - + + { //add cancel button LLButton::Params p; p.name("Cancel"); @@ -864,25 +864,25 @@ void LLFloaterModelPreview::showDecompFloater() button->setCommitCallback(onPhysicsStageCancel, NULL); mDecompFloater->addChild(button); } - + cur_y += 30; - - + + static const LLCDStageData* stage = NULL; static S32 stage_count = 0; - + if (!stage && LLConvexDecomposition::getInstance() != NULL) { stage_count = LLConvexDecomposition::getInstance()->getStages(&stage); } - + static const LLCDParam* param = NULL; static S32 param_count = 0; if (!param && LLConvexDecomposition::getInstance() != NULL) { param_count = LLConvexDecomposition::getInstance()->getParameters(¶m); } - + for (S32 j = stage_count-1; j >= 0; --j) { LLButton::Params p; @@ -896,29 +896,29 @@ void LLFloaterModelPreview::showDecompFloater() cur_y += 30; // protected against stub by stage_count being 0 for stub above LLConvexDecomposition::getInstance()->registerCallback(j, LLPhysicsDecomp::llcdCallback); - + llinfos << "Physics decomp stage " << stage[j].mName << " (" << j << ") parameters:" << llendl; llinfos << "------------------------------------" << llendl; - + for (S32 i = 0; i < param_count; ++i) { if (param[i].mStage != j) { continue; } - + std::string name(param[i].mName ? param[i].mName : ""); std::string description(param[i].mDescription ? param[i].mDescription : ""); - + std::string type = "unknown"; - + llinfos << name << " - " << description << llendl; - + if (param[i].mType == LLCDParam::LLCD_FLOAT) { mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mFloat); llinfos << "Type: float, Default: " << param[i].mDefault.mFloat << llendl; - + LLSliderCtrl::Params p; p.name(name); p.label(name); @@ -956,7 +956,7 @@ void LLFloaterModelPreview::showDecompFloater() { mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mBool); llinfos << "Type: boolean, Default: " << (param[i].mDefault.mBool ? "True" : "False") << llendl; - + LLCheckBoxCtrl::Params p; p.rect(LLRect(left, cur_y, right, cur_y-20)); p.name(name); @@ -973,11 +973,11 @@ void LLFloaterModelPreview::showDecompFloater() S32 cur_x = left; mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue); llinfos << "Type: enum, Default: " << param[i].mDefault.mIntOrEnumValue << llendl; - + { //add label LLTextBox::Params p; const LLFontGL* font = (LLFontGL*) p.font(); - + p.rect(LLRect(left, cur_y, left+font->getWidth(name), cur_y-20)); p.name(name); p.label(name); @@ -986,37 +986,37 @@ void LLFloaterModelPreview::showDecompFloater() mDecompFloater->addChild(text_box); cur_x += text_box->getRect().getWidth(); } - + { //add combo_box LLComboBox::Params p; p.rect(LLRect(cur_x, cur_y, right-right/4, cur_y-20)); p.name(name); p.label(name); p.tool_tip(description); - + llinfos << "Accepted values: " << llendl; LLComboBox* combo_box = LLUICtrlFactory::create(p); for (S32 k = 0; k < param[i].mDetails.mEnumValues.mNumEnums; ++k) { llinfos << param[i].mDetails.mEnumValues.mEnumsArray[k].mValue - << " - " << param[i].mDetails.mEnumValues.mEnumsArray[k].mName << llendl; - + << " - " << param[i].mDetails.mEnumValues.mEnumsArray[k].mName << llendl; + combo_box->add(param[i].mDetails.mEnumValues.mEnumsArray[k].mName, - LLSD::Integer(param[i].mDetails.mEnumValues.mEnumsArray[k].mValue)); + LLSD::Integer(param[i].mDetails.mEnumValues.mEnumsArray[k].mValue)); } combo_box->setValue(param[i].mDefault.mIntOrEnumValue); combo_box->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); mDecompFloater->addChild(combo_box); cur_y += 30; - + } - + llinfos << "----" << llendl; } llinfos << "-----------------------------" << llendl; } } - + cur_y += 30; //explode slider { @@ -1030,11 +1030,11 @@ void LLFloaterModelPreview::showDecompFloater() p.name("explode"); p.rect(LLRect(left, cur_y, right, cur_y-20)); LLSliderCtrl* slider = LLUICtrlFactory::create(p); - + mDecompFloater->addChild(slider); cur_y += 30; } - + //mesh render checkbox { LLCheckBoxCtrl::Params p; @@ -1045,7 +1045,7 @@ void LLFloaterModelPreview::showDecompFloater() check->setValue(true); mDecompFloater->addChild(check); } - + //hull render checkbox { LLCheckBoxCtrl::Params p; @@ -1056,7 +1056,7 @@ void LLFloaterModelPreview::showDecompFloater() check->setValue(true); mDecompFloater->addChild(check); } - + { //submesh combo box label LLTextBox::Params p; p.label("Model"); @@ -1066,7 +1066,7 @@ void LLFloaterModelPreview::showDecompFloater() text_box->setValue("Model"); mDecompFloater->addChild(text_box); } - + { //add submesh combo box LLComboBox::Params p; @@ -1082,16 +1082,16 @@ void LLFloaterModelPreview::showDecompFloater() mDecompFloater->addChild(combo_box); cur_y += 30; } - + mDecompFloater->childSetCommitCallback("model", LLFloaterModelPreview::refresh, LLFloaterModelPreview::sInstance); mDecompFloater->childSetCommitCallback("render_mesh", LLFloaterModelPreview::refresh, LLFloaterModelPreview::sInstance); mDecompFloater->childSetCommitCallback("render_hull", LLFloaterModelPreview::refresh, LLFloaterModelPreview::sInstance); - + mDecompFloater->setRect(LLRect(10, cur_y+20, right+20, 10)); } - + mDecompFloater->childSetCommitCallback("explode", LLFloaterModelPreview::onExplodeCommit, this); - + mDecompFloater->openFloater(); } @@ -1136,7 +1136,7 @@ LLModelLoader::LLModelLoader(std::string filename, S32 lod, LLModelPreview* prev mJointMap["mAnkleLeft"] = "mAnkleLeft"; mJointMap["mFootLeft"] = "mFootLeft"; mJointMap["mToeLeft"] = "mToeLeft"; - + mJointMap["avatar_mPelvis"] = "mPelvis"; mJointMap["avatar_mTorso"] = "mTorso"; mJointMap["avatar_mChest"] = "mChest"; @@ -1163,8 +1163,8 @@ LLModelLoader::LLModelLoader(std::string filename, S32 lod, LLModelPreview* prev mJointMap["avatar_mAnkleLeft"] = "mAnkleLeft"; mJointMap["avatar_mFootLeft"] = "mFootLeft"; mJointMap["avatar_mToeLeft"] = "mToeLeft"; - - + + mJointMap["hip"] = "mPelvis"; mJointMap["abdomen"] = "mTorso"; mJointMap["chest"] = "mChest"; @@ -1200,7 +1200,7 @@ void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4 LLVector4a( 1,-1,-1), LLVector4a( 1,-1, 1), }; - + for (S32 j = 0; j < model->getNumVolumeFaces(); ++j) { const LLVolumeFace& face = model->getVolumeFace(j); @@ -1211,15 +1211,15 @@ void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4 LLVector4a size; size.setSub(face.mExtents[1],face.mExtents[0]); size.mul(0.5f); - + for (U32 i = 0; i < 8; i++) { LLVector4a t; t.setMul(size, box[i]); t.add(center); - + LLVector4a v; - + mat.affineTransform(t, v); if (first_transform) @@ -1239,11 +1239,11 @@ void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& { LLVector4a mina, maxa; LLMatrix4a mata; - + mata.loadu(mat); mina.load3(min.mV); maxa.load3(max.mV); - + stretch_extents(model, mata, mina, maxa, first_transform); min.set(mina.getF32ptr()); @@ -1254,32 +1254,32 @@ void LLModelLoader::run() { DAE dae; domCOLLADA* dom = dae.open(mFilename); - + if (dom) { daeDatabase* db = dae.getDatabase(); - + daeInt count = db->getElementCount(NULL, COLLADA_TYPE_MESH); - + daeDocument* doc = dae.getDoc(mFilename); if (!doc) { llwarns << "can't find internal doc" << llendl; return; } - + daeElement* root = doc->getDomRoot(); if (!root) { llwarns << "document has no root" << llendl; return; } - + //get unit scale mTransform.setIdentity(); - + domAsset::domUnit* unit = daeSafeCast(root->getDescendant(daeElement::matchType(domAsset::domUnit::ID()))); - + if (unit) { F32 meter = unit->getMeter(); @@ -1287,14 +1287,14 @@ void LLModelLoader::run() mTransform.mMatrix[1][1] = meter; mTransform.mMatrix[2][2] = meter; } - + //get up axis rotation LLMatrix4 rotation; - + domUpAxisType up = UPAXISTYPE_Y_UP; // default is Y_UP domAsset::domUp_axis* up_axis = - daeSafeCast(root->getDescendant(daeElement::matchType(domAsset::domUp_axis::ID()))); - + daeSafeCast(root->getDescendant(daeElement::matchType(domAsset::domUp_axis::ID()))); + if (up_axis) { up = up_axis->getValue(); @@ -1308,20 +1308,20 @@ void LLModelLoader::run() { rotation.initRotation(90.0f * DEG_TO_RAD, 0.0f, 0.0f); } - + rotation *= mTransform; mTransform = rotation; - - + + for (daeInt idx = 0; idx < count; ++idx) { //build map of domEntities to LLModel domMesh* mesh = NULL; db->getElement((daeElement**) &mesh, idx, NULL, COLLADA_TYPE_MESH); - + if (mesh) { LLPointer model = LLModel::loadModelFromDomMesh(mesh); - + if (model.notNull() && validate_model(model)) { mModelList.push_back(model); @@ -1329,13 +1329,13 @@ void LLModelLoader::run() } } } - + count = db->getElementCount(NULL, COLLADA_TYPE_SKIN); for (daeInt idx = 0; idx < count; ++idx) { //add skinned meshes as instances domSkin* skin = NULL; db->getElement((daeElement**) &skin, idx, NULL, COLLADA_TYPE_SKIN); - + if (skin) { domGeometry* geom = daeSafeCast(skin->getSource().getElement()); @@ -1351,7 +1351,7 @@ void LLModelLoader::run() LLVector3 mesh_scale_vector; LLVector3 mesh_translation_vector; model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); - + LLMatrix4 normalized_transformation; normalized_transformation.setTranslation(mesh_translation_vector); @@ -1359,13 +1359,13 @@ void LLModelLoader::run() mesh_scale.initScale(mesh_scale_vector); mesh_scale *= normalized_transformation; normalized_transformation = mesh_scale; - + glh::matrix4f inv_mat((F32*) normalized_transformation.mMatrix); inv_mat = inv_mat.inverse(); LLMatrix4 inverse_normalized_transformation(inv_mat.m); - + domSkin::domBind_shape_matrix* bind_mat = skin->getBind_shape_matrix(); - + if (bind_mat) { //get bind shape matrix domFloat4x4& dom_value = bind_mat->getValue(); @@ -1377,28 +1377,28 @@ void LLModelLoader::run() model->mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j*4]; } } - + LLMatrix4 trans = normalized_transformation; trans *= model->mBindShapeMatrix; model->mBindShapeMatrix = trans; - + } - + /*{ - LLMatrix4 rotation; - if (up == UPAXISTYPE_X_UP) - { - rotation.initRotation(0.0f, 90.0f * DEG_TO_RAD, 0.0f); - } - else if (up == UPAXISTYPE_Z_UP) - { - rotation.initRotation(90.0f * DEG_TO_RAD, 90.0f * DEG_TO_RAD, 0.0f); - } - - rotation *= model->mBindShapeMatrix; - model->mBindShapeMatrix = rotation; - }*/ - + LLMatrix4 rotation; + if (up == UPAXISTYPE_X_UP) + { + rotation.initRotation(0.0f, 90.0f * DEG_TO_RAD, 0.0f); + } + else if (up == UPAXISTYPE_Z_UP) + { + rotation.initRotation(90.0f * DEG_TO_RAD, 90.0f * DEG_TO_RAD, 0.0f); + } + + rotation *= model->mBindShapeMatrix; + model->mBindShapeMatrix = rotation; + }*/ + //The joint transfom map that we'll populate below std::map jointTransforms; jointTransforms.clear(); @@ -1406,9 +1406,40 @@ void LLModelLoader::run() //Some collada setup for accessing the skeleton daeElement* pElement = 0; dae.getDatabase()->getElement( &pElement, 0, 0, "skeleton" ); + //Try to get at the skeletal instance controller domInstance_controller::domSkeleton* pSkeleton = daeSafeCast( pElement ); - if ( pSkeleton ) - { + bool missingSkeletonOrScene = false; + + //If no skeleton, do a breadth-first search to get at specific joints + if ( !pSkeleton ) + { + daeElement* pScene = root->getDescendant("visual_scene"); + if ( !pScene ) + { + llwarns<<"No visual scene - unable to parse bone offsets "< > children = pScene->getChildren(); + S32 childCount = children.getCount(); + + //Process any children that are joints + //Not all children are joints, some code be ambient lights, cameras, geometry etc.. + for (S32 i = 0; i < childCount; ++i) + { + domNode* pNode = daeSafeCast(children[i]); + if ( isNodeAJoint( pNode ) ) + { + processJointNode( pNode, jointTransforms ); + } + } + } + } + else + //Has Skeleton + { //Get the root node of the skeleton daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement(); if ( pSkeletonRootNode ) @@ -1416,7 +1447,7 @@ void LLModelLoader::run() //Once we have the root node - start acccessing it's joint components const int jointCnt = mJointMap.size(); std::map :: const_iterator jointIt = mJointMap.begin(); - bool missingID = false; + //Loop over all the possible joints within the .dae - using the allowed joint list in the ctor. for ( int i=0; i( resolver.getElement() ); - if ( pJoint ) - { - //Pull out the translate id and store it in the jointTranslations map - daeSIDResolver jointResolver( pJoint, "./translate" ); - domTranslate* pTranslate = daeSafeCast( jointResolver.getElement() ); - - LLMatrix4 workingTransform; - - //Translation via SID - if ( pTranslate ) - { - domFloat3 jointTrans = pTranslate->getValue(); - LLVector3 singleJointTranslation( jointTrans[0], jointTrans[1], jointTrans[2] ); - workingTransform.setTranslation( singleJointTranslation ); - } - else - { - //Translation via child from element - daeElement* pTranslateElement = getChildFromElement( pJoint, "translate" ); - if ( pTranslateElement && pTranslateElement->typeID() != domTranslate::ID() ) - { - llwarns<< "The found element is not a translate node" <( pTranslateElement ); - domFloat3 translateChild = pTranslateChild->getValue(); - LLVector3 singleJointTranslation( translateChild[0], translateChild[1], translateChild[2] ); - workingTransform.setTranslation( singleJointTranslation ); - } - } - //Store the joint transform w/respect to it's name. - jointTransforms[(*jointIt).second.c_str()] = workingTransform; + + //Setup the resolver + daeSIDResolver resolver( pSkeletonRootNode, str ); + + //Look for the joint + domNode* pJoint = daeSafeCast( resolver.getElement() ); + if ( pJoint ) + { + //Pull out the translate id and store it in the jointTranslations map + daeSIDResolver jointResolver( pJoint, "./translate" ); + domTranslate* pTranslate = daeSafeCast( jointResolver.getElement() ); + + LLMatrix4 workingTransform; + + //Translation via SID + if ( pTranslate ) + { + extractTranslation( pTranslate, workingTransform ); + } + else + { + //Translation via child from element + daeElement* pTranslateElement = getChildFromElement( pJoint, "translate" ); + if ( pTranslateElement && pTranslateElement->typeID() != domTranslate::ID() ) + { + llwarns<< "The found element is not a translate node" <getJoint( lookingForJoint ); - if ( pJoint ) - { - pJoint->storeCurrentXform( jointTransform.getTranslation() ); - } - else - { - //Most likely an error in the asset. - llwarns<<"Tried to apply joint position from .dae, but it did not exist in the avatar rig." << llendl; - } - //Reposition the avatars pelvis (avPos+offset) - //if ( !strcmp( (*jointIt).first.c_str(),"mPelvis" ) ) - if ( lookingForJoint == "mPelvis" ) - { - const LLVector3& pos = gAgentAvatarp->getCharacterPosition(); - gAgentAvatarp->setPelvisOffset( true, jointTransform.getTranslation() ); - gAgentAvatarp->setPosition( pos + jointTransform.getTranslation() ); - } - } - } - } - else - { - llwarns<<"No root node in this skeleton" << llendl; - } - } - else - { - llwarns<<"No skeleton in this asset" << llendl; + }//got skeleton? } + if ( !missingSkeletonOrScene ) + { + //Set the joint translations on the avatar + //The joints are reset in the dtor + const int jointCnt = mJointMap.size(); + std::map :: const_iterator jointIt = mJointMap.begin(); + for ( int i=0; igetJoint( lookingForJoint ); + if ( pJoint ) + { + pJoint->storeCurrentXform( jointTransform.getTranslation() ); + } + else + { + //Most likely an error in the asset. + llwarns<<"Tried to apply joint position from .dae, but it did not exist in the avatar rig." << llendl; + } + //Reposition the avatars pelvis (avPos+offset) + if ( lookingForJoint == "mPelvis" ) + { + const LLVector3& pos = gAgentAvatarp->getCharacterPosition(); + gAgentAvatarp->setPelvisOffset( true, jointTransform.getTranslation() ); + gAgentAvatarp->setPosition( pos + jointTransform.getTranslation() ); + } + } + } + } //missingSkeletonOrScene + + domSkin::domJoints* joints = skin->getJoints(); - + domInputLocal_Array& joint_input = joints->getInput_array(); - + for (size_t i = 0; i < joint_input.getCount(); ++i) { domInputLocal* input = joint_input.get(i); xsNMTOKEN semantic = input->getSemantic(); - + if (strcmp(semantic, COMMON_PROFILE_INPUT_JOINT) == 0) { //found joint source, fill model->mJointMap and model->mJointList daeElement* elem = input->getSource().getElement(); @@ -1533,13 +1556,13 @@ void LLModelLoader::run() if (source) { - + domName_array* names_source = source->getName_array(); if (names_source) { domListOfNames &names = names_source->getValue(); - + for (size_t j = 0; j < names.getCount(); ++j) { std::string name(names.get(j)); @@ -1557,7 +1580,7 @@ void LLModelLoader::run() if (names_source) { xsIDREFS& names = names_source->getValue(); - + for (size_t j = 0; j < names.getCount(); ++j) { std::string name(names.get(j).getID()); @@ -1582,11 +1605,11 @@ void LLModelLoader::run() { domListOfFloats& transform = t->getValue(); S32 count = transform.getCount()/16; - + for (S32 k = 0; k < count; ++k) { LLMatrix4 mat; - + for (int i = 0; i < 4; i++) { for(int j = 0; j < 4; j++) @@ -1594,14 +1617,14 @@ void LLModelLoader::run() mat.mMatrix[i][j] = transform[k*16 + i + j*4]; } } - + model->mInvBindMatrix.push_back(mat); } } } } } - + //We need to construct the alternate bind matrix (which contains the new joint positions) //in the same order as they were stored in the joint buffer. The joints associated //with the skeleton are not stored in the same order as they are in the exported joint buffer. @@ -1652,10 +1675,10 @@ void LLModelLoader::run() } LLVector3 v(pos[j], pos[j+1], pos[j+2]); - + //transform from COLLADA space to volume space v = v * inverse_normalized_transformation; - + model->mPosition.push_back(v); } } @@ -1663,7 +1686,7 @@ void LLModelLoader::run() } } } - + //grab skin weights array domSkin::domVertex_weights* weights = skin->getVertex_weights(); if (weights) @@ -1681,44 +1704,44 @@ void LLModelLoader::run() } } } - + if (vertex_weights) { domListOfFloats& w = vertex_weights->getValue(); domListOfUInts& vcount = weights->getVcount()->getValue(); domListOfInts& v = weights->getV()->getValue(); - + U32 c_idx = 0; for (size_t vc_idx = 0; vc_idx < vcount.getCount(); ++vc_idx) { //for each vertex daeUInt count = vcount[vc_idx]; - + //create list of weights that influence this vertex LLModel::weight_list weight_list; - + for (daeUInt i = 0; i < count; ++i) { //for each weight daeInt joint_idx = v[c_idx++]; daeInt weight_idx = v[c_idx++]; - + if (joint_idx == -1) { //ignore bindings to bind_shape_matrix continue; } - + F32 weight_value = w[weight_idx]; - + weight_list.push_back(LLModel::JointWeight(joint_idx, weight_value)); } - + //sort by joint weight std::sort(weight_list.begin(), weight_list.end(), LLModel::CompareWeightGreater()); - + std::vector wght; F32 total = 0.f; - + for (U32 i = 0; i < llmin((U32) 4, (U32) weight_list.size()); ++i) { //take up to 4 most significant weights if (weight_list[i].mWeight > 0.f) @@ -1736,7 +1759,7 @@ void LLModelLoader::run() wght[i].mWeight *= scale; } } - + model->mSkinWeights[model->mPosition[vc_idx]] = wght; } @@ -1754,78 +1777,153 @@ void LLModelLoader::run() } } } - + daeElement* scene = root->getDescendant("visual_scene"); if (!scene) { llwarns << "document has no visual_scene" << llendl; return; } - + processElement(scene); - + mPreview->loadModelCallback(mLod); } } - -daeElement* LLModelLoader::getChildFromElement( daeElement* pElement, std::string const & name ) -{ - daeElement* pChildOfElement = pElement->getChild( name.c_str() ); - if ( pChildOfElement ) - { - return pChildOfElement; - } - llwarns<< "Could not find a child [" << name << "] for the element: \"" << pElement->getAttribute("id") << "\"" << llendl; - return NULL; -} + +bool LLModelLoader::isNodeAJoint( domNode* pNode ) +{ + if ( mJointMap.find( pNode->getName() ) != mJointMap.end() ) + { + return true; + } + + return false; +} + +void LLModelLoader::extractTranslation( domTranslate* pTranslate, LLMatrix4& transform ) +{ + domFloat3 jointTrans = pTranslate->getValue(); + LLVector3 singleJointTranslation( jointTrans[0], jointTrans[1], jointTrans[2] ); + transform.setTranslation( singleJointTranslation ); +} + +void LLModelLoader::extractTranslationViaElement( daeElement* pTranslateElement, LLMatrix4& transform ) +{ + domTranslate* pTranslateChild = dynamic_cast( pTranslateElement ); + domFloat3 translateChild = pTranslateChild->getValue(); + LLVector3 singleJointTranslation( translateChild[0], translateChild[1], translateChild[2] ); + transform.setTranslation( singleJointTranslation ); +} + +void LLModelLoader::processJointNode( domNode* pNode, std::map& jointTransforms ) +{ + //llwarns<<"ProcessJointNode# Node:" <getName()<( jointResolver.getElement() ); + + //Translation via SID was successful + if ( pTranslate ) + { + extractTranslation( pTranslate, workingTransform ); + } + else + { + //Translation via child from element + daeElement* pTranslateElement = getChildFromElement( pNode, "translate" ); + if ( pTranslateElement && pTranslateElement->typeID() != domTranslate::ID() ) + { + llwarns<< "The found element is not a translate node" <getName() ] = workingTransform; + + //2. handle the nodes children + + //Gather and handle the incoming nodes children + daeTArray< daeSmartRef > childOfChild = pNode->getChildren(); + S32 childOfChildCount = childOfChild.getCount(); + + for (S32 i = 0; i < childOfChildCount; ++i) + { + domNode* pChildNode = daeSafeCast( childOfChild[i] ); + if ( pChildNode ) + { + processJointNode( pChildNode, jointTransforms ); + } + } +} + +daeElement* LLModelLoader::getChildFromElement( daeElement* pElement, std::string const & name ) +{ + daeElement* pChildOfElement = pElement->getChild( name.c_str() ); + if ( pChildOfElement ) + { + return pChildOfElement; + } + llwarns<< "Could not find a child [" << name << "] for the element: \"" << pElement->getAttribute("id") << "\"" << llendl; + return NULL; +} void LLModelLoader::processElement(daeElement* element) { LLMatrix4 saved_transform = mTransform; - + domTranslate* translate = daeSafeCast(element); if (translate) { domFloat3 dom_value = translate->getValue(); - + LLMatrix4 translation; translation.setTranslation(LLVector3(dom_value[0], dom_value[1], dom_value[2])); translation *= mTransform; mTransform = translation; } - + domRotate* rotate = daeSafeCast(element); if (rotate) { domFloat4 dom_value = rotate->getValue(); - + LLMatrix4 rotation; rotation.initRotTrans(dom_value[3] * DEG_TO_RAD, LLVector3(dom_value[0], dom_value[1], dom_value[2]), LLVector3(0, 0, 0)); - + rotation *= mTransform; mTransform = rotation; } - + domScale* scale = daeSafeCast(element); if (scale) { domFloat3 dom_value = scale->getValue(); - + LLMatrix4 scaling; scaling.initScale(LLVector3(dom_value[0], dom_value[1], dom_value[2])); - + scaling *= mTransform; mTransform = scaling; } - + domMatrix* matrix = daeSafeCast(element); if (matrix) { domFloat4x4 dom_value = matrix->getValue(); - + LLMatrix4 matrix_transform; - + for (int i = 0; i < 4; i++) { for(int j = 0; j < 4; j++) @@ -1837,7 +1935,7 @@ void LLModelLoader::processElement(daeElement* element) matrix_transform *= mTransform; mTransform = matrix_transform; } - + domInstance_geometry* instance_geo = daeSafeCast(element); if (instance_geo) { @@ -1851,14 +1949,14 @@ void LLModelLoader::processElement(daeElement* element) if (model) { LLMatrix4 transformation = mTransform; - + std::vector materials = getMaterials(model, instance_geo); - + // adjust the transformation to compensate for mesh normalization LLVector3 mesh_scale_vector; LLVector3 mesh_translation_vector; model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); - + LLMatrix4 mesh_translation; mesh_translation.setTranslation(mesh_translation_vector); mesh_translation *= transformation; @@ -1870,13 +1968,13 @@ void LLModelLoader::processElement(daeElement* element) transformation = mesh_scale; mScene[transformation].push_back(LLModelInstance(model, transformation, materials)); - + stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); } } } } - + domInstance_node* instance_node = daeSafeCast(element); if (instance_node) { @@ -1886,14 +1984,14 @@ void LLModelLoader::processElement(daeElement* element) processElement(instance); } } - + //process children daeTArray< daeSmartRef > children = element->getChildren(); for (S32 i = 0; i < children.getCount(); i++) { processElement(children[i]); } - + domNode* node = daeSafeCast(element); if (node) { //this element was a node, restore transform before processiing siblings @@ -1907,40 +2005,40 @@ std::vector LLModelLoader::getMaterials(LLModel* model, domIns for (int i = 0; i < model->mMaterialList.size(); i++) { LLImportMaterial import_material; - + domInstance_material* instance_mat = NULL; - + domBind_material::domTechnique_common* technique = - daeSafeCast(instance_geo->getDescendant(daeElement::matchType(domBind_material::domTechnique_common::ID()))); - + daeSafeCast(instance_geo->getDescendant(daeElement::matchType(domBind_material::domTechnique_common::ID()))); + if (technique) { daeTArray< daeSmartRef > inst_materials = technique->getChildrenByType(); for (int j = 0; j < inst_materials.getCount(); j++) { std::string symbol(inst_materials[j]->getSymbol()); - + if (symbol == model->mMaterialList[i]) // found the binding { instance_mat = inst_materials[j]; } } } - + if (instance_mat) { domMaterial* material = daeSafeCast(instance_mat->getTarget().getElement()); if (material) { domInstance_effect* instance_effect = - daeSafeCast(material->getDescendant(daeElement::matchType(domInstance_effect::ID()))); + daeSafeCast(material->getDescendant(daeElement::matchType(domInstance_effect::ID()))); if (instance_effect) { domEffect* effect = daeSafeCast(instance_effect->getUrl().getElement()); if (effect) { domProfile_COMMON* profile = - daeSafeCast(effect->getDescendant(daeElement::matchType(domProfile_COMMON::ID()))); + daeSafeCast(effect->getDescendant(daeElement::matchType(domProfile_COMMON::ID()))); if (profile) { import_material = profileToMaterial(profile); @@ -1952,7 +2050,7 @@ std::vector LLModelLoader::getMaterials(LLModel* model, domIns materials.push_back(import_material); } - + return materials; } @@ -1960,12 +2058,12 @@ LLImportMaterial LLModelLoader::profileToMaterial(domProfile_COMMON* material) { LLImportMaterial mat; mat.mFullbright = FALSE; - + daeElement* diffuse = material->getDescendant("diffuse"); if (diffuse) { domCommon_color_or_texture_type_complexType::domTexture* texture = - daeSafeCast(diffuse->getDescendant("texture")); + daeSafeCast(diffuse->getDescendant("texture")); if (texture) { domCommon_newparam_type_Array newparams = material->getNewparam_array(); @@ -1989,10 +2087,10 @@ LLImportMaterial LLModelLoader::profileToMaterial(domProfile_COMMON* material) if (init) { std::string filename = cdom::uriToNativePath(init->getValue().str()); - + mat.mDiffuseMap = LLViewerTextureManager::getFetchedTextureFromUrl("file://" + filename, TRUE, LLViewerTexture::BOOST_PREVIEW); mat.mDiffuseMap->setLoadedCallback(LLModelPreview::textureLoadedCallback, 0, TRUE, FALSE, this->mPreview, NULL, FALSE); - + mat.mDiffuseMap->forceToSaveRawImage(); mat.mDiffuseMapFilename = filename; mat.mDiffuseMapLabel = getElementLabel(material); @@ -2005,7 +2103,7 @@ LLImportMaterial LLModelLoader::profileToMaterial(domProfile_COMMON* material) } domCommon_color_or_texture_type_complexType::domColor* color = - daeSafeCast(diffuse->getDescendant("color")); + daeSafeCast(diffuse->getDescendant("color")); if (color) { domFx_color_common domfx_color = color->getValue(); @@ -2013,7 +2111,7 @@ LLImportMaterial LLModelLoader::profileToMaterial(domProfile_COMMON* material) mat.mDiffuseColor = value; } } - + daeElement* emission = material->getDescendant("emission"); if (emission) { @@ -2023,7 +2121,7 @@ LLImportMaterial LLModelLoader::profileToMaterial(domProfile_COMMON* material) mat.mFullbright = TRUE; } } - + return mat; } @@ -2036,13 +2134,13 @@ std::string LLModelLoader::getElementLabel(daeElement *element) { return name; } - + // if we have an ID attribute, use it if (element->getID()) { return std::string(element->getID()); } - + // if we have a parent, use it daeElement* parent = element->getParent(); if (parent) @@ -2053,21 +2151,21 @@ std::string LLModelLoader::getElementLabel(daeElement *element) { return name; } - + // if parent has an ID, use it if (parent->getID()) { return std::string(parent->getID()); } } - + // try to use our type daeString element_name = element->getElementName(); if (element_name) { return std::string(element_name); } - + // if all else fails, use "object" return std::string("object"); } @@ -2076,13 +2174,13 @@ LLColor4 LLModelLoader::getDaeColor(daeElement* element) { LLColor4 value; domCommon_color_or_texture_type_complexType::domColor* color = - daeSafeCast(element->getDescendant("color")); + daeSafeCast(element->getDescendant("color")); if (color) { domFx_color_common domfx_color = color->getValue(); value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]); } - + return value; } @@ -2102,17 +2200,17 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloaterModelPreview* fmp mPreviewLOD = 3; mModelLoader = NULL; mDirty = false; - + for (U32 i = 0; i < LLModel::NUM_LODS; i++) { mLODMode[i] = 1; mLimit[i] = 0; } - + mLODMode[0] = 0; - + mFMP = fmp; - + glodInit(); } @@ -2123,7 +2221,7 @@ LLModelPreview::~LLModelPreview() delete mModelLoader; mModelLoader = NULL; } - + //*HACK : *TODO : turn this back on when we understand why this crashes //glodShutdown(); } @@ -2131,40 +2229,40 @@ LLModelPreview::~LLModelPreview() U32 LLModelPreview::calcResourceCost() { rebuildUploadData(); - + U32 cost = 0; std::set accounted; U32 num_points = 0; U32 num_hulls = 0; - + F32 debug_scale = mFMP->childGetValue("debug scale").asReal(); - + F32 streaming_cost = 0.f; - + for (U32 i = 0; i < mUploadData.size(); ++i) { LLModelInstance& instance = mUploadData[i]; - + if (accounted.find(instance.mModel) == accounted.end()) { accounted.insert(instance.mModel); - + LLModel::convex_hull_decomposition& decomp = - instance.mLOD[LLModel::LOD_PHYSICS] ? - instance.mLOD[LLModel::LOD_PHYSICS]->mConvexHullDecomp : - instance.mModel->mConvexHullDecomp; - + instance.mLOD[LLModel::LOD_PHYSICS] ? + instance.mLOD[LLModel::LOD_PHYSICS]->mConvexHullDecomp : + instance.mModel->mConvexHullDecomp; + LLSD ret = LLModel::writeModel( - "", - instance.mLOD[4], - instance.mLOD[3], - instance.mLOD[2], - instance.mLOD[1], - instance.mLOD[0], - decomp, - mFMP->childGetValue("upload_skin").asBoolean(), - mFMP->childGetValue("upload_joints").asBoolean(), - TRUE); + "", + instance.mLOD[4], + instance.mLOD[3], + instance.mLOD[2], + instance.mLOD[1], + instance.mLOD[0], + decomp, + mFMP->childGetValue("upload_skin").asBoolean(), + mFMP->childGetValue("upload_joints").asBoolean(), + TRUE); cost += gMeshRepo.calcResourceCost(ret); num_hulls += decomp.size(); @@ -2172,12 +2270,12 @@ U32 LLModelPreview::calcResourceCost() { num_points += decomp[i].size(); } - + //calculate streaming cost LLMatrix4 transformation = instance.mTransform; - + LLVector3 position = LLVector3(0, 0, 0) * transformation; - + LLVector3 x_transformed = LLVector3(1, 0, 0) * transformation - position; LLVector3 y_transformed = LLVector3(0, 1, 0) * transformation - position; LLVector3 z_transformed = LLVector3(0, 0, 1) * transformation - position; @@ -2185,13 +2283,13 @@ U32 LLModelPreview::calcResourceCost() F32 y_length = y_transformed.normalize(); F32 z_length = z_transformed.normalize(); LLVector3 scale = LLVector3(x_length, y_length, z_length); - + F32 radius = scale.length()*debug_scale; - + streaming_cost += LLMeshRepository::getStreamingCost(ret, radius); } } - + mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[HULLS]", llformat("%d",num_hulls)); mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[POINTS]", llformat("%d",num_points)); mFMP->childSetTextArg("streaming cost", "[COST]", llformat("%.3f", streaming_cost)); @@ -2199,7 +2297,7 @@ U32 LLModelPreview::calcResourceCost() mFMP->childSetTextArg("dimensions", "[X]", llformat("%.3f", mPreviewScale[0]*scale)); mFMP->childSetTextArg("dimensions", "[Y]", llformat("%.3f", mPreviewScale[1]*scale)); mFMP->childSetTextArg("dimensions", "[Z]", llformat("%.3f", mPreviewScale[2]*scale)); - + updateStatusMessages(); return cost; @@ -2209,30 +2307,30 @@ void LLModelPreview::rebuildUploadData() { mUploadData.clear(); mTextureSet.clear(); - + //fill uploaddata instance vectors from scene data - + LLSpinCtrl* scale_spinner = mFMP->getChild("debug scale"); - + if (!scale_spinner) { llerrs << "floater_model_preview.xml MUST contain debug scale spinner." << llendl; } - + F32 scale = scale_spinner->getValue().asReal(); - + LLMatrix4 scale_mat; scale_mat.initScale(LLVector3(scale, scale, scale)); - + F32 max_scale = 0.f; - + for (LLModelLoader::scene::iterator iter = mBaseScene.begin(); iter != mBaseScene.end(); ++iter) { //for each transform in scene LLMatrix4 mat = iter->first; - + // compute position LLVector3 position = LLVector3(0, 0, 0) * mat; - + // compute scale LLVector3 x_transformed = LLVector3(1, 0, 0) * mat - position; LLVector3 y_transformed = LLVector3(0, 1, 0) * mat - position; @@ -2244,13 +2342,13 @@ void LLModelPreview::rebuildUploadData() max_scale = llmax(llmax(llmax(max_scale, x_length), y_length), z_length); mat *= scale_mat; - + for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) { //for each instance with said transform applied LLModelInstance instance = *model_iter; - + LLModel* base_model = instance.mModel; - + S32 idx = 0; for (idx = 0; idx < mBaseModel.size(); ++idx) { //find reference instance for this model @@ -2259,7 +2357,7 @@ void LLModelPreview::rebuildUploadData() break; } } - + for (U32 i = 0; i < LLModel::NUM_LODS; i++) { //fill LOD slots based on reference model index if (!mModel[i].empty()) @@ -2271,16 +2369,16 @@ void LLModelPreview::rebuildUploadData() instance.mLOD[i] = NULL; } } - + instance.mTransform = mat; mUploadData.push_back(instance); } } - + F32 max_import_scale = DEFAULT_MAX_PRIM_SCALE/max_scale; - + scale_spinner->setMaxValue(max_import_scale); - + if (max_import_scale < scale) { scale_spinner->setValue(max_import_scale); @@ -2294,7 +2392,7 @@ void LLModelPreview::clearModel(S32 lod) { return; } - + mVertexBuffer[lod].clear(); mModel[lod].clear(); mScene[lod].clear(); @@ -2309,7 +2407,7 @@ void LLModelPreview::loadModel(std::string filename, S32 lod) delete mModelLoader; mModelLoader = NULL; } - + if (filename.empty()) { if (mBaseModel.empty()) @@ -2318,11 +2416,11 @@ void LLModelPreview::loadModel(std::string filename, S32 lod) // if we don't have a base model to show for high LOD. mFMP->closeFloater(false); } - + mFMP->mLoading = false; return; } - + if (lod == 3 && !mGroup.empty()) { for (std::map, U32>::iterator iter = mGroup.begin(); iter != mGroup.end(); ++iter) @@ -2330,29 +2428,29 @@ void LLModelPreview::loadModel(std::string filename, S32 lod) glodDeleteGroup(iter->second); stop_gloderror(); } - + for (std::map, U32>::iterator iter = mObject.begin(); iter != mObject.end(); ++iter) { glodDeleteObject(iter->second); stop_gloderror(); } - + mGroup.clear(); mObject.clear(); } - + mModelLoader = new LLModelLoader(filename, lod, this); - + mModelLoader->start(); - + mFMP->childSetTextArg("status", "[STATUS]", mFMP->getString("status_reading_file")); - + if (mFMP->childGetValue("description_form").asString().empty()) { std::string name = gDirUtilp->getBaseFileName(filename, true); mFMP->childSetValue("description_form", name); } - + mFMP->openFloater(); } @@ -2367,7 +2465,7 @@ void LLModelPreview::clearIncompatible(S32 lod) mModel[i].clear(); mScene[i].clear(); mVertexBuffer[i].clear(); - + if (i == LLModel::LOD_HIGH) { mBaseModel = mModel[lod]; @@ -2386,7 +2484,7 @@ void LLModelPreview::loadModelCallback(S32 lod) { return; } - + mModel[lod] = mModelLoader->mModelList; mScene[lod] = mModelLoader->mScene; mVertexBuffer[lod].clear(); @@ -2395,7 +2493,7 @@ void LLModelPreview::loadModelCallback(S32 lod) { mPhysicsMesh.clear(); } - + setPreviewLOD(lod); @@ -2406,9 +2504,9 @@ void LLModelPreview::loadModelCallback(S32 lod) mVertexBuffer[5].clear(); //mModel[lod] = NULL; } - + clearIncompatible(lod); - + mDirty = true; resetPreviewTarget(); @@ -2427,28 +2525,28 @@ void LLModelPreview::resetPreviewTarget() void LLModelPreview::smoothNormals() { S32 which_lod = mPreviewLOD; - - + + if (which_lod > 4 || which_lod < 0 || mModel[which_lod].empty()) { return; } - + F32 angle_cutoff = mFMP->childGetValue("edge threshold").asReal(); - + angle_cutoff *= DEG_TO_RAD; - + if (which_lod == 3 && !mBaseModel.empty()) { for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) { (*iter)->smoothNormals(angle_cutoff); } - + mVertexBuffer[5].clear(); } - + for (LLModelLoader::model_list::iterator iter = mModel[which_lod].begin(); iter != mModel[which_lod].end(); ++iter) { (*iter)->smoothNormals(angle_cutoff); @@ -2456,22 +2554,22 @@ void LLModelPreview::smoothNormals() mVertexBuffer[which_lod].clear(); refresh(); - + } void LLModelPreview::consolidate() { std::map > composite; - + LLMatrix4 identity; - + //bake out each node in current scene to composite for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) { //for each transform in current scene LLMatrix4 mat = iter->first; glh::matrix4f inv_trans = glh::matrix4f((F32*) mat.mMatrix).inverse().transpose(); LLMatrix4 norm_mat(inv_trans.m); - + for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) { //for each instance with that transform LLModelInstance& source_instance = *model_iter; @@ -2481,15 +2579,15 @@ void LLModelPreview::consolidate() { llerrs << "Invalid model found!" << llendl; } - + for (S32 i = 0; i < source->getNumVolumeFaces(); ++i) { //for each face in instance const LLVolumeFace& src_face = source->getVolumeFace(i); LLImportMaterial& source_material = source_instance.mMaterial[i]; - + //get model in composite that is composite for this material LLModel* model = NULL; - + if (composite.find(source_material) != composite.end()) { model = composite[source_material].rbegin()->mModel; @@ -2498,7 +2596,7 @@ void LLModelPreview::consolidate() model = NULL; } } - + if (model == NULL) { //no model found, make new model std::vector materials; @@ -2510,91 +2608,91 @@ void LLModelPreview::consolidate() model->setNumVolumeFaces(0); composite[source_material].push_back(LLModelInstance(model, identity, materials)); } - + model->appendFace(src_face, source->mMaterialList[i], mat, norm_mat); } } } - - + + //condense composite into as few LLModel instances as possible LLModelLoader::model_list new_model; std::vector instance_list; LLVolumeParams volume_params; volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); - + std::vector empty_material; LLModelInstance cur_instance(new LLModel(volume_params, 0.f), identity, empty_material); cur_instance.mModel->setNumVolumeFaces(0); - + BOOL first_transform = TRUE; - + LLModelLoader::scene new_scene; LLVector3 min,max; - + for (std::map >::iterator iter = composite.begin(); - iter != composite.end(); - ++iter) + iter != composite.end(); + ++iter) { std::map >::iterator next_iter = iter; ++next_iter; for (std::vector::iterator instance_iter = iter->second.begin(); - instance_iter != iter->second.end(); - ++instance_iter) + instance_iter != iter->second.end(); + ++instance_iter) { LLModel* source = instance_iter->mModel; - + if (instance_iter->mMaterial.size() != 1) { llerrs << "WTF?" << llendl; } - + if (source->getNumVolumeFaces() != 1) { llerrs << "WTF?" << llendl; } - + if (source->mMaterialList.size() != 1) { llerrs << "WTF?" << llendl; } - + cur_instance.mModel->addFace(source->getVolumeFace(0)); cur_instance.mMaterial.push_back(instance_iter->mMaterial[0]); cur_instance.mModel->mMaterialList.push_back(source->mMaterialList[0]); - + BOOL last_model = FALSE; - + std::vector::iterator next_instance = instance_iter; ++next_instance; - + if (next_iter == composite.end() && next_instance == iter->second.end()) { last_model = TRUE; } - + if (last_model || cur_instance.mModel->getNumVolumeFaces() >= MAX_MODEL_FACES) { cur_instance.mModel->mLabel = source->mLabel; - + cur_instance.mModel->optimizeVolumeFaces(); cur_instance.mModel->normalizeVolumeFaces(); - + if (!validate_model(cur_instance.mModel)) { llerrs << "Invalid model detected." << llendl; } - + new_model.push_back(cur_instance.mModel); - + LLMatrix4 transformation = LLMatrix4(); - + // adjust the transformation to compensate for mesh normalization LLVector3 mesh_scale_vector; LLVector3 mesh_translation_vector; cur_instance.mModel->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); - + LLMatrix4 mesh_translation; mesh_translation.setTranslation(mesh_translation_vector); mesh_translation *= transformation; @@ -2604,12 +2702,12 @@ void LLModelPreview::consolidate() mesh_scale.initScale(mesh_scale_vector); mesh_scale *= transformation; transformation = mesh_scale; - + cur_instance.mTransform = transformation; - + new_scene[transformation].push_back(cur_instance); stretch_extents(cur_instance.mModel, transformation, min, max, first_transform); - + if (!last_model) { cur_instance = LLModelInstance(new LLModel(volume_params, 0.f), identity, empty_material); @@ -2618,24 +2716,24 @@ void LLModelPreview::consolidate() } } } - + mScene[mPreviewLOD] = new_scene; mModel[mPreviewLOD] = new_model; mVertexBuffer[mPreviewLOD].clear(); - + if (mPreviewLOD == LLModel::LOD_HIGH) { mBaseScene = new_scene; mBaseModel = new_model; mVertexBuffer[5].clear(); } - + mPreviewTarget = (min+max)*0.5f; mPreviewScale = (max-min)*0.5f; setPreviewTarget(mPreviewScale.magVec()*2.f); - + clearIncompatible(mPreviewLOD); - + mResourceCost = calcResourceCost(); refresh(); } @@ -2652,7 +2750,7 @@ void LLModelPreview::scrubMaterials() for (S32 i = 0; i < source->getNumVolumeFaces(); ++i) { //for each face in instance LLImportMaterial& source_material = source_instance.mMaterial[i]; - + //clear material info source_material.mDiffuseColor = LLColor4(1,1,1,1); source_material.mDiffuseMap = NULL; @@ -2662,17 +2760,17 @@ void LLModelPreview::scrubMaterials() } } } - - + + mVertexBuffer[mPreviewLOD].clear(); - + if (mPreviewLOD == LLModel::LOD_HIGH) { mBaseScene = mScene[mPreviewLOD]; mBaseModel = mModel[mPreviewLOD]; mVertexBuffer[5].clear(); } - + mResourceCost = calcResourceCost(); refresh(); } @@ -2698,26 +2796,26 @@ void LLModelPreview::genLODs(S32 which_lod) { return; } - + if (which_lod == LLModel::LOD_PHYSICS) { //clear physics mesh map mPhysicsMesh.clear(); } - + LLVertexBuffer::unbind(); - + stop_gloderror(); static U32 cur_name = 1; - + S32 limit = -1; - + if (which_lod != -1) { limit = mLimit[which_lod]; } - + U32 triangle_count = 0; - + for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) { LLModel* mdl = *iter; @@ -2726,11 +2824,11 @@ void LLModelPreview::genLODs(S32 which_lod) triangle_count += mdl->getVolumeFace(i).mNumIndices/3; } } - + U32 base_triangle_count = triangle_count; - + U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; - + if (mGroup[mBaseModel[0]] == 0) { //clear LOD maps mGroup.clear(); @@ -2738,7 +2836,7 @@ void LLModelPreview::genLODs(S32 which_lod) mPercentage.clear(); mPatch.clear(); } - + for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) { //build GLOD objects for each model in base model list LLModel* mdl = *iter; @@ -2746,32 +2844,32 @@ void LLModelPreview::genLODs(S32 which_lod) { mGroup[mdl] = cur_name++; mObject[mdl] = cur_name++; - + glodNewGroup(mGroup[mdl]); stop_gloderror(); - + glodGroupParameteri(mGroup[mdl], GLOD_ADAPT_MODE, GLOD_TRIANGLE_BUDGET); stop_gloderror(); - + glodGroupParameteri(mGroup[mdl], GLOD_ERROR_MODE, GLOD_OBJECT_SPACE_ERROR); stop_gloderror(); - + glodGroupParameterf(mGroup[mdl], GLOD_OBJECT_SPACE_ERROR_THRESHOLD, 0.025f); stop_gloderror(); - + glodNewObject(mObject[mdl], mGroup[mdl], GLOD_DISCRETE); stop_gloderror(); - + if (iter == mBaseModel.begin() && !mdl->mSkinWeights.empty()) { //regenerate vertex buffer for skinned models to prevent animation feedback during LOD generation mVertexBuffer[5].clear(); } - + if (mVertexBuffer[5].empty()) { genBuffers(5, false); } - + U32 tri_count = 0; for (U32 i = 0; i < mVertexBuffer[5][mdl].size(); ++i) { @@ -2784,10 +2882,10 @@ void LLModelPreview::genLODs(S32 which_lod) tri_count += num_indices/3; stop_gloderror(); } - + //store what percentage of total model (in terms of triangle count) this model makes up mPercentage[mdl] = (F32) tri_count / (F32) base_triangle_count; - + //build glodobject glodBuildObject(mObject[mdl]); if (stop_gloderror()) @@ -2796,18 +2894,18 @@ void LLModelPreview::genLODs(S32 which_lod) stop_gloderror(); glodDeleteObject(mObject[mdl]); stop_gloderror(); - + mGroup[mdl] = 0; mObject[mdl] = 0; - + if (which_lod == -1) { mModel[LLModel::LOD_HIGH] = mBaseModel; } - + return; } - + } //generating LODs for all entries, or this entry has a triangle budget @@ -2817,11 +2915,11 @@ void LLModelPreview::genLODs(S32 which_lod) glodGroupParameterf(mGroup[mdl], GLOD_OBJECT_SPACE_ERROR_THRESHOLD, 0.025f); stop_gloderror(); } - - + + S32 start = LLModel::LOD_HIGH; S32 end = 0; - + if (which_lod != -1) { start = end = which_lod; @@ -2836,7 +2934,7 @@ void LLModelPreview::genLODs(S32 which_lod) "high detail combo", "physics detail combo" }; - + std::string limit_name[] = { "lowest limit", @@ -2845,7 +2943,7 @@ void LLModelPreview::genLODs(S32 which_lod) "high limit", "physics limit" }; - + for (S32 lod = start; lod >= end; --lod) { if (which_lod == -1) @@ -2859,59 +2957,59 @@ void LLModelPreview::genLODs(S32 which_lod) { triangle_count = limit; } - + LLComboBox* combo_box = mFMP->findChild(combo_name[lod]); combo_box->setCurrentByIndex(2); - + LLSpinCtrl* lim = mFMP->getChild(limit_name[lod], TRUE); lim->setMaxValue(base_triangle_count); lim->setVisible(true); - + mModel[lod].clear(); mModel[lod].resize(mBaseModel.size()); mVertexBuffer[lod].clear(); - + U32 actual_tris = 0; U32 actual_verts = 0; U32 submeshes = 0; - + for (U32 mdl_idx = 0; mdl_idx < mBaseModel.size(); ++mdl_idx) { LLModel* base = mBaseModel[mdl_idx]; - + U32 target_count = U32(mPercentage[base]*triangle_count); - + if (target_count < 4) { target_count = 4; } - + glodGroupParameteri(mGroup[base], GLOD_MAX_TRIANGLES, target_count); stop_gloderror(); - + glodAdaptGroup(mGroup[base]); stop_gloderror(); - + GLint patch_count = 0; glodGetObjectParameteriv(mObject[base], GLOD_NUM_PATCHES, &patch_count); stop_gloderror(); - + LLVolumeParams volume_params; volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); mModel[lod][mdl_idx] = new LLModel(volume_params, 0.f); - + GLint* sizes = new GLint[patch_count*2]; glodGetObjectParameteriv(mObject[base], GLOD_PATCH_SIZES, sizes); stop_gloderror(); - + GLint* names = new GLint[patch_count]; glodGetObjectParameteriv(mObject[base], GLOD_PATCH_NAMES, names); stop_gloderror(); - + mModel[lod][mdl_idx]->setNumVolumeFaces(patch_count); LLModel* target_model = mModel[lod][mdl_idx]; - + for (GLint i = 0; i < patch_count; ++i) { LLPointer buff = new LLVertexBuffer(type_mask, 0); @@ -2931,29 +3029,29 @@ void LLModelPreview::genLODs(S32 which_lod) } buff->validateRange(0, buff->getNumVerts()-1, buff->getNumIndices(), 0); - + LLStrider pos; LLStrider norm; LLStrider tc; LLStrider index; - + buff->getVertexStrider(pos); buff->getNormalStrider(norm); buff->getTexCoord0Strider(tc); buff->getIndexStrider(index); - - + + target_model->setVolumeFaceData(names[i], pos, norm, tc, index, buff->getNumVerts(), buff->getNumIndices()); actual_tris += buff->getNumIndices()/3; actual_verts += buff->getNumVerts(); ++submeshes; - + if (!validate_face(target_model->getVolumeFace(names[i]))) { llerrs << "Invalid face generated during LOD generation." << llendl; } } - + //blind copy skin weights and just take closest skin weight to point on //decimated mesh for now (auto-generating LODs with skin weights is still a bit //of an open problem). @@ -2966,20 +3064,20 @@ void LLModelPreview::genLODs(S32 which_lod) target_model->mAlternateBindMatrix = base->mAlternateBindMatrix; //copy material list target_model->mMaterialList = base->mMaterialList; - + if (!validate_model(target_model)) { llerrs << "Invalid model generated when creating LODs" << llendl; } - + delete [] sizes; delete [] names; } - + //rebuild scene based on mBaseScene mScene[lod].clear(); mScene[lod] = mBaseScene; - + for (U32 i = 0; i < mBaseModel.size(); ++i) { LLModel* mdl = mBaseModel[i]; @@ -2999,19 +3097,19 @@ void LLModelPreview::genLODs(S32 which_lod) } } } - + mResourceCost = calcResourceCost(); - + /*if (which_lod == -1 && mScene[LLModel::LOD_PHYSICS].empty()) - { //build physics scene - mScene[LLModel::LOD_PHYSICS] = mScene[LLModel::LOD_LOW]; - mModel[LLModel::LOD_PHYSICS] = mModel[LLModel::LOD_LOW]; - - for (U32 i = 1; i < mModel[LLModel::LOD_PHYSICS].size(); ++i) - { - mPhysicsQ.push(mModel[LLModel::LOD_PHYSICS][i]); - } - }*/ + { //build physics scene + mScene[LLModel::LOD_PHYSICS] = mScene[LLModel::LOD_LOW]; + mModel[LLModel::LOD_PHYSICS] = mModel[LLModel::LOD_LOW]; + + for (U32 i = 1; i < mModel[LLModel::LOD_PHYSICS].size(); ++i) + { + mPhysicsQ.push(mModel[LLModel::LOD_PHYSICS][i]); + } + }*/ } void LLModelPreview::updateStatusMessages() @@ -3025,30 +3123,30 @@ void LLModelPreview::updateStatusMessages() S32 total_tris[LLModel::NUM_LODS]; S32 total_verts[LLModel::NUM_LODS]; S32 total_submeshes[LLModel::NUM_LODS]; - + for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) { //initialize total for this lod to 0 total_tris[lod] = total_verts[lod] = total_submeshes[lod] = 0; - + for (U32 i = 0; i < mModel[lod].size(); ++i) { //for each model in the lod S32 cur_tris = 0; S32 cur_verts = 0; S32 cur_submeshes = mModel[lod][i]->getNumVolumeFaces(); - + for (S32 j = 0; j < cur_submeshes; ++j) { //for each submesh (face), add triangles and vertices to current total const LLVolumeFace& face = mModel[lod][i]->getVolumeFace(j); cur_tris += face.mNumIndices/3; cur_verts += face.mNumVertices; } - + //add this model to the lod total total_tris[lod] += cur_tris; total_verts[lod] += cur_verts; total_submeshes[lod] += cur_submeshes; - + //store this model's counts to asset data tris[lod].push_back(cur_tris); verts[lod].push_back(cur_verts); @@ -3056,21 +3154,21 @@ void LLModelPreview::updateStatusMessages() } } - + std::string upload_message; - + mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[TRIANGLES]", llformat("%d", total_tris[LLModel::LOD_PHYSICS])); - + for (S32 lod = 0; lod <= LLModel::LOD_HIGH; ++lod) { mFMP->childSetTextArg(info_name[lod], "[TRIANGLES]", llformat("%d", total_tris[lod])); mFMP->childSetTextArg(info_name[lod], "[VERTICES]", llformat("%d", total_verts[lod])); mFMP->childSetTextArg(info_name[lod], "[SUBMESHES]", llformat("%d", total_submeshes[lod])); - + std::string message = "good"; const U32 lod_high = LLModel::LOD_HIGH; - + if (lod != lod_high) { if (total_submeshes[lod] && total_submeshes[lod] != total_submeshes[lod_high]) @@ -3088,7 +3186,7 @@ void LLModelPreview::updateStatusMessages() for (U32 i = 0; i < verts[lod].size(); ++i) { S32 max_verts = verts[lod+1][i]; - + if (verts[lod][i] > max_verts) { message = "too_heavy"; @@ -3097,10 +3195,10 @@ void LLModelPreview::updateStatusMessages() } } } - + mFMP->childSetTextArg(info_name[lod], "[MESSAGE]", mFMP->getString(message)); } - + if (upload_message.empty()) { mFMP->childSetTextArg("upload_message", "[MESSAGE]", std::string("")); @@ -3135,9 +3233,9 @@ void LLModelPreview::genBuffers(S32 lod, bool avatar_preview) U32 tri_count = 0; U32 vertex_count = 0; U32 mesh_count = 0; - + LLModelLoader::model_list* model = NULL; - + if (lod < 0 || lod > 4) { model = &mBaseModel; @@ -3147,16 +3245,16 @@ void LLModelPreview::genBuffers(S32 lod, bool avatar_preview) { model = &(mModel[lod]); } - + if (!mVertexBuffer[lod].empty()) { mVertexBuffer[lod].clear(); } - + mVertexBuffer[lod].clear(); - + LLModelLoader::model_list::iterator base_iter = mBaseModel.begin(); - + for (LLModelLoader::model_list::iterator iter = model->begin(); iter != model->end(); ++iter) { LLModel* mdl = *iter; @@ -3164,47 +3262,47 @@ void LLModelPreview::genBuffers(S32 lod, bool avatar_preview) { continue; } - + LLModel* base_mdl = *base_iter; base_iter++; - + for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) { const LLVolumeFace &vf = mdl->getVolumeFace(i); U32 num_vertices = vf.mNumVertices; U32 num_indices = vf.mNumIndices; - + if (!num_vertices || ! num_indices) { continue; } - + LLVertexBuffer* vb = NULL; bool skinned = avatar_preview && !mdl->mSkinWeights.empty(); - + U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; if (skinned) { mask |= LLVertexBuffer::MAP_WEIGHT4; } - + vb = new LLVertexBuffer(mask, 0); vb->allocateBuffer(num_vertices, num_indices, TRUE); - + LLStrider vertex_strider; LLStrider normal_strider; LLStrider tc_strider; LLStrider index_strider; LLStrider weights_strider; - + vb->getVertexStrider(vertex_strider); vb->getNormalStrider(normal_strider); vb->getTexCoord0Strider(tc_strider); vb->getIndexStrider(index_strider); - + if (skinned) { vb->getWeight4Strider(weights_strider); @@ -3213,22 +3311,22 @@ void LLModelPreview::genBuffers(S32 lod, bool avatar_preview) LLVector4a::memcpyNonAliased16((F32*) vertex_strider.get(), (F32*) vf.mPositions, num_vertices*4*sizeof(F32)); LLVector4a::memcpyNonAliased16((F32*) tc_strider.get(), (F32*) vf.mTexCoords, num_vertices*2*sizeof(F32)); LLVector4a::memcpyNonAliased16((F32*) normal_strider.get(), (F32*) vf.mNormals, num_vertices*4*sizeof(F32)); - + if (skinned) { for (U32 i = 0; i < num_vertices; i++) { //find closest weight to vf.mVertices[i].mPosition LLVector3 pos(vf.mPositions[i].getF32ptr()); - + const LLModel::weight_list& weight_list = base_mdl->getJointInfluences(pos); - + LLVector4 w(0,0,0,0); if (weight_list.size() > 4) { llerrs << "WTF?" << llendl; } - + for (U32 i = 0; i < weight_list.size(); ++i) { F32 wght = llmin(weight_list[i].mWeight, 0.999999f); @@ -3239,19 +3337,19 @@ void LLModelPreview::genBuffers(S32 lod, bool avatar_preview) *(weights_strider++) = w; } } - + // build indices for (U32 i = 0; i < num_indices; i++) { *(index_strider++) = vf.mIndices[i]; } - + mVertexBuffer[lod][mdl].push_back(vb); - + vertex_count += num_vertices; tri_count += num_indices/3; ++mesh_count; - + } } } @@ -3272,33 +3370,33 @@ BOOL LLModelPreview::render() { LLMutexLock lock(this); mNeedsUpdate = FALSE; - + S32 width = getWidth(); S32 height = getHeight(); - + LLGLSUIDefault def; LLGLDisable no_blend(GL_BLEND); LLGLEnable cull(GL_CULL_FACE); LLGLDepthTest depth(GL_TRUE); LLGLDisable fog(GL_FOG); - + glMatrixMode(GL_PROJECTION); gGL.pushMatrix(); glLoadIdentity(); glOrtho(0.0f, width, 0.0f, height, -1.0f, 1.0f); - + glMatrixMode(GL_MODELVIEW); gGL.pushMatrix(); glLoadIdentity(); - + gGL.color4f(0.15f, 0.2f, 0.3f, 1.f); - + gl_rect_2d_simple( width, height ); - + bool avatar_preview = false; bool upload_skin = mFMP->childGetValue("upload_skin").asBoolean(); bool upload_joints = mFMP->childGetValue("upload_joints").asBoolean(); - + for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) { for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) @@ -3311,19 +3409,19 @@ BOOL LLModelPreview::render() } } } - + if (upload_skin && !avatar_preview) { mFMP->childSetValue("upload_skin", false); upload_skin = false; } - + if (!upload_skin && upload_joints) { mFMP->childSetValue("upload_joints", false); upload_joints = false; } - + if (!avatar_preview) { mFMP->childDisable("upload_skin"); @@ -3332,7 +3430,7 @@ BOOL LLModelPreview::render() { mFMP->childEnable("upload_skin"); } - + if (!upload_skin) { mFMP->childDisable("upload_joints"); @@ -3341,125 +3439,125 @@ BOOL LLModelPreview::render() { mFMP->childEnable("upload_joints"); } - + avatar_preview = avatar_preview && upload_skin; - - + + mFMP->childSetEnabled("consolidate", !avatar_preview); F32 explode = mFMP->mDecompFloater ? mFMP->mDecompFloater->childGetValue("explode").asReal() : 0.f; - + glMatrixMode(GL_PROJECTION); gGL.popMatrix(); - + glMatrixMode(GL_MODELVIEW); gGL.popMatrix(); - + glClear(GL_DEPTH_BUFFER_BIT); - + LLViewerCamera::getInstance()->setAspect((F32) width / height ); LLViewerCamera::getInstance()->setView(LLViewerCamera::getInstance()->getDefaultFOV() / mCameraZoom); - + LLVector3 target_pos = mPreviewTarget; LLVector3 offset = mCameraOffset; - + F32 z_near = llmax(mCameraDistance-mPreviewScale.magVec(), 0.001f); F32 z_far = mCameraDistance+mPreviewScale.magVec(); - + if (avatar_preview) { target_pos = gAgentAvatarp->getPositionAgent(); z_near = 0.01f; z_far = 1024.f; mCameraDistance = 16.f; - + //render avatar previews every frame refresh(); } - + LLQuaternion camera_rot = LLQuaternion(mCameraPitch, LLVector3::y_axis) * - LLQuaternion(mCameraYaw, LLVector3::z_axis); - + LLQuaternion(mCameraYaw, LLVector3::z_axis); + LLQuaternion av_rot = camera_rot; LLViewerCamera::getInstance()->setOriginAndLookAt( - target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + offset) * av_rot), // camera - LLVector3::z_axis, // up - target_pos); // point of interest - + target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + offset) * av_rot), // camera + LLVector3::z_axis, // up + target_pos); // point of interest + LLViewerCamera::getInstance()->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, width, height, FALSE, z_near, z_far); - + stop_glerror(); - + gPipeline.enableLightsAvatar(); - + gGL.pushMatrix(); const F32 BRIGHTNESS = 0.9f; gGL.color3f(BRIGHTNESS, BRIGHTNESS, BRIGHTNESS); LLGLEnable normalize(GL_NORMALIZE); - + if (!mBaseModel.empty() && mVertexBuffer[5].empty()) { genBuffers(-1, avatar_preview); //genBuffers(3); //genLODs(); } - + bool physics = (mPreviewLOD == LLModel::LOD_PHYSICS); - + S32 physics_idx = -1; - + bool render_mesh = true; bool render_hull = false; - + if (physics && mFMP->mDecompFloater) { physics_idx = mFMP->mDecompFloater->childGetValue("model").asInteger(); render_mesh = mFMP->mDecompFloater->childGetValue("render_mesh").asBoolean(); render_hull = mFMP->mDecompFloater->childGetValue("render_hull").asBoolean(); } - + if (!mModel[mPreviewLOD].empty()) { if (mVertexBuffer[mPreviewLOD].empty()) { genBuffers(mPreviewLOD, avatar_preview); } - + if (!avatar_preview) { //for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) { LLModelInstance& instance = *iter; - + gGL.pushMatrix(); LLMatrix4 mat = instance.mTransform; - + glMultMatrixf((GLfloat*) mat.mMatrix); //for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) { //LLModelInstance& instance = *model_iter; LLModel* model = instance.mLOD[mPreviewLOD]; - + if (!model) { continue; } - + //if (instance.mTransform != mat) //{ // llerrs << "WTF?" << llendl; //} - + if (render_mesh) { for (U32 i = 0; i < mVertexBuffer[mPreviewLOD][model].size(); ++i) { LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; - + buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); if (physics) { @@ -3484,11 +3582,11 @@ BOOL LLModelPreview::render() } } } - + buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); glColor3f(0.4f, 0.4f, 0.4f); - + if (mFMP->childGetValue("show edges").asBoolean()) { glLineWidth(3.f); @@ -3499,16 +3597,16 @@ BOOL LLModelPreview::render() } } } - + if (render_hull) { LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread; if (decomp) { LLMutexLock(decomp->mMutex); - + std::map, std::vector > >::iterator iter = - mPhysicsMesh.find(model); + mPhysicsMesh.find(model); if (iter != mPhysicsMesh.end()) { for (U32 i = 0; i < iter->second.size(); ++i) @@ -3516,28 +3614,28 @@ BOOL LLModelPreview::render() if (explode > 0.f) { gGL.pushMatrix(); - + LLVector3 offset = model->mHullCenter[i]-model->mCenterOfHullCenters; offset *= explode; - + gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]); } - + static std::vector hull_colors; - + if (i+1 >= hull_colors.size()) { hull_colors.push_back(LLColor4U(rand()%128+127, rand()%128+127, rand()%128+127, 255)); } - + LLVertexBuffer* buff = iter->second[i]; if (buff) { buff->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL); - + glColor4ubv(hull_colors[i].mV); buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts()); - + if (mFMP->childGetValue("show edges").asBoolean()) { glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); @@ -3548,7 +3646,7 @@ BOOL LLModelPreview::render() glLineWidth(1.f); } } - + if (explode > 0.f) { gGL.popMatrix(); @@ -3556,15 +3654,15 @@ BOOL LLModelPreview::render() } } } - + //mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[HULLS]", llformat("%d",decomp->mHulls.size())); //mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[POINTS]", llformat("%d",decomp->mTotalPoints)); } } - + gGL.popMatrix(); } - + if (physics) { mPreviewLOD = LLModel::LOD_PHYSICS; @@ -3574,29 +3672,29 @@ BOOL LLModelPreview::render() { LLVOAvatarSelf* avatar = gAgentAvatarp; target_pos = avatar->getPositionAgent(); - + LLViewerCamera::getInstance()->setOriginAndLookAt( - target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + offset) * av_rot), // camera - LLVector3::z_axis, // up - target_pos); // point of interest - + target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + offset) * av_rot), // camera + LLVector3::z_axis, // up + target_pos); // point of interest + avatar->renderCollisionVolumes(); - + for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) { for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) { LLModelInstance& instance = *model_iter; LLModel* model = instance.mModel; - + if (!model->mSkinWeights.empty()) { for (U32 i = 0; i < mVertexBuffer[mPreviewLOD][model].size(); ++i) { LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; - + const LLVolumeFace& face = model->getVolumeFace(i); - + LLStrider position; buffer->getVertexStrider(position); @@ -3604,7 +3702,7 @@ BOOL LLModelPreview::render() buffer->getWeight4Strider(weight); //quick 'n dirty software vertex skinning - + //build matrix palette LLMatrix4 mat[64]; for (U32 j = 0; j < model->mJointList.size(); ++j) @@ -3616,55 +3714,55 @@ BOOL LLModelPreview::render() mat[j] *= joint->getWorldMatrix(); } } - + for (U32 j = 0; j < buffer->getRequestedVerts(); ++j) { LLMatrix4 final_mat; final_mat.mMatrix[0][0] = final_mat.mMatrix[1][1] = final_mat.mMatrix[2][2] = final_mat.mMatrix[3][3] = 0.f; - + LLVector4 wght; S32 idx[4]; - + F32 scale = 0.f; for (U32 k = 0; k < 4; k++) { F32 w = weight[j].mV[k]; - + idx[k] = (S32) floorf(w); wght.mV[k] = w - floorf(w); scale += wght.mV[k]; } - + wght *= 1.f/scale; - + for (U32 k = 0; k < 4; k++) { F32* src = (F32*) mat[idx[k]].mMatrix; F32* dst = (F32*) final_mat.mMatrix; - + F32 w = wght.mV[k]; - + for (U32 l = 0; l < 16; l++) { dst[l] += src[l]*w; } } - + //VECTORIZE THIS LLVector3 v(face.mPositions[j].getF32ptr()); v = v * model->mBindShapeMatrix; v = v * final_mat; - + position[j] = v; } - + buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); glColor4fv(instance.mMaterial[i].mDiffuseColor.mV); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); glColor3f(0.4f, 0.4f, 0.4f); - + if (mFMP->childGetValue("show edges").asBoolean()) { glLineWidth(3.f); @@ -3679,9 +3777,9 @@ BOOL LLModelPreview::render() } } } - + gGL.popMatrix(); - + return TRUE; } @@ -3699,7 +3797,7 @@ void LLModelPreview::refresh() void LLModelPreview::rotate(F32 yaw_radians, F32 pitch_radians) { mCameraYaw = mCameraYaw + yaw_radians; - + mCameraPitch = llclamp(mCameraPitch + pitch_radians, F_PI_BY_TWO * -0.8f, F_PI_BY_TWO * 0.8f); } @@ -3709,7 +3807,7 @@ void LLModelPreview::rotate(F32 yaw_radians, F32 pitch_radians) void LLModelPreview::zoom(F32 zoom_amt) { F32 new_zoom = mCameraZoom+zoom_amt; - + mCameraZoom = llclamp(new_zoom, 1.f, 10.f); } @@ -3757,17 +3855,17 @@ void LLFloaterModelPreview::onBrowseLowestLOD(void* data) void LLFloaterModelPreview::onUpload(void* user_data) { LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; - + if (mp->mDecompFloater) { mp->mDecompFloater->closeFloater(); } - + mp->mModelPreview->rebuildUploadData(); - + gMeshRepo.uploadModel(mp->mModelPreview->mUploadData, mp->mModelPreview->mPreviewScale, - mp->childGetValue("upload_textures").asBoolean(), mp->childGetValue("upload_skin"), mp->childGetValue("upload_joints")); - + mp->childGetValue("upload_textures").asBoolean(), mp->childGetValue("upload_skin"), mp->childGetValue("upload_joints")); + mp->closeFloater(false); } @@ -3818,15 +3916,15 @@ LLFloaterModelPreview::DecompRequest::DecompRequest(const std::string& stage, LL mContinue = 1; mModel = mdl; mParams = sInstance->mDecompParams; - + //copy out positions and indices if (mdl) { U16 index_offset = 0; - + mPositions.clear(); mIndices.clear(); - + //queue up vertex positions and indices for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) { @@ -3835,17 +3933,17 @@ LLFloaterModelPreview::DecompRequest::DecompRequest(const std::string& stage, LL { continue; } - + for (U32 j = 0; j < face.mNumVertices; ++j) { mPositions.push_back(LLVector3(face.mPositions[j].getF32ptr())); } - + for (U32 j = 0; j < face.mNumIndices; ++j) { mIndices.push_back(face.mIndices[j]+index_offset); } - + index_offset += face.mNumVertices; } } @@ -3874,4 +3972,3 @@ void LLFloaterModelPreview::DecompRequest::completed() } } - -- cgit v1.2.3 From 292941ac947d0ef07431a3addcfbe72287031cc4 Mon Sep 17 00:00:00 2001 From: prep linden Date: Fri, 19 Nov 2010 16:08:32 -0500 Subject: Fix for crash on accessing a translation element that is NULL --- indra/newview/llfloatermodelpreview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index d3da7533ec..142767529e 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1837,7 +1837,7 @@ void LLModelLoader::processJointNode( domNode* pNode, std::maptypeID() != domTranslate::ID() ) + if ( !pTranslateElement || pTranslateElement->typeID() != domTranslate::ID() ) { llwarns<< "The found element is not a translate node" < Date: Fri, 19 Nov 2010 17:07:01 -0600 Subject: SH-448 Initial draft of implementing UI spec for "advanced" importer. --- indra/newview/llfloatermodelpreview.cpp | 1333 +++++++++++++++---------------- 1 file changed, 631 insertions(+), 702 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 1c73a6cb31..b52e54275a 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -105,28 +105,54 @@ const S32 PREVIEW_TEXTURE_HEIGHT = 300; void drawBoxOutline(const LLVector3& pos, const LLVector3& size); -std::string limit_name[] = + +std::string lod_name[] = +{ + "lowest", + "low", + "medium", + "high", + "I went off the end of the lod_name array. Me so smart." +}; + +std::string lod_triangles_name[] = { - "lowest limit", - "low limit", - "medium limit", - "high limit", - "physics limit", + "lowest_triangles", + "low_triangles", + "medium_triangles", + "high_triangles", + "I went off the end of the lod_triangles_name array. Me so smart." +}; - "I went off the end of the limit_name array. Me so smart." +std::string lod_vertices_name[] = +{ + "lowest_vertices", + "low_vertices", + "medium_vertices", + "high_vertices", + "I went off the end of the lod_vertices_name array. Me so smart." }; -std::string info_name[] = +std::string lod_status_name[] = { - "lowest info", - "low info", - "medium info", - "high info", - "physics info", + "lowest_status", + "low_status", + "medium_status", + "high_status", + "I went off the end of the lod_status_name array. Me so smart." +}; - "I went off the end of the info_name array. Me so smart." +std::string lod_label_name[] = +{ + "lowest_label", + "low_label", + "medium_label", + "high_label", + "I went off the end of the lod_label_name array. Me so smart." }; + + bool validate_face(const LLVolumeFace& face) { for (U32 i = 0; i < face.mNumIndices; ++i) @@ -185,20 +211,6 @@ BOOL stop_gloderror() return FALSE; } -LLPhysicsDecompFloater::LLPhysicsDecompFloater(LLSD& key) -: LLFloater(key) -{ - -} - -LLPhysicsDecompFloater::~LLPhysicsDecompFloater() -{ - if (LLFloaterModelPreview::sInstance && LLFloaterModelPreview::sInstance->mDecompFloater) - { - LLFloaterModelPreview::sInstance->mDecompFloater = NULL; - } -} - class LLMeshFilePicker : public LLFilePickerThread { public: @@ -230,7 +242,6 @@ LLFloaterModelPreview::LLFloaterModelPreview(const LLSD& key) : mLastMouseY = 0; mGLName = 0; mLoading = FALSE; - mDecompFloater = NULL; } //----------------------------------------------------------------------------- @@ -243,75 +254,73 @@ BOOL LLFloaterModelPreview::postBuild() return FALSE; } - childSetCommitCallback("high detail combo", onHighLODCommit, this); - childSetCommitCallback("medium detail combo", onMediumLODCommit, this); - childSetCommitCallback("low detail combo", onLowLODCommit, this); - childSetCommitCallback("lowest detail combo", onLowestLODCommit, this); - childSetCommitCallback("physics detail combo", onPhysicsLODCommit, this); - - - childSetCommitCallback("high limit", onHighLimitCommit, this); - childSetCommitCallback("medium limit", onMediumLimitCommit, this); - childSetCommitCallback("low limit", onLowLimitCommit, this); - childSetCommitCallback("lowest limit", onLowestLimitCommit, this); - childSetCommitCallback("physics limit", onPhysicsLimitCommit, this); - - childSetCommitCallback("smooth normals", onSmoothNormalsCommit, this); + childSetAction("lod_browse", onBrowseLOD, this); + childSetCommitCallback("lod_triangle_limit", onTriangleLimitCommit, this); + + childSetCommitCallback("crease_angle", onGenerateNormalsCommit, this); + childSetCommitCallback("generate_normals", onGenerateNormalsCommit, this); childSetCommitCallback("show edges", onShowEdgesCommit, this); - childSetCommitCallback("auto fill", onAutoFillCommit, this); + childSetCommitCallback("lod_generate", onAutoFillCommit, this); childSetTextArg("status", "[STATUS]", getString("status_idle")); - for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) - { - if (lod == LLModel::LOD_PHYSICS) - { - childSetTextArg(info_name[lod], "[TRIANGLES]", std::string("0")); - childSetTextArg(info_name[lod], "[HULLS]", std::string("0")); - childSetTextArg(info_name[lod], "[POINTS]", std::string("0")); - } - else - { - childSetTextArg(info_name[lod], "[TRIANGLES]", std::string("0")); - childSetTextArg(info_name[lod], "[VERTICES]", std::string("0")); - childSetTextArg(info_name[lod], "[SUBMESHES]", std::string("0")); - std::string msg = getString("required"); - childSetTextArg(info_name[lod], "[MESSAGE]", msg); - } - - childSetVisible(limit_name[lod], FALSE); - } - //childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d",sUploadAmount)); childSetAction("ok_btn", onUpload, this); childSetAction("consolidate", onConsolidate, this); - childSetAction("scrub materials", onScrubMaterials, this); - - childSetAction("decompose_btn", onDecompose, this); + childSetAction("clear_materials", onClearMaterials, this); childSetCommitCallback("preview_lod_combo", onPreviewLODCommit, this); childSetCommitCallback("upload_skin", onUploadSkinCommit, this); childSetCommitCallback("upload_joints", onUploadJointsCommit, this); - childSetCommitCallback("debug scale", onDebugScaleCommit, this); + childSetCommitCallback("import_scale", onImportScaleCommit, this); + + childSetCommitCallback("lod_file_or_limit", refresh, this); + childSetCommitCallback("physics_load_radio", refresh, this); childDisable("upload_skin"); childDisable("upload_joints"); + + initDecompControls(); - const U32 width = 512; - const U32 height = 512; + LLView* preview_panel = getChild("preview_panel"); - mPreviewRect.set(getRect().getWidth()-PREVIEW_HPAD-width, - PREVIEW_HPAD+height, - getRect().getWidth()-PREVIEW_HPAD, - PREVIEW_HPAD); + mPreviewRect = preview_panel->getRect(); mModelPreview = new LLModelPreview(512, 512, this); mModelPreview->setPreviewTarget(16.f); + //set callbacks for left click on line editor rows + for (U32 i = 0; i <= LLModel::LOD_HIGH; i++) + { + LLTextBox* text = getChild(lod_label_name[i]); + if (text) + { + text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i)); + } + + text = getChild(lod_triangles_name[i]); + if (text) + { + text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i)); + } + + text = getChild(lod_vertices_name[i]); + if (text) + { + text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i)); + } + + text = getChild(lod_status_name[i]); + if (text) + { + text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i)); + } + } + return TRUE; } @@ -333,12 +342,6 @@ LLFloaterModelPreview::~LLFloaterModelPreview() { LLImageGL::deleteTextures(1, &mGLName ); } - - if (mDecompFloater) - { - mDecompFloater->closeFloater(); - mDecompFloater = NULL; - } } void LLFloaterModelPreview::loadModel(S32 lod) @@ -348,58 +351,6 @@ void LLFloaterModelPreview::loadModel(S32 lod) (new LLMeshFilePicker(this, lod))->getFile(); } -void LLFloaterModelPreview::setLODMode(S32 lod, S32 mode) -{ - if (mode == 0) - { - if (lod != LLModel::LOD_PHYSICS) - { - for (S32 i = lod; i >= 0; i--) - { - mModelPreview->clearModel(i); - } - } - else - { - mModelPreview->clearModel(lod); - } - - mModelPreview->refresh(); - mModelPreview->calcResourceCost(); - } - else if (mode == 1) - { - loadModel(lod); - } - else if (mode != mModelPreview->mLODMode[lod]) - { - mModelPreview->mLODMode[lod] = mode; - mModelPreview->genLODs(lod); - } - - mModelPreview->setPreviewLOD(lod); - - - LLSpinCtrl* lim = getChild(limit_name[lod], TRUE); - - if (mode == 2) //triangle count - { - U32 tri_count = 0; - for (LLModelLoader::model_list::iterator iter = mModelPreview->mBaseModel.begin(); - iter != mModelPreview->mBaseModel.end(); ++iter) - { - tri_count += (*iter)->getNumTriangles(); - } - - lim->setMaxValue(tri_count); - lim->setVisible(TRUE); - } - else - { - lim->setVisible(FALSE); - } -} - void LLFloaterModelPreview::setLimit(S32 lod, S32 limit) { if (limit != mModelPreview->mLimit[lod]) @@ -411,7 +362,7 @@ void LLFloaterModelPreview::setLimit(S32 lod, S32 limit) } //static -void LLFloaterModelPreview::onDebugScaleCommit(LLUICtrl*,void* userdata) +void LLFloaterModelPreview::onImportScaleCommit(LLUICtrl*,void* userdata) { LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; @@ -421,6 +372,7 @@ void LLFloaterModelPreview::onDebugScaleCommit(LLUICtrl*,void* userdata) } fp->mModelPreview->calcResourceCost(); + fp->mModelPreview->refresh(); } //static @@ -471,68 +423,6 @@ void LLFloaterModelPreview::onPreviewLODCommit(LLUICtrl* ctrl, void* userdata) fp->mModelPreview->setPreviewLOD(which_mode); } -//static -void LLFloaterModelPreview::setLODMode(S32 lod, void* userdata) -{ - LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; - - if (!fp->mModelPreview) - { - return; - } - - S32 which_mode = 0; - - std::string combo_name[] = - { - "lowest detail combo", - "low detail combo", - "medium detail combo", - "high detail combo", - "physics detail combo", - - "I went off the end of the combo_name array. Me so smart." - }; - - LLCtrlSelectionInterface* iface = fp->childGetSelectionInterface(combo_name[lod]); - if (iface) - { - which_mode = iface->getFirstSelectedIndex(); - } - - fp->setLODMode(lod, which_mode); -} - -//static -void LLFloaterModelPreview::onHighLODCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview::setLODMode(3, userdata); -} - -//static -void LLFloaterModelPreview::onMediumLODCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview::setLODMode(2, userdata); -} - -//static -void LLFloaterModelPreview::onLowLODCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview::setLODMode(1, userdata); -} - -//static -void LLFloaterModelPreview::onLowestLODCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview::setLODMode(0, userdata); -} - -//static -void LLFloaterModelPreview::onPhysicsLODCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview::setLODMode(4, userdata); -} - //static void LLFloaterModelPreview::setLimit(S32 lod, void* userdata) { @@ -543,48 +433,26 @@ void LLFloaterModelPreview::setLimit(S32 lod, void* userdata) return; } - S32 limit = fp->childGetValue(limit_name[lod]).asInteger(); + S32 limit = fp->childGetValue("lod_triangle_limit").asInteger(); fp->setLimit(lod, limit); } //static -void LLFloaterModelPreview::onHighLimitCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview::setLimit(3, userdata); -} - -//static -void LLFloaterModelPreview::onMediumLimitCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview::setLimit(2, userdata); -} - -//static -void LLFloaterModelPreview::onLowLimitCommit(LLUICtrl* ctrl, void* userdata) +void LLFloaterModelPreview::onTriangleLimitCommit(LLUICtrl* ctrl, void* userdata) { - LLFloaterModelPreview::setLimit(1, userdata); -} - -//static -void LLFloaterModelPreview::onLowestLimitCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview::setLimit(0, userdata); -} + LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; -//static -void LLFloaterModelPreview::onPhysicsLimitCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview::setLimit(4, userdata); + LLFloaterModelPreview::setLimit(fp->mModelPreview->mPreviewLOD, userdata); } //static -void LLFloaterModelPreview::onSmoothNormalsCommit(LLUICtrl* ctrl, void* userdata) +void LLFloaterModelPreview::onGenerateNormalsCommit(LLUICtrl* ctrl, void* userdata) { LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; - fp->mModelPreview->smoothNormals(); + fp->mModelPreview->generateNormals(); } //static @@ -627,22 +495,14 @@ void LLFloaterModelPreview::draw() childSetTextArg("status", "[STATUS]", getString("status_idle")); } - childSetTextArg("description_label", "[PRIM_COST]", llformat("%d", mModelPreview->mResourceCost)); + childSetTextArg("prim_cost", "[PRIM_COST]", llformat("%d", mModelPreview->mResourceCost)); childSetTextArg("description_label", "[TEXTURES]", llformat("%d", mModelPreview->mTextureSet.size())); - if (mDecompFloater) + if (mCurRequest.notNull()) { - if (mCurRequest.notNull()) - { - mDecompFloater->childSetText("status", mCurRequest->mStatusMessage); - } - else - { - const std::string idle("Idle."); - mDecompFloater->childSetText("status", idle); - } + childSetTextArg("status", "[STATUS]", mCurRequest->mStatusMessage); } - + U32 resource_cost = mModelPreview->mResourceCost*10; if (childGetValue("upload_textures").asBoolean()) @@ -658,6 +518,16 @@ void LLFloaterModelPreview::draw() gGL.getTexUnit(0)->bind(mModelPreview); + + LLView* preview_panel = getChild("preview_panel"); + + LLRect rect = preview_panel->getRect(); + if (rect != mPreviewRect) + { + mModelPreview->refresh(); + mPreviewRect = preview_panel->getRect(); + } + gGL.begin( LLRender::QUADS ); { gGL.texCoord2f(0.f, 1.f); @@ -807,13 +677,10 @@ void LLFloaterModelPreview::onPhysicsStageExecute(LLUICtrl* ctrl, void* data) if (sInstance->mModelPreview) { - if (sInstance->mDecompFloater) + S32 idx = sInstance->childGetValue("physics_layer").asInteger(); + if (idx >= 0 && idx < sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS].size()) { - S32 idx = sInstance->mDecompFloater->childGetValue("model").asInteger(); - if (idx >= 0 && idx < sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS].size()) - { - mdl = sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS][idx]; - } + mdl = sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS][idx]; } } } @@ -823,276 +690,198 @@ void LLFloaterModelPreview::onPhysicsStageExecute(LLUICtrl* ctrl, void* data) sInstance->mCurRequest = new DecompRequest(stage->mName, mdl); gMeshRepo.mDecompThread->submitRequest(sInstance->mCurRequest); } + + const std::string decompose("Decompose"); + + if (decompose == stage->mName) + { //hide decompose panel and show simplify panel + sInstance->childSetVisible("physics step 2", false); + sInstance->childSetVisible("physics step 3", true); + } } //static -void LLFloaterModelPreview::onPhysicsStageCancel(LLUICtrl* ctrl, void*data) +void LLFloaterModelPreview::onPhysicsOptimize(LLUICtrl* ctrl, void *data) { - if (sInstance && sInstance->mCurRequest.notNull()) - { - sInstance->mCurRequest->mContinue = 0; - } + //hide step 1 panel and show step 2 panel + info + sInstance->childSetVisible("physics step 1", false); + sInstance->childSetVisible("physics step 2", true); + sInstance->childSetVisible("physics info", true); +} + +//static +void LLFloaterModelPreview::onPhysicsBrowse(LLUICtrl* ctrl, void* userdata) +{ + sInstance->loadModel(LLModel::LOD_PHYSICS); } -void LLFloaterModelPreview::showDecompFloater() +//static +void LLFloaterModelPreview::onPhysicsUseLOD(LLUICtrl* ctrl, void* userdata) { - if (!mDecompFloater) + S32 which_mode = 3; + LLCtrlSelectionInterface* iface = sInstance->childGetSelectionInterface("physics_lod_combo"); + if (iface) { - LLSD key; - mDecompFloater = new LLPhysicsDecompFloater(key); + which_mode = iface->getFirstSelectedIndex(); + } - S32 left = 20; - S32 right = 320; - - S32 cur_y = 30; + sInstance->mModelPreview->setPhysicsFromLOD(which_mode); +} - { - //add status text - LLTextBox::Params p; - p.name("status"); - p.rect(LLRect(left, cur_y, right-80, cur_y-20)); - mDecompFloater->addChild(LLUICtrlFactory::create(p)); - } +//static +void LLFloaterModelPreview::onPhysicsDecomposeBack(LLUICtrl* ctrl, void* userdata) +{ + //hide step 2 panel and info and show step 1 panel + sInstance->childSetVisible("physics step 1", true); + sInstance->childSetVisible("physics step 2", false); + sInstance->childSetVisible("physics info", false); +} +//static +void LLFloaterModelPreview::onPhysicsSimplifyBack(LLUICtrl* ctrl, void* userdata) +{ + //hide step 3 panel and show step 2 panel + sInstance->childSetVisible("physics step 3", false); + sInstance->childSetVisible("physics step 2", true); +} + +//static +void LLFloaterModelPreview::onPhysicsStageCancel(LLUICtrl* ctrl, void*data) +{ + if (sInstance && sInstance->mCurRequest.notNull()) + { + sInstance->mCurRequest->mContinue = 0; + } +} - { //add cancel button - LLButton::Params p; - p.name("Cancel"); - p.label("Cancel"); - p.rect(LLRect(right-80, cur_y, right, cur_y-20)); - LLButton* button = LLUICtrlFactory::create(p); - button->setCommitCallback(onPhysicsStageCancel, NULL); - mDecompFloater->addChild(button); - } +void LLFloaterModelPreview::initDecompControls() +{ + LLSD key; - cur_y += 30; + childSetCommitCallback("cancel_btn", onPhysicsStageCancel, NULL); + childSetCommitCallback("physics_lod_combo", onPhysicsUseLOD, NULL); + childSetCommitCallback("physics_browse", onPhysicsBrowse, NULL); + childSetCommitCallback("physics_optimize", onPhysicsOptimize, NULL); + childSetCommitCallback("decompose_back", onPhysicsDecomposeBack, NULL); + childSetCommitCallback("simplify_back", onPhysicsSimplifyBack, NULL); + childSetCommitCallback("physics_layer", refresh, NULL); + static const LLCDStageData* stage = NULL; + static S32 stage_count = 0; - static const LLCDStageData* stage = NULL; - static S32 stage_count = 0; + if (!stage && LLConvexDecomposition::getInstance() != NULL) + { + stage_count = LLConvexDecomposition::getInstance()->getStages(&stage); + } - if (!stage && LLConvexDecomposition::getInstance() != NULL) - { - stage_count = LLConvexDecomposition::getInstance()->getStages(&stage); - } + static const LLCDParam* param = NULL; + static S32 param_count = 0; + if (!param && LLConvexDecomposition::getInstance() != NULL) + { + param_count = LLConvexDecomposition::getInstance()->getParameters(¶m); + } - static const LLCDParam* param = NULL; - static S32 param_count = 0; - if (!param && LLConvexDecomposition::getInstance() != NULL) + for (S32 j = stage_count-1; j >= 0; --j) + { + LLButton* button = getChild(stage[j].mName); + if (button) { - param_count = LLConvexDecomposition::getInstance()->getParameters(¶m); + button->setCommitCallback(onPhysicsStageExecute, (void*) &stage[j]); } - for (S32 j = stage_count-1; j >= 0; --j) - { - LLButton::Params p; - p.name(stage[j].mName); - p.label(stage[j].mName); - p.rect(LLRect(left, cur_y, right, cur_y-20)); - LLButton* button = LLUICtrlFactory::create(p); - button->setCommitCallback(onPhysicsStageExecute, (void*) &stage[j]); - mDecompFloater->addChild(button); - gMeshRepo.mDecompThread->mStageID[stage[j].mName] = j; - cur_y += 30; - // protected against stub by stage_count being 0 for stub above - LLConvexDecomposition::getInstance()->registerCallback(j, LLPhysicsDecomp::llcdCallback); + gMeshRepo.mDecompThread->mStageID[stage[j].mName] = j; + // protected against stub by stage_count being 0 for stub above + LLConvexDecomposition::getInstance()->registerCallback(j, LLPhysicsDecomp::llcdCallback); - llinfos << "Physics decomp stage " << stage[j].mName << " (" << j << ") parameters:" << llendl; - llinfos << "------------------------------------" << llendl; + //llinfos << "Physics decomp stage " << stage[j].mName << " (" << j << ") parameters:" << llendl; + //llinfos << "------------------------------------" << llendl; - for (S32 i = 0; i < param_count; ++i) + for (S32 i = 0; i < param_count; ++i) + { + if (param[i].mStage != j) { - if (param[i].mStage != j) - { - continue; - } + continue; + } - std::string name(param[i].mName ? param[i].mName : ""); - std::string description(param[i].mDescription ? param[i].mDescription : ""); + std::string name(param[i].mName ? param[i].mName : ""); + std::string description(param[i].mDescription ? param[i].mDescription : ""); - std::string type = "unknown"; + std::string type = "unknown"; - llinfos << name << " - " << description << llendl; + llinfos << name << " - " << description << llendl; - if (param[i].mType == LLCDParam::LLCD_FLOAT) + if (param[i].mType == LLCDParam::LLCD_FLOAT) + { + mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mFloat); + //llinfos << "Type: float, Default: " << param[i].mDefault.mFloat << llendl; + + LLSliderCtrl* slider = getChild(name); + if (slider) { - mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mFloat); - llinfos << "Type: float, Default: " << param[i].mDefault.mFloat << llendl; - - LLSliderCtrl::Params p; - p.name(name); - p.label(name); - p.rect(LLRect(left, cur_y, right, cur_y-20)); - p.min_value(param[i].mDetails.mRange.mLow.mFloat); - p.max_value(param[i].mDetails.mRange.mHigh.mFloat); - p.increment(param[i].mDetails.mRange.mDelta.mFloat); - p.tool_tip(description); - p.decimal_digits(3); - p.initial_value(param[i].mDefault.mFloat); - LLSliderCtrl* slider = LLUICtrlFactory::create(p); + slider->setMinValue(param[i].mDetails.mRange.mLow.mFloat); + slider->setMaxValue(param[i].mDetails.mRange.mHigh.mFloat); + slider->setIncrement(param[i].mDetails.mRange.mDelta.mFloat); + slider->setValue(param[i].mDefault.mFloat); slider->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); - mDecompFloater->addChild(slider); - cur_y += 30; } - else if (param[i].mType == LLCDParam::LLCD_INTEGER) + } + else if (param[i].mType == LLCDParam::LLCD_INTEGER) + { + mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue); + //llinfos << "Type: integer, Default: " << param[i].mDefault.mIntOrEnumValue << llendl; + + LLSliderCtrl* slider = getChild(name); + if (slider) { - mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue); - llinfos << "Type: integer, Default: " << param[i].mDefault.mIntOrEnumValue << llendl; - LLSliderCtrl::Params p; - p.name(name); - p.label(name); - p.rect(LLRect(left, cur_y, right, cur_y-20)); - p.min_value(param[i].mDetails.mRange.mLow.mIntOrEnumValue); - p.max_value(param[i].mDetails.mRange.mHigh.mIntOrEnumValue); - p.increment(param[i].mDetails.mRange.mDelta.mIntOrEnumValue); - p.tool_tip(description); - p.initial_value(param[i].mDefault.mIntOrEnumValue); - LLSliderCtrl* slider = LLUICtrlFactory::create(p); + slider->setMinValue(param[i].mDetails.mRange.mLow.mIntOrEnumValue); + slider->setMaxValue(param[i].mDetails.mRange.mHigh.mIntOrEnumValue); + slider->setIncrement(param[i].mDetails.mRange.mDelta.mIntOrEnumValue); + slider->setValue(param[i].mDefault.mIntOrEnumValue); slider->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); - mDecompFloater->addChild(slider); - cur_y += 30; } - else if (param[i].mType == LLCDParam::LLCD_BOOLEAN) + } + else if (param[i].mType == LLCDParam::LLCD_BOOLEAN) + { + mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mBool); + //llinfos << "Type: boolean, Default: " << (param[i].mDefault.mBool ? "True" : "False") << llendl; + + LLCheckBoxCtrl* check_box = getChild(name); + if (check_box) { - mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mBool); - llinfos << "Type: boolean, Default: " << (param[i].mDefault.mBool ? "True" : "False") << llendl; - - LLCheckBoxCtrl::Params p; - p.rect(LLRect(left, cur_y, right, cur_y-20)); - p.name(name); - p.label(name); - p.initial_value(param[i].mDefault.mBool); - p.tool_tip(description); - LLCheckBoxCtrl* check_box = LLUICtrlFactory::create(p); + check_box->setValue(param[i].mDefault.mBool); check_box->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); - mDecompFloater->addChild(check_box); - cur_y += 30; } - else if (param[i].mType == LLCDParam::LLCD_ENUM) - { - S32 cur_x = left; - mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue); - llinfos << "Type: enum, Default: " << param[i].mDefault.mIntOrEnumValue << llendl; - - { //add label - LLTextBox::Params p; - const LLFontGL* font = (LLFontGL*) p.font(); - - p.rect(LLRect(left, cur_y, left+font->getWidth(name), cur_y-20)); - p.name(name); - p.label(name); - p.initial_value(name); - LLTextBox* text_box = LLUICtrlFactory::create(p); - mDecompFloater->addChild(text_box); - cur_x += text_box->getRect().getWidth(); - } - - { //add combo_box - LLComboBox::Params p; - p.rect(LLRect(cur_x, cur_y, right-right/4, cur_y-20)); - p.name(name); - p.label(name); - p.tool_tip(description); - - llinfos << "Accepted values: " << llendl; - LLComboBox* combo_box = LLUICtrlFactory::create(p); - for (S32 k = 0; k < param[i].mDetails.mEnumValues.mNumEnums; ++k) - { - llinfos << param[i].mDetails.mEnumValues.mEnumsArray[k].mValue - << " - " << param[i].mDetails.mEnumValues.mEnumsArray[k].mName << llendl; + } + else if (param[i].mType == LLCDParam::LLCD_ENUM) + { + mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue); + //llinfos << "Type: enum, Default: " << param[i].mDefault.mIntOrEnumValue << llendl; - combo_box->add(param[i].mDetails.mEnumValues.mEnumsArray[k].mName, - LLSD::Integer(param[i].mDetails.mEnumValues.mEnumsArray[k].mValue)); - } - combo_box->setValue(param[i].mDefault.mIntOrEnumValue); - combo_box->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); - mDecompFloater->addChild(combo_box); - cur_y += 30; + { //plug into combo box + + //llinfos << "Accepted values: " << llendl; + LLComboBox* combo_box = getChild(name); + for (S32 k = 0; k < param[i].mDetails.mEnumValues.mNumEnums; ++k) + { + //llinfos << param[i].mDetails.mEnumValues.mEnumsArray[k].mValue + // << " - " << param[i].mDetails.mEnumValues.mEnumsArray[k].mName << llendl; + combo_box->add(param[i].mDetails.mEnumValues.mEnumsArray[k].mName, + LLSD::Integer(param[i].mDetails.mEnumValues.mEnumsArray[k].mValue)); } - - llinfos << "----" << llendl; + combo_box->setValue(param[i].mDefault.mIntOrEnumValue); + combo_box->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); } - llinfos << "-----------------------------" << llendl; - } - } - - cur_y += 30; - //explode slider - { - LLSliderCtrl::Params p; - p.initial_value(0); - p.min_value(0); - p.max_value(1); - p.decimal_digits(2); - p.increment(0.05f); - p.label("Explode"); - p.name("explode"); - p.rect(LLRect(left, cur_y, right, cur_y-20)); - LLSliderCtrl* slider = LLUICtrlFactory::create(p); - - mDecompFloater->addChild(slider); - cur_y += 30; - } - - //mesh render checkbox - { - LLCheckBoxCtrl::Params p; - p.label("Mesh: "); - p.name("render_mesh"); - p.rect(LLRect(left, cur_y, right/4, cur_y-20)); - LLCheckBoxCtrl* check = LLUICtrlFactory::create(p); - check->setValue(true); - mDecompFloater->addChild(check); - } - //hull render checkbox - { - LLCheckBoxCtrl::Params p; - p.label("Hull: "); - p.name("render_hull"); - p.rect(LLRect(right/4, cur_y, right/2, cur_y-20)); - LLCheckBoxCtrl* check = LLUICtrlFactory::create(p); - check->setValue(true); - mDecompFloater->addChild(check); - } - - { //submesh combo box label - LLTextBox::Params p; - p.label("Model"); - p.name("model label"); - p.rect(LLRect(right/2, cur_y, right-right/3, cur_y-20)); - LLTextBox* text_box = LLUICtrlFactory::create(p); - text_box->setValue("Model"); - mDecompFloater->addChild(text_box); - } - - { - //add submesh combo box - LLComboBox::Params p; - p.rect(LLRect(right-right/2+p.font()->getWidth("Model"), cur_y, right, cur_y-20)); - p.name("model"); - LLComboBox* combo_box = LLUICtrlFactory::create(p); - for (S32 i = 0; i < mModelPreview->mBaseModel.size(); ++i) - { - LLModel* mdl = mModelPreview->mBaseModel[i]; - combo_box->add(mdl->mLabel, i); + //llinfos << "----" << llendl; } - combo_box->setValue(0); - mDecompFloater->addChild(combo_box); - cur_y += 30; + //llinfos << "-----------------------------" << llendl; } - - mDecompFloater->childSetCommitCallback("model", LLFloaterModelPreview::refresh, LLFloaterModelPreview::sInstance); - mDecompFloater->childSetCommitCallback("render_mesh", LLFloaterModelPreview::refresh, LLFloaterModelPreview::sInstance); - mDecompFloater->childSetCommitCallback("render_hull", LLFloaterModelPreview::refresh, LLFloaterModelPreview::sInstance); - - mDecompFloater->setRect(LLRect(10, cur_y+20, right+20, 10)); } - mDecompFloater->childSetCommitCallback("explode", LLFloaterModelPreview::onExplodeCommit, this); - - mDecompFloater->openFloater(); + childSetCommitCallback("physics_layer", LLFloaterModelPreview::refresh, LLFloaterModelPreview::sInstance); + childSetCommitCallback("physics_explode", LLFloaterModelPreview::onExplodeCommit, this); + childSetCommitCallback("show physics", LLFloaterModelPreview::refresh, this); } //----------------------------------------------------------------------------- @@ -2080,18 +1869,15 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloaterModelPreview* fmp mCameraPitch = 0.f; mCameraZoom = 1.f; mTextureName = 0; - mPreviewLOD = 3; + mPreviewLOD = 0; mModelLoader = NULL; mDirty = false; for (U32 i = 0; i < LLModel::NUM_LODS; i++) { - mLODMode[i] = 1; mLimit[i] = 0; } - mLODMode[0] = 0; - mFMP = fmp; glodInit(); @@ -2118,10 +1904,9 @@ U32 LLModelPreview::calcResourceCost() U32 num_points = 0; U32 num_hulls = 0; - F32 debug_scale = mFMP->childGetValue("debug scale").asReal(); + F32 debug_scale = mFMP->childGetValue("import_scale").asReal(); F32 streaming_cost = 0.f; - for (U32 i = 0; i < mUploadData.size(); ++i) { LLModelInstance& instance = mUploadData[i]; @@ -2173,13 +1958,13 @@ U32 LLModelPreview::calcResourceCost() } } - mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[HULLS]", llformat("%d",num_hulls)); - mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[POINTS]", llformat("%d",num_points)); + //mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[HULLS]", llformat("%d",num_hulls)); + //mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[POINTS]", llformat("%d",num_points)); mFMP->childSetTextArg("streaming cost", "[COST]", llformat("%.3f", streaming_cost)); - F32 scale = mFMP->childGetValue("debug scale").asReal()*2.f; - mFMP->childSetTextArg("dimensions", "[X]", llformat("%.3f", mPreviewScale[0]*scale)); - mFMP->childSetTextArg("dimensions", "[Y]", llformat("%.3f", mPreviewScale[1]*scale)); - mFMP->childSetTextArg("dimensions", "[Z]", llformat("%.3f", mPreviewScale[2]*scale)); + F32 scale = mFMP->childGetValue("import_scale").asReal()*2.f; + mFMP->childSetTextArg("import_dimensions", "[X]", llformat("%.3f", mPreviewScale[0]*scale)); + mFMP->childSetTextArg("import_dimensions", "[Y]", llformat("%.3f", mPreviewScale[1]*scale)); + mFMP->childSetTextArg("import_dimensions", "[Z]", llformat("%.3f", mPreviewScale[2]*scale)); updateStatusMessages(); @@ -2193,11 +1978,11 @@ void LLModelPreview::rebuildUploadData() //fill uploaddata instance vectors from scene data - LLSpinCtrl* scale_spinner = mFMP->getChild("debug scale"); + LLSpinCtrl* scale_spinner = mFMP->getChild("import_scale"); if (!scale_spinner) { - llerrs << "floater_model_preview.xml MUST contain debug scale spinner." << llendl; + llerrs << "floater_model_preview.xml MUST contain import_scale spinner." << llendl; } F32 scale = scale_spinner->getValue().asReal(); @@ -2266,6 +2051,21 @@ void LLModelPreview::rebuildUploadData() { scale_spinner->setValue(max_import_scale); } + + //refill "layer" combo in physics panel + LLComboBox* combo_box = mFMP->getChild("physics_layer"); + if (combo_box) + { + S32 current = combo_box->getCurrentIndex(); + combo_box->removeall(); + + for (S32 i = 0; i < mBaseModel.size(); ++i) + { + LLModel* mdl = mBaseModel[i]; + combo_box->add(mdl->mLabel, i); + } + combo_box->setCurrentByIndex(current); + } } @@ -2304,6 +2104,8 @@ void LLModelPreview::loadModel(std::string filename, S32 lod) return; } + mLODFile[lod] = filename; + if (lod == 3 && !mGroup.empty()) { for (std::map, U32>::iterator iter = mGroup.begin(); iter != mGroup.end(); ++iter) @@ -2327,16 +2129,35 @@ void LLModelPreview::loadModel(std::string filename, S32 lod) mModelLoader->start(); mFMP->childSetTextArg("status", "[STATUS]", mFMP->getString("status_reading_file")); + + setPreviewLOD(lod); - if (mFMP->childGetValue("description_form").asString().empty()) + if (lod == mPreviewLOD) + { + mFMP->childSetText("lod_file", mLODFile[mPreviewLOD]); + } + else if (lod == LLModel::LOD_PHYSICS) { - std::string name = gDirUtilp->getBaseFileName(filename, true); - mFMP->childSetValue("description_form", name); + mFMP->childSetText("physics_file", mLODFile[lod]); } mFMP->openFloater(); } +void LLModelPreview::setPhysicsFromLOD(S32 lod) +{ + if (lod >= 0 && lod <= 3) + { + mModel[LLModel::LOD_PHYSICS] = mModel[lod]; + mScene[LLModel::LOD_PHYSICS] = mScene[lod]; + mLODFile[LLModel::LOD_PHYSICS].clear(); + mFMP->childSetText("physics_file", mLODFile[LLModel::LOD_PHYSICS]); + mVertexBuffer[LLModel::LOD_PHYSICS].clear(); + rebuildUploadData(); + refresh(); + } +} + void LLModelPreview::clearIncompatible(S32 lod) { for (U32 i = 0; i <= LLModel::LOD_HIGH; i++) @@ -2405,7 +2226,7 @@ void LLModelPreview::resetPreviewTarget() setPreviewTarget(mPreviewScale.magVec()*2.f); } -void LLModelPreview::smoothNormals() +void LLModelPreview::generateNormals() { S32 which_lod = mPreviewLOD; @@ -2416,7 +2237,7 @@ void LLModelPreview::smoothNormals() return; } - F32 angle_cutoff = mFMP->childGetValue("edge threshold").asReal(); + F32 angle_cutoff = mFMP->childGetValue("crease_angle").asReal(); angle_cutoff *= DEG_TO_RAD; @@ -2424,7 +2245,7 @@ void LLModelPreview::smoothNormals() { for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) { - (*iter)->smoothNormals(angle_cutoff); + (*iter)->generateNormals(angle_cutoff); } mVertexBuffer[5].clear(); @@ -2432,7 +2253,7 @@ void LLModelPreview::smoothNormals() for (LLModelLoader::model_list::iterator iter = mModel[which_lod].begin(); iter != mModel[which_lod].end(); ++iter) { - (*iter)->smoothNormals(angle_cutoff); + (*iter)->generateNormals(angle_cutoff); } mVertexBuffer[which_lod].clear(); @@ -2621,7 +2442,7 @@ void LLModelPreview::consolidate() refresh(); } -void LLModelPreview::scrubMaterials() +void LLModelPreview::clearMaterials() { for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) { //for each transform in current scene @@ -2644,7 +2465,6 @@ void LLModelPreview::scrubMaterials() } } - mVertexBuffer[mPreviewLOD].clear(); if (mPreviewLOD == LLModel::LOD_HIGH) @@ -2808,25 +2628,9 @@ void LLModelPreview::genLODs(S32 which_lod) start = end = which_lod; } + LLSpinCtrl* lim = mFMP->getChild("lod_triangle_limit", TRUE); + lim->setMaxValue(base_triangle_count); - std::string combo_name[] = - { - "lowest detail combo", - "low detail combo", - "medium detail combo", - "high detail combo", - "physics detail combo" - }; - - std::string limit_name[] = - { - "lowest limit", - "low limit", - "medium limit", - "high limit", - "physics limit" - }; - for (S32 lod = start; lod >= end; --lod) { if (which_lod == -1) @@ -2841,13 +2645,6 @@ void LLModelPreview::genLODs(S32 which_lod) triangle_count = limit; } - LLComboBox* combo_box = mFMP->findChild(combo_name[lod]); - combo_box->setCurrentByIndex(2); - - LLSpinCtrl* lim = mFMP->getChild(limit_name[lod], TRUE); - lim->setMaxValue(base_triangle_count); - lim->setVisible(true); - mModel[lod].clear(); mModel[lod].resize(mBaseModel.size()); mVertexBuffer[lod].clear(); @@ -3037,32 +2834,44 @@ void LLModelPreview::updateStatusMessages() } } + mFMP->childSetTextArg("submeshes_info", "[SUBMESHES]", llformat("%d", total_submeshes[LLModel::LOD_HIGH])); + + std::string mesh_status_good = mFMP->getString("mesh_status_good"); + std::string mesh_status_bad = mFMP->getString("mesh_status_bad"); + std::string mesh_status_na = mFMP->getString("mesh_status_na"); + std::string mesh_status_none = mFMP->getString("mesh_status_none"); - std::string upload_message; - - mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[TRIANGLES]", llformat("%d", total_tris[LLModel::LOD_PHYSICS])); + bool upload_ok = true; for (S32 lod = 0; lod <= LLModel::LOD_HIGH; ++lod) { - mFMP->childSetTextArg(info_name[lod], "[TRIANGLES]", llformat("%d", total_tris[lod])); - mFMP->childSetTextArg(info_name[lod], "[VERTICES]", llformat("%d", total_verts[lod])); - mFMP->childSetTextArg(info_name[lod], "[SUBMESHES]", llformat("%d", total_submeshes[lod])); + if (total_tris[lod] > 0) + { + mFMP->childSetText(lod_triangles_name[lod], llformat("%d", total_tris[lod])); + mFMP->childSetText(lod_vertices_name[lod], llformat("%d", total_verts[lod])); + } + else + { + mFMP->childSetText(lod_triangles_name[lod], mesh_status_na); + mFMP->childSetText(lod_vertices_name[lod], mesh_status_na); + } - std::string message = "good"; + + std::string message = mesh_status_good; const U32 lod_high = LLModel::LOD_HIGH; if (lod != lod_high) { if (total_submeshes[lod] && total_submeshes[lod] != total_submeshes[lod_high]) - { - message = "mesh_mismatch"; - upload_message = "bad_lod"; + { //number of submeshes is different + message = mesh_status_bad; + upload_ok = false; } else if (!tris[lod].empty() && tris[lod].size() != tris[lod_high].size()) - { - message = "model_mismatch"; - upload_message = "bad_lod"; + { //number of meshes is different + message = mesh_status_bad; + upload_ok = false; } else if (!verts[lod].empty()) { @@ -3071,27 +2880,119 @@ void LLModelPreview::updateStatusMessages() S32 max_verts = verts[lod+1][i]; if (verts[lod][i] > max_verts) - { - message = "too_heavy"; - upload_message = "bad_lod"; + { //too many vertices in this lod + message = mesh_status_bad; + upload_ok = false; } } } + else + { //no mesh + message = mesh_status_none; + } } - mFMP->childSetTextArg(info_name[lod], "[MESSAGE]", mFMP->getString(message)); + mFMP->childSetText(lod_status_name[lod], message); } - if (upload_message.empty()) + if (upload_ok) { - mFMP->childSetTextArg("upload_message", "[MESSAGE]", std::string("")); mFMP->childEnable("ok_btn"); } else { - mFMP->childSetTextArg("upload_message", "[MESSAGE]", mFMP->getString(upload_message)); mFMP->childDisable("ok_btn"); } + + //add up physics triangles etc + S32 start = 0; + S32 end = mModel[LLModel::LOD_PHYSICS].size(); + + S32 idx = mFMP->childGetValue("physics_layer").asInteger(); + + if (idx >= 0 && idx < mModel[LLModel::LOD_PHYSICS].size()) + { + start = idx; + end = idx+1; + } + + S32 phys_tris = 0; + S32 phys_hulls = 0; + S32 phys_points = 0; + + for (S32 i = start; i < end; ++i) + { //add up hulls and points and triangles for selected mesh(es) + LLModel* model = mModel[LLModel::LOD_PHYSICS][i]; + S32 cur_submeshes = model->getNumVolumeFaces(); + + LLModel::convex_hull_decomposition& decomp = model->mConvexHullDecomp; + + if (!decomp.empty()) + { + phys_hulls += decomp.size(); + for (U32 i = 0; i < decomp.size(); ++i) + { + phys_points += decomp[i].size(); + } + } + else + { //choose physics shape OR decomposition, can't use both + for (S32 j = 0; j < cur_submeshes; ++j) + { //for each submesh (face), add triangles and vertices to current total + const LLVolumeFace& face = model->getVolumeFace(j); + phys_tris += face.mNumIndices/3; + } + } + } + + if (phys_tris > 0) + { + mFMP->childSetTextArg("physics_triangles", "[TRIANGLES]", llformat("%d", phys_tris)); + } + else + { + mFMP->childSetTextArg("physics_triangles", "[TRIANGLES]", mesh_status_na); + } + + if (phys_hulls > 0) + { + mFMP->childSetTextArg("physics_hulls", "[HULLS]", llformat("%d", phys_hulls)); + mFMP->childSetTextArg("physics_points", "[POINTS]", llformat("%d", phys_points)); + } + else + { + mFMP->childSetTextArg("physics_hulls", "[HULLS]", mesh_status_na); + mFMP->childSetTextArg("physics_points", "[POINTS]", mesh_status_na); + } + + //enable/disable controls based on radio groups + if (mFMP->childGetValue("lod_from_file").asBoolean()) + { + mFMP->childDisable("lod_triangle_limit"); + mFMP->childDisable("lod_generate"); + mFMP->childEnable("lod_file"); + mFMP->childEnable("lod_browse"); + } + else + { + mFMP->childEnable("lod_triangle_limit"); + mFMP->childEnable("lod_generate"); + mFMP->childDisable("lod_file"); + mFMP->childDisable("lod_browse"); + } + + if (mFMP->childGetValue("physics_load_from_file").asBoolean()) + { + mFMP->childDisable("physics_lod_combo"); + mFMP->childEnable("physics_file"); + mFMP->childEnable("physics_browse"); + } + else + { + mFMP->childEnable("physics_lod_combo"); + mFMP->childDisable("physics_file"); + mFMP->childDisable("physics_browse"); + } } void LLModelPreview::setPreviewTarget(F32 distance) @@ -3243,6 +3144,7 @@ void LLModelPreview::update() { mDirty = false; mResourceCost = calcResourceCost(); + refresh(); } } @@ -3263,18 +3165,27 @@ BOOL LLModelPreview::render() LLGLDepthTest depth(GL_TRUE); LLGLDisable fog(GL_FOG); - glMatrixMode(GL_PROJECTION); - gGL.pushMatrix(); - glLoadIdentity(); - glOrtho(0.0f, width, 0.0f, height, -1.0f, 1.0f); + { + //clear background to blue + glMatrixMode(GL_PROJECTION); + gGL.pushMatrix(); + glLoadIdentity(); + glOrtho(0.0f, width, 0.0f, height, -1.0f, 1.0f); - glMatrixMode(GL_MODELVIEW); - gGL.pushMatrix(); - glLoadIdentity(); - - gGL.color4f(0.15f, 0.2f, 0.3f, 1.f); + glMatrixMode(GL_MODELVIEW); + gGL.pushMatrix(); + glLoadIdentity(); + + gGL.color4f(0.15f, 0.2f, 0.3f, 1.f); + + gl_rect_2d_simple( width, height ); - gl_rect_2d_simple( width, height ); + glMatrixMode(GL_PROJECTION); + gGL.popMatrix(); + + glMatrixMode(GL_MODELVIEW); + gGL.popMatrix(); + } bool avatar_preview = false; bool upload_skin = mFMP->childGetValue("upload_skin").asBoolean(); @@ -3328,24 +3239,20 @@ BOOL LLModelPreview::render() mFMP->childSetEnabled("consolidate", !avatar_preview); - F32 explode = mFMP->mDecompFloater ? mFMP->mDecompFloater->childGetValue("explode").asReal() : 0.f; - - glMatrixMode(GL_PROJECTION); - gGL.popMatrix(); - - glMatrixMode(GL_MODELVIEW); - gGL.popMatrix(); + F32 explode = mFMP->childGetValue("physics_explode").asReal(); glClear(GL_DEPTH_BUFFER_BIT); - LLViewerCamera::getInstance()->setAspect((F32) width / height ); + F32 aspect = (F32) mFMP->mPreviewRect.getWidth()/mFMP->mPreviewRect.getHeight(); + + LLViewerCamera::getInstance()->setAspect(aspect); LLViewerCamera::getInstance()->setView(LLViewerCamera::getInstance()->getDefaultFOV() / mCameraZoom); - LLVector3 target_pos = mPreviewTarget; LLVector3 offset = mCameraOffset; + LLVector3 target_pos = mPreviewTarget+offset; - F32 z_near = llmax(mCameraDistance-mPreviewScale.magVec(), 0.001f); - F32 z_far = mCameraDistance+mPreviewScale.magVec(); + F32 z_near = 0.001f; + F32 z_far = mCameraDistance+mPreviewScale.magVec()+mCameraOffset.magVec(); if (avatar_preview) { @@ -3386,21 +3293,10 @@ BOOL LLModelPreview::render() //genBuffers(3); //genLODs(); } - - bool physics = (mPreviewLOD == LLModel::LOD_PHYSICS); - - S32 physics_idx = -1; - - bool render_mesh = true; - bool render_hull = false; - - if (physics && mFMP->mDecompFloater) - { - physics_idx = mFMP->mDecompFloater->childGetValue("model").asInteger(); - render_mesh = mFMP->mDecompFloater->childGetValue("render_mesh").asBoolean(); - render_hull = mFMP->mDecompFloater->childGetValue("render_hull").asBoolean(); - } - + + bool physics = mFMP->childGetValue("show physics").asBoolean(); + S32 physics_idx = mFMP->childGetValue("physics_layer").asInteger(); + if (!mModel[mPreviewLOD].empty()) { if (mVertexBuffer[mPreviewLOD].empty()) @@ -3410,68 +3306,175 @@ BOOL LLModelPreview::render() if (!avatar_preview) { - //for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) { LLModelInstance& instance = *iter; + LLModel* model = instance.mLOD[mPreviewLOD]; + + if (!model) + { + continue; + } + gGL.pushMatrix(); LLMatrix4 mat = instance.mTransform; - glMultMatrixf((GLfloat*) mat.mMatrix); + glMultMatrixf((GLfloat*) mat.mMatrix); + + for (U32 i = 0; i < mVertexBuffer[mPreviewLOD][model].size(); ++i) + { + LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; + + buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); + + glColor4fv(instance.mMaterial[i].mDiffuseColor.mV); + if (i < instance.mMaterial.size() && instance.mMaterial[i].mDiffuseMap.notNull()) + { + gGL.getTexUnit(0)->bind(instance.mMaterial[i].mDiffuseMap, true); + if (instance.mMaterial[i].mDiffuseMap->getDiscardLevel() > -1) + { + mTextureSet.insert(instance.mMaterial[i].mDiffuseMap); + } + } + + buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + glColor3f(0.4f, 0.4f, 0.4f); + + if (mFMP->childGetValue("show edges").asBoolean()) + { + glLineWidth(3.f); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glLineWidth(1.f); + } + } + gGL.popMatrix(); + } + + if (physics) + { + glClear(GL_DEPTH_BUFFER_BIT); + LLGLEnable blend(GL_BLEND); + gGL.blendFunc(LLRender::BF_ONE, LLRender::BF_ZERO); + + LLModel* physics_model = NULL; - //for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) + if (physics_idx >= 0 && physics_idx < mModel[LLModel::LOD_PHYSICS].size() ) { - //LLModelInstance& instance = *model_iter; - LLModel* model = instance.mLOD[mPreviewLOD]; + physics_model = mModel[LLModel::LOD_PHYSICS][physics_idx]; + } + + for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) + { + LLModelInstance& instance = *iter; + + LLModel* model = instance.mLOD[LLModel::LOD_PHYSICS]; if (!model) { continue; } - //if (instance.mTransform != mat) - //{ - // llerrs << "WTF?" << llendl; - //} + gGL.pushMatrix(); + LLMatrix4 mat = instance.mTransform; - if (render_mesh) + glMultMatrixf((GLfloat*) mat.mMatrix); + + + bool render_mesh = true; + + LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread; + if (decomp) { - for (U32 i = 0; i < mVertexBuffer[mPreviewLOD][model].size(); ++i) + LLMutexLock(decomp->mMutex); + + std::map, std::vector > >::iterator iter = + mPhysicsMesh.find(model); + if (iter != mPhysicsMesh.end()) { - LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; - - buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); - if (physics) + render_mesh = false; + for (U32 i = 0; i < iter->second.size(); ++i) { - if (physics_idx > -1 && model == mModel[mPreviewLOD][physics_idx]) + if (explode > 0.f) { - glColor4f(1,0,0,1); + gGL.pushMatrix(); + + LLVector3 offset = model->mHullCenter[i]-model->mCenterOfHullCenters; + offset *= explode; + + gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]); } - else + + static std::vector hull_colors; + + if (i+1 >= hull_colors.size()) { - glColor4f(0.75f, 0.75f, 0.75f, 1.f); + hull_colors.push_back(LLColor4U(rand()%128+127, rand()%128+127, rand()%128+127, 255)); } - } - else - { - glColor4fv(instance.mMaterial[i].mDiffuseColor.mV); - if (i < instance.mMaterial.size() && instance.mMaterial[i].mDiffuseMap.notNull()) + + LLVertexBuffer* buff = iter->second[i]; + if (buff) { - gGL.getTexUnit(0)->bind(instance.mMaterial[i].mDiffuseMap, true); - if (instance.mMaterial[i].mDiffuseMap->getDiscardLevel() > -1) + buff->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL); + + glColor4ubv(hull_colors[i].mV); + buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts()); + + if (mFMP->childGetValue("show edges").asBoolean()) { - mTextureSet.insert(instance.mMaterial[i].mDiffuseMap); - } + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + glLineWidth(3.f); + glColor4ub(hull_colors[i].mV[0]/2, hull_colors[i].mV[1]/2, hull_colors[i].mV[2]/2, 255); + buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts()); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glLineWidth(1.f); + } + } + + if (explode > 0.f) + { + gGL.popMatrix(); } } + } + } + + if (render_mesh) + { + if (mVertexBuffer[LLModel::LOD_PHYSICS].empty()) + { + genBuffers(LLModel::LOD_PHYSICS, false); + } + for (U32 i = 0; i < mVertexBuffer[LLModel::LOD_PHYSICS][model].size(); ++i) + { + LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][i]; + buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); + + glColor4fv(instance.mMaterial[i].mDiffuseColor.mV); + if (i < instance.mMaterial.size() && instance.mMaterial[i].mDiffuseMap.notNull()) + { + gGL.getTexUnit(0)->bind(instance.mMaterial[i].mDiffuseMap, true); + if (instance.mMaterial[i].mDiffuseMap->getDiscardLevel() > -1) + { + mTextureSet.insert(instance.mMaterial[i].mDiffuseMap); + } + } + buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); glColor3f(0.4f, 0.4f, 0.4f); - if (mFMP->childGetValue("show edges").asBoolean()) + if (mFMP->childGetValue("show edges").asBoolean() || model == physics_model) { + if (model == physics_model) + { + glColor3f(1.f, 1.f, 0.f); + } + glLineWidth(3.f); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); @@ -3481,74 +3484,10 @@ BOOL LLModelPreview::render() } } - if (render_hull) - { - LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread; - if (decomp) - { - LLMutexLock(decomp->mMutex); - - std::map, std::vector > >::iterator iter = - mPhysicsMesh.find(model); - if (iter != mPhysicsMesh.end()) - { - for (U32 i = 0; i < iter->second.size(); ++i) - { - if (explode > 0.f) - { - gGL.pushMatrix(); - - LLVector3 offset = model->mHullCenter[i]-model->mCenterOfHullCenters; - offset *= explode; - - gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]); - } - - static std::vector hull_colors; - - if (i+1 >= hull_colors.size()) - { - hull_colors.push_back(LLColor4U(rand()%128+127, rand()%128+127, rand()%128+127, 255)); - } - - LLVertexBuffer* buff = iter->second[i]; - if (buff) - { - buff->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL); - - glColor4ubv(hull_colors[i].mV); - buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts()); - - if (mFMP->childGetValue("show edges").asBoolean()) - { - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - glLineWidth(3.f); - glColor4ub(hull_colors[i].mV[0]/2, hull_colors[i].mV[1]/2, hull_colors[i].mV[2]/2, 255); - buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts()); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glLineWidth(1.f); - } - } - - if (explode > 0.f) - { - gGL.popMatrix(); - } - } - } - } - - //mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[HULLS]", llformat("%d",decomp->mHulls.size())); - //mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[POINTS]", llformat("%d",decomp->mTotalPoints)); - } + gGL.popMatrix(); } - gGL.popMatrix(); - } - - if (physics) - { - mPreviewLOD = LLModel::LOD_PHYSICS; + gGL.setSceneBlendType(LLRender::BT_ALPHA); } } else @@ -3702,36 +3641,38 @@ void LLModelPreview::pan(F32 right, F32 up) void LLModelPreview::setPreviewLOD(S32 lod) { - mPreviewLOD = llclamp(lod, 0, 4); - refresh(); -} + lod = llclamp(lod, 0, (S32) LLModel::LOD_HIGH); -//static -void LLFloaterModelPreview::onBrowseHighLOD(void* data) -{ - LLFloaterModelPreview* mp = (LLFloaterModelPreview*) data; - mp->loadModel(3); -} + if (lod != mPreviewLOD) + { + mPreviewLOD = lod; + + LLComboBox* combo_box = mFMP->getChild("preview_lod_combo"); + combo_box->setCurrentByIndex(mPreviewLOD); + mFMP->childSetTextArg("lod_table_footer", "[DETAIL]", mFMP->getString(lod_name[mPreviewLOD])); + mFMP->childSetText("lod_file", mLODFile[mPreviewLOD]); -//static -void LLFloaterModelPreview::onBrowseMediumLOD(void* data) -{ - LLFloaterModelPreview* mp = (LLFloaterModelPreview*) data; - mp->loadModel(2); -} + LLColor4 highlight_color = LLUIColorTable::instance().getColor("MeshImportTableHighlightColor"); + LLColor4 normal_color = LLUIColorTable::instance().getColor("MeshImportTableNormalColor"); -//static -void LLFloaterModelPreview::onBrowseLowLOD(void* data) -{ - LLFloaterModelPreview* mp = (LLFloaterModelPreview*) data; - mp->loadModel(1); + for (S32 i = 0; i <= LLModel::LOD_HIGH; ++i) + { + const LLColor4& color = (i == lod) ? highlight_color : normal_color; + + mFMP->childSetColor(lod_status_name[i], color); + mFMP->childSetColor(lod_label_name[i], color); + mFMP->childSetColor(lod_triangles_name[i], color); + mFMP->childSetColor(lod_vertices_name[i], color); + } + } + refresh(); } //static -void LLFloaterModelPreview::onBrowseLowestLOD(void* data) +void LLFloaterModelPreview::onBrowseLOD(void* data) { LLFloaterModelPreview* mp = (LLFloaterModelPreview*) data; - mp->loadModel(0); + mp->loadModel(mp->mModelPreview->mPreviewLOD); } //static @@ -3739,11 +3680,6 @@ void LLFloaterModelPreview::onUpload(void* user_data) { LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; - if (mp->mDecompFloater) - { - mp->mDecompFloater->closeFloater(); - } - mp->mModelPreview->rebuildUploadData(); gMeshRepo.uploadModel(mp->mModelPreview->mUploadData, mp->mModelPreview->mPreviewScale, @@ -3760,24 +3696,17 @@ void LLFloaterModelPreview::onConsolidate(void* user_data) } //static -void LLFloaterModelPreview::onScrubMaterials(void* user_data) -{ - LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; - mp->mModelPreview->scrubMaterials(); -} - -//static -void LLFloaterModelPreview::onDecompose(void* user_data) +void LLFloaterModelPreview::onClearMaterials(void* user_data) { LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; - mp->showDecompFloater(); + mp->mModelPreview->clearMaterials(); } //static void LLFloaterModelPreview::refresh(LLUICtrl* ctrl, void* user_data) { LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; - mp->mModelPreview->refresh(); + sInstance->mModelPreview->mDirty = true; } void LLFloaterModelPreview::updateResourceCost() -- cgit v1.2.3 From 585ddf18fc399478e399595daf65e1527213909b Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Fri, 19 Nov 2010 18:49:35 -0600 Subject: SH-525 fix for crash when specifying LOD slots out of order. --- indra/newview/llfloatermodelpreview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index ddc8774ea9..49177e6308 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -2994,7 +2994,7 @@ void LLModelPreview::updateStatusMessages() { for (U32 i = 0; i < verts[lod].size(); ++i) { - S32 max_verts = verts[lod+1][i]; + S32 max_verts = i < verts[lod+1].size() ? verts[lod+1][i] : 0; if (verts[lod][i] > max_verts) { //too many vertices in this lod -- cgit v1.2.3 From 589b571013c292bf99d5bf873f9f30a8a4cff36b Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Fri, 19 Nov 2010 18:59:16 -0600 Subject: Don't reset preview target unless high LOD is being swapped out. --- indra/newview/llfloatermodelpreview.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 49177e6308..22fd3a1dbc 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -2330,7 +2330,10 @@ void LLModelPreview::loadModelCallback(S32 lod) mDirty = true; - resetPreviewTarget(); + if (lod == LLModel::LOD_HIGH) + { + resetPreviewTarget(); + } mFMP->mLoading = FALSE; refresh(); -- cgit v1.2.3 From 8f50486dd97eb3143d2d31531eda440e71df5f51 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Fri, 19 Nov 2010 20:39:17 -0600 Subject: remove unused variable make gcc happy --- indra/newview/llfloatermodelpreview.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 22fd3a1dbc..92c70c9eaf 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -3825,7 +3825,6 @@ void LLFloaterModelPreview::onClearMaterials(void* user_data) //static void LLFloaterModelPreview::refresh(LLUICtrl* ctrl, void* user_data) { - LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; sInstance->mModelPreview->mDirty = true; } -- cgit v1.2.3 From 43382f2849d5b2e8a5826a7a7d4f41254ab41735 Mon Sep 17 00:00:00 2001 From: prep linden Date: Mon, 22 Nov 2010 13:16:39 -0500 Subject: merge of earlier code that got stomped from a previous merge --- indra/newview/llfloatermodelpreview.cpp | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 92c70c9eaf..85cc205dab 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1173,21 +1173,7 @@ void LLModelLoader::run() } - /*{ - LLMatrix4 rotation; - if (up == UPAXISTYPE_X_UP) - { - rotation.initRotation(0.0f, 90.0f * DEG_TO_RAD, 0.0f); - } - else if (up == UPAXISTYPE_Z_UP) - { - rotation.initRotation(90.0f * DEG_TO_RAD, 90.0f * DEG_TO_RAD, 0.0f); - } - - rotation *= model->mBindShapeMatrix; - model->mBindShapeMatrix = rotation; - }*/ - + //The joint transfom map that we'll populate below std::map jointTransforms; jointTransforms.clear(); @@ -1195,6 +1181,7 @@ void LLModelLoader::run() //Some collada setup for accessing the skeleton daeElement* pElement = 0; dae.getDatabase()->getElement( &pElement, 0, 0, "skeleton" ); + //Try to get at the skeletal instance controller domInstance_controller::domSkeleton* pSkeleton = daeSafeCast( pElement ); bool missingSkeletonOrScene = false; @@ -1281,8 +1268,6 @@ void LLModelLoader::run() //Store the joint transform w/respect to it's name. jointTransforms[(*jointIt).second.c_str()] = workingTransform; } - - } //If anything failed in regards to extracting the skeleton, joints or translation id, @@ -1326,8 +1311,7 @@ void LLModelLoader::run() } } } //missingSkeletonOrScene - - + domSkin::domJoints* joints = skin->getJoints(); domInputLocal_Array& joint_input = joints->getInput_array(); -- cgit v1.2.3 From e3df3baff7aebd247737fd3dbcb382f3b12df10b Mon Sep 17 00:00:00 2001 From: prep linden Date: Tue, 23 Nov 2010 09:52:31 -0500 Subject: Fix for SH-479 --- indra/newview/llfloatermodelpreview.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 85cc205dab..68c7e3c1a2 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1302,12 +1302,12 @@ void LLModelLoader::run() llwarns<<"Tried to apply joint position from .dae, but it did not exist in the avatar rig." << llendl; } //Reposition the avatars pelvis (avPos+offset) - if ( lookingForJoint == "mPelvis" ) - { - const LLVector3& pos = gAgentAvatarp->getCharacterPosition(); - gAgentAvatarp->setPelvisOffset( true, jointTransform.getTranslation() ); - gAgentAvatarp->setPosition( pos + jointTransform.getTranslation() ); - } + //if ( lookingForJoint == "mPelvis" ) + //{ + // const LLVector3& pos = gAgentAvatarp->getCharacterPosition(); + // gAgentAvatarp->setPelvisOffset( true, jointTransform.getTranslation() ); + // gAgentAvatarp->setPosition( pos + jointTransform.getTranslation() ); + //} } } } //missingSkeletonOrScene -- cgit v1.2.3 From bd8d888ceab101db8e350b4b317823a316470ade Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 30 Nov 2010 00:25:44 -0600 Subject: Make importer use 3-light setup all the time --- indra/newview/llfloatermodelpreview.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 68c7e3c1a2..b82e9dd62f 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -3369,6 +3369,8 @@ BOOL LLModelPreview::render() refresh(); } + gPipeline.enableLightsPreview(); + LLQuaternion camera_rot = LLQuaternion(mCameraPitch, LLVector3::y_axis) * LLQuaternion(mCameraYaw, LLVector3::z_axis); @@ -3383,8 +3385,6 @@ BOOL LLModelPreview::render() stop_glerror(); - gPipeline.enableLightsAvatar(); - gGL.pushMatrix(); const F32 BRIGHTNESS = 0.9f; gGL.color3f(BRIGHTNESS, BRIGHTNESS, BRIGHTNESS); -- cgit v1.2.3 From 9d165362201f38f8722227ad72f23bba28125119 Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Wed, 8 Dec 2010 10:34:28 -0500 Subject: Automated merge from mesh-development --- indra/newview/llfloatermodelpreview.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index b82e9dd62f..07af8382a3 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -102,11 +102,12 @@ const S32 PREVIEW_RESIZE_HANDLE_SIZE = S32(RESIZE_HANDLE_WIDTH * OO_SQRT2) + PRE const S32 PREVIEW_HPAD = PREVIEW_RESIZE_HANDLE_SIZE; const S32 PREF_BUTTON_HEIGHT = 16 + 7 + 16; const S32 PREVIEW_TEXTURE_HEIGHT = 300; +const S32 NUM_LOD = 4; void drawBoxOutline(const LLVector3& pos, const LLVector3& size); -std::string lod_name[] = +std::string lod_name[NUM_LOD+1] = { "lowest", "low", @@ -115,7 +116,7 @@ std::string lod_name[] = "I went off the end of the lod_name array. Me so smart." }; -std::string lod_triangles_name[] = +std::string lod_triangles_name[NUM_LOD+1] = { "lowest_triangles", "low_triangles", @@ -124,7 +125,7 @@ std::string lod_triangles_name[] = "I went off the end of the lod_triangles_name array. Me so smart." }; -std::string lod_vertices_name[] = +std::string lod_vertices_name[NUM_LOD+1] = { "lowest_vertices", "low_vertices", @@ -133,7 +134,7 @@ std::string lod_vertices_name[] = "I went off the end of the lod_vertices_name array. Me so smart." }; -std::string lod_status_name[] = +std::string lod_status_name[NUM_LOD+1] = { "lowest_status", "low_status", @@ -142,7 +143,7 @@ std::string lod_status_name[] = "I went off the end of the lod_status_name array. Me so smart." }; -std::string lod_label_name[] = +std::string lod_label_name[NUM_LOD+1] = { "lowest_label", "low_label", @@ -420,6 +421,7 @@ void LLFloaterModelPreview::onPreviewLODCommit(LLUICtrl* ctrl, void* userdata) { which_mode = iface->getFirstSelectedIndex(); } + which_mode = (NUM_LOD-1)-which_mode; // combo box list of lods is in reverse order fp->mModelPreview->setPreviewLOD(which_mode); } @@ -3752,7 +3754,7 @@ void LLModelPreview::setPreviewLOD(S32 lod) mPreviewLOD = lod; LLComboBox* combo_box = mFMP->getChild("preview_lod_combo"); - combo_box->setCurrentByIndex(mPreviewLOD); + combo_box->setCurrentByIndex((NUM_LOD-1)-mPreviewLOD); // combo box list of lods is in reverse order mFMP->childSetTextArg("lod_table_footer", "[DETAIL]", mFMP->getString(lod_name[mPreviewLOD])); mFMP->childSetText("lod_file", mLODFile[mPreviewLOD]); -- cgit v1.2.3 From a1e59112d028469870c7d1b38c8dbb56f556959d Mon Sep 17 00:00:00 2001 From: prep Date: Wed, 8 Dec 2010 14:50:25 -0500 Subject: Fix for SH-424 --- indra/newview/llfloatermodelpreview.cpp | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 07af8382a3..1e0624f8c4 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -284,6 +284,7 @@ BOOL LLFloaterModelPreview::postBuild() childDisable("upload_skin"); childDisable("upload_joints"); + childDisable("ok_btn"); initDecompControls(); @@ -1554,9 +1555,11 @@ void LLModelLoader::run() } daeElement* scene = root->getDescendant("visual_scene"); + if (!scene) { llwarns << "document has no visual_scene" << llendl; + setLoadState( ERROR_PARSING ); return; } @@ -2001,6 +2004,11 @@ LLModelPreview::~LLModelPreview() U32 LLModelPreview::calcResourceCost() { rebuildUploadData(); + + if ( mModelLoader->getLoadState() != LLModelLoader::ERROR_PARSING ) + { + mFMP->childEnable("ok_btn"); + } U32 cost = 0; std::set accounted; @@ -2095,6 +2103,11 @@ void LLModelPreview::rebuildUploadData() F32 max_scale = 0.f; + if ( mBaseScene.size() > 0 ) + { + mFMP->childEnable("ok_btn"); + } + for (LLModelLoader::scene::iterator iter = mBaseScene.begin(); iter != mBaseScene.end(); ++iter) { //for each transform in scene LLMatrix4 mat = iter->first; @@ -2235,6 +2248,11 @@ void LLModelPreview::loadModel(std::string filename, S32 lod) setPreviewLOD(lod); + if ( mModelLoader->getLoadState() == LLModelLoader::ERROR_PARSING ) + { + mFMP->childDisable("ok_btn"); + } + if (lod == mPreviewLOD) { mFMP->childSetText("lod_file", mLODFile[mPreviewLOD]); @@ -3001,7 +3019,9 @@ void LLModelPreview::updateStatusMessages() mFMP->childSetText(lod_status_name[lod], message); } - if (upload_ok) + bool errorStateFromLoader = mModelLoader->getLoadState() == LLModelLoader::ERROR_PARSING ? true : false; + + if ( upload_ok && !errorStateFromLoader ) { mFMP->childEnable("ok_btn"); } @@ -3888,4 +3908,3 @@ void LLFloaterModelPreview::DecompRequest::completed() sInstance->mCurRequest = NULL; } } - -- cgit v1.2.3 From db1af2445dac667eb24c69d005509b8ff007cc9e Mon Sep 17 00:00:00 2001 From: leyla_linden Date: Thu, 9 Dec 2010 17:30:17 -0800 Subject: Initial code for the upload model wizard - loading model is working, not much else --- indra/newview/llfloatermodelpreview.cpp | 39 ++++++++++++++------------------- 1 file changed, 16 insertions(+), 23 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 1e0624f8c4..0cfebdb399 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -212,24 +212,18 @@ BOOL stop_gloderror() return FALSE; } -class LLMeshFilePicker : public LLFilePickerThread -{ -public: - LLFloaterModelPreview* mFMP; - S32 mLOD; - LLMeshFilePicker(LLFloaterModelPreview* fmp, S32 lod) +LLMeshFilePicker::LLMeshFilePicker(LLModelPreview* mp, S32 lod) : LLFilePickerThread(LLFilePicker::FFLOAD_COLLADA) { - mFMP = fmp; + mMP = mp; mLOD = lod; } - - virtual void notify(const std::string& filename) - { - mFMP->mModelPreview->loadModel(mFile, mLOD); - } -}; + +void LLMeshFilePicker::notify(const std::string& filename) +{ + mMP->loadModel(mFile, mLOD); +} //----------------------------------------------------------------------------- @@ -242,7 +236,6 @@ LLFloater(key) mLastMouseX = 0; mLastMouseY = 0; mGLName = 0; - mLoading = FALSE; } //----------------------------------------------------------------------------- @@ -294,6 +287,7 @@ BOOL LLFloaterModelPreview::postBuild() mModelPreview = new LLModelPreview(512, 512, this); mModelPreview->setPreviewTarget(16.f); + mModelPreview->setAspect((F32) mPreviewRect.getWidth()/mPreviewRect.getHeight()); //set callbacks for left click on line editor rows for (U32 i = 0; i <= LLModel::LOD_HIGH; i++) @@ -348,9 +342,9 @@ LLFloaterModelPreview::~LLFloaterModelPreview() void LLFloaterModelPreview::loadModel(S32 lod) { - mLoading = TRUE; + mModelPreview->mLoading = true; - (new LLMeshFilePicker(this, lod))->getFile(); + (new LLMeshFilePicker(mModelPreview, lod))->getFile(); } void LLFloaterModelPreview::setLimit(S32 lod, S32 limit) @@ -493,7 +487,7 @@ void LLFloaterModelPreview::draw() mModelPreview->update(); - if (!mLoading) + if (!mModelPreview->mLoading) { childSetTextArg("status", "[STATUS]", getString("status_idle")); } @@ -1966,7 +1960,7 @@ LLColor4 LLModelLoader::getDaeColor(daeElement* element) // LLModelPreview //----------------------------------------------------------------------------- -LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloaterModelPreview* fmp) +LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) : LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE), LLMutex(NULL) { mNeedsUpdate = TRUE; @@ -1978,6 +1972,7 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloaterModelPreview* fmp mPreviewLOD = 0; mModelLoader = NULL; mDirty = false; + mLoading = false; for (U32 i = 0; i < LLModel::NUM_LODS; i++) { @@ -2216,7 +2211,7 @@ void LLModelPreview::loadModel(std::string filename, S32 lod) mFMP->closeFloater(false); } - mFMP->mLoading = false; + mLoading = false; return; } @@ -2339,7 +2334,7 @@ void LLModelPreview::loadModelCallback(S32 lod) resetPreviewTarget(); } - mFMP->mLoading = FALSE; + mLoading = false; refresh(); } @@ -3369,9 +3364,7 @@ BOOL LLModelPreview::render() glClear(GL_DEPTH_BUFFER_BIT); - F32 aspect = (F32) mFMP->mPreviewRect.getWidth()/mFMP->mPreviewRect.getHeight(); - - LLViewerCamera::getInstance()->setAspect(aspect); + LLViewerCamera::getInstance()->setAspect(mAspect); LLViewerCamera::getInstance()->setView(LLViewerCamera::getInstance()->getDefaultFOV() / mCameraZoom); LLVector3 offset = mCameraOffset; -- cgit v1.2.3 From 0ae6e2b451e9dc71800740240a615d934c91e581 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Fri, 10 Dec 2010 15:18:26 -0600 Subject: Reskin model importer according to latest spec, add extra LoD decimation parameters. --- indra/newview/llfloatermodelpreview.cpp | 666 +++++++++++++++++++++++--------- 1 file changed, 484 insertions(+), 182 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index b82e9dd62f..625f8924a2 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -67,7 +67,9 @@ #include "lleconomy.h" #include "llfocusmgr.h" #include "llfloaterperms.h" +#include "lliconctrl.h" #include "llmatrix4a.h" +#include "llmenubutton.h" #include "llmeshrepository.h" #include "llsdutil_math.h" #include "lltextbox.h" @@ -80,17 +82,21 @@ #include "llvoavatarself.h" #include "pipeline.h" #include "lluictrlfactory.h" +#include "llviewermenu.h" #include "llviewermenufile.h" #include "llviewerregion.h" +#include "llviewertexturelist.h" #include "llstring.h" #include "llbutton.h" #include "llcheckboxctrl.h" #include "llsliderctrl.h" #include "llspinctrl.h" +#include "lltoggleablemenu.h" #include "llvfile.h" #include "llvfs.h" + #include "glod/glod.h" //static @@ -132,16 +138,33 @@ std::string lod_vertices_name[] = "high_vertices", "I went off the end of the lod_vertices_name array. Me so smart." }; - -std::string lod_status_name[] = + +std::string lod_status_name[] = +{ + "lowest_status", + "low_status", + "medium_status", + "high_status", + "I went off the end of the lod_status_name array. Me so smart." +}; + +std::string lod_icon_name[] = { - "lowest_status", - "low_status", - "medium_status", - "high_status", + "status_icon_lowest", + "status_icon_low", + "status_icon_medium", + "status_icon_high", "I went off the end of the lod_status_name array. Me so smart." }; +std::string lod_status_image[] = +{ + "ModelImport_Status_Good", + "ModelImport_Status_Warning", + "ModelImport_Status_Error", + "I went off the end of the lod_status_image array. Me so smart." +}; + std::string lod_label_name[] = { "lowest_label", @@ -152,7 +175,6 @@ std::string lod_label_name[] = }; - bool validate_face(const LLVolumeFace& face) { for (U32 i = 0; i < face.mNumIndices; ++i) @@ -254,21 +276,28 @@ BOOL LLFloaterModelPreview::postBuild() return FALSE; } + setViewOption("show_textures", true); + childSetAction("lod_browse", onBrowseLOD, this); - childSetCommitCallback("lod_triangle_limit", onTriangleLimitCommit, this); childSetCommitCallback("crease_angle", onGenerateNormalsCommit, this); childSetCommitCallback("generate_normals", onGenerateNormalsCommit, this); - childSetCommitCallback("show edges", onShowEdgesCommit, this); childSetCommitCallback("lod_generate", onAutoFillCommit, this); + + childSetCommitCallback("lod_mode", onLODParamCommit, this); + childSetCommitCallback("lod_error_threshold", onLODParamCommit, this); + childSetCommitCallback("lod_triangle_limit", onLODParamCommit, this); + childSetCommitCallback("build_operator", onLODParamCommit, this); + childSetCommitCallback("queue_mode", onLODParamCommit, this); + childSetCommitCallback("border_mode", onLODParamCommit, this); + childSetCommitCallback("share_tolerance", onLODParamCommit, this); childSetTextArg("status", "[STATUS]", getString("status_idle")); //childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d",sUploadAmount)); childSetAction("ok_btn", onUpload, this); - childSetAction("consolidate", onConsolidate, this); childSetAction("clear_materials", onClearMaterials, this); childSetCommitCallback("preview_lod_combo", onPreviewLODCommit, this); @@ -283,7 +312,18 @@ BOOL LLFloaterModelPreview::postBuild() childDisable("upload_skin"); childDisable("upload_joints"); + + mViewOptionMenuButton = getChild("options_gear_btn"); + + mCommitCallbackRegistrar.add("ModelImport.ViewOption.Action", boost::bind(&LLFloaterModelPreview::onViewOptionChecked, this, _2)); + mEnableCallbackRegistrar.add("ModelImport.ViewOption.Check", boost::bind(&LLFloaterModelPreview::isViewOptionChecked, this, _2)); + mEnableCallbackRegistrar.add("ModelImport.ViewOption.Enabled", boost::bind(&LLFloaterModelPreview::isViewOptionEnabled, this, _2)); + + + mViewOptionMenu = LLUICtrlFactory::getInstance()->createFromFile("menu_model_import_gear_default.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + mViewOptionMenuButton->setMenu(mViewOptionMenu, LLMenuButton::MP_BOTTOM_LEFT); + initDecompControls(); LLView* preview_panel = getChild("preview_panel"); @@ -344,6 +384,42 @@ LLFloaterModelPreview::~LLFloaterModelPreview() } } +void LLFloaterModelPreview::onViewOptionChecked(const LLSD& userdata) +{ + mViewOption[userdata.asString()] = !mViewOption[userdata.asString()]; + mModelPreview->refresh(); +} + +bool LLFloaterModelPreview::isViewOptionChecked(const LLSD& userdata) +{ + return mViewOption[userdata.asString()]; +} + +bool LLFloaterModelPreview::isViewOptionEnabled(const LLSD& userdata) +{ + return !mViewOptionDisabled[userdata.asString()]; +} + +void LLFloaterModelPreview::setViewOptionEnabled(const std::string& option, bool enabled) +{ + mViewOptionDisabled[option] = !enabled; +} + +void LLFloaterModelPreview::enableViewOption(const std::string& option) +{ + setViewOptionEnabled(option, true); +} + +void LLFloaterModelPreview::disableViewOption(const std::string& option) +{ + setViewOptionEnabled(option, false); +} + +void LLFloaterModelPreview::setViewOption(const std::string& option, bool value) +{ + mViewOption[option] = value; +} + void LLFloaterModelPreview::loadModel(S32 lod) { mLoading = TRUE; @@ -351,16 +427,6 @@ void LLFloaterModelPreview::loadModel(S32 lod) (new LLMeshFilePicker(this, lod))->getFile(); } -void LLFloaterModelPreview::setLimit(S32 lod, S32 limit) -{ - if (limit != mModelPreview->mLimit[lod]) - { - mModelPreview->mLimit[lod] = limit; - mModelPreview->genLODs(lod); - mModelPreview->setPreviewLOD(lod); - } -} - //static void LLFloaterModelPreview::onImportScaleCommit(LLUICtrl*,void* userdata) { @@ -423,30 +489,6 @@ void LLFloaterModelPreview::onPreviewLODCommit(LLUICtrl* ctrl, void* userdata) fp->mModelPreview->setPreviewLOD(which_mode); } -//static -void LLFloaterModelPreview::setLimit(S32 lod, void* userdata) -{ - LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; - - if (!fp->mModelPreview) - { - return; - } - - S32 limit = fp->childGetValue("lod_triangle_limit").asInteger(); - - - fp->setLimit(lod, limit); -} - -//static -void LLFloaterModelPreview::onTriangleLimitCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; - - LLFloaterModelPreview::setLimit(fp->mModelPreview->mPreviewLOD, userdata); -} - //static void LLFloaterModelPreview::onGenerateNormalsCommit(LLUICtrl* ctrl, void* userdata) { @@ -455,14 +497,6 @@ void LLFloaterModelPreview::onGenerateNormalsCommit(LLUICtrl* ctrl, void* userda fp->mModelPreview->generateNormals(); } -//static -void LLFloaterModelPreview::onShowEdgesCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; - - fp->mModelPreview->refresh(); -} - //static void LLFloaterModelPreview::onExplodeCommit(LLUICtrl* ctrl, void* userdata) { @@ -479,6 +513,15 @@ void LLFloaterModelPreview::onAutoFillCommit(LLUICtrl* ctrl, void* userdata) fp->mModelPreview->genLODs(); } +//static +void LLFloaterModelPreview::onLODParamCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; + fp->mModelPreview->genLODs(fp->mModelPreview->mPreviewLOD); + fp->mModelPreview->updateStatusMessages(); + fp->mModelPreview->refresh(); +} + //----------------------------------------------------------------------------- // draw() @@ -881,7 +924,6 @@ void LLFloaterModelPreview::initDecompControls() childSetCommitCallback("physics_layer", LLFloaterModelPreview::refresh, LLFloaterModelPreview::sInstance); childSetCommitCallback("physics_explode", LLFloaterModelPreview::onExplodeCommit, this); - childSetCommitCallback("show physics", LLFloaterModelPreview::refresh, this); } //----------------------------------------------------------------------------- @@ -1972,12 +2014,14 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloaterModelPreview* fmp mTextureName = 0; mPreviewLOD = 0; mModelLoader = NULL; + mMaxTriangleLimit = 0; mDirty = false; + mGenLOD = false; - for (U32 i = 0; i < LLModel::NUM_LODS; i++) - { - mLimit[i] = 0; - } + mBuildShareTolerance = 0.f; + mBuildQueueMode = GLOD_QUEUE_GREEDY; + mBuildBorderMode = GLOD_BORDER_UNLOCK; + mBuildOperator = GLOD_OPERATOR_HALF_EDGE_COLLAPSE; mFMP = fmp; @@ -2256,6 +2300,7 @@ void LLModelPreview::setPhysicsFromLOD(S32 lod) mVertexBuffer[LLModel::LOD_PHYSICS].clear(); rebuildUploadData(); refresh(); + updateStatusMessages(); } } @@ -2304,16 +2349,20 @@ void LLModelPreview::loadModelCallback(S32 lod) if (lod == LLModel::LOD_HIGH) { //save a copy of the highest LOD for automatic LOD manipulation + if (mBaseModel.empty()) + { //first time we've loaded a model, auto-gen LoD + mGenLOD = true; + } + mBaseModel = mModel[lod]; mBaseScene = mScene[lod]; mVertexBuffer[5].clear(); - //mModel[lod] = NULL; } clearIncompatible(lod); mDirty = true; - + if (lod == LLModel::LOD_HIGH) { resetPreviewTarget(); @@ -2616,11 +2665,6 @@ void LLModelPreview::genLODs(S32 which_lod) S32 limit = -1; - if (which_lod != -1) - { - limit = mLimit[which_lod]; - } - U32 triangle_count = 0; for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) @@ -2644,29 +2688,132 @@ void LLModelPreview::genLODs(S32 which_lod) mPatch.clear(); } + U32 lod_mode = 0; + + LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode"); + if (iface) + { + lod_mode = iface->getFirstSelectedIndex(); + } + + F32 lod_error_threshold = mFMP->childGetValue("lod_error_threshold").asReal(); + + if (lod_mode == 0) + { + lod_mode = GLOD_TRIANGLE_BUDGET; + if (which_lod != -1) + { + limit = mFMP->childGetValue("lod_triangle_limit").asInteger(); + } + } + else + { + lod_mode = GLOD_ERROR_THRESHOLD; + } + + U32 build_operator = 0; + + iface = mFMP->childGetSelectionInterface("build_operator"); + if (iface) + { + build_operator = iface->getFirstSelectedIndex(); + } + + if (build_operator == 0) + { + build_operator = GLOD_OPERATOR_HALF_EDGE_COLLAPSE; + } + else + { + build_operator = GLOD_OPERATOR_EDGE_COLLAPSE; + } + + U32 queue_mode; + iface = mFMP->childGetSelectionInterface("queue_mode"); + if (iface) + { + queue_mode = iface->getFirstSelectedIndex(); + } + + if (queue_mode == 0) + { + queue_mode = GLOD_QUEUE_GREEDY; + } + else if (queue_mode == 1) + { + queue_mode = GLOD_QUEUE_LAZY; + } + else + { + queue_mode = GLOD_QUEUE_INDEPENDENT; + } + + U32 border_mode = 0; + + iface = mFMP->childGetSelectionInterface("border_mode"); + if (iface) + { + border_mode = iface->getFirstSelectedIndex(); + } + + if (border_mode == 0) + { + border_mode = GLOD_BORDER_UNLOCK; + } + else + { + border_mode = GLOD_BORDER_LOCK; + } + + bool object_dirty = false; + if (border_mode != mBuildBorderMode) + { + mBuildBorderMode = border_mode; + object_dirty = true; + } + + if (queue_mode != mBuildQueueMode) + { + mBuildQueueMode = queue_mode; + object_dirty = true; + } + + if (build_operator != mBuildOperator) + { + mBuildOperator = build_operator; + object_dirty = true; + } + + F32 share_tolerance = mFMP->childGetValue("share_tolerance").asReal(); + if (share_tolerance != mBuildShareTolerance) + { + mBuildShareTolerance = share_tolerance; + object_dirty = true; + } + for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) { //build GLOD objects for each model in base model list LLModel* mdl = *iter; if (mGroup[mdl] == 0) { mGroup[mdl] = cur_name++; + } + + if (mObject[mdl] == 0 || object_dirty) + { + if (mObject[mdl] != 0) + { + glodDeleteObject(mObject[mdl]); + } + mObject[mdl] = cur_name++; glodNewGroup(mGroup[mdl]); stop_gloderror(); - glodGroupParameteri(mGroup[mdl], GLOD_ADAPT_MODE, GLOD_TRIANGLE_BUDGET); - stop_gloderror(); - - glodGroupParameteri(mGroup[mdl], GLOD_ERROR_MODE, GLOD_OBJECT_SPACE_ERROR); - stop_gloderror(); - - glodGroupParameterf(mGroup[mdl], GLOD_OBJECT_SPACE_ERROR_THRESHOLD, 0.025f); - stop_gloderror(); - glodNewObject(mObject[mdl], mGroup[mdl], GLOD_DISCRETE); stop_gloderror(); - + if (iter == mBaseModel.begin() && !mdl->mSkinWeights.empty()) { //regenerate vertex buffer for skinned models to prevent animation feedback during LOD generation mVertexBuffer[5].clear(); @@ -2689,38 +2836,25 @@ void LLModelPreview::genLODs(S32 which_lod) tri_count += num_indices/3; stop_gloderror(); } + + glodObjectParameteri(mObject[mdl], GLOD_BUILD_OPERATOR, build_operator); + stop_gloderror(); + + glodObjectParameteri(mObject[mdl], GLOD_BUILD_QUEUE_MODE, queue_mode); + stop_gloderror(); + + glodObjectParameteri(mObject[mdl], GLOD_BUILD_BORDER_MODE, border_mode); + stop_gloderror(); + + glodObjectParameterf(mObject[mdl], GLOD_BUILD_SHARE_TOLERANCE, share_tolerance); + stop_gloderror(); + + glodBuildObject(mObject[mdl]); + stop_gloderror(); //store what percentage of total model (in terms of triangle count) this model makes up mPercentage[mdl] = (F32) tri_count / (F32) base_triangle_count; - - //build glodobject - glodBuildObject(mObject[mdl]); - if (stop_gloderror()) - { - glodDeleteGroup(mGroup[mdl]); - stop_gloderror(); - glodDeleteObject(mObject[mdl]); - stop_gloderror(); - - mGroup[mdl] = 0; - mObject[mdl] = 0; - - if (which_lod == -1) - { - mModel[LLModel::LOD_HIGH] = mBaseModel; - } - - return; - } - - } - - //generating LODs for all entries, or this entry has a triangle budget - glodGroupParameteri(mGroup[mdl], GLOD_ADAPT_MODE, GLOD_TRIANGLE_BUDGET); - stop_gloderror(); - - glodGroupParameterf(mGroup[mdl], GLOD_OBJECT_SPACE_ERROR_THRESHOLD, 0.025f); - stop_gloderror(); + } } @@ -2732,9 +2866,8 @@ void LLModelPreview::genLODs(S32 which_lod) start = end = which_lod; } - LLSpinCtrl* lim = mFMP->getChild("lod_triangle_limit", TRUE); - lim->setMaxValue(base_triangle_count); - + mMaxTriangleLimit = base_triangle_count; + for (S32 lod = start; lod >= end; --lod) { if (which_lod == -1) @@ -2768,9 +2901,21 @@ void LLModelPreview::genLODs(S32 which_lod) target_count = 4; } - glodGroupParameteri(mGroup[base], GLOD_MAX_TRIANGLES, target_count); + glodGroupParameteri(mGroup[base], GLOD_ADAPT_MODE, lod_mode); + stop_gloderror(); + + glodGroupParameteri(mGroup[base], GLOD_ADAPT_MODE, lod_mode); + stop_gloderror(); + + glodGroupParameteri(mGroup[base], GLOD_ERROR_MODE, GLOD_OBJECT_SPACE_ERROR); stop_gloderror(); + glodGroupParameteri(mGroup[base], GLOD_MAX_TRIANGLES, target_count); + stop_gloderror(); + + glodGroupParameterf(mGroup[base], GLOD_OBJECT_SPACE_ERROR_THRESHOLD, lod_error_threshold); + stop_gloderror(); + glodAdaptGroup(mGroup[base]); stop_gloderror(); @@ -2938,17 +3083,26 @@ void LLModelPreview::updateStatusMessages() } } + if (mMaxTriangleLimit == 0) + { + mMaxTriangleLimit = total_tris[LLModel::LOD_HIGH]; + } + + mFMP->childSetTextArg("submeshes_info", "[SUBMESHES]", llformat("%d", total_submeshes[LLModel::LOD_HIGH])); - std::string mesh_status_good = mFMP->getString("mesh_status_good"); - std::string mesh_status_bad = mFMP->getString("mesh_status_bad"); std::string mesh_status_na = mFMP->getString("mesh_status_na"); - std::string mesh_status_none = mFMP->getString("mesh_status_none"); + + S32 upload_status[LLModel::LOD_HIGH+1]; bool upload_ok = true; - + for (S32 lod = 0; lod <= LLModel::LOD_HIGH; ++lod) { + upload_status[lod] = 0; + + std::string message = "mesh_status_good"; + if (total_tris[lod] > 0) { mFMP->childSetText(lod_triangles_name[lod], llformat("%d", total_tris[lod])); @@ -2956,26 +3110,40 @@ void LLModelPreview::updateStatusMessages() } else { + if (lod == LLModel::LOD_HIGH) + { + upload_status[lod] = 2; + message = "mesh_status_missing_lod"; + } + else + { + for (S32 i = lod-1; i >= 0; --i) + { + if (total_tris[i] > 0) + { + upload_status[lod] = 2; + message = "mesh_status_missing_lod"; + } + } + } + mFMP->childSetText(lod_triangles_name[lod], mesh_status_na); mFMP->childSetText(lod_vertices_name[lod], mesh_status_na); } - - std::string message = mesh_status_good; - const U32 lod_high = LLModel::LOD_HIGH; if (lod != lod_high) { if (total_submeshes[lod] && total_submeshes[lod] != total_submeshes[lod_high]) { //number of submeshes is different - message = mesh_status_bad; - upload_ok = false; + message = "mesh_status_submesh_mismatch"; + upload_status[lod] = 2; } else if (!tris[lod].empty() && tris[lod].size() != tris[lod_high].size()) { //number of meshes is different - message = mesh_status_bad; - upload_ok = false; + message = "mesh_status_mesh_mismatch"; + upload_status[lod] = 2; } else if (!verts[lod].empty()) { @@ -2983,20 +3151,34 @@ void LLModelPreview::updateStatusMessages() { S32 max_verts = i < verts[lod+1].size() ? verts[lod+1][i] : 0; - if (verts[lod][i] > max_verts) - { //too many vertices in this lod - message = mesh_status_bad; - upload_ok = false; + if (max_verts > 0) + { + if (verts[lod][i] > max_verts) + { //too many vertices in this lod + message = "mesh_status_too_many_vertices"; + upload_status[lod] = 2; + } } } } - else - { //no mesh - message = mesh_status_none; - } } - mFMP->childSetText(lod_status_name[lod], message); + LLIconCtrl* icon = mFMP->getChild(lod_icon_name[lod]); + LLUIImagePtr img = LLUI::getUIImage(lod_status_image[upload_status[lod]]); + icon->setVisible(true); + icon->setImage(img); + + if (upload_status[lod] >= 2) + { + upload_ok = false; + } + + if (lod == mPreviewLOD) + { + mFMP->childSetText("lod_status_message_text", mFMP->getString(message)); + icon = mFMP->getChild("lod_status_message_icon"); + icon->setImage(img); + } } if (upload_ok) @@ -3069,20 +3251,121 @@ void LLModelPreview::updateStatusMessages() mFMP->childSetTextArg("physics_points", "[POINTS]", mesh_status_na); } + if (phys_tris > 0 || phys_hulls > 0) + { + if (!mFMP->isViewOptionEnabled("show_physics")) + { + mFMP->enableViewOption("show_physics"); + mFMP->setViewOption("show_physics", true); + } + } + else + { + mFMP->disableViewOption("show_physics"); + mFMP->setViewOption("show_physics", false); + } + + const char* lod_controls[] = + { + "lod_mode", + "lod_triangle_limit", + "lod_error_tolerance", + "build_operator_text", + "queue_mode_text", + "border_mode_text", + "share_tolerance_text", + "build_operator", + "queue_mode", + "border_mode", + "share_tolerance" + }; + const U32 num_lod_controls = sizeof(lod_controls)/sizeof(char*); + + const char* file_controls[] = + { + "lod_browse", + "lod_file" + }; + const U32 num_file_controls = sizeof(file_controls)/sizeof(char*); + //enable/disable controls based on radio groups if (mFMP->childGetValue("lod_from_file").asBoolean()) { - mFMP->childDisable("lod_triangle_limit"); - mFMP->childDisable("lod_generate"); - mFMP->childEnable("lod_file"); - mFMP->childEnable("lod_browse"); + for (U32 i = 0; i < num_file_controls; ++i) + { + mFMP->childEnable(file_controls[i]); + } + + for (U32 i = 0; i < num_lod_controls; ++i) + { + mFMP->childDisable(lod_controls[i]); + } + + } - else + else if (mFMP->childGetValue("lod_auto_generate").asBoolean()) { - mFMP->childEnable("lod_triangle_limit"); - mFMP->childEnable("lod_generate"); - mFMP->childDisable("lod_file"); - mFMP->childDisable("lod_browse"); + for (U32 i = 0; i < num_file_controls; ++i) + { + mFMP->childDisable(file_controls[i]); + } + + for (U32 i = 0; i < num_lod_controls; ++i) + { + mFMP->childEnable(lod_controls[i]); + } + + //if (threshold) + { + U32 lod_mode = 0; + LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode"); + if (iface) + { + lod_mode = iface->getFirstSelectedIndex(); + } + + LLSpinCtrl* threshold = mFMP->getChild("lod_error_threshold"); + LLSpinCtrl* limit = mFMP->getChild("lod_triangle_limit"); + + limit->setMaxValue(mMaxTriangleLimit); + limit->setValue(total_tris[mPreviewLOD]); + + if (lod_mode == 0) + { + limit->setVisible(true); + threshold->setVisible(false); + + limit->setMaxValue(mMaxTriangleLimit); + } + else + { + limit->setVisible(false); + threshold->setVisible(true); + } + } + } + else + { // "None" is chosen + for (U32 i = 0; i < num_file_controls; ++i) + { + mFMP->childDisable(file_controls[i]); + } + + for (U32 i = 0; i < num_lod_controls; ++i) + { + mFMP->childDisable(lod_controls[i]); + } + + if (!mModel[mPreviewLOD].empty()) + { + mModel[mPreviewLOD].clear(); + mScene[mPreviewLOD].clear(); + mVertexBuffer[mPreviewLOD].clear(); + + //this can cause phasing issues with the UI, so reenter this function and return + updateStatusMessages(); + return; + } } if (mFMP->childGetValue("physics_load_from_file").asBoolean()) @@ -3116,7 +3399,7 @@ void LLModelPreview::clearBuffers() } } -void LLModelPreview::genBuffers(S32 lod, bool avatar_preview) +void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights) { U32 tri_count = 0; U32 vertex_count = 0; @@ -3167,7 +3450,7 @@ void LLModelPreview::genBuffers(S32 lod, bool avatar_preview) LLVertexBuffer* vb = NULL; - bool skinned = avatar_preview && !mdl->mSkinWeights.empty(); + bool skinned = include_skin_weights && !mdl->mSkinWeights.empty(); U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; @@ -3249,7 +3532,17 @@ void LLModelPreview::update() mDirty = false; mResourceCost = calcResourceCost(); refresh(); + updateStatusMessages(); } + + if (mGenLOD) + { + mGenLOD = false; + genLODs(); + refresh(); + updateStatusMessages(); + } + } //----------------------------------------------------------------------------- @@ -3260,6 +3553,12 @@ BOOL LLModelPreview::render() LLMutexLock lock(this); mNeedsUpdate = FALSE; + bool edges = mFMP->isViewOptionChecked("show_edges"); + bool joint_positions = mFMP->isViewOptionChecked("show_joint_positions"); + bool skin_weight = mFMP->isViewOptionChecked("show_skin_weight"); + bool textures = mFMP->isViewOptionChecked("show_textures"); + bool physics = mFMP->isViewOptionChecked("show_physics"); + S32 width = getWidth(); S32 height = getHeight(); @@ -3291,7 +3590,7 @@ BOOL LLModelPreview::render() gGL.popMatrix(); } - bool avatar_preview = false; + bool has_skin_weights = false; bool upload_skin = mFMP->childGetValue("upload_skin").asBoolean(); bool upload_joints = mFMP->childGetValue("upload_joints").asBoolean(); @@ -3303,45 +3602,39 @@ BOOL LLModelPreview::render() LLModel* model = instance.mModel; if (!model->mSkinWeights.empty()) { - avatar_preview = true; + has_skin_weights = true; } } } - - if (upload_skin && !avatar_preview) + + if (has_skin_weights) + { //model has skin weights, enable view options for skin weights and joint positions + mFMP->enableViewOption("show_skin_weight"); + mFMP->setViewOptionEnabled("show_joint_positions", skin_weight); + mFMP->childEnable("upload_skin"); + } + else { + mFMP->childDisable("upload_skin"); + mFMP->setViewOption("show_skin_weight", false); + mFMP->disableViewOption("show_skin_weight"); + mFMP->disableViewOption("show_joint_positions"); + skin_weight = false; + } + + if (upload_skin && !has_skin_weights) + { //can't upload skin weights if model has no skin weights mFMP->childSetValue("upload_skin", false); upload_skin = false; } if (!upload_skin && upload_joints) - { + { //can't upload joints if not uploading skin weights mFMP->childSetValue("upload_joints", false); upload_joints = false; } - if (!avatar_preview) - { - mFMP->childDisable("upload_skin"); - } - else - { - mFMP->childEnable("upload_skin"); - } - - if (!upload_skin) - { - mFMP->childDisable("upload_joints"); - } - else - { - mFMP->childEnable("upload_joints"); - } - - avatar_preview = avatar_preview && upload_skin; - - - mFMP->childSetEnabled("consolidate", !avatar_preview); + mFMP->childSetEnabled("upload_joints", upload_skin); F32 explode = mFMP->childGetValue("physics_explode").asReal(); @@ -3358,7 +3651,7 @@ BOOL LLModelPreview::render() F32 z_near = 0.001f; F32 z_far = mCameraDistance+mPreviewScale.magVec()+mCameraOffset.magVec(); - if (avatar_preview) + if (skin_weight) { target_pos = gAgentAvatarp->getPositionAgent(); z_near = 0.01f; @@ -3369,6 +3662,7 @@ BOOL LLModelPreview::render() refresh(); } + glLoadIdentity(); gPipeline.enableLightsPreview(); LLQuaternion camera_rot = LLQuaternion(mCameraPitch, LLVector3::y_axis) * @@ -3393,22 +3687,32 @@ BOOL LLModelPreview::render() if (!mBaseModel.empty() && mVertexBuffer[5].empty()) { - genBuffers(-1, avatar_preview); + genBuffers(-1, skin_weight); //genBuffers(3); //genLODs(); } - bool physics = mFMP->childGetValue("show physics").asBoolean(); S32 physics_idx = mFMP->childGetValue("physics_layer").asInteger(); if (!mModel[mPreviewLOD].empty()) { - if (mVertexBuffer[mPreviewLOD].empty()) + bool regen = mVertexBuffer[mPreviewLOD].empty(); + if (!regen) + { + const std::vector >& vb_vec = mVertexBuffer[mPreviewLOD].begin()->second; + if (!vb_vec.empty()) + { + const LLVertexBuffer* buff = vb_vec[0]; + regen = buff->hasDataType(LLVertexBuffer::TYPE_WEIGHT4) != skin_weight; + } + } + + if (regen) { - genBuffers(mPreviewLOD, avatar_preview); + genBuffers(mPreviewLOD, skin_weight); } - if (!avatar_preview) + if (!skin_weight) { for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) { @@ -3446,7 +3750,7 @@ BOOL LLModelPreview::render() gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); glColor3f(0.4f, 0.4f, 0.4f); - if (mFMP->childGetValue("show edges").asBoolean()) + if (edges) { glLineWidth(3.f); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); @@ -3527,7 +3831,7 @@ BOOL LLModelPreview::render() glColor4ubv(hull_colors[i].mV); buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts()); - if (mFMP->childGetValue("show edges").asBoolean()) + if (edges) { glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glLineWidth(3.f); @@ -3572,7 +3876,7 @@ BOOL LLModelPreview::render() gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); glColor3f(0.4f, 0.4f, 0.4f); - if (mFMP->childGetValue("show edges").asBoolean() || model == physics_model) + if (edges || model == physics_model) { if (model == physics_model) { @@ -3604,7 +3908,10 @@ BOOL LLModelPreview::render() LLVector3::z_axis, // up target_pos); // point of interest - avatar->renderCollisionVolumes(); + if (joint_positions) + { + avatar->renderCollisionVolumes(); + } for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) { @@ -3689,7 +3996,7 @@ BOOL LLModelPreview::render() buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); glColor3f(0.4f, 0.4f, 0.4f); - if (mFMP->childGetValue("show edges").asBoolean()) + if (edges) { glLineWidth(3.f); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); @@ -3770,6 +4077,7 @@ void LLModelPreview::setPreviewLOD(S32 lod) } } refresh(); + updateStatusMessages(); } //static @@ -3792,12 +4100,6 @@ void LLFloaterModelPreview::onUpload(void* user_data) mp->closeFloater(false); } -//static -void LLFloaterModelPreview::onConsolidate(void* user_data) -{ - LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; - mp->mModelPreview->consolidate(); -} //static void LLFloaterModelPreview::onClearMaterials(void* user_data) -- cgit v1.2.3 From 6a599955d1b451697bafef3ad4d72c6c43b69ab7 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Fri, 10 Dec 2010 16:13:41 -0600 Subject: merge cleanup. --- indra/newview/llfloatermodelpreview.cpp | 60 ++++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 20 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index e1a974ce13..d0769f40fe 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -420,7 +420,7 @@ void LLFloaterModelPreview::loadModel(S32 lod) { mModelPreview->mLoading = true; - (new LLMeshFilePicker(this, lod))->getFile(); + (new LLMeshFilePicker(mModelPreview, lod))->getFile(); } //static @@ -3268,18 +3268,22 @@ void LLModelPreview::updateStatusMessages() mFMP->childSetTextArg("physics_points", "[POINTS]", mesh_status_na); } - if (phys_tris > 0 || phys_hulls > 0) + LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; + if (fmp) { - if (!mFMP->isViewOptionEnabled("show_physics")) + if (phys_tris > 0 || phys_hulls > 0) { - mFMP->enableViewOption("show_physics"); - mFMP->setViewOption("show_physics", true); + if (!fmp->isViewOptionEnabled("show_physics")) + { + fmp->enableViewOption("show_physics"); + fmp->setViewOption("show_physics", true); + } + } + else + { + fmp->disableViewOption("show_physics"); + fmp->setViewOption("show_physics", false); } - } - else - { - mFMP->disableViewOption("show_physics"); - mFMP->setViewOption("show_physics", false); } const char* lod_controls[] = @@ -3570,11 +3574,21 @@ BOOL LLModelPreview::render() LLMutexLock lock(this); mNeedsUpdate = FALSE; - bool edges = mFMP->isViewOptionChecked("show_edges"); - bool joint_positions = mFMP->isViewOptionChecked("show_joint_positions"); - bool skin_weight = mFMP->isViewOptionChecked("show_skin_weight"); - bool textures = mFMP->isViewOptionChecked("show_textures"); - bool physics = mFMP->isViewOptionChecked("show_physics"); + bool edges = false; + bool joint_positions = false; + bool skin_weight = false; + bool textures = false; + bool physics = false; + + LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; + if (fmp) + { + edges = fmp->isViewOptionChecked("show_edges"); + joint_positions = fmp->isViewOptionChecked("show_joint_positions"); + skin_weight = fmp->isViewOptionChecked("show_skin_weight"); + textures = fmp->isViewOptionChecked("show_textures"); + physics = fmp->isViewOptionChecked("show_physics"); + } S32 width = getWidth(); S32 height = getHeight(); @@ -3626,16 +3640,22 @@ BOOL LLModelPreview::render() if (has_skin_weights) { //model has skin weights, enable view options for skin weights and joint positions - mFMP->enableViewOption("show_skin_weight"); - mFMP->setViewOptionEnabled("show_joint_positions", skin_weight); + if (fmp) + { + fmp->enableViewOption("show_skin_weight"); + fmp->setViewOptionEnabled("show_joint_positions", skin_weight); + } mFMP->childEnable("upload_skin"); } else { mFMP->childDisable("upload_skin"); - mFMP->setViewOption("show_skin_weight", false); - mFMP->disableViewOption("show_skin_weight"); - mFMP->disableViewOption("show_joint_positions"); + if (fmp) + { + fmp->setViewOption("show_skin_weight", false); + fmp->disableViewOption("show_skin_weight"); + fmp->disableViewOption("show_joint_positions"); + } skin_weight = false; } -- cgit v1.2.3 From 285ba513368c6b692ea2eb5d13b85300c76adbea Mon Sep 17 00:00:00 2001 From: leyla_linden Date: Fri, 10 Dec 2010 17:05:38 -0800 Subject: fixed model uploader aspect not updating, text not following resize, and file name not filling in --- indra/newview/llfloatermodelpreview.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 0cfebdb399..9aa8e62885 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -287,7 +287,6 @@ BOOL LLFloaterModelPreview::postBuild() mModelPreview = new LLModelPreview(512, 512, this); mModelPreview->setPreviewTarget(16.f); - mModelPreview->setAspect((F32) mPreviewRect.getWidth()/mPreviewRect.getHeight()); //set callbacks for left click on line editor rows for (U32 i = 0; i <= LLModel::LOD_HIGH; i++) @@ -3363,8 +3362,12 @@ BOOL LLModelPreview::render() F32 explode = mFMP->childGetValue("physics_explode").asReal(); glClear(GL_DEPTH_BUFFER_BIT); + + LLRect preview_rect = mFMP->getChildView("preview_panel")->getRect(); + F32 aspect = (F32) preview_rect.getWidth()/preview_rect.getHeight(); + + LLViewerCamera::getInstance()->setAspect(aspect); - LLViewerCamera::getInstance()->setAspect(mAspect); LLViewerCamera::getInstance()->setView(LLViewerCamera::getInstance()->getDefaultFOV() / mCameraZoom); LLVector3 offset = mCameraOffset; -- cgit v1.2.3 From 2508bb2d85484a958f6d82ee40346a9c5cfec7ff Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Fri, 10 Dec 2010 20:40:28 -0600 Subject: More correct GLOD usage -- one group, many objects. --- indra/newview/llfloatermodelpreview.cpp | 160 ++++++++++++++++---------------- 1 file changed, 82 insertions(+), 78 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index d0769f40fe..c5c1160371 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -2017,7 +2017,7 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) mDirty = false; mGenLOD = false; mLoading = false; - + mGroup = 0; mBuildShareTolerance = 0.f; mBuildQueueMode = GLOD_QUEUE_GREEDY; mBuildBorderMode = GLOD_BORDER_UNLOCK; @@ -2261,22 +2261,9 @@ void LLModelPreview::loadModel(std::string filename, S32 lod) mLODFile[lod] = filename; - if (lod == 3 && !mGroup.empty()) + if (lod == LLModel::LOD_HIGH) { - for (std::map, U32>::iterator iter = mGroup.begin(); iter != mGroup.end(); ++iter) - { - glodDeleteGroup(iter->second); - stop_gloderror(); - } - - for (std::map, U32>::iterator iter = mObject.begin(); iter != mObject.end(); ++iter) - { - glodDeleteObject(iter->second); - stop_gloderror(); - } - - mGroup.clear(); - mObject.clear(); + clearGLODGroup(); } mModelLoader = new LLModelLoader(filename, lod, this); @@ -2334,6 +2321,7 @@ void LLModelPreview::clearIncompatible(S32 lod) if (i == LLModel::LOD_HIGH) { mBaseModel = mModel[lod]; + clearGLODGroup(); mBaseScene = mScene[lod]; mVertexBuffer[5].clear(); } @@ -2342,6 +2330,23 @@ void LLModelPreview::clearIncompatible(S32 lod) } } +void LLModelPreview::clearGLODGroup() +{ + if (mGroup) + { + for (std::map, U32>::iterator iter = mObject.begin(); iter != mObject.end(); ++iter) + { + glodDeleteObject(iter->second); + stop_gloderror(); + } + mObject.clear(); + + glodDeleteGroup(mGroup); + stop_gloderror(); + mGroup = 0; + } +} + void LLModelPreview::loadModelCallback(S32 lod) { //NOT the main thread LLMutexLock lock(this); @@ -2370,6 +2375,8 @@ void LLModelPreview::loadModelCallback(S32 lod) } mBaseModel = mModel[lod]; + clearGLODGroup(); + mBaseScene = mScene[lod]; mVertexBuffer[5].clear(); } @@ -2597,6 +2604,7 @@ void LLModelPreview::consolidate() { mBaseScene = new_scene; mBaseModel = new_model; + clearGLODGroup(); mVertexBuffer[5].clear(); } @@ -2639,6 +2647,7 @@ void LLModelPreview::clearMaterials() { mBaseScene = mScene[mPreviewLOD]; mBaseModel = mModel[mPreviewLOD]; + clearGLODGroup(); mVertexBuffer[5].clear(); } @@ -2695,14 +2704,6 @@ void LLModelPreview::genLODs(S32 which_lod) U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; - if (mGroup[mBaseModel[0]] == 0) - { //clear LOD maps - mGroup.clear(); - mObject.clear(); - mPercentage.clear(); - mPatch.clear(); - } - U32 lod_mode = 0; LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode"); @@ -2806,16 +2807,19 @@ void LLModelPreview::genLODs(S32 which_lod) object_dirty = true; } - for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) - { //build GLOD objects for each model in base model list - LLModel* mdl = *iter; - if (mGroup[mdl] == 0) - { - mGroup[mdl] = cur_name++; - } + if (mGroup == 0) + { + object_dirty = true; + mGroup = cur_name++; + glodNewGroup(mGroup); + } - if (mObject[mdl] == 0 || object_dirty) - { + if (object_dirty) + { + for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) + { //build GLOD objects for each model in base model list + LLModel* mdl = *iter; + if (mObject[mdl] != 0) { glodDeleteObject(mObject[mdl]); @@ -2823,10 +2827,7 @@ void LLModelPreview::genLODs(S32 which_lod) mObject[mdl] = cur_name++; - glodNewGroup(mGroup[mdl]); - stop_gloderror(); - - glodNewObject(mObject[mdl], mGroup[mdl], GLOD_DISCRETE); + glodNewObject(mObject[mdl], mGroup, GLOD_DISCRETE); stop_gloderror(); if (iter == mBaseModel.begin() && !mdl->mSkinWeights.empty()) @@ -2866,10 +2867,7 @@ void LLModelPreview::genLODs(S32 which_lod) glodBuildObject(mObject[mdl]); stop_gloderror(); - - //store what percentage of total model (in terms of triangle count) this model makes up - mPercentage[mdl] = (F32) tri_count / (F32) base_triangle_count; - } + } } @@ -2905,35 +2903,28 @@ void LLModelPreview::genLODs(S32 which_lod) U32 actual_verts = 0; U32 submeshes = 0; + glodGroupParameteri(mGroup, GLOD_ADAPT_MODE, lod_mode); + stop_gloderror(); + + glodGroupParameteri(mGroup, GLOD_ADAPT_MODE, lod_mode); + stop_gloderror(); + + glodGroupParameteri(mGroup, GLOD_ERROR_MODE, GLOD_OBJECT_SPACE_ERROR); + stop_gloderror(); + + glodGroupParameteri(mGroup, GLOD_MAX_TRIANGLES, triangle_count); + stop_gloderror(); + + glodGroupParameterf(mGroup, GLOD_OBJECT_SPACE_ERROR_THRESHOLD, lod_error_threshold); + stop_gloderror(); + + glodAdaptGroup(mGroup); + stop_gloderror(); + for (U32 mdl_idx = 0; mdl_idx < mBaseModel.size(); ++mdl_idx) { LLModel* base = mBaseModel[mdl_idx]; - U32 target_count = U32(mPercentage[base]*triangle_count); - - if (target_count < 4) - { - target_count = 4; - } - - glodGroupParameteri(mGroup[base], GLOD_ADAPT_MODE, lod_mode); - stop_gloderror(); - - glodGroupParameteri(mGroup[base], GLOD_ADAPT_MODE, lod_mode); - stop_gloderror(); - - glodGroupParameteri(mGroup[base], GLOD_ERROR_MODE, GLOD_OBJECT_SPACE_ERROR); - stop_gloderror(); - - glodGroupParameteri(mGroup[base], GLOD_MAX_TRIANGLES, target_count); - stop_gloderror(); - - glodGroupParameterf(mGroup[base], GLOD_OBJECT_SPACE_ERROR_THRESHOLD, lod_error_threshold); - stop_gloderror(); - - glodAdaptGroup(mGroup[base]); - stop_gloderror(); - GLint patch_count = 0; glodGetObjectParameteriv(mObject[base], GLOD_NUM_PATCHES, &patch_count); stop_gloderror(); @@ -2983,8 +2974,7 @@ void LLModelPreview::genLODs(S32 which_lod) buff->getNormalStrider(norm); buff->getTexCoord0Strider(tc); buff->getIndexStrider(index); - - + target_model->setVolumeFaceData(names[i], pos, norm, tc, index, buff->getNumVerts(), buff->getNumIndices()); actual_tris += buff->getNumIndices()/3; actual_verts += buff->getNumVerts(); @@ -3771,15 +3761,22 @@ BOOL LLModelPreview::render() buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); - glColor4fv(instance.mMaterial[i].mDiffuseColor.mV); - if (i < instance.mMaterial.size() && instance.mMaterial[i].mDiffuseMap.notNull()) + if (textures) { - gGL.getTexUnit(0)->bind(instance.mMaterial[i].mDiffuseMap, true); - if (instance.mMaterial[i].mDiffuseMap->getDiscardLevel() > -1) + glColor4fv(instance.mMaterial[i].mDiffuseColor.mV); + if (i < instance.mMaterial.size() && instance.mMaterial[i].mDiffuseMap.notNull()) { - mTextureSet.insert(instance.mMaterial[i].mDiffuseMap); + gGL.getTexUnit(0)->bind(instance.mMaterial[i].mDiffuseMap, true); + if (instance.mMaterial[i].mDiffuseMap->getDiscardLevel() > -1) + { + mTextureSet.insert(instance.mMaterial[i].mDiffuseMap); + } } } + else + { + glColor4f(1,1,1,1); + } buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); @@ -3897,15 +3894,22 @@ BOOL LLModelPreview::render() buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); - glColor4fv(instance.mMaterial[i].mDiffuseColor.mV); - if (i < instance.mMaterial.size() && instance.mMaterial[i].mDiffuseMap.notNull()) + if (textures) { - gGL.getTexUnit(0)->bind(instance.mMaterial[i].mDiffuseMap, true); - if (instance.mMaterial[i].mDiffuseMap->getDiscardLevel() > -1) + glColor4fv(instance.mMaterial[i].mDiffuseColor.mV); + if (i < instance.mMaterial.size() && instance.mMaterial[i].mDiffuseMap.notNull()) { - mTextureSet.insert(instance.mMaterial[i].mDiffuseMap); + gGL.getTexUnit(0)->bind(instance.mMaterial[i].mDiffuseMap, true); + if (instance.mMaterial[i].mDiffuseMap->getDiscardLevel() > -1) + { + mTextureSet.insert(instance.mMaterial[i].mDiffuseMap); + } } } + else + { + glColor4f(1,1,1,1); + } buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); -- cgit v1.2.3 From 8e5f15a3b64e1e7cd14c8c4c9535299b93f3496b Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Fri, 10 Dec 2010 20:41:12 -0600 Subject: Remove redundant call to glodGroupParameteri --- indra/newview/llfloatermodelpreview.cpp | 3 --- 1 file changed, 3 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index c5c1160371..2e6f4cba1d 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -2903,9 +2903,6 @@ void LLModelPreview::genLODs(S32 which_lod) U32 actual_verts = 0; U32 submeshes = 0; - glodGroupParameteri(mGroup, GLOD_ADAPT_MODE, lod_mode); - stop_gloderror(); - glodGroupParameteri(mGroup, GLOD_ADAPT_MODE, lod_mode); stop_gloderror(); -- cgit v1.2.3 From b76c59a191a5d9a22db9760e0149e2e596964c00 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Mon, 13 Dec 2010 13:27:24 -0500 Subject: SH-653 FIX: upload button now starts out disabled --- indra/newview/llfloatermodelpreview.cpp | 1 + 1 file changed, 1 insertion(+) mode change 100644 => 100755 indra/newview/llfloatermodelpreview.cpp (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp old mode 100644 new mode 100755 index b82e9dd62f..4992661e92 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -267,6 +267,7 @@ BOOL LLFloaterModelPreview::postBuild() //childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d",sUploadAmount)); childSetAction("ok_btn", onUpload, this); + childDisable("ok_btn"); childSetAction("consolidate", onConsolidate, this); childSetAction("clear_materials", onClearMaterials, this); -- cgit v1.2.3 From 4a61efdee973e58e021e4c1564ed5c33e750f92f Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Mon, 13 Dec 2010 17:54:39 -0500 Subject: fixed bad line endings --- indra/newview/llfloatermodelpreview.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 007f6ee3ed..7b71598b81 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -3663,11 +3663,11 @@ BOOL LLModelPreview::render() F32 explode = mFMP->childGetValue("physics_explode").asReal(); glClear(GL_DEPTH_BUFFER_BIT); - - LLRect preview_rect = mFMP->getChildView("preview_panel")->getRect(); - F32 aspect = (F32) preview_rect.getWidth()/preview_rect.getHeight(); - - LLViewerCamera::getInstance()->setAspect(aspect); + + LLRect preview_rect = mFMP->getChildView("preview_panel")->getRect(); + F32 aspect = (F32) preview_rect.getWidth()/preview_rect.getHeight(); + + LLViewerCamera::getInstance()->setAspect(aspect); LLViewerCamera::getInstance()->setView(LLViewerCamera::getInstance()->getDefaultFOV() / mCameraZoom); -- cgit v1.2.3 From ed25bfc431bd209cb78890842ac8fabf5d6ba060 Mon Sep 17 00:00:00 2001 From: "Nyx (Neal Orman)" Date: Tue, 14 Dec 2010 14:54:05 -0500 Subject: BUILDFIX uninitialized variable a potentially uninitialized variable is causing the linux build to fail. Initializing the value to 0, as its our best guess for what it should be, as davep is currently out sick. --- indra/newview/llfloatermodelpreview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 7b71598b81..d1a7ba861b 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -2744,7 +2744,7 @@ void LLModelPreview::genLODs(S32 which_lod) build_operator = GLOD_OPERATOR_EDGE_COLLAPSE; } - U32 queue_mode; + U32 queue_mode=0; iface = mFMP->childGetSelectionInterface("queue_mode"); if (iface) { -- cgit v1.2.3 From 5f8110a68ed2fdfe70e2dbd7363f1194b0f3e67d Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Tue, 14 Dec 2010 15:52:26 -0500 Subject: SH-439 FIX: track name requested in UI separately, so we can fall back to name from dae if needed --- indra/newview/llfloatermodelpreview.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 7b71598b81..f763e9624f 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -2127,7 +2127,10 @@ void LLModelPreview::rebuildUploadData() mTextureSet.clear(); //fill uploaddata instance vectors from scene data + + std::string requested_name = mFMP->getChild("description_form")->getValue().asString(); + LLSpinCtrl* scale_spinner = mFMP->getChild("import_scale"); if (!scale_spinner) @@ -2171,6 +2174,10 @@ void LLModelPreview::rebuildUploadData() LLModelInstance instance = *model_iter; LLModel* base_model = instance.mModel; + if (base_model) + { + base_model->mRequestedLabel = requested_name; + } S32 idx = 0; for (idx = 0; idx < mBaseModel.size(); ++idx) @@ -4131,7 +4138,7 @@ void LLFloaterModelPreview::onBrowseLOD(void* data) void LLFloaterModelPreview::onUpload(void* user_data) { LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; - + mp->mModelPreview->rebuildUploadData(); gMeshRepo.uploadModel(mp->mModelPreview->mUploadData, mp->mModelPreview->mPreviewScale, -- cgit v1.2.3 From 7926c54a0bb72a77f56ff0a260edb166af979445 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Wed, 15 Dec 2010 16:58:35 -0500 Subject: SH-594 FIX: added check for nameless nodes --- indra/newview/llfloatermodelpreview.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index aa27381267..b85f3b3435 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1607,12 +1607,17 @@ void LLModelLoader::run() bool LLModelLoader::isNodeAJoint( domNode* pNode ) { + if ( pNode->getName() == NULL) + { + return false; + } + if ( mJointMap.find( pNode->getName() ) != mJointMap.end() ) { return true; } - return false; + return false; } void LLModelLoader::extractTranslation( domTranslate* pTranslate, LLMatrix4& transform ) -- cgit v1.2.3 From ad625861e120cae967d6bc60a9c1f4d86f4c2ed1 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Wed, 15 Dec 2010 17:07:07 -0500 Subject: SH-594 - added an extra redundant check for nameless nodes --- indra/newview/llfloatermodelpreview.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index b85f3b3435..660157df1e 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1637,6 +1637,12 @@ void LLModelLoader::extractTranslationViaElement( daeElement* pTranslateElement, void LLModelLoader::processJointNode( domNode* pNode, std::map& jointTransforms ) { + if (pNode->getName() == NULL) + { + llwarns << "nameless node, can't process" << llendl; + return; + } + //llwarns<<"ProcessJointNode# Node:" <getName()< Date: Mon, 20 Dec 2010 13:52:48 -0500 Subject: thread safety checking --- indra/newview/llfloatermodelpreview.cpp | 175 +++++++++++++++++--------------- 1 file changed, 92 insertions(+), 83 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 660157df1e..4d8e71918f 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -2057,7 +2057,7 @@ U32 LLModelPreview::calcResourceCost() if ( mModelLoader->getLoadState() != LLModelLoader::ERROR_PARSING ) { - mFMP->childEnable("ok_btn"); + getFMP()->childEnable("ok_btn"); } U32 cost = 0; @@ -2065,7 +2065,7 @@ U32 LLModelPreview::calcResourceCost() U32 num_points = 0; U32 num_hulls = 0; - F32 debug_scale = mFMP->childGetValue("import_scale").asReal(); + F32 debug_scale = getFMP()->childGetValue("import_scale").asReal(); F32 streaming_cost = 0.f; for (U32 i = 0; i < mUploadData.size(); ++i) @@ -2089,8 +2089,8 @@ U32 LLModelPreview::calcResourceCost() instance.mLOD[1], instance.mLOD[0], decomp, - mFMP->childGetValue("upload_skin").asBoolean(), - mFMP->childGetValue("upload_joints").asBoolean(), + getFMP()->childGetValue("upload_skin").asBoolean(), + getFMP()->childGetValue("upload_joints").asBoolean(), TRUE); cost += gMeshRepo.calcResourceCost(ret); @@ -2119,13 +2119,13 @@ U32 LLModelPreview::calcResourceCost() } } - //mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[HULLS]", llformat("%d",num_hulls)); - //mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[POINTS]", llformat("%d",num_points)); - mFMP->childSetTextArg("streaming cost", "[COST]", llformat("%.3f", streaming_cost)); - F32 scale = mFMP->childGetValue("import_scale").asReal()*2.f; - mFMP->childSetTextArg("import_dimensions", "[X]", llformat("%.3f", mPreviewScale[0]*scale)); - mFMP->childSetTextArg("import_dimensions", "[Y]", llformat("%.3f", mPreviewScale[1]*scale)); - mFMP->childSetTextArg("import_dimensions", "[Z]", llformat("%.3f", mPreviewScale[2]*scale)); + //getFMP()->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[HULLS]", llformat("%d",num_hulls)); + //getFMP()->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[POINTS]", llformat("%d",num_points)); + getFMP()->childSetTextArg("streaming cost", "[COST]", llformat("%.3f", streaming_cost)); + F32 scale = getFMP()->childGetValue("import_scale").asReal()*2.f; + getFMP()->childSetTextArg("import_dimensions", "[X]", llformat("%.3f", mPreviewScale[0]*scale)); + getFMP()->childSetTextArg("import_dimensions", "[Y]", llformat("%.3f", mPreviewScale[1]*scale)); + getFMP()->childSetTextArg("import_dimensions", "[Z]", llformat("%.3f", mPreviewScale[2]*scale)); updateStatusMessages(); @@ -2139,10 +2139,10 @@ void LLModelPreview::rebuildUploadData() //fill uploaddata instance vectors from scene data - std::string requested_name = mFMP->getChild("description_form")->getValue().asString(); + std::string requested_name = getFMP()->getChild("description_form")->getValue().asString(); - LLSpinCtrl* scale_spinner = mFMP->getChild("import_scale"); + LLSpinCtrl* scale_spinner = getFMP()->getChild("import_scale"); if (!scale_spinner) { @@ -2158,7 +2158,7 @@ void LLModelPreview::rebuildUploadData() if ( mBaseScene.size() > 0 ) { - mFMP->childEnable("ok_btn"); + getFMP()->childEnable("ok_btn"); } for (LLModelLoader::scene::iterator iter = mBaseScene.begin(); iter != mBaseScene.end(); ++iter) @@ -2226,7 +2226,7 @@ void LLModelPreview::rebuildUploadData() } //refill "layer" combo in physics panel - LLComboBox* combo_box = mFMP->getChild("physics_layer"); + LLComboBox* combo_box = getFMP()->getChild("physics_layer"); if (combo_box) { S32 current = combo_box->getCurrentIndex(); @@ -2270,7 +2270,7 @@ void LLModelPreview::loadModel(std::string filename, S32 lod) { // this is the initial file picking. Close the whole floater // if we don't have a base model to show for high LOD. - mFMP->closeFloater(false); + getFMP()->closeFloater(false); } mLoading = false; @@ -2288,25 +2288,25 @@ void LLModelPreview::loadModel(std::string filename, S32 lod) mModelLoader->start(); - mFMP->childSetTextArg("status", "[STATUS]", mFMP->getString("status_reading_file")); + getFMP()->childSetTextArg("status", "[STATUS]", getFMP()->getString("status_reading_file")); setPreviewLOD(lod); if ( mModelLoader->getLoadState() == LLModelLoader::ERROR_PARSING ) { - mFMP->childDisable("ok_btn"); + getFMP()->childDisable("ok_btn"); } if (lod == mPreviewLOD) { - mFMP->childSetText("lod_file", mLODFile[mPreviewLOD]); + getFMP()->childSetText("lod_file", mLODFile[mPreviewLOD]); } else if (lod == LLModel::LOD_PHYSICS) { - mFMP->childSetText("physics_file", mLODFile[lod]); + getFMP()->childSetText("physics_file", mLODFile[lod]); } - mFMP->openFloater(); + getFMP()->openFloater(); } void LLModelPreview::setPhysicsFromLOD(S32 lod) @@ -2316,7 +2316,7 @@ void LLModelPreview::setPhysicsFromLOD(S32 lod) mModel[LLModel::LOD_PHYSICS] = mModel[lod]; mScene[LLModel::LOD_PHYSICS] = mScene[lod]; mLODFile[LLModel::LOD_PHYSICS].clear(); - mFMP->childSetText("physics_file", mLODFile[LLModel::LOD_PHYSICS]); + getFMP()->childSetText("physics_file", mLODFile[LLModel::LOD_PHYSICS]); mVertexBuffer[LLModel::LOD_PHYSICS].clear(); rebuildUploadData(); refresh(); @@ -2365,6 +2365,13 @@ void LLModelPreview::clearGLODGroup() } } +LLFloater* LLModelPreview::getFMP() +{ + // Shouldn't be accessing this outside the main UI thread. + assert_main_thread(); + return mFMP; +} + void LLModelPreview::loadModelCallback(S32 lod) { //NOT the main thread LLMutexLock lock(this); @@ -2430,7 +2437,7 @@ void LLModelPreview::generateNormals() return; } - F32 angle_cutoff = mFMP->childGetValue("crease_angle").asReal(); + F32 angle_cutoff = getFMP()->childGetValue("crease_angle").asReal(); angle_cutoff *= DEG_TO_RAD; @@ -2724,20 +2731,20 @@ void LLModelPreview::genLODs(S32 which_lod) U32 lod_mode = 0; - LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode"); + LLCtrlSelectionInterface* iface = getFMP()->childGetSelectionInterface("lod_mode"); if (iface) { lod_mode = iface->getFirstSelectedIndex(); } - F32 lod_error_threshold = mFMP->childGetValue("lod_error_threshold").asReal(); + F32 lod_error_threshold = getFMP()->childGetValue("lod_error_threshold").asReal(); if (lod_mode == 0) { lod_mode = GLOD_TRIANGLE_BUDGET; if (which_lod != -1) { - limit = mFMP->childGetValue("lod_triangle_limit").asInteger(); + limit = getFMP()->childGetValue("lod_triangle_limit").asInteger(); } } else @@ -2747,7 +2754,7 @@ void LLModelPreview::genLODs(S32 which_lod) U32 build_operator = 0; - iface = mFMP->childGetSelectionInterface("build_operator"); + iface = getFMP()->childGetSelectionInterface("build_operator"); if (iface) { build_operator = iface->getFirstSelectedIndex(); @@ -2763,7 +2770,7 @@ void LLModelPreview::genLODs(S32 which_lod) } U32 queue_mode=0; - iface = mFMP->childGetSelectionInterface("queue_mode"); + iface = getFMP()->childGetSelectionInterface("queue_mode"); if (iface) { queue_mode = iface->getFirstSelectedIndex(); @@ -2784,7 +2791,7 @@ void LLModelPreview::genLODs(S32 which_lod) U32 border_mode = 0; - iface = mFMP->childGetSelectionInterface("border_mode"); + iface = getFMP()->childGetSelectionInterface("border_mode"); if (iface) { border_mode = iface->getFirstSelectedIndex(); @@ -2818,7 +2825,7 @@ void LLModelPreview::genLODs(S32 which_lod) object_dirty = true; } - F32 share_tolerance = mFMP->childGetValue("share_tolerance").asReal(); + F32 share_tolerance = getFMP()->childGetValue("share_tolerance").asReal(); if (share_tolerance != mBuildShareTolerance) { mBuildShareTolerance = share_tolerance; @@ -3109,9 +3116,9 @@ void LLModelPreview::updateStatusMessages() } - mFMP->childSetTextArg("submeshes_info", "[SUBMESHES]", llformat("%d", total_submeshes[LLModel::LOD_HIGH])); + getFMP()->childSetTextArg("submeshes_info", "[SUBMESHES]", llformat("%d", total_submeshes[LLModel::LOD_HIGH])); - std::string mesh_status_na = mFMP->getString("mesh_status_na"); + std::string mesh_status_na = getFMP()->getString("mesh_status_na"); S32 upload_status[LLModel::LOD_HIGH+1]; @@ -3125,8 +3132,8 @@ void LLModelPreview::updateStatusMessages() if (total_tris[lod] > 0) { - mFMP->childSetText(lod_triangles_name[lod], llformat("%d", total_tris[lod])); - mFMP->childSetText(lod_vertices_name[lod], llformat("%d", total_verts[lod])); + getFMP()->childSetText(lod_triangles_name[lod], llformat("%d", total_tris[lod])); + getFMP()->childSetText(lod_vertices_name[lod], llformat("%d", total_verts[lod])); } else { @@ -3147,8 +3154,8 @@ void LLModelPreview::updateStatusMessages() } } - mFMP->childSetText(lod_triangles_name[lod], mesh_status_na); - mFMP->childSetText(lod_vertices_name[lod], mesh_status_na); + getFMP()->childSetText(lod_triangles_name[lod], mesh_status_na); + getFMP()->childSetText(lod_vertices_name[lod], mesh_status_na); } const U32 lod_high = LLModel::LOD_HIGH; @@ -3183,7 +3190,7 @@ void LLModelPreview::updateStatusMessages() } } - LLIconCtrl* icon = mFMP->getChild(lod_icon_name[lod]); + LLIconCtrl* icon = getFMP()->getChild(lod_icon_name[lod]); LLUIImagePtr img = LLUI::getUIImage(lod_status_image[upload_status[lod]]); icon->setVisible(true); icon->setImage(img); @@ -3195,8 +3202,8 @@ void LLModelPreview::updateStatusMessages() if (lod == mPreviewLOD) { - mFMP->childSetText("lod_status_message_text", mFMP->getString(message)); - icon = mFMP->getChild("lod_status_message_icon"); + getFMP()->childSetText("lod_status_message_text", getFMP()->getString(message)); + icon = getFMP()->getChild("lod_status_message_icon"); icon->setImage(img); } } @@ -3205,18 +3212,18 @@ void LLModelPreview::updateStatusMessages() if ( upload_ok && !errorStateFromLoader ) { - mFMP->childEnable("ok_btn"); + getFMP()->childEnable("ok_btn"); } else { - mFMP->childDisable("ok_btn"); + getFMP()->childDisable("ok_btn"); } //add up physics triangles etc S32 start = 0; S32 end = mModel[LLModel::LOD_PHYSICS].size(); - S32 idx = mFMP->childGetValue("physics_layer").asInteger(); + S32 idx = getFMP()->childGetValue("physics_layer").asInteger(); if (idx >= 0 && idx < mModel[LLModel::LOD_PHYSICS].size()) { @@ -3255,22 +3262,22 @@ void LLModelPreview::updateStatusMessages() if (phys_tris > 0) { - mFMP->childSetTextArg("physics_triangles", "[TRIANGLES]", llformat("%d", phys_tris)); + getFMP()->childSetTextArg("physics_triangles", "[TRIANGLES]", llformat("%d", phys_tris)); } else { - mFMP->childSetTextArg("physics_triangles", "[TRIANGLES]", mesh_status_na); + getFMP()->childSetTextArg("physics_triangles", "[TRIANGLES]", mesh_status_na); } if (phys_hulls > 0) { - mFMP->childSetTextArg("physics_hulls", "[HULLS]", llformat("%d", phys_hulls)); - mFMP->childSetTextArg("physics_points", "[POINTS]", llformat("%d", phys_points)); + getFMP()->childSetTextArg("physics_hulls", "[HULLS]", llformat("%d", phys_hulls)); + getFMP()->childSetTextArg("physics_points", "[POINTS]", llformat("%d", phys_points)); } else { - mFMP->childSetTextArg("physics_hulls", "[HULLS]", mesh_status_na); - mFMP->childSetTextArg("physics_points", "[POINTS]", mesh_status_na); + getFMP()->childSetTextArg("physics_hulls", "[HULLS]", mesh_status_na); + getFMP()->childSetTextArg("physics_points", "[POINTS]", mesh_status_na); } LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; @@ -3315,43 +3322,43 @@ void LLModelPreview::updateStatusMessages() const U32 num_file_controls = sizeof(file_controls)/sizeof(char*); //enable/disable controls based on radio groups - if (mFMP->childGetValue("lod_from_file").asBoolean()) + if (getFMP()->childGetValue("lod_from_file").asBoolean()) { for (U32 i = 0; i < num_file_controls; ++i) { - mFMP->childEnable(file_controls[i]); + getFMP()->childEnable(file_controls[i]); } for (U32 i = 0; i < num_lod_controls; ++i) { - mFMP->childDisable(lod_controls[i]); + getFMP()->childDisable(lod_controls[i]); } } - else if (mFMP->childGetValue("lod_auto_generate").asBoolean()) + else if (getFMP()->childGetValue("lod_auto_generate").asBoolean()) { for (U32 i = 0; i < num_file_controls; ++i) { - mFMP->childDisable(file_controls[i]); + getFMP()->childDisable(file_controls[i]); } for (U32 i = 0; i < num_lod_controls; ++i) { - mFMP->childEnable(lod_controls[i]); + getFMP()->childEnable(lod_controls[i]); } //if (threshold) { U32 lod_mode = 0; - LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode"); + LLCtrlSelectionInterface* iface = getFMP()->childGetSelectionInterface("lod_mode"); if (iface) { lod_mode = iface->getFirstSelectedIndex(); } - LLSpinCtrl* threshold = mFMP->getChild("lod_error_threshold"); - LLSpinCtrl* limit = mFMP->getChild("lod_triangle_limit"); + LLSpinCtrl* threshold = getFMP()->getChild("lod_error_threshold"); + LLSpinCtrl* limit = getFMP()->getChild("lod_triangle_limit"); limit->setMaxValue(mMaxTriangleLimit); limit->setValue(total_tris[mPreviewLOD]); @@ -3374,12 +3381,12 @@ void LLModelPreview::updateStatusMessages() { // "None" is chosen for (U32 i = 0; i < num_file_controls; ++i) { - mFMP->childDisable(file_controls[i]); + getFMP()->childDisable(file_controls[i]); } for (U32 i = 0; i < num_lod_controls; ++i) { - mFMP->childDisable(lod_controls[i]); + getFMP()->childDisable(lod_controls[i]); } if (!mModel[mPreviewLOD].empty()) @@ -3394,17 +3401,17 @@ void LLModelPreview::updateStatusMessages() } } - if (mFMP->childGetValue("physics_load_from_file").asBoolean()) + if (getFMP()->childGetValue("physics_load_from_file").asBoolean()) { - mFMP->childDisable("physics_lod_combo"); - mFMP->childEnable("physics_file"); - mFMP->childEnable("physics_browse"); + getFMP()->childDisable("physics_lod_combo"); + getFMP()->childEnable("physics_file"); + getFMP()->childEnable("physics_browse"); } else { - mFMP->childEnable("physics_lod_combo"); - mFMP->childDisable("physics_file"); - mFMP->childDisable("physics_browse"); + getFMP()->childEnable("physics_lod_combo"); + getFMP()->childDisable("physics_file"); + getFMP()->childDisable("physics_browse"); } } @@ -3576,6 +3583,8 @@ void LLModelPreview::update() //----------------------------------------------------------------------------- BOOL LLModelPreview::render() { + assert_main_thread(); + LLMutexLock lock(this); mNeedsUpdate = FALSE; @@ -3627,8 +3636,8 @@ BOOL LLModelPreview::render() } bool has_skin_weights = false; - bool upload_skin = mFMP->childGetValue("upload_skin").asBoolean(); - bool upload_joints = mFMP->childGetValue("upload_joints").asBoolean(); + bool upload_skin = getFMP()->childGetValue("upload_skin").asBoolean(); + bool upload_joints = getFMP()->childGetValue("upload_joints").asBoolean(); for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) { @@ -3650,11 +3659,11 @@ BOOL LLModelPreview::render() fmp->enableViewOption("show_skin_weight"); fmp->setViewOptionEnabled("show_joint_positions", skin_weight); } - mFMP->childEnable("upload_skin"); + getFMP()->childEnable("upload_skin"); } else { - mFMP->childDisable("upload_skin"); + getFMP()->childDisable("upload_skin"); if (fmp) { fmp->setViewOption("show_skin_weight", false); @@ -3666,23 +3675,23 @@ BOOL LLModelPreview::render() if (upload_skin && !has_skin_weights) { //can't upload skin weights if model has no skin weights - mFMP->childSetValue("upload_skin", false); + getFMP()->childSetValue("upload_skin", false); upload_skin = false; } if (!upload_skin && upload_joints) { //can't upload joints if not uploading skin weights - mFMP->childSetValue("upload_joints", false); + getFMP()->childSetValue("upload_joints", false); upload_joints = false; } - mFMP->childSetEnabled("upload_joints", upload_skin); + getFMP()->childSetEnabled("upload_joints", upload_skin); - F32 explode = mFMP->childGetValue("physics_explode").asReal(); + F32 explode = getFMP()->childGetValue("physics_explode").asReal(); glClear(GL_DEPTH_BUFFER_BIT); - LLRect preview_rect = mFMP->getChildView("preview_panel")->getRect(); + LLRect preview_rect = getFMP()->getChildView("preview_panel")->getRect(); F32 aspect = (F32) preview_rect.getWidth()/preview_rect.getHeight(); LLViewerCamera::getInstance()->setAspect(aspect); @@ -3736,7 +3745,7 @@ BOOL LLModelPreview::render() //genLODs(); } - S32 physics_idx = mFMP->childGetValue("physics_layer").asInteger(); + S32 physics_idx = getFMP()->childGetValue("physics_layer").asInteger(); if (!mModel[mPreviewLOD].empty()) { @@ -4116,10 +4125,10 @@ void LLModelPreview::setPreviewLOD(S32 lod) { mPreviewLOD = lod; - LLComboBox* combo_box = mFMP->getChild("preview_lod_combo"); + LLComboBox* combo_box = getFMP()->getChild("preview_lod_combo"); combo_box->setCurrentByIndex((NUM_LOD-1)-mPreviewLOD); // combo box list of lods is in reverse order - mFMP->childSetTextArg("lod_table_footer", "[DETAIL]", mFMP->getString(lod_name[mPreviewLOD])); - mFMP->childSetText("lod_file", mLODFile[mPreviewLOD]); + getFMP()->childSetTextArg("lod_table_footer", "[DETAIL]", getFMP()->getString(lod_name[mPreviewLOD])); + getFMP()->childSetText("lod_file", mLODFile[mPreviewLOD]); LLColor4 highlight_color = LLUIColorTable::instance().getColor("MeshImportTableHighlightColor"); LLColor4 normal_color = LLUIColorTable::instance().getColor("MeshImportTableNormalColor"); @@ -4128,10 +4137,10 @@ void LLModelPreview::setPreviewLOD(S32 lod) { const LLColor4& color = (i == lod) ? highlight_color : normal_color; - mFMP->childSetColor(lod_status_name[i], color); - mFMP->childSetColor(lod_label_name[i], color); - mFMP->childSetColor(lod_triangles_name[i], color); - mFMP->childSetColor(lod_vertices_name[i], color); + getFMP()->childSetColor(lod_status_name[i], color); + getFMP()->childSetColor(lod_label_name[i], color); + getFMP()->childSetColor(lod_triangles_name[i], color); + getFMP()->childSetColor(lod_vertices_name[i], color); } } refresh(); -- cgit v1.2.3 From 4bd6edc6b037195012583467a3e5e754f6a5af77 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Mon, 20 Dec 2010 17:11:34 -0500 Subject: SH-682 FIX, SH-594 FIX - removed mFMP wrapper, added thread checking. Moved onIdle functions to llcallbacklist. --- indra/newview/llfloatermodelpreview.cpp | 196 +++++++++++++++++--------------- 1 file changed, 103 insertions(+), 93 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 4d8e71918f..f9648b0e3b 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -94,8 +94,7 @@ #include "lltoggleablemenu.h" #include "llvfile.h" #include "llvfs.h" - - +#include "llcallbacklist.h" #include "glod/glod.h" @@ -1600,8 +1599,8 @@ void LLModelLoader::run() } processElement(scene); - - mPreview->loadModelCallback(mLod); + + doOnIdleOneTime(boost::bind(&LLModelPreview::loadModelCallback,mPreview,mLod)); } } @@ -2053,11 +2052,13 @@ LLModelPreview::~LLModelPreview() U32 LLModelPreview::calcResourceCost() { + assert_main_thread(); + rebuildUploadData(); if ( mModelLoader->getLoadState() != LLModelLoader::ERROR_PARSING ) { - getFMP()->childEnable("ok_btn"); + mFMP->childEnable("ok_btn"); } U32 cost = 0; @@ -2065,7 +2066,7 @@ U32 LLModelPreview::calcResourceCost() U32 num_points = 0; U32 num_hulls = 0; - F32 debug_scale = getFMP()->childGetValue("import_scale").asReal(); + F32 debug_scale = mFMP->childGetValue("import_scale").asReal(); F32 streaming_cost = 0.f; for (U32 i = 0; i < mUploadData.size(); ++i) @@ -2089,8 +2090,8 @@ U32 LLModelPreview::calcResourceCost() instance.mLOD[1], instance.mLOD[0], decomp, - getFMP()->childGetValue("upload_skin").asBoolean(), - getFMP()->childGetValue("upload_joints").asBoolean(), + mFMP->childGetValue("upload_skin").asBoolean(), + mFMP->childGetValue("upload_joints").asBoolean(), TRUE); cost += gMeshRepo.calcResourceCost(ret); @@ -2119,13 +2120,13 @@ U32 LLModelPreview::calcResourceCost() } } - //getFMP()->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[HULLS]", llformat("%d",num_hulls)); - //getFMP()->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[POINTS]", llformat("%d",num_points)); - getFMP()->childSetTextArg("streaming cost", "[COST]", llformat("%.3f", streaming_cost)); - F32 scale = getFMP()->childGetValue("import_scale").asReal()*2.f; - getFMP()->childSetTextArg("import_dimensions", "[X]", llformat("%.3f", mPreviewScale[0]*scale)); - getFMP()->childSetTextArg("import_dimensions", "[Y]", llformat("%.3f", mPreviewScale[1]*scale)); - getFMP()->childSetTextArg("import_dimensions", "[Z]", llformat("%.3f", mPreviewScale[2]*scale)); + //mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[HULLS]", llformat("%d",num_hulls)); + //mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[POINTS]", llformat("%d",num_points)); + mFMP->childSetTextArg("streaming cost", "[COST]", llformat("%.3f", streaming_cost)); + F32 scale = mFMP->childGetValue("import_scale").asReal()*2.f; + mFMP->childSetTextArg("import_dimensions", "[X]", llformat("%.3f", mPreviewScale[0]*scale)); + mFMP->childSetTextArg("import_dimensions", "[Y]", llformat("%.3f", mPreviewScale[1]*scale)); + mFMP->childSetTextArg("import_dimensions", "[Z]", llformat("%.3f", mPreviewScale[2]*scale)); updateStatusMessages(); @@ -2134,15 +2135,17 @@ U32 LLModelPreview::calcResourceCost() void LLModelPreview::rebuildUploadData() { + assert_main_thread(); + mUploadData.clear(); mTextureSet.clear(); //fill uploaddata instance vectors from scene data - std::string requested_name = getFMP()->getChild("description_form")->getValue().asString(); + std::string requested_name = mFMP->getChild("description_form")->getValue().asString(); - LLSpinCtrl* scale_spinner = getFMP()->getChild("import_scale"); + LLSpinCtrl* scale_spinner = mFMP->getChild("import_scale"); if (!scale_spinner) { @@ -2158,7 +2161,7 @@ void LLModelPreview::rebuildUploadData() if ( mBaseScene.size() > 0 ) { - getFMP()->childEnable("ok_btn"); + mFMP->childEnable("ok_btn"); } for (LLModelLoader::scene::iterator iter = mBaseScene.begin(); iter != mBaseScene.end(); ++iter) @@ -2226,7 +2229,7 @@ void LLModelPreview::rebuildUploadData() } //refill "layer" combo in physics panel - LLComboBox* combo_box = getFMP()->getChild("physics_layer"); + LLComboBox* combo_box = mFMP->getChild("physics_layer"); if (combo_box) { S32 current = combo_box->getCurrentIndex(); @@ -2256,6 +2259,8 @@ void LLModelPreview::clearModel(S32 lod) void LLModelPreview::loadModel(std::string filename, S32 lod) { + assert_main_thread(); + LLMutexLock lock(this); if (mModelLoader) @@ -2270,7 +2275,7 @@ void LLModelPreview::loadModel(std::string filename, S32 lod) { // this is the initial file picking. Close the whole floater // if we don't have a base model to show for high LOD. - getFMP()->closeFloater(false); + mFMP->closeFloater(false); } mLoading = false; @@ -2288,35 +2293,37 @@ void LLModelPreview::loadModel(std::string filename, S32 lod) mModelLoader->start(); - getFMP()->childSetTextArg("status", "[STATUS]", getFMP()->getString("status_reading_file")); + mFMP->childSetTextArg("status", "[STATUS]", mFMP->getString("status_reading_file")); setPreviewLOD(lod); if ( mModelLoader->getLoadState() == LLModelLoader::ERROR_PARSING ) { - getFMP()->childDisable("ok_btn"); + mFMP->childDisable("ok_btn"); } if (lod == mPreviewLOD) { - getFMP()->childSetText("lod_file", mLODFile[mPreviewLOD]); + mFMP->childSetText("lod_file", mLODFile[mPreviewLOD]); } else if (lod == LLModel::LOD_PHYSICS) { - getFMP()->childSetText("physics_file", mLODFile[lod]); + mFMP->childSetText("physics_file", mLODFile[lod]); } - getFMP()->openFloater(); + mFMP->openFloater(); } void LLModelPreview::setPhysicsFromLOD(S32 lod) { + assert_main_thread(); + if (lod >= 0 && lod <= 3) { mModel[LLModel::LOD_PHYSICS] = mModel[lod]; mScene[LLModel::LOD_PHYSICS] = mScene[lod]; mLODFile[LLModel::LOD_PHYSICS].clear(); - getFMP()->childSetText("physics_file", mLODFile[LLModel::LOD_PHYSICS]); + mFMP->childSetText("physics_file", mLODFile[LLModel::LOD_PHYSICS]); mVertexBuffer[LLModel::LOD_PHYSICS].clear(); rebuildUploadData(); refresh(); @@ -2365,15 +2372,10 @@ void LLModelPreview::clearGLODGroup() } } -LLFloater* LLModelPreview::getFMP() +void LLModelPreview::loadModelCallback(S32 lod) { - // Shouldn't be accessing this outside the main UI thread. assert_main_thread(); - return mFMP; -} -void LLModelPreview::loadModelCallback(S32 lod) -{ //NOT the main thread LLMutexLock lock(this); if (!mModelLoader) { @@ -2428,6 +2430,8 @@ void LLModelPreview::resetPreviewTarget() void LLModelPreview::generateNormals() { + assert_main_thread(); + S32 which_lod = mPreviewLOD; @@ -2437,7 +2441,7 @@ void LLModelPreview::generateNormals() return; } - F32 angle_cutoff = getFMP()->childGetValue("crease_angle").asReal(); + F32 angle_cutoff = mFMP->childGetValue("crease_angle").asReal(); angle_cutoff *= DEG_TO_RAD; @@ -2731,20 +2735,20 @@ void LLModelPreview::genLODs(S32 which_lod) U32 lod_mode = 0; - LLCtrlSelectionInterface* iface = getFMP()->childGetSelectionInterface("lod_mode"); + LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode"); if (iface) { lod_mode = iface->getFirstSelectedIndex(); } - F32 lod_error_threshold = getFMP()->childGetValue("lod_error_threshold").asReal(); + F32 lod_error_threshold = mFMP->childGetValue("lod_error_threshold").asReal(); if (lod_mode == 0) { lod_mode = GLOD_TRIANGLE_BUDGET; if (which_lod != -1) { - limit = getFMP()->childGetValue("lod_triangle_limit").asInteger(); + limit = mFMP->childGetValue("lod_triangle_limit").asInteger(); } } else @@ -2754,7 +2758,7 @@ void LLModelPreview::genLODs(S32 which_lod) U32 build_operator = 0; - iface = getFMP()->childGetSelectionInterface("build_operator"); + iface = mFMP->childGetSelectionInterface("build_operator"); if (iface) { build_operator = iface->getFirstSelectedIndex(); @@ -2770,7 +2774,7 @@ void LLModelPreview::genLODs(S32 which_lod) } U32 queue_mode=0; - iface = getFMP()->childGetSelectionInterface("queue_mode"); + iface = mFMP->childGetSelectionInterface("queue_mode"); if (iface) { queue_mode = iface->getFirstSelectedIndex(); @@ -2791,7 +2795,7 @@ void LLModelPreview::genLODs(S32 which_lod) U32 border_mode = 0; - iface = getFMP()->childGetSelectionInterface("border_mode"); + iface = mFMP->childGetSelectionInterface("border_mode"); if (iface) { border_mode = iface->getFirstSelectedIndex(); @@ -2825,7 +2829,7 @@ void LLModelPreview::genLODs(S32 which_lod) object_dirty = true; } - F32 share_tolerance = getFMP()->childGetValue("share_tolerance").asReal(); + F32 share_tolerance = mFMP->childGetValue("share_tolerance").asReal(); if (share_tolerance != mBuildShareTolerance) { mBuildShareTolerance = share_tolerance; @@ -3070,6 +3074,8 @@ void LLModelPreview::genLODs(S32 which_lod) void LLModelPreview::updateStatusMessages() { + assert_main_thread(); + //triangle/vertex/submesh count for each mesh asset for each lod std::vector tris[LLModel::NUM_LODS]; std::vector verts[LLModel::NUM_LODS]; @@ -3116,9 +3122,9 @@ void LLModelPreview::updateStatusMessages() } - getFMP()->childSetTextArg("submeshes_info", "[SUBMESHES]", llformat("%d", total_submeshes[LLModel::LOD_HIGH])); + mFMP->childSetTextArg("submeshes_info", "[SUBMESHES]", llformat("%d", total_submeshes[LLModel::LOD_HIGH])); - std::string mesh_status_na = getFMP()->getString("mesh_status_na"); + std::string mesh_status_na = mFMP->getString("mesh_status_na"); S32 upload_status[LLModel::LOD_HIGH+1]; @@ -3132,8 +3138,8 @@ void LLModelPreview::updateStatusMessages() if (total_tris[lod] > 0) { - getFMP()->childSetText(lod_triangles_name[lod], llformat("%d", total_tris[lod])); - getFMP()->childSetText(lod_vertices_name[lod], llformat("%d", total_verts[lod])); + mFMP->childSetText(lod_triangles_name[lod], llformat("%d", total_tris[lod])); + mFMP->childSetText(lod_vertices_name[lod], llformat("%d", total_verts[lod])); } else { @@ -3154,8 +3160,8 @@ void LLModelPreview::updateStatusMessages() } } - getFMP()->childSetText(lod_triangles_name[lod], mesh_status_na); - getFMP()->childSetText(lod_vertices_name[lod], mesh_status_na); + mFMP->childSetText(lod_triangles_name[lod], mesh_status_na); + mFMP->childSetText(lod_vertices_name[lod], mesh_status_na); } const U32 lod_high = LLModel::LOD_HIGH; @@ -3190,7 +3196,7 @@ void LLModelPreview::updateStatusMessages() } } - LLIconCtrl* icon = getFMP()->getChild(lod_icon_name[lod]); + LLIconCtrl* icon = mFMP->getChild(lod_icon_name[lod]); LLUIImagePtr img = LLUI::getUIImage(lod_status_image[upload_status[lod]]); icon->setVisible(true); icon->setImage(img); @@ -3202,8 +3208,8 @@ void LLModelPreview::updateStatusMessages() if (lod == mPreviewLOD) { - getFMP()->childSetText("lod_status_message_text", getFMP()->getString(message)); - icon = getFMP()->getChild("lod_status_message_icon"); + mFMP->childSetText("lod_status_message_text", mFMP->getString(message)); + icon = mFMP->getChild("lod_status_message_icon"); icon->setImage(img); } } @@ -3212,18 +3218,18 @@ void LLModelPreview::updateStatusMessages() if ( upload_ok && !errorStateFromLoader ) { - getFMP()->childEnable("ok_btn"); + mFMP->childEnable("ok_btn"); } else { - getFMP()->childDisable("ok_btn"); + mFMP->childDisable("ok_btn"); } //add up physics triangles etc S32 start = 0; S32 end = mModel[LLModel::LOD_PHYSICS].size(); - S32 idx = getFMP()->childGetValue("physics_layer").asInteger(); + S32 idx = mFMP->childGetValue("physics_layer").asInteger(); if (idx >= 0 && idx < mModel[LLModel::LOD_PHYSICS].size()) { @@ -3262,22 +3268,22 @@ void LLModelPreview::updateStatusMessages() if (phys_tris > 0) { - getFMP()->childSetTextArg("physics_triangles", "[TRIANGLES]", llformat("%d", phys_tris)); + mFMP->childSetTextArg("physics_triangles", "[TRIANGLES]", llformat("%d", phys_tris)); } else { - getFMP()->childSetTextArg("physics_triangles", "[TRIANGLES]", mesh_status_na); + mFMP->childSetTextArg("physics_triangles", "[TRIANGLES]", mesh_status_na); } if (phys_hulls > 0) { - getFMP()->childSetTextArg("physics_hulls", "[HULLS]", llformat("%d", phys_hulls)); - getFMP()->childSetTextArg("physics_points", "[POINTS]", llformat("%d", phys_points)); + mFMP->childSetTextArg("physics_hulls", "[HULLS]", llformat("%d", phys_hulls)); + mFMP->childSetTextArg("physics_points", "[POINTS]", llformat("%d", phys_points)); } else { - getFMP()->childSetTextArg("physics_hulls", "[HULLS]", mesh_status_na); - getFMP()->childSetTextArg("physics_points", "[POINTS]", mesh_status_na); + mFMP->childSetTextArg("physics_hulls", "[HULLS]", mesh_status_na); + mFMP->childSetTextArg("physics_points", "[POINTS]", mesh_status_na); } LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; @@ -3322,43 +3328,43 @@ void LLModelPreview::updateStatusMessages() const U32 num_file_controls = sizeof(file_controls)/sizeof(char*); //enable/disable controls based on radio groups - if (getFMP()->childGetValue("lod_from_file").asBoolean()) + if (mFMP->childGetValue("lod_from_file").asBoolean()) { for (U32 i = 0; i < num_file_controls; ++i) { - getFMP()->childEnable(file_controls[i]); + mFMP->childEnable(file_controls[i]); } for (U32 i = 0; i < num_lod_controls; ++i) { - getFMP()->childDisable(lod_controls[i]); + mFMP->childDisable(lod_controls[i]); } } - else if (getFMP()->childGetValue("lod_auto_generate").asBoolean()) + else if (mFMP->childGetValue("lod_auto_generate").asBoolean()) { for (U32 i = 0; i < num_file_controls; ++i) { - getFMP()->childDisable(file_controls[i]); + mFMP->childDisable(file_controls[i]); } for (U32 i = 0; i < num_lod_controls; ++i) { - getFMP()->childEnable(lod_controls[i]); + mFMP->childEnable(lod_controls[i]); } //if (threshold) { U32 lod_mode = 0; - LLCtrlSelectionInterface* iface = getFMP()->childGetSelectionInterface("lod_mode"); + LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode"); if (iface) { lod_mode = iface->getFirstSelectedIndex(); } - LLSpinCtrl* threshold = getFMP()->getChild("lod_error_threshold"); - LLSpinCtrl* limit = getFMP()->getChild("lod_triangle_limit"); + LLSpinCtrl* threshold = mFMP->getChild("lod_error_threshold"); + LLSpinCtrl* limit = mFMP->getChild("lod_triangle_limit"); limit->setMaxValue(mMaxTriangleLimit); limit->setValue(total_tris[mPreviewLOD]); @@ -3381,12 +3387,12 @@ void LLModelPreview::updateStatusMessages() { // "None" is chosen for (U32 i = 0; i < num_file_controls; ++i) { - getFMP()->childDisable(file_controls[i]); + mFMP->childDisable(file_controls[i]); } for (U32 i = 0; i < num_lod_controls; ++i) { - getFMP()->childDisable(lod_controls[i]); + mFMP->childDisable(lod_controls[i]); } if (!mModel[mPreviewLOD].empty()) @@ -3401,17 +3407,17 @@ void LLModelPreview::updateStatusMessages() } } - if (getFMP()->childGetValue("physics_load_from_file").asBoolean()) + if (mFMP->childGetValue("physics_load_from_file").asBoolean()) { - getFMP()->childDisable("physics_lod_combo"); - getFMP()->childEnable("physics_file"); - getFMP()->childEnable("physics_browse"); + mFMP->childDisable("physics_lod_combo"); + mFMP->childEnable("physics_file"); + mFMP->childEnable("physics_browse"); } else { - getFMP()->childEnable("physics_lod_combo"); - getFMP()->childDisable("physics_file"); - getFMP()->childDisable("physics_browse"); + mFMP->childEnable("physics_lod_combo"); + mFMP->childDisable("physics_file"); + mFMP->childDisable("physics_browse"); } } @@ -3636,8 +3642,8 @@ BOOL LLModelPreview::render() } bool has_skin_weights = false; - bool upload_skin = getFMP()->childGetValue("upload_skin").asBoolean(); - bool upload_joints = getFMP()->childGetValue("upload_joints").asBoolean(); + bool upload_skin = mFMP->childGetValue("upload_skin").asBoolean(); + bool upload_joints = mFMP->childGetValue("upload_joints").asBoolean(); for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) { @@ -3659,11 +3665,11 @@ BOOL LLModelPreview::render() fmp->enableViewOption("show_skin_weight"); fmp->setViewOptionEnabled("show_joint_positions", skin_weight); } - getFMP()->childEnable("upload_skin"); + mFMP->childEnable("upload_skin"); } else { - getFMP()->childDisable("upload_skin"); + mFMP->childDisable("upload_skin"); if (fmp) { fmp->setViewOption("show_skin_weight", false); @@ -3675,23 +3681,23 @@ BOOL LLModelPreview::render() if (upload_skin && !has_skin_weights) { //can't upload skin weights if model has no skin weights - getFMP()->childSetValue("upload_skin", false); + mFMP->childSetValue("upload_skin", false); upload_skin = false; } if (!upload_skin && upload_joints) { //can't upload joints if not uploading skin weights - getFMP()->childSetValue("upload_joints", false); + mFMP->childSetValue("upload_joints", false); upload_joints = false; } - getFMP()->childSetEnabled("upload_joints", upload_skin); + mFMP->childSetEnabled("upload_joints", upload_skin); - F32 explode = getFMP()->childGetValue("physics_explode").asReal(); + F32 explode = mFMP->childGetValue("physics_explode").asReal(); glClear(GL_DEPTH_BUFFER_BIT); - LLRect preview_rect = getFMP()->getChildView("preview_panel")->getRect(); + LLRect preview_rect = mFMP->getChildView("preview_panel")->getRect(); F32 aspect = (F32) preview_rect.getWidth()/preview_rect.getHeight(); LLViewerCamera::getInstance()->setAspect(aspect); @@ -3745,7 +3751,7 @@ BOOL LLModelPreview::render() //genLODs(); } - S32 physics_idx = getFMP()->childGetValue("physics_layer").asInteger(); + S32 physics_idx = mFMP->childGetValue("physics_layer").asInteger(); if (!mModel[mPreviewLOD].empty()) { @@ -4125,10 +4131,10 @@ void LLModelPreview::setPreviewLOD(S32 lod) { mPreviewLOD = lod; - LLComboBox* combo_box = getFMP()->getChild("preview_lod_combo"); + LLComboBox* combo_box = mFMP->getChild("preview_lod_combo"); combo_box->setCurrentByIndex((NUM_LOD-1)-mPreviewLOD); // combo box list of lods is in reverse order - getFMP()->childSetTextArg("lod_table_footer", "[DETAIL]", getFMP()->getString(lod_name[mPreviewLOD])); - getFMP()->childSetText("lod_file", mLODFile[mPreviewLOD]); + mFMP->childSetTextArg("lod_table_footer", "[DETAIL]", mFMP->getString(lod_name[mPreviewLOD])); + mFMP->childSetText("lod_file", mLODFile[mPreviewLOD]); LLColor4 highlight_color = LLUIColorTable::instance().getColor("MeshImportTableHighlightColor"); LLColor4 normal_color = LLUIColorTable::instance().getColor("MeshImportTableNormalColor"); @@ -4137,10 +4143,10 @@ void LLModelPreview::setPreviewLOD(S32 lod) { const LLColor4& color = (i == lod) ? highlight_color : normal_color; - getFMP()->childSetColor(lod_status_name[i], color); - getFMP()->childSetColor(lod_label_name[i], color); - getFMP()->childSetColor(lod_triangles_name[i], color); - getFMP()->childSetColor(lod_vertices_name[i], color); + mFMP->childSetColor(lod_status_name[i], color); + mFMP->childSetColor(lod_label_name[i], color); + mFMP->childSetColor(lod_triangles_name[i], color); + mFMP->childSetColor(lod_vertices_name[i], color); } } refresh(); @@ -4150,6 +4156,8 @@ void LLModelPreview::setPreviewLOD(S32 lod) //static void LLFloaterModelPreview::onBrowseLOD(void* data) { + assert_main_thread(); + LLFloaterModelPreview* mp = (LLFloaterModelPreview*) data; mp->loadModel(mp->mModelPreview->mPreviewLOD); } @@ -4157,6 +4165,8 @@ void LLFloaterModelPreview::onBrowseLOD(void* data) //static void LLFloaterModelPreview::onUpload(void* user_data) { + assert_main_thread(); + LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; mp->mModelPreview->rebuildUploadData(); -- cgit v1.2.3 From e7f3f3bdbbec310030209e09d389cd434adb7991 Mon Sep 17 00:00:00 2001 From: leyla_linden Date: Mon, 20 Dec 2010 17:32:05 -0800 Subject: model upload wizard - added optimization and state changes --- indra/newview/llfloatermodelpreview.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index f9648b0e3b..85d0ae02cf 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -107,7 +107,6 @@ const S32 PREVIEW_RESIZE_HANDLE_SIZE = S32(RESIZE_HANDLE_WIDTH * OO_SQRT2) + PRE const S32 PREVIEW_HPAD = PREVIEW_RESIZE_HANDLE_SIZE; const S32 PREF_BUTTON_HEIGHT = 16 + 7 + 16; const S32 PREVIEW_TEXTURE_HEIGHT = 300; -const S32 NUM_LOD = 4; void drawBoxOutline(const LLVector3& pos, const LLVector3& size); @@ -476,12 +475,10 @@ void LLFloaterModelPreview::onPreviewLODCommit(LLUICtrl* ctrl, void* userdata) S32 which_mode = 0; - LLCtrlSelectionInterface* iface = fp->childGetSelectionInterface("preview_lod_combo"); - if (iface) - { - which_mode = iface->getFirstSelectedIndex(); - } - which_mode = (NUM_LOD-1)-which_mode; // combo box list of lods is in reverse order + LLComboBox* combo = (LLComboBox*) ctrl; + + which_mode = (NUM_LOD-1)-combo->getFirstSelectedIndex(); // combo box list of lods is in reverse order + fp->mModelPreview->setPreviewLOD(which_mode); } @@ -2699,7 +2696,7 @@ bool LLModelPreview::containsRiggedAsset( void ) } return false; } -void LLModelPreview::genLODs(S32 which_lod) +void LLModelPreview::genLODs(S32 which_lod, U32 decimation) { if (mBaseModel.empty()) { @@ -2916,7 +2913,7 @@ void LLModelPreview::genLODs(S32 which_lod) { if (lod < start) { - triangle_count /= 3; + triangle_count /= decimation; } } else -- cgit v1.2.3 From 6175e8147ff85073c67de89f08e5ecea891e1ef8 Mon Sep 17 00:00:00 2001 From: leyla_linden Date: Tue, 21 Dec 2010 17:01:03 -0800 Subject: fixed wizard model not previewing issues and added pan/zoom --- indra/newview/llfloatermodelpreview.cpp | 50 +++++++++++++++++---------------- 1 file changed, 26 insertions(+), 24 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 85d0ae02cf..0dc021c44b 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -3339,13 +3339,38 @@ void LLModelPreview::updateStatusMessages() } - else if (mFMP->childGetValue("lod_auto_generate").asBoolean()) + else if (mFMP->childGetValue("lod_none").asBoolean()) { for (U32 i = 0; i < num_file_controls; ++i) { mFMP->childDisable(file_controls[i]); } + for (U32 i = 0; i < num_lod_controls; ++i) + { + mFMP->childDisable(lod_controls[i]); + } + + if (!mModel[mPreviewLOD].empty()) + { + mModel[mPreviewLOD].clear(); + mScene[mPreviewLOD].clear(); + mVertexBuffer[mPreviewLOD].clear(); + + //this can cause phasing issues with the UI, so reenter this function and return + updateStatusMessages(); + return; + } + + + } + else + { // auto generate, also the default case for wizard which has no radio selection + for (U32 i = 0; i < num_file_controls; ++i) + { + mFMP->childDisable(file_controls[i]); + } + for (U32 i = 0; i < num_lod_controls; ++i) { mFMP->childEnable(lod_controls[i]); @@ -3380,29 +3405,6 @@ void LLModelPreview::updateStatusMessages() } } } - else - { // "None" is chosen - for (U32 i = 0; i < num_file_controls; ++i) - { - mFMP->childDisable(file_controls[i]); - } - - for (U32 i = 0; i < num_lod_controls; ++i) - { - mFMP->childDisable(lod_controls[i]); - } - - if (!mModel[mPreviewLOD].empty()) - { - mModel[mPreviewLOD].clear(); - mScene[mPreviewLOD].clear(); - mVertexBuffer[mPreviewLOD].clear(); - - //this can cause phasing issues with the UI, so reenter this function and return - updateStatusMessages(); - return; - } - } if (mFMP->childGetValue("physics_load_from_file").asBoolean()) { -- cgit v1.2.3 From e1b1db9575945fa8436b4ebabf55242635b61f38 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 22 Dec 2010 01:05:35 -0600 Subject: SH-636 Update physics tab to new spec, move "completed" physics decomp callbacks to main thread, add object model to decomposition tool, make imported model scales non-uniform. --- indra/newview/llfloatermodelpreview.cpp | 219 +++++++++++++------------------- 1 file changed, 88 insertions(+), 131 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 660157df1e..87ada50e9a 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -258,6 +258,7 @@ LLFloater(key) mLastMouseX = 0; mLastMouseY = 0; mGLName = 0; + mStatusLock = new LLMutex(NULL); } //----------------------------------------------------------------------------- @@ -304,6 +305,8 @@ BOOL LLFloaterModelPreview::postBuild() childSetCommitCallback("lod_file_or_limit", refresh, this); childSetCommitCallback("physics_load_radio", refresh, this); + //childSetCommitCallback("physics_optimize", refresh, this); + //childSetCommitCallback("physics_use_hull", refresh, this); childDisable("upload_skin"); childDisable("upload_joints"); @@ -378,6 +381,9 @@ LLFloaterModelPreview::~LLFloaterModelPreview() { LLImageGL::deleteTextures(1, &mGLName ); } + + delete mStatusLock; + mStatusLock = NULL; } void LLFloaterModelPreview::onViewOptionChecked(const LLSD& userdata) @@ -538,9 +544,10 @@ void LLFloaterModelPreview::draw() childSetTextArg("prim_cost", "[PRIM_COST]", llformat("%d", mModelPreview->mResourceCost)); childSetTextArg("description_label", "[TEXTURES]", llformat("%d", mModelPreview->mTextureSet.size())); - if (mCurRequest.notNull()) + if (!mCurRequest.empty()) { - childSetTextArg("status", "[STATUS]", mCurRequest->mStatusMessage); + LLMutexLock lock(mStatusLock); + childSetTextArg("status", "[STATUS]", mStatusMessage); } U32 resource_cost = mModelPreview->mResourceCost*10; @@ -696,7 +703,22 @@ void LLFloaterModelPreview::onPhysicsParamCommit(LLUICtrl* ctrl, void* data) if (sInstance) { LLCDParam* param = (LLCDParam*) data; - sInstance->mDecompParams[param->mName] = ctrl->getValue(); + std::string name(param->mName); + sInstance->mDecompParams[name] = ctrl->getValue(); + + if (name == "Simplify Method") + { + if (ctrl->getValue().asInteger() == 0) + { + sInstance->childSetVisible("Retain%", true); + sInstance->childSetVisible("Detail Scale", false); + } + else + { + sInstance->childSetVisible("Retain%", false); + sInstance->childSetVisible("Detail Scale", true); + } + } } } @@ -705,11 +727,9 @@ void LLFloaterModelPreview::onPhysicsStageExecute(LLUICtrl* ctrl, void* data) { LLCDStageData* stage = (LLCDStageData*) data; - LLModel* mdl = NULL; - if (sInstance) { - if (sInstance->mCurRequest.notNull()) + if (!sInstance->mCurRequest.empty()) { llinfos << "Decomposition request still pending." << llendl; return; @@ -717,36 +737,15 @@ void LLFloaterModelPreview::onPhysicsStageExecute(LLUICtrl* ctrl, void* data) if (sInstance->mModelPreview) { - S32 idx = sInstance->childGetValue("physics_layer").asInteger(); - if (idx >= 0 && idx < sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS].size()) + for (S32 i = 0; i < sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS].size(); ++i) { - mdl = sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS][idx]; + LLModel* mdl = sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS][i]; + DecompRequest* request = new DecompRequest(stage->mName, mdl); + sInstance->mCurRequest.insert(request); + gMeshRepo.mDecompThread->submitRequest(request); } } } - - if (mdl) - { - sInstance->mCurRequest = new DecompRequest(stage->mName, mdl); - gMeshRepo.mDecompThread->submitRequest(sInstance->mCurRequest); - } - - const std::string decompose("Decompose"); - - if (decompose == stage->mName) - { //hide decompose panel and show simplify panel - sInstance->childSetVisible("physics step 2", false); - sInstance->childSetVisible("physics step 3", true); - } -} - -//static -void LLFloaterModelPreview::onPhysicsOptimize(LLUICtrl* ctrl, void *data) -{ - //hide step 1 panel and show step 2 panel + info - sInstance->childSetVisible("physics step 1", false); - sInstance->childSetVisible("physics step 2", true); - sInstance->childSetVisible("physics info", true); } //static @@ -768,29 +767,16 @@ void LLFloaterModelPreview::onPhysicsUseLOD(LLUICtrl* ctrl, void* userdata) sInstance->mModelPreview->setPhysicsFromLOD(which_mode); } -//static -void LLFloaterModelPreview::onPhysicsDecomposeBack(LLUICtrl* ctrl, void* userdata) -{ - //hide step 2 panel and info and show step 1 panel - sInstance->childSetVisible("physics step 1", true); - sInstance->childSetVisible("physics step 2", false); - sInstance->childSetVisible("physics info", false); -} - -//static -void LLFloaterModelPreview::onPhysicsSimplifyBack(LLUICtrl* ctrl, void* userdata) -{ - //hide step 3 panel and show step 2 panel - sInstance->childSetVisible("physics step 3", false); - sInstance->childSetVisible("physics step 2", true); -} - //static void LLFloaterModelPreview::onPhysicsStageCancel(LLUICtrl* ctrl, void*data) { - if (sInstance && sInstance->mCurRequest.notNull()) + if (sInstance) { - sInstance->mCurRequest->mContinue = 0; + for (std::set >::iterator iter = sInstance->mCurRequest.begin(); + iter != sInstance->mCurRequest.end(); ++iter) + { + (*iter)->mContinue = 0; + } } } @@ -801,10 +787,6 @@ void LLFloaterModelPreview::initDecompControls() childSetCommitCallback("cancel_btn", onPhysicsStageCancel, NULL); childSetCommitCallback("physics_lod_combo", onPhysicsUseLOD, NULL); childSetCommitCallback("physics_browse", onPhysicsBrowse, NULL); - childSetCommitCallback("physics_optimize", onPhysicsOptimize, NULL); - childSetCommitCallback("decompose_back", onPhysicsDecomposeBack, NULL); - childSetCommitCallback("simplify_back", onPhysicsSimplifyBack, NULL); - childSetCommitCallback("physics_layer", refresh, NULL); static const LLCDStageData* stage = NULL; static S32 stage_count = 0; @@ -919,7 +901,6 @@ void LLFloaterModelPreview::initDecompControls() } } - childSetCommitCallback("physics_layer", LLFloaterModelPreview::refresh, LLFloaterModelPreview::sInstance); childSetCommitCallback("physics_explode", LLFloaterModelPreview::onExplodeCommit, this); } @@ -2225,20 +2206,6 @@ void LLModelPreview::rebuildUploadData() scale_spinner->setValue(max_import_scale); } - //refill "layer" combo in physics panel - LLComboBox* combo_box = mFMP->getChild("physics_layer"); - if (combo_box) - { - S32 current = combo_box->getCurrentIndex(); - combo_box->removeall(); - - for (S32 i = 0; i < mBaseModel.size(); ++i) - { - LLModel* mdl = mBaseModel[i]; - combo_box->add(mdl->mLabel, i); - } - combo_box->setCurrentByIndex(current); - } } @@ -3216,14 +3183,6 @@ void LLModelPreview::updateStatusMessages() S32 start = 0; S32 end = mModel[LLModel::LOD_PHYSICS].size(); - S32 idx = mFMP->childGetValue("physics_layer").asInteger(); - - if (idx >= 0 && idx < mModel[LLModel::LOD_PHYSICS].size()) - { - start = idx; - end = idx+1; - } - S32 phys_tris = 0; S32 phys_hulls = 0; S32 phys_points = 0; @@ -3289,6 +3248,32 @@ void LLModelPreview::updateStatusMessages() fmp->disableViewOption("show_physics"); fmp->setViewOption("show_physics", false); } + + //bool use_hull = fmp->childGetValue("physics_use_hull").asBoolean(); + + //fmp->childSetEnabled("physics_optimize", !use_hull); + + bool enable = phys_tris > 0 || phys_hulls > 0; + //enable = enable && !use_hull && fmp->childGetValue("physics_optimize").asBoolean(); + + //enable/disable "analysis" UI + LLPanel* panel = fmp->getChild("physics analysis"); + LLView* child = panel->getFirstChild(); + while (child) + { + child->setEnabled(enable); + child = panel->findNextSibling(child); + } + + enable = phys_hulls > 0; + //enable/disable "simplification" UI + panel = fmp->getChild("physics simplification"); + child = panel->getFirstChild(); + while (child) + { + child->setEnabled(enable); + child = panel->findNextSibling(child); + } } const char* lod_controls[] = @@ -3736,8 +3721,6 @@ BOOL LLModelPreview::render() //genLODs(); } - S32 physics_idx = mFMP->childGetValue("physics_layer").asInteger(); - if (!mModel[mPreviewLOD].empty()) { bool regen = mVertexBuffer[mPreviewLOD].empty(); @@ -3819,13 +3802,6 @@ BOOL LLModelPreview::render() LLGLEnable blend(GL_BLEND); gGL.blendFunc(LLRender::BF_ONE, LLRender::BF_ZERO); - LLModel* physics_model = NULL; - - if (physics_idx >= 0 && physics_idx < mModel[LLModel::LOD_PHYSICS].size() ) - { - physics_model = mModel[LLModel::LOD_PHYSICS][physics_idx]; - } - for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) { LLModelInstance& instance = *iter; @@ -3853,7 +3829,7 @@ BOOL LLModelPreview::render() std::map, std::vector > >::iterator iter = mPhysicsMesh.find(model); if (iter != mPhysicsMesh.end()) - { + { //render hull instead of mesh render_mesh = false; for (U32 i = 0; i < iter->second.size(); ++i) { @@ -3881,16 +3857,6 @@ BOOL LLModelPreview::render() glColor4ubv(hull_colors[i].mV); buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts()); - - if (edges) - { - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - glLineWidth(3.f); - glColor4ub(hull_colors[i].mV[0]/2, hull_colors[i].mV[1]/2, hull_colors[i].mV[2]/2, 255); - buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts()); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glLineWidth(1.f); - } } if (explode > 0.f) @@ -3913,40 +3879,19 @@ BOOL LLModelPreview::render() buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); - if (textures) - { - glColor4fv(instance.mMaterial[i].mDiffuseColor.mV); - if (i < instance.mMaterial.size() && instance.mMaterial[i].mDiffuseMap.notNull()) - { - gGL.getTexUnit(0)->bind(instance.mMaterial[i].mDiffuseMap, true); - if (instance.mMaterial[i].mDiffuseMap->getDiscardLevel() > -1) - { - mTextureSet.insert(instance.mMaterial[i].mDiffuseMap); - } - } - } - else - { - glColor4f(1,1,1,1); - } - buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - glColor3f(0.4f, 0.4f, 0.4f); - - if (edges || model == physics_model) - { - if (model == physics_model) - { - glColor3f(1.f, 1.f, 0.f); - } + glColor4f(0.4f, 0.4f, 0.0f, 0.4f); + + buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); - glLineWidth(3.f); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glLineWidth(1.f); - } + glColor3f(1.f, 1.f, 0.f); + + glLineWidth(3.f); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glLineWidth(1.f); } } @@ -4190,6 +4135,7 @@ LLFloaterModelPreview::DecompRequest::DecompRequest(const std::string& stage, LL mStage = stage; mContinue = 1; mModel = mdl; + mDecompID = &mdl->mDecompID; mParams = sInstance->mDecompParams; //copy out positions and indices @@ -4224,14 +4170,25 @@ LLFloaterModelPreview::DecompRequest::DecompRequest(const std::string& stage, LL } } +void LLFloaterModelPreview::setStatusMessage(const std::string& msg) +{ + LLMutexLock lock(mStatusLock); + mStatusMessage = msg; +} + S32 LLFloaterModelPreview::DecompRequest::statusCallback(const char* status, S32 p1, S32 p2) { setStatusMessage(llformat("%s: %d/%d", status, p1, p2)); + if (LLFloaterModelPreview::sInstance) + { + LLFloaterModelPreview::sInstance->setStatusMessage(mStatusMessage); + } + return mContinue; } void LLFloaterModelPreview::DecompRequest::completed() -{ +{ //called from the main thread mModel->setConvexHullDecomposition(mHull); if (sInstance) @@ -4243,6 +4200,6 @@ void LLFloaterModelPreview::DecompRequest::completed() LLFloaterModelPreview::sInstance->mModelPreview->refresh(); } - sInstance->mCurRequest = NULL; + sInstance->mCurRequest.erase(this); } } -- cgit v1.2.3 From 09ff90a1180cb6489c83ae1944129e6b61d9eed0 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 22 Dec 2010 03:15:56 -0600 Subject: Update llconvexdecomposition and fix gcc compiler error --- indra/newview/llfloatermodelpreview.cpp | 1279 ++++++++++++++++--------------- 1 file changed, 640 insertions(+), 639 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 1050e86060..adf8302e9d 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llfloatermodelpreview.cpp * @brief LLFloaterModelPreview class implementation * * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -111,7 +111,7 @@ const S32 PREVIEW_TEXTURE_HEIGHT = 300; void drawBoxOutline(const LLVector3& pos, const LLVector3& size); -std::string lod_name[NUM_LOD+1] = +std::string lod_name[NUM_LOD+1] = { "lowest", "low", @@ -119,7 +119,7 @@ std::string lod_name[NUM_LOD+1] = "high", "I went off the end of the lod_name array. Me so smart." }; - + std::string lod_triangles_name[NUM_LOD+1] = { "lowest_triangles", @@ -147,7 +147,7 @@ std::string lod_status_name[NUM_LOD+1] = "I went off the end of the lod_status_name array. Me so smart." }; -std::string lod_icon_name[NUM_LOD+1] = +std::string lod_icon_name[NUM_LOD+1] = { "status_icon_lowest", "status_icon_low", @@ -156,7 +156,7 @@ std::string lod_icon_name[NUM_LOD+1] = "I went off the end of the lod_status_name array. Me so smart." }; -std::string lod_status_image[NUM_LOD+1] = +std::string lod_status_image[NUM_LOD+1] = { "ModelImport_Status_Good", "ModelImport_Status_Warning", @@ -184,7 +184,7 @@ bool validate_face(const LLVolumeFace& face) return false; } } - + return true; } @@ -195,7 +195,7 @@ bool validate_model(const LLModel* mdl) llwarns << "Model has no faces!" << llendl; return false; } - + for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) { if (mdl->getVolumeFace(i).mNumVertices == 0) @@ -203,36 +203,36 @@ bool validate_model(const LLModel* mdl) llwarns << "Face has no vertices." << llendl; return false; } - + if (mdl->getVolumeFace(i).mNumIndices == 0) { llwarns << "Face has no indices." << llendl; return false; } - + if (!validate_face(mdl->getVolumeFace(i))) { return false; } } - + return true; } BOOL stop_gloderror() { GLuint error = glodGetError(); - + if (error != GLOD_NO_ERROR) { llwarns << "GLOD error detected, cannot generate LOD: " << std::hex << error << llendl; return TRUE; } - + return FALSE; } - + LLMeshFilePicker::LLMeshFilePicker(LLModelPreview* mp, S32 lod) : LLFilePickerThread(LLFilePicker::FFLOAD_COLLADA) { @@ -249,7 +249,7 @@ void LLMeshFilePicker::notify(const std::string& filename) //----------------------------------------------------------------------------- // LLFloaterModelPreview() //----------------------------------------------------------------------------- -LLFloaterModelPreview::LLFloaterModelPreview(const LLSD& key) : +LLFloaterModelPreview::LLFloaterModelPreview(const LLSD& key) : LLFloater(key) { sInstance = this; @@ -268,14 +268,14 @@ BOOL LLFloaterModelPreview::postBuild() { return FALSE; } - + setViewOption("show_textures", true); - + childSetAction("lod_browse", onBrowseLOD, this); - + childSetCommitCallback("crease_angle", onGenerateNormalsCommit, this); childSetCommitCallback("generate_normals", onGenerateNormalsCommit, this); - + childSetCommitCallback("lod_generate", onAutoFillCommit, this); childSetCommitCallback("lod_mode", onLODParamCommit, this); @@ -285,51 +285,51 @@ BOOL LLFloaterModelPreview::postBuild() childSetCommitCallback("queue_mode", onLODParamCommit, this); childSetCommitCallback("border_mode", onLODParamCommit, this); childSetCommitCallback("share_tolerance", onLODParamCommit, this); - + childSetTextArg("status", "[STATUS]", getString("status_idle")); - + //childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d",sUploadAmount)); childSetAction("ok_btn", onUpload, this); childDisable("ok_btn"); - + childSetAction("clear_materials", onClearMaterials, this); - + childSetCommitCallback("preview_lod_combo", onPreviewLODCommit, this); - + childSetCommitCallback("upload_skin", onUploadSkinCommit, this); childSetCommitCallback("upload_joints", onUploadJointsCommit, this); - + childSetCommitCallback("import_scale", onImportScaleCommit, this); childSetCommitCallback("lod_file_or_limit", refresh, this); childSetCommitCallback("physics_load_radio", refresh, this); //childSetCommitCallback("physics_optimize", refresh, this); //childSetCommitCallback("physics_use_hull", refresh, this); - + childDisable("upload_skin"); childDisable("upload_joints"); - childDisable("ok_btn"); - + childDisable("ok_btn"); + mViewOptionMenuButton = getChild("options_gear_btn"); mCommitCallbackRegistrar.add("ModelImport.ViewOption.Action", boost::bind(&LLFloaterModelPreview::onViewOptionChecked, this, _2)); mEnableCallbackRegistrar.add("ModelImport.ViewOption.Check", boost::bind(&LLFloaterModelPreview::isViewOptionChecked, this, _2)); mEnableCallbackRegistrar.add("ModelImport.ViewOption.Enabled", boost::bind(&LLFloaterModelPreview::isViewOptionEnabled, this, _2)); - - + + mViewOptionMenu = LLUICtrlFactory::getInstance()->createFromFile("menu_model_import_gear_default.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); mViewOptionMenuButton->setMenu(mViewOptionMenu, LLMenuButton::MP_BOTTOM_LEFT); initDecompControls(); - + LLView* preview_panel = getChild("preview_panel"); mPreviewRect = preview_panel->getRect(); - + mModelPreview = new LLModelPreview(512, 512, this); mModelPreview->setPreviewTarget(16.f); - + //set callbacks for left click on line editor rows for (U32 i = 0; i <= LLModel::LOD_HIGH; i++) { @@ -357,7 +357,7 @@ BOOL LLFloaterModelPreview::postBuild() text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i)); } } - + return TRUE; } @@ -367,14 +367,14 @@ BOOL LLFloaterModelPreview::postBuild() LLFloaterModelPreview::~LLFloaterModelPreview() { sInstance = NULL; - + if ( mModelPreview->containsRiggedAsset() ) { gAgentAvatarp->resetJointPositions(); } - + delete mModelPreview; - + if (mGLName) { LLImageGL::deleteTextures(1, &mGLName ); @@ -423,47 +423,47 @@ void LLFloaterModelPreview::setViewOption(const std::string& option, bool value) void LLFloaterModelPreview::loadModel(S32 lod) { mModelPreview->mLoading = true; - + (new LLMeshFilePicker(mModelPreview, lod))->getFile(); } -//static +//static void LLFloaterModelPreview::onImportScaleCommit(LLUICtrl*,void* userdata) { LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; - + if (!fp->mModelPreview) { return; } - + fp->mModelPreview->calcResourceCost(); fp->mModelPreview->refresh(); } -//static +//static void LLFloaterModelPreview::onUploadJointsCommit(LLUICtrl*,void* userdata) { LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; - + if (!fp->mModelPreview) { return; } - + fp->mModelPreview->refresh(); } -//static +//static void LLFloaterModelPreview::onUploadSkinCommit(LLUICtrl*,void* userdata) { LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; - + if (!fp->mModelPreview) { return; } - + fp->mModelPreview->refresh(); fp->mModelPreview->resetPreviewTarget(); fp->mModelPreview->clearBuffers(); @@ -473,16 +473,16 @@ void LLFloaterModelPreview::onUploadSkinCommit(LLUICtrl*,void* userdata) void LLFloaterModelPreview::onPreviewLODCommit(LLUICtrl* ctrl, void* userdata) { LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; - + if (!fp->mModelPreview) { return; } - + S32 which_mode = 0; - + LLComboBox* combo = (LLComboBox*) ctrl; - + which_mode = (NUM_LOD-1)-combo->getFirstSelectedIndex(); // combo box list of lods is in reverse order fp->mModelPreview->setPreviewLOD(which_mode); @@ -492,7 +492,7 @@ void LLFloaterModelPreview::onPreviewLODCommit(LLUICtrl* ctrl, void* userdata) void LLFloaterModelPreview::onGenerateNormalsCommit(LLUICtrl* ctrl, void* userdata) { LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; - + fp->mModelPreview->generateNormals(); } @@ -500,19 +500,19 @@ void LLFloaterModelPreview::onGenerateNormalsCommit(LLUICtrl* ctrl, void* userda void LLFloaterModelPreview::onExplodeCommit(LLUICtrl* ctrl, void* userdata) { LLFloaterModelPreview* fp = LLFloaterModelPreview::sInstance; - + fp->mModelPreview->refresh(); } -//static +//static void LLFloaterModelPreview::onAutoFillCommit(LLUICtrl* ctrl, void* userdata) { LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; - + fp->mModelPreview->genLODs(); } -//static +//static void LLFloaterModelPreview::onLODParamCommit(LLUICtrl* ctrl, void* userdata) { LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; @@ -529,38 +529,38 @@ void LLFloaterModelPreview::draw() { LLFloater::draw(); LLRect r = getRect(); - + mModelPreview->update(); - + if (!mModelPreview->mLoading) { childSetTextArg("status", "[STATUS]", getString("status_idle")); } - + childSetTextArg("prim_cost", "[PRIM_COST]", llformat("%d", mModelPreview->mResourceCost)); childSetTextArg("description_label", "[TEXTURES]", llformat("%d", mModelPreview->mTextureSet.size())); - + if (!mCurRequest.empty()) { LLMutexLock lock(mStatusLock); childSetTextArg("status", "[STATUS]", mStatusMessage); } - + U32 resource_cost = mModelPreview->mResourceCost*10; - + if (childGetValue("upload_textures").asBoolean()) { resource_cost += mModelPreview->mTextureSet.size()*10; } - + childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d", resource_cost)); - + if (mModelPreview) { gGL.color3f(1.f, 1.f, 1.f); - + gGL.getTexUnit(0)->bind(mModelPreview); - + LLView* preview_panel = getChild("preview_panel"); @@ -570,7 +570,7 @@ void LLFloaterModelPreview::draw() mModelPreview->refresh(); mPreviewRect = preview_panel->getRect(); } - + gGL.begin( LLRender::QUADS ); { gGL.texCoord2f(0.f, 1.f); @@ -583,7 +583,7 @@ void LLFloaterModelPreview::draw() gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mTop); } gGL.end(); - + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); } } @@ -602,7 +602,7 @@ BOOL LLFloaterModelPreview::handleMouseDown(S32 x, S32 y, MASK mask) mLastMouseY = y; return TRUE; } - + return LLFloater::handleMouseDown(x, y, mask); } @@ -622,7 +622,7 @@ BOOL LLFloaterModelPreview::handleMouseUp(S32 x, S32 y, MASK mask) BOOL LLFloaterModelPreview::handleHover (S32 x, S32 y, MASK mask) { MASK local_mask = mask & ~MASK_ALT; - + if (mModelPreview && hasMouseCapture()) { if (local_mask == MASK_PAN) @@ -634,25 +634,25 @@ BOOL LLFloaterModelPreview::handleHover (S32 x, S32 y, MASK mask) { F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f; F32 pitch_radians = (F32)(y - mLastMouseY) * 0.02f; - + mModelPreview->rotate(yaw_radians, pitch_radians); } - else + else { - + F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f; F32 zoom_amt = (F32)(y - mLastMouseY) * 0.02f; - + mModelPreview->rotate(yaw_radians, 0.f); mModelPreview->zoom(zoom_amt); } - - + + mModelPreview->refresh(); - + LLUI::setMousePositionLocal(this, mLastMouseX, mLastMouseY); } - + if (!mPreviewRect.pointInRect(x, y) || !mModelPreview) { return LLFloater::handleHover(x, y, mask); @@ -669,7 +669,7 @@ BOOL LLFloaterModelPreview::handleHover (S32 x, S32 y, MASK mask) { gViewerWindow->setCursor(UI_CURSOR_TOOLZOOMIN); } - + return TRUE; } @@ -683,7 +683,7 @@ BOOL LLFloaterModelPreview::handleScrollWheel(S32 x, S32 y, S32 clicks) mModelPreview->zoom((F32)clicks * -0.2f); mModelPreview->refresh(); } - + return TRUE; } @@ -695,7 +695,7 @@ void LLFloaterModelPreview::onPhysicsParamCommit(LLUICtrl* ctrl, void* data) llinfos << "convex decomposition tool is a stub on this platform. cannot get decomp." << llendl; return; } - + if (sInstance) { LLCDParam* param = (LLCDParam*) data; @@ -722,7 +722,7 @@ void LLFloaterModelPreview::onPhysicsParamCommit(LLUICtrl* ctrl, void* data) void LLFloaterModelPreview::onPhysicsStageExecute(LLUICtrl* ctrl, void* data) { LLCDStageData* stage = (LLCDStageData*) data; - + if (sInstance) { if (!sInstance->mCurRequest.empty()) @@ -730,7 +730,7 @@ void LLFloaterModelPreview::onPhysicsStageExecute(LLUICtrl* ctrl, void* data) llinfos << "Decomposition request still pending." << llendl; return; } - + if (sInstance->mModelPreview) { for (S32 i = 0; i < sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS].size(); ++i) @@ -744,13 +744,13 @@ void LLFloaterModelPreview::onPhysicsStageExecute(LLUICtrl* ctrl, void* data) } } -//static +//static void LLFloaterModelPreview::onPhysicsBrowse(LLUICtrl* ctrl, void* userdata) { sInstance->loadModel(LLModel::LOD_PHYSICS); } -//static +//static void LLFloaterModelPreview::onPhysicsUseLOD(LLUICtrl* ctrl, void* userdata) { S32 which_mode = 3; @@ -759,10 +759,10 @@ void LLFloaterModelPreview::onPhysicsUseLOD(LLUICtrl* ctrl, void* userdata) { which_mode = iface->getFirstSelectedIndex(); } - + sInstance->mModelPreview->setPhysicsFromLOD(which_mode); } - + //static void LLFloaterModelPreview::onPhysicsStageCancel(LLUICtrl* ctrl, void*data) { @@ -771,68 +771,69 @@ void LLFloaterModelPreview::onPhysicsStageCancel(LLUICtrl* ctrl, void*data) for (std::set >::iterator iter = sInstance->mCurRequest.begin(); iter != sInstance->mCurRequest.end(); ++iter) { - (*iter)->mContinue = 0; + DecompRequest* req = *iter; + req->mContinue = 0; } } } - + void LLFloaterModelPreview::initDecompControls() { LLSD key; - + childSetCommitCallback("cancel_btn", onPhysicsStageCancel, NULL); childSetCommitCallback("physics_lod_combo", onPhysicsUseLOD, NULL); childSetCommitCallback("physics_browse", onPhysicsBrowse, NULL); - + static const LLCDStageData* stage = NULL; static S32 stage_count = 0; - + if (!stage && LLConvexDecomposition::getInstance() != NULL) { stage_count = LLConvexDecomposition::getInstance()->getStages(&stage); } - + static const LLCDParam* param = NULL; static S32 param_count = 0; if (!param && LLConvexDecomposition::getInstance() != NULL) { param_count = LLConvexDecomposition::getInstance()->getParameters(¶m); } - + for (S32 j = stage_count-1; j >= 0; --j) { LLButton* button = getChild(stage[j].mName); if (button) { - button->setCommitCallback(onPhysicsStageExecute, (void*) &stage[j]); + button->setCommitCallback(onPhysicsStageExecute, (void*) &stage[j]); } gMeshRepo.mDecompThread->mStageID[stage[j].mName] = j; // protected against stub by stage_count being 0 for stub above LLConvexDecomposition::getInstance()->registerCallback(j, LLPhysicsDecomp::llcdCallback); - + //llinfos << "Physics decomp stage " << stage[j].mName << " (" << j << ") parameters:" << llendl; //llinfos << "------------------------------------" << llendl; - + for (S32 i = 0; i < param_count; ++i) { if (param[i].mStage != j) { continue; } - + std::string name(param[i].mName ? param[i].mName : ""); std::string description(param[i].mDescription ? param[i].mDescription : ""); - + std::string type = "unknown"; - + llinfos << name << " - " << description << llendl; - + if (param[i].mType == LLCDParam::LLCD_FLOAT) { mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mFloat); //llinfos << "Type: float, Default: " << param[i].mDefault.mFloat << llendl; - + LLSliderCtrl* slider = getChild(name); if (slider) { @@ -847,7 +848,7 @@ void LLFloaterModelPreview::initDecompControls() { mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue); //llinfos << "Type: integer, Default: " << param[i].mDefault.mIntOrEnumValue << llendl; - + LLSliderCtrl* slider = getChild(name); if (slider) { @@ -862,7 +863,7 @@ void LLFloaterModelPreview::initDecompControls() { mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mBool); //llinfos << "Type: boolean, Default: " << (param[i].mDefault.mBool ? "True" : "False") << llendl; - + LLCheckBoxCtrl* check_box = getChild(name); if (check_box) { @@ -874,29 +875,29 @@ void LLFloaterModelPreview::initDecompControls() { mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue); //llinfos << "Type: enum, Default: " << param[i].mDefault.mIntOrEnumValue << llendl; - + { //plug into combo box - + //llinfos << "Accepted values: " << llendl; LLComboBox* combo_box = getChild(name); for (S32 k = 0; k < param[i].mDetails.mEnumValues.mNumEnums; ++k) { - //llinfos << param[i].mDetails.mEnumValues.mEnumsArray[k].mValue + //llinfos << param[i].mDetails.mEnumValues.mEnumsArray[k].mValue // << " - " << param[i].mDetails.mEnumValues.mEnumsArray[k].mName << llendl; - - combo_box->add(param[i].mDetails.mEnumValues.mEnumsArray[k].mName, + + combo_box->add(param[i].mDetails.mEnumValues.mEnumsArray[k].mName, LLSD::Integer(param[i].mDetails.mEnumValues.mEnumsArray[k].mValue)); } combo_box->setValue(param[i].mDefault.mIntOrEnumValue); combo_box->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); } - + //llinfos << "----" << llendl; } //llinfos << "-----------------------------" << llendl; } } - + childSetCommitCallback("physics_explode", LLFloaterModelPreview::onExplodeCommit, this); } @@ -941,7 +942,7 @@ LLModelLoader::LLModelLoader(std::string filename, S32 lod, LLModelPreview* prev mJointMap["mAnkleLeft"] = "mAnkleLeft"; mJointMap["mFootLeft"] = "mFootLeft"; mJointMap["mToeLeft"] = "mToeLeft"; - + mJointMap["avatar_mPelvis"] = "mPelvis"; mJointMap["avatar_mTorso"] = "mTorso"; mJointMap["avatar_mChest"] = "mChest"; @@ -968,8 +969,8 @@ LLModelLoader::LLModelLoader(std::string filename, S32 lod, LLModelPreview* prev mJointMap["avatar_mAnkleLeft"] = "mAnkleLeft"; mJointMap["avatar_mFootLeft"] = "mFootLeft"; mJointMap["avatar_mToeLeft"] = "mToeLeft"; - - + + mJointMap["hip"] = "mPelvis"; mJointMap["abdomen"] = "mTorso"; mJointMap["chest"] = "mChest"; @@ -994,7 +995,7 @@ LLModelLoader::LLModelLoader(std::string filename, S32 lod, LLModelPreview* prev void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, BOOL& first_transform) { - LLVector4a box[] = + LLVector4a box[] = { LLVector4a(-1, 1,-1), LLVector4a(-1, 1, 1), @@ -1005,28 +1006,28 @@ void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4 LLVector4a( 1,-1,-1), LLVector4a( 1,-1, 1), }; - + for (S32 j = 0; j < model->getNumVolumeFaces(); ++j) { const LLVolumeFace& face = model->getVolumeFace(j); - + LLVector4a center; center.setAdd(face.mExtents[0], face.mExtents[1]); center.mul(0.5f); LLVector4a size; size.setSub(face.mExtents[1],face.mExtents[0]); size.mul(0.5f); - + for (U32 i = 0; i < 8; i++) { LLVector4a t; t.setMul(size, box[i]); t.add(center); - + LLVector4a v; - - mat.affineTransform(t, v); - + + mat.affineTransform(t, v); + if (first_transform) { first_transform = FALSE; @@ -1044,13 +1045,13 @@ void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& { LLVector4a mina, maxa; LLMatrix4a mata; - + mata.loadu(mat); mina.load3(min.mV); maxa.load3(max.mV); - + stretch_extents(model, mata, mina, maxa, first_transform); - + min.set(mina.getF32ptr()); max.set(maxa.getF32ptr()); } @@ -1059,32 +1060,32 @@ void LLModelLoader::run() { DAE dae; domCOLLADA* dom = dae.open(mFilename); - + if (dom) { daeDatabase* db = dae.getDatabase(); - + daeInt count = db->getElementCount(NULL, COLLADA_TYPE_MESH); - + daeDocument* doc = dae.getDoc(mFilename); if (!doc) { llwarns << "can't find internal doc" << llendl; return; } - + daeElement* root = doc->getDomRoot(); if (!root) { llwarns << "document has no root" << llendl; return; } - + //get unit scale mTransform.setIdentity(); - + domAsset::domUnit* unit = daeSafeCast(root->getDescendant(daeElement::matchType(domAsset::domUnit::ID()))); - + if (unit) { F32 meter = unit->getMeter(); @@ -1092,19 +1093,19 @@ void LLModelLoader::run() mTransform.mMatrix[1][1] = meter; mTransform.mMatrix[2][2] = meter; } - + //get up axis rotation LLMatrix4 rotation; - + domUpAxisType up = UPAXISTYPE_Y_UP; // default is Y_UP domAsset::domUp_axis* up_axis = daeSafeCast(root->getDescendant(daeElement::matchType(domAsset::domUp_axis::ID()))); - + if (up_axis) { up = up_axis->getValue(); } - + if (up == UPAXISTYPE_X_UP) { rotation.initRotation(0.0f, 90.0f * DEG_TO_RAD, 0.0f); @@ -1113,20 +1114,20 @@ void LLModelLoader::run() { rotation.initRotation(90.0f * DEG_TO_RAD, 0.0f, 0.0f); } - + rotation *= mTransform; mTransform = rotation; - - + + for (daeInt idx = 0; idx < count; ++idx) { //build map of domEntities to LLModel domMesh* mesh = NULL; db->getElement((daeElement**) &mesh, idx, NULL, COLLADA_TYPE_MESH); - + if (mesh) { LLPointer model = LLModel::loadModelFromDomMesh(mesh); - + if (model.notNull() && validate_model(model)) { mModelList.push_back(model); @@ -1134,17 +1135,17 @@ void LLModelLoader::run() } } } - + count = db->getElementCount(NULL, COLLADA_TYPE_SKIN); for (daeInt idx = 0; idx < count; ++idx) { //add skinned meshes as instances domSkin* skin = NULL; db->getElement((daeElement**) &skin, idx, NULL, COLLADA_TYPE_SKIN); - + if (skin) - { + { domGeometry* geom = daeSafeCast(skin->getSource().getElement()); - + if (geom) { domMesh* mesh = geom->getMesh(); @@ -1156,25 +1157,25 @@ void LLModelLoader::run() LLVector3 mesh_scale_vector; LLVector3 mesh_translation_vector; model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); - + LLMatrix4 normalized_transformation; normalized_transformation.setTranslation(mesh_translation_vector); - + LLMatrix4 mesh_scale; mesh_scale.initScale(mesh_scale_vector); mesh_scale *= normalized_transformation; normalized_transformation = mesh_scale; - + glh::matrix4f inv_mat((F32*) normalized_transformation.mMatrix); inv_mat = inv_mat.inverse(); - LLMatrix4 inverse_normalized_transformation(inv_mat.m); - + LLMatrix4 inverse_normalized_transformation(inv_mat.m); + domSkin::domBind_shape_matrix* bind_mat = skin->getBind_shape_matrix(); - + if (bind_mat) { //get bind shape matrix domFloat4x4& dom_value = bind_mat->getValue(); - + for (int i = 0; i < 4; i++) { for(int j = 0; j < 4; j++) @@ -1182,26 +1183,26 @@ void LLModelLoader::run() model->mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j*4]; } } - + LLMatrix4 trans = normalized_transformation; trans *= model->mBindShapeMatrix; model->mBindShapeMatrix = trans; - + } - - + + //The joint transfom map that we'll populate below std::map jointTransforms; jointTransforms.clear(); - + //Some collada setup for accessing the skeleton daeElement* pElement = 0; dae.getDatabase()->getElement( &pElement, 0, 0, "skeleton" ); - + //Try to get at the skeletal instance controller domInstance_controller::domSkeleton* pSkeleton = daeSafeCast( pElement ); bool missingSkeletonOrScene = false; - + //If no skeleton, do a breadth-first search to get at specific joints if ( !pSkeleton ) { @@ -1216,7 +1217,7 @@ void LLModelLoader::run() //Get the children at this level daeTArray< daeSmartRef > children = pScene->getChildren(); S32 childCount = children.getCount(); - + //Process any children that are joints //Not all children are joints, some code be ambient lights, cameras, geometry etc.. for (S32 i = 0; i < childCount; ++i) @@ -1225,45 +1226,45 @@ void LLModelLoader::run() if ( isNodeAJoint( pNode ) ) { processJointNode( pNode, jointTransforms ); - } + } } - } + } } - else + else //Has Skeleton - { + { //Get the root node of the skeleton daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement(); if ( pSkeletonRootNode ) - { - //Once we have the root node - start acccessing it's joint components + { + //Once we have the root node - start acccessing it's joint components const int jointCnt = mJointMap.size(); std::map :: const_iterator jointIt = mJointMap.begin(); - + //Loop over all the possible joints within the .dae - using the allowed joint list in the ctor. for ( int i=0; i( resolver.getElement() ); if ( pJoint ) - { + { //Pull out the translate id and store it in the jointTranslations map - daeSIDResolver jointResolver( pJoint, "./translate" ); + daeSIDResolver jointResolver( pJoint, "./translate" ); domTranslate* pTranslate = daeSafeCast( jointResolver.getElement() ); - + LLMatrix4 workingTransform; - + //Translation via SID if ( pTranslate ) - { + { extractTranslation( pTranslate, workingTransform ); } else @@ -1276,16 +1277,16 @@ void LLModelLoader::run() missingSkeletonOrScene = true; } else - { + { extractTranslationViaElement( pTranslateElement, workingTransform ); } } - + //Store the joint transform w/respect to it's name. - jointTransforms[(*jointIt).second.c_str()] = workingTransform; + jointTransforms[(*jointIt).second.c_str()] = workingTransform; } } - + //If anything failed in regards to extracting the skeleton, joints or translation id, //mention it if ( missingSkeletonOrScene ) @@ -1294,7 +1295,7 @@ void LLModelLoader::run() } }//got skeleton? } - + if ( !missingSkeletonOrScene ) { //Set the joint translations on the avatar @@ -1305,12 +1306,12 @@ void LLModelLoader::run() { std::string lookingForJoint = (*jointIt).first.c_str(); if ( jointTransforms.find( lookingForJoint ) != jointTransforms.end() ) - { + { LLMatrix4 jointTransform = jointTransforms[lookingForJoint]; LLJoint* pJoint = gAgentAvatarp->getJoint( lookingForJoint ); if ( pJoint ) - { - pJoint->storeCurrentXform( jointTransform.getTranslation() ); + { + pJoint->storeCurrentXform( jointTransform.getTranslation() ); } else { @@ -1319,39 +1320,39 @@ void LLModelLoader::run() } //Reposition the avatars pelvis (avPos+offset) //if ( lookingForJoint == "mPelvis" ) - //{ + //{ // const LLVector3& pos = gAgentAvatarp->getCharacterPosition(); // gAgentAvatarp->setPelvisOffset( true, jointTransform.getTranslation() ); - // gAgentAvatarp->setPosition( pos + jointTransform.getTranslation() ); + // gAgentAvatarp->setPosition( pos + jointTransform.getTranslation() ); //} } } } //missingSkeletonOrScene - + domSkin::domJoints* joints = skin->getJoints(); - + domInputLocal_Array& joint_input = joints->getInput_array(); - + for (size_t i = 0; i < joint_input.getCount(); ++i) { domInputLocal* input = joint_input.get(i); xsNMTOKEN semantic = input->getSemantic(); - + if (strcmp(semantic, COMMON_PROFILE_INPUT_JOINT) == 0) { //found joint source, fill model->mJointMap and model->mJointList daeElement* elem = input->getSource().getElement(); - + domSource* source = daeSafeCast(elem); if (source) - { - - + { + + domName_array* names_source = source->getName_array(); - + if (names_source) { - domListOfNames &names = names_source->getValue(); - + domListOfNames &names = names_source->getValue(); + for (size_t j = 0; j < names.getCount(); ++j) { std::string name(names.get(j)); @@ -1361,7 +1362,7 @@ void LLModelLoader::run() } model->mJointList.push_back(name); model->mJointMap[name] = j; - } + } } else { @@ -1369,7 +1370,7 @@ void LLModelLoader::run() if (names_source) { xsIDREFS& names = names_source->getValue(); - + for (size_t j = 0; j < names.getCount(); ++j) { std::string name(names.get(j).getID()); @@ -1394,11 +1395,11 @@ void LLModelLoader::run() { domListOfFloats& transform = t->getValue(); S32 count = transform.getCount()/16; - + for (S32 k = 0; k < count; ++k) { LLMatrix4 mat; - + for (int i = 0; i < 4; i++) { for(int j = 0; j < 4; j++) @@ -1406,19 +1407,19 @@ void LLModelLoader::run() mat.mMatrix[i][j] = transform[k*16 + i + j*4]; } } - + model->mInvBindMatrix.push_back(mat); } } } } } - + //We need to construct the alternate bind matrix (which contains the new joint positions) //in the same order as they were stored in the joint buffer. The joints associated //with the skeleton are not stored in the same order as they are in the exported joint buffer. //This remaps the skeletal joints to be in the same order as the joints stored in the model. - std::vector :: const_iterator jointIt = model->mJointList.begin(); + std::vector :: const_iterator jointIt = model->mJointList.begin(); const int jointCnt = model->mJointList.size(); for ( int i=0; imInvBindMatrix[i]; newInverse.setTranslation( jointTransforms[lookingForJoint].getTranslation() ); - model->mAlternateBindMatrix.push_back( newInverse ); + model->mAlternateBindMatrix.push_back( newInverse ); } else { llwarns<<"Possibly misnamed/missing joint [" <getVertices(); if (verts) { @@ -1455,19 +1456,19 @@ void LLModelLoader::run() if (pos_array) { domListOfFloats& pos = pos_array->getValue(); - + for (size_t j = 0; j < pos.getCount(); j += 3) { if (pos.getCount() <= j+2) { llerrs << "WTF?" << llendl; } - + LLVector3 v(pos[j], pos[j+1], pos[j+2]); - + //transform from COLLADA space to volume space v = v * inverse_normalized_transformation; - + model->mPosition.push_back(v); } } @@ -1475,7 +1476,7 @@ void LLModelLoader::run() } } } - + //grab skin weights array domSkin::domVertex_weights* weights = skin->getVertex_weights(); if (weights) @@ -1493,44 +1494,44 @@ void LLModelLoader::run() } } } - + if (vertex_weights) { domListOfFloats& w = vertex_weights->getValue(); domListOfUInts& vcount = weights->getVcount()->getValue(); domListOfInts& v = weights->getV()->getValue(); - + U32 c_idx = 0; for (size_t vc_idx = 0; vc_idx < vcount.getCount(); ++vc_idx) { //for each vertex daeUInt count = vcount[vc_idx]; - + //create list of weights that influence this vertex LLModel::weight_list weight_list; - + for (daeUInt i = 0; i < count; ++i) { //for each weight daeInt joint_idx = v[c_idx++]; daeInt weight_idx = v[c_idx++]; - + if (joint_idx == -1) { //ignore bindings to bind_shape_matrix continue; } - + F32 weight_value = w[weight_idx]; - - weight_list.push_back(LLModel::JointWeight(joint_idx, weight_value)); + + weight_list.push_back(LLModel::JointWeight(joint_idx, weight_value)); } - + //sort by joint weight std::sort(weight_list.begin(), weight_list.end(), LLModel::CompareWeightGreater()); - + std::vector wght; - + F32 total = 0.f; - + for (U32 i = 0; i < llmin((U32) 4, (U32) weight_list.size()); ++i) { //take up to 4 most significant weights if (weight_list[i].mWeight > 0.f) @@ -1539,21 +1540,21 @@ void LLModelLoader::run() total += weight_list[i].mWeight; } } - + F32 scale = 1.f/total; if (scale != 1.f) { //normalize weights for (U32 i = 0; i < wght.size(); ++i) - { + { wght[i].mWeight *= scale; } } - + model->mSkinWeights[model->mPosition[vc_idx]] = wght; } - + //add instance to scene for this model - + LLMatrix4 transform; std::vector materials; materials.resize(model->getNumVolumeFaces()); @@ -1566,23 +1567,23 @@ void LLModelLoader::run() } } } - + daeElement* scene = root->getDescendant("visual_scene"); - + if (!scene) { llwarns << "document has no visual_scene" << llendl; setLoadState( ERROR_PARSING ); return; } - + processElement(scene); doOnIdleOneTime(boost::bind(&LLModelPreview::loadModelCallback,mPreview,mLod)); } } -bool LLModelLoader::isNodeAJoint( domNode* pNode ) +bool LLModelLoader::isNodeAJoint( domNode* pNode ) { if ( pNode->getName() == NULL) { @@ -1593,7 +1594,7 @@ bool LLModelLoader::isNodeAJoint( domNode* pNode ) { return true; } - + return false; } @@ -1601,7 +1602,7 @@ void LLModelLoader::extractTranslation( domTranslate* pTranslate, LLMatrix4& tra { domFloat3 jointTrans = pTranslate->getValue(); LLVector3 singleJointTranslation( jointTrans[0], jointTrans[1], jointTrans[2] ); - transform.setTranslation( singleJointTranslation ); + transform.setTranslation( singleJointTranslation ); } void LLModelLoader::extractTranslationViaElement( daeElement* pTranslateElement, LLMatrix4& transform ) @@ -1609,7 +1610,7 @@ void LLModelLoader::extractTranslationViaElement( daeElement* pTranslateElement, domTranslate* pTranslateChild = dynamic_cast( pTranslateElement ); domFloat3 translateChild = pTranslateChild->getValue(); LLVector3 singleJointTranslation( translateChild[0], translateChild[1], translateChild[2] ); - transform.setTranslation( singleJointTranslation ); + transform.setTranslation( singleJointTranslation ); } void LLModelLoader::processJointNode( domNode* pNode, std::map& jointTransforms ) @@ -1621,18 +1622,18 @@ void LLModelLoader::processJointNode( domNode* pNode, std::mapgetName()<( jointResolver.getElement() ); - + //Translation via SID was successful if ( pTranslate ) - { + { extractTranslation( pTranslate, workingTransform ); } else @@ -1644,88 +1645,88 @@ void LLModelLoader::processJointNode( domNode* pNode, std::mapgetName() ] = workingTransform; - + jointTransforms[ pNode->getName() ] = workingTransform; + //2. handle the nodes children - + //Gather and handle the incoming nodes children daeTArray< daeSmartRef > childOfChild = pNode->getChildren(); S32 childOfChildCount = childOfChild.getCount(); - + for (S32 i = 0; i < childOfChildCount; ++i) { domNode* pChildNode = daeSafeCast( childOfChild[i] ); if ( pChildNode ) { processJointNode( pChildNode, jointTransforms ); - } + } } } daeElement* LLModelLoader::getChildFromElement( daeElement* pElement, std::string const & name ) -{ +{ daeElement* pChildOfElement = pElement->getChild( name.c_str() ); if ( pChildOfElement ) { return pChildOfElement; - } + } llwarns<< "Could not find a child [" << name << "] for the element: \"" << pElement->getAttribute("id") << "\"" << llendl; - return NULL; + return NULL; } void LLModelLoader::processElement(daeElement* element) { LLMatrix4 saved_transform = mTransform; - + domTranslate* translate = daeSafeCast(element); if (translate) { domFloat3 dom_value = translate->getValue(); - + LLMatrix4 translation; translation.setTranslation(LLVector3(dom_value[0], dom_value[1], dom_value[2])); - + translation *= mTransform; mTransform = translation; } - + domRotate* rotate = daeSafeCast(element); if (rotate) { domFloat4 dom_value = rotate->getValue(); - + LLMatrix4 rotation; rotation.initRotTrans(dom_value[3] * DEG_TO_RAD, LLVector3(dom_value[0], dom_value[1], dom_value[2]), LLVector3(0, 0, 0)); - + rotation *= mTransform; mTransform = rotation; } - + domScale* scale = daeSafeCast(element); if (scale) { domFloat3 dom_value = scale->getValue(); - + LLMatrix4 scaling; scaling.initScale(LLVector3(dom_value[0], dom_value[1], dom_value[2])); - + scaling *= mTransform; mTransform = scaling; } - + domMatrix* matrix = daeSafeCast(element); if (matrix) { domFloat4x4 dom_value = matrix->getValue(); - + LLMatrix4 matrix_transform; - + for (int i = 0; i < 4; i++) { for(int j = 0; j < 4; j++) @@ -1733,11 +1734,11 @@ void LLModelLoader::processElement(daeElement* element) matrix_transform.mMatrix[i][j] = dom_value[i + j*4]; } } - + matrix_transform *= mTransform; mTransform = matrix_transform; } - + domInstance_geometry* instance_geo = daeSafeCast(element); if (instance_geo) { @@ -1751,32 +1752,32 @@ void LLModelLoader::processElement(daeElement* element) if (model) { LLMatrix4 transformation = mTransform; - + std::vector materials = getMaterials(model, instance_geo); - + // adjust the transformation to compensate for mesh normalization LLVector3 mesh_scale_vector; LLVector3 mesh_translation_vector; model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); - + LLMatrix4 mesh_translation; mesh_translation.setTranslation(mesh_translation_vector); mesh_translation *= transformation; transformation = mesh_translation; - + LLMatrix4 mesh_scale; mesh_scale.initScale(mesh_scale_vector); mesh_scale *= transformation; transformation = mesh_scale; - + mScene[transformation].push_back(LLModelInstance(model, transformation, materials)); - - stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); + + stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); } } } } - + domInstance_node* instance_node = daeSafeCast(element); if (instance_node) { @@ -1786,18 +1787,18 @@ void LLModelLoader::processElement(daeElement* element) processElement(instance); } } - + //process children daeTArray< daeSmartRef > children = element->getChildren(); for (S32 i = 0; i < children.getCount(); i++) { processElement(children[i]); } - + domNode* node = daeSafeCast(element); if (node) { //this element was a node, restore transform before processiing siblings - mTransform = saved_transform; + mTransform = saved_transform; } } @@ -1807,26 +1808,26 @@ std::vector LLModelLoader::getMaterials(LLModel* model, domIns for (int i = 0; i < model->mMaterialList.size(); i++) { LLImportMaterial import_material; - + domInstance_material* instance_mat = NULL; - + domBind_material::domTechnique_common* technique = daeSafeCast(instance_geo->getDescendant(daeElement::matchType(domBind_material::domTechnique_common::ID()))); - + if (technique) { daeTArray< daeSmartRef > inst_materials = technique->getChildrenByType(); for (int j = 0; j < inst_materials.getCount(); j++) { std::string symbol(inst_materials[j]->getSymbol()); - + if (symbol == model->mMaterialList[i]) // found the binding { instance_mat = inst_materials[j]; } } } - + if (instance_mat) { domMaterial* material = daeSafeCast(instance_mat->getTarget().getElement()); @@ -1849,10 +1850,10 @@ std::vector LLModelLoader::getMaterials(LLModel* model, domIns } } } - + materials.push_back(import_material); } - + return materials; } @@ -1860,7 +1861,7 @@ LLImportMaterial LLModelLoader::profileToMaterial(domProfile_COMMON* material) { LLImportMaterial mat; mat.mFullbright = FALSE; - + daeElement* diffuse = material->getDescendant("diffuse"); if (diffuse) { @@ -1878,7 +1879,7 @@ LLImportMaterial LLModelLoader::profileToMaterial(domProfile_COMMON* material) if (init) { domFx_surface_init_from_common_Array init_from = init->getInit_from_array(); - + if (init_from.getCount() > i) { domImage* image = daeSafeCast(init_from[i]->getValue().getElement()); @@ -1889,10 +1890,10 @@ LLImportMaterial LLModelLoader::profileToMaterial(domProfile_COMMON* material) if (init) { std::string filename = cdom::uriToNativePath(init->getValue().str()); - + mat.mDiffuseMap = LLViewerTextureManager::getFetchedTextureFromUrl("file://" + filename, TRUE, LLViewerTexture::BOOST_PREVIEW); mat.mDiffuseMap->setLoadedCallback(LLModelPreview::textureLoadedCallback, 0, TRUE, FALSE, this->mPreview, NULL, FALSE); - + mat.mDiffuseMap->forceToSaveRawImage(); mat.mDiffuseMapFilename = filename; mat.mDiffuseMapLabel = getElementLabel(material); @@ -1903,7 +1904,7 @@ LLImportMaterial LLModelLoader::profileToMaterial(domProfile_COMMON* material) } } } - + domCommon_color_or_texture_type_complexType::domColor* color = daeSafeCast(diffuse->getDescendant("color")); if (color) @@ -1913,7 +1914,7 @@ LLImportMaterial LLModelLoader::profileToMaterial(domProfile_COMMON* material) mat.mDiffuseColor = value; } } - + daeElement* emission = material->getDescendant("emission"); if (emission) { @@ -1923,7 +1924,7 @@ LLImportMaterial LLModelLoader::profileToMaterial(domProfile_COMMON* material) mat.mFullbright = TRUE; } } - + return mat; } @@ -1936,13 +1937,13 @@ std::string LLModelLoader::getElementLabel(daeElement *element) { return name; } - + // if we have an ID attribute, use it if (element->getID()) { return std::string(element->getID()); } - + // if we have a parent, use it daeElement* parent = element->getParent(); if (parent) @@ -1953,21 +1954,21 @@ std::string LLModelLoader::getElementLabel(daeElement *element) { return name; } - + // if parent has an ID, use it if (parent->getID()) { return std::string(parent->getID()); } } - + // try to use our type daeString element_name = element->getElementName(); if (element_name) { return std::string(element_name); } - + // if all else fails, use "object" return std::string("object"); } @@ -1982,7 +1983,7 @@ LLColor4 LLModelLoader::getDaeColor(daeElement* element) domFx_color_common domfx_color = color->getValue(); value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]); } - + return value; } @@ -1990,7 +1991,7 @@ LLColor4 LLModelLoader::getDaeColor(daeElement* element) // LLModelPreview //----------------------------------------------------------------------------- -LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) +LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) : LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE), LLMutex(NULL) { mNeedsUpdate = TRUE; @@ -2010,9 +2011,9 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) mBuildQueueMode = GLOD_QUEUE_GREEDY; mBuildBorderMode = GLOD_BORDER_UNLOCK; mBuildOperator = GLOD_OPERATOR_HALF_EDGE_COLLAPSE; - + mFMP = fmp; - + glodInit(); } @@ -2023,7 +2024,7 @@ LLModelPreview::~LLModelPreview() delete mModelLoader; mModelLoader = NULL; } - + //*HACK : *TODO : turn this back on when we understand why this crashes //glodShutdown(); } @@ -2031,59 +2032,59 @@ LLModelPreview::~LLModelPreview() U32 LLModelPreview::calcResourceCost() { assert_main_thread(); - + rebuildUploadData(); if ( mModelLoader->getLoadState() != LLModelLoader::ERROR_PARSING ) { mFMP->childEnable("ok_btn"); } - + U32 cost = 0; std::set accounted; U32 num_points = 0; U32 num_hulls = 0; - + F32 debug_scale = mFMP->childGetValue("import_scale").asReal(); - + F32 streaming_cost = 0.f; for (U32 i = 0; i < mUploadData.size(); ++i) { LLModelInstance& instance = mUploadData[i]; - + if (accounted.find(instance.mModel) == accounted.end()) { accounted.insert(instance.mModel); - + LLModel::convex_hull_decomposition& decomp = instance.mLOD[LLModel::LOD_PHYSICS] ? instance.mLOD[LLModel::LOD_PHYSICS]->mConvexHullDecomp : instance.mModel->mConvexHullDecomp; - + LLSD ret = LLModel::writeModel( "", instance.mLOD[4], - instance.mLOD[3], - instance.mLOD[2], - instance.mLOD[1], + instance.mLOD[3], + instance.mLOD[2], + instance.mLOD[1], instance.mLOD[0], decomp, mFMP->childGetValue("upload_skin").asBoolean(), mFMP->childGetValue("upload_joints").asBoolean(), TRUE); cost += gMeshRepo.calcResourceCost(ret); - + num_hulls += decomp.size(); for (U32 i = 0; i < decomp.size(); ++i) { num_points += decomp[i].size(); } - + //calculate streaming cost LLMatrix4 transformation = instance.mTransform; - + LLVector3 position = LLVector3(0, 0, 0) * transformation; - + LLVector3 x_transformed = LLVector3(1, 0, 0) * transformation - position; LLVector3 y_transformed = LLVector3(0, 1, 0) * transformation - position; LLVector3 z_transformed = LLVector3(0, 0, 1) * transformation - position; @@ -2091,64 +2092,64 @@ U32 LLModelPreview::calcResourceCost() F32 y_length = y_transformed.normalize(); F32 z_length = z_transformed.normalize(); LLVector3 scale = LLVector3(x_length, y_length, z_length); - + F32 radius = scale.length()*debug_scale; - + streaming_cost += LLMeshRepository::getStreamingCost(ret, radius); } } - + //mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[HULLS]", llformat("%d",num_hulls)); - //mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[POINTS]", llformat("%d",num_points)); - mFMP->childSetTextArg("streaming cost", "[COST]", llformat("%.3f", streaming_cost)); + //mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[POINTS]", llformat("%d",num_points)); + mFMP->childSetTextArg("streaming cost", "[COST]", llformat("%.3f", streaming_cost)); F32 scale = mFMP->childGetValue("import_scale").asReal()*2.f; mFMP->childSetTextArg("import_dimensions", "[X]", llformat("%.3f", mPreviewScale[0]*scale)); mFMP->childSetTextArg("import_dimensions", "[Y]", llformat("%.3f", mPreviewScale[1]*scale)); mFMP->childSetTextArg("import_dimensions", "[Z]", llformat("%.3f", mPreviewScale[2]*scale)); - + updateStatusMessages(); - + return cost; } void LLModelPreview::rebuildUploadData() { assert_main_thread(); - + mUploadData.clear(); mTextureSet.clear(); - + //fill uploaddata instance vectors from scene data std::string requested_name = mFMP->getChild("description_form")->getValue().asString(); - + LLSpinCtrl* scale_spinner = mFMP->getChild("import_scale"); - + if (!scale_spinner) { llerrs << "floater_model_preview.xml MUST contain import_scale spinner." << llendl; } - + F32 scale = scale_spinner->getValue().asReal(); - + LLMatrix4 scale_mat; scale_mat.initScale(LLVector3(scale, scale, scale)); - + F32 max_scale = 0.f; - + if ( mBaseScene.size() > 0 ) { mFMP->childEnable("ok_btn"); } - + for (LLModelLoader::scene::iterator iter = mBaseScene.begin(); iter != mBaseScene.end(); ++iter) { //for each transform in scene LLMatrix4 mat = iter->first; - + // compute position LLVector3 position = LLVector3(0, 0, 0) * mat; - + // compute scale LLVector3 x_transformed = LLVector3(1, 0, 0) * mat - position; LLVector3 y_transformed = LLVector3(0, 1, 0) * mat - position; @@ -2156,21 +2157,21 @@ void LLModelPreview::rebuildUploadData() F32 x_length = x_transformed.normalize(); F32 y_length = y_transformed.normalize(); F32 z_length = z_transformed.normalize(); - + max_scale = llmax(llmax(llmax(max_scale, x_length), y_length), z_length); - + mat *= scale_mat; - + for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) { //for each instance with said transform applied LLModelInstance instance = *model_iter; - + LLModel* base_model = instance.mModel; if (base_model) { base_model->mRequestedLabel = requested_name; } - + S32 idx = 0; for (idx = 0; idx < mBaseModel.size(); ++idx) { //find reference instance for this model @@ -2179,7 +2180,7 @@ void LLModelPreview::rebuildUploadData() break; } } - + for (U32 i = 0; i < LLModel::NUM_LODS; i++) { //fill LOD slots based on reference model index if (!mModel[i].empty()) @@ -2191,16 +2192,16 @@ void LLModelPreview::rebuildUploadData() instance.mLOD[i] = NULL; } } - + instance.mTransform = mat; mUploadData.push_back(instance); } } - + F32 max_import_scale = DEFAULT_MAX_PRIM_SCALE/max_scale; - + scale_spinner->setMaxValue(max_import_scale); - + if (max_import_scale < scale) { scale_spinner->setValue(max_import_scale); @@ -2215,7 +2216,7 @@ void LLModelPreview::clearModel(S32 lod) { return; } - + mVertexBuffer[lod].clear(); mModel[lod].clear(); mScene[lod].clear(); @@ -2224,15 +2225,15 @@ void LLModelPreview::clearModel(S32 lod) void LLModelPreview::loadModel(std::string filename, S32 lod) { assert_main_thread(); - + LLMutexLock lock(this); - + if (mModelLoader) { delete mModelLoader; mModelLoader = NULL; } - + if (filename.empty()) { if (mBaseModel.empty()) @@ -2241,31 +2242,31 @@ void LLModelPreview::loadModel(std::string filename, S32 lod) // if we don't have a base model to show for high LOD. mFMP->closeFloater(false); } - + mLoading = false; return; } - + mLODFile[lod] = filename; if (lod == LLModel::LOD_HIGH) { clearGLODGroup(); } - + mModelLoader = new LLModelLoader(filename, lod, this); - + mModelLoader->start(); - + mFMP->childSetTextArg("status", "[STATUS]", mFMP->getString("status_reading_file")); - + setPreviewLOD(lod); if ( mModelLoader->getLoadState() == LLModelLoader::ERROR_PARSING ) { mFMP->childDisable("ok_btn"); } - + if (lod == mPreviewLOD) { mFMP->childSetText("lod_file", mLODFile[mPreviewLOD]); @@ -2274,14 +2275,14 @@ void LLModelPreview::loadModel(std::string filename, S32 lod) { mFMP->childSetText("physics_file", mLODFile[lod]); } - + mFMP->openFloater(); } void LLModelPreview::setPhysicsFromLOD(S32 lod) { assert_main_thread(); - + if (lod >= 0 && lod <= 3) { mModel[LLModel::LOD_PHYSICS] = mModel[lod]; @@ -2306,7 +2307,7 @@ void LLModelPreview::clearIncompatible(S32 lod) mModel[i].clear(); mScene[i].clear(); mVertexBuffer[i].clear(); - + if (i == LLModel::LOD_HIGH) { mBaseModel = mModel[lod]; @@ -2345,19 +2346,19 @@ void LLModelPreview::loadModelCallback(S32 lod) { return; } - + mModel[lod] = mModelLoader->mModelList; mScene[lod] = mModelLoader->mScene; mVertexBuffer[lod].clear(); - + if (lod == LLModel::LOD_PHYSICS) { mPhysicsMesh.clear(); } - + setPreviewLOD(lod); - - + + if (lod == LLModel::LOD_HIGH) { //save a copy of the highest LOD for automatic LOD manipulation if (mBaseModel.empty()) @@ -2371,16 +2372,16 @@ void LLModelPreview::loadModelCallback(S32 lod) mBaseScene = mScene[lod]; mVertexBuffer[5].clear(); } - + clearIncompatible(lod); - + mDirty = true; - + if (lod == LLModel::LOD_HIGH) { resetPreviewTarget(); } - + mLoading = false; refresh(); } @@ -2395,71 +2396,71 @@ void LLModelPreview::resetPreviewTarget() void LLModelPreview::generateNormals() { assert_main_thread(); - + S32 which_lod = mPreviewLOD; - - + + if (which_lod > 4 || which_lod < 0 || mModel[which_lod].empty()) { return; } - + F32 angle_cutoff = mFMP->childGetValue("crease_angle").asReal(); - + angle_cutoff *= DEG_TO_RAD; - + if (which_lod == 3 && !mBaseModel.empty()) { for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) { (*iter)->generateNormals(angle_cutoff); } - + mVertexBuffer[5].clear(); } - + for (LLModelLoader::model_list::iterator iter = mModel[which_lod].begin(); iter != mModel[which_lod].end(); ++iter) { (*iter)->generateNormals(angle_cutoff); } - + mVertexBuffer[which_lod].clear(); refresh(); - + } void LLModelPreview::consolidate() { std::map > composite; - + LLMatrix4 identity; - + //bake out each node in current scene to composite for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) { //for each transform in current scene LLMatrix4 mat = iter->first; glh::matrix4f inv_trans = glh::matrix4f((F32*) mat.mMatrix).inverse().transpose(); LLMatrix4 norm_mat(inv_trans.m); - + for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) { //for each instance with that transform LLModelInstance& source_instance = *model_iter; LLModel* source = source_instance.mModel; - + if (!validate_model(source)) { llerrs << "Invalid model found!" << llendl; } - + for (S32 i = 0; i < source->getNumVolumeFaces(); ++i) { //for each face in instance const LLVolumeFace& src_face = source->getVolumeFace(i); LLImportMaterial& source_material = source_instance.mMaterial[i]; - + //get model in composite that is composite for this material LLModel* model = NULL; - + if (composite.find(source_material) != composite.end()) { model = composite[source_material].rbegin()->mModel; @@ -2468,7 +2469,7 @@ void LLModelPreview::consolidate() model = NULL; } } - + if (model == NULL) { //no model found, make new model std::vector materials; @@ -2480,106 +2481,106 @@ void LLModelPreview::consolidate() model->setNumVolumeFaces(0); composite[source_material].push_back(LLModelInstance(model, identity, materials)); } - + model->appendFace(src_face, source->mMaterialList[i], mat, norm_mat); } } } - - + + //condense composite into as few LLModel instances as possible LLModelLoader::model_list new_model; std::vector instance_list; - + LLVolumeParams volume_params; volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); - + std::vector empty_material; LLModelInstance cur_instance(new LLModel(volume_params, 0.f), identity, empty_material); cur_instance.mModel->setNumVolumeFaces(0); - + BOOL first_transform = TRUE; - + LLModelLoader::scene new_scene; LLVector3 min,max; - + for (std::map >::iterator iter = composite.begin(); iter != composite.end(); ++iter) { std::map >::iterator next_iter = iter; ++next_iter; - - for (std::vector::iterator instance_iter = iter->second.begin(); + + for (std::vector::iterator instance_iter = iter->second.begin(); instance_iter != iter->second.end(); ++instance_iter) { LLModel* source = instance_iter->mModel; - + if (instance_iter->mMaterial.size() != 1) { llerrs << "WTF?" << llendl; } - + if (source->getNumVolumeFaces() != 1) { llerrs << "WTF?" << llendl; } - + if (source->mMaterialList.size() != 1) { llerrs << "WTF?" << llendl; } - + cur_instance.mModel->addFace(source->getVolumeFace(0)); cur_instance.mMaterial.push_back(instance_iter->mMaterial[0]); cur_instance.mModel->mMaterialList.push_back(source->mMaterialList[0]); - + BOOL last_model = FALSE; - + std::vector::iterator next_instance = instance_iter; ++next_instance; - + if (next_iter == composite.end() && next_instance == iter->second.end()) { last_model = TRUE; } - + if (last_model || cur_instance.mModel->getNumVolumeFaces() >= MAX_MODEL_FACES) { cur_instance.mModel->mLabel = source->mLabel; - + cur_instance.mModel->optimizeVolumeFaces(); cur_instance.mModel->normalizeVolumeFaces(); - + if (!validate_model(cur_instance.mModel)) { llerrs << "Invalid model detected." << llendl; } - + new_model.push_back(cur_instance.mModel); - + LLMatrix4 transformation = LLMatrix4(); - + // adjust the transformation to compensate for mesh normalization LLVector3 mesh_scale_vector; LLVector3 mesh_translation_vector; cur_instance.mModel->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); - + LLMatrix4 mesh_translation; mesh_translation.setTranslation(mesh_translation_vector); mesh_translation *= transformation; transformation = mesh_translation; - + LLMatrix4 mesh_scale; mesh_scale.initScale(mesh_scale_vector); mesh_scale *= transformation; transformation = mesh_scale; - + cur_instance.mTransform = transformation; - + new_scene[transformation].push_back(cur_instance); stretch_extents(cur_instance.mModel, transformation, min, max, first_transform); - + if (!last_model) { cur_instance = LLModelInstance(new LLModel(volume_params, 0.f), identity, empty_material); @@ -2588,11 +2589,11 @@ void LLModelPreview::consolidate() } } } - + mScene[mPreviewLOD] = new_scene; mModel[mPreviewLOD] = new_model; mVertexBuffer[mPreviewLOD].clear(); - + if (mPreviewLOD == LLModel::LOD_HIGH) { mBaseScene = new_scene; @@ -2600,13 +2601,13 @@ void LLModelPreview::consolidate() clearGLODGroup(); mVertexBuffer[5].clear(); } - + mPreviewTarget = (min+max)*0.5f; mPreviewScale = (max-min)*0.5f; setPreviewTarget(mPreviewScale.magVec()*2.f); - + clearIncompatible(mPreviewLOD); - + mResourceCost = calcResourceCost(); refresh(); } @@ -2619,11 +2620,11 @@ void LLModelPreview::clearMaterials() { //for each instance with that transform LLModelInstance& source_instance = *model_iter; LLModel* source = source_instance.mModel; - + for (S32 i = 0; i < source->getNumVolumeFaces(); ++i) { //for each face in instance LLImportMaterial& source_material = source_instance.mMaterial[i]; - + //clear material info source_material.mDiffuseColor = LLColor4(1,1,1,1); source_material.mDiffuseMap = NULL; @@ -2633,9 +2634,9 @@ void LLModelPreview::clearMaterials() } } } - + mVertexBuffer[mPreviewLOD].clear(); - + if (mPreviewLOD == LLModel::LOD_HIGH) { mBaseScene = mScene[mPreviewLOD]; @@ -2643,7 +2644,7 @@ void LLModelPreview::clearMaterials() clearGLODGroup(); mVertexBuffer[5].clear(); } - + mResourceCost = calcResourceCost(); refresh(); } @@ -2669,21 +2670,21 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation) { return; } - + if (which_lod == LLModel::LOD_PHYSICS) { //clear physics mesh map mPhysicsMesh.clear(); } - + LLVertexBuffer::unbind(); - + stop_gloderror(); static U32 cur_name = 1; - + S32 limit = -1; - + U32 triangle_count = 0; - + for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) { LLModel* mdl = *iter; @@ -2692,13 +2693,13 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation) triangle_count += mdl->getVolumeFace(i).mNumIndices/3; } } - + U32 base_triangle_count = triangle_count; - + U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; - + U32 lod_mode = 0; - + LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode"); if (iface) { @@ -2706,7 +2707,7 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation) } F32 lod_error_threshold = mFMP->childGetValue("lod_error_threshold").asReal(); - + if (lod_mode == 0) { lod_mode = GLOD_TRIANGLE_BUDGET; @@ -2812,14 +2813,14 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation) for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) { //build GLOD objects for each model in base model list LLModel* mdl = *iter; - + if (mObject[mdl] != 0) { glodDeleteObject(mObject[mdl]); } mObject[mdl] = cur_name++; - + glodNewObject(mObject[mdl], mGroup, GLOD_DISCRETE); stop_gloderror(); @@ -2827,12 +2828,12 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation) { //regenerate vertex buffer for skinned models to prevent animation feedback during LOD generation mVertexBuffer[5].clear(); } - + if (mVertexBuffer[5].empty()) { genBuffers(5, false); } - + U32 tri_count = 0; for (U32 i = 0; i < mVertexBuffer[5][mdl].size(); ++i) { @@ -2862,16 +2863,16 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation) stop_gloderror(); } } - - + + S32 start = LLModel::LOD_HIGH; S32 end = 0; - + if (which_lod != -1) { start = end = which_lod; } - + mMaxTriangleLimit = base_triangle_count; for (S32 lod = start; lod >= end; --lod) @@ -2887,58 +2888,58 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation) { triangle_count = limit; } - + mModel[lod].clear(); mModel[lod].resize(mBaseModel.size()); mVertexBuffer[lod].clear(); - + U32 actual_tris = 0; U32 actual_verts = 0; U32 submeshes = 0; - + glodGroupParameteri(mGroup, GLOD_ADAPT_MODE, lod_mode); - stop_gloderror(); - + stop_gloderror(); + glodGroupParameteri(mGroup, GLOD_ERROR_MODE, GLOD_OBJECT_SPACE_ERROR); stop_gloderror(); - + glodGroupParameteri(mGroup, GLOD_MAX_TRIANGLES, triangle_count); stop_gloderror(); - + glodGroupParameterf(mGroup, GLOD_OBJECT_SPACE_ERROR_THRESHOLD, lod_error_threshold); stop_gloderror(); - + glodAdaptGroup(mGroup); stop_gloderror(); for (U32 mdl_idx = 0; mdl_idx < mBaseModel.size(); ++mdl_idx) - { + { LLModel* base = mBaseModel[mdl_idx]; - + GLint patch_count = 0; glodGetObjectParameteriv(mObject[base], GLOD_NUM_PATCHES, &patch_count); stop_gloderror(); - + LLVolumeParams volume_params; volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); mModel[lod][mdl_idx] = new LLModel(volume_params, 0.f); - + GLint* sizes = new GLint[patch_count*2]; glodGetObjectParameteriv(mObject[base], GLOD_PATCH_SIZES, sizes); stop_gloderror(); - + GLint* names = new GLint[patch_count]; glodGetObjectParameteriv(mObject[base], GLOD_PATCH_NAMES, names); stop_gloderror(); - + mModel[lod][mdl_idx]->setNumVolumeFaces(patch_count); - + LLModel* target_model = mModel[lod][mdl_idx]; - + for (GLint i = 0; i < patch_count; ++i) { LLPointer buff = new LLVertexBuffer(type_mask, 0); - + if (sizes[i*2+1] > 0 && sizes[i*2] > 0) { buff->allocateBuffer(sizes[i*2+1], sizes[i*2], true); @@ -2952,30 +2953,30 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation) memset(buff->getMappedData(), 0, buff->getSize()); memset(buff->getIndicesPointer(), 0, buff->getIndicesSize()); } - + buff->validateRange(0, buff->getNumVerts()-1, buff->getNumIndices(), 0); - + LLStrider pos; LLStrider norm; LLStrider tc; LLStrider index; - + buff->getVertexStrider(pos); buff->getNormalStrider(norm); buff->getTexCoord0Strider(tc); buff->getIndexStrider(index); - + target_model->setVolumeFaceData(names[i], pos, norm, tc, index, buff->getNumVerts(), buff->getNumIndices()); actual_tris += buff->getNumIndices()/3; actual_verts += buff->getNumVerts(); ++submeshes; - + if (!validate_face(target_model->getVolumeFace(names[i]))) { llerrs << "Invalid face generated during LOD generation." << llendl; } } - + //blind copy skin weights and just take closest skin weight to point on //decimated mesh for now (auto-generating LODs with skin weights is still a bit //of an open problem). @@ -2988,20 +2989,20 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation) target_model->mAlternateBindMatrix = base->mAlternateBindMatrix; //copy material list target_model->mMaterialList = base->mMaterialList; - + if (!validate_model(target_model)) { llerrs << "Invalid model generated when creating LODs" << llendl; } - + delete [] sizes; delete [] names; } - + //rebuild scene based on mBaseScene mScene[lod].clear(); mScene[lod] = mBaseScene; - + for (U32 i = 0; i < mBaseModel.size(); ++i) { LLModel* mdl = mBaseModel[i]; @@ -3021,14 +3022,14 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation) } } } - + mResourceCost = calcResourceCost(); - + /*if (which_lod == -1 && mScene[LLModel::LOD_PHYSICS].empty()) { //build physics scene mScene[LLModel::LOD_PHYSICS] = mScene[LLModel::LOD_LOW]; mModel[LLModel::LOD_PHYSICS] = mModel[LLModel::LOD_LOW]; - + for (U32 i = 1; i < mModel[LLModel::LOD_PHYSICS].size(); ++i) { mPhysicsQ.push(mModel[LLModel::LOD_PHYSICS][i]); @@ -3039,47 +3040,47 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation) void LLModelPreview::updateStatusMessages() { assert_main_thread(); - + //triangle/vertex/submesh count for each mesh asset for each lod std::vector tris[LLModel::NUM_LODS]; std::vector verts[LLModel::NUM_LODS]; std::vector submeshes[LLModel::NUM_LODS]; - + //total triangle/vertex/submesh count for each lod S32 total_tris[LLModel::NUM_LODS]; S32 total_verts[LLModel::NUM_LODS]; S32 total_submeshes[LLModel::NUM_LODS]; - + for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) { //initialize total for this lod to 0 total_tris[lod] = total_verts[lod] = total_submeshes[lod] = 0; - + for (U32 i = 0; i < mModel[lod].size(); ++i) { //for each model in the lod S32 cur_tris = 0; S32 cur_verts = 0; S32 cur_submeshes = mModel[lod][i]->getNumVolumeFaces(); - + for (S32 j = 0; j < cur_submeshes; ++j) { //for each submesh (face), add triangles and vertices to current total const LLVolumeFace& face = mModel[lod][i]->getVolumeFace(j); cur_tris += face.mNumIndices/3; cur_verts += face.mNumVertices; } - + //add this model to the lod total total_tris[lod] += cur_tris; total_verts[lod] += cur_verts; total_submeshes[lod] += cur_submeshes; - + //store this model's counts to asset data tris[lod].push_back(cur_tris); verts[lod].push_back(cur_verts); submeshes[lod].push_back(cur_submeshes); } } - + if (mMaxTriangleLimit == 0) { mMaxTriangleLimit = total_tris[LLModel::LOD_HIGH]; @@ -3087,11 +3088,11 @@ void LLModelPreview::updateStatusMessages() mFMP->childSetTextArg("submeshes_info", "[SUBMESHES]", llformat("%d", total_submeshes[LLModel::LOD_HIGH])); - + std::string mesh_status_na = mFMP->getString("mesh_status_na"); - + S32 upload_status[LLModel::LOD_HIGH+1]; - + bool upload_ok = true; for (S32 lod = 0; lod <= LLModel::LOD_HIGH; ++lod) @@ -3127,9 +3128,9 @@ void LLModelPreview::updateStatusMessages() mFMP->childSetText(lod_triangles_name[lod], mesh_status_na); mFMP->childSetText(lod_vertices_name[lod], mesh_status_na); } - + const U32 lod_high = LLModel::LOD_HIGH; - + if (lod != lod_high) { if (total_submeshes[lod] && total_submeshes[lod] != total_submeshes[lod_high]) @@ -3147,7 +3148,7 @@ void LLModelPreview::updateStatusMessages() for (U32 i = 0; i < verts[lod].size(); ++i) { S32 max_verts = i < verts[lod+1].size() ? verts[lod+1][i] : 0; - + if (max_verts > 0) { if (verts[lod][i] > max_verts) @@ -3159,12 +3160,12 @@ void LLModelPreview::updateStatusMessages() } } } - + LLIconCtrl* icon = mFMP->getChild(lod_icon_name[lod]); LLUIImagePtr img = LLUI::getUIImage(lod_status_image[upload_status[lod]]); icon->setVisible(true); icon->setImage(img); - + if (upload_status[lod] >= 2) { upload_ok = false; @@ -3177,9 +3178,9 @@ void LLModelPreview::updateStatusMessages() icon->setImage(img); } } - + bool errorStateFromLoader = mModelLoader->getLoadState() == LLModelLoader::ERROR_PARSING ? true : false; - + if ( upload_ok && !errorStateFromLoader ) { mFMP->childEnable("ok_btn"); @@ -3262,7 +3263,7 @@ void LLModelPreview::updateStatusMessages() //bool use_hull = fmp->childGetValue("physics_use_hull").asBoolean(); //fmp->childSetEnabled("physics_optimize", !use_hull); - + bool enable = phys_tris > 0 || phys_hulls > 0; //enable = enable && !use_hull && fmp->childGetValue("physics_optimize").asBoolean(); @@ -3283,10 +3284,10 @@ void LLModelPreview::updateStatusMessages() { child->setEnabled(enable); child = panel->findNextSibling(child); - } + } } - const char* lod_controls[] = + const char* lod_controls[] = { "lod_mode", "lod_triangle_limit", @@ -3311,7 +3312,7 @@ void LLModelPreview::updateStatusMessages() //enable/disable controls based on radio groups if (mFMP->childGetValue("lod_from_file").asBoolean()) - { + { for (U32 i = 0; i < num_file_controls; ++i) { mFMP->childEnable(file_controls[i]); @@ -3322,7 +3323,7 @@ void LLModelPreview::updateStatusMessages() mFMP->childDisable(lod_controls[i]); } - + } else if (mFMP->childGetValue("lod_none").asBoolean()) { @@ -3346,8 +3347,8 @@ void LLModelPreview::updateStatusMessages() updateStatusMessages(); return; } - - + + } else { // auto generate, also the default case for wizard which has no radio selection @@ -3362,7 +3363,7 @@ void LLModelPreview::updateStatusMessages() } //if (threshold) - { + { U32 lod_mode = 0; LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode"); if (iface) @@ -3406,7 +3407,7 @@ void LLModelPreview::updateStatusMessages() } void LLModelPreview::setPreviewTarget(F32 distance) -{ +{ mCameraDistance = distance; mCameraZoom = 1.f; mCameraPitch = 0.f; @@ -3427,9 +3428,9 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights) U32 tri_count = 0; U32 vertex_count = 0; U32 mesh_count = 0; - + LLModelLoader::model_list* model = NULL; - + if (lod < 0 || lod > 4) { model = &mBaseModel; @@ -3439,16 +3440,16 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights) { model = &(mModel[lod]); } - + if (!mVertexBuffer[lod].empty()) { mVertexBuffer[lod].clear(); } - + mVertexBuffer[lod].clear(); - + LLModelLoader::model_list::iterator base_iter = mBaseModel.begin(); - + for (LLModelLoader::model_list::iterator iter = model->begin(); iter != model->end(); ++iter) { LLModel* mdl = *iter; @@ -3456,94 +3457,94 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights) { continue; } - + LLModel* base_mdl = *base_iter; base_iter++; - + for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) { const LLVolumeFace &vf = mdl->getVolumeFace(i); U32 num_vertices = vf.mNumVertices; U32 num_indices = vf.mNumIndices; - + if (!num_vertices || ! num_indices) { continue; } - + LLVertexBuffer* vb = NULL; - + bool skinned = include_skin_weights && !mdl->mSkinWeights.empty(); - + U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; - + if (skinned) { mask |= LLVertexBuffer::MAP_WEIGHT4; } - + vb = new LLVertexBuffer(mask, 0); - + vb->allocateBuffer(num_vertices, num_indices, TRUE); - + LLStrider vertex_strider; LLStrider normal_strider; LLStrider tc_strider; LLStrider index_strider; LLStrider weights_strider; - + vb->getVertexStrider(vertex_strider); vb->getNormalStrider(normal_strider); vb->getTexCoord0Strider(tc_strider); vb->getIndexStrider(index_strider); - + if (skinned) { vb->getWeight4Strider(weights_strider); } - + LLVector4a::memcpyNonAliased16((F32*) vertex_strider.get(), (F32*) vf.mPositions, num_vertices*4*sizeof(F32)); LLVector4a::memcpyNonAliased16((F32*) tc_strider.get(), (F32*) vf.mTexCoords, num_vertices*2*sizeof(F32)); LLVector4a::memcpyNonAliased16((F32*) normal_strider.get(), (F32*) vf.mNormals, num_vertices*4*sizeof(F32)); - + if (skinned) { for (U32 i = 0; i < num_vertices; i++) { //find closest weight to vf.mVertices[i].mPosition LLVector3 pos(vf.mPositions[i].getF32ptr()); - + const LLModel::weight_list& weight_list = base_mdl->getJointInfluences(pos); - + LLVector4 w(0,0,0,0); if (weight_list.size() > 4) { llerrs << "WTF?" << llendl; } - + for (U32 i = 0; i < weight_list.size(); ++i) { F32 wght = llmin(weight_list[i].mWeight, 0.999999f); F32 joint = (F32) weight_list[i].mJointIdx; w.mV[i] = joint + wght; } - + *(weights_strider++) = w; } } - + // build indices for (U32 i = 0; i < num_indices; i++) { *(index_strider++) = vf.mIndices[i]; } - + mVertexBuffer[lod][mdl].push_back(vb); - + vertex_count += num_vertices; tri_count += num_indices/3; ++mesh_count; - + } } } @@ -3574,10 +3575,10 @@ void LLModelPreview::update() BOOL LLModelPreview::render() { assert_main_thread(); - + LLMutexLock lock(this); mNeedsUpdate = FALSE; - + bool edges = false; bool joint_positions = false; bool skin_weight = false; @@ -3596,28 +3597,28 @@ BOOL LLModelPreview::render() S32 width = getWidth(); S32 height = getHeight(); - + LLGLSUIDefault def; LLGLDisable no_blend(GL_BLEND); LLGLEnable cull(GL_CULL_FACE); LLGLDepthTest depth(GL_TRUE); LLGLDisable fog(GL_FOG); - + { //clear background to blue glMatrixMode(GL_PROJECTION); gGL.pushMatrix(); glLoadIdentity(); glOrtho(0.0f, width, 0.0f, height, -1.0f, 1.0f); - + glMatrixMode(GL_MODELVIEW); gGL.pushMatrix(); glLoadIdentity(); - + gGL.color4f(0.15f, 0.2f, 0.3f, 1.f); - + gl_rect_2d_simple( width, height ); - + glMatrixMode(GL_PROJECTION); gGL.popMatrix(); @@ -3628,7 +3629,7 @@ BOOL LLModelPreview::render() bool has_skin_weights = false; bool upload_skin = mFMP->childGetValue("upload_skin").asBoolean(); bool upload_joints = mFMP->childGetValue("upload_joints").asBoolean(); - + for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) { for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) @@ -3662,79 +3663,79 @@ BOOL LLModelPreview::render() } skin_weight = false; } - + if (upload_skin && !has_skin_weights) { //can't upload skin weights if model has no skin weights mFMP->childSetValue("upload_skin", false); upload_skin = false; } - + if (!upload_skin && upload_joints) { //can't upload joints if not uploading skin weights mFMP->childSetValue("upload_joints", false); upload_joints = false; } - + mFMP->childSetEnabled("upload_joints", upload_skin); - + F32 explode = mFMP->childGetValue("physics_explode").asReal(); - + glClear(GL_DEPTH_BUFFER_BIT); - + LLRect preview_rect = mFMP->getChildView("preview_panel")->getRect(); F32 aspect = (F32) preview_rect.getWidth()/preview_rect.getHeight(); LLViewerCamera::getInstance()->setAspect(aspect); - + LLViewerCamera::getInstance()->setView(LLViewerCamera::getInstance()->getDefaultFOV() / mCameraZoom); - + LLVector3 offset = mCameraOffset; LLVector3 target_pos = mPreviewTarget+offset; - + F32 z_near = 0.001f; F32 z_far = mCameraDistance+mPreviewScale.magVec()+mCameraOffset.magVec(); - + if (skin_weight) { target_pos = gAgentAvatarp->getPositionAgent(); z_near = 0.01f; z_far = 1024.f; mCameraDistance = 16.f; - + //render avatar previews every frame refresh(); } - + glLoadIdentity(); gPipeline.enableLightsPreview(); - LLQuaternion camera_rot = LLQuaternion(mCameraPitch, LLVector3::y_axis) * + LLQuaternion camera_rot = LLQuaternion(mCameraPitch, LLVector3::y_axis) * LLQuaternion(mCameraYaw, LLVector3::z_axis); - + LLQuaternion av_rot = camera_rot; LLViewerCamera::getInstance()->setOriginAndLookAt( target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + offset) * av_rot), // camera LLVector3::z_axis, // up target_pos); // point of interest - - + + LLViewerCamera::getInstance()->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, width, height, FALSE, z_near, z_far); - + stop_glerror(); - + gGL.pushMatrix(); const F32 BRIGHTNESS = 0.9f; gGL.color3f(BRIGHTNESS, BRIGHTNESS, BRIGHTNESS); - + LLGLEnable normalize(GL_NORMALIZE); - + if (!mBaseModel.empty() && mVertexBuffer[5].empty()) { genBuffers(-1, skin_weight); //genBuffers(3); //genLODs(); } - + if (!mModel[mPreviewLOD].empty()) { bool regen = mVertexBuffer[mPreviewLOD].empty(); @@ -3752,31 +3753,31 @@ BOOL LLModelPreview::render() { genBuffers(mPreviewLOD, skin_weight); } - + if (!skin_weight) { for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) { LLModelInstance& instance = *iter; - + LLModel* model = instance.mLOD[mPreviewLOD]; - + if (!model) { continue; } - + gGL.pushMatrix(); LLMatrix4 mat = instance.mTransform; - glMultMatrixf((GLfloat*) mat.mMatrix); - + glMultMatrixf((GLfloat*) mat.mMatrix); + for (U32 i = 0; i < mVertexBuffer[mPreviewLOD][model].size(); ++i) { LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; - + buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); - + if (textures) { glColor4fv(instance.mMaterial[i].mDiffuseColor.mV); @@ -3793,11 +3794,11 @@ BOOL LLModelPreview::render() { glColor4f(1,1,1,1); } - + buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); glColor3f(0.4f, 0.4f, 0.4f); - + if (edges) { glLineWidth(3.f); @@ -3809,7 +3810,7 @@ BOOL LLModelPreview::render() } gGL.popMatrix(); } - + if (physics) { glClear(GL_DEPTH_BUFFER_BIT); @@ -3819,7 +3820,7 @@ BOOL LLModelPreview::render() for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) { LLModelInstance& instance = *iter; - + LLModel* model = instance.mLOD[LLModel::LOD_PHYSICS]; if (!model) @@ -3830,17 +3831,17 @@ BOOL LLModelPreview::render() gGL.pushMatrix(); LLMatrix4 mat = instance.mTransform; - glMultMatrixf((GLfloat*) mat.mMatrix); + glMultMatrixf((GLfloat*) mat.mMatrix); + - bool render_mesh = true; LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread; if (decomp) { LLMutexLock(decomp->mMutex); - - std::map, std::vector > >::iterator iter = + + std::map, std::vector > >::iterator iter = mPhysicsMesh.find(model); if (iter != mPhysicsMesh.end()) { //render hull instead of mesh @@ -3850,29 +3851,29 @@ BOOL LLModelPreview::render() if (explode > 0.f) { gGL.pushMatrix(); - + LLVector3 offset = model->mHullCenter[i]-model->mCenterOfHullCenters; offset *= explode; - + gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]); } - + static std::vector hull_colors; - + if (i+1 >= hull_colors.size()) { hull_colors.push_back(LLColor4U(rand()%128+127, rand()%128+127, rand()%128+127, 255)); } - + LLVertexBuffer* buff = iter->second[i]; if (buff) { - buff->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL); - + buff->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL); + glColor4ubv(hull_colors[i].mV); buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts()); } - + if (explode > 0.f) { gGL.popMatrix(); @@ -3880,7 +3881,7 @@ BOOL LLModelPreview::render() } } } - + if (render_mesh) { if (mVertexBuffer[LLModel::LOD_PHYSICS].empty()) @@ -3892,15 +3893,15 @@ BOOL LLModelPreview::render() LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][i]; buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); - + buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); glColor4f(0.4f, 0.4f, 0.0f, 0.4f); - + buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); glColor3f(1.f, 1.f, 0.f); - + glLineWidth(3.f); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); @@ -3908,10 +3909,10 @@ BOOL LLModelPreview::render() glLineWidth(1.f); } } - + gGL.popMatrix(); } - + gGL.setSceneBlendType(LLRender::BT_ALPHA); } } @@ -3919,40 +3920,40 @@ BOOL LLModelPreview::render() { LLVOAvatarSelf* avatar = gAgentAvatarp; target_pos = avatar->getPositionAgent(); - + LLViewerCamera::getInstance()->setOriginAndLookAt( target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + offset) * av_rot), // camera LLVector3::z_axis, // up target_pos); // point of interest - + if (joint_positions) { avatar->renderCollisionVolumes(); } - + for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) { for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) { LLModelInstance& instance = *model_iter; LLModel* model = instance.mModel; - + if (!model->mSkinWeights.empty()) { for (U32 i = 0; i < mVertexBuffer[mPreviewLOD][model].size(); ++i) { LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; - + const LLVolumeFace& face = model->getVolumeFace(i); - + LLStrider position; buffer->getVertexStrider(position); - + LLStrider weight; buffer->getWeight4Strider(weight); - + //quick 'n dirty software vertex skinning - + //build matrix palette LLMatrix4 mat[64]; for (U32 j = 0; j < model->mJointList.size(); ++j) @@ -3964,55 +3965,55 @@ BOOL LLModelPreview::render() mat[j] *= joint->getWorldMatrix(); } } - + for (U32 j = 0; j < buffer->getRequestedVerts(); ++j) { LLMatrix4 final_mat; final_mat.mMatrix[0][0] = final_mat.mMatrix[1][1] = final_mat.mMatrix[2][2] = final_mat.mMatrix[3][3] = 0.f; - + LLVector4 wght; S32 idx[4]; - + F32 scale = 0.f; for (U32 k = 0; k < 4; k++) { F32 w = weight[j].mV[k]; - + idx[k] = (S32) floorf(w); wght.mV[k] = w - floorf(w); scale += wght.mV[k]; } - - wght *= 1.f/scale; - + + wght *= 1.f/scale; + for (U32 k = 0; k < 4; k++) { F32* src = (F32*) mat[idx[k]].mMatrix; F32* dst = (F32*) final_mat.mMatrix; - + F32 w = wght.mV[k]; - + for (U32 l = 0; l < 16; l++) { dst[l] += src[l]*w; } } - + //VECTORIZE THIS LLVector3 v(face.mPositions[j].getF32ptr()); - + v = v * model->mBindShapeMatrix; v = v * final_mat; - + position[j] = v; } - + buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); glColor4fv(instance.mMaterial[i].mDiffuseColor.mV); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); glColor3f(0.4f, 0.4f, 0.4f); - + if (edges) { glLineWidth(3.f); @@ -4027,9 +4028,9 @@ BOOL LLModelPreview::render() } } } - + gGL.popMatrix(); - + return TRUE; } @@ -4037,8 +4038,8 @@ BOOL LLModelPreview::render() // refresh() //----------------------------------------------------------------------------- void LLModelPreview::refresh() -{ - mNeedsUpdate = TRUE; +{ + mNeedsUpdate = TRUE; } //----------------------------------------------------------------------------- @@ -4047,7 +4048,7 @@ void LLModelPreview::refresh() void LLModelPreview::rotate(F32 yaw_radians, F32 pitch_radians) { mCameraYaw = mCameraYaw + yaw_radians; - + mCameraPitch = llclamp(mCameraPitch + pitch_radians, F_PI_BY_TWO * -0.8f, F_PI_BY_TWO * 0.8f); } @@ -4057,7 +4058,7 @@ void LLModelPreview::rotate(F32 yaw_radians, F32 pitch_radians) void LLModelPreview::zoom(F32 zoom_amt) { F32 new_zoom = mCameraZoom+zoom_amt; - + mCameraZoom = llclamp(new_zoom, 1.f, 10.f); } @@ -4074,7 +4075,7 @@ void LLModelPreview::setPreviewLOD(S32 lod) if (lod != mPreviewLOD) { mPreviewLOD = lod; - + LLComboBox* combo_box = mFMP->getChild("preview_lod_combo"); combo_box->setCurrentByIndex((NUM_LOD-1)-mPreviewLOD); // combo box list of lods is in reverse order mFMP->childSetTextArg("lod_table_footer", "[DETAIL]", mFMP->getString(lod_name[mPreviewLOD])); @@ -4097,11 +4098,11 @@ void LLModelPreview::setPreviewLOD(S32 lod) updateStatusMessages(); } -//static +//static void LLFloaterModelPreview::onBrowseLOD(void* data) { assert_main_thread(); - + LLFloaterModelPreview* mp = (LLFloaterModelPreview*) data; mp->loadModel(mp->mModelPreview->mPreviewLOD); } @@ -4110,26 +4111,26 @@ void LLFloaterModelPreview::onBrowseLOD(void* data) void LLFloaterModelPreview::onUpload(void* user_data) { assert_main_thread(); - + LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; mp->mModelPreview->rebuildUploadData(); - - gMeshRepo.uploadModel(mp->mModelPreview->mUploadData, mp->mModelPreview->mPreviewScale, + + gMeshRepo.uploadModel(mp->mModelPreview->mUploadData, mp->mModelPreview->mPreviewScale, mp->childGetValue("upload_textures").asBoolean(), mp->childGetValue("upload_skin"), mp->childGetValue("upload_joints")); - + mp->closeFloater(false); } -//static +//static void LLFloaterModelPreview::onClearMaterials(void* user_data) { LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; mp->mModelPreview->clearMaterials(); } -//static +//static void LLFloaterModelPreview::refresh(LLUICtrl* ctrl, void* user_data) { sInstance->mModelPreview->mDirty = true; @@ -4155,15 +4156,15 @@ LLFloaterModelPreview::DecompRequest::DecompRequest(const std::string& stage, LL mModel = mdl; mDecompID = &mdl->mDecompID; mParams = sInstance->mDecompParams; - + //copy out positions and indices if (mdl) { U16 index_offset = 0; - + mPositions.clear(); mIndices.clear(); - + //queue up vertex positions and indices for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) { @@ -4172,17 +4173,17 @@ LLFloaterModelPreview::DecompRequest::DecompRequest(const std::string& stage, LL { continue; } - + for (U32 j = 0; j < face.mNumVertices; ++j) { mPositions.push_back(LLVector3(face.mPositions[j].getF32ptr())); } - + for (U32 j = 0; j < face.mNumIndices; ++j) { mIndices.push_back(face.mIndices[j]+index_offset); } - + index_offset += face.mNumVertices; } } @@ -4208,16 +4209,16 @@ S32 LLFloaterModelPreview::DecompRequest::statusCallback(const char* status, S32 void LLFloaterModelPreview::DecompRequest::completed() { //called from the main thread mModel->setConvexHullDecomposition(mHull); - - if (sInstance) - { + + if (sInstance) + { if (sInstance->mModelPreview) { sInstance->mModelPreview->mPhysicsMesh[mModel] = mHullMesh; sInstance->mModelPreview->mDirty = true; LLFloaterModelPreview::sInstance->mModelPreview->refresh(); } - + sInstance->mCurRequest.erase(this); } } -- cgit v1.2.3 From 8ba0baa63109d5e45c1f3cfd75c7d230ff99031f Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Wed, 22 Dec 2010 10:55:48 -0700 Subject: fix for SH-648: Crash on exit in LLViewerFetchedTexture (ref count error) --- indra/newview/llfloatermodelpreview.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 85d0ae02cf..cc4359a1bf 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -475,10 +475,10 @@ void LLFloaterModelPreview::onPreviewLODCommit(LLUICtrl* ctrl, void* userdata) S32 which_mode = 0; - LLComboBox* combo = (LLComboBox*) ctrl; - - which_mode = (NUM_LOD-1)-combo->getFirstSelectedIndex(); // combo box list of lods is in reverse order - + LLComboBox* combo = (LLComboBox*) ctrl; + + which_mode = (NUM_LOD-1)-combo->getFirstSelectedIndex(); // combo box list of lods is in reverse order + fp->mModelPreview->setPreviewLOD(which_mode); } -- cgit v1.2.3 From 07d3480ec35a9a5bade25acb99fc39935bad38a2 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 22 Dec 2010 15:18:55 -0600 Subject: SH-658 Preserve LOD mode when switching between preview LoDs. --- indra/newview/llfloatermodelpreview.cpp | 143 ++++++++++++++++++-------------- 1 file changed, 80 insertions(+), 63 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 1050e86060..39af84cfa0 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -89,6 +89,7 @@ #include "llstring.h" #include "llbutton.h" #include "llcheckboxctrl.h" +#include "llradiogroup.h" #include "llsliderctrl.h" #include "llspinctrl.h" #include "lltoggleablemenu.h" @@ -257,6 +258,12 @@ LLFloater(key) mLastMouseY = 0; mGLName = 0; mStatusLock = new LLMutex(NULL); + + mLODMode[LLModel::LOD_HIGH] = 0; + for (U32 i = 0; i < LLModel::LOD_HIGH; i++) + { + mLODMode[i] = 1; + } } //----------------------------------------------------------------------------- @@ -3309,84 +3316,87 @@ void LLModelPreview::updateStatusMessages() }; const U32 num_file_controls = sizeof(file_controls)/sizeof(char*); - //enable/disable controls based on radio groups - if (mFMP->childGetValue("lod_from_file").asBoolean()) - { - for (U32 i = 0; i < num_file_controls; ++i) - { - mFMP->childEnable(file_controls[i]); - } - - for (U32 i = 0; i < num_lod_controls; ++i) - { - mFMP->childDisable(lod_controls[i]); - } - - - } - else if (mFMP->childGetValue("lod_none").asBoolean()) + if (fmp) { - for (U32 i = 0; i < num_file_controls; ++i) - { - mFMP->childDisable(file_controls[i]); - } + //enable/disable controls based on radio groups + if (mFMP->childGetValue("lod_from_file").asBoolean()) + { + fmp->mLODMode[mPreviewLOD] = 0; + for (U32 i = 0; i < num_file_controls; ++i) + { + mFMP->childEnable(file_controls[i]); + } - for (U32 i = 0; i < num_lod_controls; ++i) - { - mFMP->childDisable(lod_controls[i]); + for (U32 i = 0; i < num_lod_controls; ++i) + { + mFMP->childDisable(lod_controls[i]); + } } - - if (!mModel[mPreviewLOD].empty()) + else if (mFMP->childGetValue("lod_none").asBoolean()) { - mModel[mPreviewLOD].clear(); - mScene[mPreviewLOD].clear(); - mVertexBuffer[mPreviewLOD].clear(); + fmp->mLODMode[mPreviewLOD] = 2; + for (U32 i = 0; i < num_file_controls; ++i) + { + mFMP->childDisable(file_controls[i]); + } - //this can cause phasing issues with the UI, so reenter this function and return - updateStatusMessages(); - return; - } - - - } - else - { // auto generate, also the default case for wizard which has no radio selection - for (U32 i = 0; i < num_file_controls; ++i) - { - mFMP->childDisable(file_controls[i]); - } + for (U32 i = 0; i < num_lod_controls; ++i) + { + mFMP->childDisable(lod_controls[i]); + } - for (U32 i = 0; i < num_lod_controls; ++i) - { - mFMP->childEnable(lod_controls[i]); + if (!mModel[mPreviewLOD].empty()) + { + mModel[mPreviewLOD].clear(); + mScene[mPreviewLOD].clear(); + mVertexBuffer[mPreviewLOD].clear(); + + //this can cause phasing issues with the UI, so reenter this function and return + updateStatusMessages(); + return; + } } + else + { // auto generate, also the default case for wizard which has no radio selection + fmp->mLODMode[mPreviewLOD] = 1; - //if (threshold) - { - U32 lod_mode = 0; - LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode"); - if (iface) + for (U32 i = 0; i < num_file_controls; ++i) { - lod_mode = iface->getFirstSelectedIndex(); + mFMP->childDisable(file_controls[i]); } - LLSpinCtrl* threshold = mFMP->getChild("lod_error_threshold"); - LLSpinCtrl* limit = mFMP->getChild("lod_triangle_limit"); + for (U32 i = 0; i < num_lod_controls; ++i) + { + mFMP->childEnable(lod_controls[i]); + } - limit->setMaxValue(mMaxTriangleLimit); - limit->setValue(total_tris[mPreviewLOD]); + //if (threshold) + { + U32 lod_mode = 0; + LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode"); + if (iface) + { + lod_mode = iface->getFirstSelectedIndex(); + } - if (lod_mode == 0) - { - limit->setVisible(true); - threshold->setVisible(false); + LLSpinCtrl* threshold = mFMP->getChild("lod_error_threshold"); + LLSpinCtrl* limit = mFMP->getChild("lod_triangle_limit"); limit->setMaxValue(mMaxTriangleLimit); - } - else - { - limit->setVisible(false); - threshold->setVisible(true); + limit->setValue(total_tris[mPreviewLOD]); + + if (lod_mode == 0) + { + limit->setVisible(true); + threshold->setVisible(false); + + limit->setMaxValue(mMaxTriangleLimit); + } + else + { + limit->setVisible(false); + threshold->setVisible(true); + } } } } @@ -4092,6 +4102,13 @@ void LLModelPreview::setPreviewLOD(S32 lod) mFMP->childSetColor(lod_triangles_name[i], color); mFMP->childSetColor(lod_vertices_name[i], color); } + + LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; + if (fmp) + { + LLRadioGroup* radio = fmp->getChild("lod_file_or_limit"); + radio->selectNthItem(fmp->mLODMode[mPreviewLOD]); + } } refresh(); updateStatusMessages(); -- cgit v1.2.3 From 6262c4a427422ea82bbdafd7e701b700784663a6 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 29 Dec 2010 15:48:59 -0600 Subject: SH-632 Fix for auto generating mesh LODs sometimes reducing High LOD triangle count. --- indra/newview/llfloatermodelpreview.cpp | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 2f1ce25511..68b9e5d23d 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -2879,6 +2879,13 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation) { start = end = which_lod; } + else + { + //SH-632 -- incremenet triangle count to avoid removing any triangles from + //highest LoD when auto-generating LoD + triangle_count++; + } + mMaxTriangleLimit = base_triangle_count; -- cgit v1.2.3 From 13ec64e0e6a107d21108e817c5f9e33b6c929525 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Thu, 30 Dec 2010 16:07:18 -0600 Subject: SH-714 Fix for skinned meshes being incorrectly scaled. --- indra/newview/llfloatermodelpreview.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 68b9e5d23d..8302befaad 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1562,11 +1562,23 @@ void LLModelLoader::run() //add instance to scene for this model - LLMatrix4 transform; + LLMatrix4 transformation = mTransform; + // adjust the transformation to compensate for mesh normalization + + LLMatrix4 mesh_translation; + mesh_translation.setTranslation(mesh_translation_vector); + mesh_translation *= transformation; + transformation = mesh_translation; + + LLMatrix4 mesh_scale; + mesh_scale.initScale(mesh_scale_vector); + mesh_scale *= transformation; + transformation = mesh_scale; + std::vector materials; materials.resize(model->getNumVolumeFaces()); - mScene[transform].push_back(LLModelInstance(model, transform, materials)); - stretch_extents(model, transform, mExtents[0], mExtents[1], mFirstTransform); + mScene[transformation].push_back(LLModelInstance(model, transformation, materials)); + stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); } } } -- cgit v1.2.3 From ca9df698db9c7a118d29adfe52f49054c333d982 Mon Sep 17 00:00:00 2001 From: Roxie Linden Date: Thu, 30 Dec 2010 22:08:25 -0800 Subject: Code review fix from davep - use booling or operator and not binary one Remove unnecessary state check. Initial dialog work for showing physics cost in upload dialog --- indra/newview/llfloatermodelpreview.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 2f1ce25511..f96c02d9b7 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -2055,6 +2055,7 @@ U32 LLModelPreview::calcResourceCost() F32 debug_scale = mFMP->childGetValue("import_scale").asReal(); F32 streaming_cost = 0.f; + F32 physics_cost = 0.f; for (U32 i = 0; i < mUploadData.size(); ++i) { LLModelInstance& instance = mUploadData[i]; @@ -2109,6 +2110,7 @@ U32 LLModelPreview::calcResourceCost() //mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[HULLS]", llformat("%d",num_hulls)); //mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[POINTS]", llformat("%d",num_points)); mFMP->childSetTextArg("streaming cost", "[COST]", llformat("%.3f", streaming_cost)); + mFMP->childSetTextArg("physics cost", "[COST]", llformat("%.3f", physics_cost)); F32 scale = mFMP->childGetValue("import_scale").asReal()*2.f; mFMP->childSetTextArg("import_dimensions", "[X]", llformat("%.3f", mPreviewScale[0]*scale)); mFMP->childSetTextArg("import_dimensions", "[Y]", llformat("%.3f", mPreviewScale[1]*scale)); -- cgit v1.2.3 From d196348d0f4bd542eee3702329dab28952b8a5e5 Mon Sep 17 00:00:00 2001 From: leyla_linden Date: Fri, 31 Dec 2010 12:53:39 -0800 Subject: Physics stage of wizard --- indra/newview/llfloatermodelpreview.cpp | 58 +++++++++++++++++---------------- 1 file changed, 30 insertions(+), 28 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 2f1ce25511..41fbdab2de 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -276,7 +276,10 @@ BOOL LLFloaterModelPreview::postBuild() return FALSE; } - setViewOption("show_textures", true); + + + + childSetAction("lod_browse", onBrowseLOD, this); @@ -393,13 +396,22 @@ LLFloaterModelPreview::~LLFloaterModelPreview() void LLFloaterModelPreview::onViewOptionChecked(const LLSD& userdata) { - mViewOption[userdata.asString()] = !mViewOption[userdata.asString()]; - mModelPreview->refresh(); + if (mModelPreview) + { + mModelPreview->mViewOption[userdata.asString()] = !mModelPreview->mViewOption[userdata.asString()]; + + mModelPreview->refresh(); + } } bool LLFloaterModelPreview::isViewOptionChecked(const LLSD& userdata) { - return mViewOption[userdata.asString()]; + if (mModelPreview) + { + return mModelPreview->mViewOption[userdata.asString()]; + } + + return false; } bool LLFloaterModelPreview::isViewOptionEnabled(const LLSD& userdata) @@ -422,11 +434,6 @@ void LLFloaterModelPreview::disableViewOption(const std::string& option) setViewOptionEnabled(option, false); } -void LLFloaterModelPreview::setViewOption(const std::string& option, bool value) -{ - mViewOption[option] = value; -} - void LLFloaterModelPreview::loadModel(S32 lod) { mModelPreview->mLoading = true; @@ -2017,7 +2024,9 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) mBuildShareTolerance = 0.f; mBuildQueueMode = GLOD_QUEUE_GREEDY; mBuildBorderMode = GLOD_BORDER_UNLOCK; - mBuildOperator = GLOD_OPERATOR_HALF_EDGE_COLLAPSE; + mBuildOperator = GLOD_OPERATOR_HALF_EDGE_COLLAPSE; + + mViewOption["show_textures"] = false; mFMP = fmp; @@ -3258,13 +3267,14 @@ void LLModelPreview::updateStatusMessages() if (!fmp->isViewOptionEnabled("show_physics")) { fmp->enableViewOption("show_physics"); - fmp->setViewOption("show_physics", true); + mViewOption["show_physics"] = true; } } else { fmp->disableViewOption("show_physics"); - fmp->setViewOption("show_physics", false); + mViewOption["show_physics"] = false; + } //bool use_hull = fmp->childGetValue("physics_use_hull").asBoolean(); @@ -3589,21 +3599,11 @@ BOOL LLModelPreview::render() LLMutexLock lock(this); mNeedsUpdate = FALSE; - bool edges = false; - bool joint_positions = false; - bool skin_weight = false; - bool textures = false; - bool physics = false; - - LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; - if (fmp) - { - edges = fmp->isViewOptionChecked("show_edges"); - joint_positions = fmp->isViewOptionChecked("show_joint_positions"); - skin_weight = fmp->isViewOptionChecked("show_skin_weight"); - textures = fmp->isViewOptionChecked("show_textures"); - physics = fmp->isViewOptionChecked("show_physics"); - } + bool edges = mViewOption["show_edges"]; + bool joint_positions = mViewOption["show_joint_positions"]; + bool skin_weight = mViewOption["show_skin_weight"]; + bool textures = mViewOption["show_textures"]; + bool physics = mViewOption["show_physics"]; S32 width = getWidth(); S32 height = getHeight(); @@ -3636,6 +3636,8 @@ BOOL LLModelPreview::render() gGL.popMatrix(); } + LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; + bool has_skin_weights = false; bool upload_skin = mFMP->childGetValue("upload_skin").asBoolean(); bool upload_joints = mFMP->childGetValue("upload_joints").asBoolean(); @@ -3667,7 +3669,7 @@ BOOL LLModelPreview::render() mFMP->childDisable("upload_skin"); if (fmp) { - fmp->setViewOption("show_skin_weight", false); + mViewOption["show_skin_weight"] = false; fmp->disableViewOption("show_skin_weight"); fmp->disableViewOption("show_joint_positions"); } -- cgit v1.2.3 From 33d9b10fbb9d3de79d389174c92e5b852dbbccdc Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Fri, 31 Dec 2010 16:48:50 -0600 Subject: SH-727 Working cancel button and cancel buttons for physics decomp stages. --- indra/newview/llfloatermodelpreview.cpp | 60 ++++++++++++++++++++++++++------- 1 file changed, 48 insertions(+), 12 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 8302befaad..2f59621e28 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -280,6 +280,7 @@ BOOL LLFloaterModelPreview::postBuild() childSetAction("lod_browse", onBrowseLOD, this); + childSetCommitCallback("cancel_btn", onCancel, this); childSetCommitCallback("crease_angle", onGenerateNormalsCommit, this); childSetCommitCallback("generate_normals", onGenerateNormalsCommit, this); @@ -552,7 +553,14 @@ void LLFloaterModelPreview::draw() LLMutexLock lock(mStatusLock); childSetTextArg("status", "[STATUS]", mStatusMessage); } - + else + { + childSetVisible("Simplify", true); + childSetVisible("simplify_cancel", false); + childSetVisible("Decompose", true); + childSetVisible("decompose_cancel", false); + } + U32 resource_cost = mModelPreview->mResourceCost*10; if (childGetValue("upload_textures").asBoolean()) @@ -728,7 +736,8 @@ void LLFloaterModelPreview::onPhysicsParamCommit(LLUICtrl* ctrl, void* data) //static void LLFloaterModelPreview::onPhysicsStageExecute(LLUICtrl* ctrl, void* data) { - LLCDStageData* stage = (LLCDStageData*) data; + LLCDStageData* stage_data = (LLCDStageData*) data; + std::string stage = stage_data->mName; if (sInstance) { @@ -743,11 +752,22 @@ void LLFloaterModelPreview::onPhysicsStageExecute(LLUICtrl* ctrl, void* data) for (S32 i = 0; i < sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS].size(); ++i) { LLModel* mdl = sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS][i]; - DecompRequest* request = new DecompRequest(stage->mName, mdl); + DecompRequest* request = new DecompRequest(stage, mdl); sInstance->mCurRequest.insert(request); gMeshRepo.mDecompThread->submitRequest(request); } } + + if (stage == "Decompose") + { + sInstance->childSetVisible("Decompose", false); + sInstance->childSetVisible("decompose_cancel", true); + } + else if (stage == "Simplify") + { + sInstance->childSetVisible("Simplify", false); + sInstance->childSetVisible("simplify_cancel", true); + } } } @@ -770,6 +790,15 @@ void LLFloaterModelPreview::onPhysicsUseLOD(LLUICtrl* ctrl, void* userdata) sInstance->mModelPreview->setPhysicsFromLOD(which_mode); } +//static +void LLFloaterModelPreview::onCancel(LLUICtrl* ctrl, void* data) +{ + if (sInstance) + { + sInstance->closeFloater(false); + } +} + //static void LLFloaterModelPreview::onPhysicsStageCancel(LLUICtrl* ctrl, void*data) { @@ -788,7 +817,9 @@ void LLFloaterModelPreview::initDecompControls() { LLSD key; - childSetCommitCallback("cancel_btn", onPhysicsStageCancel, NULL); + childSetCommitCallback("simplify_cancel", onPhysicsStageCancel, NULL); + childSetCommitCallback("decompose_cancel", onPhysicsStageCancel, NULL); + childSetCommitCallback("physics_lod_combo", onPhysicsUseLOD, NULL); childSetCommitCallback("physics_browse", onPhysicsBrowse, NULL); @@ -2029,7 +2060,7 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) mBuildShareTolerance = 0.f; mBuildQueueMode = GLOD_QUEUE_GREEDY; mBuildBorderMode = GLOD_BORDER_UNLOCK; - mBuildOperator = GLOD_OPERATOR_HALF_EDGE_COLLAPSE; + mBuildOperator = GLOD_OPERATOR_EDGE_COLLAPSE; mFMP = fmp; @@ -2732,7 +2763,9 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation) lod_mode = GLOD_TRIANGLE_BUDGET; if (which_lod != -1) { - limit = mFMP->childGetValue("lod_triangle_limit").asInteger(); + //SH-632 take budget as supplied limit+1 to prevent GLOD from creating a smaller + //decimation when the given decimation is possible + limit = mFMP->childGetValue("lod_triangle_limit").asInteger(); //+1; } } else @@ -2750,11 +2783,11 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation) if (build_operator == 0) { - build_operator = GLOD_OPERATOR_HALF_EDGE_COLLAPSE; + build_operator = GLOD_OPERATOR_EDGE_COLLAPSE; } else { - build_operator = GLOD_OPERATOR_EDGE_COLLAPSE; + build_operator = GLOD_OPERATOR_HALF_EDGE_COLLAPSE; } U32 queue_mode=0; @@ -4248,11 +4281,14 @@ void LLFloaterModelPreview::DecompRequest::completed() if (sInstance) { - if (sInstance->mModelPreview) + if (mContinue) { - sInstance->mModelPreview->mPhysicsMesh[mModel] = mHullMesh; - sInstance->mModelPreview->mDirty = true; - LLFloaterModelPreview::sInstance->mModelPreview->refresh(); + if (sInstance->mModelPreview) + { + sInstance->mModelPreview->mPhysicsMesh[mModel] = mHullMesh; + sInstance->mModelPreview->mDirty = true; + LLFloaterModelPreview::sInstance->mModelPreview->refresh(); + } } sInstance->mCurRequest.erase(this); -- cgit v1.2.3 From 961e50aab40fe09632e4f3f9aa385abd0fb42735 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Tue, 4 Jan 2011 16:22:38 -0700 Subject: clear some LLPointer issues for SH-694: check if there are any other LLPointer issues in the mesh model uploading flow and fix them if exist. --- indra/newview/llfloatermodelpreview.cpp | 42 ++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 9 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 68b9e5d23d..d63c8244df 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1590,6 +1590,35 @@ void LLModelLoader::run() } } +//called in the main thread +void LLModelLoader::loadTextures() +{ + BOOL is_paused = isPaused() ; + pause() ; //pause the loader + + for(scene::iterator iter = mScene.begin(); iter != mScene.end(); ++iter) + { + for(U32 i = 0 ; i < iter->second.size(); i++) + { + for(U32 j = 0 ; j < iter->second[i].mMaterial.size() ; j++) + { + if(!iter->second[i].mMaterial[j].mDiffuseMapFilename.empty()) + { + iter->second[i].mMaterial[j].mDiffuseMap = + LLViewerTextureManager::getFetchedTextureFromUrl("file://" + iter->second[i].mMaterial[j].mDiffuseMapFilename, TRUE, LLViewerTexture::BOOST_PREVIEW); + iter->second[i].mMaterial[j].mDiffuseMap->setLoadedCallback(LLModelPreview::textureLoadedCallback, 0, TRUE, FALSE, mPreview, NULL, FALSE); + iter->second[i].mMaterial[j].mDiffuseMap->forceToSaveRawImage(); + } + } + } + } + + if(!is_paused) + { + unpause() ; + } +} + bool LLModelLoader::isNodeAJoint( domNode* pNode ) { if ( pNode->getName() == NULL) @@ -1895,14 +1924,8 @@ LLImportMaterial LLModelLoader::profileToMaterial(domProfile_COMMON* material) // we only support init_from now - embedded data will come later domImage::domInit_from* init = image->getInit_from(); if (init) - { - std::string filename = cdom::uriToNativePath(init->getValue().str()); - - mat.mDiffuseMap = LLViewerTextureManager::getFetchedTextureFromUrl("file://" + filename, TRUE, LLViewerTexture::BOOST_PREVIEW); - mat.mDiffuseMap->setLoadedCallback(LLModelPreview::textureLoadedCallback, 0, TRUE, FALSE, this->mPreview, NULL, FALSE); - - mat.mDiffuseMap->forceToSaveRawImage(); - mat.mDiffuseMapFilename = filename; + { + mat.mDiffuseMapFilename = cdom::uriToNativePath(init->getValue().str()); mat.mDiffuseMapLabel = getElementLabel(material); } } @@ -2354,6 +2377,7 @@ void LLModelPreview::loadModelCallback(S32 lod) return; } + mModelLoader->loadTextures() ; mModel[lod] = mModelLoader->mModelList; mScene[lod] = mModelLoader->mScene; mVertexBuffer[lod].clear(); @@ -3803,7 +3827,7 @@ BOOL LLModelPreview::render() gGL.getTexUnit(0)->bind(instance.mMaterial[i].mDiffuseMap, true); if (instance.mMaterial[i].mDiffuseMap->getDiscardLevel() > -1) { - mTextureSet.insert(instance.mMaterial[i].mDiffuseMap); + mTextureSet.insert(instance.mMaterial[i].mDiffuseMap.get()); } } } -- cgit v1.2.3 From b70a8ee0daf1145d364dbcbed1e54df197b9f7fc Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Wed, 5 Jan 2011 10:37:28 -0500 Subject: fixed line endings again --- indra/newview/llfloatermodelpreview.cpp | 8648 +++++++++++++++---------------- 1 file changed, 4324 insertions(+), 4324 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 0f2924d8aa..f15d4def80 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1,4324 +1,4324 @@ -/** - * @file llfloatermodelpreview.cpp - * @brief LLFloaterModelPreview class implementation - * - * $LicenseInfo:firstyear=2004&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "dae.h" -//#include "dom.h" -#include "dom/domAsset.h" -#include "dom/domBind_material.h" -#include "dom/domCOLLADA.h" -#include "dom/domConstants.h" -#include "dom/domController.h" -#include "dom/domEffect.h" -#include "dom/domGeometry.h" -#include "dom/domInstance_geometry.h" -#include "dom/domInstance_material.h" -#include "dom/domInstance_node.h" -#include "dom/domInstance_effect.h" -#include "dom/domMaterial.h" -#include "dom/domMatrix.h" -#include "dom/domNode.h" -#include "dom/domProfile_COMMON.h" -#include "dom/domRotate.h" -#include "dom/domScale.h" -#include "dom/domTranslate.h" -#include "dom/domVisual_scene.h" - -#include "llfloatermodelpreview.h" - -#include "llfilepicker.h" -#include "llimagebmp.h" -#include "llimagetga.h" -#include "llimagejpeg.h" -#include "llimagepng.h" - -#include "llagent.h" -#include "llbutton.h" -#include "llcombobox.h" -#include "lldatapacker.h" -#include "lldrawable.h" -#include "lldrawpoolavatar.h" -#include "llrender.h" -#include "llface.h" -#include "lleconomy.h" -#include "llfocusmgr.h" -#include "llfloaterperms.h" -#include "lliconctrl.h" -#include "llmatrix4a.h" -#include "llmenubutton.h" -#include "llmeshrepository.h" -#include "llsdutil_math.h" -#include "lltextbox.h" -#include "lltoolmgr.h" -#include "llui.h" -#include "llvector4a.h" -#include "llviewercamera.h" -#include "llviewerwindow.h" -#include "llvoavatar.h" -#include "llvoavatarself.h" -#include "pipeline.h" -#include "lluictrlfactory.h" -#include "llviewermenu.h" -#include "llviewermenufile.h" -#include "llviewerregion.h" -#include "llviewertexturelist.h" -#include "llstring.h" -#include "llbutton.h" -#include "llcheckboxctrl.h" -#include "llradiogroup.h" -#include "llsliderctrl.h" -#include "llspinctrl.h" -#include "lltoggleablemenu.h" -#include "llvfile.h" -#include "llvfs.h" -#include "llcallbacklist.h" - -#include "glod/glod.h" - -//static -S32 LLFloaterModelPreview::sUploadAmount = 10; -LLFloaterModelPreview* LLFloaterModelPreview::sInstance = NULL; - -const S32 PREVIEW_BORDER_WIDTH = 2; -const S32 PREVIEW_RESIZE_HANDLE_SIZE = S32(RESIZE_HANDLE_WIDTH * OO_SQRT2) + PREVIEW_BORDER_WIDTH; -const S32 PREVIEW_HPAD = PREVIEW_RESIZE_HANDLE_SIZE; -const S32 PREF_BUTTON_HEIGHT = 16 + 7 + 16; -const S32 PREVIEW_TEXTURE_HEIGHT = 300; - -void drawBoxOutline(const LLVector3& pos, const LLVector3& size); - - -std::string lod_name[NUM_LOD+1] = -{ - "lowest", - "low", - "medium", - "high", - "I went off the end of the lod_name array. Me so smart." -}; - -std::string lod_triangles_name[NUM_LOD+1] = -{ - "lowest_triangles", - "low_triangles", - "medium_triangles", - "high_triangles", - "I went off the end of the lod_triangles_name array. Me so smart." -}; - -std::string lod_vertices_name[NUM_LOD+1] = -{ - "lowest_vertices", - "low_vertices", - "medium_vertices", - "high_vertices", - "I went off the end of the lod_vertices_name array. Me so smart." -}; - -std::string lod_status_name[NUM_LOD+1] = -{ - "lowest_status", - "low_status", - "medium_status", - "high_status", - "I went off the end of the lod_status_name array. Me so smart." -}; - -std::string lod_icon_name[NUM_LOD+1] = -{ - "status_icon_lowest", - "status_icon_low", - "status_icon_medium", - "status_icon_high", - "I went off the end of the lod_status_name array. Me so smart." -}; - -std::string lod_status_image[NUM_LOD+1] = -{ - "ModelImport_Status_Good", - "ModelImport_Status_Warning", - "ModelImport_Status_Error", - "I went off the end of the lod_status_image array. Me so smart." -}; - -std::string lod_label_name[NUM_LOD+1] = -{ - "lowest_label", - "low_label", - "medium_label", - "high_label", - "I went off the end of the lod_label_name array. Me so smart." -}; - - -bool validate_face(const LLVolumeFace& face) -{ - for (U32 i = 0; i < face.mNumIndices; ++i) - { - if (face.mIndices[i] >= face.mNumVertices) - { - llwarns << "Face has invalid index." << llendl; - return false; - } - } - - return true; -} - -bool validate_model(const LLModel* mdl) -{ - if (mdl->getNumVolumeFaces() == 0) - { - llwarns << "Model has no faces!" << llendl; - return false; - } - - for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) - { - if (mdl->getVolumeFace(i).mNumVertices == 0) - { - llwarns << "Face has no vertices." << llendl; - return false; - } - - if (mdl->getVolumeFace(i).mNumIndices == 0) - { - llwarns << "Face has no indices." << llendl; - return false; - } - - if (!validate_face(mdl->getVolumeFace(i))) - { - return false; - } - } - - return true; -} - -BOOL stop_gloderror() -{ - GLuint error = glodGetError(); - - if (error != GLOD_NO_ERROR) - { - llwarns << "GLOD error detected, cannot generate LOD: " << std::hex << error << llendl; - return TRUE; - } - - return FALSE; -} - - -LLMeshFilePicker::LLMeshFilePicker(LLModelPreview* mp, S32 lod) - : LLFilePickerThread(LLFilePicker::FFLOAD_COLLADA) - { - mMP = mp; - mLOD = lod; - } - -void LLMeshFilePicker::notify(const std::string& filename) -{ - mMP->loadModel(mFile, mLOD); -} - - -//----------------------------------------------------------------------------- -// LLFloaterModelPreview() -//----------------------------------------------------------------------------- -LLFloaterModelPreview::LLFloaterModelPreview(const LLSD& key) : -LLFloater(key) -{ - sInstance = this; - mLastMouseX = 0; - mLastMouseY = 0; - mGLName = 0; - mStatusLock = new LLMutex(NULL); - - mLODMode[LLModel::LOD_HIGH] = 0; - for (U32 i = 0; i < LLModel::LOD_HIGH; i++) - { - mLODMode[i] = 1; - } -} - -//----------------------------------------------------------------------------- -// postBuild() -//----------------------------------------------------------------------------- -BOOL LLFloaterModelPreview::postBuild() -{ - if (!LLFloater::postBuild()) - { - return FALSE; - } - - - - - - - childSetAction("lod_browse", onBrowseLOD, this); - - childSetCommitCallback("cancel_btn", onCancel, this); - childSetCommitCallback("crease_angle", onGenerateNormalsCommit, this); - childSetCommitCallback("generate_normals", onGenerateNormalsCommit, this); - - childSetCommitCallback("lod_generate", onAutoFillCommit, this); - - childSetCommitCallback("lod_mode", onLODParamCommit, this); - childSetCommitCallback("lod_error_threshold", onLODParamCommit, this); - childSetCommitCallback("lod_triangle_limit", onLODParamCommit, this); - childSetCommitCallback("build_operator", onLODParamCommit, this); - childSetCommitCallback("queue_mode", onLODParamCommit, this); - childSetCommitCallback("border_mode", onLODParamCommit, this); - childSetCommitCallback("share_tolerance", onLODParamCommit, this); - - childSetTextArg("status", "[STATUS]", getString("status_idle")); - - //childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d",sUploadAmount)); - childSetAction("ok_btn", onUpload, this); - childDisable("ok_btn"); - - childSetAction("clear_materials", onClearMaterials, this); - - childSetCommitCallback("preview_lod_combo", onPreviewLODCommit, this); - - childSetCommitCallback("upload_skin", onUploadSkinCommit, this); - childSetCommitCallback("upload_joints", onUploadJointsCommit, this); - - childSetCommitCallback("import_scale", onImportScaleCommit, this); - - childSetCommitCallback("lod_file_or_limit", refresh, this); - childSetCommitCallback("physics_load_radio", refresh, this); - //childSetCommitCallback("physics_optimize", refresh, this); - //childSetCommitCallback("physics_use_hull", refresh, this); - - childDisable("upload_skin"); - childDisable("upload_joints"); - childDisable("ok_btn"); - - mViewOptionMenuButton = getChild("options_gear_btn"); - - mCommitCallbackRegistrar.add("ModelImport.ViewOption.Action", boost::bind(&LLFloaterModelPreview::onViewOptionChecked, this, _2)); - mEnableCallbackRegistrar.add("ModelImport.ViewOption.Check", boost::bind(&LLFloaterModelPreview::isViewOptionChecked, this, _2)); - mEnableCallbackRegistrar.add("ModelImport.ViewOption.Enabled", boost::bind(&LLFloaterModelPreview::isViewOptionEnabled, this, _2)); - - - - mViewOptionMenu = LLUICtrlFactory::getInstance()->createFromFile("menu_model_import_gear_default.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); - mViewOptionMenuButton->setMenu(mViewOptionMenu, LLMenuButton::MP_BOTTOM_LEFT); - - initDecompControls(); - - LLView* preview_panel = getChild("preview_panel"); - - mPreviewRect = preview_panel->getRect(); - - mModelPreview = new LLModelPreview(512, 512, this); - mModelPreview->setPreviewTarget(16.f); - - //set callbacks for left click on line editor rows - for (U32 i = 0; i <= LLModel::LOD_HIGH; i++) - { - LLTextBox* text = getChild(lod_label_name[i]); - if (text) - { - text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i)); - } - - text = getChild(lod_triangles_name[i]); - if (text) - { - text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i)); - } - - text = getChild(lod_vertices_name[i]); - if (text) - { - text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i)); - } - - text = getChild(lod_status_name[i]); - if (text) - { - text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i)); - } - } - - return TRUE; -} - -//----------------------------------------------------------------------------- -// LLFloaterModelPreview() -//----------------------------------------------------------------------------- -LLFloaterModelPreview::~LLFloaterModelPreview() -{ - sInstance = NULL; - - if ( mModelPreview->containsRiggedAsset() ) - { - gAgentAvatarp->resetJointPositions(); - } - - delete mModelPreview; - - if (mGLName) - { - LLImageGL::deleteTextures(1, &mGLName ); - } - - delete mStatusLock; - mStatusLock = NULL; -} - -void LLFloaterModelPreview::onViewOptionChecked(const LLSD& userdata) -{ - if (mModelPreview) - { - mModelPreview->mViewOption[userdata.asString()] = !mModelPreview->mViewOption[userdata.asString()]; - - mModelPreview->refresh(); - } -} - -bool LLFloaterModelPreview::isViewOptionChecked(const LLSD& userdata) -{ - if (mModelPreview) - { - return mModelPreview->mViewOption[userdata.asString()]; - } - - return false; -} - -bool LLFloaterModelPreview::isViewOptionEnabled(const LLSD& userdata) -{ - return !mViewOptionDisabled[userdata.asString()]; -} - -void LLFloaterModelPreview::setViewOptionEnabled(const std::string& option, bool enabled) -{ - mViewOptionDisabled[option] = !enabled; -} - -void LLFloaterModelPreview::enableViewOption(const std::string& option) -{ - setViewOptionEnabled(option, true); -} - -void LLFloaterModelPreview::disableViewOption(const std::string& option) -{ - setViewOptionEnabled(option, false); -} - -void LLFloaterModelPreview::loadModel(S32 lod) -{ - mModelPreview->mLoading = true; - - (new LLMeshFilePicker(mModelPreview, lod))->getFile(); -} - -//static -void LLFloaterModelPreview::onImportScaleCommit(LLUICtrl*,void* userdata) -{ - LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; - - if (!fp->mModelPreview) - { - return; - } - - fp->mModelPreview->calcResourceCost(); - fp->mModelPreview->refresh(); -} - -//static -void LLFloaterModelPreview::onUploadJointsCommit(LLUICtrl*,void* userdata) -{ - LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; - - if (!fp->mModelPreview) - { - return; - } - - fp->mModelPreview->refresh(); -} - -//static -void LLFloaterModelPreview::onUploadSkinCommit(LLUICtrl*,void* userdata) -{ - LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; - - if (!fp->mModelPreview) - { - return; - } - - fp->mModelPreview->refresh(); - fp->mModelPreview->resetPreviewTarget(); - fp->mModelPreview->clearBuffers(); -} - -//static -void LLFloaterModelPreview::onPreviewLODCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; - - if (!fp->mModelPreview) - { - return; - } - - S32 which_mode = 0; - - LLComboBox* combo = (LLComboBox*) ctrl; - - which_mode = (NUM_LOD-1)-combo->getFirstSelectedIndex(); // combo box list of lods is in reverse order - - fp->mModelPreview->setPreviewLOD(which_mode); -} - -//static -void LLFloaterModelPreview::onGenerateNormalsCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; - - fp->mModelPreview->generateNormals(); -} - -//static -void LLFloaterModelPreview::onExplodeCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview* fp = LLFloaterModelPreview::sInstance; - - fp->mModelPreview->refresh(); -} - -//static -void LLFloaterModelPreview::onAutoFillCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; - - fp->mModelPreview->genLODs(); -} - -//static -void LLFloaterModelPreview::onLODParamCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; - fp->mModelPreview->genLODs(fp->mModelPreview->mPreviewLOD); - fp->mModelPreview->updateStatusMessages(); - fp->mModelPreview->refresh(); -} - - -//----------------------------------------------------------------------------- -// draw() -//----------------------------------------------------------------------------- -void LLFloaterModelPreview::draw() -{ - LLFloater::draw(); - LLRect r = getRect(); - - mModelPreview->update(); - - if (!mModelPreview->mLoading) - { - childSetTextArg("status", "[STATUS]", getString("status_idle")); - } - - childSetTextArg("prim_cost", "[PRIM_COST]", llformat("%d", mModelPreview->mResourceCost)); - childSetTextArg("description_label", "[TEXTURES]", llformat("%d", mModelPreview->mTextureSet.size())); - - if (!mCurRequest.empty()) - { - LLMutexLock lock(mStatusLock); - childSetTextArg("status", "[STATUS]", mStatusMessage); - } - else - { - childSetVisible("Simplify", true); - childSetVisible("simplify_cancel", false); - childSetVisible("Decompose", true); - childSetVisible("decompose_cancel", false); - } - - U32 resource_cost = mModelPreview->mResourceCost*10; - - if (childGetValue("upload_textures").asBoolean()) - { - resource_cost += mModelPreview->mTextureSet.size()*10; - } - - childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d", resource_cost)); - - if (mModelPreview) - { - gGL.color3f(1.f, 1.f, 1.f); - - gGL.getTexUnit(0)->bind(mModelPreview); - - - LLView* preview_panel = getChild("preview_panel"); - - LLRect rect = preview_panel->getRect(); - if (rect != mPreviewRect) - { - mModelPreview->refresh(); - mPreviewRect = preview_panel->getRect(); - } - - gGL.begin( LLRender::QUADS ); - { - gGL.texCoord2f(0.f, 1.f); - gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mTop); - gGL.texCoord2f(0.f, 0.f); - gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mBottom); - gGL.texCoord2f(1.f, 0.f); - gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mBottom); - gGL.texCoord2f(1.f, 1.f); - gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mTop); - } - gGL.end(); - - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - } -} - -//----------------------------------------------------------------------------- -// handleMouseDown() -//----------------------------------------------------------------------------- -BOOL LLFloaterModelPreview::handleMouseDown(S32 x, S32 y, MASK mask) -{ - if (mPreviewRect.pointInRect(x, y)) - { - bringToFront( x, y ); - gFocusMgr.setMouseCapture(this); - gViewerWindow->hideCursor(); - mLastMouseX = x; - mLastMouseY = y; - return TRUE; - } - - return LLFloater::handleMouseDown(x, y, mask); -} - -//----------------------------------------------------------------------------- -// handleMouseUp() -//----------------------------------------------------------------------------- -BOOL LLFloaterModelPreview::handleMouseUp(S32 x, S32 y, MASK mask) -{ - gFocusMgr.setMouseCapture(FALSE); - gViewerWindow->showCursor(); - return LLFloater::handleMouseUp(x, y, mask); -} - -//----------------------------------------------------------------------------- -// handleHover() -//----------------------------------------------------------------------------- -BOOL LLFloaterModelPreview::handleHover (S32 x, S32 y, MASK mask) -{ - MASK local_mask = mask & ~MASK_ALT; - - if (mModelPreview && hasMouseCapture()) - { - if (local_mask == MASK_PAN) - { - // pan here - mModelPreview->pan((F32)(x - mLastMouseX) * -0.005f, (F32)(y - mLastMouseY) * -0.005f); - } - else if (local_mask == MASK_ORBIT) - { - F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f; - F32 pitch_radians = (F32)(y - mLastMouseY) * 0.02f; - - mModelPreview->rotate(yaw_radians, pitch_radians); - } - else - { - - F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f; - F32 zoom_amt = (F32)(y - mLastMouseY) * 0.02f; - - mModelPreview->rotate(yaw_radians, 0.f); - mModelPreview->zoom(zoom_amt); - } - - - mModelPreview->refresh(); - - LLUI::setMousePositionLocal(this, mLastMouseX, mLastMouseY); - } - - if (!mPreviewRect.pointInRect(x, y) || !mModelPreview) - { - return LLFloater::handleHover(x, y, mask); - } - else if (local_mask == MASK_ORBIT) - { - gViewerWindow->setCursor(UI_CURSOR_TOOLCAMERA); - } - else if (local_mask == MASK_PAN) - { - gViewerWindow->setCursor(UI_CURSOR_TOOLPAN); - } - else - { - gViewerWindow->setCursor(UI_CURSOR_TOOLZOOMIN); - } - - return TRUE; -} - -//----------------------------------------------------------------------------- -// handleScrollWheel() -//----------------------------------------------------------------------------- -BOOL LLFloaterModelPreview::handleScrollWheel(S32 x, S32 y, S32 clicks) -{ - if (mPreviewRect.pointInRect(x, y) && mModelPreview) - { - mModelPreview->zoom((F32)clicks * -0.2f); - mModelPreview->refresh(); - } - - return TRUE; -} - -//static -void LLFloaterModelPreview::onPhysicsParamCommit(LLUICtrl* ctrl, void* data) -{ - if (LLConvexDecomposition::getInstance() == NULL) - { - llinfos << "convex decomposition tool is a stub on this platform. cannot get decomp." << llendl; - return; - } - - if (sInstance) - { - LLCDParam* param = (LLCDParam*) data; - std::string name(param->mName); - sInstance->mDecompParams[name] = ctrl->getValue(); - - if (name == "Simplify Method") - { - if (ctrl->getValue().asInteger() == 0) - { - sInstance->childSetVisible("Retain%", true); - sInstance->childSetVisible("Detail Scale", false); - } - else - { - sInstance->childSetVisible("Retain%", false); - sInstance->childSetVisible("Detail Scale", true); - } - } - } -} - -//static -void LLFloaterModelPreview::onPhysicsStageExecute(LLUICtrl* ctrl, void* data) -{ - LLCDStageData* stage_data = (LLCDStageData*) data; - std::string stage = stage_data->mName; - - if (sInstance) - { - if (!sInstance->mCurRequest.empty()) - { - llinfos << "Decomposition request still pending." << llendl; - return; - } - - if (sInstance->mModelPreview) - { - for (S32 i = 0; i < sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS].size(); ++i) - { - LLModel* mdl = sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS][i]; - DecompRequest* request = new DecompRequest(stage, mdl); - sInstance->mCurRequest.insert(request); - gMeshRepo.mDecompThread->submitRequest(request); - } - } - - if (stage == "Decompose") - { - sInstance->childSetVisible("Decompose", false); - sInstance->childSetVisible("decompose_cancel", true); - } - else if (stage == "Simplify") - { - sInstance->childSetVisible("Simplify", false); - sInstance->childSetVisible("simplify_cancel", true); - } - } -} - -//static -void LLFloaterModelPreview::onPhysicsBrowse(LLUICtrl* ctrl, void* userdata) -{ - sInstance->loadModel(LLModel::LOD_PHYSICS); -} - -//static -void LLFloaterModelPreview::onPhysicsUseLOD(LLUICtrl* ctrl, void* userdata) -{ - S32 which_mode = 3; - LLCtrlSelectionInterface* iface = sInstance->childGetSelectionInterface("physics_lod_combo"); - if (iface) - { - which_mode = iface->getFirstSelectedIndex(); - } - - sInstance->mModelPreview->setPhysicsFromLOD(which_mode); -} - -//static -void LLFloaterModelPreview::onCancel(LLUICtrl* ctrl, void* data) -{ - if (sInstance) - { - sInstance->closeFloater(false); - } -} - -//static -void LLFloaterModelPreview::onPhysicsStageCancel(LLUICtrl* ctrl, void*data) -{ - if (sInstance) - { - for (std::set >::iterator iter = sInstance->mCurRequest.begin(); - iter != sInstance->mCurRequest.end(); ++iter) - { - DecompRequest* req = *iter; - req->mContinue = 0; - } - } -} - -void LLFloaterModelPreview::initDecompControls() -{ - LLSD key; - - childSetCommitCallback("simplify_cancel", onPhysicsStageCancel, NULL); - childSetCommitCallback("decompose_cancel", onPhysicsStageCancel, NULL); - - childSetCommitCallback("physics_lod_combo", onPhysicsUseLOD, NULL); - childSetCommitCallback("physics_browse", onPhysicsBrowse, NULL); - - static const LLCDStageData* stage = NULL; - static S32 stage_count = 0; - - if (!stage && LLConvexDecomposition::getInstance() != NULL) - { - stage_count = LLConvexDecomposition::getInstance()->getStages(&stage); - } - - static const LLCDParam* param = NULL; - static S32 param_count = 0; - if (!param && LLConvexDecomposition::getInstance() != NULL) - { - param_count = LLConvexDecomposition::getInstance()->getParameters(¶m); - } - - for (S32 j = stage_count-1; j >= 0; --j) - { - LLButton* button = getChild(stage[j].mName); - if (button) - { - button->setCommitCallback(onPhysicsStageExecute, (void*) &stage[j]); - } - - gMeshRepo.mDecompThread->mStageID[stage[j].mName] = j; - // protected against stub by stage_count being 0 for stub above - LLConvexDecomposition::getInstance()->registerCallback(j, LLPhysicsDecomp::llcdCallback); - - //llinfos << "Physics decomp stage " << stage[j].mName << " (" << j << ") parameters:" << llendl; - //llinfos << "------------------------------------" << llendl; - - for (S32 i = 0; i < param_count; ++i) - { - if (param[i].mStage != j) - { - continue; - } - - std::string name(param[i].mName ? param[i].mName : ""); - std::string description(param[i].mDescription ? param[i].mDescription : ""); - - std::string type = "unknown"; - - llinfos << name << " - " << description << llendl; - - if (param[i].mType == LLCDParam::LLCD_FLOAT) - { - mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mFloat); - //llinfos << "Type: float, Default: " << param[i].mDefault.mFloat << llendl; - - LLSliderCtrl* slider = getChild(name); - if (slider) - { - slider->setMinValue(param[i].mDetails.mRange.mLow.mFloat); - slider->setMaxValue(param[i].mDetails.mRange.mHigh.mFloat); - slider->setIncrement(param[i].mDetails.mRange.mDelta.mFloat); - slider->setValue(param[i].mDefault.mFloat); - slider->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); - } - } - else if (param[i].mType == LLCDParam::LLCD_INTEGER) - { - mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue); - //llinfos << "Type: integer, Default: " << param[i].mDefault.mIntOrEnumValue << llendl; - - LLSliderCtrl* slider = getChild(name); - if (slider) - { - slider->setMinValue(param[i].mDetails.mRange.mLow.mIntOrEnumValue); - slider->setMaxValue(param[i].mDetails.mRange.mHigh.mIntOrEnumValue); - slider->setIncrement(param[i].mDetails.mRange.mDelta.mIntOrEnumValue); - slider->setValue(param[i].mDefault.mIntOrEnumValue); - slider->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); - } - } - else if (param[i].mType == LLCDParam::LLCD_BOOLEAN) - { - mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mBool); - //llinfos << "Type: boolean, Default: " << (param[i].mDefault.mBool ? "True" : "False") << llendl; - - LLCheckBoxCtrl* check_box = getChild(name); - if (check_box) - { - check_box->setValue(param[i].mDefault.mBool); - check_box->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); - } - } - else if (param[i].mType == LLCDParam::LLCD_ENUM) - { - mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue); - //llinfos << "Type: enum, Default: " << param[i].mDefault.mIntOrEnumValue << llendl; - - { //plug into combo box - - //llinfos << "Accepted values: " << llendl; - LLComboBox* combo_box = getChild(name); - for (S32 k = 0; k < param[i].mDetails.mEnumValues.mNumEnums; ++k) - { - //llinfos << param[i].mDetails.mEnumValues.mEnumsArray[k].mValue - // << " - " << param[i].mDetails.mEnumValues.mEnumsArray[k].mName << llendl; - - combo_box->add(param[i].mDetails.mEnumValues.mEnumsArray[k].mName, - LLSD::Integer(param[i].mDetails.mEnumValues.mEnumsArray[k].mValue)); - } - combo_box->setValue(param[i].mDefault.mIntOrEnumValue); - combo_box->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); - } - - //llinfos << "----" << llendl; - } - //llinfos << "-----------------------------" << llendl; - } - } - - childSetCommitCallback("physics_explode", LLFloaterModelPreview::onExplodeCommit, this); -} - -//----------------------------------------------------------------------------- -// onMouseCaptureLost() -//----------------------------------------------------------------------------- -// static -void LLFloaterModelPreview::onMouseCaptureLostModelPreview(LLMouseHandler* handler) -{ - gViewerWindow->showCursor(); -} - -//----------------------------------------------------------------------------- -// LLModelLoader -//----------------------------------------------------------------------------- -LLModelLoader::LLModelLoader(std::string filename, S32 lod, LLModelPreview* preview) -: LLThread("Model Loader"), mFilename(filename), mLod(lod), mPreview(preview), mState(STARTING), mFirstTransform(TRUE) -{ - mJointMap["mPelvis"] = "mPelvis"; - mJointMap["mTorso"] = "mTorso"; - mJointMap["mChest"] = "mChest"; - mJointMap["mNeck"] = "mNeck"; - mJointMap["mHead"] = "mHead"; - mJointMap["mSkull"] = "mSkull"; - mJointMap["mEyeRight"] = "mEyeRight"; - mJointMap["mEyeLeft"] = "mEyeLeft"; - mJointMap["mCollarLeft"] = "mCollarLeft"; - mJointMap["mShoulderLeft"] = "mShoulderLeft"; - mJointMap["mElbowLeft"] = "mElbowLeft"; - mJointMap["mWristLeft"] = "mWristLeft"; - mJointMap["mCollarRight"] = "mCollarRight"; - mJointMap["mShoulderRight"] = "mShoulderRight"; - mJointMap["mElbowRight"] = "mElbowRight"; - mJointMap["mWristRight"] = "mWristRight"; - mJointMap["mHipRight"] = "mHipRight"; - mJointMap["mKneeRight"] = "mKneeRight"; - mJointMap["mAnkleRight"] = "mAnkleRight"; - mJointMap["mFootRight"] = "mFootRight"; - mJointMap["mToeRight"] = "mToeRight"; - mJointMap["mHipLeft"] = "mHipLeft"; - mJointMap["mKneeLeft"] = "mKneeLeft"; - mJointMap["mAnkleLeft"] = "mAnkleLeft"; - mJointMap["mFootLeft"] = "mFootLeft"; - mJointMap["mToeLeft"] = "mToeLeft"; - - mJointMap["avatar_mPelvis"] = "mPelvis"; - mJointMap["avatar_mTorso"] = "mTorso"; - mJointMap["avatar_mChest"] = "mChest"; - mJointMap["avatar_mNeck"] = "mNeck"; - mJointMap["avatar_mHead"] = "mHead"; - mJointMap["avatar_mSkull"] = "mSkull"; - mJointMap["avatar_mEyeRight"] = "mEyeRight"; - mJointMap["avatar_mEyeLeft"] = "mEyeLeft"; - mJointMap["avatar_mCollarLeft"] = "mCollarLeft"; - mJointMap["avatar_mShoulderLeft"] = "mShoulderLeft"; - mJointMap["avatar_mElbowLeft"] = "mElbowLeft"; - mJointMap["avatar_mWristLeft"] = "mWristLeft"; - mJointMap["avatar_mCollarRight"] = "mCollarRight"; - mJointMap["avatar_mShoulderRight"] = "mShoulderRight"; - mJointMap["avatar_mElbowRight"] = "mElbowRight"; - mJointMap["avatar_mWristRight"] = "mWristRight"; - mJointMap["avatar_mHipRight"] = "mHipRight"; - mJointMap["avatar_mKneeRight"] = "mKneeRight"; - mJointMap["avatar_mAnkleRight"] = "mAnkleRight"; - mJointMap["avatar_mFootRight"] = "mFootRight"; - mJointMap["avatar_mToeRight"] = "mToeRight"; - mJointMap["avatar_mHipLeft"] = "mHipLeft"; - mJointMap["avatar_mKneeLeft"] = "mKneeLeft"; - mJointMap["avatar_mAnkleLeft"] = "mAnkleLeft"; - mJointMap["avatar_mFootLeft"] = "mFootLeft"; - mJointMap["avatar_mToeLeft"] = "mToeLeft"; - - - mJointMap["hip"] = "mPelvis"; - mJointMap["abdomen"] = "mTorso"; - mJointMap["chest"] = "mChest"; - mJointMap["neck"] = "mNeck"; - mJointMap["head"] = "mHead"; - mJointMap["figureHair"] = "mSkull"; - mJointMap["lCollar"] = "mCollarLeft"; - mJointMap["lShldr"] = "mShoulderLeft"; - mJointMap["lForeArm"] = "mElbowLeft"; - mJointMap["lHand"] = "mWristLeft"; - mJointMap["rCollar"] = "mCollarRight"; - mJointMap["rShldr"] = "mShoulderRight"; - mJointMap["rForeArm"] = "mElbowRight"; - mJointMap["rHand"] = "mWristRight"; - mJointMap["rThigh"] = "mHipRight"; - mJointMap["rShin"] = "mKneeRight"; - mJointMap["rFoot"] = "mFootRight"; - mJointMap["lThigh"] = "mHipLeft"; - mJointMap["lShin"] = "mKneeLeft"; - mJointMap["lFoot"] = "mFootLeft"; -} - -void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, BOOL& first_transform) -{ - LLVector4a box[] = - { - LLVector4a(-1, 1,-1), - LLVector4a(-1, 1, 1), - LLVector4a(-1,-1,-1), - LLVector4a(-1,-1, 1), - LLVector4a( 1, 1,-1), - LLVector4a( 1, 1, 1), - LLVector4a( 1,-1,-1), - LLVector4a( 1,-1, 1), - }; - - for (S32 j = 0; j < model->getNumVolumeFaces(); ++j) - { - const LLVolumeFace& face = model->getVolumeFace(j); - - LLVector4a center; - center.setAdd(face.mExtents[0], face.mExtents[1]); - center.mul(0.5f); - LLVector4a size; - size.setSub(face.mExtents[1],face.mExtents[0]); - size.mul(0.5f); - - for (U32 i = 0; i < 8; i++) - { - LLVector4a t; - t.setMul(size, box[i]); - t.add(center); - - LLVector4a v; - - mat.affineTransform(t, v); - - if (first_transform) - { - first_transform = FALSE; - min = max = v; - } - else - { - update_min_max(min, max, v); - } - } - } -} - -void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& max, BOOL& first_transform) -{ - LLVector4a mina, maxa; - LLMatrix4a mata; - - mata.loadu(mat); - mina.load3(min.mV); - maxa.load3(max.mV); - - stretch_extents(model, mata, mina, maxa, first_transform); - - min.set(mina.getF32ptr()); - max.set(maxa.getF32ptr()); -} - -void LLModelLoader::run() -{ - DAE dae; - domCOLLADA* dom = dae.open(mFilename); - - if (dom) - { - daeDatabase* db = dae.getDatabase(); - - daeInt count = db->getElementCount(NULL, COLLADA_TYPE_MESH); - - daeDocument* doc = dae.getDoc(mFilename); - if (!doc) - { - llwarns << "can't find internal doc" << llendl; - return; - } - - daeElement* root = doc->getDomRoot(); - if (!root) - { - llwarns << "document has no root" << llendl; - return; - } - - //get unit scale - mTransform.setIdentity(); - - domAsset::domUnit* unit = daeSafeCast(root->getDescendant(daeElement::matchType(domAsset::domUnit::ID()))); - - if (unit) - { - F32 meter = unit->getMeter(); - mTransform.mMatrix[0][0] = meter; - mTransform.mMatrix[1][1] = meter; - mTransform.mMatrix[2][2] = meter; - } - - //get up axis rotation - LLMatrix4 rotation; - - domUpAxisType up = UPAXISTYPE_Y_UP; // default is Y_UP - domAsset::domUp_axis* up_axis = - daeSafeCast(root->getDescendant(daeElement::matchType(domAsset::domUp_axis::ID()))); - - if (up_axis) - { - up = up_axis->getValue(); - } - - if (up == UPAXISTYPE_X_UP) - { - rotation.initRotation(0.0f, 90.0f * DEG_TO_RAD, 0.0f); - } - else if (up == UPAXISTYPE_Y_UP) - { - rotation.initRotation(90.0f * DEG_TO_RAD, 0.0f, 0.0f); - } - - rotation *= mTransform; - mTransform = rotation; - - - for (daeInt idx = 0; idx < count; ++idx) - { //build map of domEntities to LLModel - domMesh* mesh = NULL; - db->getElement((daeElement**) &mesh, idx, NULL, COLLADA_TYPE_MESH); - - if (mesh) - { - LLPointer model = LLModel::loadModelFromDomMesh(mesh); - - if (model.notNull() && validate_model(model)) - { - mModelList.push_back(model); - mModel[mesh] = model; - } - } - } - - count = db->getElementCount(NULL, COLLADA_TYPE_SKIN); - for (daeInt idx = 0; idx < count; ++idx) - { //add skinned meshes as instances - domSkin* skin = NULL; - db->getElement((daeElement**) &skin, idx, NULL, COLLADA_TYPE_SKIN); - - if (skin) - { - domGeometry* geom = daeSafeCast(skin->getSource().getElement()); - - if (geom) - { - domMesh* mesh = geom->getMesh(); - if (mesh) - { - LLModel* model = mModel[mesh]; - if (model) - { - LLVector3 mesh_scale_vector; - LLVector3 mesh_translation_vector; - model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); - - LLMatrix4 normalized_transformation; - normalized_transformation.setTranslation(mesh_translation_vector); - - LLMatrix4 mesh_scale; - mesh_scale.initScale(mesh_scale_vector); - mesh_scale *= normalized_transformation; - normalized_transformation = mesh_scale; - - glh::matrix4f inv_mat((F32*) normalized_transformation.mMatrix); - inv_mat = inv_mat.inverse(); - LLMatrix4 inverse_normalized_transformation(inv_mat.m); - - domSkin::domBind_shape_matrix* bind_mat = skin->getBind_shape_matrix(); - - if (bind_mat) - { //get bind shape matrix - domFloat4x4& dom_value = bind_mat->getValue(); - - for (int i = 0; i < 4; i++) - { - for(int j = 0; j < 4; j++) - { - model->mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j*4]; - } - } - - LLMatrix4 trans = normalized_transformation; - trans *= model->mBindShapeMatrix; - model->mBindShapeMatrix = trans; - - } - - - //The joint transfom map that we'll populate below - std::map jointTransforms; - jointTransforms.clear(); - - //Some collada setup for accessing the skeleton - daeElement* pElement = 0; - dae.getDatabase()->getElement( &pElement, 0, 0, "skeleton" ); - - //Try to get at the skeletal instance controller - domInstance_controller::domSkeleton* pSkeleton = daeSafeCast( pElement ); - bool missingSkeletonOrScene = false; - - //If no skeleton, do a breadth-first search to get at specific joints - if ( !pSkeleton ) - { - daeElement* pScene = root->getDescendant("visual_scene"); - if ( !pScene ) - { - llwarns<<"No visual scene - unable to parse bone offsets "< > children = pScene->getChildren(); - S32 childCount = children.getCount(); - - //Process any children that are joints - //Not all children are joints, some code be ambient lights, cameras, geometry etc.. - for (S32 i = 0; i < childCount; ++i) - { - domNode* pNode = daeSafeCast(children[i]); - if ( isNodeAJoint( pNode ) ) - { - processJointNode( pNode, jointTransforms ); - } - } - } - } - else - //Has Skeleton - { - //Get the root node of the skeleton - daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement(); - if ( pSkeletonRootNode ) - { - //Once we have the root node - start acccessing it's joint components - const int jointCnt = mJointMap.size(); - std::map :: const_iterator jointIt = mJointMap.begin(); - - //Loop over all the possible joints within the .dae - using the allowed joint list in the ctor. - for ( int i=0; i( resolver.getElement() ); - if ( pJoint ) - { - //Pull out the translate id and store it in the jointTranslations map - daeSIDResolver jointResolver( pJoint, "./translate" ); - domTranslate* pTranslate = daeSafeCast( jointResolver.getElement() ); - - LLMatrix4 workingTransform; - - //Translation via SID - if ( pTranslate ) - { - extractTranslation( pTranslate, workingTransform ); - } - else - { - //Translation via child from element - daeElement* pTranslateElement = getChildFromElement( pJoint, "translate" ); - if ( pTranslateElement && pTranslateElement->typeID() != domTranslate::ID() ) - { - llwarns<< "The found element is not a translate node" < :: const_iterator jointIt = mJointMap.begin(); - for ( int i=0; igetJoint( lookingForJoint ); - if ( pJoint ) - { - pJoint->storeCurrentXform( jointTransform.getTranslation() ); - } - else - { - //Most likely an error in the asset. - llwarns<<"Tried to apply joint position from .dae, but it did not exist in the avatar rig." << llendl; - } - //Reposition the avatars pelvis (avPos+offset) - //if ( lookingForJoint == "mPelvis" ) - //{ - // const LLVector3& pos = gAgentAvatarp->getCharacterPosition(); - // gAgentAvatarp->setPelvisOffset( true, jointTransform.getTranslation() ); - // gAgentAvatarp->setPosition( pos + jointTransform.getTranslation() ); - //} - } - } - } //missingSkeletonOrScene - - domSkin::domJoints* joints = skin->getJoints(); - - domInputLocal_Array& joint_input = joints->getInput_array(); - - for (size_t i = 0; i < joint_input.getCount(); ++i) - { - domInputLocal* input = joint_input.get(i); - xsNMTOKEN semantic = input->getSemantic(); - - if (strcmp(semantic, COMMON_PROFILE_INPUT_JOINT) == 0) - { //found joint source, fill model->mJointMap and model->mJointList - daeElement* elem = input->getSource().getElement(); - - domSource* source = daeSafeCast(elem); - if (source) - { - - - domName_array* names_source = source->getName_array(); - - if (names_source) - { - domListOfNames &names = names_source->getValue(); - - for (size_t j = 0; j < names.getCount(); ++j) - { - std::string name(names.get(j)); - if (mJointMap.find(name) != mJointMap.end()) - { - name = mJointMap[name]; - } - model->mJointList.push_back(name); - model->mJointMap[name] = j; - } - } - else - { - domIDREF_array* names_source = source->getIDREF_array(); - if (names_source) - { - xsIDREFS& names = names_source->getValue(); - - for (size_t j = 0; j < names.getCount(); ++j) - { - std::string name(names.get(j).getID()); - if (mJointMap.find(name) != mJointMap.end()) - { - name = mJointMap[name]; - } - model->mJointList.push_back(name); - model->mJointMap[name] = j; - } - } - } - } - } - else if (strcmp(semantic, COMMON_PROFILE_INPUT_INV_BIND_MATRIX) == 0) - { //found inv_bind_matrix array, fill model->mInvBindMatrix - domSource* source = daeSafeCast(input->getSource().getElement()); - if (source) - { - domFloat_array* t = source->getFloat_array(); - if (t) - { - domListOfFloats& transform = t->getValue(); - S32 count = transform.getCount()/16; - - for (S32 k = 0; k < count; ++k) - { - LLMatrix4 mat; - - for (int i = 0; i < 4; i++) - { - for(int j = 0; j < 4; j++) - { - mat.mMatrix[i][j] = transform[k*16 + i + j*4]; - } - } - - model->mInvBindMatrix.push_back(mat); - } - } - } - } - } - - //We need to construct the alternate bind matrix (which contains the new joint positions) - //in the same order as they were stored in the joint buffer. The joints associated - //with the skeleton are not stored in the same order as they are in the exported joint buffer. - //This remaps the skeletal joints to be in the same order as the joints stored in the model. - std::vector :: const_iterator jointIt = model->mJointList.begin(); - const int jointCnt = model->mJointList.size(); - for ( int i=0; imInvBindMatrix[i]; - newInverse.setTranslation( jointTransforms[lookingForJoint].getTranslation() ); - model->mAlternateBindMatrix.push_back( newInverse ); - } - else - { - llwarns<<"Possibly misnamed/missing joint [" <getVertices(); - if (verts) - { - domInputLocal_Array& inputs = verts->getInput_array(); - for (size_t i = 0; i < inputs.getCount() && model->mPosition.empty(); ++i) - { - if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_POSITION) == 0) - { - domSource* pos_source = daeSafeCast(inputs[i]->getSource().getElement()); - if (pos_source) - { - domFloat_array* pos_array = pos_source->getFloat_array(); - if (pos_array) - { - domListOfFloats& pos = pos_array->getValue(); - - for (size_t j = 0; j < pos.getCount(); j += 3) - { - if (pos.getCount() <= j+2) - { - llerrs << "WTF?" << llendl; - } - - LLVector3 v(pos[j], pos[j+1], pos[j+2]); - - //transform from COLLADA space to volume space - v = v * inverse_normalized_transformation; - - model->mPosition.push_back(v); - } - } - } - } - } - } - - //grab skin weights array - domSkin::domVertex_weights* weights = skin->getVertex_weights(); - if (weights) - { - domInputLocalOffset_Array& inputs = weights->getInput_array(); - domFloat_array* vertex_weights = NULL; - for (size_t i = 0; i < inputs.getCount(); ++i) - { - if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_WEIGHT) == 0) - { - domSource* weight_source = daeSafeCast(inputs[i]->getSource().getElement()); - if (weight_source) - { - vertex_weights = weight_source->getFloat_array(); - } - } - } - - if (vertex_weights) - { - domListOfFloats& w = vertex_weights->getValue(); - domListOfUInts& vcount = weights->getVcount()->getValue(); - domListOfInts& v = weights->getV()->getValue(); - - U32 c_idx = 0; - for (size_t vc_idx = 0; vc_idx < vcount.getCount(); ++vc_idx) - { //for each vertex - daeUInt count = vcount[vc_idx]; - - //create list of weights that influence this vertex - LLModel::weight_list weight_list; - - for (daeUInt i = 0; i < count; ++i) - { //for each weight - daeInt joint_idx = v[c_idx++]; - daeInt weight_idx = v[c_idx++]; - - if (joint_idx == -1) - { - //ignore bindings to bind_shape_matrix - continue; - } - - F32 weight_value = w[weight_idx]; - - weight_list.push_back(LLModel::JointWeight(joint_idx, weight_value)); - } - - //sort by joint weight - std::sort(weight_list.begin(), weight_list.end(), LLModel::CompareWeightGreater()); - - std::vector wght; - - F32 total = 0.f; - - for (U32 i = 0; i < llmin((U32) 4, (U32) weight_list.size()); ++i) - { //take up to 4 most significant weights - if (weight_list[i].mWeight > 0.f) - { - wght.push_back( weight_list[i] ); - total += weight_list[i].mWeight; - } - } - - F32 scale = 1.f/total; - if (scale != 1.f) - { //normalize weights - for (U32 i = 0; i < wght.size(); ++i) - { - wght[i].mWeight *= scale; - } - } - - model->mSkinWeights[model->mPosition[vc_idx]] = wght; - } - - //add instance to scene for this model - - LLMatrix4 transformation = mTransform; - // adjust the transformation to compensate for mesh normalization - - LLMatrix4 mesh_translation; - mesh_translation.setTranslation(mesh_translation_vector); - mesh_translation *= transformation; - transformation = mesh_translation; - - LLMatrix4 mesh_scale; - mesh_scale.initScale(mesh_scale_vector); - mesh_scale *= transformation; - transformation = mesh_scale; - - std::vector materials; - materials.resize(model->getNumVolumeFaces()); - mScene[transformation].push_back(LLModelInstance(model, transformation, materials)); - stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); - } - } - } - } - } - } - } - - daeElement* scene = root->getDescendant("visual_scene"); - - if (!scene) - { - llwarns << "document has no visual_scene" << llendl; - setLoadState( ERROR_PARSING ); - return; - } - - processElement(scene); - - doOnIdleOneTime(boost::bind(&LLModelPreview::loadModelCallback,mPreview,mLod)); - } -} - -//called in the main thread -void LLModelLoader::loadTextures() -{ - BOOL is_paused = isPaused() ; - pause() ; //pause the loader - - for(scene::iterator iter = mScene.begin(); iter != mScene.end(); ++iter) - { - for(U32 i = 0 ; i < iter->second.size(); i++) - { - for(U32 j = 0 ; j < iter->second[i].mMaterial.size() ; j++) - { - if(!iter->second[i].mMaterial[j].mDiffuseMapFilename.empty()) - { - iter->second[i].mMaterial[j].mDiffuseMap = - LLViewerTextureManager::getFetchedTextureFromUrl("file://" + iter->second[i].mMaterial[j].mDiffuseMapFilename, TRUE, LLViewerTexture::BOOST_PREVIEW); - iter->second[i].mMaterial[j].mDiffuseMap->setLoadedCallback(LLModelPreview::textureLoadedCallback, 0, TRUE, FALSE, mPreview, NULL, FALSE); - iter->second[i].mMaterial[j].mDiffuseMap->forceToSaveRawImage(); - } - } - } - } - - if(!is_paused) - { - unpause() ; - } -} - -bool LLModelLoader::isNodeAJoint( domNode* pNode ) -{ - if ( pNode->getName() == NULL) - { - return false; - } - - if ( mJointMap.find( pNode->getName() ) != mJointMap.end() ) - { - return true; - } - - return false; -} - -void LLModelLoader::extractTranslation( domTranslate* pTranslate, LLMatrix4& transform ) -{ - domFloat3 jointTrans = pTranslate->getValue(); - LLVector3 singleJointTranslation( jointTrans[0], jointTrans[1], jointTrans[2] ); - transform.setTranslation( singleJointTranslation ); -} - -void LLModelLoader::extractTranslationViaElement( daeElement* pTranslateElement, LLMatrix4& transform ) -{ - domTranslate* pTranslateChild = dynamic_cast( pTranslateElement ); - domFloat3 translateChild = pTranslateChild->getValue(); - LLVector3 singleJointTranslation( translateChild[0], translateChild[1], translateChild[2] ); - transform.setTranslation( singleJointTranslation ); -} - -void LLModelLoader::processJointNode( domNode* pNode, std::map& jointTransforms ) -{ - if (pNode->getName() == NULL) - { - llwarns << "nameless node, can't process" << llendl; - return; - } - - //llwarns<<"ProcessJointNode# Node:" <getName()<( jointResolver.getElement() ); - - //Translation via SID was successful - if ( pTranslate ) - { - extractTranslation( pTranslate, workingTransform ); - } - else - { - //Translation via child from element - daeElement* pTranslateElement = getChildFromElement( pNode, "translate" ); - if ( !pTranslateElement || pTranslateElement->typeID() != domTranslate::ID() ) - { - llwarns<< "The found element is not a translate node" <getName() ] = workingTransform; - - //2. handle the nodes children - - //Gather and handle the incoming nodes children - daeTArray< daeSmartRef > childOfChild = pNode->getChildren(); - S32 childOfChildCount = childOfChild.getCount(); - - for (S32 i = 0; i < childOfChildCount; ++i) - { - domNode* pChildNode = daeSafeCast( childOfChild[i] ); - if ( pChildNode ) - { - processJointNode( pChildNode, jointTransforms ); - } - } -} - -daeElement* LLModelLoader::getChildFromElement( daeElement* pElement, std::string const & name ) -{ - daeElement* pChildOfElement = pElement->getChild( name.c_str() ); - if ( pChildOfElement ) - { - return pChildOfElement; - } - llwarns<< "Could not find a child [" << name << "] for the element: \"" << pElement->getAttribute("id") << "\"" << llendl; - return NULL; -} - -void LLModelLoader::processElement(daeElement* element) -{ - LLMatrix4 saved_transform = mTransform; - - domTranslate* translate = daeSafeCast(element); - if (translate) - { - domFloat3 dom_value = translate->getValue(); - - LLMatrix4 translation; - translation.setTranslation(LLVector3(dom_value[0], dom_value[1], dom_value[2])); - - translation *= mTransform; - mTransform = translation; - } - - domRotate* rotate = daeSafeCast(element); - if (rotate) - { - domFloat4 dom_value = rotate->getValue(); - - LLMatrix4 rotation; - rotation.initRotTrans(dom_value[3] * DEG_TO_RAD, LLVector3(dom_value[0], dom_value[1], dom_value[2]), LLVector3(0, 0, 0)); - - rotation *= mTransform; - mTransform = rotation; - } - - domScale* scale = daeSafeCast(element); - if (scale) - { - domFloat3 dom_value = scale->getValue(); - - LLMatrix4 scaling; - scaling.initScale(LLVector3(dom_value[0], dom_value[1], dom_value[2])); - - scaling *= mTransform; - mTransform = scaling; - } - - domMatrix* matrix = daeSafeCast(element); - if (matrix) - { - domFloat4x4 dom_value = matrix->getValue(); - - LLMatrix4 matrix_transform; - - for (int i = 0; i < 4; i++) - { - for(int j = 0; j < 4; j++) - { - matrix_transform.mMatrix[i][j] = dom_value[i + j*4]; - } - } - - matrix_transform *= mTransform; - mTransform = matrix_transform; - } - - domInstance_geometry* instance_geo = daeSafeCast(element); - if (instance_geo) - { - domGeometry* geo = daeSafeCast(instance_geo->getUrl().getElement()); - if (geo) - { - domMesh* mesh = daeSafeCast(geo->getDescendant(daeElement::matchType(domMesh::ID()))); - if (mesh) - { - LLModel* model = mModel[mesh]; - if (model) - { - LLMatrix4 transformation = mTransform; - - std::vector materials = getMaterials(model, instance_geo); - - // adjust the transformation to compensate for mesh normalization - LLVector3 mesh_scale_vector; - LLVector3 mesh_translation_vector; - model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); - - LLMatrix4 mesh_translation; - mesh_translation.setTranslation(mesh_translation_vector); - mesh_translation *= transformation; - transformation = mesh_translation; - - LLMatrix4 mesh_scale; - mesh_scale.initScale(mesh_scale_vector); - mesh_scale *= transformation; - transformation = mesh_scale; - - mScene[transformation].push_back(LLModelInstance(model, transformation, materials)); - - stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); - } - } - } - } - - domInstance_node* instance_node = daeSafeCast(element); - if (instance_node) - { - daeElement* instance = instance_node->getUrl().getElement(); - if (instance) - { - processElement(instance); - } - } - - //process children - daeTArray< daeSmartRef > children = element->getChildren(); - for (S32 i = 0; i < children.getCount(); i++) - { - processElement(children[i]); - } - - domNode* node = daeSafeCast(element); - if (node) - { //this element was a node, restore transform before processiing siblings - mTransform = saved_transform; - } -} - -std::vector LLModelLoader::getMaterials(LLModel* model, domInstance_geometry* instance_geo) -{ - std::vector materials; - for (int i = 0; i < model->mMaterialList.size(); i++) - { - LLImportMaterial import_material; - - domInstance_material* instance_mat = NULL; - - domBind_material::domTechnique_common* technique = - daeSafeCast(instance_geo->getDescendant(daeElement::matchType(domBind_material::domTechnique_common::ID()))); - - if (technique) - { - daeTArray< daeSmartRef > inst_materials = technique->getChildrenByType(); - for (int j = 0; j < inst_materials.getCount(); j++) - { - std::string symbol(inst_materials[j]->getSymbol()); - - if (symbol == model->mMaterialList[i]) // found the binding - { - instance_mat = inst_materials[j]; - } - } - } - - if (instance_mat) - { - domMaterial* material = daeSafeCast(instance_mat->getTarget().getElement()); - if (material) - { - domInstance_effect* instance_effect = - daeSafeCast(material->getDescendant(daeElement::matchType(domInstance_effect::ID()))); - if (instance_effect) - { - domEffect* effect = daeSafeCast(instance_effect->getUrl().getElement()); - if (effect) - { - domProfile_COMMON* profile = - daeSafeCast(effect->getDescendant(daeElement::matchType(domProfile_COMMON::ID()))); - if (profile) - { - import_material = profileToMaterial(profile); - } - } - } - } - } - - materials.push_back(import_material); - } - - return materials; -} - -LLImportMaterial LLModelLoader::profileToMaterial(domProfile_COMMON* material) -{ - LLImportMaterial mat; - mat.mFullbright = FALSE; - - daeElement* diffuse = material->getDescendant("diffuse"); - if (diffuse) - { - domCommon_color_or_texture_type_complexType::domTexture* texture = - daeSafeCast(diffuse->getDescendant("texture")); - if (texture) - { - domCommon_newparam_type_Array newparams = material->getNewparam_array(); - for (S32 i = 0; i < newparams.getCount(); i++) - { - domFx_surface_common* surface = newparams[i]->getSurface(); - if (surface) - { - domFx_surface_init_common* init = surface->getFx_surface_init_common(); - if (init) - { - domFx_surface_init_from_common_Array init_from = init->getInit_from_array(); - - if (init_from.getCount() > i) - { - domImage* image = daeSafeCast(init_from[i]->getValue().getElement()); - if (image) - { - // we only support init_from now - embedded data will come later - domImage::domInit_from* init = image->getInit_from(); - if (init) - { - mat.mDiffuseMapFilename = cdom::uriToNativePath(init->getValue().str()); - mat.mDiffuseMapLabel = getElementLabel(material); - } - } - } - } - } - } - } - - domCommon_color_or_texture_type_complexType::domColor* color = - daeSafeCast(diffuse->getDescendant("color")); - if (color) - { - domFx_color_common domfx_color = color->getValue(); - LLColor4 value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]); - mat.mDiffuseColor = value; - } - } - - daeElement* emission = material->getDescendant("emission"); - if (emission) - { - LLColor4 emission_color = getDaeColor(emission); - if (((emission_color[0] + emission_color[1] + emission_color[2]) / 3.0) > 0.25) - { - mat.mFullbright = TRUE; - } - } - - return mat; -} - -// try to get a decent label for this element -std::string LLModelLoader::getElementLabel(daeElement *element) -{ - // if we have a name attribute, use it - std::string name = element->getAttribute("name"); - if (name.length()) - { - return name; - } - - // if we have an ID attribute, use it - if (element->getID()) - { - return std::string(element->getID()); - } - - // if we have a parent, use it - daeElement* parent = element->getParent(); - if (parent) - { - // if parent has a name, use it - std::string name = parent->getAttribute("name"); - if (name.length()) - { - return name; - } - - // if parent has an ID, use it - if (parent->getID()) - { - return std::string(parent->getID()); - } - } - - // try to use our type - daeString element_name = element->getElementName(); - if (element_name) - { - return std::string(element_name); - } - - // if all else fails, use "object" - return std::string("object"); -} - -LLColor4 LLModelLoader::getDaeColor(daeElement* element) -{ - LLColor4 value; - domCommon_color_or_texture_type_complexType::domColor* color = - daeSafeCast(element->getDescendant("color")); - if (color) - { - domFx_color_common domfx_color = color->getValue(); - value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]); - } - - return value; -} - -//----------------------------------------------------------------------------- -// LLModelPreview -//----------------------------------------------------------------------------- - -LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) -: LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE), LLMutex(NULL) -{ - mNeedsUpdate = TRUE; - mCameraDistance = 0.f; - mCameraYaw = 0.f; - mCameraPitch = 0.f; - mCameraZoom = 1.f; - mTextureName = 0; - mPreviewLOD = 0; - mModelLoader = NULL; - mMaxTriangleLimit = 0; - mDirty = false; - mGenLOD = false; - mLoading = false; - mGroup = 0; - mBuildShareTolerance = 0.f; - mBuildQueueMode = GLOD_QUEUE_GREEDY; - mBuildBorderMode = GLOD_BORDER_UNLOCK; - mBuildOperator = GLOD_OPERATOR_EDGE_COLLAPSE; - - mViewOption["show_textures"] = false; - - mFMP = fmp; - - glodInit(); -} - -LLModelPreview::~LLModelPreview() -{ - if (mModelLoader) - { - delete mModelLoader; - mModelLoader = NULL; - } - - //*HACK : *TODO : turn this back on when we understand why this crashes - //glodShutdown(); -} - -U32 LLModelPreview::calcResourceCost() -{ - assert_main_thread(); - - rebuildUploadData(); - - if ( mModelLoader->getLoadState() != LLModelLoader::ERROR_PARSING ) - { - mFMP->childEnable("ok_btn"); - } - - U32 cost = 0; - std::set accounted; - U32 num_points = 0; - U32 num_hulls = 0; - - F32 debug_scale = mFMP->childGetValue("import_scale").asReal(); - - F32 streaming_cost = 0.f; - F32 physics_cost = 0.f; - for (U32 i = 0; i < mUploadData.size(); ++i) - { - LLModelInstance& instance = mUploadData[i]; - - if (accounted.find(instance.mModel) == accounted.end()) - { - accounted.insert(instance.mModel); - - LLModel::convex_hull_decomposition& decomp = - instance.mLOD[LLModel::LOD_PHYSICS] ? - instance.mLOD[LLModel::LOD_PHYSICS]->mConvexHullDecomp : - instance.mModel->mConvexHullDecomp; - - LLSD ret = LLModel::writeModel( - "", - instance.mLOD[4], - instance.mLOD[3], - instance.mLOD[2], - instance.mLOD[1], - instance.mLOD[0], - decomp, - mFMP->childGetValue("upload_skin").asBoolean(), - mFMP->childGetValue("upload_joints").asBoolean(), - TRUE); - cost += gMeshRepo.calcResourceCost(ret); - - num_hulls += decomp.size(); - for (U32 i = 0; i < decomp.size(); ++i) - { - num_points += decomp[i].size(); - } - - //calculate streaming cost - LLMatrix4 transformation = instance.mTransform; - - LLVector3 position = LLVector3(0, 0, 0) * transformation; - - LLVector3 x_transformed = LLVector3(1, 0, 0) * transformation - position; - LLVector3 y_transformed = LLVector3(0, 1, 0) * transformation - position; - LLVector3 z_transformed = LLVector3(0, 0, 1) * transformation - position; - F32 x_length = x_transformed.normalize(); - F32 y_length = y_transformed.normalize(); - F32 z_length = z_transformed.normalize(); - LLVector3 scale = LLVector3(x_length, y_length, z_length); - - F32 radius = scale.length()*debug_scale; - - streaming_cost += LLMeshRepository::getStreamingCost(ret, radius); - } - } - - //mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[HULLS]", llformat("%d",num_hulls)); - //mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[POINTS]", llformat("%d",num_points)); - mFMP->childSetTextArg("streaming cost", "[COST]", llformat("%.3f", streaming_cost)); - mFMP->childSetTextArg("physics cost", "[COST]", llformat("%.3f", physics_cost)); - F32 scale = mFMP->childGetValue("import_scale").asReal()*2.f; - mFMP->childSetTextArg("import_dimensions", "[X]", llformat("%.3f", mPreviewScale[0]*scale)); - mFMP->childSetTextArg("import_dimensions", "[Y]", llformat("%.3f", mPreviewScale[1]*scale)); - mFMP->childSetTextArg("import_dimensions", "[Z]", llformat("%.3f", mPreviewScale[2]*scale)); - - updateStatusMessages(); - - return cost; -} - -void LLModelPreview::rebuildUploadData() -{ - assert_main_thread(); - - mUploadData.clear(); - mTextureSet.clear(); - - //fill uploaddata instance vectors from scene data - - std::string requested_name = mFMP->getChild("description_form")->getValue().asString(); - - - LLSpinCtrl* scale_spinner = mFMP->getChild("import_scale"); - - if (!scale_spinner) - { - llerrs << "floater_model_preview.xml MUST contain import_scale spinner." << llendl; - } - - F32 scale = scale_spinner->getValue().asReal(); - - LLMatrix4 scale_mat; - scale_mat.initScale(LLVector3(scale, scale, scale)); - - F32 max_scale = 0.f; - - if ( mBaseScene.size() > 0 ) - { - mFMP->childEnable("ok_btn"); - } - - for (LLModelLoader::scene::iterator iter = mBaseScene.begin(); iter != mBaseScene.end(); ++iter) - { //for each transform in scene - LLMatrix4 mat = iter->first; - - // compute position - LLVector3 position = LLVector3(0, 0, 0) * mat; - - // compute scale - LLVector3 x_transformed = LLVector3(1, 0, 0) * mat - position; - LLVector3 y_transformed = LLVector3(0, 1, 0) * mat - position; - LLVector3 z_transformed = LLVector3(0, 0, 1) * mat - position; - F32 x_length = x_transformed.normalize(); - F32 y_length = y_transformed.normalize(); - F32 z_length = z_transformed.normalize(); - - max_scale = llmax(llmax(llmax(max_scale, x_length), y_length), z_length); - - mat *= scale_mat; - - for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) - { //for each instance with said transform applied - LLModelInstance instance = *model_iter; - - LLModel* base_model = instance.mModel; - if (base_model) - { - base_model->mRequestedLabel = requested_name; - } - - S32 idx = 0; - for (idx = 0; idx < mBaseModel.size(); ++idx) - { //find reference instance for this model - if (mBaseModel[idx] == base_model) - { - break; - } - } - - for (U32 i = 0; i < LLModel::NUM_LODS; i++) - { //fill LOD slots based on reference model index - if (!mModel[i].empty()) - { - instance.mLOD[i] = mModel[i][idx]; - } - else - { - instance.mLOD[i] = NULL; - } - } - - instance.mTransform = mat; - mUploadData.push_back(instance); - } - } - - F32 max_import_scale = DEFAULT_MAX_PRIM_SCALE/max_scale; - - scale_spinner->setMaxValue(max_import_scale); - - if (max_import_scale < scale) - { - scale_spinner->setValue(max_import_scale); - } - -} - - -void LLModelPreview::clearModel(S32 lod) -{ - if (lod < 0 || lod > LLModel::LOD_PHYSICS) - { - return; - } - - mVertexBuffer[lod].clear(); - mModel[lod].clear(); - mScene[lod].clear(); -} - -void LLModelPreview::loadModel(std::string filename, S32 lod) -{ - assert_main_thread(); - - LLMutexLock lock(this); - - if (mModelLoader) - { - delete mModelLoader; - mModelLoader = NULL; - } - - if (filename.empty()) - { - if (mBaseModel.empty()) - { - // this is the initial file picking. Close the whole floater - // if we don't have a base model to show for high LOD. - mFMP->closeFloater(false); - } - - mLoading = false; - return; - } - - mLODFile[lod] = filename; - - if (lod == LLModel::LOD_HIGH) - { - clearGLODGroup(); - } - - mModelLoader = new LLModelLoader(filename, lod, this); - - mModelLoader->start(); - - mFMP->childSetTextArg("status", "[STATUS]", mFMP->getString("status_reading_file")); - - setPreviewLOD(lod); - - if ( mModelLoader->getLoadState() == LLModelLoader::ERROR_PARSING ) - { - mFMP->childDisable("ok_btn"); - } - - if (lod == mPreviewLOD) - { - mFMP->childSetText("lod_file", mLODFile[mPreviewLOD]); - } - else if (lod == LLModel::LOD_PHYSICS) - { - mFMP->childSetText("physics_file", mLODFile[lod]); - } - - mFMP->openFloater(); -} - -void LLModelPreview::setPhysicsFromLOD(S32 lod) -{ - assert_main_thread(); - - if (lod >= 0 && lod <= 3) - { - mModel[LLModel::LOD_PHYSICS] = mModel[lod]; - mScene[LLModel::LOD_PHYSICS] = mScene[lod]; - mLODFile[LLModel::LOD_PHYSICS].clear(); - mFMP->childSetText("physics_file", mLODFile[LLModel::LOD_PHYSICS]); - mVertexBuffer[LLModel::LOD_PHYSICS].clear(); - rebuildUploadData(); - refresh(); - updateStatusMessages(); - } -} - -void LLModelPreview::clearIncompatible(S32 lod) -{ - for (U32 i = 0; i <= LLModel::LOD_HIGH; i++) - { //clear out any entries that aren't compatible with this model - if (i != lod) - { - if (mModel[i].size() != mModel[lod].size()) - { - mModel[i].clear(); - mScene[i].clear(); - mVertexBuffer[i].clear(); - - if (i == LLModel::LOD_HIGH) - { - mBaseModel = mModel[lod]; - clearGLODGroup(); - mBaseScene = mScene[lod]; - mVertexBuffer[5].clear(); - } - } - } - } -} - -void LLModelPreview::clearGLODGroup() -{ - if (mGroup) - { - for (std::map, U32>::iterator iter = mObject.begin(); iter != mObject.end(); ++iter) - { - glodDeleteObject(iter->second); - stop_gloderror(); - } - mObject.clear(); - - glodDeleteGroup(mGroup); - stop_gloderror(); - mGroup = 0; - } -} - -void LLModelPreview::loadModelCallback(S32 lod) -{ - assert_main_thread(); - - LLMutexLock lock(this); - if (!mModelLoader) - { - return; - } - - mModelLoader->loadTextures() ; - mModel[lod] = mModelLoader->mModelList; - mScene[lod] = mModelLoader->mScene; - mVertexBuffer[lod].clear(); - - if (lod == LLModel::LOD_PHYSICS) - { - mPhysicsMesh.clear(); - } - - setPreviewLOD(lod); - - - if (lod == LLModel::LOD_HIGH) - { //save a copy of the highest LOD for automatic LOD manipulation - if (mBaseModel.empty()) - { //first time we've loaded a model, auto-gen LoD - mGenLOD = true; - } - - mBaseModel = mModel[lod]; - clearGLODGroup(); - - mBaseScene = mScene[lod]; - mVertexBuffer[5].clear(); - } - - clearIncompatible(lod); - - mDirty = true; - - if (lod == LLModel::LOD_HIGH) - { - resetPreviewTarget(); - } - - mLoading = false; - refresh(); -} - -void LLModelPreview::resetPreviewTarget() -{ - mPreviewTarget = (mModelLoader->mExtents[0] + mModelLoader->mExtents[1]) * 0.5f; - mPreviewScale = (mModelLoader->mExtents[1] - mModelLoader->mExtents[0]) * 0.5f; - setPreviewTarget(mPreviewScale.magVec()*2.f); -} - -void LLModelPreview::generateNormals() -{ - assert_main_thread(); - - S32 which_lod = mPreviewLOD; - - - if (which_lod > 4 || which_lod < 0 || - mModel[which_lod].empty()) - { - return; - } - - F32 angle_cutoff = mFMP->childGetValue("crease_angle").asReal(); - - angle_cutoff *= DEG_TO_RAD; - - if (which_lod == 3 && !mBaseModel.empty()) - { - for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) - { - (*iter)->generateNormals(angle_cutoff); - } - - mVertexBuffer[5].clear(); - } - - for (LLModelLoader::model_list::iterator iter = mModel[which_lod].begin(); iter != mModel[which_lod].end(); ++iter) - { - (*iter)->generateNormals(angle_cutoff); - } - - mVertexBuffer[which_lod].clear(); - refresh(); - -} - -void LLModelPreview::consolidate() -{ - std::map > composite; - - LLMatrix4 identity; - - //bake out each node in current scene to composite - for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) - { //for each transform in current scene - LLMatrix4 mat = iter->first; - glh::matrix4f inv_trans = glh::matrix4f((F32*) mat.mMatrix).inverse().transpose(); - LLMatrix4 norm_mat(inv_trans.m); - - for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) - { //for each instance with that transform - LLModelInstance& source_instance = *model_iter; - LLModel* source = source_instance.mModel; - - if (!validate_model(source)) - { - llerrs << "Invalid model found!" << llendl; - } - - for (S32 i = 0; i < source->getNumVolumeFaces(); ++i) - { //for each face in instance - const LLVolumeFace& src_face = source->getVolumeFace(i); - LLImportMaterial& source_material = source_instance.mMaterial[i]; - - //get model in composite that is composite for this material - LLModel* model = NULL; - - if (composite.find(source_material) != composite.end()) - { - model = composite[source_material].rbegin()->mModel; - if (model->getVolumeFace(0).mNumVertices + src_face.mNumVertices > 65535) - { - model = NULL; - } - } - - if (model == NULL) - { //no model found, make new model - std::vector materials; - materials.push_back(source_material); - LLVolumeParams volume_params; - volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); - model = new LLModel(volume_params, 0.f); - model->mLabel = source->mLabel; - model->setNumVolumeFaces(0); - composite[source_material].push_back(LLModelInstance(model, identity, materials)); - } - - model->appendFace(src_face, source->mMaterialList[i], mat, norm_mat); - } - } - } - - - //condense composite into as few LLModel instances as possible - LLModelLoader::model_list new_model; - std::vector instance_list; - - LLVolumeParams volume_params; - volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); - - std::vector empty_material; - LLModelInstance cur_instance(new LLModel(volume_params, 0.f), identity, empty_material); - cur_instance.mModel->setNumVolumeFaces(0); - - BOOL first_transform = TRUE; - - LLModelLoader::scene new_scene; - LLVector3 min,max; - - for (std::map >::iterator iter = composite.begin(); - iter != composite.end(); - ++iter) - { - std::map >::iterator next_iter = iter; ++next_iter; - - for (std::vector::iterator instance_iter = iter->second.begin(); - instance_iter != iter->second.end(); - ++instance_iter) - { - LLModel* source = instance_iter->mModel; - - if (instance_iter->mMaterial.size() != 1) - { - llerrs << "WTF?" << llendl; - } - - if (source->getNumVolumeFaces() != 1) - { - llerrs << "WTF?" << llendl; - } - - if (source->mMaterialList.size() != 1) - { - llerrs << "WTF?" << llendl; - } - - cur_instance.mModel->addFace(source->getVolumeFace(0)); - cur_instance.mMaterial.push_back(instance_iter->mMaterial[0]); - cur_instance.mModel->mMaterialList.push_back(source->mMaterialList[0]); - - BOOL last_model = FALSE; - - std::vector::iterator next_instance = instance_iter; ++next_instance; - - if (next_iter == composite.end() && - next_instance == iter->second.end()) - { - last_model = TRUE; - } - - if (last_model || cur_instance.mModel->getNumVolumeFaces() >= MAX_MODEL_FACES) - { - cur_instance.mModel->mLabel = source->mLabel; - - cur_instance.mModel->optimizeVolumeFaces(); - cur_instance.mModel->normalizeVolumeFaces(); - - if (!validate_model(cur_instance.mModel)) - { - llerrs << "Invalid model detected." << llendl; - } - - new_model.push_back(cur_instance.mModel); - - LLMatrix4 transformation = LLMatrix4(); - - // adjust the transformation to compensate for mesh normalization - LLVector3 mesh_scale_vector; - LLVector3 mesh_translation_vector; - cur_instance.mModel->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); - - LLMatrix4 mesh_translation; - mesh_translation.setTranslation(mesh_translation_vector); - mesh_translation *= transformation; - transformation = mesh_translation; - - LLMatrix4 mesh_scale; - mesh_scale.initScale(mesh_scale_vector); - mesh_scale *= transformation; - transformation = mesh_scale; - - cur_instance.mTransform = transformation; - - new_scene[transformation].push_back(cur_instance); - stretch_extents(cur_instance.mModel, transformation, min, max, first_transform); - - if (!last_model) - { - cur_instance = LLModelInstance(new LLModel(volume_params, 0.f), identity, empty_material); - cur_instance.mModel->setNumVolumeFaces(0); - } - } - } - } - - mScene[mPreviewLOD] = new_scene; - mModel[mPreviewLOD] = new_model; - mVertexBuffer[mPreviewLOD].clear(); - - if (mPreviewLOD == LLModel::LOD_HIGH) - { - mBaseScene = new_scene; - mBaseModel = new_model; - clearGLODGroup(); - mVertexBuffer[5].clear(); - } - - mPreviewTarget = (min+max)*0.5f; - mPreviewScale = (max-min)*0.5f; - setPreviewTarget(mPreviewScale.magVec()*2.f); - - clearIncompatible(mPreviewLOD); - - mResourceCost = calcResourceCost(); - refresh(); -} - -void LLModelPreview::clearMaterials() -{ - for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) - { //for each transform in current scene - for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) - { //for each instance with that transform - LLModelInstance& source_instance = *model_iter; - LLModel* source = source_instance.mModel; - - for (S32 i = 0; i < source->getNumVolumeFaces(); ++i) - { //for each face in instance - LLImportMaterial& source_material = source_instance.mMaterial[i]; - - //clear material info - source_material.mDiffuseColor = LLColor4(1,1,1,1); - source_material.mDiffuseMap = NULL; - source_material.mDiffuseMapFilename.clear(); - source_material.mDiffuseMapLabel.clear(); - source_material.mFullbright = false; - } - } - } - - mVertexBuffer[mPreviewLOD].clear(); - - if (mPreviewLOD == LLModel::LOD_HIGH) - { - mBaseScene = mScene[mPreviewLOD]; - mBaseModel = mModel[mPreviewLOD]; - clearGLODGroup(); - mVertexBuffer[5].clear(); - } - - mResourceCost = calcResourceCost(); - refresh(); -} - -bool LLModelPreview::containsRiggedAsset( void ) -{ - //loop through the models and determine if any of them contained a rigged asset, and if so - //return true. - //This is used to cleanup the joint positions after a preview. - for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) - { - LLModel* pModel = *iter; - if ( pModel->mAlternateBindMatrix.size() > 0 ) - { - return true; - } - } - return false; -} -void LLModelPreview::genLODs(S32 which_lod, U32 decimation) -{ - if (mBaseModel.empty()) - { - return; - } - - if (which_lod == LLModel::LOD_PHYSICS) - { //clear physics mesh map - mPhysicsMesh.clear(); - } - - LLVertexBuffer::unbind(); - - stop_gloderror(); - static U32 cur_name = 1; - - S32 limit = -1; - - U32 triangle_count = 0; - - for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) - { - LLModel* mdl = *iter; - for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) - { - triangle_count += mdl->getVolumeFace(i).mNumIndices/3; - } - } - - U32 base_triangle_count = triangle_count; - - U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; - - U32 lod_mode = 0; - - LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode"); - if (iface) - { - lod_mode = iface->getFirstSelectedIndex(); - } - - F32 lod_error_threshold = mFMP->childGetValue("lod_error_threshold").asReal(); - - if (lod_mode == 0) - { - lod_mode = GLOD_TRIANGLE_BUDGET; - if (which_lod != -1) - { - //SH-632 take budget as supplied limit+1 to prevent GLOD from creating a smaller - //decimation when the given decimation is possible - limit = mFMP->childGetValue("lod_triangle_limit").asInteger(); //+1; - } - } - else - { - lod_mode = GLOD_ERROR_THRESHOLD; - } - - U32 build_operator = 0; - - iface = mFMP->childGetSelectionInterface("build_operator"); - if (iface) - { - build_operator = iface->getFirstSelectedIndex(); - } - - if (build_operator == 0) - { - build_operator = GLOD_OPERATOR_EDGE_COLLAPSE; - } - else - { - build_operator = GLOD_OPERATOR_HALF_EDGE_COLLAPSE; - } - - U32 queue_mode=0; - iface = mFMP->childGetSelectionInterface("queue_mode"); - if (iface) - { - queue_mode = iface->getFirstSelectedIndex(); - } - - if (queue_mode == 0) - { - queue_mode = GLOD_QUEUE_GREEDY; - } - else if (queue_mode == 1) - { - queue_mode = GLOD_QUEUE_LAZY; - } - else - { - queue_mode = GLOD_QUEUE_INDEPENDENT; - } - - U32 border_mode = 0; - - iface = mFMP->childGetSelectionInterface("border_mode"); - if (iface) - { - border_mode = iface->getFirstSelectedIndex(); - } - - if (border_mode == 0) - { - border_mode = GLOD_BORDER_UNLOCK; - } - else - { - border_mode = GLOD_BORDER_LOCK; - } - - bool object_dirty = false; - if (border_mode != mBuildBorderMode) - { - mBuildBorderMode = border_mode; - object_dirty = true; - } - - if (queue_mode != mBuildQueueMode) - { - mBuildQueueMode = queue_mode; - object_dirty = true; - } - - if (build_operator != mBuildOperator) - { - mBuildOperator = build_operator; - object_dirty = true; - } - - F32 share_tolerance = mFMP->childGetValue("share_tolerance").asReal(); - if (share_tolerance != mBuildShareTolerance) - { - mBuildShareTolerance = share_tolerance; - object_dirty = true; - } - - if (mGroup == 0) - { - object_dirty = true; - mGroup = cur_name++; - glodNewGroup(mGroup); - } - - if (object_dirty) - { - for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) - { //build GLOD objects for each model in base model list - LLModel* mdl = *iter; - - if (mObject[mdl] != 0) - { - glodDeleteObject(mObject[mdl]); - } - - mObject[mdl] = cur_name++; - - glodNewObject(mObject[mdl], mGroup, GLOD_DISCRETE); - stop_gloderror(); - - if (iter == mBaseModel.begin() && !mdl->mSkinWeights.empty()) - { //regenerate vertex buffer for skinned models to prevent animation feedback during LOD generation - mVertexBuffer[5].clear(); - } - - if (mVertexBuffer[5].empty()) - { - genBuffers(5, false); - } - - U32 tri_count = 0; - for (U32 i = 0; i < mVertexBuffer[5][mdl].size(); ++i) - { - mVertexBuffer[5][mdl][i]->setBuffer(type_mask); - U32 num_indices = mVertexBuffer[5][mdl][i]->getNumIndices(); - if (num_indices > 2) - { - glodInsertElements(mObject[mdl], i, GL_TRIANGLES, num_indices, GL_UNSIGNED_SHORT, mVertexBuffer[5][mdl][i]->getIndicesPointer(), 0, 0.f); - } - tri_count += num_indices/3; - stop_gloderror(); - } - - glodObjectParameteri(mObject[mdl], GLOD_BUILD_OPERATOR, build_operator); - stop_gloderror(); - - glodObjectParameteri(mObject[mdl], GLOD_BUILD_QUEUE_MODE, queue_mode); - stop_gloderror(); - - glodObjectParameteri(mObject[mdl], GLOD_BUILD_BORDER_MODE, border_mode); - stop_gloderror(); - - glodObjectParameterf(mObject[mdl], GLOD_BUILD_SHARE_TOLERANCE, share_tolerance); - stop_gloderror(); - - glodBuildObject(mObject[mdl]); - stop_gloderror(); - } - } - - - S32 start = LLModel::LOD_HIGH; - S32 end = 0; - - if (which_lod != -1) - { - start = end = which_lod; - } - else - { - //SH-632 -- incremenet triangle count to avoid removing any triangles from - //highest LoD when auto-generating LoD - triangle_count++; - } - - - mMaxTriangleLimit = base_triangle_count; - - for (S32 lod = start; lod >= end; --lod) - { - if (which_lod == -1) - { - if (lod < start) - { - triangle_count /= decimation; - } - } - else - { - triangle_count = limit; - } - - mModel[lod].clear(); - mModel[lod].resize(mBaseModel.size()); - mVertexBuffer[lod].clear(); - - U32 actual_tris = 0; - U32 actual_verts = 0; - U32 submeshes = 0; - - glodGroupParameteri(mGroup, GLOD_ADAPT_MODE, lod_mode); - stop_gloderror(); - - glodGroupParameteri(mGroup, GLOD_ERROR_MODE, GLOD_OBJECT_SPACE_ERROR); - stop_gloderror(); - - glodGroupParameteri(mGroup, GLOD_MAX_TRIANGLES, triangle_count); - stop_gloderror(); - - glodGroupParameterf(mGroup, GLOD_OBJECT_SPACE_ERROR_THRESHOLD, lod_error_threshold); - stop_gloderror(); - - glodAdaptGroup(mGroup); - stop_gloderror(); - - for (U32 mdl_idx = 0; mdl_idx < mBaseModel.size(); ++mdl_idx) - { - LLModel* base = mBaseModel[mdl_idx]; - - GLint patch_count = 0; - glodGetObjectParameteriv(mObject[base], GLOD_NUM_PATCHES, &patch_count); - stop_gloderror(); - - LLVolumeParams volume_params; - volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); - mModel[lod][mdl_idx] = new LLModel(volume_params, 0.f); - - GLint* sizes = new GLint[patch_count*2]; - glodGetObjectParameteriv(mObject[base], GLOD_PATCH_SIZES, sizes); - stop_gloderror(); - - GLint* names = new GLint[patch_count]; - glodGetObjectParameteriv(mObject[base], GLOD_PATCH_NAMES, names); - stop_gloderror(); - - mModel[lod][mdl_idx]->setNumVolumeFaces(patch_count); - - LLModel* target_model = mModel[lod][mdl_idx]; - - for (GLint i = 0; i < patch_count; ++i) - { - LLPointer buff = new LLVertexBuffer(type_mask, 0); - - if (sizes[i*2+1] > 0 && sizes[i*2] > 0) - { - buff->allocateBuffer(sizes[i*2+1], sizes[i*2], true); - buff->setBuffer(type_mask); - glodFillElements(mObject[base], names[i], GL_UNSIGNED_SHORT, buff->getIndicesPointer()); - stop_gloderror(); - } - else - { //this face was eliminated, create a dummy triangle (one vertex, 3 indices, all 0) - buff->allocateBuffer(1, 3, true); - memset(buff->getMappedData(), 0, buff->getSize()); - memset(buff->getIndicesPointer(), 0, buff->getIndicesSize()); - } - - buff->validateRange(0, buff->getNumVerts()-1, buff->getNumIndices(), 0); - - LLStrider pos; - LLStrider norm; - LLStrider tc; - LLStrider index; - - buff->getVertexStrider(pos); - buff->getNormalStrider(norm); - buff->getTexCoord0Strider(tc); - buff->getIndexStrider(index); - - target_model->setVolumeFaceData(names[i], pos, norm, tc, index, buff->getNumVerts(), buff->getNumIndices()); - actual_tris += buff->getNumIndices()/3; - actual_verts += buff->getNumVerts(); - ++submeshes; - - if (!validate_face(target_model->getVolumeFace(names[i]))) - { - llerrs << "Invalid face generated during LOD generation." << llendl; - } - } - - //blind copy skin weights and just take closest skin weight to point on - //decimated mesh for now (auto-generating LODs with skin weights is still a bit - //of an open problem). - target_model->mPosition = base->mPosition; - target_model->mSkinWeights = base->mSkinWeights; - target_model->mJointMap = base->mJointMap; - target_model->mJointList = base->mJointList; - target_model->mInvBindMatrix = base->mInvBindMatrix; - target_model->mBindShapeMatrix = base->mBindShapeMatrix; - target_model->mAlternateBindMatrix = base->mAlternateBindMatrix; - //copy material list - target_model->mMaterialList = base->mMaterialList; - - if (!validate_model(target_model)) - { - llerrs << "Invalid model generated when creating LODs" << llendl; - } - - delete [] sizes; - delete [] names; - } - - //rebuild scene based on mBaseScene - mScene[lod].clear(); - mScene[lod] = mBaseScene; - - for (U32 i = 0; i < mBaseModel.size(); ++i) - { - LLModel* mdl = mBaseModel[i]; - LLModel* target = mModel[lod][i]; - if (target) - { - for (LLModelLoader::scene::iterator iter = mScene[lod].begin(); iter != mScene[lod].end(); ++iter) - { - for (U32 j = 0; j < iter->second.size(); ++j) - { - if (iter->second[j].mModel == mdl) - { - iter->second[j].mModel = target; - } - } - } - } - } - } - - mResourceCost = calcResourceCost(); - - /*if (which_lod == -1 && mScene[LLModel::LOD_PHYSICS].empty()) - { //build physics scene - mScene[LLModel::LOD_PHYSICS] = mScene[LLModel::LOD_LOW]; - mModel[LLModel::LOD_PHYSICS] = mModel[LLModel::LOD_LOW]; - - for (U32 i = 1; i < mModel[LLModel::LOD_PHYSICS].size(); ++i) - { - mPhysicsQ.push(mModel[LLModel::LOD_PHYSICS][i]); - } - }*/ -} - -void LLModelPreview::updateStatusMessages() -{ - assert_main_thread(); - - //triangle/vertex/submesh count for each mesh asset for each lod - std::vector tris[LLModel::NUM_LODS]; - std::vector verts[LLModel::NUM_LODS]; - std::vector submeshes[LLModel::NUM_LODS]; - - //total triangle/vertex/submesh count for each lod - S32 total_tris[LLModel::NUM_LODS]; - S32 total_verts[LLModel::NUM_LODS]; - S32 total_submeshes[LLModel::NUM_LODS]; - - for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) - { - //initialize total for this lod to 0 - total_tris[lod] = total_verts[lod] = total_submeshes[lod] = 0; - - for (U32 i = 0; i < mModel[lod].size(); ++i) - { //for each model in the lod - S32 cur_tris = 0; - S32 cur_verts = 0; - S32 cur_submeshes = mModel[lod][i]->getNumVolumeFaces(); - - for (S32 j = 0; j < cur_submeshes; ++j) - { //for each submesh (face), add triangles and vertices to current total - const LLVolumeFace& face = mModel[lod][i]->getVolumeFace(j); - cur_tris += face.mNumIndices/3; - cur_verts += face.mNumVertices; - } - - //add this model to the lod total - total_tris[lod] += cur_tris; - total_verts[lod] += cur_verts; - total_submeshes[lod] += cur_submeshes; - - //store this model's counts to asset data - tris[lod].push_back(cur_tris); - verts[lod].push_back(cur_verts); - submeshes[lod].push_back(cur_submeshes); - } - } - - if (mMaxTriangleLimit == 0) - { - mMaxTriangleLimit = total_tris[LLModel::LOD_HIGH]; - } - - - mFMP->childSetTextArg("submeshes_info", "[SUBMESHES]", llformat("%d", total_submeshes[LLModel::LOD_HIGH])); - - std::string mesh_status_na = mFMP->getString("mesh_status_na"); - - S32 upload_status[LLModel::LOD_HIGH+1]; - - bool upload_ok = true; - - for (S32 lod = 0; lod <= LLModel::LOD_HIGH; ++lod) - { - upload_status[lod] = 0; - - std::string message = "mesh_status_good"; - - if (total_tris[lod] > 0) - { - mFMP->childSetText(lod_triangles_name[lod], llformat("%d", total_tris[lod])); - mFMP->childSetText(lod_vertices_name[lod], llformat("%d", total_verts[lod])); - } - else - { - if (lod == LLModel::LOD_HIGH) - { - upload_status[lod] = 2; - message = "mesh_status_missing_lod"; - } - else - { - for (S32 i = lod-1; i >= 0; --i) - { - if (total_tris[i] > 0) - { - upload_status[lod] = 2; - message = "mesh_status_missing_lod"; - } - } - } - - mFMP->childSetText(lod_triangles_name[lod], mesh_status_na); - mFMP->childSetText(lod_vertices_name[lod], mesh_status_na); - } - - const U32 lod_high = LLModel::LOD_HIGH; - - if (lod != lod_high) - { - if (total_submeshes[lod] && total_submeshes[lod] != total_submeshes[lod_high]) - { //number of submeshes is different - message = "mesh_status_submesh_mismatch"; - upload_status[lod] = 2; - } - else if (!tris[lod].empty() && tris[lod].size() != tris[lod_high].size()) - { //number of meshes is different - message = "mesh_status_mesh_mismatch"; - upload_status[lod] = 2; - } - else if (!verts[lod].empty()) - { - for (U32 i = 0; i < verts[lod].size(); ++i) - { - S32 max_verts = i < verts[lod+1].size() ? verts[lod+1][i] : 0; - - if (max_verts > 0) - { - if (verts[lod][i] > max_verts) - { //too many vertices in this lod - message = "mesh_status_too_many_vertices"; - upload_status[lod] = 2; - } - } - } - } - } - - LLIconCtrl* icon = mFMP->getChild(lod_icon_name[lod]); - LLUIImagePtr img = LLUI::getUIImage(lod_status_image[upload_status[lod]]); - icon->setVisible(true); - icon->setImage(img); - - if (upload_status[lod] >= 2) - { - upload_ok = false; - } - - if (lod == mPreviewLOD) - { - mFMP->childSetText("lod_status_message_text", mFMP->getString(message)); - icon = mFMP->getChild("lod_status_message_icon"); - icon->setImage(img); - } - } - - bool errorStateFromLoader = mModelLoader->getLoadState() == LLModelLoader::ERROR_PARSING ? true : false; - - if ( upload_ok && !errorStateFromLoader ) - { - mFMP->childEnable("ok_btn"); - } - else - { - mFMP->childDisable("ok_btn"); - } - - //add up physics triangles etc - S32 start = 0; - S32 end = mModel[LLModel::LOD_PHYSICS].size(); - - S32 phys_tris = 0; - S32 phys_hulls = 0; - S32 phys_points = 0; - - for (S32 i = start; i < end; ++i) - { //add up hulls and points and triangles for selected mesh(es) - LLModel* model = mModel[LLModel::LOD_PHYSICS][i]; - S32 cur_submeshes = model->getNumVolumeFaces(); - - LLModel::convex_hull_decomposition& decomp = model->mConvexHullDecomp; - - if (!decomp.empty()) - { - phys_hulls += decomp.size(); - for (U32 i = 0; i < decomp.size(); ++i) - { - phys_points += decomp[i].size(); - } - } - else - { //choose physics shape OR decomposition, can't use both - for (S32 j = 0; j < cur_submeshes; ++j) - { //for each submesh (face), add triangles and vertices to current total - const LLVolumeFace& face = model->getVolumeFace(j); - phys_tris += face.mNumIndices/3; - } - } - } - - if (phys_tris > 0) - { - mFMP->childSetTextArg("physics_triangles", "[TRIANGLES]", llformat("%d", phys_tris)); - } - else - { - mFMP->childSetTextArg("physics_triangles", "[TRIANGLES]", mesh_status_na); - } - - if (phys_hulls > 0) - { - mFMP->childSetTextArg("physics_hulls", "[HULLS]", llformat("%d", phys_hulls)); - mFMP->childSetTextArg("physics_points", "[POINTS]", llformat("%d", phys_points)); - } - else - { - mFMP->childSetTextArg("physics_hulls", "[HULLS]", mesh_status_na); - mFMP->childSetTextArg("physics_points", "[POINTS]", mesh_status_na); - } - - LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; - if (fmp) - { - if (phys_tris > 0 || phys_hulls > 0) - { - if (!fmp->isViewOptionEnabled("show_physics")) - { - fmp->enableViewOption("show_physics"); - mViewOption["show_physics"] = true; - } - } - else - { - fmp->disableViewOption("show_physics"); - mViewOption["show_physics"] = false; - - } - - //bool use_hull = fmp->childGetValue("physics_use_hull").asBoolean(); - - //fmp->childSetEnabled("physics_optimize", !use_hull); - - bool enable = phys_tris > 0 || phys_hulls > 0; - //enable = enable && !use_hull && fmp->childGetValue("physics_optimize").asBoolean(); - - //enable/disable "analysis" UI - LLPanel* panel = fmp->getChild("physics analysis"); - LLView* child = panel->getFirstChild(); - while (child) - { - child->setEnabled(enable); - child = panel->findNextSibling(child); - } - - enable = phys_hulls > 0; - //enable/disable "simplification" UI - panel = fmp->getChild("physics simplification"); - child = panel->getFirstChild(); - while (child) - { - child->setEnabled(enable); - child = panel->findNextSibling(child); - } - } - - const char* lod_controls[] = - { - "lod_mode", - "lod_triangle_limit", - "lod_error_tolerance", - "build_operator_text", - "queue_mode_text", - "border_mode_text", - "share_tolerance_text", - "build_operator", - "queue_mode", - "border_mode", - "share_tolerance" - }; - const U32 num_lod_controls = sizeof(lod_controls)/sizeof(char*); - - const char* file_controls[] = - { - "lod_browse", - "lod_file" - }; - const U32 num_file_controls = sizeof(file_controls)/sizeof(char*); - - if (fmp) - { - //enable/disable controls based on radio groups - if (mFMP->childGetValue("lod_from_file").asBoolean()) - { - fmp->mLODMode[mPreviewLOD] = 0; - for (U32 i = 0; i < num_file_controls; ++i) - { - mFMP->childEnable(file_controls[i]); - } - - for (U32 i = 0; i < num_lod_controls; ++i) - { - mFMP->childDisable(lod_controls[i]); - } - } - else if (mFMP->childGetValue("lod_none").asBoolean()) - { - fmp->mLODMode[mPreviewLOD] = 2; - for (U32 i = 0; i < num_file_controls; ++i) - { - mFMP->childDisable(file_controls[i]); - } - - for (U32 i = 0; i < num_lod_controls; ++i) - { - mFMP->childDisable(lod_controls[i]); - } - - if (!mModel[mPreviewLOD].empty()) - { - mModel[mPreviewLOD].clear(); - mScene[mPreviewLOD].clear(); - mVertexBuffer[mPreviewLOD].clear(); - - //this can cause phasing issues with the UI, so reenter this function and return - updateStatusMessages(); - return; - } - } - else - { // auto generate, also the default case for wizard which has no radio selection - fmp->mLODMode[mPreviewLOD] = 1; - - for (U32 i = 0; i < num_file_controls; ++i) - { - mFMP->childDisable(file_controls[i]); - } - - for (U32 i = 0; i < num_lod_controls; ++i) - { - mFMP->childEnable(lod_controls[i]); - } - - //if (threshold) - { - U32 lod_mode = 0; - LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode"); - if (iface) - { - lod_mode = iface->getFirstSelectedIndex(); - } - - LLSpinCtrl* threshold = mFMP->getChild("lod_error_threshold"); - LLSpinCtrl* limit = mFMP->getChild("lod_triangle_limit"); - - limit->setMaxValue(mMaxTriangleLimit); - limit->setValue(total_tris[mPreviewLOD]); - - if (lod_mode == 0) - { - limit->setVisible(true); - threshold->setVisible(false); - - limit->setMaxValue(mMaxTriangleLimit); - } - else - { - limit->setVisible(false); - threshold->setVisible(true); - } - } - } - } - - if (mFMP->childGetValue("physics_load_from_file").asBoolean()) - { - mFMP->childDisable("physics_lod_combo"); - mFMP->childEnable("physics_file"); - mFMP->childEnable("physics_browse"); - } - else - { - mFMP->childEnable("physics_lod_combo"); - mFMP->childDisable("physics_file"); - mFMP->childDisable("physics_browse"); - } -} - -void LLModelPreview::setPreviewTarget(F32 distance) -{ - mCameraDistance = distance; - mCameraZoom = 1.f; - mCameraPitch = 0.f; - mCameraYaw = 0.f; - mCameraOffset.clearVec(); -} - -void LLModelPreview::clearBuffers() -{ - for (U32 i = 0; i < 6; i++) - { - mVertexBuffer[i].clear(); - } -} - -void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights) -{ - U32 tri_count = 0; - U32 vertex_count = 0; - U32 mesh_count = 0; - - LLModelLoader::model_list* model = NULL; - - if (lod < 0 || lod > 4) - { - model = &mBaseModel; - lod = 5; - } - else - { - model = &(mModel[lod]); - } - - if (!mVertexBuffer[lod].empty()) - { - mVertexBuffer[lod].clear(); - } - - mVertexBuffer[lod].clear(); - - LLModelLoader::model_list::iterator base_iter = mBaseModel.begin(); - - for (LLModelLoader::model_list::iterator iter = model->begin(); iter != model->end(); ++iter) - { - LLModel* mdl = *iter; - if (!mdl) - { - continue; - } - - LLModel* base_mdl = *base_iter; - base_iter++; - - for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) - { - const LLVolumeFace &vf = mdl->getVolumeFace(i); - U32 num_vertices = vf.mNumVertices; - U32 num_indices = vf.mNumIndices; - - if (!num_vertices || ! num_indices) - { - continue; - } - - LLVertexBuffer* vb = NULL; - - bool skinned = include_skin_weights && !mdl->mSkinWeights.empty(); - - U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; - - if (skinned) - { - mask |= LLVertexBuffer::MAP_WEIGHT4; - } - - vb = new LLVertexBuffer(mask, 0); - - vb->allocateBuffer(num_vertices, num_indices, TRUE); - - LLStrider vertex_strider; - LLStrider normal_strider; - LLStrider tc_strider; - LLStrider index_strider; - LLStrider weights_strider; - - vb->getVertexStrider(vertex_strider); - vb->getNormalStrider(normal_strider); - vb->getTexCoord0Strider(tc_strider); - vb->getIndexStrider(index_strider); - - if (skinned) - { - vb->getWeight4Strider(weights_strider); - } - - LLVector4a::memcpyNonAliased16((F32*) vertex_strider.get(), (F32*) vf.mPositions, num_vertices*4*sizeof(F32)); - LLVector4a::memcpyNonAliased16((F32*) tc_strider.get(), (F32*) vf.mTexCoords, num_vertices*2*sizeof(F32)); - LLVector4a::memcpyNonAliased16((F32*) normal_strider.get(), (F32*) vf.mNormals, num_vertices*4*sizeof(F32)); - - if (skinned) - { - for (U32 i = 0; i < num_vertices; i++) - { - //find closest weight to vf.mVertices[i].mPosition - LLVector3 pos(vf.mPositions[i].getF32ptr()); - - const LLModel::weight_list& weight_list = base_mdl->getJointInfluences(pos); - - LLVector4 w(0,0,0,0); - if (weight_list.size() > 4) - { - llerrs << "WTF?" << llendl; - } - - for (U32 i = 0; i < weight_list.size(); ++i) - { - F32 wght = llmin(weight_list[i].mWeight, 0.999999f); - F32 joint = (F32) weight_list[i].mJointIdx; - w.mV[i] = joint + wght; - } - - *(weights_strider++) = w; - } - } - - // build indices - for (U32 i = 0; i < num_indices; i++) - { - *(index_strider++) = vf.mIndices[i]; - } - - mVertexBuffer[lod][mdl].push_back(vb); - - vertex_count += num_vertices; - tri_count += num_indices/3; - ++mesh_count; - - } - } -} - -void LLModelPreview::update() -{ - if (mDirty) - { - mDirty = false; - mResourceCost = calcResourceCost(); - refresh(); - updateStatusMessages(); - } - - if (mGenLOD) - { - mGenLOD = false; - genLODs(); - refresh(); - updateStatusMessages(); - } - -} - -//----------------------------------------------------------------------------- -// render() -//----------------------------------------------------------------------------- -BOOL LLModelPreview::render() -{ - assert_main_thread(); - - LLMutexLock lock(this); - mNeedsUpdate = FALSE; - - bool edges = mViewOption["show_edges"]; - bool joint_positions = mViewOption["show_joint_positions"]; - bool skin_weight = mViewOption["show_skin_weight"]; - bool textures = mViewOption["show_textures"]; - bool physics = mViewOption["show_physics"]; - - S32 width = getWidth(); - S32 height = getHeight(); - - LLGLSUIDefault def; - LLGLDisable no_blend(GL_BLEND); - LLGLEnable cull(GL_CULL_FACE); - LLGLDepthTest depth(GL_TRUE); - LLGLDisable fog(GL_FOG); - - { - //clear background to blue - glMatrixMode(GL_PROJECTION); - gGL.pushMatrix(); - glLoadIdentity(); - glOrtho(0.0f, width, 0.0f, height, -1.0f, 1.0f); - - glMatrixMode(GL_MODELVIEW); - gGL.pushMatrix(); - glLoadIdentity(); - - gGL.color4f(0.15f, 0.2f, 0.3f, 1.f); - - gl_rect_2d_simple( width, height ); - - glMatrixMode(GL_PROJECTION); - gGL.popMatrix(); - - glMatrixMode(GL_MODELVIEW); - gGL.popMatrix(); - } - - LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; - - bool has_skin_weights = false; - bool upload_skin = mFMP->childGetValue("upload_skin").asBoolean(); - bool upload_joints = mFMP->childGetValue("upload_joints").asBoolean(); - - for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) - { - for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) - { - LLModelInstance& instance = *model_iter; - LLModel* model = instance.mModel; - if (!model->mSkinWeights.empty()) - { - has_skin_weights = true; - } - } - } - - if (has_skin_weights) - { //model has skin weights, enable view options for skin weights and joint positions - if (fmp) - { - fmp->enableViewOption("show_skin_weight"); - fmp->setViewOptionEnabled("show_joint_positions", skin_weight); - } - mFMP->childEnable("upload_skin"); - } - else - { - mFMP->childDisable("upload_skin"); - if (fmp) - { - mViewOption["show_skin_weight"] = false; - fmp->disableViewOption("show_skin_weight"); - fmp->disableViewOption("show_joint_positions"); - } - skin_weight = false; - } - - if (upload_skin && !has_skin_weights) - { //can't upload skin weights if model has no skin weights - mFMP->childSetValue("upload_skin", false); - upload_skin = false; - } - - if (!upload_skin && upload_joints) - { //can't upload joints if not uploading skin weights - mFMP->childSetValue("upload_joints", false); - upload_joints = false; - } - - mFMP->childSetEnabled("upload_joints", upload_skin); - - F32 explode = mFMP->childGetValue("physics_explode").asReal(); - - glClear(GL_DEPTH_BUFFER_BIT); - - LLRect preview_rect = mFMP->getChildView("preview_panel")->getRect(); - F32 aspect = (F32) preview_rect.getWidth()/preview_rect.getHeight(); - - LLViewerCamera::getInstance()->setAspect(aspect); - - LLViewerCamera::getInstance()->setView(LLViewerCamera::getInstance()->getDefaultFOV() / mCameraZoom); - - LLVector3 offset = mCameraOffset; - LLVector3 target_pos = mPreviewTarget+offset; - - F32 z_near = 0.001f; - F32 z_far = mCameraDistance+mPreviewScale.magVec()+mCameraOffset.magVec(); - - if (skin_weight) - { - target_pos = gAgentAvatarp->getPositionAgent(); - z_near = 0.01f; - z_far = 1024.f; - mCameraDistance = 16.f; - - //render avatar previews every frame - refresh(); - } - - glLoadIdentity(); - gPipeline.enableLightsPreview(); - - LLQuaternion camera_rot = LLQuaternion(mCameraPitch, LLVector3::y_axis) * - LLQuaternion(mCameraYaw, LLVector3::z_axis); - - LLQuaternion av_rot = camera_rot; - LLViewerCamera::getInstance()->setOriginAndLookAt( - target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + offset) * av_rot), // camera - LLVector3::z_axis, // up - target_pos); // point of interest - - - LLViewerCamera::getInstance()->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, width, height, FALSE, z_near, z_far); - - stop_glerror(); - - gGL.pushMatrix(); - const F32 BRIGHTNESS = 0.9f; - gGL.color3f(BRIGHTNESS, BRIGHTNESS, BRIGHTNESS); - - LLGLEnable normalize(GL_NORMALIZE); - - if (!mBaseModel.empty() && mVertexBuffer[5].empty()) - { - genBuffers(-1, skin_weight); - //genBuffers(3); - //genLODs(); - } - - if (!mModel[mPreviewLOD].empty()) - { - bool regen = mVertexBuffer[mPreviewLOD].empty(); - if (!regen) - { - const std::vector >& vb_vec = mVertexBuffer[mPreviewLOD].begin()->second; - if (!vb_vec.empty()) - { - const LLVertexBuffer* buff = vb_vec[0]; - regen = buff->hasDataType(LLVertexBuffer::TYPE_WEIGHT4) != skin_weight; - } - } - - if (regen) - { - genBuffers(mPreviewLOD, skin_weight); - } - - if (!skin_weight) - { - for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) - { - LLModelInstance& instance = *iter; - - LLModel* model = instance.mLOD[mPreviewLOD]; - - if (!model) - { - continue; - } - - gGL.pushMatrix(); - LLMatrix4 mat = instance.mTransform; - - glMultMatrixf((GLfloat*) mat.mMatrix); - - for (U32 i = 0; i < mVertexBuffer[mPreviewLOD][model].size(); ++i) - { - LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; - - buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); - - if (textures) - { - glColor4fv(instance.mMaterial[i].mDiffuseColor.mV); - if (i < instance.mMaterial.size() && instance.mMaterial[i].mDiffuseMap.notNull()) - { - gGL.getTexUnit(0)->bind(instance.mMaterial[i].mDiffuseMap, true); - if (instance.mMaterial[i].mDiffuseMap->getDiscardLevel() > -1) - { - mTextureSet.insert(instance.mMaterial[i].mDiffuseMap.get()); - } - } - } - else - { - glColor4f(1,1,1,1); - } - - buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - glColor3f(0.4f, 0.4f, 0.4f); - - if (edges) - { - glLineWidth(3.f); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glLineWidth(1.f); - } - } - gGL.popMatrix(); - } - - if (physics) - { - glClear(GL_DEPTH_BUFFER_BIT); - LLGLEnable blend(GL_BLEND); - gGL.blendFunc(LLRender::BF_ONE, LLRender::BF_ZERO); - - for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) - { - LLModelInstance& instance = *iter; - - LLModel* model = instance.mLOD[LLModel::LOD_PHYSICS]; - - if (!model) - { - continue; - } - - gGL.pushMatrix(); - LLMatrix4 mat = instance.mTransform; - - glMultMatrixf((GLfloat*) mat.mMatrix); - - - bool render_mesh = true; - - LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread; - if (decomp) - { - LLMutexLock(decomp->mMutex); - - std::map, std::vector > >::iterator iter = - mPhysicsMesh.find(model); - if (iter != mPhysicsMesh.end()) - { //render hull instead of mesh - render_mesh = false; - for (U32 i = 0; i < iter->second.size(); ++i) - { - if (explode > 0.f) - { - gGL.pushMatrix(); - - LLVector3 offset = model->mHullCenter[i]-model->mCenterOfHullCenters; - offset *= explode; - - gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]); - } - - static std::vector hull_colors; - - if (i+1 >= hull_colors.size()) - { - hull_colors.push_back(LLColor4U(rand()%128+127, rand()%128+127, rand()%128+127, 255)); - } - - LLVertexBuffer* buff = iter->second[i]; - if (buff) - { - buff->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL); - - glColor4ubv(hull_colors[i].mV); - buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts()); - } - - if (explode > 0.f) - { - gGL.popMatrix(); - } - } - } - } - - if (render_mesh) - { - if (mVertexBuffer[LLModel::LOD_PHYSICS].empty()) - { - genBuffers(LLModel::LOD_PHYSICS, false); - } - for (U32 i = 0; i < mVertexBuffer[LLModel::LOD_PHYSICS][model].size(); ++i) - { - LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][i]; - - buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); - - buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - glColor4f(0.4f, 0.4f, 0.0f, 0.4f); - - buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); - - glColor3f(1.f, 1.f, 0.f); - - glLineWidth(3.f); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glLineWidth(1.f); - } - } - - gGL.popMatrix(); - } - - gGL.setSceneBlendType(LLRender::BT_ALPHA); - } - } - else - { - LLVOAvatarSelf* avatar = gAgentAvatarp; - target_pos = avatar->getPositionAgent(); - - LLViewerCamera::getInstance()->setOriginAndLookAt( - target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + offset) * av_rot), // camera - LLVector3::z_axis, // up - target_pos); // point of interest - - if (joint_positions) - { - avatar->renderCollisionVolumes(); - } - - for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) - { - for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) - { - LLModelInstance& instance = *model_iter; - LLModel* model = instance.mModel; - - if (!model->mSkinWeights.empty()) - { - for (U32 i = 0; i < mVertexBuffer[mPreviewLOD][model].size(); ++i) - { - LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; - - const LLVolumeFace& face = model->getVolumeFace(i); - - LLStrider position; - buffer->getVertexStrider(position); - - LLStrider weight; - buffer->getWeight4Strider(weight); - - //quick 'n dirty software vertex skinning - - //build matrix palette - LLMatrix4 mat[64]; - for (U32 j = 0; j < model->mJointList.size(); ++j) - { - LLJoint* joint = avatar->getJoint(model->mJointList[j]); - if (joint) - { - mat[j] = model->mInvBindMatrix[j]; - mat[j] *= joint->getWorldMatrix(); - } - } - - for (U32 j = 0; j < buffer->getRequestedVerts(); ++j) - { - LLMatrix4 final_mat; - final_mat.mMatrix[0][0] = final_mat.mMatrix[1][1] = final_mat.mMatrix[2][2] = final_mat.mMatrix[3][3] = 0.f; - - LLVector4 wght; - S32 idx[4]; - - F32 scale = 0.f; - for (U32 k = 0; k < 4; k++) - { - F32 w = weight[j].mV[k]; - - idx[k] = (S32) floorf(w); - wght.mV[k] = w - floorf(w); - scale += wght.mV[k]; - } - - wght *= 1.f/scale; - - for (U32 k = 0; k < 4; k++) - { - F32* src = (F32*) mat[idx[k]].mMatrix; - F32* dst = (F32*) final_mat.mMatrix; - - F32 w = wght.mV[k]; - - for (U32 l = 0; l < 16; l++) - { - dst[l] += src[l]*w; - } - } - - //VECTORIZE THIS - LLVector3 v(face.mPositions[j].getF32ptr()); - - v = v * model->mBindShapeMatrix; - v = v * final_mat; - - position[j] = v; - } - - buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); - glColor4fv(instance.mMaterial[i].mDiffuseColor.mV); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); - glColor3f(0.4f, 0.4f, 0.4f); - - if (edges) - { - glLineWidth(3.f); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glLineWidth(1.f); - } - } - } - } - } - } - } - - gGL.popMatrix(); - - return TRUE; -} - -//----------------------------------------------------------------------------- -// refresh() -//----------------------------------------------------------------------------- -void LLModelPreview::refresh() -{ - mNeedsUpdate = TRUE; -} - -//----------------------------------------------------------------------------- -// rotate() -//----------------------------------------------------------------------------- -void LLModelPreview::rotate(F32 yaw_radians, F32 pitch_radians) -{ - mCameraYaw = mCameraYaw + yaw_radians; - - mCameraPitch = llclamp(mCameraPitch + pitch_radians, F_PI_BY_TWO * -0.8f, F_PI_BY_TWO * 0.8f); -} - -//----------------------------------------------------------------------------- -// zoom() -//----------------------------------------------------------------------------- -void LLModelPreview::zoom(F32 zoom_amt) -{ - F32 new_zoom = mCameraZoom+zoom_amt; - - mCameraZoom = llclamp(new_zoom, 1.f, 10.f); -} - -void LLModelPreview::pan(F32 right, F32 up) -{ - mCameraOffset.mV[VY] = llclamp(mCameraOffset.mV[VY] + right * mCameraDistance / mCameraZoom, -1.f, 1.f); - mCameraOffset.mV[VZ] = llclamp(mCameraOffset.mV[VZ] + up * mCameraDistance / mCameraZoom, -1.f, 1.f); -} - -void LLModelPreview::setPreviewLOD(S32 lod) -{ - lod = llclamp(lod, 0, (S32) LLModel::LOD_HIGH); - - if (lod != mPreviewLOD) - { - mPreviewLOD = lod; - - LLComboBox* combo_box = mFMP->getChild("preview_lod_combo"); - combo_box->setCurrentByIndex((NUM_LOD-1)-mPreviewLOD); // combo box list of lods is in reverse order - mFMP->childSetTextArg("lod_table_footer", "[DETAIL]", mFMP->getString(lod_name[mPreviewLOD])); - mFMP->childSetText("lod_file", mLODFile[mPreviewLOD]); - - LLColor4 highlight_color = LLUIColorTable::instance().getColor("MeshImportTableHighlightColor"); - LLColor4 normal_color = LLUIColorTable::instance().getColor("MeshImportTableNormalColor"); - - for (S32 i = 0; i <= LLModel::LOD_HIGH; ++i) - { - const LLColor4& color = (i == lod) ? highlight_color : normal_color; - - mFMP->childSetColor(lod_status_name[i], color); - mFMP->childSetColor(lod_label_name[i], color); - mFMP->childSetColor(lod_triangles_name[i], color); - mFMP->childSetColor(lod_vertices_name[i], color); - } - - LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; - if (fmp) - { - LLRadioGroup* radio = fmp->getChild("lod_file_or_limit"); - radio->selectNthItem(fmp->mLODMode[mPreviewLOD]); - } - } - refresh(); - updateStatusMessages(); -} - -//static -void LLFloaterModelPreview::onBrowseLOD(void* data) -{ - assert_main_thread(); - - LLFloaterModelPreview* mp = (LLFloaterModelPreview*) data; - mp->loadModel(mp->mModelPreview->mPreviewLOD); -} - -//static -void LLFloaterModelPreview::onUpload(void* user_data) -{ - assert_main_thread(); - - LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; - - mp->mModelPreview->rebuildUploadData(); - - gMeshRepo.uploadModel(mp->mModelPreview->mUploadData, mp->mModelPreview->mPreviewScale, - mp->childGetValue("upload_textures").asBoolean(), mp->childGetValue("upload_skin"), mp->childGetValue("upload_joints")); - - mp->closeFloater(false); -} - - -//static -void LLFloaterModelPreview::onClearMaterials(void* user_data) -{ - LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; - mp->mModelPreview->clearMaterials(); -} - -//static -void LLFloaterModelPreview::refresh(LLUICtrl* ctrl, void* user_data) -{ - sInstance->mModelPreview->mDirty = true; -} - -void LLFloaterModelPreview::updateResourceCost() -{ - U32 cost = mModelPreview->mResourceCost; - childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d",cost)); -} - -//static -void LLModelPreview::textureLoadedCallback( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata ) -{ - LLModelPreview* preview = (LLModelPreview*) userdata; - preview->refresh(); -} - -LLFloaterModelPreview::DecompRequest::DecompRequest(const std::string& stage, LLModel* mdl) -{ - mStage = stage; - mContinue = 1; - mModel = mdl; - mDecompID = &mdl->mDecompID; - mParams = sInstance->mDecompParams; - - //copy out positions and indices - if (mdl) - { - U16 index_offset = 0; - - mPositions.clear(); - mIndices.clear(); - - //queue up vertex positions and indices - for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) - { - const LLVolumeFace& face = mdl->getVolumeFace(i); - if (mPositions.size() + face.mNumVertices > 65535) - { - continue; - } - - for (U32 j = 0; j < face.mNumVertices; ++j) - { - mPositions.push_back(LLVector3(face.mPositions[j].getF32ptr())); - } - - for (U32 j = 0; j < face.mNumIndices; ++j) - { - mIndices.push_back(face.mIndices[j]+index_offset); - } - - index_offset += face.mNumVertices; - } - } -} - -void LLFloaterModelPreview::setStatusMessage(const std::string& msg) -{ - LLMutexLock lock(mStatusLock); - mStatusMessage = msg; -} - -S32 LLFloaterModelPreview::DecompRequest::statusCallback(const char* status, S32 p1, S32 p2) -{ - setStatusMessage(llformat("%s: %d/%d", status, p1, p2)); - if (LLFloaterModelPreview::sInstance) - { - LLFloaterModelPreview::sInstance->setStatusMessage(mStatusMessage); - } - - return mContinue; -} - -void LLFloaterModelPreview::DecompRequest::completed() -{ //called from the main thread - mModel->setConvexHullDecomposition(mHull); - - if (sInstance) - { - if (mContinue) - { - if (sInstance->mModelPreview) - { - sInstance->mModelPreview->mPhysicsMesh[mModel] = mHullMesh; - sInstance->mModelPreview->mDirty = true; - LLFloaterModelPreview::sInstance->mModelPreview->refresh(); - } - } - - sInstance->mCurRequest.erase(this); - } -} +/** + * @file llfloatermodelpreview.cpp + * @brief LLFloaterModelPreview class implementation + * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "dae.h" +//#include "dom.h" +#include "dom/domAsset.h" +#include "dom/domBind_material.h" +#include "dom/domCOLLADA.h" +#include "dom/domConstants.h" +#include "dom/domController.h" +#include "dom/domEffect.h" +#include "dom/domGeometry.h" +#include "dom/domInstance_geometry.h" +#include "dom/domInstance_material.h" +#include "dom/domInstance_node.h" +#include "dom/domInstance_effect.h" +#include "dom/domMaterial.h" +#include "dom/domMatrix.h" +#include "dom/domNode.h" +#include "dom/domProfile_COMMON.h" +#include "dom/domRotate.h" +#include "dom/domScale.h" +#include "dom/domTranslate.h" +#include "dom/domVisual_scene.h" + +#include "llfloatermodelpreview.h" + +#include "llfilepicker.h" +#include "llimagebmp.h" +#include "llimagetga.h" +#include "llimagejpeg.h" +#include "llimagepng.h" + +#include "llagent.h" +#include "llbutton.h" +#include "llcombobox.h" +#include "lldatapacker.h" +#include "lldrawable.h" +#include "lldrawpoolavatar.h" +#include "llrender.h" +#include "llface.h" +#include "lleconomy.h" +#include "llfocusmgr.h" +#include "llfloaterperms.h" +#include "lliconctrl.h" +#include "llmatrix4a.h" +#include "llmenubutton.h" +#include "llmeshrepository.h" +#include "llsdutil_math.h" +#include "lltextbox.h" +#include "lltoolmgr.h" +#include "llui.h" +#include "llvector4a.h" +#include "llviewercamera.h" +#include "llviewerwindow.h" +#include "llvoavatar.h" +#include "llvoavatarself.h" +#include "pipeline.h" +#include "lluictrlfactory.h" +#include "llviewermenu.h" +#include "llviewermenufile.h" +#include "llviewerregion.h" +#include "llviewertexturelist.h" +#include "llstring.h" +#include "llbutton.h" +#include "llcheckboxctrl.h" +#include "llradiogroup.h" +#include "llsliderctrl.h" +#include "llspinctrl.h" +#include "lltoggleablemenu.h" +#include "llvfile.h" +#include "llvfs.h" +#include "llcallbacklist.h" + +#include "glod/glod.h" + +//static +S32 LLFloaterModelPreview::sUploadAmount = 10; +LLFloaterModelPreview* LLFloaterModelPreview::sInstance = NULL; + +const S32 PREVIEW_BORDER_WIDTH = 2; +const S32 PREVIEW_RESIZE_HANDLE_SIZE = S32(RESIZE_HANDLE_WIDTH * OO_SQRT2) + PREVIEW_BORDER_WIDTH; +const S32 PREVIEW_HPAD = PREVIEW_RESIZE_HANDLE_SIZE; +const S32 PREF_BUTTON_HEIGHT = 16 + 7 + 16; +const S32 PREVIEW_TEXTURE_HEIGHT = 300; + +void drawBoxOutline(const LLVector3& pos, const LLVector3& size); + + +std::string lod_name[NUM_LOD+1] = +{ + "lowest", + "low", + "medium", + "high", + "I went off the end of the lod_name array. Me so smart." +}; + +std::string lod_triangles_name[NUM_LOD+1] = +{ + "lowest_triangles", + "low_triangles", + "medium_triangles", + "high_triangles", + "I went off the end of the lod_triangles_name array. Me so smart." +}; + +std::string lod_vertices_name[NUM_LOD+1] = +{ + "lowest_vertices", + "low_vertices", + "medium_vertices", + "high_vertices", + "I went off the end of the lod_vertices_name array. Me so smart." +}; + +std::string lod_status_name[NUM_LOD+1] = +{ + "lowest_status", + "low_status", + "medium_status", + "high_status", + "I went off the end of the lod_status_name array. Me so smart." +}; + +std::string lod_icon_name[NUM_LOD+1] = +{ + "status_icon_lowest", + "status_icon_low", + "status_icon_medium", + "status_icon_high", + "I went off the end of the lod_status_name array. Me so smart." +}; + +std::string lod_status_image[NUM_LOD+1] = +{ + "ModelImport_Status_Good", + "ModelImport_Status_Warning", + "ModelImport_Status_Error", + "I went off the end of the lod_status_image array. Me so smart." +}; + +std::string lod_label_name[NUM_LOD+1] = +{ + "lowest_label", + "low_label", + "medium_label", + "high_label", + "I went off the end of the lod_label_name array. Me so smart." +}; + + +bool validate_face(const LLVolumeFace& face) +{ + for (U32 i = 0; i < face.mNumIndices; ++i) + { + if (face.mIndices[i] >= face.mNumVertices) + { + llwarns << "Face has invalid index." << llendl; + return false; + } + } + + return true; +} + +bool validate_model(const LLModel* mdl) +{ + if (mdl->getNumVolumeFaces() == 0) + { + llwarns << "Model has no faces!" << llendl; + return false; + } + + for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) + { + if (mdl->getVolumeFace(i).mNumVertices == 0) + { + llwarns << "Face has no vertices." << llendl; + return false; + } + + if (mdl->getVolumeFace(i).mNumIndices == 0) + { + llwarns << "Face has no indices." << llendl; + return false; + } + + if (!validate_face(mdl->getVolumeFace(i))) + { + return false; + } + } + + return true; +} + +BOOL stop_gloderror() +{ + GLuint error = glodGetError(); + + if (error != GLOD_NO_ERROR) + { + llwarns << "GLOD error detected, cannot generate LOD: " << std::hex << error << llendl; + return TRUE; + } + + return FALSE; +} + + +LLMeshFilePicker::LLMeshFilePicker(LLModelPreview* mp, S32 lod) + : LLFilePickerThread(LLFilePicker::FFLOAD_COLLADA) + { + mMP = mp; + mLOD = lod; + } + +void LLMeshFilePicker::notify(const std::string& filename) +{ + mMP->loadModel(mFile, mLOD); +} + + +//----------------------------------------------------------------------------- +// LLFloaterModelPreview() +//----------------------------------------------------------------------------- +LLFloaterModelPreview::LLFloaterModelPreview(const LLSD& key) : +LLFloater(key) +{ + sInstance = this; + mLastMouseX = 0; + mLastMouseY = 0; + mGLName = 0; + mStatusLock = new LLMutex(NULL); + + mLODMode[LLModel::LOD_HIGH] = 0; + for (U32 i = 0; i < LLModel::LOD_HIGH; i++) + { + mLODMode[i] = 1; + } +} + +//----------------------------------------------------------------------------- +// postBuild() +//----------------------------------------------------------------------------- +BOOL LLFloaterModelPreview::postBuild() +{ + if (!LLFloater::postBuild()) + { + return FALSE; + } + + + + + + + childSetAction("lod_browse", onBrowseLOD, this); + + childSetCommitCallback("cancel_btn", onCancel, this); + childSetCommitCallback("crease_angle", onGenerateNormalsCommit, this); + childSetCommitCallback("generate_normals", onGenerateNormalsCommit, this); + + childSetCommitCallback("lod_generate", onAutoFillCommit, this); + + childSetCommitCallback("lod_mode", onLODParamCommit, this); + childSetCommitCallback("lod_error_threshold", onLODParamCommit, this); + childSetCommitCallback("lod_triangle_limit", onLODParamCommit, this); + childSetCommitCallback("build_operator", onLODParamCommit, this); + childSetCommitCallback("queue_mode", onLODParamCommit, this); + childSetCommitCallback("border_mode", onLODParamCommit, this); + childSetCommitCallback("share_tolerance", onLODParamCommit, this); + + childSetTextArg("status", "[STATUS]", getString("status_idle")); + + //childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d",sUploadAmount)); + childSetAction("ok_btn", onUpload, this); + childDisable("ok_btn"); + + childSetAction("clear_materials", onClearMaterials, this); + + childSetCommitCallback("preview_lod_combo", onPreviewLODCommit, this); + + childSetCommitCallback("upload_skin", onUploadSkinCommit, this); + childSetCommitCallback("upload_joints", onUploadJointsCommit, this); + + childSetCommitCallback("import_scale", onImportScaleCommit, this); + + childSetCommitCallback("lod_file_or_limit", refresh, this); + childSetCommitCallback("physics_load_radio", refresh, this); + //childSetCommitCallback("physics_optimize", refresh, this); + //childSetCommitCallback("physics_use_hull", refresh, this); + + childDisable("upload_skin"); + childDisable("upload_joints"); + childDisable("ok_btn"); + + mViewOptionMenuButton = getChild("options_gear_btn"); + + mCommitCallbackRegistrar.add("ModelImport.ViewOption.Action", boost::bind(&LLFloaterModelPreview::onViewOptionChecked, this, _2)); + mEnableCallbackRegistrar.add("ModelImport.ViewOption.Check", boost::bind(&LLFloaterModelPreview::isViewOptionChecked, this, _2)); + mEnableCallbackRegistrar.add("ModelImport.ViewOption.Enabled", boost::bind(&LLFloaterModelPreview::isViewOptionEnabled, this, _2)); + + + + mViewOptionMenu = LLUICtrlFactory::getInstance()->createFromFile("menu_model_import_gear_default.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + mViewOptionMenuButton->setMenu(mViewOptionMenu, LLMenuButton::MP_BOTTOM_LEFT); + + initDecompControls(); + + LLView* preview_panel = getChild("preview_panel"); + + mPreviewRect = preview_panel->getRect(); + + mModelPreview = new LLModelPreview(512, 512, this); + mModelPreview->setPreviewTarget(16.f); + + //set callbacks for left click on line editor rows + for (U32 i = 0; i <= LLModel::LOD_HIGH; i++) + { + LLTextBox* text = getChild(lod_label_name[i]); + if (text) + { + text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i)); + } + + text = getChild(lod_triangles_name[i]); + if (text) + { + text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i)); + } + + text = getChild(lod_vertices_name[i]); + if (text) + { + text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i)); + } + + text = getChild(lod_status_name[i]); + if (text) + { + text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i)); + } + } + + return TRUE; +} + +//----------------------------------------------------------------------------- +// LLFloaterModelPreview() +//----------------------------------------------------------------------------- +LLFloaterModelPreview::~LLFloaterModelPreview() +{ + sInstance = NULL; + + if ( mModelPreview->containsRiggedAsset() ) + { + gAgentAvatarp->resetJointPositions(); + } + + delete mModelPreview; + + if (mGLName) + { + LLImageGL::deleteTextures(1, &mGLName ); + } + + delete mStatusLock; + mStatusLock = NULL; +} + +void LLFloaterModelPreview::onViewOptionChecked(const LLSD& userdata) +{ + if (mModelPreview) + { + mModelPreview->mViewOption[userdata.asString()] = !mModelPreview->mViewOption[userdata.asString()]; + + mModelPreview->refresh(); + } +} + +bool LLFloaterModelPreview::isViewOptionChecked(const LLSD& userdata) +{ + if (mModelPreview) + { + return mModelPreview->mViewOption[userdata.asString()]; + } + + return false; +} + +bool LLFloaterModelPreview::isViewOptionEnabled(const LLSD& userdata) +{ + return !mViewOptionDisabled[userdata.asString()]; +} + +void LLFloaterModelPreview::setViewOptionEnabled(const std::string& option, bool enabled) +{ + mViewOptionDisabled[option] = !enabled; +} + +void LLFloaterModelPreview::enableViewOption(const std::string& option) +{ + setViewOptionEnabled(option, true); +} + +void LLFloaterModelPreview::disableViewOption(const std::string& option) +{ + setViewOptionEnabled(option, false); +} + +void LLFloaterModelPreview::loadModel(S32 lod) +{ + mModelPreview->mLoading = true; + + (new LLMeshFilePicker(mModelPreview, lod))->getFile(); +} + +//static +void LLFloaterModelPreview::onImportScaleCommit(LLUICtrl*,void* userdata) +{ + LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; + + if (!fp->mModelPreview) + { + return; + } + + fp->mModelPreview->calcResourceCost(); + fp->mModelPreview->refresh(); +} + +//static +void LLFloaterModelPreview::onUploadJointsCommit(LLUICtrl*,void* userdata) +{ + LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; + + if (!fp->mModelPreview) + { + return; + } + + fp->mModelPreview->refresh(); +} + +//static +void LLFloaterModelPreview::onUploadSkinCommit(LLUICtrl*,void* userdata) +{ + LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; + + if (!fp->mModelPreview) + { + return; + } + + fp->mModelPreview->refresh(); + fp->mModelPreview->resetPreviewTarget(); + fp->mModelPreview->clearBuffers(); +} + +//static +void LLFloaterModelPreview::onPreviewLODCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; + + if (!fp->mModelPreview) + { + return; + } + + S32 which_mode = 0; + + LLComboBox* combo = (LLComboBox*) ctrl; + + which_mode = (NUM_LOD-1)-combo->getFirstSelectedIndex(); // combo box list of lods is in reverse order + + fp->mModelPreview->setPreviewLOD(which_mode); +} + +//static +void LLFloaterModelPreview::onGenerateNormalsCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; + + fp->mModelPreview->generateNormals(); +} + +//static +void LLFloaterModelPreview::onExplodeCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview* fp = LLFloaterModelPreview::sInstance; + + fp->mModelPreview->refresh(); +} + +//static +void LLFloaterModelPreview::onAutoFillCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; + + fp->mModelPreview->genLODs(); +} + +//static +void LLFloaterModelPreview::onLODParamCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; + fp->mModelPreview->genLODs(fp->mModelPreview->mPreviewLOD); + fp->mModelPreview->updateStatusMessages(); + fp->mModelPreview->refresh(); +} + + +//----------------------------------------------------------------------------- +// draw() +//----------------------------------------------------------------------------- +void LLFloaterModelPreview::draw() +{ + LLFloater::draw(); + LLRect r = getRect(); + + mModelPreview->update(); + + if (!mModelPreview->mLoading) + { + childSetTextArg("status", "[STATUS]", getString("status_idle")); + } + + childSetTextArg("prim_cost", "[PRIM_COST]", llformat("%d", mModelPreview->mResourceCost)); + childSetTextArg("description_label", "[TEXTURES]", llformat("%d", mModelPreview->mTextureSet.size())); + + if (!mCurRequest.empty()) + { + LLMutexLock lock(mStatusLock); + childSetTextArg("status", "[STATUS]", mStatusMessage); + } + else + { + childSetVisible("Simplify", true); + childSetVisible("simplify_cancel", false); + childSetVisible("Decompose", true); + childSetVisible("decompose_cancel", false); + } + + U32 resource_cost = mModelPreview->mResourceCost*10; + + if (childGetValue("upload_textures").asBoolean()) + { + resource_cost += mModelPreview->mTextureSet.size()*10; + } + + childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d", resource_cost)); + + if (mModelPreview) + { + gGL.color3f(1.f, 1.f, 1.f); + + gGL.getTexUnit(0)->bind(mModelPreview); + + + LLView* preview_panel = getChild("preview_panel"); + + LLRect rect = preview_panel->getRect(); + if (rect != mPreviewRect) + { + mModelPreview->refresh(); + mPreviewRect = preview_panel->getRect(); + } + + gGL.begin( LLRender::QUADS ); + { + gGL.texCoord2f(0.f, 1.f); + gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mTop); + gGL.texCoord2f(0.f, 0.f); + gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mBottom); + gGL.texCoord2f(1.f, 0.f); + gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mBottom); + gGL.texCoord2f(1.f, 1.f); + gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mTop); + } + gGL.end(); + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + } +} + +//----------------------------------------------------------------------------- +// handleMouseDown() +//----------------------------------------------------------------------------- +BOOL LLFloaterModelPreview::handleMouseDown(S32 x, S32 y, MASK mask) +{ + if (mPreviewRect.pointInRect(x, y)) + { + bringToFront( x, y ); + gFocusMgr.setMouseCapture(this); + gViewerWindow->hideCursor(); + mLastMouseX = x; + mLastMouseY = y; + return TRUE; + } + + return LLFloater::handleMouseDown(x, y, mask); +} + +//----------------------------------------------------------------------------- +// handleMouseUp() +//----------------------------------------------------------------------------- +BOOL LLFloaterModelPreview::handleMouseUp(S32 x, S32 y, MASK mask) +{ + gFocusMgr.setMouseCapture(FALSE); + gViewerWindow->showCursor(); + return LLFloater::handleMouseUp(x, y, mask); +} + +//----------------------------------------------------------------------------- +// handleHover() +//----------------------------------------------------------------------------- +BOOL LLFloaterModelPreview::handleHover (S32 x, S32 y, MASK mask) +{ + MASK local_mask = mask & ~MASK_ALT; + + if (mModelPreview && hasMouseCapture()) + { + if (local_mask == MASK_PAN) + { + // pan here + mModelPreview->pan((F32)(x - mLastMouseX) * -0.005f, (F32)(y - mLastMouseY) * -0.005f); + } + else if (local_mask == MASK_ORBIT) + { + F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f; + F32 pitch_radians = (F32)(y - mLastMouseY) * 0.02f; + + mModelPreview->rotate(yaw_radians, pitch_radians); + } + else + { + + F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f; + F32 zoom_amt = (F32)(y - mLastMouseY) * 0.02f; + + mModelPreview->rotate(yaw_radians, 0.f); + mModelPreview->zoom(zoom_amt); + } + + + mModelPreview->refresh(); + + LLUI::setMousePositionLocal(this, mLastMouseX, mLastMouseY); + } + + if (!mPreviewRect.pointInRect(x, y) || !mModelPreview) + { + return LLFloater::handleHover(x, y, mask); + } + else if (local_mask == MASK_ORBIT) + { + gViewerWindow->setCursor(UI_CURSOR_TOOLCAMERA); + } + else if (local_mask == MASK_PAN) + { + gViewerWindow->setCursor(UI_CURSOR_TOOLPAN); + } + else + { + gViewerWindow->setCursor(UI_CURSOR_TOOLZOOMIN); + } + + return TRUE; +} + +//----------------------------------------------------------------------------- +// handleScrollWheel() +//----------------------------------------------------------------------------- +BOOL LLFloaterModelPreview::handleScrollWheel(S32 x, S32 y, S32 clicks) +{ + if (mPreviewRect.pointInRect(x, y) && mModelPreview) + { + mModelPreview->zoom((F32)clicks * -0.2f); + mModelPreview->refresh(); + } + + return TRUE; +} + +//static +void LLFloaterModelPreview::onPhysicsParamCommit(LLUICtrl* ctrl, void* data) +{ + if (LLConvexDecomposition::getInstance() == NULL) + { + llinfos << "convex decomposition tool is a stub on this platform. cannot get decomp." << llendl; + return; + } + + if (sInstance) + { + LLCDParam* param = (LLCDParam*) data; + std::string name(param->mName); + sInstance->mDecompParams[name] = ctrl->getValue(); + + if (name == "Simplify Method") + { + if (ctrl->getValue().asInteger() == 0) + { + sInstance->childSetVisible("Retain%", true); + sInstance->childSetVisible("Detail Scale", false); + } + else + { + sInstance->childSetVisible("Retain%", false); + sInstance->childSetVisible("Detail Scale", true); + } + } + } +} + +//static +void LLFloaterModelPreview::onPhysicsStageExecute(LLUICtrl* ctrl, void* data) +{ + LLCDStageData* stage_data = (LLCDStageData*) data; + std::string stage = stage_data->mName; + + if (sInstance) + { + if (!sInstance->mCurRequest.empty()) + { + llinfos << "Decomposition request still pending." << llendl; + return; + } + + if (sInstance->mModelPreview) + { + for (S32 i = 0; i < sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS].size(); ++i) + { + LLModel* mdl = sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS][i]; + DecompRequest* request = new DecompRequest(stage, mdl); + sInstance->mCurRequest.insert(request); + gMeshRepo.mDecompThread->submitRequest(request); + } + } + + if (stage == "Decompose") + { + sInstance->childSetVisible("Decompose", false); + sInstance->childSetVisible("decompose_cancel", true); + } + else if (stage == "Simplify") + { + sInstance->childSetVisible("Simplify", false); + sInstance->childSetVisible("simplify_cancel", true); + } + } +} + +//static +void LLFloaterModelPreview::onPhysicsBrowse(LLUICtrl* ctrl, void* userdata) +{ + sInstance->loadModel(LLModel::LOD_PHYSICS); +} + +//static +void LLFloaterModelPreview::onPhysicsUseLOD(LLUICtrl* ctrl, void* userdata) +{ + S32 which_mode = 3; + LLCtrlSelectionInterface* iface = sInstance->childGetSelectionInterface("physics_lod_combo"); + if (iface) + { + which_mode = iface->getFirstSelectedIndex(); + } + + sInstance->mModelPreview->setPhysicsFromLOD(which_mode); +} + +//static +void LLFloaterModelPreview::onCancel(LLUICtrl* ctrl, void* data) +{ + if (sInstance) + { + sInstance->closeFloater(false); + } +} + +//static +void LLFloaterModelPreview::onPhysicsStageCancel(LLUICtrl* ctrl, void*data) +{ + if (sInstance) + { + for (std::set >::iterator iter = sInstance->mCurRequest.begin(); + iter != sInstance->mCurRequest.end(); ++iter) + { + DecompRequest* req = *iter; + req->mContinue = 0; + } + } +} + +void LLFloaterModelPreview::initDecompControls() +{ + LLSD key; + + childSetCommitCallback("simplify_cancel", onPhysicsStageCancel, NULL); + childSetCommitCallback("decompose_cancel", onPhysicsStageCancel, NULL); + + childSetCommitCallback("physics_lod_combo", onPhysicsUseLOD, NULL); + childSetCommitCallback("physics_browse", onPhysicsBrowse, NULL); + + static const LLCDStageData* stage = NULL; + static S32 stage_count = 0; + + if (!stage && LLConvexDecomposition::getInstance() != NULL) + { + stage_count = LLConvexDecomposition::getInstance()->getStages(&stage); + } + + static const LLCDParam* param = NULL; + static S32 param_count = 0; + if (!param && LLConvexDecomposition::getInstance() != NULL) + { + param_count = LLConvexDecomposition::getInstance()->getParameters(¶m); + } + + for (S32 j = stage_count-1; j >= 0; --j) + { + LLButton* button = getChild(stage[j].mName); + if (button) + { + button->setCommitCallback(onPhysicsStageExecute, (void*) &stage[j]); + } + + gMeshRepo.mDecompThread->mStageID[stage[j].mName] = j; + // protected against stub by stage_count being 0 for stub above + LLConvexDecomposition::getInstance()->registerCallback(j, LLPhysicsDecomp::llcdCallback); + + //llinfos << "Physics decomp stage " << stage[j].mName << " (" << j << ") parameters:" << llendl; + //llinfos << "------------------------------------" << llendl; + + for (S32 i = 0; i < param_count; ++i) + { + if (param[i].mStage != j) + { + continue; + } + + std::string name(param[i].mName ? param[i].mName : ""); + std::string description(param[i].mDescription ? param[i].mDescription : ""); + + std::string type = "unknown"; + + llinfos << name << " - " << description << llendl; + + if (param[i].mType == LLCDParam::LLCD_FLOAT) + { + mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mFloat); + //llinfos << "Type: float, Default: " << param[i].mDefault.mFloat << llendl; + + LLSliderCtrl* slider = getChild(name); + if (slider) + { + slider->setMinValue(param[i].mDetails.mRange.mLow.mFloat); + slider->setMaxValue(param[i].mDetails.mRange.mHigh.mFloat); + slider->setIncrement(param[i].mDetails.mRange.mDelta.mFloat); + slider->setValue(param[i].mDefault.mFloat); + slider->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); + } + } + else if (param[i].mType == LLCDParam::LLCD_INTEGER) + { + mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue); + //llinfos << "Type: integer, Default: " << param[i].mDefault.mIntOrEnumValue << llendl; + + LLSliderCtrl* slider = getChild(name); + if (slider) + { + slider->setMinValue(param[i].mDetails.mRange.mLow.mIntOrEnumValue); + slider->setMaxValue(param[i].mDetails.mRange.mHigh.mIntOrEnumValue); + slider->setIncrement(param[i].mDetails.mRange.mDelta.mIntOrEnumValue); + slider->setValue(param[i].mDefault.mIntOrEnumValue); + slider->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); + } + } + else if (param[i].mType == LLCDParam::LLCD_BOOLEAN) + { + mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mBool); + //llinfos << "Type: boolean, Default: " << (param[i].mDefault.mBool ? "True" : "False") << llendl; + + LLCheckBoxCtrl* check_box = getChild(name); + if (check_box) + { + check_box->setValue(param[i].mDefault.mBool); + check_box->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); + } + } + else if (param[i].mType == LLCDParam::LLCD_ENUM) + { + mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue); + //llinfos << "Type: enum, Default: " << param[i].mDefault.mIntOrEnumValue << llendl; + + { //plug into combo box + + //llinfos << "Accepted values: " << llendl; + LLComboBox* combo_box = getChild(name); + for (S32 k = 0; k < param[i].mDetails.mEnumValues.mNumEnums; ++k) + { + //llinfos << param[i].mDetails.mEnumValues.mEnumsArray[k].mValue + // << " - " << param[i].mDetails.mEnumValues.mEnumsArray[k].mName << llendl; + + combo_box->add(param[i].mDetails.mEnumValues.mEnumsArray[k].mName, + LLSD::Integer(param[i].mDetails.mEnumValues.mEnumsArray[k].mValue)); + } + combo_box->setValue(param[i].mDefault.mIntOrEnumValue); + combo_box->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); + } + + //llinfos << "----" << llendl; + } + //llinfos << "-----------------------------" << llendl; + } + } + + childSetCommitCallback("physics_explode", LLFloaterModelPreview::onExplodeCommit, this); +} + +//----------------------------------------------------------------------------- +// onMouseCaptureLost() +//----------------------------------------------------------------------------- +// static +void LLFloaterModelPreview::onMouseCaptureLostModelPreview(LLMouseHandler* handler) +{ + gViewerWindow->showCursor(); +} + +//----------------------------------------------------------------------------- +// LLModelLoader +//----------------------------------------------------------------------------- +LLModelLoader::LLModelLoader(std::string filename, S32 lod, LLModelPreview* preview) +: LLThread("Model Loader"), mFilename(filename), mLod(lod), mPreview(preview), mState(STARTING), mFirstTransform(TRUE) +{ + mJointMap["mPelvis"] = "mPelvis"; + mJointMap["mTorso"] = "mTorso"; + mJointMap["mChest"] = "mChest"; + mJointMap["mNeck"] = "mNeck"; + mJointMap["mHead"] = "mHead"; + mJointMap["mSkull"] = "mSkull"; + mJointMap["mEyeRight"] = "mEyeRight"; + mJointMap["mEyeLeft"] = "mEyeLeft"; + mJointMap["mCollarLeft"] = "mCollarLeft"; + mJointMap["mShoulderLeft"] = "mShoulderLeft"; + mJointMap["mElbowLeft"] = "mElbowLeft"; + mJointMap["mWristLeft"] = "mWristLeft"; + mJointMap["mCollarRight"] = "mCollarRight"; + mJointMap["mShoulderRight"] = "mShoulderRight"; + mJointMap["mElbowRight"] = "mElbowRight"; + mJointMap["mWristRight"] = "mWristRight"; + mJointMap["mHipRight"] = "mHipRight"; + mJointMap["mKneeRight"] = "mKneeRight"; + mJointMap["mAnkleRight"] = "mAnkleRight"; + mJointMap["mFootRight"] = "mFootRight"; + mJointMap["mToeRight"] = "mToeRight"; + mJointMap["mHipLeft"] = "mHipLeft"; + mJointMap["mKneeLeft"] = "mKneeLeft"; + mJointMap["mAnkleLeft"] = "mAnkleLeft"; + mJointMap["mFootLeft"] = "mFootLeft"; + mJointMap["mToeLeft"] = "mToeLeft"; + + mJointMap["avatar_mPelvis"] = "mPelvis"; + mJointMap["avatar_mTorso"] = "mTorso"; + mJointMap["avatar_mChest"] = "mChest"; + mJointMap["avatar_mNeck"] = "mNeck"; + mJointMap["avatar_mHead"] = "mHead"; + mJointMap["avatar_mSkull"] = "mSkull"; + mJointMap["avatar_mEyeRight"] = "mEyeRight"; + mJointMap["avatar_mEyeLeft"] = "mEyeLeft"; + mJointMap["avatar_mCollarLeft"] = "mCollarLeft"; + mJointMap["avatar_mShoulderLeft"] = "mShoulderLeft"; + mJointMap["avatar_mElbowLeft"] = "mElbowLeft"; + mJointMap["avatar_mWristLeft"] = "mWristLeft"; + mJointMap["avatar_mCollarRight"] = "mCollarRight"; + mJointMap["avatar_mShoulderRight"] = "mShoulderRight"; + mJointMap["avatar_mElbowRight"] = "mElbowRight"; + mJointMap["avatar_mWristRight"] = "mWristRight"; + mJointMap["avatar_mHipRight"] = "mHipRight"; + mJointMap["avatar_mKneeRight"] = "mKneeRight"; + mJointMap["avatar_mAnkleRight"] = "mAnkleRight"; + mJointMap["avatar_mFootRight"] = "mFootRight"; + mJointMap["avatar_mToeRight"] = "mToeRight"; + mJointMap["avatar_mHipLeft"] = "mHipLeft"; + mJointMap["avatar_mKneeLeft"] = "mKneeLeft"; + mJointMap["avatar_mAnkleLeft"] = "mAnkleLeft"; + mJointMap["avatar_mFootLeft"] = "mFootLeft"; + mJointMap["avatar_mToeLeft"] = "mToeLeft"; + + + mJointMap["hip"] = "mPelvis"; + mJointMap["abdomen"] = "mTorso"; + mJointMap["chest"] = "mChest"; + mJointMap["neck"] = "mNeck"; + mJointMap["head"] = "mHead"; + mJointMap["figureHair"] = "mSkull"; + mJointMap["lCollar"] = "mCollarLeft"; + mJointMap["lShldr"] = "mShoulderLeft"; + mJointMap["lForeArm"] = "mElbowLeft"; + mJointMap["lHand"] = "mWristLeft"; + mJointMap["rCollar"] = "mCollarRight"; + mJointMap["rShldr"] = "mShoulderRight"; + mJointMap["rForeArm"] = "mElbowRight"; + mJointMap["rHand"] = "mWristRight"; + mJointMap["rThigh"] = "mHipRight"; + mJointMap["rShin"] = "mKneeRight"; + mJointMap["rFoot"] = "mFootRight"; + mJointMap["lThigh"] = "mHipLeft"; + mJointMap["lShin"] = "mKneeLeft"; + mJointMap["lFoot"] = "mFootLeft"; +} + +void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, BOOL& first_transform) +{ + LLVector4a box[] = + { + LLVector4a(-1, 1,-1), + LLVector4a(-1, 1, 1), + LLVector4a(-1,-1,-1), + LLVector4a(-1,-1, 1), + LLVector4a( 1, 1,-1), + LLVector4a( 1, 1, 1), + LLVector4a( 1,-1,-1), + LLVector4a( 1,-1, 1), + }; + + for (S32 j = 0; j < model->getNumVolumeFaces(); ++j) + { + const LLVolumeFace& face = model->getVolumeFace(j); + + LLVector4a center; + center.setAdd(face.mExtents[0], face.mExtents[1]); + center.mul(0.5f); + LLVector4a size; + size.setSub(face.mExtents[1],face.mExtents[0]); + size.mul(0.5f); + + for (U32 i = 0; i < 8; i++) + { + LLVector4a t; + t.setMul(size, box[i]); + t.add(center); + + LLVector4a v; + + mat.affineTransform(t, v); + + if (first_transform) + { + first_transform = FALSE; + min = max = v; + } + else + { + update_min_max(min, max, v); + } + } + } +} + +void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& max, BOOL& first_transform) +{ + LLVector4a mina, maxa; + LLMatrix4a mata; + + mata.loadu(mat); + mina.load3(min.mV); + maxa.load3(max.mV); + + stretch_extents(model, mata, mina, maxa, first_transform); + + min.set(mina.getF32ptr()); + max.set(maxa.getF32ptr()); +} + +void LLModelLoader::run() +{ + DAE dae; + domCOLLADA* dom = dae.open(mFilename); + + if (dom) + { + daeDatabase* db = dae.getDatabase(); + + daeInt count = db->getElementCount(NULL, COLLADA_TYPE_MESH); + + daeDocument* doc = dae.getDoc(mFilename); + if (!doc) + { + llwarns << "can't find internal doc" << llendl; + return; + } + + daeElement* root = doc->getDomRoot(); + if (!root) + { + llwarns << "document has no root" << llendl; + return; + } + + //get unit scale + mTransform.setIdentity(); + + domAsset::domUnit* unit = daeSafeCast(root->getDescendant(daeElement::matchType(domAsset::domUnit::ID()))); + + if (unit) + { + F32 meter = unit->getMeter(); + mTransform.mMatrix[0][0] = meter; + mTransform.mMatrix[1][1] = meter; + mTransform.mMatrix[2][2] = meter; + } + + //get up axis rotation + LLMatrix4 rotation; + + domUpAxisType up = UPAXISTYPE_Y_UP; // default is Y_UP + domAsset::domUp_axis* up_axis = + daeSafeCast(root->getDescendant(daeElement::matchType(domAsset::domUp_axis::ID()))); + + if (up_axis) + { + up = up_axis->getValue(); + } + + if (up == UPAXISTYPE_X_UP) + { + rotation.initRotation(0.0f, 90.0f * DEG_TO_RAD, 0.0f); + } + else if (up == UPAXISTYPE_Y_UP) + { + rotation.initRotation(90.0f * DEG_TO_RAD, 0.0f, 0.0f); + } + + rotation *= mTransform; + mTransform = rotation; + + + for (daeInt idx = 0; idx < count; ++idx) + { //build map of domEntities to LLModel + domMesh* mesh = NULL; + db->getElement((daeElement**) &mesh, idx, NULL, COLLADA_TYPE_MESH); + + if (mesh) + { + LLPointer model = LLModel::loadModelFromDomMesh(mesh); + + if (model.notNull() && validate_model(model)) + { + mModelList.push_back(model); + mModel[mesh] = model; + } + } + } + + count = db->getElementCount(NULL, COLLADA_TYPE_SKIN); + for (daeInt idx = 0; idx < count; ++idx) + { //add skinned meshes as instances + domSkin* skin = NULL; + db->getElement((daeElement**) &skin, idx, NULL, COLLADA_TYPE_SKIN); + + if (skin) + { + domGeometry* geom = daeSafeCast(skin->getSource().getElement()); + + if (geom) + { + domMesh* mesh = geom->getMesh(); + if (mesh) + { + LLModel* model = mModel[mesh]; + if (model) + { + LLVector3 mesh_scale_vector; + LLVector3 mesh_translation_vector; + model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); + + LLMatrix4 normalized_transformation; + normalized_transformation.setTranslation(mesh_translation_vector); + + LLMatrix4 mesh_scale; + mesh_scale.initScale(mesh_scale_vector); + mesh_scale *= normalized_transformation; + normalized_transformation = mesh_scale; + + glh::matrix4f inv_mat((F32*) normalized_transformation.mMatrix); + inv_mat = inv_mat.inverse(); + LLMatrix4 inverse_normalized_transformation(inv_mat.m); + + domSkin::domBind_shape_matrix* bind_mat = skin->getBind_shape_matrix(); + + if (bind_mat) + { //get bind shape matrix + domFloat4x4& dom_value = bind_mat->getValue(); + + for (int i = 0; i < 4; i++) + { + for(int j = 0; j < 4; j++) + { + model->mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j*4]; + } + } + + LLMatrix4 trans = normalized_transformation; + trans *= model->mBindShapeMatrix; + model->mBindShapeMatrix = trans; + + } + + + //The joint transfom map that we'll populate below + std::map jointTransforms; + jointTransforms.clear(); + + //Some collada setup for accessing the skeleton + daeElement* pElement = 0; + dae.getDatabase()->getElement( &pElement, 0, 0, "skeleton" ); + + //Try to get at the skeletal instance controller + domInstance_controller::domSkeleton* pSkeleton = daeSafeCast( pElement ); + bool missingSkeletonOrScene = false; + + //If no skeleton, do a breadth-first search to get at specific joints + if ( !pSkeleton ) + { + daeElement* pScene = root->getDescendant("visual_scene"); + if ( !pScene ) + { + llwarns<<"No visual scene - unable to parse bone offsets "< > children = pScene->getChildren(); + S32 childCount = children.getCount(); + + //Process any children that are joints + //Not all children are joints, some code be ambient lights, cameras, geometry etc.. + for (S32 i = 0; i < childCount; ++i) + { + domNode* pNode = daeSafeCast(children[i]); + if ( isNodeAJoint( pNode ) ) + { + processJointNode( pNode, jointTransforms ); + } + } + } + } + else + //Has Skeleton + { + //Get the root node of the skeleton + daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement(); + if ( pSkeletonRootNode ) + { + //Once we have the root node - start acccessing it's joint components + const int jointCnt = mJointMap.size(); + std::map :: const_iterator jointIt = mJointMap.begin(); + + //Loop over all the possible joints within the .dae - using the allowed joint list in the ctor. + for ( int i=0; i( resolver.getElement() ); + if ( pJoint ) + { + //Pull out the translate id and store it in the jointTranslations map + daeSIDResolver jointResolver( pJoint, "./translate" ); + domTranslate* pTranslate = daeSafeCast( jointResolver.getElement() ); + + LLMatrix4 workingTransform; + + //Translation via SID + if ( pTranslate ) + { + extractTranslation( pTranslate, workingTransform ); + } + else + { + //Translation via child from element + daeElement* pTranslateElement = getChildFromElement( pJoint, "translate" ); + if ( pTranslateElement && pTranslateElement->typeID() != domTranslate::ID() ) + { + llwarns<< "The found element is not a translate node" < :: const_iterator jointIt = mJointMap.begin(); + for ( int i=0; igetJoint( lookingForJoint ); + if ( pJoint ) + { + pJoint->storeCurrentXform( jointTransform.getTranslation() ); + } + else + { + //Most likely an error in the asset. + llwarns<<"Tried to apply joint position from .dae, but it did not exist in the avatar rig." << llendl; + } + //Reposition the avatars pelvis (avPos+offset) + //if ( lookingForJoint == "mPelvis" ) + //{ + // const LLVector3& pos = gAgentAvatarp->getCharacterPosition(); + // gAgentAvatarp->setPelvisOffset( true, jointTransform.getTranslation() ); + // gAgentAvatarp->setPosition( pos + jointTransform.getTranslation() ); + //} + } + } + } //missingSkeletonOrScene + + domSkin::domJoints* joints = skin->getJoints(); + + domInputLocal_Array& joint_input = joints->getInput_array(); + + for (size_t i = 0; i < joint_input.getCount(); ++i) + { + domInputLocal* input = joint_input.get(i); + xsNMTOKEN semantic = input->getSemantic(); + + if (strcmp(semantic, COMMON_PROFILE_INPUT_JOINT) == 0) + { //found joint source, fill model->mJointMap and model->mJointList + daeElement* elem = input->getSource().getElement(); + + domSource* source = daeSafeCast(elem); + if (source) + { + + + domName_array* names_source = source->getName_array(); + + if (names_source) + { + domListOfNames &names = names_source->getValue(); + + for (size_t j = 0; j < names.getCount(); ++j) + { + std::string name(names.get(j)); + if (mJointMap.find(name) != mJointMap.end()) + { + name = mJointMap[name]; + } + model->mJointList.push_back(name); + model->mJointMap[name] = j; + } + } + else + { + domIDREF_array* names_source = source->getIDREF_array(); + if (names_source) + { + xsIDREFS& names = names_source->getValue(); + + for (size_t j = 0; j < names.getCount(); ++j) + { + std::string name(names.get(j).getID()); + if (mJointMap.find(name) != mJointMap.end()) + { + name = mJointMap[name]; + } + model->mJointList.push_back(name); + model->mJointMap[name] = j; + } + } + } + } + } + else if (strcmp(semantic, COMMON_PROFILE_INPUT_INV_BIND_MATRIX) == 0) + { //found inv_bind_matrix array, fill model->mInvBindMatrix + domSource* source = daeSafeCast(input->getSource().getElement()); + if (source) + { + domFloat_array* t = source->getFloat_array(); + if (t) + { + domListOfFloats& transform = t->getValue(); + S32 count = transform.getCount()/16; + + for (S32 k = 0; k < count; ++k) + { + LLMatrix4 mat; + + for (int i = 0; i < 4; i++) + { + for(int j = 0; j < 4; j++) + { + mat.mMatrix[i][j] = transform[k*16 + i + j*4]; + } + } + + model->mInvBindMatrix.push_back(mat); + } + } + } + } + } + + //We need to construct the alternate bind matrix (which contains the new joint positions) + //in the same order as they were stored in the joint buffer. The joints associated + //with the skeleton are not stored in the same order as they are in the exported joint buffer. + //This remaps the skeletal joints to be in the same order as the joints stored in the model. + std::vector :: const_iterator jointIt = model->mJointList.begin(); + const int jointCnt = model->mJointList.size(); + for ( int i=0; imInvBindMatrix[i]; + newInverse.setTranslation( jointTransforms[lookingForJoint].getTranslation() ); + model->mAlternateBindMatrix.push_back( newInverse ); + } + else + { + llwarns<<"Possibly misnamed/missing joint [" <getVertices(); + if (verts) + { + domInputLocal_Array& inputs = verts->getInput_array(); + for (size_t i = 0; i < inputs.getCount() && model->mPosition.empty(); ++i) + { + if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_POSITION) == 0) + { + domSource* pos_source = daeSafeCast(inputs[i]->getSource().getElement()); + if (pos_source) + { + domFloat_array* pos_array = pos_source->getFloat_array(); + if (pos_array) + { + domListOfFloats& pos = pos_array->getValue(); + + for (size_t j = 0; j < pos.getCount(); j += 3) + { + if (pos.getCount() <= j+2) + { + llerrs << "WTF?" << llendl; + } + + LLVector3 v(pos[j], pos[j+1], pos[j+2]); + + //transform from COLLADA space to volume space + v = v * inverse_normalized_transformation; + + model->mPosition.push_back(v); + } + } + } + } + } + } + + //grab skin weights array + domSkin::domVertex_weights* weights = skin->getVertex_weights(); + if (weights) + { + domInputLocalOffset_Array& inputs = weights->getInput_array(); + domFloat_array* vertex_weights = NULL; + for (size_t i = 0; i < inputs.getCount(); ++i) + { + if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_WEIGHT) == 0) + { + domSource* weight_source = daeSafeCast(inputs[i]->getSource().getElement()); + if (weight_source) + { + vertex_weights = weight_source->getFloat_array(); + } + } + } + + if (vertex_weights) + { + domListOfFloats& w = vertex_weights->getValue(); + domListOfUInts& vcount = weights->getVcount()->getValue(); + domListOfInts& v = weights->getV()->getValue(); + + U32 c_idx = 0; + for (size_t vc_idx = 0; vc_idx < vcount.getCount(); ++vc_idx) + { //for each vertex + daeUInt count = vcount[vc_idx]; + + //create list of weights that influence this vertex + LLModel::weight_list weight_list; + + for (daeUInt i = 0; i < count; ++i) + { //for each weight + daeInt joint_idx = v[c_idx++]; + daeInt weight_idx = v[c_idx++]; + + if (joint_idx == -1) + { + //ignore bindings to bind_shape_matrix + continue; + } + + F32 weight_value = w[weight_idx]; + + weight_list.push_back(LLModel::JointWeight(joint_idx, weight_value)); + } + + //sort by joint weight + std::sort(weight_list.begin(), weight_list.end(), LLModel::CompareWeightGreater()); + + std::vector wght; + + F32 total = 0.f; + + for (U32 i = 0; i < llmin((U32) 4, (U32) weight_list.size()); ++i) + { //take up to 4 most significant weights + if (weight_list[i].mWeight > 0.f) + { + wght.push_back( weight_list[i] ); + total += weight_list[i].mWeight; + } + } + + F32 scale = 1.f/total; + if (scale != 1.f) + { //normalize weights + for (U32 i = 0; i < wght.size(); ++i) + { + wght[i].mWeight *= scale; + } + } + + model->mSkinWeights[model->mPosition[vc_idx]] = wght; + } + + //add instance to scene for this model + + LLMatrix4 transformation = mTransform; + // adjust the transformation to compensate for mesh normalization + + LLMatrix4 mesh_translation; + mesh_translation.setTranslation(mesh_translation_vector); + mesh_translation *= transformation; + transformation = mesh_translation; + + LLMatrix4 mesh_scale; + mesh_scale.initScale(mesh_scale_vector); + mesh_scale *= transformation; + transformation = mesh_scale; + + std::vector materials; + materials.resize(model->getNumVolumeFaces()); + mScene[transformation].push_back(LLModelInstance(model, transformation, materials)); + stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); + } + } + } + } + } + } + } + + daeElement* scene = root->getDescendant("visual_scene"); + + if (!scene) + { + llwarns << "document has no visual_scene" << llendl; + setLoadState( ERROR_PARSING ); + return; + } + + processElement(scene); + + doOnIdleOneTime(boost::bind(&LLModelPreview::loadModelCallback,mPreview,mLod)); + } +} + +//called in the main thread +void LLModelLoader::loadTextures() +{ + BOOL is_paused = isPaused() ; + pause() ; //pause the loader + + for(scene::iterator iter = mScene.begin(); iter != mScene.end(); ++iter) + { + for(U32 i = 0 ; i < iter->second.size(); i++) + { + for(U32 j = 0 ; j < iter->second[i].mMaterial.size() ; j++) + { + if(!iter->second[i].mMaterial[j].mDiffuseMapFilename.empty()) + { + iter->second[i].mMaterial[j].mDiffuseMap = + LLViewerTextureManager::getFetchedTextureFromUrl("file://" + iter->second[i].mMaterial[j].mDiffuseMapFilename, TRUE, LLViewerTexture::BOOST_PREVIEW); + iter->second[i].mMaterial[j].mDiffuseMap->setLoadedCallback(LLModelPreview::textureLoadedCallback, 0, TRUE, FALSE, mPreview, NULL, FALSE); + iter->second[i].mMaterial[j].mDiffuseMap->forceToSaveRawImage(); + } + } + } + } + + if(!is_paused) + { + unpause() ; + } +} + +bool LLModelLoader::isNodeAJoint( domNode* pNode ) +{ + if ( pNode->getName() == NULL) + { + return false; + } + + if ( mJointMap.find( pNode->getName() ) != mJointMap.end() ) + { + return true; + } + + return false; +} + +void LLModelLoader::extractTranslation( domTranslate* pTranslate, LLMatrix4& transform ) +{ + domFloat3 jointTrans = pTranslate->getValue(); + LLVector3 singleJointTranslation( jointTrans[0], jointTrans[1], jointTrans[2] ); + transform.setTranslation( singleJointTranslation ); +} + +void LLModelLoader::extractTranslationViaElement( daeElement* pTranslateElement, LLMatrix4& transform ) +{ + domTranslate* pTranslateChild = dynamic_cast( pTranslateElement ); + domFloat3 translateChild = pTranslateChild->getValue(); + LLVector3 singleJointTranslation( translateChild[0], translateChild[1], translateChild[2] ); + transform.setTranslation( singleJointTranslation ); +} + +void LLModelLoader::processJointNode( domNode* pNode, std::map& jointTransforms ) +{ + if (pNode->getName() == NULL) + { + llwarns << "nameless node, can't process" << llendl; + return; + } + + //llwarns<<"ProcessJointNode# Node:" <getName()<( jointResolver.getElement() ); + + //Translation via SID was successful + if ( pTranslate ) + { + extractTranslation( pTranslate, workingTransform ); + } + else + { + //Translation via child from element + daeElement* pTranslateElement = getChildFromElement( pNode, "translate" ); + if ( !pTranslateElement || pTranslateElement->typeID() != domTranslate::ID() ) + { + llwarns<< "The found element is not a translate node" <getName() ] = workingTransform; + + //2. handle the nodes children + + //Gather and handle the incoming nodes children + daeTArray< daeSmartRef > childOfChild = pNode->getChildren(); + S32 childOfChildCount = childOfChild.getCount(); + + for (S32 i = 0; i < childOfChildCount; ++i) + { + domNode* pChildNode = daeSafeCast( childOfChild[i] ); + if ( pChildNode ) + { + processJointNode( pChildNode, jointTransforms ); + } + } +} + +daeElement* LLModelLoader::getChildFromElement( daeElement* pElement, std::string const & name ) +{ + daeElement* pChildOfElement = pElement->getChild( name.c_str() ); + if ( pChildOfElement ) + { + return pChildOfElement; + } + llwarns<< "Could not find a child [" << name << "] for the element: \"" << pElement->getAttribute("id") << "\"" << llendl; + return NULL; +} + +void LLModelLoader::processElement(daeElement* element) +{ + LLMatrix4 saved_transform = mTransform; + + domTranslate* translate = daeSafeCast(element); + if (translate) + { + domFloat3 dom_value = translate->getValue(); + + LLMatrix4 translation; + translation.setTranslation(LLVector3(dom_value[0], dom_value[1], dom_value[2])); + + translation *= mTransform; + mTransform = translation; + } + + domRotate* rotate = daeSafeCast(element); + if (rotate) + { + domFloat4 dom_value = rotate->getValue(); + + LLMatrix4 rotation; + rotation.initRotTrans(dom_value[3] * DEG_TO_RAD, LLVector3(dom_value[0], dom_value[1], dom_value[2]), LLVector3(0, 0, 0)); + + rotation *= mTransform; + mTransform = rotation; + } + + domScale* scale = daeSafeCast(element); + if (scale) + { + domFloat3 dom_value = scale->getValue(); + + LLMatrix4 scaling; + scaling.initScale(LLVector3(dom_value[0], dom_value[1], dom_value[2])); + + scaling *= mTransform; + mTransform = scaling; + } + + domMatrix* matrix = daeSafeCast(element); + if (matrix) + { + domFloat4x4 dom_value = matrix->getValue(); + + LLMatrix4 matrix_transform; + + for (int i = 0; i < 4; i++) + { + for(int j = 0; j < 4; j++) + { + matrix_transform.mMatrix[i][j] = dom_value[i + j*4]; + } + } + + matrix_transform *= mTransform; + mTransform = matrix_transform; + } + + domInstance_geometry* instance_geo = daeSafeCast(element); + if (instance_geo) + { + domGeometry* geo = daeSafeCast(instance_geo->getUrl().getElement()); + if (geo) + { + domMesh* mesh = daeSafeCast(geo->getDescendant(daeElement::matchType(domMesh::ID()))); + if (mesh) + { + LLModel* model = mModel[mesh]; + if (model) + { + LLMatrix4 transformation = mTransform; + + std::vector materials = getMaterials(model, instance_geo); + + // adjust the transformation to compensate for mesh normalization + LLVector3 mesh_scale_vector; + LLVector3 mesh_translation_vector; + model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); + + LLMatrix4 mesh_translation; + mesh_translation.setTranslation(mesh_translation_vector); + mesh_translation *= transformation; + transformation = mesh_translation; + + LLMatrix4 mesh_scale; + mesh_scale.initScale(mesh_scale_vector); + mesh_scale *= transformation; + transformation = mesh_scale; + + mScene[transformation].push_back(LLModelInstance(model, transformation, materials)); + + stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); + } + } + } + } + + domInstance_node* instance_node = daeSafeCast(element); + if (instance_node) + { + daeElement* instance = instance_node->getUrl().getElement(); + if (instance) + { + processElement(instance); + } + } + + //process children + daeTArray< daeSmartRef > children = element->getChildren(); + for (S32 i = 0; i < children.getCount(); i++) + { + processElement(children[i]); + } + + domNode* node = daeSafeCast(element); + if (node) + { //this element was a node, restore transform before processiing siblings + mTransform = saved_transform; + } +} + +std::vector LLModelLoader::getMaterials(LLModel* model, domInstance_geometry* instance_geo) +{ + std::vector materials; + for (int i = 0; i < model->mMaterialList.size(); i++) + { + LLImportMaterial import_material; + + domInstance_material* instance_mat = NULL; + + domBind_material::domTechnique_common* technique = + daeSafeCast(instance_geo->getDescendant(daeElement::matchType(domBind_material::domTechnique_common::ID()))); + + if (technique) + { + daeTArray< daeSmartRef > inst_materials = technique->getChildrenByType(); + for (int j = 0; j < inst_materials.getCount(); j++) + { + std::string symbol(inst_materials[j]->getSymbol()); + + if (symbol == model->mMaterialList[i]) // found the binding + { + instance_mat = inst_materials[j]; + } + } + } + + if (instance_mat) + { + domMaterial* material = daeSafeCast(instance_mat->getTarget().getElement()); + if (material) + { + domInstance_effect* instance_effect = + daeSafeCast(material->getDescendant(daeElement::matchType(domInstance_effect::ID()))); + if (instance_effect) + { + domEffect* effect = daeSafeCast(instance_effect->getUrl().getElement()); + if (effect) + { + domProfile_COMMON* profile = + daeSafeCast(effect->getDescendant(daeElement::matchType(domProfile_COMMON::ID()))); + if (profile) + { + import_material = profileToMaterial(profile); + } + } + } + } + } + + materials.push_back(import_material); + } + + return materials; +} + +LLImportMaterial LLModelLoader::profileToMaterial(domProfile_COMMON* material) +{ + LLImportMaterial mat; + mat.mFullbright = FALSE; + + daeElement* diffuse = material->getDescendant("diffuse"); + if (diffuse) + { + domCommon_color_or_texture_type_complexType::domTexture* texture = + daeSafeCast(diffuse->getDescendant("texture")); + if (texture) + { + domCommon_newparam_type_Array newparams = material->getNewparam_array(); + for (S32 i = 0; i < newparams.getCount(); i++) + { + domFx_surface_common* surface = newparams[i]->getSurface(); + if (surface) + { + domFx_surface_init_common* init = surface->getFx_surface_init_common(); + if (init) + { + domFx_surface_init_from_common_Array init_from = init->getInit_from_array(); + + if (init_from.getCount() > i) + { + domImage* image = daeSafeCast(init_from[i]->getValue().getElement()); + if (image) + { + // we only support init_from now - embedded data will come later + domImage::domInit_from* init = image->getInit_from(); + if (init) + { + mat.mDiffuseMapFilename = cdom::uriToNativePath(init->getValue().str()); + mat.mDiffuseMapLabel = getElementLabel(material); + } + } + } + } + } + } + } + + domCommon_color_or_texture_type_complexType::domColor* color = + daeSafeCast(diffuse->getDescendant("color")); + if (color) + { + domFx_color_common domfx_color = color->getValue(); + LLColor4 value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]); + mat.mDiffuseColor = value; + } + } + + daeElement* emission = material->getDescendant("emission"); + if (emission) + { + LLColor4 emission_color = getDaeColor(emission); + if (((emission_color[0] + emission_color[1] + emission_color[2]) / 3.0) > 0.25) + { + mat.mFullbright = TRUE; + } + } + + return mat; +} + +// try to get a decent label for this element +std::string LLModelLoader::getElementLabel(daeElement *element) +{ + // if we have a name attribute, use it + std::string name = element->getAttribute("name"); + if (name.length()) + { + return name; + } + + // if we have an ID attribute, use it + if (element->getID()) + { + return std::string(element->getID()); + } + + // if we have a parent, use it + daeElement* parent = element->getParent(); + if (parent) + { + // if parent has a name, use it + std::string name = parent->getAttribute("name"); + if (name.length()) + { + return name; + } + + // if parent has an ID, use it + if (parent->getID()) + { + return std::string(parent->getID()); + } + } + + // try to use our type + daeString element_name = element->getElementName(); + if (element_name) + { + return std::string(element_name); + } + + // if all else fails, use "object" + return std::string("object"); +} + +LLColor4 LLModelLoader::getDaeColor(daeElement* element) +{ + LLColor4 value; + domCommon_color_or_texture_type_complexType::domColor* color = + daeSafeCast(element->getDescendant("color")); + if (color) + { + domFx_color_common domfx_color = color->getValue(); + value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]); + } + + return value; +} + +//----------------------------------------------------------------------------- +// LLModelPreview +//----------------------------------------------------------------------------- + +LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) +: LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE), LLMutex(NULL) +{ + mNeedsUpdate = TRUE; + mCameraDistance = 0.f; + mCameraYaw = 0.f; + mCameraPitch = 0.f; + mCameraZoom = 1.f; + mTextureName = 0; + mPreviewLOD = 0; + mModelLoader = NULL; + mMaxTriangleLimit = 0; + mDirty = false; + mGenLOD = false; + mLoading = false; + mGroup = 0; + mBuildShareTolerance = 0.f; + mBuildQueueMode = GLOD_QUEUE_GREEDY; + mBuildBorderMode = GLOD_BORDER_UNLOCK; + mBuildOperator = GLOD_OPERATOR_EDGE_COLLAPSE; + + mViewOption["show_textures"] = false; + + mFMP = fmp; + + glodInit(); +} + +LLModelPreview::~LLModelPreview() +{ + if (mModelLoader) + { + delete mModelLoader; + mModelLoader = NULL; + } + + //*HACK : *TODO : turn this back on when we understand why this crashes + //glodShutdown(); +} + +U32 LLModelPreview::calcResourceCost() +{ + assert_main_thread(); + + rebuildUploadData(); + + if ( mModelLoader->getLoadState() != LLModelLoader::ERROR_PARSING ) + { + mFMP->childEnable("ok_btn"); + } + + U32 cost = 0; + std::set accounted; + U32 num_points = 0; + U32 num_hulls = 0; + + F32 debug_scale = mFMP->childGetValue("import_scale").asReal(); + + F32 streaming_cost = 0.f; + F32 physics_cost = 0.f; + for (U32 i = 0; i < mUploadData.size(); ++i) + { + LLModelInstance& instance = mUploadData[i]; + + if (accounted.find(instance.mModel) == accounted.end()) + { + accounted.insert(instance.mModel); + + LLModel::convex_hull_decomposition& decomp = + instance.mLOD[LLModel::LOD_PHYSICS] ? + instance.mLOD[LLModel::LOD_PHYSICS]->mConvexHullDecomp : + instance.mModel->mConvexHullDecomp; + + LLSD ret = LLModel::writeModel( + "", + instance.mLOD[4], + instance.mLOD[3], + instance.mLOD[2], + instance.mLOD[1], + instance.mLOD[0], + decomp, + mFMP->childGetValue("upload_skin").asBoolean(), + mFMP->childGetValue("upload_joints").asBoolean(), + TRUE); + cost += gMeshRepo.calcResourceCost(ret); + + num_hulls += decomp.size(); + for (U32 i = 0; i < decomp.size(); ++i) + { + num_points += decomp[i].size(); + } + + //calculate streaming cost + LLMatrix4 transformation = instance.mTransform; + + LLVector3 position = LLVector3(0, 0, 0) * transformation; + + LLVector3 x_transformed = LLVector3(1, 0, 0) * transformation - position; + LLVector3 y_transformed = LLVector3(0, 1, 0) * transformation - position; + LLVector3 z_transformed = LLVector3(0, 0, 1) * transformation - position; + F32 x_length = x_transformed.normalize(); + F32 y_length = y_transformed.normalize(); + F32 z_length = z_transformed.normalize(); + LLVector3 scale = LLVector3(x_length, y_length, z_length); + + F32 radius = scale.length()*debug_scale; + + streaming_cost += LLMeshRepository::getStreamingCost(ret, radius); + } + } + + //mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[HULLS]", llformat("%d",num_hulls)); + //mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[POINTS]", llformat("%d",num_points)); + mFMP->childSetTextArg("streaming cost", "[COST]", llformat("%.3f", streaming_cost)); + mFMP->childSetTextArg("physics cost", "[COST]", llformat("%.3f", physics_cost)); + F32 scale = mFMP->childGetValue("import_scale").asReal()*2.f; + mFMP->childSetTextArg("import_dimensions", "[X]", llformat("%.3f", mPreviewScale[0]*scale)); + mFMP->childSetTextArg("import_dimensions", "[Y]", llformat("%.3f", mPreviewScale[1]*scale)); + mFMP->childSetTextArg("import_dimensions", "[Z]", llformat("%.3f", mPreviewScale[2]*scale)); + + updateStatusMessages(); + + return cost; +} + +void LLModelPreview::rebuildUploadData() +{ + assert_main_thread(); + + mUploadData.clear(); + mTextureSet.clear(); + + //fill uploaddata instance vectors from scene data + + std::string requested_name = mFMP->getChild("description_form")->getValue().asString(); + + + LLSpinCtrl* scale_spinner = mFMP->getChild("import_scale"); + + if (!scale_spinner) + { + llerrs << "floater_model_preview.xml MUST contain import_scale spinner." << llendl; + } + + F32 scale = scale_spinner->getValue().asReal(); + + LLMatrix4 scale_mat; + scale_mat.initScale(LLVector3(scale, scale, scale)); + + F32 max_scale = 0.f; + + if ( mBaseScene.size() > 0 ) + { + mFMP->childEnable("ok_btn"); + } + + for (LLModelLoader::scene::iterator iter = mBaseScene.begin(); iter != mBaseScene.end(); ++iter) + { //for each transform in scene + LLMatrix4 mat = iter->first; + + // compute position + LLVector3 position = LLVector3(0, 0, 0) * mat; + + // compute scale + LLVector3 x_transformed = LLVector3(1, 0, 0) * mat - position; + LLVector3 y_transformed = LLVector3(0, 1, 0) * mat - position; + LLVector3 z_transformed = LLVector3(0, 0, 1) * mat - position; + F32 x_length = x_transformed.normalize(); + F32 y_length = y_transformed.normalize(); + F32 z_length = z_transformed.normalize(); + + max_scale = llmax(llmax(llmax(max_scale, x_length), y_length), z_length); + + mat *= scale_mat; + + for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) + { //for each instance with said transform applied + LLModelInstance instance = *model_iter; + + LLModel* base_model = instance.mModel; + if (base_model) + { + base_model->mRequestedLabel = requested_name; + } + + S32 idx = 0; + for (idx = 0; idx < mBaseModel.size(); ++idx) + { //find reference instance for this model + if (mBaseModel[idx] == base_model) + { + break; + } + } + + for (U32 i = 0; i < LLModel::NUM_LODS; i++) + { //fill LOD slots based on reference model index + if (!mModel[i].empty()) + { + instance.mLOD[i] = mModel[i][idx]; + } + else + { + instance.mLOD[i] = NULL; + } + } + + instance.mTransform = mat; + mUploadData.push_back(instance); + } + } + + F32 max_import_scale = DEFAULT_MAX_PRIM_SCALE/max_scale; + + scale_spinner->setMaxValue(max_import_scale); + + if (max_import_scale < scale) + { + scale_spinner->setValue(max_import_scale); + } + +} + + +void LLModelPreview::clearModel(S32 lod) +{ + if (lod < 0 || lod > LLModel::LOD_PHYSICS) + { + return; + } + + mVertexBuffer[lod].clear(); + mModel[lod].clear(); + mScene[lod].clear(); +} + +void LLModelPreview::loadModel(std::string filename, S32 lod) +{ + assert_main_thread(); + + LLMutexLock lock(this); + + if (mModelLoader) + { + delete mModelLoader; + mModelLoader = NULL; + } + + if (filename.empty()) + { + if (mBaseModel.empty()) + { + // this is the initial file picking. Close the whole floater + // if we don't have a base model to show for high LOD. + mFMP->closeFloater(false); + } + + mLoading = false; + return; + } + + mLODFile[lod] = filename; + + if (lod == LLModel::LOD_HIGH) + { + clearGLODGroup(); + } + + mModelLoader = new LLModelLoader(filename, lod, this); + + mModelLoader->start(); + + mFMP->childSetTextArg("status", "[STATUS]", mFMP->getString("status_reading_file")); + + setPreviewLOD(lod); + + if ( mModelLoader->getLoadState() == LLModelLoader::ERROR_PARSING ) + { + mFMP->childDisable("ok_btn"); + } + + if (lod == mPreviewLOD) + { + mFMP->childSetText("lod_file", mLODFile[mPreviewLOD]); + } + else if (lod == LLModel::LOD_PHYSICS) + { + mFMP->childSetText("physics_file", mLODFile[lod]); + } + + mFMP->openFloater(); +} + +void LLModelPreview::setPhysicsFromLOD(S32 lod) +{ + assert_main_thread(); + + if (lod >= 0 && lod <= 3) + { + mModel[LLModel::LOD_PHYSICS] = mModel[lod]; + mScene[LLModel::LOD_PHYSICS] = mScene[lod]; + mLODFile[LLModel::LOD_PHYSICS].clear(); + mFMP->childSetText("physics_file", mLODFile[LLModel::LOD_PHYSICS]); + mVertexBuffer[LLModel::LOD_PHYSICS].clear(); + rebuildUploadData(); + refresh(); + updateStatusMessages(); + } +} + +void LLModelPreview::clearIncompatible(S32 lod) +{ + for (U32 i = 0; i <= LLModel::LOD_HIGH; i++) + { //clear out any entries that aren't compatible with this model + if (i != lod) + { + if (mModel[i].size() != mModel[lod].size()) + { + mModel[i].clear(); + mScene[i].clear(); + mVertexBuffer[i].clear(); + + if (i == LLModel::LOD_HIGH) + { + mBaseModel = mModel[lod]; + clearGLODGroup(); + mBaseScene = mScene[lod]; + mVertexBuffer[5].clear(); + } + } + } + } +} + +void LLModelPreview::clearGLODGroup() +{ + if (mGroup) + { + for (std::map, U32>::iterator iter = mObject.begin(); iter != mObject.end(); ++iter) + { + glodDeleteObject(iter->second); + stop_gloderror(); + } + mObject.clear(); + + glodDeleteGroup(mGroup); + stop_gloderror(); + mGroup = 0; + } +} + +void LLModelPreview::loadModelCallback(S32 lod) +{ + assert_main_thread(); + + LLMutexLock lock(this); + if (!mModelLoader) + { + return; + } + + mModelLoader->loadTextures() ; + mModel[lod] = mModelLoader->mModelList; + mScene[lod] = mModelLoader->mScene; + mVertexBuffer[lod].clear(); + + if (lod == LLModel::LOD_PHYSICS) + { + mPhysicsMesh.clear(); + } + + setPreviewLOD(lod); + + + if (lod == LLModel::LOD_HIGH) + { //save a copy of the highest LOD for automatic LOD manipulation + if (mBaseModel.empty()) + { //first time we've loaded a model, auto-gen LoD + mGenLOD = true; + } + + mBaseModel = mModel[lod]; + clearGLODGroup(); + + mBaseScene = mScene[lod]; + mVertexBuffer[5].clear(); + } + + clearIncompatible(lod); + + mDirty = true; + + if (lod == LLModel::LOD_HIGH) + { + resetPreviewTarget(); + } + + mLoading = false; + refresh(); +} + +void LLModelPreview::resetPreviewTarget() +{ + mPreviewTarget = (mModelLoader->mExtents[0] + mModelLoader->mExtents[1]) * 0.5f; + mPreviewScale = (mModelLoader->mExtents[1] - mModelLoader->mExtents[0]) * 0.5f; + setPreviewTarget(mPreviewScale.magVec()*2.f); +} + +void LLModelPreview::generateNormals() +{ + assert_main_thread(); + + S32 which_lod = mPreviewLOD; + + + if (which_lod > 4 || which_lod < 0 || + mModel[which_lod].empty()) + { + return; + } + + F32 angle_cutoff = mFMP->childGetValue("crease_angle").asReal(); + + angle_cutoff *= DEG_TO_RAD; + + if (which_lod == 3 && !mBaseModel.empty()) + { + for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) + { + (*iter)->generateNormals(angle_cutoff); + } + + mVertexBuffer[5].clear(); + } + + for (LLModelLoader::model_list::iterator iter = mModel[which_lod].begin(); iter != mModel[which_lod].end(); ++iter) + { + (*iter)->generateNormals(angle_cutoff); + } + + mVertexBuffer[which_lod].clear(); + refresh(); + +} + +void LLModelPreview::consolidate() +{ + std::map > composite; + + LLMatrix4 identity; + + //bake out each node in current scene to composite + for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) + { //for each transform in current scene + LLMatrix4 mat = iter->first; + glh::matrix4f inv_trans = glh::matrix4f((F32*) mat.mMatrix).inverse().transpose(); + LLMatrix4 norm_mat(inv_trans.m); + + for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) + { //for each instance with that transform + LLModelInstance& source_instance = *model_iter; + LLModel* source = source_instance.mModel; + + if (!validate_model(source)) + { + llerrs << "Invalid model found!" << llendl; + } + + for (S32 i = 0; i < source->getNumVolumeFaces(); ++i) + { //for each face in instance + const LLVolumeFace& src_face = source->getVolumeFace(i); + LLImportMaterial& source_material = source_instance.mMaterial[i]; + + //get model in composite that is composite for this material + LLModel* model = NULL; + + if (composite.find(source_material) != composite.end()) + { + model = composite[source_material].rbegin()->mModel; + if (model->getVolumeFace(0).mNumVertices + src_face.mNumVertices > 65535) + { + model = NULL; + } + } + + if (model == NULL) + { //no model found, make new model + std::vector materials; + materials.push_back(source_material); + LLVolumeParams volume_params; + volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); + model = new LLModel(volume_params, 0.f); + model->mLabel = source->mLabel; + model->setNumVolumeFaces(0); + composite[source_material].push_back(LLModelInstance(model, identity, materials)); + } + + model->appendFace(src_face, source->mMaterialList[i], mat, norm_mat); + } + } + } + + + //condense composite into as few LLModel instances as possible + LLModelLoader::model_list new_model; + std::vector instance_list; + + LLVolumeParams volume_params; + volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); + + std::vector empty_material; + LLModelInstance cur_instance(new LLModel(volume_params, 0.f), identity, empty_material); + cur_instance.mModel->setNumVolumeFaces(0); + + BOOL first_transform = TRUE; + + LLModelLoader::scene new_scene; + LLVector3 min,max; + + for (std::map >::iterator iter = composite.begin(); + iter != composite.end(); + ++iter) + { + std::map >::iterator next_iter = iter; ++next_iter; + + for (std::vector::iterator instance_iter = iter->second.begin(); + instance_iter != iter->second.end(); + ++instance_iter) + { + LLModel* source = instance_iter->mModel; + + if (instance_iter->mMaterial.size() != 1) + { + llerrs << "WTF?" << llendl; + } + + if (source->getNumVolumeFaces() != 1) + { + llerrs << "WTF?" << llendl; + } + + if (source->mMaterialList.size() != 1) + { + llerrs << "WTF?" << llendl; + } + + cur_instance.mModel->addFace(source->getVolumeFace(0)); + cur_instance.mMaterial.push_back(instance_iter->mMaterial[0]); + cur_instance.mModel->mMaterialList.push_back(source->mMaterialList[0]); + + BOOL last_model = FALSE; + + std::vector::iterator next_instance = instance_iter; ++next_instance; + + if (next_iter == composite.end() && + next_instance == iter->second.end()) + { + last_model = TRUE; + } + + if (last_model || cur_instance.mModel->getNumVolumeFaces() >= MAX_MODEL_FACES) + { + cur_instance.mModel->mLabel = source->mLabel; + + cur_instance.mModel->optimizeVolumeFaces(); + cur_instance.mModel->normalizeVolumeFaces(); + + if (!validate_model(cur_instance.mModel)) + { + llerrs << "Invalid model detected." << llendl; + } + + new_model.push_back(cur_instance.mModel); + + LLMatrix4 transformation = LLMatrix4(); + + // adjust the transformation to compensate for mesh normalization + LLVector3 mesh_scale_vector; + LLVector3 mesh_translation_vector; + cur_instance.mModel->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); + + LLMatrix4 mesh_translation; + mesh_translation.setTranslation(mesh_translation_vector); + mesh_translation *= transformation; + transformation = mesh_translation; + + LLMatrix4 mesh_scale; + mesh_scale.initScale(mesh_scale_vector); + mesh_scale *= transformation; + transformation = mesh_scale; + + cur_instance.mTransform = transformation; + + new_scene[transformation].push_back(cur_instance); + stretch_extents(cur_instance.mModel, transformation, min, max, first_transform); + + if (!last_model) + { + cur_instance = LLModelInstance(new LLModel(volume_params, 0.f), identity, empty_material); + cur_instance.mModel->setNumVolumeFaces(0); + } + } + } + } + + mScene[mPreviewLOD] = new_scene; + mModel[mPreviewLOD] = new_model; + mVertexBuffer[mPreviewLOD].clear(); + + if (mPreviewLOD == LLModel::LOD_HIGH) + { + mBaseScene = new_scene; + mBaseModel = new_model; + clearGLODGroup(); + mVertexBuffer[5].clear(); + } + + mPreviewTarget = (min+max)*0.5f; + mPreviewScale = (max-min)*0.5f; + setPreviewTarget(mPreviewScale.magVec()*2.f); + + clearIncompatible(mPreviewLOD); + + mResourceCost = calcResourceCost(); + refresh(); +} + +void LLModelPreview::clearMaterials() +{ + for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) + { //for each transform in current scene + for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) + { //for each instance with that transform + LLModelInstance& source_instance = *model_iter; + LLModel* source = source_instance.mModel; + + for (S32 i = 0; i < source->getNumVolumeFaces(); ++i) + { //for each face in instance + LLImportMaterial& source_material = source_instance.mMaterial[i]; + + //clear material info + source_material.mDiffuseColor = LLColor4(1,1,1,1); + source_material.mDiffuseMap = NULL; + source_material.mDiffuseMapFilename.clear(); + source_material.mDiffuseMapLabel.clear(); + source_material.mFullbright = false; + } + } + } + + mVertexBuffer[mPreviewLOD].clear(); + + if (mPreviewLOD == LLModel::LOD_HIGH) + { + mBaseScene = mScene[mPreviewLOD]; + mBaseModel = mModel[mPreviewLOD]; + clearGLODGroup(); + mVertexBuffer[5].clear(); + } + + mResourceCost = calcResourceCost(); + refresh(); +} + +bool LLModelPreview::containsRiggedAsset( void ) +{ + //loop through the models and determine if any of them contained a rigged asset, and if so + //return true. + //This is used to cleanup the joint positions after a preview. + for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) + { + LLModel* pModel = *iter; + if ( pModel->mAlternateBindMatrix.size() > 0 ) + { + return true; + } + } + return false; +} +void LLModelPreview::genLODs(S32 which_lod, U32 decimation) +{ + if (mBaseModel.empty()) + { + return; + } + + if (which_lod == LLModel::LOD_PHYSICS) + { //clear physics mesh map + mPhysicsMesh.clear(); + } + + LLVertexBuffer::unbind(); + + stop_gloderror(); + static U32 cur_name = 1; + + S32 limit = -1; + + U32 triangle_count = 0; + + for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) + { + LLModel* mdl = *iter; + for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) + { + triangle_count += mdl->getVolumeFace(i).mNumIndices/3; + } + } + + U32 base_triangle_count = triangle_count; + + U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; + + U32 lod_mode = 0; + + LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode"); + if (iface) + { + lod_mode = iface->getFirstSelectedIndex(); + } + + F32 lod_error_threshold = mFMP->childGetValue("lod_error_threshold").asReal(); + + if (lod_mode == 0) + { + lod_mode = GLOD_TRIANGLE_BUDGET; + if (which_lod != -1) + { + //SH-632 take budget as supplied limit+1 to prevent GLOD from creating a smaller + //decimation when the given decimation is possible + limit = mFMP->childGetValue("lod_triangle_limit").asInteger(); //+1; + } + } + else + { + lod_mode = GLOD_ERROR_THRESHOLD; + } + + U32 build_operator = 0; + + iface = mFMP->childGetSelectionInterface("build_operator"); + if (iface) + { + build_operator = iface->getFirstSelectedIndex(); + } + + if (build_operator == 0) + { + build_operator = GLOD_OPERATOR_EDGE_COLLAPSE; + } + else + { + build_operator = GLOD_OPERATOR_HALF_EDGE_COLLAPSE; + } + + U32 queue_mode=0; + iface = mFMP->childGetSelectionInterface("queue_mode"); + if (iface) + { + queue_mode = iface->getFirstSelectedIndex(); + } + + if (queue_mode == 0) + { + queue_mode = GLOD_QUEUE_GREEDY; + } + else if (queue_mode == 1) + { + queue_mode = GLOD_QUEUE_LAZY; + } + else + { + queue_mode = GLOD_QUEUE_INDEPENDENT; + } + + U32 border_mode = 0; + + iface = mFMP->childGetSelectionInterface("border_mode"); + if (iface) + { + border_mode = iface->getFirstSelectedIndex(); + } + + if (border_mode == 0) + { + border_mode = GLOD_BORDER_UNLOCK; + } + else + { + border_mode = GLOD_BORDER_LOCK; + } + + bool object_dirty = false; + if (border_mode != mBuildBorderMode) + { + mBuildBorderMode = border_mode; + object_dirty = true; + } + + if (queue_mode != mBuildQueueMode) + { + mBuildQueueMode = queue_mode; + object_dirty = true; + } + + if (build_operator != mBuildOperator) + { + mBuildOperator = build_operator; + object_dirty = true; + } + + F32 share_tolerance = mFMP->childGetValue("share_tolerance").asReal(); + if (share_tolerance != mBuildShareTolerance) + { + mBuildShareTolerance = share_tolerance; + object_dirty = true; + } + + if (mGroup == 0) + { + object_dirty = true; + mGroup = cur_name++; + glodNewGroup(mGroup); + } + + if (object_dirty) + { + for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) + { //build GLOD objects for each model in base model list + LLModel* mdl = *iter; + + if (mObject[mdl] != 0) + { + glodDeleteObject(mObject[mdl]); + } + + mObject[mdl] = cur_name++; + + glodNewObject(mObject[mdl], mGroup, GLOD_DISCRETE); + stop_gloderror(); + + if (iter == mBaseModel.begin() && !mdl->mSkinWeights.empty()) + { //regenerate vertex buffer for skinned models to prevent animation feedback during LOD generation + mVertexBuffer[5].clear(); + } + + if (mVertexBuffer[5].empty()) + { + genBuffers(5, false); + } + + U32 tri_count = 0; + for (U32 i = 0; i < mVertexBuffer[5][mdl].size(); ++i) + { + mVertexBuffer[5][mdl][i]->setBuffer(type_mask); + U32 num_indices = mVertexBuffer[5][mdl][i]->getNumIndices(); + if (num_indices > 2) + { + glodInsertElements(mObject[mdl], i, GL_TRIANGLES, num_indices, GL_UNSIGNED_SHORT, mVertexBuffer[5][mdl][i]->getIndicesPointer(), 0, 0.f); + } + tri_count += num_indices/3; + stop_gloderror(); + } + + glodObjectParameteri(mObject[mdl], GLOD_BUILD_OPERATOR, build_operator); + stop_gloderror(); + + glodObjectParameteri(mObject[mdl], GLOD_BUILD_QUEUE_MODE, queue_mode); + stop_gloderror(); + + glodObjectParameteri(mObject[mdl], GLOD_BUILD_BORDER_MODE, border_mode); + stop_gloderror(); + + glodObjectParameterf(mObject[mdl], GLOD_BUILD_SHARE_TOLERANCE, share_tolerance); + stop_gloderror(); + + glodBuildObject(mObject[mdl]); + stop_gloderror(); + } + } + + + S32 start = LLModel::LOD_HIGH; + S32 end = 0; + + if (which_lod != -1) + { + start = end = which_lod; + } + else + { + //SH-632 -- incremenet triangle count to avoid removing any triangles from + //highest LoD when auto-generating LoD + triangle_count++; + } + + + mMaxTriangleLimit = base_triangle_count; + + for (S32 lod = start; lod >= end; --lod) + { + if (which_lod == -1) + { + if (lod < start) + { + triangle_count /= decimation; + } + } + else + { + triangle_count = limit; + } + + mModel[lod].clear(); + mModel[lod].resize(mBaseModel.size()); + mVertexBuffer[lod].clear(); + + U32 actual_tris = 0; + U32 actual_verts = 0; + U32 submeshes = 0; + + glodGroupParameteri(mGroup, GLOD_ADAPT_MODE, lod_mode); + stop_gloderror(); + + glodGroupParameteri(mGroup, GLOD_ERROR_MODE, GLOD_OBJECT_SPACE_ERROR); + stop_gloderror(); + + glodGroupParameteri(mGroup, GLOD_MAX_TRIANGLES, triangle_count); + stop_gloderror(); + + glodGroupParameterf(mGroup, GLOD_OBJECT_SPACE_ERROR_THRESHOLD, lod_error_threshold); + stop_gloderror(); + + glodAdaptGroup(mGroup); + stop_gloderror(); + + for (U32 mdl_idx = 0; mdl_idx < mBaseModel.size(); ++mdl_idx) + { + LLModel* base = mBaseModel[mdl_idx]; + + GLint patch_count = 0; + glodGetObjectParameteriv(mObject[base], GLOD_NUM_PATCHES, &patch_count); + stop_gloderror(); + + LLVolumeParams volume_params; + volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); + mModel[lod][mdl_idx] = new LLModel(volume_params, 0.f); + + GLint* sizes = new GLint[patch_count*2]; + glodGetObjectParameteriv(mObject[base], GLOD_PATCH_SIZES, sizes); + stop_gloderror(); + + GLint* names = new GLint[patch_count]; + glodGetObjectParameteriv(mObject[base], GLOD_PATCH_NAMES, names); + stop_gloderror(); + + mModel[lod][mdl_idx]->setNumVolumeFaces(patch_count); + + LLModel* target_model = mModel[lod][mdl_idx]; + + for (GLint i = 0; i < patch_count; ++i) + { + LLPointer buff = new LLVertexBuffer(type_mask, 0); + + if (sizes[i*2+1] > 0 && sizes[i*2] > 0) + { + buff->allocateBuffer(sizes[i*2+1], sizes[i*2], true); + buff->setBuffer(type_mask); + glodFillElements(mObject[base], names[i], GL_UNSIGNED_SHORT, buff->getIndicesPointer()); + stop_gloderror(); + } + else + { //this face was eliminated, create a dummy triangle (one vertex, 3 indices, all 0) + buff->allocateBuffer(1, 3, true); + memset(buff->getMappedData(), 0, buff->getSize()); + memset(buff->getIndicesPointer(), 0, buff->getIndicesSize()); + } + + buff->validateRange(0, buff->getNumVerts()-1, buff->getNumIndices(), 0); + + LLStrider pos; + LLStrider norm; + LLStrider tc; + LLStrider index; + + buff->getVertexStrider(pos); + buff->getNormalStrider(norm); + buff->getTexCoord0Strider(tc); + buff->getIndexStrider(index); + + target_model->setVolumeFaceData(names[i], pos, norm, tc, index, buff->getNumVerts(), buff->getNumIndices()); + actual_tris += buff->getNumIndices()/3; + actual_verts += buff->getNumVerts(); + ++submeshes; + + if (!validate_face(target_model->getVolumeFace(names[i]))) + { + llerrs << "Invalid face generated during LOD generation." << llendl; + } + } + + //blind copy skin weights and just take closest skin weight to point on + //decimated mesh for now (auto-generating LODs with skin weights is still a bit + //of an open problem). + target_model->mPosition = base->mPosition; + target_model->mSkinWeights = base->mSkinWeights; + target_model->mJointMap = base->mJointMap; + target_model->mJointList = base->mJointList; + target_model->mInvBindMatrix = base->mInvBindMatrix; + target_model->mBindShapeMatrix = base->mBindShapeMatrix; + target_model->mAlternateBindMatrix = base->mAlternateBindMatrix; + //copy material list + target_model->mMaterialList = base->mMaterialList; + + if (!validate_model(target_model)) + { + llerrs << "Invalid model generated when creating LODs" << llendl; + } + + delete [] sizes; + delete [] names; + } + + //rebuild scene based on mBaseScene + mScene[lod].clear(); + mScene[lod] = mBaseScene; + + for (U32 i = 0; i < mBaseModel.size(); ++i) + { + LLModel* mdl = mBaseModel[i]; + LLModel* target = mModel[lod][i]; + if (target) + { + for (LLModelLoader::scene::iterator iter = mScene[lod].begin(); iter != mScene[lod].end(); ++iter) + { + for (U32 j = 0; j < iter->second.size(); ++j) + { + if (iter->second[j].mModel == mdl) + { + iter->second[j].mModel = target; + } + } + } + } + } + } + + mResourceCost = calcResourceCost(); + + /*if (which_lod == -1 && mScene[LLModel::LOD_PHYSICS].empty()) + { //build physics scene + mScene[LLModel::LOD_PHYSICS] = mScene[LLModel::LOD_LOW]; + mModel[LLModel::LOD_PHYSICS] = mModel[LLModel::LOD_LOW]; + + for (U32 i = 1; i < mModel[LLModel::LOD_PHYSICS].size(); ++i) + { + mPhysicsQ.push(mModel[LLModel::LOD_PHYSICS][i]); + } + }*/ +} + +void LLModelPreview::updateStatusMessages() +{ + assert_main_thread(); + + //triangle/vertex/submesh count for each mesh asset for each lod + std::vector tris[LLModel::NUM_LODS]; + std::vector verts[LLModel::NUM_LODS]; + std::vector submeshes[LLModel::NUM_LODS]; + + //total triangle/vertex/submesh count for each lod + S32 total_tris[LLModel::NUM_LODS]; + S32 total_verts[LLModel::NUM_LODS]; + S32 total_submeshes[LLModel::NUM_LODS]; + + for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) + { + //initialize total for this lod to 0 + total_tris[lod] = total_verts[lod] = total_submeshes[lod] = 0; + + for (U32 i = 0; i < mModel[lod].size(); ++i) + { //for each model in the lod + S32 cur_tris = 0; + S32 cur_verts = 0; + S32 cur_submeshes = mModel[lod][i]->getNumVolumeFaces(); + + for (S32 j = 0; j < cur_submeshes; ++j) + { //for each submesh (face), add triangles and vertices to current total + const LLVolumeFace& face = mModel[lod][i]->getVolumeFace(j); + cur_tris += face.mNumIndices/3; + cur_verts += face.mNumVertices; + } + + //add this model to the lod total + total_tris[lod] += cur_tris; + total_verts[lod] += cur_verts; + total_submeshes[lod] += cur_submeshes; + + //store this model's counts to asset data + tris[lod].push_back(cur_tris); + verts[lod].push_back(cur_verts); + submeshes[lod].push_back(cur_submeshes); + } + } + + if (mMaxTriangleLimit == 0) + { + mMaxTriangleLimit = total_tris[LLModel::LOD_HIGH]; + } + + + mFMP->childSetTextArg("submeshes_info", "[SUBMESHES]", llformat("%d", total_submeshes[LLModel::LOD_HIGH])); + + std::string mesh_status_na = mFMP->getString("mesh_status_na"); + + S32 upload_status[LLModel::LOD_HIGH+1]; + + bool upload_ok = true; + + for (S32 lod = 0; lod <= LLModel::LOD_HIGH; ++lod) + { + upload_status[lod] = 0; + + std::string message = "mesh_status_good"; + + if (total_tris[lod] > 0) + { + mFMP->childSetText(lod_triangles_name[lod], llformat("%d", total_tris[lod])); + mFMP->childSetText(lod_vertices_name[lod], llformat("%d", total_verts[lod])); + } + else + { + if (lod == LLModel::LOD_HIGH) + { + upload_status[lod] = 2; + message = "mesh_status_missing_lod"; + } + else + { + for (S32 i = lod-1; i >= 0; --i) + { + if (total_tris[i] > 0) + { + upload_status[lod] = 2; + message = "mesh_status_missing_lod"; + } + } + } + + mFMP->childSetText(lod_triangles_name[lod], mesh_status_na); + mFMP->childSetText(lod_vertices_name[lod], mesh_status_na); + } + + const U32 lod_high = LLModel::LOD_HIGH; + + if (lod != lod_high) + { + if (total_submeshes[lod] && total_submeshes[lod] != total_submeshes[lod_high]) + { //number of submeshes is different + message = "mesh_status_submesh_mismatch"; + upload_status[lod] = 2; + } + else if (!tris[lod].empty() && tris[lod].size() != tris[lod_high].size()) + { //number of meshes is different + message = "mesh_status_mesh_mismatch"; + upload_status[lod] = 2; + } + else if (!verts[lod].empty()) + { + for (U32 i = 0; i < verts[lod].size(); ++i) + { + S32 max_verts = i < verts[lod+1].size() ? verts[lod+1][i] : 0; + + if (max_verts > 0) + { + if (verts[lod][i] > max_verts) + { //too many vertices in this lod + message = "mesh_status_too_many_vertices"; + upload_status[lod] = 2; + } + } + } + } + } + + LLIconCtrl* icon = mFMP->getChild(lod_icon_name[lod]); + LLUIImagePtr img = LLUI::getUIImage(lod_status_image[upload_status[lod]]); + icon->setVisible(true); + icon->setImage(img); + + if (upload_status[lod] >= 2) + { + upload_ok = false; + } + + if (lod == mPreviewLOD) + { + mFMP->childSetText("lod_status_message_text", mFMP->getString(message)); + icon = mFMP->getChild("lod_status_message_icon"); + icon->setImage(img); + } + } + + bool errorStateFromLoader = mModelLoader->getLoadState() == LLModelLoader::ERROR_PARSING ? true : false; + + if ( upload_ok && !errorStateFromLoader ) + { + mFMP->childEnable("ok_btn"); + } + else + { + mFMP->childDisable("ok_btn"); + } + + //add up physics triangles etc + S32 start = 0; + S32 end = mModel[LLModel::LOD_PHYSICS].size(); + + S32 phys_tris = 0; + S32 phys_hulls = 0; + S32 phys_points = 0; + + for (S32 i = start; i < end; ++i) + { //add up hulls and points and triangles for selected mesh(es) + LLModel* model = mModel[LLModel::LOD_PHYSICS][i]; + S32 cur_submeshes = model->getNumVolumeFaces(); + + LLModel::convex_hull_decomposition& decomp = model->mConvexHullDecomp; + + if (!decomp.empty()) + { + phys_hulls += decomp.size(); + for (U32 i = 0; i < decomp.size(); ++i) + { + phys_points += decomp[i].size(); + } + } + else + { //choose physics shape OR decomposition, can't use both + for (S32 j = 0; j < cur_submeshes; ++j) + { //for each submesh (face), add triangles and vertices to current total + const LLVolumeFace& face = model->getVolumeFace(j); + phys_tris += face.mNumIndices/3; + } + } + } + + if (phys_tris > 0) + { + mFMP->childSetTextArg("physics_triangles", "[TRIANGLES]", llformat("%d", phys_tris)); + } + else + { + mFMP->childSetTextArg("physics_triangles", "[TRIANGLES]", mesh_status_na); + } + + if (phys_hulls > 0) + { + mFMP->childSetTextArg("physics_hulls", "[HULLS]", llformat("%d", phys_hulls)); + mFMP->childSetTextArg("physics_points", "[POINTS]", llformat("%d", phys_points)); + } + else + { + mFMP->childSetTextArg("physics_hulls", "[HULLS]", mesh_status_na); + mFMP->childSetTextArg("physics_points", "[POINTS]", mesh_status_na); + } + + LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; + if (fmp) + { + if (phys_tris > 0 || phys_hulls > 0) + { + if (!fmp->isViewOptionEnabled("show_physics")) + { + fmp->enableViewOption("show_physics"); + mViewOption["show_physics"] = true; + } + } + else + { + fmp->disableViewOption("show_physics"); + mViewOption["show_physics"] = false; + + } + + //bool use_hull = fmp->childGetValue("physics_use_hull").asBoolean(); + + //fmp->childSetEnabled("physics_optimize", !use_hull); + + bool enable = phys_tris > 0 || phys_hulls > 0; + //enable = enable && !use_hull && fmp->childGetValue("physics_optimize").asBoolean(); + + //enable/disable "analysis" UI + LLPanel* panel = fmp->getChild("physics analysis"); + LLView* child = panel->getFirstChild(); + while (child) + { + child->setEnabled(enable); + child = panel->findNextSibling(child); + } + + enable = phys_hulls > 0; + //enable/disable "simplification" UI + panel = fmp->getChild("physics simplification"); + child = panel->getFirstChild(); + while (child) + { + child->setEnabled(enable); + child = panel->findNextSibling(child); + } + } + + const char* lod_controls[] = + { + "lod_mode", + "lod_triangle_limit", + "lod_error_tolerance", + "build_operator_text", + "queue_mode_text", + "border_mode_text", + "share_tolerance_text", + "build_operator", + "queue_mode", + "border_mode", + "share_tolerance" + }; + const U32 num_lod_controls = sizeof(lod_controls)/sizeof(char*); + + const char* file_controls[] = + { + "lod_browse", + "lod_file" + }; + const U32 num_file_controls = sizeof(file_controls)/sizeof(char*); + + if (fmp) + { + //enable/disable controls based on radio groups + if (mFMP->childGetValue("lod_from_file").asBoolean()) + { + fmp->mLODMode[mPreviewLOD] = 0; + for (U32 i = 0; i < num_file_controls; ++i) + { + mFMP->childEnable(file_controls[i]); + } + + for (U32 i = 0; i < num_lod_controls; ++i) + { + mFMP->childDisable(lod_controls[i]); + } + } + else if (mFMP->childGetValue("lod_none").asBoolean()) + { + fmp->mLODMode[mPreviewLOD] = 2; + for (U32 i = 0; i < num_file_controls; ++i) + { + mFMP->childDisable(file_controls[i]); + } + + for (U32 i = 0; i < num_lod_controls; ++i) + { + mFMP->childDisable(lod_controls[i]); + } + + if (!mModel[mPreviewLOD].empty()) + { + mModel[mPreviewLOD].clear(); + mScene[mPreviewLOD].clear(); + mVertexBuffer[mPreviewLOD].clear(); + + //this can cause phasing issues with the UI, so reenter this function and return + updateStatusMessages(); + return; + } + } + else + { // auto generate, also the default case for wizard which has no radio selection + fmp->mLODMode[mPreviewLOD] = 1; + + for (U32 i = 0; i < num_file_controls; ++i) + { + mFMP->childDisable(file_controls[i]); + } + + for (U32 i = 0; i < num_lod_controls; ++i) + { + mFMP->childEnable(lod_controls[i]); + } + + //if (threshold) + { + U32 lod_mode = 0; + LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode"); + if (iface) + { + lod_mode = iface->getFirstSelectedIndex(); + } + + LLSpinCtrl* threshold = mFMP->getChild("lod_error_threshold"); + LLSpinCtrl* limit = mFMP->getChild("lod_triangle_limit"); + + limit->setMaxValue(mMaxTriangleLimit); + limit->setValue(total_tris[mPreviewLOD]); + + if (lod_mode == 0) + { + limit->setVisible(true); + threshold->setVisible(false); + + limit->setMaxValue(mMaxTriangleLimit); + } + else + { + limit->setVisible(false); + threshold->setVisible(true); + } + } + } + } + + if (mFMP->childGetValue("physics_load_from_file").asBoolean()) + { + mFMP->childDisable("physics_lod_combo"); + mFMP->childEnable("physics_file"); + mFMP->childEnable("physics_browse"); + } + else + { + mFMP->childEnable("physics_lod_combo"); + mFMP->childDisable("physics_file"); + mFMP->childDisable("physics_browse"); + } +} + +void LLModelPreview::setPreviewTarget(F32 distance) +{ + mCameraDistance = distance; + mCameraZoom = 1.f; + mCameraPitch = 0.f; + mCameraYaw = 0.f; + mCameraOffset.clearVec(); +} + +void LLModelPreview::clearBuffers() +{ + for (U32 i = 0; i < 6; i++) + { + mVertexBuffer[i].clear(); + } +} + +void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights) +{ + U32 tri_count = 0; + U32 vertex_count = 0; + U32 mesh_count = 0; + + LLModelLoader::model_list* model = NULL; + + if (lod < 0 || lod > 4) + { + model = &mBaseModel; + lod = 5; + } + else + { + model = &(mModel[lod]); + } + + if (!mVertexBuffer[lod].empty()) + { + mVertexBuffer[lod].clear(); + } + + mVertexBuffer[lod].clear(); + + LLModelLoader::model_list::iterator base_iter = mBaseModel.begin(); + + for (LLModelLoader::model_list::iterator iter = model->begin(); iter != model->end(); ++iter) + { + LLModel* mdl = *iter; + if (!mdl) + { + continue; + } + + LLModel* base_mdl = *base_iter; + base_iter++; + + for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) + { + const LLVolumeFace &vf = mdl->getVolumeFace(i); + U32 num_vertices = vf.mNumVertices; + U32 num_indices = vf.mNumIndices; + + if (!num_vertices || ! num_indices) + { + continue; + } + + LLVertexBuffer* vb = NULL; + + bool skinned = include_skin_weights && !mdl->mSkinWeights.empty(); + + U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; + + if (skinned) + { + mask |= LLVertexBuffer::MAP_WEIGHT4; + } + + vb = new LLVertexBuffer(mask, 0); + + vb->allocateBuffer(num_vertices, num_indices, TRUE); + + LLStrider vertex_strider; + LLStrider normal_strider; + LLStrider tc_strider; + LLStrider index_strider; + LLStrider weights_strider; + + vb->getVertexStrider(vertex_strider); + vb->getNormalStrider(normal_strider); + vb->getTexCoord0Strider(tc_strider); + vb->getIndexStrider(index_strider); + + if (skinned) + { + vb->getWeight4Strider(weights_strider); + } + + LLVector4a::memcpyNonAliased16((F32*) vertex_strider.get(), (F32*) vf.mPositions, num_vertices*4*sizeof(F32)); + LLVector4a::memcpyNonAliased16((F32*) tc_strider.get(), (F32*) vf.mTexCoords, num_vertices*2*sizeof(F32)); + LLVector4a::memcpyNonAliased16((F32*) normal_strider.get(), (F32*) vf.mNormals, num_vertices*4*sizeof(F32)); + + if (skinned) + { + for (U32 i = 0; i < num_vertices; i++) + { + //find closest weight to vf.mVertices[i].mPosition + LLVector3 pos(vf.mPositions[i].getF32ptr()); + + const LLModel::weight_list& weight_list = base_mdl->getJointInfluences(pos); + + LLVector4 w(0,0,0,0); + if (weight_list.size() > 4) + { + llerrs << "WTF?" << llendl; + } + + for (U32 i = 0; i < weight_list.size(); ++i) + { + F32 wght = llmin(weight_list[i].mWeight, 0.999999f); + F32 joint = (F32) weight_list[i].mJointIdx; + w.mV[i] = joint + wght; + } + + *(weights_strider++) = w; + } + } + + // build indices + for (U32 i = 0; i < num_indices; i++) + { + *(index_strider++) = vf.mIndices[i]; + } + + mVertexBuffer[lod][mdl].push_back(vb); + + vertex_count += num_vertices; + tri_count += num_indices/3; + ++mesh_count; + + } + } +} + +void LLModelPreview::update() +{ + if (mDirty) + { + mDirty = false; + mResourceCost = calcResourceCost(); + refresh(); + updateStatusMessages(); + } + + if (mGenLOD) + { + mGenLOD = false; + genLODs(); + refresh(); + updateStatusMessages(); + } + +} + +//----------------------------------------------------------------------------- +// render() +//----------------------------------------------------------------------------- +BOOL LLModelPreview::render() +{ + assert_main_thread(); + + LLMutexLock lock(this); + mNeedsUpdate = FALSE; + + bool edges = mViewOption["show_edges"]; + bool joint_positions = mViewOption["show_joint_positions"]; + bool skin_weight = mViewOption["show_skin_weight"]; + bool textures = mViewOption["show_textures"]; + bool physics = mViewOption["show_physics"]; + + S32 width = getWidth(); + S32 height = getHeight(); + + LLGLSUIDefault def; + LLGLDisable no_blend(GL_BLEND); + LLGLEnable cull(GL_CULL_FACE); + LLGLDepthTest depth(GL_TRUE); + LLGLDisable fog(GL_FOG); + + { + //clear background to blue + glMatrixMode(GL_PROJECTION); + gGL.pushMatrix(); + glLoadIdentity(); + glOrtho(0.0f, width, 0.0f, height, -1.0f, 1.0f); + + glMatrixMode(GL_MODELVIEW); + gGL.pushMatrix(); + glLoadIdentity(); + + gGL.color4f(0.15f, 0.2f, 0.3f, 1.f); + + gl_rect_2d_simple( width, height ); + + glMatrixMode(GL_PROJECTION); + gGL.popMatrix(); + + glMatrixMode(GL_MODELVIEW); + gGL.popMatrix(); + } + + LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; + + bool has_skin_weights = false; + bool upload_skin = mFMP->childGetValue("upload_skin").asBoolean(); + bool upload_joints = mFMP->childGetValue("upload_joints").asBoolean(); + + for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) + { + for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) + { + LLModelInstance& instance = *model_iter; + LLModel* model = instance.mModel; + if (!model->mSkinWeights.empty()) + { + has_skin_weights = true; + } + } + } + + if (has_skin_weights) + { //model has skin weights, enable view options for skin weights and joint positions + if (fmp) + { + fmp->enableViewOption("show_skin_weight"); + fmp->setViewOptionEnabled("show_joint_positions", skin_weight); + } + mFMP->childEnable("upload_skin"); + } + else + { + mFMP->childDisable("upload_skin"); + if (fmp) + { + mViewOption["show_skin_weight"] = false; + fmp->disableViewOption("show_skin_weight"); + fmp->disableViewOption("show_joint_positions"); + } + skin_weight = false; + } + + if (upload_skin && !has_skin_weights) + { //can't upload skin weights if model has no skin weights + mFMP->childSetValue("upload_skin", false); + upload_skin = false; + } + + if (!upload_skin && upload_joints) + { //can't upload joints if not uploading skin weights + mFMP->childSetValue("upload_joints", false); + upload_joints = false; + } + + mFMP->childSetEnabled("upload_joints", upload_skin); + + F32 explode = mFMP->childGetValue("physics_explode").asReal(); + + glClear(GL_DEPTH_BUFFER_BIT); + + LLRect preview_rect = mFMP->getChildView("preview_panel")->getRect(); + F32 aspect = (F32) preview_rect.getWidth()/preview_rect.getHeight(); + + LLViewerCamera::getInstance()->setAspect(aspect); + + LLViewerCamera::getInstance()->setView(LLViewerCamera::getInstance()->getDefaultFOV() / mCameraZoom); + + LLVector3 offset = mCameraOffset; + LLVector3 target_pos = mPreviewTarget+offset; + + F32 z_near = 0.001f; + F32 z_far = mCameraDistance+mPreviewScale.magVec()+mCameraOffset.magVec(); + + if (skin_weight) + { + target_pos = gAgentAvatarp->getPositionAgent(); + z_near = 0.01f; + z_far = 1024.f; + mCameraDistance = 16.f; + + //render avatar previews every frame + refresh(); + } + + glLoadIdentity(); + gPipeline.enableLightsPreview(); + + LLQuaternion camera_rot = LLQuaternion(mCameraPitch, LLVector3::y_axis) * + LLQuaternion(mCameraYaw, LLVector3::z_axis); + + LLQuaternion av_rot = camera_rot; + LLViewerCamera::getInstance()->setOriginAndLookAt( + target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + offset) * av_rot), // camera + LLVector3::z_axis, // up + target_pos); // point of interest + + + LLViewerCamera::getInstance()->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, width, height, FALSE, z_near, z_far); + + stop_glerror(); + + gGL.pushMatrix(); + const F32 BRIGHTNESS = 0.9f; + gGL.color3f(BRIGHTNESS, BRIGHTNESS, BRIGHTNESS); + + LLGLEnable normalize(GL_NORMALIZE); + + if (!mBaseModel.empty() && mVertexBuffer[5].empty()) + { + genBuffers(-1, skin_weight); + //genBuffers(3); + //genLODs(); + } + + if (!mModel[mPreviewLOD].empty()) + { + bool regen = mVertexBuffer[mPreviewLOD].empty(); + if (!regen) + { + const std::vector >& vb_vec = mVertexBuffer[mPreviewLOD].begin()->second; + if (!vb_vec.empty()) + { + const LLVertexBuffer* buff = vb_vec[0]; + regen = buff->hasDataType(LLVertexBuffer::TYPE_WEIGHT4) != skin_weight; + } + } + + if (regen) + { + genBuffers(mPreviewLOD, skin_weight); + } + + if (!skin_weight) + { + for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) + { + LLModelInstance& instance = *iter; + + LLModel* model = instance.mLOD[mPreviewLOD]; + + if (!model) + { + continue; + } + + gGL.pushMatrix(); + LLMatrix4 mat = instance.mTransform; + + glMultMatrixf((GLfloat*) mat.mMatrix); + + for (U32 i = 0; i < mVertexBuffer[mPreviewLOD][model].size(); ++i) + { + LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; + + buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); + + if (textures) + { + glColor4fv(instance.mMaterial[i].mDiffuseColor.mV); + if (i < instance.mMaterial.size() && instance.mMaterial[i].mDiffuseMap.notNull()) + { + gGL.getTexUnit(0)->bind(instance.mMaterial[i].mDiffuseMap, true); + if (instance.mMaterial[i].mDiffuseMap->getDiscardLevel() > -1) + { + mTextureSet.insert(instance.mMaterial[i].mDiffuseMap.get()); + } + } + } + else + { + glColor4f(1,1,1,1); + } + + buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + glColor3f(0.4f, 0.4f, 0.4f); + + if (edges) + { + glLineWidth(3.f); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glLineWidth(1.f); + } + } + gGL.popMatrix(); + } + + if (physics) + { + glClear(GL_DEPTH_BUFFER_BIT); + LLGLEnable blend(GL_BLEND); + gGL.blendFunc(LLRender::BF_ONE, LLRender::BF_ZERO); + + for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) + { + LLModelInstance& instance = *iter; + + LLModel* model = instance.mLOD[LLModel::LOD_PHYSICS]; + + if (!model) + { + continue; + } + + gGL.pushMatrix(); + LLMatrix4 mat = instance.mTransform; + + glMultMatrixf((GLfloat*) mat.mMatrix); + + + bool render_mesh = true; + + LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread; + if (decomp) + { + LLMutexLock(decomp->mMutex); + + std::map, std::vector > >::iterator iter = + mPhysicsMesh.find(model); + if (iter != mPhysicsMesh.end()) + { //render hull instead of mesh + render_mesh = false; + for (U32 i = 0; i < iter->second.size(); ++i) + { + if (explode > 0.f) + { + gGL.pushMatrix(); + + LLVector3 offset = model->mHullCenter[i]-model->mCenterOfHullCenters; + offset *= explode; + + gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]); + } + + static std::vector hull_colors; + + if (i+1 >= hull_colors.size()) + { + hull_colors.push_back(LLColor4U(rand()%128+127, rand()%128+127, rand()%128+127, 255)); + } + + LLVertexBuffer* buff = iter->second[i]; + if (buff) + { + buff->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL); + + glColor4ubv(hull_colors[i].mV); + buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts()); + } + + if (explode > 0.f) + { + gGL.popMatrix(); + } + } + } + } + + if (render_mesh) + { + if (mVertexBuffer[LLModel::LOD_PHYSICS].empty()) + { + genBuffers(LLModel::LOD_PHYSICS, false); + } + for (U32 i = 0; i < mVertexBuffer[LLModel::LOD_PHYSICS][model].size(); ++i) + { + LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][i]; + + buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); + + buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + glColor4f(0.4f, 0.4f, 0.0f, 0.4f); + + buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); + + glColor3f(1.f, 1.f, 0.f); + + glLineWidth(3.f); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glLineWidth(1.f); + } + } + + gGL.popMatrix(); + } + + gGL.setSceneBlendType(LLRender::BT_ALPHA); + } + } + else + { + LLVOAvatarSelf* avatar = gAgentAvatarp; + target_pos = avatar->getPositionAgent(); + + LLViewerCamera::getInstance()->setOriginAndLookAt( + target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + offset) * av_rot), // camera + LLVector3::z_axis, // up + target_pos); // point of interest + + if (joint_positions) + { + avatar->renderCollisionVolumes(); + } + + for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) + { + for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) + { + LLModelInstance& instance = *model_iter; + LLModel* model = instance.mModel; + + if (!model->mSkinWeights.empty()) + { + for (U32 i = 0; i < mVertexBuffer[mPreviewLOD][model].size(); ++i) + { + LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; + + const LLVolumeFace& face = model->getVolumeFace(i); + + LLStrider position; + buffer->getVertexStrider(position); + + LLStrider weight; + buffer->getWeight4Strider(weight); + + //quick 'n dirty software vertex skinning + + //build matrix palette + LLMatrix4 mat[64]; + for (U32 j = 0; j < model->mJointList.size(); ++j) + { + LLJoint* joint = avatar->getJoint(model->mJointList[j]); + if (joint) + { + mat[j] = model->mInvBindMatrix[j]; + mat[j] *= joint->getWorldMatrix(); + } + } + + for (U32 j = 0; j < buffer->getRequestedVerts(); ++j) + { + LLMatrix4 final_mat; + final_mat.mMatrix[0][0] = final_mat.mMatrix[1][1] = final_mat.mMatrix[2][2] = final_mat.mMatrix[3][3] = 0.f; + + LLVector4 wght; + S32 idx[4]; + + F32 scale = 0.f; + for (U32 k = 0; k < 4; k++) + { + F32 w = weight[j].mV[k]; + + idx[k] = (S32) floorf(w); + wght.mV[k] = w - floorf(w); + scale += wght.mV[k]; + } + + wght *= 1.f/scale; + + for (U32 k = 0; k < 4; k++) + { + F32* src = (F32*) mat[idx[k]].mMatrix; + F32* dst = (F32*) final_mat.mMatrix; + + F32 w = wght.mV[k]; + + for (U32 l = 0; l < 16; l++) + { + dst[l] += src[l]*w; + } + } + + //VECTORIZE THIS + LLVector3 v(face.mPositions[j].getF32ptr()); + + v = v * model->mBindShapeMatrix; + v = v * final_mat; + + position[j] = v; + } + + buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); + glColor4fv(instance.mMaterial[i].mDiffuseColor.mV); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); + glColor3f(0.4f, 0.4f, 0.4f); + + if (edges) + { + glLineWidth(3.f); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glLineWidth(1.f); + } + } + } + } + } + } + } + + gGL.popMatrix(); + + return TRUE; +} + +//----------------------------------------------------------------------------- +// refresh() +//----------------------------------------------------------------------------- +void LLModelPreview::refresh() +{ + mNeedsUpdate = TRUE; +} + +//----------------------------------------------------------------------------- +// rotate() +//----------------------------------------------------------------------------- +void LLModelPreview::rotate(F32 yaw_radians, F32 pitch_radians) +{ + mCameraYaw = mCameraYaw + yaw_radians; + + mCameraPitch = llclamp(mCameraPitch + pitch_radians, F_PI_BY_TWO * -0.8f, F_PI_BY_TWO * 0.8f); +} + +//----------------------------------------------------------------------------- +// zoom() +//----------------------------------------------------------------------------- +void LLModelPreview::zoom(F32 zoom_amt) +{ + F32 new_zoom = mCameraZoom+zoom_amt; + + mCameraZoom = llclamp(new_zoom, 1.f, 10.f); +} + +void LLModelPreview::pan(F32 right, F32 up) +{ + mCameraOffset.mV[VY] = llclamp(mCameraOffset.mV[VY] + right * mCameraDistance / mCameraZoom, -1.f, 1.f); + mCameraOffset.mV[VZ] = llclamp(mCameraOffset.mV[VZ] + up * mCameraDistance / mCameraZoom, -1.f, 1.f); +} + +void LLModelPreview::setPreviewLOD(S32 lod) +{ + lod = llclamp(lod, 0, (S32) LLModel::LOD_HIGH); + + if (lod != mPreviewLOD) + { + mPreviewLOD = lod; + + LLComboBox* combo_box = mFMP->getChild("preview_lod_combo"); + combo_box->setCurrentByIndex((NUM_LOD-1)-mPreviewLOD); // combo box list of lods is in reverse order + mFMP->childSetTextArg("lod_table_footer", "[DETAIL]", mFMP->getString(lod_name[mPreviewLOD])); + mFMP->childSetText("lod_file", mLODFile[mPreviewLOD]); + + LLColor4 highlight_color = LLUIColorTable::instance().getColor("MeshImportTableHighlightColor"); + LLColor4 normal_color = LLUIColorTable::instance().getColor("MeshImportTableNormalColor"); + + for (S32 i = 0; i <= LLModel::LOD_HIGH; ++i) + { + const LLColor4& color = (i == lod) ? highlight_color : normal_color; + + mFMP->childSetColor(lod_status_name[i], color); + mFMP->childSetColor(lod_label_name[i], color); + mFMP->childSetColor(lod_triangles_name[i], color); + mFMP->childSetColor(lod_vertices_name[i], color); + } + + LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; + if (fmp) + { + LLRadioGroup* radio = fmp->getChild("lod_file_or_limit"); + radio->selectNthItem(fmp->mLODMode[mPreviewLOD]); + } + } + refresh(); + updateStatusMessages(); +} + +//static +void LLFloaterModelPreview::onBrowseLOD(void* data) +{ + assert_main_thread(); + + LLFloaterModelPreview* mp = (LLFloaterModelPreview*) data; + mp->loadModel(mp->mModelPreview->mPreviewLOD); +} + +//static +void LLFloaterModelPreview::onUpload(void* user_data) +{ + assert_main_thread(); + + LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; + + mp->mModelPreview->rebuildUploadData(); + + gMeshRepo.uploadModel(mp->mModelPreview->mUploadData, mp->mModelPreview->mPreviewScale, + mp->childGetValue("upload_textures").asBoolean(), mp->childGetValue("upload_skin"), mp->childGetValue("upload_joints")); + + mp->closeFloater(false); +} + + +//static +void LLFloaterModelPreview::onClearMaterials(void* user_data) +{ + LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; + mp->mModelPreview->clearMaterials(); +} + +//static +void LLFloaterModelPreview::refresh(LLUICtrl* ctrl, void* user_data) +{ + sInstance->mModelPreview->mDirty = true; +} + +void LLFloaterModelPreview::updateResourceCost() +{ + U32 cost = mModelPreview->mResourceCost; + childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d",cost)); +} + +//static +void LLModelPreview::textureLoadedCallback( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata ) +{ + LLModelPreview* preview = (LLModelPreview*) userdata; + preview->refresh(); +} + +LLFloaterModelPreview::DecompRequest::DecompRequest(const std::string& stage, LLModel* mdl) +{ + mStage = stage; + mContinue = 1; + mModel = mdl; + mDecompID = &mdl->mDecompID; + mParams = sInstance->mDecompParams; + + //copy out positions and indices + if (mdl) + { + U16 index_offset = 0; + + mPositions.clear(); + mIndices.clear(); + + //queue up vertex positions and indices + for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) + { + const LLVolumeFace& face = mdl->getVolumeFace(i); + if (mPositions.size() + face.mNumVertices > 65535) + { + continue; + } + + for (U32 j = 0; j < face.mNumVertices; ++j) + { + mPositions.push_back(LLVector3(face.mPositions[j].getF32ptr())); + } + + for (U32 j = 0; j < face.mNumIndices; ++j) + { + mIndices.push_back(face.mIndices[j]+index_offset); + } + + index_offset += face.mNumVertices; + } + } +} + +void LLFloaterModelPreview::setStatusMessage(const std::string& msg) +{ + LLMutexLock lock(mStatusLock); + mStatusMessage = msg; +} + +S32 LLFloaterModelPreview::DecompRequest::statusCallback(const char* status, S32 p1, S32 p2) +{ + setStatusMessage(llformat("%s: %d/%d", status, p1, p2)); + if (LLFloaterModelPreview::sInstance) + { + LLFloaterModelPreview::sInstance->setStatusMessage(mStatusMessage); + } + + return mContinue; +} + +void LLFloaterModelPreview::DecompRequest::completed() +{ //called from the main thread + mModel->setConvexHullDecomposition(mHull); + + if (sInstance) + { + if (mContinue) + { + if (sInstance->mModelPreview) + { + sInstance->mModelPreview->mPhysicsMesh[mModel] = mHullMesh; + sInstance->mModelPreview->mDirty = true; + LLFloaterModelPreview::sInstance->mModelPreview->refresh(); + } + } + + sInstance->mCurRequest.erase(this); + } +} -- cgit v1.2.3 From 5b09da5079d576678eb5d66a5518044d1b22664f Mon Sep 17 00:00:00 2001 From: prep Date: Wed, 5 Jan 2011 16:07:16 -0500 Subject: Fix for SH-579 --- indra/newview/llfloatermodelpreview.cpp | 297 +++++++++++++++++++------------- 1 file changed, 179 insertions(+), 118 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index f15d4def80..c0b5b7cfa6 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -379,7 +379,7 @@ LLFloaterModelPreview::~LLFloaterModelPreview() { sInstance = NULL; - if ( mModelPreview->containsRiggedAsset() ) + if ( mModelPreview->mModelLoader->mResetJoints ) { gAgentAvatarp->resetJointPositions(); } @@ -959,7 +959,7 @@ void LLFloaterModelPreview::onMouseCaptureLostModelPreview(LLMouseHandler* handl // LLModelLoader //----------------------------------------------------------------------------- LLModelLoader::LLModelLoader(std::string filename, S32 lod, LLModelPreview* preview) -: LLThread("Model Loader"), mFilename(filename), mLod(lod), mPreview(preview), mState(STARTING), mFirstTransform(TRUE) +: LLThread("Model Loader"), mFilename(filename), mLod(lod), mPreview(preview), mState(STARTING), mFirstTransform(TRUE), mResetJoints( FALSE ) { mJointMap["mPelvis"] = "mPelvis"; mJointMap["mTorso"] = "mTorso"; @@ -1036,6 +1036,28 @@ LLModelLoader::LLModelLoader(std::string filename, S32 lod, LLModelPreview* prev mJointMap["lThigh"] = "mHipLeft"; mJointMap["lShin"] = "mKneeLeft"; mJointMap["lFoot"] = "mFootLeft"; + + //move into joint mapper class + mMasterJointList.push_front("mPelvis"); + mMasterJointList.push_front("mTorso"); + mMasterJointList.push_front("mChest"); + mMasterJointList.push_front("mNeck"); + mMasterJointList.push_front("mHead"); + mMasterJointList.push_front("mSkull"); + mMasterJointList.push_front("mCollarLeft"); + mMasterJointList.push_front("mShoulderLeft"); + mMasterJointList.push_front("mElbowLeft"); + mMasterJointList.push_front("mWristLeft"); + mMasterJointList.push_front("mCollarRight"); + mMasterJointList.push_front("mShoulderRight"); + mMasterJointList.push_front("mElbowRight"); + mMasterJointList.push_front("mWristRight"); + mMasterJointList.push_front("mHipRight"); + mMasterJointList.push_front("mKneeRight"); + mMasterJointList.push_front("mFootRight"); + mMasterJointList.push_front("mHipLeft"); + mMasterJointList.push_front("mKneeLeft"); + mMasterJointList.push_front("mFootLeft"); } void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, BOOL& first_transform) @@ -1105,32 +1127,32 @@ void LLModelLoader::run() { DAE dae; domCOLLADA* dom = dae.open(mFilename); - + if (dom) { daeDatabase* db = dae.getDatabase(); - + daeInt count = db->getElementCount(NULL, COLLADA_TYPE_MESH); - + daeDocument* doc = dae.getDoc(mFilename); if (!doc) { llwarns << "can't find internal doc" << llendl; return; } - + daeElement* root = doc->getDomRoot(); if (!root) { llwarns << "document has no root" << llendl; return; } - + //get unit scale mTransform.setIdentity(); - + domAsset::domUnit* unit = daeSafeCast(root->getDescendant(daeElement::matchType(domAsset::domUnit::ID()))); - + if (unit) { F32 meter = unit->getMeter(); @@ -1138,19 +1160,19 @@ void LLModelLoader::run() mTransform.mMatrix[1][1] = meter; mTransform.mMatrix[2][2] = meter; } - + //get up axis rotation LLMatrix4 rotation; - + domUpAxisType up = UPAXISTYPE_Y_UP; // default is Y_UP domAsset::domUp_axis* up_axis = daeSafeCast(root->getDescendant(daeElement::matchType(domAsset::domUp_axis::ID()))); - + if (up_axis) { up = up_axis->getValue(); } - + if (up == UPAXISTYPE_X_UP) { rotation.initRotation(0.0f, 90.0f * DEG_TO_RAD, 0.0f); @@ -1159,20 +1181,20 @@ void LLModelLoader::run() { rotation.initRotation(90.0f * DEG_TO_RAD, 0.0f, 0.0f); } - + rotation *= mTransform; mTransform = rotation; - - + + for (daeInt idx = 0; idx < count; ++idx) { //build map of domEntities to LLModel domMesh* mesh = NULL; db->getElement((daeElement**) &mesh, idx, NULL, COLLADA_TYPE_MESH); - + if (mesh) { LLPointer model = LLModel::loadModelFromDomMesh(mesh); - + if (model.notNull() && validate_model(model)) { mModelList.push_back(model); @@ -1180,17 +1202,17 @@ void LLModelLoader::run() } } } - + count = db->getElementCount(NULL, COLLADA_TYPE_SKIN); for (daeInt idx = 0; idx < count; ++idx) { //add skinned meshes as instances domSkin* skin = NULL; db->getElement((daeElement**) &skin, idx, NULL, COLLADA_TYPE_SKIN); - + if (skin) { domGeometry* geom = daeSafeCast(skin->getSource().getElement()); - + if (geom) { domMesh* mesh = geom->getMesh(); @@ -1202,25 +1224,25 @@ void LLModelLoader::run() LLVector3 mesh_scale_vector; LLVector3 mesh_translation_vector; model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); - + LLMatrix4 normalized_transformation; normalized_transformation.setTranslation(mesh_translation_vector); - + LLMatrix4 mesh_scale; mesh_scale.initScale(mesh_scale_vector); mesh_scale *= normalized_transformation; normalized_transformation = mesh_scale; - + glh::matrix4f inv_mat((F32*) normalized_transformation.mMatrix); inv_mat = inv_mat.inverse(); LLMatrix4 inverse_normalized_transformation(inv_mat.m); - + domSkin::domBind_shape_matrix* bind_mat = skin->getBind_shape_matrix(); - + if (bind_mat) { //get bind shape matrix domFloat4x4& dom_value = bind_mat->getValue(); - + for (int i = 0; i < 4; i++) { for(int j = 0; j < 4; j++) @@ -1228,26 +1250,26 @@ void LLModelLoader::run() model->mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j*4]; } } - + LLMatrix4 trans = normalized_transformation; trans *= model->mBindShapeMatrix; model->mBindShapeMatrix = trans; - + } - - + + //The joint transfom map that we'll populate below std::map jointTransforms; jointTransforms.clear(); - + //Some collada setup for accessing the skeleton daeElement* pElement = 0; dae.getDatabase()->getElement( &pElement, 0, 0, "skeleton" ); - + //Try to get at the skeletal instance controller domInstance_controller::domSkeleton* pSkeleton = daeSafeCast( pElement ); bool missingSkeletonOrScene = false; - + //If no skeleton, do a breadth-first search to get at specific joints if ( !pSkeleton ) { @@ -1262,7 +1284,7 @@ void LLModelLoader::run() //Get the children at this level daeTArray< daeSmartRef > children = pScene->getChildren(); S32 childCount = children.getCount(); - + //Process any children that are joints //Not all children are joints, some code be ambient lights, cameras, geometry etc.. for (S32 i = 0; i < childCount; ++i) @@ -1276,7 +1298,7 @@ void LLModelLoader::run() } } else - //Has Skeleton + //Has Skeleton { //Get the root node of the skeleton daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement(); @@ -1285,7 +1307,7 @@ void LLModelLoader::run() //Once we have the root node - start acccessing it's joint components const int jointCnt = mJointMap.size(); std::map :: const_iterator jointIt = mJointMap.begin(); - + //Loop over all the possible joints within the .dae - using the allowed joint list in the ctor. for ( int i=0; i( resolver.getElement() ); if ( pJoint ) @@ -1304,9 +1326,9 @@ void LLModelLoader::run() //Pull out the translate id and store it in the jointTranslations map daeSIDResolver jointResolver( pJoint, "./translate" ); domTranslate* pTranslate = daeSafeCast( jointResolver.getElement() ); - + LLMatrix4 workingTransform; - + //Translation via SID if ( pTranslate ) { @@ -1326,12 +1348,12 @@ void LLModelLoader::run() extractTranslationViaElement( pTranslateElement, workingTransform ); } } - + //Store the joint transform w/respect to it's name. jointTransforms[(*jointIt).second.c_str()] = workingTransform; } } - + //If anything failed in regards to extracting the skeleton, joints or translation id, //mention it if ( missingSkeletonOrScene ) @@ -1340,64 +1362,32 @@ void LLModelLoader::run() } }//got skeleton? } - - if ( !missingSkeletonOrScene ) - { - //Set the joint translations on the avatar - //The joints are reset in the dtor - const int jointCnt = mJointMap.size(); - std::map :: const_iterator jointIt = mJointMap.begin(); - for ( int i=0; igetJoint( lookingForJoint ); - if ( pJoint ) - { - pJoint->storeCurrentXform( jointTransform.getTranslation() ); - } - else - { - //Most likely an error in the asset. - llwarns<<"Tried to apply joint position from .dae, but it did not exist in the avatar rig." << llendl; - } - //Reposition the avatars pelvis (avPos+offset) - //if ( lookingForJoint == "mPelvis" ) - //{ - // const LLVector3& pos = gAgentAvatarp->getCharacterPosition(); - // gAgentAvatarp->setPelvisOffset( true, jointTransform.getTranslation() ); - // gAgentAvatarp->setPosition( pos + jointTransform.getTranslation() ); - //} - } - } - } //missingSkeletonOrScene - + + domSkin::domJoints* joints = skin->getJoints(); - + domInputLocal_Array& joint_input = joints->getInput_array(); - + for (size_t i = 0; i < joint_input.getCount(); ++i) { domInputLocal* input = joint_input.get(i); xsNMTOKEN semantic = input->getSemantic(); - + if (strcmp(semantic, COMMON_PROFILE_INPUT_JOINT) == 0) { //found joint source, fill model->mJointMap and model->mJointList daeElement* elem = input->getSource().getElement(); - + domSource* source = daeSafeCast(elem); if (source) { - - + + domName_array* names_source = source->getName_array(); - + if (names_source) { domListOfNames &names = names_source->getValue(); - + for (size_t j = 0; j < names.getCount(); ++j) { std::string name(names.get(j)); @@ -1415,7 +1405,7 @@ void LLModelLoader::run() if (names_source) { xsIDREFS& names = names_source->getValue(); - + for (size_t j = 0; j < names.getCount(); ++j) { std::string name(names.get(j).getID()); @@ -1440,11 +1430,11 @@ void LLModelLoader::run() { domListOfFloats& transform = t->getValue(); S32 count = transform.getCount()/16; - + for (S32 k = 0; k < count; ++k) { LLMatrix4 mat; - + for (int i = 0; i < 4; i++) { for(int j = 0; j < 4; j++) @@ -1452,14 +1442,55 @@ void LLModelLoader::run() mat.mMatrix[i][j] = transform[k*16 + i + j*4]; } } - + model->mInvBindMatrix.push_back(mat); } } } } } - + + //Now that we've parsed the joint array, let's determine if we have a full rig + //(which means we have all the joints that are required for an avatar versus + //a skinned asset attached to a node in a file that contains an entire skeleton, + //but does not use the skeleton). + + if ( !model->mJointList.empty() && doesJointArrayContainACompleteRig( model->mJointList ) ) + { + mResetJoints = true; + } + + if ( !missingSkeletonOrScene ) + { + //Set the joint translations on the avatar - if it's a full mapping + //The joints are reset in the dtor + if ( mResetJoints ) + { + std::map :: const_iterator masterJointIt = mJointMap.begin(); + std::map :: const_iterator masterJointItEnd = mJointMap.end(); + for (;masterJointIt!=masterJointItEnd;++masterJointIt ) + { + std::string lookingForJoint = (*masterJointIt).first.c_str(); + + if ( jointTransforms.find( lookingForJoint ) != jointTransforms.end() ) + { + //llinfos<<"joint "<getJoint( lookingForJoint ); + if ( pJoint ) + { + pJoint->storeCurrentXform( jointTransform.getTranslation() ); + } + else + { + //Most likely an error in the asset. + llwarns<<"Tried to apply joint position from .dae, but it did not exist in the avatar rig." << llendl; + } + } + } + } + } //missingSkeletonOrScene + //We need to construct the alternate bind matrix (which contains the new joint positions) //in the same order as they were stored in the joint buffer. The joints associated //with the skeleton are not stored in the same order as they are in the exported joint buffer. @@ -1483,9 +1514,9 @@ void LLModelLoader::run() llwarns<<"Possibly misnamed/missing joint [" <getVertices(); if (verts) { @@ -1501,19 +1532,19 @@ void LLModelLoader::run() if (pos_array) { domListOfFloats& pos = pos_array->getValue(); - + for (size_t j = 0; j < pos.getCount(); j += 3) { if (pos.getCount() <= j+2) { llerrs << "WTF?" << llendl; } - + LLVector3 v(pos[j], pos[j+1], pos[j+2]); - + //transform from COLLADA space to volume space v = v * inverse_normalized_transformation; - + model->mPosition.push_back(v); } } @@ -1521,7 +1552,7 @@ void LLModelLoader::run() } } } - + //grab skin weights array domSkin::domVertex_weights* weights = skin->getVertex_weights(); if (weights) @@ -1539,44 +1570,44 @@ void LLModelLoader::run() } } } - + if (vertex_weights) { domListOfFloats& w = vertex_weights->getValue(); domListOfUInts& vcount = weights->getVcount()->getValue(); domListOfInts& v = weights->getV()->getValue(); - + U32 c_idx = 0; for (size_t vc_idx = 0; vc_idx < vcount.getCount(); ++vc_idx) { //for each vertex daeUInt count = vcount[vc_idx]; - + //create list of weights that influence this vertex LLModel::weight_list weight_list; - + for (daeUInt i = 0; i < count; ++i) { //for each weight daeInt joint_idx = v[c_idx++]; daeInt weight_idx = v[c_idx++]; - + if (joint_idx == -1) { //ignore bindings to bind_shape_matrix continue; } - + F32 weight_value = w[weight_idx]; - + weight_list.push_back(LLModel::JointWeight(joint_idx, weight_value)); } - + //sort by joint weight std::sort(weight_list.begin(), weight_list.end(), LLModel::CompareWeightGreater()); - + std::vector wght; - + F32 total = 0.f; - + for (U32 i = 0; i < llmin((U32) 4, (U32) weight_list.size()); ++i) { //take up to 4 most significant weights if (weight_list[i].mWeight > 0.f) @@ -1585,7 +1616,7 @@ void LLModelLoader::run() total += weight_list[i].mWeight; } } - + F32 scale = 1.f/total; if (scale != 1.f) { //normalize weights @@ -1594,12 +1625,12 @@ void LLModelLoader::run() wght[i].mWeight *= scale; } } - + model->mSkinWeights[model->mPosition[vc_idx]] = wght; } - + //add instance to scene for this model - + LLMatrix4 transformation = mTransform; // adjust the transformation to compensate for mesh normalization @@ -1607,12 +1638,12 @@ void LLModelLoader::run() mesh_translation.setTranslation(mesh_translation_vector); mesh_translation *= transformation; transformation = mesh_translation; - + LLMatrix4 mesh_scale; mesh_scale.initScale(mesh_scale_vector); mesh_scale *= transformation; transformation = mesh_scale; - + std::vector materials; materials.resize(model->getNumVolumeFaces()); mScene[transformation].push_back(LLModelInstance(model, transformation, materials)); @@ -1624,22 +1655,52 @@ void LLModelLoader::run() } } } - + daeElement* scene = root->getDescendant("visual_scene"); - + if (!scene) { llwarns << "document has no visual_scene" << llendl; setLoadState( ERROR_PARSING ); return; } - processElement(scene); - + doOnIdleOneTime(boost::bind(&LLModelPreview::loadModelCallback,mPreview,mLod)); } } +bool LLModelLoader::doesJointArrayContainACompleteRig( const std::vector &jointListFromModel ) +{ + std::deque :: const_iterator masterJointIt = mMasterJointList.begin(); + std::deque :: const_iterator masterJointEndIt = mMasterJointList.end(); + + std::vector :: const_iterator modelJointIt = jointListFromModel.begin(); + std::vector :: const_iterator modelJointItEnd = jointListFromModel.end(); + + bool found = false; + for ( ;masterJointIt!=masterJointEndIt;++masterJointIt ) + { + found = false; + modelJointIt = jointListFromModel.begin(); + for ( ;modelJointIt!=modelJointItEnd; ++modelJointIt ) + { + if ( *masterJointIt == *modelJointIt ) + { + found = true; + break; + } + } + if ( !found ) + { + llinfos<<" Asset did not contain the joint (if you're u/l a fully rigged asset - it is required)." << *masterJointIt<< llendl; + break; + } + } + + return found; +} + //called in the main thread void LLModelLoader::loadTextures() { -- cgit v1.2.3 From f243f7e550b9dadd26d119bfeb4b215aa809997c Mon Sep 17 00:00:00 2001 From: leyla_linden Date: Thu, 6 Jan 2011 16:42:18 -0800 Subject: added callback for updating wizard dimensions and costs from the model preview properly enabling/disabling wizard buttons xml ui fixes --- indra/newview/llfloatermodelpreview.cpp | 8537 ++++++++++++++++--------------- 1 file changed, 4273 insertions(+), 4264 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index a1c2265f62..46c7cba53a 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1,4264 +1,4273 @@ -/** - * @file llfloatermodelpreview.cpp - * @brief LLFloaterModelPreview class implementation - * - * $LicenseInfo:firstyear=2004&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "dae.h" -//#include "dom.h" -#include "dom/domAsset.h" -#include "dom/domBind_material.h" -#include "dom/domCOLLADA.h" -#include "dom/domConstants.h" -#include "dom/domController.h" -#include "dom/domEffect.h" -#include "dom/domGeometry.h" -#include "dom/domInstance_geometry.h" -#include "dom/domInstance_material.h" -#include "dom/domInstance_node.h" -#include "dom/domInstance_effect.h" -#include "dom/domMaterial.h" -#include "dom/domMatrix.h" -#include "dom/domNode.h" -#include "dom/domProfile_COMMON.h" -#include "dom/domRotate.h" -#include "dom/domScale.h" -#include "dom/domTranslate.h" -#include "dom/domVisual_scene.h" - -#include "llfloatermodelpreview.h" - -#include "llfilepicker.h" -#include "llimagebmp.h" -#include "llimagetga.h" -#include "llimagejpeg.h" -#include "llimagepng.h" - -#include "llagent.h" -#include "llbutton.h" -#include "llcombobox.h" -#include "lldatapacker.h" -#include "lldrawable.h" -#include "lldrawpoolavatar.h" -#include "llrender.h" -#include "llface.h" -#include "lleconomy.h" -#include "llfocusmgr.h" -#include "llfloaterperms.h" -#include "lliconctrl.h" -#include "llmatrix4a.h" -#include "llmenubutton.h" -#include "llmeshrepository.h" -#include "llsdutil_math.h" -#include "lltextbox.h" -#include "lltoolmgr.h" -#include "llui.h" -#include "llvector4a.h" -#include "llviewercamera.h" -#include "llviewerwindow.h" -#include "llvoavatar.h" -#include "llvoavatarself.h" -#include "pipeline.h" -#include "lluictrlfactory.h" -#include "llviewermenu.h" -#include "llviewermenufile.h" -#include "llviewerregion.h" -#include "llviewertexturelist.h" -#include "llstring.h" -#include "llbutton.h" -#include "llcheckboxctrl.h" -#include "llradiogroup.h" -#include "llsliderctrl.h" -#include "llspinctrl.h" -#include "lltoggleablemenu.h" -#include "llvfile.h" -#include "llvfs.h" -#include "llcallbacklist.h" - -#include "glod/glod.h" - -//static -S32 LLFloaterModelPreview::sUploadAmount = 10; -LLFloaterModelPreview* LLFloaterModelPreview::sInstance = NULL; - -const S32 PREVIEW_BORDER_WIDTH = 2; -const S32 PREVIEW_RESIZE_HANDLE_SIZE = S32(RESIZE_HANDLE_WIDTH * OO_SQRT2) + PREVIEW_BORDER_WIDTH; -const S32 PREVIEW_HPAD = PREVIEW_RESIZE_HANDLE_SIZE; -const S32 PREF_BUTTON_HEIGHT = 16 + 7 + 16; -const S32 PREVIEW_TEXTURE_HEIGHT = 300; - -void drawBoxOutline(const LLVector3& pos, const LLVector3& size); - - -std::string lod_name[NUM_LOD+1] = -{ - "lowest", - "low", - "medium", - "high", - "I went off the end of the lod_name array. Me so smart." -}; - -std::string lod_triangles_name[NUM_LOD+1] = -{ - "lowest_triangles", - "low_triangles", - "medium_triangles", - "high_triangles", - "I went off the end of the lod_triangles_name array. Me so smart." -}; - -std::string lod_vertices_name[NUM_LOD+1] = -{ - "lowest_vertices", - "low_vertices", - "medium_vertices", - "high_vertices", - "I went off the end of the lod_vertices_name array. Me so smart." -}; - -std::string lod_status_name[NUM_LOD+1] = -{ - "lowest_status", - "low_status", - "medium_status", - "high_status", - "I went off the end of the lod_status_name array. Me so smart." -}; - -std::string lod_icon_name[NUM_LOD+1] = -{ - "status_icon_lowest", - "status_icon_low", - "status_icon_medium", - "status_icon_high", - "I went off the end of the lod_status_name array. Me so smart." -}; - -std::string lod_status_image[NUM_LOD+1] = -{ - "ModelImport_Status_Good", - "ModelImport_Status_Warning", - "ModelImport_Status_Error", - "I went off the end of the lod_status_image array. Me so smart." -}; - -std::string lod_label_name[NUM_LOD+1] = -{ - "lowest_label", - "low_label", - "medium_label", - "high_label", - "I went off the end of the lod_label_name array. Me so smart." -}; - - -bool validate_face(const LLVolumeFace& face) -{ - for (U32 i = 0; i < face.mNumIndices; ++i) - { - if (face.mIndices[i] >= face.mNumVertices) - { - llwarns << "Face has invalid index." << llendl; - return false; - } - } - - return true; -} - -bool validate_model(const LLModel* mdl) -{ - if (mdl->getNumVolumeFaces() == 0) - { - llwarns << "Model has no faces!" << llendl; - return false; - } - - for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) - { - if (mdl->getVolumeFace(i).mNumVertices == 0) - { - llwarns << "Face has no vertices." << llendl; - return false; - } - - if (mdl->getVolumeFace(i).mNumIndices == 0) - { - llwarns << "Face has no indices." << llendl; - return false; - } - - if (!validate_face(mdl->getVolumeFace(i))) - { - return false; - } - } - - return true; -} - -BOOL stop_gloderror() -{ - GLuint error = glodGetError(); - - if (error != GLOD_NO_ERROR) - { - llwarns << "GLOD error detected, cannot generate LOD: " << std::hex << error << llendl; - return TRUE; - } - - return FALSE; -} - - -LLMeshFilePicker::LLMeshFilePicker(LLModelPreview* mp, S32 lod) - : LLFilePickerThread(LLFilePicker::FFLOAD_COLLADA) - { - mMP = mp; - mLOD = lod; - } - -void LLMeshFilePicker::notify(const std::string& filename) -{ - mMP->loadModel(mFile, mLOD); -} - - -//----------------------------------------------------------------------------- -// LLFloaterModelPreview() -//----------------------------------------------------------------------------- -LLFloaterModelPreview::LLFloaterModelPreview(const LLSD& key) : -LLFloater(key) -{ - sInstance = this; - mLastMouseX = 0; - mLastMouseY = 0; - mGLName = 0; - mStatusLock = new LLMutex(NULL); - - mLODMode[LLModel::LOD_HIGH] = 0; - for (U32 i = 0; i < LLModel::LOD_HIGH; i++) - { - mLODMode[i] = 1; - } -} - -//----------------------------------------------------------------------------- -// postBuild() -//----------------------------------------------------------------------------- -BOOL LLFloaterModelPreview::postBuild() -{ - if (!LLFloater::postBuild()) - { - return FALSE; - } - - - - - - - childSetAction("lod_browse", onBrowseLOD, this); - - childSetCommitCallback("crease_angle", onGenerateNormalsCommit, this); - childSetCommitCallback("generate_normals", onGenerateNormalsCommit, this); - - childSetCommitCallback("lod_generate", onAutoFillCommit, this); - - childSetCommitCallback("lod_mode", onLODParamCommit, this); - childSetCommitCallback("lod_error_threshold", onLODParamCommit, this); - childSetCommitCallback("lod_triangle_limit", onLODParamCommit, this); - childSetCommitCallback("build_operator", onLODParamCommit, this); - childSetCommitCallback("queue_mode", onLODParamCommit, this); - childSetCommitCallback("border_mode", onLODParamCommit, this); - childSetCommitCallback("share_tolerance", onLODParamCommit, this); - - childSetTextArg("status", "[STATUS]", getString("status_idle")); - - //childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d",sUploadAmount)); - childSetAction("ok_btn", onUpload, this); - childDisable("ok_btn"); - - childSetAction("clear_materials", onClearMaterials, this); - - childSetCommitCallback("preview_lod_combo", onPreviewLODCommit, this); - - childSetCommitCallback("upload_skin", onUploadSkinCommit, this); - childSetCommitCallback("upload_joints", onUploadJointsCommit, this); - - childSetCommitCallback("import_scale", onImportScaleCommit, this); - - childSetCommitCallback("lod_file_or_limit", refresh, this); - childSetCommitCallback("physics_load_radio", refresh, this); - //childSetCommitCallback("physics_optimize", refresh, this); - //childSetCommitCallback("physics_use_hull", refresh, this); - - childDisable("upload_skin"); - childDisable("upload_joints"); - childDisable("ok_btn"); - - mViewOptionMenuButton = getChild("options_gear_btn"); - - mCommitCallbackRegistrar.add("ModelImport.ViewOption.Action", boost::bind(&LLFloaterModelPreview::onViewOptionChecked, this, _2)); - mEnableCallbackRegistrar.add("ModelImport.ViewOption.Check", boost::bind(&LLFloaterModelPreview::isViewOptionChecked, this, _2)); - mEnableCallbackRegistrar.add("ModelImport.ViewOption.Enabled", boost::bind(&LLFloaterModelPreview::isViewOptionEnabled, this, _2)); - - - - mViewOptionMenu = LLUICtrlFactory::getInstance()->createFromFile("menu_model_import_gear_default.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); - mViewOptionMenuButton->setMenu(mViewOptionMenu, LLMenuButton::MP_BOTTOM_LEFT); - - initDecompControls(); - - LLView* preview_panel = getChild("preview_panel"); - - mPreviewRect = preview_panel->getRect(); - - mModelPreview = new LLModelPreview(512, 512, this); - mModelPreview->setPreviewTarget(16.f); - - //set callbacks for left click on line editor rows - for (U32 i = 0; i <= LLModel::LOD_HIGH; i++) - { - LLTextBox* text = getChild(lod_label_name[i]); - if (text) - { - text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i)); - } - - text = getChild(lod_triangles_name[i]); - if (text) - { - text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i)); - } - - text = getChild(lod_vertices_name[i]); - if (text) - { - text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i)); - } - - text = getChild(lod_status_name[i]); - if (text) - { - text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i)); - } - } - - return TRUE; -} - -//----------------------------------------------------------------------------- -// LLFloaterModelPreview() -//----------------------------------------------------------------------------- -LLFloaterModelPreview::~LLFloaterModelPreview() -{ - sInstance = NULL; - - if ( mModelPreview->containsRiggedAsset() ) - { - gAgentAvatarp->resetJointPositions(); - } - - delete mModelPreview; - - if (mGLName) - { - LLImageGL::deleteTextures(1, &mGLName ); - } - - delete mStatusLock; - mStatusLock = NULL; -} - -void LLFloaterModelPreview::onViewOptionChecked(const LLSD& userdata) -{ - if (mModelPreview) - { - mModelPreview->mViewOption[userdata.asString()] = !mModelPreview->mViewOption[userdata.asString()]; - - mModelPreview->refresh(); - } -} - -bool LLFloaterModelPreview::isViewOptionChecked(const LLSD& userdata) -{ - if (mModelPreview) - { - return mModelPreview->mViewOption[userdata.asString()]; - } - - return false; -} - -bool LLFloaterModelPreview::isViewOptionEnabled(const LLSD& userdata) -{ - return !mViewOptionDisabled[userdata.asString()]; -} - -void LLFloaterModelPreview::setViewOptionEnabled(const std::string& option, bool enabled) -{ - mViewOptionDisabled[option] = !enabled; -} - -void LLFloaterModelPreview::enableViewOption(const std::string& option) -{ - setViewOptionEnabled(option, true); -} - -void LLFloaterModelPreview::disableViewOption(const std::string& option) -{ - setViewOptionEnabled(option, false); -} - -void LLFloaterModelPreview::loadModel(S32 lod) -{ - mModelPreview->mLoading = true; - - (new LLMeshFilePicker(mModelPreview, lod))->getFile(); -} - -//static -void LLFloaterModelPreview::onImportScaleCommit(LLUICtrl*,void* userdata) -{ - LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; - - if (!fp->mModelPreview) - { - return; - } - - fp->mModelPreview->calcResourceCost(); - fp->mModelPreview->refresh(); -} - -//static -void LLFloaterModelPreview::onUploadJointsCommit(LLUICtrl*,void* userdata) -{ - LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; - - if (!fp->mModelPreview) - { - return; - } - - fp->mModelPreview->refresh(); -} - -//static -void LLFloaterModelPreview::onUploadSkinCommit(LLUICtrl*,void* userdata) -{ - LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; - - if (!fp->mModelPreview) - { - return; - } - - fp->mModelPreview->refresh(); - fp->mModelPreview->resetPreviewTarget(); - fp->mModelPreview->clearBuffers(); -} - -//static -void LLFloaterModelPreview::onPreviewLODCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; - - if (!fp->mModelPreview) - { - return; - } - - S32 which_mode = 0; - - LLComboBox* combo = (LLComboBox*) ctrl; - - which_mode = (NUM_LOD-1)-combo->getFirstSelectedIndex(); // combo box list of lods is in reverse order - - fp->mModelPreview->setPreviewLOD(which_mode); -} - -//static -void LLFloaterModelPreview::onGenerateNormalsCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; - - fp->mModelPreview->generateNormals(); -} - -//static -void LLFloaterModelPreview::onExplodeCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview* fp = LLFloaterModelPreview::sInstance; - - fp->mModelPreview->refresh(); -} - -//static -void LLFloaterModelPreview::onAutoFillCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; - - fp->mModelPreview->genLODs(); -} - -//static -void LLFloaterModelPreview::onLODParamCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; - fp->mModelPreview->genLODs(fp->mModelPreview->mPreviewLOD); - fp->mModelPreview->updateStatusMessages(); - fp->mModelPreview->refresh(); -} - - -//----------------------------------------------------------------------------- -// draw() -//----------------------------------------------------------------------------- -void LLFloaterModelPreview::draw() -{ - LLFloater::draw(); - LLRect r = getRect(); - - mModelPreview->update(); - - if (!mModelPreview->mLoading) - { - childSetTextArg("status", "[STATUS]", getString("status_idle")); - } - - childSetTextArg("prim_cost", "[PRIM_COST]", llformat("%d", mModelPreview->mResourceCost)); - childSetTextArg("description_label", "[TEXTURES]", llformat("%d", mModelPreview->mTextureSet.size())); - - if (!mCurRequest.empty()) - { - LLMutexLock lock(mStatusLock); - childSetTextArg("status", "[STATUS]", mStatusMessage); - } - - U32 resource_cost = mModelPreview->mResourceCost*10; - - if (childGetValue("upload_textures").asBoolean()) - { - resource_cost += mModelPreview->mTextureSet.size()*10; - } - - childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d", resource_cost)); - - if (mModelPreview) - { - gGL.color3f(1.f, 1.f, 1.f); - - gGL.getTexUnit(0)->bind(mModelPreview); - - - LLView* preview_panel = getChild("preview_panel"); - - LLRect rect = preview_panel->getRect(); - if (rect != mPreviewRect) - { - mModelPreview->refresh(); - mPreviewRect = preview_panel->getRect(); - } - - gGL.begin( LLRender::QUADS ); - { - gGL.texCoord2f(0.f, 1.f); - gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mTop); - gGL.texCoord2f(0.f, 0.f); - gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mBottom); - gGL.texCoord2f(1.f, 0.f); - gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mBottom); - gGL.texCoord2f(1.f, 1.f); - gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mTop); - } - gGL.end(); - - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - } -} - -//----------------------------------------------------------------------------- -// handleMouseDown() -//----------------------------------------------------------------------------- -BOOL LLFloaterModelPreview::handleMouseDown(S32 x, S32 y, MASK mask) -{ - if (mPreviewRect.pointInRect(x, y)) - { - bringToFront( x, y ); - gFocusMgr.setMouseCapture(this); - gViewerWindow->hideCursor(); - mLastMouseX = x; - mLastMouseY = y; - return TRUE; - } - - return LLFloater::handleMouseDown(x, y, mask); -} - -//----------------------------------------------------------------------------- -// handleMouseUp() -//----------------------------------------------------------------------------- -BOOL LLFloaterModelPreview::handleMouseUp(S32 x, S32 y, MASK mask) -{ - gFocusMgr.setMouseCapture(FALSE); - gViewerWindow->showCursor(); - return LLFloater::handleMouseUp(x, y, mask); -} - -//----------------------------------------------------------------------------- -// handleHover() -//----------------------------------------------------------------------------- -BOOL LLFloaterModelPreview::handleHover (S32 x, S32 y, MASK mask) -{ - MASK local_mask = mask & ~MASK_ALT; - - if (mModelPreview && hasMouseCapture()) - { - if (local_mask == MASK_PAN) - { - // pan here - mModelPreview->pan((F32)(x - mLastMouseX) * -0.005f, (F32)(y - mLastMouseY) * -0.005f); - } - else if (local_mask == MASK_ORBIT) - { - F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f; - F32 pitch_radians = (F32)(y - mLastMouseY) * 0.02f; - - mModelPreview->rotate(yaw_radians, pitch_radians); - } - else - { - - F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f; - F32 zoom_amt = (F32)(y - mLastMouseY) * 0.02f; - - mModelPreview->rotate(yaw_radians, 0.f); - mModelPreview->zoom(zoom_amt); - } - - - mModelPreview->refresh(); - - LLUI::setMousePositionLocal(this, mLastMouseX, mLastMouseY); - } - - if (!mPreviewRect.pointInRect(x, y) || !mModelPreview) - { - return LLFloater::handleHover(x, y, mask); - } - else if (local_mask == MASK_ORBIT) - { - gViewerWindow->setCursor(UI_CURSOR_TOOLCAMERA); - } - else if (local_mask == MASK_PAN) - { - gViewerWindow->setCursor(UI_CURSOR_TOOLPAN); - } - else - { - gViewerWindow->setCursor(UI_CURSOR_TOOLZOOMIN); - } - - return TRUE; -} - -//----------------------------------------------------------------------------- -// handleScrollWheel() -//----------------------------------------------------------------------------- -BOOL LLFloaterModelPreview::handleScrollWheel(S32 x, S32 y, S32 clicks) -{ - if (mPreviewRect.pointInRect(x, y) && mModelPreview) - { - mModelPreview->zoom((F32)clicks * -0.2f); - mModelPreview->refresh(); - } - - return TRUE; -} - -//static -void LLFloaterModelPreview::onPhysicsParamCommit(LLUICtrl* ctrl, void* data) -{ - if (LLConvexDecomposition::getInstance() == NULL) - { - llinfos << "convex decomposition tool is a stub on this platform. cannot get decomp." << llendl; - return; - } - - if (sInstance) - { - LLCDParam* param = (LLCDParam*) data; - std::string name(param->mName); - sInstance->mDecompParams[name] = ctrl->getValue(); - - if (name == "Simplify Method") - { - if (ctrl->getValue().asInteger() == 0) - { - sInstance->childSetVisible("Retain%", true); - sInstance->childSetVisible("Detail Scale", false); - } - else - { - sInstance->childSetVisible("Retain%", false); - sInstance->childSetVisible("Detail Scale", true); - } - } - } -} - -//static -void LLFloaterModelPreview::onPhysicsStageExecute(LLUICtrl* ctrl, void* data) -{ - LLCDStageData* stage = (LLCDStageData*) data; - - if (sInstance) - { - if (!sInstance->mCurRequest.empty()) - { - llinfos << "Decomposition request still pending." << llendl; - return; - } - - if (sInstance->mModelPreview) - { - for (S32 i = 0; i < sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS].size(); ++i) - { - LLModel* mdl = sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS][i]; - DecompRequest* request = new DecompRequest(stage->mName, mdl); - sInstance->mCurRequest.insert(request); - gMeshRepo.mDecompThread->submitRequest(request); - } - } - } -} - -//static -void LLFloaterModelPreview::onPhysicsBrowse(LLUICtrl* ctrl, void* userdata) -{ - sInstance->loadModel(LLModel::LOD_PHYSICS); -} - -//static -void LLFloaterModelPreview::onPhysicsUseLOD(LLUICtrl* ctrl, void* userdata) -{ - S32 which_mode = 3; - LLCtrlSelectionInterface* iface = sInstance->childGetSelectionInterface("physics_lod_combo"); - if (iface) - { - which_mode = iface->getFirstSelectedIndex(); - } - - sInstance->mModelPreview->setPhysicsFromLOD(which_mode); -} - -//static -void LLFloaterModelPreview::onPhysicsStageCancel(LLUICtrl* ctrl, void*data) -{ - if (sInstance) - { - for (std::set >::iterator iter = sInstance->mCurRequest.begin(); - iter != sInstance->mCurRequest.end(); ++iter) - { - DecompRequest* req = *iter; - req->mContinue = 0; - } - } -} - -void LLFloaterModelPreview::initDecompControls() -{ - LLSD key; - - childSetCommitCallback("cancel_btn", onPhysicsStageCancel, NULL); - childSetCommitCallback("physics_lod_combo", onPhysicsUseLOD, NULL); - childSetCommitCallback("physics_browse", onPhysicsBrowse, NULL); - - static const LLCDStageData* stage = NULL; - static S32 stage_count = 0; - - if (!stage && LLConvexDecomposition::getInstance() != NULL) - { - stage_count = LLConvexDecomposition::getInstance()->getStages(&stage); - } - - static const LLCDParam* param = NULL; - static S32 param_count = 0; - if (!param && LLConvexDecomposition::getInstance() != NULL) - { - param_count = LLConvexDecomposition::getInstance()->getParameters(¶m); - } - - for (S32 j = stage_count-1; j >= 0; --j) - { - LLButton* button = getChild(stage[j].mName); - if (button) - { - button->setCommitCallback(onPhysicsStageExecute, (void*) &stage[j]); - } - - gMeshRepo.mDecompThread->mStageID[stage[j].mName] = j; - // protected against stub by stage_count being 0 for stub above - LLConvexDecomposition::getInstance()->registerCallback(j, LLPhysicsDecomp::llcdCallback); - - //llinfos << "Physics decomp stage " << stage[j].mName << " (" << j << ") parameters:" << llendl; - //llinfos << "------------------------------------" << llendl; - - for (S32 i = 0; i < param_count; ++i) - { - if (param[i].mStage != j) - { - continue; - } - - std::string name(param[i].mName ? param[i].mName : ""); - std::string description(param[i].mDescription ? param[i].mDescription : ""); - - std::string type = "unknown"; - - llinfos << name << " - " << description << llendl; - - if (param[i].mType == LLCDParam::LLCD_FLOAT) - { - mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mFloat); - //llinfos << "Type: float, Default: " << param[i].mDefault.mFloat << llendl; - - LLSliderCtrl* slider = getChild(name); - if (slider) - { - slider->setMinValue(param[i].mDetails.mRange.mLow.mFloat); - slider->setMaxValue(param[i].mDetails.mRange.mHigh.mFloat); - slider->setIncrement(param[i].mDetails.mRange.mDelta.mFloat); - slider->setValue(param[i].mDefault.mFloat); - slider->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); - } - } - else if (param[i].mType == LLCDParam::LLCD_INTEGER) - { - mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue); - //llinfos << "Type: integer, Default: " << param[i].mDefault.mIntOrEnumValue << llendl; - - LLSliderCtrl* slider = getChild(name); - if (slider) - { - slider->setMinValue(param[i].mDetails.mRange.mLow.mIntOrEnumValue); - slider->setMaxValue(param[i].mDetails.mRange.mHigh.mIntOrEnumValue); - slider->setIncrement(param[i].mDetails.mRange.mDelta.mIntOrEnumValue); - slider->setValue(param[i].mDefault.mIntOrEnumValue); - slider->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); - } - } - else if (param[i].mType == LLCDParam::LLCD_BOOLEAN) - { - mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mBool); - //llinfos << "Type: boolean, Default: " << (param[i].mDefault.mBool ? "True" : "False") << llendl; - - LLCheckBoxCtrl* check_box = getChild(name); - if (check_box) - { - check_box->setValue(param[i].mDefault.mBool); - check_box->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); - } - } - else if (param[i].mType == LLCDParam::LLCD_ENUM) - { - mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue); - //llinfos << "Type: enum, Default: " << param[i].mDefault.mIntOrEnumValue << llendl; - - { //plug into combo box - - //llinfos << "Accepted values: " << llendl; - LLComboBox* combo_box = getChild(name); - for (S32 k = 0; k < param[i].mDetails.mEnumValues.mNumEnums; ++k) - { - //llinfos << param[i].mDetails.mEnumValues.mEnumsArray[k].mValue - // << " - " << param[i].mDetails.mEnumValues.mEnumsArray[k].mName << llendl; - - combo_box->add(param[i].mDetails.mEnumValues.mEnumsArray[k].mName, - LLSD::Integer(param[i].mDetails.mEnumValues.mEnumsArray[k].mValue)); - } - combo_box->setValue(param[i].mDefault.mIntOrEnumValue); - combo_box->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); - } - - //llinfos << "----" << llendl; - } - //llinfos << "-----------------------------" << llendl; - } - } - - childSetCommitCallback("physics_explode", LLFloaterModelPreview::onExplodeCommit, this); -} - -//----------------------------------------------------------------------------- -// onMouseCaptureLost() -//----------------------------------------------------------------------------- -// static -void LLFloaterModelPreview::onMouseCaptureLostModelPreview(LLMouseHandler* handler) -{ - gViewerWindow->showCursor(); -} - -//----------------------------------------------------------------------------- -// LLModelLoader -//----------------------------------------------------------------------------- -LLModelLoader::LLModelLoader(std::string filename, S32 lod, LLModelPreview* preview) -: LLThread("Model Loader"), mFilename(filename), mLod(lod), mPreview(preview), mState(STARTING), mFirstTransform(TRUE) -{ - mJointMap["mPelvis"] = "mPelvis"; - mJointMap["mTorso"] = "mTorso"; - mJointMap["mChest"] = "mChest"; - mJointMap["mNeck"] = "mNeck"; - mJointMap["mHead"] = "mHead"; - mJointMap["mSkull"] = "mSkull"; - mJointMap["mEyeRight"] = "mEyeRight"; - mJointMap["mEyeLeft"] = "mEyeLeft"; - mJointMap["mCollarLeft"] = "mCollarLeft"; - mJointMap["mShoulderLeft"] = "mShoulderLeft"; - mJointMap["mElbowLeft"] = "mElbowLeft"; - mJointMap["mWristLeft"] = "mWristLeft"; - mJointMap["mCollarRight"] = "mCollarRight"; - mJointMap["mShoulderRight"] = "mShoulderRight"; - mJointMap["mElbowRight"] = "mElbowRight"; - mJointMap["mWristRight"] = "mWristRight"; - mJointMap["mHipRight"] = "mHipRight"; - mJointMap["mKneeRight"] = "mKneeRight"; - mJointMap["mAnkleRight"] = "mAnkleRight"; - mJointMap["mFootRight"] = "mFootRight"; - mJointMap["mToeRight"] = "mToeRight"; - mJointMap["mHipLeft"] = "mHipLeft"; - mJointMap["mKneeLeft"] = "mKneeLeft"; - mJointMap["mAnkleLeft"] = "mAnkleLeft"; - mJointMap["mFootLeft"] = "mFootLeft"; - mJointMap["mToeLeft"] = "mToeLeft"; - - mJointMap["avatar_mPelvis"] = "mPelvis"; - mJointMap["avatar_mTorso"] = "mTorso"; - mJointMap["avatar_mChest"] = "mChest"; - mJointMap["avatar_mNeck"] = "mNeck"; - mJointMap["avatar_mHead"] = "mHead"; - mJointMap["avatar_mSkull"] = "mSkull"; - mJointMap["avatar_mEyeRight"] = "mEyeRight"; - mJointMap["avatar_mEyeLeft"] = "mEyeLeft"; - mJointMap["avatar_mCollarLeft"] = "mCollarLeft"; - mJointMap["avatar_mShoulderLeft"] = "mShoulderLeft"; - mJointMap["avatar_mElbowLeft"] = "mElbowLeft"; - mJointMap["avatar_mWristLeft"] = "mWristLeft"; - mJointMap["avatar_mCollarRight"] = "mCollarRight"; - mJointMap["avatar_mShoulderRight"] = "mShoulderRight"; - mJointMap["avatar_mElbowRight"] = "mElbowRight"; - mJointMap["avatar_mWristRight"] = "mWristRight"; - mJointMap["avatar_mHipRight"] = "mHipRight"; - mJointMap["avatar_mKneeRight"] = "mKneeRight"; - mJointMap["avatar_mAnkleRight"] = "mAnkleRight"; - mJointMap["avatar_mFootRight"] = "mFootRight"; - mJointMap["avatar_mToeRight"] = "mToeRight"; - mJointMap["avatar_mHipLeft"] = "mHipLeft"; - mJointMap["avatar_mKneeLeft"] = "mKneeLeft"; - mJointMap["avatar_mAnkleLeft"] = "mAnkleLeft"; - mJointMap["avatar_mFootLeft"] = "mFootLeft"; - mJointMap["avatar_mToeLeft"] = "mToeLeft"; - - - mJointMap["hip"] = "mPelvis"; - mJointMap["abdomen"] = "mTorso"; - mJointMap["chest"] = "mChest"; - mJointMap["neck"] = "mNeck"; - mJointMap["head"] = "mHead"; - mJointMap["figureHair"] = "mSkull"; - mJointMap["lCollar"] = "mCollarLeft"; - mJointMap["lShldr"] = "mShoulderLeft"; - mJointMap["lForeArm"] = "mElbowLeft"; - mJointMap["lHand"] = "mWristLeft"; - mJointMap["rCollar"] = "mCollarRight"; - mJointMap["rShldr"] = "mShoulderRight"; - mJointMap["rForeArm"] = "mElbowRight"; - mJointMap["rHand"] = "mWristRight"; - mJointMap["rThigh"] = "mHipRight"; - mJointMap["rShin"] = "mKneeRight"; - mJointMap["rFoot"] = "mFootRight"; - mJointMap["lThigh"] = "mHipLeft"; - mJointMap["lShin"] = "mKneeLeft"; - mJointMap["lFoot"] = "mFootLeft"; -} - -void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, BOOL& first_transform) -{ - LLVector4a box[] = - { - LLVector4a(-1, 1,-1), - LLVector4a(-1, 1, 1), - LLVector4a(-1,-1,-1), - LLVector4a(-1,-1, 1), - LLVector4a( 1, 1,-1), - LLVector4a( 1, 1, 1), - LLVector4a( 1,-1,-1), - LLVector4a( 1,-1, 1), - }; - - for (S32 j = 0; j < model->getNumVolumeFaces(); ++j) - { - const LLVolumeFace& face = model->getVolumeFace(j); - - LLVector4a center; - center.setAdd(face.mExtents[0], face.mExtents[1]); - center.mul(0.5f); - LLVector4a size; - size.setSub(face.mExtents[1],face.mExtents[0]); - size.mul(0.5f); - - for (U32 i = 0; i < 8; i++) - { - LLVector4a t; - t.setMul(size, box[i]); - t.add(center); - - LLVector4a v; - - mat.affineTransform(t, v); - - if (first_transform) - { - first_transform = FALSE; - min = max = v; - } - else - { - update_min_max(min, max, v); - } - } - } -} - -void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& max, BOOL& first_transform) -{ - LLVector4a mina, maxa; - LLMatrix4a mata; - - mata.loadu(mat); - mina.load3(min.mV); - maxa.load3(max.mV); - - stretch_extents(model, mata, mina, maxa, first_transform); - - min.set(mina.getF32ptr()); - max.set(maxa.getF32ptr()); -} - -void LLModelLoader::run() -{ - DAE dae; - domCOLLADA* dom = dae.open(mFilename); - - if (dom) - { - daeDatabase* db = dae.getDatabase(); - - daeInt count = db->getElementCount(NULL, COLLADA_TYPE_MESH); - - daeDocument* doc = dae.getDoc(mFilename); - if (!doc) - { - llwarns << "can't find internal doc" << llendl; - return; - } - - daeElement* root = doc->getDomRoot(); - if (!root) - { - llwarns << "document has no root" << llendl; - return; - } - - //get unit scale - mTransform.setIdentity(); - - domAsset::domUnit* unit = daeSafeCast(root->getDescendant(daeElement::matchType(domAsset::domUnit::ID()))); - - if (unit) - { - F32 meter = unit->getMeter(); - mTransform.mMatrix[0][0] = meter; - mTransform.mMatrix[1][1] = meter; - mTransform.mMatrix[2][2] = meter; - } - - //get up axis rotation - LLMatrix4 rotation; - - domUpAxisType up = UPAXISTYPE_Y_UP; // default is Y_UP - domAsset::domUp_axis* up_axis = - daeSafeCast(root->getDescendant(daeElement::matchType(domAsset::domUp_axis::ID()))); - - if (up_axis) - { - up = up_axis->getValue(); - } - - if (up == UPAXISTYPE_X_UP) - { - rotation.initRotation(0.0f, 90.0f * DEG_TO_RAD, 0.0f); - } - else if (up == UPAXISTYPE_Y_UP) - { - rotation.initRotation(90.0f * DEG_TO_RAD, 0.0f, 0.0f); - } - - rotation *= mTransform; - mTransform = rotation; - - - for (daeInt idx = 0; idx < count; ++idx) - { //build map of domEntities to LLModel - domMesh* mesh = NULL; - db->getElement((daeElement**) &mesh, idx, NULL, COLLADA_TYPE_MESH); - - if (mesh) - { - LLPointer model = LLModel::loadModelFromDomMesh(mesh); - - if (model.notNull() && validate_model(model)) - { - mModelList.push_back(model); - mModel[mesh] = model; - } - } - } - - count = db->getElementCount(NULL, COLLADA_TYPE_SKIN); - for (daeInt idx = 0; idx < count; ++idx) - { //add skinned meshes as instances - domSkin* skin = NULL; - db->getElement((daeElement**) &skin, idx, NULL, COLLADA_TYPE_SKIN); - - if (skin) - { - domGeometry* geom = daeSafeCast(skin->getSource().getElement()); - - if (geom) - { - domMesh* mesh = geom->getMesh(); - if (mesh) - { - LLModel* model = mModel[mesh]; - if (model) - { - LLVector3 mesh_scale_vector; - LLVector3 mesh_translation_vector; - model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); - - LLMatrix4 normalized_transformation; - normalized_transformation.setTranslation(mesh_translation_vector); - - LLMatrix4 mesh_scale; - mesh_scale.initScale(mesh_scale_vector); - mesh_scale *= normalized_transformation; - normalized_transformation = mesh_scale; - - glh::matrix4f inv_mat((F32*) normalized_transformation.mMatrix); - inv_mat = inv_mat.inverse(); - LLMatrix4 inverse_normalized_transformation(inv_mat.m); - - domSkin::domBind_shape_matrix* bind_mat = skin->getBind_shape_matrix(); - - if (bind_mat) - { //get bind shape matrix - domFloat4x4& dom_value = bind_mat->getValue(); - - for (int i = 0; i < 4; i++) - { - for(int j = 0; j < 4; j++) - { - model->mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j*4]; - } - } - - LLMatrix4 trans = normalized_transformation; - trans *= model->mBindShapeMatrix; - model->mBindShapeMatrix = trans; - - } - - - //The joint transfom map that we'll populate below - std::map jointTransforms; - jointTransforms.clear(); - - //Some collada setup for accessing the skeleton - daeElement* pElement = 0; - dae.getDatabase()->getElement( &pElement, 0, 0, "skeleton" ); - - //Try to get at the skeletal instance controller - domInstance_controller::domSkeleton* pSkeleton = daeSafeCast( pElement ); - bool missingSkeletonOrScene = false; - - //If no skeleton, do a breadth-first search to get at specific joints - if ( !pSkeleton ) - { - daeElement* pScene = root->getDescendant("visual_scene"); - if ( !pScene ) - { - llwarns<<"No visual scene - unable to parse bone offsets "< > children = pScene->getChildren(); - S32 childCount = children.getCount(); - - //Process any children that are joints - //Not all children are joints, some code be ambient lights, cameras, geometry etc.. - for (S32 i = 0; i < childCount; ++i) - { - domNode* pNode = daeSafeCast(children[i]); - if ( isNodeAJoint( pNode ) ) - { - processJointNode( pNode, jointTransforms ); - } - } - } - } - else - //Has Skeleton - { - //Get the root node of the skeleton - daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement(); - if ( pSkeletonRootNode ) - { - //Once we have the root node - start acccessing it's joint components - const int jointCnt = mJointMap.size(); - std::map :: const_iterator jointIt = mJointMap.begin(); - - //Loop over all the possible joints within the .dae - using the allowed joint list in the ctor. - for ( int i=0; i( resolver.getElement() ); - if ( pJoint ) - { - //Pull out the translate id and store it in the jointTranslations map - daeSIDResolver jointResolver( pJoint, "./translate" ); - domTranslate* pTranslate = daeSafeCast( jointResolver.getElement() ); - - LLMatrix4 workingTransform; - - //Translation via SID - if ( pTranslate ) - { - extractTranslation( pTranslate, workingTransform ); - } - else - { - //Translation via child from element - daeElement* pTranslateElement = getChildFromElement( pJoint, "translate" ); - if ( pTranslateElement && pTranslateElement->typeID() != domTranslate::ID() ) - { - llwarns<< "The found element is not a translate node" < :: const_iterator jointIt = mJointMap.begin(); - for ( int i=0; igetJoint( lookingForJoint ); - if ( pJoint ) - { - pJoint->storeCurrentXform( jointTransform.getTranslation() ); - } - else - { - //Most likely an error in the asset. - llwarns<<"Tried to apply joint position from .dae, but it did not exist in the avatar rig." << llendl; - } - //Reposition the avatars pelvis (avPos+offset) - //if ( lookingForJoint == "mPelvis" ) - //{ - // const LLVector3& pos = gAgentAvatarp->getCharacterPosition(); - // gAgentAvatarp->setPelvisOffset( true, jointTransform.getTranslation() ); - // gAgentAvatarp->setPosition( pos + jointTransform.getTranslation() ); - //} - } - } - } //missingSkeletonOrScene - - domSkin::domJoints* joints = skin->getJoints(); - - domInputLocal_Array& joint_input = joints->getInput_array(); - - for (size_t i = 0; i < joint_input.getCount(); ++i) - { - domInputLocal* input = joint_input.get(i); - xsNMTOKEN semantic = input->getSemantic(); - - if (strcmp(semantic, COMMON_PROFILE_INPUT_JOINT) == 0) - { //found joint source, fill model->mJointMap and model->mJointList - daeElement* elem = input->getSource().getElement(); - - domSource* source = daeSafeCast(elem); - if (source) - { - - - domName_array* names_source = source->getName_array(); - - if (names_source) - { - domListOfNames &names = names_source->getValue(); - - for (size_t j = 0; j < names.getCount(); ++j) - { - std::string name(names.get(j)); - if (mJointMap.find(name) != mJointMap.end()) - { - name = mJointMap[name]; - } - model->mJointList.push_back(name); - model->mJointMap[name] = j; - } - } - else - { - domIDREF_array* names_source = source->getIDREF_array(); - if (names_source) - { - xsIDREFS& names = names_source->getValue(); - - for (size_t j = 0; j < names.getCount(); ++j) - { - std::string name(names.get(j).getID()); - if (mJointMap.find(name) != mJointMap.end()) - { - name = mJointMap[name]; - } - model->mJointList.push_back(name); - model->mJointMap[name] = j; - } - } - } - } - } - else if (strcmp(semantic, COMMON_PROFILE_INPUT_INV_BIND_MATRIX) == 0) - { //found inv_bind_matrix array, fill model->mInvBindMatrix - domSource* source = daeSafeCast(input->getSource().getElement()); - if (source) - { - domFloat_array* t = source->getFloat_array(); - if (t) - { - domListOfFloats& transform = t->getValue(); - S32 count = transform.getCount()/16; - - for (S32 k = 0; k < count; ++k) - { - LLMatrix4 mat; - - for (int i = 0; i < 4; i++) - { - for(int j = 0; j < 4; j++) - { - mat.mMatrix[i][j] = transform[k*16 + i + j*4]; - } - } - - model->mInvBindMatrix.push_back(mat); - } - } - } - } - } - - //We need to construct the alternate bind matrix (which contains the new joint positions) - //in the same order as they were stored in the joint buffer. The joints associated - //with the skeleton are not stored in the same order as they are in the exported joint buffer. - //This remaps the skeletal joints to be in the same order as the joints stored in the model. - std::vector :: const_iterator jointIt = model->mJointList.begin(); - const int jointCnt = model->mJointList.size(); - for ( int i=0; imInvBindMatrix[i]; - newInverse.setTranslation( jointTransforms[lookingForJoint].getTranslation() ); - model->mAlternateBindMatrix.push_back( newInverse ); - } - else - { - llwarns<<"Possibly misnamed/missing joint [" <getVertices(); - if (verts) - { - domInputLocal_Array& inputs = verts->getInput_array(); - for (size_t i = 0; i < inputs.getCount() && model->mPosition.empty(); ++i) - { - if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_POSITION) == 0) - { - domSource* pos_source = daeSafeCast(inputs[i]->getSource().getElement()); - if (pos_source) - { - domFloat_array* pos_array = pos_source->getFloat_array(); - if (pos_array) - { - domListOfFloats& pos = pos_array->getValue(); - - for (size_t j = 0; j < pos.getCount(); j += 3) - { - if (pos.getCount() <= j+2) - { - llerrs << "WTF?" << llendl; - } - - LLVector3 v(pos[j], pos[j+1], pos[j+2]); - - //transform from COLLADA space to volume space - v = v * inverse_normalized_transformation; - - model->mPosition.push_back(v); - } - } - } - } - } - } - - //grab skin weights array - domSkin::domVertex_weights* weights = skin->getVertex_weights(); - if (weights) - { - domInputLocalOffset_Array& inputs = weights->getInput_array(); - domFloat_array* vertex_weights = NULL; - for (size_t i = 0; i < inputs.getCount(); ++i) - { - if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_WEIGHT) == 0) - { - domSource* weight_source = daeSafeCast(inputs[i]->getSource().getElement()); - if (weight_source) - { - vertex_weights = weight_source->getFloat_array(); - } - } - } - - if (vertex_weights) - { - domListOfFloats& w = vertex_weights->getValue(); - domListOfUInts& vcount = weights->getVcount()->getValue(); - domListOfInts& v = weights->getV()->getValue(); - - U32 c_idx = 0; - for (size_t vc_idx = 0; vc_idx < vcount.getCount(); ++vc_idx) - { //for each vertex - daeUInt count = vcount[vc_idx]; - - //create list of weights that influence this vertex - LLModel::weight_list weight_list; - - for (daeUInt i = 0; i < count; ++i) - { //for each weight - daeInt joint_idx = v[c_idx++]; - daeInt weight_idx = v[c_idx++]; - - if (joint_idx == -1) - { - //ignore bindings to bind_shape_matrix - continue; - } - - F32 weight_value = w[weight_idx]; - - weight_list.push_back(LLModel::JointWeight(joint_idx, weight_value)); - } - - //sort by joint weight - std::sort(weight_list.begin(), weight_list.end(), LLModel::CompareWeightGreater()); - - std::vector wght; - - F32 total = 0.f; - - for (U32 i = 0; i < llmin((U32) 4, (U32) weight_list.size()); ++i) - { //take up to 4 most significant weights - if (weight_list[i].mWeight > 0.f) - { - wght.push_back( weight_list[i] ); - total += weight_list[i].mWeight; - } - } - - F32 scale = 1.f/total; - if (scale != 1.f) - { //normalize weights - for (U32 i = 0; i < wght.size(); ++i) - { - wght[i].mWeight *= scale; - } - } - - model->mSkinWeights[model->mPosition[vc_idx]] = wght; - } - - //add instance to scene for this model - - LLMatrix4 transformation = mTransform; - // adjust the transformation to compensate for mesh normalization - - LLMatrix4 mesh_translation; - mesh_translation.setTranslation(mesh_translation_vector); - mesh_translation *= transformation; - transformation = mesh_translation; - - LLMatrix4 mesh_scale; - mesh_scale.initScale(mesh_scale_vector); - mesh_scale *= transformation; - transformation = mesh_scale; - - std::vector materials; - materials.resize(model->getNumVolumeFaces()); - mScene[transformation].push_back(LLModelInstance(model, transformation, materials)); - stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); - } - } - } - } - } - } - } - - daeElement* scene = root->getDescendant("visual_scene"); - - if (!scene) - { - llwarns << "document has no visual_scene" << llendl; - setLoadState( ERROR_PARSING ); - return; - } - - processElement(scene); - - doOnIdleOneTime(boost::bind(&LLModelPreview::loadModelCallback,mPreview,mLod)); - } -} - -bool LLModelLoader::isNodeAJoint( domNode* pNode ) -{ - if ( pNode->getName() == NULL) - { - return false; - } - - if ( mJointMap.find( pNode->getName() ) != mJointMap.end() ) - { - return true; - } - - return false; -} - -void LLModelLoader::extractTranslation( domTranslate* pTranslate, LLMatrix4& transform ) -{ - domFloat3 jointTrans = pTranslate->getValue(); - LLVector3 singleJointTranslation( jointTrans[0], jointTrans[1], jointTrans[2] ); - transform.setTranslation( singleJointTranslation ); -} - -void LLModelLoader::extractTranslationViaElement( daeElement* pTranslateElement, LLMatrix4& transform ) -{ - domTranslate* pTranslateChild = dynamic_cast( pTranslateElement ); - domFloat3 translateChild = pTranslateChild->getValue(); - LLVector3 singleJointTranslation( translateChild[0], translateChild[1], translateChild[2] ); - transform.setTranslation( singleJointTranslation ); -} - -void LLModelLoader::processJointNode( domNode* pNode, std::map& jointTransforms ) -{ - if (pNode->getName() == NULL) - { - llwarns << "nameless node, can't process" << llendl; - return; - } - - //llwarns<<"ProcessJointNode# Node:" <getName()<( jointResolver.getElement() ); - - //Translation via SID was successful - if ( pTranslate ) - { - extractTranslation( pTranslate, workingTransform ); - } - else - { - //Translation via child from element - daeElement* pTranslateElement = getChildFromElement( pNode, "translate" ); - if ( !pTranslateElement || pTranslateElement->typeID() != domTranslate::ID() ) - { - llwarns<< "The found element is not a translate node" <getName() ] = workingTransform; - - //2. handle the nodes children - - //Gather and handle the incoming nodes children - daeTArray< daeSmartRef > childOfChild = pNode->getChildren(); - S32 childOfChildCount = childOfChild.getCount(); - - for (S32 i = 0; i < childOfChildCount; ++i) - { - domNode* pChildNode = daeSafeCast( childOfChild[i] ); - if ( pChildNode ) - { - processJointNode( pChildNode, jointTransforms ); - } - } -} - -daeElement* LLModelLoader::getChildFromElement( daeElement* pElement, std::string const & name ) -{ - daeElement* pChildOfElement = pElement->getChild( name.c_str() ); - if ( pChildOfElement ) - { - return pChildOfElement; - } - llwarns<< "Could not find a child [" << name << "] for the element: \"" << pElement->getAttribute("id") << "\"" << llendl; - return NULL; -} - -void LLModelLoader::processElement(daeElement* element) -{ - LLMatrix4 saved_transform = mTransform; - - domTranslate* translate = daeSafeCast(element); - if (translate) - { - domFloat3 dom_value = translate->getValue(); - - LLMatrix4 translation; - translation.setTranslation(LLVector3(dom_value[0], dom_value[1], dom_value[2])); - - translation *= mTransform; - mTransform = translation; - } - - domRotate* rotate = daeSafeCast(element); - if (rotate) - { - domFloat4 dom_value = rotate->getValue(); - - LLMatrix4 rotation; - rotation.initRotTrans(dom_value[3] * DEG_TO_RAD, LLVector3(dom_value[0], dom_value[1], dom_value[2]), LLVector3(0, 0, 0)); - - rotation *= mTransform; - mTransform = rotation; - } - - domScale* scale = daeSafeCast(element); - if (scale) - { - domFloat3 dom_value = scale->getValue(); - - LLMatrix4 scaling; - scaling.initScale(LLVector3(dom_value[0], dom_value[1], dom_value[2])); - - scaling *= mTransform; - mTransform = scaling; - } - - domMatrix* matrix = daeSafeCast(element); - if (matrix) - { - domFloat4x4 dom_value = matrix->getValue(); - - LLMatrix4 matrix_transform; - - for (int i = 0; i < 4; i++) - { - for(int j = 0; j < 4; j++) - { - matrix_transform.mMatrix[i][j] = dom_value[i + j*4]; - } - } - - matrix_transform *= mTransform; - mTransform = matrix_transform; - } - - domInstance_geometry* instance_geo = daeSafeCast(element); - if (instance_geo) - { - domGeometry* geo = daeSafeCast(instance_geo->getUrl().getElement()); - if (geo) - { - domMesh* mesh = daeSafeCast(geo->getDescendant(daeElement::matchType(domMesh::ID()))); - if (mesh) - { - LLModel* model = mModel[mesh]; - if (model) - { - LLMatrix4 transformation = mTransform; - - std::vector materials = getMaterials(model, instance_geo); - - // adjust the transformation to compensate for mesh normalization - LLVector3 mesh_scale_vector; - LLVector3 mesh_translation_vector; - model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); - - LLMatrix4 mesh_translation; - mesh_translation.setTranslation(mesh_translation_vector); - mesh_translation *= transformation; - transformation = mesh_translation; - - LLMatrix4 mesh_scale; - mesh_scale.initScale(mesh_scale_vector); - mesh_scale *= transformation; - transformation = mesh_scale; - - mScene[transformation].push_back(LLModelInstance(model, transformation, materials)); - - stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); - } - } - } - } - - domInstance_node* instance_node = daeSafeCast(element); - if (instance_node) - { - daeElement* instance = instance_node->getUrl().getElement(); - if (instance) - { - processElement(instance); - } - } - - //process children - daeTArray< daeSmartRef > children = element->getChildren(); - for (S32 i = 0; i < children.getCount(); i++) - { - processElement(children[i]); - } - - domNode* node = daeSafeCast(element); - if (node) - { //this element was a node, restore transform before processiing siblings - mTransform = saved_transform; - } -} - -std::vector LLModelLoader::getMaterials(LLModel* model, domInstance_geometry* instance_geo) -{ - std::vector materials; - for (int i = 0; i < model->mMaterialList.size(); i++) - { - LLImportMaterial import_material; - - domInstance_material* instance_mat = NULL; - - domBind_material::domTechnique_common* technique = - daeSafeCast(instance_geo->getDescendant(daeElement::matchType(domBind_material::domTechnique_common::ID()))); - - if (technique) - { - daeTArray< daeSmartRef > inst_materials = technique->getChildrenByType(); - for (int j = 0; j < inst_materials.getCount(); j++) - { - std::string symbol(inst_materials[j]->getSymbol()); - - if (symbol == model->mMaterialList[i]) // found the binding - { - instance_mat = inst_materials[j]; - } - } - } - - if (instance_mat) - { - domMaterial* material = daeSafeCast(instance_mat->getTarget().getElement()); - if (material) - { - domInstance_effect* instance_effect = - daeSafeCast(material->getDescendant(daeElement::matchType(domInstance_effect::ID()))); - if (instance_effect) - { - domEffect* effect = daeSafeCast(instance_effect->getUrl().getElement()); - if (effect) - { - domProfile_COMMON* profile = - daeSafeCast(effect->getDescendant(daeElement::matchType(domProfile_COMMON::ID()))); - if (profile) - { - import_material = profileToMaterial(profile); - } - } - } - } - } - - materials.push_back(import_material); - } - - return materials; -} - -LLImportMaterial LLModelLoader::profileToMaterial(domProfile_COMMON* material) -{ - LLImportMaterial mat; - mat.mFullbright = FALSE; - - daeElement* diffuse = material->getDescendant("diffuse"); - if (diffuse) - { - domCommon_color_or_texture_type_complexType::domTexture* texture = - daeSafeCast(diffuse->getDescendant("texture")); - if (texture) - { - domCommon_newparam_type_Array newparams = material->getNewparam_array(); - for (S32 i = 0; i < newparams.getCount(); i++) - { - domFx_surface_common* surface = newparams[i]->getSurface(); - if (surface) - { - domFx_surface_init_common* init = surface->getFx_surface_init_common(); - if (init) - { - domFx_surface_init_from_common_Array init_from = init->getInit_from_array(); - - if (init_from.getCount() > i) - { - domImage* image = daeSafeCast(init_from[i]->getValue().getElement()); - if (image) - { - // we only support init_from now - embedded data will come later - domImage::domInit_from* init = image->getInit_from(); - if (init) - { - std::string filename = cdom::uriToNativePath(init->getValue().str()); - - mat.mDiffuseMap = LLViewerTextureManager::getFetchedTextureFromUrl("file://" + filename, TRUE, LLViewerTexture::BOOST_PREVIEW); - mat.mDiffuseMap->setLoadedCallback(LLModelPreview::textureLoadedCallback, 0, TRUE, FALSE, this->mPreview, NULL, FALSE); - - mat.mDiffuseMap->forceToSaveRawImage(); - mat.mDiffuseMapFilename = filename; - mat.mDiffuseMapLabel = getElementLabel(material); - } - } - } - } - } - } - } - - domCommon_color_or_texture_type_complexType::domColor* color = - daeSafeCast(diffuse->getDescendant("color")); - if (color) - { - domFx_color_common domfx_color = color->getValue(); - LLColor4 value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]); - mat.mDiffuseColor = value; - } - } - - daeElement* emission = material->getDescendant("emission"); - if (emission) - { - LLColor4 emission_color = getDaeColor(emission); - if (((emission_color[0] + emission_color[1] + emission_color[2]) / 3.0) > 0.25) - { - mat.mFullbright = TRUE; - } - } - - return mat; -} - -// try to get a decent label for this element -std::string LLModelLoader::getElementLabel(daeElement *element) -{ - // if we have a name attribute, use it - std::string name = element->getAttribute("name"); - if (name.length()) - { - return name; - } - - // if we have an ID attribute, use it - if (element->getID()) - { - return std::string(element->getID()); - } - - // if we have a parent, use it - daeElement* parent = element->getParent(); - if (parent) - { - // if parent has a name, use it - std::string name = parent->getAttribute("name"); - if (name.length()) - { - return name; - } - - // if parent has an ID, use it - if (parent->getID()) - { - return std::string(parent->getID()); - } - } - - // try to use our type - daeString element_name = element->getElementName(); - if (element_name) - { - return std::string(element_name); - } - - // if all else fails, use "object" - return std::string("object"); -} - -LLColor4 LLModelLoader::getDaeColor(daeElement* element) -{ - LLColor4 value; - domCommon_color_or_texture_type_complexType::domColor* color = - daeSafeCast(element->getDescendant("color")); - if (color) - { - domFx_color_common domfx_color = color->getValue(); - value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]); - } - - return value; -} - -//----------------------------------------------------------------------------- -// LLModelPreview -//----------------------------------------------------------------------------- - -LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) -: LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE), LLMutex(NULL) -{ - mNeedsUpdate = TRUE; - mCameraDistance = 0.f; - mCameraYaw = 0.f; - mCameraPitch = 0.f; - mCameraZoom = 1.f; - mTextureName = 0; - mPreviewLOD = 0; - mModelLoader = NULL; - mMaxTriangleLimit = 0; - mDirty = false; - mGenLOD = false; - mLoading = false; - mGroup = 0; - mBuildShareTolerance = 0.f; - mBuildQueueMode = GLOD_QUEUE_GREEDY; - mBuildBorderMode = GLOD_BORDER_UNLOCK; - mBuildOperator = GLOD_OPERATOR_HALF_EDGE_COLLAPSE; - - mViewOption["show_textures"] = false; - - mFMP = fmp; - - glodInit(); -} - -LLModelPreview::~LLModelPreview() -{ - if (mModelLoader) - { - delete mModelLoader; - mModelLoader = NULL; - } - - //*HACK : *TODO : turn this back on when we understand why this crashes - //glodShutdown(); -} - -U32 LLModelPreview::calcResourceCost() -{ - assert_main_thread(); - - rebuildUploadData(); - - if ( mModelLoader->getLoadState() != LLModelLoader::ERROR_PARSING ) - { - mFMP->childEnable("ok_btn"); - } - - U32 cost = 0; - std::set accounted; - U32 num_points = 0; - U32 num_hulls = 0; - - F32 debug_scale = mFMP->childGetValue("import_scale").asReal(); - - F32 streaming_cost = 0.f; - F32 physics_cost = 0.f; - for (U32 i = 0; i < mUploadData.size(); ++i) - { - LLModelInstance& instance = mUploadData[i]; - - if (accounted.find(instance.mModel) == accounted.end()) - { - accounted.insert(instance.mModel); - - LLModel::convex_hull_decomposition& decomp = - instance.mLOD[LLModel::LOD_PHYSICS] ? - instance.mLOD[LLModel::LOD_PHYSICS]->mConvexHullDecomp : - instance.mModel->mConvexHullDecomp; - - LLSD ret = LLModel::writeModel( - "", - instance.mLOD[4], - instance.mLOD[3], - instance.mLOD[2], - instance.mLOD[1], - instance.mLOD[0], - decomp, - mFMP->childGetValue("upload_skin").asBoolean(), - mFMP->childGetValue("upload_joints").asBoolean(), - TRUE); - cost += gMeshRepo.calcResourceCost(ret); - - num_hulls += decomp.size(); - for (U32 i = 0; i < decomp.size(); ++i) - { - num_points += decomp[i].size(); - } - - //calculate streaming cost - LLMatrix4 transformation = instance.mTransform; - - LLVector3 position = LLVector3(0, 0, 0) * transformation; - - LLVector3 x_transformed = LLVector3(1, 0, 0) * transformation - position; - LLVector3 y_transformed = LLVector3(0, 1, 0) * transformation - position; - LLVector3 z_transformed = LLVector3(0, 0, 1) * transformation - position; - F32 x_length = x_transformed.normalize(); - F32 y_length = y_transformed.normalize(); - F32 z_length = z_transformed.normalize(); - LLVector3 scale = LLVector3(x_length, y_length, z_length); - - F32 radius = scale.length()*debug_scale; - - streaming_cost += LLMeshRepository::getStreamingCost(ret, radius); - } - } - - //mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[HULLS]", llformat("%d",num_hulls)); - //mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[POINTS]", llformat("%d",num_points)); - mFMP->childSetTextArg("streaming cost", "[COST]", llformat("%.3f", streaming_cost)); - mFMP->childSetTextArg("physics cost", "[COST]", llformat("%.3f", physics_cost)); - F32 scale = mFMP->childGetValue("import_scale").asReal()*2.f; - mFMP->childSetTextArg("import_dimensions", "[X]", llformat("%.3f", mPreviewScale[0]*scale)); - mFMP->childSetTextArg("import_dimensions", "[Y]", llformat("%.3f", mPreviewScale[1]*scale)); - mFMP->childSetTextArg("import_dimensions", "[Z]", llformat("%.3f", mPreviewScale[2]*scale)); - - updateStatusMessages(); - - return cost; -} - -void LLModelPreview::rebuildUploadData() -{ - assert_main_thread(); - - mUploadData.clear(); - mTextureSet.clear(); - - //fill uploaddata instance vectors from scene data - - std::string requested_name = mFMP->getChild("description_form")->getValue().asString(); - - - LLSpinCtrl* scale_spinner = mFMP->getChild("import_scale"); - - if (!scale_spinner) - { - llerrs << "floater_model_preview.xml MUST contain import_scale spinner." << llendl; - } - - F32 scale = scale_spinner->getValue().asReal(); - - LLMatrix4 scale_mat; - scale_mat.initScale(LLVector3(scale, scale, scale)); - - F32 max_scale = 0.f; - - if ( mBaseScene.size() > 0 ) - { - mFMP->childEnable("ok_btn"); - } - - for (LLModelLoader::scene::iterator iter = mBaseScene.begin(); iter != mBaseScene.end(); ++iter) - { //for each transform in scene - LLMatrix4 mat = iter->first; - - // compute position - LLVector3 position = LLVector3(0, 0, 0) * mat; - - // compute scale - LLVector3 x_transformed = LLVector3(1, 0, 0) * mat - position; - LLVector3 y_transformed = LLVector3(0, 1, 0) * mat - position; - LLVector3 z_transformed = LLVector3(0, 0, 1) * mat - position; - F32 x_length = x_transformed.normalize(); - F32 y_length = y_transformed.normalize(); - F32 z_length = z_transformed.normalize(); - - max_scale = llmax(llmax(llmax(max_scale, x_length), y_length), z_length); - - mat *= scale_mat; - - for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) - { //for each instance with said transform applied - LLModelInstance instance = *model_iter; - - LLModel* base_model = instance.mModel; - if (base_model) - { - base_model->mRequestedLabel = requested_name; - } - - S32 idx = 0; - for (idx = 0; idx < mBaseModel.size(); ++idx) - { //find reference instance for this model - if (mBaseModel[idx] == base_model) - { - break; - } - } - - for (U32 i = 0; i < LLModel::NUM_LODS; i++) - { //fill LOD slots based on reference model index - if (!mModel[i].empty()) - { - instance.mLOD[i] = mModel[i][idx]; - } - else - { - instance.mLOD[i] = NULL; - } - } - - instance.mTransform = mat; - mUploadData.push_back(instance); - } - } - - F32 max_import_scale = DEFAULT_MAX_PRIM_SCALE/max_scale; - - scale_spinner->setMaxValue(max_import_scale); - - if (max_import_scale < scale) - { - scale_spinner->setValue(max_import_scale); - } - -} - - -void LLModelPreview::clearModel(S32 lod) -{ - if (lod < 0 || lod > LLModel::LOD_PHYSICS) - { - return; - } - - mVertexBuffer[lod].clear(); - mModel[lod].clear(); - mScene[lod].clear(); -} - -void LLModelPreview::loadModel(std::string filename, S32 lod) -{ - assert_main_thread(); - - LLMutexLock lock(this); - - if (mModelLoader) - { - delete mModelLoader; - mModelLoader = NULL; - } - - if (filename.empty()) - { - if (mBaseModel.empty()) - { - // this is the initial file picking. Close the whole floater - // if we don't have a base model to show for high LOD. - mFMP->closeFloater(false); - } - - mLoading = false; - return; - } - - mLODFile[lod] = filename; - - if (lod == LLModel::LOD_HIGH) - { - clearGLODGroup(); - } - - mModelLoader = new LLModelLoader(filename, lod, this); - - mModelLoader->start(); - - mFMP->childSetTextArg("status", "[STATUS]", mFMP->getString("status_reading_file")); - - setPreviewLOD(lod); - - if ( mModelLoader->getLoadState() == LLModelLoader::ERROR_PARSING ) - { - mFMP->childDisable("ok_btn"); - } - - if (lod == mPreviewLOD) - { - mFMP->childSetText("lod_file", mLODFile[mPreviewLOD]); - } - else if (lod == LLModel::LOD_PHYSICS) - { - mFMP->childSetText("physics_file", mLODFile[lod]); - } - - mFMP->openFloater(); -} - -void LLModelPreview::setPhysicsFromLOD(S32 lod) -{ - assert_main_thread(); - - if (lod >= 0 && lod <= 3) - { - mModel[LLModel::LOD_PHYSICS] = mModel[lod]; - mScene[LLModel::LOD_PHYSICS] = mScene[lod]; - mLODFile[LLModel::LOD_PHYSICS].clear(); - mFMP->childSetText("physics_file", mLODFile[LLModel::LOD_PHYSICS]); - mVertexBuffer[LLModel::LOD_PHYSICS].clear(); - rebuildUploadData(); - refresh(); - updateStatusMessages(); - } -} - -void LLModelPreview::clearIncompatible(S32 lod) -{ - for (U32 i = 0; i <= LLModel::LOD_HIGH; i++) - { //clear out any entries that aren't compatible with this model - if (i != lod) - { - if (mModel[i].size() != mModel[lod].size()) - { - mModel[i].clear(); - mScene[i].clear(); - mVertexBuffer[i].clear(); - - if (i == LLModel::LOD_HIGH) - { - mBaseModel = mModel[lod]; - clearGLODGroup(); - mBaseScene = mScene[lod]; - mVertexBuffer[5].clear(); - } - } - } - } -} - -void LLModelPreview::clearGLODGroup() -{ - if (mGroup) - { - for (std::map, U32>::iterator iter = mObject.begin(); iter != mObject.end(); ++iter) - { - glodDeleteObject(iter->second); - stop_gloderror(); - } - mObject.clear(); - - glodDeleteGroup(mGroup); - stop_gloderror(); - mGroup = 0; - } -} - -void LLModelPreview::loadModelCallback(S32 lod) -{ - assert_main_thread(); - - LLMutexLock lock(this); - if (!mModelLoader) - { - return; - } - - mModel[lod] = mModelLoader->mModelList; - mScene[lod] = mModelLoader->mScene; - mVertexBuffer[lod].clear(); - - if (lod == LLModel::LOD_PHYSICS) - { - mPhysicsMesh.clear(); - } - - setPreviewLOD(lod); - - - if (lod == LLModel::LOD_HIGH) - { //save a copy of the highest LOD for automatic LOD manipulation - if (mBaseModel.empty()) - { //first time we've loaded a model, auto-gen LoD - mGenLOD = true; - } - - mBaseModel = mModel[lod]; - clearGLODGroup(); - - mBaseScene = mScene[lod]; - mVertexBuffer[5].clear(); - } - - clearIncompatible(lod); - - mDirty = true; - - if (lod == LLModel::LOD_HIGH) - { - resetPreviewTarget(); - } - - mLoading = false; - refresh(); -} - -void LLModelPreview::resetPreviewTarget() -{ - mPreviewTarget = (mModelLoader->mExtents[0] + mModelLoader->mExtents[1]) * 0.5f; - mPreviewScale = (mModelLoader->mExtents[1] - mModelLoader->mExtents[0]) * 0.5f; - setPreviewTarget(mPreviewScale.magVec()*2.f); -} - -void LLModelPreview::generateNormals() -{ - assert_main_thread(); - - S32 which_lod = mPreviewLOD; - - - if (which_lod > 4 || which_lod < 0 || - mModel[which_lod].empty()) - { - return; - } - - F32 angle_cutoff = mFMP->childGetValue("crease_angle").asReal(); - - angle_cutoff *= DEG_TO_RAD; - - if (which_lod == 3 && !mBaseModel.empty()) - { - for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) - { - (*iter)->generateNormals(angle_cutoff); - } - - mVertexBuffer[5].clear(); - } - - for (LLModelLoader::model_list::iterator iter = mModel[which_lod].begin(); iter != mModel[which_lod].end(); ++iter) - { - (*iter)->generateNormals(angle_cutoff); - } - - mVertexBuffer[which_lod].clear(); - refresh(); - -} - -void LLModelPreview::consolidate() -{ - std::map > composite; - - LLMatrix4 identity; - - //bake out each node in current scene to composite - for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) - { //for each transform in current scene - LLMatrix4 mat = iter->first; - glh::matrix4f inv_trans = glh::matrix4f((F32*) mat.mMatrix).inverse().transpose(); - LLMatrix4 norm_mat(inv_trans.m); - - for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) - { //for each instance with that transform - LLModelInstance& source_instance = *model_iter; - LLModel* source = source_instance.mModel; - - if (!validate_model(source)) - { - llerrs << "Invalid model found!" << llendl; - } - - for (S32 i = 0; i < source->getNumVolumeFaces(); ++i) - { //for each face in instance - const LLVolumeFace& src_face = source->getVolumeFace(i); - LLImportMaterial& source_material = source_instance.mMaterial[i]; - - //get model in composite that is composite for this material - LLModel* model = NULL; - - if (composite.find(source_material) != composite.end()) - { - model = composite[source_material].rbegin()->mModel; - if (model->getVolumeFace(0).mNumVertices + src_face.mNumVertices > 65535) - { - model = NULL; - } - } - - if (model == NULL) - { //no model found, make new model - std::vector materials; - materials.push_back(source_material); - LLVolumeParams volume_params; - volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); - model = new LLModel(volume_params, 0.f); - model->mLabel = source->mLabel; - model->setNumVolumeFaces(0); - composite[source_material].push_back(LLModelInstance(model, identity, materials)); - } - - model->appendFace(src_face, source->mMaterialList[i], mat, norm_mat); - } - } - } - - - //condense composite into as few LLModel instances as possible - LLModelLoader::model_list new_model; - std::vector instance_list; - - LLVolumeParams volume_params; - volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); - - std::vector empty_material; - LLModelInstance cur_instance(new LLModel(volume_params, 0.f), identity, empty_material); - cur_instance.mModel->setNumVolumeFaces(0); - - BOOL first_transform = TRUE; - - LLModelLoader::scene new_scene; - LLVector3 min,max; - - for (std::map >::iterator iter = composite.begin(); - iter != composite.end(); - ++iter) - { - std::map >::iterator next_iter = iter; ++next_iter; - - for (std::vector::iterator instance_iter = iter->second.begin(); - instance_iter != iter->second.end(); - ++instance_iter) - { - LLModel* source = instance_iter->mModel; - - if (instance_iter->mMaterial.size() != 1) - { - llerrs << "WTF?" << llendl; - } - - if (source->getNumVolumeFaces() != 1) - { - llerrs << "WTF?" << llendl; - } - - if (source->mMaterialList.size() != 1) - { - llerrs << "WTF?" << llendl; - } - - cur_instance.mModel->addFace(source->getVolumeFace(0)); - cur_instance.mMaterial.push_back(instance_iter->mMaterial[0]); - cur_instance.mModel->mMaterialList.push_back(source->mMaterialList[0]); - - BOOL last_model = FALSE; - - std::vector::iterator next_instance = instance_iter; ++next_instance; - - if (next_iter == composite.end() && - next_instance == iter->second.end()) - { - last_model = TRUE; - } - - if (last_model || cur_instance.mModel->getNumVolumeFaces() >= MAX_MODEL_FACES) - { - cur_instance.mModel->mLabel = source->mLabel; - - cur_instance.mModel->optimizeVolumeFaces(); - cur_instance.mModel->normalizeVolumeFaces(); - - if (!validate_model(cur_instance.mModel)) - { - llerrs << "Invalid model detected." << llendl; - } - - new_model.push_back(cur_instance.mModel); - - LLMatrix4 transformation = LLMatrix4(); - - // adjust the transformation to compensate for mesh normalization - LLVector3 mesh_scale_vector; - LLVector3 mesh_translation_vector; - cur_instance.mModel->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); - - LLMatrix4 mesh_translation; - mesh_translation.setTranslation(mesh_translation_vector); - mesh_translation *= transformation; - transformation = mesh_translation; - - LLMatrix4 mesh_scale; - mesh_scale.initScale(mesh_scale_vector); - mesh_scale *= transformation; - transformation = mesh_scale; - - cur_instance.mTransform = transformation; - - new_scene[transformation].push_back(cur_instance); - stretch_extents(cur_instance.mModel, transformation, min, max, first_transform); - - if (!last_model) - { - cur_instance = LLModelInstance(new LLModel(volume_params, 0.f), identity, empty_material); - cur_instance.mModel->setNumVolumeFaces(0); - } - } - } - } - - mScene[mPreviewLOD] = new_scene; - mModel[mPreviewLOD] = new_model; - mVertexBuffer[mPreviewLOD].clear(); - - if (mPreviewLOD == LLModel::LOD_HIGH) - { - mBaseScene = new_scene; - mBaseModel = new_model; - clearGLODGroup(); - mVertexBuffer[5].clear(); - } - - mPreviewTarget = (min+max)*0.5f; - mPreviewScale = (max-min)*0.5f; - setPreviewTarget(mPreviewScale.magVec()*2.f); - - clearIncompatible(mPreviewLOD); - - mResourceCost = calcResourceCost(); - refresh(); -} - -void LLModelPreview::clearMaterials() -{ - for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) - { //for each transform in current scene - for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) - { //for each instance with that transform - LLModelInstance& source_instance = *model_iter; - LLModel* source = source_instance.mModel; - - for (S32 i = 0; i < source->getNumVolumeFaces(); ++i) - { //for each face in instance - LLImportMaterial& source_material = source_instance.mMaterial[i]; - - //clear material info - source_material.mDiffuseColor = LLColor4(1,1,1,1); - source_material.mDiffuseMap = NULL; - source_material.mDiffuseMapFilename.clear(); - source_material.mDiffuseMapLabel.clear(); - source_material.mFullbright = false; - } - } - } - - mVertexBuffer[mPreviewLOD].clear(); - - if (mPreviewLOD == LLModel::LOD_HIGH) - { - mBaseScene = mScene[mPreviewLOD]; - mBaseModel = mModel[mPreviewLOD]; - clearGLODGroup(); - mVertexBuffer[5].clear(); - } - - mResourceCost = calcResourceCost(); - refresh(); -} - -bool LLModelPreview::containsRiggedAsset( void ) -{ - //loop through the models and determine if any of them contained a rigged asset, and if so - //return true. - //This is used to cleanup the joint positions after a preview. - for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) - { - LLModel* pModel = *iter; - if ( pModel->mAlternateBindMatrix.size() > 0 ) - { - return true; - } - } - return false; -} -void LLModelPreview::genLODs(S32 which_lod, U32 decimation) -{ - if (mBaseModel.empty()) - { - return; - } - - if (which_lod == LLModel::LOD_PHYSICS) - { //clear physics mesh map - mPhysicsMesh.clear(); - } - - LLVertexBuffer::unbind(); - - stop_gloderror(); - static U32 cur_name = 1; - - S32 limit = -1; - - U32 triangle_count = 0; - - for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) - { - LLModel* mdl = *iter; - for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) - { - triangle_count += mdl->getVolumeFace(i).mNumIndices/3; - } - } - - U32 base_triangle_count = triangle_count; - - U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; - - U32 lod_mode = 0; - - LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode"); - if (iface) - { - lod_mode = iface->getFirstSelectedIndex(); - } - - F32 lod_error_threshold = mFMP->childGetValue("lod_error_threshold").asReal(); - - if (lod_mode == 0) - { - lod_mode = GLOD_TRIANGLE_BUDGET; - if (which_lod != -1) - { - limit = mFMP->childGetValue("lod_triangle_limit").asInteger(); - } - } - else - { - lod_mode = GLOD_ERROR_THRESHOLD; - } - - U32 build_operator = 0; - - iface = mFMP->childGetSelectionInterface("build_operator"); - if (iface) - { - build_operator = iface->getFirstSelectedIndex(); - } - - if (build_operator == 0) - { - build_operator = GLOD_OPERATOR_HALF_EDGE_COLLAPSE; - } - else - { - build_operator = GLOD_OPERATOR_EDGE_COLLAPSE; - } - - U32 queue_mode=0; - iface = mFMP->childGetSelectionInterface("queue_mode"); - if (iface) - { - queue_mode = iface->getFirstSelectedIndex(); - } - - if (queue_mode == 0) - { - queue_mode = GLOD_QUEUE_GREEDY; - } - else if (queue_mode == 1) - { - queue_mode = GLOD_QUEUE_LAZY; - } - else - { - queue_mode = GLOD_QUEUE_INDEPENDENT; - } - - U32 border_mode = 0; - - iface = mFMP->childGetSelectionInterface("border_mode"); - if (iface) - { - border_mode = iface->getFirstSelectedIndex(); - } - - if (border_mode == 0) - { - border_mode = GLOD_BORDER_UNLOCK; - } - else - { - border_mode = GLOD_BORDER_LOCK; - } - - bool object_dirty = false; - if (border_mode != mBuildBorderMode) - { - mBuildBorderMode = border_mode; - object_dirty = true; - } - - if (queue_mode != mBuildQueueMode) - { - mBuildQueueMode = queue_mode; - object_dirty = true; - } - - if (build_operator != mBuildOperator) - { - mBuildOperator = build_operator; - object_dirty = true; - } - - F32 share_tolerance = mFMP->childGetValue("share_tolerance").asReal(); - if (share_tolerance != mBuildShareTolerance) - { - mBuildShareTolerance = share_tolerance; - object_dirty = true; - } - - if (mGroup == 0) - { - object_dirty = true; - mGroup = cur_name++; - glodNewGroup(mGroup); - } - - if (object_dirty) - { - for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) - { //build GLOD objects for each model in base model list - LLModel* mdl = *iter; - - if (mObject[mdl] != 0) - { - glodDeleteObject(mObject[mdl]); - } - - mObject[mdl] = cur_name++; - - glodNewObject(mObject[mdl], mGroup, GLOD_DISCRETE); - stop_gloderror(); - - if (iter == mBaseModel.begin() && !mdl->mSkinWeights.empty()) - { //regenerate vertex buffer for skinned models to prevent animation feedback during LOD generation - mVertexBuffer[5].clear(); - } - - if (mVertexBuffer[5].empty()) - { - genBuffers(5, false); - } - - U32 tri_count = 0; - for (U32 i = 0; i < mVertexBuffer[5][mdl].size(); ++i) - { - mVertexBuffer[5][mdl][i]->setBuffer(type_mask); - U32 num_indices = mVertexBuffer[5][mdl][i]->getNumIndices(); - if (num_indices > 2) - { - glodInsertElements(mObject[mdl], i, GL_TRIANGLES, num_indices, GL_UNSIGNED_SHORT, mVertexBuffer[5][mdl][i]->getIndicesPointer(), 0, 0.f); - } - tri_count += num_indices/3; - stop_gloderror(); - } - - glodObjectParameteri(mObject[mdl], GLOD_BUILD_OPERATOR, build_operator); - stop_gloderror(); - - glodObjectParameteri(mObject[mdl], GLOD_BUILD_QUEUE_MODE, queue_mode); - stop_gloderror(); - - glodObjectParameteri(mObject[mdl], GLOD_BUILD_BORDER_MODE, border_mode); - stop_gloderror(); - - glodObjectParameterf(mObject[mdl], GLOD_BUILD_SHARE_TOLERANCE, share_tolerance); - stop_gloderror(); - - glodBuildObject(mObject[mdl]); - stop_gloderror(); - } - } - - - S32 start = LLModel::LOD_HIGH; - S32 end = 0; - - if (which_lod != -1) - { - start = end = which_lod; - } - else - { - //SH-632 -- incremenet triangle count to avoid removing any triangles from - //highest LoD when auto-generating LoD - triangle_count++; - } - - - mMaxTriangleLimit = base_triangle_count; - - for (S32 lod = start; lod >= end; --lod) - { - if (which_lod == -1) - { - if (lod < start) - { - triangle_count /= decimation; - } - } - else - { - triangle_count = limit; - } - - mModel[lod].clear(); - mModel[lod].resize(mBaseModel.size()); - mVertexBuffer[lod].clear(); - - U32 actual_tris = 0; - U32 actual_verts = 0; - U32 submeshes = 0; - - glodGroupParameteri(mGroup, GLOD_ADAPT_MODE, lod_mode); - stop_gloderror(); - - glodGroupParameteri(mGroup, GLOD_ERROR_MODE, GLOD_OBJECT_SPACE_ERROR); - stop_gloderror(); - - glodGroupParameteri(mGroup, GLOD_MAX_TRIANGLES, triangle_count); - stop_gloderror(); - - glodGroupParameterf(mGroup, GLOD_OBJECT_SPACE_ERROR_THRESHOLD, lod_error_threshold); - stop_gloderror(); - - glodAdaptGroup(mGroup); - stop_gloderror(); - - for (U32 mdl_idx = 0; mdl_idx < mBaseModel.size(); ++mdl_idx) - { - LLModel* base = mBaseModel[mdl_idx]; - - GLint patch_count = 0; - glodGetObjectParameteriv(mObject[base], GLOD_NUM_PATCHES, &patch_count); - stop_gloderror(); - - LLVolumeParams volume_params; - volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); - mModel[lod][mdl_idx] = new LLModel(volume_params, 0.f); - - GLint* sizes = new GLint[patch_count*2]; - glodGetObjectParameteriv(mObject[base], GLOD_PATCH_SIZES, sizes); - stop_gloderror(); - - GLint* names = new GLint[patch_count]; - glodGetObjectParameteriv(mObject[base], GLOD_PATCH_NAMES, names); - stop_gloderror(); - - mModel[lod][mdl_idx]->setNumVolumeFaces(patch_count); - - LLModel* target_model = mModel[lod][mdl_idx]; - - for (GLint i = 0; i < patch_count; ++i) - { - LLPointer buff = new LLVertexBuffer(type_mask, 0); - - if (sizes[i*2+1] > 0 && sizes[i*2] > 0) - { - buff->allocateBuffer(sizes[i*2+1], sizes[i*2], true); - buff->setBuffer(type_mask); - glodFillElements(mObject[base], names[i], GL_UNSIGNED_SHORT, buff->getIndicesPointer()); - stop_gloderror(); - } - else - { //this face was eliminated, create a dummy triangle (one vertex, 3 indices, all 0) - buff->allocateBuffer(1, 3, true); - memset(buff->getMappedData(), 0, buff->getSize()); - memset(buff->getIndicesPointer(), 0, buff->getIndicesSize()); - } - - buff->validateRange(0, buff->getNumVerts()-1, buff->getNumIndices(), 0); - - LLStrider pos; - LLStrider norm; - LLStrider tc; - LLStrider index; - - buff->getVertexStrider(pos); - buff->getNormalStrider(norm); - buff->getTexCoord0Strider(tc); - buff->getIndexStrider(index); - - target_model->setVolumeFaceData(names[i], pos, norm, tc, index, buff->getNumVerts(), buff->getNumIndices()); - actual_tris += buff->getNumIndices()/3; - actual_verts += buff->getNumVerts(); - ++submeshes; - - if (!validate_face(target_model->getVolumeFace(names[i]))) - { - llerrs << "Invalid face generated during LOD generation." << llendl; - } - } - - //blind copy skin weights and just take closest skin weight to point on - //decimated mesh for now (auto-generating LODs with skin weights is still a bit - //of an open problem). - target_model->mPosition = base->mPosition; - target_model->mSkinWeights = base->mSkinWeights; - target_model->mJointMap = base->mJointMap; - target_model->mJointList = base->mJointList; - target_model->mInvBindMatrix = base->mInvBindMatrix; - target_model->mBindShapeMatrix = base->mBindShapeMatrix; - target_model->mAlternateBindMatrix = base->mAlternateBindMatrix; - //copy material list - target_model->mMaterialList = base->mMaterialList; - - if (!validate_model(target_model)) - { - llerrs << "Invalid model generated when creating LODs" << llendl; - } - - delete [] sizes; - delete [] names; - } - - //rebuild scene based on mBaseScene - mScene[lod].clear(); - mScene[lod] = mBaseScene; - - for (U32 i = 0; i < mBaseModel.size(); ++i) - { - LLModel* mdl = mBaseModel[i]; - LLModel* target = mModel[lod][i]; - if (target) - { - for (LLModelLoader::scene::iterator iter = mScene[lod].begin(); iter != mScene[lod].end(); ++iter) - { - for (U32 j = 0; j < iter->second.size(); ++j) - { - if (iter->second[j].mModel == mdl) - { - iter->second[j].mModel = target; - } - } - } - } - } - } - - mResourceCost = calcResourceCost(); - - /*if (which_lod == -1 && mScene[LLModel::LOD_PHYSICS].empty()) - { //build physics scene - mScene[LLModel::LOD_PHYSICS] = mScene[LLModel::LOD_LOW]; - mModel[LLModel::LOD_PHYSICS] = mModel[LLModel::LOD_LOW]; - - for (U32 i = 1; i < mModel[LLModel::LOD_PHYSICS].size(); ++i) - { - mPhysicsQ.push(mModel[LLModel::LOD_PHYSICS][i]); - } - }*/ -} - -void LLModelPreview::updateStatusMessages() -{ - assert_main_thread(); - - //triangle/vertex/submesh count for each mesh asset for each lod - std::vector tris[LLModel::NUM_LODS]; - std::vector verts[LLModel::NUM_LODS]; - std::vector submeshes[LLModel::NUM_LODS]; - - //total triangle/vertex/submesh count for each lod - S32 total_tris[LLModel::NUM_LODS]; - S32 total_verts[LLModel::NUM_LODS]; - S32 total_submeshes[LLModel::NUM_LODS]; - - for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) - { - //initialize total for this lod to 0 - total_tris[lod] = total_verts[lod] = total_submeshes[lod] = 0; - - for (U32 i = 0; i < mModel[lod].size(); ++i) - { //for each model in the lod - S32 cur_tris = 0; - S32 cur_verts = 0; - S32 cur_submeshes = mModel[lod][i]->getNumVolumeFaces(); - - for (S32 j = 0; j < cur_submeshes; ++j) - { //for each submesh (face), add triangles and vertices to current total - const LLVolumeFace& face = mModel[lod][i]->getVolumeFace(j); - cur_tris += face.mNumIndices/3; - cur_verts += face.mNumVertices; - } - - //add this model to the lod total - total_tris[lod] += cur_tris; - total_verts[lod] += cur_verts; - total_submeshes[lod] += cur_submeshes; - - //store this model's counts to asset data - tris[lod].push_back(cur_tris); - verts[lod].push_back(cur_verts); - submeshes[lod].push_back(cur_submeshes); - } - } - - if (mMaxTriangleLimit == 0) - { - mMaxTriangleLimit = total_tris[LLModel::LOD_HIGH]; - } - - - mFMP->childSetTextArg("submeshes_info", "[SUBMESHES]", llformat("%d", total_submeshes[LLModel::LOD_HIGH])); - - std::string mesh_status_na = mFMP->getString("mesh_status_na"); - - S32 upload_status[LLModel::LOD_HIGH+1]; - - bool upload_ok = true; - - for (S32 lod = 0; lod <= LLModel::LOD_HIGH; ++lod) - { - upload_status[lod] = 0; - - std::string message = "mesh_status_good"; - - if (total_tris[lod] > 0) - { - mFMP->childSetText(lod_triangles_name[lod], llformat("%d", total_tris[lod])); - mFMP->childSetText(lod_vertices_name[lod], llformat("%d", total_verts[lod])); - } - else - { - if (lod == LLModel::LOD_HIGH) - { - upload_status[lod] = 2; - message = "mesh_status_missing_lod"; - } - else - { - for (S32 i = lod-1; i >= 0; --i) - { - if (total_tris[i] > 0) - { - upload_status[lod] = 2; - message = "mesh_status_missing_lod"; - } - } - } - - mFMP->childSetText(lod_triangles_name[lod], mesh_status_na); - mFMP->childSetText(lod_vertices_name[lod], mesh_status_na); - } - - const U32 lod_high = LLModel::LOD_HIGH; - - if (lod != lod_high) - { - if (total_submeshes[lod] && total_submeshes[lod] != total_submeshes[lod_high]) - { //number of submeshes is different - message = "mesh_status_submesh_mismatch"; - upload_status[lod] = 2; - } - else if (!tris[lod].empty() && tris[lod].size() != tris[lod_high].size()) - { //number of meshes is different - message = "mesh_status_mesh_mismatch"; - upload_status[lod] = 2; - } - else if (!verts[lod].empty()) - { - for (U32 i = 0; i < verts[lod].size(); ++i) - { - S32 max_verts = i < verts[lod+1].size() ? verts[lod+1][i] : 0; - - if (max_verts > 0) - { - if (verts[lod][i] > max_verts) - { //too many vertices in this lod - message = "mesh_status_too_many_vertices"; - upload_status[lod] = 2; - } - } - } - } - } - - LLIconCtrl* icon = mFMP->getChild(lod_icon_name[lod]); - LLUIImagePtr img = LLUI::getUIImage(lod_status_image[upload_status[lod]]); - icon->setVisible(true); - icon->setImage(img); - - if (upload_status[lod] >= 2) - { - upload_ok = false; - } - - if (lod == mPreviewLOD) - { - mFMP->childSetText("lod_status_message_text", mFMP->getString(message)); - icon = mFMP->getChild("lod_status_message_icon"); - icon->setImage(img); - } - } - - bool errorStateFromLoader = mModelLoader->getLoadState() == LLModelLoader::ERROR_PARSING ? true : false; - - if ( upload_ok && !errorStateFromLoader ) - { - mFMP->childEnable("ok_btn"); - } - else - { - mFMP->childDisable("ok_btn"); - } - - //add up physics triangles etc - S32 start = 0; - S32 end = mModel[LLModel::LOD_PHYSICS].size(); - - S32 phys_tris = 0; - S32 phys_hulls = 0; - S32 phys_points = 0; - - for (S32 i = start; i < end; ++i) - { //add up hulls and points and triangles for selected mesh(es) - LLModel* model = mModel[LLModel::LOD_PHYSICS][i]; - S32 cur_submeshes = model->getNumVolumeFaces(); - - LLModel::convex_hull_decomposition& decomp = model->mConvexHullDecomp; - - if (!decomp.empty()) - { - phys_hulls += decomp.size(); - for (U32 i = 0; i < decomp.size(); ++i) - { - phys_points += decomp[i].size(); - } - } - else - { //choose physics shape OR decomposition, can't use both - for (S32 j = 0; j < cur_submeshes; ++j) - { //for each submesh (face), add triangles and vertices to current total - const LLVolumeFace& face = model->getVolumeFace(j); - phys_tris += face.mNumIndices/3; - } - } - } - - if (phys_tris > 0) - { - mFMP->childSetTextArg("physics_triangles", "[TRIANGLES]", llformat("%d", phys_tris)); - } - else - { - mFMP->childSetTextArg("physics_triangles", "[TRIANGLES]", mesh_status_na); - } - - if (phys_hulls > 0) - { - mFMP->childSetTextArg("physics_hulls", "[HULLS]", llformat("%d", phys_hulls)); - mFMP->childSetTextArg("physics_points", "[POINTS]", llformat("%d", phys_points)); - } - else - { - mFMP->childSetTextArg("physics_hulls", "[HULLS]", mesh_status_na); - mFMP->childSetTextArg("physics_points", "[POINTS]", mesh_status_na); - } - - LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; - if (fmp) - { - if (phys_tris > 0 || phys_hulls > 0) - { - if (!fmp->isViewOptionEnabled("show_physics")) - { - fmp->enableViewOption("show_physics"); - mViewOption["show_physics"] = true; - } - } - else - { - fmp->disableViewOption("show_physics"); - mViewOption["show_physics"] = false; - - } - - //bool use_hull = fmp->childGetValue("physics_use_hull").asBoolean(); - - //fmp->childSetEnabled("physics_optimize", !use_hull); - - bool enable = phys_tris > 0 || phys_hulls > 0; - //enable = enable && !use_hull && fmp->childGetValue("physics_optimize").asBoolean(); - - //enable/disable "analysis" UI - LLPanel* panel = fmp->getChild("physics analysis"); - LLView* child = panel->getFirstChild(); - while (child) - { - child->setEnabled(enable); - child = panel->findNextSibling(child); - } - - enable = phys_hulls > 0; - //enable/disable "simplification" UI - panel = fmp->getChild("physics simplification"); - child = panel->getFirstChild(); - while (child) - { - child->setEnabled(enable); - child = panel->findNextSibling(child); - } - } - - const char* lod_controls[] = - { - "lod_mode", - "lod_triangle_limit", - "lod_error_tolerance", - "build_operator_text", - "queue_mode_text", - "border_mode_text", - "share_tolerance_text", - "build_operator", - "queue_mode", - "border_mode", - "share_tolerance" - }; - const U32 num_lod_controls = sizeof(lod_controls)/sizeof(char*); - - const char* file_controls[] = - { - "lod_browse", - "lod_file" - }; - const U32 num_file_controls = sizeof(file_controls)/sizeof(char*); - - if (fmp) - { - //enable/disable controls based on radio groups - if (mFMP->childGetValue("lod_from_file").asBoolean()) - { - fmp->mLODMode[mPreviewLOD] = 0; - for (U32 i = 0; i < num_file_controls; ++i) - { - mFMP->childEnable(file_controls[i]); - } - - for (U32 i = 0; i < num_lod_controls; ++i) - { - mFMP->childDisable(lod_controls[i]); - } - } - else if (mFMP->childGetValue("lod_none").asBoolean()) - { - fmp->mLODMode[mPreviewLOD] = 2; - for (U32 i = 0; i < num_file_controls; ++i) - { - mFMP->childDisable(file_controls[i]); - } - - for (U32 i = 0; i < num_lod_controls; ++i) - { - mFMP->childDisable(lod_controls[i]); - } - - if (!mModel[mPreviewLOD].empty()) - { - mModel[mPreviewLOD].clear(); - mScene[mPreviewLOD].clear(); - mVertexBuffer[mPreviewLOD].clear(); - - //this can cause phasing issues with the UI, so reenter this function and return - updateStatusMessages(); - return; - } - } - else - { // auto generate, also the default case for wizard which has no radio selection - fmp->mLODMode[mPreviewLOD] = 1; - - for (U32 i = 0; i < num_file_controls; ++i) - { - mFMP->childDisable(file_controls[i]); - } - - for (U32 i = 0; i < num_lod_controls; ++i) - { - mFMP->childEnable(lod_controls[i]); - } - - //if (threshold) - { - U32 lod_mode = 0; - LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode"); - if (iface) - { - lod_mode = iface->getFirstSelectedIndex(); - } - - LLSpinCtrl* threshold = mFMP->getChild("lod_error_threshold"); - LLSpinCtrl* limit = mFMP->getChild("lod_triangle_limit"); - - limit->setMaxValue(mMaxTriangleLimit); - limit->setValue(total_tris[mPreviewLOD]); - - if (lod_mode == 0) - { - limit->setVisible(true); - threshold->setVisible(false); - - limit->setMaxValue(mMaxTriangleLimit); - } - else - { - limit->setVisible(false); - threshold->setVisible(true); - } - } - } - } - - if (mFMP->childGetValue("physics_load_from_file").asBoolean()) - { - mFMP->childDisable("physics_lod_combo"); - mFMP->childEnable("physics_file"); - mFMP->childEnable("physics_browse"); - } - else - { - mFMP->childEnable("physics_lod_combo"); - mFMP->childDisable("physics_file"); - mFMP->childDisable("physics_browse"); - } -} - -void LLModelPreview::setPreviewTarget(F32 distance) -{ - mCameraDistance = distance; - mCameraZoom = 1.f; - mCameraPitch = 0.f; - mCameraYaw = 0.f; - mCameraOffset.clearVec(); -} - -void LLModelPreview::clearBuffers() -{ - for (U32 i = 0; i < 6; i++) - { - mVertexBuffer[i].clear(); - } -} - -void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights) -{ - U32 tri_count = 0; - U32 vertex_count = 0; - U32 mesh_count = 0; - - LLModelLoader::model_list* model = NULL; - - if (lod < 0 || lod > 4) - { - model = &mBaseModel; - lod = 5; - } - else - { - model = &(mModel[lod]); - } - - if (!mVertexBuffer[lod].empty()) - { - mVertexBuffer[lod].clear(); - } - - mVertexBuffer[lod].clear(); - - LLModelLoader::model_list::iterator base_iter = mBaseModel.begin(); - - for (LLModelLoader::model_list::iterator iter = model->begin(); iter != model->end(); ++iter) - { - LLModel* mdl = *iter; - if (!mdl) - { - continue; - } - - LLModel* base_mdl = *base_iter; - base_iter++; - - for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) - { - const LLVolumeFace &vf = mdl->getVolumeFace(i); - U32 num_vertices = vf.mNumVertices; - U32 num_indices = vf.mNumIndices; - - if (!num_vertices || ! num_indices) - { - continue; - } - - LLVertexBuffer* vb = NULL; - - bool skinned = include_skin_weights && !mdl->mSkinWeights.empty(); - - U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; - - if (skinned) - { - mask |= LLVertexBuffer::MAP_WEIGHT4; - } - - vb = new LLVertexBuffer(mask, 0); - - vb->allocateBuffer(num_vertices, num_indices, TRUE); - - LLStrider vertex_strider; - LLStrider normal_strider; - LLStrider tc_strider; - LLStrider index_strider; - LLStrider weights_strider; - - vb->getVertexStrider(vertex_strider); - vb->getNormalStrider(normal_strider); - vb->getTexCoord0Strider(tc_strider); - vb->getIndexStrider(index_strider); - - if (skinned) - { - vb->getWeight4Strider(weights_strider); - } - - LLVector4a::memcpyNonAliased16((F32*) vertex_strider.get(), (F32*) vf.mPositions, num_vertices*4*sizeof(F32)); - LLVector4a::memcpyNonAliased16((F32*) tc_strider.get(), (F32*) vf.mTexCoords, num_vertices*2*sizeof(F32)); - LLVector4a::memcpyNonAliased16((F32*) normal_strider.get(), (F32*) vf.mNormals, num_vertices*4*sizeof(F32)); - - if (skinned) - { - for (U32 i = 0; i < num_vertices; i++) - { - //find closest weight to vf.mVertices[i].mPosition - LLVector3 pos(vf.mPositions[i].getF32ptr()); - - const LLModel::weight_list& weight_list = base_mdl->getJointInfluences(pos); - - LLVector4 w(0,0,0,0); - if (weight_list.size() > 4) - { - llerrs << "WTF?" << llendl; - } - - for (U32 i = 0; i < weight_list.size(); ++i) - { - F32 wght = llmin(weight_list[i].mWeight, 0.999999f); - F32 joint = (F32) weight_list[i].mJointIdx; - w.mV[i] = joint + wght; - } - - *(weights_strider++) = w; - } - } - - // build indices - for (U32 i = 0; i < num_indices; i++) - { - *(index_strider++) = vf.mIndices[i]; - } - - mVertexBuffer[lod][mdl].push_back(vb); - - vertex_count += num_vertices; - tri_count += num_indices/3; - ++mesh_count; - - } - } -} - -void LLModelPreview::update() -{ - if (mDirty) - { - mDirty = false; - mResourceCost = calcResourceCost(); - refresh(); - updateStatusMessages(); - } - - if (mGenLOD) - { - mGenLOD = false; - genLODs(); - refresh(); - updateStatusMessages(); - } - -} - -//----------------------------------------------------------------------------- -// render() -//----------------------------------------------------------------------------- -BOOL LLModelPreview::render() -{ - assert_main_thread(); - - LLMutexLock lock(this); - mNeedsUpdate = FALSE; - - bool edges = mViewOption["show_edges"]; - bool joint_positions = mViewOption["show_joint_positions"]; - bool skin_weight = mViewOption["show_skin_weight"]; - bool textures = mViewOption["show_textures"]; - bool physics = mViewOption["show_physics"]; - - S32 width = getWidth(); - S32 height = getHeight(); - - LLGLSUIDefault def; - LLGLDisable no_blend(GL_BLEND); - LLGLEnable cull(GL_CULL_FACE); - LLGLDepthTest depth(GL_TRUE); - LLGLDisable fog(GL_FOG); - - { - //clear background to blue - glMatrixMode(GL_PROJECTION); - gGL.pushMatrix(); - glLoadIdentity(); - glOrtho(0.0f, width, 0.0f, height, -1.0f, 1.0f); - - glMatrixMode(GL_MODELVIEW); - gGL.pushMatrix(); - glLoadIdentity(); - - gGL.color4f(0.15f, 0.2f, 0.3f, 1.f); - - gl_rect_2d_simple( width, height ); - - glMatrixMode(GL_PROJECTION); - gGL.popMatrix(); - - glMatrixMode(GL_MODELVIEW); - gGL.popMatrix(); - } - - LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; - - bool has_skin_weights = false; - bool upload_skin = mFMP->childGetValue("upload_skin").asBoolean(); - bool upload_joints = mFMP->childGetValue("upload_joints").asBoolean(); - - for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) - { - for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) - { - LLModelInstance& instance = *model_iter; - LLModel* model = instance.mModel; - if (!model->mSkinWeights.empty()) - { - has_skin_weights = true; - } - } - } - - if (has_skin_weights) - { //model has skin weights, enable view options for skin weights and joint positions - if (fmp) - { - fmp->enableViewOption("show_skin_weight"); - fmp->setViewOptionEnabled("show_joint_positions", skin_weight); - } - mFMP->childEnable("upload_skin"); - } - else - { - mFMP->childDisable("upload_skin"); - if (fmp) - { - mViewOption["show_skin_weight"] = false; - fmp->disableViewOption("show_skin_weight"); - fmp->disableViewOption("show_joint_positions"); - } - skin_weight = false; - } - - if (upload_skin && !has_skin_weights) - { //can't upload skin weights if model has no skin weights - mFMP->childSetValue("upload_skin", false); - upload_skin = false; - } - - if (!upload_skin && upload_joints) - { //can't upload joints if not uploading skin weights - mFMP->childSetValue("upload_joints", false); - upload_joints = false; - } - - mFMP->childSetEnabled("upload_joints", upload_skin); - - F32 explode = mFMP->childGetValue("physics_explode").asReal(); - - glClear(GL_DEPTH_BUFFER_BIT); - - LLRect preview_rect = mFMP->getChildView("preview_panel")->getRect(); - F32 aspect = (F32) preview_rect.getWidth()/preview_rect.getHeight(); - - LLViewerCamera::getInstance()->setAspect(aspect); - - LLViewerCamera::getInstance()->setView(LLViewerCamera::getInstance()->getDefaultFOV() / mCameraZoom); - - LLVector3 offset = mCameraOffset; - LLVector3 target_pos = mPreviewTarget+offset; - - F32 z_near = 0.001f; - F32 z_far = mCameraDistance+mPreviewScale.magVec()+mCameraOffset.magVec(); - - if (skin_weight) - { - target_pos = gAgentAvatarp->getPositionAgent(); - z_near = 0.01f; - z_far = 1024.f; - mCameraDistance = 16.f; - - //render avatar previews every frame - refresh(); - } - - glLoadIdentity(); - gPipeline.enableLightsPreview(); - - LLQuaternion camera_rot = LLQuaternion(mCameraPitch, LLVector3::y_axis) * - LLQuaternion(mCameraYaw, LLVector3::z_axis); - - LLQuaternion av_rot = camera_rot; - LLViewerCamera::getInstance()->setOriginAndLookAt( - target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + offset) * av_rot), // camera - LLVector3::z_axis, // up - target_pos); // point of interest - - - LLViewerCamera::getInstance()->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, width, height, FALSE, z_near, z_far); - - stop_glerror(); - - gGL.pushMatrix(); - const F32 BRIGHTNESS = 0.9f; - gGL.color3f(BRIGHTNESS, BRIGHTNESS, BRIGHTNESS); - - LLGLEnable normalize(GL_NORMALIZE); - - if (!mBaseModel.empty() && mVertexBuffer[5].empty()) - { - genBuffers(-1, skin_weight); - //genBuffers(3); - //genLODs(); - } - - if (!mModel[mPreviewLOD].empty()) - { - bool regen = mVertexBuffer[mPreviewLOD].empty(); - if (!regen) - { - const std::vector >& vb_vec = mVertexBuffer[mPreviewLOD].begin()->second; - if (!vb_vec.empty()) - { - const LLVertexBuffer* buff = vb_vec[0]; - regen = buff->hasDataType(LLVertexBuffer::TYPE_WEIGHT4) != skin_weight; - } - } - - if (regen) - { - genBuffers(mPreviewLOD, skin_weight); - } - - if (!skin_weight) - { - for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) - { - LLModelInstance& instance = *iter; - - LLModel* model = instance.mLOD[mPreviewLOD]; - - if (!model) - { - continue; - } - - gGL.pushMatrix(); - LLMatrix4 mat = instance.mTransform; - - glMultMatrixf((GLfloat*) mat.mMatrix); - - for (U32 i = 0; i < mVertexBuffer[mPreviewLOD][model].size(); ++i) - { - LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; - - buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); - - if (textures) - { - glColor4fv(instance.mMaterial[i].mDiffuseColor.mV); - if (i < instance.mMaterial.size() && instance.mMaterial[i].mDiffuseMap.notNull()) - { - gGL.getTexUnit(0)->bind(instance.mMaterial[i].mDiffuseMap, true); - if (instance.mMaterial[i].mDiffuseMap->getDiscardLevel() > -1) - { - mTextureSet.insert(instance.mMaterial[i].mDiffuseMap); - } - } - } - else - { - glColor4f(1,1,1,1); - } - - buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - glColor3f(0.4f, 0.4f, 0.4f); - - if (edges) - { - glLineWidth(3.f); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glLineWidth(1.f); - } - } - gGL.popMatrix(); - } - - if (physics) - { - glClear(GL_DEPTH_BUFFER_BIT); - LLGLEnable blend(GL_BLEND); - gGL.blendFunc(LLRender::BF_ONE, LLRender::BF_ZERO); - - for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) - { - LLModelInstance& instance = *iter; - - LLModel* model = instance.mLOD[LLModel::LOD_PHYSICS]; - - if (!model) - { - continue; - } - - gGL.pushMatrix(); - LLMatrix4 mat = instance.mTransform; - - glMultMatrixf((GLfloat*) mat.mMatrix); - - - bool render_mesh = true; - - LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread; - if (decomp) - { - LLMutexLock(decomp->mMutex); - - std::map, std::vector > >::iterator iter = - mPhysicsMesh.find(model); - if (iter != mPhysicsMesh.end()) - { //render hull instead of mesh - render_mesh = false; - for (U32 i = 0; i < iter->second.size(); ++i) - { - if (explode > 0.f) - { - gGL.pushMatrix(); - - LLVector3 offset = model->mHullCenter[i]-model->mCenterOfHullCenters; - offset *= explode; - - gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]); - } - - static std::vector hull_colors; - - if (i+1 >= hull_colors.size()) - { - hull_colors.push_back(LLColor4U(rand()%128+127, rand()%128+127, rand()%128+127, 255)); - } - - LLVertexBuffer* buff = iter->second[i]; - if (buff) - { - buff->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL); - - glColor4ubv(hull_colors[i].mV); - buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts()); - } - - if (explode > 0.f) - { - gGL.popMatrix(); - } - } - } - } - - if (render_mesh) - { - if (mVertexBuffer[LLModel::LOD_PHYSICS].empty()) - { - genBuffers(LLModel::LOD_PHYSICS, false); - } - for (U32 i = 0; i < mVertexBuffer[LLModel::LOD_PHYSICS][model].size(); ++i) - { - LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][i]; - - buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); - - buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - glColor4f(0.4f, 0.4f, 0.0f, 0.4f); - - buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); - - glColor3f(1.f, 1.f, 0.f); - - glLineWidth(3.f); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glLineWidth(1.f); - } - } - - gGL.popMatrix(); - } - - gGL.setSceneBlendType(LLRender::BT_ALPHA); - } - } - else - { - LLVOAvatarSelf* avatar = gAgentAvatarp; - target_pos = avatar->getPositionAgent(); - - LLViewerCamera::getInstance()->setOriginAndLookAt( - target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + offset) * av_rot), // camera - LLVector3::z_axis, // up - target_pos); // point of interest - - if (joint_positions) - { - avatar->renderCollisionVolumes(); - } - - for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) - { - for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) - { - LLModelInstance& instance = *model_iter; - LLModel* model = instance.mModel; - - if (!model->mSkinWeights.empty()) - { - for (U32 i = 0; i < mVertexBuffer[mPreviewLOD][model].size(); ++i) - { - LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; - - const LLVolumeFace& face = model->getVolumeFace(i); - - LLStrider position; - buffer->getVertexStrider(position); - - LLStrider weight; - buffer->getWeight4Strider(weight); - - //quick 'n dirty software vertex skinning - - //build matrix palette - LLMatrix4 mat[64]; - for (U32 j = 0; j < model->mJointList.size(); ++j) - { - LLJoint* joint = avatar->getJoint(model->mJointList[j]); - if (joint) - { - mat[j] = model->mInvBindMatrix[j]; - mat[j] *= joint->getWorldMatrix(); - } - } - - for (U32 j = 0; j < buffer->getRequestedVerts(); ++j) - { - LLMatrix4 final_mat; - final_mat.mMatrix[0][0] = final_mat.mMatrix[1][1] = final_mat.mMatrix[2][2] = final_mat.mMatrix[3][3] = 0.f; - - LLVector4 wght; - S32 idx[4]; - - F32 scale = 0.f; - for (U32 k = 0; k < 4; k++) - { - F32 w = weight[j].mV[k]; - - idx[k] = (S32) floorf(w); - wght.mV[k] = w - floorf(w); - scale += wght.mV[k]; - } - - wght *= 1.f/scale; - - for (U32 k = 0; k < 4; k++) - { - F32* src = (F32*) mat[idx[k]].mMatrix; - F32* dst = (F32*) final_mat.mMatrix; - - F32 w = wght.mV[k]; - - for (U32 l = 0; l < 16; l++) - { - dst[l] += src[l]*w; - } - } - - //VECTORIZE THIS - LLVector3 v(face.mPositions[j].getF32ptr()); - - v = v * model->mBindShapeMatrix; - v = v * final_mat; - - position[j] = v; - } - - buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); - glColor4fv(instance.mMaterial[i].mDiffuseColor.mV); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); - glColor3f(0.4f, 0.4f, 0.4f); - - if (edges) - { - glLineWidth(3.f); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glLineWidth(1.f); - } - } - } - } - } - } - } - - gGL.popMatrix(); - - return TRUE; -} - -//----------------------------------------------------------------------------- -// refresh() -//----------------------------------------------------------------------------- -void LLModelPreview::refresh() -{ - mNeedsUpdate = TRUE; -} - -//----------------------------------------------------------------------------- -// rotate() -//----------------------------------------------------------------------------- -void LLModelPreview::rotate(F32 yaw_radians, F32 pitch_radians) -{ - mCameraYaw = mCameraYaw + yaw_radians; - - mCameraPitch = llclamp(mCameraPitch + pitch_radians, F_PI_BY_TWO * -0.8f, F_PI_BY_TWO * 0.8f); -} - -//----------------------------------------------------------------------------- -// zoom() -//----------------------------------------------------------------------------- -void LLModelPreview::zoom(F32 zoom_amt) -{ - F32 new_zoom = mCameraZoom+zoom_amt; - - mCameraZoom = llclamp(new_zoom, 1.f, 10.f); -} - -void LLModelPreview::pan(F32 right, F32 up) -{ - mCameraOffset.mV[VY] = llclamp(mCameraOffset.mV[VY] + right * mCameraDistance / mCameraZoom, -1.f, 1.f); - mCameraOffset.mV[VZ] = llclamp(mCameraOffset.mV[VZ] + up * mCameraDistance / mCameraZoom, -1.f, 1.f); -} - -void LLModelPreview::setPreviewLOD(S32 lod) -{ - lod = llclamp(lod, 0, (S32) LLModel::LOD_HIGH); - - if (lod != mPreviewLOD) - { - mPreviewLOD = lod; - - LLComboBox* combo_box = mFMP->getChild("preview_lod_combo"); - combo_box->setCurrentByIndex((NUM_LOD-1)-mPreviewLOD); // combo box list of lods is in reverse order - mFMP->childSetTextArg("lod_table_footer", "[DETAIL]", mFMP->getString(lod_name[mPreviewLOD])); - mFMP->childSetText("lod_file", mLODFile[mPreviewLOD]); - - LLColor4 highlight_color = LLUIColorTable::instance().getColor("MeshImportTableHighlightColor"); - LLColor4 normal_color = LLUIColorTable::instance().getColor("MeshImportTableNormalColor"); - - for (S32 i = 0; i <= LLModel::LOD_HIGH; ++i) - { - const LLColor4& color = (i == lod) ? highlight_color : normal_color; - - mFMP->childSetColor(lod_status_name[i], color); - mFMP->childSetColor(lod_label_name[i], color); - mFMP->childSetColor(lod_triangles_name[i], color); - mFMP->childSetColor(lod_vertices_name[i], color); - } - - LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; - if (fmp) - { - LLRadioGroup* radio = fmp->getChild("lod_file_or_limit"); - radio->selectNthItem(fmp->mLODMode[mPreviewLOD]); - } - } - refresh(); - updateStatusMessages(); -} - -//static -void LLFloaterModelPreview::onBrowseLOD(void* data) -{ - assert_main_thread(); - - LLFloaterModelPreview* mp = (LLFloaterModelPreview*) data; - mp->loadModel(mp->mModelPreview->mPreviewLOD); -} - -//static -void LLFloaterModelPreview::onUpload(void* user_data) -{ - assert_main_thread(); - - LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; - - mp->mModelPreview->rebuildUploadData(); - - gMeshRepo.uploadModel(mp->mModelPreview->mUploadData, mp->mModelPreview->mPreviewScale, - mp->childGetValue("upload_textures").asBoolean(), mp->childGetValue("upload_skin"), mp->childGetValue("upload_joints")); - - mp->closeFloater(false); -} - - -//static -void LLFloaterModelPreview::onClearMaterials(void* user_data) -{ - LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; - mp->mModelPreview->clearMaterials(); -} - -//static -void LLFloaterModelPreview::refresh(LLUICtrl* ctrl, void* user_data) -{ - sInstance->mModelPreview->mDirty = true; -} - -void LLFloaterModelPreview::updateResourceCost() -{ - U32 cost = mModelPreview->mResourceCost; - childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d",cost)); -} - -//static -void LLModelPreview::textureLoadedCallback( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata ) -{ - LLModelPreview* preview = (LLModelPreview*) userdata; - preview->refresh(); -} - -LLFloaterModelPreview::DecompRequest::DecompRequest(const std::string& stage, LLModel* mdl) -{ - mStage = stage; - mContinue = 1; - mModel = mdl; - mDecompID = &mdl->mDecompID; - mParams = sInstance->mDecompParams; - - //copy out positions and indices - if (mdl) - { - U16 index_offset = 0; - - mPositions.clear(); - mIndices.clear(); - - //queue up vertex positions and indices - for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) - { - const LLVolumeFace& face = mdl->getVolumeFace(i); - if (mPositions.size() + face.mNumVertices > 65535) - { - continue; - } - - for (U32 j = 0; j < face.mNumVertices; ++j) - { - mPositions.push_back(LLVector3(face.mPositions[j].getF32ptr())); - } - - for (U32 j = 0; j < face.mNumIndices; ++j) - { - mIndices.push_back(face.mIndices[j]+index_offset); - } - - index_offset += face.mNumVertices; - } - } -} - -void LLFloaterModelPreview::setStatusMessage(const std::string& msg) -{ - LLMutexLock lock(mStatusLock); - mStatusMessage = msg; -} - -S32 LLFloaterModelPreview::DecompRequest::statusCallback(const char* status, S32 p1, S32 p2) -{ - setStatusMessage(llformat("%s: %d/%d", status, p1, p2)); - if (LLFloaterModelPreview::sInstance) - { - LLFloaterModelPreview::sInstance->setStatusMessage(mStatusMessage); - } - - return mContinue; -} - -void LLFloaterModelPreview::DecompRequest::completed() -{ //called from the main thread - mModel->setConvexHullDecomposition(mHull); - - if (sInstance) - { - if (sInstance->mModelPreview) - { - sInstance->mModelPreview->mPhysicsMesh[mModel] = mHullMesh; - sInstance->mModelPreview->mDirty = true; - LLFloaterModelPreview::sInstance->mModelPreview->refresh(); - } - - sInstance->mCurRequest.erase(this); - } -} +/** + * @file llfloatermodelpreview.cpp + * @brief LLFloaterModelPreview class implementation + * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "dae.h" +//#include "dom.h" +#include "dom/domAsset.h" +#include "dom/domBind_material.h" +#include "dom/domCOLLADA.h" +#include "dom/domConstants.h" +#include "dom/domController.h" +#include "dom/domEffect.h" +#include "dom/domGeometry.h" +#include "dom/domInstance_geometry.h" +#include "dom/domInstance_material.h" +#include "dom/domInstance_node.h" +#include "dom/domInstance_effect.h" +#include "dom/domMaterial.h" +#include "dom/domMatrix.h" +#include "dom/domNode.h" +#include "dom/domProfile_COMMON.h" +#include "dom/domRotate.h" +#include "dom/domScale.h" +#include "dom/domTranslate.h" +#include "dom/domVisual_scene.h" + +#include "llfloatermodelpreview.h" + +#include "llfilepicker.h" +#include "llimagebmp.h" +#include "llimagetga.h" +#include "llimagejpeg.h" +#include "llimagepng.h" + +#include "llagent.h" +#include "llbutton.h" +#include "llcombobox.h" +#include "lldatapacker.h" +#include "lldrawable.h" +#include "lldrawpoolavatar.h" +#include "llrender.h" +#include "llface.h" +#include "lleconomy.h" +#include "llfocusmgr.h" +#include "llfloaterperms.h" +#include "lliconctrl.h" +#include "llmatrix4a.h" +#include "llmenubutton.h" +#include "llmeshrepository.h" +#include "llsdutil_math.h" +#include "lltextbox.h" +#include "lltoolmgr.h" +#include "llui.h" +#include "llvector4a.h" +#include "llviewercamera.h" +#include "llviewerwindow.h" +#include "llvoavatar.h" +#include "llvoavatarself.h" +#include "pipeline.h" +#include "lluictrlfactory.h" +#include "llviewermenu.h" +#include "llviewermenufile.h" +#include "llviewerregion.h" +#include "llviewertexturelist.h" +#include "llstring.h" +#include "llbutton.h" +#include "llcheckboxctrl.h" +#include "llradiogroup.h" +#include "llsliderctrl.h" +#include "llspinctrl.h" +#include "lltoggleablemenu.h" +#include "llvfile.h" +#include "llvfs.h" +#include "llcallbacklist.h" + +#include "glod/glod.h" + +//static +S32 LLFloaterModelPreview::sUploadAmount = 10; +LLFloaterModelPreview* LLFloaterModelPreview::sInstance = NULL; + +const S32 PREVIEW_BORDER_WIDTH = 2; +const S32 PREVIEW_RESIZE_HANDLE_SIZE = S32(RESIZE_HANDLE_WIDTH * OO_SQRT2) + PREVIEW_BORDER_WIDTH; +const S32 PREVIEW_HPAD = PREVIEW_RESIZE_HANDLE_SIZE; +const S32 PREF_BUTTON_HEIGHT = 16 + 7 + 16; +const S32 PREVIEW_TEXTURE_HEIGHT = 300; + +void drawBoxOutline(const LLVector3& pos, const LLVector3& size); + + +std::string lod_name[NUM_LOD+1] = +{ + "lowest", + "low", + "medium", + "high", + "I went off the end of the lod_name array. Me so smart." +}; + +std::string lod_triangles_name[NUM_LOD+1] = +{ + "lowest_triangles", + "low_triangles", + "medium_triangles", + "high_triangles", + "I went off the end of the lod_triangles_name array. Me so smart." +}; + +std::string lod_vertices_name[NUM_LOD+1] = +{ + "lowest_vertices", + "low_vertices", + "medium_vertices", + "high_vertices", + "I went off the end of the lod_vertices_name array. Me so smart." +}; + +std::string lod_status_name[NUM_LOD+1] = +{ + "lowest_status", + "low_status", + "medium_status", + "high_status", + "I went off the end of the lod_status_name array. Me so smart." +}; + +std::string lod_icon_name[NUM_LOD+1] = +{ + "status_icon_lowest", + "status_icon_low", + "status_icon_medium", + "status_icon_high", + "I went off the end of the lod_status_name array. Me so smart." +}; + +std::string lod_status_image[NUM_LOD+1] = +{ + "ModelImport_Status_Good", + "ModelImport_Status_Warning", + "ModelImport_Status_Error", + "I went off the end of the lod_status_image array. Me so smart." +}; + +std::string lod_label_name[NUM_LOD+1] = +{ + "lowest_label", + "low_label", + "medium_label", + "high_label", + "I went off the end of the lod_label_name array. Me so smart." +}; + + +bool validate_face(const LLVolumeFace& face) +{ + for (U32 i = 0; i < face.mNumIndices; ++i) + { + if (face.mIndices[i] >= face.mNumVertices) + { + llwarns << "Face has invalid index." << llendl; + return false; + } + } + + return true; +} + +bool validate_model(const LLModel* mdl) +{ + if (mdl->getNumVolumeFaces() == 0) + { + llwarns << "Model has no faces!" << llendl; + return false; + } + + for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) + { + if (mdl->getVolumeFace(i).mNumVertices == 0) + { + llwarns << "Face has no vertices." << llendl; + return false; + } + + if (mdl->getVolumeFace(i).mNumIndices == 0) + { + llwarns << "Face has no indices." << llendl; + return false; + } + + if (!validate_face(mdl->getVolumeFace(i))) + { + return false; + } + } + + return true; +} + +BOOL stop_gloderror() +{ + GLuint error = glodGetError(); + + if (error != GLOD_NO_ERROR) + { + llwarns << "GLOD error detected, cannot generate LOD: " << std::hex << error << llendl; + return TRUE; + } + + return FALSE; +} + + +LLMeshFilePicker::LLMeshFilePicker(LLModelPreview* mp, S32 lod) + : LLFilePickerThread(LLFilePicker::FFLOAD_COLLADA) + { + mMP = mp; + mLOD = lod; + } + +void LLMeshFilePicker::notify(const std::string& filename) +{ + mMP->loadModel(mFile, mLOD); +} + + +//----------------------------------------------------------------------------- +// LLFloaterModelPreview() +//----------------------------------------------------------------------------- +LLFloaterModelPreview::LLFloaterModelPreview(const LLSD& key) : +LLFloater(key) +{ + sInstance = this; + mLastMouseX = 0; + mLastMouseY = 0; + mGLName = 0; + mStatusLock = new LLMutex(NULL); + + mLODMode[LLModel::LOD_HIGH] = 0; + for (U32 i = 0; i < LLModel::LOD_HIGH; i++) + { + mLODMode[i] = 1; + } +} + +//----------------------------------------------------------------------------- +// postBuild() +//----------------------------------------------------------------------------- +BOOL LLFloaterModelPreview::postBuild() +{ + if (!LLFloater::postBuild()) + { + return FALSE; + } + + + + + + + childSetAction("lod_browse", onBrowseLOD, this); + + childSetCommitCallback("crease_angle", onGenerateNormalsCommit, this); + childSetCommitCallback("generate_normals", onGenerateNormalsCommit, this); + + childSetCommitCallback("lod_generate", onAutoFillCommit, this); + + childSetCommitCallback("lod_mode", onLODParamCommit, this); + childSetCommitCallback("lod_error_threshold", onLODParamCommit, this); + childSetCommitCallback("lod_triangle_limit", onLODParamCommit, this); + childSetCommitCallback("build_operator", onLODParamCommit, this); + childSetCommitCallback("queue_mode", onLODParamCommit, this); + childSetCommitCallback("border_mode", onLODParamCommit, this); + childSetCommitCallback("share_tolerance", onLODParamCommit, this); + + childSetTextArg("status", "[STATUS]", getString("status_idle")); + + //childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d",sUploadAmount)); + childSetAction("ok_btn", onUpload, this); + childDisable("ok_btn"); + + childSetAction("clear_materials", onClearMaterials, this); + + childSetCommitCallback("preview_lod_combo", onPreviewLODCommit, this); + + childSetCommitCallback("upload_skin", onUploadSkinCommit, this); + childSetCommitCallback("upload_joints", onUploadJointsCommit, this); + + childSetCommitCallback("import_scale", onImportScaleCommit, this); + + childSetCommitCallback("lod_file_or_limit", refresh, this); + childSetCommitCallback("physics_load_radio", refresh, this); + //childSetCommitCallback("physics_optimize", refresh, this); + //childSetCommitCallback("physics_use_hull", refresh, this); + + childDisable("upload_skin"); + childDisable("upload_joints"); + childDisable("ok_btn"); + + mViewOptionMenuButton = getChild("options_gear_btn"); + + mCommitCallbackRegistrar.add("ModelImport.ViewOption.Action", boost::bind(&LLFloaterModelPreview::onViewOptionChecked, this, _2)); + mEnableCallbackRegistrar.add("ModelImport.ViewOption.Check", boost::bind(&LLFloaterModelPreview::isViewOptionChecked, this, _2)); + mEnableCallbackRegistrar.add("ModelImport.ViewOption.Enabled", boost::bind(&LLFloaterModelPreview::isViewOptionEnabled, this, _2)); + + + + mViewOptionMenu = LLUICtrlFactory::getInstance()->createFromFile("menu_model_import_gear_default.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + mViewOptionMenuButton->setMenu(mViewOptionMenu, LLMenuButton::MP_BOTTOM_LEFT); + + initDecompControls(); + + LLView* preview_panel = getChild("preview_panel"); + + mPreviewRect = preview_panel->getRect(); + + mModelPreview = new LLModelPreview(512, 512, this); + mModelPreview->setPreviewTarget(16.f); + mModelPreview->setDetailsCallback(boost::bind(&LLFloaterModelPreview::setDetails, this, _1, _2, _3, _4, _5)); + + //set callbacks for left click on line editor rows + for (U32 i = 0; i <= LLModel::LOD_HIGH; i++) + { + LLTextBox* text = getChild(lod_label_name[i]); + if (text) + { + text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i)); + } + + text = getChild(lod_triangles_name[i]); + if (text) + { + text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i)); + } + + text = getChild(lod_vertices_name[i]); + if (text) + { + text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i)); + } + + text = getChild(lod_status_name[i]); + if (text) + { + text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i)); + } + } + + return TRUE; +} + +//----------------------------------------------------------------------------- +// LLFloaterModelPreview() +//----------------------------------------------------------------------------- +LLFloaterModelPreview::~LLFloaterModelPreview() +{ + sInstance = NULL; + + if ( mModelPreview->containsRiggedAsset() ) + { + gAgentAvatarp->resetJointPositions(); + } + + delete mModelPreview; + + if (mGLName) + { + LLImageGL::deleteTextures(1, &mGLName ); + } + + delete mStatusLock; + mStatusLock = NULL; +} + +void LLFloaterModelPreview::onViewOptionChecked(const LLSD& userdata) +{ + if (mModelPreview) + { + mModelPreview->mViewOption[userdata.asString()] = !mModelPreview->mViewOption[userdata.asString()]; + + mModelPreview->refresh(); + } +} + +bool LLFloaterModelPreview::isViewOptionChecked(const LLSD& userdata) +{ + if (mModelPreview) + { + return mModelPreview->mViewOption[userdata.asString()]; + } + + return false; +} + +bool LLFloaterModelPreview::isViewOptionEnabled(const LLSD& userdata) +{ + return !mViewOptionDisabled[userdata.asString()]; +} + +void LLFloaterModelPreview::setViewOptionEnabled(const std::string& option, bool enabled) +{ + mViewOptionDisabled[option] = !enabled; +} + +void LLFloaterModelPreview::enableViewOption(const std::string& option) +{ + setViewOptionEnabled(option, true); +} + +void LLFloaterModelPreview::disableViewOption(const std::string& option) +{ + setViewOptionEnabled(option, false); +} + +void LLFloaterModelPreview::loadModel(S32 lod) +{ + mModelPreview->mLoading = true; + + (new LLMeshFilePicker(mModelPreview, lod))->getFile(); +} + +//static +void LLFloaterModelPreview::onImportScaleCommit(LLUICtrl*,void* userdata) +{ + LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; + + if (!fp->mModelPreview) + { + return; + } + + fp->mModelPreview->calcResourceCost(); + fp->mModelPreview->refresh(); +} + +//static +void LLFloaterModelPreview::onUploadJointsCommit(LLUICtrl*,void* userdata) +{ + LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; + + if (!fp->mModelPreview) + { + return; + } + + fp->mModelPreview->refresh(); +} + +//static +void LLFloaterModelPreview::onUploadSkinCommit(LLUICtrl*,void* userdata) +{ + LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; + + if (!fp->mModelPreview) + { + return; + } + + fp->mModelPreview->refresh(); + fp->mModelPreview->resetPreviewTarget(); + fp->mModelPreview->clearBuffers(); +} + +//static +void LLFloaterModelPreview::onPreviewLODCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; + + if (!fp->mModelPreview) + { + return; + } + + S32 which_mode = 0; + + LLComboBox* combo = (LLComboBox*) ctrl; + + which_mode = (NUM_LOD-1)-combo->getFirstSelectedIndex(); // combo box list of lods is in reverse order + + fp->mModelPreview->setPreviewLOD(which_mode); +} + +//static +void LLFloaterModelPreview::onGenerateNormalsCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; + + fp->mModelPreview->generateNormals(); +} + +//static +void LLFloaterModelPreview::onExplodeCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview* fp = LLFloaterModelPreview::sInstance; + + fp->mModelPreview->refresh(); +} + +//static +void LLFloaterModelPreview::onAutoFillCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; + + fp->mModelPreview->genLODs(); +} + +//static +void LLFloaterModelPreview::onLODParamCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; + fp->mModelPreview->genLODs(fp->mModelPreview->mPreviewLOD); + fp->mModelPreview->updateStatusMessages(); + fp->mModelPreview->refresh(); +} + + +//----------------------------------------------------------------------------- +// draw() +//----------------------------------------------------------------------------- +void LLFloaterModelPreview::draw() +{ + LLFloater::draw(); + LLRect r = getRect(); + + mModelPreview->update(); + + if (!mModelPreview->mLoading) + { + childSetTextArg("status", "[STATUS]", getString("status_idle")); + } + + childSetTextArg("prim_cost", "[PRIM_COST]", llformat("%d", mModelPreview->mResourceCost)); + childSetTextArg("description_label", "[TEXTURES]", llformat("%d", mModelPreview->mTextureSet.size())); + + if (!mCurRequest.empty()) + { + LLMutexLock lock(mStatusLock); + childSetTextArg("status", "[STATUS]", mStatusMessage); + } + + U32 resource_cost = mModelPreview->mResourceCost*10; + + if (childGetValue("upload_textures").asBoolean()) + { + resource_cost += mModelPreview->mTextureSet.size()*10; + } + + childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d", resource_cost)); + + if (mModelPreview) + { + gGL.color3f(1.f, 1.f, 1.f); + + gGL.getTexUnit(0)->bind(mModelPreview); + + + LLView* preview_panel = getChild("preview_panel"); + + LLRect rect = preview_panel->getRect(); + if (rect != mPreviewRect) + { + mModelPreview->refresh(); + mPreviewRect = preview_panel->getRect(); + } + + gGL.begin( LLRender::QUADS ); + { + gGL.texCoord2f(0.f, 1.f); + gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mTop); + gGL.texCoord2f(0.f, 0.f); + gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mBottom); + gGL.texCoord2f(1.f, 0.f); + gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mBottom); + gGL.texCoord2f(1.f, 1.f); + gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mTop); + } + gGL.end(); + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + } +} + +//----------------------------------------------------------------------------- +// handleMouseDown() +//----------------------------------------------------------------------------- +BOOL LLFloaterModelPreview::handleMouseDown(S32 x, S32 y, MASK mask) +{ + if (mPreviewRect.pointInRect(x, y)) + { + bringToFront( x, y ); + gFocusMgr.setMouseCapture(this); + gViewerWindow->hideCursor(); + mLastMouseX = x; + mLastMouseY = y; + return TRUE; + } + + return LLFloater::handleMouseDown(x, y, mask); +} + +//----------------------------------------------------------------------------- +// handleMouseUp() +//----------------------------------------------------------------------------- +BOOL LLFloaterModelPreview::handleMouseUp(S32 x, S32 y, MASK mask) +{ + gFocusMgr.setMouseCapture(FALSE); + gViewerWindow->showCursor(); + return LLFloater::handleMouseUp(x, y, mask); +} + +//----------------------------------------------------------------------------- +// handleHover() +//----------------------------------------------------------------------------- +BOOL LLFloaterModelPreview::handleHover (S32 x, S32 y, MASK mask) +{ + MASK local_mask = mask & ~MASK_ALT; + + if (mModelPreview && hasMouseCapture()) + { + if (local_mask == MASK_PAN) + { + // pan here + mModelPreview->pan((F32)(x - mLastMouseX) * -0.005f, (F32)(y - mLastMouseY) * -0.005f); + } + else if (local_mask == MASK_ORBIT) + { + F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f; + F32 pitch_radians = (F32)(y - mLastMouseY) * 0.02f; + + mModelPreview->rotate(yaw_radians, pitch_radians); + } + else + { + + F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f; + F32 zoom_amt = (F32)(y - mLastMouseY) * 0.02f; + + mModelPreview->rotate(yaw_radians, 0.f); + mModelPreview->zoom(zoom_amt); + } + + + mModelPreview->refresh(); + + LLUI::setMousePositionLocal(this, mLastMouseX, mLastMouseY); + } + + if (!mPreviewRect.pointInRect(x, y) || !mModelPreview) + { + return LLFloater::handleHover(x, y, mask); + } + else if (local_mask == MASK_ORBIT) + { + gViewerWindow->setCursor(UI_CURSOR_TOOLCAMERA); + } + else if (local_mask == MASK_PAN) + { + gViewerWindow->setCursor(UI_CURSOR_TOOLPAN); + } + else + { + gViewerWindow->setCursor(UI_CURSOR_TOOLZOOMIN); + } + + return TRUE; +} + +//----------------------------------------------------------------------------- +// handleScrollWheel() +//----------------------------------------------------------------------------- +BOOL LLFloaterModelPreview::handleScrollWheel(S32 x, S32 y, S32 clicks) +{ + if (mPreviewRect.pointInRect(x, y) && mModelPreview) + { + mModelPreview->zoom((F32)clicks * -0.2f); + mModelPreview->refresh(); + } + + return TRUE; +} + +//static +void LLFloaterModelPreview::onPhysicsParamCommit(LLUICtrl* ctrl, void* data) +{ + if (LLConvexDecomposition::getInstance() == NULL) + { + llinfos << "convex decomposition tool is a stub on this platform. cannot get decomp." << llendl; + return; + } + + if (sInstance) + { + LLCDParam* param = (LLCDParam*) data; + std::string name(param->mName); + sInstance->mDecompParams[name] = ctrl->getValue(); + + if (name == "Simplify Method") + { + if (ctrl->getValue().asInteger() == 0) + { + sInstance->childSetVisible("Retain%", true); + sInstance->childSetVisible("Detail Scale", false); + } + else + { + sInstance->childSetVisible("Retain%", false); + sInstance->childSetVisible("Detail Scale", true); + } + } + } +} + +//static +void LLFloaterModelPreview::onPhysicsStageExecute(LLUICtrl* ctrl, void* data) +{ + LLCDStageData* stage = (LLCDStageData*) data; + + if (sInstance) + { + if (!sInstance->mCurRequest.empty()) + { + llinfos << "Decomposition request still pending." << llendl; + return; + } + + if (sInstance->mModelPreview) + { + for (S32 i = 0; i < sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS].size(); ++i) + { + LLModel* mdl = sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS][i]; + DecompRequest* request = new DecompRequest(stage->mName, mdl); + sInstance->mCurRequest.insert(request); + gMeshRepo.mDecompThread->submitRequest(request); + } + } + } +} + +//static +void LLFloaterModelPreview::onPhysicsBrowse(LLUICtrl* ctrl, void* userdata) +{ + sInstance->loadModel(LLModel::LOD_PHYSICS); +} + +//static +void LLFloaterModelPreview::onPhysicsUseLOD(LLUICtrl* ctrl, void* userdata) +{ + S32 which_mode = 3; + LLCtrlSelectionInterface* iface = sInstance->childGetSelectionInterface("physics_lod_combo"); + if (iface) + { + which_mode = iface->getFirstSelectedIndex(); + } + + sInstance->mModelPreview->setPhysicsFromLOD(which_mode); +} + +//static +void LLFloaterModelPreview::onPhysicsStageCancel(LLUICtrl* ctrl, void*data) +{ + if (sInstance) + { + for (std::set >::iterator iter = sInstance->mCurRequest.begin(); + iter != sInstance->mCurRequest.end(); ++iter) + { + DecompRequest* req = *iter; + req->mContinue = 0; + } + } +} + +void LLFloaterModelPreview::initDecompControls() +{ + LLSD key; + + childSetCommitCallback("cancel_btn", onPhysicsStageCancel, NULL); + childSetCommitCallback("physics_lod_combo", onPhysicsUseLOD, NULL); + childSetCommitCallback("physics_browse", onPhysicsBrowse, NULL); + + static const LLCDStageData* stage = NULL; + static S32 stage_count = 0; + + if (!stage && LLConvexDecomposition::getInstance() != NULL) + { + stage_count = LLConvexDecomposition::getInstance()->getStages(&stage); + } + + static const LLCDParam* param = NULL; + static S32 param_count = 0; + if (!param && LLConvexDecomposition::getInstance() != NULL) + { + param_count = LLConvexDecomposition::getInstance()->getParameters(¶m); + } + + for (S32 j = stage_count-1; j >= 0; --j) + { + LLButton* button = getChild(stage[j].mName); + if (button) + { + button->setCommitCallback(onPhysicsStageExecute, (void*) &stage[j]); + } + + gMeshRepo.mDecompThread->mStageID[stage[j].mName] = j; + // protected against stub by stage_count being 0 for stub above + LLConvexDecomposition::getInstance()->registerCallback(j, LLPhysicsDecomp::llcdCallback); + + //llinfos << "Physics decomp stage " << stage[j].mName << " (" << j << ") parameters:" << llendl; + //llinfos << "------------------------------------" << llendl; + + for (S32 i = 0; i < param_count; ++i) + { + if (param[i].mStage != j) + { + continue; + } + + std::string name(param[i].mName ? param[i].mName : ""); + std::string description(param[i].mDescription ? param[i].mDescription : ""); + + std::string type = "unknown"; + + llinfos << name << " - " << description << llendl; + + if (param[i].mType == LLCDParam::LLCD_FLOAT) + { + mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mFloat); + //llinfos << "Type: float, Default: " << param[i].mDefault.mFloat << llendl; + + LLSliderCtrl* slider = getChild(name); + if (slider) + { + slider->setMinValue(param[i].mDetails.mRange.mLow.mFloat); + slider->setMaxValue(param[i].mDetails.mRange.mHigh.mFloat); + slider->setIncrement(param[i].mDetails.mRange.mDelta.mFloat); + slider->setValue(param[i].mDefault.mFloat); + slider->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); + } + } + else if (param[i].mType == LLCDParam::LLCD_INTEGER) + { + mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue); + //llinfos << "Type: integer, Default: " << param[i].mDefault.mIntOrEnumValue << llendl; + + LLSliderCtrl* slider = getChild(name); + if (slider) + { + slider->setMinValue(param[i].mDetails.mRange.mLow.mIntOrEnumValue); + slider->setMaxValue(param[i].mDetails.mRange.mHigh.mIntOrEnumValue); + slider->setIncrement(param[i].mDetails.mRange.mDelta.mIntOrEnumValue); + slider->setValue(param[i].mDefault.mIntOrEnumValue); + slider->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); + } + } + else if (param[i].mType == LLCDParam::LLCD_BOOLEAN) + { + mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mBool); + //llinfos << "Type: boolean, Default: " << (param[i].mDefault.mBool ? "True" : "False") << llendl; + + LLCheckBoxCtrl* check_box = getChild(name); + if (check_box) + { + check_box->setValue(param[i].mDefault.mBool); + check_box->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); + } + } + else if (param[i].mType == LLCDParam::LLCD_ENUM) + { + mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue); + //llinfos << "Type: enum, Default: " << param[i].mDefault.mIntOrEnumValue << llendl; + + { //plug into combo box + + //llinfos << "Accepted values: " << llendl; + LLComboBox* combo_box = getChild(name); + for (S32 k = 0; k < param[i].mDetails.mEnumValues.mNumEnums; ++k) + { + //llinfos << param[i].mDetails.mEnumValues.mEnumsArray[k].mValue + // << " - " << param[i].mDetails.mEnumValues.mEnumsArray[k].mName << llendl; + + combo_box->add(param[i].mDetails.mEnumValues.mEnumsArray[k].mName, + LLSD::Integer(param[i].mDetails.mEnumValues.mEnumsArray[k].mValue)); + } + combo_box->setValue(param[i].mDefault.mIntOrEnumValue); + combo_box->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); + } + + //llinfos << "----" << llendl; + } + //llinfos << "-----------------------------" << llendl; + } + } + + childSetCommitCallback("physics_explode", LLFloaterModelPreview::onExplodeCommit, this); +} + +//----------------------------------------------------------------------------- +// onMouseCaptureLost() +//----------------------------------------------------------------------------- +// static +void LLFloaterModelPreview::onMouseCaptureLostModelPreview(LLMouseHandler* handler) +{ + gViewerWindow->showCursor(); +} + +//----------------------------------------------------------------------------- +// LLModelLoader +//----------------------------------------------------------------------------- +LLModelLoader::LLModelLoader(std::string filename, S32 lod, LLModelPreview* preview) +: LLThread("Model Loader"), mFilename(filename), mLod(lod), mPreview(preview), mState(STARTING), mFirstTransform(TRUE) +{ + mJointMap["mPelvis"] = "mPelvis"; + mJointMap["mTorso"] = "mTorso"; + mJointMap["mChest"] = "mChest"; + mJointMap["mNeck"] = "mNeck"; + mJointMap["mHead"] = "mHead"; + mJointMap["mSkull"] = "mSkull"; + mJointMap["mEyeRight"] = "mEyeRight"; + mJointMap["mEyeLeft"] = "mEyeLeft"; + mJointMap["mCollarLeft"] = "mCollarLeft"; + mJointMap["mShoulderLeft"] = "mShoulderLeft"; + mJointMap["mElbowLeft"] = "mElbowLeft"; + mJointMap["mWristLeft"] = "mWristLeft"; + mJointMap["mCollarRight"] = "mCollarRight"; + mJointMap["mShoulderRight"] = "mShoulderRight"; + mJointMap["mElbowRight"] = "mElbowRight"; + mJointMap["mWristRight"] = "mWristRight"; + mJointMap["mHipRight"] = "mHipRight"; + mJointMap["mKneeRight"] = "mKneeRight"; + mJointMap["mAnkleRight"] = "mAnkleRight"; + mJointMap["mFootRight"] = "mFootRight"; + mJointMap["mToeRight"] = "mToeRight"; + mJointMap["mHipLeft"] = "mHipLeft"; + mJointMap["mKneeLeft"] = "mKneeLeft"; + mJointMap["mAnkleLeft"] = "mAnkleLeft"; + mJointMap["mFootLeft"] = "mFootLeft"; + mJointMap["mToeLeft"] = "mToeLeft"; + + mJointMap["avatar_mPelvis"] = "mPelvis"; + mJointMap["avatar_mTorso"] = "mTorso"; + mJointMap["avatar_mChest"] = "mChest"; + mJointMap["avatar_mNeck"] = "mNeck"; + mJointMap["avatar_mHead"] = "mHead"; + mJointMap["avatar_mSkull"] = "mSkull"; + mJointMap["avatar_mEyeRight"] = "mEyeRight"; + mJointMap["avatar_mEyeLeft"] = "mEyeLeft"; + mJointMap["avatar_mCollarLeft"] = "mCollarLeft"; + mJointMap["avatar_mShoulderLeft"] = "mShoulderLeft"; + mJointMap["avatar_mElbowLeft"] = "mElbowLeft"; + mJointMap["avatar_mWristLeft"] = "mWristLeft"; + mJointMap["avatar_mCollarRight"] = "mCollarRight"; + mJointMap["avatar_mShoulderRight"] = "mShoulderRight"; + mJointMap["avatar_mElbowRight"] = "mElbowRight"; + mJointMap["avatar_mWristRight"] = "mWristRight"; + mJointMap["avatar_mHipRight"] = "mHipRight"; + mJointMap["avatar_mKneeRight"] = "mKneeRight"; + mJointMap["avatar_mAnkleRight"] = "mAnkleRight"; + mJointMap["avatar_mFootRight"] = "mFootRight"; + mJointMap["avatar_mToeRight"] = "mToeRight"; + mJointMap["avatar_mHipLeft"] = "mHipLeft"; + mJointMap["avatar_mKneeLeft"] = "mKneeLeft"; + mJointMap["avatar_mAnkleLeft"] = "mAnkleLeft"; + mJointMap["avatar_mFootLeft"] = "mFootLeft"; + mJointMap["avatar_mToeLeft"] = "mToeLeft"; + + + mJointMap["hip"] = "mPelvis"; + mJointMap["abdomen"] = "mTorso"; + mJointMap["chest"] = "mChest"; + mJointMap["neck"] = "mNeck"; + mJointMap["head"] = "mHead"; + mJointMap["figureHair"] = "mSkull"; + mJointMap["lCollar"] = "mCollarLeft"; + mJointMap["lShldr"] = "mShoulderLeft"; + mJointMap["lForeArm"] = "mElbowLeft"; + mJointMap["lHand"] = "mWristLeft"; + mJointMap["rCollar"] = "mCollarRight"; + mJointMap["rShldr"] = "mShoulderRight"; + mJointMap["rForeArm"] = "mElbowRight"; + mJointMap["rHand"] = "mWristRight"; + mJointMap["rThigh"] = "mHipRight"; + mJointMap["rShin"] = "mKneeRight"; + mJointMap["rFoot"] = "mFootRight"; + mJointMap["lThigh"] = "mHipLeft"; + mJointMap["lShin"] = "mKneeLeft"; + mJointMap["lFoot"] = "mFootLeft"; +} + +void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, BOOL& first_transform) +{ + LLVector4a box[] = + { + LLVector4a(-1, 1,-1), + LLVector4a(-1, 1, 1), + LLVector4a(-1,-1,-1), + LLVector4a(-1,-1, 1), + LLVector4a( 1, 1,-1), + LLVector4a( 1, 1, 1), + LLVector4a( 1,-1,-1), + LLVector4a( 1,-1, 1), + }; + + for (S32 j = 0; j < model->getNumVolumeFaces(); ++j) + { + const LLVolumeFace& face = model->getVolumeFace(j); + + LLVector4a center; + center.setAdd(face.mExtents[0], face.mExtents[1]); + center.mul(0.5f); + LLVector4a size; + size.setSub(face.mExtents[1],face.mExtents[0]); + size.mul(0.5f); + + for (U32 i = 0; i < 8; i++) + { + LLVector4a t; + t.setMul(size, box[i]); + t.add(center); + + LLVector4a v; + + mat.affineTransform(t, v); + + if (first_transform) + { + first_transform = FALSE; + min = max = v; + } + else + { + update_min_max(min, max, v); + } + } + } +} + +void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& max, BOOL& first_transform) +{ + LLVector4a mina, maxa; + LLMatrix4a mata; + + mata.loadu(mat); + mina.load3(min.mV); + maxa.load3(max.mV); + + stretch_extents(model, mata, mina, maxa, first_transform); + + min.set(mina.getF32ptr()); + max.set(maxa.getF32ptr()); +} + +void LLModelLoader::run() +{ + DAE dae; + domCOLLADA* dom = dae.open(mFilename); + + if (dom) + { + daeDatabase* db = dae.getDatabase(); + + daeInt count = db->getElementCount(NULL, COLLADA_TYPE_MESH); + + daeDocument* doc = dae.getDoc(mFilename); + if (!doc) + { + llwarns << "can't find internal doc" << llendl; + return; + } + + daeElement* root = doc->getDomRoot(); + if (!root) + { + llwarns << "document has no root" << llendl; + return; + } + + //get unit scale + mTransform.setIdentity(); + + domAsset::domUnit* unit = daeSafeCast(root->getDescendant(daeElement::matchType(domAsset::domUnit::ID()))); + + if (unit) + { + F32 meter = unit->getMeter(); + mTransform.mMatrix[0][0] = meter; + mTransform.mMatrix[1][1] = meter; + mTransform.mMatrix[2][2] = meter; + } + + //get up axis rotation + LLMatrix4 rotation; + + domUpAxisType up = UPAXISTYPE_Y_UP; // default is Y_UP + domAsset::domUp_axis* up_axis = + daeSafeCast(root->getDescendant(daeElement::matchType(domAsset::domUp_axis::ID()))); + + if (up_axis) + { + up = up_axis->getValue(); + } + + if (up == UPAXISTYPE_X_UP) + { + rotation.initRotation(0.0f, 90.0f * DEG_TO_RAD, 0.0f); + } + else if (up == UPAXISTYPE_Y_UP) + { + rotation.initRotation(90.0f * DEG_TO_RAD, 0.0f, 0.0f); + } + + rotation *= mTransform; + mTransform = rotation; + + + for (daeInt idx = 0; idx < count; ++idx) + { //build map of domEntities to LLModel + domMesh* mesh = NULL; + db->getElement((daeElement**) &mesh, idx, NULL, COLLADA_TYPE_MESH); + + if (mesh) + { + LLPointer model = LLModel::loadModelFromDomMesh(mesh); + + if (model.notNull() && validate_model(model)) + { + mModelList.push_back(model); + mModel[mesh] = model; + } + } + } + + count = db->getElementCount(NULL, COLLADA_TYPE_SKIN); + for (daeInt idx = 0; idx < count; ++idx) + { //add skinned meshes as instances + domSkin* skin = NULL; + db->getElement((daeElement**) &skin, idx, NULL, COLLADA_TYPE_SKIN); + + if (skin) + { + domGeometry* geom = daeSafeCast(skin->getSource().getElement()); + + if (geom) + { + domMesh* mesh = geom->getMesh(); + if (mesh) + { + LLModel* model = mModel[mesh]; + if (model) + { + LLVector3 mesh_scale_vector; + LLVector3 mesh_translation_vector; + model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); + + LLMatrix4 normalized_transformation; + normalized_transformation.setTranslation(mesh_translation_vector); + + LLMatrix4 mesh_scale; + mesh_scale.initScale(mesh_scale_vector); + mesh_scale *= normalized_transformation; + normalized_transformation = mesh_scale; + + glh::matrix4f inv_mat((F32*) normalized_transformation.mMatrix); + inv_mat = inv_mat.inverse(); + LLMatrix4 inverse_normalized_transformation(inv_mat.m); + + domSkin::domBind_shape_matrix* bind_mat = skin->getBind_shape_matrix(); + + if (bind_mat) + { //get bind shape matrix + domFloat4x4& dom_value = bind_mat->getValue(); + + for (int i = 0; i < 4; i++) + { + for(int j = 0; j < 4; j++) + { + model->mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j*4]; + } + } + + LLMatrix4 trans = normalized_transformation; + trans *= model->mBindShapeMatrix; + model->mBindShapeMatrix = trans; + + } + + + //The joint transfom map that we'll populate below + std::map jointTransforms; + jointTransforms.clear(); + + //Some collada setup for accessing the skeleton + daeElement* pElement = 0; + dae.getDatabase()->getElement( &pElement, 0, 0, "skeleton" ); + + //Try to get at the skeletal instance controller + domInstance_controller::domSkeleton* pSkeleton = daeSafeCast( pElement ); + bool missingSkeletonOrScene = false; + + //If no skeleton, do a breadth-first search to get at specific joints + if ( !pSkeleton ) + { + daeElement* pScene = root->getDescendant("visual_scene"); + if ( !pScene ) + { + llwarns<<"No visual scene - unable to parse bone offsets "< > children = pScene->getChildren(); + S32 childCount = children.getCount(); + + //Process any children that are joints + //Not all children are joints, some code be ambient lights, cameras, geometry etc.. + for (S32 i = 0; i < childCount; ++i) + { + domNode* pNode = daeSafeCast(children[i]); + if ( isNodeAJoint( pNode ) ) + { + processJointNode( pNode, jointTransforms ); + } + } + } + } + else + //Has Skeleton + { + //Get the root node of the skeleton + daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement(); + if ( pSkeletonRootNode ) + { + //Once we have the root node - start acccessing it's joint components + const int jointCnt = mJointMap.size(); + std::map :: const_iterator jointIt = mJointMap.begin(); + + //Loop over all the possible joints within the .dae - using the allowed joint list in the ctor. + for ( int i=0; i( resolver.getElement() ); + if ( pJoint ) + { + //Pull out the translate id and store it in the jointTranslations map + daeSIDResolver jointResolver( pJoint, "./translate" ); + domTranslate* pTranslate = daeSafeCast( jointResolver.getElement() ); + + LLMatrix4 workingTransform; + + //Translation via SID + if ( pTranslate ) + { + extractTranslation( pTranslate, workingTransform ); + } + else + { + //Translation via child from element + daeElement* pTranslateElement = getChildFromElement( pJoint, "translate" ); + if ( pTranslateElement && pTranslateElement->typeID() != domTranslate::ID() ) + { + llwarns<< "The found element is not a translate node" < :: const_iterator jointIt = mJointMap.begin(); + for ( int i=0; igetJoint( lookingForJoint ); + if ( pJoint ) + { + pJoint->storeCurrentXform( jointTransform.getTranslation() ); + } + else + { + //Most likely an error in the asset. + llwarns<<"Tried to apply joint position from .dae, but it did not exist in the avatar rig." << llendl; + } + //Reposition the avatars pelvis (avPos+offset) + //if ( lookingForJoint == "mPelvis" ) + //{ + // const LLVector3& pos = gAgentAvatarp->getCharacterPosition(); + // gAgentAvatarp->setPelvisOffset( true, jointTransform.getTranslation() ); + // gAgentAvatarp->setPosition( pos + jointTransform.getTranslation() ); + //} + } + } + } //missingSkeletonOrScene + + domSkin::domJoints* joints = skin->getJoints(); + + domInputLocal_Array& joint_input = joints->getInput_array(); + + for (size_t i = 0; i < joint_input.getCount(); ++i) + { + domInputLocal* input = joint_input.get(i); + xsNMTOKEN semantic = input->getSemantic(); + + if (strcmp(semantic, COMMON_PROFILE_INPUT_JOINT) == 0) + { //found joint source, fill model->mJointMap and model->mJointList + daeElement* elem = input->getSource().getElement(); + + domSource* source = daeSafeCast(elem); + if (source) + { + + + domName_array* names_source = source->getName_array(); + + if (names_source) + { + domListOfNames &names = names_source->getValue(); + + for (size_t j = 0; j < names.getCount(); ++j) + { + std::string name(names.get(j)); + if (mJointMap.find(name) != mJointMap.end()) + { + name = mJointMap[name]; + } + model->mJointList.push_back(name); + model->mJointMap[name] = j; + } + } + else + { + domIDREF_array* names_source = source->getIDREF_array(); + if (names_source) + { + xsIDREFS& names = names_source->getValue(); + + for (size_t j = 0; j < names.getCount(); ++j) + { + std::string name(names.get(j).getID()); + if (mJointMap.find(name) != mJointMap.end()) + { + name = mJointMap[name]; + } + model->mJointList.push_back(name); + model->mJointMap[name] = j; + } + } + } + } + } + else if (strcmp(semantic, COMMON_PROFILE_INPUT_INV_BIND_MATRIX) == 0) + { //found inv_bind_matrix array, fill model->mInvBindMatrix + domSource* source = daeSafeCast(input->getSource().getElement()); + if (source) + { + domFloat_array* t = source->getFloat_array(); + if (t) + { + domListOfFloats& transform = t->getValue(); + S32 count = transform.getCount()/16; + + for (S32 k = 0; k < count; ++k) + { + LLMatrix4 mat; + + for (int i = 0; i < 4; i++) + { + for(int j = 0; j < 4; j++) + { + mat.mMatrix[i][j] = transform[k*16 + i + j*4]; + } + } + + model->mInvBindMatrix.push_back(mat); + } + } + } + } + } + + //We need to construct the alternate bind matrix (which contains the new joint positions) + //in the same order as they were stored in the joint buffer. The joints associated + //with the skeleton are not stored in the same order as they are in the exported joint buffer. + //This remaps the skeletal joints to be in the same order as the joints stored in the model. + std::vector :: const_iterator jointIt = model->mJointList.begin(); + const int jointCnt = model->mJointList.size(); + for ( int i=0; imInvBindMatrix[i]; + newInverse.setTranslation( jointTransforms[lookingForJoint].getTranslation() ); + model->mAlternateBindMatrix.push_back( newInverse ); + } + else + { + llwarns<<"Possibly misnamed/missing joint [" <getVertices(); + if (verts) + { + domInputLocal_Array& inputs = verts->getInput_array(); + for (size_t i = 0; i < inputs.getCount() && model->mPosition.empty(); ++i) + { + if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_POSITION) == 0) + { + domSource* pos_source = daeSafeCast(inputs[i]->getSource().getElement()); + if (pos_source) + { + domFloat_array* pos_array = pos_source->getFloat_array(); + if (pos_array) + { + domListOfFloats& pos = pos_array->getValue(); + + for (size_t j = 0; j < pos.getCount(); j += 3) + { + if (pos.getCount() <= j+2) + { + llerrs << "WTF?" << llendl; + } + + LLVector3 v(pos[j], pos[j+1], pos[j+2]); + + //transform from COLLADA space to volume space + v = v * inverse_normalized_transformation; + + model->mPosition.push_back(v); + } + } + } + } + } + } + + //grab skin weights array + domSkin::domVertex_weights* weights = skin->getVertex_weights(); + if (weights) + { + domInputLocalOffset_Array& inputs = weights->getInput_array(); + domFloat_array* vertex_weights = NULL; + for (size_t i = 0; i < inputs.getCount(); ++i) + { + if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_WEIGHT) == 0) + { + domSource* weight_source = daeSafeCast(inputs[i]->getSource().getElement()); + if (weight_source) + { + vertex_weights = weight_source->getFloat_array(); + } + } + } + + if (vertex_weights) + { + domListOfFloats& w = vertex_weights->getValue(); + domListOfUInts& vcount = weights->getVcount()->getValue(); + domListOfInts& v = weights->getV()->getValue(); + + U32 c_idx = 0; + for (size_t vc_idx = 0; vc_idx < vcount.getCount(); ++vc_idx) + { //for each vertex + daeUInt count = vcount[vc_idx]; + + //create list of weights that influence this vertex + LLModel::weight_list weight_list; + + for (daeUInt i = 0; i < count; ++i) + { //for each weight + daeInt joint_idx = v[c_idx++]; + daeInt weight_idx = v[c_idx++]; + + if (joint_idx == -1) + { + //ignore bindings to bind_shape_matrix + continue; + } + + F32 weight_value = w[weight_idx]; + + weight_list.push_back(LLModel::JointWeight(joint_idx, weight_value)); + } + + //sort by joint weight + std::sort(weight_list.begin(), weight_list.end(), LLModel::CompareWeightGreater()); + + std::vector wght; + + F32 total = 0.f; + + for (U32 i = 0; i < llmin((U32) 4, (U32) weight_list.size()); ++i) + { //take up to 4 most significant weights + if (weight_list[i].mWeight > 0.f) + { + wght.push_back( weight_list[i] ); + total += weight_list[i].mWeight; + } + } + + F32 scale = 1.f/total; + if (scale != 1.f) + { //normalize weights + for (U32 i = 0; i < wght.size(); ++i) + { + wght[i].mWeight *= scale; + } + } + + model->mSkinWeights[model->mPosition[vc_idx]] = wght; + } + + //add instance to scene for this model + + LLMatrix4 transformation = mTransform; + // adjust the transformation to compensate for mesh normalization + + LLMatrix4 mesh_translation; + mesh_translation.setTranslation(mesh_translation_vector); + mesh_translation *= transformation; + transformation = mesh_translation; + + LLMatrix4 mesh_scale; + mesh_scale.initScale(mesh_scale_vector); + mesh_scale *= transformation; + transformation = mesh_scale; + + std::vector materials; + materials.resize(model->getNumVolumeFaces()); + mScene[transformation].push_back(LLModelInstance(model, transformation, materials)); + stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); + } + } + } + } + } + } + } + + daeElement* scene = root->getDescendant("visual_scene"); + + if (!scene) + { + llwarns << "document has no visual_scene" << llendl; + setLoadState( ERROR_PARSING ); + return; + } + + setLoadState( DONE ); + + processElement(scene); + + doOnIdleOneTime(boost::bind(&LLModelPreview::loadModelCallback,mPreview,mLod)); + } +} + +bool LLModelLoader::isNodeAJoint( domNode* pNode ) +{ + if ( pNode->getName() == NULL) + { + return false; + } + + if ( mJointMap.find( pNode->getName() ) != mJointMap.end() ) + { + return true; + } + + return false; +} + +void LLModelLoader::extractTranslation( domTranslate* pTranslate, LLMatrix4& transform ) +{ + domFloat3 jointTrans = pTranslate->getValue(); + LLVector3 singleJointTranslation( jointTrans[0], jointTrans[1], jointTrans[2] ); + transform.setTranslation( singleJointTranslation ); +} + +void LLModelLoader::extractTranslationViaElement( daeElement* pTranslateElement, LLMatrix4& transform ) +{ + domTranslate* pTranslateChild = dynamic_cast( pTranslateElement ); + domFloat3 translateChild = pTranslateChild->getValue(); + LLVector3 singleJointTranslation( translateChild[0], translateChild[1], translateChild[2] ); + transform.setTranslation( singleJointTranslation ); +} + +void LLModelLoader::processJointNode( domNode* pNode, std::map& jointTransforms ) +{ + if (pNode->getName() == NULL) + { + llwarns << "nameless node, can't process" << llendl; + return; + } + + //llwarns<<"ProcessJointNode# Node:" <getName()<( jointResolver.getElement() ); + + //Translation via SID was successful + if ( pTranslate ) + { + extractTranslation( pTranslate, workingTransform ); + } + else + { + //Translation via child from element + daeElement* pTranslateElement = getChildFromElement( pNode, "translate" ); + if ( !pTranslateElement || pTranslateElement->typeID() != domTranslate::ID() ) + { + llwarns<< "The found element is not a translate node" <getName() ] = workingTransform; + + //2. handle the nodes children + + //Gather and handle the incoming nodes children + daeTArray< daeSmartRef > childOfChild = pNode->getChildren(); + S32 childOfChildCount = childOfChild.getCount(); + + for (S32 i = 0; i < childOfChildCount; ++i) + { + domNode* pChildNode = daeSafeCast( childOfChild[i] ); + if ( pChildNode ) + { + processJointNode( pChildNode, jointTransforms ); + } + } +} + +daeElement* LLModelLoader::getChildFromElement( daeElement* pElement, std::string const & name ) +{ + daeElement* pChildOfElement = pElement->getChild( name.c_str() ); + if ( pChildOfElement ) + { + return pChildOfElement; + } + llwarns<< "Could not find a child [" << name << "] for the element: \"" << pElement->getAttribute("id") << "\"" << llendl; + return NULL; +} + +void LLModelLoader::processElement(daeElement* element) +{ + LLMatrix4 saved_transform = mTransform; + + domTranslate* translate = daeSafeCast(element); + if (translate) + { + domFloat3 dom_value = translate->getValue(); + + LLMatrix4 translation; + translation.setTranslation(LLVector3(dom_value[0], dom_value[1], dom_value[2])); + + translation *= mTransform; + mTransform = translation; + } + + domRotate* rotate = daeSafeCast(element); + if (rotate) + { + domFloat4 dom_value = rotate->getValue(); + + LLMatrix4 rotation; + rotation.initRotTrans(dom_value[3] * DEG_TO_RAD, LLVector3(dom_value[0], dom_value[1], dom_value[2]), LLVector3(0, 0, 0)); + + rotation *= mTransform; + mTransform = rotation; + } + + domScale* scale = daeSafeCast(element); + if (scale) + { + domFloat3 dom_value = scale->getValue(); + + LLMatrix4 scaling; + scaling.initScale(LLVector3(dom_value[0], dom_value[1], dom_value[2])); + + scaling *= mTransform; + mTransform = scaling; + } + + domMatrix* matrix = daeSafeCast(element); + if (matrix) + { + domFloat4x4 dom_value = matrix->getValue(); + + LLMatrix4 matrix_transform; + + for (int i = 0; i < 4; i++) + { + for(int j = 0; j < 4; j++) + { + matrix_transform.mMatrix[i][j] = dom_value[i + j*4]; + } + } + + matrix_transform *= mTransform; + mTransform = matrix_transform; + } + + domInstance_geometry* instance_geo = daeSafeCast(element); + if (instance_geo) + { + domGeometry* geo = daeSafeCast(instance_geo->getUrl().getElement()); + if (geo) + { + domMesh* mesh = daeSafeCast(geo->getDescendant(daeElement::matchType(domMesh::ID()))); + if (mesh) + { + LLModel* model = mModel[mesh]; + if (model) + { + LLMatrix4 transformation = mTransform; + + std::vector materials = getMaterials(model, instance_geo); + + // adjust the transformation to compensate for mesh normalization + LLVector3 mesh_scale_vector; + LLVector3 mesh_translation_vector; + model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); + + LLMatrix4 mesh_translation; + mesh_translation.setTranslation(mesh_translation_vector); + mesh_translation *= transformation; + transformation = mesh_translation; + + LLMatrix4 mesh_scale; + mesh_scale.initScale(mesh_scale_vector); + mesh_scale *= transformation; + transformation = mesh_scale; + + mScene[transformation].push_back(LLModelInstance(model, transformation, materials)); + + stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); + } + } + } + } + + domInstance_node* instance_node = daeSafeCast(element); + if (instance_node) + { + daeElement* instance = instance_node->getUrl().getElement(); + if (instance) + { + processElement(instance); + } + } + + //process children + daeTArray< daeSmartRef > children = element->getChildren(); + for (S32 i = 0; i < children.getCount(); i++) + { + processElement(children[i]); + } + + domNode* node = daeSafeCast(element); + if (node) + { //this element was a node, restore transform before processiing siblings + mTransform = saved_transform; + } +} + +std::vector LLModelLoader::getMaterials(LLModel* model, domInstance_geometry* instance_geo) +{ + std::vector materials; + for (int i = 0; i < model->mMaterialList.size(); i++) + { + LLImportMaterial import_material; + + domInstance_material* instance_mat = NULL; + + domBind_material::domTechnique_common* technique = + daeSafeCast(instance_geo->getDescendant(daeElement::matchType(domBind_material::domTechnique_common::ID()))); + + if (technique) + { + daeTArray< daeSmartRef > inst_materials = technique->getChildrenByType(); + for (int j = 0; j < inst_materials.getCount(); j++) + { + std::string symbol(inst_materials[j]->getSymbol()); + + if (symbol == model->mMaterialList[i]) // found the binding + { + instance_mat = inst_materials[j]; + } + } + } + + if (instance_mat) + { + domMaterial* material = daeSafeCast(instance_mat->getTarget().getElement()); + if (material) + { + domInstance_effect* instance_effect = + daeSafeCast(material->getDescendant(daeElement::matchType(domInstance_effect::ID()))); + if (instance_effect) + { + domEffect* effect = daeSafeCast(instance_effect->getUrl().getElement()); + if (effect) + { + domProfile_COMMON* profile = + daeSafeCast(effect->getDescendant(daeElement::matchType(domProfile_COMMON::ID()))); + if (profile) + { + import_material = profileToMaterial(profile); + } + } + } + } + } + + materials.push_back(import_material); + } + + return materials; +} + +LLImportMaterial LLModelLoader::profileToMaterial(domProfile_COMMON* material) +{ + LLImportMaterial mat; + mat.mFullbright = FALSE; + + daeElement* diffuse = material->getDescendant("diffuse"); + if (diffuse) + { + domCommon_color_or_texture_type_complexType::domTexture* texture = + daeSafeCast(diffuse->getDescendant("texture")); + if (texture) + { + domCommon_newparam_type_Array newparams = material->getNewparam_array(); + for (S32 i = 0; i < newparams.getCount(); i++) + { + domFx_surface_common* surface = newparams[i]->getSurface(); + if (surface) + { + domFx_surface_init_common* init = surface->getFx_surface_init_common(); + if (init) + { + domFx_surface_init_from_common_Array init_from = init->getInit_from_array(); + + if (init_from.getCount() > i) + { + domImage* image = daeSafeCast(init_from[i]->getValue().getElement()); + if (image) + { + // we only support init_from now - embedded data will come later + domImage::domInit_from* init = image->getInit_from(); + if (init) + { + std::string filename = cdom::uriToNativePath(init->getValue().str()); + + mat.mDiffuseMap = LLViewerTextureManager::getFetchedTextureFromUrl("file://" + filename, TRUE, LLViewerTexture::BOOST_PREVIEW); + mat.mDiffuseMap->setLoadedCallback(LLModelPreview::textureLoadedCallback, 0, TRUE, FALSE, this->mPreview, NULL, FALSE); + + mat.mDiffuseMap->forceToSaveRawImage(); + mat.mDiffuseMapFilename = filename; + mat.mDiffuseMapLabel = getElementLabel(material); + } + } + } + } + } + } + } + + domCommon_color_or_texture_type_complexType::domColor* color = + daeSafeCast(diffuse->getDescendant("color")); + if (color) + { + domFx_color_common domfx_color = color->getValue(); + LLColor4 value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]); + mat.mDiffuseColor = value; + } + } + + daeElement* emission = material->getDescendant("emission"); + if (emission) + { + LLColor4 emission_color = getDaeColor(emission); + if (((emission_color[0] + emission_color[1] + emission_color[2]) / 3.0) > 0.25) + { + mat.mFullbright = TRUE; + } + } + + return mat; +} + +// try to get a decent label for this element +std::string LLModelLoader::getElementLabel(daeElement *element) +{ + // if we have a name attribute, use it + std::string name = element->getAttribute("name"); + if (name.length()) + { + return name; + } + + // if we have an ID attribute, use it + if (element->getID()) + { + return std::string(element->getID()); + } + + // if we have a parent, use it + daeElement* parent = element->getParent(); + if (parent) + { + // if parent has a name, use it + std::string name = parent->getAttribute("name"); + if (name.length()) + { + return name; + } + + // if parent has an ID, use it + if (parent->getID()) + { + return std::string(parent->getID()); + } + } + + // try to use our type + daeString element_name = element->getElementName(); + if (element_name) + { + return std::string(element_name); + } + + // if all else fails, use "object" + return std::string("object"); +} + +LLColor4 LLModelLoader::getDaeColor(daeElement* element) +{ + LLColor4 value; + domCommon_color_or_texture_type_complexType::domColor* color = + daeSafeCast(element->getDescendant("color")); + if (color) + { + domFx_color_common domfx_color = color->getValue(); + value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]); + } + + return value; +} + +//----------------------------------------------------------------------------- +// LLModelPreview +//----------------------------------------------------------------------------- + +LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) +: LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE), LLMutex(NULL) +{ + mNeedsUpdate = TRUE; + mCameraDistance = 0.f; + mCameraYaw = 0.f; + mCameraPitch = 0.f; + mCameraZoom = 1.f; + mTextureName = 0; + mPreviewLOD = 0; + mModelLoader = NULL; + mMaxTriangleLimit = 0; + mDirty = false; + mGenLOD = false; + mLoading = false; + mGroup = 0; + mBuildShareTolerance = 0.f; + mBuildQueueMode = GLOD_QUEUE_GREEDY; + mBuildBorderMode = GLOD_BORDER_UNLOCK; + mBuildOperator = GLOD_OPERATOR_HALF_EDGE_COLLAPSE; + + mViewOption["show_textures"] = false; + + mFMP = fmp; + + glodInit(); +} + +LLModelPreview::~LLModelPreview() +{ + if (mModelLoader) + { + delete mModelLoader; + mModelLoader = NULL; + } + + //*HACK : *TODO : turn this back on when we understand why this crashes + //glodShutdown(); +} + +U32 LLModelPreview::calcResourceCost() +{ + assert_main_thread(); + + rebuildUploadData(); + + if ( mModelLoader->getLoadState() != LLModelLoader::ERROR_PARSING ) + { + mFMP->childEnable("ok_btn"); + } + + U32 cost = 0; + std::set accounted; + U32 num_points = 0; + U32 num_hulls = 0; + + F32 debug_scale = mFMP->childGetValue("import_scale").asReal(); + + F32 streaming_cost = 0.f; + F32 physics_cost = 0.f; + for (U32 i = 0; i < mUploadData.size(); ++i) + { + LLModelInstance& instance = mUploadData[i]; + + if (accounted.find(instance.mModel) == accounted.end()) + { + accounted.insert(instance.mModel); + + LLModel::convex_hull_decomposition& decomp = + instance.mLOD[LLModel::LOD_PHYSICS] ? + instance.mLOD[LLModel::LOD_PHYSICS]->mConvexHullDecomp : + instance.mModel->mConvexHullDecomp; + + LLSD ret = LLModel::writeModel( + "", + instance.mLOD[4], + instance.mLOD[3], + instance.mLOD[2], + instance.mLOD[1], + instance.mLOD[0], + decomp, + mFMP->childGetValue("upload_skin").asBoolean(), + mFMP->childGetValue("upload_joints").asBoolean(), + TRUE); + cost += gMeshRepo.calcResourceCost(ret); + + num_hulls += decomp.size(); + for (U32 i = 0; i < decomp.size(); ++i) + { + num_points += decomp[i].size(); + } + + //calculate streaming cost + LLMatrix4 transformation = instance.mTransform; + + LLVector3 position = LLVector3(0, 0, 0) * transformation; + + LLVector3 x_transformed = LLVector3(1, 0, 0) * transformation - position; + LLVector3 y_transformed = LLVector3(0, 1, 0) * transformation - position; + LLVector3 z_transformed = LLVector3(0, 0, 1) * transformation - position; + F32 x_length = x_transformed.normalize(); + F32 y_length = y_transformed.normalize(); + F32 z_length = z_transformed.normalize(); + LLVector3 scale = LLVector3(x_length, y_length, z_length); + + F32 radius = scale.length()*debug_scale; + + streaming_cost += LLMeshRepository::getStreamingCost(ret, radius); + } + } + + //mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[HULLS]", llformat("%d",num_hulls)); + //mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[POINTS]", llformat("%d",num_points)); + F32 scale = mFMP->childGetValue("import_scale").asReal()*2.f; + + mDetailsSignal(mPreviewScale[0]*scale, mPreviewScale[1]*scale, mPreviewScale[2]*scale, streaming_cost, physics_cost); + + updateStatusMessages(); + + return cost; +} + +void LLFloaterModelPreview::setDetails(F32 x, F32 y, F32 z, F32 streaming_cost, F32 physics_cost) +{ + childSetTextArg("import_dimensions", "[X]", llformat("%.3f", x)); + childSetTextArg("import_dimensions", "[Y]", llformat("%.3f", y)); + childSetTextArg("import_dimensions", "[Z]", llformat("%.3f", z)); + childSetTextArg("streaming cost", "[COST]", llformat("%.3f", streaming_cost)); + childSetTextArg("physics cost", "[COST]", llformat("%.3f", physics_cost)); +} + +void LLModelPreview::rebuildUploadData() +{ + assert_main_thread(); + + mUploadData.clear(); + mTextureSet.clear(); + + //fill uploaddata instance vectors from scene data + + std::string requested_name = mFMP->getChild("description_form")->getValue().asString(); + + + LLSpinCtrl* scale_spinner = mFMP->getChild("import_scale"); + + if (!scale_spinner) + { + llerrs << "floater_model_preview.xml MUST contain import_scale spinner." << llendl; + } + + F32 scale = scale_spinner->getValue().asReal(); + + LLMatrix4 scale_mat; + scale_mat.initScale(LLVector3(scale, scale, scale)); + + F32 max_scale = 0.f; + + if ( mBaseScene.size() > 0 ) + { + mFMP->childEnable("ok_btn"); + } + + for (LLModelLoader::scene::iterator iter = mBaseScene.begin(); iter != mBaseScene.end(); ++iter) + { //for each transform in scene + LLMatrix4 mat = iter->first; + + // compute position + LLVector3 position = LLVector3(0, 0, 0) * mat; + + // compute scale + LLVector3 x_transformed = LLVector3(1, 0, 0) * mat - position; + LLVector3 y_transformed = LLVector3(0, 1, 0) * mat - position; + LLVector3 z_transformed = LLVector3(0, 0, 1) * mat - position; + F32 x_length = x_transformed.normalize(); + F32 y_length = y_transformed.normalize(); + F32 z_length = z_transformed.normalize(); + + max_scale = llmax(llmax(llmax(max_scale, x_length), y_length), z_length); + + mat *= scale_mat; + + for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) + { //for each instance with said transform applied + LLModelInstance instance = *model_iter; + + LLModel* base_model = instance.mModel; + if (base_model) + { + base_model->mRequestedLabel = requested_name; + } + + S32 idx = 0; + for (idx = 0; idx < mBaseModel.size(); ++idx) + { //find reference instance for this model + if (mBaseModel[idx] == base_model) + { + break; + } + } + + for (U32 i = 0; i < LLModel::NUM_LODS; i++) + { //fill LOD slots based on reference model index + if (!mModel[i].empty()) + { + instance.mLOD[i] = mModel[i][idx]; + } + else + { + instance.mLOD[i] = NULL; + } + } + + instance.mTransform = mat; + mUploadData.push_back(instance); + } + } + + F32 max_import_scale = DEFAULT_MAX_PRIM_SCALE/max_scale; + + scale_spinner->setMaxValue(max_import_scale); + + if (max_import_scale < scale) + { + scale_spinner->setValue(max_import_scale); + } + +} + + +void LLModelPreview::clearModel(S32 lod) +{ + if (lod < 0 || lod > LLModel::LOD_PHYSICS) + { + return; + } + + mVertexBuffer[lod].clear(); + mModel[lod].clear(); + mScene[lod].clear(); +} + +void LLModelPreview::loadModel(std::string filename, S32 lod) +{ + assert_main_thread(); + + LLMutexLock lock(this); + + if (mModelLoader) + { + delete mModelLoader; + mModelLoader = NULL; + } + + if (filename.empty()) + { + if (mBaseModel.empty()) + { + // this is the initial file picking. Close the whole floater + // if we don't have a base model to show for high LOD. + mFMP->closeFloater(false); + } + + mLoading = false; + return; + } + + mLODFile[lod] = filename; + + if (lod == LLModel::LOD_HIGH) + { + clearGLODGroup(); + } + + mModelLoader = new LLModelLoader(filename, lod, this); + + mModelLoader->start(); + + mFMP->childSetTextArg("status", "[STATUS]", mFMP->getString("status_reading_file")); + + setPreviewLOD(lod); + + if ( mModelLoader->getLoadState() == LLModelLoader::ERROR_PARSING ) + { + mFMP->childDisable("ok_btn"); + } + + if (lod == mPreviewLOD) + { + mFMP->childSetText("lod_file", mLODFile[mPreviewLOD]); + } + else if (lod == LLModel::LOD_PHYSICS) + { + mFMP->childSetText("physics_file", mLODFile[lod]); + } + + mFMP->openFloater(); +} + +void LLModelPreview::setPhysicsFromLOD(S32 lod) +{ + assert_main_thread(); + + if (lod >= 0 && lod <= 3) + { + mModel[LLModel::LOD_PHYSICS] = mModel[lod]; + mScene[LLModel::LOD_PHYSICS] = mScene[lod]; + mLODFile[LLModel::LOD_PHYSICS].clear(); + mFMP->childSetText("physics_file", mLODFile[LLModel::LOD_PHYSICS]); + mVertexBuffer[LLModel::LOD_PHYSICS].clear(); + rebuildUploadData(); + refresh(); + updateStatusMessages(); + } +} + +void LLModelPreview::clearIncompatible(S32 lod) +{ + for (U32 i = 0; i <= LLModel::LOD_HIGH; i++) + { //clear out any entries that aren't compatible with this model + if (i != lod) + { + if (mModel[i].size() != mModel[lod].size()) + { + mModel[i].clear(); + mScene[i].clear(); + mVertexBuffer[i].clear(); + + if (i == LLModel::LOD_HIGH) + { + mBaseModel = mModel[lod]; + clearGLODGroup(); + mBaseScene = mScene[lod]; + mVertexBuffer[5].clear(); + } + } + } + } +} + +void LLModelPreview::clearGLODGroup() +{ + if (mGroup) + { + for (std::map, U32>::iterator iter = mObject.begin(); iter != mObject.end(); ++iter) + { + glodDeleteObject(iter->second); + stop_gloderror(); + } + mObject.clear(); + + glodDeleteGroup(mGroup); + stop_gloderror(); + mGroup = 0; + } +} + +void LLModelPreview::loadModelCallback(S32 lod) +{ + assert_main_thread(); + + LLMutexLock lock(this); + if (!mModelLoader) + { + return; + } + + mModel[lod] = mModelLoader->mModelList; + mScene[lod] = mModelLoader->mScene; + mVertexBuffer[lod].clear(); + + if (lod == LLModel::LOD_PHYSICS) + { + mPhysicsMesh.clear(); + } + + setPreviewLOD(lod); + + + if (lod == LLModel::LOD_HIGH) + { //save a copy of the highest LOD for automatic LOD manipulation + if (mBaseModel.empty()) + { //first time we've loaded a model, auto-gen LoD + mGenLOD = true; + } + + mBaseModel = mModel[lod]; + clearGLODGroup(); + + mBaseScene = mScene[lod]; + mVertexBuffer[5].clear(); + } + + clearIncompatible(lod); + + mDirty = true; + + if (lod == LLModel::LOD_HIGH) + { + resetPreviewTarget(); + } + + mLoading = false; + refresh(); +} + +void LLModelPreview::resetPreviewTarget() +{ + mPreviewTarget = (mModelLoader->mExtents[0] + mModelLoader->mExtents[1]) * 0.5f; + mPreviewScale = (mModelLoader->mExtents[1] - mModelLoader->mExtents[0]) * 0.5f; + setPreviewTarget(mPreviewScale.magVec()*2.f); +} + +void LLModelPreview::generateNormals() +{ + assert_main_thread(); + + S32 which_lod = mPreviewLOD; + + + if (which_lod > 4 || which_lod < 0 || + mModel[which_lod].empty()) + { + return; + } + + F32 angle_cutoff = mFMP->childGetValue("crease_angle").asReal(); + + angle_cutoff *= DEG_TO_RAD; + + if (which_lod == 3 && !mBaseModel.empty()) + { + for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) + { + (*iter)->generateNormals(angle_cutoff); + } + + mVertexBuffer[5].clear(); + } + + for (LLModelLoader::model_list::iterator iter = mModel[which_lod].begin(); iter != mModel[which_lod].end(); ++iter) + { + (*iter)->generateNormals(angle_cutoff); + } + + mVertexBuffer[which_lod].clear(); + refresh(); + +} + +void LLModelPreview::consolidate() +{ + std::map > composite; + + LLMatrix4 identity; + + //bake out each node in current scene to composite + for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) + { //for each transform in current scene + LLMatrix4 mat = iter->first; + glh::matrix4f inv_trans = glh::matrix4f((F32*) mat.mMatrix).inverse().transpose(); + LLMatrix4 norm_mat(inv_trans.m); + + for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) + { //for each instance with that transform + LLModelInstance& source_instance = *model_iter; + LLModel* source = source_instance.mModel; + + if (!validate_model(source)) + { + llerrs << "Invalid model found!" << llendl; + } + + for (S32 i = 0; i < source->getNumVolumeFaces(); ++i) + { //for each face in instance + const LLVolumeFace& src_face = source->getVolumeFace(i); + LLImportMaterial& source_material = source_instance.mMaterial[i]; + + //get model in composite that is composite for this material + LLModel* model = NULL; + + if (composite.find(source_material) != composite.end()) + { + model = composite[source_material].rbegin()->mModel; + if (model->getVolumeFace(0).mNumVertices + src_face.mNumVertices > 65535) + { + model = NULL; + } + } + + if (model == NULL) + { //no model found, make new model + std::vector materials; + materials.push_back(source_material); + LLVolumeParams volume_params; + volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); + model = new LLModel(volume_params, 0.f); + model->mLabel = source->mLabel; + model->setNumVolumeFaces(0); + composite[source_material].push_back(LLModelInstance(model, identity, materials)); + } + + model->appendFace(src_face, source->mMaterialList[i], mat, norm_mat); + } + } + } + + + //condense composite into as few LLModel instances as possible + LLModelLoader::model_list new_model; + std::vector instance_list; + + LLVolumeParams volume_params; + volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); + + std::vector empty_material; + LLModelInstance cur_instance(new LLModel(volume_params, 0.f), identity, empty_material); + cur_instance.mModel->setNumVolumeFaces(0); + + BOOL first_transform = TRUE; + + LLModelLoader::scene new_scene; + LLVector3 min,max; + + for (std::map >::iterator iter = composite.begin(); + iter != composite.end(); + ++iter) + { + std::map >::iterator next_iter = iter; ++next_iter; + + for (std::vector::iterator instance_iter = iter->second.begin(); + instance_iter != iter->second.end(); + ++instance_iter) + { + LLModel* source = instance_iter->mModel; + + if (instance_iter->mMaterial.size() != 1) + { + llerrs << "WTF?" << llendl; + } + + if (source->getNumVolumeFaces() != 1) + { + llerrs << "WTF?" << llendl; + } + + if (source->mMaterialList.size() != 1) + { + llerrs << "WTF?" << llendl; + } + + cur_instance.mModel->addFace(source->getVolumeFace(0)); + cur_instance.mMaterial.push_back(instance_iter->mMaterial[0]); + cur_instance.mModel->mMaterialList.push_back(source->mMaterialList[0]); + + BOOL last_model = FALSE; + + std::vector::iterator next_instance = instance_iter; ++next_instance; + + if (next_iter == composite.end() && + next_instance == iter->second.end()) + { + last_model = TRUE; + } + + if (last_model || cur_instance.mModel->getNumVolumeFaces() >= MAX_MODEL_FACES) + { + cur_instance.mModel->mLabel = source->mLabel; + + cur_instance.mModel->optimizeVolumeFaces(); + cur_instance.mModel->normalizeVolumeFaces(); + + if (!validate_model(cur_instance.mModel)) + { + llerrs << "Invalid model detected." << llendl; + } + + new_model.push_back(cur_instance.mModel); + + LLMatrix4 transformation = LLMatrix4(); + + // adjust the transformation to compensate for mesh normalization + LLVector3 mesh_scale_vector; + LLVector3 mesh_translation_vector; + cur_instance.mModel->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); + + LLMatrix4 mesh_translation; + mesh_translation.setTranslation(mesh_translation_vector); + mesh_translation *= transformation; + transformation = mesh_translation; + + LLMatrix4 mesh_scale; + mesh_scale.initScale(mesh_scale_vector); + mesh_scale *= transformation; + transformation = mesh_scale; + + cur_instance.mTransform = transformation; + + new_scene[transformation].push_back(cur_instance); + stretch_extents(cur_instance.mModel, transformation, min, max, first_transform); + + if (!last_model) + { + cur_instance = LLModelInstance(new LLModel(volume_params, 0.f), identity, empty_material); + cur_instance.mModel->setNumVolumeFaces(0); + } + } + } + } + + mScene[mPreviewLOD] = new_scene; + mModel[mPreviewLOD] = new_model; + mVertexBuffer[mPreviewLOD].clear(); + + if (mPreviewLOD == LLModel::LOD_HIGH) + { + mBaseScene = new_scene; + mBaseModel = new_model; + clearGLODGroup(); + mVertexBuffer[5].clear(); + } + + mPreviewTarget = (min+max)*0.5f; + mPreviewScale = (max-min)*0.5f; + setPreviewTarget(mPreviewScale.magVec()*2.f); + + clearIncompatible(mPreviewLOD); + + mResourceCost = calcResourceCost(); + refresh(); +} + +void LLModelPreview::clearMaterials() +{ + for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) + { //for each transform in current scene + for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) + { //for each instance with that transform + LLModelInstance& source_instance = *model_iter; + LLModel* source = source_instance.mModel; + + for (S32 i = 0; i < source->getNumVolumeFaces(); ++i) + { //for each face in instance + LLImportMaterial& source_material = source_instance.mMaterial[i]; + + //clear material info + source_material.mDiffuseColor = LLColor4(1,1,1,1); + source_material.mDiffuseMap = NULL; + source_material.mDiffuseMapFilename.clear(); + source_material.mDiffuseMapLabel.clear(); + source_material.mFullbright = false; + } + } + } + + mVertexBuffer[mPreviewLOD].clear(); + + if (mPreviewLOD == LLModel::LOD_HIGH) + { + mBaseScene = mScene[mPreviewLOD]; + mBaseModel = mModel[mPreviewLOD]; + clearGLODGroup(); + mVertexBuffer[5].clear(); + } + + mResourceCost = calcResourceCost(); + refresh(); +} + +bool LLModelPreview::containsRiggedAsset( void ) +{ + //loop through the models and determine if any of them contained a rigged asset, and if so + //return true. + //This is used to cleanup the joint positions after a preview. + for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) + { + LLModel* pModel = *iter; + if ( pModel->mAlternateBindMatrix.size() > 0 ) + { + return true; + } + } + return false; +} +void LLModelPreview::genLODs(S32 which_lod, U32 decimation) +{ + if (mBaseModel.empty()) + { + return; + } + + if (which_lod == LLModel::LOD_PHYSICS) + { //clear physics mesh map + mPhysicsMesh.clear(); + } + + LLVertexBuffer::unbind(); + + stop_gloderror(); + static U32 cur_name = 1; + + S32 limit = -1; + + U32 triangle_count = 0; + + for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) + { + LLModel* mdl = *iter; + for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) + { + triangle_count += mdl->getVolumeFace(i).mNumIndices/3; + } + } + + U32 base_triangle_count = triangle_count; + + U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; + + U32 lod_mode = 0; + + LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode"); + if (iface) + { + lod_mode = iface->getFirstSelectedIndex(); + } + + F32 lod_error_threshold = mFMP->childGetValue("lod_error_threshold").asReal(); + + if (lod_mode == 0) + { + lod_mode = GLOD_TRIANGLE_BUDGET; + if (which_lod != -1) + { + limit = mFMP->childGetValue("lod_triangle_limit").asInteger(); + } + } + else + { + lod_mode = GLOD_ERROR_THRESHOLD; + } + + U32 build_operator = 0; + + iface = mFMP->childGetSelectionInterface("build_operator"); + if (iface) + { + build_operator = iface->getFirstSelectedIndex(); + } + + if (build_operator == 0) + { + build_operator = GLOD_OPERATOR_HALF_EDGE_COLLAPSE; + } + else + { + build_operator = GLOD_OPERATOR_EDGE_COLLAPSE; + } + + U32 queue_mode=0; + iface = mFMP->childGetSelectionInterface("queue_mode"); + if (iface) + { + queue_mode = iface->getFirstSelectedIndex(); + } + + if (queue_mode == 0) + { + queue_mode = GLOD_QUEUE_GREEDY; + } + else if (queue_mode == 1) + { + queue_mode = GLOD_QUEUE_LAZY; + } + else + { + queue_mode = GLOD_QUEUE_INDEPENDENT; + } + + U32 border_mode = 0; + + iface = mFMP->childGetSelectionInterface("border_mode"); + if (iface) + { + border_mode = iface->getFirstSelectedIndex(); + } + + if (border_mode == 0) + { + border_mode = GLOD_BORDER_UNLOCK; + } + else + { + border_mode = GLOD_BORDER_LOCK; + } + + bool object_dirty = false; + if (border_mode != mBuildBorderMode) + { + mBuildBorderMode = border_mode; + object_dirty = true; + } + + if (queue_mode != mBuildQueueMode) + { + mBuildQueueMode = queue_mode; + object_dirty = true; + } + + if (build_operator != mBuildOperator) + { + mBuildOperator = build_operator; + object_dirty = true; + } + + F32 share_tolerance = mFMP->childGetValue("share_tolerance").asReal(); + if (share_tolerance != mBuildShareTolerance) + { + mBuildShareTolerance = share_tolerance; + object_dirty = true; + } + + if (mGroup == 0) + { + object_dirty = true; + mGroup = cur_name++; + glodNewGroup(mGroup); + } + + if (object_dirty) + { + for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) + { //build GLOD objects for each model in base model list + LLModel* mdl = *iter; + + if (mObject[mdl] != 0) + { + glodDeleteObject(mObject[mdl]); + } + + mObject[mdl] = cur_name++; + + glodNewObject(mObject[mdl], mGroup, GLOD_DISCRETE); + stop_gloderror(); + + if (iter == mBaseModel.begin() && !mdl->mSkinWeights.empty()) + { //regenerate vertex buffer for skinned models to prevent animation feedback during LOD generation + mVertexBuffer[5].clear(); + } + + if (mVertexBuffer[5].empty()) + { + genBuffers(5, false); + } + + U32 tri_count = 0; + for (U32 i = 0; i < mVertexBuffer[5][mdl].size(); ++i) + { + mVertexBuffer[5][mdl][i]->setBuffer(type_mask); + U32 num_indices = mVertexBuffer[5][mdl][i]->getNumIndices(); + if (num_indices > 2) + { + glodInsertElements(mObject[mdl], i, GL_TRIANGLES, num_indices, GL_UNSIGNED_SHORT, mVertexBuffer[5][mdl][i]->getIndicesPointer(), 0, 0.f); + } + tri_count += num_indices/3; + stop_gloderror(); + } + + glodObjectParameteri(mObject[mdl], GLOD_BUILD_OPERATOR, build_operator); + stop_gloderror(); + + glodObjectParameteri(mObject[mdl], GLOD_BUILD_QUEUE_MODE, queue_mode); + stop_gloderror(); + + glodObjectParameteri(mObject[mdl], GLOD_BUILD_BORDER_MODE, border_mode); + stop_gloderror(); + + glodObjectParameterf(mObject[mdl], GLOD_BUILD_SHARE_TOLERANCE, share_tolerance); + stop_gloderror(); + + glodBuildObject(mObject[mdl]); + stop_gloderror(); + } + } + + + S32 start = LLModel::LOD_HIGH; + S32 end = 0; + + if (which_lod != -1) + { + start = end = which_lod; + } + else + { + //SH-632 -- incremenet triangle count to avoid removing any triangles from + //highest LoD when auto-generating LoD + triangle_count++; + } + + + mMaxTriangleLimit = base_triangle_count; + + for (S32 lod = start; lod >= end; --lod) + { + if (which_lod == -1) + { + if (lod < start) + { + triangle_count /= decimation; + } + } + else + { + triangle_count = limit; + } + + mModel[lod].clear(); + mModel[lod].resize(mBaseModel.size()); + mVertexBuffer[lod].clear(); + + U32 actual_tris = 0; + U32 actual_verts = 0; + U32 submeshes = 0; + + glodGroupParameteri(mGroup, GLOD_ADAPT_MODE, lod_mode); + stop_gloderror(); + + glodGroupParameteri(mGroup, GLOD_ERROR_MODE, GLOD_OBJECT_SPACE_ERROR); + stop_gloderror(); + + glodGroupParameteri(mGroup, GLOD_MAX_TRIANGLES, triangle_count); + stop_gloderror(); + + glodGroupParameterf(mGroup, GLOD_OBJECT_SPACE_ERROR_THRESHOLD, lod_error_threshold); + stop_gloderror(); + + glodAdaptGroup(mGroup); + stop_gloderror(); + + for (U32 mdl_idx = 0; mdl_idx < mBaseModel.size(); ++mdl_idx) + { + LLModel* base = mBaseModel[mdl_idx]; + + GLint patch_count = 0; + glodGetObjectParameteriv(mObject[base], GLOD_NUM_PATCHES, &patch_count); + stop_gloderror(); + + LLVolumeParams volume_params; + volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); + mModel[lod][mdl_idx] = new LLModel(volume_params, 0.f); + + GLint* sizes = new GLint[patch_count*2]; + glodGetObjectParameteriv(mObject[base], GLOD_PATCH_SIZES, sizes); + stop_gloderror(); + + GLint* names = new GLint[patch_count]; + glodGetObjectParameteriv(mObject[base], GLOD_PATCH_NAMES, names); + stop_gloderror(); + + mModel[lod][mdl_idx]->setNumVolumeFaces(patch_count); + + LLModel* target_model = mModel[lod][mdl_idx]; + + for (GLint i = 0; i < patch_count; ++i) + { + LLPointer buff = new LLVertexBuffer(type_mask, 0); + + if (sizes[i*2+1] > 0 && sizes[i*2] > 0) + { + buff->allocateBuffer(sizes[i*2+1], sizes[i*2], true); + buff->setBuffer(type_mask); + glodFillElements(mObject[base], names[i], GL_UNSIGNED_SHORT, buff->getIndicesPointer()); + stop_gloderror(); + } + else + { //this face was eliminated, create a dummy triangle (one vertex, 3 indices, all 0) + buff->allocateBuffer(1, 3, true); + memset(buff->getMappedData(), 0, buff->getSize()); + memset(buff->getIndicesPointer(), 0, buff->getIndicesSize()); + } + + buff->validateRange(0, buff->getNumVerts()-1, buff->getNumIndices(), 0); + + LLStrider pos; + LLStrider norm; + LLStrider tc; + LLStrider index; + + buff->getVertexStrider(pos); + buff->getNormalStrider(norm); + buff->getTexCoord0Strider(tc); + buff->getIndexStrider(index); + + target_model->setVolumeFaceData(names[i], pos, norm, tc, index, buff->getNumVerts(), buff->getNumIndices()); + actual_tris += buff->getNumIndices()/3; + actual_verts += buff->getNumVerts(); + ++submeshes; + + if (!validate_face(target_model->getVolumeFace(names[i]))) + { + llerrs << "Invalid face generated during LOD generation." << llendl; + } + } + + //blind copy skin weights and just take closest skin weight to point on + //decimated mesh for now (auto-generating LODs with skin weights is still a bit + //of an open problem). + target_model->mPosition = base->mPosition; + target_model->mSkinWeights = base->mSkinWeights; + target_model->mJointMap = base->mJointMap; + target_model->mJointList = base->mJointList; + target_model->mInvBindMatrix = base->mInvBindMatrix; + target_model->mBindShapeMatrix = base->mBindShapeMatrix; + target_model->mAlternateBindMatrix = base->mAlternateBindMatrix; + //copy material list + target_model->mMaterialList = base->mMaterialList; + + if (!validate_model(target_model)) + { + llerrs << "Invalid model generated when creating LODs" << llendl; + } + + delete [] sizes; + delete [] names; + } + + //rebuild scene based on mBaseScene + mScene[lod].clear(); + mScene[lod] = mBaseScene; + + for (U32 i = 0; i < mBaseModel.size(); ++i) + { + LLModel* mdl = mBaseModel[i]; + LLModel* target = mModel[lod][i]; + if (target) + { + for (LLModelLoader::scene::iterator iter = mScene[lod].begin(); iter != mScene[lod].end(); ++iter) + { + for (U32 j = 0; j < iter->second.size(); ++j) + { + if (iter->second[j].mModel == mdl) + { + iter->second[j].mModel = target; + } + } + } + } + } + } + + mResourceCost = calcResourceCost(); + + /*if (which_lod == -1 && mScene[LLModel::LOD_PHYSICS].empty()) + { //build physics scene + mScene[LLModel::LOD_PHYSICS] = mScene[LLModel::LOD_LOW]; + mModel[LLModel::LOD_PHYSICS] = mModel[LLModel::LOD_LOW]; + + for (U32 i = 1; i < mModel[LLModel::LOD_PHYSICS].size(); ++i) + { + mPhysicsQ.push(mModel[LLModel::LOD_PHYSICS][i]); + } + }*/ +} + +void LLModelPreview::updateStatusMessages() +{ + assert_main_thread(); + + //triangle/vertex/submesh count for each mesh asset for each lod + std::vector tris[LLModel::NUM_LODS]; + std::vector verts[LLModel::NUM_LODS]; + std::vector submeshes[LLModel::NUM_LODS]; + + //total triangle/vertex/submesh count for each lod + S32 total_tris[LLModel::NUM_LODS]; + S32 total_verts[LLModel::NUM_LODS]; + S32 total_submeshes[LLModel::NUM_LODS]; + + for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) + { + //initialize total for this lod to 0 + total_tris[lod] = total_verts[lod] = total_submeshes[lod] = 0; + + for (U32 i = 0; i < mModel[lod].size(); ++i) + { //for each model in the lod + S32 cur_tris = 0; + S32 cur_verts = 0; + S32 cur_submeshes = mModel[lod][i]->getNumVolumeFaces(); + + for (S32 j = 0; j < cur_submeshes; ++j) + { //for each submesh (face), add triangles and vertices to current total + const LLVolumeFace& face = mModel[lod][i]->getVolumeFace(j); + cur_tris += face.mNumIndices/3; + cur_verts += face.mNumVertices; + } + + //add this model to the lod total + total_tris[lod] += cur_tris; + total_verts[lod] += cur_verts; + total_submeshes[lod] += cur_submeshes; + + //store this model's counts to asset data + tris[lod].push_back(cur_tris); + verts[lod].push_back(cur_verts); + submeshes[lod].push_back(cur_submeshes); + } + } + + if (mMaxTriangleLimit == 0) + { + mMaxTriangleLimit = total_tris[LLModel::LOD_HIGH]; + } + + + mFMP->childSetTextArg("submeshes_info", "[SUBMESHES]", llformat("%d", total_submeshes[LLModel::LOD_HIGH])); + + std::string mesh_status_na = mFMP->getString("mesh_status_na"); + + S32 upload_status[LLModel::LOD_HIGH+1]; + + bool upload_ok = true; + + for (S32 lod = 0; lod <= LLModel::LOD_HIGH; ++lod) + { + upload_status[lod] = 0; + + std::string message = "mesh_status_good"; + + if (total_tris[lod] > 0) + { + mFMP->childSetText(lod_triangles_name[lod], llformat("%d", total_tris[lod])); + mFMP->childSetText(lod_vertices_name[lod], llformat("%d", total_verts[lod])); + } + else + { + if (lod == LLModel::LOD_HIGH) + { + upload_status[lod] = 2; + message = "mesh_status_missing_lod"; + } + else + { + for (S32 i = lod-1; i >= 0; --i) + { + if (total_tris[i] > 0) + { + upload_status[lod] = 2; + message = "mesh_status_missing_lod"; + } + } + } + + mFMP->childSetText(lod_triangles_name[lod], mesh_status_na); + mFMP->childSetText(lod_vertices_name[lod], mesh_status_na); + } + + const U32 lod_high = LLModel::LOD_HIGH; + + if (lod != lod_high) + { + if (total_submeshes[lod] && total_submeshes[lod] != total_submeshes[lod_high]) + { //number of submeshes is different + message = "mesh_status_submesh_mismatch"; + upload_status[lod] = 2; + } + else if (!tris[lod].empty() && tris[lod].size() != tris[lod_high].size()) + { //number of meshes is different + message = "mesh_status_mesh_mismatch"; + upload_status[lod] = 2; + } + else if (!verts[lod].empty()) + { + for (U32 i = 0; i < verts[lod].size(); ++i) + { + S32 max_verts = i < verts[lod+1].size() ? verts[lod+1][i] : 0; + + if (max_verts > 0) + { + if (verts[lod][i] > max_verts) + { //too many vertices in this lod + message = "mesh_status_too_many_vertices"; + upload_status[lod] = 2; + } + } + } + } + } + + LLIconCtrl* icon = mFMP->getChild(lod_icon_name[lod]); + LLUIImagePtr img = LLUI::getUIImage(lod_status_image[upload_status[lod]]); + icon->setVisible(true); + icon->setImage(img); + + if (upload_status[lod] >= 2) + { + upload_ok = false; + } + + if (lod == mPreviewLOD) + { + mFMP->childSetText("lod_status_message_text", mFMP->getString(message)); + icon = mFMP->getChild("lod_status_message_icon"); + icon->setImage(img); + } + } + + bool errorStateFromLoader = mModelLoader->getLoadState() == LLModelLoader::ERROR_PARSING ? true : false; + + if ( upload_ok && !errorStateFromLoader ) + { + mFMP->childEnable("ok_btn"); + } + else + { + mFMP->childDisable("ok_btn"); + } + + //add up physics triangles etc + S32 start = 0; + S32 end = mModel[LLModel::LOD_PHYSICS].size(); + + S32 phys_tris = 0; + S32 phys_hulls = 0; + S32 phys_points = 0; + + for (S32 i = start; i < end; ++i) + { //add up hulls and points and triangles for selected mesh(es) + LLModel* model = mModel[LLModel::LOD_PHYSICS][i]; + S32 cur_submeshes = model->getNumVolumeFaces(); + + LLModel::convex_hull_decomposition& decomp = model->mConvexHullDecomp; + + if (!decomp.empty()) + { + phys_hulls += decomp.size(); + for (U32 i = 0; i < decomp.size(); ++i) + { + phys_points += decomp[i].size(); + } + } + else + { //choose physics shape OR decomposition, can't use both + for (S32 j = 0; j < cur_submeshes; ++j) + { //for each submesh (face), add triangles and vertices to current total + const LLVolumeFace& face = model->getVolumeFace(j); + phys_tris += face.mNumIndices/3; + } + } + } + + if (phys_tris > 0) + { + mFMP->childSetTextArg("physics_triangles", "[TRIANGLES]", llformat("%d", phys_tris)); + } + else + { + mFMP->childSetTextArg("physics_triangles", "[TRIANGLES]", mesh_status_na); + } + + if (phys_hulls > 0) + { + mFMP->childSetTextArg("physics_hulls", "[HULLS]", llformat("%d", phys_hulls)); + mFMP->childSetTextArg("physics_points", "[POINTS]", llformat("%d", phys_points)); + } + else + { + mFMP->childSetTextArg("physics_hulls", "[HULLS]", mesh_status_na); + mFMP->childSetTextArg("physics_points", "[POINTS]", mesh_status_na); + } + + LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; + if (fmp) + { + if (phys_tris > 0 || phys_hulls > 0) + { + if (!fmp->isViewOptionEnabled("show_physics")) + { + fmp->enableViewOption("show_physics"); + mViewOption["show_physics"] = true; + } + } + else + { + fmp->disableViewOption("show_physics"); + mViewOption["show_physics"] = false; + + } + + //bool use_hull = fmp->childGetValue("physics_use_hull").asBoolean(); + + //fmp->childSetEnabled("physics_optimize", !use_hull); + + bool enable = phys_tris > 0 || phys_hulls > 0; + //enable = enable && !use_hull && fmp->childGetValue("physics_optimize").asBoolean(); + + //enable/disable "analysis" UI + LLPanel* panel = fmp->getChild("physics analysis"); + LLView* child = panel->getFirstChild(); + while (child) + { + child->setEnabled(enable); + child = panel->findNextSibling(child); + } + + enable = phys_hulls > 0; + //enable/disable "simplification" UI + panel = fmp->getChild("physics simplification"); + child = panel->getFirstChild(); + while (child) + { + child->setEnabled(enable); + child = panel->findNextSibling(child); + } + } + + const char* lod_controls[] = + { + "lod_mode", + "lod_triangle_limit", + "lod_error_tolerance", + "build_operator_text", + "queue_mode_text", + "border_mode_text", + "share_tolerance_text", + "build_operator", + "queue_mode", + "border_mode", + "share_tolerance" + }; + const U32 num_lod_controls = sizeof(lod_controls)/sizeof(char*); + + const char* file_controls[] = + { + "lod_browse", + "lod_file" + }; + const U32 num_file_controls = sizeof(file_controls)/sizeof(char*); + + if (fmp) + { + //enable/disable controls based on radio groups + if (mFMP->childGetValue("lod_from_file").asBoolean()) + { + fmp->mLODMode[mPreviewLOD] = 0; + for (U32 i = 0; i < num_file_controls; ++i) + { + mFMP->childEnable(file_controls[i]); + } + + for (U32 i = 0; i < num_lod_controls; ++i) + { + mFMP->childDisable(lod_controls[i]); + } + } + else if (mFMP->childGetValue("lod_none").asBoolean()) + { + fmp->mLODMode[mPreviewLOD] = 2; + for (U32 i = 0; i < num_file_controls; ++i) + { + mFMP->childDisable(file_controls[i]); + } + + for (U32 i = 0; i < num_lod_controls; ++i) + { + mFMP->childDisable(lod_controls[i]); + } + + if (!mModel[mPreviewLOD].empty()) + { + mModel[mPreviewLOD].clear(); + mScene[mPreviewLOD].clear(); + mVertexBuffer[mPreviewLOD].clear(); + + //this can cause phasing issues with the UI, so reenter this function and return + updateStatusMessages(); + return; + } + } + else + { // auto generate, also the default case for wizard which has no radio selection + fmp->mLODMode[mPreviewLOD] = 1; + + for (U32 i = 0; i < num_file_controls; ++i) + { + mFMP->childDisable(file_controls[i]); + } + + for (U32 i = 0; i < num_lod_controls; ++i) + { + mFMP->childEnable(lod_controls[i]); + } + + //if (threshold) + { + U32 lod_mode = 0; + LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode"); + if (iface) + { + lod_mode = iface->getFirstSelectedIndex(); + } + + LLSpinCtrl* threshold = mFMP->getChild("lod_error_threshold"); + LLSpinCtrl* limit = mFMP->getChild("lod_triangle_limit"); + + limit->setMaxValue(mMaxTriangleLimit); + limit->setValue(total_tris[mPreviewLOD]); + + if (lod_mode == 0) + { + limit->setVisible(true); + threshold->setVisible(false); + + limit->setMaxValue(mMaxTriangleLimit); + } + else + { + limit->setVisible(false); + threshold->setVisible(true); + } + } + } + } + + if (mFMP->childGetValue("physics_load_from_file").asBoolean()) + { + mFMP->childDisable("physics_lod_combo"); + mFMP->childEnable("physics_file"); + mFMP->childEnable("physics_browse"); + } + else + { + mFMP->childEnable("physics_lod_combo"); + mFMP->childDisable("physics_file"); + mFMP->childDisable("physics_browse"); + } +} + +void LLModelPreview::setPreviewTarget(F32 distance) +{ + mCameraDistance = distance; + mCameraZoom = 1.f; + mCameraPitch = 0.f; + mCameraYaw = 0.f; + mCameraOffset.clearVec(); +} + +void LLModelPreview::clearBuffers() +{ + for (U32 i = 0; i < 6; i++) + { + mVertexBuffer[i].clear(); + } +} + +void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights) +{ + U32 tri_count = 0; + U32 vertex_count = 0; + U32 mesh_count = 0; + + LLModelLoader::model_list* model = NULL; + + if (lod < 0 || lod > 4) + { + model = &mBaseModel; + lod = 5; + } + else + { + model = &(mModel[lod]); + } + + if (!mVertexBuffer[lod].empty()) + { + mVertexBuffer[lod].clear(); + } + + mVertexBuffer[lod].clear(); + + LLModelLoader::model_list::iterator base_iter = mBaseModel.begin(); + + for (LLModelLoader::model_list::iterator iter = model->begin(); iter != model->end(); ++iter) + { + LLModel* mdl = *iter; + if (!mdl) + { + continue; + } + + LLModel* base_mdl = *base_iter; + base_iter++; + + for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) + { + const LLVolumeFace &vf = mdl->getVolumeFace(i); + U32 num_vertices = vf.mNumVertices; + U32 num_indices = vf.mNumIndices; + + if (!num_vertices || ! num_indices) + { + continue; + } + + LLVertexBuffer* vb = NULL; + + bool skinned = include_skin_weights && !mdl->mSkinWeights.empty(); + + U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; + + if (skinned) + { + mask |= LLVertexBuffer::MAP_WEIGHT4; + } + + vb = new LLVertexBuffer(mask, 0); + + vb->allocateBuffer(num_vertices, num_indices, TRUE); + + LLStrider vertex_strider; + LLStrider normal_strider; + LLStrider tc_strider; + LLStrider index_strider; + LLStrider weights_strider; + + vb->getVertexStrider(vertex_strider); + vb->getNormalStrider(normal_strider); + vb->getTexCoord0Strider(tc_strider); + vb->getIndexStrider(index_strider); + + if (skinned) + { + vb->getWeight4Strider(weights_strider); + } + + LLVector4a::memcpyNonAliased16((F32*) vertex_strider.get(), (F32*) vf.mPositions, num_vertices*4*sizeof(F32)); + LLVector4a::memcpyNonAliased16((F32*) tc_strider.get(), (F32*) vf.mTexCoords, num_vertices*2*sizeof(F32)); + LLVector4a::memcpyNonAliased16((F32*) normal_strider.get(), (F32*) vf.mNormals, num_vertices*4*sizeof(F32)); + + if (skinned) + { + for (U32 i = 0; i < num_vertices; i++) + { + //find closest weight to vf.mVertices[i].mPosition + LLVector3 pos(vf.mPositions[i].getF32ptr()); + + const LLModel::weight_list& weight_list = base_mdl->getJointInfluences(pos); + + LLVector4 w(0,0,0,0); + if (weight_list.size() > 4) + { + llerrs << "WTF?" << llendl; + } + + for (U32 i = 0; i < weight_list.size(); ++i) + { + F32 wght = llmin(weight_list[i].mWeight, 0.999999f); + F32 joint = (F32) weight_list[i].mJointIdx; + w.mV[i] = joint + wght; + } + + *(weights_strider++) = w; + } + } + + // build indices + for (U32 i = 0; i < num_indices; i++) + { + *(index_strider++) = vf.mIndices[i]; + } + + mVertexBuffer[lod][mdl].push_back(vb); + + vertex_count += num_vertices; + tri_count += num_indices/3; + ++mesh_count; + + } + } +} + +void LLModelPreview::update() +{ + if (mDirty) + { + mDirty = false; + mResourceCost = calcResourceCost(); + refresh(); + updateStatusMessages(); + } + + if (mGenLOD) + { + mGenLOD = false; + genLODs(); + refresh(); + updateStatusMessages(); + } + +} + +//----------------------------------------------------------------------------- +// render() +//----------------------------------------------------------------------------- +BOOL LLModelPreview::render() +{ + assert_main_thread(); + + LLMutexLock lock(this); + mNeedsUpdate = FALSE; + + bool edges = mViewOption["show_edges"]; + bool joint_positions = mViewOption["show_joint_positions"]; + bool skin_weight = mViewOption["show_skin_weight"]; + bool textures = mViewOption["show_textures"]; + bool physics = mViewOption["show_physics"]; + + S32 width = getWidth(); + S32 height = getHeight(); + + LLGLSUIDefault def; + LLGLDisable no_blend(GL_BLEND); + LLGLEnable cull(GL_CULL_FACE); + LLGLDepthTest depth(GL_TRUE); + LLGLDisable fog(GL_FOG); + + { + //clear background to blue + glMatrixMode(GL_PROJECTION); + gGL.pushMatrix(); + glLoadIdentity(); + glOrtho(0.0f, width, 0.0f, height, -1.0f, 1.0f); + + glMatrixMode(GL_MODELVIEW); + gGL.pushMatrix(); + glLoadIdentity(); + + gGL.color4f(0.15f, 0.2f, 0.3f, 1.f); + + gl_rect_2d_simple( width, height ); + + glMatrixMode(GL_PROJECTION); + gGL.popMatrix(); + + glMatrixMode(GL_MODELVIEW); + gGL.popMatrix(); + } + + LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; + + bool has_skin_weights = false; + bool upload_skin = mFMP->childGetValue("upload_skin").asBoolean(); + bool upload_joints = mFMP->childGetValue("upload_joints").asBoolean(); + + for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) + { + for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) + { + LLModelInstance& instance = *model_iter; + LLModel* model = instance.mModel; + if (!model->mSkinWeights.empty()) + { + has_skin_weights = true; + } + } + } + + if (has_skin_weights) + { //model has skin weights, enable view options for skin weights and joint positions + if (fmp) + { + fmp->enableViewOption("show_skin_weight"); + fmp->setViewOptionEnabled("show_joint_positions", skin_weight); + } + mFMP->childEnable("upload_skin"); + } + else + { + mFMP->childDisable("upload_skin"); + if (fmp) + { + mViewOption["show_skin_weight"] = false; + fmp->disableViewOption("show_skin_weight"); + fmp->disableViewOption("show_joint_positions"); + } + skin_weight = false; + } + + if (upload_skin && !has_skin_weights) + { //can't upload skin weights if model has no skin weights + mFMP->childSetValue("upload_skin", false); + upload_skin = false; + } + + if (!upload_skin && upload_joints) + { //can't upload joints if not uploading skin weights + mFMP->childSetValue("upload_joints", false); + upload_joints = false; + } + + mFMP->childSetEnabled("upload_joints", upload_skin); + + F32 explode = mFMP->childGetValue("physics_explode").asReal(); + + glClear(GL_DEPTH_BUFFER_BIT); + + LLRect preview_rect = mFMP->getChildView("preview_panel")->getRect(); + F32 aspect = (F32) preview_rect.getWidth()/preview_rect.getHeight(); + + LLViewerCamera::getInstance()->setAspect(aspect); + + LLViewerCamera::getInstance()->setView(LLViewerCamera::getInstance()->getDefaultFOV() / mCameraZoom); + + LLVector3 offset = mCameraOffset; + LLVector3 target_pos = mPreviewTarget+offset; + + F32 z_near = 0.001f; + F32 z_far = mCameraDistance+mPreviewScale.magVec()+mCameraOffset.magVec(); + + if (skin_weight) + { + target_pos = gAgentAvatarp->getPositionAgent(); + z_near = 0.01f; + z_far = 1024.f; + mCameraDistance = 16.f; + + //render avatar previews every frame + refresh(); + } + + glLoadIdentity(); + gPipeline.enableLightsPreview(); + + LLQuaternion camera_rot = LLQuaternion(mCameraPitch, LLVector3::y_axis) * + LLQuaternion(mCameraYaw, LLVector3::z_axis); + + LLQuaternion av_rot = camera_rot; + LLViewerCamera::getInstance()->setOriginAndLookAt( + target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + offset) * av_rot), // camera + LLVector3::z_axis, // up + target_pos); // point of interest + + + LLViewerCamera::getInstance()->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, width, height, FALSE, z_near, z_far); + + stop_glerror(); + + gGL.pushMatrix(); + const F32 BRIGHTNESS = 0.9f; + gGL.color3f(BRIGHTNESS, BRIGHTNESS, BRIGHTNESS); + + LLGLEnable normalize(GL_NORMALIZE); + + if (!mBaseModel.empty() && mVertexBuffer[5].empty()) + { + genBuffers(-1, skin_weight); + //genBuffers(3); + //genLODs(); + } + + if (!mModel[mPreviewLOD].empty()) + { + bool regen = mVertexBuffer[mPreviewLOD].empty(); + if (!regen) + { + const std::vector >& vb_vec = mVertexBuffer[mPreviewLOD].begin()->second; + if (!vb_vec.empty()) + { + const LLVertexBuffer* buff = vb_vec[0]; + regen = buff->hasDataType(LLVertexBuffer::TYPE_WEIGHT4) != skin_weight; + } + } + + if (regen) + { + genBuffers(mPreviewLOD, skin_weight); + } + + if (!skin_weight) + { + for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) + { + LLModelInstance& instance = *iter; + + LLModel* model = instance.mLOD[mPreviewLOD]; + + if (!model) + { + continue; + } + + gGL.pushMatrix(); + LLMatrix4 mat = instance.mTransform; + + glMultMatrixf((GLfloat*) mat.mMatrix); + + for (U32 i = 0; i < mVertexBuffer[mPreviewLOD][model].size(); ++i) + { + LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; + + buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); + + if (textures) + { + glColor4fv(instance.mMaterial[i].mDiffuseColor.mV); + if (i < instance.mMaterial.size() && instance.mMaterial[i].mDiffuseMap.notNull()) + { + gGL.getTexUnit(0)->bind(instance.mMaterial[i].mDiffuseMap, true); + if (instance.mMaterial[i].mDiffuseMap->getDiscardLevel() > -1) + { + mTextureSet.insert(instance.mMaterial[i].mDiffuseMap); + } + } + } + else + { + glColor4f(1,1,1,1); + } + + buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + glColor3f(0.4f, 0.4f, 0.4f); + + if (edges) + { + glLineWidth(3.f); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glLineWidth(1.f); + } + } + gGL.popMatrix(); + } + + if (physics) + { + glClear(GL_DEPTH_BUFFER_BIT); + LLGLEnable blend(GL_BLEND); + gGL.blendFunc(LLRender::BF_ONE, LLRender::BF_ZERO); + + for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) + { + LLModelInstance& instance = *iter; + + LLModel* model = instance.mLOD[LLModel::LOD_PHYSICS]; + + if (!model) + { + continue; + } + + gGL.pushMatrix(); + LLMatrix4 mat = instance.mTransform; + + glMultMatrixf((GLfloat*) mat.mMatrix); + + + bool render_mesh = true; + + LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread; + if (decomp) + { + LLMutexLock(decomp->mMutex); + + std::map, std::vector > >::iterator iter = + mPhysicsMesh.find(model); + if (iter != mPhysicsMesh.end()) + { //render hull instead of mesh + render_mesh = false; + for (U32 i = 0; i < iter->second.size(); ++i) + { + if (explode > 0.f) + { + gGL.pushMatrix(); + + LLVector3 offset = model->mHullCenter[i]-model->mCenterOfHullCenters; + offset *= explode; + + gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]); + } + + static std::vector hull_colors; + + if (i+1 >= hull_colors.size()) + { + hull_colors.push_back(LLColor4U(rand()%128+127, rand()%128+127, rand()%128+127, 255)); + } + + LLVertexBuffer* buff = iter->second[i]; + if (buff) + { + buff->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL); + + glColor4ubv(hull_colors[i].mV); + buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts()); + } + + if (explode > 0.f) + { + gGL.popMatrix(); + } + } + } + } + + if (render_mesh) + { + if (mVertexBuffer[LLModel::LOD_PHYSICS].empty()) + { + genBuffers(LLModel::LOD_PHYSICS, false); + } + for (U32 i = 0; i < mVertexBuffer[LLModel::LOD_PHYSICS][model].size(); ++i) + { + LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][i]; + + buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); + + buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + glColor4f(0.4f, 0.4f, 0.0f, 0.4f); + + buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); + + glColor3f(1.f, 1.f, 0.f); + + glLineWidth(3.f); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glLineWidth(1.f); + } + } + + gGL.popMatrix(); + } + + gGL.setSceneBlendType(LLRender::BT_ALPHA); + } + } + else + { + LLVOAvatarSelf* avatar = gAgentAvatarp; + target_pos = avatar->getPositionAgent(); + + LLViewerCamera::getInstance()->setOriginAndLookAt( + target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + offset) * av_rot), // camera + LLVector3::z_axis, // up + target_pos); // point of interest + + if (joint_positions) + { + avatar->renderCollisionVolumes(); + } + + for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) + { + for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) + { + LLModelInstance& instance = *model_iter; + LLModel* model = instance.mModel; + + if (!model->mSkinWeights.empty()) + { + for (U32 i = 0; i < mVertexBuffer[mPreviewLOD][model].size(); ++i) + { + LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; + + const LLVolumeFace& face = model->getVolumeFace(i); + + LLStrider position; + buffer->getVertexStrider(position); + + LLStrider weight; + buffer->getWeight4Strider(weight); + + //quick 'n dirty software vertex skinning + + //build matrix palette + LLMatrix4 mat[64]; + for (U32 j = 0; j < model->mJointList.size(); ++j) + { + LLJoint* joint = avatar->getJoint(model->mJointList[j]); + if (joint) + { + mat[j] = model->mInvBindMatrix[j]; + mat[j] *= joint->getWorldMatrix(); + } + } + + for (U32 j = 0; j < buffer->getRequestedVerts(); ++j) + { + LLMatrix4 final_mat; + final_mat.mMatrix[0][0] = final_mat.mMatrix[1][1] = final_mat.mMatrix[2][2] = final_mat.mMatrix[3][3] = 0.f; + + LLVector4 wght; + S32 idx[4]; + + F32 scale = 0.f; + for (U32 k = 0; k < 4; k++) + { + F32 w = weight[j].mV[k]; + + idx[k] = (S32) floorf(w); + wght.mV[k] = w - floorf(w); + scale += wght.mV[k]; + } + + wght *= 1.f/scale; + + for (U32 k = 0; k < 4; k++) + { + F32* src = (F32*) mat[idx[k]].mMatrix; + F32* dst = (F32*) final_mat.mMatrix; + + F32 w = wght.mV[k]; + + for (U32 l = 0; l < 16; l++) + { + dst[l] += src[l]*w; + } + } + + //VECTORIZE THIS + LLVector3 v(face.mPositions[j].getF32ptr()); + + v = v * model->mBindShapeMatrix; + v = v * final_mat; + + position[j] = v; + } + + buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); + glColor4fv(instance.mMaterial[i].mDiffuseColor.mV); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); + glColor3f(0.4f, 0.4f, 0.4f); + + if (edges) + { + glLineWidth(3.f); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glLineWidth(1.f); + } + } + } + } + } + } + } + + gGL.popMatrix(); + + return TRUE; +} + +//----------------------------------------------------------------------------- +// refresh() +//----------------------------------------------------------------------------- +void LLModelPreview::refresh() +{ + mNeedsUpdate = TRUE; +} + +//----------------------------------------------------------------------------- +// rotate() +//----------------------------------------------------------------------------- +void LLModelPreview::rotate(F32 yaw_radians, F32 pitch_radians) +{ + mCameraYaw = mCameraYaw + yaw_radians; + + mCameraPitch = llclamp(mCameraPitch + pitch_radians, F_PI_BY_TWO * -0.8f, F_PI_BY_TWO * 0.8f); +} + +//----------------------------------------------------------------------------- +// zoom() +//----------------------------------------------------------------------------- +void LLModelPreview::zoom(F32 zoom_amt) +{ + F32 new_zoom = mCameraZoom+zoom_amt; + + mCameraZoom = llclamp(new_zoom, 1.f, 10.f); +} + +void LLModelPreview::pan(F32 right, F32 up) +{ + mCameraOffset.mV[VY] = llclamp(mCameraOffset.mV[VY] + right * mCameraDistance / mCameraZoom, -1.f, 1.f); + mCameraOffset.mV[VZ] = llclamp(mCameraOffset.mV[VZ] + up * mCameraDistance / mCameraZoom, -1.f, 1.f); +} + +void LLModelPreview::setPreviewLOD(S32 lod) +{ + lod = llclamp(lod, 0, (S32) LLModel::LOD_HIGH); + + if (lod != mPreviewLOD) + { + mPreviewLOD = lod; + + LLComboBox* combo_box = mFMP->getChild("preview_lod_combo"); + combo_box->setCurrentByIndex((NUM_LOD-1)-mPreviewLOD); // combo box list of lods is in reverse order + mFMP->childSetTextArg("lod_table_footer", "[DETAIL]", mFMP->getString(lod_name[mPreviewLOD])); + mFMP->childSetText("lod_file", mLODFile[mPreviewLOD]); + + LLColor4 highlight_color = LLUIColorTable::instance().getColor("MeshImportTableHighlightColor"); + LLColor4 normal_color = LLUIColorTable::instance().getColor("MeshImportTableNormalColor"); + + for (S32 i = 0; i <= LLModel::LOD_HIGH; ++i) + { + const LLColor4& color = (i == lod) ? highlight_color : normal_color; + + mFMP->childSetColor(lod_status_name[i], color); + mFMP->childSetColor(lod_label_name[i], color); + mFMP->childSetColor(lod_triangles_name[i], color); + mFMP->childSetColor(lod_vertices_name[i], color); + } + + LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; + if (fmp) + { + LLRadioGroup* radio = fmp->getChild("lod_file_or_limit"); + radio->selectNthItem(fmp->mLODMode[mPreviewLOD]); + } + } + refresh(); + updateStatusMessages(); +} + +//static +void LLFloaterModelPreview::onBrowseLOD(void* data) +{ + assert_main_thread(); + + LLFloaterModelPreview* mp = (LLFloaterModelPreview*) data; + mp->loadModel(mp->mModelPreview->mPreviewLOD); +} + +//static +void LLFloaterModelPreview::onUpload(void* user_data) +{ + assert_main_thread(); + + LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; + + mp->mModelPreview->rebuildUploadData(); + + gMeshRepo.uploadModel(mp->mModelPreview->mUploadData, mp->mModelPreview->mPreviewScale, + mp->childGetValue("upload_textures").asBoolean(), mp->childGetValue("upload_skin"), mp->childGetValue("upload_joints")); + + mp->closeFloater(false); +} + + +//static +void LLFloaterModelPreview::onClearMaterials(void* user_data) +{ + LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; + mp->mModelPreview->clearMaterials(); +} + +//static +void LLFloaterModelPreview::refresh(LLUICtrl* ctrl, void* user_data) +{ + sInstance->mModelPreview->mDirty = true; +} + +void LLFloaterModelPreview::updateResourceCost() +{ + U32 cost = mModelPreview->mResourceCost; + childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d",cost)); +} + +//static +void LLModelPreview::textureLoadedCallback( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata ) +{ + LLModelPreview* preview = (LLModelPreview*) userdata; + preview->refresh(); +} + +LLFloaterModelPreview::DecompRequest::DecompRequest(const std::string& stage, LLModel* mdl) +{ + mStage = stage; + mContinue = 1; + mModel = mdl; + mDecompID = &mdl->mDecompID; + mParams = sInstance->mDecompParams; + + //copy out positions and indices + if (mdl) + { + U16 index_offset = 0; + + mPositions.clear(); + mIndices.clear(); + + //queue up vertex positions and indices + for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) + { + const LLVolumeFace& face = mdl->getVolumeFace(i); + if (mPositions.size() + face.mNumVertices > 65535) + { + continue; + } + + for (U32 j = 0; j < face.mNumVertices; ++j) + { + mPositions.push_back(LLVector3(face.mPositions[j].getF32ptr())); + } + + for (U32 j = 0; j < face.mNumIndices; ++j) + { + mIndices.push_back(face.mIndices[j]+index_offset); + } + + index_offset += face.mNumVertices; + } + } +} + +void LLFloaterModelPreview::setStatusMessage(const std::string& msg) +{ + LLMutexLock lock(mStatusLock); + mStatusMessage = msg; +} + +S32 LLFloaterModelPreview::DecompRequest::statusCallback(const char* status, S32 p1, S32 p2) +{ + setStatusMessage(llformat("%s: %d/%d", status, p1, p2)); + if (LLFloaterModelPreview::sInstance) + { + LLFloaterModelPreview::sInstance->setStatusMessage(mStatusMessage); + } + + return mContinue; +} + +void LLFloaterModelPreview::DecompRequest::completed() +{ //called from the main thread + mModel->setConvexHullDecomposition(mHull); + + if (sInstance) + { + if (sInstance->mModelPreview) + { + sInstance->mModelPreview->mPhysicsMesh[mModel] = mHullMesh; + sInstance->mModelPreview->mDirty = true; + LLFloaterModelPreview::sInstance->mModelPreview->refresh(); + } + + sInstance->mCurRequest.erase(this); + } +} -- cgit v1.2.3 From 6e671281a26089d7cf947236162afc8013d25ec8 Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Fri, 7 Jan 2011 17:16:28 -0500 Subject: SH-759 FIXED Various crashes in model floater after you open file picker then cancel Took out erroneous logic for handling when a file picker is canceled. Reviewed by Davep. --- indra/newview/llfloatermodelpreview.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index c0b5b7cfa6..f57d524b46 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -379,7 +379,8 @@ LLFloaterModelPreview::~LLFloaterModelPreview() { sInstance = NULL; - if ( mModelPreview->mModelLoader->mResetJoints ) + const LLModelLoader *model_loader = mModelPreview->mModelLoader; + if (model_loader && model_loader->mResetJoints) { gAgentAvatarp->resetJointPositions(); } @@ -2373,11 +2374,9 @@ void LLModelPreview::loadModel(std::string filename, S32 lod) LLMutexLock lock(this); - if (mModelLoader) - { - delete mModelLoader; - mModelLoader = NULL; - } + // This triggers if you bring up the file picker and then hit CANCEL. + // Just use the previous model (if any) and ignore that you brought up + // the file picker. if (filename.empty()) { @@ -2386,12 +2385,17 @@ void LLModelPreview::loadModel(std::string filename, S32 lod) // this is the initial file picking. Close the whole floater // if we don't have a base model to show for high LOD. mFMP->closeFloater(false); + mLoading = false; } - - mLoading = false; return; } + if (mModelLoader) + { + delete mModelLoader; + mModelLoader = NULL; + } + mLODFile[lod] = filename; if (lod == LLModel::LOD_HIGH) -- cgit v1.2.3 From e8423f150ffdd965da5b90ee625a8afc1519626f Mon Sep 17 00:00:00 2001 From: prep linden Date: Mon, 10 Jan 2011 11:04:13 -0500 Subject: Added support for parsing a matrix sids translation elements for joints --- indra/newview/llfloatermodelpreview.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index c0b5b7cfa6..57b648769d 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1789,7 +1789,25 @@ void LLModelLoader::processJointNode( domNode* pNode, std::maptypeID() != domTranslate::ID() ) { - llwarns<< "The found element is not a translate node" <( jointResolver.getElement() ); + if ( pMatrix ) + { + //llinfos<<"A matrix SID was however found!"<getValue(); + for ( int i = 0; i < 4; i++ ) + { + for( int j = 0; j < 4; j++ ) + { + workingTransform.mMatrix[i][j] = domArray[i + j*4]; + } + } + } + else + { + llwarns<< "The found element is not translate or matrix node - most likely a corrupt export!" < Date: Tue, 11 Jan 2011 16:39:28 -0500 Subject: SH-742 FIX, SH-743 FIX: now treat requesting a specific triangle limit differently from changing some other LOD parameter, to avoid successive simplification problem --- indra/newview/llfloatermodelpreview.cpp | 34 +++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index c0b5b7cfa6..02dc1ec8be 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -291,7 +291,7 @@ BOOL LLFloaterModelPreview::postBuild() childSetCommitCallback("lod_mode", onLODParamCommit, this); childSetCommitCallback("lod_error_threshold", onLODParamCommit, this); - childSetCommitCallback("lod_triangle_limit", onLODParamCommit, this); + childSetCommitCallback("lod_triangle_limit", onLODParamCommitTriangleLimit, this); childSetCommitCallback("build_operator", onLODParamCommit, this); childSetCommitCallback("queue_mode", onLODParamCommit, this); childSetCommitCallback("border_mode", onLODParamCommit, this); @@ -531,9 +531,14 @@ void LLFloaterModelPreview::onAutoFillCommit(LLUICtrl* ctrl, void* userdata) void LLFloaterModelPreview::onLODParamCommit(LLUICtrl* ctrl, void* userdata) { LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; - fp->mModelPreview->genLODs(fp->mModelPreview->mPreviewLOD); - fp->mModelPreview->updateStatusMessages(); - fp->mModelPreview->refresh(); + fp->mModelPreview->onLODParamCommit(false); +} + +//static +void LLFloaterModelPreview::onLODParamCommitTriangleLimit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; + fp->mModelPreview->onLODParamCommit(true); } @@ -2810,7 +2815,7 @@ bool LLModelPreview::containsRiggedAsset( void ) } return false; } -void LLModelPreview::genLODs(S32 which_lod, U32 decimation) +void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_limit) { if (mBaseModel.empty()) { @@ -3041,7 +3046,17 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation) } else { - triangle_count = limit; + if (enforce_tri_limit) + { + triangle_count = limit; + } + else + { + for (S32 j=LLModel::LOD_HIGH; j>which_lod; --j) + { + triangle_count /= decimation; + } + } } mModel[lod].clear(); @@ -4307,6 +4322,13 @@ void LLModelPreview::textureLoadedCallback( BOOL success, LLViewerFetchedTexture preview->refresh(); } +void LLModelPreview::onLODParamCommit(bool enforce_tri_limit) +{ + genLODs(mPreviewLOD, 3, enforce_tri_limit); + updateStatusMessages(); + refresh(); +} + LLFloaterModelPreview::DecompRequest::DecompRequest(const std::string& stage, LLModel* mdl) { mStage = stage; -- cgit v1.2.3 From 3a47555dc27ffa74f5427e0ef44fa25b505f6c16 Mon Sep 17 00:00:00 2001 From: leyla_linden Date: Wed, 12 Jan 2011 13:38:47 -0800 Subject: SH-777 Wizard top buttons need to be clickable and switch between wizard steps --- indra/newview/llfloatermodelpreview.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 47a3a4cd30..8e08c6aa6c 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -2561,6 +2561,8 @@ void LLModelPreview::loadModelCallback(S32 lod) mLoading = false; refresh(); + + mModelLoadedSignal(); } void LLModelPreview::resetPreviewTarget() -- cgit v1.2.3 From e47ff7bd4748202ff4e6a33bd78b84288d1d1ec8 Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Wed, 12 Jan 2011 17:35:31 -0500 Subject: SH-717 Viewer crash on exit after Upload model dialog could not be spawned Took out unused function that was seen in crash report from this bug. No functionality change. --- indra/newview/llfloatermodelpreview.cpp | 15 --------------- 1 file changed, 15 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 3ac7f12e4e..8dcb441b16 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -2817,21 +2817,6 @@ void LLModelPreview::clearMaterials() refresh(); } -bool LLModelPreview::containsRiggedAsset( void ) -{ - //loop through the models and determine if any of them contained a rigged asset, and if so - //return true. - //This is used to cleanup the joint positions after a preview. - for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) - { - LLModel* pModel = *iter; - if ( pModel->mAlternateBindMatrix.size() > 0 ) - { - return true; - } - } - return false; -} void LLModelPreview::genLODs(S32 which_lod, U32 decimation) { if (mBaseModel.empty()) -- cgit v1.2.3 From dc918c66d1c843effdd71d664095109d3f7be066 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Fri, 21 Jan 2011 18:26:22 -0600 Subject: SH-704 Potential fix for crash in LLModelPreview::calcResourceCost. --- indra/newview/llfloatermodelpreview.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index cc2a8c8aac..dde470693c 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -2205,9 +2205,12 @@ U32 LLModelPreview::calcResourceCost() rebuildUploadData(); - if ( mModelLoader->getLoadState() != LLModelLoader::ERROR_PARSING ) + if (mFMP && mModelLoader) { - mFMP->childEnable("ok_btn"); + if ( mModelLoader->getLoadState() != LLModelLoader::ERROR_PARSING ) + { + mFMP->childEnable("ok_btn"); + } } U32 cost = 0; @@ -2215,7 +2218,7 @@ U32 LLModelPreview::calcResourceCost() U32 num_points = 0; U32 num_hulls = 0; - F32 debug_scale = mFMP->childGetValue("import_scale").asReal(); + F32 debug_scale = mFMP ? mFMP->childGetValue("import_scale").asReal() : 1.f; F32 streaming_cost = 0.f; F32 physics_cost = 0.f; @@ -2270,9 +2273,7 @@ U32 LLModelPreview::calcResourceCost() } } - //mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[HULLS]", llformat("%d",num_hulls)); - //mFMP->childSetTextArg(info_name[LLModel::LOD_PHYSICS], "[POINTS]", llformat("%d",num_points)); - F32 scale = mFMP->childGetValue("import_scale").asReal()*2.f; + F32 scale = mFMP ? mFMP->childGetValue("import_scale").asReal()*2.f : 2.f; mDetailsSignal(mPreviewScale[0]*scale, mPreviewScale[1]*scale, mPreviewScale[2]*scale, streaming_cost, physics_cost); -- cgit v1.2.3 From c690c30ec173faf8d8087ecb38cadbb9dd1adb4e Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 22 Feb 2011 18:33:33 -0600 Subject: SH-438 Use node name instead of mesh name for object names when importing meshes. --- indra/newview/llfloatermodelpreview.cpp | 187 +------------------------------- 1 file changed, 3 insertions(+), 184 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index dde470693c..cf7ac354b6 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1653,7 +1653,7 @@ void LLModelLoader::run() std::vector materials; materials.resize(model->getNumVolumeFaces()); - mScene[transformation].push_back(LLModelInstance(model, transformation, materials)); + mScene[transformation].push_back(LLModelInstance(model, model->mLabel, transformation, materials)); stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); } } @@ -1944,7 +1944,8 @@ void LLModelLoader::processElement(daeElement* element) mesh_scale *= transformation; transformation = mesh_scale; - mScene[transformation].push_back(LLModelInstance(model, transformation, materials)); + std::string label = getElementLabel(instance_geo); + mScene[transformation].push_back(LLModelInstance(model, label, transformation, materials)); stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); } @@ -2615,188 +2616,6 @@ void LLModelPreview::generateNormals() } -void LLModelPreview::consolidate() -{ - std::map > composite; - - LLMatrix4 identity; - - //bake out each node in current scene to composite - for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) - { //for each transform in current scene - LLMatrix4 mat = iter->first; - glh::matrix4f inv_trans = glh::matrix4f((F32*) mat.mMatrix).inverse().transpose(); - LLMatrix4 norm_mat(inv_trans.m); - - for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) - { //for each instance with that transform - LLModelInstance& source_instance = *model_iter; - LLModel* source = source_instance.mModel; - - if (!validate_model(source)) - { - llerrs << "Invalid model found!" << llendl; - } - - for (S32 i = 0; i < source->getNumVolumeFaces(); ++i) - { //for each face in instance - const LLVolumeFace& src_face = source->getVolumeFace(i); - LLImportMaterial& source_material = source_instance.mMaterial[i]; - - //get model in composite that is composite for this material - LLModel* model = NULL; - - if (composite.find(source_material) != composite.end()) - { - model = composite[source_material].rbegin()->mModel; - if (model->getVolumeFace(0).mNumVertices + src_face.mNumVertices > 65535) - { - model = NULL; - } - } - - if (model == NULL) - { //no model found, make new model - std::vector materials; - materials.push_back(source_material); - LLVolumeParams volume_params; - volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); - model = new LLModel(volume_params, 0.f); - model->mLabel = source->mLabel; - model->setNumVolumeFaces(0); - composite[source_material].push_back(LLModelInstance(model, identity, materials)); - } - - model->appendFace(src_face, source->mMaterialList[i], mat, norm_mat); - } - } - } - - - //condense composite into as few LLModel instances as possible - LLModelLoader::model_list new_model; - std::vector instance_list; - - LLVolumeParams volume_params; - volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); - - std::vector empty_material; - LLModelInstance cur_instance(new LLModel(volume_params, 0.f), identity, empty_material); - cur_instance.mModel->setNumVolumeFaces(0); - - BOOL first_transform = TRUE; - - LLModelLoader::scene new_scene; - LLVector3 min,max; - - for (std::map >::iterator iter = composite.begin(); - iter != composite.end(); - ++iter) - { - std::map >::iterator next_iter = iter; ++next_iter; - - for (std::vector::iterator instance_iter = iter->second.begin(); - instance_iter != iter->second.end(); - ++instance_iter) - { - LLModel* source = instance_iter->mModel; - - if (instance_iter->mMaterial.size() != 1) - { - llerrs << "WTF?" << llendl; - } - - if (source->getNumVolumeFaces() != 1) - { - llerrs << "WTF?" << llendl; - } - - if (source->mMaterialList.size() != 1) - { - llerrs << "WTF?" << llendl; - } - - cur_instance.mModel->addFace(source->getVolumeFace(0)); - cur_instance.mMaterial.push_back(instance_iter->mMaterial[0]); - cur_instance.mModel->mMaterialList.push_back(source->mMaterialList[0]); - - BOOL last_model = FALSE; - - std::vector::iterator next_instance = instance_iter; ++next_instance; - - if (next_iter == composite.end() && - next_instance == iter->second.end()) - { - last_model = TRUE; - } - - if (last_model || cur_instance.mModel->getNumVolumeFaces() >= MAX_MODEL_FACES) - { - cur_instance.mModel->mLabel = source->mLabel; - - cur_instance.mModel->optimizeVolumeFaces(); - cur_instance.mModel->normalizeVolumeFaces(); - - if (!validate_model(cur_instance.mModel)) - { - llerrs << "Invalid model detected." << llendl; - } - - new_model.push_back(cur_instance.mModel); - - LLMatrix4 transformation = LLMatrix4(); - - // adjust the transformation to compensate for mesh normalization - LLVector3 mesh_scale_vector; - LLVector3 mesh_translation_vector; - cur_instance.mModel->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); - - LLMatrix4 mesh_translation; - mesh_translation.setTranslation(mesh_translation_vector); - mesh_translation *= transformation; - transformation = mesh_translation; - - LLMatrix4 mesh_scale; - mesh_scale.initScale(mesh_scale_vector); - mesh_scale *= transformation; - transformation = mesh_scale; - - cur_instance.mTransform = transformation; - - new_scene[transformation].push_back(cur_instance); - stretch_extents(cur_instance.mModel, transformation, min, max, first_transform); - - if (!last_model) - { - cur_instance = LLModelInstance(new LLModel(volume_params, 0.f), identity, empty_material); - cur_instance.mModel->setNumVolumeFaces(0); - } - } - } - } - - mScene[mPreviewLOD] = new_scene; - mModel[mPreviewLOD] = new_model; - mVertexBuffer[mPreviewLOD].clear(); - - if (mPreviewLOD == LLModel::LOD_HIGH) - { - mBaseScene = new_scene; - mBaseModel = new_model; - clearGLODGroup(); - mVertexBuffer[5].clear(); - } - - mPreviewTarget = (min+max)*0.5f; - mPreviewScale = (max-min)*0.5f; - setPreviewTarget(mPreviewScale.magVec()*2.f); - - clearIncompatible(mPreviewLOD); - - mResourceCost = calcResourceCost(); - refresh(); -} - void LLModelPreview::clearMaterials() { for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) -- cgit v1.2.3 From 9f537ad93fe7992bb6d652473a4ac3680320cab5 Mon Sep 17 00:00:00 2001 From: leyla_linden Date: Wed, 23 Feb 2011 16:31:32 -0800 Subject: SH-1035 Model preview background color should match spec --- indra/newview/llfloatermodelpreview.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index dde470693c..7d42c842e8 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -603,13 +603,13 @@ void LLFloaterModelPreview::draw() gGL.begin( LLRender::QUADS ); { gGL.texCoord2f(0.f, 1.f); - gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mTop); + gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mTop-1); gGL.texCoord2f(0.f, 0.f); gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mBottom); gGL.texCoord2f(1.f, 0.f); - gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mBottom); + gGL.vertex2i(mPreviewRect.mRight-1, mPreviewRect.mBottom); gGL.texCoord2f(1.f, 1.f); - gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mTop); + gGL.vertex2i(mPreviewRect.mRight-1, mPreviewRect.mTop-1); } gGL.end(); @@ -3798,7 +3798,7 @@ BOOL LLModelPreview::render() gGL.pushMatrix(); glLoadIdentity(); - gGL.color4f(0.15f, 0.2f, 0.3f, 1.f); + gGL.color4f(0.169f, 0.169f, 0.169f, 1.f); gl_rect_2d_simple( width, height ); -- cgit v1.2.3 From ca52b0bd712483675bb04421fb4ee6881e61a135 Mon Sep 17 00:00:00 2001 From: leyla_linden Date: Thu, 24 Feb 2011 15:02:55 -0800 Subject: SH-1040 Make both model preview drop downs functional --- indra/newview/llfloatermodelpreview.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 42c93a91a5..ef7d1425c7 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -4085,6 +4085,10 @@ void LLModelPreview::setPreviewLOD(S32 lod) mFMP->childSetTextArg("lod_table_footer", "[DETAIL]", mFMP->getString(lod_name[mPreviewLOD])); mFMP->childSetText("lod_file", mLODFile[mPreviewLOD]); + // the wizard has two lod drop downs + LLComboBox* combo_box2 = mFMP->getChild("preview_lod_combo2"); + combo_box2->setCurrentByIndex((NUM_LOD-1)-mPreviewLOD); // combo box list of lods is in reverse order + LLColor4 highlight_color = LLUIColorTable::instance().getColor("MeshImportTableHighlightColor"); LLColor4 normal_color = LLUIColorTable::instance().getColor("MeshImportTableNormalColor"); -- cgit v1.2.3 From 4abb8b33fa0c3b5e5f809a783cfc62a9e02af338 Mon Sep 17 00:00:00 2001 From: prep linden Date: Mon, 28 Feb 2011 12:20:31 -0500 Subject: sh-517 Content authors can specify a pivot node (Assetpivot). --- indra/newview/llfloatermodelpreview.cpp | 84 ++++++++++++++++++++++++++++++++- 1 file changed, 83 insertions(+), 1 deletion(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index ef7d1425c7..e33ce055f6 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -174,7 +174,6 @@ std::string lod_label_name[NUM_LOD+1] = "I went off the end of the lod_label_name array. Me so smart." }; - bool validate_face(const LLVolumeFace& face) { for (U32 i = 0; i < face.mNumIndices; ++i) @@ -1675,10 +1674,42 @@ void LLModelLoader::run() processElement(scene); + handlePivotPoint( root ); + doOnIdleOneTime(boost::bind(&LLModelPreview::loadModelCallback,mPreview,mLod)); } } +void LLModelLoader::handlePivotPoint( daeElement* pRoot ) +{ + //Import an optional pivot point - a pivot point is just a node in the visual scene named "AssetPivot" + //If no assetpivot is found then the asset will use the SL default + daeElement* pScene = pRoot->getDescendant("visual_scene"); + if ( pScene ) + { + daeTArray< daeSmartRef > children = pScene->getChildren(); + S32 childCount = children.getCount(); + for (S32 i = 0; i < childCount; ++i) + { + domNode* pNode = daeSafeCast(children[i]); + if ( pNode && isNodeAPivotPoint( pNode ) ) + { + LLMatrix4 workingTransform; + daeSIDResolver nodeResolver( pNode, "./translate" ); + domTranslate* pTranslate = daeSafeCast( nodeResolver.getElement() ); + //Translation via SID was successful + //todo#extract via element as well + if ( pTranslate ) + { + extractTranslation( pTranslate, workingTransform ); + mPreview->setModelPivot( workingTransform.getTranslation() ); + mPreview->setHasPivot( true ); + } + } + } + } +} + bool LLModelLoader::doesJointArrayContainACompleteRig( const std::vector &jointListFromModel ) { std::deque :: const_iterator masterJointIt = mMasterJointList.begin(); @@ -1754,6 +1785,25 @@ bool LLModelLoader::isNodeAJoint( domNode* pNode ) return false; } +bool LLModelLoader::isNodeAPivotPoint( domNode* pNode ) +{ + bool result = false; + + if ( pNode && pNode->getName() ) + { + std::string name = pNode->getName(); + if ( name == "AssetPivot" ) + { + result = true; + } + else + { + result = false; + } + } + return result; +} + void LLModelLoader::extractTranslation( domTranslate* pTranslate, LLMatrix4& transform ) { domFloat3 jointTrans = pTranslate->getValue(); @@ -2185,6 +2235,9 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) mFMP = fmp; + mHasPivot = false; + mModelPivot = LLVector3( 0.0f, 0.0f, 0.0f ); + glodInit(); } @@ -2292,6 +2345,28 @@ void LLFloaterModelPreview::setDetails(F32 x, F32 y, F32 z, F32 streaming_cost, childSetTextArg("physics cost", "[COST]", llformat("%.3f", physics_cost)); } +void LLModelPreview::alterModelsPivot( void ) +{ + for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) + { + if ( *iter ) + { + (*iter)->offsetMesh( mModelPivot ); + } + } + + for ( int i=0;ioffsetMesh( mModelPivot ); + } + } + } +} + void LLModelPreview::rebuildUploadData() { assert_main_thread(); @@ -2347,6 +2422,7 @@ void LLModelPreview::rebuildUploadData() LLModelInstance instance = *model_iter; LLModel* base_model = instance.mModel; + if (base_model) { base_model->mRequestedLabel = requested_name; @@ -3441,6 +3517,7 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights) U32 vertex_count = 0; U32 mesh_count = 0; + LLModelLoader::model_list* model = NULL; if (lod < 0 || lod > 4) @@ -4129,6 +4206,11 @@ void LLFloaterModelPreview::onUpload(void* user_data) LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; + if ( mp && mp->mModelPreview->mHasPivot ) + { + mp->mModelPreview->alterModelsPivot(); + } + mp->mModelPreview->rebuildUploadData(); gMeshRepo.uploadModel(mp->mModelPreview->mUploadData, mp->mModelPreview->mPreviewScale, -- cgit v1.2.3 From d1a2ce75e27f34141eeb8a45ae914c453c419f1b Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 9 Mar 2011 14:18:39 -0600 Subject: SH-587 Make cancel button on physics tabs more responsive. --- indra/newview/llfloatermodelpreview.cpp | 40 ++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 13 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index e33ce055f6..c2054bf00f 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -773,11 +773,13 @@ void LLFloaterModelPreview::onPhysicsStageExecute(LLUICtrl* ctrl, void* data) if (stage == "Decompose") { + sInstance->setStatusMessage(sInstance->getString("decomposing")); sInstance->childSetVisible("Decompose", false); sInstance->childSetVisible("decompose_cancel", true); } else if (stage == "Simplify") { + sInstance->setStatusMessage(sInstance->getString("simplifying")); sInstance->childSetVisible("Simplify", false); sInstance->childSetVisible("simplify_cancel", true); } @@ -823,6 +825,8 @@ void LLFloaterModelPreview::onPhysicsStageCancel(LLUICtrl* ctrl, void*data) DecompRequest* req = *iter; req->mContinue = 0; } + + sInstance->mCurRequest.clear(); } } @@ -4301,10 +4305,13 @@ void LLFloaterModelPreview::setStatusMessage(const std::string& msg) S32 LLFloaterModelPreview::DecompRequest::statusCallback(const char* status, S32 p1, S32 p2) { - setStatusMessage(llformat("%s: %d/%d", status, p1, p2)); - if (LLFloaterModelPreview::sInstance) + if (mContinue) { - LLFloaterModelPreview::sInstance->setStatusMessage(mStatusMessage); + setStatusMessage(llformat("%s: %d/%d", status, p1, p2)); + if (LLFloaterModelPreview::sInstance) + { + LLFloaterModelPreview::sInstance->setStatusMessage(mStatusMessage); + } } return mContinue; @@ -4312,20 +4319,27 @@ S32 LLFloaterModelPreview::DecompRequest::statusCallback(const char* status, S32 void LLFloaterModelPreview::DecompRequest::completed() { //called from the main thread - mModel->setConvexHullDecomposition(mHull); - - if (sInstance) + if (mContinue) { - if (mContinue) + mModel->setConvexHullDecomposition(mHull); + + if (sInstance) { - if (sInstance->mModelPreview) + if (mContinue) { - sInstance->mModelPreview->mPhysicsMesh[mModel] = mHullMesh; - sInstance->mModelPreview->mDirty = true; - LLFloaterModelPreview::sInstance->mModelPreview->refresh(); + if (sInstance->mModelPreview) + { + sInstance->mModelPreview->mPhysicsMesh[mModel] = mHullMesh; + sInstance->mModelPreview->mDirty = true; + LLFloaterModelPreview::sInstance->mModelPreview->refresh(); + } } - } - sInstance->mCurRequest.erase(this); + sInstance->mCurRequest.erase(this); + } + } + else if (sInstance) + { + llassert(sInstance->mCurRequest.find(this) == sInstance->mCurRequest.end()); } } -- cgit v1.2.3 From c2bdb9be1455b7e6414b9a7d034b3118f6a07f23 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 9 Mar 2011 18:19:12 -0600 Subject: SH-706 Make triangle limit and error threshold spinners respond to arrow clicks. --- indra/newview/llfloatermodelpreview.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index c2054bf00f..fabf92c3c6 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -2235,6 +2235,11 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) mBuildBorderMode = GLOD_BORDER_UNLOCK; mBuildOperator = GLOD_OPERATOR_EDGE_COLLAPSE; + for (U32 i = 0; i < LLModel::NUM_LODS; ++i) + { + mRequestedTriangleCount[i] = 0; + } + mViewOption["show_textures"] = false; mFMP = fmp; @@ -2985,6 +2990,8 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim U32 actual_verts = 0; U32 submeshes = 0; + mRequestedTriangleCount[lod] = triangle_count; + glodGroupParameteri(mGroup, GLOD_ADAPT_MODE, lod_mode); stop_gloderror(); @@ -3466,7 +3473,7 @@ void LLModelPreview::updateStatusMessages() LLSpinCtrl* limit = mFMP->getChild("lod_triangle_limit"); limit->setMaxValue(mMaxTriangleLimit); - limit->setValue(total_tris[mPreviewLOD]); + limit->setValue(mRequestedTriangleCount[mPreviewLOD]); if (lod_mode == 0) { @@ -3474,6 +3481,7 @@ void LLModelPreview::updateStatusMessages() threshold->setVisible(false); limit->setMaxValue(mMaxTriangleLimit); + limit->setIncrement(mMaxTriangleLimit/32); } else { -- cgit v1.2.3 From a135831c848717cf3809a4ae47d36e57e2076c5b Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 9 Mar 2011 23:15:31 -0600 Subject: SH-632 Fix for inconsistent decimation results and off by one errors causing decimations where none are needed. --- indra/newview/llfloatermodelpreview.cpp | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index fabf92c3c6..f65fab41e7 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -2787,9 +2787,7 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim lod_mode = GLOD_TRIANGLE_BUDGET; if (which_lod != -1) { - //SH-632 take budget as supplied limit+1 to prevent GLOD from creating a smaller - //decimation when the given decimation is possible - limit = mFMP->childGetValue("lod_triangle_limit").asInteger(); //+1; + limit = mFMP->childGetValue("lod_triangle_limit").asInteger(); } } else @@ -2948,13 +2946,6 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim { start = end = which_lod; } - else - { - //SH-632 -- incremenet triangle count to avoid removing any triangles from - //highest LoD when auto-generating LoD - triangle_count++; - } - mMaxTriangleLimit = base_triangle_count; @@ -2998,15 +2989,25 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim glodGroupParameteri(mGroup, GLOD_ERROR_MODE, GLOD_OBJECT_SPACE_ERROR); stop_gloderror(); - glodGroupParameteri(mGroup, GLOD_MAX_TRIANGLES, triangle_count); + glodGroupParameterf(mGroup, GLOD_OBJECT_SPACE_ERROR_THRESHOLD, lod_error_threshold); stop_gloderror(); - glodGroupParameterf(mGroup, GLOD_OBJECT_SPACE_ERROR_THRESHOLD, lod_error_threshold); + glodGroupParameteri(mGroup, GLOD_MAX_TRIANGLES, 0); stop_gloderror(); glodAdaptGroup(mGroup); stop_gloderror(); + if (lod_mode == GLOD_TRIANGLE_BUDGET) + { //SH-632 Always adapt to 0 before adapting to actual desired amount, and always + //add 1 to desired amount to avoid decimating below desired amount + glodGroupParameteri(mGroup, GLOD_MAX_TRIANGLES, triangle_count+1); + stop_gloderror(); + + glodAdaptGroup(mGroup); + stop_gloderror(); + } + for (U32 mdl_idx = 0; mdl_idx < mBaseModel.size(); ++mdl_idx) { LLModel* base = mBaseModel[mdl_idx]; -- cgit v1.2.3 From bc54afb907e65ab2d73e1f040551c6191a4a7682 Mon Sep 17 00:00:00 2001 From: prep Date: Mon, 14 Mar 2011 16:17:34 -0400 Subject: WIP: manual pelvis offset for rigs that contain bone offsets --- indra/newview/llfloatermodelpreview.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index f65fab41e7..d4ba039eeb 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -310,6 +310,7 @@ BOOL LLFloaterModelPreview::postBuild() childSetCommitCallback("upload_joints", onUploadJointsCommit, this); childSetCommitCallback("import_scale", onImportScaleCommit, this); + childSetCommitCallback("pelvis_offset", onPelvisOffsetCommit, this); childSetCommitCallback("lod_file_or_limit", refresh, this); childSetCommitCallback("physics_load_radio", refresh, this); @@ -318,6 +319,9 @@ BOOL LLFloaterModelPreview::postBuild() childDisable("upload_skin"); childDisable("upload_joints"); + + childDisable("pelvis_offset"); + childDisable("ok_btn"); mViewOptionMenuButton = getChild("options_gear_btn"); @@ -456,6 +460,18 @@ void LLFloaterModelPreview::onImportScaleCommit(LLUICtrl*,void* userdata) fp->mModelPreview->calcResourceCost(); fp->mModelPreview->refresh(); } +//static +void LLFloaterModelPreview::onPelvisOffsetCommit( LLUICtrl*, void* userdata ) +{ + LLFloaterModelPreview *fp =(LLFloaterModelPreview*)userdata; + + if (!fp->mModelPreview) + { + return; + } + + fp->mModelPreview->refresh(); +} //static void LLFloaterModelPreview::onUploadJointsCommit(LLUICtrl*,void* userdata) @@ -3742,7 +3758,7 @@ BOOL LLModelPreview::render() if (fmp) { fmp->enableViewOption("show_skin_weight"); - fmp->setViewOptionEnabled("show_joint_positions", skin_weight); + fmp->setViewOptionEnabled("show_joint_positions", skin_weight); } mFMP->childEnable("upload_skin"); } -- cgit v1.2.3 From 5a940793e19225c065f1e37c1be32edd936a5246 Mon Sep 17 00:00:00 2001 From: prep linden Date: Wed, 16 Mar 2011 10:15:06 -0400 Subject: WIP:Manual pelvis offset --- indra/newview/llfloatermodelpreview.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index d4ba039eeb..3a7732c7b3 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -469,7 +469,7 @@ void LLFloaterModelPreview::onPelvisOffsetCommit( LLUICtrl*, void* userdata ) { return; } - + fp->mModelPreview->calcResourceCost(); fp->mModelPreview->refresh(); } @@ -2232,6 +2232,7 @@ LLColor4 LLModelLoader::getDaeColor(daeElement* element) LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) : LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE), LLMutex(NULL) +, mPelvisZOffset( 0.0f ) { mNeedsUpdate = TRUE; mCameraDistance = 0.f; @@ -2298,13 +2299,14 @@ U32 LLModelPreview::calcResourceCost() U32 num_hulls = 0; F32 debug_scale = mFMP ? mFMP->childGetValue("import_scale").asReal() : 1.f; - + mPelvisZOffset = mFMP ? mFMP->childGetValue("pelvis_offset").asReal() : 32.0f; + F32 streaming_cost = 0.f; F32 physics_cost = 0.f; for (U32 i = 0; i < mUploadData.size(); ++i) { LLModelInstance& instance = mUploadData[i]; - + if (accounted.find(instance.mModel) == accounted.end()) { accounted.insert(instance.mModel); @@ -3746,6 +3748,7 @@ BOOL LLModelPreview::render() { LLModelInstance& instance = *model_iter; LLModel* model = instance.mModel; + model->mPelvisOffset = mPelvisZOffset; if (!model->mSkinWeights.empty()) { has_skin_weights = true; -- cgit v1.2.3 From aaaddfe08942ff15bbe0c6549dc82dda95ce3ba1 Mon Sep 17 00:00:00 2001 From: prep linden Date: Wed, 16 Mar 2011 17:09:30 -0400 Subject: Fix for SH-1017. We now disallow malformed rigs to be uploaded (i.e. missing bones, improperly names bones etc...) --- indra/newview/llfloatermodelpreview.cpp | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 3a7732c7b3..6bf9fdfb9b 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -495,7 +495,8 @@ void LLFloaterModelPreview::onUploadSkinCommit(LLUICtrl*,void* userdata) { return; } - + + fp->mModelPreview->calcResourceCost(); fp->mModelPreview->refresh(); fp->mModelPreview->resetPreviewTarget(); fp->mModelPreview->clearBuffers(); @@ -1480,8 +1481,8 @@ void LLModelLoader::run() //(which means we have all the joints that are required for an avatar versus //a skinned asset attached to a node in a file that contains an entire skeleton, //but does not use the skeleton). - - if ( !model->mJointList.empty() && doesJointArrayContainACompleteRig( model->mJointList ) ) + mPreview->setRigValid( doesJointArrayContainACompleteRig( model->mJointList ) ); + if ( !model->mJointList.empty() && mPreview->isRigValid() ) { mResetJoints = true; } @@ -2233,6 +2234,7 @@ LLColor4 LLModelLoader::getDaeColor(daeElement* element) LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) : LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE), LLMutex(NULL) , mPelvisZOffset( 0.0f ) +, mRigValid( false ) { mNeedsUpdate = TRUE; mCameraDistance = 0.f; @@ -2293,6 +2295,16 @@ U32 LLModelPreview::calcResourceCost() } } + //Upload skin is selected BUT the joints coming in from the asset + //were malformed. + if ( mFMP && mFMP->childGetValue("upload_skin").asBoolean() ) + { + if ( !isRigValid() ) + { + mFMP->childDisable("ok_btn"); + } + } + U32 cost = 0; std::set accounted; U32 num_points = 0; @@ -2552,7 +2564,7 @@ void LLModelPreview::loadModel(std::string filename, S32 lod) { mFMP->childDisable("ok_btn"); } - + if (lod == mPreviewLOD) { mFMP->childSetText("lod_file", mLODFile[mPreviewLOD]); @@ -3295,15 +3307,18 @@ void LLModelPreview::updateStatusMessages() bool errorStateFromLoader = mModelLoader->getLoadState() == LLModelLoader::ERROR_PARSING ? true : false; - if ( upload_ok && !errorStateFromLoader ) + bool skinAndRigOk = true; + bool uploadingSkin = mFMP->childGetValue("upload_skin").asBoolean(); + if ( uploadingSkin && !isRigValid() ) { - mFMP->childEnable("ok_btn"); + skinAndRigOk = false; } - else + + if ( upload_ok && !errorStateFromLoader && skinAndRigOk ) { - mFMP->childDisable("ok_btn"); + mFMP->childEnable("ok_btn"); } - + //add up physics triangles etc S32 start = 0; S32 end = mModel[LLModel::LOD_PHYSICS].size(); -- cgit v1.2.3 From 359d0494308451ce1318f0291ebbf0ba58e42f44 Mon Sep 17 00:00:00 2001 From: prep linden Date: Thu, 17 Mar 2011 17:25:52 -0400 Subject: Added support for handling an asset that contains a skeletal node which has no root node for the scene (yuck). Fix for an upload issue w/simplebot --- indra/newview/llfloatermodelpreview.cpp | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 6bf9fdfb9b..190af6deef 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1070,7 +1070,6 @@ LLModelLoader::LLModelLoader(std::string filename, S32 lod, LLModelPreview* prev mMasterJointList.push_front("mChest"); mMasterJointList.push_front("mNeck"); mMasterJointList.push_front("mHead"); - mMasterJointList.push_front("mSkull"); mMasterJointList.push_front("mCollarLeft"); mMasterJointList.push_front("mShoulderLeft"); mMasterJointList.push_front("mElbowLeft"); @@ -1298,7 +1297,25 @@ void LLModelLoader::run() bool missingSkeletonOrScene = false; //If no skeleton, do a breadth-first search to get at specific joints - if ( !pSkeleton ) + bool rootNode = false; + bool skeletonWithNoRootNode = false; + + //Need to test for a skeleton that does not have a root node + //This occurs when your instance controller does not have an associated scene + if ( pSkeleton ) + { + daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement(); + if ( pSkeletonRootNode ) + { + rootNode = true; + } + else + { + skeletonWithNoRootNode = true; + } + + } + if ( !pSkeleton || !rootNode ) { daeElement* pScene = root->getDescendant("visual_scene"); if ( !pScene ) @@ -1482,7 +1499,7 @@ void LLModelLoader::run() //a skinned asset attached to a node in a file that contains an entire skeleton, //but does not use the skeleton). mPreview->setRigValid( doesJointArrayContainACompleteRig( model->mJointList ) ); - if ( !model->mJointList.empty() && mPreview->isRigValid() ) + if ( !skeletonWithNoRootNode && !model->mJointList.empty() && mPreview->isRigValid() ) { mResetJoints = true; } -- cgit v1.2.3 From 77869c9c1d80998055d35fa099dcb77f45699257 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Thu, 17 Mar 2011 17:17:31 -0500 Subject: SH-587 Fix for crash when clicking cancel in model importer. --- indra/newview/llfloatermodelpreview.cpp | 928 +++++++++++++++++--------------- 1 file changed, 484 insertions(+), 444 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 6bf9fdfb9b..eb0816adb5 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -986,7 +986,7 @@ void LLFloaterModelPreview::onMouseCaptureLostModelPreview(LLMouseHandler* handl // LLModelLoader //----------------------------------------------------------------------------- LLModelLoader::LLModelLoader(std::string filename, S32 lod, LLModelPreview* preview) -: LLThread("Model Loader"), mFilename(filename), mLod(lod), mPreview(preview), mState(STARTING), mFirstTransform(TRUE), mResetJoints( FALSE ) +: LLThread("Model Loader"), mFilename(filename), mLod(lod), mPreview(preview), mFirstTransform(TRUE), mResetJoints( FALSE ) { mJointMap["mPelvis"] = "mPelvis"; mJointMap["mTorso"] = "mTorso"; @@ -1085,6 +1085,11 @@ LLModelLoader::LLModelLoader(std::string filename, S32 lod, LLModelPreview* prev mMasterJointList.push_front("mHipLeft"); mMasterJointList.push_front("mKneeLeft"); mMasterJointList.push_front("mFootLeft"); + + if (mPreview) + { + mPreview->setLoadState(STARTING); + } } void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, BOOL& first_transform) @@ -1151,273 +1156,304 @@ void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& } void LLModelLoader::run() +{ + if (!doLoadModel()) + { + mPreview = NULL; + } + + doOnIdleOneTime(boost::bind(&LLModelLoader::loadModelCallback,this)); +} + +bool LLModelLoader::doLoadModel() { DAE dae; domCOLLADA* dom = dae.open(mFilename); - if (dom) + if (!dom) { - daeDatabase* db = dae.getDatabase(); - - daeInt count = db->getElementCount(NULL, COLLADA_TYPE_MESH); - - daeDocument* doc = dae.getDoc(mFilename); - if (!doc) - { - llwarns << "can't find internal doc" << llendl; - return; - } - - daeElement* root = doc->getDomRoot(); - if (!root) - { - llwarns << "document has no root" << llendl; - return; - } - - //get unit scale - mTransform.setIdentity(); - - domAsset::domUnit* unit = daeSafeCast(root->getDescendant(daeElement::matchType(domAsset::domUnit::ID()))); - - if (unit) - { - F32 meter = unit->getMeter(); - mTransform.mMatrix[0][0] = meter; - mTransform.mMatrix[1][1] = meter; - mTransform.mMatrix[2][2] = meter; - } - - //get up axis rotation - LLMatrix4 rotation; - - domUpAxisType up = UPAXISTYPE_Y_UP; // default is Y_UP - domAsset::domUp_axis* up_axis = - daeSafeCast(root->getDescendant(daeElement::matchType(domAsset::domUp_axis::ID()))); - - if (up_axis) - { - up = up_axis->getValue(); - } + return false; + } + + daeDatabase* db = dae.getDatabase(); + + daeInt count = db->getElementCount(NULL, COLLADA_TYPE_MESH); + + daeDocument* doc = dae.getDoc(mFilename); + if (!doc) + { + llwarns << "can't find internal doc" << llendl; + return false; + } + + daeElement* root = doc->getDomRoot(); + if (!root) + { + llwarns << "document has no root" << llendl; + return false; + } + + //get unit scale + mTransform.setIdentity(); + + domAsset::domUnit* unit = daeSafeCast(root->getDescendant(daeElement::matchType(domAsset::domUnit::ID()))); + + if (unit) + { + F32 meter = unit->getMeter(); + mTransform.mMatrix[0][0] = meter; + mTransform.mMatrix[1][1] = meter; + mTransform.mMatrix[2][2] = meter; + } + + //get up axis rotation + LLMatrix4 rotation; + + domUpAxisType up = UPAXISTYPE_Y_UP; // default is Y_UP + domAsset::domUp_axis* up_axis = + daeSafeCast(root->getDescendant(daeElement::matchType(domAsset::domUp_axis::ID()))); + + if (up_axis) + { + up = up_axis->getValue(); + } + + if (up == UPAXISTYPE_X_UP) + { + rotation.initRotation(0.0f, 90.0f * DEG_TO_RAD, 0.0f); + } + else if (up == UPAXISTYPE_Y_UP) + { + rotation.initRotation(90.0f * DEG_TO_RAD, 0.0f, 0.0f); + } + + rotation *= mTransform; + mTransform = rotation; + + + for (daeInt idx = 0; idx < count; ++idx) + { //build map of domEntities to LLModel + domMesh* mesh = NULL; + db->getElement((daeElement**) &mesh, idx, NULL, COLLADA_TYPE_MESH); - if (up == UPAXISTYPE_X_UP) + if (mesh) { - rotation.initRotation(0.0f, 90.0f * DEG_TO_RAD, 0.0f); - } - else if (up == UPAXISTYPE_Y_UP) - { - rotation.initRotation(90.0f * DEG_TO_RAD, 0.0f, 0.0f); - } - - rotation *= mTransform; - mTransform = rotation; - - - for (daeInt idx = 0; idx < count; ++idx) - { //build map of domEntities to LLModel - domMesh* mesh = NULL; - db->getElement((daeElement**) &mesh, idx, NULL, COLLADA_TYPE_MESH); + LLPointer model = LLModel::loadModelFromDomMesh(mesh); - if (mesh) + if (model.notNull() && validate_model(model)) { - LLPointer model = LLModel::loadModelFromDomMesh(mesh); - - if (model.notNull() && validate_model(model)) - { - mModelList.push_back(model); - mModel[mesh] = model; - } + mModelList.push_back(model); + mModel[mesh] = model; } } + } + + count = db->getElementCount(NULL, COLLADA_TYPE_SKIN); + for (daeInt idx = 0; idx < count; ++idx) + { //add skinned meshes as instances + domSkin* skin = NULL; + db->getElement((daeElement**) &skin, idx, NULL, COLLADA_TYPE_SKIN); - count = db->getElementCount(NULL, COLLADA_TYPE_SKIN); - for (daeInt idx = 0; idx < count; ++idx) - { //add skinned meshes as instances - domSkin* skin = NULL; - db->getElement((daeElement**) &skin, idx, NULL, COLLADA_TYPE_SKIN); + if (skin) + { + domGeometry* geom = daeSafeCast(skin->getSource().getElement()); - if (skin) + if (geom) { - domGeometry* geom = daeSafeCast(skin->getSource().getElement()); - - if (geom) + domMesh* mesh = geom->getMesh(); + if (mesh) { - domMesh* mesh = geom->getMesh(); - if (mesh) + LLModel* model = mModel[mesh]; + if (model) { - LLModel* model = mModel[mesh]; - if (model) - { - LLVector3 mesh_scale_vector; - LLVector3 mesh_translation_vector; - model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); - - LLMatrix4 normalized_transformation; - normalized_transformation.setTranslation(mesh_translation_vector); - - LLMatrix4 mesh_scale; - mesh_scale.initScale(mesh_scale_vector); - mesh_scale *= normalized_transformation; - normalized_transformation = mesh_scale; + LLVector3 mesh_scale_vector; + LLVector3 mesh_translation_vector; + model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); + + LLMatrix4 normalized_transformation; + normalized_transformation.setTranslation(mesh_translation_vector); + + LLMatrix4 mesh_scale; + mesh_scale.initScale(mesh_scale_vector); + mesh_scale *= normalized_transformation; + normalized_transformation = mesh_scale; + + glh::matrix4f inv_mat((F32*) normalized_transformation.mMatrix); + inv_mat = inv_mat.inverse(); + LLMatrix4 inverse_normalized_transformation(inv_mat.m); + + domSkin::domBind_shape_matrix* bind_mat = skin->getBind_shape_matrix(); + + if (bind_mat) + { //get bind shape matrix + domFloat4x4& dom_value = bind_mat->getValue(); - glh::matrix4f inv_mat((F32*) normalized_transformation.mMatrix); - inv_mat = inv_mat.inverse(); - LLMatrix4 inverse_normalized_transformation(inv_mat.m); - - domSkin::domBind_shape_matrix* bind_mat = skin->getBind_shape_matrix(); - - if (bind_mat) - { //get bind shape matrix - domFloat4x4& dom_value = bind_mat->getValue(); - - for (int i = 0; i < 4; i++) + for (int i = 0; i < 4; i++) + { + for(int j = 0; j < 4; j++) { - for(int j = 0; j < 4; j++) - { - model->mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j*4]; - } + model->mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j*4]; } - - LLMatrix4 trans = normalized_transformation; - trans *= model->mBindShapeMatrix; - model->mBindShapeMatrix = trans; - } + LLMatrix4 trans = normalized_transformation; + trans *= model->mBindShapeMatrix; + model->mBindShapeMatrix = trans; - //The joint transfom map that we'll populate below - std::map jointTransforms; - jointTransforms.clear(); - - //Some collada setup for accessing the skeleton - daeElement* pElement = 0; - dae.getDatabase()->getElement( &pElement, 0, 0, "skeleton" ); - - //Try to get at the skeletal instance controller - domInstance_controller::domSkeleton* pSkeleton = daeSafeCast( pElement ); - bool missingSkeletonOrScene = false; - - //If no skeleton, do a breadth-first search to get at specific joints - if ( !pSkeleton ) + } + + + //The joint transfom map that we'll populate below + std::map jointTransforms; + jointTransforms.clear(); + + //Some collada setup for accessing the skeleton + daeElement* pElement = 0; + dae.getDatabase()->getElement( &pElement, 0, 0, "skeleton" ); + + //Try to get at the skeletal instance controller + domInstance_controller::domSkeleton* pSkeleton = daeSafeCast( pElement ); + bool missingSkeletonOrScene = false; + + //If no skeleton, do a breadth-first search to get at specific joints + if ( !pSkeleton ) + { + daeElement* pScene = root->getDescendant("visual_scene"); + if ( !pScene ) { - daeElement* pScene = root->getDescendant("visual_scene"); - if ( !pScene ) - { - llwarns<<"No visual scene - unable to parse bone offsets "< > children = pScene->getChildren(); + S32 childCount = children.getCount(); + + //Process any children that are joints + //Not all children are joints, some code be ambient lights, cameras, geometry etc.. + for (S32 i = 0; i < childCount; ++i) { - //Get the children at this level - daeTArray< daeSmartRef > children = pScene->getChildren(); - S32 childCount = children.getCount(); - - //Process any children that are joints - //Not all children are joints, some code be ambient lights, cameras, geometry etc.. - for (S32 i = 0; i < childCount; ++i) + domNode* pNode = daeSafeCast(children[i]); + if ( isNodeAJoint( pNode ) ) { - domNode* pNode = daeSafeCast(children[i]); - if ( isNodeAJoint( pNode ) ) - { - processJointNode( pNode, jointTransforms ); - } + processJointNode( pNode, jointTransforms ); } } } - else - //Has Skeleton + } + else + //Has Skeleton + { + //Get the root node of the skeleton + daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement(); + if ( pSkeletonRootNode ) { - //Get the root node of the skeleton - daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement(); - if ( pSkeletonRootNode ) + //Once we have the root node - start acccessing it's joint components + const int jointCnt = mJointMap.size(); + std::map :: const_iterator jointIt = mJointMap.begin(); + + //Loop over all the possible joints within the .dae - using the allowed joint list in the ctor. + for ( int i=0; i :: const_iterator jointIt = mJointMap.begin(); + //Build a joint for the resolver to work with + char str[64]={0}; + sprintf(str,"./%s",(*jointIt).second.c_str() ); + //llwarns<<"Joint "<< str <( resolver.getElement() ); + if ( pJoint ) + { + //Pull out the translate id and store it in the jointTranslations map + daeSIDResolver jointResolver( pJoint, "./translate" ); + domTranslate* pTranslate = daeSafeCast( jointResolver.getElement() ); - //Setup the resolver - daeSIDResolver resolver( pSkeletonRootNode, str ); + LLMatrix4 workingTransform; - //Look for the joint - domNode* pJoint = daeSafeCast( resolver.getElement() ); - if ( pJoint ) - { - //Pull out the translate id and store it in the jointTranslations map - daeSIDResolver jointResolver( pJoint, "./translate" ); - domTranslate* pTranslate = daeSafeCast( jointResolver.getElement() ); - - LLMatrix4 workingTransform; - - //Translation via SID - if ( pTranslate ) + //Translation via SID + if ( pTranslate ) + { + extractTranslation( pTranslate, workingTransform ); + } + else + { + //Translation via child from element + daeElement* pTranslateElement = getChildFromElement( pJoint, "translate" ); + if ( pTranslateElement && pTranslateElement->typeID() != domTranslate::ID() ) { - extractTranslation( pTranslate, workingTransform ); + llwarns<< "The found element is not a translate node" <typeID() != domTranslate::ID() ) - { - llwarns<< "The found element is not a translate node" <getJoints(); - - domInputLocal_Array& joint_input = joints->getInput_array(); + } + + //Store the joint transform w/respect to it's name. + jointTransforms[(*jointIt).second.c_str()] = workingTransform; + } + } + + //If anything failed in regards to extracting the skeleton, joints or translation id, + //mention it + if ( missingSkeletonOrScene ) + { + llwarns<< "Partial jointmap found in asset - did you mean to just have a partial map?" << llendl; + } + }//got skeleton? + } + + + domSkin::domJoints* joints = skin->getJoints(); + + domInputLocal_Array& joint_input = joints->getInput_array(); + + for (size_t i = 0; i < joint_input.getCount(); ++i) + { + domInputLocal* input = joint_input.get(i); + xsNMTOKEN semantic = input->getSemantic(); - for (size_t i = 0; i < joint_input.getCount(); ++i) - { - domInputLocal* input = joint_input.get(i); - xsNMTOKEN semantic = input->getSemantic(); + if (strcmp(semantic, COMMON_PROFILE_INPUT_JOINT) == 0) + { //found joint source, fill model->mJointMap and model->mJointList + daeElement* elem = input->getSource().getElement(); - if (strcmp(semantic, COMMON_PROFILE_INPUT_JOINT) == 0) - { //found joint source, fill model->mJointMap and model->mJointList - daeElement* elem = input->getSource().getElement(); + domSource* source = daeSafeCast(elem); + if (source) + { - domSource* source = daeSafeCast(elem); - if (source) + + domName_array* names_source = source->getName_array(); + + if (names_source) { + domListOfNames &names = names_source->getValue(); - - domName_array* names_source = source->getName_array(); - + for (size_t j = 0; j < names.getCount(); ++j) + { + std::string name(names.get(j)); + if (mJointMap.find(name) != mJointMap.end()) + { + name = mJointMap[name]; + } + model->mJointList.push_back(name); + model->mJointMap[name] = j; + } + } + else + { + domIDREF_array* names_source = source->getIDREF_array(); if (names_source) { - domListOfNames &names = names_source->getValue(); + xsIDREFS& names = names_source->getValue(); for (size_t j = 0; j < names.getCount(); ++j) { - std::string name(names.get(j)); + std::string name(names.get(j).getID()); if (mJointMap.find(name) != mJointMap.end()) { name = mJointMap[name]; @@ -1426,279 +1462,284 @@ void LLModelLoader::run() model->mJointMap[name] = j; } } - else - { - domIDREF_array* names_source = source->getIDREF_array(); - if (names_source) - { - xsIDREFS& names = names_source->getValue(); - - for (size_t j = 0; j < names.getCount(); ++j) - { - std::string name(names.get(j).getID()); - if (mJointMap.find(name) != mJointMap.end()) - { - name = mJointMap[name]; - } - model->mJointList.push_back(name); - model->mJointMap[name] = j; - } - } - } } } - else if (strcmp(semantic, COMMON_PROFILE_INPUT_INV_BIND_MATRIX) == 0) - { //found inv_bind_matrix array, fill model->mInvBindMatrix - domSource* source = daeSafeCast(input->getSource().getElement()); - if (source) + } + else if (strcmp(semantic, COMMON_PROFILE_INPUT_INV_BIND_MATRIX) == 0) + { //found inv_bind_matrix array, fill model->mInvBindMatrix + domSource* source = daeSafeCast(input->getSource().getElement()); + if (source) + { + domFloat_array* t = source->getFloat_array(); + if (t) { - domFloat_array* t = source->getFloat_array(); - if (t) + domListOfFloats& transform = t->getValue(); + S32 count = transform.getCount()/16; + + for (S32 k = 0; k < count; ++k) { - domListOfFloats& transform = t->getValue(); - S32 count = transform.getCount()/16; + LLMatrix4 mat; - for (S32 k = 0; k < count; ++k) + for (int i = 0; i < 4; i++) { - LLMatrix4 mat; - - for (int i = 0; i < 4; i++) + for(int j = 0; j < 4; j++) { - for(int j = 0; j < 4; j++) - { - mat.mMatrix[i][j] = transform[k*16 + i + j*4]; - } + mat.mMatrix[i][j] = transform[k*16 + i + j*4]; } - - model->mInvBindMatrix.push_back(mat); } + + model->mInvBindMatrix.push_back(mat); } } } } - - //Now that we've parsed the joint array, let's determine if we have a full rig - //(which means we have all the joints that are required for an avatar versus - //a skinned asset attached to a node in a file that contains an entire skeleton, - //but does not use the skeleton). - mPreview->setRigValid( doesJointArrayContainACompleteRig( model->mJointList ) ); - if ( !model->mJointList.empty() && mPreview->isRigValid() ) - { - mResetJoints = true; - } - - if ( !missingSkeletonOrScene ) - { - //Set the joint translations on the avatar - if it's a full mapping - //The joints are reset in the dtor - if ( mResetJoints ) - { - std::map :: const_iterator masterJointIt = mJointMap.begin(); - std::map :: const_iterator masterJointItEnd = mJointMap.end(); - for (;masterJointIt!=masterJointItEnd;++masterJointIt ) + } + + //Now that we've parsed the joint array, let's determine if we have a full rig + //(which means we have all the joints that are required for an avatar versus + //a skinned asset attached to a node in a file that contains an entire skeleton, + //but does not use the skeleton). + mPreview->setRigValid( doesJointArrayContainACompleteRig( model->mJointList ) ); + if ( !model->mJointList.empty() && mPreview->isRigValid() ) + { + mResetJoints = true; + } + + if ( !missingSkeletonOrScene ) + { + //Set the joint translations on the avatar - if it's a full mapping + //The joints are reset in the dtor + if ( mResetJoints ) + { + std::map :: const_iterator masterJointIt = mJointMap.begin(); + std::map :: const_iterator masterJointItEnd = mJointMap.end(); + for (;masterJointIt!=masterJointItEnd;++masterJointIt ) + { + std::string lookingForJoint = (*masterJointIt).first.c_str(); + + if ( jointTransforms.find( lookingForJoint ) != jointTransforms.end() ) { - std::string lookingForJoint = (*masterJointIt).first.c_str(); - - if ( jointTransforms.find( lookingForJoint ) != jointTransforms.end() ) + //llinfos<<"joint "<getJoint( lookingForJoint ); + if ( pJoint ) + { + pJoint->storeCurrentXform( jointTransform.getTranslation() ); + } + else { - //llinfos<<"joint "<getJoint( lookingForJoint ); - if ( pJoint ) - { - pJoint->storeCurrentXform( jointTransform.getTranslation() ); - } - else - { - //Most likely an error in the asset. - llwarns<<"Tried to apply joint position from .dae, but it did not exist in the avatar rig." << llendl; - } + //Most likely an error in the asset. + llwarns<<"Tried to apply joint position from .dae, but it did not exist in the avatar rig." << llendl; } } } - } //missingSkeletonOrScene - - //We need to construct the alternate bind matrix (which contains the new joint positions) - //in the same order as they were stored in the joint buffer. The joints associated - //with the skeleton are not stored in the same order as they are in the exported joint buffer. - //This remaps the skeletal joints to be in the same order as the joints stored in the model. - std::vector :: const_iterator jointIt = model->mJointList.begin(); - const int jointCnt = model->mJointList.size(); - for ( int i=0; i :: const_iterator jointIt = model->mJointList.begin(); + const int jointCnt = model->mJointList.size(); + for ( int i=0; imInvBindMatrix[i]; - newInverse.setTranslation( jointTransforms[lookingForJoint].getTranslation() ); - model->mAlternateBindMatrix.push_back( newInverse ); - } - else - { - llwarns<<"Possibly misnamed/missing joint [" <mInvBindMatrix[i]; + newInverse.setTranslation( jointTransforms[lookingForJoint].getTranslation() ); + model->mAlternateBindMatrix.push_back( newInverse ); } - - //grab raw position array - - domVertices* verts = mesh->getVertices(); - if (verts) + else + { + llwarns<<"Possibly misnamed/missing joint [" <getVertices(); + if (verts) + { + domInputLocal_Array& inputs = verts->getInput_array(); + for (size_t i = 0; i < inputs.getCount() && model->mPosition.empty(); ++i) { - domInputLocal_Array& inputs = verts->getInput_array(); - for (size_t i = 0; i < inputs.getCount() && model->mPosition.empty(); ++i) + if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_POSITION) == 0) { - if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_POSITION) == 0) + domSource* pos_source = daeSafeCast(inputs[i]->getSource().getElement()); + if (pos_source) { - domSource* pos_source = daeSafeCast(inputs[i]->getSource().getElement()); - if (pos_source) + domFloat_array* pos_array = pos_source->getFloat_array(); + if (pos_array) { - domFloat_array* pos_array = pos_source->getFloat_array(); - if (pos_array) + domListOfFloats& pos = pos_array->getValue(); + + for (size_t j = 0; j < pos.getCount(); j += 3) { - domListOfFloats& pos = pos_array->getValue(); - - for (size_t j = 0; j < pos.getCount(); j += 3) + if (pos.getCount() <= j+2) { - if (pos.getCount() <= j+2) - { - llerrs << "WTF?" << llendl; - } - - LLVector3 v(pos[j], pos[j+1], pos[j+2]); - - //transform from COLLADA space to volume space - v = v * inverse_normalized_transformation; - - model->mPosition.push_back(v); + llerrs << "WTF?" << llendl; } + + LLVector3 v(pos[j], pos[j+1], pos[j+2]); + + //transform from COLLADA space to volume space + v = v * inverse_normalized_transformation; + + model->mPosition.push_back(v); } } } } } - - //grab skin weights array - domSkin::domVertex_weights* weights = skin->getVertex_weights(); - if (weights) + } + + //grab skin weights array + domSkin::domVertex_weights* weights = skin->getVertex_weights(); + if (weights) + { + domInputLocalOffset_Array& inputs = weights->getInput_array(); + domFloat_array* vertex_weights = NULL; + for (size_t i = 0; i < inputs.getCount(); ++i) { - domInputLocalOffset_Array& inputs = weights->getInput_array(); - domFloat_array* vertex_weights = NULL; - for (size_t i = 0; i < inputs.getCount(); ++i) + if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_WEIGHT) == 0) { - if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_WEIGHT) == 0) + domSource* weight_source = daeSafeCast(inputs[i]->getSource().getElement()); + if (weight_source) { - domSource* weight_source = daeSafeCast(inputs[i]->getSource().getElement()); - if (weight_source) - { - vertex_weights = weight_source->getFloat_array(); - } + vertex_weights = weight_source->getFloat_array(); } } + } + + if (vertex_weights) + { + domListOfFloats& w = vertex_weights->getValue(); + domListOfUInts& vcount = weights->getVcount()->getValue(); + domListOfInts& v = weights->getV()->getValue(); - if (vertex_weights) - { - domListOfFloats& w = vertex_weights->getValue(); - domListOfUInts& vcount = weights->getVcount()->getValue(); - domListOfInts& v = weights->getV()->getValue(); + U32 c_idx = 0; + for (size_t vc_idx = 0; vc_idx < vcount.getCount(); ++vc_idx) + { //for each vertex + daeUInt count = vcount[vc_idx]; - U32 c_idx = 0; - for (size_t vc_idx = 0; vc_idx < vcount.getCount(); ++vc_idx) - { //for each vertex - daeUInt count = vcount[vc_idx]; - - //create list of weights that influence this vertex - LLModel::weight_list weight_list; - - for (daeUInt i = 0; i < count; ++i) - { //for each weight - daeInt joint_idx = v[c_idx++]; - daeInt weight_idx = v[c_idx++]; - - if (joint_idx == -1) - { - //ignore bindings to bind_shape_matrix - continue; - } - - F32 weight_value = w[weight_idx]; - - weight_list.push_back(LLModel::JointWeight(joint_idx, weight_value)); - } - - //sort by joint weight - std::sort(weight_list.begin(), weight_list.end(), LLModel::CompareWeightGreater()); - - std::vector wght; - - F32 total = 0.f; + //create list of weights that influence this vertex + LLModel::weight_list weight_list; + + for (daeUInt i = 0; i < count; ++i) + { //for each weight + daeInt joint_idx = v[c_idx++]; + daeInt weight_idx = v[c_idx++]; - for (U32 i = 0; i < llmin((U32) 4, (U32) weight_list.size()); ++i) - { //take up to 4 most significant weights - if (weight_list[i].mWeight > 0.f) - { - wght.push_back( weight_list[i] ); - total += weight_list[i].mWeight; - } + if (joint_idx == -1) + { + //ignore bindings to bind_shape_matrix + continue; } - F32 scale = 1.f/total; - if (scale != 1.f) - { //normalize weights - for (U32 i = 0; i < wght.size(); ++i) - { - wght[i].mWeight *= scale; - } - } + F32 weight_value = w[weight_idx]; - model->mSkinWeights[model->mPosition[vc_idx]] = wght; + weight_list.push_back(LLModel::JointWeight(joint_idx, weight_value)); } - //add instance to scene for this model + //sort by joint weight + std::sort(weight_list.begin(), weight_list.end(), LLModel::CompareWeightGreater()); + + std::vector wght; - LLMatrix4 transformation = mTransform; - // adjust the transformation to compensate for mesh normalization + F32 total = 0.f; - LLMatrix4 mesh_translation; - mesh_translation.setTranslation(mesh_translation_vector); - mesh_translation *= transformation; - transformation = mesh_translation; + for (U32 i = 0; i < llmin((U32) 4, (U32) weight_list.size()); ++i) + { //take up to 4 most significant weights + if (weight_list[i].mWeight > 0.f) + { + wght.push_back( weight_list[i] ); + total += weight_list[i].mWeight; + } + } - LLMatrix4 mesh_scale; - mesh_scale.initScale(mesh_scale_vector); - mesh_scale *= transformation; - transformation = mesh_scale; + F32 scale = 1.f/total; + if (scale != 1.f) + { //normalize weights + for (U32 i = 0; i < wght.size(); ++i) + { + wght[i].mWeight *= scale; + } + } - std::vector materials; - materials.resize(model->getNumVolumeFaces()); - mScene[transformation].push_back(LLModelInstance(model, model->mLabel, transformation, materials)); - stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); + model->mSkinWeights[model->mPosition[vc_idx]] = wght; } + + //add instance to scene for this model + + LLMatrix4 transformation = mTransform; + // adjust the transformation to compensate for mesh normalization + + LLMatrix4 mesh_translation; + mesh_translation.setTranslation(mesh_translation_vector); + mesh_translation *= transformation; + transformation = mesh_translation; + + LLMatrix4 mesh_scale; + mesh_scale.initScale(mesh_scale_vector); + mesh_scale *= transformation; + transformation = mesh_scale; + + std::vector materials; + materials.resize(model->getNumVolumeFaces()); + mScene[transformation].push_back(LLModelInstance(model, model->mLabel, transformation, materials)); + stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); } } } } } } - - daeElement* scene = root->getDescendant("visual_scene"); - - if (!scene) - { - llwarns << "document has no visual_scene" << llendl; - setLoadState( ERROR_PARSING ); - return; - } - setLoadState( DONE ); + } + + daeElement* scene = root->getDescendant("visual_scene"); + + if (!scene) + { + llwarns << "document has no visual_scene" << llendl; + setLoadState( ERROR_PARSING ); + return false; + } + setLoadState( DONE ); - processElement(scene); - - handlePivotPoint( root ); - - doOnIdleOneTime(boost::bind(&LLModelPreview::loadModelCallback,mPreview,mLod)); + processElement(scene); + + handlePivotPoint( root ); + + return true; +} + +void LLModelLoader::setLoadState(U32 state) +{ + if (mPreview) + { + mPreview->setLoadState(state); + } +} + +void LLModelLoader::loadModelCallback() +{ + if (mPreview) + { + mPreview->loadModelCallback(mLod); + mPreview->mModelLoader = NULL; + } + + while (!isStopped()) + { //wait until this thread is stopped before deleting self + apr_sleep(100); } + + delete this; } void LLModelLoader::handlePivotPoint( daeElement* pRoot ) @@ -2248,6 +2289,7 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) mDirty = false; mGenLOD = false; mLoading = false; + mLoadState = LLModelLoader::STARTING; mGroup = 0; mBuildShareTolerance = 0.f; mBuildQueueMode = GLOD_QUEUE_GREEDY; @@ -2273,10 +2315,8 @@ LLModelPreview::~LLModelPreview() { if (mModelLoader) { - delete mModelLoader; - mModelLoader = NULL; + mModelLoader->mPreview = NULL; } - //*HACK : *TODO : turn this back on when we understand why this crashes //glodShutdown(); } @@ -2289,7 +2329,7 @@ U32 LLModelPreview::calcResourceCost() if (mFMP && mModelLoader) { - if ( mModelLoader->getLoadState() != LLModelLoader::ERROR_PARSING ) + if ( getLoadState() != LLModelLoader::ERROR_PARSING ) { mFMP->childEnable("ok_btn"); } @@ -2541,10 +2581,10 @@ void LLModelPreview::loadModel(std::string filename, S32 lod) if (mModelLoader) { - delete mModelLoader; - mModelLoader = NULL; + llwarns << "Incompleted model load operation pending." << llendl; + return; } - + mLODFile[lod] = filename; if (lod == LLModel::LOD_HIGH) @@ -2560,7 +2600,7 @@ void LLModelPreview::loadModel(std::string filename, S32 lod) setPreviewLOD(lod); - if ( mModelLoader->getLoadState() == LLModelLoader::ERROR_PARSING ) + if ( getLoadState() == LLModelLoader::ERROR_PARSING ) { mFMP->childDisable("ok_btn"); } @@ -3305,7 +3345,7 @@ void LLModelPreview::updateStatusMessages() } } - bool errorStateFromLoader = mModelLoader->getLoadState() == LLModelLoader::ERROR_PARSING ? true : false; + bool errorStateFromLoader = getLoadState() == LLModelLoader::ERROR_PARSING ? true : false; bool skinAndRigOk = true; bool uploadingSkin = mFMP->childGetValue("upload_skin").asBoolean(); -- cgit v1.2.3 From 9c1c791b29cb5087ebff142d4ad7a55b65be0ad0 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Thu, 17 Mar 2011 17:35:51 -0500 Subject: Merge indentation fix up. --- indra/newview/llfloatermodelpreview.cpp | 34 ++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 7d60258ca4..ce977b33bb 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1315,25 +1315,25 @@ bool LLModelLoader::doLoadModel() bool missingSkeletonOrScene = false; //If no skeleton, do a breadth-first search to get at specific joints - bool rootNode = false; - bool skeletonWithNoRootNode = false; - - //Need to test for a skeleton that does not have a root node - //This occurs when your instance controller does not have an associated scene - if ( pSkeleton ) + bool rootNode = false; + bool skeletonWithNoRootNode = false; + + //Need to test for a skeleton that does not have a root node + //This occurs when your instance controller does not have an associated scene + if ( pSkeleton ) + { + daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement(); + if ( pSkeletonRootNode ) { - daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement(); - if ( pSkeletonRootNode ) - { - rootNode = true; - } - else - { - skeletonWithNoRootNode = true; - } - + rootNode = true; } - if ( !pSkeleton || !rootNode ) + else + { + skeletonWithNoRootNode = true; + } + + } + if ( !pSkeleton || !rootNode ) { daeElement* pScene = root->getDescendant("visual_scene"); if ( !pScene ) -- cgit v1.2.3 From 51a4867ae6bcf0ec71882ba77b1c995d98834126 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Mon, 21 Mar 2011 17:31:25 -0500 Subject: SH-1168 Export upload data to disk on upload. --- indra/newview/llfloatermodelpreview.cpp | 73 ++++++++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index ce977b33bb..04dfcac20b 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -90,6 +90,7 @@ #include "llbutton.h" #include "llcheckboxctrl.h" #include "llradiogroup.h" +#include "llsdserialize.h" #include "llsliderctrl.h" #include "llspinctrl.h" #include "lltoggleablemenu.h" @@ -2561,6 +2562,71 @@ void LLModelPreview::rebuildUploadData() } +void LLModelPreview::saveUploadData(bool save_skinweights, bool save_joint_positions) +{ + if (!mLODFile[LLModel::LOD_HIGH].empty()) + { + std::string filename = mLODFile[LLModel::LOD_HIGH]; + + std::string::size_type i = filename.rfind("."); + if (i != std::string::npos) + { + filename.replace(i, filename.size()-1, ".slm"); + saveUploadData(filename, save_skinweights, save_joint_positions); + } + } +} + +void LLModelPreview::saveUploadData(const std::string& filename, bool save_skinweights, bool save_joint_positions) +{ + std::set > meshes; + std::map mesh_binary; + + LLModel::hull empty_hull; + + LLSD data; + + S32 mesh_id = 0; + + //build list of unique models and initialize local id + for (U32 i = 0; i < mUploadData.size(); ++i) + { + LLModelInstance& instance = mUploadData[i]; + + if (meshes.find(instance.mModel) == meshes.end()) + { + instance.mModel->mLocalID = mesh_id++; + meshes.insert(instance.mModel); + + std::stringstream str; + + LLModel::convex_hull_decomposition& decomp = + instance.mLOD[LLModel::LOD_PHYSICS].notNull() ? + instance.mLOD[LLModel::LOD_PHYSICS]->mConvexHullDecomp : + instance.mModel->mConvexHullDecomp; + + LLModel::writeModel(str, + instance.mLOD[LLModel::LOD_PHYSICS], + instance.mLOD[LLModel::LOD_HIGH], + instance.mLOD[LLModel::LOD_MEDIUM], + instance.mLOD[LLModel::LOD_LOW], + instance.mLOD[LLModel::LOD_IMPOSTOR], + decomp, + empty_hull, save_skinweights, save_joint_positions); + + data["mesh"][instance.mModel->mLocalID] = str.str(); + } + + data["instance"][i] = instance.asLLSD(); + } + + llofstream out(filename, std::ios_base::out | std::ios_base::binary); + LLSDSerialize::toBinary(data, out); + out.flush(); + out.close(); +} + + void LLModelPreview::clearModel(S32 lod) { @@ -4317,8 +4383,13 @@ void LLFloaterModelPreview::onUpload(void* user_data) mp->mModelPreview->rebuildUploadData(); + bool upload_skinweights = mp->childGetValue("upload_skin").asBoolean(); + bool upload_joint_positions = mp->childGetValue("upload_joints").asBoolean(); + + mp->mModelPreview->saveUploadData(upload_skinweights, upload_joint_positions); + gMeshRepo.uploadModel(mp->mModelPreview->mUploadData, mp->mModelPreview->mPreviewScale, - mp->childGetValue("upload_textures").asBoolean(), mp->childGetValue("upload_skin"), mp->childGetValue("upload_joints")); + mp->childGetValue("upload_textures").asBoolean(), upload_skinweights, upload_joint_positions); mp->closeFloater(false); } -- cgit v1.2.3 From 6ff87e2840c585711e2927028a11ba5ce78a192a Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 22 Mar 2011 17:23:48 -0500 Subject: SH-1169 Import from slm instead of dae when appropriate. --- indra/newview/llfloatermodelpreview.cpp | 226 ++++++++++++++++++++++++++++---- 1 file changed, 202 insertions(+), 24 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 04dfcac20b..6145c6c16d 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -82,6 +82,7 @@ #include "llvoavatarself.h" #include "pipeline.h" #include "lluictrlfactory.h" +#include "llviewercontrol.h" #include "llviewermenu.h" #include "llviewermenufile.h" #include "llviewerregion.h" @@ -1088,8 +1089,15 @@ LLModelLoader::LLModelLoader(std::string filename, S32 lod, LLModelPreview* prev if (mPreview) { + //only try to load from slm if viewer is configured to do so and this is the + //initial model load (not an LoD or physics shape) + mTrySLM = gSavedSettings.getBOOL("MeshImportUseSLM") && mPreview->mBaseModel.empty(); mPreview->setLoadState(STARTING); } + else + { + mTrySLM = false; + } } void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, BOOL& first_transform) @@ -1167,6 +1175,38 @@ void LLModelLoader::run() bool LLModelLoader::doLoadModel() { + //first, look for a .slm file of the same name that was modified later + //than the .dae + + if (mTrySLM) + { + std::string filename = mFilename; + + std::string::size_type i = filename.rfind("."); + if (i != std::string::npos) + { + filename.replace(i, filename.size()-1, ".slm"); + llstat slm_status; + if (LLFile::stat(filename, &slm_status) == 0) + { //slm file exists + llstat dae_status; + if (LLFile::stat(mFilename, &dae_status) != 0 || + dae_status.st_mtime < slm_status.st_mtime) + { + if (loadFromSLM(filename)) + { //slm successfully loaded, if this fails, fall through and + //try loading from dae + + mLod = -1; //successfully loading from an slm implicitly sets all + //LoDs + return true; + } + } + } + } + } + + //no suitable slm exists, load from the .dae file DAE dae; domCOLLADA* dom = dae.open(mFilename); @@ -1744,6 +1784,91 @@ void LLModelLoader::setLoadState(U32 state) } } +bool LLModelLoader::loadFromSLM(const std::string& filename) +{ + //only need to populate mScene with data from slm + llstat stat; + + if (LLFile::stat(filename, &stat)) + { //file does not exist + return false; + } + + S32 file_size = (S32) stat.st_size; + + llifstream ifstream(filename, std::ifstream::in | std::ifstream::binary); + LLSD data; + LLSDSerialize::fromBinary(data, ifstream, file_size); + ifstream.close(); + + //build model list for each LoD + model_list model[LLModel::NUM_LODS]; + + LLSD& mesh = data["mesh"]; + + LLVolumeParams volume_params; + volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); + + for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) + { + for (U32 i = 0; i < mesh.size(); ++i) + { + std::stringstream str(mesh[i].asString()); + LLPointer loaded_model = new LLModel(volume_params, (F32) lod); + if (loaded_model->createVolumeFacesFromStream(str)) + { + loaded_model->mLocalID = i; + model[lod].push_back(loaded_model); + } + else + { + llassert(model[lod].empty()); + } + } + } + + if (model[LLModel::LOD_HIGH].empty()) + { //failed to load high lod + return false; + } + + //load instance list + model_instance_list instance_list; + + LLSD& instance = data["instance"]; + + for (U32 i = 0; i < instance.size(); ++i) + { + //deserialize instance list + instance_list.push_back(LLModelInstance(instance[i])); + + //match up model instance pointers + S32 idx = instance_list[i].mLocalMeshID; + + for (U32 lod = 0; lod < LLModel::NUM_LODS; ++lod) + { + if (!model[lod].empty()) + { + instance_list[i].mLOD[lod] = model[lod][idx]; + } + } + + instance_list[i].mModel = model[LLModel::LOD_HIGH][idx]; + } + + + //convert instance_list to mScene + mFirstTransform = TRUE; + for (U32 i = 0; i < instance_list.size(); ++i) + { + LLModelInstance& cur_instance = instance_list[i]; + mScene[cur_instance.mTransform].push_back(cur_instance); + stretch_extents(cur_instance.mModel, cur_instance.mTransform, mExtents[0], mExtents[1], mFirstTransform); + } + + return true; +} + void LLModelLoader::loadModelCallback() { if (mPreview) @@ -2614,6 +2739,7 @@ void LLModelPreview::saveUploadData(const std::string& filename, bool save_skinw decomp, empty_hull, save_skinweights, save_joint_positions); + data["mesh"][instance.mModel->mLocalID] = str.str(); } @@ -2626,8 +2752,6 @@ void LLModelPreview::saveUploadData(const std::string& filename, bool save_skinw out.close(); } - - void LLModelPreview::clearModel(S32 lod) { if (lod < 0 || lod > LLModel::LOD_PHYSICS) @@ -2769,39 +2893,93 @@ void LLModelPreview::loadModelCallback(S32 lod) } mModelLoader->loadTextures() ; - mModel[lod] = mModelLoader->mModelList; - mScene[lod] = mModelLoader->mScene; - mVertexBuffer[lod].clear(); - if (lod == LLModel::LOD_PHYSICS) - { - mPhysicsMesh.clear(); - } + if (lod == -1) + { //populate all LoDs from model loader scene + mBaseModel.clear(); + mBaseScene.clear(); - setPreviewLOD(lod); + for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) + { //for each LoD + //clear scene and model info + mScene[lod].clear(); + mModel[lod].clear(); + mVertexBuffer[lod].clear(); + + if (mModelLoader->mScene.begin()->second[0].mLOD[lod].notNull()) + { //if this LoD exists in the loaded scene - if (lod == LLModel::LOD_HIGH) - { //save a copy of the highest LOD for automatic LOD manipulation - if (mBaseModel.empty()) - { //first time we've loaded a model, auto-gen LoD - mGenLOD = true; + //copy scene to current LoD + mScene[lod] = mModelLoader->mScene; + + //touch up copied scene to look like current LoD + for (LLModelLoader::scene::iterator iter = mScene[lod].begin(); iter != mScene[lod].end(); ++iter) + { + LLModelLoader::model_instance_list& list = iter->second; + + for (LLModelLoader::model_instance_list::iterator list_iter = list.begin(); list_iter != list.end(); ++list_iter) + { + //override displayed model with current LoD + list_iter->mModel = list_iter->mLOD[lod]; + + //add current model to current LoD's model list (LLModel::mLocalID makes a good vector index) + S32 idx = list_iter->mModel->mLocalID; + + if (mModel[lod].size() <= idx) + { //stretch model list to fit model at given index + mModel[lod].resize(idx+1); + } + + mModel[lod][idx] = list_iter->mModel; + } + } + } } - mBaseModel = mModel[lod]; - clearGLODGroup(); + //copy high lod to base scene for LoD generation + mBaseScene = mScene[LLModel::LOD_HIGH]; + mBaseModel = mModel[LLModel::LOD_HIGH]; - mBaseScene = mScene[lod]; - mVertexBuffer[5].clear(); + mDirty = true; + resetPreviewTarget(); } + else + { //only replace given LoD + mModel[lod] = mModelLoader->mModelList; + mScene[lod] = mModelLoader->mScene; + mVertexBuffer[lod].clear(); - clearIncompatible(lod); + if (lod == LLModel::LOD_PHYSICS) + { + mPhysicsMesh.clear(); + } - mDirty = true; + setPreviewLOD(lod); - if (lod == LLModel::LOD_HIGH) - { - resetPreviewTarget(); + + if (lod == LLModel::LOD_HIGH) + { //save a copy of the highest LOD for automatic LOD manipulation + if (mBaseModel.empty()) + { //first time we've loaded a model, auto-gen LoD + mGenLOD = true; + } + + mBaseModel = mModel[lod]; + clearGLODGroup(); + + mBaseScene = mScene[lod]; + mVertexBuffer[5].clear(); + } + + clearIncompatible(lod); + + mDirty = true; + + if (lod == LLModel::LOD_HIGH) + { + resetPreviewTarget(); + } } mLoading = false; -- cgit v1.2.3 From e711e8af3d5f560fd93334d44eb7be1e01f02bec Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Wed, 23 Mar 2011 17:33:53 -0400 Subject: SH-1168 WIP: Disable SLM save if MeshImportUseSLM not set --- indra/newview/llfloatermodelpreview.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 6145c6c16d..10f53dab01 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -2704,6 +2704,11 @@ void LLModelPreview::saveUploadData(bool save_skinweights, bool save_joint_posit void LLModelPreview::saveUploadData(const std::string& filename, bool save_skinweights, bool save_joint_positions) { + if (!gSavedSettings.getBOOL("MeshImportUseSLM")) + { + return; + } + std::set > meshes; std::map mesh_binary; -- cgit v1.2.3 From d2bb490702921b5ca9fdcd562c67844e2d4802e1 Mon Sep 17 00:00:00 2001 From: prep Date: Thu, 24 Mar 2011 09:48:34 -0400 Subject: Crash fix for SH-1176 and WIP for pelvis z offset --- indra/newview/llfloatermodelpreview.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 6145c6c16d..2587ab69c3 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1873,8 +1873,7 @@ void LLModelLoader::loadModelCallback() { if (mPreview) { - mPreview->loadModelCallback(mLod); - mPreview->mModelLoader = NULL; + mPreview->loadModelCallback(mLod); } while (!isStopped()) @@ -2494,8 +2493,13 @@ U32 LLModelPreview::calcResourceCost() U32 num_hulls = 0; F32 debug_scale = mFMP ? mFMP->childGetValue("import_scale").asReal() : 1.f; - mPelvisZOffset = mFMP ? mFMP->childGetValue("pelvis_offset").asReal() : 32.0f; - + mPelvisZOffset = mFMP ? mFMP->childGetValue("pelvis_offset").asReal() : 8.0f; + + //if ( mFMP && mFMP->childGetValue("upload_joints").asBoolean() ) + //{ + // gAgentAvatarp->setPelvisOffset( mPelvisZOffset ); + //} + F32 streaming_cost = 0.f; F32 physics_cost = 0.f; for (U32 i = 0; i < mUploadData.size(); ++i) @@ -2990,8 +2994,12 @@ void LLModelPreview::loadModelCallback(S32 lod) void LLModelPreview::resetPreviewTarget() { - mPreviewTarget = (mModelLoader->mExtents[0] + mModelLoader->mExtents[1]) * 0.5f; - mPreviewScale = (mModelLoader->mExtents[1] - mModelLoader->mExtents[0]) * 0.5f; + if ( mModelLoader ) + { + mPreviewTarget = (mModelLoader->mExtents[0] + mModelLoader->mExtents[1]) * 0.5f; + mPreviewScale = (mModelLoader->mExtents[1] - mModelLoader->mExtents[0]) * 0.5f; + } + setPreviewTarget(mPreviewScale.magVec()*2.f); } -- cgit v1.2.3 From 3528753a3a5e2f569872c49cdf6154833f483245 Mon Sep 17 00:00:00 2001 From: Leyla Farazha Date: Fri, 25 Mar 2011 14:10:35 -0700 Subject: SH-1104 Add additional panel before review step. --- indra/newview/llfloatermodelpreview.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 2587ab69c3..254f9f8a5e 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -4518,9 +4518,12 @@ void LLModelPreview::setPreviewLOD(S32 lod) mFMP->childSetTextArg("lod_table_footer", "[DETAIL]", mFMP->getString(lod_name[mPreviewLOD])); mFMP->childSetText("lod_file", mLODFile[mPreviewLOD]); - // the wizard has two lod drop downs + // the wizard has three lod drop downs LLComboBox* combo_box2 = mFMP->getChild("preview_lod_combo2"); combo_box2->setCurrentByIndex((NUM_LOD-1)-mPreviewLOD); // combo box list of lods is in reverse order + + LLComboBox* combo_box3 = mFMP->getChild("preview_lod_combo3"); + combo_box2->setCurrentByIndex((NUM_LOD-1)-mPreviewLOD); // combo box list of lods is in reverse order LLColor4 highlight_color = LLUIColorTable::instance().getColor("MeshImportTableHighlightColor"); LLColor4 normal_color = LLUIColorTable::instance().getColor("MeshImportTableNormalColor"); -- cgit v1.2.3 From 115f05100387a8f57ddb99e578657994ca80e5e6 Mon Sep 17 00:00:00 2001 From: prep Date: Mon, 28 Mar 2011 11:12:14 -0400 Subject: WIP pelvis z offset can be adjusted between -3 to +3 --- indra/newview/llfloatermodelpreview.cpp | 9406 +++++++++++++++---------------- 1 file changed, 4702 insertions(+), 4704 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 254f9f8a5e..e440fa52d4 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1,4705 +1,4703 @@ -/** - * @file llfloatermodelpreview.cpp - * @brief LLFloaterModelPreview class implementation - * - * $LicenseInfo:firstyear=2004&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "dae.h" -//#include "dom.h" -#include "dom/domAsset.h" -#include "dom/domBind_material.h" -#include "dom/domCOLLADA.h" -#include "dom/domConstants.h" -#include "dom/domController.h" -#include "dom/domEffect.h" -#include "dom/domGeometry.h" -#include "dom/domInstance_geometry.h" -#include "dom/domInstance_material.h" -#include "dom/domInstance_node.h" -#include "dom/domInstance_effect.h" -#include "dom/domMaterial.h" -#include "dom/domMatrix.h" -#include "dom/domNode.h" -#include "dom/domProfile_COMMON.h" -#include "dom/domRotate.h" -#include "dom/domScale.h" -#include "dom/domTranslate.h" -#include "dom/domVisual_scene.h" - -#include "llfloatermodelpreview.h" - -#include "llfilepicker.h" -#include "llimagebmp.h" -#include "llimagetga.h" -#include "llimagejpeg.h" -#include "llimagepng.h" - -#include "llagent.h" -#include "llbutton.h" -#include "llcombobox.h" -#include "lldatapacker.h" -#include "lldrawable.h" -#include "lldrawpoolavatar.h" -#include "llrender.h" -#include "llface.h" -#include "lleconomy.h" -#include "llfocusmgr.h" -#include "llfloaterperms.h" -#include "lliconctrl.h" -#include "llmatrix4a.h" -#include "llmenubutton.h" -#include "llmeshrepository.h" -#include "llsdutil_math.h" -#include "lltextbox.h" -#include "lltoolmgr.h" -#include "llui.h" -#include "llvector4a.h" -#include "llviewercamera.h" -#include "llviewerwindow.h" -#include "llvoavatar.h" -#include "llvoavatarself.h" -#include "pipeline.h" -#include "lluictrlfactory.h" -#include "llviewercontrol.h" -#include "llviewermenu.h" -#include "llviewermenufile.h" -#include "llviewerregion.h" -#include "llviewertexturelist.h" -#include "llstring.h" -#include "llbutton.h" -#include "llcheckboxctrl.h" -#include "llradiogroup.h" -#include "llsdserialize.h" -#include "llsliderctrl.h" -#include "llspinctrl.h" -#include "lltoggleablemenu.h" -#include "llvfile.h" -#include "llvfs.h" -#include "llcallbacklist.h" - -#include "glod/glod.h" - -//static -S32 LLFloaterModelPreview::sUploadAmount = 10; -LLFloaterModelPreview* LLFloaterModelPreview::sInstance = NULL; - -const S32 PREVIEW_BORDER_WIDTH = 2; -const S32 PREVIEW_RESIZE_HANDLE_SIZE = S32(RESIZE_HANDLE_WIDTH * OO_SQRT2) + PREVIEW_BORDER_WIDTH; -const S32 PREVIEW_HPAD = PREVIEW_RESIZE_HANDLE_SIZE; -const S32 PREF_BUTTON_HEIGHT = 16 + 7 + 16; -const S32 PREVIEW_TEXTURE_HEIGHT = 300; - -void drawBoxOutline(const LLVector3& pos, const LLVector3& size); - - -std::string lod_name[NUM_LOD+1] = -{ - "lowest", - "low", - "medium", - "high", - "I went off the end of the lod_name array. Me so smart." -}; - -std::string lod_triangles_name[NUM_LOD+1] = -{ - "lowest_triangles", - "low_triangles", - "medium_triangles", - "high_triangles", - "I went off the end of the lod_triangles_name array. Me so smart." -}; - -std::string lod_vertices_name[NUM_LOD+1] = -{ - "lowest_vertices", - "low_vertices", - "medium_vertices", - "high_vertices", - "I went off the end of the lod_vertices_name array. Me so smart." -}; - -std::string lod_status_name[NUM_LOD+1] = -{ - "lowest_status", - "low_status", - "medium_status", - "high_status", - "I went off the end of the lod_status_name array. Me so smart." -}; - -std::string lod_icon_name[NUM_LOD+1] = -{ - "status_icon_lowest", - "status_icon_low", - "status_icon_medium", - "status_icon_high", - "I went off the end of the lod_status_name array. Me so smart." -}; - -std::string lod_status_image[NUM_LOD+1] = -{ - "ModelImport_Status_Good", - "ModelImport_Status_Warning", - "ModelImport_Status_Error", - "I went off the end of the lod_status_image array. Me so smart." -}; - -std::string lod_label_name[NUM_LOD+1] = -{ - "lowest_label", - "low_label", - "medium_label", - "high_label", - "I went off the end of the lod_label_name array. Me so smart." -}; - -bool validate_face(const LLVolumeFace& face) -{ - for (U32 i = 0; i < face.mNumIndices; ++i) - { - if (face.mIndices[i] >= face.mNumVertices) - { - llwarns << "Face has invalid index." << llendl; - return false; - } - } - - return true; -} - -bool validate_model(const LLModel* mdl) -{ - if (mdl->getNumVolumeFaces() == 0) - { - llwarns << "Model has no faces!" << llendl; - return false; - } - - for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) - { - if (mdl->getVolumeFace(i).mNumVertices == 0) - { - llwarns << "Face has no vertices." << llendl; - return false; - } - - if (mdl->getVolumeFace(i).mNumIndices == 0) - { - llwarns << "Face has no indices." << llendl; - return false; - } - - if (!validate_face(mdl->getVolumeFace(i))) - { - return false; - } - } - - return true; -} - -BOOL stop_gloderror() -{ - GLuint error = glodGetError(); - - if (error != GLOD_NO_ERROR) - { - llwarns << "GLOD error detected, cannot generate LOD: " << std::hex << error << llendl; - return TRUE; - } - - return FALSE; -} - - -LLMeshFilePicker::LLMeshFilePicker(LLModelPreview* mp, S32 lod) - : LLFilePickerThread(LLFilePicker::FFLOAD_COLLADA) - { - mMP = mp; - mLOD = lod; - } - -void LLMeshFilePicker::notify(const std::string& filename) -{ - mMP->loadModel(mFile, mLOD); -} - - -//----------------------------------------------------------------------------- -// LLFloaterModelPreview() -//----------------------------------------------------------------------------- -LLFloaterModelPreview::LLFloaterModelPreview(const LLSD& key) : -LLFloater(key) -{ - sInstance = this; - mLastMouseX = 0; - mLastMouseY = 0; - mGLName = 0; - mStatusLock = new LLMutex(NULL); - - mLODMode[LLModel::LOD_HIGH] = 0; - for (U32 i = 0; i < LLModel::LOD_HIGH; i++) - { - mLODMode[i] = 1; - } -} - -//----------------------------------------------------------------------------- -// postBuild() -//----------------------------------------------------------------------------- -BOOL LLFloaterModelPreview::postBuild() -{ - if (!LLFloater::postBuild()) - { - return FALSE; - } - - - - - - - childSetAction("lod_browse", onBrowseLOD, this); - - childSetCommitCallback("cancel_btn", onCancel, this); - childSetCommitCallback("crease_angle", onGenerateNormalsCommit, this); - childSetCommitCallback("generate_normals", onGenerateNormalsCommit, this); - - childSetCommitCallback("lod_generate", onAutoFillCommit, this); - - childSetCommitCallback("lod_mode", onLODParamCommit, this); - childSetCommitCallback("lod_error_threshold", onLODParamCommit, this); - childSetCommitCallback("lod_triangle_limit", onLODParamCommitTriangleLimit, this); - childSetCommitCallback("build_operator", onLODParamCommit, this); - childSetCommitCallback("queue_mode", onLODParamCommit, this); - childSetCommitCallback("border_mode", onLODParamCommit, this); - childSetCommitCallback("share_tolerance", onLODParamCommit, this); - - childSetTextArg("status", "[STATUS]", getString("status_idle")); - - //childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d",sUploadAmount)); - childSetAction("ok_btn", onUpload, this); - childDisable("ok_btn"); - - childSetAction("clear_materials", onClearMaterials, this); - - childSetCommitCallback("preview_lod_combo", onPreviewLODCommit, this); - - childSetCommitCallback("upload_skin", onUploadSkinCommit, this); - childSetCommitCallback("upload_joints", onUploadJointsCommit, this); - - childSetCommitCallback("import_scale", onImportScaleCommit, this); - childSetCommitCallback("pelvis_offset", onPelvisOffsetCommit, this); - - childSetCommitCallback("lod_file_or_limit", refresh, this); - childSetCommitCallback("physics_load_radio", refresh, this); - //childSetCommitCallback("physics_optimize", refresh, this); - //childSetCommitCallback("physics_use_hull", refresh, this); - - childDisable("upload_skin"); - childDisable("upload_joints"); - - childDisable("pelvis_offset"); - - childDisable("ok_btn"); - - mViewOptionMenuButton = getChild("options_gear_btn"); - - mCommitCallbackRegistrar.add("ModelImport.ViewOption.Action", boost::bind(&LLFloaterModelPreview::onViewOptionChecked, this, _2)); - mEnableCallbackRegistrar.add("ModelImport.ViewOption.Check", boost::bind(&LLFloaterModelPreview::isViewOptionChecked, this, _2)); - mEnableCallbackRegistrar.add("ModelImport.ViewOption.Enabled", boost::bind(&LLFloaterModelPreview::isViewOptionEnabled, this, _2)); - - - - mViewOptionMenu = LLUICtrlFactory::getInstance()->createFromFile("menu_model_import_gear_default.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); - mViewOptionMenuButton->setMenu(mViewOptionMenu, LLMenuButton::MP_BOTTOM_LEFT); - - initDecompControls(); - - LLView* preview_panel = getChild("preview_panel"); - - mPreviewRect = preview_panel->getRect(); - - mModelPreview = new LLModelPreview(512, 512, this); - mModelPreview->setPreviewTarget(16.f); - mModelPreview->setDetailsCallback(boost::bind(&LLFloaterModelPreview::setDetails, this, _1, _2, _3, _4, _5)); - - //set callbacks for left click on line editor rows - for (U32 i = 0; i <= LLModel::LOD_HIGH; i++) - { - LLTextBox* text = getChild(lod_label_name[i]); - if (text) - { - text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i)); - } - - text = getChild(lod_triangles_name[i]); - if (text) - { - text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i)); - } - - text = getChild(lod_vertices_name[i]); - if (text) - { - text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i)); - } - - text = getChild(lod_status_name[i]); - if (text) - { - text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i)); - } - } - - return TRUE; -} - -//----------------------------------------------------------------------------- -// LLFloaterModelPreview() -//----------------------------------------------------------------------------- -LLFloaterModelPreview::~LLFloaterModelPreview() -{ - sInstance = NULL; - - const LLModelLoader *model_loader = mModelPreview->mModelLoader; - if (model_loader && model_loader->mResetJoints) - { - gAgentAvatarp->resetJointPositions(); - } - - delete mModelPreview; - - if (mGLName) - { - LLImageGL::deleteTextures(1, &mGLName ); - } - - delete mStatusLock; - mStatusLock = NULL; -} - -void LLFloaterModelPreview::onViewOptionChecked(const LLSD& userdata) -{ - if (mModelPreview) - { - mModelPreview->mViewOption[userdata.asString()] = !mModelPreview->mViewOption[userdata.asString()]; - - mModelPreview->refresh(); - } -} - -bool LLFloaterModelPreview::isViewOptionChecked(const LLSD& userdata) -{ - if (mModelPreview) - { - return mModelPreview->mViewOption[userdata.asString()]; - } - - return false; -} - -bool LLFloaterModelPreview::isViewOptionEnabled(const LLSD& userdata) -{ - return !mViewOptionDisabled[userdata.asString()]; -} - -void LLFloaterModelPreview::setViewOptionEnabled(const std::string& option, bool enabled) -{ - mViewOptionDisabled[option] = !enabled; -} - -void LLFloaterModelPreview::enableViewOption(const std::string& option) -{ - setViewOptionEnabled(option, true); -} - -void LLFloaterModelPreview::disableViewOption(const std::string& option) -{ - setViewOptionEnabled(option, false); -} - -void LLFloaterModelPreview::loadModel(S32 lod) -{ - mModelPreview->mLoading = true; - - (new LLMeshFilePicker(mModelPreview, lod))->getFile(); -} - -//static -void LLFloaterModelPreview::onImportScaleCommit(LLUICtrl*,void* userdata) -{ - LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; - - if (!fp->mModelPreview) - { - return; - } - - fp->mModelPreview->calcResourceCost(); - fp->mModelPreview->refresh(); -} -//static -void LLFloaterModelPreview::onPelvisOffsetCommit( LLUICtrl*, void* userdata ) -{ - LLFloaterModelPreview *fp =(LLFloaterModelPreview*)userdata; - - if (!fp->mModelPreview) - { - return; - } - fp->mModelPreview->calcResourceCost(); - fp->mModelPreview->refresh(); -} - -//static -void LLFloaterModelPreview::onUploadJointsCommit(LLUICtrl*,void* userdata) -{ - LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; - - if (!fp->mModelPreview) - { - return; - } - - fp->mModelPreview->refresh(); -} - -//static -void LLFloaterModelPreview::onUploadSkinCommit(LLUICtrl*,void* userdata) -{ - LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; - - if (!fp->mModelPreview) - { - return; - } - - fp->mModelPreview->calcResourceCost(); - fp->mModelPreview->refresh(); - fp->mModelPreview->resetPreviewTarget(); - fp->mModelPreview->clearBuffers(); -} - -//static -void LLFloaterModelPreview::onPreviewLODCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; - - if (!fp->mModelPreview) - { - return; - } - - S32 which_mode = 0; - - LLComboBox* combo = (LLComboBox*) ctrl; - - which_mode = (NUM_LOD-1)-combo->getFirstSelectedIndex(); // combo box list of lods is in reverse order - - fp->mModelPreview->setPreviewLOD(which_mode); -} - -//static -void LLFloaterModelPreview::onGenerateNormalsCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; - - fp->mModelPreview->generateNormals(); -} - -//static -void LLFloaterModelPreview::onExplodeCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview* fp = LLFloaterModelPreview::sInstance; - - fp->mModelPreview->refresh(); -} - -//static -void LLFloaterModelPreview::onAutoFillCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; - - fp->mModelPreview->genLODs(); -} - -//static -void LLFloaterModelPreview::onLODParamCommit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; - fp->mModelPreview->onLODParamCommit(false); -} - -//static -void LLFloaterModelPreview::onLODParamCommitTriangleLimit(LLUICtrl* ctrl, void* userdata) -{ - LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; - fp->mModelPreview->onLODParamCommit(true); -} - - -//----------------------------------------------------------------------------- -// draw() -//----------------------------------------------------------------------------- -void LLFloaterModelPreview::draw() -{ - LLFloater::draw(); - LLRect r = getRect(); - - mModelPreview->update(); - - if (!mModelPreview->mLoading) - { - childSetTextArg("status", "[STATUS]", getString("status_idle")); - } - - childSetTextArg("prim_cost", "[PRIM_COST]", llformat("%d", mModelPreview->mResourceCost)); - childSetTextArg("description_label", "[TEXTURES]", llformat("%d", mModelPreview->mTextureSet.size())); - - if (!mCurRequest.empty()) - { - LLMutexLock lock(mStatusLock); - childSetTextArg("status", "[STATUS]", mStatusMessage); - } - else - { - childSetVisible("Simplify", true); - childSetVisible("simplify_cancel", false); - childSetVisible("Decompose", true); - childSetVisible("decompose_cancel", false); - } - - U32 resource_cost = mModelPreview->mResourceCost*10; - - if (childGetValue("upload_textures").asBoolean()) - { - resource_cost += mModelPreview->mTextureSet.size()*10; - } - - childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d", resource_cost)); - - if (mModelPreview) - { - gGL.color3f(1.f, 1.f, 1.f); - - gGL.getTexUnit(0)->bind(mModelPreview); - - - LLView* preview_panel = getChild("preview_panel"); - - LLRect rect = preview_panel->getRect(); - if (rect != mPreviewRect) - { - mModelPreview->refresh(); - mPreviewRect = preview_panel->getRect(); - } - - gGL.begin( LLRender::QUADS ); - { - gGL.texCoord2f(0.f, 1.f); - gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mTop-1); - gGL.texCoord2f(0.f, 0.f); - gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mBottom); - gGL.texCoord2f(1.f, 0.f); - gGL.vertex2i(mPreviewRect.mRight-1, mPreviewRect.mBottom); - gGL.texCoord2f(1.f, 1.f); - gGL.vertex2i(mPreviewRect.mRight-1, mPreviewRect.mTop-1); - } - gGL.end(); - - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - } -} - -//----------------------------------------------------------------------------- -// handleMouseDown() -//----------------------------------------------------------------------------- -BOOL LLFloaterModelPreview::handleMouseDown(S32 x, S32 y, MASK mask) -{ - if (mPreviewRect.pointInRect(x, y)) - { - bringToFront( x, y ); - gFocusMgr.setMouseCapture(this); - gViewerWindow->hideCursor(); - mLastMouseX = x; - mLastMouseY = y; - return TRUE; - } - - return LLFloater::handleMouseDown(x, y, mask); -} - -//----------------------------------------------------------------------------- -// handleMouseUp() -//----------------------------------------------------------------------------- -BOOL LLFloaterModelPreview::handleMouseUp(S32 x, S32 y, MASK mask) -{ - gFocusMgr.setMouseCapture(FALSE); - gViewerWindow->showCursor(); - return LLFloater::handleMouseUp(x, y, mask); -} - -//----------------------------------------------------------------------------- -// handleHover() -//----------------------------------------------------------------------------- -BOOL LLFloaterModelPreview::handleHover (S32 x, S32 y, MASK mask) -{ - MASK local_mask = mask & ~MASK_ALT; - - if (mModelPreview && hasMouseCapture()) - { - if (local_mask == MASK_PAN) - { - // pan here - mModelPreview->pan((F32)(x - mLastMouseX) * -0.005f, (F32)(y - mLastMouseY) * -0.005f); - } - else if (local_mask == MASK_ORBIT) - { - F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f; - F32 pitch_radians = (F32)(y - mLastMouseY) * 0.02f; - - mModelPreview->rotate(yaw_radians, pitch_radians); - } - else - { - - F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f; - F32 zoom_amt = (F32)(y - mLastMouseY) * 0.02f; - - mModelPreview->rotate(yaw_radians, 0.f); - mModelPreview->zoom(zoom_amt); - } - - - mModelPreview->refresh(); - - LLUI::setMousePositionLocal(this, mLastMouseX, mLastMouseY); - } - - if (!mPreviewRect.pointInRect(x, y) || !mModelPreview) - { - return LLFloater::handleHover(x, y, mask); - } - else if (local_mask == MASK_ORBIT) - { - gViewerWindow->setCursor(UI_CURSOR_TOOLCAMERA); - } - else if (local_mask == MASK_PAN) - { - gViewerWindow->setCursor(UI_CURSOR_TOOLPAN); - } - else - { - gViewerWindow->setCursor(UI_CURSOR_TOOLZOOMIN); - } - - return TRUE; -} - -//----------------------------------------------------------------------------- -// handleScrollWheel() -//----------------------------------------------------------------------------- -BOOL LLFloaterModelPreview::handleScrollWheel(S32 x, S32 y, S32 clicks) -{ - if (mPreviewRect.pointInRect(x, y) && mModelPreview) - { - mModelPreview->zoom((F32)clicks * -0.2f); - mModelPreview->refresh(); - } - - return TRUE; -} - -//static -void LLFloaterModelPreview::onPhysicsParamCommit(LLUICtrl* ctrl, void* data) -{ - if (LLConvexDecomposition::getInstance() == NULL) - { - llinfos << "convex decomposition tool is a stub on this platform. cannot get decomp." << llendl; - return; - } - - if (sInstance) - { - LLCDParam* param = (LLCDParam*) data; - std::string name(param->mName); - sInstance->mDecompParams[name] = ctrl->getValue(); - - if (name == "Simplify Method") - { - if (ctrl->getValue().asInteger() == 0) - { - sInstance->childSetVisible("Retain%", true); - sInstance->childSetVisible("Detail Scale", false); - } - else - { - sInstance->childSetVisible("Retain%", false); - sInstance->childSetVisible("Detail Scale", true); - } - } - } -} - -//static -void LLFloaterModelPreview::onPhysicsStageExecute(LLUICtrl* ctrl, void* data) -{ - LLCDStageData* stage_data = (LLCDStageData*) data; - std::string stage = stage_data->mName; - - if (sInstance) - { - if (!sInstance->mCurRequest.empty()) - { - llinfos << "Decomposition request still pending." << llendl; - return; - } - - if (sInstance->mModelPreview) - { - for (S32 i = 0; i < sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS].size(); ++i) - { - LLModel* mdl = sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS][i]; - DecompRequest* request = new DecompRequest(stage, mdl); - sInstance->mCurRequest.insert(request); - gMeshRepo.mDecompThread->submitRequest(request); - } - } - - if (stage == "Decompose") - { - sInstance->setStatusMessage(sInstance->getString("decomposing")); - sInstance->childSetVisible("Decompose", false); - sInstance->childSetVisible("decompose_cancel", true); - } - else if (stage == "Simplify") - { - sInstance->setStatusMessage(sInstance->getString("simplifying")); - sInstance->childSetVisible("Simplify", false); - sInstance->childSetVisible("simplify_cancel", true); - } - } -} - -//static -void LLFloaterModelPreview::onPhysicsBrowse(LLUICtrl* ctrl, void* userdata) -{ - sInstance->loadModel(LLModel::LOD_PHYSICS); -} - -//static -void LLFloaterModelPreview::onPhysicsUseLOD(LLUICtrl* ctrl, void* userdata) -{ - S32 which_mode = 3; - LLCtrlSelectionInterface* iface = sInstance->childGetSelectionInterface("physics_lod_combo"); - if (iface) - { - which_mode = iface->getFirstSelectedIndex(); - } - - sInstance->mModelPreview->setPhysicsFromLOD(which_mode); -} - -//static -void LLFloaterModelPreview::onCancel(LLUICtrl* ctrl, void* data) -{ - if (sInstance) - { - sInstance->closeFloater(false); - } -} - -//static -void LLFloaterModelPreview::onPhysicsStageCancel(LLUICtrl* ctrl, void*data) -{ - if (sInstance) - { - for (std::set >::iterator iter = sInstance->mCurRequest.begin(); - iter != sInstance->mCurRequest.end(); ++iter) - { - DecompRequest* req = *iter; - req->mContinue = 0; - } - - sInstance->mCurRequest.clear(); - } -} - -void LLFloaterModelPreview::initDecompControls() -{ - LLSD key; - - childSetCommitCallback("simplify_cancel", onPhysicsStageCancel, NULL); - childSetCommitCallback("decompose_cancel", onPhysicsStageCancel, NULL); - - childSetCommitCallback("physics_lod_combo", onPhysicsUseLOD, NULL); - childSetCommitCallback("physics_browse", onPhysicsBrowse, NULL); - - static const LLCDStageData* stage = NULL; - static S32 stage_count = 0; - - if (!stage && LLConvexDecomposition::getInstance() != NULL) - { - stage_count = LLConvexDecomposition::getInstance()->getStages(&stage); - } - - static const LLCDParam* param = NULL; - static S32 param_count = 0; - if (!param && LLConvexDecomposition::getInstance() != NULL) - { - param_count = LLConvexDecomposition::getInstance()->getParameters(¶m); - } - - for (S32 j = stage_count-1; j >= 0; --j) - { - LLButton* button = getChild(stage[j].mName); - if (button) - { - button->setCommitCallback(onPhysicsStageExecute, (void*) &stage[j]); - } - - gMeshRepo.mDecompThread->mStageID[stage[j].mName] = j; - // protected against stub by stage_count being 0 for stub above - LLConvexDecomposition::getInstance()->registerCallback(j, LLPhysicsDecomp::llcdCallback); - - //llinfos << "Physics decomp stage " << stage[j].mName << " (" << j << ") parameters:" << llendl; - //llinfos << "------------------------------------" << llendl; - - for (S32 i = 0; i < param_count; ++i) - { - if (param[i].mStage != j) - { - continue; - } - - std::string name(param[i].mName ? param[i].mName : ""); - std::string description(param[i].mDescription ? param[i].mDescription : ""); - - std::string type = "unknown"; - - llinfos << name << " - " << description << llendl; - - if (param[i].mType == LLCDParam::LLCD_FLOAT) - { - mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mFloat); - //llinfos << "Type: float, Default: " << param[i].mDefault.mFloat << llendl; - - LLSliderCtrl* slider = getChild(name); - if (slider) - { - slider->setMinValue(param[i].mDetails.mRange.mLow.mFloat); - slider->setMaxValue(param[i].mDetails.mRange.mHigh.mFloat); - slider->setIncrement(param[i].mDetails.mRange.mDelta.mFloat); - slider->setValue(param[i].mDefault.mFloat); - slider->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); - } - } - else if (param[i].mType == LLCDParam::LLCD_INTEGER) - { - mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue); - //llinfos << "Type: integer, Default: " << param[i].mDefault.mIntOrEnumValue << llendl; - - LLSliderCtrl* slider = getChild(name); - if (slider) - { - slider->setMinValue(param[i].mDetails.mRange.mLow.mIntOrEnumValue); - slider->setMaxValue(param[i].mDetails.mRange.mHigh.mIntOrEnumValue); - slider->setIncrement(param[i].mDetails.mRange.mDelta.mIntOrEnumValue); - slider->setValue(param[i].mDefault.mIntOrEnumValue); - slider->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); - } - } - else if (param[i].mType == LLCDParam::LLCD_BOOLEAN) - { - mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mBool); - //llinfos << "Type: boolean, Default: " << (param[i].mDefault.mBool ? "True" : "False") << llendl; - - LLCheckBoxCtrl* check_box = getChild(name); - if (check_box) - { - check_box->setValue(param[i].mDefault.mBool); - check_box->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); - } - } - else if (param[i].mType == LLCDParam::LLCD_ENUM) - { - mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue); - //llinfos << "Type: enum, Default: " << param[i].mDefault.mIntOrEnumValue << llendl; - - { //plug into combo box - - //llinfos << "Accepted values: " << llendl; - LLComboBox* combo_box = getChild(name); - for (S32 k = 0; k < param[i].mDetails.mEnumValues.mNumEnums; ++k) - { - //llinfos << param[i].mDetails.mEnumValues.mEnumsArray[k].mValue - // << " - " << param[i].mDetails.mEnumValues.mEnumsArray[k].mName << llendl; - - combo_box->add(param[i].mDetails.mEnumValues.mEnumsArray[k].mName, - LLSD::Integer(param[i].mDetails.mEnumValues.mEnumsArray[k].mValue)); - } - combo_box->setValue(param[i].mDefault.mIntOrEnumValue); - combo_box->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); - } - - //llinfos << "----" << llendl; - } - //llinfos << "-----------------------------" << llendl; - } - } - - childSetCommitCallback("physics_explode", LLFloaterModelPreview::onExplodeCommit, this); -} - -//----------------------------------------------------------------------------- -// onMouseCaptureLost() -//----------------------------------------------------------------------------- -// static -void LLFloaterModelPreview::onMouseCaptureLostModelPreview(LLMouseHandler* handler) -{ - gViewerWindow->showCursor(); -} - -//----------------------------------------------------------------------------- -// LLModelLoader -//----------------------------------------------------------------------------- -LLModelLoader::LLModelLoader(std::string filename, S32 lod, LLModelPreview* preview) -: LLThread("Model Loader"), mFilename(filename), mLod(lod), mPreview(preview), mFirstTransform(TRUE), mResetJoints( FALSE ) -{ - mJointMap["mPelvis"] = "mPelvis"; - mJointMap["mTorso"] = "mTorso"; - mJointMap["mChest"] = "mChest"; - mJointMap["mNeck"] = "mNeck"; - mJointMap["mHead"] = "mHead"; - mJointMap["mSkull"] = "mSkull"; - mJointMap["mEyeRight"] = "mEyeRight"; - mJointMap["mEyeLeft"] = "mEyeLeft"; - mJointMap["mCollarLeft"] = "mCollarLeft"; - mJointMap["mShoulderLeft"] = "mShoulderLeft"; - mJointMap["mElbowLeft"] = "mElbowLeft"; - mJointMap["mWristLeft"] = "mWristLeft"; - mJointMap["mCollarRight"] = "mCollarRight"; - mJointMap["mShoulderRight"] = "mShoulderRight"; - mJointMap["mElbowRight"] = "mElbowRight"; - mJointMap["mWristRight"] = "mWristRight"; - mJointMap["mHipRight"] = "mHipRight"; - mJointMap["mKneeRight"] = "mKneeRight"; - mJointMap["mAnkleRight"] = "mAnkleRight"; - mJointMap["mFootRight"] = "mFootRight"; - mJointMap["mToeRight"] = "mToeRight"; - mJointMap["mHipLeft"] = "mHipLeft"; - mJointMap["mKneeLeft"] = "mKneeLeft"; - mJointMap["mAnkleLeft"] = "mAnkleLeft"; - mJointMap["mFootLeft"] = "mFootLeft"; - mJointMap["mToeLeft"] = "mToeLeft"; - - mJointMap["avatar_mPelvis"] = "mPelvis"; - mJointMap["avatar_mTorso"] = "mTorso"; - mJointMap["avatar_mChest"] = "mChest"; - mJointMap["avatar_mNeck"] = "mNeck"; - mJointMap["avatar_mHead"] = "mHead"; - mJointMap["avatar_mSkull"] = "mSkull"; - mJointMap["avatar_mEyeRight"] = "mEyeRight"; - mJointMap["avatar_mEyeLeft"] = "mEyeLeft"; - mJointMap["avatar_mCollarLeft"] = "mCollarLeft"; - mJointMap["avatar_mShoulderLeft"] = "mShoulderLeft"; - mJointMap["avatar_mElbowLeft"] = "mElbowLeft"; - mJointMap["avatar_mWristLeft"] = "mWristLeft"; - mJointMap["avatar_mCollarRight"] = "mCollarRight"; - mJointMap["avatar_mShoulderRight"] = "mShoulderRight"; - mJointMap["avatar_mElbowRight"] = "mElbowRight"; - mJointMap["avatar_mWristRight"] = "mWristRight"; - mJointMap["avatar_mHipRight"] = "mHipRight"; - mJointMap["avatar_mKneeRight"] = "mKneeRight"; - mJointMap["avatar_mAnkleRight"] = "mAnkleRight"; - mJointMap["avatar_mFootRight"] = "mFootRight"; - mJointMap["avatar_mToeRight"] = "mToeRight"; - mJointMap["avatar_mHipLeft"] = "mHipLeft"; - mJointMap["avatar_mKneeLeft"] = "mKneeLeft"; - mJointMap["avatar_mAnkleLeft"] = "mAnkleLeft"; - mJointMap["avatar_mFootLeft"] = "mFootLeft"; - mJointMap["avatar_mToeLeft"] = "mToeLeft"; - - - mJointMap["hip"] = "mPelvis"; - mJointMap["abdomen"] = "mTorso"; - mJointMap["chest"] = "mChest"; - mJointMap["neck"] = "mNeck"; - mJointMap["head"] = "mHead"; - mJointMap["figureHair"] = "mSkull"; - mJointMap["lCollar"] = "mCollarLeft"; - mJointMap["lShldr"] = "mShoulderLeft"; - mJointMap["lForeArm"] = "mElbowLeft"; - mJointMap["lHand"] = "mWristLeft"; - mJointMap["rCollar"] = "mCollarRight"; - mJointMap["rShldr"] = "mShoulderRight"; - mJointMap["rForeArm"] = "mElbowRight"; - mJointMap["rHand"] = "mWristRight"; - mJointMap["rThigh"] = "mHipRight"; - mJointMap["rShin"] = "mKneeRight"; - mJointMap["rFoot"] = "mFootRight"; - mJointMap["lThigh"] = "mHipLeft"; - mJointMap["lShin"] = "mKneeLeft"; - mJointMap["lFoot"] = "mFootLeft"; - - //move into joint mapper class - mMasterJointList.push_front("mPelvis"); - mMasterJointList.push_front("mTorso"); - mMasterJointList.push_front("mChest"); - mMasterJointList.push_front("mNeck"); - mMasterJointList.push_front("mHead"); - mMasterJointList.push_front("mCollarLeft"); - mMasterJointList.push_front("mShoulderLeft"); - mMasterJointList.push_front("mElbowLeft"); - mMasterJointList.push_front("mWristLeft"); - mMasterJointList.push_front("mCollarRight"); - mMasterJointList.push_front("mShoulderRight"); - mMasterJointList.push_front("mElbowRight"); - mMasterJointList.push_front("mWristRight"); - mMasterJointList.push_front("mHipRight"); - mMasterJointList.push_front("mKneeRight"); - mMasterJointList.push_front("mFootRight"); - mMasterJointList.push_front("mHipLeft"); - mMasterJointList.push_front("mKneeLeft"); - mMasterJointList.push_front("mFootLeft"); - - if (mPreview) - { - //only try to load from slm if viewer is configured to do so and this is the - //initial model load (not an LoD or physics shape) - mTrySLM = gSavedSettings.getBOOL("MeshImportUseSLM") && mPreview->mBaseModel.empty(); - mPreview->setLoadState(STARTING); - } - else - { - mTrySLM = false; - } -} - -void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, BOOL& first_transform) -{ - LLVector4a box[] = - { - LLVector4a(-1, 1,-1), - LLVector4a(-1, 1, 1), - LLVector4a(-1,-1,-1), - LLVector4a(-1,-1, 1), - LLVector4a( 1, 1,-1), - LLVector4a( 1, 1, 1), - LLVector4a( 1,-1,-1), - LLVector4a( 1,-1, 1), - }; - - for (S32 j = 0; j < model->getNumVolumeFaces(); ++j) - { - const LLVolumeFace& face = model->getVolumeFace(j); - - LLVector4a center; - center.setAdd(face.mExtents[0], face.mExtents[1]); - center.mul(0.5f); - LLVector4a size; - size.setSub(face.mExtents[1],face.mExtents[0]); - size.mul(0.5f); - - for (U32 i = 0; i < 8; i++) - { - LLVector4a t; - t.setMul(size, box[i]); - t.add(center); - - LLVector4a v; - - mat.affineTransform(t, v); - - if (first_transform) - { - first_transform = FALSE; - min = max = v; - } - else - { - update_min_max(min, max, v); - } - } - } -} - -void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& max, BOOL& first_transform) -{ - LLVector4a mina, maxa; - LLMatrix4a mata; - - mata.loadu(mat); - mina.load3(min.mV); - maxa.load3(max.mV); - - stretch_extents(model, mata, mina, maxa, first_transform); - - min.set(mina.getF32ptr()); - max.set(maxa.getF32ptr()); -} - -void LLModelLoader::run() -{ - if (!doLoadModel()) - { - mPreview = NULL; - } - - doOnIdleOneTime(boost::bind(&LLModelLoader::loadModelCallback,this)); -} - -bool LLModelLoader::doLoadModel() -{ - //first, look for a .slm file of the same name that was modified later - //than the .dae - - if (mTrySLM) - { - std::string filename = mFilename; - - std::string::size_type i = filename.rfind("."); - if (i != std::string::npos) - { - filename.replace(i, filename.size()-1, ".slm"); - llstat slm_status; - if (LLFile::stat(filename, &slm_status) == 0) - { //slm file exists - llstat dae_status; - if (LLFile::stat(mFilename, &dae_status) != 0 || - dae_status.st_mtime < slm_status.st_mtime) - { - if (loadFromSLM(filename)) - { //slm successfully loaded, if this fails, fall through and - //try loading from dae - - mLod = -1; //successfully loading from an slm implicitly sets all - //LoDs - return true; - } - } - } - } - } - - //no suitable slm exists, load from the .dae file - DAE dae; - domCOLLADA* dom = dae.open(mFilename); - - if (!dom) - { - return false; - } - - daeDatabase* db = dae.getDatabase(); - - daeInt count = db->getElementCount(NULL, COLLADA_TYPE_MESH); - - daeDocument* doc = dae.getDoc(mFilename); - if (!doc) - { - llwarns << "can't find internal doc" << llendl; - return false; - } - - daeElement* root = doc->getDomRoot(); - if (!root) - { - llwarns << "document has no root" << llendl; - return false; - } - - //get unit scale - mTransform.setIdentity(); - - domAsset::domUnit* unit = daeSafeCast(root->getDescendant(daeElement::matchType(domAsset::domUnit::ID()))); - - if (unit) - { - F32 meter = unit->getMeter(); - mTransform.mMatrix[0][0] = meter; - mTransform.mMatrix[1][1] = meter; - mTransform.mMatrix[2][2] = meter; - } - - //get up axis rotation - LLMatrix4 rotation; - - domUpAxisType up = UPAXISTYPE_Y_UP; // default is Y_UP - domAsset::domUp_axis* up_axis = - daeSafeCast(root->getDescendant(daeElement::matchType(domAsset::domUp_axis::ID()))); - - if (up_axis) - { - up = up_axis->getValue(); - } - - if (up == UPAXISTYPE_X_UP) - { - rotation.initRotation(0.0f, 90.0f * DEG_TO_RAD, 0.0f); - } - else if (up == UPAXISTYPE_Y_UP) - { - rotation.initRotation(90.0f * DEG_TO_RAD, 0.0f, 0.0f); - } - - rotation *= mTransform; - mTransform = rotation; - - - for (daeInt idx = 0; idx < count; ++idx) - { //build map of domEntities to LLModel - domMesh* mesh = NULL; - db->getElement((daeElement**) &mesh, idx, NULL, COLLADA_TYPE_MESH); - - if (mesh) - { - LLPointer model = LLModel::loadModelFromDomMesh(mesh); - - if (model.notNull() && validate_model(model)) - { - mModelList.push_back(model); - mModel[mesh] = model; - } - } - } - - count = db->getElementCount(NULL, COLLADA_TYPE_SKIN); - for (daeInt idx = 0; idx < count; ++idx) - { //add skinned meshes as instances - domSkin* skin = NULL; - db->getElement((daeElement**) &skin, idx, NULL, COLLADA_TYPE_SKIN); - - if (skin) - { - domGeometry* geom = daeSafeCast(skin->getSource().getElement()); - - if (geom) - { - domMesh* mesh = geom->getMesh(); - if (mesh) - { - LLModel* model = mModel[mesh]; - if (model) - { - LLVector3 mesh_scale_vector; - LLVector3 mesh_translation_vector; - model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); - - LLMatrix4 normalized_transformation; - normalized_transformation.setTranslation(mesh_translation_vector); - - LLMatrix4 mesh_scale; - mesh_scale.initScale(mesh_scale_vector); - mesh_scale *= normalized_transformation; - normalized_transformation = mesh_scale; - - glh::matrix4f inv_mat((F32*) normalized_transformation.mMatrix); - inv_mat = inv_mat.inverse(); - LLMatrix4 inverse_normalized_transformation(inv_mat.m); - - domSkin::domBind_shape_matrix* bind_mat = skin->getBind_shape_matrix(); - - if (bind_mat) - { //get bind shape matrix - domFloat4x4& dom_value = bind_mat->getValue(); - - for (int i = 0; i < 4; i++) - { - for(int j = 0; j < 4; j++) - { - model->mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j*4]; - } - } - - LLMatrix4 trans = normalized_transformation; - trans *= model->mBindShapeMatrix; - model->mBindShapeMatrix = trans; - - } - - - //The joint transfom map that we'll populate below - std::map jointTransforms; - jointTransforms.clear(); - - //Some collada setup for accessing the skeleton - daeElement* pElement = 0; - dae.getDatabase()->getElement( &pElement, 0, 0, "skeleton" ); - - //Try to get at the skeletal instance controller - domInstance_controller::domSkeleton* pSkeleton = daeSafeCast( pElement ); - bool missingSkeletonOrScene = false; - - //If no skeleton, do a breadth-first search to get at specific joints - bool rootNode = false; - bool skeletonWithNoRootNode = false; - - //Need to test for a skeleton that does not have a root node - //This occurs when your instance controller does not have an associated scene - if ( pSkeleton ) - { - daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement(); - if ( pSkeletonRootNode ) - { - rootNode = true; - } - else - { - skeletonWithNoRootNode = true; - } - - } - if ( !pSkeleton || !rootNode ) - { - daeElement* pScene = root->getDescendant("visual_scene"); - if ( !pScene ) - { - llwarns<<"No visual scene - unable to parse bone offsets "< > children = pScene->getChildren(); - S32 childCount = children.getCount(); - - //Process any children that are joints - //Not all children are joints, some code be ambient lights, cameras, geometry etc.. - for (S32 i = 0; i < childCount; ++i) - { - domNode* pNode = daeSafeCast(children[i]); - if ( isNodeAJoint( pNode ) ) - { - processJointNode( pNode, jointTransforms ); - } - } - } - } - else - //Has Skeleton - { - //Get the root node of the skeleton - daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement(); - if ( pSkeletonRootNode ) - { - //Once we have the root node - start acccessing it's joint components - const int jointCnt = mJointMap.size(); - std::map :: const_iterator jointIt = mJointMap.begin(); - - //Loop over all the possible joints within the .dae - using the allowed joint list in the ctor. - for ( int i=0; i( resolver.getElement() ); - if ( pJoint ) - { - //Pull out the translate id and store it in the jointTranslations map - daeSIDResolver jointResolver( pJoint, "./translate" ); - domTranslate* pTranslate = daeSafeCast( jointResolver.getElement() ); - - LLMatrix4 workingTransform; - - //Translation via SID - if ( pTranslate ) - { - extractTranslation( pTranslate, workingTransform ); - } - else - { - //Translation via child from element - daeElement* pTranslateElement = getChildFromElement( pJoint, "translate" ); - if ( pTranslateElement && pTranslateElement->typeID() != domTranslate::ID() ) - { - llwarns<< "The found element is not a translate node" <getJoints(); - - domInputLocal_Array& joint_input = joints->getInput_array(); - - for (size_t i = 0; i < joint_input.getCount(); ++i) - { - domInputLocal* input = joint_input.get(i); - xsNMTOKEN semantic = input->getSemantic(); - - if (strcmp(semantic, COMMON_PROFILE_INPUT_JOINT) == 0) - { //found joint source, fill model->mJointMap and model->mJointList - daeElement* elem = input->getSource().getElement(); - - domSource* source = daeSafeCast(elem); - if (source) - { - - - domName_array* names_source = source->getName_array(); - - if (names_source) - { - domListOfNames &names = names_source->getValue(); - - for (size_t j = 0; j < names.getCount(); ++j) - { - std::string name(names.get(j)); - if (mJointMap.find(name) != mJointMap.end()) - { - name = mJointMap[name]; - } - model->mJointList.push_back(name); - model->mJointMap[name] = j; - } - } - else - { - domIDREF_array* names_source = source->getIDREF_array(); - if (names_source) - { - xsIDREFS& names = names_source->getValue(); - - for (size_t j = 0; j < names.getCount(); ++j) - { - std::string name(names.get(j).getID()); - if (mJointMap.find(name) != mJointMap.end()) - { - name = mJointMap[name]; - } - model->mJointList.push_back(name); - model->mJointMap[name] = j; - } - } - } - } - } - else if (strcmp(semantic, COMMON_PROFILE_INPUT_INV_BIND_MATRIX) == 0) - { //found inv_bind_matrix array, fill model->mInvBindMatrix - domSource* source = daeSafeCast(input->getSource().getElement()); - if (source) - { - domFloat_array* t = source->getFloat_array(); - if (t) - { - domListOfFloats& transform = t->getValue(); - S32 count = transform.getCount()/16; - - for (S32 k = 0; k < count; ++k) - { - LLMatrix4 mat; - - for (int i = 0; i < 4; i++) - { - for(int j = 0; j < 4; j++) - { - mat.mMatrix[i][j] = transform[k*16 + i + j*4]; - } - } - - model->mInvBindMatrix.push_back(mat); - } - } - } - } - } - - //Now that we've parsed the joint array, let's determine if we have a full rig - //(which means we have all the joints that are required for an avatar versus - //a skinned asset attached to a node in a file that contains an entire skeleton, - //but does not use the skeleton). - mPreview->setRigValid( doesJointArrayContainACompleteRig( model->mJointList ) ); - if ( !skeletonWithNoRootNode && !model->mJointList.empty() && mPreview->isRigValid() ) - { - mResetJoints = true; - } - - if ( !missingSkeletonOrScene ) - { - //Set the joint translations on the avatar - if it's a full mapping - //The joints are reset in the dtor - if ( mResetJoints ) - { - std::map :: const_iterator masterJointIt = mJointMap.begin(); - std::map :: const_iterator masterJointItEnd = mJointMap.end(); - for (;masterJointIt!=masterJointItEnd;++masterJointIt ) - { - std::string lookingForJoint = (*masterJointIt).first.c_str(); - - if ( jointTransforms.find( lookingForJoint ) != jointTransforms.end() ) - { - //llinfos<<"joint "<getJoint( lookingForJoint ); - if ( pJoint ) - { - pJoint->storeCurrentXform( jointTransform.getTranslation() ); - } - else - { - //Most likely an error in the asset. - llwarns<<"Tried to apply joint position from .dae, but it did not exist in the avatar rig." << llendl; - } - } - } - } - } //missingSkeletonOrScene - - //We need to construct the alternate bind matrix (which contains the new joint positions) - //in the same order as they were stored in the joint buffer. The joints associated - //with the skeleton are not stored in the same order as they are in the exported joint buffer. - //This remaps the skeletal joints to be in the same order as the joints stored in the model. - std::vector :: const_iterator jointIt = model->mJointList.begin(); - const int jointCnt = model->mJointList.size(); - for ( int i=0; imInvBindMatrix[i]; - newInverse.setTranslation( jointTransforms[lookingForJoint].getTranslation() ); - model->mAlternateBindMatrix.push_back( newInverse ); - } - else - { - llwarns<<"Possibly misnamed/missing joint [" <getVertices(); - if (verts) - { - domInputLocal_Array& inputs = verts->getInput_array(); - for (size_t i = 0; i < inputs.getCount() && model->mPosition.empty(); ++i) - { - if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_POSITION) == 0) - { - domSource* pos_source = daeSafeCast(inputs[i]->getSource().getElement()); - if (pos_source) - { - domFloat_array* pos_array = pos_source->getFloat_array(); - if (pos_array) - { - domListOfFloats& pos = pos_array->getValue(); - - for (size_t j = 0; j < pos.getCount(); j += 3) - { - if (pos.getCount() <= j+2) - { - llerrs << "WTF?" << llendl; - } - - LLVector3 v(pos[j], pos[j+1], pos[j+2]); - - //transform from COLLADA space to volume space - v = v * inverse_normalized_transformation; - - model->mPosition.push_back(v); - } - } - } - } - } - } - - //grab skin weights array - domSkin::domVertex_weights* weights = skin->getVertex_weights(); - if (weights) - { - domInputLocalOffset_Array& inputs = weights->getInput_array(); - domFloat_array* vertex_weights = NULL; - for (size_t i = 0; i < inputs.getCount(); ++i) - { - if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_WEIGHT) == 0) - { - domSource* weight_source = daeSafeCast(inputs[i]->getSource().getElement()); - if (weight_source) - { - vertex_weights = weight_source->getFloat_array(); - } - } - } - - if (vertex_weights) - { - domListOfFloats& w = vertex_weights->getValue(); - domListOfUInts& vcount = weights->getVcount()->getValue(); - domListOfInts& v = weights->getV()->getValue(); - - U32 c_idx = 0; - for (size_t vc_idx = 0; vc_idx < vcount.getCount(); ++vc_idx) - { //for each vertex - daeUInt count = vcount[vc_idx]; - - //create list of weights that influence this vertex - LLModel::weight_list weight_list; - - for (daeUInt i = 0; i < count; ++i) - { //for each weight - daeInt joint_idx = v[c_idx++]; - daeInt weight_idx = v[c_idx++]; - - if (joint_idx == -1) - { - //ignore bindings to bind_shape_matrix - continue; - } - - F32 weight_value = w[weight_idx]; - - weight_list.push_back(LLModel::JointWeight(joint_idx, weight_value)); - } - - //sort by joint weight - std::sort(weight_list.begin(), weight_list.end(), LLModel::CompareWeightGreater()); - - std::vector wght; - - F32 total = 0.f; - - for (U32 i = 0; i < llmin((U32) 4, (U32) weight_list.size()); ++i) - { //take up to 4 most significant weights - if (weight_list[i].mWeight > 0.f) - { - wght.push_back( weight_list[i] ); - total += weight_list[i].mWeight; - } - } - - F32 scale = 1.f/total; - if (scale != 1.f) - { //normalize weights - for (U32 i = 0; i < wght.size(); ++i) - { - wght[i].mWeight *= scale; - } - } - - model->mSkinWeights[model->mPosition[vc_idx]] = wght; - } - - //add instance to scene for this model - - LLMatrix4 transformation = mTransform; - // adjust the transformation to compensate for mesh normalization - - LLMatrix4 mesh_translation; - mesh_translation.setTranslation(mesh_translation_vector); - mesh_translation *= transformation; - transformation = mesh_translation; - - LLMatrix4 mesh_scale; - mesh_scale.initScale(mesh_scale_vector); - mesh_scale *= transformation; - transformation = mesh_scale; - - std::vector materials; - materials.resize(model->getNumVolumeFaces()); - mScene[transformation].push_back(LLModelInstance(model, model->mLabel, transformation, materials)); - stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); - } - } - } - } - } - } - } - - daeElement* scene = root->getDescendant("visual_scene"); - - if (!scene) - { - llwarns << "document has no visual_scene" << llendl; - setLoadState( ERROR_PARSING ); - return false; - } - setLoadState( DONE ); - - processElement(scene); - - handlePivotPoint( root ); - - return true; -} - -void LLModelLoader::setLoadState(U32 state) -{ - if (mPreview) - { - mPreview->setLoadState(state); - } -} - -bool LLModelLoader::loadFromSLM(const std::string& filename) -{ - //only need to populate mScene with data from slm - llstat stat; - - if (LLFile::stat(filename, &stat)) - { //file does not exist - return false; - } - - S32 file_size = (S32) stat.st_size; - - llifstream ifstream(filename, std::ifstream::in | std::ifstream::binary); - LLSD data; - LLSDSerialize::fromBinary(data, ifstream, file_size); - ifstream.close(); - - //build model list for each LoD - model_list model[LLModel::NUM_LODS]; - - LLSD& mesh = data["mesh"]; - - LLVolumeParams volume_params; - volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); - - for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) - { - for (U32 i = 0; i < mesh.size(); ++i) - { - std::stringstream str(mesh[i].asString()); - LLPointer loaded_model = new LLModel(volume_params, (F32) lod); - if (loaded_model->createVolumeFacesFromStream(str)) - { - loaded_model->mLocalID = i; - model[lod].push_back(loaded_model); - } - else - { - llassert(model[lod].empty()); - } - } - } - - if (model[LLModel::LOD_HIGH].empty()) - { //failed to load high lod - return false; - } - - //load instance list - model_instance_list instance_list; - - LLSD& instance = data["instance"]; - - for (U32 i = 0; i < instance.size(); ++i) - { - //deserialize instance list - instance_list.push_back(LLModelInstance(instance[i])); - - //match up model instance pointers - S32 idx = instance_list[i].mLocalMeshID; - - for (U32 lod = 0; lod < LLModel::NUM_LODS; ++lod) - { - if (!model[lod].empty()) - { - instance_list[i].mLOD[lod] = model[lod][idx]; - } - } - - instance_list[i].mModel = model[LLModel::LOD_HIGH][idx]; - } - - - //convert instance_list to mScene - mFirstTransform = TRUE; - for (U32 i = 0; i < instance_list.size(); ++i) - { - LLModelInstance& cur_instance = instance_list[i]; - mScene[cur_instance.mTransform].push_back(cur_instance); - stretch_extents(cur_instance.mModel, cur_instance.mTransform, mExtents[0], mExtents[1], mFirstTransform); - } - - return true; -} - -void LLModelLoader::loadModelCallback() -{ - if (mPreview) - { - mPreview->loadModelCallback(mLod); - } - - while (!isStopped()) - { //wait until this thread is stopped before deleting self - apr_sleep(100); - } - - delete this; -} - -void LLModelLoader::handlePivotPoint( daeElement* pRoot ) -{ - //Import an optional pivot point - a pivot point is just a node in the visual scene named "AssetPivot" - //If no assetpivot is found then the asset will use the SL default - daeElement* pScene = pRoot->getDescendant("visual_scene"); - if ( pScene ) - { - daeTArray< daeSmartRef > children = pScene->getChildren(); - S32 childCount = children.getCount(); - for (S32 i = 0; i < childCount; ++i) - { - domNode* pNode = daeSafeCast(children[i]); - if ( pNode && isNodeAPivotPoint( pNode ) ) - { - LLMatrix4 workingTransform; - daeSIDResolver nodeResolver( pNode, "./translate" ); - domTranslate* pTranslate = daeSafeCast( nodeResolver.getElement() ); - //Translation via SID was successful - //todo#extract via element as well - if ( pTranslate ) - { - extractTranslation( pTranslate, workingTransform ); - mPreview->setModelPivot( workingTransform.getTranslation() ); - mPreview->setHasPivot( true ); - } - } - } - } -} - -bool LLModelLoader::doesJointArrayContainACompleteRig( const std::vector &jointListFromModel ) -{ - std::deque :: const_iterator masterJointIt = mMasterJointList.begin(); - std::deque :: const_iterator masterJointEndIt = mMasterJointList.end(); - - std::vector :: const_iterator modelJointIt = jointListFromModel.begin(); - std::vector :: const_iterator modelJointItEnd = jointListFromModel.end(); - - bool found = false; - for ( ;masterJointIt!=masterJointEndIt;++masterJointIt ) - { - found = false; - modelJointIt = jointListFromModel.begin(); - for ( ;modelJointIt!=modelJointItEnd; ++modelJointIt ) - { - if ( *masterJointIt == *modelJointIt ) - { - found = true; - break; - } - } - if ( !found ) - { - llinfos<<" Asset did not contain the joint (if you're u/l a fully rigged asset - it is required)." << *masterJointIt<< llendl; - break; - } - } - - return found; -} - -//called in the main thread -void LLModelLoader::loadTextures() -{ - BOOL is_paused = isPaused() ; - pause() ; //pause the loader - - for(scene::iterator iter = mScene.begin(); iter != mScene.end(); ++iter) - { - for(U32 i = 0 ; i < iter->second.size(); i++) - { - for(U32 j = 0 ; j < iter->second[i].mMaterial.size() ; j++) - { - if(!iter->second[i].mMaterial[j].mDiffuseMapFilename.empty()) - { - iter->second[i].mMaterial[j].mDiffuseMap = - LLViewerTextureManager::getFetchedTextureFromUrl("file://" + iter->second[i].mMaterial[j].mDiffuseMapFilename, TRUE, LLViewerTexture::BOOST_PREVIEW); - iter->second[i].mMaterial[j].mDiffuseMap->setLoadedCallback(LLModelPreview::textureLoadedCallback, 0, TRUE, FALSE, mPreview, NULL, FALSE); - iter->second[i].mMaterial[j].mDiffuseMap->forceToSaveRawImage(); - } - } - } - } - - if(!is_paused) - { - unpause() ; - } -} - -bool LLModelLoader::isNodeAJoint( domNode* pNode ) -{ - if ( pNode->getName() == NULL) - { - return false; - } - - if ( mJointMap.find( pNode->getName() ) != mJointMap.end() ) - { - return true; - } - - return false; -} - -bool LLModelLoader::isNodeAPivotPoint( domNode* pNode ) -{ - bool result = false; - - if ( pNode && pNode->getName() ) - { - std::string name = pNode->getName(); - if ( name == "AssetPivot" ) - { - result = true; - } - else - { - result = false; - } - } - return result; -} - -void LLModelLoader::extractTranslation( domTranslate* pTranslate, LLMatrix4& transform ) -{ - domFloat3 jointTrans = pTranslate->getValue(); - LLVector3 singleJointTranslation( jointTrans[0], jointTrans[1], jointTrans[2] ); - transform.setTranslation( singleJointTranslation ); -} - -void LLModelLoader::extractTranslationViaElement( daeElement* pTranslateElement, LLMatrix4& transform ) -{ - domTranslate* pTranslateChild = dynamic_cast( pTranslateElement ); - domFloat3 translateChild = pTranslateChild->getValue(); - LLVector3 singleJointTranslation( translateChild[0], translateChild[1], translateChild[2] ); - transform.setTranslation( singleJointTranslation ); -} - -void LLModelLoader::processJointNode( domNode* pNode, std::map& jointTransforms ) -{ - if (pNode->getName() == NULL) - { - llwarns << "nameless node, can't process" << llendl; - return; - } - - //llwarns<<"ProcessJointNode# Node:" <getName()<( jointResolver.getElement() ); - - //Translation via SID was successful - if ( pTranslate ) - { - extractTranslation( pTranslate, workingTransform ); - } - else - { - //Translation via child from element - daeElement* pTranslateElement = getChildFromElement( pNode, "translate" ); - if ( !pTranslateElement || pTranslateElement->typeID() != domTranslate::ID() ) - { - //llwarns<< "The found element is not a translate node" <( jointResolver.getElement() ); - if ( pMatrix ) - { - //llinfos<<"A matrix SID was however found!"<getValue(); - for ( int i = 0; i < 4; i++ ) - { - for( int j = 0; j < 4; j++ ) - { - workingTransform.mMatrix[i][j] = domArray[i + j*4]; - } - } - } - else - { - llwarns<< "The found element is not translate or matrix node - most likely a corrupt export!" <getName() ] = workingTransform; - - //2. handle the nodes children - - //Gather and handle the incoming nodes children - daeTArray< daeSmartRef > childOfChild = pNode->getChildren(); - S32 childOfChildCount = childOfChild.getCount(); - - for (S32 i = 0; i < childOfChildCount; ++i) - { - domNode* pChildNode = daeSafeCast( childOfChild[i] ); - if ( pChildNode ) - { - processJointNode( pChildNode, jointTransforms ); - } - } -} - -daeElement* LLModelLoader::getChildFromElement( daeElement* pElement, std::string const & name ) -{ - daeElement* pChildOfElement = pElement->getChild( name.c_str() ); - if ( pChildOfElement ) - { - return pChildOfElement; - } - llwarns<< "Could not find a child [" << name << "] for the element: \"" << pElement->getAttribute("id") << "\"" << llendl; - return NULL; -} - -void LLModelLoader::processElement(daeElement* element) -{ - LLMatrix4 saved_transform = mTransform; - - domTranslate* translate = daeSafeCast(element); - if (translate) - { - domFloat3 dom_value = translate->getValue(); - - LLMatrix4 translation; - translation.setTranslation(LLVector3(dom_value[0], dom_value[1], dom_value[2])); - - translation *= mTransform; - mTransform = translation; - } - - domRotate* rotate = daeSafeCast(element); - if (rotate) - { - domFloat4 dom_value = rotate->getValue(); - - LLMatrix4 rotation; - rotation.initRotTrans(dom_value[3] * DEG_TO_RAD, LLVector3(dom_value[0], dom_value[1], dom_value[2]), LLVector3(0, 0, 0)); - - rotation *= mTransform; - mTransform = rotation; - } - - domScale* scale = daeSafeCast(element); - if (scale) - { - domFloat3 dom_value = scale->getValue(); - - LLMatrix4 scaling; - scaling.initScale(LLVector3(dom_value[0], dom_value[1], dom_value[2])); - - scaling *= mTransform; - mTransform = scaling; - } - - domMatrix* matrix = daeSafeCast(element); - if (matrix) - { - domFloat4x4 dom_value = matrix->getValue(); - - LLMatrix4 matrix_transform; - - for (int i = 0; i < 4; i++) - { - for(int j = 0; j < 4; j++) - { - matrix_transform.mMatrix[i][j] = dom_value[i + j*4]; - } - } - - matrix_transform *= mTransform; - mTransform = matrix_transform; - } - - domInstance_geometry* instance_geo = daeSafeCast(element); - if (instance_geo) - { - domGeometry* geo = daeSafeCast(instance_geo->getUrl().getElement()); - if (geo) - { - domMesh* mesh = daeSafeCast(geo->getDescendant(daeElement::matchType(domMesh::ID()))); - if (mesh) - { - LLModel* model = mModel[mesh]; - if (model) - { - LLMatrix4 transformation = mTransform; - - std::vector materials = getMaterials(model, instance_geo); - - // adjust the transformation to compensate for mesh normalization - LLVector3 mesh_scale_vector; - LLVector3 mesh_translation_vector; - model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); - - LLMatrix4 mesh_translation; - mesh_translation.setTranslation(mesh_translation_vector); - mesh_translation *= transformation; - transformation = mesh_translation; - - LLMatrix4 mesh_scale; - mesh_scale.initScale(mesh_scale_vector); - mesh_scale *= transformation; - transformation = mesh_scale; - - std::string label = getElementLabel(instance_geo); - mScene[transformation].push_back(LLModelInstance(model, label, transformation, materials)); - - stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); - } - } - } - } - - domInstance_node* instance_node = daeSafeCast(element); - if (instance_node) - { - daeElement* instance = instance_node->getUrl().getElement(); - if (instance) - { - processElement(instance); - } - } - - //process children - daeTArray< daeSmartRef > children = element->getChildren(); - for (S32 i = 0; i < children.getCount(); i++) - { - processElement(children[i]); - } - - domNode* node = daeSafeCast(element); - if (node) - { //this element was a node, restore transform before processiing siblings - mTransform = saved_transform; - } -} - -std::vector LLModelLoader::getMaterials(LLModel* model, domInstance_geometry* instance_geo) -{ - std::vector materials; - for (int i = 0; i < model->mMaterialList.size(); i++) - { - LLImportMaterial import_material; - - domInstance_material* instance_mat = NULL; - - domBind_material::domTechnique_common* technique = - daeSafeCast(instance_geo->getDescendant(daeElement::matchType(domBind_material::domTechnique_common::ID()))); - - if (technique) - { - daeTArray< daeSmartRef > inst_materials = technique->getChildrenByType(); - for (int j = 0; j < inst_materials.getCount(); j++) - { - std::string symbol(inst_materials[j]->getSymbol()); - - if (symbol == model->mMaterialList[i]) // found the binding - { - instance_mat = inst_materials[j]; - } - } - } - - if (instance_mat) - { - domMaterial* material = daeSafeCast(instance_mat->getTarget().getElement()); - if (material) - { - domInstance_effect* instance_effect = - daeSafeCast(material->getDescendant(daeElement::matchType(domInstance_effect::ID()))); - if (instance_effect) - { - domEffect* effect = daeSafeCast(instance_effect->getUrl().getElement()); - if (effect) - { - domProfile_COMMON* profile = - daeSafeCast(effect->getDescendant(daeElement::matchType(domProfile_COMMON::ID()))); - if (profile) - { - import_material = profileToMaterial(profile); - } - } - } - } - } - - materials.push_back(import_material); - } - - return materials; -} - -LLImportMaterial LLModelLoader::profileToMaterial(domProfile_COMMON* material) -{ - LLImportMaterial mat; - mat.mFullbright = FALSE; - - daeElement* diffuse = material->getDescendant("diffuse"); - if (diffuse) - { - domCommon_color_or_texture_type_complexType::domTexture* texture = - daeSafeCast(diffuse->getDescendant("texture")); - if (texture) - { - domCommon_newparam_type_Array newparams = material->getNewparam_array(); - for (S32 i = 0; i < newparams.getCount(); i++) - { - domFx_surface_common* surface = newparams[i]->getSurface(); - if (surface) - { - domFx_surface_init_common* init = surface->getFx_surface_init_common(); - if (init) - { - domFx_surface_init_from_common_Array init_from = init->getInit_from_array(); - - if (init_from.getCount() > i) - { - domImage* image = daeSafeCast(init_from[i]->getValue().getElement()); - if (image) - { - // we only support init_from now - embedded data will come later - domImage::domInit_from* init = image->getInit_from(); - if (init) - { - mat.mDiffuseMapFilename = cdom::uriToNativePath(init->getValue().str()); - mat.mDiffuseMapLabel = getElementLabel(material); - } - } - } - } - } - } - } - - domCommon_color_or_texture_type_complexType::domColor* color = - daeSafeCast(diffuse->getDescendant("color")); - if (color) - { - domFx_color_common domfx_color = color->getValue(); - LLColor4 value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]); - mat.mDiffuseColor = value; - } - } - - daeElement* emission = material->getDescendant("emission"); - if (emission) - { - LLColor4 emission_color = getDaeColor(emission); - if (((emission_color[0] + emission_color[1] + emission_color[2]) / 3.0) > 0.25) - { - mat.mFullbright = TRUE; - } - } - - return mat; -} - -// try to get a decent label for this element -std::string LLModelLoader::getElementLabel(daeElement *element) -{ - // if we have a name attribute, use it - std::string name = element->getAttribute("name"); - if (name.length()) - { - return name; - } - - // if we have an ID attribute, use it - if (element->getID()) - { - return std::string(element->getID()); - } - - // if we have a parent, use it - daeElement* parent = element->getParent(); - if (parent) - { - // if parent has a name, use it - std::string name = parent->getAttribute("name"); - if (name.length()) - { - return name; - } - - // if parent has an ID, use it - if (parent->getID()) - { - return std::string(parent->getID()); - } - } - - // try to use our type - daeString element_name = element->getElementName(); - if (element_name) - { - return std::string(element_name); - } - - // if all else fails, use "object" - return std::string("object"); -} - -LLColor4 LLModelLoader::getDaeColor(daeElement* element) -{ - LLColor4 value; - domCommon_color_or_texture_type_complexType::domColor* color = - daeSafeCast(element->getDescendant("color")); - if (color) - { - domFx_color_common domfx_color = color->getValue(); - value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]); - } - - return value; -} - -//----------------------------------------------------------------------------- -// LLModelPreview -//----------------------------------------------------------------------------- - -LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) -: LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE), LLMutex(NULL) -, mPelvisZOffset( 0.0f ) -, mRigValid( false ) -{ - mNeedsUpdate = TRUE; - mCameraDistance = 0.f; - mCameraYaw = 0.f; - mCameraPitch = 0.f; - mCameraZoom = 1.f; - mTextureName = 0; - mPreviewLOD = 0; - mModelLoader = NULL; - mMaxTriangleLimit = 0; - mDirty = false; - mGenLOD = false; - mLoading = false; - mLoadState = LLModelLoader::STARTING; - mGroup = 0; - mBuildShareTolerance = 0.f; - mBuildQueueMode = GLOD_QUEUE_GREEDY; - mBuildBorderMode = GLOD_BORDER_UNLOCK; - mBuildOperator = GLOD_OPERATOR_EDGE_COLLAPSE; - - for (U32 i = 0; i < LLModel::NUM_LODS; ++i) - { - mRequestedTriangleCount[i] = 0; - } - - mViewOption["show_textures"] = false; - - mFMP = fmp; - - mHasPivot = false; - mModelPivot = LLVector3( 0.0f, 0.0f, 0.0f ); - - glodInit(); -} - -LLModelPreview::~LLModelPreview() -{ - if (mModelLoader) - { - mModelLoader->mPreview = NULL; - } - //*HACK : *TODO : turn this back on when we understand why this crashes - //glodShutdown(); -} - -U32 LLModelPreview::calcResourceCost() -{ - assert_main_thread(); - - rebuildUploadData(); - - if (mFMP && mModelLoader) - { - if ( getLoadState() != LLModelLoader::ERROR_PARSING ) - { - mFMP->childEnable("ok_btn"); - } - } - - //Upload skin is selected BUT the joints coming in from the asset - //were malformed. - if ( mFMP && mFMP->childGetValue("upload_skin").asBoolean() ) - { - if ( !isRigValid() ) - { - mFMP->childDisable("ok_btn"); - } - } - - U32 cost = 0; - std::set accounted; - U32 num_points = 0; - U32 num_hulls = 0; - - F32 debug_scale = mFMP ? mFMP->childGetValue("import_scale").asReal() : 1.f; - mPelvisZOffset = mFMP ? mFMP->childGetValue("pelvis_offset").asReal() : 8.0f; +/** + * @file llfloatermodelpreview.cpp + * @brief LLFloaterModelPreview class implementation + * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "dae.h" +//#include "dom.h" +#include "dom/domAsset.h" +#include "dom/domBind_material.h" +#include "dom/domCOLLADA.h" +#include "dom/domConstants.h" +#include "dom/domController.h" +#include "dom/domEffect.h" +#include "dom/domGeometry.h" +#include "dom/domInstance_geometry.h" +#include "dom/domInstance_material.h" +#include "dom/domInstance_node.h" +#include "dom/domInstance_effect.h" +#include "dom/domMaterial.h" +#include "dom/domMatrix.h" +#include "dom/domNode.h" +#include "dom/domProfile_COMMON.h" +#include "dom/domRotate.h" +#include "dom/domScale.h" +#include "dom/domTranslate.h" +#include "dom/domVisual_scene.h" + +#include "llfloatermodelpreview.h" + +#include "llfilepicker.h" +#include "llimagebmp.h" +#include "llimagetga.h" +#include "llimagejpeg.h" +#include "llimagepng.h" + +#include "llagent.h" +#include "llbutton.h" +#include "llcombobox.h" +#include "lldatapacker.h" +#include "lldrawable.h" +#include "lldrawpoolavatar.h" +#include "llrender.h" +#include "llface.h" +#include "lleconomy.h" +#include "llfocusmgr.h" +#include "llfloaterperms.h" +#include "lliconctrl.h" +#include "llmatrix4a.h" +#include "llmenubutton.h" +#include "llmeshrepository.h" +#include "llsdutil_math.h" +#include "lltextbox.h" +#include "lltoolmgr.h" +#include "llui.h" +#include "llvector4a.h" +#include "llviewercamera.h" +#include "llviewerwindow.h" +#include "llvoavatar.h" +#include "llvoavatarself.h" +#include "pipeline.h" +#include "lluictrlfactory.h" +#include "llviewercontrol.h" +#include "llviewermenu.h" +#include "llviewermenufile.h" +#include "llviewerregion.h" +#include "llviewertexturelist.h" +#include "llstring.h" +#include "llbutton.h" +#include "llcheckboxctrl.h" +#include "llradiogroup.h" +#include "llsdserialize.h" +#include "llsliderctrl.h" +#include "llspinctrl.h" +#include "lltoggleablemenu.h" +#include "llvfile.h" +#include "llvfs.h" +#include "llcallbacklist.h" + +#include "glod/glod.h" + +//static +S32 LLFloaterModelPreview::sUploadAmount = 10; +LLFloaterModelPreview* LLFloaterModelPreview::sInstance = NULL; + +const S32 PREVIEW_BORDER_WIDTH = 2; +const S32 PREVIEW_RESIZE_HANDLE_SIZE = S32(RESIZE_HANDLE_WIDTH * OO_SQRT2) + PREVIEW_BORDER_WIDTH; +const S32 PREVIEW_HPAD = PREVIEW_RESIZE_HANDLE_SIZE; +const S32 PREF_BUTTON_HEIGHT = 16 + 7 + 16; +const S32 PREVIEW_TEXTURE_HEIGHT = 300; + +void drawBoxOutline(const LLVector3& pos, const LLVector3& size); + + +std::string lod_name[NUM_LOD+1] = +{ + "lowest", + "low", + "medium", + "high", + "I went off the end of the lod_name array. Me so smart." +}; + +std::string lod_triangles_name[NUM_LOD+1] = +{ + "lowest_triangles", + "low_triangles", + "medium_triangles", + "high_triangles", + "I went off the end of the lod_triangles_name array. Me so smart." +}; + +std::string lod_vertices_name[NUM_LOD+1] = +{ + "lowest_vertices", + "low_vertices", + "medium_vertices", + "high_vertices", + "I went off the end of the lod_vertices_name array. Me so smart." +}; + +std::string lod_status_name[NUM_LOD+1] = +{ + "lowest_status", + "low_status", + "medium_status", + "high_status", + "I went off the end of the lod_status_name array. Me so smart." +}; + +std::string lod_icon_name[NUM_LOD+1] = +{ + "status_icon_lowest", + "status_icon_low", + "status_icon_medium", + "status_icon_high", + "I went off the end of the lod_status_name array. Me so smart." +}; + +std::string lod_status_image[NUM_LOD+1] = +{ + "ModelImport_Status_Good", + "ModelImport_Status_Warning", + "ModelImport_Status_Error", + "I went off the end of the lod_status_image array. Me so smart." +}; + +std::string lod_label_name[NUM_LOD+1] = +{ + "lowest_label", + "low_label", + "medium_label", + "high_label", + "I went off the end of the lod_label_name array. Me so smart." +}; + +bool validate_face(const LLVolumeFace& face) +{ + for (U32 i = 0; i < face.mNumIndices; ++i) + { + if (face.mIndices[i] >= face.mNumVertices) + { + llwarns << "Face has invalid index." << llendl; + return false; + } + } + + return true; +} + +bool validate_model(const LLModel* mdl) +{ + if (mdl->getNumVolumeFaces() == 0) + { + llwarns << "Model has no faces!" << llendl; + return false; + } + + for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) + { + if (mdl->getVolumeFace(i).mNumVertices == 0) + { + llwarns << "Face has no vertices." << llendl; + return false; + } + + if (mdl->getVolumeFace(i).mNumIndices == 0) + { + llwarns << "Face has no indices." << llendl; + return false; + } + + if (!validate_face(mdl->getVolumeFace(i))) + { + return false; + } + } + + return true; +} + +BOOL stop_gloderror() +{ + GLuint error = glodGetError(); + + if (error != GLOD_NO_ERROR) + { + llwarns << "GLOD error detected, cannot generate LOD: " << std::hex << error << llendl; + return TRUE; + } + + return FALSE; +} + + +LLMeshFilePicker::LLMeshFilePicker(LLModelPreview* mp, S32 lod) + : LLFilePickerThread(LLFilePicker::FFLOAD_COLLADA) + { + mMP = mp; + mLOD = lod; + } + +void LLMeshFilePicker::notify(const std::string& filename) +{ + mMP->loadModel(mFile, mLOD); +} + + +//----------------------------------------------------------------------------- +// LLFloaterModelPreview() +//----------------------------------------------------------------------------- +LLFloaterModelPreview::LLFloaterModelPreview(const LLSD& key) : +LLFloater(key) +{ + sInstance = this; + mLastMouseX = 0; + mLastMouseY = 0; + mGLName = 0; + mStatusLock = new LLMutex(NULL); + + mLODMode[LLModel::LOD_HIGH] = 0; + for (U32 i = 0; i < LLModel::LOD_HIGH; i++) + { + mLODMode[i] = 1; + } +} + +//----------------------------------------------------------------------------- +// postBuild() +//----------------------------------------------------------------------------- +BOOL LLFloaterModelPreview::postBuild() +{ + if (!LLFloater::postBuild()) + { + return FALSE; + } + + + + + + + childSetAction("lod_browse", onBrowseLOD, this); + + childSetCommitCallback("cancel_btn", onCancel, this); + childSetCommitCallback("crease_angle", onGenerateNormalsCommit, this); + childSetCommitCallback("generate_normals", onGenerateNormalsCommit, this); + + childSetCommitCallback("lod_generate", onAutoFillCommit, this); + + childSetCommitCallback("lod_mode", onLODParamCommit, this); + childSetCommitCallback("lod_error_threshold", onLODParamCommit, this); + childSetCommitCallback("lod_triangle_limit", onLODParamCommitTriangleLimit, this); + childSetCommitCallback("build_operator", onLODParamCommit, this); + childSetCommitCallback("queue_mode", onLODParamCommit, this); + childSetCommitCallback("border_mode", onLODParamCommit, this); + childSetCommitCallback("share_tolerance", onLODParamCommit, this); + + childSetTextArg("status", "[STATUS]", getString("status_idle")); + + //childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d",sUploadAmount)); + childSetAction("ok_btn", onUpload, this); + childDisable("ok_btn"); + + childSetAction("clear_materials", onClearMaterials, this); + + childSetCommitCallback("preview_lod_combo", onPreviewLODCommit, this); + + childSetCommitCallback("upload_skin", onUploadSkinCommit, this); + childSetCommitCallback("upload_joints", onUploadJointsCommit, this); + + childSetCommitCallback("import_scale", onImportScaleCommit, this); + childSetCommitCallback("pelvis_offset", onPelvisOffsetCommit, this); + + childSetCommitCallback("lod_file_or_limit", refresh, this); + childSetCommitCallback("physics_load_radio", refresh, this); + //childSetCommitCallback("physics_optimize", refresh, this); + //childSetCommitCallback("physics_use_hull", refresh, this); + + childDisable("upload_skin"); + childDisable("upload_joints"); + + childDisable("ok_btn"); + + mViewOptionMenuButton = getChild("options_gear_btn"); + + mCommitCallbackRegistrar.add("ModelImport.ViewOption.Action", boost::bind(&LLFloaterModelPreview::onViewOptionChecked, this, _2)); + mEnableCallbackRegistrar.add("ModelImport.ViewOption.Check", boost::bind(&LLFloaterModelPreview::isViewOptionChecked, this, _2)); + mEnableCallbackRegistrar.add("ModelImport.ViewOption.Enabled", boost::bind(&LLFloaterModelPreview::isViewOptionEnabled, this, _2)); + + + + mViewOptionMenu = LLUICtrlFactory::getInstance()->createFromFile("menu_model_import_gear_default.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + mViewOptionMenuButton->setMenu(mViewOptionMenu, LLMenuButton::MP_BOTTOM_LEFT); + + initDecompControls(); + + LLView* preview_panel = getChild("preview_panel"); + + mPreviewRect = preview_panel->getRect(); + + mModelPreview = new LLModelPreview(512, 512, this); + mModelPreview->setPreviewTarget(16.f); + mModelPreview->setDetailsCallback(boost::bind(&LLFloaterModelPreview::setDetails, this, _1, _2, _3, _4, _5)); + + //set callbacks for left click on line editor rows + for (U32 i = 0; i <= LLModel::LOD_HIGH; i++) + { + LLTextBox* text = getChild(lod_label_name[i]); + if (text) + { + text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i)); + } + + text = getChild(lod_triangles_name[i]); + if (text) + { + text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i)); + } + + text = getChild(lod_vertices_name[i]); + if (text) + { + text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i)); + } + + text = getChild(lod_status_name[i]); + if (text) + { + text->setMouseDownCallback(boost::bind(&LLModelPreview::setPreviewLOD, mModelPreview, i)); + } + } + + return TRUE; +} + +//----------------------------------------------------------------------------- +// LLFloaterModelPreview() +//----------------------------------------------------------------------------- +LLFloaterModelPreview::~LLFloaterModelPreview() +{ + sInstance = NULL; + + const LLModelLoader *model_loader = mModelPreview->mModelLoader; + if (model_loader && model_loader->mResetJoints) + { + gAgentAvatarp->resetJointPositions(); + } + + delete mModelPreview; + + if (mGLName) + { + LLImageGL::deleteTextures(1, &mGLName ); + } + + delete mStatusLock; + mStatusLock = NULL; +} + +void LLFloaterModelPreview::onViewOptionChecked(const LLSD& userdata) +{ + if (mModelPreview) + { + mModelPreview->mViewOption[userdata.asString()] = !mModelPreview->mViewOption[userdata.asString()]; + + mModelPreview->refresh(); + } +} + +bool LLFloaterModelPreview::isViewOptionChecked(const LLSD& userdata) +{ + if (mModelPreview) + { + return mModelPreview->mViewOption[userdata.asString()]; + } + + return false; +} + +bool LLFloaterModelPreview::isViewOptionEnabled(const LLSD& userdata) +{ + return !mViewOptionDisabled[userdata.asString()]; +} + +void LLFloaterModelPreview::setViewOptionEnabled(const std::string& option, bool enabled) +{ + mViewOptionDisabled[option] = !enabled; +} + +void LLFloaterModelPreview::enableViewOption(const std::string& option) +{ + setViewOptionEnabled(option, true); +} + +void LLFloaterModelPreview::disableViewOption(const std::string& option) +{ + setViewOptionEnabled(option, false); +} + +void LLFloaterModelPreview::loadModel(S32 lod) +{ + mModelPreview->mLoading = true; + + (new LLMeshFilePicker(mModelPreview, lod))->getFile(); +} + +//static +void LLFloaterModelPreview::onImportScaleCommit(LLUICtrl*,void* userdata) +{ + LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; + + if (!fp->mModelPreview) + { + return; + } + + fp->mModelPreview->calcResourceCost(); + fp->mModelPreview->refresh(); +} +//static +void LLFloaterModelPreview::onPelvisOffsetCommit( LLUICtrl*, void* userdata ) +{ + LLFloaterModelPreview *fp =(LLFloaterModelPreview*)userdata; + + if (!fp->mModelPreview) + { + return; + } + fp->mModelPreview->calcResourceCost(); + fp->mModelPreview->refresh(); +} + +//static +void LLFloaterModelPreview::onUploadJointsCommit(LLUICtrl*,void* userdata) +{ + LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; + + if (!fp->mModelPreview) + { + return; + } + + fp->mModelPreview->refresh(); +} + +//static +void LLFloaterModelPreview::onUploadSkinCommit(LLUICtrl*,void* userdata) +{ + LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; + + if (!fp->mModelPreview) + { + return; + } - //if ( mFMP && mFMP->childGetValue("upload_joints").asBoolean() ) - //{ - // gAgentAvatarp->setPelvisOffset( mPelvisZOffset ); - //} - - F32 streaming_cost = 0.f; - F32 physics_cost = 0.f; - for (U32 i = 0; i < mUploadData.size(); ++i) - { - LLModelInstance& instance = mUploadData[i]; - - if (accounted.find(instance.mModel) == accounted.end()) - { - accounted.insert(instance.mModel); - - LLModel::convex_hull_decomposition& decomp = - instance.mLOD[LLModel::LOD_PHYSICS] ? - instance.mLOD[LLModel::LOD_PHYSICS]->mConvexHullDecomp : - instance.mModel->mConvexHullDecomp; - - LLSD ret = LLModel::writeModel( - "", - instance.mLOD[4], - instance.mLOD[3], - instance.mLOD[2], - instance.mLOD[1], - instance.mLOD[0], - decomp, - mFMP->childGetValue("upload_skin").asBoolean(), - mFMP->childGetValue("upload_joints").asBoolean(), - TRUE); - cost += gMeshRepo.calcResourceCost(ret); - - num_hulls += decomp.size(); - for (U32 i = 0; i < decomp.size(); ++i) - { - num_points += decomp[i].size(); - } - - //calculate streaming cost - LLMatrix4 transformation = instance.mTransform; - - LLVector3 position = LLVector3(0, 0, 0) * transformation; - - LLVector3 x_transformed = LLVector3(1, 0, 0) * transformation - position; - LLVector3 y_transformed = LLVector3(0, 1, 0) * transformation - position; - LLVector3 z_transformed = LLVector3(0, 0, 1) * transformation - position; - F32 x_length = x_transformed.normalize(); - F32 y_length = y_transformed.normalize(); - F32 z_length = z_transformed.normalize(); - LLVector3 scale = LLVector3(x_length, y_length, z_length); - - F32 radius = scale.length()*debug_scale; - - streaming_cost += LLMeshRepository::getStreamingCost(ret, radius); - } - } - - F32 scale = mFMP ? mFMP->childGetValue("import_scale").asReal()*2.f : 2.f; - - mDetailsSignal(mPreviewScale[0]*scale, mPreviewScale[1]*scale, mPreviewScale[2]*scale, streaming_cost, physics_cost); - - updateStatusMessages(); - - return cost; -} - -void LLFloaterModelPreview::setDetails(F32 x, F32 y, F32 z, F32 streaming_cost, F32 physics_cost) -{ - childSetTextArg("import_dimensions", "[X]", llformat("%.3f", x)); - childSetTextArg("import_dimensions", "[Y]", llformat("%.3f", y)); - childSetTextArg("import_dimensions", "[Z]", llformat("%.3f", z)); - childSetTextArg("streaming cost", "[COST]", llformat("%.3f", streaming_cost)); - childSetTextArg("physics cost", "[COST]", llformat("%.3f", physics_cost)); -} - -void LLModelPreview::alterModelsPivot( void ) -{ - for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) - { - if ( *iter ) - { - (*iter)->offsetMesh( mModelPivot ); - } - } - - for ( int i=0;ioffsetMesh( mModelPivot ); - } - } - } -} - -void LLModelPreview::rebuildUploadData() -{ - assert_main_thread(); - - mUploadData.clear(); - mTextureSet.clear(); - - //fill uploaddata instance vectors from scene data - - std::string requested_name = mFMP->getChild("description_form")->getValue().asString(); - - - LLSpinCtrl* scale_spinner = mFMP->getChild("import_scale"); - - if (!scale_spinner) - { - llerrs << "floater_model_preview.xml MUST contain import_scale spinner." << llendl; - } - - F32 scale = scale_spinner->getValue().asReal(); - - LLMatrix4 scale_mat; - scale_mat.initScale(LLVector3(scale, scale, scale)); - - F32 max_scale = 0.f; - - if ( mBaseScene.size() > 0 ) - { - mFMP->childEnable("ok_btn"); - } - - for (LLModelLoader::scene::iterator iter = mBaseScene.begin(); iter != mBaseScene.end(); ++iter) - { //for each transform in scene - LLMatrix4 mat = iter->first; - - // compute position - LLVector3 position = LLVector3(0, 0, 0) * mat; - - // compute scale - LLVector3 x_transformed = LLVector3(1, 0, 0) * mat - position; - LLVector3 y_transformed = LLVector3(0, 1, 0) * mat - position; - LLVector3 z_transformed = LLVector3(0, 0, 1) * mat - position; - F32 x_length = x_transformed.normalize(); - F32 y_length = y_transformed.normalize(); - F32 z_length = z_transformed.normalize(); - - max_scale = llmax(llmax(llmax(max_scale, x_length), y_length), z_length); - - mat *= scale_mat; - - for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) - { //for each instance with said transform applied - LLModelInstance instance = *model_iter; - - LLModel* base_model = instance.mModel; - - if (base_model) - { - base_model->mRequestedLabel = requested_name; - } - - S32 idx = 0; - for (idx = 0; idx < mBaseModel.size(); ++idx) - { //find reference instance for this model - if (mBaseModel[idx] == base_model) - { - break; - } - } - - for (U32 i = 0; i < LLModel::NUM_LODS; i++) - { //fill LOD slots based on reference model index - if (!mModel[i].empty()) - { - instance.mLOD[i] = mModel[i][idx]; - } - else - { - instance.mLOD[i] = NULL; - } - } - - instance.mTransform = mat; - mUploadData.push_back(instance); - } - } - - F32 max_import_scale = DEFAULT_MAX_PRIM_SCALE/max_scale; - - scale_spinner->setMaxValue(max_import_scale); - - if (max_import_scale < scale) - { - scale_spinner->setValue(max_import_scale); - } - -} - -void LLModelPreview::saveUploadData(bool save_skinweights, bool save_joint_positions) -{ - if (!mLODFile[LLModel::LOD_HIGH].empty()) - { - std::string filename = mLODFile[LLModel::LOD_HIGH]; - - std::string::size_type i = filename.rfind("."); - if (i != std::string::npos) - { - filename.replace(i, filename.size()-1, ".slm"); - saveUploadData(filename, save_skinweights, save_joint_positions); - } - } -} - -void LLModelPreview::saveUploadData(const std::string& filename, bool save_skinweights, bool save_joint_positions) -{ - std::set > meshes; - std::map mesh_binary; - - LLModel::hull empty_hull; - - LLSD data; - - S32 mesh_id = 0; - - //build list of unique models and initialize local id - for (U32 i = 0; i < mUploadData.size(); ++i) - { - LLModelInstance& instance = mUploadData[i]; - - if (meshes.find(instance.mModel) == meshes.end()) - { - instance.mModel->mLocalID = mesh_id++; - meshes.insert(instance.mModel); - - std::stringstream str; - - LLModel::convex_hull_decomposition& decomp = - instance.mLOD[LLModel::LOD_PHYSICS].notNull() ? - instance.mLOD[LLModel::LOD_PHYSICS]->mConvexHullDecomp : - instance.mModel->mConvexHullDecomp; - - LLModel::writeModel(str, - instance.mLOD[LLModel::LOD_PHYSICS], - instance.mLOD[LLModel::LOD_HIGH], - instance.mLOD[LLModel::LOD_MEDIUM], - instance.mLOD[LLModel::LOD_LOW], - instance.mLOD[LLModel::LOD_IMPOSTOR], - decomp, - empty_hull, save_skinweights, save_joint_positions); - - - data["mesh"][instance.mModel->mLocalID] = str.str(); - } - - data["instance"][i] = instance.asLLSD(); - } - - llofstream out(filename, std::ios_base::out | std::ios_base::binary); - LLSDSerialize::toBinary(data, out); - out.flush(); - out.close(); -} - -void LLModelPreview::clearModel(S32 lod) -{ - if (lod < 0 || lod > LLModel::LOD_PHYSICS) - { - return; - } - - mVertexBuffer[lod].clear(); - mModel[lod].clear(); - mScene[lod].clear(); -} - -void LLModelPreview::loadModel(std::string filename, S32 lod) -{ - assert_main_thread(); - - LLMutexLock lock(this); - - // This triggers if you bring up the file picker and then hit CANCEL. - // Just use the previous model (if any) and ignore that you brought up - // the file picker. - - if (filename.empty()) - { - if (mBaseModel.empty()) - { - // this is the initial file picking. Close the whole floater - // if we don't have a base model to show for high LOD. - mFMP->closeFloater(false); - mLoading = false; - } - return; - } - - if (mModelLoader) - { - llwarns << "Incompleted model load operation pending." << llendl; - return; - } - - mLODFile[lod] = filename; - - if (lod == LLModel::LOD_HIGH) - { - clearGLODGroup(); - } - - mModelLoader = new LLModelLoader(filename, lod, this); - - mModelLoader->start(); - - mFMP->childSetTextArg("status", "[STATUS]", mFMP->getString("status_reading_file")); - - setPreviewLOD(lod); - - if ( getLoadState() == LLModelLoader::ERROR_PARSING ) - { - mFMP->childDisable("ok_btn"); - } - - if (lod == mPreviewLOD) - { - mFMP->childSetText("lod_file", mLODFile[mPreviewLOD]); - } - else if (lod == LLModel::LOD_PHYSICS) - { - mFMP->childSetText("physics_file", mLODFile[lod]); - } - - mFMP->openFloater(); -} - -void LLModelPreview::setPhysicsFromLOD(S32 lod) -{ - assert_main_thread(); - - if (lod >= 0 && lod <= 3) - { - mModel[LLModel::LOD_PHYSICS] = mModel[lod]; - mScene[LLModel::LOD_PHYSICS] = mScene[lod]; - mLODFile[LLModel::LOD_PHYSICS].clear(); - mFMP->childSetText("physics_file", mLODFile[LLModel::LOD_PHYSICS]); - mVertexBuffer[LLModel::LOD_PHYSICS].clear(); - rebuildUploadData(); - refresh(); - updateStatusMessages(); - } -} - -void LLModelPreview::clearIncompatible(S32 lod) -{ - for (U32 i = 0; i <= LLModel::LOD_HIGH; i++) - { //clear out any entries that aren't compatible with this model - if (i != lod) - { - if (mModel[i].size() != mModel[lod].size()) - { - mModel[i].clear(); - mScene[i].clear(); - mVertexBuffer[i].clear(); - - if (i == LLModel::LOD_HIGH) - { - mBaseModel = mModel[lod]; - clearGLODGroup(); - mBaseScene = mScene[lod]; - mVertexBuffer[5].clear(); - } - } - } - } -} - -void LLModelPreview::clearGLODGroup() -{ - if (mGroup) - { - for (std::map, U32>::iterator iter = mObject.begin(); iter != mObject.end(); ++iter) - { - glodDeleteObject(iter->second); - stop_gloderror(); - } - mObject.clear(); - - glodDeleteGroup(mGroup); - stop_gloderror(); - mGroup = 0; - } -} - -void LLModelPreview::loadModelCallback(S32 lod) -{ - assert_main_thread(); - - LLMutexLock lock(this); - if (!mModelLoader) - { - return; - } - - mModelLoader->loadTextures() ; - - if (lod == -1) - { //populate all LoDs from model loader scene - mBaseModel.clear(); - mBaseScene.clear(); - - for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) - { //for each LoD - - //clear scene and model info - mScene[lod].clear(); - mModel[lod].clear(); - mVertexBuffer[lod].clear(); - - if (mModelLoader->mScene.begin()->second[0].mLOD[lod].notNull()) - { //if this LoD exists in the loaded scene - - //copy scene to current LoD - mScene[lod] = mModelLoader->mScene; - - //touch up copied scene to look like current LoD - for (LLModelLoader::scene::iterator iter = mScene[lod].begin(); iter != mScene[lod].end(); ++iter) - { - LLModelLoader::model_instance_list& list = iter->second; - - for (LLModelLoader::model_instance_list::iterator list_iter = list.begin(); list_iter != list.end(); ++list_iter) - { - //override displayed model with current LoD - list_iter->mModel = list_iter->mLOD[lod]; - - //add current model to current LoD's model list (LLModel::mLocalID makes a good vector index) - S32 idx = list_iter->mModel->mLocalID; - - if (mModel[lod].size() <= idx) - { //stretch model list to fit model at given index - mModel[lod].resize(idx+1); - } - - mModel[lod][idx] = list_iter->mModel; - } - } - } - } - - //copy high lod to base scene for LoD generation - mBaseScene = mScene[LLModel::LOD_HIGH]; - mBaseModel = mModel[LLModel::LOD_HIGH]; - - mDirty = true; - resetPreviewTarget(); - } - else - { //only replace given LoD - mModel[lod] = mModelLoader->mModelList; - mScene[lod] = mModelLoader->mScene; - mVertexBuffer[lod].clear(); - - if (lod == LLModel::LOD_PHYSICS) - { - mPhysicsMesh.clear(); - } - - setPreviewLOD(lod); - - - if (lod == LLModel::LOD_HIGH) - { //save a copy of the highest LOD for automatic LOD manipulation - if (mBaseModel.empty()) - { //first time we've loaded a model, auto-gen LoD - mGenLOD = true; - } - - mBaseModel = mModel[lod]; - clearGLODGroup(); - - mBaseScene = mScene[lod]; - mVertexBuffer[5].clear(); - } - - clearIncompatible(lod); - - mDirty = true; - - if (lod == LLModel::LOD_HIGH) - { - resetPreviewTarget(); - } - } - - mLoading = false; - refresh(); - - mModelLoadedSignal(); -} - -void LLModelPreview::resetPreviewTarget() -{ - if ( mModelLoader ) - { - mPreviewTarget = (mModelLoader->mExtents[0] + mModelLoader->mExtents[1]) * 0.5f; - mPreviewScale = (mModelLoader->mExtents[1] - mModelLoader->mExtents[0]) * 0.5f; - } - - setPreviewTarget(mPreviewScale.magVec()*2.f); -} - -void LLModelPreview::generateNormals() -{ - assert_main_thread(); - - S32 which_lod = mPreviewLOD; - - - if (which_lod > 4 || which_lod < 0 || - mModel[which_lod].empty()) - { - return; - } - - F32 angle_cutoff = mFMP->childGetValue("crease_angle").asReal(); - - angle_cutoff *= DEG_TO_RAD; - - if (which_lod == 3 && !mBaseModel.empty()) - { - for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) - { - (*iter)->generateNormals(angle_cutoff); - } - - mVertexBuffer[5].clear(); - } - - for (LLModelLoader::model_list::iterator iter = mModel[which_lod].begin(); iter != mModel[which_lod].end(); ++iter) - { - (*iter)->generateNormals(angle_cutoff); - } - - mVertexBuffer[which_lod].clear(); - refresh(); - -} - -void LLModelPreview::clearMaterials() -{ - for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) - { //for each transform in current scene - for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) - { //for each instance with that transform - LLModelInstance& source_instance = *model_iter; - LLModel* source = source_instance.mModel; - - for (S32 i = 0; i < source->getNumVolumeFaces(); ++i) - { //for each face in instance - LLImportMaterial& source_material = source_instance.mMaterial[i]; - - //clear material info - source_material.mDiffuseColor = LLColor4(1,1,1,1); - source_material.mDiffuseMap = NULL; - source_material.mDiffuseMapFilename.clear(); - source_material.mDiffuseMapLabel.clear(); - source_material.mFullbright = false; - } - } - } - - mVertexBuffer[mPreviewLOD].clear(); - - if (mPreviewLOD == LLModel::LOD_HIGH) - { - mBaseScene = mScene[mPreviewLOD]; - mBaseModel = mModel[mPreviewLOD]; - clearGLODGroup(); - mVertexBuffer[5].clear(); - } - - mResourceCost = calcResourceCost(); - refresh(); -} - -void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_limit) -{ - if (mBaseModel.empty()) - { - return; - } - - if (which_lod == LLModel::LOD_PHYSICS) - { //clear physics mesh map - mPhysicsMesh.clear(); - } - - LLVertexBuffer::unbind(); - - stop_gloderror(); - static U32 cur_name = 1; - - S32 limit = -1; - - U32 triangle_count = 0; - - for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) - { - LLModel* mdl = *iter; - for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) - { - triangle_count += mdl->getVolumeFace(i).mNumIndices/3; - } - } - - U32 base_triangle_count = triangle_count; - - U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; - - U32 lod_mode = 0; - - LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode"); - if (iface) - { - lod_mode = iface->getFirstSelectedIndex(); - } - - F32 lod_error_threshold = mFMP->childGetValue("lod_error_threshold").asReal(); - - if (lod_mode == 0) - { - lod_mode = GLOD_TRIANGLE_BUDGET; - if (which_lod != -1) - { - limit = mFMP->childGetValue("lod_triangle_limit").asInteger(); - } - } - else - { - lod_mode = GLOD_ERROR_THRESHOLD; - } - - U32 build_operator = 0; - - iface = mFMP->childGetSelectionInterface("build_operator"); - if (iface) - { - build_operator = iface->getFirstSelectedIndex(); - } - - if (build_operator == 0) - { - build_operator = GLOD_OPERATOR_EDGE_COLLAPSE; - } - else - { - build_operator = GLOD_OPERATOR_HALF_EDGE_COLLAPSE; - } - - U32 queue_mode=0; - iface = mFMP->childGetSelectionInterface("queue_mode"); - if (iface) - { - queue_mode = iface->getFirstSelectedIndex(); - } - - if (queue_mode == 0) - { - queue_mode = GLOD_QUEUE_GREEDY; - } - else if (queue_mode == 1) - { - queue_mode = GLOD_QUEUE_LAZY; - } - else - { - queue_mode = GLOD_QUEUE_INDEPENDENT; - } - - U32 border_mode = 0; - - iface = mFMP->childGetSelectionInterface("border_mode"); - if (iface) - { - border_mode = iface->getFirstSelectedIndex(); - } - - if (border_mode == 0) - { - border_mode = GLOD_BORDER_UNLOCK; - } - else - { - border_mode = GLOD_BORDER_LOCK; - } - - bool object_dirty = false; - if (border_mode != mBuildBorderMode) - { - mBuildBorderMode = border_mode; - object_dirty = true; - } - - if (queue_mode != mBuildQueueMode) - { - mBuildQueueMode = queue_mode; - object_dirty = true; - } - - if (build_operator != mBuildOperator) - { - mBuildOperator = build_operator; - object_dirty = true; - } - - F32 share_tolerance = mFMP->childGetValue("share_tolerance").asReal(); - if (share_tolerance != mBuildShareTolerance) - { - mBuildShareTolerance = share_tolerance; - object_dirty = true; - } - - if (mGroup == 0) - { - object_dirty = true; - mGroup = cur_name++; - glodNewGroup(mGroup); - } - - if (object_dirty) - { - for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) - { //build GLOD objects for each model in base model list - LLModel* mdl = *iter; - - if (mObject[mdl] != 0) - { - glodDeleteObject(mObject[mdl]); - } - - mObject[mdl] = cur_name++; - - glodNewObject(mObject[mdl], mGroup, GLOD_DISCRETE); - stop_gloderror(); - - if (iter == mBaseModel.begin() && !mdl->mSkinWeights.empty()) - { //regenerate vertex buffer for skinned models to prevent animation feedback during LOD generation - mVertexBuffer[5].clear(); - } - - if (mVertexBuffer[5].empty()) - { - genBuffers(5, false); - } - - U32 tri_count = 0; - for (U32 i = 0; i < mVertexBuffer[5][mdl].size(); ++i) - { - mVertexBuffer[5][mdl][i]->setBuffer(type_mask); - U32 num_indices = mVertexBuffer[5][mdl][i]->getNumIndices(); - if (num_indices > 2) - { - glodInsertElements(mObject[mdl], i, GL_TRIANGLES, num_indices, GL_UNSIGNED_SHORT, mVertexBuffer[5][mdl][i]->getIndicesPointer(), 0, 0.f); - } - tri_count += num_indices/3; - stop_gloderror(); - } - - glodObjectParameteri(mObject[mdl], GLOD_BUILD_OPERATOR, build_operator); - stop_gloderror(); - - glodObjectParameteri(mObject[mdl], GLOD_BUILD_QUEUE_MODE, queue_mode); - stop_gloderror(); - - glodObjectParameteri(mObject[mdl], GLOD_BUILD_BORDER_MODE, border_mode); - stop_gloderror(); - - glodObjectParameterf(mObject[mdl], GLOD_BUILD_SHARE_TOLERANCE, share_tolerance); - stop_gloderror(); - - glodBuildObject(mObject[mdl]); - stop_gloderror(); - } - } - - - S32 start = LLModel::LOD_HIGH; - S32 end = 0; - - if (which_lod != -1) - { - start = end = which_lod; - } - - mMaxTriangleLimit = base_triangle_count; - - for (S32 lod = start; lod >= end; --lod) - { - if (which_lod == -1) - { - if (lod < start) - { - triangle_count /= decimation; - } - } - else - { - if (enforce_tri_limit) - { - triangle_count = limit; - } - else - { - for (S32 j=LLModel::LOD_HIGH; j>which_lod; --j) - { - triangle_count /= decimation; - } - } - } - - mModel[lod].clear(); - mModel[lod].resize(mBaseModel.size()); - mVertexBuffer[lod].clear(); - - U32 actual_tris = 0; - U32 actual_verts = 0; - U32 submeshes = 0; - - mRequestedTriangleCount[lod] = triangle_count; - - glodGroupParameteri(mGroup, GLOD_ADAPT_MODE, lod_mode); - stop_gloderror(); - - glodGroupParameteri(mGroup, GLOD_ERROR_MODE, GLOD_OBJECT_SPACE_ERROR); - stop_gloderror(); - - glodGroupParameterf(mGroup, GLOD_OBJECT_SPACE_ERROR_THRESHOLD, lod_error_threshold); - stop_gloderror(); - - glodGroupParameteri(mGroup, GLOD_MAX_TRIANGLES, 0); - stop_gloderror(); - - glodAdaptGroup(mGroup); - stop_gloderror(); - - if (lod_mode == GLOD_TRIANGLE_BUDGET) - { //SH-632 Always adapt to 0 before adapting to actual desired amount, and always - //add 1 to desired amount to avoid decimating below desired amount - glodGroupParameteri(mGroup, GLOD_MAX_TRIANGLES, triangle_count+1); - stop_gloderror(); - - glodAdaptGroup(mGroup); - stop_gloderror(); - } - - for (U32 mdl_idx = 0; mdl_idx < mBaseModel.size(); ++mdl_idx) - { - LLModel* base = mBaseModel[mdl_idx]; - - GLint patch_count = 0; - glodGetObjectParameteriv(mObject[base], GLOD_NUM_PATCHES, &patch_count); - stop_gloderror(); - - LLVolumeParams volume_params; - volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); - mModel[lod][mdl_idx] = new LLModel(volume_params, 0.f); - - GLint* sizes = new GLint[patch_count*2]; - glodGetObjectParameteriv(mObject[base], GLOD_PATCH_SIZES, sizes); - stop_gloderror(); - - GLint* names = new GLint[patch_count]; - glodGetObjectParameteriv(mObject[base], GLOD_PATCH_NAMES, names); - stop_gloderror(); - - mModel[lod][mdl_idx]->setNumVolumeFaces(patch_count); - - LLModel* target_model = mModel[lod][mdl_idx]; - - for (GLint i = 0; i < patch_count; ++i) - { - LLPointer buff = new LLVertexBuffer(type_mask, 0); - - if (sizes[i*2+1] > 0 && sizes[i*2] > 0) - { - buff->allocateBuffer(sizes[i*2+1], sizes[i*2], true); - buff->setBuffer(type_mask); - glodFillElements(mObject[base], names[i], GL_UNSIGNED_SHORT, buff->getIndicesPointer()); - stop_gloderror(); - } - else - { //this face was eliminated, create a dummy triangle (one vertex, 3 indices, all 0) - buff->allocateBuffer(1, 3, true); - memset(buff->getMappedData(), 0, buff->getSize()); - memset(buff->getIndicesPointer(), 0, buff->getIndicesSize()); - } - - buff->validateRange(0, buff->getNumVerts()-1, buff->getNumIndices(), 0); - - LLStrider pos; - LLStrider norm; - LLStrider tc; - LLStrider index; - - buff->getVertexStrider(pos); - buff->getNormalStrider(norm); - buff->getTexCoord0Strider(tc); - buff->getIndexStrider(index); - - target_model->setVolumeFaceData(names[i], pos, norm, tc, index, buff->getNumVerts(), buff->getNumIndices()); - actual_tris += buff->getNumIndices()/3; - actual_verts += buff->getNumVerts(); - ++submeshes; - - if (!validate_face(target_model->getVolumeFace(names[i]))) - { - llerrs << "Invalid face generated during LOD generation." << llendl; - } - } - - //blind copy skin weights and just take closest skin weight to point on - //decimated mesh for now (auto-generating LODs with skin weights is still a bit - //of an open problem). - target_model->mPosition = base->mPosition; - target_model->mSkinWeights = base->mSkinWeights; - target_model->mJointMap = base->mJointMap; - target_model->mJointList = base->mJointList; - target_model->mInvBindMatrix = base->mInvBindMatrix; - target_model->mBindShapeMatrix = base->mBindShapeMatrix; - target_model->mAlternateBindMatrix = base->mAlternateBindMatrix; - //copy material list - target_model->mMaterialList = base->mMaterialList; - - if (!validate_model(target_model)) - { - llerrs << "Invalid model generated when creating LODs" << llendl; - } - - delete [] sizes; - delete [] names; - } - - //rebuild scene based on mBaseScene - mScene[lod].clear(); - mScene[lod] = mBaseScene; - - for (U32 i = 0; i < mBaseModel.size(); ++i) - { - LLModel* mdl = mBaseModel[i]; - LLModel* target = mModel[lod][i]; - if (target) - { - for (LLModelLoader::scene::iterator iter = mScene[lod].begin(); iter != mScene[lod].end(); ++iter) - { - for (U32 j = 0; j < iter->second.size(); ++j) - { - if (iter->second[j].mModel == mdl) - { - iter->second[j].mModel = target; - } - } - } - } - } - } - - mResourceCost = calcResourceCost(); - - /*if (which_lod == -1 && mScene[LLModel::LOD_PHYSICS].empty()) - { //build physics scene - mScene[LLModel::LOD_PHYSICS] = mScene[LLModel::LOD_LOW]; - mModel[LLModel::LOD_PHYSICS] = mModel[LLModel::LOD_LOW]; - - for (U32 i = 1; i < mModel[LLModel::LOD_PHYSICS].size(); ++i) - { - mPhysicsQ.push(mModel[LLModel::LOD_PHYSICS][i]); - } - }*/ -} - -void LLModelPreview::updateStatusMessages() -{ - assert_main_thread(); - - //triangle/vertex/submesh count for each mesh asset for each lod - std::vector tris[LLModel::NUM_LODS]; - std::vector verts[LLModel::NUM_LODS]; - std::vector submeshes[LLModel::NUM_LODS]; - - //total triangle/vertex/submesh count for each lod - S32 total_tris[LLModel::NUM_LODS]; - S32 total_verts[LLModel::NUM_LODS]; - S32 total_submeshes[LLModel::NUM_LODS]; - - for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) - { - //initialize total for this lod to 0 - total_tris[lod] = total_verts[lod] = total_submeshes[lod] = 0; - - for (U32 i = 0; i < mModel[lod].size(); ++i) - { //for each model in the lod - S32 cur_tris = 0; - S32 cur_verts = 0; - S32 cur_submeshes = mModel[lod][i]->getNumVolumeFaces(); - - for (S32 j = 0; j < cur_submeshes; ++j) - { //for each submesh (face), add triangles and vertices to current total - const LLVolumeFace& face = mModel[lod][i]->getVolumeFace(j); - cur_tris += face.mNumIndices/3; - cur_verts += face.mNumVertices; - } - - //add this model to the lod total - total_tris[lod] += cur_tris; - total_verts[lod] += cur_verts; - total_submeshes[lod] += cur_submeshes; - - //store this model's counts to asset data - tris[lod].push_back(cur_tris); - verts[lod].push_back(cur_verts); - submeshes[lod].push_back(cur_submeshes); - } - } - - if (mMaxTriangleLimit == 0) - { - mMaxTriangleLimit = total_tris[LLModel::LOD_HIGH]; - } - - - mFMP->childSetTextArg("submeshes_info", "[SUBMESHES]", llformat("%d", total_submeshes[LLModel::LOD_HIGH])); - - std::string mesh_status_na = mFMP->getString("mesh_status_na"); - - S32 upload_status[LLModel::LOD_HIGH+1]; - - bool upload_ok = true; - - for (S32 lod = 0; lod <= LLModel::LOD_HIGH; ++lod) - { - upload_status[lod] = 0; - - std::string message = "mesh_status_good"; - - if (total_tris[lod] > 0) - { - mFMP->childSetText(lod_triangles_name[lod], llformat("%d", total_tris[lod])); - mFMP->childSetText(lod_vertices_name[lod], llformat("%d", total_verts[lod])); - } - else - { - if (lod == LLModel::LOD_HIGH) - { - upload_status[lod] = 2; - message = "mesh_status_missing_lod"; - } - else - { - for (S32 i = lod-1; i >= 0; --i) - { - if (total_tris[i] > 0) - { - upload_status[lod] = 2; - message = "mesh_status_missing_lod"; - } - } - } - - mFMP->childSetText(lod_triangles_name[lod], mesh_status_na); - mFMP->childSetText(lod_vertices_name[lod], mesh_status_na); - } - - const U32 lod_high = LLModel::LOD_HIGH; - - if (lod != lod_high) - { - if (total_submeshes[lod] && total_submeshes[lod] != total_submeshes[lod_high]) - { //number of submeshes is different - message = "mesh_status_submesh_mismatch"; - upload_status[lod] = 2; - } - else if (!tris[lod].empty() && tris[lod].size() != tris[lod_high].size()) - { //number of meshes is different - message = "mesh_status_mesh_mismatch"; - upload_status[lod] = 2; - } - else if (!verts[lod].empty()) - { - for (U32 i = 0; i < verts[lod].size(); ++i) - { - S32 max_verts = i < verts[lod+1].size() ? verts[lod+1][i] : 0; - - if (max_verts > 0) - { - if (verts[lod][i] > max_verts) - { //too many vertices in this lod - message = "mesh_status_too_many_vertices"; - upload_status[lod] = 2; - } - } - } - } - } - - LLIconCtrl* icon = mFMP->getChild(lod_icon_name[lod]); - LLUIImagePtr img = LLUI::getUIImage(lod_status_image[upload_status[lod]]); - icon->setVisible(true); - icon->setImage(img); - - if (upload_status[lod] >= 2) - { - upload_ok = false; - } - - if (lod == mPreviewLOD) - { - mFMP->childSetText("lod_status_message_text", mFMP->getString(message)); - icon = mFMP->getChild("lod_status_message_icon"); - icon->setImage(img); - } - } - - bool errorStateFromLoader = getLoadState() == LLModelLoader::ERROR_PARSING ? true : false; - - bool skinAndRigOk = true; - bool uploadingSkin = mFMP->childGetValue("upload_skin").asBoolean(); - if ( uploadingSkin && !isRigValid() ) - { - skinAndRigOk = false; - } - - if ( upload_ok && !errorStateFromLoader && skinAndRigOk ) - { - mFMP->childEnable("ok_btn"); - } - - //add up physics triangles etc - S32 start = 0; - S32 end = mModel[LLModel::LOD_PHYSICS].size(); - - S32 phys_tris = 0; - S32 phys_hulls = 0; - S32 phys_points = 0; - - for (S32 i = start; i < end; ++i) - { //add up hulls and points and triangles for selected mesh(es) - LLModel* model = mModel[LLModel::LOD_PHYSICS][i]; - S32 cur_submeshes = model->getNumVolumeFaces(); - - LLModel::convex_hull_decomposition& decomp = model->mConvexHullDecomp; - - if (!decomp.empty()) - { - phys_hulls += decomp.size(); - for (U32 i = 0; i < decomp.size(); ++i) - { - phys_points += decomp[i].size(); - } - } - else - { //choose physics shape OR decomposition, can't use both - for (S32 j = 0; j < cur_submeshes; ++j) - { //for each submesh (face), add triangles and vertices to current total - const LLVolumeFace& face = model->getVolumeFace(j); - phys_tris += face.mNumIndices/3; - } - } - } - - if (phys_tris > 0) - { - mFMP->childSetTextArg("physics_triangles", "[TRIANGLES]", llformat("%d", phys_tris)); - } - else - { - mFMP->childSetTextArg("physics_triangles", "[TRIANGLES]", mesh_status_na); - } - - if (phys_hulls > 0) - { - mFMP->childSetTextArg("physics_hulls", "[HULLS]", llformat("%d", phys_hulls)); - mFMP->childSetTextArg("physics_points", "[POINTS]", llformat("%d", phys_points)); - } - else - { - mFMP->childSetTextArg("physics_hulls", "[HULLS]", mesh_status_na); - mFMP->childSetTextArg("physics_points", "[POINTS]", mesh_status_na); - } - - LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; - if (fmp) - { - if (phys_tris > 0 || phys_hulls > 0) - { - if (!fmp->isViewOptionEnabled("show_physics")) - { - fmp->enableViewOption("show_physics"); - mViewOption["show_physics"] = true; - } - } - else - { - fmp->disableViewOption("show_physics"); - mViewOption["show_physics"] = false; - - } - - //bool use_hull = fmp->childGetValue("physics_use_hull").asBoolean(); - - //fmp->childSetEnabled("physics_optimize", !use_hull); - - bool enable = phys_tris > 0 || phys_hulls > 0; - //enable = enable && !use_hull && fmp->childGetValue("physics_optimize").asBoolean(); - - //enable/disable "analysis" UI - LLPanel* panel = fmp->getChild("physics analysis"); - LLView* child = panel->getFirstChild(); - while (child) - { - child->setEnabled(enable); - child = panel->findNextSibling(child); - } - - enable = phys_hulls > 0; - //enable/disable "simplification" UI - panel = fmp->getChild("physics simplification"); - child = panel->getFirstChild(); - while (child) - { - child->setEnabled(enable); - child = panel->findNextSibling(child); - } - } - - const char* lod_controls[] = - { - "lod_mode", - "lod_triangle_limit", - "lod_error_tolerance", - "build_operator_text", - "queue_mode_text", - "border_mode_text", - "share_tolerance_text", - "build_operator", - "queue_mode", - "border_mode", - "share_tolerance" - }; - const U32 num_lod_controls = sizeof(lod_controls)/sizeof(char*); - - const char* file_controls[] = - { - "lod_browse", - "lod_file" - }; - const U32 num_file_controls = sizeof(file_controls)/sizeof(char*); - - if (fmp) - { - //enable/disable controls based on radio groups - if (mFMP->childGetValue("lod_from_file").asBoolean()) - { - fmp->mLODMode[mPreviewLOD] = 0; - for (U32 i = 0; i < num_file_controls; ++i) - { - mFMP->childEnable(file_controls[i]); - } - - for (U32 i = 0; i < num_lod_controls; ++i) - { - mFMP->childDisable(lod_controls[i]); - } - } - else if (mFMP->childGetValue("lod_none").asBoolean()) - { - fmp->mLODMode[mPreviewLOD] = 2; - for (U32 i = 0; i < num_file_controls; ++i) - { - mFMP->childDisable(file_controls[i]); - } - - for (U32 i = 0; i < num_lod_controls; ++i) - { - mFMP->childDisable(lod_controls[i]); - } - - if (!mModel[mPreviewLOD].empty()) - { - mModel[mPreviewLOD].clear(); - mScene[mPreviewLOD].clear(); - mVertexBuffer[mPreviewLOD].clear(); - - //this can cause phasing issues with the UI, so reenter this function and return - updateStatusMessages(); - return; - } - } - else - { // auto generate, also the default case for wizard which has no radio selection - fmp->mLODMode[mPreviewLOD] = 1; - - for (U32 i = 0; i < num_file_controls; ++i) - { - mFMP->childDisable(file_controls[i]); - } - - for (U32 i = 0; i < num_lod_controls; ++i) - { - mFMP->childEnable(lod_controls[i]); - } - - //if (threshold) - { - U32 lod_mode = 0; - LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode"); - if (iface) - { - lod_mode = iface->getFirstSelectedIndex(); - } - - LLSpinCtrl* threshold = mFMP->getChild("lod_error_threshold"); - LLSpinCtrl* limit = mFMP->getChild("lod_triangle_limit"); - - limit->setMaxValue(mMaxTriangleLimit); - limit->setValue(mRequestedTriangleCount[mPreviewLOD]); - - if (lod_mode == 0) - { - limit->setVisible(true); - threshold->setVisible(false); - - limit->setMaxValue(mMaxTriangleLimit); - limit->setIncrement(mMaxTriangleLimit/32); - } - else - { - limit->setVisible(false); - threshold->setVisible(true); - } - } - } - } - - if (mFMP->childGetValue("physics_load_from_file").asBoolean()) - { - mFMP->childDisable("physics_lod_combo"); - mFMP->childEnable("physics_file"); - mFMP->childEnable("physics_browse"); - } - else - { - mFMP->childEnable("physics_lod_combo"); - mFMP->childDisable("physics_file"); - mFMP->childDisable("physics_browse"); - } -} - -void LLModelPreview::setPreviewTarget(F32 distance) -{ - mCameraDistance = distance; - mCameraZoom = 1.f; - mCameraPitch = 0.f; - mCameraYaw = 0.f; - mCameraOffset.clearVec(); -} - -void LLModelPreview::clearBuffers() -{ - for (U32 i = 0; i < 6; i++) - { - mVertexBuffer[i].clear(); - } -} - -void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights) -{ - U32 tri_count = 0; - U32 vertex_count = 0; - U32 mesh_count = 0; - - - LLModelLoader::model_list* model = NULL; - - if (lod < 0 || lod > 4) - { - model = &mBaseModel; - lod = 5; - } - else - { - model = &(mModel[lod]); - } - - if (!mVertexBuffer[lod].empty()) - { - mVertexBuffer[lod].clear(); - } - - mVertexBuffer[lod].clear(); - - LLModelLoader::model_list::iterator base_iter = mBaseModel.begin(); - - for (LLModelLoader::model_list::iterator iter = model->begin(); iter != model->end(); ++iter) - { - LLModel* mdl = *iter; - if (!mdl) - { - continue; - } - - LLModel* base_mdl = *base_iter; - base_iter++; - - for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) - { - const LLVolumeFace &vf = mdl->getVolumeFace(i); - U32 num_vertices = vf.mNumVertices; - U32 num_indices = vf.mNumIndices; - - if (!num_vertices || ! num_indices) - { - continue; - } - - LLVertexBuffer* vb = NULL; - - bool skinned = include_skin_weights && !mdl->mSkinWeights.empty(); - - U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; - - if (skinned) - { - mask |= LLVertexBuffer::MAP_WEIGHT4; - } - - vb = new LLVertexBuffer(mask, 0); - - vb->allocateBuffer(num_vertices, num_indices, TRUE); - - LLStrider vertex_strider; - LLStrider normal_strider; - LLStrider tc_strider; - LLStrider index_strider; - LLStrider weights_strider; - - vb->getVertexStrider(vertex_strider); - vb->getNormalStrider(normal_strider); - vb->getTexCoord0Strider(tc_strider); - vb->getIndexStrider(index_strider); - - if (skinned) - { - vb->getWeight4Strider(weights_strider); - } - - LLVector4a::memcpyNonAliased16((F32*) vertex_strider.get(), (F32*) vf.mPositions, num_vertices*4*sizeof(F32)); - LLVector4a::memcpyNonAliased16((F32*) tc_strider.get(), (F32*) vf.mTexCoords, num_vertices*2*sizeof(F32)); - LLVector4a::memcpyNonAliased16((F32*) normal_strider.get(), (F32*) vf.mNormals, num_vertices*4*sizeof(F32)); - - if (skinned) - { - for (U32 i = 0; i < num_vertices; i++) - { - //find closest weight to vf.mVertices[i].mPosition - LLVector3 pos(vf.mPositions[i].getF32ptr()); - - const LLModel::weight_list& weight_list = base_mdl->getJointInfluences(pos); - - LLVector4 w(0,0,0,0); - if (weight_list.size() > 4) - { - llerrs << "WTF?" << llendl; - } - - for (U32 i = 0; i < weight_list.size(); ++i) - { - F32 wght = llmin(weight_list[i].mWeight, 0.999999f); - F32 joint = (F32) weight_list[i].mJointIdx; - w.mV[i] = joint + wght; - } - - *(weights_strider++) = w; - } - } - - // build indices - for (U32 i = 0; i < num_indices; i++) - { - *(index_strider++) = vf.mIndices[i]; - } - - mVertexBuffer[lod][mdl].push_back(vb); - - vertex_count += num_vertices; - tri_count += num_indices/3; - ++mesh_count; - - } - } -} - -void LLModelPreview::update() -{ - if (mDirty) - { - mDirty = false; - mResourceCost = calcResourceCost(); - refresh(); - updateStatusMessages(); - } - - if (mGenLOD) - { - mGenLOD = false; - genLODs(); - refresh(); - updateStatusMessages(); - } - -} - -//----------------------------------------------------------------------------- -// render() -//----------------------------------------------------------------------------- -BOOL LLModelPreview::render() -{ - assert_main_thread(); - - LLMutexLock lock(this); - mNeedsUpdate = FALSE; - - bool edges = mViewOption["show_edges"]; - bool joint_positions = mViewOption["show_joint_positions"]; - bool skin_weight = mViewOption["show_skin_weight"]; - bool textures = mViewOption["show_textures"]; - bool physics = mViewOption["show_physics"]; - - S32 width = getWidth(); - S32 height = getHeight(); - - LLGLSUIDefault def; - LLGLDisable no_blend(GL_BLEND); - LLGLEnable cull(GL_CULL_FACE); - LLGLDepthTest depth(GL_TRUE); - LLGLDisable fog(GL_FOG); - - { - //clear background to blue - glMatrixMode(GL_PROJECTION); - gGL.pushMatrix(); - glLoadIdentity(); - glOrtho(0.0f, width, 0.0f, height, -1.0f, 1.0f); - - glMatrixMode(GL_MODELVIEW); - gGL.pushMatrix(); - glLoadIdentity(); - - gGL.color4f(0.169f, 0.169f, 0.169f, 1.f); - - gl_rect_2d_simple( width, height ); - - glMatrixMode(GL_PROJECTION); - gGL.popMatrix(); - - glMatrixMode(GL_MODELVIEW); - gGL.popMatrix(); - } - - LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; - - bool has_skin_weights = false; - bool upload_skin = mFMP->childGetValue("upload_skin").asBoolean(); - bool upload_joints = mFMP->childGetValue("upload_joints").asBoolean(); - - for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) - { - for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) - { - LLModelInstance& instance = *model_iter; - LLModel* model = instance.mModel; - model->mPelvisOffset = mPelvisZOffset; - if (!model->mSkinWeights.empty()) - { - has_skin_weights = true; - } - } - } - - if (has_skin_weights) - { //model has skin weights, enable view options for skin weights and joint positions - if (fmp) - { - fmp->enableViewOption("show_skin_weight"); - fmp->setViewOptionEnabled("show_joint_positions", skin_weight); - } - mFMP->childEnable("upload_skin"); - } - else - { - mFMP->childDisable("upload_skin"); - if (fmp) - { - mViewOption["show_skin_weight"] = false; - fmp->disableViewOption("show_skin_weight"); - fmp->disableViewOption("show_joint_positions"); - } - skin_weight = false; - } - - if (upload_skin && !has_skin_weights) - { //can't upload skin weights if model has no skin weights - mFMP->childSetValue("upload_skin", false); - upload_skin = false; - } - - if (!upload_skin && upload_joints) - { //can't upload joints if not uploading skin weights - mFMP->childSetValue("upload_joints", false); - upload_joints = false; - } - - mFMP->childSetEnabled("upload_joints", upload_skin); - - F32 explode = mFMP->childGetValue("physics_explode").asReal(); - - glClear(GL_DEPTH_BUFFER_BIT); - - LLRect preview_rect = mFMP->getChildView("preview_panel")->getRect(); - F32 aspect = (F32) preview_rect.getWidth()/preview_rect.getHeight(); - - LLViewerCamera::getInstance()->setAspect(aspect); - - LLViewerCamera::getInstance()->setView(LLViewerCamera::getInstance()->getDefaultFOV() / mCameraZoom); - - LLVector3 offset = mCameraOffset; - LLVector3 target_pos = mPreviewTarget+offset; - - F32 z_near = 0.001f; - F32 z_far = mCameraDistance+mPreviewScale.magVec()+mCameraOffset.magVec(); - - if (skin_weight) - { - target_pos = gAgentAvatarp->getPositionAgent(); - z_near = 0.01f; - z_far = 1024.f; - mCameraDistance = 16.f; - - //render avatar previews every frame - refresh(); - } - - glLoadIdentity(); - gPipeline.enableLightsPreview(); - - LLQuaternion camera_rot = LLQuaternion(mCameraPitch, LLVector3::y_axis) * - LLQuaternion(mCameraYaw, LLVector3::z_axis); - - LLQuaternion av_rot = camera_rot; - LLViewerCamera::getInstance()->setOriginAndLookAt( - target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + offset) * av_rot), // camera - LLVector3::z_axis, // up - target_pos); // point of interest - - - LLViewerCamera::getInstance()->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, width, height, FALSE, z_near, z_far); - - stop_glerror(); - - gGL.pushMatrix(); - const F32 BRIGHTNESS = 0.9f; - gGL.color3f(BRIGHTNESS, BRIGHTNESS, BRIGHTNESS); - - LLGLEnable normalize(GL_NORMALIZE); - - if (!mBaseModel.empty() && mVertexBuffer[5].empty()) - { - genBuffers(-1, skin_weight); - //genBuffers(3); - //genLODs(); - } - - if (!mModel[mPreviewLOD].empty()) - { - bool regen = mVertexBuffer[mPreviewLOD].empty(); - if (!regen) - { - const std::vector >& vb_vec = mVertexBuffer[mPreviewLOD].begin()->second; - if (!vb_vec.empty()) - { - const LLVertexBuffer* buff = vb_vec[0]; - regen = buff->hasDataType(LLVertexBuffer::TYPE_WEIGHT4) != skin_weight; - } - } - - if (regen) - { - genBuffers(mPreviewLOD, skin_weight); - } - - if (!skin_weight) - { - for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) - { - LLModelInstance& instance = *iter; - - LLModel* model = instance.mLOD[mPreviewLOD]; - - if (!model) - { - continue; - } - - gGL.pushMatrix(); - LLMatrix4 mat = instance.mTransform; - - glMultMatrixf((GLfloat*) mat.mMatrix); - - for (U32 i = 0; i < mVertexBuffer[mPreviewLOD][model].size(); ++i) - { - LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; - - buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); - - if (textures) - { - glColor4fv(instance.mMaterial[i].mDiffuseColor.mV); - if (i < instance.mMaterial.size() && instance.mMaterial[i].mDiffuseMap.notNull()) - { - gGL.getTexUnit(0)->bind(instance.mMaterial[i].mDiffuseMap, true); - if (instance.mMaterial[i].mDiffuseMap->getDiscardLevel() > -1) - { - mTextureSet.insert(instance.mMaterial[i].mDiffuseMap.get()); - } - } - } - else - { - glColor4f(1,1,1,1); - } - - buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - glColor3f(0.4f, 0.4f, 0.4f); - - if (edges) - { - glLineWidth(3.f); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glLineWidth(1.f); - } - } - gGL.popMatrix(); - } - - if (physics) - { - glClear(GL_DEPTH_BUFFER_BIT); - LLGLEnable blend(GL_BLEND); - gGL.blendFunc(LLRender::BF_ONE, LLRender::BF_ZERO); - - for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) - { - LLModelInstance& instance = *iter; - - LLModel* model = instance.mLOD[LLModel::LOD_PHYSICS]; - - if (!model) - { - continue; - } - - gGL.pushMatrix(); - LLMatrix4 mat = instance.mTransform; - - glMultMatrixf((GLfloat*) mat.mMatrix); - - - bool render_mesh = true; - - LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread; - if (decomp) - { - LLMutexLock(decomp->mMutex); - - std::map, std::vector > >::iterator iter = - mPhysicsMesh.find(model); - if (iter != mPhysicsMesh.end()) - { //render hull instead of mesh - render_mesh = false; - for (U32 i = 0; i < iter->second.size(); ++i) - { - if (explode > 0.f) - { - gGL.pushMatrix(); - - LLVector3 offset = model->mHullCenter[i]-model->mCenterOfHullCenters; - offset *= explode; - - gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]); - } - - static std::vector hull_colors; - - if (i+1 >= hull_colors.size()) - { - hull_colors.push_back(LLColor4U(rand()%128+127, rand()%128+127, rand()%128+127, 255)); - } - - LLVertexBuffer* buff = iter->second[i]; - if (buff) - { - buff->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL); - - glColor4ubv(hull_colors[i].mV); - buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts()); - } - - if (explode > 0.f) - { - gGL.popMatrix(); - } - } - } - } - - if (render_mesh) - { - if (mVertexBuffer[LLModel::LOD_PHYSICS].empty()) - { - genBuffers(LLModel::LOD_PHYSICS, false); - } - for (U32 i = 0; i < mVertexBuffer[LLModel::LOD_PHYSICS][model].size(); ++i) - { - LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][i]; - - buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); - - buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - glColor4f(0.4f, 0.4f, 0.0f, 0.4f); - - buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); - - glColor3f(1.f, 1.f, 0.f); - - glLineWidth(3.f); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glLineWidth(1.f); - } - } - - gGL.popMatrix(); - } - - gGL.setSceneBlendType(LLRender::BT_ALPHA); - } - } - else - { - LLVOAvatarSelf* avatar = gAgentAvatarp; - target_pos = avatar->getPositionAgent(); - - LLViewerCamera::getInstance()->setOriginAndLookAt( - target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + offset) * av_rot), // camera - LLVector3::z_axis, // up - target_pos); // point of interest - - if (joint_positions) - { - avatar->renderCollisionVolumes(); - } - - for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) - { - for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) - { - LLModelInstance& instance = *model_iter; - LLModel* model = instance.mModel; - - if (!model->mSkinWeights.empty()) - { - for (U32 i = 0; i < mVertexBuffer[mPreviewLOD][model].size(); ++i) - { - LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; - - const LLVolumeFace& face = model->getVolumeFace(i); - - LLStrider position; - buffer->getVertexStrider(position); - - LLStrider weight; - buffer->getWeight4Strider(weight); - - //quick 'n dirty software vertex skinning - - //build matrix palette - LLMatrix4 mat[64]; - for (U32 j = 0; j < model->mJointList.size(); ++j) - { - LLJoint* joint = avatar->getJoint(model->mJointList[j]); - if (joint) - { - mat[j] = model->mInvBindMatrix[j]; - mat[j] *= joint->getWorldMatrix(); - } - } - - for (U32 j = 0; j < buffer->getRequestedVerts(); ++j) - { - LLMatrix4 final_mat; - final_mat.mMatrix[0][0] = final_mat.mMatrix[1][1] = final_mat.mMatrix[2][2] = final_mat.mMatrix[3][3] = 0.f; - - LLVector4 wght; - S32 idx[4]; - - F32 scale = 0.f; - for (U32 k = 0; k < 4; k++) - { - F32 w = weight[j].mV[k]; - - idx[k] = (S32) floorf(w); - wght.mV[k] = w - floorf(w); - scale += wght.mV[k]; - } - - wght *= 1.f/scale; - - for (U32 k = 0; k < 4; k++) - { - F32* src = (F32*) mat[idx[k]].mMatrix; - F32* dst = (F32*) final_mat.mMatrix; - - F32 w = wght.mV[k]; - - for (U32 l = 0; l < 16; l++) - { - dst[l] += src[l]*w; - } - } - - //VECTORIZE THIS - LLVector3 v(face.mPositions[j].getF32ptr()); - - v = v * model->mBindShapeMatrix; - v = v * final_mat; - - position[j] = v; - } - - buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); - glColor4fv(instance.mMaterial[i].mDiffuseColor.mV); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); - glColor3f(0.4f, 0.4f, 0.4f); - - if (edges) - { - glLineWidth(3.f); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glLineWidth(1.f); - } - } - } - } - } - } - } - - gGL.popMatrix(); - - return TRUE; -} - -//----------------------------------------------------------------------------- -// refresh() -//----------------------------------------------------------------------------- -void LLModelPreview::refresh() -{ - mNeedsUpdate = TRUE; -} - -//----------------------------------------------------------------------------- -// rotate() -//----------------------------------------------------------------------------- -void LLModelPreview::rotate(F32 yaw_radians, F32 pitch_radians) -{ - mCameraYaw = mCameraYaw + yaw_radians; - - mCameraPitch = llclamp(mCameraPitch + pitch_radians, F_PI_BY_TWO * -0.8f, F_PI_BY_TWO * 0.8f); -} - -//----------------------------------------------------------------------------- -// zoom() -//----------------------------------------------------------------------------- -void LLModelPreview::zoom(F32 zoom_amt) -{ - F32 new_zoom = mCameraZoom+zoom_amt; - - mCameraZoom = llclamp(new_zoom, 1.f, 10.f); -} - -void LLModelPreview::pan(F32 right, F32 up) -{ - mCameraOffset.mV[VY] = llclamp(mCameraOffset.mV[VY] + right * mCameraDistance / mCameraZoom, -1.f, 1.f); - mCameraOffset.mV[VZ] = llclamp(mCameraOffset.mV[VZ] + up * mCameraDistance / mCameraZoom, -1.f, 1.f); -} - -void LLModelPreview::setPreviewLOD(S32 lod) -{ - lod = llclamp(lod, 0, (S32) LLModel::LOD_HIGH); - - if (lod != mPreviewLOD) - { - mPreviewLOD = lod; - - LLComboBox* combo_box = mFMP->getChild("preview_lod_combo"); - combo_box->setCurrentByIndex((NUM_LOD-1)-mPreviewLOD); // combo box list of lods is in reverse order - mFMP->childSetTextArg("lod_table_footer", "[DETAIL]", mFMP->getString(lod_name[mPreviewLOD])); - mFMP->childSetText("lod_file", mLODFile[mPreviewLOD]); - - // the wizard has three lod drop downs - LLComboBox* combo_box2 = mFMP->getChild("preview_lod_combo2"); - combo_box2->setCurrentByIndex((NUM_LOD-1)-mPreviewLOD); // combo box list of lods is in reverse order - - LLComboBox* combo_box3 = mFMP->getChild("preview_lod_combo3"); - combo_box2->setCurrentByIndex((NUM_LOD-1)-mPreviewLOD); // combo box list of lods is in reverse order - - LLColor4 highlight_color = LLUIColorTable::instance().getColor("MeshImportTableHighlightColor"); - LLColor4 normal_color = LLUIColorTable::instance().getColor("MeshImportTableNormalColor"); - - for (S32 i = 0; i <= LLModel::LOD_HIGH; ++i) - { - const LLColor4& color = (i == lod) ? highlight_color : normal_color; - - mFMP->childSetColor(lod_status_name[i], color); - mFMP->childSetColor(lod_label_name[i], color); - mFMP->childSetColor(lod_triangles_name[i], color); - mFMP->childSetColor(lod_vertices_name[i], color); - } - - LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; - if (fmp) - { - LLRadioGroup* radio = fmp->getChild("lod_file_or_limit"); - radio->selectNthItem(fmp->mLODMode[mPreviewLOD]); - } - } - refresh(); - updateStatusMessages(); -} - -//static -void LLFloaterModelPreview::onBrowseLOD(void* data) -{ - assert_main_thread(); - - LLFloaterModelPreview* mp = (LLFloaterModelPreview*) data; - mp->loadModel(mp->mModelPreview->mPreviewLOD); -} - -//static -void LLFloaterModelPreview::onUpload(void* user_data) -{ - assert_main_thread(); - - LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; - - if ( mp && mp->mModelPreview->mHasPivot ) - { - mp->mModelPreview->alterModelsPivot(); - } - - mp->mModelPreview->rebuildUploadData(); - - bool upload_skinweights = mp->childGetValue("upload_skin").asBoolean(); - bool upload_joint_positions = mp->childGetValue("upload_joints").asBoolean(); - - mp->mModelPreview->saveUploadData(upload_skinweights, upload_joint_positions); - - gMeshRepo.uploadModel(mp->mModelPreview->mUploadData, mp->mModelPreview->mPreviewScale, - mp->childGetValue("upload_textures").asBoolean(), upload_skinweights, upload_joint_positions); - - mp->closeFloater(false); -} - - -//static -void LLFloaterModelPreview::onClearMaterials(void* user_data) -{ - LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; - mp->mModelPreview->clearMaterials(); -} - -//static -void LLFloaterModelPreview::refresh(LLUICtrl* ctrl, void* user_data) -{ - sInstance->mModelPreview->mDirty = true; -} - -void LLFloaterModelPreview::updateResourceCost() -{ - U32 cost = mModelPreview->mResourceCost; - childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d",cost)); -} - -//static -void LLModelPreview::textureLoadedCallback( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata ) -{ - LLModelPreview* preview = (LLModelPreview*) userdata; - preview->refresh(); -} - -void LLModelPreview::onLODParamCommit(bool enforce_tri_limit) -{ - genLODs(mPreviewLOD, 3, enforce_tri_limit); - updateStatusMessages(); - refresh(); -} - -LLFloaterModelPreview::DecompRequest::DecompRequest(const std::string& stage, LLModel* mdl) -{ - mStage = stage; - mContinue = 1; - mModel = mdl; - mDecompID = &mdl->mDecompID; - mParams = sInstance->mDecompParams; - - //copy out positions and indices - if (mdl) - { - U16 index_offset = 0; - - mPositions.clear(); - mIndices.clear(); - - //queue up vertex positions and indices - for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) - { - const LLVolumeFace& face = mdl->getVolumeFace(i); - if (mPositions.size() + face.mNumVertices > 65535) - { - continue; - } - - for (U32 j = 0; j < face.mNumVertices; ++j) - { - mPositions.push_back(LLVector3(face.mPositions[j].getF32ptr())); - } - - for (U32 j = 0; j < face.mNumIndices; ++j) - { - mIndices.push_back(face.mIndices[j]+index_offset); - } - - index_offset += face.mNumVertices; - } - } -} - -void LLFloaterModelPreview::setStatusMessage(const std::string& msg) -{ - LLMutexLock lock(mStatusLock); - mStatusMessage = msg; -} - -S32 LLFloaterModelPreview::DecompRequest::statusCallback(const char* status, S32 p1, S32 p2) -{ - if (mContinue) - { - setStatusMessage(llformat("%s: %d/%d", status, p1, p2)); - if (LLFloaterModelPreview::sInstance) - { - LLFloaterModelPreview::sInstance->setStatusMessage(mStatusMessage); - } - } - - return mContinue; -} - -void LLFloaterModelPreview::DecompRequest::completed() -{ //called from the main thread - if (mContinue) - { - mModel->setConvexHullDecomposition(mHull); - - if (sInstance) - { - if (mContinue) - { - if (sInstance->mModelPreview) - { - sInstance->mModelPreview->mPhysicsMesh[mModel] = mHullMesh; - sInstance->mModelPreview->mDirty = true; - LLFloaterModelPreview::sInstance->mModelPreview->refresh(); - } - } - - sInstance->mCurRequest.erase(this); - } - } - else if (sInstance) - { - llassert(sInstance->mCurRequest.find(this) == sInstance->mCurRequest.end()); - } -} + fp->mModelPreview->calcResourceCost(); + fp->mModelPreview->refresh(); + fp->mModelPreview->resetPreviewTarget(); + fp->mModelPreview->clearBuffers(); +} + +//static +void LLFloaterModelPreview::onPreviewLODCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; + + if (!fp->mModelPreview) + { + return; + } + + S32 which_mode = 0; + + LLComboBox* combo = (LLComboBox*) ctrl; + + which_mode = (NUM_LOD-1)-combo->getFirstSelectedIndex(); // combo box list of lods is in reverse order + + fp->mModelPreview->setPreviewLOD(which_mode); +} + +//static +void LLFloaterModelPreview::onGenerateNormalsCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; + + fp->mModelPreview->generateNormals(); +} + +//static +void LLFloaterModelPreview::onExplodeCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview* fp = LLFloaterModelPreview::sInstance; + + fp->mModelPreview->refresh(); +} + +//static +void LLFloaterModelPreview::onAutoFillCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; + + fp->mModelPreview->genLODs(); +} + +//static +void LLFloaterModelPreview::onLODParamCommit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; + fp->mModelPreview->onLODParamCommit(false); +} + +//static +void LLFloaterModelPreview::onLODParamCommitTriangleLimit(LLUICtrl* ctrl, void* userdata) +{ + LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; + fp->mModelPreview->onLODParamCommit(true); +} + + +//----------------------------------------------------------------------------- +// draw() +//----------------------------------------------------------------------------- +void LLFloaterModelPreview::draw() +{ + LLFloater::draw(); + LLRect r = getRect(); + + mModelPreview->update(); + + if (!mModelPreview->mLoading) + { + childSetTextArg("status", "[STATUS]", getString("status_idle")); + } + + childSetTextArg("prim_cost", "[PRIM_COST]", llformat("%d", mModelPreview->mResourceCost)); + childSetTextArg("description_label", "[TEXTURES]", llformat("%d", mModelPreview->mTextureSet.size())); + + if (!mCurRequest.empty()) + { + LLMutexLock lock(mStatusLock); + childSetTextArg("status", "[STATUS]", mStatusMessage); + } + else + { + childSetVisible("Simplify", true); + childSetVisible("simplify_cancel", false); + childSetVisible("Decompose", true); + childSetVisible("decompose_cancel", false); + } + + U32 resource_cost = mModelPreview->mResourceCost*10; + + if (childGetValue("upload_textures").asBoolean()) + { + resource_cost += mModelPreview->mTextureSet.size()*10; + } + + childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d", resource_cost)); + + if (mModelPreview) + { + gGL.color3f(1.f, 1.f, 1.f); + + gGL.getTexUnit(0)->bind(mModelPreview); + + + LLView* preview_panel = getChild("preview_panel"); + + LLRect rect = preview_panel->getRect(); + if (rect != mPreviewRect) + { + mModelPreview->refresh(); + mPreviewRect = preview_panel->getRect(); + } + + gGL.begin( LLRender::QUADS ); + { + gGL.texCoord2f(0.f, 1.f); + gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mTop-1); + gGL.texCoord2f(0.f, 0.f); + gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mBottom); + gGL.texCoord2f(1.f, 0.f); + gGL.vertex2i(mPreviewRect.mRight-1, mPreviewRect.mBottom); + gGL.texCoord2f(1.f, 1.f); + gGL.vertex2i(mPreviewRect.mRight-1, mPreviewRect.mTop-1); + } + gGL.end(); + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + } +} + +//----------------------------------------------------------------------------- +// handleMouseDown() +//----------------------------------------------------------------------------- +BOOL LLFloaterModelPreview::handleMouseDown(S32 x, S32 y, MASK mask) +{ + if (mPreviewRect.pointInRect(x, y)) + { + bringToFront( x, y ); + gFocusMgr.setMouseCapture(this); + gViewerWindow->hideCursor(); + mLastMouseX = x; + mLastMouseY = y; + return TRUE; + } + + return LLFloater::handleMouseDown(x, y, mask); +} + +//----------------------------------------------------------------------------- +// handleMouseUp() +//----------------------------------------------------------------------------- +BOOL LLFloaterModelPreview::handleMouseUp(S32 x, S32 y, MASK mask) +{ + gFocusMgr.setMouseCapture(FALSE); + gViewerWindow->showCursor(); + return LLFloater::handleMouseUp(x, y, mask); +} + +//----------------------------------------------------------------------------- +// handleHover() +//----------------------------------------------------------------------------- +BOOL LLFloaterModelPreview::handleHover (S32 x, S32 y, MASK mask) +{ + MASK local_mask = mask & ~MASK_ALT; + + if (mModelPreview && hasMouseCapture()) + { + if (local_mask == MASK_PAN) + { + // pan here + mModelPreview->pan((F32)(x - mLastMouseX) * -0.005f, (F32)(y - mLastMouseY) * -0.005f); + } + else if (local_mask == MASK_ORBIT) + { + F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f; + F32 pitch_radians = (F32)(y - mLastMouseY) * 0.02f; + + mModelPreview->rotate(yaw_radians, pitch_radians); + } + else + { + + F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f; + F32 zoom_amt = (F32)(y - mLastMouseY) * 0.02f; + + mModelPreview->rotate(yaw_radians, 0.f); + mModelPreview->zoom(zoom_amt); + } + + + mModelPreview->refresh(); + + LLUI::setMousePositionLocal(this, mLastMouseX, mLastMouseY); + } + + if (!mPreviewRect.pointInRect(x, y) || !mModelPreview) + { + return LLFloater::handleHover(x, y, mask); + } + else if (local_mask == MASK_ORBIT) + { + gViewerWindow->setCursor(UI_CURSOR_TOOLCAMERA); + } + else if (local_mask == MASK_PAN) + { + gViewerWindow->setCursor(UI_CURSOR_TOOLPAN); + } + else + { + gViewerWindow->setCursor(UI_CURSOR_TOOLZOOMIN); + } + + return TRUE; +} + +//----------------------------------------------------------------------------- +// handleScrollWheel() +//----------------------------------------------------------------------------- +BOOL LLFloaterModelPreview::handleScrollWheel(S32 x, S32 y, S32 clicks) +{ + if (mPreviewRect.pointInRect(x, y) && mModelPreview) + { + mModelPreview->zoom((F32)clicks * -0.2f); + mModelPreview->refresh(); + } + + return TRUE; +} + +//static +void LLFloaterModelPreview::onPhysicsParamCommit(LLUICtrl* ctrl, void* data) +{ + if (LLConvexDecomposition::getInstance() == NULL) + { + llinfos << "convex decomposition tool is a stub on this platform. cannot get decomp." << llendl; + return; + } + + if (sInstance) + { + LLCDParam* param = (LLCDParam*) data; + std::string name(param->mName); + sInstance->mDecompParams[name] = ctrl->getValue(); + + if (name == "Simplify Method") + { + if (ctrl->getValue().asInteger() == 0) + { + sInstance->childSetVisible("Retain%", true); + sInstance->childSetVisible("Detail Scale", false); + } + else + { + sInstance->childSetVisible("Retain%", false); + sInstance->childSetVisible("Detail Scale", true); + } + } + } +} + +//static +void LLFloaterModelPreview::onPhysicsStageExecute(LLUICtrl* ctrl, void* data) +{ + LLCDStageData* stage_data = (LLCDStageData*) data; + std::string stage = stage_data->mName; + + if (sInstance) + { + if (!sInstance->mCurRequest.empty()) + { + llinfos << "Decomposition request still pending." << llendl; + return; + } + + if (sInstance->mModelPreview) + { + for (S32 i = 0; i < sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS].size(); ++i) + { + LLModel* mdl = sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS][i]; + DecompRequest* request = new DecompRequest(stage, mdl); + sInstance->mCurRequest.insert(request); + gMeshRepo.mDecompThread->submitRequest(request); + } + } + + if (stage == "Decompose") + { + sInstance->setStatusMessage(sInstance->getString("decomposing")); + sInstance->childSetVisible("Decompose", false); + sInstance->childSetVisible("decompose_cancel", true); + } + else if (stage == "Simplify") + { + sInstance->setStatusMessage(sInstance->getString("simplifying")); + sInstance->childSetVisible("Simplify", false); + sInstance->childSetVisible("simplify_cancel", true); + } + } +} + +//static +void LLFloaterModelPreview::onPhysicsBrowse(LLUICtrl* ctrl, void* userdata) +{ + sInstance->loadModel(LLModel::LOD_PHYSICS); +} + +//static +void LLFloaterModelPreview::onPhysicsUseLOD(LLUICtrl* ctrl, void* userdata) +{ + S32 which_mode = 3; + LLCtrlSelectionInterface* iface = sInstance->childGetSelectionInterface("physics_lod_combo"); + if (iface) + { + which_mode = iface->getFirstSelectedIndex(); + } + + sInstance->mModelPreview->setPhysicsFromLOD(which_mode); +} + +//static +void LLFloaterModelPreview::onCancel(LLUICtrl* ctrl, void* data) +{ + if (sInstance) + { + sInstance->closeFloater(false); + } +} + +//static +void LLFloaterModelPreview::onPhysicsStageCancel(LLUICtrl* ctrl, void*data) +{ + if (sInstance) + { + for (std::set >::iterator iter = sInstance->mCurRequest.begin(); + iter != sInstance->mCurRequest.end(); ++iter) + { + DecompRequest* req = *iter; + req->mContinue = 0; + } + + sInstance->mCurRequest.clear(); + } +} + +void LLFloaterModelPreview::initDecompControls() +{ + LLSD key; + + childSetCommitCallback("simplify_cancel", onPhysicsStageCancel, NULL); + childSetCommitCallback("decompose_cancel", onPhysicsStageCancel, NULL); + + childSetCommitCallback("physics_lod_combo", onPhysicsUseLOD, NULL); + childSetCommitCallback("physics_browse", onPhysicsBrowse, NULL); + + static const LLCDStageData* stage = NULL; + static S32 stage_count = 0; + + if (!stage && LLConvexDecomposition::getInstance() != NULL) + { + stage_count = LLConvexDecomposition::getInstance()->getStages(&stage); + } + + static const LLCDParam* param = NULL; + static S32 param_count = 0; + if (!param && LLConvexDecomposition::getInstance() != NULL) + { + param_count = LLConvexDecomposition::getInstance()->getParameters(¶m); + } + + for (S32 j = stage_count-1; j >= 0; --j) + { + LLButton* button = getChild(stage[j].mName); + if (button) + { + button->setCommitCallback(onPhysicsStageExecute, (void*) &stage[j]); + } + + gMeshRepo.mDecompThread->mStageID[stage[j].mName] = j; + // protected against stub by stage_count being 0 for stub above + LLConvexDecomposition::getInstance()->registerCallback(j, LLPhysicsDecomp::llcdCallback); + + //llinfos << "Physics decomp stage " << stage[j].mName << " (" << j << ") parameters:" << llendl; + //llinfos << "------------------------------------" << llendl; + + for (S32 i = 0; i < param_count; ++i) + { + if (param[i].mStage != j) + { + continue; + } + + std::string name(param[i].mName ? param[i].mName : ""); + std::string description(param[i].mDescription ? param[i].mDescription : ""); + + std::string type = "unknown"; + + llinfos << name << " - " << description << llendl; + + if (param[i].mType == LLCDParam::LLCD_FLOAT) + { + mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mFloat); + //llinfos << "Type: float, Default: " << param[i].mDefault.mFloat << llendl; + + LLSliderCtrl* slider = getChild(name); + if (slider) + { + slider->setMinValue(param[i].mDetails.mRange.mLow.mFloat); + slider->setMaxValue(param[i].mDetails.mRange.mHigh.mFloat); + slider->setIncrement(param[i].mDetails.mRange.mDelta.mFloat); + slider->setValue(param[i].mDefault.mFloat); + slider->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); + } + } + else if (param[i].mType == LLCDParam::LLCD_INTEGER) + { + mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue); + //llinfos << "Type: integer, Default: " << param[i].mDefault.mIntOrEnumValue << llendl; + + LLSliderCtrl* slider = getChild(name); + if (slider) + { + slider->setMinValue(param[i].mDetails.mRange.mLow.mIntOrEnumValue); + slider->setMaxValue(param[i].mDetails.mRange.mHigh.mIntOrEnumValue); + slider->setIncrement(param[i].mDetails.mRange.mDelta.mIntOrEnumValue); + slider->setValue(param[i].mDefault.mIntOrEnumValue); + slider->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); + } + } + else if (param[i].mType == LLCDParam::LLCD_BOOLEAN) + { + mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mBool); + //llinfos << "Type: boolean, Default: " << (param[i].mDefault.mBool ? "True" : "False") << llendl; + + LLCheckBoxCtrl* check_box = getChild(name); + if (check_box) + { + check_box->setValue(param[i].mDefault.mBool); + check_box->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); + } + } + else if (param[i].mType == LLCDParam::LLCD_ENUM) + { + mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue); + //llinfos << "Type: enum, Default: " << param[i].mDefault.mIntOrEnumValue << llendl; + + { //plug into combo box + + //llinfos << "Accepted values: " << llendl; + LLComboBox* combo_box = getChild(name); + for (S32 k = 0; k < param[i].mDetails.mEnumValues.mNumEnums; ++k) + { + //llinfos << param[i].mDetails.mEnumValues.mEnumsArray[k].mValue + // << " - " << param[i].mDetails.mEnumValues.mEnumsArray[k].mName << llendl; + + combo_box->add(param[i].mDetails.mEnumValues.mEnumsArray[k].mName, + LLSD::Integer(param[i].mDetails.mEnumValues.mEnumsArray[k].mValue)); + } + combo_box->setValue(param[i].mDefault.mIntOrEnumValue); + combo_box->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); + } + + //llinfos << "----" << llendl; + } + //llinfos << "-----------------------------" << llendl; + } + } + + childSetCommitCallback("physics_explode", LLFloaterModelPreview::onExplodeCommit, this); +} + +//----------------------------------------------------------------------------- +// onMouseCaptureLost() +//----------------------------------------------------------------------------- +// static +void LLFloaterModelPreview::onMouseCaptureLostModelPreview(LLMouseHandler* handler) +{ + gViewerWindow->showCursor(); +} + +//----------------------------------------------------------------------------- +// LLModelLoader +//----------------------------------------------------------------------------- +LLModelLoader::LLModelLoader(std::string filename, S32 lod, LLModelPreview* preview) +: LLThread("Model Loader"), mFilename(filename), mLod(lod), mPreview(preview), mFirstTransform(TRUE), mResetJoints( FALSE ) +{ + mJointMap["mPelvis"] = "mPelvis"; + mJointMap["mTorso"] = "mTorso"; + mJointMap["mChest"] = "mChest"; + mJointMap["mNeck"] = "mNeck"; + mJointMap["mHead"] = "mHead"; + mJointMap["mSkull"] = "mSkull"; + mJointMap["mEyeRight"] = "mEyeRight"; + mJointMap["mEyeLeft"] = "mEyeLeft"; + mJointMap["mCollarLeft"] = "mCollarLeft"; + mJointMap["mShoulderLeft"] = "mShoulderLeft"; + mJointMap["mElbowLeft"] = "mElbowLeft"; + mJointMap["mWristLeft"] = "mWristLeft"; + mJointMap["mCollarRight"] = "mCollarRight"; + mJointMap["mShoulderRight"] = "mShoulderRight"; + mJointMap["mElbowRight"] = "mElbowRight"; + mJointMap["mWristRight"] = "mWristRight"; + mJointMap["mHipRight"] = "mHipRight"; + mJointMap["mKneeRight"] = "mKneeRight"; + mJointMap["mAnkleRight"] = "mAnkleRight"; + mJointMap["mFootRight"] = "mFootRight"; + mJointMap["mToeRight"] = "mToeRight"; + mJointMap["mHipLeft"] = "mHipLeft"; + mJointMap["mKneeLeft"] = "mKneeLeft"; + mJointMap["mAnkleLeft"] = "mAnkleLeft"; + mJointMap["mFootLeft"] = "mFootLeft"; + mJointMap["mToeLeft"] = "mToeLeft"; + + mJointMap["avatar_mPelvis"] = "mPelvis"; + mJointMap["avatar_mTorso"] = "mTorso"; + mJointMap["avatar_mChest"] = "mChest"; + mJointMap["avatar_mNeck"] = "mNeck"; + mJointMap["avatar_mHead"] = "mHead"; + mJointMap["avatar_mSkull"] = "mSkull"; + mJointMap["avatar_mEyeRight"] = "mEyeRight"; + mJointMap["avatar_mEyeLeft"] = "mEyeLeft"; + mJointMap["avatar_mCollarLeft"] = "mCollarLeft"; + mJointMap["avatar_mShoulderLeft"] = "mShoulderLeft"; + mJointMap["avatar_mElbowLeft"] = "mElbowLeft"; + mJointMap["avatar_mWristLeft"] = "mWristLeft"; + mJointMap["avatar_mCollarRight"] = "mCollarRight"; + mJointMap["avatar_mShoulderRight"] = "mShoulderRight"; + mJointMap["avatar_mElbowRight"] = "mElbowRight"; + mJointMap["avatar_mWristRight"] = "mWristRight"; + mJointMap["avatar_mHipRight"] = "mHipRight"; + mJointMap["avatar_mKneeRight"] = "mKneeRight"; + mJointMap["avatar_mAnkleRight"] = "mAnkleRight"; + mJointMap["avatar_mFootRight"] = "mFootRight"; + mJointMap["avatar_mToeRight"] = "mToeRight"; + mJointMap["avatar_mHipLeft"] = "mHipLeft"; + mJointMap["avatar_mKneeLeft"] = "mKneeLeft"; + mJointMap["avatar_mAnkleLeft"] = "mAnkleLeft"; + mJointMap["avatar_mFootLeft"] = "mFootLeft"; + mJointMap["avatar_mToeLeft"] = "mToeLeft"; + + + mJointMap["hip"] = "mPelvis"; + mJointMap["abdomen"] = "mTorso"; + mJointMap["chest"] = "mChest"; + mJointMap["neck"] = "mNeck"; + mJointMap["head"] = "mHead"; + mJointMap["figureHair"] = "mSkull"; + mJointMap["lCollar"] = "mCollarLeft"; + mJointMap["lShldr"] = "mShoulderLeft"; + mJointMap["lForeArm"] = "mElbowLeft"; + mJointMap["lHand"] = "mWristLeft"; + mJointMap["rCollar"] = "mCollarRight"; + mJointMap["rShldr"] = "mShoulderRight"; + mJointMap["rForeArm"] = "mElbowRight"; + mJointMap["rHand"] = "mWristRight"; + mJointMap["rThigh"] = "mHipRight"; + mJointMap["rShin"] = "mKneeRight"; + mJointMap["rFoot"] = "mFootRight"; + mJointMap["lThigh"] = "mHipLeft"; + mJointMap["lShin"] = "mKneeLeft"; + mJointMap["lFoot"] = "mFootLeft"; + + //move into joint mapper class + mMasterJointList.push_front("mPelvis"); + mMasterJointList.push_front("mTorso"); + mMasterJointList.push_front("mChest"); + mMasterJointList.push_front("mNeck"); + mMasterJointList.push_front("mHead"); + mMasterJointList.push_front("mCollarLeft"); + mMasterJointList.push_front("mShoulderLeft"); + mMasterJointList.push_front("mElbowLeft"); + mMasterJointList.push_front("mWristLeft"); + mMasterJointList.push_front("mCollarRight"); + mMasterJointList.push_front("mShoulderRight"); + mMasterJointList.push_front("mElbowRight"); + mMasterJointList.push_front("mWristRight"); + mMasterJointList.push_front("mHipRight"); + mMasterJointList.push_front("mKneeRight"); + mMasterJointList.push_front("mFootRight"); + mMasterJointList.push_front("mHipLeft"); + mMasterJointList.push_front("mKneeLeft"); + mMasterJointList.push_front("mFootLeft"); + + if (mPreview) + { + //only try to load from slm if viewer is configured to do so and this is the + //initial model load (not an LoD or physics shape) + mTrySLM = gSavedSettings.getBOOL("MeshImportUseSLM") && mPreview->mBaseModel.empty(); + mPreview->setLoadState(STARTING); + } + else + { + mTrySLM = false; + } +} + +void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, BOOL& first_transform) +{ + LLVector4a box[] = + { + LLVector4a(-1, 1,-1), + LLVector4a(-1, 1, 1), + LLVector4a(-1,-1,-1), + LLVector4a(-1,-1, 1), + LLVector4a( 1, 1,-1), + LLVector4a( 1, 1, 1), + LLVector4a( 1,-1,-1), + LLVector4a( 1,-1, 1), + }; + + for (S32 j = 0; j < model->getNumVolumeFaces(); ++j) + { + const LLVolumeFace& face = model->getVolumeFace(j); + + LLVector4a center; + center.setAdd(face.mExtents[0], face.mExtents[1]); + center.mul(0.5f); + LLVector4a size; + size.setSub(face.mExtents[1],face.mExtents[0]); + size.mul(0.5f); + + for (U32 i = 0; i < 8; i++) + { + LLVector4a t; + t.setMul(size, box[i]); + t.add(center); + + LLVector4a v; + + mat.affineTransform(t, v); + + if (first_transform) + { + first_transform = FALSE; + min = max = v; + } + else + { + update_min_max(min, max, v); + } + } + } +} + +void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& max, BOOL& first_transform) +{ + LLVector4a mina, maxa; + LLMatrix4a mata; + + mata.loadu(mat); + mina.load3(min.mV); + maxa.load3(max.mV); + + stretch_extents(model, mata, mina, maxa, first_transform); + + min.set(mina.getF32ptr()); + max.set(maxa.getF32ptr()); +} + +void LLModelLoader::run() +{ + if (!doLoadModel()) + { + mPreview = NULL; + } + + doOnIdleOneTime(boost::bind(&LLModelLoader::loadModelCallback,this)); +} + +bool LLModelLoader::doLoadModel() +{ + //first, look for a .slm file of the same name that was modified later + //than the .dae + + if (mTrySLM) + { + std::string filename = mFilename; + + std::string::size_type i = filename.rfind("."); + if (i != std::string::npos) + { + filename.replace(i, filename.size()-1, ".slm"); + llstat slm_status; + if (LLFile::stat(filename, &slm_status) == 0) + { //slm file exists + llstat dae_status; + if (LLFile::stat(mFilename, &dae_status) != 0 || + dae_status.st_mtime < slm_status.st_mtime) + { + if (loadFromSLM(filename)) + { //slm successfully loaded, if this fails, fall through and + //try loading from dae + + mLod = -1; //successfully loading from an slm implicitly sets all + //LoDs + return true; + } + } + } + } + } + + //no suitable slm exists, load from the .dae file + DAE dae; + domCOLLADA* dom = dae.open(mFilename); + + if (!dom) + { + return false; + } + + daeDatabase* db = dae.getDatabase(); + + daeInt count = db->getElementCount(NULL, COLLADA_TYPE_MESH); + + daeDocument* doc = dae.getDoc(mFilename); + if (!doc) + { + llwarns << "can't find internal doc" << llendl; + return false; + } + + daeElement* root = doc->getDomRoot(); + if (!root) + { + llwarns << "document has no root" << llendl; + return false; + } + + //get unit scale + mTransform.setIdentity(); + + domAsset::domUnit* unit = daeSafeCast(root->getDescendant(daeElement::matchType(domAsset::domUnit::ID()))); + + if (unit) + { + F32 meter = unit->getMeter(); + mTransform.mMatrix[0][0] = meter; + mTransform.mMatrix[1][1] = meter; + mTransform.mMatrix[2][2] = meter; + } + + //get up axis rotation + LLMatrix4 rotation; + + domUpAxisType up = UPAXISTYPE_Y_UP; // default is Y_UP + domAsset::domUp_axis* up_axis = + daeSafeCast(root->getDescendant(daeElement::matchType(domAsset::domUp_axis::ID()))); + + if (up_axis) + { + up = up_axis->getValue(); + } + + if (up == UPAXISTYPE_X_UP) + { + rotation.initRotation(0.0f, 90.0f * DEG_TO_RAD, 0.0f); + } + else if (up == UPAXISTYPE_Y_UP) + { + rotation.initRotation(90.0f * DEG_TO_RAD, 0.0f, 0.0f); + } + + rotation *= mTransform; + mTransform = rotation; + + + for (daeInt idx = 0; idx < count; ++idx) + { //build map of domEntities to LLModel + domMesh* mesh = NULL; + db->getElement((daeElement**) &mesh, idx, NULL, COLLADA_TYPE_MESH); + + if (mesh) + { + LLPointer model = LLModel::loadModelFromDomMesh(mesh); + + if (model.notNull() && validate_model(model)) + { + mModelList.push_back(model); + mModel[mesh] = model; + } + } + } + + count = db->getElementCount(NULL, COLLADA_TYPE_SKIN); + for (daeInt idx = 0; idx < count; ++idx) + { //add skinned meshes as instances + domSkin* skin = NULL; + db->getElement((daeElement**) &skin, idx, NULL, COLLADA_TYPE_SKIN); + + if (skin) + { + domGeometry* geom = daeSafeCast(skin->getSource().getElement()); + + if (geom) + { + domMesh* mesh = geom->getMesh(); + if (mesh) + { + LLModel* model = mModel[mesh]; + if (model) + { + LLVector3 mesh_scale_vector; + LLVector3 mesh_translation_vector; + model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); + + LLMatrix4 normalized_transformation; + normalized_transformation.setTranslation(mesh_translation_vector); + + LLMatrix4 mesh_scale; + mesh_scale.initScale(mesh_scale_vector); + mesh_scale *= normalized_transformation; + normalized_transformation = mesh_scale; + + glh::matrix4f inv_mat((F32*) normalized_transformation.mMatrix); + inv_mat = inv_mat.inverse(); + LLMatrix4 inverse_normalized_transformation(inv_mat.m); + + domSkin::domBind_shape_matrix* bind_mat = skin->getBind_shape_matrix(); + + if (bind_mat) + { //get bind shape matrix + domFloat4x4& dom_value = bind_mat->getValue(); + + for (int i = 0; i < 4; i++) + { + for(int j = 0; j < 4; j++) + { + model->mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j*4]; + } + } + + LLMatrix4 trans = normalized_transformation; + trans *= model->mBindShapeMatrix; + model->mBindShapeMatrix = trans; + + } + + + //The joint transfom map that we'll populate below + std::map jointTransforms; + jointTransforms.clear(); + + //Some collada setup for accessing the skeleton + daeElement* pElement = 0; + dae.getDatabase()->getElement( &pElement, 0, 0, "skeleton" ); + + //Try to get at the skeletal instance controller + domInstance_controller::domSkeleton* pSkeleton = daeSafeCast( pElement ); + bool missingSkeletonOrScene = false; + + //If no skeleton, do a breadth-first search to get at specific joints + bool rootNode = false; + bool skeletonWithNoRootNode = false; + + //Need to test for a skeleton that does not have a root node + //This occurs when your instance controller does not have an associated scene + if ( pSkeleton ) + { + daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement(); + if ( pSkeletonRootNode ) + { + rootNode = true; + } + else + { + skeletonWithNoRootNode = true; + } + + } + if ( !pSkeleton || !rootNode ) + { + daeElement* pScene = root->getDescendant("visual_scene"); + if ( !pScene ) + { + llwarns<<"No visual scene - unable to parse bone offsets "< > children = pScene->getChildren(); + S32 childCount = children.getCount(); + + //Process any children that are joints + //Not all children are joints, some code be ambient lights, cameras, geometry etc.. + for (S32 i = 0; i < childCount; ++i) + { + domNode* pNode = daeSafeCast(children[i]); + if ( isNodeAJoint( pNode ) ) + { + processJointNode( pNode, jointTransforms ); + } + } + } + } + else + //Has Skeleton + { + //Get the root node of the skeleton + daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement(); + if ( pSkeletonRootNode ) + { + //Once we have the root node - start acccessing it's joint components + const int jointCnt = mJointMap.size(); + std::map :: const_iterator jointIt = mJointMap.begin(); + + //Loop over all the possible joints within the .dae - using the allowed joint list in the ctor. + for ( int i=0; i( resolver.getElement() ); + if ( pJoint ) + { + //Pull out the translate id and store it in the jointTranslations map + daeSIDResolver jointResolver( pJoint, "./translate" ); + domTranslate* pTranslate = daeSafeCast( jointResolver.getElement() ); + + LLMatrix4 workingTransform; + + //Translation via SID + if ( pTranslate ) + { + extractTranslation( pTranslate, workingTransform ); + } + else + { + //Translation via child from element + daeElement* pTranslateElement = getChildFromElement( pJoint, "translate" ); + if ( pTranslateElement && pTranslateElement->typeID() != domTranslate::ID() ) + { + llwarns<< "The found element is not a translate node" <getJoints(); + + domInputLocal_Array& joint_input = joints->getInput_array(); + + for (size_t i = 0; i < joint_input.getCount(); ++i) + { + domInputLocal* input = joint_input.get(i); + xsNMTOKEN semantic = input->getSemantic(); + + if (strcmp(semantic, COMMON_PROFILE_INPUT_JOINT) == 0) + { //found joint source, fill model->mJointMap and model->mJointList + daeElement* elem = input->getSource().getElement(); + + domSource* source = daeSafeCast(elem); + if (source) + { + + + domName_array* names_source = source->getName_array(); + + if (names_source) + { + domListOfNames &names = names_source->getValue(); + + for (size_t j = 0; j < names.getCount(); ++j) + { + std::string name(names.get(j)); + if (mJointMap.find(name) != mJointMap.end()) + { + name = mJointMap[name]; + } + model->mJointList.push_back(name); + model->mJointMap[name] = j; + } + } + else + { + domIDREF_array* names_source = source->getIDREF_array(); + if (names_source) + { + xsIDREFS& names = names_source->getValue(); + + for (size_t j = 0; j < names.getCount(); ++j) + { + std::string name(names.get(j).getID()); + if (mJointMap.find(name) != mJointMap.end()) + { + name = mJointMap[name]; + } + model->mJointList.push_back(name); + model->mJointMap[name] = j; + } + } + } + } + } + else if (strcmp(semantic, COMMON_PROFILE_INPUT_INV_BIND_MATRIX) == 0) + { //found inv_bind_matrix array, fill model->mInvBindMatrix + domSource* source = daeSafeCast(input->getSource().getElement()); + if (source) + { + domFloat_array* t = source->getFloat_array(); + if (t) + { + domListOfFloats& transform = t->getValue(); + S32 count = transform.getCount()/16; + + for (S32 k = 0; k < count; ++k) + { + LLMatrix4 mat; + + for (int i = 0; i < 4; i++) + { + for(int j = 0; j < 4; j++) + { + mat.mMatrix[i][j] = transform[k*16 + i + j*4]; + } + } + + model->mInvBindMatrix.push_back(mat); + } + } + } + } + } + + //Now that we've parsed the joint array, let's determine if we have a full rig + //(which means we have all the joints that are required for an avatar versus + //a skinned asset attached to a node in a file that contains an entire skeleton, + //but does not use the skeleton). + mPreview->setRigValid( doesJointArrayContainACompleteRig( model->mJointList ) ); + if ( !skeletonWithNoRootNode && !model->mJointList.empty() && mPreview->isRigValid() ) + { + mResetJoints = true; + } + + if ( !missingSkeletonOrScene ) + { + //Set the joint translations on the avatar - if it's a full mapping + //The joints are reset in the dtor + if ( mResetJoints ) + { + std::map :: const_iterator masterJointIt = mJointMap.begin(); + std::map :: const_iterator masterJointItEnd = mJointMap.end(); + for (;masterJointIt!=masterJointItEnd;++masterJointIt ) + { + std::string lookingForJoint = (*masterJointIt).first.c_str(); + + if ( jointTransforms.find( lookingForJoint ) != jointTransforms.end() ) + { + //llinfos<<"joint "<getJoint( lookingForJoint ); + if ( pJoint ) + { + pJoint->storeCurrentXform( jointTransform.getTranslation() ); + } + else + { + //Most likely an error in the asset. + llwarns<<"Tried to apply joint position from .dae, but it did not exist in the avatar rig." << llendl; + } + } + } + } + } //missingSkeletonOrScene + + //We need to construct the alternate bind matrix (which contains the new joint positions) + //in the same order as they were stored in the joint buffer. The joints associated + //with the skeleton are not stored in the same order as they are in the exported joint buffer. + //This remaps the skeletal joints to be in the same order as the joints stored in the model. + std::vector :: const_iterator jointIt = model->mJointList.begin(); + const int jointCnt = model->mJointList.size(); + for ( int i=0; imInvBindMatrix[i]; + newInverse.setTranslation( jointTransforms[lookingForJoint].getTranslation() ); + model->mAlternateBindMatrix.push_back( newInverse ); + } + else + { + llwarns<<"Possibly misnamed/missing joint [" <getVertices(); + if (verts) + { + domInputLocal_Array& inputs = verts->getInput_array(); + for (size_t i = 0; i < inputs.getCount() && model->mPosition.empty(); ++i) + { + if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_POSITION) == 0) + { + domSource* pos_source = daeSafeCast(inputs[i]->getSource().getElement()); + if (pos_source) + { + domFloat_array* pos_array = pos_source->getFloat_array(); + if (pos_array) + { + domListOfFloats& pos = pos_array->getValue(); + + for (size_t j = 0; j < pos.getCount(); j += 3) + { + if (pos.getCount() <= j+2) + { + llerrs << "WTF?" << llendl; + } + + LLVector3 v(pos[j], pos[j+1], pos[j+2]); + + //transform from COLLADA space to volume space + v = v * inverse_normalized_transformation; + + model->mPosition.push_back(v); + } + } + } + } + } + } + + //grab skin weights array + domSkin::domVertex_weights* weights = skin->getVertex_weights(); + if (weights) + { + domInputLocalOffset_Array& inputs = weights->getInput_array(); + domFloat_array* vertex_weights = NULL; + for (size_t i = 0; i < inputs.getCount(); ++i) + { + if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_WEIGHT) == 0) + { + domSource* weight_source = daeSafeCast(inputs[i]->getSource().getElement()); + if (weight_source) + { + vertex_weights = weight_source->getFloat_array(); + } + } + } + + if (vertex_weights) + { + domListOfFloats& w = vertex_weights->getValue(); + domListOfUInts& vcount = weights->getVcount()->getValue(); + domListOfInts& v = weights->getV()->getValue(); + + U32 c_idx = 0; + for (size_t vc_idx = 0; vc_idx < vcount.getCount(); ++vc_idx) + { //for each vertex + daeUInt count = vcount[vc_idx]; + + //create list of weights that influence this vertex + LLModel::weight_list weight_list; + + for (daeUInt i = 0; i < count; ++i) + { //for each weight + daeInt joint_idx = v[c_idx++]; + daeInt weight_idx = v[c_idx++]; + + if (joint_idx == -1) + { + //ignore bindings to bind_shape_matrix + continue; + } + + F32 weight_value = w[weight_idx]; + + weight_list.push_back(LLModel::JointWeight(joint_idx, weight_value)); + } + + //sort by joint weight + std::sort(weight_list.begin(), weight_list.end(), LLModel::CompareWeightGreater()); + + std::vector wght; + + F32 total = 0.f; + + for (U32 i = 0; i < llmin((U32) 4, (U32) weight_list.size()); ++i) + { //take up to 4 most significant weights + if (weight_list[i].mWeight > 0.f) + { + wght.push_back( weight_list[i] ); + total += weight_list[i].mWeight; + } + } + + F32 scale = 1.f/total; + if (scale != 1.f) + { //normalize weights + for (U32 i = 0; i < wght.size(); ++i) + { + wght[i].mWeight *= scale; + } + } + + model->mSkinWeights[model->mPosition[vc_idx]] = wght; + } + + //add instance to scene for this model + + LLMatrix4 transformation = mTransform; + // adjust the transformation to compensate for mesh normalization + + LLMatrix4 mesh_translation; + mesh_translation.setTranslation(mesh_translation_vector); + mesh_translation *= transformation; + transformation = mesh_translation; + + LLMatrix4 mesh_scale; + mesh_scale.initScale(mesh_scale_vector); + mesh_scale *= transformation; + transformation = mesh_scale; + + std::vector materials; + materials.resize(model->getNumVolumeFaces()); + mScene[transformation].push_back(LLModelInstance(model, model->mLabel, transformation, materials)); + stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); + } + } + } + } + } + } + } + + daeElement* scene = root->getDescendant("visual_scene"); + + if (!scene) + { + llwarns << "document has no visual_scene" << llendl; + setLoadState( ERROR_PARSING ); + return false; + } + setLoadState( DONE ); + + processElement(scene); + + handlePivotPoint( root ); + + return true; +} + +void LLModelLoader::setLoadState(U32 state) +{ + if (mPreview) + { + mPreview->setLoadState(state); + } +} + +bool LLModelLoader::loadFromSLM(const std::string& filename) +{ + //only need to populate mScene with data from slm + llstat stat; + + if (LLFile::stat(filename, &stat)) + { //file does not exist + return false; + } + + S32 file_size = (S32) stat.st_size; + + llifstream ifstream(filename, std::ifstream::in | std::ifstream::binary); + LLSD data; + LLSDSerialize::fromBinary(data, ifstream, file_size); + ifstream.close(); + + //build model list for each LoD + model_list model[LLModel::NUM_LODS]; + + LLSD& mesh = data["mesh"]; + + LLVolumeParams volume_params; + volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); + + for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) + { + for (U32 i = 0; i < mesh.size(); ++i) + { + std::stringstream str(mesh[i].asString()); + LLPointer loaded_model = new LLModel(volume_params, (F32) lod); + if (loaded_model->createVolumeFacesFromStream(str)) + { + loaded_model->mLocalID = i; + model[lod].push_back(loaded_model); + } + else + { + llassert(model[lod].empty()); + } + } + } + + if (model[LLModel::LOD_HIGH].empty()) + { //failed to load high lod + return false; + } + + //load instance list + model_instance_list instance_list; + + LLSD& instance = data["instance"]; + + for (U32 i = 0; i < instance.size(); ++i) + { + //deserialize instance list + instance_list.push_back(LLModelInstance(instance[i])); + + //match up model instance pointers + S32 idx = instance_list[i].mLocalMeshID; + + for (U32 lod = 0; lod < LLModel::NUM_LODS; ++lod) + { + if (!model[lod].empty()) + { + instance_list[i].mLOD[lod] = model[lod][idx]; + } + } + + instance_list[i].mModel = model[LLModel::LOD_HIGH][idx]; + } + + + //convert instance_list to mScene + mFirstTransform = TRUE; + for (U32 i = 0; i < instance_list.size(); ++i) + { + LLModelInstance& cur_instance = instance_list[i]; + mScene[cur_instance.mTransform].push_back(cur_instance); + stretch_extents(cur_instance.mModel, cur_instance.mTransform, mExtents[0], mExtents[1], mFirstTransform); + } + + return true; +} + +void LLModelLoader::loadModelCallback() +{ + if (mPreview) + { + mPreview->loadModelCallback(mLod); + } + + while (!isStopped()) + { //wait until this thread is stopped before deleting self + apr_sleep(100); + } + + delete this; +} + +void LLModelLoader::handlePivotPoint( daeElement* pRoot ) +{ + //Import an optional pivot point - a pivot point is just a node in the visual scene named "AssetPivot" + //If no assetpivot is found then the asset will use the SL default + daeElement* pScene = pRoot->getDescendant("visual_scene"); + if ( pScene ) + { + daeTArray< daeSmartRef > children = pScene->getChildren(); + S32 childCount = children.getCount(); + for (S32 i = 0; i < childCount; ++i) + { + domNode* pNode = daeSafeCast(children[i]); + if ( pNode && isNodeAPivotPoint( pNode ) ) + { + LLMatrix4 workingTransform; + daeSIDResolver nodeResolver( pNode, "./translate" ); + domTranslate* pTranslate = daeSafeCast( nodeResolver.getElement() ); + //Translation via SID was successful + //todo#extract via element as well + if ( pTranslate ) + { + extractTranslation( pTranslate, workingTransform ); + mPreview->setModelPivot( workingTransform.getTranslation() ); + mPreview->setHasPivot( true ); + } + } + } + } +} + +bool LLModelLoader::doesJointArrayContainACompleteRig( const std::vector &jointListFromModel ) +{ + std::deque :: const_iterator masterJointIt = mMasterJointList.begin(); + std::deque :: const_iterator masterJointEndIt = mMasterJointList.end(); + + std::vector :: const_iterator modelJointIt = jointListFromModel.begin(); + std::vector :: const_iterator modelJointItEnd = jointListFromModel.end(); + + bool found = false; + for ( ;masterJointIt!=masterJointEndIt;++masterJointIt ) + { + found = false; + modelJointIt = jointListFromModel.begin(); + for ( ;modelJointIt!=modelJointItEnd; ++modelJointIt ) + { + if ( *masterJointIt == *modelJointIt ) + { + found = true; + break; + } + } + if ( !found ) + { + llinfos<<" Asset did not contain the joint (if you're u/l a fully rigged asset - it is required)." << *masterJointIt<< llendl; + break; + } + } + + return found; +} + +//called in the main thread +void LLModelLoader::loadTextures() +{ + BOOL is_paused = isPaused() ; + pause() ; //pause the loader + + for(scene::iterator iter = mScene.begin(); iter != mScene.end(); ++iter) + { + for(U32 i = 0 ; i < iter->second.size(); i++) + { + for(U32 j = 0 ; j < iter->second[i].mMaterial.size() ; j++) + { + if(!iter->second[i].mMaterial[j].mDiffuseMapFilename.empty()) + { + iter->second[i].mMaterial[j].mDiffuseMap = + LLViewerTextureManager::getFetchedTextureFromUrl("file://" + iter->second[i].mMaterial[j].mDiffuseMapFilename, TRUE, LLViewerTexture::BOOST_PREVIEW); + iter->second[i].mMaterial[j].mDiffuseMap->setLoadedCallback(LLModelPreview::textureLoadedCallback, 0, TRUE, FALSE, mPreview, NULL, FALSE); + iter->second[i].mMaterial[j].mDiffuseMap->forceToSaveRawImage(); + } + } + } + } + + if(!is_paused) + { + unpause() ; + } +} + +bool LLModelLoader::isNodeAJoint( domNode* pNode ) +{ + if ( pNode->getName() == NULL) + { + return false; + } + + if ( mJointMap.find( pNode->getName() ) != mJointMap.end() ) + { + return true; + } + + return false; +} + +bool LLModelLoader::isNodeAPivotPoint( domNode* pNode ) +{ + bool result = false; + + if ( pNode && pNode->getName() ) + { + std::string name = pNode->getName(); + if ( name == "AssetPivot" ) + { + result = true; + } + else + { + result = false; + } + } + return result; +} + +void LLModelLoader::extractTranslation( domTranslate* pTranslate, LLMatrix4& transform ) +{ + domFloat3 jointTrans = pTranslate->getValue(); + LLVector3 singleJointTranslation( jointTrans[0], jointTrans[1], jointTrans[2] ); + transform.setTranslation( singleJointTranslation ); +} + +void LLModelLoader::extractTranslationViaElement( daeElement* pTranslateElement, LLMatrix4& transform ) +{ + domTranslate* pTranslateChild = dynamic_cast( pTranslateElement ); + domFloat3 translateChild = pTranslateChild->getValue(); + LLVector3 singleJointTranslation( translateChild[0], translateChild[1], translateChild[2] ); + transform.setTranslation( singleJointTranslation ); +} + +void LLModelLoader::processJointNode( domNode* pNode, std::map& jointTransforms ) +{ + if (pNode->getName() == NULL) + { + llwarns << "nameless node, can't process" << llendl; + return; + } + + //llwarns<<"ProcessJointNode# Node:" <getName()<( jointResolver.getElement() ); + + //Translation via SID was successful + if ( pTranslate ) + { + extractTranslation( pTranslate, workingTransform ); + } + else + { + //Translation via child from element + daeElement* pTranslateElement = getChildFromElement( pNode, "translate" ); + if ( !pTranslateElement || pTranslateElement->typeID() != domTranslate::ID() ) + { + //llwarns<< "The found element is not a translate node" <( jointResolver.getElement() ); + if ( pMatrix ) + { + //llinfos<<"A matrix SID was however found!"<getValue(); + for ( int i = 0; i < 4; i++ ) + { + for( int j = 0; j < 4; j++ ) + { + workingTransform.mMatrix[i][j] = domArray[i + j*4]; + } + } + } + else + { + llwarns<< "The found element is not translate or matrix node - most likely a corrupt export!" <getName() ] = workingTransform; + + //2. handle the nodes children + + //Gather and handle the incoming nodes children + daeTArray< daeSmartRef > childOfChild = pNode->getChildren(); + S32 childOfChildCount = childOfChild.getCount(); + + for (S32 i = 0; i < childOfChildCount; ++i) + { + domNode* pChildNode = daeSafeCast( childOfChild[i] ); + if ( pChildNode ) + { + processJointNode( pChildNode, jointTransforms ); + } + } +} + +daeElement* LLModelLoader::getChildFromElement( daeElement* pElement, std::string const & name ) +{ + daeElement* pChildOfElement = pElement->getChild( name.c_str() ); + if ( pChildOfElement ) + { + return pChildOfElement; + } + llwarns<< "Could not find a child [" << name << "] for the element: \"" << pElement->getAttribute("id") << "\"" << llendl; + return NULL; +} + +void LLModelLoader::processElement(daeElement* element) +{ + LLMatrix4 saved_transform = mTransform; + + domTranslate* translate = daeSafeCast(element); + if (translate) + { + domFloat3 dom_value = translate->getValue(); + + LLMatrix4 translation; + translation.setTranslation(LLVector3(dom_value[0], dom_value[1], dom_value[2])); + + translation *= mTransform; + mTransform = translation; + } + + domRotate* rotate = daeSafeCast(element); + if (rotate) + { + domFloat4 dom_value = rotate->getValue(); + + LLMatrix4 rotation; + rotation.initRotTrans(dom_value[3] * DEG_TO_RAD, LLVector3(dom_value[0], dom_value[1], dom_value[2]), LLVector3(0, 0, 0)); + + rotation *= mTransform; + mTransform = rotation; + } + + domScale* scale = daeSafeCast(element); + if (scale) + { + domFloat3 dom_value = scale->getValue(); + + LLMatrix4 scaling; + scaling.initScale(LLVector3(dom_value[0], dom_value[1], dom_value[2])); + + scaling *= mTransform; + mTransform = scaling; + } + + domMatrix* matrix = daeSafeCast(element); + if (matrix) + { + domFloat4x4 dom_value = matrix->getValue(); + + LLMatrix4 matrix_transform; + + for (int i = 0; i < 4; i++) + { + for(int j = 0; j < 4; j++) + { + matrix_transform.mMatrix[i][j] = dom_value[i + j*4]; + } + } + + matrix_transform *= mTransform; + mTransform = matrix_transform; + } + + domInstance_geometry* instance_geo = daeSafeCast(element); + if (instance_geo) + { + domGeometry* geo = daeSafeCast(instance_geo->getUrl().getElement()); + if (geo) + { + domMesh* mesh = daeSafeCast(geo->getDescendant(daeElement::matchType(domMesh::ID()))); + if (mesh) + { + LLModel* model = mModel[mesh]; + if (model) + { + LLMatrix4 transformation = mTransform; + + std::vector materials = getMaterials(model, instance_geo); + + // adjust the transformation to compensate for mesh normalization + LLVector3 mesh_scale_vector; + LLVector3 mesh_translation_vector; + model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); + + LLMatrix4 mesh_translation; + mesh_translation.setTranslation(mesh_translation_vector); + mesh_translation *= transformation; + transformation = mesh_translation; + + LLMatrix4 mesh_scale; + mesh_scale.initScale(mesh_scale_vector); + mesh_scale *= transformation; + transformation = mesh_scale; + + std::string label = getElementLabel(instance_geo); + mScene[transformation].push_back(LLModelInstance(model, label, transformation, materials)); + + stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); + } + } + } + } + + domInstance_node* instance_node = daeSafeCast(element); + if (instance_node) + { + daeElement* instance = instance_node->getUrl().getElement(); + if (instance) + { + processElement(instance); + } + } + + //process children + daeTArray< daeSmartRef > children = element->getChildren(); + for (S32 i = 0; i < children.getCount(); i++) + { + processElement(children[i]); + } + + domNode* node = daeSafeCast(element); + if (node) + { //this element was a node, restore transform before processiing siblings + mTransform = saved_transform; + } +} + +std::vector LLModelLoader::getMaterials(LLModel* model, domInstance_geometry* instance_geo) +{ + std::vector materials; + for (int i = 0; i < model->mMaterialList.size(); i++) + { + LLImportMaterial import_material; + + domInstance_material* instance_mat = NULL; + + domBind_material::domTechnique_common* technique = + daeSafeCast(instance_geo->getDescendant(daeElement::matchType(domBind_material::domTechnique_common::ID()))); + + if (technique) + { + daeTArray< daeSmartRef > inst_materials = technique->getChildrenByType(); + for (int j = 0; j < inst_materials.getCount(); j++) + { + std::string symbol(inst_materials[j]->getSymbol()); + + if (symbol == model->mMaterialList[i]) // found the binding + { + instance_mat = inst_materials[j]; + } + } + } + + if (instance_mat) + { + domMaterial* material = daeSafeCast(instance_mat->getTarget().getElement()); + if (material) + { + domInstance_effect* instance_effect = + daeSafeCast(material->getDescendant(daeElement::matchType(domInstance_effect::ID()))); + if (instance_effect) + { + domEffect* effect = daeSafeCast(instance_effect->getUrl().getElement()); + if (effect) + { + domProfile_COMMON* profile = + daeSafeCast(effect->getDescendant(daeElement::matchType(domProfile_COMMON::ID()))); + if (profile) + { + import_material = profileToMaterial(profile); + } + } + } + } + } + + materials.push_back(import_material); + } + + return materials; +} + +LLImportMaterial LLModelLoader::profileToMaterial(domProfile_COMMON* material) +{ + LLImportMaterial mat; + mat.mFullbright = FALSE; + + daeElement* diffuse = material->getDescendant("diffuse"); + if (diffuse) + { + domCommon_color_or_texture_type_complexType::domTexture* texture = + daeSafeCast(diffuse->getDescendant("texture")); + if (texture) + { + domCommon_newparam_type_Array newparams = material->getNewparam_array(); + for (S32 i = 0; i < newparams.getCount(); i++) + { + domFx_surface_common* surface = newparams[i]->getSurface(); + if (surface) + { + domFx_surface_init_common* init = surface->getFx_surface_init_common(); + if (init) + { + domFx_surface_init_from_common_Array init_from = init->getInit_from_array(); + + if (init_from.getCount() > i) + { + domImage* image = daeSafeCast(init_from[i]->getValue().getElement()); + if (image) + { + // we only support init_from now - embedded data will come later + domImage::domInit_from* init = image->getInit_from(); + if (init) + { + mat.mDiffuseMapFilename = cdom::uriToNativePath(init->getValue().str()); + mat.mDiffuseMapLabel = getElementLabel(material); + } + } + } + } + } + } + } + + domCommon_color_or_texture_type_complexType::domColor* color = + daeSafeCast(diffuse->getDescendant("color")); + if (color) + { + domFx_color_common domfx_color = color->getValue(); + LLColor4 value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]); + mat.mDiffuseColor = value; + } + } + + daeElement* emission = material->getDescendant("emission"); + if (emission) + { + LLColor4 emission_color = getDaeColor(emission); + if (((emission_color[0] + emission_color[1] + emission_color[2]) / 3.0) > 0.25) + { + mat.mFullbright = TRUE; + } + } + + return mat; +} + +// try to get a decent label for this element +std::string LLModelLoader::getElementLabel(daeElement *element) +{ + // if we have a name attribute, use it + std::string name = element->getAttribute("name"); + if (name.length()) + { + return name; + } + + // if we have an ID attribute, use it + if (element->getID()) + { + return std::string(element->getID()); + } + + // if we have a parent, use it + daeElement* parent = element->getParent(); + if (parent) + { + // if parent has a name, use it + std::string name = parent->getAttribute("name"); + if (name.length()) + { + return name; + } + + // if parent has an ID, use it + if (parent->getID()) + { + return std::string(parent->getID()); + } + } + + // try to use our type + daeString element_name = element->getElementName(); + if (element_name) + { + return std::string(element_name); + } + + // if all else fails, use "object" + return std::string("object"); +} + +LLColor4 LLModelLoader::getDaeColor(daeElement* element) +{ + LLColor4 value; + domCommon_color_or_texture_type_complexType::domColor* color = + daeSafeCast(element->getDescendant("color")); + if (color) + { + domFx_color_common domfx_color = color->getValue(); + value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]); + } + + return value; +} + +//----------------------------------------------------------------------------- +// LLModelPreview +//----------------------------------------------------------------------------- + +LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) +: LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE), LLMutex(NULL) +, mPelvisZOffset( 0.0f ) +, mRigValid( false ) +{ + mNeedsUpdate = TRUE; + mCameraDistance = 0.f; + mCameraYaw = 0.f; + mCameraPitch = 0.f; + mCameraZoom = 1.f; + mTextureName = 0; + mPreviewLOD = 0; + mModelLoader = NULL; + mMaxTriangleLimit = 0; + mDirty = false; + mGenLOD = false; + mLoading = false; + mLoadState = LLModelLoader::STARTING; + mGroup = 0; + mBuildShareTolerance = 0.f; + mBuildQueueMode = GLOD_QUEUE_GREEDY; + mBuildBorderMode = GLOD_BORDER_UNLOCK; + mBuildOperator = GLOD_OPERATOR_EDGE_COLLAPSE; + + for (U32 i = 0; i < LLModel::NUM_LODS; ++i) + { + mRequestedTriangleCount[i] = 0; + } + + mViewOption["show_textures"] = false; + + mFMP = fmp; + + mHasPivot = false; + mModelPivot = LLVector3( 0.0f, 0.0f, 0.0f ); + + glodInit(); +} + +LLModelPreview::~LLModelPreview() +{ + if (mModelLoader) + { + mModelLoader->mPreview = NULL; + } + //*HACK : *TODO : turn this back on when we understand why this crashes + //glodShutdown(); +} + +U32 LLModelPreview::calcResourceCost() +{ + assert_main_thread(); + + rebuildUploadData(); + + if (mFMP && mModelLoader) + { + if ( getLoadState() != LLModelLoader::ERROR_PARSING ) + { + mFMP->childEnable("ok_btn"); + } + } + + //Upload skin is selected BUT the joints coming in from the asset + //were malformed. + if ( mFMP && mFMP->childGetValue("upload_skin").asBoolean() ) + { + if ( !isRigValid() ) + { + mFMP->childDisable("ok_btn"); + } + } + + U32 cost = 0; + std::set accounted; + U32 num_points = 0; + U32 num_hulls = 0; + + F32 debug_scale = mFMP ? mFMP->childGetValue("import_scale").asReal() : 1.f; + mPelvisZOffset = mFMP ? mFMP->childGetValue("pelvis_offset").asReal() : 3.0f; + + if ( mFMP && mFMP->childGetValue("upload_joints").asBoolean() ) + { + gAgentAvatarp->setPelvisOffset( mPelvisZOffset ); + } + + F32 streaming_cost = 0.f; + F32 physics_cost = 0.f; + for (U32 i = 0; i < mUploadData.size(); ++i) + { + LLModelInstance& instance = mUploadData[i]; + + if (accounted.find(instance.mModel) == accounted.end()) + { + accounted.insert(instance.mModel); + + LLModel::convex_hull_decomposition& decomp = + instance.mLOD[LLModel::LOD_PHYSICS] ? + instance.mLOD[LLModel::LOD_PHYSICS]->mConvexHullDecomp : + instance.mModel->mConvexHullDecomp; + + LLSD ret = LLModel::writeModel( + "", + instance.mLOD[4], + instance.mLOD[3], + instance.mLOD[2], + instance.mLOD[1], + instance.mLOD[0], + decomp, + mFMP->childGetValue("upload_skin").asBoolean(), + mFMP->childGetValue("upload_joints").asBoolean(), + TRUE); + cost += gMeshRepo.calcResourceCost(ret); + + num_hulls += decomp.size(); + for (U32 i = 0; i < decomp.size(); ++i) + { + num_points += decomp[i].size(); + } + + //calculate streaming cost + LLMatrix4 transformation = instance.mTransform; + + LLVector3 position = LLVector3(0, 0, 0) * transformation; + + LLVector3 x_transformed = LLVector3(1, 0, 0) * transformation - position; + LLVector3 y_transformed = LLVector3(0, 1, 0) * transformation - position; + LLVector3 z_transformed = LLVector3(0, 0, 1) * transformation - position; + F32 x_length = x_transformed.normalize(); + F32 y_length = y_transformed.normalize(); + F32 z_length = z_transformed.normalize(); + LLVector3 scale = LLVector3(x_length, y_length, z_length); + + F32 radius = scale.length()*debug_scale; + + streaming_cost += LLMeshRepository::getStreamingCost(ret, radius); + } + } + + F32 scale = mFMP ? mFMP->childGetValue("import_scale").asReal()*2.f : 2.f; + + mDetailsSignal(mPreviewScale[0]*scale, mPreviewScale[1]*scale, mPreviewScale[2]*scale, streaming_cost, physics_cost); + + updateStatusMessages(); + + return cost; +} + +void LLFloaterModelPreview::setDetails(F32 x, F32 y, F32 z, F32 streaming_cost, F32 physics_cost) +{ + childSetTextArg("import_dimensions", "[X]", llformat("%.3f", x)); + childSetTextArg("import_dimensions", "[Y]", llformat("%.3f", y)); + childSetTextArg("import_dimensions", "[Z]", llformat("%.3f", z)); + childSetTextArg("streaming cost", "[COST]", llformat("%.3f", streaming_cost)); + childSetTextArg("physics cost", "[COST]", llformat("%.3f", physics_cost)); +} + +void LLModelPreview::alterModelsPivot( void ) +{ + for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) + { + if ( *iter ) + { + (*iter)->offsetMesh( mModelPivot ); + } + } + + for ( int i=0;ioffsetMesh( mModelPivot ); + } + } + } +} + +void LLModelPreview::rebuildUploadData() +{ + assert_main_thread(); + + mUploadData.clear(); + mTextureSet.clear(); + + //fill uploaddata instance vectors from scene data + + std::string requested_name = mFMP->getChild("description_form")->getValue().asString(); + + + LLSpinCtrl* scale_spinner = mFMP->getChild("import_scale"); + + if (!scale_spinner) + { + llerrs << "floater_model_preview.xml MUST contain import_scale spinner." << llendl; + } + + F32 scale = scale_spinner->getValue().asReal(); + + LLMatrix4 scale_mat; + scale_mat.initScale(LLVector3(scale, scale, scale)); + + F32 max_scale = 0.f; + + if ( mBaseScene.size() > 0 ) + { + mFMP->childEnable("ok_btn"); + } + + for (LLModelLoader::scene::iterator iter = mBaseScene.begin(); iter != mBaseScene.end(); ++iter) + { //for each transform in scene + LLMatrix4 mat = iter->first; + + // compute position + LLVector3 position = LLVector3(0, 0, 0) * mat; + + // compute scale + LLVector3 x_transformed = LLVector3(1, 0, 0) * mat - position; + LLVector3 y_transformed = LLVector3(0, 1, 0) * mat - position; + LLVector3 z_transformed = LLVector3(0, 0, 1) * mat - position; + F32 x_length = x_transformed.normalize(); + F32 y_length = y_transformed.normalize(); + F32 z_length = z_transformed.normalize(); + + max_scale = llmax(llmax(llmax(max_scale, x_length), y_length), z_length); + + mat *= scale_mat; + + for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) + { //for each instance with said transform applied + LLModelInstance instance = *model_iter; + + LLModel* base_model = instance.mModel; + + if (base_model) + { + base_model->mRequestedLabel = requested_name; + } + + S32 idx = 0; + for (idx = 0; idx < mBaseModel.size(); ++idx) + { //find reference instance for this model + if (mBaseModel[idx] == base_model) + { + break; + } + } + + for (U32 i = 0; i < LLModel::NUM_LODS; i++) + { //fill LOD slots based on reference model index + if (!mModel[i].empty()) + { + instance.mLOD[i] = mModel[i][idx]; + } + else + { + instance.mLOD[i] = NULL; + } + } + + instance.mTransform = mat; + mUploadData.push_back(instance); + } + } + + F32 max_import_scale = DEFAULT_MAX_PRIM_SCALE/max_scale; + + scale_spinner->setMaxValue(max_import_scale); + + if (max_import_scale < scale) + { + scale_spinner->setValue(max_import_scale); + } + +} + +void LLModelPreview::saveUploadData(bool save_skinweights, bool save_joint_positions) +{ + if (!mLODFile[LLModel::LOD_HIGH].empty()) + { + std::string filename = mLODFile[LLModel::LOD_HIGH]; + + std::string::size_type i = filename.rfind("."); + if (i != std::string::npos) + { + filename.replace(i, filename.size()-1, ".slm"); + saveUploadData(filename, save_skinweights, save_joint_positions); + } + } +} + +void LLModelPreview::saveUploadData(const std::string& filename, bool save_skinweights, bool save_joint_positions) +{ + std::set > meshes; + std::map mesh_binary; + + LLModel::hull empty_hull; + + LLSD data; + + S32 mesh_id = 0; + + //build list of unique models and initialize local id + for (U32 i = 0; i < mUploadData.size(); ++i) + { + LLModelInstance& instance = mUploadData[i]; + + if (meshes.find(instance.mModel) == meshes.end()) + { + instance.mModel->mLocalID = mesh_id++; + meshes.insert(instance.mModel); + + std::stringstream str; + + LLModel::convex_hull_decomposition& decomp = + instance.mLOD[LLModel::LOD_PHYSICS].notNull() ? + instance.mLOD[LLModel::LOD_PHYSICS]->mConvexHullDecomp : + instance.mModel->mConvexHullDecomp; + + LLModel::writeModel(str, + instance.mLOD[LLModel::LOD_PHYSICS], + instance.mLOD[LLModel::LOD_HIGH], + instance.mLOD[LLModel::LOD_MEDIUM], + instance.mLOD[LLModel::LOD_LOW], + instance.mLOD[LLModel::LOD_IMPOSTOR], + decomp, + empty_hull, save_skinweights, save_joint_positions); + + + data["mesh"][instance.mModel->mLocalID] = str.str(); + } + + data["instance"][i] = instance.asLLSD(); + } + + llofstream out(filename, std::ios_base::out | std::ios_base::binary); + LLSDSerialize::toBinary(data, out); + out.flush(); + out.close(); +} + +void LLModelPreview::clearModel(S32 lod) +{ + if (lod < 0 || lod > LLModel::LOD_PHYSICS) + { + return; + } + + mVertexBuffer[lod].clear(); + mModel[lod].clear(); + mScene[lod].clear(); +} + +void LLModelPreview::loadModel(std::string filename, S32 lod) +{ + assert_main_thread(); + + LLMutexLock lock(this); + + // This triggers if you bring up the file picker and then hit CANCEL. + // Just use the previous model (if any) and ignore that you brought up + // the file picker. + + if (filename.empty()) + { + if (mBaseModel.empty()) + { + // this is the initial file picking. Close the whole floater + // if we don't have a base model to show for high LOD. + mFMP->closeFloater(false); + mLoading = false; + } + return; + } + + if (mModelLoader) + { + llwarns << "Incompleted model load operation pending." << llendl; + return; + } + + mLODFile[lod] = filename; + + if (lod == LLModel::LOD_HIGH) + { + clearGLODGroup(); + } + + mModelLoader = new LLModelLoader(filename, lod, this); + + mModelLoader->start(); + + mFMP->childSetTextArg("status", "[STATUS]", mFMP->getString("status_reading_file")); + + setPreviewLOD(lod); + + if ( getLoadState() == LLModelLoader::ERROR_PARSING ) + { + mFMP->childDisable("ok_btn"); + } + + if (lod == mPreviewLOD) + { + mFMP->childSetText("lod_file", mLODFile[mPreviewLOD]); + } + else if (lod == LLModel::LOD_PHYSICS) + { + mFMP->childSetText("physics_file", mLODFile[lod]); + } + + mFMP->openFloater(); +} + +void LLModelPreview::setPhysicsFromLOD(S32 lod) +{ + assert_main_thread(); + + if (lod >= 0 && lod <= 3) + { + mModel[LLModel::LOD_PHYSICS] = mModel[lod]; + mScene[LLModel::LOD_PHYSICS] = mScene[lod]; + mLODFile[LLModel::LOD_PHYSICS].clear(); + mFMP->childSetText("physics_file", mLODFile[LLModel::LOD_PHYSICS]); + mVertexBuffer[LLModel::LOD_PHYSICS].clear(); + rebuildUploadData(); + refresh(); + updateStatusMessages(); + } +} + +void LLModelPreview::clearIncompatible(S32 lod) +{ + for (U32 i = 0; i <= LLModel::LOD_HIGH; i++) + { //clear out any entries that aren't compatible with this model + if (i != lod) + { + if (mModel[i].size() != mModel[lod].size()) + { + mModel[i].clear(); + mScene[i].clear(); + mVertexBuffer[i].clear(); + + if (i == LLModel::LOD_HIGH) + { + mBaseModel = mModel[lod]; + clearGLODGroup(); + mBaseScene = mScene[lod]; + mVertexBuffer[5].clear(); + } + } + } + } +} + +void LLModelPreview::clearGLODGroup() +{ + if (mGroup) + { + for (std::map, U32>::iterator iter = mObject.begin(); iter != mObject.end(); ++iter) + { + glodDeleteObject(iter->second); + stop_gloderror(); + } + mObject.clear(); + + glodDeleteGroup(mGroup); + stop_gloderror(); + mGroup = 0; + } +} + +void LLModelPreview::loadModelCallback(S32 lod) +{ + assert_main_thread(); + + LLMutexLock lock(this); + if (!mModelLoader) + { + return; + } + + mModelLoader->loadTextures() ; + + if (lod == -1) + { //populate all LoDs from model loader scene + mBaseModel.clear(); + mBaseScene.clear(); + + for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) + { //for each LoD + + //clear scene and model info + mScene[lod].clear(); + mModel[lod].clear(); + mVertexBuffer[lod].clear(); + + if (mModelLoader->mScene.begin()->second[0].mLOD[lod].notNull()) + { //if this LoD exists in the loaded scene + + //copy scene to current LoD + mScene[lod] = mModelLoader->mScene; + + //touch up copied scene to look like current LoD + for (LLModelLoader::scene::iterator iter = mScene[lod].begin(); iter != mScene[lod].end(); ++iter) + { + LLModelLoader::model_instance_list& list = iter->second; + + for (LLModelLoader::model_instance_list::iterator list_iter = list.begin(); list_iter != list.end(); ++list_iter) + { + //override displayed model with current LoD + list_iter->mModel = list_iter->mLOD[lod]; + + //add current model to current LoD's model list (LLModel::mLocalID makes a good vector index) + S32 idx = list_iter->mModel->mLocalID; + + if (mModel[lod].size() <= idx) + { //stretch model list to fit model at given index + mModel[lod].resize(idx+1); + } + + mModel[lod][idx] = list_iter->mModel; + } + } + } + } + + //copy high lod to base scene for LoD generation + mBaseScene = mScene[LLModel::LOD_HIGH]; + mBaseModel = mModel[LLModel::LOD_HIGH]; + + mDirty = true; + resetPreviewTarget(); + } + else + { //only replace given LoD + mModel[lod] = mModelLoader->mModelList; + mScene[lod] = mModelLoader->mScene; + mVertexBuffer[lod].clear(); + + if (lod == LLModel::LOD_PHYSICS) + { + mPhysicsMesh.clear(); + } + + setPreviewLOD(lod); + + + if (lod == LLModel::LOD_HIGH) + { //save a copy of the highest LOD for automatic LOD manipulation + if (mBaseModel.empty()) + { //first time we've loaded a model, auto-gen LoD + mGenLOD = true; + } + + mBaseModel = mModel[lod]; + clearGLODGroup(); + + mBaseScene = mScene[lod]; + mVertexBuffer[5].clear(); + } + + clearIncompatible(lod); + + mDirty = true; + + if (lod == LLModel::LOD_HIGH) + { + resetPreviewTarget(); + } + } + + mLoading = false; + refresh(); + + mModelLoadedSignal(); +} + +void LLModelPreview::resetPreviewTarget() +{ + if ( mModelLoader ) + { + mPreviewTarget = (mModelLoader->mExtents[0] + mModelLoader->mExtents[1]) * 0.5f; + mPreviewScale = (mModelLoader->mExtents[1] - mModelLoader->mExtents[0]) * 0.5f; + } + + setPreviewTarget(mPreviewScale.magVec()*2.f); +} + +void LLModelPreview::generateNormals() +{ + assert_main_thread(); + + S32 which_lod = mPreviewLOD; + + + if (which_lod > 4 || which_lod < 0 || + mModel[which_lod].empty()) + { + return; + } + + F32 angle_cutoff = mFMP->childGetValue("crease_angle").asReal(); + + angle_cutoff *= DEG_TO_RAD; + + if (which_lod == 3 && !mBaseModel.empty()) + { + for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) + { + (*iter)->generateNormals(angle_cutoff); + } + + mVertexBuffer[5].clear(); + } + + for (LLModelLoader::model_list::iterator iter = mModel[which_lod].begin(); iter != mModel[which_lod].end(); ++iter) + { + (*iter)->generateNormals(angle_cutoff); + } + + mVertexBuffer[which_lod].clear(); + refresh(); + +} + +void LLModelPreview::clearMaterials() +{ + for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) + { //for each transform in current scene + for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) + { //for each instance with that transform + LLModelInstance& source_instance = *model_iter; + LLModel* source = source_instance.mModel; + + for (S32 i = 0; i < source->getNumVolumeFaces(); ++i) + { //for each face in instance + LLImportMaterial& source_material = source_instance.mMaterial[i]; + + //clear material info + source_material.mDiffuseColor = LLColor4(1,1,1,1); + source_material.mDiffuseMap = NULL; + source_material.mDiffuseMapFilename.clear(); + source_material.mDiffuseMapLabel.clear(); + source_material.mFullbright = false; + } + } + } + + mVertexBuffer[mPreviewLOD].clear(); + + if (mPreviewLOD == LLModel::LOD_HIGH) + { + mBaseScene = mScene[mPreviewLOD]; + mBaseModel = mModel[mPreviewLOD]; + clearGLODGroup(); + mVertexBuffer[5].clear(); + } + + mResourceCost = calcResourceCost(); + refresh(); +} + +void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_limit) +{ + if (mBaseModel.empty()) + { + return; + } + + if (which_lod == LLModel::LOD_PHYSICS) + { //clear physics mesh map + mPhysicsMesh.clear(); + } + + LLVertexBuffer::unbind(); + + stop_gloderror(); + static U32 cur_name = 1; + + S32 limit = -1; + + U32 triangle_count = 0; + + for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) + { + LLModel* mdl = *iter; + for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) + { + triangle_count += mdl->getVolumeFace(i).mNumIndices/3; + } + } + + U32 base_triangle_count = triangle_count; + + U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; + + U32 lod_mode = 0; + + LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode"); + if (iface) + { + lod_mode = iface->getFirstSelectedIndex(); + } + + F32 lod_error_threshold = mFMP->childGetValue("lod_error_threshold").asReal(); + + if (lod_mode == 0) + { + lod_mode = GLOD_TRIANGLE_BUDGET; + if (which_lod != -1) + { + limit = mFMP->childGetValue("lod_triangle_limit").asInteger(); + } + } + else + { + lod_mode = GLOD_ERROR_THRESHOLD; + } + + U32 build_operator = 0; + + iface = mFMP->childGetSelectionInterface("build_operator"); + if (iface) + { + build_operator = iface->getFirstSelectedIndex(); + } + + if (build_operator == 0) + { + build_operator = GLOD_OPERATOR_EDGE_COLLAPSE; + } + else + { + build_operator = GLOD_OPERATOR_HALF_EDGE_COLLAPSE; + } + + U32 queue_mode=0; + iface = mFMP->childGetSelectionInterface("queue_mode"); + if (iface) + { + queue_mode = iface->getFirstSelectedIndex(); + } + + if (queue_mode == 0) + { + queue_mode = GLOD_QUEUE_GREEDY; + } + else if (queue_mode == 1) + { + queue_mode = GLOD_QUEUE_LAZY; + } + else + { + queue_mode = GLOD_QUEUE_INDEPENDENT; + } + + U32 border_mode = 0; + + iface = mFMP->childGetSelectionInterface("border_mode"); + if (iface) + { + border_mode = iface->getFirstSelectedIndex(); + } + + if (border_mode == 0) + { + border_mode = GLOD_BORDER_UNLOCK; + } + else + { + border_mode = GLOD_BORDER_LOCK; + } + + bool object_dirty = false; + if (border_mode != mBuildBorderMode) + { + mBuildBorderMode = border_mode; + object_dirty = true; + } + + if (queue_mode != mBuildQueueMode) + { + mBuildQueueMode = queue_mode; + object_dirty = true; + } + + if (build_operator != mBuildOperator) + { + mBuildOperator = build_operator; + object_dirty = true; + } + + F32 share_tolerance = mFMP->childGetValue("share_tolerance").asReal(); + if (share_tolerance != mBuildShareTolerance) + { + mBuildShareTolerance = share_tolerance; + object_dirty = true; + } + + if (mGroup == 0) + { + object_dirty = true; + mGroup = cur_name++; + glodNewGroup(mGroup); + } + + if (object_dirty) + { + for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) + { //build GLOD objects for each model in base model list + LLModel* mdl = *iter; + + if (mObject[mdl] != 0) + { + glodDeleteObject(mObject[mdl]); + } + + mObject[mdl] = cur_name++; + + glodNewObject(mObject[mdl], mGroup, GLOD_DISCRETE); + stop_gloderror(); + + if (iter == mBaseModel.begin() && !mdl->mSkinWeights.empty()) + { //regenerate vertex buffer for skinned models to prevent animation feedback during LOD generation + mVertexBuffer[5].clear(); + } + + if (mVertexBuffer[5].empty()) + { + genBuffers(5, false); + } + + U32 tri_count = 0; + for (U32 i = 0; i < mVertexBuffer[5][mdl].size(); ++i) + { + mVertexBuffer[5][mdl][i]->setBuffer(type_mask); + U32 num_indices = mVertexBuffer[5][mdl][i]->getNumIndices(); + if (num_indices > 2) + { + glodInsertElements(mObject[mdl], i, GL_TRIANGLES, num_indices, GL_UNSIGNED_SHORT, mVertexBuffer[5][mdl][i]->getIndicesPointer(), 0, 0.f); + } + tri_count += num_indices/3; + stop_gloderror(); + } + + glodObjectParameteri(mObject[mdl], GLOD_BUILD_OPERATOR, build_operator); + stop_gloderror(); + + glodObjectParameteri(mObject[mdl], GLOD_BUILD_QUEUE_MODE, queue_mode); + stop_gloderror(); + + glodObjectParameteri(mObject[mdl], GLOD_BUILD_BORDER_MODE, border_mode); + stop_gloderror(); + + glodObjectParameterf(mObject[mdl], GLOD_BUILD_SHARE_TOLERANCE, share_tolerance); + stop_gloderror(); + + glodBuildObject(mObject[mdl]); + stop_gloderror(); + } + } + + + S32 start = LLModel::LOD_HIGH; + S32 end = 0; + + if (which_lod != -1) + { + start = end = which_lod; + } + + mMaxTriangleLimit = base_triangle_count; + + for (S32 lod = start; lod >= end; --lod) + { + if (which_lod == -1) + { + if (lod < start) + { + triangle_count /= decimation; + } + } + else + { + if (enforce_tri_limit) + { + triangle_count = limit; + } + else + { + for (S32 j=LLModel::LOD_HIGH; j>which_lod; --j) + { + triangle_count /= decimation; + } + } + } + + mModel[lod].clear(); + mModel[lod].resize(mBaseModel.size()); + mVertexBuffer[lod].clear(); + + U32 actual_tris = 0; + U32 actual_verts = 0; + U32 submeshes = 0; + + mRequestedTriangleCount[lod] = triangle_count; + + glodGroupParameteri(mGroup, GLOD_ADAPT_MODE, lod_mode); + stop_gloderror(); + + glodGroupParameteri(mGroup, GLOD_ERROR_MODE, GLOD_OBJECT_SPACE_ERROR); + stop_gloderror(); + + glodGroupParameterf(mGroup, GLOD_OBJECT_SPACE_ERROR_THRESHOLD, lod_error_threshold); + stop_gloderror(); + + glodGroupParameteri(mGroup, GLOD_MAX_TRIANGLES, 0); + stop_gloderror(); + + glodAdaptGroup(mGroup); + stop_gloderror(); + + if (lod_mode == GLOD_TRIANGLE_BUDGET) + { //SH-632 Always adapt to 0 before adapting to actual desired amount, and always + //add 1 to desired amount to avoid decimating below desired amount + glodGroupParameteri(mGroup, GLOD_MAX_TRIANGLES, triangle_count+1); + stop_gloderror(); + + glodAdaptGroup(mGroup); + stop_gloderror(); + } + + for (U32 mdl_idx = 0; mdl_idx < mBaseModel.size(); ++mdl_idx) + { + LLModel* base = mBaseModel[mdl_idx]; + + GLint patch_count = 0; + glodGetObjectParameteriv(mObject[base], GLOD_NUM_PATCHES, &patch_count); + stop_gloderror(); + + LLVolumeParams volume_params; + volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); + mModel[lod][mdl_idx] = new LLModel(volume_params, 0.f); + + GLint* sizes = new GLint[patch_count*2]; + glodGetObjectParameteriv(mObject[base], GLOD_PATCH_SIZES, sizes); + stop_gloderror(); + + GLint* names = new GLint[patch_count]; + glodGetObjectParameteriv(mObject[base], GLOD_PATCH_NAMES, names); + stop_gloderror(); + + mModel[lod][mdl_idx]->setNumVolumeFaces(patch_count); + + LLModel* target_model = mModel[lod][mdl_idx]; + + for (GLint i = 0; i < patch_count; ++i) + { + LLPointer buff = new LLVertexBuffer(type_mask, 0); + + if (sizes[i*2+1] > 0 && sizes[i*2] > 0) + { + buff->allocateBuffer(sizes[i*2+1], sizes[i*2], true); + buff->setBuffer(type_mask); + glodFillElements(mObject[base], names[i], GL_UNSIGNED_SHORT, buff->getIndicesPointer()); + stop_gloderror(); + } + else + { //this face was eliminated, create a dummy triangle (one vertex, 3 indices, all 0) + buff->allocateBuffer(1, 3, true); + memset(buff->getMappedData(), 0, buff->getSize()); + memset(buff->getIndicesPointer(), 0, buff->getIndicesSize()); + } + + buff->validateRange(0, buff->getNumVerts()-1, buff->getNumIndices(), 0); + + LLStrider pos; + LLStrider norm; + LLStrider tc; + LLStrider index; + + buff->getVertexStrider(pos); + buff->getNormalStrider(norm); + buff->getTexCoord0Strider(tc); + buff->getIndexStrider(index); + + target_model->setVolumeFaceData(names[i], pos, norm, tc, index, buff->getNumVerts(), buff->getNumIndices()); + actual_tris += buff->getNumIndices()/3; + actual_verts += buff->getNumVerts(); + ++submeshes; + + if (!validate_face(target_model->getVolumeFace(names[i]))) + { + llerrs << "Invalid face generated during LOD generation." << llendl; + } + } + + //blind copy skin weights and just take closest skin weight to point on + //decimated mesh for now (auto-generating LODs with skin weights is still a bit + //of an open problem). + target_model->mPosition = base->mPosition; + target_model->mSkinWeights = base->mSkinWeights; + target_model->mJointMap = base->mJointMap; + target_model->mJointList = base->mJointList; + target_model->mInvBindMatrix = base->mInvBindMatrix; + target_model->mBindShapeMatrix = base->mBindShapeMatrix; + target_model->mAlternateBindMatrix = base->mAlternateBindMatrix; + //copy material list + target_model->mMaterialList = base->mMaterialList; + + if (!validate_model(target_model)) + { + llerrs << "Invalid model generated when creating LODs" << llendl; + } + + delete [] sizes; + delete [] names; + } + + //rebuild scene based on mBaseScene + mScene[lod].clear(); + mScene[lod] = mBaseScene; + + for (U32 i = 0; i < mBaseModel.size(); ++i) + { + LLModel* mdl = mBaseModel[i]; + LLModel* target = mModel[lod][i]; + if (target) + { + for (LLModelLoader::scene::iterator iter = mScene[lod].begin(); iter != mScene[lod].end(); ++iter) + { + for (U32 j = 0; j < iter->second.size(); ++j) + { + if (iter->second[j].mModel == mdl) + { + iter->second[j].mModel = target; + } + } + } + } + } + } + + mResourceCost = calcResourceCost(); + + /*if (which_lod == -1 && mScene[LLModel::LOD_PHYSICS].empty()) + { //build physics scene + mScene[LLModel::LOD_PHYSICS] = mScene[LLModel::LOD_LOW]; + mModel[LLModel::LOD_PHYSICS] = mModel[LLModel::LOD_LOW]; + + for (U32 i = 1; i < mModel[LLModel::LOD_PHYSICS].size(); ++i) + { + mPhysicsQ.push(mModel[LLModel::LOD_PHYSICS][i]); + } + }*/ +} + +void LLModelPreview::updateStatusMessages() +{ + assert_main_thread(); + + //triangle/vertex/submesh count for each mesh asset for each lod + std::vector tris[LLModel::NUM_LODS]; + std::vector verts[LLModel::NUM_LODS]; + std::vector submeshes[LLModel::NUM_LODS]; + + //total triangle/vertex/submesh count for each lod + S32 total_tris[LLModel::NUM_LODS]; + S32 total_verts[LLModel::NUM_LODS]; + S32 total_submeshes[LLModel::NUM_LODS]; + + for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) + { + //initialize total for this lod to 0 + total_tris[lod] = total_verts[lod] = total_submeshes[lod] = 0; + + for (U32 i = 0; i < mModel[lod].size(); ++i) + { //for each model in the lod + S32 cur_tris = 0; + S32 cur_verts = 0; + S32 cur_submeshes = mModel[lod][i]->getNumVolumeFaces(); + + for (S32 j = 0; j < cur_submeshes; ++j) + { //for each submesh (face), add triangles and vertices to current total + const LLVolumeFace& face = mModel[lod][i]->getVolumeFace(j); + cur_tris += face.mNumIndices/3; + cur_verts += face.mNumVertices; + } + + //add this model to the lod total + total_tris[lod] += cur_tris; + total_verts[lod] += cur_verts; + total_submeshes[lod] += cur_submeshes; + + //store this model's counts to asset data + tris[lod].push_back(cur_tris); + verts[lod].push_back(cur_verts); + submeshes[lod].push_back(cur_submeshes); + } + } + + if (mMaxTriangleLimit == 0) + { + mMaxTriangleLimit = total_tris[LLModel::LOD_HIGH]; + } + + + mFMP->childSetTextArg("submeshes_info", "[SUBMESHES]", llformat("%d", total_submeshes[LLModel::LOD_HIGH])); + + std::string mesh_status_na = mFMP->getString("mesh_status_na"); + + S32 upload_status[LLModel::LOD_HIGH+1]; + + bool upload_ok = true; + + for (S32 lod = 0; lod <= LLModel::LOD_HIGH; ++lod) + { + upload_status[lod] = 0; + + std::string message = "mesh_status_good"; + + if (total_tris[lod] > 0) + { + mFMP->childSetText(lod_triangles_name[lod], llformat("%d", total_tris[lod])); + mFMP->childSetText(lod_vertices_name[lod], llformat("%d", total_verts[lod])); + } + else + { + if (lod == LLModel::LOD_HIGH) + { + upload_status[lod] = 2; + message = "mesh_status_missing_lod"; + } + else + { + for (S32 i = lod-1; i >= 0; --i) + { + if (total_tris[i] > 0) + { + upload_status[lod] = 2; + message = "mesh_status_missing_lod"; + } + } + } + + mFMP->childSetText(lod_triangles_name[lod], mesh_status_na); + mFMP->childSetText(lod_vertices_name[lod], mesh_status_na); + } + + const U32 lod_high = LLModel::LOD_HIGH; + + if (lod != lod_high) + { + if (total_submeshes[lod] && total_submeshes[lod] != total_submeshes[lod_high]) + { //number of submeshes is different + message = "mesh_status_submesh_mismatch"; + upload_status[lod] = 2; + } + else if (!tris[lod].empty() && tris[lod].size() != tris[lod_high].size()) + { //number of meshes is different + message = "mesh_status_mesh_mismatch"; + upload_status[lod] = 2; + } + else if (!verts[lod].empty()) + { + for (U32 i = 0; i < verts[lod].size(); ++i) + { + S32 max_verts = i < verts[lod+1].size() ? verts[lod+1][i] : 0; + + if (max_verts > 0) + { + if (verts[lod][i] > max_verts) + { //too many vertices in this lod + message = "mesh_status_too_many_vertices"; + upload_status[lod] = 2; + } + } + } + } + } + + LLIconCtrl* icon = mFMP->getChild(lod_icon_name[lod]); + LLUIImagePtr img = LLUI::getUIImage(lod_status_image[upload_status[lod]]); + icon->setVisible(true); + icon->setImage(img); + + if (upload_status[lod] >= 2) + { + upload_ok = false; + } + + if (lod == mPreviewLOD) + { + mFMP->childSetText("lod_status_message_text", mFMP->getString(message)); + icon = mFMP->getChild("lod_status_message_icon"); + icon->setImage(img); + } + } + + bool errorStateFromLoader = getLoadState() == LLModelLoader::ERROR_PARSING ? true : false; + + bool skinAndRigOk = true; + bool uploadingSkin = mFMP->childGetValue("upload_skin").asBoolean(); + if ( uploadingSkin && !isRigValid() ) + { + skinAndRigOk = false; + } + + if ( upload_ok && !errorStateFromLoader && skinAndRigOk ) + { + mFMP->childEnable("ok_btn"); + } + + //add up physics triangles etc + S32 start = 0; + S32 end = mModel[LLModel::LOD_PHYSICS].size(); + + S32 phys_tris = 0; + S32 phys_hulls = 0; + S32 phys_points = 0; + + for (S32 i = start; i < end; ++i) + { //add up hulls and points and triangles for selected mesh(es) + LLModel* model = mModel[LLModel::LOD_PHYSICS][i]; + S32 cur_submeshes = model->getNumVolumeFaces(); + + LLModel::convex_hull_decomposition& decomp = model->mConvexHullDecomp; + + if (!decomp.empty()) + { + phys_hulls += decomp.size(); + for (U32 i = 0; i < decomp.size(); ++i) + { + phys_points += decomp[i].size(); + } + } + else + { //choose physics shape OR decomposition, can't use both + for (S32 j = 0; j < cur_submeshes; ++j) + { //for each submesh (face), add triangles and vertices to current total + const LLVolumeFace& face = model->getVolumeFace(j); + phys_tris += face.mNumIndices/3; + } + } + } + + if (phys_tris > 0) + { + mFMP->childSetTextArg("physics_triangles", "[TRIANGLES]", llformat("%d", phys_tris)); + } + else + { + mFMP->childSetTextArg("physics_triangles", "[TRIANGLES]", mesh_status_na); + } + + if (phys_hulls > 0) + { + mFMP->childSetTextArg("physics_hulls", "[HULLS]", llformat("%d", phys_hulls)); + mFMP->childSetTextArg("physics_points", "[POINTS]", llformat("%d", phys_points)); + } + else + { + mFMP->childSetTextArg("physics_hulls", "[HULLS]", mesh_status_na); + mFMP->childSetTextArg("physics_points", "[POINTS]", mesh_status_na); + } + + LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; + if (fmp) + { + if (phys_tris > 0 || phys_hulls > 0) + { + if (!fmp->isViewOptionEnabled("show_physics")) + { + fmp->enableViewOption("show_physics"); + mViewOption["show_physics"] = true; + } + } + else + { + fmp->disableViewOption("show_physics"); + mViewOption["show_physics"] = false; + + } + + //bool use_hull = fmp->childGetValue("physics_use_hull").asBoolean(); + + //fmp->childSetEnabled("physics_optimize", !use_hull); + + bool enable = phys_tris > 0 || phys_hulls > 0; + //enable = enable && !use_hull && fmp->childGetValue("physics_optimize").asBoolean(); + + //enable/disable "analysis" UI + LLPanel* panel = fmp->getChild("physics analysis"); + LLView* child = panel->getFirstChild(); + while (child) + { + child->setEnabled(enable); + child = panel->findNextSibling(child); + } + + enable = phys_hulls > 0; + //enable/disable "simplification" UI + panel = fmp->getChild("physics simplification"); + child = panel->getFirstChild(); + while (child) + { + child->setEnabled(enable); + child = panel->findNextSibling(child); + } + } + + const char* lod_controls[] = + { + "lod_mode", + "lod_triangle_limit", + "lod_error_tolerance", + "build_operator_text", + "queue_mode_text", + "border_mode_text", + "share_tolerance_text", + "build_operator", + "queue_mode", + "border_mode", + "share_tolerance" + }; + const U32 num_lod_controls = sizeof(lod_controls)/sizeof(char*); + + const char* file_controls[] = + { + "lod_browse", + "lod_file" + }; + const U32 num_file_controls = sizeof(file_controls)/sizeof(char*); + + if (fmp) + { + //enable/disable controls based on radio groups + if (mFMP->childGetValue("lod_from_file").asBoolean()) + { + fmp->mLODMode[mPreviewLOD] = 0; + for (U32 i = 0; i < num_file_controls; ++i) + { + mFMP->childEnable(file_controls[i]); + } + + for (U32 i = 0; i < num_lod_controls; ++i) + { + mFMP->childDisable(lod_controls[i]); + } + } + else if (mFMP->childGetValue("lod_none").asBoolean()) + { + fmp->mLODMode[mPreviewLOD] = 2; + for (U32 i = 0; i < num_file_controls; ++i) + { + mFMP->childDisable(file_controls[i]); + } + + for (U32 i = 0; i < num_lod_controls; ++i) + { + mFMP->childDisable(lod_controls[i]); + } + + if (!mModel[mPreviewLOD].empty()) + { + mModel[mPreviewLOD].clear(); + mScene[mPreviewLOD].clear(); + mVertexBuffer[mPreviewLOD].clear(); + + //this can cause phasing issues with the UI, so reenter this function and return + updateStatusMessages(); + return; + } + } + else + { // auto generate, also the default case for wizard which has no radio selection + fmp->mLODMode[mPreviewLOD] = 1; + + for (U32 i = 0; i < num_file_controls; ++i) + { + mFMP->childDisable(file_controls[i]); + } + + for (U32 i = 0; i < num_lod_controls; ++i) + { + mFMP->childEnable(lod_controls[i]); + } + + //if (threshold) + { + U32 lod_mode = 0; + LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode"); + if (iface) + { + lod_mode = iface->getFirstSelectedIndex(); + } + + LLSpinCtrl* threshold = mFMP->getChild("lod_error_threshold"); + LLSpinCtrl* limit = mFMP->getChild("lod_triangle_limit"); + + limit->setMaxValue(mMaxTriangleLimit); + limit->setValue(mRequestedTriangleCount[mPreviewLOD]); + + if (lod_mode == 0) + { + limit->setVisible(true); + threshold->setVisible(false); + + limit->setMaxValue(mMaxTriangleLimit); + limit->setIncrement(mMaxTriangleLimit/32); + } + else + { + limit->setVisible(false); + threshold->setVisible(true); + } + } + } + } + + if (mFMP->childGetValue("physics_load_from_file").asBoolean()) + { + mFMP->childDisable("physics_lod_combo"); + mFMP->childEnable("physics_file"); + mFMP->childEnable("physics_browse"); + } + else + { + mFMP->childEnable("physics_lod_combo"); + mFMP->childDisable("physics_file"); + mFMP->childDisable("physics_browse"); + } +} + +void LLModelPreview::setPreviewTarget(F32 distance) +{ + mCameraDistance = distance; + mCameraZoom = 1.f; + mCameraPitch = 0.f; + mCameraYaw = 0.f; + mCameraOffset.clearVec(); +} + +void LLModelPreview::clearBuffers() +{ + for (U32 i = 0; i < 6; i++) + { + mVertexBuffer[i].clear(); + } +} + +void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights) +{ + U32 tri_count = 0; + U32 vertex_count = 0; + U32 mesh_count = 0; + + + LLModelLoader::model_list* model = NULL; + + if (lod < 0 || lod > 4) + { + model = &mBaseModel; + lod = 5; + } + else + { + model = &(mModel[lod]); + } + + if (!mVertexBuffer[lod].empty()) + { + mVertexBuffer[lod].clear(); + } + + mVertexBuffer[lod].clear(); + + LLModelLoader::model_list::iterator base_iter = mBaseModel.begin(); + + for (LLModelLoader::model_list::iterator iter = model->begin(); iter != model->end(); ++iter) + { + LLModel* mdl = *iter; + if (!mdl) + { + continue; + } + + LLModel* base_mdl = *base_iter; + base_iter++; + + for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) + { + const LLVolumeFace &vf = mdl->getVolumeFace(i); + U32 num_vertices = vf.mNumVertices; + U32 num_indices = vf.mNumIndices; + + if (!num_vertices || ! num_indices) + { + continue; + } + + LLVertexBuffer* vb = NULL; + + bool skinned = include_skin_weights && !mdl->mSkinWeights.empty(); + + U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; + + if (skinned) + { + mask |= LLVertexBuffer::MAP_WEIGHT4; + } + + vb = new LLVertexBuffer(mask, 0); + + vb->allocateBuffer(num_vertices, num_indices, TRUE); + + LLStrider vertex_strider; + LLStrider normal_strider; + LLStrider tc_strider; + LLStrider index_strider; + LLStrider weights_strider; + + vb->getVertexStrider(vertex_strider); + vb->getNormalStrider(normal_strider); + vb->getTexCoord0Strider(tc_strider); + vb->getIndexStrider(index_strider); + + if (skinned) + { + vb->getWeight4Strider(weights_strider); + } + + LLVector4a::memcpyNonAliased16((F32*) vertex_strider.get(), (F32*) vf.mPositions, num_vertices*4*sizeof(F32)); + LLVector4a::memcpyNonAliased16((F32*) tc_strider.get(), (F32*) vf.mTexCoords, num_vertices*2*sizeof(F32)); + LLVector4a::memcpyNonAliased16((F32*) normal_strider.get(), (F32*) vf.mNormals, num_vertices*4*sizeof(F32)); + + if (skinned) + { + for (U32 i = 0; i < num_vertices; i++) + { + //find closest weight to vf.mVertices[i].mPosition + LLVector3 pos(vf.mPositions[i].getF32ptr()); + + const LLModel::weight_list& weight_list = base_mdl->getJointInfluences(pos); + + LLVector4 w(0,0,0,0); + if (weight_list.size() > 4) + { + llerrs << "WTF?" << llendl; + } + + for (U32 i = 0; i < weight_list.size(); ++i) + { + F32 wght = llmin(weight_list[i].mWeight, 0.999999f); + F32 joint = (F32) weight_list[i].mJointIdx; + w.mV[i] = joint + wght; + } + + *(weights_strider++) = w; + } + } + + // build indices + for (U32 i = 0; i < num_indices; i++) + { + *(index_strider++) = vf.mIndices[i]; + } + + mVertexBuffer[lod][mdl].push_back(vb); + + vertex_count += num_vertices; + tri_count += num_indices/3; + ++mesh_count; + + } + } +} + +void LLModelPreview::update() +{ + if (mDirty) + { + mDirty = false; + mResourceCost = calcResourceCost(); + refresh(); + updateStatusMessages(); + } + + if (mGenLOD) + { + mGenLOD = false; + genLODs(); + refresh(); + updateStatusMessages(); + } + +} + +//----------------------------------------------------------------------------- +// render() +//----------------------------------------------------------------------------- +BOOL LLModelPreview::render() +{ + assert_main_thread(); + + LLMutexLock lock(this); + mNeedsUpdate = FALSE; + + bool edges = mViewOption["show_edges"]; + bool joint_positions = mViewOption["show_joint_positions"]; + bool skin_weight = mViewOption["show_skin_weight"]; + bool textures = mViewOption["show_textures"]; + bool physics = mViewOption["show_physics"]; + + S32 width = getWidth(); + S32 height = getHeight(); + + LLGLSUIDefault def; + LLGLDisable no_blend(GL_BLEND); + LLGLEnable cull(GL_CULL_FACE); + LLGLDepthTest depth(GL_TRUE); + LLGLDisable fog(GL_FOG); + + { + //clear background to blue + glMatrixMode(GL_PROJECTION); + gGL.pushMatrix(); + glLoadIdentity(); + glOrtho(0.0f, width, 0.0f, height, -1.0f, 1.0f); + + glMatrixMode(GL_MODELVIEW); + gGL.pushMatrix(); + glLoadIdentity(); + + gGL.color4f(0.169f, 0.169f, 0.169f, 1.f); + + gl_rect_2d_simple( width, height ); + + glMatrixMode(GL_PROJECTION); + gGL.popMatrix(); + + glMatrixMode(GL_MODELVIEW); + gGL.popMatrix(); + } + + LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; + + bool has_skin_weights = false; + bool upload_skin = mFMP->childGetValue("upload_skin").asBoolean(); + bool upload_joints = mFMP->childGetValue("upload_joints").asBoolean(); + + for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) + { + for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) + { + LLModelInstance& instance = *model_iter; + LLModel* model = instance.mModel; + model->mPelvisOffset = mPelvisZOffset; + if (!model->mSkinWeights.empty()) + { + has_skin_weights = true; + } + } + } + + if (has_skin_weights) + { //model has skin weights, enable view options for skin weights and joint positions + if (fmp) + { + fmp->enableViewOption("show_skin_weight"); + fmp->setViewOptionEnabled("show_joint_positions", skin_weight); + } + mFMP->childEnable("upload_skin"); + } + else + { + mFMP->childDisable("upload_skin"); + if (fmp) + { + mViewOption["show_skin_weight"] = false; + fmp->disableViewOption("show_skin_weight"); + fmp->disableViewOption("show_joint_positions"); + } + skin_weight = false; + } + + if (upload_skin && !has_skin_weights) + { //can't upload skin weights if model has no skin weights + mFMP->childSetValue("upload_skin", false); + upload_skin = false; + } + + if (!upload_skin && upload_joints) + { //can't upload joints if not uploading skin weights + mFMP->childSetValue("upload_joints", false); + upload_joints = false; + } + + mFMP->childSetEnabled("upload_joints", upload_skin); + + F32 explode = mFMP->childGetValue("physics_explode").asReal(); + + glClear(GL_DEPTH_BUFFER_BIT); + + LLRect preview_rect = mFMP->getChildView("preview_panel")->getRect(); + F32 aspect = (F32) preview_rect.getWidth()/preview_rect.getHeight(); + + LLViewerCamera::getInstance()->setAspect(aspect); + + LLViewerCamera::getInstance()->setView(LLViewerCamera::getInstance()->getDefaultFOV() / mCameraZoom); + + LLVector3 offset = mCameraOffset; + LLVector3 target_pos = mPreviewTarget+offset; + + F32 z_near = 0.001f; + F32 z_far = mCameraDistance+mPreviewScale.magVec()+mCameraOffset.magVec(); + + if (skin_weight) + { + target_pos = gAgentAvatarp->getPositionAgent(); + z_near = 0.01f; + z_far = 1024.f; + mCameraDistance = 16.f; + + //render avatar previews every frame + refresh(); + } + + glLoadIdentity(); + gPipeline.enableLightsPreview(); + + LLQuaternion camera_rot = LLQuaternion(mCameraPitch, LLVector3::y_axis) * + LLQuaternion(mCameraYaw, LLVector3::z_axis); + + LLQuaternion av_rot = camera_rot; + LLViewerCamera::getInstance()->setOriginAndLookAt( + target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + offset) * av_rot), // camera + LLVector3::z_axis, // up + target_pos); // point of interest + + + LLViewerCamera::getInstance()->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, width, height, FALSE, z_near, z_far); + + stop_glerror(); + + gGL.pushMatrix(); + const F32 BRIGHTNESS = 0.9f; + gGL.color3f(BRIGHTNESS, BRIGHTNESS, BRIGHTNESS); + + LLGLEnable normalize(GL_NORMALIZE); + + if (!mBaseModel.empty() && mVertexBuffer[5].empty()) + { + genBuffers(-1, skin_weight); + //genBuffers(3); + //genLODs(); + } + + if (!mModel[mPreviewLOD].empty()) + { + bool regen = mVertexBuffer[mPreviewLOD].empty(); + if (!regen) + { + const std::vector >& vb_vec = mVertexBuffer[mPreviewLOD].begin()->second; + if (!vb_vec.empty()) + { + const LLVertexBuffer* buff = vb_vec[0]; + regen = buff->hasDataType(LLVertexBuffer::TYPE_WEIGHT4) != skin_weight; + } + } + + if (regen) + { + genBuffers(mPreviewLOD, skin_weight); + } + + if (!skin_weight) + { + for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) + { + LLModelInstance& instance = *iter; + + LLModel* model = instance.mLOD[mPreviewLOD]; + + if (!model) + { + continue; + } + + gGL.pushMatrix(); + LLMatrix4 mat = instance.mTransform; + + glMultMatrixf((GLfloat*) mat.mMatrix); + + for (U32 i = 0; i < mVertexBuffer[mPreviewLOD][model].size(); ++i) + { + LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; + + buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); + + if (textures) + { + glColor4fv(instance.mMaterial[i].mDiffuseColor.mV); + if (i < instance.mMaterial.size() && instance.mMaterial[i].mDiffuseMap.notNull()) + { + gGL.getTexUnit(0)->bind(instance.mMaterial[i].mDiffuseMap, true); + if (instance.mMaterial[i].mDiffuseMap->getDiscardLevel() > -1) + { + mTextureSet.insert(instance.mMaterial[i].mDiffuseMap.get()); + } + } + } + else + { + glColor4f(1,1,1,1); + } + + buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + glColor3f(0.4f, 0.4f, 0.4f); + + if (edges) + { + glLineWidth(3.f); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glLineWidth(1.f); + } + } + gGL.popMatrix(); + } + + if (physics) + { + glClear(GL_DEPTH_BUFFER_BIT); + LLGLEnable blend(GL_BLEND); + gGL.blendFunc(LLRender::BF_ONE, LLRender::BF_ZERO); + + for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) + { + LLModelInstance& instance = *iter; + + LLModel* model = instance.mLOD[LLModel::LOD_PHYSICS]; + + if (!model) + { + continue; + } + + gGL.pushMatrix(); + LLMatrix4 mat = instance.mTransform; + + glMultMatrixf((GLfloat*) mat.mMatrix); + + + bool render_mesh = true; + + LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread; + if (decomp) + { + LLMutexLock(decomp->mMutex); + + std::map, std::vector > >::iterator iter = + mPhysicsMesh.find(model); + if (iter != mPhysicsMesh.end()) + { //render hull instead of mesh + render_mesh = false; + for (U32 i = 0; i < iter->second.size(); ++i) + { + if (explode > 0.f) + { + gGL.pushMatrix(); + + LLVector3 offset = model->mHullCenter[i]-model->mCenterOfHullCenters; + offset *= explode; + + gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]); + } + + static std::vector hull_colors; + + if (i+1 >= hull_colors.size()) + { + hull_colors.push_back(LLColor4U(rand()%128+127, rand()%128+127, rand()%128+127, 255)); + } + + LLVertexBuffer* buff = iter->second[i]; + if (buff) + { + buff->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL); + + glColor4ubv(hull_colors[i].mV); + buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts()); + } + + if (explode > 0.f) + { + gGL.popMatrix(); + } + } + } + } + + if (render_mesh) + { + if (mVertexBuffer[LLModel::LOD_PHYSICS].empty()) + { + genBuffers(LLModel::LOD_PHYSICS, false); + } + for (U32 i = 0; i < mVertexBuffer[LLModel::LOD_PHYSICS][model].size(); ++i) + { + LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][i]; + + buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); + + buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + glColor4f(0.4f, 0.4f, 0.0f, 0.4f); + + buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); + + glColor3f(1.f, 1.f, 0.f); + + glLineWidth(3.f); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glLineWidth(1.f); + } + } + + gGL.popMatrix(); + } + + gGL.setSceneBlendType(LLRender::BT_ALPHA); + } + } + else + { + LLVOAvatarSelf* avatar = gAgentAvatarp; + target_pos = avatar->getPositionAgent(); + + LLViewerCamera::getInstance()->setOriginAndLookAt( + target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + offset) * av_rot), // camera + LLVector3::z_axis, // up + target_pos); // point of interest + + if (joint_positions) + { + avatar->renderCollisionVolumes(); + } + + for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) + { + for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) + { + LLModelInstance& instance = *model_iter; + LLModel* model = instance.mModel; + + if (!model->mSkinWeights.empty()) + { + for (U32 i = 0; i < mVertexBuffer[mPreviewLOD][model].size(); ++i) + { + LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; + + const LLVolumeFace& face = model->getVolumeFace(i); + + LLStrider position; + buffer->getVertexStrider(position); + + LLStrider weight; + buffer->getWeight4Strider(weight); + + //quick 'n dirty software vertex skinning + + //build matrix palette + LLMatrix4 mat[64]; + for (U32 j = 0; j < model->mJointList.size(); ++j) + { + LLJoint* joint = avatar->getJoint(model->mJointList[j]); + if (joint) + { + mat[j] = model->mInvBindMatrix[j]; + mat[j] *= joint->getWorldMatrix(); + } + } + + for (U32 j = 0; j < buffer->getRequestedVerts(); ++j) + { + LLMatrix4 final_mat; + final_mat.mMatrix[0][0] = final_mat.mMatrix[1][1] = final_mat.mMatrix[2][2] = final_mat.mMatrix[3][3] = 0.f; + + LLVector4 wght; + S32 idx[4]; + + F32 scale = 0.f; + for (U32 k = 0; k < 4; k++) + { + F32 w = weight[j].mV[k]; + + idx[k] = (S32) floorf(w); + wght.mV[k] = w - floorf(w); + scale += wght.mV[k]; + } + + wght *= 1.f/scale; + + for (U32 k = 0; k < 4; k++) + { + F32* src = (F32*) mat[idx[k]].mMatrix; + F32* dst = (F32*) final_mat.mMatrix; + + F32 w = wght.mV[k]; + + for (U32 l = 0; l < 16; l++) + { + dst[l] += src[l]*w; + } + } + + //VECTORIZE THIS + LLVector3 v(face.mPositions[j].getF32ptr()); + + v = v * model->mBindShapeMatrix; + v = v * final_mat; + + position[j] = v; + } + + buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); + glColor4fv(instance.mMaterial[i].mDiffuseColor.mV); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); + glColor3f(0.4f, 0.4f, 0.4f); + + if (edges) + { + glLineWidth(3.f); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glLineWidth(1.f); + } + } + } + } + } + } + } + + gGL.popMatrix(); + + return TRUE; +} + +//----------------------------------------------------------------------------- +// refresh() +//----------------------------------------------------------------------------- +void LLModelPreview::refresh() +{ + mNeedsUpdate = TRUE; +} + +//----------------------------------------------------------------------------- +// rotate() +//----------------------------------------------------------------------------- +void LLModelPreview::rotate(F32 yaw_radians, F32 pitch_radians) +{ + mCameraYaw = mCameraYaw + yaw_radians; + + mCameraPitch = llclamp(mCameraPitch + pitch_radians, F_PI_BY_TWO * -0.8f, F_PI_BY_TWO * 0.8f); +} + +//----------------------------------------------------------------------------- +// zoom() +//----------------------------------------------------------------------------- +void LLModelPreview::zoom(F32 zoom_amt) +{ + F32 new_zoom = mCameraZoom+zoom_amt; + + mCameraZoom = llclamp(new_zoom, 1.f, 10.f); +} + +void LLModelPreview::pan(F32 right, F32 up) +{ + mCameraOffset.mV[VY] = llclamp(mCameraOffset.mV[VY] + right * mCameraDistance / mCameraZoom, -1.f, 1.f); + mCameraOffset.mV[VZ] = llclamp(mCameraOffset.mV[VZ] + up * mCameraDistance / mCameraZoom, -1.f, 1.f); +} + +void LLModelPreview::setPreviewLOD(S32 lod) +{ + lod = llclamp(lod, 0, (S32) LLModel::LOD_HIGH); + + if (lod != mPreviewLOD) + { + mPreviewLOD = lod; + + LLComboBox* combo_box = mFMP->getChild("preview_lod_combo"); + combo_box->setCurrentByIndex((NUM_LOD-1)-mPreviewLOD); // combo box list of lods is in reverse order + mFMP->childSetTextArg("lod_table_footer", "[DETAIL]", mFMP->getString(lod_name[mPreviewLOD])); + mFMP->childSetText("lod_file", mLODFile[mPreviewLOD]); + + // the wizard has three lod drop downs + LLComboBox* combo_box2 = mFMP->getChild("preview_lod_combo2"); + combo_box2->setCurrentByIndex((NUM_LOD-1)-mPreviewLOD); // combo box list of lods is in reverse order + + LLComboBox* combo_box3 = mFMP->getChild("preview_lod_combo3"); + combo_box2->setCurrentByIndex((NUM_LOD-1)-mPreviewLOD); // combo box list of lods is in reverse order + + LLColor4 highlight_color = LLUIColorTable::instance().getColor("MeshImportTableHighlightColor"); + LLColor4 normal_color = LLUIColorTable::instance().getColor("MeshImportTableNormalColor"); + + for (S32 i = 0; i <= LLModel::LOD_HIGH; ++i) + { + const LLColor4& color = (i == lod) ? highlight_color : normal_color; + + mFMP->childSetColor(lod_status_name[i], color); + mFMP->childSetColor(lod_label_name[i], color); + mFMP->childSetColor(lod_triangles_name[i], color); + mFMP->childSetColor(lod_vertices_name[i], color); + } + + LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; + if (fmp) + { + LLRadioGroup* radio = fmp->getChild("lod_file_or_limit"); + radio->selectNthItem(fmp->mLODMode[mPreviewLOD]); + } + } + refresh(); + updateStatusMessages(); +} + +//static +void LLFloaterModelPreview::onBrowseLOD(void* data) +{ + assert_main_thread(); + + LLFloaterModelPreview* mp = (LLFloaterModelPreview*) data; + mp->loadModel(mp->mModelPreview->mPreviewLOD); +} + +//static +void LLFloaterModelPreview::onUpload(void* user_data) +{ + assert_main_thread(); + + LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; + + if ( mp && mp->mModelPreview->mHasPivot ) + { + mp->mModelPreview->alterModelsPivot(); + } + + mp->mModelPreview->rebuildUploadData(); + + bool upload_skinweights = mp->childGetValue("upload_skin").asBoolean(); + bool upload_joint_positions = mp->childGetValue("upload_joints").asBoolean(); + + mp->mModelPreview->saveUploadData(upload_skinweights, upload_joint_positions); + + gMeshRepo.uploadModel(mp->mModelPreview->mUploadData, mp->mModelPreview->mPreviewScale, + mp->childGetValue("upload_textures").asBoolean(), upload_skinweights, upload_joint_positions); + + mp->closeFloater(false); +} + + +//static +void LLFloaterModelPreview::onClearMaterials(void* user_data) +{ + LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; + mp->mModelPreview->clearMaterials(); +} + +//static +void LLFloaterModelPreview::refresh(LLUICtrl* ctrl, void* user_data) +{ + sInstance->mModelPreview->mDirty = true; +} + +void LLFloaterModelPreview::updateResourceCost() +{ + U32 cost = mModelPreview->mResourceCost; + childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d",cost)); +} + +//static +void LLModelPreview::textureLoadedCallback( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata ) +{ + LLModelPreview* preview = (LLModelPreview*) userdata; + preview->refresh(); +} + +void LLModelPreview::onLODParamCommit(bool enforce_tri_limit) +{ + genLODs(mPreviewLOD, 3, enforce_tri_limit); + updateStatusMessages(); + refresh(); +} + +LLFloaterModelPreview::DecompRequest::DecompRequest(const std::string& stage, LLModel* mdl) +{ + mStage = stage; + mContinue = 1; + mModel = mdl; + mDecompID = &mdl->mDecompID; + mParams = sInstance->mDecompParams; + + //copy out positions and indices + if (mdl) + { + U16 index_offset = 0; + + mPositions.clear(); + mIndices.clear(); + + //queue up vertex positions and indices + for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) + { + const LLVolumeFace& face = mdl->getVolumeFace(i); + if (mPositions.size() + face.mNumVertices > 65535) + { + continue; + } + + for (U32 j = 0; j < face.mNumVertices; ++j) + { + mPositions.push_back(LLVector3(face.mPositions[j].getF32ptr())); + } + + for (U32 j = 0; j < face.mNumIndices; ++j) + { + mIndices.push_back(face.mIndices[j]+index_offset); + } + + index_offset += face.mNumVertices; + } + } +} + +void LLFloaterModelPreview::setStatusMessage(const std::string& msg) +{ + LLMutexLock lock(mStatusLock); + mStatusMessage = msg; +} + +S32 LLFloaterModelPreview::DecompRequest::statusCallback(const char* status, S32 p1, S32 p2) +{ + if (mContinue) + { + setStatusMessage(llformat("%s: %d/%d", status, p1, p2)); + if (LLFloaterModelPreview::sInstance) + { + LLFloaterModelPreview::sInstance->setStatusMessage(mStatusMessage); + } + } + + return mContinue; +} + +void LLFloaterModelPreview::DecompRequest::completed() +{ //called from the main thread + if (mContinue) + { + mModel->setConvexHullDecomposition(mHull); + + if (sInstance) + { + if (mContinue) + { + if (sInstance->mModelPreview) + { + sInstance->mModelPreview->mPhysicsMesh[mModel] = mHullMesh; + sInstance->mModelPreview->mDirty = true; + LLFloaterModelPreview::sInstance->mModelPreview->refresh(); + } + } + + sInstance->mCurRequest.erase(this); + } + } + else if (sInstance) + { + llassert(sInstance->mCurRequest.find(this) == sInstance->mCurRequest.end()); + } +} -- cgit v1.2.3 From 7c27fd2037bc49cf4169db31e9dd1e4612c53ef8 Mon Sep 17 00:00:00 2001 From: Leyla Farazha Date: Mon, 28 Mar 2011 13:12:47 -0700 Subject: fixing unused LLComboBox issue that was causing mac/linux breakage --- indra/newview/llfloatermodelpreview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 254f9f8a5e..e6ff25bcff 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -4523,7 +4523,7 @@ void LLModelPreview::setPreviewLOD(S32 lod) combo_box2->setCurrentByIndex((NUM_LOD-1)-mPreviewLOD); // combo box list of lods is in reverse order LLComboBox* combo_box3 = mFMP->getChild("preview_lod_combo3"); - combo_box2->setCurrentByIndex((NUM_LOD-1)-mPreviewLOD); // combo box list of lods is in reverse order + combo_box3->setCurrentByIndex((NUM_LOD-1)-mPreviewLOD); // combo box list of lods is in reverse order LLColor4 highlight_color = LLUIColorTable::instance().getColor("MeshImportTableHighlightColor"); LLColor4 normal_color = LLUIColorTable::instance().getColor("MeshImportTableNormalColor"); -- cgit v1.2.3 From 7c993e449067a70e8008f97595c2ddb9a916c86d Mon Sep 17 00:00:00 2001 From: Leyla Farazha Date: Mon, 28 Mar 2011 13:16:34 -0700 Subject: fixing line endings in llfloatermodelpreview.cpp --- indra/newview/llfloatermodelpreview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index d7a285c666..68373981df 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -2492,7 +2492,7 @@ U32 LLModelPreview::calcResourceCost() F32 debug_scale = mFMP ? mFMP->childGetValue("import_scale").asReal() : 1.f; mPelvisZOffset = mFMP ? mFMP->childGetValue("pelvis_offset").asReal() : 3.0f; - + if ( mFMP && mFMP->childGetValue("upload_joints").asBoolean() ) { gAgentAvatarp->setPelvisOffset( mPelvisZOffset ); -- cgit v1.2.3 From 86f3c3f276f131c4a192268733e7fc8b7e81d2c9 Mon Sep 17 00:00:00 2001 From: prep Date: Mon, 28 Mar 2011 17:50:12 -0400 Subject: Fix for issue caused by uploading the TurboSquid book collection (that avatar was having it's joints reet) --- indra/newview/llfloatermodelpreview.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index e440fa52d4..eebeb53cdb 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -389,7 +389,11 @@ LLFloaterModelPreview::~LLFloaterModelPreview() gAgentAvatarp->resetJointPositions(); } - delete mModelPreview; + + if ( mModelPreview ) + { + delete mModelPreview; + } if (mGLName) { @@ -1556,7 +1560,7 @@ bool LLModelLoader::doLoadModel() //a skinned asset attached to a node in a file that contains an entire skeleton, //but does not use the skeleton). mPreview->setRigValid( doesJointArrayContainACompleteRig( model->mJointList ) ); - if ( !skeletonWithNoRootNode && !model->mJointList.empty() && mPreview->isRigValid() ) + if ( !skeletonWithNoRootNode && !model->mJointList.empty() && mPreview->isRigValid() ) { mResetJoints = true; } @@ -1878,8 +1882,6 @@ void LLModelLoader::loadModelCallback() { //wait until this thread is stopped before deleting self apr_sleep(100); } - - delete this; } void LLModelLoader::handlePivotPoint( daeElement* pRoot ) @@ -2454,7 +2456,8 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) LLModelPreview::~LLModelPreview() { if (mModelLoader) - { + { + delete mModelLoader; mModelLoader->mPreview = NULL; } //*HACK : *TODO : turn this back on when we understand why this crashes -- cgit v1.2.3 From 1ff79683128f09baf6dbaf081092fda7e5f2fe65 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Mon, 28 Mar 2011 23:50:23 -0500 Subject: SH-1225 Add skinning info to import path of .slm files. --- indra/newview/llfloatermodelpreview.cpp | 88 +++++++++++++++++++++++---------- 1 file changed, 61 insertions(+), 27 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index e440fa52d4..2204908bdf 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1326,17 +1326,19 @@ bool LLModelLoader::doLoadModel() { //get bind shape matrix domFloat4x4& dom_value = bind_mat->getValue(); + LLMeshSkinInfo& skin_info = model->mSkinInfo; + for (int i = 0; i < 4; i++) { for(int j = 0; j < 4; j++) { - model->mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j*4]; + skin_info.mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j*4]; } } LLMatrix4 trans = normalized_transformation; - trans *= model->mBindShapeMatrix; - model->mBindShapeMatrix = trans; + trans *= skin_info.mBindShapeMatrix; + skin_info.mBindShapeMatrix = trans; } @@ -1475,7 +1477,7 @@ bool LLModelLoader::doLoadModel() xsNMTOKEN semantic = input->getSemantic(); if (strcmp(semantic, COMMON_PROFILE_INPUT_JOINT) == 0) - { //found joint source, fill model->mJointMap and model->mJointList + { //found joint source, fill model->mJointMap and model->mSkinInfo.mJointNames daeElement* elem = input->getSource().getElement(); domSource* source = daeSafeCast(elem); @@ -1496,8 +1498,8 @@ bool LLModelLoader::doLoadModel() { name = mJointMap[name]; } - model->mJointList.push_back(name); - model->mJointMap[name] = j; + model->mSkinInfo.mJointNames.push_back(name); + model->mSkinInfo.mJointMap[name] = j; } } else @@ -1514,8 +1516,8 @@ bool LLModelLoader::doLoadModel() { name = mJointMap[name]; } - model->mJointList.push_back(name); - model->mJointMap[name] = j; + model->mSkinInfo.mJointNames.push_back(name); + model->mSkinInfo.mJointMap[name] = j; } } } @@ -1544,7 +1546,7 @@ bool LLModelLoader::doLoadModel() } } - model->mInvBindMatrix.push_back(mat); + model->mSkinInfo.mInvBindMatrix.push_back(mat); } } } @@ -1555,8 +1557,8 @@ bool LLModelLoader::doLoadModel() //(which means we have all the joints that are required for an avatar versus //a skinned asset attached to a node in a file that contains an entire skeleton, //but does not use the skeleton). - mPreview->setRigValid( doesJointArrayContainACompleteRig( model->mJointList ) ); - if ( !skeletonWithNoRootNode && !model->mJointList.empty() && mPreview->isRigValid() ) + mPreview->setRigValid( doesJointArrayContainACompleteRig( model->mSkinInfo.mJointNames ) ); + if ( !skeletonWithNoRootNode && !model->mSkinInfo.mJointNames.empty() && mPreview->isRigValid() ) { mResetJoints = true; } @@ -1596,8 +1598,8 @@ bool LLModelLoader::doLoadModel() //in the same order as they were stored in the joint buffer. The joints associated //with the skeleton are not stored in the same order as they are in the exported joint buffer. //This remaps the skeletal joints to be in the same order as the joints stored in the model. - std::vector :: const_iterator jointIt = model->mJointList.begin(); - const int jointCnt = model->mJointList.size(); + std::vector :: const_iterator jointIt = model->mSkinInfo.mJointNames.begin(); + const int jointCnt = model->mSkinInfo.mJointNames.size(); for ( int i=0; imInvBindMatrix[i]; + LLMatrix4 newInverse = model->mSkinInfo.mInvBindMatrix[i]; newInverse.setTranslation( jointTransforms[lookingForJoint].getTranslation() ); - model->mAlternateBindMatrix.push_back( newInverse ); + model->mSkinInfo.mAlternateBindMatrix.push_back( newInverse ); } else { @@ -1813,10 +1815,15 @@ bool LLModelLoader::loadFromSLM(const std::string& filename) { std::stringstream str(mesh[i].asString()); LLPointer loaded_model = new LLModel(volume_params, (F32) lod); - if (loaded_model->createVolumeFacesFromStream(str)) + if (loaded_model->loadModel(str)) { loaded_model->mLocalID = i; model[lod].push_back(loaded_model); + + if (lod == LLModel::LOD_HIGH && !loaded_model->mSkinInfo.mJointNames.empty()) + { //check to see if rig is valid + mPreview->setRigValid( doesJointArrayContainACompleteRig( loaded_model->mSkinInfo.mJointNames ) ); + } } else { @@ -1871,7 +1878,7 @@ void LLModelLoader::loadModelCallback() { if (mPreview) { - mPreview->loadModelCallback(mLod); + mPreview->loadModelCallback(mLod); } while (!isStopped()) @@ -2901,6 +2908,9 @@ void LLModelPreview::loadModelCallback(S32 lod) mBaseModel.clear(); mBaseScene.clear(); + bool skin_weights = false; + bool joint_positions = false; + for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) { //for each LoD @@ -2933,12 +2943,40 @@ void LLModelPreview::loadModelCallback(S32 lod) mModel[lod].resize(idx+1); } - mModel[lod][idx] = list_iter->mModel; + mModel[lod][idx] = list_iter->mModel; + if (!list_iter->mModel->mSkinWeights.empty()) + { + skin_weights = true; + + if (!list_iter->mModel->mSkinInfo.mAlternateBindMatrix.empty()) + { + joint_positions = true; + } + } } } } } + if (mFMP) + { + LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) mFMP; + + if (skin_weights) + { //enable uploading/previewing of skin weights if present in .slm file + fmp->enableViewOption("show_skin_weight"); + mViewOption["show_skin_weight"] = true; + fmp->childSetValue("upload_skin", true); + } + + if (joint_positions) + { + fmp->enableViewOption("show_joint_positions"); + mViewOption["show_joint_positions"] = true; + fmp->childSetValue("upload_joints", true); + } + } + //copy high lod to base scene for LoD generation mBaseScene = mScene[LLModel::LOD_HIGH]; mBaseModel = mModel[LLModel::LOD_HIGH]; @@ -3415,11 +3453,7 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim //of an open problem). target_model->mPosition = base->mPosition; target_model->mSkinWeights = base->mSkinWeights; - target_model->mJointMap = base->mJointMap; - target_model->mJointList = base->mJointList; - target_model->mInvBindMatrix = base->mInvBindMatrix; - target_model->mBindShapeMatrix = base->mBindShapeMatrix; - target_model->mAlternateBindMatrix = base->mAlternateBindMatrix; + target_model->mSkinInfo = base->mSkinInfo; //copy material list target_model->mMaterialList = base->mMaterialList; @@ -4391,12 +4425,12 @@ BOOL LLModelPreview::render() //build matrix palette LLMatrix4 mat[64]; - for (U32 j = 0; j < model->mJointList.size(); ++j) + for (U32 j = 0; j < model->mSkinInfo.mJointNames.size(); ++j) { - LLJoint* joint = avatar->getJoint(model->mJointList[j]); + LLJoint* joint = avatar->getJoint(model->mSkinInfo.mJointNames[j]); if (joint) { - mat[j] = model->mInvBindMatrix[j]; + mat[j] = model->mSkinInfo.mInvBindMatrix[j]; mat[j] *= joint->getWorldMatrix(); } } @@ -4437,7 +4471,7 @@ BOOL LLModelPreview::render() //VECTORIZE THIS LLVector3 v(face.mPositions[j].getF32ptr()); - v = v * model->mBindShapeMatrix; + v = v * model->mSkinInfo.mBindShapeMatrix; v = v * final_mat; position[j] = v; -- cgit v1.2.3 From 719610e68ba8275f08f51d127ab760799cb1d1c3 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 29 Mar 2011 11:50:02 -0500 Subject: SH-1225 Import convex hull data from .slm --- indra/newview/llfloatermodelpreview.cpp | 47 ++++++++++++--------------------- 1 file changed, 17 insertions(+), 30 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index d8088e2f51..541511e448 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -2520,8 +2520,8 @@ U32 LLModelPreview::calcResourceCost() LLModel::convex_hull_decomposition& decomp = instance.mLOD[LLModel::LOD_PHYSICS] ? - instance.mLOD[LLModel::LOD_PHYSICS]->mConvexHullDecomp : - instance.mModel->mConvexHullDecomp; + instance.mLOD[LLModel::LOD_PHYSICS]->mPhysics.mHull : + instance.mModel->mPhysics.mHull; LLSD ret = LLModel::writeModel( "", @@ -2739,8 +2739,8 @@ void LLModelPreview::saveUploadData(const std::string& filename, bool save_skinw LLModel::convex_hull_decomposition& decomp = instance.mLOD[LLModel::LOD_PHYSICS].notNull() ? - instance.mLOD[LLModel::LOD_PHYSICS]->mConvexHullDecomp : - instance.mModel->mConvexHullDecomp; + instance.mLOD[LLModel::LOD_PHYSICS]->mPhysics.mHull : + instance.mModel->mPhysics.mHull; LLModel::writeModel(str, instance.mLOD[LLModel::LOD_PHYSICS], @@ -2993,14 +2993,8 @@ void LLModelPreview::loadModelCallback(S32 lod) mScene[lod] = mModelLoader->mScene; mVertexBuffer[lod].clear(); - if (lod == LLModel::LOD_PHYSICS) - { - mPhysicsMesh.clear(); - } - setPreviewLOD(lod); - if (lod == LLModel::LOD_HIGH) { //save a copy of the highest LOD for automatic LOD manipulation if (mBaseModel.empty()) @@ -3123,11 +3117,6 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim return; } - if (which_lod == LLModel::LOD_PHYSICS) - { //clear physics mesh map - mPhysicsMesh.clear(); - } - LLVertexBuffer::unbind(); stop_gloderror(); @@ -3676,7 +3665,7 @@ void LLModelPreview::updateStatusMessages() LLModel* model = mModel[LLModel::LOD_PHYSICS][i]; S32 cur_submeshes = model->getNumVolumeFaces(); - LLModel::convex_hull_decomposition& decomp = model->mConvexHullDecomp; + LLModel::convex_hull_decomposition& decomp = model->mPhysics.mHull; if (!decomp.empty()) { @@ -4313,12 +4302,17 @@ BOOL LLModelPreview::render() { LLMutexLock(decomp->mMutex); - std::map, std::vector > >::iterator iter = - mPhysicsMesh.find(model); - if (iter != mPhysicsMesh.end()) + LLModel::Decomposition& physics = model->mPhysics; + + if (physics.mMesh.empty()) + { //build vertex buffer for physics mesh + gMeshRepo.buildPhysicsMesh(physics); + } + + if (!physics.mMesh.empty()) { //render hull instead of mesh render_mesh = false; - for (U32 i = 0; i < iter->second.size(); ++i) + for (U32 i = 0; i < physics.mMesh.size(); ++i) { if (explode > 0.f) { @@ -4337,15 +4331,9 @@ BOOL LLModelPreview::render() hull_colors.push_back(LLColor4U(rand()%128+127, rand()%128+127, rand()%128+127, 255)); } - LLVertexBuffer* buff = iter->second[i]; - if (buff) - { - buff->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL); - - glColor4ubv(hull_colors[i].mV); - buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts()); - } - + glColor4ubv(hull_colors[i].mV); + LLVertexBuffer::drawArrays(LLRender::TRIANGLES, physics.mMesh[i].mPositions, physics.mMesh[i].mNormals); + if (explode > 0.f) { gGL.popMatrix(); @@ -4724,7 +4712,6 @@ void LLFloaterModelPreview::DecompRequest::completed() { if (sInstance->mModelPreview) { - sInstance->mModelPreview->mPhysicsMesh[mModel] = mHullMesh; sInstance->mModelPreview->mDirty = true; LLFloaterModelPreview::sInstance->mModelPreview->refresh(); } -- cgit v1.2.3 From e69aa18c0dfbef2fa3bbefeba08fa1c258c69fb3 Mon Sep 17 00:00:00 2001 From: Leyla Farazha Date: Tue, 29 Mar 2011 16:32:28 -0700 Subject: SH-1247 Upload Wizard should pull in textures, if defined in .dae --- indra/newview/llfloatermodelpreview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 68373981df..4d498840fe 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -4218,9 +4218,9 @@ BOOL LLModelPreview::render() glColor4fv(instance.mMaterial[i].mDiffuseColor.mV); if (i < instance.mMaterial.size() && instance.mMaterial[i].mDiffuseMap.notNull()) { - gGL.getTexUnit(0)->bind(instance.mMaterial[i].mDiffuseMap, true); if (instance.mMaterial[i].mDiffuseMap->getDiscardLevel() > -1) { + gGL.getTexUnit(0)->bind(instance.mMaterial[i].mDiffuseMap, true); mTextureSet.insert(instance.mMaterial[i].mDiffuseMap.get()); } } -- cgit v1.2.3 From dd71a9faacbf52ab5a741c86924149251fadc009 Mon Sep 17 00:00:00 2001 From: prep Date: Wed, 30 Mar 2011 14:05:23 -0400 Subject: Fix for SH-1177 - Allowable range for an alternate pivot is -64 to 64 --- indra/newview/llfloatermodelpreview.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 4d7c079a6f..3cb756a006 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -111,6 +111,8 @@ const S32 PREVIEW_HPAD = PREVIEW_RESIZE_HANDLE_SIZE; const S32 PREF_BUTTON_HEIGHT = 16 + 7 + 16; const S32 PREVIEW_TEXTURE_HEIGHT = 300; +const F32 MAXIMUM_PIVOT_OFFSET = 64.0f; + void drawBoxOutline(const LLVector3& pos, const LLVector3& size); @@ -1913,8 +1915,19 @@ void LLModelLoader::handlePivotPoint( daeElement* pRoot ) if ( pTranslate ) { extractTranslation( pTranslate, workingTransform ); - mPreview->setModelPivot( workingTransform.getTranslation() ); - mPreview->setHasPivot( true ); + LLVector3 pivotTrans = workingTransform.getTranslation(); + if ( pivotTrans[VX] > MAXIMUM_PIVOT_OFFSET || pivotTrans[VX] < -MAXIMUM_PIVOT_OFFSET || + pivotTrans[VY] > MAXIMUM_PIVOT_OFFSET || pivotTrans[VY] < -MAXIMUM_PIVOT_OFFSET || + pivotTrans[VZ] > MAXIMUM_PIVOT_OFFSET || pivotTrans[VZ] < -MAXIMUM_PIVOT_OFFSET ) + { + llwarns<<"Asset Pivot Node contains an offset that is too large - values should be within (-"<setHasPivot( false ); + } + else + { + mPreview->setModelPivot( pivotTrans ); + mPreview->setHasPivot( true ); + } } } } -- cgit v1.2.3 From 080c5fe08382cf70042350e2812cab1513fb8a16 Mon Sep 17 00:00:00 2001 From: prep Date: Wed, 30 Mar 2011 15:03:05 -0400 Subject: Update skin instances pelvisoffset for each lod --- indra/newview/llfloatermodelpreview.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 3cb756a006..73405c294c 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -2535,6 +2535,15 @@ U32 LLModelPreview::calcResourceCost() instance.mLOD[LLModel::LOD_PHYSICS] ? instance.mLOD[LLModel::LOD_PHYSICS]->mPhysics.mHull : instance.mModel->mPhysics.mHull; + + //update instance skin info for each lod + for ( int j=0; jmSkinInfo.mPelvisOffset = mPelvisZOffset; + } + } LLSD ret = LLModel::writeModel( "", -- cgit v1.2.3 From 5aeac734bcfe92364a982dc31dcd6d483df25eac Mon Sep 17 00:00:00 2001 From: prep Date: Wed, 30 Mar 2011 15:04:51 -0400 Subject: Comment update --- indra/newview/llfloatermodelpreview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 73405c294c..99256e1dc1 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -2536,7 +2536,7 @@ U32 LLModelPreview::calcResourceCost() instance.mLOD[LLModel::LOD_PHYSICS]->mPhysics.mHull : instance.mModel->mPhysics.mHull; - //update instance skin info for each lod + //update instance skin info for each lods pelvisZoffset for ( int j=0; j Date: Wed, 30 Mar 2011 16:04:36 -0400 Subject: Moved joint reset flag into model preview --- indra/newview/llfloatermodelpreview.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 99256e1dc1..3da0c795d5 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -386,7 +386,8 @@ LLFloaterModelPreview::~LLFloaterModelPreview() sInstance = NULL; const LLModelLoader *model_loader = mModelPreview->mModelLoader; - if (model_loader && model_loader->mResetJoints) + + if ( mModelPreview && mModelPreview->getResetJointFlag() ) { gAgentAvatarp->resetJointPositions(); } @@ -394,7 +395,7 @@ LLFloaterModelPreview::~LLFloaterModelPreview() if ( mModelPreview ) { - delete mModelPreview; + delete mModelPreview; } if (mGLName) @@ -992,7 +993,7 @@ void LLFloaterModelPreview::onMouseCaptureLostModelPreview(LLMouseHandler* handl // LLModelLoader //----------------------------------------------------------------------------- LLModelLoader::LLModelLoader(std::string filename, S32 lod, LLModelPreview* preview) -: LLThread("Model Loader"), mFilename(filename), mLod(lod), mPreview(preview), mFirstTransform(TRUE), mResetJoints( FALSE ) +: LLThread("Model Loader"), mFilename(filename), mLod(lod), mPreview(preview), mFirstTransform(TRUE) { mJointMap["mPelvis"] = "mPelvis"; mJointMap["mTorso"] = "mTorso"; @@ -1566,14 +1567,14 @@ bool LLModelLoader::doLoadModel() mPreview->setRigValid( doesJointArrayContainACompleteRig( model->mSkinInfo.mJointNames ) ); if ( !skeletonWithNoRootNode && !model->mSkinInfo.mJointNames.empty() && mPreview->isRigValid() ) { - mResetJoints = true; + mPreview->setResetJointFlag( true ); } if ( !missingSkeletonOrScene ) { //Set the joint translations on the avatar - if it's a full mapping //The joints are reset in the dtor - if ( mResetJoints ) + if ( mPreview->getResetJointFlag() ) { std::map :: const_iterator masterJointIt = mJointMap.begin(); std::map :: const_iterator masterJointItEnd = mJointMap.end(); @@ -2438,6 +2439,7 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) : LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE), LLMutex(NULL) , mPelvisZOffset( 0.0f ) , mRigValid( false ) +, mResetJoints( false ) { mNeedsUpdate = TRUE; mCameraDistance = 0.f; -- cgit v1.2.3 From 6b9a2d24cce8efaa72c2fd60655998844394312d Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 30 Mar 2011 18:38:22 -0500 Subject: SH-477 Better mesh streaming cost estimation. --- indra/newview/llfloatermodelpreview.cpp | 34 ++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 541511e448..243f301e9d 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1093,7 +1093,7 @@ LLModelLoader::LLModelLoader(std::string filename, S32 lod, LLModelPreview* prev { //only try to load from slm if viewer is configured to do so and this is the //initial model load (not an LoD or physics shape) - mTrySLM = gSavedSettings.getBOOL("MeshImportUseSLM") && mPreview->mBaseModel.empty(); + mTrySLM = gSavedSettings.getBOOL("MeshImportUseSLM") && mPreview->mUploadData.empty(); mPreview->setLoadState(STARTING); } else @@ -1889,6 +1889,14 @@ void LLModelLoader::loadModelCallback() { //wait until this thread is stopped before deleting self apr_sleep(100); } + + //cleanup model loader + if (mPreview) + { + mPreview->mModelLoader = NULL; + } + + delete this; } void LLModelLoader::handlePivotPoint( daeElement* pRoot ) @@ -2518,13 +2526,13 @@ U32 LLModelPreview::calcResourceCost() { accounted.insert(instance.mModel); - LLModel::convex_hull_decomposition& decomp = + LLModel::Decomposition& decomp = instance.mLOD[LLModel::LOD_PHYSICS] ? - instance.mLOD[LLModel::LOD_PHYSICS]->mPhysics.mHull : - instance.mModel->mPhysics.mHull; + instance.mLOD[LLModel::LOD_PHYSICS]->mPhysics : + instance.mModel->mPhysics; - LLSD ret = LLModel::writeModel( - "", + std::stringstream ostr; + LLSD ret = LLModel::writeModel(ostr, instance.mLOD[4], instance.mLOD[3], instance.mLOD[2], @@ -2536,10 +2544,10 @@ U32 LLModelPreview::calcResourceCost() TRUE); cost += gMeshRepo.calcResourceCost(ret); - num_hulls += decomp.size(); - for (U32 i = 0; i < decomp.size(); ++i) + num_hulls += decomp.mHull.size(); + for (U32 i = 0; i < decomp.mHull.size(); ++i) { - num_points += decomp[i].size(); + num_points += decomp.mHull[i].size(); } //calculate streaming cost @@ -2737,10 +2745,10 @@ void LLModelPreview::saveUploadData(const std::string& filename, bool save_skinw std::stringstream str; - LLModel::convex_hull_decomposition& decomp = + LLModel::Decomposition& decomp = instance.mLOD[LLModel::LOD_PHYSICS].notNull() ? - instance.mLOD[LLModel::LOD_PHYSICS]->mPhysics.mHull : - instance.mModel->mPhysics.mHull; + instance.mLOD[LLModel::LOD_PHYSICS]->mPhysics : + instance.mModel->mPhysics; LLModel::writeModel(str, instance.mLOD[LLModel::LOD_PHYSICS], @@ -2749,7 +2757,7 @@ void LLModelPreview::saveUploadData(const std::string& filename, bool save_skinw instance.mLOD[LLModel::LOD_LOW], instance.mLOD[LLModel::LOD_IMPOSTOR], decomp, - empty_hull, save_skinweights, save_joint_positions); + save_skinweights, save_joint_positions); data["mesh"][instance.mModel->mLocalID] = str.str(); -- cgit v1.2.3 From b97c47c19cff4f33c6172bd18fd8b48063007a37 Mon Sep 17 00:00:00 2001 From: prep linden Date: Fri, 1 Apr 2011 12:57:45 -0400 Subject: Removed unused variable --- indra/newview/llfloatermodelpreview.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 21c9fca164..66d80e3bc3 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -384,8 +384,6 @@ BOOL LLFloaterModelPreview::postBuild() LLFloaterModelPreview::~LLFloaterModelPreview() { sInstance = NULL; - - const LLModelLoader *model_loader = mModelPreview->mModelLoader; if ( mModelPreview && mModelPreview->getResetJointFlag() ) { -- cgit v1.2.3 From f0c70a4ee3739c34b1da2ce384bfcf420f8c6c72 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Fri, 1 Apr 2011 10:58:34 -0600 Subject: fix for SH-1176: A Mesh That Crashes Client on Upload Attempt (due to triangle number overflowing) --- indra/newview/llfloatermodelpreview.cpp | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 21c9fca164..f2fa891bca 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -579,7 +579,14 @@ void LLFloaterModelPreview::draw() if (!mModelPreview->mLoading) { - childSetTextArg("status", "[STATUS]", getString("status_idle")); + if ( mModelPreview->getLoadState() > LLModelLoader::ERROR_PARSING ) + { + childSetTextArg("status", "[STATUS]", getString(LLModel::getStatusString(mModelPreview->getLoadState() - LLModelLoader::ERROR_PARSING))); + } + else + { + childSetTextArg("status", "[STATUS]", getString("status_idle")); + } } childSetTextArg("prim_cost", "[PRIM_COST]", llformat("%d", mModelPreview->mResourceCost)); @@ -1285,6 +1292,12 @@ bool LLModelLoader::doLoadModel() { LLPointer model = LLModel::loadModelFromDomMesh(mesh); + if(model->getStatus() != LLModel::NO_ERRORS) + { + setLoadState(ERROR_PARSING + model->getStatus()) ; + return true ; //abort + } + if (model.notNull() && validate_model(model)) { mModelList.push_back(model); @@ -2502,7 +2515,7 @@ U32 LLModelPreview::calcResourceCost() if (mFMP && mModelLoader) { - if ( getLoadState() != LLModelLoader::ERROR_PARSING ) + if ( getLoadState() < LLModelLoader::ERROR_PARSING ) { mFMP->childEnable("ok_btn"); } @@ -2856,7 +2869,7 @@ void LLModelPreview::loadModel(std::string filename, S32 lod) setPreviewLOD(lod); - if ( getLoadState() == LLModelLoader::ERROR_PARSING ) + if ( getLoadState() >= LLModelLoader::ERROR_PARSING ) { mFMP->childDisable("ok_btn"); } @@ -2938,8 +2951,14 @@ void LLModelPreview::loadModelCallback(S32 lod) LLMutexLock lock(this); if (!mModelLoader) { + mLoading = false ; return; } + if(getLoadState() >= LLModelLoader::ERROR_PARSING) + { + mLoading = false ; + return ; + } mModelLoader->loadTextures() ; @@ -3675,7 +3694,7 @@ void LLModelPreview::updateStatusMessages() } } - bool errorStateFromLoader = getLoadState() == LLModelLoader::ERROR_PARSING ? true : false; + bool errorStateFromLoader = getLoadState() >= LLModelLoader::ERROR_PARSING ? true : false; bool skinAndRigOk = true; bool uploadingSkin = mFMP->childGetValue("upload_skin").asBoolean(); -- cgit v1.2.3 From 1ccb583181410ebd0742b0e47047ff74cfadd45c Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Fri, 1 Apr 2011 16:47:59 -0400 Subject: added defaults button to reset model upload dialog from .dae file --- indra/newview/llfloatermodelpreview.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 21c9fca164..d356e22072 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -279,11 +279,6 @@ BOOL LLFloaterModelPreview::postBuild() return FALSE; } - - - - - childSetAction("lod_browse", onBrowseLOD, this); childSetCommitCallback("cancel_btn", onCancel, this); @@ -306,6 +301,8 @@ BOOL LLFloaterModelPreview::postBuild() childSetAction("ok_btn", onUpload, this); childDisable("ok_btn"); + childSetAction("reset_btn", onReset, this); + childSetAction("clear_materials", onClearMaterials, this); childSetCommitCallback("preview_lod_combo", onPreviewLODCommit, this); @@ -4618,6 +4615,17 @@ void LLFloaterModelPreview::onBrowseLOD(void* data) mp->loadModel(mp->mModelPreview->mPreviewLOD); } +//static +void LLFloaterModelPreview::onReset(void* user_data) +{ + assert_main_thread(); + + LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) user_data; + LLModelPreview* mp = fmp->mModelPreview; + std::string filename = mp->mLODFile[3]; + mp->loadModel(filename,3); +} + //static void LLFloaterModelPreview::onUpload(void* user_data) { -- cgit v1.2.3 From 0dd0758ab9114c53a274ff707d626c8fe5e7afb0 Mon Sep 17 00:00:00 2001 From: Leyla Farazha Date: Fri, 1 Apr 2011 15:05:17 -0700 Subject: SH-1269: Using SLM breaks upload model wizard --- indra/newview/llfloatermodelpreview.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index ff687386de..a808cc47a2 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1885,6 +1885,8 @@ bool LLModelLoader::loadFromSLM(const std::string& filename) mScene[cur_instance.mTransform].push_back(cur_instance); stretch_extents(cur_instance.mModel, cur_instance.mTransform, mExtents[0], mExtents[1], mFirstTransform); } + + setLoadState( DONE ); return true; } -- cgit v1.2.3 From c494e5c0d55b2da2f5aa5ea18fbccb670b2f3107 Mon Sep 17 00:00:00 2001 From: prep Date: Mon, 18 Apr 2011 10:41:32 -0400 Subject: WIP for SH-1281. Rigged assets are critiqued differently based upon whether they're avrigs w/wo joint offets and whether the asset contains a subset of the joints in the visual scene --- indra/newview/llfloatermodelpreview.cpp | 447 ++++++++++++++++++++++++++------ 1 file changed, 369 insertions(+), 78 deletions(-) (limited to 'indra/newview/llfloatermodelpreview.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index a808cc47a2..cdd2bcf8e3 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -340,7 +340,7 @@ BOOL LLFloaterModelPreview::postBuild() mPreviewRect = preview_panel->getRect(); - mModelPreview = new LLModelPreview(512, 512, this); + mModelPreview = new LLModelPreview(512, 512, this ); mModelPreview->setPreviewTarget(16.f); mModelPreview->setDetailsCallback(boost::bind(&LLFloaterModelPreview::setDetails, this, _1, _2, _3, _4, _5)); @@ -383,7 +383,7 @@ LLFloaterModelPreview::~LLFloaterModelPreview() sInstance = NULL; if ( mModelPreview && mModelPreview->getResetJointFlag() ) - { + { gAgentAvatarp->resetJointPositions(); } @@ -994,8 +994,11 @@ void LLFloaterModelPreview::onMouseCaptureLostModelPreview(LLMouseHandler* handl //----------------------------------------------------------------------------- // LLModelLoader //----------------------------------------------------------------------------- -LLModelLoader::LLModelLoader(std::string filename, S32 lod, LLModelPreview* preview) -: LLThread("Model Loader"), mFilename(filename), mLod(lod), mPreview(preview), mFirstTransform(TRUE) +LLModelLoader::LLModelLoader( std::string filename, S32 lod, LLModelPreview* preview, JointTransformMap& jointMap, + std::deque& jointsFromNodes ) +: mJointList( jointMap ) +, mJointsFromNode( jointsFromNodes ) +, LLThread("Model Loader"), mFilename(filename), mLod(lod), mPreview(preview), mFirstTransform(TRUE) { mJointMap["mPelvis"] = "mPelvis"; mJointMap["mTorso"] = "mTorso"; @@ -1073,27 +1076,6 @@ LLModelLoader::LLModelLoader(std::string filename, S32 lod, LLModelPreview* prev mJointMap["lShin"] = "mKneeLeft"; mJointMap["lFoot"] = "mFootLeft"; - //move into joint mapper class - mMasterJointList.push_front("mPelvis"); - mMasterJointList.push_front("mTorso"); - mMasterJointList.push_front("mChest"); - mMasterJointList.push_front("mNeck"); - mMasterJointList.push_front("mHead"); - mMasterJointList.push_front("mCollarLeft"); - mMasterJointList.push_front("mShoulderLeft"); - mMasterJointList.push_front("mElbowLeft"); - mMasterJointList.push_front("mWristLeft"); - mMasterJointList.push_front("mCollarRight"); - mMasterJointList.push_front("mShoulderRight"); - mMasterJointList.push_front("mElbowRight"); - mMasterJointList.push_front("mWristRight"); - mMasterJointList.push_front("mHipRight"); - mMasterJointList.push_front("mKneeRight"); - mMasterJointList.push_front("mFootRight"); - mMasterJointList.push_front("mHipLeft"); - mMasterJointList.push_front("mKneeLeft"); - mMasterJointList.push_front("mFootLeft"); - if (mPreview) { //only try to load from slm if viewer is configured to do so and this is the @@ -1356,12 +1338,8 @@ bool LLModelLoader::doLoadModel() skin_info.mBindShapeMatrix = trans; } - - - //The joint transfom map that we'll populate below - std::map jointTransforms; - jointTransforms.clear(); - + + //Some collada setup for accessing the skeleton daeElement* pElement = 0; dae.getDatabase()->getElement( &pElement, 0, 0, "skeleton" ); @@ -1410,7 +1388,7 @@ bool LLModelLoader::doLoadModel() domNode* pNode = daeSafeCast(children[i]); if ( isNodeAJoint( pNode ) ) { - processJointNode( pNode, jointTransforms ); + processJointNode( pNode, mJointList ); } } } @@ -1468,7 +1446,7 @@ bool LLModelLoader::doLoadModel() } //Store the joint transform w/respect to it's name. - jointTransforms[(*jointIt).second.c_str()] = workingTransform; + mJointList[(*jointIt).second.c_str()] = workingTransform; } } @@ -1571,13 +1549,10 @@ bool LLModelLoader::doLoadModel() //Now that we've parsed the joint array, let's determine if we have a full rig //(which means we have all the joints that are required for an avatar versus //a skinned asset attached to a node in a file that contains an entire skeleton, - //but does not use the skeleton). - mPreview->setRigValid( doesJointArrayContainACompleteRig( model->mSkinInfo.mJointNames ) ); - if ( !skeletonWithNoRootNode && !model->mSkinInfo.mJointNames.empty() && mPreview->isRigValid() ) - { - mPreview->setResetJointFlag( true ); - } + //but does not use the skeleton). + mPreview->critiqueRigForUploadApplicability( model->mSkinInfo.mJointNames ); + if ( !missingSkeletonOrScene ) { //Set the joint translations on the avatar - if it's a full mapping @@ -1590,10 +1565,10 @@ bool LLModelLoader::doLoadModel() { std::string lookingForJoint = (*masterJointIt).first.c_str(); - if ( jointTransforms.find( lookingForJoint ) != jointTransforms.end() ) + if ( mJointList.find( lookingForJoint ) != mJointList.end() ) { //llinfos<<"joint "<getJoint( lookingForJoint ); if ( pJoint ) { @@ -1609,6 +1584,7 @@ bool LLModelLoader::doLoadModel() } } //missingSkeletonOrScene + //We need to construct the alternate bind matrix (which contains the new joint positions) //in the same order as they were stored in the joint buffer. The joints associated //with the skeleton are not stored in the same order as they are in the exported joint buffer. @@ -1620,11 +1596,11 @@ bool LLModelLoader::doLoadModel() std::string lookingForJoint = (*jointIt).c_str(); //Look for the joint xform that we extracted from the skeleton, using the jointIt as the key //and store it in the alternate bind matrix - if ( jointTransforms.find( lookingForJoint ) != jointTransforms.end() ) + if ( mJointList.find( lookingForJoint ) != mJointList.end() ) { - LLMatrix4 jointTransform = jointTransforms[lookingForJoint]; + LLMatrix4 jointTransform = mJointList[lookingForJoint]; LLMatrix4 newInverse = model->mSkinInfo.mInvBindMatrix[i]; - newInverse.setTranslation( jointTransforms[lookingForJoint].getTranslation() ); + newInverse.setTranslation( mJointList[lookingForJoint].getTranslation() ); model->mSkinInfo.mAlternateBindMatrix.push_back( newInverse ); } else @@ -1787,7 +1763,11 @@ bool LLModelLoader::doLoadModel() processElement(scene); handlePivotPoint( root ); + + buildJointToNodeMappingFromScene( root ); + mPreview->critiqueJointToNodeMappingFromScene(); + return true; } @@ -1836,8 +1816,9 @@ bool LLModelLoader::loadFromSLM(const std::string& filename) model[lod].push_back(loaded_model); if (lod == LLModel::LOD_HIGH && !loaded_model->mSkinInfo.mJointNames.empty()) - { //check to see if rig is valid - mPreview->setRigValid( doesJointArrayContainACompleteRig( loaded_model->mSkinInfo.mJointNames ) ); + { + //check to see if rig is valid + mPreview->critiqueRigForUploadApplicability( loaded_model->mSkinInfo.mJointNames ); } } else @@ -1911,7 +1892,52 @@ void LLModelLoader::loadModelCallback() delete this; } - +//----------------------------------------------------------------------------- +// buildJointToNodeMappingFromScene() +//----------------------------------------------------------------------------- +void LLModelLoader::buildJointToNodeMappingFromScene( daeElement* pRoot ) +{ + daeElement* pScene = pRoot->getDescendant("visual_scene"); + if ( pScene ) + { + daeTArray< daeSmartRef > children = pScene->getChildren(); + S32 childCount = children.getCount(); + for (S32 i = 0; i < childCount; ++i) + { + domNode* pNode = daeSafeCast(children[i]); + processJointToNodeMapping( pNode ); + } + } +} +//----------------------------------------------------------------------------- +// processJointToNodeMapping() +//----------------------------------------------------------------------------- +void LLModelLoader::processJointToNodeMapping( domNode* pNode ) +{ + if ( isNodeAJoint( pNode ) ) + { + //1.Store the parent + std::string nodeName = pNode->getName(); + if ( !nodeName.empty() ) + { + mJointsFromNode.push_front( pNode->getName() ); + } + //2. Handle the kiddo's + daeTArray< daeSmartRef > childOfChild = pNode->getChildren(); + S32 childOfChildCount = childOfChild.getCount(); + for (S32 i = 0; i < childOfChildCount; ++i) + { + domNode* pChildNode = daeSafeCast( childOfChild[i] ); + if ( pChildNode ) + { + processJointToNodeMapping( pChildNode ); + } + } + } +} +//----------------------------------------------------------------------------- +// handlePivotPoint() +//----------------------------------------------------------------------------- void LLModelLoader::handlePivotPoint( daeElement* pRoot ) { //Import an optional pivot point - a pivot point is just a node in the visual scene named "AssetPivot" @@ -1953,37 +1979,157 @@ void LLModelLoader::handlePivotPoint( daeElement* pRoot ) } } -bool LLModelLoader::doesJointArrayContainACompleteRig( const std::vector &jointListFromModel ) +//----------------------------------------------------------------------------- +// critiqueRigForUploadApplicability() +//----------------------------------------------------------------------------- +void LLModelPreview::critiqueRigForUploadApplicability( const std::vector &jointListFromAsset ) +{ + //Determines the following use cases for a rig: + //1. It is suitable for upload with skin weights & joint positions, or + //2. It is suitable for upload as standard av with just skin weights + + bool isJointPositionUploadOK = isRigSuitableForJointPositionUpload( jointListFromAsset ); + bool isRigLegacyOK = isRigLegacy( jointListFromAsset ); + + //It's OK that both could end up being true, both default to false + if ( isJointPositionUploadOK ) + { + setRigValidForJointPositionUpload( true ); + } + + if ( isRigLegacyOK ) + { + setLegacyRigValid( true ); + } + + if ( isJointPositionUploadOK ) + { + setResetJointFlag( true ); + } +} +//----------------------------------------------------------------------------- +// critiqueJointToNodeMappingFromScene() +//----------------------------------------------------------------------------- +void LLModelPreview::critiqueJointToNodeMappingFromScene( void ) +{ + //Do the actual nodes back the joint listing from the dae? + //if yes then this is a fully rigged asset, otherwise it's just a partial rig + + std::deque::iterator jointsFromNodeIt = mJointsFromNode.begin(); + std::deque::iterator jointsFromNodeEndIt = mJointsFromNode.end(); + bool result = true; + + if ( !mJointsFromNode.empty() ) + { + for ( ;jointsFromNodeIt!=jointsFromNodeEndIt;++jointsFromNodeIt ) + { + std::string name = *jointsFromNodeIt; + if ( mJointTransformMap.find( name ) != mJointTransformMap.end() ) + { + continue; + } + else + { + llinfos<<"critiqueJointToNodeMappingFromScene is missing a: "< &jointListFromAsset ) +{ + //No joints in asset + if ( jointListFromAsset.size() == 0 ) + { + return false; + } + + bool result = false; + + std::deque :: const_iterator masterJointIt = mMasterLegacyJointList.begin(); + std::deque :: const_iterator masterJointEndIt = mMasterLegacyJointList.end(); + + std::vector :: const_iterator modelJointIt = jointListFromAsset.begin(); + std::vector :: const_iterator modelJointItEnd = jointListFromAsset.end(); + + for ( ;masterJointIt!=masterJointEndIt;++masterJointIt ) + { + result = false; + modelJointIt = jointListFromAsset.begin(); + + for ( ;modelJointIt!=modelJointItEnd; ++modelJointIt ) + { + if ( *masterJointIt == *modelJointIt ) + { + result = true; + break; + } + } + if ( !result ) + { + llinfos<<" Asset did not contain the joint (if you're u/l a fully rigged asset w/joint positions - it is required)." << *masterJointIt<< llendl; + break; + } + } + return result; +} +//----------------------------------------------------------------------------- +// isRigSuitableForJointPositionUpload() +//----------------------------------------------------------------------------- +bool LLModelPreview::isRigSuitableForJointPositionUpload( const std::vector &jointListFromAsset ) { + bool result = false; + std::deque :: const_iterator masterJointIt = mMasterJointList.begin(); std::deque :: const_iterator masterJointEndIt = mMasterJointList.end(); - std::vector :: const_iterator modelJointIt = jointListFromModel.begin(); - std::vector :: const_iterator modelJointItEnd = jointListFromModel.end(); + std::vector :: const_iterator modelJointIt = jointListFromAsset.begin(); + std::vector :: const_iterator modelJointItEnd = jointListFromAsset.end(); - bool found = false; for ( ;masterJointIt!=masterJointEndIt;++masterJointIt ) { - found = false; - modelJointIt = jointListFromModel.begin(); + result = false; + modelJointIt = jointListFromAsset.begin(); + for ( ;modelJointIt!=modelJointItEnd; ++modelJointIt ) { if ( *masterJointIt == *modelJointIt ) { - found = true; + result = true; break; } } - if ( !found ) + if ( !result ) { - llinfos<<" Asset did not contain the joint (if you're u/l a fully rigged asset - it is required)." << *masterJointIt<< llendl; + llinfos<<" Asset did not contain the joint (if you're u/l a fully rigged asset w/joint positions - it is required)." << *masterJointIt<< llendl; break; } - } - - return found; + } + return result; } + //called in the main thread void LLModelLoader::loadTextures() { @@ -2013,6 +2159,9 @@ void LLModelLoader::loadTextures() } } +//----------------------------------------------------------------------------- +// isNodeAJoint() +//----------------------------------------------------------------------------- bool LLModelLoader::isNodeAJoint( domNode* pNode ) { if ( pNode->getName() == NULL) @@ -2027,7 +2176,9 @@ bool LLModelLoader::isNodeAJoint( domNode* pNode ) return false; } - +//----------------------------------------------------------------------------- +// isNodeAPivotPoint() +//----------------------------------------------------------------------------- bool LLModelLoader::isNodeAPivotPoint( domNode* pNode ) { bool result = false; @@ -2046,14 +2197,18 @@ bool LLModelLoader::isNodeAPivotPoint( domNode* pNode ) } return result; } - +//----------------------------------------------------------------------------- +// extractTranslation() +//----------------------------------------------------------------------------- void LLModelLoader::extractTranslation( domTranslate* pTranslate, LLMatrix4& transform ) { domFloat3 jointTrans = pTranslate->getValue(); LLVector3 singleJointTranslation( jointTrans[0], jointTrans[1], jointTrans[2] ); transform.setTranslation( singleJointTranslation ); } - +//----------------------------------------------------------------------------- +// extractTranslationViaElement() +//----------------------------------------------------------------------------- void LLModelLoader::extractTranslationViaElement( daeElement* pTranslateElement, LLMatrix4& transform ) { domTranslate* pTranslateChild = dynamic_cast( pTranslateElement ); @@ -2061,8 +2216,10 @@ void LLModelLoader::extractTranslationViaElement( daeElement* pTranslateElement, LLVector3 singleJointTranslation( translateChild[0], translateChild[1], translateChild[2] ); transform.setTranslation( singleJointTranslation ); } - -void LLModelLoader::processJointNode( domNode* pNode, std::map& jointTransforms ) +//----------------------------------------------------------------------------- +// processJointNode() +//----------------------------------------------------------------------------- +void LLModelLoader::processJointNode( domNode* pNode, JointTransformMap& jointTransforms ) { if (pNode->getName() == NULL) { @@ -2135,7 +2292,9 @@ void LLModelLoader::processJointNode( domNode* pNode, std::mapgetChild( name.c_str() ); @@ -2456,8 +2615,10 @@ LLColor4 LLModelLoader::getDaeColor(daeElement* element) LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) : LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE), LLMutex(NULL) , mPelvisZOffset( 0.0f ) -, mRigValid( false ) +, mLegacyRigValid( false ) +, mRigValidJointUpload( false ) , mResetJoints( false ) +, mLastJointUpdate( false ) { mNeedsUpdate = TRUE; mCameraDistance = 0.f; @@ -2491,6 +2652,40 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) mModelPivot = LLVector3( 0.0f, 0.0f, 0.0f ); glodInit(); + + //move into joint mapper class + //1. joints for joint offset verification + mMasterJointList.push_front("mPelvis"); + mMasterJointList.push_front("mTorso"); + mMasterJointList.push_front("mChest"); + mMasterJointList.push_front("mNeck"); + mMasterJointList.push_front("mHead"); + mMasterJointList.push_front("mCollarLeft"); + mMasterJointList.push_front("mShoulderLeft"); + mMasterJointList.push_front("mElbowLeft"); + mMasterJointList.push_front("mWristLeft"); + mMasterJointList.push_front("mCollarRight"); + mMasterJointList.push_front("mShoulderRight"); + mMasterJointList.push_front("mElbowRight"); + mMasterJointList.push_front("mWristRight"); + mMasterJointList.push_front("mHipRight"); + mMasterJointList.push_front("mKneeRight"); + mMasterJointList.push_front("mFootRight"); + mMasterJointList.push_front("mHipLeft"); + mMasterJointList.push_front("mKneeLeft"); + mMasterJointList.push_front("mFootLeft"); + //2. legacy joint list - used to verify rigs that will not be using joint offsets + mMasterLegacyJointList.push_front("mPelvis"); + mMasterLegacyJointList.push_front("mTorso"); + mMasterLegacyJointList.push_front("mChest"); + mMasterLegacyJointList.push_front("mNeck"); + mMasterLegacyJointList.push_front("mHead"); + mMasterLegacyJointList.push_front("mHipRight"); + mMasterLegacyJointList.push_front("mKneeRight"); + mMasterLegacyJointList.push_front("mFootRight"); + mMasterLegacyJointList.push_front("mHipLeft"); + mMasterLegacyJointList.push_front("mKneeLeft"); + mMasterLegacyJointList.push_front("mFootLeft"); } LLModelPreview::~LLModelPreview() @@ -2518,14 +2713,20 @@ U32 LLModelPreview::calcResourceCost() } } - //Upload skin is selected BUT the joints coming in from the asset - //were malformed. + //Upload skin is selected BUT check to see if the joints coming in from the asset were malformed. if ( mFMP && mFMP->childGetValue("upload_skin").asBoolean() ) { - if ( !isRigValid() ) + bool uploadingJointPositions = mFMP->childGetValue("upload_joints").asBoolean(); + if ( uploadingJointPositions && !isRigValidForJointPositionUpload() ) + { + mFMP->childDisable("ok_btn"); + } + else + if ( !isLegacyRigValid() ) { mFMP->childDisable("ok_btn"); } + //ok_btn should not have been changed unless something was wrong with joint list } U32 cost = 0; @@ -2858,7 +3059,7 @@ void LLModelPreview::loadModel(std::string filename, S32 lod) clearGLODGroup(); } - mModelLoader = new LLModelLoader(filename, lod, this); + mModelLoader = new LLModelLoader(filename, lod, this, mJointTransformMap, mJointsFromNode ); mModelLoader->start(); @@ -3694,12 +3895,22 @@ void LLModelPreview::updateStatusMessages() bool errorStateFromLoader = getLoadState() >= LLModelLoader::ERROR_PARSING ? true : false; bool skinAndRigOk = true; - bool uploadingSkin = mFMP->childGetValue("upload_skin").asBoolean(); - if ( uploadingSkin && !isRigValid() ) + bool uploadingSkin = mFMP->childGetValue("upload_skin").asBoolean(); + bool uploadingJointPositions = mFMP->childGetValue("upload_joints").asBoolean(); + + if ( uploadingSkin ) { - skinAndRigOk = false; + if ( uploadingJointPositions && !isRigValidForJointPositionUpload() ) + { + skinAndRigOk = false; + } + else + if ( !isLegacyRigValid() ) + { + skinAndRigOk = false; + } } - + if ( upload_ok && !errorStateFromLoader && skinAndRigOk ) { mFMP->childEnable("ok_btn"); @@ -4089,7 +4300,55 @@ void LLModelPreview::update() } } +//----------------------------------------------------------------------------- +// changeAvatarsJointPositions() +//----------------------------------------------------------------------------- +void LLModelPreview::changeAvatarsJointPositions( LLModel* pModel ) +{ + if ( mMasterJointList.empty() ) + { + return; + } + + std::vector :: const_iterator jointListItBegin = pModel->mSkinInfo.mJointNames.begin(); + std::vector :: const_iterator jointListItEnd = pModel->mSkinInfo.mJointNames.end(); + + S32 index = 0; + for ( ; jointListItBegin!=jointListItEnd; ++jointListItBegin, ++index ) + { + std::string elem = *jointListItBegin; + //llinfos<<"joint "<mSkinInfo.mAlternateBindMatrix.size(); + if ( matrixCnt < 1 ) + { + llinfos<<"Total WTF moment :"<mSkinInfo.mAlternateBindMatrix[index]; + LLJoint* pJoint = gAgentAvatarp->getJoint( elem ); + if ( pJoint ) + { + pJoint->storeCurrentXform( jointTransform.getTranslation() ); + } + } + } +} +//----------------------------------------------------------------------------- +// getTranslationForJointOffset() +//----------------------------------------------------------------------------- +LLVector3 LLModelPreview::getTranslationForJointOffset( std::string joint ) +{ + LLMatrix4 jointTransform; + if ( mJointTransformMap.find( joint ) != mJointTransformMap.end() ) + { + jointTransform = mJointTransformMap[joint]; + return jointTransform.getTranslation(); + } + return LLVector3(0.0f,0.0f,0.0f); +} //----------------------------------------------------------------------------- // render() //----------------------------------------------------------------------------- @@ -4140,9 +4399,21 @@ BOOL LLModelPreview::render() LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; bool has_skin_weights = false; - bool upload_skin = mFMP->childGetValue("upload_skin").asBoolean(); + bool upload_skin = mFMP->childGetValue("upload_skin").asBoolean(); bool upload_joints = mFMP->childGetValue("upload_joints").asBoolean(); + bool resetJoints = false; + if ( upload_joints != mLastJointUpdate ) + { + if ( mLastJointUpdate ) + { + resetJoints = true; + } + + mLastJointUpdate = upload_joints; + + } + for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) { for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) @@ -4187,11 +4458,30 @@ BOOL LLModelPreview::render() if (!upload_skin && upload_joints) { //can't upload joints if not uploading skin weights mFMP->childSetValue("upload_joints", false); - upload_joints = false; - } - + upload_joints = false; + } + mFMP->childSetEnabled("upload_joints", upload_skin); + //poke at avatar when we upload custom joints + /* + if ( upload_joints ) + { + for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) + { + for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) + { + LLModelInstance& instance = *model_iter; + LLModel* model = instance.mModel; + if ( !model->mSkinWeights.empty() ) + { + changeAvatarsJointPositions( model ); + } + } + } + } + */ + F32 explode = mFMP->childGetValue("physics_explode").asReal(); glClear(GL_DEPTH_BUFFER_BIT); @@ -4468,6 +4758,7 @@ BOOL LLModelPreview::render() //quick 'n dirty software vertex skinning //build matrix palette + LLMatrix4 mat[64]; for (U32 j = 0; j < model->mSkinInfo.mJointNames.size(); ++j) { -- cgit v1.2.3