Listed as in progress because I'd like to optimize the HSV->RGB conversion a bit if I can. It's a really long code as is, but it works.
Makes Puff's bow costume cycle through hue at a a given rate, with some constant saturation and value.
Makes Puff's bow costume cycle through hue at a a given rate, with some constant saturation and value.
C206CB7C 0000003B
8138002C 88090007
2C00000F 408201C0
88090619 2C000002
408201B4 C029FFC0
4800018D 7C6802A6
C0430010 EC21102A
C042E3CC 48000149
D029FFC0 FD000890
C1230008 C143000C
C002E694 EC210024
FD600890 C0428048
48000125 C0029D80
FC210028 FC200A10
FC200828 ECE902B2
ED070072 FC200090
FC0B0840 41810014
FC203890 FC404090
C062A1C4 48000080
EC21002A FC0B0840
41810014 FC204090
FC403890 C062A1C4
48000064 EC21002A
FC0B0840 41810014
C022A1C4 FC403890
FC604090 48000048
EC21002A FC0B0840
41810014 C022A1C4
FC404090 FC603890
4800002C EC21002A
FC0B0840 41810014
FC204090 C042A1C4
FC603890 48000010
FC203890 C042A1C4
FC604090 EC0A3828
EC21002A EC42002A
EC63002A C0030014
EC210032 EC630032
C0030018 EC420032
FC20081E D821FFF8
8081FFFC FC40101E
D841FFF8 80A1FFFC
FC60181E D861FFF8
80C1FFFC 5484583E
50A42D74 7C843378
38690108 80630000
3CA00002 60A5DBF0
7C632A14 B0830000
48000054 EC211024
FD800890 C8028B00
FC21002A FC210028
FC016040 EC2C0828
4081000C C0029D80
FC20082A EC2100B2
4E800020 4E800021
C3300000 00000000
XXXXXXXX YYYYYYYY
ZZZZZZZZ 41F80000
427C0000 8001001C
60000000 00000000
Parameters (All as floating point):
XXXXXXXX: Saturation, in the range [0, 1]
YYYYYYYY: Value, in the range [0, 1]
ZZZZZZZZ: Hue rate, degrees per frame
I've been using 3F400000, 3F000000, 3DCCCCCD which seems to look all right. Experiment and find what looks good to you.
8138002C 88090007
2C00000F 408201C0
88090619 2C000002
408201B4 C029FFC0
4800018D 7C6802A6
C0430010 EC21102A
C042E3CC 48000149
D029FFC0 FD000890
C1230008 C143000C
C002E694 EC210024
FD600890 C0428048
48000125 C0029D80
FC210028 FC200A10
FC200828 ECE902B2
ED070072 FC200090
FC0B0840 41810014
FC203890 FC404090
C062A1C4 48000080
EC21002A FC0B0840
41810014 FC204090
FC403890 C062A1C4
48000064 EC21002A
FC0B0840 41810014
C022A1C4 FC403890
FC604090 48000048
EC21002A FC0B0840
41810014 C022A1C4
FC404090 FC603890
4800002C EC21002A
FC0B0840 41810014
FC204090 C042A1C4
FC603890 48000010
FC203890 C042A1C4
FC604090 EC0A3828
EC21002A EC42002A
EC63002A C0030014
EC210032 EC630032
C0030018 EC420032
FC20081E D821FFF8
8081FFFC FC40101E
D841FFF8 80A1FFFC
FC60181E D861FFF8
80C1FFFC 5484583E
50A42D74 7C843378
38690108 80630000
3CA00002 60A5DBF0
7C632A14 B0830000
48000054 EC211024
FD800890 C8028B00
FC21002A FC210028
FC016040 EC2C0828
4081000C C0029D80
FC20082A EC2100B2
4E800020 4E800021
C3300000 00000000
XXXXXXXX YYYYYYYY
ZZZZZZZZ 41F80000
427C0000 8001001C
60000000 00000000
Parameters (All as floating point):
XXXXXXXX: Saturation, in the range [0, 1]
YYYYYYYY: Value, in the range [0, 1]
ZZZZZZZZ: Hue rate, degrees per frame
I've been using 3F400000, 3F000000, 3DCCCCCD which seems to look all right. Experiment and find what looks good to you.
Thanks to @UnclePunch for the Press Down For A Random Bow Color code, which I referenced while making this.
I'm sure there's a more optimized way to implement the HSV->RGB conversion algorithm in ASM. I've taken a very basic approach here.
I'm sure there's a more optimized way to implement the HSV->RGB conversion algorithm in ASM. I've taken a very basic approach here.
Code:
# Rainbow Puff Bow Experimental [rmn]
# Hue change speed in degrees per frame, value, and saturation
# options are found in the data section at the end of the code.
# This code is long and unoptimized. Hasn't been tested
# extensively so be cautious.
# Inject at 8006cb7c
# Original instruction: lwz r0, 0x1C(r1)
# By default saves hue to 0x20 of the player entity struct.
# If you are using that space for something else, change
# those two lines to point somewhere else. That location
# defaults to 0, and the code expects a non-negative value
# value when loading a float from that location so you may
# have to initialize the memory you choose to use.
# r24 = player entity struct pointer
lwz r9, 0x2c(r24) # player data pointer
lbz r0, 0x7(r9)
cmpwi r0, 0xf # check character ID
bne done
lbz r0, 0x619(r9)
cmpwi r0, 2 # check costume ID
bne done
# Calculate C and X terms.
# Reference used for HSV->RGB conversion:
# https://en.wikipedia.org/wiki/HSL_and_HSV#Converting_to_RGB
lfs f1, -0x40(r9) # load hue #####################
bl constants
mflr r3
lfs f2, 0x10(r3) # hue deg/frame
fadds f1, f1, f2 # increment hue
lfs f2, -0x1c34(r2) # 360
bl float_mod # keep hue in [0, 360]
stfs f1, -0x40(r9) # save hue #####################
fmr f8, f1 # hue
lfs f9, 8(r3) # sat
lfs f10, 0xC(r3) # value
lfs f0, -0x196C(r2) # 60
fdivs f1, f1, f0 # Hue/60deg = H'
fmr f11, f1
lfs f2, -0x7fb8(r2) # 2
bl float_mod # H' mod 2
lfs f0, -0x6280(r2) # 1
fsub f1, f1, f0
fabs f1, f1 # |H' mod 2 - 1|
fsub f1, f0, f1 # 1 - |H' mod 2 - 1|
fmuls f7, f9, f10 # Chroma
fmuls f8, f7, f1 # X
find_region: # get R1, G1, B1
fmr f1, f0
fcmpo cr0, f11, f1
bgt gt1
fmr f1, f7
fmr f2, f8
lfs f3, -0x5e3c(r2) # 0
b region_found
gt1:
fadds f1, f1, f0
fcmpo cr0, f11, f1
bgt gt2
fmr f1, f8
fmr f2, f7
lfs f3, -0x5e3c(r2)
b region_found
gt2:
fadds f1, f1, f0
fcmpo cr0, f11, f1
bgt gt3
lfs f1, -0x5e3c(r2)
fmr f2, f7
fmr f3, f8
b region_found
gt3:
fadds f1, f1, f0
fcmpo cr0, f11, f1
bgt gt4
lfs f1, -0x5e3c(r2)
fmr f2, f8
fmr f3, f7
b region_found
gt4:
fadds f1, f1, f0
fcmpo cr0, f11, f1
bgt gt5
fmr f1, f8
lfs f2, -0x5e3c(r2)
fmr f3, f7
b region_found
gt5:
fmr f1, f7
lfs f2, -0x5e3c(r2)
fmr f3, f8
region_found:
# Get R, G, B. Will fall in range [0, 1]
fsubs f0, f10, f7 # m
fadds f1, f1, f0 # R
fadds f2, f2, f0 # G
fadds f3, f3, f0 # B
# RGB565 format:
# R and B will range from 0 to 0x1F, G will range from 0 to 0x3F
lfs f0, 0x14(r3)
fmuls f1, f1, f0
fmuls f3, f3, f0
lfs f0, 0x18(r3)
fmuls f2, f2, f0
# Convert R, G, B to integers
fctiwz f1, f1
stfd f1, -8(r1)
lwz r4, -4(r1) # R
fctiwz f2, f2
stfd f2, -8(r1)
lwz r5, -4(r1) # G
fctiwz f3, f3
stfd f3, -8(r1)
lwz r6, -4(r1) # B
# Build 16-bit color value
rlwinm r4, r4, 11, 0, 31
rlwimi r4, r5, 5, 21, 26
or r4, r4, r6 # RGB565 value
# Overwrite the bow texture color in memory
addi r3, r9, 0x108
lwz r3, 0(r3)
lis r5, 0x0002
ori r5, r5, 0xdbf0
add r3, r3, r5 # texture address
sth r4, 0(r3) # store new color
b done
float_mod:
# f1 = f1 mod f2
# r3 = pointer to constants data block
# destroys f12 but that doesn't break anything here
# Expects positive values
fdivs f1, f1, f2
fmr f12, f1
lfd f0, -0x7500(r2) # 43300000 00000000
fadd f1, f1, f0 # round value in f1 to nearest integer
fsub f1, f1, f0 # (only for positive values!)
fcmpo cr0, f1, f12
fsubs f1, f12, f1 # get remainder
ble fm_rounded_down
fm_rounded_up:
lfs f0, -0x6280(r2) # 1
fadd f1, f0, f1 # correct sign
fm_rounded_down:
fmuls f1, f1, f2 # get mod
blr
constants:
blrl
.long 0xc3300000 ; constant for fp rounding
.long 0x00000000
.long 0x3F400000 ; saturation = 0.75
.long 0x3F000000 ; value = 0.5
.long 0x3DCCCCCD ; hue degrees per frame = 0.1
.long 0x41F80000 ; 31, constant
.long 0x427C0000 ; 63, constant
done:
lwz r0, 0x1C(r1) ;instruction replaced with injection
Last edited: