#ifndef _GVIEW_H #define _GVIEW_H /* * Somewhat geomview-style OpenGL viewer for FLTK * This is analogous to vtk's RenderWindowInteractor */ #include <GL/gl.h> /* for GLuint */ #include <GL/glu.h> #include <stdio.h> #define GV_ID_CAMERA (-1) #ifndef __cplusplus typedef struct _Fl_Gview Fl_Gview; int Gview_add_drawer( Fl_Gview *gview, void (*func)( Fl_Gview *, void *obj, void *arg ), void *obj, void *arg, int id ); void Gview_get_o2w( Fl_Gview *gview, Matrix *pos, int drawer ); /* returns parent */ void Gview_set_o2w( Fl_Gview *gview, CONST Matrix *pos, int drawer ); int Gview_inpick( Fl_Gview *gview ); /* for plain-C drawers */ void Gview_setpick( Fl_Gview *gview, void (*pickcb)(Fl_Gview *, int hits, int ents, GLuint *buf) ); #else /* C++ */ #include <stdlib.h> #include <FL/Fl.H> #include <FL/Fl_Gl_Window.H> #include "geometry.h" enum Gv_Nav { GV_FLY, GV_ORBIT, GV_ROTATE, GV_TRANSLATE, GV_LASTENUM }; enum Gv_Stereo { GV_MONO, GV_REDCYAN, GV_CROSSEYED, /* not implemented yet 4/00 */ GV_QUADBUFFERED, }; struct GNumber { int has; /* 0 if not, -1 or +1 (sign) if present */ int val; int expon; /* digits after decimal point */ int prefix; /* prefix character (e.g. 'c' or 'g') */ void clear() { has = val = expon = prefix = 0; } int addchar(int c) { switch(c) { case '.': expon = 1; if(!has) has = 1, val = 0; return 1; case '-': has = -1; val = expon = 0; return 1; case 'c': case 'g': prefix = c; has = 1; val = expon = 0; return 1; } if(c >= '0' && c <= '9') { if(!has) { has = 1; val = expon = 0; } if(expon) expon++; val = 10*val + c - '0'; return 1; } return 0; } int tvalue( int defval = 0 ) { return has && prefix=='c' ? ~value(defval) : value(defval); } int value( int defval = 0 ) { return has ? has*val : defval; } float fvalue( float defval = 0 ) { if(!has) return defval; float v = has * val; while(--expon > 0) v *= 0.1; return v; } }; class Fl_Gview : public Fl_Gl_Window { public: Fl_Gview(int x, int y, int h, int w, const char *label = 0); int add_drawer( void (*func)( Fl_Gview *, void *obj, void *arg ), void *obj, void *arg, char *name = NULL, int id = -1 ); int next_id() const; void notifier( void (*func)( Fl_Gview *, void * ), void * ); int (*msg)( const char *fmt, ... ); int (*eventhook)( Fl_Gview *, int ev ); const Matrix *Tc2w() const; const Matrix *Tw2c() const; void Tc2w( const Matrix * ); void Tw2c( const Matrix * ); void lookvec( int row, const Point *vec ); void reset( int obj = GV_ID_CAMERA ); void usesubcam( int on ) { use_subc_ = on; } int usesubcam() const { return use_subc_; }; void Tc2subc( Matrix *newT ) { Tc2subc_ = *newT; } const Matrix *Tc2subc() const { return &Tc2subc_; } void subc_lrbt( float lrbt[4] ); const float *subc_lrbt() const { return subclrbt_; } const Matrix *To2w( int drawerno ) const; /* returns &Tidentity if invalid */ int To2w( int drawerno, const Matrix * ); /* returns zero if invalid */ int objparent( int drawerno ) const; /* parent object id (0=world, -1=camera) */ void objparent( int drawerno, int id ); int perspective() { return persp_; } void perspective(int persp); float focallen() const { return focallen_; } void focallen( float dist ); float halfyfov() const { return halfyfov_; } ; void halfyfov( float half_dist_at_focallen ); float angyfov() const; void angyfov( float degrees ); float nearclip() const { return near_; }; void nearclip(float newnear); float farclip() const { return far_; }; void farclip(float newfar); float aspect() const { return aspect_; } void aspect( float newasp ); /* sets window aspect ratio (xsize/ysize) */ enum Gv_Stereo stereo() const { return stereo_; } void stereo( enum Gv_Stereo setting ) { stereo_ = setting; redraw(); } float stereosep() const { return stereosep_; } void stereosep( float tanhalfangle ) { stereosep_ = tanhalfangle; redraw(); } int inpick() const { return inpick_; } // draw()ers: am I in GL_SELECT mode? void picksize( float width, float height ); void pickbuffer( int words, GLuint *buf ); void picker( void (*pickcb)(Fl_Gview *, int, int, GLuint *, void *arg), void *arg ); void (*picker( void **argp = 0 ))(Fl_Gview *, int, int, GLuint *, void *arg); int pickresults( int *wordsp, GLuint **bufp ); /* returns num hits, too */ int do_pick( float pickx, float picky ); /* Calls back function given by picker() */ int snapshot( int x, int y, int w, int h, void *packedrgb ); // Take snapshot into caller-supplied buffer, w*h*3 bytes long const Point *center() const { return &pcenw_; } void center( const Point *pcenw ); int owncoords() { return owncoords_; } void owncoords(int useown); void nav( enum Gv_Nav navmode ); enum Gv_Nav nav() const { return nav_; } /* Do nav ops apply to the target? !movingtarget() means * that all nav applies to the camera, even r and t. */ int movingtarget() const { return movingtarget_; } void movingtarget(int v) { movingtarget_ = v; notify(); } void target( int drawerno ) { if(drawerno >= GV_ID_CAMERA && drawerno < ndrawers_ && drawerno != target_) { target_ = drawerno; notify(); } } int target() const { return target_; } int ndrawers() const { return ndrawers_; } float zspeed; /* for fly, translate modes */ GNumber num; /* accumulates numeric keyboard input */ int retarget() { if(num.has) target( num.tvalue() ); return target(); } char *dname( int drawerno ); void bgcolor( Point *rgb ) { bgcolor_ = *rgb; redraw(); } const Point *bgcolor() const { return &bgcolor_; } virtual void draw(); virtual int handle(int ev); static void idlepick( void *me ); protected: void glprojection( float nearclip, float farclip, const Matrix *postproj ); Point qc2w_; Matrix Tc2w_, Tw2c_; int persp_; enum Gv_Stereo stereo_; float focallen_, halfyfov_, near_, far_; float aspect_, stereosep_; Matrix Tc2subc_; float subclrbt_[4]; // subcam frustum tan(left),tan(right),tan(bot),tan(top) int use_subc_; int target_; int movingtarget_; void (*pickcb_)( Fl_Gview *, int hits, int nents, GLuint *buf, void *arg ); int inpick_; float pickx_, picky_, pickwidth_, pickheight_; int picknents_, pickhits_; GLuint *pickbuf_; GLuint tpickbuf[1024]; void *pickarg_; /* We handle mouse-driven picking in an idle-callback, to avoid * getting behind if there are many events. */ float dpickx_, dpicky_; int pickneeded_; int hasfocus_; void (*notify_)( Fl_Gview *, void *); void *notifyarg_; void notify(); /* navigation settings */ enum Gv_Nav nav_; /* nav mode */ int owncoords_; /* own coordinates */ Point pcenw_; /* center pt (world coords) for orbit/rotate */ int nullthresh_; /* null-motion threshold in pixels */ /* Nav status -- where current mouse drag started */ int evx_, evy_, evslow_, evzaxis_, evconstrain_; Matrix evTobj2w_, evTc2w_, evTw2c_; struct drawer { void (*func)(Fl_Gview *, void *obj, void *arg); void *obj, *arg; Matrix To2w; char *name; int id; int parent; /* 0=world, GV_ID_CAMERA=attach-to-camera */ int objclip; /* object has custom clip planes? */ float objnear, objfar; }; int ndrawers_, maxdrawers_; struct drawer *drawers_; int withid( int id ) const; void draw_scene( int needproj, const Matrix *postproj ); Point bgcolor_; /* OK, it's not a Point, we just want 3 components */ void do_nav(int ev, int slow, int zaxis, int constrained); void start_nav( int navtarget ); /* Save event-position, camera, target-position */ void init() { msg = printf; eventhook = NULL; ndrawers_ = maxdrawers_ = 0; drawers_ = NULL; owncoords_ = 0; persp_ = 1; stereo_ = GV_MONO; stereosep_ = .05; target_ = GV_ID_CAMERA; movingtarget_ = 0; focallen_ = 3; halfyfov_ = .5; /* 60-degree default FOV */ near_ = .1; far_ = 100; zspeed = 1; inpick_ = 0; pickwidth_ = 2, pickheight_ = 2; picknents_ = sizeof(tpickbuf) / sizeof(tpickbuf[0]); pickbuf_ = tpickbuf; pickarg_ = NULL; notify_ = NULL; notifyarg_ = NULL; pcenw_.x[0] = pcenw_.x[1] = pcenw_.x[2] = 0; bgcolor_.x[0] = bgcolor_.x[1] = bgcolor_.x[2] = .2; nullthresh_ = 2; hasfocus_ = 0; use_subc_ = 0; Tc2subc_ = Tidentity; subclrbt_[0] = subclrbt_[2] = -1; subclrbt_[1] = subclrbt_[3] = 1; nav( GV_ORBIT ); reset( GV_ID_CAMERA ); } }; #endif /* C++ */ #endif /*_GVIEW_H*/