I recently went back to my chroma-keying stuff and discovered that now my Radeon8500 applies a filter to glDrawPixels. Half a year ago it certainly didn’t do that and I fail to see where the spec allows it.
Puzzles me why, and it also gives me some new headaches. Now I just could start using EXT_texture_rectangle and use GL_NEAREST filtering. But ho hum.
Here’s a little glut app that will show you what I mean. And it will also show just why this bothers me:
I use the alpha test to conditionally discard pixels. This starts to break when the filter kicks in.
Also note that the luminance of the ‘texture’ fluctuates as a result of the filter (might not be visible depending on your gamma settings).
Use WSAD to move the thingy around, holding ALT will decrease movement speed below integer pixel positions, which makes it interesting.
//Make sure to link with glut //#include <windows.h> #include <gl/gl.h> #include <gl/glut.h> #include <gl/glati.h> #include <stdio.h> #include <malloc.h> typedef unsigned char ubyte; typedef unsigned short ushort; typedef unsigned int uint; char description[256]; bool init_done=false; PFNGLWINDOWPOS2IARBPROC glWindowPos2iARB; PFNGLWINDOWPOS2FARBPROC glWindowPos2fARB; ubyte* pixels; //raster position for drawing the pixel rectangle float raster_x=282.0f; float raster_y=208.0f; const char* const toggle_status_string(bool stat) { if (stat) return("on"); else return("off"); } void release_memory() { if (pixels) { free(pixels); pixels=NULL; } } void init_stuff() { glWindowPos2iARB=(PFNGLWINDOWPOS2IARBPROC)wglGetProcAddress("glWindowPos2iARB"); glWindowPos2fARB=(PFNGLWINDOWPOS2FARBPROC)wglGetProcAddress("glWindowPos2fARB"); glClearColor(0.0f,0.0f,0.0f,0.0f); //allocate small RGBA pixel rectangle pixels=(ubyte*)malloc(64*64*4); int x,y; //fill completely with opaque checkerboard green/blue for (y=0;y<64;++y) { for (x=0;x<64;++x) { ubyte* p=pixels+4*(x+64*y); if (((x>>1)^(y>>1))&1) { //green tile p[0]=0; p[1]=255; p[2]=0; } else { //blue tile p[0]=0; p[1]=0; p[2]=255; } p[3]=255; //full alpha on all tiles } } //draw an opaque white outline along the outer edge for (y=0;y<64;++y) { for (x=0;x<64;++x) { if ( ((y==0)| |(y==63)) | |((x==0)| |(x==63)) ) { ubyte* p=pixels+4*(x+64*y); p[0]=255; p[1]=255; p[2]=255; p[3]=255; } } } //'cut a hole' with completely transparent pink (alpha=0) for (y=16;y<48;++y) { for (x=16;x<48;++x) { ubyte* p=pixels+4*(x+64*y); p[0]=255; p[1]=0; p[2]=255; p[3]=0; //zero alpha } } atexit(release_memory); } void display_callback() { if (!init_done) { init_stuff(); init_done=true; } glClear(GL_COLOR_BUFFER_BIT); //enable alpha test, pass condition is a>0 glAlphaFunc(GL_GREATER,0); glEnable(GL_ALPHA_TEST); //set raster position glPixelZoom(1,1); glWindowPos2fARB(raster_x,raster_y); // glWindowPos2iARB(raster_x,raster_y); //NOTE: no pink pixels should be visible // no filtering is expected glDrawPixels(64,64,GL_RGBA,GL_UNSIGNED_BYTE,pixels); glutSwapBuffers(); } void idle_callback() { glutPostRedisplay(); } void keyboard_callback(unsigned char key,int x,int y) { ubyte upcase=key&0xDF; float delta; int modifiers=glutGetModifiers(); if (modifiers&GLUT_ACTIVE_SHIFT) delta=16.0f; else { if (modifiers&GLUT_ACTIVE_ALT) delta=0.125f; else delta=1.0f; } //wsad controls position of 'black hole' if (upcase=='A') raster_x-=delta; if (upcase=='D') raster_x+=delta; if (upcase=='W') raster_y+=delta; if (upcase=='S') raster_y-=delta; //clamp hole position if (raster_x>576) raster_x=576; if (raster_x<0) raster_x=0; if (raster_y>416) raster_y=416; if (raster_y<0) raster_y=0; sprintf(description,"Raster pos=%.3f/%.3f - hold SHIFT or ALT for different speeds",raster_x,raster_y); if (upcase=='X') sprintf(description,"height is %d",glutGet(GLUT_WINDOW_HEIGHT)); glutSetWindowTitle(description); glutPostRedisplay(); } int main(int argc,char** argv) { sprintf(description,"Use WSAD to move around, SHIFT/ALT modify speed"); glutInit(&argc,argv); glutInitWindowSize(640,480); glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE|GLUT_STENCIL); glutCreateWindow(description); glutDisplayFunc(display_callback); glutKeyboardFunc(keyboard_callback); glutIdleFunc(idle_callback); glutMainLoop(); return(0); }
edit: Whoops, wrong code snippet …
edit2: Whoops, had to rip my own mistakes out …
[This message has been edited by zeckensack (edited 02-08-2003).]
[This message has been edited by zeckensack (edited 02-08-2003).]
[This message has been edited by zeckensack (edited 02-08-2003).]