1 /*
2
3 *****************************************************************************
4 * Author: *
5 * ------ *
6 * Anton Kokalj Email: Tone.Kokalj@ijs.si *
7 * Department of Physical and Organic Chemistry Phone: x 386 1 477 3523 *
8 * Jozef Stefan Institute Fax: x 386 1 477 3811 *
9 * Jamova 39, SI-1000 Ljubljana *
10 * SLOVENIA *
11 * *
12 * Source: $XCRYSDEN_TOPDIR/C/xcTogl.c
13 * ------ *
14 * Copyright (c) 1996-2003 by Anton Kokalj *
15 *****************************************************************************
16
17 */
18
19 #include <togl.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <math.h>
23 #include "struct.h"
24 #include "xcfunc.h"
25
26
27 struct Togl *mesa_togl = NULL;
28 extern void (*xcDisplay)(struct Togl *togl);
29 extern NEW_WIN_CONTEXT *FindWinContextByTogl(struct Togl *togl);
30 extern OrthoProj ort;
31 extern realTimeMove makeMovie;
32
33 extern int togl_exists;
34
35 /*
36 * Togl widget create callback. This is called by Tcl/Tk when the widget has
37 * been realized. Here's where one may do some one-time context setup or
38 * initializations.
39 */
40 int
xcToglCreateFunc(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)41 xcToglCreateFunc(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
42 {
43 Togl *togl;
44 static int first_time = 1;
45
46 if (objc != 2) {
47 Tcl_WrongNumArgs(interp, 1, objv, "pathName");
48 return TCL_ERROR;
49 }
50 if ( Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK ) {
51 return TCL_ERROR;
52 }
53 //Togl_GetToglFromName(interp, ".mesa", &mesa);
54
55 /***************************************************************/
56 /* made atomic labels (only when first structure is opened */
57 /***************************************************************/
58 /* first make font */
59 if (first_time) {
60 makeRasterFont();
61 makeAtomLabels();
62 makeXYZLabels();
63 makeTemp3D2DList();
64 /* make coor-sist */
65 makeCrdList();
66 xcGenDispList();
67 first_time = 0;
68 }
69
70 if ( strcmp(Togl_Ident(togl), ".mesa") == 0 ) {
71 xcDisplayFunc(xcDummyDisplay);
72 mesa_togl = togl;
73 }
74 else {
75 NEW_WIN_CONTEXT *wc;
76 cryNewToglInit( togl );
77 wc = FindWinContextByTogl( togl );
78 wc->xcDisplay = xcDummyDisplay;
79 }
80
81 togl_exists = XC_TRUE;
82 LoadLights();
83 LoadStructMaterial();
84
85 return TCL_OK;
86 }
87
88
89 /*
90 * Togl widget reshape callback. This is called by Tcl/Tk when the widget
91 * has been resized. Typically, we call glViewport and perhaps setup the
92 * projection matrix.
93 */
94 int
xcToglReshapeFunc(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)95 xcToglReshapeFunc(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
96 {
97 Togl *togl;
98 int w, h;
99
100 if (objc != 2) {
101 Tcl_WrongNumArgs(interp, 1, objv, "pathName");
102 return TCL_ERROR;
103 }
104 if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) {
105 return TCL_ERROR;
106 }
107
108 w = Togl_Width (togl);
109 h = Togl_Height(togl);
110
111 if ( togl == mesa_togl ) {
112 /* old fashion style */
113 VPf.width = w;
114 VPf.height = h;
115 VPf.canvassize = VPf.height;
116 if ( VPf.width < VPf.height) VPf.canvassize = VPf.width;
117
118 if (VPf.stropened) {
119 xcViewPort();
120 } else {
121 float aspect = (float) VPf.width / (float) VPf.height;
122 glViewport( 0, 0, VPf.width, VPf.height );
123 glMatrixMode(GL_PROJECTION);
124 glLoadIdentity();
125 glFrustum(-aspect, aspect, -1.0, 1.0, 1.0, 10.0);
126 glMatrixMode(GL_MODELVIEW);
127 }
128 } else {
129 /* new nicer fashion */
130 NEW_WIN_CONTEXT *wc;
131
132 /*glViewport( 0, 0, VPf.width, VPf.height );*/
133 wc = FindWinContextByTogl( togl );
134 if (!wc) return TCL_ERROR;
135 wc->VPf.height = w;
136 wc->VPf.width = h;
137
138 crySetProjection( wc, togl );
139 }
140 return TCL_OK;
141 }
142
143 /*
144 * this function is called when togle widget is destroyed
145 */
146 int
xcToglDestroyFunc(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)147 xcToglDestroyFunc(ClientData clientData, Tcl_Interp *interp,
148 int objc, Tcl_Obj *const *objv)
149 {
150 Togl *togl;
151
152 if (objc != 2) {
153 Tcl_WrongNumArgs(interp, 1, objv, "pathName");
154 return TCL_ERROR;
155 }
156 if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) {
157 return TCL_ERROR;
158 }
159
160 if ( togl == mesa_togl ) {
161 /* if this happends, then XCRYSDEN is about to exit. Do nothing. */
162 /*
163 xcMaybeDestroyLists();
164 FreeAllVariables();
165 mesa_togl = NULL;
166 */
167 xcTkFontFreeAll();
168 } else {
169 xcDisplay = NULL;
170 DestroyWinContext( togl );
171 }
172
173 return TCL_OK;
174 }
175
176 /*
177 * after user has stooped rotating/translating redisplay in nicer fashion
178 */
179 int
xcToglTimerFunc(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)180 xcToglTimerFunc(ClientData clientData, Tcl_Interp *interp,
181 int objc, Tcl_Obj *const *objv)
182 {
183 Togl *togl;
184 static int toglIsInteractive = 0;
185
186 if (objc != 2) {
187 Tcl_WrongNumArgs(interp, 1, objv, "pathName");
188 return TCL_ERROR;
189 }
190 if (Togl_GetToglFromObj(interp, objv[1], &togl) != TCL_OK) {
191 return TCL_ERROR;
192 }
193
194 if ( togl == mesa_togl ) {
195
196 /* interative rotation - zooming */
197
198 if ( !toglIsInteractive && (tr.b1motion || tr.b2motion || tr.shiftB1motion) ) {
199 toglIsInteractive = 1;
200 }
201 if ( toglIsInteractive && !(tr.b1motion || tr.b2motion || tr.shiftB1motion ) ) {
202 toglIsInteractive = 0;
203 Togl_PostRedisplay(togl);
204 }
205
206 /* real-time movie making */
207 if ( makeMovie.doit && makeMovie.mode == MOVIE_MODE_REALTIME_INTERVAL ) {
208 createMoviePPMFrame(togl);
209 }
210 }
211 return TCL_OK;
212 }
213
214 /*
215 * this function takes care <B1-Motion> binding -> that's ROTATION
216 */
217 int
XC_B1MotionCb(ClientData clientData,Tcl_Interp * interp,int argc,const char * argv[])218 XC_B1MotionCb(ClientData clientData, Tcl_Interp *interp,
219 int argc, const char *argv[])
220 {
221 int xrotnew, yrotnew; /* current <x> <y> mouse pointer position */
222 int dx, dy;
223 double fiX = 0, fiY = 0, ssize;
224 Togl *togl;
225
226 if (argc != 4) {
227 Tcl_SetResult(interp,
228 "Usage: xc_B1motion <toglname> <x> <y>", TCL_STATIC);
229 return TCL_ERROR;
230 }
231
232 if ( Togl_GetToglFromName(interp, argv[1], &togl) == TCL_ERROR ) {
233 char rss[1024];
234 snprintf(rss, sizeof(rss),
235 "couldn't find %s togl widget", argv[3]);
236 Tcl_SetResult(interp, rss, TCL_VOLATILE);
237 return TCL_ERROR;
238 }
239
240 if ( Tcl_GetInt(interp, argv[2], &xrotnew) == TCL_ERROR ) {
241 char rss[1024];
242 snprintf(rss, sizeof(rss),"wanted integer for <x>, but got \"%s\" in \"<toglname> xc_B1motion <x> <y>\" command", argv[2]);
243 Tcl_SetResult(interp, rss, TCL_VOLATILE);
244 return TCL_ERROR;
245 }
246
247 if ( Tcl_GetInt(interp, argv[3], &yrotnew) == TCL_ERROR ) {
248 char rss[1024];
249 snprintf(rss, sizeof(rss),"wanted integer for <y>, but got \"%s\" in \"<toglname> xc_B1motion <x> <y>\" command", argv[3]);
250 Tcl_SetResult(interp, rss, TCL_VOLATILE);
251 return TCL_ERROR;
252 }
253
254 /********************************************/
255 /* .MESA ---------------------------------- */
256 /********************************************/
257 if ( togl == mesa_togl ) {
258 /* if structure is not opened, do noting, just return silently */
259 if (!VPf.stropened) return TCL_OK;
260
261 /* if B1-Motion just started, then new:=old and return silently */
262 if (tr.b1motion == 0) {
263 tr.b1motion = 1;
264 tr.xrotold = xrotnew;
265 tr.yrotold = yrotnew;
266 return TCL_OK;
267 }
268
269 /* how much did Xrot&Yrot differ from last time this routine was called */
270 dx = xrotnew - tr.xrotold;
271 dy = yrotnew - tr.yrotold;
272 tr.xrotold = xrotnew;
273 tr.yrotold = yrotnew;
274
275 if ( xcr.lforce ) {
276 if ( MVf.structsize > 1e-5 ) ssize = MVf.structsize * VPf.VPfactor;
277 else ssize = ort.size * VPf.VPfactor;
278 } else {
279 ssize = ort.size * VPf.VPfactor;
280 }
281
282 /* moving Mouse in X direction means rotation in Y dir !!!!! */
283 /*
284 * 4.0 is just some emperical factor to maximize performance of
285 * mouse rotation so, that it will follow mouse pointer
286 */
287 if ( dx != 0 ) fiY = atan( 4.0 * (double) dx / ssize);
288 if ( dy != 0 ) fiX = atan( 4.0 * (double) dy / ssize);
289 /* now rotate */
290 xcRotateXY( fiX, fiY );
291 /* if dimType == XC_2D, also orientate */
292 if ( dimType == XC_2D )
293 hpsort_index1(tmp_nobjects, zorient, iwksp);
294 } else {
295 /*********************/
296 /* NEW NICER FASHION */
297 /*********************/
298 NEW_WIN_CONTEXT *wc;
299 wc = FindWinContextByTogl( togl );
300
301 /* if structure is not opened, do noting, just return silently */
302 if (!wc->VPf.stropened) return TCL_OK;
303
304 /* if B1-Motion just started, then new:=old and return silently */
305 if (wc->tr.b1motion == 0) {
306 wc->tr.b1motion = 1;
307 wc->tr.xrotold = xrotnew;
308 wc->tr.yrotold = yrotnew;
309 return TCL_OK;
310 }
311
312 /* how much did Xrot&Yrot differ from last time this routine was called */
313 dx = xrotnew - wc->tr.xrotold;
314 dy = yrotnew - wc->tr.yrotold;
315 wc->tr.xrotold = xrotnew;
316 wc->tr.yrotold = yrotnew;
317 ssize = wc->MVf.structsize * wc->VPf.VPfactor;
318
319 /* moving Mouse in X direction means rotation in Y dir !!!!! */
320 /*
321 * 4.0 is just some emperical factor to maximize performance of
322 * mouse rotation so, that it will follow mouse pointer
323 */
324 if ( dx != 0 ) fiY = atan( 4.0 * (double) dx / ssize);
325 if ( dy != 0 ) fiX = atan( 4.0 * (double) dy / ssize);
326 cryRotateXY( wc, fiX, fiY );
327 }
328 Togl_PostRedisplay(togl);
329
330 return TCL_OK;
331 }
332
333
334 /*
335 * this function takes care <Shift-B1-Motion> binding -> that's ZOOMING
336 *
337 * It only register Shift-B1-Motion, so that the display-mode goes to
338 * crude mode.
339 *
340 */
341 int
XC_ShiftB1MotionCb(ClientData clientData,Tcl_Interp * interp,int argc,const char * argv[])342 XC_ShiftB1MotionCb(ClientData clientData, Tcl_Interp *interp,
343 int argc, const char *argv[])
344 {
345 Togl *togl;
346
347 if (argc != 2) {
348 Tcl_SetResult(interp,
349 "Usage: xc_ShiftB1motion <toglname> ", TCL_STATIC);
350 return TCL_ERROR;
351 }
352
353 if ( Togl_GetToglFromName(interp, argv[1], &togl) == TCL_ERROR ) {
354 char rss[1024];
355 snprintf(rss, sizeof(rss),
356 "couldn't find %s togl widget", argv[3]);
357 Tcl_SetResult(interp, rss, TCL_VOLATILE);
358 return TCL_ERROR;
359 }
360
361 /********************************************/
362 /* .MESA ---------------------------------- */
363 /********************************************/
364 if ( togl == mesa_togl ) {
365 /* if structure is not opened, do noting, just return silently */
366 if (!VPf.stropened) return TCL_OK;
367
368 /* if Shift-B1-Motion just started register that */
369 if (tr.shiftB1motion == 0) {
370 tr.shiftB1motion = 1;
371 }
372 } else {
373 /*********************/
374 /* NEW NICER FASHION */
375 /*********************/
376 NEW_WIN_CONTEXT *wc;
377 wc = FindWinContextByTogl( togl );
378
379 /* if structure is not opened, do noting, just return silently */
380 if (!wc->VPf.stropened) return TCL_OK;
381
382 /* INSERT CODE FOR REGISTERING ShiftB1Motion HERE */
383 }
384
385 Togl_PostRedisplay(togl);
386
387 return TCL_OK;
388 }
389
390
391 /*
392 * this function takes care <B2-Motion> binding -> that's TRANSLATION
393 */
394 int
XC_B2MotionCb(ClientData clientData,Tcl_Interp * interp,int argc,const char * argv[])395 XC_B2MotionCb(ClientData clientData, Tcl_Interp *interp,
396 int argc, const char *argv[])
397 {
398 int trX, trY; /* cuurent <x> <y> mouse pointer position */
399 int dx, dy;
400 Togl *togl;
401
402 if (argc != 4) {
403 Tcl_SetResult(interp,
404 "Usage: xc_B2motion <toglname> <x> <y>", TCL_STATIC);
405 return TCL_ERROR;
406 }
407
408 if ( Togl_GetToglFromName(interp, argv[1], &togl) == TCL_ERROR ) {
409 char rss[1024];
410 snprintf(rss, sizeof(rss),
411 "couldn't find %s togl widget", argv[3]);
412 Tcl_SetResult(interp, rss, TCL_VOLATILE);
413 return TCL_ERROR;
414 }
415
416 if ( Tcl_GetInt(interp, argv[2], &trX) == TCL_ERROR ) {
417 char rss[1024];
418 snprintf(rss, sizeof(rss),"wanted integer for <x>, but got \"%s\" in \"<toglname> xc_B2motion <x> <y>\" command", argv[2]);
419 Tcl_SetResult(interp, rss, TCL_VOLATILE);
420 return TCL_ERROR;
421 }
422
423 if ( Tcl_GetInt(interp, argv[3], &trY) == TCL_ERROR ) {
424 char rss[1024];
425 snprintf(rss, sizeof(rss),"wanted integer for <y>, but got \"%s\" in \"<toglname> xc_B2motion <x> <y>\" command", argv[3]);
426 Tcl_SetResult(interp, rss, TCL_VOLATILE);
427 return TCL_ERROR;
428 }
429
430
431 /********************************************/
432 /* .MESA ---------------------------------- */
433 /********************************************/
434 if ( togl == mesa_togl ) {
435 /* if structure is not opened, do noting, just return silently */
436 if (!VPf.stropened) return TCL_OK;
437
438 /* if B2-Motion just started, then new -> old and return silently */
439 if (tr.b2motion == 0) {
440 tr.b2motion = 1;
441 tr.trXold = trX;
442 tr.trYold = trY;
443 return TCL_OK;
444 }
445 /* how much did trX & trY differ from last time this routine was called */
446 dx = trX - tr.trXold;
447 dy = trY - tr.trYold;
448 tr.trXold = trX;
449 tr.trYold = trY;
450 /*printf("dx=%d, dy=%d", dx, dy);
451 fflush(stdout);*/
452
453 tr.xtransl += dx; /* this is used in ViewPort to determine where the
454 * structure has been translated */
455 tr.ytransl -= dy; /* in X11 Y-coor is upside down */
456
457 /* ViewPort */
458 xcViewPort();
459 /* Update a Display */
460 } else {
461 /*********************/
462 /* NEW NICER FASHION */
463 /*********************/
464 NEW_WIN_CONTEXT *wc;
465 wc = FindWinContextByTogl( togl );
466
467 /* if structure is not opened, do noting, just return silently */
468 if (!wc->VPf.stropened) return TCL_OK;
469
470 /* INSERT CODE FOR TRANSLATION HERE */
471 }
472
473 Togl_PostRedisplay(togl);
474
475 return TCL_OK;
476 }
477
478
479 /*
480 * this function takes care of BUTTON_RELEASE events
481 */
482 int
XC_ButtonReleaseCb(ClientData clientData,Tcl_Interp * interp,int argc,const char * argv[])483 XC_ButtonReleaseCb(ClientData clientData, Tcl_Interp *interp,
484 int argc, const char *argv[])
485 {
486 Togl *togl;
487
488 if (argc != 3) {
489 Tcl_SetResult(interp,
490 "Usage: xc_Brelease <toglname> <B1|B2|Shift-B1>", TCL_STATIC);
491 return TCL_ERROR;
492 }
493
494 if ( Togl_GetToglFromName(interp, argv[1], &togl) == TCL_ERROR ) {
495 char rss[1024];
496 snprintf(rss, sizeof(rss),
497 "couldn't find %s togl widget", argv[3]);
498 Tcl_SetResult(interp, rss, TCL_VOLATILE);
499 return TCL_ERROR;
500 }
501
502 /********************************************/
503 /* .MESA ---------------------------------- */
504 /********************************************/
505 if ( togl == mesa_togl ) {
506 if ( strcmp(argv[2],"B1") == 0 || strcmp(argv[2],"Shift-B1") == 0 ) {
507 tr.b1motion = 0;
508 tr.shiftB1motion = 0;
509 }
510 else if ( strcmp(argv[2],"B2") == 0 ) tr.b2motion = 0;
511 /*else if ( strcmp(argv[2],"Shift-B1") == 0 ) tr.shiftB1motion = 0;*/
512 else {
513 Tcl_SetResult(interp,
514 "Usage: <toglname> xc_Brelease <B1|B2|Shift-B1>", TCL_STATIC);
515 return TCL_ERROR;
516 }
517 } else {
518 /*********************/
519 /* NEW NICER FASHION */
520 /*********************/
521 NEW_WIN_CONTEXT *wc;
522 wc = FindWinContextByTogl( togl );
523
524 if ( strcmp(argv[2],"B1") == 0 || strcmp(argv[2],"Shift-B1") == 0 ) {
525 wc->tr.b1motion = 0;
526 wc->tr.shiftB1motion = 0;
527 }
528 else if ( strcmp(argv[2],"B2") == 0 )
529 wc->tr.b2motion = 0;
530 /* else if ( strcmp(argv[2],"Shift-B1") == 0 ) wc->tr.shiftB1motion = 0; */
531 else {
532 char rss[1024];
533 snprintf(rss, sizeof(rss), "wrong mode %s, must be B1, B2, or Shift-B1", argv[2]);
534 Tcl_SetResult(interp, rss, TCL_VOLATILE);
535 /* Tcl_SetResult(interp,
536 "Usage: <toglname> xc_Brelease <B1|B2|Shift-B1>", TCL_STATIC);*/
537 return TCL_ERROR;
538 }
539 }
540
541 return TCL_OK;
542 }
543