/***********************************************************************/
/* 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 <dxconfig.h>


#ifndef tdmInteractor_h
#define tdmInteractor_h
/*---------------------------------------------------------------------------*\
 $Source: /home/gda/dxcvs/dx/src/exec/hwrender/hwInteractor.h,v $
  Author: Mark Hood

  This include file defines core data structures used by the direct
  interactor implementations.

\*---------------------------------------------------------------------------*/

#include <stdio.h>
#include <math.h>

/* SGI */
#if defined(sgi)
#ifndef Int32
#define Int32 long
#endif
#ifndef Int16
#define Int16 short
#endif
#endif

#ifdef STANDALONE 
#define tdmAllocateLocal malloc
#define tdmFree free
#endif

/* 
 * The following must match UserInteractors.h
 */
#define DX_LEFT_BUTTON_MASK     0x01
#define DX_MIDDLE_BUTTON_MASK   0x02
#define DX_RIGHT_BUTTON_MASK    0x04

#define INTERACTOR_BUTTON_UP	1
#define INTERACTOR_BUTTON_DOWN  2


typedef struct tdmInteractorS tdmInteractorT, *tdmInteractor ;
typedef struct tdmInteractorWinS tdmInteractorWinT, *tdmInteractorWin ;
typedef struct tdmInteractorCamS tdmInteractorCamT, *tdmInteractorCam ;
typedef void (*tdmViewEchoFunc) (tdmInteractor, void *, float[4][4], int) ;
typedef struct tdmInteractorEchoS tdmInteractorEchoT, *tdmInteractorEcho ;

typedef enum {tdmBackBufferDraw, tdmFrontBufferDraw,
	      tdmBothBufferDraw, tdmAuxEchoMode, tdmViewEchoMode}
tdmInteractorRedrawMode ;

typedef enum {tdmNullEcho, tdmGlobeEcho, tdmGnomonEcho}
tdmEchoType ;

typedef enum {tdmXYPlaneRoll, tdmZTwirl}
tdmRotateModel ;

typedef enum {tdmProbeCursor, tdmRoamCursor, tdmPickCursor}
tdmCursorType ;

/*
 *  Following constants must have the same values as their Picture widget
 *  counterparts (switch Xm and tdm prefixes).
 */

#define tdmCONSTRAIN_NONE       0
#define tdmCONSTRAIN_X          1
#define tdmCONSTRAIN_Y          2
#define tdmCONSTRAIN_Z          3

#define tdmSLOW_CURSOR          0
#define tdmMEDIUM_CURSOR        1
#define tdmFAST_CURSOR          2

#define tdmCURSOR_CREATE        0
#define tdmCURSOR_DELETE        1
#define tdmCURSOR_MOVE          2
#define tdmCURSOR_SELECT        3
#define tdmCURSOR_DRAG          4
#define tdmROTATION_UPDATE      5

#define tdmPCR_TRANSLATE_SPEED  5
#define tdmPCR_ROTATE_SPEED     6

#define tdmLOOK_LEFT            0
#define tdmLOOK_RIGHT           1
#define tdmLOOK_UP              2
#define tdmLOOK_DOWN            3
#define tdmLOOK_BACKWARD        4
#define tdmLOOK_FORWARD         5
#define tdmLOOK_ALIGN           6

/*
 *  Data structure returned by tdmEndStroke().
 */

typedef struct tdmInteractorReturnS {
  tdmInteractor I ;
  int id ;
  int reason ;
  float x, y, z ;
  float to[3] ;
  float from[3] ;
  float dist ;
  float up[3] ;
  float view[4][4] ;
  float matrix[4][4] ;
  float zoom_factor ;
  int change ;
} tdmInteractorReturn, *tdmInteractorReturnP ;

/*
 *  Interactor definition.
 */

struct tdmInteractorS {
  void (*DoubleClick) (tdmInteractor, int, int, tdmInteractorReturnP);
  void (*StartStroke) (tdmInteractor, int, int, int, int) ;
  void (*StrokePoint) (tdmInteractor, int, int, int, int) ;
  void (*EndStroke)   (tdmInteractor, tdmInteractorReturnP) ;
  void (*KeyStruck)    (tdmInteractor, int, int, char, int) ;
  void (*ResumeEcho)  (tdmInteractor, tdmInteractorRedrawMode) ;
  void (*EchoFunc)    (tdmInteractor, void *, float[4][4], int) ;
  void (*Destroy)     (tdmInteractor) ;

  void (*Config)() ;         /* parameters vary: beware type conversions */
  void (*restoreConfig)() ;  /* parameters vary: beware type conversions */

  tdmInteractorWin cdata ;   /* pointer to common data */
  void *pdata ;              /* pointer to private data */
  void *udata ;              /* pointer to user data */
  tdmInteractorEcho edata;   /* pointer to port layer echo functions */

  /* following interactor references are used by the Group interactor */
  tdmInteractor btn1 ;
  tdmInteractor btn2 ;
  tdmInteractor btn3 ;
  int is_group ;

  /* list of associated interactor echos */
  tdmInteractor aux ;
  int is_aux ;

  /* allocation bookkeeping */
  int used ;

  /* event mask */
  int eventMask;
} ;

/*
 *  Data shared among all of window's interactors.
 */

struct tdmInteractorCamS {
  /* global box used for manipulating 3D cursors, supplied by application */
  float box[8][3] ;
  /* global 3D cursor movement constraint */
  int cursor_constraint ;
  /* global 3D cursor speed specification */
  int cursor_speed ;

  /* view coordinate system definition, supplied by application */
  float from[3], to[3], up[3] ;
  /* distance between from point and to point */
  float vdist ;
  /* projection type, 1 if perspective, 0 if ortho */
  int projection ;
  /* field of view, width */
  float fov, width ;
  /* near, far clip planes */
  float Near, Far ;

  /* has the view coordinate system been set? */
  int view_coords_set ;
  /* has anybody changed view data? */
  int view_state ;
  /* has anybody changed box data? */
  int box_state ;

  /* width, height, depth, and center of window in screen coords */
  long d, w, h, cx, cy ;
  /* lower left corner of window relative to screen and screen dimensions */
  int ox, oy, xmaxscreen, ymaxscreen ;
  /* aspect ratio of image */
  float aspect ;
  /* view matrix */
  float viewXfm[4][4] ;
  /* projection matrix */
  float projXfm[4][4] ;
  /* screen transform */
  float scrnXfm[4][4] ;
  /* draw mode and Z buffer modes */
  int drawmode, zdraw, zbuffer ;

  /* screen coordinates of last input */
  int xlast, ylast ;

  /* copy of pointer to background image and image dimensions */
  void *image ;
  int iw, ih ;

  /* handle to graphics API context */
  /* NOTE: Do not access this through CDATA, use DEFPORT(I_PORT_HANDLE) and
   * PORT_CTX.
   */
  void *phP ;

  /* handle to graphics API echo functions */
  void *echoFuncs;

  /* handle to software transformation stack */
  void *stack ;

  /* pointer to next camera in undo/redo stack */
  tdmInteractorCam next ;
} ;

struct tdmInteractorWinS {
  /* camera stack and redo stack pointers */
  tdmInteractorCam Cam ;
  tdmInteractorCam redo ;

  /* an array of interactors */
  tdmInteractor *Interactors ;
  int numUsed ;
  int numAllocated ;

  /* handle to interactor storage */
  void *extents ;
} ;

/*
 *  Interactor data is accessed through these macros.
 */

#define FUNC(interactor,f) ((interactor)->f)
#define CALLFUNC(interactor,f) (*FUNC(interactor,f))

#define UDATA(interactor) ((interactor)->udata)
#define WINDOW(interactor) ((interactor)->cdata)
#define PRIVATE(interactor) ((interactor)->pdata)

#define BTN1(interactor) ((interactor)->btn1)
#define BTN2(interactor) ((interactor)->btn2)
#define BTN3(interactor) ((interactor)->btn3)
#define IS_GROUP(interactor) ((interactor)->is_group)
#define IS_USED(interactor) ((interactor)->used)
#define AUX(interactor) ((interactor)->aux)
#define IS_AUX(interactor) ((interactor)->is_aux)
#define EVENT_MASK(interactor)  ((interactor) ? (interactor)->eventMask : 0)

#define DEFDATA(interactor,ptype) \
register tdmInteractorCam _cdata = ((interactor)->cdata->Cam) ; \
register ptype *_pdata = (ptype *) ((interactor)->pdata) ; \
double _w 

#define PDATA(foo) (_pdata->foo)
#define CDATA(foo) (_cdata->foo)
#define I_PORT_HANDLE (_cdata->phP)

/*
 *  Misc. macros for interactor implementations.
 */

#define VCOPY(t,f) (bcopy ((char *)(f), (char *)(t), sizeof(float [3])))
#define MCOPY(t,f) (bcopy ((char *)(f), (char *)(t), sizeof(float [4][4])))
#define DMCOPY(t,f) (bcopy ((char *)(f), (char *)(t), sizeof(double [4][4])))
#define CLIPPED(x,y) ((x)<0 || (y)<0 || (x)>(CDATA(iw)-1) || (y)>(CDATA(ih)-1))

/* used to ensure pixel reads and writes are on physical screen */
#define XSCREENCLIP(x) \
(CDATA(ox)+x < 0 ? -CDATA(ox) : \
(CDATA(ox)+x > CDATA(xmaxscreen) ? CDATA(xmaxscreen)-CDATA(ox) : x))
#define YSCREENCLIP(y) \
(CDATA(oy)+y < 0 ? -CDATA(oy) : \
(CDATA(oy)+y > CDATA(ymaxscreen) ? CDATA(ymaxscreen)-CDATA(oy) : y))

#define VSUB(r, a, b) {\
r[0] = a[0] - b[0] ; \
r[1] = a[1] - b[1] ; \
r[2] = a[2] - b[2] ; }

#define CROSS(r, a, b) {\
r[0] = a[1]*b[2] - a[2]*b[1] ; \
r[1] = a[2]*b[0] - a[0]*b[2] ; \
r[2] = a[0]*b[1] - a[1]*b[0] ; }

#define XFORM_VECTOR(M, in, out) {\
out[0] = in[0]*M[0][0] + in[1]*M[1][0] + in[2]*M[2][0] ; \
out[1] = in[0]*M[0][1] + in[1]*M[1][1] + in[2]*M[2][1] ; \
out[2] = in[0]*M[0][2] + in[1]*M[1][2] + in[2]*M[2][2] ; }

#define XFORM_COORDS(M, x, y, z, nx, ny, nz) {\
nx = x*M[0][0] + y*M[1][0] + z*M[2][0] + M[3][0] ; \
ny = x*M[0][1] + y*M[1][1] + z*M[2][1] + M[3][1] ; \
nz = x*M[0][2] + y*M[1][2] + z*M[2][2] + M[3][2] ; \
if (CDATA(projection)) { \
   _w = x*M[0][3] + y*M[1][3] + z*M[2][3] + M[3][3] ; \
   if (_w) { \
     nx /= _w ; ny /= _w ; nz /= _w ;}}}

#define YFLIP(y) ((CDATA(h) - (y)) - 1)

#ifndef MAX
#define MAX(x,y) ((x) > (y)? (x): (y))
#endif
#ifndef MIN
#define MIN(x,y) ((x) < (y)? (x): (y))
#endif

#ifndef RAD2DEG
#define RAD2DEG(r) (180.0*(r)/M_PI)
#endif
#ifndef DEG2RAD
#define DEG2RAD(d) (M_PI*(d)/180.0)
#endif

#ifndef LENGTH
#define LENGTH(V) (sqrt((double)(V[0]*V[0] + V[1]*V[1] + V[2]*V[2])))
#endif

#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif

#ifdef MJHDEBUG
#define DPRINT(str) {fprintf (stderr, str); fflush(stderr);}
#define DPRINT1(str,a) {fprintf (stderr, str, a); fflush(stderr);}
#define VPRINT(V) fprintf (stderr, "%12f %12f %12f", V[0], V[1], V[2])
#define SPRINT(S) fprintf (stderr, "%12f %12f %12f", S.x, S.y, S.z)
#define CPRINT(C) fprintf (stderr, "%12f %12f %12f", C.r, C.g, C.b) ;
#define MPRINT(M) \
 fprintf \
    (stderr, \
     ": %17f %17f %17f %17f\n: %17f %17f %17f %17f\n: %17f %17f %17f %17f\n: %17f %17f %17f %17f", \
     M[0][0], M[0][1], M[0][2], M[0][3], \
     M[1][0], M[1][1], M[1][2], M[1][3], \
     M[2][0], M[2][1], M[2][2], M[2][3], \
     M[3][0], M[3][1], M[3][2], M[3][3]) ;
#else
#define DPRINT(str) 0
#define DPRINT1(str,a) 0
#define VPRINT(V) 0
#define SPRINT(S) 0
#define CPRINT(C) 0
#define MPRINT(M) 0
#endif
    
/*
 *  Following declarations used only by interactor implementations.
 */

tdmInteractor _dxfAllocateInteractor (tdmInteractorWin, int) ;
void _dxfDeallocateInteractor(tdmInteractor) ;
void _dxfNullDoubleClick (tdmInteractor, int, int, tdmInteractorReturn *) ;
void _dxfNullStartStroke (tdmInteractor, int, int, int, int) ;
void _dxfNullStrokePoint (tdmInteractor, int, int, int, int ) ;
void _dxfNullEndStroke (tdmInteractor, tdmInteractorReturn *) ;
void _dxfNullResumeEcho (tdmInteractor, tdmInteractorRedrawMode) ;
void _dxfNullKeyStruck(tdmInteractor, int, int, char, int);

/*
 *  Public interface.
 */

#define tdmDoubleClick(I,x,y,R) {if((I)) (*((I)->DoubleClick)) (I,x,y,R) ;}
#define tdmStartStroke(I,x,y,b,s) {if((I)) (*((I)->StartStroke)) (I,x,y,b,s) ;}
#define tdmStrokePoint(I,x,y,type,s) {if((I)) (*((I)->StrokePoint)) (I,x,y,type,s) ;}
#define tdmEndStroke(I,R) {if((I)) (*((I)->EndStroke)) (I,R) ;}
#define tdmKeyStruck(I,x,y,c,s) {if((I)) (*((I)->KeyStruck)) (I,x,y,c,s) ;}
#define tdmResumeEcho(I,m) {if((I)) (*((I)->ResumeEcho)) (I,m) ;}
#define tdmDestroyInteractor(I) {if((I)) (*((I)->Destroy)) (I) ;}

tdmInteractorWin _dxfInitInteractors (void *ctx, void *stack) ;
void _dxfRedrawInteractorEchos (tdmInteractorWin W) ;
void _dxfDestroyAllInteractors (tdmInteractorWin W) ;
void _dxfAssociateInteractorEcho (tdmInteractor T, tdmInteractor A) ;
void _dxfDisassociateInteractorEcho (tdmInteractorWin W, tdmInteractor A) ;

tdmInteractor _dxfCreateUserInteractor (tdmInteractorWin W, tdmViewEchoFunc E, void *udata) ;
tdmInteractor _dxfCreateZoomInteractor (tdmInteractorWin W) ;
tdmInteractor _dxfCreatePanZoomInteractor (tdmInteractorWin W) ;
tdmInteractor _dxfCreateCursorInteractor (tdmInteractorWin W, tdmCursorType C) ;
tdmInteractor _dxfCreateRotationInteractor
    (tdmInteractorWin W, tdmEchoType E, tdmRotateModel M) ;
tdmInteractor _dxfCreateViewRotationInteractor
    (tdmInteractorWin W, tdmViewEchoFunc E, tdmRotateModel M, void *udata) ;
tdmInteractor _dxfCreateNavigator
    (tdmInteractorWin W, tdmViewEchoFunc func, void *data) ;
tdmInteractor _dxfCreateInteractorGroup
    (tdmInteractorWin W, tdmInteractor btn1, tdmInteractor btn2,
    tdmInteractor btn3) ;

int _dxfPushInteractorCamera (tdmInteractorWin W) ;
int _dxfPopInteractorCamera (tdmInteractorWin W) ;
int _dxfRedoInteractorCamera (tdmInteractorWin W) ;

void _dxfInteractorViewChanged (tdmInteractorWin W) ;
void _dxfSetInteractorBox (tdmInteractorWin W, float box[8][3]) ;
void _dxfSetInteractorWindowSize (tdmInteractorWin W, int width, int height) ;
void _dxfSetInteractorViewDepth (tdmInteractorWin W, int depth) ;
void _dxfSetInteractorImage (tdmInteractorWin W, int w, int h, void *image) ;
void _dxfSetInteractorViewInfo (tdmInteractorWin W,
                                float *f, float *t, float *u, float dist,
                                float fov, float width, float aspect, int proj,
                                float Near, float Far) ;
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) ;

void _dxfSetCursorSpeed (tdmInteractorWin W, int speed) ;
void _dxfSetCursorConstraint (tdmInteractorWin W, int constraint) ;
void _dxfCursorInteractorChange (tdmInteractor I, int id, int reason,
                                 float x, float y, float z) ;

void _dxfCursorInteractorVisible (tdmInteractor I) ;
void _dxfCursorInteractorInvisible (tdmInteractor I) ;
void _dxfRotateInteractorVisible (tdmInteractor I) ;
void _dxfRotateInteractorInvisible (tdmInteractor I) ;
void _dxfSetNavigateTranslateSpeed (tdmInteractor I, float speed) ;
void _dxfSetNavigateRotateSpeed (tdmInteractor I, float speed) ;
void _dxfSetNavigateLookAt (tdmInteractor I, int direction, float angle,
                            float current_view[3][3], 
                            float viewDirReturn[3], float viewUpReturn[3]) ;
void _dxfUpdateInteractorGroup (tdmInteractor I,
                                tdmInteractor btn1,
                                tdmInteractor btn2,
                                tdmInteractor btn3) ;

void _dxfResetCursorInteractor (tdmInteractor I) ;
void _dxfResetNavigateInteractor (tdmInteractor I) ;

void _dxfSetUserInteractorMode(tdmInteractor I, dxObject args);


#endif /* tdmInteractor_h */

