Attempt to decompile handRenderHudGauge

This commit is contained in:
Ryan Dwyer 2021-04-18 22:47:25 +10:00
parent a76566fd69
commit eb099e32d4
3 changed files with 298 additions and 10 deletions

View File

@ -30856,10 +30856,10 @@ Gfx *handRenderHudInteger(Gfx *gdl, s32 value, s32 x, bool halign, s32 y, s32 va
void abmagReset(struct abmag *abmag)
{
abmag->unk00 = 0;
abmag->unk05 = 0;
abmag->unk04 = 0;
abmag->unk02 = 0;
abmag->loadedammo = 0;
abmag->change = 0;
abmag->ref = 0;
abmag->timer60 = 0;
}
#if VERSION >= VERSION_PAL_FINAL
@ -32396,6 +32396,277 @@ glabel handRenderHudGauge
);
#endif
/**
* Render an ammo gauge on the HUD.
*
* Ammo gauges can be displayed in two ways. If the capacity is less than 20,
* each bullet is displayed as a separate block with a gap between each. If the
* capacity is 20 or more, a single block covers the whole gauge and the block
* is partitioned into two (filled and empty).
*
* For the separated mode, a unit refers to a single bullet/block.
* For the merged mode, a unit refers to a single 1px high line in the gauge.
*/
// Mismatch: Regalloc (play with the if-statements near 3a8)
// Some potential clues:
// - gaugeheight variable can be removed and usages replaced with (y2 - y1)
// - (s32)ref can be made into a variable
// - At 278, asm effectively does y2 - y2 + y1, so a tmp variable is used to
// prevent optimising out the y2s
// - Unsigned comparison at fadeamount > 255U
// - There are several callee-save registers (s2, s5, s8) which can either be
// variables or used by the compiler to hold expressions that are used several
// times. Below, s2 is a variable while s5 and s8 are inline expressions.
//Gfx *handRenderHudGauge(Gfx *gdl, s32 x1, s32 y1, s32 x2, s32 y2, struct abmag *abmag, s32 remaining, s32 capacity, u32 emptycolour, u32 filledcolour, bool flip)
//{
// s32 gaugeheight = y2 - y1; // s2
// s32 unitheight;
// s32 remainder1;
// s32 remainder2;
// s32 gaugetop; // bc
// f32 ref; // b8
// s32 numunits = capacity; // b4 = s1
// s32 i;
//
// // 020
// func0f0a9da8(abmag, remaining, capacity, gaugeheight);
//
// if (capacity > 20) {
// // Use a single merged bar
// ref = abmag->ref;
// unitheight = 1;
// numunits = gaugeheight;
// gaugetop = y2 - gaugeheight;
// } else {
// // 05c
// // Use a separate block for each bullet
// ref = abmag->ref;
// unitheight = gaugeheight / capacity;
// remainder1 = unitheight * capacity - gaugeheight;
// remainder2 = (unitheight + 1) * capacity - gaugeheight;
//
// if (remainder1 < 0) {
// remainder1 = -remainder1;
// }
//
// if (remainder2 < 0) {
// remainder2 = -remainder2;
// }
//
// if (remainder2 < remainder1) {
// unitheight++;
// }
//
// gaugetop = y2 - unitheight * capacity + 1;
//
// if (unitheight <= 2) {
// gaugetop--;
// }
// }
//
// // 104
// if (unitheight == 0) {
// /**
// * Using separate blocks, but the clip capacity is more than the gauge
// * height meaning each block is less than 1px. This is impossible
// * because the gauge switches modes away from separate blocks at 20,
// * therefore this code is unreachable.
// *
// * This code renders the gauge in the merged style, but uses 1px per
// * bullet and truncates the gauge at the gaugetop if needed. This is
// * clearly an early revision of the code, as it is visually misleading
// * and also lacks the transition effect.
// */
// s32 partitiony;
// s32 tmp;
//
// gaugeheight = y2 - gaugetop;
// partitiony = y2 - gaugeheight * ref / numunits;
// tmp = y2;
//
// // 150
// if (partitiony > gaugetop) {
// // Render empty partition
// gdl = gfxSetPrimColour(gdl, emptycolour);
//
// if (flip) {
// gDPFillRectangleScaled(gdl++, x1, y2 - partitiony + y1, x2, gaugeheight + y1);
// } else {
// gDPFillRectangleScaled(gdl++, x1, gaugetop, x2, partitiony);
// }
//
// gdl = func0f153838(gdl);
// }
//
// // 25c
// // Render filled partition
// gdl = gfxSetPrimColour(gdl, filledcolour);
//
// // 278
// if (flip) {
// gDPFillRectangleScaled(gdl++, x1, y2 - tmp + y1, x2, y2 - partitiony + y1);
// } else {
// // 2e4
// gDPFillRectangleScaled(gdl++, x1, partitiony, x2, y2);
// }
// } else {
// // 338
// u32 colour;
// s32 unittop;
// s32 unitbottom;
//
// gdl = gfxSetPrimColour(gdl, emptycolour);
//
// unittop = gaugetop; // s5
// unitbottom = -1;
//
// for (i = 0; i < numunits; i++) {
// // 3a8
// bool newstate = false;
//
// //if (gaugetop + i * unitheight);
// //if (abmag);
// if (capacity);
//
// // 3b0
// if (abmag->change > 0) {
// // Loading or reloading
// // 3bc
// if (i >= numunits - (s32)ref - abmag->change && i < numunits - (s32)ref) {
// // Unit is potentially unsettled
// s32 fadeamount = abmag->timer60 - (numunits - (s32)ref - i - 1) * 64;
//
// // 3e0
// if (fadeamount >= 0) {
// if (fadeamount >= 64) {
// // Unit is transitioning to filled
// u32 weight = (fadeamount * 4 - 252) / 3;
//
// if (weight > 255) {
// weight = 255;
// }
//
// colour = colourBlend(filledcolour, 0xffffffbf, weight);
// } else {
// // Unit is bright and has not started transitioning to filled yet
// colour = colourBlend(0xffffffbf, emptycolour, fadeamount * 4);
// }
//
// newstate = true;
// }
// }
// } else /*478*/ if (abmag->change < 0) {
// // Firing
// if (i < numunits - (s32)ref - abmag->change && i >= numunits - (s32)ref) {
// s32 fadeamount = abmag->timer60 - (i - numunits + (s32)ref) * 64;
//
// // 48c
// if (fadeamount >= 0) {
// if (fadeamount > 255U) {
// colour = emptycolour;
// } else {
// // Unit was recently emptied
// colour = colourBlend(emptycolour, filledcolour | 0xff, fadeamount);
// }
//
// newstate = true;
// }
// }
// }
//
// // 4fc
// // Special case for units which are one after the last one being
// // faded. I think their colour is calculated incorrectly by the code
// // above and this is resetting them to the normal filled colour.
// if (abmag->change < 0) {
// // Firing
// if (i == numunits - (s32)ref - abmag->change) {
// colour = filledcolour;
// newstate = true;
// }
// } else {
// // 51c
// if (i == numunits - (s32)ref) {
// colour = filledcolour;
// newstate = true;
// }
// }
//
// // 52c
// // Calculate unittop and unitbottom. For merged gauges keep unittop
// // as it is if possible, so the empty and filled partitions can be
// // drawn whenever the state is changed in order to save gfx calls.
// if (unitheight <= 2) {
// // 534
// if (newstate) {
// // 53c
// if (unitbottom >= 0) {
// // Render empty or transitioning unit of merged gauge
// // 544
// if (flip) {
// gDPFillRectangleScaled(gdl++, x1, y2 - unitbottom + y1, x2, y2 - unittop + y1);
// } else {
// // 5b4
// gDPFillRectangleScaled(gdl++, x1, unittop, x2, unitbottom);
// }
// }
//
// unittop = gaugetop + i * unitheight;
// }
//
// unitbottom = gaugetop + i * unitheight + unitheight;
// } else {
// // 614
// // Separate blocks - reduce unitbottom by 1 to make a gap
// unittop = gaugetop + i * unitheight;
// unitbottom = gaugetop + i * unitheight + unitheight - 1;
// }
//
// // 61c
// if (newstate) {
// gDPSetPrimColorViaWord(gdl++, 0, 0, colour);
// }
//
// // 640
// // For separate blocks, clip the unit bottom to the bottom of the gauge
// if (unitbottom >= y2 - 1 && unitheight >= 2) {
// unitbottom = y2;
// }
//
// // 658
// // Render separated blocks
// if (unitheight >= 3) {
// // 660
// if (flip) {
// gDPFillRectangleScaled(gdl++, x1, y2 - unitbottom + y1, x2, y2 - unittop + y1);
// } else {
// // 6d0
// gDPFillRectangleScaled(gdl++, x1, unittop, x2, unitbottom);
// }
// }
// } // end loop
//
// // For merged gauges, render the final partition
// if (unitheight <= 2) {
// s32 stack;
//
// // 754
// if (flip) {
// gDPFillRectangleScaled(gdl++, x1, y2 - unitbottom + y1, x2, y2 - unittop + y1);
// } else {
// // 7c4
// gDPFillRectangleScaled(gdl++, x1, unittop, x2, unitbottom);
// }
// }
// }
//
// gdl = func0f153838(gdl);
//
// gDPSetRenderMode(gdl++, G_RM_AA_XLU_SURF, G_RM_AA_XLU_SURF2);
//
// return gdl;
//}
#if VERSION >= VERSION_PAL_FINAL
GLOBAL_ASM(
glabel handRenderHud

View File

@ -165,7 +165,7 @@ s32 weaponGetAmmoCapacity(s32 weaponnum, s32 func);
Gfx *handRenderHudString(Gfx *gdl, char *text, s32 x, bool halign, s32 y, s32 valign, u32 colour);
Gfx *handRenderHudInteger(Gfx *gdl, s32 value, s32 x, bool halign, s32 y, s32 valign, u32 colour);
void abmagReset(struct abmag *abmag);
u32 func0f0a9da8(void);
void func0f0a9da8(struct abmag *abmag, s32 remaining, s32 capacity, s32 height);
Gfx *handRenderHudGauge(Gfx *gdl, s32 x1, s32 y1, s32 x2, s32 y2, struct abmag *abmag, s32 remaining, s32 capacity, u32 vacantcolour, u32 occupiedcolour, bool flip);
Gfx *handRenderHud(Gfx *gdl);
void cboostAdd(s32 arg0);

View File

@ -2058,11 +2058,28 @@ struct beam {
};
struct abmag {
u16 unk00;
u16 unk02;
u8 unk04;
u8 unk05;
u16 alignment;
// When the gauge uses separate bars, this is zero/unused. When the gauge
// uses merged bars, this is the same figure as displayed on the HUD.
/*0x00*/ u16 loadedammo;
// Counts up to 255 when firing or reloading. It's used to determine the
// brightness of the bar in the ammo gauge.
/*0x02*/ s16 timer60;
// When firing, this is the number of bars still loaded + any bars recently
// fired which are fading to empty.
// When loading, this is the number of bars which are loaded and don't have
// a fade effect on them.
// In other words, it's a reference to where the fade effects start and is
// also a reference for the timer.
/*0x04*/ s8 ref;
// When positive, is the number of slots remaining to settle when reloading,
// including slots which are fully empty.
// When negative, is the number of slots remaining to settle when firing.
/*0x05*/ s8 change;
/*0x06*/ u16 alignment;
};
// The first 4 bytes of the hand struct