Alchemy
Loading...
Searching...
No Matches

map_animation.c

Go to the documentation of this file.
1/// @file
2/// Timed map effects: tile animation, the blend script, palette cycles.
3/// Part of field.c, the field object, compiled only through it.
4
5#include "../field_internal.h"
6
7/// Each frame: runs the 16 tile animation channels. A channel script is
8/// groups of four halfwords (source tile, count, destination tile, frames to
9/// wait) that copy tiles into VRAM; 0xfeNN jumps to halfword offset NN * 2,
10/// 0xfeff stops, and 0xffff loops to the start. MapAnimation_StartChannels
11/// schedules it (order 0xc80); the world map's still view
12/// (WorldMap_BeginStillView) suspends it. Moves each channel's cursor and timer
13/// in the map work. The retries stay gotos: as an inner for (;;) loop with
14/// continue and break, loop.c reshapes the channel loop.
16 // Each channel is written (mapState->anim + channelIndex): as
17 // mapState->anim[channelIndex], 78 of 119 instructions differ in tbs-en, and
18 // a channel pointer swaps ip and lr.
19 struct MapState *mapState = gMapWork[0];
20 u32 channelIndex;
21
22 for (channelIndex = 0; channelIndex <= 15; channelIndex++) {
23 const u16 *commands;
24 u32 sourceTileOrOpcode;
25 u32 tileCount;
26 u32 destinationTile;
27
28 // A channel with no script, or paused by a scene, keeps its place.
29 if ((mapState->anim + channelIndex)->start == NULL ||
30 (mapState->anim + channelIndex)->paused != 0)
31 continue;
32 // While the wait lasts the channel only counts down; when it is over,
33 // commands run in this same frame until one sets a new wait or stops.
34 next:
35 if ((mapState->anim + channelIndex)->timer == 0) {
36 commands = (mapState->anim + channelIndex)->cursor;
37 sourceTileOrOpcode = *commands++;
38 if (sourceTileOrOpcode == 0xffff) {
39 (mapState->anim + channelIndex)->cursor =
40 (mapState->anim + channelIndex)->start;
41 goto next;
42 }
43 // 0xfeff leaves the cursor on itself, so the channel stays stopped
44 // until it is started again; 0xfeNN jumps to halfword NN * 2 of the
45 // channel's script.
46 if ((sourceTileOrOpcode & 0xff00) == 0xfe00) {
47 if ((sourceTileOrOpcode & 0xff) == 0xff)
48 continue;
49 (mapState->anim + channelIndex)->cursor =
50 (mapState->anim + channelIndex)->start +
51 (sourceTileOrOpcode & 0xff) * 2;
52 goto next;
53 }
54 tileCount = *commands++;
55 destinationTile = commands[0];
56 (mapState->anim + channelIndex)->timer = commands[1];
57 // A source tile from 0x600 (0x200 for 64-byte tiles) is read from
58 // the copy in RAM; a lower one is copied within VRAM. The count is in
59 // tiles, eight words each (16 when wide).
60 if (mapState->wideTiles == 0) {
61 if (sourceTileOrOpcode >= 0x600)
62 Dma_Set(Ram_DecodeBuffer + sourceTileOrOpcode * 32,
63 BG_CHAR_BLOCK(1) + destinationTile * 32,
64 (DMA_ENABLE | DMA_32BIT) << 16 | tileCount * 8, REG_DMA3);
65 else
66 Dma_Set(BG_CHAR_BLOCK(1) + sourceTileOrOpcode * 32,
67 BG_CHAR_BLOCK(1) + destinationTile * 32,
68 (DMA_ENABLE | DMA_32BIT) << 16 | tileCount * 8, REG_DMA3);
69 } else {
70 if (sourceTileOrOpcode >= 0x200)
71 Dma_Set(Ram_MapBlocks + sourceTileOrOpcode * 64,
72 BG_CHAR_BLOCK(2) + destinationTile * 64,
73 (DMA_ENABLE | DMA_32BIT) << 16 | tileCount * 16, REG_DMA3);
74 else
75 Dma_Set(BG_CHAR_BLOCK(2) + sourceTileOrOpcode * 64,
76 BG_CHAR_BLOCK(2) + destinationTile * 64,
77 (DMA_ENABLE | DMA_32BIT) << 16 | tileCount * 16, REG_DMA3);
78 }
79 // A copy with a wait of 0 lets the next command run at once.
80 (mapState->anim + channelIndex)->cursor += 4;
81 goto next;
82 } else {
83 (mapState->anim + channelIndex)->timer--;
84 }
85 }
86}
87
88/// Resumes tile animation channel channelIndex by clearing its paused byte.
89/// Scenes and the lobby (menu/lobby.c, channel 5) reach it through
90/// Map_ClearLayerEntryFlagFar.
91void Map_ClearLayerEntryFlag(u32 channelIndex) {
92 struct MapState *mapState = gMapWork[0];
93 struct MapAnimation *channel = &mapState->anim[channelIndex];
94
95 channel->paused = 0;
96}
97
98/// Pauses tile animation channel channelIndex by setting its paused byte.
99/// Scenes and the lobby (menu/lobby.c, channel 5) reach it through
100/// Map_SetLayerEntryFlagFar.
101void Map_SetLayerEntryFlag(u32 channelIndex) {
102 struct MapState *mapState = gMapWork[0];
103 struct MapAnimation *channel = &mapState->anim[channelIndex];
104
105 channel->paused = 1;
106}
107
108/// Starts the tile animation channels a map's animation script lists: each
109/// 0xfdNN marker starts channel NN & 15 there (paused when bit 7 is set).
110/// Clears all 16 channels first, and schedules MapAnimation_Update when any
111/// starts. Called by Map_LoadLayeredScene with the map's own script, and by
112/// Map_InitializePerspectiveScene with the world map's default one.
113void MapAnimation_StartChannels(const u16 *script) {
114 struct MapState *mapState;
115 s32 channelsStarted;
116 u32 marker;
117
118 mapState = gMapWork[0];
119 channelsStarted = 0;
120 Dma_Fill32(0, mapState->anim, sizeof(mapState->anim));
121 // Each channel's script starts just after its marker and runs on through
122 // the rest of the stream; the scan steps over the halfwords between
123 // markers. Only the low four bits pick the channel, so a marker for 16 or
124 // more reuses one of the 16.
125 marker = *script++;
126 while (marker != 0xffff) {
127 if ((marker & 0xff00) == 0xfd00) {
128 struct MapAnimation *channel;
129 u32 channelIndex = marker & 15;
130 u32 paused = 0;
131 if (marker & 0x80)
132 paused = 1;
133 channel = &mapState->anim[channelIndex];
134 channel->start = script;
135 channel->cursor = script;
136 channel->timer = 0;
137 channel->paused = paused;
138 channelsStarted++;
139 }
140 marker = *script++;
141 }
142 // A map with no channels never schedules the update.
143 if (channelsStarted != 0)
145}
146
147/// Suspends the tile animations, unless the world map's still view is shown.
148/// Menu_SuspendFieldTasks (menu/menu/common.c) calls it
149/// through MapAnimation_SuspendFar.
151 if (((struct MapScrollWork *)gMapWork[0])->animationActive == 0)
153}
154
155/// Resumes the tile animations, unless the world map's still view is shown.
156/// Menu_ResumeFieldTasks (menu/menu/common.c) calls it
157/// through MapAnimation_ResumeFar.
159 if (((struct MapScrollWork *)gMapWork[0])->animationActive == 0)
161}
162
163/// Each frame: runs the map's blend script. A 0x3NNN command sets BLDCNT; any
164/// other sets BLDALPHA (or BLDY when not alpha blending) and waits the halfword
165/// after it in frames; 0xfeNN jumps, 0xfeff stops and 0xffff loops.
166/// DisplayBlend_StartScript schedules it (order 0xc80). Writes REG_BLDCNT,
167/// REG_BLDALPHA and REG_BLDY, and keeps the last BLDCNT in the map work's
168/// blendControl.
170 // The retries stay gotos: as a for (;;) loop with continue, loop.c hoists
171 // blendControl's address and 118 bytes of tbs-en's code change.
172 struct MapState *mapState = gMapWork[0];
173 struct BlendScriptState *blend;
174 u16 *commands;
175 u32 instruction;
176 u32 delayOrJumpIndex;
177 u16 delay16;
178
179 blend = &mapState->blend;
180 if (blend->script == 0)
181 return;
182 if (blend->paused != 0)
183 return;
184
185 // As with the tile channels, commands run in one frame until a level sets
186 // a wait; a BLDCNT command and the jumps take no time.
187again:
188 delayOrJumpIndex = blend->delay;
189 delay16 = delayOrJumpIndex;
190 if (delay16 == 0) {
191 commands = blend->cursor;
192 instruction = *commands;
193 commands++;
194 if (instruction == 0xffff) {
195 blend->cursor = blend->script;
196 goto again;
197 }
198
199 if ((instruction & 0xff00) == 0xfe00) {
200 delayOrJumpIndex = instruction & 0xff;
201 if (delayOrJumpIndex == 0xff)
202 return;
203 blend->cursor = blend->script + delayOrJumpIndex * 2;
204 goto again;
205 }
206
207 // A BLDCNT value is told apart by its top four bits being 3, its second
208 // target's sprite and backdrop bits. A level cannot reach 0x3000: the
209 // BLDALPHA coefficients and BLDY go to 16 at most.
210 if ((instruction & 0xf000) == 0x3000) {
211 REG_BLDCNT = instruction;
212 mapState->blendControl = instruction;
213 blend->cursor++;
214 goto again;
215 }
216
217 // BLDCNT's effect bits (7..6) of 1 are alpha blending; 2 and 3 fade
218 // to white or black by BLDY.
219 if ((mapState->blendControl & 0xc0) == 0x40)
220 REG_BLDALPHA = instruction;
221 else
222 REG_BLDY = instruction;
223 blend->delay = commands[0];
224 blend->cursor += 2;
225 goto again;
226 }
227 // Adding 0xffff to the halfword counts the wait down by one.
228 blend->delay = delayOrJumpIndex + 0xffff;
229}
230
231/// Starts a map's blend script, unless it is empty. Clears the map work's
232/// three-word blend state first, then schedules DisplayBlend_RunScript.
233/// Called by Map_LoadLayeredScene when the map's header has a blend script.
235 struct BlendScriptState *blend;
236 s32 hasScript;
237 volatile u32 zero;
238
239 // A fixed-source DMA of the zero word clears script, cursor, delay and
240 // paused; a script that is only its end marker leaves the blend unset.
241 hasScript = 0;
242 zero = 0;
243 blend = &((struct MapState *)gMapWork[0])->blend;
244 Dma_Set((const void *)&zero, blend,
245 (DMA_ENABLE | DMA_32BIT | DMA_SRC_FIXED) << 16 | 3, REG_DMA3);
246 if (*script != 0xffff) {
247 blend->script = script;
248 blend->cursor = script;
249 blend->delay = 0;
250 blend->paused = 0;
251 hasScript = 1;
252 }
253 if (hasScript)
255}
256
257/// Suspends the blend script. The lighthouse scenes and Vale's Babi scene
258/// reach it through DisplayBlend_SuspendScriptFar.
261}
262
263/// Resumes the blend script, through DisplayBlend_ResumeScriptFar.
266}
267
268/// Allocates the palette cycling queue (heap slot 28) with its four entries
269/// cleared.
271 struct PaletteSnapshotWork *paletteCycles;
272 struct PaletteSnapshot *cycle;
273 u16 cycleIndex;
274 u16 colorIndex;
275
276 paletteCycles = Runtime_AllocateBlock(28, sizeof(struct PaletteSnapshotWork));
277 cycle = paletteCycles->entries;
278 // Four cycles of up to 16 saved colours each.
279 for (cycleIndex = 0; cycleIndex != 4; cycleIndex++) {
280 cycle->source = 0;
281 cycle->position = 0;
282 cycle->timer = 0;
283 cycle->delay = 0;
284 cycle->count = 0;
285 for (colorIndex = 0; colorIndex != 16; colorIndex++) {
286 cycle->colors[colorIndex] = 0;
287 }
288 cycle++;
289 }
290 paletteCycles->count = 0;
291}
292
293/// Adds a palette cycle: colorCount colours of background palette paletteBank
294/// from firstColor, rotated by one every delay + 1 frames. Returns 0, or -1
295/// when all four cycles are taken. The cycle keeps a copy of the colours as
296/// they were, which every step rotates from.
297UNUSED s32 PaletteQueue_Add(s16 paletteBank, s16 firstColor, s16 delay,
298 s16 colorCount) {
299 struct PaletteSnapshotWork *paletteQueue;
300 struct PaletteSnapshot *cycle;
301 u16 *paletteColors;
302 u32 cycleIndex;
303 u16 colorCount16;
304
305 paletteQueue = gPaletteWork;
306 cycleIndex = paletteQueue->count;
307 if (cycleIndex > 3)
308 return -1;
309 // 16 colours to a palette bank; the cycle saves the colours as they are
310 // now, one halfword each.
311 cycle = &paletteQueue->entries[cycleIndex];
312 paletteColors = (u16 *)BG_PLTT + (((u16)paletteBank << 4) + (u16)firstColor);
313 colorCount16 = colorCount;
314 cycle->position = 0;
315 cycle->timer = 0;
316 cycle->count = colorCount16;
317 cycle->source = paletteColors;
318 cycle->delay = delay;
319 Dma_Set(paletteColors, cycle->colors, DMA_ENABLE << 16 | colorCount16,
320 REG_DMA3);
321 paletteQueue->count++;
322 return 0;
323}
324
325/// Stops the palette cycles and frees their queue (heap slot 28).
329}
330
331/// Starts running the palette cycles each frame.
334}
335
336/// Each frame: advances each palette cycle whose timer has run out by one
337/// colour, writing the rotated colours back to the palette. Only
338/// PaletteQueue_Start schedules it, and nothing calls that, so no palette
339/// cycle runs in the game.
341 struct PaletteSnapshotWork *paletteQueue = gPaletteWork;
342 u8 cycleIndex;
343 // BUG: four queued cycles become zero here, so none advance.
344 u16 activeCycles = paletteQueue->count & 3;
345 u16 rotatedColors[16];
346
347 for (cycleIndex = 0; cycleIndex < activeCycles; cycleIndex++) {
348 struct PaletteSnapshot *cycle = &paletteQueue->entries[cycleIndex];
349 if (cycle->timer == 0) {
350 u16 rotationOffset = cycle->position;
351 u16 colorCount = cycle->count;
352 void *paletteColors = cycle->source;
353 u16 *savedColors = cycle->colors;
354 u8 colorIndex;
355
356 // Each saved colour moves rotationOffset places down, the first ones
357 // wrapping round to the end.
358 for (colorIndex = colorCount - rotationOffset; colorIndex < colorCount;
359 colorIndex++)
360 rotatedColors[colorIndex] = *savedColors++;
361 for (colorIndex = 0; colorIndex < colorCount - rotationOffset;
362 colorIndex++)
363 rotatedColors[colorIndex] = *savedColors++;
364 Dma_Set(rotatedColors, paletteColors, DMA_ENABLE << 16 | colorCount,
365 REG_DMA3);
366 // The next step rotates one place further, back to none after a full
367 // turn, and waits delay frames.
368 rotationOffset++;
369 if (rotationOffset >= colorCount)
370 rotationOffset = 0;
371 cycle->position = rotationOffset;
372 cycle->timer = cycle->delay;
373 } else {
374 cycle->timer--;
375 }
376 }
377}
static __inline__ void Dma_Set(const volatile void *source, volatile void *destination, u32 control, volatile u32 *channel)
Starts a DMA transfer: stores the source, destination and control words into channel's registers with...
Definition dma.h:62
#define Dma_Fill32(value, destination, size)
Fills size bytes at destination with the word value by DMA3.
Definition dma.h:30
What every part of the field object shares: its includes and the few names more than one part uses.
void * gMapWork[]
struct PaletteSnapshotWork * gPaletteWork
void * Runtime_AllocateBlock(s32 kind, s32 size)
As Runtime_AllocateHeapBlock, but tries EWRAM first, for blocks that need room more than speed: the b...
Definition heap.c:80
#define BG_CHAR_BLOCK(n)
Definition io_reg.h:166
#define REG_BLDY
Definition io_reg.h:146
#define DMA_32BIT
Definition io_reg.h:210
#define DMA_SRC_FIXED
Definition io_reg.h:207
#define REG_DMA3
Definition io_reg.h:153
#define REG_BLDALPHA
Definition io_reg.h:142
#define BG_PLTT
Definition io_reg.h:157
#define REG_BLDCNT
Definition io_reg.h:119
#define DMA_ENABLE
Definition io_reg.h:217
void DisplayBlend_SuspendScript(void)
Suspends the blend script.
UNUSED void PaletteQueue_Initialize(void)
Allocates the palette cycling queue (heap slot 28) with its four entries cleared.
UNUSED s32 PaletteQueue_Add(s16 paletteBank, s16 firstColor, s16 delay, s16 colorCount)
Adds a palette cycle: colorCount colours of background palette paletteBank from firstColor,...
void Map_SetLayerEntryFlag(u32 channelIndex)
Pauses tile animation channel channelIndex by setting its paused byte.
void MapAnimation_Update(void)
Each frame: runs the 16 tile animation channels.
void DisplayBlend_StartScript(u16 *script)
Starts a map's blend script, unless it is empty.
UNUSED void PaletteQueue_Stop(void)
Stops the palette cycles and frees their queue (heap slot 28).
void MapAnimation_Resume(void)
Resumes the tile animations, unless the world map's still view is shown.
void Map_ClearLayerEntryFlag(u32 channelIndex)
Resumes tile animation channel channelIndex by clearing its paused byte.
void PaletteQueue_StepCycles(void)
Each frame: advances each palette cycle whose timer has run out by one colour, writing the rotated co...
void DisplayBlend_ResumeScript(void)
Resumes the blend script, through DisplayBlend_ResumeScriptFar.
UNUSED void PaletteQueue_Start(void)
Starts running the palette cycles each frame.
void DisplayBlend_RunScript(void)
Each frame: runs the map's blend script.
void MapAnimation_StartChannels(const u16 *script)
Starts the tile animation channels a map's animation script lists: each 0xfdNN marker starts channel ...
void MapAnimation_Suspend(void)
Suspends the tile animations, unless the world map's still view is shown.
void Runtime_ReleaseHeapBlock(s32 slot)
#define Ram_MapBlocks
Definition ram_buffer.h:12
#define Ram_DecodeBuffer
Definition ram_buffer.h:11
s32 Scheduler_ResumeTasks(SchedulerCallback callback)
Resumes the task running callback, or every task when callback is null, by clearing bit 0 of its orde...
Definition scheduler.c:243
s32 Scheduler_AddOrUpdateCallback(SchedulerCallback callback, s32 order)
Schedules callback with order, or gives a task already running it the new order, and re-sorts the tab...
Definition scheduler.c:102
s32 Scheduler_SuspendTasks(SchedulerCallback callback)
Suspends the task running callback, or every task when callback is null, by setting bit 0 of its orde...
Definition scheduler.c:172
s32 Scheduler_RemoveCallback(SchedulerCallback callback)
Unschedules the task running callback: clears its routine and gives it order 0x7fff,...
Definition scheduler.c:146
#define NULL
Definition bilibin.h:6
The map's running blend script, which sets the blend registers over time.
Definition map.h:31
u16 * cursor
Definition map.h:33
u16 * script
Definition map.h:32
u16 delay
frames
Definition map.h:34
One of the 16 tile animation channels, which copy tiles into VRAM by script.
Definition map.h:40
const u16 * cursor
Definition map.h:42
u16 timer
frames
Definition map.h:43
const u16 * start
Definition map.h:41
u16 paused
Definition map.h:44
The field map's work: the followed position, screen shake, tile animations, blend script,...
Definition map_scroll.h:27
The map work in heap slot 8 (struct MapScrollWork), seen as its tile animation channels,...
Definition map.h:49
u8 blendControl
The last BLDCNT the blend script wrote; with mode 1 in bits 7..6 its values go to BLDALPHA,...
Definition map.h:59
struct MapAnimation anim[16]
Definition map.h:54
struct BlendScriptState blend
Definition map.h:55
u8 wideTiles
nonzero: tile animations copy 64-byte tiles
Definition map.h:52
The palette cycling queue (heap slot 28): four cycles and how many are in use.
Definition palqueue.h:24
struct PaletteSnapshot entries[4]
Definition palqueue.h:25
u16 count
Cycles in use, 0 to 4; PaletteQueue_StepCycles masks four to none.
Definition palqueue.h:27
A palette cycle: a run of up to 16 background palette colours, saved and rotated by one colour every ...
Definition palqueue.h:13
s16 delay
frames; the timer restarts from it
Definition palqueue.h:17
u16 count
colours in the run
Definition palqueue.h:18
u16 colors[16]
the run's colours as saved when the cycle was added
Definition palqueue.h:19
u16 * source
the first colour of the run, in BG palette RAM
Definition palqueue.h:14
u16 position
colours rotated so far, 0 to count - 1
Definition palqueue.h:15
u16 timer
frames until the next rotation
Definition palqueue.h:16
signed int s32
Definition types.h:14
unsigned int u32
Definition types.h:15
signed short s16
Definition types.h:12
unsigned short u16
Definition types.h:13
#define UNUSED
Definition types.h:22
unsigned char u8
Definition types.h:11