tmb-codec 0.2.0__py3-none-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tmb_codec/__init__.py +23 -0
- tmb_codec/_native/tmb_codec.dll +0 -0
- tmb_codec/codec.py +230 -0
- tmb_codec/licenses/CORTO_LICENSE.txt +21 -0
- tmb_codec/py.typed +1 -0
- tmb_codec-0.2.0.dist-info/METADATA +144 -0
- tmb_codec-0.2.0.dist-info/RECORD +10 -0
- tmb_codec-0.2.0.dist-info/WHEEL +5 -0
- tmb_codec-0.2.0.dist-info/licenses/LICENSE +21 -0
- tmb_codec-0.2.0.dist-info/licenses/licenses/CORTO_LICENSE.txt +21 -0
tmb_codec/__init__.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Python bindings for the TMB1 triangle mesh codec."""
|
|
2
|
+
|
|
3
|
+
from .codec import (
|
|
4
|
+
CORNER_ROTATION,
|
|
5
|
+
FACE_IDS,
|
|
6
|
+
VERTEX_IDS,
|
|
7
|
+
MeshInfo,
|
|
8
|
+
decode,
|
|
9
|
+
encode,
|
|
10
|
+
inspect,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"CORNER_ROTATION",
|
|
15
|
+
"FACE_IDS",
|
|
16
|
+
"VERTEX_IDS",
|
|
17
|
+
"MeshInfo",
|
|
18
|
+
"decode",
|
|
19
|
+
"encode",
|
|
20
|
+
"inspect",
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
__version__ = "0.2.0"
|
|
Binary file
|
tmb_codec/codec.py
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
"""NumPy API for the native TMB1 codec."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import ctypes as ct
|
|
6
|
+
import os
|
|
7
|
+
import struct
|
|
8
|
+
import sys
|
|
9
|
+
from dataclasses import dataclass
|
|
10
|
+
from importlib.resources import files
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
import numpy as np
|
|
14
|
+
import numpy.typing as npt
|
|
15
|
+
import zstandard as zstd
|
|
16
|
+
|
|
17
|
+
VERTEX_IDS = 1 << 0
|
|
18
|
+
FACE_IDS = 1 << 1
|
|
19
|
+
CORNER_ROTATION = 1 << 2
|
|
20
|
+
|
|
21
|
+
_MAGIC = 0x31424D54
|
|
22
|
+
_VERSION = 1
|
|
23
|
+
_QUANTIZED = 1 << 8
|
|
24
|
+
_BITS_SHIFT = 16
|
|
25
|
+
_HEADER = struct.Struct("<10I")
|
|
26
|
+
_MAX_RAW = 128 * 1024 * 1024
|
|
27
|
+
_LIBRARY: ct.CDLL | None = None
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@dataclass(frozen=True, slots=True)
|
|
31
|
+
class MeshInfo:
|
|
32
|
+
vertex_count: int
|
|
33
|
+
face_count: int
|
|
34
|
+
bits: int | None
|
|
35
|
+
flags: int
|
|
36
|
+
compressed: bool
|
|
37
|
+
|
|
38
|
+
@property
|
|
39
|
+
def lossless(self) -> bool:
|
|
40
|
+
return self.bits is None
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _library_name() -> str:
|
|
44
|
+
if os.name == "nt":
|
|
45
|
+
return "tmb_codec.dll"
|
|
46
|
+
if sys.platform == "darwin":
|
|
47
|
+
return "libtmb_codec.dylib"
|
|
48
|
+
return "libtmb_codec.so"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _library() -> ct.CDLL:
|
|
52
|
+
global _LIBRARY
|
|
53
|
+
if _LIBRARY is not None:
|
|
54
|
+
return _LIBRARY
|
|
55
|
+
override = os.environ.get("TMB_CODEC_LIBRARY")
|
|
56
|
+
path = Path(override) if override else Path(str(files("tmb_codec") / "_native" / _library_name()))
|
|
57
|
+
if not path.is_file():
|
|
58
|
+
raise ModuleNotFoundError(f"TMB native library is not installed: {path}")
|
|
59
|
+
library = ct.CDLL(str(path.resolve()))
|
|
60
|
+
encode_base = [ct.c_void_p, ct.c_uint32, ct.c_void_p, ct.c_uint32, ct.c_uint32]
|
|
61
|
+
decode_base = [
|
|
62
|
+
ct.c_void_p,
|
|
63
|
+
ct.c_size_t,
|
|
64
|
+
ct.c_void_p,
|
|
65
|
+
ct.c_void_p,
|
|
66
|
+
ct.c_uint32,
|
|
67
|
+
ct.c_uint32,
|
|
68
|
+
ct.c_uint32,
|
|
69
|
+
]
|
|
70
|
+
library.tmb_encode_lossless.argtypes = encode_base + [
|
|
71
|
+
ct.POINTER(ct.c_void_p),
|
|
72
|
+
ct.POINTER(ct.c_size_t),
|
|
73
|
+
ct.c_void_p,
|
|
74
|
+
]
|
|
75
|
+
library.tmb_encode_lossless.restype = ct.c_int
|
|
76
|
+
library.tmb_encode_quantized.argtypes = encode_base + [
|
|
77
|
+
ct.c_uint32,
|
|
78
|
+
ct.POINTER(ct.c_void_p),
|
|
79
|
+
ct.POINTER(ct.c_size_t),
|
|
80
|
+
ct.c_void_p,
|
|
81
|
+
]
|
|
82
|
+
library.tmb_encode_quantized.restype = ct.c_int
|
|
83
|
+
library.tmb_decode_lossless.argtypes = decode_base + [ct.c_void_p]
|
|
84
|
+
library.tmb_decode_lossless.restype = ct.c_int
|
|
85
|
+
library.tmb_decode_quantized.argtypes = decode_base + [ct.c_uint32, ct.c_void_p]
|
|
86
|
+
library.tmb_decode_quantized.restype = ct.c_int
|
|
87
|
+
library.tmb_free.argtypes = [ct.c_void_p]
|
|
88
|
+
library.tmb_free.restype = None
|
|
89
|
+
_LIBRARY = library
|
|
90
|
+
return library
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _arrays(
|
|
94
|
+
vertices: npt.ArrayLike, faces: npt.ArrayLike
|
|
95
|
+
) -> tuple[npt.NDArray[np.float32], npt.NDArray[np.uint32]]:
|
|
96
|
+
vertex_array = np.ascontiguousarray(vertices, dtype=np.float32)
|
|
97
|
+
original_faces = np.asarray(faces)
|
|
98
|
+
if (
|
|
99
|
+
vertex_array.ndim != 2
|
|
100
|
+
or vertex_array.shape[1] != 3
|
|
101
|
+
or not len(vertex_array)
|
|
102
|
+
or not np.isfinite(vertex_array).all()
|
|
103
|
+
):
|
|
104
|
+
raise ValueError("vertices must be a finite float32 array with shape [V,3]")
|
|
105
|
+
if (
|
|
106
|
+
original_faces.ndim != 2
|
|
107
|
+
or original_faces.shape[1] != 3
|
|
108
|
+
or not len(original_faces)
|
|
109
|
+
or original_faces.dtype.kind not in "iu"
|
|
110
|
+
or original_faces.min() < 0
|
|
111
|
+
or original_faces.max() >= len(vertex_array)
|
|
112
|
+
):
|
|
113
|
+
raise ValueError("faces must contain valid triangle vertex indices")
|
|
114
|
+
return vertex_array, np.ascontiguousarray(original_faces, dtype=np.uint32)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def encode(
|
|
118
|
+
vertices: npt.ArrayLike,
|
|
119
|
+
faces: npt.ArrayLike,
|
|
120
|
+
*,
|
|
121
|
+
bits: int | None = 14,
|
|
122
|
+
flags: int = VERTEX_IDS,
|
|
123
|
+
compress: bool = True,
|
|
124
|
+
compression_level: int = 2,
|
|
125
|
+
) -> bytes:
|
|
126
|
+
"""Encode a triangle mesh; ``bits=None`` preserves float32 positions exactly."""
|
|
127
|
+
if flags not in range(8):
|
|
128
|
+
raise ValueError("flags must be in [0,7]")
|
|
129
|
+
if bits is not None and not 1 <= bits <= 31:
|
|
130
|
+
raise ValueError("bits must be None or in [1,31]")
|
|
131
|
+
vertex_array, face_array = _arrays(vertices, faces)
|
|
132
|
+
library = _library()
|
|
133
|
+
output = ct.c_void_p()
|
|
134
|
+
output_size = ct.c_size_t()
|
|
135
|
+
timings = np.empty(3, dtype=np.float64)
|
|
136
|
+
common = (
|
|
137
|
+
vertex_array.ctypes.data,
|
|
138
|
+
len(vertex_array),
|
|
139
|
+
face_array.ctypes.data,
|
|
140
|
+
len(face_array),
|
|
141
|
+
flags,
|
|
142
|
+
)
|
|
143
|
+
code = (
|
|
144
|
+
library.tmb_encode_lossless(
|
|
145
|
+
*common, ct.byref(output), ct.byref(output_size), timings.ctypes.data
|
|
146
|
+
)
|
|
147
|
+
if bits is None
|
|
148
|
+
else library.tmb_encode_quantized(
|
|
149
|
+
*common, bits, ct.byref(output), ct.byref(output_size), timings.ctypes.data
|
|
150
|
+
)
|
|
151
|
+
)
|
|
152
|
+
if code:
|
|
153
|
+
raise ValueError(f"TMB1 encode failed ({code})")
|
|
154
|
+
try:
|
|
155
|
+
raw = ct.string_at(output, output_size.value)
|
|
156
|
+
finally:
|
|
157
|
+
library.tmb_free(output)
|
|
158
|
+
return zstd.ZstdCompressor(level=compression_level).compress(raw) if compress else raw
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def _raw(data: bytes | bytearray | memoryview, compressed: bool) -> bytes:
|
|
162
|
+
body = bytes(data)
|
|
163
|
+
if not compressed:
|
|
164
|
+
return body
|
|
165
|
+
try:
|
|
166
|
+
size = zstd.frame_content_size(body)
|
|
167
|
+
if size < 0 or size == zstd.CONTENTSIZE_UNKNOWN or size > _MAX_RAW:
|
|
168
|
+
raise ValueError("invalid decompressed size")
|
|
169
|
+
return zstd.ZstdDecompressor(max_window_size=128 * 1024).decompress(
|
|
170
|
+
body, max_output_size=_MAX_RAW, allow_extra_data=False
|
|
171
|
+
)
|
|
172
|
+
except zstd.ZstdError as exc:
|
|
173
|
+
raise ValueError("invalid Zstd frame") from exc
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def _info(raw: bytes, compressed: bool) -> MeshInfo:
|
|
177
|
+
if len(raw) < _HEADER.size:
|
|
178
|
+
raise ValueError("truncated TMB1 header")
|
|
179
|
+
header = _HEADER.unpack_from(raw)
|
|
180
|
+
magic, version, wire_flags, vertex_count, face_count = header[:5]
|
|
181
|
+
flags = wire_flags & 7
|
|
182
|
+
quantized = bool(wire_flags & _QUANTIZED)
|
|
183
|
+
bits = (wire_flags >> _BITS_SHIFT) & 31
|
|
184
|
+
expected = flags | (_QUANTIZED if quantized else 0) | (bits << _BITS_SHIFT)
|
|
185
|
+
if magic != _MAGIC or version != _VERSION or wire_flags != expected:
|
|
186
|
+
raise ValueError("unsupported TMB1 version or flags")
|
|
187
|
+
if not 0 < vertex_count <= 2_000_000 or not 0 < face_count <= 4_000_000:
|
|
188
|
+
raise ValueError("TMB1 mesh exceeds supported limits")
|
|
189
|
+
if quantized != bool(bits):
|
|
190
|
+
raise ValueError("invalid TMB1 precision")
|
|
191
|
+
if sum(header[5:]) != len(raw) - _HEADER.size:
|
|
192
|
+
raise ValueError("invalid TMB1 section lengths")
|
|
193
|
+
return MeshInfo(vertex_count, face_count, bits if quantized else None, flags, compressed)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def inspect(data: bytes | bytearray | memoryview, *, compressed: bool = True) -> MeshInfo:
|
|
197
|
+
"""Read validated public metadata without decoding the mesh."""
|
|
198
|
+
raw = _raw(data, compressed)
|
|
199
|
+
return _info(raw, compressed)
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def decode(
|
|
203
|
+
data: bytes | bytearray | memoryview, *, compressed: bool = True
|
|
204
|
+
) -> tuple[npt.NDArray[np.float32], npt.NDArray[np.uint32]]:
|
|
205
|
+
"""Decode TMB1 bytes into contiguous ``vertices`` and ``faces`` arrays."""
|
|
206
|
+
raw = _raw(data, compressed)
|
|
207
|
+
info = _info(raw, compressed)
|
|
208
|
+
vertices = np.empty((info.vertex_count, 3), dtype=np.float32)
|
|
209
|
+
faces = np.empty((info.face_count, 3), dtype=np.uint32)
|
|
210
|
+
timings = np.empty(2, dtype=np.float64)
|
|
211
|
+
common = (
|
|
212
|
+
raw,
|
|
213
|
+
len(raw),
|
|
214
|
+
vertices.ctypes.data,
|
|
215
|
+
faces.ctypes.data,
|
|
216
|
+
info.vertex_count,
|
|
217
|
+
info.face_count,
|
|
218
|
+
info.flags,
|
|
219
|
+
)
|
|
220
|
+
library = _library()
|
|
221
|
+
code = (
|
|
222
|
+
library.tmb_decode_lossless(*common, timings.ctypes.data)
|
|
223
|
+
if info.lossless
|
|
224
|
+
else library.tmb_decode_quantized(*common, info.bits, timings.ctypes.data)
|
|
225
|
+
)
|
|
226
|
+
if code:
|
|
227
|
+
raise ValueError(f"TMB1 decode failed ({code})")
|
|
228
|
+
if not np.isfinite(vertices).all() or faces.max() >= info.vertex_count:
|
|
229
|
+
raise ValueError("invalid decoded mesh")
|
|
230
|
+
return vertices, faces
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
Corto
|
|
2
|
+
Copyright (c) 2015-2022, Visual Computing Lab, ISTI - CNR
|
|
3
|
+
All rights reserved.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
tmb_codec/py.typed
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tmb-codec
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Fast Triangle Mesh Binary encoding and decoding
|
|
5
|
+
Author: Tyndall-log
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
License-File: licenses/CORTO_LICENSE.txt
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: C++
|
|
12
|
+
Classifier: Topic :: Multimedia :: Graphics :: 3D Modeling
|
|
13
|
+
Project-URL: Documentation, https://github.com/Tyndall-log/tmb-codec#readme
|
|
14
|
+
Requires-Python: >=3.10
|
|
15
|
+
Requires-Dist: numpy>=1.26
|
|
16
|
+
Requires-Dist: zstandard>=0.23
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
# TMB Codec
|
|
20
|
+
|
|
21
|
+
TMB1 (Triangle Mesh Binary) is a compact general-purpose triangle-mesh codec. The
|
|
22
|
+
library provides one C ABI across Windows, macOS, Linux, and WebAssembly.
|
|
23
|
+
Native CI builds use Clang (`clang-cl` on Windows and `clang++` elsewhere).
|
|
24
|
+
|
|
25
|
+
## Features
|
|
26
|
+
|
|
27
|
+
- Float32 bit-exact lossless positions
|
|
28
|
+
- Quantized positions from 1 through 31 bits
|
|
29
|
+
- Optional restoration of vertex IDs, face IDs, and triangle corner rotation
|
|
30
|
+
- Single-file C++17 implementation
|
|
31
|
+
- No runtime dependency on Zstd; compress the completed TMB1 bundle once outside
|
|
32
|
+
the codec when using `tmb1-zstd-v1`
|
|
33
|
+
|
|
34
|
+
Applications that require stable per-vertex data use `TMB_VERTEX_IDS` (`flags=1`). This restores
|
|
35
|
+
vertex rows and triangle references to original vertex IDs while allowing face
|
|
36
|
+
row order and cyclic starting corners to remain in traversal order.
|
|
37
|
+
|
|
38
|
+
## Python
|
|
39
|
+
|
|
40
|
+
Install a prebuilt native wheel:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pip install tmb-codec
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
from tmb_codec import decode, encode
|
|
48
|
+
|
|
49
|
+
data = encode(vertices, faces, bits=14)
|
|
50
|
+
decoded_vertices, decoded_faces = decode(data)
|
|
51
|
+
|
|
52
|
+
lossless = encode(vertices, faces, bits=None)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Wheels contain the Python API, the platform-native shared library, and license
|
|
56
|
+
notices. They do not contain `src/tmb_codec.cpp` or an sdist.
|
|
57
|
+
|
|
58
|
+
## Native build
|
|
59
|
+
|
|
60
|
+
Windows:
|
|
61
|
+
|
|
62
|
+
```powershell
|
|
63
|
+
cmake -S . -B build -G Ninja -DCMAKE_CXX_COMPILER=clang-cl -DTMB_BUILD_TESTS=ON
|
|
64
|
+
cmake --build build --parallel
|
|
65
|
+
ctest --test-dir build --output-on-failure
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
macOS and Linux:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
cmake -S . -B build -G Ninja -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=Release -DTMB_BUILD_TESTS=ON
|
|
72
|
+
cmake --build build --parallel
|
|
73
|
+
ctest --test-dir build --output-on-failure
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
WebAssembly with Emscripten:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
emcmake cmake -S . -B build-wasm -DCMAKE_BUILD_TYPE=Release -DTMB_BUILD_TESTS=OFF
|
|
80
|
+
cmake --build build-wasm --parallel
|
|
81
|
+
node tests/wasm_smoke.mjs build-wasm/tmb_codec.js
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
The WASM build emits `tmb_codec.js` and `tmb_codec.wasm` with
|
|
85
|
+
memory growth enabled and exports the five public TMB functions plus malloc/free.
|
|
86
|
+
|
|
87
|
+
Every push and pull request builds and installs native wheels on Windows, macOS,
|
|
88
|
+
and Linux and runs the Python tests against those installed wheels. WASM has a
|
|
89
|
+
separate Node.js round-trip test. Pushing a `v*` tag publishes wheels to PyPI and
|
|
90
|
+
then creates a GitHub Release only after every required job succeeds.
|
|
91
|
+
|
|
92
|
+
## C API
|
|
93
|
+
|
|
94
|
+
```cpp
|
|
95
|
+
#include <tmb_codec.h>
|
|
96
|
+
|
|
97
|
+
unsigned char* bytes = nullptr;
|
|
98
|
+
size_t byte_count = 0;
|
|
99
|
+
double timings[3] = {};
|
|
100
|
+
int result = tmb_encode_quantized(
|
|
101
|
+
vertices, vertex_count,
|
|
102
|
+
faces, face_count,
|
|
103
|
+
TMB_VERTEX_IDS, 14,
|
|
104
|
+
&bytes, &byte_count, timings);
|
|
105
|
+
if (result == TMB_OK) {
|
|
106
|
+
// Send zstd(bytes[0:byte_count]) or store the raw TMB1 bundle.
|
|
107
|
+
tmb_free(bytes);
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Inputs are contiguous `float[V][3]` positions and `uint32_t[F][3]` triangle
|
|
112
|
+
indices. Encoder output is allocated by the codec and must be released with
|
|
113
|
+
`tmb_free`. Decoder output arrays are allocated by the caller.
|
|
114
|
+
|
|
115
|
+
## Format
|
|
116
|
+
|
|
117
|
+
TMB1 starts with ten little-endian uint32 values:
|
|
118
|
+
|
|
119
|
+
1. Magic `TMB1`
|
|
120
|
+
2. Format version `1`
|
|
121
|
+
3. Flags
|
|
122
|
+
4. Vertex count
|
|
123
|
+
5. Face count
|
|
124
|
+
6. Topology section size
|
|
125
|
+
7. Position section size
|
|
126
|
+
8. Vertex-ID section size
|
|
127
|
+
9. Face-ID section size
|
|
128
|
+
10. Corner-rotation section size
|
|
129
|
+
|
|
130
|
+
Quantized streams set flag bit 8 and store the coordinate bit count in flag bits
|
|
131
|
+
16 through 20. Their position section begins with four little-endian float64
|
|
132
|
+
values: origin x/y/z and a common extent. Coordinates from 1 through 16 bits use
|
|
133
|
+
one integer component per axis. Coordinates from 17 through 31 bits use low/high
|
|
134
|
+
16-bit components to keep prediction residuals inside signed 32-bit range.
|
|
135
|
+
|
|
136
|
+
The topology and position entropy streams are defined by the reference source in
|
|
137
|
+
`src/tmb_codec.cpp`. Consumers should use the provided encoder and decoder
|
|
138
|
+
unless they also maintain compatibility tests against the reference implementation.
|
|
139
|
+
|
|
140
|
+
## License
|
|
141
|
+
|
|
142
|
+
The codec incorporates and modifies MIT-licensed Corto code. Preserve
|
|
143
|
+
`licenses/CORTO_LICENSE.txt` with source and binary distributions. Project-level
|
|
144
|
+
terms are in `LICENSE`; third-party attribution is in `THIRD_PARTY_NOTICES.md`.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
tmb_codec/__init__.py,sha256=E5_bzkk2CHCqBtpNyEsj-YmUAku82AMxqKZhuH7IAUk,359
|
|
2
|
+
tmb_codec/_native/tmb_codec.dll,sha256=pmrdN5Pz7oktD_cOzCMfAMIk4sDGFDpVECdPqXsUn4o,211968
|
|
3
|
+
tmb_codec/codec.py,sha256=ig7lmaUve7BpgSaOS8XgxBtuObF9rZiV6sIc9gJjv1o,7840
|
|
4
|
+
tmb_codec/licenses/CORTO_LICENSE.txt,sha256=pO8euBMldLQyYyiVVpDkqp9wRdOd4fJzbyB9OtrobIo,1130
|
|
5
|
+
tmb_codec/py.typed,sha256=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN_XKdLCPjaYaY,2
|
|
6
|
+
tmb_codec-0.2.0.dist-info/METADATA,sha256=moKzgWEHJ4O80UszveDqi68Tg9E_Px4MQ-FBpOwfnRc,4669
|
|
7
|
+
tmb_codec-0.2.0.dist-info/WHEEL,sha256=7cuQBrKlgrMjywT6nmSZIIhuOog1xNCTkMyVVbw2aow,103
|
|
8
|
+
tmb_codec-0.2.0.dist-info/licenses/LICENSE,sha256=cQwMShNEo-Ae_Kix_mPphGFiM4tPRJe5fxVbnIa_lC0,1089
|
|
9
|
+
tmb_codec-0.2.0.dist-info/licenses/licenses/CORTO_LICENSE.txt,sha256=pO8euBMldLQyYyiVVpDkqp9wRdOd4fJzbyB9OtrobIo,1130
|
|
10
|
+
tmb_codec-0.2.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Tyndall-log
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
Corto
|
|
2
|
+
Copyright (c) 2015-2022, Visual Computing Lab, ISTI - CNR
|
|
3
|
+
All rights reserved.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|