Skip to content
Snippets Groups Projects
kira_parti.cc 16.3 KiB
Newer Older
slevy's avatar
slevy committed
#ifdef USE_KIRA

#include "worldline.h"

// #define CAVE 1		// NewN: use potentially-shared-memory malloc
#include "shmem.h"
#include "specks.h"
#include "partiviewc.h"

#include "kira_parti.h"		// declare following as extern "C"
slevy's avatar
slevy committed
#include <sys/types.h>
#include <sys/time.h>
slevy's avatar
slevy committed

slevy's avatar
 
slevy committed
static char local_id[] = "$Id$";
slevy's avatar
slevy committed

slevy's avatar
slevy committed
extern struct specklist *kira_get_parti( struct stuff *st, double realtime );
slevy's avatar
slevy committed

typedef worldbundle *worldbundleptr;
slevy's avatar
 
slevy committed

slevy's avatar
slevy committed
struct worldstuff {
slevy's avatar
slevy committed
    int nh, maxnh;
slevy's avatar
slevy committed
    worldbundleptr *wh;
slevy's avatar
slevy committed
    ifstream *ins;
slevy's avatar
slevy committed
    int ih;			// current worldbundle index
    real tmin, tmax;
    real tcur;			// current time
    real treq;			// requested time
slevy's avatar
slevy committed
    int readflags;		// KIRA_VERBOSE | KIRA_READLATER
slevy's avatar
 
slevy committed
    int treenodes;		// KIRA_{OFF|ON|ROOTS}
    int treerings;		// KIRA_{OFF|ON|ROOTS}
slevy's avatar
 
slevy committed
    int treearcs;		// KIRA_{OFF|ON|CROSS|TICK}
    float tickscale;		// size of treearc cross mark (frac of sep)
slevy's avatar
 
slevy committed
    int ringsizer;		// KIRA_RINGSEP, KIRA_RINGA
    float ringscale;		// multiplier for above
    float ringmin, ringmax;	// range of pixel sizes for ring markers
slevy's avatar
 
slevy committed
    int tracking, wastracking;	// id of particle we're tracking, or zero
    Point trackpos;		// last known position of tracked particle

slevy's avatar
 
slevy committed
    int maxstars, maxmarks;	// room allocated for each
slevy's avatar
 
slevy committed
    struct specklist *sl;
slevy's avatar
 
slevy committed
    struct specklist *marksl;
slevy's avatar
 
slevy committed
    int slvalid;
slevy's avatar
slevy committed
    int *starset;		// per-star bitmask of "sets" it belongs to

    struct specklist *trailsl;	// per-star specklist of recent history
    int maxtrail, ntrail;

slevy's avatar
 
slevy committed
    struct speck *marksp;	// current pointer, updated by add_speck
    int leafcount;		// temp, used in recursion only

slevy's avatar
slevy committed

slevy's avatar
 
slevy committed
    worldstuff() {
slevy's avatar
slevy committed
	this->init();
    }

    init() {
slevy's avatar
 
slevy committed
	nh = 0;
	wh = NULL;
	ih = 0;
	tmin = 0, tmax = 1;
	tcur = treq = 0;

	treenodes = KIRA_ON;
	treerings = KIRA_OFF;
slevy's avatar
 
slevy committed
	treearcs = KIRA_ON;
slevy's avatar
 
slevy committed
	ringsizer = KIRA_RINGA;
	ringscale = 1.5;

	ringmin = 2;
	ringmax = 50;

slevy's avatar
 
slevy committed
	tickscale = 0.25;
slevy's avatar
 
slevy committed
	tracking = wastracking = 0;

slevy's avatar
 
slevy committed
	sl = marksl = NULL;
	maxstars = maxmarks = 0;
slevy's avatar
 
slevy committed
	slvalid = 0;
slevy's avatar
slevy committed

	trailsl = NULL;
	maxtrail = ntrail = 0;

slevy's avatar
 
slevy committed
	marksp = NULL;
	leafcount = 0;
    }

};


    // speck fields:
    //  [0] worldline index (= kira index for singles, - and unique for others)
    //  [1] mass
    //  [2] number in clump
    //  [3] top-level name
    //  [4] address in clump
slevy's avatar
 
slevy committed
    //  [5] ring size
    //  [6] mass ratio (for nonleaves) (mu = child1/(child1+child2))
    //  [7..9] child separation vector (for nonleaves)
slevy's avatar
 
slevy committed

enum speckfields {
	SPECK_ID = 0,		// worldline index (= kira index for single stars,
				//			unique small negative int for others)
	SPECK_MASS = 1,		// mass
	SPECK_NCLUMP = 2,	// number of stars in clump
	SPECK_ROOTID = 3,	// worldline index of root of clump
	SPECK_TREEADDR = 4,	// bit-encoded tree address within our clump (0 for isolated stars)
	SPECK_RINGSIZE = 5,	// size of ring marker
slevy's avatar
 
slevy committed
	SPECK_MU = 6,		// mass ratio
	SPECK_SEPVEC = 7,	// separation vector[3]
	SPECK_NDATAFIELDS = 10
slevy's avatar
slevy committed
};

static char *fieldnames[] = {
	"id",
	"mass",
	"nclump",
	"rootid",
	"treeaddr",
	"ringsize",
	"mu",
	"sepvec3",
	NULL
};

slevy's avatar
 
slevy committed
void kira_invalidate( struct stuff *st ) {
    if(st->sl) st->sl->used = -1000000;
    worldstuff *ww = (worldstuff *)st->dyndatadata;
    if(ww) ww->slvalid = 0;
slevy's avatar
 
slevy committed
}

int kira_set( struct stuff *st, int what, double val )
{
    struct worldstuff *ww = (struct worldstuff *)st->dyndatadata;
    if(ww == NULL) return 0;

    if(kira_get(st, what) == val)
	return 2;

    switch(what) {
    case KIRA_NODES: ww->treenodes = (int)val; break;
    case KIRA_RINGS: ww->treerings = (int)val; break;
slevy's avatar
 
slevy committed
    case KIRA_TREE: ww->treearcs = (int)val; break;
    case KIRA_TICKSCALE: ww->tickscale = val; break;
slevy's avatar
 
slevy committed
    case KIRA_RINGSIZE: ww->ringsizer = (int)val; break;
    case KIRA_RINGSCALE: ww->ringscale = val; break;
    case KIRA_RINGMIN: ww->ringmin = val; break;
    case KIRA_RINGMAX: ww->ringmax = val; break;
slevy's avatar
 
slevy committed
    case KIRA_TRACK: if(ww->tracking != (int)val) ww->wastracking = 0;
		     ww->tracking = (int)val; break;
slevy's avatar
 
slevy committed
    default: return 0;
    }
slevy's avatar
 
slevy committed
    kira_invalidate( st );
slevy's avatar
 
slevy committed
    specks_set_timestep( st );
    parti_redraw();
    return 1;
}

double kira_get( struct stuff *st, int what )
{
    struct worldstuff *ww = (struct worldstuff *)st->dyndatadata;
    if(ww == NULL) return 0;

    switch(what) {
slevy's avatar
 
slevy committed
    case KIRA_NODES: return ww->treenodes;
    case KIRA_RINGS: return ww->treerings;
    case KIRA_TREE:  return ww->treearcs;
    case KIRA_TICKSCALE: return ww->tickscale;
    case KIRA_RINGSIZE: return ww->ringsizer;
    case KIRA_RINGSCALE: return ww->ringscale;
    case KIRA_RINGMIN: return ww->ringmin;
    case KIRA_RINGMAX: return ww->ringmax;
    case KIRA_TRACK: return ww->tracking;
slevy's avatar
 
slevy committed
    }
    return 0;
}

slevy's avatar
slevy committed
int hasdata( ifstream *s, double maxwait ) {
    struct timeval tv;
    fd_set fds;
    if(s == NULL) return 0;
    if(s->rdbuf()->in_avail() || s->eof()) return 1;
    if(maxwait < 0) maxwait = 0;
    tv.tv_sec = (int)maxwait;
    tv.tv_usec = (int) (1000000 * (maxwait - tv.tv_sec));
    FD_ZERO(&fds);
    FD_SET(s->rdbuf()->fd(), &fds);
    return(select(s->rdbuf()->fd() + 1, &fds, NULL, NULL, &tv) > 0);
}
    

int kira_read_more(struct stuff *st, int nmax, double tmax, double realdtmax)
slevy's avatar
slevy committed
{
slevy's avatar
slevy committed
    struct worldstuff *ww = (struct worldstuff *)st->dyndatadata;
    if(ww == NULL) return -1;
    ifstream *ins = ww->ins;
    if(ins == NULL || !ins->is_open()) return -1;

    int paras = 0;
    int timelimit = (realdtmax < 1e6);
    double wallstop = realdtmax + wallclock_time();
    while( paras < nmax && (ww->nh == 0 || ww->wh[ww->nh-1]->get_t_max() < tmax) ) {

	if(timelimit) {
	    double dt = wallstop - wallclock_time();
	    if(!hasdata(ins, dt))
		break;
	    if(dt <= 0)
		break;
	}
slevy's avatar
slevy committed

slevy's avatar
slevy committed
	if(ww->nh >= ww->maxnh) {
	    ww->maxnh = (ww->nh > ww->maxnh*2) ? ww->nh + 1 : ww->maxnh*2;
	    ww->wh = RenewN( ww->wh, worldbundleptr, ww->maxnh );
	}
slevy's avatar
slevy committed

slevy's avatar
slevy committed
	worldbundle *wb;

	wb = read_bundle(*ins, ww->readflags & KIRA_VERBOSE);
	if(wb == NULL) {
	    ins->close();
	    if(paras == 0) paras = -1;
	    break;
	}
slevy's avatar
slevy committed
	ww->wh[ww->nh++] = wb;
slevy's avatar
slevy committed
	paras++;
    }

    if(paras > 0) {
	ww->tmin = ww->wh[0]->get_t_min();
	ww->tmax = ww->wh[ww->nh-1]->get_t_max();
    }
    return paras;
}
slevy's avatar
slevy committed

slevy's avatar
slevy committed
int kira_open(struct stuff *st, char *filename, int readflags)
{
    ifstream *ins = new ifstream(filename);
    if (!ins || !*ins) {
	msg("Kira/starlab data file %s not found.", filename);
	delete ins;
slevy's avatar
slevy committed
	return 0;
    }

slevy's avatar
slevy committed
    worldbundle *wb;
    struct worldstuff *ww = NewN( worldstuff, 1 );	// from shmem -- avoid "new"
    ww->init();
    ww->maxnh = 1024;
    ww->wh = NewN( worldbundleptr, ww->maxnh );
    ww->ins = ins;
    ww->tmin = ww->tmax = 0;
slevy's avatar
slevy committed
    ww->tcur = ww->treq = -1.0;		// invalid
slevy's avatar
slevy committed
    ww->readflags = readflags;
slevy's avatar
slevy committed

    st->dyndata = 1;
slevy's avatar
slevy committed
    st->dyndatafunc = kira_get_parti;
slevy's avatar
slevy committed
    st->dyndatadata = ww;

slevy's avatar
slevy committed
    ww->nh = 0;
    if(! (readflags & KIRA_READLATER)) {
	kira_read_more( st, ww->maxnh, 1e38, 1e38 );

	if (ww->nh == 0) {
	    msg("Data file %s not in worldbundle format.", filename);
	    return 0;
	}
    }

    ww->ih = 0;
    ww->sl = NULL;

    // If data field names aren't already assigned, set them now.
    for(int i = 0; fieldnames[i] != NULL; i++) {
	if(st->vdesc[st->curdata][i].name[0] == '\0')
	    strcpy(st->vdesc[st->curdata][i].name, fieldnames[i]);
    }
slevy's avatar
slevy committed
    return 1;
}

double get_parti_time( struct stuff *st ) {
    if(st->dyndatadata == NULL)
	return 0.0;
    return ((struct worldstuff *)(st->dyndatadata))->tcur;
}

void set_parti_time( struct stuff *st, double reqtime ) {
    if(st->dyndatadata == NULL)
	return;
    // otherwise please seek to requested time ...
}

int get_parti_time_range( struct stuff *st, double *tmin, double *tmax )
{
    struct worldstuff *ww = (struct worldstuff *)st->dyndatadata;
    if(ww == NULL) {
slevy's avatar
slevy committed
	*tmin = *tmax = 0;
slevy's avatar
slevy committed
	return 0;
    }

    *tmin = ww->tmin;
    *tmax = ww->tmax;
    return 1;
}

slevy's avatar
 
slevy committed

slevy's avatar
 
slevy committed
speck *add_speck(dyn *b, dyn *top, int addr, speck *sp, specklist *sl, worldstuff *ww)
slevy's avatar
slevy committed
{
slevy's avatar
 
slevy committed
    sp->p.x[0] = b->get_pos()[0];
    sp->p.x[1] = b->get_pos()[1];
    sp->p.x[2] = b->get_pos()[2];

slevy's avatar
 
slevy committed
    sp->val[SPECK_ID] = b->get_index();
slevy's avatar
 
slevy committed
    if (!b->is_leaf())
slevy's avatar
 
slevy committed
	sp->val[SPECK_ID] = -sp->val[SPECK_ID];	// distinguish CM
slevy's avatar
 
slevy committed

slevy's avatar
 
slevy committed
    sp->val[SPECK_MASS] = b->get_mass();
slevy's avatar
 
slevy committed

slevy's avatar
slevy committed
    sp->val[SPECK_NCLUMP] = 0;		// complete (add n_leaves) in kira_to_parti
slevy's avatar
 
slevy committed

    // Offset unperturbed binaries by 100 in field 2.

    if (b != top) {
slevy's avatar
 
slevy committed
	dyn *bb = b;
	while (bb->get_elder_sister())
	    bb = bb->get_elder_sister();
	if (bb->get_kepler()) sp->val[SPECK_NCLUMP] += 100;
slevy's avatar
 
slevy committed
    }

slevy's avatar
 
slevy committed
    sp->val[SPECK_ROOTID] = top->get_index();
slevy's avatar
 
slevy committed

    // Addr is 0 for top-level leaf, 1 for top-level CM,
    // constructed from parent addr otherwise.

slevy's avatar
 
slevy committed
    sp->val[SPECK_TREEADDR] = addr;

    sp->val[SPECK_RINGSIZE] = 0;
slevy's avatar
 
slevy committed

    sl->nspecks++;
    sp = NextSpeck(sp, sl, 1);
slevy's avatar
 
slevy committed
    return sp;
}
    
speck *assign_specks(dyn *b, dyn *top, int addr, speck *sp, specklist *sl, worldstuff *ww)
{
    // Convert relative coordinates to absolute.

    if (b != top)
	b->inc_pos(b->get_parent()->get_pos());

slevy's avatar
 
slevy committed
    if(ww->tracking != 0 && abs(ww->tracking) == b->get_index()) {
	Point newpos;
	newpos.x[0] = b->get_pos()[0];
	newpos.x[1] = b->get_pos()[1];
	newpos.x[2] = b->get_pos()[2];
	if(ww->wastracking) {
	    Point delta;
	    vsub( &delta, &newpos,&ww->trackpos );
	    parti_nudge_camera( &delta );
	}
	ww->trackpos = newpos;
	ww->wastracking = 1;
    }

slevy's avatar
 
slevy committed
    if(b->is_leaf()
		|| ww->treenodes == KIRA_ON
		|| (ww->treenodes == KIRA_ROOTS && b == top)) {
	sp = add_speck(b, top, addr, sp, sl, ww);

	if(b->is_leaf())
	    ww->leafcount++;
    }

    if(!b->is_leaf() &&
slevy's avatar
 
slevy committed
		(ww->treerings == KIRA_ON || ww->treearcs != KIRA_OFF
slevy's avatar
 
slevy committed
		 || (ww->treerings == KIRA_ROOTS && b == top))) {

	struct speck *marksp = ww->marksp;
	ww->marksp = add_speck(b, top, addr, marksp, ww->marksl, ww);

	// find our two children

	dyn *b1 = b->get_oldest_daughter();
	dyn *b2 = b1 ? b1->get_younger_sister() : NULL;
	if(b2) {
	    vector sep = b1->get_pos() - b2->get_pos();
	    real dist = sqrt(sep * sep);
slevy's avatar
 
slevy committed
	    real mass = b->get_mass();	// = sum of b1&b2 masses.
slevy's avatar
 
slevy committed

	    real size = 0;
	    switch(ww->ringsizer) {
	    case KIRA_RINGSEP:
slevy's avatar
 
slevy committed
		size = 0.5 * dist;
slevy's avatar
 
slevy committed
		break;
	    case KIRA_RINGA:
	      {
		vector vel = b1->get_vel() - b2->get_vel();
		real speed2 = vel * vel;
		real E = 0.5 * speed2 - mass / dist;
		size = -mass / (2*E);	// semimajor axis
	      }
	    }
	    marksp->val[SPECK_RINGSIZE] = size * ww->ringscale;
slevy's avatar
 
slevy committed
	    marksp->val[SPECK_MU] = b1->get_mass() / mass;
	    marksp->val[SPECK_SEPVEC] = sep[0];
	    marksp->val[SPECK_SEPVEC+1] = sep[1];
	    marksp->val[SPECK_SEPVEC+2] = sep[2];
slevy's avatar
 
slevy committed
	}
    }
slevy's avatar
 
slevy committed

    // Recursion.

    addr *= 2;
    for_all_daughters(dyn, b, bb)
slevy's avatar
 
slevy committed
	sp = assign_specks(bb, top, addr++, sp, sl, ww);
slevy's avatar
 
slevy committed

    return sp;
slevy's avatar
slevy committed
}

slevy's avatar
 
slevy committed

slevy's avatar
slevy committed
struct specklist *kira_to_parti(dyn *root, struct stuff *st, struct specklist *sl)
slevy's avatar
slevy committed
{
slevy's avatar
 
slevy committed
    worldstuff *ww = (worldstuff *)st->dyndatadata;
slevy's avatar
slevy committed

    if(ww == NULL || ww->nh == 0) return NULL;

slevy's avatar
 
slevy committed
    struct specklist *marksl = ww->marksl;

    if(sl == NULL || sl != ww->sl) {
slevy's avatar
slevy committed
	// Use NewN to allocate these in (potentially) shared memory,
	// rather than new which will allocate in local malloc pool.
	// Needed for virdir/cave version.
slevy's avatar
 
slevy committed

	int smax = root->n_leaves();
	ww->maxstars = 2*smax;
	ww->maxmarks = 1+smax;

slevy's avatar
slevy committed
        sl = NewN( struct specklist, 1 );
	memset(sl, 0, sizeof(*sl));
slevy's avatar
 
slevy committed
	sl->bytesperspeck = SMALLSPECKSIZE( SPECK_NDATAFIELDS );
	sl->specks = NewNSpeck(sl, ww->maxstars);
slevy's avatar
slevy committed
	sl->scaledby = 1;
slevy's avatar
 
slevy committed
	marksl = NewN( struct specklist, 1 );
	*marksl = *sl;
	marksl->specks = NewNSpeck(marksl, ww->maxmarks);
	marksl->special = MARKERS;

	sl->next = marksl;
	marksl->next = NULL;

	ww->sl = sl;
	ww->marksl = marksl;

slevy's avatar
slevy committed
    }
slevy's avatar
 
slevy committed

slevy's avatar
slevy committed
    struct speck *sp = sl->specks;

slevy's avatar
 
slevy committed
    sl->nspecks = 0;
slevy's avatar
 
slevy committed
    marksl->nspecks = 0;
    ww->marksp = marksl->specks;
    ww->leafcount = 0;
slevy's avatar
 
slevy committed

    if(ww->wastracking) ww->wastracking = -1;

slevy's avatar
 
slevy committed
    for_all_daughters(dyn, root, b) {
	int ns = sl->nspecks;
slevy's avatar
 
slevy committed
	int mns = marksl->nspecks;
	int nl = ww->leafcount;
slevy's avatar
 
slevy committed
	speck *tsp = sp;
slevy's avatar
 
slevy committed
	speck *msp = ww->marksp;
slevy's avatar
 
slevy committed

slevy's avatar
 
slevy committed
	sp = assign_specks(b, b, !b->is_leaf(), sp, sl, ww);
slevy's avatar
 
slevy committed

slevy's avatar
 
slevy committed
	int k;
	int nleaves = ww->leafcount - nl;
	int count = sl->nspecks - ns;

	for(k = 0; k < count; k++) {
	    tsp->val[SPECK_NCLUMP] += nleaves;
	    if(tsp->val[0] < 0)
		tsp->val[SPECK_NCLUMP] = -tsp->val[SPECK_NCLUMP]; // negate nclump for CM nodes
slevy's avatar
 
slevy committed
	    tsp = NextSpeck(tsp, sl, 1);
slevy's avatar
slevy committed
	}
slevy's avatar
 
slevy committed
	count = marksl->nspecks - mns;
	for(k = 0; k < count; k++) {
	    msp->val[SPECK_NCLUMP] += nleaves;
	    if(msp->val[0] < 0)
		msp->val[SPECK_NCLUMP] = -msp->val[SPECK_NCLUMP]; // negate nclump for CM nodes
	    msp = NextSpeck(msp, sl, 1);
	}
slevy's avatar
slevy committed
    }
slevy's avatar
 
slevy committed

slevy's avatar
 
slevy committed
    if(ww->wastracking < 0) ww->wastracking = 0;	// Detach if tracked pcle not found now

slevy's avatar
slevy committed
    return sl;
}

slevy's avatar
slevy committed
struct specklist *kira_get_parti( struct stuff *st, double realtime )
slevy's avatar
slevy committed
{
    struct worldstuff *ww = (struct worldstuff *)(st->dyndatadata);

slevy's avatar
slevy committed
    if (ww == NULL || ww->nh == 0)
slevy's avatar
slevy committed
	return NULL;

    ww->treq = realtime;

    if (realtime < ww->tmin) realtime = ww->tmin;
    if (realtime > ww->tmax) realtime = ww->tmax;

slevy's avatar
 
slevy committed
    if (ww->tcur == realtime && ww->slvalid)
slevy's avatar
slevy committed
	return ww->sl;

    int ih = ww->ih;
    int nh = ww->nh;

    worldbundle *wb = ww->wh[ih];
    for(; realtime > wb->get_t_max() && ih < nh-1; ih++, wb = ww->wh[ih])
	;
    for(; realtime < wb->get_t_min() && ih > 0; ih--, wb = ww->wh[ih])
	;

    dyn *root = create_interpolated_tree(wb, realtime);
slevy's avatar
slevy committed
    ww->sl = kira_to_parti(root, st, ww->sl);
slevy's avatar
slevy committed
    rmtree(root);

    ww->ih = ih;
    ww->tcur = realtime;

slevy's avatar
 
slevy committed
    ww->slvalid = 1;
slevy's avatar
slevy committed
    return ww->sl;
}

slevy's avatar
 
slevy committed
void kira_draw( struct stuff *st, struct specklist *slhead, Matrix *Tc2w, float radperpix )
{
    struct worldstuff *ww = (struct worldstuff *)st->dyndatadata;
slevy's avatar
 
slevy committed

    if(ww == NULL)
	return;

slevy's avatar
 
slevy committed
    struct specklist *sl;
slevy's avatar
 
slevy committed
    float halftickscale = 0.5 * ww->tickscale;
slevy's avatar
 
slevy committed

    static Point zero = {0,0,0};
    Point fwdvec = {0,0,-radperpix};	// scaled by pixels-per-radian
slevy's avatar
 
slevy committed
    Point eyepoint, fwd, unitfwd;
slevy's avatar
 
slevy committed
    float fwdd;

    vtfmpoint( &eyepoint, &zero, Tc2w );
    vtfmvector( &fwd, &fwdvec, Tc2w );
    fwdd = -vdot( &eyepoint, &fwd );
slevy's avatar
 
slevy committed
    vunit( &unitfwd, &fwd );
slevy's avatar
 
slevy committed

#define MAXRING 32
    Point fan[MAXRING];
    int nring = 24;
    int i;
    for(i = 0; i < nring; i++) {
	float th = 2*M_PI*i / nring;
	vcomb( &fan[i],  cos(th),(Point *)&Tc2w->m[0*4+0],
			 sin(th),(Point *)&Tc2w->m[1*4+0] );
    }

    for(sl = slhead; sl != NULL; sl = sl->next) {
	if(sl->special == MARKERS) {
	    int ns = sl->nspecks;
	    struct speck *sp = sl->specks;
	    for(i = 0; i < ns; i++, sp = NextSpeck(sp, sl, 1)) {
		float unitperpix = vdot( &fwd, &sp->p ) + fwdd;
		if(unitperpix <= 0) continue;
slevy's avatar
 
slevy committed

		if(ww->treerings == KIRA_ON ||
			(ww->treerings == KIRA_ROOTS && sp->val[SPECK_TREEADDR] == 1)) {
		    float ringpixels = fabs(sp->val[SPECK_RINGSIZE]) / unitperpix;
		    if(ringpixels < ww->ringmin) ringpixels = ww->ringmin;
		    if(ringpixels > ww->ringmax) ringpixels = ww->ringmax;
		    float rring = ringpixels * unitperpix;
		    int step = ringpixels>20 ? 1 : ringpixels>8 ? 2 : 3;

		    glColor3ubv( (GLubyte *)&sp->rgba );
		    glBegin( GL_LINE_LOOP );
		    for(int k = 0; k < nring; k+=step)
			glVertex3f( sp->p.x[0] + rring*fan[k].x[0],
				    sp->p.x[1] + rring*fan[k].x[1],
				    sp->p.x[2] + rring*fan[k].x[2] );
		    glEnd();
		}
		if(ww->treearcs != KIRA_OFF) {
		    float mu = sp->val[SPECK_MU];
		    float *sep = &sp->val[SPECK_SEPVEC];
		    glColor3ubv( (GLubyte *)&sp->rgba );
		    glBegin( GL_LINES );

		    if(ww->treearcs != KIRA_TICK) {
			glVertex3f(
			    sp->p.x[0] - mu*sep[0],
			    sp->p.x[1] - mu*sep[1],
			    sp->p.x[2] - mu*sep[2] );
			glVertex3f(
			    sp->p.x[0] + (1-mu)*sep[0],
			    sp->p.x[1] + (1-mu)*sep[1],
			    sp->p.x[2] + (1-mu)*sep[2] );
		    }

		    if(ww->treearcs == KIRA_CROSS || ww->treearcs == KIRA_TICK) {
			Point cr;
			vcross( &cr,  &unitfwd, (Point *)sep );
			float sepsep = vdot((Point *)sep, (Point *)sep);
			float sepfwd = vdot((Point *)sep, &unitfwd);
			float scaleby = halftickscale / sqrt(1 - sepfwd*sepfwd/sepsep);
			glVertex3f(
			   sp->p.x[0] - scaleby*cr.x[0],
			   sp->p.x[1] - scaleby*cr.x[1],
			   sp->p.x[2] - scaleby*cr.x[2] );
			glVertex3f(
			   sp->p.x[0] + scaleby*cr.x[0],
			   sp->p.x[1] + scaleby*cr.x[1],
			   sp->p.x[2] + scaleby*cr.x[2] );
		    }
		    glEnd();
		}
slevy's avatar
 
slevy committed
	    }
	}
    }
slevy's avatar
slevy committed

    glPointSize( 1.0 );
    glBegin( GL_POINTS );
    for(i = 1; i < st->nghosts; i++) {
	sl = specks_timespecks( st, st->curdata, i );
	if(sl == NULL) continue;
	int k, rgba = 0;
	struct speck *sp;
	for(k = 0, sp = sl->specks; k < sl->nspecks; k++, sp = NextSpeck(sp, sl, 1)) {
	    if(rgba != sp->rgba) {
		glColor3ubv( (GLubyte *)&sp->rgba );
		rgba = sp->rgba;
	    }
	    glVertex3fv( &sp->p.x[0] );
	}
    }
    glEnd();

slevy's avatar
 
slevy committed
}

slevy's avatar
slevy committed
#endif /*USE_KIRA*/