The goal is to solve confusion of the "All rights reserved" for licensing
code under an open-source license.
The phrase "All rights reserved" comes from a historical convention that
required this phrase for the copyright protection to apply. This convention
is no longer relevant.
However, even though the phrase has no meaning in establishing the copyright
it has not lost meaning in terms of licensing.
This change makes it so code under the Blender Foundation copyright does
not use "all rights reserved". This is also how the GPL license itself
states how to apply it to the source code:
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software ...
This change does not change copyright notice in cases when the copyright
is dual (BF and an author), or just an author of the code. It also does
mot change copyright which is inherited from NaN Holding BV as it needs
some further investigation about what is the proper way to handle it.
502 lines
12 KiB
C
502 lines
12 KiB
C
/* SPDX-License-Identifier: GPL-2.0-or-later
|
|
* Copyright 2017 Blender Foundation */
|
|
|
|
/** \file
|
|
* \ingroup draw
|
|
*
|
|
* \brief Lattice API for render engines
|
|
*/
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "BLI_math_vector.h"
|
|
#include "BLI_utildefines.h"
|
|
|
|
#include "DNA_curve_types.h"
|
|
#include "DNA_lattice_types.h"
|
|
#include "DNA_meshdata_types.h"
|
|
#include "DNA_userdef_types.h"
|
|
|
|
#include "BKE_colorband.h"
|
|
#include "BKE_deform.h"
|
|
#include "BKE_lattice.h"
|
|
|
|
#include "GPU_batch.h"
|
|
|
|
#include "draw_cache_impl.h" /* own include */
|
|
|
|
#define SELECT 1
|
|
|
|
static void lattice_batch_cache_clear(Lattice *lt);
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
/* Lattice Interface, direct access to basic data. */
|
|
|
|
static int vert_len_calc(int u, int v, int w)
|
|
{
|
|
if (u <= 0 || v <= 0 || w <= 0) {
|
|
return 0;
|
|
}
|
|
return u * v * w;
|
|
}
|
|
|
|
static int edge_len_calc(int u, int v, int w)
|
|
{
|
|
if (u <= 0 || v <= 0 || w <= 0) {
|
|
return 0;
|
|
}
|
|
return (((((u - 1) * v) + ((v - 1) * u)) * w) + ((w - 1) * (u * v)));
|
|
}
|
|
|
|
static int lattice_render_verts_len_get(Lattice *lt)
|
|
{
|
|
if (lt->editlatt) {
|
|
lt = lt->editlatt->latt;
|
|
}
|
|
|
|
const int u = lt->pntsu;
|
|
const int v = lt->pntsv;
|
|
const int w = lt->pntsw;
|
|
|
|
if ((lt->flag & LT_OUTSIDE) == 0) {
|
|
return vert_len_calc(u, v, w);
|
|
}
|
|
|
|
/* TODO: remove internal coords. */
|
|
return vert_len_calc(u, v, w);
|
|
}
|
|
|
|
static int lattice_render_edges_len_get(Lattice *lt)
|
|
{
|
|
if (lt->editlatt) {
|
|
lt = lt->editlatt->latt;
|
|
}
|
|
|
|
const int u = lt->pntsu;
|
|
const int v = lt->pntsv;
|
|
const int w = lt->pntsw;
|
|
|
|
if ((lt->flag & LT_OUTSIDE) == 0) {
|
|
return edge_len_calc(u, v, w);
|
|
}
|
|
|
|
/* TODO: remove internal coords. */
|
|
return edge_len_calc(u, v, w);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
/* Lattice Interface, indirect, partially cached access to complex data. */
|
|
|
|
typedef struct LatticeRenderData {
|
|
int types;
|
|
|
|
int vert_len;
|
|
int edge_len;
|
|
|
|
struct {
|
|
int u_len, v_len, w_len;
|
|
} dims;
|
|
bool show_only_outside;
|
|
|
|
struct EditLatt *edit_latt;
|
|
BPoint *bp;
|
|
|
|
int actbp;
|
|
|
|
const struct MDeformVert *dvert;
|
|
} LatticeRenderData;
|
|
|
|
enum {
|
|
LR_DATATYPE_VERT = 1 << 0,
|
|
LR_DATATYPE_EDGE = 1 << 1,
|
|
LR_DATATYPE_OVERLAY = 1 << 2,
|
|
};
|
|
|
|
static LatticeRenderData *lattice_render_data_create(Lattice *lt, const int types)
|
|
{
|
|
LatticeRenderData *rdata = MEM_callocN(sizeof(*rdata), __func__);
|
|
rdata->types = types;
|
|
|
|
if (lt->editlatt) {
|
|
EditLatt *editlatt = lt->editlatt;
|
|
lt = editlatt->latt;
|
|
|
|
rdata->edit_latt = editlatt;
|
|
|
|
rdata->dvert = lt->dvert;
|
|
|
|
if (types & (LR_DATATYPE_VERT)) {
|
|
rdata->vert_len = lattice_render_verts_len_get(lt);
|
|
}
|
|
if (types & (LR_DATATYPE_EDGE)) {
|
|
rdata->edge_len = lattice_render_edges_len_get(lt);
|
|
}
|
|
if (types & LR_DATATYPE_OVERLAY) {
|
|
rdata->actbp = lt->actbp;
|
|
}
|
|
}
|
|
else {
|
|
rdata->dvert = NULL;
|
|
|
|
if (types & (LR_DATATYPE_VERT)) {
|
|
rdata->vert_len = lattice_render_verts_len_get(lt);
|
|
}
|
|
if (types & (LR_DATATYPE_EDGE)) {
|
|
rdata->edge_len = lattice_render_edges_len_get(lt);
|
|
/* No edge data. */
|
|
}
|
|
}
|
|
|
|
rdata->bp = lt->def;
|
|
|
|
rdata->dims.u_len = lt->pntsu;
|
|
rdata->dims.v_len = lt->pntsv;
|
|
rdata->dims.w_len = lt->pntsw;
|
|
|
|
rdata->show_only_outside = (lt->flag & LT_OUTSIDE) != 0;
|
|
rdata->actbp = lt->actbp;
|
|
|
|
return rdata;
|
|
}
|
|
|
|
static void lattice_render_data_free(LatticeRenderData *rdata)
|
|
{
|
|
#if 0
|
|
if (rdata->loose_verts) {
|
|
MEM_freeN(rdata->loose_verts);
|
|
}
|
|
#endif
|
|
MEM_freeN(rdata);
|
|
}
|
|
|
|
static int lattice_render_data_verts_len_get(const LatticeRenderData *rdata)
|
|
{
|
|
BLI_assert(rdata->types & LR_DATATYPE_VERT);
|
|
return rdata->vert_len;
|
|
}
|
|
|
|
static int lattice_render_data_edges_len_get(const LatticeRenderData *rdata)
|
|
{
|
|
BLI_assert(rdata->types & LR_DATATYPE_EDGE);
|
|
return rdata->edge_len;
|
|
}
|
|
|
|
static const BPoint *lattice_render_data_vert_bpoint(const LatticeRenderData *rdata,
|
|
const int vert_idx)
|
|
{
|
|
BLI_assert(rdata->types & LR_DATATYPE_VERT);
|
|
return &rdata->bp[vert_idx];
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
/* Lattice GPUBatch Cache */
|
|
|
|
typedef struct LatticeBatchCache {
|
|
GPUVertBuf *pos;
|
|
GPUIndexBuf *edges;
|
|
|
|
GPUBatch *all_verts;
|
|
GPUBatch *all_edges;
|
|
|
|
GPUBatch *overlay_verts;
|
|
|
|
/* settings to determine if cache is invalid */
|
|
bool is_dirty;
|
|
|
|
struct {
|
|
int u_len, v_len, w_len;
|
|
} dims;
|
|
bool show_only_outside;
|
|
|
|
bool is_editmode;
|
|
} LatticeBatchCache;
|
|
|
|
/* GPUBatch cache management. */
|
|
|
|
static bool lattice_batch_cache_valid(Lattice *lt)
|
|
{
|
|
LatticeBatchCache *cache = lt->batch_cache;
|
|
|
|
if (cache == NULL) {
|
|
return false;
|
|
}
|
|
|
|
if (cache->is_editmode != (lt->editlatt != NULL)) {
|
|
return false;
|
|
}
|
|
|
|
if (cache->is_dirty) {
|
|
return false;
|
|
}
|
|
|
|
if ((cache->dims.u_len != lt->pntsu) || (cache->dims.v_len != lt->pntsv) ||
|
|
(cache->dims.w_len != lt->pntsw) ||
|
|
(cache->show_only_outside != ((lt->flag & LT_OUTSIDE) != 0))) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static void lattice_batch_cache_init(Lattice *lt)
|
|
{
|
|
LatticeBatchCache *cache = lt->batch_cache;
|
|
|
|
if (!cache) {
|
|
cache = lt->batch_cache = MEM_callocN(sizeof(*cache), __func__);
|
|
}
|
|
else {
|
|
memset(cache, 0, sizeof(*cache));
|
|
}
|
|
|
|
cache->dims.u_len = lt->pntsu;
|
|
cache->dims.v_len = lt->pntsv;
|
|
cache->dims.w_len = lt->pntsw;
|
|
cache->show_only_outside = (lt->flag & LT_OUTSIDE) != 0;
|
|
|
|
cache->is_editmode = lt->editlatt != NULL;
|
|
|
|
cache->is_dirty = false;
|
|
}
|
|
|
|
void DRW_lattice_batch_cache_validate(Lattice *lt)
|
|
{
|
|
if (!lattice_batch_cache_valid(lt)) {
|
|
lattice_batch_cache_clear(lt);
|
|
lattice_batch_cache_init(lt);
|
|
}
|
|
}
|
|
|
|
static LatticeBatchCache *lattice_batch_cache_get(Lattice *lt)
|
|
{
|
|
return lt->batch_cache;
|
|
}
|
|
|
|
void DRW_lattice_batch_cache_dirty_tag(Lattice *lt, int mode)
|
|
{
|
|
LatticeBatchCache *cache = lt->batch_cache;
|
|
if (cache == NULL) {
|
|
return;
|
|
}
|
|
switch (mode) {
|
|
case BKE_LATTICE_BATCH_DIRTY_ALL:
|
|
cache->is_dirty = true;
|
|
break;
|
|
case BKE_LATTICE_BATCH_DIRTY_SELECT:
|
|
/* TODO: Separate Flag VBO. */
|
|
GPU_BATCH_DISCARD_SAFE(cache->overlay_verts);
|
|
break;
|
|
default:
|
|
BLI_assert(0);
|
|
}
|
|
}
|
|
|
|
static void lattice_batch_cache_clear(Lattice *lt)
|
|
{
|
|
LatticeBatchCache *cache = lt->batch_cache;
|
|
if (!cache) {
|
|
return;
|
|
}
|
|
|
|
GPU_BATCH_DISCARD_SAFE(cache->all_verts);
|
|
GPU_BATCH_DISCARD_SAFE(cache->all_edges);
|
|
GPU_BATCH_DISCARD_SAFE(cache->overlay_verts);
|
|
|
|
GPU_VERTBUF_DISCARD_SAFE(cache->pos);
|
|
GPU_INDEXBUF_DISCARD_SAFE(cache->edges);
|
|
}
|
|
|
|
void DRW_lattice_batch_cache_free(Lattice *lt)
|
|
{
|
|
lattice_batch_cache_clear(lt);
|
|
MEM_SAFE_FREE(lt->batch_cache);
|
|
}
|
|
|
|
/* GPUBatch cache usage. */
|
|
static GPUVertBuf *lattice_batch_cache_get_pos(LatticeRenderData *rdata,
|
|
LatticeBatchCache *cache,
|
|
bool use_weight,
|
|
const int actdef)
|
|
{
|
|
BLI_assert(rdata->types & LR_DATATYPE_VERT);
|
|
|
|
if (cache->pos == NULL) {
|
|
GPUVertFormat format = {0};
|
|
struct {
|
|
uint pos, col;
|
|
} attr_id;
|
|
|
|
attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
|
|
if (use_weight) {
|
|
attr_id.col = GPU_vertformat_attr_add(&format, "weight", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
|
|
}
|
|
|
|
const int vert_len = lattice_render_data_verts_len_get(rdata);
|
|
|
|
cache->pos = GPU_vertbuf_create_with_format(&format);
|
|
GPU_vertbuf_data_alloc(cache->pos, vert_len);
|
|
for (int i = 0; i < vert_len; i++) {
|
|
const BPoint *bp = lattice_render_data_vert_bpoint(rdata, i);
|
|
GPU_vertbuf_attr_set(cache->pos, attr_id.pos, i, bp->vec);
|
|
|
|
if (use_weight) {
|
|
const float no_active_weight = 666.0f;
|
|
float weight = (actdef > -1) ? BKE_defvert_find_weight(rdata->dvert + i, actdef) :
|
|
no_active_weight;
|
|
GPU_vertbuf_attr_set(cache->pos, attr_id.col, i, &weight);
|
|
}
|
|
}
|
|
}
|
|
|
|
return cache->pos;
|
|
}
|
|
|
|
static GPUIndexBuf *lattice_batch_cache_get_edges(LatticeRenderData *rdata,
|
|
LatticeBatchCache *cache)
|
|
{
|
|
BLI_assert(rdata->types & (LR_DATATYPE_VERT | LR_DATATYPE_EDGE));
|
|
|
|
if (cache->edges == NULL) {
|
|
const int vert_len = lattice_render_data_verts_len_get(rdata);
|
|
const int edge_len = lattice_render_data_edges_len_get(rdata);
|
|
int edge_len_real = 0;
|
|
|
|
GPUIndexBufBuilder elb;
|
|
GPU_indexbuf_init(&elb, GPU_PRIM_LINES, edge_len, vert_len);
|
|
|
|
#define LATT_INDEX(u, v, w) ((((w)*rdata->dims.v_len + (v)) * rdata->dims.u_len) + (u))
|
|
|
|
for (int w = 0; w < rdata->dims.w_len; w++) {
|
|
int wxt = ELEM(w, 0, rdata->dims.w_len - 1);
|
|
for (int v = 0; v < rdata->dims.v_len; v++) {
|
|
int vxt = ELEM(v, 0, rdata->dims.v_len - 1);
|
|
for (int u = 0; u < rdata->dims.u_len; u++) {
|
|
int uxt = ELEM(u, 0, rdata->dims.u_len - 1);
|
|
|
|
if (w && ((uxt || vxt) || !rdata->show_only_outside)) {
|
|
GPU_indexbuf_add_line_verts(&elb, LATT_INDEX(u, v, w - 1), LATT_INDEX(u, v, w));
|
|
BLI_assert(edge_len_real <= edge_len);
|
|
edge_len_real++;
|
|
}
|
|
if (v && ((uxt || wxt) || !rdata->show_only_outside)) {
|
|
GPU_indexbuf_add_line_verts(&elb, LATT_INDEX(u, v - 1, w), LATT_INDEX(u, v, w));
|
|
BLI_assert(edge_len_real <= edge_len);
|
|
edge_len_real++;
|
|
}
|
|
if (u && ((vxt || wxt) || !rdata->show_only_outside)) {
|
|
GPU_indexbuf_add_line_verts(&elb, LATT_INDEX(u - 1, v, w), LATT_INDEX(u, v, w));
|
|
BLI_assert(edge_len_real <= edge_len);
|
|
edge_len_real++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#undef LATT_INDEX
|
|
|
|
if (rdata->show_only_outside) {
|
|
BLI_assert(edge_len_real <= edge_len);
|
|
}
|
|
else {
|
|
BLI_assert(edge_len_real == edge_len);
|
|
}
|
|
UNUSED_VARS_NDEBUG(edge_len_real);
|
|
|
|
cache->edges = GPU_indexbuf_build(&elb);
|
|
}
|
|
|
|
return cache->edges;
|
|
}
|
|
|
|
static void lattice_batch_cache_create_overlay_batches(Lattice *lt)
|
|
{
|
|
/* Since LR_DATATYPE_OVERLAY is slow to generate, generate them all at once */
|
|
int options = LR_DATATYPE_VERT | LR_DATATYPE_OVERLAY;
|
|
|
|
LatticeBatchCache *cache = lattice_batch_cache_get(lt);
|
|
LatticeRenderData *rdata = lattice_render_data_create(lt, options);
|
|
|
|
if (cache->overlay_verts == NULL) {
|
|
static GPUVertFormat format = {0};
|
|
static struct {
|
|
uint pos, data;
|
|
} attr_id;
|
|
if (format.attr_len == 0) {
|
|
/* initialize vertex format */
|
|
attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
|
|
attr_id.data = GPU_vertformat_attr_add(&format, "data", GPU_COMP_U8, 1, GPU_FETCH_INT);
|
|
}
|
|
|
|
const int vert_len = lattice_render_data_verts_len_get(rdata);
|
|
|
|
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
|
|
GPU_vertbuf_data_alloc(vbo, vert_len);
|
|
for (int i = 0; i < vert_len; i++) {
|
|
const BPoint *bp = lattice_render_data_vert_bpoint(rdata, i);
|
|
|
|
char vflag = 0;
|
|
if (bp->f1 & SELECT) {
|
|
if (i == rdata->actbp) {
|
|
vflag |= VFLAG_VERT_ACTIVE;
|
|
}
|
|
else {
|
|
vflag |= VFLAG_VERT_SELECTED;
|
|
}
|
|
}
|
|
|
|
GPU_vertbuf_attr_set(vbo, attr_id.pos, i, bp->vec);
|
|
GPU_vertbuf_attr_set(vbo, attr_id.data, i, &vflag);
|
|
}
|
|
|
|
cache->overlay_verts = GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, NULL, GPU_BATCH_OWNS_VBO);
|
|
}
|
|
|
|
lattice_render_data_free(rdata);
|
|
}
|
|
|
|
GPUBatch *DRW_lattice_batch_cache_get_all_edges(Lattice *lt, bool use_weight, const int actdef)
|
|
{
|
|
LatticeBatchCache *cache = lattice_batch_cache_get(lt);
|
|
|
|
if (cache->all_edges == NULL) {
|
|
/* create batch from Lattice */
|
|
LatticeRenderData *rdata = lattice_render_data_create(lt, LR_DATATYPE_VERT | LR_DATATYPE_EDGE);
|
|
|
|
cache->all_edges = GPU_batch_create(
|
|
GPU_PRIM_LINES,
|
|
lattice_batch_cache_get_pos(rdata, cache, use_weight, actdef),
|
|
lattice_batch_cache_get_edges(rdata, cache));
|
|
|
|
lattice_render_data_free(rdata);
|
|
}
|
|
|
|
return cache->all_edges;
|
|
}
|
|
|
|
GPUBatch *DRW_lattice_batch_cache_get_all_verts(Lattice *lt)
|
|
{
|
|
LatticeBatchCache *cache = lattice_batch_cache_get(lt);
|
|
|
|
if (cache->all_verts == NULL) {
|
|
LatticeRenderData *rdata = lattice_render_data_create(lt, LR_DATATYPE_VERT);
|
|
|
|
cache->all_verts = GPU_batch_create(
|
|
GPU_PRIM_POINTS, lattice_batch_cache_get_pos(rdata, cache, false, -1), NULL);
|
|
|
|
lattice_render_data_free(rdata);
|
|
}
|
|
|
|
return cache->all_verts;
|
|
}
|
|
|
|
GPUBatch *DRW_lattice_batch_cache_get_edit_verts(Lattice *lt)
|
|
{
|
|
LatticeBatchCache *cache = lattice_batch_cache_get(lt);
|
|
|
|
if (cache->overlay_verts == NULL) {
|
|
lattice_batch_cache_create_overlay_batches(lt);
|
|
}
|
|
|
|
return cache->overlay_verts;
|
|
}
|