-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathtetrahedron.c
executable file
·240 lines (187 loc) · 5.51 KB
/
tetrahedron.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
// _____________________________________________________________________________
// | |
// | Rotating tetrahedron demo |
// | ========================= |
// | |
// | Draws a rotating tetrahedron using the DMC-1 GPU |
// | |
// | @sylefeb 2022-04-18 licence: GPL v3, see full text in repo |
// |___________________________________________________________________________|
#define SCREEN_WIDTH 320
#define SCREEN_HEIGHT 240
#include "sine_table.h"
#include "api.c"
#include "raster.c"
// -----------------------------------------------------
// Rotations
// -----------------------------------------------------
static inline void rot_z(int angle, short *x, short *y, short *z)
{
int sin = sine_table[ angle & 4095];
int cos = sine_table[(angle + 1024) & 4095];
int tx = *x; int ty = *y;
*x = (cos * tx - sin * ty) >> 12;
*y = (sin * tx + cos * ty) >> 12;
}
static inline void rot_y(int angle, short *x, short *y, short *z)
{
int sin = sine_table[ angle & 4095];
int cos = sine_table[(angle + 1024) & 4095];
int tx = *x; int tz = *z;
*x = (cos * tx - sin * tz) >> 12;
*z = (sin * tx + cos * tz) >> 12;
}
// -----------------------------------------------------
// Global state
// -----------------------------------------------------
// frame
volatile int frame;
// -----------------------------------------------------
int view_dist = 600;
static inline void project(const p3d* pt, p2d *pr)
{
int z = pt->z; // view space
int inv_z = 65536 / z;
pr->x = ((pt->x * inv_z) >> 8) + SCREEN_WIDTH/2;
pr->y = ((pt->y * inv_z) >> 8) + SCREEN_HEIGHT/2;
}
// -----------------------------------------------------
const p3d points[4] = {
{ 188, -66, 0},
{ -94, -66, 163},
{ -94, -66, -163},
{ 0, 200, 0},
};
const int indices[12] = {
0,1,2,
0,1,3,
1,2,3,
2,0,3,
};
p2d prj_points[4];
surface srfs[4];
// -----------------------------------------------------
int angle;
static inline void transform(short *x, short *y, short *z,short w)
{
rot_y(angle , x,y,z);
rot_z(angle>>1, x,y,z);
if (w != 0) {
*z += view_dist;
}
}
// -----------------------------------------------------
trsf_surface tsrfs[4];
rconvex rtris[4];
rconvex_texturing rtexs[4];
// draws all screen columns
static inline void render_frame()
{
// animation angle
angle = frame << 6;
// transform the points
for (int i = 0; i < 4; ++i) {
p3d p = points[i];
transform(&p.x,&p.y,&p.z,1);
project(&p, &prj_points[i]);
}
const int *idx = indices;
for (int s = 0 ; s < 4 ; ++ s) {
// transform the textured surfaces for rendering at this frame
surface_transform(&srfs[s], &tsrfs[s], transform);
// prepare texturing
rconvex_texturing_pre(&tsrfs[s], transform, points + *idx, &rtexs[s]);
// prepare triangle rasterization
rconvex_init(&rtris[s], 3,idx, prj_points);
idx += 3;
}
// before drawing cols wait for previous frame
wait_all_drawn();
int bound_s = -1;
for (int c = 0; c < SCREEN_WIDTH ; ++c) {
const int *idx = indices;
for (int s = 0 ; s < 4 ; ++ s) {
if (c >= rtris[s].x && c <= rtris[s].last_x && rtexs[s].ded > 0) {
rconvex_step(&rtris[s], 3,idx, prj_points);
int rz = 256;
int rx = c - SCREEN_WIDTH/2;
int ry = rtris[s].ys - SCREEN_HEIGHT/2;
if (s != bound_s) {
rconvex_texturing_bind(&rtexs[s]);
bound_s = s;
}
int light = (tsrfs[s].nz>>4);
if (light > 15) light = 15;
int dr = surface_setup_span(&tsrfs[s], rx,ry,rz);
col_send(
COLDRAW_PLANE_B(rtexs[s].ded,dr),
COLDRAW_COL(125/*texture id*/, rtris[s].ys,rtris[s].ye, light) | PLANE
);
}
// next triangle
idx += 3;
// process pending column commands
col_process();
}
// background filler
col_send(
COLDRAW_WALL(Y_MAX,0,0),
COLDRAW_COL(0, 0,239, 0) | WALL
);
// send end of column
col_send(0, COLDRAW_EOC);
}
}
// -----------------------------------------------------
// main
// -----------------------------------------------------
void main_1()
{
// hangs core 1 (we don't use it yet!)
while (1) { }
}
void main_0()
{
*LEDS = 0;
// --------------------------
// intialize view and frame
// --------------------------
frame = 0;
// --------------------------
// init oled
// --------------------------
oled_init();
oled_fullscreen();
// --------------------------
// prepare the texturing surfaces
// --------------------------
const int *idx = indices;
for (int s = 0; s < 4 ; ++s) {
surface_pre(&srfs[s], *idx,*(idx+1),*(idx+2), points);
idx += 3;
}
// prepare the rasterizer
raster_pre();
// --------------------------
// render loop
// --------------------------
while (1) {
// printf("frame %d\n",frame);
// animate view distance
view_dist = 460 + (sine_table[(frame<<5)&4095]>>4);
// draw screen
render_frame();
// next frame
++ frame;
} // while (1)
}
// -----------------------------------------------------
void main()
{
if (core_id()) {
main_1();
} else {
main_0();
}
}
// -----------------------------------------------------