aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorquou <quou@disroot.org>2024-10-13 20:07:35 +1100
committerquou <quou@disroot.org>2024-10-13 20:12:59 +1100
commitadb8da6836d87e50c717cabd22ca91508d5b5d5e (patch)
tree6f6a32390296a77b9e7086f46d67ee6729999247
parent9d196a5dbd381cba80d338f9ec29dd723fd853b9 (diff)
port to ps vita
-rw-r--r--.gitignore4
-rw-r--r--Makefile24
-rw-r--r--media/icon.pngbin0 -> 4603 bytes
-rw-r--r--plat.c381
4 files changed, 408 insertions, 1 deletions
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
--- /dev/null
+++ b/media/icon.png
Binary files 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 <psp2/audioout.h>
+#include <psp2/ctrl.h>
+#include <psp2/display.h>
+#include <psp2/kernel/processmgr.h>
+#include <psp2/kernel/sysmem.h>
+#include <psp2/kernel/threadmgr.h>
+#include <psp2/libdbg.h>
+#include <psp2common/kernel/modulemgr.h>
+
+#include <math.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#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