partiview.cc 13.41 KiB
#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 <FL/Fl.H>
#include <FL/fl_file_chooser.H>
static char *partiview_version = "Partiview version: $log$";
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 && ppui.view) ppui.view->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 );
ppui.view->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 );
}
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;
if(Fl::event_button() == FL_RIGHT_MOUSE) {
stuffs[objno]->useme = 1;
parti_object( b->label(), &ppui.st );
b->value(1);
} else {
stuffs[objno]->useme = !stuffs[objno]->useme;
}
ppui_refresh( ppui.st );
ppui.view->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();
}
void pp_stepper( void *vst ) {
struct stuff *st = (struct stuff *)vst;
if(st) {
clock_tick( st->clk );
specks_set_timestep( ppui.st );
ppui.view->redraw();
}
}
void parti_stepping( struct stuff *st, int on ) {
if(clock_running(st->clk) != on) {
if(on) Fl::add_idle( pp_stepper, st );
else Fl::remove_idle( pp_stepper, st );
if(st->clk) st->clk->walltimed = 1;
clock_set_running(st->clk, on);
}
ppui.runstop[0]->value( on && clock_fwd(st->clk) < 0 );
ppui.runstop[1]->value( on && clock_fwd(st->clk) > 0 );
}
void pp_step_cb( Fl_Button * , void *stepsign ) {
int sign = (int)stepsign;
parti_stepping( ppui.st, 0 );
clock_step( ppui.st->clk, (int)stepsign );
specks_set_timestep( ppui.st );
ppui.view->redraw();
}
void pp_run_cb( Fl_Button *runbtn, void *stepsign ) {
clock_set_fwd( ppui.st->clk, (int)stepsign );
parti_stepping( ppui.st, runbtn->value() );
}
void pp_timeinput_cb( Fl_Input *inp, void * ) {
double v;
parti_stepping( ppui.st, 0 );
if(sscanf(inp->value(), "%lf", &v))
clock_set_time( ppui.st->clk, v + ppui.timebasetime );
}
void pp_timebaseinput_cb( Fl_Input *inp, void * ) {
double newbase;
parti_stepping( ppui.st, 0 );
if(sscanf(inp->value(), "%lf", &newbase)) {
double now = clock_time( ppui.st->clk );
parti_set_timestep( ppui.st, now - newbase );
ppui.timebasetime = newbase;
}
}
void pp_jog_cb( Fl_Roller *rol, void * ) {
static double lastrol;
double v = rol->value();
clock_add( ppui.st->clk, v - lastrol );
lastrol = v;
parti_stepping( ppui.st, 0 );
specks_set_timestep( ppui.st );
parti_set_timestep( ppui.st, clock_time( ppui.st->clk ) );
ppui.view->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" );
}
void pp_stepspeed_cb( Fl_Log_Slider *spd, void * ) {
double speed = spd->truevalue();
clock_set_speed( ppui.st->clk, speed );
}
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;
}
switch(Fl::event_text()[0]) {
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:
static double bumpunit;
if(view->num.has)
clock_set_step( st->clk, view->num.fvalue() );
view->num.has = 0;
clock_step( st->clk, bump );
/* clock_notify( st->clk ); NOTYET NOTIFY */
// ppui_refresh(); ??? Yes, after we add an animation panel
view->redraw();
return 1;
}
}
return 0;
}
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.nav->parent()->redraw();
}
}
}
int tno, maxobject = 0;
for(tno = 0; tno < MAXSTUFF; tno++) {
if(stuffs[tno]) maxobject = tno;
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();
}
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->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[20];
if(st->vdesc[cd][by].name[0])
sprintf( slumlabel, "logslum %.10s", vd->name );
else
sprintf( slumlabel, "logslum(var%d)", by );
if(strcmp(ppui.slum->label(), slumlabel)) {
static char slumlab[20];
strcpy(slumlab, slumlabel);
ppui.slum->label(slumlab);
ppui.slum->parent()->redraw();
}
}
void pp_viewchanged( Fl_Gview *gview, void *st ) {
ppui_refresh( ppui.st );
}
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();
}
}
int main(int argc, char *argv[])
{
GLuint pickbuffer[20480];
Fl::warning = quietwarning;
pp_clk_init();
ppui.mainwin = make_window();
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;
ppui.playspeed = 1;
ppui.playframe->lstep(10);
parti_object( "g1", NULL );
for(int i = 1; i < argc; i++) {
specks_read( &ppui.st, argv[i] );
}
pp_ui_postinit();
ppui.view->notifier( pp_viewchanged, ppui.st );
ppui_refresh( ppui.st );
ppui.mainwin->show(1, argv);
ppui.view->show();
return Fl::run();
}