ftp.nice.ch/pub/next/graphics/3d/geomview.1.4.1.s.tar.gz#/Geomview/src/lib/mg/ri/mgridraw.c

This is mgridraw.c in view mode; [Download] [Up]

#include "mgP.h"
#include "mgriP.h"
#include "polylistP.h"

#include <stdlib.h>

void	mgri_polygon( int nv, HPoint3 *v, int nn, Point3 *n,
	      	          int nc,ColorA *c );
void	mgri_mesh( int wrap,int nu,int nv,HPoint3 *p, Point3 *n,ColorA *c );
void	mgri_line( HPoint3 *p1, HPoint3 *p2 );
void	mgri_polyline( int nv, HPoint3 *verts, int nc, ColorA *colors,
				int wrapped );
void	mgri_polylist(  int np, Poly *p, int nv, Vertex *v, 
			     int plflags );
void	mgri_drawnormal(HPoint3 *p, Point3 *n, Color* c);

void    mgri_drawPline(HPoint3 *p1, HPoint3 *p2);
			 

/*-----------------------------------------------------------------------
 * Function:	mgri_polygon
 * Description:	draw a polygon
 * Author:	wisdom
 * Date:	Fri Jan 10 13:57:53 CST 1992
 * Notes:	See mg.doc.
 *
 */
void
mgri_polygon(int nv,  HPoint3 *V, 
	     int nn,  Point3 *N, 
	     int nc,  ColorA *C)
{
  register int i, j;	
  register HPoint3 *v;
  register Point3 *n;
  register Color *c;
  register ColorA *c4;
  HPoint3 hpt;
  int flag;
  int shading;
  int ninc;
  short colorsdefined;
  short normalsdefined;
  short attrblock = 0;

    flag = _mgc->astk->ap.flag;
    if ((_mgc->astk->mat.override & MTF_DIFFUSE) && !_mgc->astk->useshader)
	nc = 0;
    
    shading = _mgc->astk->ap.shading;
    ninc = (nn > 1);
    
    if(nc == 0) {
      C = (ColorA*)&_mgc->astk->ap.mat->diffuse;
    }

    CHECK_VCN(nv,nc,nn); /* check nv,nc,nn for overflow */
    
    /* Process input into a form renderman likes */
    
    
    /* Points */ 
    /* NOTE: although ri reference states that points may be described   */
    /* with a 4-vector (x,y,z,w) ala the "Pw" token, I can't seem to get */
    /* it to work with either Photorealistic or Quick Renderman. sw      */
    if(nv>0)
	for(i = 0; i < nv; i++) mgri_normalize(&V[i], ript[i]);

    if(flag & APF_FACEDRAW) {
    	/* RGB Color */
	if (nc>0) {
	    if(nc==1) {
		RiAttributeBegin();
		attrblock=1;
		RiColor(C);
		colorsdefined = 0;
	    } else for(i = 0; i < nv; i++) {
		*(Color *)&ricolor[i] = *(Color *)&C[i];
		colorsdefined = 1;
	    }
	} else colorsdefined = 0;
    
	/* Opacity is not supported by QRMan, so it is not handled here */
	
	/* Normals - do not supply with flat shading (constant */
	/* interpolation) as this seems to confuse QRMAN       */
	normalsdefined = 0;
	if(shading!=APF_FLAT && shading!=APF_CONSTANT && nn>0) {
	    for(i = 0; i < nv; i++) {
		if(nn>1) *(Point3 *)&rinormal[i] = N[i];
		else bcopy((char *)N, (char *)rinormal[i], sizeof(float)*3);
	    }
	    normalsdefined = 1;
	}
		
	/* Define the polygon via the renderman interface */
	if(!colorsdefined && normalsdefined)
	    RiPolygon(nv, RI_P, (RtPointer)ript, RI_N, (RtPointer)rinormal,
	    	      RI_NULL);
	else if(colorsdefined && !normalsdefined)
	    RiPolygon(nv, RI_P, (RtPointer)ript, RI_CS, (RtPointer)ricolor,
	    	      RI_NULL);
	else if(!colorsdefined && !normalsdefined)
	    RiPolygon(nv, RI_P, (RtPointer)ript, RI_NULL);
	else RiPolygon(nv, RI_P, (RtPointer)ript, RI_CS, (RtPointer)ricolor,
	    RI_N, (RtPointer)rinormal, RI_NULL);
    }
    
    /* Draw Edges */
    if(flag & APF_EDGEDRAW) {
	Transform newbie;
	float dis;
	c = &_mgc->astk->ap.mat->edgecolor;
	RiAttributeBegin();

	/* translate object slightly closer to camera */
	mgri_closer();
				
	/* now draw it */
	RiColor((float *)c);
	RiGeometricRepresentation("lines");
	RiPolygon(nv, RI_P, (RtPointer)ript, RI_NULL);
	RiAttributeEnd();
    }
    
    /* Draw Normals */
    if(flag & APF_NORMALDRAW) {
    Color *color = &_mgc->astk->mat.normalcolor;
    RiAttributeBegin();
    RiSurface(RI_CONSTANT, RI_NULL);
    RiColor((float *)color);
    for (n = N, v = V, i = 0; i<nv; ++i, ++v, n += ninc)
	mgri_drawnormal(v, n, color);
    RiAttributeEnd();
    }
    
    if(attrblock) RiAttributeEnd();
}

/*-----------------------------------------------------------------------
 * Function:	mgri_line
 * Description:	draws a line
 * Author:	wisdom
 * Date:	Fri Jan 17 14:31:06 CST 1992
 * Notes:	see mg.doc
 */
void mgri_line( HPoint3 *p1, HPoint3 *p2)
{
    /* lines in QuickRenderman inherit surface properties. */
    /* we make sure they are drawn with a constant surface */
    RiAttributeBegin();
    RiSurface(RI_CONSTANT, RI_NULL);
    mgri_drawline(p1,p2,&_mgc->astk->mat.edgecolor);
    RiAttributeEnd();
}

/* following passes lines through rman interface */
void mgri_plflush(void)
{
    RiAttributeBegin();

    RiShadingInterpolation(RI_SMOOTH); /* hack to color lines correctly */
    RiSurface(RI_CONSTANT, RI_NULL);
    RiPointsLines(_mgric->plni, (RtPointer)plvca, (RtPointer)plvia,
	RI_P, (RtPointer)plp, RI_CS, (RtPointer)plc, RI_NULL);

    RiAttributeEnd();

    _mgric->plni = 0;
    _mgric->plvi = 0;
}

/*-----------------------------------------------------------------------
 * Function:	mgri_polyline
 * Description:	draws a Polyline
 * Author:	wisdom
 * Date:	Fri Nov  5 14:29:45 CST 1993
 * Notes:	see mg.doc
 *		Feeding too many verticees into the QRMAN 3.0 interface
 *		can cause bad window server crashes. To avoid this,
 *		all geometry is chunked into smaller pieces. No
 *		sharing of verticees is done because there is no 'master
 *		array' of verticees to facilitate this - this array is
 *		broken down. So, we copy and assign verticees as needed.
 *		In addition to breaking geometry down, this routine will
 *		buffer smaller and individual geometry, avoiding a QRMAN
 *		interface call until absolutely needed. This provides better
 *		performance than multiple QRMAN interface calls.
 *	        NOTE: This will be re-written to take full advantage of
 *		NS3.1 or greater
 */
void mgri_polyline( int nv, HPoint3 *V, int nc, ColorA *C, int flags )
{
    int i;
    ColorA *color;
    short colorsdefined = 0;
    RtColor wrapcolor[2];
    RtPoint wrappoint[2];
    int wrapped = flags & 1;
    Color *basecolor;
    short baseinc;

//    if(_mgric->plvi+nv > PLBUFFSIZE) {
//        /* We need to flush the buffers */    
//	mgri_plflush();
//    }
    
    if(_mgc->astk->mat.override & MTF_EDGECOLOR)
	nc = 0;

    if(nc==0) {
	basecolor = (Color *)&_mgc->astk->mat.edgecolor;
	baseinc = 0;
    } else if(nc==1) {
	basecolor = (Color *)&C[0];
	baseinc = 0;
    } else {
	basecolor = (Color *)&C[0];
	baseinc = 1;
    }

    /* process points */

    if(nv>1) {
	for(i = 0; i < nv-1; i++) {
	    plvca[_mgric->plni++] = 2;
	    plvia[_mgric->plvi] = _mgric->plvi;
	    plvia[_mgric->plvi+1] = _mgric->plvi+1;
	    mgri_normalize(&V[i], plp[_mgric->plvi]);
	    mgri_normalize(&V[i+1], plp[_mgric->plvi+1]);
	    *(Color *)&plc[_mgric->plvi] = *(Color *)basecolor;
	    *(Color *)&plc[_mgric->plvi+1] = *(Color *)(basecolor+baseinc);
	    _mgric->plvi+=2;
	    basecolor += baseinc;
	    if(_mgric->plvi> _mgric->plbuffsize) mgri_plflush();
	}
	plvca[_mgric->plni++] = 2;
	plvia[_mgric->plvi] = _mgric->plvi;
	plvia[_mgric->plvi+1] = _mgric->plvi+1;
	mgri_normalize(&V[i-1], plp[_mgric->plvi]);
	mgri_normalize(&V[i], plp[_mgric->plvi+1]);
	*(Color *)&plc[_mgric->plvi] = *(Color *)basecolor;
	*(Color *)&plc[_mgric->plvi+1] = *(Color *)(basecolor+baseinc);
	_mgric->plvi+=2;
	basecolor += baseinc;	
    }
   
    if(nv==1) {
    	/* This is a single point. Notice that we do not define the
	*  vertex only once. Tests indicate that color is not propperly
	*  assigned to a point if only a single vertex is used to define
	*  it. However, two equal verticees appears to overcome this
	*  potential problem.
	*/
	plvca[_mgric->plni] = 2;
	plvia[_mgric->plvi] = _mgric->plvi;
	plvia[_mgric->plvi+1] = _mgric->plvi+1;
	mgri_normalize(&V[0], plp[_mgric->plvi]);
	*(Point3 *)&plp[_mgric->plvi+1] = *(Point3 *)&plp[_mgric->plvi];
	/* mgri_normalize(&V[0], plp[_mgric->plvi+1]); */
	*(Color *)&plc[_mgric->plvi] = *(Color *)basecolor;
	*(Color *)&plc[_mgric->plvi+1] = *(Color *)basecolor;
	_mgric->plni++;
	_mgric->plvi+=2;
	if(_mgric->plvi> _mgric->plbuffsize) mgri_plflush();
    } 

    else if(wrapped) {
        plvca[_mgric->plni] = 2;
	plvia[_mgric->plvi] = _mgric->plvi;
	plvia[_mgric->plvi+1] = _mgric->plvi+1;
	mgri_normalize(&V[0], plp[_mgric->plvi]);
	mgri_normalize(&V[nv-1], plp[_mgric->plvi+1])
	*(Color *)&plc[_mgric->plvi] = *(Color *)basecolor;
	*(Color *)&plc[_mgric->plvi+1] = *(Color *)basecolor;
	_mgric->plni++;
	_mgric->plvi+=2;
	if(_mgric->plvi > _mgric->plbuffsize) mgri_plflush();
    }
}


/*-----------------------------------------------------------------------
 * Function:	mgri_polylist
 * Description:	draws a Polylist: linked list of Polys
 * Author:	wisdom
 * Date:	Fri Nov  5 14:32:04 CST 1993
 * Notes:
 * mgri_polylist provides three primary methods to draw polyhedra:
 * Currently, number 3 is used.
 *	1. Seperate Polygons
 *	   _mgric->polymode == MGRI_POLYGONS (OBSOLETE)
 *		Advantage: Colors and Normals can be properly utilized.
 * 		Also, MUCH less likely to crash the Windowserver.
 *		Disadvantage: *SLOW*
 *	2. (single/multiple) RiPointsPolygons call(s)
 *	   _mgric->polymode == MGRI_POINTSPOLYGONS
 *		Advantage: An order of magnitude faster for large polyhedra.
 *		Disadvantage: VERY unstable(NS3.0), but some failsafes are set
 *		by default (via the context). When QRMan matures, all
 *		safegaurds should be removed. Also, per polygon normals cannot
 *		be realized by RiPointsPolygons so QRMan computes vertex
 *		normals.
 *     3. Devided Polylist
 *        _mgric->polymode == MGRI_DEVIDEDPOLYLIST
 *	        The geometry is broken into peices, and fed one piece
 *		at a time through the QRMan interface.
 *
 */
void mgri_polylist( int np, Poly *P, int nv, Vertex *V, int plflags )
{
  register int i,j;
  register Poly *p;
  register Vertex **v, *vp;
  register Point3 *n;
  HPoint3 hpt;
  int flag,shading;
  Color *color;
  ColorA *colorA;
  int colorsdefined;
  int normalsdefined;
  int nc = nv;
  int nn = nv;
  int nvert;
  int ppi; //points polygon index
  int pvi; //points vertex index
  
  static int first = 0;  

    flag = _mgc->astk->ap.flag;
    shading = _mgc->astk->ap.shading;

/*
    if (shading & APF_CONSTANT) plflags &= ~(PL_HASVN|PL_HASPN);
    else if (shading & APF_FLAT) plflags &= ~PL_HASVN;
    else if (shading & APF_SMOOTH) plflags &= ~PL_HASPN;
*/


//Following was added at the last second in attempt to make
//overide work. I guess this has changed, I'm not sure if this
//sniglet from the gl code is all that is needed

  switch(shading) {
  case APF_FLAT: plflags &= ~PL_HASVN; break;
  case APF_SMOOTH: plflags &= ~PL_HASPN; break;
  default: plflags &= ~(PL_HASVN|PL_HASPN); break;
  }

  if ((_mgc->astk->mat.override & MTF_DIFFUSE) && !_mgc->astk->useshader) 
    plflags &= ~(PL_HASVCOL | PL_HASPCOL);

    CHECK_VCN(nv,nv,nn);
    
    if(_mgric->polymode == MGRI_POLYGONS) {
	
	if (flag & APF_FACEDRAW) {
	    RiAttributeBegin();
	    for (p = P, i = 0; i < np; i++, p++) {
	    
		/* per polygon color */
		if (plflags & PL_HASPCOL)
		    RiColor((float *)&p->pcol);
		
		/* Points */
		for (j=0, v=p->v; j < p->n_vertices; j++, v++) {
		    mgri_normalize(&(*v)->pt, ript[j]);
		}
				
		/* colors, if supplied */
		if(plflags & PL_HASVCOL) {
		    for (j=0, v=p->v; j < p->n_vertices; j++, v++)
			*(Color *)&ricolor[j] = *(Color *)&(*v)->vcol;
		    colorsdefined=1;
		}
		else colorsdefined=0;
		
		/* Opacity is not yet supported by Quick Renderman */
		
		/* Normals - do not supply with flat shading (constant */
		/* interpolation) as this seems to confuse QRMAN       */
		normalsdefined=0;
		if(shading!=APF_FLAT) {
		    if(plflags & PL_HASVN) {
			for (j=0, v=p->v; j < p->n_vertices; j++, v++)
			    *(Point3 *)&rinormal[j] = (*v)->vn;
			normalsdefined=1;
		    } else if(plflags & PL_HASPN) {
			for(j=0, v=p->v; j< p->n_vertices; j++, v++)
			    *(Point3 *)&rinormal[j] = p->pn;
			normalsdefined=1;
		    }
		}
		
		/* Define the polygon via the renderman interface */
		if(!colorsdefined && normalsdefined)
		    RiPolygon(p->n_vertices, RI_P, (RtPointer)ript, RI_N,
			    (RtPointer)rinormal, RI_NULL);
		else if(colorsdefined && !normalsdefined)
		    RiPolygon(p->n_vertices, RI_P, (RtPointer)ript, RI_CS,
			    (RtPointer)ricolor, RI_NULL);
		else if(!colorsdefined && !normalsdefined)
		    RiPolygon(p->n_vertices, RI_P, (RtPointer)ript, RI_NULL);
		else RiPolygon(p->n_vertices, RI_P, (RtPointer)ript, RI_CS, 
		    (RtPointer)ricolor, RI_N, (RtPointer)rinormal, RI_NULL);
		
	    } /* for */
	    
	    RiAttributeEnd();
	    
	} /* APF_FACEDRAW */ 
    
	if (flag & APF_EDGEDRAW) {
	    color = &_mgc->astk->ap.mat->edgecolor;
	    RiAttributeBegin();
	    RiSurface(RI_CONSTANT, RI_NULL);
	    RiColor((float *)color);
	    
	    mgri_closer();
	    
	    /* the following can be made MUCH more efficient */
	    /* if we buffer groups of points (polygons) and  */
	    /* draw all at once.                             */
	    for (p = P, i = 0; i < np; i++, p++) {	
		for (j=0, v=p->v; j < (p->n_vertices-1); j++, v++)
		    mgri_drawline((HPoint3 *)*v,(HPoint3 *)*(v+1),color);
		mgri_drawline((HPoint3 *)*v,(HPoint3 *)*(p->v),color);
	    }
	    RiAttributeEnd();
	} /* APF_EDGEDRAW */
    
    } /* MGRI_POLYGONS */
    
    else if(_mgric->polymode == MGRI_POINTSPOLYGONS) {
      
	/* normalize all verticies (colors) */
	if(plflags & PL_HASVCOL) {
	    for(i=0, vp=V; i<nv; i++, vp++) {
		mgri_normalize(&(vp->pt), ript[i]);
		//*(Color *)&ricolor[i] = *(Color *)&(vp->vcol);
	    }
	}
	else
	for(i=0,vp=V; i<nv; i++, vp++) mgri_normalize(&(vp->pt), ript[i]);
    
	/* check for rippi overflow */
	if(np>rippis) {
	    rippis = np + 500;
	    rippi = (int *)realloc(rippi, rippis*sizeof(int));
	}
	    
	ppi = pvi = 0;
	
	if(flag & APF_FACEDRAW) {
	    for(p = P, i=0; i < np; i++, p++, ppi++) {
		int nvert = p->n_vertices;
		
		if(ppi >= _mgric->fflushlimit) {
		    RiPointsPolygons(ppi, rippi, ripvi, RI_P, ript, RI_CS, ricolor, RI_NULL);
		    ppi = pvi = 0;
		}
		rippi[ppi] = nvert;
		/* check for ripvi overflow */
		if(nvert+pvi > ripvis) {
		    ripvis = nvert + pvi + 500;
		    ripvi = (int *)realloc(ripvi, ripvis*sizeof(int));
		}
		if(plflags & PL_HASPCOL) {
		    for(j=0, v=p->v; j < nvert; j++, v++, pvi++) {
			ripvi[pvi] = (*v) - V;
			*(Color *)&ricolor[pvi] = *(Color *)&(p->pcol);
		    }
		} else {
		    for(j=0, v=p->v; j < nvert; j++, v++, pvi++) {
			ripvi[pvi] = (*v) - V; /* int index into vertex list */
			*(Color *)&ricolor[pvi] = *(Color *)&(*v)->vcol; /* already done */
		    }
		}
		
	    } /* for */
	    
	    RiPointsPolygons(ppi, rippi, ripvi, RI_P, ript, RI_CS, ricolor, RI_NULL);
    
	} /* APF_FACEDRAW */
    
	ppi = pvi = 0;
    
	if(flag & APF_EDGEDRAW) {
	    RiAttributeBegin();
	    RiGeometricRepresentation(RI_LINES);
	    RiColor((float *)&_mgc->astk->mat.edgecolor);
	    for(p = P, i=0; i < np; i++, p++, ppi++) {
		int nvert = p->n_vertices;
		
		if(ppi > _mgric->lflushlimit) {
		    RiPointsPolygons(ppi, rippi, ripvi, RI_P, ript, RI_NULL);
		    ppi = pvi = 0;
		}
		rippi[ppi] = nvert;
		/* check for ripvi overflow */
		if(nvert+pvi > ripvis) {
		    ripvis = nvert + pvi + 500;
		    ripvi = (int *)realloc(ripvi, ripvis*sizeof(int));
		}
		if(plflags & PL_HASPCOL) {
		    for(j=0, v=p->v; j < nvert; j++, v++, pvi++) {
			ripvi[pvi] = (*v) - V;
		    }
		} else {
		    for(j=0, v=p->v; j < nvert; j++, v++, pvi++) {
			ripvi[pvi] = (*v) - V;
			*(Color *)&ricolor[i] = *(Color *)&(*v)->vcol; //already done		
		    }
		}
		
	    } /* for */
	    
	    RiPointsPolygons(ppi, rippi, ripvi, RI_P, ript, RI_NULL);
	    
	    RiAttributeEnd();
	    
	} /* APF_EDGEDRAW */

    } /* MGRI_POINTSPOLYGONS */

    else if(_mgric->polymode == MGRI_DEVIDEDPOLYLIST) {
        
	/* create local buffers - these are fixed */
	/* and need not be checked for overflow   */
	static RtPoint gp[GVMAXF+100];  /* vertices */
	static RtPoint gn[GVMAXF+100];  /* normals */
	static RtColor gc[GVMAXF+100];  /* colors */
	static int gvc[GVMAXF];         /* polygon vertex count array */
	static int gvi[GVMAXF+100];     /* vertex index array */ 
	
	/* we will use ript for holding normalized vertices */
	for(i=0,vp=V; i<nv; i++, vp++) mgri_normalize(&(vp->pt), ript[i]);
    
	ppi = pvi = 0;
	
	if(flag & APF_FACEDRAW && plflags & PL_HASVN && plflags & PL_HASPCOL) {
	    for(p = P, i=0; i < np; i++, p++, ppi++) {
		nvert = p->n_vertices;
		
		if(pvi+nvert >= GVMAXF) {
		    RiPointsPolygons(ppi, gvc, gvi, RI_P, gp, RI_N, gn,
			RI_CS, gc, RI_NULL);
		    ppi = pvi = 0;
		}
		gvc[ppi] = nvert;

		for(j=0, v=p->v; j < nvert; j++, v++, pvi++) {
		    gvi[pvi] = pvi;
		    *(Point3 *)&gp[pvi] = *(Point3 *)&ript[((*v) - V)];
		    *(Color *)&gc[pvi] = *(Color *)&(p->pcol);
		    *(Point3 *)&gn[pvi] = *(Point3 *)&((*v)->vn);
		}
		
	    } /* for */
	    
	    RiPointsPolygons(ppi, gvc, gvi, RI_P, gp, RI_N, gn,
		RI_CS, gc, RI_NULL);
    
	}

	else
	if(flag & APF_FACEDRAW && plflags & PL_HASVN && plflags & PL_HASVCOL) {
	    for(p = P, i=0; i < np; i++, p++, ppi++) {
		nvert = p->n_vertices;
		
		if(pvi+nvert >= GVMAXF) {
		    RiPointsPolygons(ppi, gvc, gvi, RI_P, gp,
			RI_N, gn, RI_CS, gc, RI_NULL);
		    ppi = pvi = 0;
		}
		gvc[ppi] = nvert;

		for(j=0, v=p->v; j < nvert; j++, v++, pvi++) {
		    gvi[pvi] = pvi;
		    *(Point3 *)&gp[pvi] = *(Point3 *)&ript[((*v) - V)];
		    *(Point3 *)&gn[pvi] = *(Point3 *)&((*v)->vn);
		    *(Color *)&gc[pvi] = *(Color *)&((*v)->vcol);
		}
		
	    } /* for */
	    
	    RiPointsPolygons(ppi, gvc, gvi, RI_P, gp, RI_N, gn,
		RI_CS, gc, RI_NULL);
    
	}

	else
	if(flag & APF_FACEDRAW && plflags & PL_HASVN) {
	    for(p = P, i=0; i < np; i++, p++, ppi++) {
		nvert = p->n_vertices;
		
		if(pvi+nvert >= GVMAXF) {
		    RiPointsPolygons(ppi, gvc, gvi, RI_P, gp,
			RI_N, gn, RI_NULL);
		    ppi = pvi = 0;
		}
		gvc[ppi] = nvert;

		for(j=0, v=p->v; j < nvert; j++, v++, pvi++) {
		    gvi[pvi] = pvi;
		    *(Point3 *)&gp[pvi] = *(Point3 *)&ript[((*v) - V)];
		    *(Point3 *)&gn[pvi] = *(Point3 *)&((*v)->vn);
		}
		
	    } /* for */
	    
	    RiPointsPolygons(ppi, gvc, gvi, RI_P, gp, RI_N, gn, RI_NULL);
    
	}

 	else
	if(flag & APF_FACEDRAW && plflags & PL_HASPCOL) {
	    for(p = P, i=0; i < np; i++, p++, ppi++) {
		nvert = p->n_vertices;
		
		if(pvi+nvert >= GVMAXF) {
		    RiPointsPolygons(ppi, gvc, gvi, RI_P, gp,
			RI_CS, gc, RI_NULL);
		    ppi = pvi = 0;
		}
		gvc[ppi] = nvert;

		for(j=0, v=p->v; j < nvert; j++, v++, pvi++) {
		    gvi[pvi] = pvi;
		    *(Point3 *)&gp[pvi] = *(Point3 *)&ript[((*v) - V)];
		    *(Color *)&gc[pvi] = *(Color *)&(p->pcol);
		}
		
	    } /* for */
	    
	    RiPointsPolygons(ppi, gvc, gvi, RI_P, gp, RI_CS, gc, RI_NULL);
    
	}

 	else
	if(flag & APF_FACEDRAW && plflags & PL_HASVCOL) {
	    for(p = P, i=0; i < np; i++, p++, ppi++) {
		nvert = p->n_vertices;
		
		if(pvi+nvert >= GVMAXF) {
		    RiPointsPolygons(ppi, gvc, gvi, RI_P, gp,
			RI_CS, gc, RI_NULL);
		    ppi = pvi = 0;
		}
		gvc[ppi] = nvert;

		for(j=0, v=p->v; j < nvert; j++, v++, pvi++) {
		    gvi[pvi] = pvi;
		    *(Point3 *)&gp[pvi] = *(Point3 *)&ript[((*v) - V)];
		    *(Color *)&gc[pvi] = *(Color *)&((*v)->vcol);
		}
		
	    } /* for */
	    
	    RiPointsPolygons(ppi, gvc, gvi, RI_P, gp, RI_CS, gc, RI_NULL);
    
	}

 	else
	if(flag & APF_FACEDRAW) {
	    for(p = P, i=0; i < np; i++, p++, ppi++) {
		nvert = p->n_vertices;
		
		if(pvi+nvert >= GVMAXF) {
		    RiPointsPolygons(ppi, gvc, gvi, RI_P, gp, RI_NULL);
		    ppi = pvi = 0;
		}
		gvc[ppi] = nvert;

		for(j=0, v=p->v; j < nvert; j++, v++, pvi++) {
		    gvi[pvi] = pvi;
		    *(Point3 *)&gp[pvi] = *(Point3 *)&ript[((*v) - V)];
		}
		
	    } /* for */
	    
	    RiPointsPolygons(ppi, gvc, gvi, RI_P, gp, RI_NULL);
    
	}

  
	ppi = pvi = 0;

	if(flag & APF_EDGEDRAW) {
	    RiAttributeBegin();
	    RiGeometricRepresentation(RI_LINES);
	    mgri_closer();
	    
	    color = &_mgc->astk->ap.mat->edgecolor;
	    RiColor((float *)color);

	    for(p = P, i=0; i < np; i++, p++, ppi++) {
		int nvert = p->n_vertices;
		
		if(pvi+nvert >= GVMAXF) {
		    RiPointsPolygons(ppi, gvc, gvi, RI_P, gp, RI_NULL);
		    ppi = pvi = 0;
		}
		gvc[ppi] = nvert;

		for(j=0, v=p->v; j < nvert; j++, v++, pvi++) {
		    gvi[pvi] = pvi;
		    *(Point3 *)&gp[pvi] = *(Point3 *)&ript[((*v) - V)];
		}
		
	    } /* for */
	    
	    RiPointsPolygons(ppi, gvc, gvi, RI_P, gp, RI_NULL);
	    RiAttributeEnd();
	}

    }

    /* polylist methods share a common normal
     * drawing routine, if that's selected. However
     * since MGRI_POINTSPOLYGONS method relies on
     * qrman computing normals, showing these normals
     * in that mode is misleading. Suggestions?
     */
    if (flag & APF_NORMALDRAW) {
	Color *color = &_mgc->astk->mat.normalcolor;
	RiAttributeBegin();
	RiSurface(RI_CONSTANT, RI_NULL);
	RiColor((float *)color);
	if (plflags & PL_HASPN) {
	    for (p = P, i = 0; i < np; i++, p++)
	    for (j=0, v=p->v; j < p->n_vertices; j++, v++)
		mgri_drawnormal(&(*v)->pt, &p->pn, color);
	} else if (plflags & PL_HASVN) {
	    for (vp = V, i = 0; i < nv; i++, vp++) {
		mgri_drawnormal(&vp->pt, &vp->vn, color);
	    }
	}
	RiAttributeEnd();
    }

}

/* There is a basic problem now with 4-d points and 3-d normal vectors.
For now, we'll just ignore the 4-th coordinate of the point when 
computing the tip of the normal vector.  This will work OK with all
existing models, but for genuine 4-d points it won't work.  But,
come to think of it, what is the correct interpretation of the
normal vector when the points live in 4-d?
*/
/* also, there is the fact that this function now requires a color */
void
mgri_drawnormal(HPoint3 *p, Point3 *n, Color *theColor) {	
    HPoint3 scaledn,end, tp;
    float scale;
    
    scale = _mgc->astk->ap.nscale;
    if (p->w < 0.0) return;
    HPt3Normalize(p, &tp);
    Pt3Mul(scale, n, &scaledn);
    scaledn.w = 0.0;
    HPt3Add(&tp, &scaledn, &end);
    
    mgri_drawline(&tp,&end,theColor);
    
}

void
mgri_drawline(HPoint3 *p1, HPoint3 *p2, Color *theColor)
{
    /*
     * Don't call this function directly unless you have set
     * a constant surface, otherwise the line will inherit the
     * current surface attributes.
     */

// following is special case for thick lines
// disabled for now - this doesn't work well
//   if(_mgc->astk->ap.linewidth>1.0)
//	mgri_drawPline(p1, p2);

//following is old way to draw lines
//	mgri_normalize(p1, ript[0]);
//	mgri_normalize(p2, ript[1]);
//	RiLine(2, RI_P, (RtPointer)ript, RI_NULL);

//following is newer FASTER way to draw lines (buffering)
//however, I'm not sure if the colors will work right
	plvca[_mgric->plni++] = 2;
	plvia[_mgric->plvi] = _mgric->plvi;
	plvia[_mgric->plvi+1] = _mgric->plvi+1;
	*(Color *)&plc[_mgric->plvi] = *(Color *)theColor;
	*(Color *)&plc[_mgric->plvi+1] = *(Color *)theColor;
	mgri_normalize(p1, plp[_mgric->plvi]);
	mgri_normalize(p2, plp[_mgric->plvi+1]);
	_mgric->plvi+=2;

	if(_mgric->plvi> _mgric->plbuffsize) mgri_plflush();

}

/*-----------------------------------------------------------------------
 * Function:	mgri_drawPline
 * Description:	Experimental thick line drawing procedure
 * Author:	wisdom
 * Date:	Sat Feb 20 15:47:11 CST 1993
 * Notes:
 */
void
mgri_drawPline(HPoint3 *p1, HPoint3 *p2)
{
    Transform V;
    Transform P2S,O2S, O2P, P2O, S2O;
    int xsize, ysize;
    HPoint3 pnts[4], pnts2[4];
    HPoint3 s1, s2;
    int i;
    float dx,dy,k, len;

    /* This code will simulate line drawing in Photorman */
    /* create obj->proj transform */
    CamView(_mgc->cam, V);		/* world->proj */
    TmConcat(_mgc->xstk->T, V, O2P);	/* obj->proj */
    
    /* create obj->screen transform */
    WnGet(_mgc->win, WN_XSIZE, &xsize);
    WnGet(_mgc->win, WN_YSIZE, &ysize);
    TmScale(P2S, (float)xsize, (float)ysize, 1.0);
    TmConcat(O2P, P2S, O2S);
    
    /* translate & dehomogenize line endpoints from object to screen */
    HPt3TransPt3(_mgc->O2S, p1, &s1);
    HPt3TransPt3(_mgc->O2S, p2, &s2);

    dy = s2.y - s1.y;
    dx = s2.x - s1.x;
    len = hypot(dy,dx);
    k = _mgc->astk->ap.linewidth / len;
    
    pnts[0].x = s1.x - dy * k;
    pnts[0].y = s1.y + dx * k;
    pnts[1].x = s1.x + dy * k;
    pnts[1].y = s1.y - dx * k;
    pnts[2].x = s2.x + dy * k;
    pnts[2].y = s2.y - dx * k;
    pnts[3].x = s2.x - dy * k;
    pnts[3].y = s2.y + dx * k;
	    
    pnts[0].z = s1.z;
    pnts[1].z = s1.z;
    pnts[2].z = s2.z;
    pnts[3].z = s2.z;
    
    for (i=0; i<4; ++i) pnts[i].w = 1.0;
 	    
    /* now project back... */
    /* first, find S2O transform */
    TmInvert(O2S, S2O);
    
    /* now transform screen coords to object coords */
    for(i=0;i<4;i++) {
	HPt3Transform(_mgc->S2O, &pnts[i], &pnts[i]);
	HPt3Normalize(&pnts[i], &pnts[i]);
    }

    /* DRAW HERE */
    RiPolygon(4, RI_P, (RtPointer)pnts, RI_NULL);
}

/*-----------------------------------------------------------------------
 * Function:	mgri_drawpoint
 * Description: draws a point for rman.
 * Returns:	nothing
 * Author:	wisdom
 * Date:	Fri Mar 13 15:04:01 CST 1992	
 * Notes:	This is now done in mgri_polyline
 */
void
mgri_drawpoint(HPoint3 *p)
{
    mgri_normalize(p, ript[0]);
    //RiLine(1, RI_P, &ript, RI_NULL); << This won't draw point in right color!
    bcopy( ript[0], ript[1], sizeof(RtPoint));
    RiLine(2, RI_P, (RtPointer)ript, RI_NULL);

}

void
mgri_closer()
{
    Transform Tscale, T1, T2, T3, Tcloser;
    float scaleby;
    
    if(!_mgc->zfnudge) return;
    
    scaleby = 1.-(_mgc->zfnudge*100.);
    TmScale(Tscale, scaleby, scaleby, scaleby);
    TmConcat(_mgc->xstk->T, _mgc->W2C, T1);
    TmConcat(T1, Tscale, T2);
    TmConcat(T2, _mgc->C2W, Tcloser);

    RiTransform(Tcloser);
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.