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