static void camOrbit(int dx, int dy) { const double radius = 200; double dist; Vec3 v = cam_position; Quaternion o = cam_orientation; Quaternion q, q2; /* We invert the transformation because we are transforming the camera * and not the scene. */ q = quat_conjugate(quat_trackball(dx, dy, radius)); /* The quaternion q gives us an intrinsic transformation, close to unity. * To make it extrinsic, we compute q2 = o * q * ~o */ q2 = quat_multiply(o, quat_multiply(q, quat_conjugate(o))); q2 = quat_normalize(q2); /* As round-off errors accumulate, the distance between the camera and the * target would normally fluctuate. We take steps to prevent that here. */ dist = vec3_length(v); v = quat_transform(q2, v); v = vec3_normalize(v); v = vec3_scale(v, dist); cam_position = v; cam_orientation = quat_multiply(q2, cam_orientation); }
struct model *load_model(const char *name) { char filename[1024]; unsigned char *data = NULL; struct model *model; int i, len; model = lookup(model_cache, name); if (model) return model; for (i = 0; i < nelem(formats); i++) { strlcpy(filename, name, sizeof filename); strlcat(filename, formats[i].suffix, sizeof filename); data = load_file(filename, &len); if (data) break; } if (!data) { warn("error: cannot find model: '%s'", name); return NULL; } model = formats[i].load(filename, data, len); if (!model) warn("error: cannot load model: '%s'", filename); free(data); if (model) model_cache = insert(model_cache, name, model); if (model && model->anim) { struct anim *anim = model->anim; struct pose a_from_org, b_from_org; vec4 org_from_a; extract_frame_root(&a_from_org, anim, 0); extract_frame_root(&b_from_org, anim, anim->frames - 1); vec_sub(anim->motion.position, b_from_org.position, a_from_org.position); quat_conjugate(org_from_a, a_from_org.rotation); quat_mul(anim->motion.rotation, b_from_org.rotation, org_from_a); vec_div(anim->motion.scale, b_from_org.scale, a_from_org.scale); } return model; }
/* rotate Internally used helper for CCameraObject::RotateByMouse */ static void rotate(float* camPos, float* lookAtPos, float* upVec, float xDir) { quat qRot, qView, qNewView; quat_rotate(qRot, deg_2_rad(xDir), upVec); qView[0] = lookAtPos[0] - camPos[0]; qView[1] = lookAtPos[1] - camPos[1]; qView[2] = lookAtPos[2] - camPos[2]; qView[3] = 0.0f; quat_mul(qRot, qView, qNewView); quat_conjugate(qRot); quat_mul(qNewView, qRot, qNewView); lookAtPos[0] = camPos[0] + qNewView[0]; lookAtPos[1] = camPos[1] + qNewView[1]; lookAtPos[2] = camPos[2] + qNewView[2]; }
void quat_invert(const Quat q, Quat r) { Quat conj = {0}; quat_conjugate(q, conj); /* r[0] = conj[0] * (1 / qdot( q, conj ) ); */ /* r[1] = conj[1] * (1 / qdot( q, conj ) ); */ /* r[2] = conj[2] * (1 / qdot( q, conj ) ); */ /* r[3] = conj[3] * (1 / qdot( q, conj ) ); */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wconversion" #pragma warning(push) #pragma warning(disable : 4244) r[0] = conj[0] / pow(qmagnitude(q), 2.0); r[1] = conj[1] / pow(qmagnitude(q), 2.0); r[2] = conj[2] / pow(qmagnitude(q), 2.0); r[3] = conj[3] / pow(qmagnitude(q), 2.0); #pragma warning(pop) #pragma GCC diagnostic pop }
/* quat_inverse: * A quaternion inverse is the conjugate divided by the normal. */ static INLINE void quat_inverse(AL_CONST QUAT *q, QUAT *out) { QUAT con; float norm; ASSERT(q); ASSERT(out); /* q^-1 = q^* / N(q) */ quat_conjugate(q, &con); norm = quat_normal(q); /* NOTE: If the normal is 0 then a divide-by-zero exception will occur, we * let this happen because the inverse of a zero quaternion is * undefined */ ASSERT(norm != 0); out->w = con.w / norm; out->x = con.x / norm; out->y = con.y / norm; out->z = con.z / norm; }
/* Apply incremental yaw, pitch and roll relative to the quaternion. * For example, if the quaternion represents an orientation of a ship, * this will apply yaw/pitch/roll *in the ship's local coord system to the * orientation. */ union quat *quat_apply_relative_yaw_pitch_roll(union quat *q, double yaw, double pitch, double roll) { union quat qyaw, qpitch, qroll, qrot, tempq, local_rotation, rotated_q; /* calculate amount of yaw to impart this iteration... */ quat_init_axis(&qyaw, 0.0, 1.0, 0.0, yaw); /* Calculate amount of pitch to impart this iteration... */ quat_init_axis(&qpitch, 0.0, 0.0, 1.0, pitch); /* Calculate amount of roll to impart this iteration... */ quat_init_axis(&qroll, 1.0, 0.0, 0.0, roll); /* Combine pitch, roll and yaw */ quat_mul(&tempq, &qyaw, &qpitch); quat_mul(&qrot, &tempq, &qroll); /* Convert rotation to local coordinate system */ quat_conjugate(&local_rotation, &qrot, q); /* Apply to local orientation */ quat_mul(&rotated_q, &local_rotation, q); quat_normalize_self(&rotated_q); *q = rotated_q; return q; }
/* Renders the frame and calls calcFps() */ static void render(RenderConf *rc) { double ws = world.worldSize; RenderMat3 m3; double m4[16]; calcFps(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /* 3D */ renderSet3D(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); mat3_from_quat(m3, quat_conjugate(cam_orientation)); mat4_from_mat3(m4, m3); glMultMatrixd(m4); glTranslatef(-cam_position.x, -cam_position.y, -cam_position.z); if (autorotate) camOrbit(5, 0); if (renderSPGridBoxes) renderBoxes(rc->numBoxes); if (renderWorldLoops) { /* Line loops for world box */ glColor3f(0.0, 1.0, 0.0); glBegin(GL_LINE_LOOP); glVertex3f(-ws/2, -ws/2, -ws/2); glVertex3f(-ws/2, -ws/2, +ws/2); glVertex3f(-ws/2, +ws/2, +ws/2); glVertex3f(-ws/2, +ws/2, -ws/2); glEnd(); glBegin(GL_LINE_LOOP); glVertex3f(+ws/2, -ws/2, -ws/2); glVertex3f(+ws/2, -ws/2, +ws/2); glVertex3f(+ws/2, +ws/2, +ws/2); glVertex3f(+ws/2, +ws/2, -ws/2); glEnd(); } /* Strands */ for (int s = 0; s < world.numStrands; s++) renderStrand(&world.strands[s], rc); /* Text */ renderSet2D(); const int n = 64; char string[n]; snprintf(string, n, "T = %lf K", getKineticTemperature()); renderString(string, 10, 40); snprintf(string, n, "t = %lf µs (dt = %lf fs)", getTime() / MICROSECONDS, getIntegratorTimeStep() / FEMTOSECONDS); renderString(string, 10, 25); int ips; double tps; getProgressPerSecond(&ips, &tps); snprintf(string, n, "ips = %d (time/min = %lf ns)", ips, tps / NANOSECONDS * 60); renderString(string, 10, 10); glLoadIdentity(); renderString(fps_string, 10, SCREEN_H - 10); StringList *node = strings; while (node != NULL) { renderString(node->rsc.string, node->rsc.x, node->rsc.y); node = node->next; } SDL_GL_SwapBuffers(); }
vec quat_rotate_vec(avec v, aquat q) { // ASSUME v3 == 0 return quat_quat_mul(quat_quat_mul(q, v), quat_conjugate(q)); }
vec3 quat_transform(quat q, vec3 v) { quat qv = (quat) { v.x, v.y, v.z, 0.0 }; qv = quat_mult(q, quat_mult(qv, quat_conjugate(q))); return (vec3) { q.x, q.y, q.z }; }