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 := &current[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 := &current[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 := &current[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  }