Alchemy
Loading...
Searching...
No Matches

view.c

Go to the documentation of this file.
1/// @file
2/// Screen shake, the copied BG row drawer and the ground plane scanlines.
3/// Part of field.c, the field object, compiled only through it.
4
5#include "../field_internal.h"
6
7#define MAP_SHAKE_SETTLE_FRAMES 300
8#define MAP_SHAKE_SETTLE_MAX_AMPLITUDE (Q16_ONE / 256 - 1)
9#define TILEMAP_TILE_BANK_BYTES (256 * (8 * 8))
10#define TILEMAP_MAP_BANK_BYTES (64 * 64)
11
12/// Changes the shake without restarting an axis whose argument is negative.
13/// Amplitudes are 16.16 pixels and decay is a 16.16 multiplier per frame.
14/// Scene commands reach it through Map_SetShake and Map_SetScreenShakeFar.
15void Map_SetScreenShake(s32 shakeX, s32 shakeY, s32 shakeDecay) {
16 struct MapScrollWork *work;
17
18 // A negative argument leaves that value alone, so a scene can change the
19 // decay without restarting the shake, or start one axis only. The view
20 // updates read the same three words on the world map (PerspectiveWork).
21 work = gMapWork[0];
22 if (shakeX >= 0) {
23 work->shakeX = shakeX;
24 }
25 if (shakeY >= 0) {
26 work->shakeY = shakeY;
27 }
28 if (shakeDecay >= 0) {
29 work->shakeDecay = shakeDecay;
30 }
31}
32
33/// Waits until both shake amplitudes are below 1/256 pixel, with a 300-frame
34/// limit for a shake whose decay never settles. Scene imports reach it as
35/// Map_WaitForShakeToSettleFar; it stops further shake after the wait.
37 struct MapScrollWork *work;
38 s32 waitedFrames;
39
40 work = gMapWork[0];
41 waitedFrames = 0;
42 // 300 frames is five seconds; 255 in 16.16 is just under 1/256 pixel.
43 // A decay of 1.0 or more never settles, so the limit ends the wait.
44 while (waitedFrames < MAP_SHAKE_SETTLE_FRAMES &&
47 WaitFrames(1);
48 waitedFrames++;
49 }
50 // A zero decay makes the next view update's shake its last.
51 work->shakeDecay = 0;
52}
53
54/// The copied ARM kernel reads the BG2 affine row from each 32-byte pair and
55/// writes 240 by 160 pixels as 256-colour tiles.
56typedef void (*TileMapRowDrawer)(const struct MapAffinePair *lines, u8 *pixels,
57 const u8 *tiles, const u8 *map);
58
59/// Draws the current affine page into the world map's still-view pixels.
60/// WorldMap_BeginStillView supplies 160 pairs and a 240 by 160 byte output.
61/// The ARM kernel borrows HEAP_SLOT_TEMP_RENDERER for this synchronous call;
62/// it is released before returning, while both graphics buffers stay owned
63/// by the world map.
64void TileMap_DrawRowsFromRam(const struct MapAffinePair *lines, u8 *pixels) {
65 const u8 *base;
66
67 // The second tile and map banks are BG2. The kernel falls back to BG3's
68 // preceding banks when a BG2 pixel is transparent.
69 base = gDecodeBuffer;
72 /* FAKEMATCH(one-pass): its loop notes keep gBgTileBuffer's address load ahead
73 * of lines' move into r0, as native; as the bare call, 1 of 39 instructions
74 * differs in tbs-en. */
75 do {
79 } while (0);
81}
82
83/// Rebuilds the ground plane's scanline terms when the world map pitch changes.
84/// Map_InitializePerspectiveScene and WorldMap_UpdateView supply the pitch's
85/// sine/cosine ratio and the followed position, both in 16.16. Each screen line
86/// gets a width scale and signed ground distance, or zeros above the horizon;
87/// Transform_UpdateVertices reads them to build the frame's affine page.
88void WorldMap_BuildScanlineTable(s32 pitchSlope, s32 *position,
89 struct MapScanline *scanline) {
90 s32 groundPoint[3];
91 s32 cameraPoint[3];
92 s32 horizon;
93 s32 focus;
94 s32 *cameraCoordinates;
95 s32 line;
96 s32 distance;
97 s32 difference;
98 s32 scale;
99 s32 horizontalSquared;
100 s32 verticalSquared;
101 s32 diagonal;
102 s32 vertical;
103 s32 zero;
104 s32 horizontal;
105
106 // The followed point on the ground (height 0), in camera space; horizon is
107 // its height less its depth times the pitch slope.
108 zero = 0;
109 SET_VECTOR(groundPoint, position[0], zero, position[2]);
110 Iwram_TransformVector(groundPoint, cameraPoint);
111 cameraCoordinates = cameraPoint;
112 horizon =
113 cameraCoordinates[1] - Iwram_MulQ16(cameraCoordinates[2], pitchSlope);
114 focus = -gProjection.focal;
115 for (line = 0; line < FIELD_VIEW_HEIGHT / Q16_ONE; line++) {
116 // The line's ray slope: its offset from the projection's centre line
117 // over the focal length. Lines below the screen centre have a negative
118 // displacement.
119 distance = Iwram_RatioMulQ14(focus, (gProjection.centerY - line) * Q16_ONE);
120 // A ray parallel to the ground would divide by zero.
121 difference = distance - pitchSlope;
122 if (difference == 0)
123 difference = 1;
124 scale = Iwram_RatioMulQ14(difference, horizon);
125 // A negative scale is a line below the horizon, whose ray meets the
126 // ground; the lines above it are sky and get zeros.
127 if (scale < 0) {
128 // MulQ16 by 0x8000 halves: the width scale is half the line's scale
129 // over the focal length, and the distance below is stored halved.
130 diagonal = Iwram_MulQ16(-scale, Q16_ONE / 2);
131 scanline->scale = Iwram_RatioMulQ14(gProjection.focal, diagonal);
132 diagonal = Iwram_MulQ16(scale, distance);
133 // The distance is the root of the two squared terms. Both are taken
134 // >> 4 first so the squares stay in range, which leaves the root
135 // >> 12; << 12 puts it back in 16.16.
136 horizontal = (cameraCoordinates[2] - scale) >> 4;
137 vertical = (diagonal - cameraCoordinates[1]) >> 4;
138 horizontalSquared = Iwram_MulQ16(horizontal, horizontal);
139 verticalSquared = Iwram_MulQ16(vertical, vertical);
140 verticalSquared = Iwram_Sqrt(horizontalSquared + verticalSquared) << 12;
141 // The ground distance takes the sign of the vertical term.
142 if (vertical < 0)
143 verticalSquared = -verticalSquared;
144 scanline->depth = Iwram_MulQ16(verticalSquared, Q16_ONE / 2);
145 } else {
146 scanline->scale = 0;
147 scanline->depth = 0;
148 }
149 scanline->offsetX = 0;
150 scanline->offsetY = 0;
151 scanline++;
152 }
153}
154
155#undef MAP_SHAKE_SETTLE_FRAMES
156#undef MAP_SHAKE_SETTLE_MAX_AMPLITUDE
157#undef TILEMAP_TILE_BANK_BYTES
158#undef TILEMAP_MAP_BANK_BYTES
void TileMap_DrawRowsFromRam(const struct MapAffinePair *lines, u8 *pixels)
Draws the current affine page into the world map's still-view pixels.
Definition view.c:64
#define TILEMAP_MAP_BANK_BYTES
Definition view.c:10
void Map_WaitForShakeToSettle(void)
Waits until both shake amplitudes are below 1/256 pixel, with a 300-frame limit for a shake whose dec...
Definition view.c:36
#define MAP_SHAKE_SETTLE_MAX_AMPLITUDE
Definition view.c:8
#define TILEMAP_TILE_BANK_BYTES
Definition view.c:9
void(*) TileMapRowDrawer(const struct MapAffinePair *lines, u8 *pixels, const u8 *tiles, const u8 *map)
The copied ARM kernel reads the BG2 affine row from each 32-byte pair and writes 240 by 160 pixels as...
Definition view.c:56
void Map_SetScreenShake(s32 shakeX, s32 shakeY, s32 shakeDecay)
Changes the shake without restarting an axis whose argument is negative.
Definition view.c:15
#define MAP_SHAKE_SETTLE_FRAMES
Definition view.c:7
void WorldMap_BuildScanlineTable(s32 pitchSlope, s32 *position, struct MapScanline *scanline)
Rebuilds the ground plane's scanline terms when the world map pitch changes.
Definition view.c:88
const u8 TileMap_DrawRows[]
u8 TileMap_DrawRowsCodeSize[]
What every part of the field object shares: its includes and the few names more than one part uses.
@ FIELD_VIEW_HEIGHT
#define Q16_ONE
One in the engine's signed 16.16 fixed-point format.
Definition fixed_math.h:10
void WaitFrames(s32 frames)
The game's frame loop: runs frames frames and returns.
Definition frame.c:97
u8 gDecodeBuffer[]
void * gMapWork[]
@ HEAP_SLOT_TEMP_RENDERER
Copied field row drawer or window tile decoder, released after each call.
Definition heap_state.h:49
static s32 Iwram_RatioMulQ14(s32 divisor, s32 value)
All calls go through this layer.
Definition iwram_call.h:51
static s32 Iwram_Sqrt(s32 value)
Definition iwram_call.h:63
#define Iwram_MulQ16(left, right)
Definition iwram_call.h:127
static s32 Iwram_TransformVector(const void *vector, s32 *result)
Definition iwram_call.h:65
#define SET_VECTOR(v, x, y, z)
Sets the x, y and z of a three-part vector: a position about to be projected, a per-frame step,...
Definition macros.h:12
u8 gBgTileBuffer[]
void Runtime_ReleaseHeapBlock(s32 slot)
struct Projection gProjection
#define RamCode_LoadSlot(slot, code, bytes)
Allocates a work-slot copy; release it with Runtime_ReleaseHeapBlock.
Definition ramcode.h:26
void * gWorkSlot[]
One screen line's affine parameters for BG2 and BG3.
Definition mapframe.h:27
One screen line's ground-plane terms on the world map: its width scale and distance,...
Definition mapframe.h:13
s32 offsetX
Definition mapframe.h:15
s32 offsetY
Definition mapframe.h:15
The field map's work: the followed position, screen shake, tile animations, blend script,...
Definition map_scroll.h:27
s32 shakeX
Screen shake amplitudes in 16.16 fixed-point pixels, and the 16.16 factor that scales them each frame...
Definition map_scroll.h:33
s32 centerY
screen pixels
Definition project.h:17
s32 focal
Definition project.h:13
signed int s32
Definition types.h:14
unsigned char u8
Definition types.h:11