diff options
-rw-r--r-- | asm/field_screen_effect.s | 138 | ||||
-rw-r--r-- | asm/overworld.s | 2 | ||||
-rw-r--r-- | data/field_weather.s | 2 | ||||
-rw-r--r-- | ld_script.txt | 1 | ||||
-rw-r--r-- | src/field_screen_effect.c | 75 |
5 files changed, 95 insertions, 123 deletions
diff --git a/asm/field_screen_effect.s b/asm/field_screen_effect.s index f6e1c2f05..6e5a0dc5f 100644 --- a/asm/field_screen_effect.s +++ b/asm/field_screen_effect.s @@ -5,112 +5,8 @@ .text - thumb_func_start sub_807EE00 -sub_807EE00: @ 807EE00 - push {lr} - cmp r1, 0xA0 - bhi _0807EE28 - cmp r2, 0 - bge _0807EE0C - movs r2, 0 -_0807EE0C: - cmp r2, 0xFF - ble _0807EE12 - movs r2, 0xFF -_0807EE12: - cmp r3, 0 - bge _0807EE18 - movs r3, 0 -_0807EE18: - cmp r3, 0xFF - ble _0807EE1E - movs r3, 0xFF -_0807EE1E: - lsls r1, 1 - adds r1, r0 - lsls r0, r2, 8 - orrs r0, r3 - strh r0, [r1] -_0807EE28: - pop {r0} - bx r0 - thumb_func_end sub_807EE00 - - thumb_func_start sub_807EE2C -sub_807EE2C: @ 807EE2C - push {r4-r7,lr} - mov r7, r10 - mov r6, r9 - mov r5, r8 - push {r5-r7} - sub sp, 0x4 - str r0, [sp] - mov r10, r1 - mov r9, r2 - adds r6, r3, 0 - mov r8, r6 - movs r7, 0 - cmp r6, 0 - blt _0807EEA8 -_0807EE48: - mov r0, r9 - subs r1, r0, r7 - mov r0, r10 - subs r4, r0, r6 - adds r5, r0, r6 - ldr r0, [sp] - adds r2, r4, 0 - adds r3, r5, 0 - bl sub_807EE00 - mov r0, r9 - adds r1, r0, r7 - ldr r0, [sp] - adds r2, r4, 0 - adds r3, r5, 0 - bl sub_807EE00 - mov r0, r9 - subs r1, r0, r6 - mov r0, r10 - subs r4, r0, r7 - adds r5, r0, r7 - ldr r0, [sp] - adds r2, r4, 0 - adds r3, r5, 0 - bl sub_807EE00 - mov r0, r9 - adds r1, r0, r6 - ldr r0, [sp] - adds r2, r4, 0 - adds r3, r5, 0 - bl sub_807EE00 - mov r1, r8 - adds r1, 0x1 - lsls r0, r7, 1 - subs r1, r0 - mov r8, r1 - adds r7, 0x1 - cmp r1, 0 - bge _0807EEA4 - subs r1, r6, 0x1 - lsls r0, r1, 1 - add r8, r0 - adds r6, r1, 0 -_0807EEA4: - cmp r6, r7 - bge _0807EE48 -_0807EEA8: - add sp, 0x4 - pop {r3-r5} - mov r8, r3 - mov r9, r4 - mov r10, r5 - pop {r4-r7} - pop {r0} - bx r0 - thumb_func_end sub_807EE2C - - thumb_func_start sub_807EEB8 -sub_807EEB8: @ 807EEB8 + thumb_func_start UpdateFlashLevelEffect +UpdateFlashLevelEffect: @ 807EEB8 push {r4-r6,lr} lsls r0, 24 lsrs r5, r0, 24 @@ -148,7 +44,7 @@ _0807EEE6: ldrsh r2, [r4, r3] movs r5, 0x6 ldrsh r3, [r4, r5] - bl sub_807EE2C + bl SetFlashScanlineEffectWindowBoundaries movs r0, 0x1 strh r0, [r4] b _0807EF76 @@ -169,7 +65,7 @@ _0807EF14: ldrsh r2, [r4, r3] movs r6, 0x6 ldrsh r3, [r4, r6] - bl sub_807EE2C + bl SetFlashScanlineEffectWindowBoundaries movs r0, 0 strh r0, [r4] ldrh r0, [r4, 0xA] @@ -205,14 +101,14 @@ _0807EF76: pop {r4-r6} pop {r0} bx r0 - thumb_func_end sub_807EEB8 + thumb_func_end UpdateFlashLevelEffect thumb_func_start sub_807EF7C sub_807EF7C: @ 807EF7C push {r4,lr} lsls r0, 24 lsrs r4, r0, 24 - ldr r0, _0807EFA0 @ =sub_807EEB8 + ldr r0, _0807EFA0 @ =UpdateFlashLevelEffect bl FuncIsActiveTask lsls r0, 24 cmp r0, 0 @@ -225,7 +121,7 @@ _0807EF98: pop {r0} bx r0 .align 2, 0 -_0807EFA0: .4byte sub_807EEB8 +_0807EFA0: .4byte UpdateFlashLevelEffect thumb_func_end sub_807EF7C thumb_func_start sub_807EFA4 @@ -262,7 +158,7 @@ sub_807EFC8: @ 807EFC8 ldr r0, [sp, 0x20] lsls r0, 24 lsrs r7, r0, 24 - ldr r0, _0807F00C @ =sub_807EEB8 + ldr r0, _0807F00C @ =UpdateFlashLevelEffect movs r1, 0x50 bl CreateTask lsls r0, 24 @@ -284,7 +180,7 @@ sub_807EFC8: @ 807EFC8 strh r7, [r1, 0xA] b _0807F018 .align 2, 0 -_0807F00C: .4byte sub_807EEB8 +_0807F00C: .4byte UpdateFlashLevelEffect _0807F010: .4byte gTasks+0x8 _0807F014: negs r0, r7 @@ -314,7 +210,7 @@ sub_807F028: @ 807F028 bne _0807F042 movs r5, 0x1 _0807F042: - ldr r1, _0807F070 @ =gUnknown_83C68D4 + ldr r1, _0807F070 @ =sFlashLevelPixelRadii lsls r0, 1 adds r0, r1 ldrh r2, [r0] @@ -334,25 +230,25 @@ _0807F042: pop {r0} bx r0 .align 2, 0 -_0807F070: .4byte gUnknown_83C68D4 +_0807F070: .4byte sFlashLevelPixelRadii thumb_func_end sub_807F028 - thumb_func_start sub_807F074 -sub_807F074: @ 807F074 + thumb_func_start WriteFlashScanlineEffectBuffer +WriteFlashScanlineEffectBuffer: @ 807F074 push {r4,lr} lsls r0, 24 lsrs r0, 24 cmp r0, 0 beq _0807F0A2 ldr r4, _0807F0A8 @ =gScanlineEffectRegBuffers - ldr r1, _0807F0AC @ =gUnknown_83C68D4 + ldr r1, _0807F0AC @ =sFlashLevelPixelRadii lsls r0, 1 adds r0, r1 ldrh r3, [r0] adds r0, r4, 0 movs r1, 0x78 movs r2, 0x50 - bl sub_807EE2C + bl SetFlashScanlineEffectWindowBoundaries movs r0, 0xF0 lsls r0, 3 adds r1, r4, r0 @@ -366,8 +262,8 @@ _0807F0A2: bx r0 .align 2, 0 _0807F0A8: .4byte gScanlineEffectRegBuffers -_0807F0AC: .4byte gUnknown_83C68D4 - thumb_func_end sub_807F074 +_0807F0AC: .4byte sFlashLevelPixelRadii + thumb_func_end WriteFlashScanlineEffectBuffer thumb_func_start sub_807F0B0 sub_807F0B0: @ 807F0B0 diff --git a/asm/overworld.s b/asm/overworld.s index 21fce8cac..47c5d26af 100644 --- a/asm/overworld.s +++ b/asm/overworld.s @@ -3949,7 +3949,7 @@ sub_8056A34: @ 8056A34 lsrs r0, 24 cmp r0, 0 beq _08056A52 - bl sub_807F074 + bl WriteFlashScanlineEffectBuffer ldr r2, _08056A58 @ =gUnknown_826D330 ldr r0, [r2] ldr r1, [r2, 0x4] diff --git a/data/field_weather.s b/data/field_weather.s index 890f0fef6..090c19f6b 100644 --- a/data/field_weather.s +++ b/data/field_weather.s @@ -391,5 +391,5 @@ gUnknown_83C68B8:: gUnknown_83C68BC:: @ 83C68BC spr_template 4613, 4608, gOamData_AffineOff_ObjNormal_8x8, gUnknown_83C68B8, NULL, gDummySpriteAffineAnimTable, unc_0807DAB4 -gUnknown_83C68D4:: @ 83C68D4 +sFlashLevelPixelRadii:: @ 83C68D4 .2byte 0x00c8, 0x0048, 0x0038, 0x0028, 0x0018, 0x0000 diff --git a/ld_script.txt b/ld_script.txt index bc926bf3c..afc559688 100644 --- a/ld_script.txt +++ b/ld_script.txt @@ -121,6 +121,7 @@ SECTIONS { asm/field_weather.o(.text); asm/field_weather_effects.o(.text); src/field_fadetransition.o(.text); + src/field_screen_effect.o(.text); asm/field_screen_effect.o(.text); src/battle_setup.o(.text); asm/cable_club.o(.text); 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--; + } + } +} |