1 /***********************************************************************/
2 /* Open Visualization Data Explorer                                    */
3 /* (C) Copyright IBM Corp. 1989,1999                                   */
4 /* ALL RIGHTS RESERVED                                                 */
5 /* This code licensed under the                                        */
6 /*    "IBM PUBLIC LICENSE - Open Visualization Data Explorer"          */
7 /***********************************************************************/
8 
9 #include <dxconfig.h>
10 
11 
12 /*---------------------------------------------------------------------------*\
13  $Source: /src/master/dx/src/exec/hwrender/hwClientMessage.c,v $
14 
15   This file contains functions implementing the client message protocol for
16   communicating with other DX processes.  Most of the direct interactor
17   management is handled here, since they are created and restored in
18   response to messages from the UI process.
19 
20   The primary caller of these functions is _dxfProcessEvents().  No calls to
21   the graphics library are made directly at this level.
22 
23 \*---------------------------------------------------------------------------*/
24 
25 #include <stdio.h>
26 #include <math.h>
27 
28 #include "hwDeclarations.h"
29 #include "hwClientMessage.h"
30 #include "hwWindow.h"
31 #if defined(DX_NATIVE_WINDOWS)
32 #include <windows.h>
33 #else
34 #include <X11/Xlib.h>
35 #include <X11/Xatom.h>
36 #endif
37 
38 #include "hwDebug.h"
39 
40 #define COS05  0.996
41 #define SIN15  0.259
42 #define COS15  0.966
43 #define SIN25  0.423
44 #define COS25  0.906
45 #define SIN45  0.707
46 #define SIN35  0.574
47 
48 struct atomRep _dxdtdmAtoms[MAX_ATOMS] = {{ None, NULL}};
49 
50 extern Error _dxfDraw (void*, dxObject, Camera, int);
51 extern void _dxfCacheState(char *, dxObject, dxObject, int);
52 
53 static void
54 _sendLinkCamera(tdmChildGlobalP globals,
55   float *from, float *to, float *up,
56   float width, float aspect, float fov, float dist,
57   int projection, int pixwidth);
58 
59 #if defined(DX_NATIVE_WINDOWS)
60 static int
internAtoms()61 internAtoms ()
62 #else
63 static int
64 internAtoms (Display *dpy)
65 #endif
66 {
67   /*
68    *  Intern UI/renderer protocol elements into the X server to allow the
69    *  two processes to understand each other.
70    */
71 
72   ENTRY(("internAtoms(0x%x)",dpy));
73 
74 /*
75  * IMPORTANT!  Do not change the names of these defines, they are both the
76  * define and the *string* that is shared with the UI. Changing the name
77  * will make the atom unrecognizable by the UI.
78  */
79 
80   INTERNATOM(GLWindow0);		/* Camera0 */
81   INTERNATOM(GLWindow1);		/* Camera1 */
82   INTERNATOM(GLWindow2);		/* Camera2 */
83   INTERNATOM(GLWindow2Execute);		/* Camera2Execute */
84   INTERNATOM(StartRotateInteraction);
85   INTERNATOM(FromPoint);
86   INTERNATOM(UpVector);
87   INTERNATOM(StartZoomInteraction);
88   INTERNATOM(StartPanZoomInteraction);
89   INTERNATOM(Zoom1);
90   INTERNATOM(Zoom2);
91   INTERNATOM(StartCursorInteraction);
92   INTERNATOM(CursorChange);
93   INTERNATOM(SetCursorConstraint);
94   INTERNATOM(SetCursorSpeed);
95   INTERNATOM(StartRoamInteraction);
96   INTERNATOM(RoamPoint);
97   INTERNATOM(StartNavigateInteraction);
98   INTERNATOM(NavigateMotion);
99   INTERNATOM(NavigatePivot);
100   INTERNATOM(StopInteraction);
101   INTERNATOM(DisplayGlobe);
102   INTERNATOM(CameraUndoable);
103   INTERNATOM(CameraRedoable);
104   INTERNATOM(UndoCamera);
105   INTERNATOM(RedoCamera);
106   INTERNATOM(PushCamera);
107   INTERNATOM(ButtonMapping1);
108   INTERNATOM(ButtonMapping2);
109   INTERNATOM(ButtonMapping3);
110   INTERNATOM(NavigateLookAt);
111   INTERNATOM(ExecuteOnChange);
112   INTERNATOM(Set_View);
113   INTERNATOM(GLDestroyWindow);
114   INTERNATOM(GLShutdown);
115   INTERNATOM(POKE_CONNECTION);
116   INTERNATOM(StartPickInteraction);
117   INTERNATOM(PickPoint);
118   INTERNATOM(ImageReset);
119   INTERNATOM(StartUserInteraction);
120 
121 #if defined(DX_NATIVE_WINDOWS)
122     INTERNATOM(XA_Integer);
123 #else
124   /* Add X predefined Atoms to theDisplay *dpy) list of available atoms */
125   _dxdtdmAtoms[XA_Integer].atom = XA_INTEGER;
126   _dxdtdmAtoms[XA_Integer].spelling="XA_Integer";
127 #endif
128 
129   EXIT(("1"));
130   return 1 ;
131 }
132 
133 static char *
lookupAtomName(Atom a)134 lookupAtomName (Atom a)
135 {
136   /*
137    *  Return the spelling of a given atom.  Used for debug.
138    */
139 
140   int i, numAtoms ;
141 
142   /* ENTRY(("lookupAtomName(0x%x a)",)); */
143 
144   numAtoms = sizeof(_dxdtdmAtoms) / sizeof(struct atomRep) ;
145 
146   for (i = 0 ; i < numAtoms ; i++)
147     if (_dxdtdmAtoms[i].atom == a){
148       /* EXIT(("found")); */
149       return _dxdtdmAtoms[i].spelling ;
150     }
151 
152   /* EXIT(("not found")); */
153   return "unknown atom" ;
154 }
155 
156 
157 #if defined(DX_NATIVE_WINDOWS)
158 void
_dxfSendClientMessage(HWND win,int atomIndex,tdmMessageDataP data)159 _dxfSendClientMessage (HWND win, int atomIndex, tdmMessageDataP data)
160 {
161     SendMessage(win, WM_CLIENT_MESSAGE, atomIndex, (void *)data);
162 }
163 #else
164 
165 void
_dxfSendClientMessage(Display * dpy,Window win,int atomIndex,tdmMessageDataP data)166 _dxfSendClientMessage
167     (Display *dpy, Window win, int atomIndex, tdmMessageDataP data)
168 {
169   /*
170    *  Send a client message to the specified window.
171    */
172 
173   XEvent event;
174   Atom	atom = ATOM(atomIndex);
175 
176   ENTRY(("_dxfSendClientMessage(0x%x, 0x%x, %d, 0x%x)",
177 	 dpy, win, atomIndex, data));
178 
179   event.type = ClientMessage ;
180   event.xclient.window = win ;
181   event.xclient.format = 32 ;
182   event.xclient.message_type = atom ;
183   if (data)
184     {
185       event.xclient.data.l[0] = data->l[0] ;
186       event.xclient.data.l[1] = data->l[1] ;
187       event.xclient.data.l[2] = data->l[2] ;
188       event.xclient.data.l[3] = data->l[3] ;
189       event.xclient.data.l[4] = data->l[4] ;
190     }
191 
192   switch (XSendEvent (dpy, win, True, NoEventMask, &event))
193     {
194     case 0:
195       PRINT(("error: wire protocol conversion failed"));
196       break ;
197     case BadValue:
198       PRINT(("error: BadValue"));
199       break ;
200     case BadWindow:
201       PRINT(("error: BadWindow"));
202       break ;
203     default:
204       PRINT(("atom: \"%s\"", lookupAtomName(atom)));
205       break ;
206     }
207   XFlush(dpy) ;
208   EXIT((""));
209 }
210 #endif
211 
212 static void
_SendCamera(WinP win,float to[3],float up[3],float from[3],float width,int pixwidth,float aspect,float fov,int proj,int refresh)213 _SendCamera (WinP win, float to[3], float up[3], float from[3],
214 	     float width, int pixwidth, float aspect, float fov,
215 	     int proj, int refresh)
216 {
217   /*
218    *  Send a complete camera to the UI process.
219    */
220 
221   tdmMessageData data0, data1, data2 ;
222   DEFWINDATA(win);
223 
224   ENTRY(("_SendCamera (0x%x, 0x%x, 0x%x, 0x%x, %f, %d, %f, %f, %d, %d)",
225 	 win, to, up, from, width, pixwidth, aspect, fov, proj, refresh));
226 
227 #if !defined(DX_NATIVE_WINDOWS)
228   data0.l[0] = MSG_WINDOW ; /* kludge: ought to be win.xid */
229 #endif
230   data0.f[1] = to[0] ;
231   data0.f[2] = to[1] ;
232   data0.f[3] = to[2] ;
233   PRINT(("look-to point:")); VPRINT(to);
234 
235   data0.f[4] = up[0] ;
236   data1.f[0] = up[1] ;
237   data1.f[1] = up[2] ;
238   PRINT(("up vector:"));  VPRINT(up);
239 
240   data1.f[2] = from[0] ;
241   data1.f[3] = from[1] ;
242   data1.f[4] = from[2] ;
243   PRINT(("look-from point:")); VPRINT(from);
244 
245   data2.f[0] = proj ? 30 : width ;
246   PRINT(("width %f", data2.f[0]));
247 
248   data2.l[1] = pixwidth ;
249   PRINT(("pixwidth %d", pixwidth));
250 
251   data2.f[2] = aspect ;
252   PRINT(("aspect %f", aspect));
253 
254   data2.f[3] = proj ? RAD2DEG(2*atan(fov/2.0)) : 0 ;
255   PRINT(("view angle %f", data2.f[3]));
256 
257   data2.l[4] = proj ;
258   PRINT(("%s projection", proj ? "perspective" : "orthographic"));
259 
260 #if defined(DX_NATIVE_WINDOWS)
261   _dxfSendClientMessage(PARENT_WINDOW, Camera0, &data0) ;
262   _dxfSendClientMessage(PARENT_WINDOW, Camera1, &data1) ;
263 #else
264   _dxfSendClientMessage(DPY, PARENT_WINDOW, Camera0, &data0) ;
265   _dxfSendClientMessage(DPY, PARENT_WINDOW, Camera1, &data1) ;
266 #endif
267 
268 #ifdef DX_NATIVE_WINDOWS
269   if (refresh)
270       _dxfSendClientMessage(PARENT_WINDOW, Camera2Execute, &data2) ;
271   else
272       _dxfSendClientMessage(PARENT_WINDOW, Camera2, &data2) ;
273 #else
274   if (refresh)
275       _dxfSendClientMessage(DPY, PARENT_WINDOW, Camera2Execute, &data2) ;
276   else
277       _dxfSendClientMessage(DPY, PARENT_WINDOW, Camera2, &data2) ;
278 #endif
279 
280   EXIT((""));
281 }
282 
283 int
_dxfInitCMProtocol(WinP win)284 _dxfInitCMProtocol (WinP win)
285 {
286   /*
287    *  The renderer process cannot receive client message events on the GL
288    *  window (as of 8 October 1991).  We create an unmapped intermediate X
289    *  window from which to select the client messages.
290    */
291 
292   static int first_time = 1 ;
293   DEFWINDATA(win) ;
294 
295   ENTRY(("_dxfInitCMProtocol(0x%x), win"));
296 
297 #if defined(DX_NATIVE_WINDOWS)
298   if (first_time && !internAtoms())
299 #else
300   if (first_time && !internAtoms(DPY))
301 #endif
302       goto error ;
303   else
304       first_time = 0 ;
305 
306 #if !defined(DX_NATIVE_WINDOWS)
307   MSG_WINDOW = XCreateSimpleWindow
308       (DPY, DefaultRootWindow(DPY), 0, 0, 1, 1, 0, 0, 0) ;
309 
310   if (MSG_WINDOW)
311       XSelectInput (DPY, MSG_WINDOW, 0) ;
312   else
313       DXErrorGoto (ERROR_INTERNAL, "Could not create ClientMessage window") ;
314 #endif
315 
316   EXIT(("1"));
317   return 1 ;
318 
319  error:
320   EXIT(("ERROR"));
321   return 0 ;
322 }
323 
324 
325 void
_dxfConnectUI(WinP win)326 _dxfConnectUI (WinP win)
327 {
328   /*
329    *  By invoking this routine, the UI is given the following information:
330    *
331    *  1) the window identifier to which to direct its client messages.
332    *  2) the complete state of the current camera.
333    *  3) that the renderer is ready for direct interaction.
334    */
335 
336   Vector up ;
337   dxMatrix rot ;
338   Point to, from ;
339   int pixwidth, pixheight ;
340   float width, aspect, u[3], t[3], f[3] ;
341   DEFWINDATA(win);
342 
343   ENTRY(("_dxfConnectUI (0x%x)",win));
344 
345   if (! CAMERA)
346     {
347       EXIT(("CAMERA == NULL"));
348       return ;
349     }
350 
351   DXGetView (CAMERA, &from, &to, &up) ;
352   f[0] = from.x ; f[1] = from.y ; f[2] = from.z ;
353   t[0] =   to.x ; t[1] =   to.y ; t[2] =   to.z ;
354 
355   rot = DXGetCameraRotation (CAMERA) ;
356   u[0] = rot.A[0][1] ; u[1] = rot.A[1][1] ; u[2] = rot.A[2][1] ;
357 
358   DXGetCameraResolution (CAMERA, &pixwidth, &pixheight) ;
359 
360   if (DXGetOrthographic (CAMERA, &width, &aspect))
361       _SendCamera (win, t, u, f, width, pixwidth, aspect, 0, 0, 0) ;
362   else
363     {
364       float fov ;
365 
366       DXGetPerspective (CAMERA, &fov, &aspect) ;
367       _SendCamera (win, t, u, f, 0, pixwidth, aspect, fov, 1, 0) ;
368     }
369 
370   EXIT((""));
371 }
372 
373 static void
EchoFunction(tdmInteractor I,void * data,float rot[4][4],int draw)374 EchoFunction (tdmInteractor I, void *data, float rot[4][4], int draw)
375 {
376   DEFGLOBALDATA(data);
377   DEFPORT(PORT_HANDLE) ;
378   tdmChildGlobalP globals = _gdata; /* XXX should we define MACROS for accessing
379 				       globals ? */
380 
381   /*
382    *  This function is used as the echo for the view and navigation
383    *  interactors.
384    */
385 
386   ENTRY(("EchoFunction (0x%x, 0x%x, 0x%x, %d)",I, data, rot, draw));
387 
388   if (draw)
389     {
390       /* draw button-down pass */
391       _dxfDraw (globals,OBJECT,CAMERA,0);
392 
393       /* draw interactor echos in double buffer mode */
394       if (globals->CrntInteractor == globals->CursorGroup)
395 	{
396 	  tdmResumeEcho(globals->Cursor3D, tdmViewEchoMode) ;
397 	}
398       else if (globals->CrntInteractor == globals->RoamGroup)
399 	{
400 	  tdmResumeEcho(globals->Roamer, tdmViewEchoMode) ;
401 	}
402       else if (/*globals->CrntInteractor == globals->Navigator ||*/
403 	       globals->CrntInteractor == globals->RotateGroup)
404 	{
405 	  tdmResumeEcho(globals->GnomonTwirl, tdmViewEchoMode) ;
406 	}
407     }
408   else
409     {
410       /* Do nothing */
411     }
412 
413   EXIT((""));
414 }
415 
416 
417 void
_dxfInitDXInteractors(tdmChildGlobalP globals)418 _dxfInitDXInteractors (tdmChildGlobalP globals)
419 {
420   DEFGLOBALDATA(globals) ;
421   DEFPORT(PORT_HANDLE) ;
422   tdmInteractorWin W ;
423 
424   ENTRY(("_dxfInitDXInteractors (0x%x)", globals));
425 
426   /* Turn off trace macros from this level down */
427   /* Turn it on by exporting this variable */
428   DEBUG_CALL ( if (!getenv("DXHW_DEBUG_DETAIL")) DEBUG_OFF(); );
429 
430   /* initialize interactor common data */
431   W = INTERACTOR_DATA =
432       _dxfInitInteractors(PORT_HANDLE,MATRIX_STACK) ;
433 
434   /* create individual interactors */
435   globals->User = _dxfCreateUserInteractor(W, EchoFunction, (void *)globals);
436   globals->Zoomer = _dxfCreateZoomInteractor(W) ;
437   globals->PanZoom = _dxfCreatePanZoomInteractor(W) ;
438   globals->Cursor3D = _dxfCreateCursorInteractor(W, tdmProbeCursor) ;
439   globals->Roamer = _dxfCreateCursorInteractor(W, tdmRoamCursor) ;
440   globals->Pick = _dxfCreateCursorInteractor(W, tdmPickCursor) ;
441   globals->GnomonRotate = _dxfCreateRotationInteractor
442       (W, tdmGnomonEcho, tdmXYPlaneRoll);
443 
444   /* the Globe is always passive, and is driven by the Gnomon */
445   globals->Globe = _dxfCreateRotationInteractor (W, tdmGlobeEcho,
446                                                  tdmXYPlaneRoll) ;
447   _dxfAssociateInteractorEcho (globals->GnomonRotate, globals->Globe) ;
448 
449   /* the Z rotation interactor for Execute Once mode has no echo... */
450   globals->GnomonTwirl = _dxfCreateRotationInteractor
451       (W, tdmNullEcho, tdmZTwirl) ;
452   /* ...it drives the GnomonRotate echo instead */
453   _dxfAssociateInteractorEcho (globals->GnomonTwirl, globals->GnomonRotate) ;
454 
455   /* next interactors are used in Execute On Change mode */
456   globals->Navigator = _dxfCreateNavigator
457       (W, EchoFunction, (void *)globals) ;
458   globals->ViewTwirl = _dxfCreateViewRotationInteractor
459       (W, EchoFunction, tdmZTwirl, (void *)globals) ;
460   globals->ViewRotate = _dxfCreateViewRotationInteractor
461       (W, EchoFunction, tdmXYPlaneRoll, (void *)globals) ;
462 
463   /* bind interactors to specific mouse buttons, assuming Execute Once mode */
464   globals->RotateGroup = _dxfCreateInteractorGroup
465       (W, globals->GnomonRotate, globals->GnomonRotate, globals->GnomonTwirl) ;
466   globals->CursorGroup = _dxfCreateInteractorGroup
467       (W, globals->Cursor3D, globals->GnomonRotate, globals->GnomonTwirl) ;
468   globals->RoamGroup = _dxfCreateInteractorGroup
469       (W, globals->Roamer, globals->GnomonRotate, globals->GnomonTwirl) ;
470 
471   /* default is not to display globe */
472   globals->displayGlobe = 0 ;
473   if (DXUI)
474     {
475       /* if UI, initial state is Execute Once with no current interactor */
476       globals->executeOnChange = 0 ;
477       globals->CrntInteractor = (tdmInteractor) 0 ;
478     }
479   else
480     {
481       /* no UI, initial state is Execute On Change with default RotateGroup */
482       globals->executeOnChange = 1 ;
483       globals->CrntInteractor = globals->RotateGroup ;
484       _dxfUpdateInteractorGroup (globals->RotateGroup,
485 	   globals->ViewRotate, globals->ViewRotate, globals->ViewTwirl) ;
486     }
487 
488   DEBUG_ON();
489   EXIT((""));
490 }
491 
492 
493 static int
switchInteractors(tdmChildGlobalP globals)494 switchInteractors(tdmChildGlobalP globals)
495 {
496   /*
497    *  This is a helper routine for _dxfReceiveClientMessage, used when
498    *  switching interactor modes.
499    *
500    *  If the current interactor has a persistent echo, make it invisible.
501    *  Making an interactor echo invisible, however, doesn't erase it; it
502    *  merely means that it is not to be redrawn.
503    *
504    *  `refresh' is set to let the caller of _dxfReceiveClientMessage know
505    *  that it is to refresh the image window to get rid of the persistent
506    *  interactor echo.  Most echos are of this type.  Transient echos are
507    *  only currently used for the zoom boxes of the Zoomer and PanZoom
508    *  interactors.
509    *
510    *  The Globe interactor is used only for its echo, which is oriented to
511    *  reflect the current world coordinate axes whenever it is drawn.  The
512    *  Gnomon has the same default behavior, except that it can be directly
513    *  manipulated when in Execute Once mode.  The Globe is only displayed
514    *  when the displayGlobe state is true.
515    *
516    *  The Globe and Gnomon can also be `associated' with other interactors
517    *  to indicate their orientations; in this case they can only be
518    *  redrawn under the control of the associated interactor.  Thus it is
519    *  important to disassociate the Gnomon from the current interactor
520    *  when switching modes, so that it is available to the new interactor
521    *  mode.
522    *
523    *  Interactor associations are implemented by a list attached to each
524    *  interactor.  Making an interactor invisible prevents any interactors
525    *  after it in its association list from being drawn as well.
526    *
527    *  The echo of the ViewRotation interactor is implemented by the
528    *  renderer itself.  This interactor also uses the Gnomon as a
529    *  persistent echo in addition to the rendered view, but not in the
530    *  `associated' mode, since all the Gnomon has to perform is its
531    *  default behavior of rendering the world coordinate axes.
532    */
533 
534   int refresh = 0 ;
535   DEFGLOBALDATA(globals) ;
536 
537   ENTRY(("switchInteractors(0x%x)",globals));
538 
539   if (globals->CrntInteractor == globals->RotateGroup)
540     {
541       _dxfRotateInteractorInvisible(globals->GnomonTwirl) ;
542       _dxfDisassociateInteractorEcho (INTERACTOR_DATA,
543 				      globals->GnomonTwirl) ;
544       refresh = 1 ;
545     }
546   else if (globals->CrntInteractor == globals->CursorGroup)
547     {
548       _dxfCursorInteractorInvisible(globals->Cursor3D) ;
549       _dxfRotateInteractorInvisible(globals->GnomonTwirl) ;
550       _dxfDisassociateInteractorEcho (INTERACTOR_DATA,
551 				      globals->GnomonTwirl) ;
552       refresh = 1 ;
553     }
554   else if (globals->CrntInteractor == globals->RoamGroup)
555     {
556       _dxfCursorInteractorInvisible(globals->Roamer) ;
557       _dxfRotateInteractorInvisible(globals->GnomonTwirl) ;
558       _dxfDisassociateInteractorEcho (INTERACTOR_DATA,
559 				      globals->GnomonTwirl) ;
560       refresh = 1 ;
561     }
562   else if (globals->CrntInteractor == globals->Pick)
563     {
564       _dxfCursorInteractorInvisible(globals->Pick) ;
565       refresh = 1 ;
566     }
567 #if 0
568   else if (globals->CrntInteractor == globals->Navigator)
569     {
570       _dxfRotateInteractorInvisible(globals->GnomonTwirl) ;
571       refresh = 1 ;
572     }
573 #endif
574 
575   EXIT(("refresh = %d",refresh));
576   return refresh ;
577 }
578 
579 #define INTERACTION_NONE	1
580 #define INTERACTION_ROTATE	2
581 #define INTERACTION_CURSORS	3
582 #define INTERACTION_ROAM	4
583 #define INTERACTION_PICK	5
584 #define INTERACTION_NAVIGATE	6
585 #define INTERACTION_ZOOM	7
586 #define INTERACTION_PANZOOM	8
587 #define INTERACTION_USER	9
588 
589 void
_dxfSetInteractionMode(tdmChildGlobalP globals,int mode,dxObject args)590 _dxfSetInteractionMode(tdmChildGlobalP globals, int mode, dxObject args)
591 {
592     switch(mode)
593     {
594         case INTERACTION_NONE:
595 	    globals->CrntInteractor = (tdmInteractor) 0 ;
596 	    break;
597 
598 	case INTERACTION_ROTATE:
599 	    _dxfRotateInteractorVisible(globals->GnomonTwirl) ;
600 	    _dxfRotateInteractorVisible(globals->GnomonRotate) ;
601       	    tdmResumeEcho (globals->GnomonTwirl, tdmBothBufferDraw) ;
602       	    globals->CrntInteractor = globals->RotateGroup ;
603 	    break;
604 
605 
606 	case INTERACTION_CURSORS:
607             _dxfCursorInteractorVisible(globals->Cursor3D) ;
608             _dxfRotateInteractorVisible(globals->GnomonTwirl) ;
609             _dxfRotateInteractorVisible(globals->GnomonRotate) ;
610             _dxfAssociateInteractorEcho (globals->Cursor3D,
611 						globals->GnomonTwirl) ;
612             tdmResumeEcho (globals->Cursor3D, tdmBothBufferDraw) ;
613             globals->CrntInteractor = globals->CursorGroup ;
614 	    break;
615 
616 
617 	case INTERACTION_ROAM:
618             _dxfCursorInteractorVisible(globals->Roamer) ;
619             _dxfRotateInteractorVisible(globals->GnomonTwirl) ;
620             _dxfRotateInteractorVisible(globals->GnomonRotate) ;
621             _dxfAssociateInteractorEcho (globals->Roamer,
622 						globals->GnomonTwirl) ;
623             tdmResumeEcho (globals->Roamer, tdmBothBufferDraw) ;
624             globals->CrntInteractor = globals->RoamGroup ;
625             break;
626 
627 	case INTERACTION_PICK:
628 	    _dxfCursorInteractorVisible(globals->Pick) ;
629             globals->CrntInteractor = globals->Pick ;
630 	    break;
631 
632 	case INTERACTION_NAVIGATE:
633 	{
634 	    dxMatrix rot ;
635             tdmMessageData data;
636             float width, aspect, viewDirReturn[3], viewUpReturn[3] ;
637 	    DEFGLOBALDATA(globals);
638 
639             PRINT(("StartNavigateInteraction"));
640             /* align with current view before starting new navigation session */
641             rot = DXGetCameraRotation(CAMERA) ;
642             _dxfSetNavigateLookAt (globals->Navigator, tdmLOOK_ALIGN, 0.0,
643 			          rot.A, viewDirReturn, viewUpReturn) ;
644 
645             if (DXGetOrthographic (CAMERA, &width, &aspect))
646 	      {
647 	        /* navigation switches to perspective, so push camera first */
648 	        tdmMessageData data ;
649 	        data.l[0] = _dxfPushInteractorCamera(INTERACTOR_DATA) ;
650 #if defined(DX_NATIVE_WINDOWS)
651 	        _dxfSendClientMessage (PARENT_WINDOW, CameraUndoable, &data) ;
652 #else
653 	        _dxfSendClientMessage (DPY, PARENT_WINDOW, CameraUndoable, &data) ;
654 #endif
655 
656 	      }
657 
658             /* switch to Execute On Change mode */
659             data.l[0] = 1 ;
660 #if defined(DX_NATIVE_WINDOWS)
661             _dxfSendClientMessage (PARENT_WINDOW, ExecuteOnChange, &data) ;
662 #else
663             _dxfSendClientMessage (DPY, PARENT_WINDOW, ExecuteOnChange, &data) ;
664 #endif
665 
666 	    globals->CrntInteractor = globals->Navigator ;
667 	    break;
668 	}
669 
670 	case INTERACTION_ZOOM:
671 	    globals->CrntInteractor = globals->Zoomer ;
672 	    break;
673 
674 	case INTERACTION_PANZOOM:
675 	    globals->CrntInteractor = globals->PanZoom ;
676 	    break;
677 
678 	case INTERACTION_USER:
679 	    globals->CrntInteractor = globals->User;
680 	    _dxfSetUserInteractorMode(globals->User, args);
681 	    break;
682 
683 	default:
684 	    break;
685     }
686 }
687 
688 #if defined(DX_NATIVE_WINDOWS)
689 Error
_dxfReceiveClientMessage(tdmChildGlobalP globals,UINT msg,void * data,int * NeedRefresh)690 _dxfReceiveClientMessage (tdmChildGlobalP globals,
691 			  UINT msg, void *data, int *NeedRefresh)
692 #else
693 Error
694 _dxfReceiveClientMessage (tdmChildGlobalP globals,
695 			  XClientMessageEvent *message, int *NeedRefresh)
696 #endif
697 {
698   /*
699    *  Process messages received from the UI process.  The bulk of these
700    *  are requests to start and stop interaction modes, in which case the
701    *  principal output is to set the pointer to the current interactor.
702    *  This pointer is then used by _dxfProcessEvents to drive the
703    *  interaction in response to mouse movement.
704    *
705    *  The other requests are mainly for setting view information.  The UI
706    *  doesn't have access to some of the info upon which views depend, so
707    *  the response here is send the UI the info it needs.
708    */
709 
710   DEFGLOBALDATA(globals);
711   tdmMessageData mess_data;
712   tdmMessageDataP dataP = &mess_data;
713   int pixwidth, projection ;
714   float from[3], to[3], up[3], width, aspect, fov, dist, Near, Far ;
715 
716 
717   ENTRY(("_dxfReceiveClientMessage (0x%x, 0x%x, 0x%x)",
718 	 globals, message, NeedRefresh));
719   PRINT(("message_type = %d", message->message_type));
720 
721   /* get current view parameters */
722   _dxfGetInteractorViewInfo (INTERACTOR_DATA,
723 		from, to, up, &dist, &fov, &width,
724 		&aspect, &projection, &Near, &Far,
725 		&pixwidth) ;
726 
727   /* Xlib.h has message.data.l defined as long's.  Fill in our expected
728      format to avoid problems on arch's with 64 bit long's */
729 
730 #if defined(DX_NATIVE_WINDOWS)
731   dataP->l[0] = ((long *)data)[0];
732   dataP->l[1] = ((long *)data)[1];
733   dataP->l[2] = ((long *)data)[2];
734   dataP->l[3] = ((long *)data)[3];
735   dataP->l[4] = ((long *)data)[4];
736 #else
737   dataP->l[0] = (int32)message->data.l[0];
738   dataP->l[1] = (int32)message->data.l[1];
739   dataP->l[2] = (int32)message->data.l[2];
740   dataP->l[3] = (int32)message->data.l[3];
741   dataP->l[4] = (int32)message->data.l[4];
742 #endif
743 
744 #if defined(DX_NATIVE_WINDOWS)
745 #define COMPARE_MSGTYPE(t)	((msg) == (t))
746 #else
747 #define COMPARE_MSGTYPE(t)	(message->message_type == ATOM((t)))
748 #endif
749 
750   if (COMPARE_MSGTYPE(DisplayGlobe))
751     {
752       PRINT(("DisplayGlobe %d", dataP->l[0]));
753       if (dataP->l[0] && !globals->displayGlobe)
754 	{
755 	  PRINT(("turning globe display on"));
756 	  _dxfRotateInteractorVisible(globals->Globe) ;
757 
758 	  if (globals->CrntInteractor == globals->RoamGroup ||
759 #if 0
760 	      globals->CrntInteractor == globals->Navigator ||
761 #endif
762 	      globals->CrntInteractor == globals->RotateGroup ||
763 	      globals->CrntInteractor == globals->CursorGroup)
764 	      tdmResumeEcho (globals->Globe, tdmFrontBufferDraw) ;
765 
766 	}
767       else if (!dataP->l[0] && globals->displayGlobe)
768 	{
769 	  PRINT(("turning globe display off"));
770 	  _dxfRotateInteractorInvisible(globals->Globe) ;
771 	  if (globals->CrntInteractor == globals->RoamGroup ||
772 #if 0
773 	      globals->CrntInteractor == globals->Navigator ||
774 #endif
775 	      globals->CrntInteractor == globals->RotateGroup ||
776 	      globals->CrntInteractor == globals->CursorGroup)
777 	      *NeedRefresh = 1 ;
778 	}
779       globals->displayGlobe = dataP->l[0] ;
780     }
781   else if (COMPARE_MSGTYPE(ExecuteOnChange))
782     {
783       PRINT(("ExecuteOnChange %d", dataP->l[0]));
784       if (dataP->l[0] && !globals->executeOnChange)
785 	{
786 	  PRINT(("switching to Execute On Change mode"));
787 	  _dxfUpdateInteractorGroup (globals->RoamGroup,
788 				    globals->Roamer,
789 				    globals->ViewRotate,
790 				    globals->ViewTwirl) ;
791 	  _dxfUpdateInteractorGroup (globals->CursorGroup,
792 				    globals->Cursor3D,
793 				    globals->ViewRotate,
794 				    globals->ViewTwirl) ;
795 	  _dxfUpdateInteractorGroup (globals->RotateGroup,
796 				    globals->ViewRotate,
797 				    globals->ViewRotate,
798 				    globals->ViewTwirl) ;
799 	}
800       else if (!dataP->l[0] && globals->executeOnChange)
801 	{
802 	  PRINT(("switching to Execute Once mode"));
803 	  _dxfUpdateInteractorGroup (globals->RoamGroup,
804 				    globals->Roamer,
805 				    globals->GnomonRotate,
806 				    globals->GnomonTwirl) ;
807 	  _dxfUpdateInteractorGroup (globals->CursorGroup,
808 				    globals->Cursor3D,
809 				    globals->GnomonRotate,
810 				    globals->GnomonTwirl) ;
811 	  _dxfUpdateInteractorGroup (globals->RotateGroup,
812 				    globals->GnomonRotate,
813 				    globals->GnomonRotate,
814 				    globals->GnomonTwirl) ;
815 	}
816       globals->executeOnChange = dataP->l[0] ;
817     }
818   else if (COMPARE_MSGTYPE(StopInteraction))
819     {
820       PRINT(("StopInteraction"));
821       *NeedRefresh |= switchInteractors(globals) ;
822        _dxfSetInteractionMode(globals, INTERACTION_NONE, NULL);
823     }
824   else if (COMPARE_MSGTYPE(StartRotateInteraction))
825     {
826       PRINT(("StartRotateInteraction"));
827       *NeedRefresh |= switchInteractors(globals) ;
828        _dxfSetInteractionMode(globals, INTERACTION_ROTATE, NULL);
829 
830     }
831   else if (COMPARE_MSGTYPE(StartCursorInteraction))
832     {
833       PRINT(("StartCursorInteraction"));
834       *NeedRefresh |= switchInteractors(globals) ;
835        _dxfSetInteractionMode(globals, INTERACTION_CURSORS, NULL);
836     }
837   else if (COMPARE_MSGTYPE(StartRoamInteraction))
838     {
839       PRINT(("StartRoamInteraction"));
840       *NeedRefresh |= switchInteractors(globals) ;
841        _dxfSetInteractionMode(globals, INTERACTION_ROAM, NULL);
842     }
843   else if (COMPARE_MSGTYPE(StartPickInteraction))
844     {
845       PRINT(("StartPickInteraction"));
846       *NeedRefresh |= switchInteractors(globals) ;
847        _dxfSetInteractionMode(globals, INTERACTION_PICK, NULL);
848     }
849   else if (COMPARE_MSGTYPE(SetCursorConstraint))
850     {
851       /* set global cursor constraints (applies to Roamer and Cursor3D) */
852       PRINT(("SetCursorConstraint"));
853       _dxfSetCursorConstraint (INTERACTOR_DATA, dataP->l[0]) ;
854     }
855   else if (COMPARE_MSGTYPE(SetCursorSpeed))
856     {
857       /* set global cursor speed (applies to Roamer and Cursor3D) */
858       PRINT(("SetCursorSpeed"));
859       _dxfSetCursorSpeed (INTERACTOR_DATA, dataP->l[0]) ;
860     }
861   else if (COMPARE_MSGTYPE(CursorChange))
862     {
863       /*
864        *  This is the UI's handle for moving, deleting, and adding
865        *  cursors.  Applies only to the cursor interactor.  Cursors are
866        *  usually manipulated by the user, of course, in which case the
867        *  info is sent back to the UI in _dxfSendInteractorData.
868        */
869       PRINT(("CursorChange"));
870       _dxfCursorInteractorChange (globals->Cursor3D, dataP->l[0], dataP->l[1],
871 				  dataP->f[2], dataP->f[3], dataP->f[4]) ;
872     }
873   else if (COMPARE_MSGTYPE(StartNavigateInteraction))
874     {
875       /*
876        *  Start navigation mode.  Align the current navigation vectors with
877        *  the current view before entering this mode.
878        */
879 
880       *NeedRefresh |= switchInteractors(globals) ;
881       _dxfSetInteractionMode(globals, INTERACTION_NAVIGATE, NULL);
882     }
883   else if (COMPARE_MSGTYPE(NavigateLookAt))
884     {
885       /*
886        *  Generate a new view relative to current navigation vectors.  The
887        *  new direction is specified in the first long of the message packet
888        *  followed by an angle.  Send a complete new camera back to the UI.
889        */
890 
891       dxMatrix rot ;
892       Vector up ;
893       Point from, to ;
894       double dist ;
895       int pixwidth, pixheight ;
896       float viewDirReturn[3], viewUpReturn[3], f[3], t[3];
897       tdmMessageData data;
898 
899       PRINT(("NavigateLookAt"));
900 
901       /* push camera before changing */
902       data.l[0] = _dxfPushInteractorCamera(INTERACTOR_DATA) ;
903 #if defined(DX_NATIVE_WINDOWS)
904       _dxfSendClientMessage (PARENT_WINDOW, CameraUndoable, &data) ;
905 #else
906       _dxfSendClientMessage (DPY, PARENT_WINDOW, CameraUndoable, &data) ;
907 #endif
908 
909       /*
910        *  Provide current view to _dxfSetNavigateLookAt, which then returns
911        *  new view direction and view up vectors.
912        */
913 
914       rot = DXGetCameraRotation(CAMERA) ;
915       _dxfSetNavigateLookAt (globals->Navigator, dataP->l[0], dataP->f[1],
916 			    rot.A, viewDirReturn, viewUpReturn) ;
917 
918       /* compute new `to' point based on from-to distance and view direction */
919       DXGetView (CAMERA, &from, &to, &up) ;
920       dist = DXLength(DXSub(from, to)) ;
921       f[0] = from.x ; t[0] = f[0] + dist*viewDirReturn[0] ;
922       f[1] = from.y ; t[1] = f[1] + dist*viewDirReturn[1] ;
923       f[2] = from.z ; t[2] = f[2] + dist*viewDirReturn[2] ;
924 
925       /* get other info that UI needs to complete camera */
926       DXGetCameraResolution (CAMERA, &pixwidth, &pixheight) ;
927 
928       if (DXGetOrthographic (CAMERA, &width, &aspect))
929 	  /* force perspective projection */
930 	  fov = 2.0 * atan((width/dist) / 2.0) ;
931       else
932 	  DXGetPerspective (CAMERA, &fov, &aspect) ;
933 
934       /* send camera info to UI */
935       _SendCamera (LWIN, t, viewUpReturn, f, 0, pixwidth,
936 		   aspect, fov, 1, 1) ;
937 
938       if (LINK)
939 	    _sendLinkCamera(globals, f, t, viewUpReturn, width, aspect, fov, dist,
940 					      projection, pixwidth);
941     }
942   else if (COMPARE_MSGTYPE(NavigateMotion))
943     {
944       PRINT(("NavigateMotion"));
945       _dxfSetNavigateTranslateSpeed (globals->Navigator, dataP->f[0]) ;
946     }
947   else if (COMPARE_MSGTYPE(NavigatePivot))
948     {
949       PRINT(("NavigatePivot"));
950       _dxfSetNavigateRotateSpeed (globals->Navigator, dataP->f[0]) ;
951     }
952   else if (COMPARE_MSGTYPE(StartZoomInteraction))
953     {
954       PRINT(("StartZoomInteraction"));
955       *NeedRefresh |= switchInteractors(globals) ;
956       _dxfSetInteractionMode(globals, INTERACTION_ZOOM, NULL);
957     }
958   else if (COMPARE_MSGTYPE(StartPanZoomInteraction))
959     {
960       PRINT(("StartPanZoomInteraction"));
961       *NeedRefresh |= switchInteractors(globals) ;
962       _dxfSetInteractionMode(globals, INTERACTION_PANZOOM, NULL);
963     }
964   else if (COMPARE_MSGTYPE(ImageReset))
965     {
966       /* reset interactors that require it */
967       SAVE_BUF_VALID = FALSE;
968       PRINT(("ImageReset"));
969       if (globals->CrntInteractor == globals->RoamGroup)
970       {
971 	  _dxfResetCursorInteractor(globals->Roamer) ;
972 	  printf("_dxfResetCursorInteractor(globals->Roamer);\n");
973       }
974       else if (globals->CrntInteractor == globals->Navigator)
975       {
976 	  _dxfResetNavigateInteractor(globals->Navigator) ;
977 	  printf("_dxfResetNavigateInteractor(globals->Navigator);\n");
978       }
979     }
980   else if (COMPARE_MSGTYPE(PushCamera))
981     {
982       /*
983        *  There are two camera stacks associated with each image window:
984        *  the Undo stack and the Redo stack.  Anytime the view is about to
985        *  be changed, the current view is pushed onto the Undo stack.  A
986        *  message must then be sent to the UI to indicate that it is now
987        *  possible to perform an Undo.
988        *
989        *  If the Undo stack is popped, the result gets pushed onto the
990        *  Redo stack, and vice versa.  Whenever a stack is popped, a
991        *  message is sent to the UI indicating whether the stack is now
992        *  empty.
993        *
994        *  The top of the Undo stack is always the current view.
995        */
996 
997       tdmMessageData data ;
998       PRINT(("PushCamera"));
999 
1000       data.l[0] = _dxfPushInteractorCamera(INTERACTOR_DATA) ;
1001 #if defined(DX_NATIVE_WINDOWS)
1002       _dxfSendClientMessage (PARENT_WINDOW, CameraUndoable, &data) ;
1003 #else
1004       _dxfSendClientMessage (DPY, PARENT_WINDOW, CameraUndoable, &data) ;
1005 #endif
1006     }
1007   else if (COMPARE_MSGTYPE(UndoCamera))
1008     {
1009       int r ;
1010       tdmMessageData data ;
1011       PRINT(("UndoCamera"));
1012 
1013       /* pop undo stack */
1014       if ((r = _dxfPopInteractorCamera(INTERACTOR_DATA)) != 0)
1015 	{
1016 	  int pixwidth, projection ;
1017 	  float f[3], t[3], u[3], width, aspect, fov, dist, Near, Far ;
1018 
1019 	  /* popped camera has been pushed onto redo stack */
1020 	  data.l[0] = 1 ;
1021 #if defined(DX_NATIVE_WINDOWS)
1022 	  _dxfSendClientMessage (PARENT_WINDOW, CameraRedoable, &data) ;
1023 #else
1024 	  _dxfSendClientMessage (DPY, PARENT_WINDOW, CameraRedoable, &data) ;
1025 #endif
1026 
1027 	  /* check to see if the undo stack is empty */
1028 	  data.l[0] = (r == -1 ? 0 : 1) ;
1029 
1030 	  /* get new camera info and pass it on to the UI */
1031 	  _dxfGetInteractorViewInfo (INTERACTOR_DATA,
1032  				    f, t, u, &dist, &fov, &width,
1033  				    &aspect, &projection, &Near, &Far,
1034  				    &pixwidth) ;
1035 
1036 	  _SendCamera (LWIN, t, u, f, width, pixwidth,
1037 		       aspect, fov, projection, 1) ;
1038 
1039 	  if (LINK)
1040 	    _sendLinkCamera(globals, f, t, u, width, aspect, fov, dist,
1041 					      projection, pixwidth);
1042 	}
1043       else
1044 	  data.l[0] = 0 ;
1045 
1046 #if defined(DX_NATIVE_WINDOWS)
1047       _dxfSendClientMessage (PARENT_WINDOW, CameraUndoable, &data) ;
1048 #else
1049       _dxfSendClientMessage (DPY, PARENT_WINDOW, CameraUndoable, &data) ;
1050 #endif
1051     }
1052   else if (COMPARE_MSGTYPE(RedoCamera))
1053     {
1054       int r ;
1055       tdmMessageData data ;
1056       PRINT(("RedoCamera"));
1057 
1058       /* pop the redo stack */
1059       if ((r = _dxfRedoInteractorCamera(INTERACTOR_DATA)) != 0)
1060 	{
1061 	  int pixwidth, projection ;
1062 	  float f[3], t[3], u[3], width, aspect, fov, dist, Near, Far ;
1063 
1064 	  /* re-done camera is pushed onto undo stack */
1065 	  data.l[0] = 1 ;
1066 #if defined(DX_NATIVE_WINDOWS)
1067 	  _dxfSendClientMessage (PARENT_WINDOW, CameraUndoable, &data) ;
1068 #else
1069 	  _dxfSendClientMessage (DPY, PARENT_WINDOW, CameraUndoable, &data) ;
1070 #endif
1071 
1072 	  /* check to see if the redo stack is empty */
1073 	  data.l[0] = (r == -1 ? 0 : 1) ;
1074 
1075 	  /* get new camera info and pass it on to the UI */
1076 	  _dxfGetInteractorViewInfo (INTERACTOR_DATA,
1077  				    f, t, u, &dist, &fov, &width,
1078  				    &aspect, &projection, &Near, &Far,
1079  				    &pixwidth) ;
1080 
1081 	  _SendCamera (LWIN, t, u, f, width, pixwidth,
1082 		       aspect, fov, projection, 1) ;
1083 
1084 	  if (LINK)
1085 	    _sendLinkCamera(globals, f, t, u, width, aspect, fov, dist,
1086 					      projection, pixwidth);
1087 
1088 	}
1089       else
1090 	  data.l[0] = 0 ;
1091 
1092 #if defined(DX_NATIVE_WINDOWS)
1093       _dxfSendClientMessage (PARENT_WINDOW, CameraRedoable, &data) ;
1094 #else
1095       _dxfSendClientMessage (DPY, PARENT_WINDOW, CameraRedoable, &data) ;
1096 #endif
1097     }
1098   else if (COMPARE_MSGTYPE(Set_View))
1099     {
1100       /*
1101        *  The UI process is asking us for the `view-from' point and `up'
1102        *  vector corresponding to the specified view type.  The only
1103        *  reason they're computed here is that they used to be based upon
1104        *  the bounding box of the object, and the UI didn't have access to
1105        *  the box.
1106        */
1107 
1108       Vector up, dir ;
1109       float f[3], u[3], t[3];
1110       Point from, to ;
1111       tdmMessageData data ;
1112 
1113       PRINT(("Set_View"));
1114       if (! DXGetView (CAMERA, &from, &to, &up)) {
1115 	EXIT(("ERROR: cant get current view"));
1116 	DXErrorReturn (ERROR_DATA_INVALID, "Can't get current view") ;
1117       }
1118 
1119       up = DXVec(0.0, 1.0, 0.0) ;
1120       switch (dataP->l[0])
1121 	{
1122 	case FRONT:
1123 	  PRINT(("front"));
1124 	  dir = DXVec(0.0, 0.0, 1.0) ;
1125 	  break;
1126 	case OFF_FRONT:
1127 	  PRINT(("off_front"));
1128 	  dir = DXVec(SIN15, SIN15, COS15) ;
1129 	  break;
1130 	case BACK:
1131 	  PRINT(("back"));
1132 	  dir = DXVec(0.0, 0.0, -1.0) ;
1133 	  break;
1134 	case OFF_BACK:
1135 	  PRINT(("off_back"));
1136 	  dir = DXVec(SIN15, SIN15, -COS15) ;
1137 	  break;
1138 	case TOP:
1139 	  PRINT(("top"));
1140 	  dir = DXVec(0.0, 1.0, 0.0) ;
1141 	  up = DXVec(0.0, 0.0, -1.0) ;
1142 	  break;
1143 	case OFF_TOP:
1144 	  PRINT(("off_top"));
1145 	  dir = DXVec(-SIN15, COS15, -SIN15) ;
1146 	  up = DXVec(0.0, 0.0, -1.0) ;
1147 	  break;
1148 	case BOTTOM:
1149 	  PRINT(("bottom"));
1150 	  dir = DXVec(0.0, -1.0, 0.0) ;
1151 	  up = DXVec(0.0, 0.0, 1.0) ;
1152 	  break;
1153 	case OFF_BOTTOM:
1154 	  PRINT(("off_bottom"));
1155 	  dir = DXVec(SIN15, -COS15, SIN15) ;
1156 	  up = DXVec(0.0, 0.0, 1.0) ;
1157 	  break;
1158 	case RIGHT:
1159 	  PRINT(("right"));
1160 	  dir = DXVec(1.0, 0.0, 0.0) ;
1161 	  break;
1162 	case OFF_RIGHT:
1163 	  PRINT(("off_right"));
1164 	  dir = DXVec(COS05, SIN15, SIN15) ;
1165 	  break;
1166 	case LEFT:
1167 	  PRINT(("left"));
1168 	  dir = DXVec(-1.0, 0.0, 0.0) ;
1169 	  break;
1170 	case OFF_LEFT:
1171 	  PRINT(("off_left"));
1172 	  dir = DXVec(-COS05, SIN15, SIN15) ;
1173 	  break;
1174 	case DIAGONAL:
1175 	  PRINT(("diagonal"));
1176 	  dir = DXVec(SIN45, SIN45, SIN45) ;
1177 	  break;
1178 	case OFF_DIAGONAL:
1179 	  PRINT(("off_diagonal"));
1180 	  dir = DXVec(SIN35, SIN35, SIN45) ;
1181 	  break;
1182 	}
1183 
1184       /* compute new `from' point at same distance as original */
1185       from = DXAdd(to, DXMul(DXNormalize(dir), DXLength(DXSub(from, to)))) ;
1186 
1187       data.f[0] = f[0] = from.x ;
1188       data.f[1] = f[1] = from.y ;
1189       data.f[2] = f[2] = from.z ;
1190       PRINT(("new look-from point")); VPRINT(data.f) ;
1191 #if defined(DX_NATIVE_WINDOWS)
1192       _dxfSendClientMessage (PARENT_WINDOW, FromPoint, &data) ;
1193 #else
1194       _dxfSendClientMessage (DPY, PARENT_WINDOW, FromPoint, &data) ;
1195 #endif
1196 
1197       data.f[0] = u[0] = up.x ;
1198       data.f[1] = u[0] = up.y ;
1199       data.f[2] = u[0] = up.z ;
1200       PRINT(("new up-vector")); VPRINT(data.f) ;
1201 #if defined(DX_NATIVE_WINDOWS)
1202       _dxfSendClientMessage (PARENT_WINDOW, UpVector, &data) ;
1203 #else
1204       _dxfSendClientMessage (DPY, PARENT_WINDOW, UpVector, &data) ;
1205 #endif
1206 
1207 
1208 
1209       if (LINK)
1210       {
1211 	t[0] = to.x;
1212 	t[1] = to.y;
1213 	t[2] = to.z;
1214 	_sendLinkCamera(globals, f, t, u, width, aspect, fov, dist,
1215 					      projection, pixwidth);
1216       }
1217     }
1218   else
1219     {
1220       PRINT(("%s: ignored", lookupAtomName(message->message_type)));
1221     }
1222 
1223   EXIT(("OK"));
1224   return OK ;
1225 }
1226 
1227 
1228 #define CACHE_CAMERA "CACHED_CAMERA_"
1229 
1230 static void
_sendLinkCamera(tdmChildGlobalP globals,float * from,float * to,float * up,float width,float aspect,float fov,float dist,int projection,int pixwidth)1231 _sendLinkCamera(tdmChildGlobalP globals,
1232   float *from, float *to, float *up,
1233   float width, float aspect, float fov, float dist,
1234   int projection, int pixwidth)
1235 {
1236   DEFGLOBALDATA(globals);
1237   Point F, T;
1238   Vector U;
1239   Camera c;
1240   RGBColor bkgnd;
1241 
1242   DXUIMessage("LINK",
1243       "VALUE camera %s [%f %f %f] [%f %f %f] [%f %f %f] %f %d %f %f %d",
1244       WHERE,
1245       to[0], to[1], to[2],
1246       up[0], up[1], up[2],
1247       from[0], from[1], from[2],
1248       width, pixwidth, aspect, fov, projection);
1249 
1250   c = DXNewCamera();
1251 
1252   F.x = from[0]; F.y = from[1]; F.z = from[2];
1253   T.x = to[0];   T.y = to[1];   T.z = to[2];
1254   U.x = up[0];   U.y = up[1];   U.z = up[2];
1255 
1256   DXSetView(c, F, T, U);
1257   DXSetResolution(c, pixwidth, (double)aspect);
1258   if (projection)
1259       DXSetPerspective(c, fov, aspect);
1260   else
1261       DXSetOrthographic(c, width, aspect);
1262 
1263   DXGetBackgroundColor(CAMERA, &bkgnd);
1264   DXSetBackgroundColor(c, bkgnd);
1265 
1266   _dxfCacheState(ORIGINALWHERE, NULL, (dxObject)c, 0);
1267 }
1268 
1269 void
_dxfSendInteractorData(tdmChildGlobalP globals,tdmInteractor I,tdmInteractorReturn * returnP)1270 _dxfSendInteractorData (tdmChildGlobalP globals,
1271                        tdmInteractor I, tdmInteractorReturn *returnP)
1272 {
1273   /*
1274    *  This is invoked after the user has released a mouse button, ending the
1275    *  current interaction stroke.  If anything happened during the stroke,
1276    *  send the interactor's results back to the UI.
1277    */
1278 
1279   DEFGLOBALDATA(globals);
1280   tdmMessageData data0, data1, data2 ;
1281   tdmInteractorReturn local, *R ;
1282   int pixwidth, projection ;
1283   float from[3], to[3], up[3], width, aspect, fov, dist, Near, Far ;
1284 
1285   ENTRY(("_dxfSendInteractorData(0x%x, 0x%x, 0x%x)",
1286 	 globals,I,returnP));
1287 
1288   if (!I)
1289     {
1290       EXIT(("I == NULL"));
1291       return ;
1292     }
1293 
1294 #ifdef DX_NATIVE_WINDOWS
1295   if (!globals || !PARENT_WINDOW)
1296     {
1297       PRINT(("I = %0x%x", I));
1298       PRINT(("globals = 0x%x", globals));
1299       if (globals) {
1300 	PRINT(("UI window = 0x%x", PARENT_WINDOW));
1301       }
1302       EXIT(("ERROR"));
1303       return ;
1304     }
1305 #else
1306   if (!globals || !DPY || !PARENT_WINDOW)
1307     {
1308       PRINT(("I = %0x%x", I));
1309       PRINT(("globals = 0x%x", globals));
1310       if (globals) {
1311 	PRINT(("display = 0x%x", DPY));
1312 	PRINT(("UI window = 0x%x", PARENT_WINDOW));
1313       }
1314       EXIT(("ERROR"));
1315       return ;
1316     }
1317 #endif
1318 
1319   if (returnP)
1320       /* if provided, use it.  occurs as result of double click */
1321       R = returnP ;
1322   else
1323     {
1324       /* get it ourselves. occurs at end of normal interaction stroke */
1325       tdmEndStroke (I, &local) ;
1326       R = &local ;
1327     }
1328 
1329   if (!R || !R->change)
1330     {
1331       /* nothing happened */
1332       EXIT(("no change"));
1333       return ;
1334     }
1335 
1336   /* get current view parameters */
1337   _dxfGetInteractorViewInfo (INTERACTOR_DATA,
1338 		from, to, up, &dist, &fov, &width,
1339 		&aspect, &projection, &Near, &Far,
1340 		&pixwidth) ;
1341 
1342   if (I == globals->Zoomer || I == globals->PanZoom)
1343     {
1344       /*
1345       Vector up ;
1346       Point from, to ;
1347       */
1348       float fov, width, aspect ;
1349 
1350       data0.l[0] = _dxfPushInteractorCamera(INTERACTOR_DATA) ;
1351 #if defined(DX_NATIVE_WINDOWS)
1352       _dxfSendClientMessage (PARENT_WINDOW, CameraUndoable, &data0) ;
1353 #else
1354       _dxfSendClientMessage (DPY, PARENT_WINDOW, CameraUndoable, &data0) ;
1355 #endif
1356 
1357       /*
1358       DXGetView (CAMERA, &from, &to, &up) ;
1359       */
1360 
1361       if (DXGetPerspective (CAMERA, &fov, &aspect))
1362 	{
1363 	  data1.l[0] = projection = 1 ;   /* perspective flag */
1364 	  data1.f[1] = 1.0 ; /* nominal zoom factor */
1365 	  data1.f[2] = fov = RAD2DEG(2 * atan(fov * R->zoom_factor / 2)) ;
1366 	  if (data1.f[2] < 0.001)
1367 	    {
1368 	      PRINT(("view angle is too small"));
1369 	      DXWarning ("#13940") ;
1370 	      data1.f[2] = 0.001 ;
1371 	    }
1372 	  PRINT(("sending perspective camera fov %f", data1.f[2]));
1373 	}
1374       else
1375 	{
1376 	  DXGetOrthographic (CAMERA, &width, &aspect) ;
1377 	  data1.l[0] = projection = 0 ;   /* orthogonal flag */
1378 	  data1.f[1] = R->zoom_factor ;
1379 	  data1.f[2] = fov = 0 ;   /* nominal view angle */
1380 	  PRINT(("sending ortho camera zoom factor %f", data1.f[1]));
1381 	}
1382 
1383       data1.f[3] = to[0] = R->to[0] ;
1384       data1.f[4] = to[1] = R->to[1] ;
1385       data2.f[0] = to[2] = R->to[2] ;
1386       PRINT(("sending new look-to point")); VPRINT(R->to) ;
1387 
1388       data2.f[1] = from[0] = R->from[0] ;
1389       data2.f[2] = from[1] = R->from[1] ;
1390       data2.f[3] = from[2] = R->from[2] ;
1391       PRINT(("sending new look-from point")); VPRINT(R->from) ;
1392 
1393 #if defined(DX_NATIVE_WINDOWS)
1394       _dxfSendClientMessage (PARENT_WINDOW, Zoom1, &data1) ;
1395       _dxfSendClientMessage (PARENT_WINDOW, Zoom2, &data2) ;
1396 #else
1397       _dxfSendClientMessage (DPY, PARENT_WINDOW, Zoom1, &data1) ;
1398       _dxfSendClientMessage (DPY, PARENT_WINDOW, Zoom2, &data2) ;
1399 #endif
1400     }
1401   else if (I == globals->User)
1402     {
1403       int pixwidth, pixheight, proj ;
1404       float width, aspect, fov;
1405 
1406       data0.l[0] = _dxfPushInteractorCamera(INTERACTOR_DATA) ;
1407 #if defined(DX_NATIVE_WINDOWS)
1408       _dxfSendClientMessage (PARENT_WINDOW, CameraUndoable, &data0) ;
1409 #else
1410       _dxfSendClientMessage (DPY, PARENT_WINDOW, CameraUndoable, &data0) ;
1411 #endif
1412 
1413       DXGetCameraResolution (CAMERA, &pixwidth, &pixheight) ;
1414       if (! DXGetOrthographic (CAMERA, &width, &aspect))
1415         {
1416           DXGetPerspective (CAMERA, &fov, &aspect) ;
1417           proj = 1;
1418         }
1419         else
1420           proj = 0;
1421 
1422         _SendCamera (LWIN, R->to, R->up, R->from,
1423                    width, pixwidth, aspect, fov, proj, 0) ;
1424 
1425     }
1426   else if (I == globals->RotateGroup ||
1427 	   ((I == globals->CursorGroup || I == globals->RoamGroup) &&
1428 	    R->reason == tdmROTATION_UPDATE))
1429     {
1430       if (! PARENT_WINDOW)
1431         {
1432           /* no UI:  this is the only interactor available */
1433 	  /* replace from, to, up, and dist with returned values */
1434 	  _dxfSetInteractorViewInfo (INTERACTOR_DATA,
1435 				R->from, R->to, R->up, R->dist,
1436  				fov, width, aspect, projection,
1437 				Near, Far) ;
1438         }
1439       else
1440 	{
1441 	  data0.l[0] = _dxfPushInteractorCamera(INTERACTOR_DATA) ;
1442 #if defined(DX_NATIVE_WINDOWS)
1443 	  _dxfSendClientMessage (PARENT_WINDOW, CameraUndoable, &data0) ;
1444 #else
1445 	  _dxfSendClientMessage (DPY, PARENT_WINDOW, CameraUndoable, &data0) ;
1446 #endif
1447 
1448 	  data1.f[0] = from[0] = R->from[0] ;
1449 	  data1.f[1] = from[1] = R->from[1] ;
1450 	  data1.f[2] = from[2] = R->from[2] ;
1451 	  PRINT(("new look-from point")); VPRINT(R->from) ;
1452 
1453 #if defined(DX_NATIVE_WINDOWS)
1454 	  _dxfSendClientMessage (PARENT_WINDOW, FromPoint, &data1) ;
1455 #else
1456 	  _dxfSendClientMessage (DPY, PARENT_WINDOW, FromPoint, &data1) ;
1457 #endif
1458 
1459 	  data1.f[0] = up[0] = R->up[0] ;
1460 	  data1.f[1] = up[1] = R->up[1] ;
1461 	  data1.f[2] = up[2] = R->up[2] ;
1462 	  PRINT(("new up vector")); VPRINT(R->up) ;
1463 
1464 #if defined(DX_NATIVE_WINDOWS)
1465 	  _dxfSendClientMessage (PARENT_WINDOW, UpVector, &data1) ;
1466 #else
1467 	  _dxfSendClientMessage (DPY, PARENT_WINDOW, UpVector, &data1) ;
1468 #endif
1469 	}
1470     }
1471   else if (I == globals->Navigator)
1472     {
1473       int pixwidth, pixheight ;
1474       float width, aspect, fov, viewdir[3] ;
1475 
1476       data0.l[0] = _dxfPushInteractorCamera(INTERACTOR_DATA) ;
1477 #if defined(DX_NATIVE_WINDOWS)
1478       _dxfSendClientMessage (PARENT_WINDOW, CameraUndoable, &data0) ;
1479 #else
1480       _dxfSendClientMessage (DPY, PARENT_WINDOW, CameraUndoable, &data0) ;
1481 #endif
1482 
1483       DXGetCameraResolution (CAMERA, &pixwidth, &pixheight) ;
1484       if (DXGetOrthographic (CAMERA, &width, &aspect))
1485 	{
1486 	  /* Navigator has changed projection */
1487 	  VSUB (viewdir, R->from, R->to) ;
1488 	  fov = 2.0 * atan((width/LENGTH(viewdir)) / 2.0) ;
1489 	  projection = 0;
1490 	}
1491       else
1492         {
1493 	  DXGetPerspective (CAMERA, &fov, &aspect) ;
1494 	  projection = 1;
1495 	}
1496 
1497       _SendCamera (LWIN, R->to, R->up, R->from,
1498 		   0, pixwidth, aspect, fov, 1, 1) ;
1499 
1500     }
1501   else if (I == globals->CursorGroup && R->reason != tdmROTATION_UPDATE)
1502     {
1503       data1.l[0] = R->id ;
1504       data1.l[1] = R->reason ;
1505       data1.f[2] = R->x ;
1506       data1.f[3] = R->y ;
1507       data1.f[4] = R->z ;
1508 
1509       PRINT(("sending cursor %d change,", R->id));
1510       PRINT((" reason %d", R->reason));
1511       PRINT(("coordinates")); VPRINT((&data1.f[2])) ;
1512 #if defined(DX_NATIVE_WINDOWS)
1513       _dxfSendClientMessage (PARENT_WINDOW, CursorChange, &data1) ;
1514 #else
1515       _dxfSendClientMessage (DPY, PARENT_WINDOW, CursorChange, &data1) ;
1516 #endif
1517     }
1518   else if (I == globals->RoamGroup && R->reason != tdmROTATION_UPDATE)
1519     {
1520       data1.f[0] = R->x ;
1521       data1.f[1] = R->y ;
1522       data1.f[2] = R->z ;
1523 
1524       PRINT(("sending new roam point")); VPRINT(data1.f) ;
1525 #if defined(DX_NATIVE_WINDOWS)
1526       _dxfSendClientMessage (PARENT_WINDOW, RoamPoint, &data1) ;
1527 #else
1528       _dxfSendClientMessage (DPY, PARENT_WINDOW, RoamPoint, &data1) ;
1529 #endif
1530 
1531     }
1532   else if (I == globals->Pick)
1533     {
1534       data1.f[0] = R->x ;
1535       data1.f[1] = R->y ;
1536       data1.f[2] = R->z ;
1537 
1538       PRINT(("sending new pick point")); VPRINT(data1.f) ;
1539 #ifdef DX_NATIVE_WINDOWS
1540       _dxfSendClientMessage (PARENT_WINDOW, RoamPoint, &data1) ;
1541 #else
1542       _dxfSendClientMessage (DPY, PARENT_WINDOW, PickPoint, &data1) ;
1543 #endif
1544     }
1545 
1546   if (LINK)
1547     _sendLinkCamera(globals, from, to, up, width, aspect, fov, dist,
1548 					      projection, pixwidth);
1549 
1550 
1551   EXIT((""));
1552 }
1553