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

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

/* conformal model graphics for geomview */

#include <stdlib.h>
#include "cmodelP.h"
#include "mgP.h"

#ifndef alloca
#include <alloca.h>
#endif

static int cm_show_subdivision = 0;
static int cm_maxrefine = 6;
static double cm_cosmaxbend = .95;

static int alldone = TRUE;
static int curv;

struct vertex *edge_start(struct edge *e, int ori);
void split_triangle(struct triangle *t);
void split_edge(struct edge *e, splitfunc split);
void refine_once(splitfunc split);
void refine();
struct edge *new_edge_p(struct vertex *v1, struct vertex *v2);
void make_new_quad(Transform T, HPoint3 *p, ColorA *c);
void make_new_triangle(HPoint3 *a, HPoint3 *b, HPoint3 *c, ColorA *col,
		       Transform T, Poly *p, int allvisible);

void set_cm_refine(double cm_cmb, int cm_mr, int cm_ss)
{
  /* These tests allow us to call this routine in a way that sets
     only some of the values; parameters with out-of-range values
     are not set. */

  if (cm_cmb >= 1 && cm_cmb <=1)
    cm_cosmaxbend = cm_cmb;
  if (cm_mr >=0)
    cm_maxrefine = cm_mr;
  if (cm_mr >=0)
    cm_show_subdivision = cm_ss;
  return;
}

void cmodel_clear(int space)
{
   static int initialized = FALSE; 
   
   if (initialized) {
      clear_all_vertexs();
      clear_all_edges();
      clear_all_triangles();
      }
   else {
      initialize_vertexs();
      initialize_edges();
      initialize_triangles();
      initialized = TRUE;
      }
   if (space & TM_SPHERICAL)
      curv = 1;
   else if (space & TM_HYPERBOLIC)
      curv = -1;
   else if (space & TM_EUCLIDEAN)
      curv = 0;
   /* else error */
   }

void cm_read_quad(Quad *q)
{
   int i = q->maxquad;
   QuadP *qp = q->p;
   QuadC *qc = q->c;
   Transform T;

   mggettransform(T);
   
   if (q->flag & VERT_C) {
      while (i-- > 0)
         make_new_quad(T, (HPoint3 *)qp++, (ColorA *)qc++);
      } 
   else {
      while (i-- > 0)
         make_new_quad(T, (HPoint3 *)qp++, NULL);
      }
   return;
   }

void make_new_quad(Transform T, HPoint3 *p, ColorA *c)
{
   HPoint3 tp, polar;
   int i;
   struct vertex *v[4], *vx;
   struct edge *e1, *e2, *e3, *e4, *e5;
   int apflags = _mgc->astk->ap.flag;

   if((apflags & (APF_EDGEDRAW | APF_FACEDRAW | APF_NORMALDRAW)) == 0)
	return;

   /* make 4 new vertices */
   tp.w = 1.;
   if (c) { /* vertex colors defined */
      for (i = 0; i < 4; i++) {
         projective_to_conformal(curv, p++, T, (Point3 *)&tp);
         v[i] = simple_new_vertex(&tp, c++);
         }
      }
   else {  /* no vertex colors so get color from appearance stack */
      c = (ColorA*)&_mgc->astk->ap.mat->diffuse;
      for (i = 0; i < 4; i++) {
         projective_to_conformal(curv, p++, T, (Point3 *)&tp);
         v[i] = simple_new_vertex(&tp, c);
         }
      }
   triangle_polar_point(curv, (Point3 *)&v[0]->V.pt, (Point3 *)&v[1]->V.pt,
                        (Point3 *)&v[2]->V.pt, &polar);
   for (i=0; i<4; i++)
      v[i]->polar = polar;

   e1 = new_edge_p(v[0], v[1]); 
   e2 = new_edge_p(v[1], v[2]); 
   e4 = new_edge_p(v[2], v[3]); 
   e5 = new_edge_p(v[3], v[0]);

   if(apflags & (APF_FACEDRAW|APF_NORMALDRAW)) {
       /* make two triangles and five edges */
       new_triangle(e1, e2,
		e3 = new_edge_p(v[2], v[0]),
		TRUE, TRUE, TRUE, NULL);
       new_triangle(e3, e4, e5,
		FALSE, TRUE, TRUE, NULL);
       }

   /* set the four original edges visible if required */
   if (apflags & APF_EDGEDRAW) {
      e1->visible = TRUE;
      e2->visible = TRUE; 
      e4->visible = TRUE; 
      e5->visible = TRUE; 
      }
   return;
   }

void cm_draw_mesh(Mesh *m)
{
   HPoint3 *pt, *newpt, *ppt;
   Point3 *n, *newn, *pn;
   ColorA *c, *newc = NULL, *pc;
   mgshadefunc shader = _mgc->astk->shader;
   int i, npt;
   Transform T;

   mggettransform(T);
   
   mgpushtransform();
   mgidentity();

   npt = m->nu * m->nv;
   pt = m->p;
   n = m->n;
   newpt = ppt = (HPoint3 *)alloca(npt * sizeof(HPoint3));
   newn = pn = (Point3 *)alloca(npt * sizeof(Point3));
   if(_mgc->astk->useshader) {
	newc = pc = (ColorA *)alloca(npt * sizeof(ColorA));
	c = m->c ? m->c : (ColorA *)&_mgc->astk->mat.diffuse;
   }
   for (i = 0; i < npt; ++i) {
      projective_vector_to_conformal(curv, pt, n, T, (Point3 *)ppt, pn);
      ppt->w = 1.;
      if(newc) {
	(*shader)(1, ppt, pn, c, pc);
	pc++;
	if(m->c) c++;
      }
      ++pt; ++n; ++ppt; ++pn;
      }
   mgmesh(m->flag, m->nu, m->nv, newpt, newn, newc ? newc : m->c);
   mgpoptransform();
   }

void cm_read_vect(Vect *v)
{
   int i, nv, nc;
   HPoint3 pt, *p = v->p;
   ColorA *c = v->c, *col = (ColorA *)&_mgc->astk->mat.edgecolor;
   struct vertex *v0, *v1, *v2;
   struct edge *e;
   Transform T;

   mggettransform(T);

   pt.w = 1.;
   for (i = 0; i < v->nvec; i++) {
      nv = abs(v->vnvert[i]);
      nc = v->vncolor[i];

      /* get position, color and make a new vertex */
      projective_to_conformal(curv, p++, T, (Point3 *)&pt);
      if (nc > 0) {nc--; col = c++;}
      v0 = v1 = simple_new_vertex(&pt, col);

      if (nv == 1) { /* point, not polyline */
         v0->visible = TRUE;
	 continue;
	 }

      while (--nv > 0) { /* copy polyline */

         /* get position, color and make a new vertex */
         projective_to_conformal(curv, p++, T, (Point3 *)&pt);
         if (nc > 0) {nc--; col = c++;}
	 v2 = simple_new_vertex(&pt, col);

	 e = new_edge_p(v1, v2);
	 e->visible = e->hascolor = TRUE;
	 v1 = v2;
	 }

      if (v->vnvert[i] < 0) { /* if polyline is closed */
	 e = new_edge_p(v2, v0);
	 e->visible = e->hascolor = TRUE;
	 }
      }
   }

void cm_read_polylist(PolyList *polylist)
{
   int i, j, nv, n, vertcolors, facecolors;
   HPoint3 center;
   ColorA *col;
   Transform T;
   Poly *p;

   mggettransform(T);

   p = polylist->p;
   n = polylist->n_polys;
   vertcolors = (polylist->flags & (PL_HASVCOL|PL_HASPCOL)) == PL_HASVCOL;
   facecolors = (polylist->flags & PL_HASPCOL);
   col = (ColorA*)&_mgc->astk->mat.diffuse;
   for (i = 0; i < n; i++) {
      if(facecolors) col = &p->pcol;
      nv = p->n_vertices;
      if (nv == 3) {
	 make_new_triangle(&p->v[0]->pt,
			   &p->v[1]->pt,
			   &p->v[2]->pt,
			   col, T, p, TRUE);
         }
      else {
	 center.x = center.y = center.z = center.w = 0;
	 for (j = 0; j < nv; j++)
	    HPt3Add(&center, &p->v[j]->pt, &center);
	 for (j = 1; j < nv; j++)
     	    make_new_triangle(&p->v[j-1]->pt, &p->v[j]->pt, &center,
			      vertcolors ? &p->v[j]->vcol : col, T, p, FALSE);
	 make_new_triangle(&p->v[nv-1]->pt, &p->v[0]->pt, &center,
			    vertcolors ? &p->v[0]->vcol : col, T, p, FALSE);
         }
      ++p;
      }
   }

void make_new_triangle(HPoint3 *a, HPoint3 *b, HPoint3 *c, ColorA *col,
		       Transform T, Poly *p, int allvisible)
{
   struct vertex v, *v1, *v2, *v3;
   Point3 ap, bp, cp;
   struct edge *e1, *e2, *e3;
   int apflags = _mgc->astk->ap.flag;

   projective_to_conformal(curv, a, T, &ap);
   projective_to_conformal(curv, b, T, &bp);
   projective_to_conformal(curv, c, T, &cp);

 /*fprintf(stderr,"Making tri %.1f %.1f %.1f, %.1f %.1f %.1f, %.1f %.1f %.1f\n",ap.x,ap.y,ap.z,bp.x,bp.y,bp.z,cp.x,cp.y,cp.z);*/
   /* convert to the conformal model */
   /* make a model vertex */
   triangle_polar_point(curv,&ap, &bp, &cp, &v.polar);
   v.V.vcol = *col;

   v1 = new_vertex(&ap, &v, NULL);
   v2 = new_vertex(&bp, &v, NULL);
   v3 = new_vertex(&cp, &v, NULL);
   e1 = new_edge_p(v1, v2);
   e2 = new_edge_p(v2, v3); 
   e3 = new_edge_p(v3, v1);

   if(apflags & (APF_FACEDRAW|APF_NORMALDRAW))
       new_triangle(e1, e2, e3, TRUE, TRUE, TRUE, p);

   if (apflags & APF_EDGEDRAW) {
      e1->visible = TRUE;
      if (allvisible) { 
         e2->visible = TRUE; 
         e3->visible = TRUE; 
         }
      }	

   return;
   }

struct edge *new_edge_p(struct vertex *v1, struct vertex *v2)
{
    HPoint3 polar;
    edge_polar_point(curv,(Point3 *)&v1->V.pt,(Point3 *)&v2->V.pt, &polar);
    return new_edge(v1,v2,&polar);
}

void set_normal(HPoint3 *point, HPoint3 *polar, Point3 *normal)
{
   Point3 t;
   
   if (polar == NULL) return;
   Pt3Mul(polar->w, (Point3 *)point, &t);
   Pt3Sub((Point3 *)polar, &t, normal);
 /*fprintf(stderr,"sn gives %.2f %.2f %.2f (%.2f) for polar %.2f %.2f %.2f %.2f\n",normal->x,normal->y,normal->z,sqrt(Pt3Dot(normal,normal)),polar->x,polar->y,polar->z,polar->w);*/
   Pt3Unit(normal);
   }   

void cmodel_draw(int plflags)
{
   struct triangle *tp;
   struct edge *ep;
   struct vertex *vp;
   ColorA col[2];
   HPoint3 pts[2];
   Vertex *Vertp, *verts;
   Poly *Polyp, *polys;
   int npolys, keepflags, nverts, facecolors, vertcolors, useshader, shading;
   mgshadefunc shader;

   refine();

   /* set the transform to the identity before displaying anything
      since Poincare model data is already transformed */
   mgpushtransform();
   mgidentity();

   if ((npolys = triangle_count()) != 0)
      polys = Polyp = (Poly *)alloca(npolys * sizeof(Poly));

   if ((nverts = vertex_count()) != 0) 
      verts = Vertp = (Vertex *)alloca(nverts * sizeof(Vertex));

   shading = _mgc->astk->ap.shading;
   useshader = _mgc->astk->useshader;
   shader = _mgc->astk->shader;

   vp = first_vertex();
   vertcolors = plflags & (PL_HASVCOL | PL_HASPCOL);
   while (vp != NULL) {
      Vertp->pt = vp->V.pt;
      /* visible vertices must be displayed
         invisible vertices are part of faces so we
	 must compute normals */

      if (vp->visible) {
	 mgpolyline(1, &Vertp->pt, 1, &vp->V.vcol, 0);
      } else if(IS_SMOOTH(shading)) {
        set_normal(&vp->V.pt, &vp->polar, &Vertp->vn);
	if(useshader)
	    (*shader)(1, &Vertp->pt, &Vertp->vn, &vp->V.vcol, &Vertp->vcol);
	else
	    Vertp->vcol = vp->V.vcol;
      }

      vp->vxp = Vertp++;
      vp = vp->next;
      }

   ep = first_edge();
   while (ep != NULL) { /* draw visible edges */
      if (ep->visible) {
	pts[0] = ep->v1->V.pt;
	pts[1] = ep->v2->V.pt;
        if (ep->hascolor) {
           col[0] = ep->v1->V.vcol;
           col[1] = ep->v2->V.vcol;
	   mgpolyline(2, pts, 2, col, 0);
        } else 
	   mgpolyline(2, pts, 1, &_mgc->astk->ap.mat->edgecolor, 0);
	}
      
      ep = ep->next;
      }

   tp = first_triangle();
   facecolors = (plflags & (PL_HASPCOL|PL_HASVCOL));
   while (tp != NULL) {
      tp->v[0] = edge_start(tp->e1, tp->o1)->vxp;
      tp->v[1] = edge_start(tp->e2, tp->o2)->vxp;
      tp->v[2] = edge_start(tp->e3, tp->o3)->vxp;
      Polyp->n_vertices = 3;
      Polyp->v = tp->v;
      /* computation is not exact here: assume triangle is small so center
      and vertex are very close together */
      if(IS_SHADED(shading))
	set_normal(&tp->e1->v1->V.pt, &tp->e1->v1->polar, &Polyp->pn);

      if(useshader)
	(*shader)(1, &tp->v[0]->pt, &Polyp->pn, &tp->e1->v1->V.vcol, &Polyp->pcol);
      else
	Polyp->pcol = tp->e1->v1->V.vcol;

      Polyp++;
      tp = tp->next;
      }
   
   if (npolys) {
      keepflags = _mgc->astk->ap.flag;
      if (!cm_show_subdivision)
	  _mgc->astk->ap.flag &= ~APF_EDGEDRAW;

      plflags = (plflags &~ (PL_HASPCOL|PL_HASVCOL))
		    | (IS_SMOOTH(shading) ? PL_HASVCOL : PL_HASPCOL);

      mgpolylist(npolys, polys, nverts, verts, plflags);
      _mgc->astk->ap.flag = keepflags;
      }

   /* restore the current transform */
   mgpoptransform();
   return;
   }

void refine()
{
   int maxsteps = cm_maxrefine;


   alldone = FALSE;
   
   /* should do edges at infinity here first */
   
   while (!alldone && maxsteps-- > 0) {
      alldone = TRUE;
      refine_once(edge_split);
      }
   
   return;
   }

void refine_once(splitfunc split)
{
   struct edge *ep = first_edge(), *le = get_last_edge();
   struct triangle *tp = first_triangle(), *lt = get_last_triangle();

   /* split all long edges */
   while (ep != NULL) {
      split_edge(ep, split);
      if (ep == le) break;
      ep = ep->next;
      } 
   
   if (alldone) return;
   
   /* now split all triangles that have had edges split */
   while (tp != NULL) {
      split_triangle(tp);
      if (tp == lt) break;
      tp = tp->next;
      }

   return;
   }

/* decides whether to split an edge and if so sets the split flag,
   creates a new edge and drops it into the structure */

void split_edge(struct edge *e, splitfunc split)
{
   struct vertex *mid;
   
   if (e->small) return;
   mid = (*split)(e, cm_cosmaxbend);
   if (mid == NULL) {
      e->split = FALSE;
      e->small = TRUE;
      return;
      }
   e->split = TRUE;
   e->other_half = new_edge(mid, e->v2, &e->polar);
   e->other_half->visible = e->visible;
   e->other_half->hascolor = e->hascolor;
   e->v2 = mid;
   alldone = FALSE;
   
   return;
   }

struct vertex *edge_start(struct edge *e, int ori)
{
   return ori ? e->v1 : e->v2;
   }

struct vertex *edge_mid(struct edge *e)
{
   return e->v2;
   }

struct edge *first_half(struct edge *e, int ori)
{
   return ori ? e : e->other_half;
   }

void split_triangle_at_one_edge(struct edge **e1, struct edge **e2, 
   struct edge **e3, int *o1, int *o2, int *o3, Poly *orig)
{
   struct edge *ne; 
   
   ne = new_edge_p(edge_mid(*e1), edge_start(*e3, *o3));

   new_triangle(first_half(*e1, !*o1), *e2,       ne, 
                           *o1,        *o2,       FALSE,  orig);
   *e1 = first_half(*e1, *o1);
   *e2 = ne;
   *o2 = TRUE;
   
   return;
   }

void split_triangle_at_two_edges(struct edge **e1, struct edge **e2, 
   struct edge **e3, int *o1, int *o2, int *o3, Poly *orig)
{
   struct edge *ne1, *ne2; 
   
   ne1 = new_edge_p(edge_mid(*e1), edge_start(*e3, *o3));
   ne2 = new_edge_p(edge_mid(*e1), edge_mid(*e2));

   new_triangle(first_half(*e1, !*o1), first_half(*e2, *o2), ne2, 
                           *o1,                   *o2,       FALSE, orig);
   new_triangle(first_half(*e2, !*o2), ne1,   ne2, 
                           *o2,        FALSE, TRUE, orig);
   *e1 = first_half(*e1, *o1);
   *e2 = ne1;
   *o2 = TRUE;
   
   return;
   }

void split_triangle_at_three_edges(struct edge **e1, struct edge **e2, 
   struct edge **e3, int *o1, int *o2, int *o3, Poly *orig)
{
   struct edge *ne1, *ne2, *ne3; 
   
   ne1 = new_edge_p(edge_mid(*e1), edge_mid(*e2));
   ne2 = new_edge_p(edge_mid(*e2), edge_mid(*e3));
   ne3 = new_edge_p(edge_mid(*e3), edge_mid(*e1));

   new_triangle(first_half(*e1, !*o1), first_half(*e2, *o2), ne1, 
                           *o1,                   *o2,       FALSE, orig);
   new_triangle(first_half(*e2, !*o2), first_half(*e3, *o3), ne2, 
                           *o2,                   *o3,       FALSE, orig);
   new_triangle(ne1, ne2, ne3, TRUE, TRUE, TRUE, orig);

   *e1 = first_half(*e1, *o1);
   *e2 = ne3;
   *o2 = FALSE;
   *e3 = first_half(*e3, !*o3);

   return;
   }


void split_triangle(struct triangle *t)
{
   int magic;
   Poly *orig; 

   if (t->small) return;
   orig = t->orig_poly;
   magic = t->e1->split + 2 * t->e2->split + 4 * t->e3->split;
   
   switch (magic) {
   case 0:
      t->small = TRUE;
      break;
   case 1:
      split_triangle_at_one_edge(&t->e1, &t->e2, &t->e3, 
         &t->o1, &t->o2, &t->o3, orig);
      break;
   case 2:
      split_triangle_at_one_edge(&t->e2, &t->e3, &t->e1, 
         &t->o2, &t->o3, &t->o1, orig);
      break;
   case 4:
      split_triangle_at_one_edge(&t->e3, &t->e1, &t->e2, 
         &t->o3, &t->o1, &t->o2, orig);
      break;
   case 3:
      split_triangle_at_two_edges(&t->e1, &t->e2, &t->e3, 
         &t->o1, &t->o2, &t->o3, orig);
      break;
   case 6:
      split_triangle_at_two_edges(&t->e2, &t->e3, &t->e1, 
         &t->o2, &t->o3, &t->o1, orig);
      break;
   case 5:
      split_triangle_at_two_edges(&t->e3, &t->e1, &t->e2, 
         &t->o3, &t->o1, &t->o2, orig);
      break;
   case 7:
      split_triangle_at_three_edges(&t->e1, &t->e2, &t->e3, 
         &t->o1, &t->o2, &t->o3, orig);
      break;
   default:
      break;
      }
   
   return;
   }

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