Blender V4.3
subdiv_ccg_mask.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2018 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <cmath>
10
11#include "BKE_subdiv_ccg.hh"
12
13#include "DNA_mesh_types.h"
14#include "DNA_meshdata_types.h"
15
16#include "BLI_utildefines.h"
17
18#include "BKE_customdata.hh"
19#include "BKE_subdiv.hh"
20
21#include "MEM_guardedalloc.h"
22
23using namespace blender::bke::subdiv;
24
27 int corner;
28};
29
31 // int grid_size;
34 /* Indexed by ptex face index, contains face/corner which corresponds
35 * to it.
36 *
37 * NOTE: For quad face this is an index of first corner only, since
38 * there we only have one ptex.
39 */
41};
42
44 const int ptex_face_index,
45 const float u,
46 const float v,
47 const GridPaintMask **r_mask_grid,
48 float *grid_u,
49 float *grid_v)
50{
51 GridPaintMaskData *data = static_cast<GridPaintMaskData *>(mask_evaluator->user_data);
52 const PolyCornerIndex *poly_corner = &data->ptex_face_corner[ptex_face_index];
53 const blender::IndexRange face = data->faces[poly_corner->face_index];
54 const int start_grid_index = face.start() + poly_corner->corner;
55 int corner = 0;
56 if (face.size() == 4) {
57 float corner_u, corner_v;
58 corner = rotate_quad_to_corner(u, v, &corner_u, &corner_v);
59 *r_mask_grid = &data->grid_paint_mask[start_grid_index + corner];
60 ptex_face_uv_to_grid_uv(corner_u, corner_v, grid_u, grid_v);
61 }
62 else {
63 *r_mask_grid = &data->grid_paint_mask[start_grid_index];
64 ptex_face_uv_to_grid_uv(u, v, grid_u, grid_v);
65 }
66 return corner;
67}
68
70 const float grid_u,
71 const float grid_v)
72{
73 if (mask_grid->data == nullptr) {
74 return 0;
75 }
76 const int grid_size = grid_size_from_level(mask_grid->level);
77 const int x = roundf(grid_u * (grid_size - 1));
78 const int y = roundf(grid_v * (grid_size - 1));
79 return mask_grid->data[y * grid_size + x];
80}
81
82static float eval_mask(SubdivCCGMaskEvaluator *mask_evaluator,
83 const int ptex_face_index,
84 const float u,
85 const float v)
86{
87 const GridPaintMask *mask_grid;
88 float grid_u, grid_v;
89 mask_get_grid_and_coord(mask_evaluator, ptex_face_index, u, v, &mask_grid, &grid_u, &grid_v);
90 return read_mask_grid(mask_grid, grid_u, grid_v);
91}
92
93static void free_mask_data(SubdivCCGMaskEvaluator *mask_evaluator)
94{
95 GridPaintMaskData *data = static_cast<GridPaintMaskData *>(mask_evaluator->user_data);
96 MEM_freeN(data->ptex_face_corner);
97 MEM_delete(data);
98}
99
100/* TODO(sergey): This seems to be generally used information, which almost
101 * worth adding to a subdiv itself, with possible cache of the value.
102 */
103static int count_num_ptex_faces(const Mesh *mesh)
104{
105 int num_ptex_faces = 0;
106 const blender::OffsetIndices faces = mesh->faces();
107 for (const int face_index : faces.index_range()) {
108 num_ptex_faces += (faces[face_index].size() == 4) ? 1 : faces[face_index].size();
109 }
110 return num_ptex_faces;
111}
112
113static void mask_data_init_mapping(SubdivCCGMaskEvaluator *mask_evaluator, const Mesh *mesh)
114{
115 GridPaintMaskData *data = static_cast<GridPaintMaskData *>(mask_evaluator->user_data);
116 const blender::OffsetIndices faces = mesh->faces();
117 const int num_ptex_faces = count_num_ptex_faces(mesh);
118 /* Allocate memory. */
119 data->ptex_face_corner = static_cast<PolyCornerIndex *>(
120 MEM_malloc_arrayN(num_ptex_faces, sizeof(*data->ptex_face_corner), __func__));
121 /* Fill in offsets. */
122 int ptex_face_index = 0;
123 PolyCornerIndex *ptex_face_corner = data->ptex_face_corner;
124 for (const int face_index : faces.index_range()) {
125 const blender::IndexRange face = faces[face_index];
126 if (face.size() == 4) {
127 ptex_face_corner[ptex_face_index].face_index = face_index;
128 ptex_face_corner[ptex_face_index].corner = 0;
129 ptex_face_index++;
130 }
131 else {
132 for (int corner = 0; corner < face.size(); corner++) {
133 ptex_face_corner[ptex_face_index].face_index = face_index;
134 ptex_face_corner[ptex_face_index].corner = corner;
135 ptex_face_index++;
136 }
137 }
138 }
139}
140
141static void mask_init_data(SubdivCCGMaskEvaluator *mask_evaluator, const Mesh *mesh)
142{
143 GridPaintMaskData *data = static_cast<GridPaintMaskData *>(mask_evaluator->user_data);
144 data->faces = mesh->faces();
145 data->grid_paint_mask = static_cast<const GridPaintMask *>(
146 CustomData_get_layer(&mesh->corner_data, CD_GRID_PAINT_MASK));
147 mask_data_init_mapping(mask_evaluator, mesh);
148}
149
150static void mask_init_functions(SubdivCCGMaskEvaluator *mask_evaluator)
151{
152 mask_evaluator->eval_mask = eval_mask;
153 mask_evaluator->free = free_mask_data;
154}
155
157{
158 if (!CustomData_get_layer(&mesh->corner_data, CD_GRID_PAINT_MASK)) {
159 return false;
160 }
161 /* Allocate all required memory. */
162 mask_evaluator->user_data = MEM_new<GridPaintMaskData>("mask from grid data");
163 mask_init_data(mask_evaluator, mesh);
164 mask_init_functions(mask_evaluator);
165 return true;
166}
CustomData interface, see also DNA_customdata_types.h.
const void * CustomData_get_layer(const CustomData *data, eCustomDataType type)
#define BLI_INLINE
@ CD_GRID_PAINT_MASK
Read Guarded memory(de)allocation.
ATTR_WARN_UNUSED_RESULT const BMVert * v
constexpr int64_t start() const
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition mallocn.cc:45
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
BLI_INLINE void ptex_face_uv_to_grid_uv(float ptex_u, float ptex_v, float *r_grid_u, float *r_grid_v)
BLI_INLINE int grid_size_from_level(int level)
BLI_INLINE int rotate_quad_to_corner(float quad_u, float quad_v, float *r_corner_u, float *r_corner_v)
PolyCornerIndex * ptex_face_corner
blender::OffsetIndices< int > faces
const GridPaintMask * grid_paint_mask
float(* eval_mask)(SubdivCCGMaskEvaluator *mask_evaluator, int ptex_face_index, float u, float v)
void(* free)(SubdivCCGMaskEvaluator *mask_evaluator)
bool BKE_subdiv_ccg_mask_init_from_paint(SubdivCCGMaskEvaluator *mask_evaluator, const Mesh *mesh)
static float eval_mask(SubdivCCGMaskEvaluator *mask_evaluator, const int ptex_face_index, const float u, const float v)
static void mask_init_data(SubdivCCGMaskEvaluator *mask_evaluator, const Mesh *mesh)
static int mask_get_grid_and_coord(SubdivCCGMaskEvaluator *mask_evaluator, const int ptex_face_index, const float u, const float v, const GridPaintMask **r_mask_grid, float *grid_u, float *grid_v)
static void mask_data_init_mapping(SubdivCCGMaskEvaluator *mask_evaluator, const Mesh *mesh)
static void mask_init_functions(SubdivCCGMaskEvaluator *mask_evaluator)
static int count_num_ptex_faces(const Mesh *mesh)
BLI_INLINE float read_mask_grid(const GridPaintMask *mask_grid, const float grid_u, const float grid_v)
static void free_mask_data(SubdivCCGMaskEvaluator *mask_evaluator)