/***********************************************************************/ /* 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 /*---------------------------------------------------------------------------*\ $Source: /home/gda/dxcvs/dx/src/exec/hwrender/hwZoomInteractor.c,v $ Author: Mark Hood This file contains the implementation of the tdm Zoom interactor. \*---------------------------------------------------------------------------*/ #include #include #include "hwDeclarations.h" #include "hwMatrix.h" #include "hwInteractorEcho.h" #include "hwZoomInteractor.h" #ifndef STANDALONE #include "hwMemory.h" #endif #include "hwPortLayer.h" #include "hwDebug.h" /* * Forward references */ static void StartZoomStroke (tdmInteractor, int, int, int, int) ; static void StartPanZoomStroke (tdmInteractor, int, int, int, int) ; static void StartStroke (tdmInteractor, int, int, int, int) ; static void StrokePoint (tdmInteractor, int, int, int, int) ; static void EndZoomStroke (tdmInteractor, tdmInteractorReturnP) ; static void EndPanZoomStroke (tdmInteractor, tdmInteractorReturnP) ; static void zoomConfig (tdmInteractor I) ; static void restoreConfig (tdmInteractor I) ; /* * null functions */ static void NullDoubleClick (tdmInteractor I, int x, int y, tdmInteractorReturn *R) { R->change = 0 ; } static void NullResumeEcho (tdmInteractor I, tdmInteractorRedrawMode redraw_mode) { } /* * Creation functions */ tdmInteractor _dxfCreateZoomInteractor (tdmInteractorWin W) { /* * Initialize and return a handle to a zoom interactor. */ register tdmInteractor I ; ENTRY(("_dxfCreateZoomInteractor(0x%x)", W)); if (W && (I = _dxfAllocateInteractor(W, sizeof(tdmZoomData)))) { DEFDATA(I,tdmZoomData) ; /* instance interactor object methods */ FUNC(I, StartStroke) = StartZoomStroke ; FUNC(I, StrokePoint) = StrokePoint ; FUNC(I, DoubleClick) = NullDoubleClick ; FUNC(I, EndStroke) = EndZoomStroke ; FUNC(I, ResumeEcho) = NullResumeEcho ; FUNC(I, Destroy) = _dxfDeallocateInteractor ; EXIT(("I = 0x%x",I)); return I ; } else EXIT(("ERROR")); return 0 ; } tdmInteractor _dxfCreatePanZoomInteractor (tdmInteractorWin W) { /* * Initialize and return a handle to a pan zoom interactor. */ register tdmInteractor I ; ENTRY(("_dxfCreatePanZoomInteractor(0x%x)", W)); if (W && (I = _dxfAllocateInteractor(W, sizeof(tdmZoomData)))) { DEFDATA(I, tdmZoomData) ; /* instance interactor object methods */ FUNC(I, StartStroke) = StartPanZoomStroke ; FUNC(I, StrokePoint) = StrokePoint ; FUNC(I, DoubleClick) = NullDoubleClick ; FUNC(I, EndStroke) = EndPanZoomStroke ; FUNC(I, ResumeEcho) = NullResumeEcho ; FUNC(I, Destroy) = _dxfDeallocateInteractor ; FUNC(I, KeyStruck) = _dxfNullKeyStruck; EXIT(("I = 0x%x",I)); return I ; } else EXIT(("ERROR")); return 0 ; } /* * method implementations */ static void StartZoomStroke (tdmInteractor I, int x, int y, int btn, int s) { DEFDATA(I, tdmZoomData) ; ENTRY(("StartZoomStroke(0x%x, %d, %d, %d)", I, x, y, btn)); PDATA(btn) = btn ; if (btn == 2) { EXIT(("btn == 2")); return ; } zoomConfig(I) ; /* zoom center is middle of the window */ PDATA(cx) = CDATA(w) / 2 ; PDATA(cy) = CDATA(h) / 2 ; StartStroke (I, x, y, btn, s) ; EXIT(("")); } static void StartPanZoomStroke (tdmInteractor I, int x, int y, int btn, int s) { DEFDATA(I, tdmZoomData) ; ENTRY(("StartPanZoomStroke(0x%x, %d, %d ,%d)", I, x, y, btn)); PDATA(btn) = btn ; if (btn == 2) { EXIT(("btn == 2")); return ; } zoomConfig(I) ; /* zoom center is initial mouse position */ PDATA(cx) = x ; PDATA(cy) = YFLIP(y) ; StartStroke (I, x, y, btn, s) ; EXIT(("")); } static void StartStroke (tdmInteractor I, int x, int y, int btn, int s) { DEFDATA(I, tdmZoomData) ; DEFPORT(I_PORT_HANDLE) ; int dx, dy, ax, ay ; ENTRY(("StartStroke(0x%x, %d, %d, %d)", I, x, y, btn)); PDATA(px) = x ; PDATA(py) = y ; y = YFLIP(y) ; x = x<0 ? 0 : (x>CDATA(w) ? CDATA(w) : x) ; y = y<0 ? 0 : (y>CDATA(h) ? CDATA(h) : y) ; /* displacement from zoom center */ dx = x - PDATA(cx) ; dy = y - PDATA(cy) ; ax = abs(dx) ; ay = abs(dy) ; /* force zoom box aspect to match window aspect */ if ((dy >= dx * CDATA(aspect) && dy >= -dx * CDATA(aspect)) || (dy <= -dx * CDATA(aspect) && dy <= dx * CDATA(aspect))) { PDATA(y1) = PDATA(cy) - ay ; PDATA(x1) = PDATA(cx) - ay / CDATA(aspect) ; PDATA(y2) = PDATA(y1) + 2 * ay ; PDATA(x2) = PDATA(x1) + 2 * ay / CDATA(aspect) ; } else { PDATA(x1) = PDATA(cx) - ax ; PDATA(y1) = PDATA(cy) - ax * CDATA(aspect) ; PDATA(x2) = PDATA(x1) + 2 * ax ; PDATA(y2) = PDATA(y1) + 2 * ax * CDATA(aspect) ; } _dxf_DRAW_ZOOMBOX(I, (void *)0, (float (*)[4])identity, 1) ; EXIT(("")); } static void StrokePoint (tdmInteractor I, int x, int y, int flag, int s) { DEFDATA(I, tdmZoomData) ; DEFPORT(I_PORT_HANDLE) ; int dx, dy, ax, ay ; ENTRY(("StrokePoint(0x%x, %d, %d)", I, x, y)); if ((PDATA(btn) == 2) || (x == PDATA(px) && y == PDATA(py))) { EXIT(("btn == 2 or no movement")); return ; } PDATA(px) = x ; PDATA(py) = y ; y = YFLIP(y) ; x = x<0 ? 0 : (x>CDATA(w) ? CDATA(w) : x) ; y = y<0 ? 0 : (y>CDATA(h) ? CDATA(h) : y) ; /* displacement from zoom box center */ dx = x - PDATA(cx) ; dy = y - PDATA(cy) ; ax = abs(dx) ; ay = abs(dy) ; _dxf_DRAW_ZOOMBOX(I, (void *)0, (float (*)[4])identity, 0) ; /* force zoom box aspect to equal window aspect */ if ((dy >= dx * CDATA(aspect) && dy >= -dx * CDATA(aspect)) || (dy <= -dx * CDATA(aspect) && dy <= dx * CDATA(aspect))) { PDATA(y1) = PDATA(cy) - ay ; PDATA(x1) = PDATA(cx) - ay / CDATA(aspect) ; PDATA(y2) = PDATA(y1) + 2 * ay ; PDATA(x2) = PDATA(x1) + 2 * ay / CDATA(aspect) ; } else { PDATA(x1) = PDATA(cx) - ax ; PDATA(y1) = PDATA(cy) - ax * CDATA(aspect) ; PDATA(x2) = PDATA(x1) + 2 * ax ; PDATA(y2) = PDATA(y1) + 2 * ax * CDATA(aspect) ; } _dxf_DRAW_ZOOMBOX(I, (void *)0, (float (*)[4])identity, 1) ; EXIT(("")); } static void EndZoomStroke (tdmInteractor I, tdmInteractorReturnP M) { DEFDATA(I, tdmZoomData) ; DEFPORT(I_PORT_HANDLE) ; int boxwidth ; ENTRY(("EndZoomStroke(0x%x, 0x%x)", I, M)); /* * Return zoom factor and a rotation/translation matrix. The matrix is * identity for the Zoom interactor. */ COPYMATRIX(M->matrix, identity) ; if (PDATA(btn) == 2) { M->change = 0 ; EXIT(("btn == 2")); return ; } boxwidth = PDATA(x2) - PDATA(x1) ; if (boxwidth == 0 || boxwidth == CDATA(w)) { M->change = 0 ; PRINT(("no change")); } else { if (PDATA(btn) == 1) M->zoom_factor = (float)boxwidth / (float)CDATA(w) ; else M->zoom_factor = (float)CDATA(w) / (float)boxwidth ; M->to[0] = CDATA(to[0]) ; M->to[1] = CDATA(to[1]) ; M->to[2] = CDATA(to[2]) ; M->from[0] = CDATA(from[0]) ; M->from[1] = CDATA(from[1]) ; M->from[2] = CDATA(from[2]) ; M->up[0] = CDATA(up[0]) ; M->up[1] = CDATA(up[1]) ; M->up[2] = CDATA(up[2]) ; M->change = 1 ; } /* undraw the zoom box, restore frame buffer configuration */ _dxf_DRAW_ZOOMBOX(I, (void *)0, (float (*)[4])identity, 0) ; restoreConfig(I) ; EXIT(("")); } static void EndPanZoomStroke (tdmInteractor I, tdmInteractorReturnP M) { DEFDATA(I, tdmZoomData) ; DEFPORT(I_PORT_HANDLE) ; int boxwidth ; /* * Return zoom factor and a matrix. The matrix is a rotation or * translation in view coordinates relative to the view origin (`from' * point), *not* the final view matrix; therefore, it is returned in * the `matrix' field and not the `view' field. */ ENTRY(("EndPanZoomStroke(0x%x, 0x%x)", I, M)); COPYMATRIX(M->matrix, identity) ; if (PDATA(btn) == 2) { M->change = 0 ; EXIT(("btn == 2")); return ; } _dxf_DRAW_ZOOMBOX(I, (void *)0, (float (*)[4])identity, 0) ; boxwidth = PDATA(x2) - PDATA(x1) ; if (boxwidth == 0 || boxwidth == CDATA(w)) { M->change = 0 ; PRINT(("no change")); } else { float vcx, vcy, vcz, wcx, wcy, wcz, screenToView ; if (PDATA(btn) == 1) M->zoom_factor = (float)boxwidth / (float)CDATA(w) ; else M->zoom_factor = (float)CDATA(w) / (float)boxwidth ; /* compute scale conversion for screen -> view */ screenToView = (CDATA(projection)? CDATA(fov): CDATA(width)) / CDATA(w) ; /* convert zoom center to view coordinates */ vcx = (PDATA(cx) - CDATA(w)/2) * screenToView ; vcy = (PDATA(cy) - CDATA(h)/2) * screenToView ; vcz = -1 ; if (CDATA(projection)) { /* perspective: pan pivots view vector to look at zoom center */ float rx, ry, rz, c, t ; double s ; /* [vcx,vcy,vcz] = new view vector expressed in VC: normalize it */ s = sqrt((double)(vcx*vcx + vcy*vcy + vcz*vcz)) ; vcx /= s ; vcy /= s ; vcz /= s ; /* axis of rotation in view coordinates = [vcx,vcy,vcz] X [0,0,-1] */ rx = -vcy ; ry = vcx ; rz = 0 ; /* length of axis is the sine of the angle to rotate */ s = (float) sqrt((double)(rx*rx + ry*ry)) ; /* cosine of angle is [vcx,vcy,vcz].[0,0,-1] */ c = -vcz ; /* normalize rotation axis */ rx /= s ; ry /= s ; /* construct relative rotation matrix expressing oldVC -> newVC */ t = 1.0 - c ; ROTXY (M->matrix, rx, ry, s, c, t) ; /* rotate new view vector into current world coordinates */ wcx = vcx * CDATA(viewXfm[0][0]) + vcy * CDATA(viewXfm[0][1]) + vcz * CDATA(viewXfm[0][2]) ; wcy = vcx * CDATA(viewXfm[1][0]) + vcy * CDATA(viewXfm[1][1]) + vcz * CDATA(viewXfm[1][2]) ; wcz = vcx * CDATA(viewXfm[2][0]) + vcy * CDATA(viewXfm[2][1]) + vcz * CDATA(viewXfm[2][2]) ; /* construct new `to' point */ M->to[0] = CDATA(from[0]) + CDATA(vdist)*wcx ; M->to[1] = CDATA(from[1]) + CDATA(vdist)*wcy ; M->to[2] = CDATA(from[2]) + CDATA(vdist)*wcz ; /* `from' point is unchanged */ M->from[0] = CDATA(from[0]) ; M->from[1] = CDATA(from[1]) ; M->from[2] = CDATA(from[2]) ; /* * Consider the columns of M->matrix as the basis of the newly * rotated view coordinate system, expressed in terms of the * old view coordinate system. Then rotating the Y column of * M->matrix into current world coordinates gives the new `up' * vector. */ M->up[0] = M->matrix[0][1] * CDATA(viewXfm[0][0]) + M->matrix[1][1] * CDATA(viewXfm[0][1]) + M->matrix[2][1] * CDATA(viewXfm[0][2]) ; M->up[1] = M->matrix[0][1] * CDATA(viewXfm[1][0]) + M->matrix[1][1] * CDATA(viewXfm[1][1]) + M->matrix[2][1] * CDATA(viewXfm[1][2]) ; M->up[2] = M->matrix[0][1] * CDATA(viewXfm[2][0]) + M->matrix[1][1] * CDATA(viewXfm[2][1]) + M->matrix[2][1] * CDATA(viewXfm[2][2]) ; } else { /* ortho view: pan matrix is a translation in view X and Y only */ M->matrix[3][0] = -vcx ; M->matrix[3][1] = -vcy ; /* convert translation into world coordinates */ wcx = vcx*CDATA(viewXfm[0][0]) + vcy*CDATA(viewXfm[0][1]) ; wcy = vcx*CDATA(viewXfm[1][0]) + vcy*CDATA(viewXfm[1][1]) ; wcz = vcx*CDATA(viewXfm[2][0]) + vcy*CDATA(viewXfm[2][1]) ; /* translate `to' and `from' points */ M->to[0] = CDATA(to[0]) + wcx ; M->to[1] = CDATA(to[1]) + wcy ; M->to[2] = CDATA(to[2]) + wcz ; M->from[0] = CDATA(from[0]) + wcx ; M->from[1] = CDATA(from[1]) + wcy ; M->from[2] = CDATA(from[2]) + wcz ; /* `up' remains the same */ M->up[0] = CDATA(up[0]) ; M->up[1] = CDATA(up[1]) ; M->up[2] = CDATA(up[2]) ; } PRINT(("zoom factor %f", M->zoom_factor)); PRINT(("look-to point")); VPRINT(M->to) ; PRINT(("up vector")); VPRINT(M->up) ; PRINT(("look-from point")); VPRINT(M->from) ; PRINT(("matrix")); MPRINT(M->matrix) ; M->change = 1 ; } restoreConfig(I) ; EXIT(("")); } /* * Configuration functions */ static void zoomConfig (tdmInteractor I) { DEFDATA(I, tdmZoomData) ; DEFPORT(I_PORT_HANDLE) ; ENTRY(("zoomConfig(0x%x)", I)); /* get origin of window and dimensions of screen */ _dxf_GET_WINDOW_ORIGIN (PORT_CTX, &CDATA(ox), &CDATA(oy)) ; _dxf_GET_MAXSCREEN (PORT_CTX, &CDATA(xmaxscreen), &CDATA(ymaxscreen)) ; /* save viewport and get viewing matrix */ _dxfPushViewport(CDATA(stack)) ; _dxfGetViewMatrix(CDATA(stack), CDATA(viewXfm)) ; /* push the SW modeling matrix and HW modeling/viewing matrix */ _dxfPushMatrix(CDATA(stack)) ; _dxf_PUSH_REPLACE_MATRIX (PORT_CTX, (float (*)[4])identity) ; /* set up one-to-one mapping of world to screen */ _dxf_SET_WORLD_SCREEN (PORT_CTX, CDATA(w), CDATA(h)) ; /* disable Z buffer comparisons */ if ((CDATA(zbuffer) = _dxf_GET_ZBUFFER_STATUS(PORT_CTX))) _dxf_SET_ZBUFFER_STATUS (PORT_CTX, 0) ; /* set up frame buffer */ _dxf_BUFFER_CONFIG (PORT_CTX, CDATA(image), 0, CDATA(h)-CDATA(ih), CDATA(iw)-1, CDATA(h)-1, &PDATA(displaymode), &PDATA(buffermode), tdmFrontBufferDraw) ; EXIT(("")); } static void restoreConfig (tdmInteractor I) { int left, right, bottom, top ; DEFDATA(I, tdmZoomData) ; DEFPORT(I_PORT_HANDLE) ; ENTRY(("restoreConfig(0x%x)", I)); /* restore viewport */ _dxfPopViewport(CDATA(stack)) ; _dxfGetViewport(CDATA(stack), &left, &right, &bottom, &top) ; _dxf_SET_VIEWPORT(PORT_CTX, left, right, bottom, top) ; /* restore projection matrix */ if (CDATA(projection)) _dxf_SET_PERSPECTIVE_PROJECTION (PORT_CTX, CDATA(fov), CDATA(aspect), CDATA(Near), CDATA(Far)) ; else _dxf_SET_ORTHO_PROJECTION (PORT_CTX, CDATA(width), CDATA(aspect), CDATA(Near), CDATA(Far)) ; /* restore model/view matrix */ _dxfPopMatrix(CDATA(stack)) ; _dxf_POP_MATRIX(PORT_CTX) ; /* restore zbuffer usage */ if (CDATA(zbuffer)) _dxf_SET_ZBUFFER_STATUS (PORT_CTX, 1) ; /* restore frame buffer configuration */ _dxf_BUFFER_RESTORE_CONFIG (PORT_CTX, PDATA(displaymode), PDATA(buffermode), tdmFrontBufferDraw) ; EXIT(("")); }