#include "disp.h" #include "game.h" #include #include #include #include #ifdef USE_TEXTURES #include "res/rock_tex.h" #include "res/door_tex.h" #include "res/handle_tex.h" #include "res/wood_tex.h" #endif #define FIELD_OF_VIEW (70.f * M_PI / 180.f) // Camera field of view #define TEX_SIZE (32) // Texture size in pixels #define CEILING_COLOR (0xBB) // lite gray #define FLOOR_COLOR (0x33) // dark gray // Globals unsigned char buf0[FBUF_X_SIZE * FBUF_Y_SIZE] __attribute__((aligned(64))); unsigned char buf1[FBUF_X_SIZE * FBUF_Y_SIZE] __attribute__((aligned(64))); unsigned int sts0[16] __attribute__((aligned(64))); unsigned int sts1[16] __attribute__((aligned(64))); unsigned int cur_buf; #ifdef USE_TEXTURES // Textures indexed by block number static uint16_t *g_tex[] = { NULL, // 0 (uint16_t*)&rock_tex_data, (uint16_t*)&door_tex_data, (uint16_t*)&handle_tex_data, (uint16_t*)&wood_tex_data }; #endif // Local functions static void dispDrawColumn(int x, int y0, int y1, unsigned char color) { unsigned char* buf = (cur_buf == 0 ? buf0 : buf1); if (x < 0 || x > FBUF_X_SIZE) return; if (y0 < 0) y0 = 0; for (; y0 < y1 && y0 < FBUF_Y_SIZE; y0++) { buf[y0 * FBUF_X_SIZE + x] = color; } } static void dispDrawScrColumn(Game *game, int x, int height, int type, float tx) { // Ceiling dispDrawColumn(x, 0, (FBUF_Y_SIZE - height) / 2, CEILING_COLOR); // Wall #ifdef USE_TEXTURES uint16_t *tex = g_tex[type]; if (tex) { // Draw a texture slice /*Kentec320x240x16_SSD2119TexDrawV( NULL, x, (FBUF_Y_SIZE - height) / 2, (FBUF_Y_SIZE + height) / 2, &tex[(int)(tx * TEX_SIZE) * TEX_SIZE], TEX_SIZE );*/ } else { #endif // Draw a solid color slice dispDrawColumn(x, (FBUF_Y_SIZE - height) / 2, (FBUF_Y_SIZE + height) / 2, 0xFF); #ifdef USE_TEXTURES } #endif // Floor dispDrawColumn(x, (FBUF_Y_SIZE + height) / 2, FBUF_Y_SIZE, FLOOR_COLOR); } static float dispRaycast(Game *game, int *type, float *tx, float angle) { float x = game->player.x; float y = game->player.y; // Camera is inside a block. // Return a minimal distance to avoid a division by zero. if ((gameLocate(floor(x), floor(y))) != 0) { *type = 0; *tx = 0.f; return 0.0001f; } // Precompute float vsin = sin(angle); float vcos = cos(angle); float vtan = vsin / vcos; // Calculate increments int incix = (vcos > 0.f) - (vcos < 0.f); int inciy = (vsin > 0.f) - (vsin < 0.f); float incfx = inciy / vtan; float incfy = incix * vtan; // Calculate start position int ix = floor(x) + (incix > 0); int iy = floor(y) + (inciy > 0); float fx = x + incfx * fabs(floor(y) + (inciy > 0) - y); float fy = y + incfy * fabs(floor(x) + (incix > 0) - x); // Find the first colliding tile in each direction while (incix && gameLocate(ix - (incix < 0), fy) == 0) { ix += incix; fy += incfy; } while (inciy && gameLocate(fx, iy - (inciy < 0)) == 0) { fx += incfx; iy += inciy; } // Find the shortest ray float dx = (incix) ? ((ix - x) / vcos) : 0xFFFF; float dy = (inciy) ? ((iy - y) / vsin) : 0xFFFF; if (dx < dy) { // Get block type *type = gameLocate(ix - (incix < 0), floor(fy)); // Get wall texture coordinate [0;1] *tx = fy - floor(fy); if (incix < 0) *tx = 1 - *tx; return dx; } else { // Get block type *type = gameLocate(floor(fx), iy - (inciy < 0)); // Get wall texture coordinate [0;1] *tx = fx - floor(fx); if (inciy > 0) *tx = 1 - *tx; return dy; } } // Exported functions void dispInit() { giet_fbf_cma_alloc(); giet_fbf_cma_init_buf(buf0, buf1, sts0, sts1); giet_fbf_cma_start(FBUF_X_SIZE * FBUF_Y_SIZE); cur_buf = 0; } void dispRender(Game *game) { int start = giet_proctime(); float angle = game->player.dir - FIELD_OF_VIEW / 2.f; // Cast a ray for each pixel column and draw a colored wall slice for (int i = 0; i < FBUF_X_SIZE; i++) { float dist; int type; float tx; // Cast a ray to get wall distance dist = dispRaycast(game, &type, &tx, angle); // Perspective correction dist *= cos(game->player.dir - angle); // Draw ceiling, wall and floor dispDrawScrColumn(game, i, FBUF_Y_SIZE / dist, type, tx); angle += FIELD_OF_VIEW / FBUF_X_SIZE; } giet_fbf_cma_display(cur_buf); cur_buf = !cur_buf; giet_tty_printf("[RAYCAST] flip (took %d cycles)\n", giet_proctime() - start); }