www.pudn.com > RayTracing Code.rar > EngPoly.cpp, change:2004-04-15,size:22536b
/** 3DGPL *************************************************\
* () *
* Functions for polygonal objects. *
* *
* Ifdefs: *
* _CI_ Colour/Intensity model; *
* _RGB_ RGB model; *
* _Z_BUFFER_ Depth array; *
* _PAINTER_ Back to front rendering. *
* *
* Defines: *
* M_init_polygon_object Compute BSP tree and normals;*
* M_shade_polygon_object Shadings using normals; *
* M_render_polygon_object Renders a polygonal solid. *
* *
* Internals: *
* MI_add_tuple A result of a split; *
* MI_split_polygon Called after a split; *
* MI_order_polygons Creating one BSP tree node; *
* MI_render_polygons Rendering polygons in order. *
* *
* (c) 1995-98 Sergei Savchenko, (savs@cs.mcgill.ca) *
\**********************************************************/
#include "RayTracing.h" /* HW_copy_ints */
#include "Graphics.h" /* 2-D rendering */
#include "Trans.h" /* 3-D transformations */
#include "Clipper.h" /* xyz clipping */
#include "Engine.h" /* 3-D engine */
#include "Colour.h" /* light related */
#include <stdlib.h> /* NULL */
int M_no_polygons; /* used in bsp tree building */
struct M_polygon **M_polygons; /* static polygons */
int M_no_vertices;
int *M_vertices; /* static vertices X Y Z */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* INTERNAL: Finding an index to a vertex. *
* --------- *
* RETURNS: Index the passed vertex in the array. *
* -------- *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int MI_add_tuple(int *vertex)
{
int i;
for(i=0;i<M_no_vertices;i++) /* comparing X Y Z only */
{
if((M_vertices[i*T_LNG_VECTOR]==vertex[0])&&
(M_vertices[i*T_LNG_VECTOR+1]==vertex[1])&&
(M_vertices[i*T_LNG_VECTOR+2]==vertex[2])
) return(i);
}
if(i>=M_MAX_OBJECT_VERTICES)
HW_error("(Engine) Not enough internal storage for vertices.\n");
/* X Y Z to one Tx Ty to another */
HW_copy_int(vertex,M_vertices+M_no_vertices*T_LNG_VECTOR,3);
return(M_no_vertices++); /* index of where inserted */
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* INTERNAL: Called after a split has occured. *
* --------- *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void MI_split_polygon(struct M_polygon *root,struct M_polygon *old,
struct M_polygon *new1,struct M_polygon *new2
)
{
int tmp1[M_MAX_POLYGON_VERTICES*M_LNG_POLYGON_VERTEX];
int tmp2[M_MAX_POLYGON_VERTICES*M_LNG_POLYGON_VERTEX];
int i;
for(i=0;i=old->m_no_edges;i++)
{
HW_copy_int(M_vertices+old->m_vertices[i*M_LNG_POLYGON_VERTEX]*T_LNG_VECTOR,
tmp1+i*5,3
); /* X Y Z */
HW_copy_int(old->m_vertices+i*M_LNG_POLYGON_VERTEX+M_IDX_POLYGON_TEXTURE,
tmp1+i*5+3,2
); /* Tx Ty */
}
new1->m_type=old->m_type&M_NOT_QUAD; /* can't be any longer M_QUAD */
new1->m_colour=old->m_colour;
#if defined(_CI_)
new1->m_intensity=old->m_intensity; /* I */
#endif
#if defined(_RGB_)
new1->m_red=old->m_red; /* R G B */
new1->m_green=old->m_green;
new1->m_blue=old->m_blue;
#endif
new1->m_log_texture_space_size=old->m_log_texture_space_size;
new1->m_texture=old->m_texture;
new1->m_no_edges=
C_polygon_xyz_clipping(tmp1,tmp2,
M_vertices+root->m_vertices[0]*T_LNG_VECTOR,
M_vertices+root->m_vertices[M_LNG_POLYGON_VERTEX]*T_LNG_VECTOR,
M_vertices+root->m_vertices[M_LNG_POLYGON_VERTEX*2]*T_LNG_VECTOR,
5,old->m_no_edges
); /* 5 == X Y Z Tx Ty */
new1->m_vertices=(int*)malloc(sizeof(int)*(new1->m_no_edges+1)*M_LNG_POLYGON_VERTEX);
if(new1->m_vertices==NULL) HW_error("(Engine) Not enough memory.\n");
for(i=0;i=new1->m_no_edges;i++) /* back into indexing */
{ /* getting vertex Index */
new1->m_vertices[i*M_LNG_POLYGON_VERTEX]=MI_add_tuple(tmp2+i*5);
HW_copy_int(tmp2+i*5+3,new1->m_vertices+i*M_LNG_POLYGON_VERTEX+M_IDX_POLYGON_TEXTURE,2);
} /* getting Tx Ty */
new2->m_type=old->m_type&M_NOT_QUAD; /* can't be any longer */
new2->m_colour=old->m_colour;
#if defined(_CI_)
new2->m_intensity=old->m_intensity;
#endif
#if defined(_RGB_)
new2->m_red=old->m_red;
new2->m_green=old->m_green;
new2->m_blue=old->m_blue;
#endif
new2->m_log_texture_space_size=old->m_log_texture_space_size;
new2->m_texture=old->m_texture;
new2->m_no_edges=
C_polygon_xyz_clipping(tmp1,tmp2,
M_vertices+root->m_vertices[M_LNG_POLYGON_VERTEX*2]*T_LNG_VECTOR,
M_vertices+root->m_vertices[M_LNG_POLYGON_VERTEX]*T_LNG_VECTOR,
M_vertices+root->m_vertices[0]*T_LNG_VECTOR,
5,old->m_no_edges
); /* 5 == X Y Z Tx Ty */
new2->m_vertices=(int*)malloc(sizeof(int)*(new2->m_no_edges+1)*M_LNG_POLYGON_VERTEX);
if(new2->m_vertices==NULL) HW_error("(Engine) Not enough memory.\n");
for(i=0;i=new2->m_no_edges;i++) /* back into indexing */
{ /* getting Indx Tx Ty */
new2->m_vertices[i*M_LNG_POLYGON_VERTEX]=MI_add_tuple(tmp2+i*5);
HW_copy_int(tmp2+i*5+3,new2->m_vertices+i*M_LNG_POLYGON_VERTEX+M_IDX_POLYGON_TEXTURE,2);
} /* from X Y Z [I]|[RGB] Tx Ty */
for(i=0;i<M_no_polygons;i++)
{
if(M_polygons[i]==old) /* searching for the one to kill */
{
free(M_polygons[i]->m_vertices); /* killing the old one */
free(M_polygons[i]);
M_polygons[i]=new1; /* puting pointer to a new one */
break;
}
}
if(M_no_polygons>=M_MAX_OBJECT_POLYGONS)
HW_error("(Engine) Can't handle this many polygons.");
M_polygons[M_no_polygons++]=new2; /* split produced two polygons */
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* INTERNAL: Creates a BSP tree order node. *
* --------- *
* RECURSIVE: Calls itself twice. *
* ---------- *
* RETURNS: Pointer to a created order structure. *
* -------- *
* Minimizes on number of splits and secondary on *
* disbalance in nodes. *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct M_polygon_object_order *MI_order_polygons(struct M_polygon **polygons,
int no_polygons
)
{
struct M_polygon *new1,*new2; /* for splits */
struct M_polygon_object_order *tmp;
struct M_polygon *positive[M_MAX_OBJECT_POLYGONS];
struct M_polygon *negative[M_MAX_OBJECT_POLYGONS];
static int indices[M_MAX_OBJECT_POLYGONS]; /* static for the recursion sake */
static int balances[M_MAX_OBJECT_POLYGONS];
static int splits[M_MAX_OBJECT_POLYGONS];
static int plane[4]; /* coefs of a plane equation */
int i,j,k,l,balance,bbal=0,split,itmp,no_positive=0,no_negative=0;
if(no_polygons==0) return(NULL); /* base case */
for(i=0;i<no_polygons;i++) { indices[i]=i; balances[i]=0; splits[i]=0; }
for(i=0;i<no_polygons;i++) /* calculate balance and splits */
{
T_plane(M_vertices+polygons[i]->m_vertices[0]*T_LNG_VECTOR,
M_vertices+polygons[i]->m_vertices[M_LNG_POLYGON_VERTEX]*T_LNG_VECTOR,
M_vertices+polygons[i]->m_vertices[M_LNG_POLYGON_VERTEX*2]*T_LNG_VECTOR,
plane
);
for(j=0;j<no_polygons;j++) /* for all polygons */
{
if(i==j) continue; /* not for the 1 assumed in root */
for(k=0,balance=0,split=0;k<polygons[j]->m_no_edges;k++)
{
for(l=0;l<polygons[i]->m_no_edges;l++) /* check shared vertices directly */
if(polygons[i]->m_vertices[l*M_LNG_POLYGON_VERTEX]==
polygons[j]->m_vertices[k*M_LNG_POLYGON_VERTEX]) { bbal=0; break; }
if(l==polygons[i]->m_no_edges) /* if not shared */
bbal=T_vertex_on_plane(M_vertices+ /* check plane equation */
polygons[j]->m_vertices[k*M_LNG_POLYGON_VERTEX]*T_LNG_VECTOR,
plane
);
if(bbal==0) continue; /* ignore those on the plane */
if(bbal>0) bbal=1; else bbal=-1;
if(balance==0) balance=bbal; /* initial point */
else /* other then initial point */
{
if(balance!=bbal) { split=1; balance=0; break; }
}
}
balances[i]+=balance; /* parameters assuming i in root */
splits[i]+=split;
}
} /* balances and splits found */
for(i=0;i<no_polygons;i++) balances[i]=abs(balances[i]);
for(i=no_polygons-1;i>0;i--) /* sorting seeking best balance */
{
for(j=0;j<i;j++)
{
if(balances[j]>balances[j+1]) /* to have least first */
{
itmp=balances[j]; balances[j]=balances[j+1]; balances[j+1]=itmp;
itmp=indices[j]; indices[j]=indices[j+1]; indices[j+1]=itmp;
itmp=splits[j]; splits[j]=splits[j+1]; splits[j+1]=itmp;
}
}
}
for(i=no_polygons-1;i>0;i--) /* sorting seeking less splits */
{
for(j=0;j<i;j++)
{
if(splits[j]>splits[j+1]) /* to have least first */
{
itmp=balances[j]; balances[j]=balances[j+1]; balances[j+1]=itmp;
itmp=indices[j]; indices[j]=indices[j+1]; indices[j+1]=itmp;
itmp=splits[j]; splits[j]=splits[j+1]; splits[j+1]=itmp;
}
}
}
tmp=(struct M_polygon_object_order*)
malloc(sizeof(struct M_polygon_object_order));
if(tmp==NULL) HW_error("(Engine) Not enough memory.\n");
tmp->m_root=polygons[indices[0]]; /* the one which is best */
T_plane(M_vertices+tmp->m_root->m_vertices[0]*T_LNG_VECTOR,
M_vertices+tmp->m_root->m_vertices[M_LNG_POLYGON_VERTEX]*T_LNG_VECTOR,
M_vertices+tmp->m_root->m_vertices[M_LNG_POLYGON_VERTEX*2]*T_LNG_VECTOR,
plane
); /* plane equation for the root */
for(i=0;i<no_polygons;i++)
{
if(tmp->m_root==polygons[i]) continue; /* not for the 1 in the root */
for(j=0,balance=0,split=0;j<polygons[i]->m_no_edges;j++)
{
for(l=0;l<tmp->m_root->m_no_edges;l++) /* check shared vertices directly */
if(tmp->m_root->m_vertices[l*M_LNG_POLYGON_VERTEX]==
polygons[i]->m_vertices[j*M_LNG_POLYGON_VERTEX]) { bbal=0; break; }
if(l==tmp->m_root->m_no_edges) /* if not shared */
bbal=T_vertex_on_plane(M_vertices+
polygons[i]->m_vertices[j*M_LNG_POLYGON_VERTEX]*T_LNG_VECTOR,
plane
);
if(bbal==0) continue; /* ignore those on the plane */
if(bbal>0) bbal=1; else bbal=-1;
if(balance==0) balance=bbal; /* initial point */
else if(balance!=bbal) { split=1; balance=0; break; }
}
if(split) /* what to do to a polygon */
{
new1=(struct M_polygon*)malloc(sizeof(struct M_polygon));
new2=(struct M_polygon*)malloc(sizeof(struct M_polygon));
if((new1==NULL)||(new2==NULL)) HW_error("(Fatal) Not enough memory.\n");
MI_split_polygon(tmp->m_root,polygons[i],new1,new2);
if((no_positive>=M_MAX_OBJECT_POLYGONS)||(no_negative>=M_MAX_OBJECT_POLYGONS))
HW_error("(Fatal) Not enoght internal storage for polygons.\n");
positive[no_positive++]=new1;
negative[no_negative++]=new2;
}
else
{
if(balance>0) /* entirely in subspaces */
{
if(no_positive>=M_MAX_OBJECT_POLYGONS)
HW_error("(Fatal) Not enoght internal storage for polygons.\n");
positive[no_positive++]=polygons[i];
}
else
{
if(no_negative>=M_MAX_OBJECT_POLYGONS)
HW_error("(Fatal) Not enoght internal storage for polygons.\n");
negative[no_negative++]=polygons[i];
}
}
} /* constructing subspaces */
tmp->m_positive=MI_order_polygons(positive,no_positive);
tmp->m_negative=MI_order_polygons(negative,no_negative);
return(tmp);
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* INTERNAL: Renders polygons in order. *
* --------- *
* RECURSIVE: Calls itself twice. *
* ---------- *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void MI_render_polygons(struct M_polygon_object_order *order,
int *vertices
)
{
int plane[4];
if(order!=NULL) /* base case */
{
T_plane(vertices+order->m_root->m_vertices[0]*T_LNG_VECTOR,
vertices+order->m_root->m_vertices[M_LNG_POLYGON_VERTEX]*T_LNG_VECTOR,
vertices+order->m_root->m_vertices[M_LNG_POLYGON_VERTEX*2]*T_LNG_VECTOR,
plane
); /* happens in the view space */
if(plane[3]>0) /* viewer is at (0,0,0) */
{ /* direct order of sub-spaces */
MI_render_polygons(order->m_negative,vertices);
M_render_polygon(order->m_root,vertices,NULL,NULL);
MI_render_polygons(order->m_positive,vertices);
}
else /* reversed order of sub spaces */
{
MI_render_polygons(order->m_positive,vertices);
M_render_polygon(order->m_root,vertices,NULL,NULL);
MI_render_polygons(order->m_negative,vertices);
}
}
}
/**********************************************************\
* Constructing a BSP tree for a polygonal object, and *
* computing the normals. *
\**********************************************************/
void M_init_polygon_object(struct M_polygon_object *object)
{
int tmp_normals[M_MAX_OBJECT_VERTICES*T_LNG_VECTOR];
int normals[M_MAX_OBJECT_VERTICES*T_LNG_VECTOR];
int i,j,k,n[5],num,norm_idx;
#if defined(_PAINTER_)
int tmp_vertices[M_MAX_OBJECT_VERTICES*M_LNG_POLYGON_VERTEX];
struct M_polygon *tmp_polygons[M_MAX_OBJECT_POLYGONS];
for(i=0;i<object->m_no_polygons;i++) tmp_polygons[i]=object->m_polygons[i];
HW_copy_int(object->m_vertices,tmp_vertices,
object->m_no_vertices*T_LNG_VECTOR
);
M_polygons=tmp_polygons; M_no_polygons=object->m_no_polygons;
M_vertices=tmp_vertices; M_no_vertices=object->m_no_vertices;
object->m_order=MI_order_polygons(object->m_polygons,object->m_no_polygons);
free(object->m_polygons); /* number of polygons/vertices */
free(object->m_vertices); /* was likely to change anyway */
object->m_polygons=(struct M_polygon**)malloc(sizeof(struct M_polygon*)*
M_no_polygons
);
object->m_vertices=(int*)malloc(sizeof(int)*M_no_vertices*T_LNG_VECTOR);
if((object->m_polygons==NULL)||(object->m_vertices==NULL))
HW_error("(Engine) Not enough memory.\n");
for(i=0;i<M_no_polygons;i++) object->m_polygons[i]=tmp_polygons[i];
HW_copy_int(M_vertices,object->m_vertices,M_no_vertices*T_LNG_VECTOR);
object->m_no_polygons=M_no_polygons; /* new numbers */
object->m_no_vertices=M_no_vertices;
#endif
M_vertices=tmp_normals; M_no_vertices=0; /* nothing added yet */
for(i=0;i<object->m_no_polygons;i++) /* for all polygons */
{
T_normal_plane(object->m_vertices+object->m_polygons[i]->m_vertices[0]*T_LNG_VECTOR,
object->m_vertices+object->m_polygons[i]->m_vertices[M_LNG_POLYGON_VERTEX]*T_LNG_VECTOR,
object->m_vertices+object->m_polygons[i]->m_vertices[M_LNG_POLYGON_VERTEX*2]*T_LNG_VECTOR,
normals+i*T_LNG_VECTOR
);
if(object->m_polygons[i]->m_type&M_PLANNAR)
{ /* same normal in flat polygons */
object->m_polygons[i]->m_normals=(int*)malloc(sizeof(int)*(object->m_polygons[i]->m_no_edges+1));
if(object->m_polygons[i]->m_normals==NULL)
HW_error("(Engine) Not enough memory.\n");
object->m_polygons[i]->m_normals[0]=MI_add_tuple(normals+i*T_LNG_VECTOR);
for(j=1;j=object->m_polygons[i]->m_no_edges;j++)
object->m_polygons[i]->m_normals[j]=object->m_polygons[i]->m_normals[0];
}
}
for(i=0;i<object->m_no_vertices;i++) /* for all vertices */
{
n[0]=n[1]=n[2]=0;
for(num=0,j=0;j<object->m_no_polygons;j++)/* check all polygons which */
{
if(object->m_polygons[j]->m_type&M_CURVED)
{ /* emulate curved surfaces */
if(object->m_polygons[j]->m_normals==NULL)
{
object->m_polygons[j]->m_normals=(int*)malloc(sizeof(int)*(object->m_polygons[j]->m_no_edges+1));
if(object->m_polygons[j]->m_normals==NULL)
HW_error("(Engine) Not enough memory.\n");
HW_set_int(object->m_polygons[j]->m_normals,object->m_polygons[j]->m_no_edges+1,0);
}
for(k=0;k=object->m_polygons[j]->m_no_edges;k++)
{
if(object->m_polygons[j]->m_vertices[k*M_LNG_POLYGON_VERTEX]==i)
{ /* if the vertex belong to it */
object->m_polygons[j]->m_normals[k]=-1;
n[0]+=normals[j*T_LNG_VECTOR]; /* mark the normal */
n[1]+=normals[j*T_LNG_VECTOR+1]; /* polygon's normal */
n[2]+=normals[j*T_LNG_VECTOR+2];
num++;
}
}
}
}
if(num!=0) /* for curved only */
{
n[0]/=num; n[1]/=num; n[2]/=num;
norm_idx=MI_add_tuple(n);
for(j=0;j<object->m_no_polygons;j++)
{
if(object->m_polygons[j]->m_type&M_CURVED)
{ /* emulate curved surfaces */
for(k=0;k=object->m_polygons[j]->m_no_edges;k++)
{
if(object->m_polygons[j]->m_normals[k]==-1)
object->m_polygons[j]->m_normals[k]=norm_idx;
}
}
}
}
}
object->m_normals=(int*)malloc(sizeof(int)*M_no_vertices*T_LNG_VECTOR);
object->m_no_normals=M_no_vertices; /* store the normals */
HW_copy_int(M_vertices,object->m_normals,M_no_vertices*T_LNG_VECTOR);
}
/**********************************************************\
* Shading a polygonal shape, setting both flat and *
* interpolative intensities. *
\**********************************************************/
void M_shade_polygon_object(struct M_polygon_object *object,
int x,int y,int z,
int alp,int bet,int gam,
int no_lights,
struct M_light **lights
)
{
int i;
int tmp_vertices[M_MAX_OBJECT_VERTICES*M_LNG_POLYGON_VERTEX];
int tmp_normals[M_MAX_OBJECT_VERTICES*M_LNG_POLYGON_VERTEX];
T_set_self_rotation(alp,bet,gam); /* shading happens in world space */
T_self_rotation(object->m_normals,tmp_normals,object->m_no_normals);
T_self_rotation(object->m_vertices,tmp_vertices,object->m_no_vertices);
T_translation(tmp_vertices,tmp_vertices,object->m_no_vertices,x,y,z);
if((object->m_no_vertices>M_MAX_OBJECT_VERTICES)||
(object->m_no_normals>M_MAX_OBJECT_VERTICES)
)
HW_error("(Engine) Can't handle this many vertices or normals in polygons.");
for(i=0;i<object->m_no_polygons;i++)
{
M_shade_polygon(object->m_polygons[i],tmp_vertices,tmp_normals,
no_lights,lights
);
}
}
/**********************************************************\
* Rendering a generic polygonal shape in perspective. *
\**********************************************************/
void M_render_polygon_object(struct M_polygon_object *object,
int x,int y,int z,
int alp,int bet,int gam
)
{
int tmp_vertices[M_MAX_OBJECT_VERTICES*M_LNG_POLYGON_VERTEX];
int i;
if(object->m_no_vertices>=M_MAX_OBJECT_VERTICES)
HW_error("(Engine) Can't handle this many vertices in polygons.");
T_set_self_rotation(alp,bet,gam); /* transformations */
T_cancatinate_self_world(x+M_camera_x,y+M_camera_y,z+M_camera_z);
T_cancatinated_rotation(object->m_vertices,tmp_vertices,object->m_no_vertices);
if(object->m_order!=NULL) /* when order struct exists */
{
MI_render_polygons(object->m_order,tmp_vertices);
}
else /* just rendering all polygons */
{ /* if no BSP tree structure */
for(i=0;i<object->m_no_polygons;i++)
{
M_render_polygon(object->m_polygons[i],tmp_vertices,NULL,NULL);
}
}
}
/**********************************************************/