diff options
Diffstat (limited to 'indra/newview/gltfscenemanager.cpp')
-rw-r--r-- | indra/newview/gltfscenemanager.cpp | 824 |
1 files changed, 707 insertions, 117 deletions
diff --git a/indra/newview/gltfscenemanager.cpp b/indra/newview/gltfscenemanager.cpp index 7003eab6d0..7b2de4d6de 100644 --- a/indra/newview/gltfscenemanager.cpp +++ b/indra/newview/gltfscenemanager.cpp @@ -39,7 +39,14 @@ #include "gltf/asset.h" #include "pipeline.h" #include "llviewershadermgr.h" +#include "llviewertexturelist.h" +#include "llimagej2c.h" +#include "llfloaterperms.h" +#include "llagentbenefits.h" +#include "llfilesystem.h" +#include "boost/json.hpp" +#define GLTF_SIM_SUPPORT 1 using namespace LL; @@ -66,38 +73,253 @@ void GLTFSceneManager::load() } }, LLFilePicker::FFLOAD_GLTF, - true); + false); } else { - LLNotificationsUtil::add("GLTFPreviewSelection"); + LLNotificationsUtil::add("GLTFOpenSelection"); } } -void GLTFSceneManager::load(const std::string& filename) +void GLTFSceneManager::saveAs() { - tinygltf::Model model; - LLTinyGLTFHelper::loadModel(filename, model); - - LLPointer<Asset> asset = new Asset(); - *asset = model; + LLViewerObject* obj = LLSelectMgr::instance().getSelection()->getFirstRootObject(); + if (obj && obj->mGLTFAsset) + { + LLFilePickerReplyThread::startPicker( + [](const std::vector<std::string>& filenames, LLFilePicker::ELoadFilter load_filter, LLFilePicker::ESaveFilter save_filter) + { + if (LLAppViewer::instance()->quitRequested()) + { + return; + } + if (filenames.size() > 0) + { + GLTFSceneManager::instance().save(filenames[0]); + } + }, + LLFilePicker::FFSAVE_GLTF, + "scene.gltf"); + } + else + { + LLNotificationsUtil::add("GLTFSaveSelection"); + } +} - gDebugProgram.bind(); // bind a shader to satisfy LLVertexBuffer assertions - asset->allocateGLResources(filename, model); - asset->updateTransforms(); +void GLTFSceneManager::uploadSelection() +{ + if (mUploadingAsset) + { // upload already in progress + LLNotificationsUtil::add("GLTFUploadInProgress"); + return; + } - // hang the asset off the currently selected object, or off of the avatar if no object is selected LLViewerObject* obj = LLSelectMgr::instance().getSelection()->getFirstRootObject(); + if (obj && obj->mGLTFAsset) + { + // make a copy of the asset prior to uploading + mUploadingAsset = std::make_shared<Asset>(); + mUploadingObject = obj; + *mUploadingAsset = *obj->mGLTFAsset; - if (obj) - { // assign to self avatar - obj->mGLTFAsset = asset; + GLTF::Asset& asset = *mUploadingAsset; + + for (auto& image : asset.mImages) + { + if (image.mTexture.notNull()) + { + mPendingImageUploads++; + + LLPointer<LLImageRaw> raw; + + if (image.mBufferView != INVALID_INDEX) + { + BufferView& view = asset.mBufferViews[image.mBufferView]; + Buffer& buffer = asset.mBuffers[view.mBuffer]; + + raw = LLViewerTextureManager::getRawImageFromMemory(buffer.mData.data() + view.mByteOffset, view.mByteLength, image.mMimeType); + + image.clearData(asset); + } + else + { + raw = image.mTexture->getCachedRawImage(); + } + + if (raw.notNull()) + { + LLPointer<LLImageJ2C> j2c = LLViewerTextureList::convertToUploadFile(raw); + + std::string buffer; + buffer.assign((const char*)j2c->getData(), j2c->getDataSize()); + + LLUUID asset_id = LLUUID::generateNewID(); + + std::string name; + S32 idx = (S32)(&image - &asset.mImages[0]); + + if (image.mName.empty()) + { + + name = llformat("Image_%d", idx); + } + else + { + name = image.mName; + } - if (std::find(mObjects.begin(), mObjects.end(), obj) == mObjects.end()) + LLNewBufferedResourceUploadInfo::uploadFailure_f failure = [this](LLUUID assetId, LLSD response, std::string reason) + { + // TODO: handle failure + mPendingImageUploads--; + return false; + }; + + + LLNewBufferedResourceUploadInfo::uploadFinish_f finish = [this, idx, raw, j2c](LLUUID assetId, LLSD response) + { + if (mUploadingAsset && mUploadingAsset->mImages.size() > idx) + { + mUploadingAsset->mImages[idx].mUri = assetId.asString(); + mPendingImageUploads--; + } + }; + + S32 expected_upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(j2c); + + LLResourceUploadInfo::ptr_t uploadInfo(std::make_shared<LLNewBufferedResourceUploadInfo>( + buffer, + asset_id, + name, + name, + 0, + LLFolderType::FT_TEXTURE, + LLInventoryType::IT_TEXTURE, + LLAssetType::AT_TEXTURE, + LLFloaterPerms::getNextOwnerPerms("Uploads"), + LLFloaterPerms::getGroupPerms("Uploads"), + LLFloaterPerms::getEveryonePerms("Uploads"), + expected_upload_cost, + false, + finish, + failure)); + + upload_new_resource(uploadInfo); + } + } + } + + // upload .bin + for (auto& bin : asset.mBuffers) { - mObjects.push_back(obj); + mPendingBinaryUploads++; + + S32 idx = (S32)(&bin - &asset.mBuffers[0]); + + std::string buffer; + buffer.assign((const char*)bin.mData.data(), bin.mData.size()); + + LLUUID asset_id = LLUUID::generateNewID(); + + LLNewBufferedResourceUploadInfo::uploadFailure_f failure = [this](LLUUID assetId, LLSD response, std::string reason) + { + // TODO: handle failure + mPendingBinaryUploads--; + mUploadingAsset = nullptr; + mUploadingObject = nullptr; + LL_WARNS("GLTF") << "Failed to upload GLTF binary: " << reason << LL_ENDL; + LL_WARNS("GLTF") << response << LL_ENDL; + return false; + }; + + LLNewBufferedResourceUploadInfo::uploadFinish_f finish = [this, idx](LLUUID assetId, LLSD response) + { + if (mUploadingAsset && mUploadingAsset->mBuffers.size() > idx) + { + mUploadingAsset->mBuffers[idx].mUri = assetId.asString(); + mPendingBinaryUploads--; + + // HACK: save buffer to cache to emulate a successful download + LLFileSystem cache(assetId, LLAssetType::AT_GLTF_BIN, LLFileSystem::WRITE); + auto& data = mUploadingAsset->mBuffers[idx].mData; + + llassert(data.size() <= size_t(S32_MAX)); + cache.write((const U8 *) data.data(), S32(data.size())); + } + }; +#if GLTF_SIM_SUPPORT + S32 expected_upload_cost = 1; + + LLResourceUploadInfo::ptr_t uploadInfo(std::make_shared<LLNewBufferedResourceUploadInfo>( + buffer, + asset_id, + "", + "", + 0, + LLFolderType::FT_NONE, + LLInventoryType::IT_GLTF_BIN, + LLAssetType::AT_GLTF_BIN, + LLFloaterPerms::getNextOwnerPerms("Uploads"), + LLFloaterPerms::getGroupPerms("Uploads"), + LLFloaterPerms::getEveryonePerms("Uploads"), + expected_upload_cost, + false, + finish, + failure)); + + upload_new_resource(uploadInfo); +#else + // dummy finish + finish(LLUUID::generateNewID(), LLSD()); +#endif + } + } + else + { + LLNotificationsUtil::add("GLTFUploadSelection"); + } +} + +void GLTFSceneManager::save(const std::string& filename) +{ + LLViewerObject* obj = LLSelectMgr::instance().getSelection()->getFirstRootObject(); + if (obj && obj->mGLTFAsset) + { + Asset* asset = obj->mGLTFAsset.get(); + if (!asset->save(filename)) + { + LLNotificationsUtil::add("GLTFSaveFailed"); + } + } +} + +void GLTFSceneManager::load(const std::string& filename) +{ + std::shared_ptr<Asset> asset = std::make_shared<Asset>(); + + if (asset->load(filename)) + { + gDebugProgram.bind(); // bind a shader to satisfy LLVertexBuffer assertions + asset->updateTransforms(); + + // hang the asset off the currently selected object, or off of the avatar if no object is selected + LLViewerObject* obj = LLSelectMgr::instance().getSelection()->getFirstRootObject(); + + if (obj) + { // assign to self avatar + obj->mGLTFAsset = asset; + obj->markForUpdate(); + if (std::find(mObjects.begin(), mObjects.end(), obj) == mObjects.end()) + { + mObjects.push_back(obj); + } } } + else + { + LLNotificationsUtil::add("GLTFLoadFailed"); + } } GLTFSceneManager::~GLTFSceneManager() @@ -115,8 +337,108 @@ void GLTFSceneManager::renderAlpha() render(false); } +void GLTFSceneManager::addGLTFObject(LLViewerObject* obj, LLUUID gltf_id) +{ + llassert(obj->getVolume()->getParams().getSculptID() == gltf_id); + llassert(obj->getVolume()->getParams().getSculptType() == LL_SCULPT_TYPE_GLTF); + + obj->ref(); + gAssetStorage->getAssetData(gltf_id, LLAssetType::AT_GLTF, onGLTFLoadComplete, obj); +} + +//static +void GLTFSceneManager::onGLTFBinLoadComplete(const LLUUID& id, LLAssetType::EType asset_type, void* user_data, S32 status, LLExtStat ext_status) +{ + LLViewerObject* obj = (LLViewerObject*)user_data; + llassert(asset_type == LLAssetType::AT_GLTF_BIN); + + if (status == LL_ERR_NOERR) + { + if (obj) + { + // find the Buffer with the given id in the asset + if (obj->mGLTFAsset) + { + obj->mGLTFAsset->mPendingBuffers--; + + + if (obj->mGLTFAsset->mPendingBuffers == 0) + { + if (obj->mGLTFAsset->prep()) + { + GLTFSceneManager& mgr = GLTFSceneManager::instance(); + if (std::find(mgr.mObjects.begin(), mgr.mObjects.end(), obj) == mgr.mObjects.end()) + { + GLTFSceneManager::instance().mObjects.push_back(obj); + } + } + else + { + LL_WARNS("GLTF") << "Failed to prepare GLTF asset: " << id << LL_ENDL; + obj->mGLTFAsset = nullptr; + } + } + } + } + } + else + { + LL_WARNS("GLTF") << "Failed to load GLTF asset: " << id << LL_ENDL; + obj->unref(); + } +} + +//static +void GLTFSceneManager::onGLTFLoadComplete(const LLUUID& id, LLAssetType::EType asset_type, void* user_data, S32 status, LLExtStat ext_status) +{ + LLViewerObject* obj = (LLViewerObject*)user_data; + llassert(asset_type == LLAssetType::AT_GLTF); + + if (status == LL_ERR_NOERR) + { + if (obj) + { + LLFileSystem file(id, asset_type, LLFileSystem::READ); + std::string data; + S32 file_size = file.getSize(); + data.resize(file_size); + file.read((U8*)data.data(), file_size); + + boost::json::value json = boost::json::parse(data); + + std::shared_ptr<Asset> asset = std::make_shared<Asset>(json); + obj->mGLTFAsset = asset; + + for (auto& buffer : asset->mBuffers) + { + // for now just assume the buffer is already in the asset cache + LLUUID buffer_id; + if (LLUUID::parseUUID(buffer.mUri, &buffer_id)) + { + asset->mPendingBuffers++; + + gAssetStorage->getAssetData(buffer_id, LLAssetType::AT_GLTF_BIN, onGLTFBinLoadComplete, obj); + } + else + { + LL_WARNS("GLTF") << "Buffer URI is not a valid UUID: " << buffer.mUri << LL_ENDL; + obj->unref(); + return; + } + } + } + } + else + { + LL_WARNS("GLTF") << "Failed to load GLTF asset: " << id << LL_ENDL; + obj->unref(); + } +} + void GLTFSceneManager::update() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_GLTF; + for (U32 i = 0; i < mObjects.size(); ++i) { if (mObjects[i]->isDead() || mObjects[i]->mGLTFAsset == nullptr) @@ -126,21 +448,125 @@ void GLTFSceneManager::update() continue; } - Asset* asset = mObjects[i]->mGLTFAsset; + mObjects[i]->mGLTFAsset->update(); + } + + // process pending uploads + if (mUploadingAsset && !mGLTFUploadPending) + { + if (mPendingImageUploads == 0 && mPendingBinaryUploads == 0) + { + boost::json::object obj; + mUploadingAsset->serialize(obj); + std::string buffer = boost::json::serialize(obj, {}); + + LLNewBufferedResourceUploadInfo::uploadFailure_f failure = [this](LLUUID assetId, LLSD response, std::string reason) + { + // TODO: handle failure + LL_WARNS("GLTF") << "Failed to upload GLTF json: " << reason << LL_ENDL; + LL_WARNS("GLTF") << response << LL_ENDL; - asset->update(); + mUploadingAsset = nullptr; + mUploadingObject = nullptr; + mGLTFUploadPending = false; + return false; + }; + + LLNewBufferedResourceUploadInfo::uploadFinish_f finish = [this, buffer](LLUUID assetId, LLSD response) + { + LLAppViewer::instance()->postToMainCoro( + [=]() + { + if (mUploadingAsset) + { + // HACK: save buffer to cache to emulate a successful upload + LLFileSystem cache(assetId, LLAssetType::AT_GLTF, LLFileSystem::WRITE); + + LL_INFOS("GLTF") << "Uploaded GLTF json: " << assetId << LL_ENDL; + llassert(buffer.size() <= size_t(S32_MAX)); + cache.write((const U8 *) buffer.c_str(), S32(buffer.size())); + + mUploadingAsset = nullptr; + } + + if (mUploadingObject) + { + mUploadingObject->mGLTFAsset = nullptr; + mUploadingObject->setGLTFAsset(assetId); + mUploadingObject->markForUpdate(); + mUploadingObject = nullptr; + } + + mGLTFUploadPending = false; + }); + }; + +#if GLTF_SIM_SUPPORT + S32 expected_upload_cost = 1; + LLUUID asset_id = LLUUID::generateNewID(); + + mGLTFUploadPending = true; + + LLResourceUploadInfo::ptr_t uploadInfo(std::make_shared<LLNewBufferedResourceUploadInfo>( + buffer, + asset_id, + "", + "", + 0, + LLFolderType::FT_NONE, + LLInventoryType::IT_GLTF, + LLAssetType::AT_GLTF, + LLFloaterPerms::getNextOwnerPerms("Uploads"), + LLFloaterPerms::getGroupPerms("Uploads"), + LLFloaterPerms::getEveryonePerms("Uploads"), + expected_upload_cost, + false, + finish, + failure)); + + upload_new_resource(uploadInfo); +#else + // dummy finish + finish(LLUUID::generateNewID(), LLSD()); +#endif + } + } +} +void GLTFSceneManager::render(bool opaque, bool rigged, bool unlit) +{ + U8 variant = 0; + if (rigged) + { + variant |= LLGLSLShader::GLTFVariant::RIGGED; + } + if (!opaque) + { + variant |= LLGLSLShader::GLTFVariant::ALPHA_BLEND; } + if (unlit) + { + variant |= LLGLSLShader::GLTFVariant::UNLIT; + } + + render(variant); } -void GLTFSceneManager::render(bool opaque, bool rigged) +void GLTFSceneManager::render(U8 variant) { - // for debugging, just render the whole scene as opaque - // by traversing the whole scenegraph - // Assumes camera transform is already set and - // appropriate shader is already bound + LL_PROFILE_ZONE_SCOPED_CATEGORY_GLTF; + // just render the whole scene by traversing the whole scenegraph + // Assumes camera transform is already set and appropriate shader is already bound. + // Eventually we'll want a smarter render pipe that has pre-sorted the scene graph + // into buckets by material and shader. + + // HACK -- implicitly render multi-uv variant + if (!(variant & LLGLSLShader::GLTFVariant::MULTI_UV)) + { + render((U8) (variant | LLGLSLShader::GLTFVariant::MULTI_UV)); + } - gGL.matrixMode(LLRender::MM_MODELVIEW); + bool rigged = variant & LLGLSLShader::GLTFVariant::RIGGED; for (U32 i = 0; i < mObjects.size(); ++i) { @@ -151,24 +577,205 @@ void GLTFSceneManager::render(bool opaque, bool rigged) continue; } - Asset* asset = mObjects[i]->mGLTFAsset; - + Asset* asset = mObjects[i]->mGLTFAsset.get(); gGL.pushMatrix(); LLMatrix4a mat = mObjects[i]->getGLTFAssetToAgentTransform(); - LLMatrix4a modelview; - modelview.loadu(gGLModelView); - - matMul(mat, modelview, modelview); + // provide a modelview matrix that goes from asset to camera space + // (matrix palettes are in asset space) + gGL.loadMatrix(gGLModelView); + gGL.multMatrix(mat.getF32ptr()); - asset->updateRenderTransforms(modelview); - asset->render(opaque, rigged); + render(*asset, variant); gGL.popMatrix(); } } +void GLTFSceneManager::render(Asset& asset, U8 variant) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_GLTF; + + for (U32 ds = 0; ds < 2; ++ds) + { + RenderData& rd = asset.mRenderData[ds]; + auto& batches = rd.mBatches[variant]; + + if (batches.empty()) + { + return; + } + + LLGLDisable cull_face(ds == 1 ? GL_CULL_FACE : 0); + + bool opaque = !(variant & LLGLSLShader::GLTFVariant::ALPHA_BLEND); + bool rigged = variant & LLGLSLShader::GLTFVariant::RIGGED; + + bool shader_bound = false; + + for (U32 i = 0; i < batches.size(); ++i) + { + if (batches[i].mPrimitives.empty() || batches[i].mVertexBuffer.isNull()) + { + continue; + } + + if (!shader_bound) + { // don't bind the shader until we know we have somthing to render + if (opaque) + { + gGLTFPBRMetallicRoughnessProgram.bind(variant); + } + else + { // alpha shaders need all the shadow map setup etc + gPipeline.bindDeferredShader(gGLTFPBRMetallicRoughnessProgram.mGLTFVariants[variant]); + } + + if (!rigged) + { + glBindBufferBase(GL_UNIFORM_BUFFER, LLGLSLShader::UB_GLTF_NODES, asset.mNodesUBO); + } + + glBindBufferBase(GL_UNIFORM_BUFFER, LLGLSLShader::UB_GLTF_MATERIALS, asset.mMaterialsUBO); + + for (U32 i = 0; i < TEXTURE_TYPE_COUNT; ++i) + { + mLastTexture[i] = -2; + } + + gGL.syncMatrices(); + shader_bound = true; + } + + { + LL_PROFILE_ZONE_NAMED_CATEGORY_GLTF("gltfdc - set vb"); + batches[i].mVertexBuffer->setBuffer(); + } + + S32 mat_idx = i - 1; + if (mat_idx != INVALID_INDEX) + { + Material& material = asset.mMaterials[mat_idx]; + bind(asset, material); + } + else + { + LLFetchedGLTFMaterial::sDefault.bind(); + LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::GLTF_MATERIAL_ID, -1); + } + + for (auto& pdata : batches[i].mPrimitives) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_GLTF("GLTF draw call"); + Node& node = asset.mNodes[pdata.mNodeIndex]; + Mesh& mesh = asset.mMeshes[node.mMesh]; + Primitive& primitive = mesh.mPrimitives[pdata.mPrimitiveIndex]; + + if (rigged) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_GLTF("gltfdc - bind skin"); + llassert(node.mSkin != INVALID_INDEX); + Skin& skin = asset.mSkins[node.mSkin]; + glBindBufferBase(GL_UNIFORM_BUFFER, LLGLSLShader::UB_GLTF_JOINTS, skin.mUBO); + } + else + { + LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::GLTF_NODE_ID, pdata.mNodeIndex); + } + + { + LL_PROFILE_ZONE_NAMED_CATEGORY_GLTF("gltfdc - push vb"); + + primitive.mVertexBuffer->drawRangeFast(primitive.mGLMode, primitive.mVertexOffset, primitive.mVertexOffset + primitive.getVertexCount() - 1, primitive.getIndexCount(), primitive.mIndexOffset); + } + } + } + } +} + +void GLTFSceneManager::bindTexture(Asset& asset, TextureType texture_type, TextureInfo& info, LLViewerTexture* fallback) +{ + U8 type_idx = (U8)texture_type; + + if (info.mIndex == mLastTexture[type_idx]) + { //already bound + return; + } + + S32 uniform[] = + { + LLShaderMgr::DIFFUSE_MAP, + LLShaderMgr::NORMAL_MAP, + LLShaderMgr::METALLIC_ROUGHNESS_MAP, + LLShaderMgr::OCCLUSION_MAP, + LLShaderMgr::EMISSIVE_MAP + }; + + S32 channel = LLGLSLShader::sCurBoundShaderPtr->getTextureChannel(uniform[(U8)type_idx]); + + if (channel > -1) + { + glActiveTexture(GL_TEXTURE0 + channel); + + if (info.mIndex != INVALID_INDEX) + { + Texture& texture = asset.mTextures[info.mIndex]; + + LLViewerTexture* tex = asset.mImages[texture.mSource].mTexture; + if (tex) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_GLTF("gl bind texture"); + glBindTexture(GL_TEXTURE_2D, tex->getTexName()); + + if (channel != -1 && texture.mSampler != -1) + { // set sampler state + Sampler& sampler = asset.mSamplers[texture.mSampler]; + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, sampler.mWrapS); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, sampler.mWrapT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, sampler.mMagFilter); + + // NOTE: do not set min filter. Always respect client preference for min filter + } + else + { + // set default sampler state + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } + } + else + { + glBindTexture(GL_TEXTURE_2D, fallback->getTexName()); + } + } + else + { + glBindTexture(GL_TEXTURE_2D, fallback->getTexName()); + } + } +} + + +void GLTFSceneManager::bind(Asset& asset, Material& material) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_GLTF; + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + + bindTexture(asset, TextureType::BASE_COLOR, material.mPbrMetallicRoughness.mBaseColorTexture, LLViewerFetchedTexture::sWhiteImagep); + + if (!LLPipeline::sShadowRender) + { + bindTexture(asset, TextureType::NORMAL, material.mNormalTexture, LLViewerFetchedTexture::sFlatNormalImagep); + bindTexture(asset, TextureType::METALLIC_ROUGHNESS, material.mPbrMetallicRoughness.mMetallicRoughnessTexture, LLViewerFetchedTexture::sWhiteImagep); + bindTexture(asset, TextureType::OCCLUSION, material.mOcclusionTexture, LLViewerFetchedTexture::sWhiteImagep); + bindTexture(asset, TextureType::EMISSIVE, material.mEmissiveTexture, LLViewerFetchedTexture::sWhiteImagep); + } + + shader->uniform1i(LLShaderMgr::GLTF_MATERIAL_ID, &material - &asset.mMaterials[0]); +} + LLMatrix4a inverse(const LLMatrix4a& mat) { glh::matrix4f m((F32*)mat.mMatrix); @@ -178,7 +785,7 @@ LLMatrix4a inverse(const LLMatrix4a& mat) return ret; } -bool GLTFSceneManager::lineSegmentIntersect(LLVOVolume* obj, Asset* asset, const LLVector4a& start, const LLVector4a& end, S32 face, BOOL pick_transparent, BOOL pick_rigged, BOOL pick_unselectable, S32* node_hit, S32* primitive_hit, +bool GLTFSceneManager::lineSegmentIntersect(LLVOVolume* obj, Asset* asset, const LLVector4a& start, const LLVector4a& end, S32 face, bool pick_transparent, bool pick_rigged, bool pick_unselectable, S32* node_hit, S32* primitive_hit, LLVector4a* intersection, LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent) { @@ -272,10 +879,10 @@ bool GLTFSceneManager::lineSegmentIntersect(LLVOVolume* obj, Asset* asset, const } LLDrawable* GLTFSceneManager::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, - BOOL pick_transparent, - BOOL pick_rigged, - BOOL pick_unselectable, - BOOL pick_reflection_probe, + bool pick_transparent, + bool pick_rigged, + bool pick_unselectable, + bool pick_reflection_probe, S32* node_hit, // return the index of the node that was hit S32* primitive_hit, // return the index of the primitive that was hit LLVector4a* intersection, // return the intersection point @@ -298,7 +905,7 @@ LLDrawable* GLTFSceneManager::lineSegmentIntersect(const LLVector4a& start, cons } // temporary debug -- always double check objects that have GLTF scenes hanging off of them even if the ray doesn't intersect the object bounds - if (lineSegmentIntersect((LLVOVolume*) mObjects[i].get(), mObjects[i]->mGLTFAsset, start, local_end, -1, pick_transparent, pick_rigged, pick_unselectable, node_hit, primitive_hit, &position, tex_coord, normal, tangent)) + if (lineSegmentIntersect((LLVOVolume*) mObjects[i].get(), mObjects[i]->mGLTFAsset.get(), start, local_end, -1, pick_transparent, pick_rigged, pick_unselectable, node_hit, primitive_hit, &position, tex_coord, normal, tangent)) { local_end = position; if (intersection) @@ -326,16 +933,21 @@ void renderAssetDebug(LLViewerObject* obj, Asset* asset) // assumes modelview matrix is already set gGL.pushMatrix(); - // get raycast in asset space LLMatrix4a agent_to_asset = obj->getAgentToGLTFAssetTransform(); - LLVector4a start; - LLVector4a end; + gGL.multMatrix(agent_to_asset.getF32ptr()); + + vec4 start; + vec4 end; - agent_to_asset.affineTransform(gDebugRaycastStart, start); - agent_to_asset.affineTransform(gDebugRaycastEnd, end); + LLVector4a t; + agent_to_asset.affineTransform(gDebugRaycastStart, t); + start = glm::make_vec4(t.getF32ptr()); + agent_to_asset.affineTransform(gDebugRaycastEnd, t); + end = glm::make_vec4(t.getF32ptr()); + start.w = end.w = 1.0; for (auto& node : asset->mNodes) { @@ -343,7 +955,8 @@ void renderAssetDebug(LLViewerObject* obj, Asset* asset) if (node.mMesh != INVALID_INDEX) { - gGL.loadMatrix((F32*)node.mRenderMatrix.mMatrix); + gGL.pushMatrix(); + gGL.multMatrix((F32*)glm::value_ptr(node.mAssetMatrix)); // draw bounding box of mesh primitives if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BBOXES)) @@ -361,24 +974,24 @@ void renderAssetDebug(LLViewerObject* obj, Asset* asset) } } -#if 0 +#if 1 if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST)) { gGL.flush(); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // convert raycast to node local space - LLVector4a local_start; - LLVector4a local_end; - - node.mAssetMatrixInv.affineTransform(start, local_start); - node.mAssetMatrixInv.affineTransform(end, local_end); + vec4 local_start = node.mAssetMatrixInv * start; + vec4 local_end = node.mAssetMatrixInv * end; for (auto& primitive : mesh.mPrimitives) { if (primitive.mOctree.notNull()) { - renderOctreeRaycast(local_start, local_end, primitive.mOctree); + LLVector4a s, e; + s.load3(glm::value_ptr(local_start)); + e.load3(glm::value_ptr(local_end)); + renderOctreeRaycast(s, e, primitive.mOctree); } } @@ -386,6 +999,7 @@ void renderAssetDebug(LLViewerObject* obj, Asset* asset) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } #endif + gGL.popMatrix(); } } @@ -404,35 +1018,15 @@ void GLTFSceneManager::renderDebug() gDebugProgram.bind(); + gGL.pushMatrix(); + gGL.loadMatrix(gGLModelView); + LLGLDisable cullface(GL_CULL_FACE); LLGLEnable blend(GL_BLEND); gGL.setSceneBlendType(LLRender::BT_ALPHA); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gPipeline.disableLights(); - // force update all mRenderMatrix, not just nodes with meshes - for (auto& obj : mObjects) - { - if (obj->isDead() || obj->mGLTFAsset == nullptr) - { - continue; - } - - LLMatrix4a mat = obj->getGLTFAssetToAgentTransform(); - - LLMatrix4a modelview; - modelview.loadu(gGLModelView); - - matMul(mat, modelview, modelview); - - Asset* asset = obj->mGLTFAsset; - - for (auto& node : asset->mNodes) - { - matMul(node.mAssetMatrix, modelview, node.mRenderMatrix); - } - } - for (auto& obj : mObjects) { if (obj->isDead() || obj->mGLTFAsset == nullptr) @@ -440,14 +1034,7 @@ void GLTFSceneManager::renderDebug() continue; } - Asset* asset = obj->mGLTFAsset; - - LLMatrix4a mat = obj->getGLTFAssetToAgentTransform(); - - LLMatrix4a modelview; - modelview.loadu(gGLModelView); - - matMul(mat, modelview, modelview); + Asset* asset = obj->mGLTFAsset.get(); renderAssetDebug(obj, asset); } @@ -458,10 +1045,7 @@ void GLTFSceneManager::renderDebug() for (U32 i = 0; i < 2; ++i) { LLGLDepthTest depth(GL_TRUE, i == 0 ? GL_FALSE : GL_TRUE, i == 0 ? GL_GREATER : GL_LEQUAL); - LLGLState blend(GL_BLEND, i == 0 ? TRUE : FALSE); - - - gGL.pushMatrix(); + LLGLState blend(GL_BLEND, i == 0 ? GL_TRUE : GL_FALSE); for (auto& obj : mObjects) { @@ -470,21 +1054,16 @@ void GLTFSceneManager::renderDebug() continue; } - LLMatrix4a mat = obj->getGLTFAssetToAgentTransform(); + gGL.pushMatrix(); - LLMatrix4a modelview; - modelview.loadu(gGLModelView); + gGL.multMatrix(obj->getGLTFAssetToAgentTransform().getF32ptr()); - matMul(mat, modelview, modelview); - - Asset* asset = obj->mGLTFAsset; + Asset* asset = obj->mGLTFAsset.get(); for (auto& node : asset->mNodes) { - // force update all mRenderMatrix, not just nodes with meshes - matMul(node.mAssetMatrix, modelview, node.mRenderMatrix); - - gGL.loadMatrix(node.mRenderMatrix.getF32ptr()); + gGL.pushMatrix(); + gGL.multMatrix(glm::value_ptr(node.mAssetMatrix)); // render x-axis red, y-axis green, z-axis blue gGL.color4f(1.f, 0.f, 0.f, 0.5f); gGL.begin(LLRender::LINES); @@ -514,16 +1093,18 @@ void GLTFSceneManager::renderDebug() { Node& child = asset->mNodes[child_idx]; gGL.vertex3f(0.f, 0.f, 0.f); - gGL.vertex3fv(child.mMatrix.getTranslation().getF32ptr()); + + + gGL.vertex3fv(glm::value_ptr(child.mMatrix[3])); } gGL.end(); gGL.flush(); + gGL.popMatrix(); } - } - gGL.popMatrix(); + gGL.popMatrix(); + } } - } @@ -533,32 +1114,41 @@ void GLTFSceneManager::renderDebug() S32 primitive_hit = -1; LLVector4a intersection; - LLDrawable* drawable = lineSegmentIntersect(gDebugRaycastStart, gDebugRaycastEnd, TRUE, TRUE, TRUE, TRUE, &node_hit, &primitive_hit, &intersection, nullptr, nullptr, nullptr); + LLDrawable* drawable = lineSegmentIntersect(gDebugRaycastStart, gDebugRaycastEnd, true, true, true, true, &node_hit, &primitive_hit, &intersection, nullptr, nullptr, nullptr); if (drawable) { - gGL.pushMatrix(); - Asset* asset = drawable->getVObj()->mGLTFAsset; - Node* node = &asset->mNodes[node_hit]; - Primitive* primitive = &asset->mMeshes[node->mMesh].mPrimitives[primitive_hit]; - gGL.flush(); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - gGL.color3f(1, 0, 1); - drawBoxOutline(intersection, LLVector4a(0.1f, 0.1f, 0.1f, 0.f)); - - gGL.loadMatrix((F32*) node->mRenderMatrix.mMatrix); + LLViewerObject* obj = drawable->getVObj(); + if (obj) + { + gGL.pushMatrix(); + gGL.multMatrix(obj->getGLTFAssetToAgentTransform().getF32ptr()); + Asset* asset = obj->mGLTFAsset.get(); + Node* node = &asset->mNodes[node_hit]; + Primitive* primitive = &asset->mMeshes[node->mMesh].mPrimitives[primitive_hit]; + gGL.flush(); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + gGL.color3f(1, 0, 1); + drawBoxOutline(intersection, LLVector4a(0.1f, 0.1f, 0.1f, 0.f)); + gGL.multMatrix(glm::value_ptr(node->mAssetMatrix)); - auto* listener = (LLVolumeOctreeListener*) primitive->mOctree->getListener(0); - drawBoxOutline(listener->mBounds[0], listener->mBounds[1]); + auto* listener = (LLVolumeOctreeListener*)primitive->mOctree->getListener(0); + drawBoxOutline(listener->mBounds[0], listener->mBounds[1]); - gGL.flush(); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - gGL.popMatrix(); + gGL.flush(); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + gGL.popMatrix(); + } } } + + gGL.popMatrix(); gDebugProgram.unbind(); + } + + |