Skip to content

Instantly share code, notes, and snippets.

@KapLex
Created October 12, 2012 02:20
Show Gist options
  • Save KapLex/3876973 to your computer and use it in GitHub Desktop.
Save KapLex/3876973 to your computer and use it in GitHub Desktop.
#include <pspkernel.h>
#include <pspdisplay.h>
#include <pspgu.h>
#include <pspgum.h>
#include <psprtc.h>
#include <stdio.h>
#include <string.h>
//#define TRI_DDLIST
#ifdef TRI_DDLIST
#define TRI_DLISTMODE GU_SEND
#define TRI_DLISTS 2
#define TRI_DLIST_SWAP() (triListIdx^=1)
#else
#define TRI_DLISTMODE GU_DIRECT
#define TRI_DLISTS 1
#define TRI_DLIST_SWAP() (void)0
#endif
#define TRI_DLIST() (triList[triListIdx])
extern unsigned long triDlistSizeUser __attribute__((weak));
static unsigned long triDlistSize = 256*1024;
// Globals
//--------------------------------------------------
static void* triList[TRI_DLISTS];
static unsigned long triListIdx = 0;
static void* triFrontbuffer = 0;
static void* triBackbuffer = (void*)(FRAME_BUFFER_SIZE*4);
void* triFramebuffer = (void*)(0x04000000); // always holds the absolute pointer to current drawbuffer
void* triFramebuffer2 = (void*)(0x04000000); // always holds the absolute pointer to last drawbuffer
void* triDispbuffers[2] = { 0, 0 };
void* triDepthbuffer = 0;
signed long triPsm = GU_PSM_8888;
signed long triBpp = 4;
static signed long triDoublebuffer = 1;
static signed long triInitialized = 0;
static signed long triListAvail = 0;
static signed long triVBlankEnable = 0;
static signed long triPseudoAAEnable = 0;
static signed long triSmoothditherEnable = 1;
static signed long triVBlankFlag = 0; // was VBlank called manually this frame?
static signed long triSmoothditherFlag = 0;
static signed long triPseudoAAFlag = 0;
#ifdef TRI_DDLIST
static PspGeContext triGeContext;
#endif
static float triFpsValue = 0.f;
static float triFpsMinValue = 9999.f;
static float triFpsMaxValue = 0.f;
static unsigned long long triLastTick = 0;
static unsigned long triTickFrequency = 0;
static unsigned long long triFrameCount = 0;
static unsigned long long triFrameTime = 0;
static unsigned long long triCPUTime = 0;
static unsigned long long triGPUTime = 0;
static unsigned long long triVblankTime = 0;
static signed long triColorKey = 0;
static signed long triBlend = 0;
static signed long triCurContext = 0;
#define ALIGN16 __attribute__((aligned(16)))
#define UNCACHED(x) (void*)(0x40000000 | (unsigned long)(x))
#define VRAM_BASE (0x04000000)
#define VRAM_SIZE (0x00200000)
#define VRAM_UNSWIZZLED (0x04200000) // VRAM mirror for unswizzled read
#define VRAM_LINEAR (0x04600000) // VRAM mirror for linear read (unswizzled + deinterleave)
#define MIN(a,b) ((a)<(b)?(a):(b))
// Do a fast blend of two colors x and y by alpha value z (255-srcalpha), where x is alpha premultiplied
#define FASTBLEND(x,y,z) (((x&0xFF00FF) + (((z*(y&0xFF00FF))>>8)&0xFF00FF))|((x&0xFF00) + (((z*(y&0xFF00))>>8)&0xFF00)))
static signed long DitherMatrix[2][16] = { { 0, 8, 0, 8,
8, 0, 8, 0,
0, 8, 0, 8,
8, 0, 8, 0 },
{ 8, 8, 8, 8,
0, 8, 0, 8,
8, 8, 8, 8,
0, 8, 0, 8 } };
static float ProjectionMatrix[2][16];
void triGuFinishCallback( int what )
{
sceRtcGetCurrentTick(&triGPUTime);
triGPUTime -= triFrameTime;
}
void triInit( signed long psm, triBool doublebuffer )
{
if (triInitialized!=0) return;
triInitialized = 1;
triDoublebuffer = doublebuffer;
switch (psm)
{
case GU_PSM_4444:
case GU_PSM_5650:
case GU_PSM_5551:
triBpp = 2;
triPsm = psm;
break;
default:
triBpp = 4;
triPsm = GU_PSM_8888;
break;
}
triBackbuffer = vrelptr(triVAlloc(FRAME_BUFFER_SIZE*triBpp));
if (triDoublebuffer)
{
triFrontbuffer = vrelptr(triVAlloc(FRAME_BUFFER_SIZE*triBpp));
}
else
{
triFrontbuffer = triBackbuffer;
triDispbuffers[0] = triMalloc(FRAME_BUFFER_SIZE*triBpp);
triDispbuffers[1] = triMalloc(FRAME_BUFFER_SIZE*triBpp);
memset(triDispbuffers[0],0,FRAME_BUFFER_SIZE*triBpp);
memset(triDispbuffers[1],0,FRAME_BUFFER_SIZE*triBpp);
}
triFramebuffer = vabsptr(triFrontbuffer);
triFramebuffer2 = vabsptr(triBackbuffer);
if (&triDlistSizeUser != NULL)
{
triDlistSize = triDlistSizeUser;
}
for (triListIdx=0;triListIdx<TRI_DLISTS;triListIdx++)
triList[triListIdx] = triMalloc(triDlistSize);
triListIdx = 0;
sceGuInit();
sceGuSetCallback(GU_CALLBACK_FINISH, &triGuFinishCallback);
// setup GU
sceGuStart(GU_DIRECT,triList[triListIdx]);
sceGuDrawBuffer(triPsm, triFrontbuffer, FRAME_BUFFER_WIDTH);
sceGuDispBuffer(512, 512, triBackbuffer, FRAME_BUFFER_WIDTH);
sceGuOffset(2048 - (SCREEN_WIDTH/2), 2048 - (SCREEN_HEIGHT/2));
sceGuViewport(2048, 2048, SCREEN_WIDTH, SCREEN_HEIGHT);
// Scissoring
sceGuScissor(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
sceGuEnable(GU_SCISSOR_TEST);
// Backface culling
sceGuFrontFace(GU_CCW);
sceGuDisable(GU_CULL_FACE); // no culling in 2D
// Depth test
sceGuDisable(GU_DEPTH_TEST);
sceGuDepthMask(GU_TRUE); // disable z-writes
// Color keying
sceGuDisable(GU_COLOR_TEST);
sceGuDisable(GU_ALPHA_TEST);
sceGuDisable(GU_CLIP_PLANES);
// Texturing
sceGuEnable(GU_TEXTURE_2D);
sceGuShadeModel(GU_SMOOTH);
sceGuTexWrap(GU_CLAMP, GU_CLAMP);
sceGuTexFilter(GU_LINEAR,GU_LINEAR);
sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA);
sceGuTexEnvColor(0xFFFFFFFF);
sceGuColor(0xFFFFFFFF);
sceGuAmbientColor(0xFFFFFFFF);
sceGuTexOffset(0.0f, 0.0f);
sceGuTexScale(1.0f, 1.0f);
// Blending
sceGuEnable(GU_BLEND);
sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0);
sceGuDisable(GU_DITHER);
if (triBpp<4)
{
sceGuSetDither( (ScePspIMatrix4*)DitherMatrix[0] );
sceGuEnable(GU_DITHER);
}
// Projection
gumLoadIdentity( (ScePspFMatrix4*)ProjectionMatrix[0] );
gumOrtho( (ScePspFMatrix4*)ProjectionMatrix[0], 0.0f, 480.0f, 272.0f, 0.0f, -1.0f, 1.0f );
gumLoadIdentity( (ScePspFMatrix4*)ProjectionMatrix[1] );
ScePspFVector3 displace = { -0.002f, 0.00367f, 0.0f }; // ~ 1/480, 1/272
gumTranslate( (ScePspFMatrix4*)ProjectionMatrix[1], &displace );
gumMultMatrix( (ScePspFMatrix4*)ProjectionMatrix[1], (ScePspFMatrix4*)ProjectionMatrix[1], (ScePspFMatrix4*)ProjectionMatrix[0] );
sceGumMatrixMode(GU_PROJECTION);
sceGumLoadMatrix( (ScePspFMatrix4*)ProjectionMatrix[0] );
sceGumMatrixMode(GU_VIEW);
sceGumLoadIdentity();
sceGumMatrixMode(GU_MODEL);
sceGumLoadIdentity();
sceGuClearColor( 0x0 );
sceGuClear(GU_COLOR_BUFFER_BIT|GU_FAST_CLEAR_BIT);
sceGuFinish();
sceGuSync(0,0);
sceDisplayWaitVblankStart();
sceGuDisplay(1);
if (!triDoublebuffer)
{
sceDisplaySetFrameBuf( triDispbuffers[1], 512, triPsm, PSP_DISPLAY_SETBUF_NEXTFRAME );
}
sceGuStart(TRI_DLISTMODE, TRI_DLIST());
#ifdef TRI_DDLIST
sceGuDrawBufferList(triPsm, vrelptr(triFramebuffer2), FRAME_BUFFER_WIDTH);
triCurContext = 0;
#else
triCurContext = 1;
#endif
triListAvail = 1;
sceRtcGetCurrentTick(&triLastTick);
triTickFrequency = sceRtcGetTickResolution();
triFrameCount = 0;
}
void triClose()
{
if (!triInitialized) return;
triVFree(vabsptr(triBackbuffer));
if (triDoublebuffer)
{
triVFree(vabsptr(triFrontbuffer));
}
else
{
triFree(triDispbuffers[0]);
triFree(triDispbuffers[1]);
}
for (triListIdx=0;triListIdx<TRI_DLISTS;triListIdx++)
triFree(triList[triListIdx]);
triInitialized = 0;
triListAvail = 0;
sceGuTerm();
}
void triBegin()
{
#ifdef TRI_DDLIST
sceGuStart(GU_DIRECT, triList[triListIdx^1]);
triCurContext = 1;
#endif
}
void triEnd()
{
#ifdef TRI_DDLIST
if (sceGuFinish()>triDlistSize)
{
triLogError("ERROR: Display list overflow!\n");
}
triCurContext = 0;
sceGuDrawBufferList(triPsm, vrelptr(triFramebuffer2), FRAME_BUFFER_WIDTH);
#endif
}
void triSync()
{
#ifdef TRI_DDLIST
if (triCurContext==1)
sceGuSync(GU_SYNC_LIST,GU_SYNC_WAIT);
else
sceGuSync(GU_SYNC_SEND,GU_SYNC_WAIT);
#else
sceGuSync(GU_SYNC_LIST,GU_SYNC_WAIT);
#endif
}
void triSwapbuffers()
{
unsigned long long triEndTick;
if (!triDoublebuffer)
{
if (triCurContext==1)
sceGuSync(GU_SYNC_LIST,GU_SYNC_WAIT);
else
sceGuSync(GU_SYNC_SEND,GU_SYNC_WAIT);
sceGuCopyImage(triPsm, 0, 0, 480, 272, 512, triFramebuffer, 0, 0, 512, triDispbuffers[triFrameCount&1]);
sceGuTexSync();
}
if (sceGuFinish()>triDlistSize)
{
triLogError("ERROR: Display list overflow!\n");
}
sceRtcGetCurrentTick(&triCPUTime);
// Sync to all drawing
sceGuSync(GU_SYNC_FINISH,GU_SYNC_WHAT_DONE);
if ((triVBlankEnable || triPseudoAAEnable) && !triVBlankFlag)
sceDisplayWaitVblankStart();
sceRtcGetCurrentTick(&triEndTick);
triCPUTime -= triFrameTime;
triVblankTime = triEndTick-triFrameTime;
triVBlankFlag = 0;
triFramebuffer2 = triFramebuffer;
if (triDoublebuffer)
{
triFramebuffer = vabsptr(sceGuSwapBuffers());
}
else
{
sceDisplaySetFrameBuf( triDispbuffers[triFrameCount&1], 512, triPsm, PSP_DISPLAY_SETBUF_IMMEDIATE );
}
#ifdef TRI_DDLIST
sceGuSendList(GU_TAIL, TRI_DLIST(), &triGeContext);
#endif
TRI_DLIST_SWAP();
sceGuStart(TRI_DLISTMODE, TRI_DLIST());
#ifdef TRI_DDLIST
sceGuDrawBufferList(triPsm, vrelptr(triFramebuffer2), FRAME_BUFFER_WIDTH);
#else
sceGuDrawBufferList(triPsm, vrelptr(triFramebuffer), FRAME_BUFFER_WIDTH);
#endif
if (triBpp<4 && triSmoothditherEnable)
sceGuSetDither( (ScePspIMatrix4*)DitherMatrix[triSmoothditherFlag^=1] );
if (triPseudoAAEnable)
{
sceGumMatrixMode(GU_PROJECTION);
sceGumLoadMatrix( (ScePspFMatrix4*)ProjectionMatrix[triPseudoAAFlag^=1] );
sceGumMatrixMode(GU_MODEL);
}
triFrameCount++;
if ((triEndTick-triLastTick)>=(triTickFrequency>>1))
{
triFpsValue = (float)triFrameCount/(triEndTick-triLastTick)*triTickFrequency;
if (triFrameCount>1)
{
if (triFpsMinValue>triFpsValue) triFpsMinValue = triFpsValue;
if (triFpsMaxValue<triFpsValue) triFpsMaxValue = triFpsValue;
}
triFrameCount = 0;
triLastTick = triEndTick;
}
triFrameTime = triEndTick;
}
void triClear( unsigned long color )
{
sceGuClearColor( color );
sceGuClear( GU_COLOR_BUFFER_BIT | GU_FAST_CLEAR_BIT );
}
void triVblank()
{
sceDisplayWaitVblankStart();
triVBlankFlag = 1;
}
void triCopyToScreen( signed long x, signed long y, signed long w, signed long h, signed long sx, signed long sy, signed long sbw, void* src )
{
if (triCurContext==1)
sceGuCopyImage( triPsm, x, y, w, h, 512, triFramebuffer2, sx, sy, sbw, src );
else
sceGuCopyImage( triPsm, x, y, w, h, 512, triFramebuffer, sx, sy, sbw, src );
sceGuTexSync();
}
void triCopyFromScreen( signed long x, signed long y, signed long w, signed long h, signed long dx, signed long dy, signed long dbw, void* dst )
{
if (triCurContext==1)
sceGuCopyImage( triPsm, dx, dy, w, h, dbw, dst, x, y, 512, triFramebuffer2 );
else
sceGuCopyImage( triPsm, dx, dy, w, h, dbw, dst, x, y, 512, triFramebuffer );
sceGuTexSync();
}
void triPerspective( float fov )
{
if (fov<1.0f || fov>179.0f) fov = 75.0f;
gumLoadIdentity( (ScePspFMatrix4*)ProjectionMatrix[0] );
gumPerspective( (ScePspFMatrix4*)ProjectionMatrix[0], fov, 16.0f/9.0f, 1.0f, 1000.0f );
gumLoadIdentity( (ScePspFMatrix4*)ProjectionMatrix[1] );
ScePspFVector3 displace = { -0.002f, 0.00367f, 0.0f }; // ~ 1/480, 1/272
gumTranslate( (ScePspFMatrix4*)ProjectionMatrix[1], &displace );
gumMultMatrix( (ScePspFMatrix4*)ProjectionMatrix[1], (ScePspFMatrix4*)ProjectionMatrix[1], (ScePspFMatrix4*)ProjectionMatrix[0] );
sceGumMatrixMode(GU_PROJECTION);
sceGumLoadMatrix( (ScePspFMatrix4*)ProjectionMatrix[triPseudoAAFlag] );
sceGumMatrixMode(GU_MODEL);
}
void triOrtho()
{
gumLoadIdentity( (ScePspFMatrix4*)ProjectionMatrix[0] );
gumOrtho( (ScePspFMatrix4*)ProjectionMatrix[0], 0.0f, 480.0f, 272.0f, 0.0f, -1.0f, 1.0f );
gumLoadIdentity( (ScePspFMatrix4*)ProjectionMatrix[1] );
ScePspFVector3 displace = { -0.002f, 0.00367f, 0.0f }; // ~ 1/480, 1/272
gumTranslate( (ScePspFMatrix4*)ProjectionMatrix[1], &displace );
gumMultMatrix( (ScePspFMatrix4*)ProjectionMatrix[1], (ScePspFMatrix4*)ProjectionMatrix[1], (ScePspFMatrix4*)ProjectionMatrix[0] );
sceGumMatrixMode(GU_PROJECTION);
sceGumLoadMatrix( (ScePspFMatrix4*)ProjectionMatrix[triPseudoAAFlag] );
sceGumMatrixMode(GU_MODEL);
}
void triEnable( unsigned long state )
{
switch (state)
{
case TRI_VBLANK:
triVBlankEnable = 1;
break;
case TRI_PSEUDO_FSAA:
triPseudoAAEnable = 1;
break;
case TRI_SMOOTH_DITHER:
triSmoothditherEnable = 1;
break;
case TRI_DEPTH_TEST:
if (triDepthbuffer!=0)
sceGuEnable(GU_DEPTH_TEST);
break;
case TRI_DEPTH_MASK:
if (triDepthbuffer!=0)
sceGuDepthMask(0);
break;
default:
sceGuEnable( state );
break;
}
}
void triDisable( unsigned long state )
{
switch (state)
{
case TRI_VBLANK:
triVBlankEnable = 0;
break;
case TRI_PSEUDO_FSAA:
triPseudoAAEnable = 0;
triPseudoAAFlag = 0;
break;
case TRI_SMOOTH_DITHER:
triSmoothditherEnable = 0;
break;
case TRI_DEPTH_TEST:
sceGuDisable(GU_DEPTH_TEST);
break;
case TRI_DEPTH_MASK:
sceGuDepthMask(0xFFFF);
break;
default:
sceGuDisable( state );
break;
}
}
void triRendertotexture( signed long psm, void* tbp, signed long tw, signed long th, signed long tbw )
{
signed long bpp = 0;
// check that pixelformat is a legal renderformat
switch (psm)
{
case GU_PSM_4444:
case GU_PSM_5650:
case GU_PSM_5551:
bpp = 2;
break;
case GU_PSM_8888:
bpp = 4;
break;
default:
triLogPrint("Cannot render in pixelformat %x\n", psm);
return;
}
if ((unsigned long)tbp<VRAM_BASE || ((unsigned long)tbp+tbw*th*bpp)>VRAM_SIZE+VRAM_LINEAR)
{
triLogPrint("Cannot render to non VRAM space.\n");
return; // check that texture is in VRAM
}
sceGuDrawBufferList( psm, vrelptr(tbp), tbw );
sceGuOffset(2048 - (tw/2), 2048 - (th/2));
sceGuViewport(2048, 2048, tw, th);
sceGuScissor(0, 0, tw, th);
}
void triRendertoimage( triImage* img )
{
signed long bpp = 0;
// check that pixelformat is a legal renderformat
switch (img->format)
{
case GU_PSM_4444:
case GU_PSM_5650:
case GU_PSM_5551:
bpp = 2;
break;
case GU_PSM_8888:
bpp = 4;
break;
default:
triLogPrint("Cannot render in pixelformat %x\n", img->format);
return;
}
// make sure the image is in VRAM
triImageToVRAM( img );
if ((unsigned long)img->data<VRAM_BASE || ((unsigned long)img->data+img->size)>VRAM_SIZE+VRAM_LINEAR)
{
triLogPrint("Cannot render to non VRAM space.\n");
return; // check that texture is in VRAM
}
sceGuDrawBufferList( img->format, vrelptr(img->data), img->stride );
sceGuOffset(2048 - (img->width/2), 2048 - (img->height/2));
sceGuViewport(2048, 2048, img->width, img->height);
sceGuScissor(0, 0, img->width, img->height);
}
void triRendertoscreen()
{
if (triCurContext==1)
sceGuDrawBufferList(triPsm, vrelptr(triFramebuffer), FRAME_BUFFER_WIDTH);
else
sceGuDrawBufferList(triPsm, vrelptr(triFramebuffer2), FRAME_BUFFER_WIDTH);
sceGuOffset(2048 - (SCREEN_WIDTH/2), 2048 - (SCREEN_HEIGHT/2));
sceGuViewport(2048, 2048, SCREEN_WIDTH, SCREEN_HEIGHT);
sceGuScissor(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
}
void triDrawLine( float x0, float y0, float x1, float y1, unsigned long color )
{
triVertC* vertices = (triVertC*)sceGuGetMemory(2 * sizeof(triVertC));
vertices[0].color = color;
vertices[0].x = x0;
vertices[0].y = y0;
vertices[0].z = 0.0f;
vertices[1].color = color;
vertices[1].x = x1;
vertices[1].y = y1;
vertices[1].z = 0.0f;
sceGuDisable(GU_TEXTURE_2D);
sceGuShadeModel(GU_FLAT);
sceGuDrawArray(GU_LINES, GU_COLOR_8888|GU_VERTEX_32BITF|GU_TRANSFORM_2D, 2, 0, vertices);
sceGuShadeModel(GU_SMOOTH);
sceGuEnable(GU_TEXTURE_2D);
}
void triDrawLines( triVec2* p, signed long num, unsigned long color )
{
triVertC* vertices = (triVertC*)sceGuGetMemory(num * sizeof(triVertC));
int i = 0;
for (;i<num;i++)
{
vertices[i].color = color;
vertices[i].x = p[i].x;
vertices[i].y = p[i].y;
vertices[i].z = 0.0f;
}
sceGuDisable(GU_TEXTURE_2D);
sceGuShadeModel(GU_FLAT);
sceGuDrawArray(GU_LINE_STRIP, GU_COLOR_8888|GU_VERTEX_32BITF|GU_TRANSFORM_2D, num, 0, vertices);
sceGuShadeModel(GU_SMOOTH);
sceGuEnable(GU_TEXTURE_2D);
}
void triDrawRect( float x, float y, float width, float height, unsigned long color )
{
triVertC* vertices = (triVertC*)sceGuGetMemory(2 * sizeof(triVertC));
vertices[0].color = color;
vertices[0].x = x;
vertices[0].y = y;
vertices[0].z = 0.0f;
vertices[1].color = color;
vertices[1].x = x + width;
vertices[1].y = y + height;
vertices[1].z = 0.0f;
sceGuDisable(GU_TEXTURE_2D);
sceGuShadeModel(GU_FLAT);
sceGuDrawArray(GU_SPRITES, GU_COLOR_8888|GU_VERTEX_32BITF|GU_TRANSFORM_2D, 2, 0, vertices);
sceGuShadeModel(GU_SMOOTH);
sceGuEnable(GU_TEXTURE_2D);
}
// FIXME: Move to triMath.c
void triSinCos( float angle, float* sin, float* cos )
{
asm (
"vcst.s S003, VFPU_2_PI\n"
"mtv %2, s002\n"
"vmul.s s002, s002, s003\n"
"vrot.p c000, s002, [s,c]\n"
"mfv %0, s000\n"
"mfv %1, s001\n"
:"=r"(*sin),"=r"(*cos)
:"r"(angle)
);
}
void triColorOp( signed long op )
{
sceGuEnable(GU_COLOR_LOGIC_OP);
sceGuLogicalOp( op );
}
void triNoColorOp()
{
sceGuDisable(GU_COLOR_LOGIC_OP);
}
/**
* Set how textures are applied
*
* Key for the apply-modes:
* - Cv - Color value result
* - Ct - Texture color
* - Cf - Fragment color (vcolor)
* - Cc - Constant color (ccolor)
*
* Available apply-modes are: (TFX)
* - GU_TFX_MODULATE - Cv=Ct*Cf TCC_RGB: Av=Af TCC_RGBA: Av=At*Af
* - GU_TFX_DECAL - TCC_RGB: Cv=Ct,Av=Af TCC_RGBA: Cv=Cf*(1-At)+Ct*At Av=Af
* - GU_TFX_BLEND - Cv=(Cf*(1-Ct))+(Cc*Ct) TCC_RGB: Av=Af TCC_RGBA: Av=At*Af
* - GU_TFX_REPLACE - Cv=Ct TCC_RGB: Av=Af TCC_RGBA: Av=At
* - GU_TFX_ADD - Cv=Cf+Ct TCC_RGB: Av=Af TCC_RGBA: Av=At*Af
*/
void triImageTint( signed long mode, signed long comp, unsigned long vcolor, unsigned long ccolor )
{
sceGuTexFunc(mode, comp);
sceGuTexEnvColor(ccolor);
sceGuAmbientColor(vcolor);
}
void triImageNoTint()
{
sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA);
}
// Same as triImageTint( GU_TFX_DECAL, GU_TCC_RGB, (alpha<<24)|0xFFFFFF, 0 );
void triImageConstAlpha( unsigned long alpha )
{
sceGuTexFunc(GU_TFX_DECAL, GU_TCC_RGB);
sceGuAmbientColor((alpha<<24)|0xFFFFFF);
}
void triImageBlend( signed long op, signed long src_op, signed long dst_op, unsigned long src_fix, unsigned long dst_fix )
{
sceGuEnable(GU_BLEND);
sceGuBlendFunc( op, src_op, dst_op, src_fix, dst_fix );
}
void triImageNoBlend()
{
sceGuDisable(GU_BLEND);
}
void triImageColorkey( unsigned long color )
{
sceGuEnable(GU_COLOR_TEST);
sceGuColorFunc(GU_NOTEQUAL,color,0xffffff);
}
void triImageNoColorkey()
{
sceGuDisable(GU_COLOR_TEST);
}
void triDrawImage( float x, float y, float width, float height, // rect pos and size on screen
float u0, float v0, float u1, float v1, // area of texture to render
triImage* img )
{
if (img==0 || img->width==0 || img->height==0 || width==0 || height==0) return;
// Support negative width/height to do easy flipping
if (width < 0)
{
//x += width;
float u = u0; u0 = u1; u1 = u;
width = -width;
}
if (height < 0)
{
//y += height;
float v = v0; v0 = v1; v1 = v;
height = -height;
}
if (img->format==IMG_FORMAT_T4)
{
sceGuClutMode(img->palformat, 0, 0xff, 0);
sceGuClutLoad(2, img->palette);
}
else if (img->format==IMG_FORMAT_T8)
{
sceGuClutMode(img->palformat, 0, 0xff, 0);
sceGuClutLoad(32, img->palette);
}
sceGuTexMode(img->format, 0, 0, img->swizzled);
sceGuEnable(GU_TEXTURE_2D);
float cur_v = v0;
float cur_y = y;
float v_end = v1;
float y_end = y + height;
float vslice = 512.f;
float ystep = (height/(v1-v0) * vslice);
float vstep = ((v1-v0) > 0 ? vslice : -vslice);
float x_end = x + width;
float uslice = 64.f;
//float ustep = (u1-u0)/width * xslice;
float xstep = (width/(u1-u0) * uslice);
float ustep = ((u1-u0) > 0 ? uslice : -uslice);
triChar* data = img->data;
for ( ; cur_y < y_end; cur_y+=ystep, cur_v+=vstep )
{
float cur_u = u0;
float cur_x = x;
float u_end = u1;
// support large images (height > 512)
int off = (vstep>0) ? ((int)cur_v) : ((int)(cur_v+vstep));
data += ((off*img->stride*img->bits) >> 3);
cur_v -= off;
v_end -= off;
sceGuTexImage(0, MIN(512,img->stride), MIN(512,img->tex_height), img->stride, data);
float poly_height = ((cur_y+ystep) > y_end) ? (y_end-cur_y) : ystep;
float source_height = vstep;
// support negative vsteps
if ((vstep > 0) && (cur_v+vstep > v_end))
{
source_height = (v_end-cur_v);
}
else
if ((vstep < 0) && (cur_v+vstep < v_end))
{
source_height = (cur_v-v_end);
}
triChar* udata = data;
// blit maximizing the use of the texture-cache
for( ; cur_x < x_end; cur_x+=xstep, cur_u+=ustep )
{
// support large images (width > 512)
if (cur_u>512.f || cur_u+ustep>512.f)
{
int off = (ustep>0) ? ((int)cur_u & ~31) : ((int)(cur_u+ustep) & ~31);
udata += ((off*img->bits) >> 3);
cur_u -= off;
u_end -= off;
sceGuTexImage(0, MIN(512,img->stride), MIN(512,img->tex_height), img->stride, udata);
}
triVertUV* vertices = (triVertUV*)sceGuGetMemory(2 * sizeof(triVertUV));
float poly_width = ((cur_x+xstep) > x_end) ? (x_end-cur_x) : xstep;
float source_width = ustep;
// support negative usteps
if ((ustep > 0) && (cur_u+ustep > u_end))
{
source_width = (u_end-cur_u);
}
else
if ((ustep < 0) && (cur_u+ustep < u_end))
{
source_width = (cur_u-u_end);
}
vertices[0].u = cur_u;
vertices[0].v = cur_v;
vertices[0].x = cur_x;
vertices[0].y = cur_y;
vertices[0].z = 0;
vertices[1].u = cur_u + source_width;
vertices[1].v = cur_v + source_height;
vertices[1].x = cur_x + poly_width;
vertices[1].y = cur_y + poly_height;
vertices[1].z = 0;
sceGuDrawArray(GU_SPRITES,GU_TEXTURE_32BITF|GU_VERTEX_32BITF|GU_TRANSFORM_2D,2,0,vertices);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment