[Bf-blender-cvs] [0ea4747] GPU_data_request: Mesh drawing: variety of surface normal treatments
Mike Erwin
noreply at git.blender.org
Tue Apr 21 08:29:37 CEST 2015
Commit: 0ea474775227811e4aca2bc9b64cca9d7ded5ac9
Author: Mike Erwin
Date: Tue Apr 21 01:41:26 2015 -0400
Branches: GPU_data_request
https://developer.blender.org/rB0ea474775227811e4aca2bc9b64cca9d7ded5ac9
Mesh drawing: variety of surface normal treatments
Can be NONE, SMOOTH, FLAT or LOOP.
LOOP is unfinished at the moment.
NONE might be pulled into its own drawing override mode.
Note: this commit includes some debug/tracing that is still useful to
me but will be removed in the future.
===================================================================
M source/blender/editors/space_view3d/drawobject.c
M source/blender/gpu/GPUx_draw.h
===================================================================
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index ae22f1c..f6606f1 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -4418,6 +4418,23 @@ static bool draw_mesh_object_new(Scene *scene, ARegion *ar, View3D *v3d, RegionV
return retval;
}
+static bool vertex_in_poly(int v, const MPoly *poly, const MLoop *loops)
+{
+ int i;
+ for (i = poly->loopstart; i < (poly->loopstart + poly->totloop); ++i)
+ if (loops[i].v == v)
+ return true;
+ return false;
+}
+
+static bool tessface_in_poly(const MFace *face, const MPoly *poly, const MLoop *loops)
+{
+ return vertex_in_poly(face->v1, poly, loops) &&
+ vertex_in_poly(face->v2, poly, loops) &&
+ vertex_in_poly(face->v3, poly, loops) &&
+ (face->v4 == 0 || vertex_in_poly(face->v4, poly, loops));
+}
+
static bool draw_mesh_object_new_new(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base,
const char dt, const unsigned char ob_wire_col[4], const short dflag)
{
@@ -4446,13 +4463,23 @@ static bool draw_mesh_object_new_new(Scene *scene, ARegion *ar, View3D *v3d, Reg
DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask);
bool batch_needs_setup = false;
+ if (!dm) {
+#if MCE_TRACE
+ puts("NO DM -> BAIL!!!");
+#endif
+ return true;
+ }
+
if (dm->gpux_batch == 0) {
- dm->gpux_batch = GPUx_batch_create();
+#if MCE_TRACE
+ puts("NO BATCH -> CREATE");
+#endif
batch_needs_setup = true;
}
else if (dm->gpux_batch->draw_type != dt) {
- GPUx_batch_discard(dm->gpux_batch);
- dm->gpux_batch = GPUx_batch_create();
+#if MCE_TRACE
+ puts("DIFF DRAW TYPE -> REPLACE");
+#endif
batch_needs_setup = true;
}
@@ -4460,59 +4487,229 @@ static bool draw_mesh_object_new_new(Scene *scene, ARegion *ar, View3D *v3d, Reg
const int vert_ct = dm->getNumVerts(dm);
const int edge_ct = dm->getNumEdges(dm);
const int face_ct = dm->getNumTessFaces(dm);
- const int attrib_ct = (dt > OB_WIRE) ? 2 : 1;
+ const int poly_ct = dm->getNumPolys(dm);
+ const int loop_ct = dm->getNumLoops(dm);
- VertexBuffer *verts = GPUx_vertex_buffer_create(attrib_ct, vert_ct);
+ const MVert *mverts = dm->getVertArray(dm);
+
+ VertexBuffer *verts = NULL;
ElementList *elem = NULL;
- MVert *mverts = dm->getVertArray(dm);
+
+ if (dm->gpux_batch) GPUx_batch_discard(dm->gpux_batch);
+ dm->gpux_batch = GPUx_batch_create();
dm->gpux_batch->draw_type = dt;
#if MCE_TRACE
- printf("%d verts, %d edges, %d faces\n", vert_ct, edge_ct, face_ct);
+ printf("%d verts, %d edges, %d polys, %d faces, %d loops\n",
+ vert_ct, edge_ct, poly_ct, face_ct, loop_ct);
#endif /* MCE_TRACE */
- GPUx_specify_attrib(verts, 0, GL_VERTEX_ARRAY, GL_FLOAT, 3, KEEP_FLOAT);
- GPUx_fill_attrib_stride(verts, 0, mverts, sizeof(MVert));
-
- if (dt > OB_WIRE) {
- /* draw smooth surface */
- /* TODO: handle flat faces */
- /* TODO: handle loop normals */
- int i, t, tri_ct = 0;
- MFace *faces = dm->getTessFaceArray(dm);
- dm->gpux_batch->state.common.lighting = true;
- dm->gpux_batch->state.common.interpolate = true;
- dm->gpux_batch->state.polygon.draw_back = false;
-
- GPUx_specify_attrib(verts, 1, GL_NORMAL_ARRAY, GL_SHORT, 3, NORMALIZE_INT_TO_FLOAT);
- GPUx_fill_attrib_stride(verts, 1, &mverts[0].no, sizeof(MVert));
-
- /* some tess faces are quads, some triangles
- * we draw just triangles, so count quads twice */
- for (i = 0; i < face_ct; ++i)
- tri_ct += faces[i].v4 ? 2 : 1;
-
- elem = GPUx_element_list_create(GL_TRIANGLES, tri_ct, vert_ct - 1);
-
- for (i = 0, t = 0; i < face_ct; ++i) {
- const MFace *face = faces + i;
- GPUx_set_triangle_vertices(elem, t++, face->v1, face->v2, face->v3);
- if (face->v4)
- GPUx_set_triangle_vertices(elem, t++, face->v4, face->v1, face->v3);
+#if 0 /* unused, just needed to answer some questions */
+ {
+ /* count some more stuff
+ * triangle count is fixed; minimize GL vertex count
+ * tesselating doesn't change values at vertices, so some sharing is easy to find.
+ */
+ const MPoly *polys = dm->getPolyArray(dm);
+ const MLoop *loops = dm->getLoopArray(dm);
+ const MFace *faces = dm->getTessFaceArray(dm);
+ int i, j;
+
+ for (i = 0; i < poly_ct; ++i) {
+ const MPoly *poly = polys + i;
+ printf("poly %d: ", i);
+ for (j = poly->loopstart; j < (poly->loopstart + poly->totloop); ++j) {
+ printf(" v%d", loops[j].v);
+ }
+ putchar('\n');
+ }
+ for (i = 0; i < face_ct; ++i) {
+ const MFace *f = faces + i;
+ printf("tess face %d: ", i);
+ printf(" v%d v%d v%d", f->v1, f->v2, f->v3);
+ if (f->v4) printf(" v%d", f->v4);
+ putchar('\n');
}
- GPUx_vertex_buffer_prime(verts);
- GPUx_element_list_prime(elem);
+ /* interesting so far!
+ * we only need loop_ct vertices to draw correctly, not tri_ct * 3
+ * this is true for flat shaded and multi-attrib meshes
+ * Still need tess triangles per poly...
+ * Maybe tess faces are stored in same order as polys? That would be
+ * great. Checking... BKE_mesh_recalc_tessellation has
+ * int *mface_to_poly_map;
+ * YES, MFaces follow same order as MPolys.
+ */
+ }
+#endif /* unused */
+
+ if (dt > OB_WIRE) {
+#if MCE_TRACE
+ puts("OB_SOLID+");
+#endif
+ const MFace *faces = dm->getTessFaceArray(dm);
+ const int tri_ct = poly_to_tri_count(poly_ct, loop_ct);
+ int i, t;
dm->gpux_batch->prim_type = GL_TRIANGLES;
- dm->gpux_batch->buff = verts;
- dm->gpux_batch->elem = elem;
+ dm->gpux_batch->normal_draw_mode =
+ (dflag & (DRAW_PICKING | DRAW_CONSTCOLOR)) ? NORMAL_DRAW_NONE :
+ (dflag & DM_DRAW_ALWAYS_SMOOTH) ? NORMAL_DRAW_SMOOTH :
+ NORMAL_DRAW_FLAT;
+
+ switch (dm->gpux_batch->normal_draw_mode) {
+ case NORMAL_DRAW_NONE:
+ {
+#if MCE_TRACE
+ puts("NORMAL_DRAW_NONE");
+#endif
+ /* same situations as draw_mesh_fancy:
+ * if (dflag & (DRAW_PICKING | DRAW_CONSTCOLOR)) ...
+ * except we really don't want to discard the "display" GPUxBatch,
+ * create a new one for const/no color, just to recreate the
+ * display batch next time we draw */
+
+ /* TODO: color according to object ID */
+
+ /* keep state.polygon.draw_back = true for full coverage */
+
+ verts = GPUx_vertex_buffer_create(1, vert_ct);
+ GPUx_specify_attrib(verts, 0, GL_VERTEX_ARRAY, GL_FLOAT, 3, KEEP_FLOAT);
+ GPUx_fill_attrib_stride(verts, 0, mverts, sizeof(MVert));
+
+ elem = GPUx_element_list_create(GL_TRIANGLES, tri_ct, vert_ct - 1);
+
+ for (i = 0, t = 0; i < face_ct; ++i) {
+ const MFace *face = faces + i;
+ GPUx_set_triangle_vertices(elem, t++, face->v1, face->v2, face->v3);
+ if (face->v4)
+ GPUx_set_triangle_vertices(elem, t++, face->v4, face->v1, face->v3);
+ }
+
+ break;
+ }
+ case NORMAL_DRAW_SMOOTH:
+ {
+#if MCE_TRACE
+ puts("NORMAL_DRAW_SMOOTH");
+#endif
+ dm->gpux_batch->state.common.lighting = true;
+ dm->gpux_batch->state.common.interpolate = true;
+ dm->gpux_batch->state.polygon.draw_back = false;
+
+ verts = GPUx_vertex_buffer_create(2, vert_ct);
+ GPUx_specify_attrib(verts, 0, GL_VERTEX_ARRAY, GL_FLOAT, 3, KEEP_FLOAT);
+ GPUx_specify_attrib(verts, 1, GL_NORMAL_ARRAY, GL_SHORT, 3, NORMALIZE_INT_TO_FLOAT);
+ GPUx_fill_attrib_stride(verts, 0, mverts, sizeof(MVert));
+ GPUx_fill_attrib_stride(verts, 1, &mverts[0].no, sizeof(MVert));
+
+ elem = GPUx_element_list_create(GL_TRIANGLES, tri_ct, vert_ct - 1);
+
+ for (i = 0, t = 0; i < face_ct; ++i) {
+ const MFace *face = faces + i;
+ GPUx_set_triangle_vertices(elem, t++, face->v1, face->v2, face->v3);
+ if (face->v4)
+ GPUx_set_triangle_vertices(elem, t++, face->v4, face->v1, face->v3);
+ }
+
+ break;
+ }
+ case NORMAL_DRAW_FLAT:
+ {
+#if MCE_TRACE
+ puts("NORMAL_DRAW_FLAT");
+#endif
+ int new_vert_ct = 0;
+ const MLoop *loops = dm->getLoopArray(dm);
+ const MPoly *polys = dm->getPolyArray(dm);
+ const MPoly *poly = polys;
+ short poly_normal[3];
+ {
+ /* get first poly normal */
+ float f_no[3];
+ BKE_mesh_calc_poly_normal(poly, loops + poly->loopstart, mverts, f_no);
+ normal_float_to_short_v3(poly_normal, f_no);
+ }
+ dm->gpux_batch->state.common.lighting = true;
+ dm->gpux_batch->state.common.interpolate = false;
+ dm->gpux_batch->state.polygon.draw_back = false;
+
+ new_vert_ct = 3 * tri_ct;
+ /* TODO: use loop_ct GL verts, not 3 * tri_ct
+ * conserve VRAM! encourage reuse! */
+#if MCE_TRACE
+ printf("tri_ct = %d, new_vert_ct = %d, loop_ct = %d\n", tri_ct, new_vert_ct, loop_ct);
+#endif
+ verts = GPUx_vertex_buffer_create(2, new_vert_ct);
+ GPUx_specify_attrib(verts, 0, GL_VERTEX_ARRAY, GL_FLOAT, 3, KEEP_FLOAT);
+ GPUx_specify_attrib(verts, 1, GL_NORMAL_ARRAY, GL_SHORT, 3, NORMALIZE_INT_TO_FLOAT);
+
+ elem = GPUx_element_list_create(GL_TRIANGLES, tri_ct, new_vert_ct - 1);
+
+ for (i = 0, t = 0; i < face_ct; ++i) {
+ const MFace *f = faces + i;
+
+ int v1 = 3 * t + 0,
+ v2 = 3 * t + 1,
+ v3 = 3 * t + 2;
+
+ if (!tessface_in_poly(f, poly, loops)) {
+ /* get next poly normal */
+ float f_no[3];
+ poly++;
+ assert(tessface_in_poly(f, poly, loops));
+ BKE_mesh_calc_poly_normal(poly, loops + poly->loopstart, mverts, f_no);
+ normal_float_to_short_v3(poly_normal, f_no);
+ }
+
+ GPUx_set_attrib(verts, 0, v1, &mverts[f->v1].co);
+ GPUx_set_attrib(verts, 0, v2, &mverts[f->v2].co);
+ GPUx_set_attrib(verts, 0, v3, &mverts[f->v3].co);
+ /* set only provoking vertex's normal */
+ GPUx_set_attrib(verts, 1, v3, poly_normal);
+
+ GPUx_set_triangle_vertices(elem, t++, v1, v2, v3);
+
+ if (f->v4) {
+ v1 += 3; v2 += 3; v3 += 3;
+ GPUx_set_attrib(verts, 0, v1, &mverts[f->v4].
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list