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
|