Mirai's Miscellaneous Misadventures

M28 / engines / psx.c

// copyright 2022 zamfofex
// license: AGPLv3 or later

#include <stdlib.h>
#include <psxgpu.h>

#include <mimimi/engines.h>
#include <mimimi/assets.h>
#include <mimimi/behaviors.h>
#include <mimimi/geometry.h>
#include <mimimi/chapters.h>
#include <mimimi/engines/psx.h>
#include <mimimi/malloc.h>

static unsigned short int mimimi_psx_palette[256] =
{
	0x0000, 0x0842, 0x1084, 0x18C6, 0x2529, 0x2D6B, 0x35AD, 0x3DEF,
	0x4631, 0x4E73, 0x56B5, 0x5EF7, 0x6B5A, 0x739C, 0x7BDE, 0x8420,
	0x1042, 0x2842, 0x4442, 0x5C42, 0x7442, 0x10C2, 0x28C2, 0x44C2,
	0x5CC2, 0x74C2, 0x1142, 0x2942, 0x4542, 0x5D42, 0x7542, 0x11C2,
	0x29C2, 0x45C2, 0x5DC2, 0x75C2, 0x1262, 0x2A62, 0x4662, 0x5E62,
	0x7662, 0x12E2, 0x2AE2, 0x46E2, 0x5EE2, 0x76E2, 0x1362, 0x2B62,
	0x4762, 0x5F62, 0x7762, 0x13E2, 0x2BE2, 0x47E2, 0x5FE2, 0x77E2,
	0x1048, 0x2848, 0x4448, 0x5C48, 0x7448, 0x10C8, 0x28C8, 0x44C8,
	0x5CC8, 0x74C8, 0x1148, 0x2948, 0x4548, 0x5D48, 0x7548, 0x11C8,
	0x29C8, 0x45C8, 0x5DC8, 0x75C8, 0x1268, 0x2A68, 0x4668, 0x5E68,
	0x7668, 0x12E8, 0x2AE8, 0x46E8, 0x5EE8, 0x76E8, 0x1368, 0x2B68,
	0x4768, 0x5F68, 0x7768, 0x13E8, 0x2BE8, 0x47E8, 0x5FE8, 0x77E8,
	0x104E, 0x284E, 0x444E, 0x5C4E, 0x744E, 0x10CE, 0x28CE, 0x44CE,
	0x5CCE, 0x74CE, 0x114E, 0x294E, 0x454E, 0x5D4E, 0x754E, 0x11CE,
	0x29CE, 0x45CE, 0x5DCE, 0x75CE, 0x126E, 0x2A6E, 0x466E, 0x5E6E,
	0x766E, 0x12EE, 0x2AEE, 0x46EE, 0x5EEE, 0x76EE, 0x136E, 0x2B6E,
	0x476E, 0x5F6E, 0x776E, 0x13EE, 0x2BEE, 0x47EE, 0x5FEE, 0x77EE,
	0x1053, 0x2853, 0x4453, 0x5C53, 0x7453, 0x10D3, 0x28D3, 0x44D3,
	0x5CD3, 0x74D3, 0x1153, 0x2953, 0x4553, 0x5D53, 0x7553, 0x11D3,
	0x29D3, 0x45D3, 0x5DD3, 0x75D3, 0x1273, 0x2A73, 0x4673, 0x5E73,
	0x7673, 0x12F3, 0x2AF3, 0x46F3, 0x5EF3, 0x76F3, 0x1373, 0x2B73,
	0x4773, 0x5F73, 0x7773, 0x13F3, 0x2BF3, 0x47F3, 0x5FF3, 0x77F3,
	0x1059, 0x2859, 0x4459, 0x5C59, 0x7459, 0x10D9, 0x28D9, 0x44D9,
	0x5CD9, 0x74D9, 0x1159, 0x2959, 0x4559, 0x5D59, 0x7559, 0x11D9,
	0x29D9, 0x45D9, 0x5DD9, 0x75D9, 0x1279, 0x2A79, 0x4679, 0x5E79,
	0x7679, 0x12F9, 0x2AF9, 0x46F9, 0x5EF9, 0x76F9, 0x1379, 0x2B79,
	0x4779, 0x5F79, 0x7779, 0x13F9, 0x2BF9, 0x47F9, 0x5FF9, 0x77F9,
	0x105F, 0x285F, 0x445F, 0x5C5F, 0x745F, 0x10DF, 0x28DF, 0x44DF,
	0x5CDF, 0x74DF, 0x115F, 0x295F, 0x455F, 0x5D5F, 0x755F, 0x11DF,
	0x29DF, 0x45DF, 0x5DDF, 0x75DF, 0x127F, 0x2A7F, 0x467F, 0x5E7F,
	0x767F, 0x12FF, 0x2AFF, 0x46FF, 0x5EFF, 0x76FF, 0x137F, 0x2B7F,
	0x477F, 0x5F7F, 0x777F, 0x13FF, 0x2BFF, 0x47FF, 0x5FFF, 0x77FF,
};

struct mimimi_psx_data
{
	unsigned short int *colors;
	int x, y;
};

static void mimimi_psx_stamp(void *data, int x1, int y1, struct mimimi_image *image)
{
	struct mimimi_psx_data *psx_data = data;
	
	int x0 = 0;
	int y0 = 0;
	
	if (x1 < 0) x0 = -x1;
	if (y1 < 0) y0 = -y1;
	
	int width = image->width;
	int height = image->height;
	
	if (width + x1 > 512) width = 512 - x1;
	if (height + y1 > 256) height = 256 - y1;
	
	for (int y = y0 ; y < height ; y++)
	for (int x = x0 ; x < width ; x++)
	{
		unsigned char color = image->colors[x + y * image->width];
		if (color == 0) continue;
		
		int x2 = x + x1;
		int y2 = y + y1;
		
		psx_data->colors[x2 + y2 * 512] = mimimi_psx_palette[color];
	}
	
	RECT rectangle = {psx_data->x, psx_data->y, 512, 256};
	LoadImage(&rectangle, (void *) psx_data->colors);
}

void mimimi_psx(struct mimimi_chapter *(*start)(struct mimimi_engine *engine))
{
	static struct mimimi_size size = {512, 256};
	
	ResetGraph(0);
	
	DISPENV display[2];
	SetDefDispEnv(display + 0, 0, 0, size.width, 384);
	SetDefDispEnv(display + 1, size.width, 0, size.width, 384);
	display[0].isinter = 1;
	display[1].isinter = 1;
	
	SetDispMask(1);
	
	struct mimimi_psx_data data;
	data.colors = malloc(size.width * size.height * 2);
	data.x = 0;
	data.y = 0;
	
	struct mimimi_engine engine;
	engine.data = &data;
	engine.stamp = &mimimi_psx_stamp;
	engine.size = &size;
	engine.allocator = mimimi_malloc;
	struct mimimi_chapter *chapter = (*start)(&engine);
	struct mimimi_behavior *behavior = chapter->behavior;
	
	int i = 0;
	for (;;)
	{
		i ^= 1;
		
		data.x = size.width * i;
		(*behavior->behave)(behavior->data);
		
		VSync(0);
		PutDispEnv(display + i);
	}
}