Merge branch 'ClassiCube:master' into wii-audio

This commit is contained in:
Headshotnoby 2024-03-28 00:42:53 -04:00 committed by GitHub
commit 1cb87ee034
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 1180 additions and 10 deletions

4
.gitignore vendored
View File

@ -72,6 +72,10 @@ ClassiCube*
screenshots
fontscache.txt
# CMake files
CMakeFiles/
CMakeCache.txt
#GCC object files
*.o

View File

@ -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:

21
misc/ps1/CMakeLists.txt Normal file
View File

@ -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
)

View File

@ -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
}
}
]
}

83
misc/ps1/iso.xml Normal file
View File

@ -0,0 +1,83 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
This file is processed by CMake and used by mkpsxiso to build the CD image.
NOTE: all paths are relative to the build directory; if you want to include
a file from the source tree, you'll have to prepend its path with
${PROJECT_SOURCE_DIR}.
-->
<iso_project>
<track type="data">
<!--
The "volume", "volume_set", "publisher", "data_preparer" and
"copyright" strings below can be freely modified. The ISO9660
specification, however, imposes the following limitations:
- "volume" and "volume_set" must be 32 characters or less, and can
only contain uppercase letters, digits and underscores.
- "publisher" and "data_preparer" can be up to 128 characters long
and can additionally contain spaces and some special characters.
- "copyright" should be a path to a file on the disc, even one that
does not exist (but in practice it can be set to anything).
"system" and "application" must always be set to "PLAYSTATION" in
order for the disc to be recognized as valid.
-->
<identifiers
system ="PLAYSTATION"
volume ="PSN00BSDK_TEMPLATE"
volume_set ="PSN00BSDK_TEMPLATE"
publisher ="MEIDOTEK"
data_preparer ="PSN00BSDK ${PSN00BSDK_VERSION}"
application ="PLAYSTATION"
copyright ="README.TXT;1"
/>
<!--
You may optionally include a license file using the <license> tag.
Some consoles, particularly Japanese or PAL models with a modchip,
require the disc to contain valid license data and will refuse to
boot if it is missing. License files are usually not required on
US consoles or when booting via softmods or cheat cartridges.
License files are region-specific and are not distributed with
PSn00bSDK for obvious reasons, but can be dumped from an official
game using dumpsxiso or extracted from the Sony SDK.
-->
<!--<license file="${PROJECT_SOURCE_DIR}/license.dat" />-->
<!--
Files and directories can be added to the disc by placing <file>
and <dir> tags below. All file names are case-insensitive and must
be in 8.3 format, i.e. no more than 8 characters for the name and 3
for the optional extension. Directories cannot have extensions.
A boot configuration file (SYSTEM.CNF) or executable (PSX.EXE) must
be present in the root directory. Due to BIOS limitations the root
directory cannot hold more than 30 files or directories, and the
entire disc must contain 45 directories or less. Subdirectories can
contain any number of files.
-->
<directory_tree>
<file name="SYSTEM.CNF" type="data" source="${PROJECT_SOURCE_DIR}/system.cnf" />
<file name="TEMPLATE.EXE" type="data" source="template.exe" />
<!--
This file is only required if you are using dynamic linking
(see the system/dynlink example). It contains the executable's
symbol map and can be used to obtain the address of a function
or global variable by its name.
-->
<!--<file name="TEMPLATE.MAP" type="data" source="template.map" />-->
<dummy sectors="1024"/>
</directory_tree>
</track>
<!--
CD-DA tracks can be added to the CD image by using one or more <track>
tags. The source attribute must be a path to an audio file in WAV, FLAC
or MP3 format (using WAV or FLAC is highly recommended to preserve
audio quality if you have a lossless copy of the source track).
-->
<!--<track type="audio" source="${PROJECT_SOURCE_DIR}/track2.wav" />-->
</iso_project>

4
misc/ps1/system.cnf Normal file
View File

@ -0,0 +1,4 @@
BOOT=cdrom:\template.exe;1
TCB=4
EVENT=10
STACK=801FFFF0

View File

@ -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

View File

@ -4,8 +4,20 @@
/* For abs(x) function */
#include <stdlib.h>
#ifndef __GNUC__
#if defined PLAT_PS1
#include <psxgte.h>
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 <math.h>
float Math_AbsF(float x) { return fabsf(x); /* MSVC intrinsic */ }
float Math_SqrtF(float x) { return sqrtf(x); /* MSVC intrinsic */ }
#endif

View File

@ -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)

558
src/Graphics_PS1.c Normal file
View File

@ -0,0 +1,558 @@
#include "Core.h"
#if defined CC_BUILD_PS1
#include "_GraphicsBase.h"
#include "Errors.h"
#include "Window.h"
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <psxgpu.h>
#include <psxgte.h>
#include <psxpad.h>
#include <psxapi.h>
#include <psxetc.h>
#include <inline_c.h>
// 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

228
src/Platform_PS1.c Normal file
View File

@ -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 <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <psxetc.h>
#include <psxapi.h>
#include <psxgpu.h>
#include <hwregs_c.h>
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

View File

@ -168,4 +168,4 @@ int main(int argc, char** argv) {
Process_Exit(res);
return res;
}
#endif
#endif

View File

@ -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 */

View File

@ -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;

198
src/Window_PS1.c Normal file
View File

@ -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 <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <psxapi.h>
#include <psxetc.h>
#include <psxgte.h>
#include <psxgpu.h>
#include <psxpad.h>
#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

View File

@ -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;
}
}