diff options
-rw-r--r-- | source/blender/blenkernel/BKE_pbvh.h | 4 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/pbvh.c | 61 | ||||
-rw-r--r-- | source/blender/draw/intern/DRW_render.h | 8 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_manager.c | 90 | ||||
-rw-r--r-- | source/blender/draw/modes/sculpt_mode.c | 95 | ||||
-rw-r--r-- | source/blender/gpu/GPU_buffers.h | 2 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_buffers.c | 48 |
7 files changed, 247 insertions, 61 deletions
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index 927303f8b3c..53180713cf9 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -30,6 +30,7 @@ #include "BLI_ghash.h" #include "BLI_utildefines.h" +struct Batch; struct CCGElem; struct CCGKey; struct CustomData; @@ -118,6 +119,9 @@ void BKE_pbvh_raycast_project_ray_root( void BKE_pbvh_node_draw(PBVHNode *node, void *data); void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3], int (*setMaterial)(int matnr, void *attribs), bool wireframe, bool fast); +void BKE_pbvh_draw_cb( + PBVH *bvh, float (*planes)[4], float (*fnors)[3], bool fast, + void (*draw_fn)(void *user_data, struct Batch *batch), void *user_data); /* PBVH Access */ typedef enum { diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index 6bfb9d779c2..02b4479df4f 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -1845,6 +1845,67 @@ void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*fnors)[3], pbvh_draw_BB(bvh); } +struct PBVHNodeDrawCallbackData { + + void (*draw_fn)(void *user_data, Batch *batch); + void *user_data; + bool fast; +}; + +static void pbvh_node_draw_cb(PBVHNode *node, void *data_v) +{ + struct PBVHNodeDrawCallbackData *data = data_v; + + if (!(node->flag & PBVH_FullyHidden)) { + Batch *triangles = GPU_draw_pbvh_buffers_get_batch(node->draw_buffers, data->fast); + if (triangles != NULL) { + data->draw_fn(data->user_data, triangles); + } + } +} + +/** + * Version of #BKE_pbvh_draw that runs a callback. + */ +void BKE_pbvh_draw_cb( + PBVH *bvh, float (*planes)[4], float (*fnors)[3], bool fast, + void (*draw_fn)(void *user_data, Batch *batch), void *user_data) +{ + struct PBVHNodeDrawCallbackData draw_data = { + .fast = fast, + .draw_fn = draw_fn, + .user_data = user_data, + }; + PBVHNode **nodes; + int totnode; + + for (int a = 0; a < bvh->totnode; a++) + pbvh_node_check_diffuse_changed(bvh, &bvh->nodes[a]); + + BKE_pbvh_search_gather(bvh, update_search_cb, SET_INT_IN_POINTER(PBVH_UpdateNormals | PBVH_UpdateDrawBuffers), + &nodes, &totnode); + + pbvh_update_normals(bvh, nodes, totnode, fnors); + pbvh_update_draw_buffers(bvh, nodes, totnode); + + if (nodes) MEM_freeN(nodes); + + if (planes) { + BKE_pbvh_search_callback( + bvh, BKE_pbvh_node_planes_contain_AABB, + planes, pbvh_node_draw_cb, &draw_data); + } + else { + BKE_pbvh_search_callback( + bvh, NULL, + NULL, pbvh_node_draw_cb, &draw_data); + } +#if 0 + if (G.debug_value == 14) + pbvh_draw_BB(bvh); +#endif +} + void BKE_pbvh_grids_update(PBVH *bvh, CCGElem **grids, void **gridfaces, DMFlagMat *flagmats, BLI_bitmap **grid_hidden) { diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index 1cdb213d86f..bcc3277adc9 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -254,6 +254,7 @@ typedef enum { DRWShadingGroup *DRW_shgroup_create(struct GPUShader *shader, DRWPass *pass); +DRWShadingGroup *DRW_shgroup_create_fn(struct GPUShader *shader, DRWPass *pass); DRWShadingGroup *DRW_shgroup_material_create(struct GPUMaterial *material, DRWPass *pass); DRWShadingGroup *DRW_shgroup_material_instance_create(struct GPUMaterial *material, DRWPass *pass, struct Batch *geom); DRWShadingGroup *DRW_shgroup_instance_create(struct GPUShader *shader, DRWPass *pass, struct Batch *geom); @@ -261,8 +262,15 @@ DRWShadingGroup *DRW_shgroup_point_batch_create(struct GPUShader *shader, DRWPas DRWShadingGroup *DRW_shgroup_line_batch_create(struct GPUShader *shader, DRWPass *pass); DRWShadingGroup *DRW_shgroup_empty_tri_batch_create(struct GPUShader *shader, DRWPass *pass, int size); +typedef void (DRWCallGenerateFn)( + DRWShadingGroup *shgroup, + void (*draw_fn)(DRWShadingGroup *shgroup, struct Batch *geom), + void *user_data); + void DRW_shgroup_free(struct DRWShadingGroup *shgroup); void DRW_shgroup_call_add(DRWShadingGroup *shgroup, struct Batch *geom, float (*obmat)[4]); +void DRW_shgroup_call_generate_add( + DRWShadingGroup *shgroup, DRWCallGenerateFn *geometry_fn, void *user_data, float (*obmat)[4]); void DRW_shgroup_call_dynamic_add_array(DRWShadingGroup *shgroup, const void *attr[], unsigned int attr_len); #define DRW_shgroup_call_dynamic_add(shgroup, ...) do { \ const void *array[] = {__VA_ARGS__}; \ diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index df3b4d03d8b..33456e20163 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -189,10 +189,21 @@ typedef struct DRWCall { #ifdef USE_GPU_SELECT int select_id; #endif - Batch *geometry; float (*obmat)[4]; + Batch *geometry; } DRWCall; +typedef struct DRWCallGenerate { + struct DRWCallGenerate *next, *prev; +#ifdef USE_GPU_SELECT + int select_id; +#endif + float (*obmat)[4]; + + DRWCallGenerateFn *geometry_fn; + void *user_data; +} DRWCallGenerate; + typedef struct DRWCallDynamic { struct DRWCallDynamic *next, *prev; #ifdef USE_GPU_SELECT @@ -222,6 +233,8 @@ struct DRWShadingGroup { /* Used by DRWShadingGroup.type */ enum { DRW_SHG_NORMAL, + /* same as 'DRW_SHG_NORMAL' but use a callback to generate geometry */ + DRW_SHG_NORMAL_GENERATE, DRW_SHG_POINT_BATCH, DRW_SHG_LINE_BATCH, DRW_SHG_TRIANGLE_BATCH, @@ -646,6 +659,15 @@ DRWShadingGroup *DRW_shgroup_create(struct GPUShader *shader, DRWPass *pass) return shgroup; } +DRWShadingGroup *DRW_shgroup_create_fn(struct GPUShader *shader, DRWPass *pass) +{ + DRWShadingGroup *shgroup = DRW_shgroup_create(shader, pass); + + shgroup->type = DRW_SHG_NORMAL_GENERATE; + + return shgroup; +} + DRWShadingGroup *DRW_shgroup_material_create(struct GPUMaterial *material, DRWPass *pass) { double time = 0.0; /* TODO make time variable */ @@ -796,6 +818,28 @@ void DRW_shgroup_call_add(DRWShadingGroup *shgroup, Batch *geom, float (*obmat)[ BLI_addtail(&shgroup->calls, call); } +void DRW_shgroup_call_generate_add( + DRWShadingGroup *shgroup, + DRWCallGenerateFn *geometry_fn, void *user_data, + float (*obmat)[4]) +{ + BLI_assert(geometry_fn != NULL); + BLI_assert(shgroup->type == DRW_SHG_NORMAL_GENERATE); + + DRWCallGenerate *call = MEM_callocN(sizeof(DRWCallGenerate), "DRWCallGenerate"); + + call->obmat = obmat; + + call->geometry_fn = geometry_fn; + call->user_data = user_data; + +#ifdef USE_GPU_SELECT + call->select_id = g_DRW_select_id; +#endif + + BLI_addtail(&shgroup->calls, call); +} + void DRW_shgroup_call_dynamic_add_array(DRWShadingGroup *shgroup, const void *attr[], unsigned int attr_len) { DRWInterface *interface = shgroup->interface; @@ -1348,7 +1392,7 @@ typedef struct DRWBoundTexture { GPUTexture *tex; } DRWBoundTexture; -static void draw_geometry(DRWShadingGroup *shgroup, Batch *geom, const float (*obmat)[4]) +static void draw_geometry_prepare(DRWShadingGroup *shgroup, const float (*obmat)[4]) { RegionView3D *rv3d = DST.draw_ctx.rv3d; DRWInterface *interface = shgroup->interface; @@ -1445,7 +1489,11 @@ static void draw_geometry(DRWShadingGroup *shgroup, Batch *geom, const float (*o if (interface->eye != -1) { GPU_shader_uniform_vector(shgroup->shader, interface->eye, 3, 1, (float *)eye); } +} +static void draw_geometry_execute(DRWShadingGroup *shgroup, Batch *geom) +{ + DRWInterface *interface = shgroup->interface; /* step 2 : bind vertex array & draw */ Batch_set_program(geom, GPU_shader_get_program(shgroup->shader), GPU_shader_get_interface(shgroup->shader)); if (interface->instance_vbo) { @@ -1457,6 +1505,13 @@ static void draw_geometry(DRWShadingGroup *shgroup, Batch *geom, const float (*o } } +static void draw_geometry(DRWShadingGroup *shgroup, Batch *geom, const float (*obmat)[4]) +{ + draw_geometry_prepare(shgroup, obmat); + + draw_geometry_execute(shgroup, geom); +} + static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) { BLI_assert(shgroup->shader); @@ -1472,7 +1527,9 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) DST.shader = shgroup->shader; } - if (shgroup->type != DRW_SHG_NORMAL) { + const bool is_normal = ELEM(shgroup->type, DRW_SHG_NORMAL, DRW_SHG_NORMAL_GENERATE); + + if (!is_normal) { shgroup_dynamic_batch_from_calls(shgroup); } @@ -1547,7 +1604,7 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) #endif /* Rendering Calls */ - if (shgroup->type != DRW_SHG_NORMAL) { + if (!is_normal) { /* Replacing multiple calls with only one */ float obmat[4][4]; unit_m4(obmat); @@ -1564,7 +1621,7 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) } } } - else { + else if (shgroup->type == DRW_SHG_NORMAL) { for (DRWCall *call = shgroup->calls.first; call; call = call->next) { bool neg_scale = call->obmat && is_negative_m4(call->obmat); @@ -1582,6 +1639,29 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) } } } + else if (shgroup->type == DRW_SHG_NORMAL_GENERATE) { + /* Same as 'DRW_SHG_NORMAL' but generate batches */ + for (DRWCallGenerate *call = shgroup->calls.first; call; call = call->next) { + bool neg_scale = call->obmat && is_negative_m4(call->obmat); + + /* Negative scale objects */ + if (neg_scale) { + glFrontFace(GL_CW); + } + + GPU_SELECT_LOAD_IF_PICKSEL(call); + draw_geometry_prepare(shgroup, call->obmat); + call->geometry_fn(shgroup, draw_geometry_execute, call->user_data); + + /* Reset state */ + if (neg_scale) { + glFrontFace(GL_CCW); + } + } + } + else { + BLI_assert(0); + } /* TODO: remove, (currently causes alpha issue with sculpt, need to investigate) */ DRW_state_reset(); diff --git a/source/blender/draw/modes/sculpt_mode.c b/source/blender/draw/modes/sculpt_mode.c index 114bc8c96c4..ba9219c9abb 100644 --- a/source/blender/draw/modes/sculpt_mode.c +++ b/source/blender/draw/modes/sculpt_mode.c @@ -27,6 +27,8 @@ #include "DRW_render.h" #include "DNA_object_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" #include "BKE_pbvh.h" #include "BKE_paint.h" @@ -93,13 +95,15 @@ static struct { * Add sources to source/blender/draw/modes/shaders * init in SCULPT_engine_init(); * free in SCULPT_engine_free(); */ - struct GPUShader *custom_shader; + struct GPUShader *shader_flat; + struct GPUShader *shader_smooth; } e_data = {NULL}; /* Engine data */ typedef struct SCULPT_PrivateData { /* This keeps the references of the shading groups for * easy access in SCULPT_cache_populate() */ - DRWShadingGroup *group; + DRWShadingGroup *group_flat; + DRWShadingGroup *group_smooth; } SCULPT_PrivateData; /* Transient data */ /* *********** FUNCTIONS *********** */ @@ -130,8 +134,11 @@ static void SCULPT_engine_init(void *vedata) * tex, 2); */ - if (!e_data.custom_shader) { - e_data.custom_shader = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR); + if (!e_data.shader_flat) { + e_data.shader_flat = GPU_shader_get_builtin_shader(GPU_SHADER_SIMPLE_LIGHTING_FLAT_COLOR); + } + if (!e_data.shader_smooth) { + e_data.shader_smooth = GPU_shader_get_builtin_shader(GPU_SHADER_SIMPLE_LIGHTING_SMOOTH_COLOR); } } @@ -149,8 +156,8 @@ static void SCULPT_cache_init(void *vedata) { /* Create a pass */ - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_BLEND | DRW_STATE_WIRE; - psl->pass = DRW_pass_create("My Pass", state); + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS; + psl->pass = DRW_pass_create("Sculpt Pass", state); /* Create a shadingGroup using a function in draw_common.c or custom one */ /* @@ -158,14 +165,53 @@ static void SCULPT_cache_init(void *vedata) * -- or -- * stl->g_data->group = DRW_shgroup_create(e_data.custom_shader, psl->pass); */ - stl->g_data->group = DRW_shgroup_create(e_data.custom_shader, psl->pass); + stl->g_data->group_flat = DRW_shgroup_create_fn(e_data.shader_flat, psl->pass); + stl->g_data->group_smooth = DRW_shgroup_create_fn(e_data.shader_smooth, psl->pass); /* Uniforms need a pointer to it's value so be sure it's accessible at * any given time (i.e. use static vars) */ - static float color[4] = {0.2f, 0.5f, 0.3f, 1.0}; - DRW_shgroup_uniform_vec4(stl->g_data->group, "color", color, 1); + static float light[3] = {-0.3f, 0.5f, 1.0f}; + static float alpha = 1.0f; + static float world_light = 1.0f; + + DRWShadingGroup *group_arr[2] = { + stl->g_data->group_flat, + stl->g_data->group_smooth, + }; + + for (uint i = 0; i < 2; i++) { + DRWShadingGroup *group = group_arr[i]; + DRW_shgroup_uniform_vec3(group, "light", light, 1); + DRW_shgroup_uniform_float(group, "global", &world_light, 1); + DRW_shgroup_uniform_float(group, "alpha", &alpha, 1); + } } +} +static bool object_is_flat(const Object *ob) +{ + Mesh *me = ob->data; + if (me->mpoly && me->mpoly[0].flag & ME_SMOOTH) { + return false; + } + else { + return true; + } +} + +static void sculpt_draw_cb( + DRWShadingGroup *shgroup, + void (*draw_fn)(DRWShadingGroup *shgroup, struct Batch *geom), + void *user_data) +{ + Object *ob = user_data; + PBVH *pbvh = ob->sculpt->pbvh; + + if (pbvh) { + BKE_pbvh_draw_cb( + pbvh, NULL, NULL, false, + (void (*)(void *, struct Batch *))draw_fn, shgroup); + } } /* Add geometry to shadingGroups. Execute for each objects */ @@ -177,11 +223,16 @@ static void SCULPT_cache_populate(void *vedata, Object *ob) UNUSED_VARS(psl, stl); if (ob->type == OB_MESH) { - /* Get geometry cache */ - struct Batch *geom = DRW_cache_mesh_surface_get(ob); + const DRWContextState *draw_ctx = DRW_context_state_get(); + SceneLayer *sl = draw_ctx->sl; + + if (ob == OBACT_NEW) { + /* Get geometry cache */ + DRWShadingGroup *shgroup = object_is_flat(ob) ? stl->g_data->group_flat : stl->g_data->group_smooth; - /* Add geom to a shading group */ - DRW_shgroup_call_add(stl->g_data->group, geom, ob->obmat); + /* Add geom to a shading group */ + DRW_shgroup_call_generate_add(shgroup, sculpt_draw_cb, ob, ob->obmat); + } } } @@ -198,7 +249,7 @@ static void SCULPT_cache_finish(void *vedata) /* Draw time ! Control rendering pipeline from here */ static void SCULPT_draw_scene(void *vedata) { -// SCULPT_PassList *psl = ((SCULPT_Data *)vedata)->psl; + SCULPT_PassList *psl = ((SCULPT_Data *)vedata)->psl; SCULPT_FramebufferList *fbl = ((SCULPT_Data *)vedata)->fbl; /* Default framebuffer and texture */ @@ -217,21 +268,7 @@ static void SCULPT_draw_scene(void *vedata) */ /* ... or just render passes on default framebuffer. */ -// DRW_draw_pass(psl->pass); - - { - const DRWContextState *draw_ctx = DRW_context_state_get(); - SceneLayer *sl = draw_ctx->sl; - Object *ob = OBACT_NEW; - - PBVH *pbvh = ob->sculpt->pbvh; - - /* this shader is used inside draw call */ - gpuPushMatrix(); - gpuMultMatrix(ob->obmat); - BKE_pbvh_draw(pbvh, NULL, NULL, NULL, false, false); - gpuPopMatrix(); - } + DRW_draw_pass(psl->pass); /* If you changed framebuffer, double check you rebind * the default one with its textures attached before finishing */ diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h index 958d5aed4a4..661562e2e4c 100644 --- a/source/blender/gpu/GPU_buffers.h +++ b/source/blender/gpu/GPU_buffers.h @@ -51,6 +51,7 @@ struct GPUVertPointLink; struct GPUDrawObject; struct GridCommonGPUBuffer; struct PBVH; +struct Batch; struct MVert; typedef struct GPUBuffer { @@ -257,6 +258,7 @@ void GPU_update_grid_pbvh_buffers(GPU_PBVH_Buffers *buffers, struct CCGElem **gr /* draw */ void GPU_draw_pbvh_buffers(GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial, bool wireframe, bool fast); +struct Batch *GPU_draw_pbvh_buffers_get_batch(GPU_PBVH_Buffers *buffers, bool fast); /* debug PBVH draw */ void GPU_draw_pbvh_BB(float min[3], float max[3], bool leaf, unsigned int pos); diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index 707bdf7d829..8a3c0c91b65 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -1015,10 +1015,6 @@ static void gpu_pbvh_vert_format_init__gwn(VertexFormat *format, VertexBufferAtt static void gpu_pbvh_batch_init(GPU_PBVH_Buffers *buffers) { - GPUBuiltinShader shader_id = - buffers->smooth ? GPU_SHADER_SIMPLE_LIGHTING_SMOOTH_COLOR : GPU_SHADER_SIMPLE_LIGHTING_FLAT_COLOR; - GPUShader *shader = GPU_shader_get_builtin_shader(shader_id); - /* force flushing to the GPU */ if (buffers->vert_buf->data) { VertexBuffer_use(buffers->vert_buf); @@ -1029,10 +1025,6 @@ static void gpu_pbvh_batch_init(GPU_PBVH_Buffers *buffers) PRIM_TRIANGLES, buffers->vert_buf, /* can be NULL */ buffers->index_buf); - Batch_set_program( - buffers->triangles, - GPU_shader_get_program(shader), GPU_shader_get_interface(shader)); - BATCH_DISCARD_SAFE(buffers->triangles_fast); if (buffers->index_buf_fast) { @@ -1040,10 +1032,6 @@ static void gpu_pbvh_batch_init(GPU_PBVH_Buffers *buffers) PRIM_TRIANGLES, buffers->vert_buf, /* can be NULL */ buffers->index_buf_fast); - - Batch_set_program( - buffers->triangles_fast, - GPU_shader_get_program(shader), GPU_shader_get_interface(shader)); } } @@ -1214,7 +1202,13 @@ GPU_PBVH_Buffers *GPU_build_mesh_pbvh_buffers( buffers = MEM_callocN(sizeof(GPU_PBVH_Buffers), "GPU_Buffers"); + /* smooth or flat for all */ +#if 0 buffers->smooth = mpoly[looptri[face_indices[0]].poly].flag & ME_SMOOTH; +#else + /* for DrawManager we dont support mixed smooth/flat */ + buffers->smooth = (mpoly[0].flag & ME_SMOOTH) != 0; +#endif buffers->show_diffuse_color = false; buffers->use_matcaps = false; @@ -1830,29 +1824,29 @@ void GPU_draw_pbvh_buffers( bool wireframe, bool fast) { UNUSED_VARS(wireframe, fast, setMaterial); - - { - GPUBuiltinShader shader_id = - buffers->smooth ? GPU_SHADER_SIMPLE_LIGHTING_SMOOTH_COLOR : GPU_SHADER_SIMPLE_LIGHTING_FLAT_COLOR; - GPUShader *shader = GPU_shader_get_builtin_shader(shader_id); - - static float light[3] = {-0.3f, 0.5f, 1.0f}; - static float alpha = 1.0f; - static float world_light = 1.0f; - - GPU_shader_uniform_vector(shader, GPU_shader_get_uniform(shader, "light"), 3, 1, light); - GPU_shader_uniform_vector(shader, GPU_shader_get_uniform(shader, "alpha"), 1, 1, &alpha); - GPU_shader_uniform_vector(shader, GPU_shader_get_uniform(shader, "global"), 1, 1, &world_light); - } - bool do_fast = fast && buffers->triangles_fast; Batch *triangles = do_fast ? buffers->triangles_fast : buffers->triangles; if (triangles) { + if (triangles->interface == NULL) { + GPUBuiltinShader shader_id = + buffers->smooth ? GPU_SHADER_SIMPLE_LIGHTING_SMOOTH_COLOR : GPU_SHADER_SIMPLE_LIGHTING_FLAT_COLOR; + GPUShader *shader = GPU_shader_get_builtin_shader(shader_id); + + Batch_set_program( + triangles, + GPU_shader_get_program(shader), GPU_shader_get_interface(shader)); + } Batch_draw(triangles); } } +Batch *GPU_draw_pbvh_buffers_get_batch(GPU_PBVH_Buffers *buffers, bool fast) +{ + return (fast && buffers->triangles_fast) ? + buffers->triangles_fast : buffers->triangles; +} + bool GPU_pbvh_buffers_diffuse_changed(GPU_PBVH_Buffers *buffers, GSet *bm_faces, bool show_diffuse_color) { float diffuse_color[4]; |