summary refs log tree commit diff
path: root/src/Graphics_PSP.c
diff options
context:
space:
mode:
authorWlodekM <[email protected]>2024-06-16 10:35:45 +0300
committerWlodekM <[email protected]>2024-06-16 10:35:45 +0300
commitabef6da56913f1c55528103e60a50451a39628b1 (patch)
treeb3c8092471ecbb73e568cd0d336efa0e7871ee8d /src/Graphics_PSP.c
initial commit
Diffstat (limited to 'src/Graphics_PSP.c')
-rw-r--r--src/Graphics_PSP.c450
1 files changed, 450 insertions, 0 deletions
diff --git a/src/Graphics_PSP.c b/src/Graphics_PSP.c
new file mode 100644
index 0000000..75cedff
--- /dev/null
+++ b/src/Graphics_PSP.c
@@ -0,0 +1,450 @@
+#include "Core.h"
+#if defined CC_BUILD_PSP
+#include "_GraphicsBase.h"
+#include "Errors.h"
+#include "Logger.h"
+#include "Window.h"
+
+#include <malloc.h>
+#include <pspkernel.h>
+#include <pspdisplay.h>
+#include <pspdebug.h>
+#include <pspctrl.h>
+#include <pspgu.h>
+
+#define BUFFER_WIDTH  512
+#define SCREEN_WIDTH  480
+#define SCREEN_HEIGHT 272
+
+#define FB_SIZE (BUFFER_WIDTH * SCREEN_HEIGHT * 4)
+static unsigned int __attribute__((aligned(16))) list[262144];
+
+
+/*########################################################################################################################*
+*---------------------------------------------------------General---------------------------------------------------------*
+*#########################################################################################################################*/
+static int formatFields[] = {
+	GU_TEXTURE_32BITF | GU_VERTEX_32BITF | GU_TRANSFORM_3D,
+	GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_VERTEX_32BITF | GU_TRANSFORM_3D
+};
+static ScePspFMatrix4 identity;
+
+static void guInit(void) {
+	void* framebuffer0 = (void*)0;
+	void* framebuffer1 = (void*)FB_SIZE;
+	void* depthbuffer  = (void*)(FB_SIZE + FB_SIZE);
+	Mem_Copy(&identity, &Matrix_Identity, sizeof(ScePspFMatrix4));
+	
+	sceGuInit();
+	sceGuStart(GU_DIRECT, list);
+	sceGuDrawBuffer(GU_PSM_8888, framebuffer0, BUFFER_WIDTH);
+	sceGuDispBuffer(SCREEN_WIDTH, SCREEN_HEIGHT, framebuffer1, BUFFER_WIDTH);
+	sceGuDepthBuffer(depthbuffer, BUFFER_WIDTH);
+	
+	sceGuOffset(2048 - (SCREEN_WIDTH / 2), 2048 - (SCREEN_HEIGHT / 2));
+	sceGuViewport(2048, 2048, SCREEN_WIDTH, SCREEN_HEIGHT);
+	sceGuDepthRange(65535,0);
+	sceGuFrontFace(GU_CCW);
+	sceGuShadeModel(GU_SMOOTH);
+	sceGuDisable(GU_TEXTURE_2D);
+	
+	sceGuAlphaFunc(GU_GREATER, 0x7f, 0xff);
+	sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0);
+	sceGuDepthFunc(GU_LEQUAL); // sceGuDepthFunc(GU_GEQUAL);
+	sceGuClearDepth(65535); // sceGuClearDepth(0);
+	sceGuDepthRange(0, 65535); // sceGuDepthRange(65535, 0);
+	
+	
+	sceGuSetMatrix(GU_MODEL, &identity);
+	sceGuColor(0xffffffff);
+	sceGuScissor(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+	sceGuDisable(GU_SCISSOR_TEST);
+	
+	sceGuEnable(GU_CLIP_PLANES); // TODO: swap near/far instead of this?
+	sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA);
+	
+	sceGuFinish();
+	sceGuSync(0,0);
+	sceDisplayWaitVblankStart();
+	sceGuDisplay(GU_TRUE);
+}
+
+static GfxResourceID white_square;
+void Gfx_Create(void) {
+	if (!Gfx.Created) guInit();
+	
+	Gfx.MaxTexWidth  = 512;
+	Gfx.MaxTexHeight = 512;
+	Gfx.Created      = true;
+	gfx_vsync        = true;
+	
+	Gfx_RestoreState();
+}
+
+void Gfx_Free(void) { 
+	Gfx_FreeState();
+}
+
+cc_bool Gfx_TryRestoreContext(void) { return true; }
+
+void Gfx_RestoreState(void) {
+	InitDefaultResources();
+	
+	// 1x1 dummy white texture
+	struct Bitmap bmp;
+	BitmapCol pixels[1] = { BITMAPCOLOR_WHITE };
+	Bitmap_Init(bmp, 1, 1, pixels);
+	white_square = Gfx_CreateTexture(&bmp, 0, false);
+}
+
+void Gfx_FreeState(void) {
+	FreeDefaultResources(); 
+	Gfx_DeleteTexture(&white_square);
+}
+
+#define GU_Toggle(cap) if (enabled) { sceGuEnable(cap); } else { sceGuDisable(cap); }
+
+/*########################################################################################################################*
+*---------------------------------------------------------Textures--------------------------------------------------------*
+*#########################################################################################################################*/
+typedef struct CCTexture_ {
+	cc_uint32 width, height;
+	cc_uint32 pad1, pad2; // data must be aligned to 16 bytes
+	cc_uint32 pixels[];
+} CCTexture;
+
+static GfxResourceID Gfx_AllocTexture(struct Bitmap* bmp, int rowWidth, cc_uint8 flags, cc_bool mipmaps) {
+	int size = bmp->width * bmp->height * 4;
+	CCTexture* tex = (CCTexture*)memalign(16, 16 + size);
+	
+	tex->width  = bmp->width;
+	tex->height = bmp->height;
+	CopyTextureData(tex->pixels, bmp->width * 4, bmp, rowWidth << 2);
+	return tex;
+}
+
+void Gfx_UpdateTexture(GfxResourceID texId, int x, int y, struct Bitmap* part, int rowWidth, cc_bool mipmaps) {
+	CCTexture* tex = (CCTexture*)texId;
+	cc_uint32* dst = (tex->pixels + x) + y * tex->width;
+	CopyTextureData(dst, tex->width * 4, part, rowWidth << 2);
+	// TODO: Do line by line and only invalidate the actually changed parts of lines?
+	sceKernelDcacheWritebackInvalidateRange(dst, (tex->width * part->height) * 4);
+}
+
+/*void Gfx_UpdateTexture(GfxResourceID texId, int x, int y, struct Bitmap* part, int rowWidth, cc_bool mipmaps) {
+	CCTexture* tex = (CCTexture*)texId;
+	cc_uint32* dst = (tex->pixels + x) + y * tex->width;
+
+	for (int yy = 0; yy < part->height; yy++) {
+		Mem_Copy(dst + (y + yy) * tex->width, part->scan0 + yy * rowWidth, part->width * 4);
+	}
+}*/
+
+void Gfx_DeleteTexture(GfxResourceID* texId) {
+	GfxResourceID data = *texId;
+	if (data) Mem_Free(data);
+	*texId = NULL;
+}
+
+void Gfx_EnableMipmaps(void) { }
+void Gfx_DisableMipmaps(void) { }
+
+void Gfx_BindTexture(GfxResourceID texId) {
+	CCTexture* tex = (CCTexture*)texId;
+	if (!tex) tex  = white_square; 
+	
+	sceGuTexMode(GU_PSM_8888,0,0,0);
+	sceGuTexImage(0, tex->width, tex->height, tex->width, tex->pixels);
+}
+
+
+/*########################################################################################################################*
+*-----------------------------------------------------State management----------------------------------------------------*
+*#########################################################################################################################*/
+static PackedCol gfx_clearColor;
+void Gfx_SetFaceCulling(cc_bool enabled)   { GU_Toggle(GU_CULL_FACE); }
+static void SetAlphaBlend(cc_bool enabled) { GU_Toggle(GU_BLEND); }
+void Gfx_SetAlphaArgBlend(cc_bool enabled) { }
+
+void Gfx_ClearColor(PackedCol color) {
+	if (color == gfx_clearColor) return;
+	sceGuClearColor(color);
+	gfx_clearColor = color;
+}
+
+static void SetColorWrite(cc_bool r, cc_bool g, cc_bool b, cc_bool a) {
+	unsigned int mask = 0xffffffff;
+	if (r) mask &= 0xffffff00;
+	if (g) mask &= 0xffff00ff;
+	if (b) mask &= 0xff00ffff;
+	if (a) mask &= 0x00ffffff;
+	
+	sceGuPixelMask(mask);
+}
+
+void Gfx_SetDepthWrite(cc_bool enabled) {
+	sceGuDepthMask(enabled ? 0 : 0xffffffff); 
+}
+void Gfx_SetDepthTest(cc_bool enabled)  { GU_Toggle(GU_DEPTH_TEST); }
+
+/*########################################################################################################################*
+*---------------------------------------------------------Matrices--------------------------------------------------------*
+*#########################################################################################################################*/
+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
+	// NOTE: Shared with OpenGL. might be wrong to do that though?
+	*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 float Cotangent(float x) { return Math_CosF(x) / Math_SinF(x); }
+void Gfx_CalcPerspectiveMatrix(struct Matrix* matrix, float fov, float aspect, float zFar) {
+	float zNear = 0.1f;
+	float c = Cotangent(0.5f * fov);
+
+	// Transposed, source https://learn.microsoft.com/en-us/windows/win32/opengl/glfrustum
+	// For a 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;
+
+	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;
+	// TODO: should direct3d9 one be used insted with clip range from 0,1 ?
+}
+
+
+/*########################################################################################################################*
+*-----------------------------------------------------------Misc----------------------------------------------------------*
+*#########################################################################################################################*/
+static BitmapCol* PSP_GetRow(struct Bitmap* bmp, int y, void* ctx) {
+	cc_uint8* fb = (cc_uint8*)ctx;
+	return (BitmapCol*)(fb + y * BUFFER_WIDTH * 4);
+}
+
+cc_result Gfx_TakeScreenshot(struct Stream* output) {
+	int fbWidth, fbFormat;
+	void* fb;
+
+	int res = sceDisplayGetFrameBuf(&fb, &fbWidth, &fbFormat, PSP_DISPLAY_SETBUF_NEXTFRAME);
+	if (res < 0) return res;
+	if (!fb)     return ERR_NOT_SUPPORTED;
+
+	struct Bitmap bmp;
+	bmp.scan0  = NULL;
+	bmp.width  = SCREEN_WIDTH; 
+	bmp.height = SCREEN_HEIGHT;
+
+	return Png_Encode(&bmp, output, PSP_GetRow, false, fb);
+}
+
+void Gfx_GetApiInfo(cc_string* info) {
+	String_AppendConst(info, "-- Using PSP--\n");
+	PrintMaxTextureInfo(info);
+}
+
+void Gfx_SetFpsLimit(cc_bool vsync, float minFrameMs) {
+	gfx_minFrameMs = minFrameMs;
+	gfx_vsync      = vsync;
+}
+
+void Gfx_BeginFrame(void) {
+	sceGuStart(GU_DIRECT, list);
+}
+
+void Gfx_ClearBuffers(GfxBuffers buffers) {
+	int targets = 0;
+	if (buffers & GFX_BUFFER_COLOR) targets |= GU_COLOR_BUFFER_BIT;
+	if (buffers & GFX_BUFFER_DEPTH) targets |= GU_DEPTH_BUFFER_BIT;
+	
+	sceGuClear(targets);
+}
+
+void Gfx_EndFrame(void) {
+	sceGuFinish();
+	sceGuSync(0, 0);
+
+	if (gfx_vsync) sceDisplayWaitVblankStart();
+	sceGuSwapBuffers();
+	if (gfx_minFrameMs) LimitFPS();
+}
+
+void Gfx_OnWindowResize(void) { }
+
+void Gfx_SetViewport(int x, int y, int w, int h) { }
+
+
+static cc_uint8* gfx_vertices;
+static int gfx_fields;
+
+
+/*########################################################################################################################*
+*----------------------------------------------------------Buffers--------------------------------------------------------*
+*#########################################################################################################################*/
+static cc_uint16 __attribute__((aligned(16))) gfx_indices[GFX_MAX_INDICES];
+static int vb_size;
+
+GfxResourceID Gfx_CreateIb2(int count, Gfx_FillIBFunc fillFunc, void* obj) {
+	fillFunc(gfx_indices, count, obj);
+}
+
+void Gfx_BindIb(GfxResourceID ib)    { }
+void Gfx_DeleteIb(GfxResourceID* ib) { }
+
+
+static GfxResourceID Gfx_AllocStaticVb(VertexFormat fmt, int count) {
+	return memalign(16, 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) {
+	vb_size = count * strideSizes[fmt];
+	return vb;
+}
+
+void Gfx_UnlockVb(GfxResourceID vb) { 
+	gfx_vertices = vb; 
+	sceKernelDcacheWritebackInvalidateRange(vb, vb_size);
+}
+
+
+static GfxResourceID Gfx_AllocDynamicVb(VertexFormat fmt, int maxVertices) {
+	return memalign(16, maxVertices * strideSizes[fmt]);
+}
+
+void Gfx_BindDynamicVb(GfxResourceID vb) { Gfx_BindVb(vb); }
+
+void* Gfx_LockDynamicVb(GfxResourceID vb, VertexFormat fmt, int count) {
+	vb_size = count * strideSizes[fmt];
+	return vb; 
+}
+
+void Gfx_UnlockDynamicVb(GfxResourceID vb) { 
+	gfx_vertices = vb; 
+	sceKernelDcacheWritebackInvalidateRange(vb, vb_size);
+}
+
+void Gfx_DeleteDynamicVb(GfxResourceID* vb) { Gfx_DeleteVb(vb); }
+
+
+/*########################################################################################################################*
+*-----------------------------------------------------State management----------------------------------------------------*
+*#########################################################################################################################*/
+static PackedCol gfx_fogColor;
+static float gfx_fogEnd = -1.0f, gfx_fogDensity = -1.0f;
+static int gfx_fogMode  = -1;
+
+void Gfx_SetFog(cc_bool enabled) {
+	gfx_fogEnabled = enabled;
+	//GU_Toggle(GU_FOG);
+}
+
+void Gfx_SetFogCol(PackedCol color) {
+	if (color == gfx_fogColor) return;
+	gfx_fogColor = color;
+	//sceGuFog(0.0f, gfx_fogEnd, gfx_fogColor);
+}
+
+void Gfx_SetFogDensity(float value) {
+}
+
+void Gfx_SetFogEnd(float value) {
+	if (value == gfx_fogEnd) return;
+	gfx_fogEnd = value;
+	//sceGuFog(0.0f, gfx_fogEnd, gfx_fogColor);
+}
+
+void Gfx_SetFogMode(FogFunc func) {
+	/* TODO: Implemen fake exp/exp2 fog */
+}
+
+static void SetAlphaTest(cc_bool enabled) { GU_Toggle(GU_ALPHA_TEST); }
+
+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]);
+}
+
+
+/*########################################################################################################################*
+*---------------------------------------------------------Matrices--------------------------------------------------------*
+*#########################################################################################################################*/
+static int matrix_modes[] = { GU_PROJECTION, GU_VIEW };
+static ScePspFMatrix4 tmp_matrix; // 16 byte aligned
+
+void Gfx_LoadMatrix(MatrixType type, const struct Matrix* matrix) {
+	Mem_Copy(&tmp_matrix, matrix, sizeof(ScePspFMatrix4));
+	sceGuSetMatrix(matrix_modes[type], &tmp_matrix);
+}
+
+void Gfx_LoadIdentityMatrix(MatrixType type) {
+	sceGuSetMatrix(matrix_modes[type], &identity);
+}
+
+void Gfx_EnableTextureOffset(float x, float y) {
+	sceGuTexOffset(x, y);
+}
+
+void Gfx_DisableTextureOffset(void) { 
+	sceGuTexOffset(0.0f, 0.0f);
+}
+
+
+
+/*########################################################################################################################*
+*---------------------------------------------------------Drawing---------------------------------------------------------*
+*#########################################################################################################################*/
+cc_bool Gfx_WarnIfNecessary(void) { return false; }
+
+void Gfx_SetVertexFormat(VertexFormat fmt) {
+	if (fmt == gfx_format) return;
+	gfx_format = fmt;
+	gfx_fields = formatFields[fmt];
+	gfx_stride = strideSizes[fmt];
+
+	if (fmt == VERTEX_FORMAT_TEXTURED) {
+		sceGuEnable(GU_TEXTURE_2D);
+	} else {
+		sceGuDisable(GU_TEXTURE_2D);
+	}
+}
+
+void Gfx_DrawVb_Lines(int verticesCount) {
+	sceGuDrawArray(GU_LINES, gfx_fields, verticesCount, NULL, gfx_vertices);
+}
+
+void Gfx_DrawVb_IndexedTris_Range(int verticesCount, int startVertex) {
+	sceGuDrawArray(GU_TRIANGLES, gfx_fields | GU_INDEX_16BIT, ICOUNT(verticesCount), 
+			gfx_indices, gfx_vertices + startVertex * gfx_stride);
+}
+
+void Gfx_DrawVb_IndexedTris(int verticesCount) {
+	sceGuDrawArray(GU_TRIANGLES, gfx_fields | GU_INDEX_16BIT, ICOUNT(verticesCount),
+			gfx_indices, gfx_vertices);
+}
+
+void Gfx_DrawIndexedTris_T2fC4b(int verticesCount, int startVertex) {
+	sceGuDrawArray(GU_TRIANGLES, gfx_fields | GU_INDEX_16BIT, ICOUNT(verticesCount), 
+			gfx_indices, gfx_vertices + startVertex * SIZEOF_VERTEX_TEXTURED);
+}
+#endif