From 733a6240b2448eae09d003d5e86894683b346ff5 Mon Sep 17 00:00:00 2001 From: tmyqlfpir <80724828+tmyqlfpir@users.noreply.github.com> Date: Sat, 11 Nov 2023 11:34:46 +1000 Subject: [PATCH] Optimize viewDrawPowerUps() (#765) Reduce the number of loops computed within viewDrawPowerUps() by presorting the currently available powerups. --- source/blood/src/view.cpp | 118 ++++++++++++++++++++++---------------- 1 file changed, 67 insertions(+), 51 deletions(-) diff --git a/source/blood/src/view.cpp b/source/blood/src/view.cpp index 3a18d64f18..80493a5671 100644 --- a/source/blood/src/view.cpp +++ b/source/blood/src/view.cpp @@ -1311,70 +1311,86 @@ void viewDrawStats(PLAYER *pPlayer, int x, int y) viewDrawText(3, buffer, x, y, 20, 0, 0, true, 256); } -struct POWERUPDISPLAY -{ +#define kPowerUps 11 + +const struct POWERUPDISPLAY { int nTile; - float nScaleRatio; + int nScaleRatio; int yOffset; - int remainingDuration; +} gPowerups[kPowerUps] = { + {gPowerUpInfo[kPwUpShadowCloak].picnum, fix16_from_float(0.4f), 0}, // invisibility + {gPowerUpInfo[kPwUpReflectShots].picnum, fix16_from_float(0.4f), 5}, // reflects enemy shots + {gPowerUpInfo[kPwUpDeathMask].picnum, fix16_from_float(0.3f), 9}, // invulnerability + {gPowerUpInfo[kPwUpTwoGuns].picnum, fix16_from_float(0.25f), 4}, // guns akimbo + {gPowerUpInfo[kPwUpShadowCloakUseless].picnum, fix16_from_float(0.4f), 9}, // shadow cloak (does nothing, only appears at near the end of CP04) + + // not in official maps + {gPowerUpInfo[kPwUpFeatherFall].picnum, fix16_from_float(0.3f), 7}, // feather fall + {gPowerUpInfo[kPwUpGasMask].picnum, fix16_from_float(0.4f), 4}, // gas mask + {gPowerUpInfo[kPwUpDoppleganger].picnum, fix16_from_float(0.5f), 5}, // doppelganger + {gPowerUpInfo[kPwUpAsbestArmor].picnum, fix16_from_float(0.3f), 9}, // asbestos armor + {gPowerUpInfo[kPwUpGrowShroom].picnum, fix16_from_float(0.4f), 4}, // grow shroom + {gPowerUpInfo[kPwUpShrinkShroom].picnum, fix16_from_float(0.4f), 4}, // shrink shroom }; -#define nPowerUps 11 - -void sortPowerUps(POWERUPDISPLAY* powerups) { - for (int i = 1; i < nPowerUps; i++) - { - for (int j = 0; j < nPowerUps-i; j++) - { - if (powerups[j].remainingDuration > powerups[j+1].remainingDuration) - { - POWERUPDISPLAY temp = powerups[j]; - powerups[j] = powerups[j+1]; - powerups[j+1] = temp; - } - } - } -} - void viewDrawPowerUps(PLAYER* pPlayer) { if (!gPowerupDuration) return; - POWERUPDISPLAY powerups[nPowerUps]; - powerups[0] = { gPowerUpInfo[kPwUpShadowCloak].picnum, 0.4f, 0, pPlayer->pwUpTime[kPwUpShadowCloak] }; // Invisibility - powerups[1] = { gPowerUpInfo[kPwUpReflectShots].picnum, 0.4f, 5, pPlayer->pwUpTime[kPwUpReflectShots] }; // Reflects enemy shots - powerups[2] = { gPowerUpInfo[kPwUpDeathMask].picnum, 0.3f, 9, pPlayer->pwUpTime[kPwUpDeathMask] }; // Invulnerability - powerups[3] = { gPowerUpInfo[kPwUpTwoGuns].picnum, 0.3f, 5, pPlayer->pwUpTime[kPwUpTwoGuns] }; // Guns Akimbo - powerups[4] = { gPowerUpInfo[kPwUpShadowCloakUseless].picnum, 0.4f, 9, pPlayer->pwUpTime[kPwUpShadowCloakUseless] }; // Does nothing, only appears at near the end of Cryptic Passage's Lost Monastery (CP04) - - // Not in official maps, but custom maps can use them - powerups[5] = { gPowerUpInfo[kPwUpFeatherFall].picnum, 0.3f, 7, pPlayer->pwUpTime[kPwUpFeatherFall] }; // Makes player immune to fall damage - powerups[6] = { gPowerUpInfo[kPwUpGasMask].picnum, 0.4f, 4, pPlayer->pwUpTime[kPwUpGasMask] }; // Makes player immune to choke damage - powerups[7] = { gPowerUpInfo[kPwUpDoppleganger].picnum, 0.5f, 5, pPlayer->pwUpTime[kPwUpDoppleganger] }; // Works in multiplayer, it swaps player's team colors, so enemy team player thinks it's a team mate - powerups[8] = { gPowerUpInfo[kPwUpAsbestArmor].picnum, 0.3f, 9, pPlayer->pwUpTime[kPwUpAsbestArmor] }; // Makes player immune to fire damage and draws HUD - powerups[9] = { gPowerUpInfo[kPwUpGrowShroom].picnum, 0.4f, 4, pPlayer->pwUpTime[kPwUpGrowShroom] }; // Grows player size, works only if gModernMap == true - powerups[10] = { gPowerUpInfo[kPwUpShrinkShroom].picnum, 0.4f, 4, pPlayer->pwUpTime[kPwUpShrinkShroom] }; // Shrinks player size, works only if gModernMap == true - - sortPowerUps(powerups); - - const int warningTime = 5; - const int x = 15; - int y = 50; - for (int i = 0; i < nPowerUps; i++) + int nPowerActive[kPowerUps]; + nPowerActive[0] = pPlayer->pwUpTime[kPwUpShadowCloak]; // invisibility + nPowerActive[1] = pPlayer->pwUpTime[kPwUpReflectShots]; // reflects enemy shots + nPowerActive[2] = pPlayer->pwUpTime[kPwUpDeathMask]; // invulnerability + nPowerActive[3] = pPlayer->pwUpTime[kPwUpTwoGuns];// guns akimbo + nPowerActive[4] = pPlayer->pwUpTime[kPwUpShadowCloakUseless]; // shadow cloak + + // not in official maps + nPowerActive[5] = pPlayer->pwUpTime[kPwUpFeatherFall]; // feather fall + nPowerActive[6] = pPlayer->pwUpTime[kPwUpGasMask]; // gas mask + nPowerActive[7] = pPlayer->pwUpTime[kPwUpDoppleganger]; // doppelganger + nPowerActive[8] = pPlayer->pwUpTime[kPwUpAsbestArmor]; // asbestos armor + nPowerActive[9] = pPlayer->pwUpTime[kPwUpGrowShroom]; // grow shroom + nPowerActive[10] = pPlayer->pwUpTime[kPwUpShrinkShroom]; // shrink shroom + + int nSortPower[kPowerUps+1]; + unsigned char nSortIndex[kPowerUps+1]; + unsigned char nSortCount = 0; + for (int i = 0; i < kPowerUps; i++) // sort powerups + { + if (!nPowerActive[i]) + continue; + nSortIndex[nSortCount] = i; + nSortPower[nSortCount] = nPowerActive[i]; + nSortCount++; + } + for (int i = 1; i < nSortCount; i++) { - if (powerups[i].remainingDuration) + for (int j = 0; j < nSortCount-i; j++) { - int remainingSeconds = powerups[i].remainingDuration / 100; - if (remainingSeconds > warningTime || ((int)totalclock & 32)) - { - DrawStatMaskedSprite(powerups[i].nTile, x, y + powerups[i].yOffset, 0, 0, 256, (int)(65536 * powerups[i].nScaleRatio)); - } - - DrawStatNumber("%d", remainingSeconds, kSBarNumberInv, x + 15, y, 0, remainingSeconds > warningTime ? 0 : 2, 256, 65536 * 0.5); - y += 20; + if (nSortPower[j] <= nSortPower[j+1]) + continue; + nSortPower[kPowerUps] = nSortPower[j]; + nSortPower[j] = nSortPower[j+1]; + nSortPower[j+1] = nSortPower[kPowerUps]; + nSortIndex[kPowerUps] = nSortIndex[j]; + nSortIndex[j] = nSortIndex[j+1]; + nSortIndex[j+1] = nSortIndex[kPowerUps]; } } + + const int nWarning = 5; + const int x = 15; + int y = 50; + for (int i = 0; i < nSortCount; i++) + { + const POWERUPDISPLAY *pPowerups = &gPowerups[nSortIndex[i]]; + int nTime = nSortPower[i] / 100; + if (nTime > nWarning || ((int)totalclock & 32)) + DrawStatMaskedSprite(pPowerups->nTile, x, y + pPowerups->yOffset, 0, 0, 256, pPowerups->nScaleRatio); + DrawStatNumber("%d", nTime, kSBarNumberInv, x + 15, y, 0, nTime > nWarning ? 0 : 2, 256, fix16_from_float(0.5f)); + y += 20; + } } void viewDrawMapTitle(void)