Newer
Older
#include <stdio.h>
#include <stdlib.h>
#ifdef WIN32
# include "winjunk.h"
#endif
#include <GL/gl.h>
#include "Gview.H"
#include "partiview.H"
#include "geometry.h"
#include "shmem.h"
#include <string.h>
#include <stdarg.h>
#include <math.h>
#include <errno.h>
#include "partiviewc.h"
#include "findfile.h"
#include <FL/fl_draw.H>
#include <FL/fl_file_chooser.H>
struct _ppui ppui;
struct stuff *stuffs[MAXSTUFF];
static int specks_commandstr( struct stuff **stp, const char *str ) {
if(stp == NULL || *stp == NULL || str == NULL)
return 0;
#define MAXARGS 128
char *av[MAXARGS];
int ac;
char *txt = (char *)alloca( strlen(str) + 1 );
char *s = txt;
strcpy(txt, str);
for(ac = 0; ac < MAXARGS-1; ac++) {
av[ac] = strtok(s, " \t\n");
if(av[ac] == NULL) break;
s = NULL;
}
av[ac] = NULL;
return specks_parse_args( stp, ac,av);
}
int specks_commandfmt( struct stuff **stp, const char *fmt, ... ) {
char cmd[1024];
int ok;
va_list args;
va_start(args, fmt);
vsprintf(cmd, fmt, args);
va_end(args);
ok = specks_commandstr( stp, cmd );
if(ok) parti_redraw();
return ok;
}
/* =================================================================== */
void pp_nav_init(Fl_Menu_Button *);
int pp_viewevent_cb( Fl_Gview *, int ev );
void pp_ui_init() {
pp_nav_init(ppui.nav);
/* ppui.cmd->handle_cb = pp_cmd_handle_cb; No, this doesn't work yet */
ppui.view->eventhook = pp_viewevent_cb;
}
void pp_clk_init() {
ppui.clk = NewN( SClock, 1 );
clock_init( ppui.clk );
clock_set_speed( ppui.clk, 1.0 );
ppui.clk->continuous = 1; // is this used?
ppui.clk->walltimed = 1;
}
void pp_ui_postinit() {
parti_set_timebase( ppui.st, 0.0 );
parti_set_timestep( ppui.st, 0.0 );
parti_set_running( ppui.st, 0 );
parti_set_fwd( ppui.st, 1 );
ppui.stepspeed->logstyle( FL_LOG_LINEAR );
ppui.stepspeed->truebounds( 1.0e-6, 10.0 );
ppui.stepspeed->truevalue( clock_speed( ppui.clk ) );
void pp_cmd_cb( HistInput* inp, void * ) {
if(inp->hist())
inp->hist()->addline( inp->value(), 0 );
specks_commandstr( &ppui.st, inp->value() );
ppui_refresh( ppui.st );
parti_redraw();
}
static enum Gv_Nav codes[] = { GV_FLY, GV_ORBIT, GV_ROTATE, GV_TRANSLATE };
static char *navtitles[] = {"[f]ly","[o]rbit","[r]ot","[t]ran"};
void pp_nav_init(Fl_Menu_Button *m) {
m->add("[f]ly|[o]rbit|[r]ot|[t]ran");
for(int i = m->size(); --i >= 0; )
(((Fl_Menu_Item *)(m->menu()))[i]).labelcolor( m->labelcolor() );
}
void pp_nav_cb(Fl_Menu_Button* m, struct stuff **vst) {
int v = m->value();
if(v >= 0 && v < COUNT(codes))
ppui.view->nav( codes[v] );
}
void pp_obj_cb(Fl_Menu_Button* m, void *) {
parti_object( m->text(), &ppui.st, 0 );
}
void pp_objtog_cb(Fl_Button* b, void *) {
int objno = 1;
sscanf(b->label(), "g%d", &objno);
if(objno<0||objno>=MAXSTUFF||stuffs[objno]==NULL)
return;
parti_object( b->label(), &ppui.st, 0 );
b->value(1);
} else {
stuffs[objno]->useme = !stuffs[objno]->useme;
}
parti_redraw();
}
void pp_slum_cb(Fl_Value_Slider* sl, struct stuff ** ) {
struct stuff *st = ppui.st;
int cd = st->curdata, by = st->sizedby;
if((unsigned int)cd >= MAXFILES) cd = 0;
if((unsigned int)by >= MAXVAL+1) by = 0;
struct valdesc *vd = &st->vdesc[cd][by];
vd->lum = pow(10., sl->value());
ppui.view->redraw();
}
switch(Fl::event_button()) {
case FL_RIGHT_MOUSE: sign *= 10; break;
case FL_MIDDLE_MOUSE: sign *= 0.1; break;
}
clock_step( ppui.st->clk, sign );
parti_redraw();
}
void pp_run_cb( Fl_Button *runbtn, void *stepsign ) {
clock_set_fwd( ppui.st->clk, (int)stepsign );
parti_set_running( ppui.st, runbtn->value() );
parti_set_timestep( ppui.st, v + ppui.timebasetime );
parti_redraw();
}
}
void pp_timebaseinput_cb( Fl_Input *inp, void * ) {
double newbase;
}
}
void pp_jog_cb( Fl_Roller *rol, void * ) {
static double lastrol;
double v = rol->value();
specks_set_timestep( ppui.st );
parti_set_timestep( ppui.st, clock_time( ppui.st->clk ) );
parti_redraw();
}
void pp_settrip_cb( Fl_Button *, void * ) {
char str[32];
ppui.timebasetime = clock_time( ppui.st->clk );
ppui.timestep->value( "0" );
sprintf(str, "%.16lg", ppui.timebasetime);
ppui.timebase->value(str);
}
void pp_backtrip_cb( Fl_Button *, void * ) {
clock_set_time( ppui.st->clk, ppui.timebasetime );
ppui.timestep->value( "0" );
parti_redraw();
}
void pp_stepspeed_cb( Fl_Log_Slider *spd, void * ) {
double speed = spd->truevalue();
clock_set_speed( ppui.st->clk, speed );
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
261
262
263
264
265
266
267
268
void pp_rdata_cb( Fl_Button *, struct stuff ** ) {
struct stuff *st = ppui.st;
const char *result;
result = fl_file_chooser("Choose virdir .wf path", "*.wf", NULL);
if (result)
parti_readpath( st, result );
}
void pp_playframe_cb( Fl_Counter *counter, struct stuff ** ) {
struct stuff *st = ppui.st;
if(ppui.playing)
parti_play( st, "0" );
parti_setframe( st, (int)counter->value() );
}
void pp_playtime_cb( Fl_Value_Slider *slider, struct stuff ** ) {
struct stuff *st = ppui.st;
struct wfpath *path = &ppui.path;
if(ppui.playing)
parti_play( st, "0" );
parti_setframe( st, (int) (slider->value() * path->fps + path->frame0) );
}
void pp_play_cb( Fl_Button *play, struct stuff ** ) {
if(Fl::event_state(FL_BUTTON3)) {
ppui.playmenu->popup();
} else {
parti_play( ppui.st,
play->value() ? NULL /*play at default speed*/
: "0" /*stop*/
);
}
}
int pp_viewevent_cb( Fl_Gview *view, int ev ) {
char snapinfo[1024];
int fno;
double bump;
struct stuff *st = ppui.st;
if(ev == FL_KEYBOARD || ev == FL_SHORTCUT) {
if(ppui.cmdhist && ppui.cmdhist->handle_nav(ev))
return 1;
switch(Fl::event_key()) {
case FL_Print:
if(view->num.has) {
ppui.snapfno = view->num.value();
view->num.has = 0;
}
fno = parti_snapshot(snapinfo);
if(fno >= 0)
msg("Snapped %s", snapinfo);
return 1;
}
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
case '\t':
if(!ppui.cmdhist || !ppui.cmdhist->input())
return 0;
ppui.cmdhist->input()->take_focus();
return 1;
case 'S':
if(view->num.has) {
float v = view->num.fvalue();
if(v == 0) {
parti_stereo("off");
} else {
if(fabs(v) < 1) /* plausible? */
view->stereosep( v );
parti_stereo("on");
}
view->num.has = 0;
} else {
parti_stereo( view->stereo()==GV_MONO ? "on" : "off" );
}
msg("stereo %s (focallen %g)",
parti_stereo(NULL), view->focallen());
return 1;
case '>': bump = 1; goto step;
case '<': bump = -1;
step:
parti_redraw();
case '~':
if(clock_running(st->clk)) {
} else {
int fwd = -clock_fwd( st->clk );
clock_set_fwd( st->clk, fwd );
parti_set_fwd( st, fwd );
case 'z':
case 'Z':
if(view->num.has) {
specks_set_speed( st, view->num.fvalue() );
view->num.has = 0;
} else {
specks_set_speed( st,
clock_speed(st->clk) * (key=='z' ? .5 : 2) );
}
clock_set_step( st->clk, 0.1 * clock_speed(st->clk) );
return 1;
case CTRL('K'):
if(view->num.has) {
ppui.cmdhist->scaletext( view->num.fvalue() );
view->num.has = 0;
}
return 1;
}
}
return 0;
}
static int whichobjname( const char *str ) {
if(str == NULL) return -1;
if(str[0] == '[') str++;
int objno = -1;
sscanf(str, "g%d", &objno);
return objno;
}
static void fitlabel( Fl_Widget *w, int excess = 4 ) {
int ofont = fl_font(), osize = fl_size();
fl_font( w->labelfont(), w->labelsize() );
w->hide();
w->size( width, w->h() );
w->show();
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
fl_font(ofont, osize);
}
void parti_set_alias( struct stuff *st, char *alias ) {
if(st == NULL) return;
if(alias == NULL) alias = "";
alias = strdup(alias);
if(st->alias) free(st->alias);
st->alias = alias;
int slotno, menuno, btno;
for(slotno = 0; slotno < MAXSTUFF; slotno++) {
if(stuffs[slotno] == st) {
char lbl[32];
sprintf(lbl, "[g%d]%.24s", slotno, alias);
for(menuno = ppui.obj->size()-1; --menuno >= 0; ) {
if(whichobjname( ppui.obj->text(menuno) ) == slotno) {
ppui.obj->replace( menuno, strdup(lbl) );
break;
}
}
sprintf(lbl, alias[0]=='\0' ? "g%d" : "g%d=%.24s", slotno, alias);
for(btno = ppui.objtogs->children(); --btno >= 0; ) {
Fl_Button *btn = (Fl_Button *)(ppui.objtogs->child(btno));
if(btn && whichobjname( btn->label() ) == slotno) {
btn->label( strdup(lbl) );
fitlabel( btn, 8 );
break;
}
}
}
}
}
void ppui_refresh( struct stuff *st ) {
if(ppui.view == NULL) return;
/* Possibly switch selected object */
int targ = ppui.view->target();
if(targ >= 0 && targ < MAXSTUFF && stuffs[targ] != NULL && stuffs[targ] != ppui.st) {
st = ppui.st = stuffs[targ];
}
enum Gv_Nav nav = ppui.view->nav();
for(int navcode = 0; navcode < COUNT(codes); navcode++) {
if(codes[navcode] == nav) {
ppui.nav->value( navcode );
if(strcmp(ppui.nav->label(), navtitles[navcode])) {
ppui.nav->label( navtitles[navcode] );
ppui.toprow->parent()->redraw();
}
}
}
int tno, maxobject = 0;
for(tno = 0; tno < MAXSTUFF; tno++) {
struct stuff *tst = stuffs[tno];
if(tst == NULL) continue;
maxobject = tno;
if(!timeshown && tst->clk->tmin != tst->clk->tmax) {
ppui.steprow->show();
ppui.steprow->parent()->hide(); // force top-level Pack to be redraw()n
ppui.steprow->parent()->show(); // for some reason just ->redraw() doesn't.
if(ppui.st == stuffs[tno]) {
char oname[12];
Fl_Font lfont = ppui.view->movingtarget()
? FL_HELVETICA_BOLD_ITALIC
: FL_HELVETICA;
sprintf(oname, "[g%d]", tno);
if(strcmp(ppui.obj->label(), oname) || lfont != ppui.obj->labelfont()) {
ppui.obj->label( strdup( oname ) );
// Iff we might actually move the target object,
// display its [gN] title in BOLD ITALICs.
ppui.obj->labelfont( lfont );
ppui.obj->parent()->redraw();
}
}
}
if(st == NULL)
return;
if(ppui.objgroup->active() != st->useme) {
if(st->useme) ppui.objgroup->activate();
else ppui.objgroup->deactivate();
}
// objtogs is wrapped in a Group which is invisible by default.
if(!ppui.objtogs->parent()->visible() && maxobject > 1) {
ppui.objtogs->parent()->show();
ppui.steprow->parent()->hide(); // force top-level Pack to be redraw()n
ppui.steprow->parent()->show(); // for some reason just ->redraw() doesn't.
}
if(ppui.objtogs->visible()) {
Fl_Button *b, *b0 = (Fl_Button *)ppui.objtogs->child(0);
for(tno = 0; tno <= maxobject; tno++) {
if(tno >= ppui.objtogs->children()) {
char name[8];
sprintf(name, "g%d", tno);
b = new Fl_Button( b0->x(),b0->y(),b0->w(),b0->h(), strdup(name) );
b->labelcolor( b0->labelcolor() );
b->labelfont( b0->labelfont() );
b->labelsize( b0->labelsize() );
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
b->color( b0->color() );
b->selection_color( b0->selection_color() );
b->down_box( b0->down_box() );
b->type( b0->type() );
b->callback( (Fl_Callback*)pp_objtog_cb );
ppui.objtogs->add( b );
}
b = (Fl_Button *)ppui.objtogs->child(tno);
if(stuffs[tno] == NULL) {
if(b->visible()) b->hide();
} else {
if((b->value() != 0) != stuffs[tno]->useme)
b->value( stuffs[tno]->useme );
if(!b->visible()) b->show();
}
}
}
ppui.point->value( st->usepoint );
ppui.poly->value( st->usepoly );
ppui.label->value( st->usetext );
ppui.texture->value( st->usetextures );
ppui.box->value( st->useboxes!=0 );
int boxcolor = ( st->useboxes==2 ? 1/*red*/ : 2/*green*/ );
if(boxcolor != ppui.box->color2()) {
ppui.box->color2( boxcolor );
ppui.box->redraw();
}
int cd = st->curdata, by = st->sizedby;
if((unsigned int)cd >= MAXFILES) cd = 0;
if((unsigned int)by >= MAXVAL+1) by = 0;
struct valdesc *vd = &st->vdesc[cd][by];
float lum = vd->lum;
if(lum <= 0) lum = 1;
ppui.slum->value( log10( lum ) );
char slumlabel[50], *ep = slumlabel;
if(parti_get_alias(st)[0]) {
ep = slumlabel + sprintf(slumlabel, "[%.17s] ", parti_get_alias(st));
}
if(by == CONSTVAL) {
sprintf( ep, "logslum %g", vd->lmin );
} else if(st->vdesc[cd][by].name[0]) {
sprintf( ep, "logslum %.10s", vd->name );
} else {
sprintf( ep, "logslum(field%d)", by );
}
if(strcmp(ppui.slum->label(), slumlabel)) {
static char slumlab[50];
strcpy(slumlab, slumlabel);
ppui.slum->label(slumlab);
ppui.slum->parent()->redraw();
}
}
void pp_viewchanged( Fl_Gview *gview, void *st ) {
ppui_refresh( ppui.st );
void pp_hrdiag_on_cb( Fl_Menu_ *item, void * ) {
if(ppui.hrdiag == NULL || ppui.hrdiagwin == NULL) return;
if(item->value()) {
ppui.hrdiagwin->show();
ppui.hrdiag->show();
} else {
ppui.hrdiagwin->hide();
}
}
void pp_inertia_on_cb( Fl_Menu_ *item, void * ) {
}
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
int msg( const char *fmt, ... ) {
char str[10240];
va_list args;
va_start(args, fmt);
vsprintf(str, fmt, args);
va_end(args);
if(ppui.cmdhist)
ppui.cmdhist->addline( str, 1 );
return printf("%s\n", str);
}
void quietwarning( const char *fmt, ... ) {
char msg[10240];
static char avoid[] = "X_ChangeProperty: ";
va_list args;
va_start(args, fmt);
vsprintf(msg, fmt, args);
va_end(args);
if(0!=strncmp(msg, avoid, sizeof(avoid)-1))
fputs(msg, stderr);
}
void drawjunk(Fl_Gview *view, void *obj, void *arg) {
static Point xyz[3] = {{1,0,0}, {0,1,0}, {0,0,1}};
static Point nxyz[3] = {{-1,0,0}, {0,-1,0}, {0,0,-1}};
static Point zero = {0,0,0};
static float white[3] = {1,1,1};
float censize = parti_getcensize();
int i;
glDisable(GL_LIGHTING);
if(censize > 0) {
glPushMatrix();
glScalef(censize,censize,censize);
glBegin(GL_LINES);
for(i = 0; i < 3; i++) {
glColor3fv(xyz[i].x);
glVertex3fv(xyz[i].x);
glVertex3f(0,0,0);
}
glEnd();
glPopMatrix();
}
if(censize != 0) {
censize = fabs(censize);
glPushMatrix();
const Point *cen = view->center();
glTranslatef(cen->x[0],cen->x[1],cen->x[2]);
glScalef(censize, censize, censize);
glBegin(GL_LINES);
for(i = 0; i < 3; i++) {
glColor3fv(white);
glVertex3fv(nxyz[i].x);
glVertex3fv(zero.x);
glColor3fv(xyz[i].x);
glVertex3fv(zero.x);
glVertex3fv(xyz[i].x);
}
glEnd();
glPopMatrix();
}
}
void readrc( struct stuff **stp ) {
char *rc = findfile( NULL, "~/.partiviewrc" );
if(rc) specks_read( stp, rc );
rc = findfile( NULL, "./.partiviewrc" );
if(rc) specks_read( stp, rc );
}
static int cmdargs(int argc, char **argv, int & optind) {
char *arg = argv[optind];
if(!strcmp("-c", arg)) {
char *t = NewA(char, strlen(arg)+1);
char *av[128];
int ac = tokenize(arg, t, 128, av, NULL);
specks_parse_args( &ppui.st, ac, av );
optind += 2;
return 1;
}
if(!strcmp("-geom", arg) || !strcmp("-geometry", arg)) {
ppui.reqwinsize = NULL; /* override any initial "winsize" */
/* but let fltk parse it anyway */
return 0;
int main(int argc, char *argv[])
{
GLuint pickbuffer[20480];
Fl::warning = quietwarning;
static Point black = {0,0,0};
ppui.view->bgcolor( &black );
/* make_window() sets ppui.view, etc. */
pp_ui_init();
ppui.view->add_drawer( drawjunk, NULL, NULL, NULL, 0 );
ppui.view->pickbuffer( COUNT(pickbuffer), pickbuffer );
ppui.view->zspeed = 5;
ppui.view->farclip( 2500 );
ppui.censize = 1.0;
ppui.view->movingtarget( 0 );
ppui.view->msg = msg;
if(ppui.hrdiag) {
ppui.hrdiag->msg = msg;
ppui.playspeed = 1;
ppui.playframe->lstep(10);
parti_object( "g1", NULL, 1 );
readrc( &ppui.st );
int i = 0;
if(Fl::args(argc, argv, i, cmdargs) == 0) {
fprintf(stderr, "Unrecognized option: %s\n", argv[i]);
exit(1);
}
for( ; i < argc; i++) {
specks_read( &ppui.st, argv[i] );
}
ppui.view->notifier( pp_viewchanged, ppui.st );
ppui_refresh( ppui.st );
ppui.mainwin->show(argc, argv);
if(ppui.reqwinsize != NULL) {
parti_update();
parti_winsize( ppui.reqwinsize );
ppui.reqwinsize = NULL;
}