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