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

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

Update graphical applications.

File size: 6.3 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>
[708]8#include <user_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
[708]16////////////////////////////
17// Extern variables
18////////////////////////////
[673]19
[708]20extern unsigned char*  g_tex[5];
[724]21extern unsigned char*  buf;
22extern void*           sts;
[708]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;
[673]28
[708]29//////////////////////
[673]30// Local functions
[708]31////////////////////////
[673]32
[708]33/////////////////////////////////////////////////////////////////////////
[684]34static void dispDrawColumnTex(int x, int y0, int y1, unsigned char *line)
[673]35{
[685]36    int y = (y0 >= 0 ? y0 : 0);
[691]37    int ymax = (y1 < FBUF_Y_SIZE ? y1 : FBUF_Y_SIZE);
[673]38
[724]39    for (; y < ymax; y++) 
40    {
[685]41        // Find texture coordinate
[677]42        int ty = (y - y0) * TEX_SIZE / (y1 - y0);
43
[724]44        buf[y * FBUF_X_SIZE + x] = line[ty];
[677]45    }
[673]46}
47
[708]48///////////////////////////////////////////////////////////////////////////
[677]49static void dispDrawColumnSolid(int x, int y0, int y1, unsigned char color)
[673]50{
[685]51    int y = (y0 >= 0 ? y0 : 0);
[691]52    int ymax = (y1 < FBUF_Y_SIZE ? y1 : FBUF_Y_SIZE);
[677]53
[724]54    for (; y < ymax; y++) 
55    {
56        buf[y * FBUF_X_SIZE + x] = color;
[677]57    }
58}
59
[708]60////////////////////////////////////////////////////////////////
61static void dispDrawSlice( int x, int height, int type, int tx )
[677]62{
[673]63    // Ceiling
[677]64    dispDrawColumnSolid(x,
65                        0,
66                        (FBUF_Y_SIZE - height) / 2,
67                        CEILING_COLOR);
[673]68
69    // Wall
[676]70    unsigned char *tex = g_tex[type];
[673]71
72    if (tex) {
73        // Draw a texture slice
[677]74        dispDrawColumnTex(x,
75                          (FBUF_Y_SIZE - height) / 2,
76                          (FBUF_Y_SIZE + height) / 2,
[684]77                          &tex[tx * TEX_SIZE]);
[673]78    }
79    else {
80        // Draw a solid color slice
[677]81        dispDrawColumnSolid(x,
82                            (FBUF_Y_SIZE - height) / 2,
83                            (FBUF_Y_SIZE + height) / 2,
84                            0xFF);
[673]85    }
86
87    // Floor
[677]88    dispDrawColumnSolid(x,
89                        (FBUF_Y_SIZE + height) / 2,
90                        FBUF_Y_SIZE,
91                        FLOOR_COLOR);
[673]92}
93
[708]94///////////////////////////////////////////////////////////////////////
95static float dispRaycast( int *type, float *tx, float angle )
[673]96{
[708]97    float x = game.player.x;
98    float y = game.player.y;
[673]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
[708]167////////////////////////////////////////////////////////////////
[692]168static void dispTranspose(unsigned char *buf, unsigned int size)
[684]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
[708]185////////////////////////
186// Exported functions
187////////////////////////
188
189//////////////////////////////////////////
190unsigned char* dispLoadTexture(char *path)
[676]191{
192    int fd;
193    unsigned char *tex;
194
195    tex = malloc(TEX_SIZE * TEX_SIZE);
196    fd = giet_fat_open(path, O_RDONLY);
[708]197    if (fd < 0) 
198    {
[676]199        free(tex);
200        return NULL;
201    }
202
[677]203    giet_fat_read(fd, tex, TEX_SIZE * TEX_SIZE);
[676]204    giet_fat_close(fd);
[684]205
[692]206    dispTranspose(tex, TEX_SIZE);
[684]207
[676]208    return tex;
209}
210
[708]211///////////////////////////////////////////////////
212unsigned int dispRenderSlice( unsigned int* slice )
[673]213{
[708]214    // return 0 when there is no more slice to do
[683]215
216    int type;
217    float angle, dist, tx;
[708]218    unsigned int x;
[683]219
[708]220    // get a slice index
221    sqt_lock_acquire( &slice_get_lock );
[683]222
[708]223    if (slice_x >= FBUF_X_SIZE)      // No more work to do for this frame
224    {
225        sqt_lock_release( &slice_get_lock );
[683]226        return 0;
227    }
[708]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;
[683]234    }
235
[708]236    // Cast a ray to get wall distance
237    angle = game.player.dir - FIELD_OF_VIEW / 2.f +
[683]238            x * FIELD_OF_VIEW / FBUF_X_SIZE;
239
[708]240    dist = dispRaycast(&type, &tx, angle);
[683]241
[708]242    dist *= cos(game.player.dir - angle);
[683]243
244    // Draw ceiling, wall and floor
[708]245    dispDrawSlice(x, FBUF_Y_SIZE / dist, type, tx * TEX_SIZE);
[683]246
247    // Signal this slice is done
248
[708]249    sqt_lock_acquire( &slice_done_lock );
250    slice_count++;
251    sqt_lock_release( &slice_done_lock );
252
[683]253    return 1;
[708]254}  // end dispRenderSlice()
[683]255
[673]256
Note: See TracBrowser for help on using the repository browser.