Edit: post completely rewritten with (partial?) solution.
After looking at the gu/reflection and playing around with some code I have come to these conclusions:
- You need to enclose the sceGumDrawArray that you want to be affected by stencilling with sceGuEnable(GU_STENCIL_TEST).
- You need to call sceGuStencilFunc and sceGuStencilOp twice, once before drawing your stencil, then again before you draw the things you want stencilled.
- sceGuPixelMask isn't necessary, but you must set it back to 0 if you do call it.
- The blend function should be done on SRC, not DST.
- The relevant code in the reflection sample is between lines 188 and 205
Here's my test function:
Code: Select all
struct Vertex
{
float x, y, z;
};
#define DO_VERT(vert, xx, yy, zz) \
(vert)->x = xx; \
(vert)->y = yy; \
(vert)->z = zz; \
vert++;
/*
when setting up gu:
sceGuClearStencil(0x00);
sceGuEnable(GU_STENCIL_TEST); // Stencil test (might want to move this to only enclose the things you want stencilled)
sceGuEnable(GU_BLEND);
sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0);
at the start of your rendering loop (note last flag):
sceGuClear(GU_COLOR_BUFFER_BIT | GU_DEPTH_BUFFER_BIT | GU_STENCIL_BUFFER_BIT);
before drawing stuff you want stencilled:
Gfx_StencilRectangle(...)
some parts copied from reflection sample:
Copyright (c) 2005 Jesper Svennevid
Copyright (c) 2005 McZonk <mczonk@gmx.net>
*/
void Gfx_StencilRectangle(int x, int y, int w, int h)
{
struct Vertex *vdata = sceGuGetMemory(sizeof(struct Vertex) * 4);
struct Vertex *v = vdata;
sceGuStencilFunc(GU_ALWAYS, 1, 1); // always set 1 bit in 1 bit mask
sceGuStencilOp(GU_KEEP, GU_KEEP, GU_REPLACE); // keep value on failed test (fail and zfail) and replace
sceGuDepthMask(GU_TRUE);
// turn off alpha (0) so drawing doesn't actually effect the color buffer only the stencil buffer
// if you turn alpha on (>0) then it will be give the stencilled area a background color
sceGuColor(0x00000000);
// draw polygons in the shape of desired stencil
DO_VERT(v, x, y, 0);
DO_VERT(v, x + w, y, 0);
DO_VERT(v, x, y + h, 0);
DO_VERT(v, x + w, y + h, 0);
// disable GU_TEXTURE_2D since we aren't using GU_TEXTURE_* flag
sceGuDisable(GU_TEXTURE_2D);
sceGumDrawArray(GU_TRIANGLE_STRIP,
GU_VERTEX_32BITF | GU_TRANSFORM_3D,
4, 0, vdata);
sceGuEnable(GU_TEXTURE_2D);
sceGuStencilFunc(GU_EQUAL, 1, 1); // allow drawing where stencil is 1
sceGuStencilOp(GU_KEEP, GU_KEEP, GU_KEEP); // keep the stencil buffer unchanged
sceGuDepthMask(GU_FALSE);
}
It doesn't work 100% I can see some artifacts (text from psplink showing through), probably because I'm also drawing textures with alpha which mess up the stencil buffer.