Revision: 75437
          http://sourceforge.net/p/brlcad/code/75437
Author:   starseeker
Date:     2020-04-17 16:14:01 +0000 (Fri, 17 Apr 2020)
Log Message:
-----------
Take a stab at pushing the image writing into the backend.  For the Dm object 
that looks like it leaves flushing and syncing operations as still using 
exposing xvars.

Modified Paths:
--------------
    brlcad/branches/dm-fb-merge/include/dm.h
    brlcad/branches/dm-fb-merge/src/libdm/X/dm-X.c
    brlcad/branches/dm-fb-merge/src/libdm/dm-generic.c
    brlcad/branches/dm-fb-merge/src/libdm/dm_obj.c
    brlcad/branches/dm-fb-merge/src/libdm/glx/dm-ogl.c
    brlcad/branches/dm-fb-merge/src/libdm/include/calltable.h

Modified: brlcad/branches/dm-fb-merge/include/dm.h
===================================================================
--- brlcad/branches/dm-fb-merge/include/dm.h    2020-04-17 15:21:55 UTC (rev 
75436)
+++ brlcad/branches/dm-fb-merge/include/dm.h    2020-04-17 16:14:01 UTC (rev 
75437)
@@ -28,9 +28,8 @@
 
 #include "common.h"
 
-#include "png.h"
-
 #include "vmath.h"
+#include "bu/vls.h"
 #include "bn.h"
 #include "raytrace.h"
 
@@ -291,9 +290,9 @@
 DM_EXPORT extern int dm_get_fb_visible(struct dm *dmp);
 DM_EXPORT extern int dm_set_fb_visible(struct dm *dmp, int is_fb_visible);
 
-// TODO - this should be using libicv rather than returning a PNG struct - 
right
-// now this just moving the guts of dmo_png_cmd behind the call table...
-DM_EXPORT extern png_structp dm_get_image(struct dm *dmp);
+// TODO - this should be using libicv  - right now this just moving the guts of
+// dmo_png_cmd behind the call table, so only provides PNG...
+DM_EXPORT extern int dm_write_image(struct bu_vls *msgs, FILE *fp, struct dm 
*dmp);
 
 /* TODO - dm_vp is supposed to go away, but until we figure it out
  * expose it here to allow dm hiding */

Modified: brlcad/branches/dm-fb-merge/src/libdm/X/dm-X.c
===================================================================
--- brlcad/branches/dm-fb-merge/src/libdm/X/dm-X.c      2020-04-17 15:21:55 UTC 
(rev 75436)
+++ brlcad/branches/dm-fb-merge/src/libdm/X/dm-X.c      2020-04-17 16:14:01 UTC 
(rev 75437)
@@ -55,6 +55,8 @@
 #  include "tk.h"
 #endif
 
+#include "png.h"
+
 #include "vmath.h"
 #include "bu/endian.h"
 #include "bn.h"
@@ -1752,6 +1754,264 @@
     return 0;
 }
 
+
+// TODO - this and getDisplayImage need to be consolidated...
+int
+X_write_image(struct bu_vls *msgs, FILE *fp, struct dm *dmp)
+{
+    png_structp png_p;
+    png_infop info_p;
+    XImage *ximage_p;
+    unsigned char **rows;
+    unsigned char *idata;
+    unsigned char *irow;
+    int bytes_per_pixel;
+    int bits_per_channel = 8;  /* bits per color channel */
+    int i, j, k;
+    unsigned char *dbyte0, *dbyte1, *dbyte2, *dbyte3;
+    int red_shift;
+    int green_shift;
+    int blue_shift;
+    int red_bits;
+    int green_bits;
+    int blue_bits;
+
+    png_p = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+    if (!png_p) {
+       if (msgs) {
+           bu_vls_printf(msgs, "X_write_image: could not create PNG write 
structure\n");
+       }
+       return -1;
+    }
+
+    info_p = png_create_info_struct(png_p);
+    if (!info_p) {
+       if (msgs) {
+           bu_vls_printf(msgs, "X_write_image: could not create PNG info 
structure\n");
+       }
+       png_destroy_write_struct(&png_p, NULL);
+       return -1;
+    }
+
+    ximage_p = XGetImage(((struct dm_Xvars *)dmp->i->dm_vars.pub_vars)->dpy,
+                        ((struct dm_Xvars *)dmp->i->dm_vars.pub_vars)->win,
+                        0, 0,
+                        dmp->i->dm_width,
+                        dmp->i->dm_height,
+                        ~0, ZPixmap);
+    if (!ximage_p) {
+       if (msgs) {
+           bu_vls_printf(msgs, "png: could not get XImage\n");
+       }
+       png_destroy_write_struct(&png_p, &info_p);
+       return -1;
+    }
+
+    bytes_per_pixel = ximage_p->bytes_per_line / ximage_p->width;
+
+    if (bytes_per_pixel == 4) {
+       unsigned long mask;
+       unsigned long tmask;
+
+       /* This section assumes 8 bits per channel */
+
+       mask = ximage_p->red_mask;
+       tmask = 1;
+       for (red_shift = 0; red_shift < 32; red_shift++) {
+           if (tmask & mask)
+               break;
+           tmask = tmask << 1;
+       }
+
+       mask = ximage_p->green_mask;
+       tmask = 1;
+       for (green_shift = 0; green_shift < 32; green_shift++) {
+           if (tmask & mask)
+               break;
+           tmask = tmask << 1;
+       }
+
+       mask = ximage_p->blue_mask;
+       tmask = 1;
+       for (blue_shift = 0; blue_shift < 32; blue_shift++) {
+           if (tmask & mask)
+               break;
+           tmask = tmask << 1;
+       }
+
+       /*
+        * We need to reverse things if the image byte order
+        * is different from the system's byte order.
+        */
+       if (((bu_byteorder() == BU_BIG_ENDIAN) && (ximage_p->byte_order == 
LSBFirst)) ||
+           ((bu_byteorder() == BU_LITTLE_ENDIAN) && (ximage_p->byte_order == 
MSBFirst))) {
+           DM_REVERSE_COLOR_BYTE_ORDER(red_shift, ximage_p->red_mask);
+           DM_REVERSE_COLOR_BYTE_ORDER(green_shift, ximage_p->green_mask);
+           DM_REVERSE_COLOR_BYTE_ORDER(blue_shift, ximage_p->blue_mask);
+       }
+
+    } else if (bytes_per_pixel == 2) {
+       unsigned long mask;
+       unsigned long tmask;
+       int bpb = 8;   /* bits per byte */
+
+       /*XXX
+        * This section probably needs logic similar
+        * to the previous section (i.e. bytes_per_pixel == 4).
+        * That is we may need to reverse things depending on
+        * the image byte order and the system's byte order.
+        */
+
+       mask = ximage_p->red_mask;
+       tmask = 1;
+       for (red_shift = 0; red_shift < 16; red_shift++) {
+           if (tmask & mask)
+               break;
+           tmask = tmask << 1;
+       }
+       for (red_bits = red_shift; red_bits < 16; red_bits++) {
+           if (!(tmask & mask))
+               break;
+           tmask = tmask << 1;
+       }
+
+       red_bits = red_bits - red_shift;
+       if (red_shift == 0)
+           red_shift = red_bits - bpb;
+       else
+           red_shift = red_shift - (bpb - red_bits);
+
+       mask = ximage_p->green_mask;
+       tmask = 1;
+       for (green_shift = 0; green_shift < 16; green_shift++) {
+           if (tmask & mask)
+               break;
+           tmask = tmask << 1;
+       }
+       for (green_bits = green_shift; green_bits < 16; green_bits++) {
+           if (!(tmask & mask))
+               break;
+           tmask = tmask << 1;
+       }
+
+       green_bits = green_bits - green_shift;
+       green_shift = green_shift - (bpb - green_bits);
+
+       mask = ximage_p->blue_mask;
+       tmask = 1;
+       for (blue_shift = 0; blue_shift < 16; blue_shift++) {
+           if (tmask & mask)
+               break;
+           tmask = tmask << 1;
+       }
+       for (blue_bits = blue_shift; blue_bits < 16; blue_bits++) {
+           if (!(tmask & mask))
+               break;
+           tmask = tmask << 1;
+       }
+       blue_bits = blue_bits - blue_shift;
+
+       if (blue_shift == 0)
+           blue_shift = blue_bits - bpb;
+       else
+           blue_shift = blue_shift - (bpb - blue_bits);
+    } else {
+       if (msgs) {
+           bu_vls_printf(msgs, "png: %d bytes per pixel is not yet 
supported\n", bytes_per_pixel);
+       }
+       png_destroy_write_struct(&png_p, &info_p);
+       return -1;
+    }
+
+    rows = (unsigned char **)bu_calloc(ximage_p->height, sizeof(unsigned char 
*), "rows");
+    idata = (unsigned char *)bu_calloc(ximage_p->height * ximage_p->width, 4, 
"png data");
+
+    /* for each scanline */
+    for (i = ximage_p->height - 1, j = 0; 0 <= i; --i, ++j) {
+       /* irow points to the current scanline in ximage_p */
+       irow = (unsigned char *)(ximage_p->data + 
((ximage_p->height-i-1)*ximage_p->bytes_per_line));
+
+       if (bytes_per_pixel == 4) {
+           unsigned int pixel;
+
+           /* rows[j] points to the current scanline in idata */
+           rows[j] = (unsigned char *)(idata + 
((ximage_p->height-i-1)*ximage_p->bytes_per_line));
+
+           /* for each pixel in current scanline of ximage_p */
+           for (k = 0; k < ximage_p->bytes_per_line; k += bytes_per_pixel) {
+               pixel = *((unsigned int *)(irow + k));
+
+               dbyte0 = rows[j] + k;
+               dbyte1 = dbyte0 + 1;
+               dbyte2 = dbyte0 + 2;
+               dbyte3 = dbyte0 + 3;
+
+               *dbyte0 = (pixel & ximage_p->red_mask) >> red_shift;
+               *dbyte1 = (pixel & ximage_p->green_mask) >> green_shift;
+               *dbyte2 = (pixel & ximage_p->blue_mask) >> blue_shift;
+               *dbyte3 = 255;
+           }
+       } else if (bytes_per_pixel == 2) {
+           unsigned short spixel;
+           unsigned long pixel;
+
+           /* rows[j] points to the current scanline in idata */
+           rows[j] = (unsigned char *)(idata + 
((ximage_p->height-i-1)*ximage_p->bytes_per_line*2));
+
+           /* for each pixel in current scanline of ximage_p */
+           for (k = 0; k < ximage_p->bytes_per_line; k += bytes_per_pixel) {
+               spixel = *((unsigned short *)(irow + k));
+               pixel = spixel;
+
+               dbyte0 = rows[j] + k*2;
+               dbyte1 = dbyte0 + 1;
+               dbyte2 = dbyte0 + 2;
+               dbyte3 = dbyte0 + 3;
+
+               if (0 <= red_shift)
+                   *dbyte0 = (pixel & ximage_p->red_mask) >> red_shift;
+               else
+                   *dbyte0 = (pixel & ximage_p->red_mask) << -red_shift;
+
+               *dbyte1 = (pixel & ximage_p->green_mask) >> green_shift;
+
+               if (0 <= blue_shift)
+                   *dbyte2 = (pixel & ximage_p->blue_mask) >> blue_shift;
+               else
+                   *dbyte2 = (pixel & ximage_p->blue_mask) << -blue_shift;
+
+               *dbyte3 = 255;
+           }
+       } else {
+           bu_free(rows, "rows");
+           bu_free(idata, "image data");
+           png_destroy_write_struct(&png_p, &info_p);
+           if (msgs) {
+               bu_vls_printf(msgs, "png: not supported for this platform\n");
+           }
+           return -1;
+       }
+    }
+
+    png_init_io(png_p, fp);
+    png_set_filter(png_p, 0, PNG_FILTER_NONE);
+    png_set_compression_level(png_p, 9);
+    png_set_IHDR(png_p, info_p, ximage_p->width, ximage_p->height, 
bits_per_channel,
+                PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
+                PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+    png_set_gAMA(png_p, info_p, 0.77);
+    png_write_info(png_p, info_p);
+    png_write_image(png_p, rows);
+    png_write_end(png_p, NULL);
+
+    png_destroy_write_struct(&png_p, &info_p);
+
+    bu_free(rows, "rows");
+    bu_free(idata, "image data");
+
+    return 0;
+}
+
 /* Display Manager package interface */
 struct dm_impl dm_X_impl = {
     X_close,
@@ -1795,7 +2055,7 @@
     NULL,
     X_geometry_request,
     X_internal_var,
-    NULL,
+    X_write_image,
     0,
     0,                         /* no displaylist */
     0,                            /* no stereo */

Modified: brlcad/branches/dm-fb-merge/src/libdm/dm-generic.c
===================================================================
--- brlcad/branches/dm-fb-merge/src/libdm/dm-generic.c  2020-04-17 15:21:55 UTC 
(rev 75436)
+++ brlcad/branches/dm-fb-merge/src/libdm/dm-generic.c  2020-04-17 16:14:01 UTC 
(rev 75437)
@@ -187,11 +187,11 @@
     }
 }
 
-png_structp
-dm_get_image(struct dm *dmp)
+int
+dm_write_image(struct bu_vls *msgs, FILE *fp, struct dm *dmp)
 {
-    if (!dmp || !dmp->i->dm_get_image) return NULL;
-    return dmp->i->dm_get_image(dmp);
+    if (!dmp || !dmp->i->dm_write_image) return -1;
+    return dmp->i->dm_write_image(msgs, fp, dmp);
 }
 
 /* Properly generic functions */

Modified: brlcad/branches/dm-fb-merge/src/libdm/dm_obj.c
===================================================================
--- brlcad/branches/dm-fb-merge/src/libdm/dm_obj.c      2020-04-17 15:21:55 UTC 
(rev 75436)
+++ brlcad/branches/dm-fb-merge/src/libdm/dm_obj.c      2020-04-17 16:14:01 UTC 
(rev 75437)
@@ -2040,23 +2040,8 @@
            int argc,
            const char **argv)
 {
+    struct bu_vls msgs = BU_VLS_INIT_ZERO;
     FILE *fp;
-    png_structp png_p;
-    png_infop info_p;
-    XImage *ximage_p;
-    unsigned char **rows;
-    unsigned char *idata;
-    unsigned char *irow;
-    int bytes_per_pixel;
-    int bits_per_channel = 8;  /* bits per color channel */
-    int i, j, k;
-    unsigned char *dbyte0, *dbyte1, *dbyte2, *dbyte3;
-    int red_shift;
-    int green_shift;
-    int blue_shift;
-    int red_bits;
-    int green_bits;
-    int blue_bits;
 
     if (argc != 2) {
        struct bu_vls vls = BU_VLS_INIT_ZERO;
@@ -2067,241 +2052,26 @@
        return BRLCAD_ERROR;
     }
 
-    if ((fp = fopen(argv[1], "wb")) == NULL) {
-       Tcl_AppendResult(dmop->interp, "png: cannot open \"", argv[1], " for 
writing\n", (char *)NULL);
+    if (!dmop->dmo_dmp->i->dm_write_image) {
+       Tcl_AppendResult(dmop->interp, "png: writing unsupported with this 
display manager type.\n", (char *)NULL);
        return BRLCAD_ERROR;
     }
 
-    png_p = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
-    if (!png_p) {
-       Tcl_AppendResult(dmop->interp, "png: could not create PNG write 
structure\n", (char *)NULL);
-       fclose(fp);
+    if ((fp = fopen(argv[1], "wb")) == NULL) {
+       Tcl_AppendResult(dmop->interp, "png: cannot open \"", argv[1], " for 
writing\n", (char *)NULL);
        return BRLCAD_ERROR;
     }
 
-    info_p = png_create_info_struct(png_p);
-    if (!info_p) {
-       Tcl_AppendResult(dmop->interp, "png: could not create PNG info 
structure\n", (char *)NULL);
-       fclose(fp);
-       return BRLCAD_ERROR;
-    }
+    int ret = dmop->dmo_dmp->i->dm_write_image(&msgs, fp, dmop->dmo_dmp);
 
-    ximage_p = XGetImage(((struct dm_xvars 
*)dmop->dmo_dmp->i->dm_vars.pub_vars)->dpy,
-                        ((struct dm_xvars 
*)dmop->dmo_dmp->i->dm_vars.pub_vars)->win,
-                        0, 0,
-                        dmop->dmo_dmp->i->dm_width,
-                        dmop->dmo_dmp->i->dm_height,
-                        ~0, ZPixmap);
-    if (!ximage_p) {
-       Tcl_AppendResult(dmop->interp, "png: could not get XImage\n", (char 
*)NULL);
-       fclose(fp);
-       return BRLCAD_ERROR;
+    if (ret) {
+       Tcl_AppendResult(dmop->interp, bu_vls_cstr(&msgs), (char *)NULL);
     }
 
-    bytes_per_pixel = ximage_p->bytes_per_line / ximage_p->width;
-
-    if (bytes_per_pixel == 4) {
-       unsigned long mask;
-       unsigned long tmask;
-
-       /* This section assumes 8 bits per channel */
-
-       mask = ximage_p->red_mask;
-       tmask = 1;
-       for (red_shift = 0; red_shift < 32; red_shift++) {
-           if (tmask & mask)
-               break;
-           tmask = tmask << 1;
-       }
-
-       mask = ximage_p->green_mask;
-       tmask = 1;
-       for (green_shift = 0; green_shift < 32; green_shift++) {
-           if (tmask & mask)
-               break;
-           tmask = tmask << 1;
-       }
-
-       mask = ximage_p->blue_mask;
-       tmask = 1;
-       for (blue_shift = 0; blue_shift < 32; blue_shift++) {
-           if (tmask & mask)
-               break;
-           tmask = tmask << 1;
-       }
-
-       /*
-        * We need to reverse things if the image byte order
-        * is different from the system's byte order.
-        */
-       if (((bu_byteorder() == BU_BIG_ENDIAN) && (ximage_p->byte_order == 
LSBFirst)) ||
-           ((bu_byteorder() == BU_LITTLE_ENDIAN) && (ximage_p->byte_order == 
MSBFirst))) {
-           DM_REVERSE_COLOR_BYTE_ORDER(red_shift, ximage_p->red_mask);
-           DM_REVERSE_COLOR_BYTE_ORDER(green_shift, ximage_p->green_mask);
-           DM_REVERSE_COLOR_BYTE_ORDER(blue_shift, ximage_p->blue_mask);
-       }
-
-    } else if (bytes_per_pixel == 2) {
-       unsigned long mask;
-       unsigned long tmask;
-       int bpb = 8;   /* bits per byte */
-
-       /*XXX
-        * This section probably needs logic similar
-        * to the previous section (i.e. bytes_per_pixel == 4).
-        * That is we may need to reverse things depending on
-        * the image byte order and the system's byte order.
-        */
-
-       mask = ximage_p->red_mask;
-       tmask = 1;
-       for (red_shift = 0; red_shift < 16; red_shift++) {
-           if (tmask & mask)
-               break;
-           tmask = tmask << 1;
-       }
-       for (red_bits = red_shift; red_bits < 16; red_bits++) {
-           if (!(tmask & mask))
-               break;
-           tmask = tmask << 1;
-       }
-
-       red_bits = red_bits - red_shift;
-       if (red_shift == 0)
-           red_shift = red_bits - bpb;
-       else
-           red_shift = red_shift - (bpb - red_bits);
-
-       mask = ximage_p->green_mask;
-       tmask = 1;
-       for (green_shift = 0; green_shift < 16; green_shift++) {
-           if (tmask & mask)
-               break;
-           tmask = tmask << 1;
-       }
-       for (green_bits = green_shift; green_bits < 16; green_bits++) {
-           if (!(tmask & mask))
-               break;
-           tmask = tmask << 1;
-       }
-
-       green_bits = green_bits - green_shift;
-       green_shift = green_shift - (bpb - green_bits);
-
-       mask = ximage_p->blue_mask;
-       tmask = 1;
-       for (blue_shift = 0; blue_shift < 16; blue_shift++) {
-           if (tmask & mask)
-               break;
-           tmask = tmask << 1;
-       }
-       for (blue_bits = blue_shift; blue_bits < 16; blue_bits++) {
-           if (!(tmask & mask))
-               break;
-           tmask = tmask << 1;
-       }
-       blue_bits = blue_bits - blue_shift;
-
-       if (blue_shift == 0)
-           blue_shift = blue_bits - bpb;
-       else
-           blue_shift = blue_shift - (bpb - blue_bits);
-    } else {
-       struct bu_vls vls = BU_VLS_INIT_ZERO;
-
-       bu_vls_printf(&vls, "png: %d bytes per pixel is not yet supported\n", 
bytes_per_pixel);
-       Tcl_AppendResult(dmop->interp, bu_vls_addr(&vls), (char *)NULL);
-       fclose(fp);
-       bu_vls_free(&vls);
-
-       return BRLCAD_ERROR;
-    }
-
-    rows = (unsigned char **)bu_calloc(ximage_p->height, sizeof(unsigned char 
*), "rows");
-    idata = (unsigned char *)bu_calloc(ximage_p->height * ximage_p->width, 4, 
"png data");
-
-    /* for each scanline */
-    for (i = ximage_p->height - 1, j = 0; 0 <= i; --i, ++j) {
-       /* irow points to the current scanline in ximage_p */
-       irow = (unsigned char *)(ximage_p->data + 
((ximage_p->height-i-1)*ximage_p->bytes_per_line));
-
-       if (bytes_per_pixel == 4) {
-           unsigned int pixel;
-
-           /* rows[j] points to the current scanline in idata */
-           rows[j] = (unsigned char *)(idata + 
((ximage_p->height-i-1)*ximage_p->bytes_per_line));
-
-           /* for each pixel in current scanline of ximage_p */
-           for (k = 0; k < ximage_p->bytes_per_line; k += bytes_per_pixel) {
-               pixel = *((unsigned int *)(irow + k));
-
-               dbyte0 = rows[j] + k;
-               dbyte1 = dbyte0 + 1;
-               dbyte2 = dbyte0 + 2;
-               dbyte3 = dbyte0 + 3;
-
-               *dbyte0 = (pixel & ximage_p->red_mask) >> red_shift;
-               *dbyte1 = (pixel & ximage_p->green_mask) >> green_shift;
-               *dbyte2 = (pixel & ximage_p->blue_mask) >> blue_shift;
-               *dbyte3 = 255;
-           }
-       } else if (bytes_per_pixel == 2) {
-           unsigned short spixel;
-           unsigned long pixel;
-
-           /* rows[j] points to the current scanline in idata */
-           rows[j] = (unsigned char *)(idata + 
((ximage_p->height-i-1)*ximage_p->bytes_per_line*2));
-
-           /* for each pixel in current scanline of ximage_p */
-           for (k = 0; k < ximage_p->bytes_per_line; k += bytes_per_pixel) {
-               spixel = *((unsigned short *)(irow + k));
-               pixel = spixel;
-
-               dbyte0 = rows[j] + k*2;
-               dbyte1 = dbyte0 + 1;
-               dbyte2 = dbyte0 + 2;
-               dbyte3 = dbyte0 + 3;
-
-               if (0 <= red_shift)
-                   *dbyte0 = (pixel & ximage_p->red_mask) >> red_shift;
-               else
-                   *dbyte0 = (pixel & ximage_p->red_mask) << -red_shift;
-
-               *dbyte1 = (pixel & ximage_p->green_mask) >> green_shift;
-
-               if (0 <= blue_shift)
-                   *dbyte2 = (pixel & ximage_p->blue_mask) >> blue_shift;
-               else
-                   *dbyte2 = (pixel & ximage_p->blue_mask) << -blue_shift;
-
-               *dbyte3 = 255;
-           }
-       } else {
-           bu_free(rows, "rows");
-           bu_free(idata, "image data");
-           fclose(fp);
-
-           Tcl_AppendResult(dmop->interp, "png: not supported for this 
platform\n", (char *)NULL);
-           return BRLCAD_ERROR;
-       }
-    }
-
-    png_init_io(png_p, fp);
-    png_set_filter(png_p, 0, PNG_FILTER_NONE);
-    png_set_compression_level(png_p, 9);
-    png_set_IHDR(png_p, info_p, ximage_p->width, ximage_p->height, 
bits_per_channel,
-                PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
-                PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
-    png_set_gAMA(png_p, info_p, 0.77);
-    png_write_info(png_p, info_p);
-    png_write_image(png_p, rows);
-    png_write_end(png_p, NULL);
-
-    bu_free(rows, "rows");
-    bu_free(idata, "image data");
+    bu_vls_free(&msgs);
     fclose(fp);
 
-    return BRLCAD_OK;
+    return (ret) ? BRLCAD_ERROR : BRLCAD_OK;
 }
 
 

Modified: brlcad/branches/dm-fb-merge/src/libdm/glx/dm-ogl.c
===================================================================
--- brlcad/branches/dm-fb-merge/src/libdm/glx/dm-ogl.c  2020-04-17 15:21:55 UTC 
(rev 75436)
+++ brlcad/branches/dm-fb-merge/src/libdm/glx/dm-ogl.c  2020-04-17 16:14:01 UTC 
(rev 75437)
@@ -32,6 +32,7 @@
 #include <math.h>
 #include <string.h>
 
+
 #ifdef HAVE_X11_XOSDEFS_H
 #  include <X11/Xfuncproto.h>
 #  include <X11/Xosdefs.h>
@@ -69,6 +70,8 @@
 #undef y1
 #undef j1
 
+#include "png.h"
+
 #include "tk.h"
 
 #undef VMIN            /* is used in vmath.h, too */
@@ -2623,6 +2626,264 @@
     return 0;
 }
 
+
+// TODO - this and getDisplayImage need to be consolidated...
+int
+ogl_write_image(struct bu_vls *msgs, FILE *fp, struct dm *dmp)
+{
+    png_structp png_p;
+    png_infop info_p;
+    XImage *ximage_p;
+    unsigned char **rows;
+    unsigned char *idata;
+    unsigned char *irow;
+    int bytes_per_pixel;
+    int bits_per_channel = 8;  /* bits per color channel */
+    int i, j, k;
+    unsigned char *dbyte0, *dbyte1, *dbyte2, *dbyte3;
+    int red_shift;
+    int green_shift;
+    int blue_shift;
+    int red_bits;
+    int green_bits;
+    int blue_bits;
+
+    png_p = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+    if (!png_p) {
+       if (msgs) {
+           bu_vls_printf(msgs, "ogl_write_image: could not create PNG write 
structure\n");
+       }
+       return -1;
+    }
+
+    info_p = png_create_info_struct(png_p);
+    if (!info_p) {
+       if (msgs) {
+           bu_vls_printf(msgs, "ogl_write_image: could not create PNG info 
structure\n");
+       }
+       png_destroy_write_struct(&png_p, NULL);
+       return -1;
+    }
+
+    ximage_p = XGetImage(((struct dm_glxvars *)dmp->i->dm_vars.pub_vars)->dpy,
+                        ((struct dm_glxvars *)dmp->i->dm_vars.pub_vars)->win,
+                        0, 0,
+                        dmp->i->dm_width,
+                        dmp->i->dm_height,
+                        ~0, ZPixmap);
+    if (!ximage_p) {
+       if (msgs) {
+           bu_vls_printf(msgs, "png: could not get XImage\n");
+       }
+       png_destroy_write_struct(&png_p, &info_p);
+       return -1;
+    }
+
+    bytes_per_pixel = ximage_p->bytes_per_line / ximage_p->width;
+
+    if (bytes_per_pixel == 4) {
+       unsigned long mask;
+       unsigned long tmask;
+
+       /* This section assumes 8 bits per channel */
+
+       mask = ximage_p->red_mask;
+       tmask = 1;
+       for (red_shift = 0; red_shift < 32; red_shift++) {
+           if (tmask & mask)
+               break;
+           tmask = tmask << 1;
+       }
+
+       mask = ximage_p->green_mask;
+       tmask = 1;
+       for (green_shift = 0; green_shift < 32; green_shift++) {
+           if (tmask & mask)
+               break;
+           tmask = tmask << 1;
+       }
+
+       mask = ximage_p->blue_mask;
+       tmask = 1;
+       for (blue_shift = 0; blue_shift < 32; blue_shift++) {
+           if (tmask & mask)
+               break;
+           tmask = tmask << 1;
+       }
+
+       /*
+        * We need to reverse things if the image byte order
+        * is different from the system's byte order.
+        */
+       if (((bu_byteorder() == BU_BIG_ENDIAN) && (ximage_p->byte_order == 
LSBFirst)) ||
+           ((bu_byteorder() == BU_LITTLE_ENDIAN) && (ximage_p->byte_order == 
MSBFirst))) {
+           DM_REVERSE_COLOR_BYTE_ORDER(red_shift, ximage_p->red_mask);
+           DM_REVERSE_COLOR_BYTE_ORDER(green_shift, ximage_p->green_mask);
+           DM_REVERSE_COLOR_BYTE_ORDER(blue_shift, ximage_p->blue_mask);
+       }
+
+    } else if (bytes_per_pixel == 2) {
+       unsigned long mask;
+       unsigned long tmask;
+       int bpb = 8;   /* bits per byte */
+
+       /*XXX
+        * This section probably needs logic similar
+        * to the previous section (i.e. bytes_per_pixel == 4).
+        * That is we may need to reverse things depending on
+        * the image byte order and the system's byte order.
+        */
+
+       mask = ximage_p->red_mask;
+       tmask = 1;
+       for (red_shift = 0; red_shift < 16; red_shift++) {
+           if (tmask & mask)
+               break;
+           tmask = tmask << 1;
+       }
+       for (red_bits = red_shift; red_bits < 16; red_bits++) {
+           if (!(tmask & mask))
+               break;
+           tmask = tmask << 1;
+       }
+
+       red_bits = red_bits - red_shift;
+       if (red_shift == 0)
+           red_shift = red_bits - bpb;
+       else
+           red_shift = red_shift - (bpb - red_bits);
+
+       mask = ximage_p->green_mask;
+       tmask = 1;
+       for (green_shift = 0; green_shift < 16; green_shift++) {
+           if (tmask & mask)
+               break;
+           tmask = tmask << 1;
+       }
+       for (green_bits = green_shift; green_bits < 16; green_bits++) {
+           if (!(tmask & mask))
+               break;
+           tmask = tmask << 1;
+       }
+
+       green_bits = green_bits - green_shift;
+       green_shift = green_shift - (bpb - green_bits);
+
+       mask = ximage_p->blue_mask;
+       tmask = 1;
+       for (blue_shift = 0; blue_shift < 16; blue_shift++) {
+           if (tmask & mask)
+               break;
+           tmask = tmask << 1;
+       }
+       for (blue_bits = blue_shift; blue_bits < 16; blue_bits++) {
+           if (!(tmask & mask))
+               break;
+           tmask = tmask << 1;
+       }
+       blue_bits = blue_bits - blue_shift;
+
+       if (blue_shift == 0)
+           blue_shift = blue_bits - bpb;
+       else
+           blue_shift = blue_shift - (bpb - blue_bits);
+    } else {
+       if (msgs) {
+           bu_vls_printf(msgs, "png: %d bytes per pixel is not yet 
supported\n", bytes_per_pixel);
+       }
+       png_destroy_write_struct(&png_p, &info_p);
+       return -1;
+    }
+
+    rows = (unsigned char **)bu_calloc(ximage_p->height, sizeof(unsigned char 
*), "rows");
+    idata = (unsigned char *)bu_calloc(ximage_p->height * ximage_p->width, 4, 
"png data");
+
+    /* for each scanline */
+    for (i = ximage_p->height - 1, j = 0; 0 <= i; --i, ++j) {
+       /* irow points to the current scanline in ximage_p */
+       irow = (unsigned char *)(ximage_p->data + 
((ximage_p->height-i-1)*ximage_p->bytes_per_line));
+
+       if (bytes_per_pixel == 4) {
+           unsigned int pixel;
+
+           /* rows[j] points to the current scanline in idata */
+           rows[j] = (unsigned char *)(idata + 
((ximage_p->height-i-1)*ximage_p->bytes_per_line));
+
+           /* for each pixel in current scanline of ximage_p */
+           for (k = 0; k < ximage_p->bytes_per_line; k += bytes_per_pixel) {
+               pixel = *((unsigned int *)(irow + k));
+
+               dbyte0 = rows[j] + k;
+               dbyte1 = dbyte0 + 1;
+               dbyte2 = dbyte0 + 2;
+               dbyte3 = dbyte0 + 3;
+
+               *dbyte0 = (pixel & ximage_p->red_mask) >> red_shift;
+               *dbyte1 = (pixel & ximage_p->green_mask) >> green_shift;
+               *dbyte2 = (pixel & ximage_p->blue_mask) >> blue_shift;
+               *dbyte3 = 255;
+           }
+       } else if (bytes_per_pixel == 2) {
+           unsigned short spixel;
+           unsigned long pixel;
+
+           /* rows[j] points to the current scanline in idata */
+           rows[j] = (unsigned char *)(idata + 
((ximage_p->height-i-1)*ximage_p->bytes_per_line*2));
+
+           /* for each pixel in current scanline of ximage_p */
+           for (k = 0; k < ximage_p->bytes_per_line; k += bytes_per_pixel) {
+               spixel = *((unsigned short *)(irow + k));
+               pixel = spixel;
+
+               dbyte0 = rows[j] + k*2;
+               dbyte1 = dbyte0 + 1;
+               dbyte2 = dbyte0 + 2;
+               dbyte3 = dbyte0 + 3;
+
+               if (0 <= red_shift)
+                   *dbyte0 = (pixel & ximage_p->red_mask) >> red_shift;
+               else
+                   *dbyte0 = (pixel & ximage_p->red_mask) << -red_shift;
+
+               *dbyte1 = (pixel & ximage_p->green_mask) >> green_shift;
+
+               if (0 <= blue_shift)
+                   *dbyte2 = (pixel & ximage_p->blue_mask) >> blue_shift;
+               else
+                   *dbyte2 = (pixel & ximage_p->blue_mask) << -blue_shift;
+
+               *dbyte3 = 255;
+           }
+       } else {
+           bu_free(rows, "rows");
+           bu_free(idata, "image data");
+           png_destroy_write_struct(&png_p, &info_p);
+           if (msgs) {
+               bu_vls_printf(msgs, "png: not supported for this platform\n");
+           }
+           return -1;
+       }
+    }
+
+    png_init_io(png_p, fp);
+    png_set_filter(png_p, 0, PNG_FILTER_NONE);
+    png_set_compression_level(png_p, 9);
+    png_set_IHDR(png_p, info_p, ximage_p->width, ximage_p->height, 
bits_per_channel,
+                PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
+                PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+    png_set_gAMA(png_p, info_p, 0.77);
+    png_write_info(png_p, info_p);
+    png_write_image(png_p, rows);
+    png_write_end(png_p, NULL);
+
+    png_destroy_write_struct(&png_p, &info_p);
+
+    bu_free(rows, "rows");
+    bu_free(idata, "image data");
+
+    return 0;
+}
+
 struct dm_impl dm_ogl_impl = {
     ogl_close,
     ogl_drawBegin,
@@ -2665,7 +2926,7 @@
     ogl_put_internal,
     ogl_geometry_request,
     ogl_internal_var,
-    NULL,
+    ogl_write_image,
     0,
     1,                         /* has displaylist */
     0,                          /* no stereo by default */

Modified: brlcad/branches/dm-fb-merge/src/libdm/include/calltable.h
===================================================================
--- brlcad/branches/dm-fb-merge/src/libdm/include/calltable.h   2020-04-17 
15:21:55 UTC (rev 75436)
+++ brlcad/branches/dm-fb-merge/src/libdm/include/calltable.h   2020-04-17 
16:14:01 UTC (rev 75437)
@@ -96,7 +96,7 @@
     int (*dm_put_internal)(struct dm *dmp);
     int (*dm_geometry_request)(struct dm *dmp, int width, int height);
     int (*dm_internal_var)(struct bu_vls *result, struct dm *dmp, const char 
*key);
-    png_structp (*dm_get_image)(struct dm *dmp);
+    int (*dm_write_image)(struct bu_vls *msgs, FILE *fp, struct dm *dmp);
     unsigned long dm_id;          /**< @brief window id */
     int dm_displaylist;                /**< @brief !0 means device has 
displaylist */
     int dm_stereo;                /**< @brief stereo flag */

This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.



_______________________________________________
BRL-CAD Source Commits mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/brlcad-commits

Reply via email to