From 9052c473efce6a9df39a20a87a7fb7703b6ac5b9 Mon Sep 17 00:00:00 2001 From: copygirl Date: Mon, 9 Dec 2024 07:38:16 +0100 Subject: [PATCH] Add StreamBuffer functions for "ranges" This reads / writes a float in the range of 0.0 to 1.0, but with a uniform distribution instead of whatever it's called that floating point values do. This allows us to more efficiently store euler angles, which can only have values between 0.0 and TAU. No more wasted bits! --- stream_buffer.gd | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/stream_buffer.gd b/stream_buffer.gd index 2bd5bb5..fde5b4a 100644 --- a/stream_buffer.gd +++ b/stream_buffer.gd @@ -83,6 +83,10 @@ func write_vector32(value: Vector3) -> void: write_float32(value.x); write_float func write_transform16(value: Transform3D) -> void: write_vector16(value.basis.x); write_vector16(value.basis.y); write_vector16(value.basis.z); write_vector16(value.origin) func write_transform32(value: Transform3D) -> void: write_vector32(value.basis.x); write_vector32(value.basis.y); write_vector32(value.basis.z); write_vector32(value.origin) +func write_range8(value: float) -> void: write_uint8(roundi(value * 255)) +func write_range16(value: float) -> void: write_uint16(roundi(value * 65535)) +func write_range32(value: float) -> void: write_uint32(roundi(value * 4294967295)) + func read_int8() -> int: assert(remaining_bytes() >= 1); var result := buffer.decode_s8(cursor); cursor += 1; bit = 0; return result func read_int16() -> int: assert(remaining_bytes() >= 2); var result := buffer.decode_s16(cursor); cursor += 2; bit = 0; return result @@ -105,6 +109,10 @@ func read_vector32() -> Vector3: return Vector3(read_float32(), read_float32(), func read_transform16() -> Transform3D: return Transform3D(Basis(read_vector16(), read_vector16(), read_vector16()), read_vector16()) func read_transform32() -> Transform3D: return Transform3D(Basis(read_vector32(), read_vector32(), read_vector32()), read_vector32()) +func read_range8() -> float: return float(read_uint8()) / 255 +func read_range16() -> float: return float(read_uint16()) / 65535 +func read_range32() -> float: return float(read_uint32()) / 4294967295 + func write_bit(value: bool) -> void: if bit == 0: ensure_capacity(1); buffer[size] = 0; size += 1 @@ -155,14 +163,9 @@ func write_bone_pose(value: Transform3D) -> void: var has_rot := !rot.is_zero_approx() var has_scale := !scale.is_equal_approx(Vector3.ONE) var has_scale3 := !is_equal_approx(scale.x, scale.y) or !is_equal_approx(scale.x, scale.y) - write_bit(has_pos) - write_bit(has_rot) - write_bit(has_scale) - write_bit(has_scale3) + write_bit(has_pos); write_bit(has_rot); write_bit(has_scale); write_bit(has_scale3) if has_pos: write_vector16(pos) - # TODO: Could optimize this by using 16-bit fixed-point values. - # Since these values can only be in the range 0 to 1. - if has_rot: write_vector16(rot) + if has_rot: write_range16(rot.x / TAU); write_range16(rot.y / TAU); write_range16(rot.z / TAU) if has_scale3: write_vector16(scale) elif has_scale: write_float16((scale.x + scale.y + scale.z) / 3) @@ -175,7 +178,7 @@ func read_bone_pose() -> Transform3D: var has_scale := read_bit() var has_scale3 := read_bit() if has_pos: pos = read_vector16() - if has_rot: rot = read_vector16() + if has_rot: rot = Vector3(read_range16() * TAU, read_range16() * TAU, read_range16() * TAU) if has_scale3: scale = read_vector16() elif has_scale: var s := read_float16(); scale = Vector3(s, s, s) var basis := Basis.from_scale(scale) * Basis.from_euler(rot)