DWM: Use draw manager for sculpt PBVH drawing

Add a shader-group type to draw
generated geometry by running a callback.
This commit is contained in:
Campbell Barton
2017-05-11 21:21:59 +10:00
parent f1242ea93b
commit 5ae58f8ab8
7 changed files with 248 additions and 62 deletions

View File

@@ -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 {

View File

@@ -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)
{

View File

@@ -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__}; \

View File

@@ -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();

View File

@@ -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;
/* Add geom to a shading group */
DRW_shgroup_call_add(stl->g_data->group, geom, ob->obmat);
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_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 */

View File

@@ -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);

View File

@@ -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];