home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
3D World 5 (Spanish)
/
3DWorld_05.iso
/
mac
/
ARTIC
/
W_PROG
/
CUBO.C
next >
Wrap
C/C++ Source or Header
|
1997-05-09
|
14KB
|
446 lines
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <graph.h>
#define CUAD(a) a*a
#define NUMVERT 8
#define TRUE 1
#define FALSE 0
#define ROUNDOFF 1.e-6
#define vec4_set(a,b,c,d,e) {a[0]=b;a[1]=c;a[2]=d;a[3]=e;}
void calcula_tras_a_camara();
void calcula_camrot();
void calcula_proy_a_camara();
void calcula_perspectiva(float p);
void calcula_mat_rot(double cx,double cy,double cz,double angrot);
void V4XM44(float a[4], float b[4][4], float c[4]);
void M44XM44(float a[4][4], float b[4][4], float c[4][4]);
void M44XM44a(float a[4][4], float b[4][4]);
void rellena_vertices(float lad );
void rellena_caras();
int normaliza(float *x, float *y, float *z);
void cross(float *a, float *b, float *c);
void boundig_box(float V[NUMVERT][4],float *xmin,float *xmax,float *ymin,float *ymax);
int interior_a_poly(float x, float y, int i );
float zoom;
float culling;
float mat_rot[4][4]; //matriz de rotaci¢n
float VERTICES[NUMVERT][4]; //array inicial de vertices
float VERTransf[NUMVERT][4]; //array de vertices rotados
int CARAS[6][5]; //array de caras. Por cada cara contiene el indice
//de los vertices que la componen y un flag de visibilidad
//0 -cara aculta
//1 -cara visible
float mat_tras[4][4];
float mat_rotcam[4][4];
float mat_proy[4][4];
float mat_fin[4][4];
float mat_d[4][4];
float N[3];
float V[3];
float U[3];
//float v[3];
float veccamera[3];
float vecfoco[3];
float ang; //angulo de rotacion de camara
main(){
float vecrot[3]; //vector del eje de rotaci¢n
float normal[3]; //vector normal
float angrot; //angulo de rotaci¢n en radianes
float vectemp1[3],vectemp2[3],vectemp3[3]; //vectores temporales
float modulo;
float xmin,xmax,ymin,ymax;
int ind, ind1,ind3;
int ejey, ejex;
_setvideomode( _VRES16COLOR);
_setvieworg(320,200);
//factor de zoom de camara
zoom = 200;
//Se define el vector del eje de rotacion
vecrot[0]=1.;
vecrot[1]=0.5;
vecrot[2]=0.5;
printf("Introduce el punto del camara\n");
scanf("%f, %f, %f",&veccamera[0],&veccamera[1],&veccamera[2]);
printf("Introduce el punto del foco\n");
scanf("%f, %f, %f",&vecfoco[0],&vecfoco[1],&vecfoco[2]);
_clearscreen(_GCLEARSCREEN);
rellena_vertices(5); //rellenamos con un cubo de lado 5
rellena_caras();
ind3=0;
N[0]=vecfoco[0]-veccamera[0];
N[1]=vecfoco[1]-veccamera[1];
N[2]=vecfoco[2]-veccamera[2];
normaliza( &N[0],&N[1],&N[2]);
V[0]=0-N[2]*N[0];
V[1]=0-N[2]*N[1];
V[2]=1-N[2]*N[2];
normaliza( &V[0],&V[1],&V[2]);
cross(N,V,U);
normaliza( &U[0],&U[1],&U[2]);
for(; ;){ //ciclo de rotacion
angrot=3.1416*ind3/180.;
//Normalizaci¢n del vector de rotaci¢n
normaliza( &vecrot[0],&vecrot[1],&vecrot[2]);
//C†lculo de la matriz de rotaci¢n
calcula_mat_rot(vecrot[0],vecrot[1],vecrot[2],angrot);
//Se aplica la transformacion de rotacion a los vertices
for(ind=0;ind<8; ind++)
V4XM44(VERTICES[ind], mat_rot, VERTransf[ind]);
for(ind=0;ind<6; ind++){
for(ind1=0;ind1<3; ind1++){
vectemp1[ind1]=VERTransf[CARAS[ind][1]][ind1]-
VERTransf[CARAS[ind][0]][ind1];
vectemp2[ind1]=VERTransf[CARAS[ind][2]][ind1]-
VERTransf[CARAS[ind][1]][ind1];
vectemp3[ind1]=veccamera[ind1]-VERTransf[CARAS[ind][0]][ind1];
}
cross(vectemp1,vectemp2,normal);
culling=normal[0]*vectemp3[0]+normal[1]*vectemp3[1]+normal[2]*vectemp3[2];
if(culling < 0.) CARAS[ind][4]=0.; //cara oculta
else CARAS[ind][4]=1.; //cara visible
}
calcula_tras_a_camara();
calcula_proy_a_camara();
M44XM44(mat_tras,mat_proy,mat_fin);
for(ind=0;ind<8;ind++)
{
V4XM44(VERTransf[ind],mat_fin,VERTransf[ind]);
//linea alternativa para no rotar
//V4XM44(VERTICES[ind], mat_fin, VERTransf[ind]);
calcula_perspectiva(VERTransf[ind][2]);
V4XM44(VERTransf[ind],mat_d,VERTransf[ind]);
}
// Selecci¢n del boundig box del cubo (xmax,xmin,ymax,ymin)
boundig_box(VERTransf,&xmin,&xmax,&ymin,&ymax);
// C†lculo de las normales por cara
_setcolor(8);
//ciclo de barrido de pantalla por el bounding box
for(ejex=xmin; ejex<=xmax; ejex++)
for(ejey=ymin; ejey<=ymax; ejey++)
for(ind=0;ind<6; ind++){//ciclo por las caras
if(CARAS[ind][4]==1.){ //filtro de caras visibles
if( interior_a_poly((float)ejex, (float)ejey, ind )==1)
_setpixel(ejex,ejey);
}
}
// Se dibujan las aristas visibles del cubo
_setcolor(10);
for(ind=0;ind<6; ind++) {
if(CARAS[ind][4]==1.){
_moveto( (int)VERTransf[ CARAS[ind][0] ][0], (int) VERTransf[ CARAS[ind][0] ][1]);
for(ind1=1;ind1<4; ind1++)
_lineto( (int)VERTransf[ CARAS[ind][ind1] ][0], (int) VERTransf[ CARAS[ind][ind1]][1]);
_lineto( (int)VERTransf[ CARAS[ind][0] ][0], (int) VERTransf[ CARAS[ind][0] ][1]);
}
}
ind3++;
if (getch()==27)
break;
_clearscreen(_GCLEARSCREEN);
}//fin de ciclo de angulo
_setvideomode(_DEFAULTMODE);
}//fin de main
//Funci¢n para la obtencion de la matriz concatenada de rotaci¢n
//alrededor de un eje arbitrario con cosenos directores cx,cy,cz, en
//un †ngulo de rotacion angrot.
void calcula_mat_rot(double cx,double cy,double cz,double angrot)
{
double d;
float Rx[4][4],Rxinv[4][4],Ry[4][4],Ryinv[4][4],Rdelta[4][4];
if(angrot==0.)
{//Devuelve la matriz identidad si angrot=0
vec4_set(mat_rot[0],1.,0.,0.,0.);
vec4_set(mat_rot[1],0.,1.,0.,0.);
vec4_set(mat_rot[2],0.,0.,1.,0.);
vec4_set(mat_rot[3],0.,0.,0.,1.);
}
else
{
d=sqrt(cy*cy + cz*cz);
if(d==0.0)
{//si el eje de rotaci¢n coincide con el eje x
vec4_set(mat_rot[0],1.,0.,0.,0.);
vec4_set(mat_rot[1],0.,cos(angrot),sin(angrot),0.);
vec4_set(mat_rot[2],0.,-sin(angrot),cos(angrot),0.);
vec4_set(mat_rot[3],0.,0.,0.,1.);
}
else
{
//Formacion de las matrices de rotacion
//Matriz de transformacion alrededor del eje x
vec4_set(Rx[0],1.0,0.,0.,0.);
vec4_set(Rx[1],0.,cz/d,cy/d,0.);
vec4_set(Rx[2],0.,-cy/d,cz/d,0.);
vec4_set(Rx[3],0.,0.,0.,1.);
//Inversa de la matriz de transformacion alrededor del eje x
vec4_set(Rxinv[0],1.0,0.,0.,0.);
vec4_set(Rxinv[1],0.,cz/d,-cy/d,0.);
vec4_set(Rxinv[2],0.,cy/d,cz/d,0.);
vec4_set(Rxinv[3],0.,0.,0.,1.);
//Matriz de transformacion alrededor del eje y
vec4_set(Ry[0],d,0.,cx,0.);
vec4_set(Ry[1],0.,1.,0.,0.);
vec4_set(Ry[2],-cx,0.,d,0.);
vec4_set(Ry[3],0.,0.,0.,1.);
//Inversa de la matriz de transformacion alrededor del eje y
vec4_set(Ryinv[0],d,0.,-cx,0.);
vec4_set(Ryinv[1],0.,1.,0.,0.);
vec4_set(Ryinv[2],cx,0.,d,0.);
vec4_set(Ryinv[3],0.,0.,0.,1.);
//Matriz de rotacion alrededor del eje arbitrario
vec4_set(Rdelta[0],cos(angrot),sin(angrot),0.,0.);
vec4_set(Rdelta[1],-sin(angrot),cos(angrot),0.,0.);
vec4_set(Rdelta[2],0.,0.,1.,0.);
vec4_set(Rdelta[3],0.,0.,0.,1.);
//Obtencion de la matriz concatenada de transformacion
M44XM44(Rx, Ry,mat_rot);
M44XM44a(mat_rot, Rdelta);
M44XM44a(mat_rot, Ryinv);
M44XM44a(mat_rot, Rxinv);
}
}
}
//----------------------------------------------------
// Multiplica un vector a[4] por una matriz 4x4:
// c = a*b;
// El resultado se almacena en el vector c
// -----------------------------------------------------
void V4XM44(float a[4], float b[4][4], float c[4])
{
int j;
float work[4];
for (j=0; j<4; j++) {
work[j] = a[0]*b[0][j] + a[1]*b[1][j] + a[2]*b[2][j] + a[3]*b[3][j];
}
memcpy(c, work, 4*sizeof(float));
}
//----------------------------------------------------
// Multiply dos matrices matrices 4x4:
// c = a*b;
// El resultado se almacena en c
// -----------------------------------------------------
void M44XM44(float a[4][4], float b[4][4], float c[4][4])
{
int j;
float work[4][4];
for (j=0; j<4;j++) {
work[0][j] = a[0][0]*b[0][j] + a[0][1]*b[1][j] + a[0][2]*b[2][j] + a[0][3]*b[3][j];
work[1][j] = a[1][0]*b[0][j] + a[1][1]*b[1][j] + a[1][2]*b[2][j] + a[1][3]*b[3][j];
work[2][j] = a[2][0]*b[0][j] + a[2][1]*b[1][j] + a[2][2]*b[2][j] + a[2][3]*b[3][j];
work[3][j] = a[3][0]*b[0][j] + a[3][1]*b[1][j] + a[3][2]*b[2][j] + a[3][3]*b[3][j];
}
memcpy(c, work, 16*sizeof(float));
}
//----------------------------------------------------
// Multiplica dos matrices 4x4:
// a = a*b;
// El resultado se almacena en a
// -----------------------------------------------------
void M44XM44a(float a[4][4], float b[4][4])
{
int j;
float work[4][4];
for (j=0; j<4;j++) {
work[0][j] = a[0][0]*b[0][j] + a[0][1]*b[1][j] + a[0][2]*b[2][j] + a[0][3]*b[3][j];
work[1][j] = a[1][0]*b[0][j] + a[1][1]*b[1][j] + a[1][2]*b[2][j] + a[1][3]*b[3][j];
work[2][j] = a[2][0]*b[0][j] + a[2][1]*b[1][j] + a[2][2]*b[2][j] + a[2][3]*b[3][j];
work[3][j] = a[3][0]*b[0][j] + a[3][1]*b[1][j] + a[3][2]*b[2][j] + a[3][3]*b[3][j];
}
memcpy(a, work, 16*sizeof(float));
}
void rellena_vertices(float lad )
{
int ind;
//Rellena el array de VERTICES con las coordenadas de los vertices del cubo
vec4_set(VERTICES[0],lad, lad, -lad, 1.);
vec4_set(VERTICES[1],-lad, lad, -lad, 1.);
vec4_set(VERTICES[2],-lad, lad, lad, 1.);
vec4_set(VERTICES[3],lad, lad, lad, 1.);
vec4_set(VERTICES[4],lad, -lad, -lad, 1.);
vec4_set(VERTICES[5],lad, -lad, lad, 1.);
vec4_set(VERTICES[6],-lad, -lad, lad, 1.);
vec4_set(VERTICES[7],-lad, -lad, -lad, 1.);
}
void rellena_caras()
{
//Rellena el aray de CARAS con el indice de los vertices que componen cada cara
vec4_set(CARAS[0],0,1,2,3); //superior
vec4_set(CARAS[1],4,5,6,7); //inferior
vec4_set(CARAS[2],5,3,2,6); //delantera
vec4_set(CARAS[3],4,7,1,0); //trasera
vec4_set(CARAS[4],4,0,3,5); //derecha
vec4_set(CARAS[5],7,6,2,1); //izquierda
}
//Normaliza al vector de componentes (x,y,z)
normaliza(float *x, float *y, float *z)
{
//se devuelve el vector normalizado
double modulo,xx,yy,zz;
xx=(*x);
yy=(*y);
zz=(*z);
modulo=sqrt(CUAD(xx)+CUAD(yy)+CUAD(zz));
if (modulo<ROUNDOFF) {
return(FALSE);
}
*x = (xx/modulo);
*y = (yy/modulo);
*z = (zz/modulo);
return(TRUE);
}
//Calcula el producto vectorial de dos vectores c=a x b
void cross(float *a, float *b, float *c)
{
c[0] = a[1]*b[2] - a[2]*b[1];
c[1] = a[2]*b[0] - a[0]*b[2];
c[2] = a[0]*b[1] - a[1]*b[0];
}
//Determina el bounding box de un conjunto de puntos
void boundig_box(float V[NUMVERT][4],float *xmin,float *xmax,float *ymin,float *ymax)
{
int ind;
*ymin=999999.;
*ymax=-999999.;
*xmin=999999.;
*xmax=-999999.;
for(ind=0;ind<NUMVERT; ind++)
{
*ymin=*ymin>V[ind][1]?V[ind][1]:*ymin;
*ymax=*ymax<V[ind][1]?V[ind][1]:*ymax;
*xmin=*xmin>V[ind][0]?V[ind][0]:*xmin;
*xmax=*xmax<V[ind][0]?V[ind][0]:*xmax;
}
}
// Rutina que determina si un punto es interior o exterior al poligono
//de cuatro lados formado por los cuatro vertices de cada cara
//proyectados en el plano xy
int interior_a_poly(float x, float y, int i )
{
unsigned ss,cort;
float trasl[4][2];
for(ss=0 ; ss<4 ; ss++)
{
trasl[ss][0]=VERTransf[ CARAS[i][ss] ][0]- x ;
trasl[ss][1]=VERTransf[ CARAS[i][ss] ][1] - y ;
}
for (cort=ss=0;ss<4;ss++)
if ((trasl[ss][1]*trasl[(ss+1)%4][1]<0.0) && (( (trasl[ss][0]>0.0) &&
(trasl[(ss+1)%4][0]>0.0)) ||
((trasl[ss][0]-(trasl[ss][1]*(trasl[(ss+1)%4][0]-trasl[ss][0]))/(trasl[(ss+1)%4][1]-
trasl[ss][1]))>0.0) ) ) cort ++;
if ((cort%2) !=0)
return(1); //pto. interior
return(0); //pto. exterior
}
void calcula_proy_a_camara()
{
vec4_set(mat_proy[0],U[0],V[0],N[0],0);
vec4_set(mat_proy[1],U[1],V[1],N[1],0);
vec4_set(mat_proy[2],U[2],V[2],N[2],0);
vec4_set(mat_proy[3],0,0,0,1);
}
void calcula_camrot()
{
vec4_set(mat_rotcam[0],cos(ang),sin(ang),0,0);
vec4_set(mat_rotcam[1],-sin(ang),cos(ang),0,0);
vec4_set(mat_rotcam[2],0,0,1,0);
vec4_set(mat_rotcam[3],0,0,0,1);
}
void calcula_tras_a_camara()
{
vec4_set(mat_tras[0],1,0,0,0);
vec4_set(mat_tras[1],0,1,0,0);
vec4_set(mat_tras[2],0,0,1,0);
vec4_set(mat_tras[3],-veccamera[0],-veccamera[1],-veccamera[2],1);
}
void calcula_perspectiva(float d)
{
vec4_set(mat_d[0],zoom/d/1.333,0,0,0);
vec4_set(mat_d[1],0,zoom/d,0,0);
vec4_set(mat_d[2],0,0,1,0);
vec4_set(mat_d[3],0,0,0,1);
}
/*
intersect( float a[2], float b[2], int caso, int wMin[2], int wMax[2],float salida[2])
{
float m;
if (a[0]!=b[0]) m=(a[1]-b[1])/(a[0]-b[0]);
else m=1;
switch (caso){
case 1: //LEFT
salida[0]=wMin[0];
salida[1]=b[1]+(wMin[0]-b[0])*m;
break;
case 2: //RIGHT
salida[0]=wMax[0];
salida[1]=b[1]+(wMax[0]-b[0])*m;
break;
case 3: //BOTTOM
salida[1]=wMin[1];
if(a[0]!=b[0]) salida[0]=b[1]+(wMin[1]-b[0])/m;
else salida[0]=b[0];
break;
case 4: //TOP
salida[1]=wMax[1];
if(a[0]!=b[0]) salida[0]=b[1]+(wMax[1]-b[0])/m;
else salida[0]=b[0];
break;
}
}
*/