Newer
Older
#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"
extern struct specklist *get_parti( struct stuff *st, double realtime );
typedef worldbundle *worldbundleptr;
struct worldstuff {
int nh;
worldbundleptr *wh;
int ih; // current worldbundle index
real tmin, tmax;
real tcur; // current time
real treq; // requested time
int treearcs; // KIRA_{OFF|ON|CROSS|TICK}
float tickscale; // size of treearc cross mark (frac of sep)
int ringsizer; // KIRA_RINGSEP, KIRA_RINGA
float ringscale; // multiplier for above
float ringmin, ringmax; // range of pixel sizes for ring markers
int tracking, wastracking; // id of particle we're tracking, or zero
Point trackpos; // last known position of tracked particle
struct speck *marksp; // current pointer, updated by add_speck
int leafcount; // temp, used in recursion only
worldstuff() {
nh = 0;
wh = NULL;
ih = 0;
tmin = 0, tmax = 1;
tcur = treq = 0;
treenodes = KIRA_ON;
treerings = KIRA_OFF;
ringsizer = KIRA_RINGA;
ringscale = 1.5;
ringmin = 2;
ringmax = 50;
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
// [5] ring size
// [6] mass ratio (for nonleaves) (mu = child1/(child1+child2))
// [7..9] child separation vector (for nonleaves)
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
SPECK_MU = 6, // mass ratio
SPECK_SEPVEC = 7, // separation vector[3]
SPECK_NDATAFIELDS = 10
static char *fieldnames[] = {
"id",
"mass",
"nclump",
"rootid",
"treeaddr",
"ringsize",
"mu",
"sepvec3",
NULL
};
void kira_invalidate( struct stuff *st ) {
if(st->sl) st->sl->used = -1000000;
worldstuff *ww = (worldstuff *)st->dyndatadata;
if(ww) ww->slvalid = 0;
}
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;
case KIRA_TREE: ww->treearcs = (int)val; break;
case KIRA_TICKSCALE: ww->tickscale = val; break;
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;
case KIRA_TRACK: if(ww->tracking != (int)val) ww->wastracking = 0;
ww->tracking = (int)val; break;
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) {
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;
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
int open_parti(struct stuff *st, char *filename, int verbose)
{
ifstream s(filename);
if (!s) {
msg("Data file %s not found.", filename);
return 0;
}
worldbundle *wb;
struct worldstuff *ww = new worldstuff;
ww->wh = new worldbundleptr[1024];
ww->nh = 0;
while (ww->nh < 1024 && (wb = read_bundle(s, verbose)))
ww->wh[ww->nh++] = wb;
if (ww->nh == 0) {
msg("Data file %s not in worldbundle format.", filename);
return 0;
}
ww->ih = 0;
ww->tmin = ww->wh[0]->get_t_min();
ww->tmax = ww->wh[ww->nh-1]->get_t_max();
ww->sl = NULL;
ww->tcur = ww->treq = -1.0; // invalid
st->dyndata = 1;
st->dyndatafunc = get_parti;
st->dyndatadata = ww;
// 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]);
}
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
s.close();
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) {
*tmin = 0, *tmax = 1;
return 0;
}
*tmin = ww->tmin;
*tmax = ww->tmax;
return 1;
}
speck *add_speck(dyn *b, dyn *top, int addr, speck *sp, specklist *sl, worldstuff *ww)
sp->p.x[0] = b->get_pos()[0];
sp->p.x[1] = b->get_pos()[1];
sp->p.x[2] = b->get_pos()[2];
dyn *bb = b;
while (bb->get_elder_sister())
bb = bb->get_elder_sister();
if (bb->get_kepler()) sp->val[SPECK_NCLUMP] += 100;
// Addr is 0 for top-level leaf, 1 for top-level CM,
// constructed from parent addr otherwise.
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());
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;
}
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() &&
|| (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);
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;
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];
struct specklist *to_parti(dyn *root, struct stuff *st, struct specklist *sl)
{
worldstuff *ww = (worldstuff *)st->dyndatadata;
struct specklist *marksl = ww->marksl;
if(sl == NULL || sl != ww->sl) {
// Use NewN to allocate these in (potentially) shared memory,
// rather than new which will allocate in local malloc pool.
// Needed for virdir/cave version.
int smax = root->n_leaves();
ww->maxstars = 2*smax;
ww->maxmarks = 1+smax;
sl->bytesperspeck = SMALLSPECKSIZE( SPECK_NDATAFIELDS );
sl->specks = NewNSpeck(sl, ww->maxstars);
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;
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
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);
}
if(ww->wastracking < 0) ww->wastracking = 0; // Detach if tracked pcle not found now
return sl;
}
struct specklist *get_parti( struct stuff *st, double realtime )
{
struct worldstuff *ww = (struct worldstuff *)(st->dyndatadata);
if (!ww)
return NULL;
ww->treq = realtime;
if (realtime < ww->tmin) realtime = ww->tmin;
if (realtime > ww->tmax) realtime = ww->tmax;
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);
ww->sl = to_parti(root, st, ww->sl);
rmtree(root);
ww->ih = ih;
ww->tcur = realtime;
void kira_draw( struct stuff *st, struct specklist *slhead, Matrix *Tc2w, float radperpix )
{
struct worldstuff *ww = (struct worldstuff *)st->dyndatadata;
static Point zero = {0,0,0};
Point fwdvec = {0,0,-radperpix}; // scaled by pixels-per-radian
float fwdd;
vtfmpoint( &eyepoint, &zero, Tc2w );
vtfmvector( &fwd, &fwdvec, Tc2w );
fwdd = -vdot( &eyepoint, &fwd );
#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;
486
487
488
489
490
491
492
493
494
495
496
497
498
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
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();
}