diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 06f50b429f8..109e3be3ca6 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -2148,7 +2148,7 @@ class CYCLES_RENDER_PT_bake_output(CyclesButtonsPanel, Panel): if rd.use_bake_multires: layout.prop(rd, "use_bake_clear", text="Clear Image") - if rd.bake_type == 'DISPLACEMENT': + if rd.bake_type in {'DISPLACEMENT', 'VECTOR_DISPLACEMENT'}: layout.prop(rd, "use_bake_lores_mesh") else: layout.prop(cbk, "target") diff --git a/source/blender/blenkernel/BKE_ccg.hh b/source/blender/blenkernel/BKE_ccg.hh index 675165eee6f..e87dae16e15 100644 --- a/source/blender/blenkernel/BKE_ccg.hh +++ b/source/blender/blenkernel/BKE_ccg.hh @@ -48,10 +48,6 @@ struct CCGKey { int has_mask; }; -/* initialize 'key' at the specified level */ -void CCG_key(CCGKey *key, const CCGSubSurf *ss, int level); -void CCG_key_top_level(CCGKey *key, const CCGSubSurf *ss); - inline blender::float3 &CCG_elem_co(const CCGKey & /*key*/, CCGElem *elem) { return *reinterpret_cast(elem); @@ -104,3 +100,16 @@ inline blender::float3 &CCG_elem_offset_co(const CCGKey &key, CCGElem *elem, int { return CCG_elem_co(key, CCG_elem_offset(key, elem, offset)); } + +inline int CCG_grid_size(const int level) +{ + BLI_assert(level > 0); + return (1 << (level - 1)) + 1; +} + +inline int CCG_grid_factor(int low_level, int high_level) +{ + BLI_assert(low_level > 0 && high_level > 0); + BLI_assert(low_level <= high_level); + return 1 << (high_level - low_level); +} diff --git a/source/blender/blenkernel/BKE_mesh_legacy_derived_mesh.hh b/source/blender/blenkernel/BKE_mesh_legacy_derived_mesh.hh deleted file mode 100644 index 769edc4d58e..00000000000 --- a/source/blender/blenkernel/BKE_mesh_legacy_derived_mesh.hh +++ /dev/null @@ -1,214 +0,0 @@ -/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved. - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#pragma once - -/** \file - * \ingroup bke - * - * Basic design of the DerivedMesh system: - * - * #DerivedMesh is a common set of interfaces for mesh systems. - * - * There are three main mesh data structures in Blender: - * #Mesh, #CDDerivedMesh and #BMesh. - * - * These, and a few others, all implement #DerivedMesh interfaces, - * which contains unified drawing interfaces, a few utility interfaces, - * and a bunch of read-only interfaces intended mostly for conversion from - * one format to another. - * - * All Mesh structures in blender make use of #CustomData, which is used to store - * per-element attributes and interpolate them (e.g. UVs, vertex-colors, vertex-groups, etc). - * - * Mesh is the "serialized" structure, used for storing object-mode mesh data - * and also for saving stuff to disk. Its interfaces are also what #DerivedMesh - * uses to communicate with. - * - * #CDDM is a little mesh library, that uses Mesh data structures in the backend. - * It's mostly used for modifiers, and has the advantages of not taking much - * resources. - * - * #BMesh is a full-on BREP, used for edit-mode, some modifiers, etc. - * It's much more capable (if memory-intensive) then CDDM. - * - * #DerivedMesh is somewhat hackish. Many places assumes that a #DerivedMesh is - * a CDDM (most of the time by simply copying it and converting it to one). - * CDDM is the original structure for modifiers, but has since been superseded - * by #BMesh, at least for the foreseeable future. - */ - -/* - * NOTE: This structure is read-only, for all practical purposes. - * At some point in the future, we may want to consider - * creating a replacement structure that implements a proper - * abstract mesh kernel interface. Or, we can leave this - * as it is and stick with using BMesh and CDDM. - */ - -#include "BLI_math_vector_types.hh" - -#include "DNA_customdata_types.h" - -struct CCGElem; -struct CCGKey; -struct CustomData_MeshMasks; -struct Mesh; - -enum DerivedMeshType { - DM_TYPE_CDDM, - DM_TYPE_CCGDM, -}; - -struct DerivedMesh { - /** Private DerivedMesh data, only for internal DerivedMesh use */ - CustomData vertData, edgeData, faceData, loopData, polyData; - int numVertData, numEdgeData, numTessFaceData, numLoopData, numPolyData; - DerivedMeshType type; - /* Always owned by this object. */ - int *face_offsets; - - /* Misc. Queries */ - - /* Also called in Editmode */ - int (*getNumVerts)(DerivedMesh *dm); - int (*getNumEdges)(DerivedMesh *dm); - int (*getNumLoops)(DerivedMesh *dm); - int (*getNumPolys)(DerivedMesh *dm); - - /** - * Return a pointer to the entire array of verts/edges/face from the - * derived mesh. if such an array does not exist yet, it will be created, - * and freed on the next ->release(). consider using getVert/Edge/Face if - * you are only interested in a few verts/edges/faces. - */ - /** - * \warning The real return type is `float(*)[3]`. - */ - float *(*getVertArray)(DerivedMesh *dm); - blender::int2 *(*getEdgeArray)(DerivedMesh *dm); - int *(*getCornerVertArray)(DerivedMesh *dm); - int *(*getCornerEdgeArray)(DerivedMesh *dm); - int *(*getPolyArray)(DerivedMesh *dm); - - /** - * Copy all verts/edges/faces from the derived mesh into - * `*{vert/edge/face}_r` (must point to a buffer large enough). - */ - void (*copyVertArray)(DerivedMesh *dm, float (*r_positions)[3]); - void (*copyEdgeArray)(DerivedMesh *dm, blender::int2 *r_edge); - void (*copyCornerVertArray)(DerivedMesh *dm, int *r_corner_verts); - void (*copyCornerEdgeArray)(DerivedMesh *dm, int *r_corner_edges); - void (*copyPolyArray)(DerivedMesh *dm, int *r_face_offsets); - - /** - * Return a pointer to the entire array of vert/edge/face custom data - * from the derived mesh (this gives a pointer to the actual data, not a copy). - */ - void *(*getVertDataArray)(DerivedMesh *dm, eCustomDataType type); - void *(*getEdgeDataArray)(DerivedMesh *dm, eCustomDataType type); - void *(*getLoopDataArray)(DerivedMesh *dm, eCustomDataType type); - void *(*getPolyDataArray)(DerivedMesh *dm, eCustomDataType type); - - /** Optional grid access for subsurf */ - int (*getNumGrids)(DerivedMesh *dm); - int (*getGridSize)(DerivedMesh *dm); - CCGElem **(*getGridData)(DerivedMesh *dm); - int *(*getGridOffset)(DerivedMesh *dm); - void (*getGridKey)(DerivedMesh *dm, CCGKey *key); - - /* Direct Access Operations - * - Can be undefined - * - Must be defined for modifiers that only deform however. */ - - /** - * Release reference to the DerivedMesh. This function decides internally - * if the DerivedMesh will be freed, or cached for later use. - */ - void (*release)(DerivedMesh *dm); -}; - -/** - * Utility function to initialize a #DerivedMesh's function pointers to - * the default implementation (for those functions which have a default). - */ -void DM_init_funcs(DerivedMesh *dm); - -/** - * Utility function to initialize a #DerivedMesh for the desired number - * of vertices, edges and faces (doesn't allocate memory for them, just - * sets up the custom data layers)> - */ -void DM_init(DerivedMesh *dm, - DerivedMeshType type, - int numVerts, - int numEdges, - int numTessFaces, - int numLoops, - int numPolys); - -/** - * Utility function to initialize a DerivedMesh for the desired number - * of vertices, edges and faces, with a layer setup copied from source - */ -void DM_from_template(DerivedMesh *dm, - DerivedMesh *source, - DerivedMeshType type, - int numVerts, - int numEdges, - int numTessFaces, - int numLoops, - int numPolys); - -void DM_release(DerivedMesh *dm); - -/** - * set the #CD_FLAG_NOCOPY flag in custom data layers where the mask is - * zero for the layer type, so only layer types specified by the mask - * will be copied - */ -void DM_set_only_copy(DerivedMesh *dm, const CustomData_MeshMasks *mask); - -/** - * Creates a CDDerivedMesh from the given Mesh, this will reference the - * original data in Mesh, but it is safe to apply vertex coordinates or - * calculate normals as those functions will automatically create new - * data to not overwrite the original. - */ -DerivedMesh *CDDM_from_mesh(Mesh *mesh); - -/* -------------------------------------------------------------------- */ -/** \name Custom Data Layer Access Functions - * - * \return pointer to first data layer which matches type (a flat array) - * if they return NULL, data doesn't exist. - * \note these return pointers - any change modifies the internals of the mesh. - * \{ */ - -void *DM_get_vert_data_layer(DerivedMesh *dm, eCustomDataType type); -void *DM_get_edge_data_layer(DerivedMesh *dm, eCustomDataType type); -void *DM_get_poly_data_layer(DerivedMesh *dm, eCustomDataType type); -void *DM_get_loop_data_layer(DerivedMesh *dm, eCustomDataType type); - -/** \} */ - -/** - * Custom data copy functions - * copy count elements from source_index in source to dest_index in dest - * these copy all layers for which the CD_FLAG_NOCOPY flag is not set. - */ -void DM_copy_vert_data( - const DerivedMesh *source, DerivedMesh *dest, int source_index, int dest_index, int count); - -/** - * Interpolates vertex data from the vertices indexed by `src_indices` in the - * source mesh using the given weights and stores the result in the vertex - * indexed by `dest_index` in the `dest` mesh. - */ -void DM_interp_vert_data(const DerivedMesh *source, - DerivedMesh *dest, - int *src_indices, - float *weights, - int count, - int dest_index); diff --git a/source/blender/blenkernel/BKE_multires.hh b/source/blender/blenkernel/BKE_multires.hh index f7d401e205f..ef41387f430 100644 --- a/source/blender/blenkernel/BKE_multires.hh +++ b/source/blender/blenkernel/BKE_multires.hh @@ -8,12 +8,11 @@ * \ingroup bke */ -#include "BKE_subsurf.hh" +#include "BLI_array.hh" #include "BLI_math_matrix_types.hh" #include "BLI_utildefines.h" struct Depsgraph; -struct DerivedMesh; struct MDisps; struct Mesh; struct ModifierData; @@ -26,6 +25,14 @@ struct Settings; struct ToMeshSettings; } // namespace blender::bke::subdiv +enum MultiresModifiedFlags { + /* indicates the grids have been sculpted on, so MDisps + * have to be updated */ + MULTIRES_COORDS_MODIFIED = 1, + /* indicates elements have been hidden or unhidden */ + MULTIRES_HIDDEN_MODIFIED = 2, +}; + /** * Delete mesh mdisps and grid paint masks. */ @@ -52,9 +59,6 @@ enum class MultiresFlags : uint8_t { }; ENUM_OPERATORS(MultiresFlags, MultiresFlags::IgnoreSimplify); -DerivedMesh *multires_make_derived_from_derived( - DerivedMesh *dm, MultiresModifierData *mmd, Scene *scene, Object *ob, MultiresFlags flags); - MultiresModifierData *find_multires_modifier_before(Scene *scene, ModifierData *lastmd); /** * used for applying scale on mdisps layer and syncing subdivide levels when joining objects. @@ -126,10 +130,6 @@ void multiresModifier_ensure_external_read(Mesh *mesh, const MultiresModifierDat /* Adapted from `sculptmode.c` */ void old_mdisps_bilinear(float out[3], float (*disps)[3], int st, float u, float v); -/** - * Find per-corner coordinate with given per-face UV coord. - */ -int mdisp_rot_face_to_crn(int face_size, int face_side, float u, float v, float *x, float *y); /* Reshaping, define in multires_reshape.cc */ /** diff --git a/source/blender/blenkernel/BKE_subdiv.hh b/source/blender/blenkernel/BKE_subdiv.hh index 72554e48730..5bd43f615a7 100644 --- a/source/blender/blenkernel/BKE_subdiv.hh +++ b/source/blender/blenkernel/BKE_subdiv.hh @@ -288,8 +288,8 @@ BLI_INLINE void grid_uv_to_ptex_face_uv(float grid_u, */ BLI_INLINE int grid_size_from_level(int level); -/* Simplified version of mdisp_rot_face_to_crn, only handles quad and - * works in normalized coordinates. +/* Find per-corner coordinate with given per-face UV coord. + * Only handles quad and works in normalized coordinates. * * NOTE: Output coordinates are in ptex coordinates. */ BLI_INLINE int rotate_quad_to_corner(float quad_u, diff --git a/source/blender/blenkernel/BKE_subdiv_ccg.hh b/source/blender/blenkernel/BKE_subdiv_ccg.hh index 79aad3418fc..4a332af35cb 100644 --- a/source/blender/blenkernel/BKE_subdiv_ccg.hh +++ b/source/blender/blenkernel/BKE_subdiv_ccg.hh @@ -176,12 +176,6 @@ struct SubdivCCG : blender::NonCopyable { bool hidden = false; } dirty; - /* Cached values, are not supposed to be accessed directly. */ - struct { - /* Indexed by face, indicates index of the first grid which corresponds to the face. */ - blender::Array start_face_grid_index; - } cache_; - ~SubdivCCG(); }; @@ -199,7 +193,7 @@ struct SubdivCCG : blender::NonCopyable { std::unique_ptr BKE_subdiv_to_ccg(blender::bke::subdiv::Subdiv &subdiv, const SubdivToCCGSettings &settings, const Mesh &coarse_mesh, - SubdivCCGMaskEvaluator *mask_evaluator); + SubdivCCGMaskEvaluator *mask_evaluator = nullptr); /* Helper function, creates Mesh structure which is properly setup to use * grids. @@ -278,8 +272,6 @@ inline int BKE_subdiv_ccg_grid_to_face_index(const SubdivCCG &subdiv_ccg, const return subdiv_ccg.grid_to_face_map[grid_index]; } -blender::float3 BKE_subdiv_ccg_eval_limit_point(const SubdivCCG &subdiv_ccg, - const SubdivCCGCoord &coord); void BKE_subdiv_ccg_eval_limit_positions(const SubdivCCG &subdiv_ccg, const CCGKey &key, int grid_index, @@ -309,15 +301,6 @@ bool BKE_subdiv_ccg_coord_is_mesh_boundary(blender::OffsetIndices faces, const SubdivCCG &subdiv_ccg, SubdivCCGCoord coord); -/* Get array which is indexed by face index and contains index of a first grid of the face. - * - * The "ensure" version allocates the mapping if it's not known yet and stores it in the subdiv_ccg - * descriptor. This function is NOT safe for threading. - * - * The "get" version simply returns cached array. */ -const int *BKE_subdiv_ccg_start_face_grid_index_ensure(SubdivCCG &subdiv_ccg); -const int *BKE_subdiv_ccg_start_face_grid_index_get(const SubdivCCG &subdiv_ccg); - blender::BitGroupVector<> &BKE_subdiv_ccg_grid_hidden_ensure(SubdivCCG &subdiv_ccg); void BKE_subdiv_ccg_grid_hidden_free(SubdivCCG &subdiv_ccg); diff --git a/source/blender/blenkernel/BKE_subsurf.hh b/source/blender/blenkernel/BKE_subsurf.hh deleted file mode 100644 index 2916018e1ce..00000000000 --- a/source/blender/blenkernel/BKE_subsurf.hh +++ /dev/null @@ -1,121 +0,0 @@ -/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved. - * - * SPDX-License-Identifier: GPL-2.0-or-later */ -#pragma once - -/** \file - * \ingroup bke - */ - -/* struct DerivedMesh is used directly */ -#include "BKE_mesh_legacy_derived_mesh.hh" - -/* Thread sync primitives used directly. */ -#include "BLI_ordered_edge.hh" -#include "BLI_threads.h" -#include "BLI_utildefines.h" -#include "BLI_vector_set.hh" - -struct CCGEdge; -struct CCGElem; -struct CCGFace; -struct CCGSubSurf; -struct CCGVert; -struct DerivedMesh; -struct Mesh; -struct MultiresModifierData; -struct Object; -struct Scene; - -namespace blender::bke::pbvh { -class Tree; -} -struct SubsurfModifierData; - -/**************************** External *****************************/ - -enum SubsurfFlags { - SUBSURF_USE_RENDER_PARAMS = 1, - SUBSURF_IS_FINAL_CALC = 2, - SUBSURF_FOR_EDIT_MODE = 4, - SUBSURF_IN_EDIT_MODE = 8, - SUBSURF_ALLOC_PAINT_MASK = 16, - SUBSURF_USE_GPU_BACKEND = 32, - SUBSURF_IGNORE_SIMPLIFY = 64, -}; -ENUM_OPERATORS(SubsurfFlags, SUBSURF_IGNORE_SIMPLIFY); - -DerivedMesh *subsurf_make_derived_from_derived(DerivedMesh *dm, - SubsurfModifierData *smd, - const Scene *scene, - float (*vertCos)[3], - SubsurfFlags flags); - -void subsurf_calculate_limit_positions(Mesh *mesh, float (*r_positions)[3]); - -/** - * Get grid-size from 'level', level must be greater than zero. - */ -int BKE_ccg_gridsize(int level); - -/** - * X/Y grid coordinates at 'low_level' can be multiplied by the result - * of this function to convert to grid coordinates at 'high_level'. - */ -int BKE_ccg_factor(int low_level, int high_level); - -enum MultiresModifiedFlags { - /* indicates the grids have been sculpted on, so MDisps - * have to be updated */ - MULTIRES_COORDS_MODIFIED = 1, - /* indicates elements have been hidden or unhidden */ - MULTIRES_HIDDEN_MODIFIED = 2, -}; - -/**************************** Internal *****************************/ - -struct CCGDerivedMesh { - DerivedMesh dm; - - CCGSubSurf *ss; - int freeSS; - int drawInteriorEdges, useSubsurfUv; - - struct { - int startVert; - CCGVert *vert; - } *vertMap; - struct { - int startVert; - int startEdge; - CCGEdge *edge; - } *edgeMap; - struct { - int startVert; - int startEdge; - int startFace; - CCGFace *face; - } *faceMap; - - CCGElem **gridData; - int *gridOffset; - CCGFace **gridFaces; - unsigned int **gridHidden; - /* Elements in arrays above. */ - unsigned int numGrid; - - struct { - MultiresModifierData *mmd; - int local_mmd; - - int lvl, totlvl; - float (*orco)[3]; - - Object *ob; - } multires; - - blender::VectorSet *ehash; - - ThreadMutex loops_cache_lock; - ThreadRWMutex origindex_cache_rwlock; -}; diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 7d73e8f4c61..f4581d99a49 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -34,9 +34,6 @@ set(INC_SYS set(SRC ${CMAKE_SOURCE_DIR}/release/datafiles/userdef/userdef_default.c - intern/CCGSubSurf.cc - intern/CCGSubSurf_legacy.cc - intern/CCGSubSurf_util.cc intern/action.cc intern/action_bones.cc intern/action_mirror.cc @@ -205,7 +202,6 @@ set(SRC intern/mesh_flip_faces.cc intern/mesh_iterators.cc intern/mesh_legacy_convert.cc - intern/mesh_legacy_derived_mesh.cc intern/mesh_mapping.cc intern/mesh_merge_customdata.cc intern/mesh_mirror.cc @@ -295,7 +291,6 @@ set(SRC intern/subdiv_modifier.cc intern/subdiv_stats.cc intern/subdiv_topology.cc - intern/subsurf_ccg.cc intern/text.cc intern/text_suggestions.cc intern/texture.cc @@ -461,7 +456,6 @@ set(SRC BKE_mesh_fair.hh BKE_mesh_iterators.hh BKE_mesh_legacy_convert.hh - BKE_mesh_legacy_derived_mesh.hh BKE_mesh_mapping.hh BKE_mesh_mirror.hh BKE_mesh_remap.hh @@ -523,7 +517,6 @@ set(SRC BKE_subdiv_mesh.hh BKE_subdiv_modifier.hh BKE_subdiv_topology.hh - BKE_subsurf.hh BKE_text.h BKE_text_suggestions.h BKE_texture.h @@ -553,9 +546,6 @@ set(SRC particle_private.h tracking_private.h - intern/CCGSubSurf.h - intern/CCGSubSurf_inline.h - intern/CCGSubSurf_intern.h intern/attribute_access_intern.hh intern/attribute_storage_access.hh intern/data_transfer_intern.hh diff --git a/source/blender/blenkernel/intern/CCGSubSurf.cc b/source/blender/blenkernel/intern/CCGSubSurf.cc deleted file mode 100644 index 4c8111225b0..00000000000 --- a/source/blender/blenkernel/intern/CCGSubSurf.cc +++ /dev/null @@ -1,1574 +0,0 @@ -/* SPDX-FileCopyrightText: 2023 Blender Authors - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -/** \file - * \ingroup bke - */ - -#include -#include - -#include "MEM_guardedalloc.h" - -#include "BLI_utildefines.h" /* for BLI_assert */ - -#include "BKE_ccg.hh" -#include "BKE_subsurf.hh" -#include "CCGSubSurf.h" -#include "CCGSubSurf_inline.h" -#include "CCGSubSurf_intern.h" - -/***/ - -int BKE_ccg_gridsize(int level) -{ - return ccg_gridsize(level); -} - -int BKE_ccg_factor(int low_level, int high_level) -{ - BLI_assert(low_level > 0 && high_level > 0); - BLI_assert(low_level <= high_level); - - return 1 << (high_level - low_level); -} - -/***/ - -static CCGVert *_vert_new(CCGVertHDL vHDL, CCGSubSurf *ss) -{ - int num_vert_data = ss->subdivLevels + 1; - CCGVert *v = static_cast(CCGSUBSURF_alloc( - ss, sizeof(CCGVert) + ss->meshIFC.vertDataSize * num_vert_data + ss->meshIFC.vertUserSize)); - uint8_t *user_data; - - v->vHDL = vHDL; - v->edges = nullptr; - v->faces = nullptr; - v->numEdges = v->numFaces = 0; - v->flags = 0; - - user_data = static_cast(ccgSubSurf_getVertUserData(ss, v)); - memset(user_data, 0, ss->meshIFC.vertUserSize); - if (ss->useAgeCounts) { - *((int *)&user_data[ss->vertUserAgeOffset]) = ss->currentAge; - } - - return v; -} -static void _vert_remEdge(CCGVert *v, CCGEdge *e) -{ - for (int i = 0; i < v->numEdges; i++) { - if (v->edges[i] == e) { - v->edges[i] = v->edges[--v->numEdges]; - break; - } - } -} -static void _vert_remFace(CCGVert *v, CCGFace *f) -{ - for (int i = 0; i < v->numFaces; i++) { - if (v->faces[i] == f) { - v->faces[i] = v->faces[--v->numFaces]; - break; - } - } -} -static void _vert_addEdge(CCGVert *v, CCGEdge *e, CCGSubSurf *ss) -{ - v->edges = static_cast(CCGSUBSURF_realloc( - ss, v->edges, (v->numEdges + 1) * sizeof(*v->edges), v->numEdges * sizeof(*v->edges))); - v->edges[v->numEdges++] = e; -} -static void _vert_addFace(CCGVert *v, CCGFace *f, CCGSubSurf *ss) -{ - v->faces = static_cast(CCGSUBSURF_realloc( - ss, v->faces, (v->numFaces + 1) * sizeof(*v->faces), v->numFaces * sizeof(*v->faces))); - v->faces[v->numFaces++] = f; -} -static CCGEdge *_vert_findEdgeTo(const CCGVert *v, const CCGVert *vQ) -{ - for (int i = 0; i < v->numEdges; i++) { - CCGEdge *e = v->edges[v->numEdges - 1 - i]; /* XXX, note reverse. */ - if ((e->v0 == v && e->v1 == vQ) || (e->v1 == v && e->v0 == vQ)) { - return e; - } - } - return nullptr; -} -static void _vert_free(CCGVert *v, CCGSubSurf *ss) -{ - if (v->edges) { - CCGSUBSURF_free(ss, v->edges); - } - - if (v->faces) { - CCGSUBSURF_free(ss, v->faces); - } - - CCGSUBSURF_free(ss, v); -} - -/***/ - -static CCGEdge *_edge_new(CCGEdgeHDL eHDL, CCGVert *v0, CCGVert *v1, float crease, CCGSubSurf *ss) -{ - int num_edge_data = ccg_edgebase(ss->subdivLevels + 1); - CCGEdge *e = static_cast(CCGSUBSURF_alloc( - ss, sizeof(CCGEdge) + ss->meshIFC.vertDataSize * num_edge_data + ss->meshIFC.edgeUserSize)); - uint8_t *user_data; - - e->eHDL = eHDL; - e->v0 = v0; - e->v1 = v1; - e->crease = crease; - e->faces = nullptr; - e->numFaces = 0; - e->flags = 0; - _vert_addEdge(v0, e, ss); - _vert_addEdge(v1, e, ss); - - user_data = static_cast(ccgSubSurf_getEdgeUserData(ss, e)); - memset(user_data, 0, ss->meshIFC.edgeUserSize); - if (ss->useAgeCounts) { - *((int *)&user_data[ss->edgeUserAgeOffset]) = ss->currentAge; - } - - return e; -} -static void _edge_remFace(CCGEdge *e, CCGFace *f) -{ - for (int i = 0; i < e->numFaces; i++) { - if (e->faces[i] == f) { - e->faces[i] = e->faces[--e->numFaces]; - break; - } - } -} -static void _edge_addFace(CCGEdge *e, CCGFace *f, CCGSubSurf *ss) -{ - e->faces = static_cast(CCGSUBSURF_realloc( - ss, e->faces, (e->numFaces + 1) * sizeof(*e->faces), e->numFaces * sizeof(*e->faces))); - e->faces[e->numFaces++] = f; -} -static void *_edge_getCoVert(CCGEdge *e, CCGVert *v, int lvl, int x, int dataSize) -{ - int levelBase = ccg_edgebase(lvl); - if (v == e->v0) { - return &EDGE_getLevelData(e)[dataSize * (levelBase + x)]; - } - return &EDGE_getLevelData(e)[dataSize * (levelBase + (1 << lvl) - x)]; -} - -static void _edge_free(CCGEdge *e, CCGSubSurf *ss) -{ - if (e->faces) { - CCGSUBSURF_free(ss, e->faces); - } - - CCGSUBSURF_free(ss, e); -} -static void _edge_unlinkMarkAndFree(CCGEdge *e, CCGSubSurf *ss) -{ - _vert_remEdge(e->v0, e); - _vert_remEdge(e->v1, e); - e->v0->flags |= Vert_eEffected; - e->v1->flags |= Vert_eEffected; - _edge_free(e, ss); -} - -static CCGFace *_face_new( - CCGFaceHDL fHDL, CCGVert **verts, CCGEdge **edges, int numVerts, CCGSubSurf *ss) -{ - int maxGridSize = ccg_gridsize(ss->subdivLevels); - int num_face_data = (numVerts * maxGridSize + numVerts * maxGridSize * maxGridSize + 1); - CCGFace *f = static_cast(CCGSUBSURF_alloc( - ss, - sizeof(CCGFace) + sizeof(CCGVert *) * numVerts + sizeof(CCGEdge *) * numVerts + - ss->meshIFC.vertDataSize * num_face_data + ss->meshIFC.faceUserSize)); - uint8_t *user_data; - - f->numVerts = numVerts; - BLI_assert(numVerts > 2); - f->fHDL = fHDL; - f->flags = 0; - - for (int i = 0; i < numVerts; i++) { - FACE_getVerts(f)[i] = verts[i]; - FACE_getEdges(f)[i] = edges[i]; - _vert_addFace(verts[i], f, ss); - _edge_addFace(edges[i], f, ss); - } - - user_data = static_cast(ccgSubSurf_getFaceUserData(ss, f)); - memset(user_data, 0, ss->meshIFC.faceUserSize); - if (ss->useAgeCounts) { - *((int *)&user_data[ss->faceUserAgeOffset]) = ss->currentAge; - } - - return f; -} -static void _face_free(CCGFace *f, CCGSubSurf *ss) -{ - CCGSUBSURF_free(ss, f); -} -static void _face_unlinkMarkAndFree(CCGFace *f, CCGSubSurf *ss) -{ - int j; - for (j = 0; j < f->numVerts; j++) { - _vert_remFace(FACE_getVerts(f)[j], f); - _edge_remFace(FACE_getEdges(f)[j], f); - FACE_getVerts(f)[j]->flags |= Vert_eEffected; - } - _face_free(f, ss); -} - -/***/ - -CCGSubSurf *ccgSubSurf_new(CCGMeshIFC *ifc, - int subdivLevels, - CCGAllocatorIFC *allocatorIFC, - CCGAllocatorHDL allocator) -{ - if (!allocatorIFC) { - allocatorIFC = ccg_getStandardAllocatorIFC(); - allocator = nullptr; - } - - if (subdivLevels < 1) { - return nullptr; - } - - CCGSubSurf *ss = static_cast(allocatorIFC->alloc(allocator, sizeof(*ss))); - - ss->allocatorIFC = *allocatorIFC; - ss->allocator = allocator; - - ss->vMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator); - ss->eMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator); - ss->fMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator); - - ss->meshIFC = *ifc; - - ss->subdivLevels = subdivLevels; - ss->numGrids = 0; - ss->allowEdgeCreation = 0; - ss->defaultCreaseValue = 0; - ss->defaultEdgeUserData = nullptr; - - ss->useAgeCounts = 0; - ss->vertUserAgeOffset = ss->edgeUserAgeOffset = ss->faceUserAgeOffset = 0; - - ss->calcVertNormals = 0; - ss->normalDataOffset = 0; - - ss->allocMask = 0; - - ss->q = CCGSUBSURF_alloc(ss, ss->meshIFC.vertDataSize); - ss->r = CCGSUBSURF_alloc(ss, ss->meshIFC.vertDataSize); - - ss->currentAge = 0; - - ss->syncState = eSyncState_None; - - ss->oldVMap = ss->oldEMap = ss->oldFMap = nullptr; - ss->lenTempArrays = 0; - ss->tempVerts = nullptr; - ss->tempEdges = nullptr; - - return ss; -} - -void ccgSubSurf_free(CCGSubSurf *ss) -{ - CCGAllocatorIFC allocatorIFC = ss->allocatorIFC; - CCGAllocatorHDL allocator = ss->allocator; - - if (ss->syncState) { - ccg_ehash_free(ss->oldFMap, (EHEntryFreeFP)_face_free, ss); - ccg_ehash_free(ss->oldEMap, (EHEntryFreeFP)_edge_free, ss); - ccg_ehash_free(ss->oldVMap, (EHEntryFreeFP)_vert_free, ss); - - MEM_freeN(ss->tempVerts); - MEM_freeN(ss->tempEdges); - } - - CCGSUBSURF_free(ss, ss->r); - CCGSUBSURF_free(ss, ss->q); - if (ss->defaultEdgeUserData) { - CCGSUBSURF_free(ss, ss->defaultEdgeUserData); - } - - ccg_ehash_free(ss->fMap, (EHEntryFreeFP)_face_free, ss); - ccg_ehash_free(ss->eMap, (EHEntryFreeFP)_edge_free, ss); - ccg_ehash_free(ss->vMap, (EHEntryFreeFP)_vert_free, ss); - - CCGSUBSURF_free(ss, ss); - - if (allocatorIFC.release) { - allocatorIFC.release(allocator); - } -} - -CCGError ccgSubSurf_setAllowEdgeCreation(CCGSubSurf *ss, - int allowEdgeCreation, - float defaultCreaseValue, - void *defaultUserData) -{ - if (ss->defaultEdgeUserData) { - CCGSUBSURF_free(ss, ss->defaultEdgeUserData); - } - - ss->allowEdgeCreation = !!allowEdgeCreation; - ss->defaultCreaseValue = defaultCreaseValue; - ss->defaultEdgeUserData = CCGSUBSURF_alloc(ss, ss->meshIFC.edgeUserSize); - - if (defaultUserData) { - memcpy(ss->defaultEdgeUserData, defaultUserData, ss->meshIFC.edgeUserSize); - } - else { - memset(ss->defaultEdgeUserData, 0, ss->meshIFC.edgeUserSize); - } - - return eCCGError_None; -} -void ccgSubSurf_getAllowEdgeCreation(CCGSubSurf *ss, - int *allowEdgeCreation_r, - float *defaultCreaseValue_r, - void *defaultUserData_r) -{ - if (allowEdgeCreation_r) { - *allowEdgeCreation_r = ss->allowEdgeCreation; - } - if (ss->allowEdgeCreation) { - if (defaultCreaseValue_r) { - *defaultCreaseValue_r = ss->defaultCreaseValue; - } - if (defaultUserData_r) { - memcpy(defaultUserData_r, ss->defaultEdgeUserData, ss->meshIFC.edgeUserSize); - } - } -} - -CCGError ccgSubSurf_setSubdivisionLevels(CCGSubSurf *ss, int subdivisionLevels) -{ - if (subdivisionLevels <= 0) { - return eCCGError_InvalidValue; - } - if (subdivisionLevels != ss->subdivLevels) { - ss->numGrids = 0; - ss->subdivLevels = subdivisionLevels; - ccg_ehash_free(ss->vMap, (EHEntryFreeFP)_vert_free, ss); - ccg_ehash_free(ss->eMap, (EHEntryFreeFP)_edge_free, ss); - ccg_ehash_free(ss->fMap, (EHEntryFreeFP)_face_free, ss); - ss->vMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator); - ss->eMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator); - ss->fMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator); - } - - return eCCGError_None; -} - -void ccgSubSurf_getUseAgeCounts(CCGSubSurf *ss, - int *useAgeCounts_r, - int *vertUserOffset_r, - int *edgeUserOffset_r, - int *faceUserOffset_r) -{ - *useAgeCounts_r = ss->useAgeCounts; - - if (vertUserOffset_r) { - *vertUserOffset_r = ss->vertUserAgeOffset; - } - if (edgeUserOffset_r) { - *edgeUserOffset_r = ss->edgeUserAgeOffset; - } - if (faceUserOffset_r) { - *faceUserOffset_r = ss->faceUserAgeOffset; - } -} - -CCGError ccgSubSurf_setUseAgeCounts( - CCGSubSurf *ss, int useAgeCounts, int vertUserOffset, int edgeUserOffset, int faceUserOffset) -{ - if (useAgeCounts) { - if ((vertUserOffset + 4 > ss->meshIFC.vertUserSize) || - (edgeUserOffset + 4 > ss->meshIFC.edgeUserSize) || - (faceUserOffset + 4 > ss->meshIFC.faceUserSize)) - { - return eCCGError_InvalidValue; - } - ss->useAgeCounts = 1; - ss->vertUserAgeOffset = vertUserOffset; - ss->edgeUserAgeOffset = edgeUserOffset; - ss->faceUserAgeOffset = faceUserOffset; - } - else { - ss->useAgeCounts = 0; - ss->vertUserAgeOffset = ss->edgeUserAgeOffset = ss->faceUserAgeOffset = 0; - } - - return eCCGError_None; -} - -CCGError ccgSubSurf_setCalcVertexNormals(CCGSubSurf *ss, int useVertNormals, int normalDataOffset) -{ - if (useVertNormals) { - if (normalDataOffset < 0 || normalDataOffset + 12 > ss->meshIFC.vertDataSize) { - return eCCGError_InvalidValue; - } - ss->calcVertNormals = 1; - ss->normalDataOffset = normalDataOffset; - } - else { - ss->calcVertNormals = 0; - ss->normalDataOffset = 0; - } - - return eCCGError_None; -} - -void ccgSubSurf_setAllocMask(CCGSubSurf *ss, int allocMask, int maskOffset) -{ - ss->allocMask = allocMask; - ss->maskDataOffset = maskOffset; -} - -void ccgSubSurf_setNumLayers(CCGSubSurf *ss, int numLayers) -{ - ss->meshIFC.numLayers = numLayers; -} - -/***/ - -CCGError ccgSubSurf_initFullSync(CCGSubSurf *ss) -{ - if (ss->syncState != eSyncState_None) { - return eCCGError_InvalidSyncState; - } - - ss->currentAge++; - - ss->oldVMap = ss->vMap; - ss->oldEMap = ss->eMap; - ss->oldFMap = ss->fMap; - - ss->vMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator); - ss->eMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator); - ss->fMap = ccg_ehash_new(0, &ss->allocatorIFC, ss->allocator); - - ss->numGrids = 0; - - ss->lenTempArrays = 12; - ss->tempVerts = MEM_malloc_arrayN(size_t(ss->lenTempArrays), "CCGSubsurf tempVerts"); - ss->tempEdges = MEM_malloc_arrayN(size_t(ss->lenTempArrays), "CCGSubsurf tempEdges"); - - ss->syncState = eSyncState_Vert; - - return eCCGError_None; -} - -CCGError ccgSubSurf_initPartialSync(CCGSubSurf *ss) -{ - if (ss->syncState != eSyncState_None) { - return eCCGError_InvalidSyncState; - } - - ss->currentAge++; - - ss->syncState = eSyncState_Partial; - - return eCCGError_None; -} - -CCGError ccgSubSurf_syncVertDel(CCGSubSurf *ss, CCGVertHDL vHDL) -{ - if (ss->syncState != eSyncState_Partial) { - return eCCGError_InvalidSyncState; - } - - void **prevp; - CCGVert *v = static_cast(ccg_ehash_lookupWithPrev(ss->vMap, vHDL, &prevp)); - - if (!v || v->numFaces || v->numEdges) { - return eCCGError_InvalidValue; - } - - *prevp = v->next; - _vert_free(v, ss); - - return eCCGError_None; -} - -CCGError ccgSubSurf_syncEdgeDel(CCGSubSurf *ss, CCGEdgeHDL eHDL) -{ - if (ss->syncState != eSyncState_Partial) { - return eCCGError_InvalidSyncState; - } - - void **prevp; - CCGEdge *e = static_cast(ccg_ehash_lookupWithPrev(ss->eMap, eHDL, &prevp)); - - if (!e || e->numFaces) { - return eCCGError_InvalidValue; - } - - *prevp = e->next; - _edge_unlinkMarkAndFree(e, ss); - - return eCCGError_None; -} - -CCGError ccgSubSurf_syncFaceDel(CCGSubSurf *ss, CCGFaceHDL fHDL) -{ - if (ss->syncState != eSyncState_Partial) { - return eCCGError_InvalidSyncState; - } - - void **prevp; - CCGFace *f = static_cast(ccg_ehash_lookupWithPrev(ss->fMap, fHDL, &prevp)); - - if (!f) { - return eCCGError_InvalidValue; - } - - *prevp = f->next; - _face_unlinkMarkAndFree(f, ss); - - return eCCGError_None; -} - -CCGError ccgSubSurf_syncVert( - CCGSubSurf *ss, CCGVertHDL vHDL, const void *vertData, int seam, CCGVert **v_r) -{ - void **prevp; - CCGVert *v = nullptr; - short seamflag = (seam) ? Vert_eSeam : 0; - - if (ss->syncState == eSyncState_Partial) { - v = static_cast(ccg_ehash_lookupWithPrev(ss->vMap, vHDL, &prevp)); - if (!v) { - v = _vert_new(vHDL, ss); - VertDataCopy(static_cast(ccg_vert_getCo(v, 0, ss->meshIFC.vertDataSize)), - static_cast(vertData), - ss); - ccg_ehash_insert(ss->vMap, (EHEntry *)v); - v->flags = Vert_eEffected | seamflag; - } - else if (!VertDataEqual( - static_cast(vertData), - static_cast(ccg_vert_getCo(v, 0, ss->meshIFC.vertDataSize)), - ss) || - ((v->flags & Vert_eSeam) != seamflag)) - { - int i, j; - - VertDataCopy(static_cast(ccg_vert_getCo(v, 0, ss->meshIFC.vertDataSize)), - static_cast(vertData), - ss); - v->flags = Vert_eEffected | seamflag; - - for (i = 0; i < v->numEdges; i++) { - CCGEdge *e = v->edges[i]; - e->v0->flags |= Vert_eEffected; - e->v1->flags |= Vert_eEffected; - } - for (i = 0; i < v->numFaces; i++) { - CCGFace *f = v->faces[i]; - for (j = 0; j < f->numVerts; j++) { - FACE_getVerts(f)[j]->flags |= Vert_eEffected; - } - } - } - } - else { - if (ss->syncState != eSyncState_Vert) { - return eCCGError_InvalidSyncState; - } - - v = static_cast(ccg_ehash_lookupWithPrev(ss->oldVMap, vHDL, &prevp)); - if (!v) { - v = _vert_new(vHDL, ss); - VertDataCopy(static_cast(ccg_vert_getCo(v, 0, ss->meshIFC.vertDataSize)), - static_cast(vertData), - ss); - ccg_ehash_insert(ss->vMap, (EHEntry *)v); - v->flags = Vert_eEffected | seamflag; - } - else if (!VertDataEqual( - static_cast(vertData), - static_cast(ccg_vert_getCo(v, 0, ss->meshIFC.vertDataSize)), - ss) || - ((v->flags & Vert_eSeam) != seamflag)) - { - *prevp = v->next; - ccg_ehash_insert(ss->vMap, (EHEntry *)v); - VertDataCopy(static_cast(ccg_vert_getCo(v, 0, ss->meshIFC.vertDataSize)), - static_cast(vertData), - ss); - v->flags = Vert_eEffected | Vert_eChanged | seamflag; - } - else { - *prevp = v->next; - ccg_ehash_insert(ss->vMap, (EHEntry *)v); - v->flags = 0; - } - } - - if (v_r) { - *v_r = v; - } - return eCCGError_None; -} - -CCGError ccgSubSurf_syncEdge(CCGSubSurf *ss, - CCGEdgeHDL eHDL, - CCGVertHDL e_vHDL0, - CCGVertHDL e_vHDL1, - float crease, - CCGEdge **e_r) -{ - void **prevp; - CCGEdge *e = nullptr, *eNew; - - if (ss->syncState == eSyncState_Partial) { - e = static_cast(ccg_ehash_lookupWithPrev(ss->eMap, eHDL, &prevp)); - if (!e || e->v0->vHDL != e_vHDL0 || e->v1->vHDL != e_vHDL1 || crease != e->crease) { - CCGVert *v0 = static_cast(ccg_ehash_lookup(ss->vMap, e_vHDL0)); - CCGVert *v1 = static_cast(ccg_ehash_lookup(ss->vMap, e_vHDL1)); - - eNew = _edge_new(eHDL, v0, v1, crease, ss); - - if (e) { - *prevp = eNew; - eNew->next = e->next; - - _edge_unlinkMarkAndFree(e, ss); - } - else { - ccg_ehash_insert(ss->eMap, (EHEntry *)eNew); - } - - eNew->v0->flags |= Vert_eEffected; - eNew->v1->flags |= Vert_eEffected; - } - } - else { - if (ss->syncState == eSyncState_Vert) { - ss->syncState = eSyncState_Edge; - } - else if (ss->syncState != eSyncState_Edge) { - return eCCGError_InvalidSyncState; - } - - e = static_cast(ccg_ehash_lookupWithPrev(ss->oldEMap, eHDL, &prevp)); - if (!e || e->v0->vHDL != e_vHDL0 || e->v1->vHDL != e_vHDL1 || e->crease != crease) { - CCGVert *v0 = static_cast(ccg_ehash_lookup(ss->vMap, e_vHDL0)); - CCGVert *v1 = static_cast(ccg_ehash_lookup(ss->vMap, e_vHDL1)); - e = _edge_new(eHDL, v0, v1, crease, ss); - ccg_ehash_insert(ss->eMap, (EHEntry *)e); - e->v0->flags |= Vert_eEffected; - e->v1->flags |= Vert_eEffected; - } - else { - *prevp = e->next; - ccg_ehash_insert(ss->eMap, (EHEntry *)e); - e->flags = 0; - if ((e->v0->flags | e->v1->flags) & Vert_eChanged) { - e->v0->flags |= Vert_eEffected; - e->v1->flags |= Vert_eEffected; - } - } - } - - if (e_r) { - *e_r = e; - } - return eCCGError_None; -} - -CCGError ccgSubSurf_syncFace( - CCGSubSurf *ss, CCGFaceHDL fHDL, int numVerts, CCGVertHDL *vHDLs, CCGFace **f_r) -{ - void **prevp; - CCGFace *f = nullptr, *fNew; - int j, k, topologyChanged = 0; - - if (UNLIKELY(numVerts > ss->lenTempArrays)) { - ss->lenTempArrays = (numVerts < ss->lenTempArrays * 2) ? ss->lenTempArrays * 2 : numVerts; - ss->tempVerts = static_cast( - MEM_reallocN(ss->tempVerts, sizeof(*ss->tempVerts) * ss->lenTempArrays)); - ss->tempEdges = static_cast( - MEM_reallocN(ss->tempEdges, sizeof(*ss->tempEdges) * ss->lenTempArrays)); - } - - if (ss->syncState == eSyncState_Partial) { - f = static_cast(ccg_ehash_lookupWithPrev(ss->fMap, fHDL, &prevp)); - - for (k = 0; k < numVerts; k++) { - ss->tempVerts[k] = static_cast(ccg_ehash_lookup(ss->vMap, vHDLs[k])); - } - for (k = 0; k < numVerts; k++) { - ss->tempEdges[k] = _vert_findEdgeTo(ss->tempVerts[k], ss->tempVerts[(k + 1) % numVerts]); - } - - if (f) { - if (f->numVerts != numVerts || - memcmp(FACE_getVerts(f), ss->tempVerts, sizeof(*ss->tempVerts) * numVerts) != 0 || - memcmp(FACE_getEdges(f), ss->tempEdges, sizeof(*ss->tempEdges) * numVerts) != 0) - { - topologyChanged = 1; - } - } - - if (!f || topologyChanged) { - fNew = _face_new(fHDL, ss->tempVerts, ss->tempEdges, numVerts, ss); - - if (f) { - ss->numGrids += numVerts - f->numVerts; - - *prevp = fNew; - fNew->next = f->next; - - _face_unlinkMarkAndFree(f, ss); - } - else { - ss->numGrids += numVerts; - ccg_ehash_insert(ss->fMap, (EHEntry *)fNew); - } - - for (k = 0; k < numVerts; k++) { - FACE_getVerts(fNew)[k]->flags |= Vert_eEffected; - } - } - } - else { - if (ELEM(ss->syncState, eSyncState_Vert, eSyncState_Edge)) { - ss->syncState = eSyncState_Face; - } - else if (ss->syncState != eSyncState_Face) { - return eCCGError_InvalidSyncState; - } - - f = static_cast(ccg_ehash_lookupWithPrev(ss->oldFMap, fHDL, &prevp)); - - for (k = 0; k < numVerts; k++) { - ss->tempVerts[k] = static_cast(ccg_ehash_lookup(ss->vMap, vHDLs[k])); - - if (!ss->tempVerts[k]) { - return eCCGError_InvalidValue; - } - } - for (k = 0; k < numVerts; k++) { - ss->tempEdges[k] = _vert_findEdgeTo(ss->tempVerts[k], ss->tempVerts[(k + 1) % numVerts]); - - if (!ss->tempEdges[k]) { - if (ss->allowEdgeCreation) { - CCGEdge *e = ss->tempEdges[k] = _edge_new((CCGEdgeHDL)-1, - ss->tempVerts[k], - ss->tempVerts[(k + 1) % numVerts], - ss->defaultCreaseValue, - ss); - ccg_ehash_insert(ss->eMap, (EHEntry *)e); - e->v0->flags |= Vert_eEffected; - e->v1->flags |= Vert_eEffected; - if (ss->meshIFC.edgeUserSize) { - memcpy(ccgSubSurf_getEdgeUserData(ss, e), - ss->defaultEdgeUserData, - ss->meshIFC.edgeUserSize); - } - } - else { - return eCCGError_InvalidValue; - } - } - } - - if (f) { - if (f->numVerts != numVerts || - memcmp(FACE_getVerts(f), ss->tempVerts, sizeof(*ss->tempVerts) * numVerts) != 0 || - memcmp(FACE_getEdges(f), ss->tempEdges, sizeof(*ss->tempEdges) * numVerts) != 0) - { - topologyChanged = 1; - } - } - - if (!f || topologyChanged) { - f = _face_new(fHDL, ss->tempVerts, ss->tempEdges, numVerts, ss); - ccg_ehash_insert(ss->fMap, (EHEntry *)f); - ss->numGrids += numVerts; - - for (k = 0; k < numVerts; k++) { - FACE_getVerts(f)[k]->flags |= Vert_eEffected; - } - } - else { - *prevp = f->next; - ccg_ehash_insert(ss->fMap, (EHEntry *)f); - f->flags = 0; - ss->numGrids += f->numVerts; - - for (j = 0; j < f->numVerts; j++) { - if (FACE_getVerts(f)[j]->flags & Vert_eChanged) { - for (k = 0; k < f->numVerts; k++) { - FACE_getVerts(f)[k]->flags |= Vert_eEffected; - } - break; - } - } - } - } - - if (f_r) { - *f_r = f; - } - return eCCGError_None; -} - -static void ccgSubSurf__sync(CCGSubSurf *ss) -{ - ccgSubSurf__sync_legacy(ss); -} - -CCGError ccgSubSurf_processSync(CCGSubSurf *ss) -{ - if (ss->syncState == eSyncState_Partial) { - ss->syncState = eSyncState_None; - - ccgSubSurf__sync(ss); - } - else if (ss->syncState) { - ccg_ehash_free(ss->oldFMap, (EHEntryFreeFP)_face_unlinkMarkAndFree, ss); - ccg_ehash_free(ss->oldEMap, (EHEntryFreeFP)_edge_unlinkMarkAndFree, ss); - ccg_ehash_free(ss->oldVMap, (EHEntryFreeFP)_vert_free, ss); - MEM_freeN(ss->tempEdges); - MEM_freeN(ss->tempVerts); - - ss->lenTempArrays = 0; - - ss->oldFMap = ss->oldEMap = ss->oldVMap = nullptr; - ss->tempVerts = nullptr; - ss->tempEdges = nullptr; - - ss->syncState = eSyncState_None; - - ccgSubSurf__sync(ss); - } - else { - return eCCGError_InvalidSyncState; - } - - return eCCGError_None; -} - -void ccgSubSurf__allFaces(CCGSubSurf *ss, CCGFace ***faces, int *numFaces, int *freeFaces) -{ - CCGFace **array; - int i, num; - - if (*faces == nullptr) { - array = MEM_malloc_arrayN(size_t(ss->fMap->numEntries), "CCGSubsurf allFaces"); - num = 0; - for (i = 0; i < ss->fMap->curSize; i++) { - CCGFace *f = (CCGFace *)ss->fMap->buckets[i]; - - for (; f; f = f->next) { - array[num++] = f; - } - } - - *faces = array; - *numFaces = num; - *freeFaces = 1; - } - else { - *freeFaces = 0; - } -} - -void ccgSubSurf__effectedFaceNeighbors(CCGSubSurf *ss, - CCGFace **faces, - int numFaces, - CCGVert ***verts, - int *numVerts, - CCGEdge ***edges, - int *numEdges) -{ - CCGVert **arrayV; - CCGEdge **arrayE; - int numV, numE, i, j; - - arrayV = MEM_malloc_arrayN(size_t(ss->vMap->numEntries), "CCGSubsurf arrayV"); - arrayE = MEM_malloc_arrayN(size_t(ss->eMap->numEntries), "CCGSubsurf arrayV"); - numV = numE = 0; - - for (i = 0; i < numFaces; i++) { - CCGFace *f = faces[i]; - f->flags |= Face_eEffected; - } - - for (i = 0; i < ss->vMap->curSize; i++) { - CCGVert *v = (CCGVert *)ss->vMap->buckets[i]; - - for (; v; v = v->next) { - for (j = 0; j < v->numFaces; j++) { - if (!(v->faces[j]->flags & Face_eEffected)) { - break; - } - } - - if (j == v->numFaces) { - arrayV[numV++] = v; - v->flags |= Vert_eEffected; - } - } - } - - for (i = 0; i < ss->eMap->curSize; i++) { - CCGEdge *e = (CCGEdge *)ss->eMap->buckets[i]; - - for (; e; e = e->next) { - for (j = 0; j < e->numFaces; j++) { - if (!(e->faces[j]->flags & Face_eEffected)) { - break; - } - } - - if (j == e->numFaces) { - e->flags |= Edge_eEffected; - arrayE[numE++] = e; - } - } - } - - *verts = arrayV; - *numVerts = numV; - *edges = arrayE; - *numEdges = numE; -} - -CCGError ccgSubSurf_updateFromFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF) -{ - int i, S, x, gridSize, cornerIdx, subdivLevels; - int vertDataSize = ss->meshIFC.vertDataSize, freeF; - - subdivLevels = ss->subdivLevels; - lvl = (lvl) ? lvl : subdivLevels; - gridSize = ccg_gridsize(lvl); - cornerIdx = gridSize - 1; - - ccgSubSurf__allFaces(ss, &effectedF, &numEffectedF, &freeF); - - for (i = 0; i < numEffectedF; i++) { - CCGFace *f = effectedF[i]; - - for (S = 0; S < f->numVerts; S++) { - CCGEdge *e = FACE_getEdges(f)[S]; - CCGEdge *prevE = FACE_getEdges(f)[(S + f->numVerts - 1) % f->numVerts]; - - VertDataCopy((float *)FACE_getCenterData(f), FACE_getIFCo(f, lvl, S, 0, 0), ss); - VertDataCopy( - VERT_getCo(FACE_getVerts(f)[S], lvl), FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx), ss); - - for (x = 0; x < gridSize; x++) { - VertDataCopy(FACE_getIECo(f, lvl, S, x), FACE_getIFCo(f, lvl, S, x, 0), ss); - } - - for (x = 0; x < gridSize; x++) { - int eI = gridSize - 1 - x; - VertDataCopy( - static_cast(_edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI, vertDataSize)), - FACE_getIFCo(f, lvl, S, cornerIdx, x), - ss); - VertDataCopy(static_cast( - _edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI, vertDataSize)), - FACE_getIFCo(f, lvl, S, x, cornerIdx), - ss); - } - } - } - - if (freeF) { - MEM_freeN(effectedF); - } - - return eCCGError_None; -} - -CCGError ccgSubSurf_updateToFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF) -{ - int i, S, x, gridSize, cornerIdx, subdivLevels; - int vertDataSize = ss->meshIFC.vertDataSize, freeF; - - subdivLevels = ss->subdivLevels; - lvl = (lvl) ? lvl : subdivLevels; - gridSize = ccg_gridsize(lvl); - cornerIdx = gridSize - 1; - - ccgSubSurf__allFaces(ss, &effectedF, &numEffectedF, &freeF); - - for (i = 0; i < numEffectedF; i++) { - CCGFace *f = effectedF[i]; - - for (S = 0; S < f->numVerts; S++) { - int prevS = (S + f->numVerts - 1) % f->numVerts; - CCGEdge *e = FACE_getEdges(f)[S]; - CCGEdge *prevE = FACE_getEdges(f)[prevS]; - - for (x = 0; x < gridSize; x++) { - int eI = gridSize - 1 - x; - VertDataCopy(FACE_getIFCo(f, lvl, S, cornerIdx, x), - static_cast( - _edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI, vertDataSize)), - ss); - VertDataCopy(FACE_getIFCo(f, lvl, S, x, cornerIdx), - static_cast( - _edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI, vertDataSize)), - ss); - } - - for (x = 1; x < gridSize - 1; x++) { - VertDataCopy(FACE_getIFCo(f, lvl, S, 0, x), FACE_getIECo(f, lvl, prevS, x), ss); - VertDataCopy(FACE_getIFCo(f, lvl, S, x, 0), FACE_getIECo(f, lvl, S, x), ss); - } - - VertDataCopy(FACE_getIFCo(f, lvl, S, 0, 0), (float *)FACE_getCenterData(f), ss); - VertDataCopy( - FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], lvl), ss); - } - } - - if (freeF) { - MEM_freeN(effectedF); - } - - return eCCGError_None; -} - -CCGError ccgSubSurf_stitchFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF) -{ - CCGVert **effectedV; - CCGEdge **effectedE; - int numEffectedV, numEffectedE, freeF; - int i, S, x, gridSize, cornerIdx, subdivLevels, edgeSize; - int vertDataSize = ss->meshIFC.vertDataSize; - - subdivLevels = ss->subdivLevels; - lvl = (lvl) ? lvl : subdivLevels; - gridSize = ccg_gridsize(lvl); - edgeSize = ccg_edgesize(lvl); - cornerIdx = gridSize - 1; - - ccgSubSurf__allFaces(ss, &effectedF, &numEffectedF, &freeF); - ccgSubSurf__effectedFaceNeighbors( - ss, effectedF, numEffectedF, &effectedV, &numEffectedV, &effectedE, &numEffectedE); - - /* zero */ - for (i = 0; i < numEffectedV; i++) { - CCGVert *v = effectedV[i]; - if (v->numFaces) { - VertDataZero(VERT_getCo(v, lvl), ss); - } - } - - for (i = 0; i < numEffectedE; i++) { - CCGEdge *e = effectedE[i]; - - if (e->numFaces) { - for (x = 0; x < edgeSize; x++) { - VertDataZero(EDGE_getCo(e, lvl, x), ss); - } - } - } - - /* add */ - for (i = 0; i < numEffectedF; i++) { - CCGFace *f = effectedF[i]; - - VertDataZero((float *)FACE_getCenterData(f), ss); - - for (S = 0; S < f->numVerts; S++) { - for (x = 0; x < gridSize; x++) { - VertDataZero(FACE_getIECo(f, lvl, S, x), ss); - } - } - - for (S = 0; S < f->numVerts; S++) { - int prevS = (S + f->numVerts - 1) % f->numVerts; - CCGEdge *e = FACE_getEdges(f)[S]; - CCGEdge *prevE = FACE_getEdges(f)[prevS]; - - VertDataAdd((float *)FACE_getCenterData(f), FACE_getIFCo(f, lvl, S, 0, 0), ss); - if (FACE_getVerts(f)[S]->flags & Vert_eEffected) { - VertDataAdd(VERT_getCo(FACE_getVerts(f)[S], lvl), - FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx), - ss); - } - - for (x = 1; x < gridSize - 1; x++) { - VertDataAdd(FACE_getIECo(f, lvl, S, x), FACE_getIFCo(f, lvl, S, x, 0), ss); - VertDataAdd(FACE_getIECo(f, lvl, prevS, x), FACE_getIFCo(f, lvl, S, 0, x), ss); - } - - for (x = 0; x < gridSize - 1; x++) { - int eI = gridSize - 1 - x; - if (FACE_getEdges(f)[S]->flags & Edge_eEffected) { - VertDataAdd( - static_cast(_edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI, vertDataSize)), - FACE_getIFCo(f, lvl, S, cornerIdx, x), - ss); - } - if (FACE_getEdges(f)[prevS]->flags & Edge_eEffected) { - if (x != 0) { - VertDataAdd(static_cast( - _edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI, vertDataSize)), - FACE_getIFCo(f, lvl, S, x, cornerIdx), - ss); - } - } - } - } - } - - /* average */ - for (i = 0; i < numEffectedV; i++) { - CCGVert *v = effectedV[i]; - if (v->numFaces) { - VertDataMulN(VERT_getCo(v, lvl), 1.0f / v->numFaces, ss); - } - } - - for (i = 0; i < numEffectedE; i++) { - CCGEdge *e = effectedE[i]; - - VertDataCopy(EDGE_getCo(e, lvl, 0), VERT_getCo(e->v0, lvl), ss); - VertDataCopy(EDGE_getCo(e, lvl, edgeSize - 1), VERT_getCo(e->v1, lvl), ss); - - if (e->numFaces) { - for (x = 1; x < edgeSize - 1; x++) { - VertDataMulN(EDGE_getCo(e, lvl, x), 1.0f / e->numFaces, ss); - } - } - } - - /* copy */ - for (i = 0; i < numEffectedF; i++) { - CCGFace *f = effectedF[i]; - - VertDataMulN((float *)FACE_getCenterData(f), 1.0f / f->numVerts, ss); - - for (S = 0; S < f->numVerts; S++) { - for (x = 1; x < gridSize - 1; x++) { - VertDataMulN(FACE_getIECo(f, lvl, S, x), 0.5f, ss); - } - } - - for (S = 0; S < f->numVerts; S++) { - int prevS = (S + f->numVerts - 1) % f->numVerts; - CCGEdge *e = FACE_getEdges(f)[S]; - CCGEdge *prevE = FACE_getEdges(f)[prevS]; - - VertDataCopy(FACE_getIFCo(f, lvl, S, 0, 0), (float *)FACE_getCenterData(f), ss); - VertDataCopy( - FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], lvl), ss); - - for (x = 1; x < gridSize - 1; x++) { - VertDataCopy(FACE_getIFCo(f, lvl, S, x, 0), FACE_getIECo(f, lvl, S, x), ss); - VertDataCopy(FACE_getIFCo(f, lvl, S, 0, x), FACE_getIECo(f, lvl, prevS, x), ss); - } - - for (x = 0; x < gridSize - 1; x++) { - int eI = gridSize - 1 - x; - - VertDataCopy(FACE_getIFCo(f, lvl, S, cornerIdx, x), - static_cast( - _edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI, vertDataSize)), - ss); - VertDataCopy(FACE_getIFCo(f, lvl, S, x, cornerIdx), - static_cast( - _edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI, vertDataSize)), - ss); - } - - VertDataCopy(FACE_getIECo(f, lvl, S, 0), (float *)FACE_getCenterData(f), ss); - VertDataCopy( - FACE_getIECo(f, lvl, S, gridSize - 1), FACE_getIFCo(f, lvl, S, gridSize - 1, 0), ss); - } - } - - for (i = 0; i < numEffectedV; i++) { - effectedV[i]->flags = 0; - } - for (i = 0; i < numEffectedE; i++) { - effectedE[i]->flags = 0; - } - for (i = 0; i < numEffectedF; i++) { - effectedF[i]->flags = 0; - } - - MEM_freeN(effectedE); - MEM_freeN(effectedV); - if (freeF) { - MEM_freeN(effectedF); - } - - return eCCGError_None; -} - -/*** External API accessor functions ***/ - -int ccgSubSurf_getNumVerts(const CCGSubSurf *ss) -{ - return ss->vMap->numEntries; -} -int ccgSubSurf_getNumEdges(const CCGSubSurf *ss) -{ - return ss->eMap->numEntries; -} -int ccgSubSurf_getNumFaces(const CCGSubSurf *ss) -{ - return ss->fMap->numEntries; -} - -CCGVert *ccgSubSurf_getVert(CCGSubSurf *ss, CCGVertHDL v) -{ - return (CCGVert *)ccg_ehash_lookup(ss->vMap, v); -} -CCGEdge *ccgSubSurf_getEdge(CCGSubSurf *ss, CCGEdgeHDL e) -{ - return (CCGEdge *)ccg_ehash_lookup(ss->eMap, e); -} -CCGFace *ccgSubSurf_getFace(CCGSubSurf *ss, CCGFaceHDL f) -{ - return (CCGFace *)ccg_ehash_lookup(ss->fMap, f); -} - -int ccgSubSurf_getSubdivisionLevels(const CCGSubSurf *ss) -{ - return ss->subdivLevels; -} -int ccgSubSurf_getEdgeSize(const CCGSubSurf *ss) -{ - return ccgSubSurf_getEdgeLevelSize(ss, ss->subdivLevels); -} -int ccgSubSurf_getEdgeLevelSize(const CCGSubSurf *ss, int level) -{ - if (level < 1 || level > ss->subdivLevels) { - return -1; - } - return ccg_edgesize(level); -} -int ccgSubSurf_getGridSize(const CCGSubSurf *ss) -{ - return ccgSubSurf_getGridLevelSize(ss, ss->subdivLevels); -} -int ccgSubSurf_getGridLevelSize(const CCGSubSurf *ss, int level) -{ - if (level < 1 || level > ss->subdivLevels) { - return -1; - } - return ccg_gridsize(level); -} - -int ccgSubSurf_getSimpleSubdiv(const CCGSubSurf *ss) -{ - return ss->meshIFC.simpleSubdiv; -} - -/* Vert accessors */ - -CCGVertHDL ccgSubSurf_getVertVertHandle(CCGVert *v) -{ - return v->vHDL; -} -int ccgSubSurf_getVertAge(CCGSubSurf *ss, CCGVert *v) -{ - if (ss->useAgeCounts) { - uint8_t *user_data = static_cast(ccgSubSurf_getVertUserData(ss, v)); - return ss->currentAge - *((int *)&user_data[ss->vertUserAgeOffset]); - } - return 0; -} -void *ccgSubSurf_getVertUserData(CCGSubSurf *ss, CCGVert *v) -{ - return VERT_getLevelData(v) + ss->meshIFC.vertDataSize * (ss->subdivLevels + 1); -} -int ccgSubSurf_getVertNumFaces(CCGVert *v) -{ - return v->numFaces; -} -CCGFace *ccgSubSurf_getVertFace(CCGVert *v, int index) -{ - if (index < 0 || index >= v->numFaces) { - return nullptr; - } - return v->faces[index]; -} -int ccgSubSurf_getVertNumEdges(CCGVert *v) -{ - return v->numEdges; -} -CCGEdge *ccgSubSurf_getVertEdge(CCGVert *v, int index) -{ - if (index < 0 || index >= v->numEdges) { - return nullptr; - } - return v->edges[index]; -} -void *ccgSubSurf_getVertData(CCGSubSurf *ss, CCGVert *v) -{ - return ccgSubSurf_getVertLevelData(ss, v, ss->subdivLevels); -} -void *ccgSubSurf_getVertLevelData(CCGSubSurf *ss, CCGVert *v, int level) -{ - if (level < 0 || level > ss->subdivLevels) { - return nullptr; - } - return ccg_vert_getCo(v, level, ss->meshIFC.vertDataSize); -} - -/* Edge accessors */ - -CCGEdgeHDL ccgSubSurf_getEdgeEdgeHandle(CCGEdge *e) -{ - return e->eHDL; -} -int ccgSubSurf_getEdgeAge(CCGSubSurf *ss, CCGEdge *e) -{ - if (ss->useAgeCounts) { - uint8_t *user_data = static_cast(ccgSubSurf_getEdgeUserData(ss, e)); - return ss->currentAge - *((int *)&user_data[ss->edgeUserAgeOffset]); - } - return 0; -} -void *ccgSubSurf_getEdgeUserData(CCGSubSurf *ss, CCGEdge *e) -{ - return (EDGE_getLevelData(e) + ss->meshIFC.vertDataSize * ccg_edgebase(ss->subdivLevels + 1)); -} -int ccgSubSurf_getEdgeNumFaces(CCGEdge *e) -{ - return e->numFaces; -} -CCGFace *ccgSubSurf_getEdgeFace(CCGEdge *e, int index) -{ - if (index < 0 || index >= e->numFaces) { - return nullptr; - } - return e->faces[index]; -} -CCGVert *ccgSubSurf_getEdgeVert0(CCGEdge *e) -{ - return e->v0; -} -CCGVert *ccgSubSurf_getEdgeVert1(CCGEdge *e) -{ - return e->v1; -} -void *ccgSubSurf_getEdgeDataArray(CCGSubSurf *ss, CCGEdge *e) -{ - return ccgSubSurf_getEdgeData(ss, e, 0); -} -void *ccgSubSurf_getEdgeData(CCGSubSurf *ss, CCGEdge *e, int x) -{ - return ccgSubSurf_getEdgeLevelData(ss, e, x, ss->subdivLevels); -} -void *ccgSubSurf_getEdgeLevelData(CCGSubSurf *ss, CCGEdge *e, int x, int level) -{ - if (level < 0 || level > ss->subdivLevels) { - return nullptr; - } - return ccg_edge_getCo(e, level, x, ss->meshIFC.vertDataSize); -} -float ccgSubSurf_getEdgeCrease(CCGEdge *e) -{ - return e->crease; -} - -/* Face accessors */ - -CCGFaceHDL ccgSubSurf_getFaceFaceHandle(CCGFace *f) -{ - return f->fHDL; -} -int ccgSubSurf_getFaceAge(CCGSubSurf *ss, CCGFace *f) -{ - if (ss->useAgeCounts) { - uint8_t *user_data = static_cast(ccgSubSurf_getFaceUserData(ss, f)); - return ss->currentAge - *((int *)&user_data[ss->faceUserAgeOffset]); - } - return 0; -} -void *ccgSubSurf_getFaceUserData(CCGSubSurf *ss, CCGFace *f) -{ - int maxGridSize = ccg_gridsize(ss->subdivLevels); - return FACE_getCenterData(f) + - ss->meshIFC.vertDataSize * - (1 + f->numVerts * maxGridSize + f->numVerts * maxGridSize * maxGridSize); -} -int ccgSubSurf_getFaceNumVerts(CCGFace *f) -{ - return f->numVerts; -} -CCGVert *ccgSubSurf_getFaceVert(CCGFace *f, int index) -{ - if (index < 0 || index >= f->numVerts) { - return nullptr; - } - return FACE_getVerts(f)[index]; -} -CCGEdge *ccgSubSurf_getFaceEdge(CCGFace *f, int index) -{ - if (index < 0 || index >= f->numVerts) { - return nullptr; - } - return FACE_getEdges(f)[index]; -} -int ccgSubSurf_getFaceEdgeIndex(CCGFace *f, CCGEdge *e) -{ - for (int i = 0; i < f->numVerts; i++) { - if (FACE_getEdges(f)[i] == e) { - return i; - } - } - return -1; -} -void *ccgSubSurf_getFaceCenterData(CCGFace *f) -{ - return FACE_getCenterData(f); -} -void *ccgSubSurf_getFaceGridEdgeDataArray(CCGSubSurf *ss, CCGFace *f, int gridIndex) -{ - return ccgSubSurf_getFaceGridEdgeData(ss, f, gridIndex, 0); -} -void *ccgSubSurf_getFaceGridEdgeData(CCGSubSurf *ss, CCGFace *f, int gridIndex, int x) -{ - return ccg_face_getIECo( - f, ss->subdivLevels, gridIndex, x, ss->subdivLevels, ss->meshIFC.vertDataSize); -} -void *ccgSubSurf_getFaceGridDataArray(CCGSubSurf *ss, CCGFace *f, int gridIndex) -{ - return ccgSubSurf_getFaceGridData(ss, f, gridIndex, 0, 0); -} -void *ccgSubSurf_getFaceGridData(CCGSubSurf *ss, CCGFace *f, int gridIndex, int x, int y) -{ - return ccg_face_getIFCo( - f, ss->subdivLevels, gridIndex, x, y, ss->subdivLevels, ss->meshIFC.vertDataSize); -} - -/*** External API iterator functions ***/ - -void ccgSubSurf_initVertIterator(CCGSubSurf *ss, CCGVertIterator *viter) -{ - ccg_ehashIterator_init(ss->vMap, viter); -} -void ccgSubSurf_initEdgeIterator(CCGSubSurf *ss, CCGEdgeIterator *eiter) -{ - ccg_ehashIterator_init(ss->eMap, eiter); -} -void ccgSubSurf_initFaceIterator(CCGSubSurf *ss, CCGFaceIterator *fiter) -{ - ccg_ehashIterator_init(ss->fMap, fiter); -} - -CCGVert *ccgVertIterator_getCurrent(CCGVertIterator *vi) -{ - return (CCGVert *)ccg_ehashIterator_getCurrent((EHashIterator *)vi); -} -int ccgVertIterator_isStopped(CCGVertIterator *vi) -{ - return ccg_ehashIterator_isStopped((EHashIterator *)vi); -} -void ccgVertIterator_next(CCGVertIterator *vi) -{ - ccg_ehashIterator_next((EHashIterator *)vi); -} - -CCGEdge *ccgEdgeIterator_getCurrent(CCGEdgeIterator *ei) -{ - return (CCGEdge *)ccg_ehashIterator_getCurrent((EHashIterator *)ei); -} -int ccgEdgeIterator_isStopped(CCGEdgeIterator *ei) -{ - return ccg_ehashIterator_isStopped((EHashIterator *)ei); -} -void ccgEdgeIterator_next(CCGEdgeIterator *ei) -{ - ccg_ehashIterator_next((EHashIterator *)ei); -} - -CCGFace *ccgFaceIterator_getCurrent(CCGFaceIterator *fi) -{ - return (CCGFace *)ccg_ehashIterator_getCurrent((EHashIterator *)fi); -} -int ccgFaceIterator_isStopped(CCGFaceIterator *fi) -{ - return ccg_ehashIterator_isStopped((EHashIterator *)fi); -} -void ccgFaceIterator_next(CCGFaceIterator *fi) -{ - ccg_ehashIterator_next((EHashIterator *)fi); -} - -/*** External API final vert/edge/face interface. ***/ - -int ccgSubSurf_getNumFinalVerts(const CCGSubSurf *ss) -{ - int edgeSize = ccg_edgesize(ss->subdivLevels); - int gridSize = ccg_gridsize(ss->subdivLevels); - int numFinalVerts = (ss->vMap->numEntries + ss->eMap->numEntries * (edgeSize - 2) + - ss->fMap->numEntries + - ss->numGrids * ((gridSize - 2) + ((gridSize - 2) * (gridSize - 2)))); - - return numFinalVerts; -} -int ccgSubSurf_getNumFinalEdges(const CCGSubSurf *ss) -{ - int edgeSize = ccg_edgesize(ss->subdivLevels); - int gridSize = ccg_gridsize(ss->subdivLevels); - int numFinalEdges = (ss->eMap->numEntries * (edgeSize - 1) + - ss->numGrids * ((gridSize - 1) + 2 * ((gridSize - 2) * (gridSize - 1)))); - return numFinalEdges; -} -int ccgSubSurf_getNumFinalFaces(const CCGSubSurf *ss) -{ - int gridSize = ccg_gridsize(ss->subdivLevels); - int numFinalFaces = ss->numGrids * ((gridSize - 1) * (gridSize - 1)); - return numFinalFaces; -} - -/***/ - -void CCG_key(CCGKey *key, const CCGSubSurf *ss, int level) -{ - key->level = level; - - key->elem_size = ss->meshIFC.vertDataSize; - key->has_normals = ss->calcVertNormals; - - /* if normals are present, always the last three floats of an - * element */ - if (key->has_normals) { - key->normal_offset = key->elem_size - sizeof(float[3]); - } - else { - key->normal_offset = -1; - } - - key->grid_size = ccgSubSurf_getGridLevelSize(ss, level); - key->grid_area = key->grid_size * key->grid_size; - key->grid_bytes = key->elem_size * key->grid_area; - - key->has_mask = ss->allocMask; - if (key->has_mask) { - key->mask_offset = ss->maskDataOffset; - } - else { - key->mask_offset = -1; - } -} - -void CCG_key_top_level(CCGKey *key, const CCGSubSurf *ss) -{ - CCG_key(key, ss, ccgSubSurf_getSubdivisionLevels(ss)); -} diff --git a/source/blender/blenkernel/intern/CCGSubSurf.h b/source/blender/blenkernel/intern/CCGSubSurf.h deleted file mode 100644 index 964e1e639d2..00000000000 --- a/source/blender/blenkernel/intern/CCGSubSurf.h +++ /dev/null @@ -1,219 +0,0 @@ -/* SPDX-FileCopyrightText: 2023 Blender Authors - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#pragma once - -/** \file - * \ingroup bke - */ - -using CCGMeshHDL = void *; -using CCGVertHDL = void *; -using CCGEdgeHDL = void *; -using CCGFaceHDL = void *; - -struct CCGEdge; -struct CCGFace; -struct CCGSubSurf; -struct CCGVert; - -struct CCGMeshIFC { - int vertUserSize, edgeUserSize, faceUserSize; - int numLayers; - int vertDataSize; - int simpleSubdiv; -}; - -/***/ - -using CCGAllocatorHDL = void *; - -struct CCGAllocatorIFC { - void *(*alloc)(CCGAllocatorHDL a, int numBytes); - void *(*realloc)(CCGAllocatorHDL a, void *ptr, int newSize, int oldSize); - void (*free)(CCGAllocatorHDL a, void *ptr); - void (*release)(CCGAllocatorHDL a); -}; - -/* private, so we can allocate on the stack */ -struct EHashIterator { - struct EHash *eh; - int curBucket; - struct EHEntry *curEntry; -}; - -/***/ - -enum CCGError { - eCCGError_None = 0, - - eCCGError_InvalidSyncState, - eCCGError_InvalidValue, -}; - -/***/ - -/* TODO(sergey): This actually depends on subsurf level as well. */ -#define CCG_TASK_LIMIT 16 - -/***/ - -CCGSubSurf *ccgSubSurf_new(CCGMeshIFC *ifc, - int subdivLevels, - CCGAllocatorIFC *allocatorIFC, - CCGAllocatorHDL allocator); -void ccgSubSurf_free(CCGSubSurf *ss); - -CCGError ccgSubSurf_initFullSync(CCGSubSurf *ss); -CCGError ccgSubSurf_initPartialSync(CCGSubSurf *ss); -#ifdef WITH_OPENSUBDIV -CCGError ccgSubSurf_initOpenSubdivSync(CCGSubSurf *ss); -#endif - -CCGError ccgSubSurf_syncVert( - CCGSubSurf *ss, CCGVertHDL vHDL, const void *vertData, int seam, CCGVert **v_r); -CCGError ccgSubSurf_syncEdge(CCGSubSurf *ss, - CCGEdgeHDL eHDL, - CCGVertHDL e_vHDL0, - CCGVertHDL e_vHDL1, - float crease, - CCGEdge **e_r); -CCGError ccgSubSurf_syncFace( - CCGSubSurf *ss, CCGFaceHDL fHDL, int numVerts, CCGVertHDL *vHDLs, CCGFace **f_r); - -CCGError ccgSubSurf_syncVertDel(CCGSubSurf *ss, CCGVertHDL vHDL); -CCGError ccgSubSurf_syncEdgeDel(CCGSubSurf *ss, CCGEdgeHDL eHDL); -CCGError ccgSubSurf_syncFaceDel(CCGSubSurf *ss, CCGFaceHDL fHDL); - -CCGError ccgSubSurf_processSync(CCGSubSurf *ss); - -/** - * Copy face grid coordinates to other places. - */ -CCGError ccgSubSurf_updateFromFaces(CCGSubSurf *ss, - int lvl, - CCGFace **effectedF, - int numEffectedF); -/** - * Copy other places to face grid coordinates. - */ -CCGError ccgSubSurf_updateToFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF); -/** - * Update normals for specified faces. - */ -CCGError ccgSubSurf_updateNormals(CCGSubSurf *ss, CCGFace **effectedF, int numEffectedF); -/** - * Compute subdivision levels from a given starting point, used by multi-res subdivide/propagate, - * by filling in coordinates at a certain level, and then subdividing that up to the highest level. - */ -CCGError ccgSubSurf_updateLevels(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF); -/** - * Stitch together face grids, averaging coordinates at edges and vertices, for multi-res - * displacements. - */ -CCGError ccgSubSurf_stitchFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF); - -CCGError ccgSubSurf_setSubdivisionLevels(CCGSubSurf *ss, int subdivisionLevels); - -CCGError ccgSubSurf_setAllowEdgeCreation(CCGSubSurf *ss, - int allowEdgeCreation, - float defaultCreaseValue, - void *defaultUserData); -void ccgSubSurf_getAllowEdgeCreation(CCGSubSurf *ss, - int *allowEdgeCreation_r, - float *defaultCreaseValue_r, - void *defaultUserData_r); - -void ccgSubSurf_getUseAgeCounts(CCGSubSurf *ss, - int *useAgeCounts_r, - int *vertUserOffset_r, - int *edgeUserOffset_r, - int *faceUserOffset_r); -CCGError ccgSubSurf_setUseAgeCounts( - CCGSubSurf *ss, int useAgeCounts, int vertUserOffset, int edgeUserOffset, int faceUserOffset); - -CCGError ccgSubSurf_setCalcVertexNormals(CCGSubSurf *ss, int useVertNormals, int normalDataOffset); -void ccgSubSurf_setAllocMask(CCGSubSurf *ss, int allocMask, int maskOffset); - -void ccgSubSurf_setNumLayers(CCGSubSurf *ss, int numLayers); - -/***/ - -int ccgSubSurf_getNumVerts(const CCGSubSurf *ss); -int ccgSubSurf_getNumEdges(const CCGSubSurf *ss); -int ccgSubSurf_getNumFaces(const CCGSubSurf *ss); - -int ccgSubSurf_getSubdivisionLevels(const CCGSubSurf *ss); -int ccgSubSurf_getEdgeSize(const CCGSubSurf *ss); -int ccgSubSurf_getEdgeLevelSize(const CCGSubSurf *ss, int level); -int ccgSubSurf_getGridSize(const CCGSubSurf *ss); -int ccgSubSurf_getGridLevelSize(const CCGSubSurf *ss, int level); -int ccgSubSurf_getSimpleSubdiv(const CCGSubSurf *ss); - -CCGVert *ccgSubSurf_getVert(CCGSubSurf *ss, CCGVertHDL v); -CCGVertHDL ccgSubSurf_getVertVertHandle(CCGVert *v); -int ccgSubSurf_getVertNumFaces(CCGVert *v); -CCGFace *ccgSubSurf_getVertFace(CCGVert *v, int index); -int ccgSubSurf_getVertNumEdges(CCGVert *v); -CCGEdge *ccgSubSurf_getVertEdge(CCGVert *v, int index); - -int ccgSubSurf_getVertAge(CCGSubSurf *ss, CCGVert *v); -void *ccgSubSurf_getVertUserData(CCGSubSurf *ss, CCGVert *v); -void *ccgSubSurf_getVertData(CCGSubSurf *ss, CCGVert *v); -void *ccgSubSurf_getVertLevelData(CCGSubSurf *ss, CCGVert *v, int level); - -CCGEdge *ccgSubSurf_getEdge(CCGSubSurf *ss, CCGEdgeHDL e); -CCGEdgeHDL ccgSubSurf_getEdgeEdgeHandle(CCGEdge *e); -int ccgSubSurf_getEdgeNumFaces(CCGEdge *e); -CCGFace *ccgSubSurf_getEdgeFace(CCGEdge *e, int index); -CCGVert *ccgSubSurf_getEdgeVert0(CCGEdge *e); -CCGVert *ccgSubSurf_getEdgeVert1(CCGEdge *e); -float ccgSubSurf_getEdgeCrease(CCGEdge *e); - -int ccgSubSurf_getEdgeAge(CCGSubSurf *ss, CCGEdge *e); -void *ccgSubSurf_getEdgeUserData(CCGSubSurf *ss, CCGEdge *e); -void *ccgSubSurf_getEdgeDataArray(CCGSubSurf *ss, CCGEdge *e); -void *ccgSubSurf_getEdgeData(CCGSubSurf *ss, CCGEdge *e, int x); -void *ccgSubSurf_getEdgeLevelData(CCGSubSurf *ss, CCGEdge *e, int x, int level); - -CCGFace *ccgSubSurf_getFace(CCGSubSurf *ss, CCGFaceHDL f); -CCGFaceHDL ccgSubSurf_getFaceFaceHandle(CCGFace *f); -int ccgSubSurf_getFaceNumVerts(CCGFace *f); -CCGVert *ccgSubSurf_getFaceVert(CCGFace *f, int index); -CCGEdge *ccgSubSurf_getFaceEdge(CCGFace *f, int index); -int ccgSubSurf_getFaceEdgeIndex(CCGFace *f, CCGEdge *e); - -int ccgSubSurf_getFaceAge(CCGSubSurf *ss, CCGFace *f); -void *ccgSubSurf_getFaceUserData(CCGSubSurf *ss, CCGFace *f); -void *ccgSubSurf_getFaceCenterData(CCGFace *f); -void *ccgSubSurf_getFaceGridEdgeDataArray(CCGSubSurf *ss, CCGFace *f, int gridIndex); -void *ccgSubSurf_getFaceGridEdgeData(CCGSubSurf *ss, CCGFace *f, int gridIndex, int x); -void *ccgSubSurf_getFaceGridDataArray(CCGSubSurf *ss, CCGFace *f, int gridIndex); -void *ccgSubSurf_getFaceGridData(CCGSubSurf *ss, CCGFace *f, int gridIndex, int x, int y); - -int ccgSubSurf_getNumFinalVerts(const CCGSubSurf *ss); -int ccgSubSurf_getNumFinalEdges(const CCGSubSurf *ss); -int ccgSubSurf_getNumFinalFaces(const CCGSubSurf *ss); - -/***/ - -using CCGEdgeIterator = EHashIterator; -using CCGFaceIterator = EHashIterator; -using CCGVertIterator = EHashIterator; - -void ccgSubSurf_initVertIterator(CCGSubSurf *ss, CCGVertIterator *viter); -void ccgSubSurf_initEdgeIterator(CCGSubSurf *ss, CCGEdgeIterator *eiter); -void ccgSubSurf_initFaceIterator(CCGSubSurf *ss, CCGFaceIterator *fiter); - -CCGVert *ccgVertIterator_getCurrent(CCGVertIterator *vi); -int ccgVertIterator_isStopped(CCGVertIterator *vi); -void ccgVertIterator_next(CCGVertIterator *vi); - -CCGEdge *ccgEdgeIterator_getCurrent(CCGEdgeIterator *ei); -int ccgEdgeIterator_isStopped(CCGEdgeIterator *ei); -void ccgEdgeIterator_next(CCGEdgeIterator *ei); - -CCGFace *ccgFaceIterator_getCurrent(CCGFaceIterator *fi); -int ccgFaceIterator_isStopped(CCGFaceIterator *fi); -void ccgFaceIterator_next(CCGFaceIterator *fi); diff --git a/source/blender/blenkernel/intern/CCGSubSurf_inline.h b/source/blender/blenkernel/intern/CCGSubSurf_inline.h deleted file mode 100644 index a4c5d3d3b8e..00000000000 --- a/source/blender/blenkernel/intern/CCGSubSurf_inline.h +++ /dev/null @@ -1,264 +0,0 @@ -/* SPDX-FileCopyrightText: 2023 Blender Authors - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -/** \file - * \ingroup bke - */ - -#pragma once - -#include "BLI_assert.h" -#include "BLI_compiler_compat.h" - -#include "CCGSubSurf_intern.h" - -#include -#include -#include - -BLI_INLINE int ccg_gridsize(int level) -{ - BLI_assert(level > 0); - BLI_assert(level <= CCGSUBSURF_LEVEL_MAX + 1); - return (1 << (level - 1)) + 1; -} - -BLI_INLINE int ccg_edgesize(int level) -{ - BLI_assert(level > 0); - BLI_assert(level <= CCGSUBSURF_LEVEL_MAX + 1); - return 1 + (1 << level); -} - -BLI_INLINE int ccg_spacing(int high_level, int low_level) -{ - BLI_assert(high_level > 0 && low_level > 0); - BLI_assert(high_level >= low_level); - BLI_assert((high_level - low_level) <= CCGSUBSURF_LEVEL_MAX); - return 1 << (high_level - low_level); -} - -BLI_INLINE int ccg_edgebase(int level) -{ - BLI_assert(level > 0); - BLI_assert(level <= CCGSUBSURF_LEVEL_MAX + 1); - return level + (1 << level) - 1; -} - -/* **** */ - -BLI_INLINE uint8_t *VERT_getLevelData(CCGVert *v) -{ - return (uint8_t *)(&(v)[1]); -} - -BLI_INLINE uint8_t *EDGE_getLevelData(CCGEdge *e) -{ - return (uint8_t *)(&(e)[1]); -} - -BLI_INLINE CCGVert **FACE_getVerts(CCGFace *f) -{ - return (CCGVert **)(&f[1]); -} - -BLI_INLINE CCGEdge **FACE_getEdges(CCGFace *f) -{ - return (CCGEdge **)(&(FACE_getVerts(f)[f->numVerts])); -} - -BLI_INLINE uint8_t *FACE_getCenterData(CCGFace *f) -{ - return (uint8_t *)(&(FACE_getEdges(f)[(f)->numVerts])); -} - -/* **** */ - -BLI_INLINE void *ccg_vert_getCo(CCGVert *v, int lvl, int dataSize) -{ - return &VERT_getLevelData(v)[lvl * dataSize]; -} - -BLI_INLINE float *ccg_vert_getNo(CCGVert *v, int lvl, int dataSize, int normalDataOffset) -{ - return (float *)&VERT_getLevelData(v)[lvl * dataSize + normalDataOffset]; -} - -BLI_INLINE void *ccg_edge_getCo(CCGEdge *e, int lvl, int x, int dataSize) -{ - int levelBase = ccg_edgebase(lvl); - return &EDGE_getLevelData(e)[dataSize * (levelBase + x)]; -} - -BLI_INLINE float *ccg_edge_getNo(CCGEdge *e, int lvl, int x, int dataSize, int normalDataOffset) -{ - int levelBase = ccg_edgebase(lvl); - return (float *)&EDGE_getLevelData(e)[dataSize * (levelBase + x) + normalDataOffset]; -} - -BLI_INLINE void *ccg_face_getIECo(CCGFace *f, int lvl, int S, int x, int levels, int dataSize) -{ - int maxGridSize = ccg_gridsize(levels); - int spacing = ccg_spacing(levels, lvl); - uint8_t *gridBase = FACE_getCenterData(f) + - dataSize * (1 + S * (maxGridSize + maxGridSize * maxGridSize)); - return &gridBase[dataSize * x * spacing]; -} - -BLI_INLINE void *ccg_face_getIENo( - CCGFace *f, int lvl, int S, int x, int levels, int dataSize, int normalDataOffset) -{ - int maxGridSize = ccg_gridsize(levels); - int spacing = ccg_spacing(levels, lvl); - uint8_t *gridBase = FACE_getCenterData(f) + - dataSize * (1 + S * (maxGridSize + maxGridSize * maxGridSize)); - return &gridBase[dataSize * x * spacing + normalDataOffset]; -} - -BLI_INLINE void *ccg_face_getIFCo( - CCGFace *f, int lvl, int S, int x, int y, int levels, int dataSize) -{ - int maxGridSize = ccg_gridsize(levels); - int spacing = ccg_spacing(levels, lvl); - uint8_t *gridBase = FACE_getCenterData(f) + - dataSize * (1 + S * (maxGridSize + maxGridSize * maxGridSize)); - return &gridBase[dataSize * (maxGridSize + (y * maxGridSize + x) * spacing)]; -} - -BLI_INLINE float *ccg_face_getIFNo( - CCGFace *f, int lvl, int S, int x, int y, int levels, int dataSize, int normalDataOffset) -{ - int maxGridSize = ccg_gridsize(levels); - int spacing = ccg_spacing(levels, lvl); - uint8_t *gridBase = FACE_getCenterData(f) + - dataSize * (1 + S * (maxGridSize + maxGridSize * maxGridSize)); - return (float *)&gridBase[dataSize * (maxGridSize + (y * maxGridSize + x) * spacing) + - normalDataOffset]; -} - -BLI_INLINE int ccg_face_getVertIndex(CCGFace *f, CCGVert *v) -{ - for (int i = 0; i < f->numVerts; i++) { - if (FACE_getVerts(f)[i] == v) { - return i; - } - } - return -1; -} - -BLI_INLINE int ccg_face_getEdgeIndex(CCGFace *f, CCGEdge *e) -{ - for (int i = 0; i < f->numVerts; i++) { - if (FACE_getEdges(f)[i] == e) { - return i; - } - } - return -1; -} - -BLI_INLINE void *ccg_face_getIFCoEdge( - CCGFace *f, CCGEdge *e, int f_ed_idx, int lvl, int eX, int eY, int levels, int dataSize) -{ - int maxGridSize = ccg_gridsize(levels); - int spacing = ccg_spacing(levels, lvl); - int x, y, cx, cy; - - BLI_assert(f_ed_idx == ccg_face_getEdgeIndex(f, e)); - - eX = eX * spacing; - eY = eY * spacing; - if (e->v0 != FACE_getVerts(f)[f_ed_idx]) { - eX = (maxGridSize * 2 - 1) - 1 - eX; - } - y = maxGridSize - 1 - eX; - x = maxGridSize - 1 - eY; - if (x < 0) { - f_ed_idx = (f_ed_idx + f->numVerts - 1) % f->numVerts; - cx = y; - cy = -x; - } - else if (y < 0) { - f_ed_idx = (f_ed_idx + 1) % f->numVerts; - cx = -y; - cy = x; - } - else { - cx = x; - cy = y; - } - return ccg_face_getIFCo(f, levels, f_ed_idx, cx, cy, levels, dataSize); -} - -BLI_INLINE void Normalize(float no[3]) -{ - const float length = sqrtf(no[0] * no[0] + no[1] * no[1] + no[2] * no[2]); - - if (length > EPSILON) { - const float length_inv = 1.0f / length; - - no[0] *= length_inv; - no[1] *= length_inv; - no[2] *= length_inv; - } - else { - NormZero(no); - } -} - -/* Data layers mathematics. */ - -BLI_INLINE bool VertDataEqual(const float a[], const float b[], const CCGSubSurf *ss) -{ - for (int i = 0; i < ss->meshIFC.numLayers; i++) { - if (a[i] != b[i]) { - return false; - } - } - return true; -} - -BLI_INLINE void VertDataZero(float v[], const CCGSubSurf *ss) -{ - memset(v, 0, sizeof(float) * ss->meshIFC.numLayers); -} - -BLI_INLINE void VertDataCopy(float dst[], const float src[], const CCGSubSurf *ss) -{ - for (int i = 0; i < ss->meshIFC.numLayers; i++) { - dst[i] = src[i]; - } -} - -BLI_INLINE void VertDataAdd(float a[], const float b[], const CCGSubSurf *ss) -{ - for (int i = 0; i < ss->meshIFC.numLayers; i++) { - a[i] += b[i]; - } -} - -BLI_INLINE void VertDataSub(float a[], const float b[], const CCGSubSurf *ss) -{ - for (int i = 0; i < ss->meshIFC.numLayers; i++) { - a[i] -= b[i]; - } -} - -BLI_INLINE void VertDataMulN(float v[], float f, const CCGSubSurf *ss) -{ - for (int i = 0; i < ss->meshIFC.numLayers; i++) { - v[i] *= f; - } -} - -BLI_INLINE void VertDataAvg4(float v[], - const float a[], - const float b[], - const float c[], - const float d[], - const CCGSubSurf *ss) -{ - for (int i = 0; i < ss->meshIFC.numLayers; i++) { - v[i] = (a[i] + b[i] + c[i] + d[i]) * 0.25f; - } -} diff --git a/source/blender/blenkernel/intern/CCGSubSurf_intern.h b/source/blender/blenkernel/intern/CCGSubSurf_intern.h deleted file mode 100644 index 6bd152f0198..00000000000 --- a/source/blender/blenkernel/intern/CCGSubSurf_intern.h +++ /dev/null @@ -1,258 +0,0 @@ -/* SPDX-FileCopyrightText: 2023 Blender Authors - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -/** \file - * \ingroup bke - */ - -#pragma once - -#include "CCGSubSurf.h" - -/** - * Definitions which defines internal behavior of CCGSubSurf. - */ - -/* Define this to see dump of the grids after the subsurf applied. */ -#undef DUMP_RESULT_GRIDS - -/* used for normalize_v3 in BLI_math_vector - * float.h's FLT_EPSILON causes trouble with subsurf normals - campbell */ -#define EPSILON (1.0e-35f) - -/* With this limit a single triangle becomes over 3 million faces */ -#define CCGSUBSURF_LEVEL_MAX 11 - -/** - * Common type definitions. - */ - -/** - * Hash implementation. - */ - -struct EHEntry { - struct EHEntry *next; - void *key; -}; - -struct EHash { - EHEntry **buckets; - int numEntries, curSize, curSizeIdx; - - CCGAllocatorIFC allocatorIFC; - CCGAllocatorHDL allocator; -}; - -using EHEntryFreeFP = void (*)(EHEntry *, void *); - -#define EHASH_alloc(eh, nb) (EHEntry **)((eh)->allocatorIFC.alloc((eh)->allocator, nb)) -#define EHASH_free(eh, ptr) ((eh)->allocatorIFC.free((eh)->allocator, ptr)) -#define EHASH_hash(eh, item) (((uintptr_t)(item)) % ((unsigned int)(eh)->curSize)) - -/* Generic hash functions. */ - -EHash *ccg_ehash_new(int estimatedNumEntries, - CCGAllocatorIFC *allocatorIFC, - CCGAllocatorHDL allocator); -void ccg_ehash_free(EHash *eh, EHEntryFreeFP freeEntry, void *user_data); -void ccg_ehash_insert(EHash *eh, EHEntry *entry); -void *ccg_ehash_lookupWithPrev(EHash *eh, void *key, void ***prevp_r); -void *ccg_ehash_lookup(EHash *eh, void *key); - -/* Hash elements iteration. */ - -void ccg_ehashIterator_init(EHash *eh, EHashIterator *ehi); -void *ccg_ehashIterator_getCurrent(EHashIterator *ehi); -void ccg_ehashIterator_next(EHashIterator *ehi); -int ccg_ehashIterator_isStopped(EHashIterator *ehi); - -/** - * Standard allocator implementation. - */ - -CCGAllocatorIFC *ccg_getStandardAllocatorIFC(void); - -/** - * Catmull-Clark Gridding Subdivision Surface. - */ - -/* ** Data structures, constants. enums ** */ - -enum { - Vert_eEffected = (1 << 0), - Vert_eChanged = (1 << 1), - Vert_eSeam = (1 << 2), -} /*VertFlags*/; - -enum { - Edge_eEffected = (1 << 0), -} /*CCGEdgeFlags*/; - -enum { - Face_eEffected = (1 << 0), -} /*FaceFlags*/; - -struct CCGVert { - CCGVert *next; /* EHData.next */ - CCGVertHDL vHDL; /* EHData.key */ - - short numEdges, numFaces, flags; - int osd_index; /* Index of the vertex in the map, used by OSD. */ - - CCGEdge **edges; - CCGFace **faces; - // uint8_t *levelData; - // uint8_t *user_data; -}; - -struct CCGEdge { - CCGEdge *next; /* EHData.next */ - CCGEdgeHDL eHDL; /* EHData.key */ - - short numFaces, flags; - float crease; - - CCGVert *v0, *v1; - CCGFace **faces; - - // uint8_t *levelData; - // uint8_t *user_data; -}; - -struct CCGFace { - CCGFace *next; /* EHData.next */ - CCGFaceHDL fHDL; /* EHData.key */ - - short numVerts, flags; - int osd_index; - - // CCGVert **verts; - // CCGEdge **edges; - // uint8_t *centerData; - // uint8_t **gridData; - // uint8_t *user_data; -}; - -enum SyncState { - eSyncState_None = 0, - eSyncState_Vert, - eSyncState_Edge, - eSyncState_Face, - eSyncState_Partial, -}; - -struct CCGSubSurf { - EHash *vMap; /* map of CCGVertHDL -> Vert */ - EHash *eMap; /* map of CCGEdgeHDL -> Edge */ - EHash *fMap; /* map of CCGFaceHDL -> Face */ - - CCGMeshIFC meshIFC; - - CCGAllocatorIFC allocatorIFC; - CCGAllocatorHDL allocator; - - int subdivLevels; - int numGrids; - int allowEdgeCreation; - float defaultCreaseValue; - void *defaultEdgeUserData; - - void *q, *r; - - /* Data for calc vert normals. */ - int calcVertNormals; - int normalDataOffset; - - /* Data for paint masks. */ - int allocMask; - int maskDataOffset; - - /* Data for age'ing (to debug sync). */ - int currentAge; - int useAgeCounts; - int vertUserAgeOffset; - int edgeUserAgeOffset; - int faceUserAgeOffset; - - /* Data used during syncing. */ - SyncState syncState; - - EHash *oldVMap, *oldEMap, *oldFMap; - int lenTempArrays; - CCGVert **tempVerts; - CCGEdge **tempEdges; -}; - -/* ** Utility macros ** */ - -#define CCGSUBSURF_alloc(ss, nb) ((ss)->allocatorIFC.alloc((ss)->allocator, nb)) -#define CCGSUBSURF_realloc(ss, ptr, nb, ob) \ - ((ss)->allocatorIFC.realloc((ss)->allocator, ptr, nb, ob)) -#define CCGSUBSURF_free(ss, ptr) ((ss)->allocatorIFC.free((ss)->allocator, ptr)) - -#define VERT_getCo(v, lvl) (float *)ccg_vert_getCo(v, lvl, vertDataSize) -#define VERT_getNo(v, lvl) ccg_vert_getNo(v, lvl, vertDataSize, normalDataOffset) -#define EDGE_getCo(e, lvl, x) (float *)ccg_edge_getCo(e, lvl, x, vertDataSize) -#define EDGE_getNo(e, lvl, x) ccg_edge_getNo(e, lvl, x, vertDataSize, normalDataOffset) -#define FACE_getIFNo(f, lvl, S, x, y) \ - ccg_face_getIFNo(f, lvl, S, x, y, subdivLevels, vertDataSize, normalDataOffset) -#if 0 -# define FACE_calcIFNo(f, lvl, S, x, y, no) \ - _face_calcIFNo(f, lvl, S, x, y, no, subdivLevels, vertDataSize) -#endif -#define FACE_getIENo(f, lvl, S, x) \ - ccg_face_getIENo(f, lvl, S, x, subdivLevels, vertDataSize, normalDataOffset) -#define FACE_getIECo(f, lvl, S, x) \ - (float *)ccg_face_getIECo(f, lvl, S, x, subdivLevels, vertDataSize) -#define FACE_getIFCo(f, lvl, S, x, y) \ - (float *)ccg_face_getIFCo(f, lvl, S, x, y, subdivLevels, vertDataSize) - -#define NormZero(av) \ - { \ - float *_a = (float *)av; \ - _a[0] = _a[1] = _a[2] = 0.0f; \ - } \ - (void)0 -#define NormCopy(av, bv) \ - { \ - float *_a = (float *)av; \ - const float *_b = (const float *)bv; \ - _a[0] = _b[0]; \ - _a[1] = _b[1]; \ - _a[2] = _b[2]; \ - } \ - (void)0 -#define NormAdd(av, bv) \ - { \ - float *_a = (float *)av; \ - const float *_b = (const float *)bv; \ - _a[0] += _b[0]; \ - _a[1] += _b[1]; \ - _a[2] += _b[2]; \ - } \ - (void)0 - -/* ** General purpose functions ** */ - -/* `CCGSubSurf.cc` */ - -void ccgSubSurf__allFaces(CCGSubSurf *ss, CCGFace ***faces, int *numFaces, int *freeFaces); -void ccgSubSurf__effectedFaceNeighbors(CCGSubSurf *ss, - CCGFace **faces, - int numFaces, - CCGVert ***verts, - int *numVerts, - CCGEdge ***edges, - int *numEdges); - -/* `CCGSubSurf_legacy.cc` */ - -void ccgSubSurf__sync_legacy(CCGSubSurf *ss); - -/* `CCGSubSurf_util.cc` */ - -#ifdef DUMP_RESULT_GRIDS -void ccgSubSurf__dumpCoords(CCGSubSurf *ss); -#endif diff --git a/source/blender/blenkernel/intern/CCGSubSurf_legacy.cc b/source/blender/blenkernel/intern/CCGSubSurf_legacy.cc deleted file mode 100644 index 02f375eeadb..00000000000 --- a/source/blender/blenkernel/intern/CCGSubSurf_legacy.cc +++ /dev/null @@ -1,1371 +0,0 @@ -/* SPDX-FileCopyrightText: 2023 Blender Authors - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -/** \file - * \ingroup bke - */ - -#include - -#include "MEM_guardedalloc.h" - -#include "BLI_task.h" -#include "BLI_utildefines.h" /* for BLI_assert */ - -#include "CCGSubSurf.h" -#include "CCGSubSurf_inline.h" -#include "CCGSubSurf_intern.h" - -#define FACE_calcIFNo(f, lvl, S, x, y, no) \ - _face_calcIFNo(f, lvl, S, x, y, no, subdivLevels, vertDataSize) - -/* TODO(sergey): Deduplicate the following functions/ */ -static void *_edge_getCoVert(CCGEdge *e, CCGVert *v, int lvl, int x, int dataSize) -{ - int levelBase = ccg_edgebase(lvl); - if (v == e->v0) { - return &EDGE_getLevelData(e)[dataSize * (levelBase + x)]; - } - return &EDGE_getLevelData(e)[dataSize * (levelBase + (1 << lvl) - x)]; -} -/* *************************************************** */ - -static int _edge_isBoundary(const CCGEdge *e) -{ - return e->numFaces < 2; -} - -static bool _vert_isBoundary(const CCGVert *v) -{ - for (int i = 0; i < v->numEdges; i++) { - if (_edge_isBoundary(v->edges[i])) { - return true; - } - } - return false; -} - -static CCGVert *_edge_getOtherVert(CCGEdge *e, CCGVert *vQ) -{ - if (vQ == e->v0) { - return e->v1; - } - - return e->v0; -} - -static float *_face_getIFNoEdge(CCGFace *f, - CCGEdge *e, - int f_ed_idx, - int lvl, - int eX, - int eY, - int levels, - int dataSize, - int normalDataOffset) -{ - return (float *)((uint8_t *)ccg_face_getIFCoEdge(f, e, f_ed_idx, lvl, eX, eY, levels, dataSize) + - normalDataOffset); -} - -static void _face_calcIFNo( - CCGFace *f, int lvl, int S, int x, int y, float no[3], int levels, int dataSize) -{ - const float *a = static_cast( - ccg_face_getIFCo(f, lvl, S, x + 0, y + 0, levels, dataSize)); - const float *b = static_cast( - ccg_face_getIFCo(f, lvl, S, x + 1, y + 0, levels, dataSize)); - const float *c = static_cast( - ccg_face_getIFCo(f, lvl, S, x + 1, y + 1, levels, dataSize)); - const float *d = static_cast( - ccg_face_getIFCo(f, lvl, S, x + 0, y + 1, levels, dataSize)); - const float a_cX = c[0] - a[0], a_cY = c[1] - a[1], a_cZ = c[2] - a[2]; - const float b_dX = d[0] - b[0], b_dY = d[1] - b[1], b_dZ = d[2] - b[2]; - - no[0] = b_dY * a_cZ - b_dZ * a_cY; - no[1] = b_dZ * a_cX - b_dX * a_cZ; - no[2] = b_dX * a_cY - b_dY * a_cX; - - Normalize(no); -} - -static int VERT_seam(const CCGVert *v) -{ - return ((v->flags & Vert_eSeam) != 0); -} - -static float EDGE_getSharpness(CCGEdge *e, int lvl) -{ - if (!lvl) { - return e->crease; - } - if (!e->crease) { - return 0.0f; - } - if (e->crease - lvl < 0.0f) { - return 0.0f; - } - return e->crease - lvl; -} - -struct CCGSubSurfCalcSubdivData { - CCGSubSurf *ss; - CCGVert **effectedV; - CCGEdge **effectedE; - CCGFace **effectedF; - int numEffectedV; - int numEffectedE; - int numEffectedF; - - int curLvl; -}; - -static void ccgSubSurf__calcVertNormals_faces_accumulate_cb( - void *__restrict userdata, const int ptrIdx, const TaskParallelTLS *__restrict /*tls*/) -{ - CCGSubSurfCalcSubdivData *data = static_cast(userdata); - - CCGSubSurf *ss = data->ss; - CCGFace *f = data->effectedF[ptrIdx]; - - const int subdivLevels = ss->subdivLevels; - const int lvl = ss->subdivLevels; - const int gridSize = ccg_gridsize(lvl); - const int normalDataOffset = ss->normalDataOffset; - const int vertDataSize = ss->meshIFC.vertDataSize; - - int S, x, y; - float no[3]; - - for (S = 0; S < f->numVerts; S++) { - for (y = 0; y < gridSize - 1; y++) { - for (x = 0; x < gridSize - 1; x++) { - NormZero(FACE_getIFNo(f, lvl, S, x, y)); - } - } - - if (FACE_getEdges(f)[(S - 1 + f->numVerts) % f->numVerts]->flags & Edge_eEffected) { - for (x = 0; x < gridSize - 1; x++) { - NormZero(FACE_getIFNo(f, lvl, S, x, gridSize - 1)); - } - } - if (FACE_getEdges(f)[S]->flags & Edge_eEffected) { - for (y = 0; y < gridSize - 1; y++) { - NormZero(FACE_getIFNo(f, lvl, S, gridSize - 1, y)); - } - } - if (FACE_getVerts(f)[S]->flags & Vert_eEffected) { - NormZero(FACE_getIFNo(f, lvl, S, gridSize - 1, gridSize - 1)); - } - } - - for (S = 0; S < f->numVerts; S++) { - int yLimit = !(FACE_getEdges(f)[(S - 1 + f->numVerts) % f->numVerts]->flags & Edge_eEffected); - int xLimit = !(FACE_getEdges(f)[S]->flags & Edge_eEffected); - int yLimitNext = xLimit; - int xLimitPrev = yLimit; - - for (y = 0; y < gridSize - 1; y++) { - for (x = 0; x < gridSize - 1; x++) { - int xPlusOk = (!xLimit || x < gridSize - 2); - int yPlusOk = (!yLimit || y < gridSize - 2); - - FACE_calcIFNo(f, lvl, S, x, y, no); - - NormAdd(FACE_getIFNo(f, lvl, S, x + 0, y + 0), no); - if (xPlusOk) { - NormAdd(FACE_getIFNo(f, lvl, S, x + 1, y + 0), no); - } - if (yPlusOk) { - NormAdd(FACE_getIFNo(f, lvl, S, x + 0, y + 1), no); - } - if (xPlusOk && yPlusOk) { - if (x < gridSize - 2 || y < gridSize - 2 || FACE_getVerts(f)[S]->flags & Vert_eEffected) - { - NormAdd(FACE_getIFNo(f, lvl, S, x + 1, y + 1), no); - } - } - - if (x == 0 && y == 0) { - int K; - - if (!yLimitNext || 1 < gridSize - 1) { - NormAdd(FACE_getIFNo(f, lvl, (S + 1) % f->numVerts, 0, 1), no); - } - if (!xLimitPrev || 1 < gridSize - 1) { - NormAdd(FACE_getIFNo(f, lvl, (S - 1 + f->numVerts) % f->numVerts, 1, 0), no); - } - - for (K = 0; K < f->numVerts; K++) { - if (K != S) { - NormAdd(FACE_getIFNo(f, lvl, K, 0, 0), no); - } - } - } - else if (y == 0) { - NormAdd(FACE_getIFNo(f, lvl, (S + 1) % f->numVerts, 0, x), no); - if (!yLimitNext || x < gridSize - 2) { - NormAdd(FACE_getIFNo(f, lvl, (S + 1) % f->numVerts, 0, x + 1), no); - } - } - else if (x == 0) { - NormAdd(FACE_getIFNo(f, lvl, (S - 1 + f->numVerts) % f->numVerts, y, 0), no); - if (!xLimitPrev || y < gridSize - 2) { - NormAdd(FACE_getIFNo(f, lvl, (S - 1 + f->numVerts) % f->numVerts, y + 1, 0), no); - } - } - } - } - } -} - -static void ccgSubSurf__calcVertNormals_faces_finalize_cb( - void *__restrict userdata, const int ptrIdx, const TaskParallelTLS *__restrict /*tls*/) -{ - CCGSubSurfCalcSubdivData *data = static_cast(userdata); - - CCGSubSurf *ss = data->ss; - CCGFace *f = data->effectedF[ptrIdx]; - - const int subdivLevels = ss->subdivLevels; - const int lvl = ss->subdivLevels; - const int gridSize = ccg_gridsize(lvl); - const int normalDataOffset = ss->normalDataOffset; - const int vertDataSize = ss->meshIFC.vertDataSize; - - int S, x, y; - - for (S = 0; S < f->numVerts; S++) { - NormCopy(FACE_getIFNo(f, lvl, (S + 1) % f->numVerts, 0, gridSize - 1), - FACE_getIFNo(f, lvl, S, gridSize - 1, 0)); - } - - for (S = 0; S < f->numVerts; S++) { - for (y = 0; y < gridSize; y++) { - for (x = 0; x < gridSize; x++) { - float *no = FACE_getIFNo(f, lvl, S, x, y); - Normalize(no); - } - } - - VertDataCopy( - (float *)(FACE_getCenterData(f) + normalDataOffset), FACE_getIFNo(f, lvl, S, 0, 0), ss); - - for (x = 1; x < gridSize - 1; x++) { - NormCopy(FACE_getIENo(f, lvl, S, x), FACE_getIFNo(f, lvl, S, x, 0)); - } - } -} - -static void ccgSubSurf__calcVertNormals_edges_accumulate_cb( - void *__restrict userdata, const int ptrIdx, const TaskParallelTLS *__restrict /*tls*/) -{ - CCGSubSurfCalcSubdivData *data = static_cast(userdata); - - CCGSubSurf *ss = data->ss; - CCGEdge *e = data->effectedE[ptrIdx]; - - const int subdivLevels = ss->subdivLevels; - const int lvl = ss->subdivLevels; - const int edgeSize = ccg_edgesize(lvl); - const int normalDataOffset = ss->normalDataOffset; - const int vertDataSize = ss->meshIFC.vertDataSize; - - if (e->numFaces) { - CCGFace *fLast = e->faces[e->numFaces - 1]; - int x, i; - - for (i = 0; i < e->numFaces - 1; i++) { - CCGFace *f = e->faces[i]; - const int f_ed_idx = ccg_face_getEdgeIndex(f, e); - const int f_ed_idx_last = ccg_face_getEdgeIndex(fLast, e); - - for (x = 1; x < edgeSize - 1; x++) { - NormAdd( - _face_getIFNoEdge( - fLast, e, f_ed_idx_last, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset), - _face_getIFNoEdge( - f, e, f_ed_idx, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset)); - } - } - - for (i = 0; i < e->numFaces - 1; i++) { - CCGFace *f = e->faces[i]; - const int f_ed_idx = ccg_face_getEdgeIndex(f, e); - const int f_ed_idx_last = ccg_face_getEdgeIndex(fLast, e); - - for (x = 1; x < edgeSize - 1; x++) { - NormCopy( - _face_getIFNoEdge( - f, e, f_ed_idx, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset), - _face_getIFNoEdge( - fLast, e, f_ed_idx_last, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset)); - } - } - } -} - -static void ccgSubSurf__calcVertNormals(CCGSubSurf *ss, - CCGVert **effectedV, - CCGEdge **effectedE, - CCGFace **effectedF, - int numEffectedV, - int numEffectedE, - int numEffectedF) -{ - int i, ptrIdx; - const int subdivLevels = ss->subdivLevels; - const int lvl = ss->subdivLevels; - const int edgeSize = ccg_edgesize(lvl); - const int gridSize = ccg_gridsize(lvl); - const int normalDataOffset = ss->normalDataOffset; - const int vertDataSize = ss->meshIFC.vertDataSize; - - CCGSubSurfCalcSubdivData data{}; - data.ss = ss; - data.effectedV = effectedV; - data.effectedE = effectedE; - data.effectedF = effectedF; - data.numEffectedV = numEffectedV; - data.numEffectedE = numEffectedE; - data.numEffectedF = numEffectedF; - - { - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.min_iter_per_thread = CCG_TASK_LIMIT; - BLI_task_parallel_range( - 0, numEffectedF, &data, ccgSubSurf__calcVertNormals_faces_accumulate_cb, &settings); - } - - /* XXX can I reduce the number of normalization calls here? */ - for (ptrIdx = 0; ptrIdx < numEffectedV; ptrIdx++) { - CCGVert *v = effectedV[ptrIdx]; - float *no = VERT_getNo(v, lvl); - - NormZero(no); - - for (i = 0; i < v->numFaces; i++) { - CCGFace *f = v->faces[i]; - NormAdd(no, FACE_getIFNo(f, lvl, ccg_face_getVertIndex(f, v), gridSize - 1, gridSize - 1)); - } - - if (UNLIKELY(v->numFaces == 0)) { - NormCopy(no, VERT_getCo(v, lvl)); - } - - Normalize(no); - - for (i = 0; i < v->numFaces; i++) { - CCGFace *f = v->faces[i]; - NormCopy(FACE_getIFNo(f, lvl, ccg_face_getVertIndex(f, v), gridSize - 1, gridSize - 1), no); - } - } - - { - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.min_iter_per_thread = CCG_TASK_LIMIT; - BLI_task_parallel_range( - 0, numEffectedE, &data, ccgSubSurf__calcVertNormals_edges_accumulate_cb, &settings); - } - - { - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.min_iter_per_thread = CCG_TASK_LIMIT; - BLI_task_parallel_range( - 0, numEffectedF, &data, ccgSubSurf__calcVertNormals_faces_finalize_cb, &settings); - } - - for (ptrIdx = 0; ptrIdx < numEffectedE; ptrIdx++) { - CCGEdge *e = effectedE[ptrIdx]; - - if (e->numFaces) { - CCGFace *f = e->faces[0]; - int x; - const int f_ed_idx = ccg_face_getEdgeIndex(f, e); - - for (x = 0; x < edgeSize; x++) { - NormCopy(EDGE_getNo(e, lvl, x), - _face_getIFNoEdge( - f, e, f_ed_idx, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset)); - } - } - else { - /* set to zero here otherwise the normals are uninitialized memory - * render: tests/animation/knight.blend with valgrind. - * we could be more clever and interpolate vertex normals but these are - * most likely not used so just zero out. */ - int x; - - for (x = 0; x < edgeSize; x++) { - float *no = EDGE_getNo(e, lvl, x); - NormCopy(no, EDGE_getCo(e, lvl, x)); - Normalize(no); - } - } - } -} - -static void ccgSubSurf__calcSubdivLevel_interior_faces_edges_midpoints_cb( - void *__restrict userdata, const int ptrIdx, const TaskParallelTLS *__restrict /*tls*/) -{ - CCGSubSurfCalcSubdivData *data = static_cast(userdata); - - CCGSubSurf *ss = data->ss; - CCGFace *f = data->effectedF[ptrIdx]; - - const int subdivLevels = ss->subdivLevels; - const int curLvl = data->curLvl; - const int nextLvl = curLvl + 1; - const int gridSize = ccg_gridsize(curLvl); - const int vertDataSize = ss->meshIFC.vertDataSize; - - int S, x, y; - - /* interior face midpoints - * - old interior face points - */ - for (S = 0; S < f->numVerts; S++) { - for (y = 0; y < gridSize - 1; y++) { - for (x = 0; x < gridSize - 1; x++) { - int fx = 1 + 2 * x; - int fy = 1 + 2 * y; - const float *co0 = FACE_getIFCo(f, curLvl, S, x + 0, y + 0); - const float *co1 = FACE_getIFCo(f, curLvl, S, x + 1, y + 0); - const float *co2 = FACE_getIFCo(f, curLvl, S, x + 1, y + 1); - const float *co3 = FACE_getIFCo(f, curLvl, S, x + 0, y + 1); - float *co = FACE_getIFCo(f, nextLvl, S, fx, fy); - - VertDataAvg4(co, co0, co1, co2, co3, ss); - } - } - } - - /* interior edge midpoints - * - old interior edge points - * - new interior face midpoints - */ - for (S = 0; S < f->numVerts; S++) { - for (x = 0; x < gridSize - 1; x++) { - int fx = x * 2 + 1; - const float *co0 = FACE_getIECo(f, curLvl, S, x + 0); - const float *co1 = FACE_getIECo(f, curLvl, S, x + 1); - const float *co2 = FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 1, fx); - const float *co3 = FACE_getIFCo(f, nextLvl, S, fx, 1); - float *co = FACE_getIECo(f, nextLvl, S, fx); - - VertDataAvg4(co, co0, co1, co2, co3, ss); - } - - /* interior face interior edge midpoints - * - old interior face points - * - new interior face midpoints - */ - - /* vertical */ - for (x = 1; x < gridSize - 1; x++) { - for (y = 0; y < gridSize - 1; y++) { - int fx = x * 2; - int fy = y * 2 + 1; - const float *co0 = FACE_getIFCo(f, curLvl, S, x, y + 0); - const float *co1 = FACE_getIFCo(f, curLvl, S, x, y + 1); - const float *co2 = FACE_getIFCo(f, nextLvl, S, fx - 1, fy); - const float *co3 = FACE_getIFCo(f, nextLvl, S, fx + 1, fy); - float *co = FACE_getIFCo(f, nextLvl, S, fx, fy); - - VertDataAvg4(co, co0, co1, co2, co3, ss); - } - } - - /* horizontal */ - for (y = 1; y < gridSize - 1; y++) { - for (x = 0; x < gridSize - 1; x++) { - int fx = x * 2 + 1; - int fy = y * 2; - const float *co0 = FACE_getIFCo(f, curLvl, S, x + 0, y); - const float *co1 = FACE_getIFCo(f, curLvl, S, x + 1, y); - const float *co2 = FACE_getIFCo(f, nextLvl, S, fx, fy - 1); - const float *co3 = FACE_getIFCo(f, nextLvl, S, fx, fy + 1); - float *co = FACE_getIFCo(f, nextLvl, S, fx, fy); - - VertDataAvg4(co, co0, co1, co2, co3, ss); - } - } - } -} - -static void ccgSubSurf__calcSubdivLevel_interior_faces_edges_centerpoints_shift_cb( - void *__restrict userdata, const int ptrIdx, const TaskParallelTLS *__restrict /*tls*/) -{ - CCGSubSurfCalcSubdivData *data = static_cast(userdata); - - CCGSubSurf *ss = data->ss; - CCGFace *f = data->effectedF[ptrIdx]; - - const int subdivLevels = ss->subdivLevels; - const int curLvl = data->curLvl; - const int nextLvl = curLvl + 1; - const int gridSize = ccg_gridsize(curLvl); - const int vertDataSize = ss->meshIFC.vertDataSize; - - float *q_thread = static_cast(alloca(vertDataSize)); - float *r_thread = static_cast(alloca(vertDataSize)); - - int S, x, y; - - /* interior center point shift - * - old face center point (shifting) - * - old interior edge points - * - new interior face midpoints - */ - VertDataZero(q_thread, ss); - for (S = 0; S < f->numVerts; S++) { - VertDataAdd(q_thread, FACE_getIFCo(f, nextLvl, S, 1, 1), ss); - } - VertDataMulN(q_thread, 1.0f / f->numVerts, ss); - VertDataZero(r_thread, ss); - for (S = 0; S < f->numVerts; S++) { - VertDataAdd(r_thread, FACE_getIECo(f, curLvl, S, 1), ss); - } - VertDataMulN(r_thread, 1.0f / f->numVerts, ss); - - VertDataMulN((float *)FACE_getCenterData(f), f->numVerts - 2.0f, ss); - VertDataAdd((float *)FACE_getCenterData(f), q_thread, ss); - VertDataAdd((float *)FACE_getCenterData(f), r_thread, ss); - VertDataMulN((float *)FACE_getCenterData(f), 1.0f / f->numVerts, ss); - - for (S = 0; S < f->numVerts; S++) { - /* interior face shift - * - old interior face point (shifting) - * - new interior edge midpoints - * - new interior face midpoints - */ - for (x = 1; x < gridSize - 1; x++) { - for (y = 1; y < gridSize - 1; y++) { - int fx = x * 2; - int fy = y * 2; - const float *co = FACE_getIFCo(f, curLvl, S, x, y); - float *nCo = FACE_getIFCo(f, nextLvl, S, fx, fy); - - VertDataAvg4(q_thread, - FACE_getIFCo(f, nextLvl, S, fx - 1, fy - 1), - FACE_getIFCo(f, nextLvl, S, fx + 1, fy - 1), - FACE_getIFCo(f, nextLvl, S, fx + 1, fy + 1), - FACE_getIFCo(f, nextLvl, S, fx - 1, fy + 1), - ss); - - VertDataAvg4(r_thread, - FACE_getIFCo(f, nextLvl, S, fx - 1, fy + 0), - FACE_getIFCo(f, nextLvl, S, fx + 1, fy + 0), - FACE_getIFCo(f, nextLvl, S, fx + 0, fy - 1), - FACE_getIFCo(f, nextLvl, S, fx + 0, fy + 1), - ss); - - VertDataCopy(nCo, co, ss); - VertDataSub(nCo, q_thread, ss); - VertDataMulN(nCo, 0.25f, ss); - VertDataAdd(nCo, r_thread, ss); - } - } - - /* interior edge interior shift - * - old interior edge point (shifting) - * - new interior edge midpoints - * - new interior face midpoints - */ - for (x = 1; x < gridSize - 1; x++) { - int fx = x * 2; - const float *co = FACE_getIECo(f, curLvl, S, x); - float *nCo = FACE_getIECo(f, nextLvl, S, fx); - - VertDataAvg4(q_thread, - FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 1, fx - 1), - FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 1, fx + 1), - FACE_getIFCo(f, nextLvl, S, fx + 1, +1), - FACE_getIFCo(f, nextLvl, S, fx - 1, +1), - ss); - - VertDataAvg4(r_thread, - FACE_getIECo(f, nextLvl, S, fx - 1), - FACE_getIECo(f, nextLvl, S, fx + 1), - FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 1, fx), - FACE_getIFCo(f, nextLvl, S, fx, 1), - ss); - - VertDataCopy(nCo, co, ss); - VertDataSub(nCo, q_thread, ss); - VertDataMulN(nCo, 0.25f, ss); - VertDataAdd(nCo, r_thread, ss); - } - } -} - -static void ccgSubSurf__calcSubdivLevel_verts_copydata_cb( - void *__restrict userdata, const int ptrIdx, const TaskParallelTLS *__restrict /*tls*/) -{ - CCGSubSurfCalcSubdivData *data = static_cast(userdata); - - CCGSubSurf *ss = data->ss; - CCGFace *f = data->effectedF[ptrIdx]; - - const int subdivLevels = ss->subdivLevels; - const int nextLvl = data->curLvl + 1; - const int gridSize = ccg_gridsize(nextLvl); - const int cornerIdx = gridSize - 1; - const int vertDataSize = ss->meshIFC.vertDataSize; - - int S, x; - - for (S = 0; S < f->numVerts; S++) { - CCGEdge *e = FACE_getEdges(f)[S]; - CCGEdge *prevE = FACE_getEdges(f)[(S + f->numVerts - 1) % f->numVerts]; - - VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 0), (float *)FACE_getCenterData(f), ss); - VertDataCopy(FACE_getIECo(f, nextLvl, S, 0), (float *)FACE_getCenterData(f), ss); - VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, cornerIdx), - VERT_getCo(FACE_getVerts(f)[S], nextLvl), - ss); - VertDataCopy(FACE_getIECo(f, nextLvl, S, cornerIdx), - EDGE_getCo(FACE_getEdges(f)[S], nextLvl, cornerIdx), - ss); - for (x = 1; x < gridSize - 1; x++) { - float *co = FACE_getIECo(f, nextLvl, S, x); - VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, 0), co, ss); - VertDataCopy(FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 0, x), co, ss); - } - for (x = 0; x < gridSize - 1; x++) { - int eI = gridSize - 1 - x; - VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, x), - static_cast( - _edge_getCoVert(e, FACE_getVerts(f)[S], nextLvl, eI, vertDataSize)), - ss); - VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, cornerIdx), - static_cast( - _edge_getCoVert(prevE, FACE_getVerts(f)[S], nextLvl, eI, vertDataSize)), - ss); - } - } -} - -static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss, - CCGVert **effectedV, - CCGEdge **effectedE, - CCGFace **effectedF, - const int numEffectedV, - const int numEffectedE, - const int numEffectedF, - const int curLvl) -{ - const int subdivLevels = ss->subdivLevels; - const int nextLvl = curLvl + 1; - int edgeSize = ccg_edgesize(curLvl); - int ptrIdx, i; - const int vertDataSize = ss->meshIFC.vertDataSize; - float *q = static_cast(ss->q), *r = static_cast(ss->r); - - CCGSubSurfCalcSubdivData data{}; - data.ss = ss; - data.effectedV = effectedV; - data.effectedE = effectedE; - data.effectedF = effectedF; - data.numEffectedV = numEffectedV; - data.numEffectedE = numEffectedE; - data.numEffectedF = numEffectedF; - data.curLvl = curLvl; - - { - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.min_iter_per_thread = CCG_TASK_LIMIT; - BLI_task_parallel_range(0, - numEffectedF, - &data, - ccgSubSurf__calcSubdivLevel_interior_faces_edges_midpoints_cb, - &settings); - } - - /* exterior edge midpoints - * - old exterior edge points - * - new interior face midpoints - */ - /* Not worth parallelizing. */ - for (ptrIdx = 0; ptrIdx < numEffectedE; ptrIdx++) { - CCGEdge *e = effectedE[ptrIdx]; - float sharpness = EDGE_getSharpness(e, curLvl); - int x, j; - - if (_edge_isBoundary(e) || sharpness > 1.0f) { - for (x = 0; x < edgeSize - 1; x++) { - int fx = x * 2 + 1; - const float *co0 = EDGE_getCo(e, curLvl, x + 0); - const float *co1 = EDGE_getCo(e, curLvl, x + 1); - float *co = EDGE_getCo(e, nextLvl, fx); - - VertDataCopy(co, co0, ss); - VertDataAdd(co, co1, ss); - VertDataMulN(co, 0.5f, ss); - } - } - else { - for (x = 0; x < edgeSize - 1; x++) { - int fx = x * 2 + 1; - const float *co0 = EDGE_getCo(e, curLvl, x + 0); - const float *co1 = EDGE_getCo(e, curLvl, x + 1); - float *co = EDGE_getCo(e, nextLvl, fx); - int numFaces = 0; - - VertDataCopy(q, co0, ss); - VertDataAdd(q, co1, ss); - - for (j = 0; j < e->numFaces; j++) { - CCGFace *f = e->faces[j]; - const int f_ed_idx = ccg_face_getEdgeIndex(f, e); - VertDataAdd(q, - static_cast(ccg_face_getIFCoEdge( - f, e, f_ed_idx, nextLvl, fx, 1, subdivLevels, vertDataSize)), - ss); - numFaces++; - } - - VertDataMulN(q, 1.0f / (2.0f + numFaces), ss); - - VertDataCopy(r, co0, ss); - VertDataAdd(r, co1, ss); - VertDataMulN(r, 0.5f, ss); - - VertDataCopy(co, q, ss); - VertDataSub(r, q, ss); - VertDataMulN(r, sharpness, ss); - VertDataAdd(co, r, ss); - } - } - } - - /* exterior vertex shift - * - old vertex points (shifting) - * - old exterior edge points - * - new interior face midpoints - */ - /* Not worth parallelizing. */ - for (ptrIdx = 0; ptrIdx < numEffectedV; ptrIdx++) { - CCGVert *v = effectedV[ptrIdx]; - const float *co = VERT_getCo(v, curLvl); - float *nCo = VERT_getCo(v, nextLvl); - int sharpCount = 0, allSharp = 1; - float avgSharpness = 0.0; - int j, seam = VERT_seam(v), seamEdges = 0; - - for (j = 0; j < v->numEdges; j++) { - CCGEdge *e = v->edges[j]; - float sharpness = EDGE_getSharpness(e, curLvl); - - if (seam && _edge_isBoundary(e)) { - seamEdges++; - } - - if (sharpness != 0.0f) { - sharpCount++; - avgSharpness += sharpness; - } - else { - allSharp = 0; - } - } - - if (sharpCount) { - avgSharpness /= sharpCount; - avgSharpness = std::min(avgSharpness, 1.0f); - } - - if (seamEdges < 2 || seamEdges != v->numEdges) { - seam = 0; - } - - if (!v->numEdges || ss->meshIFC.simpleSubdiv) { - VertDataCopy(nCo, co, ss); - } - else if (_vert_isBoundary(v)) { - int numBoundary = 0; - - VertDataZero(r, ss); - for (j = 0; j < v->numEdges; j++) { - CCGEdge *e = v->edges[j]; - if (_edge_isBoundary(e)) { - VertDataAdd( - r, static_cast(_edge_getCoVert(e, v, curLvl, 1, vertDataSize)), ss); - numBoundary++; - } - } - - VertDataCopy(nCo, co, ss); - VertDataMulN(nCo, 0.75f, ss); - VertDataMulN(r, 0.25f / numBoundary, ss); - VertDataAdd(nCo, r, ss); - } - else { - const int cornerIdx = (1 + (1 << (curLvl))) - 2; - int numEdges = 0, numFaces = 0; - - VertDataZero(q, ss); - for (j = 0; j < v->numFaces; j++) { - CCGFace *f = v->faces[j]; - VertDataAdd( - q, FACE_getIFCo(f, nextLvl, ccg_face_getVertIndex(f, v), cornerIdx, cornerIdx), ss); - numFaces++; - } - VertDataMulN(q, 1.0f / numFaces, ss); - VertDataZero(r, ss); - for (j = 0; j < v->numEdges; j++) { - CCGEdge *e = v->edges[j]; - VertDataAdd( - r, static_cast(_edge_getCoVert(e, v, curLvl, 1, vertDataSize)), ss); - numEdges++; - } - VertDataMulN(r, 1.0f / numEdges, ss); - - VertDataCopy(nCo, co, ss); - VertDataMulN(nCo, numEdges - 2.0f, ss); - VertDataAdd(nCo, q, ss); - VertDataAdd(nCo, r, ss); - VertDataMulN(nCo, 1.0f / numEdges, ss); - } - - if ((sharpCount > 1 && v->numFaces) || seam) { - VertDataZero(q, ss); - - if (seam) { - avgSharpness = 1.0f; - sharpCount = seamEdges; - allSharp = 1; - } - - for (j = 0; j < v->numEdges; j++) { - CCGEdge *e = v->edges[j]; - float sharpness = EDGE_getSharpness(e, curLvl); - - if (seam) { - if (_edge_isBoundary(e)) { - VertDataAdd( - q, static_cast(_edge_getCoVert(e, v, curLvl, 1, vertDataSize)), ss); - } - } - else if (sharpness != 0.0f) { - VertDataAdd( - q, static_cast(_edge_getCoVert(e, v, curLvl, 1, vertDataSize)), ss); - } - } - - VertDataMulN(q, float(1) / sharpCount, ss); - - if (sharpCount != 2 || allSharp) { - /* q = q + (co - q) * avgSharpness */ - VertDataCopy(r, co, ss); - VertDataSub(r, q, ss); - VertDataMulN(r, avgSharpness, ss); - VertDataAdd(q, r, ss); - } - - /* r = co * 0.75 + q * 0.25 */ - VertDataCopy(r, co, ss); - VertDataMulN(r, 0.75f, ss); - VertDataMulN(q, 0.25f, ss); - VertDataAdd(r, q, ss); - - /* nCo = nCo + (r - nCo) * avgSharpness */ - VertDataSub(r, nCo, ss); - VertDataMulN(r, avgSharpness, ss); - VertDataAdd(nCo, r, ss); - } - } - - /* exterior edge interior shift - * - old exterior edge midpoints (shifting) - * - old exterior edge midpoints - * - new interior face midpoints - */ - /* Not worth parallelizing. */ - for (ptrIdx = 0; ptrIdx < numEffectedE; ptrIdx++) { - CCGEdge *e = effectedE[ptrIdx]; - float sharpness = EDGE_getSharpness(e, curLvl); - int sharpCount = 0; - float avgSharpness = 0.0; - int x, j; - - if (sharpness != 0.0f) { - sharpCount = 2; - avgSharpness += sharpness; - - avgSharpness = std::min(avgSharpness, 1.0f); - } - else { - sharpCount = 0; - avgSharpness = 0; - } - - if (_edge_isBoundary(e)) { - for (x = 1; x < edgeSize - 1; x++) { - int fx = x * 2; - const float *co = EDGE_getCo(e, curLvl, x); - float *nCo = EDGE_getCo(e, nextLvl, fx); - - /* Average previous level's endpoints */ - VertDataCopy(r, EDGE_getCo(e, curLvl, x - 1), ss); - VertDataAdd(r, EDGE_getCo(e, curLvl, x + 1), ss); - VertDataMulN(r, 0.5f, ss); - - /* nCo = nCo * 0.75 + r * 0.25 */ - VertDataCopy(nCo, co, ss); - VertDataMulN(nCo, 0.75f, ss); - VertDataMulN(r, 0.25f, ss); - VertDataAdd(nCo, r, ss); - } - } - else { - for (x = 1; x < edgeSize - 1; x++) { - int fx = x * 2; - const float *co = EDGE_getCo(e, curLvl, x); - float *nCo = EDGE_getCo(e, nextLvl, fx); - int numFaces = 0; - - VertDataZero(q, ss); - VertDataZero(r, ss); - VertDataAdd(r, EDGE_getCo(e, curLvl, x - 1), ss); - VertDataAdd(r, EDGE_getCo(e, curLvl, x + 1), ss); - for (j = 0; j < e->numFaces; j++) { - CCGFace *f = e->faces[j]; - int f_ed_idx = ccg_face_getEdgeIndex(f, e); - VertDataAdd(q, - static_cast(ccg_face_getIFCoEdge( - f, e, f_ed_idx, nextLvl, fx - 1, 1, subdivLevels, vertDataSize)), - ss); - VertDataAdd(q, - static_cast(ccg_face_getIFCoEdge( - f, e, f_ed_idx, nextLvl, fx + 1, 1, subdivLevels, vertDataSize)), - ss); - - VertDataAdd(r, - static_cast(ccg_face_getIFCoEdge( - f, e, f_ed_idx, curLvl, x, 1, subdivLevels, vertDataSize)), - ss); - numFaces++; - } - VertDataMulN(q, 1.0f / (numFaces * 2.0f), ss); - VertDataMulN(r, 1.0f / (2.0f + numFaces), ss); - - VertDataCopy(nCo, co, ss); - VertDataMulN(nCo, float(numFaces), ss); - VertDataAdd(nCo, q, ss); - VertDataAdd(nCo, r, ss); - VertDataMulN(nCo, 1.0f / (2 + numFaces), ss); - - if (sharpCount == 2) { - VertDataCopy(q, co, ss); - VertDataMulN(q, 6.0f, ss); - VertDataAdd(q, EDGE_getCo(e, curLvl, x - 1), ss); - VertDataAdd(q, EDGE_getCo(e, curLvl, x + 1), ss); - VertDataMulN(q, 1 / 8.0f, ss); - - VertDataSub(q, nCo, ss); - VertDataMulN(q, avgSharpness, ss); - VertDataAdd(nCo, q, ss); - } - } - } - } - - { - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.min_iter_per_thread = CCG_TASK_LIMIT; - BLI_task_parallel_range(0, - numEffectedF, - &data, - ccgSubSurf__calcSubdivLevel_interior_faces_edges_centerpoints_shift_cb, - &settings); - } - - /* copy down */ - edgeSize = ccg_edgesize(nextLvl); - - /* Not worth parallelizing. */ - for (i = 0; i < numEffectedE; i++) { - CCGEdge *e = effectedE[i]; - VertDataCopy(EDGE_getCo(e, nextLvl, 0), VERT_getCo(e->v0, nextLvl), ss); - VertDataCopy(EDGE_getCo(e, nextLvl, edgeSize - 1), VERT_getCo(e->v1, nextLvl), ss); - } - - { - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.min_iter_per_thread = CCG_TASK_LIMIT; - BLI_task_parallel_range( - 0, numEffectedF, &data, ccgSubSurf__calcSubdivLevel_verts_copydata_cb, &settings); - } -} - -void ccgSubSurf__sync_legacy(CCGSubSurf *ss) -{ - CCGVert **effectedV; - CCGEdge **effectedE; - CCGFace **effectedF; - int numEffectedV, numEffectedE, numEffectedF; - int subdivLevels = ss->subdivLevels; - int vertDataSize = ss->meshIFC.vertDataSize; - int i, j, ptrIdx, S; - int curLvl, nextLvl; - void *q = ss->q, *r = ss->r; - - effectedV = MEM_malloc_arrayN(size_t(ss->vMap->numEntries), "CCGSubsurf effectedV"); - effectedE = MEM_malloc_arrayN(size_t(ss->eMap->numEntries), "CCGSubsurf effectedE"); - effectedF = MEM_malloc_arrayN(size_t(ss->fMap->numEntries), "CCGSubsurf effectedF"); - numEffectedV = numEffectedE = numEffectedF = 0; - for (i = 0; i < ss->vMap->curSize; i++) { - CCGVert *v = (CCGVert *)ss->vMap->buckets[i]; - for (; v; v = v->next) { - if (v->flags & Vert_eEffected) { - effectedV[numEffectedV++] = v; - - for (j = 0; j < v->numEdges; j++) { - CCGEdge *e = v->edges[j]; - if (!(e->flags & Edge_eEffected)) { - effectedE[numEffectedE++] = e; - e->flags |= Edge_eEffected; - } - } - - for (j = 0; j < v->numFaces; j++) { - CCGFace *f = v->faces[j]; - if (!(f->flags & Face_eEffected)) { - effectedF[numEffectedF++] = f; - f->flags |= Face_eEffected; - } - } - } - } - } - - curLvl = 0; - nextLvl = curLvl + 1; - - for (ptrIdx = 0; ptrIdx < numEffectedF; ptrIdx++) { - CCGFace *f = effectedF[ptrIdx]; - void *co = FACE_getCenterData(f); - VertDataZero(static_cast(co), ss); - for (i = 0; i < f->numVerts; i++) { - VertDataAdd(static_cast(co), VERT_getCo(FACE_getVerts(f)[i], curLvl), ss); - } - VertDataMulN(static_cast(co), 1.0f / f->numVerts, ss); - - f->flags = 0; - } - for (ptrIdx = 0; ptrIdx < numEffectedE; ptrIdx++) { - CCGEdge *e = effectedE[ptrIdx]; - void *co = EDGE_getCo(e, nextLvl, 1); - float sharpness = EDGE_getSharpness(e, curLvl); - - if (_edge_isBoundary(e) || sharpness >= 1.0f) { - VertDataCopy(static_cast(co), VERT_getCo(e->v0, curLvl), ss); - VertDataAdd(static_cast(co), VERT_getCo(e->v1, curLvl), ss); - VertDataMulN(static_cast(co), 0.5f, ss); - } - else { - int numFaces = 0; - VertDataCopy(static_cast(q), VERT_getCo(e->v0, curLvl), ss); - VertDataAdd(static_cast(q), VERT_getCo(e->v1, curLvl), ss); - for (i = 0; i < e->numFaces; i++) { - CCGFace *f = e->faces[i]; - VertDataAdd(static_cast(q), (float *)FACE_getCenterData(f), ss); - numFaces++; - } - VertDataMulN(static_cast(q), 1.0f / (2.0f + numFaces), ss); - - VertDataCopy(static_cast(r), VERT_getCo(e->v0, curLvl), ss); - VertDataAdd(static_cast(r), VERT_getCo(e->v1, curLvl), ss); - VertDataMulN(static_cast(r), 0.5f, ss); - - VertDataCopy(static_cast(co), static_cast(q), ss); - VertDataSub(static_cast(r), static_cast(q), ss); - VertDataMulN(static_cast(r), sharpness, ss); - VertDataAdd(static_cast(co), static_cast(r), ss); - } - - /* edge flags cleared later */ - } - for (ptrIdx = 0; ptrIdx < numEffectedV; ptrIdx++) { - CCGVert *v = effectedV[ptrIdx]; - void *co = VERT_getCo(v, curLvl); - void *nCo = VERT_getCo(v, nextLvl); - int sharpCount = 0, allSharp = 1; - float avgSharpness = 0.0; - int seam = VERT_seam(v), seamEdges = 0; - - for (i = 0; i < v->numEdges; i++) { - CCGEdge *e = v->edges[i]; - float sharpness = EDGE_getSharpness(e, curLvl); - - if (seam && _edge_isBoundary(e)) { - seamEdges++; - } - - if (sharpness != 0.0f) { - sharpCount++; - avgSharpness += sharpness; - } - else { - allSharp = 0; - } - } - - if (sharpCount) { - avgSharpness /= sharpCount; - avgSharpness = std::min(avgSharpness, 1.0f); - } - - if (seamEdges < 2 || seamEdges != v->numEdges) { - seam = 0; - } - - if (!v->numEdges || ss->meshIFC.simpleSubdiv) { - VertDataCopy(static_cast(nCo), static_cast(co), ss); - } - else if (_vert_isBoundary(v)) { - int numBoundary = 0; - - VertDataZero(static_cast(r), ss); - for (i = 0; i < v->numEdges; i++) { - CCGEdge *e = v->edges[i]; - if (_edge_isBoundary(e)) { - VertDataAdd(static_cast(r), VERT_getCo(_edge_getOtherVert(e, v), curLvl), ss); - numBoundary++; - } - } - VertDataCopy(static_cast(nCo), static_cast(co), ss); - VertDataMulN(static_cast(nCo), 0.75f, ss); - VertDataMulN(static_cast(r), 0.25f / numBoundary, ss); - VertDataAdd(static_cast(nCo), static_cast(r), ss); - } - else { - int numEdges = 0, numFaces = 0; - - VertDataZero(static_cast(q), ss); - for (i = 0; i < v->numFaces; i++) { - CCGFace *f = v->faces[i]; - VertDataAdd(static_cast(q), (float *)FACE_getCenterData(f), ss); - numFaces++; - } - VertDataMulN(static_cast(q), 1.0f / numFaces, ss); - VertDataZero(static_cast(r), ss); - for (i = 0; i < v->numEdges; i++) { - CCGEdge *e = v->edges[i]; - VertDataAdd(static_cast(r), VERT_getCo(_edge_getOtherVert(e, v), curLvl), ss); - numEdges++; - } - VertDataMulN(static_cast(r), 1.0f / numEdges, ss); - - VertDataCopy(static_cast(nCo), static_cast(co), ss); - VertDataMulN(static_cast(nCo), numEdges - 2.0f, ss); - VertDataAdd(static_cast(nCo), static_cast(q), ss); - VertDataAdd(static_cast(nCo), static_cast(r), ss); - VertDataMulN(static_cast(nCo), 1.0f / numEdges, ss); - } - - if (sharpCount > 1 || seam) { - VertDataZero(static_cast(q), ss); - - if (seam) { - avgSharpness = 1.0f; - sharpCount = seamEdges; - allSharp = 1; - } - - for (i = 0; i < v->numEdges; i++) { - CCGEdge *e = v->edges[i]; - float sharpness = EDGE_getSharpness(e, curLvl); - - if (seam) { - if (_edge_isBoundary(e)) { - CCGVert *oV = _edge_getOtherVert(e, v); - VertDataAdd(static_cast(q), VERT_getCo(oV, curLvl), ss); - } - } - else if (sharpness != 0.0f) { - CCGVert *oV = _edge_getOtherVert(e, v); - VertDataAdd(static_cast(q), VERT_getCo(oV, curLvl), ss); - } - } - - VertDataMulN(static_cast(q), float(1) / sharpCount, ss); - - if (sharpCount != 2 || allSharp) { - /* q = q + (co - q) * avgSharpness */ - VertDataCopy(static_cast(r), static_cast(co), ss); - VertDataSub(static_cast(r), static_cast(q), ss); - VertDataMulN(static_cast(r), avgSharpness, ss); - VertDataAdd(static_cast(q), static_cast(r), ss); - } - - /* r = co * 0.75 + q * 0.25 */ - VertDataCopy(static_cast(r), static_cast(co), ss); - VertDataMulN(static_cast(r), 0.75f, ss); - VertDataMulN(static_cast(q), 0.25f, ss); - VertDataAdd(static_cast(r), static_cast(q), ss); - - /* nCo = nCo + (r - nCo) * avgSharpness */ - VertDataSub(static_cast(r), static_cast(nCo), ss); - VertDataMulN(static_cast(r), avgSharpness, ss); - VertDataAdd(static_cast(nCo), static_cast(r), ss); - } - - /* vert flags cleared later */ - } - - if (ss->useAgeCounts) { - for (i = 0; i < numEffectedV; i++) { - CCGVert *v = effectedV[i]; - uint8_t *user_data = static_cast(ccgSubSurf_getVertUserData(ss, v)); - *((int *)&user_data[ss->vertUserAgeOffset]) = ss->currentAge; - } - - for (i = 0; i < numEffectedE; i++) { - CCGEdge *e = effectedE[i]; - uint8_t *user_data = static_cast(ccgSubSurf_getEdgeUserData(ss, e)); - *((int *)&user_data[ss->edgeUserAgeOffset]) = ss->currentAge; - } - - for (i = 0; i < numEffectedF; i++) { - CCGFace *f = effectedF[i]; - uint8_t *user_data = static_cast(ccgSubSurf_getFaceUserData(ss, f)); - *((int *)&user_data[ss->faceUserAgeOffset]) = ss->currentAge; - } - } - - for (i = 0; i < numEffectedE; i++) { - CCGEdge *e = effectedE[i]; - VertDataCopy(EDGE_getCo(e, nextLvl, 0), VERT_getCo(e->v0, nextLvl), ss); - VertDataCopy(EDGE_getCo(e, nextLvl, 2), VERT_getCo(e->v1, nextLvl), ss); - } - for (i = 0; i < numEffectedF; i++) { - CCGFace *f = effectedF[i]; - for (S = 0; S < f->numVerts; S++) { - CCGEdge *e = FACE_getEdges(f)[S]; - CCGEdge *prevE = FACE_getEdges(f)[(S + f->numVerts - 1) % f->numVerts]; - - VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 0), (float *)FACE_getCenterData(f), ss); - VertDataCopy(FACE_getIECo(f, nextLvl, S, 0), (float *)FACE_getCenterData(f), ss); - VertDataCopy( - FACE_getIFCo(f, nextLvl, S, 1, 1), VERT_getCo(FACE_getVerts(f)[S], nextLvl), ss); - VertDataCopy( - FACE_getIECo(f, nextLvl, S, 1), EDGE_getCo(FACE_getEdges(f)[S], nextLvl, 1), ss); - - VertDataCopy(FACE_getIFCo(f, nextLvl, S, 1, 0), - static_cast( - _edge_getCoVert(e, FACE_getVerts(f)[S], nextLvl, 1, vertDataSize)), - ss); - VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 1), - static_cast( - _edge_getCoVert(prevE, FACE_getVerts(f)[S], nextLvl, 1, vertDataSize)), - ss); - } - } - - for (curLvl = 1; curLvl < subdivLevels; curLvl++) { - ccgSubSurf__calcSubdivLevel( - ss, effectedV, effectedE, effectedF, numEffectedV, numEffectedE, numEffectedF, curLvl); - } - - if (ss->calcVertNormals) { - ccgSubSurf__calcVertNormals( - ss, effectedV, effectedE, effectedF, numEffectedV, numEffectedE, numEffectedF); - } - - for (ptrIdx = 0; ptrIdx < numEffectedV; ptrIdx++) { - CCGVert *v = effectedV[ptrIdx]; - v->flags = 0; - } - for (ptrIdx = 0; ptrIdx < numEffectedE; ptrIdx++) { - CCGEdge *e = effectedE[ptrIdx]; - e->flags = 0; - } - - MEM_freeN(effectedF); - MEM_freeN(effectedE); - MEM_freeN(effectedV); - -#ifdef DUMP_RESULT_GRIDS - ccgSubSurf__dumpCoords(ss); -#endif -} - -/* ** Public API exposed to other areas which depends on old CCG code. ** */ - -CCGError ccgSubSurf_updateNormals(CCGSubSurf *ss, CCGFace **effectedF, int numEffectedF) -{ - CCGVert **effectedV; - CCGEdge **effectedE; - int i, numEffectedV, numEffectedE, freeF; - - ccgSubSurf__allFaces(ss, &effectedF, &numEffectedF, &freeF); - ccgSubSurf__effectedFaceNeighbors( - ss, effectedF, numEffectedF, &effectedV, &numEffectedV, &effectedE, &numEffectedE); - - if (ss->calcVertNormals) { - ccgSubSurf__calcVertNormals( - ss, effectedV, effectedE, effectedF, numEffectedV, numEffectedE, numEffectedF); - } - - for (i = 0; i < numEffectedV; i++) { - effectedV[i]->flags = 0; - } - for (i = 0; i < numEffectedE; i++) { - effectedE[i]->flags = 0; - } - for (i = 0; i < numEffectedF; i++) { - effectedF[i]->flags = 0; - } - - MEM_freeN(effectedE); - MEM_freeN(effectedV); - if (freeF) { - MEM_freeN(effectedF); - } - - return eCCGError_None; -} - -CCGError ccgSubSurf_updateLevels(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF) -{ - CCGVert **effectedV; - CCGEdge **effectedE; - int numEffectedV, numEffectedE, freeF, i; - int curLvl, subdivLevels = ss->subdivLevels; - - ccgSubSurf__allFaces(ss, &effectedF, &numEffectedF, &freeF); - ccgSubSurf__effectedFaceNeighbors( - ss, effectedF, numEffectedF, &effectedV, &numEffectedV, &effectedE, &numEffectedE); - - for (curLvl = lvl; curLvl < subdivLevels; curLvl++) { - ccgSubSurf__calcSubdivLevel( - ss, effectedV, effectedE, effectedF, numEffectedV, numEffectedE, numEffectedF, curLvl); - } - - for (i = 0; i < numEffectedV; i++) { - effectedV[i]->flags = 0; - } - for (i = 0; i < numEffectedE; i++) { - effectedE[i]->flags = 0; - } - for (i = 0; i < numEffectedF; i++) { - effectedF[i]->flags = 0; - } - - MEM_freeN(effectedE); - MEM_freeN(effectedV); - if (freeF) { - MEM_freeN(effectedF); - } - - return eCCGError_None; -} diff --git a/source/blender/blenkernel/intern/CCGSubSurf_util.cc b/source/blender/blenkernel/intern/CCGSubSurf_util.cc deleted file mode 100644 index 92f2d470ccc..00000000000 --- a/source/blender/blenkernel/intern/CCGSubSurf_util.cc +++ /dev/null @@ -1,314 +0,0 @@ -/* SPDX-FileCopyrightText: 2023 Blender Authors - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -/** \file - * \ingroup bke - */ - -#include -#include - -#include "MEM_guardedalloc.h" - -#include "BLI_utildefines.h" /* for BLI_assert */ - -#include "CCGSubSurf.h" -#include "CCGSubSurf_intern.h" - -/** - * Hash implementation. - */ - -static int kHashSizes[] = { - 1, 3, 5, 11, 17, 37, 67, 131, 257, 521, - 1031, 2053, 4099, 8209, 16411, 32771, 65537, 131101, 262147, 524309, - 1048583, 2097169, 4194319, 8388617, 16777259, 33554467, 67108879, 134217757, 268435459, -}; - -/* -------------------------------------------------------------------- */ -/** \name Generic Hash Functions - * \{ */ - -EHash *ccg_ehash_new(int estimatedNumEntries, - CCGAllocatorIFC *allocatorIFC, - CCGAllocatorHDL allocator) -{ - EHash *eh = static_cast(allocatorIFC->alloc(allocator, sizeof(*eh))); - eh->allocatorIFC = *allocatorIFC; - eh->allocator = allocator; - eh->numEntries = 0; - eh->curSizeIdx = 0; - while (kHashSizes[eh->curSizeIdx] < estimatedNumEntries) { - eh->curSizeIdx++; - } - eh->curSize = kHashSizes[eh->curSizeIdx]; - eh->buckets = EHASH_alloc(eh, eh->curSize * sizeof(*eh->buckets)); - memset(eh->buckets, 0, eh->curSize * sizeof(*eh->buckets)); - - return eh; -} - -void ccg_ehash_free(EHash *eh, EHEntryFreeFP freeEntry, void *user_data) -{ - int numBuckets = eh->curSize; - - while (numBuckets--) { - EHEntry *entry = eh->buckets[numBuckets]; - - while (entry) { - EHEntry *next = entry->next; - - freeEntry(entry, user_data); - - entry = next; - } - } - - EHASH_free(eh, eh->buckets); - EHASH_free(eh, eh); -} - -void ccg_ehash_insert(EHash *eh, EHEntry *entry) -{ - int numBuckets = eh->curSize; - int hash = EHASH_hash(eh, entry->key); - entry->next = eh->buckets[hash]; - eh->buckets[hash] = entry; - eh->numEntries++; - - if (UNLIKELY(eh->numEntries > (numBuckets * 3))) { - EHEntry **oldBuckets = eh->buckets; - eh->curSize = kHashSizes[++eh->curSizeIdx]; - - eh->buckets = EHASH_alloc(eh, eh->curSize * sizeof(*eh->buckets)); - memset(eh->buckets, 0, eh->curSize * sizeof(*eh->buckets)); - - while (numBuckets--) { - for (entry = oldBuckets[numBuckets]; entry;) { - EHEntry *next = entry->next; - - hash = EHASH_hash(eh, entry->key); - entry->next = eh->buckets[hash]; - eh->buckets[hash] = entry; - - entry = next; - } - } - - EHASH_free(eh, oldBuckets); - } -} - -void *ccg_ehash_lookupWithPrev(EHash *eh, void *key, void ***prevp_r) -{ - int hash = EHASH_hash(eh, key); - void **prevp = (void **)&eh->buckets[hash]; - EHEntry *entry; - - for (; (entry = static_cast(*prevp)); prevp = (void **)&entry->next) { - if (entry->key == key) { - *prevp_r = prevp; - return entry; - } - } - - return nullptr; -} - -void *ccg_ehash_lookup(EHash *eh, void *key) -{ - int hash = EHASH_hash(eh, key); - EHEntry *entry; - - for (entry = eh->buckets[hash]; entry; entry = entry->next) { - if (entry->key == key) { - break; - } - } - - return entry; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Hash Elements Iteration - * \{ */ - -void ccg_ehashIterator_init(EHash *eh, EHashIterator *ehi) -{ - /* fill all members */ - ehi->eh = eh; - ehi->curBucket = -1; - ehi->curEntry = nullptr; - - while (!ehi->curEntry) { - ehi->curBucket++; - if (ehi->curBucket == ehi->eh->curSize) { - break; - } - ehi->curEntry = ehi->eh->buckets[ehi->curBucket]; - } -} - -void *ccg_ehashIterator_getCurrent(EHashIterator *ehi) -{ - return ehi->curEntry; -} - -void ccg_ehashIterator_next(EHashIterator *ehi) -{ - if (ehi->curEntry) { - ehi->curEntry = ehi->curEntry->next; - while (!ehi->curEntry) { - ehi->curBucket++; - if (ehi->curBucket == ehi->eh->curSize) { - break; - } - ehi->curEntry = ehi->eh->buckets[ehi->curBucket]; - } - } -} -int ccg_ehashIterator_isStopped(EHashIterator *ehi) -{ - return !ehi->curEntry; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Standard allocator implementation - * \{ */ - -static void *_stdAllocator_alloc(CCGAllocatorHDL /*a*/, int numBytes) -{ - return MEM_mallocN(numBytes, "CCG standard alloc"); -} - -static void *_stdAllocator_realloc(CCGAllocatorHDL /*a*/, void *ptr, int newSize, int /*oldSize*/) -{ - return MEM_reallocN(ptr, newSize); -} - -static void _stdAllocator_free(CCGAllocatorHDL /*a*/, void *ptr) -{ - MEM_freeN(ptr); -} - -CCGAllocatorIFC *ccg_getStandardAllocatorIFC() -{ - static CCGAllocatorIFC ifc; - - ifc.alloc = _stdAllocator_alloc; - ifc.realloc = _stdAllocator_realloc; - ifc.free = _stdAllocator_free; - ifc.release = nullptr; - - return &ifc; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name * Catmull-Clark Gridding Subdivision Surface - * \{ */ - -#ifdef DUMP_RESULT_GRIDS -void ccgSubSurf__dumpCoords(CCGSubSurf *ss) -{ - int vertDataSize = ss->meshIFC.vertDataSize; - int subdivLevels = ss->subdivLevels; - int gridSize = ccg_gridsize(subdivLevels); - int edgeSize = ccg_edgesize(subdivLevels); - int i, index, S; - - for (i = 0, index = 0; i < ss->vMap->curSize; i++) { - CCGVert *v = (CCGVert *)ss->vMap->buckets[i]; - for (; v; v = v->next, index++) { - float *co = VERT_getCo(v, subdivLevels); - printf("vertex index=%d, co=(%f, %f, %f)\n", index, co[0], co[1], co[2]); - } - } - - for (i = 0, index = 0; i < ss->eMap->curSize; i++) { - CCGEdge *e = (CCGEdge *)ss->eMap->buckets[i]; - for (; e; e = e->next, index++) { - int x; - float *co = VERT_getCo(e->v0, subdivLevels); - printf("edge index=%d, start_co=(%f, %f, %f)\n", index, co[0], co[1], co[2]); - for (x = 0; x < edgeSize; x++) { - float *co = EDGE_getCo(e, subdivLevels, x); - printf("edge index=%d, seg=%d, co=(%f, %f, %f)\n", index, x, co[0], co[1], co[2]); - } - co = VERT_getCo(e->v1, subdivLevels); - printf("edge index=%d, end_co=(%f, %f, %f)\n", index, co[0], co[1], co[2]); - } - } - - for (i = 0, index = 0; i < ss->fMap->curSize; i++) { - CCGFace *f = (CCGFace *)ss->fMap->buckets[i]; - for (; f; f = f->next, index++) { - for (S = 0; S < f->numVerts; S++) { - CCGVert *v = FACE_getVerts(f)[S]; - float *co = VERT_getCo(v, subdivLevels); - printf("face index=%d, vertex=%d, coord=(%f, %f, %f)\n", index, S, co[0], co[1], co[2]); - } - } - } - - for (i = 0, index = 0; i < ss->fMap->curSize; i++) { - CCGFace *f = (CCGFace *)ss->fMap->buckets[i]; - for (; f; f = f->next, index++) { - for (S = 0; S < f->numVerts; S++) { - CCGEdge *e = FACE_getEdges(f)[S]; - float *co1 = VERT_getCo(e->v0, subdivLevels); - float *co2 = VERT_getCo(e->v1, subdivLevels); - printf("face index=%d, edge=%d, coord1=(%f, %f, %f), coord2=(%f, %f, %f)\n", - index, - S, - co1[0], - co1[1], - co1[2], - co2[0], - co2[1], - co2[2]); - } - } - } - - for (i = 0, index = 0; i < ss->fMap->curSize; i++) { - CCGFace *f = (CCGFace *)ss->fMap->buckets[i]; - for (; f; f = f->next, index++) { - for (S = 0; S < f->numVerts; S++) { - int x, y; - for (x = 0; x < gridSize; x++) { - for (y = 0; y < gridSize; y++) { - float *co = FACE_getIFCo(f, subdivLevels, S, x, y); - printf("face index=%d. corner=%d, x=%d, y=%d, coord=(%f, %f, %f)\n", - index, - S, - x, - y, - co[0], - co[1], - co[2]); - } - } - for (x = 0; x < gridSize; x++) { - float *co = FACE_getIECo(f, subdivLevels, S, x); - printf("face index=%d. corner=%d, ie_index=%d, coord=(%f, %f, %f)\n", - index, - S, - x, - co[0], - co[1], - co[2]); - } - } - } - } -} -#endif /* DUMP_RESULT_GRIDS */ - -/** \} */ diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index 3b0b04e9c2f..4bd078a0e5a 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -51,6 +51,7 @@ #include "BKE_attribute_legacy_convert.hh" #include "BKE_attribute_math.hh" #include "BKE_attribute_storage.hh" +#include "BKE_ccg.hh" #include "BKE_customdata.hh" #include "BKE_customdata_file.h" #include "BKE_deform.hh" @@ -58,7 +59,6 @@ #include "BKE_main.hh" #include "BKE_mesh_remap.hh" #include "BKE_multires.hh" -#include "BKE_subsurf.hh" #include "BLO_read_write.hh" @@ -5190,7 +5190,7 @@ static void write_grid_paint_mask(BlendWriter *writer, for (int i = 0; i < count; i++) { const GridPaintMask *gpm = &grid_paint_mask[i]; if (gpm->data) { - const uint32_t gridsize = uint32_t(BKE_ccg_gridsize(gpm->level)); + const uint32_t gridsize = uint32_t(CCG_grid_size(gpm->level)); BLO_write_float_array(writer, gridsize * gridsize, gpm->data); } } @@ -5303,7 +5303,7 @@ static void blend_read_paint_mask(BlendDataReader *reader, for (int i = 0; i < count; i++) { GridPaintMask *gpm = &grid_paint_mask[i]; if (gpm->data) { - const int gridsize = BKE_ccg_gridsize(gpm->level); + const int gridsize = CCG_grid_size(gpm->level); BLO_read_float_array(reader, gridsize * gridsize, &gpm->data); } } diff --git a/source/blender/blenkernel/intern/mesh_legacy_convert.cc b/source/blender/blenkernel/intern/mesh_legacy_convert.cc index 5e57db5a7b0..25e0c693a1d 100644 --- a/source/blender/blenkernel/intern/mesh_legacy_convert.cc +++ b/source/blender/blenkernel/intern/mesh_legacy_convert.cc @@ -25,6 +25,7 @@ #include "BLI_math_vector_types.hh" #include "BLI_memarena.h" #include "BLI_multi_value_map.hh" +#include "BLI_ordered_edge.hh" #include "BLI_polyfill_2d.h" #include "BLI_string.h" #include "BLI_string_utf8.h" diff --git a/source/blender/blenkernel/intern/mesh_legacy_derived_mesh.cc b/source/blender/blenkernel/intern/mesh_legacy_derived_mesh.cc deleted file mode 100644 index 5c6004c3097..00000000000 --- a/source/blender/blenkernel/intern/mesh_legacy_derived_mesh.cc +++ /dev/null @@ -1,364 +0,0 @@ -/* SPDX-FileCopyrightText: 2005 Blender Authors - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#include "BLI_math_vector.h" - -#include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" - -#include "BKE_customdata.hh" -#include "BKE_mesh_legacy_derived_mesh.hh" - -/* -------------------------------------------------------------------- */ - -static float *dm_getVertArray(DerivedMesh *dm) -{ - float(*positions)[3] = (float(*)[3])CustomData_get_layer_named_for_write( - &dm->vertData, CD_PROP_FLOAT3, "position", dm->getNumVerts(dm)); - - if (!positions) { - positions = (float(*)[3])CustomData_add_layer_named( - &dm->vertData, CD_PROP_FLOAT3, CD_SET_DEFAULT, dm->getNumVerts(dm), "position"); - CustomData_set_layer_flag(&dm->vertData, CD_PROP_FLOAT3, CD_FLAG_TEMPORARY); - dm->copyVertArray(dm, positions); - } - - return (float *)positions; -} - -static blender::int2 *dm_getEdgeArray(DerivedMesh *dm) -{ - blender::int2 *edge = (blender::int2 *)CustomData_get_layer_named_for_write( - &dm->edgeData, CD_PROP_INT32_2D, ".edge_verts", dm->getNumEdges(dm)); - - if (!edge) { - edge = (blender::int2 *)CustomData_add_layer_named( - &dm->edgeData, CD_PROP_INT32_2D, CD_SET_DEFAULT, dm->getNumEdges(dm), ".edge_verts"); - CustomData_set_layer_flag(&dm->edgeData, CD_PROP_INT32_2D, CD_FLAG_TEMPORARY); - dm->copyEdgeArray(dm, edge); - } - - return edge; -} - -static int *dm_getCornerVertArray(DerivedMesh *dm) -{ - int *corner_verts = (int *)CustomData_get_layer_named_for_write( - &dm->loopData, CD_PROP_INT32, ".corner_vert", dm->getNumLoops(dm)); - - if (!corner_verts) { - corner_verts = (int *)CustomData_add_layer_named( - &dm->loopData, CD_PROP_INT32, CD_SET_DEFAULT, dm->getNumLoops(dm), ".corner_vert"); - dm->copyCornerVertArray(dm, corner_verts); - } - - return corner_verts; -} - -static int *dm_getCornerEdgeArray(DerivedMesh *dm) -{ - int *corner_edges = (int *)CustomData_get_layer_named( - &dm->loopData, CD_PROP_INT32, ".corner_edge"); - - if (!corner_edges) { - corner_edges = (int *)CustomData_add_layer_named( - &dm->loopData, CD_PROP_INT32, CD_SET_DEFAULT, dm->getNumLoops(dm), ".corner_edge"); - dm->copyCornerEdgeArray(dm, corner_edges); - } - - return corner_edges; -} - -static int *dm_getPolyArray(DerivedMesh *dm) -{ - if (!dm->face_offsets) { - dm->face_offsets = MEM_calloc_arrayN(dm->getNumPolys(dm) + 1, __func__); - dm->copyPolyArray(dm, dm->face_offsets); - } - return dm->face_offsets; -} - -void DM_init_funcs(DerivedMesh *dm) -{ - /* default function implementations */ - dm->getVertArray = dm_getVertArray; - dm->getEdgeArray = dm_getEdgeArray; - dm->getCornerVertArray = dm_getCornerVertArray; - dm->getCornerEdgeArray = dm_getCornerEdgeArray; - dm->getPolyArray = dm_getPolyArray; - - dm->getVertDataArray = DM_get_vert_data_layer; - dm->getEdgeDataArray = DM_get_edge_data_layer; - dm->getPolyDataArray = DM_get_poly_data_layer; - dm->getLoopDataArray = DM_get_loop_data_layer; -} - -void DM_init(DerivedMesh *dm, - DerivedMeshType type, - int numVerts, - int numEdges, - int numTessFaces, - int numLoops, - int numPolys) -{ - dm->type = type; - dm->numVertData = numVerts; - dm->numEdgeData = numEdges; - dm->numTessFaceData = numTessFaces; - dm->numLoopData = numLoops; - dm->numPolyData = numPolys; - - DM_init_funcs(dm); - - /* Don't use #CustomData_reset because we don't want to touch custom-data. */ - copy_vn_i(dm->vertData.typemap, CD_NUMTYPES, -1); - copy_vn_i(dm->edgeData.typemap, CD_NUMTYPES, -1); - copy_vn_i(dm->faceData.typemap, CD_NUMTYPES, -1); - copy_vn_i(dm->loopData.typemap, CD_NUMTYPES, -1); - copy_vn_i(dm->polyData.typemap, CD_NUMTYPES, -1); -} - -void DM_from_template(DerivedMesh *dm, - DerivedMesh *source, - DerivedMeshType type, - int numVerts, - int numEdges, - int numTessFaces, - int numLoops, - int numPolys) -{ - const CustomData_MeshMasks *mask = &CD_MASK_DERIVEDMESH; - CustomData_init_layout_from( - &source->vertData, &dm->vertData, mask->vmask, CD_SET_DEFAULT, numVerts); - CustomData_init_layout_from( - &source->edgeData, &dm->edgeData, mask->emask, CD_SET_DEFAULT, numEdges); - CustomData_init_layout_from( - &source->faceData, &dm->faceData, mask->fmask, CD_SET_DEFAULT, numTessFaces); - CustomData_init_layout_from( - &source->loopData, &dm->loopData, mask->lmask, CD_SET_DEFAULT, numLoops); - CustomData_init_layout_from( - &source->polyData, &dm->polyData, mask->pmask, CD_SET_DEFAULT, numPolys); - dm->face_offsets = static_cast(MEM_dupallocN(source->face_offsets)); - - dm->type = type; - dm->numVertData = numVerts; - dm->numEdgeData = numEdges; - dm->numTessFaceData = numTessFaces; - dm->numLoopData = numLoops; - dm->numPolyData = numPolys; - - DM_init_funcs(dm); -} - -void DM_release(DerivedMesh *dm) -{ - CustomData_free(&dm->vertData); - CustomData_free(&dm->edgeData); - CustomData_free(&dm->faceData); - CustomData_free(&dm->loopData); - CustomData_free(&dm->polyData); - MEM_SAFE_FREE(dm->face_offsets); -} - -void DM_set_only_copy(DerivedMesh *dm, const CustomData_MeshMasks *mask) -{ - CustomData_set_only_copy(&dm->vertData, mask->vmask); - CustomData_set_only_copy(&dm->edgeData, mask->emask); - CustomData_set_only_copy(&dm->faceData, mask->fmask); - /* this wasn't in 2.63 and is disabled for 2.64 because it gives problems with - * weight paint mode when there are modifiers applied, needs further investigation, - * see replies to r50969, Campbell */ -#if 0 - CustomData_set_only_copy(&dm->loopData, mask->lmask); - Custom(&dm->polyData, mask->pmask); -#endif -} - -void *DM_get_vert_data_layer(DerivedMesh *dm, const eCustomDataType type) -{ - return CustomData_get_layer_for_write(&dm->vertData, type, dm->getNumVerts(dm)); -} - -void *DM_get_edge_data_layer(DerivedMesh *dm, const eCustomDataType type) -{ - return CustomData_get_layer_for_write(&dm->edgeData, type, dm->getNumEdges(dm)); -} - -void *DM_get_poly_data_layer(DerivedMesh *dm, const eCustomDataType type) -{ - return CustomData_get_layer_for_write(&dm->polyData, type, dm->getNumPolys(dm)); -} - -void *DM_get_loop_data_layer(DerivedMesh *dm, const eCustomDataType type) -{ - return CustomData_get_layer_for_write(&dm->loopData, type, dm->getNumLoops(dm)); -} - -void DM_copy_vert_data( - const DerivedMesh *source, DerivedMesh *dest, int source_index, int dest_index, int count) -{ - CustomData_copy_data(&source->vertData, &dest->vertData, source_index, dest_index, count); -} - -void DM_interp_vert_data(const DerivedMesh *source, - DerivedMesh *dest, - int *src_indices, - float *weights, - int count, - int dest_index) -{ - CustomData_interp( - &source->vertData, &dest->vertData, src_indices, weights, nullptr, count, dest_index); -} - -struct CDDerivedMesh { - DerivedMesh dm; - - /* these point to data in the DerivedMesh custom data layers, - * they are only here for efficiency and convenience */ - float (*vert_positions)[3]; - blender::int2 *medge; - MFace *mface; - int *corner_verts; - int *corner_edges; -}; - -/**************** DerivedMesh interface functions ****************/ -static int cdDM_getNumVerts(DerivedMesh *dm) -{ - return dm->numVertData; -} - -static int cdDM_getNumEdges(DerivedMesh *dm) -{ - return dm->numEdgeData; -} - -static int cdDM_getNumLoops(DerivedMesh *dm) -{ - return dm->numLoopData; -} - -static int cdDM_getNumPolys(DerivedMesh *dm) -{ - return dm->numPolyData; -} - -static void cdDM_copyVertArray(DerivedMesh *dm, float (*r_positions)[3]) -{ - CDDerivedMesh *cddm = (CDDerivedMesh *)dm; - memcpy(r_positions, cddm->vert_positions, sizeof(float[3]) * dm->numVertData); -} - -static void cdDM_copyEdgeArray(DerivedMesh *dm, blender::int2 *r_edge) -{ - CDDerivedMesh *cddm = (CDDerivedMesh *)dm; - memcpy(r_edge, cddm->medge, sizeof(*r_edge) * dm->numEdgeData); -} - -static void cdDM_copyCornerVertArray(DerivedMesh *dm, int *r_corner_verts) -{ - CDDerivedMesh *cddm = (CDDerivedMesh *)dm; - memcpy(r_corner_verts, cddm->corner_verts, sizeof(*r_corner_verts) * dm->numLoopData); -} - -static void cdDM_copyCornerEdgeArray(DerivedMesh *dm, int *r_corner_edges) -{ - CDDerivedMesh *cddm = (CDDerivedMesh *)dm; - memcpy(r_corner_edges, cddm->corner_edges, sizeof(*r_corner_edges) * dm->numLoopData); -} - -static void cdDM_copyPolyArray(DerivedMesh *dm, int *r_face_offsets) -{ - memcpy(r_face_offsets, dm->face_offsets, sizeof(int) * (dm->numPolyData + 1)); -} - -static void cdDM_release(DerivedMesh *dm) -{ - CDDerivedMesh *cddm = (CDDerivedMesh *)dm; - - DM_release(dm); - MEM_freeN(cddm); -} - -/**************** CDDM interface functions ****************/ -static CDDerivedMesh *cdDM_create(const char *desc) -{ - CDDerivedMesh *cddm = MEM_callocN(desc); - DerivedMesh *dm = &cddm->dm; - - dm->getNumVerts = cdDM_getNumVerts; - dm->getNumEdges = cdDM_getNumEdges; - dm->getNumLoops = cdDM_getNumLoops; - dm->getNumPolys = cdDM_getNumPolys; - - dm->copyVertArray = cdDM_copyVertArray; - dm->copyEdgeArray = cdDM_copyEdgeArray; - dm->copyCornerVertArray = cdDM_copyCornerVertArray; - dm->copyCornerEdgeArray = cdDM_copyCornerEdgeArray; - dm->copyPolyArray = cdDM_copyPolyArray; - - dm->getVertDataArray = DM_get_vert_data_layer; - dm->getEdgeDataArray = DM_get_edge_data_layer; - - dm->release = cdDM_release; - - return cddm; -} - -static DerivedMesh *cdDM_from_mesh_ex(Mesh *mesh, const CustomData_MeshMasks *mask) -{ - CDDerivedMesh *cddm = cdDM_create(__func__); - DerivedMesh *dm = &cddm->dm; - CustomData_MeshMasks cddata_masks = *mask; - - cddata_masks.lmask &= ~CD_MASK_MDISPS; - - /* This does a referenced copy, with an exception for fluid-simulation. */ - - DM_init(dm, - DM_TYPE_CDDM, - mesh->verts_num, - mesh->edges_num, - 0 /* `mesh->totface` */, - mesh->corners_num, - mesh->faces_num); - - CustomData_merge(&mesh->vert_data, &dm->vertData, cddata_masks.vmask, mesh->verts_num); - CustomData_merge(&mesh->edge_data, &dm->edgeData, cddata_masks.emask, mesh->edges_num); - CustomData_merge(&mesh->fdata_legacy, - &dm->faceData, - cddata_masks.fmask | CD_MASK_ORIGINDEX, - 0 /* `mesh->totface` */); - CustomData_merge(&mesh->corner_data, &dm->loopData, cddata_masks.lmask, mesh->corners_num); - CustomData_merge(&mesh->face_data, &dm->polyData, cddata_masks.pmask, mesh->faces_num); - - cddm->vert_positions = static_cast(CustomData_get_layer_named_for_write( - &dm->vertData, CD_PROP_FLOAT3, "position", mesh->verts_num)); - cddm->medge = static_cast(CustomData_get_layer_named_for_write( - &dm->edgeData, CD_PROP_INT32_2D, ".edge_verts", mesh->edges_num)); - cddm->corner_verts = static_cast(CustomData_get_layer_named_for_write( - &dm->loopData, CD_PROP_INT32, ".corner_vert", mesh->corners_num)); - cddm->corner_edges = static_cast(CustomData_get_layer_named_for_write( - &dm->loopData, CD_PROP_INT32, ".corner_edge", mesh->corners_num)); - dm->face_offsets = static_cast(MEM_dupallocN(mesh->face_offset_indices)); -#if 0 - cddm->mface = CustomData_get_layer(&dm->faceData, CD_MFACE); -#else - cddm->mface = nullptr; -#endif - - /* commented since even when CD_ORIGINDEX was first added this line fails - * on the default cube, (after editmode toggle too) - campbell */ -#if 0 - BLI_assert(CustomData_has_layer(&cddm->dm.faceData, CD_ORIGINDEX)); -#endif - - return dm; -} - -DerivedMesh *CDDM_from_mesh(Mesh *mesh) -{ - return cdDM_from_mesh_ex(mesh, &CD_MASK_MESH); -} diff --git a/source/blender/blenkernel/intern/modifier.cc b/source/blender/blenkernel/intern/modifier.cc index 6099dd4e638..c20c9c6ce48 100644 --- a/source/blender/blenkernel/intern/modifier.cc +++ b/source/blender/blenkernel/intern/modifier.cc @@ -40,6 +40,7 @@ #include "BLI_string.h" #include "BLI_string_utf8.h" #include "BLI_string_utils.hh" +#include "BLI_threads.h" #include "BLI_utildefines.h" #include "BLT_translation.hh" diff --git a/source/blender/blenkernel/intern/multires.cc b/source/blender/blenkernel/intern/multires.cc index d6e90d92808..5ff571fdfd3 100644 --- a/source/blender/blenkernel/intern/multires.cc +++ b/source/blender/blenkernel/intern/multires.cc @@ -26,7 +26,6 @@ #include "BKE_ccg.hh" #include "BKE_editmesh.hh" #include "BKE_mesh.h" -#include "BKE_mesh_legacy_derived_mesh.hh" #include "BKE_mesh_runtime.hh" #include "BKE_mesh_types.hh" #include "BKE_modifier.hh" @@ -35,12 +34,9 @@ #include "BKE_paint_bvh.hh" #include "BKE_scene.hh" #include "BKE_subdiv_ccg.hh" -#include "BKE_subsurf.hh" #include "BKE_object.hh" -#include "CCGSubSurf.h" - #include "DEG_depsgraph_query.hh" #include @@ -59,9 +55,6 @@ enum DispOp { ADD_DISPLACEMENTS, }; -static void multiresModifier_disp_run( - DerivedMesh *dm, Mesh *mesh, DerivedMesh *dm2, DispOp op, CCGElem **oldGridData, int totlvl); - /** Custom-data. */ void multires_customdata_delete(Mesh *mesh) @@ -88,80 +81,15 @@ void multires_customdata_delete(Mesh *mesh) } } -/** Grid hiding */ -static BLI_bitmap *multires_mdisps_upsample_hidden(BLI_bitmap *lo_hidden, - const int lo_level, - const int hi_level, - - /* assumed to be at hi_level (or null) */ - const BLI_bitmap *prev_hidden) -{ - const int hi_gridsize = BKE_ccg_gridsize(hi_level); - const int lo_gridsize = BKE_ccg_gridsize(lo_level); - - BLI_assert(lo_level <= hi_level); - - /* fast case */ - if (lo_level == hi_level) { - return static_cast(MEM_dupallocN(lo_hidden)); - } - - BLI_bitmap *subd = BLI_BITMAP_NEW(square_i(hi_gridsize), "MDisps.hidden upsample"); - - const int factor = BKE_ccg_factor(lo_level, hi_level); - const int offset = 1 << (hi_level - lo_level - 1); - - /* low-res blocks */ - for (int yl = 0; yl < lo_gridsize; yl++) { - for (int xl = 0; xl < lo_gridsize; xl++) { - const int lo_val = BLI_BITMAP_TEST(lo_hidden, yl * lo_gridsize + xl); - - /* high-res blocks */ - for (int yo = -offset; yo <= offset; yo++) { - const int yh = yl * factor + yo; - if (yh < 0 || yh >= hi_gridsize) { - continue; - } - - for (int xo = -offset; xo <= offset; xo++) { - const int xh = xl * factor + xo; - if (xh < 0 || xh >= hi_gridsize) { - continue; - } - - const int hi_ndx = yh * hi_gridsize + xh; - - if (prev_hidden) { - /* If prev_hidden is available, copy it to - * subd, except when the equivalent element in - * lo_hidden is different */ - if (lo_val != prev_hidden[hi_ndx]) { - BLI_BITMAP_SET(subd, hi_ndx, lo_val); - } - else { - BLI_BITMAP_SET(subd, hi_ndx, prev_hidden[hi_ndx]); - } - } - else { - BLI_BITMAP_SET(subd, hi_ndx, lo_val); - } - } - } - } - } - - return subd; -} - static BLI_bitmap *multires_mdisps_downsample_hidden(const BLI_bitmap *old_hidden, const int old_level, const int new_level) { - const int new_gridsize = BKE_ccg_gridsize(new_level); - const int old_gridsize = BKE_ccg_gridsize(old_level); + const int new_gridsize = CCG_grid_size(new_level); + const int old_gridsize = CCG_grid_size(old_level); BLI_assert(new_level <= old_level); - const int factor = BKE_ccg_factor(new_level, old_level); + const int factor = CCG_grid_factor(new_level, old_level); BLI_bitmap *new_hidden = BLI_BITMAP_NEW(square_i(new_gridsize), "downsample hidden"); for (int y = 0; y < new_gridsize; y++) { @@ -175,46 +103,6 @@ static BLI_bitmap *multires_mdisps_downsample_hidden(const BLI_bitmap *old_hidde return new_hidden; } -static void multires_output_hidden_to_ccgdm(CCGDerivedMesh *ccgdm, Mesh *mesh, const int level) -{ - const blender::OffsetIndices faces = mesh->faces(); - const MDisps *mdisps = static_cast( - CustomData_get_layer(&mesh->corner_data, CD_MDISPS)); - BLI_bitmap **grid_hidden = ccgdm->gridHidden; - - const int *gridOffset = ccgdm->dm.getGridOffset(&ccgdm->dm); - - for (const int i : faces.index_range()) { - for (int j = 0; j < faces[i].size(); j++) { - int g = gridOffset[i] + j; - const MDisps *md = &mdisps[g]; - - if (BLI_bitmap *gh = md->hidden) { - grid_hidden[g] = multires_mdisps_downsample_hidden(gh, md->level, level); - } - } - } -} - -/* subdivide mdisps.hidden if needed (assumes that md.level reflects - * the current level of md.hidden) */ -static void multires_mdisps_subdivide_hidden(MDisps *md, const int new_level) -{ - - BLI_assert(md->hidden); - - /* nothing to do if already subdivided enough */ - if (md->level >= new_level) { - return; - } - - BLI_bitmap *subd = multires_mdisps_upsample_hidden(md->hidden, md->level, new_level, nullptr); - - /* swap in the subdivided data */ - MEM_freeN(md->hidden); - md->hidden = subd; -} - Mesh *BKE_multires_create_mesh(Depsgraph *depsgraph, Object *object, MultiresModifierData *mmd) { Object *object_eval = DEG_get_evaluated(depsgraph, object); @@ -534,28 +422,6 @@ static void multires_set_tot_mdisps(Mesh *mesh, const int lvl) } } -static void multires_reallocate_mdisps(const int totloop, MDisps *mdisps, const int lvl) -{ - - /* reallocate displacements to be filled in */ - for (int i = 0; i < totloop; i++) { - const int totdisp = multires_grid_tot[lvl]; - float(*disps)[3] = MEM_calloc_arrayN(totdisp, __func__); - - if (mdisps[i].disps) { - MEM_freeN(mdisps[i].disps); - } - - if (mdisps[i].level && mdisps[i].hidden) { - multires_mdisps_subdivide_hidden(&mdisps[i], lvl); - } - - mdisps[i].disps = disps; - mdisps[i].totdisp = totdisp; - mdisps[i].level = lvl; - } -} - static void multires_copy_grid(float (*gridA)[3], float (*gridB)[3], const int sizeA, @@ -588,7 +454,7 @@ static void multires_copy_grid(float (*gridA)[3], static void multires_grid_paint_mask_downsample(GridPaintMask *gpm, const int level) { if (level < gpm->level) { - const int gridsize = BKE_ccg_gridsize(level); + const int gridsize = CCG_grid_size(level); float *data = MEM_calloc_arrayN(size_t(square_i(gridsize)), __func__); for (int y = 0; y < gridsize; y++) { @@ -687,290 +553,6 @@ void multiresModifier_del_levels(MultiresModifierData *mmd, multires_set_tot_level(ob, mmd, lvl); } -static DerivedMesh *subsurf_dm_create_local(Scene *scene, - Object *ob, - DerivedMesh *dm, - const int lvl, - const bool is_simple, - const bool is_optimal, - const bool is_plain_uv, - const bool alloc_paint_mask, - const bool for_render, - SubsurfFlags flags) -{ - SubsurfModifierData smd = {{nullptr}}; - - smd.levels = smd.renderLevels = lvl; - smd.quality = 3; - if (!is_plain_uv) { - smd.uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES; - } - else { - smd.uv_smooth = SUBSURF_UV_SMOOTH_NONE; - } - if (is_simple) { - smd.subdivType = ME_SIMPLE_SUBSURF; - } - if (is_optimal) { - smd.flags |= eSubsurfModifierFlag_ControlEdges; - } - - if (ob->mode & OB_MODE_EDIT) { - flags |= SUBSURF_IN_EDIT_MODE; - } - if (alloc_paint_mask) { - flags |= SUBSURF_ALLOC_PAINT_MASK; - } - if (for_render) { - flags |= SUBSURF_USE_RENDER_PARAMS; - } - - return subsurf_make_derived_from_derived(dm, &smd, scene, nullptr, flags); -} - -static void grid_tangent( - const CCGKey &key, const int x, const int y, const int axis, CCGElem *grid, float t[3]) -{ - if (axis == 0) { - if (x == key.grid_size - 1) { - if (y == key.grid_size - 1) { - sub_v3_v3v3( - t, CCG_grid_elem_co(key, grid, x, y - 1), CCG_grid_elem_co(key, grid, x - 1, y - 1)); - } - else { - sub_v3_v3v3(t, CCG_grid_elem_co(key, grid, x, y), CCG_grid_elem_co(key, grid, x - 1, y)); - } - } - else { - sub_v3_v3v3(t, CCG_grid_elem_co(key, grid, x + 1, y), CCG_grid_elem_co(key, grid, x, y)); - } - } - else if (axis == 1) { - if (y == key.grid_size - 1) { - if (x == key.grid_size - 1) { - sub_v3_v3v3( - t, CCG_grid_elem_co(key, grid, x - 1, y), CCG_grid_elem_co(key, grid, x - 1, (y - 1))); - } - else { - sub_v3_v3v3(t, CCG_grid_elem_co(key, grid, x, y), CCG_grid_elem_co(key, grid, x, (y - 1))); - } - } - else { - sub_v3_v3v3(t, CCG_grid_elem_co(key, grid, x, (y + 1)), CCG_grid_elem_co(key, grid, x, y)); - } - } -} - -/* Construct 3x3 tangent-space matrix in 'mat' */ -static void grid_tangent_matrix( - float mat[3][3], const CCGKey &key, const int x, const int y, CCGElem *grid) -{ - grid_tangent(key, x, y, 0, grid, mat[0]); - normalize_v3(mat[0]); - - grid_tangent(key, x, y, 1, grid, mat[1]); - normalize_v3(mat[1]); - - copy_v3_v3(mat[2], CCG_grid_elem_no(key, grid, x, y)); -} - -struct MultiresThreadedData { - DispOp op; - CCGElem **gridData, **subGridData; - CCGKey *key; - CCGKey *sub_key; - blender::OffsetIndices faces; - MDisps *mdisps; - GridPaintMask *grid_paint_mask; - int *gridOffset; - int gridSize, dGridSize, dSkip; - float (*smat)[3]; -}; - -static void multires_disp_run_cb(void *__restrict userdata, - const int pidx, - const TaskParallelTLS *__restrict /*tls*/) -{ - MultiresThreadedData *tdata = static_cast(userdata); - - const DispOp op = tdata->op; - CCGElem **gridData = tdata->gridData; - CCGElem **subGridData = tdata->subGridData; - const CCGKey key = *tdata->key; - const blender::OffsetIndices faces = tdata->faces; - MDisps *mdisps = tdata->mdisps; - GridPaintMask *grid_paint_mask = tdata->grid_paint_mask; - const int *gridOffset = tdata->gridOffset; - const int gridSize = tdata->gridSize; - const int dGridSize = tdata->dGridSize; - const int dSkip = tdata->dSkip; - - const int numVerts = faces[pidx].size(); - int gIndex = gridOffset[pidx]; - - for (int S = 0; S < numVerts; S++, gIndex++) { - GridPaintMask *gpm = grid_paint_mask ? &grid_paint_mask[gIndex] : nullptr; - MDisps *mdisp = &mdisps[faces[pidx][S]]; - CCGElem *grid = gridData[gIndex]; - CCGElem *subgrid = subGridData[gIndex]; - float(*dispgrid)[3] = mdisp->disps; - - /* if needed, reallocate multires paint mask */ - if (gpm && gpm->level < key.level) { - gpm->level = key.level; - if (gpm->data) { - MEM_freeN(gpm->data); - } - gpm->data = MEM_calloc_arrayN(key.grid_area, "gpm.data"); - } - - for (int y = 0; y < gridSize; y++) { - for (int x = 0; x < gridSize; x++) { - float *co = CCG_grid_elem_co(key, grid, x, y); - float *sco = CCG_grid_elem_co(key, subgrid, x, y); - float *data = dispgrid[dGridSize * y * dSkip + x * dSkip]; - float mat[3][3], disp[3], d[3]; - - /* construct tangent space matrix */ - grid_tangent_matrix(mat, key, x, y, subgrid); - - switch (op) { - case APPLY_DISPLACEMENTS: - /* Convert displacement to object space - * and add to grid points */ - mul_v3_m3v3(disp, mat, data); - add_v3_v3v3(co, sco, disp); - break; - case CALC_DISPLACEMENTS: - /* Calculate displacement between new and old - * grid points and convert to tangent space */ - sub_v3_v3v3(disp, co, sco); - invert_m3(mat); - mul_v3_m3v3(data, mat, disp); - break; - case ADD_DISPLACEMENTS: - /* Convert subdivided displacements to tangent - * space and add to the original displacements */ - invert_m3(mat); - mul_v3_m3v3(d, mat, co); - add_v3_v3(data, d); - break; - } - - if (gpm) { - float mask; - switch (op) { - case APPLY_DISPLACEMENTS: - /* Copy mask from gpm to DM */ - CCG_grid_elem_mask(key, grid, x, y) = paint_grid_paint_mask(gpm, key.level, x, y); - break; - case CALC_DISPLACEMENTS: - /* Copy mask from DM to gpm */ - mask = CCG_grid_elem_mask(key, grid, x, y); - gpm->data[y * gridSize + x] = std::clamp(mask, 0.0f, 1.0f); - break; - case ADD_DISPLACEMENTS: - /* Add mask displacement to gpm */ - gpm->data[y * gridSize + x] += CCG_grid_elem_mask(key, grid, x, y); - break; - } - } - } - } - } -} - -/* XXX WARNING: subsurf elements from dm and oldGridData *must* be of the same format (size), - * because this code uses CCGKey's info from dm to access oldGridData's normals - * (through the call to grid_tangent_matrix())! */ -static void multiresModifier_disp_run(DerivedMesh *dm, - Mesh *mesh, - DerivedMesh *dm2, - DispOp op, - CCGElem **oldGridData, - const int totlvl) -{ - CCGDerivedMesh *ccgdm = reinterpret_cast(dm); - blender::OffsetIndices faces = mesh->faces(); - MDisps *mdisps = static_cast( - CustomData_get_layer_for_write(&mesh->corner_data, CD_MDISPS, mesh->corners_num)); - GridPaintMask *grid_paint_mask = nullptr; - int totloop, faces_num; - - /* this happens in the dm made by bmesh_mdisps_space_set */ - if (dm2 && CustomData_has_layer(&dm2->loopData, CD_MDISPS)) { - faces = blender::OffsetIndices( - blender::Span(dm2->getPolyArray(dm2), dm2->getNumPolys(dm2) + 1)); - mdisps = static_cast( - CustomData_get_layer_for_write(&dm2->loopData, CD_MDISPS, dm2->getNumLoops(dm))); - totloop = dm2->numLoopData; - faces_num = dm2->numPolyData; - } - else { - totloop = mesh->corners_num; - faces_num = mesh->faces_num; - } - - if (!mdisps) { - if (op == CALC_DISPLACEMENTS) { - mdisps = static_cast( - CustomData_add_layer(&mesh->corner_data, CD_MDISPS, CD_SET_DEFAULT, mesh->corners_num)); - } - else { - return; - } - } - - // numGrids = dm->getNumGrids(dm); /* UNUSED */ - const int gridSize = dm->getGridSize(dm); - CCGElem **gridData = dm->getGridData(dm); - int *gridOffset = dm->getGridOffset(dm); - CCGKey key; - dm->getGridKey(dm, &key); - CCGElem **subGridData = (oldGridData) ? oldGridData : gridData; - - const int dGridSize = multires_side_tot[totlvl]; - const int dSkip = (dGridSize - 1) / (gridSize - 1); - - /* multires paint masks */ - if (key.has_mask) { - grid_paint_mask = static_cast( - CustomData_get_layer_for_write(&mesh->corner_data, CD_GRID_PAINT_MASK, mesh->corners_num)); - } - - /* when adding new faces in edit mode, need to allocate disps */ - for (int i = 0; i < totloop; i++) { - if (mdisps[i].disps == nullptr) { - multires_reallocate_mdisps(totloop, mdisps, totlvl); - break; - } - } - - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.min_iter_per_thread = CCG_TASK_LIMIT; - - MultiresThreadedData data{}; - data.op = op; - data.gridData = gridData; - data.subGridData = subGridData; - data.key = &key; - data.faces = faces; - data.mdisps = mdisps; - data.grid_paint_mask = grid_paint_mask; - data.gridOffset = gridOffset; - data.gridSize = gridSize; - data.dGridSize = dGridSize; - data.dSkip = dSkip; - - BLI_task_parallel_range(0, faces_num, &data, multires_disp_run_cb, &settings); - - if (op == APPLY_DISPLACEMENTS) { - ccgSubSurf_stitchFaces(ccgdm->ss, 0, nullptr, 0); - ccgSubSurf_updateNormals(ccgdm->ss, nullptr, 0); - } -} - void multires_stitch_grids(Object *ob) { using namespace blender; @@ -990,79 +572,6 @@ void multires_stitch_grids(Object *ob) BKE_subdiv_ccg_average_stitch_faces(*subdiv_ccg, IndexMask(subdiv_ccg->faces.size())); } -DerivedMesh *multires_make_derived_from_derived(DerivedMesh *dm, - MultiresModifierData *mmd, - Scene *scene, - Object *ob, - const MultiresFlags flags) -{ - Mesh *mesh = static_cast(ob->data); - const bool render = uint8_t(flags & MultiresFlags::UseRenderParams) != 0; - const bool ignore_simplify = uint8_t(flags & MultiresFlags::IgnoreSimplify) != 0; - const int lvl = multires_get_level(scene, ob, mmd, render, ignore_simplify); - - if (lvl == 0) { - return dm; - } - - const SubsurfFlags subsurf_flags = ignore_simplify ? SUBSURF_IGNORE_SIMPLIFY : SubsurfFlags(0); - - DerivedMesh *result = subsurf_dm_create_local(scene, - ob, - dm, - lvl, - false, - mmd->flags & eMultiresModifierFlag_ControlEdges, - mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE, - uint8_t(flags & MultiresFlags::AllocPaintMask), - render, - subsurf_flags); - - CCGDerivedMesh *ccgdm = nullptr; - if (!uint8_t(flags & MultiresFlags::UseLocalMMD)) { - ccgdm = reinterpret_cast(result); - - ccgdm->multires.ob = ob; - ccgdm->multires.mmd = mmd; - ccgdm->multires.local_mmd = 0; - ccgdm->multires.lvl = lvl; - ccgdm->multires.totlvl = mmd->totlvl; - } - - const int numGrids = result->getNumGrids(result); - const int gridSize = result->getGridSize(result); - CCGElem **gridData = result->getGridData(result); - CCGKey key; - result->getGridKey(result, &key); - - CCGElem **subGridData = MEM_malloc_arrayN(size_t(numGrids), "subGridData*"); - - for (int i = 0; i < numGrids; i++) { - subGridData[i] = static_cast( - MEM_malloc_arrayN(gridSize * gridSize, key.elem_size, "subGridData")); - memcpy(subGridData[i], gridData[i], key.elem_size * gridSize * gridSize); - } - - multires_set_tot_mdisps(mesh, mmd->totlvl); - multiresModifier_ensure_external_read(mesh, mmd); - - /* Run displacement. */ - multiresModifier_disp_run( - result, static_cast(ob->data), dm, APPLY_DISPLACEMENTS, subGridData, mmd->totlvl); - - /* copy hidden elements for this level */ - if (ccgdm) { - multires_output_hidden_to_ccgdm(ccgdm, mesh, lvl); - } - - for (int i = 0; i < numGrids; i++) { - MEM_freeN(static_cast(subGridData[i])); - } - MEM_freeN(subGridData); - - return result; -} - void old_mdisps_bilinear(float out[3], float (*disps)[3], const int st, float u, float v) { const int st_max = st - 1; @@ -1297,97 +806,3 @@ void multiresModifier_ensure_external_read(Mesh *mesh, const MultiresModifierDat { multires_ensure_external_read(mesh, mmd->totlvl); } - -/***************** Multires interpolation stuff *****************/ - -int mdisp_rot_face_to_crn( - const int face_size, const int face_side, const float u, const float v, float *x, float *y) -{ - const float offset = face_side * 0.5f - 0.5f; - int S = 0; - - if (face_size == 4) { - if (u <= offset && v <= offset) { - S = 0; - } - else if (u > offset && v <= offset) { - S = 1; - } - else if (u > offset && v > offset) { - S = 2; - } - else if (u <= offset && v >= offset) { - S = 3; - } - - if (S == 0) { - *y = offset - u; - *x = offset - v; - } - else if (S == 1) { - *x = u - offset; - *y = offset - v; - } - else if (S == 2) { - *y = u - offset; - *x = v - offset; - } - else if (S == 3) { - *x = offset - u; - *y = v - offset; - } - } - else if (face_size == 3) { - int grid_size = offset; - float w = (face_side - 1) - u - v; - float W1, W2; - - if (u >= v && u >= w) { - S = 0; - W1 = w; - W2 = v; - } - else if (v >= u && v >= w) { - S = 1; - W1 = u; - W2 = w; - } - else { - S = 2; - W1 = v; - W2 = u; - } - - W1 /= (face_side - 1); - W2 /= (face_side - 1); - - *x = (1 - (2 * W1) / (1 - W2)) * grid_size; - *y = (1 - (2 * W2) / (1 - W1)) * grid_size; - } - else { - /* the complicated ngon case: find the actual coordinate from - * the barycentric coordinates and finally find the closest vertex - * should work reliably for convex cases only but better than nothing */ - -#if 0 - int minS, i; - float mindist = FLT_MAX; - - for (i = 0; i < poly->totloop; i++) { - float len = len_v3v3(nullptr, positions[corner_verts[poly->loopstart + i]]); - if (len < mindist) { - mindist = len; - minS = i; - } - } - S = minS; -#endif - /* temp not implemented yet and also not working properly in current master. - * (was worked around by subdividing once) */ - S = 0; - *x = 0; - *y = 0; - } - - return S; -} diff --git a/source/blender/blenkernel/intern/multires_unsubdivide.cc b/source/blender/blenkernel/intern/multires_unsubdivide.cc index ddccc660e25..658977ec587 100644 --- a/source/blender/blenkernel/intern/multires_unsubdivide.cc +++ b/source/blender/blenkernel/intern/multires_unsubdivide.cc @@ -21,10 +21,10 @@ #include "BLI_math_vector.h" #include "BKE_attribute.hh" +#include "BKE_ccg.hh" #include "BKE_customdata.hh" #include "BKE_mesh.hh" #include "BKE_multires.hh" -#include "BKE_subsurf.hh" #include "bmesh.hh" @@ -647,8 +647,8 @@ static void store_grid_data(MultiresUnsubdivideContext *context, } /* Write the 4 grids of the current quad with the right orientation into the face_grid buffer. */ - const int grid_size = BKE_ccg_gridsize(context->num_original_levels); - const int face_grid_size = BKE_ccg_gridsize(context->num_original_levels + 1); + const int grid_size = CCG_grid_size(context->num_original_levels); + const int face_grid_size = CCG_grid_size(context->num_original_levels + 1); const int face_grid_area = face_grid_size * face_grid_size; float(*face_grid)[3] = MEM_calloc_arrayN(face_grid_area, "face_grid"); @@ -700,8 +700,8 @@ static void multires_unsubdivide_extract_single_grid_from_face_edge( BMEdge *initial_edge_x; BMEdge *initial_edge_y; - const int grid_size = BKE_ccg_gridsize(context->num_new_levels); - const int unsubdiv_grid_size = grid->grid_size = BKE_ccg_gridsize(context->num_total_levels); + const int grid_size = CCG_grid_size(context->num_new_levels); + const int unsubdiv_grid_size = grid->grid_size = CCG_grid_size(context->num_total_levels); BLI_assert(grid->grid_co == nullptr); grid->grid_size = unsubdiv_grid_size; grid->grid_co = MEM_calloc_arrayN( @@ -1171,7 +1171,7 @@ static void multires_create_grids_in_unsubdivided_base_mesh(MultiresUnsubdivideC MDisps *mdisps = static_cast(CustomData_add_layer( &base_mesh->corner_data, CD_MDISPS, CD_SET_DEFAULT, base_mesh->corners_num)); - const int totdisp = pow_i(BKE_ccg_gridsize(context->num_total_levels), 2); + const int totdisp = pow_i(CCG_grid_size(context->num_total_levels), 2); const int totloop = base_mesh->corners_num; BLI_assert(base_mesh->corners_num == context->num_grids); diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc index fd8a5147378..a10e2d815dd 100644 --- a/source/blender/blenkernel/intern/object.cc +++ b/source/blender/blenkernel/intern/object.cc @@ -125,7 +125,6 @@ #include "BKE_softbody.h" #include "BKE_speaker.h" #include "BKE_subdiv_ccg.hh" -#include "BKE_subsurf.hh" #include "BKE_vfont.hh" #include "BKE_volume.hh" diff --git a/source/blender/blenkernel/intern/paint.cc b/source/blender/blenkernel/intern/paint.cc index 59daa140d18..d5f3e8e383a 100644 --- a/source/blender/blenkernel/intern/paint.cc +++ b/source/blender/blenkernel/intern/paint.cc @@ -65,7 +65,6 @@ #include "BKE_paint_types.hh" #include "BKE_scene.hh" #include "BKE_subdiv_ccg.hh" -#include "BKE_subsurf.hh" #include "DEG_depsgraph.hh" #include "DEG_depsgraph_query.hh" @@ -2105,8 +2104,8 @@ bool paint_is_bmesh_face_hidden(const BMFace *f) float paint_grid_paint_mask(const GridPaintMask *gpm, uint level, uint x, uint y) { - int factor = BKE_ccg_factor(level, gpm->level); - int gridsize = BKE_ccg_gridsize(gpm->level); + int factor = CCG_grid_factor(level, gpm->level); + int gridsize = CCG_grid_size(gpm->level); return gpm->data[(y * factor) * gridsize + (x * factor)]; } @@ -2770,7 +2769,7 @@ void BKE_sculpt_mask_layers_ensure(Depsgraph *depsgraph, * isn't one already */ if (mmd && !CustomData_has_layer(&mesh->corner_data, CD_GRID_PAINT_MASK)) { int level = max_ii(1, mmd->sculptlvl); - int gridsize = BKE_ccg_gridsize(level); + int gridsize = CCG_grid_size(level); int gridarea = gridsize * gridsize; GridPaintMask *gmask = static_cast(CustomData_add_layer( diff --git a/source/blender/blenkernel/intern/shrinkwrap.cc b/source/blender/blenkernel/intern/shrinkwrap.cc index 2151f5929a9..c2d3521386b 100644 --- a/source/blender/blenkernel/intern/shrinkwrap.cc +++ b/source/blender/blenkernel/intern/shrinkwrap.cc @@ -37,7 +37,6 @@ #include "BKE_mesh_wrapper.hh" #include "BKE_subdiv.hh" #include "BKE_subdiv_deform.hh" -#include "BKE_subsurf.hh" #include "DEG_depsgraph_query.hh" diff --git a/source/blender/blenkernel/intern/subdiv_ccg.cc b/source/blender/blenkernel/intern/subdiv_ccg.cc index 89b89c9bbe7..557e3a75ccd 100644 --- a/source/blender/blenkernel/intern/subdiv_ccg.cc +++ b/source/blender/blenkernel/intern/subdiv_ccg.cc @@ -1443,37 +1443,6 @@ void BKE_subdiv_ccg_neighbor_coords_get(const SubdivCCG &subdiv_ccg, #endif } -const int *BKE_subdiv_ccg_start_face_grid_index_ensure(SubdivCCG &subdiv_ccg) -{ -#ifdef WITH_OPENSUBDIV - if (subdiv_ccg.cache_.start_face_grid_index.is_empty()) { - const Subdiv *subdiv = subdiv_ccg.subdiv; - const blender::opensubdiv::TopologyRefinerImpl *topology_refiner = subdiv->topology_refiner; - if (topology_refiner == nullptr) { - return nullptr; - } - - const int num_coarse_faces = topology_refiner->base_level().GetNumFaces(); - - subdiv_ccg.cache_.start_face_grid_index.reinitialize(num_coarse_faces); - - int start_grid_index = 0; - for (int face_index = 0; face_index < num_coarse_faces; face_index++) { - const int num_face_grids = topology_refiner->base_level().GetFaceVertices(face_index).size(); - subdiv_ccg.cache_.start_face_grid_index[face_index] = start_grid_index; - start_grid_index += num_face_grids; - } - } -#endif - - return subdiv_ccg.cache_.start_face_grid_index.data(); -} - -const int *BKE_subdiv_ccg_start_face_grid_index_get(const SubdivCCG &subdiv_ccg) -{ - return subdiv_ccg.cache_.start_face_grid_index.data(); -} - static void adjacent_vertices_index_from_adjacent_edge(const SubdivCCG &subdiv_ccg, const SubdivCCGCoord &coord, const blender::Span corner_verts, @@ -1600,15 +1569,6 @@ static void subdiv_ccg_coord_to_ptex_coord(const SubdivCCG &subdiv_ccg, } } -float3 BKE_subdiv_ccg_eval_limit_point(const SubdivCCG &subdiv_ccg, const SubdivCCGCoord &coord) -{ - Subdiv *subdiv = subdiv_ccg.subdiv; - int ptex_face_index; - float u, v; - subdiv_ccg_coord_to_ptex_coord(subdiv_ccg, coord, ptex_face_index, u, v); - return eval_limit_point(subdiv, ptex_face_index, u, v); -} - void BKE_subdiv_ccg_eval_limit_positions(const SubdivCCG &subdiv_ccg, const CCGKey &key, const int grid_index, @@ -1621,7 +1581,12 @@ void BKE_subdiv_ccg_eval_limit_positions(const SubdivCCG &subdiv_ccg, const int i = CCG_grid_xy_to_index(key.grid_size, x, y); coord.x = x; coord.y = y; - r_limit_positions[i] = BKE_subdiv_ccg_eval_limit_point(subdiv_ccg, coord); + + int ptex_face_index; + float u, v; + subdiv_ccg_coord_to_ptex_coord(subdiv_ccg, coord, ptex_face_index, u, v); + + r_limit_positions[i] = eval_limit_point(subdiv_ccg.subdiv, ptex_face_index, u, v); } } } diff --git a/source/blender/blenkernel/intern/subdiv_ccg_test.cc b/source/blender/blenkernel/intern/subdiv_ccg_test.cc index ccb0409ea09..ab6908f1174 100644 --- a/source/blender/blenkernel/intern/subdiv_ccg_test.cc +++ b/source/blender/blenkernel/intern/subdiv_ccg_test.cc @@ -4,8 +4,8 @@ #include "testing/testing.h" +#include "BKE_ccg.hh" #include "BKE_subdiv_ccg.hh" -#include "BKE_subsurf.hh" namespace blender::bke::tests { TEST(subdiv_ccg_coord, to_index) @@ -20,7 +20,7 @@ TEST(subdiv_ccg_coord, to_index) key.normal_offset = -1; key.mask_offset = -1; - key.grid_size = BKE_ccg_gridsize(key.level); /* 3 */ + key.grid_size = CCG_grid_size(key.level); /* 3 */ key.grid_area = key.grid_size * key.grid_size; /* 9 */ key.grid_bytes = key.grid_area * key.elem_size; @@ -46,7 +46,7 @@ TEST(subdiv_ccg_coord, constructor) key.normal_offset = -1; key.mask_offset = -1; - key.grid_size = BKE_ccg_gridsize(key.level); /* 3 */ + key.grid_size = CCG_grid_size(key.level); /* 3 */ key.grid_area = key.grid_size * key.grid_size; /* 9 */ key.grid_bytes = key.grid_area * key.elem_size; diff --git a/source/blender/blenkernel/intern/subdiv_inline.hh b/source/blender/blenkernel/intern/subdiv_inline.hh index 55b59b2712c..27f5d3fc177 100644 --- a/source/blender/blenkernel/intern/subdiv_inline.hh +++ b/source/blender/blenkernel/intern/subdiv_inline.hh @@ -28,7 +28,7 @@ BLI_INLINE void ptex_face_uv_to_grid_uv(const float ptex_u, BLI_INLINE float2 ptex_face_uv_to_grid_uv(const float2 &ptex_uv) { - return 1.0f - float2(ptex_uv.y, ptex_uv.x); + return float2(1.0f - ptex_uv.y, 1.0f - ptex_uv.x); } BLI_INLINE void grid_uv_to_ptex_face_uv(const float grid_u, diff --git a/source/blender/blenkernel/intern/subsurf_ccg.cc b/source/blender/blenkernel/intern/subsurf_ccg.cc deleted file mode 100644 index 5ab81e2932e..00000000000 --- a/source/blender/blenkernel/intern/subsurf_ccg.cc +++ /dev/null @@ -1,1753 +0,0 @@ -/* SPDX-FileCopyrightText: 2005 Blender Authors - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -/** \file - * \ingroup bke - */ - -#include -#include -#include -#include -#include - -#include "atomic_ops.h" - -#include "MEM_guardedalloc.h" - -#include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" -#include "DNA_modifier_types.h" -#include "DNA_object_types.h" -#include "DNA_scene_types.h" - -#include "BLI_listbase.h" -#include "BLI_math_vector.h" -#include "BLI_memarena.h" -#include "BLI_ordered_edge.hh" -#include "BLI_set.hh" -#include "BLI_task.h" -#include "BLI_threads.h" -#include "BLI_utildefines.h" -#include "BLI_vector.hh" - -#include "BKE_ccg.hh" -#include "BKE_customdata.hh" -#include "BKE_mesh_legacy_derived_mesh.hh" -#include "BKE_mesh_mapping.hh" -#include "BKE_multires.hh" -#include "BKE_scene.hh" -#include "BKE_subsurf.hh" - -#include "CCGSubSurf.h" - -static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, - int drawInteriorEdges, - int useSubsurfUv, - DerivedMesh *dm); -/// - -static void *arena_alloc(CCGAllocatorHDL a, int numBytes) -{ - return BLI_memarena_alloc(reinterpret_cast(a), numBytes); -} - -static void *arena_realloc(CCGAllocatorHDL a, void *ptr, int newSize, int oldSize) -{ - void *p2 = BLI_memarena_alloc(reinterpret_cast(a), newSize); - if (ptr) { - memcpy(p2, ptr, oldSize); - } - return p2; -} - -static void arena_free(CCGAllocatorHDL /*a*/, void * /*ptr*/) -{ - /* do nothing */ -} - -static void arena_release(CCGAllocatorHDL a) -{ - BLI_memarena_free(reinterpret_cast(a)); -} - -enum CCGFlags { - CCG_USE_AGING = 1, - CCG_USE_ARENA = 2, - CCG_CALC_NORMALS = 4, - /* add an extra four bytes for a mask layer */ - CCG_ALLOC_MASK = 8, - CCG_SIMPLE_SUBDIV = 16, -}; -ENUM_OPERATORS(CCGFlags, CCG_SIMPLE_SUBDIV); - -static CCGSubSurf *_getSubSurf(CCGSubSurf *prevSS, int subdivLevels, int numLayers, CCGFlags flags) -{ - CCGMeshIFC ifc; - CCGSubSurf *ccgSS; - int useAging = !!(flags & CCG_USE_AGING); - int useArena = flags & CCG_USE_ARENA; - int normalOffset = 0; - - /* (subdivLevels == 0) is not allowed */ - subdivLevels = std::max(subdivLevels, 1); - - if (prevSS) { - int oldUseAging; - - ccgSubSurf_getUseAgeCounts(prevSS, &oldUseAging, nullptr, nullptr, nullptr); - - if ((oldUseAging != useAging) || - (ccgSubSurf_getSimpleSubdiv(prevSS) != !!(flags & CCG_SIMPLE_SUBDIV))) - { - ccgSubSurf_free(prevSS); - } - else { - ccgSubSurf_setSubdivisionLevels(prevSS, subdivLevels); - - return prevSS; - } - } - - if (useAging) { - ifc.vertUserSize = ifc.edgeUserSize = ifc.faceUserSize = 12; - } - else { - ifc.vertUserSize = ifc.edgeUserSize = ifc.faceUserSize = 8; - } - ifc.numLayers = numLayers; - ifc.vertDataSize = sizeof(float) * numLayers; - normalOffset += sizeof(float) * numLayers; - if (flags & CCG_CALC_NORMALS) { - ifc.vertDataSize += sizeof(float[3]); - } - if (flags & CCG_ALLOC_MASK) { - ifc.vertDataSize += sizeof(float); - } - ifc.simpleSubdiv = !!(flags & CCG_SIMPLE_SUBDIV); - - if (useArena) { - CCGAllocatorIFC allocatorIFC; - CCGAllocatorHDL allocator = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "subsurf arena"); - - allocatorIFC.alloc = arena_alloc; - allocatorIFC.realloc = arena_realloc; - allocatorIFC.free = arena_free; - allocatorIFC.release = arena_release; - - ccgSS = ccgSubSurf_new(&ifc, subdivLevels, &allocatorIFC, allocator); - } - else { - ccgSS = ccgSubSurf_new(&ifc, subdivLevels, nullptr, nullptr); - } - - if (useAging) { - ccgSubSurf_setUseAgeCounts(ccgSS, 1, 8, 8, 8); - } - - if (flags & CCG_ALLOC_MASK) { - normalOffset += sizeof(float); - /* mask is allocated after regular layers */ - ccgSubSurf_setAllocMask(ccgSS, 1, sizeof(float) * numLayers); - } - - if (flags & CCG_CALC_NORMALS) { - ccgSubSurf_setCalcVertexNormals(ccgSS, 1, normalOffset); - } - else { - ccgSubSurf_setCalcVertexNormals(ccgSS, 0, 0); - } - - return ccgSS; -} - -static int getEdgeIndex(CCGSubSurf *ss, CCGEdge *e, int x, int edgeSize) -{ - CCGVert *v0 = ccgSubSurf_getEdgeVert0(e); - CCGVert *v1 = ccgSubSurf_getEdgeVert1(e); - int v0idx = *((int *)ccgSubSurf_getVertUserData(ss, v0)); - int v1idx = *((int *)ccgSubSurf_getVertUserData(ss, v1)); - int edgeBase = *((int *)ccgSubSurf_getEdgeUserData(ss, e)); - - if (x == 0) { - return v0idx; - } - if (x == edgeSize - 1) { - return v1idx; - } - - return edgeBase + x - 1; -} - -static int getFaceIndex( - CCGSubSurf *ss, CCGFace *f, int S, int x, int y, int edgeSize, int gridSize) -{ - int faceBase = *((int *)ccgSubSurf_getFaceUserData(ss, f)); - int numVerts = ccgSubSurf_getFaceNumVerts(f); - - if (x == gridSize - 1 && y == gridSize - 1) { - CCGVert *v = ccgSubSurf_getFaceVert(f, S); - return *((int *)ccgSubSurf_getVertUserData(ss, v)); - } - if (x == gridSize - 1) { - CCGVert *v = ccgSubSurf_getFaceVert(f, S); - CCGEdge *e = ccgSubSurf_getFaceEdge(f, S); - int edgeBase = *((int *)ccgSubSurf_getEdgeUserData(ss, e)); - if (v == ccgSubSurf_getEdgeVert0(e)) { - return edgeBase + (gridSize - 1 - y) - 1; - } - - return edgeBase + (edgeSize - 2 - 1) - ((gridSize - 1 - y) - 1); - } - if (y == gridSize - 1) { - CCGVert *v = ccgSubSurf_getFaceVert(f, S); - CCGEdge *e = ccgSubSurf_getFaceEdge(f, (S + numVerts - 1) % numVerts); - int edgeBase = *((int *)ccgSubSurf_getEdgeUserData(ss, e)); - if (v == ccgSubSurf_getEdgeVert0(e)) { - return edgeBase + (gridSize - 1 - x) - 1; - } - - return edgeBase + (edgeSize - 2 - 1) - ((gridSize - 1 - x) - 1); - } - if (x == 0 && y == 0) { - return faceBase; - } - if (x == 0) { - S = (S + numVerts - 1) % numVerts; - return faceBase + 1 + (gridSize - 2) * S + (y - 1); - } - if (y == 0) { - return faceBase + 1 + (gridSize - 2) * S + (x - 1); - } - - return faceBase + 1 + (gridSize - 2) * numVerts + S * (gridSize - 2) * (gridSize - 2) + - (y - 1) * (gridSize - 2) + (x - 1); -} - -static void get_face_uv_map_vert(UvVertMap *vmap, - const blender::OffsetIndices faces, - const int *face_verts, - int fi, - CCGVertHDL *fverts) -{ - UvMapVert *v, *nv; - int j, nverts = faces[fi].size(); - - for (j = 0; j < nverts; j++) { - for (nv = v = BKE_mesh_uv_vert_map_get_vert(vmap, face_verts[j]); v; v = v->next) { - if (v->separate) { - nv = v; - } - if (v->face_index == fi) { - break; - } - } - - fverts[j] = POINTER_FROM_UINT(faces[nv->face_index].start() + nv->loop_of_face_index); - } -} - -static int ss_sync_from_uv(CCGSubSurf *ss, - CCGSubSurf *origss, - DerivedMesh *dm, - const float (*mloopuv)[2]) -{ - const blender::OffsetIndices faces(blender::Span(dm->getPolyArray(dm), dm->getNumPolys(dm) + 1)); - int *corner_verts = dm->getCornerVertArray(dm); - int totvert = dm->getNumVerts(dm); - int totface = dm->getNumPolys(dm); - int i, seam; - UvMapVert *v; - UvVertMap *vmap; - blender::Vector fverts; - float uv[3] = {0.0f, 0.0f, 0.0f}; /* only first 2 values are written into */ - - const int corners_num = faces.total_size(); - - /* previous behavior here is without accounting for winding, however this causes stretching in - * UV map in really simple cases with mirror + subsurf, see second part of #44530. - * Also, initially intention is to treat merged vertices from mirror modifier as seams. - * This fixes a very old regression (2.49 was correct here) */ - vmap = BKE_mesh_uv_vert_map_create( - faces, - {corner_verts, corners_num}, - {reinterpret_cast(mloopuv), corners_num}, - totvert, - blender::float2(STD_UV_CONNECT_LIMIT), - true); - if (!vmap) { - return 0; - } - - ccgSubSurf_initFullSync(ss); - - /* create vertices */ - for (i = 0; i < totvert; i++) { - if (!BKE_mesh_uv_vert_map_get_vert(vmap, i)) { - continue; - } - - for (v = BKE_mesh_uv_vert_map_get_vert(vmap, i)->next; v; v = v->next) { - if (v->separate) { - break; - } - } - - seam = (v != nullptr); - - for (v = BKE_mesh_uv_vert_map_get_vert(vmap, i); v; v = v->next) { - if (v->separate) { - CCGVert *ssv; - int loopid = faces[v->face_index].start() + v->loop_of_face_index; - CCGVertHDL vhdl = POINTER_FROM_INT(loopid); - - copy_v2_v2(uv, mloopuv[loopid]); - - ccgSubSurf_syncVert(ss, vhdl, uv, seam, &ssv); - } - } - } - - /* create edges */ - blender::Set eset; - eset.reserve(totface); - - for (i = 0; i < totface; i++) { - const blender::IndexRange face = faces[i]; - int nverts = face.size(); - int j, j_next; - CCGFace *origf = ccgSubSurf_getFace(origss, POINTER_FROM_INT(i)); - // uint *fv = &face.v1; - - fverts.reinitialize(nverts); - - get_face_uv_map_vert(vmap, faces, &corner_verts[face.start()], i, fverts.data()); - - for (j = 0, j_next = nverts - 1; j < nverts; j_next = j++) { - uint v0 = POINTER_AS_UINT(fverts[j_next]); - uint v1 = POINTER_AS_UINT(fverts[j]); - - if (eset.add({v0, v1})) { - CCGEdge *e, *orige = ccgSubSurf_getFaceEdge(origf, j_next); - CCGEdgeHDL ehdl = POINTER_FROM_INT(face[j_next]); - float crease = ccgSubSurf_getEdgeCrease(orige); - - ccgSubSurf_syncEdge(ss, ehdl, fverts[j_next], fverts[j], crease, &e); - } - } - } - - /* create faces */ - for (i = 0; i < totface; i++) { - const blender::IndexRange face = faces[i]; - int nverts = face.size(); - CCGFace *f; - - fverts.reinitialize(nverts); - - get_face_uv_map_vert(vmap, faces, &corner_verts[face.start()], i, fverts.data()); - ccgSubSurf_syncFace(ss, POINTER_FROM_INT(i), nverts, fverts.data(), &f); - } - - BKE_mesh_uv_vert_map_free(vmap); - ccgSubSurf_processSync(ss); - - return 1; -} - -static void set_subsurf_legacy_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *result, int n) -{ - CCGFaceIterator fi; - int index, gridSize, gridFaces, /*edgeSize,*/ totface, x, y, S; - const float(*dmloopuv)[2] = static_cast( - CustomData_get_layer_n(&dm->loopData, CD_PROP_FLOAT2, n)); - /* need to update both CD_MTFACE & CD_PROP_FLOAT2, hrmf, we could get away with - * just tface except applying the modifier then looses subsurf UV */ - MTFace *tface = static_cast( - CustomData_get_layer_n_for_write(&result->faceData, CD_MTFACE, n, result->numTessFaceData)); - float(*mloopuv)[2] = static_cast(CustomData_get_layer_n_for_write( - &result->loopData, CD_PROP_FLOAT2, n, result->getNumLoops(result))); - - if (!dmloopuv || (!tface && !mloopuv)) { - return; - } - - /* create a CCGSubSurf from uv's */ - CCGSubSurf *uvss = _getSubSurf(nullptr, ccgSubSurf_getSubdivisionLevels(ss), 2, CCG_USE_ARENA); - - if (!ss_sync_from_uv(uvss, ss, dm, dmloopuv)) { - ccgSubSurf_free(uvss); - return; - } - - /* get some info from CCGSubSurf */ - totface = ccgSubSurf_getNumFaces(uvss); - // edgeSize = ccgSubSurf_getEdgeSize(uvss); /* UNUSED */ - gridSize = ccgSubSurf_getGridSize(uvss); - gridFaces = gridSize - 1; - - /* make a map from original faces to CCGFaces */ - CCGFace **faceMap = MEM_malloc_arrayN(size_t(totface), "facemapuv"); - for (ccgSubSurf_initFaceIterator(uvss, &fi); !ccgFaceIterator_isStopped(&fi); - ccgFaceIterator_next(&fi)) - { - CCGFace *f = ccgFaceIterator_getCurrent(&fi); - faceMap[POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f))] = f; - } - - /* load coordinates from uvss into tface */ - MTFace *tf = tface; - float(*mluv)[2] = mloopuv; - - for (index = 0; index < totface; index++) { - CCGFace *f = faceMap[index]; - int numVerts = ccgSubSurf_getFaceNumVerts(f); - - for (S = 0; S < numVerts; S++) { - float(*faceGridData)[2] = static_cast( - ccgSubSurf_getFaceGridDataArray(uvss, f, S)); - - for (y = 0; y < gridFaces; y++) { - for (x = 0; x < gridFaces; x++) { - float *a = faceGridData[(y + 0) * gridSize + x + 0]; - float *b = faceGridData[(y + 0) * gridSize + x + 1]; - float *c = faceGridData[(y + 1) * gridSize + x + 1]; - float *d = faceGridData[(y + 1) * gridSize + x + 0]; - - if (tf) { - copy_v2_v2(tf->uv[0], a); - copy_v2_v2(tf->uv[1], d); - copy_v2_v2(tf->uv[2], c); - copy_v2_v2(tf->uv[3], b); - tf++; - } - - if (mluv) { - copy_v2_v2(mluv[0], a); - copy_v2_v2(mluv[1], d); - copy_v2_v2(mluv[2], c); - copy_v2_v2(mluv[3], b); - mluv += 4; - } - } - } - } - } - - ccgSubSurf_free(uvss); - MEM_freeN(faceMap); -} - -static void set_subsurf_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *result, int layer_index) -{ - set_subsurf_legacy_uv(ss, dm, result, layer_index); -} - -/* face weighting */ -#define SUB_ELEMS_FACE 50 -typedef float FaceVertWeight[SUB_ELEMS_FACE][SUB_ELEMS_FACE]; - -struct FaceVertWeightEntry { - FaceVertWeight *weight; - float *w; - int valid; -}; - -struct WeightTable { - FaceVertWeightEntry *weight_table; - int len; -}; - -static float *get_ss_weights(WeightTable *wtable, int gridCuts, int faceLen) -{ - int x, y, i, j; - float *w, w1, w2, w4, fac, fac2, fx, fy; - - if (wtable->len <= faceLen) { - void *tmp = MEM_calloc_arrayN(size_t(faceLen) + 1, - "weight table alloc 2"); - - if (wtable->len) { - memcpy(tmp, wtable->weight_table, sizeof(FaceVertWeightEntry) * wtable->len); - MEM_freeN(wtable->weight_table); - } - - wtable->weight_table = static_cast(tmp); - wtable->len = faceLen + 1; - } - - if (!wtable->weight_table[faceLen].valid) { - wtable->weight_table[faceLen].valid = 1; - wtable->weight_table[faceLen].w = w = MEM_calloc_arrayN( - size_t(faceLen) * size_t(faceLen) * size_t(gridCuts + 2) * size_t(gridCuts + 2), - "weight table alloc"); - fac = 1.0f / float(faceLen); - - for (i = 0; i < faceLen; i++) { - for (x = 0; x < gridCuts + 2; x++) { - for (y = 0; y < gridCuts + 2; y++) { - fx = 0.5f - float(x) / float(gridCuts + 1) / 2.0f; - fy = 0.5f - float(y) / float(gridCuts + 1) / 2.0f; - - fac2 = faceLen - 4; - w1 = (1.0f - fx) * (1.0f - fy) + (-fac2 * fx * fy * fac); - w2 = (1.0f - fx + fac2 * fx * -fac) * (fy); - w4 = (fx) * (1.0f - fy + -fac2 * fy * fac); - - /* These values aren't used for triangles and cause divide by zero. */ - if (faceLen > 3) { - fac2 = 1.0f - (w1 + w2 + w4); - fac2 = fac2 / float(faceLen - 3); - for (j = 0; j < faceLen; j++) { - w[j] = fac2; - } - } - - w[i] = w1; - w[(i - 1 + faceLen) % faceLen] = w2; - w[(i + 1) % faceLen] = w4; - - w += faceLen; - } - } - } - } - - return wtable->weight_table[faceLen].w; -} - -static void free_ss_weights(WeightTable *wtable) -{ - int i; - - for (i = 0; i < wtable->len; i++) { - if (wtable->weight_table[i].valid) { - MEM_freeN(wtable->weight_table[i].w); - } - } - - if (wtable->weight_table) { - MEM_freeN(wtable->weight_table); - } -} - -static void ss_sync_ccg_from_derivedmesh(CCGSubSurf *ss, - DerivedMesh *dm, - float (*vertexCos)[3], - int useFlatSubdiv) -{ - float creaseFactor = float(ccgSubSurf_getSubdivisionLevels(ss)); - blender::Vector fverts; - float(*positions)[3] = (float(*)[3])dm->getVertArray(dm); - const blender::int2 *edges = reinterpret_cast(dm->getEdgeArray(dm)); - int *corner_verts = dm->getCornerVertArray(dm); - const blender::OffsetIndices faces(blender::Span(dm->getPolyArray(dm), dm->getNumPolys(dm) + 1)); - int totvert = dm->getNumVerts(dm); - int totedge = dm->getNumEdges(dm); - int i, j; - int *index; - - ccgSubSurf_initFullSync(ss); - - index = (int *)dm->getVertDataArray(dm, CD_ORIGINDEX); - for (i = 0; i < totvert; i++) { - CCGVert *v; - - if (vertexCos) { - ccgSubSurf_syncVert(ss, POINTER_FROM_INT(i), vertexCos[i], 0, &v); - } - else { - ccgSubSurf_syncVert(ss, POINTER_FROM_INT(i), positions[i], 0, &v); - } - - ((int *)ccgSubSurf_getVertUserData(ss, v))[1] = (index) ? *index++ : i; - } - - index = (int *)dm->getEdgeDataArray(dm, CD_ORIGINDEX); - const float *creases = (const float *)CustomData_get_layer_named( - &dm->edgeData, CD_PROP_FLOAT, "crease_edge"); - for (i = 0; i < totedge; i++) { - CCGEdge *e; - float crease; - - crease = useFlatSubdiv ? creaseFactor : (creases ? creases[i] * creaseFactor : 0.0f); - - ccgSubSurf_syncEdge(ss, - POINTER_FROM_INT(i), - POINTER_FROM_UINT(edges[i][0]), - POINTER_FROM_UINT(edges[i][1]), - crease, - &e); - - ((int *)ccgSubSurf_getEdgeUserData(ss, e))[1] = (index) ? *index++ : i; - } - - index = (int *)dm->getPolyDataArray(dm, CD_ORIGINDEX); - for (i = 0; i < dm->numPolyData; i++) { - const blender::IndexRange face = faces[i]; - - CCGFace *f; - - fverts.reinitialize(face.size()); - - for (j = 0; j < face.size(); j++) { - fverts[j] = POINTER_FROM_UINT(corner_verts[face[j]]); - } - - /* This is very bad, means mesh is internally inconsistent. - * it is not really possible to continue without modifying - * other parts of code significantly to handle missing faces. - * since this really shouldn't even be possible we just bail. */ - if (ccgSubSurf_syncFace(ss, POINTER_FROM_INT(i), face.size(), fverts.data(), &f) == - eCCGError_InvalidValue) - { - static int hasGivenError = 0; - - if (!hasGivenError) { - // XXX error("Unrecoverable error in SubSurf calculation," - // " mesh is inconsistent."); - - hasGivenError = 1; - } - - return; - } - - ((int *)ccgSubSurf_getFaceUserData(ss, f))[1] = (index) ? *index++ : i; - } - - ccgSubSurf_processSync(ss); -} - -static void ss_sync_from_derivedmesh(CCGSubSurf *ss, - DerivedMesh *dm, - float (*vertexCos)[3], - int use_flat_subdiv, - bool /*use_subdiv_uvs*/) -{ - ss_sync_ccg_from_derivedmesh(ss, dm, vertexCos, use_flat_subdiv); -} - -/***/ - -static int ccgDM_getVertMapIndex(CCGSubSurf *ss, CCGVert *v) -{ - return ((int *)ccgSubSurf_getVertUserData(ss, v))[1]; -} - -static int ccgDM_getEdgeMapIndex(CCGSubSurf *ss, CCGEdge *e) -{ - return ((int *)ccgSubSurf_getEdgeUserData(ss, e))[1]; -} - -static int ccgDM_getFaceMapIndex(CCGSubSurf *ss, CCGFace *f) -{ - return ((int *)ccgSubSurf_getFaceUserData(ss, f))[1]; -} - -static int ccgDM_getNumVerts(DerivedMesh *dm) -{ - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; - - return ccgSubSurf_getNumFinalVerts(ccgdm->ss); -} - -static int ccgDM_getNumEdges(DerivedMesh *dm) -{ - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; - - return ccgSubSurf_getNumFinalEdges(ccgdm->ss); -} - -static int ccgDM_getNumPolys(DerivedMesh *dm) -{ - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; - - return ccgSubSurf_getNumFinalFaces(ccgdm->ss); -} - -static int ccgDM_getNumLoops(DerivedMesh *dm) -{ - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; - - /* All subsurf faces are quads */ - return 4 * ccgSubSurf_getNumFinalFaces(ccgdm->ss); -} - -/* utility function */ -BLI_INLINE void ccgDM_to_MVert(float mv[3], const CCGKey *key, CCGElem *elem) -{ - copy_v3_v3(mv, CCG_elem_co(*key, elem)); -} - -static void ccgDM_copyFinalVertArray(DerivedMesh *dm, float (*r_positions)[3]) -{ - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; - CCGSubSurf *ss = ccgdm->ss; - CCGElem *vd; - CCGKey key; - int index; - int totvert, totedge, totface; - int gridSize = ccgSubSurf_getGridSize(ss); - int edgeSize = ccgSubSurf_getEdgeSize(ss); - uint i = 0; - - CCG_key_top_level(&key, ss); - - totface = ccgSubSurf_getNumFaces(ss); - for (index = 0; index < totface; index++) { - CCGFace *f = ccgdm->faceMap[index].face; - int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f); - - vd = static_cast(ccgSubSurf_getFaceCenterData(f)); - ccgDM_to_MVert(r_positions[i++], &key, vd); - - for (S = 0; S < numVerts; S++) { - for (x = 1; x < gridSize - 1; x++) { - vd = static_cast(ccgSubSurf_getFaceGridEdgeData(ss, f, S, x)); - ccgDM_to_MVert(r_positions[i++], &key, vd); - } - } - - for (S = 0; S < numVerts; S++) { - for (y = 1; y < gridSize - 1; y++) { - for (x = 1; x < gridSize - 1; x++) { - vd = static_cast(ccgSubSurf_getFaceGridData(ss, f, S, x, y)); - ccgDM_to_MVert(r_positions[i++], &key, vd); - } - } - } - } - - totedge = ccgSubSurf_getNumEdges(ss); - for (index = 0; index < totedge; index++) { - CCGEdge *e = ccgdm->edgeMap[index].edge; - int x; - - for (x = 1; x < edgeSize - 1; x++) { - /* NOTE(@ideasman42): This gives errors with `--debug-fpe` the normals don't seem to be - * unit length. This is most likely caused by edges with no faces which are now zeroed out, - * see comment in: `ccgSubSurf__calcVertNormals()`. */ - vd = static_cast(ccgSubSurf_getEdgeData(ss, e, x)); - ccgDM_to_MVert(r_positions[i++], &key, vd); - } - } - - totvert = ccgSubSurf_getNumVerts(ss); - for (index = 0; index < totvert; index++) { - CCGVert *v = ccgdm->vertMap[index].vert; - - vd = static_cast(ccgSubSurf_getVertData(ss, v)); - ccgDM_to_MVert(r_positions[i++], &key, vd); - } -} - -/* utility function */ -BLI_INLINE void ccgDM_to_MEdge(blender::int2 *edge, const int v1, const int v2) -{ - edge->x = v1; - edge->y = v2; -} - -static void ccgDM_copyFinalEdgeArray(DerivedMesh *dm, blender::int2 *edges) -{ - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; - CCGSubSurf *ss = ccgdm->ss; - int index; - int totedge, totface; - int gridSize = ccgSubSurf_getGridSize(ss); - int edgeSize = ccgSubSurf_getEdgeSize(ss); - uint i = 0; - - totface = ccgSubSurf_getNumFaces(ss); - for (index = 0; index < totface; index++) { - CCGFace *f = ccgdm->faceMap[index].face; - int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f); - - for (S = 0; S < numVerts; S++) { - for (x = 0; x < gridSize - 1; x++) { - ccgDM_to_MEdge(&edges[i++], - getFaceIndex(ss, f, S, x, 0, edgeSize, gridSize), - getFaceIndex(ss, f, S, x + 1, 0, edgeSize, gridSize)); - } - - for (x = 1; x < gridSize - 1; x++) { - for (y = 0; y < gridSize - 1; y++) { - ccgDM_to_MEdge(&edges[i++], - getFaceIndex(ss, f, S, x, y, edgeSize, gridSize), - getFaceIndex(ss, f, S, x, y + 1, edgeSize, gridSize)); - ccgDM_to_MEdge(&edges[i++], - getFaceIndex(ss, f, S, y, x, edgeSize, gridSize), - getFaceIndex(ss, f, S, y + 1, x, edgeSize, gridSize)); - } - } - } - } - - totedge = ccgSubSurf_getNumEdges(ss); - for (index = 0; index < totedge; index++) { - CCGEdge *e = ccgdm->edgeMap[index].edge; - for (int x = 0; x < edgeSize - 1; x++) { - ccgDM_to_MEdge( - &edges[i++], getEdgeIndex(ss, e, x, edgeSize), getEdgeIndex(ss, e, x + 1, edgeSize)); - } - } -} - -struct CopyFinalLoopArrayData { - CCGDerivedMesh *ccgdm; - int *corner_verts; - int *corner_edges; - int grid_size; - int *grid_offset; - int edge_size; -}; - -static void copyFinalLoopArray_task_cb(void *__restrict userdata, - const int iter, - const TaskParallelTLS *__restrict /*tls*/) -{ - CopyFinalLoopArrayData *data = static_cast(userdata); - CCGDerivedMesh *ccgdm = data->ccgdm; - CCGSubSurf *ss = ccgdm->ss; - const int grid_size = data->grid_size; - const int edge_size = data->edge_size; - CCGFace *f = ccgdm->faceMap[iter].face; - const int num_verts = ccgSubSurf_getFaceNumVerts(f); - const int grid_index = data->grid_offset[iter]; - int *corner_verts = data->corner_verts; - int *corner_edges = data->corner_edges; - - size_t loop_i = 4 * size_t(grid_index) * (grid_size - 1) * (grid_size - 1); - for (int S = 0; S < num_verts; S++) { - for (int y = 0; y < grid_size - 1; y++) { - for (int x = 0; x < grid_size - 1; x++) { - - const int v1 = getFaceIndex(ss, f, S, x + 0, y + 0, edge_size, grid_size); - const int v2 = getFaceIndex(ss, f, S, x + 0, y + 1, edge_size, grid_size); - const int v3 = getFaceIndex(ss, f, S, x + 1, y + 1, edge_size, grid_size); - const int v4 = getFaceIndex(ss, f, S, x + 1, y + 0, edge_size, grid_size); - - if (corner_verts) { - corner_verts[loop_i + 0] = v1; - corner_verts[loop_i + 1] = v2; - corner_verts[loop_i + 2] = v3; - corner_verts[loop_i + 3] = v4; - } - if (corner_edges) { - corner_edges[loop_i + 0] = ccgdm->ehash->index_of({v1, v2}); - corner_edges[loop_i + 1] = ccgdm->ehash->index_of({v2, v3}); - corner_edges[loop_i + 2] = ccgdm->ehash->index_of({v3, v4}); - corner_edges[loop_i + 3] = ccgdm->ehash->index_of({v4, v1}); - } - - loop_i += 4; - } - } - } -} - -static void ccgDM_copyFinalCornerVertArray(DerivedMesh *dm, int *r_corner_verts) -{ - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; - CCGSubSurf *ss = ccgdm->ss; - - CopyFinalLoopArrayData data; - data.ccgdm = ccgdm; - data.corner_verts = r_corner_verts; - data.corner_edges = nullptr; - data.grid_size = ccgSubSurf_getGridSize(ss); - data.grid_offset = dm->getGridOffset(dm); - data.edge_size = ccgSubSurf_getEdgeSize(ss); - - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.min_iter_per_thread = 1; - - BLI_task_parallel_range( - 0, ccgSubSurf_getNumFaces(ss), &data, copyFinalLoopArray_task_cb, &settings); -} - -static void ccgDM_copyFinalCornerEdgeArray(DerivedMesh *dm, int *r_corner_edges) -{ - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; - CCGSubSurf *ss = ccgdm->ss; - - if (!ccgdm->ehash) { - BLI_mutex_lock(&ccgdm->loops_cache_lock); - if (!ccgdm->ehash) { - auto *ehash = new blender::VectorSet(); - ehash->reserve(ccgdm->dm.numEdgeData); - - const blender::int2 *medge = reinterpret_cast( - ccgdm->dm.getEdgeArray((DerivedMesh *)ccgdm)); - - for (int i = 0; i < ccgdm->dm.numEdgeData; i++) { - ehash->add({medge[i][0], medge[i][1]}); - } - - atomic_cas_ptr((void **)&ccgdm->ehash, ccgdm->ehash, ehash); - } - BLI_mutex_unlock(&ccgdm->loops_cache_lock); - } - - CopyFinalLoopArrayData data; - data.ccgdm = ccgdm; - data.corner_verts = nullptr; - data.corner_edges = r_corner_edges; - data.grid_size = ccgSubSurf_getGridSize(ss); - data.grid_offset = dm->getGridOffset(dm); - data.edge_size = ccgSubSurf_getEdgeSize(ss); - - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.min_iter_per_thread = 1; - - BLI_task_parallel_range( - 0, ccgSubSurf_getNumFaces(ss), &data, copyFinalLoopArray_task_cb, &settings); -} - -static void ccgDM_copyFinalPolyArray(DerivedMesh *dm, int *r_face_offsets) -{ - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; - CCGSubSurf *ss = ccgdm->ss; - int index; - int totface; - int gridSize = ccgSubSurf_getGridSize(ss); - // int edgeSize = ccgSubSurf_getEdgeSize(ss); /* UNUSED. */ - int i = 0, k = 0; - - totface = ccgSubSurf_getNumFaces(ss); - for (index = 0; index < totface; index++) { - CCGFace *f = ccgdm->faceMap[index].face; - int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f); - - for (S = 0; S < numVerts; S++) { - for (y = 0; y < gridSize - 1; y++) { - for (x = 0; x < gridSize - 1; x++) { - r_face_offsets[i] = k; - k += 4; - i++; - } - } - } - } - r_face_offsets[i] = k; -} - -static void ccgDM_release(DerivedMesh *dm) -{ - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; - - DM_release(dm); - delete ccgdm->ehash; - - if (ccgdm->gridFaces) { - MEM_freeN(ccgdm->gridFaces); - } - if (ccgdm->gridData) { - MEM_freeN(ccgdm->gridData); - } - if (ccgdm->gridOffset) { - MEM_freeN(ccgdm->gridOffset); - } - if (ccgdm->gridHidden) { - /* Using dm->getNumGrids(dm) accesses freed memory */ - uint numGrids = ccgdm->numGrid; - for (uint i = 0; i < numGrids; i++) { - if (ccgdm->gridHidden[i]) { - MEM_freeN(ccgdm->gridHidden[i]); - } - } - MEM_freeN(ccgdm->gridHidden); - } - if (ccgdm->freeSS) { - ccgSubSurf_free(ccgdm->ss); - } - MEM_freeN(ccgdm->vertMap); - MEM_freeN(ccgdm->edgeMap); - MEM_freeN(ccgdm->faceMap); - - BLI_mutex_end(&ccgdm->loops_cache_lock); - BLI_rw_mutex_end(&ccgdm->origindex_cache_rwlock); - - MEM_freeN(ccgdm); -} - -static void *ccgDM_get_vert_data_layer(DerivedMesh *dm, const eCustomDataType type) -{ - if (type == CD_ORIGINDEX) { - /* create origindex on demand to save memory */ - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; - CCGSubSurf *ss = ccgdm->ss; - int *origindex; - int a, index, totnone, totorig; - - /* Avoid re-creation if the layer exists already */ - BLI_rw_mutex_lock(&ccgdm->origindex_cache_rwlock, THREAD_LOCK_READ); - origindex = static_cast(DM_get_vert_data_layer(dm, CD_ORIGINDEX)); - BLI_rw_mutex_unlock(&ccgdm->origindex_cache_rwlock); - if (origindex) { - return origindex; - } - - BLI_rw_mutex_lock(&ccgdm->origindex_cache_rwlock, THREAD_LOCK_WRITE); - - origindex = static_cast( - CustomData_add_layer(&dm->vertData, CD_ORIGINDEX, CD_SET_DEFAULT, dm->numVertData)); - - totorig = ccgSubSurf_getNumVerts(ss); - totnone = dm->numVertData - totorig; - - /* original vertices are at the end */ - for (a = 0; a < totnone; a++) { - origindex[a] = ORIGINDEX_NONE; - } - - for (index = 0; index < totorig; index++, a++) { - CCGVert *v = ccgdm->vertMap[index].vert; - origindex[a] = ccgDM_getVertMapIndex(ccgdm->ss, v); - } - BLI_rw_mutex_unlock(&ccgdm->origindex_cache_rwlock); - - return origindex; - } - - return DM_get_vert_data_layer(dm, type); -} - -static void *ccgDM_get_edge_data_layer(DerivedMesh *dm, const eCustomDataType type) -{ - if (type == CD_ORIGINDEX) { - /* create origindex on demand to save memory */ - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; - CCGSubSurf *ss = ccgdm->ss; - int *origindex; - int a, i, index, totnone, totorig, totedge; - int edgeSize = ccgSubSurf_getEdgeSize(ss); - - /* Avoid re-creation if the layer exists already */ - origindex = static_cast(DM_get_edge_data_layer(dm, CD_ORIGINDEX)); - if (origindex) { - return origindex; - } - - origindex = static_cast( - CustomData_add_layer(&dm->edgeData, CD_ORIGINDEX, CD_SET_DEFAULT, dm->numEdgeData)); - - totedge = ccgSubSurf_getNumEdges(ss); - totorig = totedge * (edgeSize - 1); - totnone = dm->numEdgeData - totorig; - - /* original edges are at the end */ - for (a = 0; a < totnone; a++) { - origindex[a] = ORIGINDEX_NONE; - } - - for (index = 0; index < totedge; index++) { - CCGEdge *e = ccgdm->edgeMap[index].edge; - int mapIndex = ccgDM_getEdgeMapIndex(ss, e); - - for (i = 0; i < edgeSize - 1; i++, a++) { - origindex[a] = mapIndex; - } - } - - return origindex; - } - - return DM_get_edge_data_layer(dm, type); -} - -static void *ccgDM_get_poly_data_layer(DerivedMesh *dm, const eCustomDataType type) -{ - if (type == CD_ORIGINDEX) { - /* create origindex on demand to save memory */ - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; - CCGSubSurf *ss = ccgdm->ss; - int *origindex; - int a, i, index, totface; - int gridFaces = ccgSubSurf_getGridSize(ss) - 1; - - /* Avoid re-creation if the layer exists already */ - origindex = static_cast(DM_get_poly_data_layer(dm, CD_ORIGINDEX)); - if (origindex) { - return origindex; - } - - origindex = static_cast( - CustomData_add_layer(&dm->polyData, CD_ORIGINDEX, CD_SET_DEFAULT, dm->numPolyData)); - - totface = ccgSubSurf_getNumFaces(ss); - - for (a = 0, index = 0; index < totface; index++) { - CCGFace *f = ccgdm->faceMap[index].face; - int numVerts = ccgSubSurf_getFaceNumVerts(f); - int mapIndex = ccgDM_getFaceMapIndex(ss, f); - - for (i = 0; i < gridFaces * gridFaces * numVerts; i++, a++) { - origindex[a] = mapIndex; - } - } - - return origindex; - } - - return DM_get_poly_data_layer(dm, type); -} - -static int ccgDM_getNumGrids(DerivedMesh *dm) -{ - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; - int index, numFaces, numGrids; - - numFaces = ccgSubSurf_getNumFaces(ccgdm->ss); - numGrids = 0; - - for (index = 0; index < numFaces; index++) { - CCGFace *f = ccgdm->faceMap[index].face; - numGrids += ccgSubSurf_getFaceNumVerts(f); - } - - return numGrids; -} - -static int ccgDM_getGridSize(DerivedMesh *dm) -{ - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; - return ccgSubSurf_getGridSize(ccgdm->ss); -} - -static void ccgdm_create_grids(DerivedMesh *dm) -{ - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; - CCGSubSurf *ss = ccgdm->ss; - CCGElem **gridData; - CCGFace **gridFaces; - int *gridOffset; - int index, numFaces, numGrids, S, gIndex /*, gridSize */; - - if (ccgdm->gridData) { - return; - } - - numGrids = ccgDM_getNumGrids(dm); - numFaces = ccgSubSurf_getNumFaces(ss); - // gridSize = ccgDM_getGridSize(dm); /* UNUSED */ - - /* compute offset into grid array for each face */ - gridOffset = MEM_malloc_arrayN(size_t(numFaces), "ccgdm.gridOffset"); - - for (gIndex = 0, index = 0; index < numFaces; index++) { - CCGFace *f = ccgdm->faceMap[index].face; - int numVerts = ccgSubSurf_getFaceNumVerts(f); - - gridOffset[index] = gIndex; - gIndex += numVerts; - } - - /* compute grid data */ - gridData = MEM_malloc_arrayN(size_t(numGrids), "ccgdm.gridData"); - gridFaces = MEM_malloc_arrayN(size_t(numGrids), "ccgdm.gridFaces"); - - ccgdm->gridHidden = MEM_calloc_arrayN(numGrids, "ccgdm.gridHidden"); - - for (gIndex = 0, index = 0; index < numFaces; index++) { - CCGFace *f = ccgdm->faceMap[index].face; - int numVerts = ccgSubSurf_getFaceNumVerts(f); - - for (S = 0; S < numVerts; S++, gIndex++) { - gridData[gIndex] = static_cast(ccgSubSurf_getFaceGridDataArray(ss, f, S)); - gridFaces[gIndex] = f; - } - } - - ccgdm->gridData = gridData; - ccgdm->gridFaces = gridFaces; - ccgdm->gridOffset = gridOffset; - ccgdm->numGrid = numGrids; -} - -static CCGElem **ccgDM_getGridData(DerivedMesh *dm) -{ - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; - - ccgdm_create_grids(dm); - return ccgdm->gridData; -} - -static int *ccgDM_getGridOffset(DerivedMesh *dm) -{ - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; - - ccgdm_create_grids(dm); - return ccgdm->gridOffset; -} - -static void ccgDM_getGridKey(DerivedMesh *dm, CCGKey *key) -{ - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; - CCG_key_top_level(key, ccgdm->ss); -} - -static void set_default_ccgdm_callbacks(CCGDerivedMesh *ccgdm) -{ - ccgdm->dm.getNumVerts = ccgDM_getNumVerts; - ccgdm->dm.getNumEdges = ccgDM_getNumEdges; - ccgdm->dm.getNumLoops = ccgDM_getNumLoops; - ccgdm->dm.getNumPolys = ccgDM_getNumPolys; - - ccgdm->dm.copyVertArray = ccgDM_copyFinalVertArray; - ccgdm->dm.copyEdgeArray = ccgDM_copyFinalEdgeArray; - ccgdm->dm.copyCornerVertArray = ccgDM_copyFinalCornerVertArray; - ccgdm->dm.copyCornerEdgeArray = ccgDM_copyFinalCornerEdgeArray; - ccgdm->dm.copyPolyArray = ccgDM_copyFinalPolyArray; - - ccgdm->dm.getVertDataArray = ccgDM_get_vert_data_layer; - ccgdm->dm.getEdgeDataArray = ccgDM_get_edge_data_layer; - ccgdm->dm.getPolyDataArray = ccgDM_get_poly_data_layer; - ccgdm->dm.getNumGrids = ccgDM_getNumGrids; - ccgdm->dm.getGridSize = ccgDM_getGridSize; - ccgdm->dm.getGridData = ccgDM_getGridData; - ccgdm->dm.getGridOffset = ccgDM_getGridOffset; - ccgdm->dm.getGridKey = ccgDM_getGridKey; - - ccgdm->dm.release = ccgDM_release; -} - -static void create_ccgdm_maps(CCGDerivedMesh *ccgdm, CCGSubSurf *ss) -{ - CCGVertIterator vi; - CCGEdgeIterator ei; - CCGFaceIterator fi; - int totvert, totedge, totface; - - totvert = ccgSubSurf_getNumVerts(ss); - ccgdm->vertMap = MEM_malloc_arrayN>( - size_t(totvert), "vertMap"); - for (ccgSubSurf_initVertIterator(ss, &vi); !ccgVertIterator_isStopped(&vi); - ccgVertIterator_next(&vi)) - { - CCGVert *v = ccgVertIterator_getCurrent(&vi); - - ccgdm->vertMap[POINTER_AS_INT(ccgSubSurf_getVertVertHandle(v))].vert = v; - } - - totedge = ccgSubSurf_getNumEdges(ss); - ccgdm->edgeMap = MEM_malloc_arrayN>( - size_t(totedge), "edgeMap"); - for (ccgSubSurf_initEdgeIterator(ss, &ei); !ccgEdgeIterator_isStopped(&ei); - ccgEdgeIterator_next(&ei)) - { - CCGEdge *e = ccgEdgeIterator_getCurrent(&ei); - - ccgdm->edgeMap[POINTER_AS_INT(ccgSubSurf_getEdgeEdgeHandle(e))].edge = e; - } - - totface = ccgSubSurf_getNumFaces(ss); - ccgdm->faceMap = MEM_malloc_arrayN>( - size_t(totface), "faceMap"); - for (ccgSubSurf_initFaceIterator(ss, &fi); !ccgFaceIterator_isStopped(&fi); - ccgFaceIterator_next(&fi)) - { - CCGFace *f = ccgFaceIterator_getCurrent(&fi); - - ccgdm->faceMap[POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f))].face = f; - } -} - -/* Fill in all geometry arrays making it possible to access any - * hires data from the CPU. - */ -static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm, - CCGSubSurf *ss, - DerivedMesh *dm, - bool useSubsurfUv) -{ - const int totvert = ccgSubSurf_getNumVerts(ss); - const int totedge = ccgSubSurf_getNumEdges(ss); - const int totface = ccgSubSurf_getNumFaces(ss); - int index; - int i; - int vertNum = 0, edgeNum = 0, faceNum = 0; - int *polyidx = nullptr; - blender::Vector loopidx; - blender::Vector vertidx; - int loopindex, loopindex2; - int edgeSize; - int gridSize; - int gridFaces, gridCuts; - int gridSideEdges; - int gridInternalEdges; - WeightTable wtable = {nullptr}; - bool has_edge_cd; - - edgeSize = ccgSubSurf_getEdgeSize(ss); - gridSize = ccgSubSurf_getGridSize(ss); - gridFaces = gridSize - 1; - gridCuts = gridSize - 2; - // gridInternalVerts = gridSideVerts * gridSideVerts; /* As yet, unused. */ - gridSideEdges = gridSize - 1; - gridInternalEdges = (gridSideEdges - 1) * gridSideEdges * 2; - - const int *base_polyOrigIndex = static_cast( - CustomData_get_layer(&dm->polyData, CD_ORIGINDEX)); - - int *vertOrigIndex = static_cast(DM_get_vert_data_layer(&ccgdm->dm, CD_ORIGINDEX)); - int *edgeOrigIndex = static_cast(DM_get_edge_data_layer(&ccgdm->dm, CD_ORIGINDEX)); - int *polyOrigIndex = static_cast(DM_get_poly_data_layer(&ccgdm->dm, CD_ORIGINDEX)); - - has_edge_cd = ((ccgdm->dm.edgeData.totlayer - (edgeOrigIndex ? 1 : 0)) != 0); - - loopindex = loopindex2 = 0; /* current loop index */ - for (index = 0; index < totface; index++) { - CCGFace *f = ccgdm->faceMap[index].face; - int numVerts = ccgSubSurf_getFaceNumVerts(f); - int numFinalEdges = numVerts * (gridSideEdges + gridInternalEdges); - int origIndex = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f)); - int g2_wid = gridCuts + 2; - float *w, *w2; - int s, x, y; - - w = get_ss_weights(&wtable, gridCuts, numVerts); - - ccgdm->faceMap[index].startVert = vertNum; - ccgdm->faceMap[index].startEdge = edgeNum; - ccgdm->faceMap[index].startFace = faceNum; - - /* set the face base vert */ - *((int *)ccgSubSurf_getFaceUserData(ss, f)) = vertNum; - - loopidx.reinitialize(numVerts); - for (s = 0; s < numVerts; s++) { - loopidx[s] = loopindex++; - } - - vertidx.reinitialize(numVerts); - for (s = 0; s < numVerts; s++) { - CCGVert *v = ccgSubSurf_getFaceVert(f, s); - vertidx[s] = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(v)); - } - - /* I think this is for interpolating the center vert? */ - w2 = w; // + numVerts*(g2_wid-1) * (g2_wid-1); //numVerts*((g2_wid-1) * g2_wid+g2_wid-1); - DM_interp_vert_data(dm, &ccgdm->dm, vertidx.data(), w2, numVerts, vertNum); - if (vertOrigIndex) { - *vertOrigIndex = ORIGINDEX_NONE; - vertOrigIndex++; - } - - vertNum++; - - /* Interpolate per-vert data. */ - for (s = 0; s < numVerts; s++) { - for (x = 1; x < gridFaces; x++) { - w2 = w + s * numVerts * g2_wid * g2_wid + x * numVerts; - DM_interp_vert_data(dm, &ccgdm->dm, vertidx.data(), w2, numVerts, vertNum); - - if (vertOrigIndex) { - *vertOrigIndex = ORIGINDEX_NONE; - vertOrigIndex++; - } - - vertNum++; - } - } - - /* Interpolate per-vert data. */ - for (s = 0; s < numVerts; s++) { - for (y = 1; y < gridFaces; y++) { - for (x = 1; x < gridFaces; x++) { - w2 = w + s * numVerts * g2_wid * g2_wid + (y * g2_wid + x) * numVerts; - DM_interp_vert_data(dm, &ccgdm->dm, vertidx.data(), w2, numVerts, vertNum); - - if (vertOrigIndex) { - *vertOrigIndex = ORIGINDEX_NONE; - vertOrigIndex++; - } - - vertNum++; - } - } - } - - if (edgeOrigIndex) { - for (i = 0; i < numFinalEdges; i++) { - edgeOrigIndex[edgeNum + i] = ORIGINDEX_NONE; - } - } - - for (s = 0; s < numVerts; s++) { - /* Interpolate per-face data. */ - for (y = 0; y < gridFaces; y++) { - for (x = 0; x < gridFaces; x++) { - w2 = w + s * numVerts * g2_wid * g2_wid + (y * g2_wid + x) * numVerts; - CustomData_interp(&dm->loopData, - &ccgdm->dm.loopData, - loopidx.data(), - w2, - nullptr, - numVerts, - loopindex2); - loopindex2++; - - w2 = w + s * numVerts * g2_wid * g2_wid + ((y + 1) * g2_wid + (x)) * numVerts; - CustomData_interp(&dm->loopData, - &ccgdm->dm.loopData, - loopidx.data(), - w2, - nullptr, - numVerts, - loopindex2); - loopindex2++; - - w2 = w + s * numVerts * g2_wid * g2_wid + ((y + 1) * g2_wid + (x + 1)) * numVerts; - CustomData_interp(&dm->loopData, - &ccgdm->dm.loopData, - loopidx.data(), - w2, - nullptr, - numVerts, - loopindex2); - loopindex2++; - - w2 = w + s * numVerts * g2_wid * g2_wid + ((y)*g2_wid + (x + 1)) * numVerts; - CustomData_interp(&dm->loopData, - &ccgdm->dm.loopData, - loopidx.data(), - w2, - nullptr, - numVerts, - loopindex2); - loopindex2++; - - CustomData_copy_data(&dm->polyData, &ccgdm->dm.polyData, origIndex, faceNum, 1); - - if (polyOrigIndex) { - *polyOrigIndex = base_polyOrigIndex ? base_polyOrigIndex[origIndex] : origIndex; - polyOrigIndex++; - } - - /* This is a simple one to one mapping, here... */ - if (polyidx) { - polyidx[faceNum] = faceNum; - } - - faceNum++; - } - } - } - - edgeNum += numFinalEdges; - } - - for (index = 0; index < totedge; index++) { - CCGEdge *e = ccgdm->edgeMap[index].edge; - int numFinalEdges = edgeSize - 1; - int mapIndex = ccgDM_getEdgeMapIndex(ss, e); - int x; - int vertIdx[2]; - int edgeIdx = POINTER_AS_INT(ccgSubSurf_getEdgeEdgeHandle(e)); - - CCGVert *v; - v = ccgSubSurf_getEdgeVert0(e); - vertIdx[0] = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(v)); - v = ccgSubSurf_getEdgeVert1(e); - vertIdx[1] = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(v)); - - ccgdm->edgeMap[index].startVert = vertNum; - ccgdm->edgeMap[index].startEdge = edgeNum; - - /* set the edge base vert */ - *((int *)ccgSubSurf_getEdgeUserData(ss, e)) = vertNum; - - for (x = 1; x < edgeSize - 1; x++) { - float w[2]; - w[1] = float(x) / (edgeSize - 1); - w[0] = 1 - w[1]; - DM_interp_vert_data(dm, &ccgdm->dm, vertIdx, w, 2, vertNum); - if (vertOrigIndex) { - *vertOrigIndex = ORIGINDEX_NONE; - vertOrigIndex++; - } - vertNum++; - } - - if (has_edge_cd) { - BLI_assert(edgeIdx >= 0 && edgeIdx < dm->getNumEdges(dm)); - for (i = 0; i < numFinalEdges; i++) { - CustomData_copy_data(&dm->edgeData, &ccgdm->dm.edgeData, edgeIdx, edgeNum + i, 1); - } - } - - if (edgeOrigIndex) { - for (i = 0; i < numFinalEdges; i++) { - edgeOrigIndex[edgeNum + i] = mapIndex; - } - } - - edgeNum += numFinalEdges; - } - - if (useSubsurfUv) { - CustomData *loop_data = &ccgdm->dm.loopData; - CustomData *dmldata = &dm->loopData; - int numlayer = CustomData_number_of_layers(loop_data, CD_PROP_FLOAT2); - int dmnumlayer = CustomData_number_of_layers(dmldata, CD_PROP_FLOAT2); - - for (i = 0; i < numlayer && i < dmnumlayer; i++) { - set_subsurf_uv(ss, dm, &ccgdm->dm, i); - } - } - - for (index = 0; index < totvert; index++) { - CCGVert *v = ccgdm->vertMap[index].vert; - int mapIndex = ccgDM_getVertMapIndex(ccgdm->ss, v); - int vertIdx; - - vertIdx = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(v)); - - ccgdm->vertMap[index].startVert = vertNum; - - /* set the vert base vert */ - *((int *)ccgSubSurf_getVertUserData(ss, v)) = vertNum; - - DM_copy_vert_data(dm, &ccgdm->dm, vertIdx, vertNum, 1); - - if (vertOrigIndex) { - *vertOrigIndex = mapIndex; - vertOrigIndex++; - } - vertNum++; - } - - free_ss_weights(&wtable); - - BLI_assert(vertNum == ccgSubSurf_getNumFinalVerts(ss)); - BLI_assert(edgeNum == ccgSubSurf_getNumFinalEdges(ss)); - BLI_assert(loopindex2 == ccgSubSurf_getNumFinalFaces(ss) * 4); - BLI_assert(faceNum == ccgSubSurf_getNumFinalFaces(ss)); -} - -static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, - int drawInteriorEdges, - int useSubsurfUv, - DerivedMesh *dm) -{ - CCGDerivedMesh *ccgdm = MEM_callocN(__func__); - DM_from_template(&ccgdm->dm, - dm, - DM_TYPE_CCGDM, - ccgSubSurf_getNumFinalVerts(ss), - ccgSubSurf_getNumFinalEdges(ss), - 0, - ccgSubSurf_getNumFinalFaces(ss) * 4, - ccgSubSurf_getNumFinalFaces(ss)); - CustomData_free_layer_named(&ccgdm->dm.vertData, "position"); - CustomData_free_layer_named(&ccgdm->dm.edgeData, ".edge_verts"); - CustomData_free_layer_named(&ccgdm->dm.loopData, ".corner_vert"); - CustomData_free_layer_named(&ccgdm->dm.loopData, ".corner_edge"); - MEM_SAFE_FREE(ccgdm->dm.face_offsets); - - create_ccgdm_maps(ccgdm, ss); - - set_default_ccgdm_callbacks(ccgdm); - - ccgdm->ss = ss; - ccgdm->drawInteriorEdges = drawInteriorEdges; - ccgdm->useSubsurfUv = useSubsurfUv; - - set_ccgdm_all_geometry(ccgdm, ss, dm, useSubsurfUv != 0); - - ccgdm->dm.numVertData = ccgSubSurf_getNumFinalVerts(ss); - ccgdm->dm.numEdgeData = ccgSubSurf_getNumFinalEdges(ss); - ccgdm->dm.numPolyData = ccgSubSurf_getNumFinalFaces(ss); - ccgdm->dm.numLoopData = ccgdm->dm.numPolyData * 4; - ccgdm->dm.numTessFaceData = 0; - - BLI_mutex_init(&ccgdm->loops_cache_lock); - BLI_rw_mutex_init(&ccgdm->origindex_cache_rwlock); - - return ccgdm; -} - -/***/ - -DerivedMesh *subsurf_make_derived_from_derived(DerivedMesh *dm, - SubsurfModifierData *smd, - const Scene *scene, - float (*vertCos)[3], - SubsurfFlags flags) -{ - const CCGFlags useSimple = (smd->subdivType == ME_SIMPLE_SUBSURF) ? CCG_SIMPLE_SUBDIV : - CCGFlags(0); - const CCGFlags useAging = (smd->flags & eSubsurfModifierFlag_DebugIncr) ? CCG_USE_AGING : - CCGFlags(0); - const int useSubsurfUv = (smd->uv_smooth != SUBSURF_UV_SMOOTH_NONE); - const int drawInteriorEdges = !(smd->flags & eSubsurfModifierFlag_ControlEdges); - const bool ignore_simplify = (flags & SUBSURF_IGNORE_SIMPLIFY); - CCGDerivedMesh *result; - - /* NOTE: editmode calculation can only run once per - * modifier stack evaluation (uses freed cache) #36299. */ - if (flags & SUBSURF_FOR_EDIT_MODE) { - int levels = (scene != nullptr && !ignore_simplify) ? - get_render_subsurf_level(&scene->r, smd->levels, false) : - smd->levels; - - /* TODO(sergey): Same as emCache below. */ - if ((flags & SUBSURF_IN_EDIT_MODE) && smd->mCache) { - ccgSubSurf_free(static_cast(smd->mCache)); - smd->mCache = nullptr; - } - - smd->emCache = _getSubSurf(static_cast(smd->emCache), - levels, - 3, - useSimple | useAging | CCG_CALC_NORMALS); - - ss_sync_from_derivedmesh( - static_cast(smd->emCache), dm, vertCos, useSimple, useSubsurfUv); - result = getCCGDerivedMesh( - static_cast(smd->emCache), drawInteriorEdges, useSubsurfUv, dm); - } - else if (flags & SUBSURF_USE_RENDER_PARAMS) { - /* Do not use cache in render mode. */ - CCGSubSurf *ss; - int levels = (scene != nullptr && !ignore_simplify) ? - get_render_subsurf_level(&scene->r, smd->renderLevels, true) : - smd->renderLevels; - - if (levels == 0) { - return dm; - } - - ss = _getSubSurf(nullptr, levels, 3, useSimple | CCG_USE_ARENA | CCG_CALC_NORMALS); - - ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple, useSubsurfUv); - - result = getCCGDerivedMesh(ss, drawInteriorEdges, useSubsurfUv, dm); - - result->freeSS = 1; - } - else { - int useIncremental = (smd->flags & eSubsurfModifierFlag_Incremental); - int levels = (scene != nullptr && !ignore_simplify) ? - get_render_subsurf_level(&scene->r, smd->levels, false) : - smd->levels; - CCGSubSurf *ss; - - /* NOTE(@zr): It is quite possible there is a much better place to do this. It - * depends a bit on how rigorously we expect this function to never - * be called in edit-mode. In semi-theory we could share a single - * cache, but the handles used inside and outside edit-mode are not - * the same so we would need some way of converting them. Its probably - * not worth the effort. But then why am I even writing this long - * comment that no one will read? Hmm. - * - * NOTE(@brecht): Addendum: we can't really ensure that this is never called in edit - * mode, so now we have a parameter to verify it. - */ - if (!(flags & SUBSURF_IN_EDIT_MODE) && smd->emCache) { - ccgSubSurf_free(static_cast(smd->emCache)); - smd->emCache = nullptr; - } - - if (useIncremental && (flags & SUBSURF_IS_FINAL_CALC)) { - smd->mCache = ss = _getSubSurf(static_cast(smd->mCache), - levels, - 3, - useSimple | useAging | CCG_CALC_NORMALS); - - ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple, useSubsurfUv); - - result = getCCGDerivedMesh( - static_cast(smd->mCache), drawInteriorEdges, useSubsurfUv, dm); - } - else { - CCGFlags ccg_flags = useSimple | CCG_USE_ARENA | CCG_CALC_NORMALS; - CCGSubSurf *prevSS = nullptr; - - if ((smd->mCache) && (flags & SUBSURF_IS_FINAL_CALC)) { - ccgSubSurf_free(static_cast(smd->mCache)); - smd->mCache = nullptr; - } - - if (flags & SUBSURF_ALLOC_PAINT_MASK) { - ccg_flags |= CCG_ALLOC_MASK; - } - - ss = _getSubSurf(prevSS, levels, 3, ccg_flags); - ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple, useSubsurfUv); - - result = getCCGDerivedMesh(ss, drawInteriorEdges, useSubsurfUv, dm); - - if (flags & SUBSURF_IS_FINAL_CALC) { - smd->mCache = ss; - } - else { - result->freeSS = 1; - } - - if (flags & SUBSURF_ALLOC_PAINT_MASK) { - ccgSubSurf_setNumLayers(ss, 4); - } - } - } - - return (DerivedMesh *)result; -} - -void subsurf_calculate_limit_positions(Mesh *mesh, float (*r_positions)[3]) -{ - /* Finds the subsurf limit positions for the verts in a mesh - * and puts them in an array of floats. Please note that the - * calculated vert positions is incorrect for the verts - * on the boundary of the mesh. - */ - CCGSubSurf *ss = _getSubSurf(nullptr, 1, 3, CCG_USE_ARENA); - float edge_sum[3], face_sum[3]; - CCGVertIterator vi; - DerivedMesh *dm = CDDM_from_mesh(mesh); - - ss_sync_from_derivedmesh(ss, dm, nullptr, 0, false); - - for (ccgSubSurf_initVertIterator(ss, &vi); !ccgVertIterator_isStopped(&vi); - ccgVertIterator_next(&vi)) - { - CCGVert *v = ccgVertIterator_getCurrent(&vi); - int idx = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(v)); - int N = ccgSubSurf_getVertNumEdges(v); - int numFaces = ccgSubSurf_getVertNumFaces(v); - int i; - - zero_v3(edge_sum); - zero_v3(face_sum); - - for (i = 0; i < N; i++) { - CCGEdge *e = ccgSubSurf_getVertEdge(v, i); - add_v3_v3v3( - edge_sum, edge_sum, static_cast(ccgSubSurf_getEdgeData(ss, e, 1))); - } - for (i = 0; i < numFaces; i++) { - CCGFace *f = ccgSubSurf_getVertFace(v, i); - add_v3_v3(face_sum, static_cast(ccgSubSurf_getFaceCenterData(f))); - } - - /* NOTE(@brecht): ad-hoc correction for boundary vertices, to at least avoid them - * moving completely out of place. */ - if (numFaces && numFaces != N) { - mul_v3_fl(face_sum, float(N) / float(numFaces)); - } - - const float *co = static_cast(ccgSubSurf_getVertData(ss, v)); - r_positions[idx][0] = (co[0] * N * N + edge_sum[0] * 4 + face_sum[0]) / (N * (N + 5)); - r_positions[idx][1] = (co[1] * N * N + edge_sum[1] * 4 + face_sum[1]) / (N * (N + 5)); - r_positions[idx][2] = (co[2] * N * N + edge_sum[2] * 4 + face_sum[2]) / (N * (N + 5)); - } - - ccgSubSurf_free(ss); - - dm->release(dm); -} diff --git a/source/blender/editors/armature/armature_skinning.cc b/source/blender/editors/armature/armature_skinning.cc index f8c757661ab..33e2e1b598c 100644 --- a/source/blender/editors/armature/armature_skinning.cc +++ b/source/blender/editors/armature/armature_skinning.cc @@ -28,7 +28,6 @@ #include "BKE_object_deform.h" #include "BKE_report.hh" #include "BKE_subdiv_mesh.hh" -#include "BKE_subsurf.hh" #include "DEG_depsgraph.hh" #include "DEG_depsgraph_query.hh" diff --git a/source/blender/editors/object/object_bake.cc b/source/blender/editors/object/object_bake.cc index 60b4f431393..c087f8d6025 100644 --- a/source/blender/editors/object/object_bake.cc +++ b/source/blender/editors/object/object_bake.cc @@ -25,11 +25,11 @@ #include "BKE_customdata.hh" #include "BKE_global.hh" #include "BKE_image.hh" -#include "BKE_mesh_legacy_derived_mesh.hh" #include "BKE_modifier.hh" #include "BKE_multires.hh" #include "BKE_report.hh" #include "BKE_scene.hh" +#include "BKE_subdiv.hh" #include "RE_multires_bake.h" #include "RE_pipeline.h" @@ -69,11 +69,17 @@ static Vector bake_object_image_get_array(Object &object) /* holder of per-object data needed for bake job * needed to make job totally thread-safe */ struct MultiresBakerJobData { - MultiresBakerJobData *next, *prev; - /* material aligned image array (for per-face bake image) */ + MultiresBakerJobData *next = nullptr, *prev = nullptr; + + /* Material aligned image array (for per-face bake image). */ Vector ob_image; - DerivedMesh *lores_dm, *hires_dm; - int lvl, tot_lvl; + + /* Base mesh at the input of the multiresolution modifier. */ + Mesh *base_mesh = nullptr; + + /* Multi-resolution modifier which is being baked. */ + MultiresModifierData *multires_modifier = nullptr; + Set images; }; @@ -90,11 +96,9 @@ struct MultiresBakeJob { /** mode of baking (displacement, normals, AO) */ short mode; /** Use low-resolution mesh when baking displacement maps */ - bool use_lores_mesh; + bool use_low_resolution_mesh; /** Bias between object and start ray point when doing AO baking */ float bias; - /** Number of threads to be used for baking */ - int threads; }; static bool multiresbake_check(bContext *C, wmOperator *op) @@ -205,60 +209,6 @@ static bool multiresbake_check(bContext *C, wmOperator *op) return ok; } -static DerivedMesh *multiresbake_create_loresdm(Scene *scene, Object *ob, int *lvl) -{ - DerivedMesh *dm; - MultiresModifierData *mmd = get_multires_modifier(scene, ob, false); - Mesh *mesh = (Mesh *)ob->data; - MultiresModifierData tmp_mmd = dna::shallow_copy(*mmd); - - *lvl = mmd->lvl; - - if (mmd->lvl == 0) { - DerivedMesh *cddm = CDDM_from_mesh(mesh); - DM_set_only_copy(cddm, &CD_MASK_BAREMESH); - return cddm; - } - - DerivedMesh *cddm = CDDM_from_mesh(mesh); - DM_set_only_copy(cddm, &CD_MASK_BAREMESH); - tmp_mmd.lvl = mmd->lvl; - tmp_mmd.sculptlvl = mmd->lvl; - dm = multires_make_derived_from_derived( - cddm, &tmp_mmd, scene, ob, MultiresFlags::IgnoreSimplify); - - cddm->release(cddm); - - return dm; -} - -static DerivedMesh *multiresbake_create_hiresdm(Scene *scene, Object *ob, int *lvl) -{ - Mesh *mesh = (Mesh *)ob->data; - MultiresModifierData *mmd = get_multires_modifier(scene, ob, false); - MultiresModifierData tmp_mmd = dna::shallow_copy(*mmd); - DerivedMesh *cddm = CDDM_from_mesh(mesh); - DerivedMesh *dm; - - DM_set_only_copy(cddm, &CD_MASK_BAREMESH); - - /* TODO: DM_set_only_copy wouldn't set mask for loop and poly data, - * but we really need BAREMESH only to save lots of memory - */ - CustomData_set_only_copy(&cddm->loopData, CD_MASK_BAREMESH.lmask); - CustomData_set_only_copy(&cddm->polyData, CD_MASK_BAREMESH.pmask); - - *lvl = mmd->totlvl; - - tmp_mmd.lvl = mmd->totlvl; - tmp_mmd.sculptlvl = mmd->totlvl; - dm = multires_make_derived_from_derived( - cddm, &tmp_mmd, scene, ob, MultiresFlags::IgnoreSimplify); - cddm->release(cddm); - - return dm; -} - enum ClearFlag { CLEAR_TANGENT_NORMAL = 1, CLEAR_DISPLACEMENT = 2, @@ -321,7 +271,6 @@ static void clear_images_poly(const Span ob_image_array, const ClearFla static wmOperatorStatus multiresbake_image_exec_locked(bContext *C, wmOperator *op) { - Object *ob; Scene *scene = CTX_data_scene(C); int objects_baked = 0; @@ -331,10 +280,10 @@ static wmOperatorStatus multiresbake_image_exec_locked(bContext *C, wmOperator * if (scene->r.bake_flag & R_BAKE_CLEAR) { /* clear images */ CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) { - ClearFlag clear_flag = ClearFlag(0); + Object &object = *base->object; + BLI_assert(object.type == OB_MESH); - ob = base->object; - // mesh = (Mesh *)ob->data; + ClearFlag clear_flag = ClearFlag(0); if (scene->r.bake_mode == RE_BAKE_NORMALS) { clear_flag = CLEAR_TANGENT_NORMAL; @@ -344,7 +293,7 @@ static wmOperatorStatus multiresbake_image_exec_locked(bContext *C, wmOperator * } { - const Vector ob_image_array = bake_object_image_get_array(*ob); + const Vector ob_image_array = bake_object_image_get_array(object); clear_images_poly(ob_image_array, clear_flag); } } @@ -352,37 +301,31 @@ static wmOperatorStatus multiresbake_image_exec_locked(bContext *C, wmOperator * } CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) { - MultiresBakeRender bkr = {nullptr}; + Object &object = *base->object; + BLI_assert(object.type == OB_MESH); - ob = base->object; + MultiresBakeRender bake; - multires_flush_sculpt_updates(ob); + multires_flush_sculpt_updates(&object); - /* copy data stored in job descriptor */ - bkr.scene = scene; - bkr.bake_margin = scene->r.bake_margin; + /* Copy data stored in job descriptor. */ + bake.bake_margin = scene->r.bake_margin; if (scene->r.bake_mode == RE_BAKE_NORMALS) { - bkr.bake_margin_type = R_BAKE_EXTEND; + bake.bake_margin_type = R_BAKE_EXTEND; } else { - bkr.bake_margin_type = scene->r.bake_margin_type; + bake.bake_margin_type = eBakeMarginType(scene->r.bake_margin_type); } - bkr.mode = scene->r.bake_mode; - bkr.use_lores_mesh = scene->r.bake_flag & R_BAKE_LORES_MESH; - bkr.bias = scene->r.bake_biasdist; - bkr.threads = BKE_scene_num_threads(scene); - // bkr.reports= op->reports; + bake.mode = scene->r.bake_mode; + bake.use_low_resolution_mesh = scene->r.bake_flag & R_BAKE_LORES_MESH; + bake.bias = scene->r.bake_biasdist; - /* create low-resolution DM (to bake to) and hi-resolution DM (to bake from) */ - bkr.ob_image = bake_object_image_get_array(*ob); + bake.ob_image = bake_object_image_get_array(object); - bkr.hires_dm = multiresbake_create_hiresdm(scene, ob, &bkr.tot_lvl); - bkr.lores_dm = multiresbake_create_loresdm(scene, ob, &bkr.lvl); + bake.base_mesh = static_cast(object.data); + bake.multires_modifier = get_multires_modifier(scene, &object, false); - RE_multires_bake_images(&bkr); - - bkr.lores_dm->release(bkr.lores_dm); - bkr.hires_dm->release(bkr.hires_dm); + RE_multires_bake_images(bake); objects_baked++; } @@ -401,7 +344,6 @@ static wmOperatorStatus multiresbake_image_exec_locked(bContext *C, wmOperator * static void init_multiresbake_job(bContext *C, MultiresBakeJob *bkj) { Scene *scene = CTX_data_scene(C); - Object *ob; /* backup scene settings, so their changing in UI would take no effect on baker */ bkj->scene = scene; @@ -413,27 +355,22 @@ static void init_multiresbake_job(bContext *C, MultiresBakeJob *bkj) bkj->bake_margin_type = scene->r.bake_margin_type; } bkj->mode = scene->r.bake_mode; - bkj->use_lores_mesh = scene->r.bake_flag & R_BAKE_LORES_MESH; + bkj->use_low_resolution_mesh = scene->r.bake_flag & R_BAKE_LORES_MESH; bkj->bake_clear = scene->r.bake_flag & R_BAKE_CLEAR; bkj->bias = scene->r.bake_biasdist; - bkj->threads = BKE_scene_num_threads(scene); - // bkj->reports = op->reports; CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) { - int lvl; + Object &object = *base->object; + BLI_assert(object.type == OB_MESH); - ob = base->object; - - multires_flush_sculpt_updates(ob); + multires_flush_sculpt_updates(&object); MultiresBakerJobData *data = MEM_new(__func__); - data->ob_image = bake_object_image_get_array(*ob); + data->ob_image = bake_object_image_get_array(object); - /* create low-resolution DM (to bake to) and hi-resolution DM (to bake from) */ - data->hires_dm = multiresbake_create_hiresdm(scene, ob, &data->tot_lvl); - data->lores_dm = multiresbake_create_loresdm(scene, ob, &lvl); - data->lvl = lvl; + data->base_mesh = static_cast(object.data); + data->multires_modifier = get_multires_modifier(scene, &object, false); BLI_addtail(&bkj->data, data); } @@ -463,37 +400,31 @@ static void multiresbake_startjob(void *bkv, wmJobWorkerStatus *worker_status) } LISTBASE_FOREACH (MultiresBakerJobData *, data, &bkj->data) { - MultiresBakeRender bkr = {nullptr}; + MultiresBakeRender bake; /* copy data stored in job descriptor */ - bkr.scene = bkj->scene; - bkr.bake_margin = bkj->bake_margin; - bkr.bake_margin_type = bkj->bake_margin_type; - bkr.mode = bkj->mode; - bkr.use_lores_mesh = bkj->use_lores_mesh; - // bkr.reports = bkj->reports; - bkr.ob_image = data->ob_image; + bake.bake_margin = bkj->bake_margin; + bake.bake_margin_type = eBakeMarginType(bkj->bake_margin_type); + bake.mode = bkj->mode; + bake.use_low_resolution_mesh = bkj->use_low_resolution_mesh; + bake.ob_image = data->ob_image; - /* create low-resolution DM (to bake to) and hi-resolution DM (to bake from) */ - bkr.lores_dm = data->lores_dm; - bkr.hires_dm = data->hires_dm; - bkr.tot_lvl = data->tot_lvl; - bkr.lvl = data->lvl; + bake.base_mesh = data->base_mesh; + bake.multires_modifier = data->multires_modifier; /* needed for proper progress bar */ - bkr.tot_obj = tot_obj; - bkr.baked_objects = baked_objects; + bake.num_total_objects = tot_obj; + bake.num_baked_objects = baked_objects; - bkr.stop = &worker_status->stop; - bkr.do_update = &worker_status->do_update; - bkr.progress = &worker_status->progress; + bake.stop = &worker_status->stop; + bake.do_update = &worker_status->do_update; + bake.progress = &worker_status->progress; - bkr.bias = bkj->bias; - bkr.threads = bkj->threads; + bake.bias = bkj->bias; - RE_multires_bake_images(&bkr); + RE_multires_bake_images(bake); - data->images = bkr.images; + data->images = bake.images; baked_objects++; } @@ -507,8 +438,6 @@ static void multiresbake_freejob(void *bkv) data = static_cast(bkj->data.first); while (data) { next = data->next; - data->lores_dm->release(data->lores_dm); - data->hires_dm->release(data->hires_dm); /* delete here, since this delete will be called from main thread */ for (Image *image : data->images) { @@ -586,7 +515,12 @@ static wmOperatorStatus objects_bake_render_modal(bContext *C, static bool is_multires_bake(Scene *scene) { - if (ELEM(scene->r.bake_mode, RE_BAKE_NORMALS, RE_BAKE_DISPLACEMENT, RE_BAKE_AO)) { + if (ELEM(scene->r.bake_mode, + RE_BAKE_NORMALS, + RE_BAKE_DISPLACEMENT, + RE_BAKE_VECTOR_DISPLACEMENT, + RE_BAKE_AO)) + { return scene->r.bake_flag & R_BAKE_MULTIRES; } diff --git a/source/blender/editors/sculpt_paint/paint_hide.cc b/source/blender/editors/sculpt_paint/paint_hide.cc index bbf33db3fb8..dd21b64c3cf 100644 --- a/source/blender/editors/sculpt_paint/paint_hide.cc +++ b/source/blender/editors/sculpt_paint/paint_hide.cc @@ -26,7 +26,6 @@ #include "BKE_paint.hh" #include "BKE_paint_bvh.hh" #include "BKE_subdiv_ccg.hh" -#include "BKE_subsurf.hh" #include "DEG_depsgraph.hh" diff --git a/source/blender/editors/sculpt_paint/paint_mask.cc b/source/blender/editors/sculpt_paint/paint_mask.cc index c52ba2b44d5..d8fba368917 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.cc +++ b/source/blender/editors/sculpt_paint/paint_mask.cc @@ -28,7 +28,6 @@ #include "BKE_paint.hh" #include "BKE_paint_bvh.hh" #include "BKE_subdiv_ccg.hh" -#include "BKE_subsurf.hh" #include "RNA_access.hh" #include "RNA_define.hh" diff --git a/source/blender/editors/sculpt_paint/sculpt.cc b/source/blender/editors/sculpt_paint/sculpt.cc index 2e9ac472983..c08619e65a8 100644 --- a/source/blender/editors/sculpt_paint/sculpt.cc +++ b/source/blender/editors/sculpt_paint/sculpt.cc @@ -62,7 +62,6 @@ #include "BKE_paint_types.hh" #include "BKE_report.hh" #include "BKE_subdiv_ccg.hh" -#include "BKE_subsurf.hh" #include "BLI_math_rotation_legacy.hh" #include "BLI_math_vector.hh" diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.cc b/source/blender/editors/sculpt_paint/sculpt_undo.cc index 281ffe2feed..20116933a31 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.cc +++ b/source/blender/editors/sculpt_paint/sculpt_undo.cc @@ -58,7 +58,6 @@ #include "BKE_paint_types.hh" #include "BKE_scene.hh" #include "BKE_subdiv_ccg.hh" -#include "BKE_subsurf.hh" #include "BKE_undo_system.hh" /* TODO(sergey): Ideally should be no direct call to such low level things. */ diff --git a/source/blender/makesdna/DNA_modifier_defaults.h b/source/blender/makesdna/DNA_modifier_defaults.h index 5b95c6c4a4f..c30dfcc865d 100644 --- a/source/blender/makesdna/DNA_modifier_defaults.h +++ b/source/blender/makesdna/DNA_modifier_defaults.h @@ -615,8 +615,6 @@ .uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES, \ .quality = 3, \ .boundary_smooth = SUBSURF_BOUNDARY_SMOOTH_ALL, \ - .emCache = NULL, \ - .mCache = NULL, \ } #define _DNA_DEFAULT_SurfaceModifierData \ diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 37ffa394461..23907cb6481 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -268,9 +268,6 @@ typedef struct SubsurfModifierData { /** #eSubsurfBoundarySmooth. */ short boundary_smooth; char _pad[2]; - - /* TODO(sergey): Get rid of those with the old CCG subdivision code. */ - void *emCache, *mCache; } SubsurfModifierData; typedef struct LatticeModifierData { diff --git a/source/blender/makesrna/intern/rna_scene.cc b/source/blender/makesrna/intern/rna_scene.cc index 31964f48b4b..9943fbf01ca 100644 --- a/source/blender/makesrna/intern/rna_scene.cc +++ b/source/blender/makesrna/intern/rna_scene.cc @@ -6753,6 +6753,15 @@ static void rna_def_scene_render_data(BlenderRNA *brna) //{RE_BAKE_AO, "AO", 0, "Ambient Occlusion", "Bake ambient occlusion"}, {RE_BAKE_NORMALS, "NORMALS", 0, "Normals", "Bake normals"}, {RE_BAKE_DISPLACEMENT, "DISPLACEMENT", 0, "Displacement", "Bake displacement"}, + + /* TODO(sergey): Uncomment once tangent space displacement is supported. */ + /* Use C++ style comment because #if 0 breaks indentation. */ + // {RE_BAKE_VECTOR_DISPLACEMENT, + // "VECTOR_DISPLACEMENT", + // 0, + // "Vector Displacement", + // "Bake vector displacement"}, + {0, nullptr, 0, nullptr, nullptr}, }; diff --git a/source/blender/modifiers/intern/MOD_multires.cc b/source/blender/modifiers/intern/MOD_multires.cc index 60c1c770c1c..a5a2d21570c 100644 --- a/source/blender/modifiers/intern/MOD_multires.cc +++ b/source/blender/modifiers/intern/MOD_multires.cc @@ -29,7 +29,6 @@ #include "BKE_subdiv_ccg.hh" #include "BKE_subdiv_deform.hh" #include "BKE_subdiv_mesh.hh" -#include "BKE_subsurf.hh" #include "UI_interface.hh" #include "UI_interface_layout.hh" diff --git a/source/blender/modifiers/intern/MOD_subsurf.cc b/source/blender/modifiers/intern/MOD_subsurf.cc index 37fc0c4fa18..b4f63e6f4c1 100644 --- a/source/blender/modifiers/intern/MOD_subsurf.cc +++ b/source/blender/modifiers/intern/MOD_subsurf.cc @@ -50,8 +50,6 @@ #include "MOD_modifiertypes.hh" #include "MOD_ui_common.hh" -#include "intern/CCGSubSurf.h" - static void init_data(ModifierData *md) { SubsurfModifierData *smd = (SubsurfModifierData *)md; @@ -61,18 +59,6 @@ static void init_data(ModifierData *md) MEMCPY_STRUCT_AFTER(smd, DNA_struct_default_get(SubsurfModifierData), modifier); } -static void copy_data(const ModifierData *md, ModifierData *target, const int flag) -{ -#if 0 - const SubsurfModifierData *smd = (const SubsurfModifierData *)md; -#endif - SubsurfModifierData *tsmd = (SubsurfModifierData *)target; - - BKE_modifier_copydata_generic(md, target, flag); - - tsmd->emCache = tsmd->mCache = nullptr; -} - static void free_runtime_data(void *runtime_data_v) { if (runtime_data_v == nullptr) { @@ -92,14 +78,6 @@ static void free_data(ModifierData *md) { SubsurfModifierData *smd = (SubsurfModifierData *)md; - if (smd->mCache) { - ccgSubSurf_free(static_cast(smd->mCache)); - smd->mCache = nullptr; - } - if (smd->emCache) { - ccgSubSurf_free(static_cast(smd->emCache)); - smd->emCache = nullptr; - } free_runtime_data(smd->modifier.runtime); } @@ -477,13 +455,6 @@ static void panel_register(ARegionType *region_type) modifier_panel_register(region_type, eModifierType_Subsurf, panel_draw); } -static void blend_read(BlendDataReader * /*reader*/, ModifierData *md) -{ - SubsurfModifierData *smd = (SubsurfModifierData *)md; - - smd->emCache = smd->mCache = nullptr; -} - ModifierTypeInfo modifierType_Subsurf = { /*idname*/ "Subdivision", /*name*/ N_("Subdivision"), @@ -496,7 +467,7 @@ ModifierTypeInfo modifierType_Subsurf = { eModifierTypeFlag_AcceptsCVs, /*icon*/ ICON_MOD_SUBSURF, - /*copy_data*/ copy_data, + /*copy_data*/ BKE_modifier_copydata_generic, /*deform_verts*/ nullptr, /*deform_matrices*/ deform_matrices, @@ -517,6 +488,6 @@ ModifierTypeInfo modifierType_Subsurf = { /*free_runtime_data*/ free_runtime_data, /*panel_register*/ panel_register, /*blend_write*/ nullptr, - /*blend_read*/ blend_read, + /*blend_read*/ nullptr, /*foreach_cache*/ nullptr, }; diff --git a/source/blender/render/RE_multires_bake.h b/source/blender/render/RE_multires_bake.h index 815d40c0c82..271a11aa646 100644 --- a/source/blender/render/RE_multires_bake.h +++ b/source/blender/render/RE_multires_bake.h @@ -8,38 +8,50 @@ #pragma once +#include "DNA_scene_types.h" + #include "BLI_set.hh" #include "BLI_vector.hh" +#include "RE_pipeline.h" + struct Image; -struct DerivedMesh; +struct Mesh; struct MultiresBakeRender; -struct Scene; +struct MultiresModifierData; struct MultiresBakeRender { - Scene *scene; - DerivedMesh *lores_dm, *hires_dm; - int bake_margin; - char bake_margin_type; - int lvl, tot_lvl; - short mode; - bool use_lores_mesh; /* Use low-resolution mesh when baking displacement maps */ + /* Base mesh at the input of the multiresolution modifier and data of the modifier which is being + * baked. */ + Mesh *base_mesh = nullptr; + MultiresModifierData *multires_modifier = nullptr; - /* material aligned image array (for per-face bake image) */ + int bake_margin = 0; + eBakeMarginType bake_margin_type = R_BAKE_ADJACENT_FACES; + short mode = RE_BAKE_NORMALS; + + /* Use low-resolution mesh when baking displacement maps. + * When true displacement is calculated between the final position in the SubdivCCG and the + * corresponding location on the base mesh. + * When false displacement is calculated between the final position in the SubdivCCG and the + * multiresolution modifier calculated at the bake level, further subdivided (without adding + * displacement) to the final multi-resolution level. */ + bool use_low_resolution_mesh = false; + + /* Material aligned image array (for per-face bake image), */ blender::Vector ob_image; - float bias; /* Bias between object and start ray point when doing AO baking */ + /* Bias between object and start ray point when doing AO baking. */ + float bias = 0; - int tot_obj; blender::Set images; - int baked_objects, baked_faces; + int num_total_objects = 0; + int num_baked_objects = 0; - int threads; /* Number of threads to be used for baking */ - - bool *stop; - bool *do_update; - float *progress; + bool *stop = nullptr; + bool *do_update = nullptr; + float *progress = nullptr; }; -void RE_multires_bake_images(struct MultiresBakeRender *bkr); +void RE_multires_bake_images(MultiresBakeRender &bake); diff --git a/source/blender/render/RE_pipeline.h b/source/blender/render/RE_pipeline.h index 9e0af63eb63..cc1100f58a1 100644 --- a/source/blender/render/RE_pipeline.h +++ b/source/blender/render/RE_pipeline.h @@ -492,6 +492,7 @@ blender::gpu::Texture *RE_pass_ensure_gpu_texture_cache(struct Render *re, #define RE_BAKE_NORMALS 0 #define RE_BAKE_DISPLACEMENT 1 #define RE_BAKE_AO 2 +#define RE_BAKE_VECTOR_DISPLACEMENT 3 void RE_GetCameraWindow(struct Render *re, const struct Object *camera, float r_winmat[4][4]); /** diff --git a/source/blender/render/RE_texture_margin.h b/source/blender/render/RE_texture_margin.h index 7155605c622..baa4dd117c7 100644 --- a/source/blender/render/RE_texture_margin.h +++ b/source/blender/render/RE_texture_margin.h @@ -7,7 +7,6 @@ * \ingroup bke */ -struct DerivedMesh; struct ImBuf; struct Mesh; @@ -26,6 +25,3 @@ void RE_generate_texturemargin_adjacentfaces(struct ImBuf *ibuf, struct Mesh const *me, char const *uv_layer, const float uv_offset[2]); - -void RE_generate_texturemargin_adjacentfaces_dm( - struct ImBuf *ibuf, char *mask, int margin, struct DerivedMesh *dm, const float uv_offset[2]); diff --git a/source/blender/render/intern/multires_bake.cc b/source/blender/render/intern/multires_bake.cc index 08ddc4a0f94..3b56bf4d933 100644 --- a/source/blender/render/intern/multires_bake.cc +++ b/source/blender/render/intern/multires_bake.cc @@ -1,262 +1,556 @@ -/* SPDX-FileCopyrightText: 2012 Blender Authors +/* SPDX-FileCopyrightText: 2012-2025 Blender Authors * * SPDX-License-Identifier: GPL-2.0-or-later */ /** \file * \ingroup render + * + * Baker from the Multires + * ======================= + * + * This file is an implementation of a special baking mode which bakes data (normals, displacement) + * from the highest multi-resolution level to the current viewport subdivision level. + * + * The initial historical reasoning for having such baker was: + * - Lower memory footprint than the regular baker. + * - Performance (due to lower overhead compared to the regular baker at that time). + * - Ease of use: no need to have explicit object to define cage. + * Over the time some of these points became less relevant, but the ease of use is still there. + * + * The general idea of the algorithm is pretty simple: + * - Rasterize UV of the mesh at the bake level. + * - For every UV pixel that is rasterized, figure out attributes on the bake level mesh and the + * highest subdivision multi-resolution level (such as normal, position). + * - Do the math (like convert normal to the tangent space), + * - Write pixel to the image. + * + * SubdivCCG is used to access attributes at the highest multi-resolution subdivision level. + * + * The core rasterization logic works on triangles and those triangles are fed to the rasterizer in + * a way that makes it easy to sample attributes in the SubdivCCG: + * - Triangle knows which CCG index it corresponds to (triangle never covers multiple grids). + * - It also knows UV coordinates of its vertices within that grid. + * + * The way triangles are calculated when baking to the base level is pretty straightforward: + * - Triangles are actually calculated from a quad. + * - Quad vertices align with the grid vertices. + * This means that the top level loop iterates over face corners, calculates quad for the grids, + * and passes it to the triangle rasterization. + * + * When baking to a non-0 subdivision level a special trick is used to know grid index and its UV + * coordinates in the base mesh: for every loop in the bake-level mesh the algorithm calculates + * this information using subdiv's foreach logic. This assumes that the bake level mesh is + * calculated using the same foreach logic. + * + * Use low resolution mesh + * ----------------------- + * + * This is a special option for the displacement baker. + * + * When it is ON: displacement is calculated between the multi-resolution at the highest + * subdivision level and the bake-level mesh. + * + * When it is OFF: displacement is calculated between the multi-resolution at the highest + * subdivision level and a mesh which is created from the bake level mesh by subdividing it further + * to the subdivision level of the highest multi-resolution level. + * + * Possible optimizations + * ---------------------- + * + * - Reuse mesh from the viewport as bake-level mesh. + * + * It could be a bit challenging since mesh could be in sculpt mode, where it has own SubdivCCG + * and does not have UV map on the subdivided state. Additionally, it will make it harder to + * calculate tangent space as well. */ -#include +#include "RE_multires_bake.h" -#include "MEM_guardedalloc.h" +#include +#include "DNA_mesh_types.h" #include "DNA_modifier_types.h" -#include "DNA_scene_types.h" +#include "BLI_array.hh" #include "BLI_listbase.h" -#include "BLI_math_color.h" +#include "BLI_math_base.hh" #include "BLI_math_geom.h" -#include "BLI_math_matrix.h" +#include "BLI_math_matrix.hh" #include "BLI_math_vector.hh" +#include "BLI_span.hh" +#include "BLI_task.hh" #include "BLI_threads.h" #include "BKE_attribute.hh" -#include "BKE_ccg.hh" #include "BKE_customdata.hh" #include "BKE_global.hh" #include "BKE_image.hh" #include "BKE_lib_id.hh" #include "BKE_mesh.hh" -#include "BKE_mesh_legacy_derived_mesh.hh" #include "BKE_mesh_tangent.hh" #include "BKE_multires.hh" -#include "BKE_subsurf.hh" - -#include "DEG_depsgraph.hh" - -#include "RE_multires_bake.h" -#include "RE_pipeline.h" -#include "RE_texture_margin.h" +#include "BKE_subdiv.hh" +#include "BKE_subdiv_ccg.hh" +#include "BKE_subdiv_eval.hh" +#include "BKE_subdiv_foreach.hh" +#include "BKE_subdiv_mesh.hh" #include "IMB_imbuf.hh" #include "IMB_imbuf_types.hh" +#include "DEG_depsgraph.hh" + +#include "RE_texture_margin.h" + namespace blender::render { namespace { -using MPassKnownData = void (*)(Span vert_positions, - Span vert_normals, - OffsetIndices faces, - Span corner_verts, - Span corner_tris, - Span tri_faces, - Span uv_map, - DerivedMesh *hires_dm, - void *thread_data, - void *bake_data, - ImBuf *ibuf, - int face_index, - int lvl, - const float st[2], - float tangmat[3][3], - int x, - int y); +namespace subdiv = bke::subdiv; -using MInitBakeData = void *(*)(MultiresBakeRender &bake, ImBuf *ibuf); -using MFreeBakeData = void (*)(void *bake_data); +/* -------------------------------------------------------------------- */ +/** \name Math utilities that should actually be in the BLI + * The only reason they are here is that there is currently no great place to put them to. + * \{ */ -struct MultiresBakeResult { - float height_min, height_max; +template T interp_barycentric_triangle(const T data[3], const float2 &uv) +{ + return data[0] * uv.x + data[1] * uv.y + data[2] * (1.0f - uv.x - uv.y); +} + +template +T interp_bilinear_quad( + const float u, const float v, const T &p0, const T &p1, const T &p2, const T &p3) +{ + const float w0 = (1 - u) * (1 - v); + const float w1 = u * (1 - v); + const float w2 = u * v; + const float w3 = (1 - u) * v; + + return p0 * w0 + p1 * w1 + p2 * w2 + p3 * w3; +} + +float2 resolve_tri_uv(const float2 &st, const float2 &st0, const float2 &st1, const float2 &st2) +{ + float2 uv; + resolve_tri_uv_v2(uv, st, st0, st1, st2); + return uv; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Implementation of data accessor from the subdiv + * \{ */ + +template class Grid { + Span data_; + int side_size_; + + T get_element(const int x, const int y) const + { + const int64_t index = int64_t(y) * side_size_ + x; + return data_[index]; + } + + public: + Grid(const Span data, const int side_size) : data_(data), side_size_(side_size) + { + BLI_assert(data.size() == side_size_ * side_size_); + } + + T sample(const float2 uv) const + { + const float2 xy = uv * (side_size_ - 1); + + const int x0 = int(xy.x); + const int x1 = x0 >= (side_size_ - 1) ? (side_size_ - 1) : (x0 + 1); + + const int y0 = int(xy.y); + const int y1 = y0 >= (side_size_ - 1) ? (side_size_ - 1) : (y0 + 1); + + const float u = xy.x - x0; + const float v = xy.y - y0; + + return interp_bilinear_quad( + u, v, get_element(x0, y0), get_element(x1, y0), get_element(x1, y1), get_element(x0, y1)); + } }; -struct MResolvePixelData { - /* Data from low-resolution mesh. */ +template +Grid get_subdiv_ccg_grid(const SubdivCCG &subdiv_ccg, const int grid_index, const Span data) +{ + const int64_t offset = int64_t(grid_index) * subdiv_ccg.grid_area; + return Grid(Span(data.data() + offset, subdiv_ccg.grid_area), subdiv_ccg.grid_size); +} + +float3 sample_position_on_subdiv_ccg(const SubdivCCG &subdiv_ccg, + const int grid_index, + const float2 grid_uv) +{ + const Grid grid = get_subdiv_ccg_grid( + subdiv_ccg, grid_index, subdiv_ccg.positions.as_span()); + return grid.sample(grid_uv); +} + +float3 sample_normal_on_subdiv_ccg(const SubdivCCG &subdiv_ccg, + const int grid_index, + const float2 grid_uv) +{ + /* TODO(sergey): Support flat normals. + * It seems that the baker always used smooth interpolation for CCG. */ + const Grid grid = get_subdiv_ccg_grid( + subdiv_ccg, grid_index, subdiv_ccg.normals.as_span()); + return grid.sample(grid_uv); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Storage of mesh arrays, for quicker access without any lookup + * \{ */ + +struct MeshArrays { Span vert_positions; - OffsetIndices faces; + Span vert_normals; + Span corner_verts; Span corner_tris; + Span corner_normals; + Span tri_faces; - Span vert_normals; + + OffsetIndices faces; Span face_normals; + VArraySpan sharp_faces; - Span uv_map; + VArraySpan uv_map; - /* May be null. */ - const int *material_indices; - const bool *sharp_faces; + VArraySpan material_indices; - float uv_offset[2]; - Span pvtangent; - int w, h; - int tri_index; + MeshArrays() = default; - DerivedMesh *hires_dm; + explicit MeshArrays(const Mesh &mesh) + { + bke::AttributeAccessor attributes = mesh.attributes(); - int lvl; - void *thread_data; - void *bake_data; + const StringRef active_uv_map = CustomData_get_active_layer_name(&mesh.corner_data, + CD_PROP_FLOAT2); + vert_positions = mesh.vert_positions(); + vert_normals = mesh.vert_normals(); + + corner_verts = mesh.corner_verts(); + corner_tris = mesh.corner_tris(); + corner_normals = mesh.corner_normals(); + + tri_faces = mesh.corner_tri_faces(); + + faces = mesh.faces(); + face_normals = mesh.face_normals(); + sharp_faces = *attributes.lookup_or_default("sharp_face", bke::AttrDomain::Face, false); + + uv_map = *attributes.lookup(active_uv_map, bke::AttrDomain::Corner); + + material_indices = *attributes.lookup_or_default( + "material_index", bke::AttrDomain::Face, 0); + } +}; + +/* Calculate UV map coordinates at the center of the face (grid coordinates (0, 0)). */ +static float2 face_center_tex_uv_calc(const MeshArrays &mesh_arrays, const int face_index) +{ + const IndexRange &face = mesh_arrays.faces[face_index]; + float2 tex_uv_acc(0.0f, 0.0f); + for (const int corner : face) { + tex_uv_acc += mesh_arrays.uv_map[corner]; + } + return tex_uv_acc / face.size(); +} + +/* Calculate smooth normal coordinates at the center of the face (grid coordinates (0, 0)). + * NOTE: The returned value is not normalized to allow linear interpolation with other grid + * elements. */ +static float3 face_center_smooth_normal_calc(const MeshArrays &mesh_arrays, const int face_index) +{ + const IndexRange &face = mesh_arrays.faces[face_index]; + float3 normal_acc(0.0f, 0.0f, 0.0f); + for (const int corner : face) { + normal_acc += mesh_arrays.vert_normals[mesh_arrays.corner_verts[corner]]; + } + /* NOTE: No normalization here: do it after interpolation at the baking point. + * + * This preserves linearity of operation. If normalization is done here interpolation will go + * wrong. */ + return normal_acc / face.size(); +} + +/* Calculate tangent space for the given mesh state. */ +Array calc_uv_tangents(const MeshArrays &mesh_arrays) +{ + Array> tangent_data = bke::mesh::calc_uv_tangents(mesh_arrays.vert_positions, + mesh_arrays.faces, + mesh_arrays.corner_verts, + mesh_arrays.corner_tris, + mesh_arrays.tri_faces, + mesh_arrays.sharp_faces, + mesh_arrays.vert_normals, + mesh_arrays.face_normals, + mesh_arrays.corner_normals, + {mesh_arrays.uv_map}); + + return tangent_data[0]; +} + +/* Calculate tangent space at the center of the face (grid coordinates (0, 0)). */ +static float4 face_center_uv_tangent_calc(const MeshArrays &mesh_arrays, + const Span uv_tangents, + const int face_index) +{ + const IndexRange &face = mesh_arrays.faces[face_index]; + float4 tex_uv_acc(0.0f, 0.0f, 0.0f, 0.0f); + for (const int corner : face) { + tex_uv_acc += uv_tangents[corner]; + } + return tex_uv_acc / face.size(); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Common data types and utilities + * \{ */ + +struct ExtraBuffers { + Array displacement_buffer; + Array mask_buffer; +}; + +struct RasterizeTile { + ImBuf *ibuf = nullptr; /* Image buffer of the tile. */ + ExtraBuffers *extra_buffers = nullptr; + float2 uv_offset; /* UV coordinate of the tile origin. */ +}; + +struct RasterizeTriangle { + /* UV coordinates with the CCG. All vertices belong to the same grid. */ + int grid_index; + float2 grid_uvs[3]; + + /* UV texture coordinates of the triangle vertices within the tile. */ + float2 tex_uvs[3]; + + /* Positions and normals of the vertices, at the bake level. */ + float3 positions[3]; + float3 normals[3]; + + /* Triangle is shaded flat: it has the same normal at every point of its surface. + * Face normal is stored in all elements of the normals array. */ + bool is_flat; + + /* Optional tangents. + * The uv_tangents might be uninitialized if has_uv_tangents=false. */ + bool has_uv_tangents; + float4 uv_tangents[3]; + + /* Corresponds to the same fields in the #RasterizeQuad. + * Refer to its documentation for more details. */ + int bake_level_quad_index; + float2 bake_level_quad_uvs[3]; + + float3 get_position(const float2 &uv) const + { + return interp_barycentric_triangle(positions, uv); + } + + float3 get_normal(const float2 &uv) const + { + if (is_flat) { + return normals[0]; + } + return math::normalize(interp_barycentric_triangle(normals, uv)); + } + + float2 get_bake_level_quad_uv(const float2 &uv) const + { + return interp_barycentric_triangle(bake_level_quad_uvs, uv); + } +}; + +struct RasterizeQuad { + /* UV coordinates with the CCG. All vertices belong to the same grid. */ + int grid_index; + float2 grid_uvs[4]; + + /* UV texture coordinates of the triangle vertices within the tile. */ + float2 tex_uvs[4]; + + /* Positions and normals of the vertices, at the bake level. */ + float3 positions[4]; + float3 normals[4]; + + /* Quad is shaded flat: it has the same normal at every point of its surface. + * Face normal is stored in all elements of the normals array. */ + bool is_flat; + + /* Optional tangents. + * The uv_tangents might be uninitialized if has_uv_tangents=false. */ + bool has_uv_tangents; + float4 uv_tangents[4]; + + /* Face index and UV coordinate within the face when baking to non-base mesh (with some + * subdivision levels applied). + * + * The fields are referring to the face as a quad because with one subdivision level applied all + * faces becomes quads. + * + * The uv origin is at the first face corner, U points in the direction to the next corner, the + * V points in the direction of the previous corner. + * + * When baking to the base level the fields values is unspecified. */ + int bake_level_quad_index; + float2 bake_level_quad_uvs[4]; +}; + +struct RasterizeResult { + float height_min = FLT_MAX; + float height_max = -FLT_MAX; +}; + +struct BakedImBuf { + Image *image; ImBuf *ibuf; - MPassKnownData pass_data; - /* material aligned UV array */ - Image **image_array; + ExtraBuffers extra_buffers; + float2 uv_offset; }; -using MFlushPixel = void (*)(const MResolvePixelData *data, int x, int y); +struct MultiresBakeResult { + Vector baked_ibufs; -struct MBakeRast { - int w, h; - char *texels; - const MResolvePixelData *data; - MFlushPixel flush_pixel; - bool *do_update; + /* Minimum and maximum height during displacement baking. */ + float height_min = FLT_MAX; + float height_max = -FLT_MAX; }; -struct MHeightBakeData { - float *heights; - DerivedMesh *ssdm; - const int *orig_index_mp_to_orig; -}; +class MultiresBaker { + public: + virtual ~MultiresBaker() = default; -struct MNormalBakeData { - const int *orig_index_mp_to_orig; -}; + virtual float3 bake_pixel(const RasterizeTriangle &triangle, + const float2 &bary_uv, + const float2 &grid_uv, + RasterizeResult &result) const = 0; -struct BakeImBufuserData { - float *displacement_buffer; - char *mask_buffer; -}; + virtual void write_pixel(const RasterizeTile &tile, + const int2 &coord, + const float3 &value) const = 0; -static void multiresbake_get_normal(const MResolvePixelData *data, - const int tri_num, - const int vert_index, - float r_normal[3]) -{ - const int face_index = data->tri_faces[tri_num]; - const bool smoothnormal = !(data->sharp_faces && data->sharp_faces[face_index]); + protected: + void write_pixel_to_image_buffer(ImBuf &ibuf, const int2 &coord, const float3 &value) const + { + const int64_t pixel = int64_t(ibuf.x) * coord.y + coord.x; - if (smoothnormal) { - const int vi = data->corner_verts[data->corner_tris[tri_num][vert_index]]; - copy_v3_v3(r_normal, data->vert_normals[vi]); - } - else { - copy_v3_v3(r_normal, data->face_normals[face_index]); - } -} - -static void init_bake_rast(MBakeRast *bake_rast, - const ImBuf *ibuf, - const MResolvePixelData *data, - MFlushPixel flush_pixel, - bool *do_update) -{ - BakeImBufuserData *userdata = (BakeImBufuserData *)ibuf->userdata; - - memset(bake_rast, 0, sizeof(MBakeRast)); - - bake_rast->texels = userdata->mask_buffer; - bake_rast->w = ibuf->x; - bake_rast->h = ibuf->y; - bake_rast->data = data; - bake_rast->flush_pixel = flush_pixel; - bake_rast->do_update = do_update; -} - -static void flush_pixel(const MResolvePixelData *data, const int x, const int y) -{ - const float st[2] = {(x + 0.5f) / data->w + data->uv_offset[0], - (y + 0.5f) / data->h + data->uv_offset[1]}; - const float *st0, *st1, *st2; - float no0[3], no1[3], no2[3]; - float fUV[2], from_tang[3][3], to_tang[3][3]; - float u, v, w, sign; - int r; - - st0 = data->uv_map[data->corner_tris[data->tri_index][0]]; - st1 = data->uv_map[data->corner_tris[data->tri_index][1]]; - st2 = data->uv_map[data->corner_tris[data->tri_index][2]]; - - multiresbake_get_normal(data, data->tri_index, 0, no0); /* can optimize these 3 into one call */ - multiresbake_get_normal(data, data->tri_index, 1, no1); - multiresbake_get_normal(data, data->tri_index, 2, no2); - - resolve_tri_uv_v2(fUV, st, st0, st1, st2); - - u = fUV[0]; - v = fUV[1]; - w = 1 - u - v; - - if (!data->pvtangent.is_empty()) { - const float4 &tang0 = data->pvtangent[data->corner_tris[data->tri_index][0]]; - const float4 &tang1 = data->pvtangent[data->corner_tris[data->tri_index][1]]; - const float4 &tang2 = data->pvtangent[data->corner_tris[data->tri_index][2]]; - - /* the sign is the same at all face vertices for any non-degenerate face. - * Just in case we clamp the interpolated value though. */ - sign = (tang0[3] * u + tang1[3] * v + tang2[3] * w) < 0 ? (-1.0f) : 1.0f; - - /* this sequence of math is designed specifically as is with great care - * to be compatible with our shader. Please don't change without good reason. */ - for (r = 0; r < 3; r++) { - from_tang[0][r] = tang0[r] * u + tang1[r] * v + tang2[r] * w; - from_tang[2][r] = no0[r] * u + no1[r] * v + no2[r] * w; + if (ibuf.float_buffer.data) { + /* TODO(sergey): Properly tackle ibuf.channels. */ + BLI_assert(ibuf.channels == 4); + float *rrgbf = ibuf.float_buffer.data + pixel * 4; + rrgbf[0] = value[0]; + rrgbf[1] = value[1]; + rrgbf[2] = value[2]; + rrgbf[3] = 1.0f; + ibuf.userflags |= IB_RECT_INVALID; } - cross_v3_v3v3(from_tang[1], from_tang[2], from_tang[0]); /* `B = sign * cross(N, T)` */ - mul_v3_fl(from_tang[1], sign); - invert_m3_m3(to_tang, from_tang); - } - else { - zero_m3(to_tang); - } + if (ibuf.byte_buffer.data) { + uchar *rrgb = ibuf.byte_buffer.data + pixel * 4; + unit_float_to_uchar_clamp_v3(rrgb, value); + rrgb[3] = 255; + } - data->pass_data(data->vert_positions, - data->vert_normals, - data->faces, - data->corner_verts, - data->corner_tris, - data->tri_faces, - data->uv_map, - data->hires_dm, - data->thread_data, - data->bake_data, - data->ibuf, - data->tri_index, - data->lvl, - st, - to_tang, - x, - y); + ibuf.userflags |= IB_DISPLAY_BUFFER_INVALID; + } +}; + +static bool multiresbake_test_break(const MultiresBakeRender &bake) +{ + if (!bake.stop) { + /* This means baker is executed outside from job system (for example, from Python API). + * In this case there is no need to cancel, as it will be quite strange to cancel out + * execution of a script. */ + return false; + } + return *bake.stop || G.is_break; } -static void set_rast_triangle(const MBakeRast *bake_rast, const int x, const int y) +static float2 get_tile_uv(Image &image, ImageTile &tile) { - const int w = bake_rast->w; - const int h = bake_rast->h; + float uv_offset[2]; + BKE_image_get_tile_uv(&image, tile.tile_number, uv_offset); + return uv_offset; +} + +static bool need_tangent(const MultiresBakeRender &bake) +{ + return bake.mode == RE_BAKE_NORMALS; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Baking pipeline + * \{ */ + +static void flush_pixel(const MultiresBaker &baker, + const RasterizeTile &tile, + const RasterizeTriangle &triangle, + const int x, + const int y, + RasterizeResult &result) +{ + const float2 st{(x + 0.5f) / tile.ibuf->x + tile.uv_offset[0], + (y + 0.5f) / tile.ibuf->y + tile.uv_offset[1]}; + + const float2 bary_uv = resolve_tri_uv( + st, triangle.tex_uvs[0], triangle.tex_uvs[1], triangle.tex_uvs[2]); + const float2 grid_uv = interp_barycentric_triangle(triangle.grid_uvs, bary_uv); + + const float3 baked_pixel = baker.bake_pixel(triangle, bary_uv, grid_uv, result); + baker.write_pixel(tile, int2(x, y), baked_pixel); +} + +static void set_rast_triangle(const MultiresBaker &baker, + const RasterizeTile &tile, + const RasterizeTriangle &triangle, + const int x, + const int y, + RasterizeResult &result) +{ + const int w = tile.ibuf->x; + const int h = tile.ibuf->y; if (x >= 0 && x < w && y >= 0 && y < h) { - if ((bake_rast->texels[y * w + x]) == 0) { - bake_rast->texels[y * w + x] = FILTER_MASK_USED; - flush_pixel(bake_rast->data, x, y); - if (bake_rast->do_update) { - *bake_rast->do_update = true; - } + const int64_t pixel = int64_t(y) * w + x; + if (tile.extra_buffers->mask_buffer[pixel] == FILTER_MASK_NULL) { + tile.extra_buffers->mask_buffer[pixel] = FILTER_MASK_USED; + flush_pixel(baker, tile, triangle, x, y, result); } } } -static void rasterize_half(const MBakeRast *bake_rast, +static void rasterize_half(const MultiresBaker &baker, + const RasterizeTile &tile, + const RasterizeTriangle &triangle, const float2 &s0, const float2 &s1, const float2 &l0, const float2 &l1, const int y0_in, const int y1_in, - const bool is_mid_right) + const bool is_mid_right, + RasterizeResult &result) { const bool s_stable = fabsf(s1.y - s0.y) > FLT_EPSILON; const bool l_stable = fabsf(l1.y - l0.y) > FLT_EPSILON; - const int w = bake_rast->w; - const int h = bake_rast->h; + const int w = tile.ibuf->x; + const int h = tile.ibuf->y; if (y1_in <= 0 || y0_in >= h) { return; @@ -269,7 +563,7 @@ static void rasterize_half(const MBakeRast *bake_rast, /*-b(x-x0) + a(y-y0) = 0 */ float x_l = s_stable ? (s0.x + (((s1.x - s0.x) * (y - s0.y)) / (s1.y - s0.y))) : s0.x; float x_r = l_stable ? (l0.x + (((l1.x - l0.x) * (y - l0.y)) / (l1.y - l0.y))) : l0.x; - if (is_mid_right != 0) { + if (is_mid_right) { std::swap(x_l, x_r); } @@ -281,18 +575,22 @@ static void rasterize_half(const MBakeRast *bake_rast, iXr = iXr >= w ? w : iXr; for (int x = iXl; x < iXr; x++) { - set_rast_triangle(bake_rast, x, y); + set_rast_triangle(baker, tile, triangle, x, y, result); } } } } -static void bake_rasterize(const MBakeRast *bake_rast, - const float2 &st0_in, - const float2 &st1_in, - const float2 &st2_in) +static void rasterize_triangle(const MultiresBaker &baker, + const RasterizeTile &tile, + const RasterizeTriangle &triangle, + RasterizeResult &result) { - const float2 ibuf_size(bake_rast->w, bake_rast->h); + const float2 ibuf_size(tile.ibuf->x, tile.ibuf->y); + + const float2 &st0_in = triangle.tex_uvs[0]; + const float2 &st1_in = triangle.tex_uvs[1]; + const float2 &st2_in = triangle.tex_uvs[2]; float2 p_low = st0_in * ibuf_size - 0.5f; float2 p_mid = st1_in * ibuf_size - 0.5f; @@ -326,794 +624,324 @@ static void bake_rasterize(const MBakeRast *bake_rast, const int yhi_beg = int(ceilf(p_mid.y)); const int yhi = int(ceilf(p_high.y)); - // if (fTmi>ceilf(fTlo)) - rasterize_half(bake_rast, p_low, p_mid, p_low, p_high, ylo, yhi_beg, is_mid_right); - rasterize_half(bake_rast, p_mid, p_high, p_low, p_high, yhi_beg, yhi, is_mid_right); + rasterize_half( + baker, tile, triangle, p_low, p_mid, p_low, p_high, ylo, yhi_beg, is_mid_right, result); + rasterize_half( + baker, tile, triangle, p_mid, p_high, p_low, p_high, yhi_beg, yhi, is_mid_right, result); } -static bool multiresbake_test_break(const MultiresBakeRender &bake) +static void rasterize_quad(const MultiresBaker &baker, + const RasterizeTile &tile, + const RasterizeQuad &quad, + RasterizeResult &result) { - if (!bake.stop) { - /* This means baker is executed outside from job system. */ - return false; + RasterizeTriangle triangle; + triangle.grid_index = quad.grid_index; + triangle.is_flat = quad.is_flat; + triangle.has_uv_tangents = quad.has_uv_tangents; + triangle.bake_level_quad_index = quad.bake_level_quad_index; + + const int3 quad_split_data[2] = {{0, 1, 2}, {2, 3, 0}}; + for (const int3 &triangle_idx : Span(quad_split_data, 2)) { + triangle.grid_uvs[0] = quad.grid_uvs[triangle_idx.x]; + triangle.grid_uvs[1] = quad.grid_uvs[triangle_idx.y]; + triangle.grid_uvs[2] = quad.grid_uvs[triangle_idx.z]; + + triangle.tex_uvs[0] = quad.tex_uvs[triangle_idx.x]; + triangle.tex_uvs[1] = quad.tex_uvs[triangle_idx.y]; + triangle.tex_uvs[2] = quad.tex_uvs[triangle_idx.z]; + + triangle.positions[0] = quad.positions[triangle_idx.x]; + triangle.positions[1] = quad.positions[triangle_idx.y]; + triangle.positions[2] = quad.positions[triangle_idx.z]; + + triangle.normals[0] = quad.normals[triangle_idx.x]; + triangle.normals[1] = quad.normals[triangle_idx.y]; + triangle.normals[2] = quad.normals[triangle_idx.z]; + + if (triangle.has_uv_tangents) { + triangle.uv_tangents[0] = quad.uv_tangents[triangle_idx.x]; + triangle.uv_tangents[1] = quad.uv_tangents[triangle_idx.y]; + triangle.uv_tangents[2] = quad.uv_tangents[triangle_idx.z]; + } + + triangle.bake_level_quad_uvs[0] = quad.bake_level_quad_uvs[triangle_idx.x]; + triangle.bake_level_quad_uvs[1] = quad.bake_level_quad_uvs[triangle_idx.y]; + triangle.bake_level_quad_uvs[2] = quad.bake_level_quad_uvs[triangle_idx.z]; + + rasterize_triangle(baker, tile, triangle, result); } - return *bake.stop || G.is_break; } -/* **** Threading routines **** */ +/** \} */ -struct MultiresBakeQueue { - int cur_tri; - int tot_tri; - SpinLock spin; -}; +/* -------------------------------------------------------------------- */ +/** \name Displacement Baker + * \{ */ -struct MultiresBakeThread { - /* this data is actually shared between all the threads */ - MultiresBakeQueue *queue; - MultiresBakeRender *bake; - Image *image; - void *bake_data; - int num_total_faces; +class MultiresBaseDisplacementBaker : public MultiresBaker { + /* SubdivCCG at the highest multi-resolution level. */ + const SubdivCCG &high_subdiv_ccg_; - /* thread-specific data */ - MBakeRast bake_rast; - MResolvePixelData data; + /* Baking happens to non-zero subdivision level. */ + bool is_baking_to_subdivided_mesh_ = false; - /* displacement-specific data */ - float height_min, height_max; -}; + /* SubdivCCG created from the bake level mesh by subdividing it to the highest multi-resolution + * level. It is used as "reference" surface when baking with "Low Resolution Mesh" option + * disabled. */ + std::unique_ptr subdivided_ccg_; -static int multires_bake_queue_next_tri(MultiresBakeQueue *queue) -{ - int face = -1; - - /* TODO: it could worth making it so thread will handle neighbor faces - * for better memory cache utilization - */ - - BLI_spin_lock(&queue->spin); - if (queue->cur_tri < queue->tot_tri) { - face = queue->cur_tri; - queue->cur_tri++; - } - BLI_spin_unlock(&queue->spin); - - return face; -} - -static void *do_multires_bake_thread(void *data_v) -{ - MultiresBakeThread *handle = (MultiresBakeThread *)data_v; - MResolvePixelData *data = &handle->data; - MBakeRast *bake_rast = &handle->bake_rast; - MultiresBakeRender &bake = *handle->bake; - int tri_index; - - while ((tri_index = multires_bake_queue_next_tri(handle->queue)) >= 0) { - const int3 &tri = data->corner_tris[tri_index]; - const int face_i = data->tri_faces[tri_index]; - const short mat_nr = data->material_indices == nullptr ? 0 : data->material_indices[face_i]; - - if (multiresbake_test_break(bake)) { - break; - } - - Image *tri_image = mat_nr < bake.ob_image.size() ? bake.ob_image[mat_nr] : nullptr; - if (tri_image != handle->image) { - continue; - } - - data->tri_index = tri_index; - - float uv[3][2]; - sub_v2_v2v2(uv[0], data->uv_map[tri[0]], data->uv_offset); - sub_v2_v2v2(uv[1], data->uv_map[tri[1]], data->uv_offset); - sub_v2_v2v2(uv[2], data->uv_map[tri[2]], data->uv_offset); - - bake_rasterize(bake_rast, uv[0], uv[1], uv[2]); - - /* tag image buffer for refresh */ - if (data->ibuf->float_buffer.data) { - data->ibuf->userflags |= IB_RECT_INVALID; - } - - data->ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; - - /* update progress */ - BLI_spin_lock(&handle->queue->spin); - bake.baked_faces++; - - if (bake.do_update) { - *bake.do_update = true; - } - - if (bake.progress) { - *bake.progress = (float(bake.baked_objects) + - float(bake.baked_faces) / handle->num_total_faces) / - bake.tot_obj; - } - BLI_spin_unlock(&handle->queue->spin); - } - - return nullptr; -} - -/* some of arrays inside ccgdm are lazy-initialized, which will generally - * require lock around accessing such data - * this function will ensure all arrays are allocated before threading started - */ -static void init_ccgdm_arrays(DerivedMesh *dm) -{ - CCGElem **grid_data; - CCGKey key; - int grid_size; - const int *grid_offset; - - grid_size = dm->getGridSize(dm); - grid_data = dm->getGridData(dm); - grid_offset = dm->getGridOffset(dm); - dm->getGridKey(dm, &key); - - (void)grid_size; - (void)grid_data; - (void)grid_offset; -} - -static void do_multires_bake(MultiresBakeRender &bake, - Image *image, - ImageTile *tile, - ImBuf *ibuf, - const bool require_tangent, - const MPassKnownData passKnownData, - const MInitBakeData initBakeData, - const MFreeBakeData freeBakeData, - MultiresBakeResult &result) -{ - DerivedMesh *dm = bake.lores_dm; - const int lvl = bake.lvl; - if (dm->getNumPolys(dm) == 0) { - return; - } - - const Span uv_map( - reinterpret_cast(dm->getLoopDataArray(dm, CD_PROP_FLOAT2)), - dm->getNumLoops(dm)); - - Array pvtangent; - - Mesh *temp_mesh = BKE_mesh_new_nomain( - dm->getNumVerts(dm), dm->getNumEdges(dm), dm->getNumPolys(dm), dm->getNumLoops(dm)); - temp_mesh->vert_positions_for_write().copy_from( - {reinterpret_cast(dm->getVertArray(dm)), temp_mesh->verts_num}); - temp_mesh->edges_for_write().copy_from( - {reinterpret_cast(dm->getEdgeArray(dm)), temp_mesh->edges_num}); - temp_mesh->face_offsets_for_write().copy_from({dm->getPolyArray(dm), temp_mesh->faces_num + 1}); - temp_mesh->corner_verts_for_write().copy_from( - {dm->getCornerVertArray(dm), temp_mesh->corners_num}); - temp_mesh->corner_edges_for_write().copy_from( - {dm->getCornerEdgeArray(dm), temp_mesh->corners_num}); - - const Span positions = temp_mesh->vert_positions(); - const OffsetIndices faces = temp_mesh->faces(); - const Span corner_verts = temp_mesh->corner_verts(); - const Span vert_normals = temp_mesh->vert_normals(); - const Span face_normals = temp_mesh->face_normals(); - const Span corner_tris = temp_mesh->corner_tris(); - const Span tri_faces = temp_mesh->corner_tri_faces(); - - if (require_tangent) { - const bool *sharp_edges = static_cast( - CustomData_get_layer_named(&dm->edgeData, CD_PROP_BOOL, "sharp_edge")); - const bool *sharp_faces = static_cast( - CustomData_get_layer_named(&dm->polyData, CD_PROP_BOOL, "sharp_face")); - - /* Copy sharp faces and edges, for corner normals domain and tangents - * to be computed correctly. */ - if (sharp_edges != nullptr) { - bke::MutableAttributeAccessor attributes = temp_mesh->attributes_for_write(); - attributes.add("sharp_edge", - bke::AttrDomain::Edge, - bke::AttributeInitVArray(VArray::from_span( - Span(sharp_edges, temp_mesh->edges_num)))); - } - if (sharp_faces != nullptr) { - bke::MutableAttributeAccessor attributes = temp_mesh->attributes_for_write(); - attributes.add("sharp_face", - bke::AttrDomain::Face, - bke::AttributeInitVArray(VArray::from_span( - Span(sharp_faces, temp_mesh->faces_num)))); - } - - const Span corner_normals = temp_mesh->corner_normals(); - Array> tangent_data = bke::mesh::calc_uv_tangents( - positions, - faces, - corner_verts, - corner_tris, - tri_faces, - sharp_faces ? Span(sharp_faces, faces.size()) : Span(), - vert_normals, - face_normals, - corner_normals, - {uv_map}); - - pvtangent = std::move(tangent_data[0]); - } - - /* All threads share the same custom bake data. */ - void *bake_data = nullptr; - if (initBakeData) { - bake_data = initBakeData(bake, ibuf); - } - - ListBase threads; - const int tot_thread = bake.threads > 0 ? bake.threads : BLI_system_thread_count(); - if (tot_thread > 1) { - BLI_threadpool_init(&threads, do_multires_bake_thread, tot_thread); - } - - Array handles(tot_thread); - - init_ccgdm_arrays(bake.hires_dm); - - /* Faces queue. */ - MultiresBakeQueue queue; - queue.cur_tri = 0; - queue.tot_tri = corner_tris.size(); - BLI_spin_init(&queue.spin); - - /* Fill in threads handles. */ - for (int i = 0; i < tot_thread; i++) { - MultiresBakeThread *handle = &handles[i]; - - handle->bake = &bake; - handle->image = image; - handle->num_total_faces = queue.tot_tri * BLI_listbase_count(&image->tiles); - handle->queue = &queue; - - handle->data.vert_positions = positions; - handle->data.faces = faces; - handle->data.corner_verts = corner_verts; - handle->data.corner_tris = corner_tris; - handle->data.tri_faces = tri_faces; - handle->data.vert_normals = vert_normals; - handle->data.face_normals = face_normals; - handle->data.material_indices = static_cast( - CustomData_get_layer_named(&dm->polyData, CD_PROP_INT32, "material_index")); - handle->data.sharp_faces = static_cast( - CustomData_get_layer_named(&dm->polyData, CD_PROP_BOOL, "sharp_face")); - handle->data.uv_map = uv_map; - BKE_image_get_tile_uv(image, tile->tile_number, handle->data.uv_offset); - handle->data.pvtangent = pvtangent; - handle->data.w = ibuf->x; - handle->data.h = ibuf->y; - handle->data.hires_dm = bake.hires_dm; - handle->data.lvl = lvl; - handle->data.pass_data = passKnownData; - handle->data.thread_data = handle; - handle->data.bake_data = bake_data; - handle->data.ibuf = ibuf; - - handle->height_min = FLT_MAX; - handle->height_max = -FLT_MAX; - - init_bake_rast(&handle->bake_rast, ibuf, &handle->data, flush_pixel, bake.do_update); - - if (tot_thread > 1) { - BLI_threadpool_insert(&threads, handle); + public: + MultiresBaseDisplacementBaker(const MultiresBakeRender &bake, + const Mesh &bake_level_mesh, + const SubdivCCG &subdiv_ccg) + : high_subdiv_ccg_(subdiv_ccg) + { + if (!bake.use_low_resolution_mesh) { + create_subdivided_ccg(bake_level_mesh, *bake.multires_modifier); + is_baking_to_subdivided_mesh_ = bake.multires_modifier->lvl > 0; } } - /* Run threads. */ - if (tot_thread > 1) { - BLI_threadpool_end(&threads); - } - else { - do_multires_bake_thread(handles.data()); - } - - for (int i = 0; i < tot_thread; i++) { - result.height_min = min_ff(result.height_min, handles[i].height_min); - result.height_max = max_ff(result.height_max, handles[i].height_max); - } - - BLI_spin_end(&queue.spin); - - /* Finalize baking. */ - if (freeBakeData) { - freeBakeData(bake_data); - } - - BKE_id_free(nullptr, temp_mesh); -} - -/* mode = 0: interpolate normals, - * mode = 1: interpolate coord */ -static void interp_bilinear_grid( - const CCGKey &key, CCGElem *grid, float crn_x, float crn_y, int mode, float res[3]) -{ - int x0, x1, y0, y1; - float u, v; - float data[4][3]; - - x0 = int(crn_x); - x1 = x0 >= (key.grid_size - 1) ? (key.grid_size - 1) : (x0 + 1); - - y0 = int(crn_y); - y1 = y0 >= (key.grid_size - 1) ? (key.grid_size - 1) : (y0 + 1); - - u = crn_x - x0; - v = crn_y - y0; - - if (mode == 0) { - copy_v3_v3(data[0], CCG_grid_elem_no(key, grid, x0, y0)); - copy_v3_v3(data[1], CCG_grid_elem_no(key, grid, x1, y0)); - copy_v3_v3(data[2], CCG_grid_elem_no(key, grid, x1, y1)); - copy_v3_v3(data[3], CCG_grid_elem_no(key, grid, x0, y1)); - } - else { - copy_v3_v3(data[0], CCG_grid_elem_co(key, grid, x0, y0)); - copy_v3_v3(data[1], CCG_grid_elem_co(key, grid, x1, y0)); - copy_v3_v3(data[2], CCG_grid_elem_co(key, grid, x1, y1)); - copy_v3_v3(data[3], CCG_grid_elem_co(key, grid, x0, y1)); - } - - interp_bilinear_quad_v3(data, u, v, res); -} - -static void get_ccgdm_data(const OffsetIndices lores_polys, - DerivedMesh *hidm, - const int *index_mp_to_orig, - const int lvl, - const int face_index, - const float u, - const float v, - float co[3], - float n[3]) -{ - CCGElem **grid_data; - CCGKey key; - float crn_x, crn_y; - int grid_size, S, face_side; - int *grid_offset, g_index; - - grid_size = hidm->getGridSize(hidm); - grid_data = hidm->getGridData(hidm); - grid_offset = hidm->getGridOffset(hidm); - hidm->getGridKey(hidm, &key); - - if (lvl == 0) { - face_side = (grid_size << 1) - 1; - - g_index = grid_offset[face_index]; - S = mdisp_rot_face_to_crn(lores_polys[face_index].size(), - face_side, - u * (face_side - 1), - v * (face_side - 1), - &crn_x, - &crn_y); - } - else { - /* number of faces per grid side */ - int polys_per_grid_side = (1 << (lvl - 1)); - /* get the original cage face index */ - int cage_face_index = index_mp_to_orig ? index_mp_to_orig[face_index] : face_index; - /* local offset in total cage face grids - * `(1 << (2 * lvl))` is number of all faces for one cage face */ - int loc_cage_poly_ofs = face_index % (1 << (2 * lvl)); - /* local offset in the vertex grid itself */ - int cell_index = loc_cage_poly_ofs % (polys_per_grid_side * polys_per_grid_side); - int cell_side = (grid_size - 1) / polys_per_grid_side; - /* row and column based on grid side */ - int row = cell_index / polys_per_grid_side; - int col = cell_index % polys_per_grid_side; - - /* S is the vertex whose grid we are examining */ - S = face_index / (1 << (2 * (lvl - 1))) - grid_offset[cage_face_index]; - /* get offset of grid data for original cage face */ - g_index = grid_offset[cage_face_index]; - - crn_y = (row * cell_side) + u * cell_side; - crn_x = (col * cell_side) + v * cell_side; - } - - CLAMP(crn_x, 0.0f, grid_size); - CLAMP(crn_y, 0.0f, grid_size); - - if (n != nullptr) { - interp_bilinear_grid(key, grid_data[g_index + S], crn_x, crn_y, 0, n); - } - - if (co != nullptr) { - interp_bilinear_grid(key, grid_data[g_index + S], crn_x, crn_y, 1, co); - } -} - -/* mode = 0: interpolate normals, - * mode = 1: interpolate coord */ - -static void interp_bilinear_mpoly(const Span vert_positions, - const Span vert_normals, - const Span corner_verts, - const IndexRange face, - const float u, - const float v, - const int mode, - float res[3]) -{ - float data[4][3]; - - if (mode == 0) { - copy_v3_v3(data[0], vert_normals[corner_verts[face[0]]]); - copy_v3_v3(data[1], vert_normals[corner_verts[face[1]]]); - copy_v3_v3(data[2], vert_normals[corner_verts[face[2]]]); - copy_v3_v3(data[3], vert_normals[corner_verts[face[3]]]); - } - else { - copy_v3_v3(data[0], vert_positions[corner_verts[face[0]]]); - copy_v3_v3(data[1], vert_positions[corner_verts[face[1]]]); - copy_v3_v3(data[2], vert_positions[corner_verts[face[2]]]); - copy_v3_v3(data[3], vert_positions[corner_verts[face[3]]]); - } - - interp_bilinear_quad_v3(data, u, v, res); -} - -static void interp_barycentric_corner_tri(const Span vert_positions, - const Span vert_normals, - const Span corner_verts, - const int3 &corner_tri, - const float u, - const float v, - const int mode, - float res[3]) -{ - float data[3][3]; - - if (mode == 0) { - copy_v3_v3(data[0], vert_normals[corner_verts[corner_tri[0]]]); - copy_v3_v3(data[1], vert_normals[corner_verts[corner_tri[1]]]); - copy_v3_v3(data[2], vert_normals[corner_verts[corner_tri[2]]]); - } - else { - copy_v3_v3(data[0], vert_positions[corner_verts[corner_tri[0]]]); - copy_v3_v3(data[1], vert_positions[corner_verts[corner_tri[1]]]); - copy_v3_v3(data[2], vert_positions[corner_verts[corner_tri[2]]]); - } - - interp_barycentric_tri_v3(data, u, v, res); -} - -/* **************** Displacement Baker **************** */ - -static void *init_heights_data(MultiresBakeRender &bake, ImBuf *ibuf) -{ - MHeightBakeData *height_data; - DerivedMesh *lodm = bake.lores_dm; - BakeImBufuserData *userdata = static_cast(ibuf->userdata); - - if (userdata->displacement_buffer == nullptr) { - userdata->displacement_buffer = MEM_calloc_arrayN(IMB_get_pixel_count(ibuf), - "MultiresBake heights"); - } - - height_data = MEM_callocN("MultiresBake heightData"); - - height_data->heights = userdata->displacement_buffer; - - if (!bake.use_lores_mesh) { - SubsurfModifierData smd = {{nullptr}}; - int ss_lvl = bake.tot_lvl - bake.lvl; - - CLAMP(ss_lvl, 0, 6); - - if (ss_lvl > 0) { - smd.levels = smd.renderLevels = ss_lvl; - smd.uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES; - smd.quality = 3; - - height_data->ssdm = subsurf_make_derived_from_derived( - bake.lores_dm, &smd, bake.scene, nullptr, SubsurfFlags(0)); - init_ccgdm_arrays(height_data->ssdm); - } - } - - height_data->orig_index_mp_to_orig = static_cast( - lodm->getPolyDataArray(lodm, CD_ORIGINDEX)); - - return (void *)height_data; -} - -static void free_heights_data(void *bake_data) -{ - MHeightBakeData *height_data = (MHeightBakeData *)bake_data; - - if (height_data->ssdm) { - height_data->ssdm->release(height_data->ssdm); - } - - MEM_freeN(height_data); -} - -/* MultiresBake callback for heights baking - * general idea: - * - find coord of point with specified UV in hi-res mesh (let's call it p1) - * - find coord of point and normal with specified UV in lo-res mesh (or subdivided lo-res - * mesh to make texture smoother) let's call this point p0 and n. - * - height wound be dot(n, p1-p0) */ -static void apply_heights_callback(const Span vert_positions, - const Span vert_normals, - const OffsetIndices faces, - const Span corner_verts, - const Span corner_tris, - const Span tri_faces, - const Span uv_map, - DerivedMesh *hires_dm, - void *thread_data_v, - void *bake_data, - ImBuf *ibuf, - const int tri_index, - const int lvl, - const float st[2], - float /*tangmat*/[3][3], - const int x, - const int y) -{ - const int3 &tri = corner_tris[tri_index]; - const int face_i = tri_faces[tri_index]; - const IndexRange face = faces[face_i]; - MHeightBakeData *height_data = (MHeightBakeData *)bake_data; - MultiresBakeThread *thread_data = (MultiresBakeThread *)thread_data_v; - float uv[2]; - const float *st0, *st1, *st2, *st3; - int pixel = ibuf->x * y + x; - float vec[3], p0[3], p1[3], n[3], len; - - /* ideally we would work on triangles only, however, we rely on quads to get orthogonal - * coordinates for use in grid space (triangle barycentric is not orthogonal) */ - if (face.size() == 4) { - st0 = uv_map[face[0]]; - st1 = uv_map[face[1]]; - st2 = uv_map[face[2]]; - st3 = uv_map[face[3]]; - resolve_quad_uv_v2(uv, st, st0, st1, st2, st3); - } - else { - st0 = uv_map[tri[0]]; - st1 = uv_map[tri[1]]; - st2 = uv_map[tri[2]]; - resolve_tri_uv_v2(uv, st, st0, st1, st2); - } - - clamp_v2(uv, 0.0f, 1.0f); - - get_ccgdm_data( - faces, hires_dm, height_data->orig_index_mp_to_orig, lvl, face_i, uv[0], uv[1], p1, nullptr); - - if (height_data->ssdm) { - get_ccgdm_data(faces, - height_data->ssdm, - height_data->orig_index_mp_to_orig, - 0, - face_i, - uv[0], - uv[1], - p0, - n); - } - else { - if (face.size() == 4) { - interp_bilinear_mpoly(vert_positions, vert_normals, corner_verts, face, uv[0], uv[1], 1, p0); - interp_bilinear_mpoly(vert_positions, vert_normals, corner_verts, face, uv[0], uv[1], 0, n); - } - else { - interp_barycentric_corner_tri( - vert_positions, vert_normals, corner_verts, tri, uv[0], uv[1], 1, p0); - interp_barycentric_corner_tri( - vert_positions, vert_normals, corner_verts, tri, uv[0], uv[1], 0, n); - } - } - - sub_v3_v3v3(vec, p1, p0); - len = dot_v3v3(n, vec); - - height_data->heights[pixel] = len; - - thread_data->height_min = min_ff(thread_data->height_min, len); - thread_data->height_max = max_ff(thread_data->height_max, len); - - if (ibuf->float_buffer.data) { - float *rrgbf = ibuf->float_buffer.data + pixel * 4; - rrgbf[0] = rrgbf[1] = rrgbf[2] = len; - rrgbf[3] = 1.0f; - } - else { - uchar *rrgb = ibuf->byte_buffer.data + pixel * 4; - rrgb[0] = rrgb[1] = rrgb[2] = unit_float_to_uchar_clamp(len); - rrgb[3] = 255; - } -} - -/* **************** Normal Maps Baker **************** */ - -static void *init_normal_data(MultiresBakeRender &bake, ImBuf * /*ibuf*/) -{ - MNormalBakeData *normal_data; - DerivedMesh *lodm = bake.lores_dm; - - normal_data = MEM_callocN("MultiresBake normalData"); - - normal_data->orig_index_mp_to_orig = static_cast( - lodm->getPolyDataArray(lodm, CD_ORIGINDEX)); - - return (void *)normal_data; -} - -static void free_normal_data(void *bake_data) -{ - MNormalBakeData *normal_data = (MNormalBakeData *)bake_data; - - MEM_freeN(normal_data); -} - -/** - * MultiresBake callback for normals' baking. - * - * General idea: - * - Find coord and normal of point with specified UV in hi-res mesh. - * - Multiply it by tangmat. - * - Vector in color space would be `norm(vec) / 2 + (0.5, 0.5, 0.5)`. - */ -static void apply_tangmat_callback(const Span /*vert_positions*/, - const Span /*vert_normals*/, - const OffsetIndices faces, - const Span /*corner_verts*/, - const Span corner_tris, - const Span tri_faces, - const Span uv_map, - DerivedMesh *hires_dm, - void * /*thread_data*/, - void *bake_data, - ImBuf *ibuf, - const int tri_index, - const int lvl, - const float st[2], - float tangmat[3][3], - const int x, - const int y) -{ - const int3 &tri = corner_tris[tri_index]; - const int face_i = tri_faces[tri_index]; - const IndexRange face = faces[face_i]; - MNormalBakeData *normal_data = (MNormalBakeData *)bake_data; - float uv[2]; - const float *st0, *st1, *st2, *st3; - int pixel = ibuf->x * y + x; - float n[3], vec[3], tmp[3] = {0.5, 0.5, 0.5}; - - /* ideally we would work on triangles only, however, we rely on quads to get orthogonal - * coordinates for use in grid space (triangle barycentric is not orthogonal) */ - if (face.size() == 4) { - st0 = uv_map[face[0]]; - st1 = uv_map[face[1]]; - st2 = uv_map[face[2]]; - st3 = uv_map[face[3]]; - resolve_quad_uv_v2(uv, st, st0, st1, st2, st3); - } - else { - st0 = uv_map[tri[0]]; - st1 = uv_map[tri[1]]; - st2 = uv_map[tri[2]]; - resolve_tri_uv_v2(uv, st, st0, st1, st2); - } - - clamp_v2(uv, 0.0f, 1.0f); - - get_ccgdm_data( - faces, hires_dm, normal_data->orig_index_mp_to_orig, lvl, face_i, uv[0], uv[1], nullptr, n); - - mul_v3_m3v3(vec, tangmat, n); - normalize_v3_length(vec, 0.5); - add_v3_v3(vec, tmp); - - if (ibuf->float_buffer.data) { - float *rrgbf = ibuf->float_buffer.data + pixel * 4; - rrgbf[0] = vec[0]; - rrgbf[1] = vec[1]; - rrgbf[2] = vec[2]; - rrgbf[3] = 1.0f; - } - else { - uchar *rrgb = ibuf->byte_buffer.data + pixel * 4; - rgb_float_to_uchar(rrgb, vec); - rrgb[3] = 255; - } -} - -/* ******$***************** Post processing ************************* */ - -static void bake_ibuf_filter(ImBuf *ibuf, - char *mask, - const int margin, - const char margin_type, - DerivedMesh *dm, - const float uv_offset[2]) -{ - /* must check before filtering */ - const bool is_new_alpha = (ibuf->planes != R_IMF_PLANES_RGBA) && BKE_imbuf_alpha_test(ibuf); - - if (margin) { - switch (margin_type) { - case R_BAKE_ADJACENT_FACES: - RE_generate_texturemargin_adjacentfaces_dm(ibuf, mask, margin, dm, uv_offset); - break; - default: - /* fall through */ - case R_BAKE_EXTEND: - IMB_filter_extend(ibuf, mask, margin); - break; - } - } - - /* if the bake results in new alpha then change the image setting */ - if (is_new_alpha) { - ibuf->planes = R_IMF_PLANES_RGBA; - } - else { - if (margin && ibuf->planes != R_IMF_PLANES_RGBA) { - /* clear alpha added by filtering */ - IMB_rectfill_alpha(ibuf, 1.0f); - } - } -} - -static void bake_ibuf_normalize_displacement(ImBuf *ibuf, - const float *displacement, - const char *mask, - float displacement_min, - float displacement_max) -{ - const float *current_displacement = displacement; - const char *current_mask = mask; - float max_distance; - - max_distance = max_ff(fabsf(displacement_min), fabsf(displacement_max)); - - const size_t ibuf_pixel_count = IMB_get_pixel_count(ibuf); - for (size_t i = 0; i < ibuf_pixel_count; i++) { - if (*current_mask == FILTER_MASK_USED) { - float normalized_displacement; - - if (max_distance > 1e-5f) { - normalized_displacement = (*current_displacement + max_distance) / (max_distance * 2); + protected: + void get_bake_level_position_and_normal(const RasterizeTriangle &triangle, + const float2 &bary_uv, + const float2 &grid_uv, + float3 &bake_level_position, + float3 &bake_level_normal) const + { + if (subdivided_ccg_) { + if (!is_baking_to_subdivided_mesh_) { + bake_level_position = sample_position_on_subdiv_ccg( + *subdivided_ccg_, triangle.grid_index, grid_uv); + bake_level_normal = sample_normal_on_subdiv_ccg( + *subdivided_ccg_, triangle.grid_index, grid_uv); } else { - normalized_displacement = 0.5f; - } + /* Map bake level face and UV coordinate within it to the grid index and its uv within + * the subdivided_ccg_. + * + * The fact that the bake mesh is subdivided at least once makes math a bit easier since + * all its faces are quads, which maps 1:1 to the PTex faces in the subdivided_ccg_. So the + * only trick comes in mapping UV coordinate within a quad face to a corner and UV + * coordinate within this corner. */ - if (ibuf->float_buffer.data) { - /* currently baking happens to RGBA only */ - float *fp = ibuf->float_buffer.data + i * 4; - fp[0] = fp[1] = fp[2] = normalized_displacement; - fp[3] = 1.0f; - } + const float2 quad_uv = triangle.get_bake_level_quad_uv(bary_uv); + float2 corner_uv; + const int corner = subdiv::rotate_quad_to_corner( + quad_uv.x, quad_uv.y, &corner_uv.x, &corner_uv.y); - if (ibuf->byte_buffer.data) { - uchar *cp = ibuf->byte_buffer.data + 4 * i; - cp[0] = cp[1] = cp[2] = unit_float_to_uchar_clamp(normalized_displacement); - cp[3] = 255; + const float2 quad_grid_uv = subdiv::ptex_face_uv_to_grid_uv(corner_uv); + const int quad_grid_index = triangle.bake_level_quad_index * 4 + corner; + + bake_level_position = sample_position_on_subdiv_ccg( + *subdivided_ccg_, quad_grid_index, quad_grid_uv); + bake_level_normal = sample_normal_on_subdiv_ccg( + *subdivided_ccg_, quad_grid_index, quad_grid_uv); } } - - current_displacement++; - current_mask++; + else { + bake_level_position = triangle.get_position(bary_uv); + bake_level_normal = triangle.get_normal(bary_uv); + } } -} -/* **************** Common functions public API relates on **************** */ + float3 get_high_level_position(const int grid_index, const float2 &grid_uv) const + { + return sample_position_on_subdiv_ccg(high_subdiv_ccg_, grid_index, grid_uv); + } -static void count_images(MultiresBakeRender &bake) + private: + subdiv::Subdiv *create_subdiv_for_subdivided_ccg(const Mesh &bake_level_mesh, + const MultiresModifierData &multires_modifier) + { + subdiv::Settings subdiv_settings; + BKE_multires_subdiv_settings_init(&subdiv_settings, &multires_modifier); + subdiv::Subdiv *subdiv = subdiv::update_from_mesh(nullptr, &subdiv_settings, &bake_level_mesh); + + /* Initialization evaluation of the limit surface and the displacement. */ + if (!subdiv::eval_begin_from_mesh(subdiv, &bake_level_mesh, subdiv::SUBDIV_EVALUATOR_TYPE_CPU)) + { + subdiv::free(subdiv); + return nullptr; + } + + return subdiv; + } + + void create_subdivided_ccg(const Mesh &bake_level_mesh, + const MultiresModifierData &multires_modifier) + { + subdiv::Subdiv *subdiv = create_subdiv_for_subdivided_ccg(bake_level_mesh, multires_modifier); + if (!subdiv) { + return; + } + + const int top_level = multires_modifier.totlvl; + const int bake_level = multires_modifier.lvl; + + const int subdivide_level = top_level - bake_level; + if (subdivide_level == 0) { + subdiv::free(subdiv); + return; + } + + SubdivToCCGSettings settings; + settings.resolution = (1 << subdivide_level) + 1; + settings.need_normal = true; + settings.need_mask = false; + + subdivided_ccg_ = BKE_subdiv_to_ccg(*subdiv, settings, bake_level_mesh); + } +}; + +class MultiresDisplacementBaker : public MultiresBaseDisplacementBaker { + public: + MultiresDisplacementBaker(const MultiresBakeRender &bake, + const Mesh &bake_level_mesh, + const SubdivCCG &subdiv_ccg, + const ImBuf &ibuf, + ExtraBuffers &extra_buffers) + : MultiresBaseDisplacementBaker(bake, bake_level_mesh, subdiv_ccg) + { + extra_buffers.displacement_buffer.reinitialize(IMB_get_pixel_count(&ibuf)); + extra_buffers.displacement_buffer.fill(0); + } + + float3 bake_pixel(const RasterizeTriangle &triangle, + const float2 &bary_uv, + const float2 &grid_uv, + RasterizeResult &result) const override + { + float3 bake_level_position, bake_level_normal; + get_bake_level_position_and_normal( + triangle, bary_uv, grid_uv, bake_level_position, bake_level_normal); + + const float3 high_level_position = get_high_level_position(triangle.grid_index, grid_uv); + + const float length = math::dot(bake_level_normal, (high_level_position - bake_level_position)); + + result.height_min = math::min(result.height_min, length); + result.height_max = math::max(result.height_max, length); + + return {length, length, length}; + } + + void write_pixel(const RasterizeTile &tile, + const int2 &coord, + const float3 &value) const override + { + const ImBuf &ibuf = *tile.ibuf; + + const int64_t pixel = int64_t(ibuf.x) * coord.y + coord.x; + tile.extra_buffers->displacement_buffer[pixel] = value.x; + + write_pixel_to_image_buffer(*tile.ibuf, coord, value); + } +}; + +class MultiresVectorDisplacementBaker : public MultiresBaseDisplacementBaker { + public: + MultiresVectorDisplacementBaker(const MultiresBakeRender &bake, + const Mesh &bake_level_mesh, + const SubdivCCG &subdiv_ccg) + : MultiresBaseDisplacementBaker(bake, bake_level_mesh, subdiv_ccg) + { + } + + float3 bake_pixel(const RasterizeTriangle &triangle, + const float2 &bary_uv, + const float2 &grid_uv, + RasterizeResult & /*result*/) const override + { + float3 bake_level_position, bake_level_normal; + get_bake_level_position_and_normal( + triangle, bary_uv, grid_uv, bake_level_position, bake_level_normal); + + const float3 high_level_position = get_high_level_position(triangle.grid_index, grid_uv); + + return high_level_position - bake_level_position; + } + + void write_pixel(const RasterizeTile &tile, + const int2 &coord, + const float3 &value) const override + { + write_pixel_to_image_buffer(*tile.ibuf, coord, value); + } +}; + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Normal Maps Baker + * \{ */ + +class MultiresNormalsBaker : public MultiresBaker { + const SubdivCCG &subdiv_ccg_; + + public: + explicit MultiresNormalsBaker(const SubdivCCG &subdiv_ccg) : subdiv_ccg_(subdiv_ccg) {} + + float3 bake_pixel(const RasterizeTriangle &triangle, + const float2 &bary_uv, + const float2 &grid_uv, + RasterizeResult & /*result*/) const override + { + const float3x3 to_tangent = get_to_tangent_matrix(triangle, bary_uv); + const float3 normal = sample_normal_on_subdiv_ccg(subdiv_ccg_, triangle.grid_index, grid_uv); + return math::normalize(to_tangent * normal) * 0.5f + float3(0.5f, 0.5f, 0.5f); + } + + void write_pixel(const RasterizeTile &tile, + const int2 &coord, + const float3 &value) const override + { + write_pixel_to_image_buffer(*tile.ibuf, coord, value); + } + + private: + float3x3 get_to_tangent_matrix(const RasterizeTriangle &triangle, const float2 &bary_uv) const + { + if (!triangle.has_uv_tangents) { + return float3x3::identity(); + } + + const float u = bary_uv.x; + const float v = bary_uv.y; + const float w = 1 - u - v; + + const float3 &no0 = triangle.normals[0]; + const float3 &no1 = triangle.normals[1]; + const float3 &no2 = triangle.normals[2]; + + const float4 &tang0 = triangle.uv_tangents[0]; + const float4 &tang1 = triangle.uv_tangents[1]; + const float4 &tang2 = triangle.uv_tangents[2]; + + /* The sign is the same at all face vertices for any non-degenerate face. + * Just in case we clamp the interpolated value though. */ + const float sign = (tang0.w * u + tang1.w * v + tang2.w * w) < 0 ? (-1.0f) : 1.0f; + + /* This sequence of math is designed specifically as is with great care to be compatible with + * our shader. Please don't change without good reason. */ + float3x3 from_tang; + from_tang[0] = tang0.xyz() * u + tang1.xyz() * v + tang2.xyz() * w; + from_tang[2] = no0.xyz() * u + no1.xyz() * v + no2.xyz() * w; + + from_tang[1] = sign * math::cross(from_tang[2], from_tang[0]); /* `B = sign * cross(N, T)` */ + + return math::invert(from_tang); + } +}; + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Image initialization + * \{ */ + +static void initialize_images(MultiresBakeRender &bake) { bake.images.clear(); @@ -1124,125 +952,661 @@ static void count_images(MultiresBakeRender &bake) } } -static void bake_images(MultiresBakeRender &bake, MultiresBakeResult &result) +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Bake to base (non-subdivided) mesh + * \{ */ + +static std::unique_ptr create_baker(const MultiresBakeRender &bake, + const Mesh &bake_level_mesh, + const SubdivCCG &subdiv_ccg, + const ImBuf &ibuf, + ExtraBuffers &extra_buffers) { - /* construct bake result */ - result.height_min = FLT_MAX; - result.height_max = -FLT_MAX; + switch (bake.mode) { + case RE_BAKE_NORMALS: + return std::make_unique(subdiv_ccg); + case RE_BAKE_DISPLACEMENT: + return std::make_unique( + bake, bake_level_mesh, subdiv_ccg, ibuf, extra_buffers); + case RE_BAKE_VECTOR_DISPLACEMENT: + return std::make_unique(bake, bake_level_mesh, subdiv_ccg); + } + BLI_assert_unreachable(); + return nullptr; +} - for (Image *image : bake.images) { - LISTBASE_FOREACH (ImageTile *, tile, &image->tiles) { - ImageUser iuser; - BKE_imageuser_default(&iuser); - iuser.tile = tile->tile_number; +static void rasterize_base_face(const MultiresBaker &baker, + const RasterizeTile &tile, + const MeshArrays &mesh_arrays, + const Span uv_tangents, + const int face_index, + RasterizeResult &result) +{ + const IndexRange &face = mesh_arrays.faces[face_index]; + const Span face_verts = mesh_arrays.corner_verts.slice(face); - ImBuf *ibuf = BKE_image_acquire_ibuf(image, &iuser, nullptr); + RasterizeQuad quad; - if (ibuf->x > 0 && ibuf->y > 0) { - BakeImBufuserData *userdata = MEM_callocN("MultiresBake userdata"); - userdata->mask_buffer = MEM_calloc_arrayN(size_t(ibuf->y) * size_t(ibuf->x), - "MultiresBake imbuf mask"); - ibuf->userdata = userdata; + /* - Grid coordinate (0, 0): face center. + * - Grid axis U points from the face center to the middle of the edge connecting corner to + * next_corner. + * - Grid axis V points from the face center to the middle of the edge connecting prev_corner to + * corner. */ + quad.grid_uvs[0] = float2(0.0f, 0.0f); + quad.grid_uvs[1] = float2(1.0f, 0.0f); + quad.grid_uvs[2] = float2(1.0f, 1.0f); + quad.grid_uvs[3] = float2(0.0f, 1.0f); - switch (bake.mode) { - case RE_BAKE_NORMALS: - do_multires_bake(bake, - image, - tile, - ibuf, - true, - apply_tangmat_callback, - init_normal_data, - free_normal_data, - result); - break; - case RE_BAKE_DISPLACEMENT: - do_multires_bake(bake, - image, - tile, - ibuf, - false, - apply_heights_callback, - init_heights_data, - free_heights_data, - result); - break; - } - } + quad.tex_uvs[0] = face_center_tex_uv_calc(mesh_arrays, face_index); + quad.positions[0] = bke::mesh::face_center_calc(mesh_arrays.vert_positions, face_verts); - BKE_image_release_ibuf(image, ibuf, nullptr); + /* TODO(sergey): Support corner normals. */ + + quad.is_flat = mesh_arrays.sharp_faces[face_index]; + if (quad.is_flat) { + quad.normals[0] = mesh_arrays.face_normals[face_index]; + } + else { + quad.normals[0] = face_center_smooth_normal_calc(mesh_arrays, face_index); + } + + quad.has_uv_tangents = !uv_tangents.is_empty(); + if (quad.has_uv_tangents) { + quad.uv_tangents[0] = face_center_uv_tangent_calc(mesh_arrays, uv_tangents, face_index); + } + + /* The exact values do not really matter here, these fields should not be used when baking to + * the base mesh. Assign some values that will make it easier to spot that their values are not + * valid if anyone accesses them by mistake. */ + quad.bake_level_quad_index = -1; + quad.bake_level_quad_uvs[0] = float2(0.0f, 0.0f); + quad.bake_level_quad_uvs[1] = float2(0.0f, 0.0f); + quad.bake_level_quad_uvs[2] = float2(0.0f, 0.0f); + quad.bake_level_quad_uvs[3] = float2(0.0f, 0.0f); + + for (const int corner : face) { + const int prev_corner = bke::mesh::face_corner_prev(face, corner); + const int next_corner = bke::mesh::face_corner_next(face, corner); + + const float3 &position = mesh_arrays.vert_positions[mesh_arrays.corner_verts[corner]]; + const float3 &next_position = + mesh_arrays.vert_positions[mesh_arrays.corner_verts[next_corner]]; + const float3 &prev_position = + mesh_arrays.vert_positions[mesh_arrays.corner_verts[prev_corner]]; + + quad.grid_index = corner; + + quad.tex_uvs[1] = (mesh_arrays.uv_map[corner] + mesh_arrays.uv_map[next_corner]) * 0.5f; + quad.tex_uvs[2] = mesh_arrays.uv_map[corner] - tile.uv_offset; + quad.tex_uvs[3] = (mesh_arrays.uv_map[prev_corner] + mesh_arrays.uv_map[corner]) * 0.5f; + + quad.positions[1] = (position + next_position) * 0.5f; + quad.positions[2] = position; + quad.positions[3] = (prev_position + position) * 0.5f; + + if (quad.is_flat) { + quad.normals[1] = quad.normals[0]; + quad.normals[2] = quad.normals[0]; + quad.normals[3] = quad.normals[0]; + } + else { + const float3 &normal = mesh_arrays.vert_normals[mesh_arrays.corner_verts[corner]]; + const float3 &next_normal = mesh_arrays.vert_normals[mesh_arrays.corner_verts[next_corner]]; + const float3 &prev_normal = mesh_arrays.vert_normals[mesh_arrays.corner_verts[prev_corner]]; + + /* NOTE: No normalization here: do it after interpolation at the baking point. + * + * This preserves linearity of operation. If normalization is done here interpolation will go + * wrong. */ + quad.normals[1] = (normal + next_normal) * 0.5f; + quad.normals[2] = normal; + quad.normals[3] = (prev_normal + normal) * 0.5f; } - image->id.tag |= ID_TAG_DOIT; + if (quad.has_uv_tangents) { + const float4 &tangent = uv_tangents[corner]; + const float4 &next_tangent = uv_tangents[next_corner]; + const float4 &prev_tangent = uv_tangents[prev_corner]; + + quad.uv_tangents[1] = (tangent + next_tangent) * 0.5f; + quad.uv_tangents[2] = tangent; + quad.uv_tangents[3] = (prev_tangent + tangent) * 0.5f; + } + + rasterize_quad(baker, tile, quad, result); } } -static void finish_images(MultiresBakeRender &bake, MultiresBakeResult &result) +static void bake_single_image_to_base_mesh(MultiresBakeRender &bake, + const Mesh &bake_level_mesh, + const SubdivCCG &subdiv_ccg, + Image &image, + ImageTile &image_tile, + ImBuf &ibuf, + ExtraBuffers &extra_buffers, + MultiresBakeResult &result) { - const bool use_displacement_buffer = bake.mode == RE_BAKE_DISPLACEMENT; + std::unique_ptr baker = create_baker( + bake, bake_level_mesh, subdiv_ccg, ibuf, extra_buffers); + if (!baker) { + return; + } - for (Image *image : bake.images) { - LISTBASE_FOREACH (ImageTile *, tile, &image->tiles) { - ImageUser iuser; - BKE_imageuser_default(&iuser); - iuser.tile = tile->tile_number; + MeshArrays mesh_arrays(bake_level_mesh); + Array uv_tangents; + if (need_tangent(bake)) { + uv_tangents = calc_uv_tangents(mesh_arrays); + } - ImBuf *ibuf = BKE_image_acquire_ibuf(image, &iuser, nullptr); - BakeImBufuserData *userdata = (BakeImBufuserData *)ibuf->userdata; + RasterizeTile tile; + tile.ibuf = &ibuf; + tile.extra_buffers = &extra_buffers; + tile.uv_offset = get_tile_uv(image, image_tile); - if (ibuf->x <= 0 || ibuf->y <= 0) { + SpinLock spin_lock; + BLI_spin_init(&spin_lock); + std::atomic num_baked_faces = 0; + threading::parallel_for(mesh_arrays.faces.index_range(), 1, [&](const IndexRange range) { + for (const int64_t face_index : range) { + if (multiresbake_test_break(bake)) { + return; + } + + /* Check whether the face is to be baked into the current image. */ + const int mat_nr = mesh_arrays.material_indices[face_index]; + const Image *face_image = mat_nr < bake.ob_image.size() ? bake.ob_image[mat_nr] : nullptr; + if (face_image != &image) { continue; } - if (use_displacement_buffer) { - bake_ibuf_normalize_displacement(ibuf, - userdata->displacement_buffer, - userdata->mask_buffer, - result.height_min, - result.height_max); + RasterizeResult rasterize_result; + rasterize_base_face(*baker, tile, mesh_arrays, uv_tangents, face_index, rasterize_result); + + ++num_baked_faces; + BLI_spin_lock(&spin_lock); + result.height_min = std::min(result.height_min, rasterize_result.height_min); + result.height_max = std::max(result.height_max, rasterize_result.height_max); + if (bake.do_update) { + *bake.do_update = true; + } + if (bake.progress) { + *bake.progress = (float(bake.num_baked_objects) + + float(num_baked_faces) / mesh_arrays.faces.size()) / + bake.num_total_objects; + } + BLI_spin_unlock(&spin_lock); + } + }); + BLI_spin_end(&spin_lock); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Bake to subdivided mesh (base mesh with some subdivision levels) + * \{ */ + +struct GridCoord { + int grid_index; + float2 uv; +}; + +struct SubdividedCornerGridCoordData { + MeshArrays coarse_mesh_arrays; + + Array corner_grid_coords; +}; + +static Array get_subdivided_corner_grid_coords(MultiresBakeRender &bake, + const SubdivCCG &subdiv_ccg) +{ + subdiv::ToMeshSettings mesh_settings; + mesh_settings.resolution = (1 << bake.multires_modifier->lvl) + 1; + + SubdividedCornerGridCoordData data; + data.coarse_mesh_arrays = MeshArrays(*bake.base_mesh); + + subdiv::ForeachContext foreach_context; + foreach_context.user_data = &data; + + foreach_context.topology_info = [](const subdiv::ForeachContext *context, + const int /*num_vertices*/, + const int /*num_edges*/, + const int num_corners, + const int /*num_faces*/, + const int * /*subdiv_face_offset*/) -> bool { + SubdividedCornerGridCoordData *data = static_cast( + context->user_data); + data->corner_grid_coords.reinitialize(num_corners); + return true; + }; + + foreach_context.loop = [](const subdiv::ForeachContext *context, + void * /*tls*/, + const int /*ptex_face_index*/, + const float u, + const float v, + const int /*coarse_corner_index*/, + const int coarse_face_index, + const int coarse_corner, + const int subdiv_corner_index, + const int /*subdiv_vertex_index*/, + const int /*subdiv_edge_index*/) { + SubdividedCornerGridCoordData *data = static_cast( + context->user_data); + + const float2 ptex_uv(u, v); + const IndexRange coarse_face = data->coarse_mesh_arrays.faces[coarse_face_index]; + + GridCoord &corner_grid_coord = data->corner_grid_coords[subdiv_corner_index]; + corner_grid_coord.grid_index = coarse_face.start() + coarse_corner; + + if (coarse_face.size() == 4) { + corner_grid_coord.uv = subdiv::ptex_face_uv_to_grid_uv( + subdiv::rotate_quad_to_corner(coarse_corner, ptex_uv)); + } + else { + corner_grid_coord.uv = subdiv::ptex_face_uv_to_grid_uv(ptex_uv); + } + }; + + foreach_subdiv_geometry(subdiv_ccg.subdiv, &foreach_context, &mesh_settings, bake.base_mesh); + + return data.corner_grid_coords; +} + +static void rasterize_subdivided_face(const MultiresBaker &baker, + const RasterizeTile &tile, + const MeshArrays &mesh_arrays, + const Span &corner_grid_coords, + const Span uv_tangents, + const int face_index, + RasterizeResult &result) +{ + const IndexRange &face = mesh_arrays.faces[face_index]; + + /* This code operates with mesh with at leats one subdivision level applied. Such mesh only has + * quad faces as per how subdivision works. */ + BLI_assert(face.size() == 4); + + RasterizeQuad quad; + + /* TODO(sergey): Support corner normals. */ + + quad.is_flat = mesh_arrays.sharp_faces[face_index]; + quad.has_uv_tangents = !uv_tangents.is_empty(); + quad.grid_index = corner_grid_coords[face.start()].grid_index; + + for (int i = 0; i < 4; ++i) { + const int corner = face[i]; + const int vertex = mesh_arrays.corner_verts[corner]; + + BLI_assert(corner_grid_coords[corner].grid_index == quad.grid_index); + quad.grid_uvs[i] = corner_grid_coords[corner].uv; + + quad.tex_uvs[i] = mesh_arrays.uv_map[corner]; + quad.positions[i] = mesh_arrays.vert_positions[vertex]; + if (!quad.is_flat) { + quad.normals[i] = mesh_arrays.vert_normals[vertex]; + } + + if (quad.has_uv_tangents) { + quad.uv_tangents[i] = uv_tangents[corner]; + } + } + + if (quad.is_flat) { + quad.normals[0] = mesh_arrays.face_normals[face_index]; + quad.normals[1] = quad.normals[0]; + quad.normals[2] = quad.normals[0]; + quad.normals[3] = quad.normals[0]; + } + + /* Fill in bake level face information. + * The face index is known explicitly. The UV coordinates are such that first face corner is + * (0, 0), next corner is (1, 0), and previous corner is (0, 1). */ + quad.bake_level_quad_index = face_index; + quad.bake_level_quad_uvs[0] = float2(0.0f, 0.0f); + quad.bake_level_quad_uvs[1] = float2(1.0f, 0.0f); + quad.bake_level_quad_uvs[2] = float2(1.0f, 1.0f); + quad.bake_level_quad_uvs[3] = float2(0.0f, 1.0f); + + rasterize_quad(baker, tile, quad, result); +} + +static void bake_single_image_to_subdivided_mesh(MultiresBakeRender &bake, + const Mesh &bake_level_mesh, + const SubdivCCG &subdiv_ccg, + Image &image, + ImageTile &image_tile, + ImBuf &ibuf, + ExtraBuffers &extra_buffers, + MultiresBakeResult &result) +{ + std::unique_ptr baker = create_baker( + bake, bake_level_mesh, subdiv_ccg, ibuf, extra_buffers); + if (!baker) { + return; + } + + MeshArrays mesh_arrays(bake_level_mesh); + Array uv_tangents; + if (need_tangent(bake)) { + uv_tangents = calc_uv_tangents(mesh_arrays); + } + + RasterizeTile tile; + tile.ibuf = &ibuf; + tile.extra_buffers = &extra_buffers; + tile.uv_offset = get_tile_uv(image, image_tile); + + const Array corner_grid_coords = get_subdivided_corner_grid_coords(bake, subdiv_ccg); + + SpinLock spin_lock; + BLI_spin_init(&spin_lock); + std::atomic num_baked_faces = 0; + threading::parallel_for(mesh_arrays.faces.index_range(), 1, [&](const IndexRange range) { + for (const int64_t face_index : range) { + if (multiresbake_test_break(bake)) { + return; } - float uv_offset[2]; - BKE_image_get_tile_uv(image, tile->tile_number, uv_offset); - - bake_ibuf_filter(ibuf, - userdata->mask_buffer, - bake.bake_margin, - bake.bake_margin_type, - bake.lores_dm, - uv_offset); - - ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; - BKE_image_mark_dirty(image, ibuf); - - if (ibuf->float_buffer.data) { - ibuf->userflags |= IB_RECT_INVALID; + /* Check whether the face is to be baked into the current image. */ + const int mat_nr = mesh_arrays.material_indices[face_index]; + const Image *face_image = mat_nr < bake.ob_image.size() ? bake.ob_image[mat_nr] : nullptr; + if (face_image != &image) { + continue; } - if (ibuf->userdata) { - if (userdata->displacement_buffer) { - MEM_freeN(userdata->displacement_buffer); - } + RasterizeResult rasterize_result; + rasterize_subdivided_face(*baker, + tile, + mesh_arrays, + corner_grid_coords, + uv_tangents, + face_index, + rasterize_result); - MEM_freeN(userdata->mask_buffer); - MEM_freeN(userdata); - ibuf->userdata = nullptr; + ++num_baked_faces; + BLI_spin_lock(&spin_lock); + result.height_min = std::min(result.height_min, rasterize_result.height_min); + result.height_max = std::max(result.height_max, rasterize_result.height_max); + if (bake.do_update) { + *bake.do_update = true; } + if (bake.progress) { + *bake.progress = (float(bake.num_baked_objects) + + float(num_baked_faces) / mesh_arrays.faces.size()) / + bake.num_total_objects; + } + BLI_spin_unlock(&spin_lock); + } + }); + BLI_spin_end(&spin_lock); +} - BKE_image_release_ibuf(image, ibuf, nullptr); - DEG_id_tag_update(&image->id, 0); +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Image baking entry point + * \{ */ + +static void bake_single_image(MultiresBakeRender &bake, + const Mesh &bake_level_mesh, + const SubdivCCG &subdiv_ccg, + Image &image, + ImageTile &image_tile, + ImBuf &ibuf, + ExtraBuffers &extra_buffers, + MultiresBakeResult &result) +{ + if (bake.multires_modifier->lvl == 0) { + bake_single_image_to_base_mesh( + bake, bake_level_mesh, subdiv_ccg, image, image_tile, ibuf, extra_buffers, result); + return; + } + + bake_single_image_to_subdivided_mesh( + bake, bake_level_mesh, subdiv_ccg, image, image_tile, ibuf, extra_buffers, result); +} + +static void bake_images(MultiresBakeRender &bake, + const Mesh &bake_level_mesh, + const SubdivCCG &subdiv_ccg, + MultiresBakeResult &result) +{ + for (Image *image : bake.images) { + LISTBASE_FOREACH (ImageTile *, image_tile, &image->tiles) { + ImageUser iuser; + BKE_imageuser_default(&iuser); + iuser.tile = image_tile->tile_number; + + ImBuf *ibuf = BKE_image_acquire_ibuf(image, &iuser, nullptr); + if (ibuf && ibuf->x > 0 && ibuf->y > 0) { + result.baked_ibufs.append({}); + + BakedImBuf &baked_ibuf = result.baked_ibufs.last(); + baked_ibuf.image = image; + baked_ibuf.ibuf = ibuf; + baked_ibuf.uv_offset = get_tile_uv(*image, *image_tile); + + ExtraBuffers &extra_buffers = baked_ibuf.extra_buffers; + extra_buffers.mask_buffer.reinitialize(int64_t(ibuf->y) * ibuf->x); + extra_buffers.mask_buffer.fill(FILTER_MASK_NULL); + + bake_single_image( + bake, bake_level_mesh, subdiv_ccg, *image, *image_tile, *ibuf, extra_buffers, result); + } } } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Image postprocessing + * \{ */ + +static void bake_ibuf_normalize_displacement(ImBuf &ibuf, + const MutableSpan displacement, + const Span mask, + const float displacement_min, + const float displacement_max) +{ + const float *current_displacement = displacement.data(); + const char *current_mask = mask.data(); + const float max_distance = math::max(math::abs(displacement_min), math::abs(displacement_max)); + + if (max_distance <= 1e-5f) { + const float col[4] = {0.5f, 0.5f, 0.5f, 1.0f}; + IMB_rectfill(&ibuf, col); + return; + } + + /* TODO(sergey): Look into multi-threading this loop. */ + const size_t ibuf_pixel_count = IMB_get_pixel_count(&ibuf); + for (size_t i = 0; i < ibuf_pixel_count; i++) { + if (*current_mask == FILTER_MASK_USED) { + const float normalized_displacement = (*current_displacement + max_distance) / + (max_distance * 2); + + if (ibuf.float_buffer.data) { + /* TODO(sergey): Properly tackle ibuf.channels. */ + BLI_assert(ibuf.channels == 4); + float *fp = ibuf.float_buffer.data + int64_t(i) * 4; + fp[0] = fp[1] = fp[2] = normalized_displacement; + fp[3] = 1.0f; + } + + if (ibuf.byte_buffer.data) { + uchar *cp = ibuf.byte_buffer.data + int64_t(i) * 4; + cp[0] = cp[1] = cp[2] = unit_float_to_uchar_clamp(normalized_displacement); + cp[3] = 255; + } + } + + current_displacement++; + current_mask++; + } +} + +static void bake_ibuf_filter(ImBuf &ibuf, + const MutableSpan mask, + const Mesh &bake_level_mesh, + const int margin, + const eBakeMarginType margin_type, + const float2 uv_offset) +{ + /* NOTE: Must check before filtering. */ + const bool is_new_alpha = (ibuf.planes != R_IMF_PLANES_RGBA) && BKE_imbuf_alpha_test(&ibuf); + + if (margin) { + switch (margin_type) { + case R_BAKE_ADJACENT_FACES: { + const char *active_uv_map = CustomData_get_active_layer_name(&bake_level_mesh.corner_data, + CD_PROP_FLOAT2); + RE_generate_texturemargin_adjacentfaces( + &ibuf, mask.data(), margin, &bake_level_mesh, active_uv_map, uv_offset); + break; + } + default: + /* Fall through. */ + case R_BAKE_EXTEND: + IMB_filter_extend(&ibuf, mask.data(), margin); + break; + } + } + + /* If the bake results in new alpha then change the image setting. */ + if (is_new_alpha) { + ibuf.planes = R_IMF_PLANES_RGBA; + } + else { + if (margin && ibuf.planes != R_IMF_PLANES_RGBA) { + /* Clear alpha added by filtering. */ + IMB_rectfill_alpha(&ibuf, 1.0f); + } + } +} + +static void finish_images(MultiresBakeRender &bake, + const Mesh &bake_level_mesh, + MultiresBakeResult &result) +{ + const bool use_displacement_buffer = bake.mode == RE_BAKE_DISPLACEMENT; + + for (BakedImBuf &baked_ibuf : result.baked_ibufs) { + Image *image = baked_ibuf.image; + ImBuf *ibuf = baked_ibuf.ibuf; + + if (use_displacement_buffer) { + bake_ibuf_normalize_displacement(*ibuf, + baked_ibuf.extra_buffers.displacement_buffer, + baked_ibuf.extra_buffers.mask_buffer, + result.height_min, + result.height_max); + } + + bake_ibuf_filter(*ibuf, + baked_ibuf.extra_buffers.mask_buffer, + bake_level_mesh, + bake.bake_margin, + bake.bake_margin_type, + baked_ibuf.uv_offset); + + ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; + BKE_image_mark_dirty(image, ibuf); + + if (ibuf->float_buffer.data) { + ibuf->userflags |= IB_RECT_INVALID; + } + + BKE_image_release_ibuf(image, ibuf, nullptr); + DEG_id_tag_update(&image->id, 0); + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Helpers to create mesh and CCG at requested levels + * \{ */ + +static subdiv::Subdiv *create_subdiv(const Mesh &mesh, + const MultiresModifierData &multires_modifier) +{ + subdiv::Settings subdiv_settings; + BKE_multires_subdiv_settings_init(&subdiv_settings, &multires_modifier); + subdiv::Subdiv *subdiv = subdiv::update_from_mesh(nullptr, &subdiv_settings, &mesh); + subdiv::displacement_attach_from_multires(subdiv, &mesh, &multires_modifier); + + /* Initialization evaluation of the limit surface and the displacement. */ + if (!subdiv::eval_begin_from_mesh(subdiv, &mesh, subdiv::SUBDIV_EVALUATOR_TYPE_CPU)) { + subdiv::free(subdiv); + return nullptr; + } + subdiv::eval_init_displacement(subdiv); + + return subdiv; +} + +static std::unique_ptr create_subdiv_ccg(const Mesh &mesh, + const MultiresModifierData &multires_modifier) +{ + subdiv::Subdiv *subdiv = create_subdiv(mesh, multires_modifier); + if (!subdiv) { + return nullptr; + } + + SubdivToCCGSettings settings; + settings.resolution = (1 << multires_modifier.totlvl) + 1; + settings.need_normal = true; + settings.need_mask = false; + + return BKE_subdiv_to_ccg(*subdiv, settings, mesh); +} + +static Mesh *create_bake_level_mesh(const Mesh &base_mesh, + const MultiresModifierData &multires_modifier) +{ + subdiv::Subdiv *subdiv = create_subdiv(base_mesh, multires_modifier); + if (!subdiv) { + return nullptr; + } + + subdiv::ToMeshSettings mesh_settings; + mesh_settings.resolution = (1 << multires_modifier.lvl) + 1; + subdiv::displacement_attach_from_multires(subdiv, &base_mesh, &multires_modifier); + Mesh *result = subdiv::subdiv_to_mesh(subdiv, &mesh_settings, &base_mesh); + subdiv::free(subdiv); + return result; +} + +/** \} */ + } // namespace } // namespace blender::render -void RE_multires_bake_images(MultiresBakeRender *bkr) +void RE_multires_bake_images(MultiresBakeRender &bake) { - blender::render::MultiresBakeResult result; + using namespace blender::render; - blender::render::count_images(*bkr); - blender::render::bake_images(*bkr, result); - blender::render::finish_images(*bkr, result); + std::unique_ptr subdiv_ccg = create_subdiv_ccg(*bake.base_mesh, + *bake.multires_modifier); + + Mesh *bake_level_mesh = bake.base_mesh; + if (bake.multires_modifier->lvl != 0) { + bake_level_mesh = create_bake_level_mesh(*bake.base_mesh, *bake.multires_modifier); + } + + MultiresBakeResult result; + initialize_images(bake); + bake_images(bake, *bake_level_mesh, *subdiv_ccg, result); + finish_images(bake, *bake_level_mesh, result); + + if (bake_level_mesh != bake.base_mesh) { + BKE_id_free(nullptr, bake_level_mesh); + } } diff --git a/source/blender/render/intern/texture_margin.cc b/source/blender/render/intern/texture_margin.cc index 385860c4b65..150c455f8a2 100644 --- a/source/blender/render/intern/texture_margin.cc +++ b/source/blender/render/intern/texture_margin.cc @@ -15,7 +15,6 @@ #include "BKE_attribute.hh" #include "BKE_customdata.hh" #include "BKE_mesh.hh" -#include "BKE_mesh_legacy_derived_mesh.hh" #include "BKE_mesh_mapping.hh" #include "IMB_imbuf.hh" @@ -595,22 +594,3 @@ void RE_generate_texturemargin_adjacentfaces(ImBuf *ibuf, uv_map, uv_offset); } - -void RE_generate_texturemargin_adjacentfaces_dm( - ImBuf *ibuf, char *mask, const int margin, DerivedMesh *dm, const float uv_offset[2]) -{ - const blender::float2 *mloopuv = static_cast( - dm->getLoopDataArray(dm, CD_PROP_FLOAT2)); - - blender::render::texturemargin::generate_margin( - ibuf, - mask, - margin, - {reinterpret_cast(dm->getVertArray(dm)), dm->getNumVerts(dm)}, - dm->getNumEdges(dm), - blender::Span(dm->getPolyArray(dm), dm->getNumPolys(dm) + 1), - {dm->getCornerEdgeArray(dm), dm->getNumLoops(dm)}, - {dm->getCornerVertArray(dm), dm->getNumLoops(dm)}, - {mloopuv, dm->getNumLoops(dm)}, - uv_offset); -} diff --git a/tests/files/render/bake/cycles_renders/bake_from_multires_displacement_use_lowres.png b/tests/files/render/bake/cycles_renders/bake_from_multires_displacement_use_lowres.png index 968062a7354..91ec6ab91f7 100644 --- a/tests/files/render/bake/cycles_renders/bake_from_multires_displacement_use_lowres.png +++ b/tests/files/render/bake/cycles_renders/bake_from_multires_displacement_use_lowres.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4bb5358f1a4f0fa23c87d92ff4dbe033b2f22802470366e4813820c950c069a7 -size 27025 +oid sha256:e22f136049a60f0f7dee05c6f9c3dfe45940092c80098f88d035847b8dc44ab5 +size 25387 diff --git a/tests/files/render/bake/cycles_renders/bake_from_multires_normal.png b/tests/files/render/bake/cycles_renders/bake_from_multires_normal.png index 6ca11a48a9d..24aba049228 100644 --- a/tests/files/render/bake/cycles_renders/bake_from_multires_normal.png +++ b/tests/files/render/bake/cycles_renders/bake_from_multires_normal.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e5f36846bcdbcb8229a7cf969d2d5dff588db6b600c44077a43904dec5b7dd29 -size 75071 +oid sha256:7a6fa649aa71fad32771f56b9e818a8a42c47b3838cccd37c733dc2ead174fca +size 74419