From adb8da6836d87e50c717cabd22ca91508d5b5d5e Mon Sep 17 00:00:00 2001 From: quou Date: Sun, 13 Oct 2024 20:07:35 +1100 Subject: port to ps vita --- .gitignore | 4 + Makefile | 24 +++- media/icon.png | Bin 0 -> 4603 bytes plat.c | 381 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 408 insertions(+), 1 deletion(-) create mode 100644 media/icon.png diff --git a/.gitignore b/.gitignore index 5088c0d..91bfb10 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,7 @@ pack.h /ems/index.html /ems/hftrss.js /ems/hftrss.wasm +/eboot.bin +/hftrss.velf +/hftrss.vpk +/param.sfo diff --git a/Makefile b/Makefile index 4042ab4..e277580 100644 --- a/Makefile +++ b/Makefile @@ -66,6 +66,18 @@ ifeq ($(config), release_ems) libs = -lm endif +ifeq ($(config), release_psv) + compiler = arm-vita-eabi-gcc + tool_compiler = gcc + linker = arm-vita-eabi-gcc + conf_cflags = -DNDEBUG -Dplat_psv \ + -Dallocation_default_alignment=4 \ + -O3 -s + conf_lflags = -Wl,-q -O3 + libs = -lSceDisplay_stub -lSceCtrl_stub -lSceAudio_stub -lSceLibDbg_stub -lm + postbuild = psv_postbuild +endif + sources = \ animation.c \ asset.c \ @@ -131,7 +143,7 @@ objects = $(sources:%.c=%.o) images = $(image_sources:$(int_dir)/%.bmp=$(data_dir)/%.img) animations = $(anim_sources:$(int_dir)/%.anm=$(data_dir)/%.anm) -all: $(target) $(pack) +all: $(target) $(pack) $(postbuild) $(objects): %.o : %.c | $(pack) $(compiler) -MMD -MF $(basename $@).d $(cflags) -o $@ -c $< @@ -164,6 +176,16 @@ $(target): $(objects) $(data_dir): mkdir -p $(data_dir) +psv_postbuild: $(target) + vita-elf-create $(target) $(target).velf + vita-make-fself -s $(target).velf eboot.bin + vita-mksfoex -s TITLE_ID="HFTRSS001" "HFtrsS" param.sfo + vita-pack-vpk -s param.sfo -b eboot.bin $(target).vpk \ + -a media/icon.png=sce_sys/icon0.png + +vitasend: $(target) $(psv_postbuild) + curl -T $(target).vpk ftp://${VITAIP}:1337/ux0:/ + clean: rm *.d rm *.o diff --git a/media/icon.png b/media/icon.png new file mode 100644 index 0000000..f58acfc Binary files /dev/null and b/media/icon.png differ diff --git a/plat.c b/plat.c index 50f3944..ba88c24 100644 --- a/plat.c +++ b/plat.c @@ -912,3 +912,384 @@ void play_sound(int len) { } #endif + +#ifdef plat_psv + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define psv_sw 960 +#define psv_sh 544 + +typedef struct { + unsigned* vram; +} App_Internal; + +void panick(void) { + while (1) + *(int*)(0xAA) = 0x55; /* trigger coredump */ +} + +extern int vsnprintf(char*, size_t, const char*, va_list); + +void print(const char* fmt, ...) { + char buf[256]; + va_list a; + va_start(a, fmt); + vsnprintf(buf, sizeof buf, fmt, a); + va_end(a); + sceDbgLoggingHandler( + "na", + 0, + SCE_DBG_LOG_LEVEL_INFO, + 0, + "%s", + buf + ); +} + +void print_err(const char* fmt, ...) { + char buf[256]; + va_list a; + va_start(a, fmt); + vsnprintf(buf, sizeof buf, fmt, a); + va_end(a); + sceDbgLoggingHandler( + "na", + 0, + SCE_DBG_LOG_LEVEL_ERROR, + 0, + "%s", + buf + ); +} + +void print_war(const char* fmt, ...) { + char buf[256]; + va_list a; + va_start(a, fmt); + vsnprintf(buf, sizeof buf, fmt, a); + va_end(a); + sceDbgLoggingHandler( + "na", + 0, + SCE_DBG_LOG_LEVEL_WARNING, + 0, + "%s", + buf + ); +} + +int imp_assert( + int val, + const char* expr, + const char* file, + int line +) { + if (!val) { + print_err( + "%d:%s: Assertion failed: %s.\n", + line, + file, + expr + ); + pbreak(error_assertion_failed); + return 0; + } + return 1; +} + +void pbreak(Error code) { + (void)code; + __asm("bkpt 0x0"); +} + +extern int prog_init(Arena* m); +extern int prog_update(void); +extern void prog_deinit(void); + +int main(void) { + Arena a; + void* mem = malloc(memory_size); + int r; + if (!mem) { + print_err("Out of memory.\n"); + panick(); + } + sceCtrlSetSamplingMode(SCE_CTRL_MODE_ANALOG); + init_arena( + &a, + mem, + memory_size + ); + if ((r = prog_init(&a))) return r; + for (r = 1; r; r = prog_update()); + prog_deinit(); + return 0; +} + +void init_fps(FPS* f, int mpf) { + f->now = sceKernelGetProcessTimeWide(); + f->next = f->now; + f->mpf = mpf; + f->pt = 0; + f->ct = -1; +} + +void fps_begin(FPS* f) { + f->now = sceKernelGetProcessTimeWide(); +} + +void fps_end(FPS* f) { + unsigned long ts = f->next - f->now; + if (ts > 0) { + sceKernelDelayThreadCB(ts); + } +} + +void fps_update(FPS* f) { + f->next += f->mpf * 1000; + f->pt = f->ct; + f->ct = sceKernelGetProcessTimeWide(); + f->fps = 1000000 / (f->ct - f->pt); +} + +void init_rendering(App* a, App_Internal* i) { + SceUID db; + SceDisplayFrameBuf fbc = { 0 }; + int r; + a->fb = heap_alloc( + a->heap, + (viewport_w * viewport_h + 32) / 32 * sizeof *a->fb + ); + db = sceKernelAllocMemBlock( + "display", + SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW, + 2 * 1024 * 1024, + 0 + ); + sceKernelGetMemBlockBase( + db, + (void**)&i->vram + ); + fbc.size = sizeof fbc; + fbc.base = i->vram; + fbc.pitch = psv_sw; + fbc.pixelformat = SCE_DISPLAY_PIXELFORMAT_A8B8G8R8; + fbc.width = psv_sw; + fbc.height = psv_sh; + r = sceDisplaySetFrameBuf( + &fbc, + SCE_DISPLAY_SETBUF_NEXTFRAME + ); + if (r < 0) + panick(); +} + +App* new_app(struct Heap* mem, const char* n) { + App* a; + App_Internal* i; + a = heap_alloc(mem, sizeof *a + sizeof *i); + i = (App_Internal*)(&a[1]); + (void)n; + a->heap = mem; + a->s = 2; + a->o = 0; + a->err = error_none; + init_rendering(a, i); + a->o = 1; + return a; +} + +void deinit_app(App* a) { + (void)a; +} + +int vita_btn_pressed(int b, const SceCtrlData* c) { + switch (b) { + case btn_jump: + return c->buttons & SCE_CTRL_CROSS; + case btn_shoot: + return c->buttons & (SCE_CTRL_SQUARE | SCE_CTRL_RTRIGGER); + case btn_special: + return c->buttons & (SCE_CTRL_CIRCLE | SCE_CTRL_LTRIGGER); + case btn_left: + return + c->buttons & SCE_CTRL_LEFT || + c->lx < 30; + case btn_right: + return + c->buttons & SCE_CTRL_RIGHT || + c->lx > 230; + case btn_up: + return + c->buttons & SCE_CTRL_UP || + c->ly < 30; + case btn_down: + return + c->buttons & SCE_CTRL_DOWN || + c->ly > 230; + default: return 0; + } +} + +void app_begin(App* a) { + SceCtrlData ctrl; + int j; + sceCtrlPeekBufferPositive(0, &ctrl, 1); + for (j = 0; j < btn_count; j++) + a->btn_states[j] &= ~( + btn_state_just_pressed | btn_state_just_released + ); + for (j = 0; j < btn_count; j++) { + int p = vita_btn_pressed(j, &ctrl); + int ap = a->btn_states[j] & btn_state_pressed; + if (p && !ap) + a->btn_states[j] |= + btn_state_just_pressed | btn_state_pressed; + if (!p && ap) { + a->btn_states[j] |= btn_state_just_released; + a->btn_states[j] &= ~btn_state_pressed; + } + } +} + +void app_rencpy( + App* a, + App_Internal* i, + int sx, + int sy, + int s +) { + const unsigned white = 0xffffffff; + const unsigned black = 0xff000000; + int x, y, sj = 0; + int w = viewport_w * s; + int h = viewport_h * s; + int ex = mini(sx + w, psv_sw); + int ey = mini(sy + h, psv_sh); + for (y = sy; y < ey; y++, sj++) { + int sy = sj / s; + int si = 0; + for (x = sx; x < ex; x++, si++) { + int sx = si / s; + int idx = sx + sy * viewport_w; + int bit = 1 << (idx & 0x1f); + bit &= a->fb[idx >> 5]; + i->vram[x + y * psv_sw] = bit? white: black; + } + } +} + +void app_end(App* a) { + App_Internal* i = (App_Internal*)(&a[1]); + app_rencpy( + a, + i, + (psv_sw >> 1) - viewport_w, + (psv_sh >> 1) - viewport_h, + 2 + ); +} + +#define psv_aud_bs (4096) +#define psv_aud_bc 8 + +struct { + short* buf; + int queue[psv_aud_bc]; + SceUID thr, mut; + int r, bufi, time, p; +} aud; + +static int audio_worker(SceSize argc, void* argv) { + int r = 1; + (void)argc; + (void)argv; + while (r) { + int i; + for (i = 0; i < psv_aud_bc; i++) + if (aud.queue[i]) { + short* b = aud.buf + psv_aud_bs * i; + sceAudioOutOutput(aud.p, b); + sceKernelLockMutex(aud.mut, 1, 0); + aud.queue[i] = 0; + sceKernelUnlockMutex(aud.mut, 1); + } + sceKernelLockMutex(aud.mut, 1, 0); + r = aud.r; + sceKernelUnlockMutex(aud.mut, 1); + } + sceKernelExitDeleteThread(0); + return 0; +} + +void init_audio(void) { + int i; + for (i = 0; i < psv_aud_bc; i++) { + aud.queue[i] = 0; + } + aud.p = sceAudioOutOpenPort( + SCE_AUDIO_OUT_PORT_TYPE_BGM, + psv_aud_bs, + 8000, + SCE_AUDIO_OUT_MODE_MONO + ); + aud.r = 1; + aud.bufi = 0; + aud.time = 0; + aud.thr = sceKernelCreateThread( + "audio", + audio_worker, + 0, + 0x2000, + 0, + 0, + 0 + ); + aud.mut = sceKernelCreateMutex( + "audio mutex", + 0, + 0, + 0 + ); + sceKernelStartThread( + aud.thr, + 0, + 0 + ); + aud.buf = malloc(psv_aud_bs * sizeof *aud.buf); +} + +void deinit_audio(void) { + free(aud.buf); + aud.r = 0; + sceKernelDeleteMutex(aud.mut); +} + +void play_sound(int len) { + int i; + short* buf; + sceKernelLockMutex(aud.mut, 1, 0); + buf = aud.buf + aud.bufi * psv_aud_bs; + aud.queue[aud.bufi] = 1; + aud.bufi = (aud.bufi + 1) % psv_aud_bc; + for (i = 0; i < len && i < psv_aud_bs; i++, aud.time++) + buf[i] = (int16_t)(sin((double)aud.time / 0.05) * 16000.0); + for (; i < psv_aud_bs; i++) + buf[i] = 0; + sceKernelUnlockMutex(aud.mut, 1); +} + +#endif -- cgit v1.2.3-54-g00ecf