summaryrefslogtreecommitdiff
path: root/indra/llprimitive/llgltfloader.h
blob: b4d6ca19406bd40a119adec38d8b67e0233cecf0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
/**
 * @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

class gltf_sampler
{   
public:
    // 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 
};

class gltf_image
{
public:// 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
};

class gltf_texture
{
public:
    U32 imageIdx;
    U32 samplerIdx;
    LLUUID imageUuid = LLUUID::null;
};

class gltf_render_material
{
public:
    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;

};

class gltf_mesh
{
public:
    std::string name;

    // TODO add mesh import DJH 2022-04

};

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);

    //    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