Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
G
GLTF Scene Viewer
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Requirements
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Test cases
Artifacts
Deploy
Releases
Model registry
Operate
Environments
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Code review analytics
Issue analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Nils Petter Skålerud
GLTF Scene Viewer
Commits
1a6c06e8
Commit
1a6c06e8
authored
6 years ago
by
Nils Petter Skålerud
Browse files
Options
Downloads
Patches
Plain Diff
Moved fx-gltf into external
parent
58521e09
No related branches found
No related tags found
No related merge requests found
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
.gitmodules
+3
-0
3 additions, 0 deletions
.gitmodules
external/fx-gltf
+1
-0
1 addition, 0 deletions
external/fx-gltf
include/fx-gltf/gltf.h
+0
-1928
0 additions, 1928 deletions
include/fx-gltf/gltf.h
with
4 additions
and
1928 deletions
.gitmodules
+
3
−
0
View file @
1a6c06e8
[submodule "external/DMath"]
[submodule "external/DMath"]
path = external/DMath
path = external/DMath
url = git@github.com:Didgy74/DMath.git
url = git@github.com:Didgy74/DMath.git
[submodule "external/fx-gltf"]
path = external/fx-gltf
url = https://github.com/jessey-git/fx-gltf.git
This diff is collapsed.
Click to expand it.
fx-gltf
@
85ac8279
Subproject commit 85ac827969428df599f7b7866eef9af143217ec9
This diff is collapsed.
Click to expand it.
include/fx-gltf/gltf.h
deleted
100644 → 0
+
0
−
1928
View file @
58521e09
// ------------------------------------------------------------
// Copyright(c) 2018 Jesse Yurkovich
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
// See the LICENSE file in the repo root for full license information.
// ------------------------------------------------------------
#pragma once
#include
<array>
#include
<cstring>
#include
<fstream>
#include
<stdexcept>
#include
<string>
#include
<system_error>
#include
<unordered_map>
#include
<vector>
#include
<nlohmann/json.hpp>
#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1)
#define FX_GLTF_HAS_CPP_17
#include
<string_view>
#endif
namespace
fx
{
namespace
base64
{
namespace
detail
{
// clang-format off
constexpr
std
::
array
<
char
,
64
>
EncodeMap
=
{
'A'
,
'B'
,
'C'
,
'D'
,
'E'
,
'F'
,
'G'
,
'H'
,
'I'
,
'J'
,
'K'
,
'L'
,
'M'
,
'N'
,
'O'
,
'P'
,
'Q'
,
'R'
,
'S'
,
'T'
,
'U'
,
'V'
,
'W'
,
'X'
,
'Y'
,
'Z'
,
'a'
,
'b'
,
'c'
,
'd'
,
'e'
,
'f'
,
'g'
,
'h'
,
'i'
,
'j'
,
'k'
,
'l'
,
'm'
,
'n'
,
'o'
,
'p'
,
'q'
,
'r'
,
's'
,
't'
,
'u'
,
'v'
,
'w'
,
'x'
,
'y'
,
'z'
,
'0'
,
'1'
,
'2'
,
'3'
,
'4'
,
'5'
,
'6'
,
'7'
,
'8'
,
'9'
,
'+'
,
'/'
};
constexpr
std
::
array
<
char
,
256
>
DecodeMap
=
{
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
62
,
-
1
,
-
1
,
-
1
,
63
,
52
,
53
,
54
,
55
,
56
,
57
,
58
,
59
,
60
,
61
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
0
,
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
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
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
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
};
// clang-format on
}
// namespace detail
inline
std
::
string
Encode
(
std
::
vector
<
uint8_t
>
const
&
bytes
)
{
const
std
::
size_t
length
=
bytes
.
size
();
if
(
length
==
0
)
{
return
{};
}
std
::
string
out
{};
out
.
reserve
(((
length
*
4
/
3
)
+
3
)
&
(
~
3u
));
// round up to nearest 4
uint32_t
value
=
0
;
int32_t
bitCount
=
-
6
;
for
(
const
uint8_t
c
:
bytes
)
{
value
=
(
value
<<
8u
)
+
c
;
bitCount
+=
8
;
while
(
bitCount
>=
0
)
{
const
uint32_t
shiftOperand
=
bitCount
;
out
.
push_back
(
detail
::
EncodeMap
.
at
((
value
>>
shiftOperand
)
&
0x3fu
));
bitCount
-=
6
;
}
}
if
(
bitCount
>
-
6
)
{
const
uint32_t
shiftOperand
=
bitCount
+
8
;
out
.
push_back
(
detail
::
EncodeMap
.
at
(((
value
<<
8u
)
>>
shiftOperand
)
&
0x3fu
));
}
while
(
out
.
size
()
%
4
!=
0
)
{
out
.
push_back
(
'='
);
}
return
out
;
}
#if defined(FX_GLTF_HAS_CPP_17)
inline
bool
TryDecode
(
std
::
string_view
in
,
std
::
vector
<
uint8_t
>
&
out
)
#else
inline
bool
TryDecode
(
std
::
string
const
&
in
,
std
::
vector
<
uint8_t
>
&
out
)
#endif
{
out
.
clear
();
const
std
::
size_t
length
=
in
.
length
();
if
(
length
==
0
)
{
return
true
;
}
if
(
length
%
4
!=
0
)
{
return
false
;
}
out
.
reserve
((
length
/
4
)
*
3
);
bool
invalid
=
false
;
uint32_t
value
=
0
;
int32_t
bitCount
=
-
8
;
for
(
std
::
size_t
i
=
0
;
i
<
length
;
i
++
)
{
const
uint8_t
c
=
static_cast
<
uint8_t
>
(
in
[
i
]);
const
char
map
=
detail
::
DecodeMap
.
at
(
c
);
if
(
map
==
-
1
)
{
if
(
c
!=
'='
)
// Non base64 character
{
invalid
=
true
;
}
else
{
// Padding characters not where they should be
const
std
::
size_t
remaining
=
length
-
i
-
1
;
if
(
remaining
>
1
||
(
remaining
==
1
?
in
[
i
+
1
]
!=
'='
:
false
))
{
invalid
=
true
;
}
}
break
;
}
value
=
(
value
<<
6u
)
+
map
;
bitCount
+=
6
;
if
(
bitCount
>=
0
)
{
const
uint32_t
shiftOperand
=
bitCount
;
out
.
push_back
(
static_cast
<
uint8_t
>
(
value
>>
shiftOperand
));
bitCount
-=
8
;
}
}
if
(
invalid
)
{
out
.
clear
();
}
return
!
invalid
;
}
}
// namespace base64
namespace
gltf
{
class
invalid_gltf_document
:
public
std
::
runtime_error
{
public:
explicit
invalid_gltf_document
(
char
const
*
message
)
:
std
::
runtime_error
(
message
)
{
}
invalid_gltf_document
(
char
const
*
message
,
std
::
string
const
&
extra
)
:
std
::
runtime_error
(
CreateMessage
(
message
,
extra
).
c_str
())
{
}
private
:
std
::
string
CreateMessage
(
char
const
*
message
,
std
::
string
const
&
extra
)
{
return
std
::
string
(
message
).
append
(
" : "
).
append
(
extra
);
}
};
namespace
detail
{
#if defined(FX_GLTF_HAS_CPP_17)
template
<
typename
TTarget
>
inline
void
ReadRequiredField
(
std
::
string_view
key
,
nlohmann
::
json
const
&
json
,
TTarget
&
target
)
#else
template
<
typename
TKey
,
typename
TTarget
>
inline
void
ReadRequiredField
(
TKey
&&
key
,
nlohmann
::
json
const
&
json
,
TTarget
&
target
)
#endif
{
const
nlohmann
::
json
::
const_iterator
iter
=
json
.
find
(
key
);
if
(
iter
==
json
.
end
())
{
throw
invalid_gltf_document
(
"Required field not found"
,
std
::
string
(
key
));
}
target
=
iter
->
get
<
TTarget
>
();
}
#if defined(FX_GLTF_HAS_CPP_17)
template
<
typename
TTarget
>
inline
void
ReadOptionalField
(
std
::
string_view
key
,
nlohmann
::
json
const
&
json
,
TTarget
&
target
)
#else
template
<
typename
TKey
,
typename
TTarget
>
inline
void
ReadOptionalField
(
TKey
&&
key
,
nlohmann
::
json
const
&
json
,
TTarget
&
target
)
#endif
{
const
nlohmann
::
json
::
const_iterator
iter
=
json
.
find
(
key
);
if
(
iter
!=
json
.
end
())
{
target
=
iter
->
get
<
TTarget
>
();
}
}
inline
void
ReadExtensionsAndExtras
(
nlohmann
::
json
const
&
json
,
nlohmann
::
json
&
extensionsAndExtras
)
{
const
nlohmann
::
json
::
const_iterator
iterExtensions
=
json
.
find
(
"extensions"
);
const
nlohmann
::
json
::
const_iterator
iterExtras
=
json
.
find
(
"extras"
);
if
(
iterExtensions
!=
json
.
end
())
{
extensionsAndExtras
[
"extensions"
]
=
*
iterExtensions
;
}
if
(
iterExtras
!=
json
.
end
())
{
extensionsAndExtras
[
"extras"
]
=
*
iterExtras
;
}
}
template
<
typename
TValue
>
inline
void
WriteField
(
std
::
string
const
&
key
,
nlohmann
::
json
&
json
,
TValue
const
&
value
)
{
if
(
!
value
.
empty
())
{
json
[
key
]
=
value
;
}
}
template
<
typename
TValue
>
inline
void
WriteField
(
std
::
string
const
&
key
,
nlohmann
::
json
&
json
,
TValue
const
&
value
,
TValue
const
&
defaultValue
)
{
if
(
value
!=
defaultValue
)
{
json
[
key
]
=
value
;
}
}
inline
void
WriteExtensions
(
nlohmann
::
json
&
json
,
nlohmann
::
json
const
&
extensionsAndExtras
)
{
if
(
!
extensionsAndExtras
.
empty
())
{
for
(
nlohmann
::
json
::
const_iterator
it
=
extensionsAndExtras
.
begin
();
it
!=
extensionsAndExtras
.
end
();
++
it
)
{
json
[
it
.
key
()]
=
it
.
value
();
}
}
}
inline
std
::
string
GetDocumentRootPath
(
std
::
string
const
&
documentFilePath
)
{
const
std
::
size_t
pos
=
documentFilePath
.
find_last_of
(
"/
\\
"
);
if
(
pos
!=
std
::
string
::
npos
)
{
return
documentFilePath
.
substr
(
0
,
pos
);
}
return
{};
}
inline
std
::
string
CreateBufferUriPath
(
std
::
string
const
&
documentRootPath
,
std
::
string
const
&
bufferUri
)
{
// Prevent simple forms of path traversal from malicious uri references...
if
(
bufferUri
.
empty
()
||
bufferUri
.
find
(
".."
)
!=
std
::
string
::
npos
||
bufferUri
.
front
()
==
'/'
||
bufferUri
.
front
()
==
'\\'
)
{
throw
invalid_gltf_document
(
"Invalid buffer.uri value"
,
bufferUri
);
}
std
::
string
documentRoot
=
documentRootPath
;
if
(
documentRoot
.
length
()
>
0
)
{
if
(
documentRoot
.
back
()
!=
'/'
)
{
documentRoot
.
push_back
(
'/'
);
}
}
return
documentRoot
+
bufferUri
;
}
struct
ChunkHeader
{
uint32_t
chunkLength
{};
uint32_t
chunkType
{};
};
struct
GLBHeader
{
uint32_t
magic
{};
uint32_t
version
{};
uint32_t
length
{};
ChunkHeader
jsonHeader
{};
};
constexpr
uint32_t
DefaultMaxBufferCount
=
8
;
constexpr
uint32_t
DefaultMaxMemoryAllocation
=
32
*
1024
*
1024
;
constexpr
std
::
size_t
HeaderSize
{
sizeof
(
GLBHeader
)
};
constexpr
std
::
size_t
ChunkHeaderSize
{
sizeof
(
ChunkHeader
)
};
constexpr
uint32_t
GLBHeaderMagic
=
0x46546c67u
;
constexpr
uint32_t
GLBChunkJSON
=
0x4e4f534au
;
constexpr
uint32_t
GLBChunkBIN
=
0x004e4942u
;
constexpr
char
const
*
const
MimetypeApplicationOctet
=
"data:application/octet-stream;base64"
;
constexpr
char
const
*
const
MimetypeImagePNG
=
"data:image/png;base64"
;
constexpr
char
const
*
const
MimetypeImageJPG
=
"data:image/jpeg;base64"
;
}
// namespace detail
namespace
defaults
{
constexpr
std
::
array
<
float
,
16
>
IdentityMatrix
{
1
,
0
,
0
,
0
,
0
,
1
,
0
,
0
,
0
,
0
,
1
,
0
,
0
,
0
,
0
,
1
};
constexpr
std
::
array
<
float
,
4
>
IdentityRotation
{
0
,
0
,
0
,
1
};
constexpr
std
::
array
<
float
,
4
>
IdentityVec4
{
1
,
1
,
1
,
1
};
constexpr
std
::
array
<
float
,
3
>
IdentityVec3
{
1
,
1
,
1
};
constexpr
std
::
array
<
float
,
3
>
NullVec3
{
0
,
0
,
0
};
constexpr
float
IdentityScalar
=
1
;
constexpr
float
FloatSentinel
=
10000
;
constexpr
bool
AccessorNormalized
=
false
;
constexpr
float
MaterialAlphaCutoff
=
0.5
f
;
constexpr
bool
MaterialDoubleSided
=
false
;
}
// namespace defaults
using
Attributes
=
std
::
unordered_map
<
std
::
string
,
uint32_t
>
;
struct
NeverEmpty
{
bool
empty
()
const
noexcept
{
return
false
;
}
};
struct
Accessor
{
enum
class
ComponentType
:
uint16_t
{
None
=
0
,
Byte
=
5120
,
UnsignedByte
=
5121
,
Short
=
5122
,
UnsignedShort
=
5123
,
UnsignedInt
=
5125
,
Float
=
5126
};
enum
class
Type
:
uint8_t
{
None
,
Scalar
,
Vec2
,
Vec3
,
Vec4
,
Mat2
,
Mat3
,
Mat4
};
struct
Sparse
{
struct
Indices
:
NeverEmpty
{
uint32_t
bufferView
{};
uint32_t
byteOffset
{};
ComponentType
componentType
{
ComponentType
::
None
};
nlohmann
::
json
extensionsAndExtras
{};
};
struct
Values
:
NeverEmpty
{
uint32_t
bufferView
{};
uint32_t
byteOffset
{};
nlohmann
::
json
extensionsAndExtras
{};
};
int32_t
count
{};
Indices
indices
{};
Values
values
{};
nlohmann
::
json
extensionsAndExtras
{};
bool
empty
()
const
noexcept
{
return
count
==
0
;
}
};
int32_t
bufferView
{
-
1
};
uint32_t
byteOffset
{};
uint32_t
count
{};
bool
normalized
{
defaults
::
AccessorNormalized
};
ComponentType
componentType
{
ComponentType
::
None
};
Type
type
{
Type
::
None
};
Sparse
sparse
{};
std
::
string
name
;
std
::
vector
<
float
>
max
{};
std
::
vector
<
float
>
min
{};
nlohmann
::
json
extensionsAndExtras
{};
};
struct
Animation
{
struct
Channel
{
struct
Target
:
NeverEmpty
{
int32_t
node
{
-
1
};
std
::
string
path
{};
nlohmann
::
json
extensionsAndExtras
{};
};
int32_t
sampler
{
-
1
};
Target
target
{};
nlohmann
::
json
extensionsAndExtras
{};
};
struct
Sampler
{
enum
class
Type
{
Linear
,
Step
,
CubicSpline
};
int32_t
input
{
-
1
};
int32_t
output
{
-
1
};
Type
interpolation
{
Sampler
::
Type
::
Linear
};
nlohmann
::
json
extensionsAndExtras
{};
};
std
::
string
name
{};
std
::
vector
<
Channel
>
channels
{};
std
::
vector
<
Sampler
>
samplers
{};
nlohmann
::
json
extensionsAndExtras
{};
};
struct
Asset
:
NeverEmpty
{
std
::
string
copyright
{};
std
::
string
generator
{};
std
::
string
minVersion
{};
std
::
string
version
{
"2.0"
};
nlohmann
::
json
extensionsAndExtras
{};
};
struct
Buffer
{
uint32_t
byteLength
{};
std
::
string
name
;
std
::
string
uri
;
nlohmann
::
json
extensionsAndExtras
{};
std
::
vector
<
uint8_t
>
data
{};
bool
IsEmbeddedResource
()
const
noexcept
{
return
uri
.
find
(
detail
::
MimetypeApplicationOctet
)
==
0
;
}
void
SetEmbeddedResource
()
{
uri
=
std
::
string
(
detail
::
MimetypeApplicationOctet
).
append
(
","
).
append
(
base64
::
Encode
(
data
));
}
};
struct
BufferView
{
enum
class
TargetType
:
uint16_t
{
None
=
0
,
ArrayBuffer
=
34962
,
ElementArrayBuffer
=
34963
};
std
::
string
name
;
int32_t
buffer
{
-
1
};
uint32_t
byteOffset
{};
uint32_t
byteLength
{};
uint32_t
byteStride
{};
TargetType
target
{
TargetType
::
None
};
nlohmann
::
json
extensionsAndExtras
{};
};
struct
Camera
{
enum
class
Type
{
None
,
Orthographic
,
Perspective
};
struct
Orthographic
:
NeverEmpty
{
float
xmag
{
defaults
::
FloatSentinel
};
float
ymag
{
defaults
::
FloatSentinel
};
float
zfar
{
-
defaults
::
FloatSentinel
};
float
znear
{
-
defaults
::
FloatSentinel
};
nlohmann
::
json
extensionsAndExtras
{};
};
struct
Perspective
:
NeverEmpty
{
float
aspectRatio
{};
float
yfov
{};
float
zfar
{};
float
znear
{};
nlohmann
::
json
extensionsAndExtras
{};
};
std
::
string
name
{};
Type
type
{
Type
::
None
};
Orthographic
orthographic
;
Perspective
perspective
;
nlohmann
::
json
extensionsAndExtras
{};
};
struct
Image
{
int32_t
bufferView
{};
std
::
string
name
;
std
::
string
uri
;
std
::
string
mimeType
;
nlohmann
::
json
extensionsAndExtras
{};
bool
IsEmbeddedResource
()
const
noexcept
{
return
uri
.
find
(
detail
::
MimetypeImagePNG
)
==
0
||
uri
.
find
(
detail
::
MimetypeImageJPG
)
==
0
;
}
void
MaterializeData
(
std
::
vector
<
uint8_t
>
&
data
)
const
{
char
const
*
const
mimetype
=
uri
.
find
(
detail
::
MimetypeImagePNG
)
==
0
?
detail
::
MimetypeImagePNG
:
detail
::
MimetypeImageJPG
;
const
std
::
size_t
startPos
=
std
::
char_traits
<
char
>::
length
(
mimetype
)
+
1
;
const
std
::
size_t
base64Length
=
uri
.
length
()
-
startPos
;
#if defined(FX_GLTF_HAS_CPP_17)
const
bool
success
=
base64
::
TryDecode
({
&
uri
[
startPos
],
base64Length
},
data
);
#else
const
bool
success
=
base64
::
TryDecode
(
uri
.
substr
(
startPos
),
data
);
#endif
if
(
!
success
)
{
throw
invalid_gltf_document
(
"Invalid buffer.uri value"
,
"malformed base64"
);
}
}
};
struct
Material
{
enum
class
AlphaMode
:
uint8_t
{
Opaque
,
Mask
,
Blend
};
struct
Texture
{
int32_t
index
{
-
1
};
int32_t
texCoord
{};
nlohmann
::
json
extensionsAndExtras
{};
bool
empty
()
const
noexcept
{
return
index
==
-
1
;
}
};
struct
NormalTexture
:
Texture
{
float
scale
{
defaults
::
IdentityScalar
};
};
struct
OcclusionTexture
:
Texture
{
float
strength
{
defaults
::
IdentityScalar
};
};
struct
PBRMetallicRoughness
{
std
::
array
<
float
,
4
>
baseColorFactor
=
{
defaults
::
IdentityVec4
};
Texture
baseColorTexture
;
float
roughnessFactor
{
defaults
::
IdentityScalar
};
float
metallicFactor
{
defaults
::
IdentityScalar
};
Texture
metallicRoughnessTexture
;
nlohmann
::
json
extensionsAndExtras
{};
bool
empty
()
const
{
return
baseColorTexture
.
empty
()
&&
metallicRoughnessTexture
.
empty
()
&&
metallicFactor
==
1.0
f
&&
roughnessFactor
==
1.0
f
&&
baseColorFactor
==
defaults
::
IdentityVec4
;
}
};
float
alphaCutoff
{
defaults
::
MaterialAlphaCutoff
};
AlphaMode
alphaMode
{
AlphaMode
::
Opaque
};
bool
doubleSided
{
defaults
::
MaterialDoubleSided
};
NormalTexture
normalTexture
;
OcclusionTexture
occlusionTexture
;
PBRMetallicRoughness
pbrMetallicRoughness
;
Texture
emissiveTexture
;
std
::
array
<
float
,
3
>
emissiveFactor
=
{
defaults
::
NullVec3
};
std
::
string
name
;
nlohmann
::
json
extensionsAndExtras
{};
};
struct
Primitive
{
enum
class
Mode
:
uint8_t
{
Points
=
0
,
Lines
=
1
,
LineLoop
=
2
,
LineStrip
=
3
,
Triangles
=
4
,
TriangleStrip
=
5
,
TriangleFan
=
6
};
int32_t
indices
{
-
1
};
int32_t
material
{
-
1
};
Mode
mode
{
Mode
::
Triangles
};
Attributes
attributes
{};
std
::
vector
<
Attributes
>
targets
{};
nlohmann
::
json
extensionsAndExtras
{};
};
struct
Mesh
{
std
::
string
name
;
std
::
vector
<
float
>
weights
{};
std
::
vector
<
Primitive
>
primitives
{};
nlohmann
::
json
extensionsAndExtras
{};
};
struct
Node
{
std
::
string
name
;
int32_t
camera
{
-
1
};
int32_t
mesh
{
-
1
};
int32_t
skin
{
-
1
};
std
::
array
<
float
,
16
>
matrix
{
defaults
::
IdentityMatrix
};
std
::
array
<
float
,
4
>
rotation
{
defaults
::
IdentityRotation
};
std
::
array
<
float
,
3
>
scale
{
defaults
::
IdentityVec3
};
std
::
array
<
float
,
3
>
translation
{
defaults
::
NullVec3
};
std
::
vector
<
int32_t
>
children
{};
std
::
vector
<
float
>
weights
{};
nlohmann
::
json
extensionsAndExtras
{};
};
struct
Sampler
{
enum
class
MagFilter
:
uint16_t
{
None
,
Nearest
=
9728
,
Linear
=
9729
};
enum
class
MinFilter
:
uint16_t
{
None
,
Nearest
=
9728
,
Linear
=
9729
,
NearestMipMapNearest
=
9984
,
LinearMipMapNearest
=
9985
,
NearestMipMapLinear
=
9986
,
LinearMipMapLinear
=
9987
};
enum
class
WrappingMode
:
uint16_t
{
ClampToEdge
=
33071
,
MirroredRepeat
=
33648
,
Repeat
=
10497
};
std
::
string
name
;
MagFilter
magFilter
{
MagFilter
::
None
};
MinFilter
minFilter
{
MinFilter
::
None
};
WrappingMode
wrapS
{
WrappingMode
::
Repeat
};
WrappingMode
wrapT
{
WrappingMode
::
Repeat
};
nlohmann
::
json
extensionsAndExtras
{};
bool
empty
()
const
noexcept
{
return
name
.
empty
()
&&
magFilter
==
MagFilter
::
None
&&
minFilter
==
MinFilter
::
None
&&
wrapS
==
WrappingMode
::
Repeat
&&
wrapT
==
WrappingMode
::
Repeat
&&
extensionsAndExtras
.
empty
();
}
};
struct
Scene
{
std
::
string
name
;
std
::
vector
<
uint32_t
>
nodes
{};
nlohmann
::
json
extensionsAndExtras
{};
};
struct
Skin
{
int32_t
inverseBindMatrices
{
-
1
};
int32_t
skeleton
{
-
1
};
std
::
string
name
;
std
::
vector
<
uint32_t
>
joints
{};
nlohmann
::
json
extensionsAndExtras
{};
};
struct
Texture
{
std
::
string
name
;
int32_t
sampler
{
-
1
};
int32_t
source
{
-
1
};
nlohmann
::
json
extensionsAndExtras
{};
};
struct
Document
{
Asset
asset
;
std
::
vector
<
Accessor
>
accessors
{};
std
::
vector
<
Animation
>
animations
{};
std
::
vector
<
Buffer
>
buffers
{};
std
::
vector
<
BufferView
>
bufferViews
{};
std
::
vector
<
Camera
>
cameras
{};
std
::
vector
<
Image
>
images
{};
std
::
vector
<
Material
>
materials
{};
std
::
vector
<
Mesh
>
meshes
{};
std
::
vector
<
Node
>
nodes
{};
std
::
vector
<
Sampler
>
samplers
{};
std
::
vector
<
Scene
>
scenes
{};
std
::
vector
<
Skin
>
skins
{};
std
::
vector
<
Texture
>
textures
{};
int32_t
scene
{
-
1
};
std
::
vector
<
std
::
string
>
extensionsUsed
{};
std
::
vector
<
std
::
string
>
extensionsRequired
{};
nlohmann
::
json
extensionsAndExtras
{};
};
struct
ReadQuotas
{
uint32_t
MaxBufferCount
{
detail
::
DefaultMaxBufferCount
};
uint32_t
MaxFileSize
{
detail
::
DefaultMaxMemoryAllocation
};
uint32_t
MaxBufferByteLength
{
detail
::
DefaultMaxMemoryAllocation
};
};
namespace
detail
{
struct
DataContext
{
std
::
string
bufferRootPath
{};
ReadQuotas
readQuotas
;
std
::
vector
<
uint8_t
>
*
binaryData
{};
std
::
size_t
binaryOffset
{};
};
inline
std
::
size_t
GetFileSize
(
std
::
ifstream
&
file
)
{
file
.
seekg
(
0
,
file
.
end
);
const
std
::
streampos
fileSize
=
file
.
tellg
();
file
.
seekg
(
0
,
file
.
beg
);
if
(
fileSize
<
0
)
{
throw
std
::
system_error
(
std
::
make_error_code
(
std
::
errc
::
io_error
));
}
return
static_cast
<
std
::
size_t
>
(
fileSize
);
}
inline
void
MaterializeData
(
Buffer
&
buffer
)
{
const
std
::
size_t
startPos
=
std
::
char_traits
<
char
>::
length
(
detail
::
MimetypeApplicationOctet
)
+
1
;
const
std
::
size_t
base64Length
=
buffer
.
uri
.
length
()
-
startPos
;
const
std
::
size_t
decodedEstimate
=
base64Length
/
4
*
3
;
if
((
decodedEstimate
-
2
)
>
buffer
.
byteLength
)
// we need to give room for padding...
{
throw
invalid_gltf_document
(
"Invalid buffer.uri value"
,
"malformed base64"
);
}
#if defined(FX_GLTF_HAS_CPP_17)
const
bool
success
=
base64
::
TryDecode
({
&
buffer
.
uri
[
startPos
],
base64Length
},
buffer
.
data
);
#else
const
bool
success
=
base64
::
TryDecode
(
buffer
.
uri
.
substr
(
startPos
),
buffer
.
data
);
#endif
if
(
!
success
)
{
throw
invalid_gltf_document
(
"Invalid buffer.uri value"
,
"malformed base64"
);
}
}
inline
Document
Create
(
nlohmann
::
json
const
&
json
,
DataContext
const
&
dataContext
)
{
Document
document
=
json
;
if
(
document
.
buffers
.
size
()
>
dataContext
.
readQuotas
.
MaxBufferCount
)
{
throw
invalid_gltf_document
(
"Quota exceeded : number of buffers > MaxBufferCount"
);
}
for
(
auto
&
buffer
:
document
.
buffers
)
{
if
(
buffer
.
byteLength
==
0
)
{
throw
invalid_gltf_document
(
"Invalid buffer.byteLength value : 0"
);
}
if
(
buffer
.
byteLength
>
dataContext
.
readQuotas
.
MaxBufferByteLength
)
{
throw
invalid_gltf_document
(
"Quota exceeded : buffer.byteLength > MaxBufferByteLength"
);
}
if
(
!
buffer
.
uri
.
empty
())
{
if
(
buffer
.
IsEmbeddedResource
())
{
detail
::
MaterializeData
(
buffer
);
}
else
{
std
::
ifstream
fileData
(
detail
::
CreateBufferUriPath
(
dataContext
.
bufferRootPath
,
buffer
.
uri
),
std
::
ios
::
binary
);
if
(
!
fileData
.
good
())
{
throw
invalid_gltf_document
(
"Invalid buffer.uri value"
,
buffer
.
uri
);
}
buffer
.
data
.
resize
(
buffer
.
byteLength
);
fileData
.
read
(
reinterpret_cast
<
char
*>
(
&
buffer
.
data
[
0
]),
buffer
.
byteLength
);
}
}
else
if
(
dataContext
.
binaryData
!=
nullptr
)
{
detail
::
ChunkHeader
header
;
std
::
vector
<
uint8_t
>
&
binary
=
*
dataContext
.
binaryData
;
std
::
memcpy
(
&
header
,
&
binary
[
dataContext
.
binaryOffset
],
detail
::
ChunkHeaderSize
);
if
(
header
.
chunkType
!=
detail
::
GLBChunkBIN
||
header
.
chunkLength
<
buffer
.
byteLength
)
{
throw
invalid_gltf_document
(
"Invalid GLB buffer data"
);
}
buffer
.
data
.
resize
(
buffer
.
byteLength
);
std
::
memcpy
(
&
buffer
.
data
[
0
],
&
binary
[
dataContext
.
binaryOffset
+
detail
::
ChunkHeaderSize
],
buffer
.
byteLength
);
}
}
return
document
;
}
inline
void
ValidateBuffers
(
Document
const
&
document
,
bool
useBinaryFormat
)
{
if
(
document
.
buffers
.
empty
())
{
throw
invalid_gltf_document
(
"Invalid glTF document. A document must have at least 1 buffer."
);
}
bool
foundBinaryBuffer
=
false
;
for
(
std
::
size_t
bufferIndex
=
0
;
bufferIndex
<
document
.
buffers
.
size
();
bufferIndex
++
)
{
Buffer
const
&
buffer
=
document
.
buffers
[
bufferIndex
];
if
(
buffer
.
byteLength
==
0
)
{
throw
invalid_gltf_document
(
"Invalid buffer.byteLength value : 0"
);
}
if
(
buffer
.
byteLength
!=
buffer
.
data
.
size
())
{
throw
invalid_gltf_document
(
"Invalid buffer.byteLength value : does not match buffer.data size"
);
}
if
(
buffer
.
uri
.
empty
())
{
foundBinaryBuffer
=
true
;
if
(
bufferIndex
!=
0
)
{
throw
invalid_gltf_document
(
"Invalid glTF document. Only 1 buffer, the very first, is allowed to have an empty buffer.uri field."
);
}
}
}
if
(
useBinaryFormat
&&
!
foundBinaryBuffer
)
{
throw
invalid_gltf_document
(
"Invalid glTF document. No buffer found which can meet the criteria for saving to a .glb file."
);
}
}
inline
void
Save
(
Document
const
&
document
,
std
::
string
documentFilePath
,
bool
useBinaryFormat
)
{
nlohmann
::
json
json
=
documentFilePath
;
std
::
size_t
externalBufferIndex
=
0
;
if
(
useBinaryFormat
)
{
detail
::
GLBHeader
header
{
detail
::
GLBHeaderMagic
,
2
,
0
,
{
0
,
detail
::
GLBChunkJSON
}
};
detail
::
ChunkHeader
binHeader
{
0
,
detail
::
GLBChunkBIN
};
std
::
string
jsonText
=
json
.
dump
();
Buffer
const
&
binBuffer
=
document
.
buffers
.
front
();
const
uint32_t
binPaddedLength
=
((
binBuffer
.
byteLength
+
3
)
&
(
~
3u
));
const
uint32_t
binPadding
=
binPaddedLength
-
binBuffer
.
byteLength
;
binHeader
.
chunkLength
=
binPaddedLength
;
header
.
jsonHeader
.
chunkLength
=
((
jsonText
.
length
()
+
3
)
&
(
~
3u
));
const
uint32_t
headerPadding
=
static_cast
<
uint32_t
>
(
header
.
jsonHeader
.
chunkLength
-
jsonText
.
length
());
header
.
length
=
detail
::
HeaderSize
+
header
.
jsonHeader
.
chunkLength
+
detail
::
ChunkHeaderSize
+
binHeader
.
chunkLength
;
std
::
ofstream
fileData
(
documentFilePath
,
std
::
ios
::
binary
);
if
(
!
fileData
.
good
())
{
throw
std
::
system_error
(
std
::
make_error_code
(
std
::
errc
::
io_error
));
}
const
char
spaces
[
3
]
=
{
' '
,
' '
,
' '
};
const
char
nulls
[
3
]
=
{
0
,
0
,
0
};
fileData
.
write
(
reinterpret_cast
<
char
*>
(
&
header
),
detail
::
HeaderSize
);
fileData
.
write
(
jsonText
.
c_str
(),
jsonText
.
length
());
fileData
.
write
(
&
spaces
[
0
],
headerPadding
);
fileData
.
write
(
reinterpret_cast
<
char
*>
(
&
binHeader
),
detail
::
ChunkHeaderSize
);
fileData
.
write
(
reinterpret_cast
<
char
const
*>
(
&
binBuffer
.
data
[
0
]),
binBuffer
.
byteLength
);
fileData
.
write
(
&
nulls
[
0
],
binPadding
);
externalBufferIndex
=
1
;
}
else
{
std
::
ofstream
file
(
documentFilePath
);
if
(
!
file
.
is_open
())
{
throw
std
::
system_error
(
std
::
make_error_code
(
std
::
errc
::
io_error
));
}
file
<<
json
.
dump
(
2
);
}
// The glTF 2.0 spec allows a document to have more than 1 buffer. However, only the first one will be included in the .glb
// All others must be considered as External/Embedded resources. Process them if necessary...
std
::
string
documentRootPath
=
detail
::
GetDocumentRootPath
(
documentFilePath
);
for
(;
externalBufferIndex
<
document
.
buffers
.
size
();
externalBufferIndex
++
)
{
Buffer
const
&
buffer
=
document
.
buffers
[
externalBufferIndex
];
if
(
!
buffer
.
IsEmbeddedResource
())
{
std
::
ofstream
fileData
(
detail
::
CreateBufferUriPath
(
documentRootPath
,
buffer
.
uri
),
std
::
ios
::
binary
);
if
(
!
fileData
.
good
())
{
throw
invalid_gltf_document
(
"Invalid buffer.uri value"
,
buffer
.
uri
);
}
fileData
.
write
(
reinterpret_cast
<
char
const
*>
(
&
buffer
.
data
[
0
]),
buffer
.
byteLength
);
}
}
}
}
// namespace detail
inline
void
from_json
(
nlohmann
::
json
const
&
json
,
Accessor
::
Type
&
accessorType
)
{
std
::
string
type
=
json
.
get
<
std
::
string
>
();
if
(
type
==
"SCALAR"
)
{
accessorType
=
Accessor
::
Type
::
Scalar
;
}
else
if
(
type
==
"VEC2"
)
{
accessorType
=
Accessor
::
Type
::
Vec2
;
}
else
if
(
type
==
"VEC3"
)
{
accessorType
=
Accessor
::
Type
::
Vec3
;
}
else
if
(
type
==
"VEC4"
)
{
accessorType
=
Accessor
::
Type
::
Vec4
;
}
else
if
(
type
==
"MAT2"
)
{
accessorType
=
Accessor
::
Type
::
Mat2
;
}
else
if
(
type
==
"MAT3"
)
{
accessorType
=
Accessor
::
Type
::
Mat3
;
}
else
if
(
type
==
"MAT4"
)
{
accessorType
=
Accessor
::
Type
::
Mat4
;
}
else
{
throw
invalid_gltf_document
(
"Unknown accessor.type value"
,
type
);
}
}
inline
void
from_json
(
nlohmann
::
json
const
&
json
,
Accessor
::
Sparse
::
Values
&
values
)
{
detail
::
ReadRequiredField
(
"bufferView"
,
json
,
values
.
bufferView
);
detail
::
ReadOptionalField
(
"byteOffset"
,
json
,
values
.
byteOffset
);
detail
::
ReadExtensionsAndExtras
(
json
,
values
.
extensionsAndExtras
);
}
inline
void
from_json
(
nlohmann
::
json
const
&
json
,
Accessor
::
Sparse
::
Indices
&
indices
)
{
detail
::
ReadRequiredField
(
"bufferView"
,
json
,
indices
.
bufferView
);
detail
::
ReadRequiredField
(
"componentType"
,
json
,
indices
.
componentType
);
detail
::
ReadOptionalField
(
"byteOffset"
,
json
,
indices
.
byteOffset
);
detail
::
ReadExtensionsAndExtras
(
json
,
indices
.
extensionsAndExtras
);
}
inline
void
from_json
(
nlohmann
::
json
const
&
json
,
Accessor
::
Sparse
&
sparse
)
{
detail
::
ReadRequiredField
(
"count"
,
json
,
sparse
.
count
);
detail
::
ReadRequiredField
(
"indices"
,
json
,
sparse
.
indices
);
detail
::
ReadRequiredField
(
"values"
,
json
,
sparse
.
values
);
detail
::
ReadExtensionsAndExtras
(
json
,
sparse
.
extensionsAndExtras
);
}
inline
void
from_json
(
nlohmann
::
json
const
&
json
,
Accessor
&
accessor
)
{
detail
::
ReadRequiredField
(
"componentType"
,
json
,
accessor
.
componentType
);
detail
::
ReadRequiredField
(
"count"
,
json
,
accessor
.
count
);
detail
::
ReadRequiredField
(
"type"
,
json
,
accessor
.
type
);
detail
::
ReadOptionalField
(
"bufferView"
,
json
,
accessor
.
bufferView
);
detail
::
ReadOptionalField
(
"byteOffset"
,
json
,
accessor
.
byteOffset
);
detail
::
ReadOptionalField
(
"max"
,
json
,
accessor
.
max
);
detail
::
ReadOptionalField
(
"min"
,
json
,
accessor
.
min
);
detail
::
ReadOptionalField
(
"name"
,
json
,
accessor
.
name
);
detail
::
ReadOptionalField
(
"normalized"
,
json
,
accessor
.
normalized
);
detail
::
ReadOptionalField
(
"sparse"
,
json
,
accessor
.
sparse
);
detail
::
ReadExtensionsAndExtras
(
json
,
accessor
.
extensionsAndExtras
);
}
inline
void
from_json
(
nlohmann
::
json
const
&
json
,
Animation
::
Channel
::
Target
&
animationChannelTarget
)
{
detail
::
ReadRequiredField
(
"path"
,
json
,
animationChannelTarget
.
path
);
detail
::
ReadOptionalField
(
"node"
,
json
,
animationChannelTarget
.
node
);
detail
::
ReadExtensionsAndExtras
(
json
,
animationChannelTarget
.
extensionsAndExtras
);
}
inline
void
from_json
(
nlohmann
::
json
const
&
json
,
Animation
::
Channel
&
animationChannel
)
{
detail
::
ReadRequiredField
(
"sampler"
,
json
,
animationChannel
.
sampler
);
detail
::
ReadRequiredField
(
"target"
,
json
,
animationChannel
.
target
);
detail
::
ReadExtensionsAndExtras
(
json
,
animationChannel
.
extensionsAndExtras
);
}
inline
void
from_json
(
nlohmann
::
json
const
&
json
,
Animation
::
Sampler
::
Type
&
animationSamplerType
)
{
std
::
string
type
=
json
.
get
<
std
::
string
>
();
if
(
type
==
"LINEAR"
)
{
animationSamplerType
=
Animation
::
Sampler
::
Type
::
Linear
;
}
else
if
(
type
==
"STEP"
)
{
animationSamplerType
=
Animation
::
Sampler
::
Type
::
Step
;
}
else
if
(
type
==
"CUBICSPLINE"
)
{
animationSamplerType
=
Animation
::
Sampler
::
Type
::
CubicSpline
;
}
else
{
throw
invalid_gltf_document
(
"Unknown animation.sampler.interpolation value"
,
type
);
}
}
inline
void
from_json
(
nlohmann
::
json
const
&
json
,
Animation
::
Sampler
&
animationSampler
)
{
detail
::
ReadRequiredField
(
"input"
,
json
,
animationSampler
.
input
);
detail
::
ReadRequiredField
(
"output"
,
json
,
animationSampler
.
output
);
detail
::
ReadOptionalField
(
"interpolation"
,
json
,
animationSampler
.
interpolation
);
detail
::
ReadExtensionsAndExtras
(
json
,
animationSampler
.
extensionsAndExtras
);
}
inline
void
from_json
(
nlohmann
::
json
const
&
json
,
Animation
&
animation
)
{
detail
::
ReadRequiredField
(
"channels"
,
json
,
animation
.
channels
);
detail
::
ReadRequiredField
(
"samplers"
,
json
,
animation
.
samplers
);
detail
::
ReadOptionalField
(
"name"
,
json
,
animation
.
name
);
detail
::
ReadExtensionsAndExtras
(
json
,
animation
.
extensionsAndExtras
);
}
inline
void
from_json
(
nlohmann
::
json
const
&
json
,
Asset
&
asset
)
{
detail
::
ReadRequiredField
(
"version"
,
json
,
asset
.
version
);
detail
::
ReadOptionalField
(
"copyright"
,
json
,
asset
.
copyright
);
detail
::
ReadOptionalField
(
"generator"
,
json
,
asset
.
generator
);
detail
::
ReadOptionalField
(
"minVersion"
,
json
,
asset
.
minVersion
);
detail
::
ReadExtensionsAndExtras
(
json
,
asset
.
extensionsAndExtras
);
}
inline
void
from_json
(
nlohmann
::
json
const
&
json
,
Buffer
&
buffer
)
{
detail
::
ReadRequiredField
(
"byteLength"
,
json
,
buffer
.
byteLength
);
detail
::
ReadOptionalField
(
"name"
,
json
,
buffer
.
name
);
detail
::
ReadOptionalField
(
"uri"
,
json
,
buffer
.
uri
);
detail
::
ReadExtensionsAndExtras
(
json
,
buffer
.
extensionsAndExtras
);
}
inline
void
from_json
(
nlohmann
::
json
const
&
json
,
BufferView
&
bufferView
)
{
detail
::
ReadRequiredField
(
"buffer"
,
json
,
bufferView
.
buffer
);
detail
::
ReadRequiredField
(
"byteLength"
,
json
,
bufferView
.
byteLength
);
detail
::
ReadOptionalField
(
"byteOffset"
,
json
,
bufferView
.
byteOffset
);
detail
::
ReadOptionalField
(
"byteStride"
,
json
,
bufferView
.
byteStride
);
detail
::
ReadOptionalField
(
"name"
,
json
,
bufferView
.
name
);
detail
::
ReadOptionalField
(
"target"
,
json
,
bufferView
.
target
);
detail
::
ReadExtensionsAndExtras
(
json
,
bufferView
.
extensionsAndExtras
);
}
inline
void
from_json
(
nlohmann
::
json
const
&
json
,
Camera
::
Type
&
cameraType
)
{
std
::
string
type
=
json
.
get
<
std
::
string
>
();
if
(
type
==
"orthographic"
)
{
cameraType
=
Camera
::
Type
::
Orthographic
;
}
else
if
(
type
==
"perspective"
)
{
cameraType
=
Camera
::
Type
::
Perspective
;
}
else
{
throw
invalid_gltf_document
(
"Unknown camera.type value"
,
type
);
}
}
inline
void
from_json
(
nlohmann
::
json
const
&
json
,
Camera
::
Orthographic
&
camera
)
{
detail
::
ReadRequiredField
(
"xmag"
,
json
,
camera
.
xmag
);
detail
::
ReadRequiredField
(
"ymag"
,
json
,
camera
.
ymag
);
detail
::
ReadRequiredField
(
"zfar"
,
json
,
camera
.
zfar
);
detail
::
ReadRequiredField
(
"znear"
,
json
,
camera
.
znear
);
detail
::
ReadExtensionsAndExtras
(
json
,
camera
.
extensionsAndExtras
);
}
inline
void
from_json
(
nlohmann
::
json
const
&
json
,
Camera
::
Perspective
&
camera
)
{
detail
::
ReadRequiredField
(
"yfov"
,
json
,
camera
.
yfov
);
detail
::
ReadRequiredField
(
"znear"
,
json
,
camera
.
znear
);
detail
::
ReadOptionalField
(
"aspectRatio"
,
json
,
camera
.
aspectRatio
);
detail
::
ReadOptionalField
(
"zfar"
,
json
,
camera
.
zfar
);
detail
::
ReadExtensionsAndExtras
(
json
,
camera
.
extensionsAndExtras
);
}
inline
void
from_json
(
nlohmann
::
json
const
&
json
,
Camera
&
camera
)
{
detail
::
ReadRequiredField
(
"type"
,
json
,
camera
.
type
);
detail
::
ReadOptionalField
(
"name"
,
json
,
camera
.
name
);
detail
::
ReadExtensionsAndExtras
(
json
,
camera
.
extensionsAndExtras
);
if
(
camera
.
type
==
Camera
::
Type
::
Perspective
)
{
detail
::
ReadRequiredField
(
"perspective"
,
json
,
camera
.
perspective
);
}
else
if
(
camera
.
type
==
Camera
::
Type
::
Orthographic
)
{
detail
::
ReadRequiredField
(
"orthographic"
,
json
,
camera
.
orthographic
);
}
}
inline
void
from_json
(
nlohmann
::
json
const
&
json
,
Image
&
image
)
{
detail
::
ReadOptionalField
(
"bufferView"
,
json
,
image
.
bufferView
);
detail
::
ReadOptionalField
(
"mimeType"
,
json
,
image
.
mimeType
);
detail
::
ReadOptionalField
(
"name"
,
json
,
image
.
name
);
detail
::
ReadOptionalField
(
"uri"
,
json
,
image
.
uri
);
detail
::
ReadExtensionsAndExtras
(
json
,
image
.
extensionsAndExtras
);
}
inline
void
from_json
(
nlohmann
::
json
const
&
json
,
Material
::
AlphaMode
&
materialAlphaMode
)
{
std
::
string
alphaMode
=
json
.
get
<
std
::
string
>
();
if
(
alphaMode
==
"OPAQUE"
)
{
materialAlphaMode
=
Material
::
AlphaMode
::
Opaque
;
}
else
if
(
alphaMode
==
"MASK"
)
{
materialAlphaMode
=
Material
::
AlphaMode
::
Mask
;
}
else
if
(
alphaMode
==
"BLEND"
)
{
materialAlphaMode
=
Material
::
AlphaMode
::
Blend
;
}
else
{
throw
invalid_gltf_document
(
"Unknown material.alphaMode value"
,
alphaMode
);
}
}
inline
void
from_json
(
nlohmann
::
json
const
&
json
,
Material
::
Texture
&
materialTexture
)
{
detail
::
ReadRequiredField
(
"index"
,
json
,
materialTexture
.
index
);
detail
::
ReadOptionalField
(
"texCoord"
,
json
,
materialTexture
.
texCoord
);
detail
::
ReadExtensionsAndExtras
(
json
,
materialTexture
.
extensionsAndExtras
);
}
inline
void
from_json
(
nlohmann
::
json
const
&
json
,
Material
::
NormalTexture
&
materialTexture
)
{
from_json
(
json
,
static_cast
<
Material
::
Texture
&>
(
materialTexture
));
detail
::
ReadOptionalField
(
"scale"
,
json
,
materialTexture
.
scale
);
detail
::
ReadExtensionsAndExtras
(
json
,
materialTexture
.
extensionsAndExtras
);
}
inline
void
from_json
(
nlohmann
::
json
const
&
json
,
Material
::
OcclusionTexture
&
materialTexture
)
{
from_json
(
json
,
static_cast
<
Material
::
Texture
&>
(
materialTexture
));
detail
::
ReadOptionalField
(
"strength"
,
json
,
materialTexture
.
strength
);
detail
::
ReadExtensionsAndExtras
(
json
,
materialTexture
.
extensionsAndExtras
);
}
inline
void
from_json
(
nlohmann
::
json
const
&
json
,
Material
::
PBRMetallicRoughness
&
pbrMetallicRoughness
)
{
detail
::
ReadOptionalField
(
"baseColorFactor"
,
json
,
pbrMetallicRoughness
.
baseColorFactor
);
detail
::
ReadOptionalField
(
"baseColorTexture"
,
json
,
pbrMetallicRoughness
.
baseColorTexture
);
detail
::
ReadOptionalField
(
"metallicFactor"
,
json
,
pbrMetallicRoughness
.
metallicFactor
);
detail
::
ReadOptionalField
(
"metallicRoughnessTexture"
,
json
,
pbrMetallicRoughness
.
metallicRoughnessTexture
);
detail
::
ReadOptionalField
(
"roughnessFactor"
,
json
,
pbrMetallicRoughness
.
roughnessFactor
);
detail
::
ReadExtensionsAndExtras
(
json
,
pbrMetallicRoughness
.
extensionsAndExtras
);
}
inline
void
from_json
(
nlohmann
::
json
const
&
json
,
Material
&
material
)
{
detail
::
ReadOptionalField
(
"alphaMode"
,
json
,
material
.
alphaMode
);
detail
::
ReadOptionalField
(
"alphaCutoff"
,
json
,
material
.
alphaCutoff
);
detail
::
ReadOptionalField
(
"doubleSided"
,
json
,
material
.
doubleSided
);
detail
::
ReadOptionalField
(
"emissiveFactor"
,
json
,
material
.
emissiveFactor
);
detail
::
ReadOptionalField
(
"emissiveTexture"
,
json
,
material
.
emissiveTexture
);
detail
::
ReadOptionalField
(
"name"
,
json
,
material
.
name
);
detail
::
ReadOptionalField
(
"normalTexture"
,
json
,
material
.
normalTexture
);
detail
::
ReadOptionalField
(
"occlusionTexture"
,
json
,
material
.
occlusionTexture
);
detail
::
ReadOptionalField
(
"pbrMetallicRoughness"
,
json
,
material
.
pbrMetallicRoughness
);
detail
::
ReadExtensionsAndExtras
(
json
,
material
.
extensionsAndExtras
);
}
inline
void
from_json
(
nlohmann
::
json
const
&
json
,
Mesh
&
mesh
)
{
detail
::
ReadRequiredField
(
"primitives"
,
json
,
mesh
.
primitives
);
detail
::
ReadOptionalField
(
"name"
,
json
,
mesh
.
name
);
detail
::
ReadOptionalField
(
"weights"
,
json
,
mesh
.
weights
);
detail
::
ReadExtensionsAndExtras
(
json
,
mesh
.
extensionsAndExtras
);
}
inline
void
from_json
(
nlohmann
::
json
const
&
json
,
Node
&
node
)
{
detail
::
ReadOptionalField
(
"camera"
,
json
,
node
.
camera
);
detail
::
ReadOptionalField
(
"children"
,
json
,
node
.
children
);
detail
::
ReadOptionalField
(
"matrix"
,
json
,
node
.
matrix
);
detail
::
ReadOptionalField
(
"mesh"
,
json
,
node
.
mesh
);
detail
::
ReadOptionalField
(
"name"
,
json
,
node
.
name
);
detail
::
ReadOptionalField
(
"rotation"
,
json
,
node
.
rotation
);
detail
::
ReadOptionalField
(
"scale"
,
json
,
node
.
scale
);
detail
::
ReadOptionalField
(
"skin"
,
json
,
node
.
skin
);
detail
::
ReadOptionalField
(
"translation"
,
json
,
node
.
translation
);
detail
::
ReadExtensionsAndExtras
(
json
,
node
.
extensionsAndExtras
);
}
inline
void
from_json
(
nlohmann
::
json
const
&
json
,
Primitive
&
primitive
)
{
detail
::
ReadRequiredField
(
"attributes"
,
json
,
primitive
.
attributes
);
detail
::
ReadOptionalField
(
"indices"
,
json
,
primitive
.
indices
);
detail
::
ReadOptionalField
(
"material"
,
json
,
primitive
.
material
);
detail
::
ReadOptionalField
(
"mode"
,
json
,
primitive
.
mode
);
detail
::
ReadOptionalField
(
"targets"
,
json
,
primitive
.
targets
);
detail
::
ReadExtensionsAndExtras
(
json
,
primitive
.
extensionsAndExtras
);
}
inline
void
from_json
(
nlohmann
::
json
const
&
json
,
Sampler
&
sampler
)
{
detail
::
ReadOptionalField
(
"magFilter"
,
json
,
sampler
.
magFilter
);
detail
::
ReadOptionalField
(
"minFilter"
,
json
,
sampler
.
minFilter
);
detail
::
ReadOptionalField
(
"name"
,
json
,
sampler
.
name
);
detail
::
ReadOptionalField
(
"wrapS"
,
json
,
sampler
.
wrapS
);
detail
::
ReadOptionalField
(
"wrapT"
,
json
,
sampler
.
wrapT
);
detail
::
ReadExtensionsAndExtras
(
json
,
sampler
.
extensionsAndExtras
);
}
inline
void
from_json
(
nlohmann
::
json
const
&
json
,
Scene
&
scene
)
{
detail
::
ReadOptionalField
(
"name"
,
json
,
scene
.
name
);
detail
::
ReadOptionalField
(
"nodes"
,
json
,
scene
.
nodes
);
detail
::
ReadExtensionsAndExtras
(
json
,
scene
.
extensionsAndExtras
);
}
inline
void
from_json
(
nlohmann
::
json
const
&
json
,
Skin
&
skin
)
{
detail
::
ReadRequiredField
(
"joints"
,
json
,
skin
.
joints
);
detail
::
ReadOptionalField
(
"inverseBindMatrices"
,
json
,
skin
.
inverseBindMatrices
);
detail
::
ReadOptionalField
(
"name"
,
json
,
skin
.
name
);
detail
::
ReadOptionalField
(
"skeleton"
,
json
,
skin
.
skeleton
);
detail
::
ReadExtensionsAndExtras
(
json
,
skin
.
extensionsAndExtras
);
}
inline
void
from_json
(
nlohmann
::
json
const
&
json
,
Texture
&
texture
)
{
detail
::
ReadOptionalField
(
"name"
,
json
,
texture
.
name
);
detail
::
ReadOptionalField
(
"sampler"
,
json
,
texture
.
sampler
);
detail
::
ReadOptionalField
(
"source"
,
json
,
texture
.
source
);
detail
::
ReadExtensionsAndExtras
(
json
,
texture
.
extensionsAndExtras
);
}
inline
void
from_json
(
nlohmann
::
json
const
&
json
,
Document
&
document
)
{
detail
::
ReadRequiredField
(
"asset"
,
json
,
document
.
asset
);
detail
::
ReadOptionalField
(
"accessors"
,
json
,
document
.
accessors
);
detail
::
ReadOptionalField
(
"animations"
,
json
,
document
.
animations
);
detail
::
ReadOptionalField
(
"buffers"
,
json
,
document
.
buffers
);
detail
::
ReadOptionalField
(
"bufferViews"
,
json
,
document
.
bufferViews
);
detail
::
ReadOptionalField
(
"cameras"
,
json
,
document
.
cameras
);
detail
::
ReadOptionalField
(
"materials"
,
json
,
document
.
materials
);
detail
::
ReadOptionalField
(
"meshes"
,
json
,
document
.
meshes
);
detail
::
ReadOptionalField
(
"nodes"
,
json
,
document
.
nodes
);
detail
::
ReadOptionalField
(
"images"
,
json
,
document
.
images
);
detail
::
ReadOptionalField
(
"samplers"
,
json
,
document
.
samplers
);
detail
::
ReadOptionalField
(
"scene"
,
json
,
document
.
scene
);
detail
::
ReadOptionalField
(
"scenes"
,
json
,
document
.
scenes
);
detail
::
ReadOptionalField
(
"skins"
,
json
,
document
.
skins
);
detail
::
ReadOptionalField
(
"textures"
,
json
,
document
.
textures
);
detail
::
ReadOptionalField
(
"extensionsUsed"
,
json
,
document
.
extensionsUsed
);
detail
::
ReadOptionalField
(
"extensionsRequired"
,
json
,
document
.
extensionsRequired
);
detail
::
ReadExtensionsAndExtras
(
json
,
document
.
extensionsAndExtras
);
}
inline
void
to_json
(
nlohmann
::
json
&
json
,
Accessor
::
ComponentType
const
&
accessorComponentType
)
{
if
(
accessorComponentType
==
Accessor
::
ComponentType
::
None
)
{
throw
invalid_gltf_document
(
"Unknown accessor.componentType value"
);
}
json
=
static_cast
<
uint16_t
>
(
accessorComponentType
);
}
inline
void
to_json
(
nlohmann
::
json
&
json
,
Accessor
::
Type
const
&
accessorType
)
{
switch
(
accessorType
)
{
case
Accessor
::
Type
::
Scalar
:
json
=
"SCALAR"
;
break
;
case
Accessor
::
Type
::
Vec2
:
json
=
"VEC2"
;
break
;
case
Accessor
::
Type
::
Vec3
:
json
=
"VEC3"
;
break
;
case
Accessor
::
Type
::
Vec4
:
json
=
"VEC4"
;
break
;
case
Accessor
::
Type
::
Mat2
:
json
=
"MAT2"
;
break
;
case
Accessor
::
Type
::
Mat3
:
json
=
"MAT3"
;
break
;
case
Accessor
::
Type
::
Mat4
:
json
=
"MAT4"
;
break
;
default:
throw
invalid_gltf_document
(
"Unknown accessor.type value"
);
}
}
inline
void
to_json
(
nlohmann
::
json
&
json
,
Accessor
::
Sparse
::
Values
const
&
values
)
{
detail
::
WriteField
(
"bufferView"
,
json
,
values
.
bufferView
,
static_cast
<
uint32_t
>
(
-
1
));
detail
::
WriteField
(
"byteOffset"
,
json
,
values
.
byteOffset
,
{});
detail
::
WriteExtensions
(
json
,
values
.
extensionsAndExtras
);
}
inline
void
to_json
(
nlohmann
::
json
&
json
,
Accessor
::
Sparse
::
Indices
const
&
indices
)
{
detail
::
WriteField
(
"componentType"
,
json
,
indices
.
componentType
,
Accessor
::
ComponentType
::
None
);
detail
::
WriteField
(
"bufferView"
,
json
,
indices
.
bufferView
,
static_cast
<
uint32_t
>
(
-
1
));
detail
::
WriteField
(
"byteOffset"
,
json
,
indices
.
byteOffset
,
{});
detail
::
WriteExtensions
(
json
,
indices
.
extensionsAndExtras
);
}
inline
void
to_json
(
nlohmann
::
json
&
json
,
Accessor
::
Sparse
const
&
sparse
)
{
detail
::
WriteField
(
"count"
,
json
,
sparse
.
count
,
-
1
);
detail
::
WriteField
(
"indices"
,
json
,
sparse
.
indices
);
detail
::
WriteField
(
"values"
,
json
,
sparse
.
values
);
detail
::
WriteExtensions
(
json
,
sparse
.
extensionsAndExtras
);
}
inline
void
to_json
(
nlohmann
::
json
&
json
,
Accessor
const
&
accessor
)
{
detail
::
WriteField
(
"bufferView"
,
json
,
accessor
.
bufferView
,
-
1
);
detail
::
WriteField
(
"byteOffset"
,
json
,
accessor
.
byteOffset
,
{});
detail
::
WriteField
(
"componentType"
,
json
,
accessor
.
componentType
,
Accessor
::
ComponentType
::
None
);
detail
::
WriteField
(
"count"
,
json
,
accessor
.
count
,
{});
detail
::
WriteField
(
"max"
,
json
,
accessor
.
max
);
detail
::
WriteField
(
"min"
,
json
,
accessor
.
min
);
detail
::
WriteField
(
"name"
,
json
,
accessor
.
name
);
detail
::
WriteField
(
"normalized"
,
json
,
accessor
.
normalized
,
false
);
detail
::
WriteField
(
"sparse"
,
json
,
accessor
.
sparse
);
detail
::
WriteField
(
"type"
,
json
,
accessor
.
type
,
Accessor
::
Type
::
None
);
detail
::
WriteExtensions
(
json
,
accessor
.
extensionsAndExtras
);
}
inline
void
to_json
(
nlohmann
::
json
&
json
,
Animation
::
Channel
::
Target
const
&
animationChannelTarget
)
{
detail
::
WriteField
(
"node"
,
json
,
animationChannelTarget
.
node
,
-
1
);
detail
::
WriteField
(
"path"
,
json
,
animationChannelTarget
.
path
);
detail
::
WriteExtensions
(
json
,
animationChannelTarget
.
extensionsAndExtras
);
}
inline
void
to_json
(
nlohmann
::
json
&
json
,
Animation
::
Channel
const
&
animationChannel
)
{
detail
::
WriteField
(
"sampler"
,
json
,
animationChannel
.
sampler
,
-
1
);
detail
::
WriteField
(
"target"
,
json
,
animationChannel
.
target
);
detail
::
WriteExtensions
(
json
,
animationChannel
.
extensionsAndExtras
);
}
inline
void
to_json
(
nlohmann
::
json
&
json
,
Animation
::
Sampler
::
Type
const
&
animationSamplerType
)
{
switch
(
animationSamplerType
)
{
case
Animation
::
Sampler
::
Type
::
Linear
:
json
=
"LINEAR"
;
break
;
case
Animation
::
Sampler
::
Type
::
Step
:
json
=
"STEP"
;
break
;
case
Animation
::
Sampler
::
Type
::
CubicSpline
:
json
=
"CUBICSPLINE"
;
break
;
}
}
inline
void
to_json
(
nlohmann
::
json
&
json
,
Animation
::
Sampler
const
&
animationSampler
)
{
detail
::
WriteField
(
"input"
,
json
,
animationSampler
.
input
,
-
1
);
detail
::
WriteField
(
"interpolation"
,
json
,
animationSampler
.
interpolation
,
Animation
::
Sampler
::
Type
::
Linear
);
detail
::
WriteField
(
"output"
,
json
,
animationSampler
.
output
,
-
1
);
detail
::
WriteExtensions
(
json
,
animationSampler
.
extensionsAndExtras
);
}
inline
void
to_json
(
nlohmann
::
json
&
json
,
Animation
const
&
animation
)
{
detail
::
WriteField
(
"channels"
,
json
,
animation
.
channels
);
detail
::
WriteField
(
"name"
,
json
,
animation
.
name
);
detail
::
WriteField
(
"samplers"
,
json
,
animation
.
samplers
);
detail
::
WriteExtensions
(
json
,
animation
.
extensionsAndExtras
);
}
inline
void
to_json
(
nlohmann
::
json
&
json
,
Asset
const
&
asset
)
{
detail
::
WriteField
(
"copyright"
,
json
,
asset
.
copyright
);
detail
::
WriteField
(
"generator"
,
json
,
asset
.
generator
);
detail
::
WriteField
(
"minVersion"
,
json
,
asset
.
minVersion
);
detail
::
WriteField
(
"version"
,
json
,
asset
.
version
);
detail
::
WriteExtensions
(
json
,
asset
.
extensionsAndExtras
);
}
inline
void
to_json
(
nlohmann
::
json
&
json
,
Buffer
const
&
buffer
)
{
detail
::
WriteField
(
"byteLength"
,
json
,
buffer
.
byteLength
,
{});
detail
::
WriteField
(
"name"
,
json
,
buffer
.
name
);
detail
::
WriteField
(
"uri"
,
json
,
buffer
.
uri
);
detail
::
WriteExtensions
(
json
,
buffer
.
extensionsAndExtras
);
}
inline
void
to_json
(
nlohmann
::
json
&
json
,
BufferView
const
&
bufferView
)
{
detail
::
WriteField
(
"buffer"
,
json
,
bufferView
.
buffer
,
-
1
);
detail
::
WriteField
(
"byteLength"
,
json
,
bufferView
.
byteLength
,
{});
detail
::
WriteField
(
"byteOffset"
,
json
,
bufferView
.
byteOffset
,
{});
detail
::
WriteField
(
"byteStride"
,
json
,
bufferView
.
byteStride
,
{});
detail
::
WriteField
(
"name"
,
json
,
bufferView
.
name
);
detail
::
WriteField
(
"target"
,
json
,
bufferView
.
target
,
BufferView
::
TargetType
::
None
);
detail
::
WriteExtensions
(
json
,
bufferView
.
extensionsAndExtras
);
}
inline
void
to_json
(
nlohmann
::
json
&
json
,
Camera
::
Type
const
&
cameraType
)
{
switch
(
cameraType
)
{
case
Camera
::
Type
::
Orthographic
:
json
=
"orthographic"
;
break
;
case
Camera
::
Type
::
Perspective
:
json
=
"perspective"
;
break
;
default:
throw
invalid_gltf_document
(
"Unknown camera.type value"
);
}
}
inline
void
to_json
(
nlohmann
::
json
&
json
,
Camera
::
Orthographic
const
&
camera
)
{
detail
::
WriteField
(
"xmag"
,
json
,
camera
.
xmag
,
defaults
::
FloatSentinel
);
detail
::
WriteField
(
"ymag"
,
json
,
camera
.
ymag
,
defaults
::
FloatSentinel
);
detail
::
WriteField
(
"zfar"
,
json
,
camera
.
zfar
,
-
defaults
::
FloatSentinel
);
detail
::
WriteField
(
"znear"
,
json
,
camera
.
znear
,
-
defaults
::
FloatSentinel
);
detail
::
WriteExtensions
(
json
,
camera
.
extensionsAndExtras
);
}
inline
void
to_json
(
nlohmann
::
json
&
json
,
Camera
::
Perspective
const
&
camera
)
{
detail
::
WriteField
(
"aspectRatio"
,
json
,
camera
.
aspectRatio
,
{});
detail
::
WriteField
(
"yfov"
,
json
,
camera
.
yfov
,
{});
detail
::
WriteField
(
"zfar"
,
json
,
camera
.
zfar
,
{});
detail
::
WriteField
(
"znear"
,
json
,
camera
.
znear
,
{});
detail
::
WriteExtensions
(
json
,
camera
.
extensionsAndExtras
);
}
inline
void
to_json
(
nlohmann
::
json
&
json
,
Camera
const
&
camera
)
{
detail
::
WriteField
(
"name"
,
json
,
camera
.
name
);
detail
::
WriteField
(
"type"
,
json
,
camera
.
type
,
Camera
::
Type
::
None
);
detail
::
WriteExtensions
(
json
,
camera
.
extensionsAndExtras
);
if
(
camera
.
type
==
Camera
::
Type
::
Perspective
)
{
detail
::
WriteField
(
"perspective"
,
json
,
camera
.
perspective
);
}
else
if
(
camera
.
type
==
Camera
::
Type
::
Orthographic
)
{
detail
::
WriteField
(
"orthographic"
,
json
,
camera
.
orthographic
);
}
}
inline
void
to_json
(
nlohmann
::
json
&
json
,
Image
const
&
image
)
{
detail
::
WriteField
(
"bufferView"
,
json
,
image
.
bufferView
,
image
.
uri
.
empty
()
?
-
1
:
0
);
// bufferView or uri need to be written; even if default 0
detail
::
WriteField
(
"mimeType"
,
json
,
image
.
mimeType
);
detail
::
WriteField
(
"name"
,
json
,
image
.
name
);
detail
::
WriteField
(
"uri"
,
json
,
image
.
uri
);
detail
::
WriteExtensions
(
json
,
image
.
extensionsAndExtras
);
}
inline
void
to_json
(
nlohmann
::
json
&
json
,
Material
::
AlphaMode
const
&
materialAlphaMode
)
{
switch
(
materialAlphaMode
)
{
case
Material
::
AlphaMode
::
Opaque
:
json
=
"OPAQUE"
;
break
;
case
Material
::
AlphaMode
::
Mask
:
json
=
"MASK"
;
break
;
case
Material
::
AlphaMode
::
Blend
:
json
=
"BLEND"
;
break
;
}
}
inline
void
to_json
(
nlohmann
::
json
&
json
,
Material
::
Texture
const
&
materialTexture
)
{
detail
::
WriteField
(
"index"
,
json
,
materialTexture
.
index
,
-
1
);
detail
::
WriteField
(
"texCoord"
,
json
,
materialTexture
.
texCoord
,
0
);
detail
::
WriteExtensions
(
json
,
materialTexture
.
extensionsAndExtras
);
}
inline
void
to_json
(
nlohmann
::
json
&
json
,
Material
::
NormalTexture
const
&
materialTexture
)
{
to_json
(
json
,
static_cast
<
Material
::
Texture
const
&>
(
materialTexture
));
detail
::
WriteField
(
"scale"
,
json
,
materialTexture
.
scale
,
defaults
::
IdentityScalar
);
detail
::
WriteExtensions
(
json
,
materialTexture
.
extensionsAndExtras
);
}
inline
void
to_json
(
nlohmann
::
json
&
json
,
Material
::
OcclusionTexture
const
&
materialTexture
)
{
to_json
(
json
,
static_cast
<
Material
::
Texture
const
&>
(
materialTexture
));
detail
::
WriteField
(
"strength"
,
json
,
materialTexture
.
strength
,
defaults
::
IdentityScalar
);
detail
::
WriteExtensions
(
json
,
materialTexture
.
extensionsAndExtras
);
}
inline
void
to_json
(
nlohmann
::
json
&
json
,
Material
::
PBRMetallicRoughness
const
&
pbrMetallicRoughness
)
{
detail
::
WriteField
(
"baseColorFactor"
,
json
,
pbrMetallicRoughness
.
baseColorFactor
,
defaults
::
IdentityVec4
);
detail
::
WriteField
(
"baseColorTexture"
,
json
,
pbrMetallicRoughness
.
baseColorTexture
);
detail
::
WriteField
(
"metallicFactor"
,
json
,
pbrMetallicRoughness
.
metallicFactor
,
defaults
::
IdentityScalar
);
detail
::
WriteField
(
"metallicRoughnessTexture"
,
json
,
pbrMetallicRoughness
.
metallicRoughnessTexture
);
detail
::
WriteField
(
"roughnessFactor"
,
json
,
pbrMetallicRoughness
.
roughnessFactor
,
defaults
::
IdentityScalar
);
detail
::
WriteExtensions
(
json
,
pbrMetallicRoughness
.
extensionsAndExtras
);
}
inline
void
to_json
(
nlohmann
::
json
&
json
,
Material
const
&
material
)
{
detail
::
WriteField
(
"alphaCutoff"
,
json
,
material
.
alphaCutoff
,
defaults
::
MaterialAlphaCutoff
);
detail
::
WriteField
(
"alphaMode"
,
json
,
material
.
alphaMode
,
Material
::
AlphaMode
::
Opaque
);
detail
::
WriteField
(
"doubleSided"
,
json
,
material
.
doubleSided
,
defaults
::
MaterialDoubleSided
);
detail
::
WriteField
(
"emissiveTexture"
,
json
,
material
.
emissiveTexture
);
detail
::
WriteField
(
"emissiveFactor"
,
json
,
material
.
emissiveFactor
,
defaults
::
NullVec3
);
detail
::
WriteField
(
"name"
,
json
,
material
.
name
);
detail
::
WriteField
(
"normalTexture"
,
json
,
material
.
normalTexture
);
detail
::
WriteField
(
"occlusionTexture"
,
json
,
material
.
occlusionTexture
);
detail
::
WriteField
(
"pbrMetallicRoughness"
,
json
,
material
.
pbrMetallicRoughness
);
detail
::
WriteExtensions
(
json
,
material
.
extensionsAndExtras
);
}
inline
void
to_json
(
nlohmann
::
json
&
json
,
Mesh
const
&
mesh
)
{
detail
::
WriteField
(
"name"
,
json
,
mesh
.
name
);
detail
::
WriteField
(
"primitives"
,
json
,
mesh
.
primitives
);
detail
::
WriteField
(
"weights"
,
json
,
mesh
.
weights
);
detail
::
WriteExtensions
(
json
,
mesh
.
extensionsAndExtras
);
}
inline
void
to_json
(
nlohmann
::
json
&
json
,
Node
const
&
node
)
{
detail
::
WriteField
(
"camera"
,
json
,
node
.
camera
,
-
1
);
detail
::
WriteField
(
"children"
,
json
,
node
.
children
);
detail
::
WriteField
(
"matrix"
,
json
,
node
.
matrix
,
defaults
::
IdentityMatrix
);
detail
::
WriteField
(
"mesh"
,
json
,
node
.
mesh
,
-
1
);
detail
::
WriteField
(
"name"
,
json
,
node
.
name
);
detail
::
WriteField
(
"rotation"
,
json
,
node
.
rotation
,
defaults
::
IdentityRotation
);
detail
::
WriteField
(
"scale"
,
json
,
node
.
scale
,
defaults
::
IdentityVec3
);
detail
::
WriteField
(
"skin"
,
json
,
node
.
skin
,
-
1
);
detail
::
WriteField
(
"translation"
,
json
,
node
.
translation
,
defaults
::
NullVec3
);
detail
::
WriteField
(
"weights"
,
json
,
node
.
weights
);
detail
::
WriteExtensions
(
json
,
node
.
extensionsAndExtras
);
}
inline
void
to_json
(
nlohmann
::
json
&
json
,
Primitive
const
&
primitive
)
{
detail
::
WriteField
(
"attributes"
,
json
,
primitive
.
attributes
);
detail
::
WriteField
(
"indices"
,
json
,
primitive
.
indices
,
-
1
);
detail
::
WriteField
(
"material"
,
json
,
primitive
.
material
,
-
1
);
detail
::
WriteField
(
"mode"
,
json
,
primitive
.
mode
,
Primitive
::
Mode
::
Triangles
);
detail
::
WriteField
(
"targets"
,
json
,
primitive
.
targets
);
detail
::
WriteExtensions
(
json
,
primitive
.
extensionsAndExtras
);
}
inline
void
to_json
(
nlohmann
::
json
&
json
,
Sampler
const
&
sampler
)
{
if
(
!
sampler
.
empty
())
{
detail
::
WriteField
(
"name"
,
json
,
sampler
.
name
);
detail
::
WriteField
(
"magFilter"
,
json
,
sampler
.
magFilter
,
Sampler
::
MagFilter
::
None
);
detail
::
WriteField
(
"minFilter"
,
json
,
sampler
.
minFilter
,
Sampler
::
MinFilter
::
None
);
detail
::
WriteField
(
"wrapS"
,
json
,
sampler
.
wrapS
,
Sampler
::
WrappingMode
::
Repeat
);
detail
::
WriteField
(
"wrapT"
,
json
,
sampler
.
wrapT
,
Sampler
::
WrappingMode
::
Repeat
);
detail
::
WriteExtensions
(
json
,
sampler
.
extensionsAndExtras
);
}
else
{
// If a sampler is completely empty we still need to write out an empty object for the encompassing array...
json
=
nlohmann
::
json
::
object
();
}
}
inline
void
to_json
(
nlohmann
::
json
&
json
,
Scene
const
&
scene
)
{
detail
::
WriteField
(
"name"
,
json
,
scene
.
name
);
detail
::
WriteField
(
"nodes"
,
json
,
scene
.
nodes
);
detail
::
WriteExtensions
(
json
,
scene
.
extensionsAndExtras
);
}
inline
void
to_json
(
nlohmann
::
json
&
json
,
Skin
const
&
skin
)
{
detail
::
WriteField
(
"inverseBindMatrices"
,
json
,
skin
.
inverseBindMatrices
,
-
1
);
detail
::
WriteField
(
"name"
,
json
,
skin
.
name
);
detail
::
WriteField
(
"skeleton"
,
json
,
skin
.
skeleton
,
-
1
);
detail
::
WriteField
(
"joints"
,
json
,
skin
.
joints
);
detail
::
WriteExtensions
(
json
,
skin
.
extensionsAndExtras
);
}
inline
void
to_json
(
nlohmann
::
json
&
json
,
Texture
const
&
texture
)
{
detail
::
WriteField
(
"name"
,
json
,
texture
.
name
);
detail
::
WriteField
(
"sampler"
,
json
,
texture
.
sampler
,
-
1
);
detail
::
WriteField
(
"source"
,
json
,
texture
.
source
,
-
1
);
detail
::
WriteExtensions
(
json
,
texture
.
extensionsAndExtras
);
}
inline
void
to_json
(
nlohmann
::
json
&
json
,
Document
const
&
document
)
{
detail
::
WriteField
(
"accessors"
,
json
,
document
.
accessors
);
detail
::
WriteField
(
"animations"
,
json
,
document
.
animations
);
detail
::
WriteField
(
"asset"
,
json
,
document
.
asset
);
detail
::
WriteField
(
"buffers"
,
json
,
document
.
buffers
);
detail
::
WriteField
(
"bufferViews"
,
json
,
document
.
bufferViews
);
detail
::
WriteField
(
"cameras"
,
json
,
document
.
cameras
);
detail
::
WriteField
(
"images"
,
json
,
document
.
images
);
detail
::
WriteField
(
"materials"
,
json
,
document
.
materials
);
detail
::
WriteField
(
"meshes"
,
json
,
document
.
meshes
);
detail
::
WriteField
(
"nodes"
,
json
,
document
.
nodes
);
detail
::
WriteField
(
"samplers"
,
json
,
document
.
samplers
);
detail
::
WriteField
(
"scene"
,
json
,
document
.
scene
,
-
1
);
detail
::
WriteField
(
"scenes"
,
json
,
document
.
scenes
);
detail
::
WriteField
(
"skins"
,
json
,
document
.
skins
);
detail
::
WriteField
(
"textures"
,
json
,
document
.
textures
);
detail
::
WriteField
(
"extensionsUsed"
,
json
,
document
.
extensionsUsed
);
detail
::
WriteField
(
"extensionsRequired"
,
json
,
document
.
extensionsRequired
);
detail
::
WriteExtensions
(
json
,
document
.
extensionsAndExtras
);
}
inline
Document
LoadFromText
(
std
::
string
const
&
documentFilePath
,
ReadQuotas
const
&
readQuotas
=
{})
{
try
{
nlohmann
::
json
json
;
{
std
::
ifstream
file
(
documentFilePath
);
if
(
!
file
.
is_open
())
{
throw
std
::
system_error
(
std
::
make_error_code
(
std
::
errc
::
no_such_file_or_directory
));
}
file
>>
json
;
}
return
detail
::
Create
(
json
,
{
detail
::
GetDocumentRootPath
(
documentFilePath
),
readQuotas
});
}
catch
(
invalid_gltf_document
&
)
{
throw
;
}
catch
(
std
::
system_error
&
)
{
throw
;
}
catch
(...)
{
std
::
throw_with_nested
(
invalid_gltf_document
(
"Invalid glTF document. See nested exception for details."
));
}
}
inline
Document
LoadFromBinary
(
std
::
string
const
&
documentFilePath
,
ReadQuotas
const
&
readQuotas
=
{})
{
try
{
std
::
vector
<
uint8_t
>
binary
{};
{
std
::
ifstream
file
(
documentFilePath
,
std
::
ios
::
binary
);
if
(
!
file
.
is_open
())
{
throw
std
::
system_error
(
std
::
make_error_code
(
std
::
errc
::
no_such_file_or_directory
));
}
const
std
::
size_t
fileSize
=
detail
::
GetFileSize
(
file
);
if
(
fileSize
<
detail
::
HeaderSize
)
{
throw
invalid_gltf_document
(
"Invalid GLB file"
);
}
if
(
fileSize
>
readQuotas
.
MaxFileSize
)
{
throw
invalid_gltf_document
(
"Quota exceeded : file size > MaxFileSize"
);
}
binary
.
resize
(
fileSize
);
file
.
read
(
reinterpret_cast
<
char
*>
(
&
binary
[
0
]),
fileSize
);
}
detail
::
GLBHeader
header
;
std
::
memcpy
(
&
header
,
&
binary
[
0
],
detail
::
HeaderSize
);
if
(
header
.
magic
!=
detail
::
GLBHeaderMagic
||
header
.
jsonHeader
.
chunkType
!=
detail
::
GLBChunkJSON
||
header
.
jsonHeader
.
chunkLength
+
detail
::
HeaderSize
>
header
.
length
)
{
throw
invalid_gltf_document
(
"Invalid GLB header"
);
}
return
detail
::
Create
(
nlohmann
::
json
::
parse
({
&
binary
[
detail
::
HeaderSize
],
header
.
jsonHeader
.
chunkLength
}),
{
detail
::
GetDocumentRootPath
(
documentFilePath
),
readQuotas
,
&
binary
,
header
.
jsonHeader
.
chunkLength
+
detail
::
HeaderSize
});
}
catch
(
invalid_gltf_document
&
)
{
throw
;
}
catch
(
std
::
system_error
&
)
{
throw
;
}
catch
(...)
{
std
::
throw_with_nested
(
invalid_gltf_document
(
"Invalid glTF document. See nested exception for details."
));
}
}
inline
void
Save
(
Document
const
&
document
,
std
::
string
documentFilePath
,
bool
useBinaryFormat
)
{
try
{
detail
::
ValidateBuffers
(
document
,
useBinaryFormat
);
detail
::
Save
(
document
,
documentFilePath
,
useBinaryFormat
);
}
catch
(
invalid_gltf_document
&
)
{
throw
;
}
catch
(
std
::
system_error
&
)
{
throw
;
}
catch
(...)
{
std
::
throw_with_nested
(
invalid_gltf_document
(
"Invalid glTF document. See nested exception for details."
));
}
}
}
// namespace gltf
// A general-purpose utility to format an exception hierarchy into a string for output
inline
void
FormatException
(
std
::
string
&
output
,
std
::
exception
const
&
ex
,
int
level
=
0
)
{
output
.
append
(
std
::
string
(
level
,
' '
)).
append
(
ex
.
what
());
try
{
std
::
rethrow_if_nested
(
ex
);
}
catch
(
std
::
exception
const
&
e
)
{
FormatException
(
output
.
append
(
"
\n
"
),
e
,
level
+
2
);
}
}
}
// namespace fx
#undef FX_GLTF_HAS_CPP_17
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment