OpenRM - RMAUX Library (rmbfuncs.c)

## Index of OpenRM - RMAUX Library

     void rmauxEventLoop (RMpipe *currentPipe,
                          RMnode *subTreeToDraw,
                          void *vmsg)

     RMpipe *currentPipe - (input) a handle to an RMpipe object. The
        RMpipe must be fully configured (init'ed, and has a valid opened
        window assigned, and been the victim of rmPipeMakeCurrent()) prior
        to invoking the event handler.

     RMnode *subTreeToDraw - (input) a handle to an RMnode. This node is
        considered to be the root of a subtree that will be rendered onto
        "currentPipe" whenever a frame is to be rendered.

     void *vmsg - X11 users - specify NULL for this parameter.  Win32
        users: all WinMain procedures must return (msg.wParam) to Windows
        so it can gracefully exit. Pass a handle to a MSG object in to
        rmauxEventLoop (please refer to the demo programs for sample
        code. (output, return)

This is the main rmaux event handler loop for both Win32 and X11. In the source code, there are actually two different routines that are conditionally compiled, since Win32 and X11 are so different. However, from the outside, they exhibit (mostly) similar behavior.

Events are processed until some action handler returns a zero status. On X11, any keyboard press other than a modifier key will cause a zero status (exit the event loop). On Win32, we pretty much ignore the keyboard at this time, except for the modifier keys, so the only way to terminate Win32 programs that use rmauxEventLoop is to click a mouse button over the little "X" on the upper right part of the window's title bar.

A new frame will be rendered when an Expose (X11) or WM_PAINT (Win32) event is encountered. Additionally, rmauxUI() defines that frames will be rendered when other types of input events are encountered. The RMnode * parameter subTreeToDraw defines the root of the scene graph that will be rendered during all frame renderings within the rmaux* family of routines. Note the distinction between the scene graph root (subTreeToDraw) and the RMnode handle used for interactive transformations, which is set with rmauxUI(). The RMnode handles to each of these routines may point to different RMnodes.

librmaux library source file: rmbfuncs.c

     void rmauxSetGeomTransform (RMnode *target,
    	                     RMpipe *usePipe)

     RMnode *target - a handle to an RMnode. (input) All model
        transformations will be applied to this node, and will affect all
        children nodes.

     RMpipe *usePipe - a handle to an RMpipe. (input) This is is the
        currently active GL context and is used to get cursors for X11.

rmauxSetGeomTransform assigns a default set of action handlers that will be executed when rmauxEventLoop is invoked to begin processing of events. The action handlers installed by rmauxSetGeomTransform will modify the transformation matrices at the RMnode "subTree" to produce either rotations (button2 + motion) or isometric scaling (shift+button2+motion).

NOTE: (8/27/2000) rmauxSetGeomTransform is identical to rmauxUI(). A new routine, rmauxSetCamera3DTransform, has been added to OpenRM and may be used to manipulate 3d camera parameters to achieve image plane translation, as well as camera dollying along the Z axis in eye-coordinates.

rmauxSetGeomTransform maps RM_BUTTON2 to an arcball-style rotation, and SHIFT+RM_BUTTON2 to isometric scaling. Pressing the RM_BUTTON* on the mouse will initiate the transformation. Dragging the mouse while holding the RM_BUTTON* down will cause a frame to be rendered for each transformation (see Note below), then when the RM_BUTTON* is released, the appearance of interactive transformation stops and the system becomes quiescient.

Pressing any key on the keyboard other than a modifier key will cause the event loop to latch the pressed key. Once the key is released, a non-NULL user callback function for handling keypresses is called. This user key callback is set with rmauxEventLoop(). In the event no keypress callback is assigned with rmauxEventLoop, the event loop will exit if any non-modifier key is pressed (X11 only, Win32 code incomplete at this time 8/27/2000).

Applications developers may assign their own callbacks to the rmaux action handler using rmauxButtonDownFunc, rmauxButtonMotionFunc and rmauxButtonUpFunc (as well as rmauxSetIdleFunc). rmauxUI just assigns a default set of action handlers to a small, specific set of button events.

Note: none of the rmaux routines are needed to use the rest of OpenRM. Your application may use it's own event loop, and you may safely ignore all of rmaux if that's what you need.

Assumptions:

1. Whenever a frame needs to be drawn, the routine specified by rmauxSetRenderFunc is invoked. By default, that function is just rmFrame(). rmFrame() draws everything starting at the scene graph node rmRootNode().

2. X11 notes: rmauxUI creates cursors for each operation. These cursors are valid only on the XDisplay of the currently active RMpipe. Be sure to call rmPipeMakeCurrent prior to calling rmauxUI. At this time (1/15/2000) this restriction does not apply to Win32 codes.

librmaux library source file: rmbfuncs.c

     void rmauxSetCamera3DTransform (RMnode *target,
    	                         RMpipe *usePipe)

     RMnode *target - a handle to an RMnode. (input) All transformations
        will be applied to the RMcamera3D scene parameter at target, if
        such a scene parameter exists.

     RMpipe *usePipe - a handle to an RMpipe. (input) This is is the
        currently active GL context and is used to get cursors for X11.

rmauxSetCamera3DTransform assigns a default set of action handlers that will be executed when rmauxEventLoop is invoked to begin processing of events. The action handlers installed by rmauxSetCamera3DTransform will modify eye and look-at attributes of the RMcamera3D scene parameter assigned at the input RMnode "target" to achieve image plane translation, or dollying along the Z axis of eye coordinates.

rmauxSetCamera3DTransform maps RM_BUTTON1 to image plane translation, and RM_BUTTON3 to camera dolly translation. Pressing the associated RM_BUTTON* initiates the transformation. Dragging the mouse while holding the RM_BUTTON* down will cause a frame to be rendered for each transformation (see Note below), then when the RM_BUTTON* is released, the appearance of interactive transformation stops and the system becomes quiescient.

Pressing any key on the keyboard other than a modifier key will cause the event loop to latch the pressed key. Once the key is released, a non-NULL user callback function for handling keypresses is called. This user key callback is set with rmauxEventLoop(). In the event no keypress callback is assigned with rmauxEventLoop, the event loop will exit if any non-modifier key is pressed (X11 only, Win32 code incomplete at this time 8/27/2000).

Applications developers may assign their own callbacks to the rmaux action handler using rmauxButtonDownFunc, rmauxButtonMotionFunc and rmauxButtonUpFunc (as well as rmauxSetIdleFunc). rmauxUI just assigns a default set of action handlers to a small, specific set of button events.

Note: none of the rmaux routines are needed to use the rest of OpenRM. Your application may use it's own event loop, and you may safely ignore all of rmaux if that's what you need.

Assumptions:

1. Whenever a frame needs to be drawn, the routine specified by rmauxSetRenderFunc is invoked. By default, that function is just rmFrame(). rmFrame() draws everything starting at the scene graph node rmRootNode().

2. X11 notes: rmauxUI creates cursors for each operation. These cursors are valid only on the XDisplay of the currently active RMpipe. Be sure to call rmPipeMakeCurrent prior to calling rmauxUI. At this time (1/15/2000) this restriction does not apply to Win32 codes.

librmaux library source file: rmbfuncs.c

     void rmauxUI (RMnode *target,
    	       RMpipe *usePipe)

     RMnode *target - a handle to an RMnode. (input) All model
        transformations will be applied to this node, and will affect all
        children nodes.

     RMpipe *usePipe - a handle to an RMpipe. (input) This is is the
        currently active GL context and is used to get cursors for X11.

rmauxUI assigns a default set of action handlers that will be executed when rmauxEventLoop is invoked to begin processing of events. There are three types of transformations implemented by rmauxUI: a virtual arcball interface to specify rotations, a camera dolly translation, and an image plane translation.

rmauxUI maps RM_BUTTON2 to an arcball-style rotation, and SHIFT+RM_BUTTON2 to isometric scaling. Pressing the RM_BUTTON* on the mouse will initiate the transformation. Dragging the mouse while holding the RM_BUTTON* down will cause a frame to be rendered for each transformation (see Note below), then when the RM_BUTTON* is released, the appearance of interactive transformation stops and the system becomes quiescient.

Pressing any key on the keyboard other than a modifier key will cause the event loop to latch the pressed key. Once the key is released, a non-NULL user callback function for handling keypresses is called. This user key callback is set with rmauxEventLoop().

Resizing the window bound to the RMpipe will call a non-NULL user callback function for handling window resizing. This user resize callback is set with rmauxEventLoop().

Applications developers may assign their own callbacks to the rmaux action handler using rmauxButtonDownFunc, rmauxButtonMotionFunc and rmauxButtonUpFunc (as well as rmauxSetIdleFunc). rmauxUI just assigns a default set of action handlers to a small, specific set of button events.

Note: none of the rmaux routines are needed to use the rest of OpenRM. Your application may use it's own event loop, and you may safely ignore all of rmaux if that's what you need.

Assumptions:

1. Whenever a frame needs to be drawn, the routine specified by rmauxSetRenderFunc is invoked. By default, that function is just rmFrame(). rmFrame() draws everything starting at the scene graph node rmRootNode().

2. X11 notes: rmauxUI creates cursors for each operation. These cursors are valid only on the XDisplay of the currently active RMpipe. Be sure to call rmPipeMakeCurrent prior to calling rmauxUI. At this time (1/15/2000) this restriction does not apply to Win32 codes.

librmaux library source file: rmbfuncs.c

     rmauxSetInitFunc (void (*userinitfunc)(RMpipe *drawOn, RMnode *subTree))

     void (*userinitfunc)(RMpipe *drawOnPipe, RMnode *subtree) - a handle to a caller-supplied
        initialization function.

Use this routine to register your application's "init" function with RMaux. This initialization function will be called from within rmauxEventLoop after all OpenGL and window system initialization had been complete, and it is safe to begin using all of OpenRM.

librmaux library source file: rmbfuncs.c

     void rmauxSetIdleFunc (RMpipe *p,
                            int (*userfunc)(RMpipe *currentPipe, int pointerX, int pointerY))

     RMpipe *p - a handle to an active RMpipe object.

     int (*userfunc)(RMpipe *currentPipe, int pointerX, int pointerY) - a
        handle to an application function that will be called when the
        system is idle. The routine will be passed the current (x,y) pixel
        location of the pointer, along with a handle to the controlling
        RMpipe. When the app idle callback returns a zero, event loop
        processing is terminated; when a non-zero value is returned,
        processing continues.

Use this routine to register an application function that will be called (X11) when there are no other events in the event queue or (Win32) a timer with a 20msec interval "alarm" has expired.

Win32 Notes: we need the RMpipe pointer so that we can obtain the window handle for the purpose of attaching a "timer" function to a window. because the timer goes off at a specified interval (in the absence of other messages to process), it's not really an "idle" function except in the sense that the app function is called 20msec after a period of idleness is detected.

X: it really is an idle function. note that we detect idleness inside the event loop attached to a window, and don't need the RMpipe structure. it is included here so that one API can be used for both Win32 and X.

The value returned by the application idle callback has an effect upon event loop processing: when the app callback returns a zero, event loop processing is terminated. When a non-zero value is returned, event loop processing continues.

librmaux library source file: rmbfuncs.c

     void rmauxSetKeyFunc (int (*userfunc)(RMpipe *p, char k, KeySym code))

     int (*userfunc)(RMpipe *p, char k, KeySym code) - a pointer to a user function
        (input).

Use rmauxSetKeyFunc to assign a keypress handler that will be invoked by rmauxEventLoop whenever a non-modifier keypress is detected. The userFunc will be provided the keyboard key that was pressed, the current RMpipe, and a KeySym code. Unlike mouse event mappings, where a different callback is invoked depending upon motion, button up or down events, a single key handler is used to perform processing of all keyboard events. Application-supplied key handler callbacks must contain sufficient internal logic to detect which key was pressed, and take appropriate action.

The userFunc should return RM_CHILL to rmauxEventLoop if event processing is to continue, or return RM_WHACKED if event loop processing should continue.

The RM demo programs typically assign the default key handler rmauxDefaultKeyFunc, which will terminate event loop processing whenever the user presses the "q" key on the keyboard.

Notes:

4/20/02 - this routine was updated to unify keypress handling on both X11 and Win32 platforms. The same API is used in both places, but the KeySym type is artificially defined on Win32 in order to coerce API consistency across platforms. Presently, the KeySym "code" parameter is not used on Win32. Only printable ASCII chars will trigger a call to the user-defined key-handling function on Win32; refer to your Win32 developer documentation to learn more about which keys actually trigger an WM_CHAR event, which in turn initiates a call to the user-supplied key-handling callback.

librmaux library source file: rmbfuncs.c

     int rmauxDefaultKeyFunc (RMpipe *currentPipe,
                              char    key,
    			  KeySym  code)

     RMpipe *currentPipe - a handle to the current pipe (input)
     char key - key from most recent key press (input)
     KeySym code (input) - an X11 KeySym code.

This simple key callback function intercepts "Q/q" key presses and then signals to quit application.

4/20/02 - this routine was updated to unify keypress handling on both X11 and Win32 platforms. The same API is used in both places, but the KeySym type is artificially defined on Win32 in order to coerce API consistency across platforms. Presently, the KeySym "code" parameter is not used on Win32. Only printable ASCII chars will trigger a call to the user-defined key-handling function on Win32; refer to your Win32 developer documentation to learn more about which keys actually trigger an WM_CHAR event, which in turn initiates a call to the user-supplied key-handling callback.

3/27/04 - the input parameter "code" is ignored by this routine. The parameter is present to facilitate API consistency between user-supplied key handler callbacks and this RMaux default key handler.

librmaux library source file: rmbfuncs.c

     void rmauxSetResizeFunc (RMpipe *p,
                              RMnode *cameraNode,
    			  RMenum (*userfunc)(RMpipe *p, RMnode *n, int winWidth, int winHeight))

     RMpipe *p - an RMpipe object (input).

     RMnode *cameraNode - a handle to an RMnode, which should contain either
        an RMcamera2D or RMcamera3D scene parameter (input, but modified at
        runtime when a window resize event occurs).

     void (*userfunc)(RMpipe *p, RMnode *n, int winWidth, int winHeight) - a pointer to a user function (input).

The rmaux*UI()/rmauxEventLoop routines will catch all resize events to the application window. The user may inmplement a routine to handle window resizing and specify it here.

The default resize function routine used by rmauxSetResizeFunc() adjusts camera parameters according to the resized window geometry.

See rmauxDefaultResizeFunc() for more details about the parameters to the resize callback function.

librmaux library source file: rmbfuncs.c

     int rmauxDefaultResizeFunc (RMpipe *currentPipe,
                                 RMnode *cameraNode,
    			     int     winWidth,
    			     int     winHeight)

     RMpipe *currentPipe - a handle to the current pipe

     RMnode *cameraNode - a handle to a scene graph node containing either
        an RMcamera2D or RMcamera3D scene parameter.

     int winWidth, winHeight - two integers specifying the new window
        size in pixels. These values are provided by rmauxEventLoop to
        the resize callback (input).

This simple resize callback function will adjust the aspect ratio of the 2D or 3D camera scene parameter contained in "cameraNode" to reflect the ratio of width to height dimensions of the resized window.

If the target node "cameraNode" does not contain either a RMcamera2D or RMcamera3D scene parameter, this routine will issue a warning message.

This routine always returns RM_CHILL, regardless of errors.

librmaux library source file: rmbfuncs.c

     void rmauxSetRenderFunc (void (*userfunc)(RMpipe *currentPipe))

     void (*userfunc)(RMpipe *currentPipe) - a pointer to a user function
        (input).

The rmaux*UI()/rmauxEventLoop routines will occasionally have the need to render an image. For the trackball interface, rendering is needed whenever the mouse button is pressed and dragged. The rmauxEventLoop event handler allows applications to set a routine that is called whenever rendering is needed.

The default rendering routine used by rmauxSetRenderFunc() calls the generic rendering routine rmFrame().

librmaux library source file: rmbfuncs.c

     void rmauxSetButtonDownFunc (unsigned int whichbutton,
    		              unsigned int modmask,
    		              int (*userfunc) (RMpipe *currentPipe, int pointerX, int pointerY))

     unsigned int whichbutton - An integer value specifying which button
        will be assigned an action handler. Valid values are RM_BUTTON1,
        RM_BUTTON2, RM_BUTTON3, RM_BUTTON4 or RM_BUTTON5.

     unsigned int modmask - An integer value specifying a modifier mask
        that can be used to qualify buttons. Valid values are
        RM_NONE_MODMASK, RM_SHIFT_MODMASK or RM_CONTROL_MODMASK.

     int (*userfunc) (RMpipe *currentPipe, int xPointerPosition, int
        yPointerPosition) - the function that will be invoked when the
        named button is pressed and modifier mask conditions are met. The
        user function will be passed integer values representing the (x,y)
        pixel coordinate of the pointer, along with a handle to the
        current/calling RMpipe.

Applications may use this routine to define action handlers that will be invoked from inside of rmauxEventLoop(). This routine is one of three used to assign an application callback that will be invoked when a button is pressed. One of two modifier keys may also be specified, the shift key or control key, to be used in conjunction with a button.

This routine, rmauxSetButtonDownFunc, is used to assign a callback to correspond to button down events.

The return value from the application callback is significant. A return value of zero will cause the event loop to terminate. A value of 1 cause the event loop to continue processing events (strictly speaking, any non-zero value will keep the event loop going).

librmaux library source file: rmbfuncs.c

     void rmauxSetButtonUpFunc (unsigned int whichbutton,
    		            unsigned int modmask,
    		            int (*userfunc) (RMpipe *currentPipe, int pointerX, int pointerY))

     unsigned int whichbutton - An integer value specifying which button
        will be assigned an action handler. Valid values are RM_BUTTON1,
        RM_BUTTON2, RM_BUTTON3, RM_BUTTON4 or RM_BUTTON5.

     unsigned int modmask - An integer value specifying a modifier mask
        that can be used to qualify buttons. Valid values are
        RM_NONE_MODMASK, RM_SHIFT_MODMASK or RM_CONTROL_MODMASK.

     int (*userfunc) (RMpipe *currentPipe, int xPointerPosition, int
        yPointerPosition) - the function that will be invoked when the
        named button is released, and modifier mask conditions are
        met. The user function will be passed integer values representing
        the (x,y) pixel coordinate of the pointer, along with a handle to
        the current/calling RMpipe.

Applications may use this routine to define action handlers that will be invoked from inside of rmauxEventLoop(). This routine is one of three used to assign an application callback that will be invoked when a button release event is detected, and while modifier conditions are met. One of two modifier keys may also be specified, the shift key or control key, to be used in conjunction with a button.

This routine, rmauxSetButtonUpFunc, is used to assign a callback to correspond to button button release events, possibly with a modifier key present.

The return value from the application callback is significant. A return value of zero will cause the event loop to terminate. A value of 1 cause the event loop to continue processing events (strictly speaking, any non-zero value will keep the event loop going).

librmaux library source file: rmbfuncs.c

     void rmauxSetButtonMotionFunc (unsigned int whichbutton,
    		                unsigned int modmask,
    		                int (*userfunc) (RMpipe *currentPipe, int pointerX, int pointerY))

     unsigned int whichbutton - An integer value specifying which button
        will be assigned an action handler. Valid values are RM_BUTTON1,
        RM_BUTTON2, RM_BUTTON3, RM_BUTTON4 or RM_BUTTON5.

     unsigned int modmask - An integer value specifying a modifier mask
        that can be used to qualify buttons. Valid values are
        RM_NONE_MODMASK, RM_SHIFT_MODMASK or RM_CONTROL_MODMASK.

     int (*userfunc) (RMpipe *currentPipe, int xPointerPosition, int
        yPointerPosition) - the function that will be invoked when the
        named button is depressed, the the pointer is moving, and modifier
        mask conditions are met. The user function will be passed integer
        values representing the (x,y) pixel coordinate of the pointer,
        along with a handle to the current/calling RMpipe.

Applications may use this routine to define action handlers that will be invoked from inside of rmauxEventLoop(). This routine is one of three used to assign an application callback that will be invoked when a motion event is detected, while a button is pressed and while modifier conditions are met. One of two modifier keys may also be specified, the shift key or control key, to be used in conjunction with a button.

This routine, rmauxSetButtonMotionFunc, is used to assign a callback to correspond to motion events while a button, and possibly a modifer key are depressed.

The return value from the application callback is significant. A return value of zero will cause the event loop to terminate. A value of 1 cause the event loop to continue processing events (strictly speaking, any non-zero value will keep the event loop going).

librmaux library source file: rmbfuncs.c

     void rmauxSetSpinEnable (RMenum spinEnableBoolean)

     RMenum spinEnableBoolean - may be either RM_TRUE or RM_FALSE. When set to
        RM_TRUE, "spin mode" will be enabled. When set to RM_FALSE, "spin mode"
        is disabled.

"Spin mode" refers to auto-rotation. With spin mode enabled, if the pointer is moving then you release RM_BUTTON2, then the RMnode "target" will be autorotated until such a time as you again press RM_BUTTON2. The direction and velocity of rotation is a function of how quickly the pointer is moving when you release RM_BUTTON2. Internally, spin mode is implemented by using an idle callback, so auto-spin will occur only when there are no events to process. The idle callback used to implement auto-rotation is independent of rmauxSetIdleFunc(), so you may have an idle function and auto-spin will still be operational.

Auto-spins are applied to the transformation target set with either rmauxSetGeomTransform() or rmauxUI(). You may enable auto-spin without assigning a transformation target, but no auto-spin will occur unless you have established a transformation target.

librmaux library source file: rmbfuncs.c

     RMenum rmauxGetSpinEnable (void)

Returns either RM_TRUE or RM_FALSE, reflecting the current state of whether or not "auto spin" is enabled. See the description of rmauxSetSpinEnable for more details about auto-spin mode.

librmaux library source file: rmbfuncs.c