summaryrefslogtreecommitdiff
path: root/indra/newview/gltf/README.md
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/gltf/README.md')
-rw-r--r--indra/newview/gltf/README.md156
1 files changed, 156 insertions, 0 deletions
diff --git a/indra/newview/gltf/README.md b/indra/newview/gltf/README.md
new file mode 100644
index 0000000000..8e7df0a439
--- /dev/null
+++ b/indra/newview/gltf/README.md
@@ -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.
+
+
+