DRW: Add visibility callback function.

This add a callback function that runs after frustum culling test.

This callback returns the final visibility for this object.

Be aware that it's called for EVERY drawcalls that use this callback even
if their visibility has been cached.
This commit is contained in:
Clément Foucault 2018-04-24 12:29:15 +02:00
parent 8fb9dfbec5
commit 2ff8f965df
4 changed files with 54 additions and 8 deletions

@ -336,11 +336,19 @@ typedef void (DRWCallGenerateFn)(
void (*draw_fn)(DRWShadingGroup *shgroup, struct Gwn_Batch *geom),
void *user_data);
/* return final visibility */
typedef bool (DRWCallVisibilityFn)(
bool vis_in,
void *user_data);
void DRW_shgroup_instance_batch(DRWShadingGroup *shgroup, struct Gwn_Batch *batch);
void DRW_shgroup_free(struct DRWShadingGroup *shgroup);
void DRW_shgroup_call_add(DRWShadingGroup *shgroup, struct Gwn_Batch *geom, float (*obmat)[4]);
void DRW_shgroup_call_object_add(DRWShadingGroup *shgroup, struct Gwn_Batch *geom, struct Object *ob);
void DRW_shgroup_call_object_add_with_callback(
DRWShadingGroup *shgroup, struct Gwn_Batch *geom, struct Object *ob,
DRWCallVisibilityFn *callback, void *user_data);
/* Used for drawing a batch with instancing without instance attribs. */
void DRW_shgroup_call_instances_add(
DRWShadingGroup *shgroup, struct Gwn_Batch *geom, float (*obmat)[4], unsigned int *count);

@ -102,6 +102,9 @@ enum {
};
typedef struct DRWCallState {
DRWCallVisibilityFn *visibility_cb;
void *user_data;
unsigned char flag;
unsigned char cache_id; /* Compared with DST.state_cache_id to see if matrices are still valid. */
uint16_t matflag; /* Which matrices to compute. */

@ -274,6 +274,7 @@ static DRWCallState *drw_call_state_create(DRWShadingGroup *shgroup, float (*obm
DRWCallState *state = BLI_mempool_alloc(DST.vmempool->states);
state->flag = 0;
state->cache_id = 0;
state->visibility_cb = NULL;
state->matflag = shgroup->matflag;
/* Matrices */
@ -357,6 +358,26 @@ void DRW_shgroup_call_object_add(DRWShadingGroup *shgroup, Gwn_Batch *geom, Obje
BLI_LINKS_APPEND(&shgroup->calls, call);
}
void DRW_shgroup_call_object_add_with_callback(
DRWShadingGroup *shgroup, Gwn_Batch *geom, Object *ob,
DRWCallVisibilityFn *callback, void *user_data)
{
BLI_assert(geom != NULL);
BLI_assert(shgroup->type == DRW_SHG_NORMAL);
DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls);
call->state = drw_call_state_object(shgroup, ob->obmat, ob);
call->state->visibility_cb = callback;
call->state->user_data = user_data;
call->type = DRW_CALL_SINGLE;
call->single.geometry = geom;
#ifdef USE_GPU_SELECT
call->select_id = DST.select_id;
#endif
BLI_LINKS_APPEND(&shgroup->calls, call);
}
void DRW_shgroup_call_instances_add(DRWShadingGroup *shgroup, Gwn_Batch *geom, float (*obmat)[4], unsigned int *count)
{
BLI_assert(geom != NULL);

@ -644,22 +644,35 @@ bool DRW_culling_box_test(BoundBox *bbox)
/** \name Draw (DRW_draw)
* \{ */
static void draw_visibility_eval(DRWCallState *st)
{
bool culled = st->flag & DRW_CALL_CULLED;
if (st->cache_id != DST.state_cache_id) {
/* Update culling result for this view. */
culled = !DRW_culling_sphere_test(&st->bsphere);
}
if (st->visibility_cb) {
culled = !st->visibility_cb(!culled, st->user_data);
}
SET_FLAG_FROM_TEST(st->flag, culled, DRW_CALL_CULLED);
}
static void draw_matrices_model_prepare(DRWCallState *st)
{
if (st->cache_id == DST.state_cache_id) {
return; /* Values are already updated for this view. */
/* Values are already updated for this view. */
return;
}
else {
st->cache_id = DST.state_cache_id;
}
if (DRW_culling_sphere_test(&st->bsphere)) {
st->flag &= ~DRW_CALL_CULLED;
}
else {
st->flag |= DRW_CALL_CULLED;
return; /* No need to go further the call will not be used. */
}
/* No need to go further the call will not be used. */
if (st->flag & DRW_CALL_CULLED)
return;
/* Order matters */
if (st->matflag & (DRW_CALL_MODELVIEW | DRW_CALL_MODELVIEWINVERSE |
@ -1014,6 +1027,7 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
for (DRWCall *call = shgroup->calls.first; call; call = call->next) {
/* OPTI/IDEA(clem): Do this preparation in another thread. */
draw_visibility_eval(call->state);
draw_matrices_model_prepare(call->state);
if ((call->state->flag & DRW_CALL_CULLED) != 0)