00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #ifndef SCRIPT_IMAGETKSCRIPT_C_DEFINED
00039 #define SCRIPT_IMAGETKSCRIPT_C_DEFINED
00040
00041 #include "Script/ImageTkScript.H"
00042
00043 #include "Image/Image.H"
00044 #include "Image/Pixels.H"
00045 #include "Script/ImageScript.H"
00046 #include "Util/Assert.H"
00047 #include "Util/Types.H"
00048 #include "Util/log.H"
00049 #include "tcl/interp.h"
00050 #include "tcl/pkg.h"
00051
00052 #include <X11/Xlib.h>
00053 #include <X11/Xutil.h>
00054 #include <X11/extensions/XShm.h>
00055 #include <stdlib.h>
00056 #include <sys/shm.h>
00057 #include <tk.h>
00058
00059 namespace
00060 {
00061 int fourByteAlign(int v)
00062 {
00063 const int remainder = v % 4;
00064 return (remainder == 0) ? v : v + (4-remainder);
00065 }
00066 }
00067
00068 template <class T>
00069 struct ImageTk
00070 {
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080 static Tk_ImageType imageType;
00081
00082 struct Master
00083 {
00084 Tk_ImageMaster token;
00085 Image<T> image;
00086 };
00087
00088 struct Instance
00089 {
00090 Master* const master;
00091 Tk_Window const tkwin;
00092 GC gc;
00093 XImage* image;
00094 XShmSegmentInfo shminfo;
00095 char* buffer;
00096 bool shm_buffer;
00097
00098 Instance(Tk_Window tkw, Master* m)
00099 :
00100 master(m),
00101 tkwin(tkw),
00102 gc(0),
00103 image(0)
00104 {
00105 const Image<PixRGB<byte> > img = m->image;
00106
00107 const Dims idims = img.getDims();
00108
00109
00110 int byt_per_pix = 4;
00111 if (Tk_Depth(tkwin) == 16) byt_per_pix = 2;
00112
00113
00114 int Shm_OK = XShmQueryExtension(Tk_Display(tkwin));
00115
00116
00117 char* disp = getenv("DISPLAY");
00118 if (disp != NULL && disp[0] != ':')
00119 {
00120 Shm_OK = 0;
00121 LDEBUG("Not using shared memory for remote display");
00122 }
00123
00124
00125 const int padded_width = fourByteAlign(idims.w());
00126
00127
00128 if (Shm_OK)
00129 {
00130 shminfo.shmid = shmget(IPC_PRIVATE,
00131 padded_width*idims.h()*byt_per_pix,
00132 IPC_CREAT | 0777);
00133 buffer = (char *)shmat(shminfo.shmid, NULL, 0);
00134 if (buffer == 0) LFATAL("Cannot get shared memory");
00135 shminfo.shmaddr = buffer;
00136 shminfo.readOnly = False;
00137 XShmAttach(Tk_Display(tkwin), &shminfo);
00138 shm_buffer = true;
00139 }
00140 else
00141 {
00142 const int bufsiz = padded_width * idims.h() * byt_per_pix;
00143 buffer = (char *)malloc(bufsiz);
00144 LDEBUG("buffer: %p", buffer);
00145 if (buffer == NULL) LFATAL("Cannot allocate image buffer");
00146 shm_buffer = false;
00147 }
00148
00149 uint idepth;
00150 int pad;
00151
00152
00153 if (byt_per_pix == 2)
00154 { idepth = 16; pad = 16;}
00155 else
00156 { idepth = 24; pad = 32;}
00157
00158 if (shm_buffer)
00159
00160 image = XShmCreateImage(Tk_Display(tkwin), Tk_Visual(tkwin), idepth, ZPixmap,
00161 buffer, &shminfo, idims.w(), idims.h());
00162 else
00163
00164 image = XCreateImage(Tk_Display(tkwin), Tk_Visual(tkwin), idepth,
00165 ZPixmap , 0, buffer,
00166 idims.w(), idims.h(), pad,
00167 fourByteAlign(byt_per_pix * idims.w()));
00168
00169 int w = idims.w(); int h = idims.h();
00170
00171 const byte* im = reinterpret_cast<const byte*>(img.getArrayPtr());
00172 byte* bu = reinterpret_cast<byte*>(buffer);
00173
00174 if (byt_per_pix == 2)
00175 {
00176 const int bytes_per_row = fourByteAlign(byt_per_pix * w);
00177
00178
00179 for (int j = 0; j < h; ++j)
00180 {
00181 byte* bu_row = bu + j*bytes_per_row;
00182 for (int i = 0; i < w; ++i)
00183 {
00184 *bu_row++ = ((im[1] & 0x1C)<<3) | ((im[2] & 0xF8)>>3);
00185 *bu_row++ = ((im[1] & 0xE0)>>5) | (im[0] & 0xF8);
00186 im += 3;
00187 }
00188 }
00189 }
00190 else
00191 {
00192
00193 for (int i = 0; i < w * h; i ++)
00194 { *bu++ = im[2]; *bu++ = im[1]; *bu++ = *im; *bu++ = 255; im += 3; }
00195 }
00196 }
00197
00198 ~Instance()
00199 {
00200 if (this->shm_buffer)
00201 {
00202 XShmDetach(Tk_Display(this->tkwin), &this->shminfo);
00203 }
00204
00205 if (this->image)
00206 {
00207
00208
00209
00210
00211
00212
00213 this->image->data = 0;
00214 XDestroyImage(this->image);
00215 this->image = 0;
00216 }
00217
00218 if (this->shm_buffer)
00219 {
00220 shmdt(this->shminfo.shmaddr);
00221 shmctl(this->shminfo.shmid, IPC_RMID, NULL);
00222 }
00223 else
00224 {
00225 free(this->buffer);
00226 }
00227
00228 if (this->gc)
00229 XFreeGC(Tk_Display(this->tkwin), this->gc);
00230 }
00231
00232 void draw(Display* display,
00233 Drawable drawable,
00234 int imageX, int imageY,
00235 int width, int height,
00236 int drawableX, int drawableY)
00237 {
00238 if (this->gc == 0)
00239 this->gc = XCreateGC(display, drawable, 0, NULL);
00240
00241 if (this->shm_buffer)
00242 XShmPutImage(display, drawable, this->gc, this->image,
00243 imageX, imageY, drawableX, drawableY,
00244 width, height, 0);
00245 else
00246 XPutImage(display, drawable, this->gc, this->image,
00247 imageX, imageY, drawableX, drawableY,
00248 width, height);
00249 XFlush(display);
00250 }
00251 };
00252
00253 #ifdef INVT_NEWER_TCL_VERSION
00254 static int createMaster(Tcl_Interp* intp,
00255 const char* name,
00256 int objc,
00257 Tcl_Obj* CONST objv[],
00258 const Tk_ImageType* typePtr,
00259 Tk_ImageMaster token,
00260 ClientData* masterDataPtr)
00261 #else
00262 static int createMaster(Tcl_Interp* intp,
00263 char* name,
00264 int objc,
00265 Tcl_Obj* CONST objv[],
00266 Tk_ImageType* typePtr,
00267 Tk_ImageMaster token,
00268 ClientData* masterDataPtr)
00269 #endif
00270 {
00271 tcl::interpreter interp(intp);
00272
00273 try
00274 {
00275 if (objc != 1)
00276 {
00277 Tcl_AppendResult
00278 (intp, "wrong # args: expected\n"
00279 "\timage create Image<type> name img", 0);
00280 return TCL_ERROR;
00281 }
00282
00283 const Image<T> image = tcl::convert_to<Image<T> >(objv[0]);
00284
00285 Master* master = new Master;
00286
00287 master->token = token;
00288 master->image = image;
00289
00290 *masterDataPtr = static_cast<void*>(master);
00291
00292 Tk_ImageChanged(token, 0, 0,
00293 master->image.getWidth(),
00294 master->image.getHeight(),
00295 master->image.getWidth(),
00296 master->image.getHeight());
00297
00298 return TCL_OK;
00299 }
00300 catch (...)
00301 {
00302 interp.handle_live_exception(imageType.name, SRC_POS);
00303 }
00304 return TCL_ERROR;
00305 }
00306
00307 static ClientData getInstance(Tk_Window tkwin,
00308 ClientData masterData)
00309 {
00310 return static_cast<void*>
00311 (new Instance(tkwin, static_cast<Master*>(masterData)));
00312 }
00313
00314 static void displayInstance(ClientData instanceData,
00315 Display* display,
00316 Drawable drawable,
00317 int imageX,
00318 int imageY,
00319 int width,
00320 int height,
00321 int drawableX,
00322 int drawableY)
00323 {
00324 LDEBUG("image x=%d, y=%d", imageX, imageY);
00325 LDEBUG("image w=%d, h=%d", width, height);
00326 LDEBUG("drawable x=%d, y=%d", drawableX, drawableY);
00327
00328 Instance* instance = static_cast<Instance*>(instanceData);
00329
00330 instance->draw(display, drawable, imageX, imageY,
00331 width, height, drawableX, drawableY);
00332 }
00333
00334 static void freeInstance(ClientData instanceData,
00335 Display* display)
00336 {
00337 delete static_cast<Instance*>(instanceData);
00338 }
00339
00340 static void deleteMaster(ClientData masterData)
00341 {
00342 delete static_cast<Master*>(masterData);
00343 }
00344 };
00345
00346 #ifdef INVT_NEWER_TCL_VERSION
00347
00348 #define INST_IMG_TK_TYPE(T) \
00349 \
00350 template <> \
00351 Tk_ImageType ImageTk< T >::imageType = \
00352 { \
00353 "Image<" #T ">", \
00354 &ImageTk< T >::createMaster, \
00355 &ImageTk< T >::getInstance, \
00356 &ImageTk< T >::displayInstance, \
00357 &ImageTk< T >::freeInstance, \
00358 &ImageTk< T >::deleteMaster \
00359 }
00360 #else
00361 #define INST_IMG_TK_TYPE(T) \
00362 \
00363 template <> \
00364 Tk_ImageType ImageTk< T >::imageType = \
00365 { \
00366 const_cast<char*>("Image<" #T ">"), \
00367 &ImageTk< T >::createMaster, \
00368 &ImageTk< T >::getInstance, \
00369 &ImageTk< T >::displayInstance, \
00370 &ImageTk< T >::freeInstance, \
00371 &ImageTk< T >::deleteMaster \
00372 }
00373 #endif
00374
00375 INST_IMG_TK_TYPE(byte);
00376 INST_IMG_TK_TYPE(float);
00377 INST_IMG_TK_TYPE(PixRGB<byte>);
00378 INST_IMG_TK_TYPE(PixRGB<float>);
00379
00380
00381 extern "C"
00382 int Imagetk_Init(Tcl_Interp* interp)
00383 {
00384 GVX_PKG_CREATE(pkg, interp, "ImageTk", "4.$Revision: 1$");
00385
00386 Tk_CreateImageType(&ImageTk<byte>::imageType);
00387 Tk_CreateImageType(&ImageTk<float>::imageType);
00388 Tk_CreateImageType(&ImageTk<PixRGB<byte> >::imageType);
00389 Tk_CreateImageType(&ImageTk<PixRGB<float> >::imageType);
00390
00391 GVX_PKG_RETURN(pkg);
00392 }
00393
00394
00395
00396
00397
00398
00399
00400 #endif // SCRIPT_IMAGETKSCRIPT_C_DEFINED