diff options
author | Brecht Van Lommel <brecht@blender.org> | 2020-07-03 16:30:04 +0300 |
---|---|---|
committer | Brecht Van Lommel <brecht@blender.org> | 2020-09-09 18:01:17 +0300 |
commit | 565510bd7fd87ae146cabafb27f1dfd550450f58 (patch) | |
tree | 57ff84b2aa4ba7e5c1dc0511be858d6b3bf156e6 /source/blender | |
parent | a5db981b0ea044313239c3cc2ee92d19a8f682ea (diff) |
Geometry: add .attributes in the Python API for Mesh, Hair and Point Cloud
This puts all generic float/int/vector/color/string geometry attributes in a new
.attributes property. For meshes it provides a more general API for existing
attributes, for point clouds attributes will be used as an essential part of
particle nodes.
This patch was implemented by @lichtwerk, with further changes by me. It's
still a work in progress, but posting here to show what is going on and for
early feedback.
Ref T76659
Differential Revision: https://developer.blender.org/D8200
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/blenkernel/BKE_attribute.h | 82 | ||||
-rw-r--r-- | source/blender/blenkernel/CMakeLists.txt | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/attribute.c | 291 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/customdata.c | 56 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_customdata_types.h | 10 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_hair_types.h | 2 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_mesh_types.h | 3 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_pointcloud_types.h | 2 | ||||
-rw-r--r-- | source/blender/makesrna/RNA_access.h | 12 | ||||
-rw-r--r-- | source/blender/makesrna/intern/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/blender/makesrna/intern/makesrna.c | 1 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_attribute.c | 662 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_hair.c | 4 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_internal.h | 8 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_mesh.c | 3 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_pointcloud.c | 2 | ||||
-rw-r--r-- | source/blender/python/bmesh/bmesh_py_types_customdata.c | 87 |
17 files changed, 1187 insertions, 41 deletions
diff --git a/source/blender/blenkernel/BKE_attribute.h b/source/blender/blenkernel/BKE_attribute.h new file mode 100644 index 00000000000..9eba13ef7c4 --- /dev/null +++ b/source/blender/blenkernel/BKE_attribute.h @@ -0,0 +1,82 @@ +/* + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup bke + * \brief Generic geometry attributes built on CustomData. + */ + +#pragma once + +#include "BLI_sys_types.h" + +#include "BKE_customdata.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct CustomData; +struct CustomDataLayer; +struct ID; +struct PointerRNA; +struct ReportList; + +/* Attribute.domain */ +typedef enum AttributeDomain { + ATTR_DOMAIN_VERTEX = 0, /* Mesh Vertex */ + ATTR_DOMAIN_EDGE = 1, /* Mesh Edge */ + ATTR_DOMAIN_CORNER = 2, /* Mesh Corner */ + ATTR_DOMAIN_POLYGON = 3, /* Mesh Polygon */ + + ATTR_DOMAIN_POINT = 4, /* Hair or PointCloud Point */ + ATTR_DOMAIN_CURVE = 5, /* Hair Curve */ + + ATTR_DOMAIN_NUM +} AttributeDomain; + +/* Attributes */ + +struct CustomDataLayer *BKE_id_attribute_new(struct ID *id, + const char *name, + const int type, + const AttributeDomain domain, + struct ReportList *reports); +void BKE_id_attribute_remove(struct ID *id, + struct CustomDataLayer *layer, + struct ReportList *reports); + +AttributeDomain BKE_id_attribute_domain(struct ID *id, struct CustomDataLayer *layer); +int BKE_id_attribute_data_length(struct ID *id, struct CustomDataLayer *layer); +bool BKE_id_attribute_rename(struct ID *id, + struct CustomDataLayer *layer, + const char *new_name, + struct ReportList *reports); + +int BKE_id_attributes_length(struct ID *id, const CustomDataMask mask); + +struct CustomDataLayer *BKE_id_attributes_active_get(struct ID *id); +void BKE_id_attributes_active_set(struct ID *id, struct CustomDataLayer *layer); +int *BKE_id_attributes_active_index_p(struct ID *id); + +CustomData *BKE_id_attributes_iterator_next_domain(struct ID *id, struct CustomDataLayer *layers); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index bf3077b7743..cf43d0fe845 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -77,6 +77,7 @@ set(SRC intern/armature.c intern/armature_deform.c intern/armature_update.c + intern/attribute.c intern/autoexec.c intern/blender.c intern/blender_copybuffer.c @@ -267,6 +268,7 @@ set(SRC BKE_animsys.h BKE_appdir.h BKE_armature.h + BKE_attribute.h BKE_autoexec.h BKE_blender.h BKE_blender_copybuffer.h diff --git a/source/blender/blenkernel/intern/attribute.c b/source/blender/blenkernel/intern/attribute.c new file mode 100644 index 00000000000..49c255fc065 --- /dev/null +++ b/source/blender/blenkernel/intern/attribute.c @@ -0,0 +1,291 @@ +/* + * 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. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * Implementation of generic geometry attributes management. This is built + * on top of CustomData, which manages individual domains. + */ + +/** \file + * \ingroup bke + */ + +#include <string.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_ID.h" +#include "DNA_customdata_types.h" +#include "DNA_hair_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_pointcloud_types.h" + +#include "BLI_string_utf8.h" + +#include "BKE_attribute.h" +#include "BKE_customdata.h" +#include "BKE_report.h" + +#include "RNA_access.h" + +typedef struct DomainInfo { + CustomData *customdata; + int length; +} DomainInfo; + +static void get_domains(ID *id, DomainInfo info[ATTR_DOMAIN_NUM]) +{ + memset(info, 0, sizeof(DomainInfo) * ATTR_DOMAIN_NUM); + + switch (GS(id->name)) { + case ID_PT: { + PointCloud *pointcloud = (PointCloud *)id; + info[ATTR_DOMAIN_POINT].customdata = &pointcloud->pdata; + info[ATTR_DOMAIN_POINT].length = pointcloud->totpoint; + break; + } + case ID_ME: { + Mesh *mesh = (Mesh *)id; + info[ATTR_DOMAIN_VERTEX].customdata = &mesh->vdata; + info[ATTR_DOMAIN_VERTEX].length = mesh->totvert; + info[ATTR_DOMAIN_EDGE].customdata = &mesh->edata; + info[ATTR_DOMAIN_EDGE].length = mesh->totedge; + info[ATTR_DOMAIN_CORNER].customdata = &mesh->ldata; + info[ATTR_DOMAIN_CORNER].length = mesh->totloop; + info[ATTR_DOMAIN_POLYGON].customdata = &mesh->pdata; + info[ATTR_DOMAIN_POLYGON].length = mesh->totpoly; + break; + } + case ID_HA: { + Hair *hair = (Hair *)id; + info[ATTR_DOMAIN_POINT].customdata = &hair->pdata; + info[ATTR_DOMAIN_POINT].length = hair->totpoint; + info[ATTR_DOMAIN_CURVE].customdata = &hair->cdata; + info[ATTR_DOMAIN_CURVE].length = hair->totcurve; + break; + } + default: + break; + } +} + +static CustomData *attribute_customdata_find(ID *id, CustomDataLayer *layer) +{ + DomainInfo info[ATTR_DOMAIN_NUM]; + get_domains(id, info); + + for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) { + CustomData *customdata = info[domain].customdata; + if (customdata && ARRAY_HAS_ITEM(layer, customdata->layers, customdata->totlayer)) { + return customdata; + } + } + + return NULL; +} + +bool BKE_id_attribute_rename(ID *id, + CustomDataLayer *layer, + const char *new_name, + ReportList *reports) +{ + CustomData *customdata = attribute_customdata_find(id, layer); + if (customdata == NULL) { + BKE_report(reports, RPT_ERROR, "Attribute is not part of this geometry"); + return false; + } + + BLI_strncpy_utf8(layer->name, new_name, sizeof(layer->name)); + CustomData_set_layer_unique_name(customdata, layer - customdata->layers); + return true; +} + +CustomDataLayer *BKE_id_attribute_new( + ID *id, const char *name, const int type, const AttributeDomain domain, ReportList *reports) +{ + DomainInfo info[ATTR_DOMAIN_NUM]; + get_domains(id, info); + + CustomData *customdata = info[domain].customdata; + if (customdata == NULL) { + BKE_report(reports, RPT_ERROR, "Attribute domain not supported by this geometry type"); + return NULL; + } + + CustomData_add_layer_named(customdata, type, CD_DEFAULT, NULL, info[domain].length, name); + const int index = CustomData_get_named_layer_index(customdata, type, name); + return (index == -1) ? NULL : &(customdata->layers[index]); +} + +void BKE_id_attribute_remove(ID *id, CustomDataLayer *layer, ReportList *reports) +{ + CustomData *customdata = attribute_customdata_find(id, layer); + const int index = (customdata) ? + CustomData_get_named_layer_index(customdata, layer->type, layer->name) : + -1; + + if (index == -1) { + BKE_report(reports, RPT_ERROR, "Attribute is not part of this geometry"); + return; + } + + const int length = BKE_id_attribute_data_length(id, layer); + CustomData_free_layer(customdata, layer->type, length, index); +} + +int BKE_id_attributes_length(ID *id, const CustomDataMask mask) +{ + DomainInfo info[ATTR_DOMAIN_NUM]; + get_domains(id, info); + + int length = 0; + + for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) { + CustomData *customdata = info[domain].customdata; + if (customdata) { + length += CustomData_number_of_layers_typemask(customdata, mask); + } + } + + return length; +} + +AttributeDomain BKE_id_attribute_domain(ID *id, CustomDataLayer *layer) +{ + DomainInfo info[ATTR_DOMAIN_NUM]; + get_domains(id, info); + + for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) { + CustomData *customdata = info[domain].customdata; + if (customdata && ARRAY_HAS_ITEM(layer, customdata->layers, customdata->totlayer)) { + return domain; + } + } + + BLI_assert(!"Custom data layer not found in geometry"); + return ATTR_DOMAIN_NUM; +} + +int BKE_id_attribute_data_length(ID *id, CustomDataLayer *layer) +{ + DomainInfo info[ATTR_DOMAIN_NUM]; + get_domains(id, info); + + for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) { + CustomData *customdata = info[domain].customdata; + if (customdata && ARRAY_HAS_ITEM(layer, customdata->layers, customdata->totlayer)) { + return info[domain].length; + } + } + + BLI_assert(!"Custom data layer not found in geometry"); + return 0; +} + +CustomDataLayer *BKE_id_attributes_active_get(ID *id) +{ + int active_index = *BKE_id_attributes_active_index_p(id); + if (active_index > BKE_id_attributes_length(id, CD_MASK_PROP_ALL)) { + active_index = 0; + } + + DomainInfo info[ATTR_DOMAIN_NUM]; + get_domains(id, info); + + int index = 0; + + for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) { + CustomData *customdata = info[domain].customdata; + if (customdata) { + for (int i = 0; i < customdata->totlayer; i++) { + CustomDataLayer *layer = &customdata->layers[i]; + if (CD_MASK_PROP_ALL & CD_TYPE_AS_MASK(layer->type)) { + if (index == active_index) { + return layer; + } + index++; + } + } + } + } + + return NULL; +} + +void BKE_id_attributes_active_set(ID *id, CustomDataLayer *active_layer) +{ + DomainInfo info[ATTR_DOMAIN_NUM]; + get_domains(id, info); + + int index = 0; + + for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) { + CustomData *customdata = info[domain].customdata; + if (customdata) { + for (int i = 0; i < customdata->totlayer; i++) { + CustomDataLayer *layer = &customdata->layers[i]; + if (layer == active_layer) { + *BKE_id_attributes_active_index_p(id) = index; + return; + } + if (CD_MASK_PROP_ALL & CD_TYPE_AS_MASK(layer->type)) { + index++; + } + } + } + } +} + +int *BKE_id_attributes_active_index_p(ID *id) +{ + switch (GS(id->name)) { + case ID_PT: { + return &((PointCloud *)id)->attributes_active_index; + } + case ID_ME: { + return &((Mesh *)id)->attributes_active_index; + } + case ID_HA: { + return &((Hair *)id)->attributes_active_index; + } + default: + return NULL; + } +} + +CustomData *BKE_id_attributes_iterator_next_domain(ID *id, CustomDataLayer *layers) +{ + DomainInfo info[ATTR_DOMAIN_NUM]; + get_domains(id, info); + + bool use_next = (layers == NULL); + + for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) { + CustomData *customdata = info[domain].customdata; + if (customdata && customdata->layers) { + if (customdata->layers == layers) { + use_next = true; + } + else if (use_next) { + return customdata; + } + } + } + + return NULL; +} diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index b10d910cd66..7c244ed8f58 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -33,7 +33,6 @@ #include "DNA_customdata_types.h" #include "DNA_hair_types.h" #include "DNA_meshdata_types.h" -#include "DNA_pointcloud_types.h" #include "BLI_bitmap.h" #include "BLI_endian_switch.h" @@ -1976,43 +1975,42 @@ const CustomData_MeshMasks CD_MASK_BAREMESH_ORIGINDEX = { }; const CustomData_MeshMasks CD_MASK_MESH = { .vmask = (CD_MASK_MVERT | CD_MASK_MDEFORMVERT | CD_MASK_MVERT_SKIN | CD_MASK_PAINT_MASK | - CD_MASK_GENERIC_DATA | CD_MASK_PROP_COLOR), - .emask = (CD_MASK_MEDGE | CD_MASK_FREESTYLE_EDGE | CD_MASK_GENERIC_DATA), + CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR), + .emask = (CD_MASK_MEDGE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL), .fmask = 0, .lmask = (CD_MASK_MLOOP | CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | - CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_GRID_PAINT_MASK | CD_MASK_GENERIC_DATA), + CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL), .pmask = (CD_MASK_MPOLY | CD_MASK_RECAST | CD_MASK_FACEMAP | CD_MASK_FREESTYLE_FACE | - CD_MASK_GENERIC_DATA | CD_MASK_SCULPT_FACE_SETS), + CD_MASK_PROP_ALL | CD_MASK_SCULPT_FACE_SETS), }; const CustomData_MeshMasks CD_MASK_EDITMESH = { .vmask = (CD_MASK_MDEFORMVERT | CD_MASK_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_SHAPEKEY | - CD_MASK_SHAPE_KEYINDEX | CD_MASK_GENERIC_DATA | CD_MASK_PROP_COLOR), - .emask = (CD_MASK_GENERIC_DATA), + CD_MASK_SHAPE_KEYINDEX | CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR), + .emask = (CD_MASK_PROP_ALL), .fmask = 0, .lmask = (CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL | - CD_MASK_GRID_PAINT_MASK | CD_MASK_GENERIC_DATA), - .pmask = (CD_MASK_RECAST | CD_MASK_FACEMAP | CD_MASK_GENERIC_DATA | CD_MASK_SCULPT_FACE_SETS), + CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL), + .pmask = (CD_MASK_RECAST | CD_MASK_FACEMAP | CD_MASK_PROP_ALL | CD_MASK_SCULPT_FACE_SETS), }; const CustomData_MeshMasks CD_MASK_DERIVEDMESH = { .vmask = (CD_MASK_ORIGINDEX | CD_MASK_MDEFORMVERT | CD_MASK_SHAPEKEY | CD_MASK_MVERT_SKIN | - CD_MASK_ORCO | CD_MASK_CLOTH_ORCO | CD_MASK_GENERIC_DATA | CD_MASK_PROP_COLOR), - .emask = (CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_EDGE | CD_MASK_GENERIC_DATA), + CD_MASK_ORCO | CD_MASK_CLOTH_ORCO | CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR), + .emask = (CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL), .fmask = (CD_MASK_ORIGINDEX | CD_MASK_ORIGSPACE | CD_MASK_PREVIEW_MCOL | CD_MASK_TANGENT), .lmask = (CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_PREVIEW_MLOOPCOL | CD_MASK_ORIGSPACE_MLOOP | - CD_MASK_GENERIC_DATA), /* XXX MISSING CD_MASK_MLOOPTANGENT ? */ + CD_MASK_PROP_ALL), /* XXX MISSING CD_MASK_MLOOPTANGENT ? */ .pmask = (CD_MASK_ORIGINDEX | CD_MASK_RECAST | CD_MASK_FREESTYLE_FACE | CD_MASK_FACEMAP | - CD_MASK_GENERIC_DATA | CD_MASK_SCULPT_FACE_SETS), + CD_MASK_PROP_ALL | CD_MASK_SCULPT_FACE_SETS), }; const CustomData_MeshMasks CD_MASK_BMESH = { .vmask = (CD_MASK_MDEFORMVERT | CD_MASK_BWEIGHT | CD_MASK_MVERT_SKIN | CD_MASK_SHAPEKEY | - CD_MASK_SHAPE_KEYINDEX | CD_MASK_PAINT_MASK | CD_MASK_GENERIC_DATA | - CD_MASK_PROP_COLOR), - .emask = (CD_MASK_BWEIGHT | CD_MASK_CREASE | CD_MASK_FREESTYLE_EDGE | CD_MASK_GENERIC_DATA), + CD_MASK_SHAPE_KEYINDEX | CD_MASK_PAINT_MASK | CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR), + .emask = (CD_MASK_BWEIGHT | CD_MASK_CREASE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL), .fmask = 0, .lmask = (CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL | - CD_MASK_GRID_PAINT_MASK | CD_MASK_GENERIC_DATA), - .pmask = (CD_MASK_RECAST | CD_MASK_FREESTYLE_FACE | CD_MASK_FACEMAP | CD_MASK_GENERIC_DATA | + CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL), + .pmask = (CD_MASK_RECAST | CD_MASK_FREESTYLE_FACE | CD_MASK_FACEMAP | CD_MASK_PROP_ALL | CD_MASK_SCULPT_FACE_SETS), }; /** @@ -2031,18 +2029,18 @@ const CustomData_MeshMasks CD_MASK_EVERYTHING = { .vmask = (CD_MASK_MVERT | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_NORMAL | CD_MASK_MDEFORMVERT | CD_MASK_BWEIGHT | CD_MASK_MVERT_SKIN | CD_MASK_ORCO | CD_MASK_CLOTH_ORCO | CD_MASK_SHAPEKEY | CD_MASK_SHAPE_KEYINDEX | CD_MASK_PAINT_MASK | - CD_MASK_GENERIC_DATA | CD_MASK_PROP_COLOR), + CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR), .emask = (CD_MASK_MEDGE | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_BWEIGHT | - CD_MASK_CREASE | CD_MASK_FREESTYLE_EDGE | CD_MASK_GENERIC_DATA), + CD_MASK_CREASE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL), .fmask = (CD_MASK_MFACE | CD_MASK_ORIGINDEX | CD_MASK_NORMAL | CD_MASK_MTFACE | CD_MASK_MCOL | CD_MASK_ORIGSPACE | CD_MASK_TANGENT | CD_MASK_TESSLOOPNORMAL | CD_MASK_PREVIEW_MCOL | - CD_MASK_GENERIC_DATA), + CD_MASK_PROP_ALL), .lmask = (CD_MASK_MLOOP | CD_MASK_BM_ELEM_PYPTR | CD_MASK_MDISPS | CD_MASK_NORMAL | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_MLOOPTANGENT | CD_MASK_PREVIEW_MLOOPCOL | CD_MASK_ORIGSPACE_MLOOP | - CD_MASK_GRID_PAINT_MASK | CD_MASK_GENERIC_DATA), + CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL), .pmask = (CD_MASK_MPOLY | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_NORMAL | - CD_MASK_RECAST | CD_MASK_FACEMAP | CD_MASK_FREESTYLE_FACE | CD_MASK_GENERIC_DATA | + CD_MASK_RECAST | CD_MASK_FACEMAP | CD_MASK_FREESTYLE_FACE | CD_MASK_PROP_ALL | CD_MASK_SCULPT_FACE_SETS), }; @@ -4306,14 +4304,6 @@ int CustomData_layertype_layers_max(const int type) return typeInfo->layers_max(); } -static bool CustomData_is_property_layer(int type) -{ - if ((type == CD_PROP_FLOAT) || (type == CD_PROP_INT32) || (type == CD_PROP_STRING)) { - return true; - } - return false; -} - static bool cd_layer_find_dupe(CustomData *data, const char *name, int type, int index) { /* see if there is a duplicate */ @@ -4321,8 +4311,8 @@ static bool cd_layer_find_dupe(CustomData *data, const char *name, int type, int if (i != index) { CustomDataLayer *layer = &data->layers[i]; - if (CustomData_is_property_layer(type)) { - if (CustomData_is_property_layer(layer->type) && STREQ(layer->name, name)) { + if (CD_TYPE_AS_MASK(type) & CD_MASK_PROP_ALL) { + if ((CD_TYPE_AS_MASK(layer->type) & CD_MASK_PROP_ALL) && STREQ(layer->name, name)) { return true; } } diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h index 2990fa85c27..51b233449bf 100644 --- a/source/blender/makesdna/DNA_customdata_types.h +++ b/source/blender/makesdna/DNA_customdata_types.h @@ -209,17 +209,17 @@ typedef enum CustomDataType { #define CD_MASK_PROP_FLOAT3 (1ULL << CD_PROP_FLOAT3) #define CD_MASK_PROP_FLOAT2 (1ULL << CD_PROP_FLOAT2) -/** Data types that may be defined for all mesh elements types. */ -#define CD_MASK_GENERIC_DATA \ - (CD_MASK_PROP_FLOAT | CD_MASK_PROP_INT32 | CD_MASK_PROP_STRING | CD_MASK_PROP_FLOAT3 | \ - CD_MASK_PROP_FLOAT2) - /** Multires loop data. */ #define CD_MASK_MULTIRES_GRIDS (CD_MASK_MDISPS | CD_GRID_PAINT_MASK) /* All data layers. */ #define CD_MASK_ALL (~0LL) +/* All generic attributes. */ +#define CD_MASK_PROP_ALL \ + (CD_MASK_PROP_FLOAT | CD_MASK_PROP_FLOAT2 | CD_MASK_PROP_FLOAT3 | CD_MASK_PROP_INT32 | \ + CD_MASK_PROP_COLOR | CD_MASK_PROP_STRING | CD_MASK_MLOOPCOL) + typedef struct CustomData_MeshMasks { uint64_t vmask; uint64_t emask; diff --git a/source/blender/makesdna/DNA_hair_types.h b/source/blender/makesdna/DNA_hair_types.h index d120e61cfef..27799560395 100644 --- a/source/blender/makesdna/DNA_hair_types.h +++ b/source/blender/makesdna/DNA_hair_types.h @@ -56,6 +56,8 @@ typedef struct Hair { /* Custom Data */ struct CustomData pdata; struct CustomData cdata; + int attributes_active_index; + int _pad3; /* Material */ struct Material **mat; diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h index a6aef5b08ad..abfa3cc1b2e 100644 --- a/source/blender/makesdna/DNA_mesh_types.h +++ b/source/blender/makesdna/DNA_mesh_types.h @@ -191,6 +191,9 @@ typedef struct Mesh { int totpoly, totloop; /* END BMESH ONLY */ + int attributes_active_index; + int _pad3; + /* the last selected vertex/edge/face are used for the active face however * this means the active face must always be selected, this is to keep track * of the last selected face and is similar to the old active face flag where diff --git a/source/blender/makesdna/DNA_pointcloud_types.h b/source/blender/makesdna/DNA_pointcloud_types.h index d3b687c2c68..86cff098096 100644 --- a/source/blender/makesdna/DNA_pointcloud_types.h +++ b/source/blender/makesdna/DNA_pointcloud_types.h @@ -38,6 +38,8 @@ typedef struct PointCloud { /* Custom Data */ struct CustomData pdata; + int attributes_active_index; + int _pad4; /* Material */ struct Material **mat; diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 6acd9d16f80..8ee10047750 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -67,6 +67,8 @@ extern StructRNA RNA_ArmatureGpencilModifier; extern StructRNA RNA_ArmatureModifier; extern StructRNA RNA_ArrayGpencilModifier; extern StructRNA RNA_ArrayModifier; +extern StructRNA RNA_Attribute; +extern StructRNA RNA_AttributeGroup; extern StructRNA RNA_BackgroundImage; extern StructRNA RNA_BevelModifier; extern StructRNA RNA_BezierSplinePoint; @@ -93,6 +95,8 @@ extern StructRNA RNA_BrushCapabilitiesVertexPaint; extern StructRNA RNA_BrushTextureSlot; extern StructRNA RNA_BuildGpencilModifier; extern StructRNA RNA_BuildModifier; +extern StructRNA RNA_ByteColorAttribute; +extern StructRNA RNA_ByteColorAttributeValue; extern StructRNA RNA_CacheFile; extern StructRNA RNA_Camera; extern StructRNA RNA_CameraDOFSettings; @@ -247,6 +251,10 @@ extern StructRNA RNA_FaceMap; extern StructRNA RNA_FieldSettings; extern StructRNA RNA_FileBrowserFSMenuEntry; extern StructRNA RNA_FileSelectParams; +extern StructRNA RNA_FloatAttribute; +extern StructRNA RNA_FloatAttributeValue; +extern StructRNA RNA_FloatColorAttribute; +extern StructRNA RNA_FloatColorAttributeValue; extern StructRNA RNA_FloatProperty; extern StructRNA RNA_FloorConstraint; extern StructRNA RNA_FluidDomainSettings; @@ -292,6 +300,8 @@ extern StructRNA RNA_ImagePreview; extern StructRNA RNA_ImageSequence; extern StructRNA RNA_ImageTexture; extern StructRNA RNA_ImageUser; +extern StructRNA RNA_IntAttribute; +extern StructRNA RNA_IntAttributeValue; extern StructRNA RNA_IntProperty; extern StructRNA RNA_Itasc; extern StructRNA RNA_Key; @@ -588,6 +598,8 @@ extern StructRNA RNA_SplinePoint; extern StructRNA RNA_SpotLight; extern StructRNA RNA_Stereo3dDisplay; extern StructRNA RNA_StretchToConstraint; +extern StructRNA RNA_StringAttribute; +extern StructRNA RNA_StringAttributeValue; extern StructRNA RNA_StringProperty; extern StructRNA RNA_Struct; extern StructRNA RNA_StucciTexture; diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt index 303005a0f9e..0387f83d695 100644 --- a/source/blender/makesrna/intern/CMakeLists.txt +++ b/source/blender/makesrna/intern/CMakeLists.txt @@ -30,6 +30,7 @@ set(DEFSRC rna_animation.c rna_animviz.c rna_armature.c + rna_attribute.c rna_boid.c rna_brush.c rna_cachefile.c diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index a81bd4d0832..f1086ab69bc 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -4276,6 +4276,7 @@ static RNAProcessItem PROCESS_ITEMS[] = { {"rna_animation.c", "rna_animation_api.c", RNA_def_animation}, {"rna_animviz.c", NULL, RNA_def_animviz}, {"rna_armature.c", "rna_armature_api.c", RNA_def_armature}, + {"rna_attribute.c", NULL, RNA_def_attribute}, {"rna_boid.c", NULL, RNA_def_boid}, {"rna_brush.c", NULL, RNA_def_brush}, {"rna_cachefile.c", NULL, RNA_def_cachefile}, diff --git a/source/blender/makesrna/intern/rna_attribute.c b/source/blender/makesrna/intern/rna_attribute.c new file mode 100644 index 00000000000..a0bb5f67a08 --- /dev/null +++ b/source/blender/makesrna/intern/rna_attribute.c @@ -0,0 +1,662 @@ +/* + * 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. + */ + +/** \file + * \ingroup RNA + */ + +#include <stdlib.h> + +#include "RNA_access.h" +#include "RNA_define.h" +#include "RNA_enum_types.h" + +#include "rna_internal.h" + +#include "DNA_customdata_types.h" +#include "DNA_hair_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_pointcloud_types.h" + +#include "BKE_attribute.h" +#include "BKE_customdata.h" + +#include "WM_types.h" + +static const EnumPropertyItem rna_enum_attribute_type_items[] = { + {CD_PROP_FLOAT, "FLOAT", 0, "Float", "Floating point value"}, + {CD_PROP_INT32, "INT", 0, "Integer", "32 bit integer"}, + {CD_PROP_FLOAT3, "FLOAT_VECTOR", 0, "Vector", "3D vector with floating point values"}, + {CD_PROP_COLOR, "FLOAT_COLOR", 0, "Float Color", "RGBA color with floating point precisions"}, + {CD_MLOOPCOL, "BYTE_COLOR", 0, "Byte Color", "RGBA color with 8-bit precision"}, + {CD_PROP_STRING, "STRING", 0, "String", "Text string"}, + {0, NULL, 0, NULL, NULL}, +}; + +static const EnumPropertyItem rna_enum_attribute_domain_items[] = { + /* Not implement yet + {ATTR_DOMAIN_GEOMETRY, "GEOMETRY", 0, "Geometry", "Attribute on (whole) geometry"}, */ + {ATTR_DOMAIN_VERTEX, "VERTEX", 0, "Vertex", "Attribute on mesh vertex"}, + {ATTR_DOMAIN_EDGE, "EDGE", 0, "Edge", "Attribute on mesh edge"}, + {ATTR_DOMAIN_CORNER, "CORNER", 0, "Corner", "Attribute on mesh polygon corner"}, + {ATTR_DOMAIN_POLYGON, "POLYGON", 0, "Polygon", "Attribute on mesh polygons"}, + /* Not implement yet + {ATTR_DOMAIN_GRIDS, "GRIDS", 0, "Grids", "Attribute on mesh multires grids"}, */ + {ATTR_DOMAIN_POINT, "POINT", 0, "Point", "Attribute on point"}, + {ATTR_DOMAIN_CURVE, "CURVE", 0, "Curve", "Attribute on hair curve"}, + {0, NULL, 0, NULL, NULL}, +}; + +#ifdef RNA_RUNTIME + +# include "BLI_math.h" + +# include "DEG_depsgraph.h" + +# include "WM_api.h" + +/* Attribute */ + +static char *rna_Attribute_path(PointerRNA *ptr) +{ + CustomDataLayer *layer = ptr->data; + return BLI_sprintfN("attributes['%s']", layer->name); +} + +static void rna_Attribute_name_set(PointerRNA *ptr, const char *value) +{ + BKE_id_attribute_rename(ptr->owner_id, ptr->data, value, NULL); +} + +static int rna_Attribute_type_get(PointerRNA *ptr) +{ + CustomDataLayer *layer = ptr->data; + return layer->type; +} + +static const EnumPropertyItem *rna_Attribute_domain_itemf(bContext *UNUSED(C), + PointerRNA *ptr, + PropertyRNA *UNUSED(prop), + bool *r_free) +{ + EnumPropertyItem *item = NULL; + const EnumPropertyItem *domain_item = NULL; + ID *id = ptr->owner_id; + const ID_Type id_type = GS(id->name); + int totitem = 0, a; + + for (a = 0; rna_enum_attribute_domain_items[a].identifier; a++) { + domain_item = &rna_enum_attribute_domain_items[a]; + + if (id_type == ID_PT && !ELEM(domain_item->value, ATTR_DOMAIN_POINT)) { + continue; + } + if (id_type == ID_HA && !ELEM(domain_item->value, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE)) { + continue; + } + if (id_type == ID_ME && ELEM(domain_item->value, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE)) { + continue; + } + + RNA_enum_item_add(&item, &totitem, domain_item); + } + RNA_enum_item_end(&item, &totitem); + + *r_free = true; + return item; +} + +static int rna_Attribute_domain_get(PointerRNA *ptr) +{ + return BKE_id_attribute_domain(ptr->owner_id, ptr->data); +} + +static void rna_Attribute_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) +{ + ID *id = ptr->owner_id; + CustomDataLayer *layer = (CustomDataLayer *)ptr->data; + + int length = BKE_id_attribute_data_length(id, layer); + size_t struct_size; + + switch (layer->type) { + case CD_PROP_FLOAT: + struct_size = sizeof(MFloatProperty); + break; + case CD_PROP_INT32: + struct_size = sizeof(MIntProperty); + break; + case CD_PROP_FLOAT3: + struct_size = sizeof(float[3]); + break; + case CD_PROP_COLOR: + struct_size = sizeof(MPropCol); + break; + case CD_MLOOPCOL: + struct_size = sizeof(MLoopCol); + break; + case CD_PROP_STRING: + struct_size = sizeof(MStringProperty); + break; + default: + struct_size = 0; + length = 0; + break; + } + + rna_iterator_array_begin(iter, layer->data, struct_size, length, 0, NULL); +} + +static int rna_Attribute_data_length(PointerRNA *ptr) +{ + ID *id = ptr->owner_id; + CustomDataLayer *layer = (CustomDataLayer *)ptr->data; + return BKE_id_attribute_data_length(id, layer); +} + +static void rna_Attribute_update_data(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) +{ + ID *id = ptr->owner_id; + + /* cheating way for importers to avoid slow updates */ + if (id->us > 0) { + DEG_id_tag_update(id, 0); + WM_main_add_notifier(NC_GEOM | ND_DATA, id); + } +} + +/* Color Attribute */ + +static void rna_ByteColorAttributeValue_color_get(PointerRNA *ptr, float *values) +{ + MLoopCol *mlcol = (MLoopCol *)ptr->data; + srgb_to_linearrgb_uchar4(values, &mlcol->r); +} + +static void rna_ByteColorAttributeValue_color_set(PointerRNA *ptr, const float *values) +{ + MLoopCol *mlcol = (MLoopCol *)ptr->data; + linearrgb_to_srgb_uchar4(&mlcol->r, values); +} + +/* Attribute Group */ + +static PointerRNA rna_AttributeGroup_new( + ID *id, ReportList *reports, const char *name, const int type, const int domain) +{ + CustomDataLayer *layer = BKE_id_attribute_new(id, name, type, domain, reports); + DEG_id_tag_update(id, ID_RECALC_GEOMETRY); + WM_main_add_notifier(NC_GEOM | ND_DATA, id); + + PointerRNA ptr; + RNA_pointer_create(id, &RNA_Attribute, layer, &ptr); + return ptr; +} + +static void rna_AttributeGroup_remove(ID *id, ReportList *reports, PointerRNA *attribute_ptr) +{ + CustomDataLayer *layer = (CustomDataLayer *)attribute_ptr->data; + BKE_id_attribute_remove(id, layer, reports); + RNA_POINTER_INVALIDATE(attribute_ptr); + + DEG_id_tag_update(id, ID_RECALC_GEOMETRY); + WM_main_add_notifier(NC_GEOM | ND_DATA, id); +} + +static int rna_Attributes_layer_skip(CollectionPropertyIterator *UNUSED(iter), void *data) +{ + CustomDataLayer *layer = (CustomDataLayer *)data; + return !(CD_TYPE_AS_MASK(layer->type) & CD_MASK_PROP_ALL); +} + +/* Attributes are spread over multiple domains in separate CustomData, we use repeated + * array iterators to loop over all. */ +static void rna_AttributeGroup_next_domain(ID *id, + CollectionPropertyIterator *iter, + int(skip)(CollectionPropertyIterator *iter, void *data)) +{ + do { + CustomDataLayer *prev_layers = (CustomDataLayer *)iter->internal.array.endptr - + iter->internal.array.length; + CustomData *customdata = BKE_id_attributes_iterator_next_domain(id, prev_layers); + if (customdata == NULL) { + return; + } + rna_iterator_array_begin( + iter, customdata->layers, sizeof(CustomDataLayer), customdata->totlayer, false, skip); + } while (!iter->valid); +} + +void rna_AttributeGroup_iterator_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) +{ + memset(&iter->internal.array, 0, sizeof(iter->internal.array)); + rna_AttributeGroup_next_domain(ptr->owner_id, iter, rna_Attributes_layer_skip); +} + +void rna_AttributeGroup_iterator_next(CollectionPropertyIterator *iter) +{ + rna_iterator_array_next(iter); + + if (!iter->valid) { + ID *id = iter->parent.owner_id; + rna_AttributeGroup_next_domain(id, iter, rna_Attributes_layer_skip); + } +} + +PointerRNA rna_AttributeGroup_iterator_get(CollectionPropertyIterator *iter) +{ + /* refine to the proper type */ + StructRNA *type; + CustomDataLayer *layer = rna_iterator_array_get(iter); + + switch (layer->type) { + case CD_PROP_FLOAT: + type = &RNA_FloatAttribute; + break; + case CD_PROP_INT32: + type = &RNA_IntAttribute; + break; + case CD_PROP_FLOAT3: + type = &RNA_FloatVectorAttribute; + break; + case CD_PROP_COLOR: + type = &RNA_FloatColorAttribute; + break; + case CD_MLOOPCOL: + type = &RNA_ByteColorAttribute; + break; + case CD_PROP_STRING: + type = &RNA_StringAttribute; + break; + default: + return PointerRNA_NULL; + } + + return rna_pointer_inherit_refine(&iter->parent, type, layer); +} + +int rna_AttributeGroup_length(PointerRNA *ptr) +{ + return BKE_id_attributes_length(ptr->owner_id, CD_MASK_PROP_ALL); +} + +static int rna_AttributeGroup_active_index_get(PointerRNA *ptr) +{ + return *BKE_id_attributes_active_index_p(ptr->owner_id); +} + +static PointerRNA rna_AttributeGroup_active_get(PointerRNA *ptr) +{ + ID *id = ptr->owner_id; + CustomDataLayer *layer = BKE_id_attributes_active_get(id); + + PointerRNA attribute_ptr; + RNA_pointer_create(id, &RNA_Attribute, layer, &attribute_ptr); + return attribute_ptr; +} + +static void rna_AttributeGroup_active_set(PointerRNA *ptr, + PointerRNA attribute_ptr, + ReportList *UNUSED(reports)) +{ + ID *id = ptr->owner_id; + CustomDataLayer *layer = attribute_ptr.data; + BKE_id_attributes_active_set(id, layer); +} + +static void rna_AttributeGroup_active_index_set(PointerRNA *ptr, int value) +{ + *BKE_id_attributes_active_index_p(ptr->owner_id) = value; +} + +static void rna_AttributeGroup_active_index_range( + PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax) +{ + *min = 0; + *max = BKE_id_attributes_length(ptr->owner_id, CD_MASK_PROP_ALL); + + *softmin = *min; + *softmax = *max; +} + +static void rna_AttributeGroup_update_active(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + rna_Attribute_update_data(bmain, scene, ptr); +} + +#else + +static void rna_def_attribute_float(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "FloatAttribute", "Attribute"); + RNA_def_struct_sdna(srna, "CustomDataLayer"); + RNA_def_struct_ui_text(srna, "Float Attribute", "Geometry attribute with floating point values"); + + prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE); + RNA_def_property_struct_type(prop, "FloatAttributeValue"); + RNA_def_property_collection_funcs(prop, + "rna_Attribute_data_begin", + "rna_iterator_array_next", + "rna_iterator_array_end", + "rna_iterator_array_get", + "rna_Attribute_data_length", + NULL, + NULL, + NULL); + + srna = RNA_def_struct(brna, "FloatAttributeValue", NULL); + RNA_def_struct_sdna(srna, "MFloatProperty"); + RNA_def_struct_ui_text( + srna, "Float Attribute Value", "Floating point value in geometry attribute"); + prop = RNA_def_property(srna, "value", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "f"); + RNA_def_property_update(prop, 0, "rna_Attribute_update_data"); +} + +static void rna_def_attribute_float_vector(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + /* Float Vector Attribute */ + srna = RNA_def_struct(brna, "FloatVectorAttribute", "Attribute"); + RNA_def_struct_sdna(srna, "CustomDataLayer"); + RNA_def_struct_ui_text( + srna, "Float Vector Attribute", "Vector geometry attribute, with floating point precision"); + + prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE); + RNA_def_property_struct_type(prop, "FloatVectorAttributeValue"); + RNA_def_property_collection_funcs(prop, + "rna_Attribute_data_begin", + "rna_iterator_array_next", + "rna_iterator_array_end", + "rna_iterator_array_get", + "rna_Attribute_data_length", + NULL, + NULL, + NULL); + + /* Float Vector Attribute Value */ + srna = RNA_def_struct(brna, "FloatVectorAttributeValue", NULL); + RNA_def_struct_sdna(srna, "vec3f"); + RNA_def_struct_ui_text( + srna, "Float Vector Attribute Value", "Vector value in geometry attribute"); + + prop = RNA_def_property(srna, "vector", PROP_FLOAT, PROP_DIRECTION); + RNA_def_property_ui_text(prop, "Vector", "3D vector"); + RNA_def_property_float_sdna(prop, NULL, "x"); + RNA_def_property_array(prop, 3); + RNA_def_property_update(prop, 0, "rna_Attribute_update_data"); +} + +static void rna_def_attribute_float_color(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + /* Float Color Attribute */ + srna = RNA_def_struct(brna, "FloatColorAttribute", "Attribute"); + RNA_def_struct_sdna(srna, "CustomDataLayer"); + RNA_def_struct_ui_text( + srna, "Float Color Attribute", "Color geometry attribute, with floating point precision"); + + prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE); + RNA_def_property_struct_type(prop, "FloatColorAttributeValue"); + RNA_def_property_collection_funcs(prop, + "rna_Attribute_data_begin", + "rna_iterator_array_next", + "rna_iterator_array_end", + "rna_iterator_array_get", + "rna_Attribute_data_length", + NULL, + NULL, + NULL); + + /* Float Color Attribute Value */ + srna = RNA_def_struct(brna, "FloatColorAttributeValue", NULL); + RNA_def_struct_sdna(srna, "MPropCol"); + RNA_def_struct_ui_text(srna, "Float Color Attribute Value", "Color value in geometry attribute"); + + prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR); + RNA_def_property_ui_text(prop, "Color", "RGBA color in scene linear color space"); + RNA_def_property_float_sdna(prop, NULL, "color"); + RNA_def_property_array(prop, 4); + RNA_def_property_update(prop, 0, "rna_Attribute_update_data"); +} + +static void rna_def_attribute_byte_color(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + /* Byte Color Attribute */ + srna = RNA_def_struct(brna, "ByteColorAttribute", "Attribute"); + RNA_def_struct_sdna(srna, "CustomDataLayer"); + RNA_def_struct_ui_text( + srna, "Byte Color Attribute", "Color geometry attribute, with 8-bit precision"); + + prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE); + RNA_def_property_struct_type(prop, "ByteColorAttributeValue"); + RNA_def_property_collection_funcs(prop, + "rna_Attribute_data_begin", + "rna_iterator_array_next", + "rna_iterator_array_end", + "rna_iterator_array_get", + "rna_Attribute_data_length", + NULL, + NULL, + NULL); + + /* Byte Color Attribute Value */ + srna = RNA_def_struct(brna, "ByteColorAttributeValue", NULL); + RNA_def_struct_sdna(srna, "MLoopCol"); + RNA_def_struct_ui_text(srna, "Byte Color Attribute Value", "Color value in geometry attribute"); + + prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR); + RNA_def_property_array(prop, 4); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_float_funcs(prop, + "rna_ByteColorAttributeValue_color_get", + "rna_ByteColorAttributeValue_color_set", + NULL); + RNA_def_property_ui_text(prop, "Color", "RGBA color in scene linear color space"); + RNA_def_property_update(prop, 0, "rna_Attribute_update_data"); +} + +static void rna_def_attribute_int(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "IntAttribute", "Attribute"); + RNA_def_struct_sdna(srna, "CustomDataLayer"); + RNA_def_struct_ui_text(srna, "Int Attribute", "Integer geometry attribute"); + + prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE); + RNA_def_property_struct_type(prop, "IntAttributeValue"); + RNA_def_property_collection_funcs(prop, + "rna_Attribute_data_begin", + "rna_iterator_array_next", + "rna_iterator_array_end", + "rna_iterator_array_get", + "rna_Attribute_data_length", + NULL, + NULL, + NULL); + + srna = RNA_def_struct(brna, "IntAttributeValue", NULL); + RNA_def_struct_sdna(srna, "MIntProperty"); + RNA_def_struct_ui_text(srna, "Integer Attribute Value", "Integer value in geometry attribute"); + prop = RNA_def_property(srna, "value", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "i"); + RNA_def_property_update(prop, 0, "rna_Attribute_update_data"); +} + +static void rna_def_attribute_string(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "StringAttribute", "Attribute"); + RNA_def_struct_sdna(srna, "CustomDataLayer"); + RNA_def_struct_ui_text(srna, "String Attribute", "String geometry attribute"); + + prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE); + RNA_def_property_struct_type(prop, "StringAttributeValue"); + RNA_def_property_collection_funcs(prop, + "rna_Attribute_data_begin", + "rna_iterator_array_next", + "rna_iterator_array_end", + "rna_iterator_array_get", + "rna_Attribute_data_length", + NULL, + NULL, + NULL); + + srna = RNA_def_struct(brna, "StringAttributeValue", NULL); + RNA_def_struct_sdna(srna, "MStringProperty"); + RNA_def_struct_ui_text(srna, "String Attribute Value", "String value in geometry attribute"); + prop = RNA_def_property(srna, "value", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "s"); + RNA_def_property_update(prop, 0, "rna_Attribute_update_data"); +} + +static void rna_def_attribute(BlenderRNA *brna) +{ + PropertyRNA *prop; + StructRNA *srna; + + srna = RNA_def_struct(brna, "Attribute", NULL); + RNA_def_struct_sdna(srna, "CustomDataLayer"); + RNA_def_struct_ui_text(srna, "Attribute", "Geometry attribute"); + RNA_def_struct_path_func(srna, "rna_Attribute_path"); + + prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); + RNA_def_struct_name_property(srna, prop); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Attribute_name_set"); + RNA_def_property_ui_text(prop, "Name", "Name of the Attribute"); + RNA_def_struct_name_property(srna, prop); + + prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "type"); + RNA_def_property_enum_items(prop, rna_enum_attribute_type_items); + RNA_def_property_enum_funcs(prop, "rna_Attribute_type_get", NULL, NULL); + RNA_def_property_ui_text(prop, "Data Type", "Type of data stored in attribute"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + + prop = RNA_def_property(srna, "domain", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_enum_attribute_domain_items); + RNA_def_property_enum_funcs( + prop, "rna_Attribute_domain_get", NULL, "rna_Attribute_domain_itemf"); + RNA_def_property_ui_text(prop, "Domain", "Domain of the Attribute"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + + /* types */ + rna_def_attribute_float(brna); + rna_def_attribute_float_vector(brna); + rna_def_attribute_float_color(brna); + rna_def_attribute_byte_color(brna); + rna_def_attribute_int(brna); + rna_def_attribute_string(brna); +} + +/* Mesh/PointCloud/Hair.attributes */ +static void rna_def_attribute_group(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + FunctionRNA *func; + PropertyRNA *parm; + + srna = RNA_def_struct(brna, "AttributeGroup", NULL); + RNA_def_struct_ui_text(srna, "Attribute Group", "Group of geometry attributes"); + RNA_def_struct_sdna(srna, "ID"); + + /* API */ + func = RNA_def_function(srna, "new", "rna_AttributeGroup_new"); + RNA_def_function_ui_description(func, "Add an attribute"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); + parm = RNA_def_string(func, "name", "Attribute", 0, "", "Attribute name"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_enum( + func, "type", rna_enum_attribute_type_items, CD_PROP_FLOAT, "Type", "Attribute type"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_enum(func, + "domain", + rna_enum_attribute_domain_items, + ATTR_DOMAIN_VERTEX, + "Domain", + "Attribute domain"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_pointer(func, "attribute", "Attribute", "", "New geometry attribute"); + RNA_def_parameter_flags(parm, 0, PARM_RNAPTR); + RNA_def_function_return(func, parm); + + func = RNA_def_function(srna, "remove", "rna_AttributeGroup_remove"); + RNA_def_function_ui_description(func, "Remove an attribute"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); + parm = RNA_def_pointer(func, "attribute", "Attribute", "", "Geometry Attribute"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); + + /* Active */ + prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "Attribute"); + RNA_def_property_pointer_funcs( + prop, "rna_AttributeGroup_active_get", "rna_AttributeGroup_active_set", NULL, NULL); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_UNLINK); + RNA_def_property_ui_text(prop, "Active Attribute", "Active attribute"); + RNA_def_property_update(prop, 0, "rna_AttributeGroup_update_active"); + + prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_NONE); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_int_funcs(prop, + "rna_AttributeGroup_active_index_get", + "rna_AttributeGroup_active_index_set", + "rna_AttributeGroup_active_index_range"); + RNA_def_property_update(prop, 0, "rna_AttributeGroup_update_active"); +} + +void rna_def_attributes_common(StructRNA *srna) +{ + PropertyRNA *prop; + + /* Attributes */ + prop = RNA_def_property(srna, "attributes", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_funcs(prop, + "rna_AttributeGroup_iterator_begin", + "rna_AttributeGroup_iterator_next", + "rna_iterator_array_end", + "rna_AttributeGroup_iterator_get", + "rna_AttributeGroup_length", + NULL, + NULL, + NULL); + RNA_def_property_struct_type(prop, "Attribute"); + RNA_def_property_ui_text(prop, "Attributes", "Geometry attributes"); + RNA_def_property_srna(prop, "AttributeGroup"); +} + +void RNA_def_attribute(BlenderRNA *brna) +{ + rna_def_attribute(brna); + rna_def_attribute_group(brna); +} +#endif diff --git a/source/blender/makesrna/intern/rna_hair.c b/source/blender/makesrna/intern/rna_hair.c index f6dc93323fe..4ca66c6b583 100644 --- a/source/blender/makesrna/intern/rna_hair.c +++ b/source/blender/makesrna/intern/rna_hair.c @@ -34,6 +34,7 @@ # include "BLI_math_vector.h" +# include "BKE_attribute.h" # include "BKE_hair.h" # include "DEG_depsgraph.h" @@ -224,6 +225,9 @@ static void rna_def_hair(BlenderRNA *brna) RNA_def_property_collection_funcs( prop, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "rna_IDMaterials_assign_int"); + /* attributes */ + rna_def_attributes_common(srna); + /* common */ rna_def_animdata_common(srna); } diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index ad43202d850..eaf4e8866f9 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -151,6 +151,7 @@ void RNA_def_action(struct BlenderRNA *brna); void RNA_def_animation(struct BlenderRNA *brna); void RNA_def_animviz(struct BlenderRNA *brna); void RNA_def_armature(struct BlenderRNA *brna); +void RNA_def_attribute(struct BlenderRNA *brna); void RNA_def_boid(struct BlenderRNA *brna); void RNA_def_brush(struct BlenderRNA *brna); void RNA_def_cachefile(struct BlenderRNA *brna); @@ -221,6 +222,13 @@ void RNA_def_xr(struct BlenderRNA *brna); /* Common Define functions */ +void rna_def_attributes_common(struct StructRNA *srna); + +void rna_AttributeGroup_iterator_begin(CollectionPropertyIterator *iter, PointerRNA *ptr); +void rna_AttributeGroup_iterator_next(CollectionPropertyIterator *iter); +PointerRNA rna_AttributeGroup_iterator_get(CollectionPropertyIterator *iter); +int rna_AttributeGroup_length(PointerRNA *ptr); + void rna_def_animdata_common(struct StructRNA *srna); bool rna_AnimaData_override_apply(struct Main *bmain, diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index bb5ec0d6835..346946dfb0d 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -3200,6 +3200,9 @@ static void rna_def_mesh(BlenderRNA *brna) rna_def_paint_mask(brna, prop); /* End paint mask */ + /* Attributes */ + rna_def_attributes_common(srna); + /* Remesh */ prop = RNA_def_property(srna, "remesh_voxel_size", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_sdna(prop, NULL, "remesh_voxel_size"); diff --git a/source/blender/makesrna/intern/rna_pointcloud.c b/source/blender/makesrna/intern/rna_pointcloud.c index 4e3243ae80f..90ff69b2a8a 100644 --- a/source/blender/makesrna/intern/rna_pointcloud.c +++ b/source/blender/makesrna/intern/rna_pointcloud.c @@ -156,6 +156,8 @@ static void rna_def_pointcloud(BlenderRNA *brna) RNA_def_property_collection_funcs( prop, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "rna_IDMaterials_assign_int"); + rna_def_attributes_common(srna); + /* common */ rna_def_animdata_common(srna); } diff --git a/source/blender/python/bmesh/bmesh_py_types_customdata.c b/source/blender/python/bmesh/bmesh_py_types_customdata.c index a9a9a3ad5d9..a74be2b580e 100644 --- a/source/blender/python/bmesh/bmesh_py_types_customdata.c +++ b/source/blender/python/bmesh/bmesh_py_types_customdata.c @@ -84,6 +84,15 @@ PyDoc_STRVAR(bpy_bmlayeraccess_collection__float_doc, "Generic float custom-data layer.\n\ntype: :class:`BMLayerCollection`"); PyDoc_STRVAR(bpy_bmlayeraccess_collection__int_doc, "Generic int custom-data layer.\n\ntype: :class:`BMLayerCollection`"); +PyDoc_STRVAR(bpy_bmlayeraccess_collection__float_vector_doc, + "Generic 3D vector with float precision custom-data layer.\n\ntype: " + ":class:`BMLayerCollection`"); +PyDoc_STRVAR(bpy_bmlayeraccess_collection__float_color_doc, + "Generic RGBA color with float precision custom-data layer.\n\ntype: " + ":class:`BMLayerCollection`"); +PyDoc_STRVAR(bpy_bmlayeraccess_collection__color_doc, + "Generic RGBA color with 8-bit precision custom-data layer.\n\ntype: " + ":class:`BMLayerCollection`"); PyDoc_STRVAR(bpy_bmlayeraccess_collection__string_doc, "Generic string custom-data layer (exposed as bytes, 255 max length).\n\ntype: " ":class:`BMLayerCollection`"); @@ -102,8 +111,6 @@ PyDoc_STRVAR(bpy_bmlayeraccess_collection__crease_doc, PyDoc_STRVAR( bpy_bmlayeraccess_collection__uv_doc, "Accessor for :class:`BMLoopUV` UV (as a 2D Vector).\n\ntype: :class:`BMLayerCollection`"); -PyDoc_STRVAR(bpy_bmlayeraccess_collection__color_doc, - "Accessor for vertex color layer.\n\ntype: :class:`BMLayerCollection`"); PyDoc_STRVAR(bpy_bmlayeraccess_collection__skin_doc, "Accessor for skin layer.\n\ntype: :class:`BMLayerCollection`"); PyDoc_STRVAR(bpy_bmlayeraccess_collection__paint_mask_doc, @@ -188,6 +195,21 @@ static PyGetSetDef bpy_bmlayeraccess_vert_getseters[] = { (setter)NULL, bpy_bmlayeraccess_collection__int_doc, (void *)CD_PROP_INT32}, + {"float_vector", + (getter)bpy_bmlayeraccess_collection_get, + (setter)NULL, + bpy_bmlayeraccess_collection__float_vector_doc, + (void *)CD_PROP_FLOAT3}, + {"float_color", + (getter)bpy_bmlayeraccess_collection_get, + (setter)NULL, + bpy_bmlayeraccess_collection__float_color_doc, + (void *)CD_PROP_COLOR}, + {"color", + (getter)bpy_bmlayeraccess_collection_get, + (setter)NULL, + bpy_bmlayeraccess_collection__color_doc, + (void *)CD_MLOOPCOL}, {"string", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, @@ -229,6 +251,21 @@ static PyGetSetDef bpy_bmlayeraccess_edge_getseters[] = { (setter)NULL, bpy_bmlayeraccess_collection__int_doc, (void *)CD_PROP_INT32}, + {"float_vector", + (getter)bpy_bmlayeraccess_collection_get, + (setter)NULL, + bpy_bmlayeraccess_collection__float_vector_doc, + (void *)CD_PROP_FLOAT3}, + {"float_color", + (getter)bpy_bmlayeraccess_collection_get, + (setter)NULL, + bpy_bmlayeraccess_collection__float_color_doc, + (void *)CD_PROP_COLOR}, + {"color", + (getter)bpy_bmlayeraccess_collection_get, + (setter)NULL, + bpy_bmlayeraccess_collection__color_doc, + (void *)CD_MLOOPCOL}, {"string", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, @@ -267,6 +304,21 @@ static PyGetSetDef bpy_bmlayeraccess_face_getseters[] = { (setter)NULL, bpy_bmlayeraccess_collection__int_doc, (void *)CD_PROP_INT32}, + {"float_vector", + (getter)bpy_bmlayeraccess_collection_get, + (setter)NULL, + bpy_bmlayeraccess_collection__float_vector_doc, + (void *)CD_PROP_FLOAT3}, + {"float_color", + (getter)bpy_bmlayeraccess_collection_get, + (setter)NULL, + bpy_bmlayeraccess_collection__float_color_doc, + (void *)CD_PROP_COLOR}, + {"color", + (getter)bpy_bmlayeraccess_collection_get, + (setter)NULL, + bpy_bmlayeraccess_collection__color_doc, + (void *)CD_MLOOPCOL}, {"string", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, @@ -300,12 +352,21 @@ static PyGetSetDef bpy_bmlayeraccess_loop_getseters[] = { (setter)NULL, bpy_bmlayeraccess_collection__int_doc, (void *)CD_PROP_INT32}, + {"float_vector", + (getter)bpy_bmlayeraccess_collection_get, + (setter)NULL, + bpy_bmlayeraccess_collection__float_vector_doc, + (void *)CD_PROP_FLOAT3}, + {"float_color", + (getter)bpy_bmlayeraccess_collection_get, + (setter)NULL, + bpy_bmlayeraccess_collection__float_color_doc, + (void *)CD_PROP_COLOR}, {"string", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, bpy_bmlayeraccess_collection__string_doc, (void *)CD_PROP_STRING}, - {"uv", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, @@ -1072,6 +1133,14 @@ PyObject *BPy_BMLayerItem_GetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer) ret = PyLong_FromLong(*(int *)value); break; } + case CD_PROP_FLOAT3: { + ret = Vector_CreatePyObject_wrap((float *)value, 3, NULL); + break; + } + case CD_PROP_COLOR: { + ret = Vector_CreatePyObject_wrap((float *)value, 4, NULL); + break; + } case CD_PROP_STRING: { MStringProperty *mstring = value; ret = PyBytes_FromStringAndSize(mstring->s, mstring->s_len); @@ -1150,6 +1219,18 @@ int BPy_BMLayerItem_SetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer, PyObj } break; } + case CD_PROP_FLOAT3: { + if (mathutils_array_parse((float *)value, 3, 3, py_value, "BMElem Float Vector") == -1) { + ret = -1; + } + break; + } + case CD_PROP_COLOR: { + if (mathutils_array_parse((float *)value, 4, 4, py_value, "BMElem Float Color") == -1) { + ret = -1; + } + break; + } case CD_PROP_STRING: { MStringProperty *mstring = value; char *tmp_val; |