GBAlatro
A Demake of Balatro for the GBA
Loading...
Searching...
No Matches
affine_background.c
1#include "affine_background.h"
2
3#include "affine_background_gfx.h"
4#include "affine_main_menu_background_gfx.h"
5#include "graphic_utils.h"
6
7#define ANIMATION_SPEED_DIVISOR 16
8
9// Prepare screen during VBLANK
10// Pre-computes the affine matrices values for each scanline and stores in bgaff_arr. This is to be
11// done in VBLANK so the HBLANK code can just fetch the values quickly.
12static IWRAM_CODE void s_affine_background_prep_bgaff_arr();
13
14static BG_AFFINE s_bgaff_arr[SCREEN_HEIGHT + 1];
15static AFF_SRC_EX s_asx = {0};
16static enum AffineBackgroundID s_background = AFFINE_BG_NONE;
17static uint s_timer = 0;
18
20{
22
23 REG_BG_AFFINE[AFFINE_BG_IDX] = bg_aff_default;
24}
25
26IWRAM_CODE void affine_background_hblank()
27{
28 vu16 vcount = REG_VCOUNT;
29
30 if ((vcount >= SCREEN_HEIGHT)) // Exit the function if the scanline is outside the screen
31 {
32 return;
33 }
34
35 // See comment in affine_background_prep_bgaff_arr()
36 REG_BG_AFFINE[AFFINE_BG_IDX] = s_bgaff_arr[vcount + 1];
37}
38
40{
41 if (REG_IE & IRQ_HBLANK) // High quality mode with HBLANK interrupt
42 {
43 s_affine_background_prep_bgaff_arr();
44 }
45 else // Low quality mode without HBLANK interrupt
46 {
47 s_asx.scr_x = 0;
48 s_asx.scr_y = 0;
49 s_asx.tex_x += 5;
50 s_asx.tex_y += 12;
51 // Scale the sine value to fit in a s16
52 s_asx.sx = ((lu_sin(s_timer * 100)) >> 8) + 256;
53 // Scale the sine value to fit in a s16
54 s_asx.sy = ((lu_sin(s_timer * 100 + 0x4000)) >> 8) + 256;
55 s_asx.alpha = 0;
56
57 bg_rotscale_ex(&s_bgaff_arr[0], &s_asx);
58 REG_BG_AFFINE[AFFINE_BG_IDX] = s_bgaff_arr[0];
59 }
60
61 s_timer++;
62}
63
65{
66 // Reload the palette to reset any previous color scaling.
67 // Take source color directly from `affine_background_gfxPal` to avoid excessive
68 // darkening in case this function is called twice by mistake.
70 for (int i = 0; i < AFFINE_BG_PAL_LEN; i++)
71 {
72 clr_rgbscale(&pal_bg_mem[AFFINE_BG_PB] + i, affine_background_gfxPal + i, 1, color);
73 }
74}
75
77{
78 memcpy16(&pal_bg_mem[AFFINE_BG_PB], src, AFFINE_BG_PAL_LEN);
79}
80
82{
83 if (s_background == new_bg)
84 {
85 return;
86 }
87
88 s_background = new_bg;
89
90 switch (s_background)
91 {
93 REG_BG2CNT &= ~BG_AFF_32x32;
94 REG_BG2CNT |= BG_AFF_16x16;
95 REG_IE |= IRQ_HBLANK; // Enable HBLANK
96
98 (u32*)&tile8_mem[AFFINE_BG_CBB],
99 (const u32*)affine_main_menu_background_gfxTiles,
100 affine_main_menu_background_gfxTilesLen / 4,
102 );
103 GRIT_CPY(&se_mem[AFFINE_BG_SBB], affine_main_menu_background_gfxMap);
104 affine_background_load_palette(affine_main_menu_background_gfxPal);
105 break;
106 case AFFINE_BG_GAME:
107 REG_BG2CNT &= ~BG_AFF_16x16;
108 REG_BG2CNT |= BG_AFF_32x32;
109 REG_IE &= ~IRQ_HBLANK; // Disable HBLANK
110
112 (u32*)&tile8_mem[AFFINE_BG_CBB],
113 (const u32*)affine_background_gfxTiles,
114 affine_background_gfxTilesLen / 4,
116 );
117 GRIT_CPY(&se_mem[AFFINE_BG_SBB], affine_background_gfxMap);
118 affine_background_load_palette(affine_background_gfxPal);
119 break;
120 default:
121 break;
122 }
123}
124
125static IWRAM_CODE void s_affine_background_prep_bgaff_arr()
126{
127 for (u16 vcount = 0; vcount < SCREEN_HEIGHT; vcount++)
128 {
129 const s32 timer_s32 = s_timer << 8;
130 const s32 vcount_s32 = vcount << 8;
131 const s16 vcount_s16 = vcount;
132 const s32 vcount_sine = lu_sin(vcount_s32 + timer_s32 / ANIMATION_SPEED_DIVISOR);
133
134 s_asx.scr_x = (SCREEN_WIDTH / 2);
135 // scr_y must equal vcount otherwise the background will have no vertical difference
136 s_asx.scr_y = vcount_s16 - (SCREEN_HEIGHT / 2);
137 s_asx.tex_x = (1000 * 1000) + (vcount_sine);
138 s_asx.tex_y = (1000 * 1000);
139 s_asx.sx = 128;
140 s_asx.sy = 128;
141 s_asx.alpha = vcount_sine + (timer_s32 / ANIMATION_SPEED_DIVISOR);
142
143 bg_rotscale_ex(&s_bgaff_arr[vcount], &s_asx);
144 }
145
146 /* HBLANK occurs after the scanline so REG_VCOUNT represents the
147 * the scanline that just passed, so when it's SCREEN_HEIGHT we will
148 * actually be updating the first line
149 */
150 s_bgaff_arr[SCREEN_HEIGHT] = s_bgaff_arr[0];
151}
Utilities for affine background on GBA.
void affine_background_set_color(COLOR color)
Update the affine background color.
void affine_background_init()
Initialize resources for affine background rendering.
IWRAM_CODE void affine_background_update()
Per-frame update of the affine background.
#define AFFINE_BG_IDX
The index of the affine background BGCNT register etc.
AffineBackgroundID
An ID to specify background rendering types.
@ AFFINE_BG_GAME
Display background for game play.
@ AFFINE_BG_NONE
Display background for the initial splash screen.
@ AFFINE_BG_MAIN_MENU
Display background for main menu.
void affine_background_change_background(enum AffineBackgroundID new_bg)
Update the background id.
#define AFFINE_BG_PAL_LEN
Number of u16 colors available in the palette.
IWRAM_CODE void affine_background_hblank()
Interrupt routine to update display on HBLANK.
void affine_background_load_palette(const u16 *src)
Set the background palette.
#define AFFINE_BG_PB
The starting index of the background palette.
Graphic utility functions.
void memcpy32_tile8_with_palette_offset(u32 *dst, const u32 *src, uint wcount, u8 palette_offset)
Copies 32 bit data from src to dst, applying a palette offset to the data.