00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "jed_defs.h"
00028
00029
00030 #include <stdio.h>
00031 #include <stdlib.h>
00032 #include <string.h>
00033 #include "toolkits/entorno/camara.h"
00034 #include "matriz4.h"
00035
00036 #ifdef GLTT_ENABLED
00037 #include "toolkits/util/gl_fonts.h"
00038 #endif
00039
00040
00041
00042
00043
00044 static VECTOR obj, arr;
00045
00046 #define ESPERO(tipo, msg) \
00047 if ( tipo_token != (tipo) ) { \
00048 fprintf(stderr, "<CAMARA> ERROR: Esperaba %s y recibi [%s].\n", \
00049 (msg), cad); fflush(stderr); return FALSE; \
00050 }
00051
00052 #define DISMINUIR(n) \
00053 if ( (n) > 10000000 + EPSILON ) (n) /= 2; \
00054 else if ( (n) > 1000000 + EPSILON ) (n) -= 1000000; \
00055 else if ( (n) > 100000 + EPSILON ) (n) -= 100000; \
00056 else if ( (n) > 10000 + EPSILON ) (n) -= 10000; \
00057 else if ( (n) > 1000 + EPSILON ) (n) -= 1000; \
00058 else if ( (n) > 100 + EPSILON ) (n) -= 100; \
00059 else if ( (n) > 10 + EPSILON ) (n) -= 10; \
00060 else if ( (n) > 1 + EPSILON ) (n) -= 1; \
00061 else if ( (n) > 0.1 + EPSILON ) (n) -= 0.1; \
00062 else if ( (n) > 0.01 + EPSILON ) (n) -= 0.01; \
00063 else if ( (n) > 0.001 + EPSILON ) (n) -= 0.001; \
00064 else if ( (n) > 0.0001 + EPSILON ) (n) -= 0.0001; \
00065 else (n) = 0.0001;
00066
00067 #define AUMENTAR(n) \
00068 if ( (n) < 0.001 ) (n) += 0.0001; \
00069 else if ( (n) < 0.01 ) (n) += 0.001; \
00070 else if ( (n) < 0.1 - EPSILON ) (n) += 0.01; \
00071 else if ( (n) < 1 - EPSILON ) (n) += 0.1; \
00072 else if ( (n) < 10 - EPSILON ) (n) += 1; \
00073 else if ( (n) < 100 - EPSILON ) (n) += 10; \
00074 else if ( (n) < 1000 - EPSILON ) (n) += 100; \
00075 else if ( (n) < 10000 - EPSILON ) (n) += 1000; \
00076 else if ( (n) < 100000 - EPSILON ) (n) += 10000; \
00077 else if ( (n) < 1000000 - EPSILON ) (n) += 100000; \
00078 else if ( (n) < 10000000 - EPSILON ) (n) *= 2; \
00079 else (n) = 10000000;
00080
00081
00082
00083
00084
00085
00086
00087 CAMARA::CAMARA()
00088 {
00089
00090 _posicion.x = 2.5;
00091 _posicion.y = 0.5;
00092 _posicion.z = 0.5;
00093
00094
00095 float magnitud = 0;
00096 VECTOR k(0, 0, 1);
00097 _orientacion.importar_angulo_eje(magnitud, k);
00098
00099
00100 mostrar_etiqueta = FALSE;
00101 transparencia_etiqueta = 1.0;
00102 color_etiqueta.r = 1;
00103 color_etiqueta.g = 1;
00104 color_etiqueta.b = 0;
00105
00106
00107 _ventana_xtam = _ventana_ytam = 200;
00108 _fov = 60.0;
00109 modo_seguimiento = CAM_GLOBAL;
00110 modo_control = CAM_STANDARD;
00111 _modo_proyeccion = CAM_PERSPECTIVA;
00112 _near_plane = 0.05;
00113 _far_plane = 100;
00114
00115 _nombre_padre = NULL;
00116 _Padre = NULL;
00117
00118 _con_posicion = TRUE;
00119 tipo_modelo = 0;
00120 }
00121
00122 CAMARA::~CAMARA()
00123 {
00124 if ( _nombre_padre ) delete _nombre_padre;
00125 }
00126
00127 void
00128 CAMARA::set_far_plane(double f)
00129 {
00130 _far_plane = f;
00131 }
00132
00133 double
00134 CAMARA::far_plane(void)
00135 {
00136 return _far_plane;
00137 }
00138
00139 void
00140 CAMARA::set_near_plane(double f)
00141 {
00142 _near_plane = f;
00143 }
00144
00145 double
00146 CAMARA::near_plane(void)
00147 {
00148 return _near_plane;
00149 }
00150
00151 VECTOR CAMARA::posicion(void) { return _posicion; }
00152 QUATERNION CAMARA::orientacion(void) { return _orientacion; }
00153 void CAMARA::set_posicion(VECTOR p) { _posicion = p; }
00154 void CAMARA::set_orientacion(QUATERNION o) { _orientacion = o; }
00155 char * CAMARA::nombre_padre(void) { return _nombre_padre; }
00156 void CAMARA::asociar_padre(ENTIDAD *p) { _Padre = p; }
00157 double CAMARA::fov(void) { return _fov; };
00158
00159 void
00160 CAMARA::set_fov(double in_nuevo_fov)
00161 {
00162 if ( in_nuevo_fov > EPSILON && in_nuevo_fov < 180.0 ) {
00163 _fov = in_nuevo_fov;
00164 }
00165 }
00166
00167 static QUATERNION TMP_quaternion;
00168
00169 BOOLEAN
00170 CAMARA::consultar_variable(const char *nombre_variable, int &tipo, void **ref)
00180 {
00181 if ( strcmp(nombre_variable, "posicion") == 0 ) {
00182 tipo = T_VECTOR; (*ref) = &_posicion; return TRUE;
00183 }
00184 if ( strcmp(nombre_variable, "orientacion") == 0 ) {
00185
00186 TMP_quaternion = _orientacion;
00187 tipo = T_QUATERNION;(*ref) = &TMP_quaternion; return TRUE;
00188 }
00189 ;
00190 return FALSE;
00191 }
00192
00193 BOOLEAN
00194 CAMARA::minmax_visible(VECTOR esquinas[8])
00209 {
00210
00211 MATRIZ_4x4 R, T1, T2, R1, R2;
00212 QUATERNION p_ori;
00213 VECTOR p_pos(0, 0, 0);
00214 void *interfaz;
00215 int tipo;
00216
00217 if ( _Padre && _Padre->consultar_variable("posicion", tipo, &interfaz) &&
00218 _con_posicion ) {
00219 if ( tipo == T_VECTOR ) p_pos = (*(VECTOR *)interfaz);
00220 }
00221
00222 T1.translacion(_posicion.x, _posicion.y, _posicion.z);
00223 T2.translacion(p_pos.x, p_pos.y, p_pos.z);
00224
00225 R1.importar_quaternion(_orientacion);
00226
00227 if ( _Padre &&
00228 _Padre->consultar_variable("orientacion_absoluta", tipo, &interfaz) &&
00229 tipo == T_QUATERNION ) {
00230 p_ori = (*(QUATERNION *)interfaz);
00231 R2.importar_quaternion(p_ori);
00232 R = T2 * (R2 * (T1 * R1));
00233 }
00234 else {
00235 R = T2 * (T1 * R1);
00236 }
00237
00238
00239 double xn = 1, yn = 1;
00240 double xf = 1, yf = 1;
00241
00242 if ( _modo_proyeccion != CAM_PARALELA ) {
00243 yn = 2 * _near_plane * tan(DEG2RAD(_fov) / 2);
00244 xn = yn * ((double)_ventana_xtam/(double)_ventana_ytam);
00245 }
00246 else {
00247 if ( _ventana_xtam > _ventana_ytam ) {
00248 xn = 1;
00249 yn = (double)_ventana_ytam / (double)_ventana_xtam;
00250 }
00251 else {
00252 xn = (double)_ventana_xtam / (double)_ventana_ytam;
00253 yn = 1;
00254 }
00255 }
00256
00257 xf = xn;
00258 yf = yn;
00259 if ( _modo_proyeccion != CAM_PARALELA ) {
00260 yf = 2 * _far_plane * tan(DEG2RAD(_fov) / 2);
00261 xf = yf * ((double)_ventana_xtam/(double)_ventana_ytam);
00262 }
00263
00264
00265 VECTOR normales_planos[6];
00266 VECTOR puntos_planos[6];
00267 VECTOR p1, p2, p3;
00268 int i;
00269
00270 for ( i = 0; i < 6; i++ ) {
00271 switch ( i ) {
00272 case 0:
00273 p1.x = _near_plane; p1.y = xn/2; p1.z = -yn/2;
00274 p2.x = _near_plane; p2.y = -xn/2; p2.z = yn/2;
00275 p3.x = _near_plane; p3.y = -xn/2; p3.z = -yn/2;
00276 break;
00277 case 1:
00278 p1.x = _near_plane; p1.y = xn/2; p1.z = yn/2;
00279 p2.x = _far_plane; p2.y = xf/2; p2.z = yf/2;
00280 p3.x = _near_plane; p3.y = -xn/2; p3.z = yn/2;
00281 break;
00282 case 2:
00283 p1.x = _near_plane; p1.y = xn/2; p1.z = -yn/2;
00284 p2.x = _far_plane; p2.y = xf/2; p2.z = -yf/2;
00285 p3.x = _near_plane; p3.y = xn/2; p3.z = yn/2;
00286 break;
00287 case 3:
00288 p1.x = _near_plane; p1.y = -xn/2; p1.z = -yn/2;
00289 p2.x = _far_plane; p2.y = -xf/2; p2.z = -yf/2;
00290 p3.x = _near_plane; p3.y = xn/2; p3.z = -yn/2;
00291 break;
00292 case 4:
00293 p1.x = _near_plane; p1.y = -xn/2; p1.z = -yn/2;
00294 p2.x = _near_plane; p2.y = -xn/2; p2.z = yn/2;
00295 p3.x = _far_plane; p3.y = -xf/2; p3.z = -yf/2;
00296 break;
00297 case 5:
00298 p1.x = _far_plane; p1.y = -xf/2; p1.z = yf/2;
00299 p2.x = _far_plane; p2.y = xf/2; p2.z = -yf/2;
00300 p3.x = _far_plane; p3.y = -xf/2; p3.z = -yf/2;
00301 break;
00302 default: break;
00303 }
00304 p1 = R * p1;
00305 p2 = R * p2;
00306 p3 = R * p3;
00307
00308 normales_planos[i] = ((p2 - p1).producto_cruz(p3 - p1));
00309 normales_planos[i].normalizar();
00310 puntos_planos[i] = p1;
00311 }
00312
00313
00314 int j;
00315 BOOLEAN fuera;
00316 VECTOR p;
00317
00318 for ( i = 0; i < 6; i++ ) {
00319 fuera = TRUE;
00320 for ( j = 0; j < 8; j++ ) {
00321 p = esquinas[j] - puntos_planos[i];
00322 if ( p.producto_punto(normales_planos[i]) > 0 ) {
00323 fuera = FALSE;
00324 break;
00325 }
00326 }
00327 if ( fuera ) return FALSE;
00328 }
00329
00330 return TRUE;
00331 }
00332
00333 BOOLEAN
00334 CAMARA::proyectar_punto(VECTOR *in_P, double *out_U, double *out_V)
00374 {
00375
00376 preprocesar_vista();
00377 (*out_U) = 0;
00378 (*out_V) = 0;
00379
00380 double factor_fov = ((double)_ventana_xtam/(double)_ventana_ytam);
00381 double machete = 1/tan(DEG2RAD(_fov/2));
00382
00383 _up.normalizar();
00384 _up = _up * machete;
00385 _right.normalizar();
00386 _right = _right * machete / factor_fov;
00387
00388
00389 RAYO r;
00390
00391 r.origen = _pos;
00392 r.direccion = ((*in_P) - _pos);
00393 if ( r.direccion.norma() < EPSILON ) {
00394 return FALSE;
00395 }
00396 r.direccion.normalizar();
00397
00398
00399 double A, B, C, D;
00400 VECTOR normal = _dir*(-1);
00401
00402 normal.normalizar();
00403 A = normal.x;
00404 B = normal.y;
00405 C = normal.z;
00406 D = -A*(_pos.x+A/2) - B*(_pos.y+B/2) - C*(_pos.z+C/2);
00407
00408
00409
00410
00411 VECTOR p_prima;
00412 double t;
00413
00414 t = (A*r.origen.x + B*r.origen.y + C*r.origen.z + D) /
00415 (A*r.direccion.x + B*r.direccion.y + C*r.direccion.z);
00416
00417 if ( t < EPSILON ) {
00418 return FALSE;
00419 }
00420
00421 p_prima = r.origen + r.direccion*t;
00422
00423
00424 VECTOR centro;
00425
00426 centro = _dir;
00427 centro.normalizar();
00428 centro = centro*_near_plane + _pos;
00429 p_prima = p_prima - centro;
00430
00431
00432 (*out_U) = (p_prima.producto_punto(_right)+0.5);
00433 (*out_V) = (-p_prima.producto_punto(_up)+0.5);
00434
00435
00436
00437 if ( (*out_U) < -1 || (*out_U) > 2 ||
00438 (*out_V) < -1 || (*out_V) > 2 ) {
00439 return FALSE;
00440 }
00441
00442 (*out_U) *= _ventana_xtam;
00443 (*out_V) *= _ventana_ytam;
00444
00445
00446
00447 return TRUE;
00448 }
00449
00450 void
00451 CAMARA::preprocesar_vista(void)
00459 {
00460
00461 MATRIZ_4x4 R, T1, T2, R1, R2;
00462 QUATERNION p_ori;
00463 VECTOR p_pos(0, 0, 0);
00464 void *interfaz;
00465 int tipo;
00466
00467 if ( _Padre && _Padre->consultar_variable("posicion", tipo, &interfaz) &&
00468 _con_posicion ) {
00469 if ( tipo == T_VECTOR ) p_pos = (*(VECTOR *)interfaz);
00470 }
00471
00472
00473
00474 T1.translacion(-_posicion.x, -_posicion.y, -_posicion.z);
00475 T2.translacion(-p_pos.x, -p_pos.y, -p_pos.z);
00476
00477 R1.importar_quaternion(_orientacion);
00478
00479 if ( _Padre &&
00480 _Padre->consultar_variable("orientacion_absoluta", tipo, &interfaz) &&
00481 tipo == T_QUATERNION ) {
00482 p_ori = (*(QUATERNION *)interfaz);
00483 R2.importar_quaternion(p_ori);
00484 R = R1.inversa() * (T1 * (R2.inversa() * T2));
00485 }
00486 else {
00487 R = R1.inversa() * (T1 * T2);
00488 }
00489
00490
00491 MATRIZ_4x4 R_i = R.inversa();
00492 double factor_fov = ((double)_ventana_xtam/(double)_ventana_ytam);
00493
00494 _right.x = _right.z = 0;
00495 _right.y = -factor_fov * tan(DEG2RAD(_fov/2));
00496 _up.x = _up.y = 0;
00497 _up.z = tan(DEG2RAD(_fov/2));
00498 _dir.x = 0.5;
00499 _dir.y = _dir.z = 0;
00500 _pos = _posicion + p_pos;
00501 _dir = R_i * _dir;
00502 _up = R_i * _up;
00503 _right = R_i * _right;
00504 }
00505
00506 MATRIZ_4x4
00507 CAMARA::calcular_matriz_de_proyeccion(int modo_stereo)
00514 {
00515
00516
00517
00518
00519
00520
00521
00522
00523 double izq, der, arr, aba, aspecto;
00524 MATRIZ_4x4 P;
00525
00526 switch ( _modo_proyeccion ) {
00527 case CAM_PARALELA:
00528 P.ortho(-1, 1, -1, 1, _near_plane, _far_plane);
00529 break;
00530 case CAM_PERSPECTIVA: default:
00531
00532
00533
00534 aspecto = (double)_ventana_xtam/(double)_ventana_ytam;
00535 arr = _near_plane * tan(_fov * PI / 360.0);
00536 aba = -arr;
00537 izq = aspecto * aba;
00538 der = aspecto * arr;
00539 P.frustum(izq, der, aba, arr, _near_plane, _far_plane);
00540 break;
00541 }
00542
00543
00544 MATRIZ_4x4 R, T1, T2, R1, R_adic2, R_adic1, R2, Tstereo;
00545 QUATERNION p_ori;
00546 VECTOR p_pos(0, 0, 0), pstereo;
00547 void *interfaz;
00548 int tipo;
00549 double factor_distancia_entre_ojos = 0.04;
00550
00551 if ( _Padre && _Padre->consultar_variable("posicion", tipo, &interfaz) &&
00552 _con_posicion ) {
00553 if ( tipo == T_VECTOR ) p_pos = (*(VECTOR *)interfaz);
00554 }
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564 R1.importar_quaternion(_orientacion);
00565
00566 T1.translacion(-_posicion.x, -_posicion.y, -_posicion.z);
00567 T2.translacion(-p_pos.x, -p_pos.y, -p_pos.z);
00568
00569 R_adic2.rotacion_eje(DEG2RAD(90), 0, 0, 1);
00570 R_adic1.rotacion_eje(DEG2RAD(-90), 1, 0, 0);
00571
00572 if ( _Padre &&
00573 _Padre->consultar_variable("orientacion_absoluta", tipo, &interfaz) &&
00574 tipo == T_QUATERNION ) {
00575 p_ori = (*(QUATERNION *)interfaz);
00576 R2.importar_quaternion(p_ori);
00577 R = R1.inversa() * (T1 * (R2.inversa() * T2));
00578 }
00579 else {
00580 R = R1.inversa() * (T1 * T2);
00581 }
00582
00583 R = R_adic1 * (R_adic2 * R);
00584
00585 if ( modo_stereo == 1 ) {
00586 pstereo.x = -R.M[0][0] * factor_distancia_entre_ojos;
00587 pstereo.y = -R.M[0][1] * factor_distancia_entre_ojos;
00588 pstereo.z = -R.M[0][2] * factor_distancia_entre_ojos;
00589 Tstereo.translacion(pstereo.x, pstereo.y, pstereo.z);
00590 R = R * Tstereo;
00591 }
00592 if ( modo_stereo == 2 ) {
00593 pstereo.x = R.M[0][0] * factor_distancia_entre_ojos;
00594 pstereo.y = R.M[0][1] * factor_distancia_entre_ojos;
00595 pstereo.z = R.M[0][2] * factor_distancia_entre_ojos;
00596 Tstereo.translacion(pstereo.x, pstereo.y, pstereo.z);
00597 R = R * Tstereo;
00598 }
00599
00600 R = P * R;
00601 return R;
00602 }
00603
00604
00605
00606 #ifdef GL_ENABLED
00607
00608 void
00609 CAMARA::pintar_base_gl(void)
00610 {
00611 VECTOR o(0, 0, 0);
00612 VECTOR i(1, 0, 0);
00613 VECTOR j(0, 1, 0);
00614 VECTOR k(0, 0, 1);
00615
00616 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
00617 glDisable(GL_LIGHTING);
00618 glDisable(GL_TEXTURE_2D);
00619 glShadeModel(GL_FLAT);
00620 glColor3f(1, 0, 0); PINTAR_VECTOR_GL(o, i, 0.05, 0.3, 0.1);
00621 glColor3f(0, 1, 0); PINTAR_VECTOR_GL(o, j, 0.05, 0.3, 0.1);
00622 glColor3f(0, 0, 1); PINTAR_VECTOR_GL(o, k, 0.05, 0.3, 0.1);
00623 }
00624
00625 void
00626 CAMARA::pintar_volumen_gl(void)
00627 {
00628
00629
00630 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
00631 glDisable(GL_LIGHTING);
00632 glDisable(GL_TEXTURE_2D);
00633 glShadeModel(GL_FLAT);
00634
00635
00636 double xn = 1, yn = 1;
00637 double xf = 1, yf = 1;
00638
00639 if ( _modo_proyeccion != CAM_PARALELA ) {
00640 yn = 2 * _near_plane * tan(DEG2RAD(_fov) / 2);
00641 xn = yn * ((double)_ventana_xtam/(double)_ventana_ytam);
00642 }
00643 else {
00644 if ( _ventana_xtam > _ventana_ytam ) {
00645 xn = 1;
00646 yn = (double)_ventana_ytam / (double)_ventana_xtam;
00647 }
00648 else {
00649 xn = (double)_ventana_xtam / (double)_ventana_ytam;
00650 yn = 1;
00651 }
00652 }
00653
00654 xf = xn;
00655 yf = yn;
00656 if ( _modo_proyeccion != CAM_PARALELA ) {
00657 yf = 2 * _far_plane * tan(DEG2RAD(_fov) / 2);
00658 xf = yf * ((double)_ventana_xtam/(double)_ventana_ytam);
00659 }
00660
00661
00662 glColor3f(1, 0.5, 0.5);
00663 glBegin(GL_POINTS);
00664 glVertex3d(0, 0, 0);
00665 glEnd();
00666
00667 glDisable(GL_LIGHTING);
00668 glColor3f(0, 1, 1);
00669 glBegin(GL_LINE_LOOP);
00670 glVertex3d(_near_plane, -xn/2, -yn/2);
00671 glVertex3d(_near_plane, xn/2, -yn/2);
00672 glVertex3d(_near_plane, xn/2, yn/2);
00673 glVertex3d(_near_plane, -xn/2, yn/2);
00674 glEnd();
00675 glBegin(GL_LINES);
00676 glVertex3d(_near_plane, -xn/10, -yn/10);
00677 glVertex3d(_near_plane, xn/10, yn/10);
00678 glVertex3d(_near_plane, xn/10, -yn/10);
00679 glVertex3d(_near_plane, -xn/10, yn/10);
00680 glVertex3d(_near_plane, -xn/10, yn/2);
00681 glVertex3d(_near_plane, 0, yn/2+yn/10);
00682 glVertex3d(_near_plane, 0, yn/2+yn/10);
00683 glVertex3d(_near_plane, xn/10, yn/2);
00684 glEnd();
00685
00686 glColor3f(0, 1, 1);
00687 glBegin(GL_LINE_LOOP);
00688 glVertex3d(_far_plane, -xf/2, -yf/2);
00689 glVertex3d(_far_plane, xf/2, -yf/2);
00690 glVertex3d(_far_plane, xf/2, yf/2);
00691 glVertex3d(_far_plane, -xf/2, yf/2);
00692 glEnd();
00693 glBegin(GL_LINES);
00694 glVertex3d(_far_plane, -xf/10, -yf/10);
00695 glVertex3d(_far_plane, xf/10, yf/10);
00696 glVertex3d(_far_plane, xf/10, -yf/10);
00697 glVertex3d(_far_plane, -xf/10, yf/10);
00698 glVertex3d(_far_plane, -xf/10, yf/2);
00699 glVertex3d(_far_plane, 0, yf/2+yf/10);
00700 glVertex3d(_far_plane, 0, yf/2+yf/10);
00701 glVertex3d(_far_plane, xf/10, yf/2);
00702 glEnd();
00703
00704 glBegin(GL_LINES);
00705 glVertex3d(_near_plane, -xn/2, -yn/2);
00706 glVertex3d(_far_plane, -xf/2, -yf/2);
00707 glVertex3d(_near_plane, xn/2, -yn/2);
00708 glVertex3d(_far_plane, xf/2, -yf/2);
00709 glVertex3d(_near_plane, xn/2, yn/2);
00710 glVertex3d(_far_plane, xf/2, yf/2);
00711 glVertex3d(_near_plane, -xn/2, yn/2);
00712 glVertex3d(_far_plane, -xf/2, yf/2);
00713 glEnd();
00714 }
00715
00716 void
00717 CAMARA::set_modelo(int val)
00724 {
00725 tipo_modelo = val;
00726 }
00727
00728 int
00729 CAMARA::modelo(void)
00730 {
00731 return tipo_modelo;
00732 }
00733
00734 void
00735 CAMARA::pintar_gl(void)
00742 {
00743 if ( !tipo_modelo ) return;
00744
00745
00746 MATRIZ_4x4 R, T1, T2, R1, R2;
00747 QUATERNION p_ori;
00748 VECTOR p_pos(0, 0, 0);
00749 void *interfaz;
00750 int tipo;
00751
00752 if ( _Padre && _Padre->consultar_variable("posicion", tipo, &interfaz) &&
00753 _con_posicion ) {
00754 if ( tipo == T_VECTOR ) p_pos = (*(VECTOR *)interfaz);
00755 }
00756
00757 T1.translacion(_posicion.x, _posicion.y, _posicion.z);
00758 T2.translacion(p_pos.x, p_pos.y, p_pos.z);
00759
00760 R1.importar_quaternion(_orientacion);
00761
00762 if ( _Padre &&
00763 _Padre->consultar_variable("orientacion_absoluta", tipo, &interfaz) &&
00764 tipo == T_QUATERNION ) {
00765 p_ori = (*(QUATERNION *)interfaz);
00766 R2.importar_quaternion(p_ori);
00767 R = T2 * (R2 * (T1 * R1));
00768 }
00769 else {
00770 R = T2 * (T1 * R1);
00771 }
00772
00773
00774 glPushMatrix();
00775 R.cargar_gl();
00776 switch ( tipo_modelo ) {
00777 case 1: pintar_base_gl(); break;
00778 case 2: default: pintar_volumen_gl();
00779 }
00780 glPopMatrix();
00781 }
00782
00783 #endif // GL_ENABLED
00784
00785
00786
00787 #ifdef GL_ENABLED
00788
00789 void
00790 CAMARA::activar_gl(int modo_stereo)
00807 {
00808 MATRIZ_4x4 R;
00809
00810
00811 glMatrixMode(GL_PROJECTION);
00812 glLoadIdentity();
00813
00814 R = calcular_matriz_de_proyeccion(modo_stereo);
00815 R.cargar_gl();
00816
00817
00818 #ifdef TEMPORAL
00819 MATRIZ_4x4 T;
00820
00821 T.importar_gl();
00822 T.imprimir();
00823 #endif
00824
00825
00826 glMatrixMode(GL_MODELVIEW);
00827 }
00828
00829 void
00830 CAMARA::activar_centro_gl(void)
00837 {
00838 VECTOR p = _posicion;
00839
00840 _posicion.x = _posicion.y = _posicion.z = 0;
00841 _con_posicion = FALSE;
00842 activar_gl();
00843 _con_posicion = TRUE;
00844 _posicion = p;
00845 }
00846
00847 void
00848 CAMARA::subbillboard_gl(int tam, int x, int y, int dx, int dy, int cuadre)
00863 {
00864 int x_tam, y_tam, delta_x = 0, delta_y = 0, ancho_cuadrito, alto_cuadrito;
00865
00866 if ( _ventana_xtam < _ventana_ytam ) {
00867 if ( cuadre == 0 ) delta_y = (_ventana_ytam - _ventana_xtam)/2;
00868 if ( cuadre > 0 ) delta_y = _ventana_ytam - _ventana_xtam;
00869 x_tam = y_tam = _ventana_xtam;
00870 }
00871 else {
00872 if ( cuadre == 0 ) delta_x = (_ventana_xtam - _ventana_ytam)/2;
00873 if ( cuadre > 0 ) delta_x = _ventana_xtam - _ventana_ytam;
00874 x_tam = y_tam = _ventana_ytam;
00875 }
00876 ancho_cuadrito = x_tam/tam;
00877 alto_cuadrito = y_tam/tam;
00878
00879 glViewport(delta_x + x*ancho_cuadrito, delta_y + y*alto_cuadrito,
00880 dx*ancho_cuadrito - 1, dy*alto_cuadrito - 1);
00881
00882 glMatrixMode(GL_PROJECTION);
00883 glLoadIdentity();
00884 glMatrixMode(GL_MODELVIEW);
00885 glLoadIdentity();
00886 }
00887
00888 double
00889 CAMARA::factor_font(void)
00890 {
00891 return 1/(6.25*_ventana_xtam);
00892 }
00893
00894 void
00895 CAMARA::billboard_gl(int tipo)
00916 {
00917
00918 #ifndef GLTT_ENABLED
00919 static BOOLEAN advertido = FALSE;
00920 if ( mostrar_etiqueta && !advertido ) {
00921 fprintf(stderr, "<CAMARA> Warning: tengo la etiqueta %s\n"
00922 "pero no se puede mostrar por que AQUYNZA se compilo sin la\n"
00923 "libreria libgltt.\n", nombre());
00924 fflush(stderr);
00925 advertido = TRUE;
00926 }
00927 #endif
00928 #ifdef GLTT_ENABLED
00929 static FTFace *font = NULL;
00930 static GLTTFont* vector_font = NULL;
00931 int llx, lly, urx, ury;
00932 float factor = (float)(factor_font());
00933
00934 if ( mostrar_etiqueta ) {
00935
00936 glViewport(0, _ventana_ytam - _ventana_xtam, _ventana_xtam, _ventana_xtam);
00937 glMatrixMode(GL_PROJECTION); glLoadIdentity();
00938 glMatrixMode(GL_MODELVIEW); glLoadIdentity();
00939 glDisable(GL_LIGHTING); glDisable(GL_DEPTH_TEST);
00940
00941
00942 font = chequear_fuente("./etc/fonts/crystal.ttf");
00943 if ( !font ) {
00944 fprintf(stderr,
00945 "<CAMARA> - Error fatal: No encuentro una truetype font!\n");
00946 fflush(stderr);
00947 exit(1);
00948 }
00949 if ( !vector_font ) {
00950 vector_font = new GLTTFont(font);
00951 }
00952
00953 static int num_vistas = 2;
00954 if ( num_vistas > 0 ) {
00955 if ( !vector_font->create(150) ) {
00956 fprintf(stderr,"<CAMARA> ERROR fatal: "
00957 "no puedo crear una fuente GLTT");
00958 fflush(stderr);
00959 exit(1);
00960 }
00961 num_vistas--;
00962 }
00963
00964
00965 ACTIVAR_TRANSPARENCIA(transparencia_etiqueta);
00966
00967
00968 vector_font->getBBox(nombre(), llx, lly, urx, ury);
00969 double dy = ((double)ury) * factor;
00970
00971 glColor4d(color_etiqueta.r, color_etiqueta.g, color_etiqueta.b,
00972 (double)transparencia_etiqueta);
00973 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
00974 glRectd(-0.99, 0.99 - 60*factor - dy*1.2, 0.99, 0.99);
00975
00976 glTranslatef(-((float)urx/2)*factor,
00977 0.99f - 40*factor - (float)dy, 0.0f);
00978 glScalef(factor, factor, factor);
00979
00980 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
00981 vector_font->output(nombre());
00982
00983 glDisable(GL_BLEND);
00984 }
00985 #endif
00986
00987
00988 int delta;
00989
00990 switch ( tipo ) {
00991 case CAM_NO_CUADRAR:
00992 glViewport(0, 0, _ventana_xtam, _ventana_ytam);
00993 break;
00994 case CAM_CUADRAR_X:
00995 delta = (_ventana_ytam - _ventana_xtam)/2;
00996 glViewport(0, delta, _ventana_xtam, _ventana_xtam);
00997 break;
00998 case CAM_CUADRAR_Y:
00999 delta = (_ventana_xtam - _ventana_ytam)/2;
01000 glViewport(delta, 0, _ventana_ytam, _ventana_ytam);
01001 break;
01002 case CAM_CUADRAR_MENOR: default:
01003 if ( _ventana_xtam < _ventana_ytam ) {
01004 delta = (_ventana_ytam - _ventana_xtam)/2;
01005 glViewport(0, delta, _ventana_xtam, _ventana_xtam);
01006 }
01007 else {
01008 delta = (_ventana_xtam - _ventana_ytam)/2;
01009 glViewport(delta, 0, _ventana_ytam, _ventana_ytam);
01010 }
01011 break;
01012 }
01013 glMatrixMode(GL_PROJECTION); glLoadIdentity();
01014 glMatrixMode(GL_MODELVIEW); glLoadIdentity();
01015 }
01016 #endif // GL_ENABLED
01017
01018 void
01019 CAMARA::activar_povray(FILE *fd)
01027 {
01028 preprocesar_vista();
01029
01030
01031 fprintf(fd,
01032 "\n//- Especificacion de la camara ----------------------------------------\n"
01033 "camera {\n"
01034 " location <%f, %f, %f>\n"
01035 " direction <%f, %f, %f>\n"
01036 " up <%f, %f, %f>\n"
01037 " right <%f, %f, %f>\n"
01038 "}\n",
01039 _pos.x, _pos.y, _pos.z,
01040 _dir.x, _dir.y, _dir.z,
01041 _up.x, _up.y, _up.z,
01042 _right.x, _right.y, _right.z
01043 );
01044
01045 }
01046
01047
01048
01049 void
01050 CAMARA::imprimir(void)
01051 {
01052 double yaw, pitch, roll;
01053 MATRIZ_4x4 R;
01054 float h, m, s, gg, mm, ss;
01055
01056 R.importar_quaternion(_orientacion);
01057 R.exportar_angulos_euler(&yaw, &pitch, &roll);
01058 clrscr();
01059
01060
01061 printf("<CAMARA \"%s\">:\n", nombre());
01062
01063 if ( _modo_proyeccion == CAM_PERSPECTIVA ) {
01064 printf(" - Camara en modo de proyeccion PERSPECTIVA\n");
01065 }
01066 else if ( _modo_proyeccion == CAM_PARALELA ) {
01067 printf(" - Camara en modo de proyeccion PARALELA\n");
01068 }
01069 else {
01070 printf(" - Camara en modo de proyeccion DESCONOCIDO\n");
01071 }
01072 ;
01073
01074 printf(" - posision(x, y, z) = <%.2f, %.2f, %.2f>\n"
01075 " - orientacion(yaw, pitch, roll) = <%.2f, %.2f, %.2f> (en grados)\n",
01076 _posicion.x, _posicion.y, _posicion.z,
01077 RAD2DEG(yaw), RAD2DEG(pitch), RAD2DEG(roll));
01078
01079
01080 DEG2hms(RAD2DEG(yaw), &h, &m, &s);
01081 DEG2gms(RAD2DEG(pitch), &gg, &mm, &ss);
01082 printf(
01083 " . Orientacion precisa: RA<%2.0f:%2.0f:%.2f> DEC<%3.0f:%2.0f:%.2f>\n",
01084 h, m, s, gg, mm, ss);
01085
01086
01087 preprocesar_vista();
01088 printf(" . Vector UP = <%.2f, %.2f, %.2f>\n",
01089 _up.x, _up.y, _up.z);
01090
01091 printf(" - fov = %.2f\n"
01092 " - _near_plane = %.4f\n"
01093 " - _far_plane = %.4f\n",
01094 _fov, _near_plane, _far_plane);
01095
01096 fflush(stdout);
01097 }
01098
01099 BOOLEAN
01100 CAMARA::procesar_teclado(EVENTO_GUI *e)
01111 {
01112 double yaw, pitch, roll;
01113 double inc;
01114 MATRIZ_4x4 R;
01115
01116 #define INICIO_EULER() \
01117 R.importar_quaternion(_orientacion); \
01118 R.exportar_angulos_euler(&yaw, &pitch, &roll);
01119
01120 #define FIN_EULER() \
01121 R.rotacion_angulos_euler(yaw, pitch, roll); \
01122 _orientacion = R.exportar_quaternion(); \
01123 break;
01124
01125
01126 if ( _fov > 90 ) inc = DEG2RAD(10);
01127 else if ( _fov > 45 ) inc = DEG2RAD(5);
01128 else if ( _fov > 15 ) inc = DEG2RAD(2.5);
01129 else if ( _fov > 5 ) inc = DEG2RAD(1);
01130 else inc = DEG2RAD(0.1);
01131
01132 switch( e->key_code ) {
01133
01134 case JK_RIGHT: INICIO_EULER();
01135 yaw -= inc;
01136 while ( yaw < DEG2RAD(0) ) yaw += DEG2RAD(360);
01137 FIN_EULER();
01138 case JK_LEFT: INICIO_EULER();
01139 yaw += inc;
01140 while ( yaw >= DEG2RAD(360) ) yaw -= DEG2RAD(360);
01141 FIN_EULER();
01142 case JK_s: INICIO_EULER();
01143 roll += DEG2RAD(5);
01144 while ( roll > DEG2RAD(360) ) roll -= DEG2RAD(360);
01145 FIN_EULER();
01146 case JK_S: INICIO_EULER();
01147 roll -= DEG2RAD(5);
01148 while ( roll < 0 ) roll += DEG2RAD(360);
01149 FIN_EULER();
01150 case JK_UP: INICIO_EULER();
01151 pitch -= inc;
01152 if ( pitch < DEG2RAD(-90) ) pitch = DEG2RAD(-90);
01153 FIN_EULER();
01154 case JK_DOWN: INICIO_EULER();
01155 pitch += inc;
01156 if ( pitch > DEG2RAD(90) ) pitch = DEG2RAD(90);
01157 FIN_EULER();
01158
01159
01160 case JK_x: _posicion.x -= 0.25; break;
01161 case JK_X: _posicion.x += 0.25; break;
01162 case JK_y: _posicion.y -= 0.25; break;
01163 case JK_Y: _posicion.y += 0.25; break;
01164 case JK_z: _posicion.z -= 0.25; break;
01165 case JK_Z: _posicion.z += 0.25; break;
01166
01167 case JK_A:
01168 if ( _fov < 0.1 - EPSILON ) _fov += 0.1;
01169 else if ( _fov < 1 - EPSILON ) _fov++;
01170 else if ( _fov < 175 - EPSILON ) _fov += 5;
01171 break;
01172 case JK_a:
01173 if ( _fov > 5 + EPSILON ) _fov -= 5;
01174 else if ( _fov > 1 + EPSILON ) _fov--;
01175 else if ( _fov > 0.1 + EPSILON ) _fov -= 0.1;
01176 break;
01177
01178 case JK_p:
01179 switch ( _modo_proyeccion ) {
01180 case CAM_PERSPECTIVA: _modo_proyeccion = CAM_PARALELA; break;
01181 default: _modo_proyeccion = CAM_PERSPECTIVA; break;
01182 }
01183 break;
01184
01185 case JK_e:
01186 if ( mostrar_etiqueta ) {
01187 mostrar_etiqueta = FALSE;
01188 }
01189 else {
01190 mostrar_etiqueta = TRUE;
01191 }
01192 break;
01193
01194 case JK_m:
01195 switch ( modo_control ) {
01196 case CAM_STANDARD: modo_control = CAM_VUELO; break;
01197 default: modo_control = CAM_STANDARD; break;
01198 }
01199 break;
01200
01201 case JK_i:
01202 imprimir();
01203 break;
01204
01205 case JK_N: AUMENTAR(_near_plane); imprimir(); break;
01206 case JK_n: DISMINUIR(_near_plane); imprimir(); break;
01207 case JK_F: AUMENTAR(_far_plane); imprimir(); break;
01208 case JK_f: DISMINUIR(_far_plane); imprimir(); break;
01209
01210
01211 default: return FALSE;
01212 }
01213 return TRUE;
01214 }
01215
01216 BOOLEAN
01217 CAMARA::procesar_mouse(EVENTO_GUI *e)
01220 {
01221 static BOOLEAN mover_plano_viz = FALSE;
01222 static BOOLEAN girar_plano_viz = FALSE;
01223 static BOOLEAN avanzar = FALSE;
01224 MATRIZ_4x4 R, S;
01225 VECTOR u, v, w;
01226 double ax, ay;
01227
01228 if ( e->mouse_delta_x > 5 ) e->mouse_delta_x = 5;
01229 if ( e->mouse_delta_x < -5 ) e->mouse_delta_x = -5;
01230 if ( e->mouse_delta_y > 5 ) e->mouse_delta_y = 5;
01231 if ( e->mouse_delta_y < -5 ) e->mouse_delta_y = -5;
01232 if ( e->tipo_de_evento == ETYPE_BUTTON_DOWN ) {
01233 mover_plano_viz = FALSE;
01234 girar_plano_viz = FALSE;
01235 avanzar = FALSE;
01236 if ( e->mouse_button_mask & 0x01 ) girar_plano_viz = TRUE;
01237 if ( e->mouse_button_mask & 0x02 ) mover_plano_viz = TRUE;
01238 if ( e->mouse_button_mask & 0x04 ||
01239 e->mouse_button_mask == 0x03 ) avanzar = TRUE;
01240 }
01241 else if ( e->tipo_de_evento == ETYPE_BUTTON_UP ) {
01242 mover_plano_viz = FALSE;
01243 girar_plano_viz = FALSE;
01244 avanzar = FALSE;
01245 }
01246 else {
01247 R.importar_quaternion(_orientacion);
01248 u.x = R.M[0][0]; u.y = R.M[1][0]; u.z = R.M[2][0];
01249 v.x = R.M[0][1]; v.y = R.M[1][1]; v.z = R.M[2][1];
01250 w.x = R.M[0][2]; w.y = R.M[1][2]; w.z = R.M[2][2];
01251 if ( mover_plano_viz ) {
01252 _posicion = _posicion - v * (0.1*((double)e->mouse_delta_x));
01253 _posicion = _posicion - w * (0.1*((double)e->mouse_delta_y));
01254 }
01255 if ( avanzar ) {
01256
01257 _posicion = _posicion - u * (0.1*((double)e->mouse_delta_y));
01258 }
01259 if ( girar_plano_viz ) {
01260 ax = MINIMO(-(0.01*((double)e->mouse_delta_x)), 2);
01261 ay = MINIMO((0.01*((double)e->mouse_delta_y)), 2);
01262
01263 S.rotacion_eje(ay, v.x, v.y, v.z);
01264 R = S * R;
01265
01266 S.rotacion_eje(ax, 0, 0, 1);
01267 R = S * R;
01268
01269 _orientacion = R.exportar_quaternion();
01270 _orientacion.normalizar();
01271
01272 }
01273 }
01274 ;
01275 return TRUE;
01276 }
01277
01278 void
01279 CAMARA::procesar_resize(int xtam, int ytam)
01280 {
01281 _ventana_xtam = xtam;
01282 _ventana_ytam = ytam;
01283 }
01284
01285
01286
01287 BOOLEAN
01288 CAMARA::leer(TOKENIZADOR *Sabiondo)
01289 {
01290 char cad[1000];
01291 int tipo_token = TK_DESCONOCIDO, pos;
01292 VECTOR direccion;
01293 double magnitud, yaw, pitch, roll;
01294 MATRIZ_4x4 R;
01295
01296
01297 pos = 1;
01298 while ( tipo_token != TK_CERRAR) {
01299 tipo_token = Sabiondo->siguiente_token(cad);
01300 switch ( pos ) {
01301 case 1:
01302 ESPERO(TK_CADENA, "una cadena");
01303 if ( strlen(cad) > MAX_CAD-1 ) cad[MAX_CAD-1] = '\0';
01304 des_comille(cad);
01305 set_nombre(cad);
01306 pos++;
01307 break;
01308 case 2: ESPERO(TK_ABRIR, "\"{\""); pos++; break;
01309 default:
01310 if ( tipo_token == TK_CERRAR ) break;
01311 ESPERO(TK_IDENTIFICADOR, "un identificador (3)");
01312 if ( strcmp(cad, "posicion") == 0 ) {
01313 tipo_token = Sabiondo->siguiente_token(cad);
01314 ESPERO(TK_VECTOR_INICIO, "el inicio de un VECTOR");
01315 _posicion.x = atof(&cad[1]);
01316 tipo_token = Sabiondo->siguiente_token(cad);
01317 ESPERO(TK_NUMERO, "un numero (dato 2 de un VECTOR)");
01318 _posicion.y = atof(cad);
01319 tipo_token = Sabiondo->siguiente_token(cad);
01320 ESPERO(TK_VECTOR_FIN, "el final de un VECTOR");
01321 cad[strlen(cad) - 1] = '\0';
01322 _posicion.z = atof(cad);
01323 }
01324 else if ( strcmp(cad, "orientacion") == 0 ) {
01325 tipo_token = Sabiondo->siguiente_token(cad);
01326 ESPERO(TK_NUMERO, "un numero (magnitud de rotacion)");
01327 magnitud = DEG2RAD(atof(cad));
01328 tipo_token = Sabiondo->siguiente_token(cad);
01329 ESPERO(TK_VECTOR_INICIO, "el inicio de un VECTOR");
01330 direccion.x = atof(&(cad[1]));
01331 tipo_token = Sabiondo->siguiente_token(cad);
01332 ESPERO(TK_NUMERO, "un numero (dato 2 de un VECTOR)");
01333 direccion.y = atof(cad);
01334 tipo_token = Sabiondo->siguiente_token(cad);
01335 ESPERO(TK_VECTOR_FIN, "el final de un VECTOR");
01336 cad[strlen(cad) - 1] = '\0';
01337 direccion.z = atof(cad);
01338 direccion.normalizar();
01339 _orientacion.importar_angulo_eje(magnitud, direccion);
01340 }
01341 else if ( strcmp(cad, "orientacion_euler") == 0 ) {
01342 tipo_token = Sabiondo->siguiente_token(cad);
01343 ESPERO(TK_VECTOR_INICIO, "el inicio de un VECTOR");
01344 yaw = DEG2RAD(atof(&(cad[1])));
01345 tipo_token = Sabiondo->siguiente_token(cad);
01346 ESPERO(TK_NUMERO, "un numero (dato 2 de un VECTOR)");
01347 pitch = DEG2RAD(atof(cad));
01348 tipo_token = Sabiondo->siguiente_token(cad);
01349 ESPERO(TK_VECTOR_FIN, "el final de un VECTOR");
01350 cad[strlen(cad) - 1] = '\0';
01351 roll = DEG2RAD(atof(cad));
01352 R.rotacion_angulos_euler(yaw, pitch, roll);
01353 _orientacion = R.exportar_quaternion();
01354 }
01355 else if ( strcmp(cad, "fov") == 0 ) {
01356 tipo_token = Sabiondo->siguiente_token(cad);
01357 ESPERO(TK_NUMERO, "un numero");
01358 _fov = atof(cad);
01359 }
01360 else if ( strcmp(cad, "far_plane") == 0 ) {
01361 tipo_token = Sabiondo->siguiente_token(cad);
01362 ESPERO(TK_NUMERO, "un numero");
01363 _far_plane = atof(cad);
01364 }
01365 else if ( strcmp(cad, "near_plane") == 0 ) {
01366 tipo_token = Sabiondo->siguiente_token(cad);
01367 ESPERO(TK_NUMERO, "un numero");
01368 _near_plane = atof(cad);
01369 }
01370 else if ( strcmp(cad, "tipo_modelo") == 0 ) {
01371 tipo_token = Sabiondo->siguiente_token(cad);
01372 ESPERO(TK_NUMERO, "un numero");
01373 tipo_modelo = (int)floor(atof(cad));
01374 }
01375 else if ( strcmp(cad, "mostrar_etiqueta") == 0 ) {
01376 tipo_token = Sabiondo->siguiente_token(cad);
01377 ESPERO(TK_IDENTIFICADOR, "TRUE o FALSE");
01378 if ( strcmp(cad, "TRUE") == 0 ) mostrar_etiqueta = TRUE;
01379 else mostrar_etiqueta = FALSE;
01380 }
01381 else if ( strcmp(cad, "proyeccion") == 0 ) {
01382 tipo_token = Sabiondo->siguiente_token(cad);
01383 ESPERO(TK_IDENTIFICADOR, "PERSPECTIVA o PARALELA");
01384 if ( strcmp(cad, "PARALELA") == 0 )
01385 _modo_proyeccion = CAM_PARALELA;
01386 else _modo_proyeccion = CAM_PERSPECTIVA;
01387 }
01388 else if ( strcmp(cad, "transparencia_etiqueta") == 0 ) {
01389 tipo_token = Sabiondo->siguiente_token(cad);
01390 ESPERO(TK_NUMERO, "un numero entre 0 y 1");
01391 transparencia_etiqueta = atof(cad);
01392 }
01393 else if ( strcmp(cad, "color_etiqueta") == 0 ) {
01394 tipo_token = Sabiondo->siguiente_token(cad);
01395 ESPERO(TK_VECTOR_INICIO, "el inicio de un COLOR");
01396 color_etiqueta.r = (float)atof(&cad[1]);
01397 tipo_token = Sabiondo->siguiente_token(cad);
01398 ESPERO(TK_NUMERO, "un numero (dato 2 de un COLOR)");
01399 color_etiqueta.g = (float)atof(cad);
01400 tipo_token = Sabiondo->siguiente_token(cad);
01401 ESPERO(TK_VECTOR_FIN, "el final de un COLOR");
01402 cad[strlen(cad) - 1] = '\0';
01403 color_etiqueta.b = (float)atof(cad);
01404 }
01405 else if ( strcmp(cad, "padre") == 0 ) {
01406 tipo_token = Sabiondo->siguiente_token(cad);
01407 ESPERO(TK_CADENA, "el nombre de una cosa padre");
01408 des_comille(cad);
01409 _nombre_padre = new char[strlen(cad) + 1];
01410 if ( !_nombre_padre ) {
01411 fprintf(stderr, "<CAMARA> - ERROR: No hay memoria!\n");
01412 fflush(stderr);
01413 return FALSE;
01414 }
01415 strcpy(_nombre_padre, cad);
01416 }
01417 ;
01418 break;
01419 }
01420 }
01421
01422 return TRUE;
01423 }
01424
01425
01426
01427
01428