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(¢er, &p->v[j]->pt, ¢er); for (j = 1; j < nv; j++) make_new_triangle(&p->v[j-1]->pt, &p->v[j]->pt, ¢er, vertcolors ? &p->v[j]->vcol : col, T, p, FALSE); make_new_triangle(&p->v[nv-1]->pt, &p->v[0]->pt, ¢er, 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.