diff options
Diffstat (limited to 'indra')
| -rw-r--r-- | indra/cmake/TinyGLTF.cmake | 7 | ||||
| -rw-r--r-- | indra/llmath/v4color.h | 12 | ||||
| -rw-r--r-- | indra/llprimitive/CMakeLists.txt | 6 | ||||
| -rw-r--r-- | indra/llprimitive/lldaeloader.cpp | 42 | ||||
| -rw-r--r-- | indra/llprimitive/lldaeloader.h | 3 | ||||
| -rw-r--r-- | indra/llprimitive/llgltfloader.cpp | 404 | ||||
| -rw-r--r-- | indra/llprimitive/llgltfloader.h | 201 | ||||
| -rw-r--r-- | indra/llprimitive/llmodelloader.cpp | 13 | ||||
| -rw-r--r-- | indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyF.glsl | 4 | ||||
| -rw-r--r-- | indra/newview/llfilepicker.cpp | 54 | ||||
| -rw-r--r-- | indra/newview/llfilepicker.h | 8 | ||||
| -rw-r--r-- | indra/newview/llfloatermodelpreview.cpp | 2 | ||||
| -rw-r--r-- | indra/newview/llmodelpreview.cpp | 50 | ||||
| -rw-r--r-- | indra/newview/llviewermenu.cpp | 5 | ||||
| -rw-r--r-- | indra/newview/llviewermenufile.cpp | 7 | 
15 files changed, 701 insertions, 117 deletions
diff --git a/indra/cmake/TinyGLTF.cmake b/indra/cmake/TinyGLTF.cmake new file mode 100644 index 0000000000..bb731637a0 --- /dev/null +++ b/indra/cmake/TinyGLTF.cmake @@ -0,0 +1,7 @@ +# -*- cmake -*- +include(Prebuilt) + +use_prebuilt_binary(tinygltf) + +set(TINYGLTF_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/tinygltf)  + diff --git a/indra/llmath/v4color.h b/indra/llmath/v4color.h index 175edf1471..f2863be531 100644 --- a/indra/llmath/v4color.h +++ b/indra/llmath/v4color.h @@ -88,7 +88,8 @@ class LLColor4  		const LLColor4&	set(const LLColor3 &vec);	// Sets LLColor4 to LLColor3 vec (no change in alpha)  		const LLColor4&	set(const LLColor3 &vec, F32 a);	// Sets LLColor4 to LLColor3 vec, with alpha specified  		const LLColor4&	set(const F32 *vec);			// Sets LLColor4 to vec -		const LLColor4&	set(const LLColor4U& color4u); // Sets LLColor4 to color4u, rescaled. +        const LLColor4&	set(const F64 *vec);			// Sets LLColor4 to (double)vec +        const LLColor4&	set(const LLColor4U& color4u); // Sets LLColor4 to color4u, rescaled.  		const LLColor4&    setAlpha(F32 a); @@ -334,6 +335,15 @@ inline const LLColor4&	LLColor4::set(const F32 *vec)  	return (*this);  } +inline const LLColor4&	LLColor4::set(const F64 *vec) +{ +    mV[VX] = static_cast<F32>(vec[VX]); +    mV[VY] = static_cast<F32>(vec[VY]); +    mV[VZ] = static_cast<F32>(vec[VZ]); +    mV[VW] = static_cast<F32>(vec[VW]); +    return (*this); +} +  // deprecated  inline const LLColor4&	LLColor4::setVec(F32 x, F32 y, F32 z)  { diff --git a/indra/llprimitive/CMakeLists.txt b/indra/llprimitive/CMakeLists.txt index fff4d8ef0a..e131b12371 100644 --- a/indra/llprimitive/CMakeLists.txt +++ b/indra/llprimitive/CMakeLists.txt @@ -10,15 +10,19 @@ include(LLCoreHttp)  include(LLXML)  include(LLPhysicsExtensions)  include(LLCharacter) +include(LLRender) +include(TinyGLTF)  include_directories(      ${LLCOMMON_INCLUDE_DIRS}      ${LLMATH_INCLUDE_DIRS}      ${LLMESSAGE_INCLUDE_DIRS}      ${LLXML_INCLUDE_DIRS} +    ${LLRENDER_INCLUDE_DIRS}      ${LIBS_PREBUILT_DIR}/include/collada      ${LIBS_PREBUILT_DIR}/include/collada/1.4      ${LLCHARACTER_INCLUDE_DIRS} +    ${TINYGLTF_INCLUDE_DIR}      )  include_directories(SYSTEM      ${LLCOMMON_SYSTEM_INCLUDE_DIRS} @@ -28,6 +32,7 @@ include_directories(SYSTEM  set(llprimitive_SOURCE_FILES      lldaeloader.cpp +    llgltfloader.cpp      llmaterialid.cpp      llmaterial.cpp      llmaterialtable.cpp @@ -46,6 +51,7 @@ set(llprimitive_SOURCE_FILES  set(llprimitive_HEADER_FILES      CMakeLists.txt      lldaeloader.h +    llgltfloader.h      legacy_object_types.h      llmaterial.h      llmaterialid.h diff --git a/indra/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp index e89690438e..68b29f01da 100644 --- a/indra/llprimitive/lldaeloader.cpp +++ b/indra/llprimitive/lldaeloader.cpp @@ -2504,20 +2504,6 @@ bool LLDAELoader::addVolumeFacesFromDomMesh(LLModel* pModel,domMesh* mesh, LLSD&  	return (status == LLModel::NO_ERRORS);  } -//static  -LLModel* LLDAELoader::loadModelFromDomMesh(domMesh *mesh) -{ -	LLVolumeParams volume_params; -	volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); -	LLModel* ret = new LLModel(volume_params, 0.f);  -	createVolumeFacesFromDomMesh(ret, mesh); -    if (ret->mLabel.empty()) -    { -	    ret->mLabel = getElementLabel(mesh); -    } -    return ret; -} -  //static diff version supports creating multiple models when material counts spill  // over the 8 face server-side limit  // @@ -2608,31 +2594,3 @@ bool LLDAELoader::loadModelsFromDomMesh(domMesh* mesh, std::vector<LLModel*>& mo  	return true;  } - -bool LLDAELoader::createVolumeFacesFromDomMesh(LLModel* pModel, domMesh* mesh) -{ -	if (mesh) -	{ -		pModel->ClearFacesAndMaterials(); - -		LLSD placeholder; -		addVolumeFacesFromDomMesh(pModel, mesh, placeholder); - -		if (pModel->getNumVolumeFaces() > 0) -		{ -			pModel->normalizeVolumeFaces(); -			pModel->optimizeVolumeFaces(); - -			if (pModel->getNumVolumeFaces() > 0) -			{ -				return true; -			} -		} -	} -	else -	{	 -		LL_WARNS() << "no mesh found" << LL_ENDL; -	} - -	return false; -} diff --git a/indra/llprimitive/lldaeloader.h b/indra/llprimitive/lldaeloader.h index 2b211343e1..52ad908870 100644 --- a/indra/llprimitive/lldaeloader.h +++ b/indra/llprimitive/lldaeloader.h @@ -90,9 +90,6 @@ protected:  	bool verifyController( domController* pController );  	static bool addVolumeFacesFromDomMesh(LLModel* model, domMesh* mesh, LLSD& log_msg); -	static bool createVolumeFacesFromDomMesh(LLModel* model, domMesh *mesh); - -	static LLModel* loadModelFromDomMesh(domMesh* mesh);  	// Loads a mesh breaking it into one or more models as necessary  	// to get around volume face limitations while retaining >8 materials diff --git a/indra/llprimitive/llgltfloader.cpp b/indra/llprimitive/llgltfloader.cpp new file mode 100644 index 0000000000..3ec11f70c6 --- /dev/null +++ b/indra/llprimitive/llgltfloader.cpp @@ -0,0 +1,404 @@ +/** + * @file LLGLTFLoader.cpp + * @brief LLGLTFLoader class implementation + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, 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 "LLGLTFLoader.h" + +// Import & define single-header gltf import/export lib +#define TINYGLTF_IMPLEMENTATION +#define TINYGLTF_USE_CPP14  // default is C++ 11 + +// tinygltf by default loads image files using STB +#define STB_IMAGE_IMPLEMENTATION +// to use our own image loading: +// 1. replace this definition with TINYGLTF_NO_STB_IMAGE +// 2. provide image loader callback with TinyGLTF::SetImageLoader(LoadimageDataFunction LoadImageData, void *user_data) + +// tinygltf saves image files using STB +#define STB_IMAGE_WRITE_IMPLEMENTATION +// similarly, can override with TINYGLTF_NO_STB_IMAGE_WRITE and TinyGLTF::SetImageWriter(fxn, data) + +// Additionally, disable inclusion of STB header files entirely with +// TINYGLTF_NO_INCLUDE_STB_IMAGE +// TINYGLTF_NO_INCLUDE_STB_IMAGE_WRITE +#include "tinygltf\tiny_gltf.h" + + +// TODO: includes inherited from dae loader.  Validate / prune + +#include <boost/lexical_cast.hpp> + +#include "llsdserialize.h" +#include "lljoint.h" + +#include "glh/glh_linear.h" +#include "llmatrix4a.h" + +#include <boost/regex.hpp> +#include <boost/algorithm/string/replace.hpp> + +static const std::string lod_suffix[LLModel::NUM_LODS] = +{ +	"_LOD0", +	"_LOD1", +	"_LOD2", +	"", +	"_PHYS", +}; + +const U32 LIMIT_MATERIALS_OUTPUT = 12; + +LLGLTFLoader::LLGLTFLoader(std::string filename, +    S32                                 lod, +    LLModelLoader::load_callback_t      load_cb, +    LLModelLoader::joint_lookup_func_t  joint_lookup_func, +    LLModelLoader::texture_load_func_t  texture_load_func, +    LLModelLoader::state_callback_t     state_cb, +    void *                              opaque_userdata, +    JointTransformMap &                 jointTransformMap, +    JointNameSet &                      jointsFromNodes, +    std::map<std::string, std::string> &jointAliasMap, +    U32                                 maxJointsPerMesh, +    U32                                 modelLimit) //, +    //bool                                preprocess) +    : LLModelLoader( filename, +                     lod, +                     load_cb, +                     joint_lookup_func, +                     texture_load_func, +                     state_cb, +                     opaque_userdata, +                     jointTransformMap, +                     jointsFromNodes, +                     jointAliasMap, +                     maxJointsPerMesh ), +    mGeneratedModelLimit(modelLimit), +    //mPreprocessGLTF(preprocess), +    mMeshesLoaded(false), +    mMaterialsLoaded(false) +{ +} + +LLGLTFLoader::~LLGLTFLoader() {} + +bool LLGLTFLoader::OpenFile(const std::string &filename) +{ +    tinygltf::TinyGLTF loader; +    std::string        error_msg; +    std::string        warn_msg; + +    // Load a tinygltf model fom a file. Assumes that the input filename has already been +    // been sanitized to one of (.gltf , .glb) extensions, so does a simple find to distinguish. +    if (std::string::npos == filename.rfind(".gltf")) +    {  // file is binary +        mGltfLoaded = loader.LoadBinaryFromFile(&mGltfModel, &error_msg, &warn_msg, filename); +    } +    else +    {  // file is ascii +        mGltfLoaded = loader.LoadASCIIFromFile(&mGltfModel, &error_msg, &warn_msg, filename); +    } + +    if (!mGltfLoaded) +    { +        if (!warn_msg.empty()) +            LL_WARNS("GLTF_IMPORT") << "gltf load warning: " << warn_msg.c_str() << LL_ENDL; +        if (!error_msg.empty()) +            LL_WARNS("GLTF_IMPORT") << "gltf load error: " << error_msg.c_str() << LL_ENDL; +        return false; +    } + +    mMeshesLoaded = parseMeshes(); +    if (mMeshesLoaded) uploadMeshes(); + +    mMaterialsLoaded = parseMaterials(); +    if (mMaterialsLoaded) uploadMaterials(); + +    return (mMeshesLoaded || mMaterialsLoaded); +} + +bool LLGLTFLoader::parseMeshes() +{ +    if (!mGltfLoaded) return false; + +    // 2022-04 DJH Volume params from dae example. TODO understand PCODE +    LLVolumeParams volume_params; +    volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);     +     +    for (tinygltf::Mesh mesh : mGltfModel.meshes) +    { +        LLModel *pModel = new LLModel(volume_params, 0.f); + +        if (populateModelFromMesh(pModel, mesh)         &&  +            (LLModel::NO_ERRORS == pModel->getStatus()) && +            validate_model(pModel)) +        { +            mModelList.push_back(pModel); +        } +        else +        { +            setLoadState(ERROR_MODEL + pModel->getStatus()); +            delete(pModel); +            return false; +        } +    } +    return true; +} + +bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const tinygltf::Mesh &mesh) +{ +    pModel->mLabel = mesh.name; +    int pos_idx, norm_idx, tan_idx, uv0_idx, uv1_idx, color0_idx, color1_idx; +    tinygltf::Accessor indices_a, positions_a, normals_a, uv0_a, color0_a; + +    auto prims = mesh.primitives; +    for (auto prim : prims) +    { +        if (prim.indices >= 0) indices_a = mGltfModel.accessors[prim.indices]; + +        pos_idx = (prim.attributes.count("POSITION") > 0) ? prim.attributes.at("POSITION") : -1; +        if (pos_idx >= 0) +        { +            positions_a = mGltfModel.accessors[pos_idx]; +            if (TINYGLTF_COMPONENT_TYPE_FLOAT != positions_a.componentType)  +                continue; +            auto positions_bv = mGltfModel.bufferViews[positions_a.bufferView]; +            auto positions_buf = mGltfModel.buffers[positions_bv.buffer]; +            //auto type = positions_vb. +            //if (positions_buf.name +        } + +        norm_idx = (prim.attributes.count("NORMAL") > 0) ? prim.attributes.at("NORMAL") : -1; +        tan_idx = (prim.attributes.count("TANGENT") > 0) ? prim.attributes.at("TANGENT") : -1; +        uv0_idx = (prim.attributes.count("TEXCOORDS_0") > 0) ? prim.attributes.at("TEXCOORDS_0") : -1; +        uv1_idx = (prim.attributes.count("TEXCOORDS_1") > 0) ? prim.attributes.at("TEXCOORDS_1") : -1; +        color0_idx = (prim.attributes.count("COLOR_0") > 0) ? prim.attributes.at("COLOR_0") : -1; +        color1_idx = (prim.attributes.count("COLOR_1") > 0) ? prim.attributes.at("COLOR_1") : -1; + +        if (prim.mode == TINYGLTF_MODE_TRIANGLES) +        { +            //auto pos = mesh.    TODO resume here DJH 2022-04 +        } +    } +     +    //pModel->addFace() +    return false; +} + +bool LLGLTFLoader::parseMaterials()  +{ +    if (!mGltfLoaded) return false; + +    // fill local texture data structures +    mSamplers.clear(); +    for (auto in_sampler : mGltfModel.samplers) +    { +        gltf_sampler sampler; +        sampler.magFilter = in_sampler.magFilter > 0 ? in_sampler.magFilter : GL_LINEAR; +        sampler.minFilter = in_sampler.minFilter > 0 ? in_sampler.minFilter : GL_LINEAR;; +        sampler.wrapS     = in_sampler.wrapS; +        sampler.wrapT     = in_sampler.wrapT; +        sampler.name      = in_sampler.name; // unused +        mSamplers.push_back(sampler); +    } + +    mImages.clear(); +    for (auto in_image : mGltfModel.images) +    { +        gltf_image image; +        image.numChannels     = in_image.component; +        image.bytesPerChannel = in_image.bits >> 3;     // Convert bits to bytes +        image.pixelType       = in_image.pixel_type;    // Maps exactly, i.e. TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE == GL_UNSIGNED_BYTE, etc +        image.size            = in_image.image.size(); +        image.height          = in_image.height; +        image.width           = in_image.width; +        image.data            = in_image.image.data(); + +        if (in_image.as_is) +        { +            LL_WARNS("GLTF_IMPORT") << "Unsupported image encoding" << LL_ENDL; +            return false; +        } +         +        if (image.size != image.height * image.width * image.numChannels * image.bytesPerChannel) +        { +            LL_WARNS("GLTF_IMPORT") << "Image size error" << LL_ENDL; +            return false; +        } + +        mImages.push_back(image); +    } + +    mTextures.clear(); +    for (auto in_tex : mGltfModel.textures) +    { +        gltf_texture tex; +        tex.imageIdx   = in_tex.source; +        tex.samplerIdx = in_tex.sampler; +        tex.imageUuid.setNull(); + +        if (tex.imageIdx >= mImages.size() || tex.samplerIdx >= mSamplers.size()) +        { +            LL_WARNS("GLTF_IMPORT") << "Texture sampler/image index error" << LL_ENDL; +            return false; +        } + +        mTextures.push_back(tex); +    } + +    // parse each material +    for (tinygltf::Material gltf_material : mGltfModel.materials) +    { +        gltf_render_material mat; +        mat.name = gltf_material.name; + +        tinygltf::PbrMetallicRoughness& pbr = gltf_material.pbrMetallicRoughness; +        mat.hasPBR = true;  // Always true, for now + +        mat.baseColor.set(pbr.baseColorFactor.data()); +        mat.hasBaseTex = pbr.baseColorTexture.index >= 0; +        mat.baseColorTexIdx = pbr.baseColorTexture.index; +        mat.baseColorTexCoords = pbr.baseColorTexture.texCoord; + +        mat.metalness = pbr.metallicFactor; +        mat.roughness = pbr.roughnessFactor; +        mat.hasMRTex = pbr.metallicRoughnessTexture.index >= 0; +        mat.metalRoughTexIdx = pbr.metallicRoughnessTexture.index; +        mat.metalRoughTexCoords = pbr.metallicRoughnessTexture.texCoord; + +        mat.normalScale = gltf_material.normalTexture.scale; +        mat.hasNormalTex = gltf_material.normalTexture.index >= 0; +        mat.normalTexIdx = gltf_material.normalTexture.index; +        mat.normalTexCoords = gltf_material.normalTexture.texCoord; + +        mat.occlusionScale = gltf_material.occlusionTexture.strength; +        mat.hasOcclusionTex = gltf_material.occlusionTexture.index >= 0; +        mat.occlusionTexIdx = gltf_material.occlusionTexture.index; +        mat.occlusionTexCoords = gltf_material.occlusionTexture.texCoord; + +        mat.emissiveColor.set(gltf_material.emissiveFactor.data()); +        mat.hasEmissiveTex = gltf_material.emissiveTexture.index >= 0; +        mat.emissiveTexIdx = gltf_material.emissiveTexture.index; +        mat.emissiveTexCoords = gltf_material.emissiveTexture.texCoord; + +        mat.alphaMode = gltf_material.alphaMode; +        mat.alphaMask = gltf_material.alphaCutoff; + +        if ((mat.hasNormalTex    && (mat.normalTexIdx     >= mTextures.size())) || +            (mat.hasOcclusionTex && (mat.occlusionTexIdx  >= mTextures.size())) || +            (mat.hasEmissiveTex  && (mat.emissiveTexIdx   >= mTextures.size())) || +            (mat.hasBaseTex      && (mat.baseColorTexIdx  >= mTextures.size())) || +            (mat.hasMRTex        && (mat.metalRoughTexIdx >= mTextures.size()))) +        { +            LL_WARNS("GLTF_IMPORT") << "Texture resource index error" << LL_ENDL; +            return false; +        } + +        if ((mat.hasNormalTex    && (mat.normalTexCoords      > 2)) ||    // mesh can have up to 3 sets of UV +            (mat.hasOcclusionTex && (mat.occlusionTexCoords   > 2)) || +            (mat.hasEmissiveTex  && (mat.emissiveTexCoords    > 2)) || +            (mat.hasBaseTex      && (mat.baseColorTexCoords   > 2)) || +            (mat.hasMRTex        && (mat.metalRoughTexCoords  > 2))) +        { +            LL_WARNS("GLTF_IMPORT") << "Image texcoord index error" << LL_ENDL; +            return false; +        } + +        mMaterials.push_back(mat); +    } + +    return true;  +} + +// TODO: convert raw vertex buffers to UUIDs +void LLGLTFLoader::uploadMeshes() +{ +    llassert(0); +} + +// convert raw image buffers to texture UUIDs & assemble into a render material +void LLGLTFLoader::uploadMaterials() +{ +    for (gltf_render_material mat : mMaterials) // Initially 1 material per gltf file, but design for multiple +    { +        if (mat.hasBaseTex) +        { +            gltf_texture& gtex = mTextures[mat.baseColorTexIdx]; +            if (gtex.imageUuid.isNull())  +            { +                gtex.imageUuid = imageBufferToTextureUUID(gtex); +            } +        } + +        if (mat.hasMRTex) +        { +            gltf_texture& gtex = mTextures[mat.metalRoughTexIdx]; +            if (gtex.imageUuid.isNull()) +            { +                gtex.imageUuid = imageBufferToTextureUUID(gtex); +            } +        } + +        if (mat.hasNormalTex) +        { +            gltf_texture& gtex = mTextures[mat.normalTexIdx]; +            if (gtex.imageUuid.isNull()) +            { +                gtex.imageUuid = imageBufferToTextureUUID(gtex); +            } +        } + +        if (mat.hasOcclusionTex) +        { +            gltf_texture& gtex = mTextures[mat.occlusionTexIdx]; +            if (gtex.imageUuid.isNull()) +            { +                gtex.imageUuid = imageBufferToTextureUUID(gtex); +            } +        } + +        if (mat.hasEmissiveTex) +        { +            gltf_texture& gtex = mTextures[mat.emissiveTexIdx]; +            if (gtex.imageUuid.isNull()) +            { +                gtex.imageUuid = imageBufferToTextureUUID(gtex); +            } +        } +    } +} + +LLUUID LLGLTFLoader::imageBufferToTextureUUID(const gltf_texture& tex) +{ +    //gltf_image& image = mImages[tex.imageIdx]; +    //gltf_sampler& sampler = mSamplers[tex.samplerIdx]; + +    // fill an LLSD container with image+sampler data + +    // upload texture + +    // retrieve UUID + +    return LLUUID::null; +} diff --git a/indra/llprimitive/llgltfloader.h b/indra/llprimitive/llgltfloader.h new file mode 100644 index 0000000000..9ee816e24e --- /dev/null +++ b/indra/llprimitive/llgltfloader.h @@ -0,0 +1,201 @@ +/** + * @file LLGLTFLoader.h + * @brief LLGLTFLoader class definition + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, 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$ + */ + +#ifndef LL_LLGLTFLoader_H +#define LL_LLGLTFLoader_H + +#include "tinygltf/tiny_gltf.h" + +#include "llglheaders.h" +#include "llmodelloader.h" + +// gltf_* structs are temporary, used to organize the subset of data that eventually goes into the material LLSD + +typedef struct // gltf sampler +{   // Uses GL enums +    S32 minFilter;      // GL_NEAREST, GL_LINEAR, GL_NEAREST_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR or GL_LINEAR_MIPMAP_LINEAR +    S32 magFilter;      // GL_NEAREST or GL_LINEAR +    S32 wrapS;          // GL_CLAMP_TO_EDGE, GL_MIRRORED_REPEAT or GL_REPEAT +    S32 wrapT;          // GL_CLAMP_TO_EDGE, GL_MIRRORED_REPEAT or GL_REPEAT +    //S32 wrapR;        // Found in some sample files, but not part of glTF 2.0 spec. Ignored. +    std::string name;   // optional, currently unused +    // extensions and extras are sampler optional fields that we don't support - at least initially  +} gltf_sampler; + +typedef struct // gltf image +{   // Note that glTF images are defined with row 0 at the top (opposite of OpenGL) +    U8* data;               // ptr to decoded image data +    U32 size;               // in bytes, regardless of channel width +    U32 width; +    U32 height; +    U32 numChannels;        // range 1..4 +    U32 bytesPerChannel;    // converted from gltf "bits", expects only 8, 16 or 32 as input +    U32 pixelType;          // one of (TINYGLTF_COMPONENT_TYPE)_UNSIGNED_BYTE, _UNSIGNED_SHORT, _UNSIGNED_INT, or _FLOAT +} gltf_image; + +typedef struct // texture +{ +    U32 imageIdx; +    U32 samplerIdx; +    LLUUID imageUuid = LLUUID::null; +} gltf_texture; + +typedef struct // render material +{ +    std::string name; + +    // scalar values +    LLColor4    baseColor;      // linear encoding. Multiplied with vertex color, if present. +    double      metalness; +    double      roughness; +    double      normalScale;    // scale applies only to X,Y components of normal +    double      occlusionScale; // strength multiplier for occlusion +    LLColor4    emissiveColor;  // emissive mulitiplier, assumed linear encoding (spec 2.0 is silent) +    std::string alphaMode;      // "OPAQUE", "MASK" or "BLEND" +    double      alphaMask;      // alpha cut-off + +    // textures +    U32 baseColorTexIdx;    // always sRGB encoded +    U32 metalRoughTexIdx;   // always linear, roughness in G channel, metalness in B channel +    U32 normalTexIdx;       // linear, valid range R[0-1], G[0-1], B[0.5-1]. Normal = texel * 2 - vec3(1.0)    +    U32 occlusionTexIdx;    // linear, occlusion in R channel, 0 meaning fully occluded, 1 meaning not occluded +    U32 emissiveTexIdx;     // always stored as sRGB, in nits (candela / meter^2) + +    // texture coordinates +    U32 baseColorTexCoords; +    U32 metalRoughTexCoords; +    U32 normalTexCoords; +    U32 occlusionTexCoords; +    U32 emissiveTexCoords; + +    // TODO: Add traditional (diffuse, normal, specular) UUIDs here, or add this struct to LL_TextureEntry?? + +    bool        hasPBR; +    bool        hasBaseTex, hasMRTex, hasNormalTex, hasOcclusionTex, hasEmissiveTex; + +    // This field is populated after upload +    LLUUID      material_uuid = LLUUID::null; + +} gltf_render_material; + +typedef struct  // gltf_mesh +{ +    std::string name; + +    // TODO add mesh import DJH 2022-04 + +} gltf_mesh; + +class LLGLTFLoader : public LLModelLoader +{ +  public: +    typedef std::map<std::string, LLImportMaterial> material_map; + +    LLGLTFLoader(std::string filename, +                    S32                                 lod, +                    LLModelLoader::load_callback_t      load_cb, +                    LLModelLoader::joint_lookup_func_t  joint_lookup_func, +                    LLModelLoader::texture_load_func_t  texture_load_func, +                    LLModelLoader::state_callback_t     state_cb, +                    void *                              opaque_userdata, +                    JointTransformMap &                 jointTransformMap, +                    JointNameSet &                      jointsFromNodes, +                    std::map<std::string, std::string> &jointAliasMap, +                    U32                                 maxJointsPerMesh, +                    U32                                 modelLimit); //, +                    //bool                                preprocess ); +    virtual ~LLGLTFLoader(); + +    virtual bool OpenFile(const std::string &filename); + +protected: +    tinygltf::Model mGltfModel; +    bool            mGltfLoaded; +    bool            mMeshesLoaded; +    bool            mMaterialsLoaded; + +    std::vector<gltf_mesh>              mMeshes; +    std::vector<gltf_render_material>   mMaterials; + +    std::vector<gltf_texture>           mTextures; +    std::vector<gltf_image>             mImages; +    std::vector<gltf_sampler>           mSamplers; + +private: +    bool parseMeshes(); +    void uploadMeshes(); +    bool parseMaterials(); +    void uploadMaterials(); +    bool populateModelFromMesh(LLModel* pModel, const tinygltf::Mesh &mesh); +    LLUUID imageBufferToTextureUUID(const gltf_texture& tex); + +    U32  mGeneratedModelLimit;  // Attempt to limit amount of generated submodels +    //    bool mPreprocessGLTF; + +    /*  Below inherited from dae loader - unknown if/how useful here + +    void processElement(gltfElement *element, bool &badElement, GLTF *gltf); +    void processGltfModel(LLModel *model, GLTF *gltf, gltfElement *pRoot, gltfMesh *mesh, gltfSkin *skin); + +    material_map     getMaterials(LLModel *model, gltfInstance_geometry *instance_geo, GLTF *gltf); +    LLImportMaterial profileToMaterial(gltfProfile_COMMON *material, GLTF *gltf); +    LLColor4         getGltfColor(gltfElement *element); + +    gltfElement *getChildFromElement(gltfElement *pElement, std::string const &name); + +    bool isNodeAJoint(gltfNode *pNode); +    void processJointNode(gltfNode *pNode, std::map<std::string, LLMatrix4> &jointTransforms); +    void extractTranslation(gltfTranslate *pTranslate, LLMatrix4 &transform); +    void extractTranslationViaElement(gltfElement *pTranslateElement, LLMatrix4 &transform); +    void extractTranslationViaSID(gltfElement *pElement, LLMatrix4 &transform); +    void buildJointToNodeMappingFromScene(gltfElement *pRoot); +    void processJointToNodeMapping(gltfNode *pNode); +    void processChildJoints(gltfNode *pParentNode); + +    bool verifyCount(int expected, int result); + +    // Verify that a controller matches vertex counts +    bool verifyController(gltfController *pController); + +    static bool addVolumeFacesFromGltfMesh(LLModel *model, gltfMesh *mesh, LLSD &log_msg); +    static bool createVolumeFacesFromGltfMesh(LLModel *model, gltfMesh *mesh); + +    static LLModel *loadModelFromGltfMesh(gltfMesh *mesh); + +    // Loads a mesh breaking it into one or more models as necessary +    // to get around volume face limitations while retaining >8 materials +    // +    bool loadModelsFromGltfMesh(gltfMesh *mesh, std::vector<LLModel *> &models_out, U32 submodel_limit); + +    static std::string getElementLabel(gltfElement *element); +    static size_t      getSuffixPosition(std::string label); +    static std::string getLodlessLabel(gltfElement *element); + +    static std::string preprocessGLTF(std::string filename); +    */ +     +}; +#endif  // LL_LLGLTFLLOADER_H diff --git a/indra/llprimitive/llmodelloader.cpp b/indra/llprimitive/llmodelloader.cpp index 5171621007..554ed54de1 100644 --- a/indra/llprimitive/llmodelloader.cpp +++ b/indra/llprimitive/llmodelloader.cpp @@ -160,7 +160,8 @@ bool LLModelLoader::getSLMFilename(const std::string& model_filename, std::strin      std::string::size_type i = model_filename.rfind(".");      if (i != std::string::npos)      { -        slm_filename.replace(i, model_filename.size()-1, ".slm"); +        slm_filename.resize(i, '\0'); +        slm_filename.append(".slm");          return true;      }      else @@ -172,7 +173,7 @@ bool LLModelLoader::getSLMFilename(const std::string& model_filename, std::strin  bool LLModelLoader::doLoadModel()  {  	//first, look for a .slm file of the same name that was modified later -	//than the .dae +	//than the specified model file  	if (mTrySLM)  	{ @@ -182,13 +183,13 @@ bool LLModelLoader::doLoadModel()  			llstat slm_status;  			if (LLFile::stat(slm_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) +				llstat model_file_status; +				if (LLFile::stat(mFilename, &model_file_status) != 0 || +					model_file_status.st_mtime < slm_status.st_mtime)  				{  					if (loadFromSLM(slm_filename))  					{ //slm successfully loaded, if this fails, fall through and -						//try loading from dae +						//try loading from model file  						mLod = -1; //successfully loading from an slm implicitly sets all   									//LoDs diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyF.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyF.glsl index 9fcee04c32..f693323d45 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyF.glsl @@ -38,7 +38,7 @@ uniform sampler2D diffuseMap;  VARYING vec4 vertex_color;  VARYING vec2 vary_texcoord0;  VARYING vec3 vary_texcoord1; -VARYING vec4 vary_position; +VARYING vec3 vary_position;  uniform samplerCube environmentMap; @@ -74,7 +74,7 @@ void main()  	vec3 amblit;  	vec3 additive;  	vec3 atten; -		vec3 pos = vary_position.xyz/vary_position.w; +	vec3 pos = vary_position.xyz;  	calcAtmosphericVars(pos.xyz, vec3(0), 1.0, sunlit, amblit, additive, atten, false); diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index 3669fb1eeb..4e2cc34207 100644 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -55,13 +55,11 @@ LLFilePicker LLFilePicker::sInstance;  #define IMAGE_FILTER L"Images (*.tga; *.bmp; *.jpg; *.jpeg; *.png)\0*.tga;*.bmp;*.jpg;*.jpeg;*.png\0"  #define ANIM_FILTER L"Animations (*.bvh; *.anim)\0*.bvh;*.anim\0"  #define COLLADA_FILTER L"Scene (*.dae)\0*.dae\0" -#ifdef _CORY_TESTING -#define GEOMETRY_FILTER L"SL Geometry (*.slg)\0*.slg\0" -#endif +#define GLTF_FILTER L"glTF (*.gltf; *.glb)\0*.gltf;*.glb\0"  #define XML_FILTER L"XML files (*.xml)\0*.xml\0"  #define SLOBJECT_FILTER L"Objects (*.slobject)\0*.slobject\0"  #define RAW_FILTER L"RAW files (*.raw)\0*.raw\0" -#define MODEL_FILTER L"Model files (*.dae)\0*.dae\0" +#define MODEL_FILTER L"Model files (*.dae; *.gltf; *.glb)\0*.dae;*.gltf;*.glb\0"  #define SCRIPT_FILTER L"Script files (*.lsl)\0*.lsl\0"  #define DICTIONARY_FILTER L"Dictionary files (*.dic; *.xcu)\0*.dic;*.xcu\0"  #endif @@ -193,16 +191,14 @@ BOOL LLFilePicker::setupFilter(ELoadFilter filter)  		mOFN.lpstrFilter = ANIM_FILTER \  			L"\0";  		break; -	case FFLOAD_COLLADA: +    case FFLOAD_GLTF: +        mOFN.lpstrFilter = GLTF_FILTER \ +            L"\0"; +        break; +    case FFLOAD_COLLADA:  		mOFN.lpstrFilter = COLLADA_FILTER \  			L"\0";  		break; -#ifdef _CORY_TESTING -	case FFLOAD_GEOMETRY: -		mOFN.lpstrFilter = GEOMETRY_FILTER \ -			L"\0"; -		break; -#endif  	case FFLOAD_XML:  		mOFN.lpstrFilter = XML_FILTER \  			L"\0"; @@ -480,18 +476,16 @@ BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename,  			L"XAF Anim File (*.xaf)\0*.xaf\0" \  			L"\0";  		break; -#ifdef _CORY_TESTING -	case FFSAVE_GEOMETRY: +	case FFSAVE_GLTF:  		if (filename.empty())  		{ -			wcsncpy( mFilesW,L"untitled.slg", FILENAME_BUFFER_SIZE);	/*Flawfinder: ignore*/ +			wcsncpy( mFilesW,L"untitled.glb", FILENAME_BUFFER_SIZE);	/*Flawfinder: ignore*/  		} -		mOFN.lpstrDefExt = L"slg"; +		mOFN.lpstrDefExt = L"glb";  		mOFN.lpstrFilter = -			L"SLG SL Geometry File (*.slg)\0*.slg\0" \ +			L"glTF Asset File (*.gltf *.glb)\0*.gltf;*.glb\0" \  			L"\0";  		break; -#endif  	case FFSAVE_XML:  		if (filename.empty())  		{ @@ -621,14 +615,13 @@ std::vector<std::string>* LLFilePicker::navOpenFilterProc(ELoadFilter filter) //              allowedv->push_back("bvh");              allowedv->push_back("anim");              break; +        case FFLOAD_GLTF: +            allowedv->push_back("gltf"); +            allowedv->push_back("glb"); +            break;          case FFLOAD_COLLADA:              allowedv->push_back("dae");              break; -#ifdef _CORY_TESTING -        case FFLOAD_GEOMETRY: -            allowedv->push_back("slg"); -            break; -#endif          case FFLOAD_XML:              allowedv->push_back("xml");              break; @@ -728,13 +721,11 @@ bool	LLFilePicker::doNavSaveDialog(ESaveFilter filter, const std::string& filena  			extension = "xaf";  			break; -#ifdef _CORY_TESTING -		case FFSAVE_GEOMETRY: +		case FFSAVE_GLTF:  			type = "\?\?\?\?";  			creator = "\?\?\?\?"; -			extension = "slg"; +			extension = "glb";  			break; -#endif	  		case FFSAVE_XML:  			type = "\?\?\?\?"; @@ -1354,10 +1345,13 @@ BOOL LLFilePicker::getOpenFile( ELoadFilter filter, bool blocking )  		case FFLOAD_XML:  			filtername = add_xml_filter_to_gtkchooser(picker);  			break; -		case FFLOAD_COLLADA: -			filtername = add_collada_filter_to_gtkchooser(picker); -			break; -		case FFLOAD_IMAGE: +        case FFLOAD_GLTF: +            filtername = dead_code_should_blow_up_here(picker); +            break; +        case FFLOAD_COLLADA: +            filtername = add_collada_filter_to_gtkchooser(picker); +            break; +        case FFLOAD_IMAGE:  			filtername = add_imageload_filter_to_gtkchooser(picker);  			break;  		case FFLOAD_SCRIPT: diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h index 04ba4416d7..a314207da6 100644 --- a/indra/newview/llfilepicker.h +++ b/indra/newview/llfilepicker.h @@ -77,9 +77,7 @@ public:  		FFLOAD_WAV = 2,  		FFLOAD_IMAGE = 3,  		FFLOAD_ANIM = 4, -#ifdef _CORY_TESTING -		FFLOAD_GEOMETRY = 5, -#endif +		FFLOAD_GLTF = 5,  		FFLOAD_XML = 6,  		FFLOAD_SLOBJECT = 7,  		FFLOAD_RAW = 8, @@ -99,9 +97,7 @@ public:  		FFSAVE_BMP = 5,  		FFSAVE_AVI = 6,  		FFSAVE_ANIM = 7, -#ifdef _CORY_TESTING -		FFSAVE_GEOMETRY = 8, -#endif +		FFSAVE_GLTF = 8,  		FFSAVE_XML = 9,  		FFSAVE_COLLADA = 10,  		FFSAVE_RAW = 11, diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 7279e1ad6d..b77341f806 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -97,7 +97,7 @@ private:  };  LLMeshFilePicker::LLMeshFilePicker(LLModelPreview* mp, S32 lod) -: LLFilePickerThread(LLFilePicker::FFLOAD_COLLADA) +: LLFilePickerThread(LLFilePicker::FFLOAD_MODEL)  	{  		mMP = mp;  		mLOD = lod; diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index 859d987fc3..e67bd6468e 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -30,6 +30,7 @@  #include "llmodelloader.h"  #include "lldaeloader.h" +#include "llgltfloader.h"  #include "llfloatermodelpreview.h"  #include "llagent.h" @@ -732,20 +733,41 @@ void LLModelPreview::loadModel(std::string filename, S32 lod, bool force_disable      std::map<std::string, std::string> joint_alias_map;      getJointAliases(joint_alias_map); -    mModelLoader = new LLDAELoader( -        filename, -        lod, -        &LLModelPreview::loadedCallback, -        &LLModelPreview::lookupJointByName, -        &LLModelPreview::loadTextures, -        &LLModelPreview::stateChangedCallback, -        this, -        mJointTransformMap, -        mJointsFromNode, -        joint_alias_map, -        LLSkinningUtil::getMaxJointCount(), -        gSavedSettings.getU32("ImporterModelLimit"), -        gSavedSettings.getBOOL("ImporterPreprocessDAE")); +    // three possible file extensions, .dae .gltf .glb +    // check for .dae and if not then assume one of the .gl?? +    if (std::string::npos != filename.rfind(".dae")) +    { +        mModelLoader = new LLDAELoader( +            filename, +            lod, +            &LLModelPreview::loadedCallback, +            &LLModelPreview::lookupJointByName, +            &LLModelPreview::loadTextures, +            &LLModelPreview::stateChangedCallback, +            this, +            mJointTransformMap, +            mJointsFromNode, +            joint_alias_map, +            LLSkinningUtil::getMaxJointCount(), +            gSavedSettings.getU32("ImporterModelLimit"), +            gSavedSettings.getBOOL("ImporterPreprocessDAE")); +    } +    else +    { +        mModelLoader = new LLGLTFLoader( +            filename, +            lod, +            &LLModelPreview::loadedCallback, +            &LLModelPreview::lookupJointByName, +            &LLModelPreview::loadTextures, +            &LLModelPreview::stateChangedCallback, +            this, +            mJointTransformMap, +            mJointsFromNode, +            joint_alias_map, +            LLSkinningUtil::getMaxJointCount(), +            gSavedSettings.getU32("ImporterModelLimit")); +    }      if (force_disable_slm)      { diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 8732bde35c..9c8a666185 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -267,16 +267,11 @@ void handle_reset_view();  void handle_duplicate_in_place(void*); -  void handle_object_owner_self(void*);  void handle_object_owner_permissive(void*);  void handle_object_lock(void*);  void handle_object_asset_ids(void*);  void force_take_copy(void*); -#ifdef _CORY_TESTING -void force_export_copy(void*); -void force_import_geometry(void*); -#endif  void handle_force_parcel_owner_to_me(void*);  void handle_force_parcel_to_content(void*); diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index 28ff69eaf5..32fdfe282d 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -277,9 +277,6 @@ void LLMediaFilePicker::notify(const std::vector<std::string>& filenames)  static std::string SOUND_EXTENSIONS = "wav";  static std::string IMAGE_EXTENSIONS = "tga bmp jpg jpeg png";  static std::string ANIM_EXTENSIONS =  "bvh anim"; -#ifdef _CORY_TESTING -static std::string GEOMETRY_EXTENSIONS = "slg"; -#endif  static std::string XML_EXTENSIONS = "xml";  static std::string SLOBJECT_EXTENSIONS = "slobject";  #endif @@ -301,10 +298,6 @@ std::string build_extensions_string(LLFilePicker::ELoadFilter filter)  		return SLOBJECT_EXTENSIONS;  	case LLFilePicker::FFLOAD_MODEL:  		return MODEL_EXTENSIONS; -#ifdef _CORY_TESTING -	case LLFilePicker::FFLOAD_GEOMETRY: -		return GEOMETRY_EXTENSIONS; -#endif  	case LLFilePicker::FFLOAD_XML:  	    return XML_EXTENSIONS;      case LLFilePicker::FFLOAD_ALL:  | 
