azuray/src/main.cc

326 lines
9.1 KiB
C++

#define __BSD_VISIBLE 1
#include <gint/display.h>
#include <gint/keyboard.h>
#include <gint/defs/util.h>
#include <gint/gint.h>
#include <azur/gint/render.h>
#include <math.h>
#include <libprof.h>
#include "azuray.h"
/* Map data as produced by the fxconv converter. */
typedef struct {
u16 width, height;
u8 *cells;
} map_asset_t;
extern map_asset_t const map_1;
struct MapInstance: public azuray::Map
{
using Texture = azuray::Texture;
map_asset_t const *M;
MapInstance(map_asset_t const *M_init):
Map(M_init->width, M_init->height), M {M_init}
{
/* Generate walls from blocks */
for(uint z = 0; z < this->height; z++) {
for(uint x = 0; x <= this->width; x++) {
Texture t;
if(isCellSolid(x-1, z) || isCellSolid(x, z))
t = _blockTexture();
setXWall(x, z, t, t);
}
}
for(uint z = 0; z <= this->height; z++) {
for(uint x = 0; x < this->width; x++) {
Texture t;
if(isCellSolid(x, z-1) || isCellSolid(x, z))
t = _blockTexture();
setZWall(x, z, t, t);
}
}
/* Add a few transparent "gates" for testing */
Texture gate = _gateTexture();
for(uint z = 0; z < this->height; z++) {
if(_walkable(0, z))
setXWall(1, z, gate, gate);
if(_walkable(this->width-1, z)) {
setXWall(this->width - 1, z, gate, gate);
setXWall(this->width, z, gate, gate);
}
}
setXWall(6, 5, gate, gate);
}
/* Generate a random texture for the side of a block. */
Texture _blockTexture()
{
/* Select tile #0, #1, #6 or #7 semi-randomly */
static int dist[] = { 0, 0, 0, 1, 1, 1, 6, 7 };
int tile_no = dist[rand() % 8];
Texture t;
t.type = Texture::TypeImage;
t.combining = false;
t.imageIndex = tile_no;
return t;
}
/* Partially-transparent gate sprite texture. */
Texture _gateTexture()
{
Texture t;
t.type = Texture::TypeImage;
t.combining = true;
t.imageIndex = 3;
return t;
}
/*** Physics ***/
bool _walkable(uint x, uint z)
{
/* Lines are top-down in the asset but bottom-up in coordinates */
z = M->height - z - 1;
return x < M->width && z < M->height && !M->cells[z * M->width + x];
}
bool isXWallSolid(uint x, uint z, bool) override
{
return !_walkable(x-1, z) || !_walkable(x, z);
}
bool isZWallSolid(uint x, uint z, bool) override
{
return !_walkable(x, z-1) || !_walkable(x, z);
}
bool isCellSolid(uint x, uint z) override
{
return x < width && z < height && !_walkable(x, z);
}
};
static num num_cos_dl(num a)
{
num u = 1.0;
int p = 7;
for(p = 2 * p - 1; p >= 1; p -= 2)
u = num(1) - a * a / (p * p + p) * u;
return u;
}
num num_cos(num a)
{
if(a < 0) a = -a;
a = a % num(6.28319);
if(a > num(3.14159)) a -= num(6.28319);
return num_cos_dl(a);
}
num num_sin(num a)
{
return num_cos(a - num(1.57080));
}
#define RGB24(HEX) \
(((HEX >> 8) & 0xf800) | \
((HEX >> 5) & 0x07e0) | \
((HEX >> 3) & 0x001f))
std::unique_ptr<azuray::ImageBank> setupImageBank()
{
/* Load textures from the tileset into the texture bank */
extern image_t const img_tileset;
int texCount = img_tileset.height / 16;
auto IB = azuray::mkImageBank(texCount, 16, img_tileset.palette);
if(!IB)
return IB;
for(int i = 0; i < texCount; i++) {
image_t sub;
image_sub(&img_tileset, 0, 16*i, 16, 16, &sub);
IB->loadImage(i, &sub);
}
return IB;
}
int main(void)
{
prof_init();
azrp_config_scale(1);
vec3 pos(4.5, 0.5, 3.5);
vec3 dir;
num angle = 0;
bool infoview = false;
bool freeze_infoview = false;
num depth = azuray::depthForFOV(100_n);
int render_us_prev_frame = 0;
azuray::PerfInfo perf_prev_frame {};
MapInstance MI(&map_1);
auto IB = setupImageBank();
while(1) {
dir = vec3(num_cos(angle), 0, -num_sin(angle));
/*** Rendering ***/
azuray::perf_reset();
prof_t perf_render = prof_make();
prof_enter(perf_render);
int bg = C_RGB(0, 0, 0);
int floor1 = C_RGB(10, 6, 3);
int floor2 = C_RGB(12, 8, 2);
azrp_clear(bg);
azuray::draw_floor(MI, pos, dir, depth, floor1, floor2);
azuray::draw_walls(MI, *IB, pos, dir, depth);
if(render_us_prev_frame > 0) {
int color = C_WHITE;
if(render_us_prev_frame > 33000)
color = C_RGB(31, 20, 0);
if(render_us_prev_frame > 50000)
color = C_RED;
azrp_print_opt(DWIDTH/2, 1, NULL, color, DTEXT_CENTER,
DTEXT_TOP, "%d ms (%d FPS)",
render_us_prev_frame,
1000000 / render_us_prev_frame);
}
if(infoview) {
char str[32];
pos.x.strToBuffer(str);
azrp_print_opt(1, 1, NULL, C_WHITE, DTEXT_LEFT, DTEXT_TOP,
"x: %.8s", str);
pos.z.strToBuffer(str);
azrp_print_opt(1, 11, NULL, C_WHITE, DTEXT_LEFT, DTEXT_TOP,
"z: %.8s", str);
angle.strToBuffer(str);
azrp_print_opt(1, 21, NULL, C_WHITE, DTEXT_LEFT, DTEXT_TOP,
"angle: %.8s", str);
static int colors[] = {
RGB24(0x264653),
RGB24(0x2a9d8f),
RGB24(0xe9c46a),
RGB24(0xf4a261),
RGB24(0xe76f51),
};
static char const * const desc[] = {
"Raycast",
"Render walls",
"Bound floor",
"Render floor",
};
if(render_us_prev_frame > 0) {
int times[4];
times[0] = prof_time(perf_prev_frame.time_raycast);
times[1] = prof_time(perf_prev_frame.time_shader_walls);
times[2] = prof_time(perf_prev_frame.time_floor_y);
times[3] = prof_time(perf_prev_frame.time_floor_x);
/* Remove floor_x from floor_y */
times[2] -= times[3];
int fields[4], w = 120;
for(int i = 0; i < 4; i++)
fields[i] = times[i] * w / render_us_prev_frame;
int x = DWIDTH - w - 5, y = 4, h = 8;
azrp_rect(x, y, w, h, C_RGB(15, 15, 15));
for(int i = 0; i < 4; i++) {
azrp_rect(x, y, fields[i], h, colors[i]);
azrp_print_opt(x+fields[i]/2, y+h+1, NULL, C_WHITE,
DTEXT_CENTER, DTEXT_TOP, "%d", (times[i]+500) / 1000);
x += fields[i];
}
y += h+12;
x = DWIDTH-12;
for(int i = 0; i < 4; i++) {
azrp_rect(x, y+1, 7, 7, colors[i]);
azrp_text_opt(x-4, y, NULL, C_WHITE, DTEXT_RIGHT,
DTEXT_TOP, desc[i], -1);
y += 11;
}
if(freeze_infoview) {
azrp_print_opt(DWIDTH-1, y, NULL, 0x5555, DTEXT_RIGHT,
DTEXT_TOP, "S-VARS: unfreeze");
}
}
}
azrp_update();
prof_leave(perf_render);
if(!freeze_infoview) {
render_us_prev_frame = prof_time(perf_render);
perf_prev_frame = azuray::perf_get();
}
/*** Input ***/
cleareventflips();
clearevents();
vec3 move_dir = {0, 0, 0};
if(keydown(KEY_F2))
move_dir += vec3(dir.z, 0, -dir.x);
if(keydown(KEY_F1))
move_dir += -vec3(dir.z, 0, -dir.x);
if(keydown(KEY_UP))
move_dir += dir;
if(keydown(KEY_DOWN))
move_dir += -dir;
if(keydown(KEY_RIGHT))
angle = (angle + .1_n) % 6.28319_n;
if(keydown(KEY_LEFT))
angle = (angle - .1_n + 6.28319_n) % 6.28319_n;
if(keydown(KEY_PLUS))
pos.y = min(pos.y + .1_n, 1_n);
if(keydown(KEY_MINUS))
pos.y = max(pos.y - .1_n, 0_n);
if(keypressed(KEY_MENU))
gint_osmenu();
if(keypressed(KEY_EXIT))
break;
if(keypressed(KEY_VARS) && !keydown(KEY_SHIFT))
infoview = !infoview;
if(keypressed(KEY_VARS) && keydown(KEY_SHIFT))
freeze_infoview = !freeze_infoview;
if(keypressed(KEY_F4)) {
pos.x = 2.550979_n;
pos.z = 3.719253_n;
angle = -0.29986_n;
}
if(keypressed(KEY_F5)) {
pos.x = 5.513748_n;
pos.z = 5.348083_n;
angle = 0_n;
}
if(keypressed(KEY_F6)) {
pos.x = 2.489120_n;
pos.z = 3.642013_n;
angle = -2.59976_n;
}
/*** Physics ***/
num speed = 0.1;
if(move_dir.x != 0 || move_dir.z != 0)
pos = azuray::physics_move(MI, pos, move_dir, speed);
}
return 0;
}