diff options
Diffstat (limited to 'indra/newview/llfloaterimportcollada.cpp')
-rw-r--r-- | indra/newview/llfloaterimportcollada.cpp | 1116 |
1 files changed, 1116 insertions, 0 deletions
diff --git a/indra/newview/llfloaterimportcollada.cpp b/indra/newview/llfloaterimportcollada.cpp new file mode 100644 index 0000000000..476c02cd46 --- /dev/null +++ b/indra/newview/llfloaterimportcollada.cpp @@ -0,0 +1,1116 @@ +/** + * @file llfloaterimportcollada.cpp + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llfloaterimportcollada.h" + +#include "dae.h" +//#include "dom.h" +#include "dom/domAsset.h" +#include "dom/domBind_material.h" +#include "dom/domConstants.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 "llagent.h" +#include "llassetuploadresponders.h" +#include "lleconomy.h" +#include "llfloaterperms.h" +#include "llfloaterreg.h" +#include "llsdutil.h" +#include "llsdutil_math.h" +#include "llselectmgr.h" +#include "llvfile.h" +#include "llvfs.h" +#include "llviewermenufile.h" +#include "llviewerregion.h" +#include "llvolumemessage.h" +#include "llmodel.h" +#include "llmeshreduction.h" +#include "material_codes.h" + +// +// floater +// + +#if LL_MESH_ENABLED + +LLFloaterImportCollada::LLFloaterImportCollada(const LLSD& key) + : LLFloater(key) +{ +} + + +BOOL LLFloaterImportCollada::postBuild() +{ + if (!LLFloater::postBuild()) + { + return FALSE; + } + + childSetCommitCallback("ok", LLImportCollada::onCommitOK, this); + childSetCommitCallback("cancel", LLImportCollada::onCommitCancel, this); + + setStatusIdle(); + setAssetCount(0,0); + enableOK(TRUE); + + return TRUE; +} + + +void LLFloaterImportCollada::setAssetCount(S32 mesh_count, S32 texture_count) +{ + childSetTextArg("mesh count", "[COUNT]", llformat("%d", mesh_count)); + childSetTextArg("texture count", "[COUNT]", llformat("%d", texture_count)); +} + +void LLFloaterImportCollada::setStatusAssetUploading(std::string asset_name) +{ + LLUIString uploading = getString("status_uploading"); + uploading.setArg("[NAME]", asset_name); + childSetTextArg("status", "[STATUS]", uploading.getString()); +} + +void LLFloaterImportCollada::setStatusCreatingPrim(std::string prim_name) +{ + LLUIString creating = getString("status_creating"); + creating.setArg("[NAME]", prim_name); + childSetTextArg("status", "[STATUS]", creating.getString()); +} + +void LLFloaterImportCollada::setStatusIdle() +{ + childSetTextArg("status", "[STATUS]", getString("status_idle")); +} + +void LLFloaterImportCollada::enableOK(BOOL enable) +{ + childSetEnabled("ok", enable); +} + + +// +// misc helpers +// + + +// why oh why do forbid matrix multiplication in our llmath library? +LLMatrix4 matrix_multiply(LLMatrix4 a, LLMatrix4 b) +{ + a *= b; + + return a; +} + +// why oh why does colladadom not provide such things? +daeElement* getFirstChild(daeElement* parent) +{ + daeTArray< daeSmartRef<daeElement> > children = parent->getChildren(); + + if (children.getCount() > 0) + { + return children[0]; + } + else + { + return NULL; + } +} + +// why oh why does colladadom not provide such things? +daeElement* getNextSibling(daeElement* child) +{ + daeElement* parent = child->getParent(); + + if (parent == NULL) + { + // must be root, root has no siblings + return NULL; + } + + daeElement* sibling = NULL; + + daeTArray< daeSmartRef<daeElement> > children = parent->getChildren(); + for (S32 i = 0; i < children.getCount(); i++) + { + if (child == children[i]) + { + if ((i+1) < children.getCount()) + { + sibling = children[i+1]; + } + } + } + + return sibling; +} + +// try to get a decent label for this element +std::string 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 getDaeColor(daeElement* element) +{ + LLColor4 value; + domCommon_color_or_texture_type_complexType::domColor* color = + daeSafeCast<domCommon_color_or_texture_type_complexType::domColor>(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; +} + +LLTextureEntry profileToTextureEntry(domProfile_COMMON* material) +{ + LLTextureEntry te; + + te.setID(LLUUID("5748decc-f629-461c-9a36-a35a221fe21f")); // blank texture + daeElement* diffuse = material->getDescendant("diffuse"); + if (diffuse) + { + te.setColor(LLColor3(0.1f, 0.9f, 1.0f)); + + domCommon_color_or_texture_type_complexType::domTexture* texture = + daeSafeCast<domCommon_color_or_texture_type_complexType::domTexture>(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() > 0) + { + daeElement* image = init_from[0]->getValue().getElement(); + if (image) + { + LLUUID texture_asset = LLImportColladaAssetCache::getInstance()->getAssetForDaeElement(image); + + if (texture_asset.notNull()) + { + te.setID(texture_asset); + te.setColor(LLColor3(1,1,1)); + } + } + } + } + } + } + } + + domCommon_color_or_texture_type_complexType::domColor* color = + daeSafeCast<domCommon_color_or_texture_type_complexType::domColor>(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]); + te.setColor(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) + { + te.setFullbright(TRUE); + } + } + + return te; +} + +std::vector<LLTextureEntry> getMaterials(LLModel* model, domInstance_geometry* instance_geo) +{ + std::vector<LLTextureEntry> texture_entries; + for (int i = 0; i < model->mMaterialList.size(); i++) + { + LLTextureEntry texture_entry; + + domInstance_material* instance_mat = NULL; + + domBind_material::domTechnique_common* technique = + daeSafeCast<domBind_material::domTechnique_common>(instance_geo->getDescendant(daeElement::matchType(domBind_material::domTechnique_common::ID()))); + + if (technique) + { + daeTArray< daeSmartRef<domInstance_material> > inst_materials = technique->getChildrenByType<domInstance_material>(); + 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<domMaterial>(instance_mat->getTarget().getElement()); + if (material) + { + domInstance_effect* instance_effect = + daeSafeCast<domInstance_effect>(material->getDescendant(daeElement::matchType(domInstance_effect::ID()))); + if (instance_effect) + { + domEffect* effect = daeSafeCast<domEffect>(instance_effect->getUrl().getElement()); + if (effect) + { + domProfile_COMMON* profile = + daeSafeCast<domProfile_COMMON>(effect->getDescendant(daeElement::matchType(domProfile_COMMON::ID()))); + if (profile) + { + texture_entry = profileToTextureEntry(profile); + } + } + } + } + } + + texture_entries.push_back(texture_entry); + } + + return texture_entries; +} + +LLTextureEntry instanceGeoToTextureEntry(domInstance_geometry* instance_geo) +{ + LLTextureEntry te; + domInstance_material* instance_mat = + daeSafeCast<domInstance_material>(instance_geo->getDescendant(daeElement::matchType(domInstance_material::ID()))); + if (instance_mat) + { + } + + return te; +} + + + +// responder for asset uploads +// does all the normal stuff followed by a notification to continue importing +// WARNING - currently unused - TODO +class LLColladaNewAgentInventoryResponder : public LLNewAgentInventoryResponder +{ + LLColladaNewAgentInventoryResponder(const LLSD& post_data, + const LLUUID& vfile_id, + LLAssetType::EType asset_type) + : LLNewAgentInventoryResponder(post_data, vfile_id, asset_type) + { + } + LLColladaNewAgentInventoryResponder(const LLSD& post_data, + const std::string& file_name, + LLAssetType::EType asset_type) + : LLNewAgentInventoryResponder(post_data, file_name, asset_type) + { + } + + virtual void uploadComplete(const LLSD& content) + { + LLNewAgentInventoryResponder::uploadComplete(content); + } + +}; + +BOOL LLImportColladaAssetCache::uploadImageAsset(domImage* image) +{ + // we only support init_from now - embedded data will come later + domImage::domInit_from* init = image->getInit_from(); + if (!init) + { + return FALSE; + } + + std::string filename = cdom::uriToNativePath(init->getValue().str()); + + std::string name = getElementLabel(image); + + LLUUID transaction_id = upload_new_resource(filename, name, std::string(), + 0, LLFolderType::FT_TEXTURE, LLInventoryType::IT_TEXTURE, + LLFloaterPerms::getNextOwnerPerms(), LLFloaterPerms::getGroupPerms(), + LLFloaterPerms::getEveryonePerms(), + name, NULL, + LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(), NULL); + + if (transaction_id.isNull()) + { + llwarns << "cannot upload " << filename << llendl; + + return FALSE; + } + + mTransactionMap[transaction_id] = image; + + LLFloaterReg::findTypedInstance<LLFloaterImportCollada>("import_collada")->setStatusAssetUploading(name); + + return TRUE; +} + + + +// +// asset cache - +// uploads assets and provides a map from collada element to asset +// + + + +BOOL LLImportColladaAssetCache::uploadMeshAsset(domMesh* mesh) +{ + LLPointer<LLModel> model = LLModel::loadModelFromDomMesh(mesh); + + if (model->getNumVolumeFaces() == 0) + { + return FALSE; + } + + // generate LODs + + + std::vector<LLPointer<LLModel> > lods; + lods.push_back(model); + S32 triangle_count = model->getNumTriangles(); + + for (S32 i = 0; i < 4; i++) + { + LLPointer<LLModel> last_model = lods.back(); + + S32 triangle_target = (S32)(triangle_count / pow(3.f, i + 1)); + if (triangle_target > 16) + { + LLMeshReduction reduction; + LLPointer<LLModel> new_model = reduction.reduce(model, triangle_target, LLMeshReduction::TRIANGLE_BUDGET); + lods.push_back(new_model); + } + else + { + lods.push_back(last_model); + } + } + + // write model to temp file + + std::string filename = gDirUtilp->getTempFilename(); + LLModel::writeModel(filename, + lods[4], + lods[0], + lods[1], + lods[2], + lods[3], + lods[4]->mPhysicsShape); + + + // copy file to VFS + + LLTransactionID tid; + tid.generate(); + LLAssetID uuid = tid.makeAssetID(gAgent.getSecureSessionID()); // create asset uuid + + S32 file_size; + LLAPRFile infile ; + infile.open(filename, LL_APR_RB, NULL, &file_size); + + if (infile.getFileHandle()) + { + LLVFile file(gVFS, uuid, LLAssetType::AT_MESH, LLVFile::WRITE); + + file.setMaxSize(file_size); + + const S32 buf_size = 65536; + U8 copy_buf[buf_size]; + while ((file_size = infile.read(copy_buf, buf_size))) + { + file.write(copy_buf, file_size); + } + } + + + std::string name = getElementLabel(mesh); + + upload_new_resource(tid, LLAssetType::AT_MESH, name, std::string(), 0,LLFolderType::FT_MESH, LLInventoryType::IT_MESH, + LLFloaterPerms::getNextOwnerPerms(), LLFloaterPerms::getGroupPerms(), LLFloaterPerms::getEveryonePerms(), + name, NULL, + LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(), NULL); + + LLFile::remove(filename); + + mTransactionMap[uuid] = mesh; + + LLFloaterReg::findTypedInstance<LLFloaterImportCollada>("import_collada")->setStatusAssetUploading(name); + + return TRUE; +} + + +// called by the mesh asset upload responder to indicate the mesh asset has been uploaded +void LLImportColladaAssetCache::assetUploaded(LLUUID transaction_uuid, LLUUID asset_uuid, BOOL success) +{ + std::map<LLUUID, daeElement*>::iterator i = mTransactionMap.find(transaction_uuid); + + if (i != mTransactionMap.end()) + { + daeElement* element = i->second; + + + if (success) + { + mAssetMap[element] = asset_uuid; + } + else // failure + { + // if failed, put back on end of queue + mUploadsPending.push_back(element); + } + + mUploads--; + uploadNextAsset(); + } +} + +const S32 MAX_CONCURRENT_UPLOADS = 5; + +void LLImportColladaAssetCache::uploadNextAsset() +{ + while ((mUploadsPending.size() > 0) && (mUploads < MAX_CONCURRENT_UPLOADS)) + { + BOOL upload_started = FALSE; + + daeElement* element = mUploadsPending.back(); + mUploadsPending.pop_back(); + + domImage* image = daeSafeCast<domImage>(element); + if (image) + { + upload_started = uploadImageAsset(image); + } + + domMesh* mesh = daeSafeCast<domMesh>(element); + if (mesh) + { + upload_started = uploadMeshAsset(mesh); + } + + if (upload_started) + { + mUploads++; + } + + } + + if ((mUploadsPending.size() == 0) && (mUploads == 0)) + { + // we're done! notify the importer + LLImportCollada::getInstance()->assetsUploaded(); + } + + updateCount(); +} + + +void LLImportColladaAssetCache::clear() +{ + mDAE = NULL; + mTransactionMap.clear(); + mAssetMap.clear(); + mUploadsPending.clear(); + mUploads = 0; +} + +void LLImportColladaAssetCache::endImport() +{ + clear(); +} + +void LLImportColladaAssetCache::updateCount() +{ + S32 mesh_count = 0; + S32 image_count = 0; + + for (S32 i = 0; i < mUploadsPending.size(); i++) + { + daeElement* element = mUploadsPending[i]; + + if (daeSafeCast<domMesh>(element)) + { + mesh_count++; + } + + if (daeSafeCast<domImage>(element)) + { + image_count++; + } + } + + LLFloaterReg::findTypedInstance<LLFloaterImportCollada>("import_collada")->setAssetCount(mesh_count, image_count); +} + +void LLImportColladaAssetCache::prepareForUpload(DAE* dae) +{ + clear(); + mDAE = dae; + + daeDatabase* db = mDAE->getDatabase(); + + S32 mesh_count = db->getElementCount(NULL, COLLADA_TYPE_MESH); + for (S32 i = 0; i < mesh_count; i++) + { + domMesh* mesh = NULL; + + db->getElement((daeElement**) &mesh, i, NULL, COLLADA_TYPE_MESH); + + mUploadsPending.push_back(mesh); + } + + + S32 image_count = db->getElementCount(NULL, COLLADA_TYPE_IMAGE); + for (S32 i = 0; i < image_count; i++) + { + domImage* image = NULL; + db->getElement((daeElement**) &image, i, NULL, COLLADA_TYPE_IMAGE); + + mUploadsPending.push_back(image); + } + + updateCount(); +} + + +void LLImportColladaAssetCache::uploadAssets() +{ + uploadNextAsset(); +} + + +LLUUID LLImportColladaAssetCache::getAssetForDaeElement(daeElement* element) +{ + LLUUID id; + + std::map<daeElement*, LLUUID>::iterator i = mAssetMap.find(element); + if (i != mAssetMap.end()) + { + id = i->second; + } + + return id; +} + + +// +// importer +// + + + +LLImportCollada::LLImportCollada() +{ + mIsImporting = FALSE; +} + + + + +void LLImportCollada::appendObjectAsset(domInstance_geometry* instance_geo) +{ + domGeometry* geo = daeSafeCast<domGeometry>(instance_geo->getUrl().getElement()); + if (!geo) + { + llwarns << "cannot find geometry" << llendl; + return; + } + + domMesh* mesh = daeSafeCast<domMesh>(geo->getDescendant(daeElement::matchType(domMesh::ID()))); + if (!mesh) + { + llwarns << "could not find mesh" << llendl; + return; + } + + LLUUID mesh_asset = LLImportColladaAssetCache::getInstance()->getAssetForDaeElement(mesh); + if (mesh_asset.isNull()) + { + llwarns << "no mesh asset, skipping" << llendl; + return; + } + + // load the model + LLModel* model = LLModel::loadModelFromDomMesh(mesh); + + + + + // get our local transformation + LLMatrix4 transformation = mStack.front().transformation; + + // 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); + transformation = matrix_multiply(mesh_translation, transformation); + LLMatrix4 mesh_scale; + mesh_scale.initScale(mesh_scale_vector); + transformation = matrix_multiply(mesh_scale, transformation); + + // check for reflection + BOOL reflected = (transformation.determinant() < 0); + + // compute position + LLVector3 position = LLVector3(0, 0, 0) * transformation; + + // compute scale + 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); + + // adjust for "reflected" geometry + LLVector3 x_transformed_reflected = x_transformed; + if (reflected) + { + x_transformed_reflected *= -1.0; + } + + // compute rotation + LLMatrix3 rotation_matrix; + rotation_matrix.setRows(x_transformed_reflected, y_transformed, z_transformed); + LLQuaternion quat_rotation = rotation_matrix.quaternion(); + quat_rotation.normalize(); // the rotation_matrix might not have been orthoginal. make it so here. + LLVector3 euler_rotation; + quat_rotation.getEulerAngles(&euler_rotation.mV[VX], &euler_rotation.mV[VY], &euler_rotation.mV[VZ]); + + + // + // build parameter block to construct this prim + // + + LLSD object_params; + + // create prim + + // set volume params + LLVolumeParams volume_params; + volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE ); + volume_params.setBeginAndEndS( 0.f, 1.f ); + volume_params.setBeginAndEndT( 0.f, 1.f ); + volume_params.setRatio ( 1, 1 ); + volume_params.setShear ( 0, 0 ); + U8 sculpt_type = LL_SCULPT_TYPE_MESH; + if (reflected) + { + sculpt_type |= LL_SCULPT_FLAG_MIRROR; + } + volume_params.setSculptID(mesh_asset, sculpt_type); + object_params["shape"] = volume_params.asLLSD(); + + object_params["material"] = LL_MCODE_WOOD; + + object_params["group-id"] = gAgent.getGroupID(); + object_params["pos"] = ll_sd_from_vector3(position); + object_params["rotation"] = ll_sd_from_quaternion(quat_rotation); + object_params["scale"] = ll_sd_from_vector3(scale); + object_params["name"] = mStack.front().name; + + // load material from dae file + std::vector<LLTextureEntry> texture_entries = getMaterials(model, instance_geo); + object_params["facelist"] = LLSD::emptyArray(); + for (int i = 0; i < texture_entries.size(); i++) + { + object_params["facelist"][i] = texture_entries[i].asLLSD(); + } + + // set extra parameters + LLSculptParams sculpt_params; + sculpt_params.setSculptTexture(mesh_asset); + sculpt_params.setSculptType(sculpt_type); + U8 buffer[MAX_OBJECT_PARAMS_SIZE+1]; + LLDataPackerBinaryBuffer dp(buffer, MAX_OBJECT_PARAMS_SIZE); + sculpt_params.pack(dp); + std::vector<U8> v(dp.getCurrentSize()); + memcpy(&v[0], buffer, dp.getCurrentSize()); + LLSD extra_parameter; + extra_parameter["extra_parameter"] = sculpt_params.mType; + extra_parameter["param_data"] = v; + object_params["extra_parameters"].append(extra_parameter); + + mObjectList.append(object_params); + + delete model; + + LLFloaterReg::findTypedInstance<LLFloaterImportCollada>("import_collada")->setStatusCreatingPrim(mStack.front().name); + + return; +} + +void LLImportCollada::uploadObjectAsset() +{ + LLSD request; + request["objects"] = mObjectList; + + std::string url = gAgent.getRegion()->getCapability("UploadObjectAsset"); + LLHTTPClient::post(url, request, new LLHTTPClient::Responder()); +} + + + +void LLImportCollada::importFile(std::string filename) +{ + if (mIsImporting) + { + llwarns << "Importer already running, import command for " << filename << " ignored" << llendl; + return; + } + + LLFloaterReg::showInstance("import_collada"); + LLFloaterReg::findTypedInstance<LLFloaterImportCollada>("import_collada")->enableOK(TRUE); + + + mIsImporting = TRUE; + mDAE = new DAE; + mImportOrigin = gAgent.getPositionAgent() + LLVector3(0, 0, 2); + mSceneTransformation = LLMatrix4(); // identity + mFilename = filename; + mCreates = 0; + mObjectList = LLSD::emptyArray(); + + if (mDAE->open(mFilename) == NULL) + { + llwarns << "cannot open file " << mFilename << llendl; + endImport(); + return; + } + + LLImportColladaAssetCache::getInstance()->prepareForUpload(mDAE); + + return; +} + + +void LLImportCollada::assetsUploaded() +{ + if (!mIsImporting) + { + // weird, we got a callback while not importing. + return; + } + + daeDocument* doc = mDAE->getDoc(mFilename); + if (!doc) + { + llwarns << "can't find internal doc" << llendl; + endImport(); + } + + daeElement* root = doc->getDomRoot(); + if (!root) + { + llwarns << "document has no root" << llendl; + endImport(); + } + + domAsset::domUnit* unit = daeSafeCast<domAsset::domUnit>(root->getDescendant(daeElement::matchType(domAsset::domUnit::ID()))); + if (unit) + { + mSceneTransformation *= unit->getMeter(); + } + + domUpAxisType up = UPAXISTYPE_Y_UP; // default is Y_UP + domAsset::domUp_axis* up_axis = + daeSafeCast<domAsset::domUp_axis>(root->getDescendant(daeElement::matchType(domAsset::domUp_axis::ID()))); + if (up_axis) + { + up = up_axis->getValue(); + } + + if (up == UPAXISTYPE_X_UP) + { + LLMatrix4 rotation; + rotation.initRotation(0.0f, 90.0f * DEG_TO_RAD, 0.0f); + + mSceneTransformation = matrix_multiply(rotation, mSceneTransformation); + } + else if (up == UPAXISTYPE_Y_UP) + { + LLMatrix4 rotation; + rotation.initRotation(90.0f * DEG_TO_RAD, 0.0f, 0.0f); + + mSceneTransformation = matrix_multiply(rotation, mSceneTransformation); + } + // else Z_UP, which is our behavior + + + + daeElement* scene = root->getDescendant("visual_scene"); + if (!scene) + { + llwarns << "document has no visual_scene" << llendl; + endImport(); + } + + processElement(scene); + processNextElement(); +} + +void LLImportCollada::pushStack(daeElement* next_element, std::string name, LLMatrix4 transformation) +{ + struct StackState new_state; + + new_state.next_element = next_element; + new_state.name = name; + new_state.transformation = transformation; + + mStack.push_front(new_state); +} + + + +void LLImportCollada::popStack() +{ + mStack.pop_front(); +} + + + +BOOL LLImportCollada::processElement(daeElement* element) +{ + if (mStack.size() > 0) + { + mStack.front().next_element = getNextSibling(element); + } + + domTranslate* translate = daeSafeCast<domTranslate>(element); + if (translate) + { + domFloat3 dom_value = translate->getValue(); + + LLMatrix4 translation; + translation.setTranslation(LLVector3(dom_value[0], dom_value[1], dom_value[2])); + + mStack.front().transformation = matrix_multiply(translation, mStack.front().transformation); + } + + domRotate* rotate = daeSafeCast<domRotate>(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)); + + mStack.front().transformation = matrix_multiply(rotation, mStack.front().transformation); + } + + domScale* scale = daeSafeCast<domScale>(element); + if (scale) + { + domFloat3 dom_value = scale->getValue(); + + LLMatrix4 scaling; + scaling.initScale(LLVector3(dom_value[0], dom_value[1], dom_value[2])); + + mStack.front().transformation = matrix_multiply(scaling, mStack.front().transformation); + } + + domMatrix* matrix = daeSafeCast<domMatrix>(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]; + } + + mStack.front().transformation = matrix_multiply(matrix_transform, mStack.front().transformation); + } + + domInstance_geometry* instance_geo = daeSafeCast<domInstance_geometry>(element); + if (instance_geo) + { + appendObjectAsset(instance_geo); + } + + domNode* node = daeSafeCast<domNode>(element); + if (node) + { + pushStack(getFirstChild(element), getElementLabel(element), mStack.front().transformation); + } + + domInstance_node* instance_node = daeSafeCast<domInstance_node>(element); + if (instance_node) + { + daeElement* instance = instance_node->getUrl().getElement(); + if (instance) + { + pushStack(getFirstChild(instance), getElementLabel(instance), mStack.front().transformation); + } + } + + domVisual_scene* scene = daeSafeCast<domVisual_scene>(element); + if (scene) + { + pushStack(getFirstChild(element), std::string("scene"), mSceneTransformation); + } + + return FALSE; +} + + +void LLImportCollada::processNextElement() +{ + while(1) + { + if (mStack.size() == 0) + { + uploadObjectAsset(); + endImport(); + return; + } + + daeElement *element = mStack.front().next_element; + + if (element == NULL) + { + popStack(); + } + else + { + processElement(element); + } + } +} + + +void LLImportCollada::endImport() +{ + LLFloaterReg::hideInstance("import_collada"); + + LLImportColladaAssetCache::getInstance()->endImport(); + + if (mDAE) + { + delete mDAE; + mDAE = NULL; + } + + mIsImporting = FALSE; +} + + +/* static */ +void LLImportCollada::onCommitOK(LLUICtrl*, void*) +{ + LLFloaterReg::findTypedInstance<LLFloaterImportCollada>("import_collada")->enableOK(FALSE); + + LLImportColladaAssetCache::getInstance()->uploadAssets(); +} + + +/* static */ +void LLImportCollada::onCommitCancel(LLUICtrl*, void*) +{ + getInstance()->endImport(); +} + +#endif |