Bevel: Custom Profile and CurveProfile Widget

Custom profiles in bevel allows the profile curve to be controlled by
manually placed control points. Orientation is regularized along
groups of edges, and the 'pipe case' is updated. This commit includes
many updates to comments and changed variable names as well.

A 'cutoff' vertex mesh method is added to bevel in addition to the
existing grid fill option for replacing vertices.

The UI of the bevel modifier and tool are updated and unified.

Also, a 'CurveProfile' widget is added to BKE for defining the profile
in the interface, which may be useful in other situations.

Many thanks to Howard, my mentor for this GSoC project.

Reviewers: howardt, campbellbarton

Differential Revision: https://developer.blender.org/D5516
This commit is contained in:
Hans Goudey 2019-11-20 16:12:32 -05:00
parent 8c6ce74239
commit ba1e9ae473
Notes: blender-bot 2025-02-14 01:17:13 +00:00
Referenced by issue #91398, Camera BG jitter offset (regression)
Referenced by issue #88681, Armature combined with subdivision incorrect normals
Referenced by issue #71879, Select expand/contract from face mode to edge mode doesnt flush to faces if there are zero edges selected after contraction
Referenced by issue #71882, Offset Edge Slide doesn't switch selection mode correctly
Referenced by issue #71844, Outliner: show_active doesn't expand armature to show active bone
Referenced by issue #71769, The plus icon is on the left and no effect when you click
Referenced by issue #71749, Shrink Wrap Modifier: Default shrink wrap surface constraint option yield inert results on objects with overlapping vertices and same topology
Referenced by issue #71722, Alembic speed decrease for deforming geometry
39 changed files with 4574 additions and 723 deletions

View File

@ -4680,6 +4680,8 @@ def km_bevel_modal_map(_params):
("MARK_SHARP_TOGGLE", {"type": 'K', "value": 'PRESS', "any": True}, None),
("OUTER_MITER_CHANGE", {"type": 'O', "value": 'PRESS', "any": True}, None),
("INNER_MITER_CHANGE", {"type": 'I', "value": 'PRESS', "any": True}, None),
("CUSTOM_PROFILE_TOGGLE", {"type": 'Z', "value": 'PRESS', "any": True}, None),
("VERTEX_MESH_CHANGE", {"type": 'N', "value": 'PRESS', "any": True}, None),
])
return keymap

View File

@ -133,43 +133,55 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
layout.prop(md, "end_cap")
def BEVEL(self, layout, ob, md):
split = layout.split()
col = split.column()
if md.offset_type == 'PERCENT':
col.prop(md, "width_pct")
offset_type = md.offset_type
if offset_type == 'PERCENT':
layout.prop(md, "width_pct")
else:
col.prop(md, "width")
col.prop(md, "segments")
col.prop(md, "profile")
col.prop(md, "material")
offset_text = "Width"
if offset_type == 'DEPTH':
offset_text = "Depth"
elif offset_type == 'OFFSET':
offset_text = "Offset"
layout.prop(md, "width", text=offset_text)
layout.row().prop(md, "offset_type", expand=True)
split = layout.split()
col = split.column()
col.prop(md, "use_only_vertices")
col.prop(md, "use_clamp_overlap")
col.prop(md, "loop_slide")
col = split.column()
col.prop(md, "mark_seam")
col.prop(md, "mark_sharp")
col.prop(md, "harden_normals")
layout.row().prop(md, "segments")
layout.row().prop(md, "profile")
layout.row().prop(md, "material")
layout.label(text="Miter Type:")
layout.row().prop(md, "miter_outer", text="Outer")
layout.row().prop(md, "miter_inner", text="Inner")
if md.miter_inner in {'MITER_PATCH', 'MITER_ARC'}:
layout.row().prop(md, "spread")
layout.label(text="Limit Method:")
layout.row().prop(md, "limit_method", expand=True)
if md.limit_method == 'ANGLE':
layout.prop(md, "angle_limit")
elif md.limit_method == 'VGROUP':
layout.label(text="Vertex Group:")
layout.prop_search(md, "vertex_group", ob, "vertex_groups", text="")
layout.label(text="Width Method:")
layout.row().prop(md, "offset_type", expand=True)
layout.label(text="Set Face Strength Mode")
layout.label(text="Face Strength Mode:")
layout.row().prop(md, "face_strength_mode", expand=True)
layout.label(text="Miter Patterns")
layout.row().prop(md, "miter_outer")
layout.row().prop(md, "miter_inner")
layout.row().prop(md, "spread")
layout.label(text="Intersection Type:")
layout.row().prop(md, "vmesh_method", expand=True)
layout.row().prop(md, "use_custom_profile")
row = layout.row()
row.enabled = md.use_custom_profile
if md.use_custom_profile:
layout.template_curveprofile(md, "custom_profile")
def BOOLEAN(self, layout, _ob, md):
split = layout.split()

View File

@ -68,6 +68,7 @@ set(SRC_DNA_INC
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_outliner_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_packedFile_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_particle_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_curveprofile_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_rigidbody_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_scene_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_screen_types.h

View File

@ -0,0 +1,76 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright (C) 2019 Blender Foundation.
* All rights reserved.
*/
#ifndef __BKE_CURVEPROFILE_H__
#define __BKE_CURVEPROFILE_H__
/** \file
* \ingroup bke
*/
struct CurveProfile;
struct CurveProfilePoint;
void BKE_curveprofile_set_defaults(struct CurveProfile *profile);
struct CurveProfile *BKE_curveprofile_add(int preset);
void BKE_curveprofile_free_data(struct CurveProfile *profile);
void BKE_curveprofile_free(struct CurveProfile *profile);
void BKE_curveprofile_copy_data(struct CurveProfile *target, const struct CurveProfile *profile);
struct CurveProfile *BKE_curveprofile_copy(const struct CurveProfile *profile);
bool BKE_curveprofile_remove_point(struct CurveProfile *profile, struct CurveProfilePoint *point);
void BKE_curveprofile_remove_by_flag(struct CurveProfile *profile, const short flag);
struct CurveProfilePoint *BKE_curveprofile_insert(struct CurveProfile *profile, float x, float y);
void BKE_curveprofile_selected_handle_set(struct CurveProfile *profile, int type_1, int type_2);
void BKE_curveprofile_reverse(struct CurveProfile *profile);
void BKE_curveprofile_reset(struct CurveProfile *profile);
void BKE_curveprofile_create_samples(struct CurveProfile *profile,
int segments_len,
bool sample_straight_edges,
struct CurveProfilePoint *r_samples);
void BKE_curveprofile_initialize(struct CurveProfile *profile, short segments_len);
/* Called for a complete update of the widget after modifications */
void BKE_curveprofile_update(struct CurveProfile *profile, const bool rem_doubles);
/* Need to find the total length of the curve to sample a portion of it */
float BKE_curveprofile_total_length(const struct CurveProfile *profile);
void BKE_curveprofile_create_samples_even_spacing(struct CurveProfile *profile,
int segments_len,
struct CurveProfilePoint *r_samples);
/* Length portion is the fraction of the total path length where we want the location */
void BKE_curveprofile_evaluate_length_portion(const struct CurveProfile *profile,
float length_portion,
float *x_out,
float *y_out);
#endif

View File

@ -185,6 +185,7 @@ set(SRC
intern/pbvh_bmesh.c
intern/pbvh_parallel.cc
intern/pointcache.c
intern/curveprofile.c
intern/report.c
intern/rigidbody.c
intern/scene.c
@ -330,6 +331,7 @@ set(SRC
BKE_particle.h
BKE_pbvh.h
BKE_pointcache.h
BKE_curveprofile.h
BKE_report.h
BKE_rigidbody.h
BKE_scene.h

File diff suppressed because it is too large Load Diff

View File

@ -29,6 +29,7 @@
#include "DNA_anim_types.h"
#include "DNA_collection_types.h"
#include "DNA_curveprofile_types.h"
#include "DNA_linestyle_types.h"
#include "DNA_mesh_types.h"
#include "DNA_node_types.h"
@ -80,6 +81,7 @@
#include "BKE_node.h"
#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_curveprofile.h"
#include "BKE_rigidbody.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
@ -182,6 +184,8 @@ ToolSettings *BKE_toolsettings_copy(ToolSettings *toolsettings, const int flag)
/* duplicate Grease Pencil multiframe fallof */
ts->gp_sculpt.cur_falloff = BKE_curvemapping_copy(ts->gp_sculpt.cur_falloff);
ts->gp_sculpt.cur_primitive = BKE_curvemapping_copy(ts->gp_sculpt.cur_primitive);
ts->custom_bevel_profile_preset = BKE_curveprofile_copy(ts->custom_bevel_profile_preset);
return ts;
}
@ -224,6 +228,10 @@ void BKE_toolsettings_free(ToolSettings *toolsettings)
BKE_curvemapping_free(toolsettings->gp_sculpt.cur_primitive);
}
if (toolsettings->custom_bevel_profile_preset) {
BKE_curveprofile_free(toolsettings->custom_bevel_profile_preset);
}
MEM_freeN(toolsettings);
}
@ -729,6 +737,9 @@ void BKE_scene_init(Scene *sce)
copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
}
/* Curve Profile */
sce->toolsettings->custom_bevel_profile_preset = BKE_curveprofile_add(PROF_PRESET_LINE);
for (int i = 0; i < ARRAY_SIZE(sce->orientation_slots); i++) {
sce->orientation_slots[i].index_custom = -1;
}

View File

@ -74,6 +74,7 @@
#include "DNA_object_types.h"
#include "DNA_packedFile_types.h"
#include "DNA_particle_types.h"
#include "DNA_curveprofile_types.h"
#include "DNA_lightprobe_types.h"
#include "DNA_rigidbody_types.h"
#include "DNA_text_types.h"
@ -132,6 +133,7 @@
#include "BKE_paint.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
#include "BKE_curveprofile.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
@ -2697,6 +2699,19 @@ static void direct_link_curvemapping(FileData *fd, CurveMapping *cumap)
/** \} */
/* -------------------------------------------------------------------- */
/** \name Read CurveProfile
* \{ */
static void direct_link_curveprofile(FileData *fd, CurveProfile *profile)
{
profile->path = newdataadr(fd, profile->path);
profile->table = NULL;
profile->segments = NULL;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Read ID: Brush
* \{ */
@ -5802,6 +5817,13 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
}
}
}
else if (md->type == eModifierType_Bevel) {
BevelModifierData *bmd = (BevelModifierData *)md;
bmd->custom_profile = newdataadr(fd, bmd->custom_profile);
if (bmd->custom_profile) {
direct_link_curveprofile(fd, bmd->custom_profile);
}
}
}
}
@ -6758,6 +6780,13 @@ static void direct_link_scene(FileData *fd, Scene *sce)
if (sce->toolsettings->gp_sculpt.cur_primitive) {
direct_link_curvemapping(fd, sce->toolsettings->gp_sculpt.cur_primitive);
}
/* Relink toolsettings curve profile */
sce->toolsettings->custom_bevel_profile_preset = newdataadr(
fd, sce->toolsettings->custom_bevel_profile_preset);
if (sce->toolsettings->custom_bevel_profile_preset) {
direct_link_curveprofile(fd, sce->toolsettings->custom_bevel_profile_preset);
}
}
if (sce->ed) {

View File

@ -36,6 +36,7 @@
#include "DNA_cloth_types.h"
#include "DNA_collection_types.h"
#include "DNA_constraint_types.h"
#include "DNA_curveprofile_types.h"
#include "DNA_gpu_types.h"
#include "DNA_light_types.h"
#include "DNA_layer_types.h"
@ -74,6 +75,7 @@
#include "BKE_node.h"
#include "BKE_paint.h"
#include "BKE_pointcache.h"
#include "BKE_curveprofile.h"
#include "BKE_report.h"
#include "BKE_rigidbody.h"
#include "BKE_screen.h"
@ -3932,10 +3934,35 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
{
/* Versioning code until next subversion bump goes here. */
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
sa->flag &= ~AREA_FLAG_UNUSED_6;
}
}
/* Add custom curve profile to toolsettings for bevel tool */
if (!DNA_struct_elem_find(fd->filesdna, "ToolSettings", "CurveProfile", "custom_profile")) {
for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
ToolSettings *ts = scene->toolsettings;
if ((ts) && (ts->custom_bevel_profile_preset == NULL)) {
ts->custom_bevel_profile_preset = BKE_curveprofile_add(PROF_PRESET_LINE);
}
}
}
/* Add custom curve profile to bevel modifier */
if (!DNA_struct_elem_find(fd->filesdna, "BevelModifier", "CurveProfile", "custom_profile")) {
for (Object *object = bmain->objects.first; object != NULL; object = object->id.next) {
for (ModifierData *md = object->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_Bevel) {
BevelModifierData *bmd = (BevelModifierData *)md;
if (!bmd->custom_profile) {
bmd->custom_profile = BKE_curveprofile_add(PROF_PRESET_LINE);
}
}
}
}
}
}
}

View File

@ -27,6 +27,7 @@
#include "BLI_system.h"
#include "DNA_camera_types.h"
#include "DNA_curveprofile_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_mesh_types.h"
#include "DNA_object_types.h"
@ -51,6 +52,7 @@
#include "BKE_paint.h"
#include "BKE_screen.h"
#include "BKE_workspace.h"
#include "BKE_curveprofile.h"
#include "BLO_readfile.h"
@ -324,6 +326,11 @@ static void blo_update_defaults_scene(Main *bmain, Scene *scene)
copy_v2_v2(me->mloopuv[i].uv, uv_values[i]);
}
}
/* Make sure that the curve profile is initialized */
if (ts->custom_bevel_profile_preset == NULL) {
ts->custom_bevel_profile_preset = BKE_curveprofile_add(PROF_PRESET_LINE);
}
}
/**

View File

@ -139,6 +139,7 @@
#include "DNA_workspace_types.h"
#include "DNA_movieclip_types.h"
#include "DNA_mask_types.h"
#include "DNA_curveprofile_types.h"
#include "MEM_guardedalloc.h" // MEM_freeN
#include "BLI_bitmap.h"
@ -953,6 +954,12 @@ static void write_curvemapping(WriteData *wd, CurveMapping *cumap)
write_curvemapping_curves(wd, cumap);
}
static void write_CurveProfile(WriteData *wd, CurveProfile *profile)
{
writestruct(wd, DATA, CurveProfile, 1, profile);
writestruct(wd, DATA, CurveProfilePoint, profile->path_len, profile->path);
}
static void write_node_socket(WriteData *wd, bNodeSocket *sock)
{
/* actual socket writing */
@ -1759,6 +1766,12 @@ static void write_modifiers(WriteData *wd, ListBase *modbase)
}
}
}
else if (md->type == eModifierType_Bevel) {
BevelModifierData *bmd = (BevelModifierData *)md;
if (bmd->custom_profile) {
write_CurveProfile(wd, bmd->custom_profile);
}
}
}
}
@ -2533,6 +2546,10 @@ static void write_scene(WriteData *wd, Scene *sce)
if (tos->gp_sculpt.cur_primitive) {
write_curvemapping(wd, tos->gp_sculpt.cur_primitive);
}
/* Write the curve profile to the file. */
if (tos->custom_bevel_profile_preset) {
write_CurveProfile(wd, tos->custom_bevel_profile_preset);
}
write_paint(wd, &tos->imapaint.paint);

View File

@ -1725,6 +1725,12 @@ static BMO_FlagSet bmo_enum_bevel_miter_type[] = {
{0, NULL},
};
static BMO_FlagSet bmo_enum_bevel_vmesh_method[] = {
{BEVEL_VMESH_ADJ, "ADJ"},
{BEVEL_VMESH_CUTOFF, "CUTOFF"},
{0, NULL},
};
/*
* Bevel.
*
@ -1735,7 +1741,8 @@ static BMOpDefine bmo_bevel_def = {
/* slots_in */
{{"geom", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, /* input edges and vertices */
{"offset", BMO_OP_SLOT_FLT}, /* amount to offset beveled edge */
{"offset_type", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM}, bmo_enum_bevel_offset_type}, /* how to measure the offset */
{"offset_type", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM},
bmo_enum_bevel_offset_type}, /* how to measure the offset */
{"segments", BMO_OP_SLOT_INT}, /* number of segments in bevel */
{"profile", BMO_OP_SLOT_FLT}, /* profile shape, 0->1 (.5=>round) */
{"vertex_only", BMO_OP_SLOT_BOOL}, /* only bevel vertices, not edges */
@ -1746,13 +1753,18 @@ static BMOpDefine bmo_bevel_def = {
{"mark_sharp", BMO_OP_SLOT_BOOL}, /* extend edge data to allow sharp edges to run across bevels */
{"harden_normals", BMO_OP_SLOT_BOOL}, /* harden normals */
{"face_strength_mode", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM},
bmo_enum_bevel_face_strength_type}, /* whether to set face strength, and which faces to set if so */
bmo_enum_bevel_face_strength_type}, /* whether to set face strength, and which faces to set if so */
{"miter_outer", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM},
bmo_enum_bevel_miter_type}, /* outer miter kind */
bmo_enum_bevel_miter_type}, /* outer miter kind */
{"miter_inner", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM},
bmo_enum_bevel_miter_type}, /* outer miter kind */
bmo_enum_bevel_miter_type}, /* outer miter kind */
{"spread", BMO_OP_SLOT_FLT}, /* amount to offset beveled edge */
{"smoothresh", BMO_OP_SLOT_FLT}, /* for passing mesh's smoothresh, used in hardening */
{"use_custom_profile", BMO_OP_SLOT_BOOL}, /* Whether to use custom profile feature */
/* the ProfileWiget struct for the custom profile shape */
{"custom_profile", BMO_OP_SLOT_PTR, {(int)BMO_OP_SLOT_SUBTYPE_PTR_STRUCT}},
{"vmesh_method", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM},
bmo_enum_bevel_vmesh_method},
{{'\0'}},
},
/* slots_out */

View File

@ -237,6 +237,7 @@ typedef enum eBMOpSlotSubType_Ptr {
BMO_OP_SLOT_SUBTYPE_PTR_SCENE = 101,
BMO_OP_SLOT_SUBTYPE_PTR_OBJECT = 102,
BMO_OP_SLOT_SUBTYPE_PTR_MESH = 103,
BMO_OP_SLOT_SUBTYPE_PTR_STRUCT = 104,
} eBMOpSlotSubType_Ptr;
typedef enum eBMOpSlotSubType_Int {
BMO_OP_SLOT_SUBTYPE_INT_ENUM = 200,
@ -294,8 +295,8 @@ typedef struct BMOpSlot {
BLI_assert(((slot >= (op)->slots_in) && (slot < &(op)->slots_in[BMO_OP_MAX_SLOTS])) || \
((slot >= (op)->slots_out) && (slot < &(op)->slots_out[BMO_OP_MAX_SLOTS])))
/* way more than probably needed, compiler complains if limit hit */
#define BMO_OP_MAX_SLOTS 20
/* Limit hit, so expanded for bevel operator. Compiler complains if limit is hit. */
#define BMO_OP_MAX_SLOTS 21
/* BMOpDefine->type_flag */
typedef enum {

View File

@ -126,6 +126,12 @@ enum {
BEVEL_MITER_ARC,
};
/* Bevel vertex mesh creation methods */
enum {
BEVEL_VMESH_ADJ,
BEVEL_VMESH_CUTOFF,
};
/* Normal Face Strength values */
enum {
FACE_STRENGTH_WEAK = -16384,

View File

@ -24,6 +24,8 @@
#include "bmesh.h"
#include "bmesh_tools.h"
#include "BKE_curveprofile.h"
#include "DNA_curveprofile_types.h"
#include "intern/bmesh_operators_private.h" /* own include */
@ -45,6 +47,9 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op)
const int miter_inner = BMO_slot_int_get(op->slots_in, "miter_inner");
const float spread = BMO_slot_float_get(op->slots_in, "spread");
const float smoothresh = BMO_slot_float_get(op->slots_in, "smoothresh");
const bool use_custom_profile = BMO_slot_bool_get(op->slots_in, "use_custom_profile");
const CurveProfile *custom_profile = BMO_slot_ptr_get(op->slots_in, "custom_profile");
const int vmesh_method = BMO_slot_int_get(op->slots_in, "vmesh_method");
if (offset > 0) {
BMOIter siter;
@ -87,7 +92,10 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op)
miter_outer,
miter_inner,
spread,
smoothresh);
smoothresh,
use_custom_profile,
custom_profile,
vmesh_method);
BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "faces.out", BM_FACE, BM_ELEM_TAG);
BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "edges.out", BM_EDGE, BM_ELEM_TAG);

File diff suppressed because it is too large Load Diff

View File

@ -21,6 +21,7 @@
* \ingroup bmesh
*/
struct CurveProfile;
struct MDeformVert;
void BM_mesh_bevel(BMesh *bm,
@ -42,6 +43,8 @@ void BM_mesh_bevel(BMesh *bm,
const int miter_outer,
const int miter_inner,
const float spread,
const float smoothresh);
const float smoothresh,
const bool use_custom_profile,
const struct CurveProfile *custom_profile,
const int vmesh_method);
#endif /* __BMESH_BEVEL_H__ */

View File

@ -346,6 +346,8 @@ typedef enum {
/** sphere widget (used to input a unit-vector, aka normal) */
UI_BTYPE_UNITVEC = 31 << 9,
UI_BTYPE_CURVE = 32 << 9,
/** Profile editing widget */
UI_BTYPE_CURVEPROFILE = 33 << 9,
UI_BTYPE_LISTBOX = 36 << 9,
UI_BTYPE_LISTROW = 37 << 9,
UI_BTYPE_HSVCIRCLE = 38 << 9,
@ -1973,6 +1975,7 @@ void uiTemplateCurveMapping(uiLayout *layout,
bool brush,
bool neg_slope,
bool tone);
void uiTemplateCurveProfile(uiLayout *layout, struct PointerRNA *ptr, const char *propname);
void uiTemplateColorPicker(uiLayout *layout,
struct PointerRNA *ptr,
const char *propname,

View File

@ -27,16 +27,21 @@
#include "DNA_color_types.h"
#include "DNA_screen_types.h"
#include "DNA_movieclip_types.h"
#include "DNA_curveprofile_types.h"
#include "BLI_math.h"
#include "BLI_rect.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
#include "BLI_polyfill_2d.h"
#include "MEM_guardedalloc.h"
#include "BKE_colorband.h"
#include "BKE_colortools.h"
#include "BKE_node.h"
#include "BKE_tracking.h"
#include "BKE_curveprofile.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@ -1814,6 +1819,8 @@ static void ui_draw_but_curve_grid(
immVertex2f(pos, rect->xmax, fy);
fy += dy;
}
/* Note: Assertion fails with here when the view is moved farther below the center.
* Missing two points from the number given with immBegin. */
immEnd();
}
@ -2113,6 +2120,231 @@ void ui_draw_but_CURVE(ARegion *ar, uiBut *but, const uiWidgetColors *wcol, cons
immUnbindProgram();
}
/** Used to draw a curve profile widget. Somewhat similar to ui_draw_but_CURVE */
void ui_draw_but_CURVEPROFILE(ARegion *ar,
uiBut *but,
const uiWidgetColors *wcol,
const rcti *rect)
{
uint i;
float fx, fy;
CurveProfile *profile;
if (but->editprofile) {
profile = but->editprofile;
}
else {
profile = (CurveProfile *)but->poin;
}
/* Calculate offset and zoom */
float zoomx = (BLI_rcti_size_x(rect) - 2.0f) / BLI_rctf_size_x(&profile->view_rect);
float zoomy = (BLI_rcti_size_y(rect) - 2.0f) / BLI_rctf_size_y(&profile->view_rect);
float offsx = profile->view_rect.xmin - (1.0f / zoomx);
float offsy = profile->view_rect.ymin - (1.0f / zoomy);
/* Exit early if too narrow */
if (zoomx == 0.0f) {
return;
}
/* Test needed because path can draw outside of boundary */
int scissor[4];
GPU_scissor_get_i(scissor);
rcti scissor_new = {
.xmin = rect->xmin,
.ymin = rect->ymin,
.xmax = rect->xmax,
.ymax = rect->ymax,
};
rcti scissor_region = {0, ar->winx, 0, ar->winy};
BLI_rcti_isect(&scissor_new, &scissor_region, &scissor_new);
GPU_scissor(scissor_new.xmin,
scissor_new.ymin,
BLI_rcti_size_x(&scissor_new),
BLI_rcti_size_y(&scissor_new));
GPU_line_width(1.0f);
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
/* Backdrop */
float color_backdrop[4] = {0, 0, 0, 1};
if (profile->flag & PROF_USE_CLIP) {
gl_shaded_color_get_fl((uchar *)wcol->inner, -20, color_backdrop);
immUniformColor3fv(color_backdrop);
immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
immUniformColor3ubv((uchar *)wcol->inner);
immRectf(pos,
rect->xmin + zoomx * (profile->clip_rect.xmin - offsx),
rect->ymin + zoomy * (profile->clip_rect.ymin - offsy),
rect->xmin + zoomx * (profile->clip_rect.xmax - offsx),
rect->ymin + zoomy * (profile->clip_rect.ymax - offsy));
}
else {
rgb_uchar_to_float(color_backdrop, (uchar *)wcol->inner);
immUniformColor3fv(color_backdrop);
immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
}
/* 0.25 step grid */
gl_shaded_color((uchar *)wcol->inner, -16);
ui_draw_but_curve_grid(pos, rect, zoomx, zoomy, offsx, offsy, 0.25f);
/* 1.0 step grid */
gl_shaded_color((uchar *)wcol->inner, -24);
ui_draw_but_curve_grid(pos, rect, zoomx, zoomy, offsx, offsy, 1.0f);
/* Draw the path's fill */
if (profile->table == NULL) {
BKE_curveprofile_update(profile, false);
}
CurveProfilePoint *pts = profile->table;
/* Also add the last points on the right and bottom edges to close off the fill polygon */
bool add_left_tri = profile->view_rect.xmin < 0.0f;
bool add_bottom_tri = profile->view_rect.ymin < 0.0f;
uint tot_points = (uint)PROF_N_TABLE(profile->path_len) + 1 + add_left_tri + add_bottom_tri;
uint tot_triangles = tot_points - 2;
/* Create array of the positions of the table's points */
float(*table_coords)[2] = MEM_mallocN(sizeof(*table_coords) * tot_points, "table x coords");
for (i = 0; i < (uint)PROF_N_TABLE(profile->path_len);
i++) { /* Only add the points from the table here */
table_coords[i][0] = pts[i].x;
table_coords[i][1] = pts[i].y;
}
if (add_left_tri && add_bottom_tri) {
/* Add left side, bottom left corner, and bottom side points */
table_coords[tot_points - 3][0] = profile->view_rect.xmin;
table_coords[tot_points - 3][1] = 1.0f;
table_coords[tot_points - 2][0] = profile->view_rect.xmin;
table_coords[tot_points - 2][1] = profile->view_rect.ymin;
table_coords[tot_points - 1][0] = 1.0f;
table_coords[tot_points - 1][1] = profile->view_rect.ymin;
}
else if (add_left_tri) {
/* Add the left side and bottom left corner points */
table_coords[tot_points - 2][0] = profile->view_rect.xmin;
table_coords[tot_points - 2][1] = 1.0f;
table_coords[tot_points - 1][0] = profile->view_rect.xmin;
table_coords[tot_points - 1][1] = 0.0f;
}
else if (add_bottom_tri) {
/* Add the bottom side and bottom left corner points */
table_coords[tot_points - 2][0] = 0.0f;
table_coords[tot_points - 2][1] = profile->view_rect.ymin;
table_coords[tot_points - 1][0] = 1.0f;
table_coords[tot_points - 1][1] = profile->view_rect.ymin;
}
else {
/* Just add the bottom corner point. Side points would be redundant anyway */
table_coords[tot_points - 1][0] = 0.0f;
table_coords[tot_points - 1][1] = 0.0f;
}
/* Calculate the table point indices of the triangles for the profile's fill */
uint(*tri_indices)[3] = MEM_mallocN(sizeof(*tri_indices) * tot_triangles, "return tri indices");
BLI_polyfill_calc(table_coords, tot_points, -1, tri_indices);
/* Draw the triangles for the profile fill */
immUniformColor3ubvAlpha((const uchar *)wcol->item, 128);
GPU_blend(true);
GPU_polygon_smooth(false);
immBegin(GPU_PRIM_TRIS, 3 * tot_triangles);
for (i = 0; i < tot_triangles; i++) {
for (uint j = 0; j < 3; j++) {
uint *tri = tri_indices[i];
fx = rect->xmin + zoomx * (table_coords[tri[j]][0] - offsx);
fy = rect->ymin + zoomy * (table_coords[tri[j]][1] - offsy);
immVertex2f(pos, fx, fy);
}
}
immEnd();
MEM_freeN(tri_indices);
/* Draw the profile's path so the edge stands out a bit */
tot_points -= (add_left_tri + add_left_tri);
GPU_line_width(1.0f);
immUniformColor3ubvAlpha((const uchar *)wcol->item, 255);
GPU_line_smooth(true);
immBegin(GPU_PRIM_LINE_STRIP, tot_points - 1);
for (i = 0; i < tot_points - 1; i++) {
fx = rect->xmin + zoomx * (table_coords[i][0] - offsx);
fy = rect->ymin + zoomy * (table_coords[i][1] - offsy);
immVertex2f(pos, fx, fy);
}
immEnd();
immUnbindProgram();
MEM_freeN(table_coords);
/* New GPU instructions for control points and sampled points. */
format = immVertexFormat();
pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
uint col = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
/* Calculate vertex colors based on text theme. */
float color_vert[4], color_vert_select[4], color_sample[4];
UI_GetThemeColor4fv(TH_TEXT_HI, color_vert);
UI_GetThemeColor4fv(TH_TEXT, color_vert_select);
color_sample[0] = (float)wcol->item[0] / 255.0f;
color_sample[1] = (float)wcol->item[1] / 255.0f;
color_sample[2] = (float)wcol->item[2] / 255.0f;
color_sample[3] = (float)wcol->item[3] / 255.0f;
if (len_squared_v3v3(color_vert, color_vert_select) < 0.1f) {
interp_v3_v3v3(color_vert, color_vert_select, color_backdrop, 0.75f);
}
if (len_squared_v3(color_vert) > len_squared_v3(color_vert_select)) {
/* Ensure brightest text color is used for selection. */
swap_v3_v3(color_vert, color_vert_select);
}
/* Draw the control points. */
pts = profile->path;
tot_points = (uint)profile->path_len;
GPU_line_smooth(false);
GPU_blend(false);
GPU_point_size(max_ff(3.0f, min_ff(UI_DPI_FAC / but->block->aspect * 5.0f, 5.0f)));
immBegin(GPU_PRIM_POINTS, tot_points);
for (i = 0; i < tot_points; i++) {
fx = rect->xmin + zoomx * (pts[i].x - offsx);
fy = rect->ymin + zoomy * (pts[i].y - offsy);
immAttr4fv(col, (pts[i].flag & PROF_SELECT) ? color_vert_select : color_vert);
immVertex2f(pos, fx, fy);
}
immEnd();
/* Draw the sampled points in addition to the control points if they have been created */
pts = profile->segments;
tot_points = (uint)profile->segments_len;
if (tot_points > 0 && pts) {
GPU_point_size(max_ff(2.0f, min_ff(UI_DPI_FAC / but->block->aspect * 3.0f, 3.0f)));
immBegin(GPU_PRIM_POINTS, tot_points);
for (i = 0; i < tot_points; i++) {
fx = rect->xmin + zoomx * (pts[i].x - offsx);
fy = rect->ymin + zoomy * (pts[i].y - offsy);
immAttr4fv(col, color_sample);
immVertex2f(pos, fx, fy);
}
immEnd();
}
immUnbindProgram();
/* restore scissortest */
GPU_scissor(scissor[0], scissor[1], scissor[2], scissor[3]);
/* Outline */
format = immVertexFormat();
pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
immUniformColor3ubv((const uchar *)wcol->outline);
imm_draw_box_wire_2d(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
immUnbindProgram();
}
void ui_draw_but_TRACKPREVIEW(ARegion *UNUSED(ar),
uiBut *but,
const uiWidgetColors *UNUSED(wcol),

View File

@ -32,7 +32,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_brush_types.h"
#include "DNA_curveprofile_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
@ -57,6 +57,7 @@
#include "BKE_tracking.h"
#include "BKE_unit.h"
#include "BKE_paint.h"
#include "BKE_curveprofile.h"
#include "IMB_colormanagement.h"
@ -442,6 +443,8 @@ static uiButMultiState *ui_multibut_lookup(uiHandleButtonData *data, const uiBut
static ColorBand but_copypaste_coba = {0};
static CurveMapping but_copypaste_curve = {0};
static bool but_copypaste_curve_alive = false;
static CurveProfile but_copypaste_profile = {0};
static bool but_copypaste_profile_alive = false;
/** \} */
@ -1080,6 +1083,13 @@ static void ui_apply_but_CURVE(bContext *C, uiBut *but, uiHandleButtonData *data
data->applied = true;
}
static void ui_apply_but_CURVEPROFILE(bContext *C, uiBut *but, uiHandleButtonData *data)
{
ui_apply_but_func(C, but);
data->retval = but->retval;
data->applied = true;
}
/** \} */
/* -------------------------------------------------------------------- */
@ -1979,6 +1989,7 @@ static void ui_apply_but(
float *editvec;
ColorBand *editcoba;
CurveMapping *editcumap;
CurveProfile *editprofile;
data->retval = 0;
@ -2036,11 +2047,13 @@ static void ui_apply_but(
editvec = but->editvec;
editcoba = but->editcoba;
editcumap = but->editcumap;
editprofile = but->editprofile;
but->editstr = NULL;
but->editval = NULL;
but->editvec = NULL;
but->editcoba = NULL;
but->editcumap = NULL;
but->editprofile = NULL;
/* handle different types */
switch (but->type) {
@ -2100,6 +2113,9 @@ static void ui_apply_but(
case UI_BTYPE_CURVE:
ui_apply_but_CURVE(C, but, data);
break;
case UI_BTYPE_CURVEPROFILE:
ui_apply_but_CURVEPROFILE(C, but, data);
break;
case UI_BTYPE_KEY_EVENT:
case UI_BTYPE_HOTKEY_EVENT:
ui_apply_but_BUT(C, but, data);
@ -2147,6 +2163,7 @@ static void ui_apply_but(
but->editvec = editvec;
but->editcoba = editcoba;
but->editcumap = editcumap;
but->editprofile = editprofile;
}
/** \} */
@ -2446,6 +2463,29 @@ static void ui_but_paste_curvemapping(bContext *C, uiBut *but)
}
}
static void ui_but_copy_CurveProfile(uiBut *but)
{
if (but->poin != NULL) {
but_copypaste_profile_alive = true;
BKE_curveprofile_free_data(&but_copypaste_profile);
BKE_curveprofile_copy_data(&but_copypaste_profile, (CurveProfile *)but->poin);
}
}
static void ui_but_paste_CurveProfile(bContext *C, uiBut *but)
{
if (but_copypaste_profile_alive) {
if (!but->poin) {
but->poin = MEM_callocN(sizeof(CurveProfile), "CurveProfile");
}
button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
BKE_curveprofile_free_data((CurveProfile *)but->poin);
BKE_curveprofile_copy_data((CurveProfile *)but->poin, &but_copypaste_profile);
button_activate_state(C, but, BUTTON_STATE_EXIT);
}
}
static void ui_but_copy_operator(bContext *C, uiBut *but, char *output, int output_len_max)
{
PointerRNA *opptr;
@ -2540,6 +2580,10 @@ static void ui_but_copy(bContext *C, uiBut *but, const bool copy_array)
ui_but_copy_curvemapping(but);
break;
case UI_BTYPE_CURVEPROFILE:
ui_but_copy_CurveProfile(but);
break;
case UI_BTYPE_BUT:
if (!but->optype) {
break;
@ -2623,6 +2667,10 @@ static void ui_but_paste(bContext *C, uiBut *but, uiHandleButtonData *data, cons
ui_but_paste_curvemapping(C, but);
break;
case UI_BTYPE_CURVEPROFILE:
ui_but_paste_CurveProfile(C, but);
break;
default:
break;
}
@ -2633,6 +2681,7 @@ static void ui_but_paste(bContext *C, uiBut *but, uiHandleButtonData *data, cons
void ui_but_clipboard_free(void)
{
BKE_curvemapping_free_data(&but_copypaste_curve);
BKE_curveprofile_free_data(&but_copypaste_profile);
}
/** \} */
@ -3757,6 +3806,9 @@ static void ui_numedit_begin(uiBut *but, uiHandleButtonData *data)
if (but->type == UI_BTYPE_CURVE) {
but->editcumap = (CurveMapping *)but->poin;
}
if (but->type == UI_BTYPE_CURVEPROFILE) {
but->editprofile = (CurveProfile *)but->poin;
}
else if (but->type == UI_BTYPE_COLORBAND) {
data->coba = (ColorBand *)but->poin;
but->editcoba = data->coba;
@ -3847,6 +3899,7 @@ static void ui_numedit_end(uiBut *but, uiHandleButtonData *data)
but->editvec = NULL;
but->editcoba = NULL;
but->editcumap = NULL;
but->editprofile = NULL;
data->dragstartx = 0;
data->draglastx = 0;
@ -6803,6 +6856,281 @@ static int ui_do_but_CURVE(
return WM_UI_HANDLER_CONTINUE;
}
/* Same as ui_numedit_but_CURVE with some smaller changes. */
static bool ui_numedit_but_CURVEPROFILE(uiBlock *block,
uiBut *but,
uiHandleButtonData *data,
int evtx,
int evty,
bool snap,
const bool shift)
{
CurveProfile *profile = (CurveProfile *)but->poin;
CurveProfilePoint *pts = profile->path;
float fx, fy, zoomx, zoomy;
int mx, my, dragx, dragy;
int a;
bool changed = false;
/* evtx evty and drag coords are absolute mousecoords,
* prevents errors when editing when layout changes */
mx = evtx;
my = evty;
ui_window_to_block(data->region, block, &mx, &my);
dragx = data->draglastx;
dragy = data->draglasty;
ui_window_to_block(data->region, block, &dragx, &dragy);
zoomx = BLI_rctf_size_x(&but->rect) / BLI_rctf_size_x(&profile->view_rect);
zoomy = BLI_rctf_size_y(&but->rect) / BLI_rctf_size_y(&profile->view_rect);
if (snap) {
float d[2];
d[0] = mx - data->dragstartx;
d[1] = my - data->dragstarty;
if (len_squared_v2(d) < (3.0f * 3.0f)) {
snap = false;
}
}
fx = (mx - dragx) / zoomx;
fy = (my - dragy) / zoomy;
if (data->dragsel != -1) {
CurveProfilePoint *point_last = NULL;
const float mval_factor = ui_mouse_scale_warp_factor(shift);
bool moved_point = false; /* for ctrl grid, can't use orig coords because of sorting */
fx *= mval_factor;
fy *= mval_factor;
/* Move all the points that aren't the last or the first */
for (a = 1; a < profile->path_len - 1; a++) {
if (pts[a].flag & PROF_SELECT) {
float origx = pts[a].x, origy = pts[a].y;
pts[a].x += fx;
pts[a].y += fy;
if (snap) {
pts[a].x = 0.125f * roundf(8.0f * pts[a].x);
pts[a].y = 0.125f * roundf(8.0f * pts[a].y);
}
if (!moved_point && (pts[a].x != origx || pts[a].y != origy)) {
moved_point = true;
}
point_last = &pts[a];
}
}
BKE_curveprofile_update(profile, false);
if (moved_point) {
data->draglastx = evtx;
data->draglasty = evty;
changed = true;
#ifdef USE_CONT_MOUSE_CORRECT
/* note: using 'cmp_last' is weak since there may be multiple points selected,
* but in practice this isnt really an issue */
if (ui_but_is_cursor_warp(but)) {
/* OK but can go outside bounds */
data->ungrab_mval[0] = but->rect.xmin + ((point_last->x - profile->view_rect.xmin) * zoomx);
data->ungrab_mval[1] = but->rect.ymin + ((point_last->y - profile->view_rect.ymin) * zoomy);
BLI_rctf_clamp_pt_v(&but->rect, data->ungrab_mval);
}
#endif
}
data->dragchange = true; /* mark for selection */
}
else {
/* clamp for clip */
if (profile->flag & PROF_USE_CLIP) {
if (profile->view_rect.xmin - fx < profile->clip_rect.xmin) {
fx = profile->view_rect.xmin - profile->clip_rect.xmin;
}
else if (profile->view_rect.xmax - fx > profile->clip_rect.xmax) {
fx = profile->view_rect.xmax - profile->clip_rect.xmax;
}
if (profile->view_rect.ymin - fy < profile->clip_rect.ymin) {
fy = profile->view_rect.ymin - profile->clip_rect.ymin;
}
else if (profile->view_rect.ymax - fy > profile->clip_rect.ymax) {
fy = profile->view_rect.ymax - profile->clip_rect.ymax;
}
}
profile->view_rect.xmin -= fx;
profile->view_rect.ymin -= fy;
profile->view_rect.xmax -= fx;
profile->view_rect.ymax -= fy;
data->draglastx = evtx;
data->draglasty = evty;
changed = true;
}
return changed;
}
/** Interaction for curve profile widget.
* \note Uses hardcoded keys rather than the keymap. */
static int ui_do_but_CURVEPROFILE(
bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
{
int mx, my, i;
mx = event->x;
my = event->y;
ui_window_to_block(data->region, block, &mx, &my);
/* Move selected control points. */
if (event->type == GKEY && event->val == KM_RELEASE) {
data->dragstartx = mx;
data->dragstarty = my;
data->draglastx = mx;
data->draglasty = my;
button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
return WM_UI_HANDLER_BREAK;
}
CurveProfile *profile = (CurveProfile *)but->poin;
/* Delete selected control points. */
if (event->type == XKEY && event->val == KM_RELEASE) {
BKE_curveprofile_remove_by_flag(profile, PROF_SELECT);
BKE_curveprofile_update(profile, false);
button_activate_state(C, but, BUTTON_STATE_EXIT);
return WM_UI_HANDLER_BREAK;
}
/* Selecting, adding, and starting point movements. */
if (data->state == BUTTON_STATE_HIGHLIGHT) {
if (event->type == LEFTMOUSE && event->val == KM_PRESS) {
CurveProfilePoint *pts; /* Path or table. */
const float m_xy[2] = {mx, my};
float dist_min_sq;
int i_selected = -1;
if (event->ctrl) {
float f_xy[2];
BLI_rctf_transform_pt_v(&profile->view_rect, &but->rect, f_xy, m_xy);
BKE_curveprofile_insert(profile, f_xy[0], f_xy[1]);
BKE_curveprofile_update(profile, false);
}
/* Check for selecting of a point by finding closest point in radius. */
dist_min_sq = SQUARE(U.dpi_fac * 14.0f); /* 14 pixels radius for selecting points. */
pts = profile->path;
for (i = 0; i < profile->path_len; i++) {
float f_xy[2];
BLI_rctf_transform_pt_v(&but->rect, &profile->view_rect, f_xy, &pts[i].x);
const float dist_sq = len_squared_v2v2(m_xy, f_xy);
if (dist_sq < dist_min_sq) {
i_selected = i;
dist_min_sq = dist_sq;
}
}
/* Add a point if the click was close to the path but not a control point. */
if (i_selected == -1) { /* No control point selected. */
float f_xy[2], f_xy_prev[2];
pts = profile->table;
BLI_rctf_transform_pt_v(&but->rect, &profile->view_rect, f_xy, &pts[0].x);
dist_min_sq = SQUARE(U.dpi_fac * 8.0f); /* 8 pixel radius from each table point. */
/* Loop through the path's high resolution table and find what's near the click. */
for (i = 1; i <= PROF_N_TABLE(profile->path_len); i++) {
copy_v2_v2(f_xy_prev, f_xy);
BLI_rctf_transform_pt_v(&but->rect, &profile->view_rect, f_xy, &pts[i].x);
if (dist_squared_to_line_segment_v2(m_xy, f_xy_prev, f_xy) < dist_min_sq) {
BLI_rctf_transform_pt_v(&profile->view_rect, &but->rect, f_xy, m_xy);
CurveProfilePoint *new_pt = BKE_curveprofile_insert(profile, f_xy[0], f_xy[1]);
BKE_curveprofile_update(profile, false);
/* reset pts back to the control points. */
pts = profile->path;
/* Get the index of the newly added point. */
for (i = 0; i < profile->path_len; i++) {
if (&pts[i] == new_pt) {
i_selected = i;
}
}
break;
}
}
}
/* Change the flag for the point(s) if one was selected. */
if (i_selected != -1) {
/* Deselect all if this one is deselected, except if we hold shift. */
if (!event->shift) {
for (i = 0; i < profile->path_len; i++) {
pts[i].flag &= ~PROF_SELECT;
}
pts[i_selected].flag |= PROF_SELECT;
}
else {
pts[i_selected].flag ^= PROF_SELECT;
}
}
else {
/* Move the view. */
data->cancel = true;
}
data->dragsel = i_selected;
data->dragstartx = mx;
data->dragstarty = my;
data->draglastx = mx;
data->draglasty = my;
button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
return WM_UI_HANDLER_BREAK;
}
}
else if (data->state == BUTTON_STATE_NUM_EDITING) { /* Do control point movement. */
if (event->type == MOUSEMOVE) {
if (mx != data->draglastx || my != data->draglasty) {
if (ui_numedit_but_CURVEPROFILE(
block, but, data, mx, my, event->ctrl != 0, event->shift != 0)) {
ui_numedit_apply(C, block, but, data);
}
}
}
else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
/* Finish move. */
if (data->dragsel != -1) {
CurveProfilePoint *pts = profile->path;
if (data->dragchange == false) {
/* Deselect all, select one. */
if (!event->shift) {
for (i = 0; i < profile->path_len; i++) {
pts[i].flag &= ~PROF_SELECT;
}
pts[data->dragsel].flag |= PROF_SELECT;
}
}
else {
BKE_curveprofile_update(profile, true); /* Remove doubles after move. */
}
}
button_activate_state(C, but, BUTTON_STATE_EXIT);
}
return WM_UI_HANDLER_BREAK;
}
return WM_UI_HANDLER_CONTINUE;
}
static bool ui_numedit_but_HISTOGRAM(uiBut *but, uiHandleButtonData *data, int mx, int my)
{
Histogram *hist = (Histogram *)but->poin;
@ -7208,6 +7536,9 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
case UI_BTYPE_CURVE:
retval = ui_do_but_CURVE(C, block, but, data, event);
break;
case UI_BTYPE_CURVEPROFILE:
retval = ui_do_but_CURVEPROFILE(C, block, but, data, event);
break;
case UI_BTYPE_HSVCUBE:
retval = ui_do_but_HSVCUBE(C, block, but, data, event);
break;
@ -7599,7 +7930,7 @@ static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonA
copy_v2_fl(data->ungrab_mval, FLT_MAX);
#endif
if (ELEM(but->type, UI_BTYPE_CURVE, UI_BTYPE_SEARCH_MENU)) {
if (ELEM(but->type, UI_BTYPE_CURVE, UI_BTYPE_CURVEPROFILE, UI_BTYPE_SEARCH_MENU)) {
/* XXX curve is temp */
}
else {

View File

@ -274,6 +274,7 @@ struct uiBut {
float *editvec;
void *editcoba;
void *editcumap;
void *editprofile;
uiButPushedStateFunc pushed_state_func;
void *pushed_state_arg;
@ -740,6 +741,10 @@ void ui_draw_but_CURVE(ARegion *ar,
uiBut *but,
const struct uiWidgetColors *wcol,
const rcti *rect);
void ui_draw_but_CURVEPROFILE(ARegion *ar,
uiBut *but,
const struct uiWidgetColors *wcol,
const rcti *rect);
void ui_draw_but_IMAGE(ARegion *ar,
uiBut *but,
const struct uiWidgetColors *wcol,

View File

@ -422,7 +422,8 @@ bool ui_but_is_cursor_warp(const uiBut *but)
UI_BTYPE_HSVCIRCLE,
UI_BTYPE_TRACK_PREVIEW,
UI_BTYPE_HSVCUBE,
UI_BTYPE_CURVE)) {
UI_BTYPE_CURVE,
UI_BTYPE_CURVEPROFILE)) {
return true;
}
}

View File

@ -35,6 +35,7 @@
#include "DNA_texture_types.h"
#include "DNA_gpencil_modifier_types.h"
#include "DNA_shader_fx_types.h"
#include "DNA_curveprofile_types.h"
#include "BLI_utildefines.h"
#include "BLI_alloca.h"
@ -69,6 +70,7 @@
#include "BKE_packedFile.h"
#include "BKE_paint.h"
#include "BKE_particle.h"
#include "BKE_curveprofile.h"
#include "BKE_report.h"
#include "BKE_screen.h"
#include "BKE_shader_fx.h"
@ -4504,6 +4506,612 @@ void uiTemplateCurveMapping(uiLayout *layout,
/** \} */
/* -------------------------------------------------------------------- */
/** \name Curve Profile Template
* \{ */
static void CurveProfile_presets_dofunc(bContext *C, void *profile_v, int event)
{
CurveProfile *profile = profile_v;
profile->preset = event;
BKE_curveprofile_reset(profile);
BKE_curveprofile_update(profile, false);
ED_undo_push(C, "CurveProfile tools");
ED_region_tag_redraw(CTX_wm_region(C));
}
static uiBlock *CurveProfile_presets_func(bContext *C, ARegion *ar, CurveProfile *profile)
{
uiBlock *block;
short yco = 0;
short menuwidth = 12 * UI_UNIT_X;
menuwidth = 0;
block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
UI_block_func_butmenu_set(block, CurveProfile_presets_dofunc, profile);
uiDefIconTextBut(block,
UI_BTYPE_BUT_MENU,
1,
ICON_BLANK1,
IFACE_("Default"),
0,
yco -= UI_UNIT_Y,
menuwidth,
UI_UNIT_Y,
NULL,
0.0,
0.0,
0,
PROF_PRESET_LINE,
"");
uiDefIconTextBut(block,
UI_BTYPE_BUT_MENU,
1,
ICON_BLANK1,
IFACE_("Support Loops"),
0,
yco -= UI_UNIT_Y,
menuwidth,
UI_UNIT_Y,
NULL,
0.0,
0.0,
0,
PROF_PRESET_SUPPORTS,
"");
uiDefIconTextBut(block,
UI_BTYPE_BUT_MENU,
1,
ICON_BLANK1,
IFACE_("Cornice Moulding"),
0,
yco -= UI_UNIT_Y,
menuwidth,
UI_UNIT_Y,
NULL,
0.0,
0.0,
0,
PROF_PRESET_CORNICE,
"");
uiDefIconTextBut(block,
UI_BTYPE_BUT_MENU,
1,
ICON_BLANK1,
IFACE_("Crown Moulding"),
0,
yco -= UI_UNIT_Y,
menuwidth,
UI_UNIT_Y,
NULL,
0.0,
0.0,
0,
PROF_PRESET_CROWN,
"");
uiDefIconTextBut(block,
UI_BTYPE_BUT_MENU,
1,
ICON_BLANK1,
IFACE_("Steps"),
0,
yco -= UI_UNIT_Y,
menuwidth,
UI_UNIT_Y,
NULL,
0.0,
0.0,
0,
PROF_PRESET_STEPS,
"");
UI_block_direction_set(block, UI_DIR_DOWN);
UI_block_bounds_set_text(block, (int)(3.0f * UI_UNIT_X));
return block;
}
static uiBlock *CurveProfile_buttons_presets(bContext *C, ARegion *ar, void *profile_v)
{
return CurveProfile_presets_func(C, ar, (CurveProfile *)profile_v);
}
/* Only for CurveProfile tools block */
enum {
UIPROFILE_FUNC_RESET,
UIPROFILE_FUNC_RESET_VIEW,
};
static void CurveProfile_tools_dofunc(bContext *C, void *profile_v, int event)
{
CurveProfile *profile = profile_v;
switch (event) {
case UIPROFILE_FUNC_RESET: /* reset */
BKE_curveprofile_reset(profile);
BKE_curveprofile_update(profile, false);
break;
case UIPROFILE_FUNC_RESET_VIEW: /* reset view to clipping rect */
profile->view_rect = profile->clip_rect;
break;
}
ED_undo_push(C, "CurveProfile tools");
ED_region_tag_redraw(CTX_wm_region(C));
}
static uiBlock *CurveProfile_tools_func(bContext *C, ARegion *ar, CurveProfile *profile)
{
uiBlock *block;
short yco = 0;
short menuwidth = 10 * UI_UNIT_X;
block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
UI_block_func_butmenu_set(block, CurveProfile_tools_dofunc, profile);
uiDefIconTextBut(block,
UI_BTYPE_BUT_MENU,
1,
ICON_BLANK1,
IFACE_("Reset View"),
0,
yco -= UI_UNIT_Y,
menuwidth,
UI_UNIT_Y,
NULL,
0.0,
0.0,
0,
UIPROFILE_FUNC_RESET_VIEW,
"");
uiDefIconTextBut(block,
UI_BTYPE_BUT_MENU,
1,
ICON_BLANK1,
IFACE_("Reset Curve"),
0,
yco -= UI_UNIT_Y,
menuwidth,
UI_UNIT_Y,
NULL,
0.0,
0.0,
0,
UIPROFILE_FUNC_RESET,
"");
UI_block_direction_set(block, UI_DIR_DOWN);
UI_block_bounds_set_text(block, (int)(3.0f * UI_UNIT_X));
return block;
}
static uiBlock *CurveProfile_buttons_tools(bContext *C, ARegion *ar, void *profile_v)
{
return CurveProfile_tools_func(C, ar, (CurveProfile *)profile_v);
}
static void CurveProfile_buttons_zoom_in(bContext *C, void *profile_v, void *UNUSED(arg))
{
CurveProfile *profile = profile_v;
float d;
/* we allow 20 times zoom */
if (BLI_rctf_size_x(&profile->view_rect) > 0.04f * BLI_rctf_size_x(&profile->clip_rect)) {
d = 0.1154f * BLI_rctf_size_x(&profile->view_rect);
profile->view_rect.xmin += d;
profile->view_rect.xmax -= d;
d = 0.1154f * BLI_rctf_size_y(&profile->view_rect);
profile->view_rect.ymin += d;
profile->view_rect.ymax -= d;
}
ED_region_tag_redraw(CTX_wm_region(C));
}
static void CurveProfile_buttons_zoom_out(bContext *C, void *profile_v, void *UNUSED(arg))
{
CurveProfile *profile = profile_v;
float d, d1;
/* Allow 20 times zoom, but don't view outside clip */
if (BLI_rctf_size_x(&profile->view_rect) < 20.0f * BLI_rctf_size_x(&profile->clip_rect)) {
d = d1 = 0.15f * BLI_rctf_size_x(&profile->view_rect);
if (profile->flag & PROF_USE_CLIP) {
if (profile->view_rect.xmin - d < profile->clip_rect.xmin) {
d1 = profile->view_rect.xmin - profile->clip_rect.xmin;
}
}
profile->view_rect.xmin -= d1;
d1 = d;
if (profile->flag & PROF_USE_CLIP) {
if (profile->view_rect.xmax + d > profile->clip_rect.xmax) {
d1 = -profile->view_rect.xmax + profile->clip_rect.xmax;
}
}
profile->view_rect.xmax += d1;
d = d1 = 0.15f * BLI_rctf_size_y(&profile->view_rect);
if (profile->flag & PROF_USE_CLIP) {
if (profile->view_rect.ymin - d < profile->clip_rect.ymin) {
d1 = profile->view_rect.ymin - profile->clip_rect.ymin;
}
}
profile->view_rect.ymin -= d1;
d1 = d;
if (profile->flag & PROF_USE_CLIP) {
if (profile->view_rect.ymax + d > profile->clip_rect.ymax) {
d1 = -profile->view_rect.ymax + profile->clip_rect.ymax;
}
}
profile->view_rect.ymax += d1;
}
ED_region_tag_redraw(CTX_wm_region(C));
}
static void CurveProfile_clipping_toggle(bContext *C, void *cb_v, void *profile_v)
{
CurveProfile *profile = profile_v;
profile->flag ^= PROF_USE_CLIP;
BKE_curveprofile_update(profile, false);
rna_update_cb(C, cb_v, NULL);
}
static void CurveProfile_buttons_reverse(bContext *C, void *cb_v, void *profile_v)
{
CurveProfile *profile = profile_v;
BKE_curveprofile_reverse(profile);
BKE_curveprofile_update(profile, false);
rna_update_cb(C, cb_v, NULL);
}
static void CurveProfile_buttons_delete(bContext *C, void *cb_v, void *profile_v)
{
CurveProfile *profile = profile_v;
BKE_curveprofile_remove_by_flag(profile, SELECT);
BKE_curveprofile_update(profile, false);
rna_update_cb(C, cb_v, NULL);
}
static void CurveProfile_buttons_setsharp(bContext *C, void *cb_v, void *profile_v)
{
CurveProfile *profile = profile_v;
BKE_curveprofile_selected_handle_set(profile, HD_VECT, HD_VECT);
BKE_curveprofile_update(profile, false);
rna_update_cb(C, cb_v, NULL);
}
static void CurveProfile_buttons_setcurved(bContext *C, void *cb_v, void *profile_v)
{
CurveProfile *profile = profile_v;
BKE_curveprofile_selected_handle_set(profile, HD_AUTO, HD_AUTO);
BKE_curveprofile_update(profile, false);
rna_update_cb(C, cb_v, NULL);
}
static void CurveProfile_buttons_update(bContext *C, void *arg1_v, void *profile_v)
{
CurveProfile *profile = profile_v;
BKE_curveprofile_update(profile, true);
rna_update_cb(C, arg1_v, NULL);
}
static void CurveProfile_buttons_layout(uiLayout *layout, PointerRNA *ptr, RNAUpdateCb *cb)
{
CurveProfile *profile = ptr->data;
CurveProfilePoint *point = NULL;
uiLayout *row, *sub;
uiBlock *block;
uiBut *bt;
int i, icon, path_width, path_height;
bool point_last_or_first = false;
rctf bounds;
block = uiLayoutGetBlock(layout);
UI_block_emboss_set(block, UI_EMBOSS);
uiLayoutRow(layout, false);
/* Preset selector */
/* There is probably potential to use simpler "uiItemR" functions here, but automatic updating
* after a preset is selected would be more complicated. */
bt = uiDefBlockBut(
block, CurveProfile_buttons_presets, profile, "Preset", 0, 0, UI_UNIT_X, UI_UNIT_X, "");
UI_but_funcN_set(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
row = uiLayoutRow(layout, false);
/* (Left aligned) */
sub = uiLayoutRow(row, true);
uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT);
/* Zoom in */
bt = uiDefIconBut(block,
UI_BTYPE_BUT,
0,
ICON_ZOOM_IN,
0,
0,
UI_UNIT_X,
UI_UNIT_X,
NULL,
0.0,
0.0,
0.0,
0.0,
TIP_("Zoom in"));
UI_but_func_set(bt, CurveProfile_buttons_zoom_in, profile, NULL);
/* Zoom out */
bt = uiDefIconBut(block,
UI_BTYPE_BUT,
0,
ICON_ZOOM_OUT,
0,
0,
UI_UNIT_X,
UI_UNIT_X,
NULL,
0.0,
0.0,
0.0,
0.0,
TIP_("Zoom out"));
UI_but_func_set(bt, CurveProfile_buttons_zoom_out, profile, NULL);
/* (Right aligned) */
sub = uiLayoutRow(row, true);
uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_RIGHT);
/* Reset view, reset curve */
bt = uiDefIconBlockBut(
block, CurveProfile_buttons_tools, profile, 0, 0, 0, 0, UI_UNIT_X, UI_UNIT_X, TIP_("Tools"));
UI_but_funcN_set(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
/* Flip path */
bt = uiDefIconBut(block,
UI_BTYPE_BUT,
0,
ICON_ARROW_LEFTRIGHT,
0,
0,
UI_UNIT_X,
UI_UNIT_X,
NULL,
0.0,
0.0,
0.0,
0.0,
TIP_("Reverse Path"));
UI_but_funcN_set(bt, CurveProfile_buttons_reverse, MEM_dupallocN(cb), profile);
/* Clipping toggle */
icon = (profile->flag & PROF_USE_CLIP) ? ICON_CLIPUV_HLT : ICON_CLIPUV_DEHLT;
bt = uiDefIconBut(block,
UI_BTYPE_BUT,
0,
icon,
0,
0,
UI_UNIT_X,
UI_UNIT_X,
NULL,
0.0,
0.0,
0.0,
0.0,
TIP_("Toggle Profile Clipping"));
UI_but_funcN_set(bt, CurveProfile_clipping_toggle, MEM_dupallocN(cb), profile);
UI_block_funcN_set(block, rna_update_cb, MEM_dupallocN(cb), NULL);
/* The path itself */
path_width = max_ii(uiLayoutGetWidth(layout), UI_UNIT_X);
path_width = min_ii(path_width, (int)(16.0f * UI_UNIT_X));
path_height = path_width;
uiLayoutRow(layout, false);
uiDefBut(block,
UI_BTYPE_CURVEPROFILE,
0,
"",
0,
0,
(short)path_width,
(short)path_height,
profile,
0.0f,
1.0f,
-1,
0,
"");
/* Position sliders for (first) selected point */
for (i = 0; i < profile->path_len; i++) {
if (profile->path[i].flag & PROF_SELECT) {
point = &profile->path[i];
break;
}
}
if (i == 0 || i == profile->path_len - 1) {
point_last_or_first = true;
}
/* Selected point data */
if (point) {
if (profile->flag & PROF_USE_CLIP) {
bounds = profile->clip_rect;
}
else {
bounds.xmin = bounds.ymin = -1000.0;
bounds.xmax = bounds.ymax = 1000.0;
}
uiLayoutRow(layout, true);
UI_block_funcN_set(block, CurveProfile_buttons_update, MEM_dupallocN(cb), profile);
/* Sharp / Smooth */
bt = uiDefIconBut(block,
UI_BTYPE_BUT,
0,
ICON_LINCURVE,
0,
0,
UI_UNIT_X,
UI_UNIT_X,
NULL,
0.0,
0.0,
0.0,
0.0,
TIP_("Set the point's handle type to sharp."));
if (point_last_or_first) {
UI_but_flag_enable(bt, UI_BUT_DISABLED);
}
UI_but_funcN_set(bt, CurveProfile_buttons_setsharp, MEM_dupallocN(cb), profile);
bt = uiDefIconBut(block,
UI_BTYPE_BUT,
0,
ICON_SMOOTHCURVE,
0,
0,
UI_UNIT_X,
UI_UNIT_X,
NULL,
0.0,
0.0,
0.0,
0.0,
TIP_("Set the point's handle type to sharp."));
UI_but_funcN_set(bt, CurveProfile_buttons_setcurved, MEM_dupallocN(cb), profile);
if (point_last_or_first) {
UI_but_flag_enable(bt, UI_BUT_DISABLED);
}
/* Position */
bt = uiDefButF(block,
UI_BTYPE_NUM,
0,
"X:",
0,
2 * UI_UNIT_Y,
UI_UNIT_X * 10,
UI_UNIT_Y,
&point->x,
bounds.xmin,
bounds.xmax,
1,
5,
"");
if (point_last_or_first) {
UI_but_flag_enable(bt, UI_BUT_DISABLED);
}
bt = uiDefButF(block,
UI_BTYPE_NUM,
0,
"Y:",
0,
1 * UI_UNIT_Y,
UI_UNIT_X * 10,
UI_UNIT_Y,
&point->y,
bounds.ymin,
bounds.ymax,
1,
5,
"");
if (point_last_or_first) {
UI_but_flag_enable(bt, UI_BUT_DISABLED);
}
/* Delete points */
bt = uiDefIconBut(block,
UI_BTYPE_BUT,
0,
ICON_X,
0,
0,
UI_UNIT_X,
UI_UNIT_X,
NULL,
0.0,
0.0,
0.0,
0.0,
TIP_("Delete points"));
UI_but_funcN_set(bt, CurveProfile_buttons_delete, MEM_dupallocN(cb), profile);
if (point_last_or_first) {
UI_but_flag_enable(bt, UI_BUT_DISABLED);
}
}
uiItemR(layout, ptr, "use_sample_straight_edges", 0, NULL, ICON_NONE);
uiItemR(layout, ptr, "use_sample_even_lengths", 0, NULL, ICON_NONE);
UI_block_funcN_set(block, NULL, NULL, NULL);
}
/** Template for a path creation widget intended for custom bevel profiles.
* This section is quite similar to uiTemplateCurveMapping, but with reduced complexity */
void uiTemplateCurveProfile(uiLayout *layout, PointerRNA *ptr, const char *propname)
{
RNAUpdateCb *cb;
PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
PointerRNA cptr;
ID *id;
uiBlock *block = uiLayoutGetBlock(layout);
if (!prop) {
RNA_warning(
"Curve Profile property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
return;
}
if (RNA_property_type(prop) != PROP_POINTER) {
RNA_warning(
"Curve Profile is not a pointer: %s.%s", RNA_struct_identifier(ptr->type), propname);
return;
}
cptr = RNA_property_pointer_get(ptr, prop);
if (!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_CurveProfile)) {
return;
}
/* Share update functionality with the CurveMapping widget template. */
cb = MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
cb->ptr = *ptr;
cb->prop = prop;
id = cptr.owner_id;
UI_block_lock_set(block, (id && ID_IS_LINKED(id)), ERROR_LIBDATA_MESSAGE);
CurveProfile_buttons_layout(layout, &cptr, cb);
UI_block_lock_clear(block);
MEM_freeN(cb);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name ColorPicker Template
* \{ */

View File

@ -4774,6 +4774,10 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
ui_draw_but_CURVE(ar, but, &tui->wcol_regular, rect);
break;
case UI_BTYPE_CURVEPROFILE:
ui_draw_but_CURVEPROFILE(ar, but, &tui->wcol_regular, rect);
break;
case UI_BTYPE_PROGRESS_BAR:
wt = widget_type(UI_WTYPE_PROGRESSBAR);
fstyle = &style->widgetlabel;

View File

@ -33,8 +33,10 @@
#include "BKE_unit.h"
#include "BKE_layer.h"
#include "BKE_mesh.h"
#include "BKE_curveprofile.h"
#include "DNA_mesh_types.h"
#include "DNA_curveprofile_types.h"
#include "RNA_define.h"
#include "RNA_access.h"
@ -43,6 +45,7 @@
#include "WM_types.h"
#include "UI_interface.h"
#include "UI_resources.h"
#include "ED_mesh.h"
#include "ED_numinput.h"
@ -96,6 +99,8 @@ typedef struct {
short gizmo_flag;
short value_mode; /* Which value does mouse movement and numeric input affect? */
float segments; /* Segments as float so smooth mouse pan works in small increments */
CurveProfile *custom_profile;
} BevelData;
enum {
@ -114,6 +119,8 @@ enum {
BEV_MODAL_MARK_SHARP_TOGGLE,
BEV_MODAL_OUTER_MITER_CHANGE,
BEV_MODAL_INNER_MITER_CHANGE,
BEV_MODAL_CUSTOM_PROFILE_TOGGLE,
BEV_MODAL_VERTEX_MESH_CHANGE,
};
static float get_bevel_offset(wmOperator *op)
@ -129,15 +136,15 @@ static float get_bevel_offset(wmOperator *op)
return val;
}
static void edbm_bevel_update_header(bContext *C, wmOperator *op)
static void edbm_bevel_update_status_text(bContext *C, wmOperator *op)
{
char header[UI_MAX_DRAW_STR];
char status_text[UI_MAX_DRAW_STR];
char buf[UI_MAX_DRAW_STR];
char *p = buf;
int available_len = sizeof(buf);
Scene *sce = CTX_data_scene(C);
char offset_str[NUM_STR_REP_LEN];
const char *mode_str, *omiter_str, *imiter_str;
const char *mode_str, *omiter_str, *imiter_str, *vmesh_str;
PropertyRNA *prop;
#define WM_MODALKEY(_id) \
@ -167,22 +174,27 @@ static void edbm_bevel_update_header(bContext *C, wmOperator *op)
prop = RNA_struct_find_property(op->ptr, "miter_inner");
RNA_property_enum_name_gettexted(
C, op->ptr, prop, RNA_property_enum_get(op->ptr, prop), &imiter_str);
prop = RNA_struct_find_property(op->ptr, "vmesh_method");
RNA_property_enum_name_gettexted(
C, op->ptr, prop, RNA_property_enum_get(op->ptr, prop), &vmesh_str);
BLI_snprintf(header,
sizeof(header),
TIP_("%s: confirm, "
"%s: cancel, "
"%s: mode (%s), "
"%s: width (%s), "
"%s: segments (%d), "
"%s: profile (%.3f), "
"%s: clamp overlap (%s), "
"%s: vertex only (%s), "
"%s: outer miter (%s), "
"%s: inner miter (%s), "
"%s: harden normals (%s), "
"%s: mark seam (%s), "
"%s: mark sharp (%s)"),
BLI_snprintf(status_text,
sizeof(status_text),
TIP_("%s: Confirm, "
"%s: Cancel, "
"%s: Mode (%s), "
"%s: Width (%s), "
"%s: Segments (%d), "
"%s: Profile (%.3f), "
"%s: Clamp Overlap (%s), "
"%s: Vertex Only (%s), "
"%s: Outer Miter (%s), "
"%s: Inner Miter (%s), "
"%s: Harden Normals (%s), "
"%s: Mark Seam (%s), "
"%s: Mark Sharp (%s), "
"%s: Custom Profile (%s), "
"%s: Intersection (%s)"),
WM_MODALKEY(BEV_MODAL_CONFIRM),
WM_MODALKEY(BEV_MODAL_CANCEL),
WM_MODALKEY(BEV_MODAL_OFFSET_MODE_CHANGE),
@ -206,16 +218,21 @@ static void edbm_bevel_update_header(bContext *C, wmOperator *op)
WM_MODALKEY(BEV_MODAL_MARK_SEAM_TOGGLE),
WM_bool_as_string(RNA_boolean_get(op->ptr, "mark_seam")),
WM_MODALKEY(BEV_MODAL_MARK_SHARP_TOGGLE),
WM_bool_as_string(RNA_boolean_get(op->ptr, "mark_sharp")));
WM_bool_as_string(RNA_boolean_get(op->ptr, "mark_sharp")),
WM_MODALKEY(BEV_MODAL_CUSTOM_PROFILE_TOGGLE),
WM_bool_as_string(RNA_boolean_get(op->ptr, "use_custom_profile")),
WM_MODALKEY(BEV_MODAL_VERTEX_MESH_CHANGE),
vmesh_str);
#undef WM_MODALKEY
ED_workspace_status_text(C, header);
ED_workspace_status_text(C, status_text);
}
static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal)
{
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = CTX_data_tool_settings(C);
BevelData *opdata;
ViewLayer *view_layer = CTX_data_view_layer(C);
float pixels_per_inch;
@ -230,6 +247,9 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal)
uint objects_used_len = 0;
opdata->max_obj_scale = FLT_MIN;
/* Put the Curve Profile from the toolsettings into the opdata struct */
opdata->custom_profile = ts->custom_bevel_profile_preset;
{
uint ob_store_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
@ -318,6 +338,8 @@ static bool edbm_bevel_calc(wmOperator *op)
const int miter_outer = RNA_enum_get(op->ptr, "miter_outer");
const int miter_inner = RNA_enum_get(op->ptr, "miter_inner");
const float spread = RNA_float_get(op->ptr, "spread");
const bool use_custom_profile = RNA_boolean_get(op->ptr, "use_custom_profile");
const int vmesh_method = RNA_enum_get(op->ptr, "vmesh_method");
for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) {
em = opdata->ob_store[ob_index].em;
@ -344,7 +366,8 @@ static bool edbm_bevel_calc(wmOperator *op)
"bevel geom=%hev offset=%f segments=%i vertex_only=%b offset_type=%i profile=%f "
"clamp_overlap=%b material=%i loop_slide=%b mark_seam=%b mark_sharp=%b "
"harden_normals=%b face_strength_mode=%i "
"miter_outer=%i miter_inner=%i spread=%f smoothresh=%f",
"miter_outer=%i miter_inner=%i spread=%f smoothresh=%f use_custom_profile=%b "
"custom_profile=%p vmesh_method=%i",
BM_ELEM_SELECT,
offset,
segments,
@ -361,7 +384,10 @@ static bool edbm_bevel_calc(wmOperator *op)
miter_outer,
miter_inner,
spread,
me->smoothresh);
me->smoothresh,
use_custom_profile,
opdata->custom_profile,
vmesh_method);
BMO_op_exec(em->bm, &bmop);
@ -389,7 +415,6 @@ static bool edbm_bevel_calc(wmOperator *op)
static void edbm_bevel_exit(bContext *C, wmOperator *op)
{
BevelData *opdata = op->customdata;
ScrArea *sa = CTX_wm_area(C);
if (sa) {
@ -430,7 +455,7 @@ static void edbm_bevel_cancel(bContext *C, wmOperator *op)
ED_region_tag_redraw(CTX_wm_region(C));
}
/* bevel! yay!!*/
/* bevel! yay!! */
static int edbm_bevel_exec(bContext *C, wmOperator *op)
{
if (!edbm_bevel_init(C, op, false)) {
@ -500,7 +525,7 @@ static int edbm_bevel_invoke(bContext *C, wmOperator *op, const wmEvent *event)
edbm_bevel_calc_initial_length(op, event, false);
edbm_bevel_update_header(C, op);
edbm_bevel_update_status_text(C, op);
if (!edbm_bevel_calc(op)) {
edbm_bevel_cancel(C, op);
@ -598,13 +623,9 @@ wmKeyMap *bevel_modal_keymap(wmKeyConfig *keyconf)
static const EnumPropertyItem modal_items[] = {
{BEV_MODAL_CANCEL, "CANCEL", 0, "Cancel", "Cancel bevel"},
{BEV_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", "Confirm bevel"},
{BEV_MODAL_VALUE_OFFSET, "VALUE_OFFSET", 0, "Value is offset", "Value changes offset"},
{BEV_MODAL_VALUE_PROFILE, "VALUE_PROFILE", 0, "Value is profile", "Value changes profile"},
{BEV_MODAL_VALUE_SEGMENTS,
"VALUE_SEGMENTS",
0,
"Value is segments",
"Value changes segments"},
{BEV_MODAL_VALUE_OFFSET, "VALUE_OFFSET", 0, "Change offset", "Value changes offset"},
{BEV_MODAL_VALUE_PROFILE, "VALUE_PROFILE", 0, "Change profile", "Value changes profile"},
{BEV_MODAL_VALUE_SEGMENTS, "VALUE_SEGMENTS", 0, "Change segments", "Value changes segments"},
{BEV_MODAL_SEGMENTS_UP, "SEGMENTS_UP", 0, "Increase segments", "Increase segments"},
{BEV_MODAL_SEGMENTS_DOWN, "SEGMENTS_DOWN", 0, "Decrease segments", "Decrease segments"},
{BEV_MODAL_OFFSET_MODE_CHANGE,
@ -647,12 +668,18 @@ wmKeyMap *bevel_modal_keymap(wmKeyConfig *keyconf)
0,
"Change inner miter",
"Cycle through inner miter kinds"},
{BEV_MODAL_CUSTOM_PROFILE_TOGGLE, "CUSTOM_PROFILE_TOGGLE", 0, "Toggle custom profile", ""},
{BEV_MODAL_VERTEX_MESH_CHANGE,
"VERTEX_MESH_CHANGE",
0,
"Change intersection method",
"Cycle through intersection methods"},
{0, NULL, 0, NULL, NULL},
};
wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Bevel Modal Map");
/* this function is called for each spacetype, only needs to add map once */
/* This function is called for each spacetype, only needs to add map once */
if (keymap && keymap->modal_items) {
return NULL;
}
@ -682,14 +709,14 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
handleNumInput(C, &opdata->num_input[opdata->value_mode], event)) {
edbm_bevel_numinput_set_value(op);
edbm_bevel_calc(op);
edbm_bevel_update_header(C, op);
edbm_bevel_update_status_text(C, op);
return OPERATOR_RUNNING_MODAL;
}
else if (etype == MOUSEMOVE) {
if (!has_numinput) {
edbm_bevel_mouse_set_value(op, event);
edbm_bevel_calc(op);
edbm_bevel_update_header(C, op);
edbm_bevel_update_status_text(C, op);
handled = true;
}
}
@ -703,7 +730,7 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
RNA_int_set(op->ptr, "segments", (int)opdata->segments);
edbm_bevel_calc(op);
edbm_bevel_update_header(C, op);
edbm_bevel_update_status_text(C, op);
handled = true;
}
else if (etype == EVT_MODAL_MAP) {
@ -723,7 +750,7 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
opdata->segments = opdata->segments + 1;
RNA_int_set(op->ptr, "segments", (int)opdata->segments);
edbm_bevel_calc(op);
edbm_bevel_update_header(C, op);
edbm_bevel_update_status_text(C, op);
handled = true;
break;
@ -731,7 +758,7 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
opdata->segments = max_ff(opdata->segments - 1, 1);
RNA_int_set(op->ptr, "segments", (int)opdata->segments);
edbm_bevel_calc(op);
edbm_bevel_update_header(C, op);
edbm_bevel_update_status_text(C, op);
handled = true;
break;
@ -758,7 +785,7 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
edbm_bevel_mouse_set_value(op, event);
}
edbm_bevel_calc(op);
edbm_bevel_update_header(C, op);
edbm_bevel_update_status_text(C, op);
handled = true;
break;
@ -766,7 +793,7 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
bool clamp_overlap = RNA_boolean_get(op->ptr, "clamp_overlap");
RNA_boolean_set(op->ptr, "clamp_overlap", !clamp_overlap);
edbm_bevel_calc(op);
edbm_bevel_update_header(C, op);
edbm_bevel_update_status_text(C, op);
handled = true;
break;
}
@ -790,7 +817,7 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
bool vertex_only = RNA_boolean_get(op->ptr, "vertex_only");
RNA_boolean_set(op->ptr, "vertex_only", !vertex_only);
edbm_bevel_calc(op);
edbm_bevel_update_header(C, op);
edbm_bevel_update_status_text(C, op);
handled = true;
break;
}
@ -799,7 +826,7 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
bool mark_seam = RNA_boolean_get(op->ptr, "mark_seam");
RNA_boolean_set(op->ptr, "mark_seam", !mark_seam);
edbm_bevel_calc(op);
edbm_bevel_update_header(C, op);
edbm_bevel_update_status_text(C, op);
handled = true;
break;
}
@ -808,7 +835,7 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
bool mark_sharp = RNA_boolean_get(op->ptr, "mark_sharp");
RNA_boolean_set(op->ptr, "mark_sharp", !mark_sharp);
edbm_bevel_calc(op);
edbm_bevel_update_header(C, op);
edbm_bevel_update_status_text(C, op);
handled = true;
break;
}
@ -824,7 +851,7 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
RNA_enum_set(op->ptr, "miter_inner", miter_inner);
edbm_bevel_calc(op);
edbm_bevel_update_header(C, op);
edbm_bevel_update_status_text(C, op);
handled = true;
break;
}
@ -837,7 +864,7 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
RNA_enum_set(op->ptr, "miter_outer", miter_outer);
edbm_bevel_calc(op);
edbm_bevel_update_header(C, op);
edbm_bevel_update_status_text(C, op);
handled = true;
break;
}
@ -846,7 +873,29 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
bool harden_normals = RNA_boolean_get(op->ptr, "harden_normals");
RNA_boolean_set(op->ptr, "harden_normals", !harden_normals);
edbm_bevel_calc(op);
edbm_bevel_update_header(C, op);
edbm_bevel_update_status_text(C, op);
handled = true;
break;
}
case BEV_MODAL_CUSTOM_PROFILE_TOGGLE: {
bool use_custom_profile = RNA_boolean_get(op->ptr, "use_custom_profile");
RNA_boolean_set(op->ptr, "use_custom_profile", !use_custom_profile);
edbm_bevel_calc(op);
edbm_bevel_update_status_text(C, op);
handled = true;
break;
}
case BEV_MODAL_VERTEX_MESH_CHANGE: {
int vmesh_method = RNA_enum_get(op->ptr, "vmesh_method");
vmesh_method++;
if (vmesh_method > BEVEL_VMESH_CUTOFF) {
vmesh_method = BEVEL_VMESH_ADJ;
}
RNA_enum_set(op->ptr, "vmesh_method", vmesh_method);
edbm_bevel_calc(op);
edbm_bevel_update_status_text(C, op);
handled = true;
break;
}
@ -858,13 +907,84 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
handleNumInput(C, &opdata->num_input[opdata->value_mode], event)) {
edbm_bevel_numinput_set_value(op);
edbm_bevel_calc(op);
edbm_bevel_update_header(C, op);
edbm_bevel_update_status_text(C, op);
return OPERATOR_RUNNING_MODAL;
}
return OPERATOR_RUNNING_MODAL;
}
static void edbm_bevel_ui(bContext *C, wmOperator *op)
{
uiLayout *layout = op->layout;
uiLayout *row, *col, *split;
PointerRNA ptr, toolsettings_ptr;
PropertyRNA *prop;
const char *offset_name;
RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
if (RNA_enum_get(&ptr, "offset_type") == BEVEL_AMT_PERCENT) {
uiItemR(layout, &ptr, "offset_pct", 0, NULL, ICON_NONE);
}
else {
switch (RNA_enum_get(&ptr, "offset_type")) {
case BEVEL_AMT_DEPTH:
offset_name = "Depth";
break;
case BEVEL_AMT_WIDTH:
offset_name = "Width";
break;
case BEVEL_AMT_OFFSET:
offset_name = "Offset";
break;
}
prop = RNA_struct_find_property(op->ptr, "offset_type");
RNA_property_enum_name_gettexted(
C, op->ptr, prop, RNA_property_enum_get(op->ptr, prop), &offset_name);
uiItemR(layout, &ptr, "offset", 0, offset_name, ICON_NONE);
}
row = uiLayoutRow(layout, true);
uiItemR(row, &ptr, "offset_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
split = uiLayoutSplit(layout, 0.5f, true);
col = uiLayoutColumn(split, true);
uiItemR(col, &ptr, "vertex_only", 0, NULL, ICON_NONE);
uiItemR(col, &ptr, "clamp_overlap", 0, NULL, ICON_NONE);
uiItemR(col, &ptr, "loop_slide", 0, NULL, ICON_NONE);
col = uiLayoutColumn(split, true);
uiItemR(col, &ptr, "mark_seam", 0, NULL, ICON_NONE);
uiItemR(col, &ptr, "mark_sharp", 0, NULL, ICON_NONE);
uiItemR(col, &ptr, "harden_normals", 0, NULL, ICON_NONE);
uiItemR(layout, &ptr, "segments", 0, NULL, ICON_NONE);
uiItemR(layout, &ptr, "profile", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
uiItemR(layout, &ptr, "material", 0, NULL, ICON_NONE);
uiItemL(layout, "Miter Type:", ICON_NONE);
uiItemR(layout, &ptr, "miter_outer", 0, "Outer", ICON_NONE);
uiItemR(layout, &ptr, "miter_inner", 0, "Inner", ICON_NONE);
if (RNA_enum_get(&ptr, "miter_inner") == BEVEL_MITER_ARC) {
uiItemR(layout, &ptr, "spread", 0, NULL, ICON_NONE);
}
uiItemL(layout, "Face Strength Mode:", ICON_NONE);
row = uiLayoutRow(layout, true);
uiItemR(row, &ptr, "face_strength_mode", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
uiItemL(layout, "Intersection Type:", ICON_NONE);
row = uiLayoutRow(layout, true);
uiItemR(row, &ptr, "vmesh_method", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
uiItemR(layout, &ptr, "use_custom_profile", 0, NULL, ICON_NONE);
if (RNA_boolean_get(&ptr, "use_custom_profile")) {
/* Get an RNA pointer to ToolSettings to give to the curve profile template code */
Scene *scene = CTX_data_scene(C);
RNA_pointer_create(&scene->id, &RNA_ToolSettings, scene->toolsettings, &toolsettings_ptr);
uiTemplateCurveProfile(layout, &toolsettings_ptr, "custom_bevel_profile_preset");
}
}
void MESH_OT_bevel(wmOperatorType *ot)
{
PropertyRNA *prop;
@ -906,10 +1026,19 @@ void MESH_OT_bevel(wmOperatorType *ot)
{0, NULL, 0, NULL, NULL},
};
static EnumPropertyItem vmesh_method_items[] = {
{BEVEL_VMESH_ADJ, "ADJ", 0, "Grid Fill", "Default patterned fill"},
{BEVEL_VMESH_CUTOFF,
"CUTOFF",
0,
"Cutoff",
"A cut-off at each profile's end before the intersection"},
{0, NULL, 0, NULL, NULL},
};
/* identifiers */
ot->name = "Bevel";
ot->description =
"Cut into selected items at an angle to create flat or rounded bevel or chamfer";
ot->description = "Cut into selected items at an angle to create bevel or chamfer";
ot->idname = "MESH_OT_bevel";
/* api callbacks */
@ -919,19 +1048,23 @@ void MESH_OT_bevel(wmOperatorType *ot)
ot->cancel = edbm_bevel_cancel;
ot->poll = ED_operator_editmesh;
ot->poll_property = edbm_bevel_poll_property;
ot->ui = edbm_bevel_ui;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR_XY | OPTYPE_BLOCKING;
/* properties */
RNA_def_enum(
ot->srna, "offset_type", offset_type_items, 0, "Width Type", "What distance Width measures");
prop = RNA_def_property(ot->srna, "offset", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_range(prop, 0.0, 1e6);
RNA_def_property_ui_range(prop, 0.0f, 100.0, 1, 3);
RNA_def_property_ui_range(prop, 0.0, 100.0, 1, 3);
RNA_def_property_ui_text(prop, "Width", "Bevel amount");
prop = RNA_def_property(ot->srna, "offset_pct", PROP_FLOAT, PROP_PERCENTAGE);
RNA_def_property_range(prop, 0.0, 100);
RNA_def_property_ui_text(prop, "Width Percent", "Bevel amount for percentage method");
RNA_def_int(ot->srna,
"segments",
1,
@ -941,6 +1074,7 @@ void MESH_OT_bevel(wmOperatorType *ot)
"Segments for curved edge",
1,
100);
RNA_def_float(ot->srna,
"profile",
0.5f,
@ -950,16 +1084,22 @@ void MESH_OT_bevel(wmOperatorType *ot)
"Controls profile shape (0.5 = round)",
PROFILE_HARD_MIN,
1.0f);
RNA_def_boolean(ot->srna, "vertex_only", false, "Vertex Only", "Bevel only vertices");
RNA_def_boolean(ot->srna,
"clamp_overlap",
false,
"Clamp Overlap",
"Do not allow beveled edges/vertices to overlap each other");
RNA_def_boolean(
ot->srna, "loop_slide", true, "Loop Slide", "Prefer slide along edge to even widths");
ot->srna, "loop_slide", true, "Loop Slide", "Prefer sliding along edges to even widths");
RNA_def_boolean(ot->srna, "mark_seam", false, "Mark Seams", "Mark Seams along beveled edges");
RNA_def_boolean(ot->srna, "mark_sharp", false, "Mark Sharp", "Mark beveled edges as sharp");
RNA_def_int(ot->srna,
"material",
-1,
@ -969,29 +1109,34 @@ void MESH_OT_bevel(wmOperatorType *ot)
"Material for bevel faces (-1 means use adjacent faces)",
-1,
100);
RNA_def_boolean(ot->srna,
"harden_normals",
false,
"Harden Normals",
"Match normals of new faces to adjacent faces");
RNA_def_enum(ot->srna,
"face_strength_mode",
face_strength_mode_items,
BEVEL_FACE_STRENGTH_NONE,
"Face Strength Mode",
"Whether to set face strength, and which faces to set face strength on");
RNA_def_enum(ot->srna,
"miter_outer",
miter_outer_items,
BEVEL_MITER_SHARP,
"Outer Miter",
"Pattern to use for outside of miters");
RNA_def_enum(ot->srna,
"miter_inner",
miter_inner_items,
BEVEL_MITER_SHARP,
"Inner Miter",
"Pattern to use for inside of miters");
RNA_def_float(ot->srna,
"spread",
0.1f,
@ -1001,6 +1146,20 @@ void MESH_OT_bevel(wmOperatorType *ot)
"Amount to spread arcs for arc inner miters",
0.0f,
100.0f);
RNA_def_boolean(ot->srna,
"use_custom_profile",
false,
"Custom Profile",
"Use a custom profile for the bevel");
RNA_def_enum(ot->srna,
"vmesh_method",
vmesh_method_items,
BEVEL_VMESH_ADJ,
"Vertex Mesh Method",
"The method to use to create meshes at intersections");
prop = RNA_def_boolean(ot->srna, "release_confirm", 0, "Confirm on Release", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}

View File

@ -0,0 +1,91 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright (C) 2019 Blender Foundation.
* All rights reserved.
*/
/** \file
* \ingroup DNA
*/
#ifndef DNA_PROFILEPATH_TYPES_H
#define DNA_PROFILEPATH_TYPES_H
#include "DNA_vec_types.h"
/** Number of points in high resolution table is dynamic up to a maximum. */
#define PROF_TABLE_MAX 512
/** Number of table points per control point. */
#define PROF_RESOL 16
/** Dynamic size of widget's high resolution table. Input should be profile->totpoint. */
#define PROF_N_TABLE(n_pts) min_ii(PROF_TABLE_MAX, (((n_pts - 1)) * PROF_RESOL) + 1)
/** Each control point that makes up the profile.
* \note The flags use the same enum as Bezier curves, but they aren't garanteed
* to have identical functionality, and all types aren't implemented. */
typedef struct CurveProfilePoint {
/** Location of the point, keep together. */
float x, y;
/** Flag selection state and others. */
short flag;
/** Flags for both handle's type (eBezTriple_Handle). */
char h1, h2;
} CurveProfilePoint;
/** #CurveProfilePoint.flag */
enum {
PROF_SELECT = (1 << 0),
};
/** Defines a profile */
typedef struct CurveProfile {
/** Number of user-added points that define the profile. */
short path_len;
/** Number of sampled points. */
short segments_len;
/** Preset to use when reset. */
int preset;
/** Sequence of points defining the shape of the curve. */
CurveProfilePoint *path;
/** Display and evaluation table at higher resolution for curves. */
CurveProfilePoint *table;
/** The positions of the sampled points. Used to display a preview of where they will be. */
CurveProfilePoint *segments;
/** Flag for mode states, sampling options, etc... */
int flag;
/** Used for keeping track how many times the widget is changed. */
int changed_timestamp;
/** Widget's current view, and clipping rect (is default rect too). */
rctf view_rect, clip_rect;
} CurveProfile;
/** #CurveProfile.flag */
enum {
PROF_USE_CLIP = (1 << 0), /* Keep control points inside bounding rectangle. */
PROF_SYMMETRY_MODE = (1 << 1), /* Unused for now. */
PROF_SAMPLE_STRAIGHT_EDGES = (1 << 2), /* Sample extra points on straight edges. */
PROF_SAMPLE_EVEN_LENGTHS = (1 << 3), /* Put segments evenly spaced along the path. */
};
typedef enum eCurveProfilePresets {
PROF_PRESET_LINE = 0, /* Default simple line between end points. */
PROF_PRESET_SUPPORTS = 1, /* Support loops for a regular curved profile. */
PROF_PRESET_CORNICE = 2, /* Moulding type example. */
PROF_PRESET_CROWN = 3, /* Second moulding example. */
PROF_PRESET_STEPS = 4, /* Dynamic number of steps defined by totsegments. */
} eCurveProfilePresets;
#endif

View File

@ -377,10 +377,11 @@ typedef struct BevelModifierData {
short mat;
short edge_flags;
short face_str_mode;
/* patterns to use for mitering non-reflex and reflex miter edges */
/** Patterns to use for mitering non-reflex and reflex miter edges */
short miter_inner;
short miter_outer;
char _pad0[2];
/** The method to use for creating >2-way intersections */
short vmesh_method;
/** Controls profile shape (0->1, .5 is round). */
float profile;
/** if the MOD_BEVEL_ANGLE is set,
@ -390,6 +391,10 @@ typedef struct BevelModifierData {
/** if the MOD_BEVEL_VWEIGHT option is set,
* this will be the name of the vert group, MAX_VGROUP_NAME */
char defgrp_name[64];
/** Curve info for the custom profile */
struct CurveProfile *custom_profile;
} BevelModifierData;
/* BevelModifierData->flags and BevelModifierData->lim_flags */
@ -399,8 +404,8 @@ enum {
MOD_BEVEL_ANGLE = (1 << 3),
MOD_BEVEL_WEIGHT = (1 << 4),
MOD_BEVEL_VGROUP = (1 << 5),
/* unused = (1 << 7), */
/* unused = (1 << 8), */
MOD_BEVEL_CUSTOM_PROFILE = (1 << 7),
MOD_BEVEL_SAMPLE_STRAIGHT = (1 << 8),
/* unused = (1 << 9), */
/* unused = (1 << 10), */
/* unused = (1 << 11), */
@ -439,6 +444,12 @@ enum {
MOD_BEVEL_MITER_ARC,
};
/* BevelModifier->vmesh_method */
enum {
MOD_BEVEL_VMESH_ADJ,
MOD_BEVEL_VMESH_CUTOFF,
};
typedef struct SmokeModifierData {
ModifierData modifier;

View File

@ -33,7 +33,8 @@
extern "C" {
#endif
#include "DNA_color_types.h" /* color management */
#include "DNA_color_types.h" /* color management */
#include "DNA_curveprofile_types.h"
#include "DNA_customdata_types.h" /* Scene's runtime cddata masks. */
#include "DNA_vec_types.h"
#include "DNA_listBase.h"
@ -50,6 +51,7 @@ struct Brush;
struct Collection;
struct ColorSpace;
struct CurveMapping;
struct CurveProfile;
struct CustomData_MeshMasks;
struct Editing;
struct Image;
@ -1515,6 +1517,11 @@ typedef struct ToolSettings {
/* Normal Editing */
float normal_vector[3];
char _pad6[4];
/* Custom Curve Profile for bevel tool:
* Temporary until there is a proper preset system that stores the profiles or maybe stores
* entire bevel configurations. */
struct CurveProfile *custom_bevel_profile_preset;
} ToolSettings;
/* *************************************************************** */

View File

@ -131,6 +131,7 @@ static const char *includefiles[] = {
"DNA_layer_types.h",
"DNA_workspace_types.h",
"DNA_lightprobe_types.h",
"DNA_curveprofile_types.h",
/* see comment above before editing! */
@ -1590,6 +1591,7 @@ int main(int argc, char **argv)
#include "DNA_layer_types.h"
#include "DNA_workspace_types.h"
#include "DNA_lightprobe_types.h"
#include "DNA_curveprofile_types.h"
/* end of list */

View File

@ -209,6 +209,8 @@ extern StructRNA RNA_CurveMapPoint;
extern StructRNA RNA_CurveMapping;
extern StructRNA RNA_CurveModifier;
extern StructRNA RNA_CurvePoint;
extern StructRNA RNA_CurveProfile;
extern StructRNA RNA_CurveProfilePoint;
extern StructRNA RNA_DampedTrackConstraint;
extern StructRNA RNA_DataTransferModifier;
extern StructRNA RNA_DecimateModifier;

View File

@ -216,6 +216,8 @@ extern const EnumPropertyItem rna_enum_dt_layers_select_dst_items[];
extern const EnumPropertyItem rna_enum_abc_compression_items[];
extern const EnumPropertyItem rna_enum_context_mode_items[];
extern const EnumPropertyItem rna_enum_curveprofile_preset_items[];
/* API calls */
int rna_node_tree_type_to_enum(struct bNodeTreeType *typeinfo);
int rna_node_tree_idname_to_enum(const char *idname);

View File

@ -68,6 +68,7 @@ set(DEFSRC
rna_palette.c
rna_particle.c
rna_pose.c
rna_curveprofile.c
rna_render.c
rna_rigidbody.c
rna_rna.c

View File

@ -4255,6 +4255,7 @@ static RNAProcessItem PROCESS_ITEMS[] = {
{"rna_palette.c", NULL, RNA_def_palette},
{"rna_particle.c", NULL, RNA_def_particle},
{"rna_pose.c", "rna_pose_api.c", RNA_def_pose},
{"rna_curveprofile.c", NULL, RNA_def_profile},
{"rna_lightprobe.c", NULL, RNA_def_lightprobe},
{"rna_render.c", NULL, RNA_def_render},
{"rna_rigidbody.c", NULL, RNA_def_rigidbody},

View File

@ -0,0 +1,322 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/** \file
* \ingroup RNA
*/
#include <stdlib.h>
#include <stdio.h>
#include "DNA_curveprofile_types.h"
#include "DNA_curve_types.h"
#include "DNA_texture_types.h"
#include "BLI_utildefines.h"
#include "RNA_define.h"
#include "rna_internal.h"
#include "WM_api.h"
#include "WM_types.h"
#ifdef RNA_RUNTIME
# include "RNA_access.h"
# include "DNA_image_types.h"
# include "DNA_material_types.h"
# include "DNA_movieclip_types.h"
# include "DNA_node_types.h"
# include "DNA_object_types.h"
# include "DNA_particle_types.h"
# include "DNA_sequence_types.h"
# include "MEM_guardedalloc.h"
# include "BKE_colorband.h"
# include "BKE_curveprofile.h"
# include "BKE_image.h"
# include "BKE_movieclip.h"
# include "BKE_node.h"
# include "BKE_sequencer.h"
# include "BKE_linestyle.h"
# include "DEG_depsgraph.h"
# include "ED_node.h"
# include "IMB_colormanagement.h"
# include "IMB_imbuf.h"
static void rna_CurveProfile_clip_set(PointerRNA *ptr, bool value)
{
CurveProfile *profile = (CurveProfile *)ptr->data;
if (value) {
profile->flag |= PROF_USE_CLIP;
}
else {
profile->flag &= ~PROF_USE_CLIP;
}
BKE_curveprofile_update(profile, false);
}
static void rna_CurveProfile_sample_straight_set(PointerRNA *ptr, bool value)
{
CurveProfile *profile = (CurveProfile *)ptr->data;
if (value) {
profile->flag |= PROF_SAMPLE_STRAIGHT_EDGES;
}
else {
profile->flag &= ~PROF_SAMPLE_STRAIGHT_EDGES;
}
BKE_curveprofile_update(profile, false);
}
static void rna_CurveProfile_sample_even_set(PointerRNA *ptr, bool value)
{
CurveProfile *profile = (CurveProfile *)ptr->data;
if (value) {
profile->flag |= PROF_SAMPLE_EVEN_LENGTHS;
}
else {
profile->flag &= ~PROF_SAMPLE_EVEN_LENGTHS;
}
BKE_curveprofile_update(profile, false);
}
static void rna_CurveProfile_remove_point(CurveProfile *profile,
ReportList *reports,
PointerRNA *point_ptr)
{
CurveProfilePoint *point = point_ptr->data;
if (BKE_curveprofile_remove_point(profile, point) == false) {
BKE_report(reports, RPT_ERROR, "Unable to remove path point");
return;
}
RNA_POINTER_INVALIDATE(point_ptr);
}
static void rna_CurveProfile_evaluate(struct CurveProfile *profile,
ReportList *reports,
float length_portion,
float *location)
{
if (!profile->table) {
BKE_report(reports, RPT_ERROR, "CurveProfile table not initialized, call initialize()");
}
BKE_curveprofile_evaluate_length_portion(profile, length_portion, &location[0], &location[1]);
}
static void rna_CurveProfile_initialize(struct CurveProfile *profile, int segments_len)
{
BKE_curveprofile_initialize(profile, (short)segments_len);
}
static void rna_CurveProfile_update(struct CurveProfile *profile)
{
BKE_curveprofile_update(profile, false);
}
#else
static const EnumPropertyItem prop_handle_type_items[] = {
{HD_AUTO, "AUTO", 0, "Auto Handle", ""},
{HD_VECT, "VECTOR", 0, "Vector Handle", ""},
{0, NULL, 0, NULL, NULL},
};
static void rna_def_curveprofilepoint(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "CurveProfilePoint", NULL);
RNA_def_struct_ui_text(srna, "CurveProfilePoint", "Point of a path used to define a profile");
prop = RNA_def_property(srna, "location", PROP_FLOAT, PROP_XYZ);
RNA_def_property_float_sdna(prop, NULL, "x");
RNA_def_property_array(prop, 2);
RNA_def_property_ui_text(prop, "Location", "X/Y coordinates of the path point");
prop = RNA_def_property(srna, "handle_type_1", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "h1");
RNA_def_property_enum_items(prop, prop_handle_type_items);
RNA_def_property_ui_text(
prop, "First Handle Type", "Path interpolation at this point: Bezier or vector");
prop = RNA_def_property(srna, "handle_type_2", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "h2");
RNA_def_property_enum_items(prop, prop_handle_type_items);
RNA_def_property_ui_text(
prop, "Second Handle Type", "Path interpolation at this point: Bezier or vector");
prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PROF_SELECT);
RNA_def_property_ui_text(prop, "Select", "Selection state of the path point");
}
static void rna_def_curveprofile_points_api(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
PropertyRNA *parm;
FunctionRNA *func;
RNA_def_property_srna(cprop, "CurveProfilePoints");
srna = RNA_def_struct(brna, "CurveProfilePoints", NULL);
RNA_def_struct_sdna(srna, "CurveProfile");
RNA_def_struct_ui_text(srna, "Profile Point", "Collection of Profile Points");
func = RNA_def_function(srna, "add", "BKE_curveprofile_insert");
RNA_def_function_ui_description(func, "Add point to the profile");
parm = RNA_def_float(func,
"x",
0.0f,
-FLT_MAX,
FLT_MAX,
"X Position",
"X Position for new point",
-FLT_MAX,
FLT_MAX);
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_float(func,
"y",
0.0f,
-FLT_MAX,
FLT_MAX,
"Y Position",
"Y Position for new point",
-FLT_MAX,
FLT_MAX);
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "point", "CurveProfilePoint", "", "New point");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_CurveProfile_remove_point");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Delete point from the profile");
parm = RNA_def_pointer(func, "point", "CurveProfilePoint", "", "Point to remove");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
static void rna_def_curveprofile(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
PropertyRNA *parm;
FunctionRNA *func;
static const EnumPropertyItem rna_enum_curveprofile_preset_items[] = {
{PROF_PRESET_LINE, "LINE", 0, "Line", "Default"},
{PROF_PRESET_SUPPORTS, "SUPPORTS", 0, "Support Loops", "Loops on each side of the profile"},
{PROF_PRESET_CORNICE, "CORNICE", 0, "Cornice Moulding", ""},
{PROF_PRESET_CROWN, "CROWN", 0, "Crown Moulding", ""},
{PROF_PRESET_STEPS, "STEPS", 0, "Steps", "A number of steps defined by the segments"},
{0, NULL, 0, NULL, NULL},
};
srna = RNA_def_struct(brna, "CurveProfile", NULL);
RNA_def_struct_ui_text(srna, "CurveProfile", "Profile Path editor used to build a profile path");
prop = RNA_def_property(srna, "preset", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "preset");
RNA_def_property_enum_items(prop, rna_enum_curveprofile_preset_items);
RNA_def_property_ui_text(prop, "Preset", "");
prop = RNA_def_property(srna, "use_clip", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PROF_USE_CLIP);
RNA_def_property_ui_text(prop, "Clip", "Force the path view to fit a defined boundary");
RNA_def_property_boolean_funcs(prop, NULL, "rna_CurveProfile_clip_set");
prop = RNA_def_property(srna, "use_sample_straight_edges", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PROF_SAMPLE_STRAIGHT_EDGES);
RNA_def_property_ui_text(prop, "Sample Straight Edges", "Sample edges with vector handles");
RNA_def_property_boolean_funcs(prop, NULL, "rna_CurveProfile_sample_straight_set");
prop = RNA_def_property(srna, "use_sample_even_lengths", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PROF_SAMPLE_EVEN_LENGTHS);
RNA_def_property_ui_text(prop, "Sample Even Lengths", "Sample edges with even lengths");
RNA_def_property_boolean_funcs(prop, NULL, "rna_CurveProfile_sample_even_set");
func = RNA_def_function(srna, "update", "rna_CurveProfile_update");
RNA_def_function_ui_description(func, "Update the profile");
func = RNA_def_function(srna, "initialize", "rna_CurveProfile_initialize");
parm = RNA_def_int(func,
"totsegments",
1,
1,
1000,
"",
"The number of segment values to"
" initialize the segments table with",
1,
100);
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
RNA_def_function_ui_description(func, "Set the number of display segments and fill tables");
prop = RNA_def_property(srna, "points", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "path", "path_len");
RNA_def_property_struct_type(prop, "CurveProfilePoint");
RNA_def_property_ui_text(prop, "Points", "Profile control points");
rna_def_curveprofile_points_api(brna, prop);
prop = RNA_def_property(srna, "segments", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "segments", "segments_len");
RNA_def_property_struct_type(prop, "CurveProfilePoint");
RNA_def_property_ui_text(prop, "Segments", "Segments sampled from control points");
func = RNA_def_function(srna, "evaluate", "rna_CurveProfile_evaluate");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Evaluate the at the given portion of the path length");
parm = RNA_def_float(func,
"length_portion",
0.0f,
0.0f,
1.0f,
"Length Portion",
"Portion of the path length to travel before evaluation",
0.0f,
1.0f);
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_float_vector(func,
"location",
2,
NULL,
-100.0f,
100.0f,
"Location",
"The location at the given portion of the profile",
-100.0f,
100.0f);
RNA_def_function_output(func, parm);
}
void RNA_def_profile(BlenderRNA *brna)
{
rna_def_curveprofilepoint(brna);
rna_def_curveprofile(brna);
}
#endif

View File

@ -178,6 +178,7 @@ void RNA_def_packedfile(struct BlenderRNA *brna);
void RNA_def_palette(struct BlenderRNA *brna);
void RNA_def_particle(struct BlenderRNA *brna);
void RNA_def_pose(struct BlenderRNA *brna);
void RNA_def_profile(struct BlenderRNA *brna);
void RNA_def_lightprobe(struct BlenderRNA *brna);
void RNA_def_render(struct BlenderRNA *brna);
void RNA_def_rigidbody(struct BlenderRNA *brna);

View File

@ -37,6 +37,7 @@
#include "BLT_translation.h"
#include "BKE_animsys.h"
#include "BKE_curveprofile.h"
#include "BKE_data_transfer.h"
#include "BKE_dynamicpaint.h"
#include "BKE_effect.h"
@ -433,7 +434,6 @@ const EnumPropertyItem rna_enum_axis_flag_xyz_items[] = {
};
#ifdef RNA_RUNTIME
# include "DNA_particle_types.h"
# include "DNA_curve_types.h"
# include "DNA_smoke_types.h"
@ -998,6 +998,18 @@ static PointerRNA rna_CollisionModifier_settings_get(PointerRNA *ptr)
return rna_pointer_inherit_refine(ptr, &RNA_CollisionSettings, ob->pd);
}
/* Special update function for setting the number of segments of the modifier that also resamples
* the segments in the custom profile. */
static void rna_BevelModifier_update_segments(Main *bmain, Scene *scene, PointerRNA *ptr)
{
BevelModifierData *bmd = (BevelModifierData *)ptr->data;
if (RNA_boolean_get(ptr, "use_custom_profile")) {
short segments = (short)RNA_int_get(ptr, "segments");
BKE_curveprofile_initialize(bmd->custom_profile, segments);
}
rna_Modifier_update(bmain, scene, ptr);
}
static void rna_UVProjectModifier_num_projectors_set(PointerRNA *ptr, int value)
{
UVProjectModifierData *md = (UVProjectModifierData *)ptr->data;
@ -3583,10 +3595,26 @@ static void rna_def_modifier_bevel(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
static EnumPropertyItem prop_miter_items[] = {
{MOD_BEVEL_MITER_SHARP, "MITER_SHARP", 0, "Sharp", "Default sharp miter"},
{MOD_BEVEL_MITER_PATCH, "MITER_PATCH", 0, "Patch", "Miter with extra corner"},
{MOD_BEVEL_MITER_ARC, "MITER_ARC", 0, "Arc", "Miter with curved arc"},
static const EnumPropertyItem prop_miter_outer_items[] = {
{MOD_BEVEL_MITER_SHARP, "MITER_SHARP", 0, "Sharp", "Outside of miter is sharp"},
{MOD_BEVEL_MITER_PATCH, "MITER_PATCH", 0, "Patch", "Outside of miter is squared-off patch"},
{MOD_BEVEL_MITER_ARC, "MITER_ARC", 0, "Arc", "Outside of miter is arc"},
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem prop_miter_inner_items[] = {
{MOD_BEVEL_MITER_SHARP, "MITER_SHARP", 0, "Sharp", "Inside of miter is sharp"},
{MOD_BEVEL_MITER_ARC, "MITER_ARC", 0, "Arc", "Inside of miter is arc"},
{0, NULL, 0, NULL, NULL},
};
static EnumPropertyItem prop_vmesh_method_items[] = {
{MOD_BEVEL_VMESH_ADJ, "ADJ", 0, "Grid Fill", "Default patterned fill"},
{MOD_BEVEL_VMESH_CUTOFF,
"CUTOFF",
0,
"Cutoff",
"A cut-off at the end of each profile before the intersection"},
{0, NULL, 0, NULL, NULL},
};
@ -3614,7 +3642,7 @@ static void rna_def_modifier_bevel(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "res");
RNA_def_property_range(prop, 1, 100);
RNA_def_property_ui_text(prop, "Segments", "Number of segments for round edges/verts");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
RNA_def_property_update(prop, 0, "rna_BevelModifier_update_segments");
prop = RNA_def_property(srna, "use_only_vertices", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_BEVEL_VERT);
@ -3648,7 +3676,7 @@ static void rna_def_modifier_bevel(BlenderRNA *brna)
prop = RNA_def_property(srna, "offset_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "val_flags");
RNA_def_property_enum_items(prop, prop_val_type_items);
RNA_def_property_ui_text(prop, "Amount Type", "What distance Width measures");
RNA_def_property_ui_text(prop, "Width Type", "What distance Width measures");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "profile", PROP_FLOAT, PROP_FACTOR);
@ -3693,13 +3721,13 @@ static void rna_def_modifier_bevel(BlenderRNA *brna)
prop = RNA_def_property(srna, "miter_outer", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "miter_outer");
RNA_def_property_enum_items(prop, prop_miter_items);
RNA_def_property_enum_items(prop, prop_miter_outer_items);
RNA_def_property_ui_text(prop, "Outer Miter", "Pattern to use for outside of miters");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "miter_inner", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "miter_inner");
RNA_def_property_enum_items(prop, prop_miter_items);
RNA_def_property_enum_items(prop, prop_miter_inner_items);
RNA_def_property_ui_text(prop, "Inner Miter", "Pattern to use for inside of miters");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
@ -3709,6 +3737,25 @@ static void rna_def_modifier_bevel(BlenderRNA *brna)
RNA_def_property_ui_range(prop, 0.0f, 100.0f, 0.1, 4);
RNA_def_property_ui_text(prop, "Spread", "Spread distance for inner miter arcs");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "use_custom_profile", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_BEVEL_CUSTOM_PROFILE);
RNA_def_property_ui_text(
prop, "Custom Profile", "Whether to use a user inputed curve for the bevel's profile");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "custom_profile", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "CurveProfile");
RNA_def_property_pointer_sdna(prop, NULL, "custom_profile");
RNA_def_property_ui_text(prop, "Custom Profile Path", "The path for the custom profile");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "vmesh_method", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "vmesh_method");
RNA_def_property_enum_items(prop, prop_vmesh_method_items);
RNA_def_property_ui_text(
prop, "Vertex Mesh Method", "The method to use to create the mesh at intersections");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
}
static void rna_def_modifier_shrinkwrap(BlenderRNA *brna)

View File

@ -3307,6 +3307,12 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_struct_type(prop, "MeshStatVis");
RNA_def_property_ui_text(prop, "Mesh Statistics Visualization", NULL);
/* CurveProfile */
prop = RNA_def_property(srna, "custom_bevel_profile_preset", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "custom_bevel_profile_preset");
RNA_def_property_struct_type(prop, "CurveProfile");
RNA_def_property_ui_text(prop, "Curve Profile Widget", "Used for defining a profile's path");
}
static void rna_def_unified_paint_settings(BlenderRNA *brna)

View File

@ -1220,6 +1220,10 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_boolean(func, "use_negative_slope", false, "", "Use a negative slope by default");
RNA_def_boolean(func, "show_tone", false, "", "Show tone options");
func = RNA_def_function(srna, "template_curveprofile", "uiTemplateCurveProfile");
RNA_def_function_ui_description(func, "A profile path editor used for custom profiles");
api_ui_item_rna_common(func);
func = RNA_def_function(srna, "template_color_ramp", "uiTemplateColorRamp");
RNA_def_function_ui_description(func, "Item. A color ramp widget");
api_ui_item_rna_common(func);

View File

@ -31,6 +31,7 @@
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_curveprofile_types.h"
#include "BKE_deform.h"
#include "BKE_mesh.h"
@ -40,6 +41,7 @@
#include "bmesh.h"
#include "bmesh_tools.h"
#include "BKE_curveprofile.h"
#include "DEG_depsgraph_query.h"
@ -47,7 +49,7 @@ static void initData(ModifierData *md)
{
BevelModifierData *bmd = (BevelModifierData *)md;
bmd->value = 0.1f;
bmd->value = 1.0f;
bmd->res = 1;
bmd->flags = 0;
bmd->val_flags = MOD_BEVEL_AMT_OFFSET;
@ -62,11 +64,16 @@ static void initData(ModifierData *md)
bmd->profile = 0.5f;
bmd->bevel_angle = DEG2RADF(30.0f);
bmd->defgrp_name[0] = '\0';
bmd->custom_profile = BKE_curveprofile_add(PROF_PRESET_LINE);
}
static void copyData(const ModifierData *md_src, ModifierData *md_dst, const int flag)
{
const BevelModifierData *bmd_src = (const BevelModifierData *)md_src;
BevelModifierData *bmd_dst = (BevelModifierData *)md_dst;
modifier_copyData_generic(md_src, md_dst, flag);
bmd_dst->custom_profile = BKE_curveprofile_copy(bmd_src->custom_profile);
}
static void requiredDataMask(Object *UNUSED(ob),
@ -109,6 +116,8 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
const int miter_outer = bmd->miter_outer;
const int miter_inner = bmd->miter_inner;
const float spread = bmd->spread;
const bool use_custom_profile = (bmd->flags & MOD_BEVEL_CUSTOM_PROFILE);
const int vmesh_method = bmd->vmesh_method;
bm = BKE_mesh_to_bmesh_ex(mesh,
&(struct BMeshCreateParams){0},
@ -210,7 +219,10 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
miter_outer,
miter_inner,
spread,
mesh->smoothresh);
mesh->smoothresh,
use_custom_profile,
bmd->custom_profile,
vmesh_method);
result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh);
@ -229,6 +241,18 @@ static bool dependsOnNormals(ModifierData *UNUSED(md))
return true;
}
static void freeData(ModifierData *md)
{
BevelModifierData *bmd = (BevelModifierData *)md;
BKE_curveprofile_free(bmd->custom_profile);
}
static bool isDisabled(const Scene *UNUSED(scene), ModifierData *md, bool UNUSED(userRenderParams))
{
BevelModifierData *bmd = (BevelModifierData *)md;
return (bmd->value == 0.0f);
}
ModifierTypeInfo modifierType_Bevel = {
/* name */ "Bevel",
/* structName */ "BevelModifierData",
@ -236,19 +260,16 @@ ModifierTypeInfo modifierType_Bevel = {
/* type */ eModifierTypeType_Constructive,
/* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsEditmode |
eModifierTypeFlag_EnableInEditmode | eModifierTypeFlag_AcceptsCVs,
/* copyData */ copyData,
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ applyModifier,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ NULL,
/* isDisabled */ NULL,
/* freeData */ freeData,
/* isDisabled */ isDisabled,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ dependsOnNormals,