[jak2] add sprite glow renderer (#2232)

Adds the "sprite glow" renderer, which is responsible for the glowing
lights.
This commit is contained in:
water111 2023-02-20 20:25:45 -05:00 committed by GitHub
parent f388898d7b
commit 08ce65fd9b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
43 changed files with 4043 additions and 724 deletions

View File

@ -128,6 +128,13 @@ class Vector {
return *this;
}
Vector<T, Size>& operator+=(const T& other) {
for (int i = 0; i < Size; i++) {
m_data[i] += other;
}
return *this;
}
Vector<T, Size> elementwise_multiply(const Vector<T, Size>& other) const {
Vector<T, Size> result;
for (int i = 0; i < Size; i++) {

View File

@ -3662,6 +3662,7 @@
(signal 96)
(finish 97)
(label 98)
(hack 127)
)
(defenum gs-reg64
@ -4047,10 +4048,10 @@
)
(deftype gs-adcmd (structure)
((word uint32 4 :offset-assert 0)
(quad uint128 :offset 0)
(data uint64 :offset 0)
(cmds gs-reg64 :offset 8)
((word uint32 4 :offset-assert 0 :score -10)
(quad uint128 :offset 0 :score -10)
(data uint64 :offset 0 :score -10)
(cmds gs-reg64 :offset 8 :score 10)
(cmd uint8 :offset 8)
(x uint32 :offset 0)
(y uint32 :offset 4)
@ -4356,10 +4357,10 @@
)
(deftype gs-packed-xyzw (vector)
((ix int32 :offset 0)
(iy int32 :offset 4)
(iz int32 :offset 8)
(iw int32 :offset 12)
((ix int32 :offset 0 :score 10)
(iy int32 :offset 4 :score 10)
(iz int32 :offset 8 :score 10)
(iw int32 :offset 12 :score 10)
)
:method-count-assert 9
:size-assert #x10
@ -20356,6 +20357,7 @@
(fade-b float :offset-assert 52)
(tex-id texture-id :offset-assert 56)
(dummy uint32 :offset-assert 60)
(quads vector 4 :inline :offset 0)
)
:method-count-assert 10
:size-assert #x40
@ -20368,14 +20370,14 @@
(deftype simple-sprite-system (structure)
((count int16 :offset-assert 0)
(max-count int16 :offset-assert 2)
(data sprite-glow-data :offset-assert 4)
(data (inline-array sprite-glow-data) :offset-assert 4)
)
:method-count-assert 12
:size-assert #x8
:flag-assert #xc00000008
(:methods
(add! (_type_ dma-buffer) none 9)
(simple-sprite-system-method-10 (_type_ dma-buffer) none 10)
(add! (_type_ sprite-glow-data) none 9)
(draw-all-sprites! (_type_ dma-buffer) none 10)
(clear! (_type_) none 11)
)
)
@ -23852,14 +23854,14 @@
(deftype sprite-glow-template (structure)
((clear-init-giftag gs-gif-tag :inline :offset-assert 0)
(clear-init-adcmds vector4w 5 :inline :offset-assert 16) ;; gs-adcmd?
(clear-init-adcmds gs-adcmd 5 :inline :offset-assert 16) ;; gs-adcmd?
(clear-draw-giftag gs-gif-tag :inline :offset-assert 96)
(clear-draw-clr-0 gs-packed-rgba :inline :offset-assert 112)
(clear-draw-xyz-0 vector 2 :inline :offset-assert 128)
(clear-draw-xyz-0 gs-packed-xyzw 2 :inline :offset-assert 128)
(clear-draw-clr-1 gs-packed-rgba :inline :offset-assert 160)
(clear-draw-xyz-1 vector 2 :inline :offset-assert 176)
(offscr-setup-giftag gs-gif-tag :inline :offset-assert 208)
(offscr-setup-adcmds vector4w 8 :inline :offset-assert 224) ;; gs-adcmd?
(offscr-setup-adcmds gs-adcmd 8 :inline :offset-assert 224) ;; gs-adcmd?
(offscr-first-giftag gs-gif-tag :inline :offset-assert 352)
(offscr-first-clr gs-packed-rgba :inline :offset-assert 368)
(offscr-first-uv-0 gs-packed-uv :inline :offset-assert 384)
@ -23867,7 +23869,7 @@
(offscr-first-uv-1 gs-packed-uv :inline :offset-assert 416)
(offscr-first-xyzw-1 gs-packed-xyzw :inline :offset-assert 432)
(repeat-draw-giftag gs-gif-tag :inline :offset-assert 448)
(repeat-draw-adcmds vector4w 29 :inline :offset-assert 464) ;; gs-adcmd?
(repeat-draw-adcmds gs-adcmd 29 :inline :offset-assert 464) ;; gs-adcmd?
(flare-alpha-giftag gs-gif-tag :inline :offset-assert 928)
(flare-alpha-clr gs-packed-rgba :inline :offset-assert 944)
(flare-alpha-uv gs-packed-uv :inline :offset-assert 960)
@ -23876,7 +23878,7 @@
(flare-alpha-xyzw-2 gs-packed-xyzw :inline :offset-assert 1008)
(flare-alpha-xyzw-3 gs-packed-xyzw :inline :offset-assert 1024)
(flare-init-giftag gs-gif-tag :inline :offset-assert 1040)
(flare-init-adcmds vector4w 8 :inline :offset-assert 1056) ;; gs-adcmd?
(flare-init-adcmds gs-adcmd 8 :inline :offset-assert 1056) ;; gs-adcmd?
(flare-draw-giftag gs-gif-tag :inline :offset-assert 1184)
(flare-draw-clr gs-packed-rgba :inline :offset-assert 1200)
(flare-draw-stq-0 gs-packed-stq :inline :offset-assert 1216)
@ -23894,11 +23896,11 @@
)
(deftype sprite-glow-consts (structure)
((camera matrix :inline :offset-assert 0)
(perspective matrix :inline :offset-assert 64)
(hvdf-offset vector :inline :offset-assert 128)
(hmge-scale vector :inline :offset-assert 144)
(consts vector :inline :offset-assert 160 :score -1)
((camera matrix :inline :offset-assert 0) ;; 0
(perspective matrix :inline :offset-assert 64) ;; 4
(hvdf-offset vector :inline :offset-assert 128);; 8
(hmge-scale vector :inline :offset-assert 144) ;; 9
(consts vector :inline :offset-assert 160 :score -1) ;; 10
(pfog0 float :offset 160)
(deg-to-rad float :offset 164)
(min-scale float :offset 168)
@ -23935,6 +23937,7 @@
((control-packet dma-packet :inline :offset-assert 0)
(num-sprites uint32 :offset-assert 16)
(dummys uint32 3 :offset-assert 20)
(num-sprites-quad uint128 :offset 16)
(vecdata-packet dma-packet :inline :offset-assert 32)
(vecdata sprite-glow-data :inline :offset-assert 48)
(shader-packet dma-packet :inline :offset-assert 112)
@ -23950,9 +23953,11 @@
((control-packet dma-packet :inline :offset-assert 0)
(num-sprites uint32 :offset-assert 16)
(dummys uint32 3 :offset-assert 20)
(num-sprites-quad uint128 :offset 16)
(vecdata-packet dma-packet :inline :offset-assert 32)
(vecdata sprite-glow-data :inline :offset-assert 48)
(shader-packet dma-packet :inline :offset-assert 112)
(shader-packet-ptr pointer :offset 116) ;; pointer to adgif shader to upload.
(mscal-packet dma-packet :inline :offset-assert 128)
)
:method-count-assert 9
@ -23966,9 +23971,9 @@
(define-extern sprite-glow-init-engine (function dma-buffer none))
(define-extern *sprite-glow-dma-packet-data* sprite-glow-dma-packet-data)
(define-extern sprite-glow-add-sprite (function dma-buffer sprite-vec-data-2d float float float adgif-shader none))
(define-extern sprite-glow-add-simple-sprite (function dma-buffer sprite-glow-dma-packet-data sprite-glow-data pointer))
(define-extern sprite-glow-add-simple-sprite (function dma-buffer sprite-glow-dma-packet-data sprite-glow-data pointer none))
(define-extern sprite-glow-draw (function dma-buffer none))
(define-extern add-shader-to-dma (function dma-buffer pointer))
(define-extern add-shader-to-dma (function dma-buffer adgif-shader))
(define-extern *simple-sprite-system* simple-sprite-system)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

View File

@ -495,7 +495,7 @@
"(method 181 gator)": [
2, 3, 7, 10, 11, 14, 15, 16, 17, 18, 19, 20, 21, 22, 25, 26, 30
],
"(method 10 simple-sprite-system)": [0, 1, 3, 4, 5, 6, 9, 11],
"(method 10 simple-sprite-system)": [0],
"target-pilot-post": [0, 2, 4, 13, 16, 22, 27, 41],
"(anon-function 0 ruins-obs)": [
0, 5, 7, 12, 13, 15, 17, 23, 24, 33, 42, 45, 46, 53, 58

View File

@ -66,7 +66,7 @@
"sprite-distort": [["L27", "vu-function"]],
"sprite-glow": [
["L29", "vu-function"],
["L27", "vector"]
["L27", "dma-packet"]
],
"debug": [
["L250", "(inline-array vector)", 32],

View File

@ -1591,7 +1591,7 @@
[48, "vector4w"]
],
"(method 22 traffic-tracker)": [[16, "mystery-traffic-object-spawn-params"]],
"(method 10 simple-sprite-system)": [[16, ["array", "texture-id", 4]]],
"(method 10 simple-sprite-system)": [[16, ["array", "texture-id", 128]]],
"(anon-function 3 ruins-obs)": [[16, "event-message-block"]],
"(event unbroken ruins-breakable-wall)": [[16, "attack-info"]],
"(method 21 spider-eyes)": [[32, "vector"]],

View File

@ -10525,5 +10525,21 @@
[8, "a3", "pal-electric-fan"],
[15, "a3", "pal-electric-fan"],
[22, "t0", "pal-electric-fan"]
],
"sprite-glow-init-engine": [
[[8, 22], "a0", "dma-packet"],
[[32, 50], "a1", "dma-packet"],
[[52, 74], "a1", "dma-packet"],
[[76, 84], "a0", "dma-packet"],
[[85, 92], "v1", "dma-packet"]
],
"sprite-glow-add-sprite": [
[[0, 33], "v1", "sprite-glow-cnt-template"]
],
"sprite-glow-add-simple-sprite": [
[[0, 33], "v1", "sprite-glow-ref-template"]
],
"add-shader-to-dma": [
[[6, 8], "v1", "(pointer uint32)"]
]
}

View File

@ -749,6 +749,8 @@ const std::unordered_map<
{
{"ocean-near-indices",
{{"data", ArrayFieldDecompMeta(TypeSpec("ocean-near-index"), 32)}}},
{"simple-sprite-system",
{{"data", ArrayFieldDecompMeta(TypeSpec("sprite-glow-data"), 64)}}},
{"ocean-mid-masks", {{"data", ArrayFieldDecompMeta(TypeSpec("ocean-mid-mask"), 8)}}},
{"sparticle-launcher",
{{"init-specs", ArrayFieldDecompMeta(TypeSpec("sp-field-init-spec"), 16)}}},

View File

@ -0,0 +1,298 @@
# Sprite Glow: EE side
It's pretty simple, no asm.
# VU Memory Map
Offset is 400 (0-400 -> 400-800 as input buffers)
```
400 - 800 (input second buffer)
800 - template copy 1
884 - template copy 2
980 - constants
```
# DMA init
```
@ 0x500930 tag: TAG: 0x00000000 cnt qwc 0x0018
vif0: STCYCL cl: 4 wl: 4
vif1: UNPACK-V4-32: 24 addr: 980 us: false tops: false
@ 0x500ac0 tag: TAG: 0x00777650 ref qwc 0x0054
vif0: STCYCL cl: 4 wl: 4
vif1: UNPACK-V4-32: 84 addr: 800 us: false tops: false
@ 0x500ad0 tag: TAG: 0x00777650 ref qwc 0x0054
vif0: MSCAL 0x0
vif1: UNPACK-V4-32: 84 addr: 884 us: false tops: false
@ 0x500ae0 tag: TAG: 0x00000000 cnt qwc 0x0000
vif0: BASE 0x0
vif1: OFFSET 0x190
@ 0x500af0 tag: TAG: 0x00000000 cnt qwc 0x0000
vif0: NOP
vif1: FLUSHE
```
First tag is uploading the constants.
Next two are uploading two copies of the templates and run init. Output is double buffered, so this makes sense.
Next tag sets up input double buffer.
Final tag is just sync before starting the draws
# Template system
The VU program is (as usual) double buffered.
There are two input buffers, containing data uploaded through VIF.
There are two output buffers, each containing the `sprite-glow-template`.
While the program runs, it transform vertices, putting the results in the template.
Once done, it `xgkick`s, which waits for the previous run's draw to finish if needed,
then begins the drawing process.
# What is drawn?
Annoyingly, there are 6 draws this time:
- Probe Clear alpha
- Probe Draw alpha
- Offscreen sample
- Offscreen repeat
- Draw Alpha
- Draw Final
In summary:
- Probe Clear alpha: draw a `alpha = 0` square. Always drawn.
- Probe Draw alpha: draw an `alpha = 1` square. 1 px smaller than first draw. Uses normal z test.
## Draw 1 and 2: "Probe Clear alpha" and "Probe Draw alpha"
First is the `clear`. The first tag is 5 regs of adgif:
- `texflush`
- `(new 'static 'gs-alpha :a 2 :b 2 :c 2 :d 1)`
- `(new 'static 'gs-test :ate 1 :afail 1 :zte 1 :ztst 2)`
- `(new 'static 'gs-zbuf :zbp 304 :psm 1 :zmsk 1)`
- `(new 'static 'gs-frame :fbp 408 :fbw 8 :fbmsk #xffffff)`
The alpha is:
```
Cv = (0 - 0) * 0 + Cd
```
which means to not write any color.
The test is:
- alpha test always fails, means only rgba is written always
- ztest is usual GEQUAL
When combined with the alpha settings, this only writes alpha, no rgb or depth.
The zbuf looks at the normal zbuf, but z writing is masked again. Just in case.
The gs-frame yet again masks away rgb writes. Just in case.
There are two draws. Both are sprites. The first draw sets alpha to 0 and uses z = #xffffff, so it always passes.
The second draw is similar but:
- z comes from the transformed vertex. So it has normal depth test behavior
- alpha is 1
- it's 1 pixel smaller than the first draw.
So the end result is:
- a `alpha = 0` square always
- an `alpha = 1` square, offset in by 1 pixel on all sides, but only where depth passes.
## Draw 3: Offscreen Sample
Switches to GS context 2. Samples from framebuffer and writes to a temporary texture (64 px width, uses only 32).
- only writes alpha
- mmag/mmin on
- tcc = 1, tfx = 1 (rgba, decal) - RGBA all come from texture, nothing fancy
- rgb writes masked (only write alpha)
- clamp clamps
- alpha test thing disables z buffer writing.
This basically just copies the inner square from draw 2 to a separate texture.
## Draw 4: Repeat draw
This appears to draw over itself again and again. I think it effectively blends using texture filtering. So the 0, 0 px will have the average value of alpha.
## Draw 5: flare alpha
This is set up in the `repeat-draw-adcmds`. Drawing to the framebuffer again.
# VU1 program
```
out memory map:
68: adgif0
69: adgif1
70: adgif2
71: adgif3
72: adgif4
```
```
;; math:
first, input position is multiplied by camera matrix (including adding part). Only xyz is computed here. (p0, vf01)
color: rgb *= a
fade = clamp(0, 1, p0.z * fade_a + fade_b)
INIT program
iaddiu vi05, vi00, 0x320 | nop ;; vi05 = 800 (template)
lq.xyzw vf25, 988(vi00) | nop
lq.xyzw vf26, 989(vi00) | nop
lq.xyzw vf27, 990(vi00) | nop
lq.xyzw vf30, 996(vi00) | nop
lq.xyzw vf31, 997(vi00) | nop
lq.xyzw vf28, 1002(vi00) | nop
lq.xyzw vf29, 1003(vi00) | nop
nop | nop :e
nop | nop
regs:
vi02 = input ptr
vi03 = num_sprites
vi04 = adgif ptr
vi05 = output buffer (double buffered, so toggles)
vf25 = hvdf
vf26 = hmge
vf27 = consts
vf30 = basis_x
vf31 = basis_y
vf28 = clamp_min
vf29 = clamp_max
DRAW program
xtop vi02 | nop ;; vi02 = input buffer's control
nop | nop
ilwr.x vi03, vi02 | nop ;; vi03 = num_sprites (1 always?)
iaddi vi02, vi02, 0x1 | nop ;; vi02 = sprite data
iaddiu vi04, vi02, 0x90 | nop ;; vi04 = adgif data
L1:
lq.xyzw vf03, 2(vi02) | nop ;; vf03 = color
lq.xyzw vf02, 1(vi02) | nop ;; vf02 = [size_probe, z_offset, rot-angle, size-y]
lq.xyzw vf01, 0(vi02) | nop ;; vf01 = [position.xyz, size-x]
lq.xyzw vf24, 983(vi00) | nop ;; vf24 = [camera_mat[3]]
lq.xyzw vf21, 980(vi00) | nop ;; vf21 = [camera_mat[0]]
lq.xyzw vf22, 981(vi00) | nop ;; vf22 = [camera_mat[1]]
lq.xyzw vf23, 982(vi00) | nop ;; vf23 = [camera_mat[2]]
lq.xyzw vf04, 3(vi02) | mulaw.xyz ACC, vf24, vf00 ;; vf04 = [fade_a, fade_b, X, X] | multiply
lq.xyzw vf24, 987(vi00) | maddax.xyz ACC, vf21, vf01 ;; vf24 = [perspective[3]] | multiply
lq.xyzw vf21, 984(vi00) | madday.xyz ACC, vf22, vf01 ;; vf21 = [perspective[0]] | multiply
lq.xyzw vf22, 985(vi00) | maddz.xyz vf01, vf23, vf01 ;; vf22 = [perspective[1]] | multiply
lq.xyzw vf23, 986(vi00) | nop ;; vf23 = [perspective[2]]
lq.xyzw vf09, 0(vi04) | nop ;; vf09 = adgif[0]
lq.xyzw vf10, 1(vi04) | mulw.xyz vf03, vf03, vf03 ;; vf10 = adgif[1] | color multiply by alpha
div Q, vf02.y, vf01.z | mulz.x vf04, vf04, vf01 ;; Q = (z_offset / p0.z) | fade_a *= p0.z
lq.xyzw vf11, 2(vi04) | nop ;; vf11 = adgif[2]
0.0078125 | nop :i ;; I = 0.0078125 (= 1/128)
lq.xyzw vf12, 3(vi04) | nop ;; vf12 = adgif[3]
lq.xyzw vf13, 4(vi04) | addy.x vf04, vf04, vf04 ;; vf13 = adgif[4] | fade_a += fade_b
sq.xyzw vf09, 68(vi05) | muly.z vf05, vf02, vf27 ;; adgif0 store | vf05.z = rot-angle * deg_to_rad
move.w vf05, vf00 | addw.z vf02, vf00, vf01 ;; vf05.w = 1 | vf02.z = size-x
sq.xyzw vf10, 69(vi05) | mul.w vf09, vf00, Q ;; agdif1 store | vf09.w = (z_offset / p0.z)
sq.xyzw vf11, 70(vi05) | nop ;; adgif2 store
sq.xyzw vf12, 71(vi05) | miniw.x vf04, vf04, vf00 ;; adgif3 store | clamp fade 1
sq.xyzw vf13, 72(vi05) | nop ;; adgif4 store
nop | subw.w vf09, vf00, vf09 ;; vf09.w = 1 - (z_offset / p0.z);
nop | maxx.x vf04, vf04, vf00 ;; clamp fade 2
nop | mulw.xyz vf01, vf01, vf09 ;; multiply by pscale
nop | mulx.xyz vf03, vf03, vf04 ;; multiply color by fade
nop | mulaw.xyzw ACC, vf24, vf00 ;; multiply by perspective matrix
nop | maddax.xyzw ACC, vf21, vf01
nop | madday.xyzw ACC, vf22, vf01
nop | muli.xyz vf03, vf03, I ;; color scaling.
nop | maddz.xyzw vf01, vf23, vf01 ;; perspective matrix.
nop | nop
iaddi vi03, vi03, -0x1 | mulz.z vf06, vf05, vf05 ;; dec sprite count | vf06 = rot^2
lq.xyzw vf15, 991(vi00) | nop ;; vf15 = sincos01
iaddi vi02, vi02, 0x3 | nop ;; inc input pointer... by the wrong amount lol
fcset 0x0 | mul.xyzw vf07, vf01, vf26 ;; hmge mult
nop | mulz.zw vf09, vf05, vf06 ;; vf09 = rot^3
lq.xyzw vf15, 992(vi00) | mula.zw ACC, vf05, vf15 ;; vf15 = sincos23 | acc working on sincos.
nop | nop
div Q, vf00.w, vf07.w | clipw.xyz vf07, vf07 ;; Q = 1 / p_hmged.w | clip!!!
nop | mulz.zw vf10, vf09, vf06 ;; vf10 is rot thing
lq.xyzw vf15, 993(vi00) | madda.zw ACC, vf09, vf15 ;; vf15 is rot coeff, working on sincos
nop | nop
fcand vi01, 0x3f | nop ;; check clipping result
ibne vi00, vi01, L2 | mulz.zw vf09, vf10, vf06 ;; skip if clipped | working on rot
lq.xyzw vf15, 994(vi00) | madda.zw ACC, vf10, vf15 ;; rot | rot
nop | mul.xyz vf01, vf01, Q ;; perspective multiply
nop | mul.xyzw vf02, vf02, Q ;; vf02 *= q
nop | mulz.zw vf10, vf09, vf06 ;; rot
lq.xyzw vf15, 995(vi00) | madda.zw ACC, vf09, vf15 ;; rot89 | rot
nop | add.xyzw vf01, vf01, vf25 ;; hvdf offset
nop | maxw.x vf02, vf02, vf00 ;; clip size_probe to 1
nop | miniw.x vf02, vf02, vf29 ;; min size_probe against clamp max.w
nop | miniz.zw vf02, vf02, vf29 ;; min zw against clamp max.z
nop | madd.zw vf05, vf10, vf15 ;; vf05 = sincos output
nop | ftoi0.xyzw vf03, vf03 ;; colors to ints or whatever
nop | addx.xy vf09, vf28, vf02 ;; vf09 = [cmin.x + probe_size, cmin.y + probe_size]
nop | subx.xy vf11, vf01, vf02 ;; vf11 = probe lower corner = [p0.xy - probe_size]
nop | addx.xy vf12, vf01, vf02 ;; vf12 = probe upper corner = [po.xy + probe_size]
nop | subx.xy vf10, vf29, vf02 ;; vf10 = [cmax.x - probe_size, cmax.y - probe_size]
nop | mulaz.xyzw ACC, vf30, vf05
nop | msubw.xyzw vf15, vf31, vf05 ;; rotate the basis
nop | max.xy vf20, vf01, vf09 ;; vf20 is some clamped position.
nop | addx.zw vf11, vf01, vf00 ;; vf11.zw = vf01.zw
nop | addx.zw vf12, vf01, vf00 ;; vf12.zw = vf01.zw
nop | subw.xy vf17, vf28, vf00 ;; vf17 = [clamp_min.x - 1, clamp_min.y - 1]
nop | mulz.xyzw vf15, vf15, vf02 ;; rot_basis *= vf02.z (x-scale)
nop | addw.xy vf18, vf28, vf00 ;; vf18 = [calm_min.x + 1, clamp_min.y + 1]
nop | ftoi4.xyzw vf11, vf11 ;; usual ftoi4 of clear positions
nop | ftoi4.xyzw vf12, vf12
nop | mini.xy vf20, vf20, vf10 ;; vf20 clamp again.
nop | mulaw.xyzw ACC, vf30, vf05
sq.xyzw vf03, 75(vi05) | maddz.xyzw vf16, vf31, vf05 ;; store color of flare | second row of rotation matrix
sq.xyz vf11, 11(vi05) | sub.xy vf17, vf20, vf17 ;; store clear pos | offset vf17
sq.xyz vf12, 12(vi05) | sub.xy vf18, vf20, vf18 ;; store clear pos | offset vf18
lq.xyzw vf11, 998(vi00) | subx.xy vf19, vf20, vf02 ;; compute first clear pos,
lq.xyzw vf12, 999(vi00) | mulw.xyzw vf16, vf16, vf02 ;; y scale
lq.xyzw vf13, 1000(vi00) | addx.xy vf20, vf20, vf02 ;; first clear pos, upper corner.
lq.xyzw vf14, 1001(vi00) | mulaw.xyzw ACC, vf01, vf00
nop | maddax.xyzw ACC, vf15, vf11
nop | maddy.xyzw vf11, vf16, vf11
nop | mulaw.xyzw ACC, vf01, vf00
nop | maddax.xyzw ACC, vf15, vf12
nop | maddy.xyzw vf12, vf16, vf12
nop | mulaw.xyzw ACC, vf01, vf00
nop | maddax.xyzw ACC, vf15, vf13
nop | maddy.xyzw vf13, vf16, vf13
nop | mulaw.xyzw ACC, vf01, vf00
nop | maddax.xyzw ACC, vf15, vf14
nop | maddy.xyzw vf14, vf16, vf14
nop | subx.xy vf17, vf17, vf02
nop | addx.xy vf18, vf18, vf02
iaddiu vi04, vi04, 0x50 | subw.xy vf19, vf19, vf00 ;; offset first clear pos lower
nop | addw.xy vf20, vf20, vf00 ;; offset first clear pos upper
nop | ftoi4.xyzw vf11, vf11
nop | ftoi4.xyzw vf12, vf12
nop | ftoi4.xyzw vf13, vf13
nop | ftoi4.xyzw vf14, vf14
sq.xy vf11, 61(vi05) | ftoi4.xyzw vf17, vf17
sq.xy vf12, 62(vi05) | ftoi4.xyzw vf18, vf18
sq.xy vf13, 63(vi05) | ftoi4.xyzw vf19, vf19
sq.xy vf14, 64(vi05) | ftoi4.xyzw vf20, vf20
sq.xy vf17, 24(vi05) | nop
sq.xy vf18, 26(vi05) | nop
sq.xy vf19, 8(vi05) | nop
sq.xy vf20, 9(vi05) | nop
sq.xy vf11, 77(vi05) | nop
sq.xy vf12, 79(vi05) | nop
sq.xy vf13, 81(vi05) | nop
sq.xy vf14, 83(vi05) | nop
xgkick vi05 | nop
L2:
iaddiu vi01, vi00, 0x694 | nop
ibne vi00, vi03, L1 | nop
isub vi05, vi01, vi05 | nop
nop | nop :e
nop | nop
```

View File

@ -132,6 +132,11 @@ set(RUNTIME_SOURCE
graphics/opengl_renderer/foreground/Generic2_DMA.cpp
graphics/opengl_renderer/foreground/Generic2_Build.cpp
graphics/opengl_renderer/foreground/Generic2_OpenGL.cpp
graphics/opengl_renderer/sprite/GlowRenderer.cpp
graphics/opengl_renderer/sprite/Sprite3.cpp
graphics/opengl_renderer/sprite/Sprite3_Distort.cpp
graphics/opengl_renderer/sprite/Sprite3_Glow.cpp
graphics/opengl_renderer/sprite/SpriteRenderer.cpp
graphics/opengl_renderer/ocean/CommonOceanRenderer.cpp
graphics/opengl_renderer/ocean/OceanMid.cpp
graphics/opengl_renderer/ocean/OceanMid_PS2.cpp
@ -159,8 +164,6 @@ set(RUNTIME_SOURCE
graphics/opengl_renderer/SkyBlendCPU.cpp
graphics/opengl_renderer/SkyBlendGPU.cpp
graphics/opengl_renderer/SkyRenderer.cpp
graphics/opengl_renderer/Sprite3.cpp
graphics/opengl_renderer/SpriteRenderer.cpp
graphics/opengl_renderer/TextureUploadHandler.cpp
graphics/opengl_renderer/VisDataHandler.cpp
graphics/opengl_renderer/DepthCue.cpp

View File

@ -9,8 +9,6 @@
#include "game/graphics/opengl_renderer/LightningRenderer.h"
#include "game/graphics/opengl_renderer/ShadowRenderer.h"
#include "game/graphics/opengl_renderer/SkyRenderer.h"
#include "game/graphics/opengl_renderer/Sprite3.h"
#include "game/graphics/opengl_renderer/SpriteRenderer.h"
#include "game/graphics/opengl_renderer/TextureUploadHandler.h"
#include "game/graphics/opengl_renderer/VisDataHandler.h"
#include "game/graphics/opengl_renderer/background/Shrub.h"
@ -20,6 +18,8 @@
#include "game/graphics/opengl_renderer/foreground/Merc2.h"
#include "game/graphics/opengl_renderer/ocean/OceanMidAndFar.h"
#include "game/graphics/opengl_renderer/ocean/OceanNear.h"
#include "game/graphics/opengl_renderer/sprite/Sprite3.h"
#include "game/graphics/opengl_renderer/sprite/SpriteRenderer.h"
#include "game/graphics/pipelines/opengl.h"
#include "third-party/imgui/imgui.h"

View File

@ -95,6 +95,11 @@ ShaderLibrary::ShaderLibrary(GameVersion version) {
at(ShaderId::POST_PROCESSING) = {"post_processing", version};
at(ShaderId::DEPTH_CUE) = {"depth_cue", version};
at(ShaderId::EMERC) = {"emerc", version};
at(ShaderId::GLOW_PROBE) = {"glow_probe", version};
at(ShaderId::GLOW_PROBE_READ) = {"glow_probe_read", version};
at(ShaderId::GLOW_PROBE_READ_DEBUG) = {"glow_probe_read_debug", version};
at(ShaderId::GLOW_PROBE_DOWNSAMPLE) = {"glow_probe_downsample", version};
at(ShaderId::GLOW_DRAW) = {"glow_draw", version};
for (auto& shader : m_shaders) {
ASSERT_MSG(shader.okay(), "error compiling shader");

View File

@ -48,6 +48,11 @@ enum class ShaderId {
POST_PROCESSING = 22,
DEPTH_CUE = 23,
EMERC = 24,
GLOW_PROBE = 25,
GLOW_PROBE_READ = 26,
GLOW_PROBE_READ_DEBUG = 27,
GLOW_PROBE_DOWNSAMPLE = 28,
GLOW_DRAW = 29,
MAX_SHADERS
};

View File

@ -0,0 +1,16 @@
#version 430 core
out vec4 color;
in vec4 fragment_color;
in float discard_flag;
in vec2 uv_texture;
layout (binding = 0) uniform sampler2D tex;
void main() {
vec4 texture_color = texture(tex, uv_texture);
color.xyz = texture_color.xyz * fragment_color.xyz * 2.f * discard_flag / 128.f;
color.w = fragment_color.w * texture_color.w;
}

View File

@ -0,0 +1,31 @@
#version 430 core
layout (location = 0) in vec4 position_in;
layout (location = 1) in vec4 rgba_in;
layout (location = 2) in vec2 uv_texture_in;
layout (location = 3) in vec2 uv_probe_in;
out vec4 fragment_color;
out vec2 uv_texture;
out float discard_flag;
const float SCISSOR_ADJUST = HEIGHT_SCALE * 512.0/448.0;
layout (binding = 1) uniform sampler2D probe_tex;
void main() {
vec4 transformed = position_in;
transformed.xy -= (2048.);
transformed.z /= (8388608);
transformed.z -= 1;
transformed.x /= (256);
transformed.y /= -(128);
transformed.xyz *= transformed.w;
// scissoring area adjust
transformed.y *= SCISSOR_ADJUST;
gl_Position = transformed;
fragment_color = rgba_in;
uv_texture = uv_texture_in;
discard_flag = texture(probe_tex, uv_probe_in).a;
}

View File

@ -0,0 +1,10 @@
#version 430 core
out vec4 color;
in vec4 fragment_color;
void main() {
color = fragment_color;
}

View File

@ -0,0 +1,23 @@
#version 430 core
layout (location = 0) in vec4 position_in;
layout (location = 1) in vec4 rgba_in;
out vec4 fragment_color;
const float SCISSOR_ADJUST = HEIGHT_SCALE * 512.0/448.0;
void main() {
vec4 transformed = position_in;
transformed.xy -= (2048.);
transformed.z /= (8388608);
transformed.z -= 1;
transformed.x /= (256);
transformed.y /= -(128);
transformed.xyz *= transformed.w;
// scissoring area adjust
transformed.y *= SCISSOR_ADJUST;
gl_Position = transformed;
fragment_color = rgba_in;
}

View File

@ -0,0 +1,13 @@
#version 430 core
out vec4 out_color;
uniform sampler2D tex;
in flat vec4 fragment_color;
in vec2 tex_coord;
void main() {
vec2 texture_coords = vec2(tex_coord.x, tex_coord.y);
// sample framebuffer texture
out_color = texture(tex, texture_coords);
}

View File

@ -0,0 +1,10 @@
#version 430 core
layout (location = 0) in vec4 position_in;
out vec2 tex_coord;
void main() {
gl_Position = vec4((position_in.xy * 2) - 1.f, 0.f, 1.f);
tex_coord = position_in.xy;
}

View File

@ -0,0 +1,14 @@
#version 430 core
out vec4 out_color;
uniform sampler2D tex;
in vec2 tex_coord;
void main() {
vec2 texture_coords = vec2(tex_coord.x, tex_coord.y);
// sample framebuffer texture
out_color = texture(tex, texture_coords);
}

View File

@ -0,0 +1,13 @@
#version 430 core
layout (location = 0) in vec4 position_in;
layout (location = 1) in vec4 rgba_in;
layout (location = 2) in vec2 uv;
out vec2 tex_coord;
void main() {
gl_Position = vec4((position_in.xy * 2) - 1.f, 0.f, 1.f);
tex_coord.x = uv.x / 512;
tex_coord.y = 1.f - ((uv.y + 16) / 448);
}

View File

@ -0,0 +1,7 @@
#version 430 core
out vec4 out_color;
void main() {
out_color = vec4(0, 0.5, 1, 1);
}

View File

@ -0,0 +1,11 @@
#version 430 core
layout (location = 0) in vec4 position_in;
layout (location = 1) in vec4 rgba_in;
layout (location = 2) in vec2 uv;
void main() {
float x = (uv.x / 512) * 2 - 1;
float y = -(((uv.y + 16) / 448) * 2 - 1);
gl_Position = vec4(x, y, 0, 1.f);
}

View File

@ -0,0 +1,737 @@
#include "GlowRenderer.h"
#include "third-party/imgui/imgui.h"
/*
* The glow renderer draws a sprite, but only if the center of the sprite is "visible".
* To determine visibility, we draw a test "probe" at the center of the sprite and see how many
* pixels of the probe were visible.
*
* The inputs to this renderer are the transformed vertices that would be computed on VU1.
* The convention is that float -> int conversions and scalings are dropped.
*
* To detect if this is visible, we do something a little different from the original game:
* - first copy the depth buffer to a separate texture. It seems like we could eliminate this copy
* eventually and always render to a texture.
*
* - For each sprite draw a "test probe" using this depth buffer. Write to a separate texture.
* This test probe is pretty small. First clear alpha to 0, then draw a test image with alpha = 1
* and depth testing on.
*
* - Repeatedly sample the result of the probe as a texture and draw it to another texture with half
* the size. This effectively averages the alpha values with texture filtering.
*
* - Stop once we've reached 2x2. At this point we can sample the center of this "texture" and the
* alpha will indicate the fraction of pixels in the original probe that passed depth. Use this
* to scale the intensity of the actual sprite draw.
*
* There are a number of optimizations made at this point:
* - Probe clear/drawing are batched.
* - Instead of doing the "downsampling" one-at-a-time, all probes are copied to a big grid and
* the downsampling happens in batches.
* - The sampling of the final downsampled texture happens inside the vertex shader. On PS2, it's
* used as a texture, drawn as alpha-only over the entire region, then blended with the final
* draw. But the alpha of the entire first draw is constant, and we can figure it out in the
* vertex shader, so there's no need to do this approach.
*
* there are a few remaining improvements that could be made:
* - The final draws could be bucketed, this would reduce draw calls by a lot.
* - The depth buffer copy could likely be eliminated.
* - There's a possibility that overlapping probes do the "wrong" thing. This could be solved by
* copying from the depth buffer to the grid, then drawing probes on the grid. Currently the
* probes are drawn aligned with the framebuffer, then copied back to the grid. This approach
* would also lower the vram needed.
*/
GlowRenderer::GlowRenderer() {
m_vertex_buffer.resize(kMaxVertices);
m_sprite_data_buffer.resize(kMaxSprites);
m_index_buffer.resize(kMaxIndices);
// dynamic buffer: this will hold vertices that are generated by the game and updated each frame.
// the most important optimization here is to have as few uploads as possible. The size of the
// upload isn't too important - we only have at most 256 sprites so the overhead of uploading
// anything dominates. So we use a single vertex format for all of our draws.
{
glGenBuffers(1, &m_ogl.vertex_buffer);
glGenVertexArrays(1, &m_ogl.vao);
glBindVertexArray(m_ogl.vao);
glBindBuffer(GL_ARRAY_BUFFER, m_ogl.vertex_buffer);
auto bytes = kMaxVertices * sizeof(Vertex);
glBufferData(GL_ARRAY_BUFFER, bytes, nullptr, GL_STREAM_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, // location 0 in the shader
4, // 4 floats per vert
GL_FLOAT, // floats
GL_TRUE, // normalized, ignored,
sizeof(Vertex), //
(void*)offsetof(Vertex, x) // offset in array
);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, // location 1 in the shader
4, // 4 color components
GL_FLOAT, // floats
GL_TRUE, // normalized, ignored,
sizeof(Vertex), //
(void*)offsetof(Vertex, r) // offset in array
);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, // location 2 in the shader
2, // 2 uv
GL_FLOAT, // floats
GL_TRUE, // normalized, ignored,
sizeof(Vertex), //
(void*)offsetof(Vertex, u) // offset in array (why is this a pointer...)
);
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, // location 2 in the shader
2, // 2 uv
GL_FLOAT, // floats
GL_TRUE, // normalized, ignored,
sizeof(Vertex), //
(void*)offsetof(Vertex, uu) // offset in array (why is this a pointer...)
);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glGenBuffers(1, &m_ogl.index_buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ogl.index_buffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, kMaxIndices * sizeof(u32), nullptr, GL_STREAM_DRAW);
glBindVertexArray(0);
}
// static buffer: this will hold draws for downsampling. Because everything is normalized, we can
// reuse the same vertices for all downsampling!
// Note that we can't do a single giant square - otherwise it would "bleed" over the edges.
// the boundary between cells needs to be preserved.
{
glGenBuffers(1, &m_ogl_downsampler.vertex_buffer);
glGenVertexArrays(1, &m_ogl_downsampler.vao);
glBindVertexArray(m_ogl_downsampler.vao);
glBindBuffer(GL_ARRAY_BUFFER, m_ogl_downsampler.vertex_buffer);
std::vector<Vertex> vertices;
std::vector<u32> indices;
vertices.resize(kMaxSprites * 4);
indices.resize(kMaxSprites * 5);
for (int i = 0; i < kMaxSprites; i++) {
int x = i / kDownsampleBatchWidth;
int y = i % kDownsampleBatchWidth;
float step = 1.f / kDownsampleBatchWidth;
Vertex* vtx = &vertices.at(i * 4);
for (int j = 0; j < 4; j++) {
vtx[j].r = 0.f; // debug
vtx[j].g = 0.f;
vtx[j].b = 0.f;
vtx[j].a = 0.f;
vtx[j].x = x * step;
vtx[j].y = y * step;
vtx[j].z = 0;
vtx[j].w = 0;
}
vtx[1].x += step;
vtx[2].y += step;
vtx[3].x += step;
vtx[3].y += step;
indices.at(i * 5 + 0) = i * 4;
indices.at(i * 5 + 1) = i * 4 + 1;
indices.at(i * 5 + 2) = i * 4 + 2;
indices.at(i * 5 + 3) = i * 4 + 3;
indices.at(i * 5 + 4) = UINT32_MAX;
}
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), vertices.data(),
GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, // location 0 in the shader
4, // 4 floats per vert
GL_FLOAT, // floats
GL_TRUE, // normalized, ignored,
sizeof(Vertex), //
(void*)offsetof(Vertex, x) // offset in array
);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, // location 1 in the shader
4, // 4 color components
GL_FLOAT, // floats
GL_TRUE, // normalized, ignored,
sizeof(Vertex), //
(void*)offsetof(Vertex, r) // offset in array
);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, // location 2 in the shader
3, // 4 color components
GL_FLOAT, // floats
GL_TRUE, // normalized, ignored,
sizeof(Vertex), //
(void*)offsetof(Vertex, u) // offset in array (why is this a pointer...)
);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glGenBuffers(1, &m_ogl_downsampler.index_buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ogl_downsampler.index_buffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(u32), indices.data(),
GL_STATIC_DRAW);
glBindVertexArray(0);
}
// probe fbo setup: this fbo will hold the result of drawing probes.
glGenFramebuffers(1, &m_ogl.probe_fbo);
glBindFramebuffer(GL_FRAMEBUFFER, m_ogl.probe_fbo);
glGenTextures(1, &m_ogl.probe_fbo_rgba_tex);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_ogl.probe_fbo_rgba_tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_ogl.probe_fbo_w, m_ogl.probe_fbo_h, 0, GL_RGBA,
GL_UNSIGNED_BYTE, nullptr);
glGenRenderbuffers(1, &m_ogl.probe_fbo_zbuf_rb);
glBindRenderbuffer(GL_RENDERBUFFER, m_ogl.probe_fbo_zbuf_rb);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, m_ogl.probe_fbo_w,
m_ogl.probe_fbo_h);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER,
m_ogl.probe_fbo_zbuf_rb);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
m_ogl.probe_fbo_rgba_tex, 0);
GLenum render_targets[1] = {GL_COLOR_ATTACHMENT0};
glDrawBuffers(1, render_targets);
auto status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
ASSERT(status == GL_FRAMEBUFFER_COMPLETE);
// downsample fbo setup: each will hold a grid of probes.
// there's one fbo for each size.
int ds_size = kFirstDownsampleSize;
for (int i = 0; i < kDownsampleIterations; i++) {
m_ogl.downsample_fbos[i].size = ds_size * kDownsampleBatchWidth;
glGenFramebuffers(1, &m_ogl.downsample_fbos[i].fbo);
glBindFramebuffer(GL_FRAMEBUFFER, m_ogl.downsample_fbos[i].fbo);
glGenTextures(1, &m_ogl.downsample_fbos[i].tex);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_ogl.downsample_fbos[i].tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, ds_size * kDownsampleBatchWidth,
ds_size * kDownsampleBatchWidth, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
m_ogl.downsample_fbos[i].tex, 0);
glDrawBuffers(1, render_targets);
status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
ASSERT(status == GL_FRAMEBUFFER_COMPLETE);
ds_size /= 2;
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// set up a default draw mode for sprites. If they don't set values, they will get this
// from the giftag
m_default_draw_mode.set_ab(true);
// ;; (new 'static 'gs-test :ate 1 :afail 1 :zte 1 :ztst 2)
// (new 'static 'gs-adcmd :cmds (gs-reg64 test-1) :x #x51001)
m_default_draw_mode.set_at(true);
m_default_draw_mode.set_alpha_fail(GsTest::AlphaFail::FB_ONLY);
m_default_draw_mode.set_zt(true);
m_default_draw_mode.set_depth_test(GsTest::ZTest::GEQUAL);
m_default_draw_mode.set_alpha_test(DrawMode::AlphaTest::NEVER);
// ;; (new 'static 'gs-zbuf :zbp 304 :psm 1 :zmsk 1)
// (new 'static 'gs-adcmd :cmds (gs-reg64 zbuf-1) :x #x1000130 :y #x1)
m_default_draw_mode.disable_depth_write();
}
namespace {
void copy_to_vertex(GlowRenderer::Vertex* vtx, const Vector4f& xyzw) {
vtx->x = xyzw.x();
vtx->y = xyzw.y();
vtx->z = xyzw.z();
vtx->w = xyzw.w();
}
} // namespace
SpriteGlowOutput* GlowRenderer::alloc_sprite() {
ASSERT(m_next_sprite < m_sprite_data_buffer.size());
return &m_sprite_data_buffer[m_next_sprite++];
}
void GlowRenderer::cancel_sprite() {
ASSERT(m_next_sprite);
m_next_sprite--;
}
// vertex addition is done in passes, so the "pass1" for all sprites is before any "pass2" vertices.
// But, we still do a single big upload for all passes.
// this way pass1 can be a single giant draw.
/*!
* Add pass 1 vertices, for drawing the probe.
*/
void GlowRenderer::add_sprite_pass_1(const SpriteGlowOutput& data) {
{ // first draw is a GS sprite to clear the alpha. This is faster than glClear, and the game
// computes these for us and gives it a large z that always passes.
// We need to convert to triangle strip.
u32 idx_start = m_next_vertex;
Vertex* vtx = alloc_vtx(4);
for (int i = 0; i < 4; i++) {
vtx[i].r = 1.f; // red for debug
vtx[i].g = 0.f;
vtx[i].b = 0.f;
vtx[i].a = 0.f; // clearing alpha
}
copy_to_vertex(vtx, data.first_clear_pos[0]);
copy_to_vertex(vtx + 1, data.first_clear_pos[0]);
vtx[1].x = data.first_clear_pos[1].x();
copy_to_vertex(vtx + 2, data.first_clear_pos[0]);
vtx[2].y = data.first_clear_pos[1].y();
copy_to_vertex(vtx + 3, data.first_clear_pos[1]);
u32* idx = alloc_index(5);
idx[0] = idx_start;
idx[1] = idx_start + 1;
idx[2] = idx_start + 2;
idx[3] = idx_start + 3;
idx[4] = UINT32_MAX;
}
{ // second draw is the actual probe, using the real Z, and setting alpha to 1.
u32 idx_start = m_next_vertex;
Vertex* vtx = alloc_vtx(4);
for (int i = 0; i < 4; i++) {
vtx[i].r = 0.f;
vtx[i].g = 1.f; // green for debug
vtx[i].b = 0.f;
vtx[i].a = 1.f; // setting alpha
}
copy_to_vertex(vtx, data.second_clear_pos[0]);
copy_to_vertex(vtx + 1, data.second_clear_pos[0]);
vtx[1].x = data.second_clear_pos[1].x();
copy_to_vertex(vtx + 2, data.second_clear_pos[0]);
vtx[2].y = data.second_clear_pos[1].y();
copy_to_vertex(vtx + 3, data.second_clear_pos[1]);
u32* idx = alloc_index(5);
idx[0] = idx_start;
idx[1] = idx_start + 1;
idx[2] = idx_start + 2;
idx[3] = idx_start + 3;
idx[4] = UINT32_MAX;
}
}
/*!
* Add pass 2 vertices, for copying from the probe fbo to the biggest grid.
*/
void GlowRenderer::add_sprite_pass_2(const SpriteGlowOutput& data, int sprite_idx) {
// output is a grid of kBatchWidth * kBatchWidth.
// for simplicity, we'll map to (0, 1) here, and the shader will convert to (-1, 1) for opengl.
int x = sprite_idx / kDownsampleBatchWidth;
int y = sprite_idx % kDownsampleBatchWidth;
float step = 1.f / kDownsampleBatchWidth;
u32 idx_start = m_next_vertex;
Vertex* vtx = alloc_vtx(4);
for (int i = 0; i < 4; i++) {
vtx[i].r = 1.f; // debug
vtx[i].g = 0.f;
vtx[i].b = 0.f;
vtx[i].a = 0.f;
vtx[i].x = x * step; // start of our cell
vtx[i].y = y * step;
vtx[i].z = 0;
vtx[i].w = 0;
}
vtx[1].x += step;
vtx[2].y += step;
vtx[3].x += step;
vtx[3].y += step;
// transformation code gives us these coordinates for where to sample probe fbo
vtx[0].u = data.offscreen_uv[0][0];
vtx[0].v = data.offscreen_uv[0][1];
vtx[1].u = data.offscreen_uv[1][0];
vtx[1].v = data.offscreen_uv[0][1];
vtx[2].u = data.offscreen_uv[0][0];
vtx[2].v = data.offscreen_uv[1][1];
vtx[3].u = data.offscreen_uv[1][0];
vtx[3].v = data.offscreen_uv[1][1];
u32* idx = alloc_index(5);
idx[0] = idx_start;
idx[1] = idx_start + 1;
idx[2] = idx_start + 2;
idx[3] = idx_start + 3;
idx[4] = UINT32_MAX;
}
/*!
* Add pass 3 vertices and update sprite records. This is the final draw.
*/
void GlowRenderer::add_sprite_pass_3(const SpriteGlowOutput& data, int sprite_idx) {
// figure out our cell, we'll need to read from this to see if we're visible or not.
int x = sprite_idx / kDownsampleBatchWidth;
int y = sprite_idx % kDownsampleBatchWidth;
float step = 1.f / kDownsampleBatchWidth;
u32 idx_start = m_next_vertex;
Vertex* vtx = alloc_vtx(4);
for (int i = 0; i < 4; i++) {
// include the color, used by the shader
vtx[i].r = data.flare_draw_color[0];
vtx[i].g = data.flare_draw_color[1];
vtx[i].b = data.flare_draw_color[2];
vtx[i].a = data.flare_draw_color[3];
copy_to_vertex(&vtx[i], data.flare_xyzw[i]);
vtx[i].u = 0;
vtx[i].v = 0;
// where to sample from to see probe result
// offset by step/2 to sample the middle.
// we use 2x2 for the final resolution and sample the middle - should be the same as
// going to a 1x1, but saves a draw.
vtx[i].uu = x * step + step / 2;
vtx[i].vv = y * step + step / 2;
}
// texture uv's hardcoded to corners
vtx[1].u = 1;
vtx[3].v = 1;
vtx[2].u = 1;
vtx[2].v = 1;
// get a record
auto& record = m_sprite_records[sprite_idx];
record.draw_mode = m_default_draw_mode;
record.tbp = 0;
record.idx = m_next_index;
u32* idx = alloc_index(5);
// flip first two - fan -> strip
idx[0] = idx_start + 1;
idx[1] = idx_start + 0;
idx[2] = idx_start + 2;
idx[3] = idx_start + 3;
idx[4] = UINT32_MAX;
// handle adgif stuff
{
ASSERT(data.adgif.tex0_addr == (u32)GsRegisterAddress::TEX0_1);
GsTex0 reg(data.adgif.tex0_data);
record.tbp = reg.tbp0();
record.draw_mode.set_tcc(reg.tcc());
// shader is hardcoded for this right now.
ASSERT(reg.tcc() == 1);
ASSERT(reg.tfx() == GsTex0::TextureFunction::MODULATE);
}
{
ASSERT((u8)data.adgif.tex1_addr == (u8)GsRegisterAddress::TEX1_1);
GsTex1 reg(data.adgif.tex1_data);
record.draw_mode.set_filt_enable(reg.mmag());
}
{
ASSERT(data.adgif.mip_addr == (u32)GsRegisterAddress::MIPTBP1_1);
// ignore
}
// clamp or zbuf
if (GsRegisterAddress(data.adgif.clamp_addr) == GsRegisterAddress::ZBUF_1) {
GsZbuf x(data.adgif.clamp_data);
record.draw_mode.set_depth_write_enable(!x.zmsk());
} else if (GsRegisterAddress(data.adgif.clamp_addr) == GsRegisterAddress::CLAMP_1) {
u32 val = data.adgif.clamp_data;
if (!(val == 0b101 || val == 0 || val == 1 || val == 0b100)) {
ASSERT_MSG(false, fmt::format("clamp: 0x{:x}", val));
}
record.draw_mode.set_clamp_s_enable(val & 0b001);
record.draw_mode.set_clamp_t_enable(val & 0b100);
} else {
ASSERT(false);
}
// alpha
ASSERT(data.adgif.alpha_addr == (u32)GsRegisterAddress::ALPHA_1); // ??
// ;; a = 0, b = 2, c = 1, d = 1
// Cv = (Cs - 0) * Ad + D
// leaving out the multiply by Ad.
record.draw_mode.set_alpha_blend(DrawMode::AlphaBlend::SRC_0_FIX_DST);
}
/*!
* Blit the depth buffer from the default rendering buffer to the depth buffer of the probe fbo.
*/
void GlowRenderer::blit_depth(SharedRenderState* render_state) {
if (m_ogl.probe_fbo_w != render_state->render_fb_w ||
m_ogl.probe_fbo_h != render_state->render_fb_h) {
m_ogl.probe_fbo_w = render_state->render_fb_w;
m_ogl.probe_fbo_h = render_state->render_fb_h;
glBindTexture(GL_TEXTURE_2D, m_ogl.probe_fbo_rgba_tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_ogl.probe_fbo_w, m_ogl.probe_fbo_h, 0, GL_RGBA,
GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_2D, 0);
glBindRenderbuffer(GL_RENDERBUFFER, m_ogl.probe_fbo_zbuf_rb);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, m_ogl.probe_fbo_w,
m_ogl.probe_fbo_h);
}
glBindFramebuffer(GL_READ_FRAMEBUFFER, render_state->render_fb);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_ogl.probe_fbo);
glBlitFramebuffer(render_state->render_fb_x, // srcX0
render_state->render_fb_y, // srcY0
render_state->render_fb_x + render_state->render_fb_w, // srcX1
render_state->render_fb_y + render_state->render_fb_h, // srcY1
0, // dstX0
0, // dstY0
m_ogl.probe_fbo_w, // dstX1
m_ogl.probe_fbo_h, // dstY1
GL_DEPTH_BUFFER_BIT, // mask
GL_NEAREST // filter
);
}
void GlowRenderer::draw_debug_window() {
ImGui::Checkbox("Show Probes", &m_debug.show_probes);
ImGui::Checkbox("Show Copy", &m_debug.show_probe_copies);
ImGui::Text("Count: %d", m_debug.num_sprites);
}
/*!
* Do all downsample draws to make 2x2 textures.
*/
void GlowRenderer::downsample_chain(SharedRenderState* render_state,
ScopedProfilerNode& prof,
u32 num_sprites) {
glBindVertexArray(m_ogl_downsampler.vao);
glEnable(GL_PRIMITIVE_RESTART);
glPrimitiveRestartIndex(UINT32_MAX);
render_state->shaders[ShaderId::GLOW_PROBE_DOWNSAMPLE].activate();
for (int i = 0; i < kDownsampleIterations - 1; i++) {
auto* source = &m_ogl.downsample_fbos[i];
auto* dest = &m_ogl.downsample_fbos[i + 1];
glBindTexture(GL_TEXTURE_2D, source->tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindFramebuffer(GL_FRAMEBUFFER, dest->fbo);
glViewport(0, 0, dest->size, dest->size);
prof.add_draw_call();
prof.add_tri(num_sprites * 4);
// the grid fill order is the same as the downsample order, so we don't need to do all cells
// if we aren't using all sprites.
glDrawElements(GL_TRIANGLE_STRIP, num_sprites * 5, GL_UNSIGNED_INT, nullptr);
}
glViewport(render_state->draw_offset_x, render_state->draw_offset_y, render_state->draw_region_w,
render_state->draw_region_h);
}
/*!
* Draw probes (including the clear) to the probe fbo. Also copies vertex/index buffer.
*/
void GlowRenderer::draw_probes(SharedRenderState* render_state,
ScopedProfilerNode& prof,
u32 idx_start,
u32 idx_end) {
glBindFramebuffer(GL_FRAMEBUFFER, m_ogl.probe_fbo);
glBindVertexArray(m_ogl.vao);
glEnable(GL_PRIMITIVE_RESTART);
glPrimitiveRestartIndex(UINT32_MAX);
glBindBuffer(GL_ARRAY_BUFFER, m_ogl.vertex_buffer);
glBufferData(GL_ARRAY_BUFFER, m_next_vertex * sizeof(Vertex), m_vertex_buffer.data(),
GL_STREAM_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ogl.index_buffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_next_index * sizeof(u32), m_index_buffer.data(),
GL_STREAM_DRAW);
// do probes
render_state->shaders[ShaderId::GLOW_PROBE].activate();
prof.add_draw_call();
prof.add_tri(m_next_sprite * 4);
glDisable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_GEQUAL);
glDrawElements(GL_TRIANGLE_STRIP, idx_end - idx_start, GL_UNSIGNED_INT,
(void*)(idx_start * sizeof(u32)));
}
/*!
* Draw red/green probes to the framebuffer for debugging.
*/
void GlowRenderer::debug_draw_probes(SharedRenderState* render_state,
ScopedProfilerNode& prof,
u32 idx_start,
u32 idx_end) {
prof.add_draw_call();
prof.add_tri(m_next_sprite * 4);
glBindFramebuffer(GL_FRAMEBUFFER, render_state->render_fb);
glDrawElements(GL_TRIANGLE_STRIP, idx_end - idx_start, GL_UNSIGNED_INT,
(void*)(idx_start * sizeof(u32)));
}
/*!
* Copy probes from probe fbo to grid.
*/
void GlowRenderer::draw_probe_copies(SharedRenderState* render_state,
ScopedProfilerNode& prof,
u32 idx_start,
u32 idx_end) {
// read probe from probe fbo, write it to the first downsample fbo
render_state->shaders[ShaderId::GLOW_PROBE_READ].activate();
glBindFramebuffer(GL_FRAMEBUFFER, m_ogl.downsample_fbos[0].fbo);
glBindTexture(GL_TEXTURE_2D, m_ogl.probe_fbo_rgba_tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glViewport(0, 0, m_ogl.downsample_fbos[0].size, m_ogl.downsample_fbos[0].size);
prof.add_draw_call();
prof.add_tri(m_next_sprite * 2);
glDrawElements(GL_TRIANGLE_STRIP, idx_end - idx_start, GL_UNSIGNED_INT,
(void*)(idx_start * sizeof(u32)));
glViewport(render_state->draw_offset_x, render_state->draw_offset_y, render_state->draw_region_w,
render_state->draw_region_h);
}
/*!
* Draw blue squares to show where probes and being copied from, to help debug texture offsets.
*/
void GlowRenderer::debug_draw_probe_copies(SharedRenderState* render_state,
ScopedProfilerNode& prof,
u32 idx_start,
u32 idx_end) {
render_state->shaders[ShaderId::GLOW_PROBE_READ_DEBUG].activate();
prof.add_draw_call();
prof.add_tri(m_next_sprite * 2);
glBindFramebuffer(GL_FRAMEBUFFER, render_state->render_fb);
glDrawElements(GL_TRIANGLE_STRIP, idx_end - idx_start, GL_UNSIGNED_INT,
(void*)(idx_start * sizeof(u32)));
}
/*!
* Draw all pending sprites.
*/
void GlowRenderer::flush(SharedRenderState* render_state, ScopedProfilerNode& prof) {
m_debug.num_sprites = m_next_sprite;
if (!m_next_sprite) {
// no sprites submitted.
return;
}
// copy depth from framebuffer to a temporary buffer
// (this is a bit wasteful)
blit_depth(render_state);
// generate vertex/index data for probes
u32 probe_idx_start = m_next_index;
for (u32 sidx = 0; sidx < m_next_sprite; sidx++) {
add_sprite_pass_1(m_sprite_data_buffer[sidx]);
}
// generate vertex/index data for copy to downsample buffer
u32 copy_idx_start = m_next_index;
for (u32 sidx = 0; sidx < m_next_sprite; sidx++) {
add_sprite_pass_2(m_sprite_data_buffer[sidx], sidx);
}
u32 copy_idx_end = m_next_index;
// generate vertex/index data for framebuffer draws
for (u32 sidx = 0; sidx < m_next_sprite; sidx++) {
add_sprite_pass_3(m_sprite_data_buffer[sidx], sidx);
}
// draw probes
draw_probes(render_state, prof, probe_idx_start, copy_idx_start);
if (m_debug.show_probes) {
debug_draw_probes(render_state, prof, probe_idx_start, copy_idx_start);
}
// copy probes
draw_probe_copies(render_state, prof, copy_idx_start, copy_idx_end);
if (m_debug.show_probe_copies) {
debug_draw_probe_copies(render_state, prof, copy_idx_start, copy_idx_end);
}
// downsample probes.
downsample_chain(render_state, prof, m_next_sprite);
draw_sprites(render_state, prof);
m_next_vertex = 0;
m_next_index = 0;
m_next_sprite = 0;
glBindFramebuffer(GL_FRAMEBUFFER, render_state->render_fb);
}
/*!
* Final drawing of sprites.
*/
void GlowRenderer::draw_sprites(SharedRenderState* render_state, ScopedProfilerNode& prof) {
glBindFramebuffer(GL_FRAMEBUFFER, render_state->render_fb);
glBindVertexArray(m_ogl.vao);
glEnable(GL_PRIMITIVE_RESTART);
glPrimitiveRestartIndex(UINT32_MAX);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, m_ogl.downsample_fbos[kDownsampleIterations - 1].tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
render_state->shaders[ShaderId::GLOW_DRAW].activate();
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_GEQUAL);
glEnable(GL_BLEND);
// Cv = (Cs - 0) * Ad + D
glBlendFunc(GL_ONE, GL_ONE);
glBlendEquation(GL_FUNC_ADD);
glDepthMask(GL_FALSE);
for (u32 i = 0; i < m_next_sprite; i++) {
const auto& record = m_sprite_records[i];
auto tex = render_state->texture_pool->lookup(record.tbp);
if (!tex) {
fmt::print("Failed to find texture at {}, using random", record.tbp);
tex = render_state->texture_pool->get_placeholder_texture();
}
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, *tex);
if (record.draw_mode.get_clamp_s_enable()) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
} else {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
}
if (record.draw_mode.get_clamp_t_enable()) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
} else {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
}
if (record.draw_mode.get_filt_enable()) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
} else {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}
prof.add_draw_call();
prof.add_tri(2);
glDrawElements(GL_TRIANGLE_STRIP, 5, GL_UNSIGNED_INT, (void*)(record.idx * sizeof(u32)));
}
}
GlowRenderer::Vertex* GlowRenderer::alloc_vtx(int num) {
ASSERT(m_next_vertex + num <= m_vertex_buffer.size());
auto* result = &m_vertex_buffer[m_next_vertex];
m_next_vertex += num;
return result;
}
u32* GlowRenderer::alloc_index(int num) {
ASSERT(m_next_index + num <= m_index_buffer.size());
auto* result = &m_index_buffer[m_next_index];
m_next_index += num;
return result;
}

View File

@ -0,0 +1,112 @@
#pragma once
#include "game/graphics/opengl_renderer/sprite/sprite_common.h"
class GlowRenderer {
public:
GlowRenderer();
SpriteGlowOutput* alloc_sprite();
void cancel_sprite();
void flush(SharedRenderState* render_state, ScopedProfilerNode& prof);
void draw_debug_window();
// Vertex can hold all possible values for all passes. The total number of vertices is very small
// so it ends up a lot faster to do a single upload, even if the size is like 50% larger than it
// could be.
struct Vertex {
float x, y, z, w;
float r, g, b, a;
float u, v;
float uu, vv;
};
private:
struct {
bool show_probes = false;
bool show_probe_copies = false;
int num_sprites = 0;
} m_debug;
void add_sprite_pass_1(const SpriteGlowOutput& data);
void add_sprite_pass_2(const SpriteGlowOutput& data, int sprite_idx);
void add_sprite_pass_3(const SpriteGlowOutput& data, int sprite_idx);
void blit_depth(SharedRenderState* render_state);
void draw_probes(SharedRenderState* render_state,
ScopedProfilerNode& prof,
u32 idx_start,
u32 idx_end);
void debug_draw_probes(SharedRenderState* render_state,
ScopedProfilerNode& prof,
u32 idx_start,
u32 idx_end);
void draw_probe_copies(SharedRenderState* render_state,
ScopedProfilerNode& prof,
u32 idx_start,
u32 idx_end);
void debug_draw_probe_copies(SharedRenderState* render_state,
ScopedProfilerNode& prof,
u32 idx_start,
u32 idx_end);
void downsample_chain(SharedRenderState* render_state, ScopedProfilerNode& prof, u32 num_sprites);
void draw_sprites(SharedRenderState* render_state, ScopedProfilerNode& prof);
std::vector<Vertex> m_vertex_buffer;
std::vector<SpriteGlowOutput> m_sprite_data_buffer;
u32 m_next_sprite = 0;
u32 m_next_vertex = 0;
Vertex* alloc_vtx(int num);
std::vector<u32> m_index_buffer;
u32 m_next_index = 0;
u32* alloc_index(int num);
struct DsFbo {
int size = -1;
GLuint fbo;
GLuint tex;
};
static constexpr int kDownsampleBatchWidth = 16;
static constexpr int kMaxSprites = kDownsampleBatchWidth * kDownsampleBatchWidth;
static constexpr int kMaxVertices = kMaxSprites * 32; // check.
static constexpr int kMaxIndices = kMaxSprites * 32; // check.
static constexpr int kDownsampleIterations = 5;
static constexpr int kFirstDownsampleSize = 32; // should be power of 2.
struct {
GLuint vertex_buffer;
GLuint vao;
GLuint index_buffer;
GLuint probe_fbo;
GLuint probe_fbo_rgba_tex;
GLuint probe_fbo_zbuf_rb;
int probe_fbo_w = 640;
int probe_fbo_h = 480;
DsFbo downsample_fbos[kDownsampleIterations];
} m_ogl;
struct {
GLuint vao;
GLuint index_buffer;
GLuint vertex_buffer;
} m_ogl_downsampler;
DrawMode m_default_draw_mode;
struct SpriteRecord {
u32 tbp;
DrawMode draw_mode;
u32 idx;
};
std::array<SpriteRecord, kMaxSprites> m_sprite_records;
};

View File

@ -1,5 +1,3 @@
#include "Sprite3.h"
#include "common/log/log.h"
@ -36,19 +34,8 @@ u32 process_sprite_chunk_header(DmaFollower& dma) {
return header[0];
}
/*!
* Does the next DMA transfer look like the frame data for sprite distort?
*/
bool looks_like_distort_frame_data(const DmaFollower& dma) {
return dma.current_tag().kind == DmaTag::Kind::CNT &&
dma.current_tag_vifcode0().kind == VifCode::Kind::NOP &&
dma.current_tag_vifcode1().kind == VifCode::Kind::UNPACK_V4_32;
}
} // namespace
constexpr int SPRITE_RENDERER_MAX_SPRITES = 1920 * 10;
constexpr int SPRITE_RENDERER_MAX_DISTORT_SPRITES =
256 * 10; // size of sprite-aux-list in GOAL code * SPRITE_MAX_AMOUNT_MULT
} // namespace
Sprite3::Sprite3(const std::string& name, int my_id)
: BucketRenderer(name, my_id), m_direct(name, my_id, 1024) {
@ -143,620 +130,6 @@ void Sprite3::opengl_setup_normal() {
m_current_mode = m_default_mode;
}
void Sprite3::opengl_setup_distort() {
// Create framebuffer to snapshot current render to a texture that can be bound for the distort
// shader This will represent tex0 from the original GS data
glGenFramebuffers(1, &m_distort_ogl.fbo);
glBindFramebuffer(GL_FRAMEBUFFER, m_distort_ogl.fbo);
glGenTextures(1, &m_distort_ogl.fbo_texture);
glBindTexture(GL_TEXTURE_2D, m_distort_ogl.fbo_texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, m_distort_ogl.fbo_width, m_distort_ogl.fbo_height, 0,
GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// Texture clamping here matches the GS init data for distort
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
m_distort_ogl.fbo_texture, 0);
ASSERT(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Non-instancing
// ----------------------
glGenBuffers(1, &m_distort_ogl.vertex_buffer);
glGenVertexArrays(1, &m_distort_ogl.vao);
glBindVertexArray(m_distort_ogl.vao);
glBindBuffer(GL_ARRAY_BUFFER, m_distort_ogl.vertex_buffer);
// note: each sprite shares a single vertex per slice, account for that here
int distort_vert_buffer_len =
SPRITE_RENDERER_MAX_DISTORT_SPRITES *
((5 - 1) * 11 + 1); // max * ((verts_per_slice - 1) * max_slices + 1)
glBufferData(GL_ARRAY_BUFFER, distort_vert_buffer_len * sizeof(SpriteDistortVertex), nullptr,
GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, // location 0 in the shader
3, // 3 floats per vert
GL_FLOAT, // floats
GL_FALSE, // don't normalize, ignored
sizeof(SpriteDistortVertex), //
(void*)offsetof(SpriteDistortVertex, xyz) // offset in array
);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, // location 1 in the shader
2, // 2 floats per vert
GL_FLOAT, // floats
GL_FALSE, // don't normalize, ignored
sizeof(SpriteDistortVertex), //
(void*)offsetof(SpriteDistortVertex, st) // offset in array
);
// note: add one extra element per sprite that marks the end of a triangle strip
int distort_idx_buffer_len = SPRITE_RENDERER_MAX_DISTORT_SPRITES *
((5 * 11) + 1); // max * ((verts_per_slice * max_slices) + 1)
glGenBuffers(1, &m_distort_ogl.index_buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_distort_ogl.index_buffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, distort_idx_buffer_len * sizeof(u32), nullptr,
GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
m_sprite_distorter_vertices.resize(distort_vert_buffer_len);
m_sprite_distorter_indices.resize(distort_idx_buffer_len);
m_sprite_distorter_frame_data.resize(SPRITE_RENDERER_MAX_DISTORT_SPRITES);
// Instancing
// ----------------------
glGenVertexArrays(1, &m_distort_instanced_ogl.vao);
glBindVertexArray(m_distort_instanced_ogl.vao);
int distort_max_sprite_slices = 0;
for (int i = 3; i < 12; i++) {
// For each 'resolution', there can be that many slices
distort_max_sprite_slices += i;
}
glGenBuffers(1, &m_distort_instanced_ogl.vertex_buffer);
glBindBuffer(GL_ARRAY_BUFFER, m_distort_instanced_ogl.vertex_buffer);
int distort_instanced_vert_buffer_len = distort_max_sprite_slices * 5; // 5 vertices per slice
glBufferData(GL_ARRAY_BUFFER, distort_instanced_vert_buffer_len * sizeof(SpriteDistortVertex),
nullptr, GL_STREAM_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, // location 0 in the shader
3, // 3 floats per vert
GL_FLOAT, // floats
GL_FALSE, // don't normalize, ignored
sizeof(SpriteDistortVertex), //
(void*)offsetof(SpriteDistortVertex, xyz) // offset in array
);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, // location 1 in the shader
2, // 2 floats per vert
GL_FLOAT, // floats
GL_FALSE, // don't normalize, ignored
sizeof(SpriteDistortVertex), //
(void*)offsetof(SpriteDistortVertex, st) // offset in array
);
glGenBuffers(1, &m_distort_instanced_ogl.instance_buffer);
glBindBuffer(GL_ARRAY_BUFFER, m_distort_instanced_ogl.instance_buffer);
int distort_instance_buffer_len = SPRITE_RENDERER_MAX_DISTORT_SPRITES;
glBufferData(GL_ARRAY_BUFFER, distort_instance_buffer_len * sizeof(SpriteDistortInstanceData),
nullptr, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, // location 2 in the shader
4, // 4 floats per vert
GL_FLOAT, // floats
GL_FALSE, // normalized, ignored,
sizeof(SpriteDistortInstanceData), //
(void*)offsetof(SpriteDistortInstanceData, x_y_z_s) // offset in array
);
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, // location 3 in the shader
4, // 4 floats per vert
GL_FLOAT, // floats
GL_FALSE, // normalized, ignored,
sizeof(SpriteDistortInstanceData), //
(void*)offsetof(SpriteDistortInstanceData, sx_sy_sz_t) // offset in array
);
glVertexAttribDivisor(2, 1);
glVertexAttribDivisor(3, 1);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
m_sprite_distorter_vertices_instanced.resize(distort_instanced_vert_buffer_len);
for (int i = 3; i < 12; i++) {
auto vec = std::vector<SpriteDistortInstanceData>();
vec.resize(distort_instance_buffer_len);
m_sprite_distorter_instances_by_res[i] = vec;
}
}
/*!
* Run the sprite distorter.
*/
void Sprite3::render_distorter(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
// Skip to distorter DMA
m_direct.reset_state();
while (dma.current_tag().qwc != 7) {
auto direct_data = dma.read_and_advance();
m_direct.render_vif(direct_data.vif0(), direct_data.vif1(), direct_data.data,
direct_data.size_bytes, render_state, prof);
}
m_direct.flush_pending(render_state, prof);
// Read DMA
{
auto prof_node = prof.make_scoped_child("dma");
distort_dma(dma, prof_node);
}
if (!m_enabled || !m_distort_enable) {
// Distort disabled, we can stop here since all the DMA has been read
return;
}
// Set up vertex data
{
auto prof_node = prof.make_scoped_child("setup");
if (m_enable_distort_instancing) {
distort_setup_instanced(prof_node);
} else {
distort_setup(prof_node);
}
}
// Draw
{
auto prof_node = prof.make_scoped_child("drawing");
if (m_enable_distort_instancing) {
distort_draw_instanced(render_state, prof_node);
} else {
distort_draw(render_state, prof_node);
}
}
}
/*!
* Reads all sprite distort related DMA packets.
*/
void Sprite3::distort_dma(DmaFollower& dma, ScopedProfilerNode& /*prof*/) {
// First should be the GS setup
auto sprite_distorter_direct_setup = dma.read_and_advance();
ASSERT(sprite_distorter_direct_setup.vifcode0().kind == VifCode::Kind::NOP);
ASSERT(sprite_distorter_direct_setup.vifcode1().kind == VifCode::Kind::DIRECT);
ASSERT(sprite_distorter_direct_setup.vifcode1().immediate == 7);
memcpy(&m_sprite_distorter_setup, sprite_distorter_direct_setup.data, 7 * 16);
auto gif_tag = m_sprite_distorter_setup.gif_tag;
ASSERT(gif_tag.nloop() == 1);
ASSERT(gif_tag.eop() == 1);
ASSERT(gif_tag.nreg() == 6);
ASSERT(gif_tag.reg(0) == GifTag::RegisterDescriptor::AD);
auto zbuf1 = m_sprite_distorter_setup.zbuf;
ASSERT(zbuf1.zbp() == 0x1c0);
ASSERT(zbuf1.zmsk() == true);
ASSERT(zbuf1.psm() == TextureFormat::PSMZ24);
auto tex0 = m_sprite_distorter_setup.tex0;
ASSERT(tex0.tbw() == 8);
ASSERT(tex0.tw() == 9);
ASSERT(tex0.th() == 8);
auto tex1 = m_sprite_distorter_setup.tex1;
ASSERT(tex1.mmag() == true);
ASSERT(tex1.mmin() == 1);
auto alpha = m_sprite_distorter_setup.alpha;
ASSERT(alpha.a_mode() == GsAlpha::BlendMode::SOURCE);
ASSERT(alpha.b_mode() == GsAlpha::BlendMode::DEST);
ASSERT(alpha.c_mode() == GsAlpha::BlendMode::SOURCE);
ASSERT(alpha.d_mode() == GsAlpha::BlendMode::DEST);
// Next is the aspect used by the sine tables (PC only)
//
// This was added to let the renderer reliably detect when the sine tables changed,
// which is whenever the aspect ratio changed. However, the tables aren't always
// updated on the same frame that the aspect changed, so this just lets the game
// easily notify the renderer when it finally does get updated.
auto sprite_distort_tables_aspect = dma.read_and_advance();
ASSERT(sprite_distort_tables_aspect.size_bytes == 16);
ASSERT(sprite_distort_tables_aspect.vifcode1().kind == VifCode::Kind::PC_PORT);
memcpy(&m_sprite_distorter_sine_tables_aspect, sprite_distort_tables_aspect.data,
sizeof(math::Vector4f));
// Next thing should be the sine tables
auto sprite_distorter_tables = dma.read_and_advance();
unpack_to_stcycl(&m_sprite_distorter_sine_tables, sprite_distorter_tables,
VifCode::Kind::UNPACK_V4_32, 4, 4, 0x8b * 16, 0x160, false, false);
ASSERT(GsPrim(m_sprite_distorter_sine_tables.gs_gif_tag.prim()).kind() ==
GsPrim::Kind::TRI_STRIP);
// Finally, should be frame data packets (containing sprites)
// Up to 170 sprites will be DMA'd at a time followed by a mscalf,
// and this process can happen twice up to a maximum of 256 sprites DMA'd
// (256 is the size of sprite-aux-list which drives this).
int sprite_idx = 0;
m_distort_stats.total_sprites = 0;
while (looks_like_distort_frame_data(dma)) {
math::Vector<u32, 4> num_sprites_vec;
// Read sprite packets
do {
int qwc = dma.current_tag().qwc;
int dest = dma.current_tag_vifcode1().immediate;
auto distort_data = dma.read_and_advance();
if (dest == 511) {
// VU address 511 specifies the number of sprites
unpack_to_no_stcycl(&num_sprites_vec, distort_data, VifCode::Kind::UNPACK_V4_32, 16, dest,
false, false);
} else {
// VU address >= 512 is the actual vertex data
ASSERT(dest >= 512);
ASSERT(sprite_idx + (qwc / 3) <= (int)m_sprite_distorter_frame_data.capacity());
unpack_to_no_stcycl(&m_sprite_distorter_frame_data.at(sprite_idx), distort_data,
VifCode::Kind::UNPACK_V4_32, qwc * 16, dest, false, false);
sprite_idx += qwc / 3;
}
} while (looks_like_distort_frame_data(dma));
// Sprite packets should always end with a mscalf flush
ASSERT(dma.current_tag().kind == DmaTag::Kind::CNT);
ASSERT(dma.current_tag_vifcode0().kind == VifCode::Kind::MSCALF);
ASSERT(dma.current_tag_vifcode1().kind == VifCode::Kind::FLUSH);
dma.read_and_advance();
m_distort_stats.total_sprites += num_sprites_vec.x();
}
// Done
ASSERT(m_distort_stats.total_sprites <= SPRITE_RENDERER_MAX_DISTORT_SPRITES);
}
/*!
* Sets up OpenGL data for each distort sprite.
*/
void Sprite3::distort_setup(ScopedProfilerNode& /*prof*/) {
m_distort_stats.total_tris = 0;
m_sprite_distorter_vertices.clear();
m_sprite_distorter_indices.clear();
int sprite_idx = 0;
int sprites_left = m_distort_stats.total_sprites;
// This part is mostly ripped from the VU program
while (sprites_left != 0) {
// flag seems to represent the 'resolution' of the circle sprite used to create the distortion
// effect For example, a flag value of 3 will create a circle using 3 "pie-slice" shapes
u32 flag = m_sprite_distorter_frame_data.at(sprite_idx).flag;
u32 slices_left = flag;
// flag has a minimum value of 3 which represents the first ientry
// Additionally, the ientry index has 352 added to it (which is the start of the entry array
// in VU memory), so we need to subtract that as well
int entry_index = m_sprite_distorter_sine_tables.ientry[flag - 3].x() - 352;
// Here would be adding the giftag, but we don't need that
// Get the frame data for the next distort sprite
SpriteDistortFrameData frame_data = m_sprite_distorter_frame_data.at(sprite_idx);
sprite_idx++;
// Build the OpenGL data for the sprite
math::Vector2f vf03 = frame_data.st;
math::Vector3f vf14 = frame_data.xyz;
// Each slice shares a center vertex, we can use this fact and cut out duplicate vertices
u32 center_vert_idx = m_sprite_distorter_vertices.size();
m_sprite_distorter_vertices.push_back({vf14, vf03});
do {
math::Vector3f vf06 = m_sprite_distorter_sine_tables.entry[entry_index++].xyz();
math::Vector2f vf07 = m_sprite_distorter_sine_tables.entry[entry_index++].xy();
math::Vector3f vf08 = m_sprite_distorter_sine_tables.entry[entry_index + 0].xyz();
math::Vector2f vf09 = m_sprite_distorter_sine_tables.entry[entry_index + 1].xy();
slices_left--;
math::Vector2f vf11 = (vf07 * frame_data.rgba.z()) + frame_data.st;
math::Vector2f vf13 = (vf09 * frame_data.rgba.z()) + frame_data.st;
math::Vector3f vf06_2 = (vf06 * frame_data.rgba.x()) + frame_data.xyz;
math::Vector2f vf07_2 = (vf07 * frame_data.rgba.x()) + frame_data.st;
math::Vector3f vf08_2 = (vf08 * frame_data.rgba.x()) + frame_data.xyz;
math::Vector2f vf09_2 = (vf09 * frame_data.rgba.x()) + frame_data.st;
math::Vector3f vf10 = (vf06 * frame_data.rgba.y()) + frame_data.xyz;
math::Vector3f vf12 = (vf08 * frame_data.rgba.y()) + frame_data.xyz;
math::Vector3f vf06_3 = vf06_2;
math::Vector3f vf08_3 = vf08_2;
m_sprite_distorter_indices.push_back(m_sprite_distorter_vertices.size());
m_sprite_distorter_vertices.push_back({vf06_3, vf07_2});
m_sprite_distorter_indices.push_back(m_sprite_distorter_vertices.size());
m_sprite_distorter_vertices.push_back({vf08_3, vf09_2});
m_sprite_distorter_indices.push_back(m_sprite_distorter_vertices.size());
m_sprite_distorter_vertices.push_back({vf10, vf11});
m_sprite_distorter_indices.push_back(m_sprite_distorter_vertices.size());
m_sprite_distorter_vertices.push_back({vf12, vf13});
// Originally, would add the shared center vertex, but in our case we can just add the index
m_sprite_distorter_indices.push_back(center_vert_idx);
// m_sprite_distorter_vertices.push_back({vf14, vf03});
m_distort_stats.total_tris += 2;
} while (slices_left != 0);
// Mark the end of the triangle strip
m_sprite_distorter_indices.push_back(UINT32_MAX);
sprites_left--;
}
}
/*!
* Sets up OpenGL data for rendering distort sprites using instanced rendering.
*
* A mesh is built once for each possible sprite resolution and is only re-built
* when the dimensions of the window are changed. These meshes are built just like
* the triangle strips in the VU program, but with the sprite-specific data removed.
*
* Required sprite-specific frame data is kept as is and is grouped by resolution.
*/
void Sprite3::distort_setup_instanced(ScopedProfilerNode& /*prof*/) {
if (m_distort_instanced_ogl.last_aspect_x != m_sprite_distorter_sine_tables_aspect.x() ||
m_distort_instanced_ogl.last_aspect_y != m_sprite_distorter_sine_tables_aspect.y()) {
m_distort_instanced_ogl.last_aspect_x = m_sprite_distorter_sine_tables_aspect.x();
m_distort_instanced_ogl.last_aspect_y = m_sprite_distorter_sine_tables_aspect.y();
// Aspect ratio changed, which means we have a new sine table
m_sprite_distorter_vertices_instanced.clear();
// Build a mesh for every possible distort sprite resolution
auto vf03 = math::Vector2f(0, 0);
auto vf14 = math::Vector3f(0, 0, 0);
for (int res = 3; res < 12; res++) {
int entry_index = m_sprite_distorter_sine_tables.ientry[res - 3].x() - 352;
for (int i = 0; i < res; i++) {
math::Vector3f vf06 = m_sprite_distorter_sine_tables.entry[entry_index++].xyz();
math::Vector2f vf07 = m_sprite_distorter_sine_tables.entry[entry_index++].xy();
math::Vector3f vf08 = m_sprite_distorter_sine_tables.entry[entry_index + 0].xyz();
math::Vector2f vf09 = m_sprite_distorter_sine_tables.entry[entry_index + 1].xy();
// Normally, there would be a bunch of transformations here against the sprite data.
// Instead, we'll let the shader do it and just store the sine table specific parts here.
m_sprite_distorter_vertices_instanced.push_back({vf06, vf07});
m_sprite_distorter_vertices_instanced.push_back({vf08, vf09});
m_sprite_distorter_vertices_instanced.push_back({vf06, vf07});
m_sprite_distorter_vertices_instanced.push_back({vf08, vf09});
m_sprite_distorter_vertices_instanced.push_back({vf14, vf03});
}
}
m_distort_instanced_ogl.vertex_data_changed = true;
}
// Set up instance data for each sprite
m_distort_stats.total_tris = 0;
for (auto& [res, vec] : m_sprite_distorter_instances_by_res) {
vec.clear();
}
for (int i = 0; i < m_distort_stats.total_sprites; i++) {
SpriteDistortFrameData frame_data = m_sprite_distorter_frame_data.at(i);
// Shader just needs the position, tex coords, and scale
auto x_y_z_s = math::Vector4f(frame_data.xyz.x(), frame_data.xyz.y(), frame_data.xyz.z(),
frame_data.st.x());
auto sx_sy_sz_t = math::Vector4f(frame_data.rgba.x(), frame_data.rgba.y(), frame_data.rgba.z(),
frame_data.st.y());
int res = frame_data.flag;
m_sprite_distorter_instances_by_res[res].push_back({x_y_z_s, sx_sy_sz_t});
m_distort_stats.total_tris += res * 2;
}
}
/*!
* Draws each distort sprite.
*/
void Sprite3::distort_draw(SharedRenderState* render_state, ScopedProfilerNode& prof) {
// First, make sure the distort framebuffer is the correct size
distort_setup_framebuffer_dims(render_state);
if (m_distort_stats.total_tris == 0) {
// No distort sprites to draw, we can end early
return;
}
// Do common distort drawing logic
distort_draw_common(render_state, prof);
// Set up shader
auto shader = &render_state->shaders[ShaderId::SPRITE_DISTORT];
shader->activate();
Vector4f colorf = Vector4f(m_sprite_distorter_sine_tables.color.x() / 255.0f,
m_sprite_distorter_sine_tables.color.y() / 255.0f,
m_sprite_distorter_sine_tables.color.z() / 255.0f,
m_sprite_distorter_sine_tables.color.w() / 255.0f);
glUniform4fv(glGetUniformLocation(shader->id(), "u_color"), 1, colorf.data());
// Bind vertex array
glBindVertexArray(m_distort_ogl.vao);
// Enable prim restart, we need this to break up the triangle strips
glEnable(GL_PRIMITIVE_RESTART);
glPrimitiveRestartIndex(UINT32_MAX);
// Upload vertex data
glBindBuffer(GL_ARRAY_BUFFER, m_distort_ogl.vertex_buffer);
glBufferData(GL_ARRAY_BUFFER, m_sprite_distorter_vertices.size() * sizeof(SpriteDistortVertex),
m_sprite_distorter_vertices.data(), GL_DYNAMIC_DRAW);
// Upload element data
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_distort_ogl.index_buffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_sprite_distorter_indices.size() * sizeof(u32),
m_sprite_distorter_indices.data(), GL_DYNAMIC_DRAW);
// Draw
prof.add_draw_call();
prof.add_tri(m_distort_stats.total_tris);
glDrawElements(GL_TRIANGLE_STRIP, m_sprite_distorter_indices.size(), GL_UNSIGNED_INT, (void*)0);
// Done
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
/*!
* Draws each distort sprite using instanced rendering.
*/
void Sprite3::distort_draw_instanced(SharedRenderState* render_state, ScopedProfilerNode& prof) {
// First, make sure the distort framebuffer is the correct size
distort_setup_framebuffer_dims(render_state);
if (m_distort_stats.total_tris == 0) {
// No distort sprites to draw, we can end early
return;
}
// Do common distort drawing logic
distort_draw_common(render_state, prof);
// Set up shader
auto shader = &render_state->shaders[ShaderId::SPRITE_DISTORT_INSTANCED];
shader->activate();
Vector4f colorf = Vector4f(m_sprite_distorter_sine_tables.color.x() / 255.0f,
m_sprite_distorter_sine_tables.color.y() / 255.0f,
m_sprite_distorter_sine_tables.color.z() / 255.0f,
m_sprite_distorter_sine_tables.color.w() / 255.0f);
glUniform4fv(glGetUniformLocation(shader->id(), "u_color"), 1, colorf.data());
// Bind vertex array
glBindVertexArray(m_distort_instanced_ogl.vao);
// Upload vertex data (if it changed)
if (m_distort_instanced_ogl.vertex_data_changed) {
m_distort_instanced_ogl.vertex_data_changed = false;
glBindBuffer(GL_ARRAY_BUFFER, m_distort_instanced_ogl.vertex_buffer);
glBufferData(GL_ARRAY_BUFFER,
m_sprite_distorter_vertices_instanced.size() * sizeof(SpriteDistortVertex),
m_sprite_distorter_vertices_instanced.data(), GL_STREAM_DRAW);
}
// Draw each resolution group
glBindBuffer(GL_ARRAY_BUFFER, m_distort_instanced_ogl.instance_buffer);
prof.add_tri(m_distort_stats.total_tris);
int vert_offset = 0;
for (int res = 3; res < 12; res++) {
auto& instances = m_sprite_distorter_instances_by_res[res];
int num_verts = res * 5;
if (instances.size() > 0) {
// Upload instance data
glBufferData(GL_ARRAY_BUFFER, instances.size() * sizeof(SpriteDistortInstanceData),
instances.data(), GL_DYNAMIC_DRAW);
// Draw
prof.add_draw_call();
glDrawArraysInstanced(GL_TRIANGLE_STRIP, vert_offset, num_verts, instances.size());
}
vert_offset += num_verts;
}
// Done
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
void Sprite3::distort_draw_common(SharedRenderState* render_state, ScopedProfilerNode& /*prof*/) {
// The distort effect needs to read the current framebuffer, so copy what's been rendered so far
// to a texture that we can then pass to the shader
glBindFramebuffer(GL_READ_FRAMEBUFFER, render_state->render_fb);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_distort_ogl.fbo);
glBlitFramebuffer(render_state->render_fb_x, // srcX0
render_state->render_fb_y, // srcY0
render_state->render_fb_x + render_state->render_fb_w, // srcX1
render_state->render_fb_y + render_state->render_fb_h, // srcY1
0, // dstX0
0, // dstY0
m_distort_ogl.fbo_width, // dstX1
m_distort_ogl.fbo_height, // dstY1
GL_COLOR_BUFFER_BIT, // mask
GL_NEAREST // filter
);
glBindFramebuffer(GL_FRAMEBUFFER, render_state->render_fb);
// Set up OpenGL state
m_current_mode.set_depth_write_enable(!m_sprite_distorter_setup.zbuf.zmsk()); // zbuf
glBindTexture(GL_TEXTURE_2D, m_distort_ogl.fbo_texture); // tex0
m_current_mode.set_filt_enable(m_sprite_distorter_setup.tex1.mmag()); // tex1
update_mode_from_alpha1(m_sprite_distorter_setup.alpha.data, m_current_mode); // alpha1
// note: clamp and miptbp are skipped since that is set up ahead of time with the distort
// framebuffer texture
setup_opengl_from_draw_mode(m_current_mode, GL_TEXTURE0, false);
}
void Sprite3::distort_setup_framebuffer_dims(SharedRenderState* render_state) {
// Distort framebuffer must be the same dimensions as the default window framebuffer
if (m_distort_ogl.fbo_width != render_state->render_fb_w ||
m_distort_ogl.fbo_height != render_state->render_fb_h) {
m_distort_ogl.fbo_width = render_state->render_fb_w;
m_distort_ogl.fbo_height = render_state->render_fb_h;
glBindTexture(GL_TEXTURE_2D, m_distort_ogl.fbo_texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, m_distort_ogl.fbo_width, m_distort_ogl.fbo_height, 0,
GL_RGB, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_2D, 0);
}
}
/*!
* Handle DMA data that does the per-frame setup.
* This should get the dma chain immediately after the call to sprite-draw-distorters.
@ -1026,24 +399,30 @@ void Sprite3::render_jak2(DmaFollower& dma,
auto child = prof.make_scoped_child("2d-group1");
render_2d_group1(dma, render_state, child);
flush_sprites(render_state, prof, true);
auto nop_flushe = dma.read_and_advance();
ASSERT(nop_flushe.vifcode0().kind == VifCode::Kind::NOP);
ASSERT(nop_flushe.vifcode1().kind == VifCode::Kind::FLUSHE);
}
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBlendEquation(GL_FUNC_ADD);
// TODO finish this up.
{
auto p = prof.make_scoped_child("glow");
glow_dma_and_draw(dma, render_state, p);
}
// fmt::print("next bucket is 0x{}\n", render_state->next_bucket);
while (dma.current_tag_offset() != render_state->next_bucket) {
// auto tag = dma.current_tag();
// fmt::print("@ 0x{:x} tag: {}", dma.current_tag_offset(), tag.print());
auto data = dma.read_and_advance();
VifCode code(data.vif0());
(void)data;
// VifCode code(data.vif0());
// fmt::print("@ 0x{:x} tag: {}", dma.current_tag_offset(), tag.print());
// fmt::print(" vif0: {}\n", code.print());
if (code.kind == VifCode::Kind::NOP) {
// fmt::print(" vif1: {}\n", VifCode(data.vif1()).print());
}
}
}
void Sprite3::render_jak1(DmaFollower& dma,
@ -1128,6 +507,8 @@ void Sprite3::draw_debug_window() {
ImGui::Checkbox("3d", &m_3d_enable);
ImGui::Checkbox("Distort", &m_distort_enable);
ImGui::Checkbox("Distort instancing", &m_enable_distort_instancing);
ImGui::Separator();
m_glow_renderer.draw_debug_window();
}
///////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -9,7 +9,8 @@
#include "game/graphics/opengl_renderer/BucketRenderer.h"
#include "game/graphics/opengl_renderer/DirectRenderer.h"
#include "game/graphics/opengl_renderer/background/background_common.h"
#include "game/graphics/opengl_renderer/sprite_common.h"
#include "game/graphics/opengl_renderer/sprite/GlowRenderer.h"
#include "game/graphics/opengl_renderer/sprite/sprite_common.h"
class Sprite3 : public BucketRenderer {
public:
@ -61,6 +62,11 @@ class Sprite3 : public BucketRenderer {
void flush_sprites(SharedRenderState* render_state, ScopedProfilerNode& prof, bool double_draw);
GlowRenderer m_glow_renderer;
void glow_dma_and_draw(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof);
struct SpriteDistorterSetup {
GifTag gif_tag;
GsZbuf zbuf;

View File

@ -0,0 +1,630 @@
#include "Sprite3.h"
#include "game/graphics/opengl_renderer/dma_helpers.h"
namespace {
/*!
* Does the next DMA transfer look like the frame data for sprite distort?
*/
bool looks_like_distort_frame_data(const DmaFollower& dma) {
return dma.current_tag().kind == DmaTag::Kind::CNT &&
dma.current_tag_vifcode0().kind == VifCode::Kind::NOP &&
dma.current_tag_vifcode1().kind == VifCode::Kind::UNPACK_V4_32;
}
constexpr int SPRITE_RENDERER_MAX_DISTORT_SPRITES =
256 * 10; // size of sprite-aux-list in GOAL code * SPRITE_MAX_AMOUNT_MULT
} // namespace
void Sprite3::opengl_setup_distort() {
// Create framebuffer to snapshot current render to a texture that can be bound for the distort
// shader This will represent tex0 from the original GS data
glGenFramebuffers(1, &m_distort_ogl.fbo);
glBindFramebuffer(GL_FRAMEBUFFER, m_distort_ogl.fbo);
glGenTextures(1, &m_distort_ogl.fbo_texture);
glBindTexture(GL_TEXTURE_2D, m_distort_ogl.fbo_texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, m_distort_ogl.fbo_width, m_distort_ogl.fbo_height, 0,
GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// Texture clamping here matches the GS init data for distort
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
m_distort_ogl.fbo_texture, 0);
ASSERT(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Non-instancing
// ----------------------
glGenBuffers(1, &m_distort_ogl.vertex_buffer);
glGenVertexArrays(1, &m_distort_ogl.vao);
glBindVertexArray(m_distort_ogl.vao);
glBindBuffer(GL_ARRAY_BUFFER, m_distort_ogl.vertex_buffer);
// note: each sprite shares a single vertex per slice, account for that here
int distort_vert_buffer_len =
SPRITE_RENDERER_MAX_DISTORT_SPRITES *
((5 - 1) * 11 + 1); // max * ((verts_per_slice - 1) * max_slices + 1)
glBufferData(GL_ARRAY_BUFFER, distort_vert_buffer_len * sizeof(SpriteDistortVertex), nullptr,
GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, // location 0 in the shader
3, // 3 floats per vert
GL_FLOAT, // floats
GL_FALSE, // don't normalize, ignored
sizeof(SpriteDistortVertex), //
(void*)offsetof(SpriteDistortVertex, xyz) // offset in array
);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, // location 1 in the shader
2, // 2 floats per vert
GL_FLOAT, // floats
GL_FALSE, // don't normalize, ignored
sizeof(SpriteDistortVertex), //
(void*)offsetof(SpriteDistortVertex, st) // offset in array
);
// note: add one extra element per sprite that marks the end of a triangle strip
int distort_idx_buffer_len = SPRITE_RENDERER_MAX_DISTORT_SPRITES *
((5 * 11) + 1); // max * ((verts_per_slice * max_slices) + 1)
glGenBuffers(1, &m_distort_ogl.index_buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_distort_ogl.index_buffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, distort_idx_buffer_len * sizeof(u32), nullptr,
GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
m_sprite_distorter_vertices.resize(distort_vert_buffer_len);
m_sprite_distorter_indices.resize(distort_idx_buffer_len);
m_sprite_distorter_frame_data.resize(SPRITE_RENDERER_MAX_DISTORT_SPRITES);
// Instancing
// ----------------------
glGenVertexArrays(1, &m_distort_instanced_ogl.vao);
glBindVertexArray(m_distort_instanced_ogl.vao);
int distort_max_sprite_slices = 0;
for (int i = 3; i < 12; i++) {
// For each 'resolution', there can be that many slices
distort_max_sprite_slices += i;
}
glGenBuffers(1, &m_distort_instanced_ogl.vertex_buffer);
glBindBuffer(GL_ARRAY_BUFFER, m_distort_instanced_ogl.vertex_buffer);
int distort_instanced_vert_buffer_len = distort_max_sprite_slices * 5; // 5 vertices per slice
glBufferData(GL_ARRAY_BUFFER, distort_instanced_vert_buffer_len * sizeof(SpriteDistortVertex),
nullptr, GL_STREAM_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, // location 0 in the shader
3, // 3 floats per vert
GL_FLOAT, // floats
GL_FALSE, // don't normalize, ignored
sizeof(SpriteDistortVertex), //
(void*)offsetof(SpriteDistortVertex, xyz) // offset in array
);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, // location 1 in the shader
2, // 2 floats per vert
GL_FLOAT, // floats
GL_FALSE, // don't normalize, ignored
sizeof(SpriteDistortVertex), //
(void*)offsetof(SpriteDistortVertex, st) // offset in array
);
glGenBuffers(1, &m_distort_instanced_ogl.instance_buffer);
glBindBuffer(GL_ARRAY_BUFFER, m_distort_instanced_ogl.instance_buffer);
int distort_instance_buffer_len = SPRITE_RENDERER_MAX_DISTORT_SPRITES;
glBufferData(GL_ARRAY_BUFFER, distort_instance_buffer_len * sizeof(SpriteDistortInstanceData),
nullptr, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, // location 2 in the shader
4, // 4 floats per vert
GL_FLOAT, // floats
GL_FALSE, // normalized, ignored,
sizeof(SpriteDistortInstanceData), //
(void*)offsetof(SpriteDistortInstanceData, x_y_z_s) // offset in array
);
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, // location 3 in the shader
4, // 4 floats per vert
GL_FLOAT, // floats
GL_FALSE, // normalized, ignored,
sizeof(SpriteDistortInstanceData), //
(void*)offsetof(SpriteDistortInstanceData, sx_sy_sz_t) // offset in array
);
glVertexAttribDivisor(2, 1);
glVertexAttribDivisor(3, 1);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
m_sprite_distorter_vertices_instanced.resize(distort_instanced_vert_buffer_len);
for (int i = 3; i < 12; i++) {
auto vec = std::vector<SpriteDistortInstanceData>();
vec.resize(distort_instance_buffer_len);
m_sprite_distorter_instances_by_res[i] = vec;
}
}
/*!
* Run the sprite distorter.
*/
void Sprite3::render_distorter(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
// Skip to distorter DMA
m_direct.reset_state();
while (dma.current_tag().qwc != 7) {
auto direct_data = dma.read_and_advance();
m_direct.render_vif(direct_data.vif0(), direct_data.vif1(), direct_data.data,
direct_data.size_bytes, render_state, prof);
}
m_direct.flush_pending(render_state, prof);
// Read DMA
{
auto prof_node = prof.make_scoped_child("dma");
distort_dma(dma, prof_node);
}
if (!m_enabled || !m_distort_enable) {
// Distort disabled, we can stop here since all the DMA has been read
return;
}
// Set up vertex data
{
auto prof_node = prof.make_scoped_child("setup");
if (m_enable_distort_instancing) {
distort_setup_instanced(prof_node);
} else {
distort_setup(prof_node);
}
}
// Draw
{
auto prof_node = prof.make_scoped_child("drawing");
if (m_enable_distort_instancing) {
distort_draw_instanced(render_state, prof_node);
} else {
distort_draw(render_state, prof_node);
}
}
}
/*!
* Reads all sprite distort related DMA packets.
*/
void Sprite3::distort_dma(DmaFollower& dma, ScopedProfilerNode& /*prof*/) {
// First should be the GS setup
auto sprite_distorter_direct_setup = dma.read_and_advance();
ASSERT(sprite_distorter_direct_setup.vifcode0().kind == VifCode::Kind::NOP);
ASSERT(sprite_distorter_direct_setup.vifcode1().kind == VifCode::Kind::DIRECT);
ASSERT(sprite_distorter_direct_setup.vifcode1().immediate == 7);
memcpy(&m_sprite_distorter_setup, sprite_distorter_direct_setup.data, 7 * 16);
auto gif_tag = m_sprite_distorter_setup.gif_tag;
ASSERT(gif_tag.nloop() == 1);
ASSERT(gif_tag.eop() == 1);
ASSERT(gif_tag.nreg() == 6);
ASSERT(gif_tag.reg(0) == GifTag::RegisterDescriptor::AD);
auto zbuf1 = m_sprite_distorter_setup.zbuf;
ASSERT(zbuf1.zbp() == 0x1c0);
ASSERT(zbuf1.zmsk() == true);
ASSERT(zbuf1.psm() == TextureFormat::PSMZ24);
auto tex0 = m_sprite_distorter_setup.tex0;
ASSERT(tex0.tbw() == 8);
ASSERT(tex0.tw() == 9);
ASSERT(tex0.th() == 8);
auto tex1 = m_sprite_distorter_setup.tex1;
ASSERT(tex1.mmag() == true);
ASSERT(tex1.mmin() == 1);
auto alpha = m_sprite_distorter_setup.alpha;
ASSERT(alpha.a_mode() == GsAlpha::BlendMode::SOURCE);
ASSERT(alpha.b_mode() == GsAlpha::BlendMode::DEST);
ASSERT(alpha.c_mode() == GsAlpha::BlendMode::SOURCE);
ASSERT(alpha.d_mode() == GsAlpha::BlendMode::DEST);
// Next is the aspect used by the sine tables (PC only)
//
// This was added to let the renderer reliably detect when the sine tables changed,
// which is whenever the aspect ratio changed. However, the tables aren't always
// updated on the same frame that the aspect changed, so this just lets the game
// easily notify the renderer when it finally does get updated.
auto sprite_distort_tables_aspect = dma.read_and_advance();
ASSERT(sprite_distort_tables_aspect.size_bytes == 16);
ASSERT(sprite_distort_tables_aspect.vifcode1().kind == VifCode::Kind::PC_PORT);
memcpy(&m_sprite_distorter_sine_tables_aspect, sprite_distort_tables_aspect.data,
sizeof(math::Vector4f));
// Next thing should be the sine tables
auto sprite_distorter_tables = dma.read_and_advance();
unpack_to_stcycl(&m_sprite_distorter_sine_tables, sprite_distorter_tables,
VifCode::Kind::UNPACK_V4_32, 4, 4, 0x8b * 16, 0x160, false, false);
ASSERT(GsPrim(m_sprite_distorter_sine_tables.gs_gif_tag.prim()).kind() ==
GsPrim::Kind::TRI_STRIP);
// Finally, should be frame data packets (containing sprites)
// Up to 170 sprites will be DMA'd at a time followed by a mscalf,
// and this process can happen twice up to a maximum of 256 sprites DMA'd
// (256 is the size of sprite-aux-list which drives this).
int sprite_idx = 0;
m_distort_stats.total_sprites = 0;
while (looks_like_distort_frame_data(dma)) {
math::Vector<u32, 4> num_sprites_vec;
// Read sprite packets
do {
int qwc = dma.current_tag().qwc;
int dest = dma.current_tag_vifcode1().immediate;
auto distort_data = dma.read_and_advance();
if (dest == 511) {
// VU address 511 specifies the number of sprites
unpack_to_no_stcycl(&num_sprites_vec, distort_data, VifCode::Kind::UNPACK_V4_32, 16, dest,
false, false);
} else {
// VU address >= 512 is the actual vertex data
ASSERT(dest >= 512);
ASSERT(sprite_idx + (qwc / 3) <= (int)m_sprite_distorter_frame_data.capacity());
unpack_to_no_stcycl(&m_sprite_distorter_frame_data.at(sprite_idx), distort_data,
VifCode::Kind::UNPACK_V4_32, qwc * 16, dest, false, false);
sprite_idx += qwc / 3;
}
} while (looks_like_distort_frame_data(dma));
// Sprite packets should always end with a mscalf flush
ASSERT(dma.current_tag().kind == DmaTag::Kind::CNT);
ASSERT(dma.current_tag_vifcode0().kind == VifCode::Kind::MSCALF);
ASSERT(dma.current_tag_vifcode1().kind == VifCode::Kind::FLUSH);
dma.read_and_advance();
m_distort_stats.total_sprites += num_sprites_vec.x();
}
// Done
ASSERT(m_distort_stats.total_sprites <= SPRITE_RENDERER_MAX_DISTORT_SPRITES);
}
/*!
* Sets up OpenGL data for each distort sprite.
*/
void Sprite3::distort_setup(ScopedProfilerNode& /*prof*/) {
m_distort_stats.total_tris = 0;
m_sprite_distorter_vertices.clear();
m_sprite_distorter_indices.clear();
int sprite_idx = 0;
int sprites_left = m_distort_stats.total_sprites;
// This part is mostly ripped from the VU program
while (sprites_left != 0) {
// flag seems to represent the 'resolution' of the circle sprite used to create the distortion
// effect For example, a flag value of 3 will create a circle using 3 "pie-slice" shapes
u32 flag = m_sprite_distorter_frame_data.at(sprite_idx).flag;
u32 slices_left = flag;
// flag has a minimum value of 3 which represents the first ientry
// Additionally, the ientry index has 352 added to it (which is the start of the entry array
// in VU memory), so we need to subtract that as well
int entry_index = m_sprite_distorter_sine_tables.ientry[flag - 3].x() - 352;
// Here would be adding the giftag, but we don't need that
// Get the frame data for the next distort sprite
SpriteDistortFrameData frame_data = m_sprite_distorter_frame_data.at(sprite_idx);
sprite_idx++;
// Build the OpenGL data for the sprite
math::Vector2f vf03 = frame_data.st;
math::Vector3f vf14 = frame_data.xyz;
// Each slice shares a center vertex, we can use this fact and cut out duplicate vertices
u32 center_vert_idx = m_sprite_distorter_vertices.size();
m_sprite_distorter_vertices.push_back({vf14, vf03});
do {
math::Vector3f vf06 = m_sprite_distorter_sine_tables.entry[entry_index++].xyz();
math::Vector2f vf07 = m_sprite_distorter_sine_tables.entry[entry_index++].xy();
math::Vector3f vf08 = m_sprite_distorter_sine_tables.entry[entry_index + 0].xyz();
math::Vector2f vf09 = m_sprite_distorter_sine_tables.entry[entry_index + 1].xy();
slices_left--;
math::Vector2f vf11 = (vf07 * frame_data.rgba.z()) + frame_data.st;
math::Vector2f vf13 = (vf09 * frame_data.rgba.z()) + frame_data.st;
math::Vector3f vf06_2 = (vf06 * frame_data.rgba.x()) + frame_data.xyz;
math::Vector2f vf07_2 = (vf07 * frame_data.rgba.x()) + frame_data.st;
math::Vector3f vf08_2 = (vf08 * frame_data.rgba.x()) + frame_data.xyz;
math::Vector2f vf09_2 = (vf09 * frame_data.rgba.x()) + frame_data.st;
math::Vector3f vf10 = (vf06 * frame_data.rgba.y()) + frame_data.xyz;
math::Vector3f vf12 = (vf08 * frame_data.rgba.y()) + frame_data.xyz;
math::Vector3f vf06_3 = vf06_2;
math::Vector3f vf08_3 = vf08_2;
m_sprite_distorter_indices.push_back(m_sprite_distorter_vertices.size());
m_sprite_distorter_vertices.push_back({vf06_3, vf07_2});
m_sprite_distorter_indices.push_back(m_sprite_distorter_vertices.size());
m_sprite_distorter_vertices.push_back({vf08_3, vf09_2});
m_sprite_distorter_indices.push_back(m_sprite_distorter_vertices.size());
m_sprite_distorter_vertices.push_back({vf10, vf11});
m_sprite_distorter_indices.push_back(m_sprite_distorter_vertices.size());
m_sprite_distorter_vertices.push_back({vf12, vf13});
// Originally, would add the shared center vertex, but in our case we can just add the index
m_sprite_distorter_indices.push_back(center_vert_idx);
// m_sprite_distorter_vertices.push_back({vf14, vf03});
m_distort_stats.total_tris += 2;
} while (slices_left != 0);
// Mark the end of the triangle strip
m_sprite_distorter_indices.push_back(UINT32_MAX);
sprites_left--;
}
}
/*!
* Sets up OpenGL data for rendering distort sprites using instanced rendering.
*
* A mesh is built once for each possible sprite resolution and is only re-built
* when the dimensions of the window are changed. These meshes are built just like
* the triangle strips in the VU program, but with the sprite-specific data removed.
*
* Required sprite-specific frame data is kept as is and is grouped by resolution.
*/
void Sprite3::distort_setup_instanced(ScopedProfilerNode& /*prof*/) {
if (m_distort_instanced_ogl.last_aspect_x != m_sprite_distorter_sine_tables_aspect.x() ||
m_distort_instanced_ogl.last_aspect_y != m_sprite_distorter_sine_tables_aspect.y()) {
m_distort_instanced_ogl.last_aspect_x = m_sprite_distorter_sine_tables_aspect.x();
m_distort_instanced_ogl.last_aspect_y = m_sprite_distorter_sine_tables_aspect.y();
// Aspect ratio changed, which means we have a new sine table
m_sprite_distorter_vertices_instanced.clear();
// Build a mesh for every possible distort sprite resolution
auto vf03 = math::Vector2f(0, 0);
auto vf14 = math::Vector3f(0, 0, 0);
for (int res = 3; res < 12; res++) {
int entry_index = m_sprite_distorter_sine_tables.ientry[res - 3].x() - 352;
for (int i = 0; i < res; i++) {
math::Vector3f vf06 = m_sprite_distorter_sine_tables.entry[entry_index++].xyz();
math::Vector2f vf07 = m_sprite_distorter_sine_tables.entry[entry_index++].xy();
math::Vector3f vf08 = m_sprite_distorter_sine_tables.entry[entry_index + 0].xyz();
math::Vector2f vf09 = m_sprite_distorter_sine_tables.entry[entry_index + 1].xy();
// Normally, there would be a bunch of transformations here against the sprite data.
// Instead, we'll let the shader do it and just store the sine table specific parts here.
m_sprite_distorter_vertices_instanced.push_back({vf06, vf07});
m_sprite_distorter_vertices_instanced.push_back({vf08, vf09});
m_sprite_distorter_vertices_instanced.push_back({vf06, vf07});
m_sprite_distorter_vertices_instanced.push_back({vf08, vf09});
m_sprite_distorter_vertices_instanced.push_back({vf14, vf03});
}
}
m_distort_instanced_ogl.vertex_data_changed = true;
}
// Set up instance data for each sprite
m_distort_stats.total_tris = 0;
for (auto& [res, vec] : m_sprite_distorter_instances_by_res) {
vec.clear();
}
for (int i = 0; i < m_distort_stats.total_sprites; i++) {
SpriteDistortFrameData frame_data = m_sprite_distorter_frame_data.at(i);
// Shader just needs the position, tex coords, and scale
auto x_y_z_s = math::Vector4f(frame_data.xyz.x(), frame_data.xyz.y(), frame_data.xyz.z(),
frame_data.st.x());
auto sx_sy_sz_t = math::Vector4f(frame_data.rgba.x(), frame_data.rgba.y(), frame_data.rgba.z(),
frame_data.st.y());
int res = frame_data.flag;
m_sprite_distorter_instances_by_res[res].push_back({x_y_z_s, sx_sy_sz_t});
m_distort_stats.total_tris += res * 2;
}
}
/*!
* Draws each distort sprite.
*/
void Sprite3::distort_draw(SharedRenderState* render_state, ScopedProfilerNode& prof) {
// First, make sure the distort framebuffer is the correct size
distort_setup_framebuffer_dims(render_state);
if (m_distort_stats.total_tris == 0) {
// No distort sprites to draw, we can end early
return;
}
// Do common distort drawing logic
distort_draw_common(render_state, prof);
// Set up shader
auto shader = &render_state->shaders[ShaderId::SPRITE_DISTORT];
shader->activate();
Vector4f colorf = Vector4f(m_sprite_distorter_sine_tables.color.x() / 255.0f,
m_sprite_distorter_sine_tables.color.y() / 255.0f,
m_sprite_distorter_sine_tables.color.z() / 255.0f,
m_sprite_distorter_sine_tables.color.w() / 255.0f);
glUniform4fv(glGetUniformLocation(shader->id(), "u_color"), 1, colorf.data());
// Bind vertex array
glBindVertexArray(m_distort_ogl.vao);
// Enable prim restart, we need this to break up the triangle strips
glEnable(GL_PRIMITIVE_RESTART);
glPrimitiveRestartIndex(UINT32_MAX);
// Upload vertex data
glBindBuffer(GL_ARRAY_BUFFER, m_distort_ogl.vertex_buffer);
glBufferData(GL_ARRAY_BUFFER, m_sprite_distorter_vertices.size() * sizeof(SpriteDistortVertex),
m_sprite_distorter_vertices.data(), GL_DYNAMIC_DRAW);
// Upload element data
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_distort_ogl.index_buffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_sprite_distorter_indices.size() * sizeof(u32),
m_sprite_distorter_indices.data(), GL_DYNAMIC_DRAW);
// Draw
prof.add_draw_call();
prof.add_tri(m_distort_stats.total_tris);
glDrawElements(GL_TRIANGLE_STRIP, m_sprite_distorter_indices.size(), GL_UNSIGNED_INT, (void*)0);
// Done
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
/*!
* Draws each distort sprite using instanced rendering.
*/
void Sprite3::distort_draw_instanced(SharedRenderState* render_state, ScopedProfilerNode& prof) {
// First, make sure the distort framebuffer is the correct size
distort_setup_framebuffer_dims(render_state);
if (m_distort_stats.total_tris == 0) {
// No distort sprites to draw, we can end early
return;
}
// Do common distort drawing logic
distort_draw_common(render_state, prof);
// Set up shader
auto shader = &render_state->shaders[ShaderId::SPRITE_DISTORT_INSTANCED];
shader->activate();
Vector4f colorf = Vector4f(m_sprite_distorter_sine_tables.color.x() / 255.0f,
m_sprite_distorter_sine_tables.color.y() / 255.0f,
m_sprite_distorter_sine_tables.color.z() / 255.0f,
m_sprite_distorter_sine_tables.color.w() / 255.0f);
glUniform4fv(glGetUniformLocation(shader->id(), "u_color"), 1, colorf.data());
// Bind vertex array
glBindVertexArray(m_distort_instanced_ogl.vao);
// Upload vertex data (if it changed)
if (m_distort_instanced_ogl.vertex_data_changed) {
m_distort_instanced_ogl.vertex_data_changed = false;
glBindBuffer(GL_ARRAY_BUFFER, m_distort_instanced_ogl.vertex_buffer);
glBufferData(GL_ARRAY_BUFFER,
m_sprite_distorter_vertices_instanced.size() * sizeof(SpriteDistortVertex),
m_sprite_distorter_vertices_instanced.data(), GL_STREAM_DRAW);
}
// Draw each resolution group
glBindBuffer(GL_ARRAY_BUFFER, m_distort_instanced_ogl.instance_buffer);
prof.add_tri(m_distort_stats.total_tris);
int vert_offset = 0;
for (int res = 3; res < 12; res++) {
auto& instances = m_sprite_distorter_instances_by_res[res];
int num_verts = res * 5;
if (instances.size() > 0) {
// Upload instance data
glBufferData(GL_ARRAY_BUFFER, instances.size() * sizeof(SpriteDistortInstanceData),
instances.data(), GL_DYNAMIC_DRAW);
// Draw
prof.add_draw_call();
glDrawArraysInstanced(GL_TRIANGLE_STRIP, vert_offset, num_verts, instances.size());
}
vert_offset += num_verts;
}
// Done
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
void Sprite3::distort_draw_common(SharedRenderState* render_state, ScopedProfilerNode& /*prof*/) {
// The distort effect needs to read the current framebuffer, so copy what's been rendered so far
// to a texture that we can then pass to the shader
glBindFramebuffer(GL_READ_FRAMEBUFFER, render_state->render_fb);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_distort_ogl.fbo);
glBlitFramebuffer(render_state->render_fb_x, // srcX0
render_state->render_fb_y, // srcY0
render_state->render_fb_x + render_state->render_fb_w, // srcX1
render_state->render_fb_y + render_state->render_fb_h, // srcY1
0, // dstX0
0, // dstY0
m_distort_ogl.fbo_width, // dstX1
m_distort_ogl.fbo_height, // dstY1
GL_COLOR_BUFFER_BIT, // mask
GL_NEAREST // filter
);
glBindFramebuffer(GL_FRAMEBUFFER, render_state->render_fb);
// Set up OpenGL state
m_current_mode.set_depth_write_enable(!m_sprite_distorter_setup.zbuf.zmsk()); // zbuf
glBindTexture(GL_TEXTURE_2D, m_distort_ogl.fbo_texture); // tex0
m_current_mode.set_filt_enable(m_sprite_distorter_setup.tex1.mmag()); // tex1
update_mode_from_alpha1(m_sprite_distorter_setup.alpha.data, m_current_mode); // alpha1
// note: clamp and miptbp are skipped since that is set up ahead of time with the distort
// framebuffer texture
setup_opengl_from_draw_mode(m_current_mode, GL_TEXTURE0, false);
}
void Sprite3::distort_setup_framebuffer_dims(SharedRenderState* render_state) {
// Distort framebuffer must be the same dimensions as the default window framebuffer
if (m_distort_ogl.fbo_width != render_state->render_fb_w ||
m_distort_ogl.fbo_height != render_state->render_fb_h) {
m_distort_ogl.fbo_width = render_state->render_fb_w;
m_distort_ogl.fbo_height = render_state->render_fb_h;
glBindTexture(GL_TEXTURE_2D, m_distort_ogl.fbo_texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, m_distort_ogl.fbo_width, m_distort_ogl.fbo_height, 0,
GL_RGB, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_2D, 0);
}
}

View File

@ -0,0 +1,228 @@
#include "game/graphics/opengl_renderer/sprite/Sprite3.h"
struct SpriteGlowData {
float pos[3];
float size_x;
float size_probe;
float z_offset;
float rot_angle;
float size_y;
float color[4];
float fade_a;
float fade_b;
u32 tex_id;
u32 dummy;
};
static_assert(sizeof(SpriteGlowData) == 16 * 4);
/*!
* Transformation math from the sprite-glow vu1 program.
* Populates the SpriteGlowOutput struct with the same data that would get filled into the
* output template on VU1. Excludes float to int conversions.
*
* Not a particularly efficient implementation, but I think the total number of glow sprites is
* small, so not a big deal.
*/
bool glow_math(const SpriteGlowConsts* consts,
const void* vec_data,
const void* adgif_data,
SpriteGlowOutput* out) {
const auto* in = (const SpriteGlowData*)vec_data;
static_assert(sizeof(out->adgif) == 5 * 16);
memcpy(&out->adgif, adgif_data, 5 * 16);
// the transformation here is a bit strange - there's two matrix multiplies.
// one for camera, and one for perspective. Usually they do one, or when they really need both
// for stuff like emerc, they optimize knowing which entires of perspective are always 0.
// But not this time. My guess is that the VU program time is very small compared to actual
// drawing, so they don't really care.
// Transform point to camera frame.
Vector4f p0 = consts->camera[3] + consts->camera[0] * in->pos[0] +
consts->camera[1] * in->pos[1] + consts->camera[2] * in->pos[2];
// Compute fade. Interestingly, the fade is computed based on depth, not distance from the camera.
// I think this is kind of wrong, and it leads to some weird fadeout behavior.
float fade = in->fade_a * p0.z() + in->fade_b; // fade_a is negative
if (fade < 0)
fade = 0;
if (fade > 1)
fade = 1;
// Adjust color based on fade.
Vector4f rgba(in->color[0], in->color[1], in->color[2], in->color[3]);
rgba.x() *= rgba.w() * fade / 128.f;
rgba.y() *= rgba.w() * fade / 128.f;
rgba.z() *= rgba.w() * fade / 128.f;
out->flare_draw_color = rgba;
// Apply an offset. This moves the point along a line between its original position, and the
// camera (so this offset doesn't make the thing move up/down/left/right on screen, just "toward"
// the camera).
float pscale = 1.f - (in->z_offset / p0.z());
p0.x() *= pscale;
p0.y() *= pscale;
p0.z() *= pscale;
// Apply perspective transformation (no divide yet)
p0 = consts->perspective[3] + consts->perspective[0] * p0.x() + consts->perspective[1] * p0.y() +
consts->perspective[2] * p0.z();
// HMGE's meaning is unknown, but it's scaling factors for clipping. Apply those, and reject if
// the origin is off-screen.
Vector4f pos_hmged = p0.elementwise_multiply(consts->hmge);
float clip_plus = std::abs(pos_hmged.w());
float clip_minus = -clip_plus;
if (pos_hmged.x() > clip_plus || pos_hmged.x() < clip_minus)
return false;
if (pos_hmged.y() > clip_plus || pos_hmged.y() < clip_minus)
return false;
if (pos_hmged.z() > clip_plus || pos_hmged.z() < clip_minus)
return false;
// apply perspective divide. Interestingly using hmge's w here...
float perspective_q = 1.f / pos_hmged.w();
p0.x() *= perspective_q;
p0.y() *= perspective_q;
p0.z() *= perspective_q;
out->perspective_q = perspective_q;
// apply offset to final point. These offsets are applied after perspective divide, and are
// required for the PS2 screen coordinates (centered at 2048, 2048).
p0 += consts->hvdf;
// from this point on, things are in screen coordinates. So our sizes (not screen coordinates)
// should be scaled by q to become sizes in screen coordinates.
Vector4f vf02(in->size_probe, in->z_offset, in->size_x, in->size_y);
vf02 *= perspective_q;
// clamp the probe size to be in (1, clamp_max.w)
if (vf02.x() < 1)
vf02.x() = 1; // size_probe
if (vf02.x() > consts->clamp_max.w())
vf02.x() = consts->clamp_max.w(); // size probe
// clamp the maximum size_x/size_y to clamp_max.z
if (vf02.z() > consts->clamp_max.z())
vf02.z() = consts->clamp_max.z(); // size x
if (vf02.w() > consts->clamp_max.z())
vf02.w() = consts->clamp_max.z(); // size y
// compute the minimum safe position for the center of the probe, so corner ends up at min/max
math::Vector2f vf09_min_probe_center(consts->clamp_min.x() + vf02.x(),
consts->clamp_min.y() + vf02.x());
math::Vector2f vf10_max_probe_center(consts->clamp_max.x() - vf02.x(),
consts->clamp_max.y() - vf02.x());
// clear corners. these don't have rotation applied, I guess (vf11, vf12)
out->second_clear_pos[0] = Vector4f(p0.x() - vf02.x(), p0.y() - vf02.x(), p0.z(), p0.w());
out->second_clear_pos[1] = Vector4f(p0.x() + vf02.x(), p0.y() + vf02.x(), p0.z(), p0.w());
// compute offset from center of sprite to corner. This includes the rotation
math::Vector2f basis_x(consts->basis_x[0], 0); // x scaling factor
math::Vector2f basis_y(0, consts->basis_y[1]); // y scarling factor
// rotate them
float rot_rad = in->rot_angle * consts->deg_to_rad;
float rot_sin = std::sin(rot_rad);
float rot_cos = std::cos(rot_rad);
math::Vector2f vf15_rotated_basis_x = basis_x * rot_sin - basis_y * rot_cos;
math::Vector2f vf16_rotated_basis_y = basis_x * rot_cos + basis_y * rot_sin;
vf15_rotated_basis_x *= vf02.z(); // scale x
vf16_rotated_basis_y *= vf02.w(); // scale y
// limit position so the clear doesn't go out of bounds
// max.xy vf20, vf01, vf09 -> is this bugged? I think the x broadcast here is wrong
// this breaks fadeout as the sprite moves off the top of the screen. I've fixed it here because
// I'm pretty sure this is just a mistake.
math::Vector2f vf20_pos(std::max(p0.x(), vf09_min_probe_center.x()),
std::max(p0.y(), vf09_min_probe_center.y()));
vf20_pos.min_in_place(vf10_max_probe_center);
// vf17 thing, vf18 thing
math::Vector2f vf17(consts->clamp_min.x() - 1, consts->clamp_min.y() - 1);
math::Vector2f vf18(consts->clamp_min.x() + 1, consts->clamp_min.y() + 1);
vf17 = vf20_pos - vf17;
vf17 -= vf02.x();
vf18 = vf20_pos - vf18;
vf18 += vf02.x();
out->offscreen_uv[0] = vf17;
out->offscreen_uv[1] = vf18;
out->first_clear_pos[0] =
Vector4f(vf20_pos.x() - vf02.x() - 1, vf20_pos.y() - vf02.x() - 1, 0xffffff, p0.w());
out->first_clear_pos[1] =
Vector4f(vf20_pos.x() + vf02.x() + 1, vf20_pos.y() + vf02.x() + 1, 0xffffff, p0.w());
// mulaw.xyzw ACC, vf01, vf00
// maddax.xyzw ACC, vf15, vf11
// maddy.xyzw vf11, vf16, vf11
for (int i = 0; i < 4; i++) {
out->flare_xyzw[i] = p0;
math::Vector2f off = (vf15_rotated_basis_x * consts->xy_array[i].x()) +
(vf16_rotated_basis_y * consts->xy_array[i].y());
out->flare_xyzw[i].x() += off.x();
out->flare_xyzw[i].y() += off.y();
}
return true;
}
/*!
* Handle glow dma and draw glow sprites using GlowRenderer
*/
void Sprite3::glow_dma_and_draw(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
auto maybe_consts_setup = dma.read_and_advance();
if (maybe_consts_setup.size_bytes != sizeof(SpriteGlowConsts)) {
fmt::print("no consts...\n");
return;
}
SpriteGlowConsts consts;
memcpy(&consts, maybe_consts_setup.data, sizeof(SpriteGlowConsts));
auto templ_1 = dma.read_and_advance();
ASSERT(templ_1.size_bytes == 16 * 0x54);
auto templ_2 = dma.read_and_advance();
ASSERT(templ_2.size_bytes == 16 * 0x54);
auto bo = dma.read_and_advance();
ASSERT(bo.size_bytes == 0);
auto flushe = dma.read_and_advance();
ASSERT(flushe.size_bytes == 0);
auto control_xfer = dma.read_and_advance();
while (control_xfer.size_bytes == 0 && control_xfer.vifcode0().kind == VifCode::Kind::NOP &&
control_xfer.vifcode1().kind == VifCode::Kind::NOP) {
control_xfer = dma.read_and_advance();
}
while (control_xfer.size_bytes == 16) {
auto vecdata_xfer = dma.read_and_advance();
auto shader_xfer = dma.read_and_advance();
auto call = dma.read_and_advance();
(void)call;
u32 num_sprites;
memcpy(&num_sprites, control_xfer.data, 4);
ASSERT(num_sprites == 1); // always, for whatever reason.
ASSERT(vecdata_xfer.size_bytes == 4 * 16);
ASSERT(shader_xfer.size_bytes == 5 * 16);
auto* out = m_glow_renderer.alloc_sprite();
if (!glow_math(&consts, vecdata_xfer.data, shader_xfer.data, out)) {
m_glow_renderer.cancel_sprite();
}
control_xfer = dma.read_and_advance();
while (control_xfer.size_bytes == 0 && control_xfer.vifcode0().kind == VifCode::Kind::NOP &&
control_xfer.vifcode1().kind == VifCode::Kind::NOP) {
control_xfer = dma.read_and_advance();
}
}
m_glow_renderer.flush(render_state, prof);
}

View File

@ -5,7 +5,7 @@
#include "game/graphics/opengl_renderer/BucketRenderer.h"
#include "game/graphics/opengl_renderer/DirectRenderer.h"
#include "game/graphics/opengl_renderer/sprite_common.h"
#include "game/graphics/opengl_renderer/sprite/sprite_common.h"
class SpriteRenderer : public BucketRenderer {
public:

View File

@ -210,3 +210,34 @@ enum SpriteProgMem {
static_assert(offsetof(SpriteFrameData, hmge_scale) == 256);
static_assert(sizeof(SpriteFrameDataJak1) == 0x290, "SpriteFrameData size");
static_assert(sizeof(SpriteFrameData) == 0x2a0, "SpriteFrameData size");
/*!
* Post-transformation description of a sprite glow - passed to the GlowRenderer.
*/
struct SpriteGlowOutput {
math::Vector4f first_clear_pos[2]; // 8, 9
math::Vector4f second_clear_pos[2]; // 11, 12 corners for the second clear draw
math::Vector2f offscreen_uv[2]; // 24, 26
math::Vector4f flare_xyzw[4];
AdGifData adgif; // 68, 69, 70, 71, 72
math::Vector4f flare_draw_color; // 75
float perspective_q;
};
struct SpriteGlowConsts {
math::Vector4f camera[4];
math::Vector4f perspective[4];
math::Vector4f hvdf;
math::Vector4f hmge;
float pfog0;
float deg_to_rad;
float min_scale;
float inv_area;
math::Vector4f sincos[5];
math::Vector4f basis_x;
math::Vector4f basis_y;
math::Vector4f xy_array[4];
math::Vector4f clamp_min;
math::Vector4f clamp_max;
};
static_assert(sizeof(SpriteGlowConsts) == 0x180);

View File

@ -1805,7 +1805,7 @@
(when (not (paused?))
(clear *stdcon1*)
(debug-reset-buffers)
;(clear! *simple-sprite-system*)
(clear! *simple-sprite-system*)
)
(set! (-> s5-1 bucket-group) (dma-buffer-add-buckets (-> s5-1 calc-buf) 327))
)

View File

@ -79,6 +79,7 @@
(signal 96)
(finish 97)
(label 98)
(hack 127)
)
(defenum gs-reg64

View File

@ -19,6 +19,7 @@
(fade-b float :offset-assert 52)
(tex-id texture-id :offset-assert 56)
(dummy uint32 :offset-assert 60)
(quads vector 4 :inline :offset 0)
)
:method-count-assert 10
:size-assert #x40
@ -41,14 +42,14 @@
(deftype simple-sprite-system (structure)
((count int16 :offset-assert 0)
(max-count int16 :offset-assert 2)
(data sprite-glow-data :offset-assert 4)
(data (inline-array sprite-glow-data) :offset-assert 4)
)
:method-count-assert 12
:size-assert #x8
:flag-assert #xc00000008
(:methods
(add! (_type_ dma-buffer) none 9)
(simple-sprite-system-method-10 (_type_ dma-buffer) none 10)
(add! (_type_ sprite-glow-data) none 9)
(draw-all-sprites! (_type_ dma-buffer) none 10)
(clear! (_type_) none 11)
)
)

View File

@ -7,3 +7,790 @@
;; DECOMP BEGINS
(deftype sprite-glow-template (structure)
((clear-init-giftag gs-gif-tag :inline :offset-assert 0)
(clear-init-adcmds gs-adcmd 5 :inline :offset-assert 16)
(clear-draw-giftag gs-gif-tag :inline :offset-assert 96)
(clear-draw-clr-0 gs-packed-rgba :inline :offset-assert 112)
(clear-draw-xyz-0 gs-packed-xyzw 2 :inline :offset-assert 128) ;; 8
(clear-draw-clr-1 gs-packed-rgba :inline :offset-assert 160)
(clear-draw-xyz-1 vector 2 :inline :offset-assert 176) ;; 11
(offscr-setup-giftag gs-gif-tag :inline :offset-assert 208) ;; 13
(offscr-setup-adcmds gs-adcmd 8 :inline :offset-assert 224)
(offscr-first-giftag gs-gif-tag :inline :offset-assert 352)
(offscr-first-clr gs-packed-rgba :inline :offset-assert 368)
(offscr-first-uv-0 gs-packed-uv :inline :offset-assert 384) ;; 24
(offscr-first-xyzw-0 gs-packed-xyzw :inline :offset-assert 400)
(offscr-first-uv-1 gs-packed-uv :inline :offset-assert 416) ;; 26
(offscr-first-xyzw-1 gs-packed-xyzw :inline :offset-assert 432)
(repeat-draw-giftag gs-gif-tag :inline :offset-assert 448) ;; 28
(repeat-draw-adcmds gs-adcmd 29 :inline :offset-assert 464)
(flare-alpha-giftag gs-gif-tag :inline :offset-assert 928) ;; 58
(flare-alpha-clr gs-packed-rgba :inline :offset-assert 944)
(flare-alpha-uv gs-packed-uv :inline :offset-assert 960)
(flare-alpha-xyzw-0 gs-packed-xyzw :inline :offset-assert 976) ;; 61
(flare-alpha-xyzw-1 gs-packed-xyzw :inline :offset-assert 992)
(flare-alpha-xyzw-2 gs-packed-xyzw :inline :offset-assert 1008)
(flare-alpha-xyzw-3 gs-packed-xyzw :inline :offset-assert 1024)
(flare-init-giftag gs-gif-tag :inline :offset-assert 1040) ;; 65
(flare-init-adcmds gs-adcmd 8 :inline :offset-assert 1056)
(flare-draw-giftag gs-gif-tag :inline :offset-assert 1184) ;; 74
(flare-draw-clr gs-packed-rgba :inline :offset-assert 1200)
(flare-draw-stq-0 gs-packed-stq :inline :offset-assert 1216)
(flare-draw-xyzw-0 gs-packed-xyzw :inline :offset-assert 1232) ;; 77
(flare-draw-stq-1 gs-packed-stq :inline :offset-assert 1248)
(flare-draw-xyzw-1 gs-packed-xyzw :inline :offset-assert 1264)
(flare-draw-stq-2 gs-packed-stq :inline :offset-assert 1280)
(flare-draw-xyzw-2 gs-packed-xyzw :inline :offset-assert 1296)
(flare-draw-stq-3 gs-packed-stq :inline :offset-assert 1312)
(flare-draw-xyzw-3 gs-packed-xyzw :inline :offset-assert 1328)
)
:method-count-assert 9
:size-assert #x540
:flag-assert #x900000540
)
(deftype sprite-glow-consts (structure)
((camera matrix :inline :offset-assert 0)
(perspective matrix :inline :offset-assert 64)
(hvdf-offset vector :inline :offset-assert 128)
(hmge-scale vector :inline :offset-assert 144)
(consts vector :inline :offset-assert 160)
(pfog0 float :offset 160)
(deg-to-rad float :offset 164)
(min-scale float :offset 168)
(inv-area float :offset 172)
(sincos-01 vector :inline :offset-assert 176)
(sincos-23 vector :inline :offset-assert 192)
(sincos-45 vector :inline :offset-assert 208)
(sincos-67 vector :inline :offset-assert 224)
(sincos-89 vector :inline :offset-assert 240)
(basis-x vector :inline :offset-assert 256)
(basis-y vector :inline :offset-assert 272)
(xy-array vector 4 :inline :offset-assert 288)
(clamp-min vector :inline :offset-assert 352)
(clamp-max vector :inline :offset-assert 368)
)
:method-count-assert 9
:size-assert #x180
:flag-assert #x900000180
)
(define *sprite-glow-template*
(new 'static 'sprite-glow-template
:clear-init-giftag (new 'static 'gs-gif-tag
:tag (new 'static 'gif-tag64 :nloop #x5 :nreg #x1)
:regs (new 'static 'gif-tag-regs :regs0 (gif-reg-id a+d))
)
:clear-init-adcmds (new 'static 'inline-array gs-adcmd 5
(new 'static 'gs-adcmd :cmds (gs-reg64 texflush))
;; (new 'static 'gs-alpha :a 2 :b 2 :c 2 :d 1)
(new 'static 'gs-adcmd :cmds (gs-reg64 alpha-1) :x #x6a)
;; (new 'static 'gs-test :ate 1 :afail 1 :zte 1 :ztst 2)
(new 'static 'gs-adcmd :cmds (gs-reg64 test-1) :x #x51001)
;; (new 'static 'gs-zbuf :zbp 304 :psm 1 :zmsk 1)
(new 'static 'gs-adcmd :cmds (gs-reg64 zbuf-1) :x #x1000130 :y #x1)
;; (new 'static 'gs-frame :fbp 408 :fbw 8 :fbmsk #xffffff)
(new 'static 'gs-adcmd :cmds (gs-reg64 frame-1) :x #x80198 :y #xffffff)
)
:clear-draw-giftag (new 'static 'gs-gif-tag
:tag (new 'static 'gif-tag64
:nloop #x2
:pre #x1
:prim (new 'static 'gs-prim :prim (gs-prim-type sprite))
:nreg #x3
)
:regs (new 'static 'gif-tag-regs :regs0 (gif-reg-id rgbaq) :regs1 (gif-reg-id xyzf2) :regs2 (gif-reg-id xyzf2))
)
:clear-draw-xyz-0 (new 'static 'inline-array gs-packed-xyzw 2
(new 'static 'gs-packed-xyzw :iz -1)
(new 'static 'gs-packed-xyzw :iz -1)
)
:clear-draw-clr-1 (new 'static 'gs-packed-rgba :x #xff :w #xff)
:offscr-setup-giftag (new 'static 'gs-gif-tag
:tag (new 'static 'gif-tag64 :nloop #x8 :nreg #x1)
:regs (new 'static 'gif-tag-regs :regs0 (gif-reg-id a+d))
)
:offscr-setup-adcmds (new 'static 'inline-array gs-adcmd 8
;; (new 'static 'gs-frame :fbp 144 :fbw 1 :fbmsk #xffffff)
(new 'static 'gs-adcmd :cmds (gs-reg64 frame-2) :x #x10090 :y #xffffff)
;; (new 'static 'gs-zbuf :zbp 304 :psm 1)
(new 'static 'gs-adcmd :cmds (gs-reg64 zbuf-2) :x #x1000130)
;; mmag/mmin on
(new 'static 'gs-adcmd :cmds (gs-reg64 tex1-2) :x #x60)
;; (new 'static 'gs-tex0 :tbp0 #x3300 :tbw 8 :tw 9 :th 9 :tcc 1 :tfx 1)
(new 'static 'gs-adcmd :cmds (gs-reg64 tex0-2) :x #x64023300 :y #xe)
;; wms, wmt both 1
(new 'static 'gs-adcmd :cmds (gs-reg64 clamp-2) :x #x5)
;; ate 1, afail 1, zte 1, ztst 1
(new 'static 'gs-adcmd :cmds (gs-reg64 test-2) :x #x31001)
(new 'static 'gs-adcmd :cmds (gs-reg64 xyoffset-2))
(new 'static 'gs-adcmd :cmds (gs-reg64 texflush))
)
:offscr-first-giftag (new 'static 'gs-gif-tag
:tag (new 'static 'gif-tag64
:nloop #x1
:pre #x1
:prim (new 'static 'gs-prim :prim (gs-prim-type sprite) :tme #x1 :fst #x1 :ctxt #x1)
:nreg #x5
)
:regs (new 'static 'gif-tag-regs
:regs0 (gif-reg-id rgbaq)
:regs1 (gif-reg-id uv)
:regs2 (gif-reg-id xyz2)
:regs3 (gif-reg-id uv)
:regs4 (gif-reg-id xyz2)
)
)
:offscr-first-clr (new 'static 'gs-packed-rgba :x #x80 :y #x80 :z #x80 :w #x80)
:offscr-first-xyzw-1 (new 'static 'gs-packed-xyzw :ix #x200 :iy #x200)
:repeat-draw-giftag (new 'static 'gs-gif-tag
:tag (new 'static 'gif-tag64 :nloop #x1d :nreg #x1)
:regs (new 'static 'gif-tag-regs :regs0 (gif-reg-id a+d))
)
:repeat-draw-adcmds (new 'static 'inline-array gs-adcmd 29
;; tbp: 0x1200, tbw 1, tw = 5, th = 5, tcc = 1, tfx = 1
(new 'static 'gs-adcmd :cmds (gs-reg64 tex0-2) :x #x54005200 :y #xd)
(new 'static 'gs-adcmd :cmds (gs-reg64 texflush))
(new 'static 'gs-adcmd :cmds (gs-reg64 uv) :x #x100010)
(new 'static 'gs-adcmd :cmds (gs-reg64 xyz2))
(new 'static 'gs-adcmd :cmds (gs-reg64 uv) :x #x2100210)
(new 'static 'gs-adcmd :cmds (gs-reg64 xyz2) :x #x1000100)
(new 'static 'gs-adcmd :cmds (gs-reg64 texflush))
(new 'static 'gs-adcmd :cmds (gs-reg64 uv) :x #x100010)
(new 'static 'gs-adcmd :cmds (gs-reg64 xyz2))
(new 'static 'gs-adcmd :cmds (gs-reg64 uv) :x #x1100110)
(new 'static 'gs-adcmd :cmds (gs-reg64 xyz2) :x #x800080)
(new 'static 'gs-adcmd :cmds (gs-reg64 texflush))
(new 'static 'gs-adcmd :cmds (gs-reg64 uv) :x #x100010)
(new 'static 'gs-adcmd :cmds (gs-reg64 xyz2))
(new 'static 'gs-adcmd :cmds (gs-reg64 uv) :x #x900090)
(new 'static 'gs-adcmd :cmds (gs-reg64 xyz2) :x #x400040)
(new 'static 'gs-adcmd :cmds (gs-reg64 texflush))
(new 'static 'gs-adcmd :cmds (gs-reg64 uv) :x #x100010)
(new 'static 'gs-adcmd :cmds (gs-reg64 xyz2))
(new 'static 'gs-adcmd :cmds (gs-reg64 uv) :x #x500050)
(new 'static 'gs-adcmd :cmds (gs-reg64 xyz2) :x #x200020)
;; fbp = 408, fbw = 8 (normal screen drawing)
(new 'static 'gs-adcmd :cmds (gs-reg64 frame-2) :x #x80198 :y #xffffff)
;; (new 'static 'gs-test :ate 1 :afail 1 :zte 1 :ztst 2)
(new 'static 'gs-adcmd :cmds (gs-reg64 test-2) :x #x51001)
;; (new 'static 'gs-zbuf :zbp 304 :psm 1 :zmsk 1)
(new 'static 'gs-adcmd :cmds (gs-reg64 zbuf-2) :x #x1000130 :y #x1)
(new 'static 'gs-adcmd :cmds (gs-reg64 xyoffset-2) :x #x7000 :y #x7300)
(new 'static 'gs-adcmd :cmds (gs-reg64 scissor-2) :x #x1ff0000 :y #x19f0000)
;; zte = 1, ztst = 2
(new 'static 'gs-adcmd :cmds (gs-reg64 test-2) :x #x50000)
;; (new 'static 'gs-alpha :a 2 :b 2 :c 2 :d 1)
(new 'static 'gs-adcmd :cmds (gs-reg64 alpha-2) :x #x6a)
(new 'static 'gs-adcmd :cmds (gs-reg64 texflush))
)
:flare-alpha-giftag (new 'static 'gs-gif-tag
:tag (new 'static 'gif-tag64
:nloop #x1
:pre #x1
:prim (new 'static 'gs-prim :prim (gs-prim-type tri-fan) :tme #x1 :fst #x1 :ctxt #x1)
:nreg #x6
)
:regs (new 'static 'gif-tag-regs
:regs0 (gif-reg-id rgbaq)
:regs1 (gif-reg-id uv)
:regs2 (gif-reg-id xyzf2)
:regs3 (gif-reg-id xyzf2)
:regs4 (gif-reg-id xyzf2)
:regs5 (gif-reg-id xyzf2)
)
)
:flare-alpha-clr (new 'static 'gs-packed-rgba :x #x80 :y #x80 :z #x80 :w #x80)
:flare-alpha-uv (new 'static 'gs-packed-uv :x (the-as float #x10) :y (the-as float #x10))
:flare-alpha-xyzw-0 (new 'static 'gs-packed-xyzw :iz -1)
:flare-alpha-xyzw-1 (new 'static 'gs-packed-xyzw :iz -1)
:flare-alpha-xyzw-2 (new 'static 'gs-packed-xyzw :iz -1)
:flare-alpha-xyzw-3 (new 'static 'gs-packed-xyzw :iz -1)
:flare-init-giftag (new 'static 'gs-gif-tag
:tag (new 'static 'gif-tag64 :nloop #x8 :nreg #x1)
:regs (new 'static 'gif-tag-regs :regs0 (gif-reg-id a+d))
)
:flare-init-adcmds (new 'static 'inline-array gs-adcmd 8
(new 'static 'gs-adcmd :cmds (gs-reg64 texflush))
;; normal frame, no mask
(new 'static 'gs-adcmd :cmds (gs-reg64 frame-1) :x #x80198)
(new 'static 'gs-adcmd :cmds (gs-reg64 hack))
(new 'static 'gs-adcmd :cmds (gs-reg64 hack))
(new 'static 'gs-adcmd :cmds (gs-reg64 hack))
(new 'static 'gs-adcmd :cmds (gs-reg64 hack))
(new 'static 'gs-adcmd :cmds (gs-reg64 hack))
;; a = 0, b = 2, c = 1, d = 1
(new 'static 'gs-adcmd :cmds (gs-reg64 alpha-1) :x #x58)
)
:flare-draw-giftag (new 'static 'gs-gif-tag
:tag (new 'static 'gif-tag64
:nloop #x1
:eop #x1
:pre #x1
:prim (new 'static 'gs-prim :prim (gs-prim-type tri-fan) :tme #x1 :abe #x1)
:nreg #x9
)
:regs (new 'static 'gif-tag-regs
:regs0 (gif-reg-id rgbaq)
:regs1 (gif-reg-id st)
:regs2 (gif-reg-id xyzf2)
:regs3 (gif-reg-id st)
:regs4 (gif-reg-id xyzf2)
:regs5 (gif-reg-id st)
:regs6 (gif-reg-id xyzf2)
:regs7 (gif-reg-id st)
:regs8 (gif-reg-id xyzf2)
)
)
:flare-draw-clr (new 'static 'gs-packed-rgba :y 64 :w #x80)
:flare-draw-stq-0 (new 'static 'gs-packed-stq :z 1.0)
:flare-draw-xyzw-0 (new 'static 'gs-packed-xyzw :iz -1)
:flare-draw-stq-1 (new 'static 'gs-packed-stq :x 1.0 :z 1.0)
:flare-draw-xyzw-1 (new 'static 'gs-packed-xyzw :iz -1)
:flare-draw-stq-2 (new 'static 'gs-packed-stq :x 1.0 :y 1.0 :z 1.0)
:flare-draw-xyzw-2 (new 'static 'gs-packed-xyzw :iz -1)
:flare-draw-stq-3 (new 'static 'gs-packed-stq :y 1.0 :z 1.0)
:flare-draw-xyzw-3 (new 'static 'gs-packed-xyzw :iz -1)
)
)
(define sprite-glow-vu1-block (new 'static 'vu-function #|:length #x86 :qlength 67|#))
;; WARN: Return type mismatch vector vs none.
(defun sprite-glow-init-consts ((arg0 sprite-glow-consts))
(let ((v1-0 *math-camera*))
(let* ((t0-0 (-> arg0 camera))
(t1-0 (-> v1-0 camera-rot))
(a1-0 (-> t1-0 quad 0))
(a2-0 (-> t1-0 quad 1))
(a3-0 (-> t1-0 quad 2))
(t1-1 (-> t1-0 trans quad))
)
(set! (-> t0-0 quad 0) a1-0)
(set! (-> t0-0 quad 1) a2-0)
(set! (-> t0-0 quad 2) a3-0)
(set! (-> t0-0 trans quad) t1-1)
)
(let* ((t0-1 (-> arg0 perspective))
(t1-2 (-> v1-0 perspective))
(a1-1 (-> t1-2 quad 0))
(a2-1 (-> t1-2 quad 1))
(a3-1 (-> t1-2 quad 2))
(t1-3 (-> t1-2 trans quad))
)
(set! (-> t0-1 quad 0) a1-1)
(set! (-> t0-1 quad 1) a2-1)
(set! (-> t0-1 quad 2) a3-1)
(set! (-> t0-1 trans quad) t1-3)
)
(set! (-> arg0 hvdf-offset quad) (-> v1-0 hvdf-off quad))
(set! (-> arg0 hmge-scale quad) (-> v1-0 hmge-scale quad))
(set! (-> arg0 basis-x quad) (the-as uint128 0))
(set! (-> arg0 basis-x x) (- (-> *math-camera* perspective vector 0 x)))
(set! (-> arg0 basis-y quad) (the-as uint128 0))
(set! (-> arg0 basis-y y) (- (-> *math-camera* perspective vector 1 y)))
(set! (-> arg0 pfog0) (-> v1-0 pfog0))
)
(set! (-> arg0 deg-to-rad) 0.000095873795)
(set! (-> arg0 min-scale) (sqrtf (* (/ 1.0 (-> arg0 basis-x x)) (/ 1.0 (-> arg0 basis-y y)))))
(set! (-> arg0 inv-area) (/ 1.0 (* (-> arg0 min-scale) (-> arg0 min-scale))))
(let ((v1-5 (-> arg0 sincos-01)))
(set! (-> v1-5 z) 0.999998)
(set! (-> v1-5 w) 1.0)
)
(let ((v1-6 (-> arg0 sincos-23)))
(set! (-> v1-6 z) -0.16666014)
(set! (-> v1-6 w) -0.49998003)
)
(let ((v1-7 (-> arg0 sincos-45)))
(set! (-> v1-7 z) 0.008326521)
(set! (-> v1-7 w) 0.041620404)
)
(let ((v1-8 (-> arg0 sincos-67)))
(set! (-> v1-8 z) -0.0001956241)
(set! (-> v1-8 w) -0.0013636408)
)
(let ((v1-9 (-> arg0 sincos-89)))
(set! (-> v1-9 z) 0.0000023042373)
(set! (-> v1-9 w) 0.000020170546)
)
(set-vector! (-> arg0 xy-array 0) -0.5 -0.5 0.0 0.0)
(set-vector! (-> arg0 xy-array 1) 0.5 -0.5 0.0 0.0)
(set-vector! (-> arg0 xy-array 2) 0.5 0.5 0.0 0.0)
(set-vector! (-> arg0 xy-array 3) -0.5 0.5 0.0 0.0)
(set-vector! (-> arg0 clamp-min) 1792.0 1840.0 0.0 0.0)
(set-vector! (-> arg0 clamp-max) 2304.0 2256.0 2048.0 50.0)
(none)
)
(defun sprite-glow-init-engine ((arg0 dma-buffer))
(dma-buffer-add-vu-function arg0 sprite-glow-vu1-block 1)
(let ((s5-0 24))
(let* ((v1-0 arg0)
(a0-2 (the-as dma-packet (-> v1-0 base)))
)
(set! (-> a0-2 dma) (new 'static 'dma-tag :id (dma-tag-id cnt) :qwc s5-0))
(set! (-> a0-2 vif0) (new 'static 'vif-tag :imm #x404 :cmd (vif-cmd stcycl)))
(set! (-> a0-2 vif1) (new 'static 'vif-tag :imm #x3d4 :cmd (vif-cmd unpack-v4-32) :num s5-0))
(set! (-> v1-0 base) (the-as pointer (&+ a0-2 16)))
)
(sprite-glow-init-consts (the-as sprite-glow-consts (-> arg0 base)))
(&+! (-> arg0 base) (* s5-0 16))
)
(let ((v1-3 84))
(let* ((a0-6 arg0)
(a1-6 (the-as dma-packet (-> a0-6 base)))
)
(set! (-> a1-6 dma)
(new 'static 'dma-tag :id (dma-tag-id ref) :addr (the-as int *sprite-glow-template*) :qwc v1-3)
)
(set! (-> a1-6 vif0) (new 'static 'vif-tag :imm #x404 :cmd (vif-cmd stcycl)))
(set! (-> a1-6 vif1) (new 'static 'vif-tag :imm #x320 :cmd (vif-cmd unpack-v4-32) :num v1-3))
(set! (-> a0-6 base) (the-as pointer (&+ a1-6 16)))
)
(let* ((a0-7 arg0)
(a1-8 (the-as dma-packet (-> a0-7 base)))
)
(set! (-> a1-8 dma)
(new 'static 'dma-tag :id (dma-tag-id ref) :addr (the-as int *sprite-glow-template*) :qwc v1-3)
)
(set! (-> a1-8 vif0) (new 'static 'vif-tag :cmd (vif-cmd mscal) :msk #x1 :imm #x0))
(set! (-> a1-8 vif1) (new 'static 'vif-tag :imm #x374 :cmd (vif-cmd unpack-v4-32) :num v1-3))
(set! (-> a0-7 base) (the-as pointer (&+ a1-8 16)))
)
)
(let* ((v1-8 arg0)
(a0-8 (the-as dma-packet (-> v1-8 base)))
)
(set! (-> a0-8 dma) (new 'static 'dma-tag :id (dma-tag-id cnt)))
(set! (-> a0-8 vif0) (new 'static 'vif-tag :cmd (vif-cmd base)))
(set! (-> a0-8 vif1) (new 'static 'vif-tag :imm #x190 :cmd (vif-cmd offset)))
(set! (-> v1-8 base) (the-as pointer (&+ a0-8 16)))
)
(let ((v1-9 (the-as dma-packet (-> arg0 base))))
(set! (-> v1-9 dma) (new 'static 'dma-tag :id (dma-tag-id cnt)))
(set! (-> v1-9 vif0) (new 'static 'vif-tag))
(set! (-> v1-9 vif1) (new 'static 'vif-tag :cmd (vif-cmd flushe) :msk #x1))
(set! (-> arg0 base) (the-as pointer (&+ v1-9 16)))
)
0
(none)
)
(deftype sprite-glow-dma-packet-data (structure)
((control-packet dma-packet :inline :offset-assert 0)
(vecdata-packet dma-packet :inline :offset-assert 16)
(shader-cnt-packet dma-packet :inline :offset-assert 32)
(shader-ref-packet dma-packet :inline :offset-assert 48)
(mscal-packet dma-packet :inline :offset-assert 64)
)
:method-count-assert 9
:size-assert #x50
:flag-assert #x900000050
)
(deftype sprite-glow-cnt-template (structure)
((control-packet dma-packet :inline :offset-assert 0)
(num-sprites uint32 :offset-assert 16)
(dummys uint32 3 :offset-assert 20)
(num-sprites-quad uint128 :offset 16)
(vecdata-packet dma-packet :inline :offset-assert 32)
(vecdata sprite-glow-data :inline :offset-assert 48)
(shader-packet dma-packet :inline :offset-assert 112)
(shader adgif-shader :inline :offset-assert 128)
(mscal-packet dma-packet :inline :offset-assert 208)
)
:method-count-assert 9
:size-assert #xe0
:flag-assert #x9000000e0
)
(deftype sprite-glow-ref-template (structure)
((control-packet dma-packet :inline :offset-assert 0)
(num-sprites uint32 :offset-assert 16)
(dummys uint32 3 :offset-assert 20)
(num-sprites-quad uint128 :offset 16)
(vecdata-packet dma-packet :inline :offset-assert 32)
(vecdata sprite-glow-data :inline :offset-assert 48)
(shader-packet dma-packet :inline :offset-assert 112)
(shader-packet-ptr pointer :offset 116)
(mscal-packet dma-packet :inline :offset-assert 128)
)
:method-count-assert 9
:size-assert #x90
:flag-assert #x900000090
)
(define *sprite-glow-dma-packet-data*
(new 'static 'sprite-glow-dma-packet-data
:control-packet (new 'static 'dma-packet
:dma (new 'static 'dma-tag :qwc #x1 :id (dma-tag-id cnt))
:vif0 (new 'static 'vif-tag :imm #x404 :cmd (vif-cmd stcycl))
:vif1 (new 'static 'vif-tag :imm #x8000 :num #x1 :cmd (vif-cmd unpack-v4-32))
)
:vecdata-packet (new 'static 'dma-packet
:dma (new 'static 'dma-tag :qwc #x4 :id (dma-tag-id cnt))
:vif0 (new 'static 'vif-tag :imm #x404 :cmd (vif-cmd stcycl))
:vif1 (new 'static 'vif-tag :imm #x8001 :num #x4 :cmd (vif-cmd unpack-v4-32))
)
:shader-cnt-packet (new 'static 'dma-packet
:dma (new 'static 'dma-tag :qwc #x5 :id (dma-tag-id cnt))
:vif0 (new 'static 'vif-tag :imm #x404 :cmd (vif-cmd stcycl))
:vif1 (new 'static 'vif-tag :imm #x8091 :num #x5 :cmd (vif-cmd unpack-v4-32))
)
:shader-ref-packet (new 'static 'dma-packet
:dma (new 'static 'dma-tag :qwc #x5 :id (dma-tag-id ref))
:vif0 (new 'static 'vif-tag :imm #x404 :cmd (vif-cmd stcycl))
:vif1 (new 'static 'vif-tag :imm #x8091 :num #x5 :cmd (vif-cmd unpack-v4-32))
)
:mscal-packet (new 'static 'dma-packet
:dma (new 'static 'dma-tag :id (dma-tag-id cnt))
:vif1 (new 'static 'vif-tag :cmd (vif-cmd flushe) :msk #x1)
)
)
)
(set! (-> *sprite-glow-dma-packet-data* mscal-packet vif0)
(new 'static 'vif-tag :cmd (vif-cmd mscalf) :msk #x1 :imm #xa)
)
;; WARN: Return type mismatch sprite-glow-cnt-template vs none.
(defun sprite-glow-add-sprite ((arg0 dma-buffer) (arg1 sprite-vec-data-2d) (arg2 float) (arg3 float) (arg4 float) (arg5 adgif-shader))
(let ((v1-0 (the-as sprite-glow-cnt-template (-> arg0 base))))
(let* ((t5-0 *sprite-glow-dma-packet-data*)
(t2-0 (-> t5-0 control-packet quad))
(t3-0 (-> t5-0 vecdata-packet quad))
(t4-0 (-> t5-0 shader-cnt-packet quad))
(t5-1 (-> t5-0 mscal-packet quad))
)
(set! (-> v1-0 control-packet quad) t2-0)
(set! (-> v1-0 num-sprites-quad) (the-as uint128 0))
(set! (-> v1-0 vecdata-packet quad) t3-0)
(set! (-> v1-0 shader-packet quad) t4-0)
(set! (-> v1-0 mscal-packet quad) t5-1)
)
(let ((t2-1 (-> arg1 x-y-z-sx quad))
(t3-1 (-> arg1 flag-rot-sy quad))
(a1-1 (-> arg1 r-g-b-a quad))
)
(set! (-> v1-0 vecdata position quad) t2-1)
(set! (-> v1-0 vecdata quads 1 quad) t3-1)
(set! (-> v1-0 vecdata color quad) a1-1)
)
(let ((a1-2 1))
(set! (-> v1-0 vecdata z-offset) arg4)
(set! (-> v1-0 vecdata fade-a) arg2)
(set! (-> v1-0 vecdata fade-b) arg3)
(set! (-> v1-0 num-sprites) (the-as uint a1-2))
)
(let ((a1-3 (-> arg5 quad 0 quad))
(a2-1 (-> arg5 quad 1 quad))
(a3-1 (-> arg5 quad 2 quad))
(t0-1 (-> arg5 quad 3 quad))
(t1-1 (-> arg5 quad 4 quad))
)
(set! (-> v1-0 shader quad 0 quad) a1-3)
(set! (-> v1-0 shader quad 1 quad) a2-1)
(set! (-> v1-0 shader quad 2 quad) a3-1)
(set! (-> v1-0 shader quad 3 quad) t0-1)
(set! (-> v1-0 shader quad 4 quad) t1-1)
)
(set! (-> arg0 base) (the-as pointer (&+ v1-0 224)))
)
(none)
)
;; WARN: Return type mismatch sprite-glow-ref-template vs none.
(defun sprite-glow-add-simple-sprite ((arg0 dma-buffer) (arg1 sprite-glow-dma-packet-data) (arg2 sprite-glow-data) (arg3 pointer))
(let ((v1-0 (the-as sprite-glow-ref-template (-> arg0 base))))
(let ((t0-0 (-> arg1 control-packet quad))
(t1-0 (-> arg1 vecdata-packet quad))
(t2-0 (-> arg1 shader-ref-packet quad))
(a1-1 (-> arg1 mscal-packet quad))
)
(set! (-> v1-0 control-packet quad) t0-0)
(set! (-> v1-0 num-sprites-quad) (the-as uint128 0))
(set! (-> v1-0 vecdata-packet quad) t1-0)
(set! (-> v1-0 shader-packet quad) t2-0)
(set! (-> v1-0 mscal-packet quad) a1-1)
)
(let ((a1-2 (-> arg2 position quad))
(t0-1 (-> arg2 quads 1 quad))
(t1-1 (-> arg2 color quad))
(a2-1 (-> arg2 quads 3 quad))
(t2-1 1)
)
(set! (-> v1-0 vecdata position quad) a1-2)
(set! (-> v1-0 vecdata quads 1 quad) t0-1)
(set! (-> v1-0 vecdata color quad) t1-1)
(set! (-> v1-0 vecdata quads 3 quad) a2-1)
(set! (-> v1-0 num-sprites) (the-as uint t2-1))
)
(set! (-> v1-0 shader-packet-ptr) arg3)
(set! (-> arg0 base) (the-as pointer (&+ v1-0 144)))
)
(none)
)
(defun sprite-glow-draw ((arg0 dma-buffer))
(local-vars (a2-0 float))
(let* ((s5-0 *sprite-aux-list*)
(s4-0 (-> s5-0 entry))
(s3-0 #f)
)
(dotimes (s2-0 s4-0)
(let ((v1-2 (-> s5-0 data s2-0)))
(when (and (not s3-0) (= (-> v1-2 aux-type) (sprite-aux-type glow)))
(let* ((a0-5 (-> v1-2 aux-data omega))
(a3-0 (cond
((zero? a0-5)
(set! a2-0 0.0)
1.0
)
(else
(let* ((f1-1 (* 0.00024414062 a0-5))
(f0-4 (- f1-1 (the float (the int f1-1))))
)
(let ((f1-3 (* 4096.0 (- f1-1 f0-4))))
(set! a2-0 (/ -1.0 (* (- 1.0 f0-4) f1-3)))
)
(/ f0-4 (- 1.0 f0-4))
)
)
)
)
)
(sprite-glow-add-sprite arg0 (-> v1-2 vec-data) a2-0 a3-0 (-> v1-2 aux-data user-float) (-> v1-2 gif-data))
)
)
)
)
)
0
(none)
)
(defmethod add! simple-sprite-system ((obj simple-sprite-system) (arg0 sprite-glow-data))
(let ((v1-0 (-> obj count)))
(when (< v1-0 (-> obj max-count))
(let* ((a2-3 (-> obj data v1-0))
(v1-2 arg0)
(a1-1 a2-3)
(a2-4 (-> v1-2 position quad))
(a3-0 (-> v1-2 quads 1 quad))
(t0-0 (-> v1-2 color quad))
(v1-3 (-> v1-2 quads 3 quad))
)
(set! (-> a1-1 position quad) a2-4)
(set! (-> a1-1 quads 1 quad) a3-0)
(set! (-> a1-1 color quad) t0-0)
(set! (-> a1-1 quads 3 quad) v1-3)
)
(+! (-> obj count) 1)
)
)
0
(none)
)
;; WARN: Return type mismatch pointer vs adgif-shader.
(defun add-shader-to-dma ((arg0 dma-buffer))
(let* ((a1-0 (new 'static 'dma-packet :dma (new 'static 'dma-tag :id (dma-tag-id next))))
(v1-0 (-> arg0 base))
(a1-1 (-> a1-0 quad))
(v0-0 (&+ v1-0 16))
)
(let ((a2-0 (&+ v1-0 96)))
(set! (-> (the-as (pointer uint128) v1-0)) a1-1)
(set! (-> (the-as (pointer uint32) v1-0) 1) (the-as uint a2-0))
(set! (-> arg0 base) a2-0)
)
(the-as adgif-shader v0-0)
)
)
(defmethod draw-all-sprites! simple-sprite-system ((obj simple-sprite-system) (arg0 dma-buffer))
(local-vars (sv-528 sprite-glow-dma-packet-data) (sv-532 (pointer texture-id)) (sv-536 pointer))
(b! (zero? (-> obj count)) cfg-13 :delay (nop!))
(set! sv-528 *sprite-glow-dma-packet-data*)
(set! sv-532 (new 'stack-no-clear 'array 'texture-id 128))
(set! sv-536 (-> arg0 base))
(when (> (-> obj count) 128)
(format 0 "TOO MANY SPRITES (~D)~%" (-> obj count))
(break!)
)
(dotimes (v1-5 (-> obj count))
(set! (-> sv-532 v1-5) (-> obj data v1-5 tex-id))
)
(countdown (s4-0 (-> obj count))
(let ((s3-0 (-> sv-532 s4-0)))
(when (nonzero? s3-0)
(let ((s2-0 (add-shader-to-dma arg0)))
(adgif-shader<-texture-simple! s2-0 (lookup-texture-by-id s3-0))
(countdown (s1-1 (+ s4-0 1))
(when (= s3-0 (-> sv-532 s1-1))
(set! (-> sv-532 s1-1) (new 'static 'texture-id))
(let ((a2-1 (-> obj data s1-1)))
(sprite-glow-add-simple-sprite arg0 sv-528 a2-1 (the-as pointer s2-0))
)
)
)
)
)
)
)
(label cfg-13)
0
(none)
)
(defmethod clear! simple-sprite-system ((obj simple-sprite-system))
(set! (-> obj count) 0)
0
(none)
)
(define *simple-sprite-system*
(new 'static 'simple-sprite-system :max-count #x80 :data (new 'static 'inline-array sprite-glow-data 128
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
)
)
)

View File

@ -929,10 +929,9 @@
;; sprite glow
;;;;;;;;;;;;;;;;
;; TODO: figure out what this is doing
; (sprite-glow-init-engine dma-buff)
; (sprite-glow-draw dma-buff)
; (simple-sprite-system-method-10 *simple-sprite-system* dma-buff)
(sprite-glow-init-engine dma-buff)
(sprite-glow-draw dma-buff)
(draw-all-sprites! *simple-sprite-system* dma-buff)
(let* ((v1-26 dma-buff)
(pkt6 (the-as dma-packet (-> v1-26 base)))
)

View File

@ -271,7 +271,7 @@
)
(when (nonzero? *simple-sprite-system*)
;; added nonzero check
(add! *simple-sprite-system* (the-as dma-buffer (-> s3-1 1)))
(add! *simple-sprite-system* (the sprite-glow-data (-> s3-1 1)))
)
(forward-up->quaternion (the-as quaternion (-> s3-1 0)) arg1 (the-as vector (-> obj rbody state matrix)))
(quaternion-rotate-local-x! (the-as quaternion (-> s3-1 0)) (the-as quaternion (-> s3-1 0)) 32768.0)
@ -386,7 +386,7 @@
(set! (-> s4-0 color x) 255.0)
(set! (-> s4-0 color y) (rand-vu-float-range 192.0 255.0))
(set! (-> s4-0 color w) (* f30-1 (rand-vu-float-range 16.0 18.0)))
(add! *simple-sprite-system* (the-as dma-buffer s4-0))
(add! *simple-sprite-system* s4-0)
(let ((f0-21 (-> obj camera-dist2))
(f1-6 245760.0)
)
@ -399,7 +399,7 @@
(set! (-> s4-0 fade-b) 2.3332994)
(set! (-> s4-0 color z) (rand-vu-float-range 128.0 160.0))
(set! (-> s4-0 color w) (* f30-1 (rand-vu-float-range 32.0 36.0)))
(add! *simple-sprite-system* (the-as dma-buffer s4-0))
(add! *simple-sprite-system* s4-0)
)
)
)
@ -419,7 +419,7 @@
(set! (-> s4-1 rot-angle) (* 182.04445 (rand-vu-float-range -4.0 4.0)))
(set! (-> s4-1 color y) (* 64.0 (rand-vu)))
(set! (-> s4-1 color w) (* f30-1 (rand-vu-float-range 16.0 21.0)))
(add! *simple-sprite-system* (the-as dma-buffer s4-1))
(add! *simple-sprite-system* s4-1)
)
)
)

View File

@ -410,7 +410,7 @@ bits 5 and 6 (0x20 and 0x40) should be zero"
(goto cfg-4)
)
(format #t "[~8x] ~A~%" obj 'gs-adcmd)
(format #t "~1Tword[4] @ #x~X~%" (-> obj word))
(format #t "~1Tword[4] @ #x~X~%" (&-> obj x))
(format #t "~1Tquad: ~D~%" (-> obj quad))
(format #t "~1Tdata: ~D~%" (-> obj data))
(format #t "~1Tcmds: ~D~%" (-> obj cmds))
@ -1039,16 +1039,16 @@ bits 5 and 6 (0x20 and 0x40) should be zero"
(goto cfg-4)
)
(format #t "[~8x] ~A~%" obj 'gs-packed-xyzw)
(format #t "~1Tdata[4] @ #x~X~%" (&-> obj x))
(format #t "~1Tdata[4] @ #x~X~%" (&-> obj ix))
(format #t "~1Tx: ~f~%" (-> obj x))
(format #t "~1Ty: ~f~%" (-> obj y))
(format #t "~1Tz: ~f~%" (-> obj z))
(format #t "~1Tw: ~f~%" (-> obj w))
(format #t "~1Tquad: ~D~%" (-> obj quad))
(format #t "~1Tix: ~D~%" (-> obj x))
(format #t "~1Tiy: ~D~%" (-> obj y))
(format #t "~1Tiz: ~D~%" (-> obj z))
(format #t "~1Tiw: ~D~%" (-> obj w))
(format #t "~1Tix: ~D~%" (-> obj ix))
(format #t "~1Tiy: ~D~%" (-> obj iy))
(format #t "~1Tiz: ~D~%" (-> obj iz))
(format #t "~1Tiw: ~D~%" (-> obj iw))
(label cfg-4)
obj
)

View File

@ -27,8 +27,8 @@
:regs (new 'static 'gif-tag-regs-32 :regs0 (gif-reg-id st) :regs1 (gif-reg-id rgbaq) :regs2 (gif-reg-id xyzf2))
)
:adnops (new 'static 'inline-array gs-adcmd 2
(new 'static 'gs-adcmd :word (new 'static 'array uint32 4 #x0 #x0 #x7f #x0))
(new 'static 'gs-adcmd :word (new 'static 'array uint32 4 #x0 #x0 #x7f #x0))
(new 'static 'gs-adcmd :cmds (gs-reg64 hack))
(new 'static 'gs-adcmd :cmds (gs-reg64 hack))
)
)
)

View File

@ -14,6 +14,7 @@
(fade-b float :offset-assert 52)
(tex-id texture-id :offset-assert 56)
(dummy uint32 :offset-assert 60)
(quads vector 4 :inline :offset 0)
)
:method-count-assert 10
:size-assert #x40
@ -61,14 +62,14 @@
(deftype simple-sprite-system (structure)
((count int16 :offset-assert 0)
(max-count int16 :offset-assert 2)
(data sprite-glow-data :offset-assert 4)
(data (inline-array sprite-glow-data) :offset-assert 4)
)
:method-count-assert 12
:size-assert #x8
:flag-assert #xc00000008
(:methods
(add! (_type_ dma-buffer) none 9)
(simple-sprite-system-method-10 (_type_ dma-buffer) none 10)
(add! (_type_ sprite-glow-data) none 9)
(draw-all-sprites! (_type_ dma-buffer) none 10)
(clear! (_type_) none 11)
)
)

View File

@ -0,0 +1,917 @@
;;-*-Lisp-*-
(in-package goal)
;; definition of type sprite-glow-template
(deftype sprite-glow-template (structure)
((clear-init-giftag gs-gif-tag :inline :offset-assert 0)
(clear-init-adcmds gs-adcmd 5 :inline :offset-assert 16)
(clear-draw-giftag gs-gif-tag :inline :offset-assert 96)
(clear-draw-clr-0 gs-packed-rgba :inline :offset-assert 112)
(clear-draw-xyz-0 gs-packed-xyzw 2 :inline :offset-assert 128)
(clear-draw-clr-1 gs-packed-rgba :inline :offset-assert 160)
(clear-draw-xyz-1 vector 2 :inline :offset-assert 176)
(offscr-setup-giftag gs-gif-tag :inline :offset-assert 208)
(offscr-setup-adcmds gs-adcmd 8 :inline :offset-assert 224)
(offscr-first-giftag gs-gif-tag :inline :offset-assert 352)
(offscr-first-clr gs-packed-rgba :inline :offset-assert 368)
(offscr-first-uv-0 gs-packed-uv :inline :offset-assert 384)
(offscr-first-xyzw-0 gs-packed-xyzw :inline :offset-assert 400)
(offscr-first-uv-1 gs-packed-uv :inline :offset-assert 416)
(offscr-first-xyzw-1 gs-packed-xyzw :inline :offset-assert 432)
(repeat-draw-giftag gs-gif-tag :inline :offset-assert 448)
(repeat-draw-adcmds gs-adcmd 29 :inline :offset-assert 464)
(flare-alpha-giftag gs-gif-tag :inline :offset-assert 928)
(flare-alpha-clr gs-packed-rgba :inline :offset-assert 944)
(flare-alpha-uv gs-packed-uv :inline :offset-assert 960)
(flare-alpha-xyzw-0 gs-packed-xyzw :inline :offset-assert 976)
(flare-alpha-xyzw-1 gs-packed-xyzw :inline :offset-assert 992)
(flare-alpha-xyzw-2 gs-packed-xyzw :inline :offset-assert 1008)
(flare-alpha-xyzw-3 gs-packed-xyzw :inline :offset-assert 1024)
(flare-init-giftag gs-gif-tag :inline :offset-assert 1040)
(flare-init-adcmds gs-adcmd 8 :inline :offset-assert 1056)
(flare-draw-giftag gs-gif-tag :inline :offset-assert 1184)
(flare-draw-clr gs-packed-rgba :inline :offset-assert 1200)
(flare-draw-stq-0 gs-packed-stq :inline :offset-assert 1216)
(flare-draw-xyzw-0 gs-packed-xyzw :inline :offset-assert 1232)
(flare-draw-stq-1 gs-packed-stq :inline :offset-assert 1248)
(flare-draw-xyzw-1 gs-packed-xyzw :inline :offset-assert 1264)
(flare-draw-stq-2 gs-packed-stq :inline :offset-assert 1280)
(flare-draw-xyzw-2 gs-packed-xyzw :inline :offset-assert 1296)
(flare-draw-stq-3 gs-packed-stq :inline :offset-assert 1312)
(flare-draw-xyzw-3 gs-packed-xyzw :inline :offset-assert 1328)
)
:method-count-assert 9
:size-assert #x540
:flag-assert #x900000540
)
;; definition for method 3 of type sprite-glow-template
(defmethod inspect sprite-glow-template ((obj sprite-glow-template))
(when (not obj)
(set! obj obj)
(goto cfg-4)
)
(format #t "[~8x] ~A~%" obj 'sprite-glow-template)
(format #t "~1Tclear-init-giftag: #<gs-gif-tag @ #x~X>~%" (-> obj clear-init-giftag))
(format #t "~1Tclear-init-adcmds[5] @ #x~X~%" (-> obj clear-init-adcmds))
(format #t "~1Tclear-draw-giftag: #<gs-gif-tag @ #x~X>~%" (-> obj clear-draw-giftag))
(format #t "~1Tclear-draw-clr-0: #<gs-packed-rgba @ #x~X>~%" (-> obj clear-draw-clr-0))
(format #t "~1Tclear-draw-xyz-0[2] @ #x~X~%" (-> obj clear-draw-xyz-0))
(format #t "~1Tclear-draw-clr-1: #<gs-packed-rgba @ #x~X>~%" (-> obj clear-draw-clr-1))
(format #t "~1Tclear-draw-xyz-1[2] @ #x~X~%" (-> obj clear-draw-xyz-1))
(format #t "~1Toffscr-setup-giftag: #<gs-gif-tag @ #x~X>~%" (-> obj offscr-setup-giftag))
(format #t "~1Toffscr-setup-adcmds[8] @ #x~X~%" (-> obj offscr-setup-adcmds))
(format #t "~1Toffscr-first-giftag: #<gs-gif-tag @ #x~X>~%" (-> obj offscr-first-giftag))
(format #t "~1Toffscr-first-clr: #<gs-packed-rgba @ #x~X>~%" (-> obj offscr-first-clr))
(format #t "~1Toffscr-first-uv-0: #<gs-packed-uv @ #x~X>~%" (-> obj offscr-first-uv-0))
(format #t "~1Toffscr-first-xyzw-0: #<gs-packed-xyzw @ #x~X>~%" (-> obj offscr-first-xyzw-0))
(format #t "~1Toffscr-first-uv-1: #<gs-packed-uv @ #x~X>~%" (-> obj offscr-first-uv-1))
(format #t "~1Toffscr-first-xyzw-1: #<gs-packed-xyzw @ #x~X>~%" (-> obj offscr-first-xyzw-1))
(format #t "~1Trepeat-draw-giftag: #<gs-gif-tag @ #x~X>~%" (-> obj repeat-draw-giftag))
(format #t "~1Trepeat-draw-adcmds[29] @ #x~X~%" (-> obj repeat-draw-adcmds))
(format #t "~1Tflare-alpha-giftag: #<gs-gif-tag @ #x~X>~%" (-> obj flare-alpha-giftag))
(format #t "~1Tflare-alpha-clr: #<gs-packed-rgba @ #x~X>~%" (-> obj flare-alpha-clr))
(format #t "~1Tflare-alpha-uv: #<gs-packed-uv @ #x~X>~%" (-> obj flare-alpha-uv))
(format #t "~1Tflare-alpha-xyzw-0: #<gs-packed-xyzw @ #x~X>~%" (-> obj flare-alpha-xyzw-0))
(format #t "~1Tflare-alpha-xyzw-1: #<gs-packed-xyzw @ #x~X>~%" (-> obj flare-alpha-xyzw-1))
(format #t "~1Tflare-alpha-xyzw-2: #<gs-packed-xyzw @ #x~X>~%" (-> obj flare-alpha-xyzw-2))
(format #t "~1Tflare-alpha-xyzw-3: #<gs-packed-xyzw @ #x~X>~%" (-> obj flare-alpha-xyzw-3))
(format #t "~1Tflare-init-giftag: #<gs-gif-tag @ #x~X>~%" (-> obj flare-init-giftag))
(format #t "~1Tflare-init-adcmds[8] @ #x~X~%" (-> obj flare-init-adcmds))
(format #t "~1Tflare-draw-giftag: #<gs-gif-tag @ #x~X>~%" (-> obj flare-draw-giftag))
(format #t "~1Tflare-draw-clr: #<gs-packed-rgba @ #x~X>~%" (-> obj flare-draw-clr))
(format #t "~1Tflare-draw-stq-0: #<gs-packed-stq @ #x~X>~%" (-> obj flare-draw-stq-0))
(format #t "~1Tflare-draw-xyzw-0: #<gs-packed-xyzw @ #x~X>~%" (-> obj flare-draw-xyzw-0))
(format #t "~1Tflare-draw-stq-1: #<gs-packed-stq @ #x~X>~%" (-> obj flare-draw-stq-1))
(format #t "~1Tflare-draw-xyzw-1: #<gs-packed-xyzw @ #x~X>~%" (-> obj flare-draw-xyzw-1))
(format #t "~1Tflare-draw-stq-2: #<gs-packed-stq @ #x~X>~%" (-> obj flare-draw-stq-2))
(format #t "~1Tflare-draw-xyzw-2: #<gs-packed-xyzw @ #x~X>~%" (-> obj flare-draw-xyzw-2))
(format #t "~1Tflare-draw-stq-3: #<gs-packed-stq @ #x~X>~%" (-> obj flare-draw-stq-3))
(format #t "~1Tflare-draw-xyzw-3: #<gs-packed-xyzw @ #x~X>~%" (-> obj flare-draw-xyzw-3))
(label cfg-4)
obj
)
;; definition of type sprite-glow-consts
(deftype sprite-glow-consts (structure)
((camera matrix :inline :offset-assert 0)
(perspective matrix :inline :offset-assert 64)
(hvdf-offset vector :inline :offset-assert 128)
(hmge-scale vector :inline :offset-assert 144)
(consts vector :inline :offset-assert 160)
(pfog0 float :offset 160)
(deg-to-rad float :offset 164)
(min-scale float :offset 168)
(inv-area float :offset 172)
(sincos-01 vector :inline :offset-assert 176)
(sincos-23 vector :inline :offset-assert 192)
(sincos-45 vector :inline :offset-assert 208)
(sincos-67 vector :inline :offset-assert 224)
(sincos-89 vector :inline :offset-assert 240)
(basis-x vector :inline :offset-assert 256)
(basis-y vector :inline :offset-assert 272)
(xy-array vector 4 :inline :offset-assert 288)
(clamp-min vector :inline :offset-assert 352)
(clamp-max vector :inline :offset-assert 368)
)
:method-count-assert 9
:size-assert #x180
:flag-assert #x900000180
)
;; definition for method 3 of type sprite-glow-consts
(defmethod inspect sprite-glow-consts ((obj sprite-glow-consts))
(when (not obj)
(set! obj obj)
(goto cfg-4)
)
(format #t "[~8x] ~A~%" obj 'sprite-glow-consts)
(format #t "~1Tcamera: #<matrix @ #x~X>~%" (-> obj camera))
(format #t "~1Tperspective: #<matrix @ #x~X>~%" (-> obj perspective))
(format #t "~1Thvdf-offset: #<vector @ #x~X>~%" (-> obj hvdf-offset))
(format #t "~1Thmge-scale: #<vector @ #x~X>~%" (-> obj hmge-scale))
(format #t "~1Tconsts: #<vector @ #x~X>~%" (&-> obj pfog0))
(format #t "~1Tpfog0: ~f~%" (-> obj pfog0))
(format #t "~1Tdeg-to-rad: ~f~%" (-> obj deg-to-rad))
(format #t "~1Tmin-scale: ~f~%" (-> obj min-scale))
(format #t "~1Tinv-area: ~f~%" (-> obj inv-area))
(format #t "~1Tsincos-01: #<vector @ #x~X>~%" (-> obj sincos-01))
(format #t "~1Tsincos-23: #<vector @ #x~X>~%" (-> obj sincos-23))
(format #t "~1Tsincos-45: #<vector @ #x~X>~%" (-> obj sincos-45))
(format #t "~1Tsincos-67: #<vector @ #x~X>~%" (-> obj sincos-67))
(format #t "~1Tsincos-89: #<vector @ #x~X>~%" (-> obj sincos-89))
(format #t "~1Tbasis-x: #<vector @ #x~X>~%" (-> obj basis-x))
(format #t "~1Tbasis-y: #<vector @ #x~X>~%" (-> obj basis-y))
(format #t "~1Txy-array[4] @ #x~X~%" (-> obj xy-array))
(format #t "~1Tclamp-min: #<vector @ #x~X>~%" (-> obj clamp-min))
(format #t "~1Tclamp-max: #<vector @ #x~X>~%" (-> obj clamp-max))
(label cfg-4)
obj
)
;; definition for symbol *sprite-glow-template*, type sprite-glow-template
(define *sprite-glow-template*
(new 'static 'sprite-glow-template
:clear-init-giftag (new 'static 'gs-gif-tag
:tag (new 'static 'gif-tag64 :nloop #x5 :nreg #x1)
:regs (new 'static 'gif-tag-regs :regs0 (gif-reg-id a+d))
)
:clear-init-adcmds (new 'static 'inline-array gs-adcmd 5
(new 'static 'gs-adcmd :cmds (gs-reg64 texflush))
(new 'static 'gs-adcmd :cmds (gs-reg64 alpha-1) :x #x6a)
(new 'static 'gs-adcmd :cmds (gs-reg64 test-1) :x #x51001)
(new 'static 'gs-adcmd :cmds (gs-reg64 zbuf-1) :x #x1000130 :y #x1)
(new 'static 'gs-adcmd :cmds (gs-reg64 frame-1) :x #x80198 :y #xffffff)
)
:clear-draw-giftag (new 'static 'gs-gif-tag
:tag (new 'static 'gif-tag64
:nloop #x2
:pre #x1
:prim (new 'static 'gs-prim :prim (gs-prim-type sprite))
:nreg #x3
)
:regs (new 'static 'gif-tag-regs :regs0 (gif-reg-id rgbaq) :regs1 (gif-reg-id xyzf2) :regs2 (gif-reg-id xyzf2))
)
:clear-draw-xyz-0 (new 'static 'inline-array gs-packed-xyzw 2
(new 'static 'gs-packed-xyzw :iz -1)
(new 'static 'gs-packed-xyzw :iz -1)
)
:clear-draw-clr-1 (new 'static 'gs-packed-rgba :x #xff :w #xff)
:offscr-setup-giftag (new 'static 'gs-gif-tag
:tag (new 'static 'gif-tag64 :nloop #x8 :nreg #x1)
:regs (new 'static 'gif-tag-regs :regs0 (gif-reg-id a+d))
)
:offscr-setup-adcmds (new 'static 'inline-array gs-adcmd 8
(new 'static 'gs-adcmd :cmds (gs-reg64 frame-2) :x #x10090 :y #xffffff)
(new 'static 'gs-adcmd :cmds (gs-reg64 zbuf-2) :x #x1000130)
(new 'static 'gs-adcmd :cmds (gs-reg64 tex1-2) :x #x60)
(new 'static 'gs-adcmd :cmds (gs-reg64 tex0-2) :x #x64023300 :y #xe)
(new 'static 'gs-adcmd :cmds (gs-reg64 clamp-2) :x #x5)
(new 'static 'gs-adcmd :cmds (gs-reg64 test-2) :x #x31001)
(new 'static 'gs-adcmd :cmds (gs-reg64 xyoffset-2))
(new 'static 'gs-adcmd :cmds (gs-reg64 texflush))
)
:offscr-first-giftag (new 'static 'gs-gif-tag
:tag (new 'static 'gif-tag64
:nloop #x1
:pre #x1
:prim (new 'static 'gs-prim :prim (gs-prim-type sprite) :tme #x1 :fst #x1 :ctxt #x1)
:nreg #x5
)
:regs (new 'static 'gif-tag-regs
:regs0 (gif-reg-id rgbaq)
:regs1 (gif-reg-id uv)
:regs2 (gif-reg-id xyz2)
:regs3 (gif-reg-id uv)
:regs4 (gif-reg-id xyz2)
)
)
:offscr-first-clr (new 'static 'gs-packed-rgba :x #x80 :y #x80 :z #x80 :w #x80)
:offscr-first-xyzw-1 (new 'static 'gs-packed-xyzw :ix #x200 :iy #x200)
:repeat-draw-giftag (new 'static 'gs-gif-tag
:tag (new 'static 'gif-tag64 :nloop #x1d :nreg #x1)
:regs (new 'static 'gif-tag-regs :regs0 (gif-reg-id a+d))
)
:repeat-draw-adcmds (new 'static 'inline-array gs-adcmd 29
(new 'static 'gs-adcmd :cmds (gs-reg64 tex0-2) :x #x54005200 :y #xd)
(new 'static 'gs-adcmd :cmds (gs-reg64 texflush))
(new 'static 'gs-adcmd :cmds (gs-reg64 uv) :x #x100010)
(new 'static 'gs-adcmd :cmds (gs-reg64 xyz2))
(new 'static 'gs-adcmd :cmds (gs-reg64 uv) :x #x2100210)
(new 'static 'gs-adcmd :cmds (gs-reg64 xyz2) :x #x1000100)
(new 'static 'gs-adcmd :cmds (gs-reg64 texflush))
(new 'static 'gs-adcmd :cmds (gs-reg64 uv) :x #x100010)
(new 'static 'gs-adcmd :cmds (gs-reg64 xyz2))
(new 'static 'gs-adcmd :cmds (gs-reg64 uv) :x #x1100110)
(new 'static 'gs-adcmd :cmds (gs-reg64 xyz2) :x #x800080)
(new 'static 'gs-adcmd :cmds (gs-reg64 texflush))
(new 'static 'gs-adcmd :cmds (gs-reg64 uv) :x #x100010)
(new 'static 'gs-adcmd :cmds (gs-reg64 xyz2))
(new 'static 'gs-adcmd :cmds (gs-reg64 uv) :x #x900090)
(new 'static 'gs-adcmd :cmds (gs-reg64 xyz2) :x #x400040)
(new 'static 'gs-adcmd :cmds (gs-reg64 texflush))
(new 'static 'gs-adcmd :cmds (gs-reg64 uv) :x #x100010)
(new 'static 'gs-adcmd :cmds (gs-reg64 xyz2))
(new 'static 'gs-adcmd :cmds (gs-reg64 uv) :x #x500050)
(new 'static 'gs-adcmd :cmds (gs-reg64 xyz2) :x #x200020)
(new 'static 'gs-adcmd :cmds (gs-reg64 frame-2) :x #x80198 :y #xffffff)
(new 'static 'gs-adcmd :cmds (gs-reg64 test-2) :x #x51001)
(new 'static 'gs-adcmd :cmds (gs-reg64 zbuf-2) :x #x1000130 :y #x1)
(new 'static 'gs-adcmd :cmds (gs-reg64 xyoffset-2) :x #x7000 :y #x7300)
(new 'static 'gs-adcmd :cmds (gs-reg64 scissor-2) :x #x1ff0000 :y #x19f0000)
(new 'static 'gs-adcmd :cmds (gs-reg64 test-2) :x #x50000)
(new 'static 'gs-adcmd :cmds (gs-reg64 alpha-2) :x #x6a)
(new 'static 'gs-adcmd :cmds (gs-reg64 texflush))
)
:flare-alpha-giftag (new 'static 'gs-gif-tag
:tag (new 'static 'gif-tag64
:nloop #x1
:pre #x1
:prim (new 'static 'gs-prim :prim (gs-prim-type tri-fan) :tme #x1 :fst #x1 :ctxt #x1)
:nreg #x6
)
:regs (new 'static 'gif-tag-regs
:regs0 (gif-reg-id rgbaq)
:regs1 (gif-reg-id uv)
:regs2 (gif-reg-id xyzf2)
:regs3 (gif-reg-id xyzf2)
:regs4 (gif-reg-id xyzf2)
:regs5 (gif-reg-id xyzf2)
)
)
:flare-alpha-clr (new 'static 'gs-packed-rgba :x #x80 :y #x80 :z #x80 :w #x80)
:flare-alpha-uv (new 'static 'gs-packed-uv :x (the-as float #x10) :y (the-as float #x10))
:flare-alpha-xyzw-0 (new 'static 'gs-packed-xyzw :iz -1)
:flare-alpha-xyzw-1 (new 'static 'gs-packed-xyzw :iz -1)
:flare-alpha-xyzw-2 (new 'static 'gs-packed-xyzw :iz -1)
:flare-alpha-xyzw-3 (new 'static 'gs-packed-xyzw :iz -1)
:flare-init-giftag (new 'static 'gs-gif-tag
:tag (new 'static 'gif-tag64 :nloop #x8 :nreg #x1)
:regs (new 'static 'gif-tag-regs :regs0 (gif-reg-id a+d))
)
:flare-init-adcmds (new 'static 'inline-array gs-adcmd 8
(new 'static 'gs-adcmd :cmds (gs-reg64 texflush))
(new 'static 'gs-adcmd :cmds (gs-reg64 frame-1) :x #x80198)
(new 'static 'gs-adcmd :cmds (gs-reg64 hack))
(new 'static 'gs-adcmd :cmds (gs-reg64 hack))
(new 'static 'gs-adcmd :cmds (gs-reg64 hack))
(new 'static 'gs-adcmd :cmds (gs-reg64 hack))
(new 'static 'gs-adcmd :cmds (gs-reg64 hack))
(new 'static 'gs-adcmd :cmds (gs-reg64 alpha-1) :x #x58)
)
:flare-draw-giftag (new 'static 'gs-gif-tag
:tag (new 'static 'gif-tag64
:nloop #x1
:eop #x1
:pre #x1
:prim (new 'static 'gs-prim :prim (gs-prim-type tri-fan) :tme #x1 :abe #x1)
:nreg #x9
)
:regs (new 'static 'gif-tag-regs
:regs0 (gif-reg-id rgbaq)
:regs1 (gif-reg-id st)
:regs2 (gif-reg-id xyzf2)
:regs3 (gif-reg-id st)
:regs4 (gif-reg-id xyzf2)
:regs5 (gif-reg-id st)
:regs6 (gif-reg-id xyzf2)
:regs7 (gif-reg-id st)
:regs8 (gif-reg-id xyzf2)
)
)
:flare-draw-clr (new 'static 'gs-packed-rgba :y 64 :w #x80)
:flare-draw-stq-0 (new 'static 'gs-packed-stq :z 1.0)
:flare-draw-xyzw-0 (new 'static 'gs-packed-xyzw :iz -1)
:flare-draw-stq-1 (new 'static 'gs-packed-stq :x 1.0 :z 1.0)
:flare-draw-xyzw-1 (new 'static 'gs-packed-xyzw :iz -1)
:flare-draw-stq-2 (new 'static 'gs-packed-stq :x 1.0 :y 1.0 :z 1.0)
:flare-draw-xyzw-2 (new 'static 'gs-packed-xyzw :iz -1)
:flare-draw-stq-3 (new 'static 'gs-packed-stq :y 1.0 :z 1.0)
:flare-draw-xyzw-3 (new 'static 'gs-packed-xyzw :iz -1)
)
)
;; definition for symbol sprite-glow-vu1-block, type vu-function
(define sprite-glow-vu1-block (new 'static 'vu-function :length #x86 :qlength 67))
;; definition for function sprite-glow-init-consts
;; INFO: Used lq/sq
;; WARN: Return type mismatch vector vs none.
(defun sprite-glow-init-consts ((arg0 sprite-glow-consts))
(let ((v1-0 *math-camera*))
(let* ((t0-0 (-> arg0 camera))
(t1-0 (-> v1-0 camera-rot))
(a1-0 (-> t1-0 quad 0))
(a2-0 (-> t1-0 quad 1))
(a3-0 (-> t1-0 quad 2))
(t1-1 (-> t1-0 trans quad))
)
(set! (-> t0-0 quad 0) a1-0)
(set! (-> t0-0 quad 1) a2-0)
(set! (-> t0-0 quad 2) a3-0)
(set! (-> t0-0 trans quad) t1-1)
)
(let* ((t0-1 (-> arg0 perspective))
(t1-2 (-> v1-0 perspective))
(a1-1 (-> t1-2 quad 0))
(a2-1 (-> t1-2 quad 1))
(a3-1 (-> t1-2 quad 2))
(t1-3 (-> t1-2 trans quad))
)
(set! (-> t0-1 quad 0) a1-1)
(set! (-> t0-1 quad 1) a2-1)
(set! (-> t0-1 quad 2) a3-1)
(set! (-> t0-1 trans quad) t1-3)
)
(set! (-> arg0 hvdf-offset quad) (-> v1-0 hvdf-off quad))
(set! (-> arg0 hmge-scale quad) (-> v1-0 hmge-scale quad))
(set! (-> arg0 basis-x quad) (the-as uint128 0))
(set! (-> arg0 basis-x x) (- (-> *math-camera* perspective vector 0 x)))
(set! (-> arg0 basis-y quad) (the-as uint128 0))
(set! (-> arg0 basis-y y) (- (-> *math-camera* perspective vector 1 y)))
(set! (-> arg0 pfog0) (-> v1-0 pfog0))
)
(set! (-> arg0 deg-to-rad) 0.000095873795)
(set! (-> arg0 min-scale) (sqrtf (* (/ 1.0 (-> arg0 basis-x x)) (/ 1.0 (-> arg0 basis-y y)))))
(set! (-> arg0 inv-area) (/ 1.0 (* (-> arg0 min-scale) (-> arg0 min-scale))))
(let ((v1-5 (-> arg0 sincos-01)))
(set! (-> v1-5 z) 0.999998)
(set! (-> v1-5 w) 1.0)
)
(let ((v1-6 (-> arg0 sincos-23)))
(set! (-> v1-6 z) -0.16666014)
(set! (-> v1-6 w) -0.49998003)
)
(let ((v1-7 (-> arg0 sincos-45)))
(set! (-> v1-7 z) 0.008326521)
(set! (-> v1-7 w) 0.041620404)
)
(let ((v1-8 (-> arg0 sincos-67)))
(set! (-> v1-8 z) -0.0001956241)
(set! (-> v1-8 w) -0.0013636408)
)
(let ((v1-9 (-> arg0 sincos-89)))
(set! (-> v1-9 z) 0.0000023042373)
(set! (-> v1-9 w) 0.000020170546)
)
(set-vector! (-> arg0 xy-array 0) -0.5 -0.5 0.0 0.0)
(set-vector! (-> arg0 xy-array 1) 0.5 -0.5 0.0 0.0)
(set-vector! (-> arg0 xy-array 2) 0.5 0.5 0.0 0.0)
(set-vector! (-> arg0 xy-array 3) -0.5 0.5 0.0 0.0)
(set-vector! (-> arg0 clamp-min) 1792.0 1840.0 0.0 0.0)
(set-vector! (-> arg0 clamp-max) 2304.0 2256.0 2048.0 50.0)
(none)
)
;; definition for function sprite-glow-init-engine
;; WARN: Return type mismatch int vs none.
(defun sprite-glow-init-engine ((arg0 dma-buffer))
(dma-buffer-add-vu-function arg0 sprite-glow-vu1-block 1)
(let ((s5-0 24))
(let* ((v1-0 arg0)
(a0-2 (the-as dma-packet (-> v1-0 base)))
)
(set! (-> a0-2 dma) (new 'static 'dma-tag :id (dma-tag-id cnt) :qwc s5-0))
(set! (-> a0-2 vif0) (new 'static 'vif-tag :imm #x404 :cmd (vif-cmd stcycl)))
(set! (-> a0-2 vif1) (new 'static 'vif-tag :imm #x3d4 :cmd (vif-cmd unpack-v4-32) :num s5-0))
(set! (-> v1-0 base) (the-as pointer (&+ a0-2 16)))
)
(sprite-glow-init-consts (the-as sprite-glow-consts (-> arg0 base)))
(&+! (-> arg0 base) (* s5-0 16))
)
(let ((v1-3 84))
(let* ((a0-6 arg0)
(a1-6 (the-as dma-packet (-> a0-6 base)))
)
(set! (-> a1-6 dma)
(new 'static 'dma-tag :id (dma-tag-id ref) :addr (the-as int *sprite-glow-template*) :qwc v1-3)
)
(set! (-> a1-6 vif0) (new 'static 'vif-tag :imm #x404 :cmd (vif-cmd stcycl)))
(set! (-> a1-6 vif1) (new 'static 'vif-tag :imm #x320 :cmd (vif-cmd unpack-v4-32) :num v1-3))
(set! (-> a0-6 base) (the-as pointer (&+ a1-6 16)))
)
(let* ((a0-7 arg0)
(a1-8 (the-as dma-packet (-> a0-7 base)))
)
(set! (-> a1-8 dma)
(new 'static 'dma-tag :id (dma-tag-id ref) :addr (the-as int *sprite-glow-template*) :qwc v1-3)
)
(set! (-> a1-8 vif0) (new 'static 'vif-tag :cmd (vif-cmd mscal) :msk #x1 :imm #x0))
(set! (-> a1-8 vif1) (new 'static 'vif-tag :imm #x374 :cmd (vif-cmd unpack-v4-32) :num v1-3))
(set! (-> a0-7 base) (the-as pointer (&+ a1-8 16)))
)
)
(let* ((v1-8 arg0)
(a0-8 (the-as dma-packet (-> v1-8 base)))
)
(set! (-> a0-8 dma) (new 'static 'dma-tag :id (dma-tag-id cnt)))
(set! (-> a0-8 vif0) (new 'static 'vif-tag :cmd (vif-cmd base)))
(set! (-> a0-8 vif1) (new 'static 'vif-tag :imm #x190 :cmd (vif-cmd offset)))
(set! (-> v1-8 base) (the-as pointer (&+ a0-8 16)))
)
(let ((v1-9 (the-as dma-packet (-> arg0 base))))
(set! (-> v1-9 dma) (new 'static 'dma-tag :id (dma-tag-id cnt)))
(set! (-> v1-9 vif0) (new 'static 'vif-tag))
(set! (-> v1-9 vif1) (new 'static 'vif-tag :cmd (vif-cmd flushe) :msk #x1))
(set! (-> arg0 base) (the-as pointer (&+ v1-9 16)))
)
0
(none)
)
;; definition of type sprite-glow-dma-packet-data
(deftype sprite-glow-dma-packet-data (structure)
((control-packet dma-packet :inline :offset-assert 0)
(vecdata-packet dma-packet :inline :offset-assert 16)
(shader-cnt-packet dma-packet :inline :offset-assert 32)
(shader-ref-packet dma-packet :inline :offset-assert 48)
(mscal-packet dma-packet :inline :offset-assert 64)
)
:method-count-assert 9
:size-assert #x50
:flag-assert #x900000050
)
;; definition for method 3 of type sprite-glow-dma-packet-data
(defmethod inspect sprite-glow-dma-packet-data ((obj sprite-glow-dma-packet-data))
(when (not obj)
(set! obj obj)
(goto cfg-4)
)
(format #t "[~8x] ~A~%" obj 'sprite-glow-dma-packet-data)
(format #t "~1Tcontrol-packet: #<dma-packet @ #x~X>~%" (-> obj control-packet))
(format #t "~1Tvecdata-packet: #<dma-packet @ #x~X>~%" (-> obj vecdata-packet))
(format #t "~1Tshader-cnt-packet: #<dma-packet @ #x~X>~%" (-> obj shader-cnt-packet))
(format #t "~1Tshader-ref-packet: #<dma-packet @ #x~X>~%" (-> obj shader-ref-packet))
(format #t "~1Tmscal-packet: #<dma-packet @ #x~X>~%" (-> obj mscal-packet))
(label cfg-4)
obj
)
;; definition of type sprite-glow-cnt-template
(deftype sprite-glow-cnt-template (structure)
((control-packet dma-packet :inline :offset-assert 0)
(num-sprites uint32 :offset-assert 16)
(dummys uint32 3 :offset-assert 20)
(num-sprites-quad uint128 :offset 16)
(vecdata-packet dma-packet :inline :offset-assert 32)
(vecdata sprite-glow-data :inline :offset-assert 48)
(shader-packet dma-packet :inline :offset-assert 112)
(shader adgif-shader :inline :offset-assert 128)
(mscal-packet dma-packet :inline :offset-assert 208)
)
:method-count-assert 9
:size-assert #xe0
:flag-assert #x9000000e0
)
;; definition for method 3 of type sprite-glow-cnt-template
(defmethod inspect sprite-glow-cnt-template ((obj sprite-glow-cnt-template))
(when (not obj)
(set! obj obj)
(goto cfg-4)
)
(format #t "[~8x] ~A~%" obj 'sprite-glow-cnt-template)
(format #t "~1Tcontrol-packet: #<dma-packet @ #x~X>~%" (-> obj control-packet))
(format #t "~1Tnum-sprites: ~D~%" (-> obj num-sprites))
(format #t "~1Tdummys[3] @ #x~X~%" (-> obj dummys))
(format #t "~1Tvecdata-packet: #<dma-packet @ #x~X>~%" (-> obj vecdata-packet))
(format #t "~1Tvecdata: #<sprite-glow-data @ #x~X>~%" (-> obj vecdata))
(format #t "~1Tshader-packet: #<dma-packet @ #x~X>~%" (-> obj shader-packet))
(format #t "~1Tshader: #<adgif-shader @ #x~X>~%" (-> obj shader))
(format #t "~1Tmscal-packet: #<dma-packet @ #x~X>~%" (-> obj mscal-packet))
(label cfg-4)
obj
)
;; definition of type sprite-glow-ref-template
(deftype sprite-glow-ref-template (structure)
((control-packet dma-packet :inline :offset-assert 0)
(num-sprites uint32 :offset-assert 16)
(dummys uint32 3 :offset-assert 20)
(num-sprites-quad uint128 :offset 16)
(vecdata-packet dma-packet :inline :offset-assert 32)
(vecdata sprite-glow-data :inline :offset-assert 48)
(shader-packet dma-packet :inline :offset-assert 112)
(shader-packet-ptr pointer :offset 116)
(mscal-packet dma-packet :inline :offset-assert 128)
)
:method-count-assert 9
:size-assert #x90
:flag-assert #x900000090
)
;; definition for method 3 of type sprite-glow-ref-template
(defmethod inspect sprite-glow-ref-template ((obj sprite-glow-ref-template))
(when (not obj)
(set! obj obj)
(goto cfg-4)
)
(format #t "[~8x] ~A~%" obj 'sprite-glow-ref-template)
(format #t "~1Tcontrol-packet: #<dma-packet @ #x~X>~%" (-> obj control-packet))
(format #t "~1Tnum-sprites: ~D~%" (-> obj num-sprites))
(format #t "~1Tdummys[3] @ #x~X~%" (-> obj dummys))
(format #t "~1Tvecdata-packet: #<dma-packet @ #x~X>~%" (-> obj vecdata-packet))
(format #t "~1Tvecdata: #<sprite-glow-data @ #x~X>~%" (-> obj vecdata))
(format #t "~1Tshader-packet: #<dma-packet @ #x~X>~%" (-> obj shader-packet))
(format #t "~1Tmscal-packet: #<dma-packet @ #x~X>~%" (-> obj mscal-packet))
(label cfg-4)
obj
)
;; definition for symbol *sprite-glow-dma-packet-data*, type sprite-glow-dma-packet-data
(define *sprite-glow-dma-packet-data*
(new 'static 'sprite-glow-dma-packet-data
:control-packet (new 'static 'dma-packet
:dma (new 'static 'dma-tag :qwc #x1 :id (dma-tag-id cnt))
:vif0 (new 'static 'vif-tag :imm #x404 :cmd (vif-cmd stcycl))
:vif1 (new 'static 'vif-tag :imm #x8000 :num #x1 :cmd (vif-cmd unpack-v4-32))
)
:vecdata-packet (new 'static 'dma-packet
:dma (new 'static 'dma-tag :qwc #x4 :id (dma-tag-id cnt))
:vif0 (new 'static 'vif-tag :imm #x404 :cmd (vif-cmd stcycl))
:vif1 (new 'static 'vif-tag :imm #x8001 :num #x4 :cmd (vif-cmd unpack-v4-32))
)
:shader-cnt-packet (new 'static 'dma-packet
:dma (new 'static 'dma-tag :qwc #x5 :id (dma-tag-id cnt))
:vif0 (new 'static 'vif-tag :imm #x404 :cmd (vif-cmd stcycl))
:vif1 (new 'static 'vif-tag :imm #x8091 :num #x5 :cmd (vif-cmd unpack-v4-32))
)
:shader-ref-packet (new 'static 'dma-packet
:dma (new 'static 'dma-tag :qwc #x5 :id (dma-tag-id ref))
:vif0 (new 'static 'vif-tag :imm #x404 :cmd (vif-cmd stcycl))
:vif1 (new 'static 'vif-tag :imm #x8091 :num #x5 :cmd (vif-cmd unpack-v4-32))
)
:mscal-packet (new 'static 'dma-packet
:dma (new 'static 'dma-tag :id (dma-tag-id cnt))
:vif1 (new 'static 'vif-tag :cmd (vif-cmd flushe) :msk #x1)
)
)
)
;; failed to figure out what this is:
(set! (-> *sprite-glow-dma-packet-data* mscal-packet vif0)
(new 'static 'vif-tag :cmd (vif-cmd mscalf) :msk #x1 :imm #xa)
)
;; definition for function sprite-glow-add-sprite
;; INFO: Used lq/sq
;; WARN: Return type mismatch sprite-glow-cnt-template vs none.
(defun sprite-glow-add-sprite ((arg0 dma-buffer) (arg1 sprite-vec-data-2d) (arg2 float) (arg3 float) (arg4 float) (arg5 adgif-shader))
(let ((v1-0 (the-as sprite-glow-cnt-template (-> arg0 base))))
(let* ((t5-0 *sprite-glow-dma-packet-data*)
(t2-0 (-> t5-0 control-packet quad))
(t3-0 (-> t5-0 vecdata-packet quad))
(t4-0 (-> t5-0 shader-cnt-packet quad))
(t5-1 (-> t5-0 mscal-packet quad))
)
(set! (-> v1-0 control-packet quad) t2-0)
(set! (-> v1-0 num-sprites-quad) (the-as uint128 0))
(set! (-> v1-0 vecdata-packet quad) t3-0)
(set! (-> v1-0 shader-packet quad) t4-0)
(set! (-> v1-0 mscal-packet quad) t5-1)
)
(let ((t2-1 (-> arg1 x-y-z-sx quad))
(t3-1 (-> arg1 flag-rot-sy quad))
(a1-1 (-> arg1 r-g-b-a quad))
)
(set! (-> v1-0 vecdata position quad) t2-1)
(set! (-> v1-0 vecdata quads 1 quad) t3-1)
(set! (-> v1-0 vecdata color quad) a1-1)
)
(let ((a1-2 1))
(set! (-> v1-0 vecdata z-offset) arg4)
(set! (-> v1-0 vecdata fade-a) arg2)
(set! (-> v1-0 vecdata fade-b) arg3)
(set! (-> v1-0 num-sprites) (the-as uint a1-2))
)
(let ((a1-3 (-> arg5 quad 0 quad))
(a2-1 (-> arg5 quad 1 quad))
(a3-1 (-> arg5 quad 2 quad))
(t0-1 (-> arg5 quad 3 quad))
(t1-1 (-> arg5 quad 4 quad))
)
(set! (-> v1-0 shader quad 0 quad) a1-3)
(set! (-> v1-0 shader quad 1 quad) a2-1)
(set! (-> v1-0 shader quad 2 quad) a3-1)
(set! (-> v1-0 shader quad 3 quad) t0-1)
(set! (-> v1-0 shader quad 4 quad) t1-1)
)
(set! (-> arg0 base) (the-as pointer (&+ v1-0 224)))
)
(none)
)
;; definition for function sprite-glow-add-simple-sprite
;; INFO: Used lq/sq
;; WARN: Return type mismatch sprite-glow-ref-template vs none.
(defun sprite-glow-add-simple-sprite ((arg0 dma-buffer) (arg1 sprite-glow-dma-packet-data) (arg2 sprite-glow-data) (arg3 pointer))
(let ((v1-0 (the-as sprite-glow-ref-template (-> arg0 base))))
(let ((t0-0 (-> arg1 control-packet quad))
(t1-0 (-> arg1 vecdata-packet quad))
(t2-0 (-> arg1 shader-ref-packet quad))
(a1-1 (-> arg1 mscal-packet quad))
)
(set! (-> v1-0 control-packet quad) t0-0)
(set! (-> v1-0 num-sprites-quad) (the-as uint128 0))
(set! (-> v1-0 vecdata-packet quad) t1-0)
(set! (-> v1-0 shader-packet quad) t2-0)
(set! (-> v1-0 mscal-packet quad) a1-1)
)
(let ((a1-2 (-> arg2 position quad))
(t0-1 (-> arg2 quads 1 quad))
(t1-1 (-> arg2 color quad))
(a2-1 (-> arg2 quads 3 quad))
(t2-1 1)
)
(set! (-> v1-0 vecdata position quad) a1-2)
(set! (-> v1-0 vecdata quads 1 quad) t0-1)
(set! (-> v1-0 vecdata color quad) t1-1)
(set! (-> v1-0 vecdata quads 3 quad) a2-1)
(set! (-> v1-0 num-sprites) (the-as uint t2-1))
)
(set! (-> v1-0 shader-packet-ptr) arg3)
(set! (-> arg0 base) (the-as pointer (&+ v1-0 144)))
)
(none)
)
;; definition for function sprite-glow-draw
;; WARN: Return type mismatch int vs none.
(defun sprite-glow-draw ((arg0 dma-buffer))
(local-vars (a2-0 float))
(let* ((s5-0 *sprite-aux-list*)
(s4-0 (-> s5-0 entry))
(s3-0 #f)
)
(dotimes (s2-0 s4-0)
(let ((v1-2 (-> s5-0 data s2-0)))
(when (and (not s3-0) (= (-> v1-2 aux-type) (sprite-aux-type glow)))
(let* ((a0-5 (-> v1-2 aux-data omega))
(a3-0 (cond
((zero? a0-5)
(set! a2-0 0.0)
1.0
)
(else
(let* ((f1-1 (* 0.00024414062 a0-5))
(f0-4 (- f1-1 (the float (the int f1-1))))
)
(let ((f1-3 (* 4096.0 (- f1-1 f0-4))))
(set! a2-0 (/ -1.0 (* (- 1.0 f0-4) f1-3)))
)
(/ f0-4 (- 1.0 f0-4))
)
)
)
)
)
(sprite-glow-add-sprite arg0 (-> v1-2 vec-data) a2-0 a3-0 (-> v1-2 aux-data user-float) (-> v1-2 gif-data))
)
)
)
)
)
0
(none)
)
;; definition for method 9 of type simple-sprite-system
;; INFO: Used lq/sq
;; WARN: Return type mismatch int vs none.
(defmethod add! simple-sprite-system ((obj simple-sprite-system) (arg0 sprite-glow-data))
(let ((v1-0 (-> obj count)))
(when (< v1-0 (-> obj max-count))
(let* ((a2-3 (-> obj data v1-0))
(v1-2 arg0)
(a1-1 a2-3)
(a2-4 (-> v1-2 position quad))
(a3-0 (-> v1-2 quads 1 quad))
(t0-0 (-> v1-2 color quad))
(v1-3 (-> v1-2 quads 3 quad))
)
(set! (-> a1-1 position quad) a2-4)
(set! (-> a1-1 quads 1 quad) a3-0)
(set! (-> a1-1 color quad) t0-0)
(set! (-> a1-1 quads 3 quad) v1-3)
)
(+! (-> obj count) 1)
)
)
0
(none)
)
;; definition for function add-shader-to-dma
;; INFO: Used lq/sq
;; WARN: Return type mismatch pointer vs adgif-shader.
(defun add-shader-to-dma ((arg0 dma-buffer))
(let* ((a1-0 (new 'static 'dma-packet :dma (new 'static 'dma-tag :id (dma-tag-id next))))
(v1-0 (-> arg0 base))
(a1-1 (-> a1-0 quad))
(v0-0 (&+ v1-0 16))
)
(let ((a2-0 (&+ v1-0 96)))
(set! (-> (the-as (pointer uint128) v1-0)) a1-1)
(set! (-> (the-as (pointer uint32) v1-0) 1) (the-as uint a2-0))
(set! (-> arg0 base) a2-0)
)
(the-as adgif-shader v0-0)
)
)
;; definition for method 10 of type simple-sprite-system
;; WARN: Return type mismatch int vs none.
(defmethod draw-all-sprites! simple-sprite-system ((obj simple-sprite-system) (arg0 dma-buffer))
(local-vars (sv-528 sprite-glow-dma-packet-data) (sv-532 (pointer texture-id)) (sv-536 pointer))
(b! (zero? (-> obj count)) cfg-13 :delay (nop!))
(set! sv-528 *sprite-glow-dma-packet-data*)
(set! sv-532 (new 'stack-no-clear 'array 'texture-id 128))
(set! sv-536 (-> arg0 base))
(dotimes (v1-5 (-> obj count))
(set! (-> sv-532 v1-5) (-> obj data v1-5 tex-id))
)
(countdown (s4-0 (-> obj count))
(let ((s3-0 (-> sv-532 s4-0)))
(when (nonzero? s3-0)
(let ((s2-0 (add-shader-to-dma arg0)))
(adgif-shader<-texture-simple! s2-0 (lookup-texture-by-id s3-0))
(countdown (s1-1 (+ s4-0 1))
(when (= s3-0 (-> sv-532 s1-1))
(set! (-> sv-532 s1-1) (new 'static 'texture-id))
(let ((a2-1 (-> obj data s1-1)))
(sprite-glow-add-simple-sprite arg0 sv-528 a2-1 (the-as pointer s2-0))
)
)
)
)
)
)
)
(label cfg-13)
0
(none)
)
;; definition for method 11 of type simple-sprite-system
;; WARN: Return type mismatch int vs none.
(defmethod clear! simple-sprite-system ((obj simple-sprite-system))
(set! (-> obj count) 0)
0
(none)
)
;; definition for symbol *simple-sprite-system*, type simple-sprite-system
(define *simple-sprite-system*
(new 'static 'simple-sprite-system :max-count #x80 :data (new 'static 'inline-array sprite-glow-data 128
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
(new 'static 'sprite-glow-data)
)
)
)

View File

@ -791,8 +791,7 @@
;; definition for function sprite-draw
;; WARN: Return type mismatch int vs none.
;; WARN: Failed store: (s.w! (+ v1-27 8) 0) at op 160
;; WARN: Failed store: (s.w! (+ v1-27 12) 0) at op 161
;; ERROR: Failed store: (s.w! (+ v1-27 8) 0) at op 160
(defun sprite-draw ((disp display))
(let ((dma-mem-begin (-> *display* frames (-> *display* on-screen) global-buf base)))
(with-dma-buffer-add-bucket ((dma-buff (-> *display* frames (-> *display* on-screen) global-buf))
@ -878,7 +877,7 @@
)
(sprite-glow-init-engine dma-buff)
(sprite-glow-draw dma-buff)
(simple-sprite-system-method-10 *simple-sprite-system* dma-buff)
(draw-all-sprites! *simple-sprite-system* dma-buff)
(let ((v1-26 dma-buff))
(let ((pkt6 (the-as dma-packet (-> v1-26 base))))
(set! (-> pkt6 dma) (new 'static 'dma-tag :id (dma-tag-id cnt)))

View File

@ -273,7 +273,7 @@
(set! (-> s3-1 1 normal w) f0-14)
(set! (-> s3-1 1 normal x) (* 0.025 f0-14))
)
(add! *simple-sprite-system* (the-as dma-buffer (-> s3-1 1)))
(add! *simple-sprite-system* (the-as sprite-glow-data (-> s3-1 1)))
(forward-up->quaternion (the-as quaternion (-> s3-1 0)) arg1 (the-as vector (-> obj rbody state matrix)))
(quaternion-rotate-local-x! (the-as quaternion (-> s3-1 0)) (the-as quaternion (-> s3-1 0)) 32768.0)
(let ((v1-16 (-> s3-1 0 normal)))
@ -390,7 +390,7 @@
(set! (-> s4-0 color x) 255.0)
(set! (-> s4-0 color y) (rand-vu-float-range 192.0 255.0))
(set! (-> s4-0 color w) (* f30-1 (rand-vu-float-range 16.0 18.0)))
(add! *simple-sprite-system* (the-as dma-buffer s4-0))
(add! *simple-sprite-system* s4-0)
(let ((f0-21 (-> obj camera-dist2))
(f1-6 245760.0)
)
@ -403,7 +403,7 @@
(set! (-> s4-0 fade-b) 2.3332994)
(set! (-> s4-0 color z) (rand-vu-float-range 128.0 160.0))
(set! (-> s4-0 color w) (* f30-1 (rand-vu-float-range 32.0 36.0)))
(add! *simple-sprite-system* (the-as dma-buffer s4-0))
(add! *simple-sprite-system* s4-0)
)
)
)
@ -423,7 +423,7 @@
(set! (-> s4-1 rot-angle) (* 182.04445 (rand-vu-float-range -4.0 4.0)))
(set! (-> s4-1 color y) (* 64.0 (rand-vu)))
(set! (-> s4-1 color w) (* f30-1 (rand-vu-float-range 16.0 21.0)))
(add! *simple-sprite-system* (the-as dma-buffer s4-1))
(add! *simple-sprite-system* s4-1)
)
)
)