/* * Copyright © 2009 Eric Anholt * Copyright © 2009 Ian D. Romanick * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Authors: * Eric Anholt * */ #include #include #include #include #include #include "glass.h" static const float identity_mat4[16] = { 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 }; /* result = mat4 * point4 */ void mult_m4_p4(float *result, const float *mat4, const float *point4) { result[0] = point4[0] * mat4[0 * 4 + 0] + point4[1] * mat4[1 * 4 + 0] + point4[2] * mat4[2 * 4 + 0] + point4[3] * mat4[3 * 4 + 0]; result[1] = point4[0] * mat4[0 * 4 + 1] + point4[1] * mat4[1 * 4 + 1] + point4[2] * mat4[2 * 4 + 1] + point4[3] * mat4[3 * 4 + 1]; result[2] = point4[0] * mat4[0 * 4 + 2] + point4[1] * mat4[1 * 4 + 2] + point4[2] * mat4[2 * 4 + 2] + point4[3] * mat4[3 * 4 + 2]; result[3] = point4[0] * mat4[0 * 4 + 3] + point4[1] * mat4[1 * 4 + 3] + point4[2] * mat4[2 * 4 + 3] + point4[3] * mat4[3 * 4 + 3]; } /* result = a4 * b4 */ void mult_m4_m4(float *result, const float *a4, const float *b4) { int row, col; float a_temp[16], b_temp[16]; if (a4 == result) { memcpy(a_temp, a4, sizeof(a_temp)); a4 = a_temp; } if (b4 == result) { memcpy(b_temp, b4, sizeof(b_temp)); b4 = b_temp; } for (col = 0; col < 4; col++) { for (row = 0; row < 4; row++) { result[col * 4 + row] = a4[0 * 4 + row] * b4[col * 4 + 0] + a4[1 * 4 + row] * b4[col * 4 + 1] + a4[2 * 4 + row] * b4[col * 4 + 2] + a4[3 * 4 + row] * b4[col * 4 + 3]; } } } void print_m4(const float *mat4, const char *name) { int row; printf("%s = \n", name); for (row = 0; row < 4; row++) { printf(" %c %7.4f %7.4f %7.4f %7.4f%s\n", row == 0 ? '[' : ' ', mat4[0 * 4 + row], mat4[1 * 4 + row], mat4[2 * 4 + row], mat4[3 * 4 + row], row == 3 ? " ]" : ""); } } void init_m4_translate(float *mat4, float x, float y, float z) { memcpy(mat4, identity_mat4, sizeof(identity_mat4)); mat4[3 * 4 + 0] = x; mat4[3 * 4 + 1] = y; mat4[3 * 4 + 2] = z; } void init_m4_x_rotate(float *mat4, float x_rads) { int i; for (i = 0; i < 16; i++) mat4[i] = 0.0; mat4[0 * 4 + 0] = 1.0; mat4[1 * 4 + 1] = cos(x_rads); mat4[1 * 4 + 2] = sin(x_rads); mat4[2 * 4 + 1] = -sin(x_rads); mat4[2 * 4 + 2] = cos(x_rads); mat4[3 * 4 + 3] = 1.0; } void init_m4_y_rotate(float *mat4, float y_rads) { int i; for (i = 0; i < 16; i++) mat4[i] = 0.0; mat4[1 * 4 + 1] = 1.0; mat4[0 * 4 + 0] = cos(y_rads); mat4[0 * 4 + 2] = sin(y_rads); mat4[2 * 4 + 0] = -sin(y_rads); mat4[2 * 4 + 2] = cos(y_rads); mat4[3 * 4 + 3] = 1.0; } void init_m4_z_rotate(float *mat4, float y_rads) { int i; for (i = 0; i < 16; i++) mat4[i] = 0.0; mat4[1 * 4 + 1] = 1.0; mat4[0 * 4 + 0] = cos(y_rads); mat4[0 * 4 + 2] = sin(y_rads); mat4[2 * 4 + 0] = -sin(y_rads); mat4[2 * 4 + 2] = cos(y_rads); mat4[3 * 4 + 3] = 1.0; } void init_m4_perspective(float *mat4, float fovy, float aspect, float near, float far) { double sine = sin(fovy / 2.0); double cosine = cos(fovy / 2.0); memcpy(mat4, identity_mat4, sizeof(identity_mat4)); mat4[0 * 4 + 0] = cosine / (sine * aspect); mat4[1 * 4 + 1] = cosine / sine; mat4[2 * 4 + 2] = -(far + near) / (far - near); mat4[2 * 4 + 3] = -1.0; mat4[3 * 4 + 2] = -2.0 * near * far / (far - near); mat4[3 * 4 + 3] = 0.0; } void print_GLUvec4(char *desc, const GLUvec4 *vec) { printf("%s: %f %f %f %f\n", desc, vec->values[0], vec->values[1], vec->values[2], vec->values[3]); } void print_GLUmat4(char *desc, const GLUmat4 *m) { int i; printf("%s:\n", desc); for (i = 0; i < 4; i++) { printf("%s%f %f %f %f%s\n", i == 0 ? "{" : " ", m->col[0].values[i], m->col[1].values[i], m->col[2].values[i], m->col[3].values[i], i == 0 ? "" : "}"); } } static float length_3v(GLUvec4 *vec) { return sqrt(vec->values[0] * vec->values[0] + vec->values[1] * vec->values[1] + vec->values[2] * vec->values[2]); } void make_sphere_frustum(GLUmat4 *mat, GLUvec4 *center, float radius) { float near_radius; float center_distance = length_3v(center); float near = center_distance - radius; float far = center_distance + radius; assert(near > 0); /* We want to make a frustum that just bounds the sphere. * Obviously the near/far will the length of the vector to the center * plus or minus the radius. For gluFrustum6, though, the l/r/t/b values * are on the near plane, so we have to figure out where a line from * the eye (0,0,0) tangent to the sphere ends up intersecting the near * plane. * * Given hideous ASCII art: * ___ * / \/\__ a = sqrt(n*n+2rn) * / r/\|t \__ * | /__|_____\ * | r | n * \ / * \_/ * * then tan θ = r/a = t/n. * so t = nr/a = nr/sqrt(n*n+2rn). */ near_radius = near * radius / sqrt(near * near + 2.0 * near * radius); gluFrustum6f(mat, -near_radius, near_radius, -near_radius, near_radius, near, far); }