open-goal-jak-project/docs/progress-notes/jak1/scratch/generic_tie_to_etie.md

5.2 KiB

Finding the Normals

We're going to assume that the generic tie math in Jak 1 is the same as ETIE as Jak 2. This could be wrong, but it should be easy to verify.

The tricky part is finding the normals. These are needed for ETIE, but not plain TIE.

For looking through the types, it seems like generic TIE uses the same normals as ETIE:

(deftype generic-tie-normal (structure)
  ((x     int8  :offset-assert 0)
   (y     int8  :offset-assert 1)
   (z     int8  :offset-assert 2)
   (dummy int8  :offset-assert 3) ;; was 0 in ETIE normals.
   )
  :method-count-assert 9
  :size-assert         #x4
  :flag-assert         #x900000004
  )

Searching around for normal

(deftype generic-tie-header (structure)
  ((effect              uint8              :offset-assert 0)
   (interp-table-size   uint8              :offset-assert 1)
   (num-bps             uint8              :offset-assert 2)
   (num-ips             uint8              :offset-assert 3)
   (tint-color          uint32             :offset-assert 4)
   (index-table-offset  uint16             :offset-assert 8)
   (kick-table-offset   uint16             :offset-assert 10)
   (normal-table-offset uint16             :offset-assert 12) ;; here it is!
   (interp-table-offset uint16             :offset-assert 14)
   (gsf-header          gsf-header :inline :offset-assert 16)
   )
  :method-count-assert 9
  :size-assert         #x20
  :flag-assert         #x900000020
  )

My first guess is that the generic data for a TIE fragment is just a header, and these uint16s are byte-offsets for the normal data. I'd guess that there's a header per-fragment - they used uint8's for num-bps/num-ips (base points, interpolated points). A single proto might have more than 255 points, but a fragment won't.

My guess is that generic-ref in a tie-fragment points to some data that starts with generic-tie-header.

(deftype tie-fragment (drawable)
  ((gif-ref       (inline-array adgif-shader) :offset 4)
   (point-ref     uint32         :offset 8)
   (color-index   uint16         :offset 12)
   (base-colors   uint8          :offset 14)
   (tex-count     uint16         :offset-assert 32)
   (gif-count     uint16         :offset-assert 34)
   (vertex-count  uint16         :offset-assert 36)
   (color-count   uint16         :offset-assert 38)
   (num-tris      uint16         :offset-assert 40)
   (num-dverts    uint16         :offset-assert 42)
   (dp-ref        uint32         :offset-assert 44)
   (dp-qwc        uint32         :offset-assert 48)
   (generic-ref   uint32         :offset-assert 52) ;; the data we want
   (generic-count uint32         :offset-assert 56)
   (debug-lines   (array vector-array)  :offset-assert 60)
   )
  :method-count-assert 18
  :size-assert         #x40
  :flag-assert         #x1200000040
  )

Extract the data from the file

    u16 generic_qwc = read_plain_data_field<u32>(ref, "generic-count", dts);
    if (generic_qwc) {
      generic_data.resize(16 * generic_qwc);
      auto generic_data_ref = deref_label(get_field_ref(ref, "generic-ref", dts));
      memcpy_plain_data((u8*)generic_data.data(), generic_data_ref, generic_qwc * 16);

The data made sense. There were some cases where the interp-table and the normal-table appeared to be on top of each other, but this only occured when num-ips was 0 and interp-table-size was 0 too.

Treating normal-table-offset as a byte-offset from the start of the header seemed to work.

One fear I had is that the mesh for generic/non-generic is somehow different, so I sanity checked that num-ips + num-bps from the generic header matched the total unique vertex count from the TIE unpacker.

Finding the Envmap shader

We need an additional shader for the environment map draw. Fortunately, this seems the same as Jak 2 - there's a field in prototype-bucket-tie for it. I turned on that code for Jak 1, and it found envmap shaders on reasonable things.

Finding the tint color

This is a little trickier. In jak 2, the tint color was specified per bucket, but in Jak 1, it's specified per fragment. Luckily my data format for ETIE can support this, but extract_tie.cpp needs some refactoring to actually generate it.

Normal Bugs

Some very small number of fragments appear totally wrong.

The most likely explanation is the normals are in the wrong order. The normals seems like valid normals, but looking at the mesh, they are clearly wrong.

I made the assumption that the order of normals would match the order of points, but could this be wrong?

There's this table called index_table:

0 2 32 33
1 3 16 17
34 35 4 5
6 8 36 37
7 9 18 20
38 39 19 21
10 11 40 41
22 23 12 13
42 43 24 25
14 15 44 45
26 27 28 29
46 47 30 31

but going through extremely carefully showed nothing interesting... It all matches up perfectly

Next step: maybe the normal matrix is wrong... let's try to actually find the mystery scaling factor:

vmulx.xyz vf16, vf10, vf14

the vf14.x here.

lui t6, 16256
mtc1 f1, t6 ;; 1.0

qmfc2.i s1, vf10
mtc1 f12, s1
dsra32 s2, s1, 0
mtc1 f13, s2
pextuw s2, r0, s2
mtc1 f14, s2
mula.s f12, f12
madda.s f13, f13
madd.s f15, f14, f14
rsqrt.s f15, f1, f15
mfc1 s1, f15
qmtc2.i vf14, s1
vmulx.xyz vf16, vf10, vf14