From da94644c383be30941347fa72d1f43d423e2dae2 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Sat, 29 Jul 2023 23:21:35 +0200 Subject: [PATCH] port: make it link and load nothing happens after loading though --- Makefile | 4 +- include/PR/R4300.h | 20 + include/PR/os_convert.h | 9 +- port/include/fs.h | 18 + port/include/input.h | 31 + port/include/preprocess.h | 33 + port/include/romdata.h | 22 + port/include/system.h | 11 + port/include/video.h | 15 + port/n64-fast3d-engine/LICENSE.txt | 19 + port/n64-fast3d-engine/gfx_cc.c | 41 + port/n64-fast3d-engine/gfx_cc.h | 58 + port/n64-fast3d-engine/gfx_opengl.c | 510 +++++ port/n64-fast3d-engine/gfx_opengl.h | 8 + port/n64-fast3d-engine/gfx_pc.c | 1697 +++++++++++++++++ port/n64-fast3d-engine/gfx_pc.h | 36 + port/n64-fast3d-engine/gfx_rendering_api.h | 35 + port/n64-fast3d-engine/gfx_screen_config.h | 7 + port/n64-fast3d-engine/gfx_sdl2.c | 191 ++ port/n64-fast3d-engine/gfx_sdl2.h | 8 + .../gfx_window_manager_api.h | 21 + port/n64-fast3d-engine/glad/glad.c | 475 +++++ port/n64-fast3d-engine/glad/glad.h | 874 +++++++++ port/n64-fast3d-engine/glad/khrplatform.h | 311 +++ port/src/crash.c | 39 + port/src/fs.c | 89 + port/src/input.c | 137 ++ port/src/libultra.c | 446 +++++ port/src/main.c | 74 + port/src/pdmain.c | 644 +++++++ port/src/pdsched.c | 388 ++++ port/src/preprocess.c | 901 +++++++++ port/src/romdata.c | 417 ++++ port/src/system.c | 47 + port/src/video.c | 59 + src/game/bg.c | 30 + src/game/challenge.c | 62 +- src/game/file.c | 66 +- src/game/game_1531a0.c | 84 +- src/game/getitle.c | 14 +- src/game/hudmsg.c | 4 + src/game/lang.c | 9 +- src/game/propobj.c | 10 +- src/game/texdecompress.c | 11 +- src/game/texinit.c | 8 +- src/game/texreset.c | 19 +- src/include/data.h | 8 + src/include/lib/dma.h | 8 +- src/include/lib/sched.h | 2 + src/include/lib/str.h | 5 + src/include/math.h | 7 + src/include/platform.h | 75 + src/include/stdarg.h | 4 +- src/include/stdlib.h | 16 +- src/include/string.h | 17 +- src/include/types.h | 11 + src/lib/anim.c | 12 +- src/lib/audiomgr.c | 2 + src/lib/dma.c | 14 +- src/lib/main.c | 16 +- src/lib/memp.c | 21 + src/lib/mp3/util_c.c | 28 + src/lib/mtx_c.c | 4 + src/lib/rdp.c | 2 + src/lib/rmon.c | 12 + src/lib/rzip_c.c | 100 + src/lib/snd.c | 54 +- src/lib/vminit.c | 24 +- 68 files changed, 8291 insertions(+), 163 deletions(-) create mode 100644 port/include/fs.h create mode 100644 port/include/input.h create mode 100644 port/include/preprocess.h create mode 100644 port/include/romdata.h create mode 100644 port/include/system.h create mode 100644 port/include/video.h create mode 100644 port/n64-fast3d-engine/LICENSE.txt create mode 100644 port/n64-fast3d-engine/gfx_cc.c create mode 100644 port/n64-fast3d-engine/gfx_cc.h create mode 100644 port/n64-fast3d-engine/gfx_opengl.c create mode 100644 port/n64-fast3d-engine/gfx_opengl.h create mode 100644 port/n64-fast3d-engine/gfx_pc.c create mode 100644 port/n64-fast3d-engine/gfx_pc.h create mode 100644 port/n64-fast3d-engine/gfx_rendering_api.h create mode 100644 port/n64-fast3d-engine/gfx_screen_config.h create mode 100644 port/n64-fast3d-engine/gfx_sdl2.c create mode 100644 port/n64-fast3d-engine/gfx_sdl2.h create mode 100644 port/n64-fast3d-engine/gfx_window_manager_api.h create mode 100644 port/n64-fast3d-engine/glad/glad.c create mode 100644 port/n64-fast3d-engine/glad/glad.h create mode 100644 port/n64-fast3d-engine/glad/khrplatform.h create mode 100644 port/src/crash.c create mode 100644 port/src/fs.c create mode 100644 port/src/input.c create mode 100644 port/src/libultra.c create mode 100644 port/src/main.c create mode 100644 port/src/pdmain.c create mode 100644 port/src/pdsched.c create mode 100644 port/src/preprocess.c create mode 100644 port/src/romdata.c create mode 100644 port/src/system.c create mode 100644 port/src/video.c create mode 100644 src/include/platform.h create mode 100644 src/lib/mp3/util_c.c create mode 100644 src/lib/rzip_c.c diff --git a/Makefile b/Makefile index fdfe77898..da78d5e5e 100644 --- a/Makefile +++ b/Makefile @@ -169,7 +169,8 @@ DEFINES := \ MATCHING=$(MATCHING) \ PAL=$(PAL) \ PIRACYCHECKS=$(PIRACYCHECKS) \ - ROM_SIZE=$(ROM_SIZE) + ROM_SIZE=$(ROM_SIZE) \ + PLATFORM_N64=1 ifeq ($(DEBUG),1) DEFINES := $(DEFINES) DEBUG=1 @@ -296,6 +297,7 @@ INCLUDES = \ -I include \ -I include/PR \ -I src/include \ + -I src/include/lib/libc \ -I src/generated/$(ROMID) \ -I src/lib/ultra/audio \ diff --git a/include/PR/R4300.h b/include/PR/R4300.h index 0c25f1d58..061ed8158 100644 --- a/include/PR/R4300.h +++ b/include/PR/R4300.h @@ -60,6 +60,8 @@ #else /* _LANGUAGE_C */ +#ifdef PLATFORM_N64 + #define K0_TO_K1(x) ((u32)(x)|0xA0000000) /* kseg0 to kseg1 */ #define K1_TO_K0(x) ((u32)(x)&0x9FFFFFFF) /* kseg1 to kseg0 */ #define K0_TO_PHYS(x) ((u32)(x)&0x1FFFFFFF) /* kseg0 to physical */ @@ -68,6 +70,24 @@ #define PHYS_TO_K0(x) ((u32)(x)|0x80000000) /* physical to kseg0 */ #define PHYS_TO_K1(x) ((u32)(x)|0xA0000000) /* physical to kseg1 */ +#else /* PLATFORM_N64 */ + +#ifdef PLATFORM_64BIT +typedef u64 k_ptr_t; +#else +typedef u32 k_ptr_t; +#endif + +#define K0_TO_K1(x) ((k_ptr_t)(x)) /* kseg0 to kseg1 */ +#define K1_TO_K0(x) ((k_ptr_t)(x)) /* kseg1 to kseg0 */ +#define K0_TO_PHYS(x) ((k_ptr_t)(x)) /* kseg0 to physical */ +#define K1_TO_PHYS(x) ((k_ptr_t)(x)) /* kseg1 to physical */ +#define KDM_TO_PHYS(x) ((k_ptr_t)(x)) /* direct mapped to physical */ +#define PHYS_TO_K0(x) ((k_ptr_t)(x)) /* physical to kseg0 */ +#define PHYS_TO_K1(x) ((k_ptr_t)(x)) /* physical to kseg1 */ + +#endif /* PLATFORM_N64 */ + #endif /* _LANGUAGE_ASSEMBLY */ /* diff --git a/include/PR/os_convert.h b/include/PR/os_convert.h index 4be88b5fe..41f5880a9 100644 --- a/include/PR/os_convert.h +++ b/include/PR/os_convert.h @@ -70,12 +70,17 @@ extern "C" { #define OS_CYCLES_TO_NSEC(c) (((u64)(c)*(1000000000LL/15625000LL))/(OS_CPU_COUNTER/15625000LL)) #define OS_CYCLES_TO_USEC(c) (((u64)(c)*(1000000LL/15625LL))/(OS_CPU_COUNTER/15625LL)) +#ifdef PLATFORM_N64 #define OS_K0_TO_PHYSICAL(x) (u32)(((char *)(x)-0x80000000)) #define OS_K1_TO_PHYSICAL(x) (u32)(((char *)(x)-0xa0000000)) - #define OS_PHYSICAL_TO_K0(x) (void *)(((u32)(x)+0x80000000)) #define OS_PHYSICAL_TO_K1(x) (void *)(((u32)(x)+0xa0000000)) - +#else +#define OS_K0_TO_PHYSICAL(x) (uintptr_t)(x) +#define OS_K1_TO_PHYSICAL(x) (uintptr_t)(x) +#define OS_PHYSICAL_TO_K0(x) (void *)(x) +#define OS_PHYSICAL_TO_K1(x) (void *)(x) +#endif /************************************************************************** * diff --git a/port/include/fs.h b/port/include/fs.h new file mode 100644 index 000000000..c117b4d69 --- /dev/null +++ b/port/include/fs.h @@ -0,0 +1,18 @@ +#ifndef _IN_FS_H +#define _IN_FS_H + +#include +#include + +#ifdef PATH_MAX +#define FS_MAXPATH PATH_MAX +#else +#define FS_MAXPATH 1024 +#endif + +s32 fsInit(void); + +void *fsFileLoad(const char *name, u32 *outSize); +s32 fsFileSize(const char *name); + +#endif diff --git a/port/include/input.h b/port/include/input.h new file mode 100644 index 000000000..6609e7cba --- /dev/null +++ b/port/include/input.h @@ -0,0 +1,31 @@ +#ifndef _IN_INPUT_H +#define _IN_INPUT_H + +#include +#include + +#define INPUT_MAX_CONTROLLERS MAXCONTROLLERS +#define INPUT_RUMBLE_STRENGTH 0.333f + +// returns bitmask of connected controllers or -1 if failed +s32 inputInit(void); + +// returns 0 if read, non-0 if failed +s32 inputReadController(s32 idx, OSContPad *npad); + +// returns 1 if rumble is supported for specified controller +s32 inputRumbleSupported(s32 idx); + +// returns 1 if specified controller is connected +s32 inputControllerConnected(s32 idx); + +// returns bitmask of connected controllers +s32 inputControllerMask(void); + +// 0 strength turns it off +void inputRumble(s32 idx, f32 strength, f32 time); + +// call this every frame +void inputUpdate(void); + +#endif diff --git a/port/include/preprocess.h b/port/include/preprocess.h new file mode 100644 index 000000000..33faaed1a --- /dev/null +++ b/port/include/preprocess.h @@ -0,0 +1,33 @@ +#ifndef _IN_PREPROCESS_H +#define _IN_PREPROCESS_H + +#include + +typedef void (*preprocessfunc)(u8 *data, u32 size); + +void preprocessAnimations(u8 *data, u32 size); +void preprocessMpConfigs(u8 *data, u32 size); +void preprocessFont(u8 *data, u32 size); +void preprocessJpnFont(u8 *data, u32 size); +void preprocessALBankFile(u8 *data, u32 size); +void preprocessSequences(u8 *data, u32 size); +void preprocessFiringRange(u8 *data, u32 size); +void preprocessTexturesList(u8 *data, u32 size); + +void preprocessBgSection1Header(u8 *data, u32 size); +void preprocessBgSection1(u8 *data, u32 size); +void preprocessBgSection2Header(u8 *data, u32 size); +void preprocessBgSection2(u8 *data, u32 size); +void preprocessBgSection3Header(u8 *data, u32 size); +void preprocessBgSection3(u8 *data, u32 size); +void preprocessBgRoom(u8 *data, u32 ofs); +void preprocessBgLights(u8 *data, u32 ofs); + +void preprocessLangFile(u8 *data, u32 size); +void preprocessPadsFile(u8 *data, u32 size); +void preprocessTilesFile(u8 *data, u32 size); +void preprocessSetupFile(u8 *data, u32 size); +void preprocessModelFile(u8 *data, u32 size); +void preprocessGunFile(u8 *data, u32 size); + +#endif diff --git a/port/include/romdata.h b/port/include/romdata.h new file mode 100644 index 000000000..70da7e824 --- /dev/null +++ b/port/include/romdata.h @@ -0,0 +1,22 @@ +#ifndef _IN_ROMDATA_H +#define _IN_ROMDATA_H + +#include + +extern u8 *g_RomFile; +extern u32 g_RomFileSize; + +s32 romdataInit(void); + +u8 *romdataFileLoad(s32 fileNum, u32 *outSize); +void romdataFilePreprocess(s32 fileNum, s32 loadType, u8 *data, u32 size); +void romdataFileFree(s32 fileNum); + +u8 *romdataFileGetData(s32 fileNum); +s32 romdataFileGetSize(s32 fileNum); + +u8 *romdataSegGetData(const char *segName); +u8 *romdataSegGetDataEnd(const char *segName); +u32 romdataSegGetSize(const char *segName); + +#endif diff --git a/port/include/system.h b/port/include/system.h new file mode 100644 index 000000000..257ac1f9d --- /dev/null +++ b/port/include/system.h @@ -0,0 +1,11 @@ +#ifndef _IN_SYSTEM_H +#define _IN_SYSTEM_H + +#include + +u64 sysGetTicks(void); +u64 sysGetTicksPerSecond(void); + +void sysFatalError(const char *fmt, ...) __attribute__((noreturn)); + +#endif diff --git a/port/include/video.h b/port/include/video.h new file mode 100644 index 000000000..ed2dc5931 --- /dev/null +++ b/port/include/video.h @@ -0,0 +1,15 @@ +#ifndef _IN_VIDEO_H +#define _IN_VIDEO_H + +#include +#include + +s32 videoInit(void); +void videoStartFrame(void); +void videoSubmitCommands(Gfx *cmds); +void videoClearScreen(void); +void videoEndFrame(void); + +void *videoGetWindowHandle(void); + +#endif diff --git a/port/n64-fast3d-engine/LICENSE.txt b/port/n64-fast3d-engine/LICENSE.txt new file mode 100644 index 000000000..22137711c --- /dev/null +++ b/port/n64-fast3d-engine/LICENSE.txt @@ -0,0 +1,19 @@ +Copyright (c) 2020 Emill, MaikelChan + +Redistribution and use in source forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form are not allowed except in cases where the binary contains no assets you do not have the right to distribute. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/port/n64-fast3d-engine/gfx_cc.c b/port/n64-fast3d-engine/gfx_cc.c new file mode 100644 index 000000000..d43f54bc8 --- /dev/null +++ b/port/n64-fast3d-engine/gfx_cc.c @@ -0,0 +1,41 @@ +#include "gfx_cc.h" + +void gfx_cc_get_features(uint32_t shader_id, struct CCFeatures *cc_features) { + for (int i = 0; i < 4; i++) { + cc_features->c[0][i] = (shader_id >> (i * 3)) & 7; + cc_features->c[1][i] = (shader_id >> (12 + i * 3)) & 7; + } + + cc_features->opt_alpha = (shader_id & SHADER_OPT_ALPHA) != 0; + cc_features->opt_fog = (shader_id & SHADER_OPT_FOG) != 0; + cc_features->opt_texture_edge = (shader_id & SHADER_OPT_TEXTURE_EDGE) != 0; + cc_features->opt_noise = (shader_id & SHADER_OPT_NOISE) != 0; + + cc_features->used_textures[0] = false; + cc_features->used_textures[1] = false; + cc_features->num_inputs = 0; + + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 4; j++) { + if (cc_features->c[i][j] >= SHADER_INPUT_1 && cc_features->c[i][j] <= SHADER_INPUT_4) { + if (cc_features->c[i][j] > cc_features->num_inputs) { + cc_features->num_inputs = cc_features->c[i][j]; + } + } + if (cc_features->c[i][j] == SHADER_TEXEL0 || cc_features->c[i][j] == SHADER_TEXEL0A) { + cc_features->used_textures[0] = true; + } + if (cc_features->c[i][j] == SHADER_TEXEL1) { + cc_features->used_textures[1] = true; + } + } + } + + cc_features->do_single[0] = cc_features->c[0][2] == 0; + cc_features->do_single[1] = cc_features->c[1][2] == 0; + cc_features->do_multiply[0] = cc_features->c[0][1] == 0 && cc_features->c[0][3] == 0; + cc_features->do_multiply[1] = cc_features->c[1][1] == 0 && cc_features->c[1][3] == 0; + cc_features->do_mix[0] = cc_features->c[0][1] == cc_features->c[0][3]; + cc_features->do_mix[1] = cc_features->c[1][1] == cc_features->c[1][3]; + cc_features->color_alpha_same = (shader_id & 0xfff) == ((shader_id >> 12) & 0xfff); +} diff --git a/port/n64-fast3d-engine/gfx_cc.h b/port/n64-fast3d-engine/gfx_cc.h new file mode 100644 index 000000000..2840b83ee --- /dev/null +++ b/port/n64-fast3d-engine/gfx_cc.h @@ -0,0 +1,58 @@ +#ifndef GFX_CC_H +#define GFX_CC_H + +#include +#include + +enum { + CC_0, + CC_TEXEL0, + CC_TEXEL1, + CC_PRIM, + CC_SHADE, + CC_ENV, + CC_TEXEL0A, + CC_LOD +}; + +enum { + SHADER_0, + SHADER_INPUT_1, + SHADER_INPUT_2, + SHADER_INPUT_3, + SHADER_INPUT_4, + SHADER_TEXEL0, + SHADER_TEXEL0A, + SHADER_TEXEL1 +}; + +#define SHADER_OPT_ALPHA (1 << 24) +#define SHADER_OPT_FOG (1 << 25) +#define SHADER_OPT_TEXTURE_EDGE (1 << 26) +#define SHADER_OPT_NOISE (1 << 27) + +struct CCFeatures { + uint8_t c[2][4]; + bool opt_alpha; + bool opt_fog; + bool opt_texture_edge; + bool opt_noise; + bool used_textures[2]; + int num_inputs; + bool do_single[2]; + bool do_multiply[2]; + bool do_mix[2]; + bool color_alpha_same; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +void gfx_cc_get_features(uint32_t shader_id, struct CCFeatures *cc_features); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/port/n64-fast3d-engine/gfx_opengl.c b/port/n64-fast3d-engine/gfx_opengl.c new file mode 100644 index 000000000..b3fdf89fb --- /dev/null +++ b/port/n64-fast3d-engine/gfx_opengl.c @@ -0,0 +1,510 @@ +#include +#include +#include +#include + +#ifndef _LANGUAGE_C +#define _LANGUAGE_C +#endif +#include + +#include "glad/glad.h" + +#include "gfx_cc.h" +#include "gfx_rendering_api.h" + +struct ShaderProgram { + uint32_t shader_id; + GLuint opengl_program_id; + uint8_t num_inputs; + bool used_textures[2]; + uint8_t num_floats; + GLint attrib_locations[7]; + uint8_t attrib_sizes[7]; + uint8_t num_attribs; + bool used_noise; + GLint frame_count_location; + GLint window_height_location; +}; + +static struct ShaderProgram shader_program_pool[64]; +static uint8_t shader_program_pool_size; +static GLuint opengl_vbo; + +static uint32_t frame_count; +static uint32_t current_height; + +static bool gfx_opengl_z_is_from_0_to_1(void) { + return false; +} + +static void gfx_opengl_vertex_array_set_attribs(struct ShaderProgram *prg) { + size_t num_floats = prg->num_floats; + size_t pos = 0; + + for (int i = 0; i < prg->num_attribs; i++) { + glEnableVertexAttribArray(prg->attrib_locations[i]); + glVertexAttribPointer(prg->attrib_locations[i], prg->attrib_sizes[i], GL_FLOAT, GL_FALSE, num_floats * sizeof(float), (void *) (pos * sizeof(float))); + pos += prg->attrib_sizes[i]; + } +} + +static void gfx_opengl_set_uniforms(struct ShaderProgram *prg) { + if (prg->used_noise) { + glUniform1i(prg->frame_count_location, frame_count); + glUniform1i(prg->window_height_location, current_height); + } +} + +static void gfx_opengl_unload_shader(struct ShaderProgram *old_prg) { + if (old_prg != NULL) { + for (int i = 0; i < old_prg->num_attribs; i++) { + glDisableVertexAttribArray(old_prg->attrib_locations[i]); + } + } +} + +static void gfx_opengl_load_shader(struct ShaderProgram *new_prg) { + glUseProgram(new_prg->opengl_program_id); + gfx_opengl_vertex_array_set_attribs(new_prg); + gfx_opengl_set_uniforms(new_prg); +} + +static void append_str(char *buf, size_t *len, const char *str) { + while (*str != '\0') buf[(*len)++] = *str++; +} + +static void append_line(char *buf, size_t *len, const char *str) { + while (*str != '\0') buf[(*len)++] = *str++; + buf[(*len)++] = '\n'; +} + +static const char *shader_item_to_str(uint32_t item, bool with_alpha, bool only_alpha, bool inputs_have_alpha, bool hint_single_element) { + if (!only_alpha) { + switch (item) { + case SHADER_0: + return with_alpha ? "vec4(0.0, 0.0, 0.0, 0.0)" : "vec3(0.0, 0.0, 0.0)"; + case SHADER_INPUT_1: + return with_alpha || !inputs_have_alpha ? "vInput1" : "vInput1.rgb"; + case SHADER_INPUT_2: + return with_alpha || !inputs_have_alpha ? "vInput2" : "vInput2.rgb"; + case SHADER_INPUT_3: + return with_alpha || !inputs_have_alpha ? "vInput3" : "vInput3.rgb"; + case SHADER_INPUT_4: + return with_alpha || !inputs_have_alpha ? "vInput4" : "vInput4.rgb"; + case SHADER_TEXEL0: + return with_alpha ? "texVal0" : "texVal0.rgb"; + case SHADER_TEXEL0A: + return hint_single_element ? "texVal0.a" : + (with_alpha ? "vec4(texVal0.a, texVal0.a, texVal0.a, texVal0.a)" : "vec3(texVal0.a, texVal0.a, texVal0.a)"); + case SHADER_TEXEL1: + return with_alpha ? "texVal1" : "texVal1.rgb"; + } + } else { + switch (item) { + case SHADER_0: + return "0.0"; + case SHADER_INPUT_1: + return "vInput1.a"; + case SHADER_INPUT_2: + return "vInput2.a"; + case SHADER_INPUT_3: + return "vInput3.a"; + case SHADER_INPUT_4: + return "vInput4.a"; + case SHADER_TEXEL0: + return "texVal0.a"; + case SHADER_TEXEL0A: + return "texVal0.a"; + case SHADER_TEXEL1: + return "texVal1.a"; + } + } + return ""; +} + +static void append_formula(char *buf, size_t *len, uint8_t c[2][4], bool do_single, bool do_multiply, bool do_mix, bool with_alpha, bool only_alpha, bool opt_alpha) { + if (do_single) { + append_str(buf, len, shader_item_to_str(c[only_alpha][3], with_alpha, only_alpha, opt_alpha, false)); + } else if (do_multiply) { + append_str(buf, len, shader_item_to_str(c[only_alpha][0], with_alpha, only_alpha, opt_alpha, false)); + append_str(buf, len, " * "); + append_str(buf, len, shader_item_to_str(c[only_alpha][2], with_alpha, only_alpha, opt_alpha, true)); + } else if (do_mix) { + append_str(buf, len, "mix("); + append_str(buf, len, shader_item_to_str(c[only_alpha][1], with_alpha, only_alpha, opt_alpha, false)); + append_str(buf, len, ", "); + append_str(buf, len, shader_item_to_str(c[only_alpha][0], with_alpha, only_alpha, opt_alpha, false)); + append_str(buf, len, ", "); + append_str(buf, len, shader_item_to_str(c[only_alpha][2], with_alpha, only_alpha, opt_alpha, true)); + append_str(buf, len, ")"); + } else { + append_str(buf, len, "("); + append_str(buf, len, shader_item_to_str(c[only_alpha][0], with_alpha, only_alpha, opt_alpha, false)); + append_str(buf, len, " - "); + append_str(buf, len, shader_item_to_str(c[only_alpha][1], with_alpha, only_alpha, opt_alpha, false)); + append_str(buf, len, ") * "); + append_str(buf, len, shader_item_to_str(c[only_alpha][2], with_alpha, only_alpha, opt_alpha, true)); + append_str(buf, len, " + "); + append_str(buf, len, shader_item_to_str(c[only_alpha][3], with_alpha, only_alpha, opt_alpha, false)); + } +} + +static struct ShaderProgram *gfx_opengl_create_and_load_new_shader(uint32_t shader_id) { + struct CCFeatures cc_features; + gfx_cc_get_features(shader_id, &cc_features); + + char vs_buf[1024]; + char fs_buf[1024]; + size_t vs_len = 0; + size_t fs_len = 0; + size_t num_floats = 4; + + // Vertex shader + append_line(vs_buf, &vs_len, "#version 110"); + append_line(vs_buf, &vs_len, "attribute vec4 aVtxPos;"); + if (cc_features.used_textures[0] || cc_features.used_textures[1]) { + append_line(vs_buf, &vs_len, "attribute vec2 aTexCoord;"); + append_line(vs_buf, &vs_len, "varying vec2 vTexCoord;"); + num_floats += 2; + } + if (cc_features.opt_fog) { + append_line(vs_buf, &vs_len, "attribute vec4 aFog;"); + append_line(vs_buf, &vs_len, "varying vec4 vFog;"); + num_floats += 4; + } + for (int i = 0; i < cc_features.num_inputs; i++) { + vs_len += sprintf(vs_buf + vs_len, "attribute vec%d aInput%d;\n", cc_features.opt_alpha ? 4 : 3, i + 1); + vs_len += sprintf(vs_buf + vs_len, "varying vec%d vInput%d;\n", cc_features.opt_alpha ? 4 : 3, i + 1); + num_floats += cc_features.opt_alpha ? 4 : 3; + } + append_line(vs_buf, &vs_len, "void main() {"); + if (cc_features.used_textures[0] || cc_features.used_textures[1]) { + append_line(vs_buf, &vs_len, "vTexCoord = aTexCoord;"); + } + if (cc_features.opt_fog) { + append_line(vs_buf, &vs_len, "vFog = aFog;"); + } + for (int i = 0; i < cc_features.num_inputs; i++) { + vs_len += sprintf(vs_buf + vs_len, "vInput%d = aInput%d;\n", i + 1, i + 1); + } + append_line(vs_buf, &vs_len, "gl_Position = aVtxPos;"); + append_line(vs_buf, &vs_len, "}"); + + // Fragment shader + append_line(fs_buf, &fs_len, "#version 110"); + //append_line(fs_buf, &fs_len, "precision mediump float;"); + if (cc_features.used_textures[0] || cc_features.used_textures[1]) { + append_line(fs_buf, &fs_len, "varying vec2 vTexCoord;"); + } + if (cc_features.opt_fog) { + append_line(fs_buf, &fs_len, "varying vec4 vFog;"); + } + for (int i = 0; i < cc_features.num_inputs; i++) { + fs_len += sprintf(fs_buf + fs_len, "varying vec%d vInput%d;\n", cc_features.opt_alpha ? 4 : 3, i + 1); + } + if (cc_features.used_textures[0]) { + append_line(fs_buf, &fs_len, "uniform sampler2D uTex0;"); + } + if (cc_features.used_textures[1]) { + append_line(fs_buf, &fs_len, "uniform sampler2D uTex1;"); + } + + if (cc_features.opt_alpha && cc_features.opt_noise) { + append_line(fs_buf, &fs_len, "uniform int frame_count;"); + append_line(fs_buf, &fs_len, "uniform int window_height;"); + + append_line(fs_buf, &fs_len, "float random(in vec3 value) {"); + append_line(fs_buf, &fs_len, " float random = dot(sin(value), vec3(12.9898, 78.233, 37.719));"); + append_line(fs_buf, &fs_len, " return fract(sin(random) * 143758.5453);"); + append_line(fs_buf, &fs_len, "}"); + } + + append_line(fs_buf, &fs_len, "void main() {"); + + if (cc_features.used_textures[0]) { + append_line(fs_buf, &fs_len, "vec4 texVal0 = texture2D(uTex0, vTexCoord);"); + } + if (cc_features.used_textures[1]) { + append_line(fs_buf, &fs_len, "vec4 texVal1 = texture2D(uTex1, vTexCoord);"); + } + + append_str(fs_buf, &fs_len, cc_features.opt_alpha ? "vec4 texel = " : "vec3 texel = "); + if (!cc_features.color_alpha_same && cc_features.opt_alpha) { + append_str(fs_buf, &fs_len, "vec4("); + append_formula(fs_buf, &fs_len, cc_features.c, cc_features.do_single[0], cc_features.do_multiply[0], cc_features.do_mix[0], false, false, true); + append_str(fs_buf, &fs_len, ", "); + append_formula(fs_buf, &fs_len, cc_features.c, cc_features.do_single[1], cc_features.do_multiply[1], cc_features.do_mix[1], true, true, true); + append_str(fs_buf, &fs_len, ")"); + } else { + append_formula(fs_buf, &fs_len, cc_features.c, cc_features.do_single[0], cc_features.do_multiply[0], cc_features.do_mix[0], cc_features.opt_alpha, false, cc_features.opt_alpha); + } + append_line(fs_buf, &fs_len, ";"); + + if (cc_features.opt_texture_edge && cc_features.opt_alpha) { + append_line(fs_buf, &fs_len, "if (texel.a > 0.3) texel.a = 1.0; else discard;"); + } + // TODO discard if alpha is 0? + if (cc_features.opt_fog) { + if (cc_features.opt_alpha) { + append_line(fs_buf, &fs_len, "texel = vec4(mix(texel.rgb, vFog.rgb, vFog.a), texel.a);"); + } else { + append_line(fs_buf, &fs_len, "texel = mix(texel, vFog.rgb, vFog.a);"); + } + } + + if (cc_features.opt_alpha && cc_features.opt_noise) { + append_line(fs_buf, &fs_len, "texel.a *= floor(clamp(random(vec3(floor(gl_FragCoord.xy * (240.0 / float(window_height))), float(frame_count))) + texel.a, 0.0, 1.0));"); + } + + if (cc_features.opt_alpha) { + append_line(fs_buf, &fs_len, "gl_FragColor = texel;"); + } else { + append_line(fs_buf, &fs_len, "gl_FragColor = vec4(texel, 1.0);"); + } + append_line(fs_buf, &fs_len, "}"); + + vs_buf[vs_len] = '\0'; + fs_buf[fs_len] = '\0'; + + /*puts("Vertex shader:"); + puts(vs_buf); + puts("Fragment shader:"); + puts(fs_buf); + puts("End");*/ + + const GLchar *sources[2] = { vs_buf, fs_buf }; + const GLint lengths[2] = { vs_len, fs_len }; + GLint success; + + GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vertex_shader, 1, &sources[0], &lengths[0]); + glCompileShader(vertex_shader); + glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success); + if (!success) { + GLint max_length = 0; + glGetShaderiv(vertex_shader, GL_INFO_LOG_LENGTH, &max_length); + char error_log[1024]; + fprintf(stderr, "Vertex shader compilation failed\n"); + glGetShaderInfoLog(vertex_shader, max_length, &max_length, &error_log[0]); + fprintf(stderr, "%s\n", &error_log[0]); + abort(); + } + + GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fragment_shader, 1, &sources[1], &lengths[1]); + glCompileShader(fragment_shader); + glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success); + if (!success) { + GLint max_length = 0; + glGetShaderiv(fragment_shader, GL_INFO_LOG_LENGTH, &max_length); + char error_log[1024]; + fprintf(stderr, "Fragment shader compilation failed\n"); + glGetShaderInfoLog(fragment_shader, max_length, &max_length, &error_log[0]); + fprintf(stderr, "%s\n", &error_log[0]); + abort(); + } + + GLuint shader_program = glCreateProgram(); + glAttachShader(shader_program, vertex_shader); + glAttachShader(shader_program, fragment_shader); + glLinkProgram(shader_program); + + size_t cnt = 0; + + struct ShaderProgram *prg = &shader_program_pool[shader_program_pool_size++]; + prg->attrib_locations[cnt] = glGetAttribLocation(shader_program, "aVtxPos"); + prg->attrib_sizes[cnt] = 4; + ++cnt; + + if (cc_features.used_textures[0] || cc_features.used_textures[1]) { + prg->attrib_locations[cnt] = glGetAttribLocation(shader_program, "aTexCoord"); + prg->attrib_sizes[cnt] = 2; + ++cnt; + } + + if (cc_features.opt_fog) { + prg->attrib_locations[cnt] = glGetAttribLocation(shader_program, "aFog"); + prg->attrib_sizes[cnt] = 4; + ++cnt; + } + + for (int i = 0; i < cc_features.num_inputs; i++) { + char name[16]; + sprintf(name, "aInput%d", i + 1); + prg->attrib_locations[cnt] = glGetAttribLocation(shader_program, name); + prg->attrib_sizes[cnt] = cc_features.opt_alpha ? 4 : 3; + ++cnt; + } + + prg->shader_id = shader_id; + prg->opengl_program_id = shader_program; + prg->num_inputs = cc_features.num_inputs; + prg->used_textures[0] = cc_features.used_textures[0]; + prg->used_textures[1] = cc_features.used_textures[1]; + prg->num_floats = num_floats; + prg->num_attribs = cnt; + + gfx_opengl_load_shader(prg); + + if (cc_features.used_textures[0]) { + GLint sampler_location = glGetUniformLocation(shader_program, "uTex0"); + glUniform1i(sampler_location, 0); + } + if (cc_features.used_textures[1]) { + GLint sampler_location = glGetUniformLocation(shader_program, "uTex1"); + glUniform1i(sampler_location, 1); + } + + if (cc_features.opt_alpha && cc_features.opt_noise) { + prg->frame_count_location = glGetUniformLocation(shader_program, "frame_count"); + prg->window_height_location = glGetUniformLocation(shader_program, "window_height"); + prg->used_noise = true; + } else { + prg->used_noise = false; + } + + return prg; +} + +static struct ShaderProgram *gfx_opengl_lookup_shader(uint32_t shader_id) { + for (size_t i = 0; i < shader_program_pool_size; i++) { + if (shader_program_pool[i].shader_id == shader_id) { + return &shader_program_pool[i]; + } + } + return NULL; +} + +static void gfx_opengl_shader_get_info(struct ShaderProgram *prg, uint8_t *num_inputs, bool used_textures[2]) { + *num_inputs = prg->num_inputs; + used_textures[0] = prg->used_textures[0]; + used_textures[1] = prg->used_textures[1]; +} + +static GLuint gfx_opengl_new_texture(void) { + GLuint ret; + glGenTextures(1, &ret); + return ret; +} + +static void gfx_opengl_select_texture(int tile, GLuint texture_id) { + glActiveTexture(GL_TEXTURE0 + tile); + glBindTexture(GL_TEXTURE_2D, texture_id); +} + +static void gfx_opengl_upload_texture(const uint8_t *rgba32_buf, int width, int height) { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgba32_buf); +} + +static uint32_t gfx_cm_to_opengl(uint32_t val) { + if (val & G_TX_CLAMP) { + return GL_CLAMP_TO_EDGE; + } + return (val & G_TX_MIRROR) ? GL_MIRRORED_REPEAT : GL_REPEAT; +} + +static void gfx_opengl_set_sampler_parameters(int tile, bool linear_filter, uint32_t cms, uint32_t cmt) { + glActiveTexture(GL_TEXTURE0 + tile); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, linear_filter ? GL_LINEAR : GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, linear_filter ? GL_LINEAR : GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gfx_cm_to_opengl(cms)); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gfx_cm_to_opengl(cmt)); +} + +static void gfx_opengl_set_depth_test(bool depth_test) { + if (depth_test) { + glEnable(GL_DEPTH_TEST); + } else { + glDisable(GL_DEPTH_TEST); + } +} + +static void gfx_opengl_set_depth_mask(bool z_upd) { + glDepthMask(z_upd ? GL_TRUE : GL_FALSE); +} + +static void gfx_opengl_set_zmode_decal(bool zmode_decal) { + if (zmode_decal) { + glPolygonOffset(-2, -2); + glEnable(GL_POLYGON_OFFSET_FILL); + } else { + glPolygonOffset(0, 0); + glDisable(GL_POLYGON_OFFSET_FILL); + } +} + +static void gfx_opengl_set_viewport(int x, int y, int width, int height) { + glViewport(x, y, width, height); + current_height = height; +} + +static void gfx_opengl_set_scissor(int x, int y, int width, int height) { + glScissor(x, y, width, height); +} + +static void gfx_opengl_set_use_alpha(bool use_alpha) { + if (use_alpha) { + glEnable(GL_BLEND); + } else { + glDisable(GL_BLEND); + } +} + +static void gfx_opengl_draw_triangles(float buf_vbo[], size_t buf_vbo_len, size_t buf_vbo_num_tris) { + //printf("flushing %d tris\n", buf_vbo_num_tris); + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * buf_vbo_len, buf_vbo, GL_STREAM_DRAW); + glDrawArrays(GL_TRIANGLES, 0, 3 * buf_vbo_num_tris); +} + +static void gfx_opengl_init(void) { + gladLoadGLES2Loader(SDL_GL_GetProcAddress); + glGenBuffers(1, &opengl_vbo); + glBindBuffer(GL_ARRAY_BUFFER, opengl_vbo); + glDepthFunc(GL_LEQUAL); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +} + +static void gfx_opengl_on_resize(void) { +} + +static void gfx_opengl_start_frame(void) { + frame_count++; + + glDisable(GL_SCISSOR_TEST); + glDepthMask(GL_TRUE); // Must be set to clear Z-buffer + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glEnable(GL_SCISSOR_TEST); +} + +static void gfx_opengl_end_frame(void) { +} + +static void gfx_opengl_finish_render(void) { +} + +struct GfxRenderingAPI gfx_opengl_api = { + gfx_opengl_z_is_from_0_to_1, + gfx_opengl_unload_shader, + gfx_opengl_load_shader, + gfx_opengl_create_and_load_new_shader, + gfx_opengl_lookup_shader, + gfx_opengl_shader_get_info, + gfx_opengl_new_texture, + gfx_opengl_select_texture, + gfx_opengl_upload_texture, + gfx_opengl_set_sampler_parameters, + gfx_opengl_set_depth_test, + gfx_opengl_set_depth_mask, + gfx_opengl_set_zmode_decal, + gfx_opengl_set_viewport, + gfx_opengl_set_scissor, + gfx_opengl_set_use_alpha, + gfx_opengl_draw_triangles, + gfx_opengl_init, + gfx_opengl_on_resize, + gfx_opengl_start_frame, + gfx_opengl_end_frame, + gfx_opengl_finish_render +}; diff --git a/port/n64-fast3d-engine/gfx_opengl.h b/port/n64-fast3d-engine/gfx_opengl.h new file mode 100644 index 000000000..95be897a2 --- /dev/null +++ b/port/n64-fast3d-engine/gfx_opengl.h @@ -0,0 +1,8 @@ +#ifndef GFX_OPENGL_H +#define GFX_OPENGL_H + +#include "gfx_rendering_api.h" + +extern struct GfxRenderingAPI gfx_opengl_api; + +#endif diff --git a/port/n64-fast3d-engine/gfx_pc.c b/port/n64-fast3d-engine/gfx_pc.c new file mode 100644 index 000000000..e8ccf15c8 --- /dev/null +++ b/port/n64-fast3d-engine/gfx_pc.c @@ -0,0 +1,1697 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef _LANGUAGE_C +#define _LANGUAGE_C +#endif +#include + +#include "gfx_pc.h" +#include "gfx_cc.h" +#include "gfx_window_manager_api.h" +#include "gfx_rendering_api.h" +#include "gfx_screen_config.h" + +#define SUPPORT_CHECK(x) assert(x) + +// SCALE_M_N: upscale/downscale M-bit integer to N-bit +#define SCALE_5_8(VAL_) (((VAL_) * 0xFF) / 0x1F) +#define SCALE_8_5(VAL_) ((((VAL_) + 4) * 0x1F) / 0xFF) +#define SCALE_4_8(VAL_) ((VAL_) * 0x11) +#define SCALE_8_4(VAL_) ((VAL_) / 0x11) +#define SCALE_3_8(VAL_) ((VAL_) * 0x24) +#define SCALE_8_3(VAL_) ((VAL_) / 0x24) + +#define SCREEN_WIDTH 320 +#define SCREEN_HEIGHT 240 +#define HALF_SCREEN_WIDTH (SCREEN_WIDTH / 2) +#define HALF_SCREEN_HEIGHT (SCREEN_HEIGHT / 2) + +#define RATIO_X (gfx_current_dimensions.width / (2.0f * HALF_SCREEN_WIDTH)) +#define RATIO_Y (gfx_current_dimensions.height / (2.0f * HALF_SCREEN_HEIGHT)) + +#define MAX_BUFFERED 256 +#define MAX_LIGHTS 2 +#define MAX_VERTICES 64 + +struct RGBA { + uint8_t r, g, b, a; +}; + +union Vec4b { + struct { uint8_t r, g, b, a; }; + struct { uint8_t x, y, z, w; }; +}; + +struct XYWidthHeight { + uint16_t x, y, width, height; +}; + +struct LoadedVertex { + float x, y, z, w; + float u, v; + struct RGBA color; + uint8_t clip_rej; +}; + +struct TextureHashmapNode { + struct TextureHashmapNode *next; + + const uint8_t *texture_addr; + uint8_t fmt, siz; + + uint32_t texture_id; + uint8_t cms, cmt; + bool linear_filter; +}; +static struct { + struct TextureHashmapNode *hashmap[1024]; + struct TextureHashmapNode pool[512]; + uint32_t pool_pos; +} gfx_texture_cache; + +struct ColorCombiner { + uint32_t cc_id; + struct ShaderProgram *prg; + uint8_t shader_input_mapping[2][4]; +}; + +static struct ColorCombiner color_combiner_pool[64]; +static uint8_t color_combiner_pool_size; + +static struct RSP { + float modelview_matrix_stack[11][4][4]; + uint8_t modelview_matrix_stack_size; + + float MP_matrix[4][4]; + float P_matrix[4][4]; + + Light_t current_lights[MAX_LIGHTS + 1]; + float current_lights_coeffs[MAX_LIGHTS][3]; + float current_lookat_coeffs[2][3]; // lookat_x, lookat_y + uint8_t current_num_lights; // includes ambient light + bool lights_changed; + + uint32_t geometry_mode; + int16_t fog_mul, fog_offset; + + struct { + // U0.16 + uint16_t s, t; + } texture_scaling_factor; + + struct LoadedVertex loaded_vertices[MAX_VERTICES + 4]; + + uintptr_t segment_addrs[16]; + + union Vec4b vertex_color_table[64]; +} rsp; + +static struct RDP { + const uint8_t *palette; + struct { + const uint8_t *addr; + uint8_t siz; + uint8_t tile_number; + } texture_to_load; + struct { + const uint8_t *addr; + uint32_t size_bytes; + } loaded_texture[2]; + struct { + uint8_t fmt; + uint8_t siz; + uint8_t cms, cmt; + uint16_t uls, ult, lrs, lrt; // U10.2 + uint32_t line_size_bytes; + } texture_tile; + bool textures_changed[2]; + + uint32_t other_mode_l, other_mode_h; + uint32_t combine_mode; + + struct RGBA env_color, prim_color, fog_color, fill_color; + struct XYWidthHeight viewport, scissor; + bool viewport_or_scissor_changed; + void *z_buf_address; + void *color_image_address; +} rdp; + +static struct RenderingState { + bool depth_test; + bool depth_mask; + bool decal_mode; + bool alpha_blend; + struct XYWidthHeight viewport, scissor; + struct ShaderProgram *shader_program; + struct TextureHashmapNode *textures[2]; +} rendering_state; + +struct GfxDimensions gfx_current_dimensions; + +static bool dropped_frame; + +static float buf_vbo[MAX_BUFFERED * (26 * 3)]; // 3 vertices in a triangle and 26 floats per vtx +static size_t buf_vbo_len; +static size_t buf_vbo_num_tris; + +static struct GfxWindowManagerAPI *gfx_wapi; +static struct GfxRenderingAPI *gfx_rapi; + +static void gfx_flush(void) { + if (buf_vbo_len > 0) { + int num = buf_vbo_num_tris; + gfx_rapi->draw_triangles(buf_vbo, buf_vbo_len, buf_vbo_num_tris); + buf_vbo_len = 0; + buf_vbo_num_tris = 0; + } +} + +static struct ShaderProgram *gfx_lookup_or_create_shader_program(uint32_t shader_id) { + struct ShaderProgram *prg = gfx_rapi->lookup_shader(shader_id); + if (prg == NULL) { + gfx_rapi->unload_shader(rendering_state.shader_program); + prg = gfx_rapi->create_and_load_new_shader(shader_id); + rendering_state.shader_program = prg; + } + return prg; +} + +static void gfx_generate_cc(struct ColorCombiner *comb, uint32_t cc_id) { + uint8_t c[2][4]; + uint32_t shader_id = (cc_id >> 24) << 24; + uint8_t shader_input_mapping[2][4] = {{0}}; + for (int i = 0; i < 4; i++) { + c[0][i] = (cc_id >> (i * 3)) & 7; + c[1][i] = (cc_id >> (12 + i * 3)) & 7; + } + for (int i = 0; i < 2; i++) { + if (c[i][0] == c[i][1] || c[i][2] == CC_0) { + c[i][0] = c[i][1] = c[i][2] = 0; + } + uint8_t input_number[8] = {0}; + int next_input_number = SHADER_INPUT_1; + for (int j = 0; j < 4; j++) { + int val = 0; + switch (c[i][j]) { + case CC_0: + break; + case CC_TEXEL0: + val = SHADER_TEXEL0; + break; + case CC_TEXEL1: + val = SHADER_TEXEL1; + break; + case CC_TEXEL0A: + val = SHADER_TEXEL0A; + break; + case CC_PRIM: + case CC_SHADE: + case CC_ENV: + case CC_LOD: + if (input_number[c[i][j]] == 0) { + shader_input_mapping[i][next_input_number - 1] = c[i][j]; + input_number[c[i][j]] = next_input_number++; + } + val = input_number[c[i][j]]; + break; + } + shader_id |= val << (i * 12 + j * 3); + } + } + comb->cc_id = cc_id; + comb->prg = gfx_lookup_or_create_shader_program(shader_id); + memcpy(comb->shader_input_mapping, shader_input_mapping, sizeof(shader_input_mapping)); +} + +static struct ColorCombiner *gfx_lookup_or_create_color_combiner(uint32_t cc_id) { + static struct ColorCombiner *prev_combiner; + if (prev_combiner != NULL && prev_combiner->cc_id == cc_id) { + return prev_combiner; + } + + for (size_t i = 0; i < color_combiner_pool_size; i++) { + if (color_combiner_pool[i].cc_id == cc_id) { + return prev_combiner = &color_combiner_pool[i]; + } + } + gfx_flush(); + struct ColorCombiner *comb = &color_combiner_pool[color_combiner_pool_size++]; + gfx_generate_cc(comb, cc_id); + return prev_combiner = comb; +} + +static bool gfx_texture_cache_lookup(int tile, struct TextureHashmapNode **n, const uint8_t *orig_addr, uint32_t fmt, uint32_t siz) { + size_t hash = (uintptr_t)orig_addr; + hash = (hash >> 5) & 0x3ff; + struct TextureHashmapNode **node = &gfx_texture_cache.hashmap[hash]; + while (*node != NULL && *node - gfx_texture_cache.pool < (int)gfx_texture_cache.pool_pos) { + if ((*node)->texture_addr == orig_addr && (*node)->fmt == fmt && (*node)->siz == siz) { + gfx_rapi->select_texture(tile, (*node)->texture_id); + *n = *node; + return true; + } + node = &(*node)->next; + } + if (gfx_texture_cache.pool_pos == sizeof(gfx_texture_cache.pool) / sizeof(struct TextureHashmapNode)) { + // Pool is full. We just invalidate everything and start over. + gfx_texture_cache.pool_pos = 0; + node = &gfx_texture_cache.hashmap[hash]; + //puts("Clearing texture cache"); + } + *node = &gfx_texture_cache.pool[gfx_texture_cache.pool_pos++]; + if ((*node)->texture_addr == NULL) { + (*node)->texture_id = gfx_rapi->new_texture(); + } + gfx_rapi->select_texture(tile, (*node)->texture_id); + gfx_rapi->set_sampler_parameters(tile, false, 0, 0); + (*node)->cms = 0; + (*node)->cmt = 0; + (*node)->linear_filter = false; + (*node)->next = NULL; + (*node)->texture_addr = orig_addr; + (*node)->fmt = fmt; + (*node)->siz = siz; + *n = *node; + return false; +} + +static void import_texture_rgba16(int tile) { + uint8_t rgba32_buf[8192]; + + for (uint32_t i = 0; i < rdp.loaded_texture[tile].size_bytes / 2; i++) { + uint16_t col16 = (rdp.loaded_texture[tile].addr[2 * i] << 8) | rdp.loaded_texture[tile].addr[2 * i + 1]; + uint8_t a = col16 & 1; + uint8_t r = col16 >> 11; + uint8_t g = (col16 >> 6) & 0x1f; + uint8_t b = (col16 >> 1) & 0x1f; + rgba32_buf[4*i + 0] = SCALE_5_8(r); + rgba32_buf[4*i + 1] = SCALE_5_8(g); + rgba32_buf[4*i + 2] = SCALE_5_8(b); + rgba32_buf[4*i + 3] = a ? 255 : 0; + } + + uint32_t width = rdp.texture_tile.line_size_bytes / 2; + uint32_t height = rdp.loaded_texture[tile].size_bytes / rdp.texture_tile.line_size_bytes; + + gfx_rapi->upload_texture(rgba32_buf, width, height); +} + +static void import_texture_rgba32(int tile) { + uint32_t width = rdp.texture_tile.line_size_bytes / 2; + uint32_t height = (rdp.loaded_texture[tile].size_bytes / 2) / rdp.texture_tile.line_size_bytes; + gfx_rapi->upload_texture(rdp.loaded_texture[tile].addr, width, height); +} + +static void import_texture_ia4(int tile) { + uint8_t rgba32_buf[32768]; + + for (uint32_t i = 0; i < rdp.loaded_texture[tile].size_bytes * 2; i++) { + uint8_t byte = rdp.loaded_texture[tile].addr[i / 2]; + uint8_t part = (byte >> (4 - (i % 2) * 4)) & 0xf; + uint8_t intensity = part >> 1; + uint8_t alpha = part & 1; + uint8_t r = intensity; + uint8_t g = intensity; + uint8_t b = intensity; + rgba32_buf[4*i + 0] = SCALE_3_8(r); + rgba32_buf[4*i + 1] = SCALE_3_8(g); + rgba32_buf[4*i + 2] = SCALE_3_8(b); + rgba32_buf[4*i + 3] = alpha ? 255 : 0; + } + + uint32_t width = rdp.texture_tile.line_size_bytes * 2; + uint32_t height = rdp.loaded_texture[tile].size_bytes / rdp.texture_tile.line_size_bytes; + + gfx_rapi->upload_texture(rgba32_buf, width, height); +} + +static void import_texture_ia8(int tile) { + uint8_t rgba32_buf[16384]; + + for (uint32_t i = 0; i < rdp.loaded_texture[tile].size_bytes; i++) { + uint8_t intensity = rdp.loaded_texture[tile].addr[i] >> 4; + uint8_t alpha = rdp.loaded_texture[tile].addr[i] & 0xf; + uint8_t r = intensity; + uint8_t g = intensity; + uint8_t b = intensity; + rgba32_buf[4*i + 0] = SCALE_4_8(r); + rgba32_buf[4*i + 1] = SCALE_4_8(g); + rgba32_buf[4*i + 2] = SCALE_4_8(b); + rgba32_buf[4*i + 3] = SCALE_4_8(alpha); + } + + uint32_t width = rdp.texture_tile.line_size_bytes; + uint32_t height = rdp.loaded_texture[tile].size_bytes / rdp.texture_tile.line_size_bytes; + + gfx_rapi->upload_texture(rgba32_buf, width, height); +} + +static void import_texture_ia16(int tile) { + uint8_t rgba32_buf[8192]; + + for (uint32_t i = 0; i < rdp.loaded_texture[tile].size_bytes / 2; i++) { + uint8_t intensity = rdp.loaded_texture[tile].addr[2 * i]; + uint8_t alpha = rdp.loaded_texture[tile].addr[2 * i + 1]; + uint8_t r = intensity; + uint8_t g = intensity; + uint8_t b = intensity; + rgba32_buf[4*i + 0] = r; + rgba32_buf[4*i + 1] = g; + rgba32_buf[4*i + 2] = b; + rgba32_buf[4*i + 3] = alpha; + } + + uint32_t width = rdp.texture_tile.line_size_bytes / 2; + uint32_t height = rdp.loaded_texture[tile].size_bytes / rdp.texture_tile.line_size_bytes; + + gfx_rapi->upload_texture(rgba32_buf, width, height); +} + +static void import_texture_i4(int tile) { + uint8_t rgba32_buf[32768]; + + for (uint32_t i = 0; i < rdp.loaded_texture[tile].size_bytes * 2; i++) { + uint8_t byte = rdp.loaded_texture[tile].addr[i / 2]; + uint8_t part = (byte >> (4 - (i % 2) * 4)) & 0xf; + uint8_t intensity = part; + uint8_t r = intensity; + uint8_t g = intensity; + uint8_t b = intensity; + rgba32_buf[4*i + 0] = SCALE_4_8(r); + rgba32_buf[4*i + 1] = SCALE_4_8(g); + rgba32_buf[4*i + 2] = SCALE_4_8(b); + rgba32_buf[4*i + 3] = 255; + } + + uint32_t width = rdp.texture_tile.line_size_bytes * 2; + uint32_t height = rdp.loaded_texture[tile].size_bytes / rdp.texture_tile.line_size_bytes; + + gfx_rapi->upload_texture(rgba32_buf, width, height); +} + +static void import_texture_i8(int tile) { + uint8_t rgba32_buf[16384]; + + for (uint32_t i = 0; i < rdp.loaded_texture[tile].size_bytes; i++) { + uint8_t intensity = rdp.loaded_texture[tile].addr[i]; + uint8_t r = intensity; + uint8_t g = intensity; + uint8_t b = intensity; + rgba32_buf[4*i + 0] = r; + rgba32_buf[4*i + 1] = g; + rgba32_buf[4*i + 2] = b; + rgba32_buf[4*i + 3] = 255; + } + + uint32_t width = rdp.texture_tile.line_size_bytes; + uint32_t height = rdp.loaded_texture[tile].size_bytes / rdp.texture_tile.line_size_bytes; + + gfx_rapi->upload_texture(rgba32_buf, width, height); +} + + +static void import_texture_ci4(int tile) { + uint8_t rgba32_buf[32768]; + + for (uint32_t i = 0; i < rdp.loaded_texture[tile].size_bytes * 2; i++) { + uint8_t byte = rdp.loaded_texture[tile].addr[i / 2]; + uint8_t idx = (byte >> (4 - (i % 2) * 4)) & 0xf; + uint16_t col16 = (rdp.palette[idx * 2] << 8) | rdp.palette[idx * 2 + 1]; // Big endian load + uint8_t a = col16 & 1; + uint8_t r = col16 >> 11; + uint8_t g = (col16 >> 6) & 0x1f; + uint8_t b = (col16 >> 1) & 0x1f; + rgba32_buf[4*i + 0] = SCALE_5_8(r); + rgba32_buf[4*i + 1] = SCALE_5_8(g); + rgba32_buf[4*i + 2] = SCALE_5_8(b); + rgba32_buf[4*i + 3] = a ? 255 : 0; + } + + uint32_t width = rdp.texture_tile.line_size_bytes * 2; + uint32_t height = rdp.loaded_texture[tile].size_bytes / rdp.texture_tile.line_size_bytes; + + gfx_rapi->upload_texture(rgba32_buf, width, height); +} + +static void import_texture_ci8(int tile) { + uint8_t rgba32_buf[16384]; + + for (uint32_t i = 0; i < rdp.loaded_texture[tile].size_bytes; i++) { + uint8_t idx = rdp.loaded_texture[tile].addr[i]; + uint16_t col16 = (rdp.palette[idx * 2] << 8) | rdp.palette[idx * 2 + 1]; // Big endian load + uint8_t a = col16 & 1; + uint8_t r = col16 >> 11; + uint8_t g = (col16 >> 6) & 0x1f; + uint8_t b = (col16 >> 1) & 0x1f; + rgba32_buf[4*i + 0] = SCALE_5_8(r); + rgba32_buf[4*i + 1] = SCALE_5_8(g); + rgba32_buf[4*i + 2] = SCALE_5_8(b); + rgba32_buf[4*i + 3] = a ? 255 : 0; + } + + uint32_t width = rdp.texture_tile.line_size_bytes; + uint32_t height = rdp.loaded_texture[tile].size_bytes / rdp.texture_tile.line_size_bytes; + + gfx_rapi->upload_texture(rgba32_buf, width, height); +} + +static void import_texture(int tile) { + uint8_t fmt = rdp.texture_tile.fmt; + uint8_t siz = rdp.texture_tile.siz; + + if (gfx_texture_cache_lookup(tile, &rendering_state.textures[tile], rdp.loaded_texture[tile].addr, fmt, siz)) { + return; + } + + if (fmt == G_IM_FMT_RGBA) { + if (siz == G_IM_SIZ_16b) { + import_texture_rgba16(tile); + } else if (siz == G_IM_SIZ_32b) { + import_texture_rgba32(tile); + } else { + abort(); + } + } else if (fmt == G_IM_FMT_IA) { + if (siz == G_IM_SIZ_4b) { + import_texture_ia4(tile); + } else if (siz == G_IM_SIZ_8b) { + import_texture_ia8(tile); + } else if (siz == G_IM_SIZ_16b) { + import_texture_ia16(tile); + } else { + abort(); + } + } else if (fmt == G_IM_FMT_CI) { + if (siz == G_IM_SIZ_4b) { + import_texture_ci4(tile); + } else if (siz == G_IM_SIZ_8b) { + import_texture_ci8(tile); + } else { + abort(); + } + } else if (fmt == G_IM_FMT_I) { + if (siz == G_IM_SIZ_4b) { + import_texture_i4(tile); + } else if (siz == G_IM_SIZ_8b) { + import_texture_i8(tile); + } else { + abort(); + } + } else { + abort(); + } + //printf("Time diff: %d\n", t1 - t0); +} + +static void gfx_normalize_vector(float v[3]) { + float s = sqrtf(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); + v[0] /= s; + v[1] /= s; + v[2] /= s; +} + +static void gfx_transposed_matrix_mul(float res[3], const float a[3], const float b[4][4]) { + res[0] = a[0] * b[0][0] + a[1] * b[0][1] + a[2] * b[0][2]; + res[1] = a[0] * b[1][0] + a[1] * b[1][1] + a[2] * b[1][2]; + res[2] = a[0] * b[2][0] + a[1] * b[2][1] + a[2] * b[2][2]; +} + +static void calculate_normal_dir(const Light_t *light, float coeffs[3]) { + float light_dir[3] = { + light->dir[0] / 127.0f, + light->dir[1] / 127.0f, + light->dir[2] / 127.0f + }; + gfx_transposed_matrix_mul(coeffs, light_dir, rsp.modelview_matrix_stack[rsp.modelview_matrix_stack_size - 1]); + gfx_normalize_vector(coeffs); +} + +static void gfx_matrix_mul(float res[4][4], const float a[4][4], const float b[4][4]) { + float tmp[4][4]; + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + tmp[i][j] = a[i][0] * b[0][j] + + a[i][1] * b[1][j] + + a[i][2] * b[2][j] + + a[i][3] * b[3][j]; + } + } + memcpy(res, tmp, sizeof(tmp)); +} + +static void gfx_sp_matrix(uint8_t parameters, const int32_t *addr) { + float matrix[4][4]; +#ifndef GBI_FLOATS + // Original GBI where fixed point matrices are used + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j += 2) { + int32_t int_part = addr[i * 2 + j / 2]; + uint32_t frac_part = addr[8 + i * 2 + j / 2]; + matrix[i][j] = (int32_t)((int_part & 0xffff0000) | (frac_part >> 16)) / 65536.0f; + matrix[i][j + 1] = (int32_t)((int_part << 16) | (frac_part & 0xffff)) / 65536.0f; + } + } +#else + // For a modified GBI where fixed point values are replaced with floats + memcpy(matrix, addr, sizeof(matrix)); +#endif + + if (parameters & G_MTX_PROJECTION) { + if (parameters & G_MTX_LOAD) { + memcpy(rsp.P_matrix, matrix, sizeof(matrix)); + } else { + gfx_matrix_mul(rsp.P_matrix, matrix, rsp.P_matrix); + } + } else { // G_MTX_MODELVIEW + if ((parameters & G_MTX_PUSH) && rsp.modelview_matrix_stack_size < 11) { + ++rsp.modelview_matrix_stack_size; + memcpy(rsp.modelview_matrix_stack[rsp.modelview_matrix_stack_size - 1], rsp.modelview_matrix_stack[rsp.modelview_matrix_stack_size - 2], sizeof(matrix)); + } + if (parameters & G_MTX_LOAD) { + memcpy(rsp.modelview_matrix_stack[rsp.modelview_matrix_stack_size - 1], matrix, sizeof(matrix)); + } else { + gfx_matrix_mul(rsp.modelview_matrix_stack[rsp.modelview_matrix_stack_size - 1], matrix, rsp.modelview_matrix_stack[rsp.modelview_matrix_stack_size - 1]); + } + rsp.lights_changed = 1; + } + gfx_matrix_mul(rsp.MP_matrix, rsp.modelview_matrix_stack[rsp.modelview_matrix_stack_size - 1], rsp.P_matrix); +} + +static void gfx_sp_pop_matrix(uint32_t count) { + while (count--) { + if (rsp.modelview_matrix_stack_size > 0) { + --rsp.modelview_matrix_stack_size; + if (rsp.modelview_matrix_stack_size > 0) { + gfx_matrix_mul(rsp.MP_matrix, rsp.modelview_matrix_stack[rsp.modelview_matrix_stack_size - 1], rsp.P_matrix); + } + } + } +} + +static float gfx_adjust_x_for_aspect_ratio(float x) { + return x * (4.0f / 3.0f) / ((float)gfx_current_dimensions.width / (float)gfx_current_dimensions.height); +} + +static void gfx_sp_vertex(size_t n_vertices, size_t dest_index, const Vtx *vertices) { + for (size_t i = 0; i < n_vertices; i++, dest_index++) { + const Vtx* v = &vertices[i]; + struct LoadedVertex *d = &rsp.loaded_vertices[dest_index]; + + float x = v->v[0] * rsp.MP_matrix[0][0] + v->v[1] * rsp.MP_matrix[1][0] + v->v[2] * rsp.MP_matrix[2][0] + rsp.MP_matrix[3][0]; + float y = v->v[0] * rsp.MP_matrix[0][1] + v->v[1] * rsp.MP_matrix[1][1] + v->v[2] * rsp.MP_matrix[2][1] + rsp.MP_matrix[3][1]; + float z = v->v[0] * rsp.MP_matrix[0][2] + v->v[1] * rsp.MP_matrix[1][2] + v->v[2] * rsp.MP_matrix[2][2] + rsp.MP_matrix[3][2]; + float w = v->v[0] * rsp.MP_matrix[0][3] + v->v[1] * rsp.MP_matrix[1][3] + v->v[2] * rsp.MP_matrix[2][3] + rsp.MP_matrix[3][3]; + + x = gfx_adjust_x_for_aspect_ratio(x); + + short U = v->s * rsp.texture_scaling_factor.s >> 16; + short V = v->t * rsp.texture_scaling_factor.t >> 16; + + union Vec4b* normcolor = &rsp.vertex_color_table[v->colour]; + + if (rsp.geometry_mode & G_LIGHTING) { + if (rsp.lights_changed) { + for (int i = 0; i < rsp.current_num_lights - 1; i++) { + calculate_normal_dir(&rsp.current_lights[i], rsp.current_lights_coeffs[i]); + } + static const Light_t lookat_x = { {0, 0, 0}, 0, {0, 0, 0}, 0, {127, 0, 0}, 0 }; + static const Light_t lookat_y = { {0, 0, 0}, 0, {0, 0, 0}, 0, {0, 127, 0}, 0 }; + calculate_normal_dir(&lookat_x, rsp.current_lookat_coeffs[0]); + calculate_normal_dir(&lookat_y, rsp.current_lookat_coeffs[1]); + rsp.lights_changed = false; + } + + int r = rsp.current_lights[rsp.current_num_lights - 1].col[0]; + int g = rsp.current_lights[rsp.current_num_lights - 1].col[1]; + int b = rsp.current_lights[rsp.current_num_lights - 1].col[2]; + + for (int i = 0; i < rsp.current_num_lights - 1; i++) { + float intensity = 0; + intensity += normcolor->x * rsp.current_lights_coeffs[i][0]; + intensity += normcolor->y * rsp.current_lights_coeffs[i][1]; + intensity += normcolor->z * rsp.current_lights_coeffs[i][2]; + intensity /= 127.0f; + if (intensity > 0.0f) { + r += intensity * rsp.current_lights[i].col[0]; + g += intensity * rsp.current_lights[i].col[1]; + b += intensity * rsp.current_lights[i].col[2]; + } + } + + d->color.r = r > 255 ? 255 : r; + d->color.g = g > 255 ? 255 : g; + d->color.b = b > 255 ? 255 : b; + + if (rsp.geometry_mode & G_TEXTURE_GEN) { + float dotx = 0, doty = 0; + dotx += normcolor->x * rsp.current_lookat_coeffs[0][0]; + dotx += normcolor->y * rsp.current_lookat_coeffs[0][1]; + dotx += normcolor->z * rsp.current_lookat_coeffs[0][2]; + doty += normcolor->x * rsp.current_lookat_coeffs[1][0]; + doty += normcolor->y * rsp.current_lookat_coeffs[1][1]; + doty += normcolor->z * rsp.current_lookat_coeffs[1][2]; + + float ssc = rsp.texture_scaling_factor.s; + float tsc = rsp.texture_scaling_factor.t; + + //U = (int32_t)((dotx / 127.0f + 1.0f) / 4.0f * rsp.texture_scaling_factor.s); + //V = (int32_t)((doty / 127.0f + 1.0f) / 4.0f * rsp.texture_scaling_factor.t); + + U = (int32_t)((dotx / 127.0f + 1.0f) / 4.0f * ssc); + V = (int32_t)((doty / 127.0f + 1.0f) / 4.0f * tsc); + } + } else { + d->color.r = normcolor->r; + d->color.g = normcolor->g; + d->color.b = normcolor->b; + } + + d->u = U; + d->v = V; + + // trivial clip rejection + d->clip_rej = 0; + if (x < -w) d->clip_rej |= 1; + if (x > w) d->clip_rej |= 2; + if (y < -w) d->clip_rej |= 4; + if (y > w) d->clip_rej |= 8; + if (z < -w) d->clip_rej |= 16; + if (z > w) d->clip_rej |= 32; + + d->x = x; + d->y = y; + d->z = z; + d->w = w; + + if (rsp.geometry_mode & G_FOG) { + if (fabsf(w) < 0.001f) { + // To avoid division by zero + w = 0.001f; + } + + float winv = 1.0f / w; + if (winv < 0.0f) { + winv = 32767.0f; + } + + float fog_z = z * winv * rsp.fog_mul + rsp.fog_offset; + if (fog_z < 0) fog_z = 0; + if (fog_z > 255) fog_z = 255; + d->color.a = fog_z; // Use alpha variable to store fog factor + } else { + d->color.a = normcolor->a; + } + } +} + +static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx) { + struct LoadedVertex *v1 = &rsp.loaded_vertices[vtx1_idx]; + struct LoadedVertex *v2 = &rsp.loaded_vertices[vtx2_idx]; + struct LoadedVertex *v3 = &rsp.loaded_vertices[vtx3_idx]; + struct LoadedVertex *v_arr[3] = {v1, v2, v3}; + + //if (rand()%2) return; + + if (v1->clip_rej & v2->clip_rej & v3->clip_rej) { + // The whole triangle lies outside the visible area + return; + } + + if ((rsp.geometry_mode & G_CULL_BOTH) != 0) { + float dx1 = v1->x / (v1->w) - v2->x / (v2->w); + float dy1 = v1->y / (v1->w) - v2->y / (v2->w); + float dx2 = v3->x / (v3->w) - v2->x / (v2->w); + float dy2 = v3->y / (v3->w) - v2->y / (v2->w); + float cross = dx1 * dy2 - dy1 * dx2; + + if ((v1->w < 0) ^ (v2->w < 0) ^ (v3->w < 0)) { + // If one vertex lies behind the eye, negating cross will give the correct result. + // If all vertices lie behind the eye, the triangle will be rejected anyway. + cross = -cross; + } + + switch (rsp.geometry_mode & G_CULL_BOTH) { + case G_CULL_FRONT: + if (cross <= 0) return; + break; + case G_CULL_BACK: + if (cross >= 0) return; + break; + case G_CULL_BOTH: + // Why is this even an option? + return; + } + } + + bool depth_test = (rsp.geometry_mode & G_ZBUFFER) == G_ZBUFFER; + if (depth_test != rendering_state.depth_test) { + gfx_flush(); + gfx_rapi->set_depth_test(depth_test); + rendering_state.depth_test = depth_test; + } + + bool z_upd = (rdp.other_mode_l & Z_UPD) == Z_UPD; + if (z_upd != rendering_state.depth_mask) { + gfx_flush(); + gfx_rapi->set_depth_mask(z_upd); + rendering_state.depth_mask = z_upd; + } + + bool zmode_decal = (rdp.other_mode_l & ZMODE_DEC) == ZMODE_DEC; + if (zmode_decal != rendering_state.decal_mode) { + gfx_flush(); + gfx_rapi->set_zmode_decal(zmode_decal); + rendering_state.decal_mode = zmode_decal; + } + + if (rdp.viewport_or_scissor_changed) { + if (memcmp(&rdp.viewport, &rendering_state.viewport, sizeof(rdp.viewport)) != 0) { + gfx_flush(); + gfx_rapi->set_viewport(rdp.viewport.x, rdp.viewport.y, rdp.viewport.width, rdp.viewport.height); + rendering_state.viewport = rdp.viewport; + } + if (memcmp(&rdp.scissor, &rendering_state.scissor, sizeof(rdp.scissor)) != 0) { + gfx_flush(); + gfx_rapi->set_scissor(rdp.scissor.x, rdp.scissor.y, rdp.scissor.width, rdp.scissor.height); + rendering_state.scissor = rdp.scissor; + } + rdp.viewport_or_scissor_changed = false; + } + + uint32_t cc_id = rdp.combine_mode; + + bool use_alpha = (rdp.other_mode_l & (G_BL_A_MEM << 18)) == 0; + bool use_fog = (rdp.other_mode_l >> 30) == G_BL_CLR_FOG; + bool texture_edge = (rdp.other_mode_l & CVG_X_ALPHA) == CVG_X_ALPHA; + bool use_noise = (rdp.other_mode_l & G_AC_DITHER) == G_AC_DITHER; + + if (texture_edge) { + use_alpha = true; + } + + if (use_alpha) cc_id |= SHADER_OPT_ALPHA; + if (use_fog) cc_id |= SHADER_OPT_FOG; + if (texture_edge) cc_id |= SHADER_OPT_TEXTURE_EDGE; + if (use_noise) cc_id |= SHADER_OPT_NOISE; + + if (!use_alpha) { + cc_id &= ~0xfff000; + } + + struct ColorCombiner *comb = gfx_lookup_or_create_color_combiner(cc_id); + struct ShaderProgram *prg = comb->prg; + if (prg != rendering_state.shader_program) { + gfx_flush(); + gfx_rapi->unload_shader(rendering_state.shader_program); + gfx_rapi->load_shader(prg); + rendering_state.shader_program = prg; + } + if (use_alpha != rendering_state.alpha_blend) { + gfx_flush(); + gfx_rapi->set_use_alpha(use_alpha); + rendering_state.alpha_blend = use_alpha; + } + uint8_t num_inputs; + bool used_textures[2]; + gfx_rapi->shader_get_info(prg, &num_inputs, used_textures); + + for (int i = 0; i < 2; i++) { + if (used_textures[i]) { + if (rdp.textures_changed[i]) { + gfx_flush(); + import_texture(i); + rdp.textures_changed[i] = false; + } + bool linear_filter = (rdp.other_mode_h & (3U << G_MDSFT_TEXTFILT)) != G_TF_POINT; + if (linear_filter != rendering_state.textures[i]->linear_filter || rdp.texture_tile.cms != rendering_state.textures[i]->cms || rdp.texture_tile.cmt != rendering_state.textures[i]->cmt) { + gfx_flush(); + gfx_rapi->set_sampler_parameters(i, linear_filter, rdp.texture_tile.cms, rdp.texture_tile.cmt); + rendering_state.textures[i]->linear_filter = linear_filter; + rendering_state.textures[i]->cms = rdp.texture_tile.cms; + rendering_state.textures[i]->cmt = rdp.texture_tile.cmt; + } + } + } + + bool use_texture = used_textures[0] || used_textures[1]; + uint32_t tex_width = (rdp.texture_tile.lrs - rdp.texture_tile.uls + 4) / 4; + uint32_t tex_height = (rdp.texture_tile.lrt - rdp.texture_tile.ult + 4) / 4; + + bool z_is_from_0_to_1 = gfx_rapi->z_is_from_0_to_1(); + + for (int i = 0; i < 3; i++) { + float z = v_arr[i]->z, w = v_arr[i]->w; + if (z_is_from_0_to_1) { + z = (z + w) / 2.0f; + } + buf_vbo[buf_vbo_len++] = v_arr[i]->x; + buf_vbo[buf_vbo_len++] = v_arr[i]->y; + buf_vbo[buf_vbo_len++] = z; + buf_vbo[buf_vbo_len++] = w; + + if (use_texture) { + float u = (v_arr[i]->u - rdp.texture_tile.uls * 8) / 32.0f; + float v = (v_arr[i]->v - rdp.texture_tile.ult * 8) / 32.0f; + if ((rdp.other_mode_h & (3U << G_MDSFT_TEXTFILT)) != G_TF_POINT) { + // Linear filter adds 0.5f to the coordinates + u += 0.5f; + v += 0.5f; + } + buf_vbo[buf_vbo_len++] = u / tex_width; + buf_vbo[buf_vbo_len++] = v / tex_height; + } + + if (use_fog) { + buf_vbo[buf_vbo_len++] = rdp.fog_color.r / 255.0f; + buf_vbo[buf_vbo_len++] = rdp.fog_color.g / 255.0f; + buf_vbo[buf_vbo_len++] = rdp.fog_color.b / 255.0f; + buf_vbo[buf_vbo_len++] = v_arr[i]->color.a / 255.0f; // fog factor (not alpha) + } + + for (int j = 0; j < num_inputs; j++) { + struct RGBA *color; + struct RGBA tmp; + for (int k = 0; k < 1 + (use_alpha ? 1 : 0); k++) { + switch (comb->shader_input_mapping[k][j]) { + case CC_PRIM: + color = &rdp.prim_color; + break; + case CC_SHADE: + color = &v_arr[i]->color; + break; + case CC_ENV: + color = &rdp.env_color; + break; + case CC_LOD: + { + float distance_frac = (v1->w - 3000.0f) / 3000.0f; + if (distance_frac < 0.0f) distance_frac = 0.0f; + if (distance_frac > 1.0f) distance_frac = 1.0f; + tmp.r = tmp.g = tmp.b = tmp.a = distance_frac * 255.0f; + color = &tmp; + break; + } + default: + memset(&tmp, 0, sizeof(tmp)); + color = &tmp; + break; + } + if (k == 0) { + buf_vbo[buf_vbo_len++] = color->r / 255.0f; + buf_vbo[buf_vbo_len++] = color->g / 255.0f; + buf_vbo[buf_vbo_len++] = color->b / 255.0f; + } else { + if (use_fog && color == &v_arr[i]->color) { + // Shade alpha is 100% for fog + buf_vbo[buf_vbo_len++] = 1.0f; + } else { + buf_vbo[buf_vbo_len++] = color->a / 255.0f; + } + } + } + } + /*struct RGBA *color = &v_arr[i]->color; + buf_vbo[buf_vbo_len++] = color->r / 255.0f; + buf_vbo[buf_vbo_len++] = color->g / 255.0f; + buf_vbo[buf_vbo_len++] = color->b / 255.0f; + buf_vbo[buf_vbo_len++] = color->a / 255.0f;*/ + } + if (++buf_vbo_num_tris == MAX_BUFFERED) { + gfx_flush(); + } +} + +static void gfx_sp_geometry_mode(uint32_t clear, uint32_t set) { + rsp.geometry_mode &= ~clear; + rsp.geometry_mode |= set; +} + +static void gfx_calc_and_set_viewport(const Vp_t *viewport) { + // 2 bits fraction + float width = 2.0f * viewport->vscale[0] / 4.0f; + float height = 2.0f * viewport->vscale[1] / 4.0f; + float x = (viewport->vtrans[0] / 4.0f) - width / 2.0f; + float y = SCREEN_HEIGHT - ((viewport->vtrans[1] / 4.0f) + height / 2.0f); + + width *= RATIO_X; + height *= RATIO_Y; + x *= RATIO_X; + y *= RATIO_Y; + + rdp.viewport.x = x; + rdp.viewport.y = y; + rdp.viewport.width = width; + rdp.viewport.height = height; + + rdp.viewport_or_scissor_changed = true; +} + +static void gfx_sp_movemem(uint8_t index, uint8_t offset, const void* data) { + switch (index) { + case G_MV_VIEWPORT: + gfx_calc_and_set_viewport((const Vp_t *) data); + break; +#if 0 + case G_MV_LOOKATY: + case G_MV_LOOKATX: + memcpy(rsp.current_lookat + (index - G_MV_LOOKATY) / 2, data, sizeof(Light_t)); + //rsp.lights_changed = 1; + break; +#endif +#ifdef F3DEX_GBI_2 + case G_MV_LIGHT: { + int lightidx = offset / 24 - 2; + if (lightidx >= 0 && lightidx <= MAX_LIGHTS) { // skip lookat + // NOTE: reads out of bounds if it is an ambient light + memcpy(rsp.current_lights + lightidx, data, sizeof(Light_t)); + } + break; + } +#else + case G_MV_L0: + case G_MV_L1: + case G_MV_L2: + // NOTE: reads out of bounds if it is an ambient light + memcpy(rsp.current_lights + (index - G_MV_L0) / 2, data, sizeof(Light_t)); + break; +#endif + } +} + +static void gfx_sp_moveword(uint8_t index, uint16_t offset, uintptr_t data) { + switch (index) { + case G_MW_NUMLIGHT: +#ifdef F3DEX_GBI_2 + rsp.current_num_lights = data / 24 + 1; // add ambient light +#else + // Ambient light is included + // The 31th bit is a flag that lights should be recalculated + rsp.current_num_lights = (data - 0x80000000U) / 32; +#endif + rsp.lights_changed = 1; + break; + case G_MW_FOG: + rsp.fog_mul = (int16_t)(data >> 16); + rsp.fog_offset = (int16_t)data; + break; + case G_MW_SEGMENT: + rsp.segment_addrs[(offset >> 2) & 0xf] = data; + break; + } +} + +static void gfx_sp_texture(uint16_t sc, uint16_t tc, uint8_t level, uint8_t tile, uint8_t on) { + rsp.texture_scaling_factor.s = sc; + rsp.texture_scaling_factor.t = tc; +} + +static void gfx_dp_set_scissor(uint32_t mode, uint32_t ulx, uint32_t uly, uint32_t lrx, uint32_t lry) { + float x = ulx / 4.0f * RATIO_X; + float y = (SCREEN_HEIGHT - lry / 4.0f) * RATIO_Y; + float width = (lrx - ulx) / 4.0f * RATIO_X; + float height = (lry - uly) / 4.0f * RATIO_Y; + + rdp.scissor.x = x; + rdp.scissor.y = y; + rdp.scissor.width = width; + rdp.scissor.height = height; + + rdp.viewport_or_scissor_changed = true; +} + +static void gfx_dp_set_texture_image(uint32_t format, uint32_t size, uint32_t width, const void* addr) { + rdp.texture_to_load.addr = addr; + rdp.texture_to_load.siz = size; +} + +static void gfx_dp_set_tile(uint8_t fmt, uint32_t siz, uint32_t line, uint32_t tmem, uint8_t tile, uint32_t palette, uint32_t cmt, uint32_t maskt, uint32_t shiftt, uint32_t cms, uint32_t masks, uint32_t shifts) { + if (tile == G_TX_RENDERTILE) { + SUPPORT_CHECK(palette == 0); // palette should set upper 4 bits of color index in 4b mode + rdp.texture_tile.fmt = fmt; + rdp.texture_tile.siz = siz; + rdp.texture_tile.cms = cms; + rdp.texture_tile.cmt = cmt; + rdp.texture_tile.line_size_bytes = line * 8; + rdp.textures_changed[0] = true; + rdp.textures_changed[1] = true; + } + + if (tile == G_TX_LOADTILE) { + rdp.texture_to_load.tile_number = tmem / 256; + } +} + +static void gfx_dp_set_tile_size(uint8_t tile, uint16_t uls, uint16_t ult, uint16_t lrs, uint16_t lrt) { + if (tile == G_TX_RENDERTILE) { + rdp.texture_tile.uls = uls; + rdp.texture_tile.ult = ult; + rdp.texture_tile.lrs = lrs; + rdp.texture_tile.lrt = lrt; + rdp.textures_changed[0] = true; + rdp.textures_changed[1] = true; + } +} + +static void gfx_dp_load_tlut(uint8_t tile, uint32_t high_index) { + //SUPPORT_CHECK(tile == G_TX_LOADTILE); + SUPPORT_CHECK(rdp.texture_to_load.siz == G_IM_SIZ_16b); + rdp.palette = rdp.texture_to_load.addr; +} + +static void gfx_dp_load_block(uint8_t tile, uint32_t uls, uint32_t ult, uint32_t lrs, uint32_t dxt) { + if (tile == 1) return; + // SUPPORT_CHECK(tile == G_TX_LOADTILE); + SUPPORT_CHECK(uls == 0); + SUPPORT_CHECK(ult == 0); + + // The lrs field rather seems to be number of pixels to load + uint32_t word_size_shift; + switch (rdp.texture_to_load.siz) { + case G_IM_SIZ_4b: + word_size_shift = 0; // Or -1? It's unused in SM64 anyway. + break; + case G_IM_SIZ_8b: + word_size_shift = 0; + break; + case G_IM_SIZ_16b: + word_size_shift = 1; + break; + case G_IM_SIZ_32b: + word_size_shift = 2; + break; + } + uint32_t size_bytes = (lrs + 1) << word_size_shift; + rdp.loaded_texture[rdp.texture_to_load.tile_number].size_bytes = size_bytes; + assert(size_bytes <= 4096 && "bug: too big texture"); + rdp.loaded_texture[rdp.texture_to_load.tile_number].addr = rdp.texture_to_load.addr; + + rdp.textures_changed[rdp.texture_to_load.tile_number] = true; +} + +static void gfx_dp_load_tile(uint8_t tile, uint32_t uls, uint32_t ult, uint32_t lrs, uint32_t lrt) { + if (tile == 1) return; + SUPPORT_CHECK(tile == G_TX_LOADTILE); + SUPPORT_CHECK(uls == 0); + SUPPORT_CHECK(ult == 0); + + uint32_t word_size_shift; + switch (rdp.texture_to_load.siz) { + case G_IM_SIZ_4b: + word_size_shift = 0; + break; + case G_IM_SIZ_8b: + word_size_shift = 0; + break; + case G_IM_SIZ_16b: + word_size_shift = 1; + break; + case G_IM_SIZ_32b: + word_size_shift = 2; + break; + } + + uint32_t size_bytes = (((lrs >> G_TEXTURE_IMAGE_FRAC) + 1) * ((lrt >> G_TEXTURE_IMAGE_FRAC) + 1)) << word_size_shift; + rdp.loaded_texture[rdp.texture_to_load.tile_number].size_bytes = size_bytes; + + assert(size_bytes <= 4096 && "bug: too big texture"); + rdp.loaded_texture[rdp.texture_to_load.tile_number].addr = rdp.texture_to_load.addr; + rdp.texture_tile.uls = uls; + rdp.texture_tile.ult = ult; + rdp.texture_tile.lrs = lrs; + rdp.texture_tile.lrt = lrt; + + rdp.textures_changed[rdp.texture_to_load.tile_number] = true; +} + + +static uint8_t color_comb_component(uint32_t v) { + switch (v) { + case G_CCMUX_TEXEL0: + return CC_TEXEL0; + case G_CCMUX_TEXEL1: + return CC_TEXEL1; + case G_CCMUX_PRIMITIVE: + return CC_PRIM; + case G_CCMUX_SHADE: + return CC_SHADE; + case G_CCMUX_ENVIRONMENT: + return CC_ENV; + case G_CCMUX_TEXEL0_ALPHA: + return CC_TEXEL0A; + case G_CCMUX_LOD_FRACTION: + return CC_LOD; + default: + return CC_0; + } +} + +static inline uint32_t color_comb(uint32_t a, uint32_t b, uint32_t c, uint32_t d) { + return color_comb_component(a) | + (color_comb_component(b) << 3) | + (color_comb_component(c) << 6) | + (color_comb_component(d) << 9); +} + +static void gfx_dp_set_combine_mode(uint32_t rgb, uint32_t alpha) { + rdp.combine_mode = rgb | (alpha << 12); +} + +static void gfx_dp_set_env_color(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { + rdp.env_color.r = r; + rdp.env_color.g = g; + rdp.env_color.b = b; + rdp.env_color.a = a; +} + +static void gfx_dp_set_prim_color(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { + rdp.prim_color.r = r; + rdp.prim_color.g = g; + rdp.prim_color.b = b; + rdp.prim_color.a = a; + rdp.fill_color.r = r; + rdp.fill_color.g = g; + rdp.fill_color.b = b; + rdp.fill_color.a = a; +} + +static void gfx_dp_set_fog_color(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { + rdp.fog_color.r = r; + rdp.fog_color.g = g; + rdp.fog_color.b = b; + rdp.fog_color.a = a; +} + +static void gfx_dp_set_fill_color(uint32_t packed_color) { + uint16_t col16 = (uint16_t)packed_color; + uint32_t r = col16 >> 11; + uint32_t g = (col16 >> 6) & 0x1f; + uint32_t b = (col16 >> 1) & 0x1f; + uint32_t a = col16 & 1; + rdp.fill_color.r = SCALE_5_8(r); + rdp.fill_color.g = SCALE_5_8(g); + rdp.fill_color.b = SCALE_5_8(b); + rdp.fill_color.a = a * 255; +} + +static void gfx_draw_rectangle(int32_t ulx, int32_t uly, int32_t lrx, int32_t lry) { + uint32_t saved_other_mode_h = rdp.other_mode_h; + uint32_t cycle_type = (rdp.other_mode_h & (3U << G_MDSFT_CYCLETYPE)); + + if (cycle_type == G_CYC_COPY) { + rdp.other_mode_h = (rdp.other_mode_h & ~(3U << G_MDSFT_TEXTFILT)) | G_TF_POINT; + } + + // U10.2 coordinates + float ulxf = ulx; + float ulyf = uly; + float lrxf = lrx; + float lryf = lry; + + ulxf = ulxf / (4.0f * HALF_SCREEN_WIDTH) - 1.0f; + ulyf = -(ulyf / (4.0f * HALF_SCREEN_HEIGHT)) + 1.0f; + lrxf = lrxf / (4.0f * HALF_SCREEN_WIDTH) - 1.0f; + lryf = -(lryf / (4.0f * HALF_SCREEN_HEIGHT)) + 1.0f; + + ulxf = gfx_adjust_x_for_aspect_ratio(ulxf); + lrxf = gfx_adjust_x_for_aspect_ratio(lrxf); + + struct LoadedVertex* ul = &rsp.loaded_vertices[MAX_VERTICES + 0]; + struct LoadedVertex* ll = &rsp.loaded_vertices[MAX_VERTICES + 1]; + struct LoadedVertex* lr = &rsp.loaded_vertices[MAX_VERTICES + 2]; + struct LoadedVertex* ur = &rsp.loaded_vertices[MAX_VERTICES + 3]; + + ul->x = ulxf; + ul->y = ulyf; + ul->z = -1.0f; + ul->w = 1.0f; + + ll->x = ulxf; + ll->y = lryf; + ll->z = -1.0f; + ll->w = 1.0f; + + lr->x = lrxf; + lr->y = lryf; + lr->z = -1.0f; + lr->w = 1.0f; + + ur->x = lrxf; + ur->y = ulyf; + ur->z = -1.0f; + ur->w = 1.0f; + + // The coordinates for texture rectangle shall bypass the viewport setting + struct XYWidthHeight default_viewport = {0, 0, gfx_current_dimensions.width, gfx_current_dimensions.height}; + struct XYWidthHeight viewport_saved = rdp.viewport; + uint32_t geometry_mode_saved = rsp.geometry_mode; + + rdp.viewport = default_viewport; + rdp.viewport_or_scissor_changed = true; + rsp.geometry_mode = 0; + + gfx_sp_tri1(MAX_VERTICES + 0, MAX_VERTICES + 1, MAX_VERTICES + 3); + gfx_sp_tri1(MAX_VERTICES + 1, MAX_VERTICES + 2, MAX_VERTICES + 3); + + rsp.geometry_mode = geometry_mode_saved; + rdp.viewport = viewport_saved; + rdp.viewport_or_scissor_changed = true; + + if (cycle_type == G_CYC_COPY) { + rdp.other_mode_h = saved_other_mode_h; + } +} + +static void gfx_dp_texture_rectangle(int32_t ulx, int32_t uly, int32_t lrx, int32_t lry, uint8_t tile, int16_t uls, int16_t ult, int16_t dsdx, int16_t dtdy, bool flip) { + uint32_t saved_combine_mode = rdp.combine_mode; + if ((rdp.other_mode_h & (3U << G_MDSFT_CYCLETYPE)) == G_CYC_COPY) { + // Per RDP Command Summary Set Tile's shift s and this dsdx should be set to 4 texels + // Divide by 4 to get 1 instead + dsdx >>= 2; + + // Color combiner is turned off in copy mode + gfx_dp_set_combine_mode(color_comb(0, 0, 0, G_CCMUX_TEXEL0), color_comb(0, 0, 0, G_ACMUX_TEXEL0)); + + // Per documentation one extra pixel is added in this modes to each edge + lrx += 1 << 2; + lry += 1 << 2; + } + + // uls and ult are S10.5 + // dsdx and dtdy are S5.10 + // lrx, lry, ulx, uly are U10.2 + // lrs, lrt are S10.5 + if (flip) { + dsdx = -dsdx; + dtdy = -dtdy; + } + int16_t width = !flip ? lrx - ulx : lry - uly; + int16_t height = !flip ? lry - uly : lrx - ulx; + float lrs = ((uls << 7) + dsdx * width) >> 7; + float lrt = ((ult << 7) + dtdy * height) >> 7; + + struct LoadedVertex* ul = &rsp.loaded_vertices[MAX_VERTICES + 0]; + struct LoadedVertex* ll = &rsp.loaded_vertices[MAX_VERTICES + 1]; + struct LoadedVertex* lr = &rsp.loaded_vertices[MAX_VERTICES + 2]; + struct LoadedVertex* ur = &rsp.loaded_vertices[MAX_VERTICES + 3]; + ul->u = uls; + ul->v = ult; + lr->u = lrs; + lr->v = lrt; + if (!flip) { + ll->u = uls; + ll->v = lrt; + ur->u = lrs; + ur->v = ult; + } else { + ll->u = lrs; + ll->v = ult; + ur->u = uls; + ur->v = lrt; + } + + gfx_draw_rectangle(ulx, uly, lrx, lry); + rdp.combine_mode = saved_combine_mode; +} + +static void gfx_dp_fill_rectangle(int32_t ulx, int32_t uly, int32_t lrx, int32_t lry) { + if (rdp.color_image_address == rdp.z_buf_address) { + // Don't clear Z buffer here since we already did it with glClear + return; + } + uint32_t mode = (rdp.other_mode_h & (3U << G_MDSFT_CYCLETYPE)); + + if (mode == G_CYC_COPY || mode == G_CYC_FILL) { + // Per documentation one extra pixel is added in this modes to each edge + lrx += 1 << 2; + lry += 1 << 2; + } + + for (int i = MAX_VERTICES; i < MAX_VERTICES + 4; i++) { + struct LoadedVertex* v = &rsp.loaded_vertices[i]; + v->color = rdp.fill_color; + } + + uint32_t saved_combine_mode = rdp.combine_mode; + gfx_dp_set_combine_mode(color_comb(0, 0, 0, G_CCMUX_SHADE), color_comb(0, 0, 0, G_ACMUX_SHADE)); + gfx_draw_rectangle(ulx, uly, lrx, lry); + rdp.combine_mode = saved_combine_mode; +} + +static void gfx_dp_set_z_image(void *z_buf_address) { + rdp.z_buf_address = z_buf_address; +} + +static void gfx_dp_set_color_image(uint32_t format, uint32_t size, uint32_t width, void* address) { + rdp.color_image_address = address; +} + +static void gfx_sp_set_other_mode(uint32_t shift, uint32_t num_bits, uint64_t mode) { + uint64_t mask = (((uint64_t)1 << num_bits) - 1) << shift; + uint64_t om = rdp.other_mode_l | ((uint64_t)rdp.other_mode_h << 32); + om = (om & ~mask) | mode; + rdp.other_mode_l = (uint32_t)om; + rdp.other_mode_h = (uint32_t)(om >> 32); +} + +static void gfx_sp_set_vertex_colors(uint32_t count, union Vec4b* rgba) { + for (int i = 0; i < count; i++) + rsp.vertex_color_table[i] = rgba[i]; +} + +static inline void *seg_addr(const uintptr_t w1) { + const uintptr_t seg = (w1 & 0x0f000000) >> 24; + if (seg > 0 && rsp.segment_addrs[seg] > 0) { + // Yuk. + const uintptr_t addr = (w1 & 0x00ffffff); + if (addr > (512 * 1024)) + return (void *) w1; + return (void *)(addr + rsp.segment_addrs[seg]); + } + return (void *) w1; +} + +#define C0(pos, width) ((cmd->words.w0 >> (pos)) & ((1U << width) - 1)) +#define C1(pos, width) ((cmd->words.w1 >> (pos)) & ((1U << width) - 1)) + +static void gfx_run_dl(Gfx* cmd) { + int dummy = 0; + for (;;) { + uint32_t opcode = cmd->words.w0 >> 24; + + switch (opcode) { + // RSP commands: + case G_MTX: +#ifdef F3DEX_GBI_2 + gfx_sp_matrix(C0(0, 8) ^ G_MTX_PUSH, (const int32_t *) seg_addr(cmd->words.w1)); +#else + gfx_sp_matrix(C0(16, 8), (const int32_t *) seg_addr(cmd->words.w1)); +#endif + break; + case (uint8_t)G_POPMTX: +#ifdef F3DEX_GBI_2 + gfx_sp_pop_matrix(cmd->words.w1 / 64); +#else + gfx_sp_pop_matrix(1); +#endif + break; + case G_MOVEMEM: +#ifdef F3DEX_GBI_2 + gfx_sp_movemem(C0(0, 8), C0(8, 8) * 8, seg_addr(cmd->words.w1)); +#else + gfx_sp_movemem(C0(16, 8), 0, seg_addr(cmd->words.w1)); +#endif + break; + case (uint8_t)G_MOVEWORD: +#ifdef F3DEX_GBI_2 + gfx_sp_moveword(C0(16, 8), C0(0, 16), cmd->words.w1); +#else + gfx_sp_moveword(C0(0, 8), C0(8, 16), cmd->words.w1); +#endif + break; + case (uint8_t)G_TEXTURE: +#ifdef F3DEX_GBI_2 + gfx_sp_texture(C1(16, 16), C1(0, 16), C0(11, 3), C0(8, 3), C0(1, 7)); +#else + gfx_sp_texture(C1(16, 16), C1(0, 16), C0(11, 3), C0(8, 3), C0(0, 8)); +#endif + break; + case G_VTX: +#ifdef F3DEX_GBI_2 + gfx_sp_vertex(C0(12, 8), C0(1, 7) - C0(12, 8), seg_addr(cmd->words.w1)); +#elif defined(F3DEX_GBI) || defined(F3DLP_GBI) + gfx_sp_vertex(C0(10, 6), C0(16, 8) / 2, seg_addr(cmd->words.w1)); +#else + gfx_sp_vertex(C0(12, 4), C0(8, 4), seg_addr(cmd->words.w1)); +#endif + break; + case G_DL: + if (C0(16, 1) == 0) { + // Push return address + gfx_run_dl((Gfx *)seg_addr(cmd->words.w1)); + } else { + cmd = (Gfx *)seg_addr(cmd->words.w1); + --cmd; // increase after break + } + break; + case (uint8_t)G_ENDDL: + return; +#ifdef F3DEX_GBI_2 + case G_GEOMETRYMODE: + gfx_sp_geometry_mode(~C0(0, 24), cmd->words.w1); + break; +#else + case (uint8_t)G_SETGEOMETRYMODE: + gfx_sp_geometry_mode(0, cmd->words.w1); + break; + case (uint8_t)G_CLEARGEOMETRYMODE: + gfx_sp_geometry_mode(cmd->words.w1, 0); + break; +#endif + case (uint8_t)G_TRI1: +#ifdef F3DEX_GBI_2 + gfx_sp_tri1(C0(16, 8) / 2, C0(8, 8) / 2, C0(0, 8) / 2); +#elif defined(F3DEX_GBI) || defined(F3DLP_GBI) + gfx_sp_tri1(C1(16, 8) / 2, C1(8, 8) / 2, C1(0, 8) / 2); +#else + gfx_sp_tri1(C1(16, 8) / 10, C1(8, 8) / 10, C1(0, 8) / 10); +#endif + break; +#if defined(F3DEX_GBI) || defined(F3DLP_GBI) + case (uint8_t)G_TRI2: + gfx_sp_tri1(C0(16, 8) / 2, C0(8, 8) / 2, C0(0, 8) / 2); + gfx_sp_tri1(C1(16, 8) / 2, C1(8, 8) / 2, C1(0, 8) / 2); + break; +#endif + case (uint8_t)G_TRI4: + gfx_sp_tri1(C1(0, 4), C1(4, 4), C0(0, 4)); + gfx_sp_tri1(C1(8, 4), C1(12, 4), C0(4, 4)); + gfx_sp_tri1(C1(16, 4), C1(20, 4), C0(8, 4)); + gfx_sp_tri1(C1(24, 4), C1(28, 4), C0(12, 4)); + break; + case (uint8_t)G_SETOTHERMODE_L: +#ifdef F3DEX_GBI_2 + gfx_sp_set_other_mode(31 - C0(8, 8) - C0(0, 8), C0(0, 8) + 1, cmd->words.w1); +#else + gfx_sp_set_other_mode(C0(8, 8), C0(0, 8), cmd->words.w1); +#endif + break; + case (uint8_t)G_SETOTHERMODE_H: +#ifdef F3DEX_GBI_2 + gfx_sp_set_other_mode(63 - C0(8, 8) - C0(0, 8), C0(0, 8) + 1, (uint64_t) cmd->words.w1 << 32); +#else + gfx_sp_set_other_mode(C0(8, 8) + 32, C0(0, 8), (uint64_t) cmd->words.w1 << 32); +#endif + break; + case G_COL: + gfx_sp_set_vertex_colors(C0(0, 16) / 4, seg_addr(cmd->words.w1)); + break; + + // RDP Commands: + case G_SETTIMG: + gfx_dp_set_texture_image(C0(21, 3), C0(19, 2), C0(0, 10), seg_addr(cmd->words.w1)); + break; + case G_LOADBLOCK: + gfx_dp_load_block(C1(24, 3), C0(12, 12), C0(0, 12), C1(12, 12), C1(0, 12)); + break; + case G_LOADTILE: + gfx_dp_load_tile(C1(24, 3), C0(12, 12), C0(0, 12), C1(12, 12), C1(0, 12)); + break; + case G_SETTILE: + gfx_dp_set_tile(C0(21, 3), C0(19, 2), C0(9, 9), C0(0, 9), C1(24, 3), C1(20, 4), C1(18, 2), C1(14, 4), C1(10, 4), C1(8, 2), C1(4, 4), C1(0, 4)); + break; + case G_SETTILESIZE: + gfx_dp_set_tile_size(C1(24, 3), C0(12, 12), C0(0, 12), C1(12, 12), C1(0, 12)); + break; + case G_LOADTLUT: + gfx_dp_load_tlut(C1(24, 3), C1(14, 10)); + break; + case G_SETENVCOLOR: + gfx_dp_set_env_color(C1(24, 8), C1(16, 8), C1(8, 8), C1(0, 8)); + break; + case G_SETPRIMCOLOR: + gfx_dp_set_prim_color(C1(24, 8), C1(16, 8), C1(8, 8), C1(0, 8)); + break; + case G_SETFOGCOLOR: + gfx_dp_set_fog_color(C1(24, 8), C1(16, 8), C1(8, 8), C1(0, 8)); + break; + case G_SETFILLCOLOR: + gfx_dp_set_fill_color(cmd->words.w1); + break; + case G_SETCOMBINE: + gfx_dp_set_combine_mode( + color_comb(C0(20, 4), C1(28, 4), C0(15, 5), C1(15, 3)), + color_comb(C0(12, 3), C1(12, 3), C0(9, 3), C1(9, 3))); + /*color_comb(C0(5, 4), C1(24, 4), C0(0, 5), C1(6, 3)), + color_comb(C1(21, 3), C1(3, 3), C1(18, 3), C1(0, 3)));*/ + break; + // G_SETPRIMCOLOR, G_CCMUX_PRIMITIVE, G_ACMUX_PRIMITIVE, is used by Goddard + // G_CCMUX_TEXEL1, LOD_FRACTION is used in Bowser room 1 + case G_TEXRECT: + case G_TEXRECTFLIP: + { + int32_t lrx, lry, tile, ulx, uly; + uint32_t uls, ult, dsdx, dtdy; +#ifdef F3DEX_GBI_2E + lrx = (int32_t)(C0(0, 24) << 8) >> 8; + lry = (int32_t)(C1(0, 24) << 8) >> 8; + ++cmd; + ulx = (int32_t)(C0(0, 24) << 8) >> 8; + uly = (int32_t)(C1(0, 24) << 8) >> 8; + ++cmd; + uls = C0(16, 16); + ult = C0(0, 16); + dsdx = C1(16, 16); + dtdy = C1(0, 16); +#else + lrx = C0(12, 12); + lry = C0(0, 12); + tile = C1(24, 3); + ulx = C1(12, 12); + uly = C1(0, 12); + ++cmd; + uls = C1(16, 16); + ult = C1(0, 16); + ++cmd; + dsdx = C1(16, 16); + dtdy = C1(0, 16); +#endif + gfx_dp_texture_rectangle(ulx, uly, lrx, lry, tile, uls, ult, dsdx, dtdy, opcode == G_TEXRECTFLIP); + break; + } + case G_FILLRECT: +#ifdef F3DEX_GBI_2E + { + int32_t lrx, lry, ulx, uly; + lrx = (int32_t)(C0(0, 24) << 8) >> 8; + lry = (int32_t)(C1(0, 24) << 8) >> 8; + ++cmd; + ulx = (int32_t)(C0(0, 24) << 8) >> 8; + uly = (int32_t)(C1(0, 24) << 8) >> 8; + gfx_dp_fill_rectangle(ulx, uly, lrx, lry); + break; + } +#else + gfx_dp_fill_rectangle(C1(12, 12), C1(0, 12), C0(12, 12), C0(0, 12)); + break; +#endif + case G_SETSCISSOR: + gfx_dp_set_scissor(C1(24, 2), C0(12, 12), C0(0, 12), C1(12, 12), C1(0, 12)); + break; + case G_SETZIMG: + gfx_dp_set_z_image(seg_addr(cmd->words.w1)); + break; + case G_SETCIMG: + gfx_dp_set_color_image(C0(21, 3), C0(19, 2), C0(0, 11), seg_addr(cmd->words.w1)); + break; + case G_RDPPIPESYNC: + case G_RDPFULLSYNC: + case G_RDPLOADSYNC: + case G_RDPTILESYNC: + break; + default: + fprintf(stderr, "Unhandled opcode: 0x%08x\n", opcode); + break; + } + ++cmd; + } +} + +static void gfx_sp_reset() { + rsp.modelview_matrix_stack_size = 1; + rsp.current_num_lights = 2; + rsp.lights_changed = true; + for (size_t i = 0; i < sizeof(rsp.segment_addrs) / sizeof(*rsp.segment_addrs); i++) + rsp.segment_addrs[i] = 0; +} + +void gfx_get_dimensions(uint32_t *width, uint32_t *height) { + gfx_wapi->get_dimensions(width, height); +} + +void gfx_init(struct GfxWindowManagerAPI *wapi, struct GfxRenderingAPI *rapi, const char *game_name, bool start_in_fullscreen) { + gfx_wapi = wapi; + gfx_rapi = rapi; + gfx_wapi->init(game_name, start_in_fullscreen); + gfx_rapi->init(); + /* + // Used in the 120 star TAS + static uint32_t precomp_shaders[] = { + 0x01200200, + 0x00000045, + 0x00000200, + 0x01200a00, + 0x00000a00, + 0x01a00045, + 0x00000551, + 0x01045045, + 0x05a00a00, + 0x01200045, + 0x05045045, + 0x01045a00, + 0x01a00a00, + 0x0000038d, + 0x01081081, + 0x0120038d, + 0x03200045, + 0x03200a00, + 0x01a00a6f, + 0x01141045, + 0x07a00a00, + 0x05200200, + 0x03200200, + 0x09200200, + 0x0920038d, + 0x09200045 + }; + for (size_t i = 0; i < sizeof(precomp_shaders) / sizeof(uint32_t); i++) { + gfx_lookup_or_create_shader_program(precomp_shaders[i]); + } + */ +} + +struct GfxRenderingAPI *gfx_get_current_rendering_api(void) { + return gfx_rapi; +} + +void gfx_start_frame(void) { + gfx_wapi->handle_events(); + gfx_wapi->get_dimensions(&gfx_current_dimensions.width, &gfx_current_dimensions.height); + if (gfx_current_dimensions.height == 0) { + // Avoid division by zero + gfx_current_dimensions.height = 1; + } + gfx_current_dimensions.aspect_ratio = (float)gfx_current_dimensions.width / (float)gfx_current_dimensions.height; +} + +void gfx_run(Gfx *commands) { + gfx_sp_reset(); + + //puts("New frame"); + + if (!gfx_wapi->start_frame()) { + dropped_frame = true; + return; + } + dropped_frame = false; + + gfx_rapi->start_frame(); + gfx_run_dl(commands); + gfx_flush(); + + gfx_rapi->end_frame(); + gfx_wapi->swap_buffers_begin(); +} + +void gfx_end_frame(void) { + if (!dropped_frame) { + gfx_rapi->finish_render(); + gfx_wapi->swap_buffers_end(); + } +} diff --git a/port/n64-fast3d-engine/gfx_pc.h b/port/n64-fast3d-engine/gfx_pc.h new file mode 100644 index 000000000..ef85a5624 --- /dev/null +++ b/port/n64-fast3d-engine/gfx_pc.h @@ -0,0 +1,36 @@ +#ifndef GFX_PC_H +#define GFX_PC_H + +#include +#include + +#ifndef _LANGUAGE_C +#define _LANGUAGE_C +#endif +#include + +struct GfxRenderingAPI; +struct GfxWindowManagerAPI; + +struct GfxDimensions { + uint32_t width, height; + float aspect_ratio; +}; + +extern struct GfxDimensions gfx_current_dimensions; + +#ifdef __cplusplus +extern "C" { +#endif + +void gfx_init(struct GfxWindowManagerAPI *wapi, struct GfxRenderingAPI *rapi, const char *game_name, bool start_in_fullscreen); +struct GfxRenderingAPI *gfx_get_current_rendering_api(void); +void gfx_start_frame(void); +void gfx_run(Gfx *commands); +void gfx_end_frame(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/port/n64-fast3d-engine/gfx_rendering_api.h b/port/n64-fast3d-engine/gfx_rendering_api.h new file mode 100644 index 000000000..ed6f1c4c9 --- /dev/null +++ b/port/n64-fast3d-engine/gfx_rendering_api.h @@ -0,0 +1,35 @@ +#ifndef GFX_RENDERING_API_H +#define GFX_RENDERING_API_H + +#include +#include +#include + +struct ShaderProgram; + +struct GfxRenderingAPI { + bool (*z_is_from_0_to_1)(void); + void (*unload_shader)(struct ShaderProgram *old_prg); + void (*load_shader)(struct ShaderProgram *new_prg); + struct ShaderProgram *(*create_and_load_new_shader)(uint32_t shader_id); + struct ShaderProgram *(*lookup_shader)(uint32_t shader_id); + void (*shader_get_info)(struct ShaderProgram *prg, uint8_t *num_inputs, bool used_textures[2]); + uint32_t (*new_texture)(void); + void (*select_texture)(int tile, uint32_t texture_id); + void (*upload_texture)(const uint8_t *rgba32_buf, int width, int height); + void (*set_sampler_parameters)(int sampler, bool linear_filter, uint32_t cms, uint32_t cmt); + void (*set_depth_test)(bool depth_test); + void (*set_depth_mask)(bool z_upd); + void (*set_zmode_decal)(bool zmode_decal); + void (*set_viewport)(int x, int y, int width, int height); + void (*set_scissor)(int x, int y, int width, int height); + void (*set_use_alpha)(bool use_alpha); + void (*draw_triangles)(float buf_vbo[], size_t buf_vbo_len, size_t buf_vbo_num_tris); + void (*init)(void); + void (*on_resize)(void); + void (*start_frame)(void); + void (*end_frame)(void); + void (*finish_render)(void); +}; + +#endif diff --git a/port/n64-fast3d-engine/gfx_screen_config.h b/port/n64-fast3d-engine/gfx_screen_config.h new file mode 100644 index 000000000..5b933f853 --- /dev/null +++ b/port/n64-fast3d-engine/gfx_screen_config.h @@ -0,0 +1,7 @@ +#ifndef GFX_SCREEN_CONFIG_H +#define GFX_SCREEN_CONFIG_H + +#define DESIRED_SCREEN_WIDTH 640 +#define DESIRED_SCREEN_HEIGHT 480 + +#endif diff --git a/port/n64-fast3d-engine/gfx_sdl2.c b/port/n64-fast3d-engine/gfx_sdl2.c new file mode 100644 index 000000000..3e0b99ae4 --- /dev/null +++ b/port/n64-fast3d-engine/gfx_sdl2.c @@ -0,0 +1,191 @@ +#include +#include +#include + +#include "gfx_window_manager_api.h" +#include "gfx_screen_config.h" + +#define GFX_API_NAME "SDL2 - OpenGL" + +static SDL_Window *wnd; +static int vsync_enabled = 0; +static unsigned int window_width = DESIRED_SCREEN_WIDTH; +static unsigned int window_height = DESIRED_SCREEN_HEIGHT; +static bool fullscreen_state; +static void (*on_fullscreen_changed_callback)(bool is_now_fullscreen); + +static void set_fullscreen(bool on, bool call_callback) { + if (fullscreen_state == on) { + return; + } + fullscreen_state = on; + + if (on) { + SDL_DisplayMode mode; + SDL_GetDesktopDisplayMode(0, &mode); + window_width = mode.w; + window_height = mode.h; + } else { + window_width = DESIRED_SCREEN_WIDTH; + window_height = DESIRED_SCREEN_HEIGHT; + } + SDL_SetWindowSize(wnd, window_width, window_height); + SDL_SetWindowFullscreen(wnd, on ? SDL_WINDOW_FULLSCREEN : 0); + + if (on_fullscreen_changed_callback != NULL && call_callback) { + on_fullscreen_changed_callback(on); + } +} + +static void test_vsync(void) { + // Even if SDL_GL_SetSwapInterval succeeds, it doesn't mean that VSync actually works. + // A 60 Hz monitor should have a swap interval of 16.67 milliseconds. + // Try to detect the length of a vsync by swapping buffers some times. + // Since the graphics card may enqueue a fixed number of frames, + // first send in four dummy frames to hopefully fill the queue. + // This method will fail if the refresh rate is changed, which, in + // combination with that we can't control the queue size (i.e. lag) + // is a reason this generic SDL2 backend should only be used as last resort. + Uint32 start; + Uint32 end; + + SDL_GL_SwapWindow(wnd); + SDL_GL_SwapWindow(wnd); + SDL_GL_SwapWindow(wnd); + SDL_GL_SwapWindow(wnd); + SDL_GL_SwapWindow(wnd); + SDL_GL_SwapWindow(wnd); + SDL_GL_SwapWindow(wnd); + SDL_GL_SwapWindow(wnd); + start = SDL_GetTicks(); + SDL_GL_SwapWindow(wnd); + SDL_GL_SwapWindow(wnd); + SDL_GL_SwapWindow(wnd); + SDL_GL_SwapWindow(wnd); + end = SDL_GetTicks(); + + float average = 4.0 * 1000.0 / (end - start); + + vsync_enabled = 1; + if (average > 27 && average < 33) { + SDL_GL_SetSwapInterval(1); + } else if (average > 57 && average < 63) { + SDL_GL_SetSwapInterval(2); + } else if (average > 86 && average < 94) { + SDL_GL_SetSwapInterval(3); + } else if (average > 115 && average < 125) { + SDL_GL_SetSwapInterval(4); + } else { + vsync_enabled = 0; + } +} + +static void gfx_sdl_init(const char *game_name, bool start_in_fullscreen) { + SDL_Init(SDL_INIT_VIDEO); + + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + + //SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); + //SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4); + + char title[512]; + int len = sprintf(title, "%s (%s)", game_name, GFX_API_NAME); + + wnd = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, + window_width, window_height, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE); + + if (start_in_fullscreen) { + set_fullscreen(true, false); + } + + SDL_GL_CreateContext(wnd); + + SDL_GL_SetSwapInterval(1); + test_vsync(); + if (!vsync_enabled) + puts("Warning: VSync is not enabled or not working. Falling back to timer for synchronization"); +} + +static void gfx_sdl_set_fullscreen_changed_callback(void (*on_fullscreen_changed)(bool is_now_fullscreen)) { + on_fullscreen_changed_callback = on_fullscreen_changed; +} + +static void gfx_sdl_set_fullscreen(bool enable) { + set_fullscreen(enable, true); +} + +static void gfx_sdl_main_loop(void (*run_one_game_iter)(void)) { + while (1) { + run_one_game_iter(); + } +} + +static void gfx_sdl_get_dimensions(uint32_t *width, uint32_t *height) { + *width = window_width; + *height = window_height; +} + +static void gfx_sdl_handle_events(void) { + SDL_Event event; + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_WINDOWEVENT: + if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) { + window_width = event.window.data1; + window_height = event.window.data2; + } + break; + case SDL_QUIT: + exit(0); + } + } +} + +static bool gfx_sdl_start_frame(void) { + return true; +} + +static void sync_framerate_with_timer(void) { + // Number of milliseconds a frame should take (60 fps) + const Uint32 FRAME_TIME = 1000 / 60; + static Uint32 last_time; + Uint32 elapsed = SDL_GetTicks() - last_time; + + if (elapsed < FRAME_TIME) + SDL_Delay(FRAME_TIME - elapsed); + last_time += FRAME_TIME; +} + +static void gfx_sdl_swap_buffers_begin(void) { + if (!vsync_enabled) { + sync_framerate_with_timer(); + } + + SDL_GL_SwapWindow(wnd); +} + +static void gfx_sdl_swap_buffers_end(void) { +} + +static double gfx_sdl_get_time(void) { + return 0.0; +} + +static void *gfx_sdl_get_window_handle(void) { + return wnd; +} + +struct GfxWindowManagerAPI gfx_sdl = { + gfx_sdl_init, + gfx_sdl_set_fullscreen_changed_callback, + gfx_sdl_set_fullscreen, + gfx_sdl_main_loop, + gfx_sdl_get_dimensions, + gfx_sdl_handle_events, + gfx_sdl_start_frame, + gfx_sdl_swap_buffers_begin, + gfx_sdl_swap_buffers_end, + gfx_sdl_get_time, + gfx_sdl_get_window_handle, +}; diff --git a/port/n64-fast3d-engine/gfx_sdl2.h b/port/n64-fast3d-engine/gfx_sdl2.h new file mode 100644 index 000000000..458eccb54 --- /dev/null +++ b/port/n64-fast3d-engine/gfx_sdl2.h @@ -0,0 +1,8 @@ +#ifndef GFX_SDL_H +#define GFX_SDL_H + +#include "gfx_window_manager_api.h" + +extern struct GfxWindowManagerAPI gfx_sdl; + +#endif diff --git a/port/n64-fast3d-engine/gfx_window_manager_api.h b/port/n64-fast3d-engine/gfx_window_manager_api.h new file mode 100644 index 000000000..1aadf7367 --- /dev/null +++ b/port/n64-fast3d-engine/gfx_window_manager_api.h @@ -0,0 +1,21 @@ +#ifndef GFX_WINDOW_MANAGER_API_H +#define GFX_WINDOW_MANAGER_API_H + +#include +#include + +struct GfxWindowManagerAPI { + void (*init)(const char *game_name, bool start_in_fullscreen); + void (*set_fullscreen_changed_callback)(void (*on_fullscreen_changed)(bool is_now_fullscreen)); + void (*set_fullscreen)(bool enable); + void (*main_loop)(void (*run_one_game_iter)(void)); + void (*get_dimensions)(uint32_t *width, uint32_t *height); + void (*handle_events)(void); + bool (*start_frame)(void); + void (*swap_buffers_begin)(void); + void (*swap_buffers_end)(void); + double (*get_time)(void); // For debug + void *(*get_window_handle)(void); +}; + +#endif diff --git a/port/n64-fast3d-engine/glad/glad.c b/port/n64-fast3d-engine/glad/glad.c new file mode 100644 index 000000000..ff7a74d0e --- /dev/null +++ b/port/n64-fast3d-engine/glad/glad.c @@ -0,0 +1,475 @@ +/* + + OpenGL ES loader generated by glad 0.1.34 on Wed Jul 26 19:11:08 2023. + + Language/Generator: C/C++ + Specification: gl + APIs: gles2=2.0 + Profile: compatibility + Extensions: + + Loader: True + Local files: True + Omit khrplatform: False + Reproducible: False + + Commandline: + --profile="compatibility" --api="gles2=2.0" --generator="c" --spec="gl" --local-files --extensions="" + Online: + https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gles2%3D2.0 +*/ + +#include +#include +#include +#include "glad.h" + +struct gladGLversionStruct GLVersion = { 0, 0 }; + +#if defined(GL_ES_VERSION_3_0) || defined(GL_VERSION_3_0) +#define _GLAD_IS_SOME_NEW_VERSION 1 +#endif + +static int max_loaded_major; +static int max_loaded_minor; + +static const char *exts = NULL; +static int num_exts_i = 0; +static char **exts_i = NULL; + +static int get_exts(void) { +#ifdef _GLAD_IS_SOME_NEW_VERSION + if(max_loaded_major < 3) { +#endif + exts = (const char *)glGetString(GL_EXTENSIONS); +#ifdef _GLAD_IS_SOME_NEW_VERSION + } else { + unsigned int index; + + num_exts_i = 0; + glGetIntegerv(GL_NUM_EXTENSIONS, &num_exts_i); + if (num_exts_i > 0) { + exts_i = (char **)malloc((size_t)num_exts_i * (sizeof *exts_i)); + } + + if (exts_i == NULL) { + return 0; + } + + for(index = 0; index < (unsigned)num_exts_i; index++) { + const char *gl_str_tmp = (const char*)glGetStringi(GL_EXTENSIONS, index); + size_t len = strlen(gl_str_tmp); + + char *local_str = (char*)malloc((len+1) * sizeof(char)); + if(local_str != NULL) { + memcpy(local_str, gl_str_tmp, (len+1) * sizeof(char)); + } + exts_i[index] = local_str; + } + } +#endif + return 1; +} + +static void free_exts(void) { + if (exts_i != NULL) { + int index; + for(index = 0; index < num_exts_i; index++) { + free((char *)exts_i[index]); + } + free((void *)exts_i); + exts_i = NULL; + } +} + +static int has_ext(const char *ext) { +#ifdef _GLAD_IS_SOME_NEW_VERSION + if(max_loaded_major < 3) { +#endif + const char *extensions; + const char *loc; + const char *terminator; + extensions = exts; + if(extensions == NULL || ext == NULL) { + return 0; + } + + while(1) { + loc = strstr(extensions, ext); + if(loc == NULL) { + return 0; + } + + terminator = loc + strlen(ext); + if((loc == extensions || *(loc - 1) == ' ') && + (*terminator == ' ' || *terminator == '\0')) { + return 1; + } + extensions = terminator; + } +#ifdef _GLAD_IS_SOME_NEW_VERSION + } else { + int index; + if(exts_i == NULL) return 0; + for(index = 0; index < num_exts_i; index++) { + const char *e = exts_i[index]; + + if(exts_i[index] != NULL && strcmp(e, ext) == 0) { + return 1; + } + } + } +#endif + + return 0; +} +int GLAD_GL_ES_VERSION_2_0 = 0; +PFNGLACTIVETEXTUREPROC glad_glActiveTexture = NULL; +PFNGLATTACHSHADERPROC glad_glAttachShader = NULL; +PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation = NULL; +PFNGLBINDBUFFERPROC glad_glBindBuffer = NULL; +PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer = NULL; +PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer = NULL; +PFNGLBINDTEXTUREPROC glad_glBindTexture = NULL; +PFNGLBLENDCOLORPROC glad_glBlendColor = NULL; +PFNGLBLENDEQUATIONPROC glad_glBlendEquation = NULL; +PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate = NULL; +PFNGLBLENDFUNCPROC glad_glBlendFunc = NULL; +PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate = NULL; +PFNGLBUFFERDATAPROC glad_glBufferData = NULL; +PFNGLBUFFERSUBDATAPROC glad_glBufferSubData = NULL; +PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus = NULL; +PFNGLCLEARPROC glad_glClear = NULL; +PFNGLCLEARCOLORPROC glad_glClearColor = NULL; +PFNGLCLEARDEPTHFPROC glad_glClearDepthf = NULL; +PFNGLCLEARSTENCILPROC glad_glClearStencil = NULL; +PFNGLCOLORMASKPROC glad_glColorMask = NULL; +PFNGLCOMPILESHADERPROC glad_glCompileShader = NULL; +PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D = NULL; +PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D = NULL; +PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D = NULL; +PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D = NULL; +PFNGLCREATEPROGRAMPROC glad_glCreateProgram = NULL; +PFNGLCREATESHADERPROC glad_glCreateShader = NULL; +PFNGLCULLFACEPROC glad_glCullFace = NULL; +PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers = NULL; +PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers = NULL; +PFNGLDELETEPROGRAMPROC glad_glDeleteProgram = NULL; +PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers = NULL; +PFNGLDELETESHADERPROC glad_glDeleteShader = NULL; +PFNGLDELETETEXTURESPROC glad_glDeleteTextures = NULL; +PFNGLDEPTHFUNCPROC glad_glDepthFunc = NULL; +PFNGLDEPTHMASKPROC glad_glDepthMask = NULL; +PFNGLDEPTHRANGEFPROC glad_glDepthRangef = NULL; +PFNGLDETACHSHADERPROC glad_glDetachShader = NULL; +PFNGLDISABLEPROC glad_glDisable = NULL; +PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray = NULL; +PFNGLDRAWARRAYSPROC glad_glDrawArrays = NULL; +PFNGLDRAWELEMENTSPROC glad_glDrawElements = NULL; +PFNGLENABLEPROC glad_glEnable = NULL; +PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray = NULL; +PFNGLFINISHPROC glad_glFinish = NULL; +PFNGLFLUSHPROC glad_glFlush = NULL; +PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer = NULL; +PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D = NULL; +PFNGLFRONTFACEPROC glad_glFrontFace = NULL; +PFNGLGENBUFFERSPROC glad_glGenBuffers = NULL; +PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers = NULL; +PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers = NULL; +PFNGLGENTEXTURESPROC glad_glGenTextures = NULL; +PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap = NULL; +PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib = NULL; +PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform = NULL; +PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders = NULL; +PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation = NULL; +PFNGLGETBOOLEANVPROC glad_glGetBooleanv = NULL; +PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv = NULL; +PFNGLGETERRORPROC glad_glGetError = NULL; +PFNGLGETFLOATVPROC glad_glGetFloatv = NULL; +PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv = NULL; +PFNGLGETINTEGERVPROC glad_glGetIntegerv = NULL; +PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog = NULL; +PFNGLGETPROGRAMIVPROC glad_glGetProgramiv = NULL; +PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv = NULL; +PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog = NULL; +PFNGLGETSHADERPRECISIONFORMATPROC glad_glGetShaderPrecisionFormat = NULL; +PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource = NULL; +PFNGLGETSHADERIVPROC glad_glGetShaderiv = NULL; +PFNGLGETSTRINGPROC glad_glGetString = NULL; +PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv = NULL; +PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv = NULL; +PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation = NULL; +PFNGLGETUNIFORMFVPROC glad_glGetUniformfv = NULL; +PFNGLGETUNIFORMIVPROC glad_glGetUniformiv = NULL; +PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv = NULL; +PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv = NULL; +PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv = NULL; +PFNGLHINTPROC glad_glHint = NULL; +PFNGLISBUFFERPROC glad_glIsBuffer = NULL; +PFNGLISENABLEDPROC glad_glIsEnabled = NULL; +PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer = NULL; +PFNGLISPROGRAMPROC glad_glIsProgram = NULL; +PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer = NULL; +PFNGLISSHADERPROC glad_glIsShader = NULL; +PFNGLISTEXTUREPROC glad_glIsTexture = NULL; +PFNGLLINEWIDTHPROC glad_glLineWidth = NULL; +PFNGLLINKPROGRAMPROC glad_glLinkProgram = NULL; +PFNGLPIXELSTOREIPROC glad_glPixelStorei = NULL; +PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset = NULL; +PFNGLREADPIXELSPROC glad_glReadPixels = NULL; +PFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler = NULL; +PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage = NULL; +PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage = NULL; +PFNGLSCISSORPROC glad_glScissor = NULL; +PFNGLSHADERBINARYPROC glad_glShaderBinary = NULL; +PFNGLSHADERSOURCEPROC glad_glShaderSource = NULL; +PFNGLSTENCILFUNCPROC glad_glStencilFunc = NULL; +PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate = NULL; +PFNGLSTENCILMASKPROC glad_glStencilMask = NULL; +PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate = NULL; +PFNGLSTENCILOPPROC glad_glStencilOp = NULL; +PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate = NULL; +PFNGLTEXIMAGE2DPROC glad_glTexImage2D = NULL; +PFNGLTEXPARAMETERFPROC glad_glTexParameterf = NULL; +PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv = NULL; +PFNGLTEXPARAMETERIPROC glad_glTexParameteri = NULL; +PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv = NULL; +PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D = NULL; +PFNGLUNIFORM1FPROC glad_glUniform1f = NULL; +PFNGLUNIFORM1FVPROC glad_glUniform1fv = NULL; +PFNGLUNIFORM1IPROC glad_glUniform1i = NULL; +PFNGLUNIFORM1IVPROC glad_glUniform1iv = NULL; +PFNGLUNIFORM2FPROC glad_glUniform2f = NULL; +PFNGLUNIFORM2FVPROC glad_glUniform2fv = NULL; +PFNGLUNIFORM2IPROC glad_glUniform2i = NULL; +PFNGLUNIFORM2IVPROC glad_glUniform2iv = NULL; +PFNGLUNIFORM3FPROC glad_glUniform3f = NULL; +PFNGLUNIFORM3FVPROC glad_glUniform3fv = NULL; +PFNGLUNIFORM3IPROC glad_glUniform3i = NULL; +PFNGLUNIFORM3IVPROC glad_glUniform3iv = NULL; +PFNGLUNIFORM4FPROC glad_glUniform4f = NULL; +PFNGLUNIFORM4FVPROC glad_glUniform4fv = NULL; +PFNGLUNIFORM4IPROC glad_glUniform4i = NULL; +PFNGLUNIFORM4IVPROC glad_glUniform4iv = NULL; +PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv = NULL; +PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv = NULL; +PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv = NULL; +PFNGLUSEPROGRAMPROC glad_glUseProgram = NULL; +PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram = NULL; +PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f = NULL; +PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv = NULL; +PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f = NULL; +PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv = NULL; +PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f = NULL; +PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv = NULL; +PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f = NULL; +PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv = NULL; +PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer = NULL; +PFNGLVIEWPORTPROC glad_glViewport = NULL; +static void load_GL_ES_VERSION_2_0(GLADloadproc load) { + if(!GLAD_GL_ES_VERSION_2_0) return; + glad_glActiveTexture = (PFNGLACTIVETEXTUREPROC)load("glActiveTexture"); + glad_glAttachShader = (PFNGLATTACHSHADERPROC)load("glAttachShader"); + glad_glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC)load("glBindAttribLocation"); + glad_glBindBuffer = (PFNGLBINDBUFFERPROC)load("glBindBuffer"); + glad_glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)load("glBindFramebuffer"); + glad_glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)load("glBindRenderbuffer"); + glad_glBindTexture = (PFNGLBINDTEXTUREPROC)load("glBindTexture"); + glad_glBlendColor = (PFNGLBLENDCOLORPROC)load("glBlendColor"); + glad_glBlendEquation = (PFNGLBLENDEQUATIONPROC)load("glBlendEquation"); + glad_glBlendEquationSeparate = (PFNGLBLENDEQUATIONSEPARATEPROC)load("glBlendEquationSeparate"); + glad_glBlendFunc = (PFNGLBLENDFUNCPROC)load("glBlendFunc"); + glad_glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC)load("glBlendFuncSeparate"); + glad_glBufferData = (PFNGLBUFFERDATAPROC)load("glBufferData"); + glad_glBufferSubData = (PFNGLBUFFERSUBDATAPROC)load("glBufferSubData"); + glad_glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)load("glCheckFramebufferStatus"); + glad_glClear = (PFNGLCLEARPROC)load("glClear"); + glad_glClearColor = (PFNGLCLEARCOLORPROC)load("glClearColor"); + glad_glClearDepthf = (PFNGLCLEARDEPTHFPROC)load("glClearDepthf"); + glad_glClearStencil = (PFNGLCLEARSTENCILPROC)load("glClearStencil"); + glad_glColorMask = (PFNGLCOLORMASKPROC)load("glColorMask"); + glad_glCompileShader = (PFNGLCOMPILESHADERPROC)load("glCompileShader"); + glad_glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC)load("glCompressedTexImage2D"); + glad_glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)load("glCompressedTexSubImage2D"); + glad_glCopyTexImage2D = (PFNGLCOPYTEXIMAGE2DPROC)load("glCopyTexImage2D"); + glad_glCopyTexSubImage2D = (PFNGLCOPYTEXSUBIMAGE2DPROC)load("glCopyTexSubImage2D"); + glad_glCreateProgram = (PFNGLCREATEPROGRAMPROC)load("glCreateProgram"); + glad_glCreateShader = (PFNGLCREATESHADERPROC)load("glCreateShader"); + glad_glCullFace = (PFNGLCULLFACEPROC)load("glCullFace"); + glad_glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)load("glDeleteBuffers"); + glad_glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)load("glDeleteFramebuffers"); + glad_glDeleteProgram = (PFNGLDELETEPROGRAMPROC)load("glDeleteProgram"); + glad_glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC)load("glDeleteRenderbuffers"); + glad_glDeleteShader = (PFNGLDELETESHADERPROC)load("glDeleteShader"); + glad_glDeleteTextures = (PFNGLDELETETEXTURESPROC)load("glDeleteTextures"); + glad_glDepthFunc = (PFNGLDEPTHFUNCPROC)load("glDepthFunc"); + glad_glDepthMask = (PFNGLDEPTHMASKPROC)load("glDepthMask"); + glad_glDepthRangef = (PFNGLDEPTHRANGEFPROC)load("glDepthRangef"); + glad_glDetachShader = (PFNGLDETACHSHADERPROC)load("glDetachShader"); + glad_glDisable = (PFNGLDISABLEPROC)load("glDisable"); + glad_glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC)load("glDisableVertexAttribArray"); + glad_glDrawArrays = (PFNGLDRAWARRAYSPROC)load("glDrawArrays"); + glad_glDrawElements = (PFNGLDRAWELEMENTSPROC)load("glDrawElements"); + glad_glEnable = (PFNGLENABLEPROC)load("glEnable"); + glad_glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)load("glEnableVertexAttribArray"); + glad_glFinish = (PFNGLFINISHPROC)load("glFinish"); + glad_glFlush = (PFNGLFLUSHPROC)load("glFlush"); + glad_glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)load("glFramebufferRenderbuffer"); + glad_glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)load("glFramebufferTexture2D"); + glad_glFrontFace = (PFNGLFRONTFACEPROC)load("glFrontFace"); + glad_glGenBuffers = (PFNGLGENBUFFERSPROC)load("glGenBuffers"); + glad_glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC)load("glGenerateMipmap"); + glad_glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)load("glGenFramebuffers"); + glad_glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)load("glGenRenderbuffers"); + glad_glGenTextures = (PFNGLGENTEXTURESPROC)load("glGenTextures"); + glad_glGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC)load("glGetActiveAttrib"); + glad_glGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC)load("glGetActiveUniform"); + glad_glGetAttachedShaders = (PFNGLGETATTACHEDSHADERSPROC)load("glGetAttachedShaders"); + glad_glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC)load("glGetAttribLocation"); + glad_glGetBooleanv = (PFNGLGETBOOLEANVPROC)load("glGetBooleanv"); + glad_glGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC)load("glGetBufferParameteriv"); + glad_glGetError = (PFNGLGETERRORPROC)load("glGetError"); + glad_glGetFloatv = (PFNGLGETFLOATVPROC)load("glGetFloatv"); + glad_glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)load("glGetFramebufferAttachmentParameteriv"); + glad_glGetIntegerv = (PFNGLGETINTEGERVPROC)load("glGetIntegerv"); + glad_glGetProgramiv = (PFNGLGETPROGRAMIVPROC)load("glGetProgramiv"); + glad_glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)load("glGetProgramInfoLog"); + glad_glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC)load("glGetRenderbufferParameteriv"); + glad_glGetShaderiv = (PFNGLGETSHADERIVPROC)load("glGetShaderiv"); + glad_glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)load("glGetShaderInfoLog"); + glad_glGetShaderPrecisionFormat = (PFNGLGETSHADERPRECISIONFORMATPROC)load("glGetShaderPrecisionFormat"); + glad_glGetShaderSource = (PFNGLGETSHADERSOURCEPROC)load("glGetShaderSource"); + glad_glGetString = (PFNGLGETSTRINGPROC)load("glGetString"); + glad_glGetTexParameterfv = (PFNGLGETTEXPARAMETERFVPROC)load("glGetTexParameterfv"); + glad_glGetTexParameteriv = (PFNGLGETTEXPARAMETERIVPROC)load("glGetTexParameteriv"); + glad_glGetUniformfv = (PFNGLGETUNIFORMFVPROC)load("glGetUniformfv"); + glad_glGetUniformiv = (PFNGLGETUNIFORMIVPROC)load("glGetUniformiv"); + glad_glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)load("glGetUniformLocation"); + glad_glGetVertexAttribfv = (PFNGLGETVERTEXATTRIBFVPROC)load("glGetVertexAttribfv"); + glad_glGetVertexAttribiv = (PFNGLGETVERTEXATTRIBIVPROC)load("glGetVertexAttribiv"); + glad_glGetVertexAttribPointerv = (PFNGLGETVERTEXATTRIBPOINTERVPROC)load("glGetVertexAttribPointerv"); + glad_glHint = (PFNGLHINTPROC)load("glHint"); + glad_glIsBuffer = (PFNGLISBUFFERPROC)load("glIsBuffer"); + glad_glIsEnabled = (PFNGLISENABLEDPROC)load("glIsEnabled"); + glad_glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC)load("glIsFramebuffer"); + glad_glIsProgram = (PFNGLISPROGRAMPROC)load("glIsProgram"); + glad_glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC)load("glIsRenderbuffer"); + glad_glIsShader = (PFNGLISSHADERPROC)load("glIsShader"); + glad_glIsTexture = (PFNGLISTEXTUREPROC)load("glIsTexture"); + glad_glLineWidth = (PFNGLLINEWIDTHPROC)load("glLineWidth"); + glad_glLinkProgram = (PFNGLLINKPROGRAMPROC)load("glLinkProgram"); + glad_glPixelStorei = (PFNGLPIXELSTOREIPROC)load("glPixelStorei"); + glad_glPolygonOffset = (PFNGLPOLYGONOFFSETPROC)load("glPolygonOffset"); + glad_glReadPixels = (PFNGLREADPIXELSPROC)load("glReadPixels"); + glad_glReleaseShaderCompiler = (PFNGLRELEASESHADERCOMPILERPROC)load("glReleaseShaderCompiler"); + glad_glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)load("glRenderbufferStorage"); + glad_glSampleCoverage = (PFNGLSAMPLECOVERAGEPROC)load("glSampleCoverage"); + glad_glScissor = (PFNGLSCISSORPROC)load("glScissor"); + glad_glShaderBinary = (PFNGLSHADERBINARYPROC)load("glShaderBinary"); + glad_glShaderSource = (PFNGLSHADERSOURCEPROC)load("glShaderSource"); + glad_glStencilFunc = (PFNGLSTENCILFUNCPROC)load("glStencilFunc"); + glad_glStencilFuncSeparate = (PFNGLSTENCILFUNCSEPARATEPROC)load("glStencilFuncSeparate"); + glad_glStencilMask = (PFNGLSTENCILMASKPROC)load("glStencilMask"); + glad_glStencilMaskSeparate = (PFNGLSTENCILMASKSEPARATEPROC)load("glStencilMaskSeparate"); + glad_glStencilOp = (PFNGLSTENCILOPPROC)load("glStencilOp"); + glad_glStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC)load("glStencilOpSeparate"); + glad_glTexImage2D = (PFNGLTEXIMAGE2DPROC)load("glTexImage2D"); + glad_glTexParameterf = (PFNGLTEXPARAMETERFPROC)load("glTexParameterf"); + glad_glTexParameterfv = (PFNGLTEXPARAMETERFVPROC)load("glTexParameterfv"); + glad_glTexParameteri = (PFNGLTEXPARAMETERIPROC)load("glTexParameteri"); + glad_glTexParameteriv = (PFNGLTEXPARAMETERIVPROC)load("glTexParameteriv"); + glad_glTexSubImage2D = (PFNGLTEXSUBIMAGE2DPROC)load("glTexSubImage2D"); + glad_glUniform1f = (PFNGLUNIFORM1FPROC)load("glUniform1f"); + glad_glUniform1fv = (PFNGLUNIFORM1FVPROC)load("glUniform1fv"); + glad_glUniform1i = (PFNGLUNIFORM1IPROC)load("glUniform1i"); + glad_glUniform1iv = (PFNGLUNIFORM1IVPROC)load("glUniform1iv"); + glad_glUniform2f = (PFNGLUNIFORM2FPROC)load("glUniform2f"); + glad_glUniform2fv = (PFNGLUNIFORM2FVPROC)load("glUniform2fv"); + glad_glUniform2i = (PFNGLUNIFORM2IPROC)load("glUniform2i"); + glad_glUniform2iv = (PFNGLUNIFORM2IVPROC)load("glUniform2iv"); + glad_glUniform3f = (PFNGLUNIFORM3FPROC)load("glUniform3f"); + glad_glUniform3fv = (PFNGLUNIFORM3FVPROC)load("glUniform3fv"); + glad_glUniform3i = (PFNGLUNIFORM3IPROC)load("glUniform3i"); + glad_glUniform3iv = (PFNGLUNIFORM3IVPROC)load("glUniform3iv"); + glad_glUniform4f = (PFNGLUNIFORM4FPROC)load("glUniform4f"); + glad_glUniform4fv = (PFNGLUNIFORM4FVPROC)load("glUniform4fv"); + glad_glUniform4i = (PFNGLUNIFORM4IPROC)load("glUniform4i"); + glad_glUniform4iv = (PFNGLUNIFORM4IVPROC)load("glUniform4iv"); + glad_glUniformMatrix2fv = (PFNGLUNIFORMMATRIX2FVPROC)load("glUniformMatrix2fv"); + glad_glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC)load("glUniformMatrix3fv"); + glad_glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)load("glUniformMatrix4fv"); + glad_glUseProgram = (PFNGLUSEPROGRAMPROC)load("glUseProgram"); + glad_glValidateProgram = (PFNGLVALIDATEPROGRAMPROC)load("glValidateProgram"); + glad_glVertexAttrib1f = (PFNGLVERTEXATTRIB1FPROC)load("glVertexAttrib1f"); + glad_glVertexAttrib1fv = (PFNGLVERTEXATTRIB1FVPROC)load("glVertexAttrib1fv"); + glad_glVertexAttrib2f = (PFNGLVERTEXATTRIB2FPROC)load("glVertexAttrib2f"); + glad_glVertexAttrib2fv = (PFNGLVERTEXATTRIB2FVPROC)load("glVertexAttrib2fv"); + glad_glVertexAttrib3f = (PFNGLVERTEXATTRIB3FPROC)load("glVertexAttrib3f"); + glad_glVertexAttrib3fv = (PFNGLVERTEXATTRIB3FVPROC)load("glVertexAttrib3fv"); + glad_glVertexAttrib4f = (PFNGLVERTEXATTRIB4FPROC)load("glVertexAttrib4f"); + glad_glVertexAttrib4fv = (PFNGLVERTEXATTRIB4FVPROC)load("glVertexAttrib4fv"); + glad_glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)load("glVertexAttribPointer"); + glad_glViewport = (PFNGLVIEWPORTPROC)load("glViewport"); +} +static int find_extensionsGLES2(void) { + if (!get_exts()) return 0; + (void)&has_ext; + free_exts(); + return 1; +} + +static void find_coreGLES2(void) { + + /* Thank you @elmindreda + * https://github.com/elmindreda/greg/blob/master/templates/greg.c.in#L176 + * https://github.com/glfw/glfw/blob/master/src/context.c#L36 + */ + int i, major, minor; + + const char* version; + const char* prefixes[] = { + "OpenGL ES-CM ", + "OpenGL ES-CL ", + "OpenGL ES ", + NULL + }; + + version = (const char*) glGetString(GL_VERSION); + if (!version) return; + + for (i = 0; prefixes[i]; i++) { + const size_t length = strlen(prefixes[i]); + if (strncmp(version, prefixes[i], length) == 0) { + version += length; + break; + } + } + +/* PR #18 */ +#ifdef _MSC_VER + sscanf_s(version, "%d.%d", &major, &minor); +#else + sscanf(version, "%d.%d", &major, &minor); +#endif + + GLVersion.major = major; GLVersion.minor = minor; + max_loaded_major = major; max_loaded_minor = minor; + GLAD_GL_ES_VERSION_2_0 = (major == 2 && minor >= 0) || major > 2; + if (GLVersion.major > 2 || (GLVersion.major >= 2 && GLVersion.minor >= 0)) { + max_loaded_major = 2; + max_loaded_minor = 0; + } +} + +int gladLoadGLES2Loader(GLADloadproc load) { + GLVersion.major = 0; GLVersion.minor = 0; + glGetString = (PFNGLGETSTRINGPROC)load("glGetString"); + if(glGetString == NULL) return 0; + if(glGetString(GL_VERSION) == NULL) return 0; + find_coreGLES2(); + load_GL_ES_VERSION_2_0(load); + + if (!find_extensionsGLES2()) return 0; + return GLVersion.major != 0 || GLVersion.minor != 0; +} + diff --git a/port/n64-fast3d-engine/glad/glad.h b/port/n64-fast3d-engine/glad/glad.h new file mode 100644 index 000000000..9defb23df --- /dev/null +++ b/port/n64-fast3d-engine/glad/glad.h @@ -0,0 +1,874 @@ +/* + + OpenGL ES loader generated by glad 0.1.34 on Wed Jul 26 19:11:08 2023. + + Language/Generator: C/C++ + Specification: gl + APIs: gles2=2.0 + Profile: compatibility + Extensions: + + Loader: True + Local files: True + Omit khrplatform: False + Reproducible: False + + Commandline: + --profile="compatibility" --api="gles2=2.0" --generator="c" --spec="gl" --local-files --extensions="" + Online: + https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gles2%3D2.0 +*/ + + +#ifndef __glad_h_ +#define __glad_h_ + +#ifdef __gl2_h_ +#error OpenGL ES 2 header already included, remove this include, glad already provides it +#endif +#define __gl2_h_ + +#ifdef __gl3_h_ +#error OpenGL ES 3 header already included, remove this include, glad already provides it +#endif +#define __gl3_h_ + +#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) +#define APIENTRY __stdcall +#endif + +#ifndef APIENTRY +#define APIENTRY +#endif +#ifndef APIENTRYP +#define APIENTRYP APIENTRY * +#endif + +#ifndef GLAPIENTRY +#define GLAPIENTRY APIENTRY +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +struct gladGLversionStruct { + int major; + int minor; +}; + +typedef void* (* GLADloadproc)(const char *name); + +#ifndef GLAPI +# if defined(GLAD_GLAPI_EXPORT) +# if defined(_WIN32) || defined(__CYGWIN__) +# if defined(GLAD_GLAPI_EXPORT_BUILD) +# if defined(__GNUC__) +# define GLAPI __attribute__ ((dllexport)) extern +# else +# define GLAPI __declspec(dllexport) extern +# endif +# else +# if defined(__GNUC__) +# define GLAPI __attribute__ ((dllimport)) extern +# else +# define GLAPI __declspec(dllimport) extern +# endif +# endif +# elif defined(__GNUC__) && defined(GLAD_GLAPI_EXPORT_BUILD) +# define GLAPI __attribute__ ((visibility ("default"))) extern +# else +# define GLAPI extern +# endif +# else +# define GLAPI extern +# endif +#endif + +GLAPI struct gladGLversionStruct GLVersion; +GLAPI int gladLoadGLES2Loader(GLADloadproc); + +#include "khrplatform.h" +typedef unsigned int GLenum; +typedef unsigned char GLboolean; +typedef unsigned int GLbitfield; +typedef void GLvoid; +typedef khronos_int8_t GLbyte; +typedef khronos_uint8_t GLubyte; +typedef khronos_int16_t GLshort; +typedef khronos_uint16_t GLushort; +typedef int GLint; +typedef unsigned int GLuint; +typedef khronos_int32_t GLclampx; +typedef int GLsizei; +typedef khronos_float_t GLfloat; +typedef khronos_float_t GLclampf; +typedef double GLdouble; +typedef double GLclampd; +typedef void *GLeglClientBufferEXT; +typedef void *GLeglImageOES; +typedef char GLchar; +typedef char GLcharARB; +#ifdef __APPLE__ +typedef void *GLhandleARB; +#else +typedef unsigned int GLhandleARB; +#endif +typedef khronos_uint16_t GLhalf; +typedef khronos_uint16_t GLhalfARB; +typedef khronos_int32_t GLfixed; +typedef khronos_intptr_t GLintptr; +typedef khronos_intptr_t GLintptrARB; +typedef khronos_ssize_t GLsizeiptr; +typedef khronos_ssize_t GLsizeiptrARB; +typedef khronos_int64_t GLint64; +typedef khronos_int64_t GLint64EXT; +typedef khronos_uint64_t GLuint64; +typedef khronos_uint64_t GLuint64EXT; +typedef struct __GLsync *GLsync; +struct _cl_context; +struct _cl_event; +typedef void (APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +typedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +typedef void (APIENTRY *GLDEBUGPROCKHR)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +typedef void (APIENTRY *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam); +typedef unsigned short GLhalfNV; +typedef GLintptr GLvdpauSurfaceNV; +typedef void (APIENTRY *GLVULKANPROCNV)(void); +#define GL_DEPTH_BUFFER_BIT 0x00000100 +#define GL_STENCIL_BUFFER_BIT 0x00000400 +#define GL_COLOR_BUFFER_BIT 0x00004000 +#define GL_FALSE 0 +#define GL_TRUE 1 +#define GL_POINTS 0x0000 +#define GL_LINES 0x0001 +#define GL_LINE_LOOP 0x0002 +#define GL_LINE_STRIP 0x0003 +#define GL_TRIANGLES 0x0004 +#define GL_TRIANGLE_STRIP 0x0005 +#define GL_TRIANGLE_FAN 0x0006 +#define GL_ZERO 0 +#define GL_ONE 1 +#define GL_SRC_COLOR 0x0300 +#define GL_ONE_MINUS_SRC_COLOR 0x0301 +#define GL_SRC_ALPHA 0x0302 +#define GL_ONE_MINUS_SRC_ALPHA 0x0303 +#define GL_DST_ALPHA 0x0304 +#define GL_ONE_MINUS_DST_ALPHA 0x0305 +#define GL_DST_COLOR 0x0306 +#define GL_ONE_MINUS_DST_COLOR 0x0307 +#define GL_SRC_ALPHA_SATURATE 0x0308 +#define GL_FUNC_ADD 0x8006 +#define GL_BLEND_EQUATION 0x8009 +#define GL_BLEND_EQUATION_RGB 0x8009 +#define GL_BLEND_EQUATION_ALPHA 0x883D +#define GL_FUNC_SUBTRACT 0x800A +#define GL_FUNC_REVERSE_SUBTRACT 0x800B +#define GL_BLEND_DST_RGB 0x80C8 +#define GL_BLEND_SRC_RGB 0x80C9 +#define GL_BLEND_DST_ALPHA 0x80CA +#define GL_BLEND_SRC_ALPHA 0x80CB +#define GL_CONSTANT_COLOR 0x8001 +#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 +#define GL_CONSTANT_ALPHA 0x8003 +#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 +#define GL_BLEND_COLOR 0x8005 +#define GL_ARRAY_BUFFER 0x8892 +#define GL_ELEMENT_ARRAY_BUFFER 0x8893 +#define GL_ARRAY_BUFFER_BINDING 0x8894 +#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 +#define GL_STREAM_DRAW 0x88E0 +#define GL_STATIC_DRAW 0x88E4 +#define GL_DYNAMIC_DRAW 0x88E8 +#define GL_BUFFER_SIZE 0x8764 +#define GL_BUFFER_USAGE 0x8765 +#define GL_CURRENT_VERTEX_ATTRIB 0x8626 +#define GL_FRONT 0x0404 +#define GL_BACK 0x0405 +#define GL_FRONT_AND_BACK 0x0408 +#define GL_TEXTURE_2D 0x0DE1 +#define GL_CULL_FACE 0x0B44 +#define GL_BLEND 0x0BE2 +#define GL_DITHER 0x0BD0 +#define GL_STENCIL_TEST 0x0B90 +#define GL_DEPTH_TEST 0x0B71 +#define GL_SCISSOR_TEST 0x0C11 +#define GL_POLYGON_OFFSET_FILL 0x8037 +#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E +#define GL_SAMPLE_COVERAGE 0x80A0 +#define GL_NO_ERROR 0 +#define GL_INVALID_ENUM 0x0500 +#define GL_INVALID_VALUE 0x0501 +#define GL_INVALID_OPERATION 0x0502 +#define GL_OUT_OF_MEMORY 0x0505 +#define GL_CW 0x0900 +#define GL_CCW 0x0901 +#define GL_LINE_WIDTH 0x0B21 +#define GL_ALIASED_POINT_SIZE_RANGE 0x846D +#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E +#define GL_CULL_FACE_MODE 0x0B45 +#define GL_FRONT_FACE 0x0B46 +#define GL_DEPTH_RANGE 0x0B70 +#define GL_DEPTH_WRITEMASK 0x0B72 +#define GL_DEPTH_CLEAR_VALUE 0x0B73 +#define GL_DEPTH_FUNC 0x0B74 +#define GL_STENCIL_CLEAR_VALUE 0x0B91 +#define GL_STENCIL_FUNC 0x0B92 +#define GL_STENCIL_FAIL 0x0B94 +#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 +#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96 +#define GL_STENCIL_REF 0x0B97 +#define GL_STENCIL_VALUE_MASK 0x0B93 +#define GL_STENCIL_WRITEMASK 0x0B98 +#define GL_STENCIL_BACK_FUNC 0x8800 +#define GL_STENCIL_BACK_FAIL 0x8801 +#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 +#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 +#define GL_STENCIL_BACK_REF 0x8CA3 +#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 +#define GL_STENCIL_BACK_WRITEMASK 0x8CA5 +#define GL_VIEWPORT 0x0BA2 +#define GL_SCISSOR_BOX 0x0C10 +#define GL_COLOR_CLEAR_VALUE 0x0C22 +#define GL_COLOR_WRITEMASK 0x0C23 +#define GL_UNPACK_ALIGNMENT 0x0CF5 +#define GL_PACK_ALIGNMENT 0x0D05 +#define GL_MAX_TEXTURE_SIZE 0x0D33 +#define GL_MAX_VIEWPORT_DIMS 0x0D3A +#define GL_SUBPIXEL_BITS 0x0D50 +#define GL_RED_BITS 0x0D52 +#define GL_GREEN_BITS 0x0D53 +#define GL_BLUE_BITS 0x0D54 +#define GL_ALPHA_BITS 0x0D55 +#define GL_DEPTH_BITS 0x0D56 +#define GL_STENCIL_BITS 0x0D57 +#define GL_POLYGON_OFFSET_UNITS 0x2A00 +#define GL_POLYGON_OFFSET_FACTOR 0x8038 +#define GL_TEXTURE_BINDING_2D 0x8069 +#define GL_SAMPLE_BUFFERS 0x80A8 +#define GL_SAMPLES 0x80A9 +#define GL_SAMPLE_COVERAGE_VALUE 0x80AA +#define GL_SAMPLE_COVERAGE_INVERT 0x80AB +#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 +#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 +#define GL_DONT_CARE 0x1100 +#define GL_FASTEST 0x1101 +#define GL_NICEST 0x1102 +#define GL_GENERATE_MIPMAP_HINT 0x8192 +#define GL_BYTE 0x1400 +#define GL_UNSIGNED_BYTE 0x1401 +#define GL_SHORT 0x1402 +#define GL_UNSIGNED_SHORT 0x1403 +#define GL_INT 0x1404 +#define GL_UNSIGNED_INT 0x1405 +#define GL_FLOAT 0x1406 +#define GL_FIXED 0x140C +#define GL_DEPTH_COMPONENT 0x1902 +#define GL_ALPHA 0x1906 +#define GL_RGB 0x1907 +#define GL_RGBA 0x1908 +#define GL_LUMINANCE 0x1909 +#define GL_LUMINANCE_ALPHA 0x190A +#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 +#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 +#define GL_UNSIGNED_SHORT_5_6_5 0x8363 +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_VERTEX_SHADER 0x8B31 +#define GL_MAX_VERTEX_ATTRIBS 0x8869 +#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB +#define GL_MAX_VARYING_VECTORS 0x8DFC +#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D +#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C +#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 +#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD +#define GL_SHADER_TYPE 0x8B4F +#define GL_DELETE_STATUS 0x8B80 +#define GL_LINK_STATUS 0x8B82 +#define GL_VALIDATE_STATUS 0x8B83 +#define GL_ATTACHED_SHADERS 0x8B85 +#define GL_ACTIVE_UNIFORMS 0x8B86 +#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 +#define GL_ACTIVE_ATTRIBUTES 0x8B89 +#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A +#define GL_SHADING_LANGUAGE_VERSION 0x8B8C +#define GL_CURRENT_PROGRAM 0x8B8D +#define GL_NEVER 0x0200 +#define GL_LESS 0x0201 +#define GL_EQUAL 0x0202 +#define GL_LEQUAL 0x0203 +#define GL_GREATER 0x0204 +#define GL_NOTEQUAL 0x0205 +#define GL_GEQUAL 0x0206 +#define GL_ALWAYS 0x0207 +#define GL_KEEP 0x1E00 +#define GL_REPLACE 0x1E01 +#define GL_INCR 0x1E02 +#define GL_DECR 0x1E03 +#define GL_INVERT 0x150A +#define GL_INCR_WRAP 0x8507 +#define GL_DECR_WRAP 0x8508 +#define GL_VENDOR 0x1F00 +#define GL_RENDERER 0x1F01 +#define GL_VERSION 0x1F02 +#define GL_EXTENSIONS 0x1F03 +#define GL_NEAREST 0x2600 +#define GL_LINEAR 0x2601 +#define GL_NEAREST_MIPMAP_NEAREST 0x2700 +#define GL_LINEAR_MIPMAP_NEAREST 0x2701 +#define GL_NEAREST_MIPMAP_LINEAR 0x2702 +#define GL_LINEAR_MIPMAP_LINEAR 0x2703 +#define GL_TEXTURE_MAG_FILTER 0x2800 +#define GL_TEXTURE_MIN_FILTER 0x2801 +#define GL_TEXTURE_WRAP_S 0x2802 +#define GL_TEXTURE_WRAP_T 0x2803 +#define GL_TEXTURE 0x1702 +#define GL_TEXTURE_CUBE_MAP 0x8513 +#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A +#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C +#define GL_TEXTURE0 0x84C0 +#define GL_TEXTURE1 0x84C1 +#define GL_TEXTURE2 0x84C2 +#define GL_TEXTURE3 0x84C3 +#define GL_TEXTURE4 0x84C4 +#define GL_TEXTURE5 0x84C5 +#define GL_TEXTURE6 0x84C6 +#define GL_TEXTURE7 0x84C7 +#define GL_TEXTURE8 0x84C8 +#define GL_TEXTURE9 0x84C9 +#define GL_TEXTURE10 0x84CA +#define GL_TEXTURE11 0x84CB +#define GL_TEXTURE12 0x84CC +#define GL_TEXTURE13 0x84CD +#define GL_TEXTURE14 0x84CE +#define GL_TEXTURE15 0x84CF +#define GL_TEXTURE16 0x84D0 +#define GL_TEXTURE17 0x84D1 +#define GL_TEXTURE18 0x84D2 +#define GL_TEXTURE19 0x84D3 +#define GL_TEXTURE20 0x84D4 +#define GL_TEXTURE21 0x84D5 +#define GL_TEXTURE22 0x84D6 +#define GL_TEXTURE23 0x84D7 +#define GL_TEXTURE24 0x84D8 +#define GL_TEXTURE25 0x84D9 +#define GL_TEXTURE26 0x84DA +#define GL_TEXTURE27 0x84DB +#define GL_TEXTURE28 0x84DC +#define GL_TEXTURE29 0x84DD +#define GL_TEXTURE30 0x84DE +#define GL_TEXTURE31 0x84DF +#define GL_ACTIVE_TEXTURE 0x84E0 +#define GL_REPEAT 0x2901 +#define GL_CLAMP_TO_EDGE 0x812F +#define GL_MIRRORED_REPEAT 0x8370 +#define GL_FLOAT_VEC2 0x8B50 +#define GL_FLOAT_VEC3 0x8B51 +#define GL_FLOAT_VEC4 0x8B52 +#define GL_INT_VEC2 0x8B53 +#define GL_INT_VEC3 0x8B54 +#define GL_INT_VEC4 0x8B55 +#define GL_BOOL 0x8B56 +#define GL_BOOL_VEC2 0x8B57 +#define GL_BOOL_VEC3 0x8B58 +#define GL_BOOL_VEC4 0x8B59 +#define GL_FLOAT_MAT2 0x8B5A +#define GL_FLOAT_MAT3 0x8B5B +#define GL_FLOAT_MAT4 0x8B5C +#define GL_SAMPLER_2D 0x8B5E +#define GL_SAMPLER_CUBE 0x8B60 +#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 +#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 +#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 +#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 +#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A +#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 +#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F +#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A +#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B +#define GL_COMPILE_STATUS 0x8B81 +#define GL_INFO_LOG_LENGTH 0x8B84 +#define GL_SHADER_SOURCE_LENGTH 0x8B88 +#define GL_SHADER_COMPILER 0x8DFA +#define GL_SHADER_BINARY_FORMATS 0x8DF8 +#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9 +#define GL_LOW_FLOAT 0x8DF0 +#define GL_MEDIUM_FLOAT 0x8DF1 +#define GL_HIGH_FLOAT 0x8DF2 +#define GL_LOW_INT 0x8DF3 +#define GL_MEDIUM_INT 0x8DF4 +#define GL_HIGH_INT 0x8DF5 +#define GL_FRAMEBUFFER 0x8D40 +#define GL_RENDERBUFFER 0x8D41 +#define GL_RGBA4 0x8056 +#define GL_RGB5_A1 0x8057 +#define GL_RGB565 0x8D62 +#define GL_DEPTH_COMPONENT16 0x81A5 +#define GL_STENCIL_INDEX8 0x8D48 +#define GL_RENDERBUFFER_WIDTH 0x8D42 +#define GL_RENDERBUFFER_HEIGHT 0x8D43 +#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 +#define GL_RENDERBUFFER_RED_SIZE 0x8D50 +#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 +#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 +#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 +#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 +#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 +#define GL_COLOR_ATTACHMENT0 0x8CE0 +#define GL_DEPTH_ATTACHMENT 0x8D00 +#define GL_STENCIL_ATTACHMENT 0x8D20 +#define GL_NONE 0 +#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 +#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 +#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 +#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9 +#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD +#define GL_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_RENDERBUFFER_BINDING 0x8CA7 +#define GL_MAX_RENDERBUFFER_SIZE 0x84E8 +#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 +#ifndef GL_ES_VERSION_2_0 +#define GL_ES_VERSION_2_0 1 +GLAPI int GLAD_GL_ES_VERSION_2_0; +typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC)(GLenum texture); +GLAPI PFNGLACTIVETEXTUREPROC glad_glActiveTexture; +#define glActiveTexture glad_glActiveTexture +typedef void (APIENTRYP PFNGLATTACHSHADERPROC)(GLuint program, GLuint shader); +GLAPI PFNGLATTACHSHADERPROC glad_glAttachShader; +#define glAttachShader glad_glAttachShader +typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONPROC)(GLuint program, GLuint index, const GLchar *name); +GLAPI PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation; +#define glBindAttribLocation glad_glBindAttribLocation +typedef void (APIENTRYP PFNGLBINDBUFFERPROC)(GLenum target, GLuint buffer); +GLAPI PFNGLBINDBUFFERPROC glad_glBindBuffer; +#define glBindBuffer glad_glBindBuffer +typedef void (APIENTRYP PFNGLBINDFRAMEBUFFERPROC)(GLenum target, GLuint framebuffer); +GLAPI PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer; +#define glBindFramebuffer glad_glBindFramebuffer +typedef void (APIENTRYP PFNGLBINDRENDERBUFFERPROC)(GLenum target, GLuint renderbuffer); +GLAPI PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer; +#define glBindRenderbuffer glad_glBindRenderbuffer +typedef void (APIENTRYP PFNGLBINDTEXTUREPROC)(GLenum target, GLuint texture); +GLAPI PFNGLBINDTEXTUREPROC glad_glBindTexture; +#define glBindTexture glad_glBindTexture +typedef void (APIENTRYP PFNGLBLENDCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +GLAPI PFNGLBLENDCOLORPROC glad_glBlendColor; +#define glBlendColor glad_glBlendColor +typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC)(GLenum mode); +GLAPI PFNGLBLENDEQUATIONPROC glad_glBlendEquation; +#define glBlendEquation glad_glBlendEquation +typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC)(GLenum modeRGB, GLenum modeAlpha); +GLAPI PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate; +#define glBlendEquationSeparate glad_glBlendEquationSeparate +typedef void (APIENTRYP PFNGLBLENDFUNCPROC)(GLenum sfactor, GLenum dfactor); +GLAPI PFNGLBLENDFUNCPROC glad_glBlendFunc; +#define glBlendFunc glad_glBlendFunc +typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC)(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +GLAPI PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate; +#define glBlendFuncSeparate glad_glBlendFuncSeparate +typedef void (APIENTRYP PFNGLBUFFERDATAPROC)(GLenum target, GLsizeiptr size, const void *data, GLenum usage); +GLAPI PFNGLBUFFERDATAPROC glad_glBufferData; +#define glBufferData glad_glBufferData +typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, const void *data); +GLAPI PFNGLBUFFERSUBDATAPROC glad_glBufferSubData; +#define glBufferSubData glad_glBufferSubData +typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSPROC)(GLenum target); +GLAPI PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus; +#define glCheckFramebufferStatus glad_glCheckFramebufferStatus +typedef void (APIENTRYP PFNGLCLEARPROC)(GLbitfield mask); +GLAPI PFNGLCLEARPROC glad_glClear; +#define glClear glad_glClear +typedef void (APIENTRYP PFNGLCLEARCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +GLAPI PFNGLCLEARCOLORPROC glad_glClearColor; +#define glClearColor glad_glClearColor +typedef void (APIENTRYP PFNGLCLEARDEPTHFPROC)(GLfloat d); +GLAPI PFNGLCLEARDEPTHFPROC glad_glClearDepthf; +#define glClearDepthf glad_glClearDepthf +typedef void (APIENTRYP PFNGLCLEARSTENCILPROC)(GLint s); +GLAPI PFNGLCLEARSTENCILPROC glad_glClearStencil; +#define glClearStencil glad_glClearStencil +typedef void (APIENTRYP PFNGLCOLORMASKPROC)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +GLAPI PFNGLCOLORMASKPROC glad_glColorMask; +#define glColorMask glad_glColorMask +typedef void (APIENTRYP PFNGLCOMPILESHADERPROC)(GLuint shader); +GLAPI PFNGLCOMPILESHADERPROC glad_glCompileShader; +#define glCompileShader glad_glCompileShader +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); +GLAPI PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D; +#define glCompressedTexImage2D glad_glCompressedTexImage2D +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); +GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D; +#define glCompressedTexSubImage2D glad_glCompressedTexSubImage2D +typedef void (APIENTRYP PFNGLCOPYTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +GLAPI PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D; +#define glCopyTexImage2D glad_glCopyTexImage2D +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D; +#define glCopyTexSubImage2D glad_glCopyTexSubImage2D +typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC)(void); +GLAPI PFNGLCREATEPROGRAMPROC glad_glCreateProgram; +#define glCreateProgram glad_glCreateProgram +typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC)(GLenum type); +GLAPI PFNGLCREATESHADERPROC glad_glCreateShader; +#define glCreateShader glad_glCreateShader +typedef void (APIENTRYP PFNGLCULLFACEPROC)(GLenum mode); +GLAPI PFNGLCULLFACEPROC glad_glCullFace; +#define glCullFace glad_glCullFace +typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC)(GLsizei n, const GLuint *buffers); +GLAPI PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers; +#define glDeleteBuffers glad_glDeleteBuffers +typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSPROC)(GLsizei n, const GLuint *framebuffers); +GLAPI PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers; +#define glDeleteFramebuffers glad_glDeleteFramebuffers +typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC)(GLuint program); +GLAPI PFNGLDELETEPROGRAMPROC glad_glDeleteProgram; +#define glDeleteProgram glad_glDeleteProgram +typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSPROC)(GLsizei n, const GLuint *renderbuffers); +GLAPI PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers; +#define glDeleteRenderbuffers glad_glDeleteRenderbuffers +typedef void (APIENTRYP PFNGLDELETESHADERPROC)(GLuint shader); +GLAPI PFNGLDELETESHADERPROC glad_glDeleteShader; +#define glDeleteShader glad_glDeleteShader +typedef void (APIENTRYP PFNGLDELETETEXTURESPROC)(GLsizei n, const GLuint *textures); +GLAPI PFNGLDELETETEXTURESPROC glad_glDeleteTextures; +#define glDeleteTextures glad_glDeleteTextures +typedef void (APIENTRYP PFNGLDEPTHFUNCPROC)(GLenum func); +GLAPI PFNGLDEPTHFUNCPROC glad_glDepthFunc; +#define glDepthFunc glad_glDepthFunc +typedef void (APIENTRYP PFNGLDEPTHMASKPROC)(GLboolean flag); +GLAPI PFNGLDEPTHMASKPROC glad_glDepthMask; +#define glDepthMask glad_glDepthMask +typedef void (APIENTRYP PFNGLDEPTHRANGEFPROC)(GLfloat n, GLfloat f); +GLAPI PFNGLDEPTHRANGEFPROC glad_glDepthRangef; +#define glDepthRangef glad_glDepthRangef +typedef void (APIENTRYP PFNGLDETACHSHADERPROC)(GLuint program, GLuint shader); +GLAPI PFNGLDETACHSHADERPROC glad_glDetachShader; +#define glDetachShader glad_glDetachShader +typedef void (APIENTRYP PFNGLDISABLEPROC)(GLenum cap); +GLAPI PFNGLDISABLEPROC glad_glDisable; +#define glDisable glad_glDisable +typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC)(GLuint index); +GLAPI PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray; +#define glDisableVertexAttribArray glad_glDisableVertexAttribArray +typedef void (APIENTRYP PFNGLDRAWARRAYSPROC)(GLenum mode, GLint first, GLsizei count); +GLAPI PFNGLDRAWARRAYSPROC glad_glDrawArrays; +#define glDrawArrays glad_glDrawArrays +typedef void (APIENTRYP PFNGLDRAWELEMENTSPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices); +GLAPI PFNGLDRAWELEMENTSPROC glad_glDrawElements; +#define glDrawElements glad_glDrawElements +typedef void (APIENTRYP PFNGLENABLEPROC)(GLenum cap); +GLAPI PFNGLENABLEPROC glad_glEnable; +#define glEnable glad_glEnable +typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC)(GLuint index); +GLAPI PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray; +#define glEnableVertexAttribArray glad_glEnableVertexAttribArray +typedef void (APIENTRYP PFNGLFINISHPROC)(void); +GLAPI PFNGLFINISHPROC glad_glFinish; +#define glFinish glad_glFinish +typedef void (APIENTRYP PFNGLFLUSHPROC)(void); +GLAPI PFNGLFLUSHPROC glad_glFlush; +#define glFlush glad_glFlush +typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFERPROC)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +GLAPI PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer; +#define glFramebufferRenderbuffer glad_glFramebufferRenderbuffer +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D; +#define glFramebufferTexture2D glad_glFramebufferTexture2D +typedef void (APIENTRYP PFNGLFRONTFACEPROC)(GLenum mode); +GLAPI PFNGLFRONTFACEPROC glad_glFrontFace; +#define glFrontFace glad_glFrontFace +typedef void (APIENTRYP PFNGLGENBUFFERSPROC)(GLsizei n, GLuint *buffers); +GLAPI PFNGLGENBUFFERSPROC glad_glGenBuffers; +#define glGenBuffers glad_glGenBuffers +typedef void (APIENTRYP PFNGLGENERATEMIPMAPPROC)(GLenum target); +GLAPI PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap; +#define glGenerateMipmap glad_glGenerateMipmap +typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSPROC)(GLsizei n, GLuint *framebuffers); +GLAPI PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers; +#define glGenFramebuffers glad_glGenFramebuffers +typedef void (APIENTRYP PFNGLGENRENDERBUFFERSPROC)(GLsizei n, GLuint *renderbuffers); +GLAPI PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers; +#define glGenRenderbuffers glad_glGenRenderbuffers +typedef void (APIENTRYP PFNGLGENTEXTURESPROC)(GLsizei n, GLuint *textures); +GLAPI PFNGLGENTEXTURESPROC glad_glGenTextures; +#define glGenTextures glad_glGenTextures +typedef void (APIENTRYP PFNGLGETACTIVEATTRIBPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +GLAPI PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib; +#define glGetActiveAttrib glad_glGetActiveAttrib +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +GLAPI PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform; +#define glGetActiveUniform glad_glGetActiveUniform +typedef void (APIENTRYP PFNGLGETATTACHEDSHADERSPROC)(GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders); +GLAPI PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders; +#define glGetAttachedShaders glad_glGetAttachedShaders +typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC)(GLuint program, const GLchar *name); +GLAPI PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation; +#define glGetAttribLocation glad_glGetAttribLocation +typedef void (APIENTRYP PFNGLGETBOOLEANVPROC)(GLenum pname, GLboolean *data); +GLAPI PFNGLGETBOOLEANVPROC glad_glGetBooleanv; +#define glGetBooleanv glad_glGetBooleanv +typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params); +GLAPI PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv; +#define glGetBufferParameteriv glad_glGetBufferParameteriv +typedef GLenum (APIENTRYP PFNGLGETERRORPROC)(void); +GLAPI PFNGLGETERRORPROC glad_glGetError; +#define glGetError glad_glGetError +typedef void (APIENTRYP PFNGLGETFLOATVPROC)(GLenum pname, GLfloat *data); +GLAPI PFNGLGETFLOATVPROC glad_glGetFloatv; +#define glGetFloatv glad_glGetFloatv +typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)(GLenum target, GLenum attachment, GLenum pname, GLint *params); +GLAPI PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv; +#define glGetFramebufferAttachmentParameteriv glad_glGetFramebufferAttachmentParameteriv +typedef void (APIENTRYP PFNGLGETINTEGERVPROC)(GLenum pname, GLint *data); +GLAPI PFNGLGETINTEGERVPROC glad_glGetIntegerv; +#define glGetIntegerv glad_glGetIntegerv +typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC)(GLuint program, GLenum pname, GLint *params); +GLAPI PFNGLGETPROGRAMIVPROC glad_glGetProgramiv; +#define glGetProgramiv glad_glGetProgramiv +typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC)(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +GLAPI PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog; +#define glGetProgramInfoLog glad_glGetProgramInfoLog +typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params); +GLAPI PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv; +#define glGetRenderbufferParameteriv glad_glGetRenderbufferParameteriv +typedef void (APIENTRYP PFNGLGETSHADERIVPROC)(GLuint shader, GLenum pname, GLint *params); +GLAPI PFNGLGETSHADERIVPROC glad_glGetShaderiv; +#define glGetShaderiv glad_glGetShaderiv +typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC)(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +GLAPI PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog; +#define glGetShaderInfoLog glad_glGetShaderInfoLog +typedef void (APIENTRYP PFNGLGETSHADERPRECISIONFORMATPROC)(GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision); +GLAPI PFNGLGETSHADERPRECISIONFORMATPROC glad_glGetShaderPrecisionFormat; +#define glGetShaderPrecisionFormat glad_glGetShaderPrecisionFormat +typedef void (APIENTRYP PFNGLGETSHADERSOURCEPROC)(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); +GLAPI PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource; +#define glGetShaderSource glad_glGetShaderSource +typedef const GLubyte * (APIENTRYP PFNGLGETSTRINGPROC)(GLenum name); +GLAPI PFNGLGETSTRINGPROC glad_glGetString; +#define glGetString glad_glGetString +typedef void (APIENTRYP PFNGLGETTEXPARAMETERFVPROC)(GLenum target, GLenum pname, GLfloat *params); +GLAPI PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv; +#define glGetTexParameterfv glad_glGetTexParameterfv +typedef void (APIENTRYP PFNGLGETTEXPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params); +GLAPI PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv; +#define glGetTexParameteriv glad_glGetTexParameteriv +typedef void (APIENTRYP PFNGLGETUNIFORMFVPROC)(GLuint program, GLint location, GLfloat *params); +GLAPI PFNGLGETUNIFORMFVPROC glad_glGetUniformfv; +#define glGetUniformfv glad_glGetUniformfv +typedef void (APIENTRYP PFNGLGETUNIFORMIVPROC)(GLuint program, GLint location, GLint *params); +GLAPI PFNGLGETUNIFORMIVPROC glad_glGetUniformiv; +#define glGetUniformiv glad_glGetUniformiv +typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC)(GLuint program, const GLchar *name); +GLAPI PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation; +#define glGetUniformLocation glad_glGetUniformLocation +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVPROC)(GLuint index, GLenum pname, GLfloat *params); +GLAPI PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv; +#define glGetVertexAttribfv glad_glGetVertexAttribfv +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC)(GLuint index, GLenum pname, GLint *params); +GLAPI PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv; +#define glGetVertexAttribiv glad_glGetVertexAttribiv +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC)(GLuint index, GLenum pname, void **pointer); +GLAPI PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv; +#define glGetVertexAttribPointerv glad_glGetVertexAttribPointerv +typedef void (APIENTRYP PFNGLHINTPROC)(GLenum target, GLenum mode); +GLAPI PFNGLHINTPROC glad_glHint; +#define glHint glad_glHint +typedef GLboolean (APIENTRYP PFNGLISBUFFERPROC)(GLuint buffer); +GLAPI PFNGLISBUFFERPROC glad_glIsBuffer; +#define glIsBuffer glad_glIsBuffer +typedef GLboolean (APIENTRYP PFNGLISENABLEDPROC)(GLenum cap); +GLAPI PFNGLISENABLEDPROC glad_glIsEnabled; +#define glIsEnabled glad_glIsEnabled +typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFERPROC)(GLuint framebuffer); +GLAPI PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer; +#define glIsFramebuffer glad_glIsFramebuffer +typedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC)(GLuint program); +GLAPI PFNGLISPROGRAMPROC glad_glIsProgram; +#define glIsProgram glad_glIsProgram +typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFERPROC)(GLuint renderbuffer); +GLAPI PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer; +#define glIsRenderbuffer glad_glIsRenderbuffer +typedef GLboolean (APIENTRYP PFNGLISSHADERPROC)(GLuint shader); +GLAPI PFNGLISSHADERPROC glad_glIsShader; +#define glIsShader glad_glIsShader +typedef GLboolean (APIENTRYP PFNGLISTEXTUREPROC)(GLuint texture); +GLAPI PFNGLISTEXTUREPROC glad_glIsTexture; +#define glIsTexture glad_glIsTexture +typedef void (APIENTRYP PFNGLLINEWIDTHPROC)(GLfloat width); +GLAPI PFNGLLINEWIDTHPROC glad_glLineWidth; +#define glLineWidth glad_glLineWidth +typedef void (APIENTRYP PFNGLLINKPROGRAMPROC)(GLuint program); +GLAPI PFNGLLINKPROGRAMPROC glad_glLinkProgram; +#define glLinkProgram glad_glLinkProgram +typedef void (APIENTRYP PFNGLPIXELSTOREIPROC)(GLenum pname, GLint param); +GLAPI PFNGLPIXELSTOREIPROC glad_glPixelStorei; +#define glPixelStorei glad_glPixelStorei +typedef void (APIENTRYP PFNGLPOLYGONOFFSETPROC)(GLfloat factor, GLfloat units); +GLAPI PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset; +#define glPolygonOffset glad_glPolygonOffset +typedef void (APIENTRYP PFNGLREADPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels); +GLAPI PFNGLREADPIXELSPROC glad_glReadPixels; +#define glReadPixels glad_glReadPixels +typedef void (APIENTRYP PFNGLRELEASESHADERCOMPILERPROC)(void); +GLAPI PFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler; +#define glReleaseShaderCompiler glad_glReleaseShaderCompiler +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEPROC)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage; +#define glRenderbufferStorage glad_glRenderbufferStorage +typedef void (APIENTRYP PFNGLSAMPLECOVERAGEPROC)(GLfloat value, GLboolean invert); +GLAPI PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage; +#define glSampleCoverage glad_glSampleCoverage +typedef void (APIENTRYP PFNGLSCISSORPROC)(GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI PFNGLSCISSORPROC glad_glScissor; +#define glScissor glad_glScissor +typedef void (APIENTRYP PFNGLSHADERBINARYPROC)(GLsizei count, const GLuint *shaders, GLenum binaryFormat, const void *binary, GLsizei length); +GLAPI PFNGLSHADERBINARYPROC glad_glShaderBinary; +#define glShaderBinary glad_glShaderBinary +typedef void (APIENTRYP PFNGLSHADERSOURCEPROC)(GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length); +GLAPI PFNGLSHADERSOURCEPROC glad_glShaderSource; +#define glShaderSource glad_glShaderSource +typedef void (APIENTRYP PFNGLSTENCILFUNCPROC)(GLenum func, GLint ref, GLuint mask); +GLAPI PFNGLSTENCILFUNCPROC glad_glStencilFunc; +#define glStencilFunc glad_glStencilFunc +typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC)(GLenum face, GLenum func, GLint ref, GLuint mask); +GLAPI PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate; +#define glStencilFuncSeparate glad_glStencilFuncSeparate +typedef void (APIENTRYP PFNGLSTENCILMASKPROC)(GLuint mask); +GLAPI PFNGLSTENCILMASKPROC glad_glStencilMask; +#define glStencilMask glad_glStencilMask +typedef void (APIENTRYP PFNGLSTENCILMASKSEPARATEPROC)(GLenum face, GLuint mask); +GLAPI PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate; +#define glStencilMaskSeparate glad_glStencilMaskSeparate +typedef void (APIENTRYP PFNGLSTENCILOPPROC)(GLenum fail, GLenum zfail, GLenum zpass); +GLAPI PFNGLSTENCILOPPROC glad_glStencilOp; +#define glStencilOp glad_glStencilOp +typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEPROC)(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); +GLAPI PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate; +#define glStencilOpSeparate glad_glStencilOpSeparate +typedef void (APIENTRYP PFNGLTEXIMAGE2DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI PFNGLTEXIMAGE2DPROC glad_glTexImage2D; +#define glTexImage2D glad_glTexImage2D +typedef void (APIENTRYP PFNGLTEXPARAMETERFPROC)(GLenum target, GLenum pname, GLfloat param); +GLAPI PFNGLTEXPARAMETERFPROC glad_glTexParameterf; +#define glTexParameterf glad_glTexParameterf +typedef void (APIENTRYP PFNGLTEXPARAMETERFVPROC)(GLenum target, GLenum pname, const GLfloat *params); +GLAPI PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv; +#define glTexParameterfv glad_glTexParameterfv +typedef void (APIENTRYP PFNGLTEXPARAMETERIPROC)(GLenum target, GLenum pname, GLint param); +GLAPI PFNGLTEXPARAMETERIPROC glad_glTexParameteri; +#define glTexParameteri glad_glTexParameteri +typedef void (APIENTRYP PFNGLTEXPARAMETERIVPROC)(GLenum target, GLenum pname, const GLint *params); +GLAPI PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv; +#define glTexParameteriv glad_glTexParameteriv +typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); +GLAPI PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D; +#define glTexSubImage2D glad_glTexSubImage2D +typedef void (APIENTRYP PFNGLUNIFORM1FPROC)(GLint location, GLfloat v0); +GLAPI PFNGLUNIFORM1FPROC glad_glUniform1f; +#define glUniform1f glad_glUniform1f +typedef void (APIENTRYP PFNGLUNIFORM1FVPROC)(GLint location, GLsizei count, const GLfloat *value); +GLAPI PFNGLUNIFORM1FVPROC glad_glUniform1fv; +#define glUniform1fv glad_glUniform1fv +typedef void (APIENTRYP PFNGLUNIFORM1IPROC)(GLint location, GLint v0); +GLAPI PFNGLUNIFORM1IPROC glad_glUniform1i; +#define glUniform1i glad_glUniform1i +typedef void (APIENTRYP PFNGLUNIFORM1IVPROC)(GLint location, GLsizei count, const GLint *value); +GLAPI PFNGLUNIFORM1IVPROC glad_glUniform1iv; +#define glUniform1iv glad_glUniform1iv +typedef void (APIENTRYP PFNGLUNIFORM2FPROC)(GLint location, GLfloat v0, GLfloat v1); +GLAPI PFNGLUNIFORM2FPROC glad_glUniform2f; +#define glUniform2f glad_glUniform2f +typedef void (APIENTRYP PFNGLUNIFORM2FVPROC)(GLint location, GLsizei count, const GLfloat *value); +GLAPI PFNGLUNIFORM2FVPROC glad_glUniform2fv; +#define glUniform2fv glad_glUniform2fv +typedef void (APIENTRYP PFNGLUNIFORM2IPROC)(GLint location, GLint v0, GLint v1); +GLAPI PFNGLUNIFORM2IPROC glad_glUniform2i; +#define glUniform2i glad_glUniform2i +typedef void (APIENTRYP PFNGLUNIFORM2IVPROC)(GLint location, GLsizei count, const GLint *value); +GLAPI PFNGLUNIFORM2IVPROC glad_glUniform2iv; +#define glUniform2iv glad_glUniform2iv +typedef void (APIENTRYP PFNGLUNIFORM3FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +GLAPI PFNGLUNIFORM3FPROC glad_glUniform3f; +#define glUniform3f glad_glUniform3f +typedef void (APIENTRYP PFNGLUNIFORM3FVPROC)(GLint location, GLsizei count, const GLfloat *value); +GLAPI PFNGLUNIFORM3FVPROC glad_glUniform3fv; +#define glUniform3fv glad_glUniform3fv +typedef void (APIENTRYP PFNGLUNIFORM3IPROC)(GLint location, GLint v0, GLint v1, GLint v2); +GLAPI PFNGLUNIFORM3IPROC glad_glUniform3i; +#define glUniform3i glad_glUniform3i +typedef void (APIENTRYP PFNGLUNIFORM3IVPROC)(GLint location, GLsizei count, const GLint *value); +GLAPI PFNGLUNIFORM3IVPROC glad_glUniform3iv; +#define glUniform3iv glad_glUniform3iv +typedef void (APIENTRYP PFNGLUNIFORM4FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +GLAPI PFNGLUNIFORM4FPROC glad_glUniform4f; +#define glUniform4f glad_glUniform4f +typedef void (APIENTRYP PFNGLUNIFORM4FVPROC)(GLint location, GLsizei count, const GLfloat *value); +GLAPI PFNGLUNIFORM4FVPROC glad_glUniform4fv; +#define glUniform4fv glad_glUniform4fv +typedef void (APIENTRYP PFNGLUNIFORM4IPROC)(GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +GLAPI PFNGLUNIFORM4IPROC glad_glUniform4i; +#define glUniform4i glad_glUniform4i +typedef void (APIENTRYP PFNGLUNIFORM4IVPROC)(GLint location, GLsizei count, const GLint *value); +GLAPI PFNGLUNIFORM4IVPROC glad_glUniform4iv; +#define glUniform4iv glad_glUniform4iv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv; +#define glUniformMatrix2fv glad_glUniformMatrix2fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv; +#define glUniformMatrix3fv glad_glUniformMatrix3fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv; +#define glUniformMatrix4fv glad_glUniformMatrix4fv +typedef void (APIENTRYP PFNGLUSEPROGRAMPROC)(GLuint program); +GLAPI PFNGLUSEPROGRAMPROC glad_glUseProgram; +#define glUseProgram glad_glUseProgram +typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC)(GLuint program); +GLAPI PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram; +#define glValidateProgram glad_glValidateProgram +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FPROC)(GLuint index, GLfloat x); +GLAPI PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f; +#define glVertexAttrib1f glad_glVertexAttrib1f +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVPROC)(GLuint index, const GLfloat *v); +GLAPI PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv; +#define glVertexAttrib1fv glad_glVertexAttrib1fv +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FPROC)(GLuint index, GLfloat x, GLfloat y); +GLAPI PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f; +#define glVertexAttrib2f glad_glVertexAttrib2f +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVPROC)(GLuint index, const GLfloat *v); +GLAPI PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv; +#define glVertexAttrib2fv glad_glVertexAttrib2fv +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z); +GLAPI PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f; +#define glVertexAttrib3f glad_glVertexAttrib3f +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVPROC)(GLuint index, const GLfloat *v); +GLAPI PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv; +#define glVertexAttrib3fv glad_glVertexAttrib3fv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f; +#define glVertexAttrib4f glad_glVertexAttrib4f +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVPROC)(GLuint index, const GLfloat *v); +GLAPI PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv; +#define glVertexAttrib4fv glad_glVertexAttrib4fv +typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); +GLAPI PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer; +#define glVertexAttribPointer glad_glVertexAttribPointer +typedef void (APIENTRYP PFNGLVIEWPORTPROC)(GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI PFNGLVIEWPORTPROC glad_glViewport; +#define glViewport glad_glViewport +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/port/n64-fast3d-engine/glad/khrplatform.h b/port/n64-fast3d-engine/glad/khrplatform.h new file mode 100644 index 000000000..01646449c --- /dev/null +++ b/port/n64-fast3d-engine/glad/khrplatform.h @@ -0,0 +1,311 @@ +#ifndef __khrplatform_h_ +#define __khrplatform_h_ + +/* +** Copyright (c) 2008-2018 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +/* Khronos platform-specific types and definitions. + * + * The master copy of khrplatform.h is maintained in the Khronos EGL + * Registry repository at https://github.com/KhronosGroup/EGL-Registry + * The last semantic modification to khrplatform.h was at commit ID: + * 67a3e0864c2d75ea5287b9f3d2eb74a745936692 + * + * Adopters may modify this file to suit their platform. Adopters are + * encouraged to submit platform specific modifications to the Khronos + * group so that they can be included in future versions of this file. + * Please submit changes by filing pull requests or issues on + * the EGL Registry repository linked above. + * + * + * See the Implementer's Guidelines for information about where this file + * should be located on your system and for more details of its use: + * http://www.khronos.org/registry/implementers_guide.pdf + * + * This file should be included as + * #include + * by Khronos client API header files that use its types and defines. + * + * The types in khrplatform.h should only be used to define API-specific types. + * + * Types defined in khrplatform.h: + * khronos_int8_t signed 8 bit + * khronos_uint8_t unsigned 8 bit + * khronos_int16_t signed 16 bit + * khronos_uint16_t unsigned 16 bit + * khronos_int32_t signed 32 bit + * khronos_uint32_t unsigned 32 bit + * khronos_int64_t signed 64 bit + * khronos_uint64_t unsigned 64 bit + * khronos_intptr_t signed same number of bits as a pointer + * khronos_uintptr_t unsigned same number of bits as a pointer + * khronos_ssize_t signed size + * khronos_usize_t unsigned size + * khronos_float_t signed 32 bit floating point + * khronos_time_ns_t unsigned 64 bit time in nanoseconds + * khronos_utime_nanoseconds_t unsigned time interval or absolute time in + * nanoseconds + * khronos_stime_nanoseconds_t signed time interval in nanoseconds + * khronos_boolean_enum_t enumerated boolean type. This should + * only be used as a base type when a client API's boolean type is + * an enum. Client APIs which use an integer or other type for + * booleans cannot use this as the base type for their boolean. + * + * Tokens defined in khrplatform.h: + * + * KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values. + * + * KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0. + * KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0. + * + * Calling convention macros defined in this file: + * KHRONOS_APICALL + * KHRONOS_APIENTRY + * KHRONOS_APIATTRIBUTES + * + * These may be used in function prototypes as: + * + * KHRONOS_APICALL void KHRONOS_APIENTRY funcname( + * int arg1, + * int arg2) KHRONOS_APIATTRIBUTES; + */ + +#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC) +# define KHRONOS_STATIC 1 +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APICALL + *------------------------------------------------------------------------- + * This precedes the return type of the function in the function prototype. + */ +#if defined(KHRONOS_STATIC) + /* If the preprocessor constant KHRONOS_STATIC is defined, make the + * header compatible with static linking. */ +# define KHRONOS_APICALL +#elif defined(_WIN32) +# define KHRONOS_APICALL __declspec(dllimport) +#elif defined (__SYMBIAN32__) +# define KHRONOS_APICALL IMPORT_C +#elif defined(__ANDROID__) +# define KHRONOS_APICALL __attribute__((visibility("default"))) +#else +# define KHRONOS_APICALL +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APIENTRY + *------------------------------------------------------------------------- + * This follows the return type of the function and precedes the function + * name in the function prototype. + */ +#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__) + /* Win32 but not WinCE */ +# define KHRONOS_APIENTRY __stdcall +#else +# define KHRONOS_APIENTRY +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APIATTRIBUTES + *------------------------------------------------------------------------- + * This follows the closing parenthesis of the function prototype arguments. + */ +#if defined (__ARMCC_2__) +#define KHRONOS_APIATTRIBUTES __softfp +#else +#define KHRONOS_APIATTRIBUTES +#endif + +/*------------------------------------------------------------------------- + * basic type definitions + *-----------------------------------------------------------------------*/ +#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__) + + +/* + * Using + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 +/* + * To support platform where unsigned long cannot be used interchangeably with + * inptr_t (e.g. CHERI-extended ISAs), we can use the stdint.h intptr_t. + * Ideally, we could just use (u)intptr_t everywhere, but this could result in + * ABI breakage if khronos_uintptr_t is changed from unsigned long to + * unsigned long long or similar (this results in different C++ name mangling). + * To avoid changes for existing platforms, we restrict usage of intptr_t to + * platforms where the size of a pointer is larger than the size of long. + */ +#if defined(__SIZEOF_LONG__) && defined(__SIZEOF_POINTER__) +#if __SIZEOF_POINTER__ > __SIZEOF_LONG__ +#define KHRONOS_USE_INTPTR_T +#endif +#endif + +#elif defined(__VMS ) || defined(__sgi) + +/* + * Using + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(_WIN32) && !defined(__SCITECH_SNAP__) + +/* + * Win32 + */ +typedef __int32 khronos_int32_t; +typedef unsigned __int32 khronos_uint32_t; +typedef __int64 khronos_int64_t; +typedef unsigned __int64 khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(__sun__) || defined(__digital__) + +/* + * Sun or Digital + */ +typedef int khronos_int32_t; +typedef unsigned int khronos_uint32_t; +#if defined(__arch64__) || defined(_LP64) +typedef long int khronos_int64_t; +typedef unsigned long int khronos_uint64_t; +#else +typedef long long int khronos_int64_t; +typedef unsigned long long int khronos_uint64_t; +#endif /* __arch64__ */ +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif 0 + +/* + * Hypothetical platform with no float or int64 support + */ +typedef int khronos_int32_t; +typedef unsigned int khronos_uint32_t; +#define KHRONOS_SUPPORT_INT64 0 +#define KHRONOS_SUPPORT_FLOAT 0 + +#else + +/* + * Generic fallback + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#endif + + +/* + * Types that are (so far) the same on all platforms + */ +typedef signed char khronos_int8_t; +typedef unsigned char khronos_uint8_t; +typedef signed short int khronos_int16_t; +typedef unsigned short int khronos_uint16_t; + +/* + * Types that differ between LLP64 and LP64 architectures - in LLP64, + * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears + * to be the only LLP64 architecture in current use. + */ +#ifdef KHRONOS_USE_INTPTR_T +typedef intptr_t khronos_intptr_t; +typedef uintptr_t khronos_uintptr_t; +#elif defined(_WIN64) +typedef signed long long int khronos_intptr_t; +typedef unsigned long long int khronos_uintptr_t; +#else +typedef signed long int khronos_intptr_t; +typedef unsigned long int khronos_uintptr_t; +#endif + +#if defined(_WIN64) +typedef signed long long int khronos_ssize_t; +typedef unsigned long long int khronos_usize_t; +#else +typedef signed long int khronos_ssize_t; +typedef unsigned long int khronos_usize_t; +#endif + +#if KHRONOS_SUPPORT_FLOAT +/* + * Float type + */ +typedef float khronos_float_t; +#endif + +#if KHRONOS_SUPPORT_INT64 +/* Time types + * + * These types can be used to represent a time interval in nanoseconds or + * an absolute Unadjusted System Time. Unadjusted System Time is the number + * of nanoseconds since some arbitrary system event (e.g. since the last + * time the system booted). The Unadjusted System Time is an unsigned + * 64 bit value that wraps back to 0 every 584 years. Time intervals + * may be either signed or unsigned. + */ +typedef khronos_uint64_t khronos_utime_nanoseconds_t; +typedef khronos_int64_t khronos_stime_nanoseconds_t; +#endif + +/* + * Dummy value used to pad enum types to 32 bits. + */ +#ifndef KHRONOS_MAX_ENUM +#define KHRONOS_MAX_ENUM 0x7FFFFFFF +#endif + +/* + * Enumerated boolean type + * + * Values other than zero should be considered to be true. Therefore + * comparisons should not be made against KHRONOS_TRUE. + */ +typedef enum { + KHRONOS_FALSE = 0, + KHRONOS_TRUE = 1, + KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM +} khronos_boolean_enum_t; + +#endif /* __khrplatform_h_ */ diff --git a/port/src/crash.c b/port/src/crash.c new file mode 100644 index 000000000..625da2745 --- /dev/null +++ b/port/src/crash.c @@ -0,0 +1,39 @@ +#include +#include +#include +#include + +u8 g_CrashHasMessage = 0; +s32 g_CrashEnabled = 0; + +static char crashMsg[1024]; + +void crashCreateThread(void) +{ + // TODO: install a crash handler of some sort +} + +void crashSetMessage(char *string) +{ + strncpy(crashMsg, string, sizeof(crashMsg) - 1); + fprintf(stderr, "crashSetMessage: %s\n", crashMsg); + g_CrashHasMessage = 1; +} + +void crashReset(void) +{ + crashMsg[0] = 0; + g_CrashHasMessage = 0; +} + +void crashAppendChar(char c) +{ + g_CrashHasMessage = 1; + for (u32 i = 0; i < sizeof(crashMsg) - 1; ++i) { + if (crashMsg[i] == '\0') { + crashMsg[i] = c; + crashMsg[i + 1] = '\0'; + break; + } + } +} diff --git a/port/src/fs.c b/port/src/fs.c new file mode 100644 index 000000000..61f267465 --- /dev/null +++ b/port/src/fs.c @@ -0,0 +1,89 @@ +#include +#include +#include +#include +#include +#include +#include "fs.h" + +#ifdef PATH_MAX +#define FS_MAXPATH PATH_MAX +#else +#define FS_MAXPATH 1024 +#endif + +#define FS_BASEDIR "data" +#define FS_MAX_FILES 2048 + +static char baseDir[FS_MAXPATH + 1]; + +static struct { + char *name[FS_MAXPATH + 1]; + s32 size; + void *data; +} fileSlots[FS_MAX_FILES]; + +static const char *fsFullPath(const char *relPath) +{ + static char pathBuf[FS_MAXPATH]; + snprintf(pathBuf, sizeof(pathBuf), "%s/%s", baseDir, relPath); + return pathBuf; +} + +s32 fsInit(void) +{ + // TODO: support appdata/home/whatever + strcpy(baseDir, FS_BASEDIR); + return 0; +} + +void *fsFileLoad(const char *name, u32 *outSize) +{ + const char *fullName = fsFullPath(name); + + FILE *f = fopen(fullName, "rb"); + if (!f) { + fprintf(stderr, "fsFileLoad: could not find file: %s\n", fullName); + return NULL; + } + + fseek(f, 0, SEEK_END); + const s32 size = ftell(f); + fseek(f, 0, SEEK_SET); + + if (size < 0) { + fprintf(stderr, "fsFileLoad: empty file or invalid size (%d): %s\n", size, fullName); + fclose(f); + return NULL; + } + + void *buf = NULL; + if (size) { + buf = calloc(1, size + 1); // sick hack for a free null terminator + if (!buf) { + fprintf(stderr, "fsFileLoad: could not alloc %d bytes for file: %s\n", size, fullName); + fclose(f); + return NULL; + } + fread(buf, 1, size, f); + } + + fclose(f); + + if (outSize) { + *outSize = size; + } + + return buf; +} + +s32 fsFileSize(const char *name) +{ + const char *fullName = fsFullPath(name); + struct stat st; + if (stat(fullName, &st) < 0) { + return -1; + } else { + return st.st_size; + } +} diff --git a/port/src/input.c b/port/src/input.c new file mode 100644 index 000000000..5a1ef006d --- /dev/null +++ b/port/src/input.c @@ -0,0 +1,137 @@ +#include +#include +#include +#include +#include "input.h" + +static SDL_GameController *pads[INPUT_MAX_CONTROLLERS]; +static SDL_Haptic *haptics[INPUT_MAX_CONTROLLERS]; + +static const u16 buttonMap[] = { + /* SDL_CONTROLLER_BUTTON_A */ A_BUTTON, + /* SDL_CONTROLLER_BUTTON_B */ B_BUTTON, + /* SDL_CONTROLLER_BUTTON_X */ Z_TRIG, + /* SDL_CONTROLLER_BUTTON_Y */ Z_TRIG, + /* SDL_CONTROLLER_BUTTON_BACK */ START_BUTTON, + /* SDL_CONTROLLER_BUTTON_GUIDE */ 0, + /* SDL_CONTROLLER_BUTTON_START */ START_BUTTON, + /* SDL_CONTROLLER_BUTTON_LEFTSTICK */ 0, + /* SDL_CONTROLLER_BUTTON_RIGHTSTICK */ 0, + /* SDL_CONTROLLER_BUTTON_LEFTSHOULDER */ L_TRIG, + /* SDL_CONTROLLER_BUTTON_RIGHTSHOULDER */ R_TRIG, + /* SDL_CONTROLLER_BUTTON_DPAD_UP */ U_JPAD, + /* SDL_CONTROLLER_BUTTON_DPAD_DOWN */ D_JPAD, + /* SDL_CONTROLLER_BUTTON_DPAD_LEFT */ L_JPAD, + /* SDL_CONTROLLER_BUTTON_DPAD_RIGHT */ R_JPAD, +}; + +static const u16 buttonTrigLeft = Z_TRIG; +static const u16 buttonTrigRight = Z_TRIG; + +static s32 connectedMask = 0; + +s32 inputInit(void) +{ + if (!SDL_WasInit(SDL_INIT_GAMECONTROLLER)) { + if (SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) != 0) { + return -1; + } + } + + const s32 numJoys = SDL_NumJoysticks(); + + s32 ret = 0; + for (s32 jidx = 0, cidx = 0; jidx < numJoys && cidx < INPUT_MAX_CONTROLLERS; ++jidx) { + if (SDL_IsGameController(jidx)) { + pads[cidx] = SDL_GameControllerOpen(jidx); + if (pads[cidx]) { + SDL_Haptic *hap = SDL_HapticOpen(jidx); + if (hap) { + if (SDL_HapticRumbleSupported(hap) && (SDL_HapticRumbleInit(hap) == 0)) { + haptics[cidx] = hap; + } else { + SDL_HapticClose(hap); + } + } + ret |= 1 << cidx; + ++cidx; + } + } + } + + connectedMask = ret; + + return ret; +} + +s32 inputReadController(s32 idx, OSContPad *npad) +{ + if (idx < 0 || idx >= INPUT_MAX_CONTROLLERS || !pads[idx] || !npad) { + return -1; + } + + const s16 leftX = SDL_GameControllerGetAxis(pads[idx], SDL_CONTROLLER_AXIS_LEFTX); + const s16 leftY = SDL_GameControllerGetAxis(pads[idx], SDL_CONTROLLER_AXIS_LEFTY); + const s16 rightX = SDL_GameControllerGetAxis(pads[idx], SDL_CONTROLLER_AXIS_RIGHTX); + const s16 rightY = SDL_GameControllerGetAxis(pads[idx], SDL_CONTROLLER_AXIS_RIGHTY); + + npad->button = 0; + + if (rightX < -0x4000) npad->button |= L_CBUTTONS; + if (rightX > +0x4000) npad->button |= R_CBUTTONS; + if (rightY < -0x4000) npad->button |= U_CBUTTONS; + if (rightY > +0x4000) npad->button |= D_CBUTTONS; + + for (size_t i = 0; i < sizeof(buttonMap) / sizeof(*buttonMap); ++i) { + if (buttonMap[i]) { + if (SDL_GameControllerGetButton(pads[idx], i)) { + npad->button |= buttonMap[i]; + } + } + } + + const s32 stickY = -leftY / 0x100; + npad->stick_x = leftX / 0x100; + npad->stick_y = (stickY == 128) ? 127 : stickY; + + return 0; +} + +void inputUpdate(void) +{ + SDL_GameControllerUpdate(); + // TODO: handle controller changes +} + +s32 inputControllerConnected(s32 idx) +{ + if (idx < 0 || idx >= INPUT_MAX_CONTROLLERS) { + return 0; + } + return !!pads[idx]; +} + +s32 inputRumbleSupported(s32 idx) +{ + if (idx < 0 || idx >= INPUT_MAX_CONTROLLERS) { + return 0; + } + return !!haptics[idx]; +} + +void inputRumble(s32 idx, f32 strength, f32 time) +{ + if (idx < 0 || idx >= INPUT_MAX_CONTROLLERS || !haptics[idx]) { + return; + } + if (strength <= 0.f) { + SDL_HapticRumbleStop(haptics[idx]); + } else { + SDL_HapticRumblePlay(haptics[idx], strength, (u32)(time * 1000.f)); + } +} + +s32 inputControllerMask(void) +{ + return connectedMask; +} diff --git a/port/src/libultra.c b/port/src/libultra.c new file mode 100644 index 000000000..21ca2d881 --- /dev/null +++ b/port/src/libultra.c @@ -0,0 +1,446 @@ +#include +#include +#include +#include +#include +#include +#include "system.h" +#include "input.h" +#include "video.h" + +#define EEPROM_SIZE (EEP16K_MAXBLOCKS * 8) +#define EEPROM_FNAME "eeprom.bin" +#define OS_COUNTER_RATE 46875000ULL + +u64 osClockRate = OS_CLOCK_RATE; +u32 osMemSize = 16 * 1024 * 1024; /* expansion pak installed plus some extra */ +s32 osTvType = OS_TV_NTSC; /* 0 = PAL, 1 = NTSC, 2 = MPAL */ +s32 osResetType = 0; /* 0 = cold reset */ +s32 osViClock = VI_NTSC_CLOCK; + +/* Time */ + +OSTime osGetTime(void) +{ + // u64 should be enough to last a while + return (sysGetTicks() * OS_COUNTER_RATE) / sysGetTicksPerSecond(); +} + +u32 osGetCount(void) +{ + return (u32)osGetTime(); +} + +/* Thread */ + +void osCreateThread(OSThread *thrd, OSId id, void (*entry)(void *), void *arg, void *sp, OSPri p) +{ + thrd->id = id; + thrd->state = OS_STATE_STOPPED; +} + +void osDestroyThread(OSThread *thrd) +{ + thrd->id = 0; + thrd->state = 0; +} + +void osYieldThread(void) +{ + +} + +void osStartThread(OSThread *thrd) +{ + thrd->state = OS_STATE_RUNNING; +} + +void osStopThread(OSThread *thrd) +{ + thrd->state = OS_STATE_STOPPED; +} + +OSPri osGetThreadPri(OSThread *thrd) +{ + return 0; +} + +void osSetThreadPri(OSThread *thrd, OSPri pri) +{ + +} + +/* Mesg */ + +void osCreateMesgQueue(OSMesgQueue *mq, OSMesg *msgBuf, s32 count) +{ + mq->validCount = 0; + mq->first = 0; + mq->msgCount = count; + mq->msg = msgBuf; +} + +void osSetEventMesg(OSEvent e, OSMesgQueue *mq, OSMesg msg) +{ + +} + +s32 osSendMesg(OSMesgQueue *mq, OSMesg msg, s32 flag) +{ + return 0; +} + +s32 osRecvMesg(OSMesgQueue *mq, OSMesg *msg, s32 flag) +{ + return 0; +} + +/* Vi */ + +void osCreateViManager(OSPri pri) +{ + +} + +void osViSetMode(OSViMode *mode) +{ + +} + +void osViSetEvent(OSMesgQueue *mq, OSMesg msg, u32 retraceCount) +{ + +} + +void osViBlack(u8 active) +{ + if (active) { + videoClearScreen(); + } +} + +void osViSetSpecialFeatures(u32 func) +{ + +} + +void osViSwapBuffer(void *vaddr) +{ + +} + +void osViSetXScale(f32 value) +{ + +} + +void osViSetYScale(f32 value) +{ + +} + +/* Ai */ + +s32 osAiSetFrequency(u32 frequency) +{ + register unsigned int dacRate; + register char bitRate; + register float f; + f = osViClock / (float)frequency + .5f; + dacRate = f; + + if (dacRate < AI_MIN_DAC_RATE) { + return -1; + } + + bitRate = dacRate / 66; + + if (bitRate > AI_MAX_BIT_RATE) { + bitRate = AI_MAX_BIT_RATE; + } + + return osViClock / (s32)dacRate; +} + +u32 osAiGetLength(void) +{ + return 0; +} + +s32 osAiSetNextBuffer(void *bufPtr, u32 size) +{ + return 0; +} + +/* Cont */ + +s32 osContInit(OSMesgQueue *mesgq, u8 *bitpattern, OSContStatus *data) +{ + if (bitpattern) { + *bitpattern = inputControllerMask(); + } + if (data) { + osContGetQuery(data); + } + return 0; +} + +s32 osContStartReadData(OSMesgQueue *mesgq) +{ + osSendMesg(mesgq, (OSMesg)0, OS_MESG_NOBLOCK); + return 0; +} + +void osContGetReadData(OSContPad *pad) +{ + // game always passes in an array of 4 OSContPads + for (s32 i = 0; i < MAXCONTROLLERS; ++i, ++pad) { + pad->button = 0; + pad->stick_x = 0; + pad->stick_y = 0; + if (inputReadController(i, pad) < 0) { + pad->errno = CONT_NO_RESPONSE_ERROR; + } else { + pad->errno = 0; + } + } +} + +s32 osContStartQuery(OSMesgQueue *mq) +{ + return 0; +} + +void osContGetQuery(OSContStatus *status) +{ + // also always 4 status structs here + for (s32 i = 0; i < MAXCONTROLLERS; ++i, ++status) { + if (inputControllerConnected(i)) { + status->errno = 0; + status->type = CONT_ABSOLUTE; + status->status = 1; + } else { + status->errno = CONT_NO_RESPONSE_ERROR; + status->type = 0; + status->status = 0; + } + } +} + +/* Motor */ + +s32 osMotorProbe(OSMesgQueue *ctrlrqueue, OSPfs* pfs, s32 channel) +{ + if (pfs && inputRumbleSupported(channel)) { + pfs->queue = ctrlrqueue; + pfs->channel = channel; + pfs->activebank = 0xff; + pfs->status = PFS_MOTOR_INITIALIZED; + return 0; + } + return PFS_ERR_NOPACK; +} + +s32 __osMotorAccess(OSPfs *pfs, s32 cmd) +{ + if (!pfs || pfs->channel < 0 || pfs->channel >= INPUT_MAX_CONTROLLERS) { + return PFS_ERR_NOPACK; + } + + const f32 strength = (cmd == MOTOR_START) ? INPUT_RUMBLE_STRENGTH : 0.f; + inputRumble(pfs->channel, strength, 5.f); // hope someone turns it off in those 5 seconds + + return 0; +} + +/* Eeprom */ + +s32 osEepromProbe(OSMesgQueue *mq) +{ + return EEPROM_TYPE_16K; +} + +s32 osEepromLongRead(OSMesgQueue *mq, u8 address, u8 *buffer, int nbytes) +{ + u8 content[EEPROM_SIZE]; + s32 ret = -1; + FILE *fp = fopen(EEPROM_FNAME, "rb"); + if (fp == NULL) { + return -1; + } + if (fread(content, 1, EEPROM_SIZE, fp) == EEPROM_SIZE) { + memcpy(buffer, content + address * 8, nbytes); + ret = 0; + } + fclose(fp); + return ret; +} + +s32 osEepromLongWrite(OSMesgQueue *mq, u8 address, u8 *buffer, int nbytes) +{ + u8 content[EEPROM_SIZE] = { 0 }; + if (address != 0 || nbytes != EEPROM_SIZE) { + osEepromLongRead(mq, 0, content, EEPROM_SIZE); + } + memcpy(content + address * 8, buffer, nbytes); + FILE* fp = fopen(EEPROM_FNAME, "wb"); + if (fp == NULL) { + return -1; + } + s32 ret = fwrite(content, 1, EEPROM_SIZE, fp) == EEPROM_SIZE ? 0 : -1; + fclose(fp); + return ret; +} + +/* Pfs */ + +s32 osPfsIsPlug(OSMesgQueue *queue, u8 *pattern) +{ + if (pattern) { + *pattern = 0; + } + return 0; +} + +s32 osPfsInitPak(OSMesgQueue *queue, OSPfs *pfs, s32 channel, s32 *arg3) +{ + return PFS_ERR_NOPACK; +} + +s32 osPfsChecker(OSPfs *pfs) +{ + return PFS_ERR_NOPACK; +} + +s32 osPfsFreeBlocks(OSPfs *pfs, s32 *remaining) +{ + return PFS_ERR_NOPACK; +} + +s32 osPfsNumFiles(OSPfs *pfs, s32 *max_files, s32 *files_used) +{ + return PFS_ERR_NOPACK; +} + +s32 osPfsAllocateFile(OSPfs *pfs, u16 company_code, u32 game_code, u8 *game_name, u8 *ext_name, int num_bytes, s32 *file_no) +{ + return PFS_ERR_NOPACK; +} + +s32 osPfsFindFile(OSPfs *pfs, u16 company_code, u32 game_code, u8 *game_name, u8 *ext_name, s32 *file_no) +{ + return PFS_ERR_NOPACK; +} + +s32 osPfsDeleteFile(OSPfs *pfs, u16 company_code, u32 game_code, u8 *game_name, u8 *ext_name) +{ + return PFS_ERR_NOPACK; +} + +s32 osPfsReSizeFile(OSPfs *pfs, u16 company_code, u32 game_code, u8 *game_name, u8 *ext_name, int length) +{ + return PFS_ERR_NOPACK; +} + +s32 osPfsFileState(OSPfs *pfs, s32 fileNo, OSPfsState *state) +{ + return PFS_ERR_NOPACK; +} + +s32 osPfsReadWriteFile(OSPfs* pfs, s32 fileNo, u8 flag, int offset, int size, u8* data) +{ + return PFS_ERR_NOPACK; +} + +/* Gbpak */ + +s32 osGbpakInit(OSMesgQueue *, OSPfs *, int) +{ + return PFS_ERR_NOPACK; +} + +s32 osGbpakPower(OSPfs *, s32) +{ + return PFS_ERR_NOPACK; +} + +s32 osGbpakReadWrite(OSPfs *, u16, u16, u8 *, u16) +{ + return PFS_ERR_NOPACK; +} + +s32 osGbpakReadId(OSPfs *, OSGbpakId *, u8 *) +{ + return PFS_ERR_NOPACK; +} + +/* Misc */ + +void osWritebackDCacheAll(void) +{ + +} + +void osWritebackDCache(void *a, s32 b) +{ + +} + +void osInvalDCache(void *a, s32 b) +{ + +} + +s32 osPiStartDma(OSIoMesg *mb, s32 priority, s32 direction, uintptr_t devAddr, void *vAddr, size_t nbytes, OSMesgQueue *mq) +{ + memcpy(vAddr, (const void *)devAddr, nbytes); + return 0; +} + +s32 osPiReadIo(u32 devaddr, u32 *data) +{ + return 0; +} + +uintptr_t osVirtualToPhysical(void *addr) +{ + return (uintptr_t)addr; +} + +u32 osGetMemSize(void) +{ + return osMemSize; +} + +OSIntMask osGetIntMask(void) +{ + return 0; +} + +OSIntMask osSetIntMask(OSIntMask mask) +{ + return 0; +} + +/* libc compatibility wrappers */ + +#ifndef HAVE_BZERO +void bzero(void *ptr, s32 size) +{ + memset(ptr, 0, size); +} +#endif + +#ifndef HAVE_BCOPY +void bcopy(const void *src, void *dst, s32 n) +{ + memcpy(dst, src, n); +} +#endif + +#ifndef HAVE_BCMP +s32 bcmp(const void *s1, const void *s2, s32 n) +{ + return memcmp(s1, s2, n); +} +#endif diff --git a/port/src/main.c b/port/src/main.c new file mode 100644 index 000000000..534a706c3 --- /dev/null +++ b/port/src/main.c @@ -0,0 +1,74 @@ +#include +#include +#include +#include +#include + +#include "lib/main.h" +#include "bss.h" + +#include "video.h" +#include "input.h" +#include "fs.h" +#include "romdata.h" +#include "system.h" + +u32 g_OsMemSize = 0; +u8 g_Is4Mb = 0; +s8 g_Resetting = false; +OSSched g_Sched; + +OSMesgQueue g_MainMesgQueue; +OSMesg g_MainMesgBuf[32]; + +u8 *g_MempHeap = NULL; +u32 g_MempHeapSize = 0; + +u32 g_VmNumTlbMisses = 0; +u32 g_VmNumPageMisses = 0; +u32 g_VmNumPageReplaces = 0; +u8 g_VmShowStats = 0; + +s32 bootGetMemSize(void) +{ + return (s32)g_OsMemSize; +} + +void *bootAllocateStack(s32 threadid, s32 size) +{ + static u8 bruh[0x1000]; + return bruh; +} + +void bootCreateSched(void) +{ + osCreateMesgQueue(&g_MainMesgQueue, g_MainMesgBuf, ARRAYCOUNT(g_MainMesgBuf)); + if (osTvType == OS_TV_MPAL) { + osCreateScheduler(&g_Sched, NULL, OS_VI_MPAL_LAN1, 1); + } else { + osCreateScheduler(&g_Sched, NULL, OS_VI_NTSC_LAN1, 1); + } +} + +int main(int argc, const char **argv) +{ + fsInit(); + videoInit(); + inputInit(); + romdataInit(); + + bootCreateSched(); + + g_OsMemSize = osGetMemSize(); + g_SndDisabled = true; // for now + + g_MempHeapSize = g_OsMemSize; + g_MempHeap = calloc(1, g_MempHeapSize); + if (!g_MempHeap) { + sysFatalError("Could not alloc %u bytes for memp heap.", g_MempHeapSize); + } + + mainProc(); + + return 0; +} diff --git a/port/src/pdmain.c b/port/src/pdmain.c new file mode 100644 index 000000000..5d029d84c --- /dev/null +++ b/port/src/pdmain.c @@ -0,0 +1,644 @@ +#include +#include + +#include +#include +#include "lib/sched.h" +#include "lib/vars.h" +#include "constants.h" +#include "game/camdraw.h" +#include "game/cheats.h" +#include "game/debug.h" +#include "game/file.h" +#include "game/lang.h" +#include "game/race.h" +#include "game/body.h" +#include "game/stubs/game_000840.h" +#include "game/stubs/game_000850.h" +#include "game/stubs/game_000860.h" +#include "game/stubs/game_000870.h" +#include "game/smoke.h" +#include "game/stubs/game_0008e0.h" +#include "game/stubs/game_0008f0.h" +#include "game/stubs/game_000900.h" +#include "game/stubs/game_000910.h" +#include "game/tex.h" +#include "game/stubs/game_00b180.h" +#include "game/stubs/game_00b200.h" +#include "game/challenge.h" +#include "game/title.h" +#include "game/pdmode.h" +#include "game/objectives.h" +#include "game/endscreen.h" +#include "game/playermgr.h" +#include "game/game_1531a0.h" +#include "game/gfxmemory.h" +#include "game/lang.h" +#include "game/lv.h" +#include "game/timing.h" +#include "game/music.h" +#include "game/stubs/game_175f50.h" +#include "game/game_175f90.h" +#include "game/zbuf.h" +#include "game/game_1a78b0.h" +#include "game/mplayer/mplayer.h" +#include "game/pak.h" +#include "game/splat.h" +#include "game/utils.h" +#include "bss.h" +#include "lib/audiomgr.h" +#include "lib/args.h" +#include "lib/boot.h" +#include "lib/vm.h" +#include "lib/rzip.h" +#include "lib/vi.h" +#include "lib/fault.h" +#include "lib/crash.h" +#include "lib/dma.h" +#include "lib/joy.h" +#include "lib/main.h" +#include "lib/snd.h" +#include "lib/memp.h" +#include "lib/mema.h" +#include "lib/profile.h" +#include "lib/videbug.h" +#include "lib/debughud.h" +#include "lib/anim.h" +#include "lib/rdp.h" +#include "lib/lib_34d0.h" +#include "lib/lib_2f490.h" +#include "lib/rmon.h" +#include "lib/rng.h" +#include "lib/str.h" +#include "data.h" +#include "types.h" + +#include "video.h" +#include "input.h" + +extern u8 *g_MempHeap; +extern u32 g_MempHeapSize; + +void rngSetSeed(u32 seed); +void schedFrame(OSSched *sc); + +bool var8005d9b0 = false; +s32 g_StageNum = STAGE_TITLE; +u32 g_MainMemaHeapSize = 1024 * 300; +bool var8005d9bc = false; +s32 var8005d9c0 = 0; +s32 var8005d9c4 = 0; +bool g_MainGameLogicEnabled = true; +u32 g_MainNumGfxTasks = 0; +bool g_MainIsEndscreen = false; +s32 g_DoBootPakMenu = 0; + +u32 var8005dd3c = 0x00000000; +u32 var8005dd40 = 0x00000000; +u32 var8005dd44 = 0x00000000; +u32 var8005dd48 = 0x00000000; +u32 var8005dd4c = 0x00000000; +u32 var8005dd50 = 0x00000000; +s32 g_MainChangeToStageNum = -1; +bool g_MainIsDebugMenuOpen = false; + +struct stageallocation g_StageAllocations8Mb[] = { + { STAGE_CITRAINING, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" }, + { STAGE_DEFECTION, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" }, + { STAGE_INVESTIGATION, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" }, + { STAGE_EXTRACTION, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" }, + { STAGE_CHICAGO, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" }, + { STAGE_G5BUILDING, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" }, + { STAGE_VILLA, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma600" }, + { STAGE_INFILTRATION, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma500" }, + { STAGE_RESCUE, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma500" }, + { STAGE_ESCAPE, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma500" }, + { STAGE_AIRBASE, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" }, + { STAGE_AIRFORCEONE, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" }, + { STAGE_CRASHSITE, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" }, + { STAGE_PELAGIC, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" }, + { STAGE_DEEPSEA, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" }, + { STAGE_DEFENSE, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" }, + { STAGE_ATTACKSHIP, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" }, + { STAGE_SKEDARRUINS, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" }, + { STAGE_MP_SKEDAR, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" }, + { STAGE_MP_RAVINE, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" }, + { STAGE_MP_PIPES, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" }, + { STAGE_MP_G5BUILDING, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" }, + { STAGE_MP_SEWERS, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" }, + { STAGE_MP_WAREHOUSE, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" }, + { STAGE_MP_BASE, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" }, + { STAGE_MP_COMPLEX, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" }, + { STAGE_MP_TEMPLE, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" }, + { STAGE_MP_FELICITY, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" }, + { STAGE_MP_AREA52, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" }, + { STAGE_MP_GRID, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" }, + { STAGE_MP_CARPARK, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" }, + { STAGE_MP_RUINS, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" }, + { STAGE_MP_FORTRESS, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" }, + { STAGE_MP_VILLA, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" }, + { STAGE_TEST_RUN, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" }, + { STAGE_TEST_MP2, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" }, + { STAGE_TEST_MP6, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" }, + { STAGE_TEST_MP7, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" }, + { STAGE_TEST_MP8, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" }, + { STAGE_TEST_MP14, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" }, + { STAGE_TEST_MP16, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" }, + { STAGE_TEST_MP17, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" }, + { STAGE_TEST_MP18, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" }, + { STAGE_TEST_MP19, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" }, + { STAGE_TEST_MP20, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" }, + { STAGE_TEST_ASH, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" }, + { STAGE_28, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" }, + { STAGE_MBR, "-ml0 -me0 -mgfx120 -mvtx100 -ma700" }, + { STAGE_TEST_SILO, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" }, + { STAGE_24, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" }, + { STAGE_MAIANSOS, "-ml0 -me0 -mgfx120 -mvtx100 -ma500" }, + { STAGE_RETAKING, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" }, + { STAGE_TEST_DEST, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" }, + { STAGE_2B, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" }, + { STAGE_WAR, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" }, + { STAGE_TEST_UFF, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" }, + { STAGE_TEST_OLD, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" }, + { STAGE_DUEL, "-ml0 -me0 -mgfx120 -mvtx100 -ma700" }, + { STAGE_TEST_LAM, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" }, + { STAGE_TEST_ARCH, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" }, + { STAGE_TEST_LEN, "-ml0 -me0 -mgfx120 -mvtx98 -ma300" }, + { STAGE_TITLE, "-ml0 -me0 -mgfx80 -mvtx20 -ma001" }, + { 0, "-ml0 -me0 -mgfx120 -mvtx98 -ma300" }, +}; + +struct stageallocation g_StageAllocations4Mb[] = { + { STAGE_MP_SKEDAR, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" }, + { STAGE_MP_PIPES, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" }, + { STAGE_MP_AREA52, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" }, + { STAGE_MP_RAVINE, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" }, + { STAGE_MP_G5BUILDING, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" }, + { STAGE_MP_SEWERS, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" }, + { STAGE_MP_WAREHOUSE, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" }, + { STAGE_MP_BASE, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" }, + { STAGE_MP_COMPLEX, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" }, + { STAGE_MP_TEMPLE, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" }, + { STAGE_MP_FELICITY, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" }, + { STAGE_MP_GRID, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" }, + { STAGE_TEST_RUN, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" }, + { STAGE_MP_CARPARK, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" }, + { STAGE_MP_RUINS, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" }, + { STAGE_MP_FORTRESS, "-ml0 -me0 -mgfx96 -mvtx96 -ma130" }, + { STAGE_MP_VILLA, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" }, + { STAGE_TEST_MP2, "-ml0 -me0 -mgfx96 -mvtx96 -ma115" }, + { STAGE_TEST_MP6, "-ml0 -me0 -mgfx96 -mvtx96 -ma115" }, + { STAGE_TEST_MP7, "-ml0 -me0 -mgfx96 -mvtx96 -ma115" }, + { STAGE_TEST_MP8, "-ml0 -me0 -mgfx96 -mvtx96 -ma115" }, + { STAGE_TEST_MP14, "-ml0 -me0 -mgfx96 -mvtx96 -ma115" }, + { STAGE_TEST_MP16, "-ml0 -me0 -mgfx96 -mvtx96 -ma115" }, + { STAGE_TEST_MP17, "-ml0 -me0 -mgfx96 -mvtx96 -ma115" }, + { STAGE_TEST_MP18, "-ml0 -me0 -mgfx96 -mvtx96 -ma115" }, + { STAGE_TEST_MP19, "-ml0 -me0 -mgfx96 -mvtx96 -ma115" }, + { STAGE_TEST_MP20, "-ml0 -me0 -mgfx96 -mvtx96 -ma115" }, + { STAGE_TEST_LEN, "-ml0 -me0 -mgfx100 -mvtx96 -ma120" }, + { STAGE_4MBMENU, "-mgfx100 -mvtx50 -ma50" }, + { STAGE_TITLE, "-ml0 -me0 -mgfx80 -mvtx20 -ma001" }, + { 0, "-ml0 -me0 -mgfx100 -mvtx96 -ma300" }, +}; + +Gfx var8005dcc8[] = { + gsSPSegment(0x00, 0x00000000), + gsSPDisplayList(&var800613a0), + gsSPDisplayList(&var80061380), + gsDPFullSync(), + gsSPEndDisplayList(), +}; + +Gfx var8005dcf0[] = { + gsSPSegment(0x00, 0x00000000), + gsSPDisplayList(&var800613a0), + gsSPDisplayList(&var80061380), + gsDPFullSync(), + gsSPEndDisplayList(), +}; + +s32 g_MainIsBooting = 1; + +void mainInit(void) +{ + s32 x; + s32 i; + s32 j; + u32 addr; + + faultInit(); + dmaInit(); + amgrInit(); + varsInit(); + mempInit(); + memaInit(); + joyInit(); + joyReset(); + + g_Is4Mb = (osGetMemSize() <= 0x400000); + g_VmShowStats = 0; + + // no copyright screen + viConfigureForLegal(); + viBlack(true); + + filesInit(); + + if (var8005d9b0) { + argSetString(" -ml0 -me0 -mgfx100 -mvtx50 -mt700 -ma400"); + } + + mempSetHeap(g_MempHeap, g_MempHeapSize); + + mempResetPool(MEMPOOL_8); + mempResetPool(MEMPOOL_PERMANENT); + crashReset(); + challengesInit(); + utilsInit(); + texInit(); + langInit(); + lvInit(); + cheatsInit(); + textInit(); + dhudInit(); + playermgrInit(); + frametimeInit(); + profileInit(); + smokesInit(); + mpInit(); + pheadInit(); + paksInit(); + pheadInit2(); + animsInit(); + racesInit(); + bodiesInit(); + titleInit(); + + g_MainIsBooting = 0; +} + +void mainProc(void) +{ + mainInit(); + rdpInit(); + sndInit(); + + while (true) { + mainLoop(); + } +} + +/** + * It's suspected that this function would have allowed developers to override + * the value of variables while the game is running in order to view their + * effects immediately rather than having to recompile the game each time. + * + * The developers would have used rmon to create a table of name/value pairs, + * then this function would have looked up the given variable name in the table + * and written the new value to the variable's address. + */ +void mainOverrideVariable(char *name, void *value) +{ + // empty +} + +/** + * This function enters an infinite loop which iterates once per stage load. + * Within this loop is an inner loop which runs very frequently and decides + * whether to run mainTick on each iteration. + * + * NTSC beta checks two shorts at an offset 64MB into the development board + * and refuses to continue if they are not any of the allowed values. + * Decomp patches these reads in its build system so it can be played + * without the development board. + */ +void mainLoop(void) +{ + s32 ending = false; + s32 index; + s32 numplayers; + u32 stack; + + func0f175f98(); + + var8005d9c4 = 0; + argGetLevel(&g_StageNum); + + if (g_DoBootPakMenu) { + g_Vars.unk0004e4 = 0xfd; + g_StageNum = STAGE_BOOTPAKMENU; + } + + if (g_StageNum != STAGE_TITLE) { + titleSetNextStage(g_StageNum); + + if (g_StageNum < STAGE_TITLE) { + func0f01b148(0); + + if (argFindByPrefix(1, "-hard")) { + lvSetDifficulty(argFindByPrefix(1, "-hard")[0] - '0'); + } + } + } + + if (g_StageNum == STAGE_CITRAINING && IS4MB()) { + g_StageNum = STAGE_4MBMENU; + } + + rngSetSeed(osGetCount()); + + // Outer loop - this is infinite because ending is never changed + while (!ending) { + g_MainNumGfxTasks = 0; + g_MainGameLogicEnabled = true; + g_MainIsEndscreen = false; + + if (var8005d9b0 && var8005d9c4 == 0) { + index = -1; + + if (IS4MB()) { + if (g_StageNum < STAGE_TITLE && getNumPlayers() >= 2) { + index = 0; \ + while (g_StageAllocations4Mb[index].stagenum) { \ + if (g_StageAllocations4Mb[index].stagenum == g_StageNum + 400) { \ + break; \ + } \ + index++; + } + + if (g_StageAllocations4Mb[index].stagenum == 0) { + index = -1; + } + } + + if (index); + + if (index < 0) { + index = 0; + while (g_StageAllocations4Mb[index].stagenum) { + if (g_StageNum == g_StageAllocations4Mb[index].stagenum) { + break; + } + + index++; + } + } + + argSetString(g_StageAllocations4Mb[index].string); + } else { + // 8MB + if (g_StageNum < STAGE_TITLE && getNumPlayers() >= 2) { + index = 0; \ + while (g_StageAllocations8Mb[index].stagenum) { \ + if (g_StageNum + 400 == g_StageAllocations8Mb[index].stagenum) { \ + break; \ + } \ + index++; + } + + if (g_StageAllocations8Mb[index].stagenum == 0) { + index = -1; + } + } + + if (index < 0) { + index = 0; + + while (g_StageAllocations8Mb[index].stagenum) { + if (g_StageNum == g_StageAllocations8Mb[index].stagenum) { + break; + } + + index++; + } + } + + argSetString(g_StageAllocations8Mb[index].string); + } + } + + var8005d9c4 = 0; + + mempResetPool(MEMPOOL_7); + mempResetPool(MEMPOOL_STAGE); + filesStop(4); + + if (argFindByPrefix(1, "-ma")) { + g_MainMemaHeapSize = strtol(argFindByPrefix(1, "-ma"), NULL, 0) * 1024; + } + + memaReset(mempAlloc(g_MainMemaHeapSize, MEMPOOL_STAGE), g_MainMemaHeapSize); + langReset(g_StageNum); + playermgrReset(); + + if (g_StageNum >= STAGE_TITLE) { + numplayers = 0; + } else { + if (argFindByPrefix(1, "-play")) { + numplayers = strtol(argFindByPrefix(1, "-play"), NULL, 0); + } else { + numplayers = 1; + } + + if (getNumPlayers() >= 2) { + numplayers = getNumPlayers(); + } + } + + if (numplayers < 2) { + g_Vars.bondplayernum = 0; + g_Vars.coopplayernum = -1; + g_Vars.antiplayernum = -1; + } else if (argFindByPrefix(1, "-coop")) { + g_Vars.bondplayernum = 0; + g_Vars.coopplayernum = 1; + g_Vars.antiplayernum = -1; + } else if (argFindByPrefix(1, "-anti")) { + g_Vars.bondplayernum = 0; + g_Vars.coopplayernum = -1; + g_Vars.antiplayernum = 1; + } + + playermgrAllocatePlayers(numplayers); + + if (argFindByPrefix(1, "-mpbots")) { + g_Vars.lvmpbotlevel = 1; + } + + if (g_Vars.coopplayernum >= 0 || g_Vars.antiplayernum >= 0) { + g_MpSetup.chrslots = 0x03; + mpReset(); + } else if (g_Vars.perfectbuddynum) { + mpReset(); + } else if (g_Vars.mplayerisrunning == false + && (numplayers >= 2 || g_Vars.lvmpbotlevel || argFindByPrefix(1, "-play"))) { + g_MpSetup.chrslots = 1; + + if (numplayers >= 2) { + g_MpSetup.chrslots |= 1 << 1; + } + + if (numplayers >= 3) { + g_MpSetup.chrslots |= 1 << 2; + } + + if (numplayers >= 4) { + g_MpSetup.chrslots |= 1 << 3; + } + + g_MpSetup.stagenum = g_StageNum; + mpReset(); + } + + gfxReset(); + joyReset(); + dhudReset(); + zbufReset(g_StageNum); + lvReset(g_StageNum); + viReset(g_StageNum); + frametimeCalculate(); + profileReset(); + + while (g_MainChangeToStageNum < 0) { + const s32 cycles = osGetCount() - g_Vars.thisframestartt; + if (cycles >= g_Vars.mininc60 * CYCLES_PER_FRAME - CYCLES_PER_FRAME / 2) { + schedStartFrame(&g_Sched); + mainTick(); + schedEndFrame(&g_Sched); + } + } + + lvStop(); + mempDisablePool(MEMPOOL_STAGE); + mempDisablePool(MEMPOOL_7); + filesStop(4); + viBlack(true); + pak0f116994(); + + g_StageNum = g_MainChangeToStageNum; + g_MainChangeToStageNum = -1; + } +} + +void mainTick(void) +{ + Gfx *gdl; + Gfx *gdlstart; + OSScMsg msg = {OS_SC_DONE_MSG}; + s32 i; + + if (g_MainChangeToStageNum < 0) { + frametimeCalculate(); + profileReset(); + profileSetMarker(PROFILE_MAINTICK_START); + joyDebugJoy(); + schedSetCrashEnable2(false); + + if (g_MainGameLogicEnabled) { + gdl = gdlstart = gfxGetMasterDisplayList(); + + gDPSetTile(gdl++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 0, 0x0000, G_TX_LOADTILE, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD); + gDPSetTile(gdl++, G_IM_FMT_RGBA, G_IM_SIZ_4b, 0, 0x0100, 6, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD); + + lvTick(); + playermgrShuffle(); + + if (g_StageNum < STAGE_TITLE) { + for (i = 0; i < PLAYERCOUNT(); i++) { + setCurrentPlayerNum(playermgrGetPlayerAtOrder(i)); + + if (g_StageNum != STAGE_TEST_OLD || !titleIsKeepingMode()) { + viSetViewPosition(g_Vars.currentplayer->viewleft, g_Vars.currentplayer->viewtop); + viSetFovAspectAndSize( + g_Vars.currentplayer->fovy, g_Vars.currentplayer->aspect, + g_Vars.currentplayer->viewwidth, g_Vars.currentplayer->viewheight); + } + + lvTickPlayer(); + } + } + + gdl = lvRender(gdl); + + if (debugGetProfileMode() >= 2) { + gdl = profileRender(gdl); + } + + gDPFullSync(gdl++); + gSPEndDisplayList(gdl++); + } + + if (g_MainGameLogicEnabled) { + gfxSwapBuffers(); + viUpdateMode(); + } + + rdpCreateTask(gdlstart, gdl, 0, (s32) &msg); + memaPrint(); + profileSetMarker(PROFILE_MAINTICK_END); + } +} + +void mainEndStage(void) +{ + sndStopNosedive(); + + if (!g_MainIsEndscreen) { + pak0f11c6d0(); + joyDisableTemporarily(); + + if (g_Vars.coopplayernum >= 0) { + s32 prevplayernum = g_Vars.currentplayernum; + s32 i; + + for (i = 0; i < PLAYERCOUNT(); i++) { + setCurrentPlayerNum(i); + endscreenPushCoop(); + } + + setCurrentPlayerNum(prevplayernum); + musicStartMenu(); + } else if (g_Vars.antiplayernum >= 0) { + s32 prevplayernum = g_Vars.currentplayernum; + s32 i; + + for (i = 0; i < PLAYERCOUNT(); i++) { + setCurrentPlayerNum(i); + endscreenPushAnti(); + } + + setCurrentPlayerNum(prevplayernum); + musicStartMenu(); + } else if (g_Vars.normmplayerisrunning) { + mpEndMatch(); + } else { + endscreenPrepare(); + musicStartMenu(); + } + } + + g_MainIsEndscreen = true; +} + +/** + * Change to the given stage at the end of the current frame. + */ +void mainChangeToStage(s32 stagenum) +{ + pak0f11c6d0(); + + g_MainChangeToStageNum = stagenum; +} + +s32 mainGetStageNum(void) +{ + return g_StageNum; +} + +void func0000e990(void) +{ + objectivesCheckAll(); + objectivesDisableChecking(); + mainEndStage(); +} diff --git a/port/src/pdsched.c b/port/src/pdsched.c new file mode 100644 index 000000000..3e786affe --- /dev/null +++ b/port/src/pdsched.c @@ -0,0 +1,388 @@ +#include +#include +#include "lib/boot.h" +#include "lib/sched.h" +#include "constants.h" +#include "game/menugfx.h" +#include "bss.h" +#include "lib/args.h" +#include "lib/audiomgr.h" +#include "lib/reset.h" +#include "lib/rzip.h" +#include "lib/crash.h" +#include "lib/main.h" +#include "lib/snd.h" +#include "lib/pimgr.h" +#include "lib/profile.h" +#include "lib/rmon.h" +#include "lib/lib_48150.h" +#include "lib/vi.h" +#include "lib/joy.h" +#include "data.h" +#include "types.h" + +#include "video.h" +#include "input.h" + +/* + * private typedefs and defines + */ +#define VIDEO_MSG 666 +#define RSP_DONE_MSG 667 +#define RDP_DONE_MSG 668 +#define PRE_NMI_MSG 669 + +/* + * OSScTask state + */ +#define OS_SC_DP 0x0001 /* set if still needs dp */ +#define OS_SC_SP 0x0002 /* set if still needs sp */ +#define OS_SC_YIELD 0x0010 /* set if yield requested */ +#define OS_SC_YIELDED 0x0020 /* set if yield completed */ + +/* + * OSScTask->flags type identifier + */ +#define OS_SC_XBUS (OS_SC_SP | OS_SC_DP) +#define OS_SC_DRAM (OS_SC_SP | OS_SC_DP | OS_SC_DRAM_DLIST) +#define OS_SC_DP_XBUS (OS_SC_SP) +#define OS_SC_DP_DRAM (OS_SC_SP | OS_SC_DRAM_DLIST) +#define OS_SC_SP_XBUS (OS_SC_DP) +#define OS_SC_SP_DRAM (OS_SC_DP | OS_SC_DRAM_DLIST) + +/* + * private functions + */ +void __scMain(void *arg); +void __scHandleTasks(OSSched *s); +void __scHandleRSP(OSSched *s); +void __scHandleRDP(OSSched *s); +void __scAppendList(OSSched *s, OSScTask *t); +OSScTask *__scTaskReady(OSScTask *t); +s32 __scTaskComplete(OSSched *s,OSScTask *t); +void __scExec(OSSched *sc, OSScTask *sp, OSScTask *dp); +void __scYield(OSSched *s); +s32 __scSchedule(OSSched *sc, OSScTask **sp, OSScTask **dp, s32 availRCP); + +OSViMode var8008dcc0[NUM_GFXTASKS]; +OSViMode *var8008dd60[NUM_GFXTASKS]; +OSViMode var8008dd68[NUM_GFXTASKS]; +s32 var8008de08; +s32 g_ViCurVStart0; +s32 g_ViCurVStart1; +u32 var8008de14; +OSTimer g_SchedRspTimer; +u32 g_SchedDpCounters[4]; +struct artifact g_ArtifactLists[3][120]; +u8 g_SchedSpecialArtifactIndexes[3]; +s32 g_SchedWriteArtifactsIndex; +s32 g_SchedFrontArtifactsIndex; +s32 g_SchedPendingArtifactsIndex; + +bool g_SchedCrashedUnexpectedly = false; +bool g_SchedCrashEnable1 = false; +bool g_SchedCrashEnable2 = false; +u32 g_SchedCrashRenderInterval = 45000000; +u32 g_SchedCrashLastRendered = 0; + +s32 var8005ce74 = 0; +f32 g_ViXScalesBySlot[NUM_GFXTASKS] = {1, 1}; +f32 g_ViYScalesBySlot[NUM_GFXTASKS] = {1, 1}; +bool g_SchedViModesPending[NUM_GFXTASKS] = {false, false}; +s32 g_ViUnblackTimer = NUM_FRAMEBUFFERS + 1; +s32 g_ViShakeDirection = 1; +s32 g_ViShakeIntensity = 0; +s32 g_ViShakeTimer = 0; +u32 var8005cea0 = 0; +u32 var8005cea4 = 0; +OSScMsg g_SchedRspMsg = {OS_SC_RSP_MSG}; +bool g_SchedIsFirstTask = true; + +void schedSetCrashEnable1(bool enable) +{ + g_SchedCrashEnable1 = enable; +} + +void schedSetCrashedUnexpectedly(bool enable) +{ + g_SchedCrashedUnexpectedly = enable; +} + +void schedSetCrashEnable2(bool enable) +{ + g_SchedCrashEnable2 = enable; +} + +void schedSetCrashRenderInterval(u32 cycles) +{ + g_SchedCrashRenderInterval = cycles; +} + +void schedRenderCrashOnBuffer(void *framebuffer) +{ + if ((g_SchedCrashEnable2 && g_SchedCrashEnable1) || g_SchedCrashedUnexpectedly) { + // crashRenderFrame(framebuffer); + g_SchedCrashLastRendered = osGetCount(); + } +} + +void schedRenderCrashPeriodically(u32 framecount) +{ + if ((framecount & 0xf) == 0 && ((g_SchedCrashEnable2 && g_SchedCrashEnable1) || g_SchedCrashedUnexpectedly)) { + if (osGetCount() - g_SchedCrashLastRendered > g_SchedCrashRenderInterval) { + // crashRenderFrame(g_FrameBuffers[0]); + // crashRenderFrame(g_FrameBuffers[1]); + } + } +} + +void schedInitCrashLastRendered(void) +{ + g_SchedCrashLastRendered = osGetCount(); +} + +void osCreateScheduler(OSSched *sc, OSThread *thread, u8 mode, u32 numFields) +{ + sc->curRSPTask = 0; + sc->curRDPTask = 0; + sc->clientList = 0; + sc->frameCount = 0; + sc->audioListHead = 0; + sc->gfxListHead = 0; + sc->audioListTail = 0; + sc->gfxListTail = 0; + sc->retraceMsg.type = OS_SC_RETRACE_MSG; + sc->prenmiMsg.type = OS_SC_PRE_NMI_MSG; + sc->thread = thread; + + osCreateMesgQueue(&sc->interruptQ, sc->intBuf, OS_SC_MAX_MESGS); + osCreateMesgQueue(&sc->cmdQ, sc->cmdMsgBuf, OS_SC_MAX_MESGS); + + osCreateViManager(OS_PRIORITY_VIMGR); + + var8008de08 = osViModeTable[mode].comRegs.hStart; + g_ViCurVStart0 = osViModeTable[mode].fldRegs[0].vStart; + g_ViCurVStart1 = osViModeTable[mode].fldRegs[1].vStart; + + var8008dd60[0] = &var8008dd68[0]; + var8008dd60[1] = &var8008dd68[1]; + + var8008dd68[0] = osViModeTable[mode]; + var8008dd68[1] = osViModeTable[mode]; + + osViSetEvent(&sc->interruptQ, (OSMesg)VIDEO_MSG, numFields); + schedInitCrashLastRendered(); +} + +void osScAddClient(OSSched *sc, OSScClient *c, OSMesgQueue *msgQ, bool is30fps) +{ + c->msgQ = msgQ; + c->is30fps = is30fps; + c->next = sc->clientList; + sc->clientList = c; +} + +OSMesgQueue *osScGetCmdQ(OSSched *sc) +{ + return &sc->cmdQ; +} + +void __scUpdateViMode(void) +{ + if (g_SchedIsFirstTask) { + osViBlack(false); + g_SchedIsFirstTask = false; + } + + var8005ce74 = (var8005ce74 + 1) % 2; + + if (g_SchedViModesPending[1 - var8005ce74]) { + if (var8008dd60[1 - var8005ce74]->comRegs.width != var8008dcc0[1 - var8005ce74].comRegs.width + || var8008dd60[1 - var8005ce74]->comRegs.xScale != var8008dcc0[1 - var8005ce74].comRegs.xScale + || var8008dd60[1 - var8005ce74]->fldRegs[0].yScale != var8008dcc0[1 - var8005ce74].fldRegs[0].yScale + || var8008dd60[1 - var8005ce74]->fldRegs[1].yScale != var8008dcc0[1 - var8005ce74].fldRegs[1].yScale + || var8008dd60[1 - var8005ce74]->fldRegs[0].origin != var8008dcc0[1 - var8005ce74].fldRegs[0].origin + || var8008dd60[1 - var8005ce74]->fldRegs[1].origin != var8008dcc0[1 - var8005ce74].fldRegs[1].origin) { + osViSetMode(var8008dd60[1 - var8005ce74]); + osViBlack(g_ViUnblackTimer); + osViSetXScale(g_ViXScalesBySlot[1 - var8005ce74]); + osViSetYScale(g_ViYScalesBySlot[1 - var8005ce74]); + osViSetSpecialFeatures(OS_VI_GAMMA_OFF | OS_VI_DITHER_FILTER_ON); + } + + g_SchedViModesPending[1 - var8005ce74] = false; + } + + if (g_ViUnblackTimer != 0 && g_ViUnblackTimer <= NUM_FRAMEBUFFERS) { + g_ViUnblackTimer--; + } +} + +/** + * Nintendo's sheduler accepts tasks on a "command" message queue. + * This isn't used here. + * + * In PD, the main and audio threads submit tasks by calling this function + * instead. It temporarily increases the calling thread's priority above the + * scheduler, adds the task to the linked list directly and attempts to execute + * it. This is faster than the queue method because it avoids switching threads. + */ +void schedSubmitTask(OSSched *sc, OSScTask *t) +{ + if (sc->doAudio && t->list.t.type == M_AUDTASK) { + // TODO: audio frame + } else if (t->list.t.type == M_GFXTASK) { + videoSubmitCommands((Gfx *)t->list.t.data_ptr); + } +} + +void schedStartFrame(OSSched *sc) +{ + videoStartFrame(); +} + +/** + * Handle a retrace (vsync) event. + * + * Audio tasks are scheduled based on retrace + a timer (approximately 6ms). + * On NTSC, this is done on every second frame if 8MB, or every second frame + * if 4MB. I guess less memory means the audio queue has to be kept smaller + * and processed more frequently. On PAL, it's every second frame regardless. + * + * Controller input is polled here. + * + * Lastly, if there's crash information available then it will be checked and + * rendered periodically (once every 16 retraces). I guess this makes it render + * if the RDP has hung. + */ +void schedEndFrame(OSSched *sc) +{ + sc->frameCount++; + +#if PAL + if (!g_Resetting && (sc->frameCount & 1)) { + // osStopTimer(&g_SchedRspTimer); + // osSetTimer(&g_SchedRspTimer, 280000, 0, amgrGetFrameMesgQueue(), &g_SchedRspMsg); + } +#else + if (!g_Resetting && ((sc->frameCount & 1) || IS4MB())) { + // osStopTimer(&g_SchedRspTimer); + // osSetTimer(&g_SchedRspTimer, 280000, 0, amgrGetFrameMesgQueue(), &g_SchedRspMsg); + } +#endif + + if (!g_Resetting) { + viHandleRetrace(); + } + + inputUpdate(); + joysHandleRetrace(); + sndHandleRetrace(); + schedRenderCrashPeriodically(sc->frameCount); + videoEndFrame(); + + // check for vid mode changes + __scUpdateViMode(); +} + +void schedInitArtifacts(void) +{ + s32 i; + s32 j; + + for (i = 0; i < 3; i++) { + for (j = 0; j < MAX_ARTIFACTS; j++) { + g_ArtifactLists[i][j].type = ARTIFACTTYPE_FREE; + } + + g_SchedSpecialArtifactIndexes[i] = 0; + } +} + +/** + * The write list is an artifact list that is not currently being displayed on + * the screen. Update logic can write here to put artifacts on the next frame. + */ +struct artifact *schedGetWriteArtifacts(void) +{ + return g_ArtifactLists[g_SchedWriteArtifactsIndex]; +} + +/** + * The front list is the artifact list that is currently being displayed on the + * screen. Rendering logic reads this list. The list may be re-used for multiple + * frames in a row during lag. + */ +struct artifact *schedGetFrontArtifacts(void) +{ + return g_ArtifactLists[g_SchedFrontArtifactsIndex]; +} + +/** + * The pending list is possibly misnamed. I'm not sure how this list works. + * + * @TODO: Investigate. + */ +struct artifact *schedGetPendingArtifacts(void) +{ + return g_ArtifactLists[g_SchedPendingArtifactsIndex]; +} + +void schedIncrementWriteArtifacts(void) +{ + g_SchedWriteArtifactsIndex = (g_SchedWriteArtifactsIndex + 1) % 3; +} + +void schedIncrementFrontArtifacts(void) +{ + g_SchedFrontArtifactsIndex = (g_SchedFrontArtifactsIndex + 1) % 3; +} + +void schedIncrementPendingArtifacts(void) +{ + g_SchedPendingArtifactsIndex = (g_SchedPendingArtifactsIndex + 1) % 3; +} + +void schedResetArtifacts(void) +{ + g_SchedWriteArtifactsIndex = 0; + g_SchedFrontArtifactsIndex = 1; + g_SchedPendingArtifactsIndex = 0; +} + +void schedUpdatePendingArtifacts(void) +{ + struct artifact *artifacts = schedGetPendingArtifacts(); + s32 i; + + for (i = 0; i < MAX_ARTIFACTS; i++) { + struct artifact *artifact = &artifacts[i]; + + if (artifact->type != ARTIFACTTYPE_FREE) { + u16 *unk08 = artifact->unk08; + u16 value08 = unk08[0]; + + if (g_SchedSpecialArtifactIndexes[g_SchedPendingArtifactsIndex] == 1) { + u16 *unk0c = artifact->unk0c.u16p; + u16 value0c = unk0c[0]; + + if (value0c > value08) { + artifact->unk02 = value08; + } else { + artifact->unk02 = value0c; + } + } else { + artifact->unk02 = value08; + } + } + } + + g_SchedSpecialArtifactIndexes[g_SchedPendingArtifactsIndex] = 0; + + schedIncrementPendingArtifacts(); +} + +void schedConsiderScreenshot(void) +{ + +} diff --git a/port/src/preprocess.c b/port/src/preprocess.c new file mode 100644 index 000000000..287c0b498 --- /dev/null +++ b/port/src/preprocess.c @@ -0,0 +1,901 @@ +#include +#include +#include +#include +#include +#include "platform.h" +#include "data.h" +#include "bss.h" +#include "preprocess.h" +#include "romdata.h" + +#define PD_BEFIELD_I16(x) x = PD_BE16(x) +#define PD_BEFIELD_I32(x) x = PD_BE32(x) +#define PD_BEFIELD_F32(x) *(u32 *)&x = PD_BE32(*(u32 *)&x) +#define PD_BEFIELD_PTR(x) x = (void *)PD_BE32((u32)x) + +#define PD_PTR_BASE(x, b) (void *)((u8 *)b + (u32)x) +#define PD_PTR_BASEOFS(x, b, d) (void *)((u8 *)b + (u32)x - d) + +static inline void preprocessALWaveTable(ALWaveTable *tbl, u8 *bankBase) +{ + if ((uintptr_t)tbl->base < 0x02000000) { + // already swapped (maybe come up with a better check) + return; + } + + PD_BEFIELD_I32(tbl->len); + PD_BEFIELD_PTR(tbl->base); + + if (tbl->type == AL_ADPCM_WAVE) { + if (tbl->waveInfo.adpcmWave.loop ) { + PD_BEFIELD_PTR(tbl->waveInfo.adpcmWave.loop); + ALADPCMloop *loop = PD_PTR_BASE(tbl->waveInfo.adpcmWave.loop, bankBase); + PD_BEFIELD_I32(loop->count); + PD_BEFIELD_I32(loop->start); + PD_BEFIELD_I32(loop->end); + /* TODO: this goes into the mixer -- swapping not required? + for (s32 i = 0; i < 16; ++i) { + PD_BEFIELD_I16(loop->state[i]); + } + */ + } + if (tbl->waveInfo.adpcmWave.book) { + PD_BEFIELD_PTR(tbl->waveInfo.adpcmWave.book); + ALADPCMBook *book = PD_PTR_BASE(tbl->waveInfo.adpcmWave.book, bankBase); + PD_BEFIELD_I32(book->npredictors); + PD_BEFIELD_I32(book->order); + /* TODO: this goes into the mixer -- swapping not required? + const s32 bookSize = book->order * book->npredictors * ADPCMVSIZE; + for (s32 i = 0; i < bookSize && i < 128; ++i) { + PD_BEFIELD_I16(book->book[i]); + } + */ + } + } else if (tbl->type == AL_RAW16_WAVE) { + if (tbl->waveInfo.rawWave.loop) { + PD_BEFIELD_PTR(tbl->waveInfo.rawWave.loop); + ALRawLoop *loop = PD_PTR_BASE(tbl->waveInfo.rawWave.loop, bankBase); + PD_BEFIELD_I32(loop->count); + PD_BEFIELD_I32(loop->start); + PD_BEFIELD_I32(loop->end); + } + } +} + +static inline void preprocessALSound(ALSound *snd, u8 *bankBase) +{ + if ((uintptr_t)snd->wavetable < 0x02000000) { + // already swapped (maybe come up with a better check) + return; + } + + if (snd->envelope) { + PD_BEFIELD_PTR(snd->envelope); + ALEnvelope *env = PD_PTR_BASE(snd->envelope, bankBase); + PD_BEFIELD_I32(env->attackTime); + PD_BEFIELD_I32(env->releaseTime); + PD_BEFIELD_I32(env->decayTime); + } + + if (snd->keyMap) { + PD_BEFIELD_PTR(snd->keyMap); + } + + if (snd->wavetable) { + PD_BEFIELD_PTR(snd->wavetable); + preprocessALWaveTable(PD_PTR_BASE(snd->wavetable, bankBase), bankBase); + } +} + +static inline void preprocessALInstrument(ALInstrument *inst, u8 *bankBase) +{ + if ((uintptr_t)inst->soundArray[0] < 0x02000000) { + // already swapped (maybe come up with a better check) + return; + } + + PD_BEFIELD_I16(inst->bendRange); + PD_BEFIELD_I16(inst->soundCount); + + for (s16 i = 0; i < inst->soundCount; ++i) { + PD_BEFIELD_PTR(inst->soundArray[i]); + preprocessALSound(PD_PTR_BASE(inst->soundArray[i], bankBase), bankBase); + } +} + +static inline void preprocessALBank(ALBank *bank, u8 *bankBase) +{ + if ((uintptr_t)bank->instArray[0] < 0x02000000) { + // already swapped (maybe come up with a better check) + return; + } + + PD_BEFIELD_I32(bank->sampleRate); + PD_BEFIELD_I16(bank->instCount); + + if (bank->percussion) { + PD_BEFIELD_PTR(bank->percussion); + preprocessALInstrument(PD_PTR_BASE(bank->percussion, bankBase), bankBase); + } + + for (s16 i = 0; i < bank->instCount; ++i) { + PD_BEFIELD_PTR(bank->instArray[i]); + preprocessALInstrument(PD_PTR_BASE(bank->instArray[i], bankBase), bankBase); + } +} + +static inline void preprocessGfx(Gfx *gdl) +{ + while (gdl) { + const u8 opcode = gdl->bytes[0]; + PD_BEFIELD_I32(gdl->words.w0); + PD_BEFIELD_I32(gdl->words.w1); + if (opcode == G_ENDDL) { + break; + } + ++gdl; + } +} + +static inline void preprocessVtx(Vtx *vtx) +{ + PD_BEFIELD_I16(vtx->x); + PD_BEFIELD_I16(vtx->y); + PD_BEFIELD_I16(vtx->z); + PD_BEFIELD_I16(vtx->s); + PD_BEFIELD_I16(vtx->t); +} + +static void preprocessModelGunDL(struct modelrodata_gundl *gundl, u8 *base, u32 ofs) +{ + PD_BEFIELD_PTR(gundl->opagdl); + PD_BEFIELD_PTR(gundl->xlugdl); + PD_BEFIELD_PTR(gundl->baseaddr); + PD_BEFIELD_PTR(gundl->vertices); + PD_BEFIELD_I32(gundl->numvertices); + PD_BEFIELD_I16(gundl->unk12); + + Vtx *vtx = PD_PTR_BASEOFS(gundl->vertices, base, ofs); + for (s16 i = 0; i < gundl->numvertices; ++i, ++vtx) { + preprocessVtx(vtx); + } + + preprocessGfx(PD_PTR_BASEOFS(gundl->opagdl, base, ofs)); + preprocessGfx(PD_PTR_BASEOFS(gundl->xlugdl, base, ofs)); +} + +static void preprocessModelDL(struct modelrodata_dl *dl, u8 *base, u32 ofs) +{ + PD_BEFIELD_PTR(dl->opagdl); + PD_BEFIELD_PTR(dl->xlugdl); + PD_BEFIELD_PTR(dl->colours); + PD_BEFIELD_PTR(dl->vertices); + + PD_BEFIELD_I16(dl->numvertices); + PD_BEFIELD_I16(dl->numcolours); + PD_BEFIELD_I16(dl->mcount); + PD_BEFIELD_I16(dl->rwdataindex); + + Vtx *vtx = PD_PTR_BASEOFS(dl->vertices, base, ofs); + for (s16 i = 0; i < dl->numvertices; ++i, ++vtx) { + preprocessVtx(vtx); + } + + preprocessGfx(PD_PTR_BASEOFS(dl->opagdl, base, ofs)); + preprocessGfx(PD_PTR_BASEOFS(dl->xlugdl, base, ofs)); +} + +static void preprocessModelNode(struct modelnode *node, u8 *base, u32 ofs) +{ + PD_BEFIELD_I16(node->type); + PD_BEFIELD_PTR(node->child); + PD_BEFIELD_PTR(node->next); + PD_BEFIELD_PTR(node->parent); + + if (!node->rodata) { + return; + } + + PD_BEFIELD_PTR(node->rodata); + union modelrodata* ro = PD_PTR_BASEOFS(node->rodata, base, ofs); + + switch (node->type & 0xff) { + case MODELNODETYPE_CHRINFO: + PD_BEFIELD_I16(ro->chrinfo.animpart); + PD_BEFIELD_I16(ro->chrinfo.mtxindex); + PD_BEFIELD_I16(ro->chrinfo.rwdataindex); + PD_BEFIELD_F32(ro->chrinfo.unk04); + break; + case MODELNODETYPE_POSITION: + PD_BEFIELD_F32(ro->position.drawdist); + PD_BEFIELD_F32(ro->position.pos.x); + PD_BEFIELD_F32(ro->position.pos.y); + PD_BEFIELD_F32(ro->position.pos.z); + PD_BEFIELD_I16(ro->position.part); + PD_BEFIELD_I16(ro->position.mtxindex0); + PD_BEFIELD_I16(ro->position.mtxindex1); + PD_BEFIELD_I16(ro->position.mtxindex2); + break; + case MODELNODETYPE_GUNDL: + preprocessModelGunDL(&ro->gundl, base, ofs); + break; + case MODELNODETYPE_05: + break; + case MODELNODETYPE_DISTANCE: + PD_BEFIELD_F32(ro->distance.near); + PD_BEFIELD_F32(ro->distance.far); + PD_BEFIELD_I16(ro->distance.rwdataindex); + PD_BEFIELD_PTR(ro->distance.target); + // TODO: assuming target points to one of the nodes we'll swap by following node->next + break; + case MODELNODETYPE_REORDER: + PD_BEFIELD_F32(ro->reorder.unk00); + PD_BEFIELD_F32(ro->reorder.unk04); + PD_BEFIELD_F32(ro->reorder.unk08); + PD_BEFIELD_F32(ro->reorder.unk0c[0]); + PD_BEFIELD_F32(ro->reorder.unk0c[1]); + PD_BEFIELD_F32(ro->reorder.unk0c[2]); + PD_BEFIELD_I16(ro->reorder.rwdataindex); + PD_BEFIELD_I16(ro->reorder.side); + break; + case MODELNODETYPE_BBOX: + PD_BEFIELD_F32(ro->bbox.xmin); + PD_BEFIELD_F32(ro->bbox.xmax); + PD_BEFIELD_F32(ro->bbox.ymin); + PD_BEFIELD_F32(ro->bbox.ymax); + PD_BEFIELD_F32(ro->bbox.zmin); + PD_BEFIELD_F32(ro->bbox.zmax); + PD_BEFIELD_I32(ro->bbox.hitpart); + break; + case MODELNODETYPE_0B: + PD_BEFIELD_PTR(ro->type0b.baseaddr); + PD_BEFIELD_I16(ro->type0b.rwdataindex); + PD_BEFIELD_I32(ro->type0b.unk00); + PD_BEFIELD_PTR(ro->type0b.unk3c); + // TODO: do we need to swap the rest of the words? + break; + case MODELNODETYPE_CHRGUNFIRE: + PD_BEFIELD_PTR(ro->chrgunfire.baseaddr); + PD_BEFIELD_PTR(ro->chrgunfire.texture); + PD_BEFIELD_I16(ro->chrgunfire.rwdataindex); + PD_BEFIELD_F32(ro->chrgunfire.pos.x); + PD_BEFIELD_F32(ro->chrgunfire.pos.y); + PD_BEFIELD_F32(ro->chrgunfire.pos.z); + PD_BEFIELD_F32(ro->chrgunfire.dim.x); + PD_BEFIELD_F32(ro->chrgunfire.dim.y); + PD_BEFIELD_F32(ro->chrgunfire.dim.z); + PD_BEFIELD_F32(ro->chrgunfire.unk1c); + // TODO: do we swap contents of *texture or is it part of mdl->textureconfigs[]? + break; + case MODELNODETYPE_0D: + PD_BEFIELD_PTR(ro->type0d.baseaddr); + PD_BEFIELD_PTR(ro->type0d.unk10); + PD_BEFIELD_PTR(ro->type0d.unk14); + // TODO: do we need to swap the rest of the words? + break; + case MODELNODETYPE_0E: + case MODELNODETYPE_0F: + break; + case MODELNODETYPE_11: + PD_BEFIELD_PTR(ro->type11.unk14); + // TODO: do we need to swap the rest of the words? + break; + case MODELNODETYPE_TOGGLE: + PD_BEFIELD_I16(ro->toggle.rwdataindex); + PD_BEFIELD_PTR(ro->toggle.target); + // TODO: assuming target points to one of the nodes we'll swap by following node->next + break; + case MODELNODETYPE_DL: + preprocessModelDL(&ro->dl, base, ofs); + break; + case 0x19: + PD_BEFIELD_I32(ro->type19.numvertices); + for (s32 i = 0; i < ARRAYCOUNT(ro->type19.vertices); ++i) { + PD_BEFIELD_F32(ro->type19.vertices[i].x); + PD_BEFIELD_F32(ro->type19.vertices[i].y); + PD_BEFIELD_F32(ro->type19.vertices[i].z); + } + break; + default: + fprintf(stderr, "preprocessModelNode: node at %p: unknown node->type: 0x%02x\n", node, node->type & 0xff); + break; + } + + if (node->child) { + node = PD_PTR_BASEOFS(node->child, base, ofs); + } else { + while (node) { + if (node->next) { + node = PD_PTR_BASEOFS(node->next, base, ofs); + break; + } + node = PD_PTR_BASEOFS(node->parent, base, ofs); + } + } +} + +static inline void preprocessPadData(u8 *ptr) +{ + // for some insane reason pads are packed + // header is always 1 word, the rest of the fields depends on the flags + u32 *header = (u32 *) ptr; + PD_BEFIELD_I32(header[0]); + + ptr += 4; + + if ((*header >> 14) & PADFLAG_INTPOS) { + // position is 3x s16 + s16 *sbuffer = (s16 *) ptr; + PD_BEFIELD_I16(sbuffer[0]); + PD_BEFIELD_I16(sbuffer[1]); + PD_BEFIELD_I16(sbuffer[2]); + ptr += 8; + } else { + // position is 3x f32 + f32 *fbuffer = (f32 *) ptr; + PD_BEFIELD_F32(fbuffer[0]); + PD_BEFIELD_F32(fbuffer[1]); + PD_BEFIELD_F32(fbuffer[2]); + ptr += 12; + } + + if (!((*header >> 14) & (PADFLAG_UPALIGNTOX | PADFLAG_UPALIGNTOY | PADFLAG_UPALIGNTOZ))) { + // up vector, 3x f32 + f32 *fbuffer = (f32 *) ptr; + PD_BEFIELD_F32(fbuffer[0]); + PD_BEFIELD_F32(fbuffer[1]); + PD_BEFIELD_F32(fbuffer[2]); + ptr += 12; + } + + if (!((*header >> 14) & (PADFLAG_LOOKALIGNTOX | PADFLAG_LOOKALIGNTOY | PADFLAG_LOOKALIGNTOZ))) { + // look vector, 3x f32 + f32 *fbuffer = (f32 *) ptr; + PD_BEFIELD_F32(fbuffer[0]); + PD_BEFIELD_F32(fbuffer[1]); + PD_BEFIELD_F32(fbuffer[2]); + ptr += 12; + } + + if ((*header >> 14) & PADFLAG_HASBBOXDATA) { + // bbox, 3x f32 mins + 3x f32 maxs + f32 *fbuffer = (f32 *) ptr; + PD_BEFIELD_F32(fbuffer[0]); + PD_BEFIELD_F32(fbuffer[1]); + PD_BEFIELD_F32(fbuffer[2]); + PD_BEFIELD_F32(fbuffer[3]); + PD_BEFIELD_F32(fbuffer[4]); + PD_BEFIELD_F32(fbuffer[5]); + } +} + + +void preprocessAnimations(u8 *data, u32 size) +{ + // set the anim table pointers as well + extern u8 *_animationsTableRomStart; + extern u8 *_animationsTableRomEnd; + // the animation table is at the end of the segment + u32 *animtbl = (void *)(data + size - 0x38a0); + _animationsTableRomStart = (u8 *)animtbl; + _animationsTableRomEnd = data + size; + PD_BEFIELD_I32(*animtbl); + const u32 count = *animtbl++; + struct animtableentry *anim = (struct animtableentry *)animtbl; + for (u32 i = 0; i < count; ++i, ++anim) { + PD_BEFIELD_I16(anim->numframes); + PD_BEFIELD_I16(anim->bytesperframe); + PD_BEFIELD_I16(anim->headerlen); + PD_BEFIELD_I32(anim->data); + } +} + +void preprocessMpConfigs(u8 *data, u32 size) +{ + const u32 count = size / sizeof(struct mpconfig); + struct mpconfig *cfg = (struct mpconfig *)data; + for (u32 i = 0; i < count; ++i, ++cfg) { + PD_BEFIELD_I32(cfg->setup.options); + PD_BEFIELD_I16(cfg->setup.teamscorelimit); + PD_BEFIELD_I16(cfg->setup.chrslots); + // TODO: are these required or are they always 0? + PD_BEFIELD_I16(cfg->setup.fileguid.deviceserial); + PD_BEFIELD_I32(cfg->setup.fileguid.fileid); + } +} + +void preprocessFont(u8 *data, u32 size) +{ + struct font *fnt = (struct font *)data; + + for (s32 i = 0; i < ARRAYCOUNT(fnt->kerning); ++i) { + PD_BEFIELD_I32(fnt->kerning[i]); + } + + for (s32 i = 0; i < ARRAYCOUNT(fnt->chars); ++i) { + PD_BEFIELD_I32(fnt->chars[i].kerningindex); + PD_BEFIELD_PTR(fnt->chars[i].pixeldata); + } +} + +void preprocessJpnFont(u8 *data, u32 size) +{ + // ??? +} + +void preprocessALBankFile(u8 *data, u32 size) +{ + ALBankFile *bankf = (ALBankFile *)data; + PD_BEFIELD_I16(bankf->revision); + PD_BEFIELD_I16(bankf->bankCount); + + for (s16 i = 0; i < bankf->bankCount; ++i) { + PD_BEFIELD_PTR(bankf->bankArray[i]); + preprocessALBank(PD_PTR_BASE(bankf->bankArray[i], data), data); + } +} + +void preprocessSequences(u8 *data, u32 size) +{ + struct seqtable *seq = (struct seqtable *)data; + PD_BEFIELD_I16(seq->count); + + for (s16 i = 0; i < seq->count; ++i) { + PD_BEFIELD_I16(seq->entries[i].binlen); + PD_BEFIELD_I16(seq->entries[i].ziplen); + PD_BEFIELD_I32(seq->entries[i].romaddr); + } +} + +void preprocessFiringRange(u8 *data, u32 size) +{ + // u16 texts[9] is the first and only thing we care about here + // probably no sense supporting custom sizes either + u16 *texts = (u16 *)data; + for (s32 i = 0; i < 9; ++i) { + PD_BEFIELD_I16(texts[i]); + } +} + +void preprocessTexturesList(u8 *data, u32 size) +{ + struct texture *tex = (struct texture *)data; + const u32 count = size / sizeof(*tex); + for (u32 i = 0; i < count; ++i, ++tex) { + // TODO: it sure looks like none of the fields except soundsurfacetype, surfacetype and dataoffset are set + // just swap the last 3 bytes of the first word + const u32 dofs = (u32)tex->dataoffset << 8; + tex->dataoffset = PD_BE32(dofs); + } +} + +void preprocessModel(u8 *base, u32 ofs) +{ + struct modeldef *mdl = (struct modeldef *)base; + + PD_BEFIELD_I16(mdl->nummatrices); + PD_BEFIELD_I16(mdl->numparts); + PD_BEFIELD_I16(mdl->numtexconfigs); + PD_BEFIELD_I16(mdl->rwdatalen); + PD_BEFIELD_F32(mdl->scale); + + if (mdl->skel) { + PD_BEFIELD_PTR(mdl->skel); + if ((u32)mdl->skel >= 0x10000) { + // skeleton is a pointer instead of an index + // preprocessSkeleton((struct skeleton *)(base + (u32)mdl->skel)); // TODO + } + } + + if (mdl->parts) { + PD_BEFIELD_PTR(mdl->parts); + struct modelnode **parts = PD_PTR_BASEOFS(mdl->parts, base, ofs); + for (s16 i = 0; i < mdl->numparts; ++i) { + PD_BEFIELD_PTR(parts[i]); + } + s16 *partnums = (s16 *)&parts[mdl->numparts]; + for (s16 i = 0; i < mdl->numparts; ++i) { + PD_BEFIELD_I16(partnums[i]); + } + } + + if (mdl->texconfigs) { + PD_BEFIELD_PTR(mdl->texconfigs); + struct textureconfig *texconfigs = PD_PTR_BASEOFS(mdl->texconfigs, base, ofs); + for (s16 i = 0; i < mdl->numtexconfigs; ++i) { + PD_BEFIELD_I32(texconfigs[i].texturenum); + } + } + + if (mdl->rootnode) { + PD_BEFIELD_PTR(mdl->rootnode); + preprocessModelNode(PD_PTR_BASEOFS(mdl->rootnode, base, ofs), base, ofs); + } +} + +void preprocessLangFile(u8 *data, u32 size) +{ + // lang banks are just an offset table + text data right after + // offsets are from the beginning of the bank + // however we cannot preprocess them in advance because the length of the + // offset table is unknown, so that's done in lang.c on demand instead +} + +void preprocessPadsFile(u8 *data, u32 size) +{ + struct padsfileheader *hdr = (void *)data; + + PD_BEFIELD_I32(hdr->numpads); + PD_BEFIELD_I32(hdr->numcovers); + + for (s32 i = 0; i < hdr->numpads; ++i) { + if (hdr->padoffsets[i]) { + PD_BEFIELD_I32(hdr->padoffsets[i]); + preprocessPadData(PD_PTR_BASE(hdr->padoffsets[i], hdr)); + } + } + + if (hdr->numcovers && hdr->coversoffset) { + PD_BEFIELD_I32(hdr->coversoffset); + struct coverdefinition *def = PD_PTR_BASE(hdr->coversoffset, hdr); + for (s32 i = 0; i < hdr->numcovers; ++i, ++def) { + PD_BEFIELD_I16(def->flags); + PD_BEFIELD_F32(def->look.x); + PD_BEFIELD_F32(def->look.y); + PD_BEFIELD_F32(def->look.z); + PD_BEFIELD_F32(def->pos.x); + PD_BEFIELD_F32(def->pos.y); + PD_BEFIELD_F32(def->pos.z); + } + } + + if (hdr->waypointsoffset) { + PD_BEFIELD_I32(hdr->waypointsoffset); + struct waypoint *wp = PD_PTR_BASE(hdr->waypointsoffset, hdr); + while (wp->padnum) { + PD_BEFIELD_I32(wp->padnum); + PD_BEFIELD_I32(wp->groupnum); + PD_BEFIELD_I32(wp->step); + PD_BEFIELD_PTR(wp->neighbours); + ++wp; + } + } + + if (hdr->waygroupsoffset) { + PD_BEFIELD_I32(hdr->waygroupsoffset); + struct waygroup *wg = PD_PTR_BASE(hdr->waygroupsoffset, hdr); + while (wg->neighbours) { + PD_BEFIELD_PTR(wg->neighbours); + PD_BEFIELD_PTR(wg->waypoints); + PD_BEFIELD_I32(wg->step); + ++wg; + } + } +} + +void preprocessTilesFile(u8 *data, u32 size) +{ + u32 *roomTable = (u32 *)data; + PD_BEFIELD_I32(roomTable[0]); + + const u32 numRooms = roomTable[0]; + ++roomTable; + + u32 *rooms = roomTable; + for (u32 i = 0; i < numRooms; ++i) { + PD_BEFIELD_I32(rooms[i]); + } + + struct geo *geo = (struct geo *)(data + rooms[0]); + struct geo *end = (struct geo *)(data + rooms[numRooms]); + + while (geo < end) { + PD_BEFIELD_I16(geo->flags); + switch (geo->type) { + case GEOTYPE_TILE_I: { + struct geotilei *tile = (struct geotilei *)geo; + PD_BEFIELD_I16(tile->floorcol); + PD_BEFIELD_I16(tile->floortype); + for (u32 i = 0; i < geo->numvertices; ++i) { + PD_BEFIELD_I16(tile->vertices[i][0]); + PD_BEFIELD_I16(tile->vertices[i][1]); + PD_BEFIELD_I16(tile->vertices[i][2]); + } + geo = (struct geo *)((u8 *)geo + (uintptr_t)(geo->numvertices - 0x40) * 6 + 0x18e); + break; + } + case GEOTYPE_TILE_F: { + struct geotilef *tile = (struct geotilef *)geo; + PD_BEFIELD_I16(tile->floorcol); + PD_BEFIELD_I16(tile->floortype); + for (u32 i = 0; i < geo->numvertices; ++i) { + PD_BEFIELD_F32(tile->vertices[i].x); + PD_BEFIELD_F32(tile->vertices[i].y); + PD_BEFIELD_F32(tile->vertices[i].z); + } + geo = (struct geo *)((u8 *)geo + (uintptr_t)(geo->numvertices - 0x40) * 12 + 0x310); + break; + } + case GEOTYPE_BLOCK: { + struct geoblock *blk = (struct geoblock *)geo; + PD_BEFIELD_F32(blk->ymin); + PD_BEFIELD_F32(blk->ymax); + for (u32 i = 0; i < geo->numvertices; ++i) { + PD_BEFIELD_F32(blk->vertices[i][0]); + PD_BEFIELD_F32(blk->vertices[i][1]); + } + geo = (struct geo *)((u8 *)geo + sizeof(struct geoblock)); + break; + } + case GEOTYPE_CYL: { + struct geocyl *cyl = (struct geocyl *)geo; + PD_BEFIELD_F32(cyl->x); + PD_BEFIELD_F32(cyl->z); + PD_BEFIELD_F32(cyl->radius); + PD_BEFIELD_F32(cyl->ymin); + PD_BEFIELD_F32(cyl->ymax); + geo = (struct geo *)((u8 *)geo + sizeof(struct geocyl)); + break; + } + default: + break; + } + } +} + +void preprocessSetupFile(u8 *data, u32 size) +{ + struct stagesetup *set = (void *)data; + + if (set->intro) { + PD_BEFIELD_PTR(set->intro); + for (s32 *p = PD_PTR_BASE(set->intro, set); (u8 *)p < data + size; ++p) { + PD_BEFIELD_I32(*p); + if (*p == 0x0c /*endintro*/) { + break; + } + } + } + + if (set->props) { + PD_BEFIELD_PTR(set->props); + for (s32 *p = PD_PTR_BASE(set->props, set); (u8 *)p < data + size; ++p) { + PD_BEFIELD_I32(*p); + if (*p == 0x34 /*endprops*/) { + break; + } + } + } + + if (set->paths) { + PD_BEFIELD_PTR(set->paths); + struct path *p = PD_PTR_BASE(set->paths, set); + while ((u8 *)p < data + size && p->pads) { + PD_BEFIELD_PTR(p->pads); + PD_BEFIELD_I16(p->len); + s32 *pp = PD_PTR_BASE(p->pads, set); + while ((u8 *)pp < data + size) { + PD_BEFIELD_I32(*pp); + if (*pp < 0) { + break; + } + } + } + } + + if (set->ailists) { + PD_BEFIELD_PTR(set->ailists); + struct ailist *p = PD_PTR_BASE(set->ailists, set); + while ((u8 *)p < data + size && p->list) { + PD_BEFIELD_I32(p->id); + PD_BEFIELD_PTR(p->list); + // the actual command lists are made up of variable length instructions, + // but they don't do any wonky word casting, so they should probably work as is + } + } + + // the rest of the pointers are set after loading +} + +void preprocessModelFile(u8 *data, u32 size) +{ + preprocessModel(data, size); +} + +void preprocessGunFile(u8 *data, u32 size) +{ + preprocessModel(data, size); +} + +void preprocessBgSection1Header(u8 *data, u32 size) +{ + u32 *header = (u32 *)data; + PD_BEFIELD_I32(header[0]); // inflatedsize + PD_BEFIELD_I32(header[1]); // section1size + PD_BEFIELD_I32(header[2]); // primcompsize +} + +void preprocessBgSection1(u8 *data, u32 ofs) { + struct { + u32 unk00; + u32 roomsofs; + u32 portalsofs; + u32 commandsofs; + u32 lightsofs; + u32 stanofs; + } __attribute__((packed)) *header = (void *)data; + + PD_BEFIELD_I32(header->unk00); + PD_BEFIELD_I32(header->roomsofs); + PD_BEFIELD_I32(header->portalsofs); + + struct bgroom *rm = PD_PTR_BASEOFS(header->roomsofs, data, ofs); + for (; rm->unk00; ++rm) { + PD_BEFIELD_I32(rm->unk00); + PD_BEFIELD_F32(rm->pos.x); + PD_BEFIELD_F32(rm->pos.y); + PD_BEFIELD_F32(rm->pos.z); + } + + struct bgportal *portals = PD_PTR_BASEOFS(header->portalsofs, data, ofs); + s32 numportals = 0; + u32 offset = 0; + for (struct bgportal *prt = portals; prt->verticesoffset; ++prt) { + PD_BEFIELD_I16(prt->verticesoffset); + PD_BEFIELD_I16(prt->roomnum1); + PD_BEFIELD_I16(prt->roomnum2); + ++numportals; + offset += sizeof(struct bgportal); + } + offset += sizeof(struct bgportal); + + // see bgBuildTables for an explanation of what the fuck this is + for (s32 i = 1; 1; i++) { + for (s32 j = 0; j < numportals; j++) { + if (portals[j].verticesoffset == i) { + portals[j].verticesoffset = offset; + } + } + struct portalvertices *pverts = PD_PTR_BASE(offset, portals); + for (u32 i = 0; i < pverts->count; ++i) { + PD_BEFIELD_F32(pverts->vertices[i].x); + PD_BEFIELD_F32(pverts->vertices[i].y); + PD_BEFIELD_F32(pverts->vertices[i].z); + } + } + + if (header->commandsofs) { + PD_BEFIELD_I32(header->commandsofs); + struct bgcmd *cmd = PD_PTR_BASEOFS(header->commandsofs, data, ofs); + for (; cmd->type != 0x00; cmd++) { + PD_BEFIELD_I32(cmd->param); + } + } + + if (header->lightsofs) { + PD_BEFIELD_I32(header->lightsofs); + // data swapping done later in preprocessBgLights + } + + if (header->stanofs) { + PD_BEFIELD_I32(header->stanofs); + // unused, so won't swap the contents + } +} + +void preprocessBgSection2Header(u8 *data, u32 size) +{ + u16 *header = (u16 *)data; + PD_BEFIELD_I16(header[0]); // inflatedsize + PD_BEFIELD_I16(header[1]); // section2compsize +} + +void preprocessBgSection2(u8 *data, u32 size) +{ + // section2 is a texture id list + u16 *section2 = (u16 *)data; + for (s32 i = 0; i < size; ++i) { + PD_BEFIELD_I16(section2[i]); + } +} + +void preprocessBgSection3Header(u8 *data, u32 size) +{ + u16 *header = (u16 *)data; + PD_BEFIELD_I16(header[0]); + PD_BEFIELD_I16(header[1]); +} + +void preprocessBgSection3(u8 *data, u32 size) +{ + // room bounding boxes, 6x s16 per room + s16 *bbox = (s16 *)data; + for (s32 i = 1; i < g_Vars.roomcount; ++i) { + PD_BEFIELD_I16(*bbox); ++bbox; + PD_BEFIELD_I16(*bbox); ++bbox; + PD_BEFIELD_I16(*bbox); ++bbox; + PD_BEFIELD_I16(*bbox); ++bbox; + PD_BEFIELD_I16(*bbox); ++bbox; + PD_BEFIELD_I16(*bbox); ++bbox; + } + + // gfxdatalen list + u16 *gfxdatalen = (u16 *)bbox; + for (s32 i = 1; i < g_Vars.roomcount; ++i) { + PD_BEFIELD_I16(*gfxdatalen); ++gfxdatalen; + } +} + +void preprocessBgRoom(u8 *data, u32 ofs) { + struct roomgfxdata *rgfx = (void *)data; + + PD_BEFIELD_I16(rgfx->numvertices); + PD_BEFIELD_I16(rgfx->numcolours); + PD_BEFIELD_I16(rgfx->numlights); + PD_BEFIELD_I16(rgfx->lightsindex); + PD_BEFIELD_PTR(rgfx->vertices); + PD_BEFIELD_PTR(rgfx->opablocks); + PD_BEFIELD_PTR(rgfx->xlublocks); + PD_BEFIELD_PTR(rgfx->colours); + + Vtx *vertices = PD_PTR_BASEOFS(rgfx->vertices, data, ofs); + Vtx *vtx = vertices; + for (s32 i = 0; i < rgfx->numvertices; ++i, ++vtx) { + preprocessVtx(vtx); + } + + // here's hoping that xlublocks and opablocks aren't completely separate trees + + struct roomblock *blk = rgfx->blocks; + struct roomblock *end = (void *)vertices; + struct coord *tmp; + + for (; blk + 1 <= end; blk++) { + PD_BEFIELD_PTR(blk->next); + switch (blk->type) { + case ROOMBLOCKTYPE_LEAF: + if (blk->gdl) { + PD_BEFIELD_PTR(blk->gdl); + preprocessGfx(PD_PTR_BASEOFS(blk->gdl, data, ofs)); + } + break; + case ROOMBLOCKTYPE_PARENT: + PD_BEFIELD_PTR(blk->child); + PD_BEFIELD_PTR(blk->unk0c); + tmp = PD_PTR_BASEOFS(blk->unk0c, data, ofs); + for (s32 i = 0; i < 2; ++i) { + PD_BEFIELD_F32(tmp[i].x); + PD_BEFIELD_F32(tmp[i].y); + PD_BEFIELD_F32(tmp[i].z); + } + if ((u8 *)tmp < (u8 *)end) { + end = (void *)tmp; + } + break; + default: + break; + } + } +} + +void preprocessBgLights(u8 *data, u32 ofs) +{ + struct light *lbase = (void *)data; + if (!lbase) { + return; + } + + for (s32 i = 0; i < g_Vars.roomcount; ++i) { + if (g_Rooms[i].numlights) { + struct light *lit = &lbase[g_Rooms[i].lightindex]; + for (s32 i = 0; i < g_Rooms[i].numlights; ++i, ++lit) { + PD_BEFIELD_I16(lit->bbox->x); + PD_BEFIELD_I16(lit->bbox->y); + PD_BEFIELD_I16(lit->bbox->z); + PD_BEFIELD_I16(lit->colour); // TODO: required? + PD_BEFIELD_I16(lit->roomnum); + } + } + } +} diff --git a/port/src/romdata.c b/port/src/romdata.c new file mode 100644 index 000000000..6bee895c0 --- /dev/null +++ b/port/src/romdata.c @@ -0,0 +1,417 @@ +#include +#include +#include +#include +#include +#include +#include "lib/rzip.h" +#include "romdata.h" +#include "fs.h" +#include "system.h" +#include "preprocess.h" +#include "platform.h" + +/** + * asset files and ROM segments can be replaced by optional external files, + * but asset filenames still have to be either pulled from the ROM or from an + * external file, so stuff can't be completely custom + * + * all data is assumed to be big endian, so it has to be byteswapped + * at load time, which is fucking terrible + */ + +#define ROMDATA_ROM_NAME "pd.ntsc-final.z64" +#define ROMDATA_ROM_SIZE 33554432 +#define ROMDATA_ROM_HASH // TODO + +#define ROMDATA_FILEDIR "files" +#define ROMDATA_SEGDIR "segs" + +// for ntsc-final +#define ROMDATA_FILES_OFS 0x28080 +#define ROMDATA_DATA_OFS 0x39850 + +#define ROMDATA_MAX_FILES 2048 + +u8 *g_RomFile; +u32 g_RomFileSize; + +static u8 *romDataSeg; +static u32 romDataSegSize; + +struct romfile { + u8 **segstart; + u8 **segend; + const char *name; + u8 *data; + u32 size; + preprocessfunc preprocess; + s32 external; + s32 preprocessed; +}; + +static struct romfile fileSlots[ROMDATA_MAX_FILES]; + +#define ROMSEG_START(n) _ ## n ## SegmentRomStart +#define ROMSEG_END(n) _ ## n ## SegmentRomEnd + +/* segment table for ntsc-final */ +/* size will get calculated automatically if it is 0 */ +/* if there are replacement files in the data dir, they will be loaded instead */ +#define ROMSEG_LIST() \ + ROMSEG_DECL_SEG(fontjpnsingle, 0x194b20, 0x0, preprocessJpnFont ) \ + ROMSEG_DECL_SEG(fontjpnmulti, 0x19fb40, 0x0, preprocessJpnFont ) \ + ROMSEG_DECL_SEG(animations, 0x1a15c0, 0x0, preprocessAnimations ) \ + ROMSEG_DECL_SEG(mpconfigs, 0x7d0a40, 0x11E0, preprocessMpConfigs ) \ + ROMSEG_DECL_SEG(mpstringsE, 0x7d1c20, 0x3700, NULL ) \ + ROMSEG_DECL_SEG(mpstringsJ, 0x7d5320, 0x3700, NULL ) \ + ROMSEG_DECL_SEG(mpstringsP, 0x7d8a20, 0x3700, NULL ) \ + ROMSEG_DECL_SEG(mpstringsG, 0x7dc120, 0x3700, NULL ) \ + ROMSEG_DECL_SEG(mpstringsF, 0x7df820, 0x3700, NULL ) \ + ROMSEG_DECL_SEG(mpstringsS, 0x7e2f20, 0x3700, NULL ) \ + ROMSEG_DECL_SEG(mpstringsI, 0x7e6620, 0x3700, NULL ) \ + ROMSEG_DECL_SEG(firingrange, 0x7e9d20, 0x1550, preprocessFiringRange ) \ + ROMSEG_DECL_SEG(fonttahoma, 0x7f7860, 0x0, preprocessFont ) \ + ROMSEG_DECL_SEG(fontnumeric, 0x7f8b20, 0x0, preprocessFont ) \ + ROMSEG_DECL_SEG(fonthandelgothicsm, 0x7f9d30, 0x0, preprocessFont ) \ + ROMSEG_DECL_SEG(fonthandelgothicxs, 0x7fbfb0, 0x0, preprocessFont ) \ + ROMSEG_DECL_SEG(fonthandelgothicmd, 0x7fdd80, 0x0, preprocessFont ) \ + ROMSEG_DECL_SEG(fonthandelgothiclg, 0x8008e0, 0x0, preprocessFont ) \ + ROMSEG_DECL_SEG(sfxctl, 0x80a250, 0x2fb80, preprocessALBankFile ) \ + ROMSEG_DECL_SEG(sfxtbl, 0x839dd0, 0x4c2160, NULL ) \ + ROMSEG_DECL_SEG(seqctl, 0xcfbf30, 0xa060, preprocessALBankFile ) \ + ROMSEG_DECL_SEG(seqtbl, 0xd05f90, 0x17c070, NULL ) \ + ROMSEG_DECL_SEG(sequences, 0xe82000, 0x563a0, preprocessSequences ) \ + ROMSEG_DECL_SEG(texturesdata, 0x1d65f40, 0x291d60, NULL ) \ + ROMSEG_DECL_SEG(textureslist, 0x1ff7ca0, 0x6d80, preprocessTexturesList ) + +// declare the vars first + +#undef ROMSEG_DECL_SEG +#define ROMSEG_DECL_SEG(name, ofs, size, preproc) u8 *ROMSEG_START(name), *ROMSEG_END(name); +ROMSEG_LIST() + +// this is part of the animations seg and as such does not follow the naming convention +// these are set in preprocessAnimations +u8 *_animationsTableRomStart; +u8 *_animationsTableRomEnd; + +// then build the table + +#undef ROMSEG_DECL_SEG +#define ROMSEG_DECL_SEG(name, ofs, size, preproc) { &ROMSEG_START(name), &ROMSEG_END(name), #name, (u8 *)ofs, size, preproc }, +static struct romfile romSegs[] = { + ROMSEG_LIST() + { NULL, NULL, NULL, NULL, 0, NULL }, +}; + +/* the game sets g_LoadType to the type of file it expects, */ +/* so we can hijack that in fileLoad and automatically byteswap the file */ +static preprocessfunc filePreprocFuncs[] = { + /* LOADTYPE_NONE */ NULL, + /* LOADTYPE_BG */ NULL, // loaded in parts + /* LOADTYPE_TILES */ preprocessTilesFile, + /* LOADTYPE_LANG */ preprocessLangFile, + /* LOADTYPE_SETUP */ preprocessSetupFile, + /* LOADTYPE_PADS */ preprocessPadsFile, + /* LOADTYPE_MODEL */ preprocessModelFile, + /* LOADTYPE_GUN */ preprocessGunFile, +}; + +static inline void romdataLoadRom(void) +{ + g_RomFile = fsFileLoad(ROMDATA_ROM_NAME, &g_RomFileSize); + + if (!g_RomFile) { + sysFatalError("Could not open ROM file " ROMDATA_ROM_NAME ".\nEnsure that it is in the data directory."); + } + + if (g_RomFileSize != ROMDATA_ROM_SIZE) { + sysFatalError("Wrong ROM file size.\nExpected: %u\nGot: %u", ROMDATA_ROM_SIZE, g_RomFileSize); + } + + if (memcmp(g_RomFile + 0x3b, "NPDE", 4) || memcmp(g_RomFile + 0x20, "Perfect Dark", 12)) { + sysFatalError("Wrong ROM file.\nEnsure that it is the correct NTSC v1.1 ROM in z64 format."); + } + + // inflate the compressed data segment since that's where some useful stuff is + + u8 *zipped = g_RomFile + ROMDATA_DATA_OFS; + if (!zipped) { + sysFatalError("Data segment not found."); + } + if (!rzipIs1173(zipped)) { + sysFatalError("Data segment is not 1173-compressed."); + } + + const u32 dataSegLen = ((u32)zipped[2] << 16) | ((u32)zipped[3] << 8) | (u32)zipped[4]; + if (dataSegLen < ROMDATA_FILES_OFS) { + sysFatalError("Data segment too small (%u), need at least %u.", dataSegLen, ROMDATA_FILES_OFS); + } + + u8 *dataSeg = calloc(1, dataSegLen); + if (!dataSeg) { + sysFatalError("Could not allocate %u bytes for data segment.", dataSegLen); + } + + u8 scratch[5 * 1024]; + if (rzipInflate(zipped, dataSeg, scratch) < 0) { + free(dataSeg); + sysFatalError("Could not inflate data segment."); + } + + romDataSeg = dataSeg; + romDataSegSize = dataSegLen; +} + +static inline void romdataInitSegment(struct romfile *seg) +{ + if (!seg->size) { + // size unknown + if (seg[1].name) { + // use next segment's base to calculate + seg->size = seg[1].data - seg->data; + } else { + // this is the last segment, calculate based on rom size + seg->size = (u8 *)g_RomFileSize - seg->data; + } + } + + // check if we have an external replacement and load it if so + u8 *newData = NULL; + const s32 extFileSize = fsFileSize(seg->name); + if (extFileSize > 0) { + char tmp[FS_MAXPATH]; + snprintf(tmp, sizeof(tmp), ROMDATA_SEGDIR "/%s", seg->name); + newData = fsFileLoad(tmp, &seg->size); + } + + if (!newData) { + // no external data, just make it point to the rom + if (g_RomFile) { + newData = g_RomFile + (uintptr_t)seg->data; + printf("loading segment %s from ROM (offset %08x pointer %p)\n", seg->name, (u32)seg->data, newData); + fflush(stdout); + } else { + sysFatalError("No ROM or external file for segment:\n%s", seg->name); + } + } else { + // loaded external data + seg->external = 1; + printf("loading segment %s from file (pointer %p)\n", seg->name, newData); + fflush(stdout); + } + + seg->data = newData; + + if (seg->segstart) { + *seg->segstart = seg->data; + } + + if (seg->segend) { + *seg->segend = seg->data + seg->size; + } + + // call the post load function if any + if (seg->preprocess && !seg->preprocessed) { + seg->preprocess(seg->data, seg->size); + seg->preprocessed = 1; + } +} + +static inline s32 romdataLoadExternalFileList(void) +{ + romDataSeg = fsFileLoad("filenames.lst", &romDataSegSize); // this null terminates the file by itself + if (!romDataSeg || !romDataSegSize) { + return 0; + } + + s32 n = 1; + char *p = (char *)romDataSeg; + while (*p && n < ROMDATA_MAX_FILES) { + // skip whitespace + while (*p && isspace(*p)) ++p; + if (*p) { + const char *start = p; + // skip to next whitespace or end of file + while (*p && !isspace(*p)) ++p; + // null terminate the name if needed + if (*p) { + *p++ = '\0'; + } + fileSlots[n++].name = start; + } + } + + return n - 1; +} + +static inline void romdataInitFiles(void) +{ + if (!g_RomFile) { + // no ROM; try to load the file name list from disk + if (!romdataLoadExternalFileList()) { + sysFatalError("No ROM or external file for filename table."); + } + return; + } + + // the file offset table is in the data seg + const u32 *offsets = (u32 *)(romDataSeg + ROMDATA_FILES_OFS); + u32 i; + for (i = 1; offsets[i]; ++i) { + if (offsets + i + 1 < (u32 *)(romDataSeg + romDataSegSize)) { + const u32 nextofs = PD_BE32(offsets[i + 1]); + const u32 ofs = PD_BE32(offsets[i]); + fileSlots[i].data = g_RomFile + ofs; + fileSlots[i].size = nextofs - ofs; + fileSlots[i].external = 0; + fileSlots[i].preprocessed = 0; + } + } + + // last offset is to the name table + const u32 *nameOffsets = (u32 *)(g_RomFile + PD_BE32(offsets[i - 1])); + for (i = 1; nameOffsets[i]; ++i) { + const u32 ofs = PD_BE32(nameOffsets[i]); + fileSlots[i].name = (const char *)nameOffsets + ofs; // ofs is relative to the start of the name table + printf("file %d name `%s` ofs %d size %u\n", i, fileSlots[i].name, fileSlots[i].data - g_RomFile, fileSlots[i].size); + } +} + +static inline struct romfile *romdataGetSeg(const char *name) +{ + struct romfile *seg = romSegs; + while (seg->name && strcmp(name, seg->name)) { + ++seg; + } + return seg; +} + +s32 romdataInit(void) +{ + romdataLoadRom(); + + // set segments to point to the rom or load them externally + for (struct romfile *seg = romSegs; seg->name; ++seg) { + romdataInitSegment(seg); + } + + // load file table from the files segment + romdataInitFiles(); + + printf("romdataInit: loaded rom, size = %u\n", g_RomFileSize); + fflush(stdout); + + return 0; +} + +s32 romdataFileGetSize(s32 fileNum) +{ + if (fileNum < 1 || fileNum >= ROMDATA_MAX_FILES) { + fprintf(stderr, "romdataFileGetSize: invalid file num %d", fileNum); + return -1; + } + if (!fileSlots[fileNum].data) { + fprintf(stderr, "romdataFileGetSize: file %d is not loaded", fileNum); + return -1; + } + return fileSlots[fileNum].size; +} + +u8 *romdataFileGetData(s32 fileNum) +{ + if (fileNum < 1 || fileNum >= ROMDATA_MAX_FILES) { + fprintf(stderr, "romdataFileGetData: invalid file num %d", fileNum); + return NULL; + } + if (!fileSlots[fileNum].data) { + fprintf(stderr, "romdataFileGetData: file %d is not loaded, loading", fileNum); + return romdataFileLoad(fileNum, NULL); + } + return fileSlots[fileNum].data; +} + +u8 *romdataFileLoad(s32 fileNum, u32 *outSize) +{ + if (fileNum < 1 || fileNum >= ROMDATA_MAX_FILES) { + fprintf(stderr, "romdataFileLoad: invalid file num %d", fileNum); + return NULL; + } + + u8 *out = NULL; + + // try to load external file + if (!fileSlots[fileNum].external) { + char tmp[FS_MAXPATH] = { 0 }; + snprintf(tmp, sizeof(tmp), ROMDATA_FILEDIR "/%s", fileSlots[fileNum].name); + if (fsFileSize(tmp) > 0) { + u32 size = 0; + out = fsFileLoad(tmp, &size); + if (out && size) { + printf("file %d (%s) loaded externally\n", fileNum, fileSlots[fileNum].name); + fileSlots[fileNum].data = out; + fileSlots[fileNum].size = size; + fileSlots[fileNum].external = 1; + } + } + } + + if (!out) { + out = fileSlots[fileNum].data; + } + + if (out && outSize) { + *outSize = fileSlots[fileNum].size; + } + + return out; +} + +void romdataFilePreprocess(s32 fileNum, s32 loadType, u8 *data, u32 size) +{ + if (fileNum < 1 || fileNum >= ROMDATA_MAX_FILES) { + fprintf(stderr, "romdataFilePreprocess: invalid file num %d", fileNum); + return; + } + + if (data && size /* && !fileSlots[fileNum].preprocessed*/) { + if (loadType && loadType < (u32)ARRAYCOUNT(filePreprocFuncs) && filePreprocFuncs[loadType]) { + filePreprocFuncs[loadType](data, size); + // fileSlots[fileNum].preprocessed = 1; + } + } +} + +void romdataFileFree(s32 fileNum) +{ + if (fileNum < 1 || fileNum >= ROMDATA_MAX_FILES) { + fprintf(stderr, "fsFileFree: invalid file num %d", fileNum); + return; + } + + if (!fileSlots[fileNum].external) { + fprintf(stderr, "fsFileFree: file %d not external", fileNum); + return; + } + + free(fileSlots[fileNum].data); + fileSlots[fileNum].data = NULL; + fileSlots[fileNum].external = 0; +} + +u8 *romdataSegGetData(const char *segName) +{ + return romdataGetSeg(segName)->data; +} + +u8 *romdataSegGetDataEnd(const char *segName) +{ + struct romfile *seg = romdataGetSeg(segName); + return seg->data + seg->size; +} + +u32 romdataSegGetSize(const char *segName) +{ + return romdataGetSeg(segName)->size; +} diff --git a/port/src/system.c b/port/src/system.c new file mode 100644 index 000000000..055377431 --- /dev/null +++ b/port/src/system.c @@ -0,0 +1,47 @@ +#include +#include +#include +#include +#include +#include +#include "system.h" + +static u64 startTick = 0; +static u64 tickFreq = 0; + +static void sysInitTicks(void) +{ + tickFreq = SDL_GetPerformanceFrequency(); + startTick = SDL_GetPerformanceCounter(); +} + +u64 sysGetTicks(void) +{ + if (tickFreq == 0) { + sysInitTicks(); + } + return (SDL_GetPerformanceCounter() - startTick); +} + +u64 sysGetTicksPerSecond(void) +{ + if (tickFreq == 0) { + sysInitTicks(); + } + return tickFreq; +} + +void sysFatalError(const char *fmt, ...) +{ + char errmsg[2048] = { 0 }; + + va_list ap; + va_start(ap, fmt); + vsnprintf(errmsg, sizeof(errmsg), fmt, ap); + va_end(ap); + + fprintf(stderr, "FATAL ERROR: %s\n", errmsg); + + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal error", errmsg, NULL); + exit(1); +} diff --git a/port/src/video.c b/port/src/video.c new file mode 100644 index 000000000..16570a305 --- /dev/null +++ b/port/src/video.c @@ -0,0 +1,59 @@ +#include +#include +#include +#include +#include + +#include "../n64-fast3d-engine/gfx_pc.h" +#include "../n64-fast3d-engine/gfx_sdl2.h" +#include "../n64-fast3d-engine/gfx_opengl.h" + +static struct GfxWindowManagerAPI *wmAPI; +static struct GfxRenderingAPI *renderingAPI; + +static bool initDone = false; + +s32 videoInit(void) +{ + wmAPI = &gfx_sdl; + renderingAPI = &gfx_opengl_api; + gfx_init(wmAPI, renderingAPI, "PD", false); + initDone = true; + return 0; +} + +void videoStartFrame(void) +{ + if (initDone) { + gfx_start_frame(); + } +} + +void videoSubmitCommands(Gfx *cmds) +{ + if (initDone) { + gfx_run(cmds); + } +} + +void videoEndFrame(void) +{ + if (initDone) { + gfx_end_frame(); + } +} + +void videoClearScreen(void) +{ + videoStartFrame(); + // TODO: clear + videoEndFrame(); +} + +void *videoGetWindowHandle(void) +{ + if (initDone && wmAPI) { + return wmAPI->get_window_handle(); + } + return NULL; +} diff --git a/src/game/bg.c b/src/game/bg.c index 640955cb0..4835c75a2 100644 --- a/src/game/bg.c +++ b/src/game/bg.c @@ -43,6 +43,9 @@ #include "data.h" #include "gbiex.h" #include "types.h" +#ifndef PLATFORM_N64 +#include "preprocess.h" +#endif #define BGCMD_END 0x00 #define BGCMD_PUSH 0x01 @@ -1492,6 +1495,9 @@ void bgReset(s32 stagenum) // Copy section 1 header to stack and parse into variables header = (u8 *)ALIGN16((uintptr_t)headerbuffer); bgLoadFile(header, 0, 0x40); +#ifndef PLATFORM_N64 + preprocessBgSection1Header(header, 0x40); +#endif inflatedsize = *(u32 *)&header[0]; section1compsize = *(u32 *)&header[4]; primcompsize = *(u32 *)&header[8]; @@ -1516,6 +1522,10 @@ void bgReset(s32 stagenum) scratch += 0xc; bgInflate((u8 *) scratch, g_BgPrimaryData, primcompsize); +#ifndef PLATFORM_N64 + preprocessBgSection1(g_BgPrimaryData, 0x0f000000); +#endif + // Shrink the allocation (ie. free the scratch space) mempRealloc(g_BgPrimaryData, inflatedsize, MEMPOOL_STAGE); @@ -1523,6 +1533,9 @@ void bgReset(s32 stagenum) section2start = section1compsize + 0xc; bgLoadFile(header, section2start, 0x40); +#ifndef PLATFORM_N64 + preprocessBgSection2Header(header, 0x40); +#endif inflatedsize = (*(u16 *) &header[0] & 0x7fff) - 1; section2compsize = *(u16 *) &header[2]; @@ -1552,6 +1565,10 @@ void bgReset(s32 stagenum) // Iterate texture IDs and ensure they're loaded inflatedsize = (*(u16 *) &header[0] & 0x7fff) >> 1; +#ifndef PLATFORM_N64 + preprocessBgSection2((u8 *)section2, inflatedsize); +#endif + for (i = 0; i ^ inflatedsize; i++) { texLoadFromTextureNum(section2[i] & 0xffff & 0xffff & 0xffff & 0xffff & 0xffff & 0xffff & 0xffff & 0xffff, NULL); } @@ -1891,6 +1908,9 @@ void bgBuildTables(s32 stagenum) // Load and read the header header = (u8 *)ALIGN16((uintptr_t)headerbuffer); bgLoadFile(header, g_BgSection3, 0x40); +#ifndef PLATFORM_N64 + preprocessBgSection3Header(header, 0x40); +#endif inflatedsize = (*(u16 *)&header[0] & 0x7fff) - 1; section3compsize = *(u16 *)&header[2]; inflatedsize = (inflatedsize | 0xf) + 1; @@ -1909,6 +1929,9 @@ void bgBuildTables(s32 stagenum) bgLoadFile(scratch, g_BgSection3 + 4, ((section3compsize - 1) | 0xf) + 1); bgInflate(scratch, section3, section3compsize); +#ifndef PLATFORM_N64 + preprocessBgSection3(section3, section3compsize); +#endif // Section 3 starts with a table of room bounding boxes bboxptr = (s16 *) section3; @@ -1966,6 +1989,10 @@ void bgBuildTables(s32 stagenum) numlightsptr++; } +#ifndef PLATFORM_N64 + preprocessBgLights(g_BgLightsFileData, 0); +#endif + // Free the section 3 allocation mempRealloc(section3, 0, MEMPOOL_STAGE); @@ -2795,6 +2822,9 @@ void bgLoadRoom(s32 roomnum) // Inflate the data to the left side of the allocation inflatedlen = bgInflate(memaddr, allocation, g_BgRooms[roomnum + 1].unk00 - g_BgRooms[roomnum].unk00); +#ifndef PLATFORM_N64 + preprocessBgRoom(allocation, g_BgRooms[roomnum].unk00); +#endif g_Rooms[roomnum].gfxdata = (struct roomgfxdata *)allocation; diff --git a/src/game/challenge.c b/src/game/challenge.c index 7a1481f5d..ca809ca99 100644 --- a/src/game/challenge.c +++ b/src/game/challenge.c @@ -367,41 +367,55 @@ bool challengeIsCompletedByChrWithNumPlayersBySlot(s32 mpchrnum, s32 slot, s32 n return false; } +#ifdef PLATFORM_N64 +#define BTYPE s32 +#else +#define BTYPE uintptr_t +#endif + struct mpconfigfull *challengeLoadConfig(s32 confignum, u8 *buffer, s32 len) { struct mpconfigfull *mpconfig; u8 buffer2[sizeof(struct mpstrings) + 40]; struct mpstrings *loadedstrings; - s32 bank; + BTYPE bank; u32 language_id = langGetFileNumOffset(); +#ifdef PLATFORM_N64 extern struct mpconfig _mpconfigsSegmentRomStart[]; - extern struct mpstrings _mpstringsESegmentRomStart; - extern struct mpstrings _mpstringsJSegmentRomStart; - extern struct mpstrings _mpstringsPSegmentRomStart; - extern struct mpstrings _mpstringsGSegmentRomStart; - extern struct mpstrings _mpstringsFSegmentRomStart; - extern struct mpstrings _mpstringsSSegmentRomStart; - extern struct mpstrings _mpstringsISegmentRomStart; - extern struct mpstrings _mpstringsESegmentRomEnd; - extern struct mpstrings _mpstringsJSegmentRomEnd; - extern struct mpstrings _mpstringsPSegmentRomEnd; - extern struct mpstrings _mpstringsGSegmentRomEnd; - extern struct mpstrings _mpstringsFSegmentRomEnd; - extern struct mpstrings _mpstringsSSegmentRomEnd; - extern struct mpstrings _mpstringsISegmentRomEnd; +#else + extern u8 EXT_SEG _mpconfigsSegmentRomStart; +#endif + extern struct mpstrings EXT_SEG _mpstringsESegmentRomStart; + extern struct mpstrings EXT_SEG _mpstringsJSegmentRomStart; + extern struct mpstrings EXT_SEG _mpstringsPSegmentRomStart; + extern struct mpstrings EXT_SEG _mpstringsGSegmentRomStart; + extern struct mpstrings EXT_SEG _mpstringsFSegmentRomStart; + extern struct mpstrings EXT_SEG _mpstringsSSegmentRomStart; + extern struct mpstrings EXT_SEG _mpstringsISegmentRomStart; + extern struct mpstrings EXT_SEG _mpstringsESegmentRomEnd; + extern struct mpstrings EXT_SEG _mpstringsJSegmentRomEnd; + extern struct mpstrings EXT_SEG _mpstringsPSegmentRomEnd; + extern struct mpstrings EXT_SEG _mpstringsGSegmentRomEnd; + extern struct mpstrings EXT_SEG _mpstringsFSegmentRomEnd; + extern struct mpstrings EXT_SEG _mpstringsSSegmentRomEnd; + extern struct mpstrings EXT_SEG _mpstringsISegmentRomEnd; - s32 banks[][2] = { - { (s32)&_mpstringsESegmentRomStart, (s32)&_mpstringsESegmentRomEnd }, - { (s32)&_mpstringsJSegmentRomStart, (s32)&_mpstringsJSegmentRomEnd }, - { (s32)&_mpstringsPSegmentRomStart, (s32)&_mpstringsPSegmentRomEnd }, - { (s32)&_mpstringsGSegmentRomStart, (s32)&_mpstringsGSegmentRomEnd }, - { (s32)&_mpstringsFSegmentRomStart, (s32)&_mpstringsFSegmentRomEnd }, - { (s32)&_mpstringsSSegmentRomStart, (s32)&_mpstringsSSegmentRomEnd }, - { (s32)&_mpstringsISegmentRomStart, (s32)&_mpstringsISegmentRomEnd }, + BTYPE banks[][2] = { + { (BTYPE)REF_SEG _mpstringsESegmentRomStart, (BTYPE)REF_SEG _mpstringsESegmentRomEnd }, + { (BTYPE)REF_SEG _mpstringsJSegmentRomStart, (BTYPE)REF_SEG _mpstringsJSegmentRomEnd }, + { (BTYPE)REF_SEG _mpstringsPSegmentRomStart, (BTYPE)REF_SEG _mpstringsPSegmentRomEnd }, + { (BTYPE)REF_SEG _mpstringsGSegmentRomStart, (BTYPE)REF_SEG _mpstringsGSegmentRomEnd }, + { (BTYPE)REF_SEG _mpstringsFSegmentRomStart, (BTYPE)REF_SEG _mpstringsFSegmentRomEnd }, + { (BTYPE)REF_SEG _mpstringsSSegmentRomStart, (BTYPE)REF_SEG _mpstringsSSegmentRomEnd }, + { (BTYPE)REF_SEG _mpstringsISegmentRomStart, (BTYPE)REF_SEG _mpstringsISegmentRomEnd }, }; // Load mpconfigs - mpconfig = dmaExecWithAutoAlign(buffer, (s32)&_mpconfigsSegmentRomStart[confignum], sizeof(struct mpconfig)); +#ifdef PLATFORM_N64 + mpconfig = dmaExecWithAutoAlign(buffer, (BTYPE)&_mpconfigsSegmentRomStart[confignum], sizeof(struct mpconfig)); +#else + mpconfig = dmaExecWithAutoAlign(buffer, (BTYPE)REF_SEG _mpconfigsSegmentRomStart + confignum * sizeof(struct mpconfig), sizeof(struct mpconfig)); +#endif // Load mpstrings bank = banks[language_id][0]; diff --git a/src/game/file.c b/src/game/file.c index 1f110e2c5..2760f6d14 100644 --- a/src/game/file.c +++ b/src/game/file.c @@ -10,6 +10,9 @@ #include "lib/rzip.h" #include "data.h" #include "types.h" +#ifndef PLATFORM_N64 +#include "romdata.h" +#endif /** * This file contains functions relating to ROM asset files. @@ -49,6 +52,14 @@ * functions that support this theory. */ +/** + * Currently the port just takes the filename from the filename[] array and feeds it + * into its own FS API that just loads it from disk. The whole file number/slot system + * is still mostly intact as a kludge. This will probably be removed later and reworked + * to just use filenames. + */ + +#ifdef PLATFORM_N64 extern void *_file_bg_sev_seg; extern void *_file_bg_silo_seg; extern void *_file_bg_stat_seg; @@ -2068,7 +2079,9 @@ extern void *_file_Asaucerexp1M; extern void *_file_PjaplogoZ; extern void *_file_PjappdZ; #endif + extern void *_filenamesSegmentRomStart; +#endif // PLATFORM_N64 struct fileinfo g_FileInfo[NUM_FILES]; @@ -2076,6 +2089,7 @@ struct fileinfo g_FileInfo[NUM_FILES]; u32 var800aa570; #endif +#ifdef PLATFORM_N64 u32 g_FileTable[] = { /*0x0000*/ 0, /*0x0001*/ (uintptr_t) &_file_bg_sev_seg, @@ -4099,14 +4113,22 @@ u32 g_FileTable[] = { #endif (uintptr_t) &_filenamesSegmentRomStart, }; +#else // PLATFORM_N64 +u32 g_FileTable[NUM_FILES + 1]; // TODO: this is only used to get the filenum, remove this +#endif // PLATFORM_N64 romptr_t fileGetRomAddress(s32 filenum) { +#ifdef PLATFORM_N64 return (romptr_t) g_FileTable[filenum]; +#else + return (romptr_t) romdataFileGetData(filenum); +#endif } u32 fileGetRomSizeByTableAddress(u32 *filetableaddr) { +#ifdef PLATFORM_N64 u32 size; if (filetableaddr[1]) { @@ -4116,6 +4138,10 @@ u32 fileGetRomSizeByTableAddress(u32 *filetableaddr) } return size; +#else + const s32 size = romdataFileGetSize(filetableaddr - g_FileTable); + return (size < 0) ? 0 : size; +#endif } s32 fileGetRomSize(s32 filenum) @@ -4128,9 +4154,21 @@ u32 file0f166ea8(u32 *filetableaddr) return 0; } -void fileLoad(u8 *dst, u32 allocationlen, u32 *romaddrptr, struct fileinfo *info) +void fileLoad(u8 *dst, u32 allocationlen, romptr_t *romaddrptr, struct fileinfo *info) { +#ifndef PLATFORM_N64 + // load the file first + const s32 filenum = (u32 *)romaddrptr - g_FileTable; + u32 romsize = 0; + u8 *filedata = romdataFileLoad(filenum, &romsize); + if (!filedata) { + return; + } + romaddrptr = (romptr_t *)&filedata; +#else u32 romsize = fileGetRomSizeByTableAddress(romaddrptr); +#endif + u8 buffer[5 * 1024]; if (allocationlen == 0) { @@ -4167,6 +4205,12 @@ void fileLoad(u8 *dst, u32 allocationlen, u32 *romaddrptr, struct fileinfo *info info->loadedsize = result; } } + +#ifndef PLATFORM_N64 + // byteswap/preprocess file according to g_LoadType right after inflating it + const u32 dstsize = allocationlen ? info->loadedsize : romsize; + romdataFilePreprocess(filenum, g_LoadType, dst, dstsize); +#endif } void filesInit(void) @@ -4181,7 +4225,9 @@ void filesInit(void) info->loadedsize = 0; info->allocsize = 0; +#ifdef PLATFORM_N64 fileGetRomSizeByTableAddress((u32 *)(g_FileTable + i)); +#endif if (g_FileTable); if (g_FileInfo); @@ -4195,7 +4241,16 @@ void fileLoadPartToAddr(u16 filenum, void *memaddr, s32 offset, u32 len) u32 stack[2]; if (fileGetRomSizeByTableAddress((u32 *)&g_FileTable[filenum])) { +#ifdef PLATFORM_N64 dmaExec(memaddr, (romptr_t) g_FileTable[filenum] + offset, len); +#else + const u8 *src = romdataFileGetData(filenum); + if (src) { + dmaExec(memaddr, (uintptr_t) src + offset, len); + } + // this intentionally does not execute romdataFilePreprocess, + // because bg files are loaded and inflated in parts +#endif } } @@ -4207,13 +4262,17 @@ u32 fileGetInflatedSize(s32 filenum) #if VERSION < VERSION_NTSC_1_0 char message[128]; #endif - u32 romaddr; + uintptr_t romaddr; romaddrptr = &g_FileTable[filenum]; if (1); +#ifdef PLATFORM_N64 romaddr = *romaddrptr; +#else + romaddr = (uintptr_t)romdataFileGetData(filenum); +#endif ptr = (u8 *) ((uintptr_t) &buffer[0x10] & ~0xf); if (romaddr == 0) { @@ -4272,6 +4331,9 @@ void *fileLoadToNew(s32 filenum, u32 method) void fileRemove(s32 filenum) { g_FileTable[filenum] = 0; +#ifndef PLATFORM_N64 + romdataFileFree(filenum); +#endif } void *fileLoadToAddr(s32 filenum, s32 method, u8 *ptr, u32 size) diff --git a/src/game/game_1531a0.c b/src/game/game_1531a0.c index 6efb98d3b..7f302a5d6 100644 --- a/src/game/game_1531a0.c +++ b/src/game/game_1531a0.c @@ -198,9 +198,9 @@ void text0f1531dc(bool arg0) void textLoadFont(u8 *romstart, u8 *romend, struct font **fontptr, struct fontchar **charsptr, bool monospace) { - extern u8 _fonthandelgothicsmSegmentRomStart; - extern u8 _fonthandelgothicxsSegmentRomStart; - extern u8 _fonthandelgothicmdSegmentRomStart; + extern u8 EXT_SEG _fonthandelgothicsmSegmentRomStart; + extern u8 EXT_SEG _fonthandelgothicxsSegmentRomStart; + extern u8 EXT_SEG _fonthandelgothicmdSegmentRomStart; u32 len; s32 maxwidth; @@ -213,9 +213,9 @@ void textLoadFont(u8 *romstart, u8 *romend, struct font **fontptr, struct fontch #if PAL // PAL has more characters in these fonts - if (romstart == &_fonthandelgothicsmSegmentRomStart - || romstart == &_fonthandelgothicxsSegmentRomStart - || romstart == &_fonthandelgothicmdSegmentRomStart) { + if (romstart == REF_SEG _fonthandelgothicsmSegmentRomStart + || romstart == REF_SEG _fonthandelgothicxsSegmentRomStart + || romstart == REF_SEG _fonthandelgothicmdSegmentRomStart) { numchars = 135; } #endif @@ -236,7 +236,7 @@ void textLoadFont(u8 *romstart, u8 *romend, struct font **fontptr, struct fontch } #if VERSION >= VERSION_JPN_FINAL - if (romstart == &_fonthandelgothicsmSegmentRomStart) { + if (romstart == REF_SEG _fonthandelgothicsmSegmentRomStart) { for (i = 0; i < NUMCHARS(); i++) { chars[i].baseline++; } @@ -264,9 +264,9 @@ void textLoadFont(u8 *romstart, u8 *romend, struct font **fontptr, struct fontch *charsptr = chars; #if PAL - if (romstart == &_fonthandelgothicsmSegmentRomStart - || romstart == &_fonthandelgothicxsSegmentRomStart - || romstart == &_fonthandelgothicmdSegmentRomStart) { + if (romstart == REF_SEG _fonthandelgothicsmSegmentRomStart + || romstart == REF_SEG _fonthandelgothicxsSegmentRomStart + || romstart == REF_SEG _fonthandelgothicmdSegmentRomStart) { // Increment the baseline of the pipe character. // It is suspected that the pipe character is used as a reference to set // the size for all other text, so changing this increases the line @@ -278,16 +278,16 @@ void textLoadFont(u8 *romstart, u8 *romend, struct font **fontptr, struct fontch void textReset(void) { - extern u8 _fontbankgothicSegmentRomStart, _fontbankgothicSegmentRomEnd; - extern u8 _fontzurichSegmentRomStart, _fontzurichSegmentRomEnd; - extern u8 _fonttahomaSegmentRomStart, _fonttahomaSegmentRomEnd; - extern u8 _fontnumericSegmentRomStart, _fontnumericSegmentRomEnd; - extern u8 _fonthandelgothicsmSegmentRomStart, _fonthandelgothicsmSegmentRomEnd; - extern u8 _fonthandelgothicxsSegmentRomStart, _fonthandelgothicxsSegmentRomEnd; - extern u8 _fonthandelgothicmdSegmentRomStart, _fonthandelgothicmdSegmentRomEnd; - extern u8 _fonthandelgothiclgSegmentRomStart, _fonthandelgothiclgSegmentRomEnd; - extern u8 _fontocramdSegmentRomStart, _fontocramdSegmentRomEnd; - extern u8 _fontocralgSegmentRomStart, _fontocralgSegmentRomEnd; + extern u8 EXT_SEG _fontbankgothicSegmentRomStart, EXT_SEG _fontbankgothicSegmentRomEnd; + extern u8 EXT_SEG _fontzurichSegmentRomStart, EXT_SEG _fontzurichSegmentRomEnd; + extern u8 EXT_SEG _fonttahomaSegmentRomStart, EXT_SEG _fonttahomaSegmentRomEnd; + extern u8 EXT_SEG _fontnumericSegmentRomStart, EXT_SEG _fontnumericSegmentRomEnd; + extern u8 EXT_SEG _fonthandelgothicsmSegmentRomStart, EXT_SEG _fonthandelgothicsmSegmentRomEnd; + extern u8 EXT_SEG _fonthandelgothicxsSegmentRomStart, EXT_SEG _fonthandelgothicxsSegmentRomEnd; + extern u8 EXT_SEG _fonthandelgothicmdSegmentRomStart, EXT_SEG _fonthandelgothicmdSegmentRomEnd; + extern u8 EXT_SEG _fonthandelgothiclgSegmentRomStart, EXT_SEG _fonthandelgothiclgSegmentRomEnd; + extern u8 EXT_SEG _fontocramdSegmentRomStart, EXT_SEG _fontocramdSegmentRomEnd; + extern u8 EXT_SEG _fontocralgSegmentRomStart, EXT_SEG _fontocralgSegmentRomEnd; var8007faec = 0; g_FontTahoma2 = NULL; @@ -322,17 +322,17 @@ void textReset(void) var8007fae8 = 0; if (g_Vars.stagenum == STAGE_TITLE) { - textLoadFont(&_fonthandelgothicsmSegmentRomStart, &_fonthandelgothicsmSegmentRomEnd, &g_FontHandelGothicSm, &g_CharsHandelGothicSm, false); - textLoadFont(&_fonthandelgothicmdSegmentRomStart, &_fonthandelgothicmdSegmentRomEnd, &g_FontHandelGothicMd, &g_CharsHandelGothicMd, false); - textLoadFont(&_fonthandelgothiclgSegmentRomStart, &_fonthandelgothiclgSegmentRomEnd, &g_FontHandelGothicLg, &g_CharsHandelGothicLg, false); + textLoadFont(REF_SEG _fonthandelgothicsmSegmentRomStart, REF_SEG _fonthandelgothicsmSegmentRomEnd, &g_FontHandelGothicSm, &g_CharsHandelGothicSm, false); + textLoadFont(REF_SEG _fonthandelgothicmdSegmentRomStart, REF_SEG _fonthandelgothicmdSegmentRomEnd, &g_FontHandelGothicMd, &g_CharsHandelGothicMd, false); + textLoadFont(REF_SEG _fonthandelgothiclgSegmentRomStart, REF_SEG _fonthandelgothiclgSegmentRomEnd, &g_FontHandelGothicLg, &g_CharsHandelGothicLg, false); } else if (g_Vars.stagenum == STAGE_CREDITS) { - textLoadFont(&_fonthandelgothicxsSegmentRomStart, &_fonthandelgothicxsSegmentRomEnd, &g_FontHandelGothicXs, &g_CharsHandelGothicXs, false); - textLoadFont(&_fonthandelgothicsmSegmentRomStart, &_fonthandelgothicsmSegmentRomEnd, &g_FontHandelGothicSm, &g_CharsHandelGothicSm, false); - textLoadFont(&_fonthandelgothicmdSegmentRomStart, &_fonthandelgothicmdSegmentRomEnd, &g_FontHandelGothicMd, &g_CharsHandelGothicMd, false); - textLoadFont(&_fonthandelgothiclgSegmentRomStart, &_fonthandelgothiclgSegmentRomEnd, &g_FontHandelGothicLg, &g_CharsHandelGothicLg, false); + textLoadFont(REF_SEG _fonthandelgothicxsSegmentRomStart, REF_SEG _fonthandelgothicxsSegmentRomEnd, &g_FontHandelGothicXs, &g_CharsHandelGothicXs, false); + textLoadFont(REF_SEG _fonthandelgothicsmSegmentRomStart, REF_SEG _fonthandelgothicsmSegmentRomEnd, &g_FontHandelGothicSm, &g_CharsHandelGothicSm, false); + textLoadFont(REF_SEG _fonthandelgothicmdSegmentRomStart, REF_SEG _fonthandelgothicmdSegmentRomEnd, &g_FontHandelGothicMd, &g_CharsHandelGothicMd, false); + textLoadFont(REF_SEG _fonthandelgothiclgSegmentRomStart, REF_SEG _fonthandelgothiclgSegmentRomEnd, &g_FontHandelGothicLg, &g_CharsHandelGothicLg, false); } else { #if VERSION >= VERSION_JPN_FINAL - textLoadFont(&_fontnumericSegmentRomStart, &_fontnumericSegmentRomEnd, &g_FontNumeric, &g_CharsNumeric, false); + textLoadFont(REF_SEG _fontnumericSegmentRomStart, REF_SEG _fontnumericSegmentRomEnd, &g_FontNumeric, &g_CharsNumeric, false); if (g_Vars.normmplayerisrunning) { if (IS4MB()) { @@ -347,40 +347,40 @@ void textReset(void) } } - textLoadFont(&_fonthandelgothicsmSegmentRomStart, &_fonthandelgothicsmSegmentRomEnd, &g_FontHandelGothicSm, &g_CharsHandelGothicSm, false); + textLoadFont(REF_SEG _fonthandelgothicsmSegmentRomStart, REF_SEG _fonthandelgothicsmSegmentRomEnd, &g_FontHandelGothicSm, &g_CharsHandelGothicSm, false); if (!g_Vars.normmplayerisrunning || IS8MB()) { - textLoadFont(&_fonthandelgothicmdSegmentRomStart, &_fonthandelgothicmdSegmentRomEnd, &g_FontHandelGothicMd, &g_CharsHandelGothicMd, false); + textLoadFont(REF_SEG _fonthandelgothicmdSegmentRomStart, REF_SEG _fonthandelgothicmdSegmentRomEnd, &g_FontHandelGothicMd, &g_CharsHandelGothicMd, false); } if (g_Vars.stagenum == STAGE_TEST_OLD) { - textLoadFont(&_fonthandelgothiclgSegmentRomStart, &_fonthandelgothiclgSegmentRomEnd, &g_FontHandelGothicLg, &g_CharsHandelGothicLg, false); + textLoadFont(REF_SEG _fonthandelgothiclgSegmentRomStart, REF_SEG _fonthandelgothiclgSegmentRomEnd, &g_FontHandelGothicLg, &g_CharsHandelGothicLg, false); } textLoadFont(&_fonthandelgothicxsSegmentRomStart, &_fonthandelgothicxsSegmentRomEnd, &g_FontHandelGothicXs, &g_CharsHandelGothicXs, false); #elif VERSION >= VERSION_PAL_BETA - textLoadFont(&_fontnumericSegmentRomStart, &_fontnumericSegmentRomEnd, &g_FontNumeric, &g_CharsNumeric, false); - textLoadFont(&_fonthandelgothicxsSegmentRomStart, &_fonthandelgothicxsSegmentRomEnd, &g_FontHandelGothicXs, &g_CharsHandelGothicXs, false); - textLoadFont(&_fonthandelgothicsmSegmentRomStart, &_fonthandelgothicsmSegmentRomEnd, &g_FontHandelGothicSm, &g_CharsHandelGothicSm, false); + textLoadFont(REF_SEG _fontnumericSegmentRomStart, REF_SEG _fontnumericSegmentRomEnd, &g_FontNumeric, &g_CharsNumeric, false); + textLoadFont(REF_SEG _fonthandelgothicxsSegmentRomStart, REF_SEG _fonthandelgothicxsSegmentRomEnd, &g_FontHandelGothicXs, &g_CharsHandelGothicXs, false); + textLoadFont(REF_SEG _fonthandelgothicsmSegmentRomStart, REF_SEG _fonthandelgothicsmSegmentRomEnd, &g_FontHandelGothicSm, &g_CharsHandelGothicSm, false); if (!g_Vars.normmplayerisrunning) { - textLoadFont(&_fonthandelgothicmdSegmentRomStart, &_fonthandelgothicmdSegmentRomEnd, &g_FontHandelGothicMd, &g_CharsHandelGothicMd, false); + textLoadFont(REF_SEG _fonthandelgothicmdSegmentRomStart, REF_SEG _fonthandelgothicmdSegmentRomEnd, &g_FontHandelGothicMd, &g_CharsHandelGothicMd, false); } if (g_Vars.stagenum == STAGE_TEST_OLD) { - textLoadFont(&_fonthandelgothiclgSegmentRomStart, &_fonthandelgothiclgSegmentRomEnd, &g_FontHandelGothicLg, &g_CharsHandelGothicLg, false); + textLoadFont(REF_SEG _fonthandelgothiclgSegmentRomStart, REF_SEG _fonthandelgothiclgSegmentRomEnd, &g_FontHandelGothicLg, &g_CharsHandelGothicLg, false); } #else // This unused GE font exists in NTSC but was removed in the PAL version - textLoadFont(&_fonttahomaSegmentRomStart, &_fonttahomaSegmentRomEnd, &g_FontTahoma2, &g_FontTahoma1, false); + textLoadFont(REF_SEG _fonttahomaSegmentRomStart, &_fonttahomaSegmentRomEnd, &g_FontTahoma2, &g_FontTahoma1, false); - textLoadFont(&_fontnumericSegmentRomStart, &_fontnumericSegmentRomEnd, &g_FontNumeric, &g_CharsNumeric, false); - textLoadFont(&_fonthandelgothicxsSegmentRomStart, &_fonthandelgothicxsSegmentRomEnd, &g_FontHandelGothicXs, &g_CharsHandelGothicXs, false); - textLoadFont(&_fonthandelgothicsmSegmentRomStart, &_fonthandelgothicsmSegmentRomEnd, &g_FontHandelGothicSm, &g_CharsHandelGothicSm, false); - textLoadFont(&_fonthandelgothicmdSegmentRomStart, &_fonthandelgothicmdSegmentRomEnd, &g_FontHandelGothicMd, &g_CharsHandelGothicMd, false); + textLoadFont(REF_SEG _fontnumericSegmentRomStart, REF_SEG _fontnumericSegmentRomEnd, &g_FontNumeric, &g_CharsNumeric, false); + textLoadFont(REF_SEG _fonthandelgothicxsSegmentRomStart, REF_SEG _fonthandelgothicxsSegmentRomEnd, &g_FontHandelGothicXs, &g_CharsHandelGothicXs, false); + textLoadFont(REF_SEG _fonthandelgothicsmSegmentRomStart, REF_SEG _fonthandelgothicsmSegmentRomEnd, &g_FontHandelGothicSm, &g_CharsHandelGothicSm, false); + textLoadFont(REF_SEG _fonthandelgothicmdSegmentRomStart, REF_SEG _fonthandelgothicmdSegmentRomEnd, &g_FontHandelGothicMd, &g_CharsHandelGothicMd, false); if (g_Vars.stagenum == STAGE_TEST_OLD) { - textLoadFont(&_fonthandelgothiclgSegmentRomStart, &_fonthandelgothiclgSegmentRomEnd, &g_FontHandelGothicLg, &g_CharsHandelGothicLg, false); + textLoadFont(REF_SEG _fonthandelgothiclgSegmentRomStart, REF_SEG _fonthandelgothiclgSegmentRomEnd, &g_FontHandelGothicLg, &g_CharsHandelGothicLg, false); } #endif } diff --git a/src/game/getitle.c b/src/game/getitle.c index ea6fbd136..ba2a399dc 100644 --- a/src/game/getitle.c +++ b/src/game/getitle.c @@ -38,6 +38,8 @@ u32 var80062494 = 0x00000001; s32 var80062498 = 0; u32 var8006249c = 0x00000000; +#ifdef PLATFORM_N64 + extern u8 var020043f8; extern u8 var02004468; extern u8 var02004700; @@ -138,13 +140,13 @@ Gfx *getitle0f0155f0(Gfx *gdl, s32 arg1, u8 arg2) return gdl; } -extern u8 _getitleSegmentRomStart; -extern u8 _getitleSegmentStart; -extern u8 _getitleSegmentEnd; +extern u8 EXT_SEG _getitleSegmentRomStart; +extern u8 EXT_SEG _getitleSegmentStart; +extern u8 EXT_SEG _getitleSegmentEnd; void getitleLoad(void *addr, u32 arg1) { - u32 len = (romptr_t)&_getitleSegmentEnd - (romptr_t)&_getitleSegmentStart; + u32 len = (romptr_t) REF_SEG _getitleSegmentEnd - (romptr_t) REF_SEG _getitleSegmentStart; var80062414 = 0; var8009cc8c = 880; @@ -152,7 +154,7 @@ void getitleLoad(void *addr, u32 arg1) var80062498 = 0; var8009cc90 = addr; - dmaExec(var8009cc90, (romptr_t) &_getitleSegmentRomStart, ALIGN64(len)); + dmaExec(var8009cc90, (romptr_t) REF_SEG _getitleSegmentRomStart, ALIGN64(len)); } Gfx *getitleRender(Gfx *gdl) @@ -211,3 +213,5 @@ bool getitle0f0160e8(void) { return (var80062414 ^ 2) == 0; } + +#endif // PLATFORM_N64 diff --git a/src/game/hudmsg.c b/src/game/hudmsg.c index f9ac6d6c6..f497c88ed 100644 --- a/src/game/hudmsg.c +++ b/src/game/hudmsg.c @@ -106,7 +106,11 @@ s32 hudmsgIsZoomRangeVisible(void) * with the return type we need, and link it to the same address as viGetHeight * via the linker config. */ +#ifdef PLATFORM_N64 extern s32 viGetHeight_hack(void); +#else +#define viGetHeight_hack viGetHeight +#endif Gfx *hudmsgRenderMissionTimer(Gfx *gdl, u32 alpha) { diff --git a/src/game/lang.c b/src/game/lang.c index 74c770403..5c39493fd 100644 --- a/src/game/lang.c +++ b/src/game/lang.c @@ -9,6 +9,7 @@ #include "lib/main.h" #include "data.h" #include "types.h" +#include "platform.h" /** * Officially, the NTSC versions are American English only, while the PAL @@ -213,9 +214,9 @@ u32 langGetLangBankIndexFromStagenum(s32 stagenum) return bank; } -extern u8 _fontjpnSegmentRomStart; -extern u8 _fontjpnsingleSegmentRomStart; -extern u8 _fontjpnmultiSegmentRomStart; +extern u8 EXT_SEG _fontjpnSegmentRomStart; +extern u8 EXT_SEG _fontjpnsingleSegmentRomStart; +extern u8 EXT_SEG _fontjpnmultiSegmentRomStart; struct jpncharpixels *langGetJpnCharPixels(s32 codepoint) { @@ -403,7 +404,7 @@ char *langGet(s32 textid) u32 addr; if (bank && bank[textindex]) { - addr = (uintptr_t)bank + bank[textindex]; + addr = (uintptr_t)bank + PD_BE32(bank[textindex]); } else { addr = 0; } diff --git a/src/game/propobj.c b/src/game/propobj.c index 198b84644..9d1e7ed17 100644 --- a/src/game/propobj.c +++ b/src/game/propobj.c @@ -4237,7 +4237,11 @@ void ammocrateTick(struct prop *prop) * function with the third argument and link it to the same address as * nbombCreateStorm via the linker config. */ +#ifdef PLATFORM_N64 void nbombCreateStorm_hack(struct coord *pos, struct prop *ownerprop, struct prop *nbombprop); +#else +#define nbombCreateStorm_hack(x, y, z) nbombCreateStorm(x, y) +#endif /** * Handles the following: @@ -14251,7 +14255,7 @@ void objApplyMomentum(struct defaultobj *obj, struct coord *speed, f32 rotation, } #if PIRACYCHECKS -extern u8 _blankSegmentRomStart; +extern u8 EXT_SEG _blankSegmentRomStart; /** * This function is called whenever a player exits a lift as well as on tick @@ -14294,7 +14298,7 @@ void piracyRestore(void) } // Copy the writeaddr/copylen pairs from ROM to the buffer - dmaExec(ptr, (romptr_t) &_blankSegmentRomStart, 0x40); + dmaExec(ptr, (romptr_t) REF_SEG _blankSegmentRomStart, 0x40); // Calculate what needs to be copied and where i = 0; @@ -14312,7 +14316,7 @@ void piracyRestore(void) // Copy it if (copylen != 0) { - dmaExec((void *) writeaddr, (romptr_t) &_blankSegmentRomStart + readoffset, copylen); + dmaExec((void *) writeaddr, (romptr_t) REF_SEG _blankSegmentRomStart + readoffset, copylen); } // Increment the index, so the next time the function is called diff --git a/src/game/texdecompress.c b/src/game/texdecompress.c index 734363920..055d52e21 100644 --- a/src/game/texdecompress.c +++ b/src/game/texdecompress.c @@ -2084,7 +2084,7 @@ void texLoadFromDisplayList(Gfx *gdl, struct texpool *pool, s32 arg2) } } -extern u8 _texturesdataSegmentRomStart; +extern u8 EXT_SEG _texturesdataSegmentRomStart; /** * Load and decompress a texture from ROM. @@ -2179,7 +2179,7 @@ void texLoad(s32 *updateword, struct texpool *pool, bool arg2) // Copy the compressed texture to RAM dmaExec(alignedcompbuffer, - (romptr_t) &_texturesdataSegmentRomStart + (thisoffset & 0xfffffff8), + (romptr_t) REF_SEG _texturesdataSegmentRomStart + (thisoffset & 0xfffffff8), ((u32) (nextoffset - thisoffset) + 0x1f) >> 4 << 4); compptr = (u8 *) alignedcompbuffer + (thisoffset & 7); @@ -2263,7 +2263,12 @@ void texLoad(s32 *updateword, struct texpool *pool, bool arg2) pool->rightpos->next = 0; if (tail != NULL) { - tail->next = (uintptr_t) pool->rightpos & 0xffffff; + tail->next = (uintptr_t) pool->rightpos + #ifdef PLATFORM_N64 + & 0xffffff; + #else + ; + #endif } else { pool->head = pool->rightpos; } diff --git a/src/game/texinit.c b/src/game/texinit.c index 4c0a11314..408d9c76e 100644 --- a/src/game/texinit.c +++ b/src/game/texinit.c @@ -8,12 +8,12 @@ void texInit(void) { - extern u8 _textureslistSegmentRomStart; - extern u8 _textureslistSegmentRomEnd; + extern u8 EXT_SEG _textureslistSegmentRomStart; + extern u8 EXT_SEG _textureslistSegmentRomEnd; - u32 len = ((&_textureslistSegmentRomEnd - &_textureslistSegmentRomStart) + 15) & -16; + u32 len = ((REF_SEG _textureslistSegmentRomEnd - REF_SEG _textureslistSegmentRomStart) + 15) & -16; g_Textures = mempAlloc(len, MEMPOOL_PERMANENT); - dmaExec(g_Textures, (romptr_t) &_textureslistSegmentRomStart, len); + dmaExec(g_Textures, (romptr_t) REF_SEG _textureslistSegmentRomStart, len); } diff --git a/src/game/texreset.c b/src/game/texreset.c index e53631099..d70547469 100644 --- a/src/game/texreset.c +++ b/src/game/texreset.c @@ -37,20 +37,26 @@ extern Gfx *g_TexGdl3; extern struct textureconfig *g_TexRedLinesConfigs; extern struct textureconfig *g_TexGroup11Configs; -extern u8 _textureconfigSegmentRomStart; -extern u8 _textureconfigSegmentStart; -extern u8 _textureconfigSegmentEnd; +extern u8 EXT_SEG _textureconfigSegmentRomStart; +extern u8 EXT_SEG _textureconfigSegmentStart; +extern u8 EXT_SEG _textureconfigSegmentEnd; void texReset(void) { s32 stage; +#ifdef PLATFORM_N64 u32 len = &_textureconfigSegmentEnd - &_textureconfigSegmentStart; +#endif s32 i; +#ifdef PLATFORM_N64 g_TextureConfigSegment = mempAlloc(len, MEMPOOL_STAGE); dmaExec(g_TextureConfigSegment, (romptr_t)&_textureconfigSegmentRomStart, len); - g_TexBase = (uintptr_t)g_TextureConfigSegment - ROM_SIZE * 1024 * 1024; +#else + g_TexBase = 0; +#endif + g_TexGdl1 = (Gfx *)(g_TexBase + (uintptr_t)g_TcGdl1); g_TexGdl2 = (Gfx *)(g_TexBase + (uintptr_t)g_TcGdl2); g_TexGdl3 = (Gfx *)(g_TexBase + (uintptr_t)g_TcGdl3); @@ -72,7 +78,12 @@ void texReset(void) g_TexGeneralConfigs = (struct textureconfig *)(g_TexBase + (uintptr_t)g_TcGeneralConfigs); g_TexRadarConfigs = (struct textureconfig *)(g_TexBase + (uintptr_t)g_TcRadarConfigs); +#ifdef PLATFORM_N64 g_TexNumConfigs = (len - (uintptr_t)&g_TcWallhitConfigs + ROM_SIZE * 1024 * 1024) / sizeof(struct textureconfig); +#else + // TODO: load this shit externally for fuck's sake + g_TexNumConfigs = 18 + 5 + 6 + 2 + 96 + 3 + 6 + 10 + 1 + 56 + 1; +#endif g_TexWords = mempAlloc(ALIGN16(g_TexNumConfigs * 4), MEMPOOL_STAGE); for (i = 0; i < g_TexNumConfigs; i++) { diff --git a/src/include/data.h b/src/include/data.h index 96be2ddc3..9c9e9126a 100644 --- a/src/include/data.h +++ b/src/include/data.h @@ -4,6 +4,14 @@ #include "constants.h" #include "types.h" +#ifdef PLATFORM_N64 +#define EXT_SEG +#define REF_SEG & +#else +#define EXT_SEG * +#define REF_SEG +#endif + #define bool s32 #define ubool u32 diff --git a/src/include/lib/dma.h b/src/include/lib/dma.h index 18b588c2f..9c2ae0049 100644 --- a/src/include/lib/dma.h +++ b/src/include/lib/dma.h @@ -5,11 +5,11 @@ #include "types.h" void dmaInit(void); -void dmaStart(void *memaddr, u32 romaddr, u32 len, bool priority); +void dmaStart(void *memaddr, romptr_t romaddr, u32 len, bool priority); void dmaCheckPiracy(void *memaddr, u32 len); void dmaWait(void); -void dmaExec(void *memaddr, u32 romaddr, u32 len); -void dmaExecHighPriority(void *memaddr, u32 romaddr, u32 len); -void *dmaExecWithAutoAlign(void *memaddr, u32 romaddr, u32 len); +void dmaExec(void *memaddr, romptr_t romaddr, u32 len); +void dmaExecHighPriority(void *memaddr, romptr_t romaddr, u32 len); +void *dmaExecWithAutoAlign(void *memaddr, romptr_t romaddr, u32 len); #endif diff --git a/src/include/lib/sched.h b/src/include/lib/sched.h index b81898a57..da4c54d95 100644 --- a/src/include/lib/sched.h +++ b/src/include/lib/sched.h @@ -23,5 +23,7 @@ void schedIncrementFrontArtifacts(void); void schedUpdatePendingArtifacts(void); void schedConsiderScreenshot(void); void schedSetCrashedUnexpectedly(bool enable); +void schedStartFrame(OSSched *sc); +void schedEndFrame(OSSched *sc); #endif diff --git a/src/include/lib/str.h b/src/include/lib/str.h index 5acd717c4..c80ba0dae 100644 --- a/src/include/lib/str.h +++ b/src/include/lib/str.h @@ -4,6 +4,7 @@ #include "data.h" #include "types.h" +#ifdef PLATFORM_N64 char *strcpy(char *dst, const char *src); char *strncpy(char *dst, const char *src, s32 len); char *strcat(char *dst, const char *src); @@ -14,5 +15,9 @@ s32 isdigit(char c); s32 isalpha(char c); s32 isspace(char c); s32 strtol(const char *src, const char **endptr, s32 base); +#else +#include +#include +#endif #endif diff --git a/src/include/math.h b/src/include/math.h index 721a3a4cf..2eaf5462f 100644 --- a/src/include/math.h +++ b/src/include/math.h @@ -1,6 +1,13 @@ #ifndef IN_MATH_H #define IN_MATH_H +#ifndef PLATFORM_N64 +#include_next +#undef M_PI +#undef M_TAU +#undef errno // fuck off +#endif + // @bug? #define M_BADPI 3.141092641f #define M_PI 3.141592741f diff --git a/src/include/platform.h b/src/include/platform.h new file mode 100644 index 000000000..b77f09e81 --- /dev/null +++ b/src/include/platform.h @@ -0,0 +1,75 @@ +#ifndef _IN_PLATFORM_H +#define _IN_PLATFORM_H + +// detect OS +#if defined(_WIN32) + #define PLATFORM_WIN32 1 +#else + // assume POSIX compatible + #define PLATFORM_POSIX 1 + #if defined(__linux__) + #define PLATFORM_LINUX 1 + #else // TODO + #error "Unknown platform." + #endif +#endif + +// detect arch +#if defined(__x86_64__) || defined(_M_X64) + #define PLATFORM_X86_64 1 + #define PLATFORM_64BIT 1 +#elif defined(__i386__) || defined(_X86_) || defined(_M_IX86) + #define PLATFORM_X86 1 +#else // TODO + #error "Unknown CPU arch." +#endif + +// detect endianness +#if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) + #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + #define PLATFORM_BIG_ENDIAN 1 + #else + #define PLATFORM_LITTLE_ENDIAN 1 + #endif +#elif __BIG_ENDIAN__ + #define PLATFORM_BIG_ENDIAN 1 +#else + #error "Could not determine endianness." +#endif + +// byteswap macros + +#ifdef __GNUC__ + #define PD_BSWAP16(x) __builtin_bswap16(x) + #define PD_BSWAP32(x) __builtin_bswap32(x) + #define PD_BSWAP64(x) __builtin_bswap64(x) +#else + #error "Implement PD_BSWAP macros for your compiler." +#endif + +#ifdef PLATFORM_BIG_ENDIAN + #define PD_BE16(x) (x) + #define PD_BE32(x) (x) + #define PD_BE64(x) (x) + #define PD_LE16(x) PD_BSWAP16(x) + #define PD_LE32(x) PD_BSWAP32(x) + #define PD_LE64(x) PD_BSWAP64(x) +#else + #define PD_BE16(x) PD_BSWAP16(x) + #define PD_BE32(x) PD_BSWAP32(x) + #define PD_BE64(x) PD_BSWAP64(x) + #define PD_LE16(x) (x) + #define PD_LE32(x) (x) + #define PD_LE64(x) (x) +#endif + +// TODO: use uintptr_t or something +#ifdef PLATFORM_64BIT + #define PD_BEPTR(x) PD_BE64(x) + #define PD_LEPTR(x) PD_LE64(x) +#else + #define PD_BEPTR(x) PD_BE32(x) + #define PD_LEPTR(x) PD_LE32(x) +#endif + +#endif diff --git a/src/include/stdarg.h b/src/include/stdarg.h index d39676633..fc651f9b4 100755 --- a/src/include/stdarg.h +++ b/src/include/stdarg.h @@ -1,5 +1,5 @@ -#ifndef STDARG_H -#define STDARG_H +#ifndef N64_STDARG_H +#define N64_STDARG_H // When not building with IDO, use the builtin vaarg macros for portability. #ifndef __sgi diff --git a/src/include/stdlib.h b/src/include/stdlib.h index 6fbb6ce2f..2a00a8212 100755 --- a/src/include/stdlib.h +++ b/src/include/stdlib.h @@ -1,5 +1,12 @@ -#ifndef __STDLIB_H__ -#define __STDLIB_H__ +#ifndef __N64_STDLIB_H__ +#define __N64_STDLIB_H__ + +#ifndef PLATFORM_N64 + +#include_next +#undef errno // fuck off + +#else // PLATFORM_N64 #ifndef NULL #define NULL 0 @@ -18,4 +25,7 @@ typedef struct ldiv_t lldiv_t lldiv(long long num, long long denom); ldiv_t ldiv(long num, long denom); -#endif /* !__STDLIB_H__ */ + +#endif // PLATFORM_N64 + +#endif /* !__N64_STDLIB_H__ */ diff --git a/src/include/string.h b/src/include/string.h index 9c809db00..ed13c9352 100755 --- a/src/include/string.h +++ b/src/include/string.h @@ -1,5 +1,8 @@ -#ifndef __STRING_H__ -#define __STRING_H__ +#ifndef __N64_STRING_H__ +#define __N64_STRING_H__ + +#ifdef PLATFORM_N64 + #ifdef __cplusplus extern "C" { #endif @@ -52,4 +55,12 @@ extern size_t strlen(const char *); #ifdef __cplusplus } #endif -#endif /* !__STRING_H__ */ + +#else + +#include_next +#undef errno // fuck off + +#endif + +#endif /* !__N64_STRING_H__ */ diff --git a/src/include/types.h b/src/include/types.h index b2a522a4c..cea8ef6f3 100644 --- a/src/include/types.h +++ b/src/include/types.h @@ -11,9 +11,16 @@ #define bool s32 #define ubool u32 + +#ifdef PLATFORM_N64 #define intptr_t s32 #define uintptr_t u32 #define romptr_t u32 +#else +#include +#undef errno // fuck off +#define romptr_t uintptr_t +#endif typedef s32 PakErr1; typedef s32 PakErr2; @@ -6239,7 +6246,11 @@ struct tex { /*0x0c*/ u32 lutmodeindex : 2; /*0x0c*/ u32 unk0c_02 : 1; /*0x0c*/ u32 unk0c_03 : 1; +#ifdef PLATFORM_N64 /*0x0c*/ u32 next : 24; +#else + /*0x0c*/ uintptr_t next; +#endif }; struct texcacheitem { diff --git a/src/lib/anim.c b/src/lib/anim.c index 3873e966f..025eb4866 100644 --- a/src/lib/anim.c +++ b/src/lib/anim.c @@ -39,17 +39,17 @@ s32 g_AnimMaxHeaderLength = 608; bool g_AnimHostEnabled = false; u8 *g_AnimHostSegment = NULL; -extern u8 _animationsTableRomStart; -extern u8 _animationsTableRomEnd; +extern u8 EXT_SEG _animationsTableRomStart; +extern u8 EXT_SEG _animationsTableRomEnd; void animsInit(void) { s32 i; u32 *ptr; - u32 tablelen = ALIGN64(&_animationsTableRomEnd - &_animationsTableRomStart); + u32 tablelen = ALIGN64(REF_SEG _animationsTableRomEnd - REF_SEG _animationsTableRomStart); ptr = mempAlloc(tablelen, MEMPOOL_PERMANENT); - dmaExec(ptr, (romptr_t) &_animationsTableRomStart, tablelen); + dmaExec(ptr, (romptr_t) REF_SEG _animationsTableRomStart, tablelen); g_NumAnimations = g_NumRomAnimations = ptr[0]; g_Anims = g_RomAnims = (struct animtableentry *)&ptr[1]; @@ -131,7 +131,7 @@ s32 animGetNumAnimations(void) return g_NumAnimations; } -extern u8 _animationsSegmentRomStart; +extern u8 EXT_SEG _animationsSegmentRomStart; u8 *animDma(u8 *dst, u32 segoffset, u32 len) { @@ -140,7 +140,7 @@ u8 *animDma(u8 *dst, u32 segoffset, u32 len) return dst; } - return dmaExecWithAutoAlign(dst, (romptr_t) &_animationsSegmentRomStart + segoffset, len); + return dmaExecWithAutoAlign(dst, (romptr_t) REF_SEG _animationsSegmentRomStart + segoffset, len); } /** diff --git a/src/lib/audiomgr.c b/src/lib/audiomgr.c index 382ee38e0..8dc79c4a7 100644 --- a/src/lib/audiomgr.c +++ b/src/lib/audiomgr.c @@ -283,12 +283,14 @@ void amgrHandleFrameMsg(AudioInfo *info, AudioInfo *previnfo) g_AmgrCurrentCmdList->flags = OS_SC_NEEDS_RSP; g_AmgrCurrentCmdList->list.t.type = M_AUDTASK; g_AmgrCurrentCmdList->list.t.flags = 0; +#ifdef PLATFORM_N64 g_AmgrCurrentCmdList->list.t.ucode_boot = (u64 *) &rspbootTextStart; g_AmgrCurrentCmdList->list.t.ucode_boot_size = (uintptr_t) &rspbootTextEnd - (uintptr_t) &rspbootTextStart; g_AmgrCurrentCmdList->list.t.ucode = (u64 *) &aspTextStart; g_AmgrCurrentCmdList->list.t.ucode_data = (u64 *) &aspDataStart; g_AmgrCurrentCmdList->list.t.ucode_size = SP_UCODE_SIZE; g_AmgrCurrentCmdList->list.t.ucode_data_size = SP_UCODE_DATA_SIZE; +#endif g_AmgrCurrentCmdList->list.t.data_ptr = (u64 *) datastart; g_AmgrCurrentCmdList->list.t.data_size = (cmd - datastart) * sizeof(Acmd); g_AmgrCurrentCmdList->list.t.yield_data_ptr = NULL; diff --git a/src/lib/dma.c b/src/lib/dma.c index e21605c3a..bfc5ef4a7 100644 --- a/src/lib/dma.c +++ b/src/lib/dma.c @@ -28,8 +28,9 @@ void dmaInit(void) osCreateMesgQueue(&g_DmaMesgQueue, g_DmaMesgs, ARRAYCOUNT(g_DmaMesgs)); } -void dmaStart(void *memaddr, u32 romaddr, u32 len, bool priority) +void dmaStart(void *memaddr, romptr_t romaddr, u32 len, bool priority) { +#ifdef PLATFORM_N64 u32 numiterations; u32 remainder; s32 i; @@ -73,6 +74,9 @@ void dmaStart(void *memaddr, u32 romaddr, u32 len, bool priority) osPiStartDma(&g_DmaIoMsgs[i], priority, 0, romaddr, memaddr, remainder, &g_DmaMesgQueue); } +#else // PLATFORM_N64 + bcopy((const void *)romaddr, memaddr, len); +#endif // PLATFORM_N64 } #if VERSION >= VERSION_NTSC_1_0 @@ -121,6 +125,7 @@ void dmaCheckPiracy(void *memaddr, u32 len) void dmaWait(void) { +#ifdef PLATFORM_N64 u32 stack; OSIoMesg *msg; s32 i; @@ -137,9 +142,10 @@ void dmaWait(void) g_DmaSlotsBusy[i] = false; g_DmaNumSlotsBusy--; } +#endif } -void dmaExec(void *memaddr, u32 romaddr, u32 len) +void dmaExec(void *memaddr, romptr_t romaddr, u32 len) { dmaStart(memaddr, romaddr, len, false); dmaWait(); @@ -148,7 +154,7 @@ void dmaExec(void *memaddr, u32 romaddr, u32 len) #endif } -void dmaExecHighPriority(void *memaddr, u32 romaddr, u32 len) +void dmaExecHighPriority(void *memaddr, romptr_t romaddr, u32 len) { dmaStart(memaddr, romaddr, len, true); dmaWait(); @@ -172,7 +178,7 @@ void dmaExecHighPriority(void *memaddr, u32 romaddr, u32 len) * If a length of zero is passed, no DMA is done. This can be used to retrieve * the memory address that would have been returned. */ -void *dmaExecWithAutoAlign(void *memaddr, u32 romaddr, u32 len) +void *dmaExecWithAutoAlign(void *memaddr, romptr_t romaddr, u32 len) { u32 alignedrom = ALIGN2(romaddr); u32 alignedmem = ALIGN16((uintptr_t) memaddr); diff --git a/src/lib/main.c b/src/lib/main.c index be7d63a73..2d776e661 100644 --- a/src/lib/main.c +++ b/src/lib/main.c @@ -305,11 +305,11 @@ Gfx var8005dcf0[] = { s32 g_MainIsBooting = 1; -extern u8 _accessingpakSegmentRomStart; -extern u8 _accessingpakSegmentRomEnd; -extern u8 _copyrightSegmentRomStart; -extern u8 _copyrightSegmentRomEnd; -extern u8 _bssSegmentEnd; +extern u8 EXT_SEG _accessingpakSegmentRomStart; +extern u8 EXT_SEG _accessingpakSegmentRomEnd; +extern u8 EXT_SEG _copyrightSegmentRomStart; +extern u8 EXT_SEG _copyrightSegmentRomEnd; +extern u8 EXT_SEG _bssSegmentEnd; /** * Initialise various subsystems, display the copyright or accessing pak texture, @@ -429,9 +429,9 @@ void mainInit(void) // DMA the compressed texture from the ROM to the framebuffer. // It's using the framebuffer as a temporary data buffer. if (g_DoBootPakMenu) { - dmaExec(fb, (romptr_t) &_accessingpakSegmentRomStart, &_accessingpakSegmentRomEnd - &_accessingpakSegmentRomStart); + dmaExec(fb, (romptr_t) REF_SEG _accessingpakSegmentRomStart, REF_SEG _accessingpakSegmentRomEnd - REF_SEG _accessingpakSegmentRomStart); } else { - dmaExec(fb, (romptr_t) &_copyrightSegmentRomStart, &_copyrightSegmentRomEnd - &_copyrightSegmentRomStart); + dmaExec(fb, (romptr_t) REF_SEG _copyrightSegmentRomStart, REF_SEG _copyrightSegmentRomEnd - REF_SEG _copyrightSegmentRomStart); } // This is required for a match @@ -630,7 +630,7 @@ void mainInit(void) argSetString(" -ml0 -me0 -mgfx100 -mvtx50 -mt700 -ma400"); } - start = (u8 *) PHYS_TO_K0(osVirtualToPhysical(&_bssSegmentEnd)); + start = (u8 *) PHYS_TO_K0(osVirtualToPhysical(REF_SEG _bssSegmentEnd)); if (g_VmMarker); mempSetHeap(start, g_VmMarker - start); diff --git a/src/lib/memp.c b/src/lib/memp.c index 2340c1859..99b8bf476 100644 --- a/src/lib/memp.c +++ b/src/lib/memp.c @@ -43,6 +43,11 @@ * memp memory is to load a new stage which wipes the stage pool. */ +#ifndef PLATFORM_N64 +// TODO: set this in a config or something +#define MEMP_EXPANSION_POOL_SIZE (8 * 1024 * 1024) +#endif + struct memorypool { /*0x00*/ u8 *start; /*0x04*/ u8 *leftpos; @@ -82,6 +87,15 @@ void mempSetHeap(u8 *heapstart, u32 heaplen) g_MempExpansionPools[i].prevallocation = 0; } +#ifndef PLATFORM_N64 + // separate the heap space into onboard and expansion + u32 expansionlen = 0; + if (heaplen > MEMP_EXPANSION_POOL_SIZE) { + heaplen -= MEMP_EXPANSION_POOL_SIZE; + expansionlen = MEMP_EXPANSION_POOL_SIZE; + } +#endif + g_MempOnboardPools[MEMPOOL_0].start = heapstart; g_MempOnboardPools[MEMPOOL_0].rightpos = heapstart + heaplen; g_MempOnboardPools[MEMPOOL_PERMANENT].start = heapstart; @@ -89,6 +103,7 @@ void mempSetHeap(u8 *heapstart, u32 heaplen) g_MempOnboardPools[MEMPOOL_STAGE].start = heapstart; g_MempOnboardPools[MEMPOOL_STAGE].rightpos = heapstart + heaplen; +#ifdef PLATFORM_N64 // If 8MB, reserve the entire expansion pak for the stage pool #if VERSION >= VERSION_NTSC_1_0 extraend = (u8 *) K0BASE + bootGetMemSize(); @@ -105,6 +120,12 @@ void mempSetHeap(u8 *heapstart, u32 heaplen) g_MempExpansionPools[MEMPOOL_STAGE].start = (u8 *) K0BASE + 4 * 1024 * 1024; g_MempExpansionPools[MEMPOOL_STAGE].rightpos = extraend; } +#else + if (expansionlen) { + g_MempExpansionPools[MEMPOOL_STAGE].start = heapstart + heaplen; + g_MempExpansionPools[MEMPOOL_STAGE].rightpos = heapstart + heaplen + expansionlen; + } +#endif for (i = 0; i < ARRAYCOUNT(g_MempOnboardPools); i++) { g_MempOnboardPools[i].end = g_MempOnboardPools[i].rightpos; diff --git a/src/lib/mp3/util_c.c b/src/lib/mp3/util_c.c new file mode 100644 index 000000000..48dc42d5d --- /dev/null +++ b/src/lib/mp3/util_c.c @@ -0,0 +1,28 @@ +#include +#include "internal.h" +#include "mp3.h" + +s32 mp3utilGetBits(u8 *buffer, s32 *count, s32 numbits) +{ + return 0; +} + +s32 mp3util000462f8(u8 *arg0, s32 *arg1, s32 arg2, s32 arg3, s32 arg4, s32 arg5, s16 **arg6, u8 **arg7) +{ + return 0; +} + +s32 mp3util000464a8(u8 *arg0, s32 *arg1, s32 arg2, s32 arg3, s32 arg4, s16 **arg5, u8 **arg6) +{ + return 0; +} + +void func00046650(struct asistream_4f64 *arg0, s32 arg1, struct asistream_4f64 *arg2, struct asistream_4f64 *arg3, void *arg4) +{ + +} + +void func00047550(struct asistream_4f64 *arg0, s32 arg1, struct asistream_4f64 *arg2, struct asistream_4f64 *arg3) +{ + +} diff --git a/src/lib/mtx_c.c b/src/lib/mtx_c.c index 3a9f5ae59..a1cabebcb 100644 --- a/src/lib/mtx_c.c +++ b/src/lib/mtx_c.c @@ -298,6 +298,7 @@ void mtx00015f88(f32 mult, Mtxf *mtx) u32 mtxGetObfuscatedRomBase(void) { +#ifdef PLATFORM_N64 u32 value; osRecvMesg(&__osPiAccessQueue, NULL, OS_MESG_BLOCK * 0x10000); @@ -312,6 +313,9 @@ u32 mtxGetObfuscatedRomBase(void) osSendMesg(&__osPiAccessQueue, 0, 0); return value; +#else + return 0; +#endif } void mtxF2L(Mtxf *src, Mtxf *dst) diff --git a/src/lib/rdp.c b/src/lib/rdp.c index bebdd8585..f5c05f614 100644 --- a/src/lib/rdp.c +++ b/src/lib/rdp.c @@ -83,6 +83,7 @@ void rdpCreateTask(Gfx *gdlstart, Gfx *gdlend, u32 arg2, s32 msg) sctask = &g_RdpCurTask->sctask; task = &sctask->list; +#ifdef PLATFORM_N64 task->t.ucode_boot = (u64 *) rspbootTextStart; task->t.ucode_boot_size = (uintptr_t) rspbootTextEnd - (uintptr_t) rspbootTextStart; @@ -90,6 +91,7 @@ void rdpCreateTask(Gfx *gdlstart, Gfx *gdlend, u32 arg2, s32 msg) task->t.ucode = (u64 *) &gspTextStart; task->t.ucode_data = (u64 *) &gspDataStart; +#endif task->t.output_buff = (u64 *)g_RdpOutBufferStart; task->t.output_buff_size = (u64 *)g_RdpOutBufferEnd; task->t.data_ptr = (u64 *) gdlstart; diff --git a/src/lib/rmon.c b/src/lib/rmon.c index 0d149bd24..5e9019848 100644 --- a/src/lib/rmon.c +++ b/src/lib/rmon.c @@ -1,3 +1,4 @@ +#ifdef PLATFORM_N64 #include #include #include "constants.h" @@ -6,6 +7,11 @@ #include "lib/libc/xprintf.h" #include "data.h" #include "types.h" +#else +#include +#include +#include "types.h" +#endif void rmonproc() { @@ -69,5 +75,11 @@ void rmonPrintf(const char *format, ...) va_list ap; va_start(ap, format); +#ifdef PLATFORM_N64 _Printf(rmonProut, NULL, format, ap); +#else + fprintf(stderr, "rmonPrintf: "); + vfprintf(stderr, format, ap); + va_end(ap); +#endif } diff --git a/src/lib/rzip_c.c b/src/lib/rzip_c.c new file mode 100644 index 000000000..925b5c950 --- /dev/null +++ b/src/lib/rzip_c.c @@ -0,0 +1,100 @@ +// see https://github.com/n64decomp/007/blob/master/tools/mktex/src/libpdtex/reader.c +// and https://github.com/doomhack/perfect_dark/blob/master/src/lib/rzip.c + +#include + +// OSContPad has a field called errno because fuck you +#undef errno + +#include "lib/rzip.h" + +void *var80091558; // g_RzipUnused + +bool rzipIs1172(void *buffer) +{ + const u8* src = buffer; + return (src[0] == 0x11 && src[1] == 0x72); +} + +bool rzipIs1173(void *buffer) +{ + const u8* src = buffer; + return (src[0] == 0x11 && src[1] == 0x73); +} + +static inline s32 rzipInflate1172(z_stream *strm, u8 *src, void *dst) +{ + strm->avail_in = 0x2000; + strm->next_in = src; + + do { + strm->avail_out = 0x2000; + strm->next_out = dst; + if (inflate(strm, Z_FINISH) == Z_STREAM_ERROR) { + rmonPrintf("rzipInflate1172: Z_STREAM_ERROR\n"); + return 0; + } + } while (strm->avail_out == 0); + + return strm->total_out; +} + +static inline s32 rzipInflate1173(z_stream *strm, u8 *src, void *dst, u32 dstLen) +{ + strm->avail_in = -1; // compressed size unknown + strm->next_in = src; + strm->avail_out = dstLen; + strm->next_out = dst; + + if (inflate(strm, Z_SYNC_FLUSH) == Z_STREAM_ERROR) { + rmonPrintf("rzipInflate1173: Z_STREAM_ERROR\n"); + return 0; + } + + return strm->total_out; +} + +s32 rzipInflate(void *srcp, void *dst, void *scratch) +{ + s32 ret = 0; + u8 *src = srcp; + z_stream strm = { 0 }; + + ret = inflateInit2(&strm, -15); + if (ret != Z_OK) { + rmonPrintf("rzipInflate: inflateInit2 failed: %d\n", ret); + return 0; + } + + if (rzipIs1173(src)) { + // 1173, we know the uncompressed length + const u32 dstLen = ((u32)src[2] << 16) | ((u32)src[3] << 8) | (u32)src[4]; + ret = rzipInflate1173(&strm, src + 5, dst, dstLen); + } else if (rzipIs1172(src)) { + // 1172, uncompressed length unknown + ret = rzipInflate1172(&strm, src + 2, dst); + } else { + rmonPrintf("rzipInflate: input not in any known rare zip format\n"); + ret = 0; + } + + inflateEnd(&strm); + + if (ret) { + var80091558 = strm.next_in; + return strm.total_out; + } else { + return 0; + } +} + +u32 rzipInit(void) +{ + // this builds tables in the original assembly version, we don't need that + return 0; +} + +void *rzipGetSomething(void) +{ + return var80091558; +} diff --git a/src/lib/snd.c b/src/lib/snd.c index edca566ea..4efc893ef 100644 --- a/src/lib/snd.c +++ b/src/lib/snd.c @@ -843,12 +843,12 @@ s16 var8005ecf8[] = { -1, }; -extern u8 _sfxctlSegmentRomStart; -extern u8 _sfxtblSegmentRomStart; -extern u8 _seqctlSegmentRomStart; -extern u8 _seqctlSegmentRomEnd; -extern u8 _seqtblSegmentRomStart; -extern u8 _sequencesSegmentRomStart; +extern u8 EXT_SEG _sfxctlSegmentRomStart; +extern u8 EXT_SEG _sfxtblSegmentRomStart; +extern u8 EXT_SEG _seqctlSegmentRomStart; +extern u8 EXT_SEG _seqctlSegmentRomEnd; +extern u8 EXT_SEG _seqtblSegmentRomStart; +extern u8 EXT_SEG _sequencesSegmentRomStart; bool sndIsPlayingMp3(void) { @@ -933,19 +933,19 @@ void sndLoadSfxCtl(void) // Load the first 256 bytes of the ctl file. size = 256; - dmaExec(buffer, (romptr_t) &_sfxctlSegmentRomStart, size); + dmaExec(buffer, (romptr_t) REF_SEG _sfxctlSegmentRomStart, size); // Get the ROM address of the first (and only) bank, // then load the first 256 bytes of the bank. file = (ALBankFile *) buffer; - romaddr = (romptr_t)&_sfxctlSegmentRomStart; + romaddr = (romptr_t) REF_SEG _sfxctlSegmentRomStart; romaddr += (u32)file->bankArray[0]; dmaExec(buffer, romaddr, size); // Get the ROM address of the first (and only) instrument, // then load the first 256 bytes of the instrument. bank = (ALBank *) buffer; - romaddr = (romptr_t)&_sfxctlSegmentRomStart; + romaddr = (romptr_t) REF_SEG _sfxctlSegmentRomStart; romaddr += (u32)bank->instArray[0]; dmaExec(buffer, romaddr, size); @@ -966,7 +966,7 @@ void sndLoadSfxCtl(void) // Convert ctl-local offsets to ROM offsets for (i = 0; i < g_NumSounds; i++) { - g_ALSoundRomOffsets[i] += (romptr_t) &_sfxctlSegmentRomStart; + g_ALSoundRomOffsets[i] += (romptr_t) REF_SEG _sfxctlSegmentRomStart; } // Allocate and initialise cache @@ -1011,7 +1011,7 @@ ALEnvelope *sndLoadEnvelope(u32 offset, u16 cacheindex) s32 sum1; s32 sum2; - offset += (romptr_t)&_sfxctlSegmentRomStart; + offset += (romptr_t) REF_SEG _sfxctlSegmentRomStart; do { dmaExecHighPriority(s2, offset, 0x40); @@ -1034,7 +1034,7 @@ ALEnvelope *sndLoadEnvelope(u32 offset, u16 cacheindex) u8 sp5f[0x50]; ALEnvelope *s1 = (ALEnvelope *)ALIGN16((uintptr_t)sp5f); - offset += (romptr_t)&_sfxctlSegmentRomStart; + offset += (romptr_t) REF_SEG _sfxctlSegmentRomStart; dmaExecHighPriority(s1, offset, 0x40); #endif @@ -1058,7 +1058,7 @@ ALKeyMap *sndLoadKeymap(u32 offset, u16 cacheindex) s32 sum1; s32 sum2; - offset += (romptr_t)&_sfxctlSegmentRomStart; + offset += (romptr_t) REF_SEG _sfxctlSegmentRomStart; do { dmaExecHighPriority(s2, offset, 0x40); @@ -1081,7 +1081,7 @@ ALKeyMap *sndLoadKeymap(u32 offset, u16 cacheindex) u8 sp5f[0x50]; ALKeyMap *s1 = (ALKeyMap *)ALIGN16((uintptr_t)sp5f); - offset += (romptr_t)&_sfxctlSegmentRomStart; + offset += (romptr_t) REF_SEG _sfxctlSegmentRomStart; dmaExecHighPriority(s1, offset, 0x40); #endif @@ -1105,7 +1105,7 @@ ALADPCMBook *sndLoadAdpcmBook(u32 offset, u16 cacheindex) s32 sum1; s32 sum2; - offset += (romptr_t)&_sfxctlSegmentRomStart; + offset += (romptr_t) REF_SEG _sfxctlSegmentRomStart; do { dmaExecHighPriority(s2, offset, 0x140); @@ -1128,7 +1128,7 @@ ALADPCMBook *sndLoadAdpcmBook(u32 offset, u16 cacheindex) u8 sp5f[0x150]; ALADPCMBook *s1 = (ALADPCMBook *)ALIGN16((uintptr_t)sp5f); - offset += (romptr_t)&_sfxctlSegmentRomStart; + offset += (romptr_t) REF_SEG _sfxctlSegmentRomStart; dmaExecHighPriority(s1, offset, 0x140); #endif @@ -1156,7 +1156,7 @@ ALADPCMloop *sndLoadAdpcmLoop(u32 offset, u16 cacheindex) return NULL; } - offset += (romptr_t)&_sfxctlSegmentRomStart; + offset += (romptr_t) REF_SEG _sfxctlSegmentRomStart; do { dmaExecHighPriority(s2, offset, 0x40); @@ -1183,7 +1183,7 @@ ALADPCMloop *sndLoadAdpcmLoop(u32 offset, u16 cacheindex) return NULL; } - offset += (romptr_t)&_sfxctlSegmentRomStart; + offset += (romptr_t) REF_SEG _sfxctlSegmentRomStart; dmaExecHighPriority(s1, offset, 0x40); #endif @@ -1208,7 +1208,7 @@ ALWaveTable *sndLoadWavetable(u32 offset, u16 cacheindex) s32 sum2; ALWaveTable *tmp; - offset += (romptr_t)&_sfxctlSegmentRomStart; + offset += (romptr_t) REF_SEG _sfxctlSegmentRomStart; do { dmaExecHighPriority(s2, offset, 0x40); @@ -1232,7 +1232,7 @@ ALWaveTable *sndLoadWavetable(u32 offset, u16 cacheindex) ALWaveTable *s1 = (ALWaveTable *)ALIGN16((uintptr_t)sp5f); ALWaveTable *tmp; - offset += (romptr_t)&_sfxctlSegmentRomStart; + offset += (romptr_t) REF_SEG _sfxctlSegmentRomStart; dmaExecHighPriority(s1, offset, 0x40); #endif @@ -1241,7 +1241,7 @@ ALWaveTable *sndLoadWavetable(u32 offset, u16 cacheindex) *tmp = *s1; - tmp->base += (romptr_t)&_sfxtblSegmentRomStart; + tmp->base += (romptr_t) REF_SEG _sfxtblSegmentRomStart; if (tmp->type == AL_ADPCM_WAVE) { tmp->waveInfo.adpcmWave.book = sndLoadAdpcmBook((uintptr_t)tmp->waveInfo.adpcmWave.book, cacheindex); @@ -1453,7 +1453,7 @@ void sndInit(void) if (!g_SndDisabled) { // Allocate memory for the audio heap, // clear it and give it to the audio library - u32 len = &_seqctlSegmentRomEnd - &_seqctlSegmentRomStart; + u32 len = REF_SEG _seqctlSegmentRomEnd - REF_SEG _seqctlSegmentRomStart; u8 *ptr = mempAlloc(heaplen, MEMPOOL_PERMANENT); s32 i; u8 *heapstart = ptr; @@ -1478,25 +1478,25 @@ void sndInit(void) // Load seq.ctl var80095200 = 0xffffffff; bankfile = alHeapAlloc(&g_SndHeap, 1, len); - dmaExec(bankfile, (romptr_t) &_seqctlSegmentRomStart, len); + dmaExec(bankfile, (romptr_t) REF_SEG _seqctlSegmentRomStart, len); // Load seq.tbl - alBnkfNew(bankfile, &_seqtblSegmentRomStart); + alBnkfNew(bankfile, REF_SEG _seqtblSegmentRomStart); // Load the sequences table. To do this, load the header of the // sequences segment and read the number of sequences, then allocate // enough space for the table and load it. var80095204 = bankfile->bankArray[0]; g_SeqTable = alHeapDBAlloc(0, 0, &g_SndHeap, 1, 0x10); - dmaExec(g_SeqTable, (romptr_t) &_sequencesSegmentRomStart, 0x10); + dmaExec(g_SeqTable, (romptr_t) REF_SEG _sequencesSegmentRomStart, 0x10); len = g_SeqTable->count * sizeof(struct seqtableentry) + 4; g_SeqTable = alHeapDBAlloc(0, 0, &g_SndHeap, 1, len); - dmaExec(g_SeqTable, (romptr_t) &_sequencesSegmentRomStart, (len + 0xf) & 0xfffffff0); + dmaExec(g_SeqTable, (romptr_t) REF_SEG _sequencesSegmentRomStart, (len + 0xf) & 0xfffffff0); // Promote segment-relative offsets to ROM addresses for (i = 0; i < g_SeqTable->count; i++) { - g_SeqTable->entries[i].romaddr += (romptr_t) &_sequencesSegmentRomStart; + g_SeqTable->entries[i].romaddr += (romptr_t) REF_SEG _sequencesSegmentRomStart; } synconfig.maxVVoices = 44; diff --git a/src/lib/vminit.c b/src/lib/vminit.c index 86269d6b0..f7bdb7047 100644 --- a/src/lib/vminit.c +++ b/src/lib/vminit.c @@ -95,9 +95,9 @@ s32 g_VmNumPages = 0; u32 var8005cf88 = 0; -extern u8 _gameSegmentStart; -extern u8 _gameSegmentEnd; -extern u8 _gamezipSegmentRomStart; +extern u8 EXT_SEG _gameSegmentStart; +extern u8 EXT_SEG _gameSegmentEnd; +extern u8 EXT_SEG _gamezipSegmentRomStart; extern u32 g_VmPhysicalSlots; extern u32 *g_VmVirtualToPhysicalTable; @@ -207,24 +207,24 @@ void vmInit(void) { g_Is4Mb = true; - g_VmNumPages = (s32)((&_gameSegmentEnd - &_gameSegmentStart) + (VM_PAGE_SIZE - 1)) / VM_PAGE_SIZE; + g_VmNumPages = (s32)((REF_SEG _gameSegmentEnd - REF_SEG _gameSegmentStart) + (VM_PAGE_SIZE - 1)) / VM_PAGE_SIZE; g_VmRamEnd = 0x7f000000 + VM_PAGE_SIZE * g_VmNumPages; g_VmVirtualToPhysicalTableEnd = STACK_START; gameseg = (u8 *) (STACK_START - g_VmNumPages * 8); g_VmVirtualToPhysicalTable = (u32 *) gameseg; - numpages = (u32) (((uintptr_t) &_gameSegmentEnd - (uintptr_t) &_gameSegmentStart) + (VM_PAGE_SIZE - 1)) / VM_PAGE_SIZE; + numpages = (u32) (((uintptr_t) REF_SEG _gameSegmentEnd - (uintptr_t) REF_SEG _gameSegmentStart) + (VM_PAGE_SIZE - 1)) / VM_PAGE_SIZE; numentries = numpages + 1; g_VmZipTable = (u32 *) ((uintptr_t) ((u32 *) gameseg - (numentries + 4)) & ~0xf); // Load gamezips pointer list - dmaExec(g_VmZipTable, (romptr_t) &_gamezipSegmentRomStart, ALIGN16((numentries + 1) << 2)); + dmaExec(g_VmZipTable, (romptr_t) REF_SEG _gamezipSegmentRomStart, ALIGN16((numentries + 1) << 2)); // Make pointers absolute instead of relative to their segment for (pagenum = 0; pagenum < numentries; pagenum++) { - g_VmZipTable[pagenum] += (romptr_t) &_gamezipSegmentRomStart; + g_VmZipTable[pagenum] += (romptr_t) REF_SEG _gamezipSegmentRomStart; } // Find the size of the biggest compressed zip @@ -262,14 +262,14 @@ void vmInit(void) // Expansion pak is being used g_Is4Mb = numentries * false; - numpages = (u32)((&_gameSegmentEnd - &_gameSegmentStart) + (VM_PAGE_SIZE - 1)) / VM_PAGE_SIZE; + numpages = (u32)((REF_SEG _gameSegmentEnd - REF_SEG _gameSegmentStart) + (VM_PAGE_SIZE - 1)) / VM_PAGE_SIZE; s7 = (u8 *) STACK_START; #if VERSION >= VERSION_NTSC_1_0 numentries = numpages + 1; - gameseg = (u8 *) ((uintptr_t) (s7 - (u8 *) ALIGN64((uintptr_t) &_gameSegmentEnd - (uintptr_t) &_gameSegmentStart)) & 0xfffe0000); + gameseg = (u8 *) ((uintptr_t) (s7 - (u8 *) ALIGN64((uintptr_t) REF_SEG _gameSegmentEnd - (uintptr_t) REF_SEG _gameSegmentStart)) & 0xfffe0000); #else - gameseg = (u8 *) ((uintptr_t) (s7 - (u8 *) ALIGN64((uintptr_t) &_gameSegmentEnd - (uintptr_t) &_gameSegmentStart)) & 0xfffe0000); + gameseg = (u8 *) ((uintptr_t) (s7 - (u8 *) ALIGN64((uintptr_t) REF_SEG _gameSegmentEnd - (uintptr_t) REF_SEG _gameSegmentStart)) & 0xfffe0000); numentries = numpages + 1; #endif @@ -278,7 +278,7 @@ void vmInit(void) numentries2 = numentries; // Load gamezips pointer list - dmaExec(romaddrs, (romptr_t) &_gamezipSegmentRomStart, ALIGN16((numentries2 + 1) << 2)); + dmaExec(romaddrs, (romptr_t) REF_SEG _gamezipSegmentRomStart, ALIGN16((numentries2 + 1) << 2)); if (pagenum); @@ -290,7 +290,7 @@ void vmInit(void) // Make pointers absolute instead of relative to their segment for (ITER = 0; ITER < numentries2; ITER++) { \ - romaddrs[ITER] += (romptr_t) &_gamezipSegmentRomStart; + romaddrs[ITER] += (romptr_t) REF_SEG _gamezipSegmentRomStart; } // Load each zip from the ROM and inflate them to the game segment