float ShakerDoPyra(float targ1, float targ2, float *v0, float *v1, float *v2, float *v3, float *p0, float *p1, float *p2, float *p3, float wt, float inv_wt) { float d0[3], cp[3], d2[3], d3[3]; float av[3], t0[3], push[3]; float cur, dev, sc, result1, result2 = 0.0F; add3f(v1, v2, av); subtract3f(v2, v1, d2); add3f(v3, av, av); subtract3f(v3, v1, d3); subtract3f(av, v0, t0); cross_product3f(d2, d3, cp); scale3f(av, 0.33333333F, av); normalize3f(cp); subtract3f(av, v0, d0); cur = dot_product3f(d0, cp); dev = cur - targ1; result1 = (float) fabs(dev); if(result1 > R_SMALL8) { sc = wt * dev; if((cur * targ1) < 0.0) /* inverted */ sc = sc * inv_wt; /* inversion fixing weight */ scale3f(cp, sc, push); add3f(push, p0, p0); scale3f(push, 0.333333F, push); subtract3f(p1, push, p1); subtract3f(p2, push, p2); subtract3f(p3, push, p3); } if((targ2 >= 0.0F) && ((cur * targ1 > 0.0) || (fabs(targ1) < 0.1))) { /* so long as we're not inverted... also make sure v0 is the right distance from the average point */ cur = length3f(d0); normalize3f(d0); dev = cur - targ2; result2 = (float) fabs(dev); if(result2 > R_SMALL4) { sc = wt * dev * 2.0F; scale3f(d0, sc, push); add3f(push, p0, p0); scale3f(push, 0.333333F, push); subtract3f(p1, push, p1); subtract3f(p2, push, p2); subtract3f(p3, push, p3); } } return result1 + result2; }
/* fonction à itérer sur les sommets, donc v = e -> vertex décore v avec la normal égale à la moyen des produits vectoriel des faces. Marche uniquement en dim 3 avec des coordonnées flottantes */ static void set_average_normal3f(half_edge e, gl_vertex* v) { point3f A,B,C; vecteur3f_cell AB, AC, V; A = v->coord.a3f; /* initialize la normale à zéro */ GLnormal3f(v,0.0,0.0,0.0); /* on recule avec pred jusqu'à arriver au bord ou à faire un tour, pour être sur de regarder toutes les faces, même au bord */ half_edge e0 = e; while(e0->prev && e0->prev != e) e0 = e0->prev; half_edge e1 = e0, e2 = e1 -> next; unsigned char first = 1; /* boucle parcourant toutes les faces autour de e et additionnant tous les produits vectoriels des faces */ while(e1 && e2 && (first || e1 != e0)) { B = e1->opp->vertex->coord.a3f; C = e2->opp->vertex->coord.a3f; vec3f(&AB,A,B); vec3f(&AC,A,C); vec_prod3f(&V,&AB,&AC); add3f(e->vertex->normal.a3f,&V); first = 0; e1 = e2; e2 = e1 -> next; } /* finalement, on normalize la normale */ normalize3f(e->vertex->normal.a3f); }
float ShakerDoLine(float *v0, float *v1, float *v2, float *p0, float *p1, float *p2, float wt) { /* v0-v1-v2 */ float d0[3], d1[3], cp[3], d2[3], d3[3], d4[3], push[3]; float dev, sc, lcp, result; subtract3f(v2, v1, d2); subtract3f(v0, v1, d1); normalize3f(d2); normalize23f(d1, d0); cross_product3f(d2, d0, cp); lcp = (float) length3f(cp); if(lcp > R_SMALL4) { lcp = 1.0F / lcp; scale3f(cp, lcp, cp); /* axis 0 */ subtract3f(v2, v0, d3); normalize3f(d3); /* axis 1 */ cross_product3f(cp, d3, d4); normalize3f(d4); /* displacement direction */ dev = dot_product3f(d1, d4); /* current deviation */ if((result = (float) fabs(dev)) > R_SMALL8) { sc = wt * dev; scale3f(d4, sc, push); add3f(push, p1, p1); scale3f(push, 0.5F, push); subtract3f(p0, push, p0); subtract3f(p2, push, p2); } else { result = 0.0; } } else result = 0.0; return result; }
float ShakerGetPyra(float *targ2, float *v0, float *v1, float *v2, float *v3) { float d0[3], cp[3], d2[3], d3[3]; float av[3], t0[3]; add3f(v1, v2, av); subtract3f(v2, v1, d2); add3f(v3, av, av); subtract3f(v3, v1, d3); subtract3f(av, v0, t0); cross_product3f(d2, d3, cp); scale3f(av, 0.33333333F, av); normalize3f(cp); subtract3f(av, v0, d0); (*targ2) = length3f(d0); return (dot_product3f(d0, cp)); }
static void RepValence(CGO *cgo, bool s1, bool s2, bool isRamped, float *v1, float *v2, int *other, int a1, int a2, float *coord, float *color1, float *color2, int ord, float tube_size, int fancy, unsigned int b1, unsigned int b2, int a, bool b1masked, bool b2masked) { float d[3], t[3], p0[3], p1[3], p2[3]; int a3; const float indent = tube_size; /* direction vector */ subtract3f(v2, v1, p0); copy3f(p0, d); normalize3f(p0); /* need a prioritized third atom to get planarity */ a3 = ObjectMoleculeGetPrioritizedOther(other, a1, a2, NULL); if(a3 < 0) { t[0] = p0[0]; t[1] = p0[1]; t[2] = -p0[2]; } else { subtract3f(coord + 3 * a3, v1, t); normalize3f(t); } cross_product3f(d, t, p1); normalize3f(p1); if(length3f(p1) == 0.0) { p1[0] = p0[1]; p1[1] = p0[2]; p1[2] = p0[0]; cross_product3f(p0, p1, p2); normalize3f(p2); } else { cross_product3f(d, p1, p2); normalize3f(p2); } /* now we have a coordinate system */ mult3f(p2, tube_size, t); bool ord3 = (ord == 3); if (ord3) mult3f(t, 2.f, t); if (fancy || ord3){ RepLine(cgo, s1, s2, isRamped, v1, v2, color1, b1, b2, a, color2, b1masked, b2masked); } if(fancy) { float f[] = { indent, 1.f - indent }; float f_1[] = { 1.f - f[0], 1.f - f[1] }; float vv1[] = { (f_1[0] * v1[0] + f[0] * v2[0]) - 2 * t[0], (f_1[0] * v1[1] + f[0] * v2[1]) - 2 * t[1], (f_1[0] * v1[2] + f[0] * v2[2]) - 2 * t[2] }; float vv2[] = { (f_1[1] * v1[0] + f[1] * v2[0]) - 2 * t[0], (f_1[1] * v1[1] + f[1] * v2[1]) - 2 * t[1], (f_1[1] * v1[2] + f[1] * v2[2]) - 2 * t[2] }; RepLine(cgo, s1, s2, isRamped, vv1, vv2, color1, b1, b2, a, color2, b1masked, b2masked); } else { float vv1[][3] = { { v1[0] - t[0], v1[1] - t[1], v1[2] - t[2] }, { v1[0] + t[0], v1[1] + t[1], v1[2] + t[2] } }; float vv2[][3] = { { v2[0] - t[0], v2[1] - t[1], v2[2] - t[2] }, { v2[0] + t[0], v2[1] + t[1], v2[2] + t[2] } }; RepLine(cgo, s1, s2, isRamped, vv1[0], vv2[0], color1, b1, b2, a, color2, b1masked, b2masked); RepLine(cgo, s1, s2, isRamped, vv1[1], vv2[1], color1, b1, b2, a, color2, b1masked, b2masked); } }
static int RepWireZeroOrderBond(CGO *cgo, bool s1, bool s2, float *v1, float *v2, float *rgb1, float *rgb2, unsigned int b1, unsigned int b2, int a, float dash_gap, float dash_length, bool b1masked, bool b2masked) { int ok = true; float axis[3], naxis[3]; subtract3f(v2, v1, axis); copy3f(axis, naxis); normalize3f(naxis); float blen = length3f(axis); float dash_tot = dash_gap + dash_length; int ndashes = blen / dash_tot; // only do even number of dashes if (ndashes < 2) { ndashes = 2; } else if (ndashes % 2) { --ndashes; } float remspace = blen - (ndashes * dash_length); // remaining space for first gaps float dgap = remspace / (ndashes - 1.f); // endpoints at each vertex, therefore only account for ndashes-1 spaces float placep[3], placep2[3], adddlen[3], adddtot[3]; float dplace; int ndashes_drawn = 0; bool color2_set = false; mult3f(naxis, dash_length, adddlen); // adddlen - length of dash as x/y/z vector mult3f(naxis, dash_length + dgap, adddtot); // adddtot - length of dash plus gap as x/y/z vector copy3f(v1, placep); if (s1){ ok &= CGOColorv(cgo, rgb1); ok &= CGOPickColor(cgo, b1, b1masked ? cPickableNoPick : a); for (dplace = 0.f; (dplace+dash_length) < blen / 2.f; ){ add3f(placep, adddlen, placep2); cgo->add<cgo::draw::line>(placep, placep2); add3f(placep, adddtot, placep); dplace += dash_length + dgap; ++ndashes_drawn; } if (!s2){ if (dplace < blen / 2.f){ // if we are behind the mid-point, only s1, so draw a half-bond add3f(placep, adddlen, placep2); cgo->add<cgo::draw::line>(placep, placep2); add3f(placep, adddtot, placep); dplace += dash_length + dgap; ++ndashes_drawn; } } } else { float tmpp[3]; dplace = (ndashes/2) * (dash_length + dgap); mult3f(naxis, dplace, tmpp); add3f(v1, tmpp, placep); ndashes_drawn = ndashes/2; // if !s1, then definitely s2, so draw half-bond if (dplace <= blen / 2.f){ // if no s1, and we are behind the mid-point, draw half-bond with only s2 add3f(placep, adddlen, placep2); ok &= CGOColorv(cgo, rgb2); ok &= CGOPickColor(cgo, b2, b2masked ? cPickableNoPick : a); color2_set = true; cgo->add<cgo::draw::line>(placep, placep2); add3f(placep, adddtot, placep); dplace += dash_length + dgap; ++ndashes_drawn; } } if (s2){ if (dplace < blen / 2.f){ // if we are behind the mid-point, draw a split cylinder with both colors float tmpp[3]; mult3f(axis, .5f, tmpp); add3f(v1, tmpp, tmpp); cgo->add<cgo::draw::line>(placep, tmpp); add3f(placep, adddlen, placep2); if (!color2_set){ ok &= CGOColorv(cgo, rgb2); ok &= CGOPickColor(cgo, b2, b2masked ? cPickableNoPick : a); } cgo->add<cgo::draw::line>(tmpp, placep2); add3f(placep, adddtot, placep); dplace += dash_length + dgap; ++ndashes_drawn; } else if (!color2_set){ ok &= CGOColorv(cgo, rgb2); ok &= CGOPickColor(cgo, b2, b2masked ? cPickableNoPick : a); } while (ndashes_drawn < ndashes){ add3f(placep, adddlen, placep2); cgo->add<cgo::draw::line>(placep, placep2); add3f(placep, adddtot, placep); dplace += dash_length + dgap; ++ndashes_drawn; } } return ok; }
static void RepAromatic(CGO *cgo, bool s1, bool s2, bool isRamped, float *v1, float *v2, int *other, int a1, int a2, float *coord, float *color1, float *color2, float tube_size, int half_state, unsigned int b1, unsigned int b2, int a, bool b1masked, bool b2masked) { float d[3], t[3], p0[3], p1[3], p2[3], *vv; int a3; int double_sided; /* direction vector */ p0[0] = (v2[0] - v1[0]); p0[1] = (v2[1] - v1[1]); p0[2] = (v2[2] - v1[2]); copy3f(p0, d); normalize3f(p0); /* need a prioritized third atom to get planarity */ a3 = ObjectMoleculeGetPrioritizedOther(other, a1, a2, &double_sided); if(a3 < 0) { t[0] = p0[0]; t[1] = p0[1]; t[2] = -p0[2]; } else { vv = coord + 3 * a3; t[0] = *(vv++) - v1[0]; t[1] = *(vv++) - v1[1]; t[2] = *(vv++) - v1[2]; normalize3f(t); } cross_product3f(d, t, p1); normalize3f(p1); if(length3f(p1) == 0.0) { p1[0] = p0[1]; p1[1] = p0[2]; p1[2] = p0[0]; cross_product3f(p0, p1, p2); normalize3f(p2); } else { cross_product3f(d, p1, p2); normalize3f(p2); } t[0] = p2[0] * tube_size * 2; t[1] = p2[1] * tube_size * 2; t[2] = p2[2] * tube_size * 2; RepLine(cgo, s1, s2, isRamped, v1, v2, color1, b1, b2, a, color2, b1masked, b2masked); if (s1){ CGOColorv(cgo, color1); CGOPickColor(cgo, b1, b1masked ? cPickableNoPick : a); float f[] = { 0.14F, 0.4F } ; float f_1[] = { 1.0F - f[0], 1.0F - f[1] }; float pt1[] = { (f_1[0] * v1[0] + f[0] * v2[0]), (f_1[0] * v1[1] + f[0] * v2[1]), (f_1[0] * v1[2] + f[0] * v2[2]) }; float pt2[] = { (f_1[1] * v1[0] + f[1] * v2[0]), (f_1[1] * v1[1] + f[1] * v2[1]), (f_1[1] * v1[2] + f[1] * v2[2]) }; float p1[3], p2[3]; subtract3f(pt1, t, p1); subtract3f(pt2, t, p2); cgo->add<cgo::draw::line>(p1, p2); if(double_sided) { add3f(pt1, t, p1); add3f(pt2, t, p2); cgo->add<cgo::draw::line>(p1, p2); } } if (s2){ CGOColorv(cgo, color2); CGOPickColor(cgo, b2, b2masked ? cPickableNoPick : a); float f[] = { 0.6F, 0.86F } ; float f_1[] = { 1.0F - f[0], 1.0F - f[1] }; float pt1[] = { (f_1[0] * v1[0] + f[0] * v2[0]), (f_1[0] * v1[1] + f[0] * v2[1]), (f_1[0] * v1[2] + f[0] * v2[2]) }; float pt2[] = { (f_1[1] * v1[0] + f[1] * v2[0]), (f_1[1] * v1[1] + f[1] * v2[1]), (f_1[1] * v1[2] + f[1] * v2[2]) }; float p1[3], p2[3]; subtract3f(pt1, t, p1); subtract3f(pt2, t, p2); cgo->add<cgo::draw::line>(p1, p2); if(double_sided) { add3f(pt1, t, p1); add3f(pt2, t, p2); cgo->add<cgo::draw::line>(p1, p2); } } }
void RandomizeBodiesSplitData(NBodyConfig config, float* position_x, float *position_y, float *position_z, float *mass, float* velocity_x, float *velocity_y, float *velocity_z, float* color, float cluster_scale, float velocity_scale, int body_count) { if (color) { int v = 0; for (int i = 0; i < body_count; i++) { color[v++] = (float) rand() / (float) RAND_MAX; color[v++] = (float) rand() / (float) RAND_MAX; color[v++] = (float) rand() / (float) RAND_MAX; color[v++] = 1.0f; } } switch (config) { default: case NBODY_CONFIG_RANDOM: { float scale = cluster_scale * std::max(1.0f, body_count / (1024.f)); float vscale = velocity_scale * scale; int p = 0, v = 0; int i = 0; while (i < body_count) { float3 point; point[0] = (float) rand() / (float) RAND_MAX * 2.0f - 1.0f; point[1] = (float) rand() / (float) RAND_MAX * 2.0f - 1.0f; point[2] = (float) rand() / (float) RAND_MAX * 2.0f - 1.0f; float lenSqr = dot3f(point, point); if (lenSqr > 1) continue; float3 velocity; velocity[0] = (float) rand() / (float) RAND_MAX * 2.0f - 1.0f; velocity[1] = (float) rand() / (float) RAND_MAX * 2.0f - 1.0f; velocity[2] = (float) rand() / (float) RAND_MAX * 2.0f - 1.0f; lenSqr = dot3f(velocity, velocity); if (lenSqr > 1) continue; position_x[p] = point[0] * scale; // pos.x position_y[p] = point[1] * scale; // pos.y position_z[p] = point[2] * scale; // pos.z mass[p] = 1.0f; // mass velocity_x[v] = velocity[0] * vscale; // pos.x velocity_y[v] = velocity[1] * vscale; // pos.x velocity_z[v] = velocity[2] * vscale; // pos.x p++; v++; i++; } } break; case NBODY_CONFIG_SHELL: { float scale = cluster_scale; float vscale = scale * velocity_scale; float inner = 2.5f * scale; float outer = 4.0f * scale; int p = 0, v = 0; int i = 0; while (i < body_count) { float x, y, z; x = (float) rand() / (float) RAND_MAX * 2.0f - 1.0f; y = (float) rand() / (float) RAND_MAX * 2.0f - 1.0f; z = (float) rand() / (float) RAND_MAX * 2.0f - 1.0f; float3 point = { {x, y, z} }; float len = normalize3f(point); if (len > 1) continue; position_x[p] = point[0] * (inner + (outer - inner) * rand() / (float) RAND_MAX); position_y[p] = point[1] * (inner + (outer - inner) * rand() / (float) RAND_MAX); position_z[p] = point[2] * (inner + (outer - inner) * rand() / (float) RAND_MAX); mass[p] = 1.0f; x = 0.0f; y = 0.0f; z = 1.0f; float3 axis = { {x, y, z} }; normalize3f(axis); if (1 - dot3f(point, axis) < 1e-6) { axis[0] = point[1]; axis[1] = point[0]; normalize3f(axis); } float3 vv = { {position_x[i], position_y[i], position_z[i]} }; vv = cross3f(vv, axis); velocity_x[v] = vv[0] * vscale; velocity_y[v] = vv[1] * vscale; velocity_z[v] = vv[2] * vscale; p++; v++; i++; } } break; case NBODY_CONFIG_MWM31: ////////////// Galaxy collision //////////////////////////// { float scale = cluster_scale; float vscale = scale * velocity_scale; float mscale = scale * scale * scale; std::ifstream *infile; switch (body_count) { case 16384: infile = new std::ifstream(GalaxyDataFiles[0]); break; case 24576: infile = new std::ifstream(GalaxyDataFiles[1]); break; case 32768: infile = new std::ifstream(GalaxyDataFiles[2]); break; case 65536: infile = new std::ifstream(GalaxyDataFiles[3]); break; case 81920: infile = new std::ifstream(GalaxyDataFiles[4]); break; default: printf("Numbodies must be one of 16384, 24576, 32768, 65536 or 81920.\n"); exit(1); break; } int numPoints = 0; int p = 0; float pX, pY, pZ, vX, vY, vZ, bMass, bIDf; int bID; if (!infile->fail()) { while (!(infile->eof()) && numPoints < body_count) { numPoints++; *infile >> bMass >> pX >> pY >> pZ >> vX >> vY >> vZ >> bIDf; bID = (int)bIDf; bMass *= mscale; position_x[p] = scale * pX; position_y[p] = scale * pY; position_z[p] = scale * pZ; mass[p] = bMass; velocity_x[p] = vscale * vX; velocity_y[p] = vscale * vY; velocity_z[p] = vscale * vZ; SetupGalaxyColor(p, color, bID); p++; } } delete infile; } break; case NBODY_CONFIG_EXPAND: { float scale = cluster_scale * std::max(1.0f, body_count / (1024.f)); float vscale = scale * velocity_scale; int p = 0, v = 0; for (int i = 0; i < body_count;) { float3 point; point[0] = (float) rand() / (float) RAND_MAX * 2.0f - 1.0f; point[1] = (float) rand() / (float) RAND_MAX * 2.0f - 1.0f; point[2] = (float) rand() / (float) RAND_MAX * 2.0f - 1.0f; float lenSqr = dot3f(point, point); if (lenSqr > 1) continue; position_x[p] = point[0] * scale; // pos.x position_y[p] = point[1] * scale; // pos.y position_z[p] = point[2] * scale; // pos.z mass[p] = 1.0f; // mass velocity_x[v] = point[0] * vscale; // pos.x velocity_y[v] = point[1] * vscale; // pos.x velocity_z[v] = point[2] * vscale; // pos.x p++; v++; i++; } } break; } }
float ShakerDoPlan(float *v0, float *v1, float *v2, float *v3, float *p0, float *p1, float *p2, float *p3, float target, int fixed, float wt) { float result; float d01[3], d12[3], d23[3], d03[3], cp0[3], cp1[3], dp, sc, dev, d0[3], push[3]; double s01, s12, s23, s03; subtract3f(v0, v1, d01); subtract3f(v1, v2, d12); subtract3f(v2, v3, d23); subtract3f(v0, v3, d03); s03 = lengthsq3f(d03); s01 = lengthsq3f(d01); s12 = lengthsq3f(d12); s23 = lengthsq3f(d23); if((s03 < s01) || (s03 < s12) || (s03 < s23)) return 0.0F; cross_product3f(d01, d12, cp0); cross_product3f(d12, d23, cp1); normalize3f(cp0); normalize3f(cp1); dp = dot_product3f(cp0, cp1); result = (dev = 1.0F - (float) fabs(dp)); if(dev > R_SMALL4) { /* add3f(cp0,cp1,d0); normalize3f(d0); cross_product3f(cp0,d12,pos); dp2 = dot_product3f(cp1,pos); */ if(fixed && (dp * target < 0.0F)) { /* fixed & backwards... */ if(dp < 0.0F) { sc = -wt * dev * 0.5F; } else { sc = wt * dev * 0.5F; } sc *= 0.02F; /* weaken considerably to allow resolution of inconsistencies (folded rings, etc.) */ } else if(dp > 0) { sc = -wt * dev * 0.5F; } else { sc = wt * dev * 0.5F; } if(fixed && (fixed < 7)) { /* in small rings, ramp up the planarity factor */ sc *= 8; } else { sc *= 0.2F; } /* pair-wise nudges */ subtract3f(v0, v3, d0); normalize3f(d0); scale3f(d0, sc, push); add3f(push, p0, p0); subtract3f(p3, push, p3); subtract3f(v1, v2, d0); normalize3f(d0); scale3f(d0, sc, push); add3f(push, p1, p1); subtract3f(p2, push, p2); sc = -sc; subtract3f(v0, v2, d0); normalize3f(d0); scale3f(d0, sc, push); add3f(push, p0, p0); subtract3f(p2, push, p2); subtract3f(v1, v3, d0); normalize3f(d0); scale3f(d0, sc, push); add3f(push, p1, p1); subtract3f(p3, push, p3); } else { result = 0.0; } return result; }
void initcamera() { // initialize view (u,v,n) in world coordinates vrp.x = vrp.y = vrp.z = 0.0f; dir.x = 0.0f; dir.y = 0.0f; dir.z = -1.0f; up.x = 0.0f; up.y = 1.0f; up.z = 0.0f; // initialize viewvolume in image plane (assumes that imageplane reference point is 0,0,0) // adjust so we have same aspect ratio as window float fwidth = FRUSTUMWIDTH; float fheight = FRUSTUMHEIGHT; float aspect; if (viewport.w > viewport.h) { aspect = (float) viewport.w/viewport.h; fwidth = fwidth * aspect; } else { aspect = (float) viewport.h/viewport.w; fheight = fheight * aspect; } frustum.bottom = -fheight/2.0f; frustum.top = -frustum.bottom; frustum.left = -fwidth/2.0f; frustum.right = -frustum.left; // initialize eyepos origin #ifdef ORTHO e.u = 0.0f; e.v = 0.0f; e.n = -10000.0f; //ORTHO frustum.near = -2.0f; frustum.far = 2.0f; #else e.u = 0.0f; e.v = 0.0f; e.n = -5.0f; // PERSPECTIVE frustum.near = 0.1f; frustum.far = 100.0f; #endif // initialize viewvolume in image plane (assumes that imageplane reference point is 0,0,0) viewvolume.bottom = frustum.bottom; viewvolume.left = frustum.left; viewvolume.top = frustum.top; viewvolume.right = frustum.right; viewvolume.far = frustum.far; viewvolume.near = frustum.near; // set projection matrix #ifdef ORTHO setortho(scale, viewvolume); #else float fovy = 2.0f * atan(frustum.top/-e.n); fovy = fovy * DEGREES; setperspective(fovy, 1.0f, 0.1f, 100.0f); #endif // initialize view (u,v,n) in world coordinates camera.r.x = vrp.x; camera.r.y = vrp.y; camera.r.z = vrp.z; camera.n.x = dir.x; camera.n.y = dir.y; camera.n.z = dir.z; camera.v.x = up.x; camera.v.y = up.y; camera.v.z = up.z; camera.v = normalize3f(camera.v); camera.u = cross3f(camera.n, camera.v); camera.e.u = e.u; camera.e.v = e.v; camera.e.n = e.n; // set view to world transform matrix setvwm(vwm, camera); // set world to view transform matrix setwvm(wvm, camera); // initialize eyepos origin eyepos.u = e.u; eyepos.v = e.v; eyepos.n = e.n; return; }