gem5/splash2/codes/apps/raytrace/poly.C
Sanchayan Maity 2fcc51c2c1 Commit splash2 benchmark
While at it also add the libpthread static library amd m5op_x86
for matrix multiplication test code as well.

Note that the splash2 benchmark code does not comply with gem5
coding guidelines. Academic guys never seem to follow 80 columns
and no whitespace guideline :(.
2017-04-26 20:50:15 +05:30

828 lines
22 KiB
C

/*************************************************************************/
/* */
/* Copyright (c) 1994 Stanford University */
/* */
/* All rights reserved. */
/* */
/* Permission is given to use, copy, and modify this software for any */
/* non-commercial purpose as long as this copyright notice is not */
/* removed. All other uses, including redistribution in whole or in */
/* part, are forbidden without prior written permission. */
/* */
/* This software is provided with absolutely no warranty and no */
/* support. */
/* */
/*************************************************************************/
/*
* NAME
* poly.c
*
* DESCRIPTION
* This file contains all routines that operate on polygon objects.
*
*/
#include <cmath>
#include <cstdio>
#include "rt.h"
/*
* NAME
* PolyName - return the object name
*
* SYNOPSIS
* CHAR *PolyName()
*
* RETURNS
* A pointer to the name string.
*/
CHAR *PolyName()
{
return ("poly");
}
/*
* NAME
* PolyPrint - print the polygon object data to stdout
*
* SYNOPSIS
* VOID PolyPrint(po)
* OBJECT *po; // Ptr to polygon object.
*
* RETURNS
* Nothing.
*/
VOID PolyPrint(OBJECT *po)
{
INT i, j;
INT *vindex; /* Ptr to vertex index. */
VEC3 *vlist, *vptr; /* Ptr to vertex list. */
POLY *pp; /* Ptr to polygon data. */
ELEMENT *pe; /* Ptr to polygon element. */
pe = po->pelem;
fprintf(stderr, "\tpolygon: %ld polygons.\n", po->numelements);
for (i = 0; i < po->numelements; i++)
{
pp = (POLY *)pe->data;
fprintf(stderr, "\t\tVertices: %ld Plane eq: %f %f %f %f\n", pp->nverts, pp->norm[0], pp->norm[1], pp->norm[2], pp->d);
vlist = pp->vptr;
vindex = pp->vindex;
for (j = 0; j < pp->nverts; j++)
{
vptr = vlist + (*vindex);
fprintf(stderr, "\t\t%f %f %f \n", (*vptr)[0], (*vptr)[1], (*vptr)[2]);
vindex++;
}
pe++;
}
}
/*
* NAME
* PolyElementBoundBox - compute polygon element bounding box
*
* SYNOPSIS
* VOID PolyElementBoundBox(pe, pp)
* ELEMENT *pe; // Ptr to polygon element.
* POLY *pp; // Ptr to polygon data.
*
* RETURNS
* Nothing.
*/
VOID PolyElementBoundBox(ELEMENT *pe, POLY *pp)
{
INT i; /* Index. */
INT *vindex; /* Vertex index pointer. */
BBOX *pbb; /* Ptr to bounding box. */
VEC3 *vlist, *vptr; /* Vertex list pointer. */
REAL minx, maxx;
REAL miny, maxy;
REAL minz, maxz;
pbb = &(pe->bv);
minx = miny = minz = HUGE_REAL;
maxx = maxy = maxz = -HUGE_REAL;
vlist = pp->vptr;
vindex = pp->vindex;
for (i = 0; i < pp->nverts; i++)
{
vptr = vlist + (*vindex);
minx = Min(minx, (*vptr)[0]);
miny = Min(miny, (*vptr)[1]);
minz = Min(minz, (*vptr)[2]);
maxx = Max(maxx, (*vptr)[0]);
maxy = Max(maxy, (*vptr)[1]);
maxz = Max(maxz, (*vptr)[2]);
vindex++;
}
pbb->dnear[0] = minx;
pbb->dnear[1] = miny;
pbb->dnear[2] = minz;
pbb->dfar[0] = maxx;
pbb->dfar[1] = maxy;
pbb->dfar[2] = maxz;
}
/*
* NAME
* PolyBoundBox - compute polygon object bounding box
*
* SYNOPSIS
* VOID PolyBoundBox(po)
* OBJECT *po; // Ptr to polygon object.
*
* RETURNS
* Nothing.
*/
VOID PolyBoundBox(OBJECT *po)
{
INT i;
POLY *pp; /* Ptr to polygon data. */
ELEMENT *pe; /* Ptr to polygon element. */
BBOX *pbb; /* Ptr to bounding box. */
REAL minx, maxx;
REAL miny, maxy;
REAL minz, maxz;
pe = po->pelem;
pbb = &(po->bv);
minx = miny = minz = HUGE_REAL;
maxx = maxy = maxz = -HUGE_REAL;
for (i = 0; i < po->numelements; i++)
{
pp = (POLY *)pe->data;
PolyElementBoundBox(pe, pp);
minx = Min(minx, pe->bv.dnear[0]);
miny = Min(miny, pe->bv.dnear[1]);
minz = Min(minz, pe->bv.dnear[2]);
maxx = Max(maxx, pe->bv.dfar[0]);
maxy = Max(maxy, pe->bv.dfar[1]);
maxz = Max(maxz, pe->bv.dfar[2]);
pe++;
}
pbb->dnear[0] = minx;
pbb->dnear[1] = miny;
pbb->dnear[2] = minz;
pbb->dfar[0] = maxx;
pbb->dfar[1] = maxy;
pbb->dfar[2] = maxz;
}
/*
* NAME
* PolyNormal - compute polygon unit normal at given point on the surface
*
* SYNOPSIS
* VOID PolyNormal(hit, Pi, Ni)
* IRECORD *hit; // Ptr to intersection record.
* POINT Pi; // Ipoint.
* POINT Ni; // Normal.
*
* NOTES
* If no normal interpolation, the normal is the face normal. Otherwise,
* interpolate with the normal plane equation.
*
* RETURNS
* Nothing.
*/
VOID PolyNormal(IRECORD *hit, POINT Pi, POINT Ni)
{
ELEMENT *pe;
POLY *pp;
/* Retrieve normal from hit polygon. */
pe = hit->pelem;
pp = (POLY *)pe->data;
VecCopy(Ni, pp->norm);
}
/*
* NAME
* PolyDataNormalize - normalize polygon data and bounding box
*
* SYNOPSIS
* VOID PolyDataNormalize(po, normMat)
* OBJECT *po; // Ptr to polygon object.
* MATRIX normMat; // Normalization matrix.
*
* RETURNS
* Nothing.
*/
VOID PolyDataNormalize(OBJECT *po, MATRIX normMat)
{
INT i;
POINT coord;
VEC3 *pv; /* Ptr to vertex list. */
POLY *pp; /* Ptr to polygon data. */
ELEMENT *pe; /* Ptr to polygon element. */
/* Normalize bounding box. */
pe = po->pelem;
NormalizeBoundBox(&po->bv, normMat);
/* Normalize vertex list. */
pp = (POLY *)pe->data;
pv = pp->vptr;
coord[0] = (*pv)[0];
coord[1] = (*pv)[1];
coord[2] = (*pv)[2];
coord[3] = 1.0;
/* Transform coordinate by xform matrix. */
while (coord[0] != HUGE_REAL && coord[1] != HUGE_REAL && coord[2] != HUGE_REAL)
{
VecMatMult(coord, normMat, coord);
(*pv)[0] = coord[0];
(*pv)[1] = coord[1];
(*pv)[2] = coord[2];
pv++;
coord[0] = (*pv)[0];
coord[1] = (*pv)[1];
coord[2] = (*pv)[2];
coord[3] = 1.0;
}
/* Normalize bounding boxes of object elements. */
for (i = 0; i < po->numelements; i++)
{
pp = (POLY *)pe->data;
NormalizeBoundBox(&pe->bv, normMat);
/* Find new d of plane equation. */
pv = pp->vptr + (*(pp->vindex));
pp->d = -(pp->norm[0]*(*pv)[0] + pp->norm[1]*(*pv)[1] + pp->norm[2]*(*pv)[2]);
pe++;
}
}
/*
* NAME
* PolyPeIntersect - calculate intersection of ray with polygon
*
* SYNOPSIS
* INT PolyPeIntersect(pr, pe, hit)
* RAY *pr; // Ptr to incident ray.
* ELEMENT *pe; // Polyangle object
* IRECORD *hit; // Intersection record.
*
* NOTES
* Check first to see if ray is parallel to plane or if the intersection
* point with the plane is behind the eye.
*
* If neither of these cases applies, determine if the intersection point
* is contained in the polygon. First, project onto a plane. Translate
* the intersection point to the origin. If a ray starting from the
* origin along the 2 - d X axis of the plane crosses an odd number of
* polygon edges, the point is in the polygon.
*
* RETURNS
* The number of intersection points.
*/
INT PolyPeIntersect(RAY *pr, ELEMENT *pe, IRECORD *hit)
{
INT i;
INT *vindex; /* Vertex index pointer. */
INT toright; /* Counter. */
INT sh, nsh; /* Sign holders. */
REAL Rd_dot_Pn; /* Polygon normal dot ray direction. */
REAL Ro_dot_Pn; /* Polygon normal dot ray origin. */
REAL tval; /* Intersection t distance value. */
REAL x[MAX_VERTS + 1]; /* Projection list. */
REAL y[MAX_VERTS + 1]; /* Projection list. */
REAL ix, iy; /* Intersection projection point. */
REAL dx, dy; /* Deltas between 2 vertices. */
REAL xint; /* Intersection value. */
VEC3 I; /* Intersection point. */
VEC3 *vlist, *vpos; /* Vertex list pointer. */
POLY *pp; /* Ptr to polygon data. */
pp = (POLY *)pe->data;
Rd_dot_Pn = VecDot(pp->norm, pr->D);
if (ABS(Rd_dot_Pn) < RAYEPS) /* Ray is parallel. */
return (0);
Ro_dot_Pn = VecDot(pp->norm, pr->P);
tval = -(pp->d + Ro_dot_Pn)/Rd_dot_Pn; /* Intersection distance. */
if (tval < RAYEPS) /* Intersects behind ray. */
return (0);
RayPoint(I, pr, tval);
/* Polygon containment. */
/* Project onto plane with greatest normal component. */
vlist = pp->vptr;
vindex = pp->vindex;
switch (pp->axis_proj)
{
case X_AXIS:
for (i = 0; i < pp->nverts; i++)
{
vpos = vlist + (*vindex);
x[i] = (*vpos)[1];
y[i] = (*vpos)[2];
vindex++;
}
ix = I[1];
iy = I[2];
break;
case Y_AXIS:
for (i = 0; i < pp->nverts; i++)
{
vpos = vlist + (*vindex);
x[i] = (*vpos)[0];
y[i] = (*vpos)[2];
vindex++;
}
ix = I[0];
iy = I[2];
break;
case Z_AXIS:
for (i = 0; i < pp->nverts; i++)
{
vpos = vlist + (*vindex);
x[i] = (*vpos)[0];
y[i] = (*vpos)[1];
vindex++;
}
ix = I[0];
iy = I[1];
break;
}
/* Translate to origin. */
for (i = 0; i < pp->nverts; i++)
{
x[i] -= ix;
y[i] -= iy;
if (ABS(y[i]) < RAYEPS)
y[i] = 0.0;
}
x[pp->nverts] = x[0];
y[pp->nverts] = y[0];
/*
* If intersection point crosses an odd number of line segments,
* the point is inside the polygon
*/
if (y[0] < 0.0)
sh = 0;
else
sh = 1;
toright = 0;
for (i = 0; i < pp->nverts; i++)
{
/* Check if segment crosses in y. */
if (y[i + 1] < 0.0)
nsh = 0;
else
nsh = 1;
if (nsh ^ sh)
{
dy = y[i + 1] - y[i];
if (ABS(dy) >= RAYEPS)
{
dx = x[i + 1] - x[i];
xint = x[i] - y[i]*dx / dy;
if (xint > 0.0)
toright++;
}
}
sh = nsh;
}
if (toright%2 == 1)
{
IsectAdd(hit, tval, pe);
return (1);
}
else
return (0);
}
/*
* NAME
* PolyIntersect - call polygon object intersection routine
*
* SYNOPSIS
* INT PolyIntersect(pr, po, hit)
* RAY *pr; // Ptr to incident ray.
* OBJECT *po; // Ptr to polygon object.
* IRECORD *hit; // Intersection record.
*
* RETURNS
* The number of intersections found.
*/
INT PolyIntersect(RAY *pr, OBJECT *po, IRECORD *hit)
{
INT i;
INT nhits; /* # hits in polyhedra. */
ELEMENT *pe; /* Ptr to polygon element. */
IRECORD newhit; /* Hit list. */
/* Traverse polygon list to find intersections. */
nhits = 0;
pe = po->pelem;
hit[0].t = HUGE_REAL;
for (i = 0; i < po->numelements; i++)
{
if (PolyPeIntersect(pr, pe, &newhit))
{
nhits++;
if (newhit.t < hit[0].t)
{
hit[0].t = newhit.t;
hit[0].pelem = newhit.pelem;
}
}
pe++;
}
return (nhits);
}
/*
* NAME
* PolyTransform - transform polygon object by a transformation matrix
*
* SYNOPSIS
* VOID PolyTransform(po, xtrans, xinvT)
* OBJECT *po; // Ptr to polygon object.
* MATRIX xtrans; // Transformation matrix.
* MATRIX xinvT; // Transpose of inverse matrix.
*
* NOTES
* Routine must:
* - transform face normals
* - transform vertices
* - calculate plane equation d variables
*
* RETURNS
* Nothing.
*/
VOID PolyTransform(OBJECT *po, MATRIX xtrans, MATRIX xinvT)
{
INT i; /* Indices. */
INT numelems; /* # of elements. */
VEC3 *vptr, *vp; /* Vertex list pointers. */
VEC4 norm, coord; /* Transform 4 vectors. */
POLY *pp; /* Ptr to polygon data. */
ELEMENT *pe; /* Ptr to polygon element. */
pe = po->pelem;
numelems = po->numelements;
/* Get vertex list address and transform vertices. */
pp = (POLY *)pe->data;
vptr = pp->vptr;
coord[0] = (*vptr)[0];
coord[1] = (*vptr)[1];
coord[2] = (*vptr)[2];
coord[3] = 1.0;
while (coord[0] != HUGE_REAL && coord[1] != HUGE_REAL && coord[2] != HUGE_REAL)
{
/* Transform coordinate by xform matrix. */
VecMatMult(coord, xtrans, coord);
(*vptr)[0] = coord[0];
(*vptr)[1] = coord[1];
(*vptr)[2] = coord[2];
vptr++;
coord[0] = (*vptr)[0];
coord[1] = (*vptr)[1];
coord[2] = (*vptr)[2];
coord[3] = 1.0;
}
/* Transform polygon list. */
for (i = 0; i < numelems; i++)
{
pp = (POLY *)pe->data;
/* Transform face normal by view matrix inverse. */
norm[0] = pp->norm[0];
norm[1] = pp->norm[1];
norm[2] = pp->norm[2];
norm[3] = 0.0;
VecMatMult(norm, xinvT, norm);
VecNorm(norm);
pp->norm[0] = norm[0];
pp->norm[1] = norm[1];
pp->norm[2] = norm[2];
/* Calculate plane equation variable d. */
vp = pp->vptr + *(pp->vindex);
pp->d = -(pp->norm[0]*(*vp)[0] + pp->norm[1]*(*vp)[1] + pp->norm[2]*(*vp)[2]);
/* Set best axis projection. */
norm[0] = ABS(pp->norm[0]);
norm[1] = ABS(pp->norm[1]);
norm[2] = ABS(pp->norm[2]);
if (norm[0] >= norm[1] && norm[0] >= norm[2])
pp->axis_proj = X_AXIS;
else
if (norm[1] >= norm[0] && norm[1] >= norm[2])
pp->axis_proj = Y_AXIS;
else
pp->axis_proj = Z_AXIS;
pe++;
}
}
/*
* NAME
* PolyRead - read polygon object data from file
*
* SYNOPSIS
* VOID PolyRead(po, pf)
* OBJECT *po; // Ptr to polygon object.
* FILE *pf; // Ptr to file.
*
* RETURNS
* Nothing.
*/
VOID PolyRead(OBJECT *po, FILE *pf)
{
INT i, j; /* Indices. */
INT instat; /* Read status. */
INT *vindex;
INT totalverts; /* Total # of vertices in poly mesh. */
CHAR normstr[5]; /* Face/vertex normal flag string. */
BOOL pnormals; /* Face normals present? */
VEC3 pnorm; /* Polygon normal accumulator. */
VEC3 *vlist, *vptr, *vp; /* Ptr to vertex list. */
VEC3 *vptmp, *vptmp2; /* Ptr to vertex list. */
VEC3 tmppnt, tmppnt2, cross;
POLY *pp; /* Ptr to polygon data. */
ELEMENT *pe; /* Ptr to polygon element. */
pe = po->pelem;
/* Allocate space for object data. */
instat = fscanf(pf, "%ld", &totalverts);
if (instat != 1)
{
printf("Error in PolyRead: totalverts.\n");
exit(-1);
}
pp = GlobalMalloc(sizeof(POLY)*po->numelements, "poly.c");
vlist = GlobalMalloc(sizeof(VEC3)*(totalverts + 1), "poly.c");
vptr = vlist;
/* Are polygon face normals supplied? */
instat = fscanf(pf, "%s\n", normstr);
if (instat != 1)
{
printf("Error in PolyRead: face normal indicator.\n");
exit(-1);
}
pnormals = (normstr[2] == 'y' ? TRUE : FALSE);
/* Read vertex list. */
for (i = 0; i < totalverts; i++)
{
instat = fscanf(pf, "%lf %lf %lf", &(*vptr)[0], &(*vptr)[1], &(*vptr)[2]);
if (instat != 3)
{
printf("Error in PolyRead: vertex %ld.\n", i);
exit(-1);
}
vptr++;
}
(*vptr)[0] = HUGE_REAL;
(*vptr)[1] = HUGE_REAL;
(*vptr)[2] = HUGE_REAL;
/* Read polygon list. */
for (i = 0; i < po->numelements; i++)
{
instat = fscanf(pf, "%ld", &(pp->nverts));
if (instat != 1)
{
printf("Error in PolyRead: vertex count.\n");
exit(-1);
}
if (pp->nverts > MAX_VERTS)
{
printf("Polygon vertex count, %ld, exceeds maximum.\n", pp->nverts);
exit(-1);
}
if (pnormals)
{
instat = fscanf(pf, " %lf %lf %lf", &(pp->norm[0]), &(pp->norm[1]), &(pp->norm[2]));
if (instat != 3)
{
printf("Error in PolyRead: face normal %ld.\n", i);
exit(-1);
}
}
pp->vptr = vlist;
pp->vindex = GlobalMalloc(sizeof(INT)*pp->nverts, "poly.c");
vindex = pp->vindex;
for (j = 0; j < pp->nverts; j++)
{
instat = fscanf(pf, "%ld", vindex++);
if (instat != 1)
{
printf("Error in PolyRead: vertex index %ld.\n", i);
exit(-1);
}
}
/* If not supplied, calculate plane normal. */
vindex = pp->vindex;
vptr = vlist;
if (!pnormals)
{
vp = vptr + (*vindex);
VecZero(pnorm);
for (j = 0; j < pp->nverts - 2; j++)
{
vptmp = vptr + (*(vindex + 1));
vptmp2 = vptr + (*(vindex + 2));
VecSub(tmppnt, (*vptmp), (*vp));
VecSub(tmppnt2, (*vptmp2), (*vptmp));
VecCross(cross, tmppnt, tmppnt2);
VecAdd(pnorm, pnorm, cross);
vp = vptmp;
vindex += 1;
}
VecSub(tmppnt, (*vptmp2), (*vp));
vindex = pp->vindex;
vp = vptr + (*vindex);
VecSub(tmppnt2, (*vp), (*vptmp2));
VecCross(cross, tmppnt, tmppnt2);
VecAdd(pnorm, pnorm, cross);
vp = vptr + (*vindex);
VecSub(tmppnt, (*vp), (*vptmp2));
vptmp = vptr + (*(vindex + 1));
VecSub(tmppnt2, (*vptmp), (*vp));
VecCross(cross, tmppnt, tmppnt2);
VecAdd(pnorm, pnorm, cross);
VecScale(pp->norm, 1.0/VecLen(pnorm), pnorm);
}
/* Calculate plane equation d. */
vp = pp->vptr + *(pp->vindex);
pp->d = -(pp->norm[0]*(*vp)[0] + pp->norm[1]*(*vp)[1] + pp->norm[2]*(*vp)[2]);
pe->data = (CHAR *)pp;
pe->parent = po;
PolyElementBoundBox(pe, pp);
pp++;
pe++;
}
}