/* * Common vector algebra functions * * A.k.a. Biblioteca con funciones útiles para los proyectos de * Computación Gráfica con SDL (Versión pirata de glutamato.h). * ****************************************************************************** * Note: Assumes normalized directions pretty much everywhere, for efficiency * ****************************************************************************** * * Copyright (C) 2006-2008 Alejandro Valenzuela Roca, * * This file is part of MotorJ, a free framework for videogame creation. * * * * MotorJ is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * MotorJ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with MotorJ. If not, see . */ #include "support.h" #ifdef NINTENDO_WII extern mjApplication App; #endif /*Implementación*/ /* Cheap random integers in range between 0 and range-1 (uses rand(), so it must be seeded using srand() */ unsigned rand_range(unsigned upperlimit){ return (unsigned)( (upperlimit*1.0) * rand() / ( RAND_MAX + 1.0 ) ); } /* Replace directory separation char (for WIN32 compatibility) */ char * replace_dir_char(const char * ruta){ char * ruta2 = NULL; int pos = 0; ruta2 = new char[strlen(ruta)+1]; while (ruta[pos] != '\0'){ if (ruta[pos] == NOSEPDIR){ ruta2[pos] = SEPDIR; } else { ruta2[pos] = ruta[pos]; } pos++; } ruta2[strlen(ruta)] = '\0'; return ruta2; } void _debug(char * file, int line, const char * format, ...) { FILE * ar; char buf[2048]; #ifdef DEBUGTOFILE ar = fopen("mj_debug.txt","a"); #else ar = NULL; #endif va_list va; va_start(va,format); snprintf(buf,2047,"(%s:%d): %s\n", file, line, format); if (ar) { vfprintf(ar,buf,va); fclose(ar); } vfprintf(stdout,buf,va); va_end(va); } /* glPushMatrix/glPopMatrix functions - for both shortand and Nintendo DS compatibility*/ void push(void) { glPushMatrix(); } void pop(void) { #ifndef NINTENDO_DS glPopMatrix(); #else glPopMatrix(1); #endif } /* Sets vectors to the state equal to that implied by glLoadIdentity() */ void initial_angle(vector3 * angles){ angles->x = 0; angles->y = 0; angles->z = 0; } void initial_dir(vector3 * direction){ direction->x = 0; direction->y = 0; direction->z = -1; } void initial_vdir(vector3 * vert_dir) { vert_dir->x = 0; vert_dir->y = 1; vert_dir->z = 0; } void initial_pos(vector3 * position){ position->x = 0; position->y = 0; position->z = 0; } /* Geometry/Math */ /* TODO: These functions must be replaced by something ds-native, involving 512 degrees */ /* Convierte rad_to_deg a deg_to_rad (útil para sen/cos) de math.h */ GLfloat deg_to_rad( GLfloat degs){ return (degs / 180)* 3.141592; } /* Y al revés */ GLfloat rad_to_deg( GLfloat rads){ return (rads * 180) / 3.141592; } /* Establish vector components */ vector3 * v3_est(GLfloat x, GLfloat y, GLfloat z, vector3 * u){ u->x = x; u->y = y; u->z = z; return u; } /* Set vectors as vectorial constants */ void v3_0(vector3 * u){ u->x = 0; u->y = 0; u->z = 0; } void v3_i(vector3 * u){ v3_0(u); u->x = 1; } void v3_j(vector3 * u){ v3_0(u); u->y = 1; } void v3_k(vector3 * u){ v3_0(u); u->z = 1; } void v3_1(vector3 * u){ u->x = 1; u->y = 1; u->z = 1; } /* Vector copy */ void vec_copy(vector3 & u, vector3 * r){ r->x = u.x; r->y = u.y; r->z = u.z; } /* Vectorial addition */ void vec_sum(float alpha, vector3 & u, vector3 * r){ r->x += alpha*u.x; r->y += alpha*u.y; r->z += alpha*u.z; } void vec_sum2(vector3 & u, vector3 * r){ r->x += u.x; r->y += u.y; r->z += u.z; } /* Dot product */ GLfloat dot(vector3 & u, vector3 & v){ return ((u.x*v.x)+ (u.y*v.y)+ (u.z*v.z)); } /* Cross product*/ void cross(vector3 & u, vector3 & v, vector3 * r){ r->x = (u.y*v.z) - (u.z*v.y); r->y = (u.z*v.x) - (u.x*v.z); r->z = (u.x*v.y) - (u.y*v.x); } /* Angle between two vectors*/ GLfloat vec_ang(vector3 & u, vector3 & v) { float pp = dot(u,v); float nv = (vec_norm(u)*vec_norm(v)); float ratio = pp/nv; /* Sometmes internal rounding causes slight errors to occur ( |ratio| slightly above 1) ...*/ if (ratio > 1.0) { ratio = (0.999999); } else if (ratio < -1.0) { ratio = (-0.999999); } return acosf(ratio); } /* Scalar component of one vector against another*/ GLfloat scal_comp(vector3 & u, vector3 & v){ return (dot(u,v)/vec_norm(v)); } /* Vectorial norm (length) of a vector */ GLfloat vec_norm(vector3 & u){ return (GLfloat) sqrt((u.y*u.y)+(u.x*u.x)+(u.z*u.z)); } /* Scalar-vector multiplication */ void mul_scal(GLfloat alpha, vector3 * u){ u->x *= alpha; u->y *= alpha; u->z *= alpha; } /* Vector normalization (set length to 1, but don't change its direction) */ float normalize( vector3 * u){ GLfloat n = vec_norm(*u); if ((n != 1.0) && (n != 0.0)){ mul_scal(1.0/n,u); } return n; } /* Scalar projection of a vector on another vector*/ GLfloat scal_proj(vector3 & u, vector3 & v){ return (scal_comp(u,v)/vec_norm(v)); } /* Vectorial projection of a vector on another */ void vec_proj(vector3 & u, vector3 & v, vector3 * r){ vec_copy(v,r); normalize(r); mul_scal(scal_comp(u,v),r); } /* Distance between 2 points */ GLfloat dist_p(vector3 & pos1, vector3 pos2){ vec_sum(-1,pos1,&pos2); return vec_norm(pos2); } /* Reflect a vector */ void vec_refl(vector3 & d, vector3 & n, vector3 * r) { vec_copy(n,r); mul_scal(-2.0*dot(n,d),r); vec_sum2(d,r); } void calc_normal(triangle &tr, vector3 * n) { vector3 e1; vector3 e2; vec_copy(* tr.v1, &e1); vec_copy(* tr.v2, &e2); vec_sum(-1, * tr.v0, &e1); vec_sum(-1, * tr.v0, &e2); cross(e1, e2, n); normalize(n); } /* Stolen from gluLookAt.. Source: http://www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/glu/lookat.html Directions must be _NORMALIZED_ */ // .. the same as gluLookAt, only backwards.. #ifdef NINTENDO_WII void obj_pos_rot(vector3 & pos, vector3 & dir, vector3 & dir_v) { Mtx transf; Mtx temp; vector3 s; vector3 u; guMtxTrans(*App.wiiCurrentMtx, pos.x, pos.y, pos.z); /* Note: f = dir = center - eye */ /* Formerly, in gluLookAt, s = f x v but since we need to do the opposite, s = v x f */ cross(dir_v, dir, &s); /* Formerly, in gluLookAt, u = s x f but since we need to do the opposite, u = f x s */ cross(dir, s, &u); /* Matrix components are specified in column-wise order (m[0] = M[1][1], m[1] = M[1][2], m[2] = M[1][3], etc) */ transf[0][0] = s.x; transf[0][1] = s.y; transf[0][2] = s.z; transf[0][3] = 0; transf[1][1] = u.x; transf[1][2] = u.y; transf[1][3] = u.z; transf[1][4] = 0; /* Note the direction components are not inverted anymore */ transf[2][0] = dir.x; transf[2][1] = dir.y; transf[2][2] = dir.z; transf[2][3] = 0; transf[3][0] = 0; transf[3][1] = 0; transf[3][2] = 0; transf[3][3] = 1; guMtxCopy(*App.wiiCurrentMtx, temp); guMtxConcat(temp, transf, *App.wiiCurrentMtx); } #endif #ifdef PC_SDL void obj_pos_rot(vector3 & pos, vector3 & dir, vector3 & dir_v){ //GLfloat m[16]; GLfloat transf[16]; vector3 s; vector3 u; // Translation is done first, without inverting the components glTranslatef(pos.x,pos.y,pos.z); /* Note: f = dir = center - eye */ /* Formerly, in gluLookAt, s = f x v but since we need to do the opposite, s = v x f */ cross(dir_v, dir, &s); /* Formerly, in gluLookAt, u = s x f but since we need to do the opposite, u = f x s */ cross(dir, s, &u); /* Matrix components are specified in column-wise order (m[0] = M[1][1], m[1] = M[1][2], m[2] = M[1][3], etc) */ transf[0] = s.x; transf[1] = s.y; transf[2] = s.z; transf[3] = 0; transf[4] = u.x; transf[5] = u.y; transf[6] = u.z; transf[7] = 0; /* Note the direction components are not inverted anymore */ transf[8] = dir.x; transf[9] = dir.y; transf[10] = dir.z; transf[11] = 0; transf[12] = 0; transf[13] = 0; transf[14] = 0; transf[15] = 1; glMultMatrixf(transf); } #endif #ifdef NINTENDO_DS // Nintendo DS-specific version void obj_pos_rot(vector3 & pos, vector3 & dir, vector3 & dir_v){ //GLfloat m[16]; m3x3 transf; vector3 s; vector3 u; // Translation is done first, without inverting the components // y sin invertir las componentes glTranslatef(pos.x,pos.y,pos.z); /* Note: f = dir = center - eye */ /* Formerly, in gluLookAt, s = f x v but since we need to do the opposite, s = v x f */ cross(dir_v, dir, &s); /* Formerly, in gluLookAt, u = s x f but since we need to do the opposite, u = f x s */ cross(dir, s, &u); /* Matrix components are specified in column-wise order (m[0] = M[1][1], m[1] = M[1][2], m[2] = M[1][3], etc) */ transf.m[0] = floattof32(s.x); transf.m[1] = floattof32(s.y); transf.m[2] = floattof32(s.z); // transf.m[3] = 0; transf.m[3] = floattof32(u.x); transf.m[4] = floattof32(u.y); transf.m[5] = floattof32(u.z); // transf.m[7] = 0; /* Note the direction components are not inverted anymore */ transf.m[6] = floattof32(dir.x); transf.m[7] = floattof32(dir.y); transf.m[8] = floattof32(dir.z); // transf.m[11] = 0; // transf.m[12] = 0; // transf.m[13] = 0; // transf.m[14] = 0; // transf.m[15] = 1; glMultMatrix3x3(&transf); } #endif void tr_pseudocen(triangle &tr, vector3 * center) { v3_est(2*tr.v0->x, 2*tr.v0->y, 2*tr.v0->z, center); vec_sum2 (*tr.v2, center); vec_sum2 (*tr.v1, center); mul_scal (0.25, center); //vec_sum (0.5, side1, center); }