icmp.c 4.84 KB
#include "stdlib.h"
#include "GL/glx.h"
#include <X11/keysym.h>
#include "PRimage.h"

short rbuf[8192]; 
short gbuf[8192]; 
short bbuf[8192]; 

Display *dpy;
Window window;

static void make_window(int width, int height, char *name, int border);

main(int argc,char *argv[]) {
    IMAGE *image[2];
    int x, y, xsize, ysize;
    int zsize, i, show_diff = 0, which = 0;
    unsigned char *buf[2];
    int zoom = 1;

    while(argc > 1 && argv[1][0] == '-') {
        switch(argv[1][1]) {
	case 'z':
	    zoom = 2;
	    break;
	default:
	    goto usage;
	}
	argc--; argv++;
    }
    if(argc < 3) {
usage:
	fprintf(stderr,"usage: icmp [-z] image1.rgb image2.rgb\n");
	exit(1);
    } 
    for(i = 0; i < 2; i++) {
	if( (image[i]=iopen(argv[i+1],"r")) == NULL ) {
	    fprintf(stderr,"icmp: can't open input file %s\n",argv[i+1]);
	    exit(1);
	}
	if (i == 1 && (xsize != image[i]->xsize || ysize != image[i]->ysize ||
	    zsize != image[i]->zsize)) {
	    fprintf(stderr, "image sizes are different\n");
	    exit(1);
	}
	xsize = image[i]->xsize;
	ysize = image[i]->ysize;
	zsize = image[i]->zsize;
	if(zsize<3) {
	    fprintf(stderr,"image: this is not an RGB image file\n");
	    exit(1);
	}
	buf[i] = (unsigned char *)malloc(xsize*ysize*3);
	for(y=0; y<ysize; y++) {
	    getrow(image[i],rbuf,y,0);
	    getrow(image[i],gbuf,y,1);
	    getrow(image[i],bbuf,y,2);
	    for(x = 0; x < xsize; x++) {
		buf[i][(y*xsize+x)*3+0] = rbuf[x];
		buf[i][(y*xsize+x)*3+1] = gbuf[x];
		buf[i][(y*xsize+x)*3+2] = bbuf[x];
	    }
	}
    }
    make_window(xsize*zoom, ysize*zoom, argv[1], 1);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glMatrixMode(GL_PROJECTION);
    glOrtho(0, image[0]->xsize*zoom, 0, image[0]->ysize*zoom, -1, 1);
    glMatrixMode(GL_MODELVIEW);
    glRasterPos2i(0, 0);
    glPixelZoom(zoom, zoom);
    for(;;) {
	XEvent ev;
	XNextEvent(dpy, &ev);
	switch(ev.type) {
	case Expose:
redraw:
	    glClearColor(0.5, 0.5, 0.5, 0.5);
	    glClear(GL_COLOR_BUFFER_BIT);
	    glDrawPixels(xsize, ysize, GL_RGB, GL_UNSIGNED_BYTE, buf[which]);

	    if (!show_diff) goto out;
	    for(y = 0; y < ysize; y++) {
	    	for(x = 0; x < xsize; x++) {
		    if (buf[0][(y*xsize+x)*3+0] != buf[1][(y*xsize+x)*3+0] ||
			buf[0][(y*xsize+x)*3+1] != buf[1][(y*xsize+x)*3+1] ||
			buf[0][(y*xsize+x)*3+2] != buf[1][(y*xsize+x)*3+2]) {
			static GLubyte white[3] = { 0xff, 0xff, 0xff };
			glRasterPos2i(x*zoom, y*zoom);
			glDrawPixels(1, 1,  GL_RGB, GL_UNSIGNED_BYTE, white);
			glRasterPos2i(0, 0);
		    }
		}
	    }
out:
	    glXSwapBuffers(dpy, window);
	    break;
	case KeyPress: {
	    char buf[100];
	    KeySym ks;

	    (void)XLookupString(&ev.xkey, buf, sizeof(buf), &ks, 0);
	    switch (ks) {
	    case XK_Escape:
	    case XK_q:
		exit(0);
	    case XK_space:
	    	which ^= 1;
		XStoreName(dpy, window, argv[1+which]);
		goto redraw;
	    }
	    break;
	}
	case ButtonPress:
	    if (ev.xbutton.button == Button1) {
		show_diff = 1;
		goto redraw;
	    }
	    break;
	case ButtonRelease:
	    if (ev.xbutton.button == Button1) {
		show_diff = 0;
		goto redraw;
	    }
	    break;
	}
    }
}

static int attributeList[] = { GLX_RGBA, GLX_RED_SIZE, 1, GLX_DOUBLEBUFFER, None };

void
noborder(Display *dpy, Window win) {
    struct { long flags,functions,decorations,input_mode; } *hints;
    int fmt;
    unsigned long nitems,byaf;
    Atom type,mwmhints = XInternAtom(dpy,"_MOTIF_WM_HINTS",False);

    XGetWindowProperty(dpy,win,mwmhints,0,4,False, mwmhints,&type,&fmt,&nitems,&byaf,(unsigned char**)&hints);

    if (!hints) hints = (void *)malloc(sizeof *hints);
    hints->decorations = 0;
    hints->flags |= 2;

    XChangeProperty(dpy,win,mwmhints,mwmhints,32,PropModeReplace,(unsigned char *)hints,4);
    XFlush(dpy);
    free(hints);
}

static void
make_window(int width, int height, char *name, int border) {
    XVisualInfo *vi;
    XSetWindowAttributes swa;
    GLXContext cx;
    XSizeHints sizehints;

    dpy = XOpenDisplay(0);
    if (!(vi = glXChooseVisual(dpy, DefaultScreen(dpy), attributeList))) {
	printf("can't find requested visual\n");
	exit(1);
    }
    cx = glXCreateContext(dpy, vi, 0, GL_TRUE);

    swa.colormap = XCreateColormap(dpy, RootWindow(dpy, vi->screen),
                           vi->visual, AllocNone);
    sizehints.flags = PMinSize | PMaxSize;
    sizehints.min_width = sizehints.max_width = width;
    sizehints.min_height = sizehints.max_height = height;

    swa.border_pixel = 0;
    swa.event_mask = ExposureMask | StructureNotifyMask | KeyPressMask | ButtonPressMask | ButtonReleaseMask;
    window = XCreateWindow(dpy, RootWindow(dpy, vi->screen), 0, 0, width, height,
                        0, vi->depth, InputOutput, vi->visual,
                        CWBorderPixel|CWColormap|CWEventMask, &swa);
    XMapWindow(dpy, window);
    XSetStandardProperties(dpy, window, name, name,
	    None, (void *)0, 0, &sizehints);

    if (!border) noborder(dpy, window);

    glXMakeCurrent(dpy, window, cx);
}