I have created a simple program that lets the user control a character on the screen. At the moment all screen output is very flickery, I'm guessing that I have to implement double buffering but am not sure how to do this? My code is below:
It seems like you can't use double buffering with the standard console (you need to write your own text routines, rendered on a backbuffer). But you should at least wait the VBlank in your main loop, like this:
void inputLoop()
{
while (1)
{
pspDebugScreenSetXY(0, 0);
pspDebugScreenPrintf("Press X, O, [] or /\\ to move character... \n");
sceCtrlReadBufferPositive(&pad, 1);
if((pad.Buttons) & (PSP_CTRL_CROSS)) // move down
{
y++;
drawCharacter();
}
else if((pad.Buttons) & (PSP_CTRL_SQUARE)) // move left
{
x--;
drawCharacter();
}
else if((pad.Buttons) & (PSP_CTRL_TRIANGLE)) // move up
{
y--;
drawCharacter();
}
else if((pad.Buttons) & (PSP_CTRL_CIRCLE)) // move down
{
x++;
drawCharacter();
}
sceDisplayWaitVblankStart();
}
}
Also, I don't think it's a good idea to redraw the character one time in each 'if' in your loop, because it will become more and more complex as your game becomes bigger. For example, you could save its coordinates and compare them with those of the last time and redraw it only if they have changed...
int main()
{
SceCtrlData pad;
struct timeval tick;
unsigned int oldButtons = 0;
pBufferPointer[0] = (u32*)(0x04000000+0x40000000); // pointer to 1st page in VRAM
pBufferPointer[1] = (u32*)(0x04000000+0x40000000+FRAME_BUFFER_SIZE); // pointer to 2nd page in VRAM
pspDebugScreenInit(); // do this so that we can use pspDebugScreenPrintf
SetupCallbacks();
sceCtrlSetSamplingCycle(0);
sceCtrlSetSamplingMode(PSP_CTRL_MODE_ANALOG);
sceDisplaySetMode(0, SCREEN_WIDTH, SCREEN_HEIGHT);
bg = LoadImage("bg.png"); // load bg
mario = LoadImage("m.png"); // load our character
cursor = LoadImage("cursor.png"); // load a cursor
currentPage = 1; // prepare a page to be displayed
pVRAM = pBufferPointer[currentPage];
Render(); // render to page 1
int lastTime = Sys_Milliseconds();
while (!done)
{
int timeNow = Sys_Milliseconds();
int delta = timeNow-lastTime;
lastTime = timeNow;
offset--; // change the offset position to draw the background image
if (offset<=-128) // this will give us an illusion of a moving background
offset = 0;
gettimeofday(&tick, 0);
sceCtrlPeekBufferPositive(&pad, 1); // using sceCtrlPeekBufferPositive is faster than sceCtrlReadBufferPositive
// because sceCtrlReadBufferPositive waits for vsync
if (pad.Buttons != 0) // one or more buttons have been pressed
{
// do a screen shot only if CIRCLE button wasn't in 'down' state previously
if ((pad.Buttons&PSP_CTRL_CIRCLE) && !(oldButtons&PSP_CTRL_CIRCLE))
{
ScreenShot("ms0:/screenshot.png");
}
// CROSS button to exit
if (pad.Buttons & PSP_CTRL_CROSS)
{
done = true;
}
if (pad.Buttons & PSP_CTRL_LEFT)
{
if (xMan > 0) xMan--;
}
else if (pad.Buttons & PSP_CTRL_RIGHT)
{
if (xMan < SCREEN_WIDTH-1) xMan++;
}
}
oldButtons = pad.Buttons;
// range of pad.Lx and pad.Ly is 0-255
if (pad.Lx<64)
{
if (x>0) x--;
}
else if (pad.Lx>196)
{
if (x<SCREEN_WIDTH-1)
x++;
}
if (pad.Ly<64)
{
if (y>0) y--;
}
else if (pad.Ly>196)
{
if (y<SCREEN_HEIGHT-1)
y++;
}
// flip and bring the background page to the front
sceDisplayWaitVblankStart();
sceDisplaySetFrameBuf(pVRAM, FRAME_BUFFER_WIDTH, PSP_DISPLAY_PIXEL_FORMAT_8888, 0);
// make the previous page as the background page for rendering
currentPage = 1-currentPage;
pVRAM = pBufferPointer[currentPage];
Render(); // render all images to buffer
}
FreeImage(bg); // free the images
FreeImage(mario);
FreeImage(cursor);
sceKernelExitGame();
return 0;
}
Thanks for posting the code, but it's not much use to me because you haven't included the parts that initialise variables such as pVRAM, FRAME_BUFFER_SIZE and FRAME_BUFFER_WIDTH? If you provide me with this info then I can try to integrate your code into mine in order to implement double buffering.