A lot of code in codegen was used by previous GLSL system. Now most of it is not used due to all the things being written from scratch in 2.8 and we can clean most of it. As a side not this make the system a bit less flexible (no support for cubemaps, preview image, etc...) but can be extended again.
1131 lines
34 KiB
C
1131 lines
34 KiB
C
/*
|
|
* Copyright 2016, Blender Foundation.
|
|
*
|
|
* 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.
|
|
*
|
|
* Contributor(s): Blender Institute
|
|
*
|
|
*/
|
|
|
|
/** \file blender/draw/intern/draw_manager_data.c
|
|
* \ingroup draw
|
|
*/
|
|
|
|
#include "draw_manager.h"
|
|
|
|
#include "BKE_curve.h"
|
|
#include "BKE_global.h"
|
|
#include "BKE_mesh.h"
|
|
#include "BKE_object.h"
|
|
#include "BKE_paint.h"
|
|
#include "BKE_pbvh.h"
|
|
|
|
#include "DNA_curve_types.h"
|
|
#include "DNA_mesh_types.h"
|
|
#include "DNA_meta_types.h"
|
|
|
|
#include "BLI_link_utils.h"
|
|
#include "BLI_mempool.h"
|
|
|
|
#include "intern/gpu_codegen.h"
|
|
|
|
struct GPUVertFormat *g_pos_format = NULL;
|
|
|
|
extern struct GPUUniformBuffer *view_ubo; /* draw_manager_exec.c */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Uniform Buffer Object (DRW_uniformbuffer)
|
|
* \{ */
|
|
|
|
GPUUniformBuffer *DRW_uniformbuffer_create(int size, const void *data)
|
|
{
|
|
return GPU_uniformbuffer_create(size, data, NULL);
|
|
}
|
|
|
|
void DRW_uniformbuffer_update(GPUUniformBuffer *ubo, const void *data)
|
|
{
|
|
GPU_uniformbuffer_update(ubo, data);
|
|
}
|
|
|
|
void DRW_uniformbuffer_free(GPUUniformBuffer *ubo)
|
|
{
|
|
GPU_uniformbuffer_free(ubo);
|
|
}
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Uniforms (DRW_shgroup_uniform)
|
|
* \{ */
|
|
|
|
static void drw_shgroup_uniform_create_ex(DRWShadingGroup *shgroup, int loc,
|
|
DRWUniformType type, const void *value, int length, int arraysize)
|
|
{
|
|
DRWUniform *uni = BLI_mempool_alloc(DST.vmempool->uniforms);
|
|
uni->location = loc;
|
|
uni->type = type;
|
|
uni->length = length;
|
|
uni->arraysize = arraysize;
|
|
|
|
switch (type) {
|
|
case DRW_UNIFORM_INT_COPY:
|
|
uni->ivalue = *((int *)value);
|
|
break;
|
|
case DRW_UNIFORM_BOOL_COPY:
|
|
uni->ivalue = (int)*((bool *)value);
|
|
break;
|
|
case DRW_UNIFORM_FLOAT_COPY:
|
|
uni->fvalue = *((float *)value);
|
|
break;
|
|
default:
|
|
uni->pvalue = value;
|
|
break;
|
|
}
|
|
|
|
BLI_LINKS_PREPEND(shgroup->uniforms, uni);
|
|
}
|
|
|
|
static void drw_shgroup_builtin_uniform(
|
|
DRWShadingGroup *shgroup, int builtin, const void *value, int length, int arraysize)
|
|
{
|
|
int loc = GPU_shader_get_builtin_uniform(shgroup->shader, builtin);
|
|
|
|
if (loc != -1) {
|
|
drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_FLOAT, value, length, arraysize);
|
|
}
|
|
}
|
|
|
|
static void drw_shgroup_uniform(DRWShadingGroup *shgroup, const char *name,
|
|
DRWUniformType type, const void *value, int length, int arraysize)
|
|
{
|
|
int location;
|
|
if (ELEM(type, DRW_UNIFORM_BLOCK, DRW_UNIFORM_BLOCK_PERSIST)) {
|
|
location = GPU_shader_get_uniform_block(shgroup->shader, name);
|
|
}
|
|
else {
|
|
location = GPU_shader_get_uniform(shgroup->shader, name);
|
|
}
|
|
|
|
if (location == -1) {
|
|
if (G.debug & G_DEBUG)
|
|
fprintf(stderr, "Pass : %s, Uniform '%s' not found!\n", shgroup->pass_parent->name, name);
|
|
/* Nice to enable eventually, for now eevee uses uniforms that might not exist. */
|
|
// BLI_assert(0);
|
|
return;
|
|
}
|
|
|
|
BLI_assert(arraysize > 0 && arraysize <= 16);
|
|
BLI_assert(length >= 0 && length <= 16);
|
|
|
|
drw_shgroup_uniform_create_ex(shgroup, location, type, value, length, arraysize);
|
|
|
|
#ifndef NDEBUG
|
|
/* Save uniform name to easily identify it when debugging. */
|
|
BLI_strncpy(shgroup->uniforms->name, name, MAX_UNIFORM_NAME);
|
|
#endif
|
|
}
|
|
|
|
void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, const GPUTexture *tex)
|
|
{
|
|
BLI_assert(tex != NULL);
|
|
drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_TEXTURE, tex, 0, 1);
|
|
}
|
|
|
|
/* Same as DRW_shgroup_uniform_texture but is garanteed to be bound if shader does not change between shgrp. */
|
|
void DRW_shgroup_uniform_texture_persistent(DRWShadingGroup *shgroup, const char *name, const GPUTexture *tex)
|
|
{
|
|
BLI_assert(tex != NULL);
|
|
drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_TEXTURE_PERSIST, tex, 0, 1);
|
|
}
|
|
|
|
void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup, const char *name, const GPUUniformBuffer *ubo)
|
|
{
|
|
BLI_assert(ubo != NULL);
|
|
drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_BLOCK, ubo, 0, 1);
|
|
}
|
|
|
|
/* Same as DRW_shgroup_uniform_block but is garanteed to be bound if shader does not change between shgrp. */
|
|
void DRW_shgroup_uniform_block_persistent(DRWShadingGroup *shgroup, const char *name, const GPUUniformBuffer *ubo)
|
|
{
|
|
BLI_assert(ubo != NULL);
|
|
drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_BLOCK_PERSIST, ubo, 0, 1);
|
|
}
|
|
|
|
void DRW_shgroup_uniform_texture_ref(DRWShadingGroup *shgroup, const char *name, GPUTexture **tex)
|
|
{
|
|
drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_TEXTURE_REF, tex, 0, 1);
|
|
}
|
|
|
|
void DRW_shgroup_uniform_bool(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize)
|
|
{
|
|
drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_BOOL, value, 1, arraysize);
|
|
}
|
|
|
|
void DRW_shgroup_uniform_float(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize)
|
|
{
|
|
drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 1, arraysize);
|
|
}
|
|
|
|
void DRW_shgroup_uniform_vec2(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize)
|
|
{
|
|
drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 2, arraysize);
|
|
}
|
|
|
|
void DRW_shgroup_uniform_vec3(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize)
|
|
{
|
|
drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 3, arraysize);
|
|
}
|
|
|
|
void DRW_shgroup_uniform_vec4(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize)
|
|
{
|
|
drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 4, arraysize);
|
|
}
|
|
|
|
void DRW_shgroup_uniform_short_to_int(DRWShadingGroup *shgroup, const char *name, const short *value, int arraysize)
|
|
{
|
|
drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_SHORT_TO_INT, value, 1, arraysize);
|
|
}
|
|
|
|
void DRW_shgroup_uniform_short_to_float(DRWShadingGroup *shgroup, const char *name, const short *value, int arraysize)
|
|
{
|
|
drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_SHORT_TO_FLOAT, value, 1, arraysize);
|
|
}
|
|
|
|
void DRW_shgroup_uniform_int(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize)
|
|
{
|
|
drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_INT, value, 1, arraysize);
|
|
}
|
|
|
|
void DRW_shgroup_uniform_ivec2(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize)
|
|
{
|
|
drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_INT, value, 2, arraysize);
|
|
}
|
|
|
|
void DRW_shgroup_uniform_ivec3(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize)
|
|
{
|
|
drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_INT, value, 3, arraysize);
|
|
}
|
|
|
|
void DRW_shgroup_uniform_mat3(DRWShadingGroup *shgroup, const char *name, const float (*value)[3])
|
|
{
|
|
drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT, (float *)value, 9, 1);
|
|
}
|
|
|
|
void DRW_shgroup_uniform_mat4(DRWShadingGroup *shgroup, const char *name, const float (*value)[4])
|
|
{
|
|
drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT, (float *)value, 16, 1);
|
|
}
|
|
|
|
/* Stores the int instead of a pointer. */
|
|
void DRW_shgroup_uniform_int_copy(DRWShadingGroup *shgroup, const char *name, const int value)
|
|
{
|
|
drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_INT_COPY, &value, 1, 1);
|
|
}
|
|
|
|
void DRW_shgroup_uniform_bool_copy(DRWShadingGroup *shgroup, const char *name, const bool value)
|
|
{
|
|
drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_BOOL_COPY, &value, 1, 1);
|
|
}
|
|
|
|
void DRW_shgroup_uniform_float_copy(DRWShadingGroup *shgroup, const char *name, const float value)
|
|
{
|
|
drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT_COPY, &value, 1, 1);
|
|
}
|
|
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Draw Call (DRW_calls)
|
|
* \{ */
|
|
|
|
static void drw_call_calc_orco(Object *ob, float (*r_orcofacs)[3])
|
|
{
|
|
ID *ob_data = (ob) ? ob->data : NULL;
|
|
float *texcoloc = NULL;
|
|
float *texcosize = NULL;
|
|
if (ob_data != NULL) {
|
|
switch (GS(ob_data->name)) {
|
|
case ID_ME:
|
|
BKE_mesh_texspace_get_reference((Mesh *)ob_data, NULL, &texcoloc, NULL, &texcosize);
|
|
break;
|
|
case ID_CU:
|
|
{
|
|
Curve *cu = (Curve *)ob_data;
|
|
if (cu->bb == NULL || (cu->bb->flag & BOUNDBOX_DIRTY)) {
|
|
BKE_curve_texspace_calc(cu);
|
|
}
|
|
texcoloc = cu->loc;
|
|
texcosize = cu->size;
|
|
break;
|
|
}
|
|
case ID_MB:
|
|
{
|
|
MetaBall *mb = (MetaBall *)ob_data;
|
|
texcoloc = mb->loc;
|
|
texcosize = mb->size;
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ((texcoloc != NULL) && (texcosize != NULL)) {
|
|
mul_v3_v3fl(r_orcofacs[1], texcosize, 2.0f);
|
|
invert_v3(r_orcofacs[1]);
|
|
sub_v3_v3v3(r_orcofacs[0], texcoloc, texcosize);
|
|
negate_v3(r_orcofacs[0]);
|
|
mul_v3_v3(r_orcofacs[0], r_orcofacs[1]); /* result in a nice MADD in the shader */
|
|
}
|
|
else {
|
|
copy_v3_fl(r_orcofacs[0], 0.0f);
|
|
copy_v3_fl(r_orcofacs[1], 1.0f);
|
|
}
|
|
}
|
|
|
|
static DRWCallState *drw_call_state_create(DRWShadingGroup *shgroup, float (*obmat)[4], Object *ob)
|
|
{
|
|
DRWCallState *state = BLI_mempool_alloc(DST.vmempool->states);
|
|
state->flag = 0;
|
|
state->cache_id = 0;
|
|
state->visibility_cb = NULL;
|
|
state->matflag = shgroup->matflag;
|
|
|
|
/* Matrices */
|
|
if (obmat != NULL) {
|
|
copy_m4_m4(state->model, obmat);
|
|
|
|
if (is_negative_m4(state->model)) {
|
|
state->flag |= DRW_CALL_NEGSCALE;
|
|
}
|
|
}
|
|
else {
|
|
unit_m4(state->model);
|
|
}
|
|
|
|
if (ob != NULL) {
|
|
float corner[3];
|
|
BoundBox *bbox = BKE_object_boundbox_get(ob);
|
|
/* Get BoundSphere center and radius from the BoundBox. */
|
|
mid_v3_v3v3(state->bsphere.center, bbox->vec[0], bbox->vec[6]);
|
|
mul_v3_m4v3(corner, obmat, bbox->vec[0]);
|
|
mul_m4_v3(obmat, state->bsphere.center);
|
|
state->bsphere.radius = len_v3v3(state->bsphere.center, corner);
|
|
}
|
|
else {
|
|
/* Bypass test. */
|
|
state->bsphere.radius = -1.0f;
|
|
}
|
|
|
|
/* Orco factors: We compute this at creation to not have to save the *ob_data */
|
|
if ((state->matflag & DRW_CALL_ORCOTEXFAC) != 0) {
|
|
drw_call_calc_orco(ob, state->orcotexfac);
|
|
state->matflag &= ~DRW_CALL_ORCOTEXFAC;
|
|
}
|
|
|
|
return state;
|
|
}
|
|
|
|
static DRWCallState *drw_call_state_object(DRWShadingGroup *shgroup, float (*obmat)[4], Object *ob)
|
|
{
|
|
if (DST.ob_state == NULL) {
|
|
DST.ob_state = drw_call_state_create(shgroup, obmat, ob);
|
|
}
|
|
else {
|
|
/* If the DRWCallState is reused, add necessary matrices. */
|
|
DST.ob_state->matflag |= shgroup->matflag;
|
|
}
|
|
|
|
return DST.ob_state;
|
|
}
|
|
|
|
void DRW_shgroup_call_add(DRWShadingGroup *shgroup, GPUBatch *geom, float (*obmat)[4])
|
|
{
|
|
BLI_assert(geom != NULL);
|
|
BLI_assert(ELEM(shgroup->type, DRW_SHG_NORMAL, DRW_SHG_FEEDBACK_TRANSFORM));
|
|
|
|
DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls);
|
|
call->state = drw_call_state_create(shgroup, obmat, NULL);
|
|
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_range_add(DRWShadingGroup *shgroup, GPUBatch *geom, float (*obmat)[4], uint v_sta, uint v_count)
|
|
{
|
|
BLI_assert(geom != NULL);
|
|
BLI_assert(ELEM(shgroup->type, DRW_SHG_NORMAL, DRW_SHG_FEEDBACK_TRANSFORM));
|
|
BLI_assert(v_count);
|
|
|
|
DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls);
|
|
call->state = drw_call_state_create(shgroup, obmat, NULL);
|
|
call->type = DRW_CALL_RANGE;
|
|
call->range.geometry = geom;
|
|
call->range.start = v_sta;
|
|
call->range.count = v_count;
|
|
#ifdef USE_GPU_SELECT
|
|
call->select_id = DST.select_id;
|
|
#endif
|
|
|
|
BLI_LINKS_APPEND(&shgroup->calls, call);
|
|
}
|
|
|
|
static void drw_shgroup_call_procedural_add_ex(
|
|
DRWShadingGroup *shgroup, GPUPrimType prim_type, uint vert_count, float (*obmat)[4], Object *ob)
|
|
{
|
|
BLI_assert(ELEM(shgroup->type, DRW_SHG_NORMAL, DRW_SHG_FEEDBACK_TRANSFORM));
|
|
|
|
DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls);
|
|
if (ob) {
|
|
call->state = drw_call_state_object(shgroup, ob->obmat, ob);
|
|
}
|
|
else {
|
|
call->state = drw_call_state_create(shgroup, obmat, NULL);
|
|
}
|
|
call->type = DRW_CALL_PROCEDURAL;
|
|
call->procedural.prim_type = prim_type;
|
|
call->procedural.vert_count = vert_count;
|
|
#ifdef USE_GPU_SELECT
|
|
call->select_id = DST.select_id;
|
|
#endif
|
|
|
|
BLI_LINKS_APPEND(&shgroup->calls, call);
|
|
}
|
|
|
|
void DRW_shgroup_call_procedural_points_add(DRWShadingGroup *shgroup, uint point_len, float (*obmat)[4])
|
|
{
|
|
drw_shgroup_call_procedural_add_ex(shgroup, GPU_PRIM_POINTS, point_len, obmat, NULL);
|
|
}
|
|
|
|
void DRW_shgroup_call_procedural_lines_add(DRWShadingGroup *shgroup, uint line_count, float (*obmat)[4])
|
|
{
|
|
drw_shgroup_call_procedural_add_ex(shgroup, GPU_PRIM_LINES, line_count * 2, obmat, NULL);
|
|
}
|
|
|
|
void DRW_shgroup_call_procedural_triangles_add(DRWShadingGroup *shgroup, uint tria_count, float (*obmat)[4])
|
|
{
|
|
drw_shgroup_call_procedural_add_ex(shgroup, GPU_PRIM_TRIS, tria_count * 3, obmat, NULL);
|
|
}
|
|
|
|
/* TODO (fclem): this is a sign that the api is starting to be limiting.
|
|
* Maybe add special function that general purpose for special cases. */
|
|
void DRW_shgroup_call_object_procedural_triangles_culled_add(DRWShadingGroup *shgroup, uint tria_count, Object *ob)
|
|
{
|
|
drw_shgroup_call_procedural_add_ex(shgroup, GPU_PRIM_TRIS, tria_count * 3, NULL, ob);
|
|
}
|
|
|
|
/* These calls can be culled and are optimized for redraw */
|
|
void DRW_shgroup_call_object_add_ex(DRWShadingGroup *shgroup, GPUBatch *geom, Object *ob, bool bypass_culling)
|
|
{
|
|
BLI_assert(geom != NULL);
|
|
BLI_assert(ELEM(shgroup->type, DRW_SHG_NORMAL, DRW_SHG_FEEDBACK_TRANSFORM));
|
|
|
|
DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls);
|
|
call->state = drw_call_state_object(shgroup, ob->obmat, ob);
|
|
call->type = DRW_CALL_SINGLE;
|
|
call->single.geometry = geom;
|
|
#ifdef USE_GPU_SELECT
|
|
call->select_id = DST.select_id;
|
|
#endif
|
|
|
|
/* NOTE this will disable culling for the whole object. */
|
|
call->state->flag |= (bypass_culling) ? DRW_CALL_BYPASS_CULLING : 0;
|
|
|
|
BLI_LINKS_APPEND(&shgroup->calls, call);
|
|
}
|
|
|
|
void DRW_shgroup_call_object_add_with_callback(
|
|
DRWShadingGroup *shgroup, GPUBatch *geom, Object *ob,
|
|
DRWCallVisibilityFn *callback, void *user_data)
|
|
{
|
|
BLI_assert(geom != NULL);
|
|
BLI_assert(ELEM(shgroup->type, DRW_SHG_NORMAL, DRW_SHG_FEEDBACK_TRANSFORM));
|
|
|
|
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, GPUBatch *geom, float (*obmat)[4], uint *count)
|
|
{
|
|
BLI_assert(geom != NULL);
|
|
BLI_assert(ELEM(shgroup->type, DRW_SHG_NORMAL, DRW_SHG_FEEDBACK_TRANSFORM));
|
|
|
|
DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls);
|
|
call->state = drw_call_state_create(shgroup, obmat, NULL);
|
|
call->type = DRW_CALL_INSTANCES;
|
|
call->instances.geometry = geom;
|
|
call->instances.count = count;
|
|
#ifdef USE_GPU_SELECT
|
|
call->select_id = DST.select_id;
|
|
#endif
|
|
|
|
BLI_LINKS_APPEND(&shgroup->calls, call);
|
|
}
|
|
|
|
/* These calls can be culled and are optimized for redraw */
|
|
void DRW_shgroup_call_object_instances_add(DRWShadingGroup *shgroup, GPUBatch *geom, Object *ob, uint *count)
|
|
{
|
|
BLI_assert(geom != NULL);
|
|
BLI_assert(ELEM(shgroup->type, DRW_SHG_NORMAL, DRW_SHG_FEEDBACK_TRANSFORM));
|
|
|
|
DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls);
|
|
call->state = drw_call_state_object(shgroup, ob->obmat, ob);
|
|
call->type = DRW_CALL_INSTANCES;
|
|
call->instances.geometry = geom;
|
|
call->instances.count = count;
|
|
#ifdef USE_GPU_SELECT
|
|
call->select_id = DST.select_id;
|
|
#endif
|
|
|
|
BLI_LINKS_APPEND(&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(ELEM(shgroup->type, DRW_SHG_NORMAL, DRW_SHG_FEEDBACK_TRANSFORM));
|
|
|
|
DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls);
|
|
call->state = drw_call_state_create(shgroup, obmat, NULL);
|
|
call->type = DRW_CALL_GENERATE;
|
|
call->generate.geometry_fn = geometry_fn;
|
|
call->generate.user_data = user_data;
|
|
#ifdef USE_GPU_SELECT
|
|
call->select_id = DST.select_id;
|
|
#endif
|
|
|
|
BLI_LINKS_APPEND(&shgroup->calls, call);
|
|
}
|
|
|
|
static void sculpt_draw_cb(
|
|
DRWShadingGroup *shgroup,
|
|
void (*draw_fn)(DRWShadingGroup *shgroup, GPUBatch *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 *, GPUBatch *))draw_fn, shgroup);
|
|
}
|
|
}
|
|
|
|
void DRW_shgroup_call_sculpt_add(DRWShadingGroup *shgroup, Object *ob, float (*obmat)[4])
|
|
{
|
|
DRW_shgroup_call_generate_add(shgroup, sculpt_draw_cb, ob, obmat);
|
|
}
|
|
|
|
void DRW_shgroup_call_dynamic_add_array(DRWShadingGroup *shgroup, const void *attr[], uint attr_len)
|
|
{
|
|
#ifdef USE_GPU_SELECT
|
|
if (G.f & G_PICKSEL) {
|
|
if (shgroup->instance_count == shgroup->inst_selectid->vertex_len) {
|
|
GPU_vertbuf_data_resize(shgroup->inst_selectid, shgroup->instance_count + 32);
|
|
}
|
|
GPU_vertbuf_attr_set(shgroup->inst_selectid, 0, shgroup->instance_count, &DST.select_id);
|
|
}
|
|
#endif
|
|
|
|
BLI_assert(attr_len == shgroup->attribs_count);
|
|
UNUSED_VARS_NDEBUG(attr_len);
|
|
|
|
for (int i = 0; i < attr_len; ++i) {
|
|
if (shgroup->instance_count == shgroup->instance_vbo->vertex_len) {
|
|
GPU_vertbuf_data_resize(shgroup->instance_vbo, shgroup->instance_count + 32);
|
|
}
|
|
GPU_vertbuf_attr_set(shgroup->instance_vbo, i, shgroup->instance_count, attr[i]);
|
|
}
|
|
|
|
shgroup->instance_count += 1;
|
|
}
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Shading Groups (DRW_shgroup)
|
|
* \{ */
|
|
|
|
static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader)
|
|
{
|
|
shgroup->instance_geom = NULL;
|
|
shgroup->instance_vbo = NULL;
|
|
shgroup->instance_count = 0;
|
|
shgroup->uniforms = NULL;
|
|
#ifdef USE_GPU_SELECT
|
|
shgroup->inst_selectid = NULL;
|
|
shgroup->override_selectid = -1;
|
|
#endif
|
|
#ifndef NDEBUG
|
|
shgroup->attribs_count = 0;
|
|
#endif
|
|
|
|
int view_ubo_location = GPU_shader_get_uniform_block(shader, "viewBlock");
|
|
|
|
if (view_ubo_location != -1) {
|
|
drw_shgroup_uniform_create_ex(shgroup, view_ubo_location, DRW_UNIFORM_BLOCK_PERSIST, view_ubo, 0, 1);
|
|
}
|
|
else {
|
|
/* Only here to support builtin shaders. This should not be used by engines. */
|
|
drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_VIEW, DST.view_data.matstate.mat[DRW_MAT_VIEW], 16, 1);
|
|
drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_VIEW_INV, DST.view_data.matstate.mat[DRW_MAT_VIEWINV], 16, 1);
|
|
drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_VIEWPROJECTION, DST.view_data.matstate.mat[DRW_MAT_PERS], 16, 1);
|
|
drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_VIEWPROJECTION_INV, DST.view_data.matstate.mat[DRW_MAT_PERSINV], 16, 1);
|
|
drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_PROJECTION, DST.view_data.matstate.mat[DRW_MAT_WIN], 16, 1);
|
|
drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_PROJECTION_INV, DST.view_data.matstate.mat[DRW_MAT_WININV], 16, 1);
|
|
drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_CAMERATEXCO, DST.view_data.viewcamtexcofac, 3, 2);
|
|
}
|
|
|
|
shgroup->model = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODEL);
|
|
shgroup->modelinverse = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODEL_INV);
|
|
shgroup->modelview = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODELVIEW);
|
|
shgroup->modelviewinverse = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODELVIEW_INV);
|
|
shgroup->modelviewprojection = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MVP);
|
|
shgroup->normalview = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_NORMAL);
|
|
shgroup->normalworld = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_WORLDNORMAL);
|
|
shgroup->orcotexfac = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_ORCO);
|
|
shgroup->eye = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_EYE);
|
|
shgroup->callid = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_CALLID);
|
|
|
|
shgroup->matflag = 0;
|
|
if (shgroup->modelinverse > -1)
|
|
shgroup->matflag |= DRW_CALL_MODELINVERSE;
|
|
if (shgroup->modelview > -1)
|
|
shgroup->matflag |= DRW_CALL_MODELVIEW;
|
|
if (shgroup->modelviewinverse > -1)
|
|
shgroup->matflag |= DRW_CALL_MODELVIEWINVERSE;
|
|
if (shgroup->modelviewprojection > -1)
|
|
shgroup->matflag |= DRW_CALL_MODELVIEWPROJECTION;
|
|
if (shgroup->normalview > -1)
|
|
shgroup->matflag |= DRW_CALL_NORMALVIEW;
|
|
if (shgroup->normalworld > -1)
|
|
shgroup->matflag |= DRW_CALL_NORMALWORLD;
|
|
if (shgroup->orcotexfac > -1)
|
|
shgroup->matflag |= DRW_CALL_ORCOTEXFAC;
|
|
if (shgroup->eye > -1)
|
|
shgroup->matflag |= DRW_CALL_EYEVEC;
|
|
}
|
|
|
|
static void drw_shgroup_instance_init(
|
|
DRWShadingGroup *shgroup, GPUShader *shader, GPUBatch *batch, GPUVertFormat *format)
|
|
{
|
|
BLI_assert(shgroup->type == DRW_SHG_INSTANCE);
|
|
BLI_assert(batch != NULL);
|
|
BLI_assert(format != NULL);
|
|
|
|
drw_shgroup_init(shgroup, shader);
|
|
|
|
shgroup->instance_geom = batch;
|
|
#ifndef NDEBUG
|
|
shgroup->attribs_count = format->attr_len;
|
|
#endif
|
|
|
|
DRW_instancing_buffer_request(DST.idatalist, format, batch, shgroup,
|
|
&shgroup->instance_geom, &shgroup->instance_vbo);
|
|
|
|
#ifdef USE_GPU_SELECT
|
|
if (G.f & G_PICKSEL) {
|
|
/* Not actually used for rendering but alloced in one chunk.
|
|
* Plus we don't have to care about ownership. */
|
|
static GPUVertFormat inst_select_format = {0};
|
|
if (inst_select_format.attr_len == 0) {
|
|
GPU_vertformat_attr_add(&inst_select_format, "selectId", GPU_COMP_I32, 1, GPU_FETCH_INT);
|
|
}
|
|
GPUBatch *batch_dummy; /* Not used */
|
|
DRW_batching_buffer_request(DST.idatalist, &inst_select_format,
|
|
GPU_PRIM_POINTS, shgroup,
|
|
&batch_dummy, &shgroup->inst_selectid);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static void drw_shgroup_batching_init(
|
|
DRWShadingGroup *shgroup, GPUShader *shader, GPUVertFormat *format)
|
|
{
|
|
drw_shgroup_init(shgroup, shader);
|
|
|
|
#ifndef NDEBUG
|
|
shgroup->attribs_count = (format != NULL) ? format->attr_len : 0;
|
|
#endif
|
|
BLI_assert(format != NULL);
|
|
|
|
GPUPrimType type;
|
|
switch (shgroup->type) {
|
|
case DRW_SHG_POINT_BATCH: type = GPU_PRIM_POINTS; break;
|
|
case DRW_SHG_LINE_BATCH: type = GPU_PRIM_LINES; break;
|
|
case DRW_SHG_TRIANGLE_BATCH: type = GPU_PRIM_TRIS; break;
|
|
default: type = GPU_PRIM_NONE; BLI_assert(0); break;
|
|
}
|
|
|
|
DRW_batching_buffer_request(DST.idatalist, format, type, shgroup,
|
|
&shgroup->batch_geom, &shgroup->batch_vbo);
|
|
|
|
#ifdef USE_GPU_SELECT
|
|
if (G.f & G_PICKSEL) {
|
|
/* Not actually used for rendering but alloced in one chunk. */
|
|
static GPUVertFormat inst_select_format = {0};
|
|
if (inst_select_format.attr_len == 0) {
|
|
GPU_vertformat_attr_add(&inst_select_format, "selectId", GPU_COMP_I32, 1, GPU_FETCH_INT);
|
|
}
|
|
GPUBatch *batch; /* Not used */
|
|
DRW_batching_buffer_request(DST.idatalist, &inst_select_format,
|
|
GPU_PRIM_POINTS, shgroup,
|
|
&batch, &shgroup->inst_selectid);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static DRWShadingGroup *drw_shgroup_create_ex(struct GPUShader *shader, DRWPass *pass)
|
|
{
|
|
DRWShadingGroup *shgroup = BLI_mempool_alloc(DST.vmempool->shgroups);
|
|
|
|
BLI_LINKS_APPEND(&pass->shgroups, shgroup);
|
|
|
|
shgroup->type = DRW_SHG_NORMAL;
|
|
shgroup->shader = shader;
|
|
shgroup->state_extra = 0;
|
|
shgroup->state_extra_disable = ~0x0;
|
|
shgroup->stencil_mask = 0;
|
|
shgroup->calls.first = NULL;
|
|
shgroup->calls.last = NULL;
|
|
#if 0 /* All the same in the union! */
|
|
shgroup->batch_geom = NULL;
|
|
shgroup->batch_vbo = NULL;
|
|
|
|
shgroup->instance_geom = NULL;
|
|
shgroup->instance_vbo = NULL;
|
|
#endif
|
|
|
|
#if !defined(NDEBUG) || defined(USE_GPU_SELECT)
|
|
shgroup->pass_parent = pass;
|
|
#endif
|
|
|
|
return shgroup;
|
|
}
|
|
|
|
static DRWShadingGroup *drw_shgroup_material_create_ex(GPUPass *gpupass, DRWPass *pass)
|
|
{
|
|
if (!gpupass) {
|
|
/* Shader compilation error */
|
|
return NULL;
|
|
}
|
|
|
|
GPUShader *sh = GPU_pass_shader_get(gpupass);
|
|
|
|
if (!sh) {
|
|
/* Shader not yet compiled */
|
|
return NULL;
|
|
}
|
|
|
|
DRWShadingGroup *grp = drw_shgroup_create_ex(sh, pass);
|
|
return grp;
|
|
}
|
|
|
|
static DRWShadingGroup *drw_shgroup_material_inputs(DRWShadingGroup *grp, struct GPUMaterial *material)
|
|
{
|
|
ListBase *inputs = GPU_material_get_inputs(material);
|
|
|
|
/* Converting dynamic GPUInput to DRWUniform */
|
|
for (GPUInput *input = inputs->first; input; input = input->next) {
|
|
/* Textures */
|
|
if (input->source == GPU_SOURCE_TEX) {
|
|
GPUTexture *tex = NULL;
|
|
|
|
if (input->ima) {
|
|
double time = 0.0; /* TODO make time variable */
|
|
tex = GPU_texture_from_blender(input->ima, input->iuser, GL_TEXTURE_2D, input->image_isdata, time);
|
|
}
|
|
else {
|
|
/* Color Ramps */
|
|
tex = *input->coba;
|
|
}
|
|
|
|
if (input->bindtex) {
|
|
drw_shgroup_uniform_create_ex(grp, input->shaderloc, DRW_UNIFORM_TEXTURE, tex, 0, 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
GPUUniformBuffer *ubo = GPU_material_uniform_buffer_get(material);
|
|
if (ubo != NULL) {
|
|
DRW_shgroup_uniform_block(grp, GPU_UBO_BLOCK_NAME, ubo);
|
|
}
|
|
|
|
return grp;
|
|
}
|
|
|
|
GPUVertFormat *DRW_shgroup_instance_format_array(const DRWInstanceAttribFormat attribs[], int arraysize)
|
|
{
|
|
GPUVertFormat *format = MEM_callocN(sizeof(GPUVertFormat), "GPUVertFormat");
|
|
|
|
for (int i = 0; i < arraysize; ++i) {
|
|
GPU_vertformat_attr_add(format, attribs[i].name,
|
|
(attribs[i].type == DRW_ATTRIB_INT) ? GPU_COMP_I32 : GPU_COMP_F32,
|
|
attribs[i].components,
|
|
(attribs[i].type == DRW_ATTRIB_INT) ? GPU_FETCH_INT : GPU_FETCH_FLOAT);
|
|
}
|
|
return format;
|
|
}
|
|
|
|
DRWShadingGroup *DRW_shgroup_material_create(
|
|
struct GPUMaterial *material, DRWPass *pass)
|
|
{
|
|
GPUPass *gpupass = GPU_material_get_pass(material);
|
|
DRWShadingGroup *shgroup = drw_shgroup_material_create_ex(gpupass, pass);
|
|
|
|
if (shgroup) {
|
|
drw_shgroup_init(shgroup, GPU_pass_shader_get(gpupass));
|
|
drw_shgroup_material_inputs(shgroup, material);
|
|
}
|
|
|
|
return shgroup;
|
|
}
|
|
|
|
DRWShadingGroup *DRW_shgroup_material_instance_create(
|
|
struct GPUMaterial *material, DRWPass *pass, GPUBatch *geom, Object *ob, GPUVertFormat *format)
|
|
{
|
|
GPUPass *gpupass = GPU_material_get_pass(material);
|
|
DRWShadingGroup *shgroup = drw_shgroup_material_create_ex(gpupass, pass);
|
|
|
|
if (shgroup) {
|
|
shgroup->type = DRW_SHG_INSTANCE;
|
|
shgroup->instance_geom = geom;
|
|
drw_call_calc_orco(ob, shgroup->instance_orcofac);
|
|
drw_shgroup_instance_init(shgroup, GPU_pass_shader_get(gpupass), geom, format);
|
|
drw_shgroup_material_inputs(shgroup, material);
|
|
}
|
|
|
|
return shgroup;
|
|
}
|
|
|
|
DRWShadingGroup *DRW_shgroup_material_empty_tri_batch_create(
|
|
struct GPUMaterial *material, DRWPass *pass, int tri_count)
|
|
{
|
|
#ifdef USE_GPU_SELECT
|
|
BLI_assert((G.f & G_PICKSEL) == 0);
|
|
#endif
|
|
GPUPass *gpupass = GPU_material_get_pass(material);
|
|
DRWShadingGroup *shgroup = drw_shgroup_material_create_ex(gpupass, pass);
|
|
|
|
if (shgroup) {
|
|
/* Calling drw_shgroup_init will cause it to call GPU_draw_primitive(). */
|
|
drw_shgroup_init(shgroup, GPU_pass_shader_get(gpupass));
|
|
shgroup->type = DRW_SHG_TRIANGLE_BATCH;
|
|
shgroup->instance_count = tri_count * 3;
|
|
drw_shgroup_material_inputs(shgroup, material);
|
|
}
|
|
|
|
return shgroup;
|
|
}
|
|
|
|
DRWShadingGroup *DRW_shgroup_create(struct GPUShader *shader, DRWPass *pass)
|
|
{
|
|
DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass);
|
|
drw_shgroup_init(shgroup, shader);
|
|
return shgroup;
|
|
}
|
|
|
|
DRWShadingGroup *DRW_shgroup_instance_create(
|
|
struct GPUShader *shader, DRWPass *pass, GPUBatch *geom, GPUVertFormat *format)
|
|
{
|
|
DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass);
|
|
shgroup->type = DRW_SHG_INSTANCE;
|
|
shgroup->instance_geom = geom;
|
|
drw_call_calc_orco(NULL, shgroup->instance_orcofac);
|
|
drw_shgroup_instance_init(shgroup, shader, geom, format);
|
|
|
|
return shgroup;
|
|
}
|
|
|
|
DRWShadingGroup *DRW_shgroup_point_batch_create(struct GPUShader *shader, DRWPass *pass)
|
|
{
|
|
DRW_shgroup_instance_format(g_pos_format, {{"pos", DRW_ATTRIB_FLOAT, 3}});
|
|
|
|
DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass);
|
|
shgroup->type = DRW_SHG_POINT_BATCH;
|
|
|
|
drw_shgroup_batching_init(shgroup, shader, g_pos_format);
|
|
|
|
return shgroup;
|
|
}
|
|
|
|
DRWShadingGroup *DRW_shgroup_line_batch_create_with_format(
|
|
struct GPUShader *shader, DRWPass *pass, GPUVertFormat *format)
|
|
{
|
|
DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass);
|
|
shgroup->type = DRW_SHG_LINE_BATCH;
|
|
|
|
drw_shgroup_batching_init(shgroup, shader, format);
|
|
|
|
return shgroup;
|
|
}
|
|
|
|
DRWShadingGroup *DRW_shgroup_line_batch_create(struct GPUShader *shader, DRWPass *pass)
|
|
{
|
|
DRW_shgroup_instance_format(g_pos_format, {{"pos", DRW_ATTRIB_FLOAT, 3}});
|
|
|
|
return DRW_shgroup_line_batch_create_with_format(shader, pass, g_pos_format);
|
|
}
|
|
|
|
/* Very special batch. Use this if you position
|
|
* your vertices with the vertex shader
|
|
* and dont need any VBO attrib */
|
|
DRWShadingGroup *DRW_shgroup_empty_tri_batch_create(struct GPUShader *shader, DRWPass *pass, int tri_count)
|
|
{
|
|
#ifdef USE_GPU_SELECT
|
|
BLI_assert((G.f & G_PICKSEL) == 0);
|
|
#endif
|
|
DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass);
|
|
|
|
/* Calling drw_shgroup_init will cause it to call GPU_draw_primitive(). */
|
|
drw_shgroup_init(shgroup, shader);
|
|
|
|
shgroup->type = DRW_SHG_TRIANGLE_BATCH;
|
|
shgroup->instance_count = tri_count * 3;
|
|
|
|
return shgroup;
|
|
}
|
|
|
|
DRWShadingGroup *DRW_shgroup_transform_feedback_create(struct GPUShader *shader, DRWPass *pass, GPUVertBuf *tf_target)
|
|
{
|
|
BLI_assert(tf_target != NULL);
|
|
DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass);
|
|
shgroup->type = DRW_SHG_FEEDBACK_TRANSFORM;
|
|
|
|
drw_shgroup_init(shgroup, shader);
|
|
|
|
shgroup->tfeedback_target = tf_target;
|
|
|
|
return shgroup;
|
|
}
|
|
|
|
/* Specify an external batch instead of adding each attrib one by one. */
|
|
void DRW_shgroup_instance_batch(DRWShadingGroup *shgroup, struct GPUBatch *batch)
|
|
{
|
|
BLI_assert(shgroup->type == DRW_SHG_INSTANCE);
|
|
BLI_assert(shgroup->instance_count == 0);
|
|
/* You cannot use external instancing batch without a dummy format. */
|
|
BLI_assert(shgroup->attribs_count != 0);
|
|
|
|
shgroup->type = DRW_SHG_INSTANCE_EXTERNAL;
|
|
drw_call_calc_orco(NULL, shgroup->instance_orcofac);
|
|
/* PERF : This destroys the vaos cache so better check if it's necessary. */
|
|
/* Note: This WILL break if batch->verts[0] is destroyed and reallocated
|
|
* at the same adress. Bindings/VAOs would remain obsolete. */
|
|
//if (shgroup->instancing_geom->inst != batch->verts[0])
|
|
GPU_batch_instbuf_set(shgroup->instance_geom, batch->verts[0], false);
|
|
|
|
#ifdef USE_GPU_SELECT
|
|
shgroup->override_selectid = DST.select_id;
|
|
#endif
|
|
}
|
|
|
|
uint DRW_shgroup_get_instance_count(const DRWShadingGroup *shgroup)
|
|
{
|
|
return shgroup->instance_count;
|
|
}
|
|
|
|
/**
|
|
* State is added to #Pass.state while drawing.
|
|
* Use to temporarily enable draw options.
|
|
*/
|
|
void DRW_shgroup_state_enable(DRWShadingGroup *shgroup, DRWState state)
|
|
{
|
|
shgroup->state_extra |= state;
|
|
}
|
|
|
|
void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state)
|
|
{
|
|
shgroup->state_extra_disable &= ~state;
|
|
}
|
|
|
|
void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, uint mask)
|
|
{
|
|
BLI_assert(mask <= 255);
|
|
shgroup->stencil_mask = mask;
|
|
}
|
|
|
|
bool DRW_shgroup_is_empty(DRWShadingGroup *shgroup)
|
|
{
|
|
switch (shgroup->type) {
|
|
case DRW_SHG_NORMAL:
|
|
case DRW_SHG_FEEDBACK_TRANSFORM:
|
|
return shgroup->calls.first == NULL;
|
|
case DRW_SHG_POINT_BATCH:
|
|
case DRW_SHG_LINE_BATCH:
|
|
case DRW_SHG_TRIANGLE_BATCH:
|
|
case DRW_SHG_INSTANCE:
|
|
case DRW_SHG_INSTANCE_EXTERNAL:
|
|
return shgroup->instance_count == 0;
|
|
}
|
|
BLI_assert(!"Shading Group type not supported");
|
|
return true;
|
|
}
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Passes (DRW_pass)
|
|
* \{ */
|
|
|
|
DRWPass *DRW_pass_create(const char *name, DRWState state)
|
|
{
|
|
DRWPass *pass = BLI_mempool_alloc(DST.vmempool->passes);
|
|
pass->state = state;
|
|
if ((G.debug_value > 20) || (G.debug & G_DEBUG)) {
|
|
BLI_strncpy(pass->name, name, MAX_PASS_NAME);
|
|
}
|
|
|
|
pass->shgroups.first = NULL;
|
|
pass->shgroups.last = NULL;
|
|
|
|
return pass;
|
|
}
|
|
|
|
bool DRW_pass_is_empty(DRWPass *pass)
|
|
{
|
|
for (DRWShadingGroup *shgroup = pass->shgroups.first; shgroup; shgroup = shgroup->next) {
|
|
if (!DRW_shgroup_is_empty(shgroup)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void DRW_pass_state_set(DRWPass *pass, DRWState state)
|
|
{
|
|
pass->state = state;
|
|
}
|
|
|
|
void DRW_pass_state_add(DRWPass *pass, DRWState state)
|
|
{
|
|
pass->state |= state;
|
|
}
|
|
|
|
void DRW_pass_state_remove(DRWPass *pass, DRWState state)
|
|
{
|
|
pass->state &= ~state;
|
|
}
|
|
|
|
void DRW_pass_free(DRWPass *pass)
|
|
{
|
|
pass->shgroups.first = NULL;
|
|
pass->shgroups.last = NULL;
|
|
}
|
|
|
|
void DRW_pass_foreach_shgroup(DRWPass *pass, void (*callback)(void *userData, DRWShadingGroup *shgrp), void *userData)
|
|
{
|
|
for (DRWShadingGroup *shgroup = pass->shgroups.first; shgroup; shgroup = shgroup->next) {
|
|
callback(userData, shgroup);
|
|
}
|
|
}
|
|
|
|
typedef struct ZSortData {
|
|
float *axis;
|
|
float *origin;
|
|
} ZSortData;
|
|
|
|
static int pass_shgroup_dist_sort(void *thunk, const void *a, const void *b)
|
|
{
|
|
const ZSortData *zsortdata = (ZSortData *)thunk;
|
|
const DRWShadingGroup *shgrp_a = (const DRWShadingGroup *)a;
|
|
const DRWShadingGroup *shgrp_b = (const DRWShadingGroup *)b;
|
|
|
|
const DRWCall *call_a = (DRWCall *)shgrp_a->calls.first;
|
|
const DRWCall *call_b = (DRWCall *)shgrp_b->calls.first;
|
|
|
|
if (call_a == NULL) return -1;
|
|
if (call_b == NULL) return -1;
|
|
|
|
float tmp[3];
|
|
sub_v3_v3v3(tmp, zsortdata->origin, call_a->state->model[3]);
|
|
const float a_sq = dot_v3v3(zsortdata->axis, tmp);
|
|
sub_v3_v3v3(tmp, zsortdata->origin, call_b->state->model[3]);
|
|
const float b_sq = dot_v3v3(zsortdata->axis, tmp);
|
|
|
|
if (a_sq < b_sq) return 1;
|
|
else if (a_sq > b_sq) return -1;
|
|
else {
|
|
/* If there is a depth prepass put it before */
|
|
if ((shgrp_a->state_extra & DRW_STATE_WRITE_DEPTH) != 0) {
|
|
return -1;
|
|
}
|
|
else if ((shgrp_b->state_extra & DRW_STATE_WRITE_DEPTH) != 0) {
|
|
return 1;
|
|
}
|
|
else return 0;
|
|
}
|
|
}
|
|
|
|
/* ------------------ Shading group sorting --------------------- */
|
|
|
|
#define SORT_IMPL_LINKTYPE DRWShadingGroup
|
|
|
|
#define SORT_IMPL_USE_THUNK
|
|
#define SORT_IMPL_FUNC shgroup_sort_fn_r
|
|
#include "../../blenlib/intern/list_sort_impl.h"
|
|
#undef SORT_IMPL_FUNC
|
|
#undef SORT_IMPL_USE_THUNK
|
|
|
|
#undef SORT_IMPL_LINKTYPE
|
|
|
|
/**
|
|
* Sort Shading groups by decreasing Z of their first draw call.
|
|
* This is usefull for order dependant effect such as transparency.
|
|
**/
|
|
void DRW_pass_sort_shgroup_z(DRWPass *pass)
|
|
{
|
|
float (*viewinv)[4];
|
|
viewinv = DST.view_data.matstate.mat[DRW_MAT_VIEWINV];
|
|
|
|
ZSortData zsortdata = {viewinv[2], viewinv[3]};
|
|
|
|
if (pass->shgroups.first && pass->shgroups.first->next) {
|
|
pass->shgroups.first = shgroup_sort_fn_r(pass->shgroups.first, pass_shgroup_dist_sort, &zsortdata);
|
|
|
|
/* Find the next last */
|
|
DRWShadingGroup *last = pass->shgroups.first;
|
|
while ((last = last->next)) {
|
|
/* Do nothing */
|
|
}
|
|
pass->shgroups.last = last;
|
|
}
|
|
}
|
|
|
|
/** \} */
|