#define NES_HEIGHT 240
#define NES_WIDTH 256
static void SetOrthographicProjection();
static void ResetPerspectiveProjection();
static void glt_ChangeWindowSize( s32 width, s32 height );
static s32 g_WindowWidth;
static s32 g_WindowHeight;
static u32 g_RenderTargetTexture; // OpenGL texture handle.
void glt_Init(int* argc, char* argv[])
{
glutInit(argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA /*| GLUT_ALPHA*/ );
glutInitWindowPosition(0, 0);
glutInitWindowSize(NES_WIDTH, NES_HEIGHT);
glutCreateWindow("Test");
glutReshapeFunc(glt_ChangeWindowSize);
// Create a texture to copy into.
glGenTextures(1, &g_RenderTargetTexture);
glBindTexture(GL_TEXTURE_2D, g_RenderTargetTexture);
glTexImage2D(GL_TEXTURE_2D, 0, 4, NES_WIDTH, NES_WIDTH, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); // NES_WIDTH x NES_WIDTH to get a square, power-of-2 sized texture
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR/*GL_NEAREST preferred!*/);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
}
void glt_SetDisplayFunc( void (*func)(void) )
{
glutDisplayFunc( func );
}
void glt_ChangeWindowSize( s32 width, s32 height )
{
g_WindowWidth = width;
g_WindowHeight = height;
}
void glt_RunMainLoop()
{
glutMainLoop();
}
void glt_InvalidateScreen()
{
glutPostRedisplay();
}
void glt_TestDraw()
{
int x, y; // Screen pos.
f32 fScreenHeight;
f32 fScreenWidth;
f32 fXOffset;
// Clear screen to black.
glClearColor(0.0f,0.0f,0.0f,1.0f);
glClear(GL_COLOR_BUFFER_BIT /*| GL_DEPTH_BUFFER_BIT*/);
// No need for depth test, we'll draw back-to-front.
// TODO: Maybe we'll change this later so hardware can take care of it for us using the Z value.
glDisable(GL_DEPTH_TEST);
// Push modelview matrix (state leftover from 3D drawing).
glPushMatrix();
// Push projection.
SetOrthographicProjection(NES_WIDTH, NES_HEIGHT, TRUE);
glViewport(0, 0, NES_WIDTH, NES_HEIGHT); // == size of texture == NES resolution.
// Start from modelview scratch for 2D drawing.
glLoadIdentity();
// Small translation to get pixel-perfect positioning.
glTranslatef(0.375f, 0.375f, 0.0f);
// Draw.
glBegin(GL_POINTS);
for( y = 0; y < NES_HEIGHT; y++ )
{
for( x = 0; x < NES_WIDTH; x++ )
{
glColor3f( 0.0f, x%2==0?1.0f:0.5f, y>(NES_HEIGHT/2)?1.0f:0.0f );
glVertex2i( x, y );
}
}
glEnd();
//
// Copy the current framebuffer to a texture.
//
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, NES_WIDTH, NES_WIDTH, 0);
// Pop projection.
ResetPerspectiveProjection();
// Push projection.
SetOrthographicProjection(g_WindowWidth, g_WindowHeight, FALSE);
glViewport(0, 0, g_WindowWidth, g_WindowHeight); // Should always be == to current size of window!
glClearColor(0.2f,0.2f,0.2f,1.0f);
glClear(GL_COLOR_BUFFER_BIT); //Clear screen to gray color
glColor3f(0.0f,0.0f,1.0f); // Blue... but blue should not show since we use tex!!
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, g_RenderTargetTexture);
glBegin(GL_QUADS);
// Stretch to fit screen:
//glTexCoord2f(0.0f,0.0f); glVertex2i( 0, 0 );
//glTexCoord2f(1.0f,0.0f); glVertex2i( g_WindowWidth, 0 );
//glTexCoord2f(1.0f,1.0f*NES_HEIGHT/NES_WIDTH); glVertex2i( g_WindowWidth, g_WindowHeight );
//glTexCoord2f(0.0f,1.0f*NES_HEIGHT/NES_WIDTH); glVertex2i( 0, g_WindowHeight );
// Fit to height, preserve aspect ratio:
fScreenHeight = g_WindowHeight*NES_WIDTH/NES_HEIGHT; // Goes overboard, due to power-of-2 texture.
fScreenWidth = fScreenHeight;
fXOffset = (g_WindowWidth-fScreenWidth)/2.0f;
glTexCoord2f(0.0f,0.0f); glVertex2i( fXOffset, 0 );
glTexCoord2f(1.0f,0.0f); glVertex2i( fXOffset+fScreenWidth, 0 );
glTexCoord2f(1.0f,1.0f); glVertex2i( fXOffset+fScreenWidth, fScreenHeight );
glTexCoord2f(0.0f,1.0f); glVertex2i( fXOffset, fScreenHeight );
glEnd();
// Pop projection.
ResetPerspectiveProjection();
// Pop modelview matrix (restore state for 3D drawing).
glPopMatrix();
glutSwapBuffers();
}
void SetOrthographicProjection(s32 width, s32 height, BOOL bFlipY)
{
// switch to projection mode
glMatrixMode(GL_PROJECTION);
// save previous matrix which contains the
//settings for the perspective projection
glPushMatrix();
// reset matrix
glLoadIdentity();
// set a 2D orthographic projection
gluOrtho2D(0, width, 0, height);
if( bFlipY )
{
// invert the y axis, down is positive
glScalef(1, -1, 1);
// mover the origin from the bottom left corner
// to the upper left corner
glTranslatef(0, -height, 0);
}
glMatrixMode(GL_MODELVIEW);
}
void ResetPerspectiveProjection()
{
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
}
Fixed-resolution ortho projection
Hey all,
Trying to do pixel-perfect 2D plotting for a console emulator. [GLUT & C]
Currently using an orthographic projection and glBegin(GL_POINTS)/glEnd(). Since I want to be able to zoom 2x/3x, etc, I am using glCopyTexImage2d() after writing to the framebuffer to copy the results into a texture to be aligned to a screen-aligned quad (using this instead of pbuffers or PBO's, for max compatibility).
Anyhow, it's all working dandy, except for when I disable GL_LINEAR filtering for the magnification of textures. I would prefer to use GL_NEAREST, so that I know for sure that I have my pixel perfect positioning correct --> 1 texel for each pixel (or one texel for 4 pixels in the case of 2X zoom, etc).
So I am not sure if I am off-by-one somewhere (I am doing a 0.375,0.375 translate as well, as suggested by opengl.org), and/or don't know my filtering params well enough. Any help is appreciated. :)
Screenshot of what my test image looks like (vertical stripes of light&dark green&blue):
[Edited by - discman1028 on October 26, 2008 9:00:02 PM]
Actually, it seems GL_NEAREST works fine for minification, but I get a black screen upon GL_NEAREST magnification upon resizing my window to be larger, unless I use GL_LINEAR...
(In fact magnification is the important factor for me, I will probably never be minifying my rander target anyways.)
[Edited by - discman1028 on October 26, 2008 8:51:58 PM]
(In fact magnification is the important factor for me, I will probably never be minifying my rander target anyways.)
[Edited by - discman1028 on October 26, 2008 8:51:58 PM]
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement