When allocating new `CustomData` layers, often we do redundant initialization of arrays. For example, it's common that values are allocated, set to their default value, and then set to some other value. This is wasteful, and it negates the benefits of optimizations to the allocator like D15082. There are two reasons for this. The first is array-of-structs storage that makes it annoying to initialize values manually, and the second is confusing options in the Custom Data API. This patch addresses the latter. The `CustomData` "alloc type" options are rearranged. Now, besides the options that use existing layers, there are two remaining: * `CD_SET_DEFAULT` sets the default value. * Usually zeroes, but for colors this is white (how it was before). * Should be used when you add the layer but don't set all values. * `CD_CONSTRUCT` refers to the "default construct" C++ term. * Only necessary or defined for non-trivial types like vertex groups. * Doesn't do anything for trivial types like `int` or `float3`. * Should be used every other time, when all values will be set. The attribute API's `AttributeInit` types are updated as well. To update code, replace `CD_CALLOC` with `CD_SET_DEFAULT` and `CD_DEFAULT` with `CD_CONSTRUCT`. This doesn't cause any functional changes yet. Follow-up commits will change to avoid initializing new layers where the correctness is clear. Differential Revision: https://developer.blender.org/D15617
353 lines
13 KiB
C
353 lines
13 KiB
C
/* SPDX-License-Identifier: GPL-2.0-or-later
|
|
* Copyright 2009 Blender Foundation. All rights reserved. */
|
|
|
|
/** \file
|
|
* \ingroup RNA
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "RNA_define.h"
|
|
|
|
#include "DNA_customdata_types.h"
|
|
|
|
#include "BLI_sys_types.h"
|
|
|
|
#include "BLI_utildefines.h"
|
|
|
|
#include "rna_internal.h" /* own include */
|
|
|
|
#ifdef RNA_RUNTIME
|
|
|
|
# include "DNA_mesh_types.h"
|
|
|
|
# include "BKE_mesh.h"
|
|
# include "BKE_mesh_mapping.h"
|
|
# include "BKE_mesh_runtime.h"
|
|
# include "BKE_mesh_tangent.h"
|
|
# include "ED_mesh.h"
|
|
|
|
static const char *rna_Mesh_unit_test_compare(struct Mesh *mesh,
|
|
struct Mesh *mesh2,
|
|
float threshold)
|
|
{
|
|
const char *ret = BKE_mesh_cmp(mesh, mesh2, threshold);
|
|
|
|
if (!ret) {
|
|
ret = "Same";
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void rna_Mesh_create_normals_split(Mesh *mesh)
|
|
{
|
|
if (!CustomData_has_layer(&mesh->ldata, CD_NORMAL)) {
|
|
CustomData_add_layer(&mesh->ldata, CD_NORMAL, CD_SET_DEFAULT, NULL, mesh->totloop);
|
|
CustomData_set_layer_flag(&mesh->ldata, CD_NORMAL, CD_FLAG_TEMPORARY);
|
|
}
|
|
}
|
|
|
|
static void rna_Mesh_free_normals_split(Mesh *mesh)
|
|
{
|
|
CustomData_free_layers(&mesh->ldata, CD_NORMAL, mesh->totloop);
|
|
}
|
|
|
|
static void rna_Mesh_calc_tangents(Mesh *mesh, ReportList *reports, const char *uvmap)
|
|
{
|
|
float(*r_looptangents)[4];
|
|
|
|
if (CustomData_has_layer(&mesh->ldata, CD_MLOOPTANGENT)) {
|
|
r_looptangents = CustomData_get_layer(&mesh->ldata, CD_MLOOPTANGENT);
|
|
memset(r_looptangents, 0, sizeof(float[4]) * mesh->totloop);
|
|
}
|
|
else {
|
|
r_looptangents = CustomData_add_layer(
|
|
&mesh->ldata, CD_MLOOPTANGENT, CD_SET_DEFAULT, NULL, mesh->totloop);
|
|
CustomData_set_layer_flag(&mesh->ldata, CD_MLOOPTANGENT, CD_FLAG_TEMPORARY);
|
|
}
|
|
|
|
/* Compute loop normals if needed. */
|
|
if (!CustomData_has_layer(&mesh->ldata, CD_NORMAL)) {
|
|
BKE_mesh_calc_normals_split(mesh);
|
|
}
|
|
|
|
BKE_mesh_calc_loop_tangent_single(mesh, uvmap, r_looptangents, reports);
|
|
}
|
|
|
|
static void rna_Mesh_free_tangents(Mesh *mesh)
|
|
{
|
|
CustomData_free_layers(&mesh->ldata, CD_MLOOPTANGENT, mesh->totloop);
|
|
}
|
|
|
|
static void rna_Mesh_calc_looptri(Mesh *mesh)
|
|
{
|
|
BKE_mesh_runtime_looptri_ensure(mesh);
|
|
}
|
|
|
|
static void rna_Mesh_calc_smooth_groups(
|
|
Mesh *mesh, bool use_bitflags, int *r_poly_group_len, int **r_poly_group, int *r_group_total)
|
|
{
|
|
*r_poly_group_len = mesh->totpoly;
|
|
*r_poly_group = BKE_mesh_calc_smoothgroups(mesh->medge,
|
|
mesh->totedge,
|
|
mesh->mpoly,
|
|
mesh->totpoly,
|
|
mesh->mloop,
|
|
mesh->totloop,
|
|
r_group_total,
|
|
use_bitflags);
|
|
}
|
|
|
|
static void rna_Mesh_normals_split_custom_do(Mesh *mesh,
|
|
float (*custom_loopnors)[3],
|
|
const bool use_vertices)
|
|
{
|
|
if (use_vertices) {
|
|
BKE_mesh_set_custom_normals_from_vertices(mesh, custom_loopnors);
|
|
}
|
|
else {
|
|
BKE_mesh_set_custom_normals(mesh, custom_loopnors);
|
|
}
|
|
}
|
|
|
|
static void rna_Mesh_normals_split_custom_set(Mesh *mesh,
|
|
ReportList *reports,
|
|
int normals_len,
|
|
float *normals)
|
|
{
|
|
float(*loopnors)[3] = (float(*)[3])normals;
|
|
const int numloops = mesh->totloop;
|
|
|
|
if (normals_len != numloops * 3) {
|
|
BKE_reportf(reports,
|
|
RPT_ERROR,
|
|
"Number of custom normals is not number of loops (%f / %d)",
|
|
(float)normals_len / 3.0f,
|
|
numloops);
|
|
return;
|
|
}
|
|
|
|
rna_Mesh_normals_split_custom_do(mesh, loopnors, false);
|
|
|
|
DEG_id_tag_update(&mesh->id, 0);
|
|
}
|
|
|
|
static void rna_Mesh_normals_split_custom_set_from_vertices(Mesh *mesh,
|
|
ReportList *reports,
|
|
int normals_len,
|
|
float *normals)
|
|
{
|
|
float(*vertnors)[3] = (float(*)[3])normals;
|
|
const int numverts = mesh->totvert;
|
|
|
|
if (normals_len != numverts * 3) {
|
|
BKE_reportf(reports,
|
|
RPT_ERROR,
|
|
"Number of custom normals is not number of vertices (%f / %d)",
|
|
(float)normals_len / 3.0f,
|
|
numverts);
|
|
return;
|
|
}
|
|
|
|
rna_Mesh_normals_split_custom_do(mesh, vertnors, true);
|
|
|
|
DEG_id_tag_update(&mesh->id, 0);
|
|
}
|
|
|
|
static void rna_Mesh_transform(Mesh *mesh, float mat[16], bool shape_keys)
|
|
{
|
|
BKE_mesh_transform(mesh, (float(*)[4])mat, shape_keys);
|
|
|
|
DEG_id_tag_update(&mesh->id, 0);
|
|
}
|
|
|
|
static void rna_Mesh_flip_normals(Mesh *mesh)
|
|
{
|
|
BKE_mesh_polygons_flip(mesh->mpoly, mesh->mloop, &mesh->ldata, mesh->totpoly);
|
|
BKE_mesh_tessface_clear(mesh);
|
|
BKE_mesh_normals_tag_dirty(mesh);
|
|
BKE_mesh_runtime_clear_geometry(mesh);
|
|
|
|
DEG_id_tag_update(&mesh->id, 0);
|
|
}
|
|
|
|
static void rna_Mesh_split_faces(Mesh *mesh, bool free_loop_normals)
|
|
{
|
|
BKE_mesh_split_faces(mesh, free_loop_normals != 0);
|
|
}
|
|
|
|
static void rna_Mesh_update_gpu_tag(Mesh *mesh)
|
|
{
|
|
BKE_mesh_batch_cache_dirty_tag(mesh, BKE_MESH_BATCH_DIRTY_ALL);
|
|
}
|
|
|
|
static void rna_Mesh_count_selected_items(Mesh *mesh, int r_count[3])
|
|
{
|
|
BKE_mesh_count_selected_items(mesh, r_count);
|
|
}
|
|
|
|
static void rna_Mesh_clear_geometry(Mesh *mesh)
|
|
{
|
|
BKE_mesh_clear_geometry(mesh);
|
|
|
|
DEG_id_tag_update(&mesh->id, ID_RECALC_GEOMETRY_ALL_MODES);
|
|
WM_main_add_notifier(NC_GEOM | ND_DATA, mesh);
|
|
}
|
|
|
|
#else
|
|
|
|
void RNA_api_mesh(StructRNA *srna)
|
|
{
|
|
FunctionRNA *func;
|
|
PropertyRNA *parm;
|
|
const int normals_array_dim[] = {1, 3};
|
|
|
|
func = RNA_def_function(srna, "transform", "rna_Mesh_transform");
|
|
RNA_def_function_ui_description(func,
|
|
"Transform mesh vertices by a matrix "
|
|
"(Warning: inverts normals if matrix is negative)");
|
|
parm = RNA_def_float_matrix(func, "matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Matrix", 0.0f, 0.0f);
|
|
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
|
|
RNA_def_boolean(func, "shape_keys", 0, "", "Transform Shape Keys");
|
|
|
|
func = RNA_def_function(srna, "flip_normals", "rna_Mesh_flip_normals");
|
|
RNA_def_function_ui_description(func,
|
|
"Invert winding of all polygons "
|
|
"(clears tessellation, does not handle custom normals)");
|
|
|
|
func = RNA_def_function(srna, "calc_normals", "BKE_mesh_calc_normals");
|
|
RNA_def_function_ui_description(func, "Calculate vertex normals");
|
|
|
|
func = RNA_def_function(srna, "create_normals_split", "rna_Mesh_create_normals_split");
|
|
RNA_def_function_ui_description(func, "Empty split vertex normals");
|
|
|
|
func = RNA_def_function(srna, "calc_normals_split", "BKE_mesh_calc_normals_split");
|
|
RNA_def_function_ui_description(func,
|
|
"Calculate split vertex normals, which preserve sharp edges");
|
|
|
|
func = RNA_def_function(srna, "free_normals_split", "rna_Mesh_free_normals_split");
|
|
RNA_def_function_ui_description(func, "Free split vertex normals");
|
|
|
|
func = RNA_def_function(srna, "split_faces", "rna_Mesh_split_faces");
|
|
RNA_def_function_ui_description(func, "Split faces based on the edge angle");
|
|
RNA_def_boolean(
|
|
func, "free_loop_normals", 1, "Free Loop Normals", "Free loop normals custom data layer");
|
|
|
|
func = RNA_def_function(srna, "calc_tangents", "rna_Mesh_calc_tangents");
|
|
RNA_def_function_flag(func, FUNC_USE_REPORTS);
|
|
RNA_def_function_ui_description(
|
|
func,
|
|
"Compute tangents and bitangent signs, to be used together with the split normals "
|
|
"to get a complete tangent space for normal mapping "
|
|
"(split normals are also computed if not yet present)");
|
|
parm = RNA_def_string(func,
|
|
"uvmap",
|
|
NULL,
|
|
MAX_CUSTOMDATA_LAYER_NAME,
|
|
"",
|
|
"Name of the UV map to use for tangent space computation");
|
|
|
|
func = RNA_def_function(srna, "free_tangents", "rna_Mesh_free_tangents");
|
|
RNA_def_function_ui_description(func, "Free tangents");
|
|
|
|
func = RNA_def_function(srna, "calc_loop_triangles", "rna_Mesh_calc_looptri");
|
|
RNA_def_function_ui_description(func,
|
|
"Calculate loop triangle tessellation (supports editmode too)");
|
|
|
|
func = RNA_def_function(srna, "calc_smooth_groups", "rna_Mesh_calc_smooth_groups");
|
|
RNA_def_function_ui_description(func, "Calculate smooth groups from sharp edges");
|
|
RNA_def_boolean(
|
|
func, "use_bitflags", false, "", "Produce bitflags groups instead of simple numeric values");
|
|
/* return values */
|
|
parm = RNA_def_int_array(func, "poly_groups", 1, NULL, 0, 0, "", "Smooth Groups", 0, 0);
|
|
RNA_def_parameter_flags(parm, PROP_DYNAMIC, PARM_OUTPUT);
|
|
parm = RNA_def_int(
|
|
func, "groups", 0, 0, INT_MAX, "groups", "Total number of groups", 0, INT_MAX);
|
|
RNA_def_parameter_flags(parm, 0, PARM_OUTPUT);
|
|
|
|
func = RNA_def_function(srna, "normals_split_custom_set", "rna_Mesh_normals_split_custom_set");
|
|
RNA_def_function_ui_description(func,
|
|
"Define custom split normals of this mesh "
|
|
"(use zero-vectors to keep auto ones)");
|
|
RNA_def_function_flag(func, FUNC_USE_REPORTS);
|
|
/* TODO: see how array size of 0 works, this shouldn't be used. */
|
|
parm = RNA_def_float_array(func, "normals", 1, NULL, -1.0f, 1.0f, "", "Normals", 0.0f, 0.0f);
|
|
RNA_def_property_multi_array(parm, 2, normals_array_dim);
|
|
RNA_def_parameter_flags(parm, PROP_DYNAMIC, PARM_REQUIRED);
|
|
|
|
func = RNA_def_function(srna,
|
|
"normals_split_custom_set_from_vertices",
|
|
"rna_Mesh_normals_split_custom_set_from_vertices");
|
|
RNA_def_function_ui_description(
|
|
func,
|
|
"Define custom split normals of this mesh, from vertices' normals "
|
|
"(use zero-vectors to keep auto ones)");
|
|
RNA_def_function_flag(func, FUNC_USE_REPORTS);
|
|
/* TODO: see how array size of 0 works, this shouldn't be used. */
|
|
parm = RNA_def_float_array(func, "normals", 1, NULL, -1.0f, 1.0f, "", "Normals", 0.0f, 0.0f);
|
|
RNA_def_property_multi_array(parm, 2, normals_array_dim);
|
|
RNA_def_parameter_flags(parm, PROP_DYNAMIC, PARM_REQUIRED);
|
|
|
|
func = RNA_def_function(srna, "update", "ED_mesh_update");
|
|
RNA_def_boolean(func, "calc_edges", 0, "Calculate Edges", "Force recalculation of edges");
|
|
RNA_def_boolean(func,
|
|
"calc_edges_loose",
|
|
0,
|
|
"Calculate Loose Edges",
|
|
"Calculate the loose state of each edge");
|
|
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
|
|
|
|
RNA_def_function(srna, "update_gpu_tag", "rna_Mesh_update_gpu_tag");
|
|
|
|
func = RNA_def_function(srna, "unit_test_compare", "rna_Mesh_unit_test_compare");
|
|
RNA_def_pointer(func, "mesh", "Mesh", "", "Mesh to compare to");
|
|
RNA_def_float_factor(func,
|
|
"threshold",
|
|
FLT_EPSILON * 60,
|
|
0.0f,
|
|
FLT_MAX,
|
|
"Threshold",
|
|
"Comparison tolerance threshold",
|
|
0.0f,
|
|
FLT_MAX);
|
|
/* return value */
|
|
parm = RNA_def_string(
|
|
func, "result", "nothing", 64, "Return value", "String description of result of comparison");
|
|
RNA_def_function_return(func, parm);
|
|
|
|
func = RNA_def_function(srna, "clear_geometry", "rna_Mesh_clear_geometry");
|
|
RNA_def_function_ui_description(
|
|
func,
|
|
"Remove all geometry from the mesh. Note that this does not free shape keys or materials");
|
|
|
|
func = RNA_def_function(srna, "validate", "BKE_mesh_validate");
|
|
RNA_def_function_ui_description(func,
|
|
"Validate geometry, return True when the mesh has had "
|
|
"invalid geometry corrected/removed");
|
|
RNA_def_boolean(func, "verbose", false, "Verbose", "Output information about the errors found");
|
|
RNA_def_boolean(func,
|
|
"clean_customdata",
|
|
true,
|
|
"Clean Custom Data",
|
|
"Remove temp/cached custom-data layers, like e.g. normals...");
|
|
parm = RNA_def_boolean(func, "result", 0, "Result", "");
|
|
RNA_def_function_return(func, parm);
|
|
|
|
func = RNA_def_function(srna, "validate_material_indices", "BKE_mesh_validate_material_indices");
|
|
RNA_def_function_ui_description(
|
|
func,
|
|
"Validate material indices of polygons, return True when the mesh has had "
|
|
"invalid indices corrected (to default 0)");
|
|
parm = RNA_def_boolean(func, "result", 0, "Result", "");
|
|
RNA_def_function_return(func, parm);
|
|
|
|
func = RNA_def_function(srna, "count_selected_items", "rna_Mesh_count_selected_items ");
|
|
RNA_def_function_ui_description(func, "Return the number of selected items (vert, edge, face)");
|
|
parm = RNA_def_int_vector(func, "result", 3, NULL, 0, INT_MAX, "Result", NULL, 0, INT_MAX);
|
|
RNA_def_function_output(func, parm);
|
|
}
|
|
|
|
#endif
|