[SOLVED] TV Out - garbage on screen?

Discuss the development of new homebrew software, tools and libraries.

Moderators: cheriff, TyRaNiD

Post Reply
MysticWhiteDragon
Posts: 30
Joined: Thu Feb 16, 2006 8:46 am

[SOLVED] TV Out - garbage on screen?

Post by MysticWhiteDragon »

When I draw an image onto the PSP screen it draws correctly. However, when I draw the image to the TV whether it be progressive or interlaced I get black lines on the bottom of the screen and pink on the top of the screen. Any idea what could be causing that? I do have sceKernelDcacheWritebackInvalidateAll(); before I draw to the screen so I know that's not the problem.

Also in the dvemgr.prx I have this added to allow 4MB VRAM: sceGeEdramSetSize(4*1024*1024);

PSP
SCREEN_WIDTH = 480;
SCREEN_HEIGHT = 272;
BUFFER_WIDTH = 512;

TV
SCREEN_WIDTH = 720;
SCREEN_HEIGHT = 480;
BUFFER_WIDTH = 768;

I am wondering if it has something to do with my flipScreen function.

Code: Select all

void flipScreen()
{
	if(TVMode == 2 || TVMode == 1)
	{
		sceDisplayWaitVblankStart();
		sceGuCopyImage&#40;GU_PSM_8888,0,0,SCREEN_WIDTH,SCREEN_HEIGHT>>1,BUFFER_WIDTH<<1,&#40;void*&#41;0x44000C00,0,0,BUFFER_WIDTH,&#40;void*&#41;0x44200000&#41;;
		sceGuCopyImage&#40;GU_PSM_8888,0,0,SCREEN_WIDTH,SCREEN_HEIGHT>>1,BUFFER_WIDTH<<1,&#40;void*&#41;0x44000000,0,0,BUFFER_WIDTH,&#40;void*&#41;0x442C4800&#41;;
	&#125;
	else if&#40;TVMode == 3&#41;
	&#123;
		sceDisplayWaitVblankStart&#40;&#41;;
		sceGuCopyImage&#40;GU_PSM_8888,0,0,SCREEN_WIDTH,SCREEN_HEIGHT,BUFFER_WIDTH,&#40;void*&#41;0x44000000,0,0,BUFFER_WIDTH,&#40;void*&#41;0x44200000&#41;;
	&#125;

	sceGuFinish&#40;&#41;;
	sceGuSync&#40;0,0&#41;;

	if&#40;TVMode == 0&#41;
	&#123;
		sceDisplayWaitVblankStart&#40;&#41;;
		fbp0 = sceGuSwapBuffers&#40;&#41;;
	&#125;

	sceKernelDcacheWritebackInvalidateAll&#40;&#41;;
	sceGuStart&#40;GU_DIRECT,dList&#41;;
&#125;
Last edited by MysticWhiteDragon on Mon Dec 15, 2008 1:00 pm, edited 1 time in total.
J.F.
Posts: 2906
Joined: Sun Feb 22, 2004 11:41 am

Post by J.F. »

You should read more old threads. Using the TV out has been covered for quite some time. Here's one of the first places where dvemgr was modified for 4M and some sample code for doing TV out done.

http://forums.ps2dev.org/viewtopic.php?p=66568#66568
MysticWhiteDragon
Posts: 30
Joined: Thu Feb 16, 2006 8:46 am

Post by MysticWhiteDragon »

Thanks for the reply.

I always search previous threads before posting, and managed to get the cursortest example to compile from the thread you mentioned. That is how I found out to copy the image to the location 0x44200000. I am using a custom graphics library that allows scaling and such, which is why I was asking for some help.
MysticWhiteDragon
Posts: 30
Joined: Thu Feb 16, 2006 8:46 am

Post by MysticWhiteDragon »

After further digging into the code and some searching on the the internet is seems that there is a problem drawing an alpha image onto the screen when copying the framebuffer using sceGuCopyImage. I used sceKernelDcacheWritebackInvalidateAll() where needed as listed on other posts and sites.
J.F.
Posts: 2906
Joined: Sun Feb 22, 2004 11:41 am

Post by J.F. »

Copying the frame is only needed for interlaced mode. If you look at the last cursortest arc in the thread you'll see that just the regular sceGuSwapBuffers is used for LCD and non-interlaced TV. Although blitScreenToFrameBuf takes into account interlaced or non-laced, it's not used to update the screen in non-laced mode by the example. Also, interlaced (by nature of how graphics.c works) waits for outstanding GPU work to be done before doing the copies. That's probably where your code is going wrong - you aren't finishing and syncing before doing the copy.

Perhaps you should look at the video code in Basilisk II (there's a thread on that here). You'll see how I do the screen drawing in such a way as to handle various blits and even the danzef OSK with LCD or TV. That might be a little better than the cursortest, which was pretty old and basic.
MysticWhiteDragon
Posts: 30
Joined: Thu Feb 16, 2006 8:46 am

Post by MysticWhiteDragon »

After several attempts I still am having problems. Below is the code that I am using.

main.c

Code: Select all

#include <pspkernel.h>
#include <pspctrl.h>
#include <pspdisplay.h>
#include <pspdebug.h>
#include <pspkernel.h>
#include <pspsdk.h>
#include <psprtc.h>
#include <string.h>
#include <stdio.h>
#include "graphics.h"
#include "system.h"

#define printf pspDebugScreenPrintf

/* ========================= START PSP CALLBACKS ========================= */
PSP_MODULE_INFO&#40;"Test",0,1,1&#41;;
PSP_MAIN_THREAD_ATTR&#40;THREAD_ATTR_USER&#41;;//|THREAD_ATTR_VFPU&#41;; //User Mode
//PSP_MAIN_THREAD_ATTR&#40;0&#41;; //Kernel Mode
//PSP_MAIN_THREAD_STACK_SIZE_KB&#40;32&#41;;

/* Exit callback */
int exit_callback&#40;int arg1,int arg2,void *common&#41;
&#123;
	pspDveMgrSetVideoOut&#40;0,0,480,272,1,15,0&#41;;
	sceKernelDelayThread&#40;1 * 1000 * 1000&#41;;
	sceKernelExitGame&#40;&#41;;
	return 0;
&#125;

/* Callback thread */
int CallbackThread&#40;SceSize args,void *argp&#41;
&#123;
	int cbid;

	cbid = sceKernelCreateCallback&#40;"Exit Callback",exit_callback,NULL&#41;;
	sceKernelRegisterExitCallback&#40;cbid&#41;;

	sceKernelSleepThreadCB&#40;&#41;;

	return 0;
&#125;

/* Sets up the callback thread and returns its thread id */
int SetupCallbacks&#40;void&#41;
&#123;
	int thid = 0;

	thid = sceKernelCreateThread&#40;"update_thread",CallbackThread,0x11,0xFA0,0,0&#41;;
	if&#40;thid >= 0&#41;//
	&#123;
		sceKernelStartThread&#40;thid,0,0&#41;;
	&#125;

	return thid;
&#125;
/* =========================  END PSP CALLBACKS  ========================= */

void intro&#40;&#41;
&#123;
	int inum = 1,a,exit;
	char pngfile&#91;20&#93;;
	Image* intro;
	u32 introTickResolution;
	u64 introTickNow;
	u64 introTickLast;
	SceCtrlData pad;

	while&#40;inum > 0&#41;
	&#123;
		exit = 0;

		sprintf&#40;pngfile,"intro/intro%i.png",inum&#41;;

		if&#40;FileExists&#40;pngfile&#41; == 1&#41;
		&#123;
			intro = loadImage&#40;pngfile&#41;;

			// Fade In
			sceRtcGetCurrentTick&#40;&introTickLast&#41;;
			introTickResolution = sceRtcGetTickResolution&#40;&#41;;
			a = 0;
			while&#40;&#40;a < 255&#41; && &#40;exit == 0&#41;&#41;
			&#123;
				sceCtrlReadBufferPositive&#40;&pad,1&#41;;
				if&#40;pad.Buttons & &#40;PSP_CTRL_START|PSP_CTRL_CROSS|PSP_CTRL_CIRCLE&#41;&#41; &#123; exit = 1; break; &#125;
				sceRtcGetCurrentTick&#40;&introTickNow&#41;;
				a = &#40;&#40;introTickNow - introTickLast&#41; / &#40;&#40;float&#41;introTickResolution&#41;&#41; * 255;
				if&#40;a < 0&#41; &#123; a = 0; &#125;
				if&#40;a > 255&#41; &#123; a = 255; &#125;
				drawImagePart&#40;intro,0,0,0,0,intro->w,intro->h,720,480,0,0&#41;;
				ScreenFade&#40;0,0,0,255 - a&#41;;
				flipScreen&#40;&#41;;
			&#125;

			// Pause Intro Logo
			sceRtcGetCurrentTick&#40;&introTickLast&#41;;
			introTickResolution = sceRtcGetTickResolution&#40;&#41;;
			a = 0;
			while&#40;&#40;a < 767&#41; && &#40;exit == 0&#41;&#41;
			&#123;
				sceCtrlReadBufferPositive&#40;&pad,1&#41;;
				if&#40;pad.Buttons & &#40;PSP_CTRL_START|PSP_CTRL_CROSS|PSP_CTRL_CIRCLE&#41;&#41; &#123; exit = 1; break; &#125;
				sceRtcGetCurrentTick&#40;&introTickNow&#41;;
				a = &#40;&#40;introTickNow - introTickLast&#41; / &#40;&#40;float&#41;introTickResolution&#41;&#41; * 255;
				if&#40;a < 0&#41; &#123; a = 0; &#125;
			&#125;

			// Fade Out
			sceRtcGetCurrentTick&#40;&introTickLast&#41;;
			introTickResolution = sceRtcGetTickResolution&#40;&#41;;
			a = 0;
			while&#40;&#40;a < 255&#41; && &#40;exit == 0&#41;&#41;
			&#123;
				sceCtrlReadBufferPositive&#40;&pad,1&#41;;
				if&#40;pad.Buttons & &#40;PSP_CTRL_START|PSP_CTRL_CROSS|PSP_CTRL_CIRCLE&#41;&#41; &#123; exit = 1; break; &#125;
				sceRtcGetCurrentTick&#40;&introTickNow&#41;;
				a = &#40;&#40;introTickNow - introTickLast&#41; / &#40;&#40;float&#41;introTickResolution&#41;&#41; * 255;
				if&#40;a < 0&#41; &#123; a = 0; &#125;
				if&#40;a > 255&#41; &#123; a = 255; &#125;
				drawImagePart&#40;intro,0,0,0,0,intro->w,intro->h,720,480,0,0&#41;;
				ScreenFade&#40;0,0,0,a&#41;;
				flipScreen&#40;&#41;;
			&#125;

			freeImage&#40;intro&#41;;
		&#125;
		else
		&#123;
			inum = -1;
		&#125;

		inum++;
	&#125;
&#125;

int main&#40;int argc,char **argv&#41;
&#123;
	SceCtrlData pad;

	pspDebugScreenInit&#40;&#41;;
	SetupCallbacks&#40;&#41;;

	SceUID mod = pspSdkLoadStartModule&#40;"dvemgr.prx",PSP_MEMORY_PARTITION_KERNEL&#41;;
	if&#40;mod >= 0&#41;
	&#123;
		printf&#40;"X &#58; Component &#40;Progressive&#41;\n"&#41;;
		printf&#40;"O &#58; Component &#40;Interlaced&#41;\n"&#41;;
		printf&#40;"&#91;&#93;&#58; Composite\n"&#41;;
		printf&#40;"/\\&#58; PSP LCD\n"&#41;;
		while&#40;1&#41;
		&#123;
			 sceCtrlReadBufferPositive&#40;&pad,1&#41;;
			 if&#40;pad.Buttons & PSP_CTRL_CROSS&#41;    &#123; setVideoMode&#40;3&#41;; break; &#125;
			 if&#40;pad.Buttons & PSP_CTRL_CIRCLE&#41;   &#123; setVideoMode&#40;2&#41;; break; &#125;
			 if&#40;pad.Buttons & PSP_CTRL_SQUARE&#41;   &#123; setVideoMode&#40;1&#41;; break; &#125;
			 if&#40;pad.Buttons & PSP_CTRL_TRIANGLE&#41; &#123; setVideoMode&#40;0&#41;; break; &#125;
			 if&#40;pad.Buttons & PSP_CTRL_RTRIGGER&#41; &#123; break; &#125;
		&#125;
	&#125;


	initGraphics&#40;&#41;;

	intro&#40;&#41;;

//	while&#40;1&#41;
//	&#123;
//		
//	&#125;

	pspDveMgrSetVideoOut&#40;0,0,480,272,1,15,0&#41;;
	sceKernelDelayThread&#40;1 * 1000 * 1000&#41;;
	sceKernelExitGame&#40;&#41;;
	return 0;
&#125;
graphics.c

Code: Select all

#include <string.h>
#include <stdlib.h>
#include <pspdisplay.h>
#include <pspgu.h>
#include <pspgum.h>
#include <pspkernel.h>
#include <png.h>
#include "graphics.h"

unsigned int __attribute__&#40;&#40;aligned&#40;16&#41;&#41;&#41; dList&#91;262144&#93;;

int dispNumber;
u32 *vramBase = &#40;u32*&#41;&#40;0x40000000|0x04000000&#41;;

void *fbp0 = NULL;
void *fbp1;
void *zbp;

int SCREEN_WIDTH  = 480;
int SCREEN_HEIGHT = 272;
int BUFFER_WIDTH  = 512;
int interlaced = 0;
int TVMode = 0;

int SCREEN_TOP = 0;
int SCREEN_BOTTOM = 0;
int SCREEN_LEFT = 0;
int SCREEN_RIGHT = 0;

void initGraphics&#40;&#41;
&#123;
	dispNumber = 0;

	fbp0 = &#40;void*&#41;0;
	fbp1 = &#40;void*&#41;&#40;BUFFER_WIDTH * SCREEN_HEIGHT * 4&#41;;
	zbp  = &#40;void*&#41;&#40;BUFFER_WIDTH * SCREEN_HEIGHT * 8&#41;;

	sceGuInit&#40;&#41;;
	sceGuStart&#40;GU_DIRECT,dList&#41;;

	if&#40;interlaced == 1&#41;
	&#123;
		sceGuDrawBuffer&#40;GU_PSM_8888,fbp0,BUFFER_WIDTH&#41;;
		sceGuDispBuffer&#40;SCREEN_WIDTH,SCREEN_HEIGHT,fbp0,BUFFER_WIDTH&#41;;
		sceGuDepthBuffer&#40;fbp1,BUFFER_WIDTH&#41;;
	&#125;
	else
	&#123;
		sceGuDrawBuffer&#40;GU_PSM_8888,fbp0,BUFFER_WIDTH&#41;;
		sceGuDispBuffer&#40;SCREEN_WIDTH,SCREEN_HEIGHT,fbp1,BUFFER_WIDTH&#41;;
		sceGuDepthBuffer&#40;zbp,BUFFER_WIDTH&#41;;
	&#125;

	sceGuOffset&#40;2048 - &#40;&#40;SCREEN_WIDTH - SCREEN_LEFT - SCREEN_RIGHT&#41;/2&#41;,2048 - &#40;&#40;SCREEN_HEIGHT - SCREEN_TOP - SCREEN_BOTTOM&#41;/2&#41;&#41;;
	sceGuViewport&#40;2048 + SCREEN_LEFT,2048 + SCREEN_TOP,SCREEN_WIDTH - SCREEN_LEFT - SCREEN_RIGHT,SCREEN_HEIGHT - SCREEN_TOP - SCREEN_BOTTOM&#41;;
	sceGuDepthRange&#40;65535,0&#41;;

	sceGuScissor&#40;0,0,SCREEN_WIDTH,SCREEN_HEIGHT&#41;;
	sceGuEnable&#40;GU_SCISSOR_TEST&#41;;
	sceGuFrontFace&#40;GU_CCW&#41;;
	sceGuShadeModel&#40;GU_SMOOTH&#41;;
	sceGuAlphaFunc&#40;GU_GREATER,0,0xff&#41;;
	sceGuEnable&#40;GU_CULL_FACE&#41;;
	sceGuEnable&#40;GU_DEPTH_TEST&#41;;
	sceGuDepthFunc&#40;GU_GEQUAL&#41;;
	sceGuEnable&#40;GU_ALPHA_TEST&#41;;
	sceGuEnable&#40;GU_TEXTURE_2D&#41;;
//sceGuEnable&#40;GU_CLIP_PLANES&#41;;

	sceGuEnable&#40;GU_BLEND&#41;;
	sceGuBlendFunc&#40;GU_ADD,GU_SRC_ALPHA,GU_ONE_MINUS_SRC_ALPHA,0,0&#41;;

	sceGuTexMode&#40;GU_PSM_8888,0,0,1&#41;;
	sceGuTexFunc&#40;GU_TFX_REPLACE,GU_TCC_RGBA&#41;;
	sceGuTexFilter&#40;GU_LINEAR,GU_LINEAR&#41;;
	sceGuTexWrap&#40;GU_CLAMP,GU_CLAMP&#41;;
	sceGuTexScale&#40;1,1&#41;;
	sceGuTexOffset&#40;0,0&#41;;
	sceGuAmbientColor&#40;0xffffffff&#41;;

	sceGuFinish&#40;&#41;;
	sceGuSync&#40;0,0&#41;;
	sceDisplayWaitVblankStart&#40;&#41;;
	sceGuDisplay&#40;1&#41;;

	if&#40;TVMode > 0&#41;
	&#123;
//		sceDisplaySetFrameBuf&#40;&#40;void*&#41;0x44200000,BUFFER_WIDTH,PSP_DISPLAY_PIXEL_FORMAT_8888,PSP_DISPLAY_SETBUF_IMMEDIATE&#41;;
		sceDisplaySetFrameBuf&#40;&#40;void*&#41;0x44200000,BUFFER_WIDTH,PSP_DISPLAY_PIXEL_FORMAT_8888,PSP_DISPLAY_SETBUF_NEXTFRAME&#41;;
	&#125;

	sceKernelDcacheWritebackInvalidateAll&#40;&#41;;
	sceGuStart&#40;GU_DIRECT,dList&#41;;

	sceGuClearColor&#40;0&#41;;
	sceGuClearDepth&#40;0&#41;;
	sceGuClear&#40;GU_COLOR_BUFFER_BIT|GU_DEPTH_BUFFER_BIT&#41;;

	sceGumMatrixMode&#40;GU_PROJECTION&#41;;
	sceGumLoadIdentity&#40;&#41;;
	sceGumOrtho&#40;0,720,480,0,-1,1&#41;;

	sceGumMatrixMode&#40;GU_VIEW&#41;;
	sceGumLoadIdentity&#40;&#41;;

	sceGumMatrixMode&#40;GU_MODEL&#41;;
	sceGumLoadIdentity&#40;&#41;;
&#125;

void endGraphics&#40;&#41;
&#123;
	sceGuTerm&#40;&#41;;
&#125;

void setVideoMode&#40;int mode&#41;
&#123;
	TVMode = mode;

	if&#40;TVMode > 0&#41;
	&#123;
		SCREEN_TOP = 0; SCREEN_BOTTOM = 0; SCREEN_LEFT = 0; SCREEN_RIGHT = 0;
//		SCREEN_TOP = 104; SCREEN_BOTTOM = 104; SCREEN_LEFT = 120; SCREEN_RIGHT = 120; // Test
	&#125;
	else
	&#123;
		SCREEN_TOP = 0; SCREEN_BOTTOM = 0; SCREEN_LEFT = 0; SCREEN_RIGHT = 0;
	&#125;

	switch&#40;mode&#41;
	&#123;
		case 3&#58;
			pspDveMgrSetVideoOut&#40;0,0x1d2,720,480,1,15,0&#41;;
			SCREEN_WIDTH = 720;
			SCREEN_HEIGHT = 480;
			BUFFER_WIDTH = 768;
			interlaced = 0;
			break;
		case 2&#58;
			pspDveMgrSetVideoOut&#40;0,0x1d1,720,503,1,15,0&#41;;
			SCREEN_WIDTH = 720;
			SCREEN_HEIGHT = 480;
			BUFFER_WIDTH = 768;
			interlaced = 1;
			break;
		case 1&#58;
			pspDveMgrSetVideoOut&#40;2,0x1d1,720,503,1,15,0&#41;;
			SCREEN_WIDTH = 720;
			SCREEN_HEIGHT = 480;
			BUFFER_WIDTH = 768;
			interlaced = 1;
			break;
		case 0&#58;
		default&#58;
			pspDveMgrSetVideoOut&#40;0,0,480,272,1,15,0&#41;;
			SCREEN_WIDTH = 480;
			SCREEN_HEIGHT = 272;
			BUFFER_WIDTH = 512;
			interlaced = 0;
			break;
	&#125;
&#125;

void flipScreen&#40;&#41;
&#123;
	sceGuFinish&#40;&#41;;
	sceGuSync&#40;0,0&#41;;

	if&#40;interlaced&#41;
	&#123;
		sceKernelDcacheWritebackInvalidateAll&#40;&#41;;
		sceGuStart&#40;GU_DIRECT,dList&#41;;

		sceDisplayWaitVblankStart&#40;&#41;;
		sceGuCopyImage&#40;GU_PSM_8888,0,0,SCREEN_WIDTH,SCREEN_HEIGHT>>1,BUFFER_WIDTH<<1,&#40;void*&#41;0x44000C00,0,0,BUFFER_WIDTH,&#40;void*&#41;0x44200000&#41;;
		sceGuTexSync&#40;&#41;;
		sceGuCopyImage&#40;GU_PSM_8888,0,0,SCREEN_WIDTH,SCREEN_HEIGHT>>1,BUFFER_WIDTH<<1,&#40;void*&#41;0x44000000,0,0,BUFFER_WIDTH,&#40;void*&#41;0x442C4800&#41;;
		sceGuTexSync&#40;&#41;;

		sceGuFinish&#40;&#41;;
		sceGuSync&#40;0,0&#41;;
	&#125;
	else
	&#123;
		sceDisplayWaitVblankStart&#40;&#41;;
		fbp0 = sceGuSwapBuffers&#40;&#41;;
		dispNumber ^= 1;
	&#125;

	sceKernelDcacheWritebackInvalidateAll&#40;&#41;;
	sceGuStart&#40;GU_DIRECT,dList&#41;;

	sceGumMatrixMode&#40;GU_MODEL&#41;;
	sceGumLoadIdentity&#40;&#41;;
&#125;

void clearScreen&#40;&#41;
&#123;
	sceGuClearColor&#40;0&#41;;
	sceGuClearDepth&#40;0&#41;;
	sceGuClear&#40;GU_COLOR_BUFFER_BIT|GU_DEPTH_BUFFER_BIT&#41;;
&#125;

void freeImage&#40;Image* image&#41;
&#123;
	free&#40;image->data&#41;;
	free&#40;image&#41;;
&#125;

static int Power2&#40;int dimension&#41;
&#123;
	int b = dimension;
	int n;
	for&#40;n = 0;b != 0;n++&#41; b >>= 1;
	b = 1 << n;
	if&#40;b == 2 * dimension&#41; b >>= 1;
	return b;
&#125;

void swizzleImage&#40;Image* image&#41;
&#123;
	unsigned int pitch = image->tW * image->colorMode;
	unsigned int i,j;
	unsigned int rowblocks = &#40;pitch / 16&#41;;
	long size = pitch * image->tH;

	unsigned char* out = &#40;unsigned char*&#41;malloc&#40;size * sizeof&#40;unsigned char&#41;&#41;;

	for&#40;j = 0;j < image->tH;j++&#41;
	&#123;
		for&#40;i = 0;i < pitch;i++&#41;
		&#123;
			unsigned int blockx = i / 16;
			unsigned int blocky = j / 8;

			unsigned int x = &#40;i - blockx * 16&#41;;
			unsigned int y = &#40;j - blocky * 8&#41;;
			unsigned int block_index = blockx + &#40;&#40;blocky&#41; * rowblocks&#41;;
			unsigned int block_address = block_index * 16 * 8;

			out&#91;block_address + x + y * 16&#93; = image->data&#91;i + j * pitch&#93;;
		&#125;
	&#125;
	free&#40;image->data&#41;;
	image->data = out;
&#125;

void unswizzleImage&#40;Image* image&#41;
&#123;
	unsigned int pitch = image->tW * image->colorMode;
	unsigned int i,j;
	unsigned int rowblocks = &#40;pitch / 16&#41;;
	long size = image->tW * image->tH;

	unsigned char* out = &#40;unsigned char*&#41;malloc&#40;size&#41;;

	for&#40;j = 0;j < image->h;j++&#41;
	&#123;
		for&#40;i = 0;i < pitch;i++&#41;
		&#123;
			unsigned int blockx = i / 16;
			unsigned int blocky = j / 8;

			unsigned int x = &#40;i - blockx * 16&#41;;
			unsigned int y = &#40;j - blocky * 8&#41;;
			unsigned int block_index = blockx + &#40;&#40;blocky&#41; * rowblocks&#41;;
			unsigned int block_address = block_index * 16 * 8;

			out&#91;i+j*pitch&#93; = image->data&#91;block_address + x + y * 16&#93;;
		&#125;
	&#125;
	free&#40;image->data&#41;;
	image->data = out;
&#125;

Image* createImage&#40;int width,int height&#41;
&#123;
	Image* image = &#40;Image*&#41;malloc&#40;sizeof&#40;Image&#41;&#41;;
	if&#40;!image&#41; return NULL;
	image->w = width;
	image->h = height;
	image->tW = Power2&#40;width&#41;;
	image->tH = Power2&#40;height&#41;;
	image->data = &#40;unsigned char*&#41;malloc&#40;image->tW * image->tH * sizeof&#40;u32&#41;&#41;;
	if&#40;!image->data&#41; return NULL;
	memset&#40;image->data,0,image->tW * image->tH * sizeof&#40;u32&#41;&#41;;
	return image;
&#125;

void clearImage&#40;Image* image,u32 color&#41;
&#123;
	int i;
	int size = image->tW * image->tH;
	u32* data = &#40;u32*&#41;image->data;
	for&#40;i = 0;i < size;i++,data++&#41; *data = color;
&#125;

Image* loadImage&#40;const char fileName&#91;&#93;&#41;
&#123;
	Image* image = NULL;

	png_structp pngPtr;
	png_infop infoPtr;
	unsigned int sigRead = 0;
	png_uint_32 width,height;
	int bitDepth,colorType,interlaceType,x,y;
	u32* line;
	FILE *fileIn;

	fileIn = fopen&#40;fileName,"rb"&#41;;
	if&#40;fileIn == NULL&#41; return NULL;

	pngPtr = png_create_read_struct&#40;PNG_LIBPNG_VER_STRING,NULL,NULL,NULL&#41;;
	if&#40;pngPtr == NULL&#41; &#123; fclose&#40;fileIn&#41;; return NULL; &#125;

	png_set_error_fn&#40;pngPtr,&#40;png_voidp&#41;NULL,&#40;png_error_ptr&#41;NULL,NULL&#41;;
	infoPtr = png_create_info_struct&#40;pngPtr&#41;;
	if&#40;infoPtr == NULL&#41;
	&#123;
		fclose&#40;fileIn&#41;;
		png_destroy_read_struct&#40;&pngPtr,png_infopp_NULL,png_infopp_NULL&#41;;
		return NULL;
	&#125;

	png_init_io&#40;pngPtr,fileIn&#41;;
	png_set_sig_bytes&#40;pngPtr,sigRead&#41;;
	png_read_info&#40;pngPtr,infoPtr&#41;;
	png_get_IHDR&#40;pngPtr,infoPtr,&width,&height,&bitDepth,&colorType,&interlaceType,int_p_NULL,int_p_NULL&#41;;

	if&#40;width > 512 || height > 512&#41;
	&#123;
		fclose&#40;fileIn&#41;;
		png_destroy_read_struct&#40;&pngPtr,png_infopp_NULL,png_infopp_NULL&#41;;
		return NULL;
	&#125;

	image = &#40;Image*&#41;malloc&#40;sizeof&#40;Image&#41;&#41;;
	if&#40;image == NULL&#41; return NULL;

	image->w = width;
	image->h = height;
	image->tW = Power2&#40;width&#41;;
	image->tH = Power2&#40;height&#41;;
	png_set_strip_16&#40;pngPtr&#41;;
	png_set_packing&#40;pngPtr&#41;;

	if&#40;colorType == PNG_COLOR_TYPE_PALETTE&#41; png_set_palette_to_rgb&#40;pngPtr&#41;;
	if&#40;colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8&#41; png_set_gray_1_2_4_to_8&#40;pngPtr&#41;;
	if&#40;png_get_valid&#40;pngPtr,infoPtr,PNG_INFO_tRNS&#41;&#41; png_set_tRNS_to_alpha&#40;pngPtr&#41;;

	png_set_filler&#40;pngPtr,0xff,PNG_FILLER_AFTER&#41;;

	image->data = &#40;unsigned char*&#41;malloc&#40;image->tW * image->tH * sizeof&#40;u32&#41;&#41;;

	if&#40;!image->data&#41;
	&#123;
		fclose&#40;fileIn&#41;;
		png_destroy_read_struct&#40;&pngPtr,png_infopp_NULL,png_infopp_NULL&#41;;
		free&#40;image&#41;;
		return NULL;
	&#125;

	line = &#40;u32*&#41;malloc&#40;width * 4&#41;;

	if&#40;!line&#41;
	&#123;
		fclose&#40;fileIn&#41;;
		png_destroy_read_struct&#40;&pngPtr,png_infopp_NULL,png_infopp_NULL&#41;;
		return NULL;
	&#125;

	u32* data = &#40;u32*&#41;image->data;

	for&#40;y = 0;y < height;y++&#41;
	&#123;
		png_read_row&#40;pngPtr,&#40;u8*&#41;line,png_bytep_NULL&#41;;

		for&#40;x = 0;x < width;x++&#41;
		&#123;
			u32 color = line&#91;x&#93;;
			data&#91;x + y * image->tW&#93; = color;
		&#125;
	&#125;

	image->colorMode = 4;

	free&#40;line&#41;;
	png_read_end&#40;pngPtr,infoPtr&#41;;
	png_destroy_read_struct&#40;&pngPtr,&infoPtr,png_infopp_NULL&#41;;
	fclose&#40;fileIn&#41;;

	swizzleImage&#40;image&#41;;

	return image;
&#125;

void drawImagePart&#40;Image* image,int sx,int sy,int dx,int dy,int sw,int sh,int dw,int dh,int flip,float rads&#41;
&#123;
	Vertex *v = &#40;Vertex*&#41;sceGuGetMemory&#40;4 * sizeof&#40;Vertex&#41;&#41;;

	float l,t,r,b;

	sceGumPushMatrix&#40;&#41;;
	&#123;
		ScePspFVector3 pos=&#123; dx + dw / 2,dy + dh / 2,0&#125;;
		sceGumTranslate&#40;&pos&#41;;
		sceGumRotateZ&#40;rads&#41;;

		if&#40;&#40;image->tW <= 512&#41; && &#40;image->tH <= 512&#41;&#41;
		&#123;
			l = &#40;float&#41;&#40;sx&#41; / &#40;float&#41;&#40;image->tW&#41;;
			t = &#40;float&#41;&#40;sy&#41; / &#40;float&#41;&#40;image->tH&#41;;
			r = &#40;float&#41;&#40;sx+sw&#41; / &#40;float&#41;&#40;image->tW&#41;;
			b = &#40;float&#41;&#40;sy+sh&#41; / &#40;float&#41;&#40;image->tH&#41;;
			sceGuTexImage&#40;0,image->tW,image->tH,image->tW,image->data&#41;;
		&#125;
		else
		&#123;
			l = &#40;float&#41;&#40;sx % 16&#41; / 512;
			t = &#40;float&#41;&#40;sy % 16&#41; / 512;
			r = &#40;float&#41;&#40;sw + &#40;sx % 16&#41;&#41; / 512;
			b = &#40;float&#41;&#40;sh + &#40;sy % 16&#41;&#41; / 512;
			sceGuTexImage&#40;0,512,512,image->tW,image->data + &#40;&#40;sx / 16&#41; + &#40;&#40;image->tW / 16&#41; * &#40;sy / 8&#41;&#41;&#41; * 128&#41;;
		&#125;
		
		switch&#40;flip&#41;
		&#123;
			case 3&#58; // HV Flip
				v&#91;0&#93;.u = r; v&#91;0&#93;.v = b;
				v&#91;1&#93;.u = r; v&#91;1&#93;.v = t;
				v&#91;2&#93;.u = l; v&#91;2&#93;.v = b;
				v&#91;3&#93;.u = l; v&#91;3&#93;.v = t;
				break;
			case 2&#58; // V Flip
				v&#91;0&#93;.u = l; v&#91;0&#93;.v = b;
				v&#91;1&#93;.u = l; v&#91;1&#93;.v = t;
				v&#91;2&#93;.u = r; v&#91;2&#93;.v = b;
				v&#91;3&#93;.u = r; v&#91;3&#93;.v = t;
				break;;
			case 1&#58; // H Flip
				v&#91;0&#93;.u = r; v&#91;0&#93;.v = t;
				v&#91;1&#93;.u = r; v&#91;1&#93;.v = b;
				v&#91;2&#93;.u = l; v&#91;2&#93;.v = t;
				v&#91;3&#93;.u = l; v&#91;3&#93;.v = b;
				break;
			case 0&#58; // No Flip
			default&#58;
				v&#91;0&#93;.u = l; v&#91;0&#93;.v = t;
				v&#91;1&#93;.u = l; v&#91;1&#93;.v = b;
				v&#91;2&#93;.u = r; v&#91;2&#93;.v = t;
				v&#91;3&#93;.u = r; v&#91;3&#93;.v = b;
				break;
		&#125;

		v&#91;0&#93;.color = 0; v&#91;0&#93;.x = -dw / 2; v&#91;0&#93;.y = -dh / 2; v&#91;0&#93;.z = 0;
		v&#91;1&#93;.color = 0; v&#91;1&#93;.x = -dw / 2; v&#91;1&#93;.y =  dh / 2; v&#91;1&#93;.z = 0;
		v&#91;2&#93;.color = 0; v&#91;2&#93;.x =  dw / 2; v&#91;2&#93;.y = -dh / 2; v&#91;2&#93;.z = 0;
		v&#91;3&#93;.color = 0; v&#91;3&#93;.x =  dw / 2; v&#91;3&#93;.y =  dh / 2; v&#91;3&#93;.z = 0;

		sceGumDrawArray&#40;GU_TRIANGLE_STRIP,GU_COLOR_8888|GU_TEXTURE_32BITF|GU_VERTEX_32BITF|GU_TRANSFORM_3D,4,0,v&#41;;
	&#125;
	sceGumPopMatrix&#40;&#41;;
&#125;

void ScreenFade&#40;u8 r,u8 g,u8 b,u8 a&#41;
&#123;
	sceGuDisable&#40;GU_DEPTH_TEST&#41;;
	sceGuDisable&#40;GU_TEXTURE_2D&#41;;

	sceGumPushMatrix&#40;&#41;;
	&#123;
		Vertexx* v = &#40;Vertexx*&#41;sceGuGetMemory&#40;2 * sizeof&#40;Vertexx&#41;&#41;;

		v&#91;0&#93;.color = GU_RGBA&#40;r,g,b,a&#41;; v&#91;0&#93;.x =   0; v&#91;0&#93;.y =   0; v&#91;0&#93;.z = 0;
		v&#91;1&#93;.color = GU_RGBA&#40;r,g,b,a&#41;; v&#91;1&#93;.x = 720; v&#91;1&#93;.y = 480; v&#91;1&#93;.z = 0;

		sceGumDrawArray&#40;GU_SPRITES,GU_COLOR_8888|GU_VERTEX_32BITF|GU_TRANSFORM_3D,2,0,v&#41;;
	&#125;
	sceGumPopMatrix&#40;&#41;;

	sceGuEnable&#40;GU_TEXTURE_2D&#41;;
	sceGuEnable&#40;GU_DEPTH_TEST&#41;;
&#125;
graphics.h

Code: Select all

#ifndef GRAPHICS_H
#define GRAPHICS_H

#include <psptypes.h>

#define RGB&#40;r,g,b&#41;    &#40;&#40;r&#41; | &#40;&#40;g&#41;<<8&#41; | &#40;&#40;b&#41;<<16&#41; | &#40;0xff<<24&#41;&#41;
#define RGBA&#40;r,g,b,a&#41; &#40;&#40;r&#41; | &#40;&#40;g&#41;<<8&#41; | &#40;&#40;b&#41;<<16&#41; | &#40;&#40;a&#41;<<24&#41;&#41;

extern int SCREEN_WIDTH;
extern int SCREEN_HEIGHT;
extern int BUFFER_WIDTH;
extern int interlaced;
extern int TVMode;

typedef struct
&#123;
	float u,v;
	unsigned int color;
	float x,y,z;
&#125; Vertex;

typedef struct
&#123;
	unsigned int color;
	float x,y,z;
&#125; Vertexx;

typedef struct
&#123;
	int w,h,tW,tH;
	int colorMode;
	unsigned char* data;
&#125; Image;

int pspDveMgrCheckVideoOut&#40;&#41;;
int pspDveMgrSetVideoOut&#40;int,int,int,int,int,int,int&#41;;

void initGraphics&#40;&#41;;
void endGraphics&#40;&#41;;
void setVideoMode&#40;int mode&#41;;
void flipScreen&#40;&#41;;
void clearScreen&#40;&#41;;
void freeImage&#40;Image* image&#41;;

Image* loadImage&#40;const char fileName&#91;&#93;&#41;;
Image* createImage&#40;int width,int height&#41;;
void clearImage&#40;Image* image,u32 color&#41;;
void drawImagePart&#40;Image* image,int sx,int sy,int dx,int dy,int sw,int sh,int dw,int dh,int flip,float rads&#41;;
void ScreenFade&#40;u8 r,u8 g,u8 b,u8 a&#41;;

#endif
J.F.
Posts: 2906
Joined: Sun Feb 22, 2004 11:41 am

Post by J.F. »

Okay, I cleaned up your code and got it working.

http://www.mediafire.com/download.php?zbgyiz30tyg

I just used a few Pochi Style pngs for the intro pngs. The "glitch" at the start of the fade in was from not clearing the buffers. I un-hardcoded the address of the display buffer in laced... in general did some cleaning of the TV code. You might want to look at the changes I made to see how they differ. The current code doesn't need the cache flushing, for example.

I also cleaned up the start code for safety... checking for the dve and a cable, and restricting the modes you can choose based on the cable. Again, look at the changes.

I fixed the exit code so it actually works. I didn't spot anything wrong now, but I can't test the composite cable as I don't have one. I did test both the component laced and component progressive as well as with and without the dvemgr.prx and cable for robustness.
MysticWhiteDragon
Posts: 30
Joined: Thu Feb 16, 2006 8:46 am

Post by MysticWhiteDragon »

THANKS!!! That helped out a lot!

Just one thing though. I noticed that a few pixels are still messed up near the bottom of the screen. I didn't notice it until I tried the PSP LCD screen, then I moved the vertical higher up on my TV and noticed it there too. I managed to remove that problem by adding back in the sceKernelDcacheWritebackInvalidateAll(); function into my flipScreen(); function.

Also I can confirm that all modes now work correctly! I have a component and a composite cable.

I know my selection and detection for the cable was not proper. I was just using it for my own testing purposes and planned on properly incorporating it into a menu later on correctly. I also do not understand what PSP_HEAP_SIZE_KB(-256); does. Could you please explain what it does?
J.F.
Posts: 2906
Joined: Sun Feb 22, 2004 11:41 am

Post by J.F. »

Setting the heap size to be negative is used along with the large memory flag in the makefile to give the maximum memory on both the phat and the slim. -256 means set the heap to be all but 256K of the memory. Without the negative heap size, you'd need separate executables for the phat and slim.

About the only thing that code doesn't test for is phat vs slim - if you try to init dvemgr.prx on a phat, it'll blow up. If you look in apps that do TV (like any of my stuff except those old tests) you'll see that they check if you're using 3.71+ and then test if you're on a slim before trying to loadstart dvemgr.prx.

Code: Select all

	if &#40;sceKernelDevkitVersion&#40;&#41; >= 0x03070110&#41;
	&#123;
		if &#40;kuKernelGetModel&#40;&#41; == PSP_MODEL_SLIM_AND_LITE&#41;
		&#123;
			if &#40;pspSdkLoadStartModule&#40;"devmgr.prx", PSP_MEMORY_PARTITION_KERNEL&#41; >= 0&#41;
				psp_tv_cable = pspDveMgrCheckVideoOut&#40;&#41;;
		&#125;
	&#125;
EDIT: Try flushing the dcache for the image data in the image functions instead of the whole dcache every vertical blank... like this:

Code: Select all

#include <string.h>
#include <stdlib.h>
#include <pspdisplay.h>
#include <pspgu.h>
#include <pspgum.h>
#include <pspkernel.h>
#include <png.h>
#include "graphics.h"

unsigned int __attribute__&#40;&#40;aligned&#40;16&#41;&#41;&#41; dList&#91;262144&#93;;

int dispNumber;
u32 *vramBase = &#40;u32*&#41;&#40;0x40000000|0x04000000&#41;;

void *fbp0 = NULL;
void *fbp1;
void *zbp;

int SCREEN_WIDTH  = 480;
int SCREEN_HEIGHT = 272;
int BUFFER_WIDTH  = 512;
int interlaced = 0;
int TVMode = 0;

int SCREEN_TOP = 0;
int SCREEN_BOTTOM = 0;
int SCREEN_LEFT = 0;
int SCREEN_RIGHT = 0;

void initGraphics&#40;&#41;
&#123;
   dispNumber = 0;

    switch &#40;TVMode&#41;
    &#123;
        case 0&#58;
        case 3&#58;
            fbp0 = &#40;void*&#41;0;
            fbp1 = &#40;void*&#41;&#40;BUFFER_WIDTH * SCREEN_HEIGHT * 4&#41;;
            zbp  = &#40;void*&#41;&#40;BUFFER_WIDTH * SCREEN_HEIGHT * 8&#41;;
            break;
        case 1&#58;
        case 2&#58;
            // interlaced modes... display buffer is larger
            fbp0 = &#40;void*&#41;0;
            fbp1 = &#40;void*&#41;&#40;BUFFER_WIDTH * SCREEN_HEIGHT * 4&#41;;
            zbp  = &#40;void*&#41;&#40;BUFFER_WIDTH * 503 * 8&#41;;
            break;
    &#125;

   sceGuInit&#40;&#41;;
   sceGuStart&#40;GU_DIRECT,dList&#41;;

   sceGuDrawBuffer&#40;GU_PSM_8888,fbp0,BUFFER_WIDTH&#41;;
   sceGuDispBuffer&#40;SCREEN_WIDTH,SCREEN_HEIGHT,fbp1,BUFFER_WIDTH&#41;;
   sceGuDepthBuffer&#40;zbp,BUFFER_WIDTH&#41;;

   sceGuOffset&#40;2048 - &#40;&#40;SCREEN_WIDTH - SCREEN_LEFT - SCREEN_RIGHT&#41;/2&#41;,2048 - &#40;&#40;SCREEN_HEIGHT - SCREEN_TOP - SCREEN_BOTTOM&#41;/2&#41;&#41;;
   sceGuViewport&#40;2048 + SCREEN_LEFT,2048 + SCREEN_TOP,SCREEN_WIDTH - SCREEN_LEFT - SCREEN_RIGHT,SCREEN_HEIGHT - SCREEN_TOP - SCREEN_BOTTOM&#41;;
   sceGuDepthRange&#40;65535,0&#41;;

   sceGuScissor&#40;0,0,SCREEN_WIDTH,SCREEN_HEIGHT&#41;;
   sceGuEnable&#40;GU_SCISSOR_TEST&#41;;
   sceGuFrontFace&#40;GU_CCW&#41;;
   sceGuShadeModel&#40;GU_SMOOTH&#41;;
   sceGuAlphaFunc&#40;GU_GREATER,0,0xff&#41;;
   sceGuEnable&#40;GU_CULL_FACE&#41;;
   sceGuEnable&#40;GU_DEPTH_TEST&#41;;
   sceGuDepthFunc&#40;GU_GEQUAL&#41;;
   sceGuEnable&#40;GU_ALPHA_TEST&#41;;
   sceGuEnable&#40;GU_TEXTURE_2D&#41;;
//sceGuEnable&#40;GU_CLIP_PLANES&#41;;

   sceGuEnable&#40;GU_BLEND&#41;;
   sceGuBlendFunc&#40;GU_ADD,GU_SRC_ALPHA,GU_ONE_MINUS_SRC_ALPHA,0,0&#41;;

   sceGuTexMode&#40;GU_PSM_8888,0,0,1&#41;;
   sceGuTexFunc&#40;GU_TFX_REPLACE,GU_TCC_RGBA&#41;;
   sceGuTexFilter&#40;GU_LINEAR,GU_LINEAR&#41;;
   sceGuTexWrap&#40;GU_CLAMP,GU_CLAMP&#41;;
   sceGuTexScale&#40;1,1&#41;;
   sceGuTexOffset&#40;0,0&#41;;
   sceGuAmbientColor&#40;0xffffffff&#41;;

   sceGuFinish&#40;&#41;;
   sceGuSync&#40;0,0&#41;;
   sceDisplayWaitVblankStart&#40;&#41;;
   sceGuDisplay&#40;1&#41;;

   sceDisplaySetFrameBuf&#40;&#40;void*&#41;&#40;&#40;u32&#41;vramBase + &#40;u32&#41;fbp1&#41;,BUFFER_WIDTH,PSP_DISPLAY_PIXEL_FORMAT_8888,PSP_DISPLAY_SETBUF_NEXTFRAME&#41;;

   sceKernelDcacheWritebackInvalidateAll&#40;&#41;;
   sceGuStart&#40;GU_DIRECT,dList&#41;;

   sceGuClearColor&#40;0&#41;;
   sceGuClearDepth&#40;0&#41;;
   sceGuClear&#40;GU_COLOR_BUFFER_BIT|GU_DEPTH_BUFFER_BIT&#41;;

   sceGumMatrixMode&#40;GU_PROJECTION&#41;;
   sceGumLoadIdentity&#40;&#41;;
   sceGumOrtho&#40;0,720,480,0,-1,1&#41;;

   sceGumMatrixMode&#40;GU_VIEW&#41;;
   sceGumLoadIdentity&#40;&#41;;

   sceGumMatrixMode&#40;GU_MODEL&#41;;
   sceGumLoadIdentity&#40;&#41;;
&#125;

void endGraphics&#40;&#41;
&#123;
   sceGuTerm&#40;&#41;;
&#125;

void setVideoMode&#40;int mode&#41;
&#123;
   TVMode = mode;

   if&#40;TVMode > 0&#41;
   &#123;
      SCREEN_TOP = 0; SCREEN_BOTTOM = 0; SCREEN_LEFT = 0; SCREEN_RIGHT = 0;
//      SCREEN_TOP = 104; SCREEN_BOTTOM = 104; SCREEN_LEFT = 120; SCREEN_RIGHT = 120; // Test
   &#125;
   else
   &#123;
      SCREEN_TOP = 0; SCREEN_BOTTOM = 0; SCREEN_LEFT = 0; SCREEN_RIGHT = 0;
   &#125;

   switch&#40;mode&#41;
   &#123;
      case 3&#58;
         pspDveMgrSetVideoOut&#40;0,0x1d2,720,480,1,15,0&#41;;
         SCREEN_WIDTH = 720;
         SCREEN_HEIGHT = 480;
         BUFFER_WIDTH = 768;
         interlaced = 0;
         break;
      case 2&#58;
         pspDveMgrSetVideoOut&#40;0,0x1d1,720,503,1,15,0&#41;;
         SCREEN_WIDTH = 720;
         SCREEN_HEIGHT = 480;
         BUFFER_WIDTH = 768;
         interlaced = 1;
         break;
      case 1&#58;
         pspDveMgrSetVideoOut&#40;2,0x1d1,720,503,1,15,0&#41;;
         SCREEN_WIDTH = 720;
         SCREEN_HEIGHT = 480;
         BUFFER_WIDTH = 768;
         interlaced = 1;
         break;
      case 0&#58;
      default&#58;
         pspDveMgrSetVideoOut&#40;0,0,480,272,1,15,0&#41;;
         SCREEN_WIDTH = 480;
         SCREEN_HEIGHT = 272;
         BUFFER_WIDTH = 512;
         interlaced = 0;
         break;
   &#125;
&#125;

void flipScreen&#40;&#41;
&#123;
   sceGuFinish&#40;&#41;;
   sceGuSync&#40;0,0&#41;;

   if&#40;interlaced&#41;
   &#123;
      u32 vsrc = &#40;u32&#41;vramBase + &#40;u32&#41;fbp0;
      u32 vdst = &#40;u32&#41;vramBase + &#40;u32&#41;fbp1;

      //sceKernelDcacheWritebackInvalidateAll&#40;&#41;;
      sceGuStart&#40;GU_DIRECT,dList&#41;;

      sceDisplayWaitVblankStart&#40;&#41;;
      sceGuCopyImage&#40;GU_PSM_8888,0,0,SCREEN_WIDTH,SCREEN_HEIGHT>>1,BUFFER_WIDTH<<1,&#40;void*&#41;&#40;vsrc + 768*4&#41;,0,0,BUFFER_WIDTH,&#40;void*&#41;vdst&#41;;
      sceGuTexSync&#40;&#41;;
      sceGuCopyImage&#40;GU_PSM_8888,0,0,SCREEN_WIDTH,SCREEN_HEIGHT>>1,BUFFER_WIDTH<<1,&#40;void*&#41;vsrc,0,0,BUFFER_WIDTH,&#40;void*&#41;&#40;vdst + 768*262*4&#41;&#41;;
      sceGuTexSync&#40;&#41;;

      sceGuFinish&#40;&#41;;
      sceGuSync&#40;0,0&#41;;
   &#125;
   else
   &#123;
      sceDisplayWaitVblankStart&#40;&#41;;
      fbp0 = sceGuSwapBuffers&#40;&#41;;
      dispNumber ^= 1;
   &#125;

   //sceKernelDcacheWritebackInvalidateAll&#40;&#41;;
   sceGuStart&#40;GU_DIRECT,dList&#41;;

   sceGumMatrixMode&#40;GU_MODEL&#41;;
   sceGumLoadIdentity&#40;&#41;;
&#125;

void clearScreen&#40;&#41;
&#123;
   sceGuClearColor&#40;0&#41;;
   sceGuClearDepth&#40;0&#41;;
   sceGuClear&#40;GU_COLOR_BUFFER_BIT|GU_DEPTH_BUFFER_BIT&#41;;
&#125;

void freeImage&#40;Image* image&#41;
&#123;
   free&#40;image->data&#41;;
   free&#40;image&#41;;
&#125;

static int Power2&#40;int dimension&#41;
&#123;
   int b = dimension;
   int n;
   for&#40;n = 0;b != 0;n++&#41; b >>= 1;
   b = 1 << n;
   if&#40;b == 2 * dimension&#41; b >>= 1;
   return b;
&#125;

void swizzleImage&#40;Image* image&#41;
&#123;
   unsigned int pitch = image->tW * image->colorMode;
   unsigned int i,j;
   unsigned int rowblocks = &#40;pitch / 16&#41;;
   long size = pitch * image->tH;

   unsigned char* out = &#40;unsigned char*&#41;malloc&#40;size * sizeof&#40;unsigned char&#41;&#41;;

   for&#40;j = 0;j < image->tH;j++&#41;
   &#123;
      for&#40;i = 0;i < pitch;i++&#41;
      &#123;
         unsigned int blockx = i / 16;
         unsigned int blocky = j / 8;

         unsigned int x = &#40;i - blockx * 16&#41;;
         unsigned int y = &#40;j - blocky * 8&#41;;
         unsigned int block_index = blockx + &#40;&#40;blocky&#41; * rowblocks&#41;;
         unsigned int block_address = block_index * 16 * 8;

         out&#91;block_address + x + y * 16&#93; = image->data&#91;i + j * pitch&#93;;
      &#125;
   &#125;
   free&#40;image->data&#41;;
   image->data = out;
   sceKernelDcacheWritebackRange&#40;image->data,image->tW * image->tH * sizeof&#40;u32&#41;&#41;;
&#125;

void unswizzleImage&#40;Image* image&#41;
&#123;
   unsigned int pitch = image->tW * image->colorMode;
   unsigned int i,j;
   unsigned int rowblocks = &#40;pitch / 16&#41;;
   long size = image->tW * image->tH;

   unsigned char* out = &#40;unsigned char*&#41;malloc&#40;size&#41;;

   for&#40;j = 0;j < image->h;j++&#41;
   &#123;
      for&#40;i = 0;i < pitch;i++&#41;
      &#123;
         unsigned int blockx = i / 16;
         unsigned int blocky = j / 8;

         unsigned int x = &#40;i - blockx * 16&#41;;
         unsigned int y = &#40;j - blocky * 8&#41;;
         unsigned int block_index = blockx + &#40;&#40;blocky&#41; * rowblocks&#41;;
         unsigned int block_address = block_index * 16 * 8;

         out&#91;i+j*pitch&#93; = image->data&#91;block_address + x + y * 16&#93;;
      &#125;
   &#125;
   free&#40;image->data&#41;;
   image->data = out;
   sceKernelDcacheWritebackRange&#40;image->data,image->tW * image->tH * sizeof&#40;u32&#41;&#41;;
&#125;

Image* createImage&#40;int width,int height&#41;
&#123;
   Image* image = &#40;Image*&#41;malloc&#40;sizeof&#40;Image&#41;&#41;;
   if&#40;!image&#41; return NULL;
   image->w = width;
   image->h = height;
   image->tW = Power2&#40;width&#41;;
   image->tH = Power2&#40;height&#41;;
   image->data = &#40;unsigned char*&#41;malloc&#40;image->tW * image->tH * sizeof&#40;u32&#41;&#41;;
   if&#40;!image->data&#41; return NULL;
   memset&#40;image->data,0,image->tW * image->tH * sizeof&#40;u32&#41;&#41;;
   sceKernelDcacheWritebackRange&#40;image->data,image->tW * image->tH * sizeof&#40;u32&#41;&#41;;
   return image;
&#125;

void clearImage&#40;Image* image,u32 color&#41;
&#123;
   int i;
   int size = image->tW * image->tH;
   u32* data = &#40;u32*&#41;image->data;
   for&#40;i = 0;i < size;i++,data++&#41; *data = color;
   sceKernelDcacheWritebackRange&#40;image->data,image->tW * image->tH * sizeof&#40;u32&#41;&#41;;
&#125;

Image* loadImage&#40;const char fileName&#91;&#93;&#41;
&#123;
   Image* image = NULL;

   png_structp pngPtr;
   png_infop infoPtr;
   unsigned int sigRead = 0;
   png_uint_32 width,height;
   int bitDepth,colorType,interlaceType,x,y;
   u32* line;
   FILE *fileIn;

   fileIn = fopen&#40;fileName,"rb"&#41;;
   if&#40;fileIn == NULL&#41; return NULL;

   pngPtr = png_create_read_struct&#40;PNG_LIBPNG_VER_STRING,NULL,NULL,NULL&#41;;
   if&#40;pngPtr == NULL&#41; &#123; fclose&#40;fileIn&#41;; return NULL; &#125;

   png_set_error_fn&#40;pngPtr,&#40;png_voidp&#41;NULL,&#40;png_error_ptr&#41;NULL,NULL&#41;;
   infoPtr = png_create_info_struct&#40;pngPtr&#41;;
   if&#40;infoPtr == NULL&#41;
   &#123;
      fclose&#40;fileIn&#41;;
      png_destroy_read_struct&#40;&pngPtr,png_infopp_NULL,png_infopp_NULL&#41;;
      return NULL;
   &#125;

   png_init_io&#40;pngPtr,fileIn&#41;;
   png_set_sig_bytes&#40;pngPtr,sigRead&#41;;
   png_read_info&#40;pngPtr,infoPtr&#41;;
   png_get_IHDR&#40;pngPtr,infoPtr,&width,&height,&bitDepth,&colorType,&interlaceType,int_p_NULL,int_p_NULL&#41;;

   if&#40;width > 512 || height > 512&#41;
   &#123;
      fclose&#40;fileIn&#41;;
      png_destroy_read_struct&#40;&pngPtr,png_infopp_NULL,png_infopp_NULL&#41;;
      return NULL;
   &#125;

   image = &#40;Image*&#41;malloc&#40;sizeof&#40;Image&#41;&#41;;
   if&#40;image == NULL&#41; return NULL;

   image->w = width;
   image->h = height;
   image->tW = Power2&#40;width&#41;;
   image->tH = Power2&#40;height&#41;;
   png_set_strip_16&#40;pngPtr&#41;;
   png_set_packing&#40;pngPtr&#41;;

   if&#40;colorType == PNG_COLOR_TYPE_PALETTE&#41; png_set_palette_to_rgb&#40;pngPtr&#41;;
   if&#40;colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8&#41; png_set_gray_1_2_4_to_8&#40;pngPtr&#41;;
   if&#40;png_get_valid&#40;pngPtr,infoPtr,PNG_INFO_tRNS&#41;&#41; png_set_tRNS_to_alpha&#40;pngPtr&#41;;

   png_set_filler&#40;pngPtr,0xff,PNG_FILLER_AFTER&#41;;

   image->data = &#40;unsigned char*&#41;malloc&#40;image->tW * image->tH * sizeof&#40;u32&#41;&#41;;

   if&#40;!image->data&#41;
   &#123;
      fclose&#40;fileIn&#41;;
      png_destroy_read_struct&#40;&pngPtr,png_infopp_NULL,png_infopp_NULL&#41;;
      free&#40;image&#41;;
      return NULL;
   &#125;

   line = &#40;u32*&#41;malloc&#40;width * 4&#41;;

   if&#40;!line&#41;
   &#123;
      fclose&#40;fileIn&#41;;
      png_destroy_read_struct&#40;&pngPtr,png_infopp_NULL,png_infopp_NULL&#41;;
      return NULL;
   &#125;

   u32* data = &#40;u32*&#41;image->data;

   for&#40;y = 0;y < height;y++&#41;
   &#123;
      png_read_row&#40;pngPtr,&#40;u8*&#41;line,png_bytep_NULL&#41;;

      for&#40;x = 0;x < width;x++&#41;
      &#123;
         u32 color = line&#91;x&#93;;
         data&#91;x + y * image->tW&#93; = color;
      &#125;
   &#125;

   image->colorMode = 4;

   free&#40;line&#41;;
   png_read_end&#40;pngPtr,infoPtr&#41;;
   png_destroy_read_struct&#40;&pngPtr,&infoPtr,png_infopp_NULL&#41;;
   fclose&#40;fileIn&#41;;

   swizzleImage&#40;image&#41;; // flushes dcache

   return image;
&#125;

void drawImagePart&#40;Image* image,int sx,int sy,int dx,int dy,int sw,int sh,int dw,int dh,int flip,float rads&#41;
&#123;
   Vertex *v = &#40;Vertex*&#41;sceGuGetMemory&#40;4 * sizeof&#40;Vertex&#41;&#41;;

   float l,t,r,b;

   sceGumPushMatrix&#40;&#41;;
   &#123;
      ScePspFVector3 pos=&#123; dx + dw / 2,dy + dh / 2,0&#125;;
      sceGumTranslate&#40;&pos&#41;;
      sceGumRotateZ&#40;rads&#41;;

      if&#40;&#40;image->tW <= 512&#41; && &#40;image->tH <= 512&#41;&#41;
      &#123;
         l = &#40;float&#41;&#40;sx&#41; / &#40;float&#41;&#40;image->tW&#41;;
         t = &#40;float&#41;&#40;sy&#41; / &#40;float&#41;&#40;image->tH&#41;;
         r = &#40;float&#41;&#40;sx+sw&#41; / &#40;float&#41;&#40;image->tW&#41;;
         b = &#40;float&#41;&#40;sy+sh&#41; / &#40;float&#41;&#40;image->tH&#41;;
         sceGuTexImage&#40;0,image->tW,image->tH,image->tW,image->data&#41;;
      &#125;
      else
      &#123;
         l = &#40;float&#41;&#40;sx % 16&#41; / 512;
         t = &#40;float&#41;&#40;sy % 16&#41; / 512;
         r = &#40;float&#41;&#40;sw + &#40;sx % 16&#41;&#41; / 512;
         b = &#40;float&#41;&#40;sh + &#40;sy % 16&#41;&#41; / 512;
         sceGuTexImage&#40;0,512,512,image->tW,image->data + &#40;&#40;sx / 16&#41; + &#40;&#40;image->tW / 16&#41; * &#40;sy / 8&#41;&#41;&#41; * 128&#41;;
      &#125;

      switch&#40;flip&#41;
      &#123;
         case 3&#58; // HV Flip
            v&#91;0&#93;.u = r; v&#91;0&#93;.v = b;
            v&#91;1&#93;.u = r; v&#91;1&#93;.v = t;
            v&#91;2&#93;.u = l; v&#91;2&#93;.v = b;
            v&#91;3&#93;.u = l; v&#91;3&#93;.v = t;
            break;
         case 2&#58; // V Flip
            v&#91;0&#93;.u = l; v&#91;0&#93;.v = b;
            v&#91;1&#93;.u = l; v&#91;1&#93;.v = t;
            v&#91;2&#93;.u = r; v&#91;2&#93;.v = b;
            v&#91;3&#93;.u = r; v&#91;3&#93;.v = t;
            break;;
         case 1&#58; // H Flip
            v&#91;0&#93;.u = r; v&#91;0&#93;.v = t;
            v&#91;1&#93;.u = r; v&#91;1&#93;.v = b;
            v&#91;2&#93;.u = l; v&#91;2&#93;.v = t;
            v&#91;3&#93;.u = l; v&#91;3&#93;.v = b;
            break;
         case 0&#58; // No Flip
         default&#58;
            v&#91;0&#93;.u = l; v&#91;0&#93;.v = t;
            v&#91;1&#93;.u = l; v&#91;1&#93;.v = b;
            v&#91;2&#93;.u = r; v&#91;2&#93;.v = t;
            v&#91;3&#93;.u = r; v&#91;3&#93;.v = b;
            break;
      &#125;

      v&#91;0&#93;.color = 0; v&#91;0&#93;.x = -dw / 2; v&#91;0&#93;.y = -dh / 2; v&#91;0&#93;.z = 0;
      v&#91;1&#93;.color = 0; v&#91;1&#93;.x = -dw / 2; v&#91;1&#93;.y =  dh / 2; v&#91;1&#93;.z = 0;
      v&#91;2&#93;.color = 0; v&#91;2&#93;.x =  dw / 2; v&#91;2&#93;.y = -dh / 2; v&#91;2&#93;.z = 0;
      v&#91;3&#93;.color = 0; v&#91;3&#93;.x =  dw / 2; v&#91;3&#93;.y =  dh / 2; v&#91;3&#93;.z = 0;

      sceGumDrawArray&#40;GU_TRIANGLE_STRIP,GU_COLOR_8888|GU_TEXTURE_32BITF|GU_VERTEX_32BITF|GU_TRANSFORM_3D,4,0,v&#41;;
   &#125;
   sceGumPopMatrix&#40;&#41;;
&#125;

void ScreenFade&#40;u8 r,u8 g,u8 b,u8 a&#41;
&#123;
   sceGuDisable&#40;GU_DEPTH_TEST&#41;;
   sceGuDisable&#40;GU_TEXTURE_2D&#41;;

   sceGumPushMatrix&#40;&#41;;
   &#123;
      Vertexx* v = &#40;Vertexx*&#41;sceGuGetMemory&#40;2 * sizeof&#40;Vertexx&#41;&#41;;

      v&#91;0&#93;.color = GU_RGBA&#40;r,g,b,a&#41;; v&#91;0&#93;.x =   0; v&#91;0&#93;.y =   0; v&#91;0&#93;.z = 0;
      v&#91;1&#93;.color = GU_RGBA&#40;r,g,b,a&#41;; v&#91;1&#93;.x = 720; v&#91;1&#93;.y = 480; v&#91;1&#93;.z = 0;

      sceGumDrawArray&#40;GU_SPRITES,GU_COLOR_8888|GU_VERTEX_32BITF|GU_TRANSFORM_3D,2,0,v&#41;;
   &#125;
   sceGumPopMatrix&#40;&#41;;

   sceGuEnable&#40;GU_TEXTURE_2D&#41;;
   sceGuEnable&#40;GU_DEPTH_TEST&#41;;
&#125;
Post Reply