diff options
-rw-r--r-- | source/blender/blenkernel/BKE_DerivedMesh.h | 7 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_mesh_render.h | 42 | ||||
-rw-r--r-- | source/blender/blenkernel/CMakeLists.txt | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/DerivedMesh.c | 13 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/mesh.c | 4 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/mesh_render.c | 619 | ||||
-rw-r--r-- | source/blender/editors/space_view3d/drawobject.c | 360 | ||||
-rw-r--r-- | source/blender/gpu/gawain/batch.h | 2 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_mesh_types.h | 1 |
9 files changed, 685 insertions, 365 deletions
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h index 059f7309cf5..784c76bffd3 100644 --- a/source/blender/blenkernel/BKE_DerivedMesh.h +++ b/source/blender/blenkernel/BKE_DerivedMesh.h @@ -145,10 +145,6 @@ typedef DMDrawOption (*DMSetDrawOptions)(void *userData, int index); typedef DMDrawOption (*DMSetDrawOptionsMappedTex)(void *userData, int origindex, int mat_nr); typedef DMDrawOption (*DMSetDrawOptionsTex)(struct MTexPoly *mtexpoly, const bool has_vcol, int matnr); -/* Cleanup callback type */ -typedef void (*DMCleanupBatchCache)(void *batchCache); -void DM_set_batch_cleanup_callback(DMCleanupBatchCache); - typedef enum DMDrawFlag { DM_DRAW_USE_COLORS = (1 << 0), DM_DRAW_ALWAYS_SMOOTH = (1 << 1), @@ -176,6 +172,8 @@ typedef enum DMDirtyFlag { /* check this with modifier dependsOnNormals callback to see if normals need recalculation */ DM_DIRTY_NORMALS = 1 << 2, + + DM_MESH_BATCH_CACHE = 1 << 3, } DMDirtyFlag; typedef struct DerivedMesh DerivedMesh; @@ -187,7 +185,6 @@ struct DerivedMesh { int deformedOnly; /* set by modifier stack if only deformed from original */ BVHCache *bvhCache; struct GPUDrawObject *drawObject; - void *batchCache; DerivedMeshType type; float auto_bump_scale; DMDirtyFlag dirty; diff --git a/source/blender/blenkernel/BKE_mesh_render.h b/source/blender/blenkernel/BKE_mesh_render.h new file mode 100644 index 00000000000..8a2b3f9d9ec --- /dev/null +++ b/source/blender/blenkernel/BKE_mesh_render.h @@ -0,0 +1,42 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2017 by Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation, Mike Erwin, Dalai Felinto + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __BKE_MESH_RENDER_H__ +#define __BKE_MESH_RENDER_H__ + +/** \file BKE_mesh_render.h + * \ingroup bke + */ + +struct Batch; +struct Mesh; + +void BKE_mesh_batch_cache_free(struct Mesh *me); +struct Batch *BKE_mesh_batch_cache_get_all_edges(struct Mesh *me); +struct Batch *BKE_mesh_batch_cache_get_all_triangles(struct Mesh *me); +struct Batch *BKE_mesh_batch_cache_get_all_verts(struct Mesh *me); +struct Batch *BKE_mesh_batch_cache_get_fancy_edges(struct Mesh *me); +struct Batch *BKE_mesh_batch_cache_get_overlay_edges(struct Mesh *me); + +#endif /* __BKE_MESH_RENDER_H__ */ diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 2ccbed58b04..f3bab55b47d 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -133,6 +133,7 @@ set(SRC intern/mesh_evaluate.c intern/mesh_mapping.c intern/mesh_remap.c + intern/mesh_render.c intern/mesh_validate.c intern/modifier.c intern/modifiers_bmesh.c @@ -257,6 +258,7 @@ set(SRC BKE_mesh.h BKE_mesh_mapping.h BKE_mesh_remap.h + BKE_mesh_render.h BKE_modifier.h BKE_movieclip.h BKE_multires.h diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index fb0087aefac..e0bbe345fc4 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -260,12 +260,6 @@ static CustomData *dm_getPolyCData(DerivedMesh *dm) return &dm->polyData; } -static DMCleanupBatchCache cleanupBatchCache = NULL; -void DM_set_batch_cleanup_callback(DMCleanupBatchCache func) -{ - cleanupBatchCache = func; -} - /** * Utility function to initialize a DerivedMesh's function pointers to * the default implementation (for those functions which have a default) @@ -324,8 +318,6 @@ void DM_init( DM_init_funcs(dm); - dm->batchCache = NULL; /* necessary? dm->drawObject is not set to NULL yet it works fine */ - dm->needsFree = 1; dm->auto_bump_scale = -1.0f; dm->dirty = 0; @@ -385,10 +377,7 @@ int DM_release(DerivedMesh *dm) if (dm->needsFree) { bvhcache_free(&dm->bvhCache); GPU_drawobject_free(dm); - if (dm->batchCache && cleanupBatchCache) { - cleanupBatchCache(dm->batchCache); - dm->batchCache = NULL; - } + CustomData_free(&dm->vertData, dm->numVertData); CustomData_free(&dm->edgeData, dm->numEdgeData); CustomData_free(&dm->faceData, dm->numTessFaceData); diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index af02e02b017..134173580ae 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -48,6 +48,7 @@ #include "BKE_DerivedMesh.h" #include "BKE_global.h" #include "BKE_mesh.h" +#include "BKE_mesh_render.h" #include "BKE_displist.h" #include "BKE_library.h" #include "BKE_library_query.h" @@ -435,6 +436,8 @@ void BKE_mesh_free(Mesh *me) { BKE_animdata_free(&me->id, false); + BKE_mesh_batch_cache_free(me); + CustomData_free(&me->vdata, me->totvert); CustomData_free(&me->edata, me->totedge); CustomData_free(&me->fdata, me->totface); @@ -522,6 +525,7 @@ Mesh *BKE_mesh_copy(Main *bmain, Mesh *me) BKE_mesh_update_customdata_pointers(men, do_tessface); men->edit_btmesh = NULL; + men->batch_cache = NULL; men->mselect = MEM_dupallocN(men->mselect); men->bb = MEM_dupallocN(men->bb); diff --git a/source/blender/blenkernel/intern/mesh_render.c b/source/blender/blenkernel/intern/mesh_render.c new file mode 100644 index 00000000000..f90783a3dbb --- /dev/null +++ b/source/blender/blenkernel/intern/mesh_render.c @@ -0,0 +1,619 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2017 by Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation, Mike Erwin, Dalai Felinto + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/mesh_render.c + * \ingroup bke + * + * \brief Mesh API for render engines + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "BKE_customdata.h" +#include "BKE_depsgraph.h" +#include "BKE_DerivedMesh.h" +#include "BKE_editmesh.h" +#include "BKE_mesh.h" +#include "BKE_mesh_render.h" + +#include "GPU_batch.h" + +/* ---------------------------------------------------------------------- */ +/* Mesh Interface */ + +#define MESH_RENDER_FUNCTION(func_name) \ + if (me->edit_btmesh) { \ + return mesh_bmesh_##func_name(me); \ + } \ + else { \ + return mesh_struct_##func_name(me); \ + } + + +/* Mesh Implementation */ + +static int mesh_struct_get_num_edges(Mesh *me) +{ + return me->totedge; +} + +static int mesh_struct_get_num_verts(Mesh *me) +{ + return me->totvert; +} + +static int mesh_struct_get_num_faces(Mesh *me) +{ + BKE_mesh_tessface_ensure(me); + return me->totface; +} + +static int mesh_struct_get_num_polys(Mesh *me) +{ + return me->totpoly; +} + +static MEdge *mesh_struct_get_array_edge(Mesh *me) +{ + return CustomData_get_layer(&me->edata, CD_MEDGE); +} + +static MFace *mesh_struct_get_array_face(Mesh *me) +{ + BKE_mesh_tessface_ensure(me); + return CustomData_get_layer(&me->fdata, CD_MFACE); +} + +static MLoop *mesh_struct_get_array_loop(Mesh *me) +{ + return me->mloop; +} + +static MPoly *mesh_struct_get_array_poly(Mesh *me) +{ + return me->mpoly; +} + +static MVert *mesh_struct_get_array_vert(Mesh *me) +{ + return CustomData_get_layer(&me->vdata, CD_MVERT); +} + +/* BMesh Implementation */ + +/* NOTE: we may want to get rid of Derived Mesh and + * access BMesh directly */ + +static int mesh_bmesh_get_num_verts(Mesh *me) +{ + BMEditMesh *bm = me->edit_btmesh; + DerivedMesh *dm = bm->derivedFinal; + return dm->getNumVerts(dm); +} + +static int mesh_bmesh_get_num_edges(Mesh *me) +{ + BMEditMesh *bm = me->edit_btmesh; + DerivedMesh *dm = bm->derivedFinal; + return dm->getNumEdges(dm); +} + +static int mesh_bmesh_get_num_faces(Mesh *me) +{ + BMEditMesh *bm = me->edit_btmesh; + DerivedMesh *dm = bm->derivedFinal; + return dm->getNumTessFaces(dm); +} + +static int mesh_bmesh_get_num_polys(Mesh *me) +{ + BMEditMesh *bm = me->edit_btmesh; + DerivedMesh *dm = bm->derivedFinal; + return dm->getNumPolys(dm); +} + +static MEdge *mesh_bmesh_get_array_edge(Mesh *me) +{ + BMEditMesh *bm = me->edit_btmesh; + DerivedMesh *dm = bm->derivedFinal; + return dm->getEdgeArray(dm); +} + +static MFace *mesh_bmesh_get_array_face(Mesh *me) +{ + BMEditMesh *bm = me->edit_btmesh; + DerivedMesh *dm = bm->derivedFinal; + return dm->getTessFaceArray(dm); +} + +static MLoop *mesh_bmesh_get_array_loop(Mesh *me) +{ + BMEditMesh *bm = me->edit_btmesh; + DerivedMesh *dm = bm->derivedFinal; + return dm->getLoopArray(dm); +} + +static MPoly *mesh_bmesh_get_array_poly(Mesh *me) +{ + BMEditMesh *bm = me->edit_btmesh; + DerivedMesh *dm = bm->derivedFinal; + return dm->getPolyArray(dm); +} + +static MVert *mesh_bmesh_get_array_vert(Mesh *me) +{ + BMEditMesh *bm = me->edit_btmesh; + DerivedMesh *dm = bm->derivedFinal; + return dm->getVertArray(dm); +} + +/* Mesh API */ + +static int mesh_render_get_num_edges(Mesh *me) +{ + MESH_RENDER_FUNCTION(get_num_edges); +} + +static int mesh_render_get_num_faces(Mesh *me) +{ + MESH_RENDER_FUNCTION(get_num_faces); +} + +static int mesh_render_get_num_polys(Mesh *me) +{ + MESH_RENDER_FUNCTION(get_num_polys); +} + +static int mesh_render_get_num_verts(Mesh *me) +{ + MESH_RENDER_FUNCTION(get_num_verts); +} + +static MEdge *mesh_render_get_array_edge(Mesh *me) +{ + MESH_RENDER_FUNCTION(get_array_edge); +} + +static MFace *mesh_render_get_array_face(Mesh *me) +{ + MESH_RENDER_FUNCTION(get_array_face); +} + +static MLoop *mesh_render_get_array_loop(Mesh *me) +{ + MESH_RENDER_FUNCTION(get_array_loop); +} + +static MPoly *mesh_render_get_array_poly(Mesh *me) +{ + MESH_RENDER_FUNCTION(get_array_poly); +} + +static MVert *mesh_render_get_array_vert(Mesh *me) +{ + MESH_RENDER_FUNCTION(get_array_vert); +} + +/* ---------------------------------------------------------------------- */ +/* Mesh Batch Cache */ + +typedef struct MeshBatchCache { + VertexBuffer *pos_in_order; + ElementList *edges_in_order; + ElementList *triangles_in_order; + + Batch *all_verts; + Batch *all_edges; + Batch *all_triangles; + + Batch *fancy_edges; /* owns its vertex buffer (not shared) */ + Batch *overlay_edges; /* owns its vertex buffer */ + + /* TODO: settings, before DEPSGRAPH update */ + int tot_edges; + int tot_faces; + int tot_polys; + int tot_verts; + bool is_editmode; +} MeshBatchCache; + +static bool mesh_batch_cache_valid(Mesh *me) +{ + MeshBatchCache *cache = me->batch_cache; + + if (cache == NULL) { + return false; + } + + if (cache->is_editmode != (me->edit_btmesh != NULL)) { + return false; + } + + if (cache->is_editmode) { + DerivedMesh *dm = me->edit_btmesh->derivedFinal; + if ((dm->dirty & DM_MESH_BATCH_CACHE) == 0) { + return false; + } + } + + /* TODO: temporary check, waiting for depsgraph update */ + if ((cache->tot_edges != mesh_render_get_num_edges(me)) || + (cache->tot_faces != mesh_render_get_num_faces(me)) || + (cache->tot_polys != mesh_render_get_num_polys(me)) || + (cache->tot_verts != mesh_render_get_num_verts(me))) + { + return false; + } + + return true; +} + +static void mesh_batch_cache_init(Mesh *me) +{ + MeshBatchCache *cache = me->batch_cache; + cache->is_editmode = me->edit_btmesh != NULL; + + cache->tot_edges = mesh_render_get_num_edges(me); + cache->tot_faces = mesh_render_get_num_faces(me); + cache->tot_polys = mesh_render_get_num_polys(me); + cache->tot_verts = mesh_render_get_num_verts(me); + + if (cache->is_editmode) { + DerivedMesh *dm = me->edit_btmesh->derivedFinal; + dm->dirty |= DM_MESH_BATCH_CACHE; + } +} + +static MeshBatchCache *mesh_batch_cache_get(Mesh *me) +{ + if (!mesh_batch_cache_valid(me)) { + BKE_mesh_batch_cache_free(me); + me->batch_cache = MEM_callocN(sizeof(MeshBatchCache), "MeshBatchCache"); + mesh_batch_cache_init(me); + } + return me->batch_cache; +} + +static VertexBuffer *mesh_batch_cache_get_pos_in_order(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + + if (cache->pos_in_order == NULL) { + static VertexFormat format = { 0 }; + static unsigned pos_id; + if (format.attrib_ct == 0) { + /* initialize vertex format */ + pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + } + + const int vertex_ct = mesh_render_get_num_verts(me); + const MVert *verts = mesh_render_get_array_vert(me); + + cache->pos_in_order = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(cache->pos_in_order, vertex_ct); +#if 0 + const unsigned stride = (verts + 1) - verts; /* or sizeof(MVert) */ + fillAttribStride(cache->pos_in_order, pos_id, stride, &verts[0].co); +#else + for (int i = 0; i < vertex_ct; ++i) { + setAttrib(cache->pos_in_order, pos_id, i, &verts[i].co); + } +#endif + } + + return cache->pos_in_order; +} + +static ElementList *mesh_batch_cache_get_edges_in_order(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + + if (cache->edges_in_order == NULL) { + const int vertex_ct = mesh_render_get_num_verts(me); + const int edge_ct = mesh_render_get_num_edges(me); + const MEdge *edges = mesh_render_get_array_edge(me); + + ElementListBuilder elb; + ElementListBuilder_init(&elb, GL_LINES, edge_ct, vertex_ct); + for (int i = 0; i < edge_ct; ++i) { + const MEdge *edge = edges + i; + add_line_vertices(&elb, edge->v1, edge->v2); + } + cache->edges_in_order = ElementList_build(&elb); + } + + return cache->edges_in_order; +} + +static ElementList *mesh_batch_cache_get_triangles_in_order(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + + if (cache->triangles_in_order == NULL) { + const int vertex_ct = mesh_render_get_num_verts(me); + const int tessface_ct = mesh_render_get_num_faces(me); + MFace *tessfaces = mesh_render_get_array_face(me); + + ElementListBuilder elb; + ElementListBuilder_init(&elb, GL_TRIANGLES, tessface_ct * 2, vertex_ct); /* up to 2 triangles per tessface */ + for (int i = 0; i < tessface_ct; ++i) { + const MFace *tess = tessfaces + i; + add_triangle_vertices(&elb, tess->v1, tess->v2, tess->v3); + + if (tess->v4) { + add_triangle_vertices(&elb, tess->v1, tess->v3, tess->v4); + } + } + cache->triangles_in_order = ElementList_build(&elb); + } + + /* NOTE: we are reallocating, it would be interesting to reallocating the memory once we + * know the exactly triangle count (like in BKE_mesh_batch_cache_get_overlay_edges) */ + + return cache->triangles_in_order; +} + +void BKE_mesh_batch_cache_free(Mesh *me) +{ + MeshBatchCache *cache = me->batch_cache; + if (!cache) { + return; + } + + if (cache->all_verts) Batch_discard(cache->all_verts); + if (cache->all_edges) Batch_discard(cache->all_edges); + if (cache->all_triangles) Batch_discard(cache->all_triangles); + + if (cache->pos_in_order) VertexBuffer_discard(cache->pos_in_order); + if (cache->edges_in_order) ElementList_discard(cache->edges_in_order); + if (cache->triangles_in_order) ElementList_discard(cache->triangles_in_order); + + if (cache->fancy_edges) { + Batch_discard_all(cache->fancy_edges); + } + + if (cache->overlay_edges) { + Batch_discard_all(cache->overlay_edges); + } + + MEM_freeN(cache); + me->batch_cache = NULL; +} + +Batch *BKE_mesh_batch_cache_get_all_edges(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + + if (cache->all_edges == NULL) { + /* create batch from Mesh */ + cache->all_edges = Batch_create(GL_LINES, mesh_batch_cache_get_pos_in_order(me), mesh_batch_cache_get_edges_in_order(me)); + } + + return cache->all_edges; +} + +Batch *BKE_mesh_batch_cache_get_all_triangles(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + + if (cache->all_triangles == NULL) { + /* create batch from DM */ + cache->all_triangles = Batch_create(GL_TRIANGLES, mesh_batch_cache_get_pos_in_order(me), mesh_batch_cache_get_triangles_in_order(me)); + } + + return cache->all_triangles; +} + +Batch *BKE_mesh_batch_cache_get_all_verts(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + + if (cache->all_verts == NULL) { + /* create batch from DM */ + cache->all_verts = Batch_create(GL_POINTS, mesh_batch_cache_get_pos_in_order(me), NULL); + Batch_set_builtin_program(cache->all_verts, GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR); + } + + return cache->all_verts; +} + +Batch *BKE_mesh_batch_cache_get_fancy_edges(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + + if (cache->fancy_edges == NULL) { + /* create batch from DM */ + static VertexFormat format = { 0 }; + static unsigned pos_id, n1_id, n2_id; + if (format.attrib_ct == 0) { + /* initialize vertex format */ + pos_id = add_attrib(&format, "pos", COMP_F32, 3, KEEP_FLOAT); + +#if USE_10_10_10 /* takes 1/3 the space */ + n1_id = add_attrib(&format, "N1", COMP_I10, 3, NORMALIZE_INT_TO_FLOAT); + n2_id = add_attrib(&format, "N2", COMP_I10, 3, NORMALIZE_INT_TO_FLOAT); +#else + n1_id = add_attrib(&format, "N1", COMP_F32, 3, KEEP_FLOAT); + n2_id = add_attrib(&format, "N2", COMP_F32, 3, KEEP_FLOAT); +#endif + } + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + + const MVert *verts = mesh_render_get_array_vert(me); + const MEdge *edges = mesh_render_get_array_edge(me); + const MPoly *polys = mesh_render_get_array_poly(me); + const MLoop *loops = mesh_render_get_array_loop(me); + const int edge_ct = mesh_render_get_num_edges(me); + const int poly_ct = mesh_render_get_num_polys(me); + + /* need normal of each face, and which faces are adjacent to each edge */ + typedef struct { + int count; + int face_index[2]; + } AdjacentFaces; + + float (*face_normal)[3] = MEM_mallocN(poly_ct * 3 * sizeof(float), "face_normal"); + AdjacentFaces *adj_faces = MEM_callocN(edge_ct * sizeof(AdjacentFaces), "adj_faces"); + + for (int i = 0; i < poly_ct; ++i) { + const MPoly *poly = polys + i; + + BKE_mesh_calc_poly_normal(poly, loops + poly->loopstart, verts, face_normal[i]); + + for (int j = poly->loopstart; j < (poly->loopstart + poly->totloop); ++j) { + AdjacentFaces *adj = adj_faces + loops[j].e; + if (adj->count < 2) + adj->face_index[adj->count] = i; + adj->count++; + } + } + + const int vertex_ct = edge_ct * 2; /* these are GL_LINE verts, not mesh verts */ + VertexBuffer_allocate_data(vbo, vertex_ct); + for (int i = 0; i < edge_ct; ++i) { + const MEdge *edge = edges + i; + const AdjacentFaces *adj = adj_faces + i; + +#if USE_10_10_10 + PackedNormal n1value = { .x = 0, .y = 0, .z = +511 }; + PackedNormal n2value = { .x = 0, .y = 0, .z = -511 }; + + if (adj->count == 2) { + n1value = convert_i10_v3(face_normal[adj->face_index[0]]); + n2value = convert_i10_v3(face_normal[adj->face_index[1]]); + } + + const PackedNormal *n1 = &n1value; + const PackedNormal *n2 = &n2value; +#else + const float dummy1[3] = { 0.0f, 0.0f, +1.0f }; + const float dummy2[3] = { 0.0f, 0.0f, -1.0f }; + + const float *n1 = (adj->count == 2) ? face_normal[adj->face_index[0]] : dummy1; + const float *n2 = (adj->count == 2) ? face_normal[adj->face_index[1]] : dummy2; +#endif + + setAttrib(vbo, pos_id, 2 * i, &verts[edge->v1].co); + setAttrib(vbo, n1_id, 2 * i, n1); + setAttrib(vbo, n2_id, 2 * i, n2); + + setAttrib(vbo, pos_id, 2 * i + 1, &verts[edge->v2].co); + setAttrib(vbo, n1_id, 2 * i + 1, n1); + setAttrib(vbo, n2_id, 2 * i + 1, n2); + } + + MEM_freeN(adj_faces); + MEM_freeN(face_normal); + + cache->fancy_edges = Batch_create(GL_LINES, vbo, NULL); + } + + return cache->fancy_edges; +} + +static bool edge_is_real(const MEdge *edges, int edge_ct, int v1, int v2) +{ + /* TODO: same thing, except not ridiculously slow */ + + for (int e = 0; e < edge_ct; ++e) { + const MEdge *edge = edges + e; + if ((edge->v1 == v1 && edge->v2 == v2) || (edge->v1 == v2 && edge->v2 == v1)) { + return true; + } + } + + return false; +} + +static void add_overlay_tri( + VertexBuffer *vbo, unsigned pos_id, unsigned edgeMod_id, const MVert *verts, + const MEdge *edges, int edge_ct, int v1, int v2, int v3, int base_vert_idx) +{ + const float edgeMods[2] = { 0.0f, 1.0f }; + + const float *pos = verts[v1].co; + setAttrib(vbo, pos_id, base_vert_idx + 0, pos); + setAttrib(vbo, edgeMod_id, base_vert_idx + 0, edgeMods + (edge_is_real(edges, edge_ct, v2, v3) ? 1 : 0)); + + pos = verts[v2].co; + setAttrib(vbo, pos_id, base_vert_idx + 1, pos); + setAttrib(vbo, edgeMod_id, base_vert_idx + 1, edgeMods + (edge_is_real(edges, edge_ct, v3, v1) ? 1 : 0)); + + pos = verts[v3].co; + setAttrib(vbo, pos_id, base_vert_idx + 2, pos); + setAttrib(vbo, edgeMod_id, base_vert_idx + 2, edgeMods + (edge_is_real(edges, edge_ct, v1, v2) ? 1 : 0)); +} + +Batch *BKE_mesh_batch_cache_get_overlay_edges(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + + if (cache->overlay_edges == NULL) { + /* create batch from DM */ + static VertexFormat format = { 0 }; + static unsigned pos_id, edgeMod_id; + + if (format.attrib_ct == 0) { + /* initialize vertex format */ + pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + edgeMod_id = add_attrib(&format, "edgeWidthModulator", GL_FLOAT, 1, KEEP_FLOAT); + } + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + + const int edge_ct = mesh_render_get_num_edges(me); + const int tessface_ct = mesh_render_get_num_faces(me); + const MVert *verts = mesh_render_get_array_vert(me); + const MEdge *edges = mesh_render_get_array_edge(me); + const MFace *tessfaces = mesh_render_get_array_face(me); + + VertexBuffer_allocate_data(vbo, tessface_ct * 6); /* up to 2 triangles per tessface */ + + int gpu_vert_idx = 0; + for (int i = 0; i < tessface_ct; ++i) { + const MFace *tess = tessfaces + i; + add_overlay_tri(vbo, pos_id, edgeMod_id, verts, edges, edge_ct, tess->v1, tess->v2, tess->v3, gpu_vert_idx); + gpu_vert_idx += 3; + /* tessface can be triangle or quad */ + if (tess->v4) { + add_overlay_tri(vbo, pos_id, edgeMod_id, verts, edges, edge_ct, tess->v3, tess->v2, tess->v4, gpu_vert_idx); + gpu_vert_idx += 3; + } + } + + /* in some cases all the faces are quad, so no need to reallocate */ + if (vbo->vertex_ct != gpu_vert_idx) { + VertexBuffer_resize_data(vbo, gpu_vert_idx); + } + + cache->overlay_edges = Batch_create(GL_TRIANGLES, vbo, NULL); + } + + return cache->overlay_edges; +} + +#undef MESH_RENDER_FUNCTION diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index b00a7346e59..1692d3a7372 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -65,6 +65,7 @@ #include "BKE_lattice.h" #include "BKE_main.h" #include "BKE_mesh.h" +#include "BKE_mesh_render.h" #include "BKE_material.h" #include "BKE_mball.h" #include "BKE_modifier.h" @@ -214,340 +215,6 @@ typedef struct drawBMSelect_userData { bool select; } drawBMSelect_userData; -typedef struct { - VertexBuffer *pos_in_order; - ElementList *edges_in_order; - ElementList *triangles_in_order; - - Batch *all_verts; - Batch *all_edges; - Batch *all_triangles; - - Batch *fancy_edges; /* owns its vertex buffer (not shared) */ - Batch *overlay_edges; /* owns its vertex buffer */ -} MeshBatchCache; - -static void MBC_discard(MeshBatchCache *cache) -{ - if (cache->all_verts) Batch_discard(cache->all_verts); - if (cache->all_edges) Batch_discard(cache->all_edges); - if (cache->all_triangles) Batch_discard(cache->all_triangles); - - if (cache->pos_in_order) VertexBuffer_discard(cache->pos_in_order); - if (cache->edges_in_order) ElementList_discard(cache->edges_in_order); - if (cache->triangles_in_order) ElementList_discard(cache->triangles_in_order); - - if (cache->fancy_edges) { - Batch_discard_all(cache->fancy_edges); - } - - if (cache->overlay_edges) { - Batch_discard_all(cache->overlay_edges); - } - - MEM_freeN(cache); -} - -static MeshBatchCache *MBC_get(DerivedMesh *dm) -{ - if (dm->batchCache == NULL) { - /* create cache */ - dm->batchCache = MEM_callocN(sizeof(MeshBatchCache), "MeshBatchCache"); - /* init everything to 0 is ok for now */ - - - /* tell DerivedMesh how to clean up these caches (just once) */ - /* TODO: find a better place for this w/out exposing internals to DM */ - /* TODO (long term): replace DM with something less messy */ - static bool first = true; - if (first) { - DM_set_batch_cleanup_callback((DMCleanupBatchCache)MBC_discard); - first = false; - } - } - - return dm->batchCache; -} - -static VertexBuffer *MBC_get_pos_in_order(DerivedMesh *dm) -{ - MeshBatchCache *cache = MBC_get(dm); - - if (cache->pos_in_order == NULL) { - static VertexFormat format = { 0 }; - static unsigned pos_id; - if (format.attrib_ct == 0) { - /* initialize vertex format */ - pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT); - } - - const int vertex_ct = dm->getNumVerts(dm); - const MVert *verts = dm->getVertArray(dm); - const unsigned stride = (verts + 1) - verts; /* or sizeof(MVert) */ - - cache->pos_in_order = VertexBuffer_create_with_format(&format); - VertexBuffer_allocate_data(cache->pos_in_order, vertex_ct); -#if 0 - fillAttribStride(cache->pos_in_order, pos_id, stride, &verts[0].co); -#else - for (int i = 0; i < vertex_ct; ++i) { - setAttrib(cache->pos_in_order, pos_id, i, &verts[i].co); - } -#endif - } - - return cache->pos_in_order; -} - -static Batch *MBC_get_all_verts(DerivedMesh *dm) -{ - MeshBatchCache *cache = MBC_get(dm); - - if (cache->all_verts == NULL) { - /* create batch from DM */ - cache->all_verts = Batch_create(GL_POINTS, MBC_get_pos_in_order(dm), NULL); - Batch_set_builtin_program(cache->all_verts, GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR); - } - - return cache->all_verts; -} - -static ElementList *MBC_get_edges_in_order(DerivedMesh *dm) -{ - MeshBatchCache *cache = MBC_get(dm); - - if (cache->edges_in_order == NULL) { - const int vertex_ct = dm->getNumVerts(dm); - const int edge_ct = dm->getNumEdges(dm); - const MEdge *edges = dm->getEdgeArray(dm); - ElementListBuilder elb; - ElementListBuilder_init(&elb, GL_LINES, edge_ct, vertex_ct); - for (int i = 0; i < edge_ct; ++i) { - const MEdge *edge = edges + i; - add_line_vertices(&elb, edge->v1, edge->v2); - } - cache->edges_in_order = ElementList_build(&elb); - } - - return cache->edges_in_order; -} - -static ElementList *MBC_get_triangles_in_order(DerivedMesh *dm) -{ - MeshBatchCache *cache = MBC_get(dm); - - if (cache->triangles_in_order == NULL) { - const int vertex_ct = dm->getNumVerts(dm); - const int tessface_ct = dm->getNumTessFaces(dm); - const MFace *tessfaces = dm->getTessFaceArray(dm); - ElementListBuilder elb; - ElementListBuilder_init(&elb, GL_TRIANGLES, tessface_ct, vertex_ct); - for (int i = 0; i < tessface_ct; ++i) { - const MFace *tess = tessfaces + i; - add_triangle_vertices(&elb, tess->v1, tess->v2, tess->v3); - /* tessface can be triangle or quad */ - if (tess->v4) { - add_triangle_vertices(&elb, tess->v3, tess->v2, tess->v4); - } - } - cache->triangles_in_order = ElementList_build(&elb); - } - - return cache->triangles_in_order; -} - -static Batch *MBC_get_all_edges(DerivedMesh *dm) -{ - MeshBatchCache *cache = MBC_get(dm); - - if (cache->all_edges == NULL) { - /* create batch from DM */ - cache->all_edges = Batch_create(GL_LINES, MBC_get_pos_in_order(dm), MBC_get_edges_in_order(dm)); - } - - return cache->all_edges; -} - -static Batch *MBC_get_all_triangles(DerivedMesh *dm) -{ - MeshBatchCache *cache = MBC_get(dm); - - if (cache->all_triangles == NULL) { - /* create batch from DM */ - cache->all_triangles = Batch_create(GL_TRIANGLES, MBC_get_pos_in_order(dm), MBC_get_triangles_in_order(dm)); - } - - return cache->all_triangles; -} - -static Batch *MBC_get_fancy_edges(DerivedMesh *dm) -{ - MeshBatchCache *cache = MBC_get(dm); - - if (cache->fancy_edges == NULL) { - /* create batch from DM */ - static VertexFormat format = { 0 }; - static unsigned pos_id, n1_id, n2_id; - if (format.attrib_ct == 0) { - /* initialize vertex format */ - pos_id = add_attrib(&format, "pos", COMP_F32, 3, KEEP_FLOAT); - -#if USE_10_10_10 /* takes 1/3 the space */ - n1_id = add_attrib(&format, "N1", COMP_I10, 3, NORMALIZE_INT_TO_FLOAT); - n2_id = add_attrib(&format, "N2", COMP_I10, 3, NORMALIZE_INT_TO_FLOAT); -#else - n1_id = add_attrib(&format, "N1", COMP_F32, 3, KEEP_FLOAT); - n2_id = add_attrib(&format, "N2", COMP_F32, 3, KEEP_FLOAT); -#endif - } - VertexBuffer *vbo = VertexBuffer_create_with_format(&format); - - const MVert *verts = dm->getVertArray(dm); - const MEdge *edges = dm->getEdgeArray(dm); - const MPoly *polys = dm->getPolyArray(dm); - const MLoop *loops = dm->getLoopArray(dm); - const int edge_ct = dm->getNumEdges(dm); - const int poly_ct = dm->getNumPolys(dm); - - /* need normal of each face, and which faces are adjacent to each edge */ - typedef struct { - int count; - int face_index[2]; - } AdjacentFaces; - - float (*face_normal)[3] = MEM_mallocN(poly_ct * 3 * sizeof(float), "face_normal"); - AdjacentFaces *adj_faces = MEM_callocN(edge_ct * sizeof(AdjacentFaces), "adj_faces"); - - for (int i = 0; i < poly_ct; ++i) { - const MPoly *poly = polys + i; - - BKE_mesh_calc_poly_normal(poly, loops + poly->loopstart, verts, face_normal[i]); - - for (int j = poly->loopstart; j < (poly->loopstart + poly->totloop); ++j) { - AdjacentFaces *adj = adj_faces + loops[j].e; - if (adj->count < 2) - adj->face_index[adj->count] = i; - adj->count++; - } - } - - const int vertex_ct = edge_ct * 2; /* these are GL_LINE verts, not mesh verts */ - VertexBuffer_allocate_data(vbo, vertex_ct); - for (int i = 0; i < edge_ct; ++i) { - const MEdge *edge = edges + i; - const AdjacentFaces *adj = adj_faces + i; - -#if USE_10_10_10 - PackedNormal n1value = { .x = 0, .y = 0, .z = +511 }; - PackedNormal n2value = { .x = 0, .y = 0, .z = -511 }; - - if (adj->count == 2) { - n1value = convert_i10_v3(face_normal[adj->face_index[0]]); - n2value = convert_i10_v3(face_normal[adj->face_index[1]]); - } - - const PackedNormal *n1 = &n1value; - const PackedNormal *n2 = &n2value; -#else - const float dummy1[3] = { 0.0f, 0.0f, +1.0f }; - const float dummy2[3] = { 0.0f, 0.0f, -1.0f }; - - const float *n1 = (adj->count == 2) ? face_normal[adj->face_index[0]] : dummy1; - const float *n2 = (adj->count == 2) ? face_normal[adj->face_index[1]] : dummy2; -#endif - - setAttrib(vbo, pos_id, 2 * i, &verts[edge->v1].co); - setAttrib(vbo, n1_id, 2 * i, n1); - setAttrib(vbo, n2_id, 2 * i, n2); - - setAttrib(vbo, pos_id, 2 * i + 1, &verts[edge->v2].co); - setAttrib(vbo, n1_id, 2 * i + 1, n1); - setAttrib(vbo, n2_id, 2 * i + 1, n2); - } - - MEM_freeN(adj_faces); - MEM_freeN(face_normal); - - cache->fancy_edges = Batch_create(GL_LINES, vbo, NULL); - } - - return cache->fancy_edges; -} - -static bool edge_is_real(const MEdge *edges, int edge_ct, int v1, int v2) -{ - /* TODO: same thing, except not ridiculously slow */ - - for (int e = 0; e < edge_ct; ++e) { - const MEdge *edge = edges + e; - if ((edge->v1 == v1 && edge->v2 == v2) || (edge->v1 == v2 && edge->v2 == v1)) { - return true; - } - } - - return false; -} - -static void add_overlay_tri(VertexBuffer *vbo, unsigned pos_id, unsigned edgeMod_id, const MVert *verts, const MEdge *edges, int edge_ct, int v1, int v2, int v3, int base_vert_idx) -{ - const float edgeMods[2] = { 0.0f, 1.0f }; - - const float *pos = verts[v1].co; - setAttrib(vbo, pos_id, base_vert_idx + 0, pos); - setAttrib(vbo, edgeMod_id, base_vert_idx + 0, edgeMods + (edge_is_real(edges, edge_ct, v2, v3) ? 1 : 0)); - - pos = verts[v2].co; - setAttrib(vbo, pos_id, base_vert_idx + 1, pos); - setAttrib(vbo, edgeMod_id, base_vert_idx + 1, edgeMods + (edge_is_real(edges, edge_ct, v3, v1) ? 1 : 0)); - - pos = verts[v3].co; - setAttrib(vbo, pos_id, base_vert_idx + 2, pos); - setAttrib(vbo, edgeMod_id, base_vert_idx + 2, edgeMods + (edge_is_real(edges, edge_ct, v1, v2) ? 1 : 0)); -} - -static Batch *MBC_get_overlay_edges(DerivedMesh *dm) -{ - MeshBatchCache *cache = MBC_get(dm); - - if (cache->overlay_edges == NULL) { - /* create batch from DM */ - static VertexFormat format = { 0 }; - static unsigned pos_id, edgeMod_id; - if (format.attrib_ct == 0) { - /* initialize vertex format */ - pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT); - edgeMod_id = add_attrib(&format, "edgeWidthModulator", GL_FLOAT, 1, KEEP_FLOAT); - } - VertexBuffer *vbo = VertexBuffer_create_with_format(&format); - - const int vertex_ct = dm->getNumVerts(dm); - const int edge_ct = dm->getNumEdges(dm); - const int tessface_ct = dm->getNumTessFaces(dm); - const MVert *verts = dm->getVertArray(dm); - const MEdge *edges = dm->getEdgeArray(dm); - const MFace *tessfaces = dm->getTessFaceArray(dm); - - VertexBuffer_allocate_data(vbo, tessface_ct * 6); /* up to 2 triangles per tessface */ - - int gpu_vert_idx = 0; - for (int i = 0; i < tessface_ct; ++i) { - const MFace *tess = tessfaces + i; - add_overlay_tri(vbo, pos_id, edgeMod_id, verts, edges, edge_ct, tess->v1, tess->v2, tess->v3, gpu_vert_idx); - gpu_vert_idx += 3; - /* tessface can be triangle or quad */ - if (tess->v4) { - add_overlay_tri(vbo, pos_id, edgeMod_id, verts, edges, edge_ct, tess->v3, tess->v2, tess->v4, gpu_vert_idx); - gpu_vert_idx += 3; - } - } - - VertexBuffer_resize_data(vbo, gpu_vert_idx); - - cache->overlay_edges = Batch_create(GL_TRIANGLES, vbo, NULL); - } - - return cache->overlay_edges; -} static void drawcube_size(float size, unsigned pos); static void drawcircle_size(float size, unsigned pos); @@ -4370,11 +4037,10 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d, } static void draw_em_fancy_new(Scene *UNUSED(scene), ARegion *ar, View3D *UNUSED(v3d), - Object *UNUSED(ob), BMEditMesh *UNUSED(em), DerivedMesh *cageDM, DerivedMesh *UNUSED(finalDM), const char UNUSED(dt)) + Object *UNUSED(ob), Mesh *me, BMEditMesh *UNUSED(em), DerivedMesh *UNUSED(cageDM), DerivedMesh *UNUSED(finalDM), const char UNUSED(dt)) { /* for now... something simple! */ - - Batch *surface = MBC_get_all_triangles(cageDM); + Batch *surface = BKE_mesh_batch_cache_get_all_triangles(me); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); @@ -4408,7 +4074,7 @@ static void draw_em_fancy_new(Scene *UNUSED(scene), ARegion *ar, View3D *UNUSED( Batch_draw(surface); if (GLEW_VERSION_3_2) { - Batch *overlay = MBC_get_overlay_edges(cageDM); + Batch *overlay = BKE_mesh_batch_cache_get_overlay_edges(me); Batch_set_builtin_program(overlay, GPU_SHADER_EDGES_OVERLAY); Batch_Uniform2f(overlay, "viewportSize", ar->winx, ar->winy); Batch_draw(overlay); @@ -4426,7 +4092,7 @@ static void draw_em_fancy_new(Scene *UNUSED(scene), ARegion *ar, View3D *UNUSED( #endif } else { - Batch *edges = MBC_get_all_edges(cageDM); + Batch *edges = BKE_mesh_batch_cache_get_all_edges(me); Batch_set_builtin_program(edges, GPU_SHADER_3D_UNIFORM_COLOR); Batch_Uniform4f(edges, "color", 0.0f, 0.0f, 0.0f, 1.0f); glEnable(GL_LINE_SMOOTH); @@ -4436,7 +4102,7 @@ static void draw_em_fancy_new(Scene *UNUSED(scene), ARegion *ar, View3D *UNUSED( } #if 0 /* looks good even without points */ - Batch *verts = MBC_get_all_verts(cageDM); + Batch *verts = MBC_get_all_verts(me); glEnable(GL_BLEND); Batch_set_builtin_program(verts, GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_SMOOTH); @@ -4474,7 +4140,7 @@ void draw_mesh_object_outline(View3D *v3d, Object *ob, DerivedMesh *dm) /* LEGAC } } -static void draw_mesh_object_outline_new(View3D *v3d, RegionView3D *rv3d, Object *ob, DerivedMesh *dm, const bool is_active) +static void draw_mesh_object_outline_new(View3D *v3d, RegionView3D *rv3d, Object *ob, Mesh *me, const bool is_active) { if ((v3d->transp == false) && /* not when we draw the transparent pass */ (ob->mode & OB_MODE_ALL_PAINT) == false) /* not when painting (its distracting) - campbell */ @@ -4486,7 +4152,7 @@ static void draw_mesh_object_outline_new(View3D *v3d, RegionView3D *rv3d, Object UI_GetThemeColor4fv((is_active ? TH_ACTIVE : TH_SELECT), outline_color); #if 1 /* new version that draws only silhouette edges */ - Batch *fancy_edges = MBC_get_fancy_edges(dm); + Batch *fancy_edges = BKE_mesh_batch_cache_get_fancy_edges(me); if (rv3d->persp == RV3D_ORTHO) { Batch_set_builtin_program(fancy_edges, GPU_SHADER_EDGES_FRONT_BACK_ORTHO); @@ -5009,7 +4675,7 @@ static void draw_mesh_fancy_new(Scene *scene, ARegion *ar, View3D *v3d, RegionVi #if 1 /* fancy wireframes */ - Batch *fancy_edges = MBC_get_fancy_edges(dm); + Batch *fancy_edges = BKE_mesh_batch_cache_get_fancy_edges(me); if (rv3d->persp == RV3D_ORTHO) { Batch_set_builtin_program(fancy_edges, GPU_SHADER_EDGES_FRONT_BACK_ORTHO); @@ -5069,7 +4735,7 @@ static void draw_mesh_fancy_new(Scene *scene, ARegion *ar, View3D *v3d, RegionVi !(G.f & G_PICKSEL || (draw_flags & DRAW_FACE_SELECT)) && (draw_wire == OBDRAW_WIRE_OFF)) { - draw_mesh_object_outline_new(v3d, rv3d, ob, dm, (ob == OBACT)); + draw_mesh_object_outline_new(v3d, rv3d, ob, me, (ob == OBACT)); } if (draw_glsl_material(scene, ob, v3d, dt) && !(draw_flags & DRAW_MODIFIERS_PREVIEW)) { @@ -5136,7 +4802,7 @@ static void draw_mesh_fancy_new(Scene *scene, ARegion *ar, View3D *v3d, RegionVi (draw_wire == OBDRAW_WIRE_OFF) && (ob->sculpt == NULL)) { - draw_mesh_object_outline_new(v3d, rv3d, ob, dm, (ob == OBACT)); + draw_mesh_object_outline_new(v3d, rv3d, ob, me, (ob == OBACT)); } /* materials arent compatible with vertex colors */ @@ -5161,7 +4827,7 @@ static void draw_mesh_fancy_new(Scene *scene, ARegion *ar, View3D *v3d, RegionVi (ob->sculpt == NULL)) { /* TODO: move this into a separate pass */ - draw_mesh_object_outline_new(v3d, rv3d, ob, dm, (ob == OBACT)); + draw_mesh_object_outline_new(v3d, rv3d, ob, me, (ob == OBACT)); } glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW); @@ -5310,7 +4976,7 @@ static bool draw_mesh_object_new(Scene *scene, ARegion *ar, View3D *v3d, RegionV GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, NULL); } - draw_em_fancy_new(scene, ar, v3d, ob, em, cageDM, finalDM, dt); + draw_em_fancy_new(scene, ar, v3d, ob, me, em, cageDM, finalDM, dt); if (use_material) { GPU_end_object_materials(); diff --git a/source/blender/gpu/gawain/batch.h b/source/blender/gpu/gawain/batch.h index c2768377a96..932ee182703 100644 --- a/source/blender/gpu/gawain/batch.h +++ b/source/blender/gpu/gawain/batch.h @@ -21,7 +21,7 @@ typedef enum { READY_TO_DRAW } BatchPhase; -typedef struct { +typedef struct Batch{ // geometry VertexBuffer* verts; ElementList* elem; // NULL if element list not needed diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h index 39e56925903..15ea3d4d37a 100644 --- a/source/blender/makesdna/DNA_mesh_types.h +++ b/source/blender/makesdna/DNA_mesh_types.h @@ -127,6 +127,7 @@ typedef struct Mesh { short totcol; struct Multires *mr DNA_DEPRECATED; /* deprecated multiresolution modeling data, only keep for loading old files */ + void *batch_cache; } Mesh; /* deprecated by MTFace, only here for file reading */ |