WIP: pc port

This commit is contained in:
xtreme8000 2023-03-27 18:58:52 +02:00
parent 7be3341cb9
commit fc30334a4d
35 changed files with 2083 additions and 870 deletions

132
CMakeLists.txt Executable file
View file

@ -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)

View file

@ -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

32
resources/fragment.shader Normal file
View file

@ -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;
}

29
resources/vertex.shader Normal file
View file

@ -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);
}

View file

@ -18,7 +18,6 @@
*/
#include <assert.h>
#include <gccore.h>
#include <malloc.h>
#include <math.h>
#include <stddef.h>

View file

@ -18,11 +18,11 @@
*/
#include <assert.h>
#include <gccore.h>
#include <stdint.h>
#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;
}

View file

@ -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,

View file

@ -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];

View file

@ -23,7 +23,7 @@
#include <stdlib.h>
#include <string.h>
#ifdef GEKKO
#ifdef PLATFORM_WII
#include <fat.h>
#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;

View file

@ -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);
}

View file

@ -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;
}

View file

@ -18,32 +18,31 @@
*/
#include <assert.h>
#include <gccore.h>
#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);
}

View file

@ -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);
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include <gccore.h>
#include <malloc.h>
#include <string.h>
#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

View file

@ -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);

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include <gccore.h>
#include <malloc.h>
#include <math.h>
#include <ogc/tpl.h>
#include <string.h>
#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

View file

@ -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

View file

@ -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 <assert.h>
#include <gccore.h>
#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);

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <gccore.h>
#include <string.h>
#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();
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <GL/glew.h>
#include <assert.h>
#include <malloc.h>
#include <string.h>
#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);
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <assert.h>
#include <malloc.h>
#include <math.h>
#include <string.h>
#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);
}

View file

@ -17,7 +17,6 @@
along with CavEX. If not, see <http://www.gnu.org/licenses/>.
*/
#include <gccore.h>
#include <stdint.h>
#include "../../block/blocks.h"

View file

@ -20,7 +20,6 @@
#ifndef RENDER_BLOCK_H
#define RENDER_BLOCK_H
#include <gccore.h>
#include <stdbool.h>
#include <stddef.h>

View file

@ -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);

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include <gccore.h>
#include <malloc.h>
#include <string.h>
#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();
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include <gccore.h>
#include <malloc.h>
#include <math.h>
#include <ogc/tpl.h>
#include <string.h>
#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();
}

View file

@ -18,11 +18,72 @@
*/
#include <assert.h>
#include <wiiuse/wpad.h>
#include "../cglm/cglm.h"
#include "input.h"
#ifdef PLATFORM_PC
#include <GLFW/glfw3.h>
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 <wiiuse/wpad.h>
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

View file

@ -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);

150
source/platform/thread.c Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include "thread.h"
#ifdef PLATFORM_PC
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
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

66
source/platform/thread.h Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef THREAD_H
#define THREAD_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#ifdef PLATFORM_PC
#include <pthread.h>
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 <gccore.h>
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

65
source/platform/time.c Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#include "time.h"
#ifdef PLATFORM_PC
#include <time.h>
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 <ogc/lwp_watchdog.h>
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

38
source/platform/time.h Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef TIME_H
#define TIME_H
#include <stdint.h>
#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

View file

@ -19,24 +19,26 @@
#include <assert.h>
#include <math.h>
#include <ogc/lwp_watchdog.h>
#include <stdio.h>
#include <stdlib.h>
#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) {

View file

@ -23,12 +23,9 @@
#include <stddef.h>
#include <stdint.h>
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);

View file

@ -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));