source: soft/giet_vm/applications/raycast/disp.c @ 689

Last change on this file since 689 was 686, checked in by guerin, 10 years ago

remove almalloc implementation

It is in fact useless because malloc already returns aligned addresses.
Should have read the doc first ;)

File size: 7.0 KB
Line 
1#include "disp.h"
2#include "game.h"
3#include <stdio.h>
4#include <stdlib.h>
5#include <malloc.h>
6#include <math.h>
7#include <hard_config.h>
8#include <user_sqt_lock.h>
9
10#define FIELD_OF_VIEW   (70.f * M_PI / 180.f)   // Camera field of view
11#define TEX_SIZE        (32)                    // Texture size in pixels
12#define CEILING_COLOR   (0xBB)                  // lite gray
13#define FLOOR_COLOR     (0x33)                  // dark gray
14
15// Globals
16
17static unsigned char*           buf[2];         // framebuffer
18static void *                   sts[2];         // for fbf_cma
19static unsigned int             cur_buf;        // current framebuffer
20static volatile unsigned int    slice_x;        // slice index (shared)
21static sqt_lock_t               slice_x_lock;   // slice index lock
22static volatile unsigned int    slice_cnt;      // slice count (shared)
23
24// Textures indexed by block number
25static unsigned char *g_tex[] =
26{
27    NULL, // 0
28    NULL, // rock
29    NULL, // door
30    NULL, // handle
31    NULL, // wood
32};
33
34// Local functions
35
36static void dispDrawColumnTex(int x, int y0, int y1, unsigned char *line)
37{
38    int y = (y0 >= 0 ? y0 : 0);
39
40    for (; y < y1 && y < FBUF_Y_SIZE; y++) {
41        // Find texture coordinate
42        int ty = (y - y0) * TEX_SIZE / (y1 - y0);
43
44        buf[cur_buf][y * FBUF_X_SIZE + x] = line[ty];
45    }
46}
47
48static void dispDrawColumnSolid(int x, int y0, int y1, unsigned char color)
49{
50    int y = (y0 >= 0 ? y0 : 0);
51
52    for (; y < y1 && y < FBUF_Y_SIZE; y++) {
53        buf[cur_buf][y * FBUF_X_SIZE + x] = color;
54    }
55}
56
57static void dispDrawSlice(Game *game, int x, int height, int type, int tx)
58{
59    // Ceiling
60    dispDrawColumnSolid(x,
61                        0,
62                        (FBUF_Y_SIZE - height) / 2,
63                        CEILING_COLOR);
64
65    // Wall
66    unsigned char *tex = g_tex[type];
67
68    if (tex) {
69        // Draw a texture slice
70        dispDrawColumnTex(x,
71                          (FBUF_Y_SIZE - height) / 2,
72                          (FBUF_Y_SIZE + height) / 2,
73                          &tex[tx * TEX_SIZE]);
74    }
75    else {
76        // Draw a solid color slice
77        dispDrawColumnSolid(x,
78                            (FBUF_Y_SIZE - height) / 2,
79                            (FBUF_Y_SIZE + height) / 2,
80                            0xFF);
81    }
82
83    // Floor
84    dispDrawColumnSolid(x,
85                        (FBUF_Y_SIZE + height) / 2,
86                        FBUF_Y_SIZE,
87                        FLOOR_COLOR);
88}
89
90static float dispRaycast(Game *game, int *type, float *tx, float angle)
91{
92    float x = game->player.x;
93    float y = game->player.y;
94
95    // Camera is inside a block.
96    // Return a minimal distance to avoid a division by zero.
97    if ((gameLocate(floor(x), floor(y))) != 0) {
98        *type = 0;
99        *tx = 0.f;
100        return 0.0001f;
101    }
102
103    // Precompute
104    float vsin = sin(angle);
105    float vcos = cos(angle);
106    float vtan = vsin / vcos;
107
108    // Calculate increments
109    int incix = (vcos > 0.f) - (vcos < 0.f);
110    int inciy = (vsin > 0.f) - (vsin < 0.f);
111    float incfx = inciy / vtan;
112    float incfy = incix * vtan;
113
114    // Calculate start position
115    int ix = floor(x) + (incix > 0);
116    int iy = floor(y) + (inciy > 0);
117    float fx = x + incfx * fabs(floor(y) + (inciy > 0) - y);
118    float fy = y + incfy * fabs(floor(x) + (incix > 0) - x);
119
120    // Find the first colliding tile in each direction
121    while (incix && gameLocate(ix - (incix < 0), fy) == 0)
122    {
123        ix += incix;
124        fy += incfy;
125    }
126    while (inciy && gameLocate(fx, iy - (inciy < 0)) == 0)
127    {
128        fx += incfx;
129        iy += inciy;
130    }
131
132    // Find the shortest ray
133    float dx = (incix) ? ((ix - x) / vcos) : 0xFFFF;
134    float dy = (inciy) ? ((iy - y) / vsin) : 0xFFFF;
135
136    if (dx < dy)
137    {
138        // Get block type
139        *type = gameLocate(ix - (incix < 0), floor(fy));
140
141        // Get wall texture coordinate [0;1]
142        *tx = fy - floor(fy);
143        if (incix < 0)
144            *tx = 1 - *tx;
145
146        return dx;
147    }
148    else
149    {
150        // Get block type
151        *type = gameLocate(floor(fx), iy - (inciy < 0));
152
153        // Get wall texture coordinate [0;1]
154        *tx = fx - floor(fx);
155        if (inciy > 0)
156            *tx = 1 - *tx;
157
158        return dy;
159    }
160}
161
162static void dispMirror(unsigned char *buf, unsigned int size)
163{
164    int i, j;
165    unsigned char pixel;
166
167    for (i = 0; i < size; i++) {
168        for (j = i + 1; j < size; j++) {
169            int ai = i * size + j;
170            int bi = j * size + i;
171
172            pixel = buf[ai];
173            buf[ai] = buf[bi];
174            buf[bi] = pixel;
175        }
176    }
177}
178
179static unsigned char *dispLoadTexture(char *path)
180{
181    int fd;
182    unsigned char *tex;
183
184    tex = malloc(TEX_SIZE * TEX_SIZE);
185    fd = giet_fat_open(path, O_RDONLY);
186    if (fd < 0) {
187        free(tex);
188        return NULL;
189    }
190
191    giet_fat_read(fd, tex, TEX_SIZE * TEX_SIZE);
192    giet_fat_close(fd);
193
194    dispMirror(tex, TEX_SIZE);
195
196    giet_tty_printf("[RAYCAST] loaded tex %s\n", path);
197
198    return tex;
199}
200
201// Exported functions
202
203void dispInit()
204{
205    unsigned int w, h, p;
206
207    // Initialize lock
208    giet_procs_number(&w, &h, &p);
209    sqt_lock_init(&slice_x_lock, w, h, p);
210
211    // Allocate framebuffer
212    buf[0] = malloc(FBUF_X_SIZE * FBUF_Y_SIZE);
213    buf[1] = malloc(FBUF_X_SIZE * FBUF_Y_SIZE);
214    sts[0] = malloc(64);
215    sts[1] = malloc(64);
216
217    // Initialize framebuffer
218    giet_fbf_cma_alloc();
219    giet_fbf_cma_init_buf(buf[0], buf[1], sts[0], sts[1]);
220    giet_fbf_cma_start(FBUF_X_SIZE * FBUF_Y_SIZE);
221
222    // Load textures
223    g_tex[1] = dispLoadTexture("misc/rock_32.raw");
224    g_tex[2] = dispLoadTexture("misc/door_32.raw");
225    g_tex[3] = dispLoadTexture("misc/handle_32.raw");
226    g_tex[4] = dispLoadTexture("misc/wood_32.raw");
227
228    cur_buf = 0;
229    slice_cnt = 0;
230    slice_x = FBUF_X_SIZE;
231}
232
233int dispRenderSlice(Game *game)
234{
235    unsigned int x;
236    int type;
237    float angle, dist, tx;
238
239    sqt_lock_acquire(&slice_x_lock);
240
241    if (slice_x == FBUF_X_SIZE) {
242        // No more work to do for this frame
243        sqt_lock_release(&slice_x_lock);
244        return 0;
245    }
246    else {
247        // Keep slice coordinate
248        x = slice_x++;
249    }
250
251    sqt_lock_release(&slice_x_lock);
252
253    angle = game->player.dir - FIELD_OF_VIEW / 2.f +
254            x * FIELD_OF_VIEW / FBUF_X_SIZE;
255
256    // Cast a ray to get wall distance
257    dist = dispRaycast(game, &type, &tx, angle);
258
259    // Perspective correction
260    dist *= cos(game->player.dir - angle);
261
262    // Draw ceiling, wall and floor
263    dispDrawSlice(game, x, FBUF_Y_SIZE / dist, type, tx * TEX_SIZE);
264
265    // Signal this slice is done
266    atomic_increment((unsigned int*)&slice_cnt, 1);
267
268    return 1;
269}
270
271void dispRender(Game *game)
272{
273    int start = giet_proctime();
274
275    // Start rendering
276    slice_cnt = 0;
277    slice_x = 0;
278
279    // Render slices
280    while (dispRenderSlice(game));
281
282    // Wait for completion
283    while (slice_cnt != FBUF_X_SIZE);
284
285    // Flip framebuffer
286    giet_fbf_cma_display(cur_buf);
287    cur_buf = !cur_buf;
288    giet_tty_printf("[RAYCAST] flip (took %d cycles)\n", giet_proctime() - start);
289}
290
Note: See TracBrowser for help on using the repository browser.