/** * Dissolve between two images using randomized/patterned stencil buffer * and varying stencil ref. * * Brian Paul * 29 Jan 2010 */ #include #include #include #include #include #include "readtex.h" #define FILE1 "../images/bw.rgb" #define FILE2 "../images/arch.rgb" static int Win; static int WinWidth = 400, WinHeight = 400; static GLboolean Anim = GL_TRUE; static int ImgWidth[2], ImgHeight[2]; static GLenum ImgFormat[2]; static GLubyte *Image[2]; static GLfloat ScaleX[2], ScaleY[2]; static GLubyte StencilRef = 0; static int Mode = 0; static void Idle(void) { StencilRef = (GLint) (glutGet(GLUT_ELAPSED_TIME) / 10); glutPostRedisplay(); } static void FillRandomPixels(GLubyte *b) { int i; for (i = 0; i < WinWidth * WinHeight; i++) { b[i] = rand() & 0xff; } } static void FillRandomRects(GLubyte *b) { int i; memset(b, 0, WinWidth * WinHeight); for (i = 0; i < 256; i++) { int x = rand() % WinWidth; int y = rand() % WinHeight; int w = rand() % 60; int h = rand() % 60; int ix, iy; if (x + w > WinWidth) w = WinWidth - x; if (y + h > WinHeight) h = WinHeight - y; for (iy = 0; iy < h; iy++) { for (ix = 0; ix < w; ix++) { int p = (y + iy) * WinWidth + x + ix; b[p] = i; } } } } static void FillWipe(GLubyte *b) { int iy, ix; memset(b, 0, WinWidth * WinHeight); for (iy = 0; iy < WinHeight; iy++) { for (ix = 0; ix < WinWidth; ix++) { int p = iy * WinWidth + ix; b[p] = 2 * ix + iy / 2; } } } static void FillMoire(GLubyte *b) { int iy, ix; memset(b, 0, WinWidth * WinHeight); for (iy = 0; iy < WinHeight; iy++) { for (ix = 0; ix < WinWidth; ix++) { int p = iy * WinWidth + ix; b[p] = (ix / 2) * (ix / 2) - (iy / 2) * (iy / 2); } } } static void FillWaves(GLubyte *b) { int iy, ix; memset(b, 0, WinWidth * WinHeight); for (iy = 0; iy < WinHeight; iy++) { for (ix = 0; ix < WinWidth; ix++) { int p = iy * WinWidth + ix; float x = 8.0 * 3.1415 * ix / (float) WinWidth; b[p] = (int) (25.0 * sin(x) ) - iy*2; } } } typedef void (*FillFunc)(GLubyte *b); static FillFunc Funcs[] = { FillRandomPixels, FillRandomRects, FillWipe, FillMoire, FillWaves }; #define NUM_MODES (sizeof(Funcs) / sizeof(Funcs[0])) static void InitStencilBuffer(void) { GLubyte *b = malloc(WinWidth * WinHeight); Funcs[Mode](b); glStencilFunc(GL_ALWAYS, 0, ~0); glPixelZoom(1.0, 1.0); glDrawPixels(WinWidth, WinHeight, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, b); free(b); } static void Draw(void) { glClear(GL_COLOR_BUFFER_BIT); glPixelZoom(ScaleX[0], ScaleY[0]); glStencilFunc(GL_LESS, StencilRef, ~0); glDrawPixels(ImgWidth[0], ImgHeight[0], ImgFormat[0], GL_UNSIGNED_BYTE, Image[0]); glPixelZoom(ScaleX[1], ScaleY[1]); glStencilFunc(GL_GEQUAL, StencilRef, ~0); glDrawPixels(ImgWidth[1], ImgHeight[1], ImgFormat[1], GL_UNSIGNED_BYTE, Image[1]); glutSwapBuffers(); } static void Reshape(int width, int height) { WinWidth = width; WinHeight = height; glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 25.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.0, 0.0, -15.0); InitStencilBuffer(); ScaleX[0] = (float) width / ImgWidth[0]; ScaleY[0] = (float) height / ImgHeight[0]; ScaleX[1] = (float) width / ImgWidth[1]; ScaleY[1] = (float) height / ImgHeight[1]; } static void Key(unsigned char key, int x, int y) { (void) x; (void) y; switch (key) { case 'a': case ' ': Anim = !Anim; if (Anim) glutIdleFunc(Idle); else glutIdleFunc(NULL); break; case 'i': InitStencilBuffer(); break; case '-': StencilRef--; break; case '+': StencilRef++; break; case 'm': Mode = (Mode + 1) % NUM_MODES; InitStencilBuffer(); break; case 27: glutDestroyWindow(Win); exit(0); break; } glutPostRedisplay(); } static void Init(void) { Image[0] = LoadRGBImage(FILE1, &ImgWidth[0], &ImgHeight[0], &ImgFormat[0]); if (!Image[0]) { printf("Couldn't read %s\n", FILE1); exit(0); } Image[1] = LoadRGBImage(FILE2, &ImgWidth[1], &ImgHeight[1], &ImgFormat[1]); if (!Image[1]) { printf("Couldn't read %s\n", FILE2); exit(0); } glEnable(GL_STENCIL_TEST); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); } int main(int argc, char *argv[]) { glutInitWindowSize(WinWidth, WinHeight); glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_STENCIL); Win = glutCreateWindow(argv[0]); glutReshapeFunc(Reshape); glutKeyboardFunc(Key); glutDisplayFunc(Draw); if (Anim) glutIdleFunc(Idle); Init(); printf("Keys:\n"); printf(" a/SPACE toggle animation\n"); printf(" +/- single step\n"); printf(" i re-init pattern\n"); printf(" m change pattern/dissolve mode\n"); printf(" ESC exit\n"); glutMainLoop(); return 0; }