/* * 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 /* Variables globalifobicas */ int stack_val[4] = {0}; int MatrixMode_val = 0; /*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); } /* Funciones para llevar el conteo de la pila de transformaciones */ void push(void){ glPushMatrix(); //stack_val[MatrixMode_val == GL_MODELVIEW]++; //printf("stack: %d ^\n",stack_val[MatrixMode_val == GL_MODELVIEW]); //return stack_val[MatrixMode_val == GL_MODELVIEW]; } void pop(void){ #ifndef NINTENDO_DS glPopMatrix(); #else glPopMatrix(1); #endif //stack_val[MatrixMode_val == GL_MODELVIEW]--; //printf("stack: %d v\n",stack_val[MatrixMode_val == GL_MODELVIEW]); //return stack_val[MatrixMode_val == GL_MODELVIEW]; } #ifndef NINTENDO_DS #ifndef NINTENDO_WII //FIXME: Should this function even exist? void setMM(int MatrixMode){ glMatrixMode(MatrixMode); MatrixMode_val = MatrixMode; } #endif #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; } /* Producto punto de vectores */ /* 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)); } //void vec_proj(vector3 u, vector3 v, vector3 * r); /* 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); } /* 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 XD #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); } #else #ifndef NINTENDO_DS 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); } #else // 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 #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); } #ifndef NINTENDO_DS #ifndef NINTENDO_WII // FIXME: Nintendo DS-specific version missing and needed for collisions.h void posMultGLMatrix(vector3 * v){ float m[16]; vector3 o; int r; o.x = v->x; o.y = v->y; o.z = v->z; glGetFloatv(GL_MODELVIEW_MATRIX,m); //for (r = 0; r < 16; r++){ //printf("m[%d]:%f\n",r,m[r]); //} v->x = m[0]*o.x + m[4]*o.y + m[8]*o.z; + m[12];//*1; v->y = m[1]*o.x + m[5]*o.y + m[9]*o.z; + m[13]; v->z = m[2]*o.x + m[6]*o.y + m[10]*o.z; + m[14]; // 1 = 1; } void vertex_at_act_pos(vector3 * v) { float m[16]; glGetFloatv(GL_MODELVIEW_MATRIX,(float * )&m); v->x = m[12];//*1; v->y = m[13]; v->z = m[14]; } /* Obtiene una OBB unitaria (la correspondiente al solidCube, pero en su dimensión paralela bizarra de las colisiones) */ void get_current_obb( obb * box) { float m[16]; glGetFloatv(GL_MODELVIEW_MATRIX,m); // Obtener centro v3_est(m[12],m[13],m[14],&box->c); //if ((obb->Hu < 0.1) || (obb->Hv < 0.1) || (obb->Hw <0.1)) //printf("WTF?!\n"); // Obtener las direcciones (como se quieren direcciones y NO puntos, NO se les suma // la "posición actual" (obb->c, o séase m[12]~m[14],etc) v3_est(m[0], m[1], m[2] , &box->u); v3_est(m[4], m[5], m[6] , &box->v); v3_est(m[8], m[9], m[10], &box->w); // Obtener dimensiones box->Hu = vec_norm(box->u)*0.5; box->Hv = vec_norm(box->v)*0.5; box->Hw = vec_norm(box->w)*0.5; normalize(&box->u); normalize(&box->v); normalize(&box->w); } #endif #endif