/***********************************************************************/ /* 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 #include #include #include "hwDeclarations.h" #include "hwUserInteractor.h" #include "hwInteractorEcho.h" #include "hwMatrix.h" #include "hwWindow.h" #ifndef STANDALONE #include "hwMemory.h" #endif #include "hwPortLayer.h" #include "hwDebug.h" typedef float MATRIX[4][4]; void _dxf_computeMatrix(float *, float *, float *, float, MATRIX *); static void UserDoubleClick(tdmInteractor, int, int, tdmInteractorReturn *); static void UserStartStrokeP(tdmInteractor, int, int, int, int); static void UserKeyStruck(tdmInteractor, int, int, char, int); static void UserStrokePoint(tdmInteractor, int, int, int, int); static void UserEndStrokeP(tdmInteractor, tdmInteractorReturnP); static void UserDestroy(tdmInteractor); void _dxfCacheState(char *baseTag, dxObject o, dxObject c, int quietly); tdmInteractor _dxfCreateUserInteractor(tdmInteractorWin W, tdmViewEchoFunc E, void *udata) { register tdmInteractor I; if(W && (I = _dxfAllocateInteractor (W, sizeof(tdmUserInteractorData)))) { DEFDATA(I,tdmUserInteractorData); DEFPORT(I_PORT_HANDLE); /* instance initial interactor methods */ FUNC(I, DoubleClick) = UserDoubleClick; FUNC(I, StartStroke) = UserStartStrokeP; FUNC(I, StrokePoint) = UserStrokePoint; FUNC(I, EndStroke) = UserEndStrokeP; FUNC(I, Destroy) = UserDestroy; FUNC(I, KeyStruck) = UserKeyStruck; FUNC(I, ResumeEcho) = _dxfNullResumeEcho; FUNC(I, EchoFunc) = E; UDATA(I) = udata; PDATA(mode) = -1; return I; } EXIT(("ERROR")); return 0; } extern int _dxd_nUserInteractors; extern void *_dxd_UserInteractors; void _dxfSetUserInteractorMode(tdmInteractor I, dxObject args) { unsigned long eventMask; DEFDATA(I, tdmUserInteractorData); DEFGLOBALDATA(UDATA(I)); int mode; UserInteractor *imode; Array amode; if (!args) { DXMessage("no object interaction mode given, none used"); mode = -1; } else { if (DXGetObjectClass(args) == CLASS_GROUP) { amode = (Array)DXGetMember((Group)args, "submode"); args = (dxObject)DXGetMember((Group)args, "args"); } else if (DXGetObjectClass(args) == CLASS_ARRAY) { amode = (Array)args; args = NULL; } else { amode = NULL; args = NULL; } if (!amode || !DXExtractInteger((dxObject)amode, &mode)) { DXMessage("Unable to access mode - must be an integer - none used"); mode = -1; } } imode = ((UserInteractor *)_dxd_UserInteractors) + PDATA(mode); if (mode > _dxd_nUserInteractors) { DXMessage("only %d user camera interactors are available", _dxd_nUserInteractors); mode = -1; } if (PDATA(mode) >= 0) imode->EndMode(PDATA(userData)); PDATA(mode) = mode; imode = ((UserInteractor *)_dxd_UserInteractors) + mode; if (mode >= 0) { PDATA(userData) = imode->InitMode(args, CDATA(w), CDATA(h), &I->eventMask); } else I->eventMask = 0; } /* * Method implementations */ static void UserDoubleClick(tdmInteractor I, int x, int y, tdmInteractorReturn *R) { R->change = 0; } static void UserStartStrokeP(tdmInteractor I, int x, int y, int btn, int s) { float dx, dy, dz; DEFDATA(I,tdmUserInteractorData); DEFGLOBALDATA(UDATA(I)); UserInteractor *imode = ((UserInteractor *)_dxd_UserInteractors) + PDATA(mode); DXMouseEvent mouse; if (PDATA(mode) < 0 || !(imode->EventHandler)) return; CDATA(xlast) = x; CDATA(ylast) = y; PDATA(button) = btn; _dxfGetViewMatrix(CDATA(stack), CDATA(viewXfm)); if (imode->SetCamera) imode->SetCamera(PDATA(userData), CDATA(to), CDATA(from), CDATA(up), CDATA(projection), CDATA(fov), CDATA(width)); if (imode->SetRenderable) imode->SetRenderable(PDATA(userData), OBJECT); switch (PDATA(button)) { case 1: mouse.event = DXEVENT_LEFT; break; case 2: mouse.event = DXEVENT_MIDDLE; break; case 3: mouse.event = DXEVENT_RIGHT; break; } mouse.x = x; mouse.y = y; mouse.state = BUTTON_DOWN; mouse.kstate = s; imode->EventHandler(PDATA(userData), (DXEvent *)&mouse); dx = CDATA(to)[0] - CDATA(from)[0]; dy = CDATA(to)[1] - CDATA(from)[1]; dz = CDATA(to)[2] - CDATA(from)[2]; CDATA(vdist) = sqrt(dx*dx + dy*dy + dz*dz); EXIT(("")); } static void UserStrokePoint (tdmInteractor I, int x, int y, int flag, int s) { int dx, dy; float Near, Far; float to[3], from[3], up[3], zaxis[3]; float fov, width; int p; dxObject newObject; DEFDATA(I,tdmUserInteractorData) ; DEFPORT(I_PORT_HANDLE) ; DEFGLOBALDATA(UDATA(I)); UserInteractor *imode = ((UserInteractor *)_dxd_UserInteractors) + PDATA(mode); int repaint = 0; DXMouseEvent mouse; if (PDATA(mode) < 0 || !(imode->EventHandler)) return; CDATA(xlast) = x; CDATA(ylast) = y; switch (PDATA(button)) { case 1: mouse.event = DXEVENT_LEFT; break; case 2: mouse.event = DXEVENT_MIDDLE; break; case 3: mouse.event = DXEVENT_RIGHT; break; } mouse.x = x; mouse.y = y; mouse.state = (flag == INTERACTOR_BUTTON_UP) ? BUTTON_UP : BUTTON_MOTION; mouse.kstate = s; imode->EventHandler(PDATA(userData), (DXEvent *)&mouse); if (imode->GetCamera && imode->GetCamera(PDATA(userData), to, from, up, &p, &fov, &width)) { repaint = 1; _dxf_computeMatrix(to, from, up, width, (MATRIX *)&CDATA(viewXfm)); GET_VIEW_DIRECTION(CDATA(viewXfm), zaxis); _dxfGetNearFar(p, CDATA(w), p ? fov : width, from, zaxis, CDATA(box), &Near, &Far); /* * setting new clip planes requires creating a new projection matrix */ if (p) { width = 0.0; _dxfSetProjectionInfo(CDATA(stack), 1, fov, CDATA(aspect), Near, Far); _dxf_SET_PERSPECTIVE_PROJECTION(PORT_CTX, fov, CDATA(aspect), Near, Far); } else { fov = 0.0; _dxfSetProjectionInfo(CDATA(stack), 0, width, CDATA(aspect), Near, Far); _dxf_SET_ORTHO_PROJECTION(PORT_CTX, width, CDATA(aspect), Near, Far); } _dxf_LOAD_MATRIX (PORT_CTX, CDATA(viewXfm)) ; _dxfLoadViewMatrix (CDATA(stack), CDATA(viewXfm)) ; CDATA(view_state)++ ; } if (imode->GetRenderable && imode->GetRenderable(PDATA(userData), &newObject)) { repaint = 1; DXDelete(OBJECT); OBJECT = DXReference(newObject); } if (repaint) { _dxfSetCurrentView(LWIN, to, from, up, fov, width); _dxfCacheState(ORIGINALWHERE, OBJECT, NULL, 1); CALLFUNC(I,EchoFunc) (I, UDATA(I), CDATA(viewXfm), 1); } EXIT(("")); } static void UserEndStrokeP(tdmInteractor I, tdmInteractorReturnP R) { DEFDATA(I,tdmUserInteractorData); DEFGLOBALDATA(UDATA(I)); float to[3], from[3], up[3]; float fov, width; float dx, dy, dz; int p; dxObject newObject; UserInteractor *imode = ((UserInteractor *)_dxd_UserInteractors) + PDATA(mode); int changed = 0; if (PDATA(mode) < 0) return; /* * End stroke and return appropriate info. */ ENTRY(("EndStroke(0x%x, 0x%x)", I, R)); if (imode->GetCamera && imode->GetCamera(PDATA(userData), to, from, up, &p, &fov, &width)) { CDATA(to[0]) = to[0]; CDATA(to[1]) = to[1]; CDATA(to[2]) = to[2]; CDATA(from[0]) = from[0]; CDATA(from[1]) = from[1]; CDATA(from[2]) = from[2]; CDATA(up[0]) = up[0]; CDATA(up[1]) = up[1]; CDATA(up[2]) = up[2]; CDATA(projection) = p; CDATA(fov) = fov; CDATA(width) = width; changed = 1; } dx = to[0] - from[0]; dy = to[1] - from[1]; dz = to[2] - from[2]; CDATA(vdist) = sqrt(dx*dx + dy*dy + dz*dz); _dxf_computeMatrix(CDATA(to), CDATA(from), CDATA(up), CDATA(width), (MATRIX *)&CDATA(viewXfm)); _dxfRenormalizeView(CDATA(viewXfm)); R->from[0] = CDATA(from[0]); R->from[1] = CDATA(from[1]); R->from[2] = CDATA(from[2]); R->to[0] = CDATA(to[0]); R->to[1] = CDATA(to[1]); R->to[2] = CDATA(to[2]); R->up[0] = CDATA(up[0]); R->up[1] = CDATA(up[1]); R->up[2] = CDATA(up[2]); R->dist = CDATA(vdist); COPYMATRIX(R->view, CDATA(viewXfm)); R->reason = tdmROTATION_UPDATE; R->change = 1; if (imode->GetRenderable && imode->GetRenderable(PDATA(userData), &newObject)) { DXDelete(OBJECT); OBJECT = DXReference(newObject); changed = 1; } if (changed) _dxfCacheState(ORIGINALWHERE, OBJECT, NULL, 0); _dxfSetCurrentView(LWIN, to, from, up, fov, width); EXIT(("")); } static void UserDestroy(tdmInteractor I) { DEFDATA(I,tdmUserInteractorData); DEFPORT(I_PORT_HANDLE); UserInteractor *imode = ((UserInteractor *)_dxd_UserInteractors) + PDATA(mode); ENTRY(("Destroy(0x%x)", I)); if (PDATA(mode) >= 0) imode->EndMode(PDATA(userData)); _dxfDeallocateInteractor(I); EXIT(("")); } static void UserKeyStruck(tdmInteractor I, int x, int y, char c, int s) { int dx, dy; float Near, Far; float to[3], from[3], up[3], zaxis[3]; float fov, width; int p; dxObject newObject; DEFDATA(I,tdmUserInteractorData) ; DEFPORT(I_PORT_HANDLE) ; DEFGLOBALDATA(UDATA(I)); UserInteractor *imode = ((UserInteractor *)_dxd_UserInteractors) + PDATA(mode); int repaint = 0; DXKeyPressEvent keypress; if (PDATA(mode) < 0 || !(imode->EventHandler)) return; if (imode->SetCamera) imode->SetCamera(PDATA(userData), CDATA(to), CDATA(from), CDATA(up), CDATA(projection), CDATA(fov), CDATA(width)); if (imode->SetRenderable) imode->SetRenderable(PDATA(userData), OBJECT); CDATA(xlast) = x; CDATA(ylast) = y; keypress.event = DXEVENT_KEYPRESS; keypress.x = x; keypress.y = y; keypress.key = c; keypress.kstate = s; imode->EventHandler(PDATA(userData), (DXEvent *)&keypress); if (imode->GetCamera && imode->GetCamera(PDATA(userData), to, from, up, &p, &fov, &width)) { repaint = 1; _dxf_computeMatrix(to, from, up, width, (MATRIX *)&CDATA(viewXfm)); GET_VIEW_DIRECTION(CDATA(viewXfm), zaxis); _dxfGetNearFar(p, CDATA(w), p ? fov : width, from, zaxis, CDATA(box), &Near, &Far); /* * setting new clip planes requires creating a new projection matrix */ if (p) { _dxfSetProjectionInfo(CDATA(stack), 1, fov, CDATA(aspect), Near, Far); _dxf_SET_PERSPECTIVE_PROJECTION(PORT_CTX, fov, CDATA(aspect), Near, Far); } else { _dxfSetProjectionInfo(CDATA(stack), 0, width, CDATA(aspect), Near, Far); _dxf_SET_ORTHO_PROJECTION(PORT_CTX, width, CDATA(aspect), Near, Far); } _dxf_LOAD_MATRIX (PORT_CTX, CDATA(viewXfm)) ; _dxfLoadViewMatrix (CDATA(stack), CDATA(viewXfm)) ; CDATA(view_state)++ ; } if (imode->GetRenderable && imode->GetRenderable(PDATA(userData), &newObject)) { repaint = 1; DXDelete(OBJECT); OBJECT = DXReference(newObject); } if (repaint) { _dxfCacheState(ORIGINALWHERE, OBJECT, NULL, 0); CALLFUNC(I,EchoFunc) (I, UDATA(I), CDATA(viewXfm), 1); } EXIT(("")); } void _dxf_computeMatrix(float *to, float *from, float *up, float width, MATRIX *m) { float a, v[3], xaxis[3], yaxis[3], zaxis[3], r[4][4]; float t[4][4]; t[0][0] = 1.0; t[0][1] = 0.0; t[0][2] = 0.0; t[0][3] = 0.0; t[1][0] = 0.0; t[1][1] = 1.0; t[1][2] = 0.0; t[1][3] = 0.0; t[2][0] = 0.0; t[2][1] = 0.0; t[2][2] = 1.0; t[2][3] = 0.0; t[3][0] = -from[0]; t[3][1] = -from[1]; t[3][2] = -from[2]; t[3][3] = 1.0; v[0] = from[0] - to[0]; v[1] = from[1] - to[1]; v[2] = from[2] - to[2]; a = sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]); zaxis[0] = v[0] / a; zaxis[1] = v[1] / a; zaxis[2] = v[2] / a; v[0] = up[1]*zaxis[2] - up[2]*zaxis[1]; v[1] = up[2]*zaxis[0] - up[0]*zaxis[2]; v[2] = up[0]*zaxis[1] - up[1]*zaxis[0]; a = sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]); xaxis[0] = v[0] / a; xaxis[1] = v[1] / a; xaxis[2] = v[2] / a; v[0] = zaxis[1]*xaxis[2] - zaxis[2]*xaxis[1]; v[1] = zaxis[2]*xaxis[0] - zaxis[0]*xaxis[2]; v[2] = zaxis[0]*xaxis[1] - zaxis[1]*xaxis[0]; a = sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]); yaxis[0] = v[0] / a; yaxis[1] = v[1] / a; yaxis[2] = v[2] / a; r[0][0] = xaxis[0]; r[0][1] = yaxis[0]; r[0][2] = zaxis[0]; r[0][3] = 0.0; r[1][0] = xaxis[1]; r[1][1] = yaxis[1]; r[1][2] = zaxis[1]; r[1][3] = 0.0; r[2][0] = xaxis[2]; r[2][1] = yaxis[2]; r[2][2] = zaxis[2]; r[2][3] = 0.0; r[3][0] = 0.0; r[3][1] = 0.0; r[3][2] = 0.0; r[3][3] = 1.0; MULTMATRIX((*m), t, r); } #define CACHE_OBJECT_TAG "CACHED_OBJECT_" #define CACHE_CAMERA_TAG "CACHED_CAMERA_" void _dxfCacheState(char *baseTag, dxObject o, dxObject c, int quietly) { char *tag = NULL; #if 0 if (o || c) DXMessage("Caching state %s", quietly ? "QUIETLY": "LOUDLY"); #endif if (o) { tag = DXAllocate(strlen(CACHE_OBJECT_TAG) + strlen(baseTag) + 10); sprintf(tag, "%s%s", CACHE_OBJECT_TAG, baseTag); DXSetCacheEntry(o, CACHE_PERMANENT, tag, 0, 0); if (quietly) DXNotifyRegisteredNoExecute(tag); else DXNotifyRegistered(tag); DXFree((Pointer)tag); } if (c) { tag = DXAllocate(strlen(CACHE_CAMERA_TAG) + strlen(baseTag) + 10); sprintf(tag, "%s%s", CACHE_CAMERA_TAG, baseTag); DXSetCacheEntry(c, CACHE_PERMANENT, tag, 0, 0); if (quietly) DXNotifyRegisteredNoExecute(tag); else DXNotifyRegistered(tag); DXFree((Pointer)tag); } }