//Demonstrates a flaw in Dot3 operations on the ATI Radeon's (original) third texture environment
//Flaw can be reproduced on Win98SE systems with the official driver set 4.13.9009
//version number of ATIICDXX.DLL is 6.13.10.6014
//reported GL version is 1.3.2454
//Make sure to link with glut
#include <windows.h>
#include <gl/gl.h>
#include <gl/glati.h>
#include <gl/glu.h>
#include <gl/glut.h>
#include <stdio.h>
#include <malloc.h>
char description[64];
PFNGLACTIVETEXTUREARBPROC glActiveTextureARB;
static unsigned char* texture_data=NULL;
static GLuint tex_obj=0;
static int dot_unit=2;
void
init_gl_stuff()
{
glActiveTextureARB=(PFNGLACTIVETEXTUREARBPROC)wglGetProcAddress("glActiveTextureARB");
glClearColor(0.0f,0.0f,0.0f,0.0f);
glGenTextures(1,&tex_obj);
texture_data=(unsigned char*)malloc(64*64*3);
//generate nice texture
for (int x=0;x<64;++x)
{
for (int y=0;y<64;++y)
{
texture_data[(x+64*y)*3]=(unsigned char)4*x;
texture_data[(x+64*y)*3+1]=(unsigned char)4*y;
texture_data[(x+64*y)*3+2]=(unsigned char)255-x-y;
}
}
glBindTexture(GL_TEXTURE_2D,tex_obj);
glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,64,64,0,GL_RGB,GL_UNSIGNED_BYTE,texture_data);
free(texture_data);
texture_data=NULL;
//mipmaps not required for this demonstration
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE_EXT);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE_EXT);
//whip up a minimum projection
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0,640,480,0);
//set all three texture environments to COMBINE_ARB operation, select same sources and operands
//tex environment0 will do decal texturing
glEnable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE_ARB);
glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB_ARB,GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE0_RGB_ARB,GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV,GL_OPERAND0_RGB_ARB,GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE1_RGB_ARB,GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV,GL_OPERAND1_RGB_ARB,GL_SRC_COLOR);
//tex environment1 will pass through
glActiveTextureARB(GL_TEXTURE1_ARB);
glBindTexture(GL_TEXTURE_2D,tex_obj);
glEnable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE_ARB);
glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB_ARB,GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE0_RGB_ARB,GL_PREVIOUS_ARB);
glTexEnvi(GL_TEXTURE_ENV,GL_OPERAND0_RGB_ARB,GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE1_RGB_ARB,GL_PREVIOUS_ARB);
glTexEnvi(GL_TEXTURE_ENV,GL_OPERAND1_RGB_ARB,GL_SRC_COLOR);
//tex environment2 will perform the dot3 operation
glActiveTextureARB(GL_TEXTURE2_ARB);
glBindTexture(GL_TEXTURE_2D,tex_obj);
glEnable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE_ARB);
glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB_ARB,GL_DOT3_RGB_ARB);
glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE0_RGB_ARB,GL_PREVIOUS_ARB);
glTexEnvi(GL_TEXTURE_ENV,GL_OPERAND0_RGB_ARB,GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE1_RGB_ARB,GL_PREVIOUS_ARB);
glTexEnvi(GL_TEXTURE_ENV,GL_OPERAND1_RGB_ARB,GL_SRC_COLOR);
}
int
cleanup()
{
if (tex_obj)
{
glDeleteTextures(1,&tex_obj);
tex_obj=0;
}
return(0);
}
void
display()
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glBegin(GL_QUADS);
glTexCoord2f(0.0f,0.0f);
glVertex2f(0.0f,0.0f);
glTexCoord2f(1.0f,0.0f);
glVertex2f(320.0f,0.0f);
glTexCoord2f(1.0f,1.0f);
glVertex2f(320.0f,320.0f);
glTexCoord2f(0.0f,1.0f);
glVertex2f(0.0f,320.0f);
glEnd();
glutSwapBuffers();
return;
}
void
keyboard(unsigned char key,int x,int y)
{
//check for spacebar
if (key!=0x20) return;
//flip the switch
++dot_unit;
if (dot_unit==3) dot_unit=0;
//reassign texture environments
switch (dot_unit)
{
default:
case(0):
glActiveTextureARB(GL_TEXTURE0_ARB);
glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB_ARB,GL_DOT3_RGB_ARB);
glActiveTextureARB(GL_TEXTURE1_ARB);
glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB_ARB,GL_REPLACE);
glActiveTextureARB(GL_TEXTURE2_ARB);
glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB_ARB,GL_REPLACE);
break;
case(1):
glActiveTextureARB(GL_TEXTURE0_ARB);
glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB_ARB,GL_REPLACE);
glActiveTextureARB(GL_TEXTURE1_ARB);
glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB_ARB,GL_DOT3_RGB_ARB);
glActiveTextureARB(GL_TEXTURE2_ARB);
glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB_ARB,GL_REPLACE);
break;
case(2):
glActiveTextureARB(GL_TEXTURE0_ARB);
glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB_ARB,GL_REPLACE);
glActiveTextureARB(GL_TEXTURE1_ARB);
glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB_ARB,GL_REPLACE);
glActiveTextureARB(GL_TEXTURE2_ARB);
glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB_ARB,GL_DOT3_RGB_ARB);
break;
}
//update description
sprintf(description,"Dot3 operation on texture environment%u",dot_unit);
glutSetWindowTitle(description);
glutPostRedisplay();
}
int
main(int argc,char** argv)
{
sprintf(description,"Press space to reassign texture environments");
glutInit(&argc,argv);
glutInitWindowSize(640,480);
glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE);
glutCreateWindow(description);
init_gl_stuff();
glutDisplayFunc(display);
glutKeyboardFunc(keyboard);
onexit(cleanup);
glutMainLoop();
return(0);
}