
Code: Select all
#include <pspkernel.h>
#include <pspdisplay.h>
#include <pspdebug.h>
#include <stdlib.h>
#include <malloc.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <png.h>
#include <zlib.h>
#include <pspctrl.h>
#include <pspgu.h>
#include <psprtc.h>
PSP_MODULE_INFO("ImageViewer", 0, 1, 1);
PSP_MAIN_THREAD_ATTR(THREAD_ATTR_USER);
static unsigned int __attribute__((aligned(16))) list[262144];
#define BUF_WIDTH (512)
#define SCR_WIDTH (480)
#define SCR_HEIGHT (272)
typedef struct 
{
int Width;
int Height;
int power2height;
int power2width;
unsigned short *ImageData;
}Image;
//static unsigned short __attribute__((aligned(16))) pixels[BUF_WIDTH*SCR_HEIGHT];
//static unsigned short __attribute__((aligned(16))) swizzled_pixels[BUF_WIDTH*SCR_HEIGHT];
static int exitRequest = 0;
static unsigned int staticOffset = 0;
static unsigned int getMemorySize(unsigned int width, unsigned int height, unsigned int psm)
{
	switch (psm)
	{
		case GU_PSM_T4:
			return (width * height) >> 1;
		case GU_PSM_T8:
			return width * height;
		case GU_PSM_5650:
		case GU_PSM_5551:
		case GU_PSM_4444:
		case GU_PSM_T16:
			return 2 * width * height;
		case GU_PSM_8888:
		case GU_PSM_T32:
			return 4 * width * height;
		default:
			return 0;
	}
}
void* getStaticVramBuffer(unsigned int width, unsigned int height, unsigned int psm)
{
	unsigned int memSize = getMemorySize(width,height,psm);
	void* result = (void*)staticOffset;
	staticOffset += memSize;
	return result;
}
int running()
{
	return !exitRequest;
}
int exitCallback(int arg1, int arg2, void *common)
{
	exitRequest = 1;
	return 0;
}
int callbackThread(SceSize args, void *argp)
{
	int cbid;
	cbid = sceKernelCreateCallback("Exit Callback", exitCallback, NULL);
	sceKernelRegisterExitCallback(cbid);
	sceKernelSleepThreadCB();
	return 0;
}
int setupCallbacks(void)
{
	int thid = 0;
	thid = sceKernelCreateThread("update_thread", callbackThread, 0x11, 0xFA0, 0, 0);
	if(thid >= 0)
	{
		sceKernelStartThread(thid, 0, 0);
	}
	return thid;
}
void user_warning_fn(png_structp png_ptr, png_const_charp warning_msg)
{
	// ignore PNG warnings
}
int PowerOfTwo(int value)
{
int poweroftwo = 1;
    while (poweroftwo < value ){
		poweroftwo <<= 1;
	}
	return poweroftwo;
}
unsigned short Color8888To5551(unsigned int Color32)
{
unsigned char Red = (Color32);
unsigned short Red16 = Red>>3;
unsigned char Green = (Color32>>8);
unsigned short Green16 = (Green>>3)<<5;
unsigned char Blue = (Color32>>16);
unsigned short Blue16 = (Blue>>3)<<10;
unsigned char Alpha = (Color32>>24);
unsigned short Alpha16 = (Alpha>>3)<<15;
unsigned short Color16 = Red16 | Green16 | Blue16 | Alpha16;
return Color16;
}
unsigned short Color8888To4444(unsigned int Color32)
{
unsigned char Red = (Color32);
unsigned short Red16 = Red>>4;
unsigned char Green = (Color32>>8);
unsigned short Green16 = (Green>>4)<<4;
unsigned char Blue = (Color32>>16);
unsigned short Blue16 = (Blue>>4)<<8;
unsigned char Alpha = (Color32>>24);
unsigned short Alpha16 = (Alpha>>4)<<12;
unsigned short Color16 = Red16 | Green16 | Blue16 | Alpha16;
return Color16;
}
unsigned short Color8888To5650(unsigned int Color32)
{
unsigned char Red = (Color32);
unsigned short Red16 = Red>>3;
unsigned char Green = (Color32>>8);
unsigned short Green16 = (Green>>2)<<5;
unsigned char Blue = (Color32>>16);
unsigned short Blue16 = (Blue>>3)<<11;
//unsigned char Alpha = (Color32>>24);
unsigned short Color16 = Red16 | Green16 | Blue16;
return Color16;
}
struct Vertex
{
	unsigned short u, v;
	unsigned short color;
	short x, y, z;
};
void advancedBlit(int sx, int sy, int sw, int sh, int dx, int dy, int slice)
{
	int start, end;
	// blit maximizing the use of the texture-cache
	for (start = sx, end = sx+sw; start < end; start += slice, dx += slice)
	{
		struct Vertex* vertices = (struct Vertex*)sceGuGetMemory(2 * sizeof(struct Vertex));
		int width = (start + slice) < end ? slice : end-start;
		vertices[0].u = start; vertices[0].v = sy;
		vertices[0].color = 0;
		vertices[0].x = dx; vertices[0].y = dy; vertices[0].z = 0;
		vertices[1].u = start + width; vertices[1].v = sy + sh;
		vertices[1].color = 0;
		vertices[1].x = dx + width; vertices[1].y = dy + sh; vertices[1].z = 0;
		sceGuDrawArray(GU_SPRITES,GU_TEXTURE_16BIT|GU_COLOR_4444|GU_VERTEX_16BIT|GU_TRANSFORM_2D,2,0,vertices);
	}
}
void swizzle_fast(u8* out, const u8* in, unsigned int width, unsigned int height)
{
   unsigned int blockx, blocky;
   unsigned int j;
 
   unsigned int width_blocks = (width / 16);
   unsigned int height_blocks = (height / 8);
 
   unsigned int src_pitch = (width-16)/4;
   unsigned int src_row = width * 8;
 
   const u8* ysrc = in;
   u32* dst = (u32*)out;
 
   for (blocky = 0; blocky < height_blocks; ++blocky)
   {
      const u8* xsrc = ysrc;
      for (blockx = 0; blockx < width_blocks; ++blockx)
      {
         const u32* src = (u32*)xsrc;
         for (j = 0; j < 8; ++j)
         {
            *(dst++) = *(src++);
            *(dst++) = *(src++);
            *(dst++) = *(src++);
            *(dst++) = *(src++);
            src += src_pitch;
         }
         xsrc += 16;
     }
     ysrc += src_row;
   }
}
Image* LoadPng(const char* filename,int ColorMode,int Swizzle,int Vram)
{
    unsigned short *Buffer;
	unsigned short *swizzled_pixels = NULL;
	Image *Image1;
	png_structp png_ptr;
	png_infop info_ptr;
	unsigned int sig_read = 0;
	png_uint_32 width, height;
	int bit_depth, color_type, interlace_type, x, y;
	unsigned int* line;
	FILE *fp;
	int OutBytesPerPixel;
	int Power2Width = 0;
	int Power2Height = 0;
	if(ColorMode == GU_PSM_4444 || ColorMode == GU_PSM_5650 || ColorMode == GU_PSM_5551)OutBytesPerPixel = 2;
	else OutBytesPerPixel = 4;
	if ((fp = fopen(filename, "rb")) == NULL){
            printf("Can't open file %s\n",filename);
            return NULL; 
    }
	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	if (png_ptr == NULL) {
		fclose(fp);
		return NULL;
	}
	png_set_error_fn(png_ptr, (png_voidp) NULL, (png_error_ptr) NULL, user_warning_fn);
	info_ptr = png_create_info_struct(png_ptr);
	if (info_ptr == NULL) {
		fclose(fp);
		png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
		return NULL;
	}
	png_init_io(png_ptr, fp);
	png_set_sig_bytes(png_ptr, sig_read);
	png_read_info(png_ptr, info_ptr);
	png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, int_p_NULL, int_p_NULL);
	png_set_strip_16(png_ptr);
	png_set_packing(png_ptr);
	if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr);
	if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_gray_1_2_4_to_8(png_ptr);
	if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr);
	png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
	line = (unsigned int*) malloc(width * 4);
	if (!line) {
		fclose(fp);
		png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
		return NULL;
	}
	Power2Width = PowerOfTwo(width);
	Power2Height = PowerOfTwo(height);
	Buffer = memalign(16,Power2Width*Power2Height*OutBytesPerPixel);
	for (y = 0; y < height; y++) {
		png_read_row(png_ptr, (unsigned char*) line, png_bytep_NULL);
		for (x = 0; x < width; x++) {
			unsigned int *Buffer32 = (unsigned int*)Buffer;
			unsigned int color32 = line[x];
			unsigned short color16;
			//printf("%d:%d %u ",y,x,color32);
			if(ColorMode == GU_PSM_5551){
				color16 = Color8888To5551(color32);
				Buffer[y*Power2Width+x] = color16;
			}
			else if(ColorMode == GU_PSM_4444){
				color16 = Color8888To4444(color32);
				Buffer[y*Power2Width+x] = color16;
			}
			else if(ColorMode == GU_PSM_5650){
				color16 = Color8888To5650(color32);
				Buffer[y*Power2Width+x] = color16;
			}
			else {
				Buffer32[y*Power2Width+x] = color32;
			}
			//printf("%u \n",Buffer[y*width+x]);
			//printf("%u \n",color16);
		}
	}
	free(line);
	png_read_end(png_ptr, info_ptr);
	png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
	fclose(fp);	
Image1 = malloc(sizeof(Image));
Image1->Width = width;
Image1->Height = height;
Image1->power2width = Power2Width;
Image1->power2height = Power2Height;
swizzled_pixels = memalign(16,Image1->power2height*Image1->power2width*OutBytesPerPixel);
swizzle_fast((u8*)swizzled_pixels,(const u8*)Buffer,Image1->power2width*OutBytesPerPixel,Image1->power2height); 
// 512*2 because swizzle operates in bytes, and each pixel in a 16-bit texture is 2 bytes
sceKernelDcacheWritebackAll();
Image1->ImageData = swizzled_pixels;
free(Buffer);
sceGuFinish();
sceGuSync(0,0);
return Image1;	
}
int main(int argc, char* argv[])
{
	unsigned int i = 0,png = 0;
	
	Image *Image1;
	pspDebugScreenInit();
	setupCallbacks();
	// Setup GU
	void* fbp0 = getStaticVramBuffer(BUF_WIDTH,SCR_HEIGHT,GU_PSM_8888);
	void* fbp1 = getStaticVramBuffer(BUF_WIDTH,SCR_HEIGHT,GU_PSM_8888);
	void* zbp = getStaticVramBuffer(BUF_WIDTH,SCR_HEIGHT,GU_PSM_4444);
	sceGuInit();
	sceGuStart(GU_DIRECT,list);
	sceGuDrawBuffer(GU_PSM_8888,fbp0,BUF_WIDTH);
	sceGuDispBuffer(SCR_WIDTH,SCR_HEIGHT,fbp1,BUF_WIDTH);
	sceGuDepthBuffer(zbp,BUF_WIDTH);
	sceGuOffset(2048 - (SCR_WIDTH/2),2048 - (SCR_HEIGHT/2));
	sceGuViewport(2048,2048,SCR_WIDTH,SCR_HEIGHT);
	sceGuDepthRange(65535,0);
	sceGuScissor(0,0,SCR_WIDTH,SCR_HEIGHT);
	sceGuEnable(GU_SCISSOR_TEST);
	sceGuFrontFace(GU_CW);
	sceGuEnable(GU_TEXTURE_2D);
	sceGuClear(GU_COLOR_BUFFER_BIT|GU_DEPTH_BUFFER_BIT);
	sceGuFinish();
	sceGuSync(0,0);
	sceDisplayWaitVblankStart();
	sceGuDisplay(1);
	
	if((Image1 = LoadPng("2.png",GU_PSM_4444,1,0)) != NULL)png = 1;
	float curr_ms = 1.0f;
	SceCtrlData oldPad;
	oldPad.Buttons = 0;
	sceCtrlSetSamplingCycle(0);
	sceCtrlSetSamplingMode(0);
	u64 last_tick;
	sceRtcGetCurrentTick(&last_tick);
	u32 tick_frequency = sceRtcGetTickResolution();
	int frame_count = 0;
	while(running())
	{
		SceCtrlData pad;
		sceGuStart(GU_DIRECT,list);
		// switch methods if requested
		if(sceCtrlPeekBufferPositive(&pad, 1))
		{
			if (pad.Buttons != oldPad.Buttons)
			{
				if(pad.Buttons & PSP_CTRL_CROSS);
				if(pad.Buttons & PSP_CTRL_CIRCLE);
			}
			oldPad = pad;
		}
		sceGuTexMode(GU_PSM_4444,0,0,1); // 16-bit RGBA
		sceGuTexImage(0,Image1->power2width,Image1->power2height,Image1->power2width,Image1->ImageData); // setup texture as a 512x512 texture, even though the buffer is only 512x272 (480 visible)
		sceGuTexFunc(GU_TFX_REPLACE,GU_TCC_RGBA); // don't get influenced by any vertex colors
		sceGuTexFilter(GU_NEAREST,GU_NEAREST); // point-filtered sampling
		advancedBlit(0,0,Image1->Width,Image1->Height,0,0,32);
		sceGuFinish();
		sceGuSync(0,0);
		float curr_fps = 1.0f / curr_ms;
		pspDebugScreenSetOffset((int)fbp0);
		pspDebugScreenSetXY(0,0);
		pspDebugScreenPrintf("fps: %d.%03d width: %d %d height: %d %d %d %u",(int)curr_fps,(int)((curr_fps-(int)curr_fps) * 1000.0f),Image1->Width,Image1->power2width,Image1->Height,Image1->power2height,png,Image1->ImageData[100+i]);
		
//		sceDisplayWaitVblankStart();
		fbp0 = sceGuSwapBuffers();
		
		if(i>1000)i=0;
		else i++;
		// simple frame rate counter
		++frame_count;
		u64 curr_tick;
		sceRtcGetCurrentTick(&curr_tick);
		if ((curr_tick-last_tick) >= tick_frequency)
		{
			float time_span = ((int)(curr_tick-last_tick)) / (float)tick_frequency;
			curr_ms = time_span / frame_count;
			frame_count = 0;
			sceRtcGetCurrentTick(&last_tick);
		}
	}
	sceGuTerm();
	sceKernelExitGame();
	return 0;
}