diff --git a/source/blender/blenkernel/BKE_uv_islands.hh b/source/blender/blenkernel/BKE_uv_islands.hh deleted file mode 100644 index 406ecf39b71..00000000000 --- a/source/blender/blenkernel/BKE_uv_islands.hh +++ /dev/null @@ -1,746 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -#pragma once - -#include -#include - -#include "BLI_array.hh" -#include "BLI_edgehash.h" -#include "BLI_float3x3.hh" -#include "BLI_map.hh" -#include "BLI_math.h" -#include "BLI_math_vec_types.hh" -#include "BLI_rect.h" -#include "BLI_vector.hh" -#include "BLI_vector_list.hh" - -#include "DNA_meshdata_types.h" - -namespace blender::bke::uv_islands { - -struct MeshEdge; -struct MeshPrimitive; -struct UVBorder; -struct UVEdge; -struct UVIslands; -struct UVIslandsMask; -struct UVPrimitive; -struct UVPrimitiveEdge; -struct UVVertex; - -struct MeshVertex { - int64_t v; - Vector edges; -}; - -struct MeshUVVert { - MeshVertex *vertex; - float2 uv; - int64_t loop; -}; - -struct MeshEdge { - MeshVertex *vert1; - MeshVertex *vert2; - Vector primitives; -}; - -/** Represents a triangle in 3d space (MLoopTri) */ -struct MeshPrimitive { - int64_t index; - int64_t poly; - Vector edges; - Vector vertices; - - /** - * UV island this primitive belongs to. This is used to speed up the initial uv island - * extraction, but should not be used when extending uv islands. - */ - int64_t uv_island_id; - - MeshUVVert *get_other_uv_vertex(const MeshVertex *v1, const MeshVertex *v2) - { - BLI_assert(vertices[0].vertex == v1 || vertices[1].vertex == v1 || vertices[2].vertex == v1); - BLI_assert(vertices[0].vertex == v2 || vertices[1].vertex == v2 || vertices[2].vertex == v2); - for (MeshUVVert &uv_vertex : vertices) { - if (uv_vertex.vertex != v1 && uv_vertex.vertex != v2) { - return &uv_vertex; - } - } - return nullptr; - } - - rctf uv_bounds() const; - - bool has_shared_uv_edge(const MeshPrimitive *other) const - { - int shared_uv_verts = 0; - for (const MeshUVVert &vert : vertices) { - for (const MeshUVVert &other_vert : other->vertices) { - if (vert.uv == other_vert.uv) { - shared_uv_verts += 1; - } - } - } - return shared_uv_verts >= 2; - } -}; - -/** - * MeshData contains input geometry data converted in a list of primitives, edges and vertices for - * quick access for both local space and uv space. - */ -struct MeshData { - public: - const MLoopTri *looptri; - const int64_t looptri_len; - const int64_t vert_len; - const MLoop *mloop; - const MLoopUV *mloopuv; - - public: - Vector primitives; - Vector edges; - Vector vertices; - /** Total number of uv islands detected. */ - int64_t uv_island_len; - - explicit MeshData(const MLoopTri *looptri, - const int64_t looptri_len, - const int64_t vert_len, - const MLoop *mloop, - const MLoopUV *mloopuv) - : looptri(looptri), - looptri_len(looptri_len), - vert_len(vert_len), - mloop(mloop), - mloopuv(mloopuv) - { - init_vertices(); - init_primitives(); - init_edges(); - init_primitive_uv_island_ids(); - } - - void init_vertices() - { - vertices.reserve(vert_len); - for (int64_t i = 0; i < vert_len; i++) { - MeshVertex vert; - vert.v = i; - vertices.append(vert); - } - } - - void init_primitives() - { - primitives.reserve(looptri_len); - for (int64_t i = 0; i < looptri_len; i++) { - const MLoopTri &tri = looptri[i]; - MeshPrimitive primitive; - primitive.index = i; - primitive.poly = tri.poly; - - for (int j = 0; j < 3; j++) { - MeshUVVert uv_vert; - uv_vert.loop = tri.tri[j]; - uv_vert.vertex = &vertices[mloop[uv_vert.loop].v]; - uv_vert.uv = mloopuv[uv_vert.loop].uv; - primitive.vertices.append(uv_vert); - } - primitives.append(primitive); - } - } - - void init_edges() - { - edges.reserve(looptri_len * 2); - EdgeHash *eh = BLI_edgehash_new_ex(__func__, looptri_len * 3); - for (int64_t i = 0; i < looptri_len; i++) { - const MLoopTri &tri = looptri[i]; - MeshPrimitive &primitive = primitives[i]; - for (int j = 0; j < 3; j++) { - int v1 = mloop[tri.tri[j]].v; - int v2 = mloop[tri.tri[(j + 1) % 3]].v; - /* TODO: Use lookup_ptr to be able to store edge 0. */ - void *v = BLI_edgehash_lookup(eh, v1, v2); - int64_t edge_index; - if (v == nullptr) { - edge_index = edges.size(); - BLI_edgehash_insert(eh, v1, v2, POINTER_FROM_INT(edge_index + 1)); - MeshEdge edge; - edge.vert1 = &vertices[v1]; - edge.vert2 = &vertices[v2]; - edges.append(edge); - MeshEdge *edge_ptr = &edges.last(); - vertices[v1].edges.append(edge_ptr); - vertices[v2].edges.append(edge_ptr); - } - else { - edge_index = POINTER_AS_INT(v) - 1; - } - - MeshEdge *edge = &edges[edge_index]; - edge->primitives.append(&primitive); - primitive.edges.append(edge); - } - } - BLI_edgehash_free(eh, nullptr); - } - - static const int64_t INVALID_UV_ISLAND_ID = -1; - /** - * NOTE: doesn't support weird topology where unconnected mesh primitives share the same uv - * island. For a accurate implementation we should use implement an uv_prim_lookup. - */ - static void extract_uv_neighbors(Vector &prims_to_add, MeshPrimitive *primitive) - { - for (MeshEdge *edge : primitive->edges) { - for (MeshPrimitive *other_primitive : edge->primitives) { - if (primitive == other_primitive) { - continue; - } - if (other_primitive->uv_island_id != MeshData::INVALID_UV_ISLAND_ID) { - continue; - } - - if (primitive->has_shared_uv_edge(other_primitive)) { - prims_to_add.append(other_primitive); - } - } - } - } - - void init_primitive_uv_island_ids() - { - for (MeshPrimitive &primitive : primitives) { - primitive.uv_island_id = INVALID_UV_ISLAND_ID; - } - - int64_t uv_island_id = 0; - Vector prims_to_add; - for (MeshPrimitive &primitive : primitives) { - /* Early exit when uv island id is already extracted during uv neighbor extractions. */ - if (primitive.uv_island_id != INVALID_UV_ISLAND_ID) { - continue; - } - - prims_to_add.append(&primitive); - while (!prims_to_add.is_empty()) { - MeshPrimitive *primitive = prims_to_add.pop_last(); - primitive->uv_island_id = uv_island_id; - extract_uv_neighbors(prims_to_add, primitive); - } - uv_island_id++; - } - uv_island_len = uv_island_id; - } -}; - -struct UVVertex { - MeshVertex *vertex; - /* Position in uv space. */ - float2 uv; - - /* uv edges that share this UVVertex. */ - Vector uv_edges; - - struct { - bool is_border : 1; - bool is_extended : 1; - } flags; - - explicit UVVertex() - { - flags.is_border = false; - flags.is_extended = false; - } - - explicit UVVertex(const MeshUVVert &vert) : vertex(vert.vertex), uv(vert.uv) - { - flags.is_border = false; - flags.is_extended = false; - } -}; - -struct UVEdge { - std::array vertices; - Vector uv_primitives; - - bool has_shared_edge(const MeshUVVert &v1, const MeshUVVert &v2) const - { - return (vertices[0]->uv == v1.uv && vertices[1]->uv == v2.uv) || - (vertices[0]->uv == v2.uv && vertices[1]->uv == v1.uv); - } - - bool has_shared_edge(const UVVertex &v1, const UVVertex &v2) const - { - return (vertices[0]->uv == v1.uv && vertices[1]->uv == v2.uv) || - (vertices[0]->uv == v2.uv && vertices[1]->uv == v1.uv); - } - - bool has_shared_edge(const UVEdge &other) const - { - return has_shared_edge(*other.vertices[0], *other.vertices[1]); - } - - bool has_same_vertices(const MeshVertex &vert1, const MeshVertex &vert2) const - { - return (vertices[0]->vertex == &vert1 && vertices[1]->vertex == &vert2) || - (vertices[0]->vertex == &vert2 && vertices[1]->vertex == &vert1); - } - - bool has_same_uv_vertices(const UVEdge &other) const - { - return has_shared_edge(other) && - has_same_vertices(*other.vertices[0]->vertex, *other.vertices[1]->vertex); - ; - } - - bool has_same_vertices(const MeshEdge &edge) const - { - return has_same_vertices(*edge.vert1, *edge.vert2); - } - - bool is_border_edge() const - { - return uv_primitives.size() == 1; - } - - void append_to_uv_vertices() - { - for (UVVertex *vertex : vertices) { - vertex->uv_edges.append_non_duplicates(this); - } - } - - UVVertex *get_other_uv_vertex(const MeshVertex *vertex) - { - if (vertices[0]->vertex == vertex) { - return vertices[1]; - } - return vertices[0]; - } -}; - -struct UVPrimitive { - /** - * Index of the primitive in the original mesh. - */ - MeshPrimitive *primitive; - Vector edges; - - explicit UVPrimitive(MeshPrimitive *primitive) : primitive(primitive) - { - } - - void append_to_uv_edges() - { - for (UVEdge *uv_edge : edges) { - uv_edge->uv_primitives.append_non_duplicates(this); - } - } - void append_to_uv_vertices() - { - for (UVEdge *uv_edge : edges) { - uv_edge->append_to_uv_vertices(); - } - } - - Vector> shared_edges(UVPrimitive &other) - { - Vector> result; - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - if (edges[i]->has_shared_edge(*other.edges[j])) { - result.append(std::pair(edges[i], other.edges[j])); - } - } - } - return result; - } - - bool has_shared_edge(const UVPrimitive &other) const - { - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - if (edges[i]->has_shared_edge(*other.edges[j])) { - return true; - } - } - } - return false; - } - - bool has_shared_edge(const MeshPrimitive &primitive) const - { - for (const UVEdge *uv_edge : edges) { - const MeshUVVert *v1 = &primitive.vertices.last(); - for (int i = 0; i < primitive.vertices.size(); i++) { - const MeshUVVert *v2 = &primitive.vertices[i]; - if (uv_edge->has_shared_edge(*v1, *v2)) { - return true; - } - v1 = v2; - } - } - return false; - } - - /** - * Get the UVVertex in the order that the verts are ordered in the MeshPrimitive. - */ - const UVVertex *get_uv_vertex(const uint8_t mesh_vert_index) const - { - const MeshVertex *mesh_vertex = primitive->vertices[mesh_vert_index].vertex; - for (const UVEdge *uv_edge : edges) { - for (const UVVertex *uv_vert : uv_edge->vertices) { - if (uv_vert->vertex == mesh_vertex) { - return uv_vert; - } - } - } - BLI_assert_unreachable(); - return nullptr; - } - - /** - * Get the UVEdge that share the given uv coordinates. - * Will assert when no UVEdge found. - */ - UVEdge *get_uv_edge(const float2 uv1, const float2 uv2) const - { - for (UVEdge *uv_edge : edges) { - const float2 &e1 = uv_edge->vertices[0]->uv; - const float2 &e2 = uv_edge->vertices[1]->uv; - if ((e1 == uv1 && e2 == uv2) || (e1 == uv2 && e2 == uv1)) { - return uv_edge; - } - } - BLI_assert_unreachable(); - return nullptr; - } - - UVEdge *get_uv_edge(const MeshVertex *v1, const MeshVertex *v2) const - { - for (UVEdge *uv_edge : edges) { - const MeshVertex *e1 = uv_edge->vertices[0]->vertex; - const MeshVertex *e2 = uv_edge->vertices[1]->vertex; - if ((e1 == v1 && e2 == v2) || (e1 == v2 && e2 == v1)) { - return uv_edge; - } - } - BLI_assert_unreachable(); - return nullptr; - } - - const bool contains_uv_vertex(const UVVertex *uv_vertex) const - { - for (UVEdge *edge : edges) { - if (std::find(edge->vertices.begin(), edge->vertices.end(), uv_vertex) != - edge->vertices.end()) { - return true; - } - } - return false; - } - - const UVVertex *get_other_uv_vertex(const UVVertex *v1, const UVVertex *v2) const - { - BLI_assert(contains_uv_vertex(v1)); - BLI_assert(contains_uv_vertex(v2)); - - for (const UVEdge *edge : edges) { - for (const UVVertex *uv_vertex : edge->vertices) { - if (uv_vertex != v1 && uv_vertex != v2) { - return uv_vertex; - } - } - } - BLI_assert_unreachable(); - return nullptr; - } - - UVBorder extract_border() const; -}; - -struct UVBorderEdge { - UVEdge *edge; - bool tag = false; - UVPrimitive *uv_primitive; - /* Should the vertices of the edge be evaluated in reverse order. */ - bool reverse_order = false; - - int64_t index = -1; - int64_t prev_index = -1; - int64_t next_index = -1; - int64_t border_index = -1; - - explicit UVBorderEdge(UVEdge *edge, UVPrimitive *uv_primitive) - : edge(edge), uv_primitive(uv_primitive) - { - } - - UVVertex *get_uv_vertex(int index) - { - int actual_index = reverse_order ? 1 - index : index; - return edge->vertices[actual_index]; - } - - const UVVertex *get_uv_vertex(int index) const - { - int actual_index = reverse_order ? 1 - index : index; - return edge->vertices[actual_index]; - } - - /** - * Get the uv vertex from the primitive that is not part of the edge. - */ - const UVVertex *get_other_uv_vertex() const - { - return uv_primitive->get_other_uv_vertex(edge->vertices[0], edge->vertices[1]); - } - - float length() const - { - return len_v2v2(edge->vertices[0]->uv, edge->vertices[1]->uv); - } -}; - -struct UVBorderCorner { - UVBorderEdge *first; - UVBorderEdge *second; - float angle; - - UVBorderCorner(UVBorderEdge *first, UVBorderEdge *second, float angle) - : first(first), second(second), angle(angle) - { - } - - /** - * Calculate a uv coordinate between the edges of the corner. - * - * 'min_uv_distance' is the minimum distance between the corner and the - * resulting uv coordinate. The distance is in uv space. - */ - float2 uv(float factor, float min_uv_distance); -}; - -struct UVBorder { - /** Ordered list of UV Verts of the border of this island. */ - // TODO: support multiple rings + order (CW, CCW) - Vector edges; - - /** - * Check if the border is counter clock wise from its island. - */ - bool is_ccw() const; - - /** - * Flip the order of the verts, changing the order between CW and CCW. - */ - void flip(); - - /** - * Calculate the outside angle of the given vert. - */ - float outside_angle(const UVBorderEdge &vert) const; - - void update_indexes(uint64_t border_index); - - static std::optional extract_from_edges(Vector &edges); - - /** Remove edge from the border. updates the indexes. */ - void remove(int64_t index) - { - /* Could read the border_index from any border edge as they are consistent. */ - uint64_t border_index = edges[0].border_index; - edges.remove(index); - update_indexes(border_index); - } -}; - -struct UVIsland { - VectorList uv_vertices; - VectorList uv_edges; - VectorList uv_primitives; - /** - * List of borders of this island. There can be multiple borders per island as a border could - * be completely encapsulated by another one. - */ - Vector borders; - - /** - * Key is mesh vert index, Value is list of UVVertices that refer to the mesh vertex with that - * index. Map is used internally to quickly lookup similar UVVertices. - */ - Map> uv_vertex_lookup; - - UVVertex *lookup(const UVVertex &vertex) - { - int64_t vert_index = vertex.vertex->v; - Vector &vertices = uv_vertex_lookup.lookup_or_add_default(vert_index); - for (UVVertex *v : vertices) { - if (v->uv == vertex.uv) { - return v; - } - } - return nullptr; - } - - UVVertex *lookup_or_create(const UVVertex &vertex) - { - UVVertex *found_vertex = lookup(vertex); - if (found_vertex != nullptr) { - return found_vertex; - } - - uv_vertices.append(vertex); - UVVertex *result = &uv_vertices.last(); - result->uv_edges.clear(); - /* v is already a key. Ensured by UVIsland::lookup in this method. */ - uv_vertex_lookup.lookup(vertex.vertex->v).append(result); - return result; - } - - UVEdge *lookup(const UVEdge &edge) - { - UVVertex *found_vertex = lookup(*edge.vertices[0]); - if (found_vertex == nullptr) { - return nullptr; - } - for (UVEdge *e : found_vertex->uv_edges) { - UVVertex *other_vertex = e->get_other_uv_vertex(found_vertex->vertex); - if (other_vertex->vertex == edge.vertices[1]->vertex && - other_vertex->uv == edge.vertices[1]->uv) { - return e; - } - } - return nullptr; - } - - UVEdge *lookup_or_create(const UVEdge &edge) - { - UVEdge *found_edge = lookup(edge); - if (found_edge != nullptr) { - return found_edge; - } - - uv_edges.append(edge); - UVEdge *result = &uv_edges.last(); - result->uv_primitives.clear(); - return result; - } - - /** Initialize the border attribute. */ - void extract_borders(); - /** Iterative extend border to fit the mask. */ - void extend_border(const UVIslandsMask &mask, const short island_index); - - private: - void append(const UVPrimitive &primitive) - { - uv_primitives.append(primitive); - UVPrimitive *new_prim_ptr = &uv_primitives.last(); - for (int i = 0; i < 3; i++) { - UVEdge *other_edge = primitive.edges[i]; - UVEdge uv_edge_template; - uv_edge_template.vertices[0] = lookup_or_create(*other_edge->vertices[0]); - uv_edge_template.vertices[1] = lookup_or_create(*other_edge->vertices[1]); - new_prim_ptr->edges[i] = lookup_or_create(uv_edge_template); - new_prim_ptr->edges[i]->append_to_uv_vertices(); - new_prim_ptr->edges[i]->uv_primitives.append(new_prim_ptr); - } - } - - public: - bool has_shared_edge(const UVPrimitive &primitive) const - { - for (const VectorList::UsedVector &prims : uv_primitives) { - for (const UVPrimitive &prim : prims) { - if (prim.has_shared_edge(primitive)) { - return true; - } - } - } - return false; - } - - bool has_shared_edge(const MeshPrimitive &primitive) const - { - for (const VectorList::UsedVector &primitives : uv_primitives) { - for (const UVPrimitive &prim : primitives) { - if (prim.has_shared_edge(primitive)) { - return true; - } - } - } - return false; - } - - const void extend_border(const UVPrimitive &primitive) - { - for (const VectorList::UsedVector &primitives : uv_primitives) { - for (const UVPrimitive &prim : primitives) { - if (prim.has_shared_edge(primitive)) { - append(primitive); - } - } - } - } -}; - -struct UVIslands { - Vector islands; - - explicit UVIslands(MeshData &mesh_data); - - void extract_borders(); - void extend_borders(const UVIslandsMask &islands_mask); -}; - -/** Mask to find the index of the UVIsland for a given UV coordinate. */ -struct UVIslandsMask { - - /** Mask for each udim tile. */ - struct Tile { - float2 udim_offset; - ushort2 tile_resolution; - ushort2 mask_resolution; - Array mask; - - Tile(float2 udim_offset, ushort2 tile_resolution); - - bool is_masked(const uint16_t island_index, const float2 uv) const; - bool contains(const float2 uv) const; - float get_pixel_size_in_uv_space() const; - }; - - Vector tiles; - - void add_tile(float2 udim_offset, ushort2 resolution); - - /** - * Find a tile containing the given uv coordinate. - */ - const Tile *find_tile(const float2 uv) const; - - /** - * Is the given uv coordinate part of the given island_index mask. - * - * true - part of the island mask. - * false - not part of the island mask. - */ - bool is_masked(const uint16_t island_index, const float2 uv) const; - - /** - * Add the given UVIslands to the mask. Tiles should be added beforehand using the 'add_tile' - * method. - */ - void add(const UVIslands &islands); - - void dilate(int max_iterations); -}; - -} // namespace blender::bke::uv_islands diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 7bd87323ede..d645408c6e9 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -480,7 +480,6 @@ set(SRC BKE_type_conversions.hh BKE_undo_system.h BKE_unit.h - BKE_uv_islands.hh BKE_vfont.h BKE_vfontdata.h BKE_viewer_path.h