1 /*
2 * Copyright (C) 1997-2005, R3vis Corporation.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
17 * USA, or visit http://www.gnu.org/copyleft/lgpl.html.
18 *
19 * Original Contributor:
20 * Wes Bethel, R3vis Corporation, Marin County, California
21 * Additional Contributor(s):
22 *
23 * The OpenRM project is located at http://openrm.sourceforge.net/.
24 */
25 /*
26 * $Id: rmbfuncs.c,v 1.14 2005/09/12 04:05:34 wes Exp $
27 * Version: $Name: OpenRM-1-6-0-2-RC2 $
28 * $Revision: 1.14 $
29 * $Log: rmbfuncs.c,v $
30 * Revision 1.14 2005/09/12 04:05:34 wes
31 * Minor documentation updates.
32 *
33 * Revision 1.13 2005/06/08 18:33:02 wes
34 * Code cleanups to eliminate compiler warnings.
35 *
36 * Revision 1.12 2005/04/27 03:36:00 wes
37 * Attempting to reduce idle timeout in Win32
38 *
39 * Revision 1.11 2005/02/19 16:08:45 wes
40 * Distro sync and consolidation.
41 *
42 * Revision 1.10 2005/01/23 17:11:49 wes
43 * Copyright update to 2005.
44 *
45 * Revision 1.9 2004/03/30 14:13:37 wes
46 * *** empty log message ***
47 *
48 * Revision 1.8 2004/03/18 15:51:13 wes
49 * Minor changes to switch statements to avoid compile warning on SGI
50 * about "statement not reached" when there is a return inside a case.
51 *
52 * Revision 1.7 2004/01/19 17:10:24 wes
53 * Minor docs changes.
54 *
55 * Revision 1.6 2004/01/17 04:08:17 wes
56 * Updated copyright line for 2004. Tuning of auto-spin code.
57 *
58 * Revision 1.5 2003/12/12 00:36:45 wes
59 * Changed timeout parameter on the Win32 routine SetTime from 10 to 1. THe
60 * intent is to reduce the idle timer from 10ms to 1ms. After the change,
61 * I can't tell any difference, but it didn't seem to break anything. We need
62 * to test on a CPU with a higher clock rate to see if there's any difference
63 * in performance. This change affects the frequency that the user's
64 * idle callback rmaux function will be invoked.
65 *
66 * Revision 1.4 2003/10/03 19:18:01 wes
67 * Add support for auto-spin in both Win32 and X11.
68 *
69 * Revision 1.3 2003/02/18 15:41:37 wes
70 * Added a bit of documentation to rmauxSetKeyFunc.
71 *
72 * Revision 1.2 2003/02/02 02:07:18 wes
73 * Updated copyright to 2003.
74 *
75 * Revision 1.1.1.1 2003/01/28 02:15:23 wes
76 * Manual rebuild of rm150 repository.
77 *
78 * Revision 1.14 2003/01/16 22:21:18 wes
79 * Updated all source files to reflect new organization of header files:
80 * all header files formerly located in include/rmaux, include/rmi, include/rmv
81 * are now located in include/rm.
82 *
83 * Revision 1.13 2002/06/17 01:15:18 wes
84 * Replaced use of rmSubtreeFrame with rmFrame for default rendering
85 * operations. Added conditionals to check for NULL callbacks
86 * on event handling calls (button push, motion and release events).
87 *
88 * Revision 1.12 2002/04/30 19:37:59 wes
89 * Added code to Win32 event handler to invoke a caller-supplied
90 * key func callback.
91 *
92 * Revision 1.11 2001/10/14 23:52:42 wes
93 * Added button4 and button5 due to crashes reported by some users with
94 * mice with scroll wheels, and other funny mice with lots of buttons. Note
95 * that buttons 4 and 5 are accessible only under X11; Win32 provides for
96 * only 3 buttons in their API.
97 *
98 * Added a bit of code to the Win32 event processing code to more cleanly
99 * delimit those events consumed by the RMaux event loop and those to be
100 * consumed by Windows.
101 *
102 * Revision 1.10 2001/07/15 17:20:57 wes
103 * Added an RMnode * parameter to the rmauxInitFunc.
104 *
105 * Revision 1.9 2001/06/03 20:53:47 wes
106 * Added new routines for establishing callback handlers for resize
107 * and key handler events.
108 *
109 * Revision 1.8 2001/03/31 17:09:31 wes
110 * v1.4.0-alpha2 checkin.
111 *
112 * Revision 1.7 2000/12/03 22:36:15 wes
113 * First steps towards thread safety.
114 *
115 * Revision 1.6 2000/10/03 11:38:26 wes
116 * In rmauxEventLoop() [X11], upon entry and before entering
117 * the main event loop, we first remove any KeyRelease events
118 * from the event queue. There was a problem that first appeared
119 * in XF864.0.1 in which spurious KeyRelease events would sometimes
120 * be present in the event queue for the OpenGL gfx window.
121 *
122 * Revision 1.5 2000/08/28 01:31:40 wes
123 * Minor tweaks to key latching stuff.
124 *
125 * Revision 1.3 2000/04/20 16:22:16 wes
126 * JDB modifications: additional documentation, code rearranging.
127 *
128 * Revision 1.2 2000/04/17 00:06:51 wes
129 * Numerous documentation updates and code reorganization courtesy of jdb.
130 *
131 * Revision 1.1.1.1 2000/02/28 21:29:40 wes
132 * OpenRM 1.2 Checkin
133 *
134 * Revision 1.1.1.1 2000/02/28 17:18:48 wes
135 * Initial entry - pre-RM120 release, source base for OpenRM 1.2.
136 *
137 */
138
139 /*
140 * current issues 8/1999
141 * 1. rmauxEventLoop under Win32 does not exit upon a non-modifier
142 * keypress.
143 */
144
145 /*
146 * MODIFICATIONS:
147 *
148 * 1. added simple user key callback
149 * 2. added user window resize callback
150 * 3. added view plane translation to UI
151 * 4. replaced isometric scaling with camera dolly in UI
152 * 5. replaced trackball with ArcBall implementation in UI
153 * 6. substituted colored X11 cursors for emphasizing operations in UI
154 * 7. cleaned up some variable and function names, slimmed rmaux state, added docs
155 * 8. made button function arrays `static extern' to make them private
156 *
157 * 08/16/2000 jdb
158 *
159 * added key and resize default callbacks and API calls for setting rmaux state
160 * with users functions for these callbacks
161 *
162 * 02/16/01 jdb
163 */
164
165 #include <rm/rm.h>
166 #include <rm/rmaux.h>
167 #include "../rm/rmprivat.h"
168
169 #ifdef RM_X
170 #include <X11/cursorfont.h>
171 #endif
172
173 #if 1
174 #define private_rmauxSpinThreshold(x1,y1,x2,y2,t) (((((x2)-(x1))*((x2)-(x1))+((y2)-(y1))*((y2)-(y1))) - (t)) > 0 ? 1 : -1)
175 #else
176 int
private_rmauxSpinThreshold(float x1,float y1,float x2,float y2,float t)177 private_rmauxSpinThreshold(float x1,
178 float y1,
179 float x2,
180 float y2,
181 float t)
182 {
183
184 float a = (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1);
185 #if 1
186 {
187 char buf[256];
188 sprintf(buf," p1/p2 = (%g,%g) (%g,%g) \n thresh = %g, v = %g \n", x1, y1, x2, y2, t, a);
189 rmNotice(buf);
190 }
191 #endif
192 if ((a - t) > 0)
193 return 1;
194 else
195 return -1;
196 }
197 #endif
198
199
200 /* rmaux state - NOT thread-safe! */
201 static int (*staticUserIdleFunc)(RMpipe *, int, int) = NULL;
202 static void (*staticUserInitFunc)(RMpipe *, RMnode *) = NULL;
203 static int (*staticUserKeyFunc)(RMpipe *, char, KeySym) = NULL;
204 static int (*staticUserResizeFunc)(RMpipe *,RMnode *, int, int) = NULL;
205 static void (*renderfunc)(RMpipe *, RMnode *) = rmFrame;
206 static float x, y; /* stored pointer location */
207 static RMnode *camera3DTransformTarget; /* UI points to target node for interaction */
208 static RMmatrix ui_pose; /* UI stores initial target node pose for computation */
209 static RMnode *geomTransformTarget;
210 static RMmatrix saveScaleMatrix;
211 static float xscale_delta, yscale_delta;
212 static RMnode *static_sceneGraphHandle=NULL;
213 static RMnode *static_resizeCameraNode=NULL;
214
215 static RMenum spinModeEnabled=RM_FALSE;
216 static void (*spinCallbackFunc)(void) = NULL;
217 static void private_rmauxDoSpinCallback(void);
218 static RMmatrix spinMatrix;
219 static float lastBX1, lastBY1, lastBX2, lastBY2;
220 static float staticSpinThreshold = RMAUX_DEFAULT_SPIN_THRESHOLD;
221
222 #ifdef RM_X
223 static Cursor rotate_cursor, translate_cursor, dolly_cursor, scale_cursor;
224 #endif
225
226 /* button function callbacks (static extern prevents raw modification) */
227 static int (*rmauxUserButtonDownFuncs[RM_NUM_BUTTON_MODIFIERS][RM_NUM_BUTTONS + 1]) RMAUX_BUTTON_FUNC_PARMS();
228 static int (*rmauxUserButtonUpFuncs[RM_NUM_BUTTON_MODIFIERS][RM_NUM_BUTTONS + 1]) RMAUX_BUTTON_FUNC_PARMS();
229 static int (*rmauxUserButtonMotionFuncs[RM_NUM_BUTTON_MODIFIERS][RM_NUM_BUTTONS + 1]) RMAUX_BUTTON_FUNC_PARMS();
230
231 /* PRIVATE declarations */
232 void rmauxInvokeRenderFunc (RMpipe *p, RMnode *n);
233 int rmauxB1DownFunc RMAUX_BUTTON_FUNC_PARMS();
234 int rmauxB1UpFunc RMAUX_BUTTON_FUNC_PARMS();
235 int rmauxB1MotionFunc RMAUX_BUTTON_FUNC_PARMS();
236 int rmauxB2DownFunc RMAUX_BUTTON_FUNC_PARMS();
237 int rmauxB2UpFunc RMAUX_BUTTON_FUNC_PARMS();
238 int rmauxB2MotionFunc RMAUX_BUTTON_FUNC_PARMS();
239 int rmauxB3DownFunc RMAUX_BUTTON_FUNC_PARMS();
240 int rmauxB3UpFunc RMAUX_BUTTON_FUNC_PARMS();
241 int rmauxB3MotionFunc RMAUX_BUTTON_FUNC_PARMS();
242 int rmauxShiftB2DownFunc RMAUX_BUTTON_FUNC_PARMS();
243 int rmauxShiftB2UpFunc RMAUX_BUTTON_FUNC_PARMS();
244 int rmauxShiftB2MotionFunc RMAUX_BUTTON_FUNC_PARMS();
245
246 int private_rmauxButtonNumToIndex (int xbutton_num);
247 int private_rmauxModifierToIndex (int state);
248
249 RMnode *private_rmauxGetCurrentSceneGraph(void);
250 void private_rmauxSetCurrentSceneGraph(RMnode *n);
251
252 RMnode *private_rmauxGetCameraResizeNode(void);
253 void private_rmauxSetCameraResizeNode(RMnode *n);
254
255 /* viewport [0..(width-1)] X [0..(height-1)] --> NDC [-1,1] X [-1,1] */
256 #define pixeltovp(p,d) ((float)((p) - ((d) >> 1)) / (float)((d) >> 1))
257
258 /*
259 * ----------------------------------------------------
260 * @Name rmauxEventLoop
261 @pstart
262 void rmauxEventLoop (RMpipe *currentPipe,
263 RMnode *subTreeToDraw,
264 void *vmsg)
265 @pend
266
267 @astart
268 RMpipe *currentPipe - (input) a handle to an RMpipe object. The
269 RMpipe must be fully configured (init'ed, and has a valid opened
270 window assigned, and been the victim of rmPipeMakeCurrent()) prior
271 to invoking the event handler.
272
273 RMnode *subTreeToDraw - (input) a handle to an RMnode. This node is
274 considered to be the root of a subtree that will be rendered onto
275 "currentPipe" whenever a frame is to be rendered.
276
277 void *vmsg - X11 users - specify NULL for this parameter. Win32
278 users: all WinMain procedures must return (msg.wParam) to Windows
279 so it can gracefully exit. Pass a handle to a MSG object in to
280 rmauxEventLoop (please refer to the demo programs for sample
281 code. (output, return)
282 @aend
283
284 @dstart
285
286 This is the main rmaux event handler loop for both Win32 and X11. In
287 the source code, there are actually two different routines that are
288 conditionally compiled, since Win32 and X11 are so different.
289 However, from the outside, they exhibit (mostly) similar behavior.
290
291 Events are processed until some action handler returns a zero
292 status. The RM demonstration programs install a key handler function
293 (rmauxSetKeyFunc(pipe, rmauxDefaultKeyFunc)) that will cause applications
294 to terminate when the "q" key is pressed.
295
296 The default rendering function will be invoked an Expose (X11) or WM_PAINT (Win32)
297 event is encountered. Additionally, rmauxUI() defines that frames will
298 be rendered when other types of input events are encountered. The
299 RMnode * parameter subTreeToDraw defines the root of the scene graph
300 that will be rendered during all frame renderings within the rmaux*
301 family of routines. Note the distinction between the scene graph root
302 (subTreeToDraw) and the RMnode handle used for interactive transformations,
303 which is set with rmauxUI(). The RMnode handles to each of these routines
304 may point to different RMnodes.
305
306 @dend
307 * ----------------------------------------------------
308 */
309 #ifdef RM_WIN /* W32 event loop */
310
311 static RMpipe *staticPipe=NULL; /* hack! tmp! wes */
312
313 void
rmauxEventLoop(RMpipe * win_current_pipe,RMnode * subTreeToDraw,void * vmsg)314 rmauxEventLoop (RMpipe *win_current_pipe,
315 RMnode *subTreeToDraw,
316 void *vmsg)
317 {
318 MSG *msg;
319
320 private_rmauxSetCurrentSceneGraph(subTreeToDraw);
321
322 msg = (MSG *)vmsg;
323 ShowWindow(win_current_pipe->hwnd, 1);
324
325 /* staticPipe = win_current_pipe; */
326
327 if (staticUserInitFunc != NULL)
328 {
329 (*staticUserInitFunc)(win_current_pipe, subTreeToDraw);
330 staticUserInitFunc = NULL;
331 }
332 UpdateWindow(win_current_pipe->hwnd);
333
334 /* message structure, handle of window receiving the message,
335 * lowest message id to examine, highest message id to examine
336 */
337 while (GetMessage(msg, NULL, 0, 0))
338 {
339 TranslateMessage(msg); /* translates messages */
340 DispatchMessage(msg); /* dispatches messages */
341 }
342 }
343
344
345 /*
346 * the following are used to hold pointer (x,y) coordinates that
347 * will survive between calls to the WndProc. we use int *'s so
348 * this code will be thread safe.
349 */
350 static int *winPointerXY = NULL;
351
rmauxWndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)352 LONG WINAPI rmauxWndProc(HWND hWnd,
353 UINT msg,
354 WPARAM wParam,
355 LPARAM lParam)
356 {
357 static int which_button_down = -1;
358 static int which_modifier_index = -1;
359 static HDC hDC;
360 static HGLRC hRC;
361 PAINTSTRUCT ps;
362 GLsizei glnWidth, glnHeight;
363 RMpipe *win_current_pipe=NULL;
364 int stat = 0;
365 int consumedEvent = 0;
366
367 /*
368 * Windows weirdnesses (2/2000):
369 *
370 * the routine that processes events (this routine) is not called
371 * directly by the app, but by the window system. we need the RMpipe
372 * handle to pass back to callbacks, so we cheat and use a static
373 * variable inside RM. there's probably a way to wedge this into
374 * the parmameters that are passed along from rmauxEventLoop
375 * (win32 version) down to this routine, and this will be used
376 * in the future.
377 *
378 * This routine is NOT thread safe because of win_current_pipe.
379 *
380 * TODO: HOW to end the WndProc/event loop w/o Destroying the Window?
381
382 * 4/20/02 - this routine was updated to unify keypress handling on both
383 * X11 and Win32 platforms. The same API is used in both places, but the
384 * KeySym type is artificially defined on Win32 in order to coerce API
385 * consistency across platforms. Presently, the KeySym "code" parameter
386 * is not used on Win32. Only printable ASCII chars will trigger a call to
387 * the user-defined key-handling function on Win32; refer to your Win32
388 * developer documentation to learn more about which keys actually trigger
389 * an WM_CHAR event, which in turn initiates a call to the user-supplied
390 * key-handling callback.
391 */
392
393 if (staticPipe != NULL)
394 win_current_pipe = staticPipe;
395
396 /* malloc memory to hold the static variable used to hold the pointer (x,y) position */
397 if (winPointerXY == NULL)
398 {
399 winPointerXY = (int *)malloc(sizeof(int) * 2);
400 winPointerXY[0] = winPointerXY[1] = 0;
401 }
402 switch (msg)
403 {
404 case WM_TIMER:
405 stat = 1;
406 if (staticUserIdleFunc != NULL)
407 stat = (*staticUserIdleFunc)(win_current_pipe, winPointerXY[0], winPointerXY[1]);
408 if (spinCallbackFunc != NULL)
409 {
410 (*spinCallbackFunc)();
411 rmauxInvokeRenderFunc(win_current_pipe,
412 private_rmauxGetCurrentSceneGraph());
413 stat = 1;
414 }
415 if (stat <= 0)
416 DestroyWindow(hWnd);
417
418 consumedEvent = 1;
419 break;
420
421 case WM_CREATE:
422 {
423 /*
424 * assumption: when the window is created, the event
425 * loop routine has not yet been called. therefore, we need
426 * to grab the current pipe structure and stuff the window
427 * handle into it's field. note that later in the app code,
428 * we will explicitly call rmwPipeSetWindow for the purposes
429 * of syntactical consistency between the X and Win models,
430 * but in fact rmwPipeSetWindow is not *required* because
431 * we do it here.
432 */
433
434 int width, height;
435 RMpipe *p;
436
437 width = (int) LOWORD (lParam);
438 height = (int) HIWORD (lParam);
439
440 /* grap the RMpipe * passed in through the rmwCreateWindow call. */
441 p = (RMpipe *)(((LPCREATESTRUCT)lParam)->lpCreateParams);
442
443 /* make it the current RMpipe for this event loop */
444
445 win_current_pipe = staticPipe = p;
446
447 /* Select a pixel format and then create a rendering context from it */
448 if (win_current_pipe != NULL)
449 {
450 #if 0
451 hDC = GetDC(hWnd);
452 p->hdc = hDC;
453
454 setupPixelFormat(hDC, 16, 0); /* 16 bit zbuffer? */
455 setupPalette(hDC);
456 p->hRC = wglCreateContext(hDC);
457 rmPipeMakeCurrent(win_current_pipe);
458 /* build internal display lists for quadrics objects */
459 private_rmInitQuadrics(win_current_pipe->cache);
460 #endif
461 }
462 consumedEvent = 1;
463 break;
464 }
465
466 case WM_SIZE:
467 {
468 /*
469 * Redefine the viewing volume and viewport when the window size changes
470 * Make the RC current since we're going to make an OpenGL call here...
471 * get the new size of the client window
472 * note that we size according to the height,
473 * not the smaller of the height or width.
474 */
475
476 glnWidth = (GLsizei) LOWORD (lParam);
477 glnHeight = (GLsizei) HIWORD (lParam);
478
479 /*
480 * the following conditional checks for those events generated
481 * by win32 when a window is minimized, and its resulting width
482 * and/or height are set to zero. We avoid invoking the resize
483 * function if this is the case.
484 */
485 if ((glnWidth == 0) || (glnHeight == 0))
486 break;
487
488 rmPipeSetWindowSize(win_current_pipe, (int)glnWidth, (int)glnHeight);
489 if (staticUserResizeFunc != NULL)
490 {
491 if (staticUserResizeFunc(win_current_pipe, private_rmauxGetCameraResizeNode(), glnWidth, glnHeight) != RM_CHILL)
492 rmError("rmauxEventLoop() error - abnormal return status from user resizing function.");
493 else
494 rmauxInvokeRenderFunc(win_current_pipe,
495 private_rmauxGetCurrentSceneGraph()); /* draw resized window */
496 }
497
498 consumedEvent = 1;
499 break;
500 }
501
502 case WM_PAINT:
503 rmauxInvokeRenderFunc(win_current_pipe,
504 private_rmauxGetCurrentSceneGraph());
505 ValidateRect(hWnd, NULL);
506 consumedEvent = 1;
507 break;
508
509 case WM_DESTROY: /* Clean up and terminate */
510 wglDeleteContext( win_current_pipe->hRC );
511 PostQuitMessage( 0 );
512 consumedEvent = 1;
513 break;
514
515 /******** rmWarning(" need to add code to check and set buttons other than left, middle and up \n"); */
516 break;
517 case WM_LBUTTONDOWN: /* button 1 */
518 case WM_RBUTTONDOWN: /* button 3 */
519 case WM_MBUTTONDOWN: /* button 2 */
520 {
521 int ix, iy, rstat, bindex, mod_index;
522
523 winPointerXY[0] = ix = (int)LOWORD(lParam); /* pointer location */
524 winPointerXY[1] = iy = (int)HIWORD(lParam);
525
526 /* set mouse button */
527 switch (msg)
528 {
529 case WM_LBUTTONDOWN:
530 bindex = Button1;
531 break;
532
533 case WM_MBUTTONDOWN:
534 bindex = Button2;
535 break;
536 case WM_RBUTTONDOWN:
537 bindex = Button3;
538 break;
539
540 default: /* bogus mouse button */
541 break;
542 }
543
544 which_button_down = bindex = private_rmauxButtonNumToIndex(bindex);
545
546 mod_index = 0; /* determine modifiers in effect when button goes down */
547 if (wParam & MK_CONTROL)
548 mod_index |= RM_CONTROL_MODIFIER;
549 if (wParam & MK_SHIFT)
550 mod_index |= RM_SHIFT_MODIFIER;
551 which_modifier_index = mod_index = private_rmauxModifierToIndex(mod_index);
552
553 if (rmauxUserButtonDownFuncs[mod_index][bindex] != NULL)
554 rstat = (*rmauxUserButtonDownFuncs[mod_index][bindex])(win_current_pipe, ix, iy);
555 else
556 rstat = 1;
557 consumedEvent = 1;
558 break;
559 }
560
561 case WM_MOUSEMOVE:
562 {
563 int ix, iy, rstat;
564
565 winPointerXY[0] = ix = (int)LOWORD(lParam);
566 winPointerXY[1] = iy = (int)HIWORD(lParam);
567
568 if (which_button_down != -1)
569 {
570 if (rmauxUserButtonMotionFuncs[which_modifier_index][which_button_down] != NULL)
571 rstat = (*rmauxUserButtonMotionFuncs[which_modifier_index][which_button_down])(win_current_pipe, ix, iy);
572 else
573 rstat = 1;
574
575 consumedEvent = 1;
576 #if 0
577 /* this code produces failure on some Win98 systems, and
578 is being temporarily removed until this issue is
579 resolved. 10/9/2001. wbethel */
580
581 /* test removing extraneous WM_MOUSEMOVE events */
582 {
583 LPMSG lpMsg;
584 UINT filterFirst, filterLast;
585 UINT removeFlags = PM_REMOVE;
586
587 filterFirst = filterLast = WM_MOUSEMOVE;
588
589 while (PeekMessage(lpMsg, hWnd, filterFirst, filterLast, removeFlags))
590 ; /* just remove 'em all */
591 }
592 #endif
593 }
594 break;
595 }
596
597 case WM_LBUTTONUP:
598 case WM_MBUTTONUP:
599 case WM_RBUTTONUP:
600 {
601 int ix, iy;
602 int rstat, bindex, mod_index;
603
604 winPointerXY[0] = ix = (int)LOWORD(lParam);
605 winPointerXY[1] = iy = (int)HIWORD(lParam);
606
607 if (msg == WM_LBUTTONUP)
608 bindex = Button1;
609 else if (msg == WM_MBUTTONUP)
610 bindex = Button2;
611 else if (msg == WM_RBUTTONUP)
612 bindex = Button3;
613 else
614 rmWarning(" need to add code to check and set buttons other than left, middle and up \n");
615
616 which_button_down = bindex = private_rmauxButtonNumToIndex(bindex);
617
618 mod_index = 0; /* determine modifiers in effect when button goes down */
619 if (wParam & MK_CONTROL)
620 mod_index |= RM_CONTROL_MODIFIER;
621 if (wParam & MK_SHIFT)
622 mod_index |= RM_SHIFT_MODIFIER;
623 which_modifier_index = mod_index = private_rmauxModifierToIndex(mod_index);
624 if (rmauxUserButtonUpFuncs[which_modifier_index][which_button_down] != NULL)
625 rstat = (*rmauxUserButtonUpFuncs[which_modifier_index][which_button_down])(win_current_pipe, ix, iy);
626 else
627 rstat = 1;
628 which_button_down = -1;
629 consumedEvent = 1;
630 break;
631 }
632 case WM_CHAR:
633 {
634 if (staticUserKeyFunc != NULL)
635 {
636 consumedEvent = 1;
637 /*
638 * 4/20/02 - note the zero 3rd parm is a dummy. this code
639 * will invoke the user-supplied keypress callback, if
640 * present.
641 */
642 if (staticUserKeyFunc(win_current_pipe, (char)(wParam), 0) != RM_CHILL)
643 {
644 DestroyWindow(hWnd);
645 }
646 }
647 break;
648 }
649 }
650
651 if (consumedEvent != 0)
652 return 0;
653 else
654 return DefWindowProc(hWnd, msg, wParam, lParam);
655 }
656
rmauxOffscreenWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)657 LONG WINAPI rmauxOffscreenWndProc(HWND hWnd,
658 UINT message,
659 WPARAM wParam,
660 LPARAM lParam)
661 {
662 switch (message) {
663 case WM_CREATE:
664 return 0;
665 case WM_DESTROY:
666 PostQuitMessage(0);
667 return 0;
668 case WM_SIZE:
669 case WM_PALETTECHANGED:
670 break;
671 case WM_QUERYNEWPALETTE:
672 break;
673 case WM_PAINT:
674 break;
675 case WM_CHAR:
676 break;
677 default:
678 break;
679 }
680
681 /* Deal with any unprocessed messages */
682 return DefWindowProc(hWnd, message, wParam, lParam);
683 }
684 #endif /* RM_WIN */
685
686 #ifdef RM_X /* X11 event loop (documentation above) */
687 void
rmauxEventLoop(RMpipe * pipe,RMnode * subTree,void * unused)688 rmauxEventLoop (RMpipe *pipe,
689 RMnode *subTree,
690 void *unused)
691 {
692 int button_index = -1, modifier_index = -1;
693 XEvent event;
694 long mask;
695 int stat = 1;
696 int event_stat;
697 int pointerX = 0, pointerY = 0;
698
699 private_rmauxSetCurrentSceneGraph(subTree);
700
701 /* clear out any lingering keyrelease & keypress events on the display window */
702 mask = KeyPress | KeyRelease;
703 XSelectInput(rmxPipeGetDisplay(pipe), rmPipeGetWindow(pipe), mask);
704
705 XSync(rmxPipeGetDisplay(pipe), 0);
706 while (XCheckWindowEvent(rmxPipeGetDisplay(pipe),
707 rmPipeGetWindow(pipe), mask, &event) == True)
708 fprintf(stderr," removing errant Keypress or KeyRelease event \n");
709
710 if (staticUserInitFunc != NULL)
711 {
712 (*staticUserInitFunc)(pipe, subTree);
713 staticUserInitFunc = NULL;
714 }
715
716 mask = RM_AUX_XWINDOW_EVENT_MASK;
717 XSelectInput(rmxPipeGetDisplay(pipe), rmPipeGetWindow(pipe), mask);
718
719 while (stat > 0)
720 {
721 if ((staticUserIdleFunc != NULL) || (spinCallbackFunc != NULL))
722 event_stat = XCheckWindowEvent(rmxPipeGetDisplay(pipe), rmPipeGetWindow(pipe), mask, &event);
723 else
724 event_stat = XWindowEvent(rmxPipeGetDisplay(pipe), rmPipeGetWindow(pipe), mask, &event);
725
726 if ((event_stat == False) && ((staticUserIdleFunc != NULL) || (spinCallbackFunc != NULL)))
727 {
728 if (staticUserIdleFunc != NULL)
729 stat = (*staticUserIdleFunc)(pipe, pointerX, pointerY);
730
731 if (spinCallbackFunc != NULL)
732 {
733 (*spinCallbackFunc)();
734 rmauxInvokeRenderFunc(pipe, subTree);
735 }
736 }
737 else
738 {
739 switch(event.type)
740 {
741 case Expose:
742 if (event.xexpose.count == 0)
743 {
744 #if 0
745 /* debug */
746 printf(" doing a render on Expose, count=0 \n");
747 #endif
748 rmauxInvokeRenderFunc(pipe, subTree);
749 }
750 #if 0
751 /* debug */
752 else
753 printf(" Expose event, count != 0 \n");
754 #endif
755 break;
756
757 case ButtonPress:
758 {
759 button_index = private_rmauxButtonNumToIndex(event.xbutton.button);
760 modifier_index = private_rmauxModifierToIndex(event.xbutton.state);
761 pointerX = event.xbutton.x;
762 pointerY = event.xbutton.y;
763
764 /* added 6/10/02 to avoid user-induced crash */
765 if (rmauxUserButtonDownFuncs[modifier_index][button_index] != NULL)
766 stat = (*rmauxUserButtonDownFuncs[modifier_index][button_index])(pipe, pointerX, pointerY);
767 break;
768 }
769
770 case ButtonRelease:
771 {
772 button_index = private_rmauxButtonNumToIndex(event.xbutton.button);
773 modifier_index = private_rmauxModifierToIndex(event.xbutton.state);
774 pointerX = event.xbutton.x;
775 pointerY = event.xbutton.y;
776
777 /* added 6/10/02 to avoid user-induced crash */
778 if (rmauxUserButtonUpFuncs[modifier_index][button_index] != NULL)
779 stat = (*rmauxUserButtonUpFuncs[modifier_index][button_index])(pipe, pointerX, pointerY);
780
781 button_index = modifier_index = -1;
782 break;
783 }
784
785 case MotionNotify:
786 {
787 /*
788 * we'll assume that "button_index" and "modifier_index"
789 * were set by the buttonpress event, and that they
790 * are still valid. sometimes these values aren't properly
791 * set on motion events. the UI metaphor is that whatever
792 * these values are button index, modifier index) is what
793 * they are for all subsequent motion events until a release
794 * event.
795 */
796
797 /* pointerX = event.xmotion.x;
798 pointerY = event.xmotion.y; */
799 pointerX = event.xbutton.x;
800 pointerY = event.xbutton.y;
801
802 /* check for invalid state on button & modifier tags */
803 if ((modifier_index == -1) || (button_index == -1))
804 break; /* bail if they're invalid - this implies just pointer motion w/no button press */
805
806 /* call the routine which processes motion events. */
807 /* added 6/10/02 to avoid user-induced crash */
808 if (rmauxUserButtonMotionFuncs[modifier_index][button_index] != NULL)
809 stat = (*rmauxUserButtonMotionFuncs[modifier_index][button_index])(pipe, pointerX, pointerY);
810
811 /*
812 * while ButtonMotion events remain, peel them off. the
813 * problem we're addressing here is that ButtonMotion
814 * events can pile up when the renderer (or whatever action
815 * is mapped to ButtonMotion) is slower than the user. if
816 * we don't peel off "excess" events and throw them away,
817 * the renderer redraws for all the intermediate positions.
818 * the user probably wants the renderer to draw using
819 * the most recent pointer position, not all the intermediate
820 * positions.
821 */
822
823 while (XCheckMaskEvent(rmxPipeGetDisplay(pipe), ButtonMotionMask, &event) == True)
824 ;
825
826 break;
827
828 }
829
830 case ConfigureNotify:
831 {
832 /*
833 * when we get notification of a window size change, we
834 * simply set the size attribute of the window pipe. we
835 * make no assumption about modification of the aspect
836 * ratio of cameras within this window, if any, however,
837 * a non-NULL user-defined callback will be called to
838 * resize the window as required.
839 */
840
841 int new_width, new_height;
842
843 new_width = event.xconfigure.width;
844 new_height = event.xconfigure.height;
845 rmPipeSetWindowSize(pipe, new_width, new_height);
846
847 /* try to resize the window */
848 if (staticUserResizeFunc != NULL)
849 {
850 if (staticUserResizeFunc(pipe, private_rmauxGetCameraResizeNode(), new_width, new_height) != RM_CHILL)
851 rmError("rmauxEventLoop() error - abnormal return status from user resizing function.");
852 else
853 rmauxInvokeRenderFunc(pipe, subTree); /* draw resized window */
854 }
855 #if 0
856 /* debug */
857 printf(" rendering because of configurenotify \n");
858 #endif
859 rmauxInvokeRenderFunc(pipe, subTree);
860 break;
861 }
862
863 case KeyPress:
864 case KeyRelease:
865 {
866 /*
867 * grab both key presses and releases in order to latch
868 * keys for individual application actions
869 *
870 * keys are NOT latched when no key handler callback
871 * exists. when a keyhandler does not exist, the
872 * event loop exits when any non-modifier key
873 * is pressed.
874 *
875 * 8/27/2000 - this code needs more thorough testing.
876 *
877 * 02/11/01 - added rmaux state key function jdb
878 */
879
880 static char key, latch = 0;
881 static KeySym code;
882 char buf_return[32];
883 int len;
884 KeySym keysym_ret;
885 XComposeStatus status;
886
887 len = XLookupString(&(event.xkey), buf_return, 32, &keysym_ret, &status);
888
889 /* check to see if the key is one of the modifiers */
890 if (((event.type == KeyPress) || (event.type == KeyRelease)) && ((keysym_ret == XK_Shift_L) || (keysym_ret == XK_Shift_R) ||
891 (keysym_ret == XK_Control_L) || (keysym_ret == XK_Control_R)))
892 stat = 1;
893 else /* not a modifier - pass latched key press back to non-NULL key handler */
894 {
895 /* release latched key */
896 if ((latch) && (event.type == KeyRelease) && (staticUserKeyFunc != NULL))
897 {
898 if ((*buf_return == key) || (keysym_ret == code))
899 {
900 if ((staticUserKeyFunc(pipe, *buf_return, keysym_ret)) != RM_CHILL)
901 {
902 stat = 0; /* RM_WHACKED exits event loop */
903 #if 0
904 /* debug code */
905 fprintf(stderr," exiting due to keypress & latch \n");
906 #endif
907 }
908 else
909 {
910 latch = 0;
911 stat = 1;
912 }
913 } /* else oops! */
914 }
915 else /* latch new key press */
916 {
917 if ((event.type == KeyPress) && (staticUserKeyFunc != NULL))
918 {
919 key = *buf_return;
920 code = keysym_ret;
921 latch = 1;
922 stat = 1;
923 }
924 #if 0
925 else
926 {
927 /* this code added because XF86 is stupidly
928 fabricating a <cr> !!! */
929 if ((int)buf_return[0] != 13)
930 {
931 stat = 0;
932 #if 0
933 /* debug */
934 fprintf(stderr," exiting due to keypress <%s>, len=%d, a=%d \n", buf_return, len, (int)buf_return[0]);
935 #endif
936 }
937
938 }
939 #endif
940 }
941 }
942 break;
943 }
944
945 default: /* event we don't care about or garbage! */
946 break;
947
948 } /* end event type switch */
949 } /* end if have an event */
950 } /* end while (stat) */
951
952 /* foil compiler warning */
953 unused = NULL;
954 }
955 #endif /* RM_X */
956
957 /*
958 * ----------------------------------------------------
959 * @Name rmauxSetGeomTransform
960 @pstart
961 void rmauxSetGeomTransform (RMnode *target,
962 RMpipe *usePipe)
963 @pend
964
965 @astart
966 RMnode *target - a handle to an RMnode. (input) All model
967 transformations will be applied to this node, and will affect all
968 children nodes.
969
970 RMpipe *usePipe - a handle to an RMpipe. (input) This is is the
971 currently active GL context and is used to get cursors for X11.
972 @aend
973
974 @dstart
975
976 rmauxSetGeomTransform assigns a default set of action handlers that will
977 be executed when rmauxEventLoop is invoked to begin processing of
978 events. The action handlers installed by rmauxSetGeomTransform will
979 modify the transformation matrices at the RMnode "subTree" to produce
980 either rotations (button2 + motion) or isometric scaling
981 (shift+button2+motion).
982
983 NOTE: (8/27/2000) rmauxSetGeomTransform is identical to rmauxUI().
984 A new routine, rmauxSetCamera3DTransform, has been added to OpenRM
985 and may be used to manipulate 3d camera parameters to achieve
986 image plane translation, as well as camera dollying along the
987 Z axis in eye-coordinates.
988
989 rmauxSetGeomTransform maps RM_BUTTON2 to an arcball-style rotation, and
990 SHIFT+RM_BUTTON2 to isometric scaling. Pressing the RM_BUTTON* on the
991 mouse will initiate the transformation. Dragging the mouse while holding
992 the RM_BUTTON* down will cause a frame to be rendered for each
993 transformation (see Note below), then when the RM_BUTTON* is released,
994 the appearance of interactive transformation stops and the system
995 becomes quiescient.
996
997 Pressing any key on the keyboard other than a modifier key will cause
998 the event loop to latch the pressed key. Once the key is released, a
999 non-NULL user callback function for handling keypresses is called.
1000 This user key callback is set with rmauxEventLoop(). In the
1001 event no keypress callback is assigned with rmauxEventLoop, the event
1002 loop will exit if any non-modifier key is pressed (X11 only, Win32
1003 code incomplete at this time 8/27/2000).
1004
1005 Applications developers may assign their own callbacks to the rmaux
1006 action handler using rmauxButtonDownFunc, rmauxButtonMotionFunc and
1007 rmauxButtonUpFunc (as well as rmauxSetIdleFunc). rmauxUI just assigns
1008 a default set of action handlers to a small, specific set of button
1009 events.
1010
1011 Note: none of the rmaux routines are needed to use the rest of
1012 OpenRM. Your application may use it's own event loop, and you may
1013 safely ignore all of rmaux if that's what you need.
1014
1015 Assumptions:
1016
1017 1. Whenever a frame needs to be drawn, the routine specified by
1018 rmauxSetRenderFunc is invoked. By default, that function is just
1019 rmFrame(). rmFrame() draws everything starting at the scene graph
1020 node rmRootNode().
1021
1022 2. X11 notes: rmauxUI creates cursors for each operation. These
1023 cursors are valid only on the XDisplay of the currently active
1024 RMpipe. Be sure to call rmPipeMakeCurrent prior to calling rmauxUI.
1025 At this time (1/15/2000) this restriction does not apply to Win32
1026 codes.
1027
1028 @dend
1029 * ----------------------------------------------------
1030 */
1031 void
rmauxSetGeomTransform(RMnode * target,RMpipe * usePipe)1032 rmauxSetGeomTransform(RMnode *target,
1033 RMpipe *usePipe)
1034 {
1035 #ifdef RM_X
1036 XColor cursor_fg, cursor_bg;
1037
1038 /* define special X11 cursors for operation emphasis */
1039 rotate_cursor = XCreateFontCursor(rmxPipeGetDisplay(usePipe), XC_exchange);
1040 scale_cursor = XCreateFontCursor(rmxPipeGetDisplay(usePipe), XC_sizing);
1041
1042 /* define cursor colors
1043 * (r,g,b) = [0..65535] in X11 colors
1044 * (the XServer scales X11 colors to available HW color bit depth)
1045 */
1046 cursor_fg.red = 65535;
1047 cursor_fg.green = 0;
1048 cursor_fg.blue = 16383;
1049 cursor_bg.red = 65535;
1050 cursor_bg.green = 65535;
1051 cursor_bg.blue = 65535;
1052
1053 /* color special cursors to emphasize during operation */
1054 XRecolorCursor(rmxPipeGetDisplay(usePipe), rotate_cursor, &cursor_fg, &cursor_bg);
1055 XRecolorCursor(rmxPipeGetDisplay(usePipe), scale_cursor, &cursor_fg, &cursor_bg);
1056 #endif
1057 geomTransformTarget = target;
1058
1059 /* assign RM_BUTTON2: Arcball rotation */
1060 rmauxSetButtonDownFunc(RM_BUTTON2, RM_NONE_MODMASK, rmauxB2DownFunc);
1061 rmauxSetButtonUpFunc(RM_BUTTON2, RM_NONE_MODMASK, rmauxB2UpFunc);
1062 rmauxSetButtonMotionFunc(RM_BUTTON2, RM_NONE_MODMASK, rmauxB2MotionFunc);
1063
1064 /* shift+button two = scale */
1065 rmauxSetButtonDownFunc(RM_BUTTON2,RM_SHIFT_MODMASK, rmauxShiftB2DownFunc);
1066 rmauxSetButtonUpFunc(RM_BUTTON2,RM_SHIFT_MODMASK, rmauxShiftB2UpFunc);
1067 rmauxSetButtonMotionFunc(RM_BUTTON2,RM_SHIFT_MODMASK, rmauxShiftB2MotionFunc);
1068 }
1069
1070 /*
1071 * ----------------------------------------------------
1072 * @Name rmauxSetCamera3DTransform
1073 @pstart
1074 void rmauxSetCamera3DTransform (RMnode *target,
1075 RMpipe *usePipe)
1076 @pend
1077
1078 @astart
1079 RMnode *target - a handle to an RMnode. (input) All transformations
1080 will be applied to the RMcamera3D scene parameter at target, if
1081 such a scene parameter exists.
1082
1083 RMpipe *usePipe - a handle to an RMpipe. (input) This is is the
1084 currently active GL context and is used to get cursors for X11.
1085 @aend
1086
1087 @dstart
1088
1089 rmauxSetCamera3DTransform assigns a default set of action handlers that will
1090 be executed when rmauxEventLoop is invoked to begin processing of
1091 events. The action handlers installed by rmauxSetCamera3DTransform will
1092 modify eye and look-at attributes of the RMcamera3D scene parameter
1093 assigned at the input RMnode "target" to achieve image plane
1094 translation, or dollying along the Z axis of eye coordinates.
1095
1096 rmauxSetCamera3DTransform maps RM_BUTTON1 to image plane translation,
1097 and RM_BUTTON3 to camera dolly translation. Pressing the associated
1098 RM_BUTTON* initiates the transformation. Dragging the mouse while holding
1099 the RM_BUTTON* down will cause a frame to be rendered for each
1100 transformation (see Note below), then when the RM_BUTTON* is released,
1101 the appearance of interactive transformation stops and the system
1102 becomes quiescient.
1103
1104 Pressing any key on the keyboard other than a modifier key will cause
1105 the event loop to latch the pressed key. Once the key is released, a
1106 non-NULL user callback function for handling keypresses is called.
1107 This user key callback is set with rmauxEventLoop(). In the
1108 event no keypress callback is assigned with rmauxEventLoop, the event
1109 loop will exit if any non-modifier key is pressed (X11 only, Win32
1110 code incomplete at this time 8/27/2000).
1111
1112 Applications developers may assign their own callbacks to the rmaux
1113 action handler using rmauxButtonDownFunc, rmauxButtonMotionFunc and
1114 rmauxButtonUpFunc (as well as rmauxSetIdleFunc). rmauxUI just assigns
1115 a default set of action handlers to a small, specific set of button
1116 events.
1117
1118 Note: none of the rmaux routines are needed to use the rest of
1119 OpenRM. Your application may use it's own event loop, and you may
1120 safely ignore all of rmaux if that's what you need.
1121
1122 Assumptions:
1123
1124 1. Whenever a frame needs to be drawn, the routine specified by
1125 rmauxSetRenderFunc is invoked. By default, that function is just
1126 rmFrame(). rmFrame() draws everything starting at the scene graph
1127 node rmRootNode().
1128
1129 2. X11 notes: rmauxUI creates cursors for each operation. These
1130 cursors are valid only on the XDisplay of the currently active
1131 RMpipe. Be sure to call rmPipeMakeCurrent prior to calling rmauxUI.
1132 At this time (1/15/2000) this restriction does not apply to Win32
1133 codes.
1134
1135 @dend
1136 * ----------------------------------------------------
1137 */
1138 void
rmauxSetCamera3DTransform(RMnode * target,RMpipe * usePipe)1139 rmauxSetCamera3DTransform(RMnode *target,
1140 RMpipe *usePipe)
1141 {
1142 #ifdef RM_X
1143 XColor cursor_fg, cursor_bg;
1144
1145 /* define special X11 cursors for operation emphasis */
1146 translate_cursor = XCreateFontCursor(rmxPipeGetDisplay(usePipe), XC_fleur);
1147 dolly_cursor = XCreateFontCursor(rmxPipeGetDisplay(usePipe), XC_double_arrow);
1148 /* define cursor colors
1149 * (r,g,b) = [0..65535] in X11 colors
1150 * (the XServer scales X11 colors to available HW color bit depth)
1151 */
1152 cursor_fg.red = 65535;
1153 cursor_fg.green = 0;
1154 cursor_fg.blue = 16383;
1155 cursor_bg.red = 65535;
1156 cursor_bg.green = 65535;
1157 cursor_bg.blue = 65535;
1158
1159 /* color special cursors to emphasize during operation */
1160 XRecolorCursor(rmxPipeGetDisplay(usePipe), translate_cursor, &cursor_fg, &cursor_bg);
1161 XRecolorCursor(rmxPipeGetDisplay(usePipe), dolly_cursor, &cursor_fg, &cursor_bg);
1162 #endif
1163 camera3DTransformTarget = target;
1164
1165 /* assign RM_BUTTON1: image plane translation */
1166 rmauxSetButtonDownFunc(RM_BUTTON1, RM_NONE_MODMASK, rmauxB1DownFunc);
1167 rmauxSetButtonUpFunc(RM_BUTTON1, RM_NONE_MODMASK, rmauxB1UpFunc);
1168 rmauxSetButtonMotionFunc(RM_BUTTON1, RM_NONE_MODMASK, rmauxB1MotionFunc);
1169
1170 /* assign RM_BUTTON3: camera dolly translation */
1171 rmauxSetButtonDownFunc(RM_BUTTON3, RM_NONE_MODMASK, rmauxB3DownFunc);
1172 rmauxSetButtonUpFunc(RM_BUTTON3, RM_NONE_MODMASK, rmauxB3UpFunc);
1173 rmauxSetButtonMotionFunc(RM_BUTTON3, RM_NONE_MODMASK, rmauxB3MotionFunc);
1174 }
1175
1176
1177 /*
1178 * ----------------------------------------------------
1179 * @Name rmauxUI
1180 @pstart
1181 void rmauxUI (RMnode *target,
1182 RMpipe *usePipe)
1183 @pend
1184
1185 @astart
1186 RMnode *target - a handle to an RMnode. (input) All model
1187 transformations will be applied to this node, and will affect all
1188 children nodes.
1189
1190 RMpipe *usePipe - a handle to an RMpipe. (input) This is is the
1191 currently active GL context and is used to get cursors for X11.
1192 @aend
1193
1194 @dstart
1195
1196 rmauxUI assigns a default set of action handlers that will be
1197 executed when rmauxEventLoop is invoked to begin processing of
1198 events. There are three types of transformations implemented by
1199 rmauxUI: a virtual arcball interface to specify rotations, a camera
1200 dolly translation, and an image plane translation.
1201
1202 rmauxUI maps RM_BUTTON2 to an arcball-style rotation, and
1203 SHIFT+RM_BUTTON2 to isometric scaling. Pressing the RM_BUTTON* on the
1204 mouse will initiate the transformation. Dragging the mouse while holding
1205 the RM_BUTTON* down will cause a frame to be rendered for each
1206 transformation (see Note below), then when the RM_BUTTON* is released,
1207 the appearance of interactive transformation stops and the system
1208 becomes quiescient.
1209
1210 Pressing any key on the keyboard other than a modifier key will cause
1211 the event loop to latch the pressed key. Once the key is released, a
1212 non-NULL user callback function for handling keypresses is called.
1213 This user key callback is set with rmauxEventLoop().
1214
1215 Resizing the window bound to the RMpipe will call a non-NULL user
1216 callback function for handling window resizing. This user resize
1217 callback is set with rmauxEventLoop().
1218
1219 Applications developers may assign their own callbacks to the rmaux
1220 action handler using rmauxButtonDownFunc, rmauxButtonMotionFunc and
1221 rmauxButtonUpFunc (as well as rmauxSetIdleFunc). rmauxUI just assigns
1222 a default set of action handlers to a small, specific set of button
1223 events.
1224
1225 Note: none of the rmaux routines are needed to use the rest of
1226 OpenRM. Your application may use it's own event loop, and you may
1227 safely ignore all of rmaux if that's what you need.
1228
1229 Assumptions:
1230
1231 1. Whenever a frame needs to be drawn, the routine specified by
1232 rmauxSetRenderFunc is invoked. By default, that function is just
1233 rmFrame(). rmFrame() draws everything starting at the scene graph
1234 node rmRootNode().
1235
1236 2. X11 notes: rmauxUI creates cursors for each operation. These
1237 cursors are valid only on the XDisplay of the currently active
1238 RMpipe. Be sure to call rmPipeMakeCurrent prior to calling rmauxUI.
1239 At this time (1/15/2000) this restriction does not apply to Win32
1240 codes.
1241
1242 @dend
1243 * ----------------------------------------------------
1244 */
1245 void
rmauxUI(RMnode * target,RMpipe * usePipe)1246 rmauxUI (RMnode *target,
1247 RMpipe *usePipe)
1248 {
1249 #ifdef RM_X
1250 XColor cursor_fg, cursor_bg;
1251
1252 /* define special X11 cursors for operation emphasis */
1253 translate_cursor = XCreateFontCursor(rmxPipeGetDisplay(usePipe), XC_fleur);
1254 rotate_cursor = XCreateFontCursor(rmxPipeGetDisplay(usePipe), XC_exchange);
1255 dolly_cursor = XCreateFontCursor(rmxPipeGetDisplay(usePipe), XC_double_arrow);
1256 scale_cursor = XCreateFontCursor(rmxPipeGetDisplay(usePipe), XC_sizing);
1257
1258 /* define cursor colors
1259 * (r,g,b) = [0..65535] in X11 colors
1260 * (the XServer scales X11 colors to available HW color bit depth)
1261 */
1262 cursor_fg.red = 65535;
1263 cursor_fg.green = 0;
1264 cursor_fg.blue = 16383;
1265 cursor_bg.red = 65535;
1266 cursor_bg.green = 65535;
1267 cursor_bg.blue = 65535;
1268
1269 /* color special cursors to emphasize during operation */
1270 XRecolorCursor(rmxPipeGetDisplay(usePipe), rotate_cursor, &cursor_fg, &cursor_bg);
1271 XRecolorCursor(rmxPipeGetDisplay(usePipe), scale_cursor, &cursor_fg, &cursor_bg);
1272 #endif
1273
1274 /* save `UI root' node as target for interaction */
1275 if (target == NULL)
1276 {
1277 rmError("rmauxUI() error - input node is NULL.");
1278 return;
1279 }
1280 geomTransformTarget = target;
1281
1282 /* assign RM_BUTTON2: Arcball rotation */
1283 rmauxSetButtonDownFunc(RM_BUTTON2, RM_NONE_MODMASK, rmauxB2DownFunc);
1284 rmauxSetButtonUpFunc(RM_BUTTON2, RM_NONE_MODMASK, rmauxB2UpFunc);
1285 rmauxSetButtonMotionFunc(RM_BUTTON2, RM_NONE_MODMASK, rmauxB2MotionFunc);
1286
1287 /* shift+button two = scale */
1288 rmauxSetButtonDownFunc(RM_BUTTON2,RM_SHIFT_MODMASK, rmauxShiftB2DownFunc);
1289 rmauxSetButtonUpFunc(RM_BUTTON2,RM_SHIFT_MODMASK, rmauxShiftB2UpFunc);
1290 rmauxSetButtonMotionFunc(RM_BUTTON2,RM_SHIFT_MODMASK, rmauxShiftB2MotionFunc);
1291
1292 }
1293
1294
1295 /*
1296 * ----------------------------------------------------
1297 * @Name rmauxSetInitFunc
1298 @pstart
1299 rmauxSetInitFunc (void (*userinitfunc)(RMpipe *drawOn, RMnode *subTree))
1300 @pend
1301
1302 @astart
1303 void (*userinitfunc)(RMpipe *drawOnPipe, RMnode *subtree) - a handle to a caller-supplied
1304 initialization function.
1305 @aend
1306
1307 @dstart
1308
1309 Use this routine to register your application's "init" function with
1310 RMaux. This initialization function will be called from within
1311 rmauxEventLoop after all OpenGL and window system initialization had
1312 been complete, and it is safe to begin using all of OpenRM.
1313
1314 @dend
1315 * ----------------------------------------------------
1316 */
1317 void
rmauxSetInitFunc(void (* userinitfunc)(RMpipe *,RMnode *))1318 rmauxSetInitFunc (void (*userinitfunc)(RMpipe *, RMnode *))
1319 {
1320 staticUserInitFunc = userinitfunc;
1321 }
1322
1323
1324 /*
1325 * ----------------------------------------------------
1326 * @Name rmauxSetIdleFunc
1327 @pstart
1328 void rmauxSetIdleFunc (RMpipe *p,
1329 int (*userfunc)(RMpipe *currentPipe, int pointerX, int pointerY))
1330
1331 @pend
1332
1333 @astart
1334 RMpipe *p - a handle to an active RMpipe object.
1335
1336 int (*userfunc)(RMpipe *currentPipe, int pointerX, int pointerY) - a
1337 handle to an application function that will be called when the
1338 system is idle. The routine will be passed the current (x,y) pixel
1339 location of the pointer, along with a handle to the controlling
1340 RMpipe. When the app idle callback returns a zero, event loop
1341 processing is terminated; when a non-zero value is returned,
1342 processing continues.
1343 @aend
1344
1345 @dstart
1346
1347 Use this routine to register an application function that will be
1348 called (X11) when there are no other events in the event queue or
1349 (Win32) a timer with a 20msec interval "alarm" has expired.
1350
1351 Win32 Notes: we need the RMpipe pointer so that we can obtain the
1352 window handle for the purpose of attaching a "timer" function to a
1353 window. because the timer goes off at a specified interval (in the
1354 absence of other messages to process), it's not really an "idle"
1355 function except in the sense that the app function is called 20msec
1356 after a period of idleness is detected.
1357
1358 X: it really is an idle function. note that we detect idleness
1359 inside the event loop attached to a window, and don't need the
1360 RMpipe structure. it is included here so that one API can be used
1361 for both Win32 and X.
1362
1363 The value returned by the application idle callback has an effect
1364 upon event loop processing: when the app callback returns a zero,
1365 event loop processing is terminated. When a non-zero value is
1366 returned, event loop processing continues.
1367
1368 @dend
1369 * ----------------------------------------------------
1370 */
1371 void
rmauxSetIdleFunc(RMpipe * p,int (* userfunc)(RMpipe * currentPipe,int pointerX,int pointerY))1372 rmauxSetIdleFunc (RMpipe *p,
1373 int (*userfunc)(RMpipe *currentPipe, int pointerX, int pointerY))
1374 {
1375 staticUserIdleFunc = userfunc;
1376 #ifdef RM_WIN
1377 {
1378 HWND hWnd;
1379
1380 hWnd = rmPipeGetWindow(p);
1381
1382 if (hWnd != 0)
1383 {
1384 if (userfunc != NULL)
1385 SetTimer(hWnd, 101, 1, NULL); /* call every 1 msec when no other msgs present */
1386 else if (spinCallbackFunc == NULL) /* don't turn off timer if
1387 we a spinCallbackFunc is set*/
1388 KillTimer(hWnd, 101);
1389 }
1390 }
1391 #endif
1392
1393 /* foil compiler warning */
1394 p = NULL;
1395 }
1396
1397 /*
1398 * ----------------------------------------------------
1399 * @Name rmauxSetKeyFunc
1400 @pstart
1401 void rmauxSetKeyFunc (int (*userfunc)(RMpipe *p, char k, KeySym code))
1402 @pend
1403
1404 @astart
1405 int (*userfunc)(RMpipe *p, char k, KeySym code) - a pointer to a user function
1406 (input).
1407 @aend
1408
1409 @dstart
1410
1411 Use rmauxSetKeyFunc to assign a keypress handler that will be invoked by
1412 rmauxEventLoop whenever a non-modifier keypress is detected. The userFunc
1413 will be provided the keyboard key that was pressed, the current RMpipe, and a
1414 KeySym code. Unlike mouse event mappings, where a different callback is
1415 invoked depending upon motion, button up or down events, a single key handler
1416 is used to perform processing of all keyboard events. Application-supplied
1417 key handler callbacks must contain sufficient internal logic to detect
1418 which key was pressed, and take appropriate action.
1419
1420 The userFunc should return RM_CHILL to rmauxEventLoop if event processing
1421 is to continue, or return RM_WHACKED if event loop processing should
1422 continue.
1423
1424 The RM demo programs typically assign the default key handler
1425 rmauxDefaultKeyFunc, which will terminate event loop processing whenever
1426 the user presses the "q" key on the keyboard.
1427
1428 Notes:
1429
1430 4/20/02 - this routine was updated to unify keypress handling on both
1431 X11 and Win32 platforms. The same API is used in both places, but the
1432 KeySym type is artificially defined on Win32 in order to coerce API
1433 consistency across platforms. Presently, the KeySym "code" parameter
1434 is not used on Win32. Only printable ASCII chars will trigger a call to
1435 the user-defined key-handling function on Win32; refer to your Win32
1436 developer documentation to learn more about which keys actually trigger
1437 an WM_CHAR event, which in turn initiates a call to the user-supplied
1438 key-handling callback.
1439
1440 @dend
1441 * ----------------------------------------------------
1442 */
1443 void
rmauxSetKeyFunc(RMpipe * p,int (* userfunc)(RMpipe * currentPipe,char k,KeySym code))1444 rmauxSetKeyFunc (RMpipe *p,
1445 int (*userfunc)(RMpipe *currentPipe, char k, KeySym code))
1446 {
1447 staticUserKeyFunc = userfunc;
1448
1449 /* foil compiler warning */
1450 p = NULL;
1451 }
1452
1453
1454 /*
1455 * ----------------------------------------------------
1456 * @Name rmauxDefaultKeyFunc
1457 @pstart
1458 int rmauxDefaultKeyFunc (RMpipe *currentPipe,
1459 char key,
1460 KeySym code)
1461 @pend
1462
1463 @astart
1464 RMpipe *currentPipe - a handle to the current pipe (input)
1465 char key - key from most recent key press (input)
1466 KeySym code (input) - an X11 KeySym code.
1467 @aend
1468
1469 @dstart
1470
1471 This simple key callback function intercepts "Q/q" key presses and
1472 then signals to quit application.
1473
1474 4/20/02 - this routine was updated to unify keypress handling on both
1475 X11 and Win32 platforms. The same API is used in both places, but the
1476 KeySym type is artificially defined on Win32 in order to coerce API
1477 consistency across platforms. Presently, the KeySym "code" parameter
1478 is not used on Win32. Only printable ASCII chars will trigger a call to
1479 the user-defined key-handling function on Win32; refer to your Win32
1480 developer documentation to learn more about which keys actually trigger
1481 an WM_CHAR event, which in turn initiates a call to the user-supplied
1482 key-handling callback.
1483
1484 3/27/04 - the input parameter "code" is ignored by this routine. The
1485 parameter is present to facilitate API consistency between user-supplied
1486 key handler callbacks and this RMaux default key handler.
1487
1488 @dend
1489 * ----------------------------------------------------
1490 */
1491 int
rmauxDefaultKeyFunc(RMpipe * currentPipe,char key,KeySym code)1492 rmauxDefaultKeyFunc (RMpipe *currentPipe,
1493 char key,
1494 KeySym code)
1495 {
1496 /* convert to lower case */
1497 if ((key >= 'A') && (key <= 'Z'))
1498 key = key - ('A' - 'a');
1499
1500 /* take appropriate menu action */
1501 switch (key)
1502 {
1503 case 'q': /* quitting time */
1504 return (RM_WHACKED);
1505
1506 default: /* do nothing */
1507 break;
1508 }
1509
1510 /* foil compiler warning */
1511 currentPipe = NULL;
1512 code = (KeySym)0;
1513
1514 return (RM_CHILL);
1515 }
1516
1517
1518 /*
1519 * ----------------------------------------------------
1520 * @Name rmauxSetResizeFunc
1521 @pstart
1522 void rmauxSetResizeFunc (RMpipe *p,
1523 RMnode *cameraNode,
1524 RMenum (*userfunc)(RMpipe *p, RMnode *n, int winWidth, int winHeight))
1525 @pend
1526
1527 @astart
1528 RMpipe *p - an RMpipe object (input).
1529
1530 RMnode *cameraNode - a handle to an RMnode, which should contain either
1531 an RMcamera2D or RMcamera3D scene parameter (input, but modified at
1532 runtime when a window resize event occurs).
1533
1534 void (*userfunc)(RMpipe *p, RMnode *n, int winWidth, int winHeight) - a pointer to a user function (input).
1535 @aend
1536
1537 @dstart
1538
1539 The rmaux*UI()/rmauxEventLoop routines will catch all resize events to
1540 the application window. The user may inmplement a routine to handle
1541 window resizing and specify it here.
1542
1543 The default resize function routine used by rmauxSetResizeFunc()
1544 adjusts camera parameters according to the resized window geometry.
1545
1546 See rmauxDefaultResizeFunc() for more details about the parameters
1547 to the resize callback function.
1548
1549 @dend
1550 * ----------------------------------------------------
1551 */
1552 void
rmauxSetResizeFunc(RMpipe * p,RMnode * cameraNode,int (* userfunc)(RMpipe * currentPipe,RMnode * cameraNode,int pointerX,int pointerY))1553 rmauxSetResizeFunc (RMpipe *p,
1554 RMnode *cameraNode,
1555 int (*userfunc)(RMpipe *currentPipe, RMnode *cameraNode, int pointerX, int pointerY))
1556 {
1557 staticUserResizeFunc = userfunc;
1558 private_rmauxSetCameraResizeNode(cameraNode);
1559
1560 /* foil compiler warning */
1561 p = NULL;
1562 }
1563
1564
1565 /*
1566 * ----------------------------------------------------
1567 * @Name rmauxDefaultResizeFunc
1568 @pstart
1569 int rmauxDefaultResizeFunc (RMpipe *currentPipe,
1570 RMnode *cameraNode,
1571 int winWidth,
1572 int winHeight)
1573 @pend
1574
1575 @astart
1576 RMpipe *currentPipe - a handle to the current pipe
1577
1578 RMnode *cameraNode - a handle to a scene graph node containing either
1579 an RMcamera2D or RMcamera3D scene parameter.
1580
1581 int winWidth, winHeight - two integers specifying the new window
1582 size in pixels. These values are provided by rmauxEventLoop to
1583 the resize callback (input).
1584 @aend
1585
1586 @dstart
1587
1588 This simple resize callback function will adjust the aspect ratio of
1589 the 2D or 3D camera scene parameter contained in "cameraNode" to
1590 reflect the ratio of width to height dimensions of the resized window.
1591
1592 If the target node "cameraNode" does not contain either a RMcamera2D
1593 or RMcamera3D scene parameter, this routine will issue a warning message.
1594
1595 This routine always returns RM_CHILL, regardless of errors.
1596
1597 @dend
1598 * ----------------------------------------------------
1599 */
1600 int
rmauxDefaultResizeFunc(RMpipe * currentPipe,RMnode * cameraNode,int winWidth,int winHeight)1601 rmauxDefaultResizeFunc (RMpipe *currentPipe,
1602 RMnode *cameraNode,
1603 int winWidth,
1604 int winHeight)
1605 {
1606 RMcamera3D * c3=NULL;
1607 RMcamera2D * c2=NULL;
1608 RMnode * r=NULL;
1609
1610 r = cameraNode;
1611 if ((rmNodeGetSceneCamera3D (r, &c3)) != RM_WHACKED)
1612 {
1613 rmCamera3DSetAspectRatio (c3, ((float)(winWidth) / (float)(winHeight)));
1614 rmNodeSetSceneCamera3D (r, c3);
1615 }
1616 else if (rmNodeGetSceneCamera2D (r, &c2) != RM_WHACKED)
1617 {
1618 rmCamera2DSetAspectRatio (c2, ((float)(winWidth) / (float)(winHeight)));
1619 rmNodeSetSceneCamera2D (r, c2);
1620 }
1621
1622 if ((c2 == NULL) && (c3 == NULL))
1623 rmWarning("rmauxDefaultResizeFunc() - the cameraNode does not contain either a 2D or 3D camera scene parameter!");
1624
1625 if (c3 != NULL)
1626 rmCamera3DDelete(c3);
1627
1628 if (c2 != NULL)
1629 rmCamera2DDelete(c2);
1630
1631 rmPipeSetWindowSize(currentPipe, winWidth, winHeight);
1632
1633 return (RM_CHILL);
1634 }
1635
1636 /*
1637 * ----------------------------------------------------
1638 * @Name rmauxSetRenderFunc
1639 @pstart
1640 void rmauxSetRenderFunc (void (*userfunc)(RMpipe *currentPipe))
1641 @pend
1642
1643 @astart
1644 void (*userfunc)(RMpipe *currentPipe) - a pointer to a user function
1645 (input).
1646 @aend
1647
1648 @dstart
1649
1650 The rmaux*UI()/rmauxEventLoop routines will occasionally have the
1651 need to render an image. For the trackball interface, rendering is
1652 needed whenever the mouse button is pressed and dragged. The
1653 rmauxEventLoop event handler allows applications to set a routine
1654 that is called whenever rendering is needed.
1655
1656 The default rendering routine used by rmauxSetRenderFunc() calls the
1657 generic rendering routine rmFrame().
1658
1659 @dend
1660 * ----------------------------------------------------
1661 */
1662 void
rmauxSetRenderFunc(void (* userfunc)(RMpipe * p,RMnode * n))1663 rmauxSetRenderFunc (void (*userfunc)(RMpipe *p, RMnode *n))
1664 {
1665 if (userfunc != NULL)
1666 renderfunc = userfunc;
1667 }
1668
1669
1670 /*
1671 * ----------------------------------------------------
1672 * @Name rmauxSetButtonDownFunc
1673 @pstart
1674 void rmauxSetButtonDownFunc (unsigned int whichbutton,
1675 unsigned int modmask,
1676 int (*userfunc) (RMpipe *currentPipe, int pointerX, int pointerY))
1677 @pend
1678
1679 @astart
1680 unsigned int whichbutton - An integer value specifying which button
1681 will be assigned an action handler. Valid values are RM_BUTTON1,
1682 RM_BUTTON2, RM_BUTTON3, RM_BUTTON4 or RM_BUTTON5. The enumerators
1683 RM_BUTTON4 and RM_BUTTON5 are valid in X11 environments, but not
1684 valid in Windows environments.
1685
1686 unsigned int modmask - An integer value specifying a modifier mask
1687 that can be used to qualify buttons. Valid values are
1688 RM_NONE_MODMASK, RM_SHIFT_MODMASK or RM_CONTROL_MODMASK.
1689
1690 int (*userfunc) (RMpipe *currentPipe, int xPointerPosition, int
1691 yPointerPosition) - the function that will be invoked when the
1692 named button is pressed and modifier mask conditions are met. The
1693 user function will be passed integer values representing the (x,y)
1694 pixel coordinate of the pointer, along with a handle to the
1695 current/calling RMpipe.
1696 @aend
1697
1698 @dstart
1699
1700 Applications may use this routine to define action handlers that will
1701 be invoked from inside of rmauxEventLoop(). This routine is one of
1702 three used to assign an application callback that will be invoked
1703 when a button is pressed. One of two modifier keys may also be
1704 specified, the shift key or control key, to be used in conjunction
1705 with a button.
1706
1707 This routine, rmauxSetButtonDownFunc, is used to assign a callback to
1708 correspond to button down events.
1709
1710 The return value from the application callback is significant. A
1711 return value of zero will cause the event loop to terminate. A value
1712 of 1 cause the event loop to continue processing events (strictly
1713 speaking, any non-zero value will keep the event loop going).
1714
1715 @dend
1716 * ----------------------------------------------------
1717 */
1718 void
rmauxSetButtonDownFunc(unsigned int whichbutton,unsigned int modmask,int (* userfunc)RMAUX_BUTTON_FUNC_PARMS ())1719 rmauxSetButtonDownFunc (unsigned int whichbutton,
1720 unsigned int modmask,
1721 int (*userfunc) RMAUX_BUTTON_FUNC_PARMS() )
1722 {
1723 int button_index, modifier_index;
1724
1725 button_index = private_rmauxButtonNumToIndex(whichbutton);
1726 modifier_index = private_rmauxModifierToIndex(modmask);
1727
1728 rmauxUserButtonDownFuncs[modifier_index][button_index] = userfunc;
1729 }
1730
1731
1732 /*
1733 * ----------------------------------------------------
1734 * @Name rmauxSetButtonUpFunc
1735 @pstart
1736 void rmauxSetButtonUpFunc (unsigned int whichbutton,
1737 unsigned int modmask,
1738 int (*userfunc) (RMpipe *currentPipe, int pointerX, int pointerY))
1739 @pend
1740
1741 @astart
1742 unsigned int whichbutton - An integer value specifying which button
1743 will be assigned an action handler. Valid values are RM_BUTTON1,
1744 RM_BUTTON2, RM_BUTTON3, RM_BUTTON4 or RM_BUTTON5. The enumerators
1745 RM_BUTTON4 and RM_BUTTON5 are valid in X11 environments but not
1746 Windows environments.
1747
1748 unsigned int modmask - An integer value specifying a modifier mask
1749 that can be used to qualify buttons. Valid values are
1750 RM_NONE_MODMASK, RM_SHIFT_MODMASK or RM_CONTROL_MODMASK.
1751
1752 int (*userfunc) (RMpipe *currentPipe, int xPointerPosition, int
1753 yPointerPosition) - the function that will be invoked when the
1754 named button is released, and modifier mask conditions are
1755 met. The user function will be passed integer values representing
1756 the (x,y) pixel coordinate of the pointer, along with a handle to
1757 the current/calling RMpipe.
1758 @aend
1759
1760 @dstart
1761
1762 Applications may use this routine to define action handlers that will
1763 be invoked from inside of rmauxEventLoop(). This routine is one of
1764 three used to assign an application callback that will be invoked
1765 when a button release event is detected, and while modifier
1766 conditions are met. One of two modifier keys may also be specified,
1767 the shift key or control key, to be used in conjunction with a
1768 button.
1769
1770 This routine, rmauxSetButtonUpFunc, is used to assign a callback to
1771 correspond to button button release events, possibly with a modifier
1772 key present.
1773
1774 The return value from the application callback is significant. A
1775 return value of zero will cause the event loop to terminate. A value
1776 of 1 cause the event loop to continue processing events (strictly
1777 speaking, any non-zero value will keep the event loop going).
1778
1779 @dend
1780 * ----------------------------------------------------
1781 */
1782 void
rmauxSetButtonUpFunc(unsigned int whichbutton,unsigned int modmask,int (* userfunc)RMAUX_BUTTON_FUNC_PARMS ())1783 rmauxSetButtonUpFunc (unsigned int whichbutton,
1784 unsigned int modmask,
1785 int (*userfunc) RMAUX_BUTTON_FUNC_PARMS() )
1786 {
1787 int button_index, modifier_index;
1788
1789 button_index = private_rmauxButtonNumToIndex(whichbutton);
1790 modifier_index = private_rmauxModifierToIndex(modmask);
1791
1792 rmauxUserButtonUpFuncs[modifier_index][button_index] = userfunc;
1793 }
1794
1795
1796 /*
1797 * ----------------------------------------------------
1798 * @Name rmauxSetButtonMotionFunc
1799 @pstart
1800 void rmauxSetButtonMotionFunc (unsigned int whichbutton,
1801 unsigned int modmask,
1802 int (*userfunc) (RMpipe *currentPipe, int pointerX, int pointerY))
1803 @pend
1804
1805 @astart
1806 unsigned int whichbutton - An integer value specifying which button
1807 will be assigned an action handler. Valid values are RM_BUTTON1,
1808 RM_BUTTON2, RM_BUTTON3, RM_BUTTON4 or RM_BUTTON5. The enumerators
1809 RM_BUTTON4 and RM_BUTTON5 are valid in X11 environments but not
1810 Windows environments.
1811
1812 unsigned int modmask - An integer value specifying a modifier mask
1813 that can be used to qualify buttons. Valid values are
1814 RM_NONE_MODMASK, RM_SHIFT_MODMASK or RM_CONTROL_MODMASK.
1815
1816 int (*userfunc) (RMpipe *currentPipe, int xPointerPosition, int
1817 yPointerPosition) - the function that will be invoked when the
1818 named button is depressed, the the pointer is moving, and modifier
1819 mask conditions are met. The user function will be passed integer
1820 values representing the (x,y) pixel coordinate of the pointer,
1821 along with a handle to the current/calling RMpipe.
1822 @aend
1823
1824 @dstart
1825
1826 Applications may use this routine to define action handlers that will
1827 be invoked from inside of rmauxEventLoop(). This routine is one of
1828 three used to assign an application callback that will be invoked
1829 when a motion event is detected, while a button is pressed and while
1830 modifier conditions are met. One of two modifier keys may also be
1831 specified, the shift key or control key, to be used in conjunction
1832 with a button.
1833
1834 This routine, rmauxSetButtonMotionFunc, is used to assign a callback
1835 to correspond to motion events while a button, and possibly a modifer
1836 key are depressed.
1837
1838 The return value from the application callback is significant. A
1839 return value of zero will cause the event loop to terminate. A value
1840 of 1 cause the event loop to continue processing events (strictly
1841 speaking, any non-zero value will keep the event loop going).
1842
1843 @dend
1844 * ----------------------------------------------------
1845 */
1846 void
rmauxSetButtonMotionFunc(unsigned int whichbutton,unsigned int modmask,int (* userfunc)RMAUX_BUTTON_FUNC_PARMS ())1847 rmauxSetButtonMotionFunc (unsigned int whichbutton,
1848 unsigned int modmask,
1849 int (*userfunc) RMAUX_BUTTON_FUNC_PARMS() )
1850 {
1851 int button_index, modifier_index;
1852
1853 button_index = private_rmauxButtonNumToIndex(whichbutton);
1854 modifier_index = private_rmauxModifierToIndex(modmask);
1855
1856 rmauxUserButtonMotionFuncs[modifier_index][button_index] = userfunc;
1857 }
1858
1859
1860 /* button callback default definition */
1861 static int
RMAUX_BUTTON_FUNC_PARMS()1862 rmauxEventNoOp RMAUX_BUTTON_FUNC_PARMS()
1863 {
1864 /* foil compiler warning */
1865 xbutton = ybutton = 0;
1866
1867 /* foil compiler warning */
1868 p = NULL;
1869
1870 return(1);
1871 }
1872
1873
1874 /* default button down functions [rmauxEventNoOp], modified by rmauxSetButtonDownFunc() */
1875 static int (*rmauxUserButtonDownFuncs[RM_NUM_BUTTON_MODIFIERS][RM_NUM_BUTTONS + 1]) RMAUX_BUTTON_FUNC_PARMS() =
1876 {
1877 {rmauxEventNoOp, rmauxEventNoOp, rmauxEventNoOp, rmauxEventNoOp, rmauxEventNoOp, rmauxEventNoOp},
1878 {rmauxEventNoOp, rmauxEventNoOp, rmauxEventNoOp, rmauxEventNoOp, rmauxEventNoOp},
1879 {rmauxEventNoOp, rmauxEventNoOp, rmauxEventNoOp, rmauxEventNoOp, rmauxEventNoOp}
1880 };
1881
1882
1883 /* default button up functions [rmauxEventNoOp], modified by rmauxSetButtonUpFunc() */
1884 static int (*rmauxUserButtonUpFuncs[RM_NUM_BUTTON_MODIFIERS][RM_NUM_BUTTONS + 1]) RMAUX_BUTTON_FUNC_PARMS() =
1885 {
1886 {rmauxEventNoOp, rmauxEventNoOp, rmauxEventNoOp, rmauxEventNoOp, rmauxEventNoOp, rmauxEventNoOp},
1887 {rmauxEventNoOp, rmauxEventNoOp, rmauxEventNoOp, rmauxEventNoOp, rmauxEventNoOp, rmauxEventNoOp},
1888 {rmauxEventNoOp, rmauxEventNoOp, rmauxEventNoOp, rmauxEventNoOp, rmauxEventNoOp, rmauxEventNoOp}
1889 };
1890
1891
1892 /* default button motion functions [rmauxEventNoOp], modified by rmauxSetButtonMotionFunc() */
1893 static int (*rmauxUserButtonMotionFuncs[RM_NUM_BUTTON_MODIFIERS][RM_NUM_BUTTONS + 1]) RMAUX_BUTTON_FUNC_PARMS() =
1894 {
1895 {rmauxEventNoOp, rmauxEventNoOp, rmauxEventNoOp, rmauxEventNoOp, rmauxEventNoOp, rmauxEventNoOp},
1896 {rmauxEventNoOp, rmauxEventNoOp, rmauxEventNoOp, rmauxEventNoOp, rmauxEventNoOp, rmauxEventNoOp},
1897 {rmauxEventNoOp, rmauxEventNoOp, rmauxEventNoOp, rmauxEventNoOp, rmauxEventNoOp, rmauxEventNoOp}
1898 };
1899
1900
1901 /* PRIVATE (rmauxUI, rmFlyUI)
1902 *
1903 * intended for internal use, currently used only by rmFlyUI to
1904 * invoke the renderer. this routine will invoke the currently-registered
1905 * render function assigned to rmaux.
1906 *
1907 * since this is intended for internal use, it is not publicly documented.
1908 */
1909 void
rmauxInvokeRenderFunc(RMpipe * pipe,RMnode * subTreeToDraw)1910 rmauxInvokeRenderFunc (RMpipe *pipe,
1911 RMnode *subTreeToDraw)
1912 {
1913 (*renderfunc)(pipe, subTreeToDraw);
1914 }
1915
1916
1917 /* PRIVATE (rmauxUI)
1918 *
1919 * rmauxB1DownFunc is called from rmauxEventLoop when a
1920 * button1 down event is detected. rmauxUI assigns rmauxB1DownFunc
1921 * to be the action handler for button1 down.
1922 *
1923 * RM_BUTTON1: image plane translation
1924 *
1925 * applications may override this by calling rmauxSetButtonMotionFunc().
1926 * since this routine is intended to be called only from within
1927 * rmauxEventLoop, it is not publicly documented.
1928 */
1929 int
RMAUX_BUTTON_FUNC_PARMS()1930 rmauxB1DownFunc RMAUX_BUTTON_FUNC_PARMS()
1931 {
1932 int width, height;
1933
1934 #ifdef RM_X
1935 XDefineCursor(rmxPipeGetDisplay(p), rmPipeGetWindow(p), translate_cursor);
1936 #endif
1937 /* save the starting NDC cursor position */
1938 rmPipeGetWindowSize(p, &width, &height);
1939 x = pixeltovp(xbutton, width);
1940 y = -1.0F * pixeltovp(ybutton, height);
1941
1942 return(1);
1943 }
1944
1945
1946 /* PRIVATE (rmauxUI)
1947 *
1948 * rmauxB1UpFunc is called from rmauxEventLoop when a button2 up
1949 * event is detected. rmauxUI assigns rmauxB1UpFunc
1950 * to be the action handler for button1 up.
1951 *
1952 * RM_BUTTON1: image plane translation
1953 *
1954 * applications may override this by calling rmauxSetButtonMotionFunc().
1955 * since this routine is intended to be called only from within
1956 * rmauxEventLoop, it is not publicly documented.
1957 */
1958 int
RMAUX_BUTTON_FUNC_PARMS()1959 rmauxB1UpFunc RMAUX_BUTTON_FUNC_PARMS()
1960 {
1961 #ifdef RM_X
1962 XUndefineCursor(rmxPipeGetDisplay(p), rmPipeGetWindow(p));
1963 #endif
1964
1965 /* foil compiler warning */
1966 xbutton = ybutton = 0;
1967
1968 return(1);
1969 }
1970
1971
1972 /* PRIVATE (rmauxUI)
1973 *
1974 * rmauxB1MotionFunc is called from rmauxEventLoop when a motion
1975 * event is detected while button1 is held down. rmauxUI assigns
1976 * rmauxB1MotionFunc to be the action handler for button1+motion.
1977 *
1978 * RM_BUTTON1: image plane translation
1979 *
1980 * applications may override this by calling rmauxSetButtonMotionFunc().
1981 * since this routine is intended to be called only from within
1982 * rmauxEventLoop, it is not publicly documented.
1983 */
1984 int
RMAUX_BUTTON_FUNC_PARMS()1985 rmauxB1MotionFunc RMAUX_BUTTON_FUNC_PARMS()
1986 {
1987 int width, height;
1988 float x2, y2;
1989 RMcamera3D *c=NULL;
1990
1991
1992 /* get current NDC cursor position */
1993 rmPipeGetWindowSize(p, &width, &height);
1994 x2 = pixeltovp(xbutton, width);
1995 y2 = -1.0F * pixeltovp(ybutton, height);
1996
1997 /* do specified image plane translation */
1998 if (rmNodeGetSceneCamera3D(camera3DTransformTarget, &c) != RM_WHACKED)
1999 {
2000 rmauxTranslate(c, &x, &y, &x2, &y2);
2001 rmNodeSetSceneCamera3D(camera3DTransformTarget, c);
2002 rmCamera3DDelete(c);
2003 }
2004 x = x2;
2005 y = y2;
2006
2007 /* redraw the frame */
2008 rmauxInvokeRenderFunc(p, private_rmauxGetCurrentSceneGraph());
2009
2010 return(1);
2011 }
2012
2013
2014 /* PRIVATE (rmauxUI)
2015 *
2016 * rmauxB2DownFunc is called from rmauxEventLoop when a
2017 * button2 down event is detected. rmauxUI assigns rmauxB2DownFunc
2018 * to be the action handler for button2 down.
2019 *
2020 * RM_BUTTON2: Arcball rotation
2021 *
2022 * applications may override this by calling rmauxSetButtonMotionFunc().
2023 * since this routine is intended to be called only from within
2024 * rmauxEventLoop, it is not publicly documented.
2025 */
2026 int
RMAUX_BUTTON_FUNC_PARMS()2027 rmauxB2DownFunc RMAUX_BUTTON_FUNC_PARMS()
2028 {
2029 int width, height;
2030
2031 #ifdef RM_X
2032 XDefineCursor(rmxPipeGetDisplay(p), rmPipeGetWindow(p), rotate_cursor);
2033 #endif
2034
2035 if (spinCallbackFunc != NULL)
2036 {
2037 #ifdef RM_WIN
2038 if (staticUserIdleFunc == NULL)
2039 {
2040 /*
2041 * turn off the timed event generator if the user defined
2042 * idle callback isn't defined.
2043 */
2044 HWND hWnd;
2045 hWnd = rmPipeGetWindow(p);
2046 KillTimer(hWnd, 101);
2047 }
2048 #endif
2049 spinCallbackFunc = NULL;
2050 }
2051
2052 /* save the starting NDC cursor position */
2053 rmPipeGetWindowSize(p, &width, &height);
2054
2055 lastBX1 = lastBX2 = (float)xbutton;
2056 x = pixeltovp(xbutton, width);
2057
2058 lastBY1 = lastBY2 = (float)ybutton;
2059 y = -1.0F * pixeltovp(ybutton, height);
2060
2061 /* save the initial rotation matrix */
2062 if (rmNodeGetRotateMatrix(geomTransformTarget, &ui_pose) == RM_WHACKED)
2063 rmMatrixIdentity(&ui_pose);
2064
2065 return(1);
2066 }
2067
2068 void
private_rmauxComputeScaledSpinPoints(float * px1,float * py1,float * px2,float * py2,int width,int height)2069 private_rmauxComputeScaledSpinPoints(float *px1,
2070 float *py1,
2071 float *px2,
2072 float *py2,
2073 int width,
2074 int height)
2075 {
2076 RMvertex2D p1, p2, v;
2077 double d;
2078
2079 p1.x = pixeltovp(*px1, width);
2080 p1.y = pixeltovp(*py1, height);
2081
2082 p2.x = pixeltovp(*px2, width);
2083 p2.y = pixeltovp(*py2, height);
2084
2085 v.x = p2.x - p1.x;
2086 v.y = p2.y - p1.y;
2087
2088 d = (v.x * v.x) + (v.y * v.y);
2089 d = sqrt(d);
2090
2091 v.x *= d;
2092 v.y *= d;
2093
2094 *px2 = *px1 + (v.x*width);
2095 *py2 = *py1 + (v.y*height);
2096 }
2097
2098 /* PRIVATE (rmauxUI)
2099 *
2100 * rmauxB2UpFunc is called from rmauxEventLoop when a button2 up
2101 * event is detected. rmauxUI assigns rmauxB2UpFunc
2102 * to be the action handler for button2 up.
2103 *
2104 * RM_BUTTON2: Arcball rotation
2105 *
2106 * applications may override this by calling rmauxSetButtonMotionFunc().
2107 * since this routine is intended to be called only from within
2108 * rmauxEventLoop, it is not publicly documented.
2109 */
2110 int
RMAUX_BUTTON_FUNC_PARMS()2111 rmauxB2UpFunc RMAUX_BUTTON_FUNC_PARMS()
2112 {
2113 int width, height;
2114 #ifdef RM_X
2115 XUndefineCursor(rmxPipeGetDisplay(p), rmPipeGetWindow(p));
2116 #endif
2117
2118 /* printf(" x,y at release %d, %d \n", xbutton, ybutton); */
2119
2120 if (spinModeEnabled == RM_TRUE)
2121 {
2122 rmPipeGetWindowSize(p, &width, &height);
2123
2124 #ifdef RM_WIN
2125 if (private_rmauxSpinThreshold(lastBX2, lastBY2, lastBX1, lastBY1, staticSpinThreshold) > 0)
2126 #else
2127 if (private_rmauxSpinThreshold(lastBX2, lastBY2, lastBX1, lastBY1, staticSpinThreshold) > 0)
2128 #endif
2129 {
2130 spinCallbackFunc = private_rmauxDoSpinCallback;
2131 #ifdef RM_WIN
2132 {
2133 HWND hWnd;
2134 hWnd = rmPipeGetWindow(p);
2135 /*
2136 * since we've exceeded the spin threshold, under Win32 we
2137 * need to activate a timer to generate events.
2138 */
2139
2140 if (hWnd != 0)
2141 SetTimer(hWnd, 101, 1, NULL); /* call every 20 msec when no other msgs present */
2142
2143 }
2144 #endif
2145 {
2146 float px1, py1, px2, py2;
2147 px1 = lastBX2;
2148 py1 = lastBY2;
2149 px2 = lastBX1;
2150 py2 = lastBY1;
2151 private_rmauxComputeScaledSpinPoints(&px1, &py1, &px2, &py2, width, height);
2152
2153 px1 = pixeltovp(px1, width);
2154 py1 = -1.0F * pixeltovp(py1, height);
2155 px2 = pixeltovp(px2, width);
2156 py2 = -1.0F * pixeltovp(py2, height);
2157
2158 rmauxArcBall(&px1, &py1, &px2, &py2, &spinMatrix);
2159 }
2160 }
2161 }
2162
2163 /* foil compiler warning */
2164 xbutton = ybutton = 0;
2165
2166 return(1);
2167 }
2168
2169
2170 /* PRIVATE (rmauxUI)
2171 *
2172 * rmauxB2MotionFunc is called from rmauxEventLoop when a motion
2173 * event is detected while button2 is held down. rmauxUI assigns
2174 * rmauxB2MotionFunc to be the action handler for button2+motion.
2175 *
2176 * RM_BUTTON2: Arcball rotation
2177 *
2178 * applications may override this by calling rmauxSetButtonMotionFunc().
2179 * since this routine is intended to be called only from within
2180 * rmauxEventLoop, it is not publicly documented.
2181 */
2182 int
RMAUX_BUTTON_FUNC_PARMS()2183 rmauxB2MotionFunc RMAUX_BUTTON_FUNC_PARMS()
2184 {
2185 int width, height;
2186 float x2, y2;
2187 RMmatrix resultMatrix;
2188
2189 /* printf(" x,y at motion %d, %d \n", xbutton, ybutton); */
2190
2191 /* get current NDC cursor position */
2192 rmPipeGetWindowSize(p, &width, &height);
2193
2194 lastBX2 = lastBX1;
2195 lastBY2 = lastBY1;
2196
2197 lastBY1 = (float)ybutton;
2198 y2 = -1.0F * pixeltovp(ybutton, height);
2199
2200 lastBX1 = (float)xbutton;
2201 x2 = pixeltovp(xbutton, width);
2202
2203 /* do specified Arcball rotation */
2204 rmauxArcBall(&x, &y, &x2, &y2, &resultMatrix);
2205 rmMatrixMultiply(&ui_pose, &resultMatrix, &resultMatrix);
2206 rmNodeSetRotateMatrix(geomTransformTarget, &resultMatrix);
2207
2208 /* redraw the frame */
2209 rmauxInvokeRenderFunc(p, private_rmauxGetCurrentSceneGraph());
2210
2211 return(1);
2212 }
2213
2214
2215 /* PRIVATE (rmauxUI)
2216 *
2217 * rmauxB3DownFunc is called from rmauxEventLoop when a
2218 * button3 down event is detected. rmauxUI assigns rmauxB3DownFunc
2219 * to be the action handler for button3 down.
2220 *
2221 * RM_BUTTON3: camera dolly translation
2222 *
2223 * applications may override this by calling rmauxSetButtonMotionFunc().
2224 * since this routine is intended to be called only from within
2225 * rmauxEventLoop, it is not publicly documented.
2226 */
2227 int
RMAUX_BUTTON_FUNC_PARMS()2228 rmauxB3DownFunc RMAUX_BUTTON_FUNC_PARMS()
2229 {
2230 int width, height;
2231
2232 #ifdef RM_X
2233 XDefineCursor(rmxPipeGetDisplay(p), rmPipeGetWindow(p), dolly_cursor);
2234 #endif
2235 /* save the starting NDC cursor position */
2236 rmPipeGetWindowSize(p, &width, &height);
2237 x = pixeltovp(xbutton, width);
2238 y = -1.0F * pixeltovp(ybutton, height);
2239
2240 return(1);
2241 }
2242
2243
2244 /* PRIVATE (rmauxUI)
2245 *
2246 * rmauxB3UpFunc is called from rmauxEventLoop when a button3 up
2247 * event is detected. rmauxUI assigns rmauxB1UpFunc
2248 * to be the action handler for button3 up.
2249 *
2250 * RM_BUTTON3: camera dolly translation
2251 *
2252 * applications may override this by calling rmauxSetButtonMotionFunc().
2253 * since this routine is intended to be called only from within
2254 * rmauxEventLoop, it is not publicly documented.
2255 */
2256 int
RMAUX_BUTTON_FUNC_PARMS()2257 rmauxB3UpFunc RMAUX_BUTTON_FUNC_PARMS()
2258 {
2259 #ifdef RM_X
2260 XUndefineCursor(rmxPipeGetDisplay(p), rmPipeGetWindow(p));
2261 #endif
2262
2263 /* foil compiler warning */
2264 xbutton = ybutton = 0;
2265
2266 return(1);
2267 }
2268
2269
2270 /* PRIVATE (rmauxUI)
2271 *
2272 * rmauxB3MotionFunc is called from rmauxEventLoop when a motion
2273 * event is detected while button3 is held down. rmauxUI assigns
2274 * rmauxB3MotionFunc to be the action handler for button3+motion.
2275 *
2276 * RM_BUTTON3: camera dolly translation
2277 *
2278 * applications may override this by calling rmauxSetButtonMotionFunc().
2279 * since this routine is intended to be called only from within
2280 * rmauxEventLoop, it is not publicly documented.
2281 */
2282 int
RMAUX_BUTTON_FUNC_PARMS()2283 rmauxB3MotionFunc RMAUX_BUTTON_FUNC_PARMS()
2284 {
2285 int width, height;
2286 float x2, y2;
2287 RMcamera3D *c=NULL;
2288
2289 /* get current NDC cursor position */
2290 rmPipeGetWindowSize(p, &width, &height);
2291 x2 = pixeltovp(xbutton, width);
2292 y2 = -1.0F * pixeltovp(ybutton, height);
2293
2294 /* do specified dolly translation */
2295 if (rmNodeGetSceneCamera3D(camera3DTransformTarget,&c) != RM_WHACKED)
2296 {
2297 rmauxDolly(c, &x, &y, &x2, &y2);
2298 rmNodeSetSceneCamera3D(camera3DTransformTarget,c);
2299 rmCamera3DDelete(c);
2300 }
2301 x = x2;
2302 y = y2;
2303
2304 /* redraw the frame */
2305 rmauxInvokeRenderFunc(p, private_rmauxGetCurrentSceneGraph());
2306
2307 return(1);
2308 }
2309
2310 int
RMAUX_BUTTON_FUNC_PARMS()2311 rmauxShiftB2DownFunc RMAUX_BUTTON_FUNC_PARMS()
2312 {
2313 int w,h;
2314 #ifdef RM_X
2315 XDefineCursor(rmxPipeGetDisplay(p),
2316 rmPipeGetWindow(p),scale_cursor);
2317 #endif
2318
2319 rmPipeGetWindowSize(p,&w,&h);
2320 xscale_delta = 1.0F/(float)(w<<1);
2321 yscale_delta = 1.0F/(float)(h<<1);
2322 x = (float)xbutton;
2323 y = (float)ybutton;
2324 if (rmNodeGetScaleMatrix(geomTransformTarget,&saveScaleMatrix) == RM_WHACKED)
2325 rmMatrixIdentity(&saveScaleMatrix);
2326
2327 (*renderfunc)(p, private_rmauxGetCurrentSceneGraph());
2328
2329 return(1);
2330 }
2331
2332 /*
2333 * rmauxShiftB2MotionFunc is called from rmauxEventLoop when a motion
2334 * event is detected while button2 and the shift key are depressed.
2335 * rmauxUI assigns rmauxB2UpFunc
2336 * to be the action handler for shift+button2+motion. applications may
2337 * override this by calling rmauxSetButtonDownFunc().
2338 *
2339 * since this routine is intended to be called only from within
2340 * rmauxEventLoop, it is not publicly documented.
2341 */
2342 int
RMAUX_BUTTON_FUNC_PARMS()2343 rmauxShiftB2MotionFunc RMAUX_BUTTON_FUNC_PARMS()
2344 {
2345 RMmatrix m;
2346 float xnew;
2347
2348 rmMatrixIdentity(&m);
2349
2350 xnew = (float)(xbutton) - x;
2351 xnew *= xscale_delta;
2352 m.m[0][0] = m.m[1][1] = m.m[2][2] = 1.0F + xnew;
2353 rmMatrixMultiply(&saveScaleMatrix,&m,&m);
2354 rmNodeSetScaleMatrix(geomTransformTarget,&m);
2355
2356 /* rmFrame(); */
2357 (*renderfunc)(p, private_rmauxGetCurrentSceneGraph());
2358
2359 /* fprintf(stderr," scaling \n"); */
2360
2361 /* foil compiler warning */
2362 ybutton = 0;
2363
2364 return(1);
2365 }
2366
2367 int
RMAUX_BUTTON_FUNC_PARMS()2368 rmauxShiftB2UpFunc RMAUX_BUTTON_FUNC_PARMS()
2369 {
2370 #ifdef RM_X
2371 XUndefineCursor(rmxPipeGetDisplay(p),
2372 rmPipeGetWindow(p));
2373 #endif
2374 /* foil compiler warning */
2375 xbutton = ybutton = 0;
2376 return(1);
2377 }
2378
2379 /* PRIVATE (rmauxEventLoop)
2380 *
2381 * convert from X11 style button enumerators to RM enumerators
2382 */
2383 int
private_rmauxButtonNumToIndex(int xbutton_num)2384 private_rmauxButtonNumToIndex (int xbutton_num)
2385 {
2386 int rstat = 0;
2387
2388 switch(xbutton_num)
2389 {
2390 case Button1:
2391 rstat = RM_BUTTON1;
2392 break;
2393
2394 case Button2:
2395 rstat = RM_BUTTON2;
2396 break;
2397
2398 case Button3:
2399 rstat = RM_BUTTON3;
2400 break;
2401
2402 case Button4:
2403 rstat = RM_BUTTON4;
2404 break;
2405
2406 case Button5:
2407 rstat = RM_BUTTON5;
2408 break;
2409 }
2410 return(rstat);
2411 }
2412
2413
2414 /* PRIVATE (rmauxEventLoop)
2415 *
2416 * return valid RM key modifier from X11 style button modifier state
2417 */
2418 int
private_rmauxModifierToIndex(int state)2419 private_rmauxModifierToIndex (int state)
2420 {
2421 int rstat = RM_NO_MODIFIER;
2422
2423 if (state & RM_SHIFT_MODMASK)
2424 rstat = RM_SHIFT_MODIFIER;
2425 else if (state & RM_CONTROL_MODMASK)
2426 rstat = RM_CONTROL_MODIFIER;
2427
2428 return(rstat);
2429 }
2430
2431 void
private_rmauxSetCurrentSceneGraph(RMnode * n)2432 private_rmauxSetCurrentSceneGraph(RMnode *n)
2433 {
2434 static_sceneGraphHandle = n;
2435 }
2436
2437 RMnode *
private_rmauxGetCurrentSceneGraph(void)2438 private_rmauxGetCurrentSceneGraph(void)
2439 {
2440 return(static_sceneGraphHandle);
2441 }
2442
2443 void
private_rmauxSetCameraResizeNode(RMnode * n)2444 private_rmauxSetCameraResizeNode(RMnode *n)
2445 {
2446 static_resizeCameraNode = n;
2447 }
2448
2449 RMnode *
private_rmauxGetCameraResizeNode(void)2450 private_rmauxGetCameraResizeNode(void)
2451 {
2452 return(static_resizeCameraNode);
2453 }
2454
2455 static void
private_rmauxDoSpinCallback(void)2456 private_rmauxDoSpinCallback(void)
2457 {
2458 RMmatrix m;
2459 rmNodeGetRotateMatrix(geomTransformTarget, &m);
2460 rmMatrixMultiply(&m, &spinMatrix, &m);
2461 rmNodeSetRotateMatrix(geomTransformTarget, &m);
2462 }
2463
2464 /*
2465 * ----------------------------------------------------
2466 * @Name rmauxSetSpinEnable
2467 @pstart
2468 void rmauxSetSpinEnable (RMenum spinEnableBoolean)
2469 @pend
2470
2471 @astart
2472
2473 RMenum spinEnableBoolean - may be either RM_TRUE or RM_FALSE. When set to
2474 RM_TRUE, "spin mode" will be enabled. When set to RM_FALSE, "spin mode"
2475 is disabled.
2476 @aend
2477
2478 @dstart
2479
2480 "Spin mode" refers to auto-rotation. With spin mode enabled, if the
2481 pointer is moving then you release RM_BUTTON2, then the RMnode "target"
2482 will be autorotated until such a time as you again press RM_BUTTON2.
2483 The direction and velocity of rotation is a function of how quickly
2484 the pointer is moving when you release RM_BUTTON2. Internally,
2485 spin mode is implemented by using an idle callback, so auto-spin will
2486 occur only when there are no events to process. The idle callback used
2487 to implement auto-rotation is independent of rmauxSetIdleFunc(), so
2488 you may have an idle function and auto-spin will still be operational.
2489
2490 Auto-spins are applied to the transformation target set with either
2491 rmauxSetGeomTransform() or rmauxUI(). You may enable auto-spin without
2492 assigning a transformation target, but no auto-spin will occur unless
2493 you have established a transformation target.
2494
2495 @dend
2496 * ----------------------------------------------------
2497 */
2498 void
rmauxSetSpinEnable(RMenum spinEnableBool)2499 rmauxSetSpinEnable (RMenum spinEnableBool)
2500 {
2501 if ((spinEnableBool != RM_TRUE) && (spinEnableBool != RM_FALSE))
2502 {
2503 rmWarning("rmauxSetSpinEnable() error: the input spinEnableBool parameter must be either RM_TRUE or RM_FALSE.");
2504 return;
2505 }
2506
2507 if ((spinEnableBool == RM_TRUE) && (geomTransformTarget == NULL))
2508 rmWarning("rmauxSetSpinEnable() warning: you are enabling auto-spins when no transformation target has been established. While this is not an error, no auto-spin will occur unless you establish such a target with either rmauxSetGeomTransform() or rmauxUI(). \n");
2509
2510 spinModeEnabled = spinEnableBool;
2511 }
2512
2513 /*
2514 * ----------------------------------------------------
2515 * @Name rmauxGetSpinEnable
2516 @pstart
2517 RMenum rmauxGetSpinEnable (void)
2518 @pend
2519
2520 @astart
2521
2522 @aend
2523
2524 @dstart
2525
2526 Returns either RM_TRUE or RM_FALSE, reflecting the current state
2527 of whether or not "auto spin" is enabled. See the description of
2528 rmauxSetSpinEnable for more details about auto-spin mode.
2529
2530 @dend
2531 * ----------------------------------------------------
2532 */
2533 RMenum
rmauxGetSpinEnable(void)2534 rmauxGetSpinEnable (void)
2535 {
2536 return spinModeEnabled;
2537 }
2538 /* EOF */
2539