From fc30334a4de26df0ad57a5bae577ff30a04dca85 Mon Sep 17 00:00:00 2001 From: xtreme8000 Date: Mon, 27 Mar 2023 18:58:52 +0200 Subject: [PATCH] WIP: pc port --- CMakeLists.txt | 132 ++++++ Makefile | 2 +- resources/fragment.shader | 32 ++ resources/vertex.shader | 29 ++ source/chunk.c | 1 - source/chunk_mesher.c | 42 +- source/game/camera.c | 2 +- source/game/gui/screen_ingame.c | 9 +- source/main.c | 16 +- source/network/client_interface.c | 27 +- source/network/region_archive.c | 34 +- source/network/server_interface.c | 23 +- source/network/server_local.c | 7 +- source/platform/graphics/displaylist.c | 121 +---- source/platform/graphics/displaylist.h | 9 +- source/platform/graphics/gfx.c | 445 +------------------ source/platform/graphics/gfx.h | 5 + source/platform/graphics/gfx_util.c | 223 +++------- source/platform/graphics/gui_util.c | 126 +++--- source/platform/graphics/pc/displaylist.c | 148 +++++++ source/platform/graphics/pc/gfx.c | 469 ++++++++++++++++++++ source/platform/graphics/render_block.c | 1 - source/platform/graphics/render_block.h | 1 - source/platform/graphics/render_item.c | 7 +- source/platform/graphics/wii/displaylist.c | 131 ++++++ source/platform/graphics/wii/gfx.c | 488 +++++++++++++++++++++ source/platform/input.c | 65 ++- source/platform/input.h | 3 + source/platform/thread.c | 150 +++++++ source/platform/thread.h | 66 +++ source/platform/time.c | 65 +++ source/platform/time.h | 38 ++ source/util.c | 26 +- source/util.h | 7 +- source/world.c | 3 +- 35 files changed, 2083 insertions(+), 870 deletions(-) create mode 100755 CMakeLists.txt create mode 100644 resources/fragment.shader create mode 100644 resources/vertex.shader create mode 100644 source/platform/graphics/pc/displaylist.c create mode 100644 source/platform/graphics/pc/gfx.c create mode 100644 source/platform/graphics/wii/displaylist.c create mode 100644 source/platform/graphics/wii/gfx.c create mode 100644 source/platform/thread.c create mode 100644 source/platform/thread.h create mode 100644 source/platform/time.c create mode 100644 source/platform/time.h diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100755 index 0000000..2ba0fe2 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,132 @@ +cmake_minimum_required(VERSION 3.14) + +project(cavex C) + +add_compile_options(-O3 -march=native -g) + +find_package(ZLIB REQUIRED) +find_package(Threads REQUIRED) +find_package(glfw3 3.3 REQUIRED) +find_package(OpenGL REQUIRED) +find_package(GLEW REQUIRED) + +add_executable(cavex + source/block/aabb.c + source/block/block_bed.c + source/block/block_bedrock.c + source/block/block_bookshelf.c + source/block/block_bricks.c + source/block/block_brown_mushroom.c + source/block/block_cactus.c + source/block/block_cake.c + source/block/block_cast_block.c + source/block/block_chest.c + source/block/block_clay.c + source/block/block_cobblestone.c + source/block/block_cobweb.c + source/block/block_crops.c + source/block/block_dirt.c + source/block/block_dispenser.c + source/block/block_door.c + source/block/block_double_slab.c + source/block/block_farmland.c + source/block/block_fence.c + source/block/block_fire.c + source/block/block_flower.c + source/block/block_furnace.c + source/block/block_glass.c + source/block/block_glowstone.c + source/block/block_grass.c + source/block/block_gravel.c + source/block/block_ice.c + source/block/block_jukebox.c + source/block/block_ladder.c + source/block/block_lava.c + source/block/block_leaves.c + source/block/block_log.c + source/block/block_netherrack.c + source/block/block_noteblock.c + source/block/block_obsidian.c + source/block/block_ore.c + source/block/block_planks.c + source/block/block_portal.c + source/block/block_pressure_plate.c + source/block/block_pumpkin.c + source/block/block_rail.c + source/block/block_red_mushroom.c + source/block/block_reed.c + source/block/block_rose.c + source/block/block_sand.c + source/block/block_sandstone.c + source/block/block_sapling.c + source/block/blocks.c + source/block/block_slab.c + source/block/block_snow.c + source/block/block_spawner.c + source/block/block_sponge.c + source/block/block_stairs.c + source/block/block_stone.c + source/block/block_tallgrass.c + source/block/block_tnt.c + source/block/block_torch.c + source/block/block_trapdoor.c + source/block/block_water.c + source/block/block_wool.c + source/block/block_workbench.c + source/block/face_occlusion.c + + source/cNBT/buffer.c + source/cNBT/nbt_loading.c + source/cNBT/nbt_parsing.c + source/cNBT/nbt_treeops.c + source/cNBT/nbt_util.c + + source/game/gui/screen_ingame.c + source/game/gui/screen_load_world.c + source/game/gui/screen_select_world.c + source/game/gui/screen.c + source/game/camera.c + source/game/game_state.c + + source/item/inventory.c + source/item/items.c + + source/network/client_interface.c + source/network/level_archive.c + source/network/region_archive.c + source/network/server_interface.c + source/network/server_local.c + source/network/server_world.c + + source/platform/graphics/displaylist.c + source/platform/graphics/gfx_util.c + source/platform/graphics/gfx.c + source/platform/graphics/gui_util.c + source/platform/graphics/render_block.c + source/platform/graphics/render_item.c + source/platform/input.c + source/platform/thread.c + source/platform/time.c + + source/chunk_mesher.c + source/chunk.c + source/daytime.c + source/lighting.c + source/main.c + source/stack.c + source/util.c + source/world.c + + source/lodepng/lodepng.c + ) + +target_compile_definitions(cavex PRIVATE PLATFORM_PC CGLM_ALL_UNALIGNED) + +set_target_properties( + cavex PROPERTIES + C_STANDARD 99 +) + +set_property(TARGET cavex PROPERTY INTERPROCEDURAL_OPTIMIZATION True) + +target_link_libraries(cavex ${CMAKE_THREAD_LIBS_INIT} ZLIB::ZLIB glfw GLEW::GLEW OpenGL::GL m) diff --git a/Makefile b/Makefile index a14c94b..7f87eeb 100644 --- a/Makefile +++ b/Makefile @@ -32,7 +32,7 @@ INCLUDES := # options for code generation #--------------------------------------------------------------------------------- -CFLAGS = -std=c99 -pedantic -Wextra -Wno-unused-parameter -flto=auto -O3 -Wall $(MACHDEP) $(INCLUDE) +CFLAGS = -std=c99 -pedantic -Wextra -Wno-unused-parameter -flto=auto -O3 -Wall -DPLATFORM_WII $(MACHDEP) $(INCLUDE) CXXFLAGS = $(CFLAGS) LDFLAGS = -g $(MACHDEP) -Wl,-Map,$(notdir $@).map diff --git a/resources/fragment.shader b/resources/fragment.shader new file mode 100644 index 0000000..9c493e6 --- /dev/null +++ b/resources/fragment.shader @@ -0,0 +1,32 @@ +#version 110 + +uniform sampler2D tex; +uniform bool enable_texture; +uniform bool enable_alpha; + +uniform bool enable_fog; +uniform vec2 fog_delta; +uniform float fog_distance; +uniform vec3 fog_color; + +varying vec3 v_pos; +varying vec4 v_color; +varying vec2 v_texcoord; + +void main() { + vec4 tex_color = vec4(1.0); + + if(enable_texture) + tex_color = texture2D(tex, v_texcoord); + + float v_fog = 0.0; + + if(enable_fog) + v_fog = clamp((length(fog_delta + v_pos.xz) - (fog_distance - 9.0)) / 8.0, 0.0, 1.0); + + vec4 frag = v_color * tex_color; + gl_FragColor = vec4(mix(frag.rgb, fog_color, v_fog), frag.a); + + if(enable_alpha && gl_FragColor.a < 0.0625) + discard; +} diff --git a/resources/vertex.shader b/resources/vertex.shader new file mode 100644 index 0000000..15eac01 --- /dev/null +++ b/resources/vertex.shader @@ -0,0 +1,29 @@ +#version 110 + +uniform mat4 mv; +uniform mat4 proj; +uniform mat4 texm; + +uniform bool enable_lighting; +uniform float lighting[256]; + +attribute vec3 a_pos; +attribute vec4 a_color; +attribute vec2 a_texcoord; +attribute vec2 a_light; + +varying vec3 v_pos; +varying vec4 v_color; +varying vec2 v_texcoord; + +void main() { + if(enable_lighting) { + v_color = vec4(vec3(lighting[int(a_light.x) + int(a_light.y) * 16]), 1.0); + } else { + v_color = a_color; + } + + v_pos = a_pos; + v_texcoord = (texm * vec4(a_texcoord, 0.0, 1.0)).xy; + gl_Position = proj * mv * vec4(a_pos, 1.0); +} diff --git a/source/chunk.c b/source/chunk.c index 58a6980..08fb12a 100644 --- a/source/chunk.c +++ b/source/chunk.c @@ -18,7 +18,6 @@ */ #include -#include #include #include #include diff --git a/source/chunk_mesher.c b/source/chunk_mesher.c index 75651e1..7f16b73 100644 --- a/source/chunk_mesher.c +++ b/source/chunk_mesher.c @@ -18,11 +18,11 @@ */ #include -#include #include #include "chunk_mesher.h" #include "platform/graphics/displaylist.h" +#include "platform/thread.h" #include "stack.h" #include "world.h" @@ -31,6 +31,10 @@ #define BLK_INDEX2(x, y, z) ((x) + ((z) + (y)*CHUNK_SIZE) * CHUNK_SIZE) #define BLK_DATA(b, x, y, z) ((b)[BLK_INDEX((x) + 1, (y) + 1, (z) + 1)]) +#ifndef MAX +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif + struct chunk_mesher_rpc { struct chunk* chunk; // ingoing @@ -46,9 +50,9 @@ struct chunk_mesher_rpc { }; static struct chunk_mesher_rpc rpc_msg[CHUNK_MESHER_QLENGTH]; -static mqbox_t mesher_requests; -static mqbox_t mesher_results; -static mqbox_t mesher_empty_msg; +static struct thread_channel mesher_requests; +static struct thread_channel mesher_results; +static struct thread_channel mesher_empty_msg; static int chunk_test_side(enum side* on_sides, c_coord_t x, c_coord_t y, c_coord_t z) { @@ -479,8 +483,7 @@ static void chunk_mesher_build(struct chunk_mesher_rpc* req) { for(int k = 0; k < 13; k++) { if(vertices[k] > 0 && vertices[k] <= 0xFFFF * 4) { - displaylist_finalize(req->result.mesh + k, GX_QUADS, GX_VTXFMT0, - vertices[k]); + displaylist_finalize(req->result.mesh + k, vertices[k]); req->result.has_displist[k] = true; } else { displaylist_destroy(req->result.mesh + k); @@ -495,29 +498,30 @@ static void chunk_mesher_build(struct chunk_mesher_rpc* req) { static void* chunk_mesher_local_thread(void* user) { while(1) { struct chunk_mesher_rpc* request; - MQ_Receive(mesher_requests, (mqmsg_t*)&request, MQ_MSG_BLOCK); + tchannel_receive(&mesher_requests, (void**)&request, true); chunk_mesher_build(request); - MQ_Send(mesher_results, request, MQ_MSG_BLOCK); + tchannel_send(&mesher_results, request, true); } return NULL; } void chunk_mesher_init() { - MQ_Init(&mesher_requests, CHUNK_MESHER_QLENGTH); - MQ_Init(&mesher_results, CHUNK_MESHER_QLENGTH); - MQ_Init(&mesher_empty_msg, CHUNK_MESHER_QLENGTH); + tchannel_init(&mesher_requests, CHUNK_MESHER_QLENGTH); + tchannel_init(&mesher_results, CHUNK_MESHER_QLENGTH); + tchannel_init(&mesher_empty_msg, CHUNK_MESHER_QLENGTH); for(int k = 0; k < CHUNK_MESHER_QLENGTH; k++) - MQ_Send(mesher_empty_msg, rpc_msg + k, MQ_MSG_BLOCK); + tchannel_send(&mesher_empty_msg, rpc_msg + k, true); - lwp_t thread; - LWP_CreateThread(&thread, chunk_mesher_local_thread, NULL, NULL, 0, 4); + struct thread t; + thread_create(&t, chunk_mesher_local_thread, NULL, 4); } void chunk_mesher_receive() { struct chunk_mesher_rpc* result; - while(MQ_Receive(mesher_results, (mqmsg_t*)&result, MQ_MSG_NOBLOCK)) { + + while(tchannel_receive(&mesher_results, (void**)&result, false)) { for(int k = 0; k < 13; k++) { if(result->chunk->has_displist[k]) displaylist_destroy(result->chunk->mesh + k); @@ -531,7 +535,7 @@ void chunk_mesher_receive() { chunk_unref(result->chunk); - MQ_Send(mesher_empty_msg, result, MQ_MSG_BLOCK); + tchannel_send(&mesher_empty_msg, result, true); } } @@ -539,7 +543,7 @@ bool chunk_mesher_send(struct chunk* c) { assert(c); struct chunk_mesher_rpc* request; - if(!MQ_Receive(mesher_empty_msg, (mqmsg_t*)&request, MQ_MSG_NOBLOCK)) + if(!tchannel_receive(&mesher_empty_msg, (void**)&request, false)) return false; struct block_data* bd @@ -547,7 +551,7 @@ bool chunk_mesher_send(struct chunk* c) { * sizeof(struct block_data)); if(!bd) { - MQ_Send(mesher_empty_msg, request, MQ_MSG_BLOCK); + tchannel_send(&mesher_empty_msg, request, true); return false; } @@ -564,6 +568,6 @@ bool chunk_mesher_send(struct chunk* c) { } } - MQ_Send(mesher_requests, request, MQ_MSG_BLOCK); + tchannel_send(&mesher_requests, request, true); return true; } diff --git a/source/game/camera.c b/source/game/camera.c index 8a96a61..9e651ef 100644 --- a/source/game/camera.c +++ b/source/game/camera.c @@ -178,7 +178,7 @@ void camera_update(struct camera* c, float dt) { c->controller.vz = 0; } - c->ry = glm_clamp(c->ry, glm_rad(0.5F), M_PI - glm_rad(0.5F)); + c->ry = glm_clamp(c->ry, glm_rad(0.5F), GLM_PI - glm_rad(0.5F)); glm_perspective(glm_rad(gstate.config.fov), (float)gfx_width() / (float)gfx_height(), 0.1F, diff --git a/source/game/gui/screen_ingame.c b/source/game/gui/screen_ingame.c index b3a30e5..a0f45b7 100644 --- a/source/game/gui/screen_ingame.c +++ b/source/game/gui/screen_ingame.c @@ -80,11 +80,15 @@ static void screen_ingame_render3D(struct screen* s, mat4 view) { glm_scale_uni(model, 0.4F); glm_translate(model, (vec3) {-0.5F, -0.5F, -0.5F}); + gfx_depth_range(0.0F, 0.1F); + struct item_data item; if(inventory_get_slot(&gstate.inventory, inventory_get_hotbar(&gstate.inventory), &item) && item_get(&item)) items[item.id]->renderItem(item_get(&item), &item, model, false); + + gfx_depth_range(0.0F, 1.0F); } static void screen_ingame_update(struct screen* s, float dt) { @@ -180,7 +184,7 @@ static void screen_ingame_render2D(struct screen* s, int width, int height) { gstate.stats.dt_vsync * 1000.0F); gutil_text(4, 4 + 17 * 1, str, 16); - sprintf(str, "%i chunks", gstate.stats.chunks_rendered); + sprintf(str, "%zu chunks", gstate.stats.chunks_rendered); gutil_text(4, 4 + 17 * 2, str, 16); sprintf(str, "(%0.1f, %0.1f, %0.1f) (%0.1f, %0.1f)", gstate.camera.x, @@ -244,7 +248,10 @@ static void screen_ingame_render2D(struct screen* s, int width, int height) { model, (vec3) {(width - 182 * 2) / 2 + 3 * 2 + 20 * 2 * k, height - 32 * 8 / 5 - 19 * 2, 0}); + + gfx_depth_range(0.0F, 0.1F); items[item.id]->renderItem(item_get(&item), &item, model, true); + gfx_depth_range(0.0F, 1.0F); if(item.count > 1) { char count[4]; diff --git a/source/main.c b/source/main.c index fadd713..31c151b 100644 --- a/source/main.c +++ b/source/main.c @@ -23,7 +23,7 @@ #include #include -#ifdef GEKKO +#ifdef PLATFORM_WII #include #endif @@ -52,7 +52,7 @@ int main(void) { gstate.world_loaded = false; gstate.held_item_animation.finished = true; -#ifdef GEKKO +#ifdef PLATFORM_WII fatInitDefault(); #endif @@ -88,8 +88,6 @@ int main(void) { % DAY_LENGTH_TICKS) / (float)DAY_LENGTH_TICKS; - input_poll(); - clin_update(); bool render_world @@ -128,8 +126,13 @@ int main(void) { daytime_sky_colors(daytime, top_plane_color, bottom_plane_color, atmosphere_color); - gfx_clear_buffers(atmosphere_color[0], atmosphere_color[1], - atmosphere_color[2]); + if(render_world) { + gfx_clear_buffers(atmosphere_color[0], atmosphere_color[1], + atmosphere_color[2]); + } else { + gfx_clear_buffers(128, 128, 128); + } + gfx_fog_color(atmosphere_color[0], atmosphere_color[1], atmosphere_color[2]); @@ -174,6 +177,7 @@ int main(void) { daytime = fmaxf(fminf(daytime, 1), 0); + input_poll(); gfx_finish(true); } return 0; diff --git a/source/network/client_interface.c b/source/network/client_interface.c index bd32ea1..9a0dd0c 100644 --- a/source/network/client_interface.c +++ b/source/network/client_interface.c @@ -19,12 +19,15 @@ #include "client_interface.h" #include "../game/game_state.h" +#include "../platform/thread.h" #include "server_interface.h" #define RPC_INBOX_SIZE 16 static struct client_rpc rpc_msg[RPC_INBOX_SIZE]; -mqbox_t clin_inbox; -mqbox_t clin_empty_msg; +static struct thread_channel clin_inbox; +static struct thread_channel clin_empty_msg; + +static ptime_t last_pos_update; void clin_chunk(w_coord_t x, w_coord_t y, w_coord_t z, w_coord_t sx, w_coord_t sy, w_coord_t sz, uint8_t* ids, uint8_t* metadata, @@ -126,20 +129,20 @@ void clin_process(struct client_rpc* call) { } void clin_init() { - MQ_Init(&clin_inbox, RPC_INBOX_SIZE); - MQ_Init(&clin_empty_msg, RPC_INBOX_SIZE); + tchannel_init(&clin_inbox, RPC_INBOX_SIZE); + tchannel_init(&clin_empty_msg, RPC_INBOX_SIZE); for(int k = 0; k < RPC_INBOX_SIZE; k++) - MQ_Send(clin_empty_msg, rpc_msg + k, MQ_MSG_BLOCK); + tchannel_send(&clin_empty_msg, rpc_msg + k, true); + + last_pos_update = time_get(); } -static ptime_t last_pos_update = 0; - void clin_update() { - mqmsg_t call; - while(MQ_Receive(clin_inbox, &call, MQ_MSG_NOBLOCK)) { + void* call; + while(tchannel_receive(&clin_inbox, &call, false)) { clin_process(call); - MQ_Send(clin_empty_msg, call, MQ_MSG_BLOCK); + tchannel_send(&clin_empty_msg, call, true); } if(gstate.world_loaded && time_diff_ms(last_pos_update, time_get()) >= 50) { @@ -157,7 +160,7 @@ void clin_update() { void clin_rpc_send(struct client_rpc* call) { struct client_rpc* empty; - MQ_Receive(clin_empty_msg, (mqmsg_t*)&empty, MQ_MSG_BLOCK); + tchannel_receive(&clin_empty_msg, (void**)&empty, true); *empty = *call; - MQ_Send(clin_inbox, empty, MQ_MSG_BLOCK); + tchannel_send(&clin_inbox, empty, true); } diff --git a/source/network/region_archive.c b/source/network/region_archive.c index 241ada1..c82fefa 100644 --- a/source/network/region_archive.c +++ b/source/network/region_archive.c @@ -27,6 +27,30 @@ #define CHUNK_EXISTS(offset, sectors) ((offset) >= 2 && (sectors) >= 1) +static uint32_t conv_u32_native(uint8_t* data) { + return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; +} + +static void conv_native_u32(uint32_t in, uint8_t* data) { + data[0] = in >> 24; + data[1] = (in >> 16) & 0xFF; + data[2] = (in >> 8) & 0xFF; + data[3] = in & 0xFF; +} + +static size_t fread_u32(uint32_t* out, FILE* f) { + size_t res = fread(out, sizeof(uint32_t), 1, f); + *out = conv_u32_native((uint8_t*)out); + return res; +} + +static size_t fwrite_u32(uint32_t in, FILE* f) { + uint8_t tmp[sizeof(uint32_t)]; + conv_native_u32(in, tmp); + + return fwrite(tmp, sizeof(uint32_t), 1, f); +} + static int sort_region_chunks(const void* a, const void* b) { uint32_t offset_a = (*(const uint32_t*)a) >> 8; uint32_t offset_b = (*(const uint32_t*)b) >> 8; @@ -136,6 +160,10 @@ bool region_archive_create(struct region_archive* ra, string_t world_name, return false; } + // convert from big endian to native endian + for(size_t k = 0; k < REGION_SIZE * REGION_SIZE; k++) + ra->offsets[k] = conv_u32_native((uint8_t*)(ra->offsets + k)); + fclose(f); ilist_regions_init_field(ra); @@ -202,7 +230,7 @@ bool region_archive_get_blocks(struct region_archive* ra, w_coord_t x, } uint32_t length; - if(!fread(&length, sizeof(uint32_t), 1, f) + if(!fread_u32(&length, f) || length + sizeof(uint32_t) > sectors * REGION_SECTOR_SIZE) { fclose(f); return false; @@ -294,7 +322,7 @@ static bool file_overwrite_index(FILE* f, size_t index, uint32_t data) { return false; } - if(fwrite(&data, sizeof(uint32_t), 1, f) != 1) { + if(fwrite_u32(data, f) != 1) { fclose(f); return false; } @@ -311,7 +339,7 @@ static bool file_overwrite_chunk(FILE* f, size_t offset, void* data, return false; } - if(fwrite((uint32_t[]) {length + 1}, sizeof(uint32_t), 1, f) != 1) { + if(fwrite_u32(length + 1, f) != 1) { fclose(f); return false; } diff --git a/source/network/server_interface.c b/source/network/server_interface.c index e96993a..f0d977d 100644 --- a/source/network/server_interface.c +++ b/source/network/server_interface.c @@ -18,32 +18,31 @@ */ #include -#include +#include "../platform/thread.h" #include "server_interface.h" #define RPC_INBOX_SIZE 16 static struct server_rpc rpc_msg[RPC_INBOX_SIZE]; -mqbox_t svin_inbox; -mqbox_t svin_empty_msg; +static struct thread_channel svin_inbox; +static struct thread_channel svin_empty_msg; void svin_init() { - MQ_Init(&svin_inbox, RPC_INBOX_SIZE); - MQ_Init(&svin_empty_msg, RPC_INBOX_SIZE); + tchannel_init(&svin_inbox, RPC_INBOX_SIZE); + tchannel_init(&svin_empty_msg, RPC_INBOX_SIZE); for(int k = 0; k < RPC_INBOX_SIZE; k++) - MQ_Send(svin_empty_msg, rpc_msg + k, MQ_MSG_BLOCK); + tchannel_send(&svin_empty_msg, rpc_msg + k, true); } void svin_process_messages(void (*process)(struct server_rpc*, void*), void* user, bool block) { assert(process); - mqmsg_t call; - while( - MQ_Receive(svin_inbox, &call, block ? MQ_MSG_BLOCK : MQ_MSG_NOBLOCK)) { + void* call; + while(tchannel_receive(&svin_inbox, &call, block)) { process(call, user); - MQ_Send(svin_empty_msg, call, MQ_MSG_BLOCK); + tchannel_send(&svin_empty_msg, call, true); } } @@ -51,7 +50,7 @@ void svin_rpc_send(struct server_rpc* call) { assert(call); struct server_rpc* empty; - MQ_Receive(svin_empty_msg, (mqmsg_t*)&empty, MQ_MSG_BLOCK); + tchannel_receive(&svin_empty_msg, (void**)&empty, true); *empty = *call; - MQ_Send(svin_inbox, empty, MQ_MSG_BLOCK); + tchannel_send(&svin_inbox, empty, true); } diff --git a/source/network/server_local.c b/source/network/server_local.c index 3d6a40d..7c5ddfd 100644 --- a/source/network/server_local.c +++ b/source/network/server_local.c @@ -24,6 +24,7 @@ #include "../cglm/cglm.h" #include "../item/inventory.h" +#include "../platform/thread.h" #include "client_interface.h" #include "server_interface.h" #include "server_local.h" @@ -219,7 +220,7 @@ static void server_local_update(struct server_local* s) { static void* server_local_thread(void* user) { while(1) { server_local_update(user); - usleep(50 * 1000); + thread_msleep(50); } return NULL; @@ -233,6 +234,6 @@ void server_local_create(struct server_local* s) { s->player.finished_loading = false; string_init(s->level_name); - lwp_t thread; - LWP_CreateThread(&thread, server_local_thread, s, NULL, 0, 8); + struct thread t; + thread_create(&t, server_local_thread, s, 8); } diff --git a/source/platform/graphics/displaylist.c b/source/platform/graphics/displaylist.c index 357e634..c795345 100644 --- a/source/platform/graphics/displaylist.c +++ b/source/platform/graphics/displaylist.c @@ -1,5 +1,5 @@ /* - Copyright (c) 2022 ByteBit/xtreme8000 + Copyright (c) 2023 ByteBit/xtreme8000 This file is part of CavEX. @@ -17,117 +17,10 @@ along with CavEX. If not, see . */ -#include -#include -#include -#include +#ifdef PLATFORM_WII +#include "wii/displaylist.c" +#endif -#include "displaylist.h" - -#define GX_NOP 0 -#define DISPLAYLIST_CLL 32 -#define DISPLAYLIST_CACHE_LINES(v, s) \ - (((v) * (s) + 3 + DISPLAYLIST_CLL - 1) / DISPLAYLIST_CLL * DISPLAYLIST_CLL) - -#define MEM_U8(b, i) (*((uint8_t*)(b) + (i))) -#define MEM_U16(b, i) (*(uint16_t*)((uint8_t*)(b) + (i))) -#define MEM_I16(b, i) (*(int16_t*)((uint8_t*)(b) + (i))) - -void displaylist_init(struct displaylist* l, size_t vertices, - size_t vertex_size) { - assert(l && vertices > 0 && vertex_size > 0); - - l->length = DISPLAYLIST_CACHE_LINES(vertices, vertex_size); - l->data = NULL; - /* has 32 byte padding of GX_NOP in front for possible misalignment caused - * by realloc */ - l->index = DISPLAYLIST_CLL + 3; - l->finished = false; -} - -void displaylist_destroy(struct displaylist* l) { - assert(l); - - if(l->data) - free(l->data); -} - -void displaylist_reset(struct displaylist* l) { - assert(l && !l->finished); - l->index = DISPLAYLIST_CLL + 3; -} - -void displaylist_finalize(struct displaylist* l, uint8_t primitve, - uint8_t vtxfmt, uint16_t vtxcnt) { - assert(l && !l->finished && l->data); - - MEM_U8(l->data, DISPLAYLIST_CLL) = primitve | (vtxfmt & 7); - MEM_U16(l->data, DISPLAYLIST_CLL + 1) = vtxcnt; - - memset(l->data, GX_NOP, DISPLAYLIST_CLL); - memset((uint8_t*)l->data + l->index, GX_NOP, - l->length + DISPLAYLIST_CLL - l->index); - DCStoreRange(l->data, l->length + DISPLAYLIST_CLL); - l->finished = true; -} - -void displaylist_pos(struct displaylist* l, int16_t x, int16_t y, int16_t z) { - assert(l && !l->finished); - - if(!l->data) { - l->data = malloc(l->length + DISPLAYLIST_CLL); - assert(l->data); - } - - if(l->index + 9 > l->length) { - l->length = (l->length * 5 / 4 + 9 + DISPLAYLIST_CLL - 1) - / DISPLAYLIST_CLL * DISPLAYLIST_CLL; - l->data = realloc(l->data, l->length + DISPLAYLIST_CLL); - assert(l->data); - } - - MEM_U16(l->data, l->index) = x; - l->index += 2; - MEM_U16(l->data, l->index) = y; - l->index += 2; - MEM_U16(l->data, l->index) = z; - l->index += 2; -} - -void displaylist_color(struct displaylist* l, uint8_t index) { - assert(l && !l->finished && l->data); - MEM_U8(l->data, l->index++) = index; -} - -void displaylist_texcoord(struct displaylist* l, uint8_t s, uint8_t t) { - assert(l && !l->finished && l->data); - MEM_U8(l->data, l->index++) = s; - MEM_U8(l->data, l->index++) = t; -} - -void displaylist_render(struct displaylist* l) { - assert(l); - - if(l->finished) - GX_CallDispList( - (uint8_t*)l->data - + (DISPLAYLIST_CLL - (uintptr_t)l->data % DISPLAYLIST_CLL), - (l->index + (uintptr_t)l->data % DISPLAYLIST_CLL - 1) - / DISPLAYLIST_CLL * DISPLAYLIST_CLL); -} - -void displaylist_render_immediate(struct displaylist* l, uint8_t primitve, - uint8_t vtxfmt, uint16_t vtxcnt) { - assert(l && l->data); - - uint8_t* base = (uint8_t*)l->data + DISPLAYLIST_CLL + 3; - - GX_Begin(primitve, vtxfmt, vtxcnt); - for(uint16_t k = 0; k < vtxcnt; k++) { - GX_Position3s16(MEM_U16(base, 0), MEM_U16(base, 2), MEM_U16(base, 4)); - GX_Color1x8(MEM_U8(base, 6)); - GX_TexCoord2u8(MEM_U8(base, 7), MEM_U8(base, 8)); - base += 9; - } - GX_End(); -} +#ifdef PLATFORM_PC +#include "pc/displaylist.c" +#endif diff --git a/source/platform/graphics/displaylist.h b/source/platform/graphics/displaylist.h index 1ce336b..67dd5f5 100644 --- a/source/platform/graphics/displaylist.h +++ b/source/platform/graphics/displaylist.h @@ -29,17 +29,18 @@ struct displaylist { size_t length; size_t index; bool finished; +#ifdef PLATFORM_PC + int vbo; +#endif }; void displaylist_init(struct displaylist* l, size_t vertices, size_t vertex_size); void displaylist_destroy(struct displaylist* l); void displaylist_reset(struct displaylist* l); -void displaylist_finalize(struct displaylist* l, uint8_t primitve, - uint8_t vtxfmt, uint16_t vtxcnt); +void displaylist_finalize(struct displaylist* l, uint16_t vtxcnt); void displaylist_render(struct displaylist* l); -void displaylist_render_immediate(struct displaylist* l, uint8_t primitve, - uint8_t vtxfmt, uint16_t vtxcnt); +void displaylist_render_immediate(struct displaylist* l, uint16_t vtxcnt); void displaylist_pos(struct displaylist* l, int16_t x, int16_t y, int16_t z); void displaylist_color(struct displaylist* l, uint8_t index); diff --git a/source/platform/graphics/gfx.c b/source/platform/graphics/gfx.c index c5225f5..7b1ebeb 100644 --- a/source/platform/graphics/gfx.c +++ b/source/platform/graphics/gfx.c @@ -1,5 +1,5 @@ /* - Copyright (c) 2022 ByteBit/xtreme8000 + Copyright (c) 2023 ByteBit/xtreme8000 This file is part of CavEX. @@ -17,441 +17,10 @@ along with CavEX. If not, see . */ -#include -#include -#include -#include -#include -#include +#ifdef PLATFORM_WII +#include "wii/gfx.c" +#endif -#include "../../util.h" -#include "gfx.h" - -#include "textures.h" -#include "textures_tpl.h" - -#define FIFO_SIZE (256 * 1024) - -static GXRModeObj* screenMode; // TODO: rename -static void* frameBuffer[3]; -static mqmsg_t frame = NULL; -static mqbox_t frame_draw; -static mqbox_t frame_empty; -static void* fifoBuffer = NULL; -static uint8_t colors[256 * 3] ATTRIBUTE_ALIGN(32); - -static bool gfx_matrix_texture_prev = false; -static bool gfx_fog_prev = false; - -/*static void* thread_vsync(void* user) { - void* current_frame = NULL; - - while(1) { - mqmsg_t input_frame; - MQ_Receive(frame_draw, &input_frame, MQ_MSG_BLOCK); - - VIDEO_SetNextFramebuffer(input_frame); - VIDEO_Flush(); - - if(current_frame) - MQ_Send(frame_empty, current_frame, MQ_MSG_BLOCK); - - current_frame = input_frame; - - VIDEO_WaitVSync(); - } - - return NULL; -}*/ - -static volatile mqmsg_t current_frame = NULL; - -static void copy_buffers(u32 cnt) { - mqmsg_t input_frame; - - if(MQ_Receive(frame_draw, &input_frame, MQ_MSG_NOBLOCK)) { - VIDEO_SetNextFramebuffer(input_frame); - VIDEO_Flush(); - - if(current_frame) - MQ_Send(frame_empty, current_frame, MQ_MSG_BLOCK); - - current_frame = input_frame; - } -} - -static void gfx_load_textures() { - GXTexObj terrain, font, anim, gui, gui2, items, fog; - TPLFile spriteTPL; - TPL_OpenTPLFromMemory(&spriteTPL, (void*)textures_tpl, textures_tpl_size); - TPL_GetTexture(&spriteTPL, texture_terrain, &terrain); - GX_InitTexObjFilterMode(&terrain, GX_NEAR, GX_NEAR); - GX_InitTexObjMaxAniso(&terrain, GX_ANISO_1); - GX_LoadTexObj(&terrain, GX_TEXMAP0); - - TPL_GetTexture(&spriteTPL, texture_font, &font); - GX_InitTexObjFilterMode(&font, GX_NEAR, GX_NEAR); - GX_InitTexObjMaxAniso(&font, GX_ANISO_1); - GX_LoadTexObj(&font, GX_TEXMAP1); - - TPL_GetTexture(&spriteTPL, texture_anim, &anim); - GX_InitTexObjFilterMode(&anim, GX_NEAR, GX_NEAR); - GX_InitTexObjMaxAniso(&anim, GX_ANISO_1); - GX_LoadTexObj(&anim, GX_TEXMAP2); - - TPL_GetTexture(&spriteTPL, texture_gui, &gui); - GX_InitTexObjFilterMode(&gui, GX_NEAR, GX_NEAR); - GX_InitTexObjMaxAniso(&gui, GX_ANISO_1); - GX_LoadTexObj(&gui, GX_TEXMAP3); - - TPL_GetTexture(&spriteTPL, texture_gui2, &gui2); - GX_InitTexObjFilterMode(&gui2, GX_NEAR, GX_NEAR); - GX_InitTexObjMaxAniso(&gui2, GX_ANISO_1); - GX_LoadTexObj(&gui2, GX_TEXMAP4); - - TPL_GetTexture(&spriteTPL, texture_items, &items); - GX_InitTexObjFilterMode(&items, GX_NEAR, GX_NEAR); - GX_InitTexObjMaxAniso(&items, GX_ANISO_1); - GX_LoadTexObj(&items, GX_TEXMAP5); - - TPL_GetTexture(&spriteTPL, texture_fog, &fog); - GX_InitTexObjFilterMode(&fog, GX_LINEAR, GX_LINEAR); - GX_InitTexObjMaxAniso(&fog, GX_ANISO_1); - GX_InitTexObjWrapMode(&fog, GX_CLAMP, GX_CLAMP); - GX_LoadTexObj(&fog, GX_TEXMAP7); - - TPL_CloseTPLFile(&spriteTPL); -} - -int gfx_width() { - return 802; -} - -int gfx_height() { - return 480; -} - -void gfx_setup() { - VIDEO_Init(); - screenMode = VIDEO_GetPreferredMode(NULL); - frameBuffer[0] = MEM_K0_TO_K1(SYS_AllocateFramebuffer(screenMode)); - frameBuffer[1] = MEM_K0_TO_K1(SYS_AllocateFramebuffer(screenMode)); - frameBuffer[2] = MEM_K0_TO_K1(SYS_AllocateFramebuffer(screenMode)); - - MQ_Init(&frame_draw, 3); - MQ_Init(&frame_empty, 3); - - MQ_Send(frame_empty, frameBuffer[0], MQ_MSG_BLOCK); - MQ_Send(frame_empty, frameBuffer[1], MQ_MSG_BLOCK); - frame = frameBuffer[2]; - - if(CONF_GetAspectRatio() == CONF_ASPECT_16_9) { - screenMode->viWidth = 678; - } else { - screenMode->viWidth = 672; - } - - if(VIDEO_GetCurrentTvMode() == VI_PAL) { - // screenMode->viHeight = VI_MAX_HEIGHT_PAL; - screenMode->viXOrigin = (VI_MAX_WIDTH_PAL - screenMode->viWidth) / 2; - screenMode->viYOrigin = (VI_MAX_HEIGHT_PAL - screenMode->viHeight) / 2; - } else { - // screenMode->viHeight = VI_MAX_HEIGHT_NTSC; - screenMode->viXOrigin = (VI_MAX_WIDTH_NTSC - screenMode->viWidth) / 2; - screenMode->viYOrigin = (VI_MAX_HEIGHT_NTSC - screenMode->viHeight) / 2; - } - - s8 hoffset = 0; - CONF_GetDisplayOffsetH(&hoffset); - screenMode->viXOrigin += hoffset; - - VIDEO_Configure(screenMode); - VIDEO_SetNextFramebuffer(frameBuffer[0]); - VIDEO_SetPreRetraceCallback(copy_buffers); - VIDEO_SetBlack(false); - VIDEO_Flush(); - - fifoBuffer = MEM_K0_TO_K1(memalign(32, FIFO_SIZE)); - memset(fifoBuffer, 0, FIFO_SIZE); - - GX_Init(fifoBuffer, FIFO_SIZE); - gfx_clear_buffers(255, 255, 255); - GX_SetViewport(0, 0, screenMode->fbWidth, screenMode->efbHeight, 0, 1); - GX_SetDispCopyYScale( - GX_GetYScaleFactor(screenMode->efbHeight, screenMode->xfbHeight)); - GX_SetScissor(0, 0, screenMode->fbWidth, screenMode->efbHeight); - GX_SetDispCopySrc(0, 0, screenMode->fbWidth, screenMode->efbHeight); - GX_SetDispCopyDst(screenMode->fbWidth, screenMode->xfbHeight); - GX_SetCopyFilter(screenMode->aa, screenMode->sample_pattern, GX_TRUE, - screenMode->vfilter); - GX_SetFieldMode(screenMode->field_rendering, - ((screenMode->viHeight == 2 * screenMode->xfbHeight) ? - GX_ENABLE : - GX_DISABLE)); - - GX_SetCullMode(GX_CULL_BACK); - GX_CopyDisp(frameBuffer[0], GX_TRUE); - GX_SetDispCopyGamma(GX_GM_1_0); - - GX_InvalidateTexAll(); - GX_ClearVtxDesc(); - GX_SetVtxDesc(GX_VA_POS, GX_DIRECT); - GX_SetVtxDesc(GX_VA_CLR0, GX_INDEX8); - GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT); - - // blocks - GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_S16, 8); - GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGB, GX_RGB8, 0); - GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_U8, 8); - - // font drawing - GX_SetVtxAttrFmt(GX_VTXFMT1, GX_VA_POS, GX_POS_XYZ, GX_S16, 0); - GX_SetVtxAttrFmt(GX_VTXFMT1, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0); - GX_SetVtxAttrFmt(GX_VTXFMT1, GX_VA_TEX0, GX_TEX_ST, GX_U8, 7); - - // gui - GX_SetVtxAttrFmt(GX_VTXFMT2, GX_VA_POS, GX_POS_XYZ, GX_S16, 0); - GX_SetVtxAttrFmt(GX_VTXFMT2, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0); - GX_SetVtxAttrFmt(GX_VTXFMT2, GX_VA_TEX0, GX_TEX_ST, GX_U16, 8); - - // blocks etc with direct color - GX_SetVtxAttrFmt(GX_VTXFMT3, GX_VA_POS, GX_POS_XYZ, GX_S16, 8); - GX_SetVtxAttrFmt(GX_VTXFMT3, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0); - GX_SetVtxAttrFmt(GX_VTXFMT3, GX_VA_TEX0, GX_TEX_ST, GX_U8, 8); - - GX_SetArray(GX_VA_CLR0, colors, 3 * sizeof(uint8_t)); - GX_SetNumChans(1); - GX_SetNumTexGens(1); - GX_SetNumTevStages(1); - gfx_bind_texture(TEXTURE_TERRAIN); - gfx_texture(true); - gfx_alpha_test(true); - - gfx_load_textures(); - - GX_SetTexCoordGen(GX_TEXCOORD1, GX_TG_MTX2x4, GX_TG_POS, GX_TEXMTX1); - - // gfx_update_light(1.0F); - - GX_DrawDone(); -} - -void gfx_update_light(float daytime, const float* light_lookup) { - assert(daytime > -GLM_FLT_EPSILON && daytime < 1.0F + GLM_FLT_EPSILON - && light_lookup); - - for(int sky = 0; sky < 16; sky++) { - for(int torch = 0; torch < 16; torch++) { - uint8_t gray - = roundf(fmaxf(light_lookup[torch], light_lookup[sky] * daytime) - * 255.0F); - colors[(torch * 16 + sky) * 3 + 0] = gray; - colors[(torch * 16 + sky) * 3 + 1] = gray; - colors[(torch * 16 + sky) * 3 + 2] = gray; - } - } - - DCStoreRange(colors, sizeof(colors)); - GX_InvVtxCache(); -} - -void gfx_clear_buffers(uint8_t r, uint8_t g, uint8_t b) { - GX_SetCopyClear((GXColor) {r, g, b, 255}, 0x00FFFFFF); -} - -void gfx_finish(bool vsync) { - assert(frame); - - GX_SetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE); - GX_SetColorUpdate(GX_TRUE); - GX_CopyDisp(frame, GX_TRUE); - GX_SetDrawDone(); - - if(!vsync) { - GX_WaitDrawDone(); - VIDEO_SetNextFramebuffer(frame); - VIDEO_Flush(); - } -} - -void gfx_flip_buffers(float* gpu_wait, float* vsync_wait) { - assert(frame); - - ptime_t gpu_wait_start = time_get(); - GX_WaitDrawDone(); - ptime_t gpu_wait_end = time_get(); - - MQ_Send(frame_draw, frame, MQ_MSG_BLOCK); - MQ_Receive(frame_empty, &frame, MQ_MSG_BLOCK); - - if(vsync_wait) - *vsync_wait = time_diff_s(gpu_wait_end, time_get()); - if(gpu_wait) - *gpu_wait = time_diff_s(gpu_wait_start, gpu_wait_end); -} - -void gfx_bind_texture(enum gfx_texture tex) { - switch(tex) { - case TEXTURE_TERRAIN: - GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0); - break; - case TEXTURE_FONT: - GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP1, GX_COLOR0A0); - break; - case TEXTURE_ANIM: - GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP2, GX_COLOR0A0); - break; - case TEXTURE_GUI: - GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP3, GX_COLOR0A0); - break; - case TEXTURE_GUI2: - GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP4, GX_COLOR0A0); - break; - case TEXTURE_ITEMS: - GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP5, GX_COLOR0A0); - break; - } -} - -void gfx_mode_world() { - gfx_write_buffers(true, true, true); -} - -void gfx_mode_gui() { - gfx_fog(false); - - Mtx44 projection; - - guOrtho(projection, 0, gfx_height(), 0, gfx_width(), 0, 256); - GX_LoadProjectionMtx(projection, GX_ORTHOGRAPHIC); - gfx_matrix_modelview(GLM_MAT4_IDENTITY); - - gfx_lighting(false); - gfx_blending(MODE_BLEND); - gfx_alpha_test(true); - gfx_write_buffers(true, false, false); -} - -void gfx_matrix_projection(mat4 proj, bool is_perspective) { - assert(proj); - - mat4 convert; - glm_translate_make(convert, (vec3) {0, 0, -1}); - convert[3][3] = 2.0F; - glm_mat4_mul(convert, proj, convert); - glm_mat4_transpose(convert); - - GX_LoadProjectionMtx(convert, - is_perspective ? GX_PERSPECTIVE : GX_ORTHOGRAPHIC); -} - -void gfx_matrix_modelview(mat4 mv) { - assert(mv); - - mat4 convert; - glm_mat4_transpose_to(mv, convert); - GX_LoadPosMtxImm(convert, GX_PNMTX0); -} - -void gfx_matrix_texture(bool enable, mat4 tex) { - if(enable) { - assert(tex); - - mat4 convert; - glm_mat4_transpose_to(tex, convert); - GX_LoadTexMtxImm(convert, GX_TEXMTX0, GX_MTX2x4); - } - - if(enable != gfx_matrix_texture_prev) - GX_SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, - enable ? GX_TEXMTX0 : GX_IDENTITY); - gfx_matrix_texture_prev = enable; -} - -void gfx_fog_color(uint8_t r, uint8_t g, uint8_t b) { - GX_SetTevColor(GX_TEVREG0, (GXColor) {r, g, b, 255}); -} - -void gfx_fog_pos(float dx, float dz, float distance) { - assert(distance > 0); - - if(gfx_fog_prev) { - float dist = 1.0F / (distance * 2.0F); - GX_LoadTexMtxImm((mat4) {{dist, 0, 0, dx * dist + 0.5F}, - {0, 0, dist, dz * dist + 0.5F}, - {0, 0, 0, 0}, - {0, 0, 0, 1}}, - GX_TEXMTX1, GX_MTX2x4); - } -} - -void gfx_fog(bool enable) { - if(enable != gfx_fog_prev) { - GX_SetNumTexGens(enable ? 2 : 1); - GX_SetNumTevStages(enable ? 2 : 1); - - if(enable) { - GX_SetTevOp(GX_TEVSTAGE1, GX_DECAL); - GX_SetTevOrder(GX_TEVSTAGE1, GX_TEXCOORD1, GX_TEXMAP7, GX_COLOR0A0); - GX_SetTevColorIn(GX_TEVSTAGE1, GX_CC_CPREV, GX_CC_C0, GX_CC_TEXA, - GX_CC_ZERO); - } - } - - gfx_fog_prev = enable; -} - -void gfx_blending(enum gfx_blend mode) { - switch(mode) { - case MODE_BLEND: - GX_SetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, - GX_LO_NOOP); - break; - case MODE_BLEND2: - GX_SetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_ONE, GX_LO_NOOP); - break; - case MODE_INVERT: - GX_SetBlendMode(GX_BM_LOGIC, GX_BL_ZERO, GX_BL_ZERO, GX_LO_INV); - break; - case MODE_OFF: - GX_SetBlendMode(GX_BM_NONE, GX_BL_ONE, GX_BL_ZERO, GX_LO_NOOP); - break; - } -} - -void gfx_alpha_test(bool enable) { - if(enable) { - GX_SetAlphaCompare(GX_GEQUAL, 16, GX_AOP_AND, GX_ALWAYS, 0); - GX_SetZCompLoc(GX_FALSE); - } else { - GX_SetAlphaCompare(GX_ALWAYS, 0, GX_AOP_OR, GX_ALWAYS, 0); - GX_SetZCompLoc(GX_TRUE); - } -} - -void gfx_write_buffers(bool color, bool depth, bool depth_test) { - GX_SetColorUpdate(color ? GX_TRUE : GX_FALSE); - GX_SetZMode(depth_test ? GX_TRUE : GX_FALSE, GX_LEQUAL, - depth ? GX_TRUE : GX_FALSE); -} - -void gfx_texture(bool enable) { - GX_SetTevOp(GX_TEVSTAGE0, enable ? GX_MODULATE : GX_PASSCLR); -} - -void gfx_lighting(bool enable) { - GX_SetVtxDesc(GX_VA_CLR0, enable ? GX_INDEX8 : GX_DIRECT); -} - -void gfx_culling(bool enable) { - GX_SetCullMode(enable ? GX_CULL_BACK : GX_CULL_NONE); -} - -void gfx_scissor(bool enable, uint32_t x, uint32_t y, uint32_t width, - uint32_t height) { - if(enable) { - GX_SetScissor(x, y, width, height); - } else { - GX_SetScissor(0, 0, 0x3FF, 0x3FF); - } -} +#ifdef PLATFORM_PC +#include "pc/gfx.c" +#endif diff --git a/source/platform/graphics/gfx.h b/source/platform/graphics/gfx.h index 057e0b2..184a1c1 100644 --- a/source/platform/graphics/gfx.h +++ b/source/platform/graphics/gfx.h @@ -62,10 +62,15 @@ void gfx_fog(bool enable); void gfx_blending(enum gfx_blend mode); void gfx_alpha_test(bool enable); void gfx_write_buffers(bool color, bool depth, bool depth_test); +void gfx_depth_range(float near, float far); void gfx_texture(bool enable); void gfx_lighting(bool enable); void gfx_culling(bool enable); void gfx_scissor(bool enable, uint32_t x, uint32_t y, uint32_t width, uint32_t height); +void gfx_draw_lines(size_t vertex_count, const int16_t* vertices, + const uint8_t* colors); +void gfx_draw_quads(size_t vertex_count, const int16_t* vertices, + const uint8_t* colors, const uint16_t* texcoords); #endif diff --git a/source/platform/graphics/gfx_util.c b/source/platform/graphics/gfx_util.c index ec606da..939446e 100644 --- a/source/platform/graphics/gfx_util.c +++ b/source/platform/graphics/gfx_util.c @@ -1,5 +1,5 @@ /* - Copyright (c) 2022 ByteBit/xtreme8000 + Copyright (c) 2023 ByteBit/xtreme8000 This file is part of CavEX. @@ -18,7 +18,6 @@ */ #include -#include #include "../../game/game_state.h" #include "gfx.h" @@ -43,35 +42,26 @@ void gutil_sky_box(mat4 view_matrix, float celestial_angle, vec3 color_top, gfx_fog_pos(0, 0, gstate.config.fog_distance); // render a bit larger for possible inaccuracy - int16_t size = (gstate.config.fog_distance + 4) * 256; + float size = gstate.config.fog_distance + 4; - GX_Begin(GX_QUADS, GX_VTXFMT3, 8); - GX_Position3s16(-size, 16 * 256, -size); - GX_Color4u8(color_top[0], color_top[1], color_top[2], 255); - GX_TexCoord2u8(0, 0); - GX_Position3s16(-size, 16 * 256, size); - GX_Color4u8(color_top[0], color_top[1], color_top[2], 255); - GX_TexCoord2u8(0, 0); - GX_Position3s16(size, 16 * 256, size); - GX_Color4u8(color_top[0], color_top[1], color_top[2], 255); - GX_TexCoord2u8(0, 0); - GX_Position3s16(size, 16 * 256, -size); - GX_Color4u8(color_top[0], color_top[1], color_top[2], 255); - GX_TexCoord2u8(0, 0); + gfx_draw_quads(4, + (int16_t[]) {-size, 16, -size, -size, 16, size, size, 16, + size, size, 16, -size}, + (uint8_t[]) {color_top[0], color_top[1], color_top[2], 0xFF, + color_top[0], color_top[1], color_top[2], 0xFF, + color_top[0], color_top[1], color_top[2], 0xFF, + color_top[0], color_top[1], color_top[2], 0xFF}, + (uint16_t[]) {0, 0, 0, 0, 0, 0, 0, 0}); - GX_Position3s16(-size, -32 * 256, -size); - GX_Color4u8(color_bottom[0], color_bottom[1], color_bottom[2], 255); - GX_TexCoord2u8(0, 0); - GX_Position3s16(size, -32 * 256, -size); - GX_Color4u8(color_bottom[0], color_bottom[1], color_bottom[2], 255); - GX_TexCoord2u8(0, 0); - GX_Position3s16(size, -32 * 256, size); - GX_Color4u8(color_bottom[0], color_bottom[1], color_bottom[2], 255); - GX_TexCoord2u8(0, 0); - GX_Position3s16(-size, -32 * 256, size); - GX_Color4u8(color_bottom[0], color_bottom[1], color_bottom[2], 255); - GX_TexCoord2u8(0, 0); - GX_End(); + gfx_draw_quads( + 4, + (int16_t[]) {-size, -32, -size, size, -32, -size, size, -32, size, + -size, -32, size}, + (uint8_t[]) {color_bottom[0], color_bottom[1], color_bottom[2], 0xFF, + color_bottom[0], color_bottom[1], color_bottom[2], 0xFF, + color_bottom[0], color_bottom[1], color_bottom[2], 0xFF, + color_bottom[0], color_bottom[1], color_bottom[2], 0xFF}, + (uint16_t[]) {0, 0, 0, 0, 0, 0, 0, 0}); gfx_fog(false); gfx_texture(true); @@ -85,36 +75,23 @@ void gutil_sky_box(mat4 view_matrix, float celestial_angle, vec3 color_top, glm_rotate_x(tmp, glm_rad(celestial_angle * 360.0F), model_view); gfx_matrix_modelview(model_view); - GX_Begin(GX_QUADS, GX_VTXFMT3, 8); - GX_Position3s16(-30 * 256, 100 * 256, -30 * 256); - GX_Color4u8(255, 255, 255, 255); - GX_TexCoord2u8(201, 65); - GX_Position3s16(-30 * 256, 100 * 256, 30 * 256); - GX_Color4u8(255, 255, 255, 255); - GX_TexCoord2u8(201, 65 + 32); - GX_Position3s16(30 * 256, 100 * 256, 30 * 256); - GX_Color4u8(255, 255, 255, 255); - GX_TexCoord2u8(201 + 32, 65 + 32); - GX_Position3s16(30 * 256, 100 * 256, -30 * 256); - GX_Color4u8(255, 255, 255, 255); - GX_TexCoord2u8(201 + 32, 65); + gfx_draw_quads( + 4, (int16_t[]) {-30, 100, -30, -30, 100, 30, 30, 100, 30, 30, 100, -30}, + (uint8_t[]) {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, + (uint16_t[]) {201, 65, 201, 65 + 32, 201 + 32, 65 + 32, 201 + 32, 65}); - GX_Position3s16(-20 * 256, -100 * 256, -20 * 256); - GX_Color4u8(255, 255, 255, 255); - GX_TexCoord2u8(201, 32); - GX_Position3s16(20 * 256, -100 * 256, -20 * 256); - GX_Color4u8(255, 255, 255, 255); - GX_TexCoord2u8(201 + 32, 32); - GX_Position3s16(20 * 256, -100 * 256, 20 * 256); - GX_Color4u8(255, 255, 255, 255); - GX_TexCoord2u8(201 + 32, 32 + 32); - GX_Position3s16(-20 * 256, -100 * 256, 20 * 256); - GX_Color4u8(255, 255, 255, 255); - GX_TexCoord2u8(201, 32 + 32); - GX_End(); + gfx_draw_quads( + 4, + (int16_t[]) {-20, -100, -20, 20, -100, -20, 20, -100, 20, -20, -100, + 20}, + (uint8_t[]) {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, + (uint16_t[]) {201, 32, 201, 32 + 32, 201 + 32, 32 + 32, 201 + 32, 32}); gfx_blending(MODE_OFF); gfx_write_buffers(true, true, true); + gfx_alpha_test(true); } void gutil_block_selection(mat4 view_matrix, struct block_info* this) { @@ -137,117 +114,53 @@ void gutil_block_selection(mat4 view_matrix, struct block_info* this) { model_view); gfx_matrix_modelview(model_view); - GX_Begin(GX_LINES, GX_VTXFMT3, 24); + gfx_draw_lines( + 24, + (int16_t[]) { + // bottom + -pad + box.x1 * 256, -pad + box.y1 * 256, -pad + box.z1 * 256, + box.x2 * 256 + pad, -pad + box.y1 * 256, -pad + box.z1 * 256, - // bottom - GX_Position3s16(-pad + box.x1 * 256, -pad + box.y1 * 256, - -pad + box.z1 * 256); - GX_Color4u8(0, 0, 0, 153); - GX_TexCoord2u8(0, 0); - GX_Position3s16(box.x2 * 256 + pad, -pad + box.y1 * 256, - -pad + box.z1 * 256); - GX_Color4u8(0, 0, 0, 153); - GX_TexCoord2u8(0, 0); + -pad + box.x1 * 256, -pad + box.y1 * 256, -pad + box.z1 * 256, + -pad + box.x1 * 256, -pad + box.y1 * 256, box.z2 * 256 + pad, - GX_Position3s16(-pad + box.x1 * 256, -pad + box.y1 * 256, - -pad + box.z1 * 256); - GX_Color4u8(0, 0, 0, 153); - GX_TexCoord2u8(0, 0); - GX_Position3s16(-pad + box.x1 * 256, -pad + box.y1 * 256, - box.z2 * 256 + pad); - GX_Color4u8(0, 0, 0, 153); - GX_TexCoord2u8(0, 0); + box.x2 * 256 + pad, -pad + box.y1 * 256, box.z2 * 256 + pad, + box.x2 * 256 + pad, -pad + box.y1 * 256, -pad + box.z1 * 256, - GX_Position3s16(box.x2 * 256 + pad, -pad + box.y1 * 256, - box.z2 * 256 + pad); - GX_Color4u8(0, 0, 0, 153); - GX_TexCoord2u8(0, 0); - GX_Position3s16(box.x2 * 256 + pad, -pad + box.y1 * 256, - -pad + box.z1 * 256); - GX_Color4u8(0, 0, 0, 153); - GX_TexCoord2u8(0, 0); + box.x2 * 256 + pad, -pad + box.y1 * 256, box.z2 * 256 + pad, + -pad + box.x1 * 256, -pad + box.y1 * 256, box.z2 * 256 + pad, - GX_Position3s16(box.x2 * 256 + pad, -pad + box.y1 * 256, - box.z2 * 256 + pad); - GX_Color4u8(0, 0, 0, 153); - GX_TexCoord2u8(0, 0); - GX_Position3s16(-pad + box.x1 * 256, -pad + box.y1 * 256, - box.z2 * 256 + pad); - GX_Color4u8(0, 0, 0, 153); - GX_TexCoord2u8(0, 0); + // top + -pad + box.x1 * 256, box.y2 * 256 + pad, -pad + box.z1 * 256, + box.x2 * 256 + pad, box.y2 * 256 + pad, -pad + box.z1 * 256, - // top - GX_Position3s16(-pad + box.x1 * 256, box.y2 * 256 + pad, - -pad + box.z1 * 256); - GX_Color4u8(0, 0, 0, 153); - GX_TexCoord2u8(0, 0); - GX_Position3s16(box.x2 * 256 + pad, box.y2 * 256 + pad, - -pad + box.z1 * 256); - GX_Color4u8(0, 0, 0, 153); - GX_TexCoord2u8(0, 0); + -pad + box.x1 * 256, box.y2 * 256 + pad, -pad + box.z1 * 256, + -pad + box.x1 * 256, box.y2 * 256 + pad, box.z2 * 256 + pad, - GX_Position3s16(-pad + box.x1 * 256, box.y2 * 256 + pad, - -pad + box.z1 * 256); - GX_Color4u8(0, 0, 0, 153); - GX_TexCoord2u8(0, 0); - GX_Position3s16(-pad + box.x1 * 256, box.y2 * 256 + pad, - box.z2 * 256 + pad); - GX_Color4u8(0, 0, 0, 153); - GX_TexCoord2u8(0, 0); + box.x2 * 256 + pad, box.y2 * 256 + pad, box.z2 * 256 + pad, + box.x2 * 256 + pad, box.y2 * 256 + pad, -pad + box.z1 * 256, - GX_Position3s16(box.x2 * 256 + pad, box.y2 * 256 + pad, box.z2 * 256 + pad); - GX_Color4u8(0, 0, 0, 153); - GX_TexCoord2u8(0, 0); - GX_Position3s16(box.x2 * 256 + pad, box.y2 * 256 + pad, - -pad + box.z1 * 256); - GX_Color4u8(0, 0, 0, 153); - GX_TexCoord2u8(0, 0); + box.x2 * 256 + pad, box.y2 * 256 + pad, box.z2 * 256 + pad, + -pad + box.x1 * 256, box.y2 * 256 + pad, box.z2 * 256 + pad, - GX_Position3s16(box.x2 * 256 + pad, box.y2 * 256 + pad, box.z2 * 256 + pad); - GX_Color4u8(0, 0, 0, 153); - GX_TexCoord2u8(0, 0); - GX_Position3s16(-pad + box.x1 * 256, box.y2 * 256 + pad, - box.z2 * 256 + pad); - GX_Color4u8(0, 0, 0, 153); - GX_TexCoord2u8(0, 0); + // vertical + -pad + box.x1 * 256, -pad + box.y1 * 256, -pad + box.z1 * 256, + -pad + box.x1 * 256, box.y2 * 256 + pad, -pad + box.z1 * 256, - // vertical - GX_Position3s16(-pad + box.x1 * 256, -pad + box.y1 * 256, - -pad + box.z1 * 256); - GX_Color4u8(0, 0, 0, 153); - GX_TexCoord2u8(0, 0); - GX_Position3s16(-pad + box.x1 * 256, box.y2 * 256 + pad, - -pad + box.z1 * 256); - GX_Color4u8(0, 0, 0, 153); - GX_TexCoord2u8(0, 0); + box.x2 * 256 + pad, -pad + box.y1 * 256, -pad + box.z1 * 256, + box.x2 * 256 + pad, box.y2 * 256 + pad, -pad + box.z1 * 256, - GX_Position3s16(box.x2 * 256 + pad, -pad + box.y1 * 256, - -pad + box.z1 * 256); - GX_Color4u8(0, 0, 0, 153); - GX_TexCoord2u8(0, 0); - GX_Position3s16(box.x2 * 256 + pad, box.y2 * 256 + pad, - -pad + box.z1 * 256); - GX_Color4u8(0, 0, 0, 153); - GX_TexCoord2u8(0, 0); + -pad + box.x1 * 256, -pad + box.y1 * 256, box.z2 * 256 + pad, + -pad + box.x1 * 256, box.y2 * 256 + pad, box.z2 * 256 + pad, - GX_Position3s16(-pad + box.x1 * 256, -pad + box.y1 * 256, - box.z2 * 256 + pad); - GX_Color4u8(0, 0, 0, 153); - GX_TexCoord2u8(0, 0); - GX_Position3s16(-pad + box.x1 * 256, box.y2 * 256 + pad, - box.z2 * 256 + pad); - GX_Color4u8(0, 0, 0, 153); - GX_TexCoord2u8(0, 0); - - GX_Position3s16(box.x2 * 256 + pad, -pad + box.y1 * 256, - box.z2 * 256 + pad); - GX_Color4u8(0, 0, 0, 153); - GX_TexCoord2u8(0, 0); - GX_Position3s16(box.x2 * 256 + pad, box.y2 * 256 + pad, box.z2 * 256 + pad); - GX_Color4u8(0, 0, 0, 153); - GX_TexCoord2u8(0, 0); - - GX_End(); + box.x2 * 256 + pad, -pad + box.y1 * 256, box.z2 * 256 + pad, + box.x2 * 256 + pad, box.y2 * 256 + pad, box.z2 * 256 + pad}, + (uint8_t[]) {0, 0, 0, 153, 0, 0, 0, 153, 0, 0, 0, 153, 0, 0, 0, 153, + 0, 0, 0, 153, 0, 0, 0, 153, 0, 0, 0, 153, 0, 0, 0, 153, + 0, 0, 0, 153, 0, 0, 0, 153, 0, 0, 0, 153, 0, 0, 0, 153, + 0, 0, 0, 153, 0, 0, 0, 153, 0, 0, 0, 153, 0, 0, 0, 153, + 0, 0, 0, 153, 0, 0, 0, 153, 0, 0, 0, 153, 0, 0, 0, 153, + 0, 0, 0, 153, 0, 0, 0, 153, 0, 0, 0, 153, 0, 0, 0, 153}); gfx_texture(true); gfx_lighting(true); diff --git a/source/platform/graphics/gui_util.c b/source/platform/graphics/gui_util.c index c322e76..89d713e 100644 --- a/source/platform/graphics/gui_util.c +++ b/source/platform/graphics/gui_util.c @@ -1,5 +1,5 @@ /* - Copyright (c) 2022 ByteBit/xtreme8000 + Copyright (c) 2023 ByteBit/xtreme8000 This file is part of CavEX. @@ -17,7 +17,6 @@ along with CavEX. If not, see . */ -#include #include #include "gfx.h" @@ -38,20 +37,12 @@ int gutil_control_icon(int x, enum gutil_control_icon icon, char* str) { void gutil_texquad_col(int x, int y, int tx, int ty, int sx, int sy, int width, int height, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - GX_Begin(GX_QUADS, GX_VTXFMT2, 4); - GX_Position3s16(x, y, -2); - GX_Color4u8(r, g, b, a); - GX_TexCoord2u16(tx, ty); - GX_Position3s16(x + width, y, -2); - GX_Color4u8(r, g, b, a); - GX_TexCoord2u16(tx + sx, ty); - GX_Position3s16(x + width, y + height, -2); - GX_Color4u8(r, g, b, a); - GX_TexCoord2u16(tx + sx, ty + sy); - GX_Position3s16(x, y + height, -2); - GX_Color4u8(r, g, b, a); - GX_TexCoord2u16(tx, ty + sy); - GX_End(); + gfx_draw_quads( + 4, + (int16_t[]) {x, y, -2, x + width, y, -2, x + width, y + height, -2, x, + y + height, -2}, + (uint8_t[]) {r, g, b, a, r, g, b, a, r, g, b, a, r, g, b, a}, + (uint16_t[]) {tx, ty, tx + sx, ty, tx + sx, ty + sy, tx, ty + sy}); } void gutil_texquad(int x, int y, int tx, int ty, int sx, int sy, int width, @@ -62,20 +53,13 @@ void gutil_texquad(int x, int y, int tx, int ty, int sx, int sy, int width, void gutil_texquad_rt(int x, int y, int tx, int ty, int sx, int sy, int width, int height) { - GX_Begin(GX_QUADS, GX_VTXFMT2, 4); - GX_Position3s16(x, y, -2); - GX_Color4u8(0xFF, 0xFF, 0xFF, 0xFF); - GX_TexCoord2u16(tx, ty + sy); - GX_Position3s16(x + width, y, -2); - GX_Color4u8(0xFF, 0xFF, 0xFF, 0xFF); - GX_TexCoord2u16(tx, ty); - GX_Position3s16(x + width, y + height, -2); - GX_Color4u8(0xFF, 0xFF, 0xFF, 0xFF); - GX_TexCoord2u16(tx + sx, ty); - GX_Position3s16(x, y + height, -2); - GX_Color4u8(0xFF, 0xFF, 0xFF, 0xFF); - GX_TexCoord2u16(tx + sx, ty + sy); - GX_End(); + gfx_draw_quads( + 4, + (int16_t[]) {x, y, -2, x + width, y, -2, x + width, y + height, -2, x, + y + height, -2}, + (uint8_t[]) {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, + (uint16_t[]) {tx, ty + sy, tx, ty, tx + sx, ty, tx + sx, ty + sy}); } void gutil_bg() { @@ -85,24 +69,12 @@ void gutil_bg() { int cx = (gfx_width() + scale - 1) / scale; int cy = (gfx_height() + scale - 1) / scale; - GX_Begin(GX_QUADS, GX_VTXFMT2, 4 * cx * cy); for(int y = 0; y < cy; y++) { for(int x = 0; x < cx; x++) { - GX_Position3s16(x * scale, y * scale, -9); - GX_Color4u8(0x40, 0x40, 0x40, 0xFF); - GX_TexCoord2u16(39, 3); - GX_Position3s16(x * scale + scale, y * scale, -9); - GX_Color4u8(0x40, 0x40, 0x40, 0xFF); - GX_TexCoord2u16(55, 3); - GX_Position3s16(x * scale + scale, y * scale + scale, -9); - GX_Color4u8(0x40, 0x40, 0x40, 0xFF); - GX_TexCoord2u16(55, 19); - GX_Position3s16(x * scale, y * scale + scale, -9); - GX_Color4u8(0x40, 0x40, 0x40, 0xFF); - GX_TexCoord2u16(39, 19); + gutil_texquad_col(x * scale, y * scale, 39, 3, 16, 16, scale, scale, + 0x40, 0x40, 0x40, 0xFF); } } - GX_End(); } static const uint8_t font_char_width[256] = { @@ -127,42 +99,48 @@ int gutil_font_width(char* str, int scale) { void gutil_text(int x, int y, char* str, int scale) { gfx_bind_texture(TEXTURE_FONT); - GX_Begin(GX_QUADS, GX_VTXFMT1, strlen(str) * 4 * 2); while(*str) { - uint8_t tex_x = *str % 16 * 8; - uint8_t tex_y = *str / 16 * 8; + uint8_t tex_x = *str % 16 * 16; + uint8_t tex_y = *str / 16 * 16; uint8_t width = (font_char_width[(int)*str] + 1) * scale / 8; - GX_Position3s16(x + scale / 8, y + scale / 8, -2); - GX_Color4u8(0x80, 0x80, 0x80, 0xFF); - GX_TexCoord2u8(tex_x, tex_y); - GX_Position3s16(x + scale + scale / 8, y + scale / 8, -2); - GX_Color4u8(0x80, 0x80, 0x80, 0xFF); - GX_TexCoord2u8(tex_x + 8, tex_y); - GX_Position3s16(x + scale + scale / 8, y + scale + scale / 8, -2); - GX_Color4u8(0x80, 0x80, 0x80, 0xFF); - GX_TexCoord2u8(tex_x + 8, tex_y + 8); - GX_Position3s16(x + scale / 8, y + scale + scale / 8, -2); - GX_Color4u8(0x80, 0x80, 0x80, 0xFF); - GX_TexCoord2u8(tex_x, tex_y + 8); - - GX_Position3s16(x, y, -1); - GX_Color4u8(0xFF, 0xFF, 0xFF, 0xFF); - GX_TexCoord2u8(tex_x, tex_y); - GX_Position3s16(x + scale, y, -1); - GX_Color4u8(0xFF, 0xFF, 0xFF, 0xFF); - GX_TexCoord2u8(tex_x + 8, tex_y); - GX_Position3s16(x + scale, y + scale, -1); - GX_Color4u8(0xFF, 0xFF, 0xFF, 0xFF); - GX_TexCoord2u8(tex_x + 8, tex_y + 8); - GX_Position3s16(x, y + scale, -1); - GX_Color4u8(0xFF, 0xFF, 0xFF, 0xFF); - GX_TexCoord2u8(tex_x, tex_y + 8); + gfx_draw_quads( + 8, + (int16_t[]) {x + scale / 8, + y + scale / 8, + -2, + x + scale + scale / 8, + y + scale / 8, + -2, + x + scale + scale / 8, + y + scale + scale / 8, + -2, + x + scale / 8, + y + scale + scale / 8, + -2, + x, + y, + -1, + x + scale, + y, + -1, + x + scale, + y + scale, + -1, + x, + y + scale, + -1}, + (uint8_t[]) {0x80, 0x80, 0x80, 0xFF, 0x80, 0x80, 0x80, 0xFF, + 0x80, 0x80, 0x80, 0xFF, 0x80, 0x80, 0x80, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, + (uint16_t[]) {tex_x, tex_y, tex_x + 16, tex_y, tex_x + 16, + tex_y + 16, tex_x, tex_y + 16, tex_x, tex_y, + tex_x + 16, tex_y, tex_x + 16, tex_y + 16, tex_x, + tex_y + 16}); x += width; str++; } - - GX_End(); } diff --git a/source/platform/graphics/pc/displaylist.c b/source/platform/graphics/pc/displaylist.c new file mode 100644 index 0000000..1c5f25b --- /dev/null +++ b/source/platform/graphics/pc/displaylist.c @@ -0,0 +1,148 @@ +/* + Copyright (c) 2022 ByteBit/xtreme8000 + + This file is part of CavEX. + + CavEX is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + CavEX is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with CavEX. If not, see . +*/ + +#include +#include +#include +#include + +#include "../displaylist.h" + +#define MEM_U8(b, i) (*((uint8_t*)(b) + (i))) +#define MEM_U16(b, i) (*(uint16_t*)((uint8_t*)(b) + (i))) +#define MEM_I16(b, i) (*(int16_t*)((uint8_t*)(b) + (i))) +#define MEM_FLT(b, i) (*(float*)((uint8_t*)(b) + (i))) + +void displaylist_init(struct displaylist* l, size_t vertices, + size_t vertex_size) { + assert(l && vertices > 0 && vertex_size > 0); + + l->length = 4096; + l->data = NULL; + l->index = 0; + l->finished = false; +} + +void displaylist_destroy(struct displaylist* l) { + assert(l); + + if(l->data) + free(l->data); + + if(l->finished) + glDeleteBuffers(1, &l->vbo); +} + +void displaylist_reset(struct displaylist* l) { + assert(l && !l->finished); + l->index = 0; +} + +void displaylist_finalize(struct displaylist* l, uint16_t vtxcnt) { + assert(l && !l->finished && l->data); + + l->index = vtxcnt; +} + +void displaylist_pos(struct displaylist* l, int16_t x, int16_t y, int16_t z) { + assert(l && !l->finished); + + if(!l->data) { + l->data = malloc(l->length); + assert(l->data); + } + + if(l->index + 22 > l->length) { + l->length *= 2; + l->data = realloc(l->data, l->length); + assert(l->data); + } + + MEM_FLT(l->data, l->index) = (float)x / 256.0F; + l->index += 4; + MEM_FLT(l->data, l->index) = (float)y / 256.0F; + l->index += 4; + MEM_FLT(l->data, l->index) = (float)z / 256.0F; + l->index += 4; +} + +void displaylist_color(struct displaylist* l, uint8_t index) { + assert(l && !l->finished && l->data); + + MEM_U8(l->data, l->index++) = index % 16; + MEM_U8(l->data, l->index++) = index / 16; +} + +void displaylist_texcoord(struct displaylist* l, uint8_t s, uint8_t t) { + assert(l && !l->finished && l->data); + MEM_FLT(l->data, l->index) = (float)s / 256.0F; + l->index += 4; + MEM_FLT(l->data, l->index) = (float)t / 256.0F; + l->index += 4; +} + +void displaylist_render(struct displaylist* l) { + assert(l); + + if(!l->finished) { + l->finished = true; + + glGenBuffers(1, &l->vbo); + glBindBuffer(GL_ARRAY_BUFFER, l->vbo); + glBufferData(GL_ARRAY_BUFFER, l->index * 22, l->data, GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + } + + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(3); + glEnableVertexAttribArray(2); + + glBindBuffer(GL_ARRAY_BUFFER, l->vbo); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 22, NULL); + glVertexAttribPointer(3, 2, GL_UNSIGNED_BYTE, GL_FALSE, 22, + (uint8_t*)(3 * sizeof(float))); + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 22, + (uint8_t*)(2 + 3 * sizeof(float))); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + glDrawArrays(GL_QUADS, 0, l->index); + + glDisableVertexAttribArray(0); + glDisableVertexAttribArray(3); + glDisableVertexAttribArray(2); +} + +void displaylist_render_immediate(struct displaylist* l, uint16_t vtxcnt) { + assert(l && l->data && !l->finished); + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(3); + glEnableVertexAttribArray(2); + + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 22, l->data); + glVertexAttribPointer(3, 2, GL_UNSIGNED_BYTE, GL_FALSE, 22, + (uint8_t*)l->data + 3 * sizeof(float)); + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 22, + (uint8_t*)l->data + 2 + 3 * sizeof(float)); + + glDrawArrays(GL_QUADS, 0, vtxcnt); + + glDisableVertexAttribArray(0); + glDisableVertexAttribArray(3); + glDisableVertexAttribArray(2); +} diff --git a/source/platform/graphics/pc/gfx.c b/source/platform/graphics/pc/gfx.c new file mode 100644 index 0000000..d69f298 --- /dev/null +++ b/source/platform/graphics/pc/gfx.c @@ -0,0 +1,469 @@ +/* + Copyright (c) 2022 ByteBit/xtreme8000 + + This file is part of CavEX. + + CavEX is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + CavEX is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with CavEX. If not, see . +*/ + +#include +#include +#include +#include +#include +#include + +#include "../../../game/game_state.h" +#include "../../../lodepng/lodepng.h" +#include "../../../util.h" +#include "../../input.h" +#include "../gfx.h" + +static GLuint textures[8]; + +static GLuint load_tex(const char* filename, bool nearest) { + unsigned width, height; + unsigned char* img; + if(lodepng_decode32_file(&img, &width, &height, filename)) + printf("error loading texture %s\n", filename); + + GLuint tex; + glGenTextures(1, &tex); + glBindTexture(GL_TEXTURE_2D, tex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, + GL_UNSIGNED_BYTE, img); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + nearest ? GL_NEAREST : GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, + nearest ? GL_NEAREST : GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glBindTexture(GL_TEXTURE_2D, 0); + + free(img); + + return tex; +} + +static void gfx_load_textures() { + textures[0] = load_tex("terrain.png", true); + textures[1] = load_tex("default.png", true); + textures[2] = load_tex("anim.png", true); + textures[3] = load_tex("gui.png", true); + textures[4] = load_tex("gui_2.png", true); + textures[5] = load_tex("items.png", true); +} + +static void testtest(GLuint shader) { + GLint isCompiled = 0; + glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled); + if(isCompiled == GL_FALSE) { + GLint maxLength = 0; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength); + + // The maxLength includes the NULL character + char log[maxLength]; + glGetShaderInfoLog(shader, maxLength, &maxLength, log); + printf("%s\n", log); + + // Provide the infolog in whatever manor you deem best. + // Exit with failure. + glDeleteShader(shader); // Don't leak the shader. + } +} + +static GLuint create_shader(const char* vertex, const char* fragment) { + GLuint v = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(v, 1, (const GLchar* const*)&vertex, NULL); + glCompileShader(v); + testtest(v); + + GLuint f = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(f, 1, (const GLchar* const*)&fragment, NULL); + glCompileShader(f); + testtest(f); + + GLuint program = glCreateProgram(); + glAttachShader(program, v); + glAttachShader(program, f); + + glBindAttribLocation(program, 0, "a_pos"); + glBindAttribLocation(program, 1, "a_color"); + glBindAttribLocation(program, 2, "a_texcoord"); + glBindAttribLocation(program, 3, "a_light"); + + glLinkProgram(program); + return program; +} + +static int window_width = 854; +static int window_height = 480; +GLFWwindow* window; + +int gfx_width() { + return window_width; +} + +int gfx_height() { + return window_height; +} + +static enum input_button glfw_key_translate(int key) { + switch(key) { + case GLFW_KEY_W: return IB_FORWARD; + case GLFW_KEY_S: return IB_BACKWARD; + case GLFW_KEY_A: return IB_LEFT; + case GLFW_KEY_D: return IB_RIGHT; + case GLFW_KEY_SPACE: return IB_JUMP; + case GLFW_KEY_LEFT_SHIFT: return IB_INVENTORY; + case GLFW_KEY_ENTER: return IB_HOME; + default: return IB_MAX; + } +} + +static enum input_button glfw_button_translate(int key) { + switch(key) { + case GLFW_MOUSE_BUTTON_LEFT: return IB_ACTION1; + case GLFW_MOUSE_BUTTON_RIGHT: return IB_ACTION2; + default: return IB_MAX; + } +} + +static double last_mouse_x = 0, last_mouse_y = 0; + +static void framebuffer_size_callback(GLFWwindow* window, int width, + int height) { + window_width = width; + window_height = height; + glViewport(0, 0, gfx_width(), gfx_height()); +} + +static void key_callback(GLFWwindow* window, int key, int scancode, int action, + int mods) { + if(glfw_key_translate(key) != IB_MAX) + input_set_status(glfw_key_translate(key), action != GLFW_RELEASE); + + if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) { + if(glfwGetInputMode(window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED) { + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); + } else { + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + } + } +} + +static void scroll_callback(GLFWwindow* window, double xoffset, + double yoffset) { + // TODO: buttons are not released + if(glfwGetInputMode(window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED) { + if(yoffset > 0) { + input_set_status(IB_SCROLL_LEFT, GLFW_PRESS); + } else if(yoffset < 0) { + input_set_status(IB_SCROLL_RIGHT, GLFW_PRESS); + } + } +} + +static void mouse_button_callback(GLFWwindow* window, int button, int action, + int mods) { + if(glfwGetInputMode(window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED + && glfw_button_translate(button) != IB_MAX) + input_set_status(glfw_button_translate(button), action != GLFW_RELEASE); +} + +static GLuint shader_prog; + +void gfx_setup() { + glfwInit(); + + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); + window + = glfwCreateWindow(window_width, window_height, GAME_NAME, NULL, NULL); + glfwMakeContextCurrent(window); + + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + glfwSetKeyCallback(window, key_callback); + glfwSetScrollCallback(window, scroll_callback); + glfwSetMouseButtonCallback(window, mouse_button_callback); + + if(glfwRawMouseMotionSupported()) + glfwSetInputMode(window, GLFW_RAW_MOUSE_MOTION, GLFW_TRUE); + + if(glewInit()) + printf("Could not load extended OpenGL functions!\n"); + + printf("Vendor: %s\n", glGetString(GL_VENDOR)); + printf("Renderer: %s\n", glGetString(GL_RENDERER)); + printf("Version: %s\n", glGetString(GL_VERSION)); + + void* vertex = file_read("vertex.shader"); + assert(vertex); + void* fragment = file_read("fragment.shader"); + assert(fragment); + + shader_prog = create_shader(vertex, fragment); + free(vertex); + free(fragment); + glUseProgram(shader_prog); + + gfx_clear_buffers(255, 255, 255); + gfx_bind_texture(TEXTURE_TERRAIN); + gfx_texture(true); + gfx_alpha_test(true); + + glCullFace(GL_BACK); + glFrontFace(GL_CW); + gfx_culling(true); + + glDepthFunc(GL_LEQUAL); + + glViewport(0, 0, gfx_width(), gfx_height()); + + gfx_load_textures(); + + glUniform1i(glGetUniformLocation(shader_prog, "tex"), 0); +} + +void gfx_update_light(float daytime, const float* light_lookup) { + assert(daytime > -GLM_FLT_EPSILON && daytime < 1.0F + GLM_FLT_EPSILON + && light_lookup); + + float colors[256]; + + for(int sky = 0; sky < 16; sky++) { + for(int torch = 0; torch < 16; torch++) { + colors[torch * 16 + sky] + = fmaxf(light_lookup[torch], light_lookup[sky] * daytime); + } + } + + glUniform1fv(glGetUniformLocation(shader_prog, "lighting"), 256, colors); +} + +void gfx_clear_buffers(uint8_t r, uint8_t g, uint8_t b) { + glClearColor(r / 255.0F, g / 255.0F, b / 255.0F, 1.0F); +} + +void gfx_finish(bool vsync) { + glfwSwapBuffers(window); + gfx_write_buffers(true, true, true); + glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + glfwPollEvents(); + + double xpos, ypos; + glfwGetCursorPos(window, &xpos, &ypos); + + if(glfwGetInputMode(window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED) { + input_set_joystick((xpos - last_mouse_x) * 0.001F, + -(ypos - last_mouse_y) * 0.001F); + + } else { + input_set_joystick(0, 0); + } + + last_mouse_x = xpos; + last_mouse_y = ypos; +} + +void gfx_flip_buffers(float* gpu_wait, float* vsync_wait) { + *gpu_wait = 0; + *vsync_wait = 0; +} + +void gfx_bind_texture(enum gfx_texture tex) { + switch(tex) { + case TEXTURE_TERRAIN: glBindTexture(GL_TEXTURE_2D, textures[0]); break; + case TEXTURE_FONT: glBindTexture(GL_TEXTURE_2D, textures[1]); break; + case TEXTURE_ANIM: glBindTexture(GL_TEXTURE_2D, textures[2]); break; + case TEXTURE_GUI: glBindTexture(GL_TEXTURE_2D, textures[3]); break; + case TEXTURE_GUI2: glBindTexture(GL_TEXTURE_2D, textures[4]); break; + case TEXTURE_ITEMS: glBindTexture(GL_TEXTURE_2D, textures[5]); break; + } +} + +void gfx_mode_world() { + gfx_write_buffers(true, true, true); + gfx_matrix_texture(false, NULL); +} + +void gfx_mode_gui() { + gfx_fog(false); + + mat4 proj; + glm_ortho(0, gfx_width(), gfx_height(), 0, -256, 256, proj); + gfx_matrix_projection(proj, false); + gfx_matrix_modelview(GLM_MAT4_IDENTITY); + + gfx_lighting(false); + gfx_blending(MODE_BLEND); + gfx_alpha_test(true); + gfx_write_buffers(true, false, false); +} + +void gfx_matrix_projection(mat4 proj, bool is_perspective) { + assert(proj); + glUniformMatrix4fv(glGetUniformLocation(shader_prog, "proj"), 1, GL_FALSE, + (float*)proj); +} + +void gfx_matrix_modelview(mat4 mv) { + assert(mv); + glUniformMatrix4fv(glGetUniformLocation(shader_prog, "mv"), 1, GL_FALSE, + (float*)mv); +} + +void gfx_matrix_texture(bool enable, mat4 tex) { + if(enable) { + assert(tex); + glUniformMatrix4fv(glGetUniformLocation(shader_prog, "texm"), 1, + GL_FALSE, (float*)tex); + } else { + glUniformMatrix4fv(glGetUniformLocation(shader_prog, "texm"), 1, + GL_FALSE, (float*)GLM_MAT4_IDENTITY); + } +} + +void gfx_fog_color(uint8_t r, uint8_t g, uint8_t b) { + glUniform3f(glGetUniformLocation(shader_prog, "fog_color"), r / 255.0F, + g / 255.0F, b / 255.0F); +} + +void gfx_fog_pos(float dx, float dz, float distance) { + assert(distance > 0); + + glUniform2f(glGetUniformLocation(shader_prog, "fog_delta"), dx, dz); + glUniform1f(glGetUniformLocation(shader_prog, "fog_distance"), distance); +} + +void gfx_fog(bool enable) { + glUniform1i(glGetUniformLocation(shader_prog, "enable_fog"), enable); +} + +void gfx_blending(enum gfx_blend mode) { + switch(mode) { + case MODE_BLEND: + glDisable(GL_COLOR_LOGIC_OP); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + break; + case MODE_BLEND2: + glDisable(GL_COLOR_LOGIC_OP); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + break; + case MODE_INVERT: + glDisable(GL_BLEND); + glEnable(GL_COLOR_LOGIC_OP); + glLogicOp(GL_INVERT); + break; + case MODE_OFF: + glDisable(GL_COLOR_LOGIC_OP); + glDisable(GL_BLEND); + break; + } +} + +void gfx_alpha_test(bool enable) { + glUniform1i(glGetUniformLocation(shader_prog, "enable_alpha"), enable); +} + +void gfx_write_buffers(bool color, bool depth, bool depth_test) { + glColorMask(color, color, color, color); + glDepthMask(depth); + + if(depth_test) { + glEnable(GL_DEPTH_TEST); + } else { + glDisable(GL_DEPTH_TEST); + } +} + +void gfx_depth_range(float near, float far) { + glDepthRange(near, far); +} + +void gfx_texture(bool enable) { + glUniform1i(glGetUniformLocation(shader_prog, "enable_texture"), enable); +} + +void gfx_lighting(bool enable) { + glUniform1i(glGetUniformLocation(shader_prog, "enable_lighting"), enable); +} + +void gfx_culling(bool enable) { + if(enable) { + glEnable(GL_CULL_FACE); + } else { + glDisable(GL_CULL_FACE); + } +} + +void gfx_scissor(bool enable, uint32_t x, uint32_t y, uint32_t width, + uint32_t height) { + if(enable) { + glEnable(GL_SCISSOR_TEST); + glScissor(x, y, width, height); + } else { + glDisable(GL_SCISSOR_TEST); + } +} + +void gfx_draw_lines(size_t vertex_count, const int16_t* vertices, + const uint8_t* colors) { + assert(vertices && colors); + glLineWidth(2.0F); + + assert(vertex_count < 256); + + float tmp[vertex_count * 3]; + for(size_t k = 0; k < vertex_count * 3; k++) + tmp[k] = vertices[k] / 256.0F; + + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); + + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, tmp); + glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, colors); + + glDrawArrays(GL_LINES, 0, vertex_count); + + glDisableVertexAttribArray(0); + glDisableVertexAttribArray(1); +} + +void gfx_draw_quads(size_t vertex_count, const int16_t* vertices, + const uint8_t* colors, const uint16_t* texcoords) { + assert(vertices && colors && texcoords); + + assert(vertex_count < 256); + + float tmp[vertex_count * 3]; + for(size_t k = 0; k < vertex_count * 3; k++) + tmp[k] = texcoords[k] / 256.0F; + + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); + glEnableVertexAttribArray(2); + + glVertexAttribPointer(0, 3, GL_SHORT, GL_FALSE, 0, vertices); + glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, colors); + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, tmp); + + glDrawArrays(GL_QUADS, 0, vertex_count); + + glDisableVertexAttribArray(0); + glDisableVertexAttribArray(1); + glDisableVertexAttribArray(2); +} diff --git a/source/platform/graphics/render_block.c b/source/platform/graphics/render_block.c index 0d2a8b6..16a02ad 100644 --- a/source/platform/graphics/render_block.c +++ b/source/platform/graphics/render_block.c @@ -17,7 +17,6 @@ along with CavEX. If not, see . */ -#include #include #include "../../block/blocks.h" diff --git a/source/platform/graphics/render_block.h b/source/platform/graphics/render_block.h index cb413ab..f3e7cbf 100644 --- a/source/platform/graphics/render_block.h +++ b/source/platform/graphics/render_block.h @@ -20,7 +20,6 @@ #ifndef RENDER_BLOCK_H #define RENDER_BLOCK_H -#include #include #include diff --git a/source/platform/graphics/render_item.c b/source/platform/graphics/render_item.c index 0444dcf..a684cb7 100644 --- a/source/platform/graphics/render_item.c +++ b/source/platform/graphics/render_item.c @@ -208,8 +208,7 @@ void render_item_flat(struct item* item, struct item_data* stack, mat4 model, gfx_matrix_modelview(model); gfx_lighting(true); gfx_write_buffers(true, true, true); - displaylist_render_immediate(&dl, GX_QUADS, GX_VTXFMT0, - (2 + 16 * 4) * 4); + displaylist_render_immediate(&dl, (2 + 16 * 4) * 4); gfx_write_buffers(true, false, false); gfx_lighting(false); } @@ -278,7 +277,7 @@ void render_item_block(struct item* item, struct item_data* stack, mat4 model, if(inventory) { mat4 view; - glm_translate_make(view, (vec3) {3 * 2, 3 * 2, -128}); + glm_translate_make(view, (vec3) {3 * 2, 3 * 2, -16}); glm_scale(view, (vec3) {20, 20, -20}); glm_translate(view, (vec3) {0.5F, 0.5F, 0.5F}); glm_rotate_z(view, glm_rad(180.0F), view); @@ -302,7 +301,7 @@ void render_item_block(struct item* item, struct item_data* stack, mat4 model, gfx_bind_texture(b->transparent ? TEXTURE_ANIM : TEXTURE_TERRAIN); gfx_lighting(true); gfx_write_buffers(true, true, true); - displaylist_render_immediate(&dl, GX_QUADS, GX_VTXFMT0, vertices * 4); + displaylist_render_immediate(&dl, vertices * 4); gfx_matrix_modelview(GLM_MAT4_IDENTITY); gfx_write_buffers(true, false, false); gfx_lighting(false); diff --git a/source/platform/graphics/wii/displaylist.c b/source/platform/graphics/wii/displaylist.c new file mode 100644 index 0000000..7ce7939 --- /dev/null +++ b/source/platform/graphics/wii/displaylist.c @@ -0,0 +1,131 @@ +/* + Copyright (c) 2022 ByteBit/xtreme8000 + + This file is part of CavEX. + + CavEX is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + CavEX is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with CavEX. If not, see . +*/ + +#include +#include +#include +#include + +#include "../displaylist.h" + +#define GX_NOP 0 +#define DISPLAYLIST_CLL 32 +#define DISPLAYLIST_CACHE_LINES(v, s) \ + (((v) * (s) + 3 + DISPLAYLIST_CLL - 1) / DISPLAYLIST_CLL * DISPLAYLIST_CLL) + +#define MEM_U8(b, i) (*((uint8_t*)(b) + (i))) +#define MEM_U16(b, i) (*(uint16_t*)((uint8_t*)(b) + (i))) +#define MEM_I16(b, i) (*(int16_t*)((uint8_t*)(b) + (i))) + +void displaylist_init(struct displaylist* l, size_t vertices, + size_t vertex_size) { + assert(l && vertices > 0 && vertex_size > 0); + + l->length = DISPLAYLIST_CACHE_LINES(vertices, vertex_size); + l->data = NULL; + /* has 32 byte padding of GX_NOP in front for possible misalignment caused + * by realloc */ + l->index = DISPLAYLIST_CLL + 3; + l->finished = false; +} + +void displaylist_destroy(struct displaylist* l) { + assert(l); + + if(l->data) + free(l->data); +} + +void displaylist_reset(struct displaylist* l) { + assert(l && !l->finished); + l->index = DISPLAYLIST_CLL + 3; +} + +void displaylist_finalize(struct displaylist* l, uint16_t vtxcnt) { + assert(l && !l->finished && l->data); + + MEM_U8(l->data, DISPLAYLIST_CLL) = GX_QUADS | (GX_VTXFMT0 & 7); + MEM_U16(l->data, DISPLAYLIST_CLL + 1) = vtxcnt; + + memset(l->data, GX_NOP, DISPLAYLIST_CLL); + memset((uint8_t*)l->data + l->index, GX_NOP, + l->length + DISPLAYLIST_CLL - l->index); + DCStoreRange(l->data, l->length + DISPLAYLIST_CLL); + l->finished = true; +} + +void displaylist_pos(struct displaylist* l, int16_t x, int16_t y, int16_t z) { + assert(l && !l->finished); + + if(!l->data) { + l->data = malloc(l->length + DISPLAYLIST_CLL); + assert(l->data); + } + + if(l->index + 9 > l->length) { + l->length = (l->length * 5 / 4 + 9 + DISPLAYLIST_CLL - 1) + / DISPLAYLIST_CLL * DISPLAYLIST_CLL; + l->data = realloc(l->data, l->length + DISPLAYLIST_CLL); + assert(l->data); + } + + MEM_U16(l->data, l->index) = x; + l->index += 2; + MEM_U16(l->data, l->index) = y; + l->index += 2; + MEM_U16(l->data, l->index) = z; + l->index += 2; +} + +void displaylist_color(struct displaylist* l, uint8_t index) { + assert(l && !l->finished && l->data); + MEM_U8(l->data, l->index++) = index; +} + +void displaylist_texcoord(struct displaylist* l, uint8_t s, uint8_t t) { + assert(l && !l->finished && l->data); + MEM_U8(l->data, l->index++) = s; + MEM_U8(l->data, l->index++) = t; +} + +void displaylist_render(struct displaylist* l) { + assert(l); + + if(l->finished) + GX_CallDispList( + (uint8_t*)l->data + + (DISPLAYLIST_CLL - (uintptr_t)l->data % DISPLAYLIST_CLL), + (l->index + (uintptr_t)l->data % DISPLAYLIST_CLL - 1) + / DISPLAYLIST_CLL * DISPLAYLIST_CLL); +} + +void displaylist_render_immediate(struct displaylist* l, uint16_t vtxcnt) { + assert(l && l->data); + + uint8_t* base = (uint8_t*)l->data + DISPLAYLIST_CLL + 3; + + GX_Begin(GX_QUADS, GX_VTXFMT0, vtxcnt); + for(uint16_t k = 0; k < vtxcnt; k++) { + GX_Position3s16(MEM_U16(base, 0), MEM_U16(base, 2), MEM_U16(base, 4)); + GX_Color1x8(MEM_U8(base, 6)); + GX_TexCoord2u8(MEM_U8(base, 7), MEM_U8(base, 8)); + base += 9; + } + GX_End(); +} diff --git a/source/platform/graphics/wii/gfx.c b/source/platform/graphics/wii/gfx.c new file mode 100644 index 0000000..85747b7 --- /dev/null +++ b/source/platform/graphics/wii/gfx.c @@ -0,0 +1,488 @@ +/* + Copyright (c) 2022 ByteBit/xtreme8000 + + This file is part of CavEX. + + CavEX is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + CavEX is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with CavEX. If not, see . +*/ + +#include +#include +#include +#include +#include +#include + +#include "../../../util.h" +#include "../gfx.h" + +#include "textures.h" +#include "textures_tpl.h" + +#define FIFO_SIZE (256 * 1024) + +static GXRModeObj* screenMode; // TODO: rename +static void* frameBuffer[3]; +static mqmsg_t frame = NULL; +static mqbox_t frame_draw; +static mqbox_t frame_empty; +static void* fifoBuffer = NULL; +static uint8_t colors[256 * 3] ATTRIBUTE_ALIGN(32); + +static bool gfx_matrix_texture_prev = false; +static bool gfx_fog_prev = false; + +/*static void* thread_vsync(void* user) { + void* current_frame = NULL; + + while(1) { + mqmsg_t input_frame; + MQ_Receive(frame_draw, &input_frame, MQ_MSG_BLOCK); + + VIDEO_SetNextFramebuffer(input_frame); + VIDEO_Flush(); + + if(current_frame) + MQ_Send(frame_empty, current_frame, MQ_MSG_BLOCK); + + current_frame = input_frame; + + VIDEO_WaitVSync(); + } + + return NULL; +}*/ + +static volatile mqmsg_t current_frame = NULL; + +static void copy_buffers(u32 cnt) { + mqmsg_t input_frame; + + if(MQ_Receive(frame_draw, &input_frame, MQ_MSG_NOBLOCK)) { + VIDEO_SetNextFramebuffer(input_frame); + VIDEO_Flush(); + + if(current_frame) + MQ_Send(frame_empty, current_frame, MQ_MSG_BLOCK); + + current_frame = input_frame; + } +} + +static void gfx_load_textures() { + GXTexObj terrain, font, anim, gui, gui2, items, fog; + TPLFile spriteTPL; + TPL_OpenTPLFromMemory(&spriteTPL, (void*)textures_tpl, textures_tpl_size); + TPL_GetTexture(&spriteTPL, texture_terrain, &terrain); + GX_InitTexObjFilterMode(&terrain, GX_NEAR, GX_NEAR); + GX_InitTexObjMaxAniso(&terrain, GX_ANISO_1); + GX_LoadTexObj(&terrain, GX_TEXMAP0); + + TPL_GetTexture(&spriteTPL, texture_font, &font); + GX_InitTexObjFilterMode(&font, GX_NEAR, GX_NEAR); + GX_InitTexObjMaxAniso(&font, GX_ANISO_1); + GX_LoadTexObj(&font, GX_TEXMAP1); + + TPL_GetTexture(&spriteTPL, texture_anim, &anim); + GX_InitTexObjFilterMode(&anim, GX_NEAR, GX_NEAR); + GX_InitTexObjMaxAniso(&anim, GX_ANISO_1); + GX_LoadTexObj(&anim, GX_TEXMAP2); + + TPL_GetTexture(&spriteTPL, texture_gui, &gui); + GX_InitTexObjFilterMode(&gui, GX_NEAR, GX_NEAR); + GX_InitTexObjMaxAniso(&gui, GX_ANISO_1); + GX_LoadTexObj(&gui, GX_TEXMAP3); + + TPL_GetTexture(&spriteTPL, texture_gui2, &gui2); + GX_InitTexObjFilterMode(&gui2, GX_NEAR, GX_NEAR); + GX_InitTexObjMaxAniso(&gui2, GX_ANISO_1); + GX_LoadTexObj(&gui2, GX_TEXMAP4); + + TPL_GetTexture(&spriteTPL, texture_items, &items); + GX_InitTexObjFilterMode(&items, GX_NEAR, GX_NEAR); + GX_InitTexObjMaxAniso(&items, GX_ANISO_1); + GX_LoadTexObj(&items, GX_TEXMAP5); + + TPL_GetTexture(&spriteTPL, texture_fog, &fog); + GX_InitTexObjFilterMode(&fog, GX_LINEAR, GX_LINEAR); + GX_InitTexObjMaxAniso(&fog, GX_ANISO_1); + GX_InitTexObjWrapMode(&fog, GX_CLAMP, GX_CLAMP); + GX_LoadTexObj(&fog, GX_TEXMAP7); + + TPL_CloseTPLFile(&spriteTPL); +} + +int gfx_width() { + return 802; +} + +int gfx_height() { + return 480; +} + +void gfx_setup() { + VIDEO_Init(); + screenMode = VIDEO_GetPreferredMode(NULL); + frameBuffer[0] = MEM_K0_TO_K1(SYS_AllocateFramebuffer(screenMode)); + frameBuffer[1] = MEM_K0_TO_K1(SYS_AllocateFramebuffer(screenMode)); + frameBuffer[2] = MEM_K0_TO_K1(SYS_AllocateFramebuffer(screenMode)); + + MQ_Init(&frame_draw, 3); + MQ_Init(&frame_empty, 3); + + MQ_Send(frame_empty, frameBuffer[0], MQ_MSG_BLOCK); + MQ_Send(frame_empty, frameBuffer[1], MQ_MSG_BLOCK); + frame = frameBuffer[2]; + + if(CONF_GetAspectRatio() == CONF_ASPECT_16_9) { + screenMode->viWidth = 678; + } else { + screenMode->viWidth = 672; + } + + if(VIDEO_GetCurrentTvMode() == VI_PAL) { + // screenMode->viHeight = VI_MAX_HEIGHT_PAL; + screenMode->viXOrigin = (VI_MAX_WIDTH_PAL - screenMode->viWidth) / 2; + screenMode->viYOrigin = (VI_MAX_HEIGHT_PAL - screenMode->viHeight) / 2; + } else { + // screenMode->viHeight = VI_MAX_HEIGHT_NTSC; + screenMode->viXOrigin = (VI_MAX_WIDTH_NTSC - screenMode->viWidth) / 2; + screenMode->viYOrigin = (VI_MAX_HEIGHT_NTSC - screenMode->viHeight) / 2; + } + + s8 hoffset = 0; + CONF_GetDisplayOffsetH(&hoffset); + screenMode->viXOrigin += hoffset; + + VIDEO_Configure(screenMode); + VIDEO_SetNextFramebuffer(frameBuffer[0]); + VIDEO_SetPreRetraceCallback(copy_buffers); + VIDEO_SetBlack(false); + VIDEO_Flush(); + + fifoBuffer = MEM_K0_TO_K1(memalign(32, FIFO_SIZE)); + memset(fifoBuffer, 0, FIFO_SIZE); + + GX_Init(fifoBuffer, FIFO_SIZE); + gfx_clear_buffers(255, 255, 255); + GX_SetViewport(0, 0, screenMode->fbWidth, screenMode->efbHeight, 0, 1); + GX_SetDispCopyYScale( + GX_GetYScaleFactor(screenMode->efbHeight, screenMode->xfbHeight)); + GX_SetScissor(0, 0, screenMode->fbWidth, screenMode->efbHeight); + GX_SetDispCopySrc(0, 0, screenMode->fbWidth, screenMode->efbHeight); + GX_SetDispCopyDst(screenMode->fbWidth, screenMode->xfbHeight); + GX_SetCopyFilter(screenMode->aa, screenMode->sample_pattern, GX_TRUE, + screenMode->vfilter); + GX_SetFieldMode(screenMode->field_rendering, + ((screenMode->viHeight == 2 * screenMode->xfbHeight) ? + GX_ENABLE : + GX_DISABLE)); + + GX_SetCullMode(GX_CULL_BACK); + GX_CopyDisp(frameBuffer[0], GX_TRUE); + GX_SetDispCopyGamma(GX_GM_1_0); + + GX_InvalidateTexAll(); + GX_ClearVtxDesc(); + GX_SetVtxDesc(GX_VA_POS, GX_DIRECT); + GX_SetVtxDesc(GX_VA_CLR0, GX_INDEX8); + GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT); + + // blocks + GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_S16, 8); + GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGB, GX_RGB8, 0); + GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_U8, 8); + + // gui, font drawing + GX_SetVtxAttrFmt(GX_VTXFMT2, GX_VA_POS, GX_POS_XYZ, GX_S16, 0); + GX_SetVtxAttrFmt(GX_VTXFMT2, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0); + GX_SetVtxAttrFmt(GX_VTXFMT2, GX_VA_TEX0, GX_TEX_ST, GX_U16, 8); + + // blocks etc with direct color + GX_SetVtxAttrFmt(GX_VTXFMT3, GX_VA_POS, GX_POS_XYZ, GX_S16, 8); + GX_SetVtxAttrFmt(GX_VTXFMT3, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0); + GX_SetVtxAttrFmt(GX_VTXFMT3, GX_VA_TEX0, GX_TEX_ST, GX_U8, 8); + + GX_SetArray(GX_VA_CLR0, colors, 3 * sizeof(uint8_t)); + GX_SetNumChans(1); + GX_SetNumTexGens(1); + GX_SetNumTevStages(1); + gfx_bind_texture(TEXTURE_TERRAIN); + gfx_texture(true); + gfx_alpha_test(true); + + gfx_load_textures(); + + GX_SetTexCoordGen(GX_TEXCOORD1, GX_TG_MTX2x4, GX_TG_POS, GX_TEXMTX1); + + GX_DrawDone(); +} + +void gfx_update_light(float daytime, const float* light_lookup) { + assert(daytime > -GLM_FLT_EPSILON && daytime < 1.0F + GLM_FLT_EPSILON + && light_lookup); + + for(int sky = 0; sky < 16; sky++) { + for(int torch = 0; torch < 16; torch++) { + uint8_t gray + = roundf(fmaxf(light_lookup[torch], light_lookup[sky] * daytime) + * 255.0F); + colors[(torch * 16 + sky) * 3 + 0] = gray; + colors[(torch * 16 + sky) * 3 + 1] = gray; + colors[(torch * 16 + sky) * 3 + 2] = gray; + } + } + + DCStoreRange(colors, sizeof(colors)); + GX_InvVtxCache(); +} + +void gfx_clear_buffers(uint8_t r, uint8_t g, uint8_t b) { + GX_SetCopyClear((GXColor) {r, g, b, 255}, GX_MAX_Z24); +} + +void gfx_finish(bool vsync) { + assert(frame); + + GX_SetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE); + GX_SetColorUpdate(GX_TRUE); + GX_CopyDisp(frame, GX_TRUE); + GX_SetDrawDone(); + + if(!vsync) { + GX_WaitDrawDone(); + VIDEO_SetNextFramebuffer(frame); + VIDEO_Flush(); + } +} + +void gfx_flip_buffers(float* gpu_wait, float* vsync_wait) { + assert(frame); + + ptime_t gpu_wait_start = time_get(); + GX_WaitDrawDone(); + ptime_t gpu_wait_end = time_get(); + + MQ_Send(frame_draw, frame, MQ_MSG_BLOCK); + MQ_Receive(frame_empty, &frame, MQ_MSG_BLOCK); + + if(vsync_wait) + *vsync_wait = time_diff_s(gpu_wait_end, time_get()); + if(gpu_wait) + *gpu_wait = time_diff_s(gpu_wait_start, gpu_wait_end); +} + +void gfx_bind_texture(enum gfx_texture tex) { + switch(tex) { + case TEXTURE_TERRAIN: + GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0); + break; + case TEXTURE_FONT: + GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP1, GX_COLOR0A0); + break; + case TEXTURE_ANIM: + GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP2, GX_COLOR0A0); + break; + case TEXTURE_GUI: + GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP3, GX_COLOR0A0); + break; + case TEXTURE_GUI2: + GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP4, GX_COLOR0A0); + break; + case TEXTURE_ITEMS: + GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP5, GX_COLOR0A0); + break; + } +} + +void gfx_mode_world() { + gfx_write_buffers(true, true, true); +} + +void gfx_mode_gui() { + gfx_fog(false); + + Mtx44 projection; + + guOrtho(projection, 0, gfx_height(), 0, gfx_width(), 0, 256); + GX_LoadProjectionMtx(projection, GX_ORTHOGRAPHIC); + gfx_matrix_modelview(GLM_MAT4_IDENTITY); + + gfx_lighting(false); + gfx_blending(MODE_BLEND); + gfx_alpha_test(true); + gfx_write_buffers(true, false, false); +} + +void gfx_matrix_projection(mat4 proj, bool is_perspective) { + assert(proj); + + mat4 convert; + glm_translate_make(convert, (vec3) {0, 0, -1}); + convert[3][3] = 2.0F; + glm_mat4_mul(convert, proj, convert); + glm_mat4_transpose(convert); + + GX_LoadProjectionMtx(convert, + is_perspective ? GX_PERSPECTIVE : GX_ORTHOGRAPHIC); +} + +void gfx_matrix_modelview(mat4 mv) { + assert(mv); + + mat4 convert; + glm_mat4_transpose_to(mv, convert); + GX_LoadPosMtxImm(convert, GX_PNMTX0); +} + +void gfx_matrix_texture(bool enable, mat4 tex) { + if(enable) { + assert(tex); + + mat4 convert; + glm_mat4_transpose_to(tex, convert); + GX_LoadTexMtxImm(convert, GX_TEXMTX0, GX_MTX2x4); + } + + if(enable != gfx_matrix_texture_prev) + GX_SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, + enable ? GX_TEXMTX0 : GX_IDENTITY); + gfx_matrix_texture_prev = enable; +} + +void gfx_fog_color(uint8_t r, uint8_t g, uint8_t b) { + GX_SetTevColor(GX_TEVREG0, (GXColor) {r, g, b, 255}); +} + +void gfx_fog_pos(float dx, float dz, float distance) { + assert(distance > 0); + + if(gfx_fog_prev) { + float dist = 1.0F / (distance * 2.0F); + GX_LoadTexMtxImm((mat4) {{dist, 0, 0, dx * dist + 0.5F}, + {0, 0, dist, dz * dist + 0.5F}, + {0, 0, 0, 0}, + {0, 0, 0, 1}}, + GX_TEXMTX1, GX_MTX2x4); + } +} + +void gfx_fog(bool enable) { + if(enable != gfx_fog_prev) { + GX_SetNumTexGens(enable ? 2 : 1); + GX_SetNumTevStages(enable ? 2 : 1); + + if(enable) { + GX_SetTevOp(GX_TEVSTAGE1, GX_DECAL); + GX_SetTevOrder(GX_TEVSTAGE1, GX_TEXCOORD1, GX_TEXMAP7, GX_COLOR0A0); + GX_SetTevColorIn(GX_TEVSTAGE1, GX_CC_CPREV, GX_CC_C0, GX_CC_TEXA, + GX_CC_ZERO); + } + } + + gfx_fog_prev = enable; +} + +void gfx_blending(enum gfx_blend mode) { + switch(mode) { + case MODE_BLEND: + GX_SetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, + GX_LO_NOOP); + break; + case MODE_BLEND2: + GX_SetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_ONE, GX_LO_NOOP); + break; + case MODE_INVERT: + GX_SetBlendMode(GX_BM_LOGIC, GX_BL_ZERO, GX_BL_ZERO, GX_LO_INV); + break; + case MODE_OFF: + GX_SetBlendMode(GX_BM_NONE, GX_BL_ONE, GX_BL_ZERO, GX_LO_NOOP); + break; + } +} + +void gfx_alpha_test(bool enable) { + if(enable) { + GX_SetAlphaCompare(GX_GEQUAL, 16, GX_AOP_AND, GX_ALWAYS, 0); + GX_SetZCompLoc(GX_FALSE); + } else { + GX_SetAlphaCompare(GX_ALWAYS, 0, GX_AOP_OR, GX_ALWAYS, 0); + GX_SetZCompLoc(GX_TRUE); + } +} + +void gfx_write_buffers(bool color, bool depth, bool depth_test) { + GX_SetColorUpdate(color ? GX_TRUE : GX_FALSE); + GX_SetZMode(depth_test ? GX_TRUE : GX_FALSE, GX_LEQUAL, + depth ? GX_TRUE : GX_FALSE); +} + +void gfx_depth_range(float near, float far) { + GX_SetViewport(0, 0, screenMode->fbWidth, screenMode->efbHeight, near, far); +} + +void gfx_texture(bool enable) { + GX_SetTevOp(GX_TEVSTAGE0, enable ? GX_MODULATE : GX_PASSCLR); +} + +void gfx_lighting(bool enable) { + GX_SetVtxDesc(GX_VA_CLR0, enable ? GX_INDEX8 : GX_DIRECT); +} + +void gfx_culling(bool enable) { + GX_SetCullMode(enable ? GX_CULL_BACK : GX_CULL_NONE); +} + +void gfx_scissor(bool enable, uint32_t x, uint32_t y, uint32_t width, + uint32_t height) { + if(enable) { + GX_SetScissor(x, y, width, height); + } else { + GX_SetScissor(0, 0, 0x3FF, 0x3FF); + } +} + +void gfx_draw_lines(size_t vertex_count, const int16_t* vertices, + const uint8_t* colors) { + assert(vertices && colors); + + GX_Begin(GX_LINES, GX_VTXFMT3, vertex_count); + + for(size_t k = 0; k < vertex_count; k++) { + GX_Position3s16(vertices[k * 3 + 0], vertices[k * 3 + 1], + vertices[k * 3 + 2]); + GX_Color4u8(colors[k * 4 + 0], colors[k * 4 + 1], colors[k * 4 + 2], + colors[k * 4 + 3]); + GX_TexCoord2u8(0, 0); + } + + GX_End(); +} + +void gfx_draw_quads(size_t vertex_count, const int16_t* vertices, + const uint8_t* colors, const uint16_t* texcoords) { + assert(vertices && colors && texcoords); + + GX_Begin(GX_QUADS, GX_VTXFMT2, vertex_count); + + for(size_t k = 0; k < vertex_count; k++) { + GX_Position3s16(vertices[k * 3 + 0], vertices[k * 3 + 1], + vertices[k * 3 + 2]); + GX_Color4u8(colors[k * 4 + 0], colors[k * 4 + 1], colors[k * 4 + 2], + colors[k * 4 + 3]); + GX_TexCoord2u16(texcoords[k * 2 + 0], texcoords[k * 2 + 1]); + } + + GX_End(); +} diff --git a/source/platform/input.c b/source/platform/input.c index 006fb62..42b78c0 100644 --- a/source/platform/input.c +++ b/source/platform/input.c @@ -18,11 +18,72 @@ */ #include -#include #include "../cglm/cglm.h" #include "input.h" +#ifdef PLATFORM_PC + +#include + +extern GLFWwindow* window; + +static bool input_key_held[IB_MAX]; +static bool input_key_pressed[IB_MAX]; +static bool input_key_released[IB_MAX]; +static float joystick_x = 0, joystick_y = 0; + +void input_init() { + for(size_t k = 0; k < IB_MAX; k++) { + input_key_held[k] = false; + input_key_pressed[k] = false; + input_key_released[k] = false; + } +} + +void input_poll() { + for(size_t k = 0; k < IB_MAX; k++) { + input_key_pressed[k] = false; + input_key_released[k] = false; + } +} + +void input_set_status(enum input_button b, bool pressed) { + assert(b < IB_MAX); + input_key_held[b] = pressed; + input_key_pressed[b] = pressed; + input_key_released[b] = !pressed; +} + +void input_set_joystick(float x, float y) { + joystick_x = x; + joystick_y = y; +} + +bool input_pressed(enum input_button b) { + return input_key_pressed[b]; +} + +bool input_released(enum input_button b) { + return input_key_released[b]; +} + +bool input_held(enum input_button b) { + return input_key_held[b]; +} + +bool input_joystick(float dt, float* x, float* y) { + *x = joystick_x; + *y = joystick_y; + return true; +} + +#endif + +#ifdef PLATFORM_WII + +#include + static bool input_has_wpad; static bool input_has_pad; static bool input_has_joystick; @@ -129,3 +190,5 @@ bool input_joystick(float dt, float* x, float* y) { *y = input_dy * dt; return input_has_joystick; } + +#endif diff --git a/source/platform/input.h b/source/platform/input.h index fff269f..3a43857 100644 --- a/source/platform/input.h +++ b/source/platform/input.h @@ -34,11 +34,14 @@ enum input_button { IB_HOME, IB_SCROLL_LEFT, IB_SCROLL_RIGHT, + IB_MAX, }; void input_init(void); void input_poll(void); +void input_set_status(enum input_button b, bool pressed); +void input_set_joystick(float x, float y); bool input_pressed(enum input_button b); bool input_released(enum input_button b); bool input_held(enum input_button b); diff --git a/source/platform/thread.c b/source/platform/thread.c new file mode 100644 index 0000000..4a5a1a1 --- /dev/null +++ b/source/platform/thread.c @@ -0,0 +1,150 @@ +/* + Copyright (c) 2023 ByteBit/xtreme8000 + + This file is part of CavEX. + + CavEX is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + CavEX is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with CavEX. If not, see . +*/ + +#include + +#include "thread.h" + +#ifdef PLATFORM_PC + +#include +#include +#include + +void thread_create(struct thread* t, void* (*entry)(void* arg), void* arg, + uint8_t priority) { + assert(t && entry); + pthread_create(&t->native, NULL, entry, arg); +} + +void thread_join(struct thread* t) { + assert(t); + pthread_join(t->native, NULL); +} + +void thread_msleep(size_t ms) { + usleep(ms * 1000); +} + +void tchannel_init(struct thread_channel* c, size_t count) { + assert(c && count > 0); + + c->count = 0; + c->length = count; + c->data = malloc(c->length * sizeof(void*)); + + pthread_mutex_init(&c->lock, NULL); + pthread_cond_init(&c->signal, NULL); +} + +void tchannel_close(struct thread_channel* c) { + assert(c); + + free(c->data); + pthread_cond_destroy(&c->signal); + pthread_mutex_destroy(&c->lock); +} + +bool tchannel_receive(struct thread_channel* c, void** msg, bool block) { + assert(c && msg); + + pthread_mutex_lock(&c->lock); + + if(block) { + while(!c->count) + pthread_cond_wait(&c->signal, &c->lock); + } else { + if(!c->count) { + pthread_mutex_unlock(&c->lock); + return false; + } + } + + *msg = c->data[0]; + c->count--; + + memmove(c->data, c->data + 1, c->count * sizeof(void*)); + + pthread_cond_signal(&c->signal); + pthread_mutex_unlock(&c->lock); + return true; +} + +bool tchannel_send(struct thread_channel* c, void* msg, bool block) { + assert(c && msg); + + pthread_mutex_lock(&c->lock); + + if(block) { + while(c->count >= c->length) + pthread_cond_wait(&c->signal, &c->lock); + } else { + if(c->count >= c->length) { + pthread_mutex_unlock(&c->lock); + return false; + } + } + + c->data[c->count++] = msg; + + pthread_cond_signal(&c->signal); + pthread_mutex_unlock(&c->lock); + return true; +} + +#endif + +#ifdef PLATFORM_WII + +void thread_create(struct thread* t, void* (*entry)(void* arg), void* arg, + uint8_t priority) { + assert(t && entry); + LWP_CreateThread(&t->native, entry, arg, NULL, 0, priority); +} + +void thread_join(struct thread* t) { + assert(t); + + void* unused; + LWP_JoinThread(t->native, &unused); +} + +void thread_msleep(size_t ms) { + usleep(ms * 1000); +} + +void tchannel_init(struct thread_channel* c, size_t count) { + assert(c && count > 0); + MQ_Init(&c->native, count); +} + +void tchannel_close(struct thread_channel* c) { + assert(c); + MQ_Close(c->native); +} + +bool tchannel_receive(struct thread_channel* c, void** msg, bool block) { + return MQ_Receive(c->native, msg, block ? MQ_MSG_BLOCK : MQ_MSG_NOBLOCK); +} + +bool tchannel_send(struct thread_channel* c, void* msg, bool block) { + return MQ_Send(c->native, msg, block ? MQ_MSG_BLOCK : MQ_MSG_NOBLOCK); +} + +#endif diff --git a/source/platform/thread.h b/source/platform/thread.h new file mode 100644 index 0000000..e5a288d --- /dev/null +++ b/source/platform/thread.h @@ -0,0 +1,66 @@ +/* + Copyright (c) 2023 ByteBit/xtreme8000 + + This file is part of CavEX. + + CavEX is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + CavEX is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with CavEX. If not, see . +*/ + +#ifndef THREAD_H +#define THREAD_H + +#include +#include +#include + +#ifdef PLATFORM_PC +#include + +struct thread { + pthread_t native; +}; + +struct thread_channel { + pthread_mutex_t lock; + pthread_cond_t signal; + void** data; + size_t count; + size_t length; +}; + +#endif + +#ifdef PLATFORM_WII +#include + +struct thread { + lwp_t native; +}; + +struct thread_channel { + mqbox_t native; +}; +#endif + +void thread_create(struct thread* t, void* (*entry)(void* arg), void* arg, + uint8_t priority); +void thread_join(struct thread* t); +void thread_msleep(size_t ms); + +void tchannel_init(struct thread_channel* c, size_t count); +void tchannel_close(struct thread_channel* c); +bool tchannel_receive(struct thread_channel* c, void** msg, bool block); +bool tchannel_send(struct thread_channel* c, void* msg, bool block); + +#endif diff --git a/source/platform/time.c b/source/platform/time.c new file mode 100644 index 0000000..0eb6ee0 --- /dev/null +++ b/source/platform/time.c @@ -0,0 +1,65 @@ +/* + Copyright (c) 2023 ByteBit/xtreme8000 + + This file is part of CavEX. + + CavEX is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + CavEX is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with CavEX. If not, see . +*/ + +#include "time.h" + +#ifdef PLATFORM_PC + +#include + +void time_reset() { } + +ptime_t time_get() { + struct timespec t; + clock_gettime(CLOCK_MONOTONIC_RAW, &t); + return t; +} + +int32_t time_diff_ms(ptime_t f, ptime_t s) { + return (s.tv_sec - f.tv_sec) * 1000 + (s.tv_nsec - f.tv_nsec) / 1000000; +} + +float time_diff_s(ptime_t f, ptime_t s) { + return (float)(s.tv_sec - f.tv_sec) + + (float)(s.tv_nsec - f.tv_nsec) / 1000000000.0F; +} + +#endif + +#ifdef PLATFORM_WII + +#include + +void time_reset() { + settime(0); +} + +ptime_t time_get() { + return gettime(); +} + +int32_t time_diff_ms(ptime_t f, ptime_t s) { + return (s - f) / TB_TIMER_CLOCK; +} + +float time_diff_s(ptime_t f, ptime_t s) { + return (float)(s - f) / (float)(1000UL * TB_TIMER_CLOCK); +} + +#endif diff --git a/source/platform/time.h b/source/platform/time.h new file mode 100644 index 0000000..fa6e0ee --- /dev/null +++ b/source/platform/time.h @@ -0,0 +1,38 @@ +/* + Copyright (c) 2023 ByteBit/xtreme8000 + + This file is part of CavEX. + + CavEX is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + CavEX is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with CavEX. If not, see . +*/ + +#ifndef TIME_H +#define TIME_H + +#include + +#ifdef PLATFORM_WII +typedef uint64_t ptime_t; +#endif + +#ifdef PLATFORM_PC +typedef struct timespec ptime_t; +#endif + +void time_reset(void); +ptime_t time_get(void); +int32_t time_diff_ms(ptime_t f, ptime_t s); +float time_diff_s(ptime_t f, ptime_t s); + +#endif diff --git a/source/util.c b/source/util.c index b911227..956c614 100644 --- a/source/util.c +++ b/source/util.c @@ -19,24 +19,26 @@ #include #include -#include +#include +#include #include "util.h" -void time_reset() { - settime(0); -} +void* file_read(const char* name) { + FILE* f = fopen(name, "rb"); -ptime_t time_get() { - return gettime(); -} + if(!f) + return NULL; -int32_t time_diff_ms(ptime_t f, ptime_t s) { - return (s - f) / TB_TIMER_CLOCK; -} + fseek(f, 0, SEEK_END); + size_t length = ftell(f); + fseek(f, 0, SEEK_SET); + char* res = malloc(length + 1); + res[length] = 0; + fread(res, length, 1, f); + fclose(f); -float time_diff_s(ptime_t f, ptime_t s) { - return (float)(s - f) / (float)(1000UL * TB_TIMER_CLOCK); + return res; } uint32_t hash_u32(uint32_t x) { diff --git a/source/util.h b/source/util.h index a1ab782..b84dfdb 100644 --- a/source/util.h +++ b/source/util.h @@ -23,12 +23,9 @@ #include #include -typedef uint64_t ptime_t; +#include "platform/time.h" -void time_reset(void); -ptime_t time_get(void); -int32_t time_diff_ms(ptime_t f, ptime_t s); -float time_diff_s(ptime_t f, ptime_t s); +void* file_read(const char* name); uint32_t hash_u32(uint32_t x); diff --git a/source/world.c b/source/world.c index 7d82047..9ec9bfc 100644 --- a/source/world.c +++ b/source/world.c @@ -237,8 +237,7 @@ void world_set_block(struct world* w, w_coord_t x, w_coord_t y, w_coord_t z, w_coord_t cz = WCOORD_CHUNK_OFFSET(z); struct world_section* s = dict_wsection_get(w->sections, SECTION_TO_ID(cx, cz)); - - struct chunk* c = world_find_chunk(w, x, y, z); + struct chunk* c = world_chunk_from_section(w, s, y); if(!c) { c = malloc(sizeof(struct chunk));