2011-10-10 09:38:02 +00:00
|
|
|
/*
|
2002-10-12 11:37:38 +00:00
|
|
|
* 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
|
2008-01-07 19:13:47 +00:00
|
|
|
* of the License, or (at your option) any later version.
|
2002-10-12 11:37:38 +00:00
|
|
|
*
|
|
|
|
* 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,
|
2010-02-12 13:34:04 +00:00
|
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2002-10-12 11:37:38 +00:00
|
|
|
*
|
|
|
|
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
|
|
|
* All rights reserved.
|
|
|
|
*/
|
|
|
|
|
2019-02-18 08:08:12 +11:00
|
|
|
/** \file
|
|
|
|
* \ingroup bke
|
2011-02-27 20:40:57 +00:00
|
|
|
*/
|
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
2020-08-28 16:10:17 +02:00
|
|
|
/* Allow using deprecated functionality for .blend file I/O. */
|
2020-08-28 15:45:11 +02:00
|
|
|
#define DNA_DEPRECATED_ALLOW
|
|
|
|
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "DNA_defaults.h"
|
2002-10-12 11:37:38 +00:00
|
|
|
#include "DNA_key_types.h"
|
2020-05-07 15:55:52 +02:00
|
|
|
#include "DNA_material_types.h"
|
2012-02-19 22:17:30 +00:00
|
|
|
#include "DNA_mesh_types.h"
|
2018-06-26 17:45:00 +02:00
|
|
|
#include "DNA_meshdata_types.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "DNA_object_types.h"
|
2002-10-12 11:37:38 +00:00
|
|
|
|
2018-06-26 17:45:00 +02:00
|
|
|
#include "BLI_bitmap.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "BLI_edgehash.h"
|
2020-08-28 15:45:11 +02:00
|
|
|
#include "BLI_endian_switch.h"
|
2020-03-05 14:53:23 +01:00
|
|
|
#include "BLI_ghash.h"
|
|
|
|
#include "BLI_hash.h"
|
2017-02-22 09:40:46 +01:00
|
|
|
#include "BLI_linklist.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "BLI_math.h"
|
2017-02-22 09:40:46 +01:00
|
|
|
#include "BLI_memarena.h"
|
2013-09-20 11:14:08 +00:00
|
|
|
#include "BLI_string.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "BLI_utildefines.h"
|
2011-01-07 18:36:47 +00:00
|
|
|
|
2020-03-06 15:38:52 +01:00
|
|
|
#include "BLT_translation.h"
|
|
|
|
|
2020-04-03 13:07:36 +02:00
|
|
|
#include "BKE_anim_data.h"
|
2020-08-28 15:45:11 +02:00
|
|
|
#include "BKE_deform.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "BKE_editmesh.h"
|
2002-10-12 11:37:38 +00:00
|
|
|
#include "BKE_global.h"
|
2020-03-06 15:38:52 +01:00
|
|
|
#include "BKE_idtype.h"
|
2019-07-30 18:38:31 +02:00
|
|
|
#include "BKE_key.h"
|
2020-02-10 12:58:59 +01:00
|
|
|
#include "BKE_lib_id.h"
|
2020-05-07 15:55:52 +02:00
|
|
|
#include "BKE_lib_query.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "BKE_main.h"
|
2002-10-12 11:37:38 +00:00
|
|
|
#include "BKE_material.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "BKE_mesh.h"
|
|
|
|
#include "BKE_mesh_runtime.h"
|
2020-06-10 22:32:06 +10:00
|
|
|
#include "BKE_mesh_wrapper.h"
|
2010-09-09 00:14:51 +00:00
|
|
|
#include "BKE_modifier.h"
|
|
|
|
#include "BKE_multires.h"
|
2002-10-12 11:37:38 +00:00
|
|
|
#include "BKE_object.h"
|
|
|
|
|
2020-03-05 14:53:23 +01:00
|
|
|
#include "PIL_time.h"
|
|
|
|
|
Depsgraph: New dependency graph integration commit
This commit integrates the work done so far on the new dependency graph system,
where goal was to replace legacy depsgraph with the new one, supporting loads of
neat features like:
- More granular dependency relation nature, which solves issues with fake cycles
in the dependencies.
- Move towards all-animatable, by better integration of drivers into the system.
- Lay down some basis for upcoming copy-on-write, overrides and so on.
The new system is living side-by-side with the previous one and disabled by
default, so nothing will become suddenly broken. The way to enable new depsgraph
is to pass `--new-depsgraph` command line argument.
It's a bit early to consider the system production-ready, there are some TODOs
and issues were discovered during the merge period, they'll be addressed ASAP.
But it's important to merge, because it's the only way to attract artists to
really start testing this system.
There are number of assorted documents related on the design of the new system:
* http://wiki.blender.org/index.php/User:Aligorith/GSoC2013_Depsgraph#Design_Documents
* http://wiki.blender.org/index.php/User:Nazg-gul/DependencyGraph
There are also some user-related information online:
* http://code.blender.org/2015/02/blender-dependency-graph-branch-for-users/
* http://code.blender.org/2015/03/more-dependency-graph-tricks/
Kudos to everyone who was involved into the project:
- Joshua "Aligorith" Leung -- design specification, initial code
- Lukas "lukas_t" Toenne -- integrating code into blender, with further fixes
- Sergey "Sergey" "Sharybin" -- some mocking around, trying to wrap up the
project and so
- Bassam "slikdigit" Kurdali -- stressing the new system, reporting all the
issues and recording/writing documentation.
- Everyone else who i forgot to mention here :)
2015-05-12 15:05:57 +05:00
|
|
|
#include "DEG_depsgraph.h"
|
2019-07-02 16:48:28 +02:00
|
|
|
#include "DEG_depsgraph_query.h"
|
2009-05-26 04:17:47 +00:00
|
|
|
|
2020-08-28 15:45:11 +02:00
|
|
|
#include "BLO_read_write.h"
|
|
|
|
|
2020-03-09 18:40:06 +01:00
|
|
|
static void mesh_clear_geometry(Mesh *mesh);
|
2020-03-06 15:38:52 +01:00
|
|
|
static void mesh_tessface_clear_intern(Mesh *mesh, int free_customdata);
|
|
|
|
|
|
|
|
static void mesh_init_data(ID *id)
|
|
|
|
{
|
|
|
|
Mesh *mesh = (Mesh *)id;
|
|
|
|
|
|
|
|
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(mesh, id));
|
|
|
|
|
|
|
|
MEMCPY_STRUCT_AFTER(mesh, DNA_struct_default_get(Mesh), id);
|
|
|
|
|
|
|
|
CustomData_reset(&mesh->vdata);
|
|
|
|
CustomData_reset(&mesh->edata);
|
|
|
|
CustomData_reset(&mesh->fdata);
|
|
|
|
CustomData_reset(&mesh->pdata);
|
|
|
|
CustomData_reset(&mesh->ldata);
|
|
|
|
|
|
|
|
BKE_mesh_runtime_reset(mesh);
|
|
|
|
|
|
|
|
mesh->face_sets_color_seed = BLI_hash_int(PIL_check_seconds_timer_i() & UINT_MAX);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int flag)
|
|
|
|
{
|
|
|
|
Mesh *mesh_dst = (Mesh *)id_dst;
|
|
|
|
const Mesh *mesh_src = (const Mesh *)id_src;
|
|
|
|
|
|
|
|
BKE_mesh_runtime_reset_on_copy(mesh_dst, flag);
|
|
|
|
if ((mesh_src->id.tag & LIB_TAG_NO_MAIN) == 0) {
|
|
|
|
/* This is a direct copy of a main mesh, so for now it has the same topology. */
|
|
|
|
mesh_dst->runtime.deformed_only = true;
|
|
|
|
}
|
2020-08-11 21:46:06 +10:00
|
|
|
/* This option is set for run-time meshes that have been copied from the current objects mode.
|
|
|
|
* Currently this is used for edit-mesh although it could be used for sculpt or other
|
|
|
|
* kinds of data specific to an objects mode.
|
|
|
|
*
|
|
|
|
* The flag signals that the mesh hasn't been modified from the data that generated it,
|
|
|
|
* allowing us to use the object-mode data for drawing.
|
|
|
|
*
|
|
|
|
* While this could be the callers responsibility, keep here since it's
|
|
|
|
* highly unlikely we want to create a duplicate and not use it for drawing. */
|
2020-03-06 15:38:52 +01:00
|
|
|
mesh_dst->runtime.is_original = false;
|
|
|
|
|
|
|
|
/* Only do tessface if we have no polys. */
|
|
|
|
const bool do_tessface = ((mesh_src->totface != 0) && (mesh_src->totpoly == 0));
|
|
|
|
|
|
|
|
CustomData_MeshMasks mask = CD_MASK_MESH;
|
|
|
|
|
|
|
|
if (mesh_src->id.tag & LIB_TAG_NO_MAIN) {
|
|
|
|
/* For copies in depsgraph, keep data like origindex and orco. */
|
|
|
|
CustomData_MeshMasks_update(&mask, &CD_MASK_DERIVEDMESH);
|
|
|
|
}
|
|
|
|
|
|
|
|
mesh_dst->mat = MEM_dupallocN(mesh_src->mat);
|
|
|
|
|
|
|
|
const eCDAllocType alloc_type = (flag & LIB_ID_COPY_CD_REFERENCE) ? CD_REFERENCE : CD_DUPLICATE;
|
|
|
|
CustomData_copy(&mesh_src->vdata, &mesh_dst->vdata, mask.vmask, alloc_type, mesh_dst->totvert);
|
|
|
|
CustomData_copy(&mesh_src->edata, &mesh_dst->edata, mask.emask, alloc_type, mesh_dst->totedge);
|
|
|
|
CustomData_copy(&mesh_src->ldata, &mesh_dst->ldata, mask.lmask, alloc_type, mesh_dst->totloop);
|
|
|
|
CustomData_copy(&mesh_src->pdata, &mesh_dst->pdata, mask.pmask, alloc_type, mesh_dst->totpoly);
|
|
|
|
if (do_tessface) {
|
|
|
|
CustomData_copy(&mesh_src->fdata, &mesh_dst->fdata, mask.fmask, alloc_type, mesh_dst->totface);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
mesh_tessface_clear_intern(mesh_dst, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
BKE_mesh_update_customdata_pointers(mesh_dst, do_tessface);
|
|
|
|
|
|
|
|
mesh_dst->edit_mesh = NULL;
|
|
|
|
|
|
|
|
mesh_dst->mselect = MEM_dupallocN(mesh_dst->mselect);
|
|
|
|
|
|
|
|
/* TODO Do we want to add flag to prevent this? */
|
|
|
|
if (mesh_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) {
|
|
|
|
BKE_id_copy_ex(bmain, &mesh_src->key->id, (ID **)&mesh_dst->key, flag);
|
|
|
|
/* XXX This is not nice, we need to make BKE_id_copy_ex fully re-entrant... */
|
|
|
|
mesh_dst->key->from = &mesh_dst->id;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void mesh_free_data(ID *id)
|
|
|
|
{
|
|
|
|
Mesh *mesh = (Mesh *)id;
|
2020-03-09 18:40:06 +01:00
|
|
|
|
|
|
|
BKE_mesh_runtime_clear_cache(mesh);
|
|
|
|
mesh_clear_geometry(mesh);
|
2020-03-06 15:38:52 +01:00
|
|
|
MEM_SAFE_FREE(mesh->mat);
|
|
|
|
}
|
|
|
|
|
2020-05-07 15:55:52 +02:00
|
|
|
static void mesh_foreach_id(ID *id, LibraryForeachIDData *data)
|
|
|
|
{
|
|
|
|
Mesh *mesh = (Mesh *)id;
|
|
|
|
BKE_LIB_FOREACHID_PROCESS(data, mesh->texcomesh, IDWALK_CB_NEVER_SELF);
|
|
|
|
BKE_LIB_FOREACHID_PROCESS(data, mesh->key, IDWALK_CB_USER);
|
|
|
|
for (int i = 0; i < mesh->totcol; i++) {
|
|
|
|
BKE_LIB_FOREACHID_PROCESS(data, mesh->mat[i], IDWALK_CB_USER);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-28 15:45:11 +02:00
|
|
|
static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address)
|
|
|
|
{
|
|
|
|
Mesh *mesh = (Mesh *)id;
|
2020-12-14 11:28:08 +01:00
|
|
|
const bool is_undo = BLO_write_is_undo(writer);
|
|
|
|
if (mesh->id.us > 0 || is_undo) {
|
2020-09-09 20:38:33 +10:00
|
|
|
CustomDataLayer *vlayers = NULL, vlayers_buff[CD_TEMP_CHUNK_SIZE];
|
|
|
|
CustomDataLayer *elayers = NULL, elayers_buff[CD_TEMP_CHUNK_SIZE];
|
|
|
|
CustomDataLayer *flayers = NULL, flayers_buff[CD_TEMP_CHUNK_SIZE];
|
|
|
|
CustomDataLayer *llayers = NULL, llayers_buff[CD_TEMP_CHUNK_SIZE];
|
|
|
|
CustomDataLayer *players = NULL, players_buff[CD_TEMP_CHUNK_SIZE];
|
|
|
|
|
2020-12-14 11:28:08 +01:00
|
|
|
/* cache only - don't write */
|
|
|
|
mesh->mface = NULL;
|
|
|
|
mesh->totface = 0;
|
|
|
|
memset(&mesh->fdata, 0, sizeof(mesh->fdata));
|
|
|
|
memset(&mesh->runtime, 0, sizeof(mesh->runtime));
|
2020-09-09 20:38:33 +10:00
|
|
|
flayers = flayers_buff;
|
2020-12-14 11:28:08 +01:00
|
|
|
|
|
|
|
/* Do not store actual geometry data in case this is a library override ID. */
|
|
|
|
if (ID_IS_OVERRIDE_LIBRARY(mesh) && !is_undo) {
|
|
|
|
mesh->mvert = NULL;
|
|
|
|
mesh->totvert = 0;
|
|
|
|
memset(&mesh->vdata, 0, sizeof(mesh->vdata));
|
|
|
|
vlayers = vlayers_buff;
|
|
|
|
|
|
|
|
mesh->medge = NULL;
|
|
|
|
mesh->totedge = 0;
|
|
|
|
memset(&mesh->edata, 0, sizeof(mesh->edata));
|
|
|
|
elayers = elayers_buff;
|
|
|
|
|
|
|
|
mesh->mloop = NULL;
|
|
|
|
mesh->totloop = 0;
|
|
|
|
memset(&mesh->ldata, 0, sizeof(mesh->ldata));
|
|
|
|
llayers = llayers_buff;
|
|
|
|
|
|
|
|
mesh->mpoly = NULL;
|
|
|
|
mesh->totpoly = 0;
|
|
|
|
memset(&mesh->pdata, 0, sizeof(mesh->pdata));
|
|
|
|
players = players_buff;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
CustomData_blend_write_prepare(
|
|
|
|
&mesh->vdata, &vlayers, vlayers_buff, ARRAY_SIZE(vlayers_buff));
|
|
|
|
CustomData_blend_write_prepare(
|
|
|
|
&mesh->edata, &elayers, elayers_buff, ARRAY_SIZE(elayers_buff));
|
|
|
|
CustomData_blend_write_prepare(
|
|
|
|
&mesh->ldata, &llayers, llayers_buff, ARRAY_SIZE(llayers_buff));
|
|
|
|
CustomData_blend_write_prepare(
|
|
|
|
&mesh->pdata, &players, players_buff, ARRAY_SIZE(players_buff));
|
|
|
|
}
|
2020-09-09 20:38:33 +10:00
|
|
|
|
2020-08-28 15:45:11 +02:00
|
|
|
BLO_write_id_struct(writer, Mesh, id_address, &mesh->id);
|
|
|
|
BKE_id_blend_write(writer, &mesh->id);
|
|
|
|
|
|
|
|
/* direct data */
|
|
|
|
if (mesh->adt) {
|
|
|
|
BKE_animdata_blend_write(writer, mesh->adt);
|
|
|
|
}
|
|
|
|
|
|
|
|
BLO_write_pointer_array(writer, mesh->totcol, mesh->mat);
|
|
|
|
BLO_write_raw(writer, sizeof(MSelect) * mesh->totselect, mesh->mselect);
|
|
|
|
|
2020-09-09 20:38:33 +10:00
|
|
|
CustomData_blend_write(
|
|
|
|
writer, &mesh->vdata, vlayers, mesh->totvert, CD_MASK_MESH.vmask, &mesh->id);
|
|
|
|
CustomData_blend_write(
|
|
|
|
writer, &mesh->edata, elayers, mesh->totedge, CD_MASK_MESH.emask, &mesh->id);
|
2020-08-28 15:45:11 +02:00
|
|
|
/* fdata is really a dummy - written so slots align */
|
2020-09-09 20:38:33 +10:00
|
|
|
CustomData_blend_write(
|
|
|
|
writer, &mesh->fdata, flayers, mesh->totface, CD_MASK_MESH.fmask, &mesh->id);
|
|
|
|
CustomData_blend_write(
|
|
|
|
writer, &mesh->ldata, llayers, mesh->totloop, CD_MASK_MESH.lmask, &mesh->id);
|
|
|
|
CustomData_blend_write(
|
|
|
|
writer, &mesh->pdata, players, mesh->totpoly, CD_MASK_MESH.pmask, &mesh->id);
|
|
|
|
|
|
|
|
/* Free temporary data */
|
|
|
|
|
|
|
|
/* Free custom-data layers, when not assigned a buffer value. */
|
|
|
|
#define CD_LAYERS_FREE(id) \
|
|
|
|
if (id && id != id##_buff) { \
|
|
|
|
MEM_freeN(id); \
|
|
|
|
} \
|
|
|
|
((void)0)
|
|
|
|
|
|
|
|
CD_LAYERS_FREE(vlayers);
|
|
|
|
CD_LAYERS_FREE(elayers);
|
|
|
|
/* CD_LAYER_FREE(flayers); */ /* Never allocated. */
|
|
|
|
CD_LAYERS_FREE(llayers);
|
|
|
|
CD_LAYERS_FREE(players);
|
|
|
|
|
|
|
|
#undef CD_LAYERS_FREE
|
2020-08-28 15:45:11 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void mesh_blend_read_data(BlendDataReader *reader, ID *id)
|
|
|
|
{
|
|
|
|
Mesh *mesh = (Mesh *)id;
|
|
|
|
BLO_read_pointer_array(reader, (void **)&mesh->mat);
|
|
|
|
|
|
|
|
BLO_read_data_address(reader, &mesh->mvert);
|
|
|
|
BLO_read_data_address(reader, &mesh->medge);
|
|
|
|
BLO_read_data_address(reader, &mesh->mface);
|
|
|
|
BLO_read_data_address(reader, &mesh->mloop);
|
|
|
|
BLO_read_data_address(reader, &mesh->mpoly);
|
|
|
|
BLO_read_data_address(reader, &mesh->tface);
|
|
|
|
BLO_read_data_address(reader, &mesh->mtface);
|
|
|
|
BLO_read_data_address(reader, &mesh->mcol);
|
|
|
|
BLO_read_data_address(reader, &mesh->dvert);
|
|
|
|
BLO_read_data_address(reader, &mesh->mloopcol);
|
|
|
|
BLO_read_data_address(reader, &mesh->mloopuv);
|
|
|
|
BLO_read_data_address(reader, &mesh->mselect);
|
|
|
|
|
|
|
|
/* animdata */
|
|
|
|
BLO_read_data_address(reader, &mesh->adt);
|
|
|
|
BKE_animdata_blend_read_data(reader, mesh->adt);
|
|
|
|
|
|
|
|
/* Normally BKE_defvert_blend_read should be called in CustomData_blend_read,
|
|
|
|
* but for backwards compatibility in do_versions to work we do it here. */
|
|
|
|
BKE_defvert_blend_read(reader, mesh->totvert, mesh->dvert);
|
|
|
|
|
|
|
|
CustomData_blend_read(reader, &mesh->vdata, mesh->totvert);
|
|
|
|
CustomData_blend_read(reader, &mesh->edata, mesh->totedge);
|
|
|
|
CustomData_blend_read(reader, &mesh->fdata, mesh->totface);
|
|
|
|
CustomData_blend_read(reader, &mesh->ldata, mesh->totloop);
|
|
|
|
CustomData_blend_read(reader, &mesh->pdata, mesh->totpoly);
|
|
|
|
|
|
|
|
mesh->texflag &= ~ME_AUTOSPACE_EVALUATED;
|
|
|
|
mesh->edit_mesh = NULL;
|
|
|
|
BKE_mesh_runtime_reset(mesh);
|
|
|
|
|
|
|
|
/* happens with old files */
|
|
|
|
if (mesh->mselect == NULL) {
|
|
|
|
mesh->totselect = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((BLO_read_requires_endian_switch(reader)) && mesh->tface) {
|
|
|
|
TFace *tf = mesh->tface;
|
|
|
|
for (int i = 0; i < mesh->totface; i++, tf++) {
|
|
|
|
BLI_endian_switch_uint32_array(tf->col, 4);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void mesh_blend_read_lib(BlendLibReader *reader, ID *id)
|
|
|
|
{
|
|
|
|
Mesh *me = (Mesh *)id;
|
|
|
|
/* this check added for python created meshes */
|
|
|
|
if (me->mat) {
|
|
|
|
for (int i = 0; i < me->totcol; i++) {
|
|
|
|
BLO_read_id_address(reader, me->id.lib, &me->mat[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
me->totcol = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
BLO_read_id_address(reader, me->id.lib, &me->ipo); // XXX: deprecated: old anim sys
|
|
|
|
BLO_read_id_address(reader, me->id.lib, &me->key);
|
|
|
|
BLO_read_id_address(reader, me->id.lib, &me->texcomesh);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void mesh_read_expand(BlendExpander *expander, ID *id)
|
|
|
|
{
|
|
|
|
Mesh *me = (Mesh *)id;
|
|
|
|
for (int a = 0; a < me->totcol; a++) {
|
|
|
|
BLO_expand(expander, me->mat[a]);
|
|
|
|
}
|
|
|
|
|
|
|
|
BLO_expand(expander, me->key);
|
|
|
|
BLO_expand(expander, me->texcomesh);
|
|
|
|
}
|
|
|
|
|
2020-03-06 15:38:52 +01:00
|
|
|
IDTypeInfo IDType_ID_ME = {
|
|
|
|
.id_code = ID_ME,
|
|
|
|
.id_filter = FILTER_ID_ME,
|
|
|
|
.main_listbase_index = INDEX_ID_ME,
|
|
|
|
.struct_size = sizeof(Mesh),
|
2020-03-19 18:35:14 +01:00
|
|
|
.name = "Mesh",
|
2020-03-06 15:38:52 +01:00
|
|
|
.name_plural = "meshes",
|
|
|
|
.translation_context = BLT_I18NCONTEXT_ID_MESH,
|
|
|
|
.flags = 0,
|
|
|
|
|
|
|
|
.init_data = mesh_init_data,
|
|
|
|
.copy_data = mesh_copy_data,
|
|
|
|
.free_data = mesh_free_data,
|
|
|
|
.make_local = NULL,
|
2020-05-07 15:55:52 +02:00
|
|
|
.foreach_id = mesh_foreach_id,
|
2020-08-28 13:05:48 +02:00
|
|
|
.foreach_cache = NULL,
|
2021-02-25 10:17:31 +01:00
|
|
|
.owner_get = NULL,
|
2020-08-28 13:05:48 +02:00
|
|
|
|
2020-08-28 15:45:11 +02:00
|
|
|
.blend_write = mesh_blend_write,
|
|
|
|
.blend_read_data = mesh_blend_read_data,
|
|
|
|
.blend_read_lib = mesh_blend_read_lib,
|
|
|
|
.blend_read_expand = mesh_read_expand,
|
2020-11-03 11:39:36 +01:00
|
|
|
|
|
|
|
.blend_read_undo_preserve = NULL,
|
2021-01-22 14:52:50 +01:00
|
|
|
|
|
|
|
.lib_override_apply_post = NULL,
|
2020-03-06 15:38:52 +01:00
|
|
|
};
|
|
|
|
|
2010-10-27 02:22:55 +00:00
|
|
|
enum {
|
|
|
|
MESHCMP_DVERT_WEIGHTMISMATCH = 1,
|
|
|
|
MESHCMP_DVERT_GROUPMISMATCH,
|
|
|
|
MESHCMP_DVERT_TOTGROUPMISMATCH,
|
|
|
|
MESHCMP_LOOPCOLMISMATCH,
|
|
|
|
MESHCMP_LOOPUVMISMATCH,
|
|
|
|
MESHCMP_LOOPMISMATCH,
|
|
|
|
MESHCMP_POLYVERTMISMATCH,
|
|
|
|
MESHCMP_POLYMISMATCH,
|
|
|
|
MESHCMP_EDGEUNKNOWN,
|
|
|
|
MESHCMP_VERTCOMISMATCH,
|
2019-02-03 14:01:45 +11:00
|
|
|
MESHCMP_CDLAYERS_MISMATCH,
|
2010-10-27 02:22:55 +00:00
|
|
|
};
|
|
|
|
|
2011-05-09 05:09:07 +00:00
|
|
|
static const char *cmpcode_to_str(int code)
|
2010-10-27 02:22:55 +00:00
|
|
|
{
|
|
|
|
switch (code) {
|
|
|
|
case MESHCMP_DVERT_WEIGHTMISMATCH:
|
|
|
|
return "Vertex Weight Mismatch";
|
|
|
|
case MESHCMP_DVERT_GROUPMISMATCH:
|
2012-05-06 15:15:33 +00:00
|
|
|
return "Vertex Group Mismatch";
|
2010-10-27 02:22:55 +00:00
|
|
|
case MESHCMP_DVERT_TOTGROUPMISMATCH:
|
2012-05-06 15:15:33 +00:00
|
|
|
return "Vertex Doesn't Belong To Same Number Of Groups";
|
2010-10-27 02:22:55 +00:00
|
|
|
case MESHCMP_LOOPCOLMISMATCH:
|
2012-05-06 15:15:33 +00:00
|
|
|
return "Vertex Color Mismatch";
|
2010-10-27 02:22:55 +00:00
|
|
|
case MESHCMP_LOOPUVMISMATCH:
|
2012-05-06 15:15:33 +00:00
|
|
|
return "UV Mismatch";
|
2010-10-27 02:22:55 +00:00
|
|
|
case MESHCMP_LOOPMISMATCH:
|
2012-05-06 15:15:33 +00:00
|
|
|
return "Loop Mismatch";
|
2010-10-27 02:22:55 +00:00
|
|
|
case MESHCMP_POLYVERTMISMATCH:
|
2012-05-06 15:15:33 +00:00
|
|
|
return "Loop Vert Mismatch In Poly Test";
|
2010-10-27 02:22:55 +00:00
|
|
|
case MESHCMP_POLYMISMATCH:
|
2012-05-06 15:15:33 +00:00
|
|
|
return "Loop Vert Mismatch";
|
2010-10-27 02:22:55 +00:00
|
|
|
case MESHCMP_EDGEUNKNOWN:
|
2012-05-06 15:15:33 +00:00
|
|
|
return "Edge Mismatch";
|
2010-10-27 02:22:55 +00:00
|
|
|
case MESHCMP_VERTCOMISMATCH:
|
2012-05-06 15:15:33 +00:00
|
|
|
return "Vertex Coordinate Mismatch";
|
2010-10-27 02:22:55 +00:00
|
|
|
case MESHCMP_CDLAYERS_MISMATCH:
|
2012-05-06 15:15:33 +00:00
|
|
|
return "CustomData Layer Count Mismatch";
|
2010-10-27 02:22:55 +00:00
|
|
|
default:
|
2012-05-06 15:15:33 +00:00
|
|
|
return "Mesh Comparison Code Unknown";
|
|
|
|
}
|
2010-10-27 02:22:55 +00:00
|
|
|
}
|
|
|
|
|
2012-03-03 20:19:11 +00:00
|
|
|
/* thresh is threshold for comparing vertices, uvs, vertex colors,
|
|
|
|
* weights, etc.*/
|
2013-05-08 12:55:36 +00:00
|
|
|
static int customdata_compare(
|
|
|
|
CustomData *c1, CustomData *c2, Mesh *m1, Mesh *m2, const float thresh)
|
2010-10-27 02:22:55 +00:00
|
|
|
{
|
2013-05-08 12:55:36 +00:00
|
|
|
const float thresh_sq = thresh * thresh;
|
2010-10-27 02:22:55 +00:00
|
|
|
CustomDataLayer *l1, *l2;
|
2012-05-06 15:15:33 +00:00
|
|
|
int i, i1 = 0, i2 = 0, tot, j;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-04-28 06:31:57 +00:00
|
|
|
for (i = 0; i < c1->totlayer; i++) {
|
2014-07-20 01:30:29 +10:00
|
|
|
if (ELEM(c1->layers[i].type,
|
|
|
|
CD_MVERT,
|
|
|
|
CD_MEDGE,
|
|
|
|
CD_MPOLY,
|
2017-05-25 15:11:00 +10:00
|
|
|
CD_MLOOPUV,
|
|
|
|
CD_MLOOPCOL,
|
|
|
|
CD_MDEFORMVERT)) {
|
2010-10-27 02:22:55 +00:00
|
|
|
i1++;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
2012-04-28 06:31:57 +00:00
|
|
|
for (i = 0; i < c2->totlayer; i++) {
|
2014-07-20 01:30:29 +10:00
|
|
|
if (ELEM(c2->layers[i].type,
|
|
|
|
CD_MVERT,
|
|
|
|
CD_MEDGE,
|
|
|
|
CD_MPOLY,
|
2017-05-25 15:11:00 +10:00
|
|
|
CD_MLOOPUV,
|
|
|
|
CD_MLOOPCOL,
|
|
|
|
CD_MDEFORMVERT)) {
|
2010-10-27 02:22:55 +00:00
|
|
|
i2++;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
if (i1 != i2) {
|
2010-10-27 02:22:55 +00:00
|
|
|
return MESHCMP_CDLAYERS_MISMATCH;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2010-10-27 02:22:55 +00:00
|
|
|
l1 = c1->layers;
|
|
|
|
l2 = c2->layers;
|
|
|
|
tot = i1;
|
2014-07-20 01:30:29 +10:00
|
|
|
i1 = 0;
|
|
|
|
i2 = 0;
|
2012-05-06 15:15:33 +00:00
|
|
|
for (i = 0; i < tot; i++) {
|
2014-07-20 01:30:29 +10:00
|
|
|
while (
|
|
|
|
i1 < c1->totlayer &&
|
|
|
|
!ELEM(l1->type, CD_MVERT, CD_MEDGE, CD_MPOLY, CD_MLOOPUV, CD_MLOOPCOL, CD_MDEFORMVERT)) {
|
2019-04-17 06:17:24 +02:00
|
|
|
i1++;
|
|
|
|
l1++;
|
|
|
|
}
|
|
|
|
|
2014-07-20 01:30:29 +10:00
|
|
|
while (
|
|
|
|
i2 < c2->totlayer &&
|
2017-05-25 15:11:00 +10:00
|
|
|
!ELEM(l2->type, CD_MVERT, CD_MEDGE, CD_MPOLY, CD_MLOOPUV, CD_MLOOPCOL, CD_MDEFORMVERT)) {
|
2016-03-05 09:09:05 +11:00
|
|
|
i2++;
|
|
|
|
l2++;
|
2012-04-28 06:31:57 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2010-10-27 02:22:55 +00:00
|
|
|
if (l1->type == CD_MVERT) {
|
|
|
|
MVert *v1 = l1->data;
|
|
|
|
MVert *v2 = l2->data;
|
|
|
|
int vtot = m1->totvert;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-05-06 15:15:33 +00:00
|
|
|
for (j = 0; j < vtot; j++, v1++, v2++) {
|
2019-04-22 09:39:35 +10:00
|
|
|
if (len_squared_v3v3(v1->co, v2->co) > thresh_sq) {
|
2010-10-27 02:22:55 +00:00
|
|
|
return MESHCMP_VERTCOMISMATCH;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2018-09-24 17:27:41 +02:00
|
|
|
/* I don't care about normals, let's just do coordinates */
|
2010-10-27 02:22:55 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
2010-10-27 02:22:55 +00:00
|
|
|
/*we're order-agnostic for edges here*/
|
|
|
|
if (l1->type == CD_MEDGE) {
|
|
|
|
MEdge *e1 = l1->data;
|
|
|
|
MEdge *e2 = l2->data;
|
|
|
|
int etot = m1->totedge;
|
2013-08-24 13:47:57 +00:00
|
|
|
EdgeHash *eh = BLI_edgehash_new_ex(__func__, etot);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-05-06 15:15:33 +00:00
|
|
|
for (j = 0; j < etot; j++, e1++) {
|
2010-10-27 02:22:55 +00:00
|
|
|
BLI_edgehash_insert(eh, e1->v1, e1->v2, e1);
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-05-06 15:15:33 +00:00
|
|
|
for (j = 0; j < etot; j++, e2++) {
|
2019-04-22 09:39:35 +10:00
|
|
|
if (!BLI_edgehash_lookup(eh, e2->v1, e2->v2)) {
|
2010-10-27 02:22:55 +00:00
|
|
|
return MESHCMP_EDGEUNKNOWN;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2010-10-27 02:22:55 +00:00
|
|
|
}
|
|
|
|
BLI_edgehash_free(eh, NULL);
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2010-10-27 02:22:55 +00:00
|
|
|
if (l1->type == CD_MPOLY) {
|
|
|
|
MPoly *p1 = l1->data;
|
|
|
|
MPoly *p2 = l2->data;
|
|
|
|
int ptot = m1->totpoly;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-05-06 15:15:33 +00:00
|
|
|
for (j = 0; j < ptot; j++, p1++, p2++) {
|
2010-10-27 02:22:55 +00:00
|
|
|
MLoop *lp1, *lp2;
|
|
|
|
int k;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
if (p1->totloop != p2->totloop) {
|
2010-10-27 02:22:55 +00:00
|
|
|
return MESHCMP_POLYMISMATCH;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2010-10-27 02:22:55 +00:00
|
|
|
lp1 = m1->mloop + p1->loopstart;
|
|
|
|
lp2 = m2->mloop + p2->loopstart;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-05-06 15:15:33 +00:00
|
|
|
for (k = 0; k < p1->totloop; k++, lp1++, lp2++) {
|
2019-04-22 09:39:35 +10:00
|
|
|
if (lp1->v != lp2->v) {
|
2010-10-27 02:22:55 +00:00
|
|
|
return MESHCMP_POLYVERTMISMATCH;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2010-10-27 02:22:55 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
}
|
2010-10-27 02:22:55 +00:00
|
|
|
if (l1->type == CD_MLOOP) {
|
|
|
|
MLoop *lp1 = l1->data;
|
|
|
|
MLoop *lp2 = l2->data;
|
|
|
|
int ltot = m1->totloop;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-05-06 15:15:33 +00:00
|
|
|
for (j = 0; j < ltot; j++, lp1++, lp2++) {
|
2019-04-22 09:39:35 +10:00
|
|
|
if (lp1->v != lp2->v) {
|
2010-10-27 02:22:55 +00:00
|
|
|
return MESHCMP_LOOPMISMATCH;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2010-10-27 02:22:55 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2010-10-27 02:22:55 +00:00
|
|
|
if (l1->type == CD_MLOOPUV) {
|
|
|
|
MLoopUV *lp1 = l1->data;
|
|
|
|
MLoopUV *lp2 = l2->data;
|
|
|
|
int ltot = m1->totloop;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-05-06 15:15:33 +00:00
|
|
|
for (j = 0; j < ltot; j++, lp1++, lp2++) {
|
2019-04-22 09:39:35 +10:00
|
|
|
if (len_squared_v2v2(lp1->uv, lp2->uv) > thresh_sq) {
|
2010-10-27 02:22:55 +00:00
|
|
|
return MESHCMP_LOOPUVMISMATCH;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2010-10-27 02:22:55 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
2010-10-27 02:22:55 +00:00
|
|
|
if (l1->type == CD_MLOOPCOL) {
|
|
|
|
MLoopCol *lp1 = l1->data;
|
|
|
|
MLoopCol *lp2 = l2->data;
|
|
|
|
int ltot = m1->totloop;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-05-06 15:15:33 +00:00
|
|
|
for (j = 0; j < ltot; j++, lp1++, lp2++) {
|
2020-03-06 17:18:10 +01:00
|
|
|
if (abs(lp1->r - lp2->r) > thresh || abs(lp1->g - lp2->g) > thresh ||
|
|
|
|
abs(lp1->b - lp2->b) > thresh || abs(lp1->a - lp2->a) > thresh) {
|
2010-10-27 02:22:55 +00:00
|
|
|
return MESHCMP_LOOPCOLMISMATCH;
|
|
|
|
}
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
2010-10-27 02:22:55 +00:00
|
|
|
if (l1->type == CD_MDEFORMVERT) {
|
|
|
|
MDeformVert *dv1 = l1->data;
|
|
|
|
MDeformVert *dv2 = l2->data;
|
|
|
|
int dvtot = m1->totvert;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-05-06 15:15:33 +00:00
|
|
|
for (j = 0; j < dvtot; j++, dv1++, dv2++) {
|
2010-10-27 02:22:55 +00:00
|
|
|
int k;
|
2012-05-06 15:15:33 +00:00
|
|
|
MDeformWeight *dw1 = dv1->dw, *dw2 = dv2->dw;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
if (dv1->totweight != dv2->totweight) {
|
2010-10-27 02:22:55 +00:00
|
|
|
return MESHCMP_DVERT_TOTGROUPMISMATCH;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-05-06 15:15:33 +00:00
|
|
|
for (k = 0; k < dv1->totweight; k++, dw1++, dw2++) {
|
2019-04-22 09:39:35 +10:00
|
|
|
if (dw1->def_nr != dw2->def_nr) {
|
2010-10-27 02:22:55 +00:00
|
|
|
return MESHCMP_DVERT_GROUPMISMATCH;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
|
|
|
if (fabsf(dw1->weight - dw2->weight) > thresh) {
|
2010-10-27 02:22:55 +00:00
|
|
|
return MESHCMP_DVERT_WEIGHTMISMATCH;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2010-10-27 02:22:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2010-11-11 23:36:56 +00:00
|
|
|
return 0;
|
2010-10-27 02:22:55 +00:00
|
|
|
}
|
|
|
|
|
2013-09-09 02:11:44 +00:00
|
|
|
/**
|
|
|
|
* Used for unit testing; compares two meshes, checking only
|
|
|
|
* differences we care about. should be usable with leaf's
|
|
|
|
* testing framework I get RNA work done, will use hackish
|
|
|
|
* testing code for now.
|
|
|
|
*/
|
2012-05-05 21:28:12 +00:00
|
|
|
const char *BKE_mesh_cmp(Mesh *me1, Mesh *me2, float thresh)
|
2010-10-27 02:22:55 +00:00
|
|
|
{
|
|
|
|
int c;
|
2018-06-17 17:05:51 +02:00
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
if (!me1 || !me2) {
|
2010-10-27 02:22:55 +00:00
|
|
|
return "Requires two input meshes";
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2018-06-17 17:05:51 +02:00
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
if (me1->totvert != me2->totvert) {
|
2010-10-27 02:22:55 +00:00
|
|
|
return "Number of verts don't match";
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2018-06-17 17:05:51 +02:00
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
if (me1->totedge != me2->totedge) {
|
2010-10-27 02:22:55 +00:00
|
|
|
return "Number of edges don't match";
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2018-06-17 17:05:51 +02:00
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
if (me1->totpoly != me2->totpoly) {
|
2010-10-27 02:22:55 +00:00
|
|
|
return "Number of faces don't match";
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2018-06-17 17:05:51 +02:00
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
if (me1->totloop != me2->totloop) {
|
2010-10-27 02:22:55 +00:00
|
|
|
return "Number of loops don't match";
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2018-06-17 17:05:51 +02:00
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
if ((c = customdata_compare(&me1->vdata, &me2->vdata, me1, me2, thresh))) {
|
2010-10-27 02:22:55 +00:00
|
|
|
return cmpcode_to_str(c);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2010-10-27 02:22:55 +00:00
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
if ((c = customdata_compare(&me1->edata, &me2->edata, me1, me2, thresh))) {
|
2010-10-27 02:22:55 +00:00
|
|
|
return cmpcode_to_str(c);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2010-10-27 02:22:55 +00:00
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
if ((c = customdata_compare(&me1->ldata, &me2->ldata, me1, me2, thresh))) {
|
2010-10-27 02:22:55 +00:00
|
|
|
return cmpcode_to_str(c);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2010-10-27 02:22:55 +00:00
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
if ((c = customdata_compare(&me1->pdata, &me2->pdata, me1, me2, thresh))) {
|
2010-10-27 02:22:55 +00:00
|
|
|
return cmpcode_to_str(c);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2018-06-17 17:05:51 +02:00
|
|
|
|
2010-10-27 02:22:55 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-03-02 16:05:54 +00:00
|
|
|
static void mesh_ensure_tessellation_customdata(Mesh *me)
|
2009-08-30 21:30:07 +00:00
|
|
|
{
|
2012-03-20 05:04:51 +00:00
|
|
|
if (UNLIKELY((me->totface != 0) && (me->totpoly == 0))) {
|
|
|
|
/* Pass, otherwise this function clears 'mface' before
|
2020-09-30 20:09:02 +10:00
|
|
|
* versioning 'mface -> mpoly' code kicks in T30583.
|
2012-03-20 05:04:51 +00:00
|
|
|
*
|
|
|
|
* Callers could also check but safer to do here - campbell */
|
|
|
|
}
|
|
|
|
else {
|
2017-05-25 15:11:00 +10:00
|
|
|
const int tottex_original = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
|
2012-03-20 05:04:51 +00:00
|
|
|
const int totcol_original = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-20 05:04:51 +00:00
|
|
|
const int tottex_tessface = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
|
|
|
|
const int totcol_tessface = CustomData_number_of_layers(&me->fdata, CD_MCOL);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-20 05:04:51 +00:00
|
|
|
if (tottex_tessface != tottex_original || totcol_tessface != totcol_original) {
|
|
|
|
BKE_mesh_tessface_clear(me);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-05-25 15:11:00 +10:00
|
|
|
CustomData_from_bmeshpoly(&me->fdata, &me->ldata, me->totface);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-04-12 14:36:57 +00:00
|
|
|
/* TODO - add some --debug-mesh option */
|
|
|
|
if (G.debug & G_DEBUG) {
|
2012-04-25 06:06:40 +00:00
|
|
|
/* note: this warning may be un-called for if we are initializing the mesh for the
|
2012-04-12 14:36:57 +00:00
|
|
|
* first time from bmesh, rather than giving a warning about this we could be smarter
|
|
|
|
* and check if there was any data to begin with, for now just print the warning with
|
2018-09-24 18:46:51 +02:00
|
|
|
* some info to help troubleshoot what's going on - campbell */
|
2012-04-12 14:36:57 +00:00
|
|
|
printf(
|
|
|
|
"%s: warning! Tessellation uvs or vcol data got out of sync, "
|
2017-05-25 15:11:00 +10:00
|
|
|
"had to reset!\n CD_MTFACE: %d != CD_MLOOPUV: %d || CD_MCOL: %d != CD_MLOOPCOL: "
|
|
|
|
"%d\n",
|
2012-05-06 15:15:33 +00:00
|
|
|
__func__,
|
|
|
|
tottex_tessface,
|
|
|
|
tottex_original,
|
|
|
|
totcol_tessface,
|
|
|
|
totcol_original);
|
2012-04-12 14:36:57 +00:00
|
|
|
}
|
2012-03-20 05:04:51 +00:00
|
|
|
}
|
2009-08-30 21:30:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-16 21:55:30 +11:00
|
|
|
void BKE_mesh_ensure_skin_customdata(Mesh *me)
|
|
|
|
{
|
2019-02-17 18:05:18 +11:00
|
|
|
BMesh *bm = me->edit_mesh ? me->edit_mesh->bm : NULL;
|
2014-03-16 21:55:30 +11:00
|
|
|
MVertSkin *vs;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-03-16 21:55:30 +11:00
|
|
|
if (bm) {
|
|
|
|
if (!CustomData_has_layer(&bm->vdata, CD_MVERT_SKIN)) {
|
|
|
|
BMVert *v;
|
|
|
|
BMIter iter;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-03-16 21:55:30 +11:00
|
|
|
BM_data_layer_add(bm, &bm->vdata, CD_MVERT_SKIN);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-03-16 21:55:30 +11:00
|
|
|
/* Mark an arbitrary vertex as root */
|
|
|
|
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
|
2018-07-13 08:36:10 +02:00
|
|
|
vs = CustomData_bmesh_get(&bm->vdata, v->head.data, CD_MVERT_SKIN);
|
2014-03-16 21:55:30 +11:00
|
|
|
vs->flag |= MVERT_SKIN_ROOT;
|
|
|
|
break;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
}
|
2014-03-16 21:55:30 +11:00
|
|
|
else {
|
|
|
|
if (!CustomData_has_layer(&me->vdata, CD_MVERT_SKIN)) {
|
2018-07-13 08:36:10 +02:00
|
|
|
vs = CustomData_add_layer(&me->vdata, CD_MVERT_SKIN, CD_DEFAULT, NULL, me->totvert);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-03-16 21:55:30 +11:00
|
|
|
/* Mark an arbitrary vertex as root */
|
|
|
|
if (vs) {
|
|
|
|
vs->flag |= MVERT_SKIN_ROOT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-20 18:37:30 +10:00
|
|
|
bool BKE_mesh_ensure_facemap_customdata(struct Mesh *me)
|
|
|
|
{
|
2019-02-17 18:05:18 +11:00
|
|
|
BMesh *bm = me->edit_mesh ? me->edit_mesh->bm : NULL;
|
2017-07-20 18:37:30 +10:00
|
|
|
bool changed = false;
|
|
|
|
if (bm) {
|
|
|
|
if (!CustomData_has_layer(&bm->pdata, CD_FACEMAP)) {
|
|
|
|
BM_data_layer_add(bm, &bm->pdata, CD_FACEMAP);
|
|
|
|
changed = true;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2017-07-20 18:37:30 +10:00
|
|
|
else {
|
|
|
|
if (!CustomData_has_layer(&me->pdata, CD_FACEMAP)) {
|
2018-07-13 08:37:20 +02:00
|
|
|
CustomData_add_layer(&me->pdata, CD_FACEMAP, CD_DEFAULT, NULL, me->totpoly);
|
2017-07-20 18:37:30 +10:00
|
|
|
changed = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return changed;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool BKE_mesh_clear_facemap_customdata(struct Mesh *me)
|
|
|
|
{
|
2019-02-17 18:05:18 +11:00
|
|
|
BMesh *bm = me->edit_mesh ? me->edit_mesh->bm : NULL;
|
2017-07-20 18:37:30 +10:00
|
|
|
bool changed = false;
|
|
|
|
if (bm) {
|
|
|
|
if (CustomData_has_layer(&bm->pdata, CD_FACEMAP)) {
|
|
|
|
BM_data_layer_free(bm, &bm->pdata, CD_FACEMAP);
|
|
|
|
changed = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (CustomData_has_layer(&me->pdata, CD_FACEMAP)) {
|
|
|
|
CustomData_free_layers(&me->pdata, CD_FACEMAP, me->totpoly);
|
|
|
|
changed = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return changed;
|
|
|
|
}
|
|
|
|
|
2011-12-06 09:28:25 +00:00
|
|
|
/* this ensures grouped customdata (e.g. mtexpoly and mloopuv and mtface, or
|
|
|
|
* mloopcol and mcol) have the same relative active/render/clone/mask indices.
|
|
|
|
*
|
|
|
|
* note that for undo mesh data we want to skip 'ensure_tess_cd' call since
|
2012-03-18 07:38:51 +00:00
|
|
|
* we don't want to store memory for tessface when its only used for older
|
2011-12-06 09:28:25 +00:00
|
|
|
* versions of the mesh. - campbell*/
|
2013-03-17 19:55:10 +00:00
|
|
|
static void mesh_update_linked_customdata(Mesh *me, const bool do_ensure_tess_cd)
|
2009-08-30 21:30:07 +00:00
|
|
|
{
|
2011-12-06 09:28:25 +00:00
|
|
|
if (do_ensure_tess_cd) {
|
2012-03-02 16:05:54 +00:00
|
|
|
mesh_ensure_tessellation_customdata(me);
|
2011-12-06 09:28:25 +00:00
|
|
|
}
|
2009-08-30 21:30:07 +00:00
|
|
|
|
2017-05-25 15:11:00 +10:00
|
|
|
CustomData_bmesh_update_active_layers(&me->fdata, &me->ldata);
|
2009-08-30 21:30:07 +00:00
|
|
|
}
|
2009-05-23 03:24:15 +00:00
|
|
|
|
2013-03-17 19:55:10 +00:00
|
|
|
void BKE_mesh_update_customdata_pointers(Mesh *me, const bool do_ensure_tess_cd)
|
Added custom vertex/edge/face data for meshes:
All data layers, including MVert/MEdge/MFace, are now managed as custom
data layers. The pointers like Mesh.mvert, Mesh.dvert or Mesh.mcol are
still used of course, but allocating, copying or freeing these arrays
should be done through the CustomData API.
Work in progress documentation on this is here:
http://mediawiki.blender.org/index.php/BlenderDev/BlenderArchitecture/CustomData
Replaced TFace by MTFace:
This is the same struct, except that it does not contain color, that now
always stays separated in MCol. This was not a good design decision to
begin with, and it is needed for adding multiple color layers later. Note
that this does mean older Blender versions will not be able to read UV
coordinates from the next release, due to an SDNA limitation.
Removed DispListMesh:
This now fully replaced by DerivedMesh. To provide access to arrays of
vertices, edges and faces, like DispListMesh does. The semantics of the
DerivedMesh.getVertArray() and similar functions were changed to return
a pointer to an array if one exists, or otherwise allocate a temporary
one. On releasing the DerivedMesh, this temporary array will be removed
automatically.
Removed ssDM and meshDM DerivedMesh backends:
The ssDM backend was for DispListMesh, so that became obsolete automatically.
The meshDM backend was replaced by the custom data backend, that now figures
out which layers need to be modified, and only duplicates those.
This changes code in many places, and overall removes 2514 lines of code.
So, there's a good chance this might break some stuff, although I've been
testing it for a few days now. The good news is, adding multiple color and
uv layers should now become easy.
2006-11-20 04:28:02 +00:00
|
|
|
{
|
2011-12-06 09:28:25 +00:00
|
|
|
mesh_update_linked_customdata(me, do_ensure_tess_cd);
|
2009-08-30 21:30:07 +00:00
|
|
|
|
Added custom vertex/edge/face data for meshes:
All data layers, including MVert/MEdge/MFace, are now managed as custom
data layers. The pointers like Mesh.mvert, Mesh.dvert or Mesh.mcol are
still used of course, but allocating, copying or freeing these arrays
should be done through the CustomData API.
Work in progress documentation on this is here:
http://mediawiki.blender.org/index.php/BlenderDev/BlenderArchitecture/CustomData
Replaced TFace by MTFace:
This is the same struct, except that it does not contain color, that now
always stays separated in MCol. This was not a good design decision to
begin with, and it is needed for adding multiple color layers later. Note
that this does mean older Blender versions will not be able to read UV
coordinates from the next release, due to an SDNA limitation.
Removed DispListMesh:
This now fully replaced by DerivedMesh. To provide access to arrays of
vertices, edges and faces, like DispListMesh does. The semantics of the
DerivedMesh.getVertArray() and similar functions were changed to return
a pointer to an array if one exists, or otherwise allocate a temporary
one. On releasing the DerivedMesh, this temporary array will be removed
automatically.
Removed ssDM and meshDM DerivedMesh backends:
The ssDM backend was for DispListMesh, so that became obsolete automatically.
The meshDM backend was replaced by the custom data backend, that now figures
out which layers need to be modified, and only duplicates those.
This changes code in many places, and overall removes 2514 lines of code.
So, there's a good chance this might break some stuff, although I've been
testing it for a few days now. The good news is, adding multiple color and
uv layers should now become easy.
2006-11-20 04:28:02 +00:00
|
|
|
me->mvert = CustomData_get_layer(&me->vdata, CD_MVERT);
|
|
|
|
me->dvert = CustomData_get_layer(&me->vdata, CD_MDEFORMVERT);
|
|
|
|
|
|
|
|
me->medge = CustomData_get_layer(&me->edata, CD_MEDGE);
|
|
|
|
|
|
|
|
me->mface = CustomData_get_layer(&me->fdata, CD_MFACE);
|
|
|
|
me->mcol = CustomData_get_layer(&me->fdata, CD_MCOL);
|
|
|
|
me->mtface = CustomData_get_layer(&me->fdata, CD_MTFACE);
|
2018-06-17 17:05:51 +02:00
|
|
|
|
2009-05-26 04:17:47 +00:00
|
|
|
me->mpoly = CustomData_get_layer(&me->pdata, CD_MPOLY);
|
|
|
|
me->mloop = CustomData_get_layer(&me->ldata, CD_MLOOP);
|
|
|
|
|
|
|
|
me->mloopcol = CustomData_get_layer(&me->ldata, CD_MLOOPCOL);
|
|
|
|
me->mloopuv = CustomData_get_layer(&me->ldata, CD_MLOOPUV);
|
Added custom vertex/edge/face data for meshes:
All data layers, including MVert/MEdge/MFace, are now managed as custom
data layers. The pointers like Mesh.mvert, Mesh.dvert or Mesh.mcol are
still used of course, but allocating, copying or freeing these arrays
should be done through the CustomData API.
Work in progress documentation on this is here:
http://mediawiki.blender.org/index.php/BlenderDev/BlenderArchitecture/CustomData
Replaced TFace by MTFace:
This is the same struct, except that it does not contain color, that now
always stays separated in MCol. This was not a good design decision to
begin with, and it is needed for adding multiple color layers later. Note
that this does mean older Blender versions will not be able to read UV
coordinates from the next release, due to an SDNA limitation.
Removed DispListMesh:
This now fully replaced by DerivedMesh. To provide access to arrays of
vertices, edges and faces, like DispListMesh does. The semantics of the
DerivedMesh.getVertArray() and similar functions were changed to return
a pointer to an array if one exists, or otherwise allocate a temporary
one. On releasing the DerivedMesh, this temporary array will be removed
automatically.
Removed ssDM and meshDM DerivedMesh backends:
The ssDM backend was for DispListMesh, so that became obsolete automatically.
The meshDM backend was replaced by the custom data backend, that now figures
out which layers need to be modified, and only duplicates those.
This changes code in many places, and overall removes 2514 lines of code.
So, there's a good chance this might break some stuff, although I've been
testing it for a few days now. The good news is, adding multiple color and
uv layers should now become easy.
2006-11-20 04:28:02 +00:00
|
|
|
}
|
|
|
|
|
Add Custom Loop Normals.
This is the core code for it, tools (datatransfer and modifier) will come in next commits).
RNA api is already there, though.
See the code for details, but basically, we define, for each 'smooth fan'
(which is a set of adjacent loops around a same vertex that are smooth, i.e. have a single same normal),
a 'loop normal space' (or lnor space), using auto-computed normal and relevant edges, and store
custom normal as two angular factors inside that space. This allows to have custom normals
'following' deformations of the geometry, and to only save two shorts per loop in new clnor CDLayer.
Normal manipulation (editing, mixing, interpolating, etc.) shall always happen with plain 3D vectors normals,
and be converted back into storage format at the end.
Clnor computation has also been threaded (at least for Mesh case, not for BMesh), since the process can
be rather heavy with high poly meshes.
Also, bumping subversion, and fix mess in 2.70 versioning code.
2015-02-05 14:24:48 +01:00
|
|
|
bool BKE_mesh_has_custom_loop_normals(Mesh *me)
|
|
|
|
{
|
2019-02-17 18:05:18 +11:00
|
|
|
if (me->edit_mesh) {
|
|
|
|
return CustomData_has_layer(&me->edit_mesh->bm->ldata, CD_CUSTOMLOOPNORMAL);
|
Add Custom Loop Normals.
This is the core code for it, tools (datatransfer and modifier) will come in next commits).
RNA api is already there, though.
See the code for details, but basically, we define, for each 'smooth fan'
(which is a set of adjacent loops around a same vertex that are smooth, i.e. have a single same normal),
a 'loop normal space' (or lnor space), using auto-computed normal and relevant edges, and store
custom normal as two angular factors inside that space. This allows to have custom normals
'following' deformations of the geometry, and to only save two shorts per loop in new clnor CDLayer.
Normal manipulation (editing, mixing, interpolating, etc.) shall always happen with plain 3D vectors normals,
and be converted back into storage format at the end.
Clnor computation has also been threaded (at least for Mesh case, not for BMesh), since the process can
be rather heavy with high poly meshes.
Also, bumping subversion, and fix mess in 2.70 versioning code.
2015-02-05 14:24:48 +01:00
|
|
|
}
|
2020-08-07 12:30:43 +02:00
|
|
|
|
|
|
|
return CustomData_has_layer(&me->ldata, CD_CUSTOMLOOPNORMAL);
|
Add Custom Loop Normals.
This is the core code for it, tools (datatransfer and modifier) will come in next commits).
RNA api is already there, though.
See the code for details, but basically, we define, for each 'smooth fan'
(which is a set of adjacent loops around a same vertex that are smooth, i.e. have a single same normal),
a 'loop normal space' (or lnor space), using auto-computed normal and relevant edges, and store
custom normal as two angular factors inside that space. This allows to have custom normals
'following' deformations of the geometry, and to only save two shorts per loop in new clnor CDLayer.
Normal manipulation (editing, mixing, interpolating, etc.) shall always happen with plain 3D vectors normals,
and be converted back into storage format at the end.
Clnor computation has also been threaded (at least for Mesh case, not for BMesh), since the process can
be rather heavy with high poly meshes.
Also, bumping subversion, and fix mess in 2.70 versioning code.
2015-02-05 14:24:48 +01:00
|
|
|
}
|
|
|
|
|
ID-Remap - Step one: core work (cleanup and rework of generic ID datablock handling).
This commit changes a lot of how IDs are handled internally, especially the unlinking/freeing
processes. So far, this was very fuzy, to summarize cleanly deleting or replacing a datablock
was pretty much impossible, except for a few special cases.
Also, unlinking was handled by each datatype, in a rather messy and prone-to-errors way (quite
a few ID usages were missed or wrongly handled that way).
One of the main goal of id-remap branch was to cleanup this, and fatorize ID links handling
by using library_query utils to allow generic handling of those, which is now the case
(now, generic ID links handling is only "knwon" from readfile.c and library_query.c).
This commit also adds backends to allow live replacement and deletion of datablocks in Blender
(so-called 'remapping' process, where we replace all usages of a given ID pointer by a new one,
or NULL one in case of unlinking).
This will allow nice new features, like ability to easily reload or relocate libraries, real immediate
deletion of datablocks in blender, replacement of one datablock by another, etc.
Some of those are for next commits.
A word of warning: this commit is highly risky, because it affects potentially a lot in Blender core.
Though it was tested rather deeply, being totally impossible to check all possible ID usage cases,
it's likely there are some remaining issues and bugs in new code... Please report them! ;)
Review task: D2027 (https://developer.blender.org/D2027).
Reviewed by campbellbarton, thanks a bunch.
2016-06-22 17:29:38 +02:00
|
|
|
/** Free (or release) any data used by this mesh (does not free the mesh itself). */
|
|
|
|
void BKE_mesh_free(Mesh *me)
|
2002-10-12 11:37:38 +00:00
|
|
|
{
|
2020-03-06 15:38:52 +01:00
|
|
|
mesh_free_data(&me->id);
|
2019-07-30 18:38:31 +02:00
|
|
|
}
|
|
|
|
|
2020-03-09 18:40:06 +01:00
|
|
|
static void mesh_clear_geometry(Mesh *mesh)
|
2019-07-30 18:38:31 +02:00
|
|
|
{
|
|
|
|
CustomData_free(&mesh->vdata, mesh->totvert);
|
|
|
|
CustomData_free(&mesh->edata, mesh->totedge);
|
|
|
|
CustomData_free(&mesh->fdata, mesh->totface);
|
|
|
|
CustomData_free(&mesh->ldata, mesh->totloop);
|
|
|
|
CustomData_free(&mesh->pdata, mesh->totpoly);
|
|
|
|
|
|
|
|
MEM_SAFE_FREE(mesh->mselect);
|
|
|
|
MEM_SAFE_FREE(mesh->edit_mesh);
|
|
|
|
|
|
|
|
/* Note that materials and shape keys are not freed here. This is intentional, as freeing
|
|
|
|
* shape keys requires tagging the depsgraph for updated relations, which is expensive.
|
|
|
|
* Material slots should be kept in sync with the object.*/
|
|
|
|
|
|
|
|
mesh->totvert = 0;
|
|
|
|
mesh->totedge = 0;
|
|
|
|
mesh->totface = 0;
|
|
|
|
mesh->totloop = 0;
|
|
|
|
mesh->totpoly = 0;
|
|
|
|
mesh->act_face = -1;
|
|
|
|
mesh->totselect = 0;
|
|
|
|
|
|
|
|
BKE_mesh_update_customdata_pointers(mesh, false);
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
|
2020-03-09 18:40:06 +01:00
|
|
|
void BKE_mesh_clear_geometry(Mesh *mesh)
|
|
|
|
{
|
|
|
|
BKE_animdata_free(&mesh->id, false);
|
|
|
|
BKE_mesh_runtime_clear_cache(mesh);
|
|
|
|
mesh_clear_geometry(mesh);
|
|
|
|
}
|
|
|
|
|
2012-03-06 16:22:41 +00:00
|
|
|
static void mesh_tessface_clear_intern(Mesh *mesh, int free_customdata)
|
|
|
|
{
|
2012-10-31 09:50:24 +00:00
|
|
|
if (free_customdata) {
|
2012-03-06 16:22:41 +00:00
|
|
|
CustomData_free(&mesh->fdata, mesh->totface);
|
2012-10-31 09:50:24 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
CustomData_reset(&mesh->fdata);
|
|
|
|
}
|
2012-03-06 16:22:41 +00:00
|
|
|
|
|
|
|
mesh->mface = NULL;
|
|
|
|
mesh->mtface = NULL;
|
|
|
|
mesh->mcol = NULL;
|
|
|
|
mesh->totface = 0;
|
|
|
|
}
|
|
|
|
|
First step to handle missing libs/datablocks when reading a file.
Idea is, instead of ignoring completely missing linked datablocks, to
create void placeholders for them.
That way, you can work on your file, save it, and find again your missing data once
lib becomes available again. Or you can edit missing lib's path (in Outliner),
save and reload the file, and you are done.
Also, Outliner now shows broken libraries (and placeholders) with a 'broken lib' icon.
Future plans are also to be able to relocate missing libs and reload them at runtime.
Code notes:
- Placeholder ID is just a regular datablock of same type as expected linked one,
with 'default' data, and a LIB_MISSING bitflag set.
- To allow creation of such datablocks, creation of datablocks in BKE was split in two step:
+ Allocation of memory itself.
+ Setting of all internal data to default values.
See also the design task (T43351).
Reviewed by @campbellbarton, thanks a bunch!
Differential Revision: https://developer.blender.org/D1394
2015-10-20 14:44:57 +02:00
|
|
|
Mesh *BKE_mesh_add(Main *bmain, const char *name)
|
|
|
|
{
|
2020-12-27 21:46:57 -06:00
|
|
|
Mesh *me = BKE_id_new(bmain, ID_ME, name);
|
2012-10-31 15:14:14 +00:00
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
return me;
|
|
|
|
}
|
|
|
|
|
2018-06-06 12:20:21 +02:00
|
|
|
/* Custom data layer functions; those assume that totXXX are set correctly. */
|
|
|
|
static void mesh_ensure_cdlayers_primary(Mesh *mesh, bool do_tessface)
|
|
|
|
{
|
2019-04-22 09:39:35 +10:00
|
|
|
if (!CustomData_get_layer(&mesh->vdata, CD_MVERT)) {
|
2018-06-06 12:20:21 +02:00
|
|
|
CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, NULL, mesh->totvert);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
|
|
|
if (!CustomData_get_layer(&mesh->edata, CD_MEDGE)) {
|
2018-06-06 12:20:21 +02:00
|
|
|
CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_CALLOC, NULL, mesh->totedge);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
|
|
|
if (!CustomData_get_layer(&mesh->ldata, CD_MLOOP)) {
|
2018-06-06 12:20:21 +02:00
|
|
|
CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, NULL, mesh->totloop);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
|
|
|
if (!CustomData_get_layer(&mesh->pdata, CD_MPOLY)) {
|
2018-06-06 12:20:21 +02:00
|
|
|
CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, NULL, mesh->totpoly);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2018-06-06 12:20:21 +02:00
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
if (do_tessface && !CustomData_get_layer(&mesh->fdata, CD_MFACE)) {
|
2018-06-06 12:20:21 +02:00
|
|
|
CustomData_add_layer(&mesh->fdata, CD_MFACE, CD_CALLOC, NULL, mesh->totface);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2018-06-06 12:20:21 +02:00
|
|
|
}
|
|
|
|
|
2018-05-08 17:15:23 +02:00
|
|
|
Mesh *BKE_mesh_new_nomain(
|
|
|
|
int verts_len, int edges_len, int tessface_len, int loops_len, int polys_len)
|
2018-05-04 11:42:55 +02:00
|
|
|
{
|
2020-03-19 19:37:00 +01:00
|
|
|
Mesh *mesh = BKE_libblock_alloc(
|
2020-09-27 11:59:07 +02:00
|
|
|
NULL, ID_ME, BKE_idtype_idcode_to_name(ID_ME), LIB_ID_CREATE_LOCALIZE);
|
2018-05-04 11:42:55 +02:00
|
|
|
BKE_libblock_init_empty(&mesh->id);
|
|
|
|
|
2021-03-18 09:35:12 +11:00
|
|
|
/* Don't use CustomData_reset(...); because we don't want to touch custom-data. */
|
2018-05-04 11:42:55 +02:00
|
|
|
copy_vn_i(mesh->vdata.typemap, CD_NUMTYPES, -1);
|
|
|
|
copy_vn_i(mesh->edata.typemap, CD_NUMTYPES, -1);
|
|
|
|
copy_vn_i(mesh->fdata.typemap, CD_NUMTYPES, -1);
|
|
|
|
copy_vn_i(mesh->ldata.typemap, CD_NUMTYPES, -1);
|
|
|
|
copy_vn_i(mesh->pdata.typemap, CD_NUMTYPES, -1);
|
|
|
|
|
2018-05-11 10:37:16 +02:00
|
|
|
mesh->totvert = verts_len;
|
|
|
|
mesh->totedge = edges_len;
|
2018-06-06 12:16:02 +02:00
|
|
|
mesh->totface = tessface_len;
|
2018-05-11 10:37:16 +02:00
|
|
|
mesh->totloop = loops_len;
|
|
|
|
mesh->totpoly = polys_len;
|
|
|
|
|
2018-06-06 12:20:21 +02:00
|
|
|
mesh_ensure_cdlayers_primary(mesh, true);
|
|
|
|
BKE_mesh_update_customdata_pointers(mesh, false);
|
|
|
|
|
2018-05-04 11:42:55 +02:00
|
|
|
return mesh;
|
|
|
|
}
|
|
|
|
|
2021-06-17 14:56:39 +10:00
|
|
|
/**
|
|
|
|
* Copy user editable settings that we want to preserve
|
|
|
|
* when a new mesh is based on an existing mesh.
|
|
|
|
*/
|
|
|
|
void BKE_mesh_copy_parameters(Mesh *me_dst, const Mesh *me_src)
|
2019-09-16 10:45:49 +02:00
|
|
|
{
|
|
|
|
/* Copy general settings. */
|
|
|
|
me_dst->editflag = me_src->editflag;
|
|
|
|
me_dst->flag = me_src->flag;
|
|
|
|
me_dst->smoothresh = me_src->smoothresh;
|
|
|
|
me_dst->remesh_voxel_size = me_src->remesh_voxel_size;
|
2019-09-27 17:41:05 +02:00
|
|
|
me_dst->remesh_voxel_adaptivity = me_src->remesh_voxel_adaptivity;
|
2019-09-16 10:45:49 +02:00
|
|
|
me_dst->remesh_mode = me_src->remesh_mode;
|
2020-11-02 20:09:41 +01:00
|
|
|
me_dst->symmetry = me_src->symmetry;
|
2019-09-16 10:45:49 +02:00
|
|
|
|
2020-03-05 14:53:23 +01:00
|
|
|
me_dst->face_sets_color_seed = me_src->face_sets_color_seed;
|
2020-09-19 17:18:57 +02:00
|
|
|
me_dst->face_sets_color_default = me_src->face_sets_color_default;
|
2020-03-05 14:53:23 +01:00
|
|
|
|
2019-09-16 10:45:49 +02:00
|
|
|
/* Copy texture space. */
|
|
|
|
me_dst->texflag = me_src->texflag;
|
|
|
|
copy_v3_v3(me_dst->loc, me_src->loc);
|
|
|
|
copy_v3_v3(me_dst->size, me_src->size);
|
2021-06-17 14:56:39 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A version of #BKE_mesh_copy_parameters that is intended for evaluated output
|
|
|
|
* (the modifier stack for example).
|
|
|
|
*
|
|
|
|
* \warning User counts are not handled for ID's.
|
|
|
|
*/
|
|
|
|
void BKE_mesh_copy_parameters_for_eval(Mesh *me_dst, const Mesh *me_src)
|
|
|
|
{
|
|
|
|
/* User counts aren't handled, don't copy into a mesh from #G_MAIN. */
|
|
|
|
BLI_assert(me_dst->id.tag & (LIB_TAG_NO_MAIN | LIB_TAG_COPIED_ON_WRITE));
|
|
|
|
|
|
|
|
BKE_mesh_copy_parameters(me_dst, me_src);
|
2019-09-16 10:45:49 +02:00
|
|
|
|
|
|
|
/* Copy materials. */
|
|
|
|
if (me_dst->mat != NULL) {
|
|
|
|
MEM_freeN(me_dst->mat);
|
|
|
|
}
|
|
|
|
me_dst->mat = MEM_dupallocN(me_src->mat);
|
|
|
|
me_dst->totcol = me_src->totcol;
|
|
|
|
}
|
|
|
|
|
2019-08-27 18:17:27 +02:00
|
|
|
Mesh *BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src,
|
|
|
|
int verts_len,
|
|
|
|
int edges_len,
|
|
|
|
int tessface_len,
|
|
|
|
int loops_len,
|
|
|
|
int polys_len,
|
|
|
|
CustomData_MeshMasks mask)
|
2018-04-19 11:03:58 +02:00
|
|
|
{
|
2018-09-25 12:35:43 +02:00
|
|
|
/* Only do tessface if we are creating tessfaces or copying from mesh with only tessfaces. */
|
|
|
|
const bool do_tessface = (tessface_len || ((me_src->totface != 0) && (me_src->totpoly == 0)));
|
2018-04-19 11:03:58 +02:00
|
|
|
|
2018-05-03 15:42:55 +02:00
|
|
|
Mesh *me_dst = BKE_id_new_nomain(ID_ME, NULL);
|
2018-04-19 11:03:58 +02:00
|
|
|
|
2021-02-03 15:09:06 +01:00
|
|
|
me_dst->mselect = MEM_dupallocN(me_src->mselect);
|
2018-04-19 11:03:58 +02:00
|
|
|
|
2018-05-08 17:15:23 +02:00
|
|
|
me_dst->totvert = verts_len;
|
|
|
|
me_dst->totedge = edges_len;
|
2018-06-06 12:16:02 +02:00
|
|
|
me_dst->totface = tessface_len;
|
2018-05-08 17:15:23 +02:00
|
|
|
me_dst->totloop = loops_len;
|
|
|
|
me_dst->totpoly = polys_len;
|
2018-04-19 11:03:58 +02:00
|
|
|
|
2018-12-08 06:39:46 -06:00
|
|
|
me_dst->cd_flag = me_src->cd_flag;
|
2021-06-17 14:56:39 +10:00
|
|
|
BKE_mesh_copy_parameters_for_eval(me_dst, me_src);
|
2018-12-08 06:39:46 -06:00
|
|
|
|
Refactor CDData masks, to have one mask per mesh elem type.
We already have different storages for cddata of verts, edges etc.,
'simply' do the same for the mask flags we use all around Blender code
to request some data, or limit some operation to some layers, etc.
Reason we need this is that some cddata types (like Normals) are
actually shared between verts/polys/loops, and we don’t want to generate
clnors everytime we request vnors!
As a side note, this also does final fix to T59338, which was the
trigger for this patch (need to request computed loop normals for
another mesh than evaluated one).
Reviewers: brecht, campbellbarton, sergey
Differential Revision: https://developer.blender.org/D4407
2019-03-07 11:13:40 +01:00
|
|
|
CustomData_copy(&me_src->vdata, &me_dst->vdata, mask.vmask, CD_CALLOC, verts_len);
|
|
|
|
CustomData_copy(&me_src->edata, &me_dst->edata, mask.emask, CD_CALLOC, edges_len);
|
|
|
|
CustomData_copy(&me_src->ldata, &me_dst->ldata, mask.lmask, CD_CALLOC, loops_len);
|
|
|
|
CustomData_copy(&me_src->pdata, &me_dst->pdata, mask.pmask, CD_CALLOC, polys_len);
|
2018-04-19 11:03:58 +02:00
|
|
|
if (do_tessface) {
|
Refactor CDData masks, to have one mask per mesh elem type.
We already have different storages for cddata of verts, edges etc.,
'simply' do the same for the mask flags we use all around Blender code
to request some data, or limit some operation to some layers, etc.
Reason we need this is that some cddata types (like Normals) are
actually shared between verts/polys/loops, and we don’t want to generate
clnors everytime we request vnors!
As a side note, this also does final fix to T59338, which was the
trigger for this patch (need to request computed loop normals for
another mesh than evaluated one).
Reviewers: brecht, campbellbarton, sergey
Differential Revision: https://developer.blender.org/D4407
2019-03-07 11:13:40 +01:00
|
|
|
CustomData_copy(&me_src->fdata, &me_dst->fdata, mask.fmask, CD_CALLOC, tessface_len);
|
2018-04-19 11:03:58 +02:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
mesh_tessface_clear_intern(me_dst, false);
|
|
|
|
}
|
|
|
|
|
2018-06-06 12:21:36 +02:00
|
|
|
/* The destination mesh should at least have valid primary CD layers,
|
|
|
|
* even in cases where the source mesh does not. */
|
|
|
|
mesh_ensure_cdlayers_primary(me_dst, do_tessface);
|
2018-04-19 11:03:58 +02:00
|
|
|
BKE_mesh_update_customdata_pointers(me_dst, false);
|
|
|
|
|
|
|
|
return me_dst;
|
|
|
|
}
|
|
|
|
|
2018-10-11 09:08:30 +11:00
|
|
|
Mesh *BKE_mesh_new_nomain_from_template(const Mesh *me_src,
|
2018-05-08 17:15:23 +02:00
|
|
|
int verts_len,
|
|
|
|
int edges_len,
|
|
|
|
int tessface_len,
|
|
|
|
int loops_len,
|
|
|
|
int polys_len)
|
2018-04-19 11:03:58 +02:00
|
|
|
{
|
2019-08-27 18:17:27 +02:00
|
|
|
return BKE_mesh_new_nomain_from_template_ex(
|
2018-05-08 17:15:23 +02:00
|
|
|
me_src, verts_len, edges_len, tessface_len, loops_len, polys_len, CD_MASK_EVERYTHING);
|
2018-04-19 11:03:58 +02:00
|
|
|
}
|
|
|
|
|
2019-07-28 15:12:38 +02:00
|
|
|
void BKE_mesh_eval_delete(struct Mesh *mesh_eval)
|
|
|
|
{
|
|
|
|
/* Evaluated mesh may point to edit mesh, but never owns it. */
|
|
|
|
mesh_eval->edit_mesh = NULL;
|
|
|
|
BKE_mesh_free(mesh_eval);
|
|
|
|
BKE_libblock_free_data(&mesh_eval->id, false);
|
|
|
|
MEM_freeN(mesh_eval);
|
|
|
|
}
|
|
|
|
|
2018-09-20 12:33:45 +02:00
|
|
|
Mesh *BKE_mesh_copy_for_eval(struct Mesh *source, bool reference)
|
2018-08-16 14:20:36 +02:00
|
|
|
{
|
2019-02-04 17:51:15 +01:00
|
|
|
int flags = LIB_ID_COPY_LOCALIZE;
|
2018-09-20 12:33:45 +02:00
|
|
|
|
|
|
|
if (reference) {
|
|
|
|
flags |= LIB_ID_COPY_CD_REFERENCE;
|
|
|
|
}
|
|
|
|
|
2020-10-07 14:27:33 +02:00
|
|
|
Mesh *result = (Mesh *)BKE_id_copy_ex(NULL, &source->id, NULL, flags);
|
2018-08-16 14:20:36 +02:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2018-05-02 11:39:23 +02:00
|
|
|
BMesh *BKE_mesh_to_bmesh_ex(const Mesh *me,
|
|
|
|
const struct BMeshCreateParams *create_params,
|
|
|
|
const struct BMeshFromMeshParams *convert_params)
|
2009-05-26 04:17:47 +00:00
|
|
|
{
|
2013-09-24 03:31:00 +00:00
|
|
|
const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(me);
|
2009-05-26 04:17:47 +00:00
|
|
|
|
2020-12-27 21:46:57 -06:00
|
|
|
BMesh *bm = BM_mesh_create(&allocsize, create_params);
|
2018-05-02 11:39:23 +02:00
|
|
|
BM_mesh_bm_from_me(bm, me, convert_params);
|
2009-05-26 04:17:47 +00:00
|
|
|
|
|
|
|
return bm;
|
|
|
|
}
|
|
|
|
|
2018-05-02 11:39:23 +02:00
|
|
|
BMesh *BKE_mesh_to_bmesh(Mesh *me,
|
|
|
|
Object *ob,
|
|
|
|
const bool add_key_index,
|
|
|
|
const struct BMeshCreateParams *params)
|
|
|
|
{
|
2018-05-04 09:04:33 +02:00
|
|
|
return BKE_mesh_to_bmesh_ex(me,
|
|
|
|
params,
|
|
|
|
&(struct BMeshFromMeshParams){
|
|
|
|
.calc_face_normal = false,
|
|
|
|
.add_key_index = add_key_index,
|
|
|
|
.use_shapekey = true,
|
|
|
|
.active_shapekey = ob->shapenr,
|
|
|
|
});
|
2018-05-02 11:39:23 +02:00
|
|
|
}
|
|
|
|
|
2019-09-16 10:45:49 +02:00
|
|
|
Mesh *BKE_mesh_from_bmesh_nomain(BMesh *bm,
|
|
|
|
const struct BMeshToMeshParams *params,
|
|
|
|
const Mesh *me_settings)
|
2018-05-02 11:39:23 +02:00
|
|
|
{
|
2018-06-13 16:42:56 +02:00
|
|
|
BLI_assert(params->calc_object_remap == false);
|
2018-05-03 15:42:55 +02:00
|
|
|
Mesh *mesh = BKE_id_new_nomain(ID_ME, NULL);
|
2018-06-13 16:42:56 +02:00
|
|
|
BM_mesh_bm_to_me(NULL, bm, mesh, params);
|
2021-06-17 14:56:39 +10:00
|
|
|
BKE_mesh_copy_parameters_for_eval(mesh, me_settings);
|
2018-05-02 11:39:23 +02:00
|
|
|
return mesh;
|
|
|
|
}
|
|
|
|
|
2019-09-16 10:45:49 +02:00
|
|
|
Mesh *BKE_mesh_from_bmesh_for_eval_nomain(BMesh *bm,
|
|
|
|
const CustomData_MeshMasks *cd_mask_extra,
|
|
|
|
const Mesh *me_settings)
|
2018-10-10 12:51:14 +11:00
|
|
|
{
|
|
|
|
Mesh *mesh = BKE_id_new_nomain(ID_ME, NULL);
|
|
|
|
BM_mesh_bm_to_me_for_eval(bm, mesh, cd_mask_extra);
|
2021-06-17 14:56:39 +10:00
|
|
|
BKE_mesh_copy_parameters_for_eval(mesh, me_settings);
|
2018-10-10 12:51:14 +11:00
|
|
|
return mesh;
|
|
|
|
}
|
|
|
|
|
2019-09-23 15:31:11 +02:00
|
|
|
BoundBox *BKE_mesh_boundbox_get(Object *ob)
|
2002-10-12 11:37:38 +00:00
|
|
|
{
|
2019-09-23 15:31:11 +02:00
|
|
|
/* This is Object-level data access,
|
|
|
|
* DO NOT touch to Mesh's bb, would be totally thread-unsafe. */
|
|
|
|
if (ob->runtime.bb == NULL || ob->runtime.bb->flag & BOUNDBOX_DIRTY) {
|
|
|
|
Mesh *me = ob->data;
|
|
|
|
float min[3], max[3];
|
2002-10-12 11:37:38 +00:00
|
|
|
|
2019-09-23 15:31:11 +02:00
|
|
|
INIT_MINMAX(min, max);
|
2020-05-25 20:16:42 +10:00
|
|
|
if (!BKE_mesh_wrapper_minmax(me, min, max)) {
|
2019-09-23 15:31:11 +02:00
|
|
|
min[0] = min[1] = min[2] = -1.0f;
|
|
|
|
max[0] = max[1] = max[2] = 1.0f;
|
|
|
|
}
|
2018-11-27 14:17:54 +11:00
|
|
|
|
2019-09-23 15:31:11 +02:00
|
|
|
if (ob->runtime.bb == NULL) {
|
|
|
|
ob->runtime.bb = MEM_mallocN(sizeof(*ob->runtime.bb), __func__);
|
|
|
|
}
|
|
|
|
BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
|
|
|
|
ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY;
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
|
2019-09-23 15:31:11 +02:00
|
|
|
return ob->runtime.bb;
|
2018-11-27 14:17:54 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
void BKE_mesh_texspace_calc(Mesh *me)
|
|
|
|
{
|
2019-09-23 15:31:11 +02:00
|
|
|
if (me->texflag & ME_AUTOSPACE) {
|
|
|
|
float min[3], max[3];
|
|
|
|
|
|
|
|
INIT_MINMAX(min, max);
|
2020-05-25 20:16:42 +10:00
|
|
|
if (!BKE_mesh_wrapper_minmax(me, min, max)) {
|
2019-09-23 15:31:11 +02:00
|
|
|
min[0] = min[1] = min[2] = -1.0f;
|
|
|
|
max[0] = max[1] = max[2] = 1.0f;
|
|
|
|
}
|
2018-11-27 14:17:54 +11:00
|
|
|
|
2019-09-23 15:31:11 +02:00
|
|
|
float loc[3], size[3];
|
|
|
|
mid_v3_v3v3(loc, min, max);
|
2002-10-12 11:37:38 +00:00
|
|
|
|
2019-09-23 15:31:11 +02:00
|
|
|
size[0] = (max[0] - min[0]) / 2.0f;
|
|
|
|
size[1] = (max[1] - min[1]) / 2.0f;
|
|
|
|
size[2] = (max[2] - min[2]) / 2.0f;
|
|
|
|
|
|
|
|
for (int a = 0; a < 3; a++) {
|
2019-04-22 09:39:35 +10:00
|
|
|
if (size[a] == 0.0f) {
|
2012-05-06 15:15:33 +00:00
|
|
|
size[a] = 1.0f;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
|
|
|
else if (size[a] > 0.0f && size[a] < 0.00001f) {
|
2012-05-06 15:15:33 +00:00
|
|
|
size[a] = 0.00001f;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
|
|
|
else if (size[a] < 0.0f && size[a] > -0.00001f) {
|
2012-05-06 15:15:33 +00:00
|
|
|
size[a] = -0.00001f;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2005-07-14 21:57:18 +00:00
|
|
|
}
|
|
|
|
|
2010-08-01 11:00:36 +00:00
|
|
|
copy_v3_v3(me->loc, loc);
|
|
|
|
copy_v3_v3(me->size, size);
|
2019-09-23 15:31:11 +02:00
|
|
|
|
|
|
|
me->texflag |= ME_AUTOSPACE_EVALUATED;
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-23 15:31:11 +02:00
|
|
|
void BKE_mesh_texspace_ensure(Mesh *me)
|
2005-07-14 18:04:27 +00:00
|
|
|
{
|
2019-09-23 15:31:11 +02:00
|
|
|
if ((me->texflag & ME_AUTOSPACE) && !(me->texflag & ME_AUTOSPACE_EVALUATED)) {
|
|
|
|
BKE_mesh_texspace_calc(me);
|
2013-08-19 09:58:28 +00:00
|
|
|
}
|
2005-07-14 18:04:27 +00:00
|
|
|
}
|
|
|
|
|
2019-09-23 15:54:21 +02:00
|
|
|
void BKE_mesh_texspace_get(Mesh *me, float r_loc[3], float r_size[3])
|
2005-07-14 21:57:18 +00:00
|
|
|
{
|
2019-09-23 15:31:11 +02:00
|
|
|
BKE_mesh_texspace_ensure(me);
|
2005-07-14 21:57:18 +00:00
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
if (r_loc) {
|
2012-05-06 15:15:33 +00:00
|
|
|
copy_v3_v3(r_loc, me->loc);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
|
|
|
if (r_size) {
|
2012-02-28 14:05:00 +00:00
|
|
|
copy_v3_v3(r_size, me->size);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2005-07-14 21:57:18 +00:00
|
|
|
}
|
|
|
|
|
2019-09-23 15:54:21 +02:00
|
|
|
void BKE_mesh_texspace_get_reference(Mesh *me, short **r_texflag, float **r_loc, float **r_size)
|
2017-06-09 15:19:02 +02:00
|
|
|
{
|
2019-09-23 15:31:11 +02:00
|
|
|
BKE_mesh_texspace_ensure(me);
|
2017-06-09 15:19:02 +02:00
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
if (r_texflag != NULL) {
|
2017-06-09 15:19:02 +02:00
|
|
|
*r_texflag = &me->texflag;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
|
|
|
if (r_loc != NULL) {
|
2017-06-09 15:19:02 +02:00
|
|
|
*r_loc = me->loc;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
|
|
|
if (r_size != NULL) {
|
2017-06-09 15:19:02 +02:00
|
|
|
*r_size = me->size;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2017-06-09 15:19:02 +02:00
|
|
|
}
|
|
|
|
|
2013-07-15 11:11:36 +00:00
|
|
|
void BKE_mesh_texspace_copy_from_object(Mesh *me, Object *ob)
|
|
|
|
{
|
2019-09-23 15:54:21 +02:00
|
|
|
float *texloc, *texsize;
|
2013-07-15 11:11:36 +00:00
|
|
|
short *texflag;
|
|
|
|
|
2019-09-23 15:54:21 +02:00
|
|
|
if (BKE_object_obdata_texspace_get(ob, &texflag, &texloc, &texsize)) {
|
2013-07-15 11:11:36 +00:00
|
|
|
me->texflag = *texflag;
|
|
|
|
copy_v3_v3(me->loc, texloc);
|
|
|
|
copy_v3_v3(me->size, texsize);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-21 07:28:14 +00:00
|
|
|
float (*BKE_mesh_orco_verts_get(Object *ob))[3]
|
2002-10-12 11:37:38 +00:00
|
|
|
{
|
2005-07-20 04:44:02 +00:00
|
|
|
Mesh *me = ob->data;
|
2012-05-06 15:15:33 +00:00
|
|
|
Mesh *tme = me->texcomesh ? me->texcomesh : me;
|
2005-07-18 18:28:16 +00:00
|
|
|
|
2007-12-05 12:40:54 +00:00
|
|
|
/* Get appropriate vertex coordinates */
|
2020-12-27 21:46:57 -06:00
|
|
|
float(*vcos)[3] = MEM_calloc_arrayN(me->totvert, sizeof(*vcos), "orco mesh");
|
|
|
|
MVert *mvert = tme->mvert;
|
|
|
|
int totvert = min_ii(tme->totvert, me->totvert);
|
2009-11-01 00:06:53 +00:00
|
|
|
|
2020-12-27 21:46:57 -06:00
|
|
|
for (int a = 0; a < totvert; a++, mvert++) {
|
2010-08-01 11:00:36 +00:00
|
|
|
copy_v3_v3(vcos[a], mvert->co);
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
2005-07-18 18:28:16 +00:00
|
|
|
|
2012-12-21 07:28:14 +00:00
|
|
|
return vcos;
|
2007-12-05 12:40:54 +00:00
|
|
|
}
|
2005-07-18 19:58:23 +00:00
|
|
|
|
2012-05-05 21:28:12 +00:00
|
|
|
void BKE_mesh_orco_verts_transform(Mesh *me, float (*orco)[3], int totvert, int invert)
|
2007-12-05 12:40:54 +00:00
|
|
|
{
|
|
|
|
float loc[3], size[3];
|
2005-07-18 19:58:23 +00:00
|
|
|
|
2019-09-23 15:54:21 +02:00
|
|
|
BKE_mesh_texspace_get(me->texcomesh ? me->texcomesh : me, loc, size);
|
2005-07-18 19:58:23 +00:00
|
|
|
|
2012-02-23 02:17:50 +00:00
|
|
|
if (invert) {
|
2020-12-27 21:46:57 -06:00
|
|
|
for (int a = 0; a < totvert; a++) {
|
2007-12-11 20:02:21 +00:00
|
|
|
float *co = orco[a];
|
2010-08-01 11:00:36 +00:00
|
|
|
madd_v3_v3v3v3(co, loc, co, size);
|
2007-12-11 20:02:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2020-12-27 21:46:57 -06:00
|
|
|
for (int a = 0; a < totvert; a++) {
|
2007-12-11 20:02:21 +00:00
|
|
|
float *co = orco[a];
|
2012-05-06 15:15:33 +00:00
|
|
|
co[0] = (co[0] - loc[0]) / size[0];
|
|
|
|
co[1] = (co[1] - loc[1]) / size[1];
|
|
|
|
co[2] = (co[2] - loc[2]) / size[2];
|
2007-12-11 20:02:21 +00:00
|
|
|
}
|
2005-07-18 19:58:23 +00:00
|
|
|
}
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
|
2021-06-18 15:13:52 +10:00
|
|
|
/**
|
|
|
|
* Rotates the vertices of a face in case v[2] or v[3] (vertex index) is = 0.
|
|
|
|
* this is necessary to make the if #MFace.v4 check for quads work.
|
|
|
|
*/
|
|
|
|
int BKE_mesh_mface_index_validate(MFace *mface, CustomData *fdata, int mfindex, int nr)
|
2002-10-12 11:37:38 +00:00
|
|
|
{
|
|
|
|
/* first test if the face is legal */
|
2012-05-06 15:15:33 +00:00
|
|
|
if ((mface->v3 || nr == 4) && mface->v3 == mface->v4) {
|
|
|
|
mface->v4 = 0;
|
2002-10-12 11:37:38 +00:00
|
|
|
nr--;
|
|
|
|
}
|
2012-05-06 15:15:33 +00:00
|
|
|
if ((mface->v2 || mface->v4) && mface->v2 == mface->v3) {
|
|
|
|
mface->v3 = mface->v4;
|
|
|
|
mface->v4 = 0;
|
2002-10-12 11:37:38 +00:00
|
|
|
nr--;
|
|
|
|
}
|
2012-05-06 15:15:33 +00:00
|
|
|
if (mface->v1 == mface->v2) {
|
|
|
|
mface->v2 = mface->v3;
|
|
|
|
mface->v3 = mface->v4;
|
|
|
|
mface->v4 = 0;
|
2002-10-12 11:37:38 +00:00
|
|
|
nr--;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-04-27 12:07:07 +10:00
|
|
|
/* Check corrupt cases, bow-tie geometry,
|
2021-02-05 19:07:03 -08:00
|
|
|
* can't handle these because edge data won't exist so just return 0. */
|
2012-05-06 15:15:33 +00:00
|
|
|
if (nr == 3) {
|
2012-02-23 02:17:50 +00:00
|
|
|
if (
|
2012-05-06 15:15:33 +00:00
|
|
|
/* real edges */
|
|
|
|
mface->v1 == mface->v2 || mface->v2 == mface->v3 || mface->v3 == mface->v1) {
|
2011-02-09 04:45:53 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
2012-05-06 15:15:33 +00:00
|
|
|
else if (nr == 4) {
|
2012-02-23 02:17:50 +00:00
|
|
|
if (
|
2012-05-06 15:15:33 +00:00
|
|
|
/* real edges */
|
|
|
|
mface->v1 == mface->v2 || mface->v2 == mface->v3 || mface->v3 == mface->v4 ||
|
|
|
|
mface->v4 == mface->v1 ||
|
|
|
|
/* across the face */
|
|
|
|
mface->v1 == mface->v3 || mface->v2 == mface->v4) {
|
2011-02-09 04:45:53 +00:00
|
|
|
return 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2011-02-09 04:45:53 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2003-04-26 13:07:59 +00:00
|
|
|
/* prevent a zero at wrong index location */
|
2012-05-06 15:15:33 +00:00
|
|
|
if (nr == 3) {
|
|
|
|
if (mface->v3 == 0) {
|
Added custom vertex/edge/face data for meshes:
All data layers, including MVert/MEdge/MFace, are now managed as custom
data layers. The pointers like Mesh.mvert, Mesh.dvert or Mesh.mcol are
still used of course, but allocating, copying or freeing these arrays
should be done through the CustomData API.
Work in progress documentation on this is here:
http://mediawiki.blender.org/index.php/BlenderDev/BlenderArchitecture/CustomData
Replaced TFace by MTFace:
This is the same struct, except that it does not contain color, that now
always stays separated in MCol. This was not a good design decision to
begin with, and it is needed for adding multiple color layers later. Note
that this does mean older Blender versions will not be able to read UV
coordinates from the next release, due to an SDNA limitation.
Removed DispListMesh:
This now fully replaced by DerivedMesh. To provide access to arrays of
vertices, edges and faces, like DispListMesh does. The semantics of the
DerivedMesh.getVertArray() and similar functions were changed to return
a pointer to an array if one exists, or otherwise allocate a temporary
one. On releasing the DerivedMesh, this temporary array will be removed
automatically.
Removed ssDM and meshDM DerivedMesh backends:
The ssDM backend was for DispListMesh, so that became obsolete automatically.
The meshDM backend was replaced by the custom data backend, that now figures
out which layers need to be modified, and only duplicates those.
This changes code in many places, and overall removes 2514 lines of code.
So, there's a good chance this might break some stuff, although I've been
testing it for a few days now. The good news is, adding multiple color and
uv layers should now become easy.
2006-11-20 04:28:02 +00:00
|
|
|
static int corner_indices[4] = {1, 2, 0, 3};
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-06-18 14:27:41 +10:00
|
|
|
SWAP(uint, mface->v1, mface->v2);
|
|
|
|
SWAP(uint, mface->v2, mface->v3);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
if (fdata) {
|
2016-02-28 15:16:42 +01:00
|
|
|
CustomData_swap_corners(fdata, mfindex, corner_indices);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
2012-05-06 15:15:33 +00:00
|
|
|
else if (nr == 4) {
|
|
|
|
if (mface->v3 == 0 || mface->v4 == 0) {
|
Added custom vertex/edge/face data for meshes:
All data layers, including MVert/MEdge/MFace, are now managed as custom
data layers. The pointers like Mesh.mvert, Mesh.dvert or Mesh.mcol are
still used of course, but allocating, copying or freeing these arrays
should be done through the CustomData API.
Work in progress documentation on this is here:
http://mediawiki.blender.org/index.php/BlenderDev/BlenderArchitecture/CustomData
Replaced TFace by MTFace:
This is the same struct, except that it does not contain color, that now
always stays separated in MCol. This was not a good design decision to
begin with, and it is needed for adding multiple color layers later. Note
that this does mean older Blender versions will not be able to read UV
coordinates from the next release, due to an SDNA limitation.
Removed DispListMesh:
This now fully replaced by DerivedMesh. To provide access to arrays of
vertices, edges and faces, like DispListMesh does. The semantics of the
DerivedMesh.getVertArray() and similar functions were changed to return
a pointer to an array if one exists, or otherwise allocate a temporary
one. On releasing the DerivedMesh, this temporary array will be removed
automatically.
Removed ssDM and meshDM DerivedMesh backends:
The ssDM backend was for DispListMesh, so that became obsolete automatically.
The meshDM backend was replaced by the custom data backend, that now figures
out which layers need to be modified, and only duplicates those.
This changes code in many places, and overall removes 2514 lines of code.
So, there's a good chance this might break some stuff, although I've been
testing it for a few days now. The good news is, adding multiple color and
uv layers should now become easy.
2006-11-20 04:28:02 +00:00
|
|
|
static int corner_indices[4] = {2, 3, 0, 1};
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-06-18 14:27:41 +10:00
|
|
|
SWAP(uint, mface->v1, mface->v3);
|
|
|
|
SWAP(uint, mface->v2, mface->v4);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
if (fdata) {
|
2016-02-28 15:16:42 +01:00
|
|
|
CustomData_swap_corners(fdata, mfindex, corner_indices);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2008-01-29 19:49:03 +00:00
|
|
|
return nr;
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
|
2012-05-05 16:03:57 +00:00
|
|
|
Mesh *BKE_mesh_from_object(Object *ob)
|
2002-10-12 11:37:38 +00:00
|
|
|
{
|
2019-04-22 09:39:35 +10:00
|
|
|
if (ob == NULL) {
|
2012-05-06 15:15:33 +00:00
|
|
|
return NULL;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
|
|
|
if (ob->type == OB_MESH) {
|
2012-05-06 15:15:33 +00:00
|
|
|
return ob->data;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2020-08-07 12:30:43 +02:00
|
|
|
|
|
|
|
return NULL;
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
|
2018-05-29 15:49:21 +02:00
|
|
|
void BKE_mesh_assign_object(Main *bmain, Object *ob, Mesh *me)
|
2002-10-12 11:37:38 +00:00
|
|
|
{
|
2012-05-06 15:15:33 +00:00
|
|
|
Mesh *old = NULL;
|
2010-09-09 00:14:51 +00:00
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
if (ob == NULL) {
|
2012-05-06 15:15:33 +00:00
|
|
|
return;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2018-06-17 17:05:51 +02:00
|
|
|
|
2019-09-17 17:24:44 +02:00
|
|
|
multires_force_sculpt_rebuild(ob);
|
|
|
|
|
2012-05-06 15:15:33 +00:00
|
|
|
if (ob->type == OB_MESH) {
|
|
|
|
old = ob->data;
|
2019-04-22 09:39:35 +10:00
|
|
|
if (old) {
|
2015-11-09 19:47:10 +01:00
|
|
|
id_us_min(&old->id);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2012-05-06 15:15:33 +00:00
|
|
|
ob->data = me;
|
2002-10-12 11:37:38 +00:00
|
|
|
id_us_plus((ID *)me);
|
|
|
|
}
|
2018-06-17 17:05:51 +02:00
|
|
|
|
2020-02-05 11:23:58 +01:00
|
|
|
BKE_object_materials_test(bmain, ob, (ID *)me);
|
2010-09-09 00:14:51 +00:00
|
|
|
|
2020-05-08 10:14:02 +02:00
|
|
|
BKE_modifiers_test_object(ob);
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
|
2013-08-14 11:29:58 +00:00
|
|
|
void BKE_mesh_material_index_remove(Mesh *me, short index)
|
2009-01-04 14:14:06 +00:00
|
|
|
{
|
2013-08-14 11:29:58 +00:00
|
|
|
MPoly *mp;
|
|
|
|
MFace *mf;
|
2004-03-20 23:59:57 +00:00
|
|
|
int i;
|
|
|
|
|
2013-08-14 11:29:58 +00:00
|
|
|
for (mp = me->mpoly, i = 0; i < me->totpoly; i++, mp++) {
|
|
|
|
if (mp->mat_nr && mp->mat_nr >= index) {
|
2011-04-24 08:11:44 +00:00
|
|
|
mp->mat_nr--;
|
2013-08-14 11:29:58 +00:00
|
|
|
}
|
2011-04-24 08:06:26 +00:00
|
|
|
}
|
2013-08-14 11:29:58 +00:00
|
|
|
|
|
|
|
for (mf = me->mface, i = 0; i < me->totface; i++, mf++) {
|
|
|
|
if (mf->mat_nr && mf->mat_nr >= index) {
|
2004-03-20 23:59:57 +00:00
|
|
|
mf->mat_nr--;
|
2013-08-14 11:29:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-31 12:04:52 -07:00
|
|
|
bool BKE_mesh_material_index_used(Mesh *me, short index)
|
|
|
|
{
|
|
|
|
MPoly *mp;
|
|
|
|
MFace *mf;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (mp = me->mpoly, i = 0; i < me->totpoly; i++, mp++) {
|
|
|
|
if (mp->mat_nr == index) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (mf = me->mface, i = 0; i < me->totface; i++, mf++) {
|
|
|
|
if (mf->mat_nr == index) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-08-14 11:29:58 +00:00
|
|
|
void BKE_mesh_material_index_clear(Mesh *me)
|
|
|
|
{
|
|
|
|
MPoly *mp;
|
|
|
|
MFace *mf;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (mp = me->mpoly, i = 0; i < me->totpoly; i++, mp++) {
|
|
|
|
mp->mat_nr = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (mf = me->mface, i = 0; i < me->totface; i++, mf++) {
|
|
|
|
mf->mat_nr = 0;
|
2004-03-20 23:59:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-18 14:27:41 +10:00
|
|
|
void BKE_mesh_material_remap(Mesh *me, const uint *remap, uint remap_len)
|
2015-04-28 07:24:56 +10:00
|
|
|
{
|
|
|
|
const short remap_len_short = (short)remap_len;
|
|
|
|
|
|
|
|
#define MAT_NR_REMAP(n) \
|
|
|
|
if (n < remap_len_short) { \
|
|
|
|
BLI_assert(n >= 0 && remap[n] < remap_len_short); \
|
|
|
|
n = remap[n]; \
|
|
|
|
} \
|
|
|
|
((void)0)
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-02-17 18:05:18 +11:00
|
|
|
if (me->edit_mesh) {
|
|
|
|
BMEditMesh *em = me->edit_mesh;
|
2015-04-28 07:24:56 +10:00
|
|
|
BMIter iter;
|
|
|
|
BMFace *efa;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-04-28 07:24:56 +10:00
|
|
|
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
|
|
|
|
MAT_NR_REMAP(efa->mat_nr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < me->totpoly; i++) {
|
|
|
|
MAT_NR_REMAP(me->mpoly[i].mat_nr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#undef MAT_NR_REMAP
|
|
|
|
}
|
|
|
|
|
2019-08-25 12:00:03 +10:00
|
|
|
void BKE_mesh_smooth_flag_set(Mesh *me, const bool use_smooth)
|
2009-01-04 14:14:06 +00:00
|
|
|
{
|
2019-08-25 12:00:03 +10:00
|
|
|
if (use_smooth) {
|
|
|
|
for (int i = 0; i < me->totpoly; i++) {
|
|
|
|
me->mpoly[i].flag |= ME_SMOOTH;
|
2011-04-24 08:06:26 +00:00
|
|
|
}
|
|
|
|
}
|
2019-08-25 12:00:03 +10:00
|
|
|
else {
|
|
|
|
for (int i = 0; i < me->totpoly; i++) {
|
|
|
|
me->mpoly[i].flag &= ~ME_SMOOTH;
|
2004-03-20 23:59:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-07-17 21:24:43 +00:00
|
|
|
|
2013-09-09 02:11:44 +00:00
|
|
|
/**
|
|
|
|
* Find the index of the loop in 'poly' which references vertex,
|
|
|
|
* returns -1 if not found
|
|
|
|
*/
|
2020-02-08 01:02:18 +11:00
|
|
|
int poly_find_loop_from_vert(const MPoly *poly, const MLoop *loopstart, uint vert)
|
2011-04-15 01:19:13 +00:00
|
|
|
{
|
2020-12-27 21:46:57 -06:00
|
|
|
for (int j = 0; j < poly->totloop; j++, loopstart++) {
|
2019-04-22 09:39:35 +10:00
|
|
|
if (loopstart->v == vert) {
|
2013-09-09 02:11:44 +00:00
|
|
|
return j;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2011-04-15 01:19:13 +00:00
|
|
|
}
|
2018-06-17 17:05:51 +02:00
|
|
|
|
2013-09-09 02:11:44 +00:00
|
|
|
return -1;
|
2004-03-20 23:59:57 +00:00
|
|
|
}
|
2005-07-17 21:24:43 +00:00
|
|
|
|
2013-09-09 02:11:44 +00:00
|
|
|
/**
|
2014-03-16 03:24:05 +11:00
|
|
|
* Fill \a r_adj with the loop indices in \a poly adjacent to the
|
2013-09-09 02:11:44 +00:00
|
|
|
* vertex. Returns the index of the loop matching vertex, or -1 if the
|
|
|
|
* vertex is not in \a poly
|
|
|
|
*/
|
2021-06-18 14:27:41 +10:00
|
|
|
int poly_get_adj_loops_from_vert(const MPoly *poly, const MLoop *mloop, uint vert, uint r_adj[2])
|
2012-01-06 00:08:37 +00:00
|
|
|
{
|
2018-07-13 08:36:10 +02:00
|
|
|
int corner = poly_find_loop_from_vert(poly, &mloop[poly->loopstart], vert);
|
2018-06-17 17:05:51 +02:00
|
|
|
|
2013-09-09 02:11:44 +00:00
|
|
|
if (corner != -1) {
|
|
|
|
/* vertex was found */
|
2014-03-16 03:24:05 +11:00
|
|
|
r_adj[0] = ME_POLY_LOOP_PREV(mloop, poly, corner)->v;
|
2015-04-19 14:21:23 +10:00
|
|
|
r_adj[1] = ME_POLY_LOOP_NEXT(mloop, poly, corner)->v;
|
2013-05-10 10:07:01 +00:00
|
|
|
}
|
2012-01-06 00:08:37 +00:00
|
|
|
|
2013-09-09 02:11:44 +00:00
|
|
|
return corner;
|
2013-05-10 10:07:01 +00:00
|
|
|
}
|
2012-01-06 00:08:37 +00:00
|
|
|
|
2013-09-09 02:11:44 +00:00
|
|
|
/**
|
|
|
|
* Return the index of the edge vert that is not equal to \a v. If
|
|
|
|
* neither edge vertex is equal to \a v, returns -1.
|
|
|
|
*/
|
|
|
|
int BKE_mesh_edge_other_vert(const MEdge *e, int v)
|
2013-05-10 10:07:01 +00:00
|
|
|
{
|
2019-04-22 09:39:35 +10:00
|
|
|
if (e->v1 == v) {
|
2013-09-09 02:11:44 +00:00
|
|
|
return e->v2;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2020-08-07 12:30:43 +02:00
|
|
|
if (e->v2 == v) {
|
2013-09-09 02:11:44 +00:00
|
|
|
return e->v1;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2020-08-07 12:30:43 +02:00
|
|
|
|
|
|
|
return -1;
|
2013-09-09 02:11:44 +00:00
|
|
|
}
|
2013-06-12 09:35:02 +00:00
|
|
|
|
2018-10-20 21:02:52 +03:00
|
|
|
/**
|
|
|
|
* Sets each output array element to the edge index if it is a real edge, or -1.
|
|
|
|
*/
|
|
|
|
void BKE_mesh_looptri_get_real_edges(const Mesh *mesh, const MLoopTri *looptri, int r_edges[3])
|
|
|
|
{
|
|
|
|
for (int i = 2, i_next = 0; i_next < 3; i = i_next++) {
|
|
|
|
const MLoop *l1 = &mesh->mloop[looptri->tri[i]], *l2 = &mesh->mloop[looptri->tri[i_next]];
|
|
|
|
const MEdge *e = &mesh->medge[l1->e];
|
|
|
|
|
|
|
|
bool is_real = (l1->v == e->v1 && l2->v == e->v2) || (l1->v == e->v2 && l2->v == e->v1);
|
|
|
|
|
|
|
|
r_edges[i] = is_real ? l1->e : -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-09 02:11:44 +00:00
|
|
|
/* basic vertex data functions */
|
2015-07-11 04:39:27 +10:00
|
|
|
bool BKE_mesh_minmax(const Mesh *me, float r_min[3], float r_max[3])
|
2013-09-09 02:11:44 +00:00
|
|
|
{
|
|
|
|
int i = me->totvert;
|
|
|
|
MVert *mvert;
|
|
|
|
for (mvert = me->mvert; i--; mvert++) {
|
|
|
|
minmax_v3v3_v3(r_min, r_max, mvert->co);
|
2013-06-12 09:35:02 +00:00
|
|
|
}
|
2018-06-17 17:05:51 +02:00
|
|
|
|
2013-09-09 02:11:44 +00:00
|
|
|
return (me->totvert != 0);
|
|
|
|
}
|
2013-06-12 09:35:02 +00:00
|
|
|
|
2020-08-02 17:17:31 +10:00
|
|
|
void BKE_mesh_transform(Mesh *me, const float mat[4][4], bool do_keys)
|
2014-09-01 20:09:31 +10:00
|
|
|
{
|
|
|
|
int i;
|
2020-09-18 12:45:59 +02:00
|
|
|
MVert *mvert = CustomData_duplicate_referenced_layer(&me->vdata, CD_MVERT, me->totvert);
|
|
|
|
float(*lnors)[3] = CustomData_duplicate_referenced_layer(&me->ldata, CD_NORMAL, me->totloop);
|
|
|
|
|
|
|
|
/* If the referenced l;ayer has been re-allocated need to update pointers stored in the mesh. */
|
|
|
|
BKE_mesh_update_customdata_pointers(me, false);
|
2014-09-01 20:09:31 +10:00
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
for (i = 0; i < me->totvert; i++, mvert++) {
|
2014-09-01 20:09:31 +10:00
|
|
|
mul_m4_v3(mat, mvert->co);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2014-09-01 20:09:31 +10:00
|
|
|
|
|
|
|
if (do_keys && me->key) {
|
|
|
|
KeyBlock *kb;
|
|
|
|
for (kb = me->key->block.first; kb; kb = kb->next) {
|
|
|
|
float *fp = kb->data;
|
|
|
|
for (i = kb->totelem; i--; fp += 3) {
|
|
|
|
mul_m4_v3(mat, fp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-03 11:55:58 +02:00
|
|
|
/* don't update normals, caller can do this explicitly.
|
2019-04-27 12:07:07 +10:00
|
|
|
* We do update loop normals though, those may not be auto-generated
|
|
|
|
* (see e.g. STL import script)! */
|
2015-05-03 11:55:58 +02:00
|
|
|
if (lnors) {
|
|
|
|
float m3[3][3];
|
|
|
|
|
|
|
|
copy_m3_m4(m3, mat);
|
|
|
|
normalize_m3(m3);
|
|
|
|
for (i = 0; i < me->totloop; i++, lnors++) {
|
|
|
|
mul_m3_v3(m3, *lnors);
|
|
|
|
}
|
|
|
|
}
|
2014-09-01 20:09:31 +10:00
|
|
|
}
|
|
|
|
|
2013-09-09 02:11:44 +00:00
|
|
|
void BKE_mesh_translate(Mesh *me, const float offset[3], const bool do_keys)
|
|
|
|
{
|
2021-06-13 14:47:22 +10:00
|
|
|
CustomData_duplicate_referenced_layer(&me->vdata, CD_MVERT, me->totvert);
|
2020-10-28 20:15:43 +01:00
|
|
|
/* If the referenced layer has been re-allocated need to update pointers stored in the mesh. */
|
|
|
|
BKE_mesh_update_customdata_pointers(me, false);
|
|
|
|
|
2013-09-09 02:11:44 +00:00
|
|
|
int i = me->totvert;
|
2021-06-13 14:47:22 +10:00
|
|
|
for (MVert *mvert = me->mvert; i--; mvert++) {
|
2013-09-09 02:11:44 +00:00
|
|
|
add_v3_v3(mvert->co, offset);
|
2013-05-30 18:09:19 +00:00
|
|
|
}
|
2018-06-17 17:05:51 +02:00
|
|
|
|
2013-09-09 02:11:44 +00:00
|
|
|
if (do_keys && me->key) {
|
|
|
|
KeyBlock *kb;
|
|
|
|
for (kb = me->key->block.first; kb; kb = kb->next) {
|
|
|
|
float *fp = kb->data;
|
|
|
|
for (i = kb->totelem; i--; fp += 3) {
|
|
|
|
add_v3_v3(fp, offset);
|
|
|
|
}
|
2013-05-30 18:09:19 +00:00
|
|
|
}
|
2013-05-10 10:07:01 +00:00
|
|
|
}
|
2013-09-09 02:11:44 +00:00
|
|
|
}
|
2012-01-06 00:08:37 +00:00
|
|
|
|
2013-09-09 02:11:44 +00:00
|
|
|
void BKE_mesh_tessface_ensure(Mesh *mesh)
|
2005-07-17 21:24:43 +00:00
|
|
|
{
|
2013-09-09 02:11:44 +00:00
|
|
|
if (mesh->totpoly && mesh->totface == 0) {
|
|
|
|
BKE_mesh_tessface_calc(mesh);
|
2005-07-17 21:24:43 +00:00
|
|
|
}
|
|
|
|
}
|
2005-07-22 17:03:50 +00:00
|
|
|
|
2013-09-09 02:11:44 +00:00
|
|
|
void BKE_mesh_tessface_clear(Mesh *mesh)
|
2012-02-08 11:52:44 +00:00
|
|
|
{
|
2014-04-01 11:34:00 +11:00
|
|
|
mesh_tessface_clear_intern(mesh, true);
|
2012-02-08 11:52:44 +00:00
|
|
|
}
|
2012-05-08 14:58:38 +00:00
|
|
|
|
2013-01-10 04:43:31 +00:00
|
|
|
void BKE_mesh_do_versions_cd_flag_init(Mesh *mesh)
|
|
|
|
{
|
|
|
|
if (UNLIKELY(mesh->cd_flag)) {
|
|
|
|
return;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-08-07 12:30:43 +02:00
|
|
|
MVert *mv;
|
|
|
|
MEdge *med;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (mv = mesh->mvert, i = 0; i < mesh->totvert; mv++, i++) {
|
|
|
|
if (mv->bweight != 0) {
|
|
|
|
mesh->cd_flag |= ME_CDFLAG_VERT_BWEIGHT;
|
|
|
|
break;
|
2013-01-10 04:43:31 +00:00
|
|
|
}
|
2020-08-07 12:30:43 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-08-07 12:30:43 +02:00
|
|
|
for (med = mesh->medge, i = 0; i < mesh->totedge; med++, i++) {
|
|
|
|
if (med->bweight != 0) {
|
|
|
|
mesh->cd_flag |= ME_CDFLAG_EDGE_BWEIGHT;
|
|
|
|
if (mesh->cd_flag & ME_CDFLAG_EDGE_CREASE) {
|
|
|
|
break;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2020-08-07 12:30:43 +02:00
|
|
|
}
|
|
|
|
if (med->crease != 0) {
|
|
|
|
mesh->cd_flag |= ME_CDFLAG_EDGE_CREASE;
|
|
|
|
if (mesh->cd_flag & ME_CDFLAG_EDGE_BWEIGHT) {
|
|
|
|
break;
|
2013-01-10 04:43:31 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2013-01-10 04:43:31 +00:00
|
|
|
}
|
|
|
|
}
|
2013-06-15 09:42:58 +00:00
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/* MSelect functions (currently used in weight paint mode) */
|
|
|
|
|
|
|
|
void BKE_mesh_mselect_clear(Mesh *me)
|
|
|
|
{
|
2013-06-15 11:02:36 +00:00
|
|
|
if (me->mselect) {
|
|
|
|
MEM_freeN(me->mselect);
|
|
|
|
me->mselect = NULL;
|
|
|
|
}
|
2013-06-15 09:42:58 +00:00
|
|
|
me->totselect = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void BKE_mesh_mselect_validate(Mesh *me)
|
|
|
|
{
|
|
|
|
MSelect *mselect_src, *mselect_dst;
|
|
|
|
int i_src, i_dst;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
if (me->totselect == 0) {
|
2013-06-15 09:42:58 +00:00
|
|
|
return;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-06-15 09:42:58 +00:00
|
|
|
mselect_src = me->mselect;
|
2018-01-14 22:14:20 +01:00
|
|
|
mselect_dst = MEM_malloc_arrayN((me->totselect), sizeof(MSelect), "Mesh selection history");
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-06-15 09:42:58 +00:00
|
|
|
for (i_src = 0, i_dst = 0; i_src < me->totselect; i_src++) {
|
|
|
|
int index = mselect_src[i_src].index;
|
|
|
|
switch (mselect_src[i_src].type) {
|
|
|
|
case ME_VSEL: {
|
|
|
|
if (me->mvert[index].flag & SELECT) {
|
|
|
|
mselect_dst[i_dst] = mselect_src[i_src];
|
|
|
|
i_dst++;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case ME_ESEL: {
|
|
|
|
if (me->medge[index].flag & SELECT) {
|
|
|
|
mselect_dst[i_dst] = mselect_src[i_src];
|
|
|
|
i_dst++;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case ME_FSEL: {
|
|
|
|
if (me->mpoly[index].flag & SELECT) {
|
|
|
|
mselect_dst[i_dst] = mselect_src[i_src];
|
|
|
|
i_dst++;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default: {
|
|
|
|
BLI_assert(0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-06-15 09:42:58 +00:00
|
|
|
MEM_freeN(mselect_src);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-06-15 09:42:58 +00:00
|
|
|
if (i_dst == 0) {
|
|
|
|
MEM_freeN(mselect_dst);
|
|
|
|
mselect_dst = NULL;
|
|
|
|
}
|
|
|
|
else if (i_dst != me->totselect) {
|
|
|
|
mselect_dst = MEM_reallocN(mselect_dst, sizeof(MSelect) * i_dst);
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-06-15 09:42:58 +00:00
|
|
|
me->totselect = i_dst;
|
|
|
|
me->mselect = mselect_dst;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the index within me->mselect, or -1
|
|
|
|
*/
|
|
|
|
int BKE_mesh_mselect_find(Mesh *me, int index, int type)
|
|
|
|
{
|
2014-07-20 01:30:29 +10:00
|
|
|
BLI_assert(ELEM(type, ME_VSEL, ME_ESEL, ME_FSEL));
|
2013-06-15 09:42:58 +00:00
|
|
|
|
2020-12-27 21:46:57 -06:00
|
|
|
for (int i = 0; i < me->totselect; i++) {
|
2013-06-15 09:42:58 +00:00
|
|
|
if ((me->mselect[i].index == index) && (me->mselect[i].type == type)) {
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return The index of the active element.
|
|
|
|
*/
|
|
|
|
int BKE_mesh_mselect_active_get(Mesh *me, int type)
|
|
|
|
{
|
2014-07-20 01:30:29 +10:00
|
|
|
BLI_assert(ELEM(type, ME_VSEL, ME_ESEL, ME_FSEL));
|
2013-06-15 09:42:58 +00:00
|
|
|
|
2013-06-30 22:04:03 +00:00
|
|
|
if (me->totselect) {
|
2013-06-15 09:42:58 +00:00
|
|
|
if (me->mselect[me->totselect - 1].type == type) {
|
|
|
|
return me->mselect[me->totselect - 1].index;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void BKE_mesh_mselect_active_set(Mesh *me, int index, int type)
|
|
|
|
{
|
|
|
|
const int msel_index = BKE_mesh_mselect_find(me, index, type);
|
|
|
|
|
|
|
|
if (msel_index == -1) {
|
|
|
|
/* add to the end */
|
|
|
|
me->mselect = MEM_reallocN(me->mselect, sizeof(MSelect) * (me->totselect + 1));
|
|
|
|
me->mselect[me->totselect].index = index;
|
|
|
|
me->mselect[me->totselect].type = type;
|
|
|
|
me->totselect++;
|
|
|
|
}
|
|
|
|
else if (msel_index != me->totselect - 1) {
|
|
|
|
/* move to the end */
|
|
|
|
SWAP(MSelect, me->mselect[msel_index], me->mselect[me->totselect - 1]);
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_assert((me->mselect[me->totselect - 1].index == index) &&
|
|
|
|
(me->mselect[me->totselect - 1].type == type));
|
|
|
|
}
|
Bake API - bpy.ops.object.bake()
New operator that can calls a bake function to the current render engine when available. This commit provides no feature for the users, but allows external engines to be accessed by the operator and be integrated with the baking api.
The API itself is simple. Blender sends a populated array of BakePixels to the renderer, and gets back an array of floats with the result.
The Blender Internal (and multires) system is still running independent, but we eventually will pipe it through the API as well. Cycles baking will come next as a separated commit
Python Operator:
----------------
The operator can be called with some arguments, or a user interface can be created for it. In that case the arguments can be ommited and the interface can expose the settings from bpy.context.scene.render.bake
bpy.ops.object.bake(type='COMBINED', filepath="", width=512, height=512, margin=16, use_selected_to_active=False, cage_extrusion=0, cage="", normal_space='TANGENT', normal_r='POS_X', normal_g='POS_Y', normal_b='POS_Z', save_mode='INTERNAL', use_clear=False, use_split_materials=False, use_automatic_name=False)
Note: external save mode is currently disabled.
Supported Features:
------------------
* Margin - Baked result is extended this many pixels beyond the border of each UV "island," to soften seams in the texture.
* Selected to Active - bake shading on the surface of selected object to the active object. The rays are cast from the lowpoly object inwards towards the highpoly object. If the highpoly object is not entirely involved by the lowpoly object, you can tweak the rays start point with Cage Extrusion. For even more control of the cage you can use a Cage object.
* Cage Extrusion - distance to use for the inward ray cast when using selected to active
* Custom Cage - object to use as cage (instead of the lowpoly object).
* Normal swizzle - change the axis that gets mapped to RGB
* Normal space - save as tangent or object normal spaces
Supported Passes:
-----------------
Any pass that is supported by Blender renderlayer system. Though it's up to the external engine to provide a valid enum with its supported passes. Normal passes get a special treatment since we post-process them to converted and "swizzled"
Development Notes for External Engines:
---------------------------------------
(read them in bake_api.c)
* For a complete implementation example look at the Cycles Bake commit (next).
Review: D421
Reviewed by: Campbell Barton, Brecht van Lommel, Sergey Sharybin, Thomas Dinge
Normal map pipeline "consulting" by Andy Davies (metalliandy)
Original design by Brecht van Lommel.
The entire commit history can be found on the branch: bake-cycles
2014-01-02 19:05:07 -02:00
|
|
|
|
2018-12-17 18:15:41 +11:00
|
|
|
void BKE_mesh_count_selected_items(const Mesh *mesh, int r_count[3])
|
|
|
|
{
|
|
|
|
r_count[0] = r_count[1] = r_count[2] = 0;
|
2019-02-17 18:05:18 +11:00
|
|
|
if (mesh->edit_mesh) {
|
|
|
|
BMesh *bm = mesh->edit_mesh->bm;
|
2018-12-17 18:15:41 +11:00
|
|
|
r_count[0] = bm->totvertsel;
|
|
|
|
r_count[1] = bm->totedgesel;
|
|
|
|
r_count[2] = bm->totfacesel;
|
|
|
|
}
|
|
|
|
/* We could support faces in paint modes. */
|
|
|
|
}
|
2018-05-08 11:33:31 +02:00
|
|
|
|
2019-08-22 06:28:35 +10:00
|
|
|
void BKE_mesh_vert_coords_get(const Mesh *mesh, float (*vert_coords)[3])
|
|
|
|
{
|
|
|
|
const MVert *mv = mesh->mvert;
|
|
|
|
for (int i = 0; i < mesh->totvert; i++, mv++) {
|
|
|
|
copy_v3_v3(vert_coords[i], mv->co);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
float (*BKE_mesh_vert_coords_alloc(const Mesh *mesh, int *r_vert_len))[3]
|
|
|
|
{
|
|
|
|
float(*vert_coords)[3] = MEM_mallocN(sizeof(float[3]) * mesh->totvert, __func__);
|
|
|
|
BKE_mesh_vert_coords_get(mesh, vert_coords);
|
|
|
|
if (r_vert_len) {
|
|
|
|
*r_vert_len = mesh->totvert;
|
|
|
|
}
|
|
|
|
return vert_coords;
|
|
|
|
}
|
|
|
|
|
|
|
|
void BKE_mesh_vert_coords_apply(Mesh *mesh, const float (*vert_coords)[3])
|
2018-05-08 11:33:31 +02:00
|
|
|
{
|
2019-08-21 11:46:04 +10:00
|
|
|
/* This will just return the pointer if it wasn't a referenced layer. */
|
|
|
|
MVert *mv = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MVERT, mesh->totvert);
|
|
|
|
mesh->mvert = mv;
|
|
|
|
for (int i = 0; i < mesh->totvert; i++, mv++) {
|
2019-08-22 06:28:35 +10:00
|
|
|
copy_v3_v3(mv->co, vert_coords[i]);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2018-05-08 11:33:31 +02:00
|
|
|
mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
|
2019-08-22 13:45:31 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
void BKE_mesh_vert_coords_apply_with_mat4(Mesh *mesh,
|
|
|
|
const float (*vert_coords)[3],
|
|
|
|
const float mat[4][4])
|
|
|
|
{
|
|
|
|
/* This will just return the pointer if it wasn't a referenced layer. */
|
|
|
|
MVert *mv = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MVERT, mesh->totvert);
|
|
|
|
mesh->mvert = mv;
|
|
|
|
for (int i = 0; i < mesh->totvert; i++, mv++) {
|
|
|
|
mul_v3_m4v3(mv->co, mat, vert_coords[i]);
|
|
|
|
}
|
|
|
|
mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
|
2018-05-08 11:33:31 +02:00
|
|
|
}
|
|
|
|
|
2019-08-22 06:28:35 +10:00
|
|
|
void BKE_mesh_vert_normals_apply(Mesh *mesh, const short (*vert_normals)[3])
|
2018-07-05 10:12:36 +02:00
|
|
|
{
|
2019-08-21 11:46:04 +10:00
|
|
|
/* This will just return the pointer if it wasn't a referenced layer. */
|
|
|
|
MVert *mv = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MVERT, mesh->totvert);
|
|
|
|
mesh->mvert = mv;
|
|
|
|
for (int i = 0; i < mesh->totvert; i++, mv++) {
|
2019-08-22 06:28:35 +10:00
|
|
|
copy_v3_v3_short(mv->no, vert_normals[i]);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2018-07-05 10:12:36 +02:00
|
|
|
mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
|
|
|
|
}
|
|
|
|
|
2017-08-30 16:42:53 +02:00
|
|
|
/**
|
|
|
|
* Compute 'split' (aka loop, or per face corner's) normals.
|
|
|
|
*
|
2019-04-27 12:07:07 +10:00
|
|
|
* \param r_lnors_spacearr: Allows to get computed loop normal space array.
|
|
|
|
* That data, among other things, contains 'smooth fan' info, useful e.g.
|
|
|
|
* to split geometry along sharp edges...
|
2017-08-30 16:42:53 +02:00
|
|
|
*/
|
2017-02-22 09:40:46 +01:00
|
|
|
void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spacearr)
|
2015-03-20 12:41:31 +05:00
|
|
|
{
|
|
|
|
float(*r_loopnors)[3];
|
|
|
|
float(*polynors)[3];
|
|
|
|
short(*clnors)[2] = NULL;
|
|
|
|
bool free_polynors = false;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-09-04 21:02:46 +02:00
|
|
|
/* Note that we enforce computing clnors when the clnor space array is requested by caller here.
|
2019-04-27 12:07:07 +10:00
|
|
|
* However, we obviously only use the autosmooth angle threshold
|
|
|
|
* only in case autosmooth is enabled. */
|
2017-09-04 21:02:46 +02:00
|
|
|
const bool use_split_normals = (r_lnors_spacearr != NULL) || ((mesh->flag & ME_AUTOSMOOTH) != 0);
|
|
|
|
const float split_angle = (mesh->flag & ME_AUTOSMOOTH) != 0 ? mesh->smoothresh : (float)M_PI;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-03-20 12:41:31 +05:00
|
|
|
if (CustomData_has_layer(&mesh->ldata, CD_NORMAL)) {
|
|
|
|
r_loopnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL);
|
|
|
|
memset(r_loopnors, 0, sizeof(float[3]) * mesh->totloop);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
r_loopnors = CustomData_add_layer(&mesh->ldata, CD_NORMAL, CD_CALLOC, NULL, mesh->totloop);
|
|
|
|
CustomData_set_layer_flag(&mesh->ldata, CD_NORMAL, CD_FLAG_TEMPORARY);
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-03-20 12:41:31 +05:00
|
|
|
/* may be NULL */
|
|
|
|
clnors = CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-03-20 12:41:31 +05:00
|
|
|
if (CustomData_has_layer(&mesh->pdata, CD_NORMAL)) {
|
2019-04-27 12:07:07 +10:00
|
|
|
/* This assume that layer is always up to date, not sure this is the case
|
|
|
|
* (esp. in Edit mode?)... */
|
2015-03-20 12:41:31 +05:00
|
|
|
polynors = CustomData_get_layer(&mesh->pdata, CD_NORMAL);
|
|
|
|
free_polynors = false;
|
|
|
|
}
|
|
|
|
else {
|
2018-01-14 22:14:20 +01:00
|
|
|
polynors = MEM_malloc_arrayN(mesh->totpoly, sizeof(float[3]), __func__);
|
2015-10-12 20:12:55 +02:00
|
|
|
BKE_mesh_calc_normals_poly(mesh->mvert,
|
2018-07-13 08:36:10 +02:00
|
|
|
NULL,
|
|
|
|
mesh->totvert,
|
|
|
|
mesh->mloop,
|
|
|
|
mesh->mpoly,
|
|
|
|
mesh->totloop,
|
|
|
|
mesh->totpoly,
|
|
|
|
polynors,
|
|
|
|
false);
|
2015-03-20 12:41:31 +05:00
|
|
|
free_polynors = true;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-03-20 12:41:31 +05:00
|
|
|
BKE_mesh_normals_loop_split(mesh->mvert,
|
|
|
|
mesh->totvert,
|
|
|
|
mesh->medge,
|
|
|
|
mesh->totedge,
|
|
|
|
mesh->mloop,
|
|
|
|
r_loopnors,
|
|
|
|
mesh->totloop,
|
|
|
|
mesh->mpoly,
|
|
|
|
(const float(*)[3])polynors,
|
|
|
|
mesh->totpoly,
|
2017-09-04 21:02:46 +02:00
|
|
|
use_split_normals,
|
|
|
|
split_angle,
|
|
|
|
r_lnors_spacearr,
|
|
|
|
clnors,
|
|
|
|
NULL);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-03-20 12:41:31 +05:00
|
|
|
if (free_polynors) {
|
|
|
|
MEM_freeN(polynors);
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-08 11:56:31 +02:00
|
|
|
mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
|
2015-03-20 12:41:31 +05:00
|
|
|
}
|
|
|
|
|
2017-02-22 09:40:46 +01:00
|
|
|
void BKE_mesh_calc_normals_split(Mesh *mesh)
|
2015-03-20 12:41:31 +05:00
|
|
|
{
|
2017-02-22 09:40:46 +01:00
|
|
|
BKE_mesh_calc_normals_split_ex(mesh, NULL);
|
2017-02-15 23:09:31 +01:00
|
|
|
}
|
|
|
|
|
2017-02-22 09:40:46 +01:00
|
|
|
/* Split faces helper functions. */
|
|
|
|
|
|
|
|
typedef struct SplitFaceNewVert {
|
|
|
|
struct SplitFaceNewVert *next;
|
|
|
|
int new_index;
|
|
|
|
int orig_index;
|
|
|
|
float *vnor;
|
|
|
|
} SplitFaceNewVert;
|
|
|
|
|
|
|
|
typedef struct SplitFaceNewEdge {
|
|
|
|
struct SplitFaceNewEdge *next;
|
|
|
|
int new_index;
|
|
|
|
int orig_index;
|
|
|
|
int v1;
|
|
|
|
int v2;
|
|
|
|
} SplitFaceNewEdge;
|
|
|
|
|
|
|
|
/* Detect needed new vertices, and update accordingly loops' vertex indices.
|
|
|
|
* WARNING! Leaves mesh in invalid state. */
|
|
|
|
static int split_faces_prepare_new_verts(const Mesh *mesh,
|
2017-08-30 16:42:53 +02:00
|
|
|
MLoopNorSpaceArray *lnors_spacearr,
|
|
|
|
SplitFaceNewVert **new_verts,
|
|
|
|
MemArena *memarena)
|
2017-02-22 09:40:46 +01:00
|
|
|
{
|
2019-04-27 12:07:07 +10:00
|
|
|
/* This is now mandatory, trying to do the job in simple way without that data is doomed to fail,
|
|
|
|
* even when only dealing with smooth/flat faces one can find cases that no simple algorithm
|
|
|
|
* can handle properly. */
|
2017-08-30 16:42:53 +02:00
|
|
|
BLI_assert(lnors_spacearr != NULL);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-08 17:15:23 +02:00
|
|
|
const int loops_len = mesh->totloop;
|
|
|
|
int verts_len = mesh->totvert;
|
2017-02-22 09:40:46 +01:00
|
|
|
MVert *mvert = mesh->mvert;
|
|
|
|
MLoop *mloop = mesh->mloop;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-08 17:15:23 +02:00
|
|
|
BLI_bitmap *verts_used = BLI_BITMAP_NEW(verts_len, __func__);
|
|
|
|
BLI_bitmap *done_loops = BLI_BITMAP_NEW(loops_len, __func__);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-08-30 16:42:53 +02:00
|
|
|
MLoop *ml = mloop;
|
|
|
|
MLoopNorSpace **lnor_space = lnors_spacearr->lspacearr;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Refactor: Merge non-functional-change part of 'edit normals' 2017 GSoC.
This merges changes in internals, runtime-only of existing custom
normals code, which make sense as of themselves, and will make diff of
soc branch easier/lighter to review.
In the details, it mostly changes two things:
* Now, smooth fans (aka MLoopNorSpaceArray) can store either loop
indices, or pointers to BMLoop themselves. This makes sense since in
BMesh, it's relatively easy to get index from a BMElement, but nearly
impracticable to go the other way around.
* First change enforces another, now we cannot rely anymore on `loops`
being NULL in MLoopNorSpace to detect single-loop fans, so we instead
store that info in a new flag.
Again, these are expected to be totally non-functional changes.
2018-03-01 16:54:21 +01:00
|
|
|
BLI_assert(lnors_spacearr->data_type == MLNOR_SPACEARR_LOOP_INDEX);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-08 17:15:23 +02:00
|
|
|
for (int loop_idx = 0; loop_idx < loops_len; loop_idx++, ml++, lnor_space++) {
|
2017-08-30 16:42:53 +02:00
|
|
|
if (!BLI_BITMAP_TEST(done_loops, loop_idx)) {
|
|
|
|
const int vert_idx = ml->v;
|
|
|
|
const bool vert_used = BLI_BITMAP_TEST_BOOL(verts_used, vert_idx);
|
|
|
|
/* If vert is already used by another smooth fan, we need a new vert for this one. */
|
2018-05-08 17:15:23 +02:00
|
|
|
const int new_vert_idx = vert_used ? verts_len++ : vert_idx;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-08-30 16:42:53 +02:00
|
|
|
BLI_assert(*lnor_space);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Refactor: Merge non-functional-change part of 'edit normals' 2017 GSoC.
This merges changes in internals, runtime-only of existing custom
normals code, which make sense as of themselves, and will make diff of
soc branch easier/lighter to review.
In the details, it mostly changes two things:
* Now, smooth fans (aka MLoopNorSpaceArray) can store either loop
indices, or pointers to BMLoop themselves. This makes sense since in
BMesh, it's relatively easy to get index from a BMElement, but nearly
impracticable to go the other way around.
* First change enforces another, now we cannot rely anymore on `loops`
being NULL in MLoopNorSpace to detect single-loop fans, so we instead
store that info in a new flag.
Again, these are expected to be totally non-functional changes.
2018-03-01 16:54:21 +01:00
|
|
|
if ((*lnor_space)->flags & MLNOR_SPACE_IS_SINGLE) {
|
|
|
|
/* Single loop in this fan... */
|
2018-09-19 12:05:58 +10:00
|
|
|
BLI_assert(POINTER_AS_INT((*lnor_space)->loops) == loop_idx);
|
Refactor: Merge non-functional-change part of 'edit normals' 2017 GSoC.
This merges changes in internals, runtime-only of existing custom
normals code, which make sense as of themselves, and will make diff of
soc branch easier/lighter to review.
In the details, it mostly changes two things:
* Now, smooth fans (aka MLoopNorSpaceArray) can store either loop
indices, or pointers to BMLoop themselves. This makes sense since in
BMesh, it's relatively easy to get index from a BMElement, but nearly
impracticable to go the other way around.
* First change enforces another, now we cannot rely anymore on `loops`
being NULL in MLoopNorSpace to detect single-loop fans, so we instead
store that info in a new flag.
Again, these are expected to be totally non-functional changes.
2018-03-01 16:54:21 +01:00
|
|
|
BLI_BITMAP_ENABLE(done_loops, loop_idx);
|
|
|
|
if (vert_used) {
|
|
|
|
ml->v = new_vert_idx;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
Refactor: Merge non-functional-change part of 'edit normals' 2017 GSoC.
This merges changes in internals, runtime-only of existing custom
normals code, which make sense as of themselves, and will make diff of
soc branch easier/lighter to review.
In the details, it mostly changes two things:
* Now, smooth fans (aka MLoopNorSpaceArray) can store either loop
indices, or pointers to BMLoop themselves. This makes sense since in
BMesh, it's relatively easy to get index from a BMElement, but nearly
impracticable to go the other way around.
* First change enforces another, now we cannot rely anymore on `loops`
being NULL in MLoopNorSpace to detect single-loop fans, so we instead
store that info in a new flag.
Again, these are expected to be totally non-functional changes.
2018-03-01 16:54:21 +01:00
|
|
|
else {
|
2017-08-30 16:42:53 +02:00
|
|
|
for (LinkNode *lnode = (*lnor_space)->loops; lnode; lnode = lnode->next) {
|
2018-09-19 12:05:58 +10:00
|
|
|
const int ml_fan_idx = POINTER_AS_INT(lnode->link);
|
2017-08-30 16:42:53 +02:00
|
|
|
BLI_BITMAP_ENABLE(done_loops, ml_fan_idx);
|
2017-02-22 09:40:46 +01:00
|
|
|
if (vert_used) {
|
2017-08-30 16:42:53 +02:00
|
|
|
mloop[ml_fan_idx].v = new_vert_idx;
|
2017-02-15 23:09:31 +01:00
|
|
|
}
|
2017-02-15 13:56:50 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
2017-08-30 16:42:53 +02:00
|
|
|
if (!vert_used) {
|
|
|
|
BLI_BITMAP_ENABLE(verts_used, vert_idx);
|
|
|
|
/* We need to update that vertex's normal here, we won't go over it again. */
|
2019-04-27 12:07:07 +10:00
|
|
|
/* This is important! *DO NOT* set vnor to final computed lnor,
|
|
|
|
* vnor should always be defined to 'automatic normal' value computed from its polys,
|
|
|
|
* not some custom normal.
|
2017-08-30 16:42:53 +02:00
|
|
|
* Fortunately, that's the loop normal space's 'lnor' reference vector. ;) */
|
|
|
|
normal_float_to_short_v3(mvert[vert_idx].no, (*lnor_space)->vec_lnor);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* Add new vert to list. */
|
|
|
|
SplitFaceNewVert *new_vert = BLI_memarena_alloc(memarena, sizeof(*new_vert));
|
|
|
|
new_vert->orig_index = vert_idx;
|
|
|
|
new_vert->new_index = new_vert_idx;
|
|
|
|
new_vert->vnor = (*lnor_space)->vec_lnor; /* See note above. */
|
|
|
|
new_vert->next = *new_verts;
|
|
|
|
*new_verts = new_vert;
|
2017-02-15 13:56:50 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-08-30 16:42:53 +02:00
|
|
|
MEM_freeN(done_loops);
|
2017-02-22 09:40:46 +01:00
|
|
|
MEM_freeN(verts_used);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-08 17:15:23 +02:00
|
|
|
return verts_len - mesh->totvert;
|
2017-02-15 23:09:31 +01:00
|
|
|
}
|
|
|
|
|
2017-02-22 09:40:46 +01:00
|
|
|
/* Detect needed new edges, and update accordingly loops' edge indices.
|
|
|
|
* WARNING! Leaves mesh in invalid state. */
|
|
|
|
static int split_faces_prepare_new_edges(const Mesh *mesh,
|
|
|
|
SplitFaceNewEdge **new_edges,
|
|
|
|
MemArena *memarena)
|
2015-03-20 12:41:31 +05:00
|
|
|
{
|
2017-02-15 23:09:31 +01:00
|
|
|
const int num_polys = mesh->totpoly;
|
2017-02-22 09:40:46 +01:00
|
|
|
int num_edges = mesh->totedge;
|
|
|
|
MEdge *medge = mesh->medge;
|
|
|
|
MLoop *mloop = mesh->mloop;
|
2017-02-15 23:09:31 +01:00
|
|
|
const MPoly *mpoly = mesh->mpoly;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-02-22 09:40:46 +01:00
|
|
|
BLI_bitmap *edges_used = BLI_BITMAP_NEW(num_edges, __func__);
|
|
|
|
EdgeHash *edges_hash = BLI_edgehash_new_ex(__func__, num_edges);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-02-22 09:40:46 +01:00
|
|
|
const MPoly *mp = mpoly;
|
|
|
|
for (int poly_idx = 0; poly_idx < num_polys; poly_idx++, mp++) {
|
|
|
|
MLoop *ml_prev = &mloop[mp->loopstart + mp->totloop - 1];
|
|
|
|
MLoop *ml = &mloop[mp->loopstart];
|
|
|
|
for (int loop_idx = 0; loop_idx < mp->totloop; loop_idx++, ml++) {
|
|
|
|
void **eval;
|
|
|
|
if (!BLI_edgehash_ensure_p(edges_hash, ml_prev->v, ml->v, &eval)) {
|
2017-03-02 17:22:03 +01:00
|
|
|
const int edge_idx = ml_prev->e;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-02-22 09:40:46 +01:00
|
|
|
/* That edge has not been encountered yet, define it. */
|
2017-03-02 17:22:03 +01:00
|
|
|
if (BLI_BITMAP_TEST(edges_used, edge_idx)) {
|
2017-02-22 09:40:46 +01:00
|
|
|
/* Original edge has already been used, we need to define a new one. */
|
2017-03-02 17:22:03 +01:00
|
|
|
const int new_edge_idx = num_edges++;
|
2018-09-19 12:05:58 +10:00
|
|
|
*eval = POINTER_FROM_INT(new_edge_idx);
|
2017-03-02 17:22:03 +01:00
|
|
|
ml_prev->e = new_edge_idx;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-02-22 09:40:46 +01:00
|
|
|
SplitFaceNewEdge *new_edge = BLI_memarena_alloc(memarena, sizeof(*new_edge));
|
2017-03-02 17:22:03 +01:00
|
|
|
new_edge->orig_index = edge_idx;
|
|
|
|
new_edge->new_index = new_edge_idx;
|
2017-02-22 09:40:46 +01:00
|
|
|
new_edge->v1 = ml_prev->v;
|
|
|
|
new_edge->v2 = ml->v;
|
|
|
|
new_edge->next = *new_edges;
|
|
|
|
*new_edges = new_edge;
|
2017-02-15 23:09:31 +01:00
|
|
|
}
|
|
|
|
else {
|
2017-02-22 09:40:46 +01:00
|
|
|
/* We can re-use original edge. */
|
|
|
|
medge[edge_idx].v1 = ml_prev->v;
|
|
|
|
medge[edge_idx].v2 = ml->v;
|
2018-09-19 12:05:58 +10:00
|
|
|
*eval = POINTER_FROM_INT(edge_idx);
|
2017-02-22 09:40:46 +01:00
|
|
|
BLI_BITMAP_ENABLE(edges_used, edge_idx);
|
2017-02-15 23:09:31 +01:00
|
|
|
}
|
|
|
|
}
|
2017-02-22 09:40:46 +01:00
|
|
|
else {
|
|
|
|
/* Edge already known, just update loop's edge index. */
|
2018-09-19 12:05:58 +10:00
|
|
|
ml_prev->e = POINTER_AS_INT(*eval);
|
2017-02-22 09:40:46 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-02-22 09:40:46 +01:00
|
|
|
ml_prev = ml;
|
2017-02-15 23:09:31 +01:00
|
|
|
}
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-02-22 09:40:46 +01:00
|
|
|
MEM_freeN(edges_used);
|
|
|
|
BLI_edgehash_free(edges_hash, NULL);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-02-22 09:40:46 +01:00
|
|
|
return num_edges - mesh->totedge;
|
2017-02-15 23:09:31 +01:00
|
|
|
}
|
|
|
|
|
2017-02-22 09:40:46 +01:00
|
|
|
/* Perform actual split of vertices. */
|
|
|
|
static void split_faces_split_new_verts(Mesh *mesh,
|
|
|
|
SplitFaceNewVert *new_verts,
|
|
|
|
const int num_new_verts)
|
2017-02-15 23:09:31 +01:00
|
|
|
{
|
2018-05-08 17:15:23 +02:00
|
|
|
const int verts_len = mesh->totvert - num_new_verts;
|
2015-03-20 12:41:31 +05:00
|
|
|
MVert *mvert = mesh->mvert;
|
2017-02-22 09:40:46 +01:00
|
|
|
|
|
|
|
/* Remember new_verts is a single linklist, so its items are in reversed order... */
|
|
|
|
MVert *new_mv = &mvert[mesh->totvert - 1];
|
2018-05-08 17:15:23 +02:00
|
|
|
for (int i = mesh->totvert - 1; i >= verts_len; i--, new_mv--, new_verts = new_verts->next) {
|
2017-02-22 09:40:46 +01:00
|
|
|
BLI_assert(new_verts->new_index == i);
|
2017-03-02 17:22:03 +01:00
|
|
|
BLI_assert(new_verts->new_index != new_verts->orig_index);
|
2017-02-22 09:40:46 +01:00
|
|
|
CustomData_copy_data(&mesh->vdata, &mesh->vdata, new_verts->orig_index, i, 1);
|
|
|
|
if (new_verts->vnor) {
|
|
|
|
normal_float_to_short_v3(new_mv->no, new_verts->vnor);
|
2017-02-15 13:56:50 +01:00
|
|
|
}
|
2017-02-15 20:59:55 +01:00
|
|
|
}
|
2017-02-15 23:09:31 +01:00
|
|
|
}
|
|
|
|
|
2017-02-22 09:40:46 +01:00
|
|
|
/* Perform actual split of edges. */
|
|
|
|
static void split_faces_split_new_edges(Mesh *mesh,
|
|
|
|
SplitFaceNewEdge *new_edges,
|
|
|
|
const int num_new_edges)
|
2017-02-15 23:09:31 +01:00
|
|
|
{
|
|
|
|
const int num_edges = mesh->totedge - num_new_edges;
|
2015-03-20 12:41:31 +05:00
|
|
|
MEdge *medge = mesh->medge;
|
2017-02-22 09:40:46 +01:00
|
|
|
|
|
|
|
/* Remember new_edges is a single linklist, so its items are in reversed order... */
|
|
|
|
MEdge *new_med = &medge[mesh->totedge - 1];
|
|
|
|
for (int i = mesh->totedge - 1; i >= num_edges; i--, new_med--, new_edges = new_edges->next) {
|
|
|
|
BLI_assert(new_edges->new_index == i);
|
2017-03-02 17:22:03 +01:00
|
|
|
BLI_assert(new_edges->new_index != new_edges->orig_index);
|
2017-02-22 09:40:46 +01:00
|
|
|
CustomData_copy_data(&mesh->edata, &mesh->edata, new_edges->orig_index, i, 1);
|
|
|
|
new_med->v1 = new_edges->v1;
|
|
|
|
new_med->v2 = new_edges->v2;
|
2015-03-20 12:41:31 +05:00
|
|
|
}
|
2017-02-15 23:09:31 +01:00
|
|
|
}
|
|
|
|
|
2017-02-22 09:40:46 +01:00
|
|
|
/* Split faces based on the edge angle and loop normals.
|
2017-02-15 23:09:31 +01:00
|
|
|
* Matches behavior of face splitting in render engines.
|
2017-02-20 11:56:02 +01:00
|
|
|
*
|
|
|
|
* NOTE: Will leave CD_NORMAL loop data layer which is
|
|
|
|
* used by render engines to set shading up.
|
2017-02-15 23:09:31 +01:00
|
|
|
*/
|
2017-02-22 10:53:28 +01:00
|
|
|
void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals)
|
2017-02-15 23:09:31 +01:00
|
|
|
{
|
|
|
|
const int num_polys = mesh->totpoly;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-02-15 23:09:31 +01:00
|
|
|
if (num_polys == 0) {
|
|
|
|
return;
|
|
|
|
}
|
2015-03-20 12:41:31 +05:00
|
|
|
BKE_mesh_tessface_clear(mesh);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-08-30 16:42:53 +02:00
|
|
|
MLoopNorSpaceArray lnors_spacearr = {NULL};
|
|
|
|
/* Compute loop normals and loop normal spaces (a.k.a. smooth fans of faces around vertices). */
|
|
|
|
BKE_mesh_calc_normals_split_ex(mesh, &lnors_spacearr);
|
|
|
|
/* Stealing memarena from loop normals space array. */
|
|
|
|
MemArena *memarena = lnors_spacearr.mem;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-02-22 09:40:46 +01:00
|
|
|
SplitFaceNewVert *new_verts = NULL;
|
|
|
|
SplitFaceNewEdge *new_edges = NULL;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-02-22 09:40:46 +01:00
|
|
|
/* Detect loop normal spaces (a.k.a. smooth fans) that will need a new vert. */
|
2017-08-30 16:42:53 +02:00
|
|
|
const int num_new_verts = split_faces_prepare_new_verts(
|
|
|
|
mesh, &lnors_spacearr, &new_verts, memarena);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-02-22 09:40:46 +01:00
|
|
|
if (num_new_verts > 0) {
|
2019-04-27 12:07:07 +10:00
|
|
|
/* Reminder: beyond this point, there is no way out, mesh is in invalid state
|
|
|
|
* (due to early-reassignment of loops' vertex and edge indices to new,
|
|
|
|
* to-be-created split ones). */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-02-22 09:40:46 +01:00
|
|
|
const int num_new_edges = split_faces_prepare_new_edges(mesh, &new_edges, memarena);
|
2017-03-13 16:11:48 +01:00
|
|
|
/* We can have to split a vertex without having to add a single new edge... */
|
|
|
|
const bool do_edges = (num_new_edges > 0);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-02-22 09:40:46 +01:00
|
|
|
/* Reallocate all vert and edge related data. */
|
|
|
|
mesh->totvert += num_new_verts;
|
|
|
|
CustomData_realloc(&mesh->vdata, mesh->totvert);
|
2017-03-13 16:11:48 +01:00
|
|
|
if (do_edges) {
|
2017-08-30 16:42:53 +02:00
|
|
|
mesh->totedge += num_new_edges;
|
2017-03-13 16:11:48 +01:00
|
|
|
CustomData_realloc(&mesh->edata, mesh->totedge);
|
|
|
|
}
|
2017-02-22 09:40:46 +01:00
|
|
|
/* Update pointers to a newly allocated memory. */
|
|
|
|
BKE_mesh_update_customdata_pointers(mesh, false);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-02-22 09:40:46 +01:00
|
|
|
/* Perform actual split of vertices and edges. */
|
|
|
|
split_faces_split_new_verts(mesh, new_verts, num_new_verts);
|
2017-03-13 16:11:48 +01:00
|
|
|
if (do_edges) {
|
|
|
|
split_faces_split_new_edges(mesh, new_edges, num_new_edges);
|
|
|
|
}
|
2017-02-22 09:40:46 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-02-22 09:40:46 +01:00
|
|
|
/* Note: after this point mesh is expected to be valid again. */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-02-22 09:40:46 +01:00
|
|
|
/* CD_NORMAL is expected to be temporary only. */
|
2017-02-22 10:53:28 +01:00
|
|
|
if (free_loop_normals) {
|
|
|
|
CustomData_free_layers(&mesh->ldata, CD_NORMAL, mesh->totloop);
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-08-30 16:42:53 +02:00
|
|
|
/* Also frees new_verts/edges temp data, since we used its memarena to allocate them. */
|
|
|
|
BKE_lnor_spacearr_free(&lnors_spacearr);
|
2017-02-22 09:40:46 +01:00
|
|
|
|
2017-02-15 13:56:50 +01:00
|
|
|
#ifdef VALIDATE_MESH
|
|
|
|
BKE_mesh_validate(mesh, true, true);
|
|
|
|
#endif
|
2015-03-20 12:41:31 +05:00
|
|
|
}
|
|
|
|
|
2015-05-12 13:57:11 +05:00
|
|
|
/* **** Depsgraph evaluation **** */
|
|
|
|
|
2018-07-13 08:36:10 +02:00
|
|
|
void BKE_mesh_eval_geometry(Depsgraph *depsgraph, Mesh *mesh)
|
2015-05-12 13:57:11 +05:00
|
|
|
{
|
2018-05-02 11:46:56 +02:00
|
|
|
DEG_debug_print_eval(depsgraph, __func__, mesh->id.name, mesh);
|
2019-07-02 16:48:28 +02:00
|
|
|
BKE_mesh_texspace_calc(mesh);
|
2019-06-06 12:26:40 +02:00
|
|
|
/* We are here because something did change in the mesh. This means we can not trust the existing
|
|
|
|
* evaluated mesh, and we don't know what parts of the mesh did change. So we simply delete the
|
|
|
|
* evaluated mesh and let objects to re-create it with updated settings. */
|
|
|
|
if (mesh->runtime.mesh_eval != NULL) {
|
|
|
|
mesh->runtime.mesh_eval->edit_mesh = NULL;
|
|
|
|
BKE_id_free(NULL, mesh->runtime.mesh_eval);
|
|
|
|
mesh->runtime.mesh_eval = NULL;
|
|
|
|
}
|
2019-07-02 16:48:28 +02:00
|
|
|
if (DEG_is_active(depsgraph)) {
|
|
|
|
Mesh *mesh_orig = (Mesh *)DEG_get_original_id(&mesh->id);
|
2019-09-23 15:31:11 +02:00
|
|
|
if (mesh->texflag & ME_AUTOSPACE_EVALUATED) {
|
|
|
|
mesh_orig->texflag |= ME_AUTOSPACE_EVALUATED;
|
2019-07-02 16:48:28 +02:00
|
|
|
copy_v3_v3(mesh_orig->loc, mesh->loc);
|
|
|
|
copy_v3_v3(mesh_orig->size, mesh->size);
|
|
|
|
}
|
|
|
|
}
|
2015-05-12 13:57:11 +05:00
|
|
|
}
|