 |
forums.ps2dev.org Homebrew PS2, PSP & PS3 Development Discussions
|
| View previous topic :: View next topic |
| Author |
Message |
Mr.Modem
Joined: 21 Sep 2005 Posts: 28
|
Posted: Sun Dec 03, 2006 8:01 am Post subject: [Solved] PNG blitting problem |
|
|
I am working on a little program where I need to load large PNG files and blit them on the screen. It seemed like a simple task but somehow screwed up anyway. I had some old code from another project that where supposed to do what I wanted but it turned out it didn't work as expected. The code can successfully load and blit small png images but when the width of the image is larger than 512 the image get distorted. I would be very glad if someone could point if what I have done wrong.
| Code: |
#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;
}
|
EDIT: As you may see the code is based on the sdk blit sample
Last edited by Mr.Modem on Tue Dec 05, 2006 1:09 am; edited 1 time in total |
|
| Back to top |
|
 |
Insert_witty_name
Joined: 10 May 2006 Posts: 376
|
Posted: Mon Dec 04, 2006 5:47 am Post subject: |
|
|
| Maximum texture size is 512x512. |
|
| Back to top |
|
 |
chp
Joined: 23 Jun 2004 Posts: 313
|
Posted: Mon Dec 04, 2006 6:55 pm Post subject: |
|
|
If you want to blit textures larger than 512 pixels you have to offset into the texture and setup proper texture block widths to skip the unseen data, since the hardware (and sceGu) does not handle texture larger than this. If you want to address the first 512x512 block of a 1024x1024 texture you set something like this: | Code: | | sceGuTexImage(0,512,512,1024,texture); |
_________________ GE Dominator |
|
| Back to top |
|
 |
Mr.Modem
Joined: 21 Sep 2005 Posts: 28
|
Posted: Tue Dec 05, 2006 12:54 am Post subject: |
|
|
| Thanks guys! |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|