diff --git a/.gitignore b/.gitignore
index e78cff7f4..fe5b37da8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -72,6 +72,10 @@ ClassiCube*
screenshots
fontscache.txt
+# CMake files
+CMakeFiles/
+CMakeCache.txt
+
#GCC object files
*.o
diff --git a/Makefile b/Makefile
index 6211a11b9..497cd7e8d 100644
--- a/Makefile
+++ b/Makefile
@@ -138,6 +138,9 @@ vita:
$(MAKE) -f misc/vita/Makefile PLAT=vita
ps3:
$(MAKE) -f misc/ps3/Makefile PLAT=ps3
+ps1:
+ cmake --preset default misc/ps1
+ cmake --build misc/ps1/build
ps2:
$(MAKE) -f misc/ps2/Makefile PLAT=ps2
xbox:
diff --git a/misc/ps1/CMakeLists.txt b/misc/ps1/CMakeLists.txt
new file mode 100644
index 000000000..1f78b62a4
--- /dev/null
+++ b/misc/ps1/CMakeLists.txt
@@ -0,0 +1,21 @@
+cmake_minimum_required(VERSION 3.21)
+
+project(
+ ClassiCube
+ LANGUAGES C ASM
+ VERSION 1.0.0
+ DESCRIPTION "ClassiCube PS1 port"
+ HOMEPAGE_URL "https://classicube.net"
+)
+
+add_definitions(-DPLAT_PS1)
+file(GLOB _sources ../../src/*.c)
+
+psn00bsdk_add_executable(template GPREL ${_sources})
+
+psn00bsdk_add_cd_image(
+ iso # Target name
+ template # Output file name (= template.bin + template.cue)
+ iso.xml # Path to config file
+ DEPENDS template system.cnf
+)
diff --git a/misc/ps1/CMakePresets.json b/misc/ps1/CMakePresets.json
new file mode 100644
index 000000000..97d842820
--- /dev/null
+++ b/misc/ps1/CMakePresets.json
@@ -0,0 +1,26 @@
+{
+ "version": 3,
+ "cmakeMinimumRequired": {
+ "major": 3,
+ "minor": 21,
+ "patch": 0
+ },
+ "configurePresets": [
+ {
+ "name": "default",
+ "displayName": "Default configuration",
+ "description": "Use this preset to build the project using PSn00bSDK.",
+ "generator": "Ninja",
+ "toolchainFile": "$env{PSN00BSDK_LIBS}/cmake/sdk.cmake",
+ "binaryDir": "${sourceDir}/build",
+ "cacheVariables": {
+ "CMAKE_BUILD_TYPE": "Debug",
+ "PSN00BSDK_TC": "",
+ "PSN00BSDK_TARGET": "mipsel-none-elf"
+ },
+ "warnings": {
+ "dev": false
+ }
+ }
+ ]
+}
diff --git a/misc/ps1/iso.xml b/misc/ps1/iso.xml
new file mode 100644
index 000000000..96ea23a8c
--- /dev/null
+++ b/misc/ps1/iso.xml
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+
+
diff --git a/misc/ps1/system.cnf b/misc/ps1/system.cnf
new file mode 100644
index 000000000..e22172615
--- /dev/null
+++ b/misc/ps1/system.cnf
@@ -0,0 +1,4 @@
+BOOT=cdrom:\template.exe;1
+TCB=4
+EVENT=10
+STACK=801FFFF0
diff --git a/src/Core.h b/src/Core.h
index 2474e51f5..d7fac6699 100644
--- a/src/Core.h
+++ b/src/Core.h
@@ -368,6 +368,14 @@ typedef cc_uint8 cc_bool;
#define CC_BUILD_GLES
#define CC_BUILD_EGL
#undef CC_BUILD_FREETYPE
+#elif defined PLAT_PS1
+ #define CC_BUILD_PS1
+ #define CC_BUILD_OPENAL
+ #define CC_BUILD_HTTPCLIENT
+ #define CC_BUILD_COOPTHREADED
+ #define CC_BUILD_LOWMEM
+ #define CC_BUILD_CONSOLE
+ #undef CC_BUILD_FREETYPE
#endif
#endif
diff --git a/src/ExtMath.c b/src/ExtMath.c
index 5081d706f..51f938677 100644
--- a/src/ExtMath.c
+++ b/src/ExtMath.c
@@ -4,8 +4,15 @@
/* For abs(x) function */
#include
-#ifndef __GNUC__
+#if defined PLAT_PS1
+float Math_AbsF(float x) { return __builtin_fabsf(x); }
+float Math_SqrtF(float x) { return 0; } /* TODO broken */
+
+#elif defined __GNUC__
+/* Defined in .h using builtins */
+#else
#include
+
float Math_AbsF(float x) { return fabsf(x); /* MSVC intrinsic */ }
float Math_SqrtF(float x) { return sqrtf(x); /* MSVC intrinsic */ }
#endif
diff --git a/src/ExtMath.h b/src/ExtMath.h
index a176d5551..4907a416f 100644
--- a/src/ExtMath.h
+++ b/src/ExtMath.h
@@ -14,7 +14,7 @@
#define Math_Deg2Packed(x) ((cc_uint8)((x) * 256.0f / 360.0f))
#define Math_Packed2Deg(x) ((x) * 360.0f / 256.0f)
-#ifdef __GNUC__
+#if defined __GNUC__ && !defined CC_PLAT_PS1
/* fabsf/sqrtf are single intrinsic instructions in gcc/clang */
/* (sqrtf is only when -fno-math-errno though) */
#define Math_AbsF(x) __builtin_fabsf(x)
diff --git a/src/Graphics_PS1.c b/src/Graphics_PS1.c
new file mode 100644
index 000000000..d05b9837c
--- /dev/null
+++ b/src/Graphics_PS1.c
@@ -0,0 +1,272 @@
+#include "Core.h"
+#if defined CC_BUILD_PS1
+#include "_GraphicsBase.h"
+#include "Errors.h"
+#include "Window.h"
+
+void Gfx_RestoreState(void) {
+ InitDefaultResources();
+}
+
+void Gfx_FreeState(void) {
+ FreeDefaultResources();
+}
+
+void Gfx_Create(void) {
+ Gfx.MaxTexWidth = 128;
+ Gfx.MaxTexHeight = 128;
+ Gfx.Created = true;
+
+ Gfx_RestoreState();
+}
+
+void Gfx_Free(void) {
+ Gfx_FreeState();
+}
+
+
+/*########################################################################################################################*
+*---------------------------------------------------------Textures--------------------------------------------------------*
+*#########################################################################################################################*/
+static GfxResourceID Gfx_AllocTexture(struct Bitmap* bmp, cc_uint8 flags, cc_bool mipmaps) {
+ return NULL;
+}
+
+void Gfx_BindTexture(GfxResourceID texId) {
+}
+
+void Gfx_DeleteTexture(GfxResourceID* texId) {
+ GfxResourceID data = *texId;
+ if (data) Mem_Free(data);
+ *texId = NULL;
+}
+
+void Gfx_UpdateTexture(GfxResourceID texId, int x, int y, struct Bitmap* part, int rowWidth, cc_bool mipmaps) {
+ // TODO
+}
+
+void Gfx_UpdateTexturePart(GfxResourceID texId, int x, int y, struct Bitmap* part, cc_bool mipmaps) {
+ // TODO
+}
+
+void Gfx_EnableMipmaps(void) { }
+void Gfx_DisableMipmaps(void) { }
+
+
+/*########################################################################################################################*
+*------------------------------------------------------State management---------------------------------------------------*
+*#########################################################################################################################*/
+void Gfx_SetFog(cc_bool enabled) { }
+void Gfx_SetFogCol(PackedCol col) { }
+void Gfx_SetFogDensity(float value) { }
+void Gfx_SetFogEnd(float value) { }
+void Gfx_SetFogMode(FogFunc func) { }
+
+void Gfx_SetFaceCulling(cc_bool enabled) {
+ // TODO
+}
+
+void Gfx_SetAlphaTest(cc_bool enabled) {
+}
+
+void Gfx_SetAlphaBlending(cc_bool enabled) {
+}
+
+void Gfx_SetAlphaArgBlend(cc_bool enabled) { }
+
+void Gfx_ClearBuffers(GfxBuffers buffers) {
+}
+
+void Gfx_ClearColor(PackedCol color) {
+}
+
+void Gfx_SetDepthTest(cc_bool enabled) {
+}
+
+void Gfx_SetDepthWrite(cc_bool enabled) {
+ // TODO
+}
+
+static void SetColorWrite(cc_bool r, cc_bool g, cc_bool b, cc_bool a) {
+ // TODO
+}
+
+void Gfx_DepthOnlyRendering(cc_bool depthOnly) {
+ cc_bool enabled = !depthOnly;
+ SetColorWrite(enabled & gfx_colorMask[0], enabled & gfx_colorMask[1],
+ enabled & gfx_colorMask[2], enabled & gfx_colorMask[3]);
+}
+
+
+/*########################################################################################################################*
+*-------------------------------------------------------Index buffers-----------------------------------------------------*
+*#########################################################################################################################*/
+GfxResourceID Gfx_CreateIb2(int count, Gfx_FillIBFunc fillFunc, void* obj) {
+ return (void*)1;
+}
+
+void Gfx_BindIb(GfxResourceID ib) { }
+void Gfx_DeleteIb(GfxResourceID* ib) { }
+
+
+/*########################################################################################################################*
+*-------------------------------------------------------Vertex buffers----------------------------------------------------*
+*#########################################################################################################################*/
+static void* gfx_vertices;
+
+static GfxResourceID Gfx_AllocStaticVb(VertexFormat fmt, int count) {
+ return Mem_TryAlloc(count, strideSizes[fmt]);
+}
+
+void Gfx_BindVb(GfxResourceID vb) { gfx_vertices = vb; }
+
+void Gfx_DeleteVb(GfxResourceID* vb) {
+ GfxResourceID data = *vb;
+ if (data) Mem_Free(data);
+ *vb = 0;
+}
+
+void* Gfx_LockVb(GfxResourceID vb, VertexFormat fmt, int count) {
+ return vb;
+}
+
+void Gfx_UnlockVb(GfxResourceID vb) {
+ gfx_vertices = vb;
+}
+
+
+static GfxResourceID Gfx_AllocDynamicVb(VertexFormat fmt, int maxVertices) {
+ return Mem_TryAlloc(maxVertices, strideSizes[fmt]);
+}
+
+void Gfx_BindDynamicVb(GfxResourceID vb) { Gfx_BindVb(vb); }
+
+void* Gfx_LockDynamicVb(GfxResourceID vb, VertexFormat fmt, int count) {
+ return vb;
+}
+
+void Gfx_UnlockDynamicVb(GfxResourceID vb) {
+ gfx_vertices = vb;
+}
+
+void Gfx_DeleteDynamicVb(GfxResourceID* vb) { Gfx_DeleteVb(vb); }
+
+
+/*########################################################################################################################*
+*---------------------------------------------------------Matrices--------------------------------------------------------*
+*#########################################################################################################################*/
+static struct Matrix _view, _proj, mvp;
+
+void Gfx_LoadMatrix(MatrixType type, const struct Matrix* matrix) {
+ if (type == MATRIX_VIEW) _view = *matrix;
+ if (type == MATRIX_PROJECTION) _proj = *matrix;
+
+ Matrix_Mul(&mvp, &_view, &_proj);
+ // TODO
+}
+
+void Gfx_LoadIdentityMatrix(MatrixType type) {
+ Gfx_LoadMatrix(type, &Matrix_Identity);
+ // TODO
+}
+
+void Gfx_EnableTextureOffset(float x, float y) {
+ // TODO
+}
+
+void Gfx_DisableTextureOffset(void) {
+ // TODO
+}
+
+void Gfx_CalcOrthoMatrix(struct Matrix* matrix, float width, float height, float zNear, float zFar) {
+ /* Transposed, source https://learn.microsoft.com/en-us/windows/win32/opengl/glortho */
+ /* The simplified calculation below uses: L = 0, R = width, T = 0, B = height */
+ *matrix = Matrix_Identity;
+
+ matrix->row1.x = 2.0f / width;
+ matrix->row2.y = -2.0f / height;
+ matrix->row3.z = -2.0f / (zFar - zNear);
+
+ matrix->row4.x = -1.0f;
+ matrix->row4.y = 1.0f;
+ matrix->row4.z = -(zFar + zNear) / (zFar - zNear);
+}
+
+static double Cotangent(double x) { return Math_Cos(x) / Math_Sin(x); }
+void Gfx_CalcPerspectiveMatrix(struct Matrix* matrix, float fov, float aspect, float zFar) {
+ float zNear_ = zFar;
+ float zFar_ = 0.1f;
+ float c = (float)Cotangent(0.5f * fov);
+
+ /* Transposed, source https://learn.microsoft.com/en-us/windows/win32/opengl/glfrustum */
+ /* For pos FOV based perspective matrix, left/right/top/bottom are calculated as: */
+ /* left = -c * aspect, right = c * aspect, bottom = -c, top = c */
+ /* Calculations are simplified because of left/right and top/bottom symmetry */
+ *matrix = Matrix_Identity;
+ // TODO: Check is Frustum culling needs changing for this
+
+ matrix->row1.x = c / aspect;
+ matrix->row2.y = c;
+ matrix->row3.z = -(zFar_ + zNear_) / (zFar_ - zNear_);
+ matrix->row3.w = -1.0f;
+ matrix->row4.z = -(2.0f * zFar_ * zNear_) / (zFar_ - zNear_);
+ matrix->row4.w = 0.0f;
+}
+
+
+/*########################################################################################################################*
+*---------------------------------------------------------Rendering-------------------------------------------------------*
+*#########################################################################################################################*/
+void Gfx_SetVertexFormat(VertexFormat fmt) {
+ gfx_format = fmt;
+ gfx_stride = strideSizes[fmt];
+}
+
+void Gfx_DrawVb_Lines(int verticesCount) {
+
+}
+
+void Gfx_DrawVb_IndexedTris_Range(int verticesCount, int startVertex) {
+}
+
+void Gfx_DrawVb_IndexedTris(int verticesCount) {
+}
+
+void Gfx_DrawIndexedTris_T2fC4b(int verticesCount, int startVertex) {
+}
+
+
+/*########################################################################################################################*
+*---------------------------------------------------------Other/Misc------------------------------------------------------*
+*#########################################################################################################################*/
+cc_result Gfx_TakeScreenshot(struct Stream* output) {
+ return ERR_NOT_SUPPORTED;
+}
+
+cc_bool Gfx_WarnIfNecessary(void) {
+ return false;
+}
+
+void Gfx_BeginFrame(void) {
+}
+
+void Gfx_EndFrame(void) {
+ if (gfx_minFrameMs) LimitFPS();
+}
+
+void Gfx_SetFpsLimit(cc_bool vsync, float minFrameMs) {
+ gfx_minFrameMs = minFrameMs;
+ gfx_vsync = vsync;
+}
+
+void Gfx_OnWindowResize(void) {
+ // TODO
+}
+
+void Gfx_GetApiInfo(cc_string* info) {
+ String_AppendConst(info, "-- Using PS1 --\n");
+ PrintMaxTextureInfo(info);
+}
+
+cc_bool Gfx_TryRestoreContext(void) { return true; }
+#endif
diff --git a/src/Platform_PS1.c b/src/Platform_PS1.c
new file mode 100644
index 000000000..dfd452dca
--- /dev/null
+++ b/src/Platform_PS1.c
@@ -0,0 +1,229 @@
+#include "Core.h"
+#if defined PLAT_PS1
+
+#include "_PlatformBase.h"
+#include "Stream.h"
+#include "ExtMath.h"
+#include "Funcs.h"
+#include "Window.h"
+#include "Utils.h"
+#include "Errors.h"
+#include "PackedCol.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "_PlatformConsole.h"
+
+const cc_result ReturnCode_FileShareViolation = 1000000000; // not used
+const cc_result ReturnCode_FileNotFound = 99999;
+const cc_result ReturnCode_DirectoryExists = 99999;
+
+const cc_result ReturnCode_SocketInProgess = -1;
+const cc_result ReturnCode_SocketWouldBlock = -1;
+const char* Platform_AppNameSuffix = " PS1";
+void exit(int code) { } // TODO how to fix
+
+
+/*########################################################################################################################*
+*------------------------------------------------------Logging/Time-------------------------------------------------------*
+*#########################################################################################################################*/
+void Platform_Log(const char* msg, int len) {
+ char tmp[2048 + 1];
+ len = min(len, 2048);
+ Mem_Copy(tmp, msg, len); tmp[len] = '\0';
+
+ printf("%s\n", tmp);
+}
+
+#define UnixTime_TotalMS(time) ((cc_uint64)time.tv_sec * 1000 + UNIX_EPOCH + (time.tv_usec / 1000))
+TimeMS DateTime_CurrentUTC_MS(void) {
+ return 0;
+}
+
+void DateTime_CurrentLocal(struct DateTime* t) {
+ Mem_Set(t, 0, sizeof(struct DateTime));
+}
+
+
+/*########################################################################################################################*
+*--------------------------------------------------------Stopwatch--------------------------------------------------------*
+*#########################################################################################################################*/
+static volatile cc_uint32 irq_count;
+
+cc_uint64 Stopwatch_Measure(void) {
+ return irq_count;
+}
+
+cc_uint64 Stopwatch_ElapsedMicroseconds(cc_uint64 beg, cc_uint64 end) {
+ if (end < beg) return 0;
+ return (end - beg); // TODO calculate ???
+}
+
+static void timer2_handler(void) {
+ irq_count++;
+}
+
+static void Stopwatch_Init(void) {
+ TIMER_CTRL(2) = 0x0260; // CLK/8 input, repeated IRQ on overflow
+
+ EnterCriticalSection();
+ InterruptCallback(IRQ_TIMER2, &timer2_handler);
+ ExitCriticalSection();
+}
+
+
+/*########################################################################################################################*
+*-----------------------------------------------------Directory/File------------------------------------------------------*
+*#########################################################################################################################*/
+cc_result Directory_Create(const cc_string* path) {
+ return ERR_NOT_SUPPORTED;
+}
+
+int File_Exists(const cc_string* path) {
+ return 0;
+}
+
+cc_result Directory_Enum(const cc_string* dirPath, void* obj, Directory_EnumCallback callback) {
+ return ERR_NOT_SUPPORTED;
+}
+
+cc_result File_Open(cc_file* file, const cc_string* path) {
+ return ERR_NOT_SUPPORTED;
+}
+cc_result File_Create(cc_file* file, const cc_string* path) {
+ return ERR_NOT_SUPPORTED;
+}
+cc_result File_OpenOrCreate(cc_file* file, const cc_string* path) {
+ return ERR_NOT_SUPPORTED;
+}
+
+cc_result File_Read(cc_file file, void* data, cc_uint32 count, cc_uint32* bytesRead) {
+ return ERR_NOT_SUPPORTED;
+}
+
+cc_result File_Write(cc_file file, const void* data, cc_uint32 count, cc_uint32* bytesWrote) {
+ return ERR_NOT_SUPPORTED;
+}
+
+cc_result File_Close(cc_file file) {
+ return 0;
+}
+
+cc_result File_Seek(cc_file file, int offset, int seekType) {
+ return ERR_NOT_SUPPORTED;
+}
+
+cc_result File_Position(cc_file file, cc_uint32* pos) {
+ return ERR_NOT_SUPPORTED;
+}
+
+cc_result File_Length(cc_file file, cc_uint32* len) {
+ return ERR_NOT_SUPPORTED;
+}
+
+
+/*########################################################################################################################*
+*--------------------------------------------------------Threading--------------------------------------------------------*
+*#########################################################################################################################*/
+void Thread_Sleep(cc_uint32 milliseconds) {
+ // TODO sleep a bit
+ VSync(0);
+}
+
+void Thread_Run(void** handle, Thread_StartFunc func, int stackSize, const char* name) {
+ *handle = NULL;
+}
+
+void Thread_Detach(void* handle) {
+}
+
+void Thread_Join(void* handle) {
+}
+
+void* Mutex_Create(void) {
+ return NULL;
+}
+
+void Mutex_Free(void* handle) {
+}
+
+void Mutex_Lock(void* handle) {
+}
+
+void Mutex_Unlock(void* handle) {
+}
+
+void* Waitable_Create(void) {
+ return NULL;
+}
+
+void Waitable_Free(void* handle) {
+}
+
+void Waitable_Signal(void* handle) {
+}
+
+void Waitable_Wait(void* handle) {
+}
+
+void Waitable_WaitFor(void* handle, cc_uint32 milliseconds) {
+}
+
+
+/*########################################################################################################################*
+*---------------------------------------------------------Socket----------------------------------------------------------*
+*#########################################################################################################################*/
+cc_result Socket_ParseAddress(const cc_string* address, int port, cc_sockaddr* addrs, int* numValidAddrs) {
+ return ERR_NOT_SUPPORTED;
+}
+
+cc_result Socket_Connect(cc_socket* s, cc_sockaddr* addr, cc_bool nonblocking) {
+ return ERR_NOT_SUPPORTED;
+}
+
+cc_result Socket_Read(cc_socket s, cc_uint8* data, cc_uint32 count, cc_uint32* modified) {
+ return ERR_NOT_SUPPORTED;
+}
+
+cc_result Socket_Write(cc_socket s, const cc_uint8* data, cc_uint32 count, cc_uint32* modified) {
+ return ERR_NOT_SUPPORTED;
+}
+
+void Socket_Close(cc_socket s) {
+}
+
+cc_result Socket_CheckReadable(cc_socket s, cc_bool* readable) {
+ return ERR_NOT_SUPPORTED;
+}
+
+cc_result Socket_CheckWritable(cc_socket s, cc_bool* writable) {
+ return ERR_NOT_SUPPORTED;
+}
+
+
+/*########################################################################################################################*
+*--------------------------------------------------------Platform---------------------------------------------------------*
+*#########################################################################################################################*/
+void Platform_Init(void) {
+ ResetGraph( 0 );
+ Stopwatch_Init();
+}
+
+void Platform_Free(void) { }
+
+cc_bool Platform_DescribeError(cc_result res, cc_string* dst) {
+ return false;
+}
+
+
+/*########################################################################################################################*
+*-------------------------------------------------------Encryption--------------------------------------------------------*
+*#########################################################################################################################*/
+static cc_result GetMachineID(cc_uint32* key) {
+ return ERR_NOT_SUPPORTED;
+}
+#endif
diff --git a/src/Window_PS1.c b/src/Window_PS1.c
new file mode 100644
index 000000000..833224fd3
--- /dev/null
+++ b/src/Window_PS1.c
@@ -0,0 +1,206 @@
+#include "Core.h"
+#if defined CC_BUILD_PS1
+#include "Window.h"
+#include "Platform.h"
+#include "Input.h"
+#include "Event.h"
+#include "Graphics.h"
+#include "String.h"
+#include "Funcs.h"
+#include "Bitmap.h"
+#include "Errors.h"
+#include "ExtMath.h"
+#include "Logger.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define SCREEN_XRES 320
+#define SCREEN_YRES 240
+
+static cc_bool launcherMode;
+static char pad_buff[2][34];
+
+struct _DisplayData DisplayInfo;
+struct _WindowData WindowInfo;
+
+void Window_Init(void) {
+ DisplayInfo.Width = SCREEN_XRES;
+ DisplayInfo.Height = SCREEN_YRES;
+ DisplayInfo.Depth = 4; // 32 bit
+ DisplayInfo.ScaleX = 1;
+ DisplayInfo.ScaleY = 1;
+
+ Window_Main.Width = DisplayInfo.Width;
+ Window_Main.Height = DisplayInfo.Height;
+ Window_Main.Focused = true;
+ Window_Main.Exists = true;
+
+ Input.Sources = INPUT_SOURCE_GAMEPAD;
+ DisplayInfo.ContentOffsetX = 10;
+ DisplayInfo.ContentOffsetY = 10;
+
+// http://lameguy64.net/tutorials/pstutorials/chapter1/4-controllers.html
+ InitPAD(&pad_buff[0][0], 34, &pad_buff[1][0], 34);
+ pad_buff[0][0] = pad_buff[0][1] = 0xff;
+ pad_buff[1][0] = pad_buff[1][1] = 0xff;
+ StartPAD();
+ ChangeClearPAD(0);
+}
+
+void Window_Free(void) { }
+
+void Window_Create3D(int width, int height) {
+ launcherMode = false;
+}
+
+void Window_SetTitle(const cc_string* title) { }
+void Clipboard_GetText(cc_string* value) { }
+void Clipboard_SetText(const cc_string* value) { }
+
+int Window_GetWindowState(void) { return WINDOW_STATE_FULLSCREEN; }
+cc_result Window_EnterFullscreen(void) { return 0; }
+cc_result Window_ExitFullscreen(void) { return 0; }
+int Window_IsObscured(void) { return 0; }
+
+void Window_Show(void) { }
+void Window_SetSize(int width, int height) { }
+
+void Window_RequestClose(void) {
+ Event_RaiseVoid(&WindowEvents.Closing);
+}
+
+
+/*########################################################################################################################*
+*----------------------------------------------------Input processing-----------------------------------------------------*
+*#########################################################################################################################*/
+static void HandleButtons(int buttons) {
+ // Confusingly, it seems that when a bit is on, it means the button is NOT pressed
+ // So just flip the bits to make more sense
+ buttons = ~buttons;
+
+ Input_SetNonRepeatable(CCPAD_A, buttons & PAD_TRIANGLE);
+ Input_SetNonRepeatable(CCPAD_B, buttons & PAD_SQUARE);
+ Input_SetNonRepeatable(CCPAD_X, buttons & PAD_CROSS);
+ Input_SetNonRepeatable(CCPAD_Y, buttons & PAD_CIRCLE);
+
+ Input_SetNonRepeatable(CCPAD_START, buttons & PAD_START);
+ Input_SetNonRepeatable(CCPAD_SELECT, buttons & PAD_SELECT);
+
+ Input_SetNonRepeatable(CCPAD_LEFT, buttons & PAD_LEFT);
+ Input_SetNonRepeatable(CCPAD_RIGHT, buttons & PAD_RIGHT);
+ Input_SetNonRepeatable(CCPAD_UP, buttons & PAD_UP);
+ Input_SetNonRepeatable(CCPAD_DOWN, buttons & PAD_DOWN);
+
+ Input_SetNonRepeatable(CCPAD_L, buttons & PAD_L1);
+ Input_SetNonRepeatable(CCPAD_R, buttons & PAD_R1);
+ Input_SetNonRepeatable(CCPAD_ZL, buttons & PAD_L2);
+ Input_SetNonRepeatable(CCPAD_ZR, buttons & PAD_R2);
+}
+
+static void ProcessPadInput(PADTYPE* pad, double delta) {
+ HandleButtons(pad->btn);
+}
+
+void Window_ProcessEvents(double delta) {
+ PADTYPE* pad = (PADTYPE*)&pad_buff[0][0];
+ if (pad->stat == 0) ProcessPadInput(pad, delta);
+}
+
+void Cursor_SetPosition(int x, int y) { } // Makes no sense for PS Vita
+
+void Window_EnableRawMouse(void) { Input.RawMode = true; }
+void Window_UpdateRawMouse(void) { }
+void Window_DisableRawMouse(void) { Input.RawMode = false; }
+
+
+/*########################################################################################################################*
+*------------------------------------------------------Framebuffer--------------------------------------------------------*
+*#########################################################################################################################*/
+void Window_Create2D(int width, int height) {
+ launcherMode = true;
+}
+
+static DISPENV disp;
+static cc_uint16* fb;
+
+void Window_AllocFramebuffer(struct Bitmap* bmp) {
+ SetDefDispEnv(&disp, 0, 0, SCREEN_XRES, SCREEN_YRES);
+ disp.isinter = 1;
+
+ PutDispEnv(&disp);
+ SetDispMask(1);
+
+ bmp->scan0 = (BitmapCol*)Mem_Alloc(bmp->width * bmp->height, 4, "window pixels");
+ fb = Mem_Alloc(bmp->width * bmp->height, 2, "real surface");
+}
+
+#define BGRA8_to_PS1(src) \
+ ((src[2] & 0xF8) >> 3) | ((src[1] & 0xF8) << 2) | ((src[0] & 0xF8) << 7) | 0x8000
+
+void Window_DrawFramebuffer(Rect2D r, struct Bitmap* bmp) {
+ RECT rect;
+ rect.x = 0;
+ rect.y = 0;
+ rect.w = SCREEN_XRES;
+ rect.h = SCREEN_YRES;
+
+ HeapUsage usage;
+ GetHeapUsage(&usage);
+
+ Platform_Log4("%i / %i / %i / %i", &usage.total, &usage.heap, &usage.stack, &usage.alloc);
+
+
+ for (int y = 0; y < bmp->height; y++)
+ {
+ cc_uint32* src = bmp->scan0 + y * bmp->width;
+ cc_uint16* dst = fb + y * bmp->width;
+
+ for (int x = 0; x < bmp->width; x++) {
+ cc_uint8* color = (cc_uint8*)&src[x];
+ dst[x] = BGRA8_to_PS1(0);
+ }
+ }
+
+ Platform_Log4("%i / %i / %i / %i", &usage.total, &usage.heap, &usage.stack, &usage.alloc);
+
+ LoadImage(&rect, bmp->scan0);
+ DrawSync(0);
+}
+
+void Window_FreeFramebuffer(struct Bitmap* bmp) {
+ Mem_Free(bmp->scan0);
+ Mem_Free(fb);
+}
+
+
+/*########################################################################################################################*
+*------------------------------------------------------Soft keyboard------------------------------------------------------*
+*#########################################################################################################################*/
+void Window_OpenKeyboard(struct OpenKeyboardArgs* args) { /* TODO implement */ }
+void Window_SetKeyboardText(const cc_string* text) { }
+void Window_CloseKeyboard(void) { /* TODO implement */ }
+
+
+/*########################################################################################################################*
+*-------------------------------------------------------Misc/Other--------------------------------------------------------*
+*#########################################################################################################################*/
+void Window_ShowDialog(const char* title, const char* msg) {
+ /* TODO implement */
+ Platform_LogConst(title);
+ Platform_LogConst(msg);
+}
+
+cc_result Window_OpenFileDialog(const struct OpenFileDialogArgs* args) {
+ return ERR_NOT_SUPPORTED;
+}
+
+cc_result Window_SaveFileDialog(const struct SaveFileDialogArgs* args) {
+ return ERR_NOT_SUPPORTED;
+}
+#endif
diff --git a/src/_PlatformConsole.h b/src/_PlatformConsole.h
index 9845244ae..65a4c2dab 100644
--- a/src/_PlatformConsole.h
+++ b/src/_PlatformConsole.h
@@ -70,6 +70,11 @@ int Platform_GetCommandLineArgs(int argc, STRING_REF char** argv, cc_string* arg
// Consoles *sometimes* doesn't use argv[0] for program name and so argc will be 0
// (e.g. when running via some emulators)
if (!argc) return 0;
+
+#ifdef CC_BUILD_PS1
+ // When running in DuckStation at least, argv was a five element array of empty strings ???
+ return 0;
+#endif
argc--; argv++; // skip executable path argument
@@ -215,4 +220,4 @@ cc_result Platform_Decrypt(const void* data, int len, cc_string* dst) {
String_AppendAll(dst, header, min(dataLen, ENC_SIZE));
}
return 0;
-}
\ No newline at end of file
+}