Mesh: Replace auto smooth with node group #108014

Merged
Hans Goudey merged 149 commits from HooglyBoogly/blender:refactor-mesh-corner-normals-lazy into main 2023-10-20 16:54:20 +02:00
53 changed files with 608 additions and 273 deletions
Showing only changes of commit 7e6d3dd52c - Show all commits

View File

@ -592,10 +592,10 @@ set(BROTLI_HASH_TYPE SHA256)
set(BROTLI_FILE brotli-v${BROTLI_VERSION}.tar.gz) set(BROTLI_FILE brotli-v${BROTLI_VERSION}.tar.gz)
set(BROTLI_CPE "cpe:2.3:a:google:brotli:${BROTLI_VERSION}:*:*:*:*:*:*:*") set(BROTLI_CPE "cpe:2.3:a:google:brotli:${BROTLI_VERSION}:*:*:*:*:*:*:*")
set(OPENPGL_VERSION v0.4.1-beta) set(OPENPGL_VERSION v0.5.0)
set(OPENPGL_SHORT_VERSION 0.4.1) set(OPENPGL_SHORT_VERSION 0.5.0)
set(OPENPGL_URI https://github.com/OpenPathGuidingLibrary/openpgl/archive/refs/tags/${OPENPGL_VERSION}.tar.gz) set(OPENPGL_URI https://github.com/OpenPathGuidingLibrary/openpgl/archive/refs/tags/${OPENPGL_VERSION}.tar.gz)
set(OPENPGL_HASH db63f5dac5cfa8c110ede241f0c413f00db0c4748697381c4fa23e0f9e82a754) set(OPENPGL_HASH 1ec806d434d45e43e098f82ee9be0cb74928343898c57490b34ff80584e9805a)
set(OPENPGL_HASH_TYPE SHA256) set(OPENPGL_HASH_TYPE SHA256)
set(OPENPGL_FILE openpgl-${OPENPGL_VERSION}.tar.gz) set(OPENPGL_FILE openpgl-${OPENPGL_VERSION}.tar.gz)

View File

@ -43,10 +43,10 @@ ccl_device_inline float kernel_ies_interp(KernelGlobals kg, int slot, float h_an
#define IES_LOOKUP_ANGLE_V(v) kernel_data_fetch(ies, ofs + h_num + (v)) #define IES_LOOKUP_ANGLE_V(v) kernel_data_fetch(ies, ofs + h_num + (v))
/* Check whether the angle is within the bounds of the IES texture. */ /* Check whether the angle is within the bounds of the IES texture. */
if (v_angle >= IES_LOOKUP_ANGLE_V(v_num - 1)) { if (v_angle < IES_LOOKUP_ANGLE_V(0) || v_angle >= IES_LOOKUP_ANGLE_V(v_num - 1)) {
return 0.0f; return 0.0f;
} }
kernel_assert(v_angle >= IES_LOOKUP_ANGLE_V(0));
kernel_assert(h_angle >= IES_LOOKUP_ANGLE_H(0)); kernel_assert(h_angle >= IES_LOOKUP_ANGLE_H(0));
kernel_assert(h_angle <= IES_LOOKUP_ANGLE_H(h_num - 1)); kernel_assert(h_angle <= IES_LOOKUP_ANGLE_H(h_num - 1));

View File

@ -64,8 +64,9 @@ class IESTextParser {
public: public:
vector<char> text; vector<char> text;
char *data; char *data;
bool error;
IESTextParser(const string &str) : text(str.begin(), str.end()) IESTextParser(const string &str) : text(str.begin(), str.end()), error(false)
{ {
std::replace(text.begin(), text.end(), ',', ' '); std::replace(text.begin(), text.end(), ',', ' ');
data = strstr(&text[0], "\nTILT="); data = strstr(&text[0], "\nTILT=");
@ -76,15 +77,22 @@ class IESTextParser {
return (data == NULL) || (data[0] == '\0'); return (data == NULL) || (data[0] == '\0');
} }
bool has_error()
{
return error;
}
double get_double() double get_double()
{ {
if (eof()) { if (eof()) {
error = true;
return 0.0; return 0.0;
} }
char *old_data = data; char *old_data = data;
double val = strtod(data, &data); double val = strtod(data, &data);
if (data == old_data) { if (data == old_data) {
data = NULL; data = NULL;
error = true;
return 0.0; return 0.0;
} }
return val; return val;
@ -93,12 +101,14 @@ class IESTextParser {
long get_long() long get_long()
{ {
if (eof()) { if (eof()) {
error = true;
return 0; return 0;
} }
char *old_data = data; char *old_data = data;
long val = strtol(data, &data, 10); long val = strtol(data, &data, 10);
if (data == old_data) { if (data == old_data) {
data = NULL; data = NULL;
error = true;
return 0; return 0;
} }
return val; return val;
@ -191,7 +201,7 @@ bool IESFile::parse(const string &ies)
} }
} }
return !parser.eof(); return !parser.has_error();
} }
bool IESFile::process_type_b() bool IESFile::process_type_b()
@ -340,13 +350,7 @@ bool IESFile::process_type_c()
float v_first = v_angles[0], v_last = v_angles[v_angles.size() - 1]; float v_first = v_angles[0], v_last = v_angles[v_angles.size() - 1];
if (v_first == 90.0f) { if (v_first == 90.0f) {
if (v_last == 180.0f) { if (v_last != 180.0f) {
/* Flip to ensure that vertical angles always start at 0°. */
for (int i = 0; i < v_angles.size(); i++) {
v_angles[i] = 180.0f - v_angles[i];
}
}
else {
return false; return false;
} }
} }
@ -375,7 +379,7 @@ bool IESFile::process()
} }
} }
assert(v_angles[0] == 0.0f); assert(v_angles[0] == 0.0f || v_angles[0] == 90.0f);
assert(h_angles[0] == 0.0f); assert(h_angles[0] == 0.0f);
assert(h_angles[h_angles.size() - 1] == 360.0f); assert(h_angles[h_angles.size() - 1] == 360.0f);

View File

@ -40,7 +40,8 @@ def geometry_modifier_poll(context):
def get_context_modifier(context): def get_context_modifier(context):
if context.area.type == 'PROPERTIES': area = context.area
if (area is not None) and (area.type == 'PROPERTIES'):
modifier = context.modifier modifier = context.modifier
else: else:
ob = context.object ob = context.object

View File

@ -178,12 +178,8 @@ class ProjectApply(Operator):
def execute(self, _context): def execute(self, _context):
image_name = ProjectEdit._proj_hack[0] # TODO, deal with this nicer image_name = ProjectEdit._proj_hack[0] # TODO, deal with this nicer
image = bpy.data.images.get((image_name, None))
try: if image is None:
image = bpy.data.images[image_name, None]
except KeyError:
import traceback
traceback.print_exc()
self.report({'ERROR'}, tip_("Could not find image '%s'") % image_name) self.report({'ERROR'}, tip_("Could not find image '%s'") % image_name)
return {'CANCELLED'} return {'CANCELLED'}

View File

@ -655,6 +655,11 @@ class IsolateTypeRender(Operator):
bl_label = "Restrict Render Unselected" bl_label = "Restrict Render Unselected"
bl_options = {'REGISTER', 'UNDO'} bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context):
ob = context.object
return (ob is not None)
def execute(self, context): def execute(self, context):
act_type = context.object.type act_type = context.object.type

View File

@ -157,7 +157,7 @@ def _get_context_attr(context, data_path):
return context.path_resolve(data_path) return context.path_resolve(data_path)
def _set_context_attr(context, data_path, value) -> None: def _set_context_attr(context, data_path, value):
"""Set the value of a context member based on its data path.""" """Set the value of a context member based on its data path."""
owner_path, attr_name = data_path.rsplit('.', 1) owner_path, attr_name = data_path.rsplit('.', 1)
owner = context.path_resolve(owner_path) owner = context.path_resolve(owner_path)
@ -172,10 +172,10 @@ class GenericUIListOperator:
list_path: StringProperty() list_path: StringProperty()
active_index_path: StringProperty() active_index_path: StringProperty()
def get_list(self, context) -> str: def get_list(self, context):
return _get_context_attr(context, self.list_path) return _get_context_attr(context, self.list_path)
def get_active_index(self, context) -> str: def get_active_index(self, context):
return _get_context_attr(context, self.active_index_path) return _get_context_attr(context, self.active_index_path)
def set_active_index(self, context, index): def set_active_index(self, context, index):
@ -226,9 +226,11 @@ class UILIST_OT_entry_move(GenericUIListOperator, Operator):
direction: EnumProperty( direction: EnumProperty(
name="Direction", name="Direction",
items=(('UP', 'UP', 'UP'), items=(
('DOWN', 'DOWN', 'DOWN')), ('UP', 'UP', 'UP'),
default='UP' ('DOWN', 'DOWN', 'DOWN'),
),
default='UP',
) )
def execute(self, context): def execute(self, context):

View File

@ -19,6 +19,8 @@
#include "BLI_math_vector_types.hh" #include "BLI_math_vector_types.hh"
#include "BLI_span.hh" #include "BLI_span.hh"
#include "BLT_translation.h"
#include "FN_field.hh" #include "FN_field.hh"
#include "BLT_translation.h" #include "BLT_translation.h"
@ -49,8 +51,8 @@ std::ostream &operator<<(std::ostream &stream, const AttributeIDRef &attribute_i
return stream; return stream;
} }
const char *no_procedural_access_message = const char *no_procedural_access_message = N_(
"This attribute can not be accessed in a procedural context"; "This attribute can not be accessed in a procedural context");
bool allow_procedural_attribute_access(StringRef attribute_name) bool allow_procedural_attribute_access(StringRef attribute_name)
{ {

View File

@ -474,7 +474,9 @@ static int get_timecode(MovieClip *clip, int flag)
return clip->proxy.tc; return clip->proxy.tc;
} }
static void get_sequence_filepath(const MovieClip *clip, const int framenr, char *filepath) static void get_sequence_filepath(const MovieClip *clip,
const int framenr,
char filepath[FILE_MAX])
{ {
ushort numlen; ushort numlen;
char head[FILE_MAX], tail[FILE_MAX]; char head[FILE_MAX], tail[FILE_MAX];
@ -489,7 +491,7 @@ static void get_sequence_filepath(const MovieClip *clip, const int framenr, char
if (numlen) { if (numlen) {
BLI_path_sequence_encode(filepath, BLI_path_sequence_encode(filepath,
sizeof(filepath), FILE_MAX,
head, head,
tail, tail,
numlen, numlen,
@ -503,8 +505,11 @@ static void get_sequence_filepath(const MovieClip *clip, const int framenr, char
} }
/* supposed to work with sequences only */ /* supposed to work with sequences only */
static void get_proxy_filepath( static void get_proxy_filepath(const MovieClip *clip,
const MovieClip *clip, int proxy_render_size, bool undistorted, int framenr, char *filepath) int proxy_render_size,
bool undistorted,
int framenr,
char filepath[FILE_MAX])
{ {
int size = rendersize_to_number(proxy_render_size); int size = rendersize_to_number(proxy_render_size);
char dir[FILE_MAX], clipdir[FILE_MAX], clipfile[FILE_MAX]; char dir[FILE_MAX], clipdir[FILE_MAX], clipfile[FILE_MAX];
@ -516,15 +521,26 @@ static void get_proxy_filepath(
BLI_strncpy(dir, clip->proxy.dir, sizeof(dir)); BLI_strncpy(dir, clip->proxy.dir, sizeof(dir));
} }
else { else {
BLI_snprintf(dir, FILE_MAX, "%s/BL_proxy", clipdir); BLI_snprintf(dir, sizeof(dir), "%s" SEP_STR "BL_proxy", clipdir);
} }
if (undistorted) { if (undistorted) {
BLI_snprintf( BLI_snprintf(filepath,
filepath, FILE_MAX, "%s/%s/proxy_%d_undistorted/%08d", dir, clipfile, size, proxynr); FILE_MAX,
"%s" SEP_STR "%s" SEP_STR "proxy_%d_undistorted" SEP_STR "%08d",
dir,
clipfile,
size,
proxynr);
} }
else { else {
BLI_snprintf(filepath, FILE_MAX, "%s/%s/proxy_%d/%08d", dir, clipfile, size, proxynr); BLI_snprintf(filepath,
FILE_MAX,
"%s" SEP_STR "%s" SEP_STR "proxy_%d" SEP_STR "%08d",
dir,
clipfile,
size,
proxynr);
} }
BLI_path_abs(filepath, BKE_main_blendfile_path_from_global()); BLI_path_abs(filepath, BKE_main_blendfile_path_from_global());

View File

@ -1463,6 +1463,10 @@ static bool vfont_to_curve(Object *ob,
sb->x -= sinf(ct->rot) * font_select_y_offset; sb->x -= sinf(ct->rot) * font_select_y_offset;
sb->y -= cosf(ct->rot) * font_select_y_offset; sb->y -= cosf(ct->rot) * font_select_y_offset;
} }
else {
/* Simple downward shift below baseline when not rotated. */
sb->y -= font_select_y_offset;
}
sb->x *= font_size; sb->x *= font_size;
sb->y *= font_size; sb->y *= font_size;
selboxes[i - selstart].h = font_size; selboxes[i - selstart].h = font_size;

View File

@ -142,7 +142,7 @@ class BitSpan {
}; };
/** /**
* Checks if the span fullfills the requirements for a bounded span. Bounded spans can often be * Checks if the span fulfills the requirements for a bounded span. Bounded spans can often be
* processed more efficiently, because fewer cases have to be considered when aligning multiple * processed more efficiently, because fewer cases have to be considered when aligning multiple
* such spans. * such spans.
* *
@ -170,7 +170,7 @@ inline bool is_bounded_span(const BitSpan span)
} }
/** /**
* Same as #BitSpan but fullfills the requirements mentioned on #is_bounded_span. * Same as #BitSpan but fulfills the requirements mentioned on #is_bounded_span.
*/ */
class BoundedBitSpan : public BitSpan { class BoundedBitSpan : public BitSpan {
public: public:
@ -315,7 +315,7 @@ class MutableBitSpan {
}; };
/** /**
* Same as #MutableBitSpan but fullfills the requirements mentioned on #is_bounded_span. * Same as #MutableBitSpan but fulfills the requirements mentioned on #is_bounded_span.
*/ */
class MutableBoundedBitSpan : public MutableBitSpan { class MutableBoundedBitSpan : public MutableBitSpan {
public: public:

View File

@ -66,7 +66,7 @@ class ImplicitSharingInfo : NonCopyable, NonMovable {
BLI_assert(weak_users_ == 0); BLI_assert(weak_users_ == 0);
} }
/** Whether the resource can be modified inplace because there is only one owner. */ /** Whether the resource can be modified in place because there is only one owner. */
bool is_mutable() const bool is_mutable() const
{ {
return strong_users_.load(std::memory_order_relaxed) == 1; return strong_users_.load(std::memory_order_relaxed) == 1;

View File

@ -640,7 +640,7 @@ static bool seq_sound_proxy_update_cb(Sequence *seq, void *user_data)
#define SEQ_USE_PROXY_CUSTOM_FILE (1 << 21) #define SEQ_USE_PROXY_CUSTOM_FILE (1 << 21)
/* don't know, if anybody used that this way, but just in case, upgrade to new way... */ /* don't know, if anybody used that this way, but just in case, upgrade to new way... */
if ((seq->flag & SEQ_USE_PROXY_CUSTOM_FILE) && !(seq->flag & SEQ_USE_PROXY_CUSTOM_DIR)) { if ((seq->flag & SEQ_USE_PROXY_CUSTOM_FILE) && !(seq->flag & SEQ_USE_PROXY_CUSTOM_DIR)) {
BLI_snprintf(seq->strip->proxy->dir, FILE_MAXDIR, "%s/BL_proxy", seq->strip->dir); BLI_snprintf(seq->strip->proxy->dir, FILE_MAXDIR, "%s" SEP_STR "BL_proxy", seq->strip->dir);
} }
#undef SEQ_USE_PROXY_CUSTOM_DIR #undef SEQ_USE_PROXY_CUSTOM_DIR
#undef SEQ_USE_PROXY_CUSTOM_FILE #undef SEQ_USE_PROXY_CUSTOM_FILE

View File

@ -2016,7 +2016,9 @@ static int gpencil_blank_frame_add_exec(bContext *C, wmOperator *op)
CTX_DATA_END; CTX_DATA_END;
/* notifiers */ /* notifiers */
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); if (gpd != NULL) {
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
}
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED; return OPERATOR_FINISHED;

View File

@ -522,9 +522,12 @@ bool ED_operator_objectmode(struct bContext *C);
* to be displayed to the user explaining why the operator can't be used in current context. * to be displayed to the user explaining why the operator can't be used in current context.
*/ */
bool ED_operator_objectmode_poll_msg(struct bContext *C); bool ED_operator_objectmode_poll_msg(struct bContext *C);
bool ED_operator_objectmode_with_view3d_poll_msg(struct bContext *C);
bool ED_operator_view3d_active(struct bContext *C); bool ED_operator_view3d_active(struct bContext *C);
bool ED_operator_region_view3d_active(struct bContext *C); bool ED_operator_region_view3d_active(struct bContext *C);
bool ED_operator_region_gizmo_active(struct bContext *C);
/** /**
* Generic for any view2d which uses anim_ops. * Generic for any view2d which uses anim_ops.
*/ */

View File

@ -2231,6 +2231,8 @@ static void UI_OT_drop_color(wmOperatorType *ot)
ot->description = "Drop colors to buttons"; ot->description = "Drop colors to buttons";
ot->invoke = drop_color_invoke; ot->invoke = drop_color_invoke;
ot->poll = ED_operator_regionactive;
ot->flag = OPTYPE_INTERNAL; ot->flag = OPTYPE_INTERNAL;
RNA_def_float_color( RNA_def_float_color(

View File

@ -2426,19 +2426,20 @@ PointerRNA *UI_panel_custom_data_get(const Panel *panel)
PointerRNA *UI_region_panel_custom_data_under_cursor(const bContext *C, const wmEvent *event) PointerRNA *UI_region_panel_custom_data_under_cursor(const bContext *C, const wmEvent *event)
{ {
ARegion *region = CTX_wm_region(C); ARegion *region = CTX_wm_region(C);
if (region) {
LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
Panel *panel = block->panel;
if (panel == nullptr) {
continue;
}
LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) { int mx = event->xy[0];
Panel *panel = block->panel; int my = event->xy[1];
if (panel == nullptr) { ui_window_to_block(region, block, &mx, &my);
continue; const int mouse_state = ui_panel_mouse_state_get(block, panel, mx, my);
} if (ELEM(mouse_state, PANEL_MOUSE_INSIDE_CONTENT, PANEL_MOUSE_INSIDE_HEADER)) {
return UI_panel_custom_data_get(panel);
int mx = event->xy[0]; }
int my = event->xy[1];
ui_window_to_block(region, block, &mx, &my);
const int mouse_state = ui_panel_mouse_state_get(block, panel, mx, my);
if (ELEM(mouse_state, PANEL_MOUSE_INSIDE_CONTENT, PANEL_MOUSE_INSIDE_HEADER)) {
return UI_panel_custom_data_get(panel);
} }
} }

View File

@ -1684,7 +1684,7 @@ static std::optional<CollectionAddInfo> collection_add_info_get_from_op(bContext
BLI_findlink(&bmain->collections, RNA_enum_get(op->ptr, "collection"))); BLI_findlink(&bmain->collections, RNA_enum_get(op->ptr, "collection")));
} }
if (update_location_if_necessary) { if (update_location_if_necessary && CTX_wm_region_view3d(C)) {
int mval[2]; int mval[2];
if (!RNA_property_is_set(op->ptr, prop_location) && object_add_drop_xy_get(C, op, &mval)) { if (!RNA_property_is_set(op->ptr, prop_location) && object_add_drop_xy_get(C, op, &mval)) {
ED_object_location_from_view(C, add_info.loc); ED_object_location_from_view(C, add_info.loc);
@ -1928,11 +1928,13 @@ static int object_data_instance_add_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED; return OPERATOR_CANCELLED;
} }
int mval[2]; if (CTX_wm_region_view3d(C)) {
if (!RNA_property_is_set(op->ptr, prop_location) && object_add_drop_xy_get(C, op, &mval)) { int mval[2];
ED_object_location_from_view(C, loc); if (!RNA_property_is_set(op->ptr, prop_location) && object_add_drop_xy_get(C, op, &mval)) {
ED_view3d_cursor3d_position(C, mval, false, loc); ED_object_location_from_view(C, loc);
RNA_property_float_set_array(op->ptr, prop_location, loc); ED_view3d_cursor3d_position(C, mval, false, loc);
RNA_property_float_set_array(op->ptr, prop_location, loc);
}
} }
if (!ED_object_add_generic_get_opts( if (!ED_object_add_generic_get_opts(
@ -3927,7 +3929,7 @@ static int object_add_named_exec(bContext *C, wmOperator *op)
DEG_id_tag_update(&ob_add->id, ID_RECALC_TRANSFORM); DEG_id_tag_update(&ob_add->id, ID_RECALC_TRANSFORM);
} }
else { else if (CTX_wm_region_view3d(C)) {
int mval[2]; int mval[2];
if (object_add_drop_xy_get(C, op, &mval)) { if (object_add_drop_xy_get(C, op, &mval)) {
ED_object_location_from_view(C, basen->object->loc); ED_object_location_from_view(C, basen->object->loc);
@ -4029,7 +4031,7 @@ static int object_transform_to_mouse_exec(bContext *C, wmOperator *op)
MEM_freeN(objects); MEM_freeN(objects);
} }
else { else if (CTX_wm_region_view3d(C)) {
int mval[2]; int mval[2];
if (object_add_drop_xy_get(C, op, &mval)) { if (object_add_drop_xy_get(C, op, &mval)) {
float cursor[3]; float cursor[3];

View File

@ -1024,6 +1024,9 @@ static int time_segment_remove_exec(bContext *C, wmOperator *op)
TimeGpencilModifierData *gpmd = (TimeGpencilModifierData *)gpencil_edit_modifier_property_get( TimeGpencilModifierData *gpmd = (TimeGpencilModifierData *)gpencil_edit_modifier_property_get(
op, ob, eGpencilModifierType_Time); op, ob, eGpencilModifierType_Time);
if (gpmd == NULL) {
return OPERATOR_CANCELLED;
}
if (gpmd->segment_active_index < 0 || gpmd->segment_active_index >= gpmd->segments_len) { if (gpmd->segment_active_index < 0 || gpmd->segment_active_index >= gpmd->segments_len) {
return OPERATOR_CANCELLED; return OPERATOR_CANCELLED;
} }
@ -1100,6 +1103,9 @@ static int time_segment_move_exec(bContext *C, wmOperator *op)
TimeGpencilModifierData *gpmd = (TimeGpencilModifierData *)gpencil_edit_modifier_property_get( TimeGpencilModifierData *gpmd = (TimeGpencilModifierData *)gpencil_edit_modifier_property_get(
op, ob, eGpencilModifierType_Time); op, ob, eGpencilModifierType_Time);
if (gpmd == NULL) {
return OPERATOR_CANCELLED;
}
if (gpmd->segments_len < 2) { if (gpmd->segments_len < 2) {
return OPERATOR_CANCELLED; return OPERATOR_CANCELLED;
} }

View File

@ -1733,8 +1733,13 @@ static int modifier_apply_exec_ex(bContext *C, wmOperator *op, int apply_as, boo
Object *ob = ED_object_active_context(C); Object *ob = ED_object_active_context(C);
ModifierData *md = edit_modifier_property_get(op, ob, 0); ModifierData *md = edit_modifier_property_get(op, ob, 0);
const bool do_report = RNA_boolean_get(op->ptr, "report"); const bool do_report = RNA_boolean_get(op->ptr, "report");
const bool do_single_user = RNA_boolean_get(op->ptr, "single_user");
const bool do_merge_customdata = RNA_boolean_get(op->ptr, "merge_customdata"); const bool do_single_user = (apply_as == MODIFIER_APPLY_DATA) ?
RNA_boolean_get(op->ptr, "single_user") :
false;
const bool do_merge_customdata = (apply_as == MODIFIER_APPLY_DATA) ?
RNA_boolean_get(op->ptr, "merge_customdata") :
false;
if (md == nullptr) { if (md == nullptr) {
return OPERATOR_CANCELLED; return OPERATOR_CANCELLED;

View File

@ -2857,7 +2857,7 @@ void OBJECT_OT_drop_named_material(wmOperatorType *ot)
/* api callbacks */ /* api callbacks */
ot->invoke = drop_named_material_invoke; ot->invoke = drop_named_material_invoke;
ot->poll = ED_operator_objectmode_poll_msg; ot->poll = ED_operator_objectmode_with_view3d_poll_msg;
/* flags */ /* flags */
ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL; ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;

View File

@ -213,6 +213,17 @@ bool ED_operator_objectmode_poll_msg(bContext *C)
return true; return true;
} }
bool ED_operator_objectmode_with_view3d_poll_msg(bContext *C)
{
if (!ED_operator_objectmode_poll_msg(C)) {
return false;
}
if (!ED_operator_region_view3d_active(C)) {
return false;
}
return true;
}
static bool ed_spacetype_test(bContext *C, int type) static bool ed_spacetype_test(bContext *C, int type)
{ {
if (ED_operator_areaactive(C)) { if (ED_operator_areaactive(C)) {
@ -237,6 +248,19 @@ bool ED_operator_region_view3d_active(bContext *C)
return false; return false;
} }
bool ED_operator_region_gizmo_active(bContext *C)
{
ARegion *region = CTX_wm_region(C);
if (region == NULL) {
return false;
}
wmGizmoMap *gzmap = region->gizmo_map;
if (gzmap == NULL) {
return false;
}
return true;
}
bool ED_operator_animview_active(bContext *C) bool ED_operator_animview_active(bContext *C)
{ {
if (ED_operator_areaactive(C)) { if (ED_operator_areaactive(C)) {
@ -4354,23 +4378,25 @@ static int screen_context_menu_invoke(bContext *C,
ed_screens_statusbar_menu_create(layout, NULL); ed_screens_statusbar_menu_create(layout, NULL);
UI_popup_menu_end(C, pup); UI_popup_menu_end(C, pup);
} }
else if (ELEM(region->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) { else if (region) {
uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Header"), ICON_NONE); if (ELEM(region->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) {
uiLayout *layout = UI_popup_menu_layout(pup); uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Header"), ICON_NONE);
ED_screens_header_tools_menu_create(C, layout, NULL); uiLayout *layout = UI_popup_menu_layout(pup);
UI_popup_menu_end(C, pup); ED_screens_header_tools_menu_create(C, layout, NULL);
} UI_popup_menu_end(C, pup);
else if (region->regiontype == RGN_TYPE_FOOTER) { }
uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Footer"), ICON_NONE); else if (region->regiontype == RGN_TYPE_FOOTER) {
uiLayout *layout = UI_popup_menu_layout(pup); uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Footer"), ICON_NONE);
ED_screens_footer_tools_menu_create(C, layout, NULL); uiLayout *layout = UI_popup_menu_layout(pup);
UI_popup_menu_end(C, pup); ED_screens_footer_tools_menu_create(C, layout, NULL);
} UI_popup_menu_end(C, pup);
else if (region->regiontype == RGN_TYPE_NAV_BAR) { }
uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Navigation Bar"), ICON_NONE); else if (region->regiontype == RGN_TYPE_NAV_BAR) {
uiLayout *layout = UI_popup_menu_layout(pup); uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Navigation Bar"), ICON_NONE);
ED_screens_navigation_bar_tools_menu_create(C, layout, NULL); uiLayout *layout = UI_popup_menu_layout(pup);
UI_popup_menu_end(C, pup); ED_screens_navigation_bar_tools_menu_create(C, layout, NULL);
UI_popup_menu_end(C, pup);
}
} }
return OPERATOR_INTERFACE; return OPERATOR_INTERFACE;

View File

@ -202,8 +202,9 @@ static void stroke_done(const bContext *C, PaintStroke *stroke)
static int sculpt_curves_stroke_invoke(bContext *C, wmOperator *op, const wmEvent *event) static int sculpt_curves_stroke_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{ {
const Paint *paint = BKE_paint_get_active_from_context(C); Scene *scene = CTX_data_scene(C);
const Brush *brush = BKE_paint_brush_for_read(paint); Paint *paint = BKE_paint_get_active_from_paintmode(scene, PAINT_MODE_SCULPT_CURVES);
const Brush *brush = paint ? BKE_paint_brush_for_read(paint) : nullptr;
if (brush == nullptr) { if (brush == nullptr) {
return OPERATOR_CANCELLED; return OPERATOR_CANCELLED;
} }

View File

@ -2049,7 +2049,7 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
bool use_original = false; bool use_original = false;
bool normal_test_r, area_test_r; bool normal_test_r, area_test_r;
if (ss->cache && ss->cache->original) { if (ss->cache && !ss->cache->accum) {
unode = SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_COORDS); unode = SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
use_original = (unode->co || unode->bm_entry); use_original = (unode->co || unode->bm_entry);
} }
@ -3436,7 +3436,7 @@ static void sculpt_topology_update(Sculpt *sd,
/* Build a list of all nodes that are potentially within the brush's area of influence. */ /* Build a list of all nodes that are potentially within the brush's area of influence. */
const bool use_original = sculpt_tool_needs_original(brush->sculpt_tool) ? true : const bool use_original = sculpt_tool_needs_original(brush->sculpt_tool) ? true :
ss->cache->original; !ss->cache->accum;
const float radius_scale = 1.25f; const float radius_scale = 1.25f;
Vector<PBVHNode *> nodes = sculpt_pbvh_gather_generic(ob, sd, brush, use_original, radius_scale); Vector<PBVHNode *> nodes = sculpt_pbvh_gather_generic(ob, sd, brush, use_original, radius_scale);
@ -3547,7 +3547,7 @@ static void do_brush_action(Sculpt *sd,
} }
const bool use_original = sculpt_tool_needs_original(brush->sculpt_tool) ? true : const bool use_original = sculpt_tool_needs_original(brush->sculpt_tool) ? true :
ss->cache->original; !ss->cache->accum;
const bool use_pixels = sculpt_needs_pbvh_pixels(paint_mode_settings, brush, ob); const bool use_pixels = sculpt_needs_pbvh_pixels(paint_mode_settings, brush, ob);
if (sculpt_needs_pbvh_pixels(paint_mode_settings, brush, ob)) { if (sculpt_needs_pbvh_pixels(paint_mode_settings, brush, ob)) {
@ -4546,26 +4546,24 @@ static void sculpt_update_cache_invariants(
normalize_v3(cache->true_gravity_direction); normalize_v3(cache->true_gravity_direction);
} }
cache->accum = true;
/* Make copies of the mesh vertex locations and normals for some tools. */ /* Make copies of the mesh vertex locations and normals for some tools. */
if (brush->flag & BRUSH_ANCHORED) { if (brush->flag & BRUSH_ANCHORED) {
cache->original = true; cache->accum = false;
}
if (SCULPT_automasking_needs_original(sd, brush)) {
cache->original = true;
} }
/* Draw sharp does not need the original coordinates to produce the accumulate effect, so it /* Draw sharp does not need the original coordinates to produce the accumulate effect, so it
* should work the opposite way. */ * should work the opposite way. */
if (brush->sculpt_tool == SCULPT_TOOL_DRAW_SHARP) { if (brush->sculpt_tool == SCULPT_TOOL_DRAW_SHARP) {
cache->original = true; cache->accum = false;
} }
if (SCULPT_TOOL_HAS_ACCUMULATE(brush->sculpt_tool)) { if (SCULPT_TOOL_HAS_ACCUMULATE(brush->sculpt_tool)) {
if (!(brush->flag & BRUSH_ACCUMULATE)) { if (!(brush->flag & BRUSH_ACCUMULATE)) {
cache->original = true; cache->accum = false;
if (brush->sculpt_tool == SCULPT_TOOL_DRAW_SHARP) { if (brush->sculpt_tool == SCULPT_TOOL_DRAW_SHARP) {
cache->original = false; cache->accum = true;
} }
} }
} }
@ -4574,7 +4572,7 @@ static void sculpt_update_cache_invariants(
* for image brushes. It's also not necessary, just disable it. */ * for image brushes. It's also not necessary, just disable it. */
if (brush && brush->sculpt_tool == SCULPT_TOOL_PAINT && if (brush && brush->sculpt_tool == SCULPT_TOOL_PAINT &&
SCULPT_use_image_paint_brush(&tool_settings->paint_mode, ob)) { SCULPT_use_image_paint_brush(&tool_settings->paint_mode, ob)) {
cache->original = false; cache->accum = true;
} }
cache->first_time = true; cache->first_time = true;
@ -5068,7 +5066,7 @@ float SCULPT_raycast_init(ViewContext *vc,
float obimat[4][4]; float obimat[4][4];
float dist; float dist;
Object *ob = vc->obact; Object *ob = vc->obact;
RegionView3D *rv3d = static_cast<RegionView3D *>(vc->region->regiondata); RegionView3D *rv3d = vc->rv3d;
View3D *v3d = vc->v3d; View3D *v3d = vc->v3d;
/* TODO: what if the segment is totally clipped? (return == 0). */ /* TODO: what if the segment is totally clipped? (return == 0). */
@ -5117,7 +5115,7 @@ bool SCULPT_cursor_geometry_info_update(bContext *C,
ob = vc.obact; ob = vc.obact;
ss = ob->sculpt; ss = ob->sculpt;
if (!ss->pbvh) { if (!ss->pbvh || !vc.rv3d) {
zero_v3(out->location); zero_v3(out->location);
zero_v3(out->normal); zero_v3(out->normal);
zero_v3(out->active_vertex_co); zero_v3(out->active_vertex_co);
@ -5253,7 +5251,7 @@ bool SCULPT_stroke_get_location_ex(bContext *C,
ss = ob->sculpt; ss = ob->sculpt;
cache = ss->cache; cache = ss->cache;
original = force_original || ((cache) ? cache->original : false); original = force_original || ((cache) ? !cache->accum : false);
const Brush *brush = BKE_paint_brush(BKE_paint_get_active_from_context(C)); const Brush *brush = BKE_paint_brush(BKE_paint_get_active_from_context(C));

View File

@ -335,7 +335,6 @@ static int sculpt_color_filter_init(bContext *C, wmOperator *op)
Object *ob = CTX_data_active_object(C); Object *ob = CTX_data_active_object(C);
Sculpt *sd = CTX_data_tool_settings(C)->sculpt; Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
SculptSession *ss = ob->sculpt; SculptSession *ss = ob->sculpt;
PBVH *pbvh = ob->sculpt->pbvh;
View3D *v3d = CTX_wm_view3d(C); View3D *v3d = CTX_wm_view3d(C);
int mval[2]; int mval[2];
@ -360,6 +359,7 @@ static int sculpt_color_filter_init(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED; return OPERATOR_CANCELLED;
} }
const PBVHType pbvh_type_prev = BKE_pbvh_type(ss->pbvh);
SCULPT_undo_push_begin(ob, op); SCULPT_undo_push_begin(ob, op);
BKE_sculpt_color_layer_create_if_needed(ob); BKE_sculpt_color_layer_create_if_needed(ob);
@ -367,8 +367,7 @@ static int sculpt_color_filter_init(bContext *C, wmOperator *op)
* earlier steps modifying the data. */ * earlier steps modifying the data. */
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, true); BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, true);
if (pbvh_type_prev == PBVH_FACES && !ob->sculpt->pmap) {
if (BKE_pbvh_type(pbvh) == PBVH_FACES && !ob->sculpt->pmap) {
return OPERATOR_CANCELLED; return OPERATOR_CANCELLED;
} }

View File

@ -613,7 +613,10 @@ struct StrokeCache {
int radial_symmetry_pass; int radial_symmetry_pass;
float symm_rot_mat[4][4]; float symm_rot_mat[4][4];
float symm_rot_mat_inv[4][4]; float symm_rot_mat_inv[4][4];
bool original;
/* Accumulate mode. Note: inverted for SCULPT_TOOL_DRAW_SHARP. */
bool accum;
float anchored_location[3]; float anchored_location[3];
/* Paint Brush. */ /* Paint Brush. */

View File

@ -906,9 +906,12 @@ static int sculpt_mask_by_color_invoke(bContext *C, wmOperator *op, const wmEven
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Object *ob = CTX_data_active_object(C); Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt; SculptSession *ss = ob->sculpt;
View3D *v3d = CTX_wm_view3d(C);
if (v3d->shading.type == OB_SOLID) { {
v3d->shading.color_type = V3D_SHADING_VERTEX_COLOR; View3D *v3d = CTX_wm_view3d(C);
if (v3d && v3d->shading.type == OB_SOLID) {
v3d->shading.color_type = V3D_SHADING_VERTEX_COLOR;
}
} }
/* Color data is not available in multi-resolution or dynamic topology. */ /* Color data is not available in multi-resolution or dynamic topology. */

View File

@ -177,7 +177,8 @@ enum {
}; };
struct FileListEntryPreview { struct FileListEntryPreview {
char filepath[FILE_MAX]; /** Use #FILE_MAX_LIBEXTRA as this is the size written into by #filelist_file_get_full_path. */
char filepath[FILE_MAX_LIBEXTRA];
uint flags; uint flags;
int index; int index;
int attributes; /* from FileDirEntry. */ int attributes; /* from FileDirEntry. */
@ -3111,7 +3112,7 @@ static void filelist_readjob_list_lib_add_datablock(FileListReadJob *job_params,
{ {
FileListInternEntry *entry = MEM_cnew<FileListInternEntry>(__func__); FileListInternEntry *entry = MEM_cnew<FileListInternEntry>(__func__);
if (prefix_relpath_with_group_name) { if (prefix_relpath_with_group_name) {
std::string datablock_path = StringRef(group_name) + "/" + datablock_info->name; std::string datablock_path = StringRef(group_name) + SEP_STR + datablock_info->name;
entry->relpath = current_relpath_append(job_params, datablock_path.c_str()); entry->relpath = current_relpath_append(job_params, datablock_path.c_str());
} }
else { else {
@ -3791,7 +3792,7 @@ static void filelist_readjob_main_assets_add_items(FileListReadJob *job_params,
const char *id_code_name = BKE_idtype_idcode_to_name(GS(id_iter->name)); const char *id_code_name = BKE_idtype_idcode_to_name(GS(id_iter->name));
entry = MEM_cnew<FileListInternEntry>(__func__); entry = MEM_cnew<FileListInternEntry>(__func__);
std::string datablock_path = StringRef(id_code_name) + "/" + (id_iter->name + 2); std::string datablock_path = StringRef(id_code_name) + SEP_STR + (id_iter->name + 2);
entry->relpath = current_relpath_append(job_params, datablock_path.c_str()); entry->relpath = current_relpath_append(job_params, datablock_path.c_str());
entry->name = id_iter->name + 2; entry->name = id_iter->name + 2;
entry->free_name = false; entry->free_name = false;

View File

@ -847,7 +847,7 @@ static void create_inspection_string_for_generic_value(const bNodeSocket &socket
return; return;
} }
if (value_type.is<std::string>()) { if (value_type.is<std::string>()) {
ss << *static_cast<const std::string *>(buffer) << TIP_(" (String)"); ss << *static_cast<const std::string *>(buffer) << " " << TIP_("(String)");
return; return;
} }
@ -864,22 +864,22 @@ static void create_inspection_string_for_generic_value(const bNodeSocket &socket
BLI_SCOPED_DEFER([&]() { socket_type.destruct(socket_value); }); BLI_SCOPED_DEFER([&]() { socket_type.destruct(socket_value); });
if (socket_type.is<int>()) { if (socket_type.is<int>()) {
ss << *static_cast<int *>(socket_value) << TIP_(" (Integer)"); ss << *static_cast<int *>(socket_value) << " " << TIP_("(Integer)");
} }
else if (socket_type.is<float>()) { else if (socket_type.is<float>()) {
ss << *static_cast<float *>(socket_value) << TIP_(" (Float)"); ss << *static_cast<float *>(socket_value) << " " << TIP_("(Float)");
} }
else if (socket_type.is<blender::float3>()) { else if (socket_type.is<blender::float3>()) {
ss << *static_cast<blender::float3 *>(socket_value) << TIP_(" (Vector)"); ss << *static_cast<blender::float3 *>(socket_value) << " " << TIP_("(Vector)");
} }
else if (socket_type.is<blender::ColorGeometry4f>()) { else if (socket_type.is<blender::ColorGeometry4f>()) {
const blender::ColorGeometry4f &color = *static_cast<blender::ColorGeometry4f *>(socket_value); const blender::ColorGeometry4f &color = *static_cast<blender::ColorGeometry4f *>(socket_value);
ss << "(" << color.r << ", " << color.g << ", " << color.b << ", " << color.a << ")" ss << "(" << color.r << ", " << color.g << ", " << color.b << ", " << color.a << ") "
<< TIP_(" (Color)"); << TIP_("(Color)");
} }
else if (socket_type.is<bool>()) { else if (socket_type.is<bool>()) {
ss << ((*static_cast<bool *>(socket_value)) ? TIP_("True") : TIP_("False")) ss << ((*static_cast<bool *>(socket_value)) ? TIP_("True") : TIP_("False")) << " "
<< TIP_(" (Boolean)"); << TIP_("(Boolean)");
} }
} }
@ -893,32 +893,32 @@ static void create_inspection_string_for_field_info(const bNodeSocket &socket,
if (input_tooltips.is_empty()) { if (input_tooltips.is_empty()) {
/* Should have been logged as constant value. */ /* Should have been logged as constant value. */
BLI_assert_unreachable(); BLI_assert_unreachable();
ss << "Value has not been logged"; ss << TIP_("Value has not been logged");
} }
else { else {
if (socket_type.is<int>()) { if (socket_type.is<int>()) {
ss << TIP_("Integer field"); ss << TIP_("Integer field based on:");
} }
else if (socket_type.is<float>()) { else if (socket_type.is<float>()) {
ss << TIP_("Float field"); ss << TIP_("Float field based on:");
} }
else if (socket_type.is<blender::float3>()) { else if (socket_type.is<blender::float3>()) {
ss << TIP_("Vector field"); ss << TIP_("Vector field based on:");
} }
else if (socket_type.is<bool>()) { else if (socket_type.is<bool>()) {
ss << TIP_("Boolean field"); ss << TIP_("Boolean field based on:");
} }
else if (socket_type.is<std::string>()) { else if (socket_type.is<std::string>()) {
ss << TIP_("String field"); ss << TIP_("String field based on:");
} }
else if (socket_type.is<blender::ColorGeometry4f>()) { else if (socket_type.is<blender::ColorGeometry4f>()) {
ss << TIP_("Color field"); ss << TIP_("Color field based on:");
} }
ss << TIP_(" based on:\n"); ss << "\n";
for (const int i : input_tooltips.index_range()) { for (const int i : input_tooltips.index_range()) {
const blender::StringRef tooltip = input_tooltips[i]; const blender::StringRef tooltip = input_tooltips[i];
ss << "\u2022 " << tooltip; ss << "\u2022 " << TIP_(tooltip.data());
if (i < input_tooltips.size() - 1) { if (i < input_tooltips.size() - 1) {
ss << ".\n"; ss << ".\n";
} }
@ -941,7 +941,7 @@ static void create_inspection_string_for_geometry_info(const geo_log::GeometryIn
return std::string(str); return std::string(str);
}; };
ss << TIP_("Geometry:\n"); ss << TIP_("Geometry:") << "\n";
for (GeometryComponentType type : component_types) { for (GeometryComponentType type : component_types) {
switch (type) { switch (type) {
case GEO_COMPONENT_TYPE_MESH: { case GEO_COMPONENT_TYPE_MESH: {
@ -1865,7 +1865,7 @@ static char *named_attribute_tooltip(bContext * /*C*/, void *argN, const char *
NamedAttributeTooltipArg &arg = *static_cast<NamedAttributeTooltipArg *>(argN); NamedAttributeTooltipArg &arg = *static_cast<NamedAttributeTooltipArg *>(argN);
std::stringstream ss; std::stringstream ss;
ss << TIP_("Accessed named attributes:\n"); ss << TIP_("Accessed named attributes:") << "\n";
struct NameWithUsage { struct NameWithUsage {
StringRefNull name; StringRefNull name;
@ -1917,7 +1917,7 @@ static NodeExtraInfoRow row_from_used_named_attribute(
NodeExtraInfoRow row; NodeExtraInfoRow row;
row.text = std::to_string(attributes_num) + row.text = std::to_string(attributes_num) +
TIP_(attributes_num == 1 ? " Named Attribute" : " Named Attributes"); (attributes_num == 1 ? TIP_(" Named Attribute") : TIP_(" Named Attributes"));
row.icon = ICON_SPREADSHEET; row.icon = ICON_SPREADSHEET;
row.tooltip_fn = named_attribute_tooltip; row.tooltip_fn = named_attribute_tooltip;
row.tooltip_fn_arg = new NamedAttributeTooltipArg{usage_by_attribute_name}; row.tooltip_fn_arg = new NamedAttributeTooltipArg{usage_by_attribute_name};

View File

@ -52,7 +52,7 @@ void SEQUENCER_OT_rename_channel(struct wmOperatorType *ot)
/* Api callbacks. */ /* Api callbacks. */
ot->invoke = sequencer_rename_channel_invoke; ot->invoke = sequencer_rename_channel_invoke;
ot->poll = sequencer_edit_poll; ot->poll = sequencer_edit_with_channel_region_poll;
/* Flags. */ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;

View File

@ -175,6 +175,18 @@ bool sequencer_edit_poll(bContext *C)
return (SEQ_editing_get(CTX_data_scene(C)) != NULL); return (SEQ_editing_get(CTX_data_scene(C)) != NULL);
} }
bool sequencer_edit_with_channel_region_poll(bContext *C)
{
if (!sequencer_edit_poll(C)) {
return false;
}
ARegion *region = CTX_wm_region(C);
if (!(region && (region->regiontype == RGN_TYPE_CHANNELS))) {
return false;
}
return true;
}
bool sequencer_editing_initialized_and_active(bContext *C) bool sequencer_editing_initialized_and_active(bContext *C)
{ {
return ED_operator_sequencer_active(C) && sequencer_edit_poll(C); return ED_operator_sequencer_active(C) && sequencer_edit_poll(C);
@ -1482,14 +1494,14 @@ static int sequencer_split_invoke(bContext *C, wmOperator *op, const wmEvent *ev
} }
} }
float mouseloc[2]; float mouseloc[2];
UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &mouseloc[0], &mouseloc[1]); if (v2d) {
if (RNA_boolean_get(op->ptr, "use_cursor_position")) { UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &mouseloc[0], &mouseloc[1]);
RNA_int_set(op->ptr, "frame", mouseloc[0]); if (RNA_boolean_get(op->ptr, "use_cursor_position")) {
split_frame = mouseloc[0];
}
RNA_int_set(op->ptr, "channel", mouseloc[1]);
} }
else { RNA_int_set(op->ptr, "frame", split_frame);
RNA_int_set(op->ptr, "frame", split_frame);
}
RNA_int_set(op->ptr, "channel", mouseloc[1]);
RNA_enum_set(op->ptr, "side", split_side); RNA_enum_set(op->ptr, "side", split_side);
// RNA_enum_set(op->ptr, "type", split_hard); // RNA_enum_set(op->ptr, "type", split_hard);
@ -1711,16 +1723,17 @@ static int sequencer_delete_exec(bContext *C, wmOperator *op)
static int sequencer_delete_invoke(bContext *C, wmOperator *op, const wmEvent *event) static int sequencer_delete_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{ {
ARegion *region = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C); Scene *scene = CTX_data_scene(C);
ListBase *markers = &scene->markers; ListBase *markers = &scene->markers;
if (region->regiontype == RGN_TYPE_WINDOW && !BLI_listbase_is_empty(markers)) { if (!BLI_listbase_is_empty(markers)) {
/* Bounding box of 30 pixels is used for markers shortcuts, ARegion *region = CTX_wm_region(C);
* prevent conflict with markers shortcuts here. if (region && (region->regiontype == RGN_TYPE_WINDOW)) {
*/ /* Bounding box of 30 pixels is used for markers shortcuts,
if (event->mval[1] <= 30) { * prevent conflict with markers shortcuts here. */
return OPERATOR_PASS_THROUGH; if (event->mval[1] <= 30) {
return OPERATOR_PASS_THROUGH;
}
} }
} }
@ -1731,9 +1744,9 @@ void SEQUENCER_OT_delete(wmOperatorType *ot)
{ {
/* Identifiers. */ /* Identifiers. */
ot->name = "Erase Strips"; ot->name = "Delete Strips";
ot->idname = "SEQUENCER_OT_delete"; ot->idname = "SEQUENCER_OT_delete";
ot->description = "Erase selected strips from the sequencer"; ot->description = "Delete selected strips from the sequencer";
/* Api callbacks. */ /* Api callbacks. */
ot->invoke = sequencer_delete_invoke; ot->invoke = sequencer_delete_invoke;

View File

@ -141,6 +141,7 @@ int seq_effect_find_selected(struct Scene *scene,
/* Operator helpers. */ /* Operator helpers. */
bool sequencer_edit_poll(struct bContext *C); bool sequencer_edit_poll(struct bContext *C);
bool sequencer_edit_with_channel_region_poll(struct bContext *C);
bool sequencer_editing_initialized_and_active(struct bContext *C); bool sequencer_editing_initialized_and_active(struct bContext *C);
/* UNUSED */ /* UNUSED */
/* bool sequencer_strip_poll(struct bContext *C); */ /* bool sequencer_strip_poll(struct bContext *C); */

View File

@ -41,14 +41,15 @@ using blender::MutableSpan;
static bool retiming_poll(bContext *C) static bool retiming_poll(bContext *C)
{ {
if (!sequencer_edit_poll(C)) { const Editing *ed = SEQ_editing_get(CTX_data_scene(C));
if (ed == nullptr) {
return false; return false;
} }
const Editing *ed = SEQ_editing_get(CTX_data_scene(C));
Sequence *seq = ed->act_seq; Sequence *seq = ed->act_seq;
if (seq == nullptr) {
if (seq != nullptr && !SEQ_retiming_is_allowed(seq)) { return false;
}
if (!SEQ_retiming_is_allowed(seq)) {
CTX_wm_operator_poll_msg_set(C, "This strip type can not be retimed"); CTX_wm_operator_poll_msg_set(C, "This strip type can not be retimed");
return false; return false;
} }

View File

@ -568,7 +568,7 @@ static void spreadsheet_footer_region_draw(const bContext *C, ARegion *region)
SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C); SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
SpaceSpreadsheet_Runtime *runtime = sspreadsheet->runtime; SpaceSpreadsheet_Runtime *runtime = sspreadsheet->runtime;
std::stringstream ss; std::stringstream ss;
ss << "Rows: "; ss << IFACE_("Rows:") << " ";
if (runtime->visible_rows != runtime->tot_rows) { if (runtime->visible_rows != runtime->tot_rows) {
char visible_rows_str[BLI_STR_FORMAT_INT32_GROUPED_SIZE]; char visible_rows_str[BLI_STR_FORMAT_INT32_GROUPED_SIZE];
BLI_str_format_int_grouped(visible_rows_str, runtime->visible_rows); BLI_str_format_int_grouped(visible_rows_str, runtime->visible_rows);
@ -576,7 +576,7 @@ static void spreadsheet_footer_region_draw(const bContext *C, ARegion *region)
} }
char tot_rows_str[BLI_STR_FORMAT_INT32_GROUPED_SIZE]; char tot_rows_str[BLI_STR_FORMAT_INT32_GROUPED_SIZE];
BLI_str_format_int_grouped(tot_rows_str, runtime->tot_rows); BLI_str_format_int_grouped(tot_rows_str, runtime->tot_rows);
ss << tot_rows_str << " | Columns: " << runtime->tot_columns; ss << tot_rows_str << " | " << IFACE_("Columns:") << " " << runtime->tot_columns;
std::string stats_str = ss.str(); std::string stats_str = ss.str();
UI_ThemeClearColor(TH_BACK); UI_ThemeClearColor(TH_BACK);

View File

@ -102,6 +102,7 @@ static void SPREADSHEET_OT_change_spreadsheet_data_source(wmOperatorType *ot)
ot->idname = "SPREADSHEET_OT_change_spreadsheet_data_source"; ot->idname = "SPREADSHEET_OT_change_spreadsheet_data_source";
ot->invoke = select_component_domain_invoke; ot->invoke = select_component_domain_invoke;
ot->poll = ED_operator_spreadsheet_active;
RNA_def_int(ot->srna, "component_type", 0, 0, INT16_MAX, "Component Type", "", 0, INT16_MAX); RNA_def_int(ot->srna, "component_type", 0, 0, INT16_MAX, "Component Type", "", 0, INT16_MAX);
RNA_def_int(ot->srna, RNA_def_int(ot->srna,

View File

@ -860,7 +860,7 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
posit[0] = co_ss[1][0] - (numstr_size[0] / 2.0f); posit[0] = co_ss[1][0] - (numstr_size[0] / 2.0f);
posit[1] = co_ss[1][1] - (numstr_size[1] / 2.0f); posit[1] = co_ss[1][1] - (numstr_size[1] / 2.0f);
/* Adjust text position to help readability. */ /* Adjust text position to help readability. */
sub_v2_v2v2(dir_ruler, co_ss[0], co_ss[1]); sub_v2_v2v2(dir_ruler, co_ss[0], co_ss[1]);
float rot_90_vec[2] = {-dir_ruler[1], dir_ruler[0]}; float rot_90_vec[2] = {-dir_ruler[1], dir_ruler[0]};
normalize_v2(rot_90_vec); normalize_v2(rot_90_vec);
@ -941,7 +941,7 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
/* center text */ /* center text */
posit -= numstr_size / 2.0f; posit -= numstr_size / 2.0f;
/* Adjust text position if this helps readability. */ /* Adjust text position if this helps readability. */
const float len = len_v2v2(co_ss[0], co_ss[2]); const float len = len_v2v2(co_ss[0], co_ss[2]);

View File

@ -494,7 +494,7 @@ bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3])
static eViewOpsFlag viewops_flag_from_prefs(void) static eViewOpsFlag viewops_flag_from_prefs(void)
{ {
const bool use_select = (U.uiflag & USER_ORBIT_SELECTION) != 0; const bool use_select = (U.uiflag & USER_ORBIT_SELECTION) != 0;
const bool use_depth = (U.uiflag & VIEWOPS_FLAG_DEPTH_NAVIGATE) != 0; const bool use_depth = (U.uiflag & USER_DEPTH_NAVIGATE) != 0;
const bool use_zoom_to_mouse = (U.uiflag & USER_ZOOM_TO_MOUSEPOS) != 0; const bool use_zoom_to_mouse = (U.uiflag & USER_ZOOM_TO_MOUSEPOS) != 0;
enum eViewOpsFlag flag = VIEWOPS_FLAG_NONE; enum eViewOpsFlag flag = VIEWOPS_FLAG_NONE;

View File

@ -909,9 +909,12 @@ static void view3d_interactive_add_exit(bContext *C, wmOperator *op)
struct InteractivePlaceData *ipd = op->customdata; struct InteractivePlaceData *ipd = op->customdata;
ED_view3d_cursor_snap_deactive(ipd->snap_state); ED_view3d_cursor_snap_deactive(ipd->snap_state);
ED_region_draw_cb_exit(ipd->region->type, ipd->draw_handle_view); if (ipd->region != NULL) {
if (ipd->draw_handle_view != NULL) {
ED_region_tag_redraw(ipd->region); ED_region_draw_cb_exit(ipd->region->type, ipd->draw_handle_view);
}
ED_region_tag_redraw(ipd->region);
}
MEM_freeN(ipd); MEM_freeN(ipd);
} }

View File

@ -778,7 +778,14 @@ static void drawLine(
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); float viewport[4];
GPU_viewport_size_get_f(viewport);
GPU_blend(GPU_BLEND_ALPHA);
immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
immUniform2fv("viewportSize", &viewport[2]);
immUniform1f("lineWidth", U.pixelsize * 2.0f);
immUniformColor3ubv(col2); immUniformColor3ubv(col2);
immBegin(GPU_PRIM_LINES, 2); immBegin(GPU_PRIM_LINES, 2);

View File

@ -1233,7 +1233,6 @@ static void uvedit_pack_islands_multi(const Scene *scene,
MemArena *arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); MemArena *arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
Heap *heap = BLI_heap_new(); Heap *heap = BLI_heap_new();
float scale[2] = {1.0f, 1.0f};
blender::Vector<blender::geometry::PackIsland *> pack_island_vector; blender::Vector<blender::geometry::PackIsland *> pack_island_vector;
for (int i = 0; i < island_vector.size(); i++) { for (int i = 0; i < island_vector.size(); i++) {
FaceIsland *face_island = island_vector[i]; FaceIsland *face_island = island_vector[i];
@ -1264,7 +1263,7 @@ static void uvedit_pack_islands_multi(const Scene *scene,
BLI_heap_free(heap, nullptr); BLI_heap_free(heap, nullptr);
BLI_memarena_free(arena); BLI_memarena_free(arena);
pack_islands(pack_island_vector, *params, scale); const float scale = pack_islands(pack_island_vector, *params);
float base_offset[2] = {0.0f, 0.0f}; float base_offset[2] = {0.0f, 0.0f};
copy_v2_v2(base_offset, params->udim_base_offset); copy_v2_v2(base_offset, params->udim_base_offset);
@ -1306,7 +1305,7 @@ static void uvedit_pack_islands_multi(const Scene *scene,
for (int64_t i : pack_island_vector.index_range()) { for (int64_t i : pack_island_vector.index_range()) {
blender::geometry::PackIsland *pack_island = pack_island_vector[i]; blender::geometry::PackIsland *pack_island = pack_island_vector[i];
FaceIsland *island = island_vector[pack_island->caller_index]; FaceIsland *island = island_vector[pack_island->caller_index];
pack_island->build_transformation(scale[0], pack_island->angle, matrix); pack_island->build_transformation(scale, pack_island->angle, matrix);
invert_m2_m2(matrix_inverse, matrix); invert_m2_m2(matrix_inverse, matrix);
/* Add base_offset, post transform. */ /* Add base_offset, post transform. */
@ -1323,7 +1322,7 @@ static void uvedit_pack_islands_multi(const Scene *scene,
const float rescale_x = (selection_max_co[0] - selection_min_co[0]) / const float rescale_x = (selection_max_co[0] - selection_min_co[0]) /
params->target_aspect_y; params->target_aspect_y;
const float rescale_y = (selection_max_co[1] - selection_min_co[1]); const float rescale_y = (selection_max_co[1] - selection_min_co[1]);
const float rescale = std::min(rescale_x, rescale_y); const float rescale = params->scale_to_fit ? std::min(rescale_x, rescale_y) : 1.0f;
matrix[0][0] = rescale; matrix[0][0] = rescale;
matrix[0][1] = 0.0f; matrix[0][1] = 0.0f;
matrix[1][0] = 0.0f; matrix[1][0] = 0.0f;
@ -1396,6 +1395,7 @@ static int pack_islands_exec(bContext *C, wmOperator *op)
blender::geometry::UVPackIsland_Params pack_island_params; blender::geometry::UVPackIsland_Params pack_island_params;
pack_island_params.setFromUnwrapOptions(options); pack_island_params.setFromUnwrapOptions(options);
pack_island_params.rotate = RNA_boolean_get(op->ptr, "rotate"); pack_island_params.rotate = RNA_boolean_get(op->ptr, "rotate");
pack_island_params.scale_to_fit = RNA_boolean_get(op->ptr, "scale");
pack_island_params.merge_overlap = RNA_boolean_get(op->ptr, "merge_overlap"); pack_island_params.merge_overlap = RNA_boolean_get(op->ptr, "merge_overlap");
pack_island_params.ignore_pinned = false; pack_island_params.ignore_pinned = false;
pack_island_params.margin_method = eUVPackIsland_MarginMethod( pack_island_params.margin_method = eUVPackIsland_MarginMethod(
@ -1474,6 +1474,7 @@ void UV_OT_pack_islands(wmOperatorType *ot)
/* properties */ /* properties */
RNA_def_enum(ot->srna, "udim_source", pack_target, PACK_UDIM_SRC_CLOSEST, "Pack to", ""); RNA_def_enum(ot->srna, "udim_source", pack_target, PACK_UDIM_SRC_CLOSEST, "Pack to", "");
RNA_def_boolean(ot->srna, "rotate", true, "Rotate", "Rotate islands for best fit"); RNA_def_boolean(ot->srna, "rotate", true, "Rotate", "Rotate islands for best fit");
RNA_def_boolean(ot->srna, "scale", true, "Scale", "Scale islands to fill unit square");
RNA_def_boolean( RNA_def_boolean(
ot->srna, "merge_overlap", false, "Merge Overlapped", "Overlapping islands stick together"); ot->srna, "merge_overlap", false, "Merge Overlapped", "Overlapping islands stick together");
RNA_def_enum(ot->srna, RNA_def_enum(ot->srna,

View File

@ -48,6 +48,8 @@ class UVPackIsland_Params {
/** Islands can be rotated to improve packing. */ /** Islands can be rotated to improve packing. */
bool rotate; bool rotate;
/** Resize islands to fill the unit square. */
bool scale_to_fit;
/** (In UV Editor) only pack islands which have one or more selected UVs. */ /** (In UV Editor) only pack islands which have one or more selected UVs. */
bool only_selected_uvs; bool only_selected_uvs;
/** (In 3D Viewport or UV Editor) only pack islands which have selected faces. */ /** (In 3D Viewport or UV Editor) only pack islands which have selected faces. */
@ -110,18 +112,17 @@ class PackIsland {
void place_(const float scale, const uv_phi phi); void place_(const float scale, const uv_phi phi);
void finalize_geometry_(const UVPackIsland_Params &params, MemArena *arena, Heap *heap); void finalize_geometry_(const UVPackIsland_Params &params, MemArena *arena, Heap *heap);
blender::Vector<float2> triangle_vertices_;
private: private:
void calculate_pivot_(); /* Calculate `pivot_` and `half_diagonal_` based on added triangles. */ void calculate_pivot_(); /* Calculate `pivot_` and `half_diagonal_` based on added triangles. */
void calculate_pre_rotation_(const UVPackIsland_Params &params); void calculate_pre_rotation_(const UVPackIsland_Params &params);
blender::Vector<float2> triangle_vertices_;
friend class Occupancy; friend class Occupancy;
friend class OverlapMerger; friend class OverlapMerger;
}; };
void pack_islands(const Span<PackIsland *> &islands, float pack_islands(const Span<PackIsland *> &islands, const UVPackIsland_Params &params);
const UVPackIsland_Params &params,
float r_scale[2]);
/** Compute `r = mat * (a + b)` with high precision. */ /** Compute `r = mat * (a + b)` with high precision. */
void mul_v2_m2_add_v2v2(float r[2], const float mat[2][2], const float a[2], const float b[2]); void mul_v2_m2_add_v2v2(float r[2], const float mat[2][2], const float a[2], const float b[2]);

View File

@ -295,6 +295,7 @@ void PackIsland::place_(const float scale, const uv_phi phi)
UVPackIsland_Params::UVPackIsland_Params() UVPackIsland_Params::UVPackIsland_Params()
{ {
rotate = false; rotate = false;
scale_to_fit = true;
only_selected_uvs = false; only_selected_uvs = false;
only_selected_faces = false; only_selected_faces = false;
use_seams = false; use_seams = false;
@ -597,6 +598,7 @@ class Occupancy {
Occupancy(const float initial_scale); Occupancy(const float initial_scale);
void increase_scale(); /* Resize the scale of the bitmap and clear it. */ void increase_scale(); /* Resize the scale of the bitmap and clear it. */
void clear(); /* Clear occupancy information. */
/* Write or Query a triangle on the bitmap. */ /* Write or Query a triangle on the bitmap. */
float trace_triangle(const float2 &uv0, float trace_triangle(const float2 &uv0,
@ -637,6 +639,11 @@ void Occupancy::increase_scale()
BLI_assert(bitmap_scale_reciprocal > 0.0f); /* TODO: Packing has failed, report error. */ BLI_assert(bitmap_scale_reciprocal > 0.0f); /* TODO: Packing has failed, report error. */
bitmap_scale_reciprocal *= 0.5f; bitmap_scale_reciprocal *= 0.5f;
clear();
}
void Occupancy::clear()
{
for (int i = 0; i < bitmap_radix * bitmap_radix; i++) { for (int i = 0; i < bitmap_radix * bitmap_radix; i++) {
bitmap_[i] = terminal; bitmap_[i] = terminal;
} }
@ -728,33 +735,33 @@ float Occupancy::trace_triangle(const float2 &uv0,
return -1.0f; /* Available. */ return -1.0f; /* Available. */
} }
float2 PackIsland::get_diagonal_support_d4(const float scale, float2 PackIsland::get_diagonal_support(const float scale,
const float rotation, const float rotation,
const float margin) const /* const bool reflection, */
const float margin) const
{ {
if (rotation == 0.0f) { /* Caution: Only "Dihedral Group D4" transforms are calculated exactly.
return half_diagonal_ * scale + margin; /* Fast path for common case. */ * if the transform is Non-D4, an upper bound will be returned instead. */
if (rotation == DEG2RADF(-180.0f) || rotation == 0.0f || rotation == DEG2RADF(180.0f)) {
return half_diagonal_ * scale + margin;
} }
if (rotation == DEG2RADF(180.0f)) { if (rotation == DEG2RADF(-90.0f) || rotation == DEG2RADF(90.0f) ||
return get_diagonal_support_d4(scale, 0.0f, margin); /* Same as 0.0f */ rotation == DEG2RADF(270.0f)) {
return float2(half_diagonal_.y / aspect_y, half_diagonal_.x * aspect_y) * scale + margin;
} }
/* TODO: BLI_assert rotation is a "Dihedral Group D4" transform. */
float matrix[2][2]; float matrix[2][2];
build_transformation(scale, rotation, matrix); build_transformation(scale, rotation, matrix);
/* TODO: Use convex hull to calculate support. */
float diagonal_rotated[2]; float diagonal_rotated[2];
mul_v2_m2v2(diagonal_rotated, matrix, half_diagonal_); mul_v2_m2v2(diagonal_rotated, matrix, half_diagonal_);
return float2(fabsf(diagonal_rotated[0]) + margin, fabsf(diagonal_rotated[1]) + margin); float sx = fabsf(diagonal_rotated[0]);
} float sy = fabsf(diagonal_rotated[1]);
float2 PackIsland::get_diagonal_support(const float scale, return float2(sx + sy * 0.5f + margin, sx * 0.5f + sy + margin); /* Upper bound. */
const float rotation,
const float margin) const
{
/* Only "D4" transforms are currently supported. */
return get_diagonal_support_d4(scale, rotation, margin);
} }
float Occupancy::trace_island(const PackIsland *island, float Occupancy::trace_island(const PackIsland *island,
@ -815,7 +822,7 @@ static uv_phi find_best_fit_for_island(const PackIsland *island,
island->build_transformation(scale, phi.rotation, matrix); island->build_transformation(scale, phi.rotation, matrix);
/* Caution, margin is zero for support_diagonal as we're tracking the top-right corner. */ /* Caution, margin is zero for support_diagonal as we're tracking the top-right corner. */
float2 support_diagonal = island->get_diagonal_support_d4(scale, phi.rotation, 0.0f); float2 support_diagonal = island->get_diagonal_support(scale, phi.rotation, 0.0f);
/* Scan using an "Alpaca"-style search, first horizontally using "less-than". */ /* Scan using an "Alpaca"-style search, first horizontally using "less-than". */
int t = int(ceilf((2 * support_diagonal.x + margin) * occupancy.bitmap_scale_reciprocal)); int t = int(ceilf((2 * support_diagonal.x + margin) * occupancy.bitmap_scale_reciprocal));
@ -855,6 +862,161 @@ static float guess_initial_scale(const Span<PackIsland *> islands,
return sqrtf(sum) / 6.0f; return sqrtf(sum) / 6.0f;
} }
/** Helper to find the minimum enclosing square. */
class UVMinimumEnclosingSquareFinder {
public:
const float scale_;
const float margin_;
const UVPackIsland_Params *params_;
float best_quad;
float best_angle;
rctf best_bounds;
blender::Vector<float2> points;
blender::Vector<int> indices;
UVMinimumEnclosingSquareFinder(const float scale,
const float margin,
const UVPackIsland_Params *params)
: scale_(scale), margin_(margin), params_(params)
{
best_angle = 0.0f;
best_quad = 0.0f;
}
/** Calculates the square associated with a rotation of `angle`.
* \return Size of square. */
float update(const float angle)
{
float2 dir(cosf(angle), sinf(angle));
/* TODO: Once convexhull_2d bugs are fixed, we can use "rotating calipers" to go faster. */
rctf bounds;
BLI_rctf_init_minmax(&bounds);
for (const int64_t i : indices.index_range()) {
const float2 &p = points[indices[i]];
const float uv[2] = {p.x * dir.x + p.y * dir.y, -p.x * dir.y + p.y * dir.x};
BLI_rctf_do_minmax_v(&bounds, uv);
}
bounds.xmin -= margin_;
bounds.ymin -= margin_;
bounds.xmax += margin_;
bounds.ymax += margin_;
const float current_quad = std::max(BLI_rctf_size_x(&bounds) / params_->target_aspect_y,
BLI_rctf_size_y(&bounds));
if (best_quad > current_quad) {
best_quad = current_quad;
best_angle = angle;
best_bounds = bounds;
}
return current_quad;
}
/** Search between `angle0` and `angle1`, looking for the smallest square. */
void update_recursive(const float angle0,
const float quad0,
const float angle1,
const float quad1)
{
const float angle_mid = (angle0 + angle1) * 0.5f;
const float quad_mid = update(angle_mid);
const float angle_separation = angle1 - angle0;
if (angle_separation < DEG2RADF(0.002f)) {
return; /* Sufficient accuracy achieved. */
}
bool search_mode = DEG2RADF(10.0f) < angle_separation; /* In linear search mode. */
/* TODO: Degenerate inputs could have poor performance here. */
if (search_mode || (quad0 <= quad1)) {
update_recursive(angle0, quad0, angle_mid, quad_mid);
}
if (search_mode || (quad1 <= quad0)) {
update_recursive(angle_mid, quad_mid, angle1, quad1);
}
}
};
/**
* Find the minimum bounding square that encloses the UVs as specified in `r_phis`.
* If that square is smaller than `r_max_u` and `r_max_v`, then update `r_phis` accordingly.
* \return True iff `r_phis`, `r_max_u` and `r_max_v` are modified.
*/
static bool rotate_inside_square(const Span<UVAABBIsland *> island_indices,
const Span<PackIsland *> islands,
const UVPackIsland_Params &params,
const float scale,
const float margin,
MutableSpan<uv_phi> r_phis,
float *r_max_u,
float *r_max_v)
{
if (!params.rotate) {
return false; /* Unable to rotate. */
}
if (params.shape_method == ED_UVPACK_SHAPE_AABB) {
return false; /* AABB margin calculations are not preserved under rotations. */
}
BLI_assert(islands.size() > 0);
UVMinimumEnclosingSquareFinder square_finder(scale, margin, &params);
square_finder.best_quad = std::max(*r_max_u / params.target_aspect_y, *r_max_v);
float matrix[2][2];
const float aspect_y = 1.0f; /* TODO: Use `islands[0]->aspect_y`. */
for (const int64_t j : island_indices.index_range()) {
const int64_t i = island_indices[j]->index;
const PackIsland *island = islands[i];
if (island->aspect_y != aspect_y) {
return false; /* Aspect ratios are not preserved under rotation. */
}
island->build_transformation(scale, r_phis[i].rotation, matrix);
float2 pivot_transformed;
mul_v2_m2v2(pivot_transformed, matrix, island->pivot_);
float2 delta = r_phis[i].translation - pivot_transformed;
for (const int64_t k : island->triangle_vertices_.index_range()) {
float2 p = island->triangle_vertices_[k];
mul_m2_v2(matrix, p);
square_finder.points.append(p + delta);
}
}
const float(*source)[2] = reinterpret_cast<const float(*)[2]>(square_finder.points.data());
square_finder.indices.resize(square_finder.points.size());
int convex_size = BLI_convexhull_2d(
source, static_cast<int>(square_finder.points.size()), square_finder.indices.data());
square_finder.indices.resize(convex_size);
const float quad_180 = square_finder.update(DEG2RADF(-180.0f));
square_finder.update_recursive(DEG2RADF(-180.0f), quad_180, DEG2RADF(180.0f), quad_180);
if (square_finder.best_angle == 0.0f) {
return false; /* Nothing to do. */
}
/* Can use islands[0] because all islands have the same aspect_ratio. */
islands[0]->build_transformation(scale, square_finder.best_angle, matrix);
/* Transform phis. */
for (const int64_t j : island_indices.index_range()) {
const int64_t i = island_indices[j]->index;
r_phis[i].rotation += square_finder.best_angle;
mul_m2_v2(matrix, r_phis[i].translation);
r_phis[i].translation.x -= square_finder.best_bounds.xmin;
r_phis[i].translation.y -= square_finder.best_bounds.ymin;
}
*r_max_u = BLI_rctf_size_x(&square_finder.best_bounds);
*r_max_v = BLI_rctf_size_y(&square_finder.best_bounds);
return true; /* `r_phis` were modified. */
}
/** /**
* Pack irregular islands using the `xatlas` strategy, and optional D4 transforms. * Pack irregular islands using the `xatlas` strategy, and optional D4 transforms.
* *
@ -883,7 +1045,12 @@ static void pack_island_xatlas(const Span<UVAABBIsland *> island_indices,
float max_u = 0.0f; float max_u = 0.0f;
float max_v = 0.0f; float max_v = 0.0f;
int scan_line = 0; /* A heuristic to improve final layout efficiency by making an
* intermediate call to #rotate_inside_square. */
int64_t square_milestone = sqrt(island_indices.size()) / 4 + 2;
int scan_line = 0; /* Current "scan_line" of occupancy bitmap. */
int traced_islands = 0; /* Which islands are currently traced in `occupancy`. */
int i = 0; int i = 0;
/* The following `while` loop is setting up a three-way race: /* The following `while` loop is setting up a three-way race:
@ -893,10 +1060,21 @@ static void pack_island_xatlas(const Span<UVAABBIsland *> island_indices,
*/ */
while (i < island_indices.size()) { while (i < island_indices.size()) {
while (traced_islands < i) {
/* Trace an island that's been solved. (Greedy.) */
const int64_t island_index = island_indices[traced_islands]->index;
occupancy.trace_island(islands[island_index], r_phis[island_index], scale, margin, true);
traced_islands++;
}
PackIsland *island = islands[island_indices[i]->index]; PackIsland *island = islands[island_indices[i]->index];
uv_phi phi; uv_phi phi;
int max_90_multiple = params.rotate && (i < 50) ? 4 : 1; int max_90_multiple = 1;
if (params.rotate && i && (i < 50)) {
max_90_multiple = 4;
}
for (int angle_90_multiple = 0; angle_90_multiple < max_90_multiple; angle_90_multiple++) { for (int angle_90_multiple = 0; angle_90_multiple < max_90_multiple; angle_90_multiple++) {
phi = find_best_fit_for_island( phi = find_best_fit_for_island(
island, scan_line, occupancy, scale, angle_90_multiple, margin, params.target_aspect_y); island, scan_line, occupancy, scale, angle_90_multiple, margin, params.target_aspect_y);
@ -929,19 +1107,29 @@ static void pack_island_xatlas(const Span<UVAABBIsland *> island_indices,
/* Enlarge search parameters. */ /* Enlarge search parameters. */
scan_line = 0; scan_line = 0;
occupancy.increase_scale(); occupancy.increase_scale();
traced_islands = 0; /* Will trigger a re-trace of previously solved islands. */
/* Redraw already placed islands. (Greedy.) */
for (int j = 0; j < i; j++) {
occupancy.trace_island(islands[island_indices[j]->index], r_phis[j], scale, margin, true);
}
continue; continue;
} }
/* Place island. */ /* Place island. */
r_phis[island_indices[i]->index] = phi; r_phis[island_indices[i]->index] = phi;
occupancy.trace_island(island, phi, scale, margin, true);
i++; /* Next island. */ i++; /* Next island. */
if (i == square_milestone) {
if (rotate_inside_square(island_indices.take_front(i),
islands,
params,
scale,
margin,
r_phis,
&max_u,
&max_v)) {
scan_line = 0;
traced_islands = 0;
occupancy.clear();
}
}
/* Update top-right corner. */ /* Update top-right corner. */
float2 top_right = island->get_diagonal_support(scale, phi.rotation, margin) + phi.translation; float2 top_right = island->get_diagonal_support(scale, phi.rotation, margin) + phi.translation;
max_u = std::max(top_right.x, max_u); max_u = std::max(top_right.x, max_u);
@ -1083,6 +1271,8 @@ static float pack_islands_scale_margin(const Span<PackIsland *> islands,
pack_islands_alpaca_turbo(max_box_pack, aabbs, params.target_aspect_y, r_phis, &max_u, &max_v); pack_islands_alpaca_turbo(max_box_pack, aabbs, params.target_aspect_y, r_phis, &max_u, &max_v);
} }
rotate_inside_square(aabbs, islands, params, scale, margin, r_phis, &max_u, &max_v);
return std::max(max_u / params.target_aspect_y, max_v); return std::max(max_u / params.target_aspect_y, max_v);
} }
@ -1283,9 +1473,8 @@ class OverlapMerger {
return result; return result;
} }
static void pack_islands_overlap(const Span<PackIsland *> &islands, static float pack_islands_overlap(const Span<PackIsland *> &islands,
const UVPackIsland_Params &params, const UVPackIsland_Params &params)
float r_scale[2])
{ {
/* Building the binary-tree of merges is complicated to do in a single pass if we proceed in /* Building the binary-tree of merges is complicated to do in a single pass if we proceed in
@ -1316,7 +1505,7 @@ class OverlapMerger {
/* Recursively call pack_islands with `merge_overlap = false`. */ /* Recursively call pack_islands with `merge_overlap = false`. */
UVPackIsland_Params sub_params(params); UVPackIsland_Params sub_params(params);
sub_params.merge_overlap = false; sub_params.merge_overlap = false;
pack_islands(sub_islands, sub_params, r_scale); const float result = pack_islands(sub_islands, sub_params);
/* Must loop backwards! */ /* Must loop backwards! */
for (int64_t i = merge_trace.size() - 3; i >= 0; i -= 3) { for (int64_t i = merge_trace.size() - 3; i >= 0; i -= 3) {
@ -1331,6 +1520,8 @@ class OverlapMerger {
sub_b->pre_rotate_ = merge->pre_rotate_; sub_b->pre_rotate_ = merge->pre_rotate_;
delete merge; delete merge;
} }
return result;
} }
}; };
@ -1347,31 +1538,25 @@ static void finalize_geometry(const Span<PackIsland *> &islands, const UVPackIsl
BLI_memarena_free(arena); BLI_memarena_free(arena);
} }
void pack_islands(const Span<PackIsland *> &islands, float pack_islands(const Span<PackIsland *> &islands, const UVPackIsland_Params &params)
const UVPackIsland_Params &params,
float r_scale[2])
{ {
BLI_assert(0.0f <= params.margin); BLI_assert(0.0f <= params.margin);
BLI_assert(0.0f <= params.target_aspect_y); BLI_assert(0.0f <= params.target_aspect_y);
if (islands.size() == 0) { if (islands.size() == 0) {
r_scale[0] = 1.0f; return 1.0f; /* Nothing to do, just create a safe default. */
r_scale[1] = 1.0f;
return; /* Nothing to do, just create a safe default. */
} }
if (params.merge_overlap) { if (params.merge_overlap) {
return OverlapMerger::pack_islands_overlap(islands, params, r_scale); return OverlapMerger::pack_islands_overlap(islands, params);
} }
finalize_geometry(islands, params); finalize_geometry(islands, params);
if (params.margin_method == ED_UVPACK_MARGIN_FRACTION && params.margin > 0.0f) { if (params.margin_method == ED_UVPACK_MARGIN_FRACTION && params.margin > 0.0f &&
params.scale_to_fit) {
/* Uses a line search on scale. ~10x slower than other method. */ /* Uses a line search on scale. ~10x slower than other method. */
const float scale = pack_islands_margin_fraction(islands, params.margin, params); return pack_islands_margin_fraction(islands, params.margin, params);
r_scale[0] = scale;
r_scale[1] = scale;
return;
} }
float margin = params.margin; float margin = params.margin;
@ -1395,8 +1580,7 @@ void pack_islands(const Span<PackIsland *> &islands,
for (const int64_t i : islands.index_range()) { for (const int64_t i : islands.index_range()) {
islands[i]->place_(scale, phis[i]); islands[i]->place_(scale, phis[i]);
} }
r_scale[0] = 1.0f / max_uv; return params.scale_to_fit ? 1.0f / max_uv : 1.0f;
r_scale[1] = r_scale[0];
} }
/** \} */ /** \} */

View File

@ -4131,15 +4131,14 @@ void uv_parametrizer_pack(ParamHandle *handle, float margin, bool do_rotate, boo
pack_island_vector.append(pack_island); pack_island_vector.append(pack_island);
} }
float scale[2] = {1.0f, 1.0f}; const float scale = pack_islands(pack_island_vector, params);
pack_islands(pack_island_vector, params, scale);
for (const int64_t i : pack_island_vector.index_range()) { for (const int64_t i : pack_island_vector.index_range()) {
PackIsland *pack_island = pack_island_vector[i]; PackIsland *pack_island = pack_island_vector[i];
PChart *chart = handle->charts[pack_island->caller_index]; PChart *chart = handle->charts[pack_island->caller_index];
float matrix[2][2]; float matrix[2][2];
pack_island->build_transformation(scale[0], pack_island->angle, matrix); pack_island->build_transformation(scale, pack_island->angle, matrix);
for (PVert *v = chart->verts; v; v = v->nextlink) { for (PVert *v = chart->verts; v; v = v->nextlink) {
blender::geometry::mul_v2_m2_add_v2v2(v->uv, matrix, v->uv, pack_island->pre_translate); blender::geometry::mul_v2_m2_add_v2v2(v->uv, matrix, v->uv, pack_island->pre_translate);
} }

View File

@ -27,7 +27,7 @@ void ensure_usd_plugin_path_registered()
if (blender_usd_datafiles) { if (blender_usd_datafiles) {
const std::string blender_usd_data_folder = blender_usd_datafiles; const std::string blender_usd_data_folder = blender_usd_datafiles;
/* The trailing slash indicates to the USD library that the path is a directory. */ /* The trailing slash indicates to the USD library that the path is a directory. */
pxr::PlugRegistry::GetInstance().RegisterPlugins(blender_usd_data_folder + "/"); pxr::PlugRegistry::GetInstance().RegisterPlugins(blender_usd_data_folder + SEP_STR);
} }
#endif #endif
} }

View File

@ -18,7 +18,7 @@ class obj_mtl_parser_test : public testing::Test {
BKE_tempdir_init(nullptr); BKE_tempdir_init(nullptr);
std::string tmp_dir = BKE_tempdir_base(); std::string tmp_dir = BKE_tempdir_base();
std::string tmp_file_name = "mtl_test.mtl"; std::string tmp_file_name = "mtl_test.mtl";
std::string tmp_file_path = tmp_dir + "/" + tmp_file_name; std::string tmp_file_path = tmp_dir + SEP_STR + tmp_file_name;
FILE *tmp_file = BLI_fopen(tmp_file_path.c_str(), "wb"); FILE *tmp_file = BLI_fopen(tmp_file_path.c_str(), "wb");
fputs(text, tmp_file); fputs(text, tmp_file);
fclose(tmp_file); fclose(tmp_file);
@ -29,7 +29,8 @@ class obj_mtl_parser_test : public testing::Test {
} }
void check(const char *file, const MTLMaterial *expect, size_t expect_count) void check(const char *file, const MTLMaterial *expect, size_t expect_count)
{ {
std::string obj_dir = blender::tests::flags_test_asset_dir() + "/io_tests/obj/"; std::string obj_dir = blender::tests::flags_test_asset_dir() +
(SEP_STR "io_tests" SEP_STR "obj" SEP_STR);
check_impl(file, obj_dir, expect, expect_count); check_impl(file, obj_dir, expect, expect_count);
} }
void check_impl(StringRefNull mtl_file_path, void check_impl(StringRefNull mtl_file_path,

View File

@ -15,25 +15,26 @@ NODE_STORAGE_FUNCS(NodeAccumulateField)
static void node_declare(NodeDeclarationBuilder &b) static void node_declare(NodeDeclarationBuilder &b)
{ {
std::string value_in_description = "The values to be accumulated"; std::string value_in_description = N_("The values to be accumulated");
std::string leading_out_description = std::string leading_out_description = N_(
"The running total of values in the corresponding group, starting at the first value"; "The running total of values in the corresponding group, starting at the first value");
std::string trailing_out_description = std::string trailing_out_description = N_(
"The running total of values in the corresponding group, starting at zero"; "The running total of values in the corresponding group, starting at zero");
std::string total_out_description = "The total of all of the values in the corresponding group"; std::string total_out_description = N_(
"The total of all of the values in the corresponding group");
b.add_input<decl::Vector>(N_("Value"), "Value Vector") b.add_input<decl::Vector>(N_("Value"), "Value Vector")
.default_value({1.0f, 1.0f, 1.0f}) .default_value({1.0f, 1.0f, 1.0f})
.supports_field() .supports_field()
.description(N_(value_in_description)); .description(value_in_description);
b.add_input<decl::Float>(N_("Value"), "Value Float") b.add_input<decl::Float>(N_("Value"), "Value Float")
.default_value(1.0f) .default_value(1.0f)
.supports_field() .supports_field()
.description(N_(value_in_description)); .description(value_in_description);
b.add_input<decl::Int>(N_("Value"), "Value Int") b.add_input<decl::Int>(N_("Value"), "Value Int")
.default_value(1) .default_value(1)
.supports_field() .supports_field()
.description(N_(value_in_description)); .description(value_in_description);
b.add_input<decl::Int>(N_("Group ID"), "Group Index") b.add_input<decl::Int>(N_("Group ID"), "Group Index")
.supports_field() .supports_field()
.description( .description(
@ -41,33 +42,33 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Vector>(N_("Leading"), "Leading Vector") b.add_output<decl::Vector>(N_("Leading"), "Leading Vector")
.field_source_reference_all() .field_source_reference_all()
.description(N_(leading_out_description)); .description(leading_out_description);
b.add_output<decl::Float>(N_("Leading"), "Leading Float") b.add_output<decl::Float>(N_("Leading"), "Leading Float")
.field_source_reference_all() .field_source_reference_all()
.description(N_(leading_out_description)); .description(leading_out_description);
b.add_output<decl::Int>(N_("Leading"), "Leading Int") b.add_output<decl::Int>(N_("Leading"), "Leading Int")
.field_source_reference_all() .field_source_reference_all()
.description(N_(leading_out_description)); .description(leading_out_description);
b.add_output<decl::Vector>(N_("Trailing"), "Trailing Vector") b.add_output<decl::Vector>(N_("Trailing"), "Trailing Vector")
.field_source_reference_all() .field_source_reference_all()
.description(N_(trailing_out_description)); .description(trailing_out_description);
b.add_output<decl::Float>(N_("Trailing"), "Trailing Float") b.add_output<decl::Float>(N_("Trailing"), "Trailing Float")
.field_source_reference_all() .field_source_reference_all()
.description(N_(trailing_out_description)); .description(trailing_out_description);
b.add_output<decl::Int>(N_("Trailing"), "Trailing Int") b.add_output<decl::Int>(N_("Trailing"), "Trailing Int")
.field_source_reference_all() .field_source_reference_all()
.description(N_(trailing_out_description)); .description(trailing_out_description);
b.add_output<decl::Vector>(N_("Total"), "Total Vector") b.add_output<decl::Vector>(N_("Total"), "Total Vector")
.field_source_reference_all() .field_source_reference_all()
.description(N_(total_out_description)); .description(total_out_description);
b.add_output<decl::Float>(N_("Total"), "Total Float") b.add_output<decl::Float>(N_("Total"), "Total Float")
.field_source_reference_all() .field_source_reference_all()
.description(N_(total_out_description)); .description(total_out_description);
b.add_output<decl::Int>(N_("Total"), "Total Int") b.add_output<decl::Int>(N_("Total"), "Total Int")
.field_source_reference_all() .field_source_reference_all()
.description(N_(total_out_description)); .description(total_out_description);
} }
static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr) static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)

View File

@ -3,6 +3,8 @@
#include "UI_interface.h" #include "UI_interface.h"
#include "UI_resources.h" #include "UI_resources.h"
#include "BLT_translation.h"
#include "node_geometry_util.hh" #include "node_geometry_util.hh"
namespace blender::nodes::node_geo_attribute_domain_size_cc { namespace blender::nodes::node_geo_attribute_domain_size_cc {
@ -10,22 +12,22 @@ namespace blender::nodes::node_geo_attribute_domain_size_cc {
static void node_declare(NodeDeclarationBuilder &b) static void node_declare(NodeDeclarationBuilder &b)
{ {
b.add_input<decl::Geometry>("Geometry"); b.add_input<decl::Geometry>("Geometry");
b.add_output<decl::Int>("Point Count").make_available([](bNode &node) { b.add_output<decl::Int>(N_("Point Count")).make_available([](bNode &node) {
node.custom1 = GEO_COMPONENT_TYPE_MESH; node.custom1 = GEO_COMPONENT_TYPE_MESH;
}); });
b.add_output<decl::Int>("Edge Count").make_available([](bNode &node) { b.add_output<decl::Int>(N_("Edge Count")).make_available([](bNode &node) {
node.custom1 = GEO_COMPONENT_TYPE_MESH; node.custom1 = GEO_COMPONENT_TYPE_MESH;
}); });
b.add_output<decl::Int>("Face Count").make_available([](bNode &node) { b.add_output<decl::Int>(N_("Face Count")).make_available([](bNode &node) {
node.custom1 = GEO_COMPONENT_TYPE_MESH; node.custom1 = GEO_COMPONENT_TYPE_MESH;
}); });
b.add_output<decl::Int>("Face Corner Count").make_available([](bNode &node) { b.add_output<decl::Int>(N_("Face Corner Count")).make_available([](bNode &node) {
node.custom1 = GEO_COMPONENT_TYPE_MESH; node.custom1 = GEO_COMPONENT_TYPE_MESH;
}); });
b.add_output<decl::Int>("Spline Count").make_available([](bNode &node) { b.add_output<decl::Int>(N_("Spline Count")).make_available([](bNode &node) {
node.custom1 = GEO_COMPONENT_TYPE_CURVE; node.custom1 = GEO_COMPONENT_TYPE_CURVE;
}); });
b.add_output<decl::Int>("Instance Count").make_available([](bNode &node) { b.add_output<decl::Int>(N_("Instance Count")).make_available([](bNode &node) {
node.custom1 = GEO_COMPONENT_TYPE_INSTANCES; node.custom1 = GEO_COMPONENT_TYPE_INSTANCES;
}); });
} }

View File

@ -61,7 +61,7 @@ static void node_geo_exec(GeoNodeExecParams params)
const bool is_recursive = BKE_collection_has_object_recursive_instanced( const bool is_recursive = BKE_collection_has_object_recursive_instanced(
collection, const_cast<Object *>(self_object)); collection, const_cast<Object *>(self_object));
if (is_recursive) { if (is_recursive) {
params.error_message_add(NodeWarningType::Error, "Collection contains current object"); params.error_message_add(NodeWarningType::Error, TIP_("Collection contains current object"));
params.set_default_remaining_outputs(); params.set_default_remaining_outputs();
return; return;
} }

View File

@ -59,12 +59,15 @@ static void node_geo_exec(GeoNodeExecParams params)
} }
if (!attribute_exists) { if (!attribute_exists) {
params.error_message_add(NodeWarningType::Info, char *message = BLI_sprintfN(TIP_("Attribute does not exist: \"%s\""), name.c_str());
TIP_("Attribute does not exist: \"") + name + "\""); params.error_message_add(NodeWarningType::Warning, message);
MEM_freeN(message);
} }
if (cannot_delete) { if (cannot_delete) {
params.error_message_add(NodeWarningType::Warning, char *message = BLI_sprintfN(TIP_("Cannot delete built-in attribute with name \"%s\""),
TIP_("Cannot delete built-in attribute with name \"") + name + "\""); name.c_str());
params.error_message_add(NodeWarningType::Warning, message);
MEM_freeN(message);
} }
params.set_output("Geometry", std::move(geometry_set)); params.set_output("Geometry", std::move(geometry_set));

View File

@ -168,7 +168,7 @@ static bool seq_proxy_get_fname(Scene *scene,
BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir)); BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir));
} }
else { /* Per strip default. */ else { /* Per strip default. */
BLI_snprintf(dir, PROXY_MAXFILE, "%s/BL_proxy", seq->strip->dir); BLI_snprintf(dir, PROXY_MAXFILE, "%s" SEP_STR "BL_proxy", seq->strip->dir);
} }
} }

View File

@ -380,6 +380,7 @@ void GIZMOGROUP_OT_gizmo_select(wmOperatorType *ot)
/* api callbacks */ /* api callbacks */
ot->invoke = gizmo_select_invoke; ot->invoke = gizmo_select_invoke;
ot->poll = ED_operator_region_gizmo_active;
ot->flag = OPTYPE_UNDO; ot->flag = OPTYPE_UNDO;
@ -606,6 +607,7 @@ void GIZMOGROUP_OT_gizmo_tweak(wmOperatorType *ot)
/* api callbacks */ /* api callbacks */
ot->invoke = gizmo_tweak_invoke; ot->invoke = gizmo_tweak_invoke;
ot->modal = gizmo_tweak_modal; ot->modal = gizmo_tweak_modal;
ot->poll = ED_operator_region_gizmo_active;
/* TODO(@ideasman42): This causes problems tweaking settings for operators, /* TODO(@ideasman42): This causes problems tweaking settings for operators,
* need to find a way to support this. */ * need to find a way to support this. */

View File

@ -2079,11 +2079,18 @@ void WM_clipboard_text_set(const char *buf, bool selection)
bool WM_clipboard_image_available(void) bool WM_clipboard_image_available(void)
{ {
if (G.background) {
return false;
}
return (bool)GHOST_hasClipboardImage(); return (bool)GHOST_hasClipboardImage();
} }
ImBuf *WM_clipboard_image_get(void) ImBuf *WM_clipboard_image_get(void)
{ {
if (G.background) {
return NULL;
}
int width, height; int width, height;
uint *rgba = GHOST_getClipboardImage(&width, &height); uint *rgba = GHOST_getClipboardImage(&width, &height);
@ -2099,6 +2106,10 @@ ImBuf *WM_clipboard_image_get(void)
bool WM_clipboard_image_set(ImBuf *ibuf) bool WM_clipboard_image_set(ImBuf *ibuf)
{ {
if (G.background) {
return false;
}
bool free_byte_buffer = false; bool free_byte_buffer = false;
if (ibuf->rect == NULL) { if (ibuf->rect == NULL) {
/* Add a byte buffer if it does not have one. */ /* Add a byte buffer if it does not have one. */

View File

@ -42,6 +42,9 @@ op_blacklist = (
"*.*_import", "*.*_import",
"ed.undo", "ed.undo",
"ed.undo_push", "ed.undo_push",
"image.external_edit", # just annoying - but harmless (opens an app).
"image.project_edit", # just annoying - but harmless (opens an app).
"object.quadriflow_remesh", # OK but slow.
"preferences.studiolight_new", "preferences.studiolight_new",
"script.autoexec_warn_clear", "script.autoexec_warn_clear",
"screen.delete", # already used for random screens "screen.delete", # already used for random screens
@ -75,6 +78,12 @@ op_blacklist = (
"console.*", # just annoying - but harmless "console.*", # just annoying - but harmless
"wm.url_open_preset", # Annoying but harmless (opens web pages). "wm.url_open_preset", # Annoying but harmless (opens web pages).
"render.cycles_integrator_preset_add",
"render.cycles_performance_preset_add",
"render.cycles_sampling_preset_add",
"render.cycles_viewport_sampling_preset_add",
"render.preset_add",
# FIXME: # FIXME:
# Crashes with non-trivial fixes. # Crashes with non-trivial fixes.
# #
@ -245,29 +254,40 @@ if USE_ATTRSET:
def run_ops(operators, setup_func=None, reset=True): def run_ops(operators, setup_func=None, reset=True):
from bpy import context
print("\ncontext:", setup_func.__name__) print("\ncontext:", setup_func.__name__)
def temp_override_default_kwargs():
return {
"window": context.window_manager.windows[0],
}
# first invoke # first invoke
for op_id, op in operators: for op_id, op in operators:
if op.poll(): with context.temp_override(window=context.window_manager.windows[0]):
print(" operator: %4d, %s" % (STATE["counter"], op_id)) if not op.poll():
STATE["counter"] += 1 continue
sys.stdout.flush() # in case of crash
# disable will get blender in a bad state and crash easy! print(" operator: %4d, %s" % (STATE["counter"], op_id))
if reset: STATE["counter"] += 1
reset_test = True sys.stdout.flush() # in case of crash
if USE_RANDOM:
import random
if random.random() < (1.0 - RANDOM_RESET):
reset_test = False
if reset_test: # disable will get blender in a bad state and crash easy!
if USE_FILES: if reset:
reset_file() reset_test = True
else: if USE_RANDOM:
reset_blend() import random
del reset_test if random.random() < (1.0 - RANDOM_RESET):
reset_test = False
if reset_test:
if USE_FILES:
reset_file()
else:
reset_blend()
del reset_test
with context.temp_override(**temp_override_default_kwargs()):
if USE_RANDOM: if USE_RANDOM:
# we can't be sure it will work # we can't be sure it will work
@ -293,14 +313,16 @@ def run_ops(operators, setup_func=None, reset=True):
# run test # run test
if reset: if reset:
reset_blend() reset_blend()
if USE_RANDOM:
# we can't be sure it will work with context.temp_override(**temp_override_default_kwargs()):
try: if USE_RANDOM:
# we can't be sure it will work
try:
setup_func()
except:
pass
else:
setup_func() setup_func()
except:
pass
else:
setup_func()
# contexts # contexts