diff options
author | Martin Griffin <martin.griffin@algosport.co.uk> | 2019-12-20 14:24:40 +0000 |
---|---|---|
committer | Martin Griffin <martin.griffin@algosport.co.uk> | 2019-12-23 18:47:39 +0000 |
commit | 2c08f9f6fb521f33c6e58aa1970beaf969872f1f (patch) | |
tree | 7e464dfc11a67f87515b3d106e603ee85d06aede /src/field_screen_effect.c | |
parent | 7984a91c0892e0bd96ace89405d565ec0b43e084 (diff) |
Describe flash scanline effect
Based on pokeemerald's functions of the same name.
Diffstat (limited to 'src/field_screen_effect.c')
-rw-r--r-- | src/field_screen_effect.c | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/src/field_screen_effect.c b/src/field_screen_effect.c new file mode 100644 index 000000000..19ed25950 --- /dev/null +++ b/src/field_screen_effect.c @@ -0,0 +1,75 @@ +#include "global.h" + +void SetFlashScanlineEffectWindowBoundary(u16 *dest, u32 y, s32 left, s32 right) +{ + if (y <= 160) + { + if (left < 0) + left = 0; + if (left > 255) + left = 255; + if (right < 0) + right = 0; + if (right > 255) + right = 255; + dest[y] = (left << 8) | right; + } +} + +/* + * Draws a circle by approximating xy² + yx² = radius². + * + * error is approximately xy² - yx². Negative values mean the circle is + * slightly too large, and positive values mean the circle is slightly + * too small. By decreasing xy whenever the error becomes negative the + * code slightly under-approximates the size of the circle. + * + * The subtractive terms compute yx² - (yx - 1)², and therefore the sum + * is yx² - 1: + * yx | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 + * (yx * 2) - 1 | -1 | 1 | 3 | 5 | 7 | 9 | 11 | 13 + * yx² - (yx - 1)² | -1 | 1 | 3 | 5 | 7 | 9 | 11 | 13 + * cumulative error | -1 | 0 | 3 | 8 | 15 | 24 | 35 | 48 + * yx² | 0 | 1 | 4 | 9 | 16 | 25 | 36 | 49 + * + * The additive terms compute xy² - (xy - 1)² - 1, and therefore the sum + * (badly) approximates Σi² - (i - 1)², i ∈ (xy, r), consider r = 18: + * xy | 18 | 17 | 16 | 15 | 14 | 13 | ... | 0 + * xy² - (xy - 1)² | 35 | 33 | 31 | 29 | 27 | 25 | ... | -1 + * 2 * (xy - 1) | 34 | 32 | 30 | 28 | 26 | 24 | ... | -2 + * cumulative error | 34 | 66 | 96 | 124 | 150 | 174 | ... | 304 + * Σi² - (i - 1)² | 35 | 68 | 99 | 128 | 155 | 180 | ... | 323 + * 18² = 324, so if the iterations ran until xy = 0 the cumulative error + * would be xy² - r. + * + * The error is initialized to r, which corrects for the error in the + * additive terms. In practice all r iterations don't occur because we + * early-exit when yx > xy, so it's half-way between a fix for that + * error and an approximation of the midpoint between r² and (r + 1)². + * + * The algorithm takes advantage of symmetry to compute boundaries in + * both directions out from centerY (using yx for y), and also both + * directions *in* from centerY ± radius (using xy for y). Because xy + * doesn't change on every iteration, we will frequently overwrite + * boundaries set in the previous iteration. + */ +void SetFlashScanlineEffectWindowBoundaries(u16 *dest, s32 centerX, s32 centerY, s32 radius) +{ + s32 xy = radius; + s32 error = radius; + s32 yx = 0; + while (xy >= yx) + { + SetFlashScanlineEffectWindowBoundary(dest, centerY - yx, centerX - xy, centerX + xy); + SetFlashScanlineEffectWindowBoundary(dest, centerY + yx, centerX - xy, centerX + xy); + SetFlashScanlineEffectWindowBoundary(dest, centerY - xy, centerX - yx, centerX + yx); + SetFlashScanlineEffectWindowBoundary(dest, centerY + xy, centerX - yx, centerX + yx); + error -= (yx * 2) - 1; + yx++; + if (error < 0) + { + error += 2 * (xy - 1); + xy--; + } + } +} |