Revision: 75616
          http://sourceforge.net/p/brlcad/code/75616
Author:   starseeker
Date:     2020-04-27 20:14:37 +0000 (Mon, 27 Apr 2020)
Log Message:
-----------
Move tcl_img to a tests subdir

Modified Paths:
--------------
    brlcad/trunk/src/libdm/CMakeLists.txt

Added Paths:
-----------
    brlcad/trunk/src/libdm/tests/
    brlcad/trunk/src/libdm/tests/CMakeLists.txt
    brlcad/trunk/src/libdm/tests/tcl_img.cpp

Removed Paths:
-------------
    brlcad/trunk/src/libdm/tcl_img.cpp

Modified: brlcad/trunk/src/libdm/CMakeLists.txt
===================================================================
--- brlcad/trunk/src/libdm/CMakeLists.txt       2020-04-27 19:54:15 UTC (rev 
75615)
+++ brlcad/trunk/src/libdm/CMakeLists.txt       2020-04-27 20:14:37 UTC (rev 
75616)
@@ -130,8 +130,7 @@
   add_dependencies(libdm profont_ProFont_ttf_cp)
 endif(BRLCAD_ENABLE_OSG)
 
-#add_executable(tcl_img tcl_img.cpp)
-#target_link_libraries(tcl_img ${TCL_LIBRARY} ${TK_LIBRARY})
+add_subdirectory(tests)
 
 set(libdm_ignore_files
   CMakeLists.txt
@@ -161,7 +160,6 @@
   fontstash/stb_truetype.h
   osg-test.cpp
   osg_bob.cpp
-  tcl_img.cpp
   )
 CMAKEFILES(${libdm_ignore_files})
 CMAKEFILES(dm_private.h)

Deleted: brlcad/trunk/src/libdm/tcl_img.cpp
===================================================================
--- brlcad/trunk/src/libdm/tcl_img.cpp  2020-04-27 19:54:15 UTC (rev 75615)
+++ brlcad/trunk/src/libdm/tcl_img.cpp  2020-04-27 20:14:37 UTC (rev 75616)
@@ -1,312 +0,0 @@
-/*                     T C L _ I M G . C P P
- * BRL-CAD
- *
- * Published in 2020 by the United States Government.
- * This work is in the public domain.
- *
- */
-/** @file tcl_img.cpp
- *
- * Self contained example of working with image data
- * in Tcl/Tk in C/C++
- *
- * Eventually this should probably turn into a Togl-esque
- * widget that we properly include, so we ensure that our
- * window is behaving the way Tk expects it to for things
- * like refresh.  Our current behavior in that regard is
- * a bit iffy - ogl works but I'm not convinced that's
- * because we're doing the Tcl/Tk bits right, and X is
- * doing low level blitting and other X calls (which
- * isn't great for maintainability/portability and
- * can be a headache for debugging.)
- *
- */
-
-#include "common.h"
-
-#include <random>
-#include <iostream>
-#include <stdlib.h>
-#include <errno.h>
-
-#include "tcl.h"
-#include "tk.h"
-
-const char *DM_PHOTO = ".dm0.photo";
-const char *DM_CANVAS = ".dm0";
-
-/* Container holding image generation information - need to be able
- * to pass these to the update command */
-struct img_data {
-    std::default_random_engine *gen;
-    std::uniform_int_distribution<int> *colors;
-    std::uniform_int_distribution<int> *vals;
-};
-
-int
-image_update_data(ClientData clientData, Tcl_Interp *interp, int UNUSED(argc), 
char **UNUSED(argv))
-{
-    struct img_data *idata = (struct img_data *)clientData;
-
-    // Look up the internals of the image - we're going to directly manipulate
-    // the values of the image to simulate a display manager or framebuffer
-    // changing the visual via rendering.
-    Tk_PhotoImageBlock dm_data;
-    Tk_PhotoHandle dm_img = Tk_FindPhoto(interp, DM_PHOTO);
-    Tk_PhotoGetImage(dm_img, &dm_data);
-
-    // To get a little visual variation and make it easer to see changes,
-    // randomly turn on/off the individual colors for each pass.
-    int r = (*idata->colors)((*idata->gen));
-    int g = (*idata->colors)((*idata->gen));
-    int b = (*idata->colors)((*idata->gen));
-
-    // For each pixel, get a random color value and set it in the image memory 
buffer.
-    // This alters the actual data, but Tcl/Tk doesn't know about it yet.
-    for (int i = 0; i < (dm_data.width * dm_data.height * 4); i+=4) {
-       // Red
-       dm_data.pixelPtr[i] = (r) ? (*idata->vals)((*idata->gen)) : 0;
-       // Green
-       dm_data.pixelPtr[i+1] = (g) ? (*idata->vals)((*idata->gen)) : 0;
-       // Blue
-       dm_data.pixelPtr[i+2] = (b) ? (*idata->vals)((*idata->gen)) : 0;
-       // Alpha stays at 255 (Don't really need to set it since it should
-       // already be set, just doing so for local clarity about what should be
-       // happening with the buffer data...)
-       dm_data.pixelPtr[i+3] = 255;
-    }
-
-    // Let Tcl/Tk know the photo data has changed, so it can update the 
visuals accordingly
-    Tk_PhotoPutBlock(interp, dm_img, &dm_data, 0, 0, dm_data.width, 
dm_data.height, TK_PHOTO_COMPOSITE_SET);
-
-    return TCL_OK;
-}
-
-// Given an X,Y coordinate in a TkPhoto image and a desired offset in
-// X and Y, return the index value into the pixelPtr array N such that
-// N is the integer value of the R color at that X,Y coordiante, N+1
-// is the G value, N+2 is the B value and N+3 is the Alpha value.
-// If either desired offset is beyond the width and height boundaries,
-// cap the return at the minimum/maximum allowed value.
-static int
-img_xy_index(int width, int height, int x, int y, int dx, int dy)
-{
-    int nx = ((x + dx) > width)  ? width  : ((x + dx) < 0) ? 0 : x + dx;
-    int ny = ((y + dy) > height) ? height : ((y + dy) < 0) ? 0 : y + dy;
-    return (ny * width * 4) + nx * 4;
-}
-
-int
-image_paint_xy(ClientData UNUSED(clientData), Tcl_Interp *interp, int argc, 
char **argv)
-{
-    if (argc != 3) {
-       std::cerr << "Unexpected argc: " << argc << "\n";
-       return TCL_ERROR;
-    }
-
-    // Unpack the coordinates (checking errno, although it may not truly be
-    // necessary if we trust Tk to always give us valid coordinates...)
-    char *p_end;
-    errno = 0;
-    long xcoor = strtol(argv[1], &p_end, 10);
-    if (errno == ERANGE || (errno != 0 && xcoor == 0) || p_end == argv[1]) {
-       std::cerr << "Invalid image_paint_xy X coordinate: " << argv[1] << "\n";
-       return TCL_ERROR;
-    }
-    errno = 0;
-    long ycoor = strtol(argv[2], &p_end, 10);
-    if (errno == ERANGE || (errno != 0 && ycoor == 0) || p_end == argv[1]) {
-       std::cerr << "Invalid image_paint_xy Y coordinate: " << argv[2] << "\n";
-       return TCL_ERROR;
-    }
-
-    // Look up the internals of the image - we're going to directly manipulate
-    // the values of the image to simulate a display manager or framebuffer
-    // changing the visual via rendering.
-    Tk_PhotoImageBlock dm_data;
-    Tk_PhotoHandle dm_img = Tk_FindPhoto(interp, DM_PHOTO);
-    Tk_PhotoGetImage(dm_img, &dm_data);
-
-
-    for (int i = -2; i < 3; i++) {
-       for (int j = -2; j < 3; j++) {
-           int pindex = img_xy_index(dm_data.width, dm_data.height, xcoor, 
ycoor, i, j);
-           // Set to opaque white
-           dm_data.pixelPtr[pindex] = 255;
-           dm_data.pixelPtr[pindex+1] = 255;
-           dm_data.pixelPtr[pindex+2] = 255;
-           dm_data.pixelPtr[pindex+3] = 255;
-       }
-    }
-
-    // Let Tcl/Tk know the photo data has changed, so it can update the 
visuals accordingly.
-    Tk_PhotoPutBlock(interp, dm_img, &dm_data, 0, 0, dm_data.width, 
dm_data.height, TK_PHOTO_COMPOSITE_SET);
-
-    return TCL_OK;
-}
-
-int
-image_resize_view(ClientData clientData, Tcl_Interp *interp, int argc, char 
**argv)
-{
-    if (argc != 3) {
-       std::cerr << "Unexpected argc: " << argc << "\n";
-       return TCL_ERROR;
-    }
-
-    // Unpack the coordinates (checking errno, although it may not truly be
-    // necessary if we trust Tk to always give us valid coordinates...)
-    char *p_end;
-    errno = 0;
-    long width = strtol(argv[1], &p_end, 10);
-    if (errno == ERANGE || (errno != 0 && width == 0) || p_end == argv[1]) {
-       std::cerr << "Invalid width: " << argv[1] << "\n";
-       return TCL_ERROR;
-    }
-    errno = 0;
-    long height = strtol(argv[2], &p_end, 10);
-    if (errno == ERANGE || (errno != 0 && height == 0) || p_end == argv[1]) {
-       std::cerr << "Invalid height: " << argv[2] << "\n";
-       return TCL_ERROR;
-    }
-
-    // Set the new photo size.
-    Tk_PhotoHandle dm_img = Tk_FindPhoto(interp, DM_PHOTO);
-    Tk_PhotoSetSize(interp, dm_img, width, height);
-
-    image_update_data(clientData, interp, 0, NULL);
-
-    return TCL_OK;
-}
-
-
-int
-main(int UNUSED(argc), const char *argv[])
-{
-    std::string bind_cmd;
-
-    // For now, just use a fixed 512x512 image size
-    int wsize = 512;
-
-    // Set up random image data generation so we can simulate a raytrace or
-    // raster changing the view data.  We need to use these for subsequent
-    // image updating, so pack them into a structure we can pass through Tcl's
-    // evaluations.
-    std::default_random_engine gen;
-    std::uniform_int_distribution<int> colors(0,1);
-    std::uniform_int_distribution<int> vals(0,255);
-    struct img_data idata;
-    idata.gen = &gen;
-    idata.colors = &colors;
-    idata.vals = &vals;
-
-    // Set up Tcl/Tk
-    Tcl_FindExecutable(argv[0]);
-    Tcl_Interp *interp = Tcl_CreateInterp();
-    Tcl_Init(interp);
-    Tk_Init(interp);
-
-    // Make a simple toplevel window
-    Tk_Window tkwin = Tk_MainWindow(interp);
-    Tk_GeometryRequest(tkwin, wsize, wsize);
-    Tk_MakeWindowExist(tkwin);
-    Tk_MapWindow(tkwin);
-
-    // Create the (initially empty) Tcl/Tk Photo (a.k.a color image) we will
-    // use as our rendering canvas for the images.
-    //
-    // Note: confirmed with Tcl/Tk community that (at least as of Tcl/Tk 8.6)
-    // Tcl_Eval is the ONLY way to create an image object.  The C API doesn't
-    // expose that ability, although it does support manipulation of the
-    // created object.
-    std::string img_cmd = std::string("image create photo ") + 
std::string(DM_PHOTO);
-    Tcl_Eval(interp, img_cmd.c_str());
-    Tk_PhotoHandle dm_img = Tk_FindPhoto(interp, DM_PHOTO);
-    Tk_PhotoBlank(dm_img);
-    Tk_PhotoSetSize(interp, dm_img, wsize, wsize);
-
-    // Initialize the PhotoImageBlock information for a color image of size
-    // 500x500 pixels.
-    Tk_PhotoImageBlock dm_data;
-    dm_data.width = wsize;
-    dm_data.height = wsize;
-    dm_data.pixelSize = 4;
-    dm_data.pitch = wsize * 4;
-    dm_data.offset[0] = 0;
-    dm_data.offset[1] = 1;
-    dm_data.offset[2] = 2;
-    dm_data.offset[3] = 3;
-
-    // Actually create our memory for the image buffer.  Expects RGBA 
information
-    dm_data.pixelPtr = (unsigned char *)Tcl_AttemptAlloc(dm_data.width * 
dm_data.height * 4);
-    if (!dm_data.pixelPtr) {
-       std::cerr << "Tcl/Tk photo memory allocation failed!\n";
-       exit(1);
-    }
-
-    // For each pixel, get a random color value and set it in the image memory 
buffer.
-    // This alters the actual data, but Tcl/Tk doesn't know about it yet.
-    for (int i = 0; i < (dm_data.width * dm_data.height * 4); i+=4) {
-       // Red
-       dm_data.pixelPtr[i] = 0;
-       // Green
-       dm_data.pixelPtr[i+1] = (*idata.vals)((*idata.gen));
-       // Blue
-       dm_data.pixelPtr[i+2] = 0;
-       // Alpha at 255 - we dont' want transparency for this demo.
-       dm_data.pixelPtr[i+3] = 255;
-    }
-
-    // Let Tk_Photo know we have data
-    Tk_PhotoPutBlock(interp, dm_img, &dm_data, 0, 0, dm_data.width, 
dm_data.height, TK_PHOTO_COMPOSITE_SET);
-
-
-    // Define a canvas widget, pack it into the root window, and associate the 
image with it
-    // TODO - should the canvas be inside a frame?
-    std::string canvas_cmd = std::string("canvas ") + std::string(DM_CANVAS) + 
std::string(" -width ") + std::to_string(wsize) + std::string(" -height ")  + 
std::to_string(wsize) + std::string(" -borderwidth 0");
-    Tcl_Eval(interp, canvas_cmd.c_str());
-    std::string pack_cmd = std::string("pack ") + std::string(DM_CANVAS) + 
std::string(" -fill both -expand 1");
-    Tcl_Eval(interp, pack_cmd.c_str());
-    std::string canvas_img_cmd = std::string(DM_CANVAS) + std::string(" create 
image 0 0 -image ") + std::string(DM_PHOTO) + std::string(" -anchor nw");
-    Tcl_Eval(interp, canvas_img_cmd.c_str());
-
-
-    // Register a paint command so we can change the image contents neary the 
cursor position
-    (void)Tcl_CreateCommand(interp, "image_paint", (Tcl_CmdProc 
*)image_paint_xy, NULL, (Tcl_CmdDeleteProc* )NULL);
-    // Establish the Button-1+Motion combination event as the trigger for 
drawing on the image
-    bind_cmd = std::string("bind . <B1-Motion> {image_paint %x %y}");
-    Tcl_Eval(interp, bind_cmd.c_str());
-
-
-    // Register an update command so we can change the image contents
-    (void)Tcl_CreateCommand(interp, "image_update", (Tcl_CmdProc 
*)image_update_data, (ClientData)&idata, (Tcl_CmdDeleteProc* )NULL);
-    // Establish the Button-2 and Button-3 event as triggers for updating the 
image contents
-    bind_cmd = std::string("bind . <Button-2> {image_update}");
-    Tcl_Eval(interp, bind_cmd.c_str());
-    bind_cmd = std::string("bind . <Button-3> {image_update}");
-    Tcl_Eval(interp, bind_cmd.c_str());
-
-    // Register a callback to change the image size in response to a window 
change
-    (void)Tcl_CreateCommand(interp, "image_resize", (Tcl_CmdProc 
*)image_resize_view, (ClientData)&idata, (Tcl_CmdDeleteProc* )NULL);
-    // Establish the Button-1+Motion combination event as the trigger for 
drawing on the image
-    bind_cmd = std::string("bind ") + std::string(DM_CANVAS) + std::string(" 
<Configure> {image_resize [winfo width %W] [winfo height %W]\"}");
-    Tcl_Eval(interp, bind_cmd.c_str());
-
-    // Enter the main applicatio loop - the initial image will appear, and 
Button-1 mouse
-    // clicks on the window should generate and display new images
-    while (1) {
-       Tcl_DoOneEvent(0);
-       if (!Tk_GetNumMainWindows()) {
-           // If we've closed the window, we're done
-           exit(0);
-       }
-    }
-}
-
-// Local Variables:
-// tab-width: 8
-// mode: C++
-// c-basic-offset: 4
-// indent-tabs-mode: t
-// c-file-style: "stroustrup"
-// End:
-// ex: shiftwidth=4 tabstop=8

Added: brlcad/trunk/src/libdm/tests/CMakeLists.txt
===================================================================
--- brlcad/trunk/src/libdm/tests/CMakeLists.txt                         (rev 0)
+++ brlcad/trunk/src/libdm/tests/CMakeLists.txt 2020-04-27 20:14:37 UTC (rev 
75616)
@@ -0,0 +1,14 @@
+if (BRLCAD_ENABLE_TK)
+  BRLCAD_ADDEXEC(tcl_img tcl_img.cpp "libdm;${TCL_LIBRARY};${TK_LIBRARY}" 
TEST_USEDATA)
+endif (BRLCAD_ENABLE_TK)
+
+CMAKEFILES(CMakeLists.txt)
+CMAKEFILES(tcl_img.cpp)
+
+# Local Variables:
+# tab-width: 8
+# mode: cmake
+# indent-tabs-mode: t
+# End:
+# ex: shiftwidth=2 tabstop=8
+


Property changes on: brlcad/trunk/src/libdm/tests/CMakeLists.txt
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Copied: brlcad/trunk/src/libdm/tests/tcl_img.cpp (from rev 75615, 
brlcad/trunk/src/libdm/tcl_img.cpp)
===================================================================
--- brlcad/trunk/src/libdm/tests/tcl_img.cpp                            (rev 0)
+++ brlcad/trunk/src/libdm/tests/tcl_img.cpp    2020-04-27 20:14:37 UTC (rev 
75616)
@@ -0,0 +1,312 @@
+/*                     T C L _ I M G . C P P
+ * BRL-CAD
+ *
+ * Published in 2020 by the United States Government.
+ * This work is in the public domain.
+ *
+ */
+/** @file tcl_img.cpp
+ *
+ * Self contained example of working with image data
+ * in Tcl/Tk in C/C++
+ *
+ * Eventually this should probably turn into a Togl-esque
+ * widget that we properly include, so we ensure that our
+ * window is behaving the way Tk expects it to for things
+ * like refresh.  Our current behavior in that regard is
+ * a bit iffy - ogl works but I'm not convinced that's
+ * because we're doing the Tcl/Tk bits right, and X is
+ * doing low level blitting and other X calls (which
+ * isn't great for maintainability/portability and
+ * can be a headache for debugging.)
+ *
+ */
+
+#include "common.h"
+
+#include <random>
+#include <iostream>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "tcl.h"
+#include "tk.h"
+
+const char *DM_PHOTO = ".dm0.photo";
+const char *DM_CANVAS = ".dm0";
+
+/* Container holding image generation information - need to be able
+ * to pass these to the update command */
+struct img_data {
+    std::default_random_engine *gen;
+    std::uniform_int_distribution<int> *colors;
+    std::uniform_int_distribution<int> *vals;
+};
+
+int
+image_update_data(ClientData clientData, Tcl_Interp *interp, int UNUSED(argc), 
char **UNUSED(argv))
+{
+    struct img_data *idata = (struct img_data *)clientData;
+
+    // Look up the internals of the image - we're going to directly manipulate
+    // the values of the image to simulate a display manager or framebuffer
+    // changing the visual via rendering.
+    Tk_PhotoImageBlock dm_data;
+    Tk_PhotoHandle dm_img = Tk_FindPhoto(interp, DM_PHOTO);
+    Tk_PhotoGetImage(dm_img, &dm_data);
+
+    // To get a little visual variation and make it easer to see changes,
+    // randomly turn on/off the individual colors for each pass.
+    int r = (*idata->colors)((*idata->gen));
+    int g = (*idata->colors)((*idata->gen));
+    int b = (*idata->colors)((*idata->gen));
+
+    // For each pixel, get a random color value and set it in the image memory 
buffer.
+    // This alters the actual data, but Tcl/Tk doesn't know about it yet.
+    for (int i = 0; i < (dm_data.width * dm_data.height * 4); i+=4) {
+       // Red
+       dm_data.pixelPtr[i] = (r) ? (*idata->vals)((*idata->gen)) : 0;
+       // Green
+       dm_data.pixelPtr[i+1] = (g) ? (*idata->vals)((*idata->gen)) : 0;
+       // Blue
+       dm_data.pixelPtr[i+2] = (b) ? (*idata->vals)((*idata->gen)) : 0;
+       // Alpha stays at 255 (Don't really need to set it since it should
+       // already be set, just doing so for local clarity about what should be
+       // happening with the buffer data...)
+       dm_data.pixelPtr[i+3] = 255;
+    }
+
+    // Let Tcl/Tk know the photo data has changed, so it can update the 
visuals accordingly
+    Tk_PhotoPutBlock(interp, dm_img, &dm_data, 0, 0, dm_data.width, 
dm_data.height, TK_PHOTO_COMPOSITE_SET);
+
+    return TCL_OK;
+}
+
+// Given an X,Y coordinate in a TkPhoto image and a desired offset in
+// X and Y, return the index value into the pixelPtr array N such that
+// N is the integer value of the R color at that X,Y coordiante, N+1
+// is the G value, N+2 is the B value and N+3 is the Alpha value.
+// If either desired offset is beyond the width and height boundaries,
+// cap the return at the minimum/maximum allowed value.
+static int
+img_xy_index(int width, int height, int x, int y, int dx, int dy)
+{
+    int nx = ((x + dx) > width)  ? width  : ((x + dx) < 0) ? 0 : x + dx;
+    int ny = ((y + dy) > height) ? height : ((y + dy) < 0) ? 0 : y + dy;
+    return (ny * width * 4) + nx * 4;
+}
+
+int
+image_paint_xy(ClientData UNUSED(clientData), Tcl_Interp *interp, int argc, 
char **argv)
+{
+    if (argc != 3) {
+       std::cerr << "Unexpected argc: " << argc << "\n";
+       return TCL_ERROR;
+    }
+
+    // Unpack the coordinates (checking errno, although it may not truly be
+    // necessary if we trust Tk to always give us valid coordinates...)
+    char *p_end;
+    errno = 0;
+    long xcoor = strtol(argv[1], &p_end, 10);
+    if (errno == ERANGE || (errno != 0 && xcoor == 0) || p_end == argv[1]) {
+       std::cerr << "Invalid image_paint_xy X coordinate: " << argv[1] << "\n";
+       return TCL_ERROR;
+    }
+    errno = 0;
+    long ycoor = strtol(argv[2], &p_end, 10);
+    if (errno == ERANGE || (errno != 0 && ycoor == 0) || p_end == argv[1]) {
+       std::cerr << "Invalid image_paint_xy Y coordinate: " << argv[2] << "\n";
+       return TCL_ERROR;
+    }
+
+    // Look up the internals of the image - we're going to directly manipulate
+    // the values of the image to simulate a display manager or framebuffer
+    // changing the visual via rendering.
+    Tk_PhotoImageBlock dm_data;
+    Tk_PhotoHandle dm_img = Tk_FindPhoto(interp, DM_PHOTO);
+    Tk_PhotoGetImage(dm_img, &dm_data);
+
+
+    for (int i = -2; i < 3; i++) {
+       for (int j = -2; j < 3; j++) {
+           int pindex = img_xy_index(dm_data.width, dm_data.height, xcoor, 
ycoor, i, j);
+           // Set to opaque white
+           dm_data.pixelPtr[pindex] = 255;
+           dm_data.pixelPtr[pindex+1] = 255;
+           dm_data.pixelPtr[pindex+2] = 255;
+           dm_data.pixelPtr[pindex+3] = 255;
+       }
+    }
+
+    // Let Tcl/Tk know the photo data has changed, so it can update the 
visuals accordingly.
+    Tk_PhotoPutBlock(interp, dm_img, &dm_data, 0, 0, dm_data.width, 
dm_data.height, TK_PHOTO_COMPOSITE_SET);
+
+    return TCL_OK;
+}
+
+int
+image_resize_view(ClientData clientData, Tcl_Interp *interp, int argc, char 
**argv)
+{
+    if (argc != 3) {
+       std::cerr << "Unexpected argc: " << argc << "\n";
+       return TCL_ERROR;
+    }
+
+    // Unpack the coordinates (checking errno, although it may not truly be
+    // necessary if we trust Tk to always give us valid coordinates...)
+    char *p_end;
+    errno = 0;
+    long width = strtol(argv[1], &p_end, 10);
+    if (errno == ERANGE || (errno != 0 && width == 0) || p_end == argv[1]) {
+       std::cerr << "Invalid width: " << argv[1] << "\n";
+       return TCL_ERROR;
+    }
+    errno = 0;
+    long height = strtol(argv[2], &p_end, 10);
+    if (errno == ERANGE || (errno != 0 && height == 0) || p_end == argv[1]) {
+       std::cerr << "Invalid height: " << argv[2] << "\n";
+       return TCL_ERROR;
+    }
+
+    // Set the new photo size.
+    Tk_PhotoHandle dm_img = Tk_FindPhoto(interp, DM_PHOTO);
+    Tk_PhotoSetSize(interp, dm_img, width, height);
+
+    image_update_data(clientData, interp, 0, NULL);
+
+    return TCL_OK;
+}
+
+
+int
+main(int UNUSED(argc), const char *argv[])
+{
+    std::string bind_cmd;
+
+    // For now, just use a fixed 512x512 image size
+    int wsize = 512;
+
+    // Set up random image data generation so we can simulate a raytrace or
+    // raster changing the view data.  We need to use these for subsequent
+    // image updating, so pack them into a structure we can pass through Tcl's
+    // evaluations.
+    std::default_random_engine gen;
+    std::uniform_int_distribution<int> colors(0,1);
+    std::uniform_int_distribution<int> vals(0,255);
+    struct img_data idata;
+    idata.gen = &gen;
+    idata.colors = &colors;
+    idata.vals = &vals;
+
+    // Set up Tcl/Tk
+    Tcl_FindExecutable(argv[0]);
+    Tcl_Interp *interp = Tcl_CreateInterp();
+    Tcl_Init(interp);
+    Tk_Init(interp);
+
+    // Make a simple toplevel window
+    Tk_Window tkwin = Tk_MainWindow(interp);
+    Tk_GeometryRequest(tkwin, wsize, wsize);
+    Tk_MakeWindowExist(tkwin);
+    Tk_MapWindow(tkwin);
+
+    // Create the (initially empty) Tcl/Tk Photo (a.k.a color image) we will
+    // use as our rendering canvas for the images.
+    //
+    // Note: confirmed with Tcl/Tk community that (at least as of Tcl/Tk 8.6)
+    // Tcl_Eval is the ONLY way to create an image object.  The C API doesn't
+    // expose that ability, although it does support manipulation of the
+    // created object.
+    std::string img_cmd = std::string("image create photo ") + 
std::string(DM_PHOTO);
+    Tcl_Eval(interp, img_cmd.c_str());
+    Tk_PhotoHandle dm_img = Tk_FindPhoto(interp, DM_PHOTO);
+    Tk_PhotoBlank(dm_img);
+    Tk_PhotoSetSize(interp, dm_img, wsize, wsize);
+
+    // Initialize the PhotoImageBlock information for a color image of size
+    // 500x500 pixels.
+    Tk_PhotoImageBlock dm_data;
+    dm_data.width = wsize;
+    dm_data.height = wsize;
+    dm_data.pixelSize = 4;
+    dm_data.pitch = wsize * 4;
+    dm_data.offset[0] = 0;
+    dm_data.offset[1] = 1;
+    dm_data.offset[2] = 2;
+    dm_data.offset[3] = 3;
+
+    // Actually create our memory for the image buffer.  Expects RGBA 
information
+    dm_data.pixelPtr = (unsigned char *)Tcl_AttemptAlloc(dm_data.width * 
dm_data.height * 4);
+    if (!dm_data.pixelPtr) {
+       std::cerr << "Tcl/Tk photo memory allocation failed!\n";
+       exit(1);
+    }
+
+    // For each pixel, get a random color value and set it in the image memory 
buffer.
+    // This alters the actual data, but Tcl/Tk doesn't know about it yet.
+    for (int i = 0; i < (dm_data.width * dm_data.height * 4); i+=4) {
+       // Red
+       dm_data.pixelPtr[i] = 0;
+       // Green
+       dm_data.pixelPtr[i+1] = (*idata.vals)((*idata.gen));
+       // Blue
+       dm_data.pixelPtr[i+2] = 0;
+       // Alpha at 255 - we dont' want transparency for this demo.
+       dm_data.pixelPtr[i+3] = 255;
+    }
+
+    // Let Tk_Photo know we have data
+    Tk_PhotoPutBlock(interp, dm_img, &dm_data, 0, 0, dm_data.width, 
dm_data.height, TK_PHOTO_COMPOSITE_SET);
+
+
+    // Define a canvas widget, pack it into the root window, and associate the 
image with it
+    // TODO - should the canvas be inside a frame?
+    std::string canvas_cmd = std::string("canvas ") + std::string(DM_CANVAS) + 
std::string(" -width ") + std::to_string(wsize) + std::string(" -height ")  + 
std::to_string(wsize) + std::string(" -borderwidth 0");
+    Tcl_Eval(interp, canvas_cmd.c_str());
+    std::string pack_cmd = std::string("pack ") + std::string(DM_CANVAS) + 
std::string(" -fill both -expand 1");
+    Tcl_Eval(interp, pack_cmd.c_str());
+    std::string canvas_img_cmd = std::string(DM_CANVAS) + std::string(" create 
image 0 0 -image ") + std::string(DM_PHOTO) + std::string(" -anchor nw");
+    Tcl_Eval(interp, canvas_img_cmd.c_str());
+
+
+    // Register a paint command so we can change the image contents neary the 
cursor position
+    (void)Tcl_CreateCommand(interp, "image_paint", (Tcl_CmdProc 
*)image_paint_xy, NULL, (Tcl_CmdDeleteProc* )NULL);
+    // Establish the Button-1+Motion combination event as the trigger for 
drawing on the image
+    bind_cmd = std::string("bind . <B1-Motion> {image_paint %x %y}");
+    Tcl_Eval(interp, bind_cmd.c_str());
+
+
+    // Register an update command so we can change the image contents
+    (void)Tcl_CreateCommand(interp, "image_update", (Tcl_CmdProc 
*)image_update_data, (ClientData)&idata, (Tcl_CmdDeleteProc* )NULL);
+    // Establish the Button-2 and Button-3 event as triggers for updating the 
image contents
+    bind_cmd = std::string("bind . <Button-2> {image_update}");
+    Tcl_Eval(interp, bind_cmd.c_str());
+    bind_cmd = std::string("bind . <Button-3> {image_update}");
+    Tcl_Eval(interp, bind_cmd.c_str());
+
+    // Register a callback to change the image size in response to a window 
change
+    (void)Tcl_CreateCommand(interp, "image_resize", (Tcl_CmdProc 
*)image_resize_view, (ClientData)&idata, (Tcl_CmdDeleteProc* )NULL);
+    // Establish the Button-1+Motion combination event as the trigger for 
drawing on the image
+    bind_cmd = std::string("bind ") + std::string(DM_CANVAS) + std::string(" 
<Configure> {image_resize [winfo width %W] [winfo height %W]\"}");
+    Tcl_Eval(interp, bind_cmd.c_str());
+
+    // Enter the main applicatio loop - the initial image will appear, and 
Button-1 mouse
+    // clicks on the window should generate and display new images
+    while (1) {
+       Tcl_DoOneEvent(0);
+       if (!Tk_GetNumMainWindows()) {
+           // If we've closed the window, we're done
+           exit(0);
+       }
+    }
+}
+
+// Local Variables:
+// tab-width: 8
+// mode: C++
+// c-basic-offset: 4
+// indent-tabs-mode: t
+// c-file-style: "stroustrup"
+// End:
+// ex: shiftwidth=4 tabstop=8

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