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

Last change on this file was 724, checked in by alain, 9 years ago

Update graphical applications.

File size: 6.3 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_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
16////////////////////////////
17// Extern variables
18////////////////////////////
19
20extern unsigned char*  g_tex[5];
21extern unsigned char*  buf;
22extern void*           sts;
23extern unsigned int    slice_x;
24extern unsigned int    slice_count;
25extern sqt_lock_t      slice_get_lock;
26extern sqt_lock_t      slice_done_lock;
27extern Game            game;
28
29//////////////////////
30// Local functions
31////////////////////////
32
33/////////////////////////////////////////////////////////////////////////
34static void dispDrawColumnTex(int x, int y0, int y1, unsigned char *line)
35{
36    int y = (y0 >= 0 ? y0 : 0);
37    int ymax = (y1 < FBUF_Y_SIZE ? y1 : FBUF_Y_SIZE);
38
39    for (; y < ymax; y++) 
40    {
41        // Find texture coordinate
42        int ty = (y - y0) * TEX_SIZE / (y1 - y0);
43
44        buf[y * FBUF_X_SIZE + x] = line[ty];
45    }
46}
47
48///////////////////////////////////////////////////////////////////////////
49static void dispDrawColumnSolid(int x, int y0, int y1, unsigned char color)
50{
51    int y = (y0 >= 0 ? y0 : 0);
52    int ymax = (y1 < FBUF_Y_SIZE ? y1 : FBUF_Y_SIZE);
53
54    for (; y < ymax; y++) 
55    {
56        buf[y * FBUF_X_SIZE + x] = color;
57    }
58}
59
60////////////////////////////////////////////////////////////////
61static void dispDrawSlice( int x, int height, int type, int tx )
62{
63    // Ceiling
64    dispDrawColumnSolid(x,
65                        0,
66                        (FBUF_Y_SIZE - height) / 2,
67                        CEILING_COLOR);
68
69    // Wall
70    unsigned char *tex = g_tex[type];
71
72    if (tex) {
73        // Draw a texture slice
74        dispDrawColumnTex(x,
75                          (FBUF_Y_SIZE - height) / 2,
76                          (FBUF_Y_SIZE + height) / 2,
77                          &tex[tx * TEX_SIZE]);
78    }
79    else {
80        // Draw a solid color slice
81        dispDrawColumnSolid(x,
82                            (FBUF_Y_SIZE - height) / 2,
83                            (FBUF_Y_SIZE + height) / 2,
84                            0xFF);
85    }
86
87    // Floor
88    dispDrawColumnSolid(x,
89                        (FBUF_Y_SIZE + height) / 2,
90                        FBUF_Y_SIZE,
91                        FLOOR_COLOR);
92}
93
94///////////////////////////////////////////////////////////////////////
95static float dispRaycast( int *type, float *tx, float angle )
96{
97    float x = game.player.x;
98    float y = game.player.y;
99
100    // Camera is inside a block.
101    // Return a minimal distance to avoid a division by zero.
102    if ((gameLocate(floor(x), floor(y))) != 0) {
103        *type = 0;
104        *tx = 0.f;
105        return 0.0001f;
106    }
107
108    // Precompute
109    float vsin = sin(angle);
110    float vcos = cos(angle);
111    float vtan = vsin / vcos;
112
113    // Calculate increments
114    int incix = (vcos > 0.f) - (vcos < 0.f);
115    int inciy = (vsin > 0.f) - (vsin < 0.f);
116    float incfx = inciy / vtan;
117    float incfy = incix * vtan;
118
119    // Calculate start position
120    int ix = floor(x) + (incix > 0);
121    int iy = floor(y) + (inciy > 0);
122    float fx = x + incfx * fabs(floor(y) + (inciy > 0) - y);
123    float fy = y + incfy * fabs(floor(x) + (incix > 0) - x);
124
125    // Find the first colliding tile in each direction
126    while (incix && gameLocate(ix - (incix < 0), fy) == 0)
127    {
128        ix += incix;
129        fy += incfy;
130    }
131    while (inciy && gameLocate(fx, iy - (inciy < 0)) == 0)
132    {
133        fx += incfx;
134        iy += inciy;
135    }
136
137    // Find the shortest ray
138    float dx = (incix) ? ((ix - x) / vcos) : 0xFFFF;
139    float dy = (inciy) ? ((iy - y) / vsin) : 0xFFFF;
140
141    if (dx < dy)
142    {
143        // Get block type
144        *type = gameLocate(ix - (incix < 0), floor(fy));
145
146        // Get wall texture coordinate [0;1]
147        *tx = fy - floor(fy);
148        if (incix < 0)
149            *tx = 1 - *tx;
150
151        return dx;
152    }
153    else
154    {
155        // Get block type
156        *type = gameLocate(floor(fx), iy - (inciy < 0));
157
158        // Get wall texture coordinate [0;1]
159        *tx = fx - floor(fx);
160        if (inciy > 0)
161            *tx = 1 - *tx;
162
163        return dy;
164    }
165}
166
167////////////////////////////////////////////////////////////////
168static void dispTranspose(unsigned char *buf, unsigned int size)
169{
170    int i, j;
171    unsigned char pixel;
172
173    for (i = 0; i < size; i++) {
174        for (j = i + 1; j < size; j++) {
175            int ai = i * size + j;
176            int bi = j * size + i;
177
178            pixel = buf[ai];
179            buf[ai] = buf[bi];
180            buf[bi] = pixel;
181        }
182    }
183}
184
185////////////////////////
186// Exported functions
187////////////////////////
188
189//////////////////////////////////////////
190unsigned char* dispLoadTexture(char *path)
191{
192    int fd;
193    unsigned char *tex;
194
195    tex = malloc(TEX_SIZE * TEX_SIZE);
196    fd = giet_fat_open(path, O_RDONLY);
197    if (fd < 0) 
198    {
199        free(tex);
200        return NULL;
201    }
202
203    giet_fat_read(fd, tex, TEX_SIZE * TEX_SIZE);
204    giet_fat_close(fd);
205
206    dispTranspose(tex, TEX_SIZE);
207
208    return tex;
209}
210
211///////////////////////////////////////////////////
212unsigned int dispRenderSlice( unsigned int* slice )
213{
214    // return 0 when there is no more slice to do
215
216    int type;
217    float angle, dist, tx;
218    unsigned int x;
219
220    // get a slice index
221    sqt_lock_acquire( &slice_get_lock );
222
223    if (slice_x >= FBUF_X_SIZE)      // No more work to do for this frame
224    {
225        sqt_lock_release( &slice_get_lock );
226        return 0;
227    }
228    else                             // Keep slice coordinate
229    {
230        x       = slice_x;
231        slice_x = x + 1;
232        sqt_lock_release( &slice_get_lock );
233        *slice  = x;
234    }
235
236    // Cast a ray to get wall distance
237    angle = game.player.dir - FIELD_OF_VIEW / 2.f +
238            x * FIELD_OF_VIEW / FBUF_X_SIZE;
239
240    dist = dispRaycast(&type, &tx, angle);
241
242    dist *= cos(game.player.dir - angle);
243
244    // Draw ceiling, wall and floor
245    dispDrawSlice(x, FBUF_Y_SIZE / dist, type, tx * TEX_SIZE);
246
247    // Signal this slice is done
248
249    sqt_lock_acquire( &slice_done_lock );
250    slice_count++;
251    sqt_lock_release( &slice_done_lock );
252
253    return 1;
254}  // end dispRenderSlice()
255
256
Note: See TracBrowser for help on using the repository browser.