#include #include "mytypes.h" #include "scrnio.h" #include "bezpt.h" #include "revolve.h" #include "control.h" #include "poly.h" #include "readilbm.h" #include "menuexp.h" bool SpecOn = false; /* specular lighting enable - default off */ float Ambience = DefAmbience; float PtIntensity = (float)DefIntensity; float Kd = DefKd, Ks = DefKs; Pt3 LightSrc = { DefLightSrcX, DefLightSrcY, DefLightSrcZ }; static Rhomboid *polylist = null, *nextpoly; MapRhomboid *mpolylist = null, *mnextpoly; static int polyspace = 0; static bool shadeflag; long CalcMaxPolyNum() { return( GetNumSegs() * BezMesh * RevMesh ); } static bool PrepPoly() { if( polylist ) free( (char *)polylist ); polylist = (Rhomboid *)malloc( CalcMaxPolyNum() * sizeof(Rhomboid)); if( !polylist ) { OutErr("PrepPoly: not enough memory"); return( true ); } nextpoly = polylist; return(false); /* success = 0 */ } static bool PrepMPoly() { if( mpolylist ) free( (char *)mpolylist ); mpolylist = (MapRhomboid *) malloc( CalcMaxPolyNum() * sizeof(MapRhomboid)); if( !mpolylist ) { OutErr("PrepPoly: not enough memory"); return( true ); } mnextpoly = mpolylist; return(false); /* success = 0 */ } /* * Multiply a vector by scalar quantity */ void ScaleVec( fact, src, dst ) float fact; Pt3 *src, *dst; { dst->x = src->x * fact; dst->y = src->y * fact; dst->z = src->z * fact; } /* * convert a vector to a unitized vector * if possible */ void Unitize( vec ) Pt3 *vec; { float len; len = vec->x*vec->x + vec->y*vec->y + vec->z*vec->z; len = sqrt( len ); if( len != 0.0 ) { vec->x /= len; vec->y /= len; vec->z /= len; } } /* * calculate a vector from two points */ void CalcVector( src1, src2, dest ) Pt3 *src1, *src2, *dest ; { dest->x = src1->x - src2->x; dest->y = src1->y - src2->y; dest->z = src1->z - src2->z; } /* * calculate a normal from a list of polygons. This routine does the * logical trick of trying to exclude each point in turn if the * normal can not be calculated, or something of the sort. * a value of true is returned if a normal with a nonzero z component * could not be calculated */ bool CalcNormal( vxlist, normal) PtGen *vxlist[]; register Pt3 *normal; { int i, k, m; Pt3 *j[3]; Pt3 v1, v2; for( i = 0; i < RhomVxNum; i++ ) { for( k = 0, m = 3; m--; k++ ) { if( k == i ) { k++; } j[m] = &vxlist[k]->d3; } CalcVector( j[1], j[0], &v1 ); CalcVector( j[2], j[1], &v2 ); normal->z = v1.x*v2.y - v1.y*v2.x; if( normal->z == 0 ) { continue; } normal->x = v1.y*v2.z - v1.z*v2.y; normal->y = v1.z*v2.x - v1.x*v2.z; if( normal->z < 0 ) { normal->x = -normal->x; normal->y = -normal->y; normal->z = -normal->z; } Unitize(normal); return( false ); } return(true); } /* * Euclidean dot product. * I wonder what the minkowski dot product would look like */ float DotProd( v1, v2 ) Pt3 *v1, *v2; { return( v1->x*v2->x + v1->y*v2->y + v1->z*v2->z ); } /* * define a polygon as a set of four points * returns true if polygon created */ static bool CreatePoly(curpoly, p0, p1, p2, p3) register Rhomboid *curpoly; PtGen *p0, *p1, *p2, *p3; { Pt3 normal; PtGen *list[RhomVxNum]; list[0] = p0; list[1] = p1; list[2] = p2; list[3] = p3; /* * compute stuff needed only if producing shaded image */ if( shadeflag ) { Pt3 lvec; Pt3 center; float ptintens; float ldotn; /* light vector dot normal */ /* * if cant compute normal, then junk polygon */ if( CalcNormal( list, &normal )) { return(false); } curpoly->intensity = Ambience; center.x = ( list[0]->d3.x + list[1]->d3.x + list[2]->d3.x + list[3]->d3.x)/4.0; center.y = ( list[0]->d3.y + list[1]->d3.y + list[2]->d3.y + list[3]->d3.y)/4.0; center.z = ( list[0]->d3.z + list[1]->d3.z + list[2]->d3.z + list[3]->d3.z)/4.0; curpoly->depth = center.z; CalcVector( ¢er, &LightSrc, &lvec ); Unitize( &lvec ); ldotn = DotProd( &lvec, &normal ); if( ldotn < 0 ) { ptintens = PtIntensity * Kd * -ldotn; curpoly->intensity += ptintens; } /* * calculate specular component */ if( SpecOn && ldotn < 0 ) { float Kspec, Is; Pt3 rvec; /* lvec reflected through poly */ ScaleVec( 2*ldotn, &normal, &rvec ); CalcVector(&lvec, &rvec, &rvec ); Unitize( ¢er ); Kspec = DotProd( &rvec, ¢er); if( Kspec <= 0.0 ) { Is = Ks * Kspec * Kspec* PtIntensity; curpoly->intensity += Is; } } if( curpoly->intensity > 1.0 ) { curpoly->intensity = 1.0; } } else { /* * calculate depth of polygon * for now, try an average of the vertex depths */ curpoly->depth =( list[0]->d3.z + list[1]->d3.z + list[2]->d3.z + list[3]->d3.z)/4.0; } /* * store index to screen coordinates */ curpoly->pt[0] = p0->d2; curpoly->pt[1] = p1->d2; curpoly->pt[2] = p2->d2; curpoly->pt[3] = p3->d2; return(true); } /* * passable procedure for creating polygons without mapping */ static void AcceptPoly(p0, p1, p2, p3) PtGen *p0, *p1, *p2, *p3; { if( CreatePoly(nextpoly, p0, p1, p2,p3)) { nextpoly++; } } static void AcceptMPoly( p0, p1, p2, p3) PtGen *p0, *p1, *p2, *p3; { if( CreatePoly(&mnextpoly->rhom, p0, p1, p2,p3)) { mnextpoly->bezindex = RevImageB; mnextpoly->revindex = RevImageR; mnextpoly++; } } /* * compare the depth of two polygons for SortPoly */ static int CmpDepth( a, b ) Rhomboid *a, *b; { if( a->depth < b->depth ) return(-1); else if( a->depth > b->depth ) return(1); else return(0); } static int CmpMDepth( a, b ) MapRhomboid *a, *b; { if( a->rhom.depth < b->rhom.depth ) return(-1); else if( a->rhom.depth > b->rhom.depth ) return(1); else return(0); } void RevNoShade() { Rhomboid *i; if( GetNumSegs() < 1 ) { return; } ClrAbort(); shadeflag = false; if( PrepPoly() ) return; if( Revolve(AcceptPoly) ) return; CurMode = NOTACTIVE; qsort( (char *)polylist, nextpoly - polylist, sizeof(Rhomboid), CmpDepth); ClrWindow(false); for( i = polylist; i< nextpoly; i++ ) { if( AbortDraw ) return; DrawRhomFrame( i->pt ); } } void RevShade() { register Rhomboid *i; if( !AllocDither()) return; /* not enough memory */ if( GetNumSegs() < 1 ) { return; } CurMode = NOTACTIVE; ClrAbort(); shadeflag = true; if( PrepPoly() || Revolve(AcceptPoly) ) { return; } qsort( (char *)polylist, nextpoly-polylist, sizeof(Rhomboid), CmpDepth); ClrWindow(false); for( i = polylist; i< nextpoly; i++ ) { if( AbortDraw ) return; DrawRhomShade( i ); } } void RevMap() { register MapRhomboid *i; ClrAbort(); if( GetNumSegs() < 1 ) { return; } if( InitMapping() ) { return; } CurMode = NOTACTIVE; shadeflag = true; if( PrepMPoly() || Revolve(AcceptMPoly) ) { return; } qsort( (char *)mpolylist, mnextpoly-mpolylist, sizeof(MapRhomboid), CmpMDepth); ClrWindow(false); for( i = mpolylist; i< mnextpoly; i++ ) { if( AbortDraw ) return; DrawRhomMap(i); } }