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

Last change on this file since 686 was 686, checked in by guerin, 9 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
RevLine 
[673]1#include "disp.h"
2#include "game.h"
3#include <stdio.h>
4#include <stdlib.h>
[676]5#include <malloc.h>
[673]6#include <math.h>
7#include <hard_config.h>
[683]8#include <user_sqt_lock.h>
[673]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
[683]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)
[673]23
24// Textures indexed by block number
[676]25static unsigned char *g_tex[] =
[673]26{
27    NULL, // 0
[676]28    NULL, // rock
29    NULL, // door
30    NULL, // handle
31    NULL, // wood
[673]32};
33
34// Local functions
35
[684]36static void dispDrawColumnTex(int x, int y0, int y1, unsigned char *line)
[673]37{
[685]38    int y = (y0 >= 0 ? y0 : 0);
[673]39
[685]40    for (; y < y1 && y < FBUF_Y_SIZE; y++) {
41        // Find texture coordinate
[677]42        int ty = (y - y0) * TEX_SIZE / (y1 - y0);
43
[684]44        buf[cur_buf][y * FBUF_X_SIZE + x] = line[ty];
[677]45    }
[673]46}
47
[677]48static void dispDrawColumnSolid(int x, int y0, int y1, unsigned char color)
[673]49{
[685]50    int y = (y0 >= 0 ? y0 : 0);
[677]51
[685]52    for (; y < y1 && y < FBUF_Y_SIZE; y++) {
[679]53        buf[cur_buf][y * FBUF_X_SIZE + x] = color;
[677]54    }
55}
56
[684]57static void dispDrawSlice(Game *game, int x, int height, int type, int tx)
[677]58{
[673]59    // Ceiling
[677]60    dispDrawColumnSolid(x,
61                        0,
62                        (FBUF_Y_SIZE - height) / 2,
63                        CEILING_COLOR);
[673]64
65    // Wall
[676]66    unsigned char *tex = g_tex[type];
[673]67
68    if (tex) {
69        // Draw a texture slice
[677]70        dispDrawColumnTex(x,
71                          (FBUF_Y_SIZE - height) / 2,
72                          (FBUF_Y_SIZE + height) / 2,
[684]73                          &tex[tx * TEX_SIZE]);
[673]74    }
75    else {
76        // Draw a solid color slice
[677]77        dispDrawColumnSolid(x,
78                            (FBUF_Y_SIZE - height) / 2,
79                            (FBUF_Y_SIZE + height) / 2,
80                            0xFF);
[673]81    }
82
83    // Floor
[677]84    dispDrawColumnSolid(x,
85                        (FBUF_Y_SIZE + height) / 2,
86                        FBUF_Y_SIZE,
87                        FLOOR_COLOR);
[673]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
[684]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
[683]179static unsigned char *dispLoadTexture(char *path)
[676]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
[677]191    giet_fat_read(fd, tex, TEX_SIZE * TEX_SIZE);
[676]192    giet_fat_close(fd);
[684]193
194    dispMirror(tex, TEX_SIZE);
195
[676]196    giet_tty_printf("[RAYCAST] loaded tex %s\n", path);
197
198    return tex;
199}
200
[673]201// Exported functions
202
203void dispInit()
204{
[683]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
[686]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);
[679]216
[683]217    // Initialize framebuffer
[673]218    giet_fbf_cma_alloc();
[679]219    giet_fbf_cma_init_buf(buf[0], buf[1], sts[0], sts[1]);
[673]220    giet_fbf_cma_start(FBUF_X_SIZE * FBUF_Y_SIZE);
221
[683]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");
[676]227
[677]228    cur_buf = 0;
[683]229    slice_cnt = 0;
230    slice_x = FBUF_X_SIZE;
[673]231}
232
[683]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
[684]263    dispDrawSlice(game, x, FBUF_Y_SIZE / dist, type, tx * TEX_SIZE);
[683]264
265    // Signal this slice is done
266    atomic_increment((unsigned int*)&slice_cnt, 1);
267
268    return 1;
269}
270
[673]271void dispRender(Game *game)
272{
[677]273    int start = giet_proctime();
[673]274
[683]275    // Start rendering
276    slice_cnt = 0;
277    slice_x = 0;
[673]278
[683]279    // Render slices
280    while (dispRenderSlice(game));
[673]281
[683]282    // Wait for completion
283    while (slice_cnt != FBUF_X_SIZE);
[673]284
[683]285    // Flip framebuffer
[677]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);
[673]289}
[683]290
Note: See TracBrowser for help on using the repository browser.