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