Alchemy
Loading...
Searching...
No Matches

vertices.c

Go to the documentation of this file.
2#include "types.h"
3#include "frame.h"
4#include "mulq16.h"
5#include "project.h"
6#include "static_assert.h"
7
8#define VISIBLE_SCANLINES 160 ///< visible scanlines
9
10/// An eight-byte runtime entry contains the ldr/bx instructions and a target
11/// word. Entries this routine does not call keep their target word opaque.
15};
16
17/// A runtime table entry whose two-argument target this routine calls, the
18/// arctangent.
21 s32 (*target)(s32 x, s32 y);
22};
23
24/// A runtime table entry whose one-argument target this routine calls, the
25/// sine or the cosine.
28 s32 (*target)(s32 angle);
29};
30
31/// The runtime table's prefix through Trig_Cos, in its assembly order. This
32/// routine runs from a RAM copy and calls the target words, not the ROM stubs.
39};
40
41STATIC_ASSERT(sizeof(struct RuntimeUnusedEntry) == 8);
47
48extern const struct RuntimeMathTable FarCall_RuntimeTable;
49extern u32 gScanlineAngle;
50
51/// The camera's eye or target point, as this routine reads it.
52struct Position {
56};
57
58/// One scanline of the world map's ground plane. WorldMap_BuildScanlineTable
59/// fills x (the line's width scale) and z (its depth); the rest caches the
60/// rotation terms this routine computes from them for the current angle.
61struct ScanVertex {
62 s32 x; ///< the line's width scale
63 s32 z; ///< the line's depth
64 s32 dx; ///< the texture x offset from the origin, before >> 8
65 s32 dz; ///< the texture y offset from the origin, before >> 8
66 s16 u; ///< the cached BG2PA
67 s16 v; ///< the cached BG2PC
68};
69
70/// One background's affine registers, BG2PA to BG2Y.
71struct BgAffine {
73 s16 pb; ///< not written by this routine
75 s16 pd; ///< not written by this routine
78};
79
80/// Builds the world map's per-scanline affine table for one frame: the ground
81/// plane seen from eye towards target. line points at the 160 scanlines'
82/// ground terms, whose rotation terms stay cached while the yaw
83/// (gScanlineAngle) is unchanged; affine receives each line's parameters
84/// twice, for BG2 and then BG3, as the HBlank DMA writes both. Copied to RAM
85/// (heap slot 46) by Map_InitializePerspectiveScene, which runs it once, and
86/// run from there each frame by WorldMap_UpdateView into the affine page of
87/// the frame's parity. Writes gScanlineAngle when the yaw changes.
88void Transform_UpdateVertices(struct Position *eye, struct Position *target,
89 struct ScanVertex *line,
90 struct BgAffine *affine) {
91 u32 angle;
92 s32 originX;
93 s32 originZ;
94 s32 sinYaw;
95 s32 cosYaw;
96 s32 negativeSinYaw;
97 s32 scanline;
98 s32 depth;
99
100 {
101 s32 targetDeltaX = target->x;
102 s32 targetZ = target->z;
103 s32 eyeZ = eye->z;
104 s32 eyeX = eye->x;
105
106 depth = targetZ - eyeZ;
107 targetDeltaX -= eyeX;
108 angle =
109 (u16)FarCall_RuntimeTable.atan2.target(targetDeltaX >> 4, depth >> 4);
110 }
111 // The texture origin: the target at half scale.
112 originX = MulQ16(target->x, 0x8000);
113 originZ = MulQ16(target->z, 0x8000);
114 if (angle != gScanlineAngle) {
115 // The camera turned: recompute every scanline's rotation terms.
116 gScanlineAngle = angle;
117 sinYaw = FarCall_RuntimeTable.sin.target(angle);
118 cosYaw = FarCall_RuntimeTable.cos.target(angle);
119 negativeSinYaw = -sinYaw;
120 for (scanline = VISIBLE_SCANLINES - 1; scanline >= 0; scanline--) {
121 s32 widthScale = line->x;
122 s32 centerX;
123 s32 horizontalOffset;
124 s32 depthOffset;
125 s32 affinePa;
126 s32 affinePc;
127
128 depth = line->z;
129 affinePa = -(MulQ16(widthScale, cosYaw) / 256);
130 horizontalOffset = (s16)affinePa;
131 line->u = affinePa;
132 affine->pa = affinePa;
133 affinePc = MulQ16(widthScale, sinYaw) / 256;
134 line->v = affinePc;
135 affine->pc = affinePc;
136 // Read through its own address, the native builds one literal for the
137 // centre; as gProjection.centerX it loads gProjection and reads at
138 // offset 12 (1 of 157 instructions differ in tbs-en).
139 centerX = *&gProjection.centerX;
140 // UB: affine coefficients can be negative. Multiplication by 256 is
141 // representable for every signed halfword; retain native shifts below.
142#ifdef UBFIX
143 horizontalOffset = (horizontalOffset * 256) * centerX;
144 depthOffset = ((s16)affinePc * 256) * -centerX;
145#else
146 horizontalOffset = (horizontalOffset << 8) * centerX;
147 depthOffset = ((s16)affinePc << 8) * -centerX;
148#endif
149 line->dx = -(horizontalOffset + MulQ16(negativeSinYaw, depth));
150 line->dz = depthOffset + MulQ16(cosYaw, depth);
151 affine->x = (originX + line->dx) >> 8;
152 affine->y = (originZ + line->dz) >> 8;
153 affine[1] = affine[0];
154 line++;
155 affine += 2;
156 }
157 } else {
158 // Same angle: the cached terms stand and only the position moves.
159 for (scanline = VISIBLE_SCANLINES - 1; scanline >= 0; scanline--) {
160 if (gFrameCount & 1) {
161 // On odd frames the sample point shifts by half a pixel step along
162 // the line and a quarter step across it, so alternate frames sample
163 // between each other's texels.
164 /* FAKEMATCH(temporary): one variable holds the x sum and then u, both
165 * in r3 as native; as two plain expressions, 3 of 157 instructions
166 * differ in tbs-en. */
167 s32 sampleOffset;
168
169 sampleOffset = ((originX + line->dx) >> 8) + line->v / 4 + line->u / 2;
170 affine->x = sampleOffset;
171 sampleOffset = line->u;
172 affine->y =
173 ((originZ + line->dz) >> 8) + sampleOffset / 4 + line->v / 2;
174 } else {
175 affine->x = (originX + line->dx) >> 8;
176 affine->y = (originZ + line->dz) >> 8;
177 }
178 affine->pa = line->u;
179 affine->pc = line->v;
180 affine[1] = affine[0];
181 line++;
182 affine += 2;
183 }
184 }
185}
The frame loop's globals: lag counts, the CPU load display and the VBlank flags.
volatile u32 gFrameCount
Frames WaitFrames has finished.
MulQ16, the 16.16 fixed-point multiply.
static __inline__ s32 MulQ16(s32 left, s32 right)
Multiplies 16.16 fixed-point values, returning the middle 32 product bits.
Definition mulq16.h:18
The 3D projection.
struct Projection gProjection
STATIC_ASSERT, a compile-time check that emits nothing.
#define STATIC_ASSERT(condition)
C89 permits repeated extern declarations of the same array.
#define offsetof(type, member)
Definition stddef.h:19
One background's affine registers, BG2PA to BG2Y.
Definition vertices.c:71
s16 pa
Definition vertices.c:72
s32 x
Definition vertices.c:76
s16 pb
not written by this routine
Definition vertices.c:73
s32 y
Definition vertices.c:77
s16 pd
not written by this routine
Definition vertices.c:75
s16 pc
Definition vertices.c:74
The camera's eye or target point, as this routine reads it.
Definition vertices.c:52
s32 y
Definition vertices.c:54
s32 z
Definition vertices.c:55
s32 x
Definition vertices.c:53
s32 centerX
screen pixels
Definition project.h:16
A runtime table entry whose two-argument target this routine calls, the arctangent.
Definition vertices.c:19
s32(*) target(s32 x, s32 y)
Definition vertices.c:21
The runtime table's prefix through Trig_Cos, in its assembly order.
Definition vertices.c:33
struct RuntimeMathUnaryEntry cos
Definition vertices.c:38
struct RuntimeMathBinaryEntry atan2
Definition vertices.c:35
struct RuntimeUnusedEntry preceding[8]
Definition vertices.c:34
struct RuntimeUnusedEntry squareRoots[2]
Definition vertices.c:36
struct RuntimeMathUnaryEntry sin
Definition vertices.c:37
A runtime table entry whose one-argument target this routine calls, the sine or the cosine.
Definition vertices.c:26
s32(*) target(s32 angle)
Definition vertices.c:28
An eight-byte runtime entry contains the ldr/bx instructions and a target word.
Definition vertices.c:12
One scanline of the world map's ground plane.
Definition vertices.c:61
s32 x
the line's width scale
Definition vertices.c:62
s32 dz
the texture y offset from the origin, before >> 8
Definition vertices.c:65
s16 v
the cached BG2PC
Definition vertices.c:67
s32 dx
the texture x offset from the origin, before >> 8
Definition vertices.c:64
s16 u
the cached BG2PA
Definition vertices.c:66
s32 z
the line's depth
Definition vertices.c:63
The integer types, TRUE, UNUSED and the fixed-address macros.
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
const struct RuntimeMathTable FarCall_RuntimeTable
void Transform_UpdateVertices(struct Position *eye, struct Position *target, struct ScanVertex *line, struct BgAffine *affine)
Builds the world map's per-scanline affine table for one frame: the ground plane seen from eye toward...
Definition vertices.c:88
u32 gScanlineAngle
#define VISIBLE_SCANLINES
visible scanlines
Definition vertices.c:8