DRW: Support Wireframe for metaball objects
authorClément Foucault <foucault.clem@gmail.com>
Fri, 23 Nov 2018 17:02:34 +0000 (18:02 +0100)
committerClément Foucault <foucault.clem@gmail.com>
Fri, 23 Nov 2018 17:03:18 +0000 (18:03 +0100)
source/blender/draw/intern/draw_cache.c
source/blender/draw/intern/draw_cache.h
source/blender/draw/intern/draw_cache_impl.h
source/blender/draw/intern/draw_cache_impl_displist.c
source/blender/draw/intern/draw_cache_impl_metaball.c

index a2430d12f41a67527ffce999ca05fe4ff048c6da..d6caabcb2036b6c16f6429594db15571181a2e06 100644 (file)
@@ -709,7 +709,9 @@ void DRW_cache_object_face_wireframe_get(
                case OB_FONT:
                        DRW_cache_text_face_wireframe_get(ob, r_vert_tx, r_faceid_tx, r_tri_count);
                        break;
-               /* TODO, metaballs' */
+               case OB_MBALL:
+                       DRW_cache_mball_face_wireframe_get(ob, r_vert_tx, r_faceid_tx, r_tri_count);
+                       break;
        }
 }
 
@@ -3287,6 +3289,13 @@ GPUBatch *DRW_cache_mball_surface_get(Object *ob)
        return DRW_metaball_batch_cache_get_triangles_with_normals(ob);
 }
 
+void DRW_cache_mball_face_wireframe_get(
+        Object *ob, struct GPUTexture **r_vert_tx, struct GPUTexture **r_faceid_tx, int *r_tri_count)
+{
+       BLI_assert(ob->type == OB_MBALL);
+       return DRW_metaball_batch_cache_get_wireframes_face_texbuf(ob, r_vert_tx, r_faceid_tx, r_tri_count);
+}
+
 GPUBatch **DRW_cache_mball_surface_shaded_get(
         Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len)
 {
index 39bbcf2c93aeeac90895688ac7a7d09c1d450d84..d2aa26222464dc959a2a9ac00175b2f9897151ca 100644 (file)
@@ -209,5 +209,7 @@ struct GPUBatch *DRW_cache_particles_get_prim(int type);
 /* Metaball */
 struct GPUBatch *DRW_cache_mball_surface_get(struct Object *ob);
 struct GPUBatch **DRW_cache_mball_surface_shaded_get(struct Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len);
+void DRW_cache_mball_face_wireframe_get(
+        Object *ob, struct GPUTexture **r_vert_tx, struct GPUTexture **r_faceid_tx, int *r_tri_count);
 
 #endif /* __DRAW_CACHE_H__ */
index 97e7cd240ff93f545650177afe055eb2d3737000..9dc735807c077405f6809396ef56953f8ddbc469 100644 (file)
@@ -82,6 +82,8 @@ void DRW_curve_batch_cache_get_wireframes_face_texbuf(
 /* Metaball */
 struct GPUBatch *DRW_metaball_batch_cache_get_triangles_with_normals(struct Object *ob);
 struct GPUBatch **DRW_metaball_batch_cache_get_surface_shaded(struct Object *ob, struct MetaBall *mb, struct GPUMaterial **gpumat_array, uint gpumat_array_len);
+void DRW_metaball_batch_cache_get_wireframes_face_texbuf(
+        struct Object *ob, struct GPUTexture **verts_data, struct GPUTexture **face_indices, int *tri_count);
 
 /* Curve (Font) */
 struct GPUBatch *DRW_curve_batch_cache_get_overlay_cursor(struct Curve *cu);
index 1053e8fa4f79effb675bd68517a902484005af8c..d6a57676a8ddcf33f43392188a7e63aebc0358f6 100644 (file)
@@ -91,6 +91,7 @@ typedef void (setTriIndicesFn)(void *thunk, uint v1, uint v2, uint v3);
 
 static void displist_indexbufbuilder_set(
        setTriIndicesFn *set_tri_indices,
+       setTriIndicesFn *set_quad_tri_indices, /* meh, find a better solution. */
        void *thunk, const DispList *dl, const int ofs)
 {
        if (ELEM(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) {
@@ -104,18 +105,20 @@ static void displist_indexbufbuilder_set(
                else if (dl->type == DL_SURF) {
                        const int i_end = dl->totindex;
                        for (int i = 0; i < i_end; i++, idx += 4) {
-                               set_tri_indices(thunk, idx[0] + ofs, idx[2] + ofs, idx[1] + ofs);
-                               set_tri_indices(thunk, idx[2] + ofs, idx[0] + ofs, idx[3] + ofs);
+                               set_quad_tri_indices(thunk, idx[0] + ofs, idx[2] + ofs, idx[1] + ofs);
+                               set_quad_tri_indices(thunk, idx[2] + ofs, idx[0] + ofs, idx[3] + ofs);
                        }
                }
                else {
                        BLI_assert(dl->type == DL_INDEX4);
                        const int i_end = dl->parts;
                        for (int i = 0; i < i_end; i++, idx += 4) {
-                               set_tri_indices(thunk, idx[0] + ofs, idx[1] + ofs, idx[2] + ofs);
-
                                if (idx[2] != idx[3]) {
-                                       set_tri_indices(thunk, idx[0] + ofs, idx[2] + ofs, idx[3] + ofs);
+                                       set_quad_tri_indices(thunk, idx[2] + ofs, idx[0] + ofs, idx[1] + ofs);
+                                       set_quad_tri_indices(thunk, idx[0] + ofs, idx[2] + ofs, idx[3] + ofs);
+                               }
+                               else {
+                                       set_tri_indices(thunk, idx[2] + ofs, idx[0] + ofs, idx[1] + ofs);
                                }
                        }
                }
@@ -173,7 +176,9 @@ GPUIndexBuf *DRW_displist_indexbuf_calc_triangles_in_order(ListBase *lb)
 
        int ofs = 0;
        for (const DispList *dl = lb->first; dl; dl = dl->next) {
-               displist_indexbufbuilder_set((setTriIndicesFn *)GPU_indexbuf_add_tri_verts, &elb, dl, ofs);
+               displist_indexbufbuilder_set((setTriIndicesFn *)GPU_indexbuf_add_tri_verts,
+                                            (setTriIndicesFn *)GPU_indexbuf_add_tri_verts,
+                                            &elb, dl, ofs);
                ofs += dl_vert_len(dl);
        }
 
@@ -198,7 +203,9 @@ GPUIndexBuf **DRW_displist_indexbuf_calc_triangles_in_order_split_by_material(Li
        /* calc each index buffer builder */
        int ofs = 0;
        for (const DispList *dl = lb->first; dl; dl = dl->next) {
-               displist_indexbufbuilder_set((setTriIndicesFn *)GPU_indexbuf_add_tri_verts, &elb[dl->col], dl, ofs);
+               displist_indexbufbuilder_set((setTriIndicesFn *)GPU_indexbuf_add_tri_verts,
+                                            (setTriIndicesFn *)GPU_indexbuf_add_tri_verts,
+                                            &elb[dl->col], dl, ofs);
                ofs += dl_vert_len(dl);
        }
 
@@ -219,18 +226,21 @@ typedef struct DRWDisplistWireThunk {
 static void set_overlay_wires_tri_indices(void *thunk, uint v1, uint v2, uint v3)
 {
        DRWDisplistWireThunk *dwt = (DRWDisplistWireThunk *)thunk;
-       /* TODO consider non-manifold edges correctly. */
-       if (dwt->dl_type == DL_SURF) {
-               /* Tag real edges. */
-               v2 |= (1 << 30);
-               v3 |= (1 << 30);
-       }
-       else {
-               /* Tag real edges. */
-               v1 |= (1 << 30);
-               v2 |= (1 << 30);
-               v3 |= (1 << 30);
-       }
+       /* Tag real edges. */
+       v1 |= (1 << 30);
+       v2 |= (1 << 30);
+       v3 |= (1 << 30);
+       GPU_vertbuf_attr_set(dwt->vbo, dwt->index_id, dwt->vidx++, &v1);
+       GPU_vertbuf_attr_set(dwt->vbo, dwt->index_id, dwt->vidx++, &v2);
+       GPU_vertbuf_attr_set(dwt->vbo, dwt->index_id, dwt->vidx++, &v3);
+}
+
+static void set_overlay_wires_quad_tri_indices(void *thunk, uint v1, uint v2, uint v3)
+{
+       DRWDisplistWireThunk *dwt = (DRWDisplistWireThunk *)thunk;
+       /* Tag real edges. */
+       v2 |= (1 << 30);
+       v3 |= (1 << 30);
        GPU_vertbuf_attr_set(dwt->vbo, dwt->index_id, dwt->vidx++, &v1);
        GPU_vertbuf_attr_set(dwt->vbo, dwt->index_id, dwt->vidx++, &v2);
        GPU_vertbuf_attr_set(dwt->vbo, dwt->index_id, dwt->vidx++, &v3);
@@ -249,7 +259,10 @@ GPUVertBuf *DRW_displist_create_edges_overlay_texture_buf(ListBase *lb)
        int ofs = 0;
        for (const DispList *dl = lb->first; dl; dl = dl->next) {
                thunk.dl_type = dl->type;
-               displist_indexbufbuilder_set(set_overlay_wires_tri_indices, &thunk, dl, ofs);
+               /* TODO consider non-manifold edges correctly. */
+               displist_indexbufbuilder_set(set_overlay_wires_tri_indices,
+                                            set_overlay_wires_quad_tri_indices,
+                                            &thunk, dl, ofs);
                ofs += dl_vert_len(dl);
        }
 
index 6dab46ccaa037655e2879521391da4dc26b15dd5..b41b443039a7bcde7234941fbffb21701cc65bc3 100644 (file)
@@ -39,6 +39,8 @@
 
 #include "GPU_batch.h"
 
+#include "DRW_render.h"
+
 #include "draw_cache_impl.h"  /* own include */
 
 
@@ -50,8 +52,19 @@ static void metaball_batch_cache_clear(MetaBall *mb);
 typedef struct MetaBallBatchCache {
        GPUBatch *batch;
        GPUBatch **shaded_triangles;
-
        int mat_len;
+
+       /* Shared */
+       GPUVertBuf *pos_nor_in_order;
+
+       /* Wireframe */
+       struct {
+               GPUVertBuf *elem_vbo;
+               GPUTexture *elem_tx;
+               GPUTexture *verts_tx;
+               int tri_count;
+       } face_wire;
+
        /* settings to determine if cache is invalid */
        bool is_dirty;
 } MetaBallBatchCache;
@@ -80,6 +93,11 @@ static void metaball_batch_cache_init(MetaBall *mb)
        cache->mat_len = 0;
        cache->shaded_triangles = NULL;
        cache->is_dirty = false;
+       cache->pos_nor_in_order = NULL;
+       cache->face_wire.elem_vbo = NULL;
+       cache->face_wire.elem_tx = NULL;
+       cache->face_wire.verts_tx = NULL;
+       cache->face_wire.tri_count = 0;
 }
 
 static MetaBallBatchCache *metaball_batch_cache_get(MetaBall *mb)
@@ -113,7 +131,12 @@ static void metaball_batch_cache_clear(MetaBall *mb)
                return;
        }
 
+       GPU_VERTBUF_DISCARD_SAFE(cache->face_wire.elem_vbo);
+       DRW_TEXTURE_FREE_SAFE(cache->face_wire.elem_tx);
+       DRW_TEXTURE_FREE_SAFE(cache->face_wire.verts_tx);
+
        GPU_BATCH_DISCARD_SAFE(cache->batch);
+       GPU_VERTBUF_DISCARD_SAFE(cache->pos_nor_in_order);
        /* Note: shaded_triangles[0] is already freed by cache->batch */
        MEM_SAFE_FREE(cache->shaded_triangles);
        cache->mat_len = 0;
@@ -125,6 +148,45 @@ void DRW_mball_batch_cache_free(MetaBall *mb)
        MEM_SAFE_FREE(mb->batch_cache);
 }
 
+static GPUVertBuf *mball_batch_cache_get_pos_and_normals(Object *ob, MetaBallBatchCache *cache)
+{
+       if (cache->pos_nor_in_order == NULL) {
+               ListBase *lb = &ob->runtime.curve_cache->disp;
+               cache->pos_nor_in_order = DRW_displist_vertbuf_calc_pos_with_normals(lb);
+       }
+       return cache->pos_nor_in_order;
+}
+
+static GPUTexture *mball_batch_cache_get_edges_overlay_texture_buf(Object *ob, MetaBallBatchCache *cache)
+{
+       if (cache->face_wire.elem_tx != NULL) {
+               return cache->face_wire.elem_tx;
+       }
+
+       ListBase *lb = &ob->runtime.curve_cache->disp;
+
+       /* We need a special index buffer. */
+       GPUVertBuf *vbo = cache->face_wire.elem_vbo = DRW_displist_create_edges_overlay_texture_buf(lb);
+
+       /* Upload data early because we need to create the texture for it. */
+       GPU_vertbuf_use(vbo);
+       cache->face_wire.elem_tx = GPU_texture_create_from_vertbuf(vbo);
+       cache->face_wire.tri_count = vbo->vertex_alloc / 3;
+
+       return cache->face_wire.elem_tx;
+}
+
+static GPUTexture *mball_batch_cache_get_vert_pos_and_nor_in_order_buf(Object *ob, MetaBallBatchCache *cache)
+{
+       if (cache->face_wire.verts_tx == NULL) {
+               GPUVertBuf *vbo = mball_batch_cache_get_pos_and_normals(ob, cache);
+               GPU_vertbuf_use(vbo); /* Upload early for buffer texture creation. */
+               cache->face_wire.verts_tx = GPU_texture_create_buffer(GPU_R32F, vbo->vbo_id);
+       }
+
+       return cache->face_wire.verts_tx;
+}
+
 /* -------------------------------------------------------------------- */
 
 /** \name Public Object/MetaBall API
@@ -143,9 +205,9 @@ GPUBatch *DRW_metaball_batch_cache_get_triangles_with_normals(Object *ob)
                ListBase *lb = &ob->runtime.curve_cache->disp;
                cache->batch = GPU_batch_create_ex(
                        GPU_PRIM_TRIS,
-                       DRW_displist_vertbuf_calc_pos_with_normals(lb),
+                       mball_batch_cache_get_pos_and_normals(ob, cache),
                        DRW_displist_indexbuf_calc_triangles_in_order(lb),
-                       GPU_BATCH_OWNS_VBO | GPU_BATCH_OWNS_INDEX);
+                       GPU_BATCH_OWNS_INDEX);
        }
 
        return cache->batch;
@@ -169,3 +231,27 @@ GPUBatch **DRW_metaball_batch_cache_get_surface_shaded(Object *ob, MetaBall *mb,
        return cache->shaded_triangles;
 
 }
+
+void DRW_metaball_batch_cache_get_wireframes_face_texbuf(
+        Object *ob, struct GPUTexture **verts_data, struct GPUTexture **face_indices, int *tri_count)
+{
+       if (!BKE_mball_is_basis(ob)) {
+               *verts_data = NULL;
+               *face_indices = NULL;
+               *tri_count = 0;
+               return;
+       }
+
+       MetaBall *mb = ob->data;
+       MetaBallBatchCache *cache = metaball_batch_cache_get(mb);
+
+       if (cache->face_wire.verts_tx == NULL) {
+               *verts_data = mball_batch_cache_get_vert_pos_and_nor_in_order_buf(ob, cache);
+               *face_indices = mball_batch_cache_get_edges_overlay_texture_buf(ob, cache);
+       }
+       else {
+               *verts_data = cache->face_wire.verts_tx;
+               *face_indices = cache->face_wire.elem_tx;
+       }
+       *tri_count = cache->face_wire.tri_count;
+}
\ No newline at end of file