#include #include #include #include #include #include #include #include #include #include #include #include "global.h" /* Package file */ /* External Interface init_display exit_display Internals img_width, img_height Maybe main program should create picW then pass that along for usage Redisplay needed only for setting the app up */ extern "C" { int XShmGetEventBase(Display *); } enum DisplayMethod { NONE, Pseudo8, Tcolor8, Tcolor16, Tcolor32, Tcolorany }; static int img_width, img_height; static XImage *ximage; static Display *display; static GC gc; static DisplayMethod dispmethod = NONE; static unsigned char r_map[256]; static Window picwindow; inline int min(int x, int y) { return ((x < y) ? x : y); } inline int max(int x, int y) { return (x > y) ? x : y; } inline int color_index(u_char y, u_char u, u_char v) { return ( (y&0xf0) | ((u&0xc0) >> 4) | ((v&0xc0) >> 6) ); #ifdef OLD_WORKING // return ((y & 0xf0) | (((u - 80)&0x60) >> 3) | // ( ((v -80) &0x60) >> 5)); short up = short(u); short vp = short(v); return ((y & 0xf0) | ((max((up - 80),0)&0x60) >> 3) | ( ( max((vp -80),0) &0x60) >> 5)) ; #endif } static int HandleXError(Display *dpy, XErrorEvent *event); static void InstallXErrorHandler(void); static void DeInstallXErrorHandler(void); static int shmem_flag; static XShmSegmentInfo shminfo1; static int gXErrorFlag; static int CompletionType = -1; static int HandleXError(Display *dpy, XErrorEvent *event) { gXErrorFlag = 1; return 0; } static void InstallXErrorHandler() { XSetErrorHandler(HandleXError); XFlush(display); } static void DeInstallXErrorHandler() { XSetErrorHandler(NULL); XFlush(display); } void finish_display(void) { if(shmem_flag) { XShmDetach(display, &shminfo1); shmdt(shminfo1.shmaddr); shmctl(shminfo1.shmid, IPC_RMID, 0); } else // XDestroyImage(ximage); delete[] ximage->data; } /* _ _ _ _ _ _ _ _ 16 .. 235 | Y | | 0.257 0.504 0.098 || R | | 16 | 16 .. 240 | Cb | = | -0.148 -0.291 0.439 || G | + | 128| 16 .. 240 | Cr | | 0.439 -0.368 0.071 || B | | 128| - - - - - - - - rgb = inv(yuvmat) * yu - addmat _ _ _ _ _ _ | R | | 76293 -117 104581 || Y -16| | G | = | 76293 -25654 -53312 || Cb -128| | B | | 76293 132240 -82 || Cr -128| - - - - - - */ static unsigned long r_shift_bits, g_shift_bits, b_shift_bits; static unsigned long red_mask, green_mask, blue_mask; static u_long getbits2shift(unsigned long mask) { u_long rc = 0, tmp; for(rc=0; rc < (sizeof(mask) << 3); rc++) { tmp = (0x80000000 >> rc) & mask; if(tmp) break; } return rc; } inline u_long yuv_2_pixel(u_char y, u_char u, u_char v) { int yp, up, vp, rtmp, gtmp, btmp; u_long pixel, r, g, b; /* Lets define some variables */ yp = int(y) - 16; up = int(u) - 128; vp = int(v) - 128; /* Option 1: Shift, rangelimit, then shift back using the color mask info provided by X and then OR Option 2: Shift the right amount, using info provided by X, range limit using the color mask, and then OR We know the masks, From them we can obtain the shift_bit numbers Option 3: Shift left, instead of right to put it up against the 32 bit boundary then shift right the correct amount, should be easy to determine. Then apply mask and OR */ rtmp = 76293 * yp -117 * up +104581 * vp; gtmp = 76293 * yp -25654 * up -53312 * vp; btmp = 76293 * yp +132240 * up -82 * vp; rtmp = max(rtmp, 0); rtmp = min(rtmp, 16777215); gtmp = max(gtmp, 0); gtmp = min(gtmp, 16777215); btmp = max(btmp, 0); btmp = min(btmp, 16777215); r = u_long(rtmp) << 8; g = u_long(gtmp) << 8; b = u_long(btmp) << 8; pixel = ((r>>r_shift_bits) & red_mask) | ((g>>g_shift_bits) & green_mask) | ((b>>b_shift_bits) & blue_mask); return pixel; } static void confpseudocolmap(Widget top, int screen, Visual *visual) { Colormap cmap; int r_y, r_u, r_v; int r_r, r_g, r_b; int count = 0; XColor xcolor; XColor r_xcolor; double inv_yuv[3][3] = { { 1.16414435389988, -0.00178889771362, 1.59578620543534}, { 1.16414435389988, -0.39144276434224, -0.81348206850779}, { 1.16414435389988, 2.01782550960090, -0.00124583947913} }; int uv_range[4] = {80, 112, 144, 176}; /* create private colormap */ cmap = XCreateColormap(display, DefaultRootWindow(display), visual, AllocNone); xcolor.red = 0; xcolor.blue = 0; xcolor.green = 0; XAllocColor(display, cmap, &xcolor); xcolor.red = 0xffff; xcolor.blue = 0xffff; xcolor.green = 0xffff; XAllocColor(display, cmap, &xcolor); XtVaSetValues(top, XtNcolormap, cmap, NULL); // * the allocated colors correspond to the following Y, U and V values: // * Y: 40, 56, 72, 88, 104, 120, 136, 152, 168, 184, 200, 216, 232 // * U,V: -48, -16, 16, 48 // * // u,v 90,122,154,186 for(r_y = 0; r_y < 241; r_y += 16) // for(r_u=80; r_u <178; r_u +=32) for(int j=0; j <4; j++) { r_u = uv_range[j]; // for(r_v=80; r_v <178; r_v += 32) { for(int k=0; k <4; k++) { r_v = uv_range[k]; r_r = int(inv_yuv[0][0] * double(r_y - 16) + inv_yuv[0][1] * double(r_u - 128) + inv_yuv[0][2] * double(r_v - 128)); r_g = int(inv_yuv[1][0] * double(r_y - 16) + inv_yuv[1][1] * double(r_u - 128) + inv_yuv[1][2] * double(r_v - 128)); r_b = int(inv_yuv[2][0] * double(r_y - 16) + inv_yuv[2][1] * double(r_u - 128) + inv_yuv[2][2] * double(r_v - 128)); r_xcolor.flags = 0; r_xcolor.flags = DoRed | DoGreen | DoBlue; r_r = max(r_r, 0); r_r = min(r_r, 255); r_g = max(r_g, 0); r_g = min(r_g, 255); r_b = max(r_b, 0); r_b = min(r_b, 255); r_xcolor.red = r_r << 8; r_xcolor.green = r_g << 8; r_xcolor.blue = r_b << 8; if (XAllocColor(display, cmap, &r_xcolor) != 0) { r_map[ color_index(r_y, r_u, r_v) ] = r_xcolor.pixel; count++; } else { fprintf(stderr, "Couldn't alloc color\n"); } } } fprintf(stderr, "Pseudo colormap allocated with %d colors\n", count); } /* connect to server, create and map window, * allocate colors and (shared) memory */ void init_display(Widget toplevel, Widget picturewindow, int hsize, int vsize) { char dummy; int screen; XVisualInfo vinfo; int default_depth; int bytes_per_pixel; img_width = hsize; img_height = vsize; XtAddEventHandler(picturewindow, ExposureMask, FALSE, Redisplay, NULL); display = XtDisplay(picturewindow); if (display == NULL) fprintf(stderr, "Can not open display\n"); picwindow = XtWindow(picturewindow); screen = DefaultScreen(display); default_depth = DefaultDepth(display, screen); dispmethod = NONE; /* if depth is 8 try pseudo color else try true color If we have a screen of color higher than 8, we will determine usable depth when we create the image */ if(default_depth == 8) { if (XMatchVisualInfo(display, screen, default_depth, PseudoColor, &vinfo)) dispmethod = Pseudo8; else if(XMatchVisualInfo(display,screen, default_depth, TrueColor, &vinfo)) dispmethod = Tcolor8; } else if(XMatchVisualInfo(display,screen, default_depth, TrueColor, &vinfo)) dispmethod = Tcolorany; if(dispmethod == NONE) { fprintf(stderr, "Couldn't find PseudoColor or TrueColor display\n"); exit(0); } /* Only useful for true color display */ red_mask = vinfo.red_mask; green_mask = vinfo.green_mask; blue_mask = vinfo.blue_mask; r_shift_bits = getbits2shift(red_mask); g_shift_bits = getbits2shift(green_mask); b_shift_bits = getbits2shift(blue_mask); gc = XCreateGC(display, DefaultRootWindow(display), 0, 0); XtVaSetValues(toplevel, XtNvisual, vinfo.visual, NULL); if(dispmethod == Pseudo8) confpseudocolmap(toplevel, screen, vinfo.visual); if (XShmQueryExtension(display)) shmem_flag = 1; else { shmem_flag = 0; fprintf(stderr, "Shared memory not supported\nReverting to normal Xlib\n"); } if (shmem_flag) CompletionType = XShmGetEventBase(display) + ShmCompletion; InstallXErrorHandler(); if (shmem_flag) { ximage = XShmCreateImage(display, vinfo.visual, default_depth, ZPixmap, NULL, &shminfo1, hsize, vsize); if( ximage == NULL) { fprintf(stderr, "Shared memory error, using normal Xlib\n"); goto shmemerror; } shminfo1.shmid = shmget(IPC_PRIVATE, ximage->bytes_per_line * ximage->height, IPC_CREAT | 0777); if (shminfo1.shmid<0) { XDestroyImage(ximage); fprintf(stderr, "Shared memory error, disabling \n"); goto shmemerror; } shminfo1.shmaddr = (char *) shmat(shminfo1.shmid, 0, 0); if (shminfo1.shmaddr==((char *) -1)) { XDestroyImage(ximage); fprintf(stderr, "Shared memory error, disabling (address error)\n"); goto shmemerror; } ximage->data = shminfo1.shmaddr; shminfo1.readOnly = False; XShmAttach(display, &shminfo1); XSync(display, False); if (gXErrorFlag) { /* Ultimate failure here. */ XDestroyImage(ximage); shmdt(shminfo1.shmaddr); fprintf(stderr, "Shared memory error, disabling.\n"); gXErrorFlag = 0; goto shmemerror; } else { shmctl(shminfo1.shmid, IPC_RMID, 0); } fprintf(stderr, "Sharing memory.\n"); } else { shmemerror: shmem_flag = 0; ximage = XCreateImage(display,vinfo.visual,default_depth, ZPixmap,0,&dummy, hsize,vsize,8,0); ximage->data = new char[ximage->bytes_per_line * ximage->height]; } { /* Set correct byte ordering */ u_long garbage = 0x11000022; u_long garbage2 = 0x22000011; if(ntohl(garbage) == garbage) ximage->byte_order = MSBFirst; else if(ntohl(garbage) == garbage2) ximage->byte_order = LSBFirst; else { /* Unknown byte order */ fprintf(stderr, "unknown byte order of host\n"); finish_display(); exit(0); } } XInitImage(ximage); bytes_per_pixel = ximage->bytes_per_line / hsize; if(dispmethod != Pseudo8) { switch(bytes_per_pixel) { case 1: dispmethod = Tcolor8; break; case 2: dispmethod = Tcolor16; break; case 4: dispmethod = Tcolor32; break; default: fprintf(stderr, "TrueColor display needs %d bytes/pixel unsupported\n", bytes_per_pixel); } } DeInstallXErrorHandler(); } void Redisplay(Widget w, XtPointer client, XEvent *ev, Boolean *) { if(ev->xexpose.count != 0) return; XClearWindow(display, picwindow); display_image(False); } void display_image(Bool send_event) { /* display dithered image */ if (shmem_flag) { XShmPutImage(display, picwindow, gc, ximage, 0, 0, 0,0, img_width, img_height, send_event); XFlush(display); if(send_event == True) { while (1) { XEvent xev; XNextEvent(display, &xev); if (xev.type == CompletionType) break; } } } else { XPutImage(display, picwindow, gc, ximage, 0, 0,0,0, img_width, img_height); } } template void render_tcolordpy(T_t *ximgdata, u_char *ydata, u_char *udata, u_char *vdata, int hsize, int vsize) { u_char *y1, *y2, *u, *v; T_t *img1, *img2; y1 = ydata; y2 = ydata + hsize; u = udata; v = vdata; img1 = ximgdata; img2 = ximgdata + hsize; for(int j=0; j < vsize; j+= 2) { for(int i=0; i < hsize; i+= 2) { *img1++ = (T_t)yuv_2_pixel(*y1++, *u, *v); *img1++ = (T_t)yuv_2_pixel(*y1++, *u, *v); *img2++ = (T_t)yuv_2_pixel(*y2++, *u, *v); *img2++ = (T_t)yuv_2_pixel(*y2++, *u, *v); u++; v++; } y1 += hsize ; y2 += hsize ; img1 += hsize; img2 += hsize; } } void render_pseudodpy(u_char *ximgdata, u_char *ydata, u_char *udata, u_char *vdata, int hsize, int vsize) { u_char *y1, *y2, *u, *v, *img1, *img2; y1 = ydata; y2 = ydata + hsize; u = udata; v = vdata; img1 = ximgdata; img2 = ximgdata + hsize; for(int j=0; j < vsize; j+= 2) { for(int i=0; i < hsize; i+= 2) { /* Line 1, col1 */ *img1++ = r_map[color_index(*y1++, *u, *v)]; /* Line 1, col2 */ *img1++ = r_map[color_index(*y1++, *u, *v)]; /* Line 2 of image */ *img2++ = r_map[color_index(*y2++, *u, *v)]; /* Line 2, col2 */ *img2++ = r_map[color_index(*y2++, *u, *v)]; u++; v++; } y1 += hsize ; y2 += hsize ; img1 += hsize; img2 += hsize; } } void render_image(u_char *ydata, u_char *udata, u_char *vdata, int hsize, int vsize) { switch(dispmethod) { case Pseudo8: render_pseudodpy((u_char*)ximage->data, ydata,udata,vdata,hsize, vsize); break; case Tcolor8: render_tcolordpy((u_char*)ximage->data, ydata, udata, vdata, hsize, vsize); break; case Tcolor16: render_tcolordpy((u_short *)ximage->data, ydata, udata, vdata, hsize, vsize); break; case Tcolor32: render_tcolordpy((u_long *)ximage->data, ydata, udata, vdata, hsize, vsize); break; case Tcolorany: case NONE: fprintf(stderr, "render request for unsupported display\n"); } }