[Rapheal has shown how to implement a faster version of drawing sprites with the same flexibility described below, check it out here
here.]
For even more information and a solid explanation of texture cache look
here and check out the speed demo in your sdk.
[DISCLAIMER: The following is just an observation, and what I have learned so far. I cannot verify 100% whether these methods are better or worse than anything else out there, and I have not done any extensive testing. So, be very critical of every detail listed below and of course call me out on anything that looks strange or doesnt make sense!]
The following is a simple demonstration of basic sprite functionality using the GU library from the PSPSDK. I am starting to believe that handling sprites though the GU will help alot of people with certain operations.
In brief, here is how you render a sprite using the GU.
1. Upload your image to the gu using sceGuTexImage(). This will prepare the gu to map your image to any geometry specified after this call (like our sprite). Subsequent calls to sceGuTexImage() will replace the current texture with the one provided.
2. Define two vertices that represent the "top-left" and "bottom-right" corner of your sprite. Each vertex must be supplied with valid UV texture coordinates which map from 0 to imageWidth and 0 to imageHeight respectivley. You will probably want the top left hand corner of the image, to map to the top left hand corner of your sprite. To do this we will set the u,v coordinate of the first vertex to 0,0. And of course the bottom right hand corner of the sprite should map to the bottom right hand corner of the image, so we will set the u,v of the second vertex to imageHeight, imageWidth.
vertices[0].u = 0;
vertices[0].v = 0;
vertices[1].u = pImg->imageWidth;
vertices[1].v = pImg->imageHeight;
Of course, it is common to store more than one image in a single file. For example you might want each frame of an explosion animation stored in the same image. If the width of each image is 64, then you just increment the u coordinate for the bottom right vertex and top left vertex by 64 to grab each frame.
NOTE: When you are rendering in 2D (by specifying GU_TRANSFORM_2D) the gu bypasses the transformation pipeline and thus uv coodinates cannot be remaped. I mention this here because the BlitAlphaImageToScreen() routine in graphics.h tries to do this, and I believe it is wrong.
3. Render using the vertex array by calling sceDrawArray(). Once you call this the rasterizer will map your image to the bounds defined by the two sprite vertices.
Alright, now here is some code that I put together real quick to demonstrate the above. Again, please point out anything that looks wrong or doesnt make sense.
#include "main.h"
#include "graphics.h"
PSP_MODULE_INFO("PSPSplash", 0, 1, 1);
PSP_MAIN_THREAD_ATTR(THREAD_ATTR_USER);
int main(int argc, char **argv)
{
SceCtrlData pad;
bool done = false;
pspDebugScreenInit();
SetupCallbacks();
sceCtrlSetSamplingCycle(0);
sceCtrlSetSamplingMode(PSP_CTRL_MODE_ANALOG);
initGraphics();
Image *pImg = loadImage("./real.png");
unsigned short imgScaleX = pImg->imageWidth;
unsigned short imgScaleY = pImg->imageHeight;
short xPos = 0;
short yPos = 0;
unsigned short offset = 5;
while(!done)
{
sceCtrlReadBufferPositive(&pad, 1);
if(pad.Buttons & PSP_CTRL_TRIANGLE)
imgScaleY += offset;
if(pad.Buttons & PSP_CTRL_CROSS)
imgScaleY -= offset;
if(pad.Buttons & PSP_CTRL_SQUARE)
imgScaleX -= offset;
if(pad.Buttons & PSP_CTRL_CIRCLE)
imgScaleX += offset;
if(pad.Buttons & PSP_CTRL_UP)
yPos -= offset;
if(pad.Buttons & PSP_CTRL_DOWN)
yPos += offset;
if(pad.Buttons & PSP_CTRL_LEFT)
xPos -= offset;
if(pad.Buttons & PSP_CTRL_RIGHT)
xPos += offset;
sceKernelDcacheWritebackInvalidateAll();
guStart();
sceGuClearColor(RGB(0, 0, 0));
sceGuClearDepth(0);
sceGuClear(GU_COLOR_BUFFER_BIT|GU_DEPTH_BUFFER_BIT);
sceGuTexImage(0, pImg->textureWidth, pImg->textureHeight, pImg->textureWidth, (void*) pImg->data);
Vertex *vertices = (Vertex*) sceGuGetMemory(2 * sizeof(Vertex));
vertices[0].u = 0;
vertices[0].v = 0;
vertices[0].x = xPos;
vertices[0].y = yPos;
vertices[0].z = 0;
vertices[1].u = pImg->imageWidth;
vertices[1].v = pImg->imageHeight;
vertices[1].x = xPos+imgScaleX;
vertices[1].y = yPos+imgScaleY;
vertices[1].z = 0;
sceGuDrawArray(GU_SPRITES, GU_TEXTURE_16BIT | GU_VERTEX_16BIT | GU_TRANSFORM_2D, 2, 0, vertices);
sceGuFinish();
sceGuSync(0, 0);
sceDisplayWaitVblankStart();
flipScreen();
}
if(pImg)
{
delete [] pImg->data;
delete pImg;
}
sceGuTerm();
sceKernelExitGame();
return 0;
}
ExecutableSource