home *** CD-ROM | disk | FTP | other *** search
/ PCMania 1 / PCM1.ISO / ARTICULOS / CREATIVIDAD / DEMOSCENE / EJEMPLO / pcrt6.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-09-24  |  15.9 KB  |  513 lines

  1. #include <stdio.h>
  2. #include <math.h>
  3. #include <stdlib.h>
  4. #include <dos.h>
  5. #include <conio.h>
  6. #include <i86.h>
  7. #include <string.h>
  8. #include <math.h>
  9. #include "vesalint.h"
  10. #include "affine.c"
  11.  
  12. #define  RES_X 320
  13. #define  RES_Y 200
  14. #define  MID_X 160
  15. #define  MID_Y 100
  16.  
  17. #define  MAX_ITER 4
  18. #define  RADI_LUZ 25
  19.  
  20. #define  ESFERA   0
  21. #define  PLANO    1
  22. #define  CILINDRO 2
  23.  
  24. #pragma aux Set_Mode=\
  25. "int    10h"\
  26. modify  [ax]\
  27. parm    [ax]
  28.  
  29. //  rutina para interpolar la imagen para aumentarla
  30. void interpola(unsigned char *pant)
  31. {
  32.     int x,y;
  33.     pant+=3;
  34.     for (y=1;y<MID_Y;y++)
  35.     {
  36.         for (x=1;x<MID_X;x++)
  37.         {
  38.             pant[0]=(pant[-3]+pant[3])>>1;
  39.             pant[1]=(pant[-2]+pant[4])>>1;
  40.             pant[2]=(pant[-1]+pant[5])>>1;
  41.             pant+=6;
  42.         }
  43.         pant+=3;
  44.         for (x=1;x<MID_X;x++)
  45.         {
  46.             pant[0]=(pant[-RES_X*3  ]+pant[ RES_X*3  ])>>1;
  47.             pant[1]=(pant[-RES_X*3+1]+pant[ RES_X*3+1])>>1;
  48.             pant[2]=(pant[-RES_X*3+2]+pant[ RES_X*3+2])>>1;
  49.             pant[3]=(pant[-RES_X*3  ]+pant[-RES_X*3+6]+pant[RES_X*3  ]+pant[RES_X*3+6])>>2;
  50.             pant[4]=(pant[-RES_X*3+1]+pant[-RES_X*3+7]+pant[RES_X*3+1]+pant[RES_X*3+7])>>2;
  51.             pant[5]=(pant[-RES_X*3+2]+pant[-RES_X*3+8]+pant[RES_X*3+2]+pant[RES_X*3+8])>>2;
  52.             pant+=6;
  53.         }    
  54.         pant[0]=(pant[-RES_X*3  ]+pant[ RES_X*3  ])>>1;
  55.         pant[1]=(pant[-RES_X*3+1]+pant[ RES_X*3+1])>>1;
  56.         pant[2]=(pant[-RES_X*3+2]+pant[ RES_X*3+2])>>1;
  57.         pant+=9;
  58.     }
  59.     for (x=1;x<MID_X;x++)
  60.     {
  61.         pant[0]=(pant[-3]+pant[3])>>1;
  62.         pant[1]=(pant[-2]+pant[4])>>1;
  63.         pant[2]=(pant[-1]+pant[5])>>1;
  64.         pant+=6;
  65.     }
  66. }
  67.  
  68. typedef struct RT_camera
  69. {
  70.     VECTOR pos;
  71.     VECTOR target;
  72.     float roll;
  73.     float d;
  74. }RT_CAMERA;
  75.  
  76. typedef struct RT_object
  77. {
  78.     int tipo;
  79.  
  80.     //  Propiedades "fisicas" del objeto
  81.  
  82.     VECTOR ambient,diffuse,specular;
  83.     float  brillo,reflex;
  84.  
  85.     //  Propiedades si el objeto es ESFERA
  86.  
  87.     VECTOR pos;
  88.     float  radi;
  89.  
  90.     //  Propiedades si el objeto es PLANO
  91.  
  92.     VECTOR EjeX,EjeY,EjeZ;
  93.     float  d;
  94.  
  95.     //  Si el objeto es un cilindro (infinito) utiliza radi, EjeZ y pos
  96.  
  97. }RT_OBJECT;
  98.  
  99. typedef struct RT_luz
  100. {
  101.     VECTOR pos;
  102.     VECTOR color;
  103. }RT_LUZ;
  104.  
  105. typedef struct RT_escena
  106. {
  107.     int num_luz,num_objetos,num_camera;
  108.     RT_OBJECT *objetos;
  109.     RT_LUZ    *luces;
  110.     RT_CAMERA *cameras;
  111.     VECTOR    ambient;
  112.     
  113. }RT_ESCENA;
  114.  
  115. VECTOR get_normal (RT_OBJECT *objeto, VECTOR pos)
  116. {
  117.     VECTOR normal;
  118.     switch (objeto->tipo)
  119.     {
  120.         case ESFERA :
  121.              normal=mul_vtr(1/objeto->radi,vtr_sub_vtr(pos,objeto->pos));
  122.         break;
  123.         case PLANO :
  124.              normal=objeto->EjeZ;
  125.         break;
  126.         case CILINDRO:
  127.              normal=vtr_sub_vtr(pos,objeto->pos);
  128.              normal=mul_vtr(1/objeto->radi,vtr_sub_vtr(normal,mul_vtr(vtr_dot_mul_vtr(normal,objeto->EjeZ),objeto->EjeZ)));
  129.         break;
  130.     }
  131.     return normal;
  132. }
  133.  
  134. float get_intersect (RT_OBJECT *objeto, VECTOR ori_rayo, VECTOR dir_rayo)
  135. {
  136.     VECTOR v_calc;
  137.     float  bpart,disc,disc2;
  138.     
  139.     float  t,t1,t2;
  140.     switch (objeto->tipo)
  141.     {
  142.         case ESFERA :
  143.              v_calc=vtr_sub_vtr(objeto->pos,ori_rayo);
  144.              bpart=vtr_dot_mul_vtr  (v_calc,dir_rayo);
  145.              disc=bpart*bpart-mod_vtr2(v_calc)+objeto->radi*objeto->radi;
  146.              if (disc>0)
  147.              {
  148.                  disc=sqrt(disc);
  149.                  t1=bpart+disc;
  150.                  t2=bpart-disc;
  151.                  if (t2>t1) t=t1;
  152.                  else t=t2;
  153.              }
  154.              else t=-1;
  155.              break;
  156.          case PLANO :
  157.               disc=vtr_dot_mul_vtr (objeto->EjeZ,dir_rayo);
  158.               if (disc!=0)
  159.               {
  160.                   t=-(vtr_dot_mul_vtr (objeto->EjeZ,ori_rayo)+objeto->d)/disc;
  161.               }
  162.               else t=-1;
  163.               break;
  164.  
  165.          case CILINDRO :
  166.              dir_rayo=vtr_sub_vtr(dir_rayo,mul_vtr(vtr_dot_mul_vtr(dir_rayo,objeto->EjeZ),objeto->EjeZ));
  167.              disc2=mod_vtr2(dir_rayo);
  168.              if (disc2!=0)
  169.              {
  170.                  v_calc=vtr_sub_vtr(ori_rayo,objeto->pos);
  171.                  v_calc=vtr_sub_vtr(v_calc,mul_vtr(vtr_dot_mul_vtr(v_calc,objeto->EjeZ),objeto->EjeZ));
  172.                  bpart=vtr_dot_mul_vtr  (v_calc,dir_rayo);
  173.                  disc=bpart*bpart+(objeto->radi*objeto->radi-mod_vtr2(v_calc))*disc2;
  174.                  if (disc>0)
  175.                  {
  176.                      disc=sqrt(disc);
  177.                      disc2=1/disc2;
  178.                      t1=(-bpart+disc)*disc2;
  179.                      t2=(-bpart-disc)*disc2;
  180.                      if (t2>t1) t=t1;
  181.                      else t=t2;
  182.                  }
  183.                  else t=-1;
  184.              }
  185.              else t=-1;
  186.              break;
  187.     }
  188.     return t;
  189. }    
  190.  
  191. int  rayo_sombra(RT_ESCENA *esc, VECTOR origen, VECTOR rayo, float max_t,int ori_object)
  192. {
  193.     float  t;
  194.     int    sc;
  195.     for (sc=0;sc<esc->num_objetos;sc++)
  196.     if  (sc!=ori_object)
  197.     {
  198.             t=get_intersect(&esc->objetos[sc],origen,rayo);
  199.             if ((t>0)&&(t<max_t)) return 1;
  200.     }
  201.     return 0;
  202. }
  203.  
  204. VECTOR rayo_luz (RT_ESCENA *esc, VECTOR origen, VECTOR ray, int iter, int ori_object)
  205. {
  206.         int    sc,lc,min_object;
  207.         float  bpart,disc,t,min_t,cos_alfa,cos_beta,mod_luz;
  208.         VECTOR posicion,normal,v_luz,color,add_col,col_ref,ray_ref;
  209.         VECTOR zero_color={0,0,0};
  210.         VECTOR v_calc;
  211.     
  212.         min_t=1000000.0;
  213.         min_object=-1;
  214.         for (sc=0;sc<esc->num_objetos;sc++)
  215.         if  (sc!=ori_object)
  216.         {
  217.              t=get_intersect(&esc->objetos[sc],origen,ray);
  218.              if ((t>0)&&(t<min_t)) {min_t=t; min_object=sc;}
  219.         }
  220.         if (min_object>=0)      // Si el rayo da con alguna esfera...
  221.         {
  222.             posicion=vtr_add_vtr(origen,mul_vtr(min_t,ray));
  223.             normal=get_normal(&esc->objetos[min_object],posicion);
  224.             ray_ref=vtr_sub_vtr(ray,mul_vtr(2*vtr_dot_mul_vtr(ray,normal),normal));
  225.             color=vtr_dir_mul_vtr(esc->objetos[min_object].ambient,esc->ambient);
  226.             for (lc=0;lc<esc->num_luz;lc++)
  227.             {
  228.                 v_luz=vtr_sub_vtr(esc->luces[lc].pos,posicion);
  229.                 mod_luz=mod_vtr(v_luz);                 //esta es la distancia a la que se encuentra la luz
  230.                 v_luz=mul_vtr(1/mod_luz,v_luz);
  231.                 cos_alfa=vtr_dot_mul_vtr(v_luz,normal);
  232.                 if (cos_alfa>0)
  233.                     if (!rayo_sombra(esc,posicion,v_luz,mod_luz,min_object))
  234.                     {   
  235.  
  236.                         cos_beta=vtr_dot_mul_vtr(ray_ref,v_luz);
  237.                         if (cos_beta>0)
  238.                             add_col=mul_vtr(exp(esc->objetos[min_object].brillo*(cos_beta-1)),
  239.                                             esc->objetos[min_object].specular);
  240.                         else
  241.                             add_col=zero_color;
  242.                         add_col=vtr_add_vtr(mul_vtr(cos_alfa,esc->objetos[min_object].diffuse),add_col);
  243.                         add_col=vtr_dir_mul_vtr(esc->luces[lc].color,add_col);
  244.                         color=vtr_add_vtr(color,add_col);
  245.                     }
  246.             }
  247.             // si hace falta, se lanza un rayo reflejado
  248.             if (iter<MAX_ITER){
  249.             col_ref=rayo_luz(esc,posicion,ray_ref,iter+1,min_object);
  250.             color=vtr_add_vtr(mul_vtr(esc->objetos[min_object].reflex,col_ref),
  251.                               mul_vtr(1-esc->objetos[min_object].reflex,color));}
  252.         }
  253.         else color=esc->ambient;
  254. //        else color=zero_color;
  255.  
  256.         // Calculos para representar las luces
  257.         if (iter==0)
  258.         for (lc=0;lc<esc->num_luz;lc++)
  259.         {
  260.             v_calc=vtr_sub_vtr(esc->luces[lc].pos,origen);
  261.             bpart=vtr_dot_mul_vtr (v_calc,ray);
  262.             disc=bpart*bpart-mod_vtr2(v_calc)+RADI_LUZ*RADI_LUZ;
  263.             if ((disc>0)&&(bpart>0.1)&&(bpart<min_t))
  264.             {
  265.                 disc=sqrt(disc);
  266.                 color=vtr_add_vtr(color,mul_vtr(disc/RADI_LUZ,esc->luces[lc].color));
  267.             }
  268.         }
  269.         
  270.         return (color);
  271. }
  272.  
  273. void RT_render(RT_ESCENA *esc, unsigned char *dest)
  274. {
  275.     int xc,yc,ppos;
  276.     VECTOR v_col,origen,direccion,v_dir;
  277.  
  278.     VECTOR X_axe, Y_axe, Z_axe;
  279.     VECTOR X_axep, Y_axep;
  280.     VECTOR right = {1.0,0.0,0.0};
  281.     VECTOR down  = {0.0,1.0,0.0};
  282.     VECTOR deep  = {0.0,0.0,-1.0};
  283.     float  angle;
  284.  
  285.     // Calculamos el sistema de ejes para la camara
  286.  
  287.     Z_axe=unit_vtr(vtr_sub_vtr(esc->cameras->target,esc->cameras->pos));
  288.     angle=vtr_dot_mul_vtr(Z_axe,down);
  289.     if ((angle<1.0)&&(angle>-1.0))
  290.     {
  291.         X_axe=unit_vtr(vtr_cross_mul_vtr(down,Z_axe));
  292.         Y_axe=unit_vtr(vtr_cross_mul_vtr(Z_axe,X_axe));
  293.     }
  294.     else    
  295.     {
  296.         X_axe=right;
  297.         Y_axe=deep;
  298.     }
  299.  
  300.     X_axep=mul_vtr(cos(esc->cameras->roll),X_axe);
  301.     Y_axep=mul_vtr(sin(esc->cameras->roll),Y_axe);
  302.     X_axep=vtr_add_vtr(X_axep,Y_axep);
  303.     X_axe=mul_vtr(-sin(esc->cameras->roll),X_axe);
  304.     Y_axe=mul_vtr(cos(esc->cameras->roll),Y_axe);
  305.     Y_axep=vtr_add_vtr(X_axe,Y_axe);
  306.  
  307.     // Lanzamos los rayos utilizando los ejes de la camara
  308.  
  309.     origen=esc->cameras->pos;
  310.     v_dir=vtr_add_vtr(mul_vtr(-MID_Y,Y_axep),mul_vtr(-MID_X,X_axep));
  311.     v_dir=vtr_add_vtr(v_dir,mul_vtr(esc->cameras->d,Z_axe));
  312.  
  313.     ppos=0;
  314.     for (yc=-MID_Y;yc<MID_Y;yc+=2)
  315.     {
  316.         for (xc=-MID_X;xc<MID_X;xc+=2)
  317.         {
  318.             direccion=unit_vtr(v_dir);
  319.             v_dir=vtr_add_vtr(mul_vtr(2,X_axep),v_dir);
  320.             v_col=rayo_luz(esc,origen,direccion,0,-1);
  321.  
  322.             dest[ppos  ]=min(v_col.v3,254);
  323.             dest[ppos+1]=min(v_col.v2,254);
  324.             dest[ppos+2]=min(v_col.v1,254);
  325.         
  326.             ppos+=6;
  327.         }
  328.       v_dir=vtr_add_vtr(v_dir,mul_vtr(-RES_X,X_axep));
  329.       v_dir=vtr_add_vtr(mul_vtr(2,Y_axep),v_dir);
  330.       ppos+=RES_X*3;
  331.     }   
  332.     interpola(dest);
  333. }
  334.  
  335. RT_ESCENA *ray_testing;
  336. unsigned char *Virtpant1;
  337. unsigned char *Virtpant2;
  338.  
  339. void main(int argc, char *argv[])
  340. {
  341.     float movi=0;
  342.     int   c;
  343.  
  344.     Virtpant1=malloc(RES_X*RES_Y*3);
  345.     Virtpant2=malloc(RES_X*RES_Y*3);
  346.     for (c=0;c<RES_X*RES_Y*3;c++)
  347.     Virtpant1[c]=0;
  348.  
  349.     // Definiciones de los objetos, luces y camara de la escena        
  350.  
  351.     ray_testing=malloc(sizeof(RT_ESCENA));
  352.     ray_testing->num_objetos =4;
  353.     ray_testing->num_camera =1;
  354.     ray_testing->num_luz    =2;
  355.     ray_testing->objetos=malloc(sizeof (RT_OBJECT)*ray_testing->num_objetos);
  356.     ray_testing->cameras=malloc(sizeof (RT_CAMERA)*ray_testing->num_camera);
  357.     ray_testing->luces  =malloc(sizeof (RT_LUZ   )*ray_testing->num_luz);
  358.     ray_testing->ambient.v1=0;
  359.     ray_testing->ambient.v2=64;
  360.     ray_testing->ambient.v3=32;
  361.     
  362.     ray_testing->objetos[0].tipo=ESFERA;
  363.     ray_testing->objetos[0].pos.v1=100;
  364.     ray_testing->objetos[0].pos.v2=60;
  365.     ray_testing->objetos[0].pos.v3=850;
  366.     ray_testing->objetos[0].radi=100;
  367.     ray_testing->objetos[0].ambient.v1=0;
  368.     ray_testing->objetos[0].ambient.v2=0;
  369.     ray_testing->objetos[0].ambient.v3=0.2;
  370.     ray_testing->objetos[0].diffuse.v1=0;
  371.     ray_testing->objetos[0].diffuse.v2=0.25;
  372.     ray_testing->objetos[0].diffuse.v3=0.5;
  373.     ray_testing->objetos[0].specular.v1=1;
  374.     ray_testing->objetos[0].specular.v2=1;
  375.     ray_testing->objetos[0].specular.v3=1;
  376.     ray_testing->objetos[0].brillo=10;
  377.     ray_testing->objetos[0].reflex=0.3;
  378.  
  379.     ray_testing->objetos[1].tipo=ESFERA;
  380.     ray_testing->objetos[1].pos.v1=0;
  381.     ray_testing->objetos[1].pos.v2=0;
  382.     ray_testing->objetos[1].pos.v3=1000;
  383.     ray_testing->objetos[1].radi=175;
  384.     ray_testing->objetos[1].ambient.v1=0.2;
  385.     ray_testing->objetos[1].ambient.v2=0;
  386.     ray_testing->objetos[1].ambient.v3=0;
  387.     ray_testing->objetos[1].diffuse.v1=0.6;
  388.     ray_testing->objetos[1].diffuse.v2=0.25;
  389.     ray_testing->objetos[1].diffuse.v3=0;
  390.     ray_testing->objetos[1].specular.v1=1;
  391.     ray_testing->objetos[1].specular.v2=0.8;
  392.     ray_testing->objetos[1].specular.v3=0.8;
  393.     ray_testing->objetos[1].brillo=20;
  394.     ray_testing->objetos[1].reflex=0.3;
  395.  
  396.     ray_testing->objetos[2].tipo=PLANO;
  397.     ray_testing->objetos[2].EjeZ.v1=0;
  398.     ray_testing->objetos[2].EjeZ.v2=-1;
  399.     ray_testing->objetos[2].EjeZ.v3=0;
  400.     ray_testing->objetos[2].d=100;
  401.     ray_testing->objetos[2].radi=175;
  402.     ray_testing->objetos[2].ambient.v1=0.2;
  403.     ray_testing->objetos[2].ambient.v2=0;
  404.     ray_testing->objetos[2].ambient.v3=0.2;
  405.     ray_testing->objetos[2].diffuse.v1=0.7;
  406.     ray_testing->objetos[2].diffuse.v2=0.20;
  407.     ray_testing->objetos[2].diffuse.v3=0.7;
  408.     ray_testing->objetos[2].specular.v1=1;
  409.     ray_testing->objetos[2].specular.v2=.8;
  410.     ray_testing->objetos[2].specular.v3=1;
  411.     ray_testing->objetos[2].brillo=50;
  412.     ray_testing->objetos[2].reflex=0.5;
  413.  
  414.     ray_testing->objetos[3].tipo=CILINDRO;
  415.     ray_testing->objetos[3].pos.v1=-250;
  416.     ray_testing->objetos[3].pos.v2=0;
  417.     ray_testing->objetos[3].pos.v3=700;
  418.     ray_testing->objetos[3].EjeZ.v1=0;
  419.     ray_testing->objetos[3].EjeZ.v2=-1;
  420.     ray_testing->objetos[3].EjeZ.v3=0;
  421.     ray_testing->objetos[3].radi=60;
  422.     ray_testing->objetos[3].ambient.v1=0.2;
  423.     ray_testing->objetos[3].ambient.v2=0.3;
  424.     ray_testing->objetos[3].ambient.v3=0;
  425.     ray_testing->objetos[3].diffuse.v1=0.8;
  426.     ray_testing->objetos[3].diffuse.v2=0.8;
  427.     ray_testing->objetos[3].diffuse.v3=0;
  428.     ray_testing->objetos[3].specular.v1=0.9;
  429.     ray_testing->objetos[3].specular.v2=0.8;
  430.     ray_testing->objetos[3].specular.v3=0.7;
  431.     ray_testing->objetos[3].brillo=50;
  432.     ray_testing->objetos[3].reflex=0.3;
  433.  
  434.     ray_testing->luces[0].pos.v1=300;
  435.     ray_testing->luces[0].pos.v2=0;
  436.     ray_testing->luces[0].pos.v3=500;
  437.     ray_testing->luces[0].color.v1=200;
  438.     ray_testing->luces[0].color.v2=0;
  439.     ray_testing->luces[0].color.v3=0;
  440.  
  441.     ray_testing->luces[1].pos.v1=200;
  442.     ray_testing->luces[1].pos.v2=-200;
  443.     ray_testing->luces[1].pos.v3=800;
  444.     ray_testing->luces[1].color.v1=255;
  445.     ray_testing->luces[1].color.v2=255;
  446.     ray_testing->luces[1].color.v3=255;
  447.  
  448.     ray_testing->cameras[0].pos.v1=0;   
  449.     ray_testing->cameras[0].pos.v2=0;   
  450.     ray_testing->cameras[0].pos.v3=0;
  451.     ray_testing->cameras[0].target.v1=0;
  452.     ray_testing->cameras[0].target.v2=0;
  453.     ray_testing->cameras[0].target.v3=1000;
  454.     ray_testing->cameras[0].roll=0;
  455.     ray_testing->cameras[0].d=256*RES_X/320;
  456.  
  457.     // Incicializacion del modo de video
  458.  
  459.     Active.Screen.Width=320;
  460.     Active.Screen.Height=200;
  461.     Active.Screen.bpp=32;
  462.  
  463.     Active.Work.Width=RES_X;
  464.     Active.Work.Height=RES_Y;
  465.     Active.Work.bpp=24;
  466.  
  467.     Active.EnableLFB=1;
  468.  
  469.     if (!InitSetMode())
  470.     {
  471.         Active.Screen.bpp=24;
  472.         if (!InitSetMode())
  473.         {
  474.             Active.Screen.bpp=16;
  475.             if (!InitSetMode())
  476.             {
  477.                 Active.Screen.bpp=15;
  478.                 if (!InitSetMode())
  479.                 {
  480.                     Active.Screen.bpp=-1;
  481.                     Active.Screen.Height*=2;
  482.                     InitSetMode();
  483.                 }
  484.             }
  485.         }
  486.     }
  487.  
  488.     movi=0;
  489.     while (!kbhit())
  490.     {
  491.         // Calculos para "animar" los elementos de la escena
  492.         
  493.         ray_testing->cameras[0].pos.v1=800*sin(movi/80.0);
  494.         ray_testing->cameras[0].pos.v2=-200*(1-cos(movi/40.0));
  495.         ray_testing->cameras[0].pos.v3=1000*(1-cos(movi/80.0));
  496.         ray_testing->cameras[0].roll=0.5*sin(movi/20.0);
  497.         ray_testing->objetos[0].pos.v1=300*cos(movi/35.0);
  498.         ray_testing->objetos[0].pos.v3=850+300*sin(movi/35.0);
  499.         ray_testing->objetos[3].EjeZ.v2=-cos(movi/50.0);
  500.         ray_testing->objetos[3].EjeZ.v1=-sin(movi/50.0);
  501.         movi++;
  502.  
  503.         RT_render(ray_testing,Virtpant1);
  504.         Flip(Virtpant1);
  505.     }
  506.     getch();
  507.     Set_Mode(0x3);
  508.     Free_Memory();
  509.     printf("[#] Salio\n");
  510. }
  511.  
  512.  
  513.