Correct TE rotation quantization

Literally everything has its own special float quantization. Argh.
This commit is contained in:
Salad Dais
2022-07-16 23:17:34 +00:00
parent 4b963f96d2
commit 59ec99809a
2 changed files with 64 additions and 3 deletions

View File

@@ -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),
)

View File

@@ -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())