Newer
Older
#ifdef WIN32
# include "winjunk.h"
#endif
#include <string.h>
#include "Plot.H"
#include "sfont.h"
#include "shmem.h"
int Plot_add_drawer( Fl_Plot *plot,
void (*func)( Fl_Plot *, void *obj, void *arg ),
void *obj, void *arg, char *name, int id ) {
return plot->add_drawer( func, obj, arg, name, id );
}
int Plot_inpick( Fl_Plot *plot ) { return plot->inpick(); }
void Plot_setpick( Fl_Plot *, void (*pickcb)(Fl_Plot *, int hits, int ents, GLuint *buf) );
Fl_Plot::Fl_Plot(int x, int y, int w, int h, const char *label)
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
: Fl_Gl_Window(x,y,w,h,label) {
init();
end();
}
int Fl_Plot::add_drawer( void (*func)( Fl_Plot *, void *obj, void *arg ),
void *obj, void *arg, const char *name, int id )
{
if(id < 0) id = next_id();
int dno = withid( id );
if(dno < 0) {
if(ndrawers_ >= maxdrawers_) {
maxdrawers_ = ndrawers_*2 + 15;
int room = maxdrawers_ * sizeof(struct drawer);
drawers_ = (struct drawer *)
(drawers_==NULL ? malloc(room) : realloc(drawers_, room));
}
dno = ndrawers_++;
}
struct drawer *dp = &drawers_[dno];
dp->func = func;
dp->obj = obj;
dp->arg = arg;
dp->name = shmstrdup(name);
dp->id = id;
notify();
redraw();
return id;
}
void Fl_Plot::notify() {
if(notify_ != NULL)
(*notify_)( this, notifyarg_ );
}
int Fl_Plot::withid( int id ) const { // Which drawer[] slot is id in?
for(int dno = 0; dno < ndrawers_; dno++)
if(drawers_[dno].id == id)
return dno;
return -1;
}
int Fl_Plot::next_id() const {
int id;
for(id = 1; withid(id) >= 0; id++)
;
return id;
}
void draw_axis( float v0, float v1, float ybase, float ytick, float htext, char *just, char *title ) {
glColor3f( 1,1,1 );
glBegin( GL_LINES );
glVertex2f( 0,ybase );
glVertex2f( 1,ybase );
glVertex2f( 0,ybase );
glVertex2f( 0,ytick );
glVertex2f( 1,ybase );
glVertex2f( 1,ytick );
glEnd();
char lbl[16];
sprintf(lbl, "%.2g", v0);
Point at = { 0, ytick, 0 };
sfStrDrawTJ( lbl, htext, &at, NULL, just );
sprintf(lbl, "%.2g", v1);
at.x[0] = 1;
sfStrDrawTJ( lbl, htext, &at, NULL, just );
if(title) {
at.x[0] = .5;
at.x[1] = ytick + (ytick-ybase);
sfStrDrawTJ( title, htext, &at, NULL, "c" );
}
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
static float coordof( int pixel, int npix, float o0, float o1, float v0, float v1 ) {
float o = pixel * (o1-o0) / npix + o0;
return o * (v1-v0) + v0;
}
static float zoomof( int prec, float v, float zoom, float center ) {
char str[32];
float newv = center + (v - center) / zoom;
sprintf(str, "%.*g", prec, newv);
return atof(str);
}
static float choosezoom( float zoom, int pixel,
int npix, float o0, float o1, float *v0p, float *v1p ) {
float range = (*v1p - *v0p);
if(range == 0) return 1; /* unchanged */
float newv0, newv1, error;
float center = coordof( pixel, npix, o0, o1, *v0p, *v1p );
for(int prec = 0; prec < 4; prec++) {
newv0 = zoomof( prec, *v0p, zoom, center );
newv1 = zoomof( prec, *v1p, zoom, center );
error = 1 - zoom*(newv1 - newv0)/range;
if(fabs(error) < .1) break;
}
if(newv1 == newv0) return 1; /* degenerate after 4 digits?! */
*v0p = newv0;
*v1p = newv1;
return range / (newv1 - newv0);
}
float Fl_Plot::zoomview( float zoomfactor, int xev, int yev ) {
if(zoomfactor == 0) {
xrange( initx0_, initx1_ );
yrange( inity0_, inity1_ );
redraw();
return 1.0;
}
choosezoom( zoomfactor, h()-yev, h(), orthoy0_, orthoy1_, &y0_, &y1_ );
float got = choosezoom( zoomfactor, xev, w(), orthox0_, orthox1_, &x0_, &x1_ );
redraw();
return got;
}
if(!valid() || damage() || inpick()) {
/* Assume reshaped */
valid(1);
glViewport( 0, 0, w(), h() );
}
glClearDepth( 1.0 );
glColorMask( 1, 1, 1, 1 );
glClearColor( bgcolor_.x[0], bgcolor_.x[1], bgcolor_.x[2], 0 );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glDisable( GL_DEPTH_TEST );
glDisable( GL_LIGHTING );
glDisable( GL_TEXTURE_2D );
glDisable( GL_COLOR_MATERIAL );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
if(inpick()) {
GLint vp[4] = {0, 0, w(), h()};
gluPickMatrix( pickx_, picky_, pickwidth_, pickheight_, vp );
}
glOrtho( orthox0_, orthox1_, orthoy0_, orthoy1_, -1, 1 );
glMatrixMode( GL_MODELVIEW );
glPushMatrix();
glScalef( x1_ == x0_ ? 1 : 1/(x1_-x0_),
y1_ == y0_ ? 1 : 1/(y1_-y0_), 1 );
glTranslatef( -x0_, -y0_, 0 );
for(int i = 0; i < ndrawers_; i++) {
struct drawer *dp = &drawers_[i];
if(dp->func != NULL) {
if(inpick_) {
glLoadName( dp->id );
glPushName( 0 );
}
if(children() > 0)
Fl_Gl_Window::draw();
}
int Fl_Plot::handle(int ev) {
if(eventhook) {
/* Allow clients to pre-screen our events without subclassing */
switch((*eventhook)(this, ev)) {
case 1: return 1; /* pre-screener handled it */
case -1: return 0; /* pre-screener commands us to ignore it too */
default: break; /* Else just process event normally below */
}
}
if(Fl_Gl_Window::handle(ev))
return 1;
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
switch(ev) {
case FL_FOCUS: hasfocus_ = 1; return 1; // Yes, we want FL_KEYBOARD events
case FL_UNFOCUS: hasfocus_ = 0; return 1;
case FL_PUSH:
{ // Besides navigating, grab keyboard focus if we're clicked-on
if(!hasfocus_) take_focus();
}
case FL_DRAG:
case FL_RELEASE:
if(pickcb_ != NULL) {
dpickx_ = Fl::event_x();
dpicky_ = h() - Fl::event_y();
if(ev == FL_PUSH) {
do_pick( dpickx_, dpicky_ );
pickneeded_ = 0;
} else {
if(!pickneeded_) {
pickneeded_ = 1;
Fl::add_idle( Fl_Plot::idlepick, (void *)this );
}
}
return 1;
}
/* Maybe do right-button pick? */
return 0;
case FL_ENTER:
take_focus();
return 1;
case FL_KEYBOARD:
if(Fl::event_text() == NULL || Fl::event_text()[0] == '\0')
return 0;
int c = Fl::event_text()[0];
switch(c) {
case 'p':
case 'P':
do_pick( Fl::event_x_root() - x_root(),
y_root() + h() - Fl::event_y_root() );
break;
case 'V': zoomview( 1.33, Fl::event_x(), Fl::event_y() ); break;
case 'v': zoomview( 1/1.33, Fl::event_x(), Fl::event_y() ); break;
case 'w': zoomview( 0 );
case '\033': exit(0); /* ESC */
default: c = 0;
}
if(Fl::event_key(FL_Home)) {
zoomview( 0 );
return 1;
}
return c==0 ? 0 : 1;
}
return 0;
}
void Fl_Plot::xrange( float x0, float x1 ) {
initx0_ = x0_ = x0;
initx1_ = x1_ = x1;
notify(); redraw();
}
void Fl_Plot::yrange( float y0, float y1 ) {
inity0_ = y0_ = y0;
inity1_ = y1_ = y1;
notify(); redraw();
}
void Fl_Plot::xtitle( const char *str ) {
if(xtitle_) Free(xtitle_);
xtitle_ = str ? shmstrdup(str) : NULL;
notify();
redraw();
}
void Fl_Plot::ytitle( const char *str ) {
if(ytitle_) Free(ytitle_);
ytitle_ = str ? shmstrdup(str) : NULL;
notify();
redraw();
}
void Fl_Plot::picksize( float width, float height )
{
pickwidth_ = width;
pickheight_ = height;
}
void Fl_Plot::pickbuffer( int words, GLuint *buf )
{
picknents_ = words;
pickbuf_ = buf;
}
void Fl_Plot::picker( void (*pickcb)(Fl_Gl_Window *, int, int, GLuint *, void *arg), void *arg )
{
pickcb_ = pickcb;
pickarg_ = arg;
}
int Fl_Plot::pickresults( int *nentp, GLuint **bufp )
{
if(nentp) *nentp = picknents_;
if(bufp) *bufp = pickbuf_;
return pickhits_;
}
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
int Fl_Plot::do_pick( float xpick, float ypick )
{
make_current();
glSelectBuffer( picknents_, pickbuf_ );
int ok = glRenderMode( GL_SELECT );
if(ok != 0) {
fprintf(stderr, "Trouble in do_pick: glRenderMode( GL_SELECT ) = %d\n", ok);
ok = glRenderMode( GL_SELECT );
fprintf(stderr, "Retry: %d\n", ok);
}
glPushName(0);
inpick_ = 1;
pickx_ = xpick;
picky_ = ypick;
draw();
inpick_ = 0;
glPopName();
pickhits_ = glRenderMode( GL_RENDER );
if(pickcb_)
(*pickcb_)( this, pickhits_, picknents_, pickbuf_, pickarg_ );
valid(0);
return pickhits_;
}
int Fl_Plot::snapshot( int x, int y, int w, int h, void *packedrgb )
{
make_current();
glPixelStorei( GL_PACK_ALIGNMENT, 1 );
glReadBuffer( GL_FRONT );
glReadPixels(x, y, w, h, GL_RGB, GL_UNSIGNED_BYTE, packedrgb);
return 1; // Might return whether this window was properly uncovered?
}
// Take snapshot into caller-supplied buffer, w*h*3 bytes long
void Fl_Plot::idlepick( void *vthis ) {
Fl_Plot *me = (Fl_Plot *)vthis;
if(me->pickneeded_) {
me->do_pick( me->dpickx_, me->dpicky_ );
me->pickneeded_ = 0;
Fl::remove_idle( Fl_Plot::idlepick, vthis );
}
}