Revision: 75605
http://sourceforge.net/p/brlcad/code/75605
Author: starseeker
Date: 2020-04-25 15:19:06 +0000 (Sat, 25 Apr 2020)
Log Message:
-----------
Code cleanup, add comments. Next step will be to try and get an update
response for mouse motion, not simply button clicking.
Modified Paths:
--------------
brlcad/trunk/src/libdm/tcl_img.cpp
Modified: brlcad/trunk/src/libdm/tcl_img.cpp
===================================================================
--- brlcad/trunk/src/libdm/tcl_img.cpp 2020-04-25 14:51:39 UTC (rev 75604)
+++ brlcad/trunk/src/libdm/tcl_img.cpp 2020-04-25 15:19:06 UTC (rev 75605)
@@ -25,7 +25,6 @@
#include "common.h"
#include <random>
-#include <vector>
#include <iostream>
#include "tcl.h"
@@ -34,6 +33,8 @@
const char *DM_PHOTO = ".dm0.photo";
const char *DM_LABEL = ".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;
@@ -44,14 +45,22 @@
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;
@@ -59,14 +68,15 @@
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
+ // 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);
- // Pause a second after updating
- //std::this_thread::sleep_for (std::chrono::seconds(1));
-
return TCL_OK;
}
@@ -73,40 +83,41 @@
int
main(int UNUSED(argc), const char *argv[])
{
+
+ // 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;
- idata.gen = &gen;
- idata.colors = &colors;
- idata.vals = &vals;
-
- std::vector<int> rgb;
- int wsize = 512;
-
- for (int i = 0; i < wsize; i++) {
- for (int j = 0; j < wsize; j++) {
- rgb.push_back(0);
- rgb.push_back(vals(gen));
- rgb.push_back(0);
- rgb.push_back(255);
- }
- }
-
+ // 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);
- /* 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 just
- * doesn't expose that ability, although it does support manipulation of
- * the created object. */
+ // 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);
@@ -113,6 +124,8 @@
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;
@@ -122,17 +135,28 @@
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 (int i = 0; i < (dm_data.width * dm_data.height * 4); i++) {
- // Initialize the buffer with random values (simulates on-the-fly
- // buffer generation from a rasterization or raytrace)
- dm_data.pixelPtr[i] = rgb[i];
+
+ // 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, wsize, wsize,
TK_PHOTO_COMPOSITE_SET);
// TODO - examples use a label to pack and display an image - is this the
@@ -142,13 +166,15 @@
std::string pack_cmd = std::string("pack ") + std::string(DM_LABEL);
Tcl_Eval(interp, pack_cmd.c_str());
- // Register an update command
+ // 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 Button-1 as the trigger for updating the image contents
+ // Establish the Button-1 event as the trigger for updating the image
contents
std::string bind_cmd = std::string("bind . <Button-1> \"image_update\"");
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) {
int handled = 0;
while (Tcl_DoOneEvent(TCL_ALL_EVENTS|TCL_DONT_WAIT)) {
@@ -159,7 +185,6 @@
exit(0);
}
}
-
}
// Local Variables:
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