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

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

Adapt the following application to the POSIX threads API

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