summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCoprDistGit <infra@openeuler.org>2023-05-31 07:41:54 +0000
committerCoprDistGit <infra@openeuler.org>2023-05-31 07:41:54 +0000
commitf0abc5b96d066130fe2e1fcef192bac2d6a68950 (patch)
tree967fdc3009744f45ddd7d065c4657f871bd9e564
parent31a9eeef21c1ab2ea09034404135c152be90f1b9 (diff)
automatic import of python-gltflib
-rw-r--r--.gitignore1
-rw-r--r--python-gltflib.spec1736
-rw-r--r--sources1
3 files changed, 1738 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index e69de29..28d8c06 100644
--- a/.gitignore
+++ b/.gitignore
@@ -0,0 +1 @@
+/gltflib-1.0.13.tar.gz
diff --git a/python-gltflib.spec b/python-gltflib.spec
new file mode 100644
index 0000000..0a9af7e
--- /dev/null
+++ b/python-gltflib.spec
@@ -0,0 +1,1736 @@
+%global _empty_manifest_terminate_build 0
+Name: python-gltflib
+Version: 1.0.13
+Release: 1
+Summary: Library for parsing, creating, and converting glTF 2.0 files in Python.
+License: MIT
+URL: http://github.com/sergkr/gltflib
+Source0: https://mirrors.nju.edu.cn/pypi/web/packages/c4/a7/d1a819544e2d57e4958595725e5f371f8fac0060439989760b36006d3b11/gltflib-1.0.13.tar.gz
+BuildArch: noarch
+
+Requires: python3-dataclasses-json
+Requires: python3-dataclasses
+
+%description
+
+# gltflib
+
+Library for parsing, creating, and converting glTF 2.0 files in Python 3.6+.
+
+## Overview
+
+This library is intended for working with glTF 2.0 at a fairly low level, meaning you are
+responsible for managing the actual geometry data yourself. This library facilitates saving
+this data into a properly formatted glTF/GLB file. It also helps with converting resources
+inside a glTF/GLB file between external files or web URLs, data URLs, and embedded GLB
+resources.
+
+## Installation
+
+This library can be installed using pip:
+
+```
+pip install gltflib
+```
+
+## Usage
+
+The examples below illustrate how to use this library for a couple sample scenarios. The
+example models come from the Khronos glTF-Sample-Models repository available here:
+
+[https://github.com/KhronosGroup/glTF-Sample-Models](https://github.com/KhronosGroup/glTF-Sample-Models)
+
+### Parsing a glTF 2.0 Model
+
+To load a glTF 2.0 model:
+
+```python
+from gltflib import GLTF
+
+gltf = GLTF.load('glTF-Sample-Models/2.0/BoxTextured/glTF/BoxTextured.gltf')
+```
+
+The `GLTF.load` static method supports loading both the JSON-based `.gltf` format, as well
+as the binary `.glb` format. The type of the file will be determined based on the filename
+extension. Alternatively, you can use `GLTF.load_gltf(filename)` or `GLTF.load_glb(filename)`.
+
+After loading, you can inspect the model structure by accessing the `model` property:
+
+```python
+print(gltf.model)
+# GLTFModel(extensions=None, extras=None, accessors=[Accessor(extensions=None, extras=None, name=None, bufferView=0, byteOffset=0, componentType=5123, ...
+```
+
+You can also inspect the various model properties:
+
+```python
+print(gltf.model.buffers[0].uri)
+# BoxTextured0.bin
+```
+
+A glTF 2.0 model may contain resources, such as vertex geometry or image textures. These
+resources can be embedded as part of the model file, or (as with the above example) be
+referenced as external file resources.
+
+In either case, the resources are parsed alongside the model structure into the `resources`
+property after loading a model:
+
+```python
+print(gltf.resources)
+# [FileResource(CesiumLogoFlat.png), FileResource(BoxTextured0.bin)]
+```
+
+Note that the actual content of these external file resources is *not* loaded by default
+when loading a model. You can load the resource into memory in one of two ways. One way
+is to call the `load()` method on the resource:
+
+```python
+resource = gltf.resources[0]
+resource.load() # Assumes resource is a FileResource
+```
+
+Another way is to pass the `load_file_resources` flag when calling `GLTF.load()`:
+
+```python
+gltf = GLTF.load(filename, load_file_resources=True)
+```
+
+In either case, now the file resource data can be accessed via the `data` property:
+
+```python
+print(resource.data)
+# b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80?\x00\x00\x00\x00\x00\x00\...
+```
+
+Embedded resources in binary GLB files are also parsed into the `resources` list, but
+they will be of type `GLBResource` instead of `FileResource`:
+
+```python
+glb = GLTF.load('glTF-Sample-Models/2.0/BoxTextured/glTF-Binary/BoxTextured.glb')
+print(glb.resources)
+# [<gltflib.gltf_resource.GLBResource object at 0x7f03db7c1400>]
+```
+
+For embedded resources, the content is parsed into memory automatically. The binary data
+can be accessed using the `data` property:
+
+```python
+resource = glb.resources[0]
+print(resource.data)
+# b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80?\x00\x00\x00\x00\x00\x00\...'
+```
+
+### Exporting a glTF 2.0 Model
+
+To export a model, call the `GLTF.export()` instance method in the `GLTF` class.
+
+The example below creates a simple glTF 2.0 mode in memory (consisting of a single
+triangle), then exports it as a glTF file named `triangle.gltf` (alongside with an
+external file resource named `vertices.bin`):
+
+```python
+import struct
+import operator
+from gltflib import (
+ GLTF, GLTFModel, Asset, Scene, Node, Mesh, Primitive, Attributes, Buffer, BufferView, Accessor, AccessorType,
+ BufferTarget, ComponentType, GLBResource, FileResource)
+
+vertices = [
+ (-4774424.719997984, 4163079.2597148907, 671001.6353722484),
+ (-4748098.650098154, 4163079.259714891, 837217.8990777463),
+ (-4689289.5292739635, 4246272.966707474, 742710.4976137652)
+]
+
+vertex_bytearray = bytearray()
+for vertex in vertices:
+ for value in vertex:
+ vertex_bytearray.extend(struct.pack('f', value))
+bytelen = len(vertex_bytearray)
+mins = [min([operator.itemgetter(i)(vertex) for vertex in vertices]) for i in range(3)]
+maxs = [max([operator.itemgetter(i)(vertex) for vertex in vertices]) for i in range(3)]
+model = GLTFModel(
+ asset=Asset(version='2.0'),
+ scenes=[Scene(nodes=[0])],
+ nodes=[Node(mesh=0)],
+ meshes=[Mesh(primitives=[Primitive(attributes=Attributes(POSITION=0))])],
+ buffers=[Buffer(byteLength=bytelen, uri='vertices.bin')],
+ bufferViews=[BufferView(buffer=0, byteOffset=0, byteLength=bytelen, target=BufferTarget.ARRAY_BUFFER.value)],
+ accessors=[Accessor(bufferView=0, byteOffset=0, componentType=ComponentType.FLOAT.value, count=len(vertices),
+ type=AccessorType.VEC3.value, min=mins, max=maxs)]
+)
+
+resource = FileResource('vertices.bin', data=vertex_bytearray)
+gltf = GLTF(model=model, resources=[resource])
+gltf.export('triangle.gltf')
+```
+
+As with `load`, the `export` method infers the format based on the filename extension
+(`.gltf` vs `.glb`). However, you can also call `export_gltf` or `export_glb` to manually
+force the format.
+
+In the above example, the export will produce two files: `triangle.gltf` and `vertices.bin`.
+However, it is possible to bypass saving external file resources by setting the
+`save_file_resources` flag to `False` when calling `export`:
+
+```python
+gltf.export('triangle.gltf', save_file_resources=False)
+```
+
+To export the model as a binary GLB instead, simply change the extension when calling
+`export`, or use `export_glb`:
+
+```python
+gltf.export('triangle.glb')
+```
+
+Note that when exporting as a GLB, all resources will be embedded by default (even if
+they were instantiated as a `FileResource`). This is generally the desired behavior when
+saving as a GLB.
+
+However, it is possible to force some or all resources to remain external when exporting
+a GLB. To do so, you must call `export_glb` (instead of `export`), and setting either
+`embed_buffer_resources` or `embed_image_resources` (or both) to `False`:
+
+```python
+resource = FileResource('vertices.bin', data=vertex_bytearray)
+gltf = GLTF(model=model, resources=[resource])
+gltf.export_glb('triangle.glb', embed_buffer_resources=False, embed_image_resources=False)
+```
+
+In this case, you will also need to ensure that the associated buffers still have the
+appropriate `uri` set in the model:
+
+```python
+model = GLTFModel(
+ ...,
+ buffers=[Buffer(byteLength=bytelen, uri='vertices.bin')],
+```
+
+The model will be exported as a binary GLB, but with external file resources. These
+file resources will be saved by default when exporting the model. However, it is also
+possible to bypass saving external file resources by setting the `save_file_resources`
+to `False` when calling `export_glb`:
+
+```python
+gltf.export_glb('triangle.glb', embed_buffer_resources=False, embed_image_resources=False,
+ save_file_resources=False)
+```
+
+### Converting Between glTF and GLB
+
+To convert a glTF model to GLB, simply load it and export it using the `glb` extension:
+
+```python
+from gltflib import GLTF
+
+gltf = GLTF.load('glTF-Sample-Models/2.0/BoxTextured/glTF/BoxTextured.gltf')
+gltf.export('BoxTextured.glb')
+```
+
+This will automatically convert all external file resources to become embedded GLB
+resources.
+
+The reverse conversion is also possible, though with some caveats. Since a non-binary
+glTF model may not have embedded binary data, the `GLBResource` must first be converted
+to a different resource type. The section on **Resources** below goes into more details,
+but here is a quick example where the `GLBResource` is first converted to a `FileResource`
+with the filename `BoxTextured.bin` prior to exporting to glTF:
+
+```python
+from gltflib import GLTF
+
+gltf = GLTF.load('glTF-Sample-Models/2.0/BoxTextured/glTF-Binary/BoxTextured.glb')
+glb_resource = gltf.get_glb_resource()
+gltf.convert_to_file_resource(glb_resource, 'BoxTextured.bin')
+gltf.export('BoxTextured.gltf')
+```
+
+Note that a GLB file typically contains a single binary GLB chunk that combines data
+from multiple buffers (which are then consumed by multiple buffer views, images, and
+accessors). Currently, when converting a GLB to glTF, the entire GLB chunk can be
+converted to a resource of a different type, but the resource cannot be split out into
+multiple resources (e.g., separate resource per buffer).
+
+### Resources
+
+glTF and GLB models can refer to embedded or external resources (via the buffer or image
+URIs, or in the case of GLB, by leaving the first buffer's URI undefined). These
+resources are represented in this library using subclasses of the `GLTFResource` base
+class. These resources will be parsed when loading a model, and must be properly
+instantiated and added to the model prior to exporting.
+
+There are 4 resource types that are supported by this library:
+
+* `FileResource`: File resources are resources that refer to a file path.
+* `Base64Resource`: Resources that are embedded directly in the glTF (or GLB) file
+using a Base64-encoded data URI.
+* `GLBResource`: Used only by GLB files, this resource type represents the binary GLB
+chunk that is embedded directly in the GLB file.
+* `ExternalResource`: External resources refer to external web URLs.
+
+A reference to a particular resource can be obtained if its URI is known by
+calling `get_resource`:
+
+```python
+gltf = GLTF.load('glTF-Sample-Models/2.0/BoxTextured/glTF/BoxTextured.gltf')
+logo = gltf.get_resource('CesiumLogoFlat.png')
+print(logo)
+# FileResource(CesiumLogoFlat.png)
+```
+
+Alternatively, a list of all resources in a model can be obtained using the
+`resources` list on the loaded model:
+
+```python
+gltf = GLTF.load('glTF-Sample-Models/2.0/BoxTextured/glTF/BoxTextured.gltf')
+print(gltf.resources)
+# [FileResource(CesiumLogoFlat.png), FileResource(BoxTextured0.bin)]
+```
+
+The `GLTF` class provides helper methods that can be used to convert a resource
+from one type to another. Some of these methods require some additional information
+to do the conversion; for instance, the filename when converting to a `FileResource`,
+or the MIME type when converting to a `Base64Resource`.
+
+The sections below go into more detail about each resource type, including their
+caveats and limitations, as well as how to convert a given resource to that type.
+
+#### File Resources
+
+File resources are denoted using the `FileResource` class, and represent resources
+that refer to a file path (generally a relative path, though absolute file paths are
+also supported).
+
+When loading a model, these resources are parsed by looking at the `uri` property on
+buffers and images; however, their content is not automatically loaded unless the
+`load_file_resources` flag is set to `True` when calling `GLTF.load()`:
+
+```python
+gltf = GLTF.load(filename, load_file_resources=True)
+```
+
+Alternatively, the `load()` method can be called on a `FileResource` instance to load
+the data into memory:
+
+```python
+resource = FileResource('triangleWithoutIndices.bin')
+resource.load()
+```
+
+Once the file resource is loaded into memory, its content is accessible via the `data`
+property:
+
+```python
+print(resource.data)
+# b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80?\x00\x00\x00\x00\x00\x00\...
+```
+
+When exporting a model, file resources will be written to disk by default. However,
+this can be bypassed by setting the `save_file_resources` flag `False` when calling
+`export`:
+
+```python
+gltf.export(filename, save_file_resources=False)
+```
+
+When creating a model instance manually, if the intention is to also save file
+resources, then there must be a corresponding `FileResource` in the `resources`
+list for every buffer or image that references a file path (otherwise, an error
+will be raised when attempting to export):
+
+```python
+resource = FileResource('buffer.bin')
+model = GLTFModel(asset=Asset(version='2.0'), buffers=[Buffer(uri='buffer.bin', byteLength=18)])
+gltf = GLTF(model=model, resources=[resource])
+gltf.export('model.gltf')
+```
+
+When instantiating a `FileResource`, if the content of the file is known, it can
+be provided via the `data` constructor parameter:
+
+```python
+resource = FileResource('buffer.bin', data=b'binary content here')
+```
+
+A resource of another type can be converted to a `FileResource` using the
+`convert_to_file_resource` helper method on the GLTF class. This method
+requires a filename as a parameter, and returns the converted `FileResource`
+instance:
+
+```python
+resource = gltf.resources[0]
+file_resource = gltf.convert_to_file_resource(resource, 'BoxTextured.bin')
+```
+
+Note the file will not be created until the model is saved (with `save_file_resources`
+flag set to `True`). Also, note that the resource to be converted must be
+part of the `resources` list in the model (otherwise an error will be raised).
+
+If the resource is already a `FileResource` and the filename matches, no action
+is performed. If the filename is different, then the filename will be updated
+on any buffers and images that reference it.
+
+If the resource to be converted is a `GLBResource` or `Base64Resource`, it will be
+un-embedded and converted to an external file resource, and any buffers that reference
+the resource will be updated appropriately. Any embedded images that reference the
+resource will be updated. If the image previously referenced a buffer view, it will
+now reference a URI instead; the corresponding buffer view will be removed if no
+other parts of the model refer to it. Further, after removing the buffer view, if
+no other buffer views refer to the same buffer, then the buffer will be removed as
+well.
+
+If the resource to be converted is an `ExternalResource`, this method will raise an
+error (accessing external resource data is not supported).
+
+#### Base-64 (Data URI) Resources
+
+glTF supports embedding a resource directly into a JSON-based glTF file (or a GLB
+file, though it's not as common) using a
+[data URI](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs).
+In this scenario, the resource is defined as part of the URI itself, allowing the
+model to be self-contained without necessarily using the GLB format:
+
+```
+{
+ ...
+ "images": [
+ {
+ "uri": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAABccqhmAAAEDW..."
+ }
+ ],
+ ...
+}
+```
+
+When loading such a model, a resource of type `Base64Resource` will be instantiated
+and added to the model's `resources` list. The `uri` property of the resource will
+contain the original data URI, while the `data` property can be used to access the
+decoded binary data:
+
+```python
+gltf = GLTF.load('glTF-Sample-Models/2.0/BoxTextured/glTF-Embedded/BoxTextured.gltf')
+logo = gltf.resources[1]
+print(logo.data)
+# b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80?\x00\x00\x00\x00\x00\x00\...
+```
+
+To instantiate a `Base64Resource`, there are two options. One is to use the
+constructor to pass in the binary data and MIME type (which defaults to
+`application/octet-stream` if not provided):
+
+```python
+resource = Base64Resource(b'sample binary data', mime_type='application/octet-stream')
+```
+
+The other way is to use the `Base64Resource.from_uri` factory method and pass
+in the data URI:
+
+```python
+resource = Base64Resource.from_uri('data:application/octet-stream;base64,c2FtcGxlIGJpbmFyeSBkYXRh')
+```
+
+To convert a resource of another type to a `Base64Resource`, use the
+`GLTF.convert_to_base64_resource` helper method. This method accepts an optional
+`mime_type` parameter if the MIME type of the original resource is known (defaults
+to `application/octet-stream` if not provided):
+
+```python
+gltf = GLTF.load('glTF-Sample-Models/2.0/BoxTextured/glTF/BoxTextured.gltf')
+logo = gltf.get_resource('CesiumLogoFlat.png')
+gltf.convert_to_base64_resource(logo, 'image/png')
+gltf.export('BoxTexturedBase64.gltf')
+```
+
+If the resource to be converted is already a `Base64Resource`, no action is performed.
+
+If the resource is a `FileResource`, then it will be converted to a `Base64Resource`.
+The data for the `FileResource` will be loaded from disk if not already loaded (which
+may raise an `IOError` if the file does not exist).
+
+If the resource is a `GLBResource`, it will be converted to a `Base64Resource`. The
+GLB buffer will be replaced with a buffer with a data URI (or removed entirely if it
+is only used by images). Any images that refer to the resource via a buffer view will
+instead refer to the image directly via a data URI, and the corresponding buffer view
+will be removed (if it is not also referenced elsewhere). Further, if no other buffer
+views refer to the same buffer as the removed buffer view, then the buffer will be
+removed entirely as well.
+
+If the resource is an `ExternalResource`, this method will raise an error (accessing
+external resource data is not supported).
+
+#### GLB Resources
+
+GLB Resources are resources that are embedded directly in a GLB file as binary
+chunks. These resources can only be used with a GLB file (if saving to glTF, these
+resources must first be converted to a different type).
+
+There is generally one GLB chunk in a file (with the chunk type `BIN`), though it
+is valid to have multiple GLB chunks if they have a different chunk type. This
+library supports loading and saving these additional GLB chunks, though no
+assumptions are made about their content.
+
+A reference to the `GLBResource` corresponding to the primary GLB chunk (with the
+chunk type `BIN`) can be obtained by calling `get_glb_resource` on a model
+instance, and its data can be accessed via the `data` property:
+
+```python
+gltf = GLTF.load('glTF-Sample-Models/2.0/BoxTextured/glTF-Binary/BoxTextured.glb')
+glb_resource = gltf.get_glb_resource()
+print(glb_resource.data)
+# b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80?\x00\x00\x00\x00\x00\x00\...
+```
+
+Additional GLB chunks can be referenced by calling `get_glb_resource` with a
+`resource_type` parameter set to the chunk type:
+
+```python
+my_custom_glb_resource = gltf.get_glb_resource(resource_type=123)
+```
+
+An individual resource of another type can be converted to a `GLBResource` using
+the `embed_resource` helper method. This allows embedding a particular resource
+while leaving others external when exporting to GLB (in this scenario, ensure
+to use `export_glb` instead of `export`, and set both `embed_buffer_resources`
+and `embed_image_resources` to `False` to prevent the other resources from also
+being automatically embedded):
+
+```python
+gltf = GLTF.load('glTF-Sample-Models/2.0/BoxTextured/glTF-Binary/BoxTextured.glb')
+logo = gltf.get_resource('CesiumLogoFlat.png')
+gltf.embed_resource(logo)
+gltf.export_glb('BoxTexturedPartial.glb', embed_buffer_resources=False, embed_image_resources=False)
+```
+
+However, the most common scenario is to embed all resources regardless of their
+type, which happens automatically when calling `export` with a `.glb` extension
+(or when calling `export_glb` with the default set of parameters).
+
+Note that embedding an `ExternalResource` is not supported because its data is
+not accessible (this library does not support loading resources from an external
+web URL).
+
+As explained in the other sections, converting a `GLBResource` to a resource of
+another type (i.e., "un-embedding" a resource) will typically not only replace
+the URIs on the corresponding buffers and images, but may also result in removing
+the GLB buffer and buffer views entirely if they are not also referenced elsewhere.
+
+#### External Resources
+
+External resources (represented by the `ExternalResource` class) are resources
+that have an external web URL. While this library is able to load models with
+external web URLs, the resource itself will not be fetched. A resource of type
+`ExternalResource` will be instantiated with the corresponding URI, but the
+library will not perform any web requests to load the resource data. Likewise,
+the library supports saving a model containing `ExternalResource` instances,
+but again, no web requests will be performed.
+
+A resource of another type can be converted to an `ExternalResource` using the
+`GLTF.convert_to_external_resource` helper method, which accepts a URL:
+
+```python
+gltf = GLTF.load('glTF-Sample-Models/2.0/BoxTextured/glTF/BoxTextured.gltf')
+logo = gltf.get_resource('CesiumLogoFlat.png')
+gltf.convert_to_external_resource(logo, 'http://www.example.com/image.png')
+gltf.export('BoxTexturedExternal.gltf')
+```
+
+Again, since this library does not handle calling out to external resources,
+this is strictly a bookkeeping operation. It is the responsibility of the caller
+to ensure that the resource exists externally. Note when converting a resource
+to an `ExternalResource`, the resource data becomes inaccessible.
+
+If the resource is already an `ExternalResource` and the URI matches, no action
+is performed. If the URI is different, then the URI will be updated on the resource
+instance as well as on any corresponding buffers or images in the model.
+
+If the resource is a `FileResource` or `Base64Resource`, then it will be converted
+to an `ExternalResource`, and all buffers and images will be updated appropriately.
+
+If the resource is a `GLBResource`, it will be converted to an `ExternalResource`.
+The GLB buffer will be replaced with a buffer with a data URI (or removed entirely
+if it is only used by images). Any images that refer to the resource via a buffer
+view will instead refer to the image directly via a data URI, and the corresponding
+buffer view will be removed (if it is not also referenced elsewhere). Further, if
+no other buffer views refer to the same buffer as the removed buffer view, then the
+buffer will be removed entirely as well.
+
+## Credits
+
+This project is based on the `pygltflib` library by
+[dodgyville](https://gitlab.com/dodgyville) available here:
+
+https://gitlab.com/dodgyville/pygltflib
+
+Specifically, this project is based on a much earlier version of `pygltflib` at a
+time when it didn't seem to be actively maintained. I used that library as a
+starting point and added some features I needed for my own work. Since then, the
+original `pygltflib` project has been revived, but our implementations have
+diverged significantly. So now there are two :-)
+
+
+%package -n python3-gltflib
+Summary: Library for parsing, creating, and converting glTF 2.0 files in Python.
+Provides: python-gltflib
+BuildRequires: python3-devel
+BuildRequires: python3-setuptools
+BuildRequires: python3-pip
+%description -n python3-gltflib
+
+# gltflib
+
+Library for parsing, creating, and converting glTF 2.0 files in Python 3.6+.
+
+## Overview
+
+This library is intended for working with glTF 2.0 at a fairly low level, meaning you are
+responsible for managing the actual geometry data yourself. This library facilitates saving
+this data into a properly formatted glTF/GLB file. It also helps with converting resources
+inside a glTF/GLB file between external files or web URLs, data URLs, and embedded GLB
+resources.
+
+## Installation
+
+This library can be installed using pip:
+
+```
+pip install gltflib
+```
+
+## Usage
+
+The examples below illustrate how to use this library for a couple sample scenarios. The
+example models come from the Khronos glTF-Sample-Models repository available here:
+
+[https://github.com/KhronosGroup/glTF-Sample-Models](https://github.com/KhronosGroup/glTF-Sample-Models)
+
+### Parsing a glTF 2.0 Model
+
+To load a glTF 2.0 model:
+
+```python
+from gltflib import GLTF
+
+gltf = GLTF.load('glTF-Sample-Models/2.0/BoxTextured/glTF/BoxTextured.gltf')
+```
+
+The `GLTF.load` static method supports loading both the JSON-based `.gltf` format, as well
+as the binary `.glb` format. The type of the file will be determined based on the filename
+extension. Alternatively, you can use `GLTF.load_gltf(filename)` or `GLTF.load_glb(filename)`.
+
+After loading, you can inspect the model structure by accessing the `model` property:
+
+```python
+print(gltf.model)
+# GLTFModel(extensions=None, extras=None, accessors=[Accessor(extensions=None, extras=None, name=None, bufferView=0, byteOffset=0, componentType=5123, ...
+```
+
+You can also inspect the various model properties:
+
+```python
+print(gltf.model.buffers[0].uri)
+# BoxTextured0.bin
+```
+
+A glTF 2.0 model may contain resources, such as vertex geometry or image textures. These
+resources can be embedded as part of the model file, or (as with the above example) be
+referenced as external file resources.
+
+In either case, the resources are parsed alongside the model structure into the `resources`
+property after loading a model:
+
+```python
+print(gltf.resources)
+# [FileResource(CesiumLogoFlat.png), FileResource(BoxTextured0.bin)]
+```
+
+Note that the actual content of these external file resources is *not* loaded by default
+when loading a model. You can load the resource into memory in one of two ways. One way
+is to call the `load()` method on the resource:
+
+```python
+resource = gltf.resources[0]
+resource.load() # Assumes resource is a FileResource
+```
+
+Another way is to pass the `load_file_resources` flag when calling `GLTF.load()`:
+
+```python
+gltf = GLTF.load(filename, load_file_resources=True)
+```
+
+In either case, now the file resource data can be accessed via the `data` property:
+
+```python
+print(resource.data)
+# b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80?\x00\x00\x00\x00\x00\x00\...
+```
+
+Embedded resources in binary GLB files are also parsed into the `resources` list, but
+they will be of type `GLBResource` instead of `FileResource`:
+
+```python
+glb = GLTF.load('glTF-Sample-Models/2.0/BoxTextured/glTF-Binary/BoxTextured.glb')
+print(glb.resources)
+# [<gltflib.gltf_resource.GLBResource object at 0x7f03db7c1400>]
+```
+
+For embedded resources, the content is parsed into memory automatically. The binary data
+can be accessed using the `data` property:
+
+```python
+resource = glb.resources[0]
+print(resource.data)
+# b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80?\x00\x00\x00\x00\x00\x00\...'
+```
+
+### Exporting a glTF 2.0 Model
+
+To export a model, call the `GLTF.export()` instance method in the `GLTF` class.
+
+The example below creates a simple glTF 2.0 mode in memory (consisting of a single
+triangle), then exports it as a glTF file named `triangle.gltf` (alongside with an
+external file resource named `vertices.bin`):
+
+```python
+import struct
+import operator
+from gltflib import (
+ GLTF, GLTFModel, Asset, Scene, Node, Mesh, Primitive, Attributes, Buffer, BufferView, Accessor, AccessorType,
+ BufferTarget, ComponentType, GLBResource, FileResource)
+
+vertices = [
+ (-4774424.719997984, 4163079.2597148907, 671001.6353722484),
+ (-4748098.650098154, 4163079.259714891, 837217.8990777463),
+ (-4689289.5292739635, 4246272.966707474, 742710.4976137652)
+]
+
+vertex_bytearray = bytearray()
+for vertex in vertices:
+ for value in vertex:
+ vertex_bytearray.extend(struct.pack('f', value))
+bytelen = len(vertex_bytearray)
+mins = [min([operator.itemgetter(i)(vertex) for vertex in vertices]) for i in range(3)]
+maxs = [max([operator.itemgetter(i)(vertex) for vertex in vertices]) for i in range(3)]
+model = GLTFModel(
+ asset=Asset(version='2.0'),
+ scenes=[Scene(nodes=[0])],
+ nodes=[Node(mesh=0)],
+ meshes=[Mesh(primitives=[Primitive(attributes=Attributes(POSITION=0))])],
+ buffers=[Buffer(byteLength=bytelen, uri='vertices.bin')],
+ bufferViews=[BufferView(buffer=0, byteOffset=0, byteLength=bytelen, target=BufferTarget.ARRAY_BUFFER.value)],
+ accessors=[Accessor(bufferView=0, byteOffset=0, componentType=ComponentType.FLOAT.value, count=len(vertices),
+ type=AccessorType.VEC3.value, min=mins, max=maxs)]
+)
+
+resource = FileResource('vertices.bin', data=vertex_bytearray)
+gltf = GLTF(model=model, resources=[resource])
+gltf.export('triangle.gltf')
+```
+
+As with `load`, the `export` method infers the format based on the filename extension
+(`.gltf` vs `.glb`). However, you can also call `export_gltf` or `export_glb` to manually
+force the format.
+
+In the above example, the export will produce two files: `triangle.gltf` and `vertices.bin`.
+However, it is possible to bypass saving external file resources by setting the
+`save_file_resources` flag to `False` when calling `export`:
+
+```python
+gltf.export('triangle.gltf', save_file_resources=False)
+```
+
+To export the model as a binary GLB instead, simply change the extension when calling
+`export`, or use `export_glb`:
+
+```python
+gltf.export('triangle.glb')
+```
+
+Note that when exporting as a GLB, all resources will be embedded by default (even if
+they were instantiated as a `FileResource`). This is generally the desired behavior when
+saving as a GLB.
+
+However, it is possible to force some or all resources to remain external when exporting
+a GLB. To do so, you must call `export_glb` (instead of `export`), and setting either
+`embed_buffer_resources` or `embed_image_resources` (or both) to `False`:
+
+```python
+resource = FileResource('vertices.bin', data=vertex_bytearray)
+gltf = GLTF(model=model, resources=[resource])
+gltf.export_glb('triangle.glb', embed_buffer_resources=False, embed_image_resources=False)
+```
+
+In this case, you will also need to ensure that the associated buffers still have the
+appropriate `uri` set in the model:
+
+```python
+model = GLTFModel(
+ ...,
+ buffers=[Buffer(byteLength=bytelen, uri='vertices.bin')],
+```
+
+The model will be exported as a binary GLB, but with external file resources. These
+file resources will be saved by default when exporting the model. However, it is also
+possible to bypass saving external file resources by setting the `save_file_resources`
+to `False` when calling `export_glb`:
+
+```python
+gltf.export_glb('triangle.glb', embed_buffer_resources=False, embed_image_resources=False,
+ save_file_resources=False)
+```
+
+### Converting Between glTF and GLB
+
+To convert a glTF model to GLB, simply load it and export it using the `glb` extension:
+
+```python
+from gltflib import GLTF
+
+gltf = GLTF.load('glTF-Sample-Models/2.0/BoxTextured/glTF/BoxTextured.gltf')
+gltf.export('BoxTextured.glb')
+```
+
+This will automatically convert all external file resources to become embedded GLB
+resources.
+
+The reverse conversion is also possible, though with some caveats. Since a non-binary
+glTF model may not have embedded binary data, the `GLBResource` must first be converted
+to a different resource type. The section on **Resources** below goes into more details,
+but here is a quick example where the `GLBResource` is first converted to a `FileResource`
+with the filename `BoxTextured.bin` prior to exporting to glTF:
+
+```python
+from gltflib import GLTF
+
+gltf = GLTF.load('glTF-Sample-Models/2.0/BoxTextured/glTF-Binary/BoxTextured.glb')
+glb_resource = gltf.get_glb_resource()
+gltf.convert_to_file_resource(glb_resource, 'BoxTextured.bin')
+gltf.export('BoxTextured.gltf')
+```
+
+Note that a GLB file typically contains a single binary GLB chunk that combines data
+from multiple buffers (which are then consumed by multiple buffer views, images, and
+accessors). Currently, when converting a GLB to glTF, the entire GLB chunk can be
+converted to a resource of a different type, but the resource cannot be split out into
+multiple resources (e.g., separate resource per buffer).
+
+### Resources
+
+glTF and GLB models can refer to embedded or external resources (via the buffer or image
+URIs, or in the case of GLB, by leaving the first buffer's URI undefined). These
+resources are represented in this library using subclasses of the `GLTFResource` base
+class. These resources will be parsed when loading a model, and must be properly
+instantiated and added to the model prior to exporting.
+
+There are 4 resource types that are supported by this library:
+
+* `FileResource`: File resources are resources that refer to a file path.
+* `Base64Resource`: Resources that are embedded directly in the glTF (or GLB) file
+using a Base64-encoded data URI.
+* `GLBResource`: Used only by GLB files, this resource type represents the binary GLB
+chunk that is embedded directly in the GLB file.
+* `ExternalResource`: External resources refer to external web URLs.
+
+A reference to a particular resource can be obtained if its URI is known by
+calling `get_resource`:
+
+```python
+gltf = GLTF.load('glTF-Sample-Models/2.0/BoxTextured/glTF/BoxTextured.gltf')
+logo = gltf.get_resource('CesiumLogoFlat.png')
+print(logo)
+# FileResource(CesiumLogoFlat.png)
+```
+
+Alternatively, a list of all resources in a model can be obtained using the
+`resources` list on the loaded model:
+
+```python
+gltf = GLTF.load('glTF-Sample-Models/2.0/BoxTextured/glTF/BoxTextured.gltf')
+print(gltf.resources)
+# [FileResource(CesiumLogoFlat.png), FileResource(BoxTextured0.bin)]
+```
+
+The `GLTF` class provides helper methods that can be used to convert a resource
+from one type to another. Some of these methods require some additional information
+to do the conversion; for instance, the filename when converting to a `FileResource`,
+or the MIME type when converting to a `Base64Resource`.
+
+The sections below go into more detail about each resource type, including their
+caveats and limitations, as well as how to convert a given resource to that type.
+
+#### File Resources
+
+File resources are denoted using the `FileResource` class, and represent resources
+that refer to a file path (generally a relative path, though absolute file paths are
+also supported).
+
+When loading a model, these resources are parsed by looking at the `uri` property on
+buffers and images; however, their content is not automatically loaded unless the
+`load_file_resources` flag is set to `True` when calling `GLTF.load()`:
+
+```python
+gltf = GLTF.load(filename, load_file_resources=True)
+```
+
+Alternatively, the `load()` method can be called on a `FileResource` instance to load
+the data into memory:
+
+```python
+resource = FileResource('triangleWithoutIndices.bin')
+resource.load()
+```
+
+Once the file resource is loaded into memory, its content is accessible via the `data`
+property:
+
+```python
+print(resource.data)
+# b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80?\x00\x00\x00\x00\x00\x00\...
+```
+
+When exporting a model, file resources will be written to disk by default. However,
+this can be bypassed by setting the `save_file_resources` flag `False` when calling
+`export`:
+
+```python
+gltf.export(filename, save_file_resources=False)
+```
+
+When creating a model instance manually, if the intention is to also save file
+resources, then there must be a corresponding `FileResource` in the `resources`
+list for every buffer or image that references a file path (otherwise, an error
+will be raised when attempting to export):
+
+```python
+resource = FileResource('buffer.bin')
+model = GLTFModel(asset=Asset(version='2.0'), buffers=[Buffer(uri='buffer.bin', byteLength=18)])
+gltf = GLTF(model=model, resources=[resource])
+gltf.export('model.gltf')
+```
+
+When instantiating a `FileResource`, if the content of the file is known, it can
+be provided via the `data` constructor parameter:
+
+```python
+resource = FileResource('buffer.bin', data=b'binary content here')
+```
+
+A resource of another type can be converted to a `FileResource` using the
+`convert_to_file_resource` helper method on the GLTF class. This method
+requires a filename as a parameter, and returns the converted `FileResource`
+instance:
+
+```python
+resource = gltf.resources[0]
+file_resource = gltf.convert_to_file_resource(resource, 'BoxTextured.bin')
+```
+
+Note the file will not be created until the model is saved (with `save_file_resources`
+flag set to `True`). Also, note that the resource to be converted must be
+part of the `resources` list in the model (otherwise an error will be raised).
+
+If the resource is already a `FileResource` and the filename matches, no action
+is performed. If the filename is different, then the filename will be updated
+on any buffers and images that reference it.
+
+If the resource to be converted is a `GLBResource` or `Base64Resource`, it will be
+un-embedded and converted to an external file resource, and any buffers that reference
+the resource will be updated appropriately. Any embedded images that reference the
+resource will be updated. If the image previously referenced a buffer view, it will
+now reference a URI instead; the corresponding buffer view will be removed if no
+other parts of the model refer to it. Further, after removing the buffer view, if
+no other buffer views refer to the same buffer, then the buffer will be removed as
+well.
+
+If the resource to be converted is an `ExternalResource`, this method will raise an
+error (accessing external resource data is not supported).
+
+#### Base-64 (Data URI) Resources
+
+glTF supports embedding a resource directly into a JSON-based glTF file (or a GLB
+file, though it's not as common) using a
+[data URI](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs).
+In this scenario, the resource is defined as part of the URI itself, allowing the
+model to be self-contained without necessarily using the GLB format:
+
+```
+{
+ ...
+ "images": [
+ {
+ "uri": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAABccqhmAAAEDW..."
+ }
+ ],
+ ...
+}
+```
+
+When loading such a model, a resource of type `Base64Resource` will be instantiated
+and added to the model's `resources` list. The `uri` property of the resource will
+contain the original data URI, while the `data` property can be used to access the
+decoded binary data:
+
+```python
+gltf = GLTF.load('glTF-Sample-Models/2.0/BoxTextured/glTF-Embedded/BoxTextured.gltf')
+logo = gltf.resources[1]
+print(logo.data)
+# b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80?\x00\x00\x00\x00\x00\x00\...
+```
+
+To instantiate a `Base64Resource`, there are two options. One is to use the
+constructor to pass in the binary data and MIME type (which defaults to
+`application/octet-stream` if not provided):
+
+```python
+resource = Base64Resource(b'sample binary data', mime_type='application/octet-stream')
+```
+
+The other way is to use the `Base64Resource.from_uri` factory method and pass
+in the data URI:
+
+```python
+resource = Base64Resource.from_uri('data:application/octet-stream;base64,c2FtcGxlIGJpbmFyeSBkYXRh')
+```
+
+To convert a resource of another type to a `Base64Resource`, use the
+`GLTF.convert_to_base64_resource` helper method. This method accepts an optional
+`mime_type` parameter if the MIME type of the original resource is known (defaults
+to `application/octet-stream` if not provided):
+
+```python
+gltf = GLTF.load('glTF-Sample-Models/2.0/BoxTextured/glTF/BoxTextured.gltf')
+logo = gltf.get_resource('CesiumLogoFlat.png')
+gltf.convert_to_base64_resource(logo, 'image/png')
+gltf.export('BoxTexturedBase64.gltf')
+```
+
+If the resource to be converted is already a `Base64Resource`, no action is performed.
+
+If the resource is a `FileResource`, then it will be converted to a `Base64Resource`.
+The data for the `FileResource` will be loaded from disk if not already loaded (which
+may raise an `IOError` if the file does not exist).
+
+If the resource is a `GLBResource`, it will be converted to a `Base64Resource`. The
+GLB buffer will be replaced with a buffer with a data URI (or removed entirely if it
+is only used by images). Any images that refer to the resource via a buffer view will
+instead refer to the image directly via a data URI, and the corresponding buffer view
+will be removed (if it is not also referenced elsewhere). Further, if no other buffer
+views refer to the same buffer as the removed buffer view, then the buffer will be
+removed entirely as well.
+
+If the resource is an `ExternalResource`, this method will raise an error (accessing
+external resource data is not supported).
+
+#### GLB Resources
+
+GLB Resources are resources that are embedded directly in a GLB file as binary
+chunks. These resources can only be used with a GLB file (if saving to glTF, these
+resources must first be converted to a different type).
+
+There is generally one GLB chunk in a file (with the chunk type `BIN`), though it
+is valid to have multiple GLB chunks if they have a different chunk type. This
+library supports loading and saving these additional GLB chunks, though no
+assumptions are made about their content.
+
+A reference to the `GLBResource` corresponding to the primary GLB chunk (with the
+chunk type `BIN`) can be obtained by calling `get_glb_resource` on a model
+instance, and its data can be accessed via the `data` property:
+
+```python
+gltf = GLTF.load('glTF-Sample-Models/2.0/BoxTextured/glTF-Binary/BoxTextured.glb')
+glb_resource = gltf.get_glb_resource()
+print(glb_resource.data)
+# b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80?\x00\x00\x00\x00\x00\x00\...
+```
+
+Additional GLB chunks can be referenced by calling `get_glb_resource` with a
+`resource_type` parameter set to the chunk type:
+
+```python
+my_custom_glb_resource = gltf.get_glb_resource(resource_type=123)
+```
+
+An individual resource of another type can be converted to a `GLBResource` using
+the `embed_resource` helper method. This allows embedding a particular resource
+while leaving others external when exporting to GLB (in this scenario, ensure
+to use `export_glb` instead of `export`, and set both `embed_buffer_resources`
+and `embed_image_resources` to `False` to prevent the other resources from also
+being automatically embedded):
+
+```python
+gltf = GLTF.load('glTF-Sample-Models/2.0/BoxTextured/glTF-Binary/BoxTextured.glb')
+logo = gltf.get_resource('CesiumLogoFlat.png')
+gltf.embed_resource(logo)
+gltf.export_glb('BoxTexturedPartial.glb', embed_buffer_resources=False, embed_image_resources=False)
+```
+
+However, the most common scenario is to embed all resources regardless of their
+type, which happens automatically when calling `export` with a `.glb` extension
+(or when calling `export_glb` with the default set of parameters).
+
+Note that embedding an `ExternalResource` is not supported because its data is
+not accessible (this library does not support loading resources from an external
+web URL).
+
+As explained in the other sections, converting a `GLBResource` to a resource of
+another type (i.e., "un-embedding" a resource) will typically not only replace
+the URIs on the corresponding buffers and images, but may also result in removing
+the GLB buffer and buffer views entirely if they are not also referenced elsewhere.
+
+#### External Resources
+
+External resources (represented by the `ExternalResource` class) are resources
+that have an external web URL. While this library is able to load models with
+external web URLs, the resource itself will not be fetched. A resource of type
+`ExternalResource` will be instantiated with the corresponding URI, but the
+library will not perform any web requests to load the resource data. Likewise,
+the library supports saving a model containing `ExternalResource` instances,
+but again, no web requests will be performed.
+
+A resource of another type can be converted to an `ExternalResource` using the
+`GLTF.convert_to_external_resource` helper method, which accepts a URL:
+
+```python
+gltf = GLTF.load('glTF-Sample-Models/2.0/BoxTextured/glTF/BoxTextured.gltf')
+logo = gltf.get_resource('CesiumLogoFlat.png')
+gltf.convert_to_external_resource(logo, 'http://www.example.com/image.png')
+gltf.export('BoxTexturedExternal.gltf')
+```
+
+Again, since this library does not handle calling out to external resources,
+this is strictly a bookkeeping operation. It is the responsibility of the caller
+to ensure that the resource exists externally. Note when converting a resource
+to an `ExternalResource`, the resource data becomes inaccessible.
+
+If the resource is already an `ExternalResource` and the URI matches, no action
+is performed. If the URI is different, then the URI will be updated on the resource
+instance as well as on any corresponding buffers or images in the model.
+
+If the resource is a `FileResource` or `Base64Resource`, then it will be converted
+to an `ExternalResource`, and all buffers and images will be updated appropriately.
+
+If the resource is a `GLBResource`, it will be converted to an `ExternalResource`.
+The GLB buffer will be replaced with a buffer with a data URI (or removed entirely
+if it is only used by images). Any images that refer to the resource via a buffer
+view will instead refer to the image directly via a data URI, and the corresponding
+buffer view will be removed (if it is not also referenced elsewhere). Further, if
+no other buffer views refer to the same buffer as the removed buffer view, then the
+buffer will be removed entirely as well.
+
+## Credits
+
+This project is based on the `pygltflib` library by
+[dodgyville](https://gitlab.com/dodgyville) available here:
+
+https://gitlab.com/dodgyville/pygltflib
+
+Specifically, this project is based on a much earlier version of `pygltflib` at a
+time when it didn't seem to be actively maintained. I used that library as a
+starting point and added some features I needed for my own work. Since then, the
+original `pygltflib` project has been revived, but our implementations have
+diverged significantly. So now there are two :-)
+
+
+%package help
+Summary: Development documents and examples for gltflib
+Provides: python3-gltflib-doc
+%description help
+
+# gltflib
+
+Library for parsing, creating, and converting glTF 2.0 files in Python 3.6+.
+
+## Overview
+
+This library is intended for working with glTF 2.0 at a fairly low level, meaning you are
+responsible for managing the actual geometry data yourself. This library facilitates saving
+this data into a properly formatted glTF/GLB file. It also helps with converting resources
+inside a glTF/GLB file between external files or web URLs, data URLs, and embedded GLB
+resources.
+
+## Installation
+
+This library can be installed using pip:
+
+```
+pip install gltflib
+```
+
+## Usage
+
+The examples below illustrate how to use this library for a couple sample scenarios. The
+example models come from the Khronos glTF-Sample-Models repository available here:
+
+[https://github.com/KhronosGroup/glTF-Sample-Models](https://github.com/KhronosGroup/glTF-Sample-Models)
+
+### Parsing a glTF 2.0 Model
+
+To load a glTF 2.0 model:
+
+```python
+from gltflib import GLTF
+
+gltf = GLTF.load('glTF-Sample-Models/2.0/BoxTextured/glTF/BoxTextured.gltf')
+```
+
+The `GLTF.load` static method supports loading both the JSON-based `.gltf` format, as well
+as the binary `.glb` format. The type of the file will be determined based on the filename
+extension. Alternatively, you can use `GLTF.load_gltf(filename)` or `GLTF.load_glb(filename)`.
+
+After loading, you can inspect the model structure by accessing the `model` property:
+
+```python
+print(gltf.model)
+# GLTFModel(extensions=None, extras=None, accessors=[Accessor(extensions=None, extras=None, name=None, bufferView=0, byteOffset=0, componentType=5123, ...
+```
+
+You can also inspect the various model properties:
+
+```python
+print(gltf.model.buffers[0].uri)
+# BoxTextured0.bin
+```
+
+A glTF 2.0 model may contain resources, such as vertex geometry or image textures. These
+resources can be embedded as part of the model file, or (as with the above example) be
+referenced as external file resources.
+
+In either case, the resources are parsed alongside the model structure into the `resources`
+property after loading a model:
+
+```python
+print(gltf.resources)
+# [FileResource(CesiumLogoFlat.png), FileResource(BoxTextured0.bin)]
+```
+
+Note that the actual content of these external file resources is *not* loaded by default
+when loading a model. You can load the resource into memory in one of two ways. One way
+is to call the `load()` method on the resource:
+
+```python
+resource = gltf.resources[0]
+resource.load() # Assumes resource is a FileResource
+```
+
+Another way is to pass the `load_file_resources` flag when calling `GLTF.load()`:
+
+```python
+gltf = GLTF.load(filename, load_file_resources=True)
+```
+
+In either case, now the file resource data can be accessed via the `data` property:
+
+```python
+print(resource.data)
+# b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80?\x00\x00\x00\x00\x00\x00\...
+```
+
+Embedded resources in binary GLB files are also parsed into the `resources` list, but
+they will be of type `GLBResource` instead of `FileResource`:
+
+```python
+glb = GLTF.load('glTF-Sample-Models/2.0/BoxTextured/glTF-Binary/BoxTextured.glb')
+print(glb.resources)
+# [<gltflib.gltf_resource.GLBResource object at 0x7f03db7c1400>]
+```
+
+For embedded resources, the content is parsed into memory automatically. The binary data
+can be accessed using the `data` property:
+
+```python
+resource = glb.resources[0]
+print(resource.data)
+# b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80?\x00\x00\x00\x00\x00\x00\...'
+```
+
+### Exporting a glTF 2.0 Model
+
+To export a model, call the `GLTF.export()` instance method in the `GLTF` class.
+
+The example below creates a simple glTF 2.0 mode in memory (consisting of a single
+triangle), then exports it as a glTF file named `triangle.gltf` (alongside with an
+external file resource named `vertices.bin`):
+
+```python
+import struct
+import operator
+from gltflib import (
+ GLTF, GLTFModel, Asset, Scene, Node, Mesh, Primitive, Attributes, Buffer, BufferView, Accessor, AccessorType,
+ BufferTarget, ComponentType, GLBResource, FileResource)
+
+vertices = [
+ (-4774424.719997984, 4163079.2597148907, 671001.6353722484),
+ (-4748098.650098154, 4163079.259714891, 837217.8990777463),
+ (-4689289.5292739635, 4246272.966707474, 742710.4976137652)
+]
+
+vertex_bytearray = bytearray()
+for vertex in vertices:
+ for value in vertex:
+ vertex_bytearray.extend(struct.pack('f', value))
+bytelen = len(vertex_bytearray)
+mins = [min([operator.itemgetter(i)(vertex) for vertex in vertices]) for i in range(3)]
+maxs = [max([operator.itemgetter(i)(vertex) for vertex in vertices]) for i in range(3)]
+model = GLTFModel(
+ asset=Asset(version='2.0'),
+ scenes=[Scene(nodes=[0])],
+ nodes=[Node(mesh=0)],
+ meshes=[Mesh(primitives=[Primitive(attributes=Attributes(POSITION=0))])],
+ buffers=[Buffer(byteLength=bytelen, uri='vertices.bin')],
+ bufferViews=[BufferView(buffer=0, byteOffset=0, byteLength=bytelen, target=BufferTarget.ARRAY_BUFFER.value)],
+ accessors=[Accessor(bufferView=0, byteOffset=0, componentType=ComponentType.FLOAT.value, count=len(vertices),
+ type=AccessorType.VEC3.value, min=mins, max=maxs)]
+)
+
+resource = FileResource('vertices.bin', data=vertex_bytearray)
+gltf = GLTF(model=model, resources=[resource])
+gltf.export('triangle.gltf')
+```
+
+As with `load`, the `export` method infers the format based on the filename extension
+(`.gltf` vs `.glb`). However, you can also call `export_gltf` or `export_glb` to manually
+force the format.
+
+In the above example, the export will produce two files: `triangle.gltf` and `vertices.bin`.
+However, it is possible to bypass saving external file resources by setting the
+`save_file_resources` flag to `False` when calling `export`:
+
+```python
+gltf.export('triangle.gltf', save_file_resources=False)
+```
+
+To export the model as a binary GLB instead, simply change the extension when calling
+`export`, or use `export_glb`:
+
+```python
+gltf.export('triangle.glb')
+```
+
+Note that when exporting as a GLB, all resources will be embedded by default (even if
+they were instantiated as a `FileResource`). This is generally the desired behavior when
+saving as a GLB.
+
+However, it is possible to force some or all resources to remain external when exporting
+a GLB. To do so, you must call `export_glb` (instead of `export`), and setting either
+`embed_buffer_resources` or `embed_image_resources` (or both) to `False`:
+
+```python
+resource = FileResource('vertices.bin', data=vertex_bytearray)
+gltf = GLTF(model=model, resources=[resource])
+gltf.export_glb('triangle.glb', embed_buffer_resources=False, embed_image_resources=False)
+```
+
+In this case, you will also need to ensure that the associated buffers still have the
+appropriate `uri` set in the model:
+
+```python
+model = GLTFModel(
+ ...,
+ buffers=[Buffer(byteLength=bytelen, uri='vertices.bin')],
+```
+
+The model will be exported as a binary GLB, but with external file resources. These
+file resources will be saved by default when exporting the model. However, it is also
+possible to bypass saving external file resources by setting the `save_file_resources`
+to `False` when calling `export_glb`:
+
+```python
+gltf.export_glb('triangle.glb', embed_buffer_resources=False, embed_image_resources=False,
+ save_file_resources=False)
+```
+
+### Converting Between glTF and GLB
+
+To convert a glTF model to GLB, simply load it and export it using the `glb` extension:
+
+```python
+from gltflib import GLTF
+
+gltf = GLTF.load('glTF-Sample-Models/2.0/BoxTextured/glTF/BoxTextured.gltf')
+gltf.export('BoxTextured.glb')
+```
+
+This will automatically convert all external file resources to become embedded GLB
+resources.
+
+The reverse conversion is also possible, though with some caveats. Since a non-binary
+glTF model may not have embedded binary data, the `GLBResource` must first be converted
+to a different resource type. The section on **Resources** below goes into more details,
+but here is a quick example where the `GLBResource` is first converted to a `FileResource`
+with the filename `BoxTextured.bin` prior to exporting to glTF:
+
+```python
+from gltflib import GLTF
+
+gltf = GLTF.load('glTF-Sample-Models/2.0/BoxTextured/glTF-Binary/BoxTextured.glb')
+glb_resource = gltf.get_glb_resource()
+gltf.convert_to_file_resource(glb_resource, 'BoxTextured.bin')
+gltf.export('BoxTextured.gltf')
+```
+
+Note that a GLB file typically contains a single binary GLB chunk that combines data
+from multiple buffers (which are then consumed by multiple buffer views, images, and
+accessors). Currently, when converting a GLB to glTF, the entire GLB chunk can be
+converted to a resource of a different type, but the resource cannot be split out into
+multiple resources (e.g., separate resource per buffer).
+
+### Resources
+
+glTF and GLB models can refer to embedded or external resources (via the buffer or image
+URIs, or in the case of GLB, by leaving the first buffer's URI undefined). These
+resources are represented in this library using subclasses of the `GLTFResource` base
+class. These resources will be parsed when loading a model, and must be properly
+instantiated and added to the model prior to exporting.
+
+There are 4 resource types that are supported by this library:
+
+* `FileResource`: File resources are resources that refer to a file path.
+* `Base64Resource`: Resources that are embedded directly in the glTF (or GLB) file
+using a Base64-encoded data URI.
+* `GLBResource`: Used only by GLB files, this resource type represents the binary GLB
+chunk that is embedded directly in the GLB file.
+* `ExternalResource`: External resources refer to external web URLs.
+
+A reference to a particular resource can be obtained if its URI is known by
+calling `get_resource`:
+
+```python
+gltf = GLTF.load('glTF-Sample-Models/2.0/BoxTextured/glTF/BoxTextured.gltf')
+logo = gltf.get_resource('CesiumLogoFlat.png')
+print(logo)
+# FileResource(CesiumLogoFlat.png)
+```
+
+Alternatively, a list of all resources in a model can be obtained using the
+`resources` list on the loaded model:
+
+```python
+gltf = GLTF.load('glTF-Sample-Models/2.0/BoxTextured/glTF/BoxTextured.gltf')
+print(gltf.resources)
+# [FileResource(CesiumLogoFlat.png), FileResource(BoxTextured0.bin)]
+```
+
+The `GLTF` class provides helper methods that can be used to convert a resource
+from one type to another. Some of these methods require some additional information
+to do the conversion; for instance, the filename when converting to a `FileResource`,
+or the MIME type when converting to a `Base64Resource`.
+
+The sections below go into more detail about each resource type, including their
+caveats and limitations, as well as how to convert a given resource to that type.
+
+#### File Resources
+
+File resources are denoted using the `FileResource` class, and represent resources
+that refer to a file path (generally a relative path, though absolute file paths are
+also supported).
+
+When loading a model, these resources are parsed by looking at the `uri` property on
+buffers and images; however, their content is not automatically loaded unless the
+`load_file_resources` flag is set to `True` when calling `GLTF.load()`:
+
+```python
+gltf = GLTF.load(filename, load_file_resources=True)
+```
+
+Alternatively, the `load()` method can be called on a `FileResource` instance to load
+the data into memory:
+
+```python
+resource = FileResource('triangleWithoutIndices.bin')
+resource.load()
+```
+
+Once the file resource is loaded into memory, its content is accessible via the `data`
+property:
+
+```python
+print(resource.data)
+# b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80?\x00\x00\x00\x00\x00\x00\...
+```
+
+When exporting a model, file resources will be written to disk by default. However,
+this can be bypassed by setting the `save_file_resources` flag `False` when calling
+`export`:
+
+```python
+gltf.export(filename, save_file_resources=False)
+```
+
+When creating a model instance manually, if the intention is to also save file
+resources, then there must be a corresponding `FileResource` in the `resources`
+list for every buffer or image that references a file path (otherwise, an error
+will be raised when attempting to export):
+
+```python
+resource = FileResource('buffer.bin')
+model = GLTFModel(asset=Asset(version='2.0'), buffers=[Buffer(uri='buffer.bin', byteLength=18)])
+gltf = GLTF(model=model, resources=[resource])
+gltf.export('model.gltf')
+```
+
+When instantiating a `FileResource`, if the content of the file is known, it can
+be provided via the `data` constructor parameter:
+
+```python
+resource = FileResource('buffer.bin', data=b'binary content here')
+```
+
+A resource of another type can be converted to a `FileResource` using the
+`convert_to_file_resource` helper method on the GLTF class. This method
+requires a filename as a parameter, and returns the converted `FileResource`
+instance:
+
+```python
+resource = gltf.resources[0]
+file_resource = gltf.convert_to_file_resource(resource, 'BoxTextured.bin')
+```
+
+Note the file will not be created until the model is saved (with `save_file_resources`
+flag set to `True`). Also, note that the resource to be converted must be
+part of the `resources` list in the model (otherwise an error will be raised).
+
+If the resource is already a `FileResource` and the filename matches, no action
+is performed. If the filename is different, then the filename will be updated
+on any buffers and images that reference it.
+
+If the resource to be converted is a `GLBResource` or `Base64Resource`, it will be
+un-embedded and converted to an external file resource, and any buffers that reference
+the resource will be updated appropriately. Any embedded images that reference the
+resource will be updated. If the image previously referenced a buffer view, it will
+now reference a URI instead; the corresponding buffer view will be removed if no
+other parts of the model refer to it. Further, after removing the buffer view, if
+no other buffer views refer to the same buffer, then the buffer will be removed as
+well.
+
+If the resource to be converted is an `ExternalResource`, this method will raise an
+error (accessing external resource data is not supported).
+
+#### Base-64 (Data URI) Resources
+
+glTF supports embedding a resource directly into a JSON-based glTF file (or a GLB
+file, though it's not as common) using a
+[data URI](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs).
+In this scenario, the resource is defined as part of the URI itself, allowing the
+model to be self-contained without necessarily using the GLB format:
+
+```
+{
+ ...
+ "images": [
+ {
+ "uri": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAABccqhmAAAEDW..."
+ }
+ ],
+ ...
+}
+```
+
+When loading such a model, a resource of type `Base64Resource` will be instantiated
+and added to the model's `resources` list. The `uri` property of the resource will
+contain the original data URI, while the `data` property can be used to access the
+decoded binary data:
+
+```python
+gltf = GLTF.load('glTF-Sample-Models/2.0/BoxTextured/glTF-Embedded/BoxTextured.gltf')
+logo = gltf.resources[1]
+print(logo.data)
+# b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80?\x00\x00\x00\x00\x00\x00\...
+```
+
+To instantiate a `Base64Resource`, there are two options. One is to use the
+constructor to pass in the binary data and MIME type (which defaults to
+`application/octet-stream` if not provided):
+
+```python
+resource = Base64Resource(b'sample binary data', mime_type='application/octet-stream')
+```
+
+The other way is to use the `Base64Resource.from_uri` factory method and pass
+in the data URI:
+
+```python
+resource = Base64Resource.from_uri('data:application/octet-stream;base64,c2FtcGxlIGJpbmFyeSBkYXRh')
+```
+
+To convert a resource of another type to a `Base64Resource`, use the
+`GLTF.convert_to_base64_resource` helper method. This method accepts an optional
+`mime_type` parameter if the MIME type of the original resource is known (defaults
+to `application/octet-stream` if not provided):
+
+```python
+gltf = GLTF.load('glTF-Sample-Models/2.0/BoxTextured/glTF/BoxTextured.gltf')
+logo = gltf.get_resource('CesiumLogoFlat.png')
+gltf.convert_to_base64_resource(logo, 'image/png')
+gltf.export('BoxTexturedBase64.gltf')
+```
+
+If the resource to be converted is already a `Base64Resource`, no action is performed.
+
+If the resource is a `FileResource`, then it will be converted to a `Base64Resource`.
+The data for the `FileResource` will be loaded from disk if not already loaded (which
+may raise an `IOError` if the file does not exist).
+
+If the resource is a `GLBResource`, it will be converted to a `Base64Resource`. The
+GLB buffer will be replaced with a buffer with a data URI (or removed entirely if it
+is only used by images). Any images that refer to the resource via a buffer view will
+instead refer to the image directly via a data URI, and the corresponding buffer view
+will be removed (if it is not also referenced elsewhere). Further, if no other buffer
+views refer to the same buffer as the removed buffer view, then the buffer will be
+removed entirely as well.
+
+If the resource is an `ExternalResource`, this method will raise an error (accessing
+external resource data is not supported).
+
+#### GLB Resources
+
+GLB Resources are resources that are embedded directly in a GLB file as binary
+chunks. These resources can only be used with a GLB file (if saving to glTF, these
+resources must first be converted to a different type).
+
+There is generally one GLB chunk in a file (with the chunk type `BIN`), though it
+is valid to have multiple GLB chunks if they have a different chunk type. This
+library supports loading and saving these additional GLB chunks, though no
+assumptions are made about their content.
+
+A reference to the `GLBResource` corresponding to the primary GLB chunk (with the
+chunk type `BIN`) can be obtained by calling `get_glb_resource` on a model
+instance, and its data can be accessed via the `data` property:
+
+```python
+gltf = GLTF.load('glTF-Sample-Models/2.0/BoxTextured/glTF-Binary/BoxTextured.glb')
+glb_resource = gltf.get_glb_resource()
+print(glb_resource.data)
+# b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80?\x00\x00\x00\x00\x00\x00\...
+```
+
+Additional GLB chunks can be referenced by calling `get_glb_resource` with a
+`resource_type` parameter set to the chunk type:
+
+```python
+my_custom_glb_resource = gltf.get_glb_resource(resource_type=123)
+```
+
+An individual resource of another type can be converted to a `GLBResource` using
+the `embed_resource` helper method. This allows embedding a particular resource
+while leaving others external when exporting to GLB (in this scenario, ensure
+to use `export_glb` instead of `export`, and set both `embed_buffer_resources`
+and `embed_image_resources` to `False` to prevent the other resources from also
+being automatically embedded):
+
+```python
+gltf = GLTF.load('glTF-Sample-Models/2.0/BoxTextured/glTF-Binary/BoxTextured.glb')
+logo = gltf.get_resource('CesiumLogoFlat.png')
+gltf.embed_resource(logo)
+gltf.export_glb('BoxTexturedPartial.glb', embed_buffer_resources=False, embed_image_resources=False)
+```
+
+However, the most common scenario is to embed all resources regardless of their
+type, which happens automatically when calling `export` with a `.glb` extension
+(or when calling `export_glb` with the default set of parameters).
+
+Note that embedding an `ExternalResource` is not supported because its data is
+not accessible (this library does not support loading resources from an external
+web URL).
+
+As explained in the other sections, converting a `GLBResource` to a resource of
+another type (i.e., "un-embedding" a resource) will typically not only replace
+the URIs on the corresponding buffers and images, but may also result in removing
+the GLB buffer and buffer views entirely if they are not also referenced elsewhere.
+
+#### External Resources
+
+External resources (represented by the `ExternalResource` class) are resources
+that have an external web URL. While this library is able to load models with
+external web URLs, the resource itself will not be fetched. A resource of type
+`ExternalResource` will be instantiated with the corresponding URI, but the
+library will not perform any web requests to load the resource data. Likewise,
+the library supports saving a model containing `ExternalResource` instances,
+but again, no web requests will be performed.
+
+A resource of another type can be converted to an `ExternalResource` using the
+`GLTF.convert_to_external_resource` helper method, which accepts a URL:
+
+```python
+gltf = GLTF.load('glTF-Sample-Models/2.0/BoxTextured/glTF/BoxTextured.gltf')
+logo = gltf.get_resource('CesiumLogoFlat.png')
+gltf.convert_to_external_resource(logo, 'http://www.example.com/image.png')
+gltf.export('BoxTexturedExternal.gltf')
+```
+
+Again, since this library does not handle calling out to external resources,
+this is strictly a bookkeeping operation. It is the responsibility of the caller
+to ensure that the resource exists externally. Note when converting a resource
+to an `ExternalResource`, the resource data becomes inaccessible.
+
+If the resource is already an `ExternalResource` and the URI matches, no action
+is performed. If the URI is different, then the URI will be updated on the resource
+instance as well as on any corresponding buffers or images in the model.
+
+If the resource is a `FileResource` or `Base64Resource`, then it will be converted
+to an `ExternalResource`, and all buffers and images will be updated appropriately.
+
+If the resource is a `GLBResource`, it will be converted to an `ExternalResource`.
+The GLB buffer will be replaced with a buffer with a data URI (or removed entirely
+if it is only used by images). Any images that refer to the resource via a buffer
+view will instead refer to the image directly via a data URI, and the corresponding
+buffer view will be removed (if it is not also referenced elsewhere). Further, if
+no other buffer views refer to the same buffer as the removed buffer view, then the
+buffer will be removed entirely as well.
+
+## Credits
+
+This project is based on the `pygltflib` library by
+[dodgyville](https://gitlab.com/dodgyville) available here:
+
+https://gitlab.com/dodgyville/pygltflib
+
+Specifically, this project is based on a much earlier version of `pygltflib` at a
+time when it didn't seem to be actively maintained. I used that library as a
+starting point and added some features I needed for my own work. Since then, the
+original `pygltflib` project has been revived, but our implementations have
+diverged significantly. So now there are two :-)
+
+
+%prep
+%autosetup -n gltflib-1.0.13
+
+%build
+%py3_build
+
+%install
+%py3_install
+install -d -m755 %{buildroot}/%{_pkgdocdir}
+if [ -d doc ]; then cp -arf doc %{buildroot}/%{_pkgdocdir}; fi
+if [ -d docs ]; then cp -arf docs %{buildroot}/%{_pkgdocdir}; fi
+if [ -d example ]; then cp -arf example %{buildroot}/%{_pkgdocdir}; fi
+if [ -d examples ]; then cp -arf examples %{buildroot}/%{_pkgdocdir}; fi
+pushd %{buildroot}
+if [ -d usr/lib ]; then
+ find usr/lib -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+if [ -d usr/lib64 ]; then
+ find usr/lib64 -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+if [ -d usr/bin ]; then
+ find usr/bin -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+if [ -d usr/sbin ]; then
+ find usr/sbin -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+touch doclist.lst
+if [ -d usr/share/man ]; then
+ find usr/share/man -type f -printf "/%h/%f.gz\n" >> doclist.lst
+fi
+popd
+mv %{buildroot}/filelist.lst .
+mv %{buildroot}/doclist.lst .
+
+%files -n python3-gltflib -f filelist.lst
+%dir %{python3_sitelib}/*
+
+%files help -f doclist.lst
+%{_docdir}/*
+
+%changelog
+* Wed May 31 2023 Python_Bot <Python_Bot@openeuler.org> - 1.0.13-1
+- Package Spec generated
diff --git a/sources b/sources
new file mode 100644
index 0000000..3db4299
--- /dev/null
+++ b/sources
@@ -0,0 +1 @@
+c3dcb39d1ca14624506e4f7aa9909634 gltflib-1.0.13.tar.gz