Blender V5.0
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
8
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 "BKE_customdata.hh"
17#include "BKE_subdiv.hh"
18
19#include "MEM_guardedalloc.h"
20
21using namespace blender::bke::subdiv;
22
25 int corner;
26};
27
29 // int grid_size;
32 /* Indexed by ptex face index, contains face/corner which corresponds
33 * to it.
34 *
35 * NOTE: For quad face this is an index of first corner only, since
36 * there we only have one ptex.
37 */
39};
40
42 const int ptex_face_index,
43 const float u,
44 const float v,
45 const GridPaintMask **r_mask_grid,
46 float *grid_u,
47 float *grid_v)
48{
49 GridPaintMaskData *data = static_cast<GridPaintMaskData *>(mask_evaluator->user_data);
50 const PolyCornerIndex *poly_corner = &data->ptex_face_corner[ptex_face_index];
51 const blender::IndexRange face = data->faces[poly_corner->face_index];
52 const int start_grid_index = face.start() + poly_corner->corner;
53 int corner = 0;
54 if (face.size() == 4) {
55 float corner_u, corner_v;
56 corner = rotate_quad_to_corner(u, v, &corner_u, &corner_v);
57 *r_mask_grid = &data->grid_paint_mask[start_grid_index + corner];
58 ptex_face_uv_to_grid_uv(corner_u, corner_v, grid_u, grid_v);
59 }
60 else {
61 *r_mask_grid = &data->grid_paint_mask[start_grid_index];
62 ptex_face_uv_to_grid_uv(u, v, grid_u, grid_v);
63 }
64 return corner;
65}
66
68 const float grid_u,
69 const float grid_v)
70{
71 if (mask_grid->data == nullptr) {
72 return 0;
73 }
74 const int grid_size = grid_size_from_level(mask_grid->level);
75 const int x = roundf(grid_u * (grid_size - 1));
76 const int y = roundf(grid_v * (grid_size - 1));
77 return mask_grid->data[y * grid_size + x];
78}
79
80static float eval_mask(SubdivCCGMaskEvaluator *mask_evaluator,
81 const int ptex_face_index,
82 const float u,
83 const float v)
84{
85 const GridPaintMask *mask_grid;
86 float grid_u, grid_v;
87 mask_get_grid_and_coord(mask_evaluator, ptex_face_index, u, v, &mask_grid, &grid_u, &grid_v);
88 return read_mask_grid(mask_grid, grid_u, grid_v);
89}
90
91static void free_mask_data(SubdivCCGMaskEvaluator *mask_evaluator)
92{
93 GridPaintMaskData *data = static_cast<GridPaintMaskData *>(mask_evaluator->user_data);
94 MEM_freeN(data->ptex_face_corner);
95 MEM_delete(data);
96}
97
98/* TODO(sergey): This seems to be generally used information, which almost
99 * worth adding to a subdiv itself, with possible cache of the value.
100 */
102{
103 int num_ptex_faces = 0;
104 const blender::OffsetIndices faces = mesh->faces();
105 for (const int face_index : faces.index_range()) {
106 num_ptex_faces += (faces[face_index].size() == 4) ? 1 : faces[face_index].size();
107 }
108 return num_ptex_faces;
109}
110
111static void mask_data_init_mapping(SubdivCCGMaskEvaluator *mask_evaluator, const Mesh *mesh)
112{
113 GridPaintMaskData *data = static_cast<GridPaintMaskData *>(mask_evaluator->user_data);
114 const blender::OffsetIndices faces = mesh->faces();
115 const int num_ptex_faces = count_num_ptex_faces(mesh);
116 /* Allocate memory. */
117 data->ptex_face_corner = MEM_malloc_arrayN<PolyCornerIndex>(size_t(num_ptex_faces), __func__);
118 /* Fill in offsets. */
119 int ptex_face_index = 0;
120 PolyCornerIndex *ptex_face_corner = data->ptex_face_corner;
121 for (const int face_index : faces.index_range()) {
122 const blender::IndexRange face = faces[face_index];
123 if (face.size() == 4) {
124 ptex_face_corner[ptex_face_index].face_index = face_index;
125 ptex_face_corner[ptex_face_index].corner = 0;
126 ptex_face_index++;
127 }
128 else {
129 for (int corner = 0; corner < face.size(); corner++) {
130 ptex_face_corner[ptex_face_index].face_index = face_index;
131 ptex_face_corner[ptex_face_index].corner = corner;
132 ptex_face_index++;
133 }
134 }
135 }
136}
137
138static void mask_init_data(SubdivCCGMaskEvaluator *mask_evaluator, const Mesh *mesh)
139{
140 GridPaintMaskData *data = static_cast<GridPaintMaskData *>(mask_evaluator->user_data);
141 data->faces = mesh->faces();
142 data->grid_paint_mask = static_cast<const GridPaintMask *>(
144 mask_data_init_mapping(mask_evaluator, mesh);
145}
146
147static void mask_init_functions(SubdivCCGMaskEvaluator *mask_evaluator)
148{
149 mask_evaluator->eval_mask = eval_mask;
150 mask_evaluator->free = free_mask_data;
151}
152
154{
155 if (!CustomData_get_layer(&mesh->corner_data, CD_GRID_PAINT_MASK)) {
156 return false;
157 }
158 /* Allocate all required memory. */
159 mask_evaluator->user_data = MEM_new<GridPaintMaskData>("mask from grid data");
160 mask_init_data(mask_evaluator, mesh);
161 mask_init_functions(mask_evaluator);
162 return true;
163}
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.
BMesh const char void * data
ATTR_WARN_UNUSED_RESULT const BMVert * v
constexpr int64_t size() const
constexpr int64_t start() const
#define roundf(x)
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
static char faces[256]
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)