/* See {stmesh_view_paint.h} */ /* Last edited on 2015-11-18 01:02:52 by stolfilocal */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include /* #include */ /* #include */ #include /* INTERNAL PROTOTYPES */ void stmesh_view_paint_collect_edges_by_style ( stmesh_t mesh, uint32_t deg_max, uint32_t *ngP, /* (OUT) Number of groups. */ stmesh_edge_t **ePP, /* (OUT) Edges sorted by group. */ uint32_t **gstartPP /* (OUT) Beg and end of each group. */ ); /* Assign a drawing style index to each of the {ne} edges of {mesh}, and sorts them by style group. Currently, the style index for each edge is its degree (number of incident faces). However, even and odd degrees greater than {deg_max} (whhic must be even) are mapped to {deg_max} and {deg_max-1}, respectively. Returns in {*ngP} the number {ng} of distinct edge styles used. Returns in {*ePP} the address of a newly allocated vector {e[0..ne-1]} with all the mesh edges, sorted by increasing style. Also returns in {*gstartPP} the address of a newly allocated vector {gstart[0..ng]} with the beginning and end in {e} of each style group. Namely, for any group index {ig} in {0..ng-1}, the edges in group {ig} are {e[k0..k1-1]}, where {k0=gstart[ig]} and {k1=gstart[ig+1]}. Note that {gstart} will have {ng+1} elements, not {ng}. */ frgb_t stmesh_vew_paint_tweak_hue(frgb_t *p); /* Returns a version of the color {p} with the hue slightly shifted forwards. */ /* IMPLEMENTATIONS */ void stmesh_view_paint_mesh(stmesh_t mesh, bool_t showFaces, bool_t showEdges) { if (mesh == NULL) { return; } if (stmesh_view_debug_paint) { fprintf(stderr, "+ %s\n", __FUNCTION__); } if (showFaces) { stmesh_view_paint_mesh_faces(mesh); } if (showEdges) { stmesh_view_paint_mesh_edges(mesh); } if (stmesh_view_debug_paint) { fprintf(stderr, "- %s\n", __FUNCTION__); } } void stmesh_view_paint_mesh_faces(stmesh_t mesh) { bool_t debug = FALSE; if (stmesh_view_debug_paint) { fprintf(stderr, "+ %s\n", __FUNCTION__); } uint32_t nf = stmesh_face_count(mesh); float eps = stmesh_get_eps(mesh); /* Set surface finish: */ glEnable(GL_COLOR_MATERIAL); glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE); /* Get color in GL format: */ GLfloat CR = 0.700f, CG = 0.800f, CB = 0.600f; glColor3f(CR,CG,CB); /* Paint triangles: */ glBegin(GL_TRIANGLES); stmesh_face_unx_t uxf; for(uxf = 0; uxf < nf; uxf++) { /* Get face vertices: */ stmesh_face_t f = stmesh_get_face(mesh, uxf); stmesh_vert_t v[3]; stmesh_face_get_corners(f, v); /* Get vertex coords (in mm): */ r3_t vR[3]; int k; for (k = 0; k < 3; k++) { i3_t vQ = stmesh_vert_get_pos(v[k]); if (debug) { fprintf(stderr, "( %d %d %d )\n", vQ.c[0], vQ.c[1], vQ.c[2]); } vR[k] = stmesh_unround_point(&vQ, eps); } if (debug) { fprintf(stderr, "\n"); } stmesh_view_paint_triangle(vR); } glEnd(); glDisable(GL_COLOR_MATERIAL); if (stmesh_view_debug_paint) { fprintf(stderr, "- %s\n", __FUNCTION__); } } void stmesh_view_paint_mesh_edges(stmesh_t mesh) { if (stmesh_view_debug_paint) { fprintf(stderr, "+ %s\n", __FUNCTION__); } float eps = stmesh_get_eps(mesh); glEnable(GL_COLOR_MATERIAL); glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE); /* Line width cannot be changed inside a begin-end. So we need to sort the edges by style and paint each style separately. !!! Should be pre-sorted !!! */ /* Sort edges by drawing style: */ uint32_t deg_max = 4; /* Max degree for style assignment. */ uint32_t ng; /* Number of edge drawing styles. */ stmesh_edge_t *e; /* Edges {mesh.e[0..ne-1]}, sorted by style. */ uint32_t *gstart; /* Beg/end of each style group. */ stmesh_view_paint_collect_edges_by_style(mesh, deg_max, &ng, &e, &gstart); /* Define the edge colors for the first 5 groups: */ frgb_t gGolor[ng]; /* Color for each edge group. */ assert(ng >= 5); gGolor[0] = (frgb_t){{ 1.000f, 0.250f, 1.000f }}; /* Degree zero (should not happen). */ gGolor[1] = (frgb_t){{ 1.000f, 0.250f, 0.000f }}; /* Degree 1 (border). */ gGolor[2] = (frgb_t){{ 0.000f, 0.000f, 0.000f }}; /* Degree 2 (manifold). */ gGolor[3] = (frgb_t){{ 1.000f, 0.350f, 0.000f }}; /* Degree 3 (border + manifold). */ gGolor[4] = (frgb_t){{ 0.000f, 0.350f, 1.000f }}; /* Degree 4 (double manifold). */ /* Define the colors of other groups, if any: */ uint32_t ig; for (ig = 5; ig < ng; ig++) { gGolor[ig] = stmesh_vew_paint_tweak_hue(&(gGolor[ig-2])); } /* Paint edges by group: */ for (ig = 0; ig < ng; ig++) { /* Get the sublist of edges of this group: */ uint32_t k0 = gstart[ig]; /* First edge of group has index {ixEdge[k0]}. */ uint32_t k1 = gstart[ig+1]; /* Last edge of group has index {ixEdge[k1-1]}. */ if (k0 < k1) { /* Group is not empty. */ /* Set the edge color and line thickness: */ frgb_t *clr = &(gGolor[ig]); glColor3f(clr->c[0], clr->c[1], clr->c[2]); /* Set the line thickness: */ if (ig == 2) { glLineWidth(1.0f); } else { glLineWidth(2.0f); } /* Draw the edges of group {ig}: */ glBegin(GL_LINES); uint32_t ke; for(ke = k0; ke < k1; ke++) { /* Get edge: */ stmesh_edge_t ek = e[ke]; /* Get endpoints: */ stmesh_vert_t v[2]; stmesh_edge_get_endpoints(ek, v); /* Get endpoint coords in mm: */ r3_t vR[2]; int r; for (r = 0; r < 2; r++) { i3_t vQ = stmesh_vert_get_pos(v[r]); vR[r] = stmesh_unround_point(&vQ, eps); } stmesh_view_paint_line(vR); } glEnd(); } } glDisable(GL_COLOR_MATERIAL); free(gstart); free(e); if (stmesh_view_debug_paint) { fprintf(stderr, "- %s\n", __FUNCTION__); } } void stmesh_view_paint_collect_edges_by_style ( stmesh_t mesh, uint32_t deg_max, uint32_t *ngP, /* (OUT) Number of groups. */ stmesh_edge_t **ePP, /* (OUT) Edges sorted by group. */ uint32_t **gstartPP /* (OUT) Beg and end of each group. */ ) { uint32_t ne = stmesh_edge_count(mesh); /* Number of edges. */ demand((deg_max & 2) == 0, "max degree must be even"); uint32_t ng = deg_max + 1; stmesh_edge_t *e = notnull(malloc(ne*sizeof(stmesh_edge_t)), "no mem"); /* Edges sorted by style. */ uint32_t *gstart = notnull(malloc((ng+1)*sizeof(uint32_t)), "no mem"); /* Start/end of styles. */ /* Assigns group index {egroup[uxe]} to each face with index {uxe}: */ uint32_t *egroup = notnull(malloc(ne*sizeof(uint32_t)), "no mem"); /* Group of each edge. */ uint32_t ke; for (ke = 0; ke < ne; ke++) { stmesh_edge_t ek = stmesh_get_edge(mesh, ke); uint32_t deg_raw = stmesh_edge_degree(ek); uint32_t deg_clip = (deg_raw <= deg_max ? deg_raw : deg_max - (deg_raw & 1)); egroup[ke] = deg_clip; } /* Sort edge indices by group: */ stmesh_edge_unx_t *uxe = notnull(malloc(ne*sizeof(stmesh_edge_unx_t)), "no mem"); /* Edge indices in group order. */ group_sort_uint32(ne, ng, egroup, uxe, gstart); /* Pick the edges in that order: */ for (ke = 0; ke < ne; ke++) { e[ke] = stmesh_get_edge(mesh, uxe[ke]); } /* Paranoia check: */ assert(gstart[ng] == ne); (*ngP) = ng; (*ePP) = e; (*gstartPP) = gstart; free(uxe); free(egroup); } void stmesh_view_paint_slices(stmesh_t mesh, int np, stmesh_section_t *slice[]) { if (stmesh_view_debug_paint) { fprintf(stderr, "+ %s\n", __FUNCTION__); } /* For now, same color and line width for all sections: */ frgb_t clr = (frgb_t){{ 1.000f, 0.650f, 0.100f }}; float lwd = 3.0f; /* Draw the slices: */ int ip; for (ip = 0; ip < np; ip++) { stmesh_view_paint_slice(slice[ip], &clr, lwd); } if (stmesh_view_debug_paint) { fprintf(stderr, "- %s\n", __FUNCTION__); } } void stmesh_view_paint_slice(stmesh_section_t *sec, frgb_t *clr, float lwd) { /* The {Z} coordinate of the slice: */ double fpZ = ((double)sec->eps)*((double)sec->pZ); /* Set the color, finish, line thickness: */ glEnable(GL_COLOR_MATERIAL); glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE); glColor3f(clr->c[0], clr->c[1], clr->c[2]); glLineWidth(lwd); glBegin(GL_LINES); /* Loop on the paths: */ uint32_t kc; for (kc = 0; kc < sec->nc; kc++) { uint32_t ini = sec->cstart[kc]; uint32_t fin = sec->cstart[kc+1] - 1; /* Draw the path with vertices {sec->v[ini..fin]}: */ uint32_t iv; for (iv = ini; iv < fin; iv++) { r3_t p[2]; /* Segment endpoints in 3D. */ int r; for (r = 0; r < 2; r++) { r2_t *vi = &(sec->v[iv + r]); p[r] = (r3_t){{ vi->c[0], vi->c[1], fpZ }}; } stmesh_view_paint_line(p); } } glEnd(); glDisable(GL_COLOR_MATERIAL); } frgb_t stmesh_vew_paint_tweak_hue(frgb_t *p) { frgb_t r; float rmin = 1.0f; /* Min raw color coord. */ float rmax = 0.0f; /* Max raw color coord. */ int k; for (k = 0; k < 3; k++) { double a = (double)(p->c[k]); double b = (double)(p->c[(k+1) % 3]); r.c[k] = (float)(0.8*a + 0.2*b); if (r.c[k] < rmin) { rmin = r.c[k]; } if (r.c[k] > rmax) { rmax = r.c[k]; } } /* Normalize to min 0, max 1: */ for (k = 0; k < 3; k++) { r.c[k] = (r.c[k] - rmin)/(rmax - rmin); } return r; } void stmesh_view_paint_reference_plane(r3_t *minP, r3_t *maxP, double z) { glEnable(GL_COLOR_MATERIAL); glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE); glColor3f(0.650f, 0.975f, 0.925f); glBegin(GL_QUADS); glVertex3f((GLfloat)minP->c[0], (GLfloat)minP->c[1], (GLfloat)z); glVertex3f((GLfloat)maxP->c[0], (GLfloat)minP->c[1], (GLfloat)z); glVertex3f((GLfloat)maxP->c[0], (GLfloat)maxP->c[1], (GLfloat)z); glVertex3f((GLfloat)minP->c[0], (GLfloat)maxP->c[1], (GLfloat)z); glEnd(); glDisable(GL_COLOR_MATERIAL); } void stmesh_view_paint_line(r3_t v[]) { glVertex3f((GLfloat)v[0].c[0], (GLfloat)v[0].c[1], (GLfloat)v[0].c[2]); glVertex3f((GLfloat)v[1].c[0], (GLfloat)v[1].c[1], (GLfloat)v[1].c[2]); } void stmesh_view_compute_normal(r3_t *u, r3_t *v, r3_t *n) { n->c[0] = u->c[1]*v->c[2] - v->c[1]*u->c[2]; n->c[1] = u->c[2]*v->c[0] - v->c[2]*u->c[0]; n->c[2] = u->c[0]*v->c[1] - v->c[0]*u->c[1]; double nmod = sqrt(n->c[0]*n->c[0] + n->c[1]*n->c[1] + n->c[2]*n->c[2]); if (nmod > 0) { n->c[0] /= nmod; n->c[1] /= nmod; n->c[2] /= nmod; } } void stmesh_view_paint_triangle(r3_t v[]) { r3_t a, b; a.c[0] = v[1].c[0] - v[0].c[0]; a.c[1] = v[1].c[1] - v[0].c[1]; a.c[2] = v[1].c[2] - v[0].c[2]; b.c[0] = v[2].c[0] - v[0].c[0]; b.c[1] = v[2].c[1] - v[0].c[1]; b.c[2] = v[2].c[2] - v[0].c[2]; r3_t n; stmesh_view_compute_normal(&a, &b, &n); glNormal3f((GLfloat)n.c[0], (GLfloat)n.c[1], (GLfloat)n.c[2]); glVertex3f((GLfloat)v[0].c[0], (GLfloat)v[0].c[1], (GLfloat)v[0].c[2]); glVertex3f((GLfloat)v[1].c[0], (GLfloat)v[1].c[1], (GLfloat)v[1].c[2]); glVertex3f((GLfloat)v[2].c[0], (GLfloat)v[2].c[1], (GLfloat)v[2].c[2]); } void stmesh_view_paint_quad(r3_t v[]) { /* Compute normal assuming that it is flat: */ r3_t a, b; a.c[0] = v[1].c[0] - v[0].c[0]; a.c[1] = v[1].c[1] - v[0].c[1]; a.c[2] = v[1].c[2] - v[0].c[2]; b.c[0] = v[2].c[0] - v[0].c[0]; b.c[1] = v[2].c[1] - v[0].c[1]; b.c[2] = v[2].c[2] - v[0].c[2]; r3_t n; stmesh_view_compute_normal(&a, &b, &n); glNormal3f((GLfloat)n.c[0], (GLfloat)n.c[1], (GLfloat)n.c[2]); glVertex3f((GLfloat)v[0].c[0], (GLfloat)v[0].c[1], (GLfloat)v[0].c[2]); glVertex3f((GLfloat)v[1].c[0], (GLfloat)v[1].c[1], (GLfloat)v[1].c[2]); glVertex3f((GLfloat)v[2].c[0], (GLfloat)v[2].c[1], (GLfloat)v[2].c[2]); glVertex3f((GLfloat)v[3].c[0], (GLfloat)v[3].c[1], (GLfloat)v[3].c[2]); }