mirror of
https://github.com/xtreme8000/CavEX.git
synced 2025-01-22 09:11:55 -05:00
WIP: pc port
This commit is contained in:
parent
7be3341cb9
commit
fc30334a4d
35 changed files with 2083 additions and 870 deletions
132
CMakeLists.txt
Executable file
132
CMakeLists.txt
Executable 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)
|
2
Makefile
2
Makefile
|
@ -32,7 +32,7 @@ INCLUDES :=
|
|||
# options for code generation
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
CFLAGS = -std=c99 -pedantic -Wextra -Wno-unused-parameter -flto=auto -O3 -Wall $(MACHDEP) $(INCLUDE)
|
||||
CFLAGS = -std=c99 -pedantic -Wextra -Wno-unused-parameter -flto=auto -O3 -Wall -DPLATFORM_WII $(MACHDEP) $(INCLUDE)
|
||||
CXXFLAGS = $(CFLAGS)
|
||||
|
||||
LDFLAGS = -g $(MACHDEP) -Wl,-Map,$(notdir $@).map
|
||||
|
|
32
resources/fragment.shader
Normal file
32
resources/fragment.shader
Normal 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
29
resources/vertex.shader
Normal 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);
|
||||
}
|
|
@ -18,7 +18,6 @@
|
|||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <gccore.h>
|
||||
#include <malloc.h>
|
||||
#include <math.h>
|
||||
#include <stddef.h>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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);
|
||||
|
||||
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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
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,
|
||||
box.x2 * 256 + pad, -pad + box.y1 * 256, -pad + box.z1 * 256,
|
||||
|
||||
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);
|
||||
-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(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,
|
||||
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(-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,
|
||||
-pad + box.x1 * 256, -pad + box.y1 * 256, box.z2 * 256 + pad,
|
||||
|
||||
// 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,
|
||||
box.x2 * 256 + pad, box.y2 * 256 + pad, -pad + box.z1 * 256,
|
||||
|
||||
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);
|
||||
-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(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,
|
||||
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(-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,
|
||||
-pad + box.x1 * 256, box.y2 * 256 + pad, box.z2 * 256 + pad,
|
||||
|
||||
// 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);
|
||||
-pad + box.x1 * 256, -pad + box.y1 * 256, -pad + box.z1 * 256,
|
||||
-pad + box.x1 * 256, 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);
|
||||
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(-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);
|
||||
-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(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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
148
source/platform/graphics/pc/displaylist.c
Normal file
148
source/platform/graphics/pc/displaylist.c
Normal 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);
|
||||
}
|
469
source/platform/graphics/pc/gfx.c
Normal file
469
source/platform/graphics/pc/gfx.c
Normal 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);
|
||||
}
|
|
@ -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"
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#ifndef RENDER_BLOCK_H
|
||||
#define RENDER_BLOCK_H
|
||||
|
||||
#include <gccore.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
131
source/platform/graphics/wii/displaylist.c
Normal file
131
source/platform/graphics/wii/displaylist.c
Normal 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();
|
||||
}
|
488
source/platform/graphics/wii/gfx.c
Normal file
488
source/platform/graphics/wii/gfx.c
Normal 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();
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
150
source/platform/thread.c
Normal 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
66
source/platform/thread.h
Normal 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
65
source/platform/time.c
Normal 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
38
source/platform/time.h
Normal 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
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
Loading…
Reference in a new issue