Correct TE rotation quantization
Literally everything has its own special float quantization. Argh.
This commit is contained in:
@@ -7,6 +7,7 @@ import dataclasses
|
||||
import enum
|
||||
import importlib
|
||||
import logging
|
||||
import math
|
||||
import zlib
|
||||
from typing import *
|
||||
|
||||
@@ -1045,6 +1046,21 @@ _TE_FIELD_KEY = Optional[Sequence[int]]
|
||||
TE_S16_COORD = se.QuantizedFloat(se.S16, -1.000030518509476, 1.0, False)
|
||||
|
||||
|
||||
class PackedTERotation(se.QuantizedFloat):
|
||||
"""Another weird one, packed TE rotations have their own special quantization"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(se.S16, math.pi * -2, math.pi * 2, zero_median=False)
|
||||
self.step_mag = 1.0 / (se.U16.max_val + 1)
|
||||
|
||||
def _float_to_quantized(self, val: float, lower: float, upper: float):
|
||||
val = math.fmod(val, upper)
|
||||
val = super()._float_to_quantized(val, lower, upper)
|
||||
if val == se.S16.max_val + 1:
|
||||
val = self.prim_min
|
||||
return val
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class TextureEntry:
|
||||
Textures: Dict[_TE_FIELD_KEY, UUID] = _te_field(
|
||||
@@ -1056,7 +1072,7 @@ class TextureEntry:
|
||||
ScalesT: Dict[_TE_FIELD_KEY, float] = _te_field(se.F32, default=1.0)
|
||||
OffsetsS: Dict[_TE_FIELD_KEY, float] = _te_field(TE_S16_COORD, default=0.0)
|
||||
OffsetsT: Dict[_TE_FIELD_KEY, float] = _te_field(TE_S16_COORD, default=0.0)
|
||||
Rotation: Dict[_TE_FIELD_KEY, float] = _te_field(TE_S16_COORD, default=0.0)
|
||||
Rotation: Dict[_TE_FIELD_KEY, float] = _te_field(PackedTERotation(), default=0.0)
|
||||
BasicMaterials: Dict[_TE_FIELD_KEY, "BasicMaterials"] = _te_field(
|
||||
BUMP_SHINY_FULLBRIGHT, default_factory=lambda: BasicMaterials(Bump=0, FullBright=False, Shiny=0),
|
||||
)
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import math
|
||||
import unittest
|
||||
|
||||
import hippolyzer.lib.base.serialization as se
|
||||
from hippolyzer.lib.base.datatypes import UUID
|
||||
from hippolyzer.lib.base.message.message_formatting import HumanMessageSerializer
|
||||
from hippolyzer.lib.base.templates import TextureEntrySubfieldSerializer, TEFaceBitfield, TextureEntry
|
||||
from hippolyzer.lib.base.templates import TextureEntrySubfieldSerializer, TEFaceBitfield, TextureEntry, PackedTERotation
|
||||
|
||||
EXAMPLE_TE = b'\x89UgG$\xcbC\xed\x92\x0bG\xca\xed\x15F_\x08\xca*\x98:\x18\x02,\r\xf4\x1e\xc6\xf5\x91\x01]\x83\x014' \
|
||||
b'\x00\x90i+\x10\x80\xa1\xaa\xa2g\x11o\xa8]\xc6\x00\x00\x00\x00\x00\x00\x00\x00\x80?\x00\x00\x00\x80?' \
|
||||
@@ -68,8 +69,52 @@ class TemplateTests(unittest.TestCase):
|
||||
# Serialization order and format should match indra's exactly
|
||||
self.assertEqual(EXAMPLE_TE, data_field)
|
||||
deser = spec.deserialize(None, data_field, pod=True)
|
||||
self.assertEqual(deser, pod_te)
|
||||
self.assertEqual(pod_te, deser)
|
||||
|
||||
def test_textureentry_defaults(self):
|
||||
te = TextureEntry()
|
||||
self.assertEqual(UUID('89556747-24cb-43ed-920b-47caed15465f'), te.Textures[None])
|
||||
|
||||
def test_textureentry_rotation_packing(self):
|
||||
writer = se.BufferWriter("!")
|
||||
writer.write(PackedTERotation(), math.pi * 2)
|
||||
# fmod() makes this loop back around to 0
|
||||
self.assertEqual(b"\x00\x00", writer.copy_buffer())
|
||||
writer.clear()
|
||||
|
||||
writer.write(PackedTERotation(), -math.pi * 2)
|
||||
# fmod() makes this loop back around to 0
|
||||
self.assertEqual(b"\x00\x00", writer.copy_buffer())
|
||||
writer.clear()
|
||||
|
||||
writer.write(PackedTERotation(), 0)
|
||||
self.assertEqual(b"\x00\x00", writer.copy_buffer())
|
||||
writer.clear()
|
||||
|
||||
# These both map to -32768 because of overflow in the positive case
|
||||
# that isn't caught by exact equality to math.pi * 2
|
||||
writer.write(PackedTERotation(), math.pi * 1.999999)
|
||||
self.assertEqual(b"\x80\x00", writer.copy_buffer())
|
||||
writer.clear()
|
||||
|
||||
writer.write(PackedTERotation(), math.pi * -1.999999)
|
||||
self.assertEqual(b"\x80\x00", writer.copy_buffer())
|
||||
writer.clear()
|
||||
|
||||
def test_textureentry_rotation_unpacking(self):
|
||||
reader = se.BufferReader("!", b"\x00\x00")
|
||||
self.assertEqual(0, reader.read(PackedTERotation()))
|
||||
|
||||
reader = se.BufferReader("!", b"\x80\x00")
|
||||
self.assertEqual(-math.pi * 2, reader.read(PackedTERotation()))
|
||||
|
||||
# This quantization method does not allow for any representation of
|
||||
# F_TWO_PI itself, just a value slightly below it! The float representation
|
||||
# is ever so slightly different from the C++ version, but it should still
|
||||
# round-trip correctly.
|
||||
reader = se.BufferReader("!", b"\x7f\xff")
|
||||
self.assertEqual(6.282993559581101, reader.read(PackedTERotation()))
|
||||
|
||||
writer = se.BufferWriter("!")
|
||||
writer.write(PackedTERotation(), 6.282993559581101)
|
||||
self.assertEqual(b"\x7f\xff", writer.copy_buffer())
|
||||
|
||||
Reference in New Issue
Block a user