github.com/egonelbre/exp@v0.0.0-20240430123955-ed1d3aa93911/physicscompress2/physics/encoding.go (about) 1 package physics 2 3 import ( 4 "fmt" 5 6 "github.com/egonelbre/exp/bit" 7 "github.com/egonelbre/exp/coder/arith" 8 ) 9 10 func maxbits(vs ...int) (r uint) { 11 r = 0 12 for _, x := range vs { 13 if x != 0 { 14 bits := bit.ScanRight(bit.ZEncode(int64(x))) + 1 15 if r < bits { 16 r = bits 17 } 18 } 19 } 20 return 21 } 22 23 // encodes zeros well 24 func mZeros() arith.Model { 25 return &arith.Shift2{P0: 0x34a, I0: 0x1, P1: 0xd0, I1: 0x5} 26 } 27 28 func mValues(nbits uint) arith.Model { 29 return arith.NewTree(nbits, func() arith.Model { 30 return &arith.Shift2{P0: 0x438, I0: 0x3, P1: 0x61a, I1: 0x1} 31 }) 32 } 33 34 var totalbits = 0 35 36 func (s *State) Encode() []byte { 37 enc := arith.NewEncoder() 38 39 historic := s.Historic().Cubes 40 _ = historic 41 baseline := s.Baseline().Cubes 42 current := s.Current().Cubes 43 44 mzeros := mZeros() 45 items := []int{} 46 for i := range current { 47 cube, base := ¤t[i], &baseline[i] 48 if *cube == *base { 49 mzeros.Encode(enc, 0) 50 } else { 51 mzeros.Encode(enc, 1) 52 items = append(items, i) 53 } 54 } 55 56 for _, i := range items { 57 cube := ¤t[i] 58 v := uint(1) 59 if cube.Interacting { 60 v = 0 61 } 62 mzeros.Encode(enc, v) 63 } 64 65 props := IndexProps(items, len(baseline)) 66 SortByZ(props, Props(baseline)) 67 getProp := Props(current) 68 69 max := uint64(0) 70 for _, i := range props { 71 ext := uint64(bit.ZEncode(int64(getProp(i)))) 72 if max < ext { 73 max = ext 74 } 75 } 76 77 if max == 0 { 78 mzeros.Encode(enc, 1) 79 enc.Close() 80 return enc.Bytes() 81 } 82 83 nbits := bit.ScanRight(max) + 1 84 for i := 0; i < int(nbits); i += 1 { 85 mzeros.Encode(enc, 0) 86 } 87 mzeros.Encode(enc, 1) 88 89 mvalues := mValues(nbits) 90 for _, i := range props { 91 val := uint(bit.ZEncode(int64(getProp(i)))) 92 mvalues.Encode(enc, val) 93 } 94 95 enc.Close() 96 return enc.Bytes() 97 } 98 99 func (s *State) Decode(snapshot []byte) { 100 dec := arith.NewDecoder(snapshot) 101 102 s.Current().Assign(s.Baseline()) 103 historic := s.Historic().Cubes 104 _ = historic 105 baseline := s.Baseline().Cubes 106 current := s.Current().Cubes 107 108 mzeros := mZeros() 109 110 items := []int{} 111 for i := range current { 112 if mzeros.Decode(dec) == 1 { 113 items = append(items, i) 114 } 115 } 116 117 for _, i := range items { 118 cube := ¤t[i] 119 cube.Interacting = mzeros.Decode(dec) == 0 120 } 121 122 props := IndexProps(items, len(baseline)) 123 SortByZ(props, Props(baseline)) 124 setProp := SetProps(current) 125 126 nbits := uint(0) 127 for mzeros.Decode(dec) == 0 { 128 nbits += 1 129 } 130 131 if nbits == 0 { 132 for _, i := range props { 133 setProp(i, 0) 134 } 135 return 136 } 137 138 mvalues := mValues(nbits) 139 for _, i := range props { 140 z := mvalues.Decode(dec) 141 v := bit.ZDecode(uint64(z)) 142 setProp(i, int(v)) 143 } 144 } 145 146 func IndexProps(index []int, N int) []int { 147 r := make([]int, 0, len(index)*7) 148 for _, v := range index { 149 r = append(r, v, v+N, v+N*2, v+N*3, v+N*4, v+N*5, v+N*6) 150 } 151 return r 152 } 153 154 func Props(base []Cube) func(i int) int { 155 N := len(base) 156 return func(i int) int { 157 k := i % N 158 switch i / N { 159 case 0: 160 return int(base[k].Pos.X * UnitsPerMeter) 161 case 1: 162 return int(base[k].Pos.Y * UnitsPerMeter) 163 case 2: 164 return int(base[k].Pos.Z * UnitsPerMeter) 165 case 3: 166 return int(base[k].Rot.X * UnitsPerQuat) 167 case 4: 168 return int(base[k].Rot.Y * UnitsPerQuat) 169 case 5: 170 return int(base[k].Rot.Z * UnitsPerQuat) 171 case 6: 172 return int(base[k].Rot.W * UnitsPerQuat) 173 default: 174 panic("invalid") 175 } 176 } 177 } 178 179 func SetProps(cur []Cube) func(i int, v int) { 180 N := len(cur) 181 return func(i int, v int) { 182 k := i % N 183 switch i / N { 184 case 0: 185 cur[k].Pos.X = float32(v) / UnitsPerMeter 186 case 1: 187 cur[k].Pos.Y = float32(v) / UnitsPerMeter 188 case 2: 189 cur[k].Pos.Z = float32(v) / UnitsPerMeter 190 case 3: 191 cur[k].Rot.X = float32(v) / UnitsPerQuat 192 case 4: 193 cur[k].Rot.Y = float32(v) / UnitsPerQuat 194 case 5: 195 cur[k].Rot.Z = float32(v) / UnitsPerQuat 196 case 6: 197 cur[k].Rot.W = float32(v) / UnitsPerQuat 198 default: 199 panic("invalid") 200 } 201 } 202 } 203 204 func DeltaProps(hist, base []Cube) func(i int) int { 205 N := len(base) 206 return func(i int) int { 207 k := i % N 208 switch i / N { 209 case 0: 210 return int((hist[k].Pos.X - base[k].Pos.X) * UnitsPerMeter) 211 case 1: 212 return int((hist[k].Pos.Y - base[k].Pos.Y) * UnitsPerMeter) 213 case 2: 214 return int((hist[k].Pos.Z - base[k].Pos.Z) * UnitsPerMeter) 215 case 3: 216 return int((hist[k].Rot.X - base[k].Rot.X) * UnitsPerQuat) 217 case 4: 218 return int((hist[k].Rot.Y - base[k].Rot.Y) * UnitsPerQuat) 219 case 5: 220 return int((hist[k].Rot.Z - base[k].Rot.Z) * UnitsPerQuat) 221 case 6: 222 return int((hist[k].Rot.W - base[k].Rot.W) * UnitsPerQuat) 223 default: 224 panic("invalid") 225 } 226 } 227 } 228 229 func SetDeltaProps(base, cur []Cube) func(i int, v int) { 230 N := len(base) 231 return func(i int, v int) { 232 k := i % N 233 switch i / N { 234 case 0: 235 cur[k].Pos.X = float32(v)/UnitsPerMeter + base[k].Pos.X 236 case 1: 237 cur[k].Pos.Y = float32(v)/UnitsPerMeter + base[k].Pos.Y 238 case 2: 239 cur[k].Pos.Z = float32(v)/UnitsPerMeter + base[k].Pos.Z 240 case 3: 241 cur[k].Rot.X = float32(v)/UnitsPerQuat + base[k].Rot.X 242 case 4: 243 cur[k].Rot.Y = float32(v)/UnitsPerQuat + base[k].Rot.Y 244 case 5: 245 cur[k].Rot.Z = float32(v)/UnitsPerQuat + base[k].Rot.Z 246 case 6: 247 cur[k].Rot.W = float32(v)/UnitsPerQuat + base[k].Rot.W 248 default: 249 panic("invalid") 250 } 251 } 252 } 253 254 func ExtraProps(hist, base, cur []Cube) func(i int) int { 255 N := len(base) 256 return func(i int) int { 257 k := i % N 258 switch i / N { 259 case 0: 260 return int((cur[k].Pos.X - 2*base[k].Pos.X + hist[k].Pos.X) * UnitsPerMeter) 261 case 1: 262 return int((cur[k].Pos.Y - 2*base[k].Pos.Y + hist[k].Pos.Y) * UnitsPerMeter) 263 case 2: 264 return int((cur[k].Pos.Z - 2*base[k].Pos.Z + hist[k].Pos.Z) * UnitsPerMeter) 265 case 3: 266 return int((cur[k].Rot.X - 2*base[k].Rot.X + hist[k].Rot.X) * UnitsPerQuat) 267 case 4: 268 return int((cur[k].Rot.Y - 2*base[k].Rot.Y + hist[k].Rot.Y) * UnitsPerQuat) 269 case 5: 270 return int((cur[k].Rot.Z - 2*base[k].Rot.Z + hist[k].Rot.Z) * UnitsPerQuat) 271 case 6: 272 return int((cur[k].Rot.W - 2*base[k].Rot.W + hist[k].Rot.W) * UnitsPerQuat) 273 default: 274 panic("invalid") 275 } 276 } 277 } 278 279 func SetExtraProps(hist, base, cur []Cube) func(i int, v int) { 280 N := len(base) 281 return func(i int, v int) { 282 k := i % N 283 switch i / N { 284 case 0: 285 cur[k].Pos.X = float32(v)/UnitsPerMeter + 2*base[k].Pos.X - hist[k].Pos.X 286 case 1: 287 cur[k].Pos.Y = float32(v)/UnitsPerMeter + 2*base[k].Pos.Y - hist[k].Pos.Y 288 case 2: 289 cur[k].Pos.Z = float32(v)/UnitsPerMeter + 2*base[k].Pos.Z - hist[k].Pos.Z 290 case 3: 291 cur[k].Rot.X = float32(v)/UnitsPerQuat + 2*base[k].Rot.X - hist[k].Rot.X 292 case 4: 293 cur[k].Rot.Y = float32(v)/UnitsPerQuat + 2*base[k].Rot.Y - hist[k].Rot.Y 294 case 5: 295 cur[k].Rot.Z = float32(v)/UnitsPerQuat + 2*base[k].Rot.Z - hist[k].Rot.Z 296 case 6: 297 cur[k].Rot.W = float32(v)/UnitsPerQuat + 2*base[k].Rot.W - hist[k].Rot.W 298 default: 299 panic("invalid") 300 } 301 } 302 } 303 304 func SameBools(a, b []bool) { 305 if len(a) != len(b) { 306 panic("different length") 307 } 308 309 as := BoolsStr(a) 310 bs := BoolsStr(b) 311 if as != bs { 312 fmt.Println("---") 313 fmt.Println(as) 314 fmt.Println(bs) 315 fmt.Println("---") 316 } 317 } 318 319 func BoolsStr(a []bool) string { 320 r := make([]byte, 0, len(a)) 321 for _, v := range a { 322 if v { 323 r = append(r, '.') 324 } else { 325 r = append(r, 'X') 326 } 327 } 328 return string(r) 329 }