Merge branch 'project/gltf_development' of https://github.com/secondlife/viewer
# Conflicts: # autobuild.xml # indra/newview/app_settings/settings.xml # indra/newview/llinventorymodel.cpp # indra/newview/llviewermenu.cpp # indra/newview/llviewerregion.cpp # indra/newview/llvovolume.cpp # indra/newview/skins/default/xui/en/notifications.xmlmaster
commit
c203bb650a
|
|
@ -1121,6 +1121,48 @@
|
||||||
<key>description</key>
|
<key>description</key>
|
||||||
<string>glh - is a platform-indepenedent C++ OpenGL helper library</string>
|
<string>glh - is a platform-indepenedent C++ OpenGL helper library</string>
|
||||||
</map>
|
</map>
|
||||||
|
<key>glm</key>
|
||||||
|
<map>
|
||||||
|
<key>canonical_repo</key>
|
||||||
|
<string>https://github.com/secondlife/3p-glm</string>
|
||||||
|
<key>copyright</key>
|
||||||
|
<string>Copyright (c) 2005 - G-Truc Creation</string>
|
||||||
|
<key>description</key>
|
||||||
|
<string>OpenGL Mathematics</string>
|
||||||
|
<key>license</key>
|
||||||
|
<string>MIT</string>
|
||||||
|
<key>license_file</key>
|
||||||
|
<string>LICENSES/glm_license.txt</string>
|
||||||
|
<key>name</key>
|
||||||
|
<string>glm</string>
|
||||||
|
<key>platforms</key>
|
||||||
|
<map>
|
||||||
|
<key>common</key>
|
||||||
|
<map>
|
||||||
|
<key>archive</key>
|
||||||
|
<map>
|
||||||
|
<key>hash</key>
|
||||||
|
<string>353ae3a560143732503a8e14499ae12db1e66056</string>
|
||||||
|
<key>hash_algorithm</key>
|
||||||
|
<string>sha1</string>
|
||||||
|
<key>url</key>
|
||||||
|
<string>https://github.com/secondlife/3p-glm/releases/download/v1.0.1-r1/glm-v1.0.1-common-9066386153.tar.zst</string>
|
||||||
|
</map>
|
||||||
|
<key>name</key>
|
||||||
|
<string>common</string>
|
||||||
|
</map>
|
||||||
|
</map>
|
||||||
|
<key>source_type</key>
|
||||||
|
<string>git</string>
|
||||||
|
<key>vcs_branch</key>
|
||||||
|
<string>refs/tags/v1.0.1-r1</string>
|
||||||
|
<key>vcs_revision</key>
|
||||||
|
<string>399cd5ba57a9267a560ce07e50a0f8c5fe3dc66f</string>
|
||||||
|
<key>vcs_url</key>
|
||||||
|
<string>git://github.com/secondlife/3p-glm.git</string>
|
||||||
|
<key>version</key>
|
||||||
|
<string>v1.0.1</string>
|
||||||
|
</map>
|
||||||
<key>havok-source</key>
|
<key>havok-source</key>
|
||||||
<map>
|
<map>
|
||||||
<key>platforms</key>
|
<key>platforms</key>
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
## Tiling
|
## Tiling
|
||||||
|
|
||||||
|
The southwest corner of a region with PBR materials should exactly match up with the bottom left corner of the material texture(s).
|
||||||
|
|
||||||
If two adjacent regions have the same PBR terrain settings, then:
|
If two adjacent regions have the same PBR terrain settings, then:
|
||||||
|
|
||||||
- There should not be seams between the two regions at their shared border
|
- There should not be seams between the two regions at their shared border
|
||||||
|
|
|
||||||
|
|
@ -126,7 +126,7 @@ if(WINDOWS)
|
||||||
elseif (MSVC_VERSION GREATER_EQUAL 1920 AND MSVC_VERSION LESS 1930) # Visual Studio 2019
|
elseif (MSVC_VERSION GREATER_EQUAL 1920 AND MSVC_VERSION LESS 1930) # Visual Studio 2019
|
||||||
set(MSVC_VER 140)
|
set(MSVC_VER 140)
|
||||||
set(MSVC_TOOLSET_VER 142)
|
set(MSVC_TOOLSET_VER 142)
|
||||||
elseif (MSVC_VERSION GREATER_EQUAL 1930 AND MSVC_VERSION LESS 1940) # Visual Studio 2022
|
elseif (MSVC_VERSION GREATER_EQUAL 1930 AND MSVC_VERSION LESS 1950) # Visual Studio 2022
|
||||||
set(MSVC_VER 140)
|
set(MSVC_VER 140)
|
||||||
set(MSVC_TOOLSET_VER 143)
|
set(MSVC_TOOLSET_VER 143)
|
||||||
else (MSVC80)
|
else (MSVC80)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
# -*- cmake -*-
|
||||||
|
include(Prebuilt)
|
||||||
|
|
||||||
|
add_library( ll::glm INTERFACE IMPORTED )
|
||||||
|
|
||||||
|
use_system_binary( glm )
|
||||||
|
use_prebuilt_binary(glm)
|
||||||
|
|
@ -97,6 +97,8 @@ LLAssetDictionary::LLAssetDictionary()
|
||||||
addEntry(LLAssetType::AT_PERSON, new AssetEntry("PERSON", "person", "person", false, false, false));
|
addEntry(LLAssetType::AT_PERSON, new AssetEntry("PERSON", "person", "person", false, false, false));
|
||||||
addEntry(LLAssetType::AT_SETTINGS, new AssetEntry("SETTINGS", "settings", "settings blob", true, true, true));
|
addEntry(LLAssetType::AT_SETTINGS, new AssetEntry("SETTINGS", "settings", "settings blob", true, true, true));
|
||||||
addEntry(LLAssetType::AT_MATERIAL, new AssetEntry("MATERIAL", "material", "render material", true, true, true));
|
addEntry(LLAssetType::AT_MATERIAL, new AssetEntry("MATERIAL", "material", "render material", true, true, true));
|
||||||
|
addEntry(LLAssetType::AT_GLTF, new AssetEntry("GLTF", "gltf", "GLTF", true, true, true));
|
||||||
|
addEntry(LLAssetType::AT_GLTF_BIN, new AssetEntry("GLTF_BIN", "glbin", "GLTF binary", true, true, true));
|
||||||
addEntry(LLAssetType::AT_UNKNOWN, new AssetEntry("UNKNOWN", "invalid", NULL, false, false, false));
|
addEntry(LLAssetType::AT_UNKNOWN, new AssetEntry("UNKNOWN", "invalid", NULL, false, false, false));
|
||||||
addEntry(LLAssetType::AT_NONE, new AssetEntry("NONE", "-1", NULL, false, false, false));
|
addEntry(LLAssetType::AT_NONE, new AssetEntry("NONE", "-1", NULL, false, false, false));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -128,8 +128,10 @@ public:
|
||||||
|
|
||||||
AT_SETTINGS = 56, // Collection of settings
|
AT_SETTINGS = 56, // Collection of settings
|
||||||
AT_MATERIAL = 57, // Render Material
|
AT_MATERIAL = 57, // Render Material
|
||||||
|
AT_GLTF = 58, // gltf json document
|
||||||
|
AT_GLTF_BIN = 59, // gltf binary data
|
||||||
|
|
||||||
AT_COUNT = 58,
|
AT_COUNT = 60,
|
||||||
|
|
||||||
// +*********************************************************+
|
// +*********************************************************+
|
||||||
// | TO ADD AN ELEMENT TO THIS ENUM: |
|
// | TO ADD AN ELEMENT TO THIS ENUM: |
|
||||||
|
|
|
||||||
|
|
@ -371,6 +371,8 @@ const std::string LLDiskCache::assetTypeToString(LLAssetType::EType at)
|
||||||
{ LLAssetType::AT_MESH, "MESH" },
|
{ LLAssetType::AT_MESH, "MESH" },
|
||||||
{ LLAssetType::AT_SETTINGS, "SETTINGS" },
|
{ LLAssetType::AT_SETTINGS, "SETTINGS" },
|
||||||
{ LLAssetType::AT_MATERIAL, "MATERIAL" },
|
{ LLAssetType::AT_MATERIAL, "MATERIAL" },
|
||||||
|
{ LLAssetType::AT_GLTF, "GLTF" },
|
||||||
|
{ LLAssetType::AT_GLTF_BIN, "GLTF_BIN" },
|
||||||
{ LLAssetType::AT_UNKNOWN, "UNKNOWN" }
|
{ LLAssetType::AT_UNKNOWN, "UNKNOWN" }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -84,6 +84,8 @@ LLInventoryDictionary::LLInventoryDictionary()
|
||||||
addEntry(LLInventoryType::IT_ANIMATION, new InventoryEntry("animation", "animation", 1, LLAssetType::AT_ANIMATION));
|
addEntry(LLInventoryType::IT_ANIMATION, new InventoryEntry("animation", "animation", 1, LLAssetType::AT_ANIMATION));
|
||||||
addEntry(LLInventoryType::IT_GESTURE, new InventoryEntry("gesture", "gesture", 1, LLAssetType::AT_GESTURE));
|
addEntry(LLInventoryType::IT_GESTURE, new InventoryEntry("gesture", "gesture", 1, LLAssetType::AT_GESTURE));
|
||||||
addEntry(LLInventoryType::IT_MESH, new InventoryEntry("mesh", "mesh", 1, LLAssetType::AT_MESH));
|
addEntry(LLInventoryType::IT_MESH, new InventoryEntry("mesh", "mesh", 1, LLAssetType::AT_MESH));
|
||||||
|
addEntry(LLInventoryType::IT_GLTF, new InventoryEntry("gltf", "gltf", 1, LLAssetType::AT_GLTF));
|
||||||
|
addEntry(LLInventoryType::IT_GLTF_BIN, new InventoryEntry("glbin", "glbin", 1, LLAssetType::AT_GLTF_BIN));
|
||||||
addEntry(LLInventoryType::IT_WIDGET, new InventoryEntry("widget", "widget", 1, LLAssetType::AT_WIDGET));
|
addEntry(LLInventoryType::IT_WIDGET, new InventoryEntry("widget", "widget", 1, LLAssetType::AT_WIDGET));
|
||||||
addEntry(LLInventoryType::IT_PERSON, new InventoryEntry("person", "person", 1, LLAssetType::AT_PERSON));
|
addEntry(LLInventoryType::IT_PERSON, new InventoryEntry("person", "person", 1, LLAssetType::AT_PERSON));
|
||||||
addEntry(LLInventoryType::IT_SETTINGS, new InventoryEntry("settings", "settings", 1, LLAssetType::AT_SETTINGS));
|
addEntry(LLInventoryType::IT_SETTINGS, new InventoryEntry("settings", "settings", 1, LLAssetType::AT_SETTINGS));
|
||||||
|
|
@ -154,9 +156,12 @@ DEFAULT_ASSET_FOR_INV_TYPE[LLAssetType::AT_COUNT] =
|
||||||
LLInventoryType::IT_NONE, // 52 AT_RESERVED_3
|
LLInventoryType::IT_NONE, // 52 AT_RESERVED_3
|
||||||
LLInventoryType::IT_NONE, // 53 AT_RESERVED_4
|
LLInventoryType::IT_NONE, // 53 AT_RESERVED_4
|
||||||
LLInventoryType::IT_NONE, // 54 AT_RESERVED_5
|
LLInventoryType::IT_NONE, // 54 AT_RESERVED_5
|
||||||
|
LLInventoryType::IT_NONE, // 55 AT_RESERVED_6
|
||||||
|
|
||||||
LLInventoryType::IT_SETTINGS, // 55 AT_SETTINGS <- why doesnt this match the value in llassettype.h? -brad
|
LLInventoryType::IT_SETTINGS, // 56 AT_SETTINGS
|
||||||
LLInventoryType::IT_MATERIAL, // 57 AT_MATERIAL
|
LLInventoryType::IT_MATERIAL, // 57 AT_MATERIAL
|
||||||
|
LLInventoryType::IT_GLTF, // 58 AT_GLTF
|
||||||
|
LLInventoryType::IT_GLTF_BIN, // 59 AT_GLTF_BIN
|
||||||
};
|
};
|
||||||
|
|
||||||
// static
|
// static
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,9 @@ public:
|
||||||
IT_PERSON = 24,
|
IT_PERSON = 24,
|
||||||
IT_SETTINGS = 25,
|
IT_SETTINGS = 25,
|
||||||
IT_MATERIAL = 26,
|
IT_MATERIAL = 26,
|
||||||
IT_COUNT = 27,
|
IT_GLTF = 27,
|
||||||
|
IT_GLTF_BIN = 28,
|
||||||
|
IT_COUNT = 29,
|
||||||
|
|
||||||
IT_UNKNOWN = 255,
|
IT_UNKNOWN = 255,
|
||||||
IT_NONE = -1
|
IT_NONE = -1
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,34 @@ public:
|
||||||
loadu(val);
|
loadu(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
explicit LLMatrix4a(const F32* val)
|
||||||
|
{
|
||||||
|
loadu(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const LLMatrix4a& identity()
|
||||||
|
{
|
||||||
|
static const F32 v[] =
|
||||||
|
{ 1.f, 0.f, 0.f, 0.f,
|
||||||
|
0.f, 1.f, 0.f, 0.f,
|
||||||
|
0.f, 0.f, 1.f, 0.f,
|
||||||
|
0.f, 0.f, 0.f, 1.f
|
||||||
|
};
|
||||||
|
static LLMatrix4a identity_mat(v);
|
||||||
|
|
||||||
|
return identity_mat;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const LLMatrix4a& rhs) const
|
||||||
|
{
|
||||||
|
return mMatrix[0] == rhs.mMatrix[0] && mMatrix[1] == rhs.mMatrix[1] && mMatrix[2] == rhs.mMatrix[2] && mMatrix[3] == rhs.mMatrix[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const LLMatrix4a& rhs) const
|
||||||
|
{
|
||||||
|
return !(*this == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
inline F32* getF32ptr()
|
inline F32* getF32ptr()
|
||||||
{
|
{
|
||||||
return (F32*) &mMatrix;
|
return (F32*) &mMatrix;
|
||||||
|
|
|
||||||
|
|
@ -117,6 +117,16 @@ public:
|
||||||
mQ = q;
|
mQ = q;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool operator==(const LLVector4a& rhs) const
|
||||||
|
{
|
||||||
|
return equals4(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const LLVector4a& rhs) const
|
||||||
|
{
|
||||||
|
return !(*this == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////
|
////////////////////////////////////
|
||||||
// LOAD/STORE
|
// LOAD/STORE
|
||||||
////////////////////////////////////
|
////////////////////////////////////
|
||||||
|
|
|
||||||
|
|
@ -193,11 +193,13 @@ constexpr U8 LL_SCULPT_TYPE_TORUS = 2;
|
||||||
constexpr U8 LL_SCULPT_TYPE_PLANE = 3;
|
constexpr U8 LL_SCULPT_TYPE_PLANE = 3;
|
||||||
constexpr U8 LL_SCULPT_TYPE_CYLINDER = 4;
|
constexpr U8 LL_SCULPT_TYPE_CYLINDER = 4;
|
||||||
constexpr U8 LL_SCULPT_TYPE_MESH = 5;
|
constexpr U8 LL_SCULPT_TYPE_MESH = 5;
|
||||||
|
constexpr U8 LL_SCULPT_TYPE_GLTF = 6;
|
||||||
|
constexpr U8 LL_SCULPT_TYPE_MAX = LL_SCULPT_TYPE_GLTF;
|
||||||
|
|
||||||
constexpr U8 LL_SCULPT_TYPE_MASK = LL_SCULPT_TYPE_SPHERE | LL_SCULPT_TYPE_TORUS | LL_SCULPT_TYPE_PLANE |
|
constexpr U8 LL_SCULPT_TYPE_MASK = LL_SCULPT_TYPE_SPHERE | LL_SCULPT_TYPE_TORUS | LL_SCULPT_TYPE_PLANE |
|
||||||
LL_SCULPT_TYPE_CYLINDER | LL_SCULPT_TYPE_MESH;
|
LL_SCULPT_TYPE_CYLINDER | LL_SCULPT_TYPE_MESH | LL_SCULPT_TYPE_GLTF;
|
||||||
|
|
||||||
// for value checks, assign new value after adding new types
|
// for value checks, assign new value after adding new types
|
||||||
constexpr U8 LL_SCULPT_TYPE_MAX = LL_SCULPT_TYPE_MESH;
|
|
||||||
|
|
||||||
constexpr U8 LL_SCULPT_FLAG_INVERT = 64;
|
constexpr U8 LL_SCULPT_FLAG_INVERT = 64;
|
||||||
constexpr U8 LL_SCULPT_FLAG_MIRROR = 128;
|
constexpr U8 LL_SCULPT_FLAG_MIRROR = 128;
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ include(LLCoreHttp)
|
||||||
include(LLPhysicsExtensions)
|
include(LLPhysicsExtensions)
|
||||||
include(LLPrimitive)
|
include(LLPrimitive)
|
||||||
include(GLH)
|
include(GLH)
|
||||||
|
include(GLM)
|
||||||
include(TinyGLTF)
|
include(TinyGLTF)
|
||||||
include(ColladaDom)
|
include(ColladaDom)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -273,6 +273,7 @@ public:
|
||||||
F32 mAlphaCutoff;
|
F32 mAlphaCutoff;
|
||||||
|
|
||||||
AlphaMode mAlphaMode;
|
AlphaMode mAlphaMode;
|
||||||
|
|
||||||
bool mDoubleSided = false;
|
bool mDoubleSided = false;
|
||||||
|
|
||||||
// Override specific flags for state that can't use off-by-epsilon or UUID
|
// Override specific flags for state that can't use off-by-epsilon or UUID
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,10 @@ enum EDragAndDropType
|
||||||
DAD_PERSON = 17,
|
DAD_PERSON = 17,
|
||||||
DAD_SETTINGS = 18,
|
DAD_SETTINGS = 18,
|
||||||
DAD_MATERIAL = 19,
|
DAD_MATERIAL = 19,
|
||||||
DAD_COUNT = 20, // number of types in this enum
|
DAD_GLTF = 20,
|
||||||
|
DAD_GLTF_BIN = 21,
|
||||||
|
|
||||||
|
DAD_COUNT = 22, // number of types in this enum
|
||||||
};
|
};
|
||||||
|
|
||||||
// Reasons for drags to be denied.
|
// Reasons for drags to be denied.
|
||||||
|
|
|
||||||
|
|
@ -24323,6 +24323,17 @@ Change of this parameter will affect the layout of buttons in notification toast
|
||||||
<key>Value</key>
|
<key>Value</key>
|
||||||
<integer>0</integer>
|
<integer>0</integer>
|
||||||
</map>
|
</map>
|
||||||
|
<key>GLTFEnabled</key>
|
||||||
|
<map>
|
||||||
|
<key>Comment</key>
|
||||||
|
<string>Enable GLTF support. Set by SimulatorFeatures</string>
|
||||||
|
<key>Persist</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>Type</key>
|
||||||
|
<string>Boolean</string>
|
||||||
|
<key>Value</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</map>
|
||||||
|
|
||||||
<key>FSNetMapPhantomOpacity</key>
|
<key>FSNetMapPhantomOpacity</key>
|
||||||
<map>
|
<map>
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ uniform float minimum_alpha;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
float alpha = texture(diffuseMap,vary_texcoord0.xy).a;
|
float alpha = texture(diffuseMap,vary_texcoord0.xy).a * vertex_color.a;
|
||||||
|
|
||||||
if (alpha < minimum_alpha)
|
if (alpha < minimum_alpha)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -69,12 +69,16 @@ void main()
|
||||||
mirrorClip(vary_position);
|
mirrorClip(vary_position);
|
||||||
|
|
||||||
vec4 basecolor = texture(diffuseMap, base_color_texcoord.xy).rgba;
|
vec4 basecolor = texture(diffuseMap, base_color_texcoord.xy).rgba;
|
||||||
|
basecolor.rgb = srgb_to_linear(basecolor.rgb);
|
||||||
|
|
||||||
|
basecolor *= vertex_color;
|
||||||
|
|
||||||
if (basecolor.a < minimum_alpha)
|
if (basecolor.a < minimum_alpha)
|
||||||
{
|
{
|
||||||
discard;
|
discard;
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3 col = vertex_color.rgb * srgb_to_linear(basecolor.rgb);
|
vec3 col = basecolor.rgb;
|
||||||
|
|
||||||
// from mikktspace.com
|
// from mikktspace.com
|
||||||
vec3 vNt = texture(bumpMap, normal_texcoord.xy).xyz*2.0-1.0;
|
vec3 vNt = texture(bumpMap, normal_texcoord.xy).xyz*2.0-1.0;
|
||||||
|
|
@ -108,7 +112,7 @@ void main()
|
||||||
//emissive = tnorm*0.5+0.5;
|
//emissive = tnorm*0.5+0.5;
|
||||||
// See: C++: addDeferredAttachments(), GLSL: softenLightF
|
// See: C++: addDeferredAttachments(), GLSL: softenLightF
|
||||||
frag_data[0] = max(vec4(col, 0.0), vec4(0)); // Diffuse
|
frag_data[0] = max(vec4(col, 0.0), vec4(0)); // Diffuse
|
||||||
frag_data[1] = max(vec4(spec.rgb,vertex_color.a), vec4(0)); // PBR linear packed Occlusion, Roughness, Metal.
|
frag_data[1] = max(vec4(spec.rgb,0.0), vec4(0)); // PBR linear packed Occlusion, Roughness, Metal.
|
||||||
frag_data[2] = vec4(tnorm, GBUFFER_FLAG_HAS_PBR); // normal, environment intensity, flags
|
frag_data[2] = vec4(tnorm, GBUFFER_FLAG_HAS_PBR); // normal, environment intensity, flags
|
||||||
frag_data[3] = max(vec4(emissive,0), vec4(0)); // PBR sRGB Emissive
|
frag_data[3] = max(vec4(emissive,0), vec4(0)); // PBR sRGB Emissive
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -195,18 +195,18 @@ void main()
|
||||||
|
|
||||||
PBRMix mix = init_pbr_mix();
|
PBRMix mix = init_pbr_mix();
|
||||||
PBRMix mix2;
|
PBRMix mix2;
|
||||||
|
TerrainCoord terrain_texcoord;
|
||||||
switch (tm.type & MIX_X)
|
switch (tm.type & MIX_X)
|
||||||
{
|
{
|
||||||
case MIX_X:
|
case MIX_X:
|
||||||
#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3
|
#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3
|
||||||
TerrainCoord terrain_texcoord;
|
|
||||||
terrain_texcoord[0].xy = vary_coords[0].xy;
|
terrain_texcoord[0].xy = vary_coords[0].xy;
|
||||||
terrain_texcoord[0].zw = vary_coords[0].zw;
|
terrain_texcoord[0].zw = vary_coords[0].zw;
|
||||||
terrain_texcoord[1].xy = vary_coords[1].xy;
|
terrain_texcoord[1].xy = vary_coords[1].xy;
|
||||||
terrain_texcoord[1].zw = vary_coords[1].zw;
|
terrain_texcoord[1].zw = vary_coords[1].zw;
|
||||||
terrain_texcoord[2].xy = vary_coords[2].xy;
|
terrain_texcoord[2].xy = vary_coords[2].xy;
|
||||||
#elif TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 1
|
#elif TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 1
|
||||||
TerrainCoord terrain_texcoord = vary_coords[0].xy;
|
terrain_texcoord = vary_coords[0].xy;
|
||||||
#endif
|
#endif
|
||||||
mix2 = terrain_sample_and_multiply_pbr(
|
mix2 = terrain_sample_and_multiply_pbr(
|
||||||
terrain_texcoord
|
terrain_texcoord
|
||||||
|
|
@ -242,14 +242,13 @@ void main()
|
||||||
{
|
{
|
||||||
case MIX_Y:
|
case MIX_Y:
|
||||||
#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3
|
#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3
|
||||||
TerrainCoord terrain_texcoord;
|
|
||||||
terrain_texcoord[0].xy = vary_coords[2].zw;
|
terrain_texcoord[0].xy = vary_coords[2].zw;
|
||||||
terrain_texcoord[0].zw = vary_coords[3].xy;
|
terrain_texcoord[0].zw = vary_coords[3].xy;
|
||||||
terrain_texcoord[1].xy = vary_coords[3].zw;
|
terrain_texcoord[1].xy = vary_coords[3].zw;
|
||||||
terrain_texcoord[1].zw = vary_coords[4].xy;
|
terrain_texcoord[1].zw = vary_coords[4].xy;
|
||||||
terrain_texcoord[2].xy = vary_coords[4].zw;
|
terrain_texcoord[2].xy = vary_coords[4].zw;
|
||||||
#elif TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 1
|
#elif TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 1
|
||||||
TerrainCoord terrain_texcoord = vary_coords[0].zw;
|
terrain_texcoord = vary_coords[0].zw;
|
||||||
#endif
|
#endif
|
||||||
mix2 = terrain_sample_and_multiply_pbr(
|
mix2 = terrain_sample_and_multiply_pbr(
|
||||||
terrain_texcoord
|
terrain_texcoord
|
||||||
|
|
@ -285,14 +284,13 @@ void main()
|
||||||
{
|
{
|
||||||
case MIX_Z:
|
case MIX_Z:
|
||||||
#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3
|
#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3
|
||||||
TerrainCoord terrain_texcoord;
|
|
||||||
terrain_texcoord[0].xy = vary_coords[5].xy;
|
terrain_texcoord[0].xy = vary_coords[5].xy;
|
||||||
terrain_texcoord[0].zw = vary_coords[5].zw;
|
terrain_texcoord[0].zw = vary_coords[5].zw;
|
||||||
terrain_texcoord[1].xy = vary_coords[6].xy;
|
terrain_texcoord[1].xy = vary_coords[6].xy;
|
||||||
terrain_texcoord[1].zw = vary_coords[6].zw;
|
terrain_texcoord[1].zw = vary_coords[6].zw;
|
||||||
terrain_texcoord[2].xy = vary_coords[7].xy;
|
terrain_texcoord[2].xy = vary_coords[7].xy;
|
||||||
#elif TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 1
|
#elif TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 1
|
||||||
TerrainCoord terrain_texcoord = vary_coords[1].xy;
|
terrain_texcoord = vary_coords[1].xy;
|
||||||
#endif
|
#endif
|
||||||
mix2 = terrain_sample_and_multiply_pbr(
|
mix2 = terrain_sample_and_multiply_pbr(
|
||||||
terrain_texcoord
|
terrain_texcoord
|
||||||
|
|
@ -328,14 +326,13 @@ void main()
|
||||||
{
|
{
|
||||||
case MIX_W:
|
case MIX_W:
|
||||||
#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3
|
#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3
|
||||||
TerrainCoord terrain_texcoord;
|
|
||||||
terrain_texcoord[0].xy = vary_coords[7].zw;
|
terrain_texcoord[0].xy = vary_coords[7].zw;
|
||||||
terrain_texcoord[0].zw = vary_coords[8].xy;
|
terrain_texcoord[0].zw = vary_coords[8].xy;
|
||||||
terrain_texcoord[1].xy = vary_coords[8].zw;
|
terrain_texcoord[1].xy = vary_coords[8].zw;
|
||||||
terrain_texcoord[1].zw = vary_coords[9].xy;
|
terrain_texcoord[1].zw = vary_coords[9].xy;
|
||||||
terrain_texcoord[2].xy = vary_coords[9].zw;
|
terrain_texcoord[2].xy = vary_coords[9].zw;
|
||||||
#elif TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 1
|
#elif TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 1
|
||||||
TerrainCoord terrain_texcoord = vary_coords[1].zw;
|
terrain_texcoord = vary_coords[1].zw;
|
||||||
#endif
|
#endif
|
||||||
mix2 = terrain_sample_and_multiply_pbr(
|
mix2 = terrain_sample_and_multiply_pbr(
|
||||||
terrain_texcoord
|
terrain_texcoord
|
||||||
|
|
|
||||||
|
|
@ -84,11 +84,9 @@ vec2 terrain_texture_transform(vec2 vertex_texcoord, vec4[2] khr_gltf_transform)
|
||||||
{
|
{
|
||||||
vec2 texcoord = vertex_texcoord;
|
vec2 texcoord = vertex_texcoord;
|
||||||
|
|
||||||
texcoord.y = 1.0 - texcoord.y;
|
texcoord.y = -texcoord.y;
|
||||||
//texcoord.y = -texcoord.y;
|
|
||||||
texcoord = khr_texture_transform(texcoord, khr_gltf_transform[0].xy, khr_gltf_transform[0].z, khr_gltf_transform[1].xy);
|
texcoord = khr_texture_transform(texcoord, khr_gltf_transform[0].xy, khr_gltf_transform[0].z, khr_gltf_transform[1].xy);
|
||||||
texcoord.y = 1.0 - texcoord.y;
|
texcoord.y = -texcoord.y;
|
||||||
//texcoord.y = -texcoord.y;
|
|
||||||
|
|
||||||
return texcoord;
|
return texcoord;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -98,7 +98,7 @@ void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, ou
|
||||||
haze_glow = max(haze_glow, .001); // set a minimum "angle" (smaller glow.y allows tighter, brighter hotspot)
|
haze_glow = max(haze_glow, .001); // set a minimum "angle" (smaller glow.y allows tighter, brighter hotspot)
|
||||||
haze_glow *= glow.x;
|
haze_glow *= glow.x;
|
||||||
// higher glow.x gives dimmer glow (because next step is 1 / "angle")
|
// higher glow.x gives dimmer glow (because next step is 1 / "angle")
|
||||||
haze_glow = clamp(pow(haze_glow, glow.z), -10, 10);
|
haze_glow = clamp(pow(haze_glow, glow.z), -100000, 100000);
|
||||||
// glow.z should be negative, so we're doing a sort of (1 / "angle") function
|
// glow.z should be negative, so we're doing a sort of (1 / "angle") function
|
||||||
|
|
||||||
// add "minimum anti-solar illumination"
|
// add "minimum anti-solar illumination"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,156 @@
|
||||||
|
# Linden Lab GLTF Implementation
|
||||||
|
|
||||||
|
Currently in prototype stage. Much functionality is missing (blend shapes,
|
||||||
|
multiple texture coordinates, etc).
|
||||||
|
|
||||||
|
GLTF Specification can be found here: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html.
|
||||||
|
If this implementation disagrees with the GLTF Specification, the specification is correct.
|
||||||
|
|
||||||
|
Class structure and naming should match the GLTF Specification as closely as possible while
|
||||||
|
conforming to the LL coding standards. All code in headers should be contained in the
|
||||||
|
LL::GLTF namespace.
|
||||||
|
|
||||||
|
The implementation serves both the client and the server.
|
||||||
|
|
||||||
|
## Design Principles
|
||||||
|
|
||||||
|
- The implementation MUST be capable of round-trip serialization with no data loss beyond F64 to F32 conversions.
|
||||||
|
- The implementation MUST use the same indexing scheme as the GLTF specification. Do not store pointers where the
|
||||||
|
- GLTF specification stores indices, store indices.
|
||||||
|
- Limit dependencies on llcommon as much as possible. Prefer std::, boost::, and (soon) glm:: over LL facsimiles.
|
||||||
|
- Usage of LLSD is forbidden in the LL::GLTF namespace.
|
||||||
|
- Use "using namespace" liberally in .cpp files, but never in .h files.
|
||||||
|
- "using Foo = Bar" is permissible in .h files within the LL::GLTF namespace.
|
||||||
|
|
||||||
|
## Loading, Copying, and Serialization
|
||||||
|
Each class should provide two functions (Primitive shown for example):
|
||||||
|
|
||||||
|
```
|
||||||
|
// Serialize to the provided json object.
|
||||||
|
// "obj" should be "this" in json form on return
|
||||||
|
// Do not serialize default values
|
||||||
|
void serialize(boost::json::object& obj) const;
|
||||||
|
|
||||||
|
// Initialize from a provided json value
|
||||||
|
const Primitive& operator=(const Value& src);
|
||||||
|
```
|
||||||
|
|
||||||
|
"serialize" implementations should use "write":
|
||||||
|
|
||||||
|
```
|
||||||
|
void Primitive::serialize(boost::json::object& dst) const
|
||||||
|
{
|
||||||
|
write(mMaterial, "material", dst, -1);
|
||||||
|
write(mMode, "mode", dst, TINYGLTF_MODE_TRIANGLES);
|
||||||
|
write(mIndices, "indices", dst, INVALID_INDEX);
|
||||||
|
write(mAttributes, "attributes", dst);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
And operator= implementations should use "copy":
|
||||||
|
|
||||||
|
```
|
||||||
|
const Primitive& Primitive::operator=(const Value& src)
|
||||||
|
{
|
||||||
|
if (src.is_object())
|
||||||
|
{
|
||||||
|
copy(src, "material", mMaterial);
|
||||||
|
copy(src, "mode", mMode);
|
||||||
|
copy(src, "indices", mIndices);
|
||||||
|
copy(src, "attributes", mAttributes);
|
||||||
|
|
||||||
|
mGLMode = gltf_mode_to_gl_mode(mMode);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Parameters to "write" and "copy" MUST be ordered "src" before "dst"
|
||||||
|
so the code reads as "write src to dst" and "copy src to dst".
|
||||||
|
|
||||||
|
When reading string constants from GLTF json (i.e. "OPAQUE", "TRIANGLES"), these
|
||||||
|
strings should be converted to enums inside operator=. It is permissible to
|
||||||
|
store the original strings during prototyping to aid in development, but eventually
|
||||||
|
we'll purge these strings from the implementation. However, implementations MUST
|
||||||
|
preserve any and all "name" members.
|
||||||
|
|
||||||
|
"write" and "copy" implementations MUST be stored in buffer_util.h.
|
||||||
|
As implementers encounter new data types, you'll see compiler errors
|
||||||
|
pointing at templates in buffer_util.h. See vec3 as a known good
|
||||||
|
example of how to add support for a new type (there are bad examples, so beware):
|
||||||
|
|
||||||
|
```
|
||||||
|
// vec3
|
||||||
|
template<>
|
||||||
|
inline bool copy(const Value& src, vec3& dst)
|
||||||
|
{
|
||||||
|
if (src.is_array())
|
||||||
|
{
|
||||||
|
const boost::json::array& arr = src.as_array();
|
||||||
|
if (arr.size() == 3)
|
||||||
|
{
|
||||||
|
if (arr[0].is_double() &&
|
||||||
|
arr[1].is_double() &&
|
||||||
|
arr[2].is_double())
|
||||||
|
{
|
||||||
|
dst = vec3(arr[0].get_double(), arr[1].get_double(), arr[2].get_double());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline bool write(const vec3& src, Value& dst)
|
||||||
|
{
|
||||||
|
dst = boost::json::array();
|
||||||
|
boost::json::array& arr = dst.as_array();
|
||||||
|
arr.resize(3);
|
||||||
|
arr[0] = src.x;
|
||||||
|
arr[1] = src.y;
|
||||||
|
arr[2] = src.z;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
"write" MUST return true if ANY data was written
|
||||||
|
"copy" MUST return true if ANY data was copied
|
||||||
|
|
||||||
|
Speed is important, but so is safety. In writers, try to avoid redundant copies
|
||||||
|
(prefer resize over push_back, convert dst to an empty array and fill it, don't
|
||||||
|
make an array on the stack and copy it into dst).
|
||||||
|
|
||||||
|
boost::json WILL throw exceptions if you call as_foo() on a mismatched type but
|
||||||
|
WILL NOT throw exceptions on get_foo with a mismatched type. ALWAYS check is_foo
|
||||||
|
before calling as_foo or get_foo. DO NOT add exception handlers. If boost throws
|
||||||
|
an exception in serialization, the fix is to add type checks. If we see a large
|
||||||
|
number of crash reports from boost::json exceptions, each of those reports
|
||||||
|
indicates a place where we're missing "is_foo" checks. They are gold. Do not
|
||||||
|
bury them with an exception handler.
|
||||||
|
|
||||||
|
DO NOT rely on existing type conversion tools in the LL codebase -- LL data models
|
||||||
|
conflict with the GLTF specification so we MUST provide conversions independent of
|
||||||
|
our existing implementations.
|
||||||
|
|
||||||
|
### JSON Serialization ###
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
NEVER include buffer_util.h from a header.
|
||||||
|
|
||||||
|
Loading from and saving to disk (import/export) is currently done using tinygltf, but this is not a long term
|
||||||
|
solution. Eventually the implementation should rely solely on boost::json for reading and writing .gltf
|
||||||
|
files and should handle .bin files natively.
|
||||||
|
|
||||||
|
When serializing Images and Buffers to the server, clients MUST store a single UUID "uri" field and nothing else.
|
||||||
|
The server MUST reject any data that violates this requirement.
|
||||||
|
|
||||||
|
Clients MUST remove any Images from Buffers prior to upload to the server.
|
||||||
|
Servers MAY reject Assets that contain Buffers with unreferenced data.
|
||||||
|
|
||||||
|
... to be continued.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -27,8 +27,79 @@
|
||||||
#include "../llviewerprecompiledheaders.h"
|
#include "../llviewerprecompiledheaders.h"
|
||||||
|
|
||||||
#include "asset.h"
|
#include "asset.h"
|
||||||
|
#include "buffer_util.h"
|
||||||
|
|
||||||
using namespace LL::GLTF;
|
using namespace LL::GLTF;
|
||||||
|
using namespace boost::json;
|
||||||
|
|
||||||
|
namespace LL
|
||||||
|
{
|
||||||
|
namespace GLTF
|
||||||
|
{
|
||||||
|
Accessor::Type gltf_type_to_enum(const std::string& type)
|
||||||
|
{
|
||||||
|
if (type == "SCALAR")
|
||||||
|
{
|
||||||
|
return Accessor::Type::SCALAR;
|
||||||
|
}
|
||||||
|
else if (type == "VEC2")
|
||||||
|
{
|
||||||
|
return Accessor::Type::VEC2;
|
||||||
|
}
|
||||||
|
else if (type == "VEC3")
|
||||||
|
{
|
||||||
|
return Accessor::Type::VEC3;
|
||||||
|
}
|
||||||
|
else if (type == "VEC4")
|
||||||
|
{
|
||||||
|
return Accessor::Type::VEC4;
|
||||||
|
}
|
||||||
|
else if (type == "MAT2")
|
||||||
|
{
|
||||||
|
return Accessor::Type::MAT2;
|
||||||
|
}
|
||||||
|
else if (type == "MAT3")
|
||||||
|
{
|
||||||
|
return Accessor::Type::MAT3;
|
||||||
|
}
|
||||||
|
else if (type == "MAT4")
|
||||||
|
{
|
||||||
|
return Accessor::Type::MAT4;
|
||||||
|
}
|
||||||
|
|
||||||
|
LL_WARNS("GLTF") << "Unknown accessor type: " << type << LL_ENDL;
|
||||||
|
llassert(false);
|
||||||
|
|
||||||
|
return Accessor::Type::SCALAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string enum_to_gltf_type(Accessor::Type type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case Accessor::Type::SCALAR:
|
||||||
|
return "SCALAR";
|
||||||
|
case Accessor::Type::VEC2:
|
||||||
|
return "VEC2";
|
||||||
|
case Accessor::Type::VEC3:
|
||||||
|
return "VEC3";
|
||||||
|
case Accessor::Type::VEC4:
|
||||||
|
return "VEC4";
|
||||||
|
case Accessor::Type::MAT2:
|
||||||
|
return "MAT2";
|
||||||
|
case Accessor::Type::MAT3:
|
||||||
|
return "MAT3";
|
||||||
|
case Accessor::Type::MAT4:
|
||||||
|
return "MAT4";
|
||||||
|
}
|
||||||
|
|
||||||
|
LL_WARNS("GLTF") << "Unknown accessor type: " << (S32)type << LL_ENDL;
|
||||||
|
llassert(false);
|
||||||
|
|
||||||
|
return "SCALAR";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Buffer::erase(Asset& asset, S32 offset, S32 length)
|
void Buffer::erase(Asset& asset, S32 offset, S32 length)
|
||||||
{
|
{
|
||||||
|
|
@ -48,6 +119,27 @@ void Buffer::erase(Asset& asset, S32 offset, S32 length)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Buffer::serialize(object& dst) const
|
||||||
|
{
|
||||||
|
write(mName, "name", dst);
|
||||||
|
write(mUri, "uri", dst);
|
||||||
|
write_always(mByteLength, "byteLength", dst);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Buffer& Buffer::operator=(const Value& src)
|
||||||
|
{
|
||||||
|
if (src.is_object())
|
||||||
|
{
|
||||||
|
copy(src, "name", mName);
|
||||||
|
copy(src, "uri", mUri);
|
||||||
|
|
||||||
|
// NOTE: DO NOT attempt to handle the uri here.
|
||||||
|
// The uri is a reference to a file that is not loaded until
|
||||||
|
// after the json document is parsed
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
const Buffer& Buffer::operator=(const tinygltf::Buffer& src)
|
const Buffer& Buffer::operator=(const tinygltf::Buffer& src)
|
||||||
{
|
{
|
||||||
mData = src.data;
|
mData = src.data;
|
||||||
|
|
@ -56,6 +148,31 @@ const Buffer& Buffer::operator=(const tinygltf::Buffer& src)
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BufferView::serialize(object& dst) const
|
||||||
|
{
|
||||||
|
write_always(mBuffer, "buffer", dst);
|
||||||
|
write_always(mByteLength, "byteLength", dst);
|
||||||
|
write(mByteOffset, "byteOffset", dst, 0);
|
||||||
|
write(mByteStride, "byteStride", dst, 0);
|
||||||
|
write(mTarget, "target", dst, -1);
|
||||||
|
write(mName, "name", dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
const BufferView& BufferView::operator=(const Value& src)
|
||||||
|
{
|
||||||
|
if (src.is_object())
|
||||||
|
{
|
||||||
|
copy(src, "buffer", mBuffer);
|
||||||
|
copy(src, "byteLength", mByteLength);
|
||||||
|
copy(src, "byteOffset", mByteOffset);
|
||||||
|
copy(src, "byteStride", mByteStride);
|
||||||
|
copy(src, "target", mTarget);
|
||||||
|
copy(src, "name", mName);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
const BufferView& BufferView::operator=(const tinygltf::BufferView& src)
|
const BufferView& BufferView::operator=(const tinygltf::BufferView& src)
|
||||||
{
|
{
|
||||||
mBuffer = src.buffer;
|
mBuffer = src.buffer;
|
||||||
|
|
@ -67,13 +184,69 @@ const BufferView& BufferView::operator=(const tinygltf::BufferView& src)
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Accessor::Type tinygltf_type_to_enum(S32 type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case TINYGLTF_TYPE_SCALAR:
|
||||||
|
return Accessor::Type::SCALAR;
|
||||||
|
case TINYGLTF_TYPE_VEC2:
|
||||||
|
return Accessor::Type::VEC2;
|
||||||
|
case TINYGLTF_TYPE_VEC3:
|
||||||
|
return Accessor::Type::VEC3;
|
||||||
|
case TINYGLTF_TYPE_VEC4:
|
||||||
|
return Accessor::Type::VEC4;
|
||||||
|
case TINYGLTF_TYPE_MAT2:
|
||||||
|
return Accessor::Type::MAT2;
|
||||||
|
case TINYGLTF_TYPE_MAT3:
|
||||||
|
return Accessor::Type::MAT3;
|
||||||
|
case TINYGLTF_TYPE_MAT4:
|
||||||
|
return Accessor::Type::MAT4;
|
||||||
|
}
|
||||||
|
|
||||||
|
LL_WARNS("GLTF") << "Unknown tinygltf accessor type: " << type << LL_ENDL;
|
||||||
|
llassert(false);
|
||||||
|
|
||||||
|
return Accessor::Type::SCALAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Accessor::serialize(object& dst) const
|
||||||
|
{
|
||||||
|
write(mName, "name", dst);
|
||||||
|
write(mBufferView, "bufferView", dst, INVALID_INDEX);
|
||||||
|
write(mByteOffset, "byteOffset", dst, 0);
|
||||||
|
write_always(mComponentType, "componentType", dst);
|
||||||
|
write_always(mCount, "count", dst);
|
||||||
|
write_always(enum_to_gltf_type(mType), "type", dst);
|
||||||
|
write(mNormalized, "normalized", dst, false);
|
||||||
|
write(mMax, "max", dst);
|
||||||
|
write(mMin, "min", dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Accessor& Accessor::operator=(const Value& src)
|
||||||
|
{
|
||||||
|
if (src.is_object())
|
||||||
|
{
|
||||||
|
copy(src, "name", mName);
|
||||||
|
copy(src, "bufferView", mBufferView);
|
||||||
|
copy(src, "byteOffset", mByteOffset);
|
||||||
|
copy(src, "componentType", mComponentType);
|
||||||
|
copy(src, "count", mCount);
|
||||||
|
copy(src, "type", mType);
|
||||||
|
copy(src, "normalized", mNormalized);
|
||||||
|
copy(src, "max", mMax);
|
||||||
|
copy(src, "min", mMin);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
const Accessor& Accessor::operator=(const tinygltf::Accessor& src)
|
const Accessor& Accessor::operator=(const tinygltf::Accessor& src)
|
||||||
{
|
{
|
||||||
mBufferView = src.bufferView;
|
mBufferView = src.bufferView;
|
||||||
mByteOffset = src.byteOffset;
|
mByteOffset = src.byteOffset;
|
||||||
mComponentType = src.componentType;
|
mComponentType = src.componentType;
|
||||||
mCount = src.count;
|
mCount = src.count;
|
||||||
mType = src.type;
|
mType = tinygltf_type_to_enum(src.type);
|
||||||
mNormalized = src.normalized;
|
mNormalized = src.normalized;
|
||||||
mName = src.name;
|
mName = src.name;
|
||||||
mMax = src.maxValues;
|
mMax = src.maxValues;
|
||||||
|
|
|
||||||
|
|
@ -28,14 +28,15 @@
|
||||||
|
|
||||||
#include "../lltinygltfhelper.h"
|
#include "../lltinygltfhelper.h"
|
||||||
#include "llstrider.h"
|
#include "llstrider.h"
|
||||||
|
#include "boost/json.hpp"
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
// LL GLTF Implementation
|
// LL GLTF Implementation
|
||||||
namespace LL
|
namespace LL
|
||||||
{
|
{
|
||||||
namespace GLTF
|
namespace GLTF
|
||||||
{
|
{
|
||||||
class Asset;
|
|
||||||
|
|
||||||
constexpr S32 INVALID_INDEX = -1;
|
constexpr S32 INVALID_INDEX = -1;
|
||||||
|
|
||||||
class Buffer
|
class Buffer
|
||||||
|
|
@ -44,11 +45,14 @@ namespace LL
|
||||||
std::vector<U8> mData;
|
std::vector<U8> mData;
|
||||||
std::string mName;
|
std::string mName;
|
||||||
std::string mUri;
|
std::string mUri;
|
||||||
|
S32 mByteLength = 0;
|
||||||
|
|
||||||
// erase the given range from this buffer.
|
// erase the given range from this buffer.
|
||||||
// also updates all buffer views in given asset that reference this buffer
|
// also updates all buffer views in given asset that reference this buffer
|
||||||
void erase(Asset& asset, S32 offset, S32 length);
|
void erase(Asset& asset, S32 offset, S32 length);
|
||||||
|
|
||||||
|
void serialize(boost::json::object& obj) const;
|
||||||
|
const Buffer& operator=(const Value& value);
|
||||||
const Buffer& operator=(const tinygltf::Buffer& src);
|
const Buffer& operator=(const tinygltf::Buffer& src);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -56,25 +60,25 @@ namespace LL
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
S32 mBuffer = INVALID_INDEX;
|
S32 mBuffer = INVALID_INDEX;
|
||||||
S32 mByteLength;
|
S32 mByteLength = 0;
|
||||||
S32 mByteOffset;
|
S32 mByteOffset = 0;
|
||||||
S32 mByteStride;
|
S32 mByteStride = 0;
|
||||||
S32 mTarget;
|
S32 mTarget = -1;
|
||||||
S32 mComponentType;
|
|
||||||
|
|
||||||
std::string mName;
|
std::string mName;
|
||||||
|
|
||||||
|
void serialize(boost::json::object& obj) const;
|
||||||
|
const BufferView& operator=(const Value& value);
|
||||||
const BufferView& operator=(const tinygltf::BufferView& src);
|
const BufferView& operator=(const tinygltf::BufferView& src);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Accessor
|
class Accessor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
S32 mBufferView = INVALID_INDEX;
|
S32 mBufferView = INVALID_INDEX;
|
||||||
S32 mByteOffset;
|
S32 mByteOffset = 0;
|
||||||
S32 mComponentType;
|
S32 mComponentType = 0;
|
||||||
S32 mCount;
|
S32 mCount = 0;
|
||||||
std::vector<double> mMax;
|
std::vector<double> mMax;
|
||||||
std::vector<double> mMin;
|
std::vector<double> mMin;
|
||||||
|
|
||||||
|
|
@ -89,11 +93,19 @@ namespace LL
|
||||||
MAT4 = TINYGLTF_TYPE_MAT4
|
MAT4 = TINYGLTF_TYPE_MAT4
|
||||||
};
|
};
|
||||||
|
|
||||||
S32 mType;
|
Type mType = Type::SCALAR;
|
||||||
bool mNormalized;
|
bool mNormalized = false;
|
||||||
std::string mName;
|
std::string mName;
|
||||||
|
|
||||||
|
void serialize(boost::json::object& obj) const;
|
||||||
|
const Accessor& operator=(const Value& value);
|
||||||
const Accessor& operator=(const tinygltf::Accessor& src);
|
const Accessor& operator=(const tinygltf::Accessor& src);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// convert from "SCALAR", "VEC2", etc to Accessor::Type
|
||||||
|
Accessor::Type gltf_type_to_enum(const std::string& type);
|
||||||
|
|
||||||
|
// convert from Accessor::Type to "SCALAR", "VEC2", etc
|
||||||
|
std::string enum_to_gltf_type(Accessor::Type type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@
|
||||||
#include "buffer_util.h"
|
#include "buffer_util.h"
|
||||||
|
|
||||||
using namespace LL::GLTF;
|
using namespace LL::GLTF;
|
||||||
|
using namespace boost::json;
|
||||||
|
|
||||||
void Animation::allocateGLResources(Asset& asset)
|
void Animation::allocateGLResources(Asset& asset)
|
||||||
{
|
{
|
||||||
|
|
@ -84,7 +85,6 @@ void Animation::apply(Asset& asset, float time)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
void Animation::Sampler::allocateGLResources(Asset& asset)
|
void Animation::Sampler::allocateGLResources(Asset& asset)
|
||||||
{
|
{
|
||||||
Accessor& accessor = asset.mAccessors[mInput];
|
Accessor& accessor = asset.mAccessors[mInput];
|
||||||
|
|
@ -97,8 +97,96 @@ void Animation::Sampler::allocateGLResources(Asset& asset)
|
||||||
copy(asset, accessor, frame_times);
|
copy(asset, accessor, frame_times);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Animation::Sampler::serialize(object& obj) const
|
||||||
|
{
|
||||||
|
write(mInput, "input", obj, INVALID_INDEX);
|
||||||
|
write(mOutput, "output", obj, INVALID_INDEX);
|
||||||
|
write(mInterpolation, "interpolation", obj, std::string("LINEAR"));
|
||||||
|
write(mMinTime, "min_time", obj);
|
||||||
|
write(mMaxTime, "max_time", obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Animation::Sampler& Animation::Sampler::operator=(const Value& src)
|
||||||
|
{
|
||||||
|
if (src.is_object())
|
||||||
|
{
|
||||||
|
copy(src, "input", mInput);
|
||||||
|
copy(src, "output", mOutput);
|
||||||
|
copy(src, "interpolation", mInterpolation);
|
||||||
|
copy(src, "min_time", mMinTime);
|
||||||
|
copy(src, "max_time", mMaxTime);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const Animation::Sampler& Animation::Sampler::operator=(const tinygltf::AnimationSampler& src)
|
||||||
|
{
|
||||||
|
mInput = src.input;
|
||||||
|
mOutput = src.output;
|
||||||
|
mInterpolation = src.interpolation;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Animation::Channel::Target::operator==(const Channel::Target& rhs) const
|
||||||
|
{
|
||||||
|
return mNode == rhs.mNode && mPath == rhs.mPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Animation::Channel::Target::operator!=(const Channel::Target& rhs) const
|
||||||
|
{
|
||||||
|
return !(*this == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Animation::Channel::Target::serialize(object& obj) const
|
||||||
|
{
|
||||||
|
write(mNode, "node", obj, INVALID_INDEX);
|
||||||
|
write(mPath, "path", obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Animation::Channel::Target& Animation::Channel::Target::operator=(const Value& src)
|
||||||
|
{
|
||||||
|
if (src.is_object())
|
||||||
|
{
|
||||||
|
copy(src, "node", mNode);
|
||||||
|
copy(src, "path", mPath);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Animation::Channel::serialize(object& obj) const
|
||||||
|
{
|
||||||
|
write(mSampler, "sampler", obj, INVALID_INDEX);
|
||||||
|
write(mTarget, "target", obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Animation::Channel& Animation::Channel::operator=(const Value& src)
|
||||||
|
{
|
||||||
|
if (src.is_object())
|
||||||
|
{
|
||||||
|
copy(src, "sampler", mSampler);
|
||||||
|
copy(src, "target", mTarget);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Animation::Channel& Animation::Channel::operator=(const tinygltf::AnimationChannel& src)
|
||||||
|
{
|
||||||
|
mSampler = src.sampler;
|
||||||
|
|
||||||
|
mTarget.mNode = src.target_node;
|
||||||
|
mTarget.mPath = src.target_path;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Animation::Sampler::getFrameInfo(Asset& asset, F32 time, U32& frameIndex, F32& t)
|
void Animation::Sampler::getFrameInfo(Asset& asset, F32 time, U32& frameIndex, F32& t)
|
||||||
{
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED;
|
||||||
|
|
||||||
if (time < mMinTime)
|
if (time < mMinTime)
|
||||||
{
|
{
|
||||||
frameIndex = 0;
|
frameIndex = 0;
|
||||||
|
|
@ -158,13 +246,11 @@ void Animation::RotationChannel::apply(Asset& asset, Sampler& sampler, F32 time)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// interpolate
|
// interpolate
|
||||||
LLQuaternion q0(mRotations[frameIndex].get_value());
|
quat qf = glm::slerp(mRotations[frameIndex], mRotations[frameIndex + 1], t);
|
||||||
LLQuaternion q1(mRotations[frameIndex + 1].get_value());
|
|
||||||
|
|
||||||
LLQuaternion qf = slerp(t, q0, q1);
|
qf = glm::normalize(qf);
|
||||||
|
|
||||||
qf.normalize();
|
node.setRotation(qf);
|
||||||
node.setRotation(glh::quaternionf(qf.mQ));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -191,10 +277,10 @@ void Animation::TranslationChannel::apply(Asset& asset, Sampler& sampler, F32 ti
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// interpolate
|
// interpolate
|
||||||
const glh::vec3f& v0 = mTranslations[frameIndex];
|
const vec3& v0 = mTranslations[frameIndex];
|
||||||
const glh::vec3f& v1 = mTranslations[frameIndex + 1];
|
const vec3& v1 = mTranslations[frameIndex + 1];
|
||||||
|
|
||||||
glh::vec3f vf = v0 + t * (v1 - v0);
|
vec3 vf = v0 + t * (v1 - v0);
|
||||||
|
|
||||||
node.setTranslation(vf);
|
node.setTranslation(vf);
|
||||||
}
|
}
|
||||||
|
|
@ -223,15 +309,61 @@ void Animation::ScaleChannel::apply(Asset& asset, Sampler& sampler, F32 time)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// interpolate
|
// interpolate
|
||||||
const glh::vec3f& v0 = mScales[frameIndex];
|
const vec3& v0 = mScales[frameIndex];
|
||||||
const glh::vec3f& v1 = mScales[frameIndex + 1];
|
const vec3& v1 = mScales[frameIndex + 1];
|
||||||
|
|
||||||
glh::vec3f vf = v0 + t * (v1 - v0);
|
vec3 vf = v0 + t * (v1 - v0);
|
||||||
|
|
||||||
node.setScale(vf);
|
node.setScale(vf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Animation::serialize(object& obj) const
|
||||||
|
{
|
||||||
|
write(mName, "name", obj);
|
||||||
|
write(mSamplers, "samplers", obj);
|
||||||
|
|
||||||
|
std::vector<Channel> channels;
|
||||||
|
channels.insert(channels.end(), mRotationChannels.begin(), mRotationChannels.end());
|
||||||
|
channels.insert(channels.end(), mTranslationChannels.begin(), mTranslationChannels.end());
|
||||||
|
channels.insert(channels.end(), mScaleChannels.begin(), mScaleChannels.end());
|
||||||
|
|
||||||
|
write(channels, "channels", obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Animation& Animation::operator=(const Value& src)
|
||||||
|
{
|
||||||
|
if (src.is_object())
|
||||||
|
{
|
||||||
|
const object& obj = src.as_object();
|
||||||
|
|
||||||
|
copy(obj, "name", mName);
|
||||||
|
copy(obj, "samplers", mSamplers);
|
||||||
|
|
||||||
|
// make a temporory copy of generic channels
|
||||||
|
std::vector<Channel> channels;
|
||||||
|
copy(obj, "channels", channels);
|
||||||
|
|
||||||
|
// break up into channel specific implementations
|
||||||
|
for (auto& channel: channels)
|
||||||
|
{
|
||||||
|
if (channel.mTarget.mPath == "rotation")
|
||||||
|
{
|
||||||
|
mRotationChannels.push_back(channel);
|
||||||
|
}
|
||||||
|
else if (channel.mTarget.mPath == "translation")
|
||||||
|
{
|
||||||
|
mTranslationChannels.push_back(channel);
|
||||||
|
}
|
||||||
|
else if (channel.mTarget.mPath == "scale")
|
||||||
|
{
|
||||||
|
mScaleChannels.push_back(channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
const Animation& Animation::operator=(const tinygltf::Animation& src)
|
const Animation& Animation::operator=(const tinygltf::Animation& src)
|
||||||
{
|
{
|
||||||
mName = src.name;
|
mName = src.name;
|
||||||
|
|
@ -275,6 +407,18 @@ void Skin::allocateGLResources(Asset& asset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Skin& Skin::operator=(const Value& src)
|
||||||
|
{
|
||||||
|
if (src.is_object())
|
||||||
|
{
|
||||||
|
copy(src, "name", mName);
|
||||||
|
copy(src, "skeleton", mSkeleton);
|
||||||
|
copy(src, "inverseBindMatrices", mInverseBindMatrices);
|
||||||
|
copy(src, "joints", mJoints);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
const Skin& Skin::operator=(const tinygltf::Skin& src)
|
const Skin& Skin::operator=(const tinygltf::Skin& src)
|
||||||
{
|
{
|
||||||
mName = src.name;
|
mName = src.name;
|
||||||
|
|
@ -285,3 +429,10 @@ const Skin& Skin::operator=(const tinygltf::Skin& src)
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Skin::serialize(object& obj) const
|
||||||
|
{
|
||||||
|
write(mInverseBindMatrices, "inverseBindMatrices", obj, INVALID_INDEX);
|
||||||
|
write(mJoints, "joints", obj);
|
||||||
|
write(mName, "name", obj);
|
||||||
|
write(mSkeleton, "skeleton", obj, INVALID_INDEX);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "accessor.h"
|
#include "accessor.h"
|
||||||
|
|
||||||
// LL GLTF Implementation
|
// LL GLTF Implementation
|
||||||
namespace LL
|
namespace LL
|
||||||
{
|
{
|
||||||
|
|
@ -52,14 +51,10 @@ namespace LL
|
||||||
|
|
||||||
void allocateGLResources(Asset& asset);
|
void allocateGLResources(Asset& asset);
|
||||||
|
|
||||||
const Sampler& operator=(const tinygltf::AnimationSampler& src)
|
void serialize(boost::json::object& dst) const;
|
||||||
{
|
const Sampler& operator=(const Value& value);
|
||||||
mInput = src.input;
|
const Sampler& operator=(const tinygltf::AnimationSampler& src);
|
||||||
mOutput = src.output;
|
|
||||||
mInterpolation = src.interpolation;
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the frame index and time for the specified time
|
// get the frame index and time for the specified time
|
||||||
// asset -- the asset to reference for Accessors
|
// asset -- the asset to reference for Accessors
|
||||||
|
|
@ -77,27 +72,29 @@ namespace LL
|
||||||
public:
|
public:
|
||||||
S32 mNode = INVALID_INDEX;
|
S32 mNode = INVALID_INDEX;
|
||||||
std::string mPath;
|
std::string mPath;
|
||||||
|
|
||||||
|
bool operator==(const Target& other) const;
|
||||||
|
bool operator!=(const Target& other) const;
|
||||||
|
|
||||||
|
void serialize(boost::json::object& dst) const;
|
||||||
|
const Target& operator=(const Value& value);
|
||||||
};
|
};
|
||||||
|
|
||||||
S32 mSampler = INVALID_INDEX;
|
S32 mSampler = INVALID_INDEX;
|
||||||
Target mTarget;
|
Target mTarget;
|
||||||
|
|
||||||
const Channel& operator=(const tinygltf::AnimationChannel& src)
|
void serialize(boost::json::object& dst) const;
|
||||||
{
|
const Channel& operator=(const Value& value);
|
||||||
mSampler = src.sampler;
|
const Channel& operator=(const tinygltf::AnimationChannel& src);
|
||||||
|
|
||||||
mTarget.mNode = src.target_node;
|
|
||||||
mTarget.mPath = src.target_path;
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class RotationChannel : public Channel
|
class RotationChannel : public Channel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
std::vector<glh::quaternionf> mRotations;
|
RotationChannel() = default;
|
||||||
|
RotationChannel(const Channel& channel) : Channel(channel) {}
|
||||||
|
|
||||||
|
std::vector<quat> mRotations;
|
||||||
|
|
||||||
const RotationChannel& operator=(const tinygltf::AnimationChannel& src)
|
const RotationChannel& operator=(const tinygltf::AnimationChannel& src)
|
||||||
{
|
{
|
||||||
|
|
@ -116,7 +113,10 @@ namespace LL
|
||||||
class TranslationChannel : public Channel
|
class TranslationChannel : public Channel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
std::vector<glh::vec3f> mTranslations;
|
TranslationChannel() = default;
|
||||||
|
TranslationChannel(const Channel& channel) : Channel(channel) {}
|
||||||
|
|
||||||
|
std::vector<vec3> mTranslations;
|
||||||
|
|
||||||
const TranslationChannel& operator=(const tinygltf::AnimationChannel& src)
|
const TranslationChannel& operator=(const tinygltf::AnimationChannel& src)
|
||||||
{
|
{
|
||||||
|
|
@ -135,7 +135,10 @@ namespace LL
|
||||||
class ScaleChannel : public Channel
|
class ScaleChannel : public Channel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
std::vector<glh::vec3f> mScales;
|
ScaleChannel() = default;
|
||||||
|
ScaleChannel(const Channel& channel) : Channel(channel) {}
|
||||||
|
|
||||||
|
std::vector<vec3> mScales;
|
||||||
|
|
||||||
const ScaleChannel& operator=(const tinygltf::AnimationChannel& src)
|
const ScaleChannel& operator=(const tinygltf::AnimationChannel& src)
|
||||||
{
|
{
|
||||||
|
|
@ -165,6 +168,8 @@ namespace LL
|
||||||
std::vector<TranslationChannel> mTranslationChannels;
|
std::vector<TranslationChannel> mTranslationChannels;
|
||||||
std::vector<ScaleChannel> mScaleChannels;
|
std::vector<ScaleChannel> mScaleChannels;
|
||||||
|
|
||||||
|
void serialize(boost::json::object& dst) const;
|
||||||
|
const Animation& operator=(const Value& value);
|
||||||
const Animation& operator=(const tinygltf::Animation& src);
|
const Animation& operator=(const tinygltf::Animation& src);
|
||||||
|
|
||||||
void allocateGLResources(Asset& asset);
|
void allocateGLResources(Asset& asset);
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -32,9 +32,16 @@
|
||||||
#include "accessor.h"
|
#include "accessor.h"
|
||||||
#include "primitive.h"
|
#include "primitive.h"
|
||||||
#include "animation.h"
|
#include "animation.h"
|
||||||
|
#include "boost/json.hpp"
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
extern F32SecondsImplicit gFrameTimeSeconds;
|
extern F32SecondsImplicit gFrameTimeSeconds;
|
||||||
|
|
||||||
|
// wingdi defines OPAQUE, which conflicts with our enum
|
||||||
|
#if defined(OPAQUE)
|
||||||
|
#undef OPAQUE
|
||||||
|
#endif
|
||||||
|
|
||||||
// LL GLTF Implementation
|
// LL GLTF Implementation
|
||||||
namespace LL
|
namespace LL
|
||||||
{
|
{
|
||||||
|
|
@ -45,13 +52,26 @@ namespace LL
|
||||||
class Material
|
class Material
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
enum class AlphaMode
|
||||||
|
{
|
||||||
|
OPAQUE,
|
||||||
|
MASK,
|
||||||
|
BLEND
|
||||||
|
};
|
||||||
|
|
||||||
class TextureInfo
|
class TextureInfo
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
S32 mIndex = INVALID_INDEX;
|
S32 mIndex = INVALID_INDEX;
|
||||||
S32 mTexCoord = 0;
|
S32 mTexCoord = 0;
|
||||||
|
|
||||||
|
bool operator==(const TextureInfo& rhs) const;
|
||||||
|
bool operator!=(const TextureInfo& rhs) const;
|
||||||
|
|
||||||
const TextureInfo& operator=(const tinygltf::TextureInfo& src);
|
const TextureInfo& operator=(const tinygltf::TextureInfo& src);
|
||||||
|
const TextureInfo& operator=(const Value& src);
|
||||||
|
void serialize(boost::json::object& dst) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class NormalTextureInfo : public TextureInfo
|
class NormalTextureInfo : public TextureInfo
|
||||||
|
|
@ -60,6 +80,8 @@ namespace LL
|
||||||
F32 mScale = 1.0f;
|
F32 mScale = 1.0f;
|
||||||
|
|
||||||
const NormalTextureInfo& operator=(const tinygltf::NormalTextureInfo& src);
|
const NormalTextureInfo& operator=(const tinygltf::NormalTextureInfo& src);
|
||||||
|
const NormalTextureInfo& operator=(const Value& src);
|
||||||
|
void serialize(boost::json::object& dst) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class OcclusionTextureInfo : public TextureInfo
|
class OcclusionTextureInfo : public TextureInfo
|
||||||
|
|
@ -68,17 +90,24 @@ namespace LL
|
||||||
F32 mStrength = 1.0f;
|
F32 mStrength = 1.0f;
|
||||||
|
|
||||||
const OcclusionTextureInfo& operator=(const tinygltf::OcclusionTextureInfo& src);
|
const OcclusionTextureInfo& operator=(const tinygltf::OcclusionTextureInfo& src);
|
||||||
|
const OcclusionTextureInfo& operator=(const Value& src);
|
||||||
|
void serialize(boost::json::object& dst) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PbrMetallicRoughness
|
class PbrMetallicRoughness
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
glh::vec4f mBaseColorFactor = glh::vec4f(1.f,1.f,1.f,1.f);
|
vec4 mBaseColorFactor = vec4(1.f,1.f,1.f,1.f);
|
||||||
TextureInfo mBaseColorTexture;
|
TextureInfo mBaseColorTexture;
|
||||||
F32 mMetallicFactor = 1.0f;
|
F32 mMetallicFactor = 1.0f;
|
||||||
F32 mRoughnessFactor = 1.0f;
|
F32 mRoughnessFactor = 1.0f;
|
||||||
TextureInfo mMetallicRoughnessTexture;
|
TextureInfo mMetallicRoughnessTexture;
|
||||||
|
|
||||||
|
bool operator==(const PbrMetallicRoughness& rhs) const;
|
||||||
|
bool operator!=(const PbrMetallicRoughness& rhs) const;
|
||||||
const PbrMetallicRoughness& operator=(const tinygltf::PbrMetallicRoughness& src);
|
const PbrMetallicRoughness& operator=(const tinygltf::PbrMetallicRoughness& src);
|
||||||
|
const PbrMetallicRoughness& operator=(const Value& src);
|
||||||
|
void serialize(boost::json::object& dst) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -93,13 +122,16 @@ namespace LL
|
||||||
|
|
||||||
|
|
||||||
std::string mName;
|
std::string mName;
|
||||||
glh::vec3f mEmissiveFactor = glh::vec3f(0.f, 0.f, 0.f);
|
vec3 mEmissiveFactor = vec3(0.f, 0.f, 0.f);
|
||||||
std::string mAlphaMode = "OPAQUE";
|
AlphaMode mAlphaMode = AlphaMode::OPAQUE;
|
||||||
F32 mAlphaCutoff = 0.5f;
|
F32 mAlphaCutoff = 0.5f;
|
||||||
bool mDoubleSided = false;
|
bool mDoubleSided = false;
|
||||||
|
|
||||||
|
// bind for rendering
|
||||||
|
void bind(Asset& asset);
|
||||||
const Material& operator=(const tinygltf::Material& src);
|
const Material& operator=(const tinygltf::Material& src);
|
||||||
|
const Material& operator=(const Value& src);
|
||||||
|
void serialize(boost::json::object& dst) const;
|
||||||
|
|
||||||
void allocateGLResources(Asset& asset);
|
void allocateGLResources(Asset& asset);
|
||||||
};
|
};
|
||||||
|
|
@ -112,6 +144,8 @@ namespace LL
|
||||||
std::string mName;
|
std::string mName;
|
||||||
|
|
||||||
const Mesh& operator=(const tinygltf::Mesh& src);
|
const Mesh& operator=(const tinygltf::Mesh& src);
|
||||||
|
const Mesh& operator=(const Value& src);
|
||||||
|
void serialize(boost::json::object& dst) const;
|
||||||
|
|
||||||
void allocateGLResources(Asset& asset);
|
void allocateGLResources(Asset& asset);
|
||||||
};
|
};
|
||||||
|
|
@ -119,14 +153,14 @@ namespace LL
|
||||||
class Node
|
class Node
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
LLMatrix4a mMatrix; //local transform
|
mat4 mMatrix = glm::identity<mat4>(); //local transform
|
||||||
LLMatrix4a mRenderMatrix; //transform for rendering
|
mat4 mRenderMatrix; //transform for rendering
|
||||||
LLMatrix4a mAssetMatrix; //transform from local to asset space
|
mat4 mAssetMatrix; //transform from local to asset space
|
||||||
LLMatrix4a mAssetMatrixInv; //transform from asset to local space
|
mat4 mAssetMatrixInv; //transform from asset to local space
|
||||||
|
|
||||||
glh::vec3f mTranslation;
|
vec3 mTranslation = vec3(0,0,0);
|
||||||
glh::quaternionf mRotation;
|
quat mRotation = glm::identity<quat>();
|
||||||
glh::vec3f mScale;
|
vec3 mScale = vec3(1.f,1.f,1.f);
|
||||||
|
|
||||||
// if true, mMatrix is valid and up to date
|
// if true, mMatrix is valid and up to date
|
||||||
bool mMatrixValid = false;
|
bool mMatrixValid = false;
|
||||||
|
|
@ -145,13 +179,15 @@ namespace LL
|
||||||
std::string mName;
|
std::string mName;
|
||||||
|
|
||||||
const Node& operator=(const tinygltf::Node& src);
|
const Node& operator=(const tinygltf::Node& src);
|
||||||
|
const Node& operator=(const Value& src);
|
||||||
|
void serialize(boost::json::object& dst) const;
|
||||||
|
|
||||||
// Set mRenderMatrix to a transform that can be used for the current render pass
|
// Set mRenderMatrix to a transform that can be used for the current render pass
|
||||||
// modelview -- parent's render matrix
|
// modelview -- parent's render matrix
|
||||||
void updateRenderTransforms(Asset& asset, const LLMatrix4a& modelview);
|
void updateRenderTransforms(Asset& asset, const mat4& modelview);
|
||||||
|
|
||||||
// update mAssetMatrix and mAssetMatrixInv
|
// update mAssetMatrix and mAssetMatrixInv
|
||||||
void updateTransforms(Asset& asset, const LLMatrix4a& parentMatrix);
|
void updateTransforms(Asset& asset, const mat4& parentMatrix);
|
||||||
|
|
||||||
// ensure mMatrix is valid -- if mMatrixValid is false and mTRSValid is true, will update mMatrix to match Translation/Rotation/Scale
|
// ensure mMatrix is valid -- if mMatrixValid is false and mTRSValid is true, will update mMatrix to match Translation/Rotation/Scale
|
||||||
void makeMatrixValid();
|
void makeMatrixValid();
|
||||||
|
|
@ -161,15 +197,15 @@ namespace LL
|
||||||
|
|
||||||
// Set rotation of this node
|
// Set rotation of this node
|
||||||
// SIDE EFFECT: invalidates mMatrix
|
// SIDE EFFECT: invalidates mMatrix
|
||||||
void setRotation(const glh::quaternionf& rotation);
|
void setRotation(const quat& rotation);
|
||||||
|
|
||||||
// Set translation of this node
|
// Set translation of this node
|
||||||
// SIDE EFFECT: invalidates mMatrix
|
// SIDE EFFECT: invalidates mMatrix
|
||||||
void setTranslation(const glh::vec3f& translation);
|
void setTranslation(const vec3& translation);
|
||||||
|
|
||||||
// Set scale of this node
|
// Set scale of this node
|
||||||
// SIDE EFFECT: invalidates mMatrix
|
// SIDE EFFECT: invalidates mMatrix
|
||||||
void setScale(const glh::vec3f& scale);
|
void setScale(const vec3& scale);
|
||||||
};
|
};
|
||||||
|
|
||||||
class Skin
|
class Skin
|
||||||
|
|
@ -179,12 +215,14 @@ namespace LL
|
||||||
S32 mSkeleton = INVALID_INDEX;
|
S32 mSkeleton = INVALID_INDEX;
|
||||||
std::vector<S32> mJoints;
|
std::vector<S32> mJoints;
|
||||||
std::string mName;
|
std::string mName;
|
||||||
std::vector<glh::matrix4f> mInverseBindMatricesData;
|
std::vector<mat4> mInverseBindMatricesData;
|
||||||
|
|
||||||
void allocateGLResources(Asset& asset);
|
void allocateGLResources(Asset& asset);
|
||||||
void uploadMatrixPalette(Asset& asset, Node& node);
|
void uploadMatrixPalette(Asset& asset, Node& node);
|
||||||
|
|
||||||
const Skin& operator=(const tinygltf::Skin& src);
|
const Skin& operator=(const tinygltf::Skin& src);
|
||||||
|
const Skin& operator=(const Value& src);
|
||||||
|
void serialize(boost::json::object& dst) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Scene
|
class Scene
|
||||||
|
|
@ -194,9 +232,11 @@ namespace LL
|
||||||
std::string mName;
|
std::string mName;
|
||||||
|
|
||||||
const Scene& operator=(const tinygltf::Scene& src);
|
const Scene& operator=(const tinygltf::Scene& src);
|
||||||
|
const Scene& operator=(const Value& src);
|
||||||
|
void serialize(boost::json::object& dst) const;
|
||||||
|
|
||||||
void updateTransforms(Asset& asset);
|
void updateTransforms(Asset& asset);
|
||||||
void updateRenderTransforms(Asset& asset, const LLMatrix4a& modelview);
|
void updateRenderTransforms(Asset& asset, const mat4& modelview);
|
||||||
};
|
};
|
||||||
|
|
||||||
class Texture
|
class Texture
|
||||||
|
|
@ -207,18 +247,22 @@ namespace LL
|
||||||
std::string mName;
|
std::string mName;
|
||||||
|
|
||||||
const Texture& operator=(const tinygltf::Texture& src);
|
const Texture& operator=(const tinygltf::Texture& src);
|
||||||
|
const Texture& operator=(const Value& src);
|
||||||
|
void serialize(boost::json::object& dst) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Sampler
|
class Sampler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
S32 mMagFilter;
|
S32 mMagFilter = LINEAR;
|
||||||
S32 mMinFilter;
|
S32 mMinFilter = LINEAR_MIPMAP_LINEAR;
|
||||||
S32 mWrapS;
|
S32 mWrapS = REPEAT;
|
||||||
S32 mWrapT;
|
S32 mWrapT = REPEAT;
|
||||||
std::string mName;
|
std::string mName;
|
||||||
|
|
||||||
const Sampler& operator=(const tinygltf::Sampler& src);
|
const Sampler& operator=(const tinygltf::Sampler& src);
|
||||||
|
const Sampler& operator=(const Value& src);
|
||||||
|
void serialize(boost::json::object& dst) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Image
|
class Image
|
||||||
|
|
@ -231,43 +275,35 @@ namespace LL
|
||||||
S32 mBufferView = INVALID_INDEX;
|
S32 mBufferView = INVALID_INDEX;
|
||||||
|
|
||||||
std::vector<U8> mData;
|
std::vector<U8> mData;
|
||||||
S32 mWidth;
|
S32 mWidth = -1;
|
||||||
S32 mHeight;
|
S32 mHeight = -1;
|
||||||
S32 mComponent;
|
S32 mComponent = -1;
|
||||||
S32 mBits;
|
S32 mBits = -1;
|
||||||
S32 mPixelType;
|
S32 mPixelType = -1;
|
||||||
|
|
||||||
LLPointer<LLViewerFetchedTexture> mTexture;
|
LLPointer<LLViewerFetchedTexture> mTexture;
|
||||||
|
|
||||||
const Image& operator=(const tinygltf::Image& src)
|
const Image& operator=(const tinygltf::Image& src);
|
||||||
{
|
const Image& operator=(const Value& src);
|
||||||
mName = src.name;
|
void serialize(boost::json::object& dst) const;
|
||||||
mUri = src.uri;
|
|
||||||
mMimeType = src.mimeType;
|
|
||||||
mData = src.image;
|
|
||||||
mWidth = src.width;
|
|
||||||
mHeight = src.height;
|
|
||||||
mComponent = src.component;
|
|
||||||
mBits = src.bits;
|
|
||||||
mBufferView = src.bufferView;
|
|
||||||
mPixelType = src.pixel_type;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// save image clear local data, and set uri
|
// save image clear local data, and set uri
|
||||||
void decompose(Asset& asset, const std::string& filename);
|
void decompose(Asset& asset, const std::string& filename);
|
||||||
|
|
||||||
void allocateGLResources()
|
// erase the buffer view associated with this image
|
||||||
{
|
// free any associated resources
|
||||||
// allocate texture
|
// preserve only uri and name
|
||||||
|
void clearData(Asset& asset);
|
||||||
|
|
||||||
}
|
void allocateGLResources();
|
||||||
};
|
};
|
||||||
|
|
||||||
// C++ representation of a GLTF Asset
|
// C++ representation of a GLTF Asset
|
||||||
class Asset
|
class Asset
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
static const std::string minVersion_default;
|
||||||
std::vector<Scene> mScenes;
|
std::vector<Scene> mScenes;
|
||||||
std::vector<Node> mNodes;
|
std::vector<Node> mNodes;
|
||||||
std::vector<Mesh> mMeshes;
|
std::vector<Mesh> mMeshes;
|
||||||
|
|
@ -287,14 +323,15 @@ namespace LL
|
||||||
std::string mCopyright;
|
std::string mCopyright;
|
||||||
|
|
||||||
S32 mDefaultScene = INVALID_INDEX;
|
S32 mDefaultScene = INVALID_INDEX;
|
||||||
tinygltf::Value mExtras;
|
Value mExtras;
|
||||||
|
|
||||||
|
U32 mPendingBuffers = 0;
|
||||||
|
|
||||||
// the last time update() was called according to gFrameTimeSeconds
|
// the last time update() was called according to gFrameTimeSeconds
|
||||||
F32 mLastUpdateTime = gFrameTimeSeconds;
|
F32 mLastUpdateTime = gFrameTimeSeconds;
|
||||||
|
|
||||||
// prepare the asset for rendering
|
// prepare the asset for rendering
|
||||||
void allocateGLResources(const std::string& filename, const tinygltf::Model& model);
|
void allocateGLResources(const std::string& filename = "", const tinygltf::Model& model = tinygltf::Model());
|
||||||
|
|
||||||
// Called periodically (typically once per frame)
|
// Called periodically (typically once per frame)
|
||||||
// Any ongoing work (such as animations) should be handled here
|
// Any ongoing work (such as animations) should be handled here
|
||||||
|
|
@ -307,7 +344,7 @@ namespace LL
|
||||||
void updateTransforms();
|
void updateTransforms();
|
||||||
|
|
||||||
// update node render transforms
|
// update node render transforms
|
||||||
void updateRenderTransforms(const LLMatrix4a& modelview);
|
void updateRenderTransforms(const mat4& modelview);
|
||||||
|
|
||||||
void render(bool opaque, bool rigged = false);
|
void render(bool opaque, bool rigged = false);
|
||||||
void renderOpaque();
|
void renderOpaque();
|
||||||
|
|
@ -323,7 +360,13 @@ namespace LL
|
||||||
S32* primitive_hitp = nullptr // return the index of the primitive that was hit
|
S32* primitive_hitp = nullptr // return the index of the primitive that was hit
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Asset() = default;
|
||||||
|
Asset(const tinygltf::Model& src);
|
||||||
|
Asset(const Value& src);
|
||||||
|
|
||||||
const Asset& operator=(const tinygltf::Model& src);
|
const Asset& operator=(const tinygltf::Model& src);
|
||||||
|
const Asset& operator=(const Value& src);
|
||||||
|
void serialize(boost::json::object& dst) const;
|
||||||
|
|
||||||
// save the asset to a tinygltf model
|
// save the asset to a tinygltf model
|
||||||
void save(tinygltf::Model& dst);
|
void save(tinygltf::Model& dst);
|
||||||
|
|
@ -335,5 +378,8 @@ namespace LL
|
||||||
// updates all bufferview indices in this Asset as needed
|
// updates all bufferview indices in this Asset as needed
|
||||||
void eraseBufferView(S32 bufferView);
|
void eraseBufferView(S32 bufferView);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Material::AlphaMode gltf_alpha_mode_to_enum(const std::string& alpha_mode);
|
||||||
|
std::string enum_to_gltf_alpha_mode(Material::AlphaMode alpha_mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,55 +36,60 @@
|
||||||
#define LL_FUNCSIG __PRETTY_FUNCTION__
|
#define LL_FUNCSIG __PRETTY_FUNCTION__
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "accessor.h"
|
||||||
|
|
||||||
namespace LL
|
namespace LL
|
||||||
{
|
{
|
||||||
namespace GLTF
|
namespace GLTF
|
||||||
{
|
{
|
||||||
|
|
||||||
|
using string_view = boost::json::string_view;
|
||||||
|
|
||||||
// copy one Scalar from src to dst
|
// copy one Scalar from src to dst
|
||||||
template<class S, class T>
|
template<class S, class T>
|
||||||
static void copyScalar(S* src, T& dst)
|
inline void copyScalar(S* src, T& dst)
|
||||||
{
|
{
|
||||||
LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL;
|
LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy one vec2 from src to dst
|
// copy one vec2 from src to dst
|
||||||
template<class S, class T>
|
template<class S, class T>
|
||||||
static void copyVec2(S* src, T& dst)
|
inline void copyVec2(S* src, T& dst)
|
||||||
{
|
{
|
||||||
LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL;
|
LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy one vec3 from src to dst
|
// copy one vec3 from src to dst
|
||||||
template<class S, class T>
|
template<class S, class T>
|
||||||
static void copyVec3(S* src, T& dst)
|
inline void copyVec3(S* src, T& dst)
|
||||||
{
|
{
|
||||||
LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL;
|
LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy one vec4 from src to dst
|
// copy one vec4 from src to dst
|
||||||
template<class S, class T>
|
template<class S, class T>
|
||||||
static void copyVec4(S* src, T& dst)
|
inline void copyVec4(S* src, T& dst)
|
||||||
{
|
{
|
||||||
LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL;
|
LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy one vec2 from src to dst
|
// copy one mat2 from src to dst
|
||||||
template<class S, class T>
|
template<class S, class T>
|
||||||
static void copyMat2(S* src, T& dst)
|
inline void copyMat2(S* src, T& dst)
|
||||||
{
|
{
|
||||||
LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL;
|
LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy one vec3 from src to dst
|
// copy one mat3 from src to dst
|
||||||
template<class S, class T>
|
template<class S, class T>
|
||||||
static void copyMat3(S* src, T& dst)
|
inline void copyMat3(S* src, T& dst)
|
||||||
{
|
{
|
||||||
LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL;
|
LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy one vec4 from src to dst
|
// copy one mat4 from src to dst
|
||||||
template<class S, class T>
|
template<class S, class T>
|
||||||
static void copyMat4(S* src, T& dst)
|
inline void copyMat4(S* src, T& dst)
|
||||||
{
|
{
|
||||||
LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL;
|
LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL;
|
||||||
}
|
}
|
||||||
|
|
@ -93,135 +98,128 @@ namespace LL
|
||||||
// concrete implementations for different types of source and destination
|
// concrete implementations for different types of source and destination
|
||||||
//=========================================================================================================
|
//=========================================================================================================
|
||||||
|
|
||||||
// suppress unused function warning -- clang complains here but these specializations are definitely used
|
|
||||||
#if defined(__clang__)
|
|
||||||
#pragma clang diagnostic push
|
|
||||||
#pragma clang diagnostic ignored "-Wunused-function"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
void copyScalar<F32, F32>(F32* src, F32& dst)
|
inline void copyScalar<F32, F32>(F32* src, F32& dst)
|
||||||
{
|
{
|
||||||
dst = *src;
|
dst = *src;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
void copyScalar<U32, U32>(U32* src, U32& dst)
|
inline void copyScalar<U32, U32>(U32* src, U32& dst)
|
||||||
{
|
{
|
||||||
dst = *src;
|
dst = *src;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
void copyScalar<U32, U16>(U32* src, U16& dst)
|
inline void copyScalar<U32, U16>(U32* src, U16& dst)
|
||||||
{
|
{
|
||||||
dst = *src;
|
dst = *src;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
void copyScalar<U16, U16>(U16* src, U16& dst)
|
inline void copyScalar<U16, U16>(U16* src, U16& dst)
|
||||||
{
|
{
|
||||||
dst = *src;
|
dst = *src;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
void copyScalar<U16, U32>(U16* src, U32& dst)
|
inline void copyScalar<U16, U32>(U16* src, U32& dst)
|
||||||
{
|
{
|
||||||
dst = *src;
|
dst = *src;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
void copyScalar<U8, U16>(U8* src, U16& dst)
|
inline void copyScalar<U8, U16>(U8* src, U16& dst)
|
||||||
{
|
{
|
||||||
dst = *src;
|
dst = *src;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
void copyScalar<U8, U32>(U8* src, U32& dst)
|
inline void copyScalar<U8, U32>(U8* src, U32& dst)
|
||||||
{
|
{
|
||||||
dst = *src;
|
dst = *src;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
void copyVec2<F32, LLVector2>(F32* src, LLVector2& dst)
|
inline void copyVec2<F32, LLVector2>(F32* src, LLVector2& dst)
|
||||||
{
|
{
|
||||||
dst.set(src[0], src[1]);
|
dst.set(src[0], src[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
void copyVec3<F32, glh::vec3f>(F32* src, glh::vec3f& dst)
|
inline void copyVec3<F32, vec3>(F32* src, vec3& dst)
|
||||||
{
|
{
|
||||||
dst.set_value(src[0], src[1], src[2]);
|
dst = vec3(src[0], src[1], src[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
void copyVec3<F32, LLVector4a>(F32* src, LLVector4a& dst)
|
inline void copyVec3<F32, LLVector4a>(F32* src, LLVector4a& dst)
|
||||||
{
|
{
|
||||||
dst.load3(src);
|
dst.load3(src);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
void copyVec3<U16, LLColor4U>(U16* src, LLColor4U& dst)
|
inline void copyVec3<U16, LLColor4U>(U16* src, LLColor4U& dst)
|
||||||
{
|
{
|
||||||
dst.set(src[0], src[1], src[2], 255);
|
dst.set(src[0], src[1], src[2], 255);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
void copyVec4<U8, LLColor4U>(U8* src, LLColor4U& dst)
|
inline void copyVec4<U8, LLColor4U>(U8* src, LLColor4U& dst)
|
||||||
{
|
{
|
||||||
dst.set(src[0], src[1], src[2], src[3]);
|
dst.set(src[0], src[1], src[2], src[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
void copyVec4<U16, LLColor4U>(U16* src, LLColor4U& dst)
|
inline void copyVec4<U16, LLColor4U>(U16* src, LLColor4U& dst)
|
||||||
{
|
{
|
||||||
dst.set(src[0], src[1], src[2], src[3]);
|
dst.set(src[0], src[1], src[2], src[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
void copyVec4<F32, LLColor4U>(F32* src, LLColor4U& dst)
|
inline void copyVec4<F32, LLColor4U>(F32* src, LLColor4U& dst)
|
||||||
{
|
{
|
||||||
dst.set(src[0]*255, src[1]*255, src[2]*255, src[3]*255);
|
dst.set(src[0]*255, src[1]*255, src[2]*255, src[3]*255);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
void copyVec4<F32, LLVector4a>(F32* src, LLVector4a& dst)
|
inline void copyVec4<F32, LLVector4a>(F32* src, LLVector4a& dst)
|
||||||
{
|
{
|
||||||
dst.loadua(src);
|
dst.loadua(src);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
void copyVec4<U16, LLVector4a>(U16* src, LLVector4a& dst)
|
inline void copyVec4<U16, LLVector4a>(U16* src, LLVector4a& dst)
|
||||||
{
|
{
|
||||||
dst.set(src[0], src[1], src[2], src[3]);
|
dst.set(src[0], src[1], src[2], src[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
void copyVec4<U8, LLVector4a>(U8* src, LLVector4a& dst)
|
inline void copyVec4<U8, LLVector4a>(U8* src, LLVector4a& dst)
|
||||||
{
|
{
|
||||||
dst.set(src[0], src[1], src[2], src[3]);
|
dst.set(src[0], src[1], src[2], src[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
void copyVec4<F32, glh::quaternionf>(F32* src, glh::quaternionf& dst)
|
inline void copyVec4<F32, quat>(F32* src, quat& dst)
|
||||||
{
|
{
|
||||||
dst.set_value(src);
|
dst.x = src[0];
|
||||||
|
dst.y = src[1];
|
||||||
|
dst.z = src[2];
|
||||||
|
dst.w = src[3];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
void copyMat4<F32, glh::matrix4f>(F32* src, glh::matrix4f& dst)
|
inline void copyMat4<F32, mat4>(F32* src, mat4& dst)
|
||||||
{
|
{
|
||||||
dst.set_value(src);
|
dst = glm::make_mat4(src);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__clang__)
|
|
||||||
#pragma clang diagnostic pop
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//=========================================================================================================
|
//=========================================================================================================
|
||||||
|
|
||||||
// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy
|
// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy
|
||||||
template<class S, class T>
|
template<class S, class T>
|
||||||
static void copyScalar(S* src, LLStrider<T> dst, S32 stride, S32 count)
|
inline void copyScalar(S* src, LLStrider<T> dst, S32 stride, S32 count)
|
||||||
{
|
{
|
||||||
for (S32 i = 0; i < count; ++i)
|
for (S32 i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
|
|
@ -233,7 +231,7 @@ namespace LL
|
||||||
|
|
||||||
// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy
|
// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy
|
||||||
template<class S, class T>
|
template<class S, class T>
|
||||||
static void copyVec2(S* src, LLStrider<T> dst, S32 stride, S32 count)
|
inline void copyVec2(S* src, LLStrider<T> dst, S32 stride, S32 count)
|
||||||
{
|
{
|
||||||
for (S32 i = 0; i < count; ++i)
|
for (S32 i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
|
|
@ -245,7 +243,7 @@ namespace LL
|
||||||
|
|
||||||
// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy
|
// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy
|
||||||
template<class S, class T>
|
template<class S, class T>
|
||||||
static void copyVec3(S* src, LLStrider<T> dst, S32 stride, S32 count)
|
inline void copyVec3(S* src, LLStrider<T> dst, S32 stride, S32 count)
|
||||||
{
|
{
|
||||||
for (S32 i = 0; i < count; ++i)
|
for (S32 i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
|
|
@ -257,7 +255,7 @@ namespace LL
|
||||||
|
|
||||||
// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy
|
// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy
|
||||||
template<class S, class T>
|
template<class S, class T>
|
||||||
static void copyVec4(S* src, LLStrider<T> dst, S32 stride, S32 count)
|
inline void copyVec4(S* src, LLStrider<T> dst, S32 stride, S32 count)
|
||||||
{
|
{
|
||||||
for (S32 i = 0; i < count; ++i)
|
for (S32 i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
|
|
@ -269,7 +267,7 @@ namespace LL
|
||||||
|
|
||||||
// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy
|
// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy
|
||||||
template<class S, class T>
|
template<class S, class T>
|
||||||
static void copyMat2(S* src, LLStrider<T> dst, S32 stride, S32 count)
|
inline void copyMat2(S* src, LLStrider<T> dst, S32 stride, S32 count)
|
||||||
{
|
{
|
||||||
for (S32 i = 0; i < count; ++i)
|
for (S32 i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
|
|
@ -281,7 +279,7 @@ namespace LL
|
||||||
|
|
||||||
// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy
|
// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy
|
||||||
template<class S, class T>
|
template<class S, class T>
|
||||||
static void copyMat3(S* src, LLStrider<T> dst, S32 stride, S32 count)
|
inline void copyMat3(S* src, LLStrider<T> dst, S32 stride, S32 count)
|
||||||
{
|
{
|
||||||
for (S32 i = 0; i < count; ++i)
|
for (S32 i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
|
|
@ -293,7 +291,7 @@ namespace LL
|
||||||
|
|
||||||
// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy
|
// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy
|
||||||
template<class S, class T>
|
template<class S, class T>
|
||||||
static void copyMat4(S* src, LLStrider<T> dst, S32 stride, S32 count)
|
inline void copyMat4(S* src, LLStrider<T> dst, S32 stride, S32 count)
|
||||||
{
|
{
|
||||||
for (S32 i = 0; i < count; ++i)
|
for (S32 i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
|
|
@ -304,39 +302,39 @@ namespace LL
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class S, class T>
|
template<class S, class T>
|
||||||
static void copy(Asset& asset, Accessor& accessor, const S* src, LLStrider<T>& dst, S32 byteStride)
|
inline void copy(Asset& asset, Accessor& accessor, const S* src, LLStrider<T>& dst, S32 byteStride)
|
||||||
{
|
{
|
||||||
if (accessor.mType == (S32)Accessor::Type::SCALAR)
|
if (accessor.mType == Accessor::Type::SCALAR)
|
||||||
{
|
{
|
||||||
S32 stride = byteStride == 0 ? sizeof(S) * 1 : byteStride;
|
S32 stride = byteStride == 0 ? sizeof(S) * 1 : byteStride;
|
||||||
copyScalar((S*)src, dst, stride, accessor.mCount);
|
copyScalar((S*)src, dst, stride, accessor.mCount);
|
||||||
}
|
}
|
||||||
else if (accessor.mType == (S32)Accessor::Type::VEC2)
|
else if (accessor.mType == Accessor::Type::VEC2)
|
||||||
{
|
{
|
||||||
S32 stride = byteStride == 0 ? sizeof(S) * 2 : byteStride;
|
S32 stride = byteStride == 0 ? sizeof(S) * 2 : byteStride;
|
||||||
copyVec2((S*)src, dst, stride, accessor.mCount);
|
copyVec2((S*)src, dst, stride, accessor.mCount);
|
||||||
}
|
}
|
||||||
else if (accessor.mType == (S32)Accessor::Type::VEC3)
|
else if (accessor.mType == Accessor::Type::VEC3)
|
||||||
{
|
{
|
||||||
S32 stride = byteStride == 0 ? sizeof(S) * 3 : byteStride;
|
S32 stride = byteStride == 0 ? sizeof(S) * 3 : byteStride;
|
||||||
copyVec3((S*)src, dst, stride, accessor.mCount);
|
copyVec3((S*)src, dst, stride, accessor.mCount);
|
||||||
}
|
}
|
||||||
else if (accessor.mType == (S32)Accessor::Type::VEC4)
|
else if (accessor.mType == Accessor::Type::VEC4)
|
||||||
{
|
{
|
||||||
S32 stride = byteStride == 0 ? sizeof(S) * 4 : byteStride;
|
S32 stride = byteStride == 0 ? sizeof(S) * 4 : byteStride;
|
||||||
copyVec4((S*)src, dst, stride, accessor.mCount);
|
copyVec4((S*)src, dst, stride, accessor.mCount);
|
||||||
}
|
}
|
||||||
else if (accessor.mType == (S32)Accessor::Type::MAT2)
|
else if (accessor.mType == Accessor::Type::MAT2)
|
||||||
{
|
{
|
||||||
S32 stride = byteStride == 0 ? sizeof(S) * 4 : byteStride;
|
S32 stride = byteStride == 0 ? sizeof(S) * 4 : byteStride;
|
||||||
copyMat2((S*)src, dst, stride, accessor.mCount);
|
copyMat2((S*)src, dst, stride, accessor.mCount);
|
||||||
}
|
}
|
||||||
else if (accessor.mType == (S32)Accessor::Type::MAT3)
|
else if (accessor.mType == Accessor::Type::MAT3)
|
||||||
{
|
{
|
||||||
S32 stride = byteStride == 0 ? sizeof(S) * 9 : byteStride;
|
S32 stride = byteStride == 0 ? sizeof(S) * 9 : byteStride;
|
||||||
copyMat3((S*)src, dst, stride, accessor.mCount);
|
copyMat3((S*)src, dst, stride, accessor.mCount);
|
||||||
}
|
}
|
||||||
else if (accessor.mType == (S32)Accessor::Type::MAT4)
|
else if (accessor.mType == Accessor::Type::MAT4)
|
||||||
{
|
{
|
||||||
S32 stride = byteStride == 0 ? sizeof(S) * 16 : byteStride;
|
S32 stride = byteStride == 0 ? sizeof(S) * 16 : byteStride;
|
||||||
copyMat4((S*)src, dst, stride, accessor.mCount);
|
copyMat4((S*)src, dst, stride, accessor.mCount);
|
||||||
|
|
@ -349,7 +347,7 @@ namespace LL
|
||||||
|
|
||||||
// copy data from accessor to strider
|
// copy data from accessor to strider
|
||||||
template<class T>
|
template<class T>
|
||||||
static void copy(Asset& asset, Accessor& accessor, LLStrider<T>& dst)
|
inline void copy(Asset& asset, Accessor& accessor, LLStrider<T>& dst)
|
||||||
{
|
{
|
||||||
const BufferView& bufferView = asset.mBufferViews[accessor.mBufferView];
|
const BufferView& bufferView = asset.mBufferViews[accessor.mBufferView];
|
||||||
const Buffer& buffer = asset.mBuffers[bufferView.mBuffer];
|
const Buffer& buffer = asset.mBuffers[bufferView.mBuffer];
|
||||||
|
|
@ -391,12 +389,504 @@ namespace LL
|
||||||
|
|
||||||
// copy data from accessor to vector
|
// copy data from accessor to vector
|
||||||
template<class T>
|
template<class T>
|
||||||
static void copy(Asset& asset, Accessor& accessor, std::vector<T>& dst)
|
inline void copy(Asset& asset, Accessor& accessor, std::vector<T>& dst)
|
||||||
{
|
{
|
||||||
dst.resize(accessor.mCount);
|
dst.resize(accessor.mCount);
|
||||||
LLStrider<T> strider = dst.data();
|
LLStrider<T> strider = dst.data();
|
||||||
copy(asset, accessor, strider);
|
copy(asset, accessor, strider);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//=========================================================================================================
|
||||||
|
// boost::json copying utilities
|
||||||
|
// ========================================================================================================
|
||||||
|
|
||||||
|
//====================== unspecialized base template, single value ===========================
|
||||||
|
|
||||||
|
// to/from Value
|
||||||
|
template<typename T>
|
||||||
|
inline bool copy(const Value& src, T& dst)
|
||||||
|
{
|
||||||
|
dst = src;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline bool write(const T& src, Value& dst)
|
||||||
|
{
|
||||||
|
dst = boost::json::object();
|
||||||
|
src.serialize(dst.as_object());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline bool copy(const Value& src, std::unordered_map<std::string, T>& dst)
|
||||||
|
{
|
||||||
|
if (src.is_object())
|
||||||
|
{
|
||||||
|
const boost::json::object& obj = src.as_object();
|
||||||
|
for (const auto& [key, value] : obj)
|
||||||
|
{
|
||||||
|
copy<T>(value, dst[key]);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline bool write(const std::unordered_map<std::string, T>& src, Value& dst)
|
||||||
|
{
|
||||||
|
boost::json::object obj;
|
||||||
|
for (const auto& [key, value] : src)
|
||||||
|
{
|
||||||
|
Value v;
|
||||||
|
if (write<T>(value, v))
|
||||||
|
{
|
||||||
|
obj[key] = v;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dst = obj;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// to/from array
|
||||||
|
template<typename T>
|
||||||
|
inline bool copy(const Value& src, std::vector<T>& dst)
|
||||||
|
{
|
||||||
|
if (src.is_array())
|
||||||
|
{
|
||||||
|
const boost::json::array& arr = src.get_array();
|
||||||
|
dst.resize(arr.size());
|
||||||
|
for (size_t i = 0; i < arr.size(); ++i)
|
||||||
|
{
|
||||||
|
copy(arr[i], dst[i]);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline bool write(const std::vector<T>& src, Value& dst)
|
||||||
|
{
|
||||||
|
boost::json::array arr;
|
||||||
|
for (const T& t : src)
|
||||||
|
{
|
||||||
|
Value v;
|
||||||
|
if (write(t, v))
|
||||||
|
{
|
||||||
|
arr.push_back(v);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dst = arr;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// to/from object member
|
||||||
|
template<typename T>
|
||||||
|
inline bool copy(const boost::json::object& src, string_view member, T& dst)
|
||||||
|
{
|
||||||
|
auto it = src.find(member);
|
||||||
|
if (it != src.end())
|
||||||
|
{
|
||||||
|
return copy(it->value(), dst);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// always write a member to an object without checking default
|
||||||
|
template<typename T>
|
||||||
|
inline bool write_always(const T& src, string_view member, boost::json::object& dst)
|
||||||
|
{
|
||||||
|
Value& v = dst[member];
|
||||||
|
if (!write(src, v))
|
||||||
|
{
|
||||||
|
dst.erase(member);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// conditionally write a member to an object if the member
|
||||||
|
// is not the default value
|
||||||
|
template<typename T>
|
||||||
|
inline bool write(const T& src, string_view member, boost::json::object& dst, const T& default_value = T())
|
||||||
|
{
|
||||||
|
if (src != default_value)
|
||||||
|
{
|
||||||
|
return write_always(src, member, dst);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline bool write(const std::unordered_map<std::string, T>& src, string_view member, boost::json::object& dst, const std::unordered_map<std::string, T>& default_value = std::unordered_map<std::string, T>())
|
||||||
|
{
|
||||||
|
if (!src.empty())
|
||||||
|
{
|
||||||
|
Value v;
|
||||||
|
if (write<T>(src, v))
|
||||||
|
{
|
||||||
|
dst[member] = v;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline bool write(const std::vector<T>& src, string_view member, boost::json::object& dst, const std::vector<T>& deafault_value = std::vector<T>())
|
||||||
|
{
|
||||||
|
if (!src.empty())
|
||||||
|
{
|
||||||
|
Value v;
|
||||||
|
if (write(src, v))
|
||||||
|
{
|
||||||
|
dst[member] = v;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline bool copy(const Value& src, string_view member, T& dst)
|
||||||
|
{
|
||||||
|
if (src.is_object())
|
||||||
|
{
|
||||||
|
const boost::json::object& obj = src.as_object();
|
||||||
|
return copy(obj, member, dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// vec4
|
||||||
|
template<>
|
||||||
|
inline bool copy(const Value& src, vec4& dst)
|
||||||
|
{
|
||||||
|
if (src.is_array())
|
||||||
|
{
|
||||||
|
const boost::json::array& arr = src.as_array();
|
||||||
|
if (arr.size() == 4)
|
||||||
|
{
|
||||||
|
if (arr[0].is_double() &&
|
||||||
|
arr[1].is_double() &&
|
||||||
|
arr[2].is_double() &&
|
||||||
|
arr[3].is_double())
|
||||||
|
{
|
||||||
|
dst = vec4(arr[0].get_double(), arr[1].get_double(), arr[2].get_double(), arr[3].get_double());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline bool write(const vec4& src, Value& dst)
|
||||||
|
{
|
||||||
|
dst = boost::json::array();
|
||||||
|
boost::json::array& arr = dst.get_array();
|
||||||
|
arr.resize(4);
|
||||||
|
arr[0] = src.x;
|
||||||
|
arr[1] = src.y;
|
||||||
|
arr[2] = src.z;
|
||||||
|
arr[3] = src.w;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// quat
|
||||||
|
template<>
|
||||||
|
inline bool copy(const Value& src, quat& dst)
|
||||||
|
{
|
||||||
|
if (src.is_array())
|
||||||
|
{
|
||||||
|
const boost::json::array& arr = src.as_array();
|
||||||
|
if (arr.size() == 4)
|
||||||
|
{
|
||||||
|
if (arr[0].is_double() &&
|
||||||
|
arr[1].is_double() &&
|
||||||
|
arr[2].is_double() &&
|
||||||
|
arr[3].is_double())
|
||||||
|
{
|
||||||
|
dst.x = arr[0].get_double();
|
||||||
|
dst.y = arr[1].get_double();
|
||||||
|
dst.z = arr[2].get_double();
|
||||||
|
dst.w = arr[3].get_double();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline bool write(const quat& src, Value& dst)
|
||||||
|
{
|
||||||
|
dst = boost::json::array();
|
||||||
|
boost::json::array& arr = dst.get_array();
|
||||||
|
arr.resize(4);
|
||||||
|
arr[0] = src.x;
|
||||||
|
arr[1] = src.y;
|
||||||
|
arr[2] = src.z;
|
||||||
|
arr[3] = src.w;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// vec3
|
||||||
|
template<>
|
||||||
|
inline bool copy(const Value& src, vec3& dst)
|
||||||
|
{
|
||||||
|
if (src.is_array())
|
||||||
|
{
|
||||||
|
const boost::json::array& arr = src.as_array();
|
||||||
|
if (arr.size() == 3)
|
||||||
|
{
|
||||||
|
if (arr[0].is_double() &&
|
||||||
|
arr[1].is_double() &&
|
||||||
|
arr[2].is_double())
|
||||||
|
{
|
||||||
|
dst = vec3(arr[0].get_double(), arr[1].get_double(), arr[2].get_double());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline bool write(const vec3& src, Value& dst)
|
||||||
|
{
|
||||||
|
dst = boost::json::array();
|
||||||
|
boost::json::array& arr = dst.as_array();
|
||||||
|
arr.resize(3);
|
||||||
|
arr[0] = src.x;
|
||||||
|
arr[1] = src.y;
|
||||||
|
arr[2] = src.z;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// bool
|
||||||
|
template<>
|
||||||
|
inline bool copy(const Value& src, bool& dst)
|
||||||
|
{
|
||||||
|
if (src.is_bool())
|
||||||
|
{
|
||||||
|
dst = src.get_bool();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline bool write(const bool& src, Value& dst)
|
||||||
|
{
|
||||||
|
dst = src;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// F32
|
||||||
|
template<>
|
||||||
|
inline bool copy(const Value& src, F32& dst)
|
||||||
|
{
|
||||||
|
if (src.is_double())
|
||||||
|
{
|
||||||
|
dst = src.get_double();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline bool write(const F32& src, Value& dst)
|
||||||
|
{
|
||||||
|
dst = src;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// U32
|
||||||
|
template<>
|
||||||
|
inline bool copy(const Value& src, U32& dst)
|
||||||
|
{
|
||||||
|
if (src.is_int64())
|
||||||
|
{
|
||||||
|
dst = src.get_int64();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline bool write(const U32& src, Value& dst)
|
||||||
|
{
|
||||||
|
dst = src;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// F64
|
||||||
|
template<>
|
||||||
|
inline bool copy(const Value& src, F64& dst)
|
||||||
|
{
|
||||||
|
if (src.is_double())
|
||||||
|
{
|
||||||
|
dst = src.get_double();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline bool write(const F64& src, Value& dst)
|
||||||
|
{
|
||||||
|
dst = src;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Accessor::Type
|
||||||
|
template<>
|
||||||
|
inline bool copy(const Value& src, Accessor::Type& dst)
|
||||||
|
{
|
||||||
|
if (src.is_string())
|
||||||
|
{
|
||||||
|
dst = gltf_type_to_enum(src.get_string().c_str());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline bool write(const Accessor::Type& src, Value& dst)
|
||||||
|
{
|
||||||
|
dst = enum_to_gltf_type(src);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// S32
|
||||||
|
template<>
|
||||||
|
inline bool copy(const Value& src, S32& dst)
|
||||||
|
{
|
||||||
|
if (src.is_int64())
|
||||||
|
{
|
||||||
|
dst = src.get_int64();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline bool write(const S32& src, Value& dst)
|
||||||
|
{
|
||||||
|
dst = src;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// std::string
|
||||||
|
template<>
|
||||||
|
inline bool copy(const Value& src, std::string& dst)
|
||||||
|
{
|
||||||
|
if (src.is_string())
|
||||||
|
{
|
||||||
|
dst = src.get_string().c_str();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline bool write(const std::string& src, Value& dst)
|
||||||
|
{
|
||||||
|
dst = src;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// mat4
|
||||||
|
template<>
|
||||||
|
inline bool copy(const Value& src, mat4& dst)
|
||||||
|
{
|
||||||
|
if (src.is_array())
|
||||||
|
{
|
||||||
|
const boost::json::array& arr = src.get_array();
|
||||||
|
if (arr.size() == 16)
|
||||||
|
{
|
||||||
|
// populate a temporary local in case
|
||||||
|
// we hit an error in the middle of the array
|
||||||
|
// (don't partially write a matrix)
|
||||||
|
mat4 t;
|
||||||
|
F32* p = glm::value_ptr(t);
|
||||||
|
|
||||||
|
for (U32 i = 0; i < arr.size(); ++i)
|
||||||
|
{
|
||||||
|
if (arr[i].is_double())
|
||||||
|
{
|
||||||
|
p[i] = arr[i].get_double();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dst = t;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline bool write(const mat4& src, Value& dst)
|
||||||
|
{
|
||||||
|
dst = boost::json::array();
|
||||||
|
boost::json::array& arr = dst.get_array();
|
||||||
|
arr.resize(16);
|
||||||
|
const F32* p = glm::value_ptr(src);
|
||||||
|
for (U32 i = 0; i < 16; ++i)
|
||||||
|
{
|
||||||
|
arr[i] = p[i];
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Material::AlphaMode
|
||||||
|
template<>
|
||||||
|
inline bool copy(const Value& src, Material::AlphaMode& dst)
|
||||||
|
{
|
||||||
|
if (src.is_string())
|
||||||
|
{
|
||||||
|
dst = gltf_alpha_mode_to_enum(src.get_string().c_str());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline bool write(const Material::AlphaMode& src, Value& dst)
|
||||||
|
{
|
||||||
|
dst = enum_to_gltf_alpha_mode(src);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// ========================================================================================================
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file common.h
|
||||||
|
* @brief LL GLTF Implementation
|
||||||
|
*
|
||||||
|
* $LicenseInfo:firstyear=2024&license=viewerlgpl$
|
||||||
|
* Second Life Viewer Source Code
|
||||||
|
* Copyright (C) 2024, 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$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define GLM_ENABLE_EXPERIMENTAL 1
|
||||||
|
|
||||||
|
#include "glm/vec2.hpp"
|
||||||
|
#include "glm/vec3.hpp"
|
||||||
|
#include "glm/vec4.hpp"
|
||||||
|
#include "glm/mat4x4.hpp"
|
||||||
|
#include "glm/gtc/type_ptr.hpp"
|
||||||
|
#include "glm/ext/quaternion_float.hpp"
|
||||||
|
#include "glm/gtx/quaternion.hpp"
|
||||||
|
#include "glm/gtx/matrix_decompose.hpp"
|
||||||
|
|
||||||
|
// Common types and constants used in the GLTF implementation
|
||||||
|
namespace LL
|
||||||
|
{
|
||||||
|
namespace GLTF
|
||||||
|
{
|
||||||
|
using Value = boost::json::value;
|
||||||
|
|
||||||
|
using mat4 = glm::mat4;
|
||||||
|
using vec4 = glm::vec4;
|
||||||
|
using vec3 = glm::vec3;
|
||||||
|
using vec2 = glm::vec2;
|
||||||
|
using quat = glm::quat;
|
||||||
|
|
||||||
|
constexpr S32 LINEAR = 9729;
|
||||||
|
constexpr S32 NEAREST = 9728;
|
||||||
|
constexpr S32 NEAREST_MIPMAP_NEAREST = 9984;
|
||||||
|
constexpr S32 LINEAR_MIPMAP_NEAREST = 9985;
|
||||||
|
constexpr S32 NEAREST_MIPMAP_LINEAR = 9986;
|
||||||
|
constexpr S32 LINEAR_MIPMAP_LINEAR = 9987;
|
||||||
|
constexpr S32 CLAMP_TO_EDGE = 33071;
|
||||||
|
constexpr S32 MIRRORED_REPEAT = 33648;
|
||||||
|
constexpr S32 REPEAT = 10497;
|
||||||
|
|
||||||
|
class Asset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -28,10 +28,12 @@
|
||||||
|
|
||||||
#include "asset.h"
|
#include "asset.h"
|
||||||
#include "buffer_util.h"
|
#include "buffer_util.h"
|
||||||
|
#include "../llviewershadermgr.h"
|
||||||
|
|
||||||
#include "../lltinygltfhelper.h"
|
#include "../lltinygltfhelper.h"
|
||||||
|
|
||||||
using namespace LL::GLTF;
|
using namespace LL::GLTF;
|
||||||
|
using namespace boost::json;
|
||||||
|
|
||||||
void Primitive::allocateGLResources(Asset& asset)
|
void Primitive::allocateGLResources(Asset& asset)
|
||||||
{
|
{
|
||||||
|
|
@ -92,6 +94,10 @@ void Primitive::allocateGLResources(Asset& asset)
|
||||||
mask |= LLVertexBuffer::MAP_WEIGHT4;
|
mask |= LLVertexBuffer::MAP_WEIGHT4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (LLGLSLShader::sCurBoundShaderPtr == nullptr)
|
||||||
|
{ // make sure a shader is bound to satisfy mVertexBuffer->setBuffer
|
||||||
|
gDebugProgram.bind();
|
||||||
|
}
|
||||||
mVertexBuffer = new LLVertexBuffer(mask);
|
mVertexBuffer = new LLVertexBuffer(mask);
|
||||||
mVertexBuffer->allocateBuffer(mPositions.size(), mIndexArray.size()*2); // double the size of the index buffer for 32-bit indices
|
mVertexBuffer->allocateBuffer(mPositions.size(), mIndexArray.size()*2); // double the size of the index buffer for 32-bit indices
|
||||||
|
|
||||||
|
|
@ -129,7 +135,7 @@ void Primitive::allocateGLResources(Asset& asset)
|
||||||
if (mMaterial != INVALID_INDEX)
|
if (mMaterial != INVALID_INDEX)
|
||||||
{
|
{
|
||||||
const Material& material = asset.mMaterials[mMaterial];
|
const Material& material = asset.mMaterials[mMaterial];
|
||||||
LLColor4 baseColor = material.mMaterial->mBaseColor;
|
LLColor4 baseColor(glm::value_ptr(material.mPbrMetallicRoughness.mBaseColorFactor));
|
||||||
for (auto& dst : mColors)
|
for (auto& dst : mColors)
|
||||||
{
|
{
|
||||||
dst = LLColor4U(baseColor * LLColor4(dst));
|
dst = LLColor4U(baseColor * LLColor4(dst));
|
||||||
|
|
@ -351,6 +357,50 @@ Primitive::~Primitive()
|
||||||
mOctree = nullptr;
|
mOctree = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
U32 gltf_mode_to_gl_mode(U32 mode)
|
||||||
|
{
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case TINYGLTF_MODE_POINTS:
|
||||||
|
return LLRender::POINTS;
|
||||||
|
case TINYGLTF_MODE_LINE:
|
||||||
|
return LLRender::LINES;
|
||||||
|
case TINYGLTF_MODE_LINE_LOOP:
|
||||||
|
return LLRender::LINE_LOOP;
|
||||||
|
case TINYGLTF_MODE_LINE_STRIP:
|
||||||
|
return LLRender::LINE_STRIP;
|
||||||
|
case TINYGLTF_MODE_TRIANGLES:
|
||||||
|
return LLRender::TRIANGLES;
|
||||||
|
case TINYGLTF_MODE_TRIANGLE_STRIP:
|
||||||
|
return LLRender::TRIANGLE_STRIP;
|
||||||
|
case TINYGLTF_MODE_TRIANGLE_FAN:
|
||||||
|
return LLRender::TRIANGLE_FAN;
|
||||||
|
default:
|
||||||
|
return LLRender::TRIANGLES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Primitive::serialize(boost::json::object& dst) const
|
||||||
|
{
|
||||||
|
write(mMaterial, "material", dst, -1);
|
||||||
|
write(mMode, "mode", dst, TINYGLTF_MODE_TRIANGLES);
|
||||||
|
write(mIndices, "indices", dst, INVALID_INDEX);
|
||||||
|
write(mAttributes, "attributes", dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Primitive& Primitive::operator=(const Value& src)
|
||||||
|
{
|
||||||
|
if (src.is_object())
|
||||||
|
{
|
||||||
|
copy(src, "material", mMaterial);
|
||||||
|
copy(src, "mode", mMode);
|
||||||
|
copy(src, "indices", mIndices);
|
||||||
|
copy(src, "attributes", mAttributes);
|
||||||
|
|
||||||
|
mGLMode = gltf_mode_to_gl_mode(mMode);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
const Primitive& Primitive::operator=(const tinygltf::Primitive& src)
|
const Primitive& Primitive::operator=(const tinygltf::Primitive& src)
|
||||||
{
|
{
|
||||||
|
|
@ -369,32 +419,7 @@ const Primitive& Primitive::operator=(const tinygltf::Primitive& src)
|
||||||
mAttributes[it.first] = it.second;
|
mAttributes[it.first] = it.second;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (mMode)
|
mGLMode = gltf_mode_to_gl_mode(mMode);
|
||||||
{
|
|
||||||
case TINYGLTF_MODE_POINTS:
|
|
||||||
mGLMode = LLRender::POINTS;
|
|
||||||
break;
|
|
||||||
case TINYGLTF_MODE_LINE:
|
|
||||||
mGLMode = LLRender::LINES;
|
|
||||||
break;
|
|
||||||
case TINYGLTF_MODE_LINE_LOOP:
|
|
||||||
mGLMode = LLRender::LINE_LOOP;
|
|
||||||
break;
|
|
||||||
case TINYGLTF_MODE_LINE_STRIP:
|
|
||||||
mGLMode = LLRender::LINE_STRIP;
|
|
||||||
break;
|
|
||||||
case TINYGLTF_MODE_TRIANGLES:
|
|
||||||
mGLMode = LLRender::TRIANGLES;
|
|
||||||
break;
|
|
||||||
case TINYGLTF_MODE_TRIANGLE_STRIP:
|
|
||||||
mGLMode = LLRender::TRIANGLE_STRIP;
|
|
||||||
break;
|
|
||||||
case TINYGLTF_MODE_TRIANGLE_FAN:
|
|
||||||
mGLMode = LLRender::TRIANGLE_FAN;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
mGLMode = GL_TRIANGLES;
|
|
||||||
}
|
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,12 +28,14 @@
|
||||||
|
|
||||||
#include "llvertexbuffer.h"
|
#include "llvertexbuffer.h"
|
||||||
#include "llvolumeoctree.h"
|
#include "llvolumeoctree.h"
|
||||||
|
#include "boost/json.hpp"
|
||||||
|
|
||||||
// LL GLTF Implementation
|
// LL GLTF Implementation
|
||||||
namespace LL
|
namespace LL
|
||||||
{
|
{
|
||||||
namespace GLTF
|
namespace GLTF
|
||||||
{
|
{
|
||||||
|
using Value = boost::json::value;
|
||||||
class Asset;
|
class Asset;
|
||||||
|
|
||||||
constexpr U32 ATTRIBUTE_MASK =
|
constexpr U32 ATTRIBUTE_MASK =
|
||||||
|
|
@ -66,10 +68,10 @@ namespace LL
|
||||||
std::vector<LLVolumeTriangle> mOctreeTriangles;
|
std::vector<LLVolumeTriangle> mOctreeTriangles;
|
||||||
|
|
||||||
S32 mMaterial = -1;
|
S32 mMaterial = -1;
|
||||||
U32 mMode = TINYGLTF_MODE_TRIANGLES; // default to triangles
|
S32 mMode = TINYGLTF_MODE_TRIANGLES; // default to triangles
|
||||||
U32 mGLMode = LLRender::TRIANGLES;
|
U32 mGLMode = LLRender::TRIANGLES;
|
||||||
S32 mIndices = -1;
|
S32 mIndices = -1;
|
||||||
std::unordered_map<std::string, int> mAttributes;
|
std::unordered_map<std::string, S32> mAttributes;
|
||||||
|
|
||||||
// create octree based on vertex buffer
|
// create octree based on vertex buffer
|
||||||
// must be called before buffer is unmapped and after buffer is populated with good data
|
// must be called before buffer is unmapped and after buffer is populated with good data
|
||||||
|
|
@ -85,6 +87,8 @@ namespace LL
|
||||||
LLVector4a* tangent = NULL // return the surface tangent at the intersection point
|
LLVector4a* tangent = NULL // return the surface tangent at the intersection point
|
||||||
);
|
);
|
||||||
|
|
||||||
|
void serialize(boost::json::object& obj) const;
|
||||||
|
const Primitive& operator=(const Value& src);
|
||||||
const Primitive& operator=(const tinygltf::Primitive& src);
|
const Primitive& operator=(const tinygltf::Primitive& src);
|
||||||
|
|
||||||
void allocateGLResources(Asset& asset);
|
void allocateGLResources(Asset& asset);
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,14 @@
|
||||||
#include "gltf/asset.h"
|
#include "gltf/asset.h"
|
||||||
#include "pipeline.h"
|
#include "pipeline.h"
|
||||||
#include "llviewershadermgr.h"
|
#include "llviewershadermgr.h"
|
||||||
|
#include "llviewertexturelist.h"
|
||||||
|
#include "llimagej2c.h"
|
||||||
|
#include "llfloaterperms.h"
|
||||||
|
#include "llagentbenefits.h"
|
||||||
|
#include "llfilesystem.h"
|
||||||
|
#include "boost/json.hpp"
|
||||||
|
|
||||||
|
#define GLTF_SIM_SUPPORT 1
|
||||||
|
|
||||||
using namespace LL;
|
using namespace LL;
|
||||||
|
|
||||||
|
|
@ -126,6 +133,170 @@ void GLTFSceneManager::decomposeSelection()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GLTFSceneManager::uploadSelection()
|
||||||
|
{
|
||||||
|
if (mUploadingAsset)
|
||||||
|
{ // upload already in progress
|
||||||
|
LLNotificationsUtil::add("GLTFUploadInProgress");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LLViewerObject* obj = LLSelectMgr::instance().getSelection()->getFirstRootObject();
|
||||||
|
if (obj && obj->mGLTFAsset)
|
||||||
|
{
|
||||||
|
// make a copy of the asset prior to uploading
|
||||||
|
mUploadingAsset = std::make_shared<Asset>();
|
||||||
|
mUploadingObject = obj;
|
||||||
|
*mUploadingAsset = *obj->mGLTFAsset;
|
||||||
|
|
||||||
|
GLTF::Asset& asset = *mUploadingAsset;
|
||||||
|
|
||||||
|
for (auto& image : asset.mImages)
|
||||||
|
{
|
||||||
|
if (!image.mData.empty())
|
||||||
|
{
|
||||||
|
mPendingImageUploads++;
|
||||||
|
|
||||||
|
LLPointer<LLImageRaw> raw = new LLImageRaw(image.mWidth, image.mHeight, image.mComponent);
|
||||||
|
U8* data = raw->allocateData();
|
||||||
|
llassert_always(image.mData.size() == raw->getDataSize());
|
||||||
|
memcpy(data, image.mData.data(), image.mData.size());
|
||||||
|
|
||||||
|
// for GLTF native content, store image in GLTF orientation
|
||||||
|
raw->verticalFlip();
|
||||||
|
|
||||||
|
LLPointer<LLImageJ2C> j2c = LLViewerTextureList::convertToUploadFile(raw);
|
||||||
|
|
||||||
|
std::string buffer;
|
||||||
|
buffer.assign((const char*)j2c->getData(), j2c->getDataSize());
|
||||||
|
|
||||||
|
LLUUID asset_id = LLUUID::generateNewID();
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
S32 idx = (S32)(&image - &asset.mImages[0]);
|
||||||
|
|
||||||
|
if (image.mName.empty())
|
||||||
|
{
|
||||||
|
|
||||||
|
name = llformat("Image_%d", idx);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
name = image.mName;
|
||||||
|
}
|
||||||
|
|
||||||
|
LLNewBufferedResourceUploadInfo::uploadFailure_f failure = [this](LLUUID assetId, LLSD response, std::string reason)
|
||||||
|
{
|
||||||
|
// TODO: handle failure
|
||||||
|
mPendingImageUploads--;
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
LLNewBufferedResourceUploadInfo::uploadFinish_f finish = [this, idx, raw, j2c](LLUUID assetId, LLSD response)
|
||||||
|
{
|
||||||
|
if (mUploadingAsset && mUploadingAsset->mImages.size() > idx)
|
||||||
|
{
|
||||||
|
mUploadingAsset->mImages[idx].mUri = assetId.asString();
|
||||||
|
mPendingImageUploads--;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
S32 expected_upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(j2c);
|
||||||
|
|
||||||
|
LLResourceUploadInfo::ptr_t uploadInfo(std::make_shared<LLNewBufferedResourceUploadInfo>(
|
||||||
|
buffer,
|
||||||
|
asset_id,
|
||||||
|
name,
|
||||||
|
name,
|
||||||
|
0,
|
||||||
|
LLFolderType::FT_TEXTURE,
|
||||||
|
LLInventoryType::IT_TEXTURE,
|
||||||
|
LLAssetType::AT_TEXTURE,
|
||||||
|
LLFloaterPerms::getNextOwnerPerms("Uploads"),
|
||||||
|
LLFloaterPerms::getGroupPerms("Uploads"),
|
||||||
|
LLFloaterPerms::getEveryonePerms("Uploads"),
|
||||||
|
expected_upload_cost,
|
||||||
|
false,
|
||||||
|
finish,
|
||||||
|
failure));
|
||||||
|
|
||||||
|
upload_new_resource(uploadInfo);
|
||||||
|
|
||||||
|
image.clearData(asset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// upload .bin
|
||||||
|
for (auto& bin : asset.mBuffers)
|
||||||
|
{
|
||||||
|
mPendingBinaryUploads++;
|
||||||
|
|
||||||
|
S32 idx = (S32)(&bin - &asset.mBuffers[0]);
|
||||||
|
|
||||||
|
std::string buffer;
|
||||||
|
buffer.assign((const char*)bin.mData.data(), bin.mData.size());
|
||||||
|
|
||||||
|
LLUUID asset_id = LLUUID::generateNewID();
|
||||||
|
|
||||||
|
LLNewBufferedResourceUploadInfo::uploadFailure_f failure = [this](LLUUID assetId, LLSD response, std::string reason)
|
||||||
|
{
|
||||||
|
// TODO: handle failure
|
||||||
|
mPendingBinaryUploads--;
|
||||||
|
mUploadingAsset = nullptr;
|
||||||
|
mUploadingObject = nullptr;
|
||||||
|
LL_WARNS("GLTF") << "Failed to upload GLTF binary: " << reason << LL_ENDL;
|
||||||
|
LL_WARNS("GLTF") << response << LL_ENDL;
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
LLNewBufferedResourceUploadInfo::uploadFinish_f finish = [this, idx](LLUUID assetId, LLSD response)
|
||||||
|
{
|
||||||
|
if (mUploadingAsset && mUploadingAsset->mBuffers.size() > idx)
|
||||||
|
{
|
||||||
|
mUploadingAsset->mBuffers[idx].mUri = assetId.asString();
|
||||||
|
mPendingBinaryUploads--;
|
||||||
|
|
||||||
|
// HACK: save buffer to cache to emulate a successful download
|
||||||
|
LLFileSystem cache(assetId, LLAssetType::AT_GLTF_BIN, LLFileSystem::WRITE);
|
||||||
|
auto& data = mUploadingAsset->mBuffers[idx].mData;
|
||||||
|
|
||||||
|
cache.write((const U8*)data.data(), data.size());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#if GLTF_SIM_SUPPORT
|
||||||
|
S32 expected_upload_cost = 1;
|
||||||
|
|
||||||
|
LLResourceUploadInfo::ptr_t uploadInfo(std::make_shared<LLNewBufferedResourceUploadInfo>(
|
||||||
|
buffer,
|
||||||
|
asset_id,
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
0,
|
||||||
|
LLFolderType::FT_NONE,
|
||||||
|
LLInventoryType::IT_GLTF_BIN,
|
||||||
|
LLAssetType::AT_GLTF_BIN,
|
||||||
|
LLFloaterPerms::getNextOwnerPerms("Uploads"),
|
||||||
|
LLFloaterPerms::getGroupPerms("Uploads"),
|
||||||
|
LLFloaterPerms::getEveryonePerms("Uploads"),
|
||||||
|
expected_upload_cost,
|
||||||
|
false,
|
||||||
|
finish,
|
||||||
|
failure));
|
||||||
|
|
||||||
|
upload_new_resource(uploadInfo);
|
||||||
|
#else
|
||||||
|
// dummy finish
|
||||||
|
finish(LLUUID::generateNewID(), LLSD());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LLNotificationsUtil::add("GLTFUploadSelection");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void GLTFSceneManager::decomposeSelection(const std::string& filename)
|
void GLTFSceneManager::decomposeSelection(const std::string& filename)
|
||||||
{
|
{
|
||||||
LLViewerObject* obj = LLSelectMgr::instance().getSelection()->getFirstRootObject();
|
LLViewerObject* obj = LLSelectMgr::instance().getSelection()->getFirstRootObject();
|
||||||
|
|
@ -176,7 +347,7 @@ void GLTFSceneManager::load(const std::string& filename)
|
||||||
if (obj)
|
if (obj)
|
||||||
{ // assign to self avatar
|
{ // assign to self avatar
|
||||||
obj->mGLTFAsset = asset;
|
obj->mGLTFAsset = asset;
|
||||||
|
obj->markForUpdate();
|
||||||
if (std::find(mObjects.begin(), mObjects.end(), obj) == mObjects.end())
|
if (std::find(mObjects.begin(), mObjects.end(), obj) == mObjects.end())
|
||||||
{
|
{
|
||||||
mObjects.push_back(obj);
|
mObjects.push_back(obj);
|
||||||
|
|
@ -199,6 +370,109 @@ void GLTFSceneManager::renderAlpha()
|
||||||
render(false);
|
render(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GLTFSceneManager::addGLTFObject(LLViewerObject* obj, LLUUID gltf_id)
|
||||||
|
{
|
||||||
|
llassert(obj->getVolume()->getParams().getSculptID() == gltf_id);
|
||||||
|
llassert(obj->getVolume()->getParams().getSculptType() == LL_SCULPT_TYPE_GLTF);
|
||||||
|
|
||||||
|
obj->ref();
|
||||||
|
gAssetStorage->getAssetData(gltf_id, LLAssetType::AT_GLTF, onGLTFLoadComplete, obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
//static
|
||||||
|
void GLTFSceneManager::onGLTFBinLoadComplete(const LLUUID& id, LLAssetType::EType asset_type, void* user_data, S32 status, LLExtStat ext_status)
|
||||||
|
{
|
||||||
|
LLViewerObject* obj = (LLViewerObject*)user_data;
|
||||||
|
llassert(asset_type == LLAssetType::AT_GLTF_BIN);
|
||||||
|
|
||||||
|
if (status == LL_ERR_NOERR)
|
||||||
|
{
|
||||||
|
if (obj)
|
||||||
|
{
|
||||||
|
// find the Buffer with the given id in the asset
|
||||||
|
if (obj->mGLTFAsset)
|
||||||
|
{
|
||||||
|
for (auto& buffer : obj->mGLTFAsset->mBuffers)
|
||||||
|
{
|
||||||
|
LLUUID buffer_id;
|
||||||
|
if (LLUUID::parseUUID(buffer.mUri, &buffer_id) && buffer_id == id)
|
||||||
|
{
|
||||||
|
LLFileSystem file(id, asset_type, LLFileSystem::READ);
|
||||||
|
|
||||||
|
buffer.mData.resize(file.getSize());
|
||||||
|
file.read((U8*)buffer.mData.data(), buffer.mData.size());
|
||||||
|
|
||||||
|
obj->mGLTFAsset->mPendingBuffers--;
|
||||||
|
|
||||||
|
if (obj->mGLTFAsset->mPendingBuffers == 0)
|
||||||
|
{
|
||||||
|
obj->mGLTFAsset->allocateGLResources();
|
||||||
|
GLTFSceneManager& mgr = GLTFSceneManager::instance();
|
||||||
|
if (std::find(mgr.mObjects.begin(), mgr.mObjects.end(), obj) == mgr.mObjects.end())
|
||||||
|
{
|
||||||
|
GLTFSceneManager::instance().mObjects.push_back(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LL_WARNS("GLTF") << "Failed to load GLTF asset: " << id << LL_ENDL;
|
||||||
|
obj->unref();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//static
|
||||||
|
void GLTFSceneManager::onGLTFLoadComplete(const LLUUID& id, LLAssetType::EType asset_type, void* user_data, S32 status, LLExtStat ext_status)
|
||||||
|
{
|
||||||
|
LLViewerObject* obj = (LLViewerObject*)user_data;
|
||||||
|
llassert(asset_type == LLAssetType::AT_GLTF);
|
||||||
|
|
||||||
|
if (status == LL_ERR_NOERR)
|
||||||
|
{
|
||||||
|
if (obj)
|
||||||
|
{
|
||||||
|
LLFileSystem file(id, asset_type, LLFileSystem::READ);
|
||||||
|
std::string data;
|
||||||
|
data.resize(file.getSize());
|
||||||
|
file.read((U8*)data.data(), data.size());
|
||||||
|
|
||||||
|
boost::json::value json = boost::json::parse(data);
|
||||||
|
|
||||||
|
std::shared_ptr<Asset> asset = std::make_shared<Asset>(json);
|
||||||
|
obj->mGLTFAsset = asset;
|
||||||
|
|
||||||
|
for (auto& buffer : asset->mBuffers)
|
||||||
|
{
|
||||||
|
// for now just assume the buffer is already in the asset cache
|
||||||
|
LLUUID buffer_id;
|
||||||
|
if (LLUUID::parseUUID(buffer.mUri, &buffer_id))
|
||||||
|
{
|
||||||
|
asset->mPendingBuffers++;
|
||||||
|
|
||||||
|
gAssetStorage->getAssetData(buffer_id, LLAssetType::AT_GLTF_BIN, onGLTFBinLoadComplete, obj);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LL_WARNS("GLTF") << "Buffer URI is not a valid UUID: " << buffer.mUri << LL_ENDL;
|
||||||
|
obj->unref();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LL_WARNS("GLTF") << "Failed to load GLTF asset: " << id << LL_ENDL;
|
||||||
|
obj->unref();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void GLTFSceneManager::update()
|
void GLTFSceneManager::update()
|
||||||
{
|
{
|
||||||
for (U32 i = 0; i < mObjects.size(); ++i)
|
for (U32 i = 0; i < mObjects.size(); ++i)
|
||||||
|
|
@ -212,6 +486,107 @@ void GLTFSceneManager::update()
|
||||||
|
|
||||||
mObjects[i]->mGLTFAsset->update();
|
mObjects[i]->mGLTFAsset->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// process pending uploads
|
||||||
|
if (mUploadingAsset && !mGLTFUploadPending)
|
||||||
|
{
|
||||||
|
if (mPendingImageUploads == 0 && mPendingBinaryUploads == 0)
|
||||||
|
{
|
||||||
|
std::string filename(gDirUtilp->getTempDir() + "/upload.gltf");
|
||||||
|
#if 0
|
||||||
|
tinygltf::Model model;
|
||||||
|
mUploadingAsset->save(model);
|
||||||
|
|
||||||
|
tinygltf::TinyGLTF writer;
|
||||||
|
|
||||||
|
writer.WriteGltfSceneToFile(&model, filename, false, false, true, false);
|
||||||
|
#else
|
||||||
|
boost::json::object obj;
|
||||||
|
mUploadingAsset->serialize(obj);
|
||||||
|
std::string json = boost::json::serialize(obj, {});
|
||||||
|
|
||||||
|
{
|
||||||
|
std::ofstream o(filename);
|
||||||
|
o << json;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::ifstream t(filename);
|
||||||
|
std::stringstream str;
|
||||||
|
str << t.rdbuf();
|
||||||
|
|
||||||
|
std::string buffer = str.str();
|
||||||
|
|
||||||
|
LLNewBufferedResourceUploadInfo::uploadFailure_f failure = [this](LLUUID assetId, LLSD response, std::string reason)
|
||||||
|
{
|
||||||
|
// TODO: handle failure
|
||||||
|
LL_WARNS("GLTF") << "Failed to upload GLTF json: " << reason << LL_ENDL;
|
||||||
|
LL_WARNS("GLTF") << response << LL_ENDL;
|
||||||
|
|
||||||
|
mUploadingAsset = nullptr;
|
||||||
|
mUploadingObject = nullptr;
|
||||||
|
mGLTFUploadPending = false;
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
LLNewBufferedResourceUploadInfo::uploadFinish_f finish = [this, buffer](LLUUID assetId, LLSD response)
|
||||||
|
{
|
||||||
|
LLAppViewer::instance()->postToMainCoro(
|
||||||
|
[=]()
|
||||||
|
{
|
||||||
|
if (mUploadingAsset)
|
||||||
|
{
|
||||||
|
// HACK: save buffer to cache to emulate a successful upload
|
||||||
|
LLFileSystem cache(assetId, LLAssetType::AT_GLTF, LLFileSystem::WRITE);
|
||||||
|
|
||||||
|
LL_INFOS("GLTF") << "Uploaded GLTF json: " << assetId << LL_ENDL;
|
||||||
|
cache.write((const U8 *) buffer.c_str(), buffer.size());
|
||||||
|
|
||||||
|
mUploadingAsset = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mUploadingObject)
|
||||||
|
{
|
||||||
|
mUploadingObject->mGLTFAsset = nullptr;
|
||||||
|
mUploadingObject->setGLTFAsset(assetId);
|
||||||
|
mUploadingObject->markForUpdate();
|
||||||
|
mUploadingObject = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
mGLTFUploadPending = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
#if GLTF_SIM_SUPPORT
|
||||||
|
S32 expected_upload_cost = 1;
|
||||||
|
LLUUID asset_id = LLUUID::generateNewID();
|
||||||
|
|
||||||
|
mGLTFUploadPending = true;
|
||||||
|
|
||||||
|
LLResourceUploadInfo::ptr_t uploadInfo(std::make_shared<LLNewBufferedResourceUploadInfo>(
|
||||||
|
buffer,
|
||||||
|
asset_id,
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
0,
|
||||||
|
LLFolderType::FT_NONE,
|
||||||
|
LLInventoryType::IT_GLTF,
|
||||||
|
LLAssetType::AT_GLTF,
|
||||||
|
LLFloaterPerms::getNextOwnerPerms("Uploads"),
|
||||||
|
LLFloaterPerms::getGroupPerms("Uploads"),
|
||||||
|
LLFloaterPerms::getEveryonePerms("Uploads"),
|
||||||
|
expected_upload_cost,
|
||||||
|
false,
|
||||||
|
finish,
|
||||||
|
failure));
|
||||||
|
|
||||||
|
upload_new_resource(uploadInfo);
|
||||||
|
#else
|
||||||
|
// dummy finish
|
||||||
|
finish(LLUUID::generateNewID(), LLSD());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLTFSceneManager::render(bool opaque, bool rigged)
|
void GLTFSceneManager::render(bool opaque, bool rigged)
|
||||||
|
|
@ -219,7 +594,7 @@ void GLTFSceneManager::render(bool opaque, bool rigged)
|
||||||
// for debugging, just render the whole scene as opaque
|
// for debugging, just render the whole scene as opaque
|
||||||
// by traversing the whole scenegraph
|
// by traversing the whole scenegraph
|
||||||
// Assumes camera transform is already set and
|
// Assumes camera transform is already set and
|
||||||
// appropriate shader is already bound
|
// appropriate shader is already boundd
|
||||||
|
|
||||||
gGL.matrixMode(LLRender::MM_MODELVIEW);
|
gGL.matrixMode(LLRender::MM_MODELVIEW);
|
||||||
|
|
||||||
|
|
@ -243,7 +618,8 @@ void GLTFSceneManager::render(bool opaque, bool rigged)
|
||||||
|
|
||||||
matMul(mat, modelview, modelview);
|
matMul(mat, modelview, modelview);
|
||||||
|
|
||||||
asset->updateRenderTransforms(modelview);
|
mat4 mdv = glm::make_mat4(modelview.getF32ptr());
|
||||||
|
asset->updateRenderTransforms(mdv);
|
||||||
asset->render(opaque, rigged);
|
asset->render(opaque, rigged);
|
||||||
|
|
||||||
gGL.popMatrix();
|
gGL.popMatrix();
|
||||||
|
|
@ -411,20 +787,24 @@ void renderAssetDebug(LLViewerObject* obj, Asset* asset)
|
||||||
// get raycast in asset space
|
// get raycast in asset space
|
||||||
LLMatrix4a agent_to_asset = obj->getAgentToGLTFAssetTransform();
|
LLMatrix4a agent_to_asset = obj->getAgentToGLTFAssetTransform();
|
||||||
|
|
||||||
LLVector4a start;
|
vec4 start;
|
||||||
LLVector4a end;
|
vec4 end;
|
||||||
|
|
||||||
agent_to_asset.affineTransform(gDebugRaycastStart, start);
|
LLVector4a t;
|
||||||
agent_to_asset.affineTransform(gDebugRaycastEnd, end);
|
agent_to_asset.affineTransform(gDebugRaycastStart, t);
|
||||||
|
start = glm::make_vec4(t.getF32ptr());
|
||||||
|
agent_to_asset.affineTransform(gDebugRaycastEnd, t);
|
||||||
|
end = glm::make_vec4(t.getF32ptr());
|
||||||
|
|
||||||
|
start.w = end.w = 1.0;
|
||||||
|
|
||||||
|
|
||||||
for (auto& node : asset->mNodes)
|
for (auto& node : asset->mNodes)
|
||||||
{
|
{
|
||||||
Mesh& mesh = asset->mMeshes[node.mMesh];
|
Mesh& mesh = asset->mMeshes[node.mMesh];
|
||||||
|
|
||||||
if (node.mMesh != INVALID_INDEX)
|
if (node.mMesh != INVALID_INDEX)
|
||||||
{
|
{
|
||||||
gGL.loadMatrix((F32*)node.mRenderMatrix.mMatrix);
|
gGL.loadMatrix((F32*)glm::value_ptr(node.mRenderMatrix));
|
||||||
|
|
||||||
// draw bounding box of mesh primitives
|
// draw bounding box of mesh primitives
|
||||||
if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BBOXES))
|
if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BBOXES))
|
||||||
|
|
@ -442,24 +822,24 @@ void renderAssetDebug(LLViewerObject* obj, Asset* asset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 1
|
||||||
if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST))
|
if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST))
|
||||||
{
|
{
|
||||||
gGL.flush();
|
gGL.flush();
|
||||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||||
|
|
||||||
// convert raycast to node local space
|
// convert raycast to node local space
|
||||||
LLVector4a local_start;
|
vec4 local_start = node.mAssetMatrixInv * start;
|
||||||
LLVector4a local_end;
|
vec4 local_end = node.mAssetMatrixInv * end;
|
||||||
|
|
||||||
node.mAssetMatrixInv.affineTransform(start, local_start);
|
|
||||||
node.mAssetMatrixInv.affineTransform(end, local_end);
|
|
||||||
|
|
||||||
for (auto& primitive : mesh.mPrimitives)
|
for (auto& primitive : mesh.mPrimitives)
|
||||||
{
|
{
|
||||||
if (primitive.mOctree.notNull())
|
if (primitive.mOctree.notNull())
|
||||||
{
|
{
|
||||||
renderOctreeRaycast(local_start, local_end, primitive.mOctree);
|
LLVector4a s, e;
|
||||||
|
s.load3(glm::value_ptr(local_start));
|
||||||
|
e.load3(glm::value_ptr(local_end));
|
||||||
|
renderOctreeRaycast(s, e, primitive.mOctree);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -499,18 +879,18 @@ void GLTFSceneManager::renderDebug()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
LLMatrix4a mat = obj->getGLTFAssetToAgentTransform();
|
mat4 mat = glm::make_mat4(obj->getGLTFAssetToAgentTransform().getF32ptr());
|
||||||
|
|
||||||
LLMatrix4a modelview;
|
mat4 modelview = glm::make_mat4(gGLModelView);
|
||||||
modelview.loadu(gGLModelView);
|
|
||||||
|
|
||||||
matMul(mat, modelview, modelview);
|
|
||||||
|
|
||||||
|
modelview = modelview * mat;
|
||||||
|
|
||||||
Asset* asset = obj->mGLTFAsset.get();
|
Asset* asset = obj->mGLTFAsset.get();
|
||||||
|
|
||||||
for (auto& node : asset->mNodes)
|
for (auto& node : asset->mNodes)
|
||||||
{
|
{
|
||||||
matMul(node.mAssetMatrix, modelview, node.mRenderMatrix);
|
node.mRenderMatrix = modelview * node.mAssetMatrix;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -523,13 +903,6 @@ void GLTFSceneManager::renderDebug()
|
||||||
|
|
||||||
Asset* asset = obj->mGLTFAsset.get();
|
Asset* asset = obj->mGLTFAsset.get();
|
||||||
|
|
||||||
LLMatrix4a mat = obj->getGLTFAssetToAgentTransform();
|
|
||||||
|
|
||||||
LLMatrix4a modelview;
|
|
||||||
modelview.loadu(gGLModelView);
|
|
||||||
|
|
||||||
matMul(mat, modelview, modelview);
|
|
||||||
|
|
||||||
renderAssetDebug(obj, asset);
|
renderAssetDebug(obj, asset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -551,21 +924,20 @@ void GLTFSceneManager::renderDebug()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
LLMatrix4a mat = obj->getGLTFAssetToAgentTransform();
|
mat4 mat = glm::make_mat4(obj->getGLTFAssetToAgentTransform().getF32ptr());
|
||||||
|
|
||||||
LLMatrix4a modelview;
|
mat4 modelview = glm::make_mat4(gGLModelView);
|
||||||
modelview.loadu(gGLModelView);
|
|
||||||
|
|
||||||
matMul(mat, modelview, modelview);
|
modelview = modelview * mat;
|
||||||
|
|
||||||
Asset* asset = obj->mGLTFAsset.get();
|
Asset* asset = obj->mGLTFAsset.get();
|
||||||
|
|
||||||
for (auto& node : asset->mNodes)
|
for (auto& node : asset->mNodes)
|
||||||
{
|
{
|
||||||
// force update all mRenderMatrix, not just nodes with meshes
|
// force update all mRenderMatrix, not just nodes with meshes
|
||||||
matMul(node.mAssetMatrix, modelview, node.mRenderMatrix);
|
node.mRenderMatrix = modelview * node.mAssetMatrix;
|
||||||
|
|
||||||
gGL.loadMatrix(node.mRenderMatrix.getF32ptr());
|
gGL.loadMatrix(glm::value_ptr(node.mRenderMatrix));
|
||||||
// render x-axis red, y-axis green, z-axis blue
|
// render x-axis red, y-axis green, z-axis blue
|
||||||
gGL.color4f(1.f, 0.f, 0.f, 0.5f);
|
gGL.color4f(1.f, 0.f, 0.f, 0.5f);
|
||||||
gGL.begin(LLRender::LINES);
|
gGL.begin(LLRender::LINES);
|
||||||
|
|
@ -595,7 +967,9 @@ void GLTFSceneManager::renderDebug()
|
||||||
{
|
{
|
||||||
Node& child = asset->mNodes[child_idx];
|
Node& child = asset->mNodes[child_idx];
|
||||||
gGL.vertex3f(0.f, 0.f, 0.f);
|
gGL.vertex3f(0.f, 0.f, 0.f);
|
||||||
gGL.vertex3fv(child.mMatrix.getTranslation().getF32ptr());
|
|
||||||
|
|
||||||
|
gGL.vertex3fv(glm::value_ptr(child.mMatrix[3]));
|
||||||
}
|
}
|
||||||
gGL.end();
|
gGL.end();
|
||||||
gGL.flush();
|
gGL.flush();
|
||||||
|
|
@ -628,9 +1002,8 @@ void GLTFSceneManager::renderDebug()
|
||||||
gGL.color3f(1, 0, 1);
|
gGL.color3f(1, 0, 1);
|
||||||
drawBoxOutline(intersection, LLVector4a(0.1f, 0.1f, 0.1f, 0.f));
|
drawBoxOutline(intersection, LLVector4a(0.1f, 0.1f, 0.1f, 0.f));
|
||||||
|
|
||||||
gGL.loadMatrix((F32*) node->mRenderMatrix.mMatrix);
|
gGL.loadMatrix(glm::value_ptr(node->mRenderMatrix));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
auto* listener = (LLVolumeOctreeListener*) primitive->mOctree->getListener(0);
|
auto* listener = (LLVolumeOctreeListener*) primitive->mOctree->getListener(0);
|
||||||
drawBoxOutline(listener->mBounds[0], listener->mBounds[1]);
|
drawBoxOutline(listener->mBounds[0], listener->mBounds[1]);
|
||||||
|
|
@ -643,3 +1016,5 @@ void GLTFSceneManager::renderDebug()
|
||||||
gDebugProgram.unbind();
|
gDebugProgram.unbind();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ namespace LL
|
||||||
void save(const std::string& filename); // save selected asset to filename (suitable for use in external programs)
|
void save(const std::string& filename); // save selected asset to filename (suitable for use in external programs)
|
||||||
void decomposeSelection(); // open file picker and choose a location to decompose to
|
void decomposeSelection(); // open file picker and choose a location to decompose to
|
||||||
void decomposeSelection(const std::string& filename); // decompose selected asset into simulator-ready .gltf, .bin, and .j2c files
|
void decomposeSelection(const std::string& filename); // decompose selected asset into simulator-ready .gltf, .bin, and .j2c files
|
||||||
|
void uploadSelection(); // decompose selected asset and upload to simulator
|
||||||
|
|
||||||
void update();
|
void update();
|
||||||
void render(bool opaque, bool rigged = false);
|
void render(bool opaque, bool rigged = false);
|
||||||
|
|
@ -77,7 +78,18 @@ namespace LL
|
||||||
|
|
||||||
void renderDebug();
|
void renderDebug();
|
||||||
|
|
||||||
|
void addGLTFObject(LLViewerObject* object, LLUUID gltf_id);
|
||||||
|
static void onGLTFLoadComplete(const LLUUID& id, LLAssetType::EType asset_type, void* user_data, S32 status, LLExtStat ext_status);
|
||||||
|
static void onGLTFBinLoadComplete(const LLUUID& id, LLAssetType::EType asset_type, void* user_data, S32 status, LLExtStat ext_status);
|
||||||
|
|
||||||
std::vector<LLPointer<LLViewerObject>> mObjects;
|
std::vector<LLPointer<LLViewerObject>> mObjects;
|
||||||
|
|
||||||
|
std::shared_ptr<GLTF::Asset> mUploadingAsset;
|
||||||
|
bool mGLTFUploadPending = false;
|
||||||
|
LLPointer<LLViewerObject> mUploadingObject;
|
||||||
|
U32 mPendingImageUploads = 0;
|
||||||
|
U32 mPendingBinaryUploads = 0;
|
||||||
|
U32 mPendingGLTFUploads = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -455,7 +455,6 @@ void LLDrawPoolTerrain::renderFullShaderPBR(bool local_materials)
|
||||||
|
|
||||||
LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
|
LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
|
||||||
llassert(shader);
|
llassert(shader);
|
||||||
|
|
||||||
|
|
||||||
// Like for PBR materials, PBR terrain texture transforms are defined by
|
// Like for PBR materials, PBR terrain texture transforms are defined by
|
||||||
// the KHR_texture_transform spec, but with the following notable
|
// the KHR_texture_transform spec, but with the following notable
|
||||||
|
|
@ -470,7 +469,6 @@ void LLDrawPoolTerrain::renderFullShaderPBR(bool local_materials)
|
||||||
// i.e. this isn't fully compliant with KHR_texture_transform, but is
|
// i.e. this isn't fully compliant with KHR_texture_transform, but is
|
||||||
// compliant when all texture infos used by a material have the same
|
// compliant when all texture infos used by a material have the same
|
||||||
// texture transform.
|
// texture transform.
|
||||||
|
|
||||||
LLGLTFMaterial::TextureTransform::PackTight transforms_packed[terrain_material_count];
|
LLGLTFMaterial::TextureTransform::PackTight transforms_packed[terrain_material_count];
|
||||||
for (U32 i = 0; i < terrain_material_count; ++i)
|
for (U32 i = 0; i < terrain_material_count; ++i)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1328,11 +1328,11 @@ bool LLFace::getGeometryVolume(const LLVolume& volume,
|
||||||
{
|
{
|
||||||
color = tep->getGLTFRenderMaterial()->mBaseColor;
|
color = tep->getGLTFRenderMaterial()->mBaseColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rebuild_color)
|
if (rebuild_color)
|
||||||
{ //decide if shiny goes in alpha channel of color
|
{ //decide if shiny goes in alpha channel of color
|
||||||
if (tep &&
|
if (tep &&
|
||||||
!isInAlphaPool()) // <--- alpha channel MUST contain transparency, not shiny
|
!isInAlphaPool() && tep->getGLTFRenderMaterial() == nullptr) // <--- alpha channel MUST contain transparency, not shiny
|
||||||
{
|
{
|
||||||
LLMaterial* mat = tep->getMaterialParams().get();
|
LLMaterial* mat = tep->getMaterialParams().get();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -77,16 +77,7 @@ void LLFetchedGLTFMaterial::bind(LLViewerTexture* media_tex)
|
||||||
{
|
{
|
||||||
if (mAlphaMode == LLGLTFMaterial::ALPHA_MODE_MASK)
|
if (mAlphaMode == LLGLTFMaterial::ALPHA_MODE_MASK)
|
||||||
{
|
{
|
||||||
// dividing the alpha cutoff by transparency here allows the shader to compare against
|
min_alpha = mAlphaCutoff;
|
||||||
// the alpha value of the texture without needing the transparency value
|
|
||||||
if (mBaseColor.mV[3] > 0.f)
|
|
||||||
{
|
|
||||||
min_alpha = mAlphaCutoff / mBaseColor.mV[3];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
min_alpha = 1024.f;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
shader->uniform1f(LLShaderMgr::MINIMUM_ALPHA, min_alpha);
|
shader->uniform1f(LLShaderMgr::MINIMUM_ALPHA, min_alpha);
|
||||||
}
|
}
|
||||||
|
|
@ -151,7 +142,6 @@ void LLFetchedGLTFMaterial::bind(LLViewerTexture* media_tex)
|
||||||
mTextureTransform[GLTF_TEXTURE_INFO_EMISSIVE].getPacked(emissive_packed);
|
mTextureTransform[GLTF_TEXTURE_INFO_EMISSIVE].getPacked(emissive_packed);
|
||||||
shader->uniform4fv(LLShaderMgr::TEXTURE_EMISSIVE_TRANSFORM, 2, (F32*)emissive_packed);
|
shader->uniform4fv(LLShaderMgr::TEXTURE_EMISSIVE_TRANSFORM, 2, (F32*)emissive_packed);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LLViewerFetchedTexture* fetch_texture(const LLUUID& id)
|
LLViewerFetchedTexture* fetch_texture(const LLUUID& id)
|
||||||
|
|
|
||||||
|
|
@ -2379,23 +2379,29 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url)
|
||||||
{
|
{
|
||||||
session_id = message_data["asset_id"].asUUID();
|
session_id = message_data["asset_id"].asUUID();
|
||||||
}
|
}
|
||||||
LLIMProcessing::processNewMessage(
|
|
||||||
message_data["from_agent_id"].asUUID(),
|
LLAppViewer::instance()->postToMainCoro([=]()
|
||||||
from_group,
|
{
|
||||||
message_data["to_agent_id"].asUUID(),
|
std::vector<U8> local_bin_bucket = bin_bucket;
|
||||||
message_data.has("offline") ? static_cast<U8>(message_data["offline"].asInteger()) : IM_OFFLINE,
|
LLHost local_sender = sender;
|
||||||
dialog,
|
LLIMProcessing::processNewMessage(
|
||||||
session_id,
|
message_data["from_agent_id"].asUUID(),
|
||||||
static_cast<U32>(message_data["timestamp"].asInteger()),
|
from_group,
|
||||||
message_data["from_agent_name"].asString(),
|
message_data["to_agent_id"].asUUID(),
|
||||||
message_data["message"].asString(),
|
message_data.has("offline") ? static_cast<U8>(message_data["offline"].asInteger()) : IM_OFFLINE,
|
||||||
static_cast<U32>((message_data.has("parent_estate_id")) ? message_data["parent_estate_id"].asInteger() : 1), // 1 - IMMainland
|
dialog,
|
||||||
message_data["region_id"].asUUID(),
|
session_id,
|
||||||
position,
|
static_cast<U32>(message_data["timestamp"].asInteger()),
|
||||||
bin_bucket.data(),
|
message_data["from_agent_name"].asString(),
|
||||||
bin_bucket.size(),
|
message_data["message"].asString(),
|
||||||
sender,
|
static_cast<U32>((message_data.has("parent_estate_id")) ? message_data["parent_estate_id"].asInteger() : 1), // 1 - IMMainland
|
||||||
message_data["asset_id"].asUUID());
|
message_data["region_id"].asUUID(),
|
||||||
|
position,
|
||||||
|
local_bin_bucket.data(),
|
||||||
|
local_bin_bucket.size(),
|
||||||
|
local_sender,
|
||||||
|
message_data["asset_id"].asUUID());
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1551,6 +1551,13 @@ U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item, U32 mask)
|
||||||
return mask;
|
return mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (item->getType() == LLAssetType::AT_MESH ||
|
||||||
|
item->getType() == LLAssetType::AT_GLTF ||
|
||||||
|
item->getType() == LLAssetType::AT_GLTF_BIN)
|
||||||
|
{
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
|
||||||
LLPointer<LLViewerInventoryItem> old_item = getItem(item->getUUID());
|
LLPointer<LLViewerInventoryItem> old_item = getItem(item->getUUID());
|
||||||
LLPointer<LLViewerInventoryItem> new_item;
|
LLPointer<LLViewerInventoryItem> new_item;
|
||||||
if(old_item)
|
if(old_item)
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,8 @@ LLViewerAssetDictionary::LLViewerAssetDictionary()
|
||||||
addEntry(LLViewerAssetType::AT_NONE, new ViewerAssetEntry(DAD_NONE));
|
addEntry(LLViewerAssetType::AT_NONE, new ViewerAssetEntry(DAD_NONE));
|
||||||
addEntry(LLViewerAssetType::AT_SETTINGS, new ViewerAssetEntry(DAD_SETTINGS));
|
addEntry(LLViewerAssetType::AT_SETTINGS, new ViewerAssetEntry(DAD_SETTINGS));
|
||||||
addEntry(LLViewerAssetType::AT_MATERIAL, new ViewerAssetEntry(DAD_MATERIAL));
|
addEntry(LLViewerAssetType::AT_MATERIAL, new ViewerAssetEntry(DAD_MATERIAL));
|
||||||
|
addEntry(LLViewerAssetType::AT_GLTF, new ViewerAssetEntry(DAD_GLTF));
|
||||||
|
addEntry(LLViewerAssetType::AT_GLTF_BIN, new ViewerAssetEntry(DAD_GLTF_BIN));
|
||||||
};
|
};
|
||||||
|
|
||||||
EDragAndDropType LLViewerAssetType::lookupDragAndDropType(EType asset_type)
|
EDragAndDropType LLViewerAssetType::lookupDragAndDropType(EType asset_type)
|
||||||
|
|
|
||||||
|
|
@ -305,9 +305,17 @@ void LLResourceUploadInfo::assignDefaults()
|
||||||
mDescription = "(No Description)";
|
mDescription = "(No Description)";
|
||||||
}
|
}
|
||||||
|
|
||||||
mFolderId = gInventory.findUserDefinedCategoryUUIDForType(
|
if (mAssetType == LLAssetType::AT_GLTF ||
|
||||||
(mDestinationFolderType == LLFolderType::FT_NONE) ?
|
mAssetType == LLAssetType::AT_GLTF_BIN)
|
||||||
(LLFolderType::EType)mAssetType : mDestinationFolderType);
|
{
|
||||||
|
mFolderId = LLUUID::null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mFolderId = gInventory.findUserDefinedCategoryUUIDForType(
|
||||||
|
(mDestinationFolderType == LLFolderType::FT_NONE) ?
|
||||||
|
(LLFolderType::EType)mAssetType : mDestinationFolderType);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string LLResourceUploadInfo::getDisplayName() const
|
std::string LLResourceUploadInfo::getDisplayName() const
|
||||||
|
|
|
||||||
|
|
@ -2733,7 +2733,13 @@ void LLViewerMediaImpl::mimeDiscoveryCoro(std::string url)
|
||||||
{
|
{
|
||||||
if (initializeMedia(mimeType))
|
if (initializeMedia(mimeType))
|
||||||
{
|
{
|
||||||
loadURI();
|
ref();
|
||||||
|
LLAppViewer::instance()->postToMainCoro([this]()
|
||||||
|
{
|
||||||
|
loadURI();
|
||||||
|
unref();
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -143,6 +143,7 @@
|
||||||
#include "boost/unordered_map.hpp"
|
#include "boost/unordered_map.hpp"
|
||||||
#include <boost/regex.hpp>
|
#include <boost/regex.hpp>
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
|
#include <boost/json.hpp>
|
||||||
#include "llcleanup.h"
|
#include "llcleanup.h"
|
||||||
#include "llviewershadermgr.h"
|
#include "llviewershadermgr.h"
|
||||||
#include "gltfscenemanager.h"
|
#include "gltfscenemanager.h"
|
||||||
|
|
@ -4008,6 +4009,13 @@ bool enable_os_exception()
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool enable_gltf()
|
||||||
|
{
|
||||||
|
static LLCachedControl<bool> enablegltf(gSavedSettings, "GLTFEnabled", false);
|
||||||
|
return enablegltf;
|
||||||
|
}
|
||||||
|
|
||||||
class LLSelfRemoveAllAttachments : public view_listener_t
|
class LLSelfRemoveAllAttachments : public view_listener_t
|
||||||
{
|
{
|
||||||
bool handleEvent(const LLSD& userdata)
|
bool handleEvent(const LLSD& userdata)
|
||||||
|
|
@ -10045,7 +10053,6 @@ class LLAdvancedClickGLTFOpen: public view_listener_t
|
||||||
{
|
{
|
||||||
bool handleEvent(const LLSD& userdata)
|
bool handleEvent(const LLSD& userdata)
|
||||||
{
|
{
|
||||||
// open personal lighting floater when previewing an HDRI (keeps HDRI from implicitly unloading when opening build tools)
|
|
||||||
LL::GLTFSceneManager::instance().load();
|
LL::GLTFSceneManager::instance().load();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -10055,7 +10062,6 @@ class LLAdvancedClickGLTFSaveAs : public view_listener_t
|
||||||
{
|
{
|
||||||
bool handleEvent(const LLSD& userdata)
|
bool handleEvent(const LLSD& userdata)
|
||||||
{
|
{
|
||||||
// open personal lighting floater when previewing an HDRI (keeps HDRI from implicitly unloading when opening build tools)
|
|
||||||
LL::GLTFSceneManager::instance().saveAs();
|
LL::GLTFSceneManager::instance().saveAs();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -10065,12 +10071,39 @@ class LLAdvancedClickGLTFDecompose : public view_listener_t
|
||||||
{
|
{
|
||||||
bool handleEvent(const LLSD& userdata)
|
bool handleEvent(const LLSD& userdata)
|
||||||
{
|
{
|
||||||
// open personal lighting floater when previewing an HDRI (keeps HDRI from implicitly unloading when opening build tools)
|
|
||||||
LL::GLTFSceneManager::instance().decomposeSelection();
|
LL::GLTFSceneManager::instance().decomposeSelection();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class LLAdvancedClickGLTFUpload: public view_listener_t
|
||||||
|
{
|
||||||
|
bool handleEvent(const LLSD& userdata)
|
||||||
|
{
|
||||||
|
LL::GLTFSceneManager::instance().uploadSelection();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class LLAdvancedClickResizeWindow : public view_listener_t
|
||||||
|
{
|
||||||
|
bool handleEvent(const LLSD& userdata)
|
||||||
|
{
|
||||||
|
S32 w = 0;
|
||||||
|
S32 h = 0;
|
||||||
|
|
||||||
|
sscanf(userdata.asString().c_str(), "%dx%d", &w, &h);
|
||||||
|
|
||||||
|
if (w > 0 && h > 0)
|
||||||
|
{
|
||||||
|
gViewerWindow->getWindow()->setSize(LLCoordWindow(w, h));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// these are used in the gl menus to set control values that require shader recompilation
|
// these are used in the gl menus to set control values that require shader recompilation
|
||||||
class LLToggleShaderControl : public view_listener_t
|
class LLToggleShaderControl : public view_listener_t
|
||||||
{
|
{
|
||||||
|
|
@ -12527,6 +12560,8 @@ void initialize_menus()
|
||||||
view_listener_t::addMenu(new LLAdvancedClickGLTFOpen(), "Advanced.ClickGLTFOpen");
|
view_listener_t::addMenu(new LLAdvancedClickGLTFOpen(), "Advanced.ClickGLTFOpen");
|
||||||
view_listener_t::addMenu(new LLAdvancedClickGLTFSaveAs(), "Advanced.ClickGLTFSaveAs");
|
view_listener_t::addMenu(new LLAdvancedClickGLTFSaveAs(), "Advanced.ClickGLTFSaveAs");
|
||||||
view_listener_t::addMenu(new LLAdvancedClickGLTFDecompose(), "Advanced.ClickGLTFDecompose");
|
view_listener_t::addMenu(new LLAdvancedClickGLTFDecompose(), "Advanced.ClickGLTFDecompose");
|
||||||
|
view_listener_t::addMenu(new LLAdvancedClickGLTFUpload(), "Advanced.ClickGLTFUpload");
|
||||||
|
view_listener_t::addMenu(new LLAdvancedClickResizeWindow(), "Advanced.ClickResizeWindow");
|
||||||
view_listener_t::addMenu(new LLAdvancedPurgeShaderCache(), "Advanced.ClearShaderCache");
|
view_listener_t::addMenu(new LLAdvancedPurgeShaderCache(), "Advanced.ClearShaderCache");
|
||||||
view_listener_t::addMenu(new LLAdvancedRebuildTerrain(), "Advanced.RebuildTerrain");
|
view_listener_t::addMenu(new LLAdvancedRebuildTerrain(), "Advanced.RebuildTerrain");
|
||||||
//[FIX FIRE-1927 - enable DoubleClickTeleport shortcut : SJ]
|
//[FIX FIRE-1927 - enable DoubleClickTeleport shortcut : SJ]
|
||||||
|
|
@ -12891,6 +12926,7 @@ void initialize_menus()
|
||||||
commit.add("Pathfinding.Characters.Select", boost::bind(&LLFloaterPathfindingCharacters::openCharactersWithSelectedObjects));
|
commit.add("Pathfinding.Characters.Select", boost::bind(&LLFloaterPathfindingCharacters::openCharactersWithSelectedObjects));
|
||||||
enable.add("EnableSelectInPathfindingCharacters", boost::bind(&enable_object_select_in_pathfinding_characters));
|
enable.add("EnableSelectInPathfindingCharacters", boost::bind(&enable_object_select_in_pathfinding_characters));
|
||||||
enable.add("Advanced.EnableErrorOSException", boost::bind(&enable_os_exception));
|
enable.add("Advanced.EnableErrorOSException", boost::bind(&enable_os_exception));
|
||||||
|
enable.add("EnableGLTF", boost::bind(&enable_gltf));
|
||||||
enable.add("EnableBridgeFunction", boost::bind(&enable_bridge_function)); // <FS:CR>
|
enable.add("EnableBridgeFunction", boost::bind(&enable_bridge_function)); // <FS:CR>
|
||||||
|
|
||||||
view_listener_t::addMenu(new LLFloaterVisible(), "FloaterVisible");
|
view_listener_t::addMenu(new LLFloaterVisible(), "FloaterVisible");
|
||||||
|
|
|
||||||
|
|
@ -4466,7 +4466,9 @@ LLMatrix4a LLViewerObject::getGLTFNodeTransformAgent(S32 node_index) const
|
||||||
|
|
||||||
LLMatrix4a asset_to_agent = getGLTFAssetToAgentTransform();
|
LLMatrix4a asset_to_agent = getGLTFAssetToAgentTransform();
|
||||||
LLMatrix4a node_to_agent;
|
LLMatrix4a node_to_agent;
|
||||||
matMul(node.mAssetMatrix, asset_to_agent, node_to_agent);
|
LLMatrix4a am;
|
||||||
|
am.loadu(glm::value_ptr(node.mAssetMatrix));
|
||||||
|
matMul(am, asset_to_agent, node_to_agent);
|
||||||
|
|
||||||
mat = node_to_agent;
|
mat = node_to_agent;
|
||||||
}
|
}
|
||||||
|
|
@ -4477,6 +4479,7 @@ LLMatrix4a LLViewerObject::getGLTFNodeTransformAgent(S32 node_index) const
|
||||||
|
|
||||||
return mat;
|
return mat;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLViewerObject::getGLTFNodeTransformAgent(S32 node_index, LLVector3* position, LLQuaternion* rotation, LLVector3* scale) const
|
void LLViewerObject::getGLTFNodeTransformAgent(S32 node_index, LLVector3* position, LLQuaternion* rotation, LLVector3* scale) const
|
||||||
{
|
{
|
||||||
LLMatrix4a node_to_agent = getGLTFNodeTransformAgent(node_index);
|
LLMatrix4a node_to_agent = getGLTFNodeTransformAgent(node_index);
|
||||||
|
|
@ -4524,7 +4527,9 @@ void LLViewerObject::setGLTFNodeRotationAgent(S32 node_index, const LLQuaternion
|
||||||
if (node.mParent != -1)
|
if (node.mParent != -1)
|
||||||
{
|
{
|
||||||
auto& parent = mGLTFAsset->mNodes[node.mParent];
|
auto& parent = mGLTFAsset->mNodes[node.mParent];
|
||||||
matMul(agent_to_asset, parent.mAssetMatrixInv, agent_to_node);
|
LLMatrix4a ami;
|
||||||
|
ami.loadu(glm::value_ptr(parent.mAssetMatrixInv));
|
||||||
|
matMul(agent_to_asset, ami, agent_to_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
LLQuaternion agent_to_node_rot(agent_to_node.asMatrix4());
|
LLQuaternion agent_to_node_rot(agent_to_node.asMatrix4());
|
||||||
|
|
@ -4536,9 +4541,13 @@ void LLViewerObject::setGLTFNodeRotationAgent(S32 node_index, const LLQuaternion
|
||||||
LLVector3 pos;
|
LLVector3 pos;
|
||||||
LLQuaternion rot;
|
LLQuaternion rot;
|
||||||
LLVector3 scale;
|
LLVector3 scale;
|
||||||
decomposeMatrix(node.mMatrix, pos, rot, scale);
|
LLMatrix4a mat;
|
||||||
|
mat.loadu(glm::value_ptr(node.mMatrix));
|
||||||
|
decomposeMatrix(mat, pos, rot, scale);
|
||||||
|
|
||||||
node.mMatrix.asMatrix4().initAll(scale, new_rot, pos);
|
mat.asMatrix4().initAll(scale, new_rot, pos);
|
||||||
|
|
||||||
|
node.mMatrix = glm::make_mat4(mat.getF32ptr());
|
||||||
|
|
||||||
mGLTFAsset->updateTransforms();
|
mGLTFAsset->updateTransforms();
|
||||||
}
|
}
|
||||||
|
|
@ -4552,7 +4561,9 @@ void LLViewerObject::moveGLTFNode(S32 node_index, const LLVector3& offset)
|
||||||
|
|
||||||
LLMatrix4a agent_to_asset = getAgentToGLTFAssetTransform();
|
LLMatrix4a agent_to_asset = getAgentToGLTFAssetTransform();
|
||||||
LLMatrix4a agent_to_node;
|
LLMatrix4a agent_to_node;
|
||||||
matMul(agent_to_asset, node.mAssetMatrixInv, agent_to_node);
|
LLMatrix4a ami;
|
||||||
|
ami.loadu(glm::value_ptr(node.mAssetMatrixInv));
|
||||||
|
matMul(agent_to_asset, ami, agent_to_node);
|
||||||
|
|
||||||
LLVector4a origin = LLVector4a::getZero();
|
LLVector4a origin = LLVector4a::getZero();
|
||||||
LLVector4a offset_v;
|
LLVector4a offset_v;
|
||||||
|
|
@ -4569,7 +4580,12 @@ void LLViewerObject::moveGLTFNode(S32 node_index, const LLVector3& offset)
|
||||||
trans.setIdentity();
|
trans.setIdentity();
|
||||||
trans.mMatrix[3] = offset_v;
|
trans.mMatrix[3] = offset_v;
|
||||||
|
|
||||||
matMul(trans, node.mMatrix, node.mMatrix);
|
LLMatrix4a mat;
|
||||||
|
mat.loadu(glm::value_ptr(node.mMatrix));
|
||||||
|
|
||||||
|
matMul(trans, mat, mat);
|
||||||
|
|
||||||
|
node.mMatrix = glm::make_mat4(mat.getF32ptr());
|
||||||
|
|
||||||
// TODO -- only update transforms for this node and its children (or use a dirty flag)
|
// TODO -- only update transforms for this node and its children (or use a dirty flag)
|
||||||
mGLTFAsset->updateTransforms();
|
mGLTFAsset->updateTransforms();
|
||||||
|
|
@ -7690,6 +7706,23 @@ void LLViewerObject::shrinkWrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LLViewerObject::setGLTFAsset(const LLUUID& id)
|
||||||
|
{
|
||||||
|
//get the sculpt params and set the sculpt type and id
|
||||||
|
auto* param = getExtraParameterEntryCreate(LLNetworkData::PARAMS_SCULPT);
|
||||||
|
|
||||||
|
LLSculptParams* sculpt_params = (LLSculptParams*)param->data;
|
||||||
|
sculpt_params->setSculptTexture(id, LL_SCULPT_TYPE_GLTF);
|
||||||
|
|
||||||
|
setParameterEntryInUse(LLNetworkData::PARAMS_SCULPT, true, true);
|
||||||
|
|
||||||
|
// Update the volume
|
||||||
|
LLVolumeParams volume_params;
|
||||||
|
volume_params.setSculptID(id, LL_SCULPT_TYPE_GLTF);
|
||||||
|
updateVolume(volume_params);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class ObjectPhysicsProperties : public LLHTTPNode
|
class ObjectPhysicsProperties : public LLHTTPNode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @file llviewerobject.h
|
* @file llviewerobject.h
|
||||||
* @brief Description of LLViewerObject class, which is the base class for most objects in the viewer.
|
* @brief Description of LLViewerObject class, which is the base class for most objects in the viewer.
|
||||||
|
|
@ -759,6 +760,11 @@ public:
|
||||||
F32 mPhysicsDensity;
|
F32 mPhysicsDensity;
|
||||||
F32 mPhysicsRestitution;
|
F32 mPhysicsRestitution;
|
||||||
|
|
||||||
|
// set the GLTF asset for this LLViewerObject to the specified asset id
|
||||||
|
// id MUST be for a GLTF asset (LLAssetType::AT_GLTF)
|
||||||
|
// will relesae any currently held references to a GLTF asset on id change
|
||||||
|
void setGLTFAsset(const LLUUID& id);
|
||||||
|
|
||||||
// Associated GLTF Asset
|
// Associated GLTF Asset
|
||||||
std::shared_ptr<LL::GLTF::Asset> mGLTFAsset;
|
std::shared_ptr<LL::GLTF::Asset> mGLTFAsset;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2639,24 +2639,14 @@ void LLViewerRegion::setSimulatorFeatures(const LLSD& sim_features)
|
||||||
|
|
||||||
gSavedSettings.setBOOL("RenderMirrors", mirrors_enabled);
|
gSavedSettings.setBOOL("RenderMirrors", mirrors_enabled);
|
||||||
|
|
||||||
if (features.has("PBRTerrainEnabled"))
|
if (features.has("GLTFEnabled"))
|
||||||
{
|
{
|
||||||
bool enabled = features["PBRTerrainEnabled"];
|
bool enabled = features["GLTFEnabled"];
|
||||||
gSavedSettings.setBOOL("RenderTerrainPBREnabled", enabled);
|
gSavedSettings.setBOOL("GLTFEnabled", enabled);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
gSavedSettings.setBOOL("RenderTerrainPBREnabled", false);
|
gSavedSettings.setBOOL("GLTFEnabled", false);
|
||||||
}
|
|
||||||
|
|
||||||
if (features.has("PBRMaterialSwatchEnabled"))
|
|
||||||
{
|
|
||||||
bool enabled = features["PBRMaterialSwatchEnabled"];
|
|
||||||
gSavedSettings.setBOOL("UIPreviewMaterial", enabled);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
gSavedSettings.setBOOL("UIPreviewMaterial", false);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,7 @@
|
||||||
#include "llsculptidsize.h"
|
#include "llsculptidsize.h"
|
||||||
#include "llavatarappearancedefines.h"
|
#include "llavatarappearancedefines.h"
|
||||||
#include "llgltfmateriallist.h"
|
#include "llgltfmateriallist.h"
|
||||||
|
#include "gltfscenemanager.h"
|
||||||
// [RLVa:KB] - Checked: RLVa-2.0.0
|
// [RLVa:KB] - Checked: RLVa-2.0.0
|
||||||
#include "rlvactions.h"
|
#include "rlvactions.h"
|
||||||
#include "rlvlocks.h"
|
#include "rlvlocks.h"
|
||||||
|
|
@ -1290,6 +1291,11 @@ bool LLVOVolume::setVolume(const LLVolumeParams ¶ms_in, const S32 detail, bo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((volume_params.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_GLTF)
|
||||||
|
{ // notify GLTFSceneManager about new GLTF object
|
||||||
|
LL::GLTFSceneManager::instance().addGLTFObject(this, volume_params.getSculptID());
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (NO_LOD == lod)
|
else if (NO_LOD == lod)
|
||||||
|
|
@ -1564,6 +1570,12 @@ bool LLVOVolume::calcLOD()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mGLTFAsset != nullptr)
|
||||||
|
{
|
||||||
|
// do not calculate LOD for GLTF objects
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
S32 cur_detail = 0;
|
S32 cur_detail = 0;
|
||||||
|
|
||||||
F32 radius;
|
F32 radius;
|
||||||
|
|
@ -5921,7 +5933,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
|
||||||
|
|
||||||
LLVOVolume* vobj = drawablep->getVOVolume();
|
LLVOVolume* vobj = drawablep->getVOVolume();
|
||||||
|
|
||||||
if (!vobj || vobj->isDead())
|
if (!vobj || vobj->isDead() || vobj->mGLTFAsset)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -474,6 +474,13 @@
|
||||||
<menu_item_call label="Öffnen..." name="Open..."/>
|
<menu_item_call label="Öffnen..." name="Open..."/>
|
||||||
<menu_item_call label="Speichern unter..." name="Save As..."/>
|
<menu_item_call label="Speichern unter..." name="Save As..."/>
|
||||||
<menu_item_call label="Trennen..." name="Decompose..."/>
|
<menu_item_call label="Trennen..." name="Decompose..."/>
|
||||||
|
<menu_item_call label="Hochladen..." name="Upload..."/>
|
||||||
|
</menu>
|
||||||
|
<menu label="Auflösung" name="Video">
|
||||||
|
<menu_item_call label="1080x1920" name="1080x1920"/>
|
||||||
|
<menu_item_call label="1920x1080" name="1920x1080"/>
|
||||||
|
<menu_item_call label="1280x720" name="1280x720"/>
|
||||||
|
<menu_item_call label="720x1280" name="720x1280"/>
|
||||||
</menu>
|
</menu>
|
||||||
<menu label="Render-Tests" name="Render Tests">
|
<menu label="Render-Tests" name="Render Tests">
|
||||||
<menu_item_check label="Kamera-Versatz" name="Camera Offset"/>
|
<menu_item_check label="Kamera-Versatz" name="Camera Offset"/>
|
||||||
|
|
|
||||||
|
|
@ -5082,6 +5082,14 @@ Möchten Sie fortfahren?
|
||||||
Sie müssen ein Objekt auswählen, das mit einem GLTF-Gegenstand verknüpft ist.
|
Sie müssen ein Objekt auswählen, das mit einem GLTF-Gegenstand verknüpft ist.
|
||||||
<usetemplate name="okbutton" yestext="OK"/>
|
<usetemplate name="okbutton" yestext="OK"/>
|
||||||
</notification>
|
</notification>
|
||||||
|
<notification name="GLTFUploadSelection">
|
||||||
|
Sie müssen ein Objekt auswählen, das nur mit einem lokalen GLTF-Gegenstand verknüpft ist.
|
||||||
|
<usetemplate name="okbutton" yestext="OK"/>
|
||||||
|
</notification>
|
||||||
|
<notification name="GLTFUploadInProgress">
|
||||||
|
Upload wird gerade durchgeführt. Bitte versuchen Sie es später erneut.
|
||||||
|
<usetemplate name="okbutton" yestext="OK"/>
|
||||||
|
</notification>
|
||||||
|
|
||||||
<notification name="NoValidEnvSettingFound">
|
<notification name="NoValidEnvSettingFound">
|
||||||
Keine gültige Einstellung für die Umgebung ausgewählt.
|
Keine gültige Einstellung für die Umgebung ausgewählt.
|
||||||
|
|
|
||||||
|
|
@ -4120,21 +4120,69 @@
|
||||||
<menu_item_call
|
<menu_item_call
|
||||||
label="Open..."
|
label="Open..."
|
||||||
name="Open...">
|
name="Open...">
|
||||||
|
<menu_item_call.on_enable
|
||||||
|
function="EnableGLTF"/>
|
||||||
<menu_item_call.on_click
|
<menu_item_call.on_click
|
||||||
function="Advanced.ClickGLTFOpen" />
|
function="Advanced.ClickGLTFOpen" />
|
||||||
</menu_item_call>
|
</menu_item_call>
|
||||||
<menu_item_call
|
<menu_item_call
|
||||||
label="Save As..."
|
label="Save As..."
|
||||||
name="Save As...">
|
name="Save As...">
|
||||||
|
<menu_item_call.on_enable
|
||||||
|
function="EnableGLTF"/>
|
||||||
<menu_item_call.on_click
|
<menu_item_call.on_click
|
||||||
function="Advanced.ClickGLTFSaveAs" />
|
function="Advanced.ClickGLTFSaveAs" />
|
||||||
</menu_item_call>
|
</menu_item_call>
|
||||||
<menu_item_call
|
<menu_item_call
|
||||||
label="Decompose..."
|
label="Decompose..."
|
||||||
name="Decompose...">
|
name="Decompose...">
|
||||||
|
<menu_item_call.on_enable
|
||||||
|
function="EnableGLTF"/>
|
||||||
<menu_item_call.on_click
|
<menu_item_call.on_click
|
||||||
function="Advanced.ClickGLTFDecompose" />
|
function="Advanced.ClickGLTFDecompose" />
|
||||||
</menu_item_call>
|
</menu_item_call>
|
||||||
|
<menu_item_call
|
||||||
|
label="Upload..."
|
||||||
|
name="Upload...">
|
||||||
|
<menu_item_call.on_enable
|
||||||
|
function="EnableGLTF"/>
|
||||||
|
<menu_item_call.on_click
|
||||||
|
function="Advanced.ClickGLTFUpload" />
|
||||||
|
</menu_item_call>
|
||||||
|
</menu>
|
||||||
|
<menu
|
||||||
|
create_jump_keys="true"
|
||||||
|
label="Video"
|
||||||
|
name="Video"
|
||||||
|
tear_off="true">
|
||||||
|
<menu_item_call
|
||||||
|
label="1080x1920"
|
||||||
|
name="1080x1920">
|
||||||
|
<menu_item_call.on_click
|
||||||
|
function="Advanced.ClickResizeWindow"
|
||||||
|
parameter="1080x1920"/>
|
||||||
|
</menu_item_call>
|
||||||
|
<menu_item_call
|
||||||
|
label="1920x1080"
|
||||||
|
name="1920x1080">
|
||||||
|
<menu_item_call.on_click
|
||||||
|
function="Advanced.ClickResizeWindow"
|
||||||
|
parameter="1920x1080"/>
|
||||||
|
</menu_item_call>
|
||||||
|
<menu_item_call
|
||||||
|
label="1280x720"
|
||||||
|
name="1280x720">
|
||||||
|
<menu_item_call.on_click
|
||||||
|
function="Advanced.ClickResizeWindow"
|
||||||
|
parameter="1280x720"/>
|
||||||
|
</menu_item_call>
|
||||||
|
<menu_item_call
|
||||||
|
label="720x1280"
|
||||||
|
name="720x1280">
|
||||||
|
<menu_item_call.on_click
|
||||||
|
function="Advanced.ClickResizeWindow"
|
||||||
|
parameter="720x1280"/>
|
||||||
|
</menu_item_call>
|
||||||
</menu>
|
</menu>
|
||||||
<menu
|
<menu
|
||||||
create_jump_keys="true"
|
create_jump_keys="true"
|
||||||
|
|
|
||||||
|
|
@ -14367,6 +14367,28 @@ This will replace the items in the selected outfit with the items you are wearin
|
||||||
yestext="OK"/>
|
yestext="OK"/>
|
||||||
</notification>
|
</notification>
|
||||||
|
|
||||||
|
<notification
|
||||||
|
icon="alertmodal.tga"
|
||||||
|
name="GLTFUploadSelection"
|
||||||
|
type="alert">
|
||||||
|
You must select an object that has local-only GLTF asset associated with it.
|
||||||
|
<tag>fail</tag>
|
||||||
|
<usetemplate
|
||||||
|
name="okbutton"
|
||||||
|
yestext="OK"/>
|
||||||
|
</notification>
|
||||||
|
|
||||||
|
<notification
|
||||||
|
icon="alertmodal.tga"
|
||||||
|
name="GLTFUploadInProgress"
|
||||||
|
type="alert">
|
||||||
|
Upload is currently in progress. Please try again later.
|
||||||
|
<tag>fail</tag>
|
||||||
|
<usetemplate
|
||||||
|
name="okbutton"
|
||||||
|
yestext="OK"/>
|
||||||
|
</notification>
|
||||||
|
|
||||||
|
|
||||||
<notification
|
<notification
|
||||||
icon="alertmodal.tga"
|
icon="alertmodal.tga"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue