/*********************************************************************/ /* */ /* I.B.M. CONFIDENTIAL */ /* xxxx-yyy (c) COPYRIGHT IBM CORP. 1990 ALL RIGHTS RESERVED. */ /* */ /* (I.B.M. CONFIDENTIAL-RESTRICTED when combined with the aggregated */ /* OCO source materials for this program.) */ /* OCO SOURCE MATERIAL */ /* LICENSED MATERIALS-PROPERTY OF IBM. */ /* */ /*********************************************************************/ #include #include #include #define N_USER_INTERACTORS 3 static void *RotateInitMode(Object, int, int, int *); static void RotateEndMode(void *); static void RotateSetCamera(void *, float *, float *, float *, int, float, float); static int RotateGetCamera(void *, float *, float *, float *, int *, float *, float *); static void RotateSetRenderable(void *, Object); static int RotateGetRenderable(void *, Object *); static void RotateEventHandler(void *, DXEvent *); static void *PanInitMode(Object, int, int, int *); static void PanEndMode(void *); static void PanSetCamera(void *, float *, float *, float *, int, float, float); static int PanGetCamera(void *, float *, float *, float *, int *, float *, float *); static void PanSetRenderable(void *, Object); static int PanGetRenderable(void *, Object *); static void PanEventHandler(void *, DXEvent *); static void *ZoomInitMode(Object, int, int, int *); static void ZoomEndMode(void *); static void ZoomSetCamera(void *, float *, float *, float *, int, float, float); static int ZoomGetCamera(void *, float *, float *, float *, int *, float *, float *); static void ZoomSetRenderable(void *, Object); static int ZoomGetRenderable(void *, Object *); static void ZoomEventHandler(void *, DXEvent *); static UserInteractor _userInteractionTable[N_USER_INTERACTORS]; int DXDefaultUserInteractors(int *n, void *t) { _userInteractionTable[0].InitMode = RotateInitMode; _userInteractionTable[0].EndMode = RotateEndMode; _userInteractionTable[0].SetCamera = RotateSetCamera; _userInteractionTable[0].GetCamera = RotateGetCamera; _userInteractionTable[0].SetRenderable = RotateSetRenderable; _userInteractionTable[0].GetRenderable = RotateGetRenderable; _userInteractionTable[0].EventHandler = RotateEventHandler; _userInteractionTable[1].InitMode = PanInitMode; _userInteractionTable[1].EndMode = PanEndMode; _userInteractionTable[1].SetCamera = PanSetCamera; _userInteractionTable[1].GetCamera = PanGetCamera; _userInteractionTable[1].SetRenderable = PanSetRenderable; _userInteractionTable[1].GetRenderable = PanGetRenderable; _userInteractionTable[1].EventHandler = PanEventHandler; _userInteractionTable[2].InitMode = ZoomInitMode; _userInteractionTable[2].EndMode = ZoomEndMode; _userInteractionTable[2].SetCamera = ZoomSetCamera; _userInteractionTable[2].GetCamera = ZoomGetCamera; _userInteractionTable[2].SetRenderable = ZoomSetRenderable; _userInteractionTable[2].GetRenderable = ZoomGetRenderable; _userInteractionTable[2].EventHandler = ZoomEventHandler; *n = N_USER_INTERACTORS; *(long **)t = (long *)_userInteractionTable; return 1; } /***** Rotate *****/ static void RotateStartStroke(void *, DXMouseEvent *); static void RotateEndStroke(void *, DXMouseEvent *); typedef struct RotateData { Object args; /* Interactor arguments */ int w, h; /* Width and height of window */ Object obj; /* Current object */ float to[3]; /* Current camera parameters */ float from[3]; float up[3]; int p; float fov; float width; float grad; int motionFlag; struct { int x, y; } buttonPositions[3]; int buttonStates[3]; } *RotateData; static void * RotateInitMode(Object args, int w, int h, int *mask) { RotateData rdata = (RotateData)DXAllocateZero(sizeof(struct RotateData)); if (! rdata) return NULL; if (args) { } /* * Grab the window size */ rdata->w = w; rdata->h = h; if (w > h) rdata->grad = h / 2.0; else rdata->grad = w / 2.0; rdata->buttonStates[0] = BUTTON_UP; rdata->buttonStates[1] = BUTTON_UP; rdata->buttonStates[2] = BUTTON_UP; *mask = DXEVENT_LEFT; return (void *)rdata; } static void RotateEndMode(void *data) { RotateData rdata = (RotateData)data; if (rdata) { if (rdata->args) DXDelete(rdata->args); if (rdata->obj) DXDelete(rdata->obj); } DXFree(data); } static void RotateSetCamera(void *data, float to[3], float from[3], float up[3], int proj, float fov, float width) { int i; RotateData rdata = (RotateData)data; /* * Grab the camera */ for (i = 0; i < 3; i++) rdata->to[i] = to[i], rdata->from[i] = from[i], rdata->up[i] = up[i]; rdata->p = proj; rdata->fov = fov; rdata->width = width; } static int RotateGetCamera(void *data, float to[3], float from[3], float up[3], int *proj, float *fov, float *width) { int i; RotateData rdata = (RotateData)data; /* * Return the camera */ for (i = 0; i < 3; i++) to[i] = rdata->to[i], from[i] = rdata->from[i], up[i] = rdata->up[i]; *proj = rdata->p; *fov = rdata->fov; *width = rdata->width; return 1; } static void RotateSetRenderable(void *data, Object obj) { RotateData rdata = (RotateData)data; DXReference(obj); if (rdata->obj) DXDelete(rdata->obj); rdata->obj = obj; } static int RotateGetRenderable(void *data, Object *obj) { RotateData rdata = (RotateData)data; if (rdata->obj) { *obj = rdata->obj; return 1; } else { *obj = NULL; return 0; } } static void RotateEventHandler(void *data, DXEvent *event) { RotateData rdata = (RotateData)data; switch(event->any.event) { case DXEVENT_LEFT: case DXEVENT_MIDDLE: case DXEVENT_RIGHT: { int b = WHICH_BUTTON(event); switch (event->mouse.state) { case BUTTON_DOWN: RotateStartStroke(data, (DXMouseEvent *)event); rdata->buttonStates[b] = BUTTON_DOWN; break; case BUTTON_MOTION: if (rdata->buttonStates[b] == BUTTON_UP) RotateStartStroke(data, (DXMouseEvent *)event); else RotateEndStroke(data, (DXMouseEvent *)event); rdata->buttonStates[b] = BUTTON_DOWN; break; case BUTTON_UP: RotateEndStroke(data, (DXMouseEvent *)event); rdata->buttonStates[b] = BUTTON_UP; break; default: break; } } break; default: break; } } static void RotateStartStroke(void *data, DXMouseEvent *event) { RotateData rdata = (RotateData)data; /* * Just keep track of which button is pressed * and where it was pressed. */ int b = WHICH_BUTTON(event); if (b != NO_BUTTON) { rdata->buttonPositions[b].x = event->x; rdata->buttonPositions[b].y = event->y; } return; } static void RotateEndStroke(void *data, DXMouseEvent *event) { float a, t, s, c; float dx, dy; int b = WHICH_BUTTON(event); RotateData rdata = (RotateData)data; if (! rdata) return; dx = event->x - rdata->buttonPositions[b].x; dy = event->y - rdata->buttonPositions[b].y; dx = -dx; dy = -dy; rdata->buttonPositions[b].x = event->x; rdata->buttonPositions[b].y = event->y; rdata->motionFlag = (event->state == BUTTON_MOTION); a = sqrt(dx*dx + dy*dy); if (a != 0) { float ov[3], nv[3], rot[4][4]; float rt[3], up[3]; float stroke[3], axis[3], d; ov[0] = rdata->from[0] - rdata->to[0]; ov[1] = rdata->from[1] - rdata->to[1]; ov[2] = rdata->from[2] - rdata->to[2]; rt[0] = ov[1]*rdata->up[2] - ov[2]*rdata->up[1]; rt[1] = ov[2]*rdata->up[0] - ov[0]*rdata->up[2]; rt[2] = ov[0]*rdata->up[1] - ov[1]*rdata->up[0]; d = sqrt(rt[0]*rt[0] + rt[1]*rt[1] + rt[2]*rt[2]); rt[0] /= d; rt[1] /= d; rt[2] /= d; up[0] = rt[1]*ov[2] - rt[2]*ov[1]; up[1] = rt[2]*ov[0] - rt[0]*ov[2]; up[2] = rt[0]*ov[1] - rt[1]*ov[0]; d = sqrt(up[0]*up[0] + up[1]*up[1] + up[2]*up[2]); rdata->up[0] = up[0] /= d; rdata->up[1] = up[1] /= d; rdata->up[2] = up[2] /= d; dx /= rdata->grad; dy /= rdata->grad; stroke[0] = dx*rt[0] + dy*up[0]; stroke[1] = dx*rt[1] + dy*up[1]; stroke[2] = dx*rt[2] + dy*up[2]; axis[0] = ov[1]*stroke[2] - ov[2]*stroke[1]; axis[1] = ov[2]*stroke[0] - ov[0]*stroke[2]; axis[2] = ov[0]*stroke[1] - ov[1]*stroke[0]; d = sqrt(axis[0]*axis[0] + axis[1]*axis[1] + axis[2]*axis[2]); axis[0] /= d; axis[1] /= d; axis[2] /= d; a = sqrt(dx*dx + dy*dy); s = (float)sin(a); c = (float)cos(a); t = 1.0 - c; ROTXYZ(rot, axis[0], axis[1], axis[2], s, c, t); nv[0] = rot[0][0]*ov[0] + rot[1][0]*ov[1] + rot[2][0]*ov[2]; nv[1] = rot[0][1]*ov[0] + rot[1][1]*ov[1] + rot[2][1]*ov[2]; nv[2] = rot[0][2]*ov[0] + rot[1][2]*ov[1] + rot[2][2]*ov[2]; rdata->from[0] = rdata->to[0] + nv[0]; rdata->from[1] = rdata->to[1] + nv[1]; rdata->from[2] = rdata->to[2] + nv[2]; } return; } /***** Pan *****/ static void PanStartStroke(void *, DXMouseEvent *); static void PanEndStroke(void *, DXMouseEvent *); typedef struct PanData { Object args; /* Interactor arguments */ int w, h; /* Width and height of window */ Object obj; /* Current object */ float to[3]; /* Current camera parameters */ float from[3]; float up[3]; int p; float fov; float width; float grad; int motionFlag; struct { int x, y; } buttonPositions[3]; int buttonStates[3]; } *PanData; static void * PanInitMode(Object args, int w, int h, int *mask) { PanData pdata = (PanData)DXAllocateZero(sizeof(struct PanData)); if (! pdata) return NULL; if (args) { } /* * Grab the window size */ pdata->w = w; pdata->h = h; if (w > h) pdata->grad = h / 2.0; else pdata->grad = w / 2.0; pdata->buttonStates[0] = BUTTON_UP; pdata->buttonStates[1] = BUTTON_UP; pdata->buttonStates[2] = BUTTON_UP; *mask = DXEVENT_LEFT; return (void *)pdata; } static void PanEndMode(void *data) { PanData pdata = (PanData)data; if (pdata) { if (pdata->args) DXDelete(pdata->args); if (pdata->obj) DXDelete(pdata->obj); } DXFree(data); } static void PanSetCamera(void *data, float to[3], float from[3], float up[3], int proj, float fov, float width) { int i; float dx = to[0] - from[0]; float dy = to[1] - from[1]; float dz = to[2] - from[2]; float vd = sqrt(dx*dx + dy*dy + dz*dz); PanData pdata = (PanData)data; /* * Grab the camera */ for (i = 0; i < 3; i++) pdata->to[i] = to[i], pdata->from[i] = from[i], pdata->up[i] = up[i]; pdata->p = proj; pdata->fov = fov; pdata->width = width; if (proj) pdata->grad = (fov * vd) / pdata->w; else pdata->grad = width / pdata->w; } static int PanGetCamera(void *data, float to[3], float from[3], float up[3], int *proj, float *fov, float *width) { int i; PanData pdata = (PanData)data; /* * Return the camera */ for (i = 0; i < 3; i++) to[i] = pdata->to[i], from[i] = pdata->from[i], up[i] = pdata->up[i]; *proj = pdata->p; *fov = pdata->fov; *width = pdata->width; return 1; } static void PanSetRenderable(void *data, Object obj) { PanData pdata = (PanData)data; DXReference(obj); if (pdata->obj) DXDelete(pdata->obj); pdata->obj = obj; } static int PanGetRenderable(void *data, Object *obj) { PanData pdata = (PanData)data; if (pdata->obj) { *obj = pdata->obj; return 1; } else { *obj = NULL; return 0; } } static void PanEventHandler(void *data, DXEvent *event) { PanData pdata = (PanData)data; switch(event->any.event) { case DXEVENT_LEFT: case DXEVENT_MIDDLE: case DXEVENT_RIGHT: { int b = WHICH_BUTTON(event); switch (event->mouse.state) { case BUTTON_DOWN: PanStartStroke(data, (DXMouseEvent *)event); pdata->buttonStates[b] = BUTTON_DOWN; break; case BUTTON_MOTION: if (pdata->buttonStates[b] == BUTTON_UP) PanStartStroke(data, (DXMouseEvent *)event); else PanEndStroke(data, (DXMouseEvent *)event); pdata->buttonStates[b] = BUTTON_DOWN; break; case BUTTON_UP: PanEndStroke(data, (DXMouseEvent *)event); pdata->buttonStates[b] = BUTTON_UP; break; default: break; } } break; default: break; } } static void PanStartStroke(void *data, DXMouseEvent *event) { PanData pdata = (PanData)data; /* * Just keep track of which button is * pressed and where it was pressed. */ int b = WHICH_BUTTON(event); if (b != NO_BUTTON) { pdata->buttonPositions[b].x = event->x; pdata->buttonPositions[b].y = event->y; } return; } static void PanEndStroke(void *data, DXMouseEvent *event) { int b = WHICH_BUTTON(event); PanData pdata = (PanData)data; if (! pdata) return; pdata->motionFlag = (event->state == BUTTON_MOTION); if (event->x != pdata->buttonPositions[b].x || event->y != pdata->buttonPositions[b].y) { float a, u[3], r[3], v[3]; float dx, dy; dx = event->x - pdata->buttonPositions[b].x; dy = event->y - pdata->buttonPositions[b].y; dx = -dx; dy = -dy; a = sqrt(pdata->up[0]*pdata->up[0] + pdata->up[1]*pdata->up[1] + pdata->up[2]*pdata->up[2]); u[0] = pdata->up[0]/a; u[1] = pdata->up[1]/a; u[2] = pdata->up[2]/a; v[0] = pdata->from[0] - pdata->to[0]; v[1] = pdata->from[1] - pdata->to[1]; v[2] = pdata->from[2] - pdata->to[2]; r[0] = v[2]*pdata->up[1] - v[1]*pdata->up[2]; r[1] = v[0]*pdata->up[2] - v[2]*pdata->up[0]; r[2] = v[1]*pdata->up[0] - v[0]*pdata->up[1]; a = sqrt(r[0]*r[0] + r[1]*r[1]+ r[2]*r[2]); r[0] /= a; r[1] /= a; r[2] /= a; v[0] = (-dx*r[0] + dy*u[0]) * pdata->grad; v[1] = (-dx*r[1] + dy*u[1]) * pdata->grad; v[2] = (-dx*r[2] + dy*u[2]) * pdata->grad; pdata->to[0] += v[0]; pdata->to[1] += v[1]; pdata->to[2] += v[2]; pdata->from[0] += v[0]; pdata->from[1] += v[1]; pdata->from[2] += v[2]; } pdata->buttonPositions[b].x = event->x; pdata->buttonPositions[b].y = event->y; return; } /***** Zoom *****/ static void ZoomStartStroke(void *, DXMouseEvent *); static void ZoomEndStroke(void *, DXMouseEvent *); typedef struct ZoomData { Object args; /* Interactor arguments */ int w, h; /* Width and height of window */ Object obj; /* Current object */ float to[3]; /* Current camera parameters */ float from[3]; float up[3]; int p; float init_fov, fov; float init_width, width; int motionFlag; struct { int x, y; } buttonPositions[3]; int buttonStates[3]; } *ZoomData; static void * ZoomInitMode(Object args, int w, int h, int *mask) { ZoomData zdata = (ZoomData)DXAllocateZero(sizeof(struct ZoomData)); if (! zdata) return NULL; if (args) { } /* * Grab the window size */ zdata->w = w; zdata->h = h; zdata->buttonStates[0] = BUTTON_UP; zdata->buttonStates[1] = BUTTON_UP; zdata->buttonStates[2] = BUTTON_UP; *mask = DXEVENT_LEFT; return (void *)zdata; } static void ZoomEndMode(void *data) { ZoomData zdata = (ZoomData)data; if (zdata) { if (zdata->args) DXDelete(zdata->args); if (zdata->obj) DXDelete(zdata->obj); } DXFree(data); } static void ZoomSetCamera(void *data, float to[3], float from[3], float up[3], int proj, float fov, float width) { int i; float dx = to[0] - from[0]; float dy = to[1] - from[1]; float dz = to[2] - from[2]; float vd = sqrt(dx*dx + dy*dy + dz*dz); ZoomData zdata = (ZoomData)data; /* * Grab the camera */ for (i = 0; i < 3; i++) zdata->to[i] = to[i], zdata->from[i] = from[i], zdata->up[i] = up[i]; zdata->p = proj; zdata->fov = zdata->init_fov = fov; zdata->width = zdata->init_width = width; } static int ZoomGetCamera(void *data, float to[3], float from[3], float up[3], int *proj, float *fov, float *width) { int i; ZoomData zdata = (ZoomData)data; /* * Return the camera */ for (i = 0; i < 3; i++) to[i] = zdata->to[i], from[i] = zdata->from[i], up[i] = zdata->up[i]; *proj = zdata->p; *fov = zdata->fov; *width = zdata->width; return 1; } static void ZoomSetRenderable(void *data, Object obj) { ZoomData zdata = (ZoomData)data; DXReference(obj); if (zdata->obj) DXDelete(zdata->obj); zdata->obj = obj; } static int ZoomGetRenderable(void *data, Object *obj) { ZoomData zdata = (ZoomData)data; if (zdata->obj) { *obj = zdata->obj; return 1; } else { *obj = NULL; return 0; } } static void ZoomEventHandler(void *data, DXEvent *event) { ZoomData zdata = (ZoomData)data; switch(event->any.event) { case DXEVENT_LEFT: case DXEVENT_MIDDLE: case DXEVENT_RIGHT: { int b = WHICH_BUTTON(event); switch (event->mouse.state) { case BUTTON_DOWN: ZoomStartStroke(data, (DXMouseEvent *)event); zdata->buttonStates[b] = BUTTON_DOWN; break; case BUTTON_MOTION: if (zdata->buttonStates[b] == BUTTON_UP) ZoomStartStroke(data, (DXMouseEvent *)event); else ZoomEndStroke(data, (DXMouseEvent *)event); zdata->buttonStates[b] = BUTTON_DOWN; break; case BUTTON_UP: ZoomEndStroke(data, (DXMouseEvent *)event); zdata->buttonStates[b] = BUTTON_UP; break; default: break; } } break; default: break; } } static void ZoomStartStroke(void *data, DXMouseEvent *event) { ZoomData zdata = (ZoomData)data; /* * Just keep track of which button is * pressed and where it was pressed. */ int b = WHICH_BUTTON(event); if (b != NO_BUTTON) { zdata->buttonPositions[b].x = event->x; zdata->buttonPositions[b].y = event->y; } return; } static void ZoomEndStroke(void *data, DXMouseEvent *event) { float dy; int b = WHICH_BUTTON(event); ZoomData zdata = (ZoomData)data; if (! zdata) return; zdata->motionFlag = (event->state == BUTTON_MOTION); dy = (event->y - zdata->buttonPositions[b].y) / ((float) zdata->h); dy = 1 - dy; if (event->x != zdata->buttonPositions[b].x || event->y != zdata->buttonPositions[b].y) { if (zdata->p) { zdata->fov += dy * zdata->init_fov; } else { zdata->width += dy * zdata->init_width; } } zdata->buttonPositions[b].x = event->x; zdata->buttonPositions[b].y = event->y; return; }