/***********************************************************************/ /* Open Visualization Data Explorer */ /* (C) Copyright IBM Corp. 1989,1999 */ /* ALL RIGHTS RESERVED */ /* This code licensed under the */ /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */ /***********************************************************************/ #include #ifndef lint static char rcsid[] = "$Header: /home/gda/dxcvs/dx/src/exec/hwrender/hwInteractor.c,v 1.3 1999/05/10 15:45:34 gda Exp $" ; #endif /*---------------------------------------------------------------------------*\ $Source: /home/gda/dxcvs/dx/src/exec/hwrender/hwInteractor.c,v $ This file contains core utilities for managing direct interactors. \*---------------------------------------------------------------------------*/ #include #include "hwDeclarations.h" #ifndef STANDALONE #include "hwMemory.h" #endif #include "hwDebug.h" /* * Allocation utils */ static tdmInteractor _allocateInteractorArray (tdmInteractorWin W) ; static tdmInteractor _allocateMoreInteractors (tdmInteractorWin W) ; /* interactor storage is allocated in multiples of ARRAYSIZE */ #define ARRAYSIZE 16 /* pointer to array of `ARRAYSIZE' interactors */ typedef tdmInteractorT (*InteractorArray)[ARRAYSIZE] ; tdmInteractorWin _dxfInitInteractors (void *portHandle, void *stack) { tdmInteractorWin W ; ENTRY(("_dxfInitInteractors(0x%x, 0x%x)", portHandle, stack)); /* allocate interactor common data associated with image window */ if (! (W = (tdmInteractorWin) tdmAllocateLocal (sizeof(tdmInteractorWinT)))) { /* !!!!! No warning message set???? */ EXIT(("ERROR:out of memory")); return (tdmInteractorWin) 0 ; } W->Interactors = (tdmInteractor *) 0 ; W->extents = (void *) 0 ; W->numUsed = 0 ; W->numAllocated = 0 ; /* initialize camera stack */ W->Cam = (tdmInteractorCam) 0 ; W->redo = (tdmInteractorCam) 0 ; _dxfPushInteractorCamera(W) ; W->Cam->view_state++ ; W->Cam->cursor_speed = tdmMEDIUM_CURSOR ; /* copy handles to graphics API context and software transformation stack */ W->Cam->phP = portHandle ; W->Cam->stack = stack ; EXIT(("W = 0x%x", W)); return W ; } void _dxfDestroyAllInteractors (tdmInteractorWin W) { int i ; tdmInteractorCam curr, next ; ENTRY(("_dxfDestroyAllInteractors(0x%x)", W)); if (! W) { EXIT(("ERROR: bad window")); return ; } /* destroy all used interactors */ if (W->Interactors) { for (i = 0 ; i < W->numAllocated ; i++) if (IS_USED(W->Interactors[i])) /* * Invoke the interactor's destroy method. It must call * _dxfDeallocateInteractor() itself at some point. */ tdmDestroyInteractor(W->Interactors[i]) ; tdmFree((void *) W->Interactors) ; W->Interactors = (tdmInteractor *) 0 ; } /* destroy all allocated interactor data */ if (W->extents) { InteractorArray *array = (InteractorArray *) W->extents ; int numInteractorArrays = W->numAllocated / ARRAYSIZE ; for (i = 0 ; i < numInteractorArrays ; i++) { tdmFree((void *) array[i]) ; array[i] = (InteractorArray) 0 ; } tdmFree(W->extents) ; W->extents = (void *) 0 ; } /* destroy all camera info on undo and redo stacks */ curr = W->Cam ; W->Cam = (tdmInteractorCam) 0 ; while (curr) { next = curr->next ; curr->next = (tdmInteractorCam) 0 ; tdmFree ((void *) curr) ; if (next) curr = next ; else { curr = W->redo ; W->redo = (tdmInteractorCam) 0 ; } } tdmFree((void *) W) ; EXIT(("")); } tdmInteractor _dxfAllocateInteractor (tdmInteractorWin W, int size) { int i ; tdmInteractor I = (tdmInteractor) 0 ; ENTRY(("_dxfAllocateInteractor(0x%x, %d)", W, size)); if (! W) goto error ; if (W->numUsed == W->numAllocated) /* create more interactors */ I = _allocateMoreInteractors(W) ; else /* find an unused interactor */ for (i = 0 ; i < W->numAllocated ; i++) if (! IS_USED(W->Interactors[i])) { I = W->Interactors[i] ; break ; } if (! I) goto error ; if (size) /* allocate interactor private data */ if (! (PRIVATE(I) = tdmAllocateLocal(size))) goto error ; else bzero ((char *) PRIVATE(I), size) ; WINDOW(I) = W ; AUX(I) = (tdmInteractor) 0 ; IS_AUX(I) = 0 ; IS_GROUP(I) = 0 ; IS_USED(I) = 1 ; W->numUsed++ ; /* * Default event mask */ I->eventMask = DXEVENT_LEFT | DXEVENT_MIDDLE | DXEVENT_RIGHT; EXIT(("I = 0x%x", I)); return I ; error: EXIT(("ERROR")); return (tdmInteractor) 0 ; } void _dxfDeallocateInteractor (tdmInteractor interactor) { tdmInteractorWin W ; ENTRY(("_dxfDeallocateInteractor(0x%x)", interactor)); if (! interactor || ! (W = WINDOW(interactor))) { EXIT(("ERROR")); return ; } if (PRIVATE(interactor)) tdmFree((void *) PRIVATE(interactor)) ; bzero ((char *) interactor, sizeof(tdmInteractorT)) ; IS_USED(interactor) = 0 ; W->numUsed-- ; EXIT(("")); } /* * Here is a picture of some of the lower level details implemented below. * Boxes represent contiguous arrays. A downward arrow is a pointer to * the first element of a contiguous array. Left arrows are pointers to * interactor objects. * * W.extents W.Interactors * | | * v | * +---------------+ | * |InteractorArray|------------------------. | * |InteractorArray|-------------. | | * | . | | v v * | . | | +----------+ +---+ * |InteractorArray|--. | |interactor|<--|ptr| -+ * +---------------+ | | |interactor|<--|ptr| | * | | | . |<--| . | ARRAYSIZE * | | | . |<--| . | | * | v |interactor|<--|ptr| -+ * | +----------+----------+ | | * | |interactor|<-------------|ptr| -+ * | |interactor|<-------------|ptr| | * | | . |<-------------| . | ARRAYSIZE * | | . |<-------------| . | | * v |interactor|<-------------|ptr| -+ * +----------+----------+ | | * |interactor|<------------------------|ptr| -+ * |interactor|<------------------------|ptr| | * | . |<------------------------| . | ARRAYSIZE * | . |<------------------------| . | | * |interactor|<------------------------|ptr| -+ * +----------+ +---+ */ static tdmInteractor _allocateMoreInteractors (tdmInteractorWin W) { int i, j ; tdmInteractor newArray, *tmp ; ENTRY(("_allocateMoreInteractors(0x%x)", W)); /* allocate ARRAYSIZE more interactor pointers */ tmp = (tdmInteractor *) tdmAllocateLocal((W->numUsed + ARRAYSIZE) * sizeof(tdmInteractor)) ; if (! tmp) goto error ; /* allocate a new storage array with space for ARRAYSIZE interactors */ newArray = _allocateInteractorArray(W) ; if (! newArray) { tdmFree((void *) tmp) ; goto error ; } else W->numAllocated = W->numUsed + ARRAYSIZE ; /* copy exiting pointers */ for (i = 0 ; i < W->numUsed ; i++) tmp[i] = W->Interactors[i] ; /* init new pointers */ for (i = W->numUsed, j = 0 ; i < W->numAllocated ; i++, j++) tmp[i] = &newArray[j] ; if (W->Interactors) tdmFree((void *) W->Interactors) ; W->Interactors = tmp ; EXIT(("OK")); return W->Interactors[W->numUsed] ; error: EXIT(("ERROR")); return (tdmInteractor) 0 ; } static tdmInteractor _allocateInteractorArray (tdmInteractorWin W) { InteractorArray *tmp ; int i, numInteractorArrays ; ENTRY(("_allocateInteractorArray(0x%x)", W)); numInteractorArrays = W->numAllocated / ARRAYSIZE ; /* get a bigger array of array pointers */ tmp = (InteractorArray *) tdmAllocateLocal((numInteractorArrays + 1) * sizeof(InteractorArray)) ; if (! tmp) { EXIT(("ERROR")); return (tdmInteractor) 0 ; } /* allocate a new InteractorArray of size ARRAYSIZE */ tmp[numInteractorArrays] = (InteractorArray) tdmAllocateLocal(ARRAYSIZE * sizeof(tdmInteractorT)) ; if (! tmp[numInteractorArrays]) { tdmFree((void *) tmp) ; EXIT(("ERROR")); return (tdmInteractor) 0 ; } else bzero ((char *) tmp[numInteractorArrays], ARRAYSIZE * sizeof(tdmInteractorT)) ; /* copy existing array pointers */ for (i = 0 ; i < numInteractorArrays ; i++) tmp[i] = ((InteractorArray *) W->extents)[i] ; /* free old array pointer array */ if (W->extents) tdmFree(W->extents) ; /* copy new */ W->extents = (void *) tmp ; EXIT(("")); return *tmp[numInteractorArrays] ; } /* * Camera stack utils: * * Each window contains two stacks: the undo stack (W->Cam) and the redo * stack (W->redo). The top of the undo stack is the current camera in * use. When camera info is popped off the undo stack, it is pushed onto * the redo stack and vice versa. * * Note that these stacks are entirely separate from the stack managed by * the routines in hwMatrix.c. The latter routines are used to maintain * the state of the transformations used during application data * structure traversal, while the routines in this file maintain a * history of view transforms and other important information. * * The undo and redo stacks are limited in size to STACKLIMIT, which if * exceeded frees the bottom stack entry. */ #define STACKLIMIT 10 static int _PushInteractorCamera (tdmInteractorCam *stack, tdmInteractorCam new) { register int i ; register tdmInteractorCam p ; ENTRY(("_PushInteractorCamera(0x%x, 0x%x)", stack, new)); if (! stack) { EXIT(("bad camera stack reference")); return 0 ; } /* Chop tail. This is crude. Not worth improving for small stack limit. */ for (p= *stack, i=0 ; p && inext, i++) ; if (p && p->next) { tdmFree((void *)p->next) ; p->next = (tdmInteractorCam) 0 ; } if (! new) /* allocate new camera */ if (new = (tdmInteractorCam) tdmAllocateLocal(sizeof(tdmInteractorCamT))) if (*stack) /* copy current top */ memcpy ((void *)new, (void *)*stack, sizeof(tdmInteractorCamT)) ; else /* init new camera */ bzero ((char *)new, sizeof(tdmInteractorCamT)) ; else { EXIT(("out of memory")); return 0 ; } new->next = *stack ; *stack = new ; EXIT(("OK")); return 1 ; } int _dxfPushInteractorCamera (tdmInteractorWin W) { ENTRY(("_dxfPushInteractorCamera(0x%x)", W)); if (! W) { EXIT(("bad window")); return 0 ; } if (_PushInteractorCamera (&W->Cam, 0)) { EXIT(("OK")); return 1 ; } else { EXIT(("error")); return 0 ; } } static int _MoveInteractorCamera (tdmInteractorCam *dest, tdmInteractorCam *source) { /* pop source stack and push onto destination stack */ tdmInteractorCam top ; ENTRY(("_MoveInteractorCamera(0x%x, 0x%x)", dest, source)); if (!source || !*source) { EXIT(("empty source stack")); return 0 ; } top = *source ; *source = top->next ; top->next = 0 ; if (*source) (*source)->view_state++ ; if (! _PushInteractorCamera (dest, top)) { EXIT(("ERROR")); return 0 ; } EXIT(("OK")); return 1 ; } int _dxfPopInteractorCamera (tdmInteractorWin W) { tdmInteractorCam top ; ENTRY(("_dxfPopInteractorCamera(0x%x)", W)); /* there must always be at least one camera in W->Cam stack */ if (! W->Cam->next) { EXIT(("tried to pop last camera")); return 0 ; } /* pop current camera stack and push onto redo stack */ if (! _MoveInteractorCamera (&W->redo, &W->Cam)) { EXIT(("ERROR")); return 0 ; } /* indicate if OK to pop further */ if (W->Cam->next) { EXIT(("OK")); return 1 ; } else { EXIT(("last undoable camera")); return -1 ; } } int _dxfRedoInteractorCamera (tdmInteractorWin W) { tdmInteractorCam top ; ENTRY(("_dxfRedoInteractorCamera(0x%x)", W)); /* pop redo stack and push onto current camera stack */ if (! _MoveInteractorCamera (&W->Cam, &W->redo)) { EXIT(("ERROR")); return 0 ; } /* indicate if anything left on redo stack */ if (W->redo) { EXIT(("")); return 1 ; } else { EXIT(("popped last camera")); return -1 ; } } /* * General interactor utils */ void _dxfRedrawInteractorEchos (tdmInteractorWin W) { int i ; /* redraw all appropriate interactor echos in this window */ ENTRY(("_dxfRedrawInteractorEchos(0x%x)", W)); if (! W) { EXIT(("bad window")); return ; } for (i = 0 ; i < W->numAllocated ; i++) if (IS_USED(W->Interactors[i]) && !IS_AUX(W->Interactors[i]) && !IS_GROUP(W->Interactors[i])) tdmResumeEcho (W->Interactors[i], tdmBothBufferDraw) ; EXIT(("")); return ; } void _dxfAssociateInteractorEcho (tdmInteractor T, tdmInteractor A) { ENTRY(("_dxfAssociateInteractorEcho(0x%x, 0x%x)", T, A)); /* * Associate the echo of A to T. An associated interactor need not be * directly manipulated since it is driven by the interactor it is * associated with. * * Associations are stored in a list. AUX(T) is the head of the list * for interactor T. If T is a rotation interactor and is redrawn with * tdmResumeEcho(T), it first checks to see if it is visible, redraws * itself, and then calls tdmResumeEcho(AUX(T)). AUX(T) may also be * the head of its own sublist, in which case it calls * tdmResumeEcho(AUX(AUX(T))) recursively. * * This is not a general facility. One major restriction is that if an * interactor uses either the globe or the gnomon as its echo, then all * its associated interactors succeeding it in the list must also use * echo either globes or gnomons. This is because configuring the * frame buffer for a globe or gnomon is something that can only be * done once per redraw. */ if (T) AUX(T) = A ; if (A) IS_AUX(A) = 1 ; EXIT(("")); } void _dxfDisassociateInteractorEcho (tdmInteractorWin W, tdmInteractor A) { int i ; ENTRY(("_dxfDisassociateInteractorEcho(0x%x, 0x%x)", W, A)); /* break all associations with aux interactor A */ if (!W || !A || !IS_AUX(A)) { EXIT(("")); return ; } for (i = 0 ; i < W->numAllocated ; i++) if (IS_USED(W->Interactors[i]) && AUX(W->Interactors[i]) == A) AUX(W->Interactors[i]) = (tdmInteractor) 0 ; IS_AUX(A) = 0 ; EXIT(("")); } void _dxfSetInteractorBox (tdmInteractorWin W, float box[8][3]) { int i ; tdmInteractorCam C ; ENTRY(("_dxfSetInteractorBox(0x%x, 0x%x)", W, box)); /* set up global box for all cursors in this window */ if (!W || !(C = W->Cam)) goto error ; for (i = 0 ; i < 8 ; i++) { VPRINT(box[i]); C->box[i][0] = box[i][0] ; C->box[i][1] = box[i][1] ; C->box[i][2] = box[i][2] ; } C->box_state++ ; EXIT(("")); return ; error: EXIT(("error")); return; } void _dxfSetInteractorViewInfo (tdmInteractorWin W, float *f, float *t, float *u, float dist, float fov, float width, float aspect, int proj, float Near, float Far) { tdmInteractorCam C ; ENTRY(("_dxfSetInteractorViewInfo" "(0x%x, 0x%x, 0x%x, 0x%x, %f, %f, %f, %f, %d, %f, %f)", W, f, t, u, dist, fov, width, aspect, proj, Near, Far)); if (!W || !(C = W->Cam)) goto error ; C->from[0] = f[0] ; C->from[1] = f[1] ; C->from[2] = f[2] ; C-> to[0] = t[0] ; C-> to[1] = t[1] ; C-> to[2] = t[2] ; C-> up[0] = u[0] ; C-> up[1] = u[1] ; C-> up[2] = u[2] ; if (dist != 0) C->vdist = dist ; else C->vdist = (float) sqrt ((double)((f[0]-t[0])*(f[0]-t[0]) + (f[1]-t[1])*(f[1]-t[1]) + (f[2]-t[2])*(f[2]-t[2]))) ; /* !!!!!!! This is very questionable coding style if it's correct !!!!! */ if (C->projection = proj) { /* perspective */ C->fov = fov ; PRINT(("perspective projection fov %f", fov)); } else { /* orthogonal width in world coordinates */ C->width = width ; PRINT(("orthogonal projection width %f", width)); } C->aspect = aspect ; C->view_coords_set = 1 ; C->Near = Near ; C->Far = Far ; C->view_state++ ; PRINT(("look-to point:")); VPRINT(C->to); PRINT(("look-from point, dist %f", C->vdist)); VPRINT(C->from) ; PRINT(("up vector, length %f", LENGTH(C->up))); VPRINT(C->up) ; PRINT(("Near clip: %f", C->Near)); PRINT((" Far clip: %f", C->Far)); EXIT(("")); return ; error: EXIT(("ERROR")); return; } void _dxfSetInteractorWindowSize (tdmInteractorWin W, int width, int height) { tdmInteractorCam C ; ENTRY(("_dxfSetInteractorWindowSize(0x%x, %d, %d)", W, width, height)); /* record size of this window in pixels */ if (!W || !(C = W->Cam)) goto error ; C->w = width ; C->h = height ; C->aspect = (float)height/(float)width ; PRINT(("width: %d height: %d aspect: %f", C->w, C->h, C->aspect)); _dxfInteractorViewChanged(W) ; EXIT(("")); return ; error: EXIT(("ERROR")); return; } void _dxfSetInteractorViewDepth (tdmInteractorWin W, int depth) { tdmInteractorCam C ; ENTRY(("_dxfSetInteractorViewDepth(0x%x, %d)", W, depth)); /* record range of Z buffer for this window */ if (!W || !(C = W->Cam)) goto error ; C->d = depth ; PRINT(("depth: %d", C->d)); _dxfInteractorViewChanged(W) ; EXIT(("")); return ; error: EXIT(("ERROR")); return; } void _dxfGetInteractorViewInfo (tdmInteractorWin W, float *f, float *t, float *u, float *dist, float *fov, float *width, float *aspect, int *projection, float *Near, float *Far, int *pixwidth) { tdmInteractorCam C ; ENTRY(("_dxfGetInteractorViewInfo(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, " "0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)", W, f, t, u, dist, fov, width, aspect, projection, Near, Far, pixwidth)); if (!W || !(C = W->Cam) || !C->view_coords_set) goto error ; f[0] = C->from[0] ; f[1] = C->from[1] ; f[2] = C->from[2] ; t[0] = C-> to[0] ; t[1] = C-> to[1] ; t[2] = C-> to[2] ; u[0] = C-> up[0] ; u[1] = C-> up[1] ; u[2] = C-> up[2] ; /* !!!!! should we check for NULL?? */ *dist = C->vdist ; *fov = C->fov ; *width = C->width ; *aspect = C->aspect ; *projection = C->projection ; *Near = C->Near ; *Far = C->Far ; *pixwidth = C->w ; PRINT(("look-to point")); VPRINT(C->to) ; PRINT(("look-from point")); VPRINT(C->from) ; PRINT(("to-from dist: %12f" , C->vdist)); PRINT(("up vector, length %f", LENGTH(C->up))); VPRINT(C->up) ; PRINT(("width in pixels: %d aspect: %f", C->w, C->aspect)); PRINT(("%s", C->projection ? "perspective fov " : "ortho width ")); PRINT(("%f", C->projection ? C->fov : C->width)); PRINT(("Near clip: %f Far clip: %f", C->Near, C->Far)); EXIT(("")); return ; error: EXIT(("ERROR")); return; } void _dxfInteractorViewChanged(tdmInteractorWin W) { tdmInteractorCam C ; ENTRY(("_dxfInteractorViewChanged(0x%x)", W)); if (!W || !(C = W->Cam)) goto error ; C->view_state++ ; EXIT(("")); return ; error: EXIT(("ERROR")); return; } void _dxfSetInteractorImage (tdmInteractorWin W, int w, int h, void *image) { tdmInteractorCam C ; ENTRY(("_dxfSetInteractorImage(0x%x, %d, %d, 0x%x)", W, w, h, image)); /* copy pointer to application window background image */ if (!W || !(C = W->Cam)) goto error ; C->iw = w ; C->ih = h ; C->image = image ; EXIT(("")); return ; error: EXIT(("ERROR")); return; } void _dxfSetCursorSpeed (tdmInteractorWin W, int speed) { tdmInteractorCam C ; ENTRY(("_dxfSetCursorSpeed(0x%x, %d)", W, speed)); /* set speed global to all cursors in this window */ if (!W || !(C = W->Cam)) goto error ; C->cursor_speed = speed ; EXIT(("")); return ; error: EXIT(("ERROR")); return; } void _dxfSetCursorConstraint (tdmInteractorWin W, int constraint) { tdmInteractorCam C ; ENTRY(("_dxfSetCursorConstraint(0x%x, %d)", W, constraint)); /* set constraints global to all cursors in this window */ if (!W || !(C = W->Cam)) goto error ; C->cursor_constraint = constraint ; _dxfRedrawInteractorEchos(W) ; EXIT(("")); return ; error: EXIT(("ERROR")); return; } /* * Null functions for interactor implementations to use. */ void _dxfNullDoubleClick (tdmInteractor I, int x, int y, tdmInteractorReturn *R) { R->change = 0 ; } void _dxfNullStartStroke (tdmInteractor I, int x, int y, int btn, int s) { } void _dxfNullStrokePoint (tdmInteractor I, int a, int b, int type, int s) { } void _dxfNullEndStroke (tdmInteractor I, tdmInteractorReturn *R) { R->change = 0 ; } void _dxfNullResumeEcho (tdmInteractor I, tdmInteractorRedrawMode redrawMode) { } void _dxfNullKeyStruck(tdmInteractor I, int x, int y, char c, int s) { }