 |
forums.ps2dev.org Homebrew PS2, PSP & PS3 Development Discussions
|
| View previous topic :: View next topic |
| Author |
Message |
bengarney
Joined: 22 Oct 2005 Posts: 24
|
Posted: Wed Nov 16, 2005 8:28 pm Post subject: PSPGL Viewport/Projection Oddities |
|
|
Howdy again!
I've got the following setup code that I use to manage my working area for rendering purposes. It works great on a varety of GL implementations (mac, pc, linux, on all drivers, and has for years...).
screenHeight and screenWidth are 479 and 271 respectively - one pixel less than my actual framebuffer size (just to be safe).
| Code: |
glMatrixMode(GL_PROJECTION); glLoadIdentity();
glOrtho(rect.startX, rect.startX + rect.width,
rect.height, 0,
0, 1);
glTranslatef(0, -rect.startY, 0);
glMatrixMode(GL_MODELVIEW); glLoadIdentity();
glViewport(rect.startX, screenHeight - (rect.startY + rect.height), rect.width, rect.height);
|
This code should implement the behavior that rendering is limited to the specified rectangle, with an orthographic projection on the XY plane (so that if I draw a 0,0, it's top left, and if I draw at 480, 272 it's bottom right, but things I try to draw outside the passed rect just get clipped out). However, it seems to be causing weird scaling and mispositioning problems, even though it work fine on many other GL implementations. (That snippet has worked reliably on ATI, nVidia, and other chipsets on mac, windows, and linux for about seven years.)
Help! :)
Thanks in advance,
Ben |
|
| Back to top |
|
 |
bengarney
Joined: 22 Oct 2005 Posts: 24
|
Posted: Fri Nov 18, 2005 3:27 pm Post subject: |
|
|
So, after some more experimenting, I find that the clipping is done against the proper rectangle, but the rendering isn't offset appropriately - it stays relative to the topleft corner, regardless of what x/y I pass to glViewport.
This seems related to a problem described in this thread: http://forums.ps2dev.org/viewtopic.php?t=3221
Doing some experimenting but I'm not feeling too confident - not as familiar with the innards of GU as no doubt many of you are here. :) |
|
| Back to top |
|
 |
bengarney
Joined: 22 Oct 2005 Posts: 24
|
Posted: Fri Nov 18, 2005 3:42 pm Post subject: |
|
|
And a little more testing suggests it's probably two things. First, the area to which the graphics are clipped is being set properly but the graphics themselves aren't offset properly, and second, I'm not sure that the GL offset semantics (ie, the lowerleft corner) are being preserved properly - it seems the PSP operates from top right.
I just can't quite figure out how to diddle the values I get in at glViewport properly such that they turn into the right values to put into the registers. I'll be doing trial and error but that's always painful. :) |
|
| Back to top |
|
 |
jsgf
Joined: 12 Jul 2005 Posts: 254
|
Posted: Fri Nov 18, 2005 4:46 pm Post subject: |
|
|
| OK, that sounds easy enough to fix. I'll take a look at it when I get a chance. I really need a bug system to keep track of all this... |
|
| Back to top |
|
 |
bengarney
Joined: 22 Oct 2005 Posts: 24
|
Posted: Fri Nov 18, 2005 9:02 pm Post subject: |
|
|
| Thanks! :) |
|
| Back to top |
|
 |
bengarney
Joined: 22 Oct 2005 Posts: 24
|
Posted: Sat Nov 19, 2005 6:52 am Post subject: |
|
|
Some additional notes:
I meant top left for PSP, bottom left for GL. Don't think anything uses top right.
| Code: |
/* Viewport / Screen Offset */
sendCommandi(CMD_OFFSETX, (2048 - width/2 - x) << 4);
sendCommandi(CMD_OFFSETY, (2048 - height/2 - y) << 4);
/* Viewport Size (X/Y, Width/Height) */
sendCommandf(CMD_VIEWPORT_SX, (float) (width/2));
sendCommandf(CMD_VIEWPORT_SY, (float) (-height/2));
/* Viewport Center (X/Y) */
sendCommandf(CMD_VIEWPORT_TX, (float) (2048 + x));
sendCommandf(CMD_VIEWPORT_TY, (float) (2048 + y));
/* Drawing Rectangle */
sendCommandi(CMD_REGION1, (y << 10) | x);
sendCommandi(CMD_REGION2, (((y + height)-1) << 10) | ((x + width)-1));
|
Notice the additional x/y terms. I suspect the solution involves something along these lines, but I'm not confident that my math is actually right in anything more than spirit. I know it's not, in fact, as it doesn't work right. :P |
|
| Back to top |
|
 |
bengarney
Joined: 22 Oct 2005 Posts: 24
|
Posted: Sun Nov 20, 2005 12:09 pm Post subject: |
|
|
Alrighty - here's a modified copy of the envmap sample app. You can move the viewport around by using the d-pad and the buttons on the right. One side controls X size/position and the other Y size/position.
Useful for visualizing what the values mean, and now that I've seen it, I expect I can get the PSPGL implementation to do what I mean. :)
| Code: |
/*
* PSP Software Development Kit - http://www.pspdev.org
* -----------------------------------------------------------------------
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
*
* envmap.c - Sample to desmonstrate environment mapping functionality
*
* Copyright (c) 2005 Jesper Svennevid
* Copyright (c) 2005 Renaldas Zioma <rej@scene.lt>
*
*/
#include <pspkernel.h>
#include <pspdisplay.h>
#include <pspdebug.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <pspctrl.h>
#include <pspgu.h>
#include <pspgum.h>
PSP_MODULE_INFO("EnvMap Sample", 0, 1, 1);
PSP_MAIN_THREAD_ATTR(THREAD_ATTR_USER);
#define printf pspDebugScreenPrintf
static unsigned int __attribute__((aligned(16))) list[262144];
extern unsigned char env0_start[];
typedef struct Vertex
{
float nx,ny,nz;
float x,y,z;
} Vertex;
int SetupCallbacks();
void genTorus( unsigned slices, unsigned rows, float radius, float thickness,
Vertex* dstVertices, unsigned short* dstIndices );
#define BUF_WIDTH (512)
#define SCR_WIDTH (480)
#define SCR_HEIGHT (272)
#define PIXEL_SIZE (4) /* change this if you change to another screenmode */
#define FRAME_SIZE (BUF_WIDTH * SCR_HEIGHT * PIXEL_SIZE)
#define ZBUF_SIZE (BUF_WIDTH SCR_HEIGHT * 2) /* zbuffer seems to be 16-bit? */
#define TORUS_SLICES 48 // numc
#define TORUS_ROWS 48 // numt
#define TORUS_RADIUS 1.0f
#define TORUS_THICKNESS 0.5f
#define LIGHT_DISTANCE 3.0f
Vertex __attribute__((aligned(16))) torus_vertices[TORUS_SLICES*TORUS_ROWS];
unsigned short __attribute__((aligned(16))) torus_indices[TORUS_SLICES*TORUS_ROWS*6];
int main(int argc, char* argv[])
{
pspDebugScreenInit();
SetupCallbacks();
// generate geometry
genTorus( TORUS_ROWS, TORUS_SLICES, TORUS_RADIUS, TORUS_THICKNESS, torus_vertices, torus_indices );
// flush cache so that no stray data remains
sceKernelDcacheWritebackAll();
//setup Pad
SceCtrlData pad;
u32 oldButtons = 0;
sceCtrlSetSamplingCycle(0);
sceCtrlSetSamplingMode(0);
// setup GU
sceGuInit();
sceGuStart(GU_DIRECT,list);
sceGuDrawBuffer(GU_PSM_8888,(void*)0,BUF_WIDTH);
sceGuDispBuffer(SCR_WIDTH,SCR_HEIGHT,(void*)0x88000,BUF_WIDTH);
sceGuDepthBuffer((void*)0x110000,BUF_WIDTH);
sceGuOffset(2048 - (SCR_WIDTH/2),2048 - (SCR_HEIGHT/2));
sceGuViewport(2048,2048,SCR_WIDTH,SCR_HEIGHT);
sceGuDepthRange(0xc350,0x2710);
sceGuScissor(0,0,SCR_WIDTH,SCR_HEIGHT);
sceGuEnable(GU_SCISSOR_TEST);
sceGuDepthFunc(GU_GEQUAL);
sceGuEnable(GU_DEPTH_TEST);
sceGuFrontFace(GU_CW);
sceGuShadeModel(GU_SMOOTH);
sceGuEnable(GU_CULL_FACE);
sceGuEnable(GU_CLIP_PLANES);
sceGuEnable(GU_TEXTURE_2D);
sceGuEnable(GU_LIGHTING);
sceGuEnable(GU_LIGHT0);
sceGuFinish();
sceGuSync(0,0);
sceDisplayWaitVblankStart();
sceGuDisplay(GU_TRUE);
// run sample
int valTorus = 0;
int valEnvMap = 0;
int rotateTorus = 1;
int rotateEnvMap = 1;
int startX = 2048;
int startY = 2048;
int sizeX = 480;
int sizeY = 272;
for(;;)
{
sceGuStart(GU_DIRECT,list);
// Diddle the viewport
sceGuViewport(startX, startY, sizeX, sizeY);
// clear screen
sceGuClearColor(0x554433);
sceGuClearDepth(0);
sceGuClear(GU_COLOR_BUFFER_BIT|GU_DEPTH_BUFFER_BIT);
// setup a light
ScePspFVector3 dir = { 0, 0, 1 };
sceGuLight(0,GU_DIRECTIONAL,GU_DIFFUSE,&dir);
sceGuLightColor(0,GU_DIFFUSE,0x00ff4040 );
sceGuLightAtt(0,1.0f,0.0f,0.0f);
sceGuAmbient(0x00202020);
// setup proj/view matrices
sceGumMatrixMode(GU_PROJECTION);
sceGumLoadIdentity();
sceGumPerspective(75.0f,16.0/9.0f,1.0f,1000.0f);
sceGumMatrixMode(GU_VIEW);
sceGumLoadIdentity();
// setup envmap texture
sceGuTexMode(GU_PSM_4444,0,0,0);
sceGuTexImage(0,64,64,64,env0_start);
sceGuTexFunc(GU_TFX_MODULATE,GU_TCC_RGB);
sceGuTexFilter(GU_LINEAR,GU_LINEAR);
sceGuAmbientColor(0xffffffff);
// setup envmap matrix (2x3)
// 2d rotation/translation matrix
// [ cosa -sina ]
// [ sina cosa ]
// [ tx ty ]
// envmap matrix is transposed
// since it is passed to GU as columns
float angle = -2.0f * valEnvMap * (GU_PI/180.0f);
float cs = cosf(angle);
float sn = sinf(angle);
ScePspFVector3 envmapMatrixColumns[2] = {
{ cs, sn, 0.0f },
{ -sn, cs, 0.0f }
};
sceGuLight( 2, GU_DIRECTIONAL, GU_DIFFUSE, &envmapMatrixColumns[0] );
sceGuLight( 3, GU_DIRECTIONAL, GU_DIFFUSE, &envmapMatrixColumns[1] );
// setup envmap texture coord generation
sceGuTexMapMode(
GU_ENVIRONMENT_MAP, // envmap mode on
2, // use 2nd light position as an envmap matrix 1st column
3 // use 3rd light position as an envmap matrix 2nd column
);
// draw torus
sceGumMatrixMode(GU_MODEL);
{
ScePspFVector3 pos = {0,0,-2.5f};
ScePspFVector3 rot = {valTorus * 0.79f * (GU_PI/180.0f), valTorus * 0.98f * (GU_PI/180.0f), valTorus * 1.32f * (GU_PI/180.0f)};
sceGumLoadIdentity();
sceGumTranslate(&pos);
sceGumRotateXYZ(&rot);
}
sceGuColor(0xffffff);
sceGumDrawArray(GU_TRIANGLES,GU_NORMAL_32BITF|GU_VERTEX_32BITF|GU_INDEX_16BIT|GU_TRANSFORM_3D,sizeof(torus_indices)/sizeof(unsigned short),torus_indices,torus_vertices);
pspDebugScreenSetXY(0,0);
printf( "Press X to toggle environment map rotation" );
pspDebugScreenSetXY(0,1);
printf( "Press O to toggle torus rotation" );
pspDebugScreenSetXY(0,2);
printf( " rect = %d, %d, %d, %d", startX, startY, sizeX, sizeY );
sceCtrlReadBufferPositive(&pad, 1);
if(oldButtons != pad.Buttons)
{
if(pad.Buttons & PSP_CTRL_CROSS)
rotateTorus ^= 0x01;
if(pad.Buttons & PSP_CTRL_CIRCLE)
rotateEnvMap ^= 0x01;
}
oldButtons = pad.Buttons;
// Increase startX
if(pad.Buttons & PSP_CTRL_UP)
startX++;
// Decrease startX
if(pad.Buttons & PSP_CTRL_DOWN)
startX--;
// Increase sizeX
if(pad.Buttons & PSP_CTRL_RIGHT)
sizeX++;
// Decreate sizeY
if(pad.Buttons & PSP_CTRL_LEFT)
sizeX--;
// Increase startX
if(pad.Buttons & PSP_CTRL_TRIANGLE)
startY++;
// Decrease startX
if(pad.Buttons & PSP_CTRL_CROSS)
startY--;
// Increase sizeX
if(pad.Buttons & PSP_CTRL_CIRCLE)
sizeY++;
// Decreate sizeY
if(pad.Buttons & PSP_CTRL_SQUARE)
sizeY--;
sceGuFinish();
sceGuSync(0,0);
// sceDisplayWaitVblankStart();
sceGuSwapBuffers();
if(rotateTorus) valTorus++;
if(rotateEnvMap) valEnvMap++;
}
sceGuTerm();
sceKernelExitGame();
return 0;
}
/* Exit callback */
int exit_callback(int arg1, int arg2, void *common)
{
sceKernelExitGame();
return 0;
}
/* Callback thread */
int CallbackThread(SceSize args, void *argp)
{
int cbid;
cbid = sceKernelCreateCallback("Exit Callback", exit_callback, NULL);
sceKernelRegisterExitCallback(cbid);
sceKernelSleepThreadCB();
return 0;
}
/* Sets up the callback thread and returns its thread id */
int SetupCallbacks(void)
{
int thid = 0;
thid = sceKernelCreateThread("update_thread", CallbackThread, 0x11, 0xFA0, 0, 0);
if(thid >= 0)
{
sceKernelStartThread(thid, 0, 0);
}
return thid;
}
/* usefull geometry functions */
void genTorus( unsigned slices, unsigned rows, float radius, float thickness, Vertex* dstVertices, unsigned short* dstIndices )
{
unsigned int i,j;
// generate torus (TODO: tri-strips)
for (j = 0; j < slices; ++j)
{
for (i = 0; i < rows; ++i)
{
struct Vertex* curr = &dstVertices[i+j*rows];
float s = i + 0.5f;
float t = j;
float cs,ct,ss,st;
cs = cosf(s * (2*GU_PI)/slices);
ct = cosf(t * (2*GU_PI)/rows);
ss = sinf(s * (2*GU_PI)/slices);
st = sinf(t * (2*GU_PI)/rows);
curr->nx = cs * ct;
curr->ny = cs * st;
curr->nz = ss;
curr->x = (radius + thickness * cs) * ct;
curr->y = (radius + thickness * cs) * st;
curr->z = thickness * ss;
}
}
for (j = 0; j < slices; ++j)
{
for (i = 0; i < rows; ++i)
{
unsigned short* curr = &dstIndices[(i+(j*rows))*6];
unsigned int i1 = (i+1)%rows, j1 = (j+1)%slices;
*curr++ = i + j * rows;
*curr++ = i1 + j * rows;
*curr++ = i + j1 * rows;
*curr++ = i1 + j * rows;
*curr++ = i1 + j1 * rows;
*curr++ = i + j1 * rows;
}
}
}
|
|
|
| Back to top |
|
 |
bengarney
Joined: 22 Oct 2005 Posts: 24
|
Posted: Sun Nov 20, 2005 2:38 pm Post subject: And a solution... |
|
|
And the new glViewport.c, that seems to be working - but takes a topleft x,y instead of a bottomleft, so beware!
| Code: |
#include "pspgl_internal.h"
void glViewport (GLint x, GLint y, GLsizei width, GLsizei height)
{
pspgl_curctx->viewport.x = x;
pspgl_curctx->viewport.y = y;
pspgl_curctx->viewport.width = width;
pspgl_curctx->viewport.height = height;
// Figure appropriate center values
int cx = 2048 - (pspgl_curctx->draw->width / 2) + (width / 2) + x;
int cy = 2048 - (pspgl_curctx->draw->height / 2) + (height / 2) + y;
/* Viewport / Screen Offset */
sendCommandi(CMD_OFFSETX, ((2048 - (480/2))) << 4);
sendCommandi(CMD_OFFSETY, ((2048 - (272/2))) << 4);
/* Viewport Size (X/Y, Width/Height) */
sendCommandf(66,(float)(width>>1));
sendCommandf(67,(float)(((-height) + ((-height) >> 31))>>1));
/* Viewport Center (X/Y) */
sendCommandf(69, (float) (cx));
sendCommandf(70, (float) (cy));
/* Drawing Rectangle */
y = 0; x = 0;
height = 272; width = 480;
sendCommandi(CMD_REGION1, (y << 10) | x);
sendCommandi(CMD_REGION2, (((y+height)-1) << 10) | ((x+width)-1));
return;
}
|
Don't need the error checking, as it'll draw fine with out of range values (as long as you stay within the 4k range, I assume...).
The Drawing Rect update is probably not needed either, but I do it anyway.
So, working mostly! :)
Luckily, I only call glViewport from two places so all I have to do is make it so that those two places don't correct for GL's bottom left convention.
Hope this can make it into the official PSPGL repo someday soon. :) |
|
| Back to top |
|
 |
jsgf
Joined: 12 Jul 2005 Posts: 254
|
Posted: Wed Nov 23, 2005 7:48 pm Post subject: |
|
|
| I just checked in a correct version of glViewport, which uses y=0 is bottom. I also fixed glScissor in the same way. I also added a "viewports" demo/test to exercise it. |
|
| Back to top |
|
 |
bengarney
Joined: 22 Oct 2005 Posts: 24
|
Posted: Thu Nov 24, 2005 5:42 am Post subject: |
|
|
| Thanks! |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|