Blender V4.5
MOD_subsurf.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2005 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cstddef>
10#include <cstring>
11
12#include <fmt/format.h>
13
14#include "MEM_guardedalloc.h"
15
16#include "BLI_utildefines.h"
17
18#include "BLT_translation.hh"
19
20#include "DNA_defaults.h"
21#include "DNA_mesh_types.h"
22#include "DNA_object_types.h"
23#include "DNA_scene_types.h"
24#include "DNA_screen_types.h"
25
26#include "BKE_context.hh"
27#include "BKE_editmesh.hh"
28#include "BKE_global.hh"
29#include "BKE_mesh.hh"
30#include "BKE_mesh_types.hh"
31#include "BKE_mesh_wrapper.hh"
32#include "BKE_scene.hh"
33#include "BKE_subdiv.hh"
34#include "BKE_subdiv_ccg.hh"
35#include "BKE_subdiv_deform.hh"
36#include "BKE_subdiv_mesh.hh"
38
39#include "UI_interface.hh"
40#include "UI_resources.hh"
41
42#include "RE_engine.h"
43
44#include "RNA_access.hh"
45#include "RNA_prototypes.hh"
46
47#include "DEG_depsgraph.hh"
49
50#include "MOD_modifiertypes.hh"
51#include "MOD_ui_common.hh"
52
53#include "intern/CCGSubSurf.h"
54
63
64static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
65{
66#if 0
67 const SubsurfModifierData *smd = (const SubsurfModifierData *)md;
68#endif
70
72
73 tsmd->emCache = tsmd->mCache = nullptr;
74}
75
76static void free_runtime_data(void *runtime_data_v)
77{
78 if (runtime_data_v == nullptr) {
79 return;
80 }
81 SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)runtime_data_v;
82 if (runtime_data->subdiv_cpu != nullptr) {
84 }
85 if (runtime_data->subdiv_gpu != nullptr) {
87 }
88 MEM_freeN(runtime_data);
89}
90
91static void free_data(ModifierData *md)
92{
94
95 if (smd->mCache) {
96 ccgSubSurf_free(static_cast<CCGSubSurf *>(smd->mCache));
97 smd->mCache = nullptr;
98 }
99 if (smd->emCache) {
100 ccgSubSurf_free(static_cast<CCGSubSurf *>(smd->emCache));
101 smd->emCache = nullptr;
102 }
104}
105
106static bool is_disabled(const Scene *scene, ModifierData *md, bool use_render_params)
107{
109 int levels = (use_render_params) ? smd->renderLevels : smd->levels;
110
111 return get_render_subsurf_level(&scene->r, levels, use_render_params != 0) == 0;
112}
113
115 const ModifierEvalContext *ctx)
116{
118 const bool use_render_params = (ctx->flag & MOD_APPLY_RENDER);
119 const int requested_levels = (use_render_params) ? smd->renderLevels : smd->levels;
120 return get_render_subsurf_level(&scene->r, requested_levels, use_render_params);
121}
122
123/* Subdivide into fully qualified mesh. */
124
126 const SubsurfModifierData *smd,
127 const ModifierEvalContext *ctx)
128{
129 const int level = subdiv_levels_for_modifier_get(smd, ctx);
130 settings->resolution = (1 << level) + 1;
132 !(ctx->flag & MOD_APPLY_TO_ORIGINAL);
133}
134
136 const ModifierEvalContext *ctx,
137 Mesh *mesh,
139{
140 Mesh *result = mesh;
142 subdiv_mesh_settings_init(&mesh_settings, smd, ctx);
143 if (mesh_settings.resolution < 3) {
144 return result;
145 }
146 result = blender::bke::subdiv::subdiv_to_mesh(subdiv, &mesh_settings, mesh);
147 return result;
148}
149
150/* Subdivide into CCG. */
151
153 const SubsurfModifierData *smd,
154 const ModifierEvalContext *ctx)
155{
156 const int level = subdiv_levels_for_modifier_get(smd, ctx);
157 settings->resolution = (1 << level) + 1;
158 settings->need_normal = true;
159 settings->need_mask = false;
160}
161
163 const ModifierEvalContext *ctx,
164 Mesh *mesh,
166{
167 Mesh *result = mesh;
168 SubdivToCCGSettings ccg_settings;
169 subdiv_ccg_settings_init(&ccg_settings, smd, ctx);
170 if (ccg_settings.resolution < 3) {
171 return result;
172 }
173 result = BKE_subdiv_to_ccg_mesh(*subdiv, ccg_settings, *mesh);
174 return result;
175}
176
177/* Cache settings for lazy CPU evaluation. */
178
180 Mesh *mesh,
182 SubsurfRuntimeData *runtime_data,
183 const bool has_gpu_subdiv)
184{
186 subdiv_mesh_settings_init(&mesh_settings, smd, ctx);
187
188 runtime_data->has_gpu_subdiv = has_gpu_subdiv;
189 runtime_data->resolution = mesh_settings.resolution;
190 runtime_data->use_optimal_display = mesh_settings.use_optimal_display;
192
193 mesh->runtime->subsurf_runtime_data = runtime_data;
194}
195
197 const Object *ob,
198 int required_mode)
199{
200 ModifierData *md = static_cast<ModifierData *>(ob->modifiers.last);
201
202 while (md) {
203 if (BKE_modifier_is_enabled(scene, md, required_mode)) {
204 break;
205 }
206
207 md = md->prev;
208 }
209
210 return md;
211}
212
213/* Modifier itself. */
214
215static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
216{
217 using namespace blender;
218 Mesh *result = mesh;
219#if !defined(WITH_OPENSUBDIV)
220 BKE_modifier_set_error(ctx->object, md, "Disabled, built without OpenSubdiv");
221 return result;
222#endif
225 return result;
226 }
227
229
230 /* Decrement the recent usage counters. */
231 if (runtime_data->used_cpu) {
232 runtime_data->used_cpu--;
233 }
234
235 if (runtime_data->used_gpu) {
236 runtime_data->used_gpu--;
237 }
238
239 /* Delay evaluation to the draw code if possible, provided we do not have to apply the modifier.
240 */
241 if ((ctx->flag & MOD_APPLY_TO_ORIGINAL) == 0) {
243
244 /* Same check as in `DRW_mesh_batch_cache_create_requested` to keep both code coherent. The
245 * difference is that here we do not check for the final edit mesh pointer as it is not yet
246 * assigned at this stage of modifier stack evaluation. */
247 const bool is_render_mode = (ctx->flag & MOD_APPLY_RENDER) != 0;
248 const bool is_editmode = (mesh->runtime->edit_mesh != nullptr);
249 const int required_mode = BKE_subsurf_modifier_eval_required_mode(is_render_mode, is_editmode);
250
251 /* Check if we are the last modifier in the stack. */
252 ModifierData *md = modifier_get_last_enabled_for_mode(scene, ctx->object, required_mode);
253 if (md == (const ModifierData *)smd) {
254 const bool has_gpu_subdiv = BKE_subsurf_modifier_can_do_gpu_subdiv(smd, mesh);
255 subdiv_cache_mesh_wrapper_settings(ctx, mesh, smd, runtime_data, has_gpu_subdiv);
256
257 /* Delay for:
258 * - Background mode: Not sure if we are going to use the tessellated mesh.
259 * - Render: Engine might do its own subdivision and not need this.
260 * - GPU subdivision support: Might only need to display and not access tessellated mesh.
261 *
262 * If we can't delay, we still create the wrapper so external renderers can get the base
263 * mesh. But we tessellate immediately to take advantage of better parallellization
264 * as part of multithreaded depsgraph evaluation. */
265 const bool delay = G.background || is_render_mode || has_gpu_subdiv;
266 if (!delay) {
268 }
269
270 return result;
271 }
272 }
273
275 runtime_data, mesh, false);
276 if (subdiv == nullptr) {
277 /* Happens on bad topology, but also on empty input mesh. */
278 return result;
279 }
280 const bool use_clnors = BKE_subsurf_modifier_use_custom_loop_normals(smd, mesh);
281 if (use_clnors) {
284 memcpy(data, mesh->corner_normals().data(), mesh->corner_normals().size_in_bytes());
285 }
286 /* TODO(sergey): Decide whether we ever want to use CCG for subsurf,
287 * maybe when it is a last modifier in the stack? */
288 if (true) {
289 result = subdiv_as_mesh(smd, ctx, mesh, subdiv);
290 }
291 else {
292 result = subdiv_as_ccg(smd, ctx, mesh, subdiv);
293 }
294
295 if (use_clnors) {
297 *result,
298 {static_cast<float3 *>(
299 CustomData_get_layer_for_write(&result->corner_data, CD_NORMAL, result->corners_num)),
300 result->corners_num});
302 }
303 // blender::bke::subdiv::stats_print(&subdiv->stats);
304 if (!ELEM(subdiv, runtime_data->subdiv_cpu, runtime_data->subdiv_gpu)) {
306 }
307 return result;
308}
309
311 const ModifierEvalContext *ctx,
312 Mesh *mesh,
315{
316#if !defined(WITH_OPENSUBDIV)
317 BKE_modifier_set_error(ctx->object, md, "Disabled, built without OpenSubdiv");
318 return;
319#endif
320
321 /* Subsurf does not require extra space mapping, keep matrices as is. */
322
325 return;
326 }
329 runtime_data, mesh, false);
330 if (subdiv == nullptr) {
331 /* Happens on bad topology, but also on empty input mesh. */
332 return;
333 }
334 blender::bke::subdiv::deform_coarse_vertices(subdiv, mesh, positions);
335 if (!ELEM(subdiv, runtime_data->subdiv_cpu, runtime_data->subdiv_gpu)) {
337 }
338}
339
340#ifdef WITH_CYCLES
341static bool get_show_adaptive_options(const bContext *C, Panel *panel)
342{
343 /* Don't show adaptive options if cycles isn't the active engine. */
344 const RenderEngineType *engine_type = CTX_data_engine_type(C);
345 if (!STREQ(engine_type->idname, "CYCLES")) {
346 return false;
347 }
348
349 /* Only show adaptive options if this is the last modifier. */
351 ModifierData *md = static_cast<ModifierData *>(ptr->data);
352 if (md->next != nullptr) {
353 return false;
354 }
355
356 /* Don't show adaptive options if the cycles experimental feature set is disabled. */
357 Scene *scene = CTX_data_scene(C);
359 return false;
360 }
361
362 return true;
363}
364#endif
365
366static void panel_draw(const bContext *C, Panel *panel)
367{
368 uiLayout *layout = panel->layout;
369
370 PointerRNA ob_ptr;
372
373 /* Only test for adaptive subdivision if built with cycles. */
374 bool show_adaptive_options = false;
375 bool ob_use_adaptive_subdivision = false;
376 PointerRNA cycles_ptr = {};
377 PointerRNA ob_cycles_ptr = {};
378#ifdef WITH_CYCLES
379 Scene *scene = CTX_data_scene(C);
380 PointerRNA scene_ptr = RNA_id_pointer_create(&scene->id);
381 if (BKE_scene_uses_cycles(scene)) {
382 cycles_ptr = RNA_pointer_get(&scene_ptr, "cycles");
383 ob_cycles_ptr = RNA_pointer_get(&ob_ptr, "cycles");
384 if (!RNA_pointer_is_null(&ob_cycles_ptr)) {
385 show_adaptive_options = get_show_adaptive_options(C, panel);
386 ob_use_adaptive_subdivision = show_adaptive_options &&
387 RNA_boolean_get(&ob_cycles_ptr, "use_adaptive_subdivision");
388 }
389 }
390#else
391 UNUSED_VARS(C);
392#endif
393
394 layout->prop(ptr, "subdivision_type", UI_ITEM_R_EXPAND, std::nullopt, ICON_NONE);
395
396 uiLayoutSetPropSep(layout, true);
397
398 uiLayout *col = &layout->column(true);
399 col->prop(ptr, "levels", UI_ITEM_NONE, IFACE_("Levels Viewport"), ICON_NONE);
400 col->prop(ptr, "render_levels", UI_ITEM_NONE, IFACE_("Render"), ICON_NONE);
401
402 layout->prop(ptr, "show_only_control_edges", UI_ITEM_NONE, std::nullopt, ICON_NONE);
403
405 SubsurfModifierData *smd = static_cast<SubsurfModifierData *>(ptr->data);
406 Object *ob = static_cast<Object *>(ob_ptr.data);
408 smd, static_cast<const Mesh *>(ob->data)))
409 {
410 layout->label(RPT_("Sharp edges or custom normals detected, disabling GPU subdivision"),
411 ICON_INFO);
412 }
413 else if (Object *ob_eval = DEG_get_evaluated(depsgraph, ob)) {
414 if (ModifierData *md_eval = BKE_modifiers_findby_name(ob_eval, smd->modifier.name)) {
415 if (md_eval->type == eModifierType_Subsurf) {
416 SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)md_eval->runtime;
417
418 if (runtime_data && runtime_data->used_gpu) {
419 if (runtime_data->used_cpu) {
420 layout->label(RPT_("Using both CPU and GPU subdivision"), ICON_INFO);
421 }
422 }
423 }
424 }
425 }
426
427 if (show_adaptive_options) {
428 PanelLayout adaptive_panel = layout->panel_prop_with_bool_header(
429 C,
430 ptr,
431 "open_adaptive_subdivision_panel",
432 &ob_cycles_ptr,
433 "use_adaptive_subdivision",
434 IFACE_("Adaptive Subdivision"));
435 if (adaptive_panel.body) {
436 uiLayoutSetActive(adaptive_panel.body, ob_use_adaptive_subdivision);
437 adaptive_panel.body->prop(
438 &ob_cycles_ptr, "dicing_rate", UI_ITEM_NONE, std::nullopt, ICON_NONE);
439
440 float render = std::max(RNA_float_get(&cycles_ptr, "dicing_rate") *
441 RNA_float_get(&ob_cycles_ptr, "dicing_rate"),
442 0.1f);
443 float preview = std::max(RNA_float_get(&cycles_ptr, "preview_dicing_rate") *
444 RNA_float_get(&ob_cycles_ptr, "dicing_rate"),
445 0.1f);
446
447 uiLayout *split = &adaptive_panel.body->split(0.4f, false);
448 split->column(true).label("", ICON_NONE);
449 uiLayout *col = &split->column(true);
450 col->label(fmt::format(fmt::runtime(RPT_("Viewport {:.2f} px")), preview), ICON_NONE);
451 col->label(fmt::format(fmt::runtime(RPT_("Render {:.2f} px")), render), ICON_NONE);
452 }
453 }
454
455 if (uiLayout *advanced_layout = layout->panel_prop(
456 C, ptr, "open_advanced_panel", IFACE_("Advanced")))
457 {
458 uiLayoutSetPropSep(advanced_layout, true);
459
460 advanced_layout->prop(ptr, "use_limit_surface", UI_ITEM_NONE, std::nullopt, ICON_NONE);
461
462 uiLayout *col = &advanced_layout->column(true);
464 ob_use_adaptive_subdivision || RNA_boolean_get(ptr, "use_limit_surface"));
465 col->prop(ptr, "quality", UI_ITEM_NONE, std::nullopt, ICON_NONE);
466
467 advanced_layout->prop(ptr, "uv_smooth", UI_ITEM_NONE, std::nullopt, ICON_NONE);
468 advanced_layout->prop(ptr, "boundary_smooth", UI_ITEM_NONE, std::nullopt, ICON_NONE);
469 advanced_layout->prop(ptr, "use_creases", UI_ITEM_NONE, std::nullopt, ICON_NONE);
470 advanced_layout->prop(ptr, "use_custom_normals", UI_ITEM_NONE, std::nullopt, ICON_NONE);
471 }
472
474}
475
476static void panel_register(ARegionType *region_type)
477{
479}
480
481static void blend_read(BlendDataReader * /*reader*/, ModifierData *md)
482{
484
485 smd->emCache = smd->mCache = nullptr;
486}
487
489 /*idname*/ "Subdivision",
490 /*name*/ N_("Subdivision"),
491 /*struct_name*/ "SubsurfModifierData",
492 /*struct_size*/ sizeof(SubsurfModifierData),
493 /*srna*/ &RNA_SubsurfModifier,
498 /*icon*/ ICON_MOD_SUBSURF,
499
500 /*copy_data*/ copy_data,
501
502 /*deform_verts*/ nullptr,
503 /*deform_matrices*/ deform_matrices,
504 /*deform_verts_EM*/ nullptr,
505 /*deform_matrices_EM*/ nullptr,
506 /*modify_mesh*/ modify_mesh,
507 /*modify_geometry_set*/ nullptr,
508
509 /*init_data*/ init_data,
510 /*required_data_mask*/ nullptr,
511 /*free_data*/ free_data,
512 /*is_disabled*/ is_disabled,
513 /*update_depsgraph*/ nullptr,
514 /*depends_on_time*/ nullptr,
515 /*depends_on_normals*/ nullptr,
516 /*foreach_ID_link*/ nullptr,
517 /*foreach_tex_link*/ nullptr,
518 /*free_runtime_data*/ free_runtime_data,
519 /*panel_register*/ panel_register,
520 /*blend_write*/ nullptr,
521 /*blend_read*/ blend_read,
522 /*foreach_cache*/ nullptr,
523};
Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
RenderEngineType * CTX_data_engine_type(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
@ CD_CONSTRUCT
void CustomData_free_layers(CustomData *data, eCustomDataType type)
void * CustomData_get_layer_for_write(CustomData *data, eCustomDataType type, int totelem)
void * CustomData_add_layer(CustomData *data, eCustomDataType type, eCDAllocType alloctype, int totelem)
Mesh * BKE_mesh_wrapper_ensure_subdivision(Mesh *mesh)
bool BKE_modifier_is_enabled(const Scene *scene, ModifierData *md, int required_mode)
void BKE_modifier_copydata_generic(const ModifierData *md, ModifierData *md_dst, int flag)
@ eModifierTypeFlag_AcceptsCVs
@ eModifierTypeFlag_SupportsMapping
@ eModifierTypeFlag_EnableInEditmode
@ eModifierTypeFlag_SupportsEditmode
@ eModifierTypeFlag_AcceptsMesh
ModifierData * BKE_modifiers_findby_name(const Object *ob, const char *name)
void BKE_modifier_set_error(const Object *ob, ModifierData *md, const char *format,...) ATTR_PRINTF_FORMAT(3
@ MOD_APPLY_TO_ORIGINAL
@ MOD_APPLY_RENDER
bool BKE_scene_uses_cycles(const Scene *scene)
Definition scene.cc:2832
int get_render_subsurf_level(const RenderData *r, int lvl, bool for_render)
Definition scene.cc:2750
bool BKE_scene_uses_cycles_experimental_features(Scene *scene)
Definition scene.cc:2848
Mesh * BKE_subdiv_to_ccg_mesh(blender::bke::subdiv::Subdiv &subdiv, const SubdivToCCGSettings &settings, const Mesh &coarse_mesh)
bool BKE_subsurf_modifier_can_do_gpu_subdiv(const SubsurfModifierData *smd, const Mesh *mesh)
int BKE_subsurf_modifier_eval_required_mode(bool is_final_render, bool is_edit_mode)
bool BKE_subsurf_modifier_force_disable_gpu_evaluation_for_mesh(const SubsurfModifierData *smd, const Mesh *mesh)
bool BKE_subsurf_modifier_use_custom_loop_normals(const SubsurfModifierData *smd, const Mesh *mesh)
bool BKE_subsurf_modifier_runtime_init(SubsurfModifierData *smd, bool use_render_params)
blender::bke::subdiv::Subdiv * BKE_subsurf_modifier_subdiv_descriptor_ensure(SubsurfRuntimeData *runtime_data, const Mesh *mesh, bool for_draw_code)
#define BLI_assert(a)
Definition BLI_assert.h:46
#define UNUSED_VARS(...)
#define ELEM(...)
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
#define STREQ(a, b)
#define RPT_(msgid)
#define IFACE_(msgid)
void ccgSubSurf_free(CCGSubSurf *ss)
Scene * DEG_get_evaluated_scene(const Depsgraph *graph)
T * DEG_get_evaluated(const Depsgraph *depsgraph, T *id)
#define DNA_struct_default_get(struct_name)
@ eModifierType_Subsurf
@ eSubsurfModifierFlag_ControlEdges
@ eSubsurfModifierFlag_UseCustomNormals
Object is a sort of wrapper for general info.
@ OB_MESH
static void split(const char *text, const char *seps, char ***str, int *count)
static bool is_disabled
Read Guarded memory(de)allocation.
static void deform_matrices(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh, blender::MutableSpan< blender::float3 > positions, blender::MutableSpan< blender::float3x3 > matrices)
static void init_data(ModifierData *md)
static void panel_register(ARegionType *region_type)
static void blend_read(BlendDataReader *, ModifierData *md)
static void panel_draw(const bContext *, Panel *panel)
static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
static Mesh * modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
Definition MOD_array.cc:862
static void free_data(ModifierData *md)
Definition MOD_bevel.cc:271
static void free_runtime_data(void *runtime_data_v)
static void init_data(ModifierData *md)
static void subdiv_cache_mesh_wrapper_settings(const ModifierEvalContext *ctx, Mesh *mesh, SubsurfModifierData *smd, SubsurfRuntimeData *runtime_data, const bool has_gpu_subdiv)
static void panel_register(ARegionType *region_type)
static void free_runtime_data(void *runtime_data_v)
static Mesh * subdiv_as_ccg(SubsurfModifierData *smd, const ModifierEvalContext *ctx, Mesh *mesh, blender::bke::subdiv::Subdiv *subdiv)
static ModifierData * modifier_get_last_enabled_for_mode(const Scene *scene, const Object *ob, int required_mode)
static void blend_read(BlendDataReader *, ModifierData *md)
static Mesh * modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
static void free_data(ModifierData *md)
static void subdiv_mesh_settings_init(blender::bke::subdiv::ToMeshSettings *settings, const SubsurfModifierData *smd, const ModifierEvalContext *ctx)
static void subdiv_ccg_settings_init(SubdivToCCGSettings *settings, const SubsurfModifierData *smd, const ModifierEvalContext *ctx)
ModifierTypeInfo modifierType_Subsurf
static Mesh * subdiv_as_mesh(SubsurfModifierData *smd, const ModifierEvalContext *ctx, Mesh *mesh, blender::bke::subdiv::Subdiv *subdiv)
static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
static void deform_matrices(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh, blender::MutableSpan< blender::float3 > positions, blender::MutableSpan< blender::float3x3 >)
static int subdiv_levels_for_modifier_get(const SubsurfModifierData *smd, const ModifierEvalContext *ctx)
static void panel_draw(const bContext *C, Panel *panel)
PanelType * modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw)
PointerRNA * modifier_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ptr)
void modifier_error_message_draw(uiLayout *layout, PointerRNA *ptr)
#define C
Definition RandGen.cpp:29
@ UI_ITEM_R_EXPAND
void uiLayoutSetActive(uiLayout *layout, bool active)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
#define UI_ITEM_NONE
BMesh const char void * data
BPy_StructRNA * depsgraph
uint col
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
#define G(x, y, z)
void free(Subdiv *subdiv)
Definition subdiv.cc:190
void deform_coarse_vertices(Subdiv *subdiv, const Mesh *coarse_mesh, MutableSpan< float3 > vert_positions)
Mesh * subdiv_to_mesh(Subdiv *subdiv, const ToMeshSettings *settings, const Mesh *coarse_mesh)
void mesh_set_custom_normals_normalized(Mesh &mesh, MutableSpan< float3 > corner_normals)
PointerRNA RNA_pointer_get(PointerRNA *ptr, const char *name)
float RNA_float_get(PointerRNA *ptr, const char *name)
bool RNA_pointer_is_null(const PointerRNA *ptr)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
PointerRNA RNA_id_pointer_create(ID *id)
void * last
int corners_num
MeshRuntimeHandle * runtime
CustomData corner_data
struct ModifierData * next
struct ModifierData * prev
ModifierApplyFlag flag
ListBase modifiers
struct uiLayout * layout
void * data
Definition RNA_types.hh:53
char idname[64]
Definition RE_engine.h:74
struct RenderData r
blender::bke::subdiv::Subdiv * subdiv_cpu
blender::bke::subdiv::Subdiv * subdiv_gpu
PanelLayout panel_prop_with_bool_header(const bContext *C, PointerRNA *open_prop_owner, blender::StringRefNull open_prop_name, PointerRNA *bool_prop_owner, blender::StringRefNull bool_prop_name, std::optional< blender::StringRefNull > label)
PanelLayout panel_prop(const bContext *C, PointerRNA *open_prop_owner, blender::StringRefNull open_prop_name)
void label(blender::StringRef name, int icon)
uiLayout & column(bool align)
uiLayout & split(float percentage, bool align)
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4227
uint8_t flag
Definition wm_window.cc:139