├── Readme.md ├── .devcontainer ├── Dockerfile └── devcontainer.json ├── KOS patch └── README.txt ├── backend ├── gd_item.def ├── Makefile ├── db_item.def ├── gd_item.h ├── db_list.h ├── gdemu_sdk.h ├── gd_list.h ├── controls.p1.h ├── db_list.c ├── db_item.h ├── gdemu_sdk.c └── gdemu_control.c ├── .gitignore ├── .github └── ISSUE_TEMPLATE │ ├── missing-boxart-metadata.md │ ├── feature_request.md │ └── bug_report.md ├── ui ├── openmenu_pal.h ├── ui_line_large.c ├── common.h ├── ui_grid.h ├── ui_line_desc.h ├── animation.c ├── ui_scroll.h ├── dc │ ├── pvr_texture.h │ ├── text_widths.h │ ├── input.h │ ├── input.c │ ├── pvr_texture.c │ └── font_bitmap.c ├── draw_kos.h ├── ui_line_large.h ├── ui_menu_credits.h ├── openmenu_lcd.h ├── animation.h ├── font_prototypes.h ├── theme_manager.h ├── draw_prototypes.h ├── global_settings.h ├── openmenu_vmu.h ├── global_settings.c └── draw_kos.c ├── .clang-format ├── texture ├── serial_sanitize.h ├── txr_manager.h ├── lru.h ├── simple_texture_allocator.h ├── block_pool.h ├── block_pool.c ├── simple_texture_allocator.c ├── lru.c ├── dat_reader.c ├── txr_manager.c └── serial_sanitize.c ├── inc ├── dbgprint.h ├── vm2_api.h ├── dat_format.h └── bloader.h ├── external ├── ini_opt.h ├── easing.h ├── ini.h ├── easing.c └── ini.c ├── tools ├── dat_packer_interface.h ├── reader.c ├── packer.c ├── Makefile ├── dat_packer_internal.c ├── menufaker.c ├── renamecsv.c ├── tsv_to_txt_ini.c └── metapacker.c ├── LICENSE.md ├── Makefile ├── LICENSE.Crayon_VMU.md ├── vm2_api.c └── main.c /Readme.md: -------------------------------------------------------------------------------- 1 | u/westhinksdifferent/ for design mockups -------------------------------------------------------------------------------- /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG VER="gcc-9" 2 | 3 | FROM haydenkow/dcdev-kos-toolchain:${VER} -------------------------------------------------------------------------------- /KOS patch/README.txt: -------------------------------------------------------------------------------- 1 | patch for add GDFS support 2 | 1) replace kos/kernel/arch/dreamcast/fs/fs_iso9660.c 3 | 2) rebuild KOS 4 | -------------------------------------------------------------------------------- /backend/gd_item.def: -------------------------------------------------------------------------------- 1 | /* CFG(section, name, default) */ 2 | /* CFG(OPENMENU, num_items, "0") */ 3 | CFG(ITEMS, name, "OpenMenu") 4 | CFG(ITEMS, disc, "1/1") 5 | CFG(ITEMS, vga, "1") 6 | CFG(ITEMS, region, "JUE") 7 | CFG(ITEMS, version, "v1.001") 8 | CFG(ITEMS, date, "19990909") 9 | CFG(ITEMS, product, "T-0000A") 10 | #undef CFG -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.ini 2 | *.o 3 | *.bin 4 | *.BIN 5 | *.elf 6 | *.map 7 | gdrom 8 | .vscode 9 | tools/*.exe 10 | tools/*.7z 11 | tools/*.dbg 12 | tools/*.com 13 | tools/*.ini 14 | tools/cosmo 15 | tools/*.DAT 16 | tools/BOX 17 | tools/ICON 18 | tools/datpack 19 | tools/datread 20 | tools/datstrip 21 | tools/menufaker 22 | tools/metapack 23 | tools/renamecsv 24 | tools/tsv2ini 25 | -------------------------------------------------------------------------------- /backend/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | CFLAGS = $(PRJCFLAGS) -I.. 4 | OBJLIBS = ../libbackend.a 5 | OBJS = gd_list.o ini.o 6 | 7 | all : $(OBJLIBS) 8 | 9 | ../libbackend.a : $(OBJS) 10 | $(ECHO) $(AR) $(ARFLAGS) rs $@ $? 11 | $(AR) $(ARFLAGS) rs $@ $? 12 | 13 | clean : 14 | $(ECHO) cleaning up backend 15 | -$(RM) -f $(OBJS) 16 | 17 | force_look : 18 | true -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/missing-boxart-metadata.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Missing boxart/metadata 3 | about: Game has missing boxart or metadata. 4 | title: "[BOXART] Game Title missing boxart/metadat" 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Game Title 11 | ## Game Serial 12 | Other relevant info 13 | 14 | ### Paste OPENMENU.INI below 15 | ```ini 16 | HERE 17 | ``` 18 | -------------------------------------------------------------------------------- /ui/openmenu_pal.h: -------------------------------------------------------------------------------- 1 | #ifndef __openmenu_pal__ 2 | #define __openmenu_pal__ 3 | 4 | //static unsigned int size_openmenu_pal = 32; 5 | static unsigned char openmenu_pal[] __attribute__((aligned(16))) = 6 | { 7 | 0x00, 0x00, 0x00, 0x00, 0xbc, 0x0b, 0x8a, 0x47, 0x00, 0x00, 0x25, 0xe1, 0x46, 0x42, 0x00, 0x00, 8 | 0x6a, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0xe3, 0x00, 0x00, 0xbb, 0xfa, 0x85, 0xf5, 9 | }; 10 | #endif 11 | 12 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | 2 | BasedOnStyle: Google 3 | AllowAllArgumentsOnNextLine: true 4 | AllowAllParametersOfDeclarationOnNextLine: true 5 | AllowShortBlocksOnASingleLine: false 6 | AllowShortIfStatementsOnASingleLine: false 7 | AllowShortCaseLabelsOnASingleLine: false 8 | AllowShortFunctionsOnASingleLine: None 9 | BinPackArguments: true 10 | BinPackParameters: true 11 | BreakBeforeBraces: Attach 12 | ColumnLimit: 0 13 | IndentWidth: 2 14 | UseTab: Never -------------------------------------------------------------------------------- /backend/db_item.def: -------------------------------------------------------------------------------- 1 | /*DB_ITEM_STRI(ITEM, product, "T-0000A")*/ 2 | DB_ITEM_STRI(ITEM, description, "Text here...") 3 | DB_ITEM_CHAR(ITEM, num_players, 0) 4 | DB_ITEM_CHAR(ITEM, vmu_blocks, 0) 5 | DB_ITEM_ACCESSORY(ITEM, accessories, 0) 6 | DB_ITEM_CHAR(ITEM, network, 0) 7 | DB_ITEM_GENRE(ITEM, genre, 0) 8 | DB_ITEM_CHAR(ITEM, padding1, 0) 9 | DB_ITEM_CHAR(ITEM, padding2, 0) 10 | #undef DB_ITEM_STRI 11 | #undef DB_ITEM_CHAR 12 | #undef DB_ITEM_GENRE 13 | #undef DB_ITEM_ACCESSORY 14 | -------------------------------------------------------------------------------- /texture/serial_sanitize.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: serial_sanitize.h 3 | * Project: texture 4 | * File Created: Monday, 28th June 2021 1:47:41 pm 5 | * Author: Hayden Kowalchuk 6 | * ----- 7 | * Copyright (c) 2021 Hayden Kowalchuk, Hayden Kowalchuk 8 | * License: BSD 3-clause "New" or "Revised" License, http://www.opensource.org/licenses/BSD-3-Clause 9 | */ 10 | 11 | #pragma once 12 | 13 | const char* serial_santize_art(const char* id); 14 | const char* serial_santize_meta(const char* id); 15 | int serial_sanitizer_init(void); 16 | -------------------------------------------------------------------------------- /inc/dbgprint.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: dbgprint.h 3 | * Project: ini_parse 4 | * File Created: Wednesday, 9th June 2021 8:49:15 pm 5 | * Author: Hayden Kowalchuk 6 | * ----- 7 | * Copyright (c) 2021 Hayden Kowalchuk, Hayden Kowalchuk 8 | * License: BSD 3-clause "New" or "Revised" License, http://www.opensource.org/licenses/BSD-3-Clause 9 | */ 10 | 11 | #pragma once 12 | 13 | #if DEBUG 14 | #define DBG_PRINT(...) printf(__VA_ARGS__) 15 | #define DBG_CHAR_INFO (0) 16 | #define DBG_KERN_INFO (0) 17 | #else 18 | #define DBG_PRINT(...) 19 | #endif 20 | -------------------------------------------------------------------------------- /backend/gd_item.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: item.h 3 | * Project: ini_parse 4 | * File Created: Wednesday, 19th May 2021 3:00:52 pm 5 | * Author: Hayden Kowalchuk 6 | * ----- 7 | * Copyright (c) 2021 Hayden Kowalchuk, Hayden Kowalchuk 8 | * License: BSD 3-clause "New" or "Revised" License, http://www.opensource.org/licenses/BSD-3-Clause 9 | */ 10 | 11 | #pragma once 12 | 13 | typedef struct gd_item 14 | { 15 | char name[128]; 16 | char date[12]; 17 | char product[12]; 18 | char disc[8]; 19 | char version[8]; 20 | char region[4]; 21 | unsigned int slot_num; 22 | char vga[1]; 23 | } gd_item; 24 | 25 | -------------------------------------------------------------------------------- /backend/db_list.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: db_list.h 3 | * Project: backend 4 | * File Created: Wednesday, 16th June 2021 10:32:48 pm 5 | * Author: Hayden Kowalchuk 6 | * ----- 7 | * Copyright (c) 2021 Hayden Kowalchuk, Hayden Kowalchuk 8 | * License: BSD 3-clause "New" or "Revised" License, http://www.opensource.org/licenses/BSD-3-Clause 9 | */ 10 | 11 | #pragma once 12 | 13 | #include "db_item.h" 14 | 15 | int db_load_DAT(void); 16 | int db_get_meta(const char *id, struct db_item **item); 17 | 18 | const char *db_format_nplayers_str(int nplayers); 19 | const char *db_format_vmu_blocks_str(int num_blocks); -------------------------------------------------------------------------------- /external/ini_opt.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: ini_opt.h 3 | * Project: openMenuc 4 | * File Created: Wednesday, 19th May 2021 2:46:51 pm 5 | * Author: Hayden Kowalchuk 6 | * ----- 7 | * Copyright (c) 2021 Hayden Kowalchuk, Hayden Kowalchuk 8 | * License: BSD 3-clause "New" or "Revised" License, http://www.opensource.org/licenses/BSD-3-Clause 9 | */ 10 | 11 | #pragma once 12 | 13 | #define INI_ALLOW_MULTILINE (0) 14 | #define INI_ALLOW_BOM (0) 15 | #define INI_ALLOW_INLINE_COMMENTS (0) 16 | #define INI_STOP_ON_FIRST_ERROR (1) 17 | #define INI_HANDLER_LINENO (0) 18 | #define INI_USE_STACK (1) 19 | #define INI_MAX_LINE (400) 20 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /ui/ui_line_large.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File: ui_line_large.c 3 | * Project: ui 4 | * File Created: Wednesday, 19th May 2021 9:08:14 pm 5 | * Author: Hayden Kowalchuk 6 | * ----- 7 | * Copyright (c) 2021 Hayden Kowalchuk, Hayden Kowalchuk 8 | * License: BSD 3-clause "New" or "Revised" License, http://www.opensource.org/licenses/BSD-3-Clause 9 | */ 10 | #include "ui_line_large.h" 11 | 12 | #include 13 | 14 | #include "../backend/gd_list.h" 15 | 16 | /* @Note: whats the plan here? */ 17 | 18 | FUNCTION(UI_NAME, init) 19 | { 20 | 21 | } 22 | 23 | FUNCTION(UI_NAME, setup) 24 | { 25 | 26 | } 27 | 28 | FUNCTION_INPUT(UI_NAME, handle_input) 29 | { 30 | (void)button; 31 | } 32 | 33 | FUNCTION(UI_NAME, draw) 34 | { 35 | 36 | } 37 | 38 | -------------------------------------------------------------------------------- /texture/txr_manager.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: txr_manager.h 3 | * Project: texture 4 | * File Created: Friday, 21st May 2021 2:30:41 pm 5 | * Author: Hayden Kowalchuk 6 | * ----- 7 | * Copyright (c) 2021 Hayden Kowalchuk, Hayden Kowalchuk 8 | * License: BSD 3-clause "New" or "Revised" License, http://www.opensource.org/licenses/BSD-3-Clause 9 | */ 10 | 11 | #pragma once 12 | 13 | struct image; 14 | 15 | int txr_create_small_pool(void); 16 | int txr_create_large_pool(void); 17 | void txr_empty_small_pool(void); 18 | void txr_empty_large_pool(void); 19 | 20 | int txr_load_DATs(void); /* Loads our DAT files full of images */ 21 | 22 | int txr_get_small(const char *id, struct image *img); 23 | int txr_get_large(const char *id, struct image *img); 24 | -------------------------------------------------------------------------------- /ui/common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: common.h 3 | * Project: ui 4 | * File Created: Thursday, 20th May 2021 12:53:34 am 5 | * Author: Hayden Kowalchuk 6 | * ----- 7 | * Copyright (c) 2021 Hayden Kowalchuk, Hayden Kowalchuk 8 | * License: BSD 3-clause "New" or "Revised" License, http://www.opensource.org/licenses/BSD-3-Clause 9 | */ 10 | 11 | #pragma once 12 | 13 | #include 14 | 15 | #include "../external/easing.h" 16 | 17 | enum control 18 | { 19 | NONE = 0, 20 | LEFT, 21 | RIGHT, 22 | UP, 23 | DOWN, 24 | A, 25 | B, 26 | X, 27 | Y, 28 | START, 29 | TRIG_L, 30 | TRIG_R 31 | }; 32 | 33 | static inline int file_exists(const char *path) 34 | { 35 | struct stat st; 36 | return (fs_stat(path, &st, STAT_TYPE_NONE) == 0); 37 | } 38 | 39 | -------------------------------------------------------------------------------- /backend/gdemu_sdk.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: gdemu_sdk.h 3 | * Project: openMenu 4 | * File Created: Sunday, 20th January 2019 8:22:56 pm 5 | * Author: megavolt85 6 | * ----- 7 | * 8 | */ 9 | 10 | #ifndef GDEMU_SDK_H 11 | #define GDEMU_SDK_H 12 | #include 13 | 14 | /* return 8 byte: 00 00 09 01 00 00 14 05 15 | * 01 09 00 00 - internal bootloader version. don't used in early models 16 | * 05 14 00 00 - FW version (5.14.0) 17 | */ 18 | int gdemu_get_version(void *buffer, uint32_t *size); 19 | 20 | /* param = 0x55 next img */ 21 | /* param = 0x44 prev img */ 22 | #define GDEMU_NEXT_IMG 0x55 23 | #define GDEMU_PREV_IMG 0x44 24 | int gdemu_img_cmd(uint8_t cmd); 25 | 26 | /* 0 = reset to default img */ 27 | /* 1 to 999 = set image index */ 28 | int gdemu_set_img_num(uint16_t img_num); 29 | #endif /* GDEMU_SDK_H */ 30 | -------------------------------------------------------------------------------- /inc/vm2_api.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | typedef struct maple_alldevinfo 4 | { 5 | uint32 functions; /**< \brief Function codes supported */ 6 | uint32 function_data[3]; /**< \brief Additional data per function */ 7 | uint8 area_code; /**< \brief Region code */ 8 | uint8 connector_direction; /**< \brief ? */ 9 | char product_name[30]; /**< \brief Name of device */ 10 | char product_license[60]; /**< \brief License statement */ 11 | uint16 standby_power; /**< \brief Power consumption (standby) */ 12 | uint16 max_power; /**< \brief Power consumption (max) */ 13 | char extended[40]; 14 | char free[40]; 15 | } maple_alldevinfo_t; 16 | 17 | 18 | int vm2_set_id(maple_device_t * dev, const char *ID, const char *name); 19 | int check_vm2_present(maple_device_t * dev); 20 | -------------------------------------------------------------------------------- /tools/dat_packer_interface.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: dat_packer_interfacer.h 3 | * Project: tools 4 | * File Created: Thursday, 17th June 2021 12:07:37 am 5 | * Author: Hayden Kowalchuk 6 | * ----- 7 | * Copyright (c) 2021 Hayden Kowalchuk, Hayden Kowalchuk 8 | * License: BSD 3-clause "New" or "Revised" License, http://www.opensource.org/licenses/BSD-3-Clause 9 | */ 10 | 11 | #pragma once 12 | 13 | #include "../inc/dat_format.h" 14 | 15 | typedef struct bin_item_raw { 16 | char ID[12]; 17 | uint32_t offset; 18 | } bin_item_raw; 19 | 20 | #if defined(WIN32) || defined(WINNT) 21 | #define PATH_SEP "\\" 22 | #else 23 | #define PATH_SEP "/" 24 | #endif 25 | 26 | void open_output(const char *path); 27 | void write_bin_file(bin_header *file_header, bin_item_raw *bin_items, void *data_buf); 28 | int iterate_dir(const char *path, int (*file_cb)(const char *, const char *, struct stat *), bin_header *file_header, bin_item_raw **bin_items); 29 | -------------------------------------------------------------------------------- /ui/ui_grid.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: ui_grid.h 3 | * Project: ui 4 | * File Created: Saturday, 5th June 2021 10:07:48 pm 5 | * Author: Hayden Kowalchuk 6 | * ----- 7 | * Copyright (c) 2021 Hayden Kowalchuk, Hayden Kowalchuk 8 | * License: BSD 3-clause "New" or "Revised" License, http://www.opensource.org/licenses/BSD-3-Clause 9 | */ 10 | 11 | #pragma once 12 | 13 | /* buttons: 14 | 1 LEFT 15 | 2 RIGHT 16 | 3 UP 17 | 4 DOWN 18 | 19 | 5 A 20 | 6 B 21 | 22 | 7 START 23 | */ 24 | 25 | #define UI_NAME GRID_3 26 | 27 | #define FUNC_NAME(name, func) name##_##func 28 | 29 | #define MAKE_FN(name, func) void name##_##func(void) 30 | #define FUNCTION(signal, func) MAKE_FN(signal, func) 31 | 32 | #define MAKE_FN_INPUT(name, func) void name##_##func(unsigned int button) 33 | #define FUNCTION_INPUT(signal, func) MAKE_FN_INPUT(signal, func) 34 | 35 | FUNCTION(UI_NAME, init); 36 | FUNCTION(UI_NAME, setup); 37 | FUNCTION_INPUT(UI_NAME, handle_input); 38 | FUNCTION(UI_NAME, drawOP); 39 | FUNCTION(UI_NAME, drawTR); 40 | -------------------------------------------------------------------------------- /ui/ui_line_desc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: ui_line_desc.h 3 | * Project: ui 4 | * File Created: Wednesday, 19th May 2021 9:29:03 pm 5 | * Author: Hayden Kowalchuk 6 | * ----- 7 | * Copyright (c) 2021 Hayden Kowalchuk, Hayden Kowalchuk 8 | * License: BSD 3-clause "New" or "Revised" License, http://www.opensource.org/licenses/BSD-3-Clause 9 | */ 10 | 11 | #pragma once 12 | 13 | /* buttons: 14 | 1 LEFT 15 | 2 RIGHT 16 | 3 UP 17 | 4 DOWN 18 | 19 | 5 A 20 | 6 B 21 | 22 | 7 START 23 | */ 24 | 25 | #define UI_NAME LIST_DESC 26 | 27 | #define FUNC_NAME(name, func) name##_##func 28 | 29 | #define MAKE_FN(name, func) void name##_##func(void) 30 | #define FUNCTION(signal, func) MAKE_FN(signal, func) 31 | 32 | #define MAKE_FN_INPUT(name, func) void name##_##func(unsigned int button) 33 | #define FUNCTION_INPUT(signal, func) MAKE_FN_INPUT(signal, func) 34 | 35 | FUNCTION(UI_NAME, init); 36 | FUNCTION(UI_NAME, setup); 37 | FUNCTION_INPUT(UI_NAME, handle_input); 38 | FUNCTION(UI_NAME, drawOP); 39 | FUNCTION(UI_NAME, drawTR); 40 | -------------------------------------------------------------------------------- /ui/animation.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File: animation.c 3 | * Project: ui 4 | * File Created: Wednesday, 16th June 2021 10:23:13 pm 5 | * Author: Hayden Kowalchuk 6 | * ----- 7 | * Copyright (c) 2021 Hayden Kowalchuk, Hayden Kowalchuk 8 | * License: BSD 3-clause "New" or "Revised" License, http://www.opensource.org/licenses/BSD-3-Clause 9 | */ 10 | 11 | #include "animation.h" 12 | 13 | #include 14 | 15 | void anim_update_2d(anim2d *anim) 16 | { 17 | AHEasingFunction ease = CubicEaseInOut; 18 | const float dt = (float)anim->time.frame_now / (float)anim->time.frame_len; 19 | const float dv = (*ease)(dt); 20 | anim->cur.x = anim->start.x + (anim->end.x - anim->start.x) * dv; 21 | anim->cur.y = anim->start.y + (anim->end.y - anim->start.y) * dv; 22 | } 23 | 24 | void anim_clear(anim2d *anim) 25 | { 26 | anim->time = (AnimBare){.frame_len = 0, .frame_now = 0, .active = 0}; 27 | anim->start = (vec2d){.x = 0.f, .y = 0.f}; 28 | anim->end = (vec2d){.x = 0.f, .y = 0.f}; 29 | anim->cur = (vec2d){.x = 0.f, .y = 0.f}; 30 | } 31 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /texture/lru.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | /* Function callbacks */ 6 | typedef unsigned int (*user_add_cb)(const char* key, void* user); 7 | typedef unsigned int (*user_del_cb)(const char* key, void* value, void* user); 8 | 9 | struct CacheEntry 10 | { 11 | char* key; 12 | int value; 13 | UT_hash_handle hh; 14 | }; 15 | 16 | typedef struct cache_instance 17 | { 18 | unsigned int cache_max_size; 19 | void* callback_data; 20 | user_add_cb callback_add; 21 | user_del_cb callback_del; 22 | struct CacheEntry* cache; 23 | } cache_instance; 24 | 25 | void cache_set_size(cache_instance* cache, int size); 26 | void cache_callback_userdata(cache_instance* cache, void* user); 27 | void cache_callback_add(cache_instance* cache, user_add_cb callback); 28 | void cache_callback_del(cache_instance* cache, user_del_cb callback); 29 | 30 | int find_in_cache(cache_instance* cache, const char* key); 31 | void add_to_cache(cache_instance* cache, const char* key, int value); 32 | void empty_cache(cache_instance* cache); 33 | -------------------------------------------------------------------------------- /ui/ui_scroll.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: ui_scroll.h 3 | * Project: ui 4 | * File Created: Sunday, 13th June 2021 12:33:33 pm 5 | * Author: Hayden Kowalchuk 6 | * ----- 7 | * Copyright (c) 2021 Hayden Kowalchuk, Hayden Kowalchuk 8 | * License: BSD 3-clause "New" or "Revised" License, http://www.opensource.org/licenses/BSD-3-Clause 9 | */ 10 | 11 | #pragma once 12 | 13 | #define UI_NAME SCROLL 14 | 15 | #define MAKE_FN(name, func) void name##_##func(void) 16 | #define FUNCTION(signal, func) MAKE_FN(signal, func) 17 | 18 | #define MAKE_FN_INPUT(name, func) void name##_##func(unsigned int button) 19 | #define FUNCTION_INPUT(signal, func) MAKE_FN_INPUT(signal, func) 20 | 21 | /* Called once on boot */ 22 | FUNCTION(UI_NAME, init); 23 | /* Similar to above for now but may change when swapping interfaces is added */ 24 | FUNCTION(UI_NAME, setup); 25 | /* Handles incoming input each frame, your job to manage */ 26 | FUNCTION_INPUT(UI_NAME, handle_input); 27 | /* Called per frame to draw your UI */ 28 | FUNCTION(UI_NAME, drawOP); 29 | FUNCTION(UI_NAME, drawTR); 30 | -------------------------------------------------------------------------------- /ui/dc/pvr_texture.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: common.h 3 | * Project: ui 4 | * File Created: Monday, 3rd June 2019 1:01:31 pm 5 | * Author: Hayden Kowalchuk (hayden@hkowsoftware.com) 6 | * ----- 7 | * Copyright (c) 2019 Hayden Kowalchuk 8 | */ 9 | 10 | #pragma once 11 | 12 | #include 13 | #include 14 | 15 | /* Offset and dimensions of each sprite within a spritesheet (romdisk/foo.txt file) */ 16 | typedef struct image 17 | { 18 | char name[16]; 19 | uint32_t width, height; 20 | uint32_t format; 21 | pvr_ptr_t texture; 22 | } image; 23 | 24 | void* pvr_get_internal_buffer(void); 25 | /* Convenience functions */ 26 | extern pvr_ptr_t load_pvr(const char* filename, uint32_t* w, uint32_t* h, uint32_t* txrFormat); 27 | extern pvr_ptr_t load_pvr_to_buffer(const char* filename, uint32_t* w, uint32_t* h, uint32_t* txrFormat, void* buffer); 28 | extern pvr_ptr_t load_pvr_from_buffer(const void* input, uint32_t* w, uint32_t* h, uint32_t* txrFormat); 29 | 30 | /* base method */ 31 | extern pvr_ptr_t load_pvr_from_buffer_to_buffer(const void* input, uint32_t* w, uint32_t* h, uint32_t* txrFormat, void* buffer); 32 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. 2 | { 3 | "name": "Dreamcast Dev", 4 | "build": { 5 | "dockerfile": "Dockerfile", 6 | "args": { "VER": "gcc-9" } 7 | }, 8 | 9 | // Set *default* container specific settings.json values on container create. 10 | "settings": {}, 11 | 12 | // Add the IDs of extensions you want installed when the container is created. 13 | // Note that some extensions may not work in Alpine Linux. See https://aka.ms/vscode-remote/linux. 14 | "extensions": [ 15 | "ms-vscode.cpptools" 16 | ], 17 | 18 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 19 | // "forwardPorts": [], 20 | 21 | // Use 'postCreateCommand' to run commands after the container is created. 22 | // "postCreateCommand": "uname -a", 23 | 24 | // Replace when using a ptrace-based debugger like C++, Go, and Rust 25 | // "runArgs": [ "--init", "--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined" ], 26 | 27 | // Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. 28 | "remoteUser": "dev" 29 | } -------------------------------------------------------------------------------- /ui/draw_kos.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: draw_kos.h 3 | * Project: ui 4 | * File Created: Wednesday, 19th May 2021 11:54:58 pm 5 | * Author: Hayden Kowalchuk 6 | * ----- 7 | * Copyright (c) 2021 Hayden Kowalchuk, Hayden Kowalchuk 8 | * License: BSD 3-clause "New" or "Revised" License, http://www.opensource.org/licenses/BSD-3-Clause 9 | */ 10 | 11 | #pragma once 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #include "../texture/simple_texture_allocator.h" 18 | #include "dc/pvr_texture.h" 19 | #include "theme_manager.h" 20 | 21 | #ifndef PVR_PACK_ARGB 22 | #define PVR_PACK_ARGB(a, r, g, b) ( \ 23 | (((uint8_t)((a))) << 24) | \ 24 | (((uint8_t)((r))) << 16) | \ 25 | (((uint8_t)((g))) << 8) | \ 26 | (((uint8_t)((b))) << 0)) 27 | #endif 28 | 29 | #define COLOR_WHITE (0xFFFFFFFF) /*(PVR_PACK_ARGB(0xFF,0xFF,0xFF,0xFF))*/ 30 | #define COLOR_BLACK (0xFF000000) /*(PVR_PACK_ARGB(0xFF,0x00,0x00,0x00))*/ 31 | #define COLOR_ORANGE_J (0xFFFAAA8F) /*(PVR_PACK_ARGB(0xFF,250,170,143))*/ 32 | #define COLOR_ORANGE_U (0xFFF6A61B) /*(PVR_PACK_ARGB(0xFF,246,166,27))*/ 33 | #define COLOR_BLUE (0xFF9FBCE0) /*(PVR_PACK_ARGB(0xFF,159,188,224))*/ 34 | -------------------------------------------------------------------------------- /ui/ui_line_large.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: ui_line_large.h 3 | * Project: ui 4 | * File Created: Wednesday, 19th May 2021 9:09:42 pm 5 | * Author: Hayden Kowalchuk 6 | * ----- 7 | * Copyright (c) 2021 Hayden Kowalchuk, Hayden Kowalchuk 8 | * License: BSD 3-clause "New" or "Revised" License, http://www.opensource.org/licenses/BSD-3-Clause 9 | */ 10 | 11 | #pragma once 12 | 13 | /* buttons are defined in an enum `control` and have these values and names 14 | 0 NONE 15 | 1 LEFT 16 | 2 RIGHT 17 | 3 UP 18 | 4 DOWN 19 | 20 | 5 A 21 | 6 B 22 | 7 X 23 | 8 Y 24 | 25 | 9 START 26 | */ 27 | 28 | #define UI_NAME LIST_LARGE 29 | 30 | #define MAKE_FN(name, func) void name##_##func(void) 31 | #define FUNCTION(signal, func) MAKE_FN(signal, func) 32 | 33 | #define MAKE_FN_INPUT(name, func) void name##_##func(unsigned int button) 34 | #define FUNCTION_INPUT(signal, func) MAKE_FN_INPUT(signal, func) 35 | 36 | /* Called once on boot */ 37 | FUNCTION(UI_NAME, init); 38 | /* Similar to above for now but may change when swapping interfaces is added */ 39 | FUNCTION(UI_NAME, setup); 40 | /* Handles incoming input each frame, your job to manage */ 41 | FUNCTION_INPUT(UI_NAME, handle_input); 42 | /* Called per frame to draw your UI */ 43 | FUNCTION(UI_NAME, draw); 44 | -------------------------------------------------------------------------------- /backend/gd_list.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: gd_list.h 3 | * Project: ini_parse 4 | * File Created: Wednesday, 19th May 2021 5:33:33 pm 5 | * Author: Hayden Kowalchuk 6 | * ----- 7 | * Copyright (c) 2021 Hayden Kowalchuk, Hayden Kowalchuk 8 | * License: BSD 3-clause "New" or "Revised" License, http://www.opensource.org/licenses/BSD-3-Clause 9 | */ 10 | 11 | #pragma once 12 | 13 | struct gd_item; 14 | int list_read(const char *filename); 15 | int list_read_default(void); 16 | void list_destroy(void); 17 | void list_print_slots(void); 18 | void list_print_temp(void); 19 | void list_print(const struct gd_item **list); 20 | 21 | /* simple sorting methods */ 22 | const struct gd_item **list_get(void); 23 | void list_set_sort_name(void); 24 | void list_set_sort_region(void); 25 | void list_set_sort_genre(void); 26 | void list_set_sort_default(void); 27 | /* complex filtering and sorting */ 28 | void list_set_genre(int genre); 29 | void list_set_genre_sort(int genre, int sort); 30 | void list_set_sort_filter(const char type, int num); 31 | /* Grab multidisc games */ 32 | void list_set_multidisc(const char *product_id); 33 | const struct gd_item **list_get_multidisc(void); 34 | 35 | int list_length(void); 36 | int list_multidisc_length(void); 37 | const struct gd_item *list_item_get(int idx); 38 | -------------------------------------------------------------------------------- /ui/ui_menu_credits.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: ui_menu_credits.h 3 | * Project: ui 4 | * File Created: Monday, 12th July 2021 11:40:41 pm 5 | * Author: Hayden Kowalchuk 6 | * ----- 7 | * Copyright (c) 2021 Hayden Kowalchuk, Hayden Kowalchuk 8 | * License: BSD 3-clause "New" or "Revised" License, http://www.opensource.org/licenses/BSD-3-Clause 9 | */ 10 | 11 | #pragma once 12 | 13 | #include "common.h" 14 | #include "global_settings.h" 15 | #include "backend/gd_item.h" 16 | 17 | struct theme_color; 18 | 19 | void menu_setup(enum draw_state* state, struct theme_color* _colors, int* timeout_ptr); 20 | void popup_setup(enum draw_state* state, struct theme_color* _colors, int* timeout_ptr); 21 | 22 | void handle_input_menu(enum control input); 23 | void handle_input_credits(enum control input); 24 | void handle_input_multidisc(enum control input); 25 | void handle_input_exit(enum control input); 26 | void handle_input_codebreaker(enum control input); 27 | 28 | void draw_menu_op(void); 29 | void draw_menu_tr(void); 30 | 31 | void draw_credits_op(void); 32 | void draw_credits_tr(void); 33 | 34 | void draw_multidisc_op(void); 35 | void draw_multidisc_tr(void); 36 | 37 | void draw_exit_op(void); 38 | void draw_exit_tr(void); 39 | 40 | void draw_codebreaker_op(void); 41 | void draw_codebreaker_tr(void); 42 | 43 | void set_cur_game_item(const gd_item *id); 44 | const gd_item *get_cur_game_item(); 45 | -------------------------------------------------------------------------------- /texture/simple_texture_allocator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: simple_texture_allocator.h 3 | * Project: texture 4 | * File Created: Friday, 18th June 2021 3:28:27 pm 5 | * Author: Hayden Kowalchuk 6 | * ----- 7 | * Copyright (c) 2021 Hayden Kowalchuk, Hayden Kowalchuk 8 | * License: BSD 3-clause "New" or "Revised" License, http://www.opensource.org/licenses/BSD-3-Clause 9 | */ 10 | 11 | #pragma once 12 | #define TEX_ALIGNMENT (32) 13 | 14 | #include 15 | 16 | /* 1mb buffer */ 17 | #define TEXMAN_BUFFER_SIZE (2 * 1024 * 1024) 18 | 19 | struct Simple_Texture 20 | { 21 | unsigned char *location; 22 | int width, height; 23 | }; 24 | 25 | /* used for initialization */ 26 | int texman_inited(void); 27 | void texman_reset(void *buf, uint32_t size); 28 | void texman_set_buffer(void *buf, uint32_t size); 29 | 30 | /* management funcs for clients 31 | Steps: 32 | 1. create 33 | 2. reserve memory & upload by pointer OR upload_swizzle 34 | 35 | note: texture will be bound 36 | */ 37 | uint32_t texman_create(void); 38 | void texman_clear(void); 39 | int texman_get_space_available(void); 40 | int texman_is_space_available(void); 41 | unsigned char *texman_get_tex_data(uint32_t num); 42 | struct Simple_Texture *texman_reserve_memory(uint32_t width, uint32_t height, int bpp); 43 | void texman_upload(uint32_t width, uint32_t height, int bpp, const void *buffer); 44 | void texman_bind_tex(uint32_t num); 45 | -------------------------------------------------------------------------------- /ui/openmenu_lcd.h: -------------------------------------------------------------------------------- 1 | #ifndef __openmenu_lcd__ 2 | #define __openmenu_lcd__ 3 | 4 | //static unsigned int size_openmenu_lcd = 192; 5 | static unsigned char openmenu_lcd[] __attribute__((aligned(16))) = 6 | { 7 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3e, 0x97, 0xb6, 0x52, 0xf7, 0xbc, 0x32, 0x90, 0xb6, 0x52, 8 | 0x14, 0xa4, 0x32, 0x97, 0xb6, 0x52, 0xf4, 0xa4, 0x32, 0x94, 0xb6, 0x52, 0x94, 0xa4, 0x32, 0xf7, 9 | 0xb6, 0x5e, 0xf7, 0xbc, 0x32, 0xf7, 0xb6, 0x5e, 0xf7, 0xbc, 0x00, 0x00, 0x36, 0x40, 0x00, 0x00, 10 | 0x00, 0x00, 0x3f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xfc, 11 | 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x80, 0x00, 0x00, 0x03, 12 | 0xf8, 0x0f, 0xe0, 0x00, 0x00, 0x07, 0xe0, 0x03, 0xf0, 0x00, 0x00, 0x07, 0x81, 0xc1, 0xf0, 0x00, 13 | 0x00, 0x0f, 0x0f, 0xf8, 0xf8, 0x00, 0x00, 0x0f, 0x1f, 0xfc, 0x78, 0x00, 0x00, 0x1e, 0x3f, 0xfe, 14 | 0x3c, 0x00, 0x00, 0x1e, 0x3c, 0x1e, 0x3c, 0x00, 0x00, 0x1e, 0x3c, 0x1e, 0x3c, 0x00, 0x00, 0x1e, 15 | 0x3c, 0x1e, 0x3c, 0x00, 0x00, 0x1e, 0x3c, 0x1e, 0x3c, 0x00, 0x00, 0x1e, 0x1f, 0x9e, 0x3c, 0x00, 16 | 0x00, 0x0f, 0x0f, 0x3e, 0x78, 0x00, 0x00, 0x0f, 0x80, 0x7c, 0x78, 0x00, 0x00, 0x07, 0xf7, 0xf8, 17 | 0xf0, 0x00, 0x00, 0x03, 0xff, 0xf1, 0xe0, 0x00, 0x00, 0x00, 0xff, 0xe3, 0xc0, 0x00, 0x00, 0x00, 18 | 0x3f, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xf8, 0x00, 0x00, 19 | }; 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /backend/controls.p1.h: -------------------------------------------------------------------------------- 1 | const int altctrl_size = 220; 2 | const unsigned char altctrl_data[220] = 3 | { 4 | 0x00, 0xE7, 0x52, 0x55, 0x08, 0x75, 0x08, 0x74, 5 | 0x53, 0x84, 0x0C, 0x60, 0xC0, 0xC8, 0x00, 0x89, 6 | 0x02, 0x77, 0x52, 0x84, 0x0C, 0x60, 0xC0, 0xC8, 7 | 0x00, 0x89, 0x01, 0x77, 0x18, 0x47, 0x51, 0x84, 8 | 0x0C, 0x60, 0x06, 0xCA, 0x06, 0xC9, 0x0C, 0x37, 9 | 0x50, 0x60, 0x0C, 0x60, 0x40, 0xC8, 0x00, 0x8B, 10 | 0x01, 0x77, 0x23, 0xA0, 0x18, 0x47, 0xE0, 0x04, 11 | 0xC0, 0x00, 0xA0, 0x00, 0x6C, 0xA0, 0x09, 0x8C, 12 | 0x24, 0x9B, 0x09, 0x8C, 0x20, 0x9B, 0x09, 0x8C, 13 | 0x28, 0x9B, 0x09, 0x8C, 0x2C, 0x9B, 0x09, 0x8C, 14 | 0x58, 0x15, 0x01, 0x8C, 0x22, 0x35, 0x08, 0x8C, 15 | 0x72, 0xA0, 0x09, 0x8C, 0x34, 0x3A, 0x08, 0x8C, 16 | 0x0C, 0xA0, 0x09, 0x8C, 0x8A, 0xA0, 0x09, 0x8C, 17 | 0x70, 0xA0, 0x09, 0x8C, 0x71, 0xA0, 0x09, 0x8C, 18 | 0x94, 0x73, 0x09, 0x8C, 0x00, 0x00, 0xFF, 0xFF, 19 | 0xFF, 0xFF, 0xFD, 0xFF, 0x80, 0xC8, 0x00, 0x8B, 20 | 0x01, 0x77, 0x20, 0xC8, 0x02, 0x8B, 0x08, 0xE1, 21 | 0x18, 0x41, 0x1C, 0x37, 0x0E, 0xCA, 0x0E, 0xC9, 22 | 0x0C, 0x37, 0x55, 0x84, 0x0C, 0x60, 0x80, 0xC8, 23 | 0x03, 0x89, 0x40, 0xC8, 0x04, 0x89, 0x03, 0xA0, 24 | 0x20, 0x77, 0x40, 0xC8, 0x00, 0x8B, 0x10, 0x77, 25 | 0x54, 0x84, 0x0C, 0x60, 0x80, 0xC8, 0x04, 0x89, 26 | 0x40, 0xC8, 0x05, 0x89, 0x80, 0xC9, 0x03, 0xA0, 27 | 0x0C, 0x37, 0x40, 0xC8, 0x00, 0x8B, 0x40, 0x77, 28 | 0x51, 0x60, 0x09, 0x91, 0x18, 0x20, 0x03, 0x8B, 29 | 0x02, 0xD0, 0x02, 0x60, 0x2B, 0x40, 0x04, 0xE4, 30 | 0x0B, 0x00, 0x72, 0x24, 0xE0, 0x00, 0x00, 0x8C, 31 | 0x0E, 0x06, 0x09, 0x00 32 | }; 33 | 34 | 35 | -------------------------------------------------------------------------------- /ui/animation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: animation.h 3 | * Project: ui 4 | * File Created: Wednesday, 16th June 2021 10:23:23 pm 5 | * Author: Hayden Kowalchuk 6 | * ----- 7 | * Copyright (c) 2021 Hayden Kowalchuk, Hayden Kowalchuk 8 | * License: BSD 3-clause "New" or "Revised" License, http://www.opensource.org/licenses/BSD-3-Clause 9 | */ 10 | 11 | #pragma once 12 | 13 | #include 14 | 15 | #include "../external/easing.h" 16 | 17 | typedef struct vec2d 18 | { 19 | float x; 20 | float y; 21 | } vec2d; 22 | 23 | typedef struct AnimBare 24 | { 25 | int frame_len; 26 | int frame_now; 27 | bool active; 28 | } AnimBare; 29 | 30 | typedef struct anim2d 31 | { 32 | AnimBare time; 33 | vec2d start; 34 | vec2d end; 35 | vec2d cur; 36 | } anim2d; 37 | 38 | void anim_update_2d(anim2d *anim); 39 | void anim_clear(anim2d *anim); 40 | 41 | static inline bool anim_finished(AnimBare *anim) 42 | { 43 | return anim->frame_now == anim->frame_len; 44 | } 45 | 46 | static inline bool anim_active(AnimBare *anim) 47 | { 48 | return anim->active; 49 | } 50 | 51 | static inline bool anim_alive(AnimBare *anim) 52 | { 53 | return anim_active(anim) && (anim->frame_now <= anim->frame_len); 54 | } 55 | 56 | static inline void anim_tick(AnimBare *anim) 57 | { 58 | if (anim_alive(anim) && !anim_finished(anim)) 59 | { 60 | anim->frame_now++; 61 | } 62 | } 63 | 64 | static inline void anim_tick_backward(AnimBare *anim) 65 | { 66 | if (anim_active(anim)) 67 | { 68 | anim->frame_now--; 69 | } 70 | 71 | if (anim->frame_now <= 0) 72 | { 73 | anim->active = false; 74 | anim->frame_now = 0; 75 | } 76 | } 77 | 78 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Modified BSD License 2 | ==================== 3 | 4 | _Copyright © `2021`, `Hayden Kowalchuk`_ 5 | _All rights reserved._ 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | notice, this list of conditions and the following disclaimer in the 14 | documentation and/or other materials provided with the distribution. 15 | * Neither the name of the copyright holder nor the 16 | names of its contributors may be used to endorse or promote products 17 | derived from this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY 23 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | TARGET := themeMenu.elf 2 | 3 | EXT_SRCS := external/easing.c 4 | TXR_SRCS := texture/block_pool.c texture/lru.c texture/txr_manager.c texture/dat_reader.c texture/serial_sanitize.c texture/simple_texture_allocator.c 5 | BACKEND_SRCS := external/ini.c backend/gd_list.c backend/gdemu_sdk.c backend/gdemu_control.c backend/db_list.c 6 | UI_MENUS := ui/ui_scroll.c ui/ui_line_large.c ui/ui_line_desc.c ui/ui_grid.c ui/global_settings.c ui/ui_menu_credits.c ui/theme_manager.c 7 | UI_SRCS := ui/dc/font_bmf.c ui/dc/font_bitmap.c ui/dc/pvr_texture.c ui/dc/input.c ui/draw_kos.c ui/animation.c 8 | 9 | SRCS := $(BACKEND_SRCS) $(UI_SRCS) $(UI_MENUS) $(TXR_SRCS) $(EXT_SRCS) vm2_api.c main.c 10 | OBJS = $(subst .c,.o,$(SRCS)) 11 | 12 | CC := kos-cc 13 | AS := kos-as 14 | OBJCOPY := $(KOS_OBJCOPY) 15 | RM := rm 16 | 17 | CFLAGS := -I. -ffunction-sections -fdata-sections -std=c11 -O2 -g -Wno-unknown-pragmas -Wall -Wextra $(OPTIONS) 18 | LDFLAGS := -Wl,--gc-sections -Xlinker -Map=output.map 19 | LIBS := -lm 20 | 21 | all: clean-elf $(TARGET) 22 | 23 | %.o: %.s 24 | @echo $(AS) $< 25 | @$(CC) -x assembler-with-cpp $(CFLAGS) -c $< -o $@ 26 | 27 | %.o: %.c 28 | @echo $(CC) $< 29 | @$(CC) -c $< -o $@ $(CFLAGS) 30 | 31 | $(TARGET): $(OBJS) 32 | @echo \> $(CC) -o $(TARGET) 33 | @$(CC) -o $(TARGET) $(LDFLAGS) $(CFLAGS) $(OBJS) $(LIBS) $(MAP) 34 | @echo $(notdir $(OBJCOPY)) -R .stack -O binary $@ $(basename $@).bin 35 | @$(OBJCOPY) -R .stack -O binary $@ 1ST_READ.BIN 36 | 37 | .PHONY: clean 38 | .PHONY: clean-elf 39 | 40 | clean: 41 | -@$(RM) -f $(TARGET) $(OBJS) *.bin *.BIN 42 | 43 | clean-elf: 44 | -@$(RM) -f $(TARGET) 45 | 46 | run: $(TARGET) 47 | $(KOS_LOADER) $(TARGET) 48 | -------------------------------------------------------------------------------- /LICENSE.Crayon_VMU.md: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | ==================== 3 | 4 | Copyright (c) `2019`, `Protofall` & `2019`, `Hayden Kowalchuk` 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | * Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /texture/block_pool.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: block_pool.h 3 | * Project: lru_cache 4 | * File Created: Thursday, 20th May 2021 5:27:47 pm 5 | * Author: Hayden Kowalchuk 6 | * ----- 7 | * Copyright (c) 2021 Hayden Kowalchuk, Hayden Kowalchuk 8 | * License: BSD 3-clause "New" or "Revised" License, http://www.opensource.org/licenses/BSD-3-Clause 9 | */ 10 | 11 | #pragma once 12 | 13 | #include 14 | 15 | typedef struct slot_format 16 | { 17 | uint32_t width, height; 18 | uint32_t format; 19 | } slot_format; 20 | 21 | typedef struct block_pool 22 | { 23 | void *base; 24 | unsigned int size; 25 | unsigned int slots; 26 | unsigned int slot_size; 27 | unsigned char *state; 28 | slot_format *format; 29 | } block_pool; 30 | 31 | void pool_create(block_pool *pool, void *buffer, unsigned int size, unsigned int slot); 32 | void pool_destroy(block_pool *pool); 33 | void pool_destroy_user(block_pool *pool, void (*user_free)(void *ptr)); 34 | void pool_get_next_free(block_pool *pool, unsigned int *slot_num, void **ptr); 35 | void pool_dealloc_all(block_pool *pool); 36 | void pool_dealloc_slot(block_pool *pool, unsigned int slot_num); 37 | 38 | /* inline funcs */ 39 | static inline void *pool_get_slot_addr(const block_pool *pool, unsigned int slot_num) 40 | { 41 | return (void *)((uintptr_t)pool->base + slot_num * pool->slot_size); 42 | } 43 | 44 | static inline const slot_format *pool_get_slot_format(const block_pool *pool, unsigned int slot_num) 45 | { 46 | return &pool->format[slot_num]; 47 | } 48 | 49 | static inline void pool_set_slot_format(block_pool *pool, unsigned int slot_num, unsigned int width, unsigned int height, unsigned int format) 50 | { 51 | pool->format[slot_num].width = width; 52 | pool->format[slot_num].height = height; 53 | pool->format[slot_num].format = format; 54 | } 55 | 56 | -------------------------------------------------------------------------------- /ui/dc/text_widths.h: -------------------------------------------------------------------------------- 1 | const char char_widths[256] = 2 | { 3 | 0x03, 0x03, 0x04, 0x09, 0x08, 0x0c, 0x0a, 0x02, 4 | 0x04, 0x04, 0x04, 0x0a, 0x02, 0x04, 0x02, 0x04, 5 | 0x09, 0x04, 0x08, 0x08, 0x09, 0x08, 0x08, 0x08, 6 | 0x09, 0x09, 0x02, 0x02, 0x0a, 0x07, 0x0a, 0x07, 7 | 0x0c, 0x0d, 0x08, 0x0b, 0x0c, 0x08, 0x07, 0x0c, 8 | 0x0b, 0x03, 0x03, 0x0a, 0x09, 0x0f, 0x0c, 0x0d, 9 | 0x08, 0x0d, 0x0a, 0x08, 0x0a, 0x0a, 0x0d, 0x11, 10 | 0x0c, 0x0a, 0x0a, 0x05, 0x04, 0x05, 0x05, 0x0a, 11 | 0x03, 0x07, 0x08, 0x08, 0x08, 0x08, 0x05, 0x09, 12 | 0x08, 0x03, 0x03, 0x08, 0x03, 0x0d, 0x08, 0x09, 13 | 0x08, 0x08, 0x05, 0x06, 0x05, 0x08, 0x09, 0x0c, 14 | 0x09, 0x08, 0x08, 0x05, 0x03, 0x05, 0x05, 0x05, 15 | 0x09, 0x02, 0x09, 0x05, 0x06, 0x09, 0x06, 0x00, 16 | 0x05, 0x12, 0x0b, 0x05, 0x10, 0x0a, 0x00, 0x00, 17 | 0x00, 0x02, 0x02, 0x05, 0x05, 0x02, 0x07, 0x0d, 18 | 0x00, 0x0e, 0x08, 0x05, 0x0f, 0x08, 0x0a, 0x00, 19 | 0x03, 0x03, 0x05, 0x08, 0x08, 0x0a, 0x09, 0x03, 20 | 0x04, 0x04, 0x05, 0x08, 0x03, 0x06, 0x03, 0x04, 21 | 0x08, 0x06, 0x07, 0x08, 0x08, 0x08, 0x08, 0x07, 22 | 0x08, 0x08, 0x03, 0x03, 0x08, 0x08, 0x08, 0x06, 23 | 0x0b, 0x08, 0x08, 0x09, 0x09, 0x07, 0x07, 0x09, 24 | 0x09, 0x03, 0x06, 0x08, 0x07, 0x0b, 0x09, 0x0a, 25 | 0x08, 0x0a, 0x08, 0x08, 0x08, 0x09, 0x08, 0x0c, 26 | 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x05, 0x05, 27 | 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x04, 0x07, 28 | 0x07, 0x03, 0x03, 0x06, 0x03, 0x0a, 0x07, 0x07, 29 | 0x07, 0x07, 0x04, 0x06, 0x04, 0x07, 0x06, 0x09, 30 | 0x06, 0x06, 0x06, 0x04, 0x04, 0x04, 0x08, 0x04, 31 | 0x08, 0x03, 0x08, 0x06, 0x09, 0x05, 0x05, 0x00, 32 | 0x07, 0x0f, 0x08, 0x05, 0x0e, 0x08, 0x00, 0x00, 33 | 0x00, 0x03, 0x03, 0x06, 0x06, 0x05, 0x07, 0x0d, 34 | 0x07, 0x0b, 0x06, 0x05, 0x0c, 0x06, 0x08, 0x00 35 | }; 36 | 37 | const int char_widths_length = 256; 38 | -------------------------------------------------------------------------------- /inc/dat_format.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: dat_format.h 3 | * Project: ini_parse 4 | * File Created: Tuesday, 8th June 2021 8:49:08 pm 5 | * Author: Hayden Kowalchuk 6 | * ----- 7 | * Copyright (c) 2021 Hayden Kowalchuk, Hayden Kowalchuk 8 | * License: BSD 3-clause "New" or "Revised" License, http://www.opensource.org/licenses/BSD-3-Clause 9 | */ 10 | 11 | #pragma once 12 | #include 13 | #include 14 | 15 | typedef struct bin_item 16 | { 17 | char ID[12]; 18 | uint32_t offset; 19 | UT_hash_handle hh; /* makes this structure hashable */ 20 | } bin_item; 21 | 22 | typedef struct bin_header 23 | { 24 | union 25 | { 26 | struct 27 | { 28 | char alpha[3]; 29 | char version; 30 | } rich; 31 | uint32_t raw; 32 | } magic; /* DAT1 : DAT + single digit version */ 33 | uint32_t chunk_size; /* Size of each chunk in the file */ 34 | uint32_t num_chunks; /* How many chunks are present in this bin */ 35 | uint32_t padding0; /* Unused in ver1 */ 36 | } bin_header; 37 | 38 | typedef struct dat_file 39 | { 40 | uint32_t chunk_size; /* Size of each chunk in the file */ 41 | uint32_t num_chunks; /* How many chunks are present in this bin */ 42 | #ifdef STANDALONE_BINARY 43 | FILE *handle; 44 | #else 45 | file_t handle; /* Open File Handle, commonly FILE* */ 46 | #endif 47 | bin_item *items; /* Holds actual data */ 48 | bin_item *hash; /* Hash table for above */ 49 | } dat_file; 50 | 51 | int DAT_init(dat_file *bin); 52 | int DAT_load_parse(dat_file *bin, const char *path); 53 | void DAT_info(const dat_file *bin); 54 | 55 | uint32_t DAT_get_offset_by_ID(const dat_file *bin, const char *ID); 56 | uint32_t DAT_get_index_by_ID(const dat_file *bin, const char *ID); 57 | int DAT_read_file_by_ID(const dat_file *bin, const char *ID, void *buf); 58 | int DAT_read_file_by_num(const dat_file *bin, uint32_t chunk_num, void *buf); 59 | -------------------------------------------------------------------------------- /ui/font_prototypes.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: font_prototypes.h 3 | * Project: ui 4 | * File Created: Thursday, 20th May 2021 12:35:54 am 5 | * Author: Hayden Kowalchuk 6 | * ----- 7 | * Copyright (c) 2021 Hayden Kowalchuk, Hayden Kowalchuk 8 | * License: BSD 3-clause "New" or "Revised" License, http://www.opensource.org/licenses/BSD-3-Clause 9 | */ 10 | 11 | #pragma once 12 | /* BMF formatted nice text */ 13 | int font_bmf_init(const char *fnt, const char *texture, int is_wide); 14 | void font_bmf_destroy(void); 15 | 16 | void font_bmf_begin_draw(void); 17 | void font_bmf_set_scale(float scale); 18 | void font_bmf_set_height_default(void); 19 | void font_bmf_set_height(float height); 20 | 21 | void font_bmf_draw(int x, int y, uint32_t color, const char *str); 22 | void font_bmf_draw_main(int x, int y, uint32_t color, const char *str); 23 | void font_bmf_draw_sub(int x, int y, uint32_t color, const char *str); 24 | void font_bmf_draw_sub_wrap(int x, int y, uint32_t color, const char *str, int width); 25 | void font_bmf_draw_auto_size(int x, int y, uint32_t color, const char *str, int width); 26 | void font_bmf_draw_centered(int x, int y, uint32_t color, const char *str); 27 | void font_bmf_draw_centered_auto_size(int x, int y, uint32_t color, const char *str, int width); 28 | 29 | /* Basic fixed width bitmap font */ 30 | int font_bmp_init(const char *filename, int char_width, int char_height); 31 | void font_bmp_destroy(void); 32 | 33 | void font_bmp_begin_draw(void); 34 | void font_bmp_set_color(uint32_t color); 35 | void font_bmp_set_color_components(int r, int g, int b, int a); 36 | 37 | void font_bmp_draw_main(int x, int y, const char *str); 38 | void font_bmp_draw_sub(int x, int y, const char *str); 39 | void font_bmp_draw_sub_wrap(int x, int y, const char *str, int width); 40 | void font_bmp_draw_auto_size(int x, int y, const char *str, int width); 41 | void font_bmp_draw_centered(int x, int y, const char *str); -------------------------------------------------------------------------------- /ui/theme_manager.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: theme_manager.h 3 | * Project: ui 4 | * File Created: Tuesday, 27th July 2021 12:09:25 pm 5 | * Author: Hayden Kowalchuk 6 | * ----- 7 | * Copyright (c) 2021 Hayden Kowalchuk, Hayden Kowalchuk 8 | * License: BSD 3-clause "New" or "Revised" License, http://www.opensource.org/licenses/BSD-3-Clause 9 | */ 10 | 11 | #pragma once 12 | 13 | #include 14 | #include 15 | 16 | #include "global_settings.h" 17 | 18 | struct image; 19 | 20 | typedef struct theme_color 21 | { 22 | uint32_t text_color; 23 | uint32_t highlight_color; 24 | uint32_t menu_text_color; 25 | uint32_t menu_highlight_color; 26 | uint32_t menu_bkg_color; 27 | uint32_t menu_bkg_border_color; 28 | uint32_t icon_color; 29 | } theme_color; 30 | 31 | typedef struct theme_region 32 | { 33 | const char *bg_left; 34 | const char *bg_right; 35 | theme_color colors; 36 | } theme_region; 37 | 38 | typedef struct theme_custom 39 | { 40 | char bg_left[32]; 41 | char bg_right[32]; 42 | char name[20]; 43 | theme_color colors; 44 | } theme_custom; 45 | 46 | typedef struct theme_scroll 47 | { 48 | char bg_left[32]; 49 | char bg_right[32]; 50 | char name[20]; 51 | theme_color colors; 52 | char font[32]; 53 | uint32_t cursor_color; 54 | uint32_t multidisc_color; 55 | int cursor_width; 56 | int cursor_height; 57 | int items_per_page; 58 | int pos_gameslist_x; 59 | int pos_gameslist_y; 60 | int pos_gameinfo_x; 61 | int pos_gameinfo_region_y; 62 | int pos_gameinfo_vga_y; 63 | int pos_gameinfo_disc_y; 64 | int pos_gameinfo_date_y; 65 | int pos_gameinfo_version_y; 66 | int pos_gametxr_x; 67 | int pos_gametxr_y; 68 | } theme_scroll; 69 | 70 | int theme_manager_load(void); 71 | theme_region *theme_get_default(CFG_ASPECT aspect, int *num_themes); 72 | theme_custom *theme_get_custom(int *num_themes); 73 | theme_scroll *theme_get_scroll(int *num_themes); 74 | -------------------------------------------------------------------------------- /backend/db_list.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File: db_list.c 3 | * Project: backend 4 | * File Created: Wednesday, 16th June 2021 10:32:39 pm 5 | * Author: Hayden Kowalchuk 6 | * ----- 7 | * Copyright (c) 2021 Hayden Kowalchuk, Hayden Kowalchuk 8 | * License: BSD 3-clause "New" or "Revised" License, http://www.opensource.org/licenses/BSD-3-Clause 9 | */ 10 | 11 | #include "db_list.h" 12 | 13 | #include 14 | 15 | #include "../inc/dat_format.h" 16 | #include "../texture/serial_sanitize.h" 17 | #include "db_item.h" 18 | 19 | static dat_file dat_meta; 20 | static db_item *db; 21 | static int dat_first_index; 22 | 23 | int db_load_DAT(void) 24 | { 25 | DAT_init(&dat_meta); 26 | DAT_load_parse(&dat_meta, "META.DAT"); 27 | dat_first_index = dat_meta.items[0].offset; 28 | 29 | /* Read DAT to db, but use Hash table to quickly search */ 30 | db = malloc(dat_meta.num_chunks * sizeof(db_item)); 31 | if (!db) 32 | { 33 | printf("%s no free memory\n", __func__); 34 | return 0; 35 | } 36 | 37 | fs_read(dat_meta.handle, db, dat_meta.num_chunks * sizeof(db_item)); 38 | fs_close(dat_meta.handle); 39 | 40 | DAT_info(&dat_meta); 41 | 42 | return 0; 43 | } 44 | 45 | /* Returns 0 on success and places a pointer in item, otherwise returns 1 and item = NULL */ 46 | int db_get_meta(const char *id, struct db_item **item) 47 | { 48 | const char *id_santized = serial_santize_meta(id); 49 | uint32_t index = DAT_get_index_by_ID(&dat_meta, id_santized); 50 | 51 | if (index == 0xFFFFFFFF) 52 | { 53 | *item = NULL; 54 | return 1; 55 | } 56 | 57 | *item = &db[index - dat_first_index]; 58 | return 0; 59 | } 60 | 61 | const char *db_format_nplayers_str(int nplayers) 62 | { 63 | static char str[10]; 64 | sprintf(str, "%d Player%c", nplayers, (nplayers > 1 ? 's' : '\0')); 65 | return str; 66 | } 67 | 68 | const char *db_format_vmu_blocks_str(int num_blocks) 69 | { 70 | static char str[12]; 71 | sprintf(str, "%d Block%c", num_blocks, (num_blocks != 1 ? 's' : '\0')); 72 | return str; 73 | } 74 | 75 | -------------------------------------------------------------------------------- /backend/db_item.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: db_item.h 3 | * Project: backend 4 | * File Created: Wednesday, 16th June 2021 5:44:34 pm 5 | * Author: Hayden Kowalchuk 6 | * ----- 7 | * Copyright (c) 2021 Hayden Kowalchuk, Hayden Kowalchuk 8 | * License: BSD 3-clause "New" or "Revised" License, http://www.opensource.org/licenses/BSD-3-Clause 9 | */ 10 | 11 | #pragma once 12 | 13 | typedef enum FLAGS_GENRE 14 | { 15 | GENRE_NONE = (0 << 0), // 0 16 | GENRE_ACTION = (1 << 0), // 1 17 | GENRE_RACING = (1 << 1), // 2 18 | GENRE_SIMULATION = (1 << 2), // 4 19 | GENRE_SPORTS = (1 << 3), // 8 20 | GENRE_LIGHTGUN = (1 << 4), // 16 21 | GENRE_FIGHTING = (1 << 5), // 32 22 | GENRE_SHOOTER = (1 << 6), // 64 23 | GENRE_SURVIVAL = (1 << 7), // 128 24 | GENRE_ADVENTURE = (1 << 8), // 256 25 | GENRE_PLATFORMER = (1 << 9), // 512 26 | GENRE_RPG = (1 << 10), // 1024 27 | GENRE_SHMUP = (1 << 11), // 2048 28 | GENRE_STRATEGY = (1 << 12), // 4096 29 | GENRE_PUZZLE = (1 << 13), // 8192 30 | GENRE_ARCADE = (1 << 14), // 16384 31 | GENRE_MUSIC = (1 << 15), // 32768 32 | } FLAGS_GENRE; 33 | 34 | typedef enum FLAGS_ACCESORIES 35 | { 36 | ACCESORIES_NONE = (0 << 0), // 0 37 | ACCESORIES_JUMP_PACK = (1 << 0), // 1 38 | ACCESORIES_KEYBOARD = (1 << 1), // 2 39 | ACCESORIES_VGA = (1 << 2), // 4 40 | ACCESORIES_MOUSE = (1 << 3), // 8 41 | ACCESORIES_MARACAS = (1 << 4), // 16 42 | ACCESORIES_RACING_WHEEL = (1 << 5), // 32 43 | ACCESORIES_MICROPHONE = (1 << 6), // 64 44 | ACCESORIES_ARCADE_STICK = (1 << 7), // 128 45 | ACCESORIES_LIGHTGUN = (1 << 8), // 256 46 | ACCESORIES_BBA = (1 << 9), // 512 47 | ACCESORIES_FISHING_ROD = (1 << 10), // 1024 48 | ACCESORIES_ASCII_PAD = (1 << 11), // 2048 49 | ACCESORIES_DREAMEYE = (1 << 12), // 4096 50 | ACCESORIES_MODEM = (1 << 13), // 8192 51 | ACCESORIES_UNUSED = (1 << 14), // 16384 52 | ACCESORIES_UNUSED2 = (1 << 15), // 32768 53 | } FLAGS_ACCESORIES; 54 | 55 | typedef struct db_item 56 | { 57 | unsigned char num_players; 58 | unsigned char vmu_blocks; 59 | unsigned char accessories; /* Accessories Described above */ 60 | unsigned char network; /* 0, none. 1, modem. 2, bba. 3, both */ 61 | unsigned short genre; /* Genres Described above */ 62 | char padding1; /*Currently Unused, for expansion */ 63 | char padding2; /*Currently Unused, for expansion */ 64 | char description[376]; 65 | } db_item; 66 | 67 | -------------------------------------------------------------------------------- /external/easing.h: -------------------------------------------------------------------------------- 1 | // 2 | // easing.h 3 | // 4 | // Copyright (c) 2011, Auerhaus Development, LLC 5 | // 6 | // This program is free software. It comes without any warranty, to 7 | // the extent permitted by applicable law. You can redistribute it 8 | // and/or modify it under the terms of the Do What The Fuck You Want 9 | // To Public License, Version 2, as published by Sam Hocevar. See 10 | // http://sam.zoy.org/wtfpl/COPYING for more details. 11 | // 12 | 13 | #ifndef AH_EASING_H 14 | #define AH_EASING_H 15 | 16 | #if defined(__LP64__) && !defined(AH_EASING_USE_DBL_PRECIS) 17 | #define AH_EASING_USE_DBL_PRECIS 18 | #endif 19 | 20 | #ifdef AH_EASING_USE_DBL_PRECIS 21 | #define AH_FLOAT_TYPE double 22 | #else 23 | #define AH_FLOAT_TYPE float 24 | #endif 25 | typedef AH_FLOAT_TYPE AHFloat; 26 | 27 | #if defined __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | typedef AHFloat (*AHEasingFunction)(AHFloat); 32 | 33 | // Linear interpolation (no easing) 34 | AHFloat LinearInterpolation(AHFloat p); 35 | 36 | // Quadratic easing; p^2 37 | AHFloat QuadraticEaseIn(AHFloat p); 38 | AHFloat QuadraticEaseOut(AHFloat p); 39 | AHFloat QuadraticEaseInOut(AHFloat p); 40 | 41 | // Cubic easing; p^3 42 | AHFloat CubicEaseIn(AHFloat p); 43 | AHFloat CubicEaseOut(AHFloat p); 44 | AHFloat CubicEaseInOut(AHFloat p); 45 | 46 | // Quartic easing; p^4 47 | AHFloat QuarticEaseIn(AHFloat p); 48 | AHFloat QuarticEaseOut(AHFloat p); 49 | AHFloat QuarticEaseInOut(AHFloat p); 50 | 51 | // Quintic easing; p^5 52 | AHFloat QuinticEaseIn(AHFloat p); 53 | AHFloat QuinticEaseOut(AHFloat p); 54 | AHFloat QuinticEaseInOut(AHFloat p); 55 | 56 | // Sine wave easing; sin(p * PI/2) 57 | AHFloat SineEaseIn(AHFloat p); 58 | AHFloat SineEaseOut(AHFloat p); 59 | AHFloat SineEaseInOut(AHFloat p); 60 | 61 | // Circular easing; sqrt(1 - p^2) 62 | AHFloat CircularEaseIn(AHFloat p); 63 | AHFloat CircularEaseOut(AHFloat p); 64 | AHFloat CircularEaseInOut(AHFloat p); 65 | 66 | // Exponential easing, base 2 67 | AHFloat ExponentialEaseIn(AHFloat p); 68 | AHFloat ExponentialEaseOut(AHFloat p); 69 | AHFloat ExponentialEaseInOut(AHFloat p); 70 | 71 | // Exponentially-damped sine wave easing 72 | AHFloat ElasticEaseIn(AHFloat p); 73 | AHFloat ElasticEaseOut(AHFloat p); 74 | AHFloat ElasticEaseInOut(AHFloat p); 75 | 76 | // Overshooting cubic easing; 77 | AHFloat BackEaseIn(AHFloat p); 78 | AHFloat BackEaseOut(AHFloat p); 79 | AHFloat BackEaseInOut(AHFloat p); 80 | 81 | // Exponentially-decaying bounce easing 82 | AHFloat BounceEaseIn(AHFloat p); 83 | AHFloat BounceEaseOut(AHFloat p); 84 | AHFloat BounceEaseInOut(AHFloat p); 85 | 86 | #ifdef __cplusplus 87 | } 88 | #endif 89 | 90 | #endif -------------------------------------------------------------------------------- /ui/draw_prototypes.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: draw_prototypes.h 3 | * Project: ui 4 | * File Created: Wednesday, 19th May 2021 9:33:13 pm 5 | * Author: Hayden Kowalchuk 6 | * ----- 7 | * Copyright (c) 2021 Hayden Kowalchuk, Hayden Kowalchuk 8 | * License: BSD 3-clause "New" or "Revised" License, http://www.opensource.org/licenses/BSD-3-Clause 9 | */ 10 | 11 | #include "common.h" 12 | 13 | #ifdef _arch_dreamcast 14 | #include "draw_kos.h" 15 | #else 16 | #include "draw_console.h" 17 | #endif 18 | 19 | struct dat_file; 20 | 21 | typedef struct dimen_RECT 22 | { 23 | int16_t x; 24 | int16_t y; 25 | int16_t w; 26 | int16_t h; 27 | } dimen_RECT; 28 | 29 | /* Called only once at start */ 30 | void draw_init(void); 31 | 32 | /* called at the start of each frame */ 33 | void draw_setup(void); 34 | 35 | /* Controls which list we are drawing into */ 36 | void draw_set_list(int list); 37 | int draw_get_list(void); 38 | 39 | /* returns default missing texture */ 40 | void *draw_load_missing_icon(void *user); 41 | /* Throws pass whatever is relevant to your platform as a pointer and it will filled + returned if successfull, otherwise NULL */ 42 | void *draw_load_texture(const char *filename, void *user); 43 | void *draw_load_texture_buffer(const char *filename, void *user, void *buffer); 44 | /* Loads from new DAT file using struct + ID of file requested */ 45 | void *draw_load_texture_from_DAT_to_buffer(const struct dat_file *bin, const char *ID, void *user, void *buffer); 46 | 47 | /* draws an image at coords of a given size */ 48 | void draw_draw_image(int x, int y, float width, float height, uint32_t color, void *user); 49 | /* draws an image centered at coords of a given size */ 50 | void draw_draw_image_centered(int x, int y, float width, float height, uint32_t color, void *user); 51 | /* draws an image at coords as a square */ 52 | void draw_draw_square(int x, int y, float size, uint32_t color, void *user); 53 | /* Draws part of an image specified in rect at the given coords of size */ 54 | void draw_draw_sub_image(int x, int y, float width, float height, uint32_t color, void *user, const dimen_RECT *rect); 55 | 56 | /* Draws untextured quad at coords with size and color(rgba) */ 57 | void draw_draw_quad(int x, int y, float width, float height, uint32_t color); 58 | 59 | /* exec proto */ 60 | struct gd_item; 61 | void bloom_launch(const struct gd_item *disc); 62 | void bleem_launch(const struct gd_item *disc); 63 | void dreamcast_launch_disc(const struct gd_item *disc); 64 | void dreamcast_launch_cb(const struct gd_item *disc); 65 | 66 | /* z depth */ 67 | float z_get(void); 68 | float z_set_cond(float z); 69 | float z_set(float z); 70 | float z_inc(void); 71 | void z_reset(void); 72 | -------------------------------------------------------------------------------- /texture/block_pool.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File: block_pool.c 3 | * Project: lru_cache 4 | * File Created: Thursday, 20th May 2021 5:27:40 pm 5 | * Author: Hayden Kowalchuk 6 | * ----- 7 | * Copyright (c) 2021 Hayden Kowalchuk, Hayden Kowalchuk 8 | * License: BSD 3-clause "New" or "Revised" License, http://www.opensource.org/licenses/BSD-3-Clause 9 | */ 10 | 11 | #include "block_pool.h" 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | static inline void _pool_mark_used(block_pool *pool, unsigned int slot_num) 18 | { 19 | pool->state[slot_num] = 1; 20 | } 21 | 22 | static inline void _pool_mark_open(block_pool *pool, unsigned int slot_num) 23 | { 24 | pool->state[slot_num] = 0; 25 | } 26 | 27 | void pool_create(block_pool *pool, void *buffer, unsigned int size, unsigned int slots) 28 | { 29 | const unsigned int state_size = sizeof(unsigned char) * slots; 30 | const unsigned int format_size = sizeof(slot_format) * slots; 31 | 32 | pool->base = buffer; 33 | pool->size = size; 34 | pool->slots = slots; 35 | pool->slot_size = size / slots; 36 | pool->state = malloc(state_size); 37 | 38 | if (!pool->state) 39 | { 40 | printf("%s no free memory\n", __func__); 41 | return; 42 | } 43 | 44 | pool->format = malloc(format_size); 45 | 46 | if (!pool->format) 47 | { 48 | printf("%s no free memory\n", __func__); 49 | return; 50 | } 51 | 52 | memset(pool->state, '\0', state_size); 53 | memset(pool->format, '\0', format_size); 54 | } 55 | 56 | void pool_get_next_free(block_pool *pool, unsigned int *slot_num, void **ptr) 57 | { 58 | for (unsigned int i = 0; i < pool->slots; i++) 59 | { 60 | if (!pool->state[i]) 61 | { 62 | _pool_mark_used(pool, i); 63 | 64 | if (slot_num) 65 | { 66 | *slot_num = i; 67 | } 68 | 69 | if (ptr) 70 | { 71 | *ptr = (void *)((uintptr_t)pool->base + i * pool->slot_size); 72 | } 73 | 74 | return; 75 | } 76 | } 77 | 78 | /* Error condition */ 79 | *slot_num = 0xFFFFFFFF; 80 | *ptr = NULL; 81 | } 82 | 83 | void pool_dealloc_all(block_pool *pool) 84 | { 85 | for (unsigned int i = 0; i < pool->slots; i++) 86 | { 87 | _pool_mark_open(pool, i); 88 | } 89 | } 90 | 91 | void pool_dealloc_slot(block_pool *pool, unsigned int slot_num) 92 | { 93 | if (slot_num < pool->slots) 94 | { 95 | _pool_mark_open(pool, slot_num); 96 | } 97 | } 98 | 99 | void pool_destroy_user(block_pool *pool, void (*user_free)(void *ptr)) 100 | { 101 | pool->base = NULL; 102 | pool->size = 0; 103 | pool->slots = 0; 104 | (*user_free)(pool->state); 105 | (*user_free)(pool->format); 106 | } 107 | 108 | void pool_destroy(block_pool *pool) 109 | { 110 | pool->base = NULL; 111 | pool->size = 0; 112 | pool->slots = 0; 113 | free(pool->state); 114 | free(pool->format); 115 | pool->state = NULL; 116 | pool->format = NULL; 117 | } 118 | 119 | -------------------------------------------------------------------------------- /ui/dc/input.h: -------------------------------------------------------------------------------- 1 | #ifndef INPUT_H 2 | #define INPUT_H 3 | /* 4 | * Filename: d:\Dev\Dreamcast\UB_SHARE\gamejam\game\src\common\input.h 5 | * Path: d:\Dev\Dreamcast\UB_SHARE\gamejam\game\src\common 6 | * Created Date: Saturday, July 6th 2019, 6:23:18 pm 7 | * Author: Hayden Kowalchuk 8 | * 9 | * Copyright (c) 2019 HaydenKow 10 | */ 11 | 12 | #include 13 | #include 14 | 15 | typedef enum 16 | { 17 | BTN_NULL = 0, 18 | BTN_A = 1, 19 | BTN_B = 2, 20 | BTN_X = 4, 21 | BTN_Y = 8, 22 | BTN_START = 16, 23 | } BUTTON; 24 | 25 | typedef enum 26 | { 27 | ACTION_NULL = 0, 28 | BTN_RELEASE = 32, 29 | BTN_PRESS = 64, 30 | BTN_HELD = 128, 31 | } ACTION_TYPE; 32 | 33 | typedef enum 34 | { 35 | DPAD_UP = 1, 36 | DPAD_DOWN = 2, 37 | DPAD_LEFT = 4, 38 | DPAD_RIGHT = 8, 39 | DPAD_UP_HELD = 16, 40 | DPAD_DOWN_HELD = 32, 41 | DPAD_LEFT_HELD = 64, 42 | DPAD_RIGHT_HELD = 128, 43 | } DPAD_DIRECTION; 44 | 45 | typedef enum 46 | { 47 | SHIFT_UP = 0, 48 | SHIFT_DOWN = 1, 49 | SHIFT_LEFT = 2, 50 | SHIFT_RIGHT = 3, 51 | } DPAD_SHIFT; 52 | 53 | typedef enum 54 | { 55 | AXES_NULL = 0, 56 | AXES_X = 1, 57 | AXES_Y = 2, 58 | } ANALOG_AXES; 59 | 60 | typedef enum 61 | { 62 | TRIGGER_NULL = 0, 63 | TRIGGER_L = 1, 64 | TRIGGER_R = 2, 65 | } TRIGGER; 66 | 67 | typedef uint8_t dpad_t; 68 | 69 | typedef struct __attribute__((packed)) inputs 70 | { 71 | uint8_t btn_a; 72 | uint8_t btn_b; 73 | uint8_t btn_x; 74 | uint8_t btn_y; 75 | uint8_t btn_start; 76 | uint8_t trg_left; /* Pressure Sensitive */ 77 | uint8_t trg_right; /* Pressure Sensitive */ 78 | dpad_t dpad; 79 | uint8_t axes_1; /* Main Analog X */ 80 | uint8_t axes_2; /* Main Analog Y */ 81 | /* Note the below may not exist on some platforms */ 82 | uint8_t axes_3; /* Secondary Analog X */ 83 | uint8_t axes_4; /* Secondary Analog Y */ 84 | } inputs; 85 | 86 | void INPT_ReceiveFromHost(inputs _in); 87 | 88 | bool INPT_Button(BUTTON btn); 89 | bool INPT_ButtonEx(BUTTON btn, ACTION_TYPE type); 90 | dpad_t INPT_DPAD(void); 91 | bool INPT_DPADDirection(DPAD_DIRECTION dir); 92 | float INPT_AnalogF(ANALOG_AXES axes); 93 | uint8_t INPT_AnalogI(ANALOG_AXES axes); 94 | bool INPT_TriggerPressed(TRIGGER trigger); 95 | uint8_t INPT_TriggerValue(TRIGGER trigger); 96 | 97 | /* Input Strings */ 98 | #ifdef _arch_dreamcast 99 | #define STRING_A_BTN "\x092" 100 | #define STRING_B_BTN "\x093" 101 | #define STRING_X_BTN "\x094" 102 | #define STRING_Y_BTN "\x095" 103 | #define STRING_START_BTN "\x090" 104 | #endif 105 | #if defined(WIN32) || defined(__linux__) 106 | #if 0 107 | #define STRING_A_BTN "V" 108 | #define STRING_B_BTN "C" 109 | #define STRING_X_BTN "X" 110 | #define STRING_Y_BTN "Z" 111 | #define STRING_START_BTN "/" 112 | #endif 113 | #define STRING_A_BTN "\x092" 114 | #define STRING_B_BTN "\x093" 115 | #define STRING_X_BTN "\x094" 116 | #define STRING_Y_BTN "\x095" 117 | #define STRING_START_BTN "\x090" 118 | #endif 119 | #ifdef PSP 120 | #define STRING_A_BTN "\x096" 121 | #define STRING_B_BTN "\x097" 122 | #define STRING_X_BTN "\x098" 123 | #define STRING_Y_BTN "\x099" 124 | #define STRING_START_BTN "\x091" 125 | #endif 126 | 127 | #endif /* INPUT_H */ 128 | -------------------------------------------------------------------------------- /ui/global_settings.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: global_settings.h 3 | * Project: ui 4 | * File Created: Monday, 12th July 2021 10:33:26 am 5 | * Author: Hayden Kowalchuk 6 | * ----- 7 | * Copyright (c) 2021 Hayden Kowalchuk, Hayden Kowalchuk 8 | * License: BSD 3-clause "New" or "Revised" License, http://www.opensource.org/licenses/BSD-3-Clause 9 | */ 10 | 11 | #pragma once 12 | 13 | #include 14 | #include 15 | 16 | #define SETTINGS_VERSION 2 17 | 18 | extern void exit_to_bios(void); 19 | extern int cb_multidisc; 20 | extern int start_cb; 21 | 22 | typedef enum CFG_REGION 23 | { 24 | REGION_START = 0, 25 | REGION_NTSC_U = REGION_START, 26 | REGION_NTSC_J, 27 | REGION_PAL, 28 | REGION_END = REGION_PAL, 29 | } CFG_REGION; 30 | 31 | typedef enum CFG_ASPECT 32 | { 33 | ASPECT_START = 0, 34 | ASPECT_NORMAL = ASPECT_START, 35 | ASPECT_WIDE, 36 | ASPECT_END = ASPECT_WIDE 37 | } CFG_ASPECT; 38 | 39 | typedef enum CFG_UI 40 | { 41 | UI_START = 0, 42 | UI_LINE_DESC = UI_START, 43 | UI_GRID3, 44 | UI_SCROLL, 45 | UI_END = UI_SCROLL 46 | } CFG_UI; 47 | 48 | typedef enum CFG_SORT 49 | { 50 | SORT_START = 0, 51 | SORT_DEFAULT = SORT_START, 52 | SORT_NAME, 53 | SORT_DATE, 54 | SORT_PRODUCT, 55 | SORT_END = SORT_PRODUCT 56 | } CFG_SORT; 57 | 58 | typedef enum CFG_FILTER 59 | { 60 | FILTER_START = 0, 61 | FILTER_ALL = FILTER_START, 62 | FILTER_ACTION, 63 | FILTER_RACING, 64 | FILTER_SIMULATION, 65 | FILTER_SPORTS, 66 | FILTER_LIGHTGUN, 67 | FILTER_FIGHTING, 68 | FILTER_SHOOTER, 69 | FILTER_SURVIVAL, 70 | FILTER_ADVENTURE, 71 | FILTER_PLATFORMER, 72 | FILTER_RPG, 73 | FILTER_SHMUP, 74 | FILTER_STRATEGY, 75 | FILTER_PUZZLE, 76 | FILTER_ARCADE, 77 | FILTER_MUSIC, 78 | FILTER_END = FILTER_MUSIC 79 | } CFG_FILTER; 80 | 81 | typedef enum CFG_BEEP 82 | { 83 | BEEP_START = 0, 84 | BEEP_OFF = BEEP_START, 85 | BEEP_ON, 86 | BEEP_END = BEEP_ON 87 | } CFG_BEEP; 88 | 89 | typedef enum CFG_MULTIDISC 90 | { 91 | MULTIDISC_START = 0, 92 | MULTIDISC_SHOW = MULTIDISC_START, 93 | MULTIDISC_HIDE, 94 | MULTIDISC_END = MULTIDISC_HIDE 95 | } CFG_MULTIDISC; 96 | 97 | typedef enum CFG_CUSTOM_THEME 98 | { 99 | THEME_START = 0, 100 | THEME_OFF = THEME_START, 101 | THEME_ON, 102 | THEME_END = THEME_ON 103 | } CFG_CUSTOM_THEME; 104 | 105 | typedef enum CFG_CUSTOM_THEME_NUM 106 | { 107 | THEME_NUM_START = 0, 108 | THEME_0 = THEME_NUM_START, 109 | THEME_1, 110 | THEME_2, 111 | THEME_3, 112 | THEME_4, 113 | THEME_5, 114 | THEME_6, 115 | THEME_7, 116 | THEME_8, 117 | THEME_9, 118 | THEME_NUM_END = THEME_9 119 | } CFG_CUSTOM_THEME_NUM; 120 | 121 | typedef struct openmenu_settings_s 122 | { 123 | char identifier[2]; /* OM */ 124 | uint8_t version; 125 | char region; 126 | char aspect; 127 | char ui; 128 | char sort; 129 | char filter; 130 | char beep; 131 | char multidisc; 132 | char custom_theme; 133 | uint8_t custom_theme_num; 134 | } openmenu_settings; 135 | 136 | typedef CFG_REGION region; 137 | 138 | enum draw_state 139 | { 140 | DRAW_UI = 0, 141 | DRAW_MULTIDISC, 142 | DRAW_EXIT, 143 | DRAW_MENU, 144 | DRAW_CREDITS, 145 | DRAW_CODEBREAKER 146 | }; 147 | 148 | void settings_init(void); 149 | void settings_load(void); 150 | void settings_save(void); 151 | openmenu_settings* settings_get(void); 152 | -------------------------------------------------------------------------------- /tools/reader.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File: reader.c 3 | * Project: dat_builder 4 | * File Created: Tuesday, 8th June 2021 2:47:35 pm 5 | * Author: Hayden Kowalchuk 6 | * ----- 7 | * Copyright (c) 2021 Hayden Kowalchuk, Hayden Kowalchuk 8 | * License: BSD 3-clause "New" or "Revised" License, http://www.opensource.org/licenses/BSD-3-Clause 9 | */ 10 | 11 | #ifdef COSMO 12 | #include "cosmo/cosmopolitan.h" 13 | #else 14 | #if defined(WIN32) || defined(WINNT) 15 | #include 16 | #define mkdir(A, B) mkdir(A) 17 | #endif 18 | #include 19 | #include 20 | #include 21 | #endif 22 | 23 | #define DEBUG (1) 24 | 25 | #include 26 | 27 | #include "../inc/dat_format.h" 28 | #include "../inc/dbgprint.h" 29 | /* Called: 30 | ./datread input.dat (-d) 31 | 32 | Dumps all info about the container, optionally dump to files in input/ 33 | */ 34 | 35 | #if defined(WIN32) || defined(WINNT) 36 | #define PATH_SEP "\\" 37 | #else 38 | #define PATH_SEP "/" 39 | #endif 40 | 41 | #define NUM_ARGS (1) 42 | 43 | void DAT_dump(const dat_file *bin, const char *output) { 44 | char out_filename[FILENAME_MAX] = {0}; 45 | mkdir(output, 777); 46 | uint8_t *file_buffer = malloc(bin->chunk_size); 47 | 48 | DBG_PRINT("BIN Stats:\nChunk Size: %d\nNum Chunks: %d\n\n", bin->chunk_size, bin->num_chunks); 49 | for (int i = 0; i < bin->num_chunks; i++) { 50 | DBG_PRINT("Record[%d] %s at 0x%X\n", bin->items[i].offset, bin->items[i].ID, bin->items[i].offset * bin->chunk_size); 51 | /* Create output filename */ 52 | strcpy(out_filename, output); 53 | strcat(out_filename, bin->items[i].ID); 54 | strcat(out_filename, ".pvr"); 55 | 56 | /* Read chunk to buffer */ 57 | int ret_f = fseek((FILE *)bin->handle, bin->items[i].offset * bin->chunk_size, SEEK_SET); 58 | int ret_r = fread(file_buffer, bin->chunk_size, 1, (FILE *)bin->handle); 59 | 60 | /* Write out */ 61 | FILE *fd = fopen(out_filename, "wb"); 62 | int ret_w = fwrite(file_buffer, bin->chunk_size, 1, fd); 63 | fclose(fd); 64 | } 65 | } 66 | 67 | int main(int argc, char **argv) { 68 | int dump_files = 0; 69 | char output_dir[FILENAME_MAX]; 70 | 71 | if (argc < NUM_ARGS + 1 /*binary itself*/) { 72 | printf("Incorrect usage!\n\t./datread input.dat (-d)\n"); 73 | return 1; 74 | } 75 | 76 | if ((argc == NUM_ARGS + 2) && !strcasecmp(argv[2], "-d")) { 77 | dump_files = 1; 78 | strcpy(output_dir, "." PATH_SEP); 79 | strcat(output_dir, argv[1]); 80 | char *dir_basename = strrchr(output_dir, '.'); 81 | if (dir_basename) { 82 | //*dir_basename = '\0'; 83 | memcpy(dir_basename, PATH_SEP, strlen(PATH_SEP) + 1); 84 | } 85 | } 86 | 87 | /* Basic Usage */ 88 | dat_file input_bin; 89 | DAT_init(&input_bin); 90 | DAT_load_parse(&input_bin, argv[1]); 91 | 92 | /* Dump info and files */ 93 | if (dump_files) { 94 | DAT_dump(&input_bin, output_dir); 95 | } else { 96 | DAT_info(&input_bin); 97 | } 98 | 99 | /* Hashmap test */ 100 | printf("\nSearching known:\n"); 101 | const char *search = "T40502N"; 102 | printf("Found %s at %X\n", search, DAT_get_offset_by_ID(&input_bin, search)); 103 | 104 | printf("\nSearching missing:\n"); 105 | const char *missing = "MISSING"; 106 | printf("Found %s at %X\n", missing, DAT_get_offset_by_ID(&input_bin, missing)); 107 | } 108 | -------------------------------------------------------------------------------- /ui/openmenu_vmu.h: -------------------------------------------------------------------------------- 1 | #ifndef __openmenu_icon__ 2 | #define __openmenu_icon__ 3 | 4 | //static unsigned int size_openmenu_icon = 512; 5 | static unsigned char openmenu_icon[] __attribute__((aligned(16))) = 6 | { 7 | 0xdc, 0xcc, 0x5c, 0xcc, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xc5, 0xcc, 0xcc, 0xc3, 0x57, 8 | 0xec, 0xcc, 0x5c, 0xcc, 0xee, 0xee, 0xee, 0xee, 0xe5, 0x55, 0x5e, 0xc5, 0xec, 0xcc, 0xcc, 0x32, 9 | 0xec, 0xcc, 0x5c, 0xcc, 0xee, 0xee, 0xee, 0xee, 0xe5, 0xcc, 0xce, 0xc5, 0xec, 0xcc, 0xcc, 0xc3, 10 | 0xec, 0x5c, 0x5c, 0xcc, 0xee, 0xee, 0xee, 0xee, 0xe5, 0xcc, 0xce, 0xc5, 0xec, 0xcc, 0xcc, 0xcc, 11 | 0xe5, 0x5c, 0x5c, 0xcc, 0xee, 0xee, 0xee, 0xee, 0xe5, 0xcc, 0xce, 0xc5, 0xec, 0xcc, 0xcc, 0xc5, 12 | 0xe5, 0x55, 0x5c, 0xcc, 0xee, 0xee, 0xee, 0xee, 0xe5, 0xcc, 0xce, 0xc5, 0xec, 0xcc, 0xcc, 0xc5, 13 | 0xec, 0x5c, 0x5c, 0xcc, 0xee, 0xee, 0xee, 0xee, 0xe5, 0xcc, 0xce, 0xc5, 0xec, 0xcc, 0xcc, 0xc5, 14 | 0xec, 0x5c, 0x5c, 0xcc, 0xee, 0xee, 0xee, 0xee, 0xe5, 0xcc, 0xce, 0xc5, 0xec, 0xcc, 0xcc, 0xc5, 15 | 0xec, 0xcc, 0x5c, 0xcc, 0xee, 0xee, 0xee, 0xee, 0xe5, 0xcc, 0xce, 0xc5, 0xec, 0xcc, 0xcc, 0xc5, 16 | 0xec, 0xcc, 0x5c, 0xcc, 0xce, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xc5, 0xcc, 0xcc, 0xcc, 0xc5, 17 | 0xec, 0xcc, 0xc5, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x5c, 0xcc, 0xcc, 0xcc, 0xc5, 18 | 0xec, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xc5, 19 | 0xec, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xc5, 20 | 0xec, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xc5, 21 | 0xec, 0xcc, 0xcc, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xcc, 0xcc, 0xc5, 22 | 0xec, 0xcc, 0xc5, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xc5, 0x5c, 0xcc, 0xc5, 23 | 0xec, 0xcc, 0x5c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc5, 0xcc, 0xc5, 24 | 0xec, 0xcc, 0x5c, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xc5, 0xcc, 0xc5, 25 | 0xec, 0xcc, 0x5c, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xc5, 0xec, 0xc5, 26 | 0xec, 0xcc, 0x5c, 0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xfe, 0xc5, 0xec, 0xc5, 27 | 0xec, 0xcc, 0x5c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc5, 0xec, 0xc5, 28 | 0xec, 0xcc, 0x5c, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xc5, 0xec, 0xc5, 29 | 0xec, 0xcc, 0x5c, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xc5, 0xec, 0xc5, 30 | 0xec, 0xcc, 0x5c, 0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xfe, 0xc5, 0xec, 0xc5, 31 | 0xec, 0xcc, 0x5c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc5, 0xec, 0xc5, 32 | 0xec, 0xcc, 0x5c, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xc5, 0xec, 0xc5, 33 | 0xec, 0xcc, 0x5c, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xc5, 0xec, 0xc5, 34 | 0xec, 0xcc, 0x5c, 0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xc5, 0xec, 0xc5, 35 | 0xe5, 0x5c, 0x5c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc5, 0xe8, 0x85, 36 | 0xec, 0xcc, 0x5c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc5, 0xec, 0xc5, 37 | 0xec, 0xcc, 0x5c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc5, 0xcc, 0xc5, 38 | 0xd5, 0x55, 0x55, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x56, 39 | }; 40 | #endif 41 | 42 | -------------------------------------------------------------------------------- /texture/simple_texture_allocator.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File: simple_texture_allocator.c 3 | * Project: texture 4 | * File Created: Friday, 18th June 2021 3:28:27 pm 5 | * Author: Hayden Kowalchuk 6 | * ----- 7 | * Copyright (c) 2021 Hayden Kowalchuk, Hayden Kowalchuk 8 | * License: BSD 3-clause "New" or "Revised" License, http://www.opensource.org/licenses/BSD-3-Clause 9 | */ 10 | 11 | #include "simple_texture_allocator.h" 12 | 13 | #include 14 | #include 15 | #include 16 | #include "../texture/txr_manager.h" 17 | 18 | static struct Simple_Texture textures[32]; 19 | static void *tex_buffer = NULL; 20 | static void *tex_buffer_start = NULL; 21 | static void *tex_buffer_max = NULL; 22 | static uint32_t tex_number = 0; 23 | 24 | static inline size_t getMemorySize(int width, int height, int bpp) 25 | { 26 | return (size_t)(bpp * width * height); 27 | } 28 | 29 | int texman_inited(void) 30 | { 31 | return tex_buffer != 0; 32 | } 33 | 34 | void texman_reset(void *buf, uint32_t size) 35 | { 36 | memset(textures, 0, sizeof(textures)); 37 | tex_number = 0; 38 | tex_buffer = tex_buffer_start = buf; 39 | tex_buffer_max = buf + size; 40 | #ifdef DEBUG 41 | char msg[64]; 42 | sprintf(msg, "TEXMAN: reset @ %p size %d bytes\n", buf, size); 43 | printf(msg); 44 | #endif 45 | } 46 | 47 | void texman_clear(void) 48 | { 49 | memset(textures, 0, sizeof(textures)); 50 | tex_number = 0; 51 | tex_buffer = tex_buffer_start; 52 | #ifdef DEBUG 53 | char msg[64]; 54 | sprintf(msg, "TEXMAN: clear %p size %d bytes!\n", tex_buffer, TEXMAN_BUFFER_SIZE); 55 | printf(msg); 56 | #endif 57 | } 58 | 59 | void texman_set_buffer(void *buf, uint32_t size) 60 | { 61 | tex_buffer = buf; 62 | tex_buffer_max = buf + size; 63 | } 64 | 65 | int texman_get_space_available(void) 66 | { 67 | return (tex_buffer_max - tex_buffer); 68 | } 69 | 70 | int texman_is_space_available(void) 71 | { 72 | return (tex_buffer_max - tex_buffer) > (32 * 1024); 73 | } 74 | 75 | unsigned char *texman_get_tex_data(uint32_t num) 76 | { 77 | return textures[num].location; 78 | } 79 | 80 | struct Simple_Texture *texman_reserve_memory(uint32_t width, uint32_t height, int bpp) 81 | { 82 | if(texman_is_space_available()) 83 | { 84 | size_t tex_size = getMemorySize(width, height, bpp); 85 | tex_buffer = (void *)((((size_t)tex_buffer + tex_size + TEX_ALIGNMENT - 1) / TEX_ALIGNMENT) * TEX_ALIGNMENT); 86 | #ifdef DEBUG 87 | printf("TEX_MAN: tex [%d] reserved %d bytes @ %x left: %d kb\n", tex_number, tex_size, (uint32_t)textures[tex_number].location, (tex_buffer_max - tex_buffer) / 1024); 88 | #endif 89 | } 90 | else 91 | { 92 | printf("TEX_MAN: potential memory overrun! free space: %d bytes\n", texman_get_space_available()); 93 | } 94 | 95 | return &textures[tex_number]; 96 | } 97 | 98 | uint32_t texman_create(void) 99 | { 100 | tex_number++; 101 | textures[tex_number] = (struct Simple_Texture) 102 | { 103 | location : tex_buffer, 104 | width : 0, 105 | height : 0 106 | }; 107 | 108 | #ifdef DEBUG 109 | printf("TEX_MAN: new tex [%d] @ %x\n", tex_number, tex_buffer); 110 | #endif 111 | return tex_number; 112 | } 113 | 114 | void texman_upload(uint32_t width, uint32_t height, int bpp, const void *buffer) 115 | { 116 | struct Simple_Texture *current = texman_reserve_memory(width, height, bpp); 117 | current->width = width; 118 | current->height = height; 119 | memcpy(current->location, buffer, getMemorySize(width, height, bpp)); 120 | } 121 | 122 | -------------------------------------------------------------------------------- /texture/lru.c: -------------------------------------------------------------------------------- 1 | #include "lru.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #if DEBUG 8 | #define DBG_PRINT(...) printf(__VA_ARGS__) 9 | #else 10 | #define DBG_PRINT(...) 11 | #endif 12 | 13 | /* Missing on sh-elf-gcc 9.1 ? */ 14 | char *strdup(const char *s); 15 | 16 | // this is an example of how to do a LRU cache in C using uthash 17 | // http://uthash.sourceforge.net/ 18 | // by Jehiah Czebotar 2011 - jehiah@gmail.com 19 | // this code is in the public domain http://unlicense.org/ 20 | 21 | void cache_set_size(cache_instance *cache, int size) 22 | { 23 | cache->cache_max_size = size; 24 | } 25 | 26 | void cache_callback_userdata(cache_instance *cache, void *user) 27 | { 28 | cache->callback_data = user; 29 | } 30 | 31 | void cache_callback_add(cache_instance *cache, user_add_cb callback) 32 | { 33 | cache->callback_add = callback; 34 | } 35 | 36 | void cache_callback_del(cache_instance *cache, user_del_cb callback) 37 | { 38 | cache->callback_del = callback; 39 | } 40 | 41 | int find_in_cache(cache_instance *cache, const char *key) 42 | { 43 | struct CacheEntry *entry; 44 | 45 | if (!cache || !key) 46 | { 47 | return -1; 48 | } 49 | 50 | HASH_FIND_STR(cache->cache, key, entry); 51 | 52 | if (entry) 53 | { 54 | // remove it (so the subsequent add will throw it on the front of the list) 55 | 56 | if (entry != cache->cache) 57 | { 58 | HASH_DELETE(hh, cache->cache, entry); 59 | HASH_ADD_STR(cache->cache, key, entry); 60 | } 61 | 62 | return entry->value; 63 | } 64 | 65 | return -1; 66 | } 67 | 68 | void add_to_cache(cache_instance *cache, const char *key, int value) 69 | { 70 | DBG_PRINT("+%s( %s )\n", __func__, key); 71 | struct CacheEntry *entry, *tmp_entry, *new_entry; 72 | unsigned int cb_return = 0xFFFFFFFF; 73 | 74 | /* Call user function */ 75 | if (cache->callback_add) 76 | { 77 | cb_return = (*cache->callback_add)(key, cache->callback_data); 78 | } 79 | 80 | entry = calloc(1, sizeof(struct CacheEntry)); 81 | 82 | if (!entry) 83 | { 84 | printf("%s no free memory\n", __func__); 85 | return; 86 | } 87 | 88 | entry->key = strdup(key); 89 | 90 | if (cb_return != 0xFFFFFFFF) 91 | { 92 | value = cb_return; 93 | } 94 | 95 | entry->value = value; 96 | new_entry = entry; 97 | HASH_ADD_STR(cache->cache, key, entry); 98 | 99 | // prune the cache to cache_max_size 100 | if (HASH_COUNT(cache->cache) > cache->cache_max_size) 101 | { 102 | HASH_ITER(hh, cache->cache, entry, tmp_entry) 103 | { 104 | // prune the first entry (loop is based on insertion order so this deletes the oldest item) 105 | HASH_DELETE(hh, cache->cache, entry); 106 | DBG_PRINT("-del_from_cache( %s )\n", key); 107 | 108 | if (cache->callback_del) 109 | { 110 | (*cache->callback_del)(entry->key, &entry->value, cache->callback_data); 111 | if (cache->callback_add) 112 | { 113 | cb_return = (*cache->callback_add)(key, cache->callback_data); 114 | } 115 | new_entry->value = cb_return; 116 | } 117 | 118 | free(entry->key); 119 | free(entry); 120 | break; 121 | } 122 | } 123 | } 124 | 125 | void empty_cache(cache_instance *cache) 126 | { 127 | struct CacheEntry *entry, *tmp_entry; 128 | HASH_ITER(hh, cache->cache, entry, tmp_entry) 129 | { 130 | // prune all entries 131 | HASH_DELETE(hh, cache->cache, entry); 132 | DBG_PRINT("-del_from_cache( %s )\n", key); 133 | 134 | if (cache->callback_del) 135 | { 136 | (*cache->callback_del)(entry->key, &entry->value, cache->callback_data); 137 | } 138 | 139 | free(entry->key); 140 | free(entry); 141 | } 142 | } 143 | 144 | -------------------------------------------------------------------------------- /tools/packer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File: packer.c 3 | * Project: dat_builder 4 | * File Created: Tuesday, 8th June 2021 2:32:46 pm 5 | * Author: Hayden Kowalchuk 6 | * ----- 7 | * Copyright (c) 2021 Hayden Kowalchuk, Hayden Kowalchuk 8 | * License: BSD 3-clause "New" or "Revised" License, http://www.opensource.org/licenses/BSD-3-Clause 9 | */ 10 | 11 | #ifdef COSMO 12 | #include "cosmo/cosmopolitan.h" 13 | #else 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #endif 24 | 25 | #include "dat_packer_interface.h" 26 | 27 | /* Called: 28 | ./datpack FOLDER output.dat 29 | 30 | packs the items in the folder into the output.bin 31 | */ 32 | 33 | #define NUM_ARGS (2) 34 | 35 | /* Locals */ 36 | static bin_header file_header; 37 | static bin_item_raw *bin_items; 38 | static unsigned char *data_buf; 39 | 40 | int add_pvr_file(const char *path, const char *folder, struct stat *statptr) { 41 | char temp_id[12]; 42 | char temp_file[FILENAME_MAX]; 43 | 44 | if (file_header.chunk_size == 0) { 45 | file_header.chunk_size = (uint32_t)statptr->st_size; 46 | data_buf = malloc(file_header.chunk_size * file_header.padding0); /* Temporarily use padding0 as num_files */ 47 | } else { 48 | if (statptr->st_size != file_header.chunk_size) { 49 | printf("Err: Filesize mismatch for %s, found %ld vs %d!\n", path, statptr->st_size, file_header.chunk_size); 50 | return -1; 51 | } 52 | } 53 | /* Check if filename too long, dont try to reconcile, just skip */ 54 | char *dot = strrchr(path, '.'); 55 | if ((size_t)dot - (size_t)path > 11) { 56 | printf("Err: filename too long \"%s\", maxlength = 11!\n", path); 57 | return -1; 58 | } 59 | 60 | temp_file[0] = '\0'; 61 | strcpy(temp_file, folder); 62 | strcat(temp_file, PATH_SEP); 63 | strcat(temp_file, path); 64 | FILE *temp_fd = fopen(temp_file, "rb"); 65 | if (!temp_fd) { 66 | printf("ERR: cant read %s\n", temp_file); 67 | return -1; 68 | } 69 | fread(data_buf + (file_header.num_chunks * file_header.chunk_size), file_header.chunk_size, 1, temp_fd); 70 | fclose(temp_fd); 71 | 72 | /* Use filename as ID, remove extension */ 73 | printf("Working on %s\n", path); 74 | memset(temp_id, '\0', sizeof(temp_id)); 75 | strncpy(temp_id, path, 11); 76 | char *end = strrchr(temp_id, '.'); 77 | if (end) { 78 | const size_t nul_len = sizeof(temp_id) - ((size_t)end - (size_t)temp_id); 79 | memset(end, '\0', nul_len); 80 | } 81 | char *temp_start = temp_id; 82 | while (*temp_start) 83 | *temp_start++ = toupper(*temp_start); 84 | temp_id[11] = '\0'; 85 | temp_id[10] = '\0'; 86 | memcpy(&bin_items[file_header.num_chunks].ID, temp_id, sizeof(bin_items->ID)); 87 | 88 | bin_items[file_header.num_chunks].offset = file_header.num_chunks + 1; 89 | (void)file_header.num_chunks++; 90 | 91 | printf("Added[%d] as %s\n", file_header.num_chunks, temp_id); 92 | } 93 | 94 | int main(int argc, char **argv) { 95 | if (argc < NUM_ARGS + 1 /*binary itself*/) { 96 | printf("Incorrect usage!\n\t./datpack FOLDER output.dat\n"); 97 | return 1; 98 | } 99 | 100 | /* Setup file constraints */ 101 | memcpy(&file_header.magic.rich.alpha, "DAT", 3); 102 | file_header.magic.rich.version = 1; 103 | file_header.chunk_size = 0; 104 | file_header.num_chunks = 0; 105 | file_header.padding0 = 0; 106 | 107 | open_output(argv[2]); 108 | iterate_dir(argv[1], add_pvr_file, &file_header, &bin_items); 109 | file_header.padding0 = 0; 110 | write_bin_file(&file_header, bin_items, data_buf); 111 | 112 | return EXIT_SUCCESS; 113 | } -------------------------------------------------------------------------------- /tools/Makefile: -------------------------------------------------------------------------------- 1 | CC := gcc 2 | OBJCOPY := objcopy 3 | INCS := -I../ 4 | DEFINES := -DSTANDALONE_BINARY=1 5 | CFLAGS_COSMO := -g -Os -static -nostdlib -nostdinc -fno-pie -no-pie -mno-red-zone -fno-omit-frame-pointer -pg -mnop-mcount -DCOSMO $(INCS) $(DEFINES) 6 | LDFLAGS_COSMO := -fuse-ld=bfd -Wl,-T,cosmo/ape.lds -include cosmo/cosmopolitan.h cosmo/crt.o cosmo/ape.o cosmo/cosmopolitan.a 7 | CFLAGS := -O2 -s $(INCS) $(DEFINES) -Wno-unused-result 8 | 9 | all: datread datpack metapack datstrip tsv2ini renamecsv menufaker 10 | 11 | .PHONY: win 12 | win: CC:=x86_64-w64-mingw32-gcc 13 | win: native 14 | 15 | .PHONY: cosmo 16 | cosmo: datread.com datpack.com metapack.com datstrip.com tsv2ini.com renamecsv.com menufaker.com 17 | 18 | .PHONY: native 19 | native: datread$(EXT) datpack$(EXT) metapack$(EXT) datstrip$(EXT) tsv2ini$(EXT) renamecsv$(EXT) menufaker$(EXT) 20 | 21 | datread.com: reader.c ../texture/dat_reader.c 22 | @echo "$(CC) $<" 23 | @$(CC) $(CFLAGS_COSMO) -o $@.dbg $^ $(LDFLAGS_COSMO) 24 | @$(OBJCOPY) -S -O binary $@.dbg $@ 25 | @echo "$(OBJCOPY) $@.dbg -> $@" 26 | 27 | datpack.com: packer.c dat_packer_internal.c 28 | @echo "$(CC) $<" 29 | @$(CC) $(CFLAGS_COSMO) -o $@.dbg $^ $(LDFLAGS_COSMO) 30 | @$(OBJCOPY) -S -O binary $@.dbg $@ 31 | @echo "$(OBJCOPY) $@.dbg -> $@" 32 | 33 | metapack.com: metapacker.c dat_packer_internal.c ../external/ini.c 34 | @echo "$(CC) $<" 35 | @$(CC) $(CFLAGS_COSMO) -o $@.dbg $^ $(LDFLAGS_COSMO) 36 | @$(OBJCOPY) -S -O binary $@.dbg $@ 37 | @echo "$(OBJCOPY) $@.dbg -> $@" 38 | 39 | datstrip.com: stripper.c ../backend/gd_list.c ../external/ini.c 40 | @echo "$(CC) $<" 41 | @$(CC) $(CFLAGS_COSMO) -o $@.dbg $^ $(LDFLAGS_COSMO) 42 | @$(OBJCOPY) -S -O binary $@.dbg $@ 43 | @echo "$(OBJCOPY) $@.dbg -> $@" 44 | 45 | tsv2ini.com: tsv_to_txt_ini.c 46 | @echo "$(CC) $<" 47 | @$(CC) $(CFLAGS_COSMO) -o $@.dbg $^ $(LDFLAGS_COSMO) 48 | @$(OBJCOPY) -S -O binary $@.dbg $@ 49 | @echo "$(OBJCOPY) $@.dbg -> $@" 50 | 51 | renamecsv.com: renamecsv.c 52 | @echo "$(CC) $<" 53 | @$(CC) $(CFLAGS_COSMO) -o $@.dbg $^ $(LDFLAGS_COSMO) 54 | @$(OBJCOPY) -S -O binary $@.dbg $@ 55 | @echo "$(OBJCOPY) $@.dbg -> $@" 56 | 57 | menufaker.com: menufaker.c 58 | @echo "$(CC) $<" 59 | @$(CC) $(CFLAGS_COSMO) -o $@.dbg $^ $(LDFLAGS_COSMO) 60 | @$(OBJCOPY) -S -O binary $@.dbg $@ 61 | @echo "$(OBJCOPY) $@.dbg -> $@" 62 | 63 | datread$(EXT): reader.c ../texture/dat_reader.c 64 | @echo "$(CC) $<" 65 | @$(CC) $(CFLAGS) -o $@ $^ 66 | @echo "> $@" 67 | 68 | datpack$(EXT): packer.c dat_packer_internal.c 69 | @echo "$(CC) $<" 70 | @$(CC) $(CFLAGS) -o $@ $^ 71 | @echo "> $@" 72 | 73 | metapack$(EXT): metapacker.c dat_packer_internal.c ../external/ini.c 74 | @echo "$(CC) $<" 75 | @$(CC) $(CFLAGS) -o $@ $^ 76 | @echo "> $@" 77 | 78 | tsv2ini$(EXT): tsv_to_txt_ini.c 79 | @echo "$(CC) $<" 80 | @$(CC) $(CFLAGS) -o $@ $^ 81 | @echo "> $@" 82 | 83 | renamecsv$(EXT): renamecsv.c 84 | @echo "$(CC) $<" 85 | @$(CC) $(CFLAGS) -o $@ $^ 86 | @echo "> $@" 87 | 88 | datstrip$(EXT): stripper.c ../backend/gd_list.c ../external/ini.c 89 | @echo "$(CC) $<" 90 | @$(CC) $(CFLAGS) -o $@ $^ 91 | @echo "> $@" 92 | 93 | menufaker$(EXT): menufaker.c 94 | @echo "$(CC) $<" 95 | @$(CC) $(CFLAGS) -o $@ $^ 96 | @echo "> $@" 97 | 98 | .PHONY: clean 99 | clean: 100 | -rm -f datread.com.dbg datpack.com.dbg metapack.com.dbg datstrip.com.dbg menufaker.com.dbg tsv2ini.com.dbg renamecsv.com.dbg 101 | 102 | .PHONY: win-distclean 103 | win-distclean: EXT = .exe 104 | win-distclean: distclean 105 | 106 | .PHONY: distclean 107 | distclean: clean 108 | -rm -f datread.com datpack.com metapack.com datstrip.com menufaker.com tsv2ini.com renamecsv.com datread$(EXT) datpack$(EXT) metapack$(EXT) datstrip$(EXT) menufaker$(EXT) tsv2ini$(EXT) renamecsv$(EXT) 109 | 110 | -------------------------------------------------------------------------------- /tools/dat_packer_internal.c: -------------------------------------------------------------------------------- 1 | #ifdef COSMO 2 | #include "cosmo/cosmopolitan.h" 3 | #else 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #endif 14 | 15 | #include "dat_packer_interface.h" 16 | 17 | static FILE *out_fd; 18 | 19 | void open_output(const char *path) { 20 | out_fd = fopen(path, "wb"); 21 | if (!out_fd) { 22 | printf("ERR: unable to open %s for writing!\n", path); 23 | } 24 | } 25 | 26 | void write_bin_file(bin_header *file_header, bin_item_raw *bin_items, void *data_buf) { 27 | printf("Writing:"); 28 | /* Write header */ 29 | printf("header.."); 30 | fwrite(file_header, sizeof(bin_header), 1, out_fd); 31 | /* Write file list */ 32 | printf("item list.."); 33 | fwrite(bin_items, sizeof(bin_item_raw), file_header->num_chunks, out_fd); 34 | /* Write padding out to first chunk offset */ 35 | printf("padding.."); 36 | int padding_size = ((file_header->padding0 + 1) * file_header->chunk_size) - ftell(out_fd); 37 | char *nul = calloc(1, padding_size); 38 | fwrite(nul, padding_size, 1, out_fd); 39 | free(nul); 40 | /* Write out all chunks */ 41 | if (ftell(out_fd) % file_header->chunk_size != 0) { 42 | printf("\nDAT:Corrupted Header while writing!\n"); 43 | fclose(out_fd); 44 | return; 45 | } 46 | printf("chunks.."); 47 | fwrite(data_buf, file_header->num_chunks * file_header->chunk_size, 1, out_fd); 48 | 49 | fclose(out_fd); 50 | printf("done!\n"); 51 | } 52 | 53 | static int print_cb(const char *path, const char *folder, struct stat *statptr) { 54 | printf("%s\n", path); 55 | } 56 | 57 | int iterate_dir(const char *path, int (*file_cb)(const char *, const char *, struct stat *), bin_header *file_header, bin_item_raw **bin_items) { 58 | struct dirent *dp; 59 | struct stat statbuf; 60 | char pathbuf[FILENAME_MAX]; 61 | uint32_t num_files_found; 62 | 63 | DIR *dir = opendir(path); 64 | 65 | if (file_cb == NULL) { 66 | file_cb = print_cb; 67 | } 68 | 69 | // Unable to open directory stream 70 | if (!dir) 71 | return -1; 72 | 73 | /* Loop twice, first time to count then second time to add */ 74 | num_files_found = 0; 75 | while ((dp = readdir(dir)) != NULL) { 76 | /* ignore these */ 77 | if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) 78 | continue; 79 | 80 | /* create proper full path */ 81 | getcwd(pathbuf, FILENAME_MAX); 82 | strcat(pathbuf, PATH_SEP); 83 | strcat(pathbuf, path); 84 | strcat(pathbuf, PATH_SEP); 85 | strcat(pathbuf, dp->d_name); 86 | if (stat(pathbuf, &statbuf) == -1) { 87 | printf("ERR: errno = %d\n", errno); 88 | return -1; 89 | } 90 | 91 | /* only check files */ 92 | if (S_ISREG(statbuf.st_mode)) { 93 | num_files_found++; 94 | } 95 | } 96 | #ifdef COSMO 97 | closedir(dir); 98 | dir = opendir(path); 99 | #else 100 | rewinddir(dir); 101 | #endif 102 | 103 | file_header->padding0 = num_files_found; 104 | *bin_items = malloc(sizeof(bin_item_raw) * num_files_found); 105 | 106 | while ((dp = readdir(dir)) != NULL) { 107 | /* ignore these */ 108 | if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) 109 | continue; 110 | 111 | /* create proper full path */ 112 | getcwd(pathbuf, FILENAME_MAX); 113 | strcat(pathbuf, PATH_SEP); 114 | strcat(pathbuf, path); 115 | strcat(pathbuf, PATH_SEP); 116 | strcat(pathbuf, dp->d_name); 117 | if (stat(pathbuf, &statbuf) == -1) { 118 | printf("ERR: errno = %d\n", errno); 119 | return -1; 120 | } 121 | 122 | /* only check files */ 123 | if (S_ISREG(statbuf.st_mode)) { 124 | (*file_cb)(dp->d_name, path, &statbuf); 125 | } 126 | } 127 | 128 | closedir(dir); 129 | } -------------------------------------------------------------------------------- /vm2_api.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "inc/vm2_api.h" 7 | 8 | static uint8_t recv_buff[196]; 9 | 10 | static void vbl_allinfo_callback(maple_state_t *state, maple_frame_t * frm) 11 | { 12 | maple_response_t *resp; 13 | (void) state; 14 | 15 | /* So.. did we get a response? */ 16 | resp = (maple_response_t *)frm->recv_buf; 17 | 18 | if (resp->response == MAPLE_RESPONSE_ALLINFO) 19 | { 20 | /* Copy in the new buff */ 21 | memcpy(recv_buff, resp, 196); 22 | } 23 | 24 | maple_frame_unlock(frm); 25 | genwait_wake_all(frm); 26 | } 27 | 28 | /* Send a ALLINFO command for the given port/unit */ 29 | static int send_allinfo(maple_device_t * dev) 30 | { 31 | // Reserve access; if we don't get it, forget about it 32 | if (maple_frame_lock(&dev->frame) < 0) 33 | { 34 | return -1; 35 | } 36 | 37 | // Setup our autodetect frame to probe at a new device 38 | maple_frame_init(&dev->frame); 39 | dev->frame.cmd = MAPLE_COMMAND_ALLINFO; 40 | dev->frame.dst_port = dev->port; 41 | dev->frame.dst_unit = dev->unit; 42 | dev->frame.callback = vbl_allinfo_callback; 43 | maple_queue_frame(&dev->frame); 44 | 45 | /* Wait for the VM2 to accept it */ 46 | if(genwait_wait(&dev->frame, "vmu_get_allinfo", 200, NULL) < 0) 47 | { 48 | if(dev->frame.state != MAPLE_FRAME_UNSENT) 49 | { 50 | /* It's probably never coming back, so just unlock the frame */ 51 | dev->frame.state = MAPLE_FRAME_VACANT; 52 | /*dbglog(DBG_ERROR, */printf("send_allinfo: timeout to unit %c%c\n", dev->port + 'A', dev->unit + '0'); 53 | return MAPLE_ETIMEOUT; 54 | } 55 | } 56 | 57 | return MAPLE_EOK; 58 | } 59 | 60 | static void vm2_reply(maple_state_t *state, maple_frame_t * frm) 61 | { 62 | maple_response_t *resp; 63 | (void) state; 64 | 65 | /* So.. did we get a response? */ 66 | resp = (maple_response_t *)frm->recv_buf; 67 | 68 | if (resp->response != MAPLE_RESPONSE_OK) 69 | { 70 | printf("maple: bad response %d on device, wait ACK\n",resp->response); 71 | } 72 | 73 | memcpy(recv_buff, resp, 4); 74 | 75 | maple_frame_unlock(frm); 76 | genwait_wake_all(frm); 77 | } 78 | 79 | int vm2_set_id(maple_device_t * dev, const char *ID, const char *name) 80 | { 81 | maple_response_t *resp; 82 | uint32_t *send_buf; 83 | 84 | wait_vm2: 85 | 86 | if(maple_frame_lock(&dev->frame) < 0) 87 | return 0; 88 | 89 | maple_frame_init(&dev->frame); 90 | send_buf = (uint32_t *)dev->frame.recv_buf; 91 | send_buf[0] = MAPLE_FUNC_MEMCARD; 92 | strncpy((char *) &dev->frame.recv_buf[4], ID, 12); 93 | if (name) 94 | { 95 | strncpy((char *) &dev->frame.recv_buf[16], name, 128); 96 | } 97 | dev->frame.cmd = 33; 98 | dev->frame.dst_port = dev->port; 99 | dev->frame.dst_unit = dev->unit; 100 | dev->frame.length = name ? 36 : 4; 101 | dev->frame.callback = vm2_reply; 102 | dev->frame.send_buf = send_buf; 103 | maple_queue_frame(&dev->frame); 104 | 105 | /* Wait for the VM2 to accept it */ 106 | if(genwait_wait(&dev->frame, "vm2_set_id", 200, NULL) < 0) 107 | { 108 | if(dev->frame.state != MAPLE_FRAME_UNSENT) 109 | { 110 | /* It's probably never coming back, so just unlock the frame */ 111 | dev->frame.state = MAPLE_FRAME_VACANT; 112 | dbglog(DBG_ERROR, "vm2_set_id: timeout to unit %c%c\n", dev->port + 'A', dev->unit + '0'); 113 | return -1; 114 | } 115 | } 116 | 117 | resp = (maple_response_t *) recv_buff; 118 | 119 | if (resp->response == MAPLE_RESPONSE_OK) 120 | { 121 | return 0; 122 | } 123 | else if (resp->response == MAPLE_RESPONSE_AGAIN) 124 | { 125 | goto wait_vm2; 126 | } 127 | 128 | return -1; 129 | } 130 | 131 | int check_vm2_present(maple_device_t * dev) 132 | { 133 | /* Clear the old buffer */ 134 | memset(recv_buff, 0, 196); 135 | 136 | if (send_allinfo(dev) != MAPLE_EOK) 137 | { 138 | return 0; 139 | } 140 | 141 | maple_alldevinfo_t *info = (maple_alldevinfo_t *) &recv_buff[4]; 142 | 143 | if (!strncasecmp(info->extended, "VM2 by Dreamware", 16) || 144 | !strncasecmp(info->extended, "USB RP2040 EMU ", 16)) 145 | { 146 | return 1; 147 | } 148 | 149 | return 0; 150 | } 151 | 152 | -------------------------------------------------------------------------------- /tools/menufaker.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File: menufaker.c 3 | * Project: tools 4 | * File Created: Friday, 18th June 2021 11:02:52 am 5 | * Author: Hayden Kowalchuk 6 | * ----- 7 | * Copyright (c) 2021 Hayden Kowalchuk, Hayden Kowalchuk 8 | * License: BSD 3-clause "New" or "Revised" License, http://www.opensource.org/licenses/BSD-3-Clause 9 | */ 10 | #ifdef COSMO 11 | #include "cosmo/cosmopolitan.h" 12 | #else 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #endif 20 | 21 | /* Called: 22 | ./menufaker filelist.csv 23 | 24 | reads filelist.csv and creates a full OPENMENU.INI from it 25 | */ 26 | 27 | /* Compile: 28 | x86_64-w64-mingw32-gcc menufaker.c -Os -s -o menufaker.exe 29 | gcc menufaker.c -Os -s -o menufaker 30 | */ 31 | 32 | #ifdef WIN32 33 | /* This code is public domain -- Will Hartung 4/9/09 */ 34 | size_t getline(char **lineptr, size_t *n, FILE *stream) { 35 | char *bufptr = NULL; 36 | char *p = bufptr; 37 | size_t size; 38 | int c; 39 | 40 | if (lineptr == NULL) { 41 | return -1; 42 | } 43 | if (stream == NULL) { 44 | return -1; 45 | } 46 | if (n == NULL) { 47 | return -1; 48 | } 49 | bufptr = *lineptr; 50 | size = *n; 51 | 52 | c = fgetc(stream); 53 | if (c == EOF) { 54 | return -1; 55 | } 56 | if (bufptr == NULL) { 57 | bufptr = malloc(128); 58 | if (bufptr == NULL) { 59 | return -1; 60 | } 61 | size = 128; 62 | } 63 | p = bufptr; 64 | while (c != EOF) { 65 | if ((p - bufptr) > (size - 1)) { 66 | size = size + 128; 67 | bufptr = realloc(bufptr, size); 68 | if (bufptr == NULL) { 69 | return -1; 70 | } 71 | } 72 | *p++ = c; 73 | if (c == '\n') { 74 | break; 75 | } 76 | c = fgetc(stream); 77 | } 78 | 79 | *p++ = '\0'; 80 | *lineptr = bufptr; 81 | *n = size; 82 | 83 | return p - bufptr - 1; 84 | } 85 | #endif 86 | 87 | static void ini_write_header(int num_games, FILE *fd) { 88 | const char *items_header = 89 | "[ITEMS]\n" 90 | "01.name=openMenu\n" 91 | "01.disc=1/1\n" 92 | "01.vga=1\n" 93 | "01.region=JUE\n" 94 | "01.version=V0.1.0\n" 95 | "01.date=20210609\n" 96 | "01.product=NEODC_1\n\n"; 97 | fwrite("[OPENMENU]\nnum_items=", strlen("[OPENMENU]\nnum_items="), 1, fd); 98 | fprintf(fd, "%d\n\n", num_games); 99 | fwrite(items_header, strlen(items_header), 1, fd); 100 | } 101 | 102 | static void ini_add_game(int num, const char *product_id, const char *name, FILE *fd) { 103 | const char *game_template = 104 | "%02d.name=%s\n" 105 | "%02d.disc=1/1\n" 106 | "%02d.vga=1\n" 107 | "%02d.region=JUE\n" 108 | "%02d.version=V0.1.0\n" 109 | "%02d.date=20210609\n" 110 | "%02d.product=%s\n\n"; 111 | fprintf(fd, game_template, num, name, num, num, num, num, num, num, product_id); 112 | } 113 | 114 | #define NUM_ARGS (1) 115 | 116 | int main(int argc, char **argv) { 117 | if (argc < NUM_ARGS + 1 /*binary itself*/) { 118 | printf("Incorrect usage!\n\t./menufaker filelist.csv\n"); 119 | return 1; 120 | } 121 | 122 | const char *csv_file = argv[1]; 123 | char filename_temp[FILENAME_MAX]; 124 | char filename_temp2[FILENAME_MAX]; 125 | 126 | FILE *csv_fd, *ini_fd; 127 | char *line = malloc(FILENAME_MAX); 128 | size_t len = FILENAME_MAX; 129 | size_t read; 130 | 131 | csv_fd = fopen(csv_file, "rb"); 132 | ini_fd = fopen("OPENMENU.INI", "w"); 133 | if (csv_fd == 0 || ini_fd == 0) 134 | exit(EXIT_FAILURE); 135 | 136 | ini_write_header(256, ini_fd); 137 | int idx = 2; 138 | while ((read = getline(&line, &len, csv_fd)) != -1) { 139 | line[read - 1] = '\0'; 140 | char *comma = strrchr(line, ','); 141 | *comma = '\0'; 142 | 143 | char *game_name = line; 144 | char *product_id = comma + 1; 145 | 146 | char *game_name_end = strrchr(game_name, '(') - 1; /* removes (USA) */ 147 | char *product_id_end = strrchr(product_id, '.'); 148 | *(game_name_end) = '\0'; 149 | *(product_id_end) = '\0'; 150 | 151 | ini_add_game(idx++, product_id, game_name, ini_fd); 152 | } 153 | 154 | fclose(csv_fd); 155 | fclose(ini_fd); 156 | 157 | return EXIT_SUCCESS; 158 | } -------------------------------------------------------------------------------- /tools/renamecsv.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File: renamecsv.c 3 | * Project: meta 4 | * File Created: Thursday, 17th June 2021 4:36:42 pm 5 | * Author: Hayden Kowalchuk 6 | * ----- 7 | * Copyright (c) 2021 Hayden Kowalchuk, Hayden Kowalchuk 8 | * License: BSD 3-clause "New" or "Revised" License, http://www.opensource.org/licenses/BSD-3-Clause 9 | */ 10 | 11 | #ifdef COSMO 12 | #include "cosmo/cosmopolitan.h" 13 | #else 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #endif 21 | 22 | /* Called: 23 | ./renamecsv FOLDER filelist.csv (-ext pvr) 24 | 25 | reads filelist.csv and renames all files in Folder 26 | if -ext is specified, ignores extension in csv and uses supplied one 27 | */ 28 | 29 | /* Compile: 30 | x86_64-w64-mingw32-gcc renamecsv.c -Os -s -o renamecsv.exe 31 | gcc renamecsv.c -Os -s -o renamecsv 32 | */ 33 | 34 | #ifdef WIN32 35 | /* This code is public domain -- Will Hartung 4/9/09 */ 36 | size_t getline(char **lineptr, size_t *n, FILE *stream) { 37 | char *bufptr = NULL; 38 | char *p = bufptr; 39 | size_t size; 40 | int c; 41 | 42 | if (lineptr == NULL) { 43 | return -1; 44 | } 45 | if (stream == NULL) { 46 | return -1; 47 | } 48 | if (n == NULL) { 49 | return -1; 50 | } 51 | bufptr = *lineptr; 52 | size = *n; 53 | 54 | c = fgetc(stream); 55 | if (c == EOF) { 56 | return -1; 57 | } 58 | if (bufptr == NULL) { 59 | bufptr = malloc(128); 60 | if (bufptr == NULL) { 61 | return -1; 62 | } 63 | size = 128; 64 | } 65 | p = bufptr; 66 | while (c != EOF) { 67 | if ((p - bufptr) > (size - 1)) { 68 | size = size + 128; 69 | bufptr = realloc(bufptr, size); 70 | if (bufptr == NULL) { 71 | return -1; 72 | } 73 | } 74 | *p++ = c; 75 | if (c == '\n') { 76 | break; 77 | } 78 | c = fgetc(stream); 79 | } 80 | 81 | *p++ = '\0'; 82 | *lineptr = bufptr; 83 | *n = size; 84 | 85 | return p - bufptr - 1; 86 | } 87 | 88 | #endif 89 | 90 | #define NUM_ARGS (2) 91 | 92 | int main(int argc, char **argv) { 93 | if (argc < NUM_ARGS + 1 /*binary itself*/) { 94 | printf("Incorrect usage!\n\t./renamecsv FOLDER filelist.csv (-ext pvr)\n"); 95 | return 1; 96 | } 97 | 98 | const char *folder = argv[1]; 99 | const char *csv_file = argv[2]; 100 | const char *new_extension = NULL; 101 | char filename_temp[FILENAME_MAX]; 102 | char filename_temp2[FILENAME_MAX]; 103 | int folder_len = strlen(folder); 104 | int replace_ext = (argc == NUM_ARGS + 2 + 1) && (strcmp(argv[3], "-ext") == 0); 105 | if (replace_ext) { 106 | new_extension = argv[4]; 107 | } 108 | 109 | FILE *csv_fd; 110 | char *line = malloc(FILENAME_MAX); 111 | size_t len = FILENAME_MAX; 112 | size_t read; 113 | 114 | csv_fd = fopen(csv_file, "rb"); 115 | if (!csv_fd) 116 | exit(EXIT_FAILURE); 117 | 118 | printf("REN: Renaming files in %s as per %s\n", folder, csv_file); 119 | 120 | while ((read = getline(&line, &len, csv_fd)) != -1) { 121 | line[read - 1] = '\0'; 122 | char *comma = strrchr(line, ','); 123 | *comma = '\0'; 124 | 125 | char *filename_cur = line; 126 | char *filename_new = comma + 1; 127 | char *filename_new_end = strrchr(filename_new, '\r'); 128 | if (!filename_new_end) { 129 | filename_new_end = strrchr(filename_new, '\n'); 130 | } 131 | if (filename_new_end) { 132 | *filename_new_end = '\0'; 133 | } 134 | 135 | if (replace_ext) { 136 | char *filename_cur_ext = strrchr(filename_cur, '.') + 1; 137 | char *filename_new_ext = strrchr(filename_new, '.') + 1; 138 | memcpy(filename_cur_ext, new_extension, 3); 139 | memcpy(filename_new_ext, new_extension, 3); 140 | *(filename_cur_ext + 3) = '\0'; 141 | *(filename_new_ext + 3) = '\0'; 142 | } 143 | 144 | memcpy(filename_temp, folder, folder_len + 1); 145 | memcpy(filename_temp2, folder, folder_len + 1); 146 | strcat(filename_temp, filename_cur); 147 | strcat(filename_temp2, filename_new); 148 | struct stat buffer; 149 | int exists = (stat(filename_temp, &buffer) == 0); 150 | if (exists) { 151 | int ret = rename(filename_temp, filename_temp2); 152 | if (ret == 0) { 153 | /*Note: Too verbose */ 154 | //printf("%s -> [%s]\n", filename_temp, filename_temp2); 155 | } else { 156 | printf("%s -> [%s]\n", filename_temp, filename_temp2); 157 | perror(filename_temp); 158 | } 159 | } else { 160 | printf("REN:Error %s missing!\n", filename_temp); 161 | } 162 | } 163 | 164 | fclose(csv_fd); 165 | 166 | return EXIT_SUCCESS; 167 | } -------------------------------------------------------------------------------- /ui/dc/input.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Filename: d:\Dev\Dreamcast\UB_SHARE\gamejam\game\src\common\input.c 3 | * Path: d:\Dev\Dreamcast\UB_SHARE\gamejam\game\src\common 4 | * Created Date: Saturday, July 6th 2019, 6:23:40 pm 5 | * Author: Hayden Kowalchuk 6 | * 7 | * Copyright (c) 2019 HaydenKow 8 | */ 9 | #include "input.h" 10 | 11 | #include 12 | 13 | static inputs _current, _last; 14 | 15 | void INPT_ReceiveFromHost(inputs _in) 16 | { 17 | memset(&_current, 0, sizeof(inputs)); 18 | 19 | /* Handle Setting Single press */ 20 | for (int index = 0; index < 5; index++) 21 | { 22 | uint8_t *state_in = (uint8_t *)(&_in.btn_a) + index; 23 | uint8_t *state_last = (uint8_t *)(&_last.btn_a) + index; 24 | uint8_t *state_current = (uint8_t *)(&_current.btn_a) + index; 25 | 26 | if (*state_in && !(*state_last)) 27 | { 28 | *state_current |= BTN_PRESS; 29 | } 30 | 31 | if (*state_in && *state_last) 32 | { 33 | *state_current |= BTN_HELD; 34 | } 35 | 36 | if (!*state_in && *state_last) 37 | { 38 | *state_current |= BTN_RELEASE; 39 | } 40 | } 41 | 42 | /* Handle DPAD Values */ 43 | /* Loops through 8 values */ 44 | for (int index = 0; index < 4; index++) 45 | { 46 | if ((_in.dpad & (1 << index))) 47 | { 48 | _current.dpad |= (1 << index); 49 | } 50 | 51 | if ((_in.dpad & (1 << index)) && (_last.dpad & (1 << index))) 52 | { 53 | _current.dpad |= (1 << (index + 4)); 54 | } 55 | } 56 | 57 | /* Handle Analog Axes Values */ 58 | /* Loops through 4 Axes for 2 Analog Sticks */ 59 | _current.axes_1 = _in.axes_1; 60 | _current.axes_2 = _in.axes_2; 61 | 62 | /* Triggers */ 63 | _current.trg_left = _in.trg_left; 64 | _current.trg_right = _in.trg_right; 65 | 66 | _last = _in; 67 | } 68 | 69 | bool INPT_Button(BUTTON btn) 70 | { 71 | switch (btn) 72 | { 73 | case BTN_A: 74 | return _current.btn_a; 75 | break; 76 | 77 | case BTN_B: 78 | return _current.btn_b; 79 | break; 80 | 81 | case BTN_X: 82 | return _current.btn_x; 83 | break; 84 | 85 | case BTN_Y: 86 | return _current.btn_y; 87 | break; 88 | 89 | case BTN_START: 90 | return _current.btn_start; 91 | break; 92 | 93 | default: 94 | return _current.btn_a || _current.btn_b || _current.btn_x || _current.btn_y || _current.btn_start; 95 | break; 96 | } 97 | 98 | return false; 99 | } 100 | 101 | bool INPT_ButtonEx(BUTTON btn, ACTION_TYPE type) 102 | { 103 | switch (btn) 104 | { 105 | case BTN_A: 106 | return (_current.btn_a & type) == type; 107 | break; 108 | 109 | case BTN_B: 110 | return (_current.btn_b & type) == type; 111 | break; 112 | 113 | case BTN_X: 114 | return (_current.btn_x & type) == type; 115 | break; 116 | 117 | case BTN_Y: 118 | return (_current.btn_y & type) == type; 119 | break; 120 | 121 | case BTN_START: 122 | return (_current.btn_start & type) == type; 123 | break; 124 | 125 | default: 126 | break; 127 | } 128 | 129 | return false; 130 | } 131 | 132 | dpad_t INPT_DPAD() 133 | { 134 | return _current.dpad; 135 | } 136 | 137 | bool INPT_DPADDirection(DPAD_DIRECTION dir) 138 | { 139 | return !!(_current.dpad & dir); 140 | } 141 | 142 | /* -1.0 is lowest, 1.0 is highest and middle is 0 */ 143 | float INPT_AnalogF(ANALOG_AXES axes) 144 | { 145 | switch (axes) 146 | { 147 | case AXES_X: 148 | return ((int)(_current.axes_1) - 128) / 128.0f; 149 | break; 150 | 151 | case AXES_Y: 152 | return ((int)(_current.axes_2) - 128) / 128.0f; 153 | break; 154 | 155 | case AXES_NULL: 156 | default: 157 | break; 158 | } 159 | 160 | return 0.0f; 161 | } 162 | 163 | /* 0 is lowest, 255 is highest and middle is 128 */ 164 | uint8_t INPT_AnalogI(ANALOG_AXES axes) 165 | { 166 | switch (axes) 167 | { 168 | case AXES_X: 169 | return _current.axes_1; 170 | break; 171 | 172 | case AXES_Y: 173 | return _current.axes_2; 174 | break; 175 | 176 | case AXES_NULL: 177 | default: 178 | break; 179 | } 180 | 181 | /* default center value */ 182 | return 128; 183 | } 184 | 185 | bool INPT_TriggerPressed(TRIGGER trigger) 186 | { 187 | switch (trigger) 188 | { 189 | case TRIGGER_L: 190 | return !!_current.trg_left; 191 | break; 192 | 193 | case TRIGGER_R: 194 | return !!_current.trg_right; 195 | break; 196 | 197 | case TRIGGER_NULL: 198 | default: 199 | break; 200 | } 201 | 202 | return false; 203 | } 204 | 205 | uint8_t INPT_TriggerValue(TRIGGER trigger) 206 | { 207 | switch (trigger) 208 | { 209 | case TRIGGER_L: 210 | return _current.trg_left; 211 | break; 212 | 213 | case TRIGGER_R: 214 | return _current.trg_right; 215 | break; 216 | 217 | case TRIGGER_NULL: 218 | default: 219 | break; 220 | } 221 | 222 | return 0; 223 | } 224 | 225 | -------------------------------------------------------------------------------- /inc/bloader.h: -------------------------------------------------------------------------------- 1 | const int bloader_size = 696; 2 | uint8_t bloader_data[696] = 3 | { 4 | 0x01, 0xee, 0x35, 0xd0, 0x0e, 0x40, 0x33, 0xd4, 5 | 0x1e, 0x44, 0xe3, 0x60, 0x39, 0xc2, 0x33, 0xdf, 6 | 0x2e, 0x44, 0x88, 0xb0, 0x09, 0x00, 0x25, 0xd3, 7 | 0x00, 0xe0, 0x04, 0x13, 0x09, 0xe1, 0x18, 0x41, 8 | 0x29, 0x71, 0x17, 0x13, 0x2e, 0xd1, 0x3d, 0xd3, 9 | 0x0a, 0x20, 0x03, 0xe2, 0x10, 0x42, 0x06, 0x21, 10 | 0x06, 0x21, 0x06, 0x21, 0x05, 0x23, 0xfe, 0x73, 11 | 0xf8, 0x8f, 0xfc, 0x71, 0x05, 0x23, 0x12, 0x60, 12 | 0xf8, 0x71, 0x12, 0x60, 0x33, 0xd1, 0x12, 0x60, 13 | 0xfe, 0xe2, 0x29, 0x20, 0x02, 0x21, 0x32, 0xd1, 14 | 0x03, 0xe0, 0x02, 0x21, 0x23, 0xc7, 0xfe, 0xe2, 15 | 0x01, 0xe4, 0x0c, 0xe6, 0x06, 0x63, 0x32, 0x61, 16 | 0x29, 0x21, 0x12, 0x23, 0x7f, 0xe5, 0x10, 0x45, 17 | 0x02, 0x89, 0x32, 0x61, 0x48, 0x21, 0xfa, 0x8b, 18 | 0x10, 0x46, 0xf3, 0x8b, 0x14, 0xd2, 0x15, 0xd1, 19 | 0x22, 0x21, 0x0d, 0xd6, 0x6a, 0x46, 0x0e, 0xc7, 20 | 0x03, 0x65, 0x13, 0xd0, 0x13, 0xd1, 0x02, 0xe4, 21 | 0x56, 0x63, 0x10, 0x43, 0x09, 0xf0, 0xfc, 0x8f, 22 | 0x08, 0x71, 0x56, 0x63, 0x10, 0x43, 0x09, 0xf0, 23 | 0x0a, 0xf1, 0xfb, 0x8f, 0x08, 0x71, 0x10, 0x44, 24 | 0xf2, 0x8b, 0x04, 0xd7, 0x6a, 0x47, 0x71, 0xa0, 25 | 0x09, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0xff, 26 | 0x01, 0x00, 0x14, 0x00, 0x01, 0x00, 0x04, 0x00, 27 | 0x20, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 28 | 0x00, 0x08, 0x00, 0x00, 0x00, 0xf0, 0x03, 0x00, 29 | 0xff, 0xff, 0x1f, 0x00, 0xe4, 0x74, 0x5f, 0xa0, 30 | 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x8c, 31 | 0xf0, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x8d, 32 | 0x3c, 0x69, 0x5f, 0xa0, 0x08, 0x68, 0x5f, 0xa0, 33 | 0x20, 0x68, 0x5f, 0xa0, 0x14, 0x6c, 0x5f, 0xa0, 34 | 0x14, 0x74, 0x5f, 0xa0, 0x14, 0x78, 0x5f, 0xa0, 35 | 0x34, 0x78, 0x5f, 0xa0, 0x54, 0x78, 0x5f, 0xa0, 36 | 0x74, 0x78, 0x5f, 0xa0, 0x14, 0x7c, 0x5f, 0xa0, 37 | 0x1c, 0x00, 0xa0, 0xff, 0x2c, 0x00, 0xa0, 0xff, 38 | 0x3c, 0x00, 0xa0, 0xff, 0x44, 0x80, 0x5f, 0xa0, 39 | 0x08, 0x80, 0x5f, 0xa0, 0x10, 0x00, 0xd0, 0xff, 40 | 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0xa0, 0xe3, 41 | 0xff, 0xe2, 0x18, 0x43, 0x09, 0x42, 0x28, 0x43, 42 | 0x01, 0x42, 0x02, 0xc7, 0x29, 0x20, 0x3b, 0x20, 43 | 0x2b, 0x40, 0x09, 0x00, 0x03, 0x4f, 0x02, 0x00, 44 | 0xf0, 0xcb, 0x0e, 0x40, 0xf4, 0xe5, 0x28, 0x45, 45 | 0x53, 0x66, 0x20, 0x76, 0x18, 0x45, 0x18, 0x46, 46 | 0xff, 0xe3, 0x18, 0x43, 0x28, 0x43, 0x1c, 0x73, 47 | 0x32, 0x60, 0x20, 0xc8, 0x01, 0x8d, 0x02, 0xe2, 48 | 0x01, 0xe2, 0x18, 0x42, 0x08, 0x42, 0x08, 0x42, 49 | 0x00, 0xe1, 0xe0, 0x72, 0x23, 0x60, 0x09, 0x40, 50 | 0x08, 0x40, 0x28, 0x22, 0x16, 0x06, 0x16, 0x05, 51 | 0xf7, 0x8b, 0x09, 0x00, 0x09, 0x00, 0x09, 0x00, 52 | 0x09, 0x00, 0x09, 0x00, 0x09, 0x00, 0x07, 0x4f, 53 | 0x0b, 0x00, 0x09, 0x00, 0x27, 0xd4, 0x28, 0xd3, 54 | 0x42, 0x64, 0x00, 0xee, 0x30, 0x34, 0x08, 0x89, 55 | 0x26, 0xd3, 0x04, 0xee, 0x30, 0x34, 0x04, 0x89, 56 | 0x25, 0xd3, 0x30, 0x34, 0x01, 0x89, 0x3e, 0xa0, 57 | 0x09, 0x00, 0x24, 0xc7, 0xec, 0x30, 0x02, 0x60, 58 | 0x24, 0xd1, 0x11, 0x20, 0x3e, 0xd1, 0x18, 0x21, 59 | 0x0b, 0x89, 0x26, 0xd1, 0x22, 0xc7, 0xe3, 0x62, 60 | 0x08, 0x42, 0x2c, 0x30, 0x00, 0xe3, 0x06, 0x62, 61 | 0x12, 0x22, 0x06, 0x62, 0x32, 0x22, 0x02, 0x62, 62 | 0x32, 0x22, 0x38, 0xd1, 0x18, 0x21, 0x26, 0x89, 63 | 0x22, 0xc7, 0xe3, 0x62, 0x08, 0x42, 0x0c, 0x32, 64 | 0x28, 0xc7, 0xe3, 0x61, 0x08, 0x41, 0xec, 0x31, 65 | 0x0c, 0x31, 0x26, 0x64, 0x15, 0x65, 0x51, 0x24, 66 | 0x02, 0x74, 0x15, 0x65, 0x51, 0x24, 0x26, 0x64, 67 | 0x15, 0x65, 0x51, 0x24, 0x26, 0x64, 0x15, 0x65, 68 | 0x51, 0x24, 0x02, 0x74, 0x15, 0x65, 0x51, 0x24, 69 | 0x02, 0x74, 0x15, 0x65, 0x51, 0x24, 0x02, 0x74, 70 | 0x15, 0x65, 0x51, 0x24, 0x26, 0x64, 0x15, 0x65, 71 | 0x51, 0x24, 0x02, 0x74, 0x15, 0x65, 0x51, 0x24, 72 | 0x02, 0x74, 0x15, 0x65, 0x51, 0x24, 0x21, 0xd0, 73 | 0x2b, 0x40, 0xfa, 0x04, 0xcc, 0x07, 0x00, 0xac, 74 | 0x31, 0x2e, 0x30, 0x30, 0x31, 0x2e, 0x30, 0x31, 75 | 0x31, 0x2e, 0x30, 0x32, 0x48, 0x98, 0x02, 0xac, 76 | 0x48, 0xd4, 0x02, 0xac, 0x00, 0xe0, 0x00, 0x00, 77 | 0x00, 0xe7, 0x0e, 0xac, 0x90, 0x43, 0x01, 0xac, 78 | 0xd4, 0x84, 0x06, 0xac, 0x52, 0xb8, 0x5e, 0x3f, 79 | 0x80, 0xcd, 0x0e, 0xac, 0x44, 0x4f, 0x01, 0xac, 80 | 0x38, 0xb8, 0x06, 0xac, 0x6a, 0x01, 0x01, 0xac, 81 | 0xe2, 0x3b, 0x02, 0xac, 0xf8, 0x3b, 0x02, 0xac, 82 | 0x0a, 0x3c, 0x02, 0xac, 0x30, 0x02, 0x01, 0xac, 83 | 0x10, 0x77, 0x02, 0xac, 0x28, 0x77, 0x02, 0xac, 84 | 0x3a, 0x77, 0x02, 0xac, 0x09, 0x00, 0x09, 0x00, 85 | 0x09, 0x00, 0x10, 0xd3, 0x32, 0x60, 0x08, 0x20, 86 | 0x41, 0x8b, 0x01, 0xe0, 0x02, 0x23, 0x09, 0x00, 87 | 0x09, 0x00, 0x09, 0x00, 0x09, 0x00, 0x2d, 0xd3, 88 | 0x32, 0x60, 0x08, 0x20, 0x1f, 0x8b, 0x01, 0xe0, 89 | 0x02, 0x23, 0x09, 0x00, 0x20, 0x01, 0x00, 0xac, 90 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 91 | }; 92 | 93 | typedef struct bloader_cfg 94 | { 95 | uint32_t enable_wide; 96 | uint32_t enable_3d; 97 | } bloader_cfg_t; 98 | 99 | 100 | -------------------------------------------------------------------------------- /texture/dat_reader.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File: reader.c 3 | * Project: dat_builder 4 | * File Created: Tuesday, 8th June 2021 2:47:35 pm 5 | * Author: Hayden Kowalchuk 6 | * ----- 7 | * Copyright (c) 2021 Hayden Kowalchuk, Hayden Kowalchuk 8 | * License: BSD 3-clause "New" or "Revised" License, http://www.opensource.org/licenses/BSD-3-Clause 9 | */ 10 | 11 | #ifdef COSMO 12 | #include "../tools/cosmo/cosmopolitan.h" 13 | #else 14 | #include 15 | #include 16 | #endif 17 | 18 | #include 19 | 20 | #include "../inc/dat_format.h" 21 | 22 | /* Define configure constants */ 23 | /* only defined when building the binary tool */ 24 | #ifdef STANDALONE_BINARY 25 | #define DEBUG 26 | #endif 27 | 28 | #ifdef DEBUG 29 | #define DBG_PRINT(...) printf(__VA_ARGS__) 30 | #else 31 | #define DBG_PRINT(...) 32 | #endif 33 | 34 | typedef struct bin_item_raw 35 | { 36 | char ID[12]; 37 | uint32_t offset; 38 | } bin_item_raw; 39 | 40 | int DAT_init(dat_file *bin) 41 | { 42 | memset(bin, '\0', sizeof(dat_file)); 43 | return 0; 44 | } 45 | 46 | int DAT_load_parse(dat_file *bin, const char *path) 47 | { 48 | #ifndef STANDALONE_BINARY 49 | file_t bin_fd; 50 | #else 51 | FILE *bin_fd; 52 | #endif 53 | bin_header file_header; 54 | 55 | #ifdef STANDALONE_BINARY 56 | bin_fd = fopen(path, "rb"); 57 | const char *filename_safe = path; 58 | #else 59 | char filename_safe[128]; 60 | snprintf(filename_safe, 127, "/cd/%s", path); 61 | 62 | bin_fd = fs_open(filename_safe, O_RDONLY); 63 | #endif 64 | 65 | #ifndef STANDALONE_BINARY 66 | if (bin_fd == -1) 67 | #else 68 | if (!bin_fd) 69 | #endif 70 | { 71 | printf("DAT:Error Cant read input %s!\n", filename_safe); 72 | return 1; 73 | } 74 | 75 | printf("DAT:Open %s (%s)\n", filename_safe, path); 76 | 77 | #ifndef STANDALONE_BINARY 78 | fs_read(bin_fd, &file_header, sizeof(bin_header)); 79 | #else 80 | fread(&file_header, sizeof(bin_header), 1, bin_fd); 81 | #endif 82 | if (file_header.magic.rich.version != 1) 83 | { 84 | printf("DAT:Error Incorrect input file format!\n"); 85 | return 1; 86 | } 87 | 88 | /* setup basic bin file info */ 89 | bin->chunk_size = file_header.chunk_size; 90 | bin->num_chunks = file_header.num_chunks; 91 | bin->handle = bin_fd; 92 | bin->items = malloc(bin->num_chunks * sizeof(bin_item)); 93 | 94 | if (!bin->items) 95 | { 96 | printf("%s no free memory\n", __func__); 97 | return 1; 98 | } 99 | 100 | bin->hash = NULL; 101 | 102 | /* Parse file table to Hash table */ 103 | for (unsigned int i = 0; i < file_header.num_chunks; i++) 104 | { 105 | #ifndef STANDALONE_BINARY 106 | fs_read(bin->handle, &bin->items[i], sizeof(bin_item_raw)); 107 | #else 108 | fread(&bin->items[i], sizeof(bin_item_raw), 1, bin->handle); 109 | #endif 110 | HASH_ADD_STR(bin->hash, ID, &bin->items[i]); 111 | } 112 | 113 | /* Leave our handle in a handy place in case we need to read after */ 114 | #ifndef STANDALONE_BINARY 115 | fs_seek(bin->handle, bin->items[0].offset * bin->chunk_size, SEEK_SET); 116 | #else 117 | fseek(bin->handle, bin->items[0].offset * bin->chunk_size, SEEK_SET); 118 | #endif 119 | return 0; 120 | } 121 | 122 | void DAT_info(const dat_file *bin) 123 | { 124 | DBG_PRINT("DAT:Stats\nChunk Size: %u\nNum Chunks: %u\n\n", bin->chunk_size, bin->num_chunks); 125 | 126 | for (unsigned int i = 0; i < bin->num_chunks; i++) 127 | { 128 | DBG_PRINT("Record[%u] %s at 0x%X\n", bin->items[i].offset, bin->items[i].ID, (unsigned int)(bin->items[i].offset * bin->chunk_size)); 129 | } 130 | DBG_PRINT("\n"); 131 | } 132 | 133 | uint32_t DAT_get_offset_by_ID(const dat_file *bin, const char *ID) 134 | { 135 | const bin_item *item; 136 | uint32_t ret; 137 | 138 | HASH_FIND_STR(bin->hash, ID, item); 139 | 140 | if (item) 141 | { 142 | ret = item->offset * bin->chunk_size; 143 | } 144 | else 145 | { 146 | ret = 0; 147 | } 148 | 149 | return ret; 150 | } 151 | 152 | uint32_t DAT_get_index_by_ID(const dat_file *bin, const char *ID) 153 | { 154 | const bin_item *item; 155 | uint32_t ret; 156 | 157 | HASH_FIND_STR(bin->hash, ID, item); 158 | 159 | if (item) 160 | { 161 | ret = item->offset; 162 | } 163 | else 164 | { 165 | ret = 0xFFFFFFFF; 166 | } 167 | 168 | return ret; 169 | } 170 | 171 | int DAT_read_file_by_ID(const dat_file *bin, const char *ID, void *buf) 172 | { 173 | uint32_t offset = DAT_get_offset_by_ID(bin, ID); 174 | 175 | if (offset) 176 | { 177 | #ifndef STANDALONE_BINARY 178 | fs_seek(bin->handle, offset, SEEK_SET); 179 | fs_read(bin->handle, buf, bin->chunk_size); 180 | #else 181 | fseek(bin->handle, offset, SEEK_SET); 182 | fread(buf, bin->chunk_size, 1, bin->handle); 183 | #endif 184 | return 1; 185 | } 186 | 187 | return 0; 188 | } 189 | 190 | int DAT_read_file_by_num(const dat_file *bin, uint32_t chunk_num, void *buf) 191 | { 192 | uint32_t offset = chunk_num * bin->chunk_size; 193 | 194 | if (chunk_num <= bin->num_chunks) 195 | { 196 | #ifndef STANDALONE_BINARY 197 | fs_seek(bin->handle, offset, SEEK_SET); 198 | fs_read(bin->handle, buf, bin->chunk_size); 199 | #else 200 | fseek(bin->handle, offset, SEEK_SET); 201 | fread(buf, bin->chunk_size, 1, bin->handle); 202 | #endif 203 | return 1; 204 | } 205 | 206 | return 0; 207 | } 208 | 209 | -------------------------------------------------------------------------------- /backend/gdemu_sdk.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define ATA_SR_BSY 0x80 4 | #define ATA_SR_DRDY 0x40 5 | #define ATA_SR_DF 0x20 6 | #define ATA_SR_DSC 0x10 7 | #define ATA_SR_DRQ 0x08 8 | #define ATA_SR_CORR 0x04 9 | #define ATA_SR_IDX 0x02 10 | #define ATA_SR_ERR 0x01 11 | 12 | #define ATA_ER_BBK 0x80 13 | #define ATA_ER_UNC 0x40 14 | #define ATA_ER_MC 0x20 15 | #define ATA_ER_IDNF 0x10 16 | #define ATA_ER_MCR 0x08 17 | #define ATA_ER_ABRT 0x04 18 | #define ATA_ER_TK0NF 0x02 19 | #define ATA_ER_AMNF 0x01 20 | 21 | #define ATAPI_CMD_PACKET 0xA0 22 | 23 | /* ATA-related registers. Some of these serve very different purposes when read 24 | than they do when written (hence why some addresses are duplicated). */ 25 | #define G1_ATA_ALTSTATUS 0xA05F7018 /* Read */ 26 | #define G1_ATA_CTRL 0xA05F7018 /* Write */ 27 | #define G1_ATA_DATA 0xA05F7080 /* Read/Write */ 28 | #define G1_ATA_ERROR 0xA05F7084 /* Read */ 29 | #define G1_ATA_FEATURES 0xA05F7084 /* Write */ 30 | #define G1_ATA_IRQ_REASON 0xA05F7088 /* Read */ 31 | #define G1_ATA_SECTOR_COUNT 0xA05F7088 /* Write */ 32 | #define G1_ATA_LBA_LOW 0xA05F708C /* Read/Write */ 33 | #define G1_ATA_LBA_MID 0xA05F7090 /* Read/Write */ 34 | #define G1_ATA_LBA_HIGH 0xA05F7094 /* Read/Write */ 35 | #define G1_ATA_DEVICE_SELECT 0xA05F7098 /* Read/Write */ 36 | #define G1_ATA_STATUS_REG 0xA05F709C /* Read */ 37 | #define G1_ATA_COMMAND_REG 0xA05F709C /* Write */ 38 | 39 | /* status of the external interrupts 40 | * bit 3 = External Device interrupt 41 | * bit 2 = Modem interrupt 42 | * bit 1 = AICA interrupt 43 | * bit 0 = GD-ROM interrupt */ 44 | #define EXT_INT_STAT 0xA05F6904 /* Read */ 45 | 46 | /* Macros to access the ATA registers */ 47 | #define OUT16(addr, data) *((volatile uint16_t *)addr) = data 48 | #define OUT8(addr, data) *((volatile uint8_t *)addr) = data 49 | #define IN32(addr) *((volatile uint32_t *)addr) 50 | #define IN16(addr) *((volatile uint16_t *)addr) 51 | #define IN8(addr) *((volatile uint8_t *)addr) 52 | 53 | #define g1_ata_wait_interrupt() \ 54 | do { \ 55 | } while (!(IN32(EXT_INT_STAT) & 1)); 56 | 57 | #define g1_ata_wait_status(n) \ 58 | do { \ 59 | } while ((IN8(G1_ATA_ALTSTATUS) & (n))) 60 | 61 | #define g1_ata_wait_nstatus(n) \ 62 | do { \ 63 | } while (!(IN8(G1_ATA_ALTSTATUS) & (n))) 64 | 65 | #define g1_ata_wait_drq() g1_ata_wait_nstatus(ATA_SR_DRQ) 66 | 67 | #define g1_ata_wait_bsydrq() g1_ata_wait_status(ATA_SR_DRQ | ATA_SR_BSY) 68 | 69 | static int send_packet_command(uint16_t *cmd_buff) 70 | { 71 | g1_ata_wait_bsydrq(); 72 | OUT8(G1_ATA_COMMAND_REG, ATAPI_CMD_PACKET); 73 | g1_ata_wait_drq(); 74 | 75 | (void)IN32(G1_ATA_STATUS_REG); 76 | int i; 77 | for (i = 0; i < 6; i++) 78 | { 79 | OUT16(G1_ATA_DATA, cmd_buff[i]); 80 | } 81 | 82 | g1_ata_wait_interrupt(); 83 | 84 | (void)IN32(G1_ATA_STATUS_REG); 85 | 86 | return (IN8(G1_ATA_ALTSTATUS) & ATA_SR_ERR); 87 | } 88 | 89 | static int send_packet_data_command(uint16_t *cmd_buff, uint16_t *buffer, uint32_t *size) 90 | { 91 | g1_ata_wait_bsydrq(); 92 | 93 | OUT8(G1_ATA_FEATURES, 0); 94 | OUT8(G1_ATA_COMMAND_REG, ATAPI_CMD_PACKET); 95 | g1_ata_wait_drq(); 96 | 97 | (void)IN32(G1_ATA_STATUS_REG); 98 | int i; 99 | for (i = 0; i < 6; i++) 100 | { 101 | OUT16(G1_ATA_DATA, cmd_buff[i]); 102 | } 103 | 104 | g1_ata_wait_interrupt(); 105 | 106 | if (!(IN8(G1_ATA_STATUS_REG) & ATA_SR_DRQ)) 107 | { 108 | if (size) 109 | { 110 | *size = 0; 111 | } 112 | 113 | return 0; 114 | } 115 | 116 | uint16_t len = (IN8(G1_ATA_LBA_MID) | (IN8(G1_ATA_LBA_HIGH) << 8)); 117 | 118 | *size = (uint32_t)len; 119 | 120 | len >>= 1; 121 | 122 | (void)IN32(G1_ATA_STATUS_REG); 123 | 124 | for (i = 0; i < len; i++) 125 | { 126 | buffer[i] = IN16(G1_ATA_DATA); 127 | } 128 | 129 | g1_ata_wait_interrupt(); 130 | 131 | (void)IN32(G1_ATA_STATUS_REG); 132 | 133 | return (IN8(G1_ATA_ALTSTATUS) & ATA_SR_ERR); 134 | } 135 | 136 | /* return 8 byte: 00 00 09 01 00 00 14 05 137 | * 01 09 00 00 - internal bootloader version. don't used in early models 138 | * 05 14 00 00 - FW version (5.14.0) 139 | */ 140 | 141 | int gdemu_get_version(void *buffer, uint32_t *size) 142 | { 143 | uint8_t cmd_buff[12] __attribute__((aligned(4))); 144 | ((uint32_t *)cmd_buff)[0] = 0; 145 | ((uint32_t *)cmd_buff)[1] = 0; 146 | ((uint32_t *)cmd_buff)[2] = 0; 147 | 148 | cmd_buff[0] = 0x52; 149 | 150 | return send_packet_data_command((uint16_t *)cmd_buff, (uint16_t *)buffer, size); 151 | } 152 | 153 | /* param = 0x55 next img */ 154 | /* param = 0x44 prev img */ 155 | int gdemu_img_cmd(uint8_t cmd) 156 | { 157 | uint8_t cmd_buff[12] __attribute__((aligned(4))); 158 | ((uint32_t *)cmd_buff)[0] = 0; 159 | ((uint32_t *)cmd_buff)[1] = 0; 160 | ((uint32_t *)cmd_buff)[2] = 0; 161 | 162 | cmd_buff[0] = 0x52; 163 | cmd_buff[1] = 0x81; 164 | cmd_buff[2] = cmd; 165 | 166 | return send_packet_command((uint16_t *)cmd_buff); 167 | } 168 | 169 | /* 0 = reset to default img */ 170 | /* 1 to 999 = set image index */ 171 | int gdemu_set_img_num(uint16_t img_num) 172 | { 173 | uint8_t cmd_buff[12] __attribute__((aligned(4))); 174 | ((uint32_t *)cmd_buff)[0] = 0; 175 | ((uint32_t *)cmd_buff)[1] = 0; 176 | ((uint32_t *)cmd_buff)[2] = 0; 177 | 178 | cmd_buff[0] = 0x52; 179 | cmd_buff[1] = 0x82; 180 | cmd_buff[2] = (uint8_t)(img_num); 181 | cmd_buff[3] = (uint8_t)(img_num >> 8); 182 | 183 | return send_packet_command((uint16_t *)cmd_buff); 184 | } 185 | 186 | -------------------------------------------------------------------------------- /tools/tsv_to_txt_ini.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File: tsv_to_txt_ini.c 3 | * Project: tools 4 | * File Created: Tuesday, 22nd June 2021 10:35:52 pm 5 | * Author: Hayden Kowalchuk 6 | * ----- 7 | * Copyright (c) 2021 Hayden Kowalchuk, Hayden Kowalchuk 8 | * License: BSD 3-clause "New" or "Revised" License, http://www.opensource.org/licenses/BSD-3-Clause 9 | */ 10 | 11 | #ifdef COSMO 12 | #include "cosmo/cosmopolitan.h" 13 | #else 14 | #include 15 | #include 16 | #include 17 | #include 18 | #endif 19 | 20 | /* Called: 21 | ./tsv2ini input.tsv FOLDER 22 | 23 | reads the tsv sheet and creates ini metadata files in FOLDER based on serial 24 | */ 25 | 26 | #define NUM_ARGS (2) 27 | #define MAX_LINE (512) 28 | 29 | #if defined(WIN32) || defined(WINNT) 30 | #define PATH_SEP "\\" 31 | #else 32 | #define PATH_SEP "/" 33 | #endif 34 | 35 | #ifdef WIN32 36 | char *strsep(char **stringp, const char *delim) { 37 | char *rv = *stringp; 38 | if (rv) { 39 | *stringp += strcspn(*stringp, delim); 40 | if (**stringp) 41 | *(*stringp)++ = '\0'; 42 | else 43 | *stringp = 0; 44 | } 45 | return rv; 46 | } 47 | 48 | /* This code is public domain -- Will Hartung 4/9/09 */ 49 | size_t getline(char **lineptr, size_t *n, FILE *stream) { 50 | char *bufptr = NULL; 51 | char *p = bufptr; 52 | size_t size; 53 | int c; 54 | 55 | if (lineptr == NULL) { 56 | return -1; 57 | } 58 | if (stream == NULL) { 59 | return -1; 60 | } 61 | if (n == NULL) { 62 | return -1; 63 | } 64 | bufptr = *lineptr; 65 | size = *n; 66 | 67 | c = fgetc(stream); 68 | if (c == EOF) { 69 | return -1; 70 | } 71 | if (bufptr == NULL) { 72 | bufptr = malloc(MAX_LINE); 73 | if (bufptr == NULL) { 74 | return -1; 75 | } 76 | size = MAX_LINE; 77 | } 78 | p = bufptr; 79 | while (c != EOF) { 80 | if ((p - bufptr) > (size - 1)) { 81 | size = size + MAX_LINE; 82 | bufptr = realloc(bufptr, size); 83 | if (bufptr == NULL) { 84 | return -1; 85 | } 86 | } 87 | *p++ = c; 88 | if (c == '\n') { 89 | break; 90 | } 91 | c = fgetc(stream); 92 | } 93 | 94 | *p++ = '\0'; 95 | *lineptr = bufptr; 96 | *n = size; 97 | 98 | return p - bufptr - 1; 99 | } 100 | #endif 101 | 102 | static void write_ini(const char *filename, const char *players, const char *vmu_blocks, const char *accessories, const char *genre, const char *synopsis) { 103 | FILE *ini_fd = fopen(filename, "w"); 104 | if (!ini_fd) { 105 | printf("Error: Couldn't write %s!\n"); 106 | return; 107 | } 108 | 109 | const char *_players = (players && (strlen(players) > 0) ? players : "0"); 110 | const char *_vmu_blocks = (vmu_blocks && (strlen(vmu_blocks) > 0) ? vmu_blocks : "0"); 111 | const char *_accessories = (accessories && (strlen(accessories) > 0) ? accessories : "0"); 112 | const char *_genre = (genre && (strlen(genre) > 0) ? genre : "0"); 113 | const char *_synopsis = (synopsis && (strlen(synopsis) > 0) ? synopsis : "0"); 114 | _synopsis += (synopsis[0] == '"'); /* Strip leading quotation mark */ 115 | 116 | const char *meta_template = 117 | "[ITEM]\n" 118 | "num_players=%s\n" 119 | "vmu_blocks=%s\n" 120 | "accessories=%s\n" 121 | "network=0\n" 122 | "genre=%s\n" 123 | "description=%s\n" 124 | "padding1=0\n" 125 | "padding2=0\n"; 126 | fprintf(ini_fd, meta_template, _players, _vmu_blocks, _accessories, _genre, _synopsis); 127 | 128 | fclose(ini_fd); 129 | } 130 | 131 | int main(int argc, char **argv) { 132 | if (argc < NUM_ARGS + 1 /*binary itself*/) { 133 | printf("Incorrect usage!\n\t./tsv2ini input.tsv FOLDER\n"); 134 | return 1; 135 | } 136 | 137 | const char *tsv_file = argv[1]; 138 | const char *output_folder = argv[2]; 139 | 140 | char filename_temp[128]; 141 | 142 | FILE *tsv_fd; 143 | char *line = malloc(MAX_LINE); 144 | size_t len = FILENAME_MAX; 145 | size_t read; 146 | 147 | tsv_fd = fopen(tsv_file, "rb"); 148 | if (tsv_fd == 0) 149 | exit(EXIT_FAILURE); 150 | 151 | int i = 0; 152 | 153 | while ((read = getline(&line, &len, tsv_fd)) != -1) { 154 | line[read - 1] = '\0'; 155 | /* Region | Players | VMU Blocks | Genre | Network | Accesories | Product ID | Name | Synopsis */ 156 | 157 | const char *delim = "\t"; 158 | char *token = strsep(&line, delim); 159 | const char *region = token; 160 | const char *players = strsep(&line, delim); 161 | const char *vmu_blocks = strsep(&line, delim); 162 | const char *genre = strsep(&line, delim); 163 | const char *network = strsep(&line, delim); 164 | const char *accesories = strsep(&line, delim); 165 | const char *product_no = strsep(&line, delim); 166 | const char *name = strsep(&line, delim); 167 | char *synopsis = strsep(&line, delim); 168 | 169 | /* Remove unneeded newline */ 170 | char *synopsis_end = strrchr(synopsis, '\r'); 171 | if (!synopsis_end) { 172 | synopsis_end = strrchr(synopsis, '\n'); 173 | } 174 | if (synopsis_end) { 175 | *(synopsis_end - 1) = '\0'; 176 | } 177 | 178 | memcpy(filename_temp, output_folder, strlen(output_folder) + 1); 179 | strcat(filename_temp, PATH_SEP); 180 | strcat(filename_temp, product_no); 181 | strcat(filename_temp, ".txt"); 182 | 183 | write_ini(filename_temp, players, vmu_blocks, accesories, genre, synopsis); 184 | i++; 185 | } 186 | 187 | fclose(tsv_fd); 188 | 189 | printf("TSV: Wrote %d records out to %s!\n", i, output_folder); 190 | 191 | return EXIT_SUCCESS; 192 | } -------------------------------------------------------------------------------- /ui/dc/pvr_texture.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File: common.c 3 | * Project: ui 4 | * File Created: Monday, 3rd June 2019 1:25:54 pm 5 | * Author: Hayden Kowalchuk (hayden@hkowsoftware.com) 6 | * ----- 7 | * Copyright (c) 2019 Hayden Kowalchuk 8 | */ 9 | #include "pvr_texture.h" 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #define PVR_HDR_SIZE 0x20 17 | 18 | static unsigned char* _internal_buf = NULL; 19 | static char filename_safe[128]; 20 | 21 | static uint32_t pvr_get_texture_size(const void* input, uint32_t* w, uint32_t* h, uint32_t* txrFormat) 22 | { 23 | unsigned char* texBuf = (unsigned char*)input; 24 | 25 | const int texW = texBuf[PVR_HDR_SIZE - 4] | texBuf[PVR_HDR_SIZE - 3] << 8; 26 | const int texH = texBuf[PVR_HDR_SIZE - 2] | texBuf[PVR_HDR_SIZE - 1] << 8; 27 | int texFormat = 0, texColor = 0; 28 | int bpp = 2; 29 | 30 | switch ((unsigned int)texBuf[PVR_HDR_SIZE - 8]) 31 | { 32 | case 0x00: 33 | texColor = PVR_TXRFMT_ARGB1555; 34 | bpp = 2; 35 | break; //(bilevel translucent alpha 0,255) 36 | 37 | case 0x01: 38 | texColor = PVR_TXRFMT_RGB565; 39 | bpp = 2; 40 | break; //(non translucent RGB565 ) 41 | 42 | case 0x02: 43 | texColor = PVR_TXRFMT_ARGB4444; 44 | bpp = 2; 45 | break; //(translucent alpha 0-255) 46 | 47 | case 0x03: 48 | texColor = PVR_TXRFMT_YUV422; 49 | bpp = 1; 50 | break; //(non translucent UYVY ) 51 | 52 | case 0x04: 53 | texColor = PVR_TXRFMT_BUMP; 54 | bpp = 2; 55 | break; //(special bump-mapping format) 56 | 57 | case 0x05: 58 | texColor = PVR_TXRFMT_PAL4BPP; 59 | bpp = 1; 60 | break; //(4-bit palleted texture) 61 | 62 | case 0x06: 63 | texColor = PVR_TXRFMT_PAL8BPP; 64 | bpp = 1; 65 | break; //(8-bit palleted texture) 66 | 67 | default: 68 | texColor = PVR_TXRFMT_RGB565; 69 | bpp = 2; 70 | break; 71 | } 72 | 73 | switch ((unsigned int)texBuf[PVR_HDR_SIZE - 7]) 74 | { 75 | case 0x01: 76 | texFormat = PVR_TXRFMT_TWIDDLED; 77 | break; //SQUARE TWIDDLED 78 | 79 | case 0x03: 80 | texFormat = PVR_TXRFMT_VQ_ENABLE; 81 | break; //VQ TWIDDLED 82 | 83 | case 0x09: 84 | texFormat = PVR_TXRFMT_NONTWIDDLED; 85 | break; //RECTANGLE 86 | 87 | case 0x0B: 88 | texFormat = PVR_TXRFMT_STRIDE | PVR_TXRFMT_NONTWIDDLED; 89 | break; //RECTANGULAR STRIDE 90 | 91 | case 0x0D: 92 | texFormat = PVR_TXRFMT_TWIDDLED; 93 | break; //RECTANGULAR TWIDDLED 94 | 95 | case 0x10: 96 | texFormat = PVR_TXRFMT_VQ_ENABLE | PVR_TXRFMT_NONTWIDDLED; 97 | break; //SMALL VQ 98 | 99 | default: 100 | texFormat = PVR_TXRFMT_NONE; 101 | break; 102 | } 103 | 104 | const int txr_size = texW * texH * bpp; 105 | *w = texW; 106 | *h = texH; 107 | *txrFormat = texFormat | texColor; 108 | 109 | return txr_size; 110 | } 111 | 112 | pvr_ptr_t load_pvr_from_buffer_to_buffer(const void* input, uint32_t* w, uint32_t* h, uint32_t* txrFormat, void* buffer) 113 | { 114 | unsigned char* texBuf = (unsigned char*)input; 115 | uint32_t txr_size = pvr_get_texture_size(input, w, h, txrFormat); 116 | 117 | pvr_txr_load(texBuf + PVR_HDR_SIZE, (pvr_ptr_t)buffer, txr_size); 118 | 119 | return buffer; 120 | } 121 | 122 | pvr_ptr_t load_pvr_from_buffer(const void* input, uint32_t* w, uint32_t* h, uint32_t* txrFormat) 123 | { 124 | pvr_ptr_t rv; 125 | unsigned char* texBuf = (unsigned char*)input; 126 | uint32_t txr_size = pvr_get_texture_size(input, w, h, txrFormat); 127 | 128 | if (!txr_size) 129 | { 130 | return NULL; 131 | } 132 | 133 | if (!(rv = pvr_mem_malloc(txr_size))) 134 | { 135 | printf("PVR: Couldn't allocate memory for texture!\n"); 136 | return NULL; 137 | } 138 | 139 | pvr_txr_load(texBuf + PVR_HDR_SIZE, rv, txr_size); 140 | 141 | return rv; 142 | } 143 | 144 | void* pvr_get_internal_buffer(void) 145 | { 146 | if (!_internal_buf) 147 | { 148 | _internal_buf = malloc(512 * 512 * 2); 149 | 150 | if (!_internal_buf) 151 | { 152 | printf("%s no free memory\n", __func__); 153 | return NULL; 154 | } 155 | } 156 | 157 | return _internal_buf; 158 | } 159 | 160 | static void pvr_read_to_internal(const char* filename) 161 | { 162 | uint32_t texSize; 163 | file_t tex_fd; 164 | 165 | snprintf(filename_safe, 127, "/cd/%s", filename); 166 | 167 | /* replace all - with _ */ 168 | char* iter = filename_safe; 169 | 170 | while (*iter++) 171 | { 172 | if (*iter == '-') 173 | { 174 | *iter = '_'; 175 | } 176 | } 177 | 178 | unsigned char* texBuf = pvr_get_internal_buffer(); 179 | memset(texBuf, '\0', PVR_HDR_SIZE); 180 | 181 | tex_fd = fs_open(filename_safe, O_RDONLY); 182 | if (tex_fd == -1) 183 | { 184 | printf("PVR:Error opening %s!\n", filename_safe); 185 | return; 186 | } 187 | 188 | fs_seek(tex_fd, 0, SEEK_END); 189 | texSize = fs_tell(tex_fd); 190 | 191 | fs_seek(tex_fd, 0, SEEK_SET); 192 | fs_read(tex_fd, texBuf, PVR_HDR_SIZE/2); 193 | 194 | if (!strncmp((char *)texBuf,"GBIX", 4)) 195 | { 196 | fs_read(tex_fd, texBuf+(PVR_HDR_SIZE/2), texSize - (PVR_HDR_SIZE/2)); 197 | } 198 | else 199 | { 200 | fs_seek(tex_fd, 0, SEEK_SET); 201 | fs_read(tex_fd, texBuf+(PVR_HDR_SIZE/2), texSize); 202 | } 203 | 204 | fs_close(tex_fd); 205 | } 206 | 207 | pvr_ptr_t load_pvr(const char* filename, uint32_t* w, uint32_t* h, uint32_t* txrFormat) 208 | { 209 | pvr_read_to_internal(filename); 210 | 211 | return load_pvr_from_buffer(_internal_buf, w, h, txrFormat); 212 | } 213 | 214 | pvr_ptr_t load_pvr_to_buffer(const char* filename, uint32_t* w, uint32_t* h, uint32_t* txrFormat, void* buffer) 215 | { 216 | pvr_read_to_internal(filename); 217 | 218 | return load_pvr_from_buffer_to_buffer(_internal_buf, w, h, txrFormat, buffer); 219 | } 220 | 221 | -------------------------------------------------------------------------------- /texture/txr_manager.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File: txr_manager.c 3 | * Project: texture 4 | * File Created: Friday, 21st May 2021 2:30:13 pm 5 | * Author: Hayden Kowalchuk 6 | * ----- 7 | * Copyright (c) 2021 Hayden Kowalchuk, Hayden Kowalchuk 8 | * License: BSD 3-clause "New" or "Revised" License, http://www.opensource.org/licenses/BSD-3-Clause 9 | */ 10 | 11 | #include "txr_manager.h" 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #include "../inc/dat_format.h" 18 | #include "../ui/draw_kos.h" 19 | #include "../ui/draw_prototypes.h" 20 | #include "block_pool.h" 21 | #include "lru.h" 22 | #include "serial_sanitize.h" 23 | 24 | /* CFG for small pvr pool (128x128 16bit, 16 spaces) */ 25 | #define SM_SLOT_NUM (16) 26 | #define SM_SLOT_SIZE (128 * 128 * 2) 27 | #define SM_POOL_SIZE (SM_SLOT_NUM * SM_SLOT_SIZE * sizeof(char)) 28 | 29 | /* CFG for large pvr pool (256x256 16bit, 4 spaces) */ 30 | #define LG_SLOT_NUM (4) 31 | #define LG_SLOT_SIZE (256 * 256 * 2) 32 | #define LG_POOL_SIZE (LG_SLOT_NUM * LG_SLOT_SIZE * sizeof(char)) 33 | 34 | typedef struct dat_system 35 | { 36 | cache_instance cache; 37 | block_pool pool; 38 | struct dat_file addon; 39 | struct dat_file primary; 40 | } dat_system; 41 | 42 | static dat_system icon_system; 43 | static dat_system box_system; 44 | 45 | unsigned int block_pool_add_cb(const char *key, void *user) 46 | { 47 | /* unused here but could be good info to know */ 48 | (void)key; 49 | 50 | block_pool *pool = (block_pool *)user; 51 | unsigned int ret; 52 | char *ptr; 53 | pool_get_next_free(pool, &ret, (void **)&ptr); 54 | return ret; 55 | } 56 | 57 | unsigned int block_pool_del_cb(const char *key, void *value, void *user) 58 | { 59 | /* unused here but could be good info to know */ 60 | (void)key; 61 | 62 | block_pool *pool = (block_pool *)user; 63 | unsigned int slot_num = *(unsigned int *)value; 64 | pool_dealloc_slot(pool, slot_num); 65 | return 0; 66 | } 67 | 68 | int txr_load_DATs(void) 69 | { 70 | serial_sanitizer_init(); /*@Todo: Move this */ 71 | 72 | DAT_init(&icon_system.addon); 73 | DAT_init(&icon_system.primary); 74 | DAT_init(&box_system.addon); 75 | DAT_init(&box_system.primary); 76 | 77 | DAT_load_parse(&icon_system.primary, "ICON.DAT"); 78 | DAT_load_parse(&box_system.primary, "BOX.DAT"); 79 | DAT_load_parse(&icon_system.addon, "ICON_EX.DAT"); 80 | DAT_load_parse(&box_system.addon, "BOX_EX.DAT"); 81 | 82 | return 0; 83 | } 84 | 85 | int txr_create_small_pool(void) 86 | { 87 | void *buffer = pvr_mem_malloc(SM_POOL_SIZE); 88 | pool_create(&icon_system.pool, buffer, SM_POOL_SIZE, SM_SLOT_NUM); 89 | icon_system.cache.cache = NULL; 90 | cache_set_size(&icon_system.cache, SM_SLOT_NUM); 91 | cache_callback_userdata(&icon_system.cache, &icon_system.pool); 92 | cache_callback_add(&icon_system.cache, block_pool_add_cb); 93 | cache_callback_del(&icon_system.cache, block_pool_del_cb); 94 | 95 | return 0; 96 | } 97 | 98 | /* pool_destroy_user(&pvr_small, pvr_mem_free); */ 99 | 100 | int txr_create_large_pool(void) 101 | { 102 | void *buffer = pvr_mem_malloc(LG_POOL_SIZE); 103 | pool_create(&box_system.pool, buffer, LG_POOL_SIZE, LG_SLOT_NUM); 104 | box_system.cache.cache = NULL; 105 | cache_set_size(&box_system.cache, LG_SLOT_NUM); 106 | cache_callback_userdata(&box_system.cache, &box_system.pool); 107 | cache_callback_add(&box_system.cache, block_pool_add_cb); 108 | cache_callback_del(&box_system.cache, block_pool_del_cb); 109 | 110 | return 0; 111 | } 112 | 113 | void txr_empty_small_pool(void) 114 | { 115 | empty_cache(&icon_system.cache); 116 | pool_dealloc_all(&icon_system.pool); 117 | } 118 | 119 | void txr_empty_large_pool(void) 120 | { 121 | empty_cache(&box_system.cache); 122 | pool_dealloc_all(&box_system.pool); 123 | } 124 | 125 | static int txr_get_from_dat_set(const char *id, struct image *img, dat_system *system) 126 | { 127 | void *txr_ptr; 128 | int slot_num; 129 | const char *id_santized = serial_santize_art(id); 130 | 131 | /* Initially check addon then fall back to regular */ 132 | uint32_t temp_offset = DAT_get_offset_by_ID(&system->addon, id_santized); 133 | const dat_file *dat_source = &system->addon; 134 | 135 | if (!temp_offset) 136 | { 137 | temp_offset = DAT_get_offset_by_ID(&system->primary, id_santized); 138 | dat_source = &system->primary; 139 | 140 | if (!temp_offset) 141 | { 142 | dat_source = NULL; 143 | } 144 | } 145 | 146 | /* check if exists in DAT and if not, return missing image */ 147 | if (!dat_source) 148 | { 149 | draw_load_missing_icon(img); 150 | return 0; 151 | } 152 | 153 | slot_num = find_in_cache(&system->cache, id_santized); 154 | 155 | if (slot_num == -1) 156 | { 157 | add_to_cache(&system->cache, id_santized, 0); 158 | slot_num = find_in_cache(&system->cache, id_santized); 159 | txr_ptr = pool_get_slot_addr(&system->pool, slot_num); 160 | 161 | /* now load the texture into vram */ 162 | draw_load_texture_from_DAT_to_buffer(dat_source, id_santized, img, txr_ptr); 163 | pool_set_slot_format(&system->pool, slot_num, img->width, img->height, img->format); 164 | } 165 | else 166 | { 167 | const slot_format *fmt = pool_get_slot_format(&system->pool, slot_num); 168 | img->width = fmt->width; 169 | img->height = fmt->height; 170 | img->format = fmt->format; 171 | img->texture = pool_get_slot_addr(&system->pool, slot_num); 172 | } 173 | 174 | return 0; 175 | } 176 | 177 | /* 178 | called with "T1121.pvr" and a pointer to pointer to vram 179 | returns pointer to use for texture upload/reference 180 | */ 181 | int txr_get_small(const char *id, struct image *img) 182 | { 183 | return txr_get_from_dat_set(id, img, &icon_system); 184 | } 185 | 186 | int txr_get_large(const char *id, struct image *img) 187 | { 188 | return txr_get_from_dat_set(id, img, &box_system); 189 | } 190 | 191 | -------------------------------------------------------------------------------- /external/ini.h: -------------------------------------------------------------------------------- 1 | /* inih -- simple .INI file parser 2 | 3 | SPDX-License-Identifier: BSD-3-Clause 4 | 5 | Copyright (C) 2009-2020, Ben Hoyt 6 | 7 | inih is released under the New BSD license (see LICENSE.txt). Go to the project 8 | home page for more info: 9 | 10 | https://github.com/benhoyt/inih 11 | 12 | */ 13 | 14 | #ifndef INI_H 15 | #define INI_H 16 | 17 | /* Make this header file easier to include in C++ code */ 18 | #ifdef __cplusplus 19 | extern "C" { 20 | #endif 21 | 22 | #ifdef COSMO 23 | #include "../tools/cosmo/cosmopolitan.h" 24 | #else 25 | #include 26 | #endif 27 | 28 | #include "ini_opt.h" 29 | 30 | /* Nonzero if ini_handler callback should accept lineno parameter. */ 31 | #ifndef INI_HANDLER_LINENO 32 | #define INI_HANDLER_LINENO 0 33 | #endif 34 | 35 | /* Typedef for prototype of handler function. */ 36 | #if INI_HANDLER_LINENO 37 | typedef int (*ini_handler)(void* user, const char* section, const char* name, const char* value, int lineno); 38 | #else 39 | typedef int (*ini_handler)(void* user, const char* section, const char* name, const char* value); 40 | #endif 41 | 42 | /* Typedef for prototype of fgets-style reader function. */ 43 | typedef char* (*ini_reader)(char* str, int num, void* stream); 44 | 45 | /* Parse given INI-style file. May have [section]s, name=value pairs 46 | (whitespace stripped), and comments starting with ';' (semicolon). Section 47 | is "" if name=value pair parsed before any section heading. name:value 48 | pairs are also supported as a concession to Python's configparser. 49 | 50 | For each name=value pair parsed, call handler function with given user 51 | pointer as well as section, name, and value (data only valid for duration 52 | of handler call). Handler should return nonzero on success, zero on error. 53 | 54 | Returns 0 on success, line number of first error on parse error (doesn't 55 | stop on first error), -1 on file open error, or -2 on memory allocation 56 | error (only when INI_USE_STACK is zero). 57 | */ 58 | int ini_parse(const char* filename, ini_handler handler, void* user); 59 | 60 | /* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't 61 | close the file when it's finished -- the caller must do that. */ 62 | int ini_parse_file(FILE* file, ini_handler handler, void* user); 63 | 64 | /* Same as ini_parse(), but takes an ini_reader function pointer instead of 65 | filename. Used for implementing custom or string-based I/O (see also 66 | ini_parse_string). */ 67 | int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler, void* user); 68 | 69 | /* Same as ini_parse(), but takes a zero-terminated string with the INI data 70 | instead of a file. Useful for parsing INI data from a network socket or 71 | already in memory. */ 72 | int ini_parse_string(const char* string, ini_handler handler, void* user); 73 | 74 | /* Nonzero to allow multi-line value parsing, in the style of Python's 75 | configparser. If allowed, ini_parse() will call the handler with the same 76 | name for each subsequent line parsed. */ 77 | #ifndef INI_ALLOW_MULTILINE 78 | #define INI_ALLOW_MULTILINE 1 79 | #endif 80 | 81 | /* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of 82 | the file. See https://github.com/benhoyt/inih/issues/21 */ 83 | #ifndef INI_ALLOW_BOM 84 | #define INI_ALLOW_BOM 1 85 | #endif 86 | 87 | /* Chars that begin a start-of-line comment. Per Python configparser, allow 88 | both ; and # comments at the start of a line by default. */ 89 | #ifndef INI_START_COMMENT_PREFIXES 90 | #define INI_START_COMMENT_PREFIXES ";#" 91 | #endif 92 | 93 | /* Nonzero to allow inline comments (with valid inline comment characters 94 | specified by INI_INLINE_COMMENT_PREFIXES). Set to 0 to turn off and match 95 | Python 3.2+ configparser behaviour. */ 96 | #ifndef INI_ALLOW_INLINE_COMMENTS 97 | #define INI_ALLOW_INLINE_COMMENTS 1 98 | #endif 99 | #ifndef INI_INLINE_COMMENT_PREFIXES 100 | #define INI_INLINE_COMMENT_PREFIXES ";" 101 | #endif 102 | 103 | /* Nonzero to use stack for line buffer, zero to use heap (malloc/free). */ 104 | #ifndef INI_USE_STACK 105 | #define INI_USE_STACK 1 106 | #endif 107 | 108 | /* Maximum line length for any line in INI file (stack or heap). Note that 109 | this must be 3 more than the longest line (due to '\r', '\n', and '\0'). */ 110 | #ifndef INI_MAX_LINE 111 | #define INI_MAX_LINE 200 112 | #endif 113 | 114 | /* Nonzero to allow heap line buffer to grow via realloc(), zero for a 115 | fixed-size buffer of INI_MAX_LINE bytes. Only applies if INI_USE_STACK is 116 | zero. */ 117 | #ifndef INI_ALLOW_REALLOC 118 | #define INI_ALLOW_REALLOC 0 119 | #endif 120 | 121 | /* Initial size in bytes for heap line buffer. Only applies if INI_USE_STACK 122 | is zero. */ 123 | #ifndef INI_INITIAL_ALLOC 124 | #define INI_INITIAL_ALLOC 200 125 | #endif 126 | 127 | /* Stop parsing on first error (default is to keep parsing). */ 128 | #ifndef INI_STOP_ON_FIRST_ERROR 129 | #define INI_STOP_ON_FIRST_ERROR 0 130 | #endif 131 | 132 | /* Nonzero to call the handler at the start of each new section (with 133 | name and value NULL). Default is to only call the handler on 134 | each name=value pair. */ 135 | #ifndef INI_CALL_HANDLER_ON_NEW_SECTION 136 | #define INI_CALL_HANDLER_ON_NEW_SECTION 0 137 | #endif 138 | 139 | /* Nonzero to allow a name without a value (no '=' or ':' on the line) and 140 | call the handler with value NULL in this case. Default is to treat 141 | no-value lines as an error. */ 142 | #ifndef INI_ALLOW_NO_VALUE 143 | #define INI_ALLOW_NO_VALUE 0 144 | #endif 145 | 146 | /* Nonzero to use custom ini_malloc, ini_free, and ini_realloc memory 147 | allocation functions (INI_USE_STACK must also be 0). These functions must 148 | have the same signatures as malloc/free/realloc and behave in a similar 149 | way. ini_realloc is only needed if INI_ALLOW_REALLOC is set. */ 150 | #ifndef INI_CUSTOM_ALLOCATOR 151 | #define INI_CUSTOM_ALLOCATOR 0 152 | #endif 153 | 154 | 155 | #ifdef __cplusplus 156 | } 157 | #endif 158 | 159 | #endif /* INI_H */ 160 | -------------------------------------------------------------------------------- /ui/dc/font_bitmap.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File: font.c 3 | * Project: ui 4 | * File Created: Monday, 3rd June 2019 1:00:17 pm 5 | * Author: Hayden Kowalchuk (hayden@hkowsoftware.com) 6 | * ----- 7 | * Copyright (c) 2019 Hayden Kowalchuk 8 | */ 9 | 10 | #include 11 | 12 | #include "../../inc/dbgprint.h" 13 | #include "../draw_prototypes.h" 14 | 15 | typedef struct bitmap_font 16 | { 17 | int char_width; 18 | int char_height; 19 | image texture; 20 | } bitmap_font; 21 | 22 | static bitmap_font font; 23 | static uint32_t font_color; 24 | 25 | #define FONT_PERROW(font) (font.texture.width / font.char_width) 26 | #define BUFFER_MAX_CHARS (128) 27 | 28 | #ifdef KOS_SPRITE 29 | static pvr_sprite_hdr_t font_header; 30 | #define VERT_PER_CHAR (1) 31 | static pvr_sprite_txr_t charbuf[BUFFER_MAX_CHARS * VERT_PER_CHAR] __attribute__((aligned(32))); 32 | #else 33 | static pvr_poly_hdr_t font_header; 34 | #define VERT_PER_CHAR (4) 35 | static pvr_vertex_t charbuf[BUFFER_MAX_CHARS * VERT_PER_CHAR] __attribute__((aligned(32))); 36 | #endif 37 | 38 | static int charbuffered; 39 | 40 | int font_bmp_init(const char *filename, int char_width, int char_height) 41 | { 42 | unsigned int temp = texman_create(); 43 | draw_load_texture_buffer(filename, &font.texture, texman_get_tex_data(temp)); 44 | texman_reserve_memory(font.texture.width, font.texture.height, 2 /* 16Bit */); 45 | 46 | font.char_height = char_height; 47 | font.char_width = char_width; 48 | 49 | font_color = 0xFFFFFFFF; // White 50 | 51 | return 0; 52 | } 53 | 54 | void font_bmp_begin_draw() 55 | { 56 | /* Make a polygon header */ 57 | #ifdef KOS_SPRITE 58 | pvr_sprite_cxt_t tmp; 59 | pvr_sprite_cxt_txr(&tmp, draw_get_list(), font.texture.format, font.texture.width, font.texture.height, font.texture.texture, PVR_FILTER_NONE); 60 | pvr_sprite_compile(&font_header, &tmp); 61 | #else 62 | pvr_poly_cxt_t tmp; 63 | pvr_poly_cxt_txr(&tmp, draw_get_list(), font.texture.format, font.texture.width, font.texture.height, font.texture.texture, PVR_FILTER_BILINEAR); 64 | pvr_poly_compile(&font_header, &tmp); 65 | #endif 66 | } 67 | 68 | void font_bmp_set_color(uint32_t color) 69 | { 70 | /*@Note: Either lxdream-nitro weirdness or something is wrong in how we draw, set both to 0xFFFFFFFF */ 71 | font_color = color; 72 | #ifdef KOS_SPRITE 73 | font_header.argb = color; 74 | #endif 75 | /* Start a textured polygon set (with the font texture and color) */ 76 | pvr_prim(&font_header, sizeof(font_header)); 77 | } 78 | 79 | void font_bmp_set_color_default(void) 80 | { 81 | font_bmp_set_color(0xFFFFFFFF); 82 | } 83 | 84 | void font_bmp_set_color_components(int r, int g, int b, int a) 85 | { 86 | font_color = PVR_PACK_ARGB(a, r, g, b); 87 | } 88 | 89 | /* Draws a font letter using two triangle strips */ 90 | static void font_bmp_draw_char(int x, int y, unsigned char ch) 91 | { 92 | const int index = ch - 32; 93 | const int ix = (index % FONT_PERROW(font)) * font.char_width; 94 | const int iy = (index / FONT_PERROW(font)) * font.char_height; 95 | 96 | /* Upper left */ 97 | const float x1 = x; 98 | const float y1 = y; 99 | const float u1 = ix * 1.0f / font.texture.width; 100 | const float v1 = iy * 1.0f / font.texture.height; 101 | 102 | /* Lower right */ 103 | const float x2 = x1 + font.char_width; 104 | const float y2 = y1 + font.char_height; 105 | const float u2 = (ix + font.char_width) * 1.0f / font.texture.width; 106 | const float v2 = (iy + font.char_height) * 1.0f / font.texture.height; 107 | 108 | const float z = z_get(); 109 | 110 | if (index == -1) 111 | { 112 | return; 113 | } 114 | #ifdef KOS_SPRITE 115 | pvr_sprite_txr_t vert = 116 | { 117 | .flags = PVR_CMD_VERTEX_EOL, /* Always? */ 118 | /* upper left */ 119 | .ax = x1, 120 | .ay = y1, 121 | .az = z, 122 | /* upper right */ 123 | .bx = x2, 124 | .by = y1, 125 | .bz = z, 126 | /* lower left */ 127 | .cx = x2, 128 | .cy = y2, 129 | .cz = z, 130 | /* interpolated */ 131 | .dx = x1, 132 | .dy = y2, 133 | .auv = PVR_PACK_16BIT_UV(u1, v1), /* UVS */ 134 | .buv = PVR_PACK_16BIT_UV(u2, v1), /* UVS */ 135 | .cuv = PVR_PACK_16BIT_UV(u2, v2), /* UVS */ 136 | }; 137 | 138 | charbuf[charbuffered] = vert; 139 | #else 140 | pvr_vertex_t *vert1, *vert2, *vert3, *vert4; 141 | vert1 = &charbuf[charbuffered + 0]; 142 | vert2 = &charbuf[charbuffered + 1]; 143 | vert3 = &charbuf[charbuffered + 2]; 144 | vert4 = &charbuf[charbuffered + 3]; 145 | 146 | vert1->flags = PVR_CMD_VERTEX; 147 | vert1->x = x1; 148 | vert1->y = y2; 149 | vert1->z = z; 150 | vert1->u = u1; 151 | vert1->v = v2; 152 | vert1->argb = font_color; 153 | vert1->oargb = 0; 154 | 155 | vert2->flags = PVR_CMD_VERTEX; 156 | vert2->x = x1; 157 | vert2->y = y1; 158 | vert2->z = z; 159 | vert2->u = u1; 160 | vert2->v = v1; 161 | vert2->argb = font_color; 162 | vert2->oargb = 0; 163 | 164 | vert3->flags = PVR_CMD_VERTEX; 165 | vert3->x = x2; 166 | vert3->y = y2; 167 | vert3->z = z; 168 | vert3->u = u2; 169 | vert3->v = v2; 170 | vert3->argb = font_color; 171 | vert3->oargb = 0; 172 | 173 | vert4->flags = PVR_CMD_VERTEX_EOL; 174 | vert4->x = x2; 175 | vert4->y = y1; 176 | vert4->z = z; 177 | vert4->u = u2; 178 | vert4->v = v1; 179 | vert4->argb = font_color; 180 | vert4->oargb = 0; 181 | #endif 182 | charbuffered += VERT_PER_CHAR; 183 | } 184 | 185 | static void _font_bmp_draw_string(int x1, int y1, const char *str) 186 | { 187 | z_inc(); 188 | charbuffered = 0; 189 | 190 | do 191 | { 192 | unsigned char chr = (*str); 193 | font_bmp_draw_char(x1, y1, chr); 194 | x1 += (int)(font.char_width); 195 | } 196 | while (*++str); 197 | 198 | pvr_prim(charbuf, charbuffered * sizeof(charbuf[0])); 199 | } 200 | 201 | /* @Note: revisit this */ 202 | void font_bmp_draw_sub_wrap(int x1, int y1, int width, const char *str) 203 | { 204 | (void)width; 205 | _font_bmp_draw_string(x1, y1, str); 206 | } 207 | 208 | void font_bmp_draw_main(int x1, int y1, const char *str) 209 | { 210 | _font_bmp_draw_string(x1, y1, str); 211 | } 212 | 213 | void font_draw_sub(int x1, int y1, const char *str) 214 | { 215 | _font_bmp_draw_string(x1, y1, str); 216 | } 217 | 218 | -------------------------------------------------------------------------------- /ui/global_settings.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File: global_settings.c 3 | * Project: ui 4 | * File Created: Monday, 12th July 2021 10:33:21 am 5 | * Author: Hayden Kowalchuk 6 | * ----- 7 | * Copyright (c) 2021 Hayden Kowalchuk, Hayden Kowalchuk 8 | * License: BSD 3-clause "New" or "Revised" License, http://www.opensource.org/licenses/BSD-3-Clause 9 | */ 10 | 11 | #include "global_settings.h" 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | /* Images and such */ 22 | #if __has_include("openmenu_lcd.h") && __has_include("openmenu_pal.h") && __has_include("openmenu_vmu.h") 23 | #include "openmenu_lcd.h" 24 | #include "openmenu_pal.h" 25 | #include "openmenu_vmu.h" 26 | 27 | #define OPENMENU_ICON (openmenu_icon) 28 | #define OPENMENU_LCD (openmenu_lcd) 29 | #define OPENMENU_PAL (openmenu_pal) 30 | #define OPENMENU_ICONS (1) 31 | #else 32 | #define OPENMENU_ICON (NULL) 33 | #define OPENMENU_LCD (NULL) 34 | #define OPENMENU_PAL (NULL) 35 | #define OPENMENU_ICONS (0) 36 | #endif 37 | 38 | static openmenu_settings savedata; 39 | 40 | static void settings_defaults(void) 41 | { 42 | savedata.identifier[0] = 'O'; 43 | savedata.identifier[1] = 'M'; 44 | savedata.version = SETTINGS_VERSION; 45 | savedata.ui = UI_LINE_DESC; 46 | savedata.region = REGION_NTSC_U; 47 | savedata.aspect = ASPECT_NORMAL; 48 | savedata.sort = SORT_DEFAULT; 49 | savedata.filter = FILTER_ALL; 50 | savedata.beep = BEEP_ON; 51 | savedata.multidisc = MULTIDISC_SHOW; 52 | savedata.custom_theme = THEME_OFF; 53 | savedata.custom_theme_num = THEME_0; 54 | } 55 | 56 | static void vmu_alldisplay_icon(uint8_t *bitmap) 57 | { 58 | int i = 0; 59 | maple_device_t *dev; 60 | 61 | while((dev = maple_enum_type(i++, MAPLE_FUNC_LCD))) 62 | { 63 | vmu_draw_lcd(dev, bitmap); 64 | } 65 | } 66 | 67 | static int settings_validate(openmenu_settings *s) 68 | { 69 | if (s->version != SETTINGS_VERSION) 70 | { 71 | return -1; 72 | } 73 | 74 | if (s->identifier[0] != 'O' || s->identifier[1] != 'M') 75 | { 76 | return -2; 77 | } 78 | 79 | if ((s->ui < UI_START) || (s->ui > UI_END)) 80 | { 81 | savedata.ui = UI_LINE_DESC; 82 | } 83 | 84 | if ((s->region < REGION_START) || (s->region > REGION_END)) 85 | { 86 | savedata.region = REGION_NTSC_U; 87 | } 88 | 89 | if ((s->aspect < ASPECT_START) || (s->aspect > ASPECT_END)) 90 | { 91 | savedata.aspect = ASPECT_NORMAL; 92 | } 93 | 94 | if ((s->sort < SORT_START) || (s->sort > SORT_END)) 95 | { 96 | savedata.sort = SORT_DEFAULT; 97 | } 98 | 99 | if ((s->filter < FILTER_START) || (s->filter > FILTER_END)) 100 | { 101 | savedata.filter = FILTER_ALL; 102 | } 103 | 104 | if ((s->beep < BEEP_START) || (s->beep > BEEP_END)) 105 | { 106 | savedata.beep = BEEP_ON; 107 | } 108 | 109 | if ((s->multidisc < MULTIDISC_START) || (s->multidisc > MULTIDISC_END)) 110 | { 111 | savedata.multidisc = MULTIDISC_SHOW; 112 | } 113 | 114 | if ((s->custom_theme < THEME_START) || (s->custom_theme > THEME_END)) 115 | { 116 | savedata.custom_theme_num = (CFG_CUSTOM_THEME_NUM) THEME_OFF; 117 | } 118 | 119 | if (s->custom_theme_num > THEME_NUM_END) 120 | { 121 | savedata.custom_theme_num = THEME_NUM_START; 122 | } 123 | 124 | if (s->custom_theme) 125 | { 126 | savedata.region = REGION_END + 1 + s->custom_theme_num; 127 | } 128 | 129 | return 0; 130 | } 131 | 132 | void settings_init(void) 133 | { 134 | settings_defaults(); 135 | 136 | #if OPENMENU_ICONS 137 | vmu_alldisplay_icon(OPENMENU_LCD); 138 | #endif 139 | thd_sleep(200); 140 | 141 | settings_load(); 142 | } 143 | 144 | void settings_load(void) 145 | { 146 | char save_name[24]; 147 | maple_device_t *vmu; 148 | file_t f; 149 | openmenu_settings tmp; 150 | 151 | for (int i = 0; i < 8; i++) 152 | { 153 | if (!(vmu = maple_enum_type(i, MAPLE_FUNC_MEMCARD))) 154 | { 155 | // no more connected VMU's 156 | //printf("vmu %d not connected\n", i); 157 | return; 158 | } 159 | 160 | // Try and load savefile 161 | 162 | sprintf(save_name, "/vmu/%c%c/OPENMENU.CFG", vmu->port+'A', vmu->unit+'0'); 163 | 164 | if ((f = fs_open(save_name, O_RDONLY)) == FILEHND_INVALID) 165 | { 166 | //printf("save %s not found\n", save_name); 167 | continue; 168 | } 169 | 170 | fs_read(f, &tmp, sizeof(openmenu_settings)); 171 | 172 | if (settings_validate(&tmp) < 0) 173 | { 174 | //printf("settings not valid\n"); 175 | fs_close(f); 176 | fs_unlink(save_name); 177 | continue; 178 | } 179 | 180 | memcpy(&savedata, &tmp, sizeof(openmenu_settings)); 181 | 182 | fs_close(f); 183 | 184 | if (savedata.beep == BEEP_ON) 185 | { 186 | vmu_beep_raw(vmu, 0x000065f0); // Turn on Beep 187 | thd_sleep(500); 188 | vmu_beep_raw(vmu, 0x00000000); // Turn off Beep 189 | } 190 | 191 | return; 192 | } 193 | } 194 | 195 | /* Beeps while saving if enabled */ 196 | void settings_save(void) 197 | { 198 | char save_name[24]; 199 | maple_device_t *vmu; 200 | file_t f; 201 | int pkg_size; 202 | vmu_pkg_t pkg; 203 | uint8_t *pkg_out; 204 | 205 | strcpy(pkg.desc_short, "openMenu Config"); 206 | strcpy(pkg.desc_long, "openMenu Preferences"); 207 | strcpy(pkg.app_id, "openMenuPref"); 208 | 209 | pkg.icon_cnt = OPENMENU_ICONS; 210 | pkg.icon_data = OPENMENU_ICON; 211 | pkg.icon_anim_speed = 0; 212 | pkg.eyecatch_type = VMUPKG_EC_NONE; 213 | memcpy(pkg.icon_pal, OPENMENU_PAL, 32); 214 | pkg.data = (uint8_t *) &savedata; 215 | pkg.data_len = sizeof(openmenu_settings); 216 | 217 | if(vmu_pkg_build(&pkg, &pkg_out, &pkg_size) < 0) 218 | { 219 | //printf("ERROR can't build vmu_pkg\n"); 220 | return; 221 | } 222 | 223 | for (int i = 0; i < 8; i++) 224 | { 225 | if (!(vmu = maple_enum_type(i, MAPLE_FUNC_MEMCARD))) 226 | { 227 | // no more connected VMU's 228 | break; 229 | } 230 | 231 | sprintf(save_name, "/vmu/%c%c/OPENMENU.CFG", vmu->port+'A', vmu->unit+'0'); 232 | 233 | if ((f = fs_open(save_name, O_RDONLY)) != FILEHND_INVALID) 234 | { 235 | // save file found 236 | fs_close(f); 237 | fs_unlink(save_name); 238 | } 239 | 240 | if((vmufs_free_blocks(vmu)*512) < pkg_size) 241 | { 242 | // no free memory, try next vmu 243 | //printf("ERROR vmu don't have free memory\n"); 244 | continue; 245 | } 246 | 247 | if ((f = fs_open(save_name, O_WRONLY | O_META)) == FILEHND_INVALID) 248 | { 249 | // can't create save file, try next vmu 250 | //printf("ERROR cant create %s\n", save_name); 251 | fs_close(f); 252 | fs_unlink(save_name); 253 | } 254 | 255 | fs_write(f, pkg_out, pkg_size); 256 | fs_close(f); 257 | 258 | if (savedata.beep == BEEP_ON) 259 | { 260 | vmu_beep_raw(vmu, 0x000065f0); // Turn on Beep 261 | thd_sleep(500); 262 | vmu_beep_raw(vmu, 0x00000000); // Turn off Beep 263 | } 264 | 265 | break; 266 | } 267 | 268 | free(pkg_out); 269 | } 270 | 271 | openmenu_settings *settings_get(void) 272 | { 273 | return &savedata; 274 | } 275 | 276 | -------------------------------------------------------------------------------- /backend/gdemu_control.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "inc/vm2_api.h" 7 | #include "backend/gd_item.h" 8 | #include "gdemu_sdk.h" 9 | #include "gdmenu_binary.h" 10 | #include "cb_loader.h" 11 | #include "controls.p1.h" 12 | 13 | extern maple_device_t *vm2_dev; 14 | 15 | static void wait_cd_ready(void) 16 | { 17 | for (int i = 0; i < 500; i++) 18 | { 19 | if (cdrom_reinit() == ERR_OK) 20 | { 21 | return; 22 | } 23 | thd_sleep(20); 24 | } 25 | } 26 | 27 | void bloom_launch(gd_item *disc) 28 | { 29 | file_t fd; 30 | uint32_t bloom_size; 31 | uint8_t *bloom_buf; 32 | 33 | fd = fs_open("/cd/BLOOM.BIN", O_RDONLY); 34 | 35 | if (fd == -1) 36 | { 37 | printf("Can't open %s\n", "/cd/BLOOM.BIN"); 38 | return; 39 | } 40 | 41 | fs_seek(fd, 0, SEEK_END); 42 | bloom_size = fs_tell(fd); 43 | fs_seek(fd, 0, SEEK_SET); 44 | bloom_buf = (uint8_t*) malloc(bloom_size+32); 45 | bloom_buf = (uint8_t*) (((uint32_t) bloom_buf & 0xffffffe0) + 0x20); 46 | fs_read(fd, bloom_buf, bloom_size); 47 | fs_close(fd); 48 | 49 | gdemu_set_img_num((uint16_t)disc->slot_num); 50 | 51 | wait_cd_ready(); 52 | 53 | /* Patch */ 54 | ((uint16_t *) 0xAC000198)[0] = 0xFF86; 55 | 56 | arch_exec(bloom_buf, bloom_size); 57 | } 58 | 59 | void bleem_launch(gd_item *disc) 60 | { 61 | file_t fd; 62 | uint32_t bleem_size; 63 | uint8_t *bleem_buf; 64 | 65 | fd = fs_open("/cd/BLEEM.BIN", O_RDONLY); 66 | 67 | if (fd == -1) 68 | { 69 | printf("Can't open %s\n", "/cd/BLEEM.BIN"); 70 | return; 71 | } 72 | 73 | fs_seek(fd, 0, SEEK_END); 74 | bleem_size = fs_tell(fd); 75 | fs_seek(fd, 0, SEEK_SET); 76 | bleem_buf = (uint8_t*) malloc(bleem_size+32); 77 | bleem_buf = (uint8_t*) (((uint32_t) bleem_buf & 0xffffffe0) + 0x20); 78 | fs_read(fd, bleem_buf, bleem_size); 79 | fs_close(fd); 80 | 81 | gdemu_set_img_num((uint16_t)disc->slot_num); 82 | 83 | wait_cd_ready(); 84 | 85 | /* Patch */ 86 | ((uint16_t *) 0xAC000198)[0] = 0xFF86; 87 | 88 | for (int i = 0; i < altctrl_size; i++) 89 | { 90 | bleem_buf[i+0x7079C] = altctrl_data[i]; 91 | } 92 | 93 | bleem_buf[0x49E6] = 0x06; // patch restart emu A+B+X+Y+dpad down 94 | bleem_buf[0x49E7] = 0x0E; // exit to menu A+B+X+Y+START 95 | 96 | bleem_buf[0x1CA70] = 1; 97 | 98 | arch_exec(bleem_buf, bleem_size); 99 | } 100 | 101 | void dreamcast_launch_disc(gd_item *disc) 102 | { 103 | ldr_params_t param; 104 | param.region_free = 1; 105 | param.force_vga = 1; 106 | param.IGR = 1; 107 | param.boot_intro = 1; 108 | param.sega_license = 1; 109 | 110 | if (!strncmp(disc->region, "JUE", 3)) 111 | { 112 | param.game_region = (int)(((uint8_t *) 0x8C000072)[0] & 7); 113 | } 114 | else 115 | { 116 | switch (disc->region[0]) 117 | { 118 | case 'J': 119 | param.game_region = 0; 120 | break; 121 | 122 | case 'U': 123 | param.game_region = 1; 124 | break; 125 | 126 | case 'E': 127 | param.game_region = 2; 128 | break; 129 | 130 | default: 131 | param.game_region = (int)(((uint8_t *) 0x8C000072)[0] & 7); 132 | break; 133 | } 134 | } 135 | 136 | gdemu_set_img_num((uint16_t)disc->slot_num); 137 | //thd_sleep(500); 138 | 139 | if (vm2_dev) 140 | { 141 | vm2_set_id(vm2_dev, disc->product, disc->name); 142 | } 143 | 144 | wait_cd_ready(); 145 | 146 | int status = 0, disc_type = 0; 147 | 148 | cdrom_get_status(&status, &disc_type); 149 | 150 | param.disc_type = disc_type == CD_GDROM; 151 | 152 | if (!strncmp(disc->name, "PSO VER.2", 9) || !strncmp(disc->name, "SONIC ADVENTURE 2", 18)) 153 | { 154 | param. need_game_fix = 1; 155 | } 156 | else 157 | { 158 | param. need_game_fix = 0; 159 | } 160 | 161 | if (!strncmp((char*)0x8c0007CC, "1.004", 5)) 162 | { 163 | ((uint32_t *) 0xAC000E20)[0] = 0; 164 | } 165 | else if (!strncmp((char*)0x8c0007CC, "1.01d", 5) || 166 | !strncmp((char*)0x8c0007CC, "1.01c", 5)) 167 | { 168 | ((uint32_t *) 0xAC000E1C)[0] = 0; 169 | } 170 | 171 | ((uint32_t *) 0xAC0000E4)[0] = -3; 172 | 173 | memcpy((void*)0xACCFFF00, ¶m, 32); 174 | 175 | arch_exec(gdmenu_loader, gdmenu_loader_length); 176 | } 177 | 178 | void dreamcast_launch_cb(gd_item *disc) 179 | { 180 | file_t fd; 181 | uint32_t cb_size; 182 | uint8_t *cb_buf; 183 | uint32_t cheat_size = 0; 184 | uint8_t *cheat_buf; 185 | char cheat_name[32]; 186 | 187 | fd = fs_open("/cd/PELICAN.BIN", O_RDONLY); 188 | 189 | if (fd == -1) 190 | { 191 | return; 192 | } 193 | 194 | fs_seek(fd, 0, SEEK_END); 195 | cb_size = fs_tell(fd); 196 | fs_seek(fd, 0, SEEK_SET); 197 | cb_buf = (uint8_t*) malloc(cb_size+32); 198 | cb_buf = (uint8_t*) (((uint32_t) cb_buf & 0xffffffe0) + 0x20); 199 | fs_read(fd, cb_buf, cb_size); 200 | fs_close(fd); 201 | 202 | sprintf(cheat_name, "/cd/cheats/%s.bin", disc->product); 203 | 204 | if ((fd = fs_open(cheat_name, O_RDONLY)) == -1) 205 | { 206 | fd = fs_open("/cd/cheats/FCDCHEATS.BIN", O_RDONLY); 207 | } 208 | 209 | if (fd != -1) 210 | { 211 | fs_seek(fd, 0, SEEK_END); 212 | cheat_size = fs_tell(fd); 213 | fs_seek(fd, 0, SEEK_SET); 214 | 215 | cheat_buf = (uint8_t*) malloc(cheat_size+32); 216 | cheat_buf = (uint8_t*) (((uint32_t) cheat_buf & 0xffffffe0) + 0x20); 217 | 218 | fs_read(fd, cheat_buf, 16); 219 | 220 | if (!strncmp((const char *) cheat_buf, "XploderDC Cheats", 16)) 221 | { 222 | fs_seek(fd, 640, SEEK_SET); 223 | cheat_size -= 640; 224 | fs_read(fd, cheat_buf, cheat_size); 225 | 226 | if (!((uint32_t *) cheat_buf)[0]) 227 | { 228 | cheat_size = 0; 229 | } 230 | } 231 | else 232 | { 233 | cheat_size = 0; 234 | } 235 | 236 | fs_close(fd); 237 | } 238 | 239 | gdemu_set_img_num((uint16_t)disc->slot_num); 240 | //thd_sleep(500); 241 | 242 | if (vm2_dev) 243 | { 244 | vm2_set_id(vm2_dev, disc->product, disc->name); 245 | } 246 | 247 | wait_cd_ready(); 248 | 249 | ((uint16_t *) 0xAC000198)[0] = 0xFF86; 250 | 251 | int status = 0, disc_type = 0; 252 | 253 | cdrom_get_status(&status, &disc_type); 254 | 255 | if (cheat_size) 256 | { 257 | uint16_t *pelican = (uint16_t *) cb_buf; 258 | 259 | pelican[128] = 0; 260 | pelican[129] = 0x90; 261 | 262 | pelican[10818] = (uint16_t) cheat_size; 263 | pelican[10819] = (cheat_size >> 16); 264 | 265 | pelican[10820] = 0; 266 | pelican[10821] = 0x8CD0; 267 | 268 | memcpy((void*)0xACD00000, cheat_buf, cheat_size); 269 | } 270 | 271 | if (disc_type != CD_GDROM) 272 | { 273 | CDROM_TOC toc; 274 | cdrom_read_toc(&toc, 0); 275 | uint32_t lba = cdrom_locate_data_track(&toc); 276 | 277 | uint16_t *pelican = (uint16_t *) cb_buf; 278 | 279 | pelican[4067] = 0x711F; 280 | pelican[4074] = 0xE500; 281 | pelican[4302] = (uint16_t) lba; 282 | pelican[4303] = (uint16_t) (lba >> 16); 283 | pelican[472] = 0x0009; 284 | pelican[4743] = 0x0018; 285 | pelican[4745] = 0x0018; 286 | pelican[5261] = 0x0008; 287 | pelican[5433] = 0x0009; 288 | pelican[5436] = 0x0009; 289 | pelican[5438] = 0x0008; 290 | pelican[5460] = 0x0009; 291 | pelican[5472] = 0x0009; 292 | pelican[5511] = 0x0008; 293 | pelican[310573] = 0x64C3; 294 | pelican[310648] = 0x0009; 295 | pelican[310666] = 0x0009; 296 | pelican[310708] = 0x0018; 297 | pelican[310784] = 0x0000; 298 | pelican[310785] = 0x8CE1; 299 | 300 | memcpy((void*)0xACE10000, cb_loader_data, cb_loader_size); 301 | } 302 | 303 | arch_exec(cb_buf, cb_size); 304 | } 305 | 306 | -------------------------------------------------------------------------------- /external/easing.c: -------------------------------------------------------------------------------- 1 | // 2 | // easing.c 3 | // 4 | // Copyright (c) 2011, Auerhaus Development, LLC 5 | // 6 | // This program is free software. It comes without any warranty, to 7 | // the extent permitted by applicable law. You can redistribute it 8 | // and/or modify it under the terms of the Do What The Fuck You Want 9 | // To Public License, Version 2, as published by Sam Hocevar. See 10 | // http://sam.zoy.org/wtfpl/COPYING for more details. 11 | // 12 | 13 | #include "easing.h" 14 | 15 | #include 16 | 17 | /* Possible missing defines */ 18 | #ifndef M_PI 19 | #define M_PI (3.14159265358979323846) 20 | #endif 21 | #ifndef M_PI_2 22 | #define M_PI_2 (1.57079632679489661923) 23 | #endif 24 | 25 | // Modeled after the line y = x 26 | AHFloat LinearInterpolation(AHFloat p) 27 | { 28 | return p; 29 | } 30 | 31 | // Modeled after the parabola y = x^2 32 | AHFloat QuadraticEaseIn(AHFloat p) 33 | { 34 | return p * p; 35 | } 36 | 37 | // Modeled after the parabola y = -x^2 + 2x 38 | AHFloat QuadraticEaseOut(AHFloat p) 39 | { 40 | return -(p * (p - 2)); 41 | } 42 | 43 | // Modeled after the piecewise quadratic 44 | // y = (1/2)((2x)^2) ; [0, 0.5) 45 | // y = -(1/2)((2x-1)*(2x-3) - 1) ; [0.5, 1] 46 | AHFloat QuadraticEaseInOut(AHFloat p) 47 | { 48 | if (p < 0.5) 49 | { 50 | return 2 * p * p; 51 | } 52 | 53 | return (-2 * p * p) + (4 * p) - 1; 54 | } 55 | 56 | // Modeled after the cubic y = x^3 57 | AHFloat CubicEaseIn(AHFloat p) 58 | { 59 | return p * p * p; 60 | } 61 | 62 | // Modeled after the cubic y = (x - 1)^3 + 1 63 | AHFloat CubicEaseOut(AHFloat p) 64 | { 65 | AHFloat f = (p - 1); 66 | return f * f * f + 1; 67 | } 68 | 69 | // Modeled after the piecewise cubic 70 | // y = (1/2)((2x)^3) ; [0, 0.5) 71 | // y = (1/2)((2x-2)^3 + 2) ; [0.5, 1] 72 | AHFloat CubicEaseInOut(AHFloat p) 73 | { 74 | if (p < 0.5) 75 | { 76 | return 4 * p * p * p; 77 | } 78 | 79 | AHFloat f = ((2 * p) - 2); 80 | return 0.5 * f * f * f + 1; 81 | } 82 | 83 | // Modeled after the quartic x^4 84 | AHFloat QuarticEaseIn(AHFloat p) 85 | { 86 | return p * p * p * p; 87 | } 88 | 89 | // Modeled after the quartic y = 1 - (x - 1)^4 90 | AHFloat QuarticEaseOut(AHFloat p) 91 | { 92 | AHFloat f = (p - 1); 93 | return f * f * f * (1 - p) + 1; 94 | } 95 | 96 | // Modeled after the piecewise quartic 97 | // y = (1/2)((2x)^4) ; [0, 0.5) 98 | // y = -(1/2)((2x-2)^4 - 2) ; [0.5, 1] 99 | AHFloat QuarticEaseInOut(AHFloat p) 100 | { 101 | if (p < 0.5) 102 | { 103 | return 8 * p * p * p * p; 104 | } 105 | 106 | AHFloat f = (p - 1); 107 | return -8 * f * f * f * f + 1; 108 | } 109 | 110 | // Modeled after the quintic y = x^5 111 | AHFloat QuinticEaseIn(AHFloat p) 112 | { 113 | return p * p * p * p * p; 114 | } 115 | 116 | // Modeled after the quintic y = (x - 1)^5 + 1 117 | AHFloat QuinticEaseOut(AHFloat p) 118 | { 119 | AHFloat f = (p - 1); 120 | return f * f * f * f * f + 1; 121 | } 122 | 123 | // Modeled after the piecewise quintic 124 | // y = (1/2)((2x)^5) ; [0, 0.5) 125 | // y = (1/2)((2x-2)^5 + 2) ; [0.5, 1] 126 | AHFloat QuinticEaseInOut(AHFloat p) 127 | { 128 | if (p < 0.5) 129 | { 130 | return 16 * p * p * p * p * p; 131 | } 132 | 133 | AHFloat f = ((2 * p) - 2); 134 | return 0.5 * f * f * f * f * f + 1; 135 | } 136 | 137 | // Modeled after quarter-cycle of sine wave 138 | AHFloat SineEaseIn(AHFloat p) 139 | { 140 | return sin((p - 1) * M_PI_2) + 1; 141 | } 142 | 143 | // Modeled after quarter-cycle of sine wave (different phase) 144 | AHFloat SineEaseOut(AHFloat p) 145 | { 146 | return sin(p * M_PI_2); 147 | } 148 | 149 | // Modeled after half sine wave 150 | AHFloat SineEaseInOut(AHFloat p) 151 | { 152 | return 0.5 * (1 - cos(p * M_PI)); 153 | } 154 | 155 | // Modeled after shifted quadrant IV of unit circle 156 | AHFloat CircularEaseIn(AHFloat p) 157 | { 158 | return 1 - sqrt(1 - (p * p)); 159 | } 160 | 161 | // Modeled after shifted quadrant II of unit circle 162 | AHFloat CircularEaseOut(AHFloat p) 163 | { 164 | return sqrt((2 - p) * p); 165 | } 166 | 167 | // Modeled after the piecewise circular function 168 | // y = (1/2)(1 - sqrt(1 - 4x^2)) ; [0, 0.5) 169 | // y = (1/2)(sqrt(-(2x - 3)*(2x - 1)) + 1) ; [0.5, 1] 170 | AHFloat CircularEaseInOut(AHFloat p) 171 | { 172 | if (p < 0.5) 173 | { 174 | return 0.5 * (1 - sqrt(1 - 4 * (p * p))); 175 | } 176 | 177 | return 0.5 * (sqrt(-((2 * p) - 3) * ((2 * p) - 1)) + 1); 178 | } 179 | 180 | // Modeled after the exponential function y = 2^(10(x - 1)) 181 | AHFloat ExponentialEaseIn(AHFloat p) 182 | { 183 | return (p == 0.0) ? p : pow(2, 10 * (p - 1)); 184 | } 185 | 186 | // Modeled after the exponential function y = -2^(-10x) + 1 187 | AHFloat ExponentialEaseOut(AHFloat p) 188 | { 189 | return (p == 1.0) ? p : 1 - pow(2, -10 * p); 190 | } 191 | 192 | // Modeled after the piecewise exponential 193 | // y = (1/2)2^(10(2x - 1)) ; [0,0.5) 194 | // y = -(1/2)*2^(-10(2x - 1))) + 1 ; [0.5,1] 195 | AHFloat ExponentialEaseInOut(AHFloat p) 196 | { 197 | if (p == 0.0 || p == 1.0) 198 | { 199 | return p; 200 | } 201 | 202 | if (p < 0.5) 203 | { 204 | return 0.5 * pow(2, (20 * p) - 10); 205 | } 206 | 207 | return -0.5 * pow(2, (-20 * p) + 10) + 1; 208 | } 209 | 210 | // Modeled after the damped sine wave y = sin(13pi/2*x)*pow(2, 10 * (x - 1)) 211 | AHFloat ElasticEaseIn(AHFloat p) 212 | { 213 | return sin(13 * M_PI_2 * p) * pow(2, 10 * (p - 1)); 214 | } 215 | 216 | // Modeled after the damped sine wave y = sin(-13pi/2*(x + 1))*pow(2, -10x) + 1 217 | AHFloat ElasticEaseOut(AHFloat p) 218 | { 219 | return sin(-13 * M_PI_2 * (p + 1)) * pow(2, -10 * p) + 1; 220 | } 221 | 222 | // Modeled after the piecewise exponentially-damped sine wave: 223 | // y = (1/2)*sin(13pi/2*(2*x))*pow(2, 10 * ((2*x) - 1)) ; [0,0.5) 224 | // y = (1/2)*(sin(-13pi/2*((2x-1)+1))*pow(2,-10(2*x-1)) + 2) ; [0.5, 1] 225 | AHFloat ElasticEaseInOut(AHFloat p) 226 | { 227 | if (p < 0.5) 228 | { 229 | return 0.5 * sin(13 * M_PI_2 * (2 * p)) * pow(2, 10 * ((2 * p) - 1)); 230 | } 231 | 232 | return 0.5 * (sin(-13 * M_PI_2 * ((2 * p - 1) + 1)) * pow(2, -10 * (2 * p - 1)) + 2); 233 | } 234 | 235 | // Modeled after the overshooting cubic y = x^3-x*sin(x*pi) 236 | AHFloat BackEaseIn(AHFloat p) 237 | { 238 | return p * p * p - p * sin(p * M_PI); 239 | } 240 | 241 | // Modeled after overshooting cubic y = 1-((1-x)^3-(1-x)*sin((1-x)*pi)) 242 | AHFloat BackEaseOut(AHFloat p) 243 | { 244 | AHFloat f = (1 - p); 245 | return 1 - (f * f * f - f * sin(f * M_PI)); 246 | } 247 | 248 | // Modeled after the piecewise overshooting cubic function: 249 | // y = (1/2)*((2x)^3-(2x)*sin(2*x*pi)) ; [0, 0.5) 250 | // y = (1/2)*(1-((1-x)^3-(1-x)*sin((1-x)*pi))+1) ; [0.5, 1] 251 | AHFloat BackEaseInOut(AHFloat p) 252 | { 253 | if (p < 0.5) 254 | { 255 | AHFloat f = 2 * p; 256 | return 0.5 * (f * f * f - f * sin(f * M_PI)); 257 | } 258 | 259 | AHFloat f = (1 - (2 * p - 1)); 260 | return 0.5 * (1 - (f * f * f - f * sin(f * M_PI))) + 0.5; 261 | } 262 | 263 | AHFloat BounceEaseIn(AHFloat p) 264 | { 265 | return 1 - BounceEaseOut(1 - p); 266 | } 267 | 268 | AHFloat BounceEaseOut(AHFloat p) 269 | { 270 | if (p < 4 / 11.0) 271 | { 272 | return (121 * p * p) / 16.0; 273 | } 274 | else if (p < 8 / 11.0) 275 | { 276 | return (363 / 40.0 * p * p) - (99 / 10.0 * p) + 17 / 5.0; 277 | } 278 | else if (p < 9 / 10.0) 279 | { 280 | return (4356 / 361.0 * p * p) - (35442 / 1805.0 * p) + 16061 / 1805.0; 281 | } 282 | 283 | return (54 / 5.0 * p * p) - (513 / 25.0 * p) + 268 / 25.0; 284 | } 285 | 286 | AHFloat BounceEaseInOut(AHFloat p) 287 | { 288 | if (p < 0.5) 289 | { 290 | return 0.5 * BounceEaseIn(p * 2); 291 | } 292 | 293 | return 0.5 * BounceEaseOut(p * 2 - 1) + 0.5; 294 | } 295 | 296 | -------------------------------------------------------------------------------- /texture/serial_sanitize.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File: serial_sanitize.c 3 | * Project: texture 4 | * File Created: Tuesday, 8th June 2021 10:24:28 pm 5 | * Author: Hayden Kowalchuk 6 | * ----- 7 | * Copyright (c) 2021 Hayden Kowalchuk, Hayden Kowalchuk 8 | * License: BSD 3-clause "New" or "Revised" License, http://www.opensource.org/licenses/BSD-3-Clause 9 | */ 10 | 11 | #include 12 | 13 | // Disc serial will be the filename, e.g. T8119N.PVR 14 | /* Name, IP Serial, Disc Serial */ 15 | // F355 Challenge: Passione Rossa, MK-0100, T-8119N 16 | 17 | enum REMAP_TYPE 18 | { 19 | REMAP_NONE = (0 << 0), // 0 20 | REMAP_ART = (1 << 0), // 1 21 | REMAP_META = (1 << 1), // 2 22 | }; 23 | 24 | #define REMAP_ADD_ART(ip, disc) (serial_remap) \ 25 | { \ 26 | .ip_serial = ip, \ 27 | .art_serial = disc, \ 28 | .remap_choice = REMAP_ART \ 29 | } 30 | 31 | #define REMAP_ADD_META(ip, disc) (serial_remap) \ 32 | { \ 33 | .ip_serial = ip, \ 34 | .meta_serial = disc, \ 35 | .remap_choice = REMAP_META \ 36 | } 37 | 38 | #define REMAP_ADD_BOTH(ip, disc)(serial_remap) \ 39 | { \ 40 | .ip_serial = ip, \ 41 | .meta_serial = disc, \ 42 | .art_serial = disc, \ 43 | .remap_choice = REMAP_META | REMAP_ART \ 44 | } 45 | 46 | typedef struct serial_remap 47 | { 48 | const char* ip_serial; 49 | const char* art_serial; 50 | const char* meta_serial; 51 | UT_hash_handle hh; /* makes this structure hashable */ 52 | const enum REMAP_TYPE remap_choice; 53 | } serial_remap; 54 | 55 | /* Generate from excel with: 56 | find: ^(.*)[\t](.*)[\n] 57 | replace: REMAP_ADD_META("$1", "$2"),\n 58 | */ 59 | 60 | static serial_remap serial_remap_members[] = 61 | { 62 | /* PAL Regional Duplicates */ 63 | REMAP_ADD_BOTH("T13001D05", "T13001D"), /* Blue Stinger */ 64 | REMAP_ADD_BOTH("T8111D58", "T8111D50"), /* ECW Hardcore Revolution */ 65 | //T9705D50 T9706D50 NBA Showtime: NBA on NBC, Incorrect IP.BIN 66 | //T7003D T7005D Plasma Sword: Nightmare of Bilstein, Incorrect IP.BIN 67 | REMAP_ADD_BOTH("T45001D09", "T45001D05"), /* Tom Clancy's Rainbow Six */ 68 | REMAP_ADD_BOTH("T45001D18", "T45001D05"), /* Tom Clancy's Rainbow Six */ 69 | REMAP_ADD_BOTH("T45002D09", "T45002D05"), /* Tom Clancy's Rainbow Six: Rogue Spear */ 70 | REMAP_ADD_BOTH("T36815D06", "T36804D05"), /* Tomb Raider Chronicles */ 71 | REMAP_ADD_BOTH("T36815D13", "T36804D05"), /* Tomb Raider Chronicles */ 72 | REMAP_ADD_BOTH("T36815D18", "T36804D05"), /* Tomb Raider Chronicles */ 73 | REMAP_ADD_BOTH("MK5109506", "MK5109505"), /* UEFA Dream Soccer */ 74 | REMAP_ADD_BOTH("MK5109509", "MK5109505"), /* UEFA Dream Soccer */ 75 | REMAP_ADD_BOTH("MK5109518", "MK5109505"), /* UEFA Dream Soccer */ 76 | REMAP_ADD_BOTH("T8103N18", "T8103N50"), /* WWF Attitude */ 77 | 78 | /* PAL Missing Meta */ 79 | REMAP_ADD_META("T10001D", "T10004N"), 80 | REMAP_ADD_META("MK5100450", "MK51004"), 81 | REMAP_ADD_META("MK5117850", "MK51178"), /* NBA 2K2 */ 82 | REMAP_ADD_META("T9713D", "T9709N"), 83 | REMAP_ADD_META("T9705D50", "T9706N"), 84 | REMAP_ADD_META("T9703D50", "T9703N"), 85 | REMAP_ADD_META("T8102D", "T8101N"), 86 | REMAP_ADD_META("MK5102550", "MK51025"), 87 | REMAP_ADD_META("T9502D50", "T9504N"), /* Nightmare Creatures II */ 88 | REMAP_ADD_META("MK5110250", "MK51102"), 89 | REMAP_ADD_META("T7003D", "T1207N"), 90 | REMAP_ADD_META("T17710D50", "T17713N"), 91 | REMAP_ADD_META("T8106D50", "T31101N"), 92 | REMAP_ADD_META("MK5106150", "MK51061"), 93 | REMAP_ADD_META("T45006D50", "17701N"), 94 | REMAP_ADD_META("17701D", "17701N"), 95 | REMAP_ADD_META("17707D", "17707N"), 96 | REMAP_ADD_META("T8107D", "T8109N"), 97 | REMAP_ADD_META("T7012D", "T40218N"), 98 | REMAP_ADD_META("MK5102151", "T40215N"), 99 | REMAP_ADD_META("T7004D", "T1205N"), 100 | REMAP_ADD_META("T7021D", "T1220N"), 101 | REMAP_ADD_META("T22901D", "T22901N"), 102 | REMAP_ADD_META("T9709D50", "T9707N"), 103 | REMAP_ADD_META("MK5100650", "MK51006"), 104 | REMAP_ADD_META("MK5105350", "MK51053"), 105 | REMAP_ADD_META("MK5101950", "MK51019"), 106 | REMAP_ADD_META("T8104D", "T8106N"), 107 | REMAP_ADD_META("T9505D", "T9507N"), 108 | REMAP_ADD_META("T15109D", "T15108N"), 109 | REMAP_ADD_META("T15104D", "T15106N"), 110 | REMAP_ADD_META("T17722D", "T40207N"), 111 | REMAP_ADD_META("T17726D", "T40212N"), 112 | REMAP_ADD_META("MK5100050", "MK51000"), 113 | REMAP_ADD_META("MK5106050", "MK51060"), 114 | REMAP_ADD_META("T1401D", "T1401N"), 115 | REMAP_ADD_META("T41401D", "T41401N"), 116 | REMAP_ADD_META("T8105D50", "T8105N"), 117 | REMAP_ADD_META("T8112D50", "T8116N"), 118 | REMAP_ADD_META("MK5105150", "MK51051"), 119 | REMAP_ADD_META("T36816D", "T1216N"), 120 | REMAP_ADD_META("T45004D", "T41704N"), 121 | REMAP_ADD_META("T17702D", "T17702N"), 122 | REMAP_ADD_META("T17713D", "T17718N"), 123 | REMAP_ADD_META("T13011D50", "T13008N"), /* Spider-Man */ 124 | REMAP_ADD_META("T8117D50", "T8118N"), 125 | REMAP_ADD_META("T23001D", "T23001N"), 126 | REMAP_ADD_META("T13010D", "T23003N"), 127 | REMAP_ADD_META("T17723D", "T40209N"), 128 | REMAP_ADD_META("T7005D", "T1203N"), 129 | REMAP_ADD_META("T7013D50", "T1213N"), 130 | REMAP_ADD_META("T7006D", "T1210N"), 131 | REMAP_ADD_META("T17711D", "T17708N"), 132 | REMAP_ADD_META("T40206D", "T40206N"), 133 | REMAP_ADD_META("T17721D", "T40216N"), 134 | REMAP_ADD_META("T17703D", "T17703N"), 135 | REMAP_ADD_META("T36807D", "T36805N"), 136 | REMAP_ADD_META("T36808D", "T36808N"), 137 | REMAP_ADD_META("T7009D50", "T1208N"), 138 | REMAP_ADD_META("T8108D", "T8108N"), 139 | REMAP_ADD_META("T9503D", "T9512N"), 140 | REMAP_ADD_META("MK5100250", "MK51002"), 141 | REMAP_ADD_META("MK5101153", "MK51011"), 142 | REMAP_ADD_META("T40201D", "T40202N"), 143 | REMAP_ADD_META("T40210D", "T40211N"), 144 | REMAP_ADD_META("T45001D05", "T40401N"), 145 | REMAP_ADD_META("T45002D05", "T40402N"), 146 | REMAP_ADD_META("T36815D05", "T36812N"), 147 | REMAP_ADD_META("T36804D05", "T36806N"), 148 | REMAP_ADD_META("T13008D", "T13006N"), 149 | REMAP_ADD_META("T40204D", "T40205N"), 150 | REMAP_ADD_META("MK5102050", "MK57020"), 151 | REMAP_ADD_META("T8101D50", "T8102N"), 152 | REMAP_ADD_META("T40203D", "T40204N"), 153 | REMAP_ADD_META("T15113D", "T15125N"), 154 | REMAP_ADD_META("T36810D", "T36810N"), 155 | REMAP_ADD_META("T8110D50", "T8110N"), 156 | REMAP_ADD_META("T13002D", "T13002N"), 157 | REMAP_ADD_META("MK5109450", "T44301N"), 158 | REMAP_ADD_META("MK5100150", "MK51001"), 159 | REMAP_ADD_META("MK5102850", "MK51028"), 160 | REMAP_ADD_META("MK5105450", "MK51054"), 161 | REMAP_ADD_META("T15106D", "T15113N"), 162 | REMAP_ADD_META("T36809D", "T36804N"), 163 | REMAP_ADD_META("T40504D", "T8111N"), 164 | REMAP_ADD_META("T40601D", "T40601N"), 165 | REMAP_ADD_META("T7016D", "T22904N"), 166 | REMAP_ADD_META("T8103N50", "T8103N"), 167 | REMAP_ADD_META("T10003D", "T10005N"), 168 | 169 | /* JAP Missing Meta */ 170 | REMAP_ADD_META("HDR0054", "MK51053"), /* Sega GT */ 171 | REMAP_ADD_META("HDR0053", "MK51035"), 172 | REMAP_ADD_META("HDR0159", "MK51136"), 173 | REMAP_ADD_META("T3601M", "T3602M"), 174 | REMAP_ADD_META("T3602M", "T3601N"), 175 | REMAP_ADD_META("T40903M", "T40901M"), 176 | REMAP_ADD_META("HDR0129", "MK51100"), 177 | REMAP_ADD_META("HDR0163", "MK51193"), 178 | REMAP_ADD_META("HDR0178", "MK5119250"), 179 | REMAP_ADD_META("HDR0010", "MK51019"), 180 | REMAP_ADD_META("HDR0063", "MK51092"), 181 | REMAP_ADD_META("HDR0016", "MK5105950"), 182 | REMAP_ADD_META("HDR0164", "MK5118450"), 183 | REMAP_ADD_META("T30801M", "T40202N"), 184 | REMAP_ADD_META("T30803M", "T40211N"), 185 | REMAP_ADD_META("HDR0029", "MK51051") 186 | }; 187 | 188 | static const int serials_added = sizeof(serial_remap_members) / sizeof(serial_remap); 189 | static serial_remap* serial_remap_list = NULL; 190 | 191 | const char* serial_santize_art(const char* id) 192 | { 193 | const serial_remap* item; 194 | const char* ret = id; 195 | 196 | HASH_FIND_STR(serial_remap_list, id, item); 197 | 198 | if (item && (item->remap_choice & REMAP_ART)) 199 | { 200 | ret = item->art_serial; 201 | } 202 | 203 | return ret; 204 | } 205 | 206 | const char* serial_santize_meta(const char* id) 207 | { 208 | const serial_remap* item; 209 | const char* ret = id; 210 | 211 | HASH_FIND_STR(serial_remap_list, id, item); 212 | 213 | if (item && (item->remap_choice & REMAP_META)) 214 | { 215 | ret = item->meta_serial; 216 | } 217 | 218 | return ret; 219 | } 220 | 221 | int serial_sanitizer_init(void) 222 | { 223 | for (int i = 0; i < serials_added; i++) 224 | { 225 | HASH_ADD_STR(serial_remap_list, ip_serial, &serial_remap_members[i]); 226 | } 227 | 228 | return 0; 229 | } 230 | 231 | -------------------------------------------------------------------------------- /external/ini.c: -------------------------------------------------------------------------------- 1 | /* inih -- simple .INI file parser 2 | 3 | SPDX-License-Identifier: BSD-3-Clause 4 | 5 | Copyright (C) 2009-2020, Ben Hoyt 6 | 7 | inih is released under the New BSD license (see LICENSE.txt). Go to the project 8 | home page for more info: 9 | 10 | https://github.com/benhoyt/inih 11 | 12 | */ 13 | 14 | #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) 15 | #define _CRT_SECURE_NO_WARNINGS 16 | #endif 17 | 18 | #ifdef COSMO 19 | #include "../tools/cosmo/cosmopolitan.h" 20 | #else 21 | #include 22 | #include 23 | #include 24 | #endif 25 | 26 | #include "ini.h" 27 | 28 | #if !INI_USE_STACK 29 | #if INI_CUSTOM_ALLOCATOR 30 | #include 31 | void* ini_malloc(size_t size); 32 | void ini_free(void* ptr); 33 | void* ini_realloc(void* ptr, size_t size); 34 | #else 35 | #ifndef COSMO 36 | #include 37 | #endif 38 | #define ini_malloc malloc 39 | #define ini_free free 40 | #define ini_realloc realloc 41 | #endif 42 | #endif 43 | 44 | #define MAX_SECTION 50 45 | #define MAX_NAME 50 46 | 47 | /* Used by ini_parse_string() to keep track of string parsing state. */ 48 | typedef struct 49 | { 50 | const char* ptr; 51 | size_t num_left; 52 | } ini_parse_string_ctx; 53 | 54 | /* Strip whitespace chars off end of given string, in place. Return s. */ 55 | static char* rstrip(char* s) 56 | { 57 | char* p = s + strlen(s); 58 | 59 | while (p > s && isspace((unsigned char)(*--p))) 60 | { 61 | *p = '\0'; 62 | } 63 | 64 | return s; 65 | } 66 | 67 | /* Return pointer to first non-whitespace char in given string. */ 68 | static char* lskip(const char* s) 69 | { 70 | while (*s && isspace((unsigned char)(*s))) 71 | { 72 | s++; 73 | } 74 | 75 | return (char*)s; 76 | } 77 | 78 | /* Return pointer to first char (of chars) or inline comment in given string, 79 | or pointer to NUL at end of string if neither found. Inline comment must 80 | be prefixed by a whitespace character to register as a comment. */ 81 | static char* find_chars_or_comment(const char* s, const char* chars) 82 | { 83 | #if INI_ALLOW_INLINE_COMMENTS 84 | int was_space = 0; 85 | while (*s && (!chars || !strchr(chars, *s)) && 86 | !(was_space && strchr(INI_INLINE_COMMENT_PREFIXES, *s))) 87 | { 88 | was_space = isspace((unsigned char)(*s)); 89 | s++; 90 | } 91 | #else 92 | while (*s && (!chars || !strchr(chars, *s))) 93 | { 94 | s++; 95 | } 96 | #endif 97 | return (char*)s; 98 | } 99 | 100 | /* Similar to strncpy, but ensures dest (size bytes) is 101 | NUL-terminated, and doesn't pad with NULs. */ 102 | static char* strncpy0(char* dest, const char* src, size_t size) 103 | { 104 | /* Could use strncpy internally, but it causes gcc warnings (see issue #91) */ 105 | size_t i; 106 | for (i = 0; i < size - 1 && src[i]; i++) 107 | { 108 | dest[i] = src[i]; 109 | } 110 | dest[i] = '\0'; 111 | 112 | return dest; 113 | } 114 | 115 | /* See documentation in header file. */ 116 | int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler, void* user) 117 | { 118 | /* Uses a fair bit of stack (use heap instead if you need to) */ 119 | #if INI_USE_STACK 120 | char line[INI_MAX_LINE]; 121 | int max_line = INI_MAX_LINE; 122 | #else 123 | char* line; 124 | size_t max_line = INI_INITIAL_ALLOC; 125 | #endif 126 | #if INI_ALLOW_REALLOC && !INI_USE_STACK 127 | char* new_line; 128 | size_t offset; 129 | #endif 130 | char section[MAX_SECTION] = ""; 131 | char prev_name[MAX_NAME] = ""; 132 | 133 | char* start; 134 | char* end; 135 | char* name; 136 | char* value; 137 | int lineno = 0; 138 | int error = 0; 139 | 140 | #if !INI_USE_STACK 141 | line = (char*)ini_malloc(INI_INITIAL_ALLOC); 142 | if (!line) { 143 | return -2; 144 | } 145 | #endif 146 | 147 | #if INI_HANDLER_LINENO 148 | #define HANDLER(u, s, n, v) handler(u, s, n, v, lineno) 149 | #else 150 | #define HANDLER(u, s, n, v) handler(u, s, n, v) 151 | #endif 152 | 153 | /* Scan through stream line by line */ 154 | while (reader(line, (int)max_line, stream) != NULL) 155 | { 156 | #if INI_ALLOW_REALLOC && !INI_USE_STACK 157 | offset = strlen(line); 158 | while (offset == max_line - 1 && line[offset - 1] != '\n') 159 | { 160 | max_line *= 2; 161 | if (max_line > INI_MAX_LINE) 162 | { 163 | max_line = INI_MAX_LINE; 164 | } 165 | 166 | new_line = ini_realloc(line, max_line); 167 | 168 | if (!new_line) 169 | { 170 | ini_free(line); 171 | return -2; 172 | } 173 | 174 | line = new_line; 175 | if (reader(line + offset, (int)(max_line - offset), stream) == NULL) 176 | { 177 | break; 178 | } 179 | 180 | if (max_line >= INI_MAX_LINE) 181 | { 182 | break; 183 | } 184 | 185 | offset += strlen(line + offset); 186 | } 187 | #endif 188 | 189 | lineno++; 190 | 191 | start = line; 192 | #if INI_ALLOW_BOM 193 | if (lineno == 1 && (unsigned char)start[0] == 0xEF && 194 | (unsigned char)start[1] == 0xBB && 195 | (unsigned char)start[2] == 0xBF) 196 | { 197 | start += 3; 198 | } 199 | #endif 200 | start = lskip(rstrip(start)); 201 | 202 | if (strchr(INI_START_COMMENT_PREFIXES, *start)) 203 | { 204 | /* Start-of-line comment */ 205 | } 206 | #if INI_ALLOW_MULTILINE 207 | else if (*prev_name && *start && start > line) 208 | { 209 | /* Non-blank line with leading whitespace, treat as continuation 210 | of previous name's value (as per Python configparser). */ 211 | if (!HANDLER(user, section, prev_name, start) && !error) 212 | { 213 | error = lineno; 214 | } 215 | } 216 | #endif 217 | else if (*start == '[') 218 | { 219 | /* A "[section]" line */ 220 | end = find_chars_or_comment(start + 1, "]"); 221 | if (*end == ']') 222 | { 223 | *end = '\0'; 224 | strncpy0(section, start + 1, sizeof(section)); 225 | *prev_name = '\0'; 226 | #if INI_CALL_HANDLER_ON_NEW_SECTION 227 | if (!HANDLER(user, section, NULL, NULL) && !error) 228 | { 229 | error = lineno; 230 | } 231 | #endif 232 | } 233 | else if (!error) 234 | { 235 | /* No ']' found on section line */ 236 | error = lineno; 237 | } 238 | } 239 | else if (*start) { 240 | /* Not a comment, must be a name[=:]value pair */ 241 | end = find_chars_or_comment(start, "=:"); 242 | if (*end == '=' || *end == ':') 243 | { 244 | *end = '\0'; 245 | name = rstrip(start); 246 | value = end + 1; 247 | #if INI_ALLOW_INLINE_COMMENTS 248 | end = find_chars_or_comment(value, NULL); 249 | if (*end) 250 | { 251 | *end = '\0'; 252 | } 253 | #endif 254 | value = lskip(value); 255 | rstrip(value); 256 | 257 | /* Valid name[=:]value pair found, call handler */ 258 | strncpy0(prev_name, name, sizeof(prev_name)); 259 | if (!HANDLER(user, section, name, value) && !error) 260 | { 261 | error = lineno; 262 | } 263 | } 264 | else if (!error) 265 | { 266 | /* No '=' or ':' found on name[=:]value line */ 267 | #if INI_ALLOW_NO_VALUE 268 | *end = '\0'; 269 | name = rstrip(start); 270 | if (!HANDLER(user, section, name, NULL) && !error) 271 | error = lineno; 272 | #else 273 | error = lineno; 274 | #endif 275 | } 276 | } 277 | 278 | #if INI_STOP_ON_FIRST_ERROR 279 | if (error) 280 | { 281 | break; 282 | } 283 | #endif 284 | } 285 | 286 | #if !INI_USE_STACK 287 | ini_free(line); 288 | #endif 289 | 290 | return error; 291 | } 292 | 293 | /* See documentation in header file. */ 294 | int ini_parse_file(FILE* file, ini_handler handler, void* user) 295 | { 296 | return ini_parse_stream((ini_reader)fgets, file, handler, user); 297 | } 298 | 299 | /* See documentation in header file. */ 300 | int ini_parse(const char* filename, ini_handler handler, void* user) 301 | { 302 | FILE* file; 303 | int error; 304 | 305 | file = fopen(filename, "rb"); 306 | if (!file) 307 | { 308 | return -1; 309 | } 310 | error = ini_parse_file(file, handler, user); 311 | fclose(file); 312 | return error; 313 | } 314 | 315 | /* An ini_reader function to read the next line from a string buffer. This 316 | is the fgets() equivalent used by ini_parse_string(). */ 317 | static char* ini_reader_string(char* str, int num, void* stream) 318 | { 319 | ini_parse_string_ctx* ctx = (ini_parse_string_ctx*)stream; 320 | const char* ctx_ptr = ctx->ptr; 321 | size_t ctx_num_left = ctx->num_left; 322 | char* strp = str; 323 | char c; 324 | 325 | if (ctx_num_left == 0 || num < 2) 326 | { 327 | return NULL; 328 | } 329 | 330 | while (num > 1 && ctx_num_left != 0) 331 | { 332 | c = *ctx_ptr++; 333 | ctx_num_left--; 334 | *strp++ = c; 335 | 336 | if (c == '\n') 337 | { 338 | break; 339 | } 340 | num--; 341 | } 342 | 343 | *strp = '\0'; 344 | ctx->ptr = ctx_ptr; 345 | ctx->num_left = ctx_num_left; 346 | return str; 347 | } 348 | 349 | /* See documentation in header file. */ 350 | int ini_parse_string(const char* string, ini_handler handler, void* user) 351 | { 352 | ini_parse_string_ctx ctx; 353 | 354 | ctx.ptr = string; 355 | ctx.num_left = strlen(string); 356 | 357 | return ini_parse_stream((ini_reader)ini_reader_string, &ctx, handler, user); 358 | } 359 | 360 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * File: main.c 4 | * Project: kos_pvr_texture_load 5 | * File Created: Wednesday, 23rd January 2019 8:07:09 pm 6 | * Author: Hayden Kowalchuk (hayden@hkowsoftware.com) 7 | * ----- 8 | * Copyright (c) 2019 Hayden Kowalchuk 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "backend/db_list.h" 26 | #include "backend/gd_list.h" 27 | #include "ui/common.h" 28 | #include "ui/dc/input.h" 29 | #include "ui/draw_prototypes.h" 30 | #include "ui/global_settings.h" 31 | #include "ui/ui_menu_credits.h" 32 | #include "inc/vm2_api.h" 33 | 34 | /* UI Collection */ 35 | #include "ui/ui_grid.h" 36 | #undef UI_NAME 37 | #include "ui/ui_line_desc.h" 38 | #undef UI_NAME 39 | #include "ui/ui_scroll.h" 40 | #undef UI_NAME 41 | 42 | #include "texture/txr_manager.h" 43 | 44 | #include "inc/bloader.h" 45 | 46 | maple_device_t *vm2_dev = NULL; 47 | 48 | void (*current_ui_init)(void); 49 | void (*current_ui_setup)(void); 50 | void (*current_ui_draw_OP)(void); 51 | void (*current_ui_draw_TR)(void); 52 | void (*current_ui_handle_input)(unsigned int); 53 | 54 | typedef struct ui_template 55 | { 56 | void (*init)(void); 57 | void (*setup)(void); 58 | void (*drawOP)(void); 59 | void (*drawTR)(void); 60 | void (*handle_input)(unsigned int); 61 | } ui_template; 62 | 63 | #define UI_TEMPLATE(name) (ui_template) \ 64 | { \ 65 | .init = FUNC_NAME(name, init), \ 66 | .setup = FUNC_NAME(name, setup), \ 67 | .drawOP = FUNC_NAME(name, drawOP), \ 68 | .drawTR = FUNC_NAME(name, drawTR), \ 69 | .handle_input = FUNC_NAME(name, handle_input), \ 70 | } 71 | 72 | static ui_template ui_choices[] = 73 | { 74 | UI_TEMPLATE(LIST_DESC), 75 | UI_TEMPLATE(GRID_3), 76 | UI_TEMPLATE(SCROLL), 77 | }; 78 | 79 | static const int num_ui_choices = sizeof(ui_choices) / sizeof(ui_template); 80 | static int need_reload_ui = 0; 81 | 82 | static void ui_set_choice(int choice) 83 | { 84 | need_reload_ui = 0; 85 | 86 | if (choice < UI_START || choice >= num_ui_choices) 87 | { 88 | choice = UI_START; 89 | } 90 | 91 | current_ui_init = ui_choices[choice].init; 92 | current_ui_setup = ui_choices[choice].setup; 93 | current_ui_draw_OP = ui_choices[choice].drawOP; 94 | current_ui_draw_TR = ui_choices[choice].drawTR; 95 | current_ui_handle_input = ui_choices[choice].handle_input; 96 | 97 | /* Call init & setup */ 98 | (*current_ui_init)(); 99 | (*current_ui_setup)(); 100 | } 101 | 102 | void reload_ui(void) 103 | { 104 | need_reload_ui = 1; 105 | } 106 | 107 | static int init(void) 108 | { 109 | int ret = 0; 110 | 111 | /* Load settings */ 112 | settings_init(); 113 | 114 | ret += txr_create_small_pool(); 115 | ret += txr_create_large_pool(); 116 | ret += txr_load_DATs(); 117 | ret += list_read_default(); 118 | ret += db_load_DAT(); 119 | ret += theme_manager_load(); 120 | 121 | openmenu_settings* cur = settings_get(); 122 | 123 | if(!cur->filter) 124 | { 125 | switch (cur->sort) 126 | { 127 | case SORT_NAME: 128 | list_set_sort_name(); 129 | break; 130 | 131 | case SORT_DATE: 132 | list_set_sort_region(); 133 | break; 134 | 135 | case SORT_PRODUCT: 136 | list_set_sort_genre(); 137 | break; 138 | 139 | default: 140 | case SORT_DEFAULT: 141 | list_set_sort_default(); 142 | break; 143 | } 144 | } 145 | else 146 | { 147 | list_set_genre_sort((FLAGS_GENRE)cur->filter - 1, cur->sort); 148 | } 149 | 150 | /* setup internal memory zones */ 151 | draw_init(); 152 | 153 | /* Load UI */ 154 | ui_set_choice(cur->ui); 155 | 156 | return ret; 157 | } 158 | 159 | static void draw(void) 160 | { 161 | pvr_wait_ready(); 162 | pvr_scene_begin(); 163 | 164 | draw_set_list(PVR_LIST_OP_POLY); 165 | pvr_list_begin(PVR_LIST_OP_POLY); 166 | 167 | (*current_ui_draw_OP)(); 168 | 169 | pvr_list_finish(); 170 | 171 | draw_set_list(PVR_LIST_TR_POLY); 172 | pvr_list_begin(PVR_LIST_TR_POLY); 173 | 174 | (*current_ui_draw_TR)(); 175 | 176 | pvr_list_finish(); 177 | 178 | pvr_scene_finish(); 179 | } 180 | 181 | static void processInput(void) 182 | { 183 | inputs _input; 184 | unsigned int buttons; 185 | 186 | maple_device_t *cont; 187 | cont_state_t *state; 188 | 189 | cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER); 190 | 191 | if (!cont) 192 | return; 193 | 194 | state = (cont_state_t *)maple_dev_status(cont); 195 | 196 | buttons = state->buttons; 197 | 198 | /* Reset Everything */ 199 | memset(&_input, 0, sizeof(inputs)); 200 | 201 | /* DPAD */ 202 | _input.dpad = (state->buttons >> 4) & ~240; //mrneo240 ;) 203 | 204 | /* BUTTONS */ 205 | _input.btn_a = (uint8_t) !!(buttons & CONT_A); 206 | _input.btn_b = (uint8_t) !!(buttons & CONT_B); 207 | _input.btn_x = (uint8_t) !!(buttons & CONT_X); 208 | _input.btn_y = (uint8_t) !!(buttons & CONT_Y); 209 | _input.btn_start = (uint8_t) !!(buttons & CONT_START); 210 | 211 | /* ANALOG */ 212 | _input.axes_1 = ((uint8_t)(state->joyx) + 128); 213 | _input.axes_2 = ((uint8_t)(state->joyy) + 128); 214 | 215 | /* TRIGGERS */ 216 | if (!strncmp("Dreamcast Fishing Controller", cont->info.product_name, 28)) 217 | { 218 | _input.trg_left = 0; 219 | _input.trg_right = 0; 220 | } 221 | else 222 | { 223 | _input.trg_left = (uint8_t)state->ltrig & 255; 224 | _input.trg_right = (uint8_t)state->rtrig & 255; 225 | } 226 | 227 | INPT_ReceiveFromHost(_input); 228 | } 229 | 230 | static int translate_input(void) 231 | { 232 | processInput(); 233 | 234 | if (INPT_DPADDirection(DPAD_LEFT)) 235 | { 236 | return LEFT; 237 | } 238 | 239 | if (INPT_DPADDirection(DPAD_RIGHT)) 240 | { 241 | return RIGHT; 242 | } 243 | 244 | if (INPT_DPADDirection(DPAD_UP)) 245 | { 246 | return UP; 247 | } 248 | 249 | if (INPT_DPADDirection(DPAD_DOWN)) 250 | { 251 | return DOWN; 252 | } 253 | 254 | if (INPT_AnalogI(AXES_X) < 128 - 24) 255 | { 256 | return LEFT; 257 | } 258 | 259 | if (INPT_AnalogI(AXES_X) > 128 + 24) 260 | { 261 | return RIGHT; 262 | } 263 | 264 | if (INPT_AnalogI(AXES_Y) < 128 - 24) 265 | { 266 | return UP; 267 | } 268 | 269 | if (INPT_AnalogI(AXES_Y) > 128 + 24) 270 | { 271 | return DOWN; 272 | } 273 | 274 | if (INPT_Button(BTN_A)) 275 | { 276 | return A; 277 | } 278 | 279 | if (INPT_Button(BTN_B)) 280 | { 281 | return B; 282 | } 283 | 284 | if (INPT_Button(BTN_X)) 285 | { 286 | return X; 287 | } 288 | 289 | if (INPT_Button(BTN_Y)) 290 | { 291 | return Y; 292 | } 293 | 294 | if (INPT_Button(BTN_START)) 295 | { 296 | return START; 297 | } 298 | 299 | /* Triggers */ 300 | if (INPT_TriggerPressed(TRIGGER_L)) 301 | { 302 | return TRIG_L; 303 | } 304 | 305 | if (INPT_TriggerPressed(TRIGGER_R)) 306 | { 307 | return TRIG_R; 308 | } 309 | 310 | return NONE; 311 | } 312 | 313 | static void init_gfx_pvr(void) 314 | { 315 | /* BlueCrab (c) 2014, 316 | This assumes that the video mode is initialized as KOS 317 | normally does, that is to 640x480 NTSC IL or 640x480 VGA */ 318 | int dc_region, ct; 319 | 320 | dc_region = flashrom_get_region(); 321 | ct = vid_check_cable(); 322 | 323 | /* Prompt the user for whether to run in PAL50 or PAL60 if the flashrom says 324 | the Dreamcast is European and a VGA Box is not hooked up. */ 325 | if (dc_region == FLASHROM_REGION_EUROPE && ct != CT_VGA) 326 | { 327 | if (/*pal_menu()*/ 1 == 1) 328 | vid_set_mode(DM_640x480_NTSC_IL, PM_RGB565); 329 | else 330 | vid_set_mode(DM_640x480_PAL_IL, PM_RGB565); 331 | } 332 | 333 | pvr_init_params_t params = 334 | { 335 | /* Enable opaque and translucent polygons with size 32 and 32 */ 336 | {PVR_BINSIZE_32, PVR_BINSIZE_0, PVR_BINSIZE_32, PVR_BINSIZE_0, PVR_BINSIZE_0}, /* Only TR */ 337 | 256 * 1024, /* 256kb Vertex buffer */ 338 | 0, /* No DMA, but maybe? */ 339 | 0, /* No FSAA */ 340 | 0, /* Disable TR autosort */ 341 | 0, 342 | 0 343 | }; 344 | 345 | pvr_init(¶ms); 346 | draw_set_list(PVR_LIST_OP_POLY); 347 | } 348 | 349 | int main(int argc, char *argv[]) 350 | { 351 | /* unused */ 352 | (void)argc; 353 | (void)argv; 354 | 355 | for (int i = 0; i < 8; i++) 356 | { 357 | maple_device_t * vmu = maple_enum_type(i, MAPLE_FUNC_MEMCARD); 358 | 359 | if (vmu && check_vm2_present(vmu)) 360 | { 361 | int port, unit; 362 | 363 | port = vmu->port; 364 | unit = vmu->unit; 365 | 366 | vm2_set_id(vmu, "openmenu", NULL); 367 | vm2_dev = vmu; 368 | 369 | thd_sleep(200); 370 | 371 | while (!maple_enum_dev(port, unit)) 372 | { 373 | thd_pass(); 374 | } 375 | 376 | break; 377 | } 378 | } 379 | 380 | fflush(stdout); 381 | setbuf(stdout, NULL); 382 | init_gfx_pvr(); 383 | 384 | if (init()) 385 | { 386 | puts("Init error."); 387 | return 1; 388 | } 389 | 390 | for (;;) 391 | { 392 | z_reset(); 393 | (*current_ui_handle_input)(translate_input()); 394 | vid_waitvbl(); 395 | 396 | if(need_reload_ui) 397 | { 398 | ui_set_choice(settings_get()->ui); 399 | } 400 | else 401 | draw(); 402 | } 403 | 404 | return 0; 405 | } 406 | 407 | void exit_to_bios(void) 408 | { 409 | bloader_cfg_t *bloader_config = (bloader_cfg_t *) &bloader_data[bloader_size-sizeof(bloader_cfg_t)]; 410 | openmenu_settings* cur = settings_get(); 411 | 412 | bloader_config->enable_wide = cur->aspect; 413 | 414 | if (!strncmp("Dreamcast Fishing Controller", maple_enum_type(0, MAPLE_FUNC_CONTROLLER)->info.product_name, 28)) 415 | { 416 | bloader_config->enable_3d = 0; 417 | } 418 | else 419 | { 420 | bloader_config->enable_3d = 1; 421 | } 422 | 423 | if (vm2_dev) 424 | { 425 | const gd_item *item = get_cur_game_item(); 426 | vm2_set_id(vm2_dev, item->product, item->name); 427 | } 428 | 429 | arch_exec_at(bloader_data, bloader_size, 0xacf00000); 430 | } 431 | 432 | -------------------------------------------------------------------------------- /ui/draw_kos.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File: draw_kos.c 3 | * Project: ui 4 | * File Created: Wednesday, 19th May 2021 9:33:03 pm 5 | * Author: Hayden Kowalchuk 6 | * ----- 7 | * Copyright (c) 2021 Hayden Kowalchuk, Hayden Kowalchuk 8 | * License: BSD 3-clause "New" or "Revised" License, http://www.opensource.org/licenses/BSD-3-Clause 9 | */ 10 | 11 | #include "draw_kos.h" 12 | 13 | #include 14 | #include 15 | 16 | #include "../inc/dat_format.h" 17 | #include "draw_prototypes.h" 18 | #include "font_prototypes.h" 19 | 20 | image img_empty_boxart; 21 | image img_dir_boxart; 22 | 23 | static int current_list; 24 | 25 | void draw_set_list(int list) 26 | { 27 | current_list = list; 28 | } 29 | 30 | int draw_get_list(void) 31 | { 32 | return current_list; 33 | } 34 | 35 | static float z_depth; 36 | 37 | float z_get(void) 38 | { 39 | return z_depth; 40 | } 41 | 42 | float z_set(float z) 43 | { 44 | z_depth = z; 45 | return z_depth; 46 | } 47 | 48 | float z_set_cond(float z) 49 | { 50 | if (z > z_depth) 51 | { 52 | z_depth = z; 53 | } 54 | else 55 | { 56 | z_inc(); 57 | } 58 | 59 | return z_depth; 60 | } 61 | 62 | void z_reset(void) 63 | { 64 | z_depth = 1.0f; 65 | } 66 | 67 | float z_inc(void) 68 | { 69 | z_depth += 1.0f; 70 | 71 | /* 512 Puts Blit infront of everything*/ 72 | if (z_depth > 512.0f) 73 | { 74 | z_depth = 512.0f; 75 | } 76 | 77 | return z_depth; 78 | } 79 | 80 | static void* pvr_scratch_buf; 81 | /* Called only once at start */ 82 | void draw_init(void) 83 | { 84 | pvr_scratch_buf = pvr_mem_malloc(TEXMAN_BUFFER_SIZE); 85 | texman_reset(pvr_scratch_buf, TEXMAN_BUFFER_SIZE); 86 | 87 | z_reset(); 88 | } 89 | 90 | /* called at the start of each frame */ 91 | void draw_setup(void) 92 | { 93 | texman_reset(pvr_scratch_buf, TEXMAN_BUFFER_SIZE); 94 | } 95 | 96 | void* draw_load_missing_icon(void* user) 97 | { 98 | image* img = (image*)user; 99 | img->texture = img_empty_boxart.texture; 100 | img->width = img_empty_boxart.width; 101 | img->height = img_empty_boxart.height; 102 | img->format = img_empty_boxart.format; 103 | 104 | return img; 105 | } 106 | 107 | /* Throws ID into id and returns something if needs to*/ 108 | void* draw_load_texture(const char* filename, void* user) 109 | { 110 | image* img = (image*)user; 111 | 112 | pvr_ptr_t txr; 113 | 114 | if (!(txr = load_pvr(filename, &img->width, &img->height, &img->format))) 115 | { 116 | img->texture = img_empty_boxart.texture; 117 | img->width = img_empty_boxart.width; 118 | img->height = img_empty_boxart.height; 119 | img->format = img_empty_boxart.format; 120 | 121 | return img; 122 | } 123 | 124 | img->texture = txr; 125 | 126 | return user; 127 | } 128 | 129 | void* draw_load_texture_buffer(const char* filename, void* user, void* buffer) 130 | { 131 | image* img = (image*)user; 132 | 133 | pvr_ptr_t txr; 134 | 135 | if (!(txr = load_pvr_to_buffer(filename, &img->width, &img->height, &img->format, buffer))) 136 | { 137 | img->texture = img_empty_boxart.texture; 138 | img->width = img_empty_boxart.width; 139 | img->height = img_empty_boxart.height; 140 | img->format = img_empty_boxart.format; 141 | 142 | return img; 143 | } 144 | 145 | img->texture = txr; 146 | 147 | return user; 148 | } 149 | 150 | void* draw_load_texture_from_DAT_to_buffer(const struct dat_file* bin, const char* ID, void* user, void* buffer) 151 | { 152 | image* img = (image*)user; 153 | pvr_ptr_t txr; 154 | int ret = DAT_read_file_by_ID(bin, ID, pvr_get_internal_buffer()); 155 | 156 | if (!ret) 157 | { 158 | img->texture = img_empty_boxart.texture; 159 | img->width = img_empty_boxart.width; 160 | img->height = img_empty_boxart.height; 161 | img->format = img_empty_boxart.format; 162 | 163 | return img; 164 | } 165 | 166 | txr = load_pvr_from_buffer_to_buffer(pvr_get_internal_buffer(), &img->width, &img->height, &img->format, buffer); 167 | img->texture = txr; 168 | 169 | return user; 170 | } 171 | 172 | /* draws an image at coords of a given size */ 173 | void draw_draw_image(int x, int y, float width, float height, uint32_t color, void* user) 174 | { 175 | image* img = (image*)user; 176 | const dimen_RECT uv_01 = 177 | { 178 | .x = 0, 179 | .y = 0, 180 | .w = img->width, 181 | .h = img->height 182 | }; 183 | 184 | draw_draw_sub_image(x, y, width, height, color, user, &uv_01); 185 | } 186 | 187 | void draw_draw_sub_image(int x, int y, float width, float height, uint32_t color, void* user, const dimen_RECT* rect) 188 | { 189 | image* img = (image*)user; 190 | 191 | if (img == NULL || img->width == 0 || img->height == 0) 192 | { 193 | return; 194 | } 195 | 196 | /* Upper left */ 197 | const float x1 = round((float)x); 198 | const float y1 = round((float)y); 199 | const float u1 = (float)rect->x / img->width; 200 | const float v1 = (float)rect->y / img->height; 201 | 202 | /* Lower right */ 203 | const float x2 = round((float)x + width); 204 | const float y2 = round((float)y + height); 205 | const float u2 = (float)(rect->x + rect->w) / img->width; 206 | const float v2 = (float)(rect->y + rect->h) / img->height; 207 | 208 | const float z = z_inc(); 209 | 210 | #ifdef KOS_SPRITE 211 | pvr_sprite_cxt_t context; 212 | pvr_sprite_hdr_t header; 213 | 214 | pvr_sprite_cxt_txr(&context, draw_get_list(), img->format, img->width, img->height, img->texture, PVR_FILTER_BILINEAR); 215 | pvr_sprite_compile(&header, &context); 216 | 217 | pvr_prim(&header, sizeof(header)); 218 | 219 | pvr_sprite_txr_t vert = 220 | { 221 | .flags = PVR_CMD_VERTEX_EOL, /* Always? */ 222 | /* upper left */ 223 | .ax = x1, 224 | .ay = y1, 225 | .az = z, 226 | /* upper right */ 227 | .bx = x2, 228 | .by = y1, 229 | .bz = z, 230 | /* lower left */ 231 | .cx = x2, 232 | .cy = y2, 233 | .cz = z, 234 | /* interpolated */ 235 | .dx = x1, 236 | .dy = y2, 237 | .auv = PVR_PACK_16BIT_UV(u1, v1), /* UVS */ 238 | .buv = PVR_PACK_16BIT_UV(u2, v1), /* UVS */ 239 | .cuv = PVR_PACK_16BIT_UV(u2, v2), /* UVS */ 240 | }; 241 | 242 | pvr_prim(&vert, sizeof(vert)); 243 | #else 244 | pvr_poly_cxt_t context; 245 | pvr_poly_hdr_t header; 246 | 247 | pvr_poly_cxt_txr(&context, draw_get_list(), img->format, img->width, img->height, img->texture, PVR_FILTER_BILINEAR); 248 | 249 | if(context.txr.enable != PVR_TEXTURE_DISABLE) 250 | { 251 | switch(context.txr.width) 252 | { 253 | case 8: 254 | case 16: 255 | case 32: 256 | case 64: 257 | case 128: 258 | case 256: 259 | case 512: 260 | case 1024: 261 | break; 262 | 263 | default: 264 | printf("%s error tex size %d(%ld) %d(%ld)\n", __func__, context.txr.width, img->width, context.txr.height, img->height); 265 | return; 266 | break; 267 | } 268 | } 269 | 270 | pvr_poly_compile(&header, &context); 271 | pvr_prim(&header, sizeof(header)); 272 | 273 | pvr_vertex_t vert = 274 | { 275 | .argb = color, 276 | .oargb = 0, 277 | .flags = PVR_CMD_VERTEX, 278 | .z = 1 279 | }; 280 | 281 | vert.x = x1; 282 | vert.y = y2; 283 | vert.z = z; 284 | vert.u = u1; 285 | vert.v = v2; 286 | pvr_prim(&vert, sizeof(vert)); 287 | 288 | vert.x = x1; 289 | vert.y = y1; 290 | vert.u = u1; 291 | vert.v = v1; 292 | pvr_prim(&vert, sizeof(vert)); 293 | 294 | vert.x = x2; 295 | vert.y = y2; 296 | vert.u = u2; 297 | vert.v = v2; 298 | pvr_prim(&vert, sizeof(vert)); 299 | 300 | vert.flags = PVR_CMD_VERTEX_EOL; 301 | vert.x = x2; 302 | vert.y = y1; 303 | vert.u = u2; 304 | vert.v = v1; 305 | pvr_prim(&vert, sizeof(vert)); 306 | #endif 307 | } 308 | 309 | /* Draws untextured quad at coords with size and color(rgba) */ 310 | void draw_draw_quad(int x, int y, float width, float height, uint32_t color) 311 | { 312 | /* Upper left */ 313 | const float x1 = round((float)x); 314 | const float y1 = round((float)y); 315 | 316 | /* Lower right */ 317 | const float x2 = round((float)x + width); 318 | const float y2 = round((float)y + height); 319 | const float z = z_inc(); 320 | 321 | #ifdef KOS_SPRITE 322 | pvr_sprite_cxt_t context; 323 | pvr_sprite_hdr_t header; 324 | 325 | pvr_sprite_cxt_col(&context, draw_get_list()); 326 | pvr_sprite_compile(&header, &context); 327 | 328 | header.argb = color; 329 | 330 | pvr_prim(&header, sizeof(header)); 331 | 332 | pvr_sprite_col_t vert = 333 | { 334 | .flags = PVR_CMD_VERTEX_EOL, /* Always? */ 335 | /* upper left */ 336 | .ax = x1, 337 | .ay = y1, 338 | .az = z, 339 | /* upper right */ 340 | .bx = x2, 341 | .by = y1, 342 | .bz = z, 343 | /* lower left */ 344 | .cx = x2, 345 | .cy = y2, 346 | .cz = z, 347 | /* interpolated */ 348 | .dx = x1, 349 | .dy = y2 350 | }; 351 | 352 | pvr_prim(&vert, sizeof(vert)); 353 | #else 354 | pvr_poly_cxt_t context; 355 | pvr_poly_hdr_t header; 356 | 357 | pvr_poly_cxt_col(&context, draw_get_list()); 358 | 359 | if(context.txr.enable != PVR_TEXTURE_DISABLE) 360 | { 361 | switch(context.txr.width) 362 | { 363 | case 8: 364 | case 16: 365 | case 32: 366 | case 64: 367 | case 128: 368 | case 256: 369 | case 512: 370 | case 1024: 371 | break; 372 | 373 | default: 374 | printf("%s error tex size %d(%f) %d(%f)\n", __func__, context.txr.width, width, context.txr.height, height); 375 | return; 376 | break; 377 | } 378 | } 379 | 380 | pvr_poly_compile(&header, &context); 381 | pvr_prim(&header, sizeof(header)); 382 | 383 | pvr_vertex_t vert = 384 | { 385 | .argb = color, 386 | .oargb = 0, 387 | .flags = PVR_CMD_VERTEX, 388 | .z = z, 389 | .u = 0, 390 | .v = 0 391 | }; 392 | 393 | vert.x = x1; 394 | vert.y = y2; 395 | pvr_prim(&vert, sizeof(vert)); 396 | 397 | vert.x = x1; 398 | vert.y = y1; 399 | pvr_prim(&vert, sizeof(vert)); 400 | 401 | vert.x = x2; 402 | vert.y = y2; 403 | pvr_prim(&vert, sizeof(vert)); 404 | 405 | vert.flags = PVR_CMD_VERTEX_EOL; 406 | vert.x = x2; 407 | vert.y = y1; 408 | pvr_prim(&vert, sizeof(vert)); 409 | #endif 410 | } 411 | 412 | /* draws an image at coords as a square */ 413 | void draw_draw_square(int x, int y, float size, uint32_t color, void* user) 414 | { 415 | draw_draw_image(x, y, size, size, color, user); 416 | } 417 | 418 | void draw_draw_image_centered(int x, int y, float width, float height, uint32_t color, void* user) 419 | { 420 | const int x_extent = width / 2; 421 | const int y_extent = height / 2; 422 | draw_draw_image(x - x_extent, y - y_extent, width, height, color, user); 423 | } 424 | 425 | -------------------------------------------------------------------------------- /tools/metapacker.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File: metapack.c 3 | * Project: tools 4 | * File Created: Thursday, 17th June 2021 12:02:11 am 5 | * Author: Hayden Kowalchuk 6 | * ----- 7 | * Copyright (c) 2021 Hayden Kowalchuk, Hayden Kowalchuk 8 | * License: BSD 3-clause "New" or "Revised" License, http://www.opensource.org/licenses/BSD-3-Clause 9 | */ 10 | 11 | #ifdef COSMO 12 | #include "cosmo/cosmopolitan.h" 13 | #else 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #endif 24 | 25 | #define strcasecmp strcasecmp 26 | 27 | #include "../backend/db_item.h" 28 | #include "../external/ini.h" 29 | #include "dat_packer_interface.h" 30 | 31 | /* Called: 32 | ./metapack FOLDER output.dat 33 | 34 | packs the items in the folder into the output.dat 35 | */ 36 | 37 | #define NUM_ARGS (2) 38 | 39 | /* Locals */ 40 | static bin_header file_header; 41 | static bin_item_raw *bin_items; 42 | static unsigned char *data_buf; 43 | 44 | static inline long int filelen(FILE *f) { 45 | long int end; 46 | fseek(f, 0, SEEK_END); 47 | end = ftell(f); 48 | fseek(f, 0, SEEK_SET); 49 | 50 | return end; 51 | } 52 | 53 | static unsigned short meta_genre_to_enum(const char *genre) { 54 | if (0) { 55 | } else if (strcmp(genre, "Action") == 0) { 56 | return GENRE_ACTION; 57 | } else if (strcmp(genre, "Racing") == 0) { 58 | return GENRE_RACING; 59 | } else if (strcmp(genre, "Simulation") == 0) { 60 | return GENRE_SIMULATION; 61 | } else if (strcmp(genre, "Sports") == 0) { 62 | return GENRE_SPORTS; 63 | } else if (strcmp(genre, "Lightgun") == 0) { 64 | return GENRE_LIGHTGUN; 65 | } else if (strcmp(genre, "Fighting") == 0) { 66 | return GENRE_FIGHTING; 67 | } else if (strcmp(genre, "Shooter") == 0) { 68 | return GENRE_SHOOTER; 69 | } else if (strcmp(genre, "Survival") == 0) { 70 | return GENRE_SURVIVAL; 71 | } else if (strcmp(genre, "Adventure") == 0) { 72 | return GENRE_ADVENTURE; 73 | } else if (strcmp(genre, "Platformer") == 0) { 74 | return GENRE_PLATFORMER; 75 | } else if (strcmp(genre, "RPG") == 0) { 76 | return GENRE_RPG; 77 | } else if (strcmp(genre, "Shmup") == 0) { 78 | return GENRE_SHMUP; 79 | } else if (strcmp(genre, "Strategy") == 0) { 80 | return GENRE_STRATEGY; 81 | } else if (strcmp(genre, "Puzzle") == 0) { 82 | return GENRE_PUZZLE; 83 | } else if (strcmp(genre, "Arcade") == 0) { 84 | return GENRE_ARCADE; 85 | } else if (strcmp(genre, "Music") == 0) { 86 | return GENRE_MUSIC; 87 | } else if (strcmp(genre, "0") == 0) { 88 | return GENRE_NONE; 89 | } else /* default: */ 90 | { 91 | printf("META: Unknown genre: %s\n", genre); 92 | return GENRE_NONE; 93 | } 94 | } 95 | 96 | static unsigned short meta_accessory_to_enum(const char *accessory) { 97 | if (0) { 98 | } else if (strcmp(accessory, "JUMP") == 0) { 99 | return ACCESORIES_JUMP_PACK; 100 | } else if (strcmp(accessory, "KEY") == 0) { 101 | return ACCESORIES_KEYBOARD; 102 | } else if (strcmp(accessory, "VGA") == 0) { 103 | return ACCESORIES_VGA; 104 | } else if (strcmp(accessory, "MS") == 0) { 105 | return ACCESORIES_MOUSE; 106 | } else if (strcmp(accessory, "OLE") == 0) { 107 | return ACCESORIES_MARACAS; 108 | } else if (strcmp(accessory, "RACE") == 0) { 109 | return ACCESORIES_RACING_WHEEL; 110 | } else if (strcmp(accessory, "MIC") == 0) { 111 | return ACCESORIES_MICROPHONE; 112 | } else if (strcmp(accessory, "ARC") == 0) { 113 | return ACCESORIES_ARCADE_STICK; 114 | } else if (strcmp(accessory, "GUN") == 0) { 115 | return ACCESORIES_LIGHTGUN; 116 | } else if (strcmp(accessory, "ETH") == 0) { 117 | return ACCESORIES_BBA; 118 | } else if (strcmp(accessory, "FISH") == 0) { 119 | return ACCESORIES_FISHING_ROD; 120 | } else if (strcmp(accessory, "ASC") == 0) { 121 | return ACCESORIES_ASCII_PAD; 122 | } else if (strcmp(accessory, "CAM") == 0) { 123 | return ACCESORIES_DREAMEYE; 124 | } else if (strcmp(accessory, "MOD") == 0) { 125 | return ACCESORIES_MODEM; 126 | } else if (strcmp(accessory, "0") == 0 || strcmp(accessory, "-") == 0) { 127 | return ACCESORIES_NONE; 128 | } else /* default: */ 129 | { 130 | printf("META: Unknown accessory: %s\n", accessory); 131 | return ACCESORIES_NONE; 132 | } 133 | } 134 | 135 | static unsigned short meta_parse_genre(const char *genre) { 136 | unsigned short ret = GENRE_NONE; 137 | char temp[64]; 138 | const char *delim = "+"; 139 | memcpy(temp, genre, strlen(genre) + 1); 140 | 141 | char *token = strtok(temp, delim); 142 | const char *item = token; 143 | do { 144 | ret += meta_genre_to_enum(item); 145 | item = strtok(NULL, delim); 146 | } while (item); 147 | return ret; 148 | } 149 | 150 | static unsigned short meta_parse_accessories(const char *accessories) { 151 | unsigned short ret = ACCESORIES_NONE; 152 | char temp[64]; 153 | const char *delim = "+"; 154 | memcpy(temp, accessories, strlen(accessories) + 1); 155 | 156 | char *token = strtok(temp, delim); 157 | const char *item = token; 158 | do { 159 | ret += meta_accessory_to_enum(item); 160 | item = strtok(NULL, delim); 161 | } while (item); 162 | return ret; 163 | } 164 | 165 | static int read_meta_ini(void *user, const char *section, const char *name, const char *value) { 166 | /* Parsing Meta into struct */ 167 | db_item *item = (db_item *)user; 168 | 169 | if (0) 170 | ; 171 | #define DB_ITEM_STRI(s, n, default) else if (strcasecmp(section, #s) == 0 && \ 172 | strcasecmp(name, #n) == 0) strcpy(item->n, value); 173 | #define DB_ITEM_CHAR(s, n, default) else if (strcasecmp(section, #s) == 0 && \ 174 | strcasecmp(name, #n) == 0) item->n = (unsigned char)atoi(value); 175 | #define DB_ITEM_GENRE(s, n, default) else if (strcasecmp(section, #s) == 0 && \ 176 | strcasecmp(name, #n) == 0) item->n = meta_parse_genre(value); 177 | #define DB_ITEM_ACCESSORY(s, n, default) else if (strcasecmp(section, #s) == 0 && \ 178 | strcasecmp(name, #n) == 0) item->n = meta_parse_accessories(value); 179 | #include "../backend/db_item.def" 180 | 181 | return 1; 182 | } 183 | 184 | static void meta_init_item(db_item *item) { 185 | memset(item->description, '\0', sizeof(item->description)); 186 | #define DB_ITEM_STRI(s, n, default) strcpy(item->n, default); 187 | #define DB_ITEM_CHAR(s, n, default) item->n = default; 188 | #define DB_ITEM_GENRE(s, n, default) item->n = default; 189 | #define DB_ITEM_ACCESSORY(s, n, default) item->n = default; 190 | #include "../backend/db_item.def" 191 | } 192 | 193 | /* buffer is where the db_item struct should be filled */ 194 | int game_meta_read(const char *filename, void *buffer) { 195 | /* Always LD/cdrom */ 196 | FILE *ini = fopen(filename, "rb"); 197 | if (!ini) { 198 | printf("INI:Error opening %s!\n", filename); 199 | fflush(stdout); 200 | /*exit or something */ 201 | return -1; 202 | } 203 | size_t ini_size = filelen(ini); 204 | char *ini_buffer = malloc(ini_size + 2); /* to hold newline and NUL */ 205 | fread(ini_buffer, ini_size, 1, ini); 206 | fclose(ini); 207 | /* Forcibly terminate string with newline and NUL */ 208 | ini_buffer[ini_size] = '\n'; 209 | ini_buffer[ini_size + 1] = '\0'; 210 | db_item *item = (db_item *)buffer; 211 | 212 | meta_init_item(item); 213 | 214 | if (ini_parse_string(ini_buffer, read_meta_ini, buffer) < 0) { 215 | printf("INI:Error Parsing %s!\n", filename); 216 | fflush(stdout); 217 | /*exit or something */ 218 | return -1; 219 | } 220 | free(ini_buffer); 221 | 222 | return 0; 223 | } 224 | 225 | int add_bin_file(const char *path, const char *folder, struct stat *statptr) { 226 | char temp_id[12]; 227 | char temp_file[FILENAME_MAX]; 228 | 229 | if (file_header.chunk_size == 0) { 230 | file_header.chunk_size = sizeof(db_item); 231 | data_buf = malloc(file_header.chunk_size * file_header.padding0); /* Temporarily use padding0 as num_files */ 232 | /* work out if we need padding chunks */ 233 | uint32_t total_header_size = sizeof(bin_header) + (file_header.padding0 * sizeof(bin_item_raw)); 234 | /* Use padding0 for how many extra chunks may be used for header, this will add to bin_item offset */ 235 | file_header.padding0 = total_header_size / file_header.chunk_size; 236 | printf("Total header chunks: %u\n\n", file_header.padding0 + 1); 237 | } 238 | 239 | /* Check if filename too long, dont try to reconcile, just skip */ 240 | char *dot = strrchr(path, '.'); 241 | if ((size_t)dot - (size_t)path > 11) { 242 | printf("Err: filename too long \"%s\", maxlength = 11!\n", path); 243 | return -1; 244 | } 245 | 246 | temp_file[0] = '\0'; 247 | strcpy(temp_file, folder); 248 | strcat(temp_file, PATH_SEP); 249 | strcat(temp_file, path); 250 | db_item *record = (db_item *)(data_buf + (file_header.num_chunks * file_header.chunk_size)); 251 | game_meta_read(temp_file, record); 252 | 253 | /* Use filename as ID, remove extension */ 254 | memset(temp_id, '\0', sizeof(temp_id)); 255 | strncpy(temp_id, path, 11); 256 | char *end = strrchr(temp_id, '.'); 257 | if (end) { 258 | const size_t nul_len = sizeof(temp_id) - ((size_t)end - (size_t)temp_id); 259 | memset(end, '\0', nul_len); 260 | } 261 | char *temp_start = temp_id; 262 | while (*temp_start) 263 | *temp_start++ = toupper(*temp_start); 264 | temp_id[11] = '\0'; 265 | temp_id[10] = '\0'; 266 | memcpy(&bin_items[file_header.num_chunks].ID, temp_id, sizeof(bin_items->ID)); 267 | 268 | printf("id:%s\nnum_players:%d\nvmu_blocks:%d\naccessories:%d\ngenre:%d\ndesc:%s\n\n", temp_id, record->num_players, record->vmu_blocks, record->accessories, record->genre, record->description); 269 | 270 | bin_items[file_header.num_chunks].offset = file_header.padding0 + file_header.num_chunks + 1; 271 | (void)file_header.num_chunks++; 272 | 273 | printf("Added[%d] as %s\n", file_header.padding0 + file_header.num_chunks, temp_id); 274 | } 275 | 276 | int main(int argc, char **argv) { 277 | if (argc < NUM_ARGS + 1 /*binary itself*/) { 278 | printf("Incorrect usage!\n\t./datpack FOLDER output.dat\n"); 279 | return 1; 280 | } 281 | 282 | /* Setup file constraints */ 283 | memcpy(&file_header.magic.rich.alpha, "DAT", 3); 284 | file_header.magic.rich.version = 1; 285 | file_header.chunk_size = 0; 286 | file_header.num_chunks = 0; 287 | file_header.padding0 = 0; 288 | 289 | open_output(argv[2]); 290 | iterate_dir(argv[1], add_bin_file, &file_header, &bin_items); 291 | write_bin_file(&file_header, bin_items, data_buf); 292 | 293 | return EXIT_SUCCESS; 294 | } --------------------------------------------------------------------------------