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..2ac752cac 100644 --- a/src/Core.h +++ b/src/Core.h @@ -118,6 +118,7 @@ typedef cc_uint8 cc_bool; #endif +#define CC_BUILD_NETWORKING #define CC_BUILD_FREETYPE #ifndef CC_BUILD_FLATPAK #define CC_BUILD_RESOURCES @@ -329,6 +330,7 @@ typedef cc_uint8 cc_bool; #define CC_BUILD_CONSOLE #undef CC_BUILD_FREETYPE #undef CC_BUILD_RESOURCES + #undef CC_BUILD_NETWORKING #elif defined PLAT_PS2 #define CC_BUILD_PS2 #define CC_BUILD_OPENAL @@ -368,6 +370,17 @@ 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_HTTPCLIENT + #define CC_BUILD_COOPTHREADED + #define CC_BUILD_LOWMEM + #define CC_BUILD_CONSOLE + #define CC_BUILD_NOMUSIC + #define CC_BUILD_NOSOUNDS + #undef CC_BUILD_FREETYPE + #undef CC_BUILD_RESOURCES + #undef CC_BUILD_NETWORKING #endif #endif diff --git a/src/ExtMath.c b/src/ExtMath.c index 5081d706f..6196c6785 100644 --- a/src/ExtMath.c +++ b/src/ExtMath.c @@ -4,8 +4,20 @@ /* For abs(x) function */ #include -#ifndef __GNUC__ +#if defined PLAT_PS1 +#include +float Math_AbsF(float x) { return __builtin_fabsf(x); } + +float Math_SqrtF(float x) { + int fp_x = (int)(x * (1 << 12)); + fp_x = SquareRoot12(fp_x); + return (float)fp_x / (1 << 12); +} +#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..8b427d81f --- /dev/null +++ b/src/Graphics_PS1.c @@ -0,0 +1,558 @@ +#include "Core.h" +#if defined CC_BUILD_PS1 +#include "_GraphicsBase.h" +#include "Errors.h" +#include "Window.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +// Based off https://github.com/Lameguy64/PSn00bSDK/blob/master/examples/beginner/hello/main.c + + +// Length of the ordering table, i.e. the range Z coordinates can have, 0-15 in +// this case. Larger values will allow for more granularity with depth (useful +// when drawing a complex 3D scene) at the expense of RAM usage and performance. +#define OT_LENGTH 1024 + +// Size of the buffer GPU commands and primitives are written to. If the program +// crashes due to too many primitives being drawn, increase this value. +#define BUFFER_LENGTH 8192 + +typedef struct { + DISPENV disp_env; + DRAWENV draw_env; + + cc_uint32 ot[OT_LENGTH]; + cc_uint8 buffer[BUFFER_LENGTH]; +} RenderBuffer; + +static RenderBuffer buffers[2]; +static cc_uint8* next_packet; +static int active_buffer; +static RenderBuffer* buffer; + +static void OnBufferUpdated(void) { + buffer = &buffers[active_buffer]; + next_packet = buffer->buffer; + ClearOTagR(buffer->ot, OT_LENGTH); +} + +static void SetupContexts(int w, int h, int r, int g, int b) { + SetDefDrawEnv(&buffers[0].draw_env, 0, 0, w, h); + SetDefDispEnv(&buffers[0].disp_env, 0, 0, w, h); + SetDefDrawEnv(&buffers[1].draw_env, 0, h, w, h); + SetDefDispEnv(&buffers[1].disp_env, 0, h, w, h); + + setRGB0(&buffers[0].draw_env, r, g, b); + setRGB0(&buffers[1].draw_env, r, g, b); + buffers[0].draw_env.isbg = 1; + buffers[1].draw_env.isbg = 1; + + active_buffer = 0; + OnBufferUpdated(); +} + +static void FlipBuffers(void) { + DrawSync(0); + VSync(0); + + RenderBuffer* draw_buffer = &buffers[active_buffer]; + RenderBuffer* disp_buffer = &buffers[active_buffer ^ 1]; + + PutDispEnv(&disp_buffer->disp_env); + DrawOTagEnv(&draw_buffer->ot[OT_LENGTH - 1], &draw_buffer->draw_env); + + active_buffer ^= 1; + OnBufferUpdated(); +} + +static void* new_primitive(int size) { + RenderBuffer* buffer = &buffers[active_buffer]; + uint8_t* prim = next_packet; + + next_packet += size; + + assert(next_packet <= &buffer->buffer[BUFFER_LENGTH]); + return (void*)prim; +} + +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(); + ResetGraph(0); + + SetupContexts(Window_Main.Width, Window_Main.Height, 63, 0, 127); + SetDispMask(1); + + InitGeom(); + //gte_SetGeomOffset(Window_Main.Width / 2, Window_Main.Height / 2); + // Set screen depth (basically FOV control, W/2 works best) + //gte_SetGeomScreen(Window_Main.Width / 2); +} + +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) { + int r = PackedCol_R(color); + int g = PackedCol_G(color); + int b = PackedCol_B(color); + + setRGB0(&buffers[0].draw_env, r, g, b); + setRGB0(&buffers[1].draw_env, r, g, b); +} + +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; +#define ToFixed(v) (int)(v * (1 << 12)) + +static void LoadTransformMatrix(struct Matrix* src) { + // https://math.stackexchange.com/questions/237369/given-this-transformation-matrix-how-do-i-decompose-it-into-translation-rotati + MATRIX mtx; + + mtx.t[0] = 0; + mtx.t[1] = 0; + mtx.t[2] = 0; + + //Platform_Log3("X: %f3, Y: %f3, Z: %f3", &src->row1.x, &src->row1.y, &src->row1.z); + //Platform_Log3("X: %f3, Y: %f3, Z: %f3", &src->row2.x, &src->row2.y, &src->row2.z); + //Platform_Log3("X: %f3, Y: %f3, Z: %f3", &src->row3.x, &src->row3.y, &src->row3.z); + //Platform_Log3("X: %f3, Y: %f3, Z: %f3", &src->row4.x, &src->row4.y, &src->row4.z); + //Platform_LogConst("===="); + + float len1 = Math_SqrtF(src->row1.x + src->row1.y + src->row1.z); + float len2 = Math_SqrtF(src->row2.x + src->row2.y + src->row2.z); + float len3 = Math_SqrtF(src->row3.x + src->row3.y + src->row3.z); + + mtx.m[0][0] = ToFixed(1); + mtx.m[0][1] = 0; + mtx.m[0][2] = 0; + + mtx.m[1][0] = 0; + mtx.m[1][1] = ToFixed(1); + mtx.m[1][2] = 0; + + mtx.m[2][0] = 0; + mtx.m[2][1] = ToFixed(1); + mtx.m[2][2] = 1; + + gte_SetRotMatrix(&mtx); + gte_SetTransMatrix(&mtx); +} + +/*static void LoadTransformMatrix(struct Matrix* src) { + // https://math.stackexchange.com/questions/237369/given-this-transformation-matrix-how-do-i-decompose-it-into-translation-rotati + MATRIX mtx; + + mtx.t[0] = ToFixed(src->row4.x); + mtx.t[1] = ToFixed(src->row4.y); + mtx.t[2] = ToFixed(src->row4.z); + + Platform_Log3("X: %f3, Y: %f3, Z: %f3", &src->row1.x, &src->row1.y, &src->row1.z); + Platform_Log3("X: %f3, Y: %f3, Z: %f3", &src->row2.x, &src->row2.y, &src->row2.z); + Platform_Log3("X: %f3, Y: %f3, Z: %f3", &src->row3.x, &src->row3.y, &src->row3.z); + Platform_Log3("X: %f3, Y: %f3, Z: %f3", &src->row4.x, &src->row4.y, &src->row4.z); + Platform_LogConst("===="); + + float len1 = Math_SqrtF(src->row1.x + src->row1.y + src->row1.z); + float len2 = Math_SqrtF(src->row2.x + src->row2.y + src->row2.z); + float len3 = Math_SqrtF(src->row3.x + src->row3.y + src->row3.z); + + mtx.m[0][0] = ToFixed(src->row1.x / len1); + mtx.m[0][1] = ToFixed(src->row1.y / len1); + mtx.m[0][2] = ToFixed(src->row1.z / len1); + + mtx.m[1][0] = ToFixed(src->row2.x / len2); + mtx.m[1][1] = ToFixed(src->row2.y / len2); + mtx.m[1][2] = ToFixed(src->row2.z / len2); + + mtx.m[2][0] = ToFixed(src->row3.x / len3); + mtx.m[2][1] = ToFixed(src->row3.y / len3); + mtx.m[2][2] = ToFixed(src->row3.z / len3); + + gte_SetRotMatrix(&mtx); + gte_SetTransMatrix(&mtx); +}*/ + +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); + LoadTransformMatrix(&mvp); +} + +void Gfx_LoadIdentityMatrix(MatrixType type) { + Gfx_LoadMatrix(type, &Matrix_Identity); +} + +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) { + /* Source https://learn.microsoft.com/en-us/windows/win32/direct3d9/d3dxmatrixorthooffcenterrh */ + /* The simplified calculation below uses: L = 0, R = width, T = 0, B = height */ + /* NOTE: This calculation is shared with Direct3D 11 backend */ + *matrix = Matrix_Identity; + + matrix->row1.x = 2.0f / width; + matrix->row2.y = -2.0f / height; + matrix->row3.z = 1.0f / (zNear - zFar); + + matrix->row4.x = -1.0f; + matrix->row4.y = 1.0f; + matrix->row4.z = zNear / (zNear - zFar); +} + +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 = 0.01f; + /* Source https://learn.microsoft.com/en-us/windows/win32/direct3d9/d3dxmatrixperspectivefovrh */ + float c = (float)Cotangent(0.5f * fov); + *matrix = Matrix_Identity; + + matrix->row1.x = c / aspect; + matrix->row2.y = c; + matrix->row3.z = zFar / (zNear - zFar); + matrix->row3.w = -1.0f; + matrix->row4.z = (zNear * zFar) / (zNear - zFar); + matrix->row4.w = 0.0f; +} + + +/*########################################################################################################################* +*---------------------------------------------------------Rendering-------------------------------------------------------* +*#########################################################################################################################*/ +void Gfx_SetVertexFormat(VertexFormat fmt) { + gfx_format = fmt; + gfx_stride = strideSizes[fmt]; +} + +void Gfx_DrawVb_Lines(int verticesCount) { + +} + +static void Transform(Vec3* result, struct VertexTextured* a, const struct Matrix* mat) { + /* a could be pointing to result - therefore can't directly assign X/Y/Z */ + float x = a->x * mat->row1.x + a->y * mat->row2.x + a->z * mat->row3.x + mat->row4.x; + float y = a->x * mat->row1.y + a->y * mat->row2.y + a->z * mat->row3.y + mat->row4.y; + float z = a->x * mat->row1.z + a->y * mat->row2.z + a->z * mat->row3.z + mat->row4.z; + + result->x = x * (320/2) + (320/2); + result->y = y * -(240/2) + (240/2); + result->z = z * OT_LENGTH; +} + +cc_bool VERTEX_LOGGING; +static void DrawQuads(int verticesCount, int startVertex) { + for (int i = 0; i < verticesCount; i += 4) + { + struct VertexTextured* v = (struct VertexTextured*)gfx_vertices + startVertex + i; + + POLY_F4* poly = new_primitive(sizeof(POLY_F4)); + setPolyF4(poly); + + Vec3 coords[4]; + Transform(&coords[0], &v[0], &mvp); + Transform(&coords[1], &v[1], &mvp); + Transform(&coords[2], &v[2], &mvp); + Transform(&coords[3], &v[3], &mvp); + + poly->x0 = coords[1].x; poly->y0 = coords[1].y; + poly->x1 = coords[0].x; poly->y1 = coords[0].y; + poly->x2 = coords[2].x; poly->y2 = coords[2].y; + poly->x3 = coords[3].x; poly->y3 = coords[3].y; + + int X = v[0].x, Y = v[0].y, Z = v[0].z; + if (VERTEX_LOGGING) Platform_Log3("IN: %i, %i, %i", &X, &Y, &Z); + X = poly->x1; Y = poly->y1, Z = coords[0].z; + + poly->r0 = PackedCol_R(v->Col); + poly->g0 = PackedCol_G(v->Col); + poly->b0 = PackedCol_B(v->Col); + + int p = (coords[0].z + coords[1].z + coords[2].z + coords[3].z) / 4; + if (VERTEX_LOGGING) Platform_Log4("OUT: %i, %i, %i (%i)", &X, &Y, &Z, &p); + + if (p < 0 || p >= OT_LENGTH) continue; + addPrim(&buffer->ot[p >> 2], poly); + } +} + +/*static void DrawQuads(int verticesCount, int startVertex) { + for (int i = 0; i < verticesCount; i += 4) + { + struct VertexTextured* v = (struct VertexTextured*)gfx_vertices + startVertex + i; + + POLY_F4* poly = new_primitive(sizeof(POLY_F4)); + setPolyF4(poly); + + SVECTOR coords[4]; + coords[0].vx = v[0].x; coords[0].vy = v[0].y; coords[0].vz = v[0].z; + coords[1].vx = v[1].x; coords[1].vy = v[1].y; coords[1].vz = v[1].z; + coords[2].vx = v[2].x; coords[2].vy = v[2].y; coords[2].vz = v[1].z; + coords[3].vx = v[3].x; coords[3].vy = v[3].y; coords[3].vz = v[3].z; + + int X = coords[0].vx, Y = coords[0].vy, Z = coords[0].vz; + //Platform_Log3("IN: %i, %i, %i", &X, &Y, &Z); + gte_ldv3(&coords[0], &coords[1], &coords[2]); + gte_rtpt(); + gte_stsxy0(&poly->x0); + + int p; + gte_avsz3(); + gte_stotz( &p ); + + X = poly->x0; Y = poly->y0, Z = p; + //Platform_Log3("OUT: %i, %i, %i", &X, &Y, &Z); + if (((p >> 2) >= OT_LENGTH) || ((p >> 2) < 0)) + continue; + + gte_ldv0(&coords[3]); + gte_rtps(); + gte_stsxy3(&poly->x1, &poly->x2, &poly->x3); + + //poly->x0 = v[1].x; poly->y0 = v[1].y; + //poly->x1 = v[0].x; poly->y1 = v[0].y; + //poly->x2 = v[2].x; poly->y2 = v[2].y; + //poly->x3 = v[3].x; poly->y3 = v[3].y; + + poly->r0 = PackedCol_R(v->Col); + poly->g0 = PackedCol_G(v->Col); + poly->b0 = PackedCol_B(v->Col); + + addPrim(&buffer->ot[p >> 2], poly); + } +}*/ + +/*static void DrawQuads(int verticesCount, int startVertex) { + for (int i = 0; i < verticesCount; i += 4) + { + struct VertexTextured* v = (struct VertexTextured*)gfx_vertices + startVertex + i; + + POLY_F4* poly = new_primitive(sizeof(POLY_F4)); + setPolyF4(poly); + + poly->x0 = v[1].x; poly->y0 = v[1].y; + poly->x1 = v[0].x; poly->y1 = v[0].y; + poly->x2 = v[2].x; poly->y2 = v[2].y; + poly->x3 = v[3].x; poly->y3 = v[3].y; + + poly->r0 = PackedCol_R(v->Col); + poly->g0 = PackedCol_G(v->Col); + poly->b0 = PackedCol_B(v->Col); + + int p = 0; + addPrim(&buffer->ot[p >> 2], poly); + } +}*/ + +void Gfx_DrawVb_IndexedTris_Range(int verticesCount, int startVertex) { + if (gfx_format == VERTEX_FORMAT_COLOURED) return; + DrawQuads(verticesCount, startVertex); +} + +void Gfx_DrawVb_IndexedTris(int verticesCount) { + if (gfx_format == VERTEX_FORMAT_COLOURED) return; + DrawQuads(verticesCount, 0); +} + +void Gfx_DrawIndexedTris_T2fC4b(int verticesCount, int startVertex) { + DrawQuads(verticesCount, 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) { + // Draw the square by allocating a TILE (i.e. untextured solid color + // rectangle) primitive at Z = 1. + TILE *tile = (TILE *)new_primitive(sizeof(TILE)); + + setTile(tile); + setXY0 (tile, 40, 40); + setWH (tile, 64, 64); + setRGB0(tile, 255, 255, 0); + addPrim(&buffer->ot[1 >> 2], tile); +} + +void Gfx_EndFrame(void) { + FlipBuffers(); + 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..e654127c9 --- /dev/null +++ b/src/Platform_PS1.c @@ -0,0 +1,228 @@ +#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 +void exit(int code) { } // TODO how to fix +#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"; + + +/*########################################################################################################################* +*------------------------------------------------------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) * 1000; +} + +static void timer2_handler(void) { irq_count++; } + +static void Stopwatch_Init(void) { + TIMER_CTRL(2) = 0x0258; // CLK/8 input, IRQ on reload + TIMER_RELOAD(2) = (F_CPU / 8) / 1000; // 1000 Hz + + 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/Program.c b/src/Program.c index fef95a37f..104c9bfda 100644 --- a/src/Program.c +++ b/src/Program.c @@ -168,4 +168,4 @@ int main(int argc, char** argv) { Process_Exit(res); return res; } -#endif \ No newline at end of file +#endif diff --git a/src/Protocol.c b/src/Protocol.c index e4d45ba39..0459a32c7 100644 --- a/src/Protocol.c +++ b/src/Protocol.c @@ -1,9 +1,10 @@ #include "Protocol.h" +#include "Game.h" +#ifdef CC_BUILD_NETWORKING #include "String.h" #include "Deflate.h" #include "Server.h" #include "Stream.h" -#include "Game.h" #include "Entity.h" #include "Platform.h" #include "Screens.h" @@ -1872,6 +1873,13 @@ static void OnReset(void) { Protocol_Reset(); FreeMapStates(); } +#else +void CPE_SendPlayerClick(int button, cc_bool pressed, cc_uint8 targetId, struct RayTracer* t) { } + +static void OnInit(void) { } + +static void OnReset(void) { } +#endif struct IGameComponent Protocol_Component = { OnInit, /* Init */ diff --git a/src/Server.c b/src/Server.c index cd13c2cbd..3d1b8dad3 100644 --- a/src/Server.c +++ b/src/Server.c @@ -128,7 +128,7 @@ static void SPConnection_BeginConnect(void) { Random_SeedFromCurrentTime(&rnd); World_NewMap(); -#if defined CC_BUILD_NDS +#if defined CC_BUILD_NDS || defined CC_BUILD_PS1 World_SetDimensions(16, 16, 16); #elif defined CC_BUILD_LOWMEM World_SetDimensions(64, 64, 64); @@ -136,7 +136,7 @@ static void SPConnection_BeginConnect(void) { World_SetDimensions(128, 64, 128); #endif -#if defined CC_BUILD_N64 || defined CC_BUILD_NDS +#if defined CC_BUILD_N64 || defined CC_BUILD_NDS || defined CC_BUILD_PS1 Gen_Active = &FlatgrassGen; #else Gen_Active = &NotchyGen; @@ -223,10 +223,12 @@ static void SPConnection_Init(void) { *--------------------------------------------------Multiplayer connection-------------------------------------------------* *#########################################################################################################################*/ static cc_socket net_socket = -1; +static cc_result net_writeFailure; +static void OnClose(void); + +#ifdef CC_BUILD_NETWORKING static cc_uint8 net_readBuffer[4096 * 5]; static cc_uint8* net_readCurrent; - -static cc_result net_writeFailure; static double net_lastPacket; static cc_uint8 lastOpcode; @@ -234,7 +236,6 @@ static cc_bool net_connecting; static double net_connectTimeout; #define NET_TIMEOUT_SECS 15 -static void OnClose(void); static void MPConnection_FinishConnect(void) { net_connecting = false; Event_RaiseVoid(&NetEvents.Connected); @@ -475,8 +476,14 @@ static void MPConnection_Init(void) { Server.SendData = MPConnection_SendData; net_readCurrent = net_readBuffer; } +#else +static void MPConnection_Init(void) { SPConnection_Init(); } +#endif +/*########################################################################################################################* +*---------------------------------------------------Component interface---------------------------------------------------* +*#########################################################################################################################*/ static void OnNewMap(void) { int i; if (Server.IsSinglePlayer) return; diff --git a/src/Window_PS1.c b/src/Window_PS1.c new file mode 100644 index 000000000..df1fa58d1 --- /dev/null +++ b/src/Window_PS1.c @@ -0,0 +1,198 @@ +#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 = 0.5f; + DisplayInfo.ScaleY = 0.5f; + + 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; + + for (int y = r.y; y < r.y + r.Height; y++) + { + cc_uint32* src = bmp->scan0 + y * bmp->width; + cc_uint16* dst = fb + y * bmp->width; + + for (int x = r.x; x < r.x + r.Width; x++) { + cc_uint8* color = (cc_uint8*)&src[x]; + dst[x] = BGRA8_to_PS1(color); + } + } + + LoadImage(&rect, fb); + 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 +}