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

Last change on this file since 673 was 673, checked in by guerin, 9 years ago

raycast: initial port

Raycast is a small game that looks like Wolfenstein 3D. I created
it for my SESI project, on a Cortex M4 devboard.

Imported from
github.com/libcg/tiva-c/tree/master/boards/dk-tm4c129x/upmc_raycast

File size: 4.9 KB
Line 
1#include "disp.h"
2#include "game.h"
3#include <stdio.h>
4#include <stdlib.h>
5#include <math.h>
6#include <hard_config.h>
7
8#ifdef USE_TEXTURES
9#include "res/rock_tex.h"
10#include "res/door_tex.h"
11#include "res/handle_tex.h"
12#include "res/wood_tex.h"
13#endif
14
15#define FIELD_OF_VIEW   (70.f * M_PI / 180.f)   // Camera field of view
16#define TEX_SIZE        (32)                    // Texture size in pixels
17#define CEILING_COLOR   (0xBB)                  // lite gray
18#define FLOOR_COLOR     (0x33)                  // dark gray
19
20// Globals
21
22unsigned char buf0[FBUF_X_SIZE * FBUF_Y_SIZE] __attribute__((aligned(64)));
23unsigned char buf1[FBUF_X_SIZE * FBUF_Y_SIZE] __attribute__((aligned(64)));
24unsigned int  sts0[16]  __attribute__((aligned(64)));
25unsigned int  sts1[16]  __attribute__((aligned(64)));
26unsigned int  cur_buf;
27
28#ifdef USE_TEXTURES
29// Textures indexed by block number
30static uint16_t *g_tex[] =
31{
32    NULL, // 0
33    (uint16_t*)&rock_tex_data,
34    (uint16_t*)&door_tex_data,
35    (uint16_t*)&handle_tex_data,
36    (uint16_t*)&wood_tex_data
37};
38#endif
39
40// Local functions
41
42static void dispDrawColumn(int x, int y0, int y1, unsigned char color)
43{
44        unsigned char* buf = (cur_buf == 0 ? buf0 : buf1);
45
46        if (x < 0 || x > FBUF_X_SIZE)
47                return;
48
49        if (y0 < 0)
50                y0 = 0;
51
52        for (; y0 < y1 && y0 < FBUF_Y_SIZE; y0++) {
53                buf[y0 * FBUF_X_SIZE + x] = color;
54        }
55}
56
57static void dispDrawScrColumn(Game *game, int x, int height, int type, float tx)
58{
59    // Ceiling
60    dispDrawColumn(x,
61                   0,
62                   (FBUF_Y_SIZE - height) / 2,
63                   CEILING_COLOR);
64
65    // Wall
66#ifdef USE_TEXTURES
67    uint16_t *tex = g_tex[type];
68
69    if (tex) {
70        // Draw a texture slice
71        /*Kentec320x240x16_SSD2119TexDrawV(
72            NULL, x,
73            (FBUF_Y_SIZE - height) / 2, (FBUF_Y_SIZE + height) / 2,
74            &tex[(int)(tx * TEX_SIZE) * TEX_SIZE], TEX_SIZE
75        );*/
76    }
77    else {
78#endif
79        // Draw a solid color slice
80        dispDrawColumn(x,
81                       (FBUF_Y_SIZE - height) / 2,
82                       (FBUF_Y_SIZE + height) / 2,
83                       0xFF);
84#ifdef USE_TEXTURES
85    }
86#endif
87
88    // Floor
89    dispDrawColumn(x,
90                   (FBUF_Y_SIZE + height) / 2,
91                   FBUF_Y_SIZE,
92                   FLOOR_COLOR);
93}
94
95static float dispRaycast(Game *game, 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// Exported functions
168
169void dispInit()
170{
171    giet_fbf_cma_alloc();
172    giet_fbf_cma_init_buf(buf0, buf1, sts0, sts1);
173    giet_fbf_cma_start(FBUF_X_SIZE * FBUF_Y_SIZE);
174
175        cur_buf = 0;
176}
177
178void dispRender(Game *game)
179{
180        int start = giet_proctime();
181    float angle = game->player.dir - FIELD_OF_VIEW / 2.f;
182
183    // Cast a ray for each pixel column and draw a colored wall slice
184    for (int i = 0; i < FBUF_X_SIZE; i++)
185    {
186        float dist;
187        int type;
188        float tx;
189
190        // Cast a ray to get wall distance
191        dist = dispRaycast(game, &type, &tx, angle);
192
193        // Perspective correction
194        dist *= cos(game->player.dir - angle);
195
196        // Draw ceiling, wall and floor
197        dispDrawScrColumn(game, i, FBUF_Y_SIZE / dist, type, tx);
198
199        angle += FIELD_OF_VIEW / FBUF_X_SIZE;
200    }
201
202        giet_fbf_cma_display(cur_buf);
203        cur_buf = !cur_buf;
204        giet_tty_printf("[RAYCAST] flip (took %d cycles)\n", giet_proctime() - start);
205}
Note: See TracBrowser for help on using the repository browser.