Cleanup: replace attrib w/ attr
[blender.git] / source / blender / draw / intern / draw_cache_impl_curve.c
index ac991336e05774546236f386a27b900525839dae..742ca20ba83c9ac7a999ab0f05ad31ba3e99aeae 100644 (file)
 #include "DNA_curve_types.h"
 
 #include "BKE_curve.h"
-
+#include "BKE_displist.h"
 #include "BKE_font.h"
 
 #include "GPU_batch.h"
 #include "GPU_texture.h"
+#include "GPU_material.h"
 
 #include "UI_resources.h"
 
@@ -104,21 +105,22 @@ static void curve_render_wire_verts_edges_len_get(
        BLI_assert(r_vert_len || r_edge_len);
        int vert_len = 0;
        int edge_len = 0;
-       *r_curve_len = 0;
+       int curve_len = 0;
        for (const BevList *bl = ob_curve_cache->bev.first; bl; bl = bl->next) {
                if (bl->nr > 0) {
                        const bool is_cyclic = bl->poly != -1;
-                       /* Curve */
-                       *r_curve_len += 1;
-
-                       /* verts */
+                       edge_len += (is_cyclic) ? bl->nr : bl->nr - 1;
                        vert_len += bl->nr;
-
-                       /* edges */
-                       edge_len += bl->nr;
-                       if (!is_cyclic) {
-                               edge_len -= 1;
-                       }
+                       curve_len += 1;
+               }
+       }
+       for (const DispList *dl = ob_curve_cache->disp.first; dl; dl = dl->next) {
+               if (ELEM(dl->type, DL_SEGM, DL_POLY)) {
+                       BLI_assert(dl->parts == 1);
+                       const bool is_cyclic = dl->type == DL_POLY;
+                       edge_len += (is_cyclic) ? dl->nr : dl->nr - 1;
+                       vert_len += dl->nr;
+                       curve_len += 1;
                }
        }
        if (r_vert_len) {
@@ -127,6 +129,9 @@ static void curve_render_wire_verts_edges_len_get(
        if (r_edge_len) {
                *r_edge_len = edge_len;
        }
+       if (r_curve_len) {
+               *r_curve_len = curve_len;
+       }
 }
 
 static int curve_render_normal_len_get(const ListBase *lb, const CurveCache *ob_curve_cache)
@@ -297,19 +302,60 @@ static int curve_render_data_normal_len_get(const CurveRenderData *rdata)
        return rdata->normal.len;
 }
 
+static void curve_cd_calc_used_gpu_layers(int *cd_layers, struct GPUMaterial **gpumat_array, int gpumat_array_len)
+{
+       GPUVertAttrLayers gpu_attrs = {{{0}}};
+       for (int i = 0; i < gpumat_array_len; i++) {
+               struct GPUMaterial *gpumat = gpumat_array[i];
+               if (gpumat == NULL) {
+                       continue;
+               }
+               GPU_material_vertex_attrs(gpumat, &gpu_attrs);
+               for (int j = 0; j < gpu_attrs.totlayer; j++) {
+                       const char *name = gpu_attrs.layer[j].name;
+                       int type = gpu_attrs.layer[j].type;
+
+                       /* Curves cannot have named layers.
+                        * Note: We could relax this assumption later. */
+                       if (name[0] != '\0') {
+                               continue;
+                       }
+
+                       if (type == CD_AUTO_FROM_NAME) {
+                               type = CD_MTFACE;
+                       }
+
+                       switch (type) {
+                               case CD_MTFACE:
+                                       *cd_layers |= CD_MLOOPUV;
+                                       break;
+                               case CD_TANGENT:
+                                       /* Currently unsupported */
+                                       // *cd_layers |= CD_TANGENT;
+                                       break;
+                               case CD_MCOL:
+                                       /* Curve object don't have Color data. */
+                                       break;
+                               case CD_ORCO:
+                                       *cd_layers |= CD_ORCO;
+                                       break;
+                       }
+               }
+       }
+}
 
 /* ---------------------------------------------------------------------- */
 /* Curve GPUBatch Cache */
 
 typedef struct CurveBatchCache {
        struct {
-               /* Split by normals if necessary. */
                GPUVertBuf *pos_nor;
                GPUVertBuf *curves_pos;
        } ordered;
 
        struct {
                GPUVertBuf *pos_nor;
+               GPUVertBuf *uv;
 
                GPUVertBuf *wireframe_data;
        } tess;
@@ -346,6 +392,7 @@ typedef struct CurveBatchCache {
        GPUIndexBuf **surf_per_mat_tris;
        GPUBatch **surf_per_mat;
        int mat_len;
+       int cd_used, cd_needed;
 
        /* settings to determine if cache is invalid */
        bool is_dirty;
@@ -362,6 +409,10 @@ static bool curve_batch_cache_valid(Curve *cu)
                return false;
        }
 
+       if (cache->mat_len != max_ii(1, cu->totcol)) {
+               return false;
+       }
+
        if (cache->is_dirty) {
                return false;
        }
@@ -401,6 +452,17 @@ static void curve_batch_cache_init(Curve *cu)
        }
 #endif
 
+       cache->cd_used = 0;
+       cache->mat_len = max_ii(1, cu->totcol);
+       cache->surf_per_mat_tris = MEM_mallocN(sizeof(*cache->surf_per_mat_tris) * cache->mat_len, __func__);
+       cache->surf_per_mat = MEM_mallocN(sizeof(*cache->surf_per_mat) * cache->mat_len, __func__);
+
+       /* TODO Might be wiser to alloc in one chunck. */
+       for (int i = 0; i < cache->mat_len; ++i) {
+               cache->surf_per_mat_tris[i] = MEM_callocN(sizeof(GPUIndexBuf), "GPUIndexBuf");
+               cache->surf_per_mat[i] = MEM_callocN(sizeof(GPUBatch), "GPUBatch");
+       }
+
        cache->is_editmode = (cu->editnurb != NULL) || (cu->editfont != NULL);
 
        cache->is_dirty = false;
@@ -472,6 +534,7 @@ static void curve_batch_cache_clear(Curve *cu)
        MEM_SAFE_FREE(cache->surf_per_mat_tris);
        MEM_SAFE_FREE(cache->surf_per_mat);
        cache->mat_len = 0;
+       cache->cd_used = 0;
 }
 
 void DRW_curve_batch_cache_free(Curve *cu)
@@ -481,7 +544,6 @@ void DRW_curve_batch_cache_free(Curve *cu)
 }
 
 /* -------------------------------------------------------------------- */
-
 /** \name Private Curve Cache API
  * \{ */
 
@@ -510,6 +572,13 @@ static void curve_create_curves_pos(CurveRenderData *rdata, GPUVertBuf *vbo_curv
                        GPU_vertbuf_attr_set(vbo_curves_pos, attr_id.pos, v_idx, bevp->vec);
                }
        }
+       for (const DispList *dl = rdata->ob_curve_cache->disp.first; dl; dl = dl->next) {
+               if (ELEM(dl->type, DL_SEGM, DL_POLY)) {
+                       for (int i = 0; i < dl->nr; v_idx++, i++) {
+                               GPU_vertbuf_attr_set(vbo_curves_pos, attr_id.pos, v_idx, &((float(*)[3])dl->verts)[i]);
+                       }
+               }
+       }
        BLI_assert(v_idx == vert_len);
 }
 
@@ -541,7 +610,19 @@ static void curve_create_curves_lines(CurveRenderData *rdata, GPUIndexBuf *ibo_c
                GPU_indexbuf_add_primitive_restart(&elb);
                v_idx += bl->nr;
        }
-
+       for (const DispList *dl = rdata->ob_curve_cache->disp.first; dl; dl = dl->next) {
+               if (ELEM(dl->type, DL_SEGM, DL_POLY)) {
+                       const bool is_cyclic = dl->type == DL_POLY;
+                       if (is_cyclic) {
+                               GPU_indexbuf_add_generic_vert(&elb, v_idx + (dl->nr - 1));
+                       }
+                       for (int i = 0; i < dl->nr; i++) {
+                               GPU_indexbuf_add_generic_vert(&elb, v_idx + i);
+                       }
+                       GPU_indexbuf_add_primitive_restart(&elb);
+                       v_idx += dl->nr;
+               }
+       }
        GPU_indexbuf_build_in_place(&elb, ibo_curve_lines);
 }
 
@@ -581,7 +662,7 @@ static void curve_create_edit_curves_nor(CurveRenderData *rdata, GPUVertBuf *vbo
                        GPUPackedNormal pnor = GPU_normal_convert_i10_v3(nor);
                        GPUPackedNormal ptan = GPU_normal_convert_i10_v3(bevp->dir);
 
-                       /* Only set attribs for one vertex. */
+                       /* Only set attributes for one vertex. */
                        GPU_vertbuf_attr_set(vbo_curves_nor, attr_id.pos, vbo_len_used, bevp->vec);
                        GPU_vertbuf_attr_set(vbo_curves_nor, attr_id.rad, vbo_len_used, &bevp->radius);
                        GPU_vertbuf_attr_set(vbo_curves_nor, attr_id.nor, vbo_len_used, &pnor);
@@ -668,8 +749,8 @@ static void curve_create_edit_data_and_handles(
                                        GPU_indexbuf_add_point_vert(elbp_verts, vbo_len_used + 1);
                                }
                                if (elbp_lines) {
-                                       GPU_indexbuf_add_line_verts(elbp_lines, vbo_len_used + 0, vbo_len_used + 1);
-                                       GPU_indexbuf_add_line_verts(elbp_lines, vbo_len_used + 0, vbo_len_used + 2);
+                                       GPU_indexbuf_add_line_verts(elbp_lines, vbo_len_used + 1, vbo_len_used + 0);
+                                       GPU_indexbuf_add_line_verts(elbp_lines, vbo_len_used + 1, vbo_len_used + 2);
                                }
                                if (vbo_data) {
                                        char vflag[3] = {
@@ -743,7 +824,6 @@ static void curve_create_edit_data_and_handles(
 /** \} */
 
 /* -------------------------------------------------------------------- */
-
 /** \name Public Object/Curve API
  * \{ */
 
@@ -786,46 +866,16 @@ GPUBatch **DRW_curve_batch_cache_get_surface_shaded(
         struct Curve *cu,
         struct GPUMaterial **gpumat_array, uint gpumat_array_len)
 {
-#if 0
        CurveBatchCache *cache = curve_batch_cache_get(cu);
 
-       if (cache->surface.mat_len != gpumat_array_len) {
-               GPU_BATCH_DISCARD_ARRAY_SAFE(cache->surface.shaded_triangles, cache->surface.mat_len);
-       }
-
-       if (cache->surface.shaded_triangles == NULL) {
-               CurveRenderData *rdata = curve_render_data_create(cu, ob_curve_cache, CU_DATATYPE_SURFACE);
-               ListBase *lb = &rdata->ob_curve_cache->disp;
+       BLI_assert(gpumat_array_len == cache->mat_len);
 
-               cache->surface.mat_len = gpumat_array_len;
-               if (cu->flag & CU_UV_ORCO) {
-                       cache->surface.shaded_triangles = DRW_displist_batch_calc_tri_pos_normals_and_uv_split_by_material(
-                               lb, gpumat_array_len);
-               }
-               else {
-                       cache->surface.shaded_triangles = MEM_mallocN(
-                               sizeof(*cache->surface.shaded_triangles) * gpumat_array_len, __func__);
-                       GPUIndexBuf **el = DRW_displist_indexbuf_calc_triangles_in_order_split_by_material(
-                               lb, gpumat_array_len);
-
-                       if (cache->surface.verts == NULL) {
-                               cache->surface.verts = DRW_displist_vertbuf_calc_pos_with_normals(lb);
-                       }
-
-                       for (int i = 0; i < gpumat_array_len; ++i) {
-                               cache->surface.shaded_triangles[i] = GPU_batch_create_ex(
-                                       GPU_PRIM_TRIS, cache->surface.verts, el[i], GPU_BATCH_OWNS_INDEX);
-                       }
-
-                       MEM_freeN(el); /* Save `el` in cache? */
-               }
+       curve_cd_calc_used_gpu_layers(&cache->cd_needed, gpumat_array, gpumat_array_len);
 
-               curve_render_data_free(rdata);
+       for (int i = 0; i < cache->mat_len; ++i) {
+               DRW_batch_request(&cache->surf_per_mat[i]);
        }
-
-       return cache->surface.shaded_triangles;
-#endif
-       return NULL;
+       return cache->surf_per_mat;
 }
 
 GPUBatch *DRW_curve_batch_cache_get_wireframes_face(Curve *cu)
@@ -844,8 +894,23 @@ void DRW_curve_batch_cache_create_requested(Object *ob)
 {
        BLI_assert(ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT));
 
-       Curve *me = (Curve *)ob->data;
-       CurveBatchCache *cache = curve_batch_cache_get(me);
+       Curve *cu = ob->data;
+       CurveBatchCache *cache = curve_batch_cache_get(cu);
+
+       /* Verify that all surface batches have needed attribute layers. */
+       /* TODO(fclem): We could be a bit smarter here and only do it per material. */
+       for (int i = 0; i < cache->mat_len; ++i) {
+               if ((cache->cd_used & cache->cd_needed) != cache->cd_needed) {
+                       /* We can't discard batches at this point as they have been
+                        * referenced for drawing. Just clear them in place. */
+                       GPU_batch_clear(cache->surf_per_mat[i]);
+                       memset(cache->surf_per_mat[i], 0, sizeof(*cache->surf_per_mat[i]));
+               }
+       }
+       if ((cache->cd_used & cache->cd_needed) != cache->cd_needed) {
+               cache->cd_used |= cache->cd_needed;
+               cache->cd_needed = 0;
+       }
 
        /* Init batches and request VBOs & IBOs */
        if (DRW_batch_requested(cache->batch.surfaces, GPU_PRIM_TRIS)) {
@@ -879,12 +944,24 @@ void DRW_curve_batch_cache_create_requested(Object *ob)
        if (DRW_batch_requested(cache->batch.edit_normals, GPU_PRIM_LINES)) {
                DRW_vbo_request(cache->batch.edit_normals, &cache->edit.curves_nor);
        }
+       for (int i = 0; i < cache->mat_len; ++i) {
+               if (DRW_batch_requested(cache->surf_per_mat[i], GPU_PRIM_TRIS)) {
+                       if (cache->mat_len > 1) {
+                               DRW_ibo_request(cache->surf_per_mat[i], &cache->surf_per_mat_tris[i]);
+                       }
+                       if (cache->cd_used & CD_MLOOPUV) {
+                               DRW_vbo_request(cache->surf_per_mat[i], &cache->tess.uv);
+                       }
+                       DRW_vbo_request(cache->surf_per_mat[i], &cache->tess.pos_nor);
+               }
+       }
 
        /* Generate MeshRenderData flags */
        int mr_flag = 0;
        DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->ordered.pos_nor, CU_DATATYPE_SURFACE);
        DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->ordered.curves_pos, CU_DATATYPE_WIRE);
        DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->tess.pos_nor, CU_DATATYPE_SURFACE);
+       DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->tess.uv, CU_DATATYPE_SURFACE);
        DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->tess.wireframe_data, CU_DATATYPE_SURFACE);
        DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag, cache->ibo.surfaces_tris, CU_DATATYPE_SURFACE);
        DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag, cache->ibo.curves_lines, CU_DATATYPE_WIRE);
@@ -896,28 +973,41 @@ void DRW_curve_batch_cache_create_requested(Object *ob)
        DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag, cache->ibo.edit_verts_points, CU_DATATYPE_OVERLAY);
        DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag, cache->ibo.edit_lines, CU_DATATYPE_OVERLAY);
 
-       CurveRenderData *rdata = curve_render_data_create(me, ob->runtime.curve_cache, mr_flag);
+       for (int i = 0; i < cache->mat_len; ++i) {
+               DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag, cache->surf_per_mat_tris[i], CU_DATATYPE_SURFACE);
+       }
+
+       CurveRenderData *rdata = curve_render_data_create(cu, ob->runtime.curve_cache, mr_flag);
 
        /* DispLists */
        ListBase *lb = &rdata->ob_curve_cache->disp;
 
        /* Generate VBOs */
        if (DRW_vbo_requested(cache->ordered.pos_nor)) {
-               DRW_displist_vertbuf_calc_pos_with_normals(lb, cache->ordered.pos_nor);
+               DRW_displist_vertbuf_create_pos_and_nor(lb, cache->ordered.pos_nor);
        }
        if (DRW_vbo_requested(cache->ordered.curves_pos)) {
                curve_create_curves_pos(rdata, cache->ordered.curves_pos);
        }
 
+       if (DRW_vbo_requested(cache->tess.pos_nor) ||
+           DRW_vbo_requested(cache->tess.uv))
+       {
+               DRW_displist_vertbuf_create_pos_and_nor_and_uv_tess(lb, cache->tess.pos_nor, cache->tess.uv);
+       }
        if (DRW_vbo_requested(cache->tess.wireframe_data)) {
-               DRW_displist_create_edges_overlay_batch(lb, cache->tess.wireframe_data);
+               DRW_displist_vertbuf_create_wireframe_data_tess(lb, cache->tess.wireframe_data);
+       }
+
+       if (DRW_ibo_requested(cache->surf_per_mat_tris[0])) {
+               DRW_displist_indexbuf_create_triangles_tess_split_by_material(lb, cache->surf_per_mat_tris, cache->mat_len);
        }
 
        if (DRW_ibo_requested(cache->ibo.curves_lines)) {
                curve_create_curves_lines(rdata, cache->ibo.curves_lines);
        }
        if (DRW_ibo_requested(cache->ibo.surfaces_tris)) {
-               DRW_displist_indexbuf_calc_triangles_in_order(lb, cache->ibo.surfaces_tris);
+               DRW_displist_indexbuf_create_triangles_in_order(lb, cache->ibo.surfaces_tris);
        }
 
        if (DRW_vbo_requested(cache->edit.pos) ||
@@ -933,6 +1023,13 @@ void DRW_curve_batch_cache_create_requested(Object *ob)
        }
 
        curve_render_data_free(rdata);
+
+#ifdef DEBUG
+       /* Make sure all requested batches have been setup. */
+       for (int i = 0; i < sizeof(cache->batch) / sizeof(void *); ++i) {
+               BLI_assert(!DRW_batch_requested(((GPUBatch **)&cache->batch)[i], 0));
+       }
+#endif
 }
 
 /** \} */