EngBase.cpp
上传用户:lhwx1029
上传日期:2013-03-07
资源大小:1173k
文件大小:22k
源码类别:

3D图形编程

开发平台:

Visual C++

  1. /** 3DGPL *************************************************
  2.  * ()                                                     *
  3.  * Functions for the base of polygonal 3D engine.         *
  4.  *                                                        *
  5.  * Ifdefs:                                                *
  6.  *  _CI_                     Colour/Intensity model;      *
  7.  *  _RGB_                    RGB model;                   *
  8.  *  _Z_BUFFER_               Depth array;                 *
  9.  *  _PAINTER_                Back to front order.         *
  10.  *                                                        *
  11.  * Defines:                                               *
  12.  *  M_init_rendering         Set type of rendering;       *
  13.  *  M_shade_vertex           Shading a single vertex;     *
  14.  *  M_sort_elements          Polygons in _PAINTER_;       *
  15.  *                                                        *
  16.  *  M_shade_polygon          Shading using normals;       *
  17.  *  M_render_polygon         Rendering in perspective;    *
  18.  *                                                        *
  19.  *  M_set_gate               Set gate's clipping bounds.  *
  20.  *                                                        *
  21.  * Internals:                                             *
  22.  *  MI_construct_tuples      Gets X Y Z R G B Tx Ty;      *
  23.  *  MI_tmapping_vectors      Computes U V for tmapping.   *
  24.  *                                                        *
  25.  * (c) 1995-98 Sergei Savchenko, (savs@cs.mcgill.ca)      *
  26. **********************************************************/
  27. #include "Graphics.h"           /* 2-D rendering */
  28. #include "Trans.h"                 /* 3-D transformations */
  29. #include "Clipper.h"             /* 2-D/3-D clipping */
  30. #include "Engine.h"               /* 3-D engine */
  31. #include <stdlib.h>                         /* NULL */
  32. #include <limits.h>                         /* INT_MIN and INT_MAX */
  33. int M_force_linear_tmapping=0;              /* when the polygons are small */
  34. int M_rendering_type;                       /* types that can be rendered */
  35. unsigned char M_camera_gam;                 /* needed for surfaces */
  36. int M_camera_x,M_camera_y,M_camera_z;
  37. int M_camera_log_focus;                     /* camera parameters */
  38. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  39.  * INTERNAL: Constructing polygon list.                  *
  40.  * ---------                                             *
  41. * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  42. void CI_construct_tuples(int *from,register int *to,
  43.                          int *vertices,int *colours,
  44.                          int *textures,
  45.                          int dimension,int length,int *min,int *max
  46.                         )
  47. {
  48.  register int i,index;
  49.  HW_set_int(min,3,INT_MAX);                 /* X Y Z */
  50.  HW_set_int(max,3,INT_MIN);                 /* initializing searching */
  51.  for(i=0;i<length;i++)
  52.  {
  53.   HW_copy_int(vertices+((index=(*from++))*T_LNG_VECTOR),to,3);
  54.   if(*to>max[0]) max[0]=*to;                /* determining polygon's extend */
  55.   if(*to<min[0]) min[0]=*to;
  56.   to++;
  57.   if(*to>max[1]) max[1]=*to;
  58.   if(*to<min[1]) min[1]=*to;
  59.   to++;
  60.   if(*to>max[2]) max[2]=*to;
  61.   if(*to<min[2]) min[2]=*to;                /* by searching max/min */
  62.   to++;
  63. #if defined(_CI_)
  64.   if(dimension>=M_LNG_SHADED)
  65.   {
  66.    if(colours==NULL)
  67.    {
  68.     *to++=(*(from++))<<M_P;                 /* store I */
  69.    }
  70.    else
  71.    {
  72.     *to++=colours[index*CL_LNG_COLOUR]<<M_P;
  73.     from++;                                 /* skip empty space for I */
  74.    }
  75.    if(dimension==M_LNG_TEXTURED)
  76.    {
  77.     if(textures==NULL)
  78.     {
  79.      *to++=(*(from++))<<M_P;
  80.      *to++=(*(from++))<<M_P;                 /* store Tx,Ty */
  81.     }
  82.     else
  83.     {
  84.      *to++=textures[index*2]<<M_P;
  85.      *to++=textures[index*2+1]<<M_P;
  86.      from+=2;
  87.     }
  88.    }
  89.    else from+=2;                            /* Tx Ty */
  90.   }
  91.   else from+=3;                             /* I Tx Ty */
  92. #endif
  93. #if defined(_RGB_)
  94.   if(dimension>=M_LNG_SHADED)
  95.   {
  96.    if(colours==NULL)
  97.    {
  98.     *to++=(*(from++))<<M_P;                 /* store R G B */
  99.     *to++=(*(from++))<<M_P;
  100.     *to++=(*(from++))<<M_P;
  101.    }
  102.    else
  103.    {
  104.     HW_copy_int(colours+(index*CL_LNG_COLOUR),to,3);
  105.     *to++<<=M_P;
  106.     *to++<<=M_P;
  107.     *to++<<=M_P;
  108.     from+=3;                                /* skip empty space for R G B */
  109.    }
  110.    if(dimension==M_LNG_TEXTURED)
  111.    {
  112.     if(textures==NULL)
  113.     {
  114.      *to++=(*(from++))<<M_P;
  115.      *to++=(*(from++))<<M_P;                /* store Tx,Ty */
  116.     }
  117.     else
  118.     {
  119.      *to++=textures[index*2]<<M_P;
  120.      *to++=textures[index*2+1]<<M_P;
  121.      from+=2;
  122.     }
  123.    }
  124.    else from+=2;                            /* Tx Ty */
  125.   }
  126.   else from+=5;                             /* R G B Tx Ty */
  127. #endif
  128.  }
  129. }
  130. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  131.  * INTERNAL: Finding u,v texture orientation vectors.    *
  132.  * ---------                                             *
  133. * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  134. void MI_tmapping_vectors(int type,int *p1,int *p2,int *p3,
  135.                          int log_texture_space_size,
  136.                          int *u,int *v
  137.                         )
  138. {
  139.  int a[T_MAX_MATRIX_SIZE][T_MAX_MATRIX_SIZE];
  140.  int b[T_MAX_MATRIX_SIZE][T_MAX_MATRIX_SIZE];
  141.  int x[T_MAX_MATRIX_SIZE][T_MAX_MATRIX_SIZE];
  142.  if(type)                                   /* regular shape */
  143.  {
  144.   if(type&M_QUAD_XY)
  145.   {
  146.    T_vector(p1,p2,u,3);                     /* X Y Z */
  147.    T_vector(p2,p3,v,3);                     /* direct order */
  148.   }
  149.   else
  150.   {
  151.    T_vector(p2,p1,u,3);                     /* X Y Z */
  152.    T_vector(p3,p2,v,3);                     /* reversed order */
  153.   }
  154.  }
  155.  else                                       /* non regular shape */
  156.  {
  157.   T_vector(p1+M_IDX_TEXTURE,p2+M_IDX_TEXTURE,a[0],2);
  158.   T_vector(p2+M_IDX_TEXTURE,p3+M_IDX_TEXTURE,a[1],2);
  159.   T_vector(p1,p2,b[0],3);                   /* X Y Z */
  160.   T_vector(p2,p3,b[1],3);                   /* setting system of equations */
  161.   T_linear_solve(a,b,x,2,3,M_P,log_texture_space_size);
  162.   HW_copy_int(x[0],u,3);                    /* X Y Z */
  163.   HW_copy_int(x[1],v,3);
  164.  }
  165. }
  166. /**********************************************************
  167.  * Set rendering options.                                 *
  168.  *                                                        *
  169.  * SETS: M_rendering_type                                 *
  170.  * -----                                                  *
  171. **********************************************************/
  172. void M_init_rendering(int type)
  173. {
  174.  M_rendering_type=type;                     /* allowed rendering methods */
  175. }
  176. /**********************************************************
  177.  * Set the camera parameters, orientation and position    *
  178.  * of the projection plane and perspective focus.         *
  179.  *                                                        *
  180.  * SETS: M_rendering_type                                 *
  181.  * -----                                                  *
  182. **********************************************************/
  183. void M_set_camera(unsigned char alp,unsigned char bet,unsigned char gam,
  184.                   int x,int y,int z,int log_focus
  185.                  )
  186. {
  187.  T_set_world_rotation((unsigned char)256-alp,(unsigned char)256-bet,
  188.                       (unsigned char)256-gam
  189.                      );
  190.  M_camera_gam=(unsigned char)256-gam;
  191.  M_camera_x=-x;
  192.  M_camera_y=-y;
  193.  M_camera_z=-z;
  194.  M_camera_log_focus=log_focus;              /* other parameter of the camera */
  195. }
  196. /**********************************************************
  197.  * Shading a single vertex using a list of light sources  *
  198.  * and determining contribution of each light source.     *
  199. **********************************************************/
  200. void M_shade_vertex(int *intensity,
  201.                     int *vertex,int *normal,
  202.                     int no_lights, struct M_light **lights
  203.                    )
  204. {
  205.  int j,light_vector[T_LNG_VECTOR],prd;
  206.  struct M_light *light;
  207. #if defined(_CI_)
  208.  intensity[0]=0;                            /* intensity */
  209. #endif
  210. #if defined(_RGB_)
  211.  intensity[0]=0;                            /* RGB */
  212.  intensity[1]=0;
  213.  intensity[2]=0;
  214. #endif
  215.  for(j=0;j<no_lights;j++)
  216.  {
  217.   light=lights[j];
  218.   switch(light->m_type)
  219.   {
  220.    case M_AMBIENT:                          /* uniform illumination */
  221.    {
  222. #if defined(_CI_)
  223.     intensity[0]+=light->m_intensity;
  224. #endif
  225. #if defined(_RGB_)
  226.     intensity[0]+=light->m_red;
  227.     intensity[1]+=light->m_green;
  228.     intensity[2]+=light->m_blue;
  229. #endif
  230.    }
  231.    break;
  232.    case M_POINT:                            /* depends on the unit vector */
  233.    {
  234.     T_unit_vector(vertex,light->m_parameter,light_vector);
  235.     prd=T_scalar_product(light_vector,normal);
  236.     if(prd<0) break;
  237. #if defined(_CI_)
  238.     intensity[0]+=(prd*light->m_intensity)>>T_LOG_NORMAL_SIZE;
  239. #endif
  240. #if defined(_RGB_)
  241.     intensity[0]+=(prd*light->m_red)>>T_LOG_NORMAL_SIZE;
  242.     intensity[1]+=(prd*light->m_green)>>T_LOG_NORMAL_SIZE;
  243.     intensity[2]+=(prd*light->m_blue)>>T_LOG_NORMAL_SIZE;
  244. #endif
  245.    }
  246.    break;
  247.    case M_DIRECT:                           /* depends on the normal */
  248.    {
  249.     prd=-T_scalar_product(light->m_parameter,normal);
  250.     if(prd<0) break;
  251. #if defined(_CI_)
  252.     intensity[0]+=(prd*light->m_intensity)>>T_LOG_NORMAL_SIZE;
  253. #endif
  254. #if defined(_RGB_)
  255.     intensity[0]+=(prd*light->m_red)>>T_LOG_NORMAL_SIZE;
  256.     intensity[1]+=(prd*light->m_green)>>T_LOG_NORMAL_SIZE;
  257.     intensity[2]+=(prd*light->m_blue)>>T_LOG_NORMAL_SIZE;
  258. #endif
  259.    }
  260.    break;
  261.   }
  262.  }
  263. }
  264. /**********************************************************
  265.  * Sorting at the same time an array of vertices and an   *
  266.  * array of indices.                                      *
  267. **********************************************************/
  268. #if defined(_PAINTER_)
  269. void M_sort_elements(int *vertices,int dimension,int *indices,int number)
  270. {
  271.  int i,j,tmp;
  272.  for(i=number-1;i>0;i--)                    /* buble sorting indexes */
  273.  {
  274.   for(j=0;j<i;j++)
  275.   {
  276.    if(vertices[indices[j]*dimension]<vertices[indices[(j+1)]*dimension])
  277.    {                                        /* render the ones further away */
  278.     tmp=indices[j]; indices[j]=indices[j+1]; indices[j+1]=tmp;
  279.    }                                        /* earlier */
  280.   }
  281.  }
  282. }
  283. #endif
  284. /**********************************************************
  285.  * Shading a single polygon using a list of light sources *
  286.  * for each vertex at the same time computing flat        *
  287.  * illumination for the whole polygon to use for low      *
  288.  * rendering options.                                     *
  289. **********************************************************/
  290. void M_shade_polygon(struct M_polygon *poly,int *vertices,
  291.                      int *normals, int no_lights,
  292.                      struct M_light **lights
  293.                     )
  294. {
  295.  int i,*vertex,*normal_idxs;
  296. #if defined(_CI_)
  297.  poly->m_intensity=0;
  298. #endif
  299. #if defined(_RGB_)
  300.  poly->m_red=0;
  301.  poly->m_green=0;
  302.  poly->m_blue=0;                            /* init flat intensity */
  303. #endif
  304.  vertex=poly->m_vertices;
  305.  normal_idxs=poly->m_normals;
  306.  for(i=0;i<=poly->m_no_edges;i++,vertex+=M_LNG_POLYGON_VERTEX,normal_idxs++)
  307.  {
  308.   M_shade_vertex(vertex+1,vertices+vertex[0]*T_LNG_VECTOR,
  309.                  normals+(*normal_idxs*T_LNG_VECTOR),
  310.                  no_lights,lights
  311.                 );
  312. #if defined(_CI_)
  313.   poly->m_intensity+=vertex[1];
  314. #endif
  315. #if defined(_RGB_)
  316.   poly->m_red+=vertex[1];
  317.   poly->m_green+=vertex[2];
  318.   poly->m_blue+=vertex[3];                  /* polygon's illumination */
  319. #endif
  320.  }
  321. #if defined(_CI_)
  322.  poly->m_intensity/=(poly->m_no_edges+1);
  323. #endif
  324. #if defined(_RGB_)
  325.  poly->m_red/=(poly->m_no_edges+1);
  326.  poly->m_green/=(poly->m_no_edges+1);       /* computing intensities for */
  327.  poly->m_blue/=(poly->m_no_edges+1);        /* dirty rendering options */
  328. #endif
  329. }
  330. /**********************************************************
  331.  * Rendering a generic polygon in perspective.            *
  332.  * Firstly vertex tuples are being created, they are      *
  333.  * of length M_LNG_WHATEVER, they are being pyramide      *
  334.  * clipped and Z clipped, hence tuples are being sent     *
  335.  * into perspective acquiring length of G_LNG_WHATEVER,   *
  336.  * (Z might get discarded for _PAINTER_, that's why),     *
  337.  * culling is being done, and then method dependent       *
  338.  * (AMBIENT, SHADED) rendering are being done.            *
  339.  * Specifically for perspective a function to get         *
  340.  * mapping vectors would be invoked.                      *
  341. **********************************************************/
  342. void M_render_polygon(struct M_polygon *poly,
  343.                       int *vertices,int *colours,
  344.                       int *textures
  345.                      )
  346. {
  347.  int original1[M_MAX_POLYGON_VERTICES*C_MAX_DIMENSIONS];
  348.  int original2[M_MAX_POLYGON_VERTICES*C_MAX_DIMENSIONS];
  349.  int perspective[M_MAX_POLYGON_VERTICES*C_MAX_DIMENSIONS];
  350.  int vector1[T_LNG_VECTOR],vector2[T_LNG_VECTOR];
  351.  int *clipped,number,cnd;
  352.  int i,min[3],max[3];                       /* extends X Y Z */
  353.  switch(M_rendering_type)
  354.  {
  355.   case M_WIRE:                              /* X Y Z, a wireframe */
  356.   {
  357.    number=poly->m_no_edges;
  358.    CI_construct_tuples((int*)poly->m_vertices,original1,
  359.                        vertices,colours,textures,
  360.                        M_LNG_FLAT,number+1,min,max
  361.                       );
  362.    if((cnd=C_volume_clipping(min,max))!=0)  /* using extends */
  363.    {
  364.     if(cnd==-1)
  365.     {
  366.      number=C_polygon_z_clipping(original1,clipped=original2,
  367.                                  M_LNG_FLAT,number
  368.                                 );
  369.     }
  370.     else clipped=original1;                 /* source is of M_LNG_FLAT */
  371.     T_perspective(clipped,perspective,M_LNG_FLAT,number+1,M_camera_log_focus);
  372.                                             /* result is of G_LNG_FLAT */
  373.     if(T_normal_z_negative(perspective,perspective+G_LNG_FLAT,
  374.                                        perspective+G_LNG_FLAT*2
  375.                           )
  376.       )
  377.     {
  378.      for(i=0;i<number;i++)
  379.      {
  380. #if defined(_CI_)
  381.       G_line(perspective+i*G_LNG_FLAT,perspective+(i+1)*G_LNG_FLAT,
  382.              poly->m_colour,poly->m_intensity
  383.             );
  384. #endif
  385. #if defined(_RGB_)
  386.       G_line(perspective+i*G_LNG_FLAT,perspective+(i+1)*G_LNG_FLAT,
  387.              poly->m_colour,poly->m_red,poly->m_green,poly->m_blue
  388.             );
  389. #endif
  390.      }
  391.     }
  392.    }
  393.   } break;
  394.   case M_FLAT:                              /* X Y Z, flat shaded polygon */
  395.   {
  396.    number=poly->m_no_edges;
  397.    CI_construct_tuples((int*)poly->m_vertices,original1,
  398.                        vertices,colours,textures,
  399.                        M_LNG_FLAT,number+1,min,max
  400.                       );
  401.    if((cnd=C_volume_clipping(min,max))!=0)  /* using extends */
  402.    {
  403.     if(cnd==-1)
  404.     {
  405.      number=C_polygon_z_clipping(original1,clipped=original2,
  406.                                  M_LNG_FLAT,number
  407.                                 );
  408.     }
  409.     else clipped=original1;                 /* source is of M_LNG_FLAT */
  410.     T_perspective(clipped,perspective,M_LNG_FLAT,number+1,M_camera_log_focus);
  411.                                             /* result is of G_LNG_FLAT */
  412.     if(T_normal_z_negative(perspective,perspective+G_LNG_FLAT,
  413.                                        perspective+G_LNG_FLAT*2
  414.                           )
  415.       )
  416.     {
  417. #if defined(_CI_)
  418.      G_flat_polygon(perspective,number,poly->m_colour,poly->m_intensity);
  419. #endif
  420. #if defined(_RGB_)
  421.      G_flat_polygon(perspective,number,poly->m_colour,poly->m_red,
  422.                        poly->m_green,poly->m_blue
  423.                       );
  424. #endif
  425.     }
  426.    }
  427.   } break;
  428.   case M_TEXTURED:                          /* X Y Z [I] or [R G B] Tx Ty */
  429.   {                                         /* texture mapped polygon */
  430.    if(poly->m_texture!=NULL)
  431.    {
  432.     number=poly->m_no_edges;
  433.     CI_construct_tuples((int*)poly->m_vertices,original1,
  434.                         vertices,colours,textures,
  435.                         M_LNG_TEXTURED,number+1,min,max
  436.                        );
  437.     if((cnd=C_volume_clipping(min,max))!=0) /* using extends */
  438.     {
  439.      if(cnd==-1) number=C_polygon_z_clipping(original1,clipped=original2,
  440.                                              M_LNG_TEXTURED,number
  441.                                             );
  442.      else clipped=original1;                /* source is of M_LNG_TEXTURED */
  443.      T_perspective(clipped,perspective,M_LNG_TEXTURED,number+1,M_camera_log_focus);
  444.                                             /* result is of G_LNG_TEXTURED */
  445.      if(T_normal_z_negative(perspective,perspective+G_LNG_TEXTURED,
  446.                                         perspective+G_LNG_TEXTURED*2
  447.                            )
  448.        )
  449.      {
  450.       if((M_force_linear_tmapping)||
  451.          (clipped[2]<G_Z_MAPPING_SWITCH)    /* non-linear one */
  452.         )
  453.       {                                     /* original is of M_LNG_TEXTURED */
  454.        MI_tmapping_vectors(poly->m_type&M_QUAD,
  455.                            original1,
  456.                            original1+M_LNG_TEXTURED,
  457.                            original1+M_LNG_TEXTURED*2,
  458.                            poly->m_log_texture_space_size,
  459.                            vector1,vector2
  460.                           );
  461.        G_prp_textured_polygon(perspective,number,clipped,
  462.                               vector1,vector2,
  463.                               poly->m_texture->m_texture_bytes,
  464.                               poly->m_texture->m_log_texture_size,
  465.                               poly->m_log_texture_space_size
  466.                              );
  467.       }
  468.       else                                  /* linear mapping */
  469.       {
  470.        G_lin_textured_polygon(perspective,number,
  471.                               poly->m_texture->m_texture_bytes,
  472.                               poly->m_texture->m_log_texture_size
  473.                              );
  474.       }
  475.      }
  476.     }
  477.     break;                                  /* if no texture do shaded */
  478.    }
  479.   }
  480.   case M_SHADED:                            /* X Y Z [I] or [R G B] */
  481.   {                                         /* Gourand shaded polygons */
  482.    number=poly->m_no_edges;
  483.    CI_construct_tuples((int*)poly->m_vertices,original1,
  484.                        vertices,colours,textures,
  485.                        M_LNG_SHADED,number+1,min,max
  486.                       );
  487.    if((cnd=C_volume_clipping(min,max))!=0)  /* using extends */
  488.    {
  489.     if(cnd==-1)
  490.     {
  491.      number=C_polygon_z_clipping(original1,clipped=original2,
  492.                                  M_LNG_SHADED,number
  493.                                 );
  494.     }
  495.     else clipped=original1;                 /* source is of M_LNG_SHADED */
  496.     T_perspective(clipped,perspective,M_LNG_SHADED,number+1,M_camera_log_focus);
  497.                                             /* result is of G_LNG_SHADED */
  498.     if(T_normal_z_negative(perspective,perspective+G_LNG_SHADED,
  499.                                        perspective+G_LNG_SHADED*2
  500.                           )
  501.       )
  502.     {
  503.      G_shaded_polygon(perspective,number,poly->m_colour);
  504.     }
  505.    }
  506.   }
  507.   break;
  508.  }
  509. }
  510. /**********************************************************
  511.  * Setting clipping limits for the extend of a            *
  512.  * perspective projection of a gate to the screen.        *
  513.  *                                                        *
  514.  * Firstly vertex tuples are created, they are pyramide   *
  515.  * clipped and Z clipped, hence tuples are sent into      *
  516.  * perspective, further the extends are found and the     *
  517.  * clipping bounds set.                                   *
  518.  *                                                        *
  519.  * RETURNS: 1 on success;                                 *
  520.  * -------- 0 when clipping limits can't be set.          *
  521. **********************************************************/
  522. int M_set_gate(struct M_gate *gate,int *vertices)
  523. {
  524.  int original1[M_MAX_POLYGON_VERTICES*C_MAX_DIMENSIONS];
  525.  int original2[M_MAX_POLYGON_VERTICES*C_MAX_DIMENSIONS];
  526.  int perspective[M_MAX_POLYGON_VERTICES*C_MAX_DIMENSIONS];
  527.  int *tmp,*clipped,number,cnd;
  528.  int min[3],max[3];                         /* extends X Y Z */
  529.  int nminx,nminy,nmaxx,nmaxy;               /* new clipping bounds */
  530.  int i,*to;
  531.  number=gate->m_no_edges;
  532.  HW_set_int(min,3,INT_MAX);                 /* X Y Z */
  533.  HW_set_int(max,3,INT_MIN);                 /* initializing searching */
  534.  for(to=original1,i=0;i<=number;i++)
  535.  {
  536.   HW_copy_int(vertices+(gate->m_vertices[i]*T_LNG_VECTOR),to,3);
  537.   if(*to>max[0]) max[0]=*to;                /* determining polygon's extend */
  538.   if(*to<min[0]) min[0]=*to;
  539.   to++;
  540.   if(*to>max[1]) max[1]=*to;
  541.   if(*to<min[1]) min[1]=*to;
  542.   to++;
  543.   if(*to>max[2]) max[2]=*to;
  544.   if(*to<min[2]) min[2]=*to;                /* by searching max/min */
  545.   to++;
  546.  }
  547.  if((cnd=C_volume_clipping(min,max))!=0)    /* using extends */
  548.  {
  549.   if(cnd==-1)
  550.   {
  551.    number=C_polygon_z_clipping(original1,clipped=original2,M_LNG_FLAT,number);
  552.   }
  553.   else clipped=original1;                   /* source is of length 3 */
  554.   T_perspective(clipped,perspective,M_LNG_FLAT,number+1,M_camera_log_focus);
  555.                                             /* result is of G_LNG_FLAT */
  556.   if(!T_normal_z_negative(perspective,perspective+G_LNG_FLAT,
  557.                                       perspective+G_LNG_FLAT*2)
  558.                          )
  559.    return(0);                               /* gate is back culled */
  560.   nminx=nminy=INT_MAX;
  561.   nmaxx=nmaxy=INT_MIN;                      /* initializing searching */
  562.   for(tmp=perspective,i=0;i<number;i++)
  563.   {
  564.    if(*tmp>nmaxx) nmaxx=*tmp;               /* determining gate extend */
  565.    if(*tmp<nminx) nminx=*tmp;               /* X */
  566.    tmp++;
  567.    if(*tmp>nmaxy) nmaxy=*tmp;               /* Y */
  568.    if(*tmp<nminy) nminy=*tmp;
  569.    tmp++;
  570. #if defined(_Z_BUFFER_)
  571.    tmp++;                                   /* Z if present */
  572. #endif
  573.   }
  574.   return(C_set_bounds(nminx,nminy,nmaxx,nmaxy));
  575.  }
  576.  else return(0);                            /* gate is behind the viewer */
  577. }
  578. /**********************************************************/