void a3d_mat4f_orthonormal_copy(const a3d_mat4f_t* self, a3d_mat4f_t* copy) { assert(self); assert(copy); LOGD("debug"); /* * perform modified Gram-Schmitt ortho-normalization */ a3d_vec4f_t v0 = { .x = self->m00, .y = self->m01, .z = self->m02, .w = self->m03 }; a3d_vec4f_t v1 = { .x = self->m10, .y = self->m11, .z = self->m12, .w = self->m13 }; a3d_vec4f_t v2 = { .x = self->m20, .y = self->m21, .z = self->m22, .w = self->m23 }; a3d_vec4f_t v3 = { .x = self->m30, .y = self->m31, .z = self->m32, .w = self->m33 }; // normalize u0 a3d_vec4f_t u0; a3d_vec4f_normalize_copy(&v0, &u0); // subtract the component of v1 in the direction of u0 // normalize u1 a3d_vec4f_t u1; a3d_vec4f_t projuv; a3d_mat4f_projuv(&u0, &v1, &projuv); a3d_vec4f_subv_copy(&v1, &projuv, &u1); a3d_vec4f_normalize(&u1); // subtract the component of v2 in the direction of u1 // subtract the component of u2 in the direction of u0 // normalize u2 a3d_vec4f_t u2; a3d_mat4f_projuv(&u1, &v2, &projuv); a3d_vec4f_subv_copy(&v2, &projuv, &u2); a3d_mat4f_projuv(&u0, &u2, &projuv); a3d_vec4f_subv(&u2, &projuv); a3d_vec4f_normalize(&u2); // subtract the component of v3 in the direction of u2 // subtract the component of u3 in the direction of u1 // subtract the component of u3 in the direction of u0 // normalize u3 a3d_vec4f_t u3; a3d_mat4f_projuv(&u2, &v3, &projuv); a3d_vec4f_subv_copy(&v3, &projuv, &u3); a3d_mat4f_projuv(&u1, &u3, &projuv); a3d_vec4f_subv(&u3, &projuv); a3d_mat4f_projuv(&u0, &u3, &projuv); a3d_vec4f_subv(&u3, &projuv); a3d_vec4f_normalize(&u3); // copy the orthonormal vectors copy->m00 = u0.x; copy->m01 = u0.y; copy->m02 = u0.z; copy->m03 = u0.w; copy->m10 = u1.x; copy->m11 = u1.y; copy->m12 = u1.z; copy->m13 = u1.w; copy->m20 = u2.x; copy->m21 = u2.y; copy->m22 = u2.z; copy->m23 = u2.w; copy->m30 = u3.x; copy->m31 = u3.y; copy->m32 = u3.z; copy->m33 = u3.w; } /* * quaternion operations */ void a3d_mat4f_rotateq(a3d_mat4f_t* self, int load, const a3d_quaternion_t* q) { assert(self); assert(q); LOGD("debug load=%i", load); float x2 = q->v.x*q->v.x; float y2 = q->v.y*q->v.y; float z2 = q->v.z*q->v.z; float xy = q->v.x*q->v.y; float xz = q->v.x*q->v.z; float yz = q->v.y*q->v.z; float xw = q->v.x*q->s; float yw = q->v.y*q->s; float zw = q->v.z*q->s; // requires normalized quaternions a3d_mat4f_t m = { 1.0f - 2.0f*(y2 + z2), 2.0f*(xy - zw), 2.0f*(xz + yw), 0.0f, 2.0f*(xy + zw), 1.0f - 2.0f*(x2 + z2), 2.0f*(yz - xw), 0.0f, 2.0f*(xz - yw), 2.0f*(yz + xw), 1.0f - 2.0f*(x2 + y2), 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, }; if(load) a3d_mat4f_copy(&m, self); else a3d_mat4f_mulm(self, &m); } /* * GL matrix operations */ void a3d_mat4f_lookat(a3d_mat4f_t* self, int load, GLfloat eyex, GLfloat eyey, GLfloat eyez, GLfloat centerx, GLfloat centery, GLfloat centerz, GLfloat upx, GLfloat upy, GLfloat upz) { assert(self); LOGD("debug load=%i, eye=(%f,%f,%f), center=(%f,%f,%f), up=(%f,%f,%f)", load, eyex, eyey, eyez, centerx, centery, centerz, upx, upy, upz); a3d_vec3f_t eye = { eyex, eyey, eyez }; a3d_vec3f_t center = { centerx, centery, centerz }; a3d_vec3f_t up = { upx, upy, upz }; a3d_vec3f_t n; a3d_vec3f_subv_copy(¢er, &eye, &n); a3d_vec3f_normalize(&n); a3d_vec3f_normalize(&up); a3d_vec3f_t u; a3d_vec3f_t v; a3d_vec3f_cross_copy(&n, &up, &u); a3d_vec3f_cross_copy(&u, &n, &v); a3d_vec3f_normalize(&u); a3d_vec3f_normalize(&v); a3d_mat4f_t m = { u.x, v.x, -n.x, 0.0f, u.y, v.y, -n.y, 0.0f, u.z, v.z, -n.z, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, }; a3d_mat4f_translate(&m, 0, -eye.x, -eye.y, -eye.z); if(load) a3d_mat4f_copy(&m, self); else a3d_mat4f_mulm(self, &m); } void a3d_mat4f_perspective(a3d_mat4f_t* self, int load, GLfloat fovy, GLfloat aspect, GLfloat znear, GLfloat zfar) { assert(self); LOGD("debug load=%i, fovy=%f, aspect=%f, znear=%f, zfar=%f", load, fovy, aspect, znear, zfar); GLfloat f = 1.0f/tanf(fovy*(M_PI/180.0f)/2.0f); GLfloat m00 = f/aspect; GLfloat m11 = f; GLfloat m22 = (zfar + znear)/(znear - zfar); GLfloat m23 = (2.0f*zfar*znear)/(znear - zfar); a3d_mat4f_t m = { m00, 0.0f, 0.0f, 0.0f, 0.0f, m11, 0.0f, 0.0f, 0.0f, 0.0f, m22, -1.0f, 0.0f, 0.0f, m23, 0.0f, }; if(load) a3d_mat4f_copy(&m, self); else a3d_mat4f_mulm(self, &m); } void a3d_mat4f_perspectiveStereo(a3d_mat4f_t* pmL, a3d_mat4f_t* pmR, int load, GLfloat fovy, GLfloat aspect, GLfloat znear, GLfloat zfar, GLfloat convergence, GLfloat eye_separation) { assert(pmL); assert(pmR); // http://www.animesh.me/2011/05/rendering-3d-anaglyph-in-opengl.html GLfloat tan_fovy2 = tanf(fovy*(M_PI/180.0f)/2.0f); GLfloat es2 = eye_separation/2.0f; GLfloat top = znear*tan_fovy2; GLfloat bottom = -top; GLfloat a = aspect*tan_fovy2*convergence; GLfloat b = a - es2; GLfloat c = a + es2; GLfloat d = znear/convergence; GLfloat left = -b*d; GLfloat right = c*d; // left perspective matrix a3d_mat4f_frustum(pmL, load, left, right, bottom, top, znear, zfar); // right perspective matrix left = -c*d; right = b*d; a3d_mat4f_frustum(pmR, load, left, right, bottom, top, znear, zfar); }
void gear_draw(gear_t* self, a3d_mat4f_t* mvp, a3d_mat4f_t* mvm) { assert(self); LOGD("debug"); a3d_mat3f_t nm; a3d_mat4f_normalmatrix(mvm, &nm); a3d_vec3f_t light_position; a3d_vec3f_load(&light_position, 5.0f, 5.0f, 10.0); a3d_vec3f_normalize(&light_position); // TODO - optimize // front, back, front teeth and back teeth glUseProgram(self->face_program); glEnableVertexAttribArray(self->face_attribute_vertex); // compute color for flat shaded surface a3d_vec3f_t normal_front; a3d_vec4f_t color; a3d_vec3f_load(&normal_front, 0.0f, 0.0f, 1.0f); a3d_mat3f_mulv(&nm, &normal_front); a3d_vec3f_normalize(&normal_front); a3d_vec4f_load(&color, 0.2f, 0.2f, 0.2f, 1.0f); // ambient GLfloat ndotlp = a3d_vec3f_dot(&normal_front, &light_position); if(ndotlp > 0.0f) { a3d_vec4f_t diffuse; a3d_vec4f_load(&diffuse, ndotlp, ndotlp, ndotlp, 0.0f); a3d_vec4f_addv(&color, &diffuse); // ambient + diffuse a3d_vec4f_mulv(&color, &self->color); // color * (ambient + diffuse) } else { a3d_vec4f_mulv(&color, &self->color); } glUniform4fv(self->face_uniform_color, 1, (GLfloat*) &color); glUniformMatrix4fv(self->face_uniform_mvp, 1, GL_FALSE, (GLfloat*) mvp); glBindBuffer(GL_ARRAY_BUFFER, self->front_vid); glVertexAttribPointer(self->face_attribute_vertex, 3, GL_FLOAT, GL_FALSE, 0, 0); glDrawArrays(GL_TRIANGLE_STRIP, 0, self->front_ec); glBindBuffer(GL_ARRAY_BUFFER, self->front_teeth_vid); glVertexAttribPointer(self->face_attribute_vertex, 3, GL_FLOAT, GL_FALSE, 0, 0); glDrawArrays(GL_TRIANGLES, 0, self->front_teeth_ec); // compute color for flat shaded surface a3d_vec3f_t normal_back; a3d_vec3f_load(&normal_back, 0.0f, 0.0f, -1.0f); a3d_mat3f_mulv(&nm, &normal_back); a3d_vec3f_normalize(&normal_back); a3d_vec4f_load(&color, 0.2f, 0.2f, 0.2f, 1.0f); // reload ambient ndotlp = a3d_vec3f_dot(&normal_back, &light_position); if(ndotlp > 0.0f) { a3d_vec4f_t diffuse; a3d_vec4f_load(&diffuse, ndotlp, ndotlp, ndotlp, 0.0f); a3d_vec4f_addv(&color, &diffuse); // ambient + diffuse a3d_vec4f_mulv(&color, &self->color); // color * (ambient + diffuse) } else { a3d_vec4f_mulv(&color, &self->color); } glUniform4fv(self->face_uniform_color, 1, (GLfloat*) &color); glBindBuffer(GL_ARRAY_BUFFER, self->back_vid); glVertexAttribPointer(self->face_attribute_vertex, 3, GL_FLOAT, GL_FALSE, 0, 0); glDrawArrays(GL_TRIANGLE_STRIP, 0, self->back_ec); glBindBuffer(GL_ARRAY_BUFFER, self->back_teeth_vid); glVertexAttribPointer(self->face_attribute_vertex, 3, GL_FLOAT, GL_FALSE, 0, 0); glDrawArrays(GL_TRIANGLES, 0, self->back_teeth_ec); glDisableVertexAttribArray(self->face_attribute_vertex); // outward teeth glUseProgram(self->outward_program); glEnableVertexAttribArray(self->outward_attribute_vertex); glEnableVertexAttribArray(self->outward_attribute_normal); glUniform4fv(self->outward_uniform_color, 1, (GLfloat*) &self->color); glUniformMatrix3fv(self->outward_uniform_nm, 1, GL_FALSE, (GLfloat*) &nm); glUniformMatrix4fv(self->outward_uniform_mvp, 1, GL_FALSE, (GLfloat*) mvp); glBindBuffer(GL_ARRAY_BUFFER, self->outward_vid); glVertexAttribPointer(self->outward_attribute_vertex, 3, GL_FLOAT, GL_FALSE, 0, 0); glBindBuffer(GL_ARRAY_BUFFER, self->outward_nid); glVertexAttribPointer(self->outward_attribute_normal, 3, GL_FLOAT, GL_FALSE, 0, 0); glDrawArrays(GL_TRIANGLE_STRIP, 0, self->outward_ec); glDisableVertexAttribArray(self->outward_attribute_normal); glDisableVertexAttribArray(self->outward_attribute_vertex); // cylinder glUseProgram(self->cylinder_program); glEnableVertexAttribArray(self->cylinder_attribute_vertex); glEnableVertexAttribArray(self->cylinder_attribute_normal); glUniform4fv(self->cylinder_uniform_color, 1, (GLfloat*) &self->color); glUniformMatrix3fv(self->cylinder_uniform_nm, 1, GL_FALSE, (GLfloat*) &nm); glUniformMatrix4fv(self->cylinder_uniform_mvp, 1, GL_FALSE, (GLfloat*) mvp); glBindBuffer(GL_ARRAY_BUFFER, self->cylinder_vid); glVertexAttribPointer(self->cylinder_attribute_vertex, 3, GL_FLOAT, GL_FALSE, 0, 0); glBindBuffer(GL_ARRAY_BUFFER, self->cylinder_nid); glVertexAttribPointer(self->cylinder_attribute_normal, 3, GL_FLOAT, GL_FALSE, 0, 0); glDrawArrays(GL_TRIANGLE_STRIP, 0, self->cylinder_ec); glDisableVertexAttribArray(self->cylinder_attribute_normal); glDisableVertexAttribArray(self->cylinder_attribute_vertex); glUseProgram(0); glBindBuffer(GL_ARRAY_BUFFER, 0); }