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

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

raycast: load textures from misc/

File size: 5.5 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
9#define FIELD_OF_VIEW   (70.f * M_PI / 180.f)   // Camera field of view
10#define TEX_SIZE        (32)                    // Texture size in pixels
11#define CEILING_COLOR   (0xBB)                  // lite gray
12#define FLOOR_COLOR     (0x33)                  // dark gray
13
14// Globals
15
16unsigned char buf0[FBUF_X_SIZE * FBUF_Y_SIZE] __attribute__((aligned(64)));
17unsigned char buf1[FBUF_X_SIZE * FBUF_Y_SIZE] __attribute__((aligned(64)));
18unsigned int  sts0[16]  __attribute__((aligned(64)));
19unsigned int  sts1[16]  __attribute__((aligned(64)));
20unsigned int  cur_buf;
21
22// Textures indexed by block number
23static unsigned char *g_tex[] =
24{
25    NULL, // 0
26    NULL, // rock
27    NULL, // door
28    NULL, // handle
29    NULL, // wood
30};
31
32// Local functions
33
34static void dispDrawColumn(int x, int y0, int y1, unsigned char color)
35{
36        unsigned char* buf = (cur_buf == 0 ? buf0 : buf1);
37
38        if (x < 0 || x > FBUF_X_SIZE)
39                return;
40
41        if (y0 < 0)
42                y0 = 0;
43
44        for (; y0 < y1 && y0 < FBUF_Y_SIZE; y0++) {
45                buf[y0 * FBUF_X_SIZE + x] = color;
46        }
47}
48
49static void dispDrawScrColumn(Game *game, int x, int height, int type, float tx)
50{
51    // Ceiling
52    dispDrawColumn(x,
53                   0,
54                   (FBUF_Y_SIZE - height) / 2,
55                   CEILING_COLOR);
56
57    // Wall
58    unsigned char *tex = g_tex[type];
59
60    if (tex) {
61        // Draw a texture slice
62        dispDrawColumn(x,
63               (FBUF_Y_SIZE - height) / 2,
64               (FBUF_Y_SIZE + height) / 2,
65               (x % 2 ? 0xAF : 0x7F));
66        /*Kentec320x240x16_SSD2119TexDrawV(
67            NULL, x,
68            (FBUF_Y_SIZE - height) / 2, (FBUF_Y_SIZE + height) / 2,
69            &tex[(int)(tx * TEX_SIZE) * TEX_SIZE], TEX_SIZE
70        );*/
71    }
72    else {
73        // Draw a solid color slice
74        dispDrawColumn(x,
75                       (FBUF_Y_SIZE - height) / 2,
76                       (FBUF_Y_SIZE + height) / 2,
77                       0xFF);
78    }
79
80    // Floor
81    dispDrawColumn(x,
82                   (FBUF_Y_SIZE + height) / 2,
83                   FBUF_Y_SIZE,
84                   FLOOR_COLOR);
85}
86
87static float dispRaycast(Game *game, int *type, float *tx, float angle)
88{
89    float x = game->player.x;
90    float y = game->player.y;
91
92    // Camera is inside a block.
93    // Return a minimal distance to avoid a division by zero.
94    if ((gameLocate(floor(x), floor(y))) != 0) {
95        *type = 0;
96        *tx = 0.f;
97        return 0.0001f;
98    }
99
100    // Precompute
101    float vsin = sin(angle);
102    float vcos = cos(angle);
103    float vtan = vsin / vcos;
104
105    // Calculate increments
106    int incix = (vcos > 0.f) - (vcos < 0.f);
107    int inciy = (vsin > 0.f) - (vsin < 0.f);
108    float incfx = inciy / vtan;
109    float incfy = incix * vtan;
110
111    // Calculate start position
112    int ix = floor(x) + (incix > 0);
113    int iy = floor(y) + (inciy > 0);
114    float fx = x + incfx * fabs(floor(y) + (inciy > 0) - y);
115    float fy = y + incfy * fabs(floor(x) + (incix > 0) - x);
116
117    // Find the first colliding tile in each direction
118    while (incix && gameLocate(ix - (incix < 0), fy) == 0)
119    {
120        ix += incix;
121        fy += incfy;
122    }
123    while (inciy && gameLocate(fx, iy - (inciy < 0)) == 0)
124    {
125        fx += incfx;
126        iy += inciy;
127    }
128
129    // Find the shortest ray
130    float dx = (incix) ? ((ix - x) / vcos) : 0xFFFF;
131    float dy = (inciy) ? ((iy - y) / vsin) : 0xFFFF;
132
133    if (dx < dy)
134    {
135        // Get block type
136        *type = gameLocate(ix - (incix < 0), floor(fy));
137
138        // Get wall texture coordinate [0;1]
139        *tx = fy - floor(fy);
140        if (incix < 0)
141            *tx = 1 - *tx;
142
143        return dx;
144    }
145    else
146    {
147        // Get block type
148        *type = gameLocate(floor(fx), iy - (inciy < 0));
149
150        // Get wall texture coordinate [0;1]
151        *tx = fx - floor(fx);
152        if (inciy > 0)
153            *tx = 1 - *tx;
154
155        return dy;
156    }
157}
158
159unsigned char *loadTexture(char *path)
160{
161    int fd;
162    unsigned char *tex;
163
164    tex = malloc(TEX_SIZE * TEX_SIZE);
165    fd = giet_fat_open(path, O_RDONLY);
166    if (fd < 0) {
167        free(tex);
168        return NULL;
169    }
170
171    giet_fat_read(fd, g_tex[1], TEX_SIZE * TEX_SIZE);
172    giet_fat_close(fd);
173    giet_tty_printf("[RAYCAST] loaded tex %s\n", path);
174
175    return tex;
176}
177
178// Exported functions
179
180void dispInit()
181{
182    // initialize framebuffer
183    giet_fbf_cma_alloc();
184    giet_fbf_cma_init_buf(buf0, buf1, sts0, sts1);
185    giet_fbf_cma_start(FBUF_X_SIZE * FBUF_Y_SIZE);
186
187    // load textures
188    g_tex[1] = loadTexture("misc/rock_32.raw");
189    g_tex[2] = loadTexture("misc/door_32.raw");
190    g_tex[3] = loadTexture("misc/handle_32.raw");
191    g_tex[4] = loadTexture("misc/wood_32.raw");
192
193        cur_buf = 0;
194}
195
196void dispRender(Game *game)
197{
198        int start = giet_proctime();
199    float angle = game->player.dir - FIELD_OF_VIEW / 2.f;
200
201    // Cast a ray for each pixel column and draw a colored wall slice
202    for (int i = 0; i < FBUF_X_SIZE; i++)
203    {
204        float dist;
205        int type;
206        float tx;
207
208        // Cast a ray to get wall distance
209        dist = dispRaycast(game, &type, &tx, angle);
210
211        // Perspective correction
212        dist *= cos(game->player.dir - angle);
213
214        // Draw ceiling, wall and floor
215        dispDrawScrColumn(game, i, FBUF_Y_SIZE / dist, type, tx);
216
217        angle += FIELD_OF_VIEW / FBUF_X_SIZE;
218    }
219
220        giet_fbf_cma_display(cur_buf);
221        cur_buf = !cur_buf;
222        giet_tty_printf("[RAYCAST] flip (took %d cycles)\n", giet_proctime() - start);
223}
Note: See TracBrowser for help on using the repository browser.