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_CPE "cpe:2.3:a:google:brotli:${BROTLI_VERSION}:*:*:*:*:*:*:*")
set(OPENPGL_VERSION v0.4.1-beta)
set(OPENPGL_SHORT_VERSION 0.4.1)
set(OPENPGL_VERSION v0.5.0)
set(OPENPGL_SHORT_VERSION 0.5.0)
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_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))
/* 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;
}
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(h_num - 1));

View File

@ -64,8 +64,9 @@ class IESTextParser {
public:
vector<char> text;
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(), ',', ' ');
data = strstr(&text[0], "\nTILT=");
@ -76,15 +77,22 @@ class IESTextParser {
return (data == NULL) || (data[0] == '\0');
}
bool has_error()
{
return error;
}
double get_double()
{
if (eof()) {
error = true;
return 0.0;
}
char *old_data = data;
double val = strtod(data, &data);
if (data == old_data) {
data = NULL;
error = true;
return 0.0;
}
return val;
@ -93,12 +101,14 @@ class IESTextParser {
long get_long()
{
if (eof()) {
error = true;
return 0;
}
char *old_data = data;
long val = strtol(data, &data, 10);
if (data == old_data) {
data = NULL;
error = true;
return 0;
}
return val;
@ -191,7 +201,7 @@ bool IESFile::parse(const string &ies)
}
}
return !parser.eof();
return !parser.has_error();
}
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];
if (v_first == 90.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 {
if (v_last != 180.0f) {
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[h_angles.size() - 1] == 360.0f);

View File

@ -40,7 +40,8 @@ def geometry_modifier_poll(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
else:
ob = context.object

View File

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

View File

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

View File

@ -157,7 +157,7 @@ def _get_context_attr(context, 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."""
owner_path, attr_name = data_path.rsplit('.', 1)
owner = context.path_resolve(owner_path)
@ -172,10 +172,10 @@ class GenericUIListOperator:
list_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)
def get_active_index(self, context) -> str:
def get_active_index(self, context):
return _get_context_attr(context, self.active_index_path)
def set_active_index(self, context, index):
@ -226,9 +226,11 @@ class UILIST_OT_entry_move(GenericUIListOperator, Operator):
direction: EnumProperty(
name="Direction",
items=(('UP', 'UP', 'UP'),
('DOWN', 'DOWN', 'DOWN')),
default='UP'
items=(
('UP', 'UP', 'UP'),
('DOWN', 'DOWN', 'DOWN'),
),
default='UP',
)
def execute(self, context):

View File

@ -19,6 +19,8 @@
#include "BLI_math_vector_types.hh"
#include "BLI_span.hh"
#include "BLT_translation.h"
#include "FN_field.hh"
#include "BLT_translation.h"
@ -49,8 +51,8 @@ std::ostream &operator<<(std::ostream &stream, const AttributeIDRef &attribute_i
return stream;
}
const char *no_procedural_access_message =
"This attribute can not be accessed in a procedural context";
const char *no_procedural_access_message = N_(
"This attribute can not be accessed in a procedural context");
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;
}
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;
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) {
BLI_path_sequence_encode(filepath,
sizeof(filepath),
FILE_MAX,
head,
tail,
numlen,
@ -503,8 +505,11 @@ static void get_sequence_filepath(const MovieClip *clip, const int framenr, char
}
/* supposed to work with sequences only */
static void get_proxy_filepath(
const MovieClip *clip, int proxy_render_size, bool undistorted, int framenr, char *filepath)
static void get_proxy_filepath(const MovieClip *clip,
int proxy_render_size,
bool undistorted,
int framenr,
char filepath[FILE_MAX])
{
int size = rendersize_to_number(proxy_render_size);
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));
}
else {
BLI_snprintf(dir, FILE_MAX, "%s/BL_proxy", clipdir);
BLI_snprintf(dir, sizeof(dir), "%s" SEP_STR "BL_proxy", clipdir);
}
if (undistorted) {
BLI_snprintf(
filepath, FILE_MAX, "%s/%s/proxy_%d_undistorted/%08d", dir, clipfile, size, proxynr);
BLI_snprintf(filepath,
FILE_MAX,
"%s" SEP_STR "%s" SEP_STR "proxy_%d_undistorted" SEP_STR "%08d",
dir,
clipfile,
size,
proxynr);
}
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());

View File

@ -1463,6 +1463,10 @@ static bool vfont_to_curve(Object *ob,
sb->x -= sinf(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->y *= 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
* 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 {
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 {
public:

View File

@ -66,7 +66,7 @@ class ImplicitSharingInfo : NonCopyable, NonMovable {
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
{
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)
/* 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)) {
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_FILE

View File

@ -2016,7 +2016,9 @@ static int gpencil_blank_frame_add_exec(bContext *C, wmOperator *op)
CTX_DATA_END;
/* 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);
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.
*/
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_region_view3d_active(struct bContext *C);
bool ED_operator_region_gizmo_active(struct bContext *C);
/**
* 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->invoke = drop_color_invoke;
ot->poll = ED_operator_regionactive;
ot->flag = OPTYPE_INTERNAL;
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)
{
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) {
Panel *panel = block->panel;
if (panel == nullptr) {
continue;
}
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);
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")));
}
if (update_location_if_necessary) {
if (update_location_if_necessary && CTX_wm_region_view3d(C)) {
int mval[2];
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);
@ -1928,11 +1928,13 @@ static int object_data_instance_add_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
int mval[2];
if (!RNA_property_is_set(op->ptr, prop_location) && object_add_drop_xy_get(C, op, &mval)) {
ED_object_location_from_view(C, loc);
ED_view3d_cursor3d_position(C, mval, false, loc);
RNA_property_float_set_array(op->ptr, prop_location, loc);
if (CTX_wm_region_view3d(C)) {
int mval[2];
if (!RNA_property_is_set(op->ptr, prop_location) && object_add_drop_xy_get(C, op, &mval)) {
ED_object_location_from_view(C, 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(
@ -3927,7 +3929,7 @@ static int object_add_named_exec(bContext *C, wmOperator *op)
DEG_id_tag_update(&ob_add->id, ID_RECALC_TRANSFORM);
}
else {
else if (CTX_wm_region_view3d(C)) {
int mval[2];
if (object_add_drop_xy_get(C, op, &mval)) {
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);
}
else {
else if (CTX_wm_region_view3d(C)) {
int mval[2];
if (object_add_drop_xy_get(C, op, &mval)) {
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(
op, ob, eGpencilModifierType_Time);
if (gpmd == NULL) {
return OPERATOR_CANCELLED;
}
if (gpmd->segment_active_index < 0 || gpmd->segment_active_index >= gpmd->segments_len) {
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(
op, ob, eGpencilModifierType_Time);
if (gpmd == NULL) {
return OPERATOR_CANCELLED;
}
if (gpmd->segments_len < 2) {
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);
ModifierData *md = edit_modifier_property_get(op, ob, 0);
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) {
return OPERATOR_CANCELLED;

View File

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

View File

@ -213,6 +213,17 @@ bool ED_operator_objectmode_poll_msg(bContext *C)
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)
{
if (ED_operator_areaactive(C)) {
@ -237,6 +248,19 @@ bool ED_operator_region_view3d_active(bContext *C)
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)
{
if (ED_operator_areaactive(C)) {
@ -4354,23 +4378,25 @@ static int screen_context_menu_invoke(bContext *C,
ed_screens_statusbar_menu_create(layout, NULL);
UI_popup_menu_end(C, pup);
}
else if (ELEM(region->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) {
uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Header"), ICON_NONE);
uiLayout *layout = UI_popup_menu_layout(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);
uiLayout *layout = UI_popup_menu_layout(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);
uiLayout *layout = UI_popup_menu_layout(pup);
ED_screens_navigation_bar_tools_menu_create(C, layout, NULL);
UI_popup_menu_end(C, pup);
else if (region) {
if (ELEM(region->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) {
uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Header"), ICON_NONE);
uiLayout *layout = UI_popup_menu_layout(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);
uiLayout *layout = UI_popup_menu_layout(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);
uiLayout *layout = UI_popup_menu_layout(pup);
ED_screens_navigation_bar_tools_menu_create(C, layout, NULL);
UI_popup_menu_end(C, pup);
}
}
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)
{
const Paint *paint = BKE_paint_get_active_from_context(C);
const Brush *brush = BKE_paint_brush_for_read(paint);
Scene *scene = CTX_data_scene(C);
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) {
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 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);
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. */
const bool use_original = sculpt_tool_needs_original(brush->sculpt_tool) ? true :
ss->cache->original;
!ss->cache->accum;
const float radius_scale = 1.25f;
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 :
ss->cache->original;
!ss->cache->accum;
const bool use_pixels = 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);
}
cache->accum = true;
/* Make copies of the mesh vertex locations and normals for some tools. */
if (brush->flag & BRUSH_ANCHORED) {
cache->original = true;
}
if (SCULPT_automasking_needs_original(sd, brush)) {
cache->original = true;
cache->accum = false;
}
/* Draw sharp does not need the original coordinates to produce the accumulate effect, so it
* should work the opposite way. */
if (brush->sculpt_tool == SCULPT_TOOL_DRAW_SHARP) {
cache->original = true;
cache->accum = false;
}
if (SCULPT_TOOL_HAS_ACCUMULATE(brush->sculpt_tool)) {
if (!(brush->flag & BRUSH_ACCUMULATE)) {
cache->original = true;
cache->accum = false;
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. */
if (brush && brush->sculpt_tool == SCULPT_TOOL_PAINT &&
SCULPT_use_image_paint_brush(&tool_settings->paint_mode, ob)) {
cache->original = false;
cache->accum = true;
}
cache->first_time = true;
@ -5068,7 +5066,7 @@ float SCULPT_raycast_init(ViewContext *vc,
float obimat[4][4];
float dist;
Object *ob = vc->obact;
RegionView3D *rv3d = static_cast<RegionView3D *>(vc->region->regiondata);
RegionView3D *rv3d = vc->rv3d;
View3D *v3d = vc->v3d;
/* 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;
ss = ob->sculpt;
if (!ss->pbvh) {
if (!ss->pbvh || !vc.rv3d) {
zero_v3(out->location);
zero_v3(out->normal);
zero_v3(out->active_vertex_co);
@ -5253,7 +5251,7 @@ bool SCULPT_stroke_get_location_ex(bContext *C,
ss = ob->sculpt;
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));

View File

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

View File

@ -613,7 +613,10 @@ struct StrokeCache {
int radial_symmetry_pass;
float symm_rot_mat[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];
/* 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);
Object *ob = CTX_data_active_object(C);
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. */

View File

@ -177,7 +177,8 @@ enum {
};
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;
int index;
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__);
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());
}
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));
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->name = id_iter->name + 2;
entry->free_name = false;

View File

@ -847,7 +847,7 @@ static void create_inspection_string_for_generic_value(const bNodeSocket &socket
return;
}
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;
}
@ -864,22 +864,22 @@ static void create_inspection_string_for_generic_value(const bNodeSocket &socket
BLI_SCOPED_DEFER([&]() { socket_type.destruct(socket_value); });
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>()) {
ss << *static_cast<float *>(socket_value) << TIP_(" (Float)");
ss << *static_cast<float *>(socket_value) << " " << TIP_("(Float)");
}
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>()) {
const blender::ColorGeometry4f &color = *static_cast<blender::ColorGeometry4f *>(socket_value);
ss << "(" << color.r << ", " << color.g << ", " << color.b << ", " << color.a << ")"
<< TIP_(" (Color)");
ss << "(" << color.r << ", " << color.g << ", " << color.b << ", " << color.a << ") "
<< TIP_("(Color)");
}
else if (socket_type.is<bool>()) {
ss << ((*static_cast<bool *>(socket_value)) ? TIP_("True") : TIP_("False"))
<< TIP_(" (Boolean)");
ss << ((*static_cast<bool *>(socket_value)) ? TIP_("True") : TIP_("False")) << " "
<< TIP_("(Boolean)");
}
}
@ -893,32 +893,32 @@ static void create_inspection_string_for_field_info(const bNodeSocket &socket,
if (input_tooltips.is_empty()) {
/* Should have been logged as constant value. */
BLI_assert_unreachable();
ss << "Value has not been logged";
ss << TIP_("Value has not been logged");
}
else {
if (socket_type.is<int>()) {
ss << TIP_("Integer field");
ss << TIP_("Integer field based on:");
}
else if (socket_type.is<float>()) {
ss << TIP_("Float field");
ss << TIP_("Float field based on:");
}
else if (socket_type.is<blender::float3>()) {
ss << TIP_("Vector field");
ss << TIP_("Vector field based on:");
}
else if (socket_type.is<bool>()) {
ss << TIP_("Boolean field");
ss << TIP_("Boolean field based on:");
}
else if (socket_type.is<std::string>()) {
ss << TIP_("String field");
ss << TIP_("String field based on:");
}
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()) {
const blender::StringRef tooltip = input_tooltips[i];
ss << "\u2022 " << tooltip;
ss << "\u2022 " << TIP_(tooltip.data());
if (i < input_tooltips.size() - 1) {
ss << ".\n";
}
@ -941,7 +941,7 @@ static void create_inspection_string_for_geometry_info(const geo_log::GeometryIn
return std::string(str);
};
ss << TIP_("Geometry:\n");
ss << TIP_("Geometry:") << "\n";
for (GeometryComponentType type : component_types) {
switch (type) {
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);
std::stringstream ss;
ss << TIP_("Accessed named attributes:\n");
ss << TIP_("Accessed named attributes:") << "\n";
struct NameWithUsage {
StringRefNull name;
@ -1917,7 +1917,7 @@ static NodeExtraInfoRow row_from_used_named_attribute(
NodeExtraInfoRow row;
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.tooltip_fn = named_attribute_tooltip;
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. */
ot->invoke = sequencer_rename_channel_invoke;
ot->poll = sequencer_edit_poll;
ot->poll = sequencer_edit_with_channel_region_poll;
/* Flags. */
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);
}
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)
{
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];
UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &mouseloc[0], &mouseloc[1]);
if (RNA_boolean_get(op->ptr, "use_cursor_position")) {
RNA_int_set(op->ptr, "frame", mouseloc[0]);
if (v2d) {
UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &mouseloc[0], &mouseloc[1]);
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, "channel", mouseloc[1]);
RNA_int_set(op->ptr, "frame", split_frame);
RNA_enum_set(op->ptr, "side", split_side);
// 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)
{
ARegion *region = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
ListBase *markers = &scene->markers;
if (region->regiontype == RGN_TYPE_WINDOW && !BLI_listbase_is_empty(markers)) {
/* Bounding box of 30 pixels is used for markers shortcuts,
* prevent conflict with markers shortcuts here.
*/
if (event->mval[1] <= 30) {
return OPERATOR_PASS_THROUGH;
if (!BLI_listbase_is_empty(markers)) {
ARegion *region = CTX_wm_region(C);
if (region && (region->regiontype == RGN_TYPE_WINDOW)) {
/* Bounding box of 30 pixels is used for markers shortcuts,
* prevent conflict with markers shortcuts here. */
if (event->mval[1] <= 30) {
return OPERATOR_PASS_THROUGH;
}
}
}
@ -1731,9 +1744,9 @@ void SEQUENCER_OT_delete(wmOperatorType *ot)
{
/* Identifiers. */
ot->name = "Erase Strips";
ot->name = "Delete Strips";
ot->idname = "SEQUENCER_OT_delete";
ot->description = "Erase selected strips from the sequencer";
ot->description = "Delete selected strips from the sequencer";
/* Api callbacks. */
ot->invoke = sequencer_delete_invoke;

View File

@ -141,6 +141,7 @@ int seq_effect_find_selected(struct Scene *scene,
/* Operator helpers. */
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);
/* UNUSED */
/* bool sequencer_strip_poll(struct bContext *C); */

View File

@ -41,14 +41,15 @@ using blender::MutableSpan;
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;
}
const Editing *ed = SEQ_editing_get(CTX_data_scene(C));
Sequence *seq = ed->act_seq;
if (seq != nullptr && !SEQ_retiming_is_allowed(seq)) {
if (seq == nullptr) {
return false;
}
if (!SEQ_retiming_is_allowed(seq)) {
CTX_wm_operator_poll_msg_set(C, "This strip type can not be retimed");
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_Runtime *runtime = sspreadsheet->runtime;
std::stringstream ss;
ss << "Rows: ";
ss << IFACE_("Rows:") << " ";
if (runtime->visible_rows != runtime->tot_rows) {
char visible_rows_str[BLI_STR_FORMAT_INT32_GROUPED_SIZE];
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];
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();
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->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,

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[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]);
float rot_90_vec[2] = {-dir_ruler[1], dir_ruler[0]};
normalize_v2(rot_90_vec);
@ -941,7 +941,7 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
/* center text */
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]);

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)
{
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;
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;
ED_view3d_cursor_snap_deactive(ipd->snap_state);
ED_region_draw_cb_exit(ipd->region->type, ipd->draw_handle_view);
ED_region_tag_redraw(ipd->region);
if (ipd->region != NULL) {
if (ipd->draw_handle_view != NULL) {
ED_region_draw_cb_exit(ipd->region->type, ipd->draw_handle_view);
}
ED_region_tag_redraw(ipd->region);
}
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);
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);
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__);
Heap *heap = BLI_heap_new();
float scale[2] = {1.0f, 1.0f};
blender::Vector<blender::geometry::PackIsland *> pack_island_vector;
for (int i = 0; i < island_vector.size(); 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_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};
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()) {
blender::geometry::PackIsland *pack_island = pack_island_vector[i];
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);
/* 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]) /
params->target_aspect_y;
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][1] = 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;
pack_island_params.setFromUnwrapOptions(options);
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.ignore_pinned = false;
pack_island_params.margin_method = eUVPackIsland_MarginMethod(
@ -1474,6 +1474,7 @@ void UV_OT_pack_islands(wmOperatorType *ot)
/* properties */
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, "scale", true, "Scale", "Scale islands to fill unit square");
RNA_def_boolean(
ot->srna, "merge_overlap", false, "Merge Overlapped", "Overlapping islands stick together");
RNA_def_enum(ot->srna,

View File

@ -48,6 +48,8 @@ class UVPackIsland_Params {
/** Islands can be rotated to improve packing. */
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. */
bool only_selected_uvs;
/** (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 finalize_geometry_(const UVPackIsland_Params &params, MemArena *arena, Heap *heap);
blender::Vector<float2> triangle_vertices_;
private:
void calculate_pivot_(); /* Calculate `pivot_` and `half_diagonal_` based on added triangles. */
void calculate_pre_rotation_(const UVPackIsland_Params &params);
blender::Vector<float2> triangle_vertices_;
friend class Occupancy;
friend class OverlapMerger;
};
void pack_islands(const Span<PackIsland *> &islands,
const UVPackIsland_Params &params,
float r_scale[2]);
float pack_islands(const Span<PackIsland *> &islands, const UVPackIsland_Params &params);
/** 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]);

View File

@ -295,6 +295,7 @@ void PackIsland::place_(const float scale, const uv_phi phi)
UVPackIsland_Params::UVPackIsland_Params()
{
rotate = false;
scale_to_fit = true;
only_selected_uvs = false;
only_selected_faces = false;
use_seams = false;
@ -597,6 +598,7 @@ class Occupancy {
Occupancy(const float initial_scale);
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. */
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. */
bitmap_scale_reciprocal *= 0.5f;
clear();
}
void Occupancy::clear()
{
for (int i = 0; i < bitmap_radix * bitmap_radix; i++) {
bitmap_[i] = terminal;
}
@ -728,33 +735,33 @@ float Occupancy::trace_triangle(const float2 &uv0,
return -1.0f; /* Available. */
}
float2 PackIsland::get_diagonal_support_d4(const float scale,
const float rotation,
const float margin) const
float2 PackIsland::get_diagonal_support(const float scale,
const float rotation,
/* const bool reflection, */
const float margin) const
{
if (rotation == 0.0f) {
return half_diagonal_ * scale + margin; /* Fast path for common case. */
/* Caution: Only "Dihedral Group D4" transforms are calculated exactly.
* 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)) {
return get_diagonal_support_d4(scale, 0.0f, margin); /* Same as 0.0f */
if (rotation == DEG2RADF(-90.0f) || rotation == DEG2RADF(90.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];
build_transformation(scale, rotation, matrix);
/* TODO: Use convex hull to calculate support. */
float diagonal_rotated[2];
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,
const float rotation,
const float margin) const
{
/* Only "D4" transforms are currently supported. */
return get_diagonal_support_d4(scale, rotation, margin);
return float2(sx + sy * 0.5f + margin, sx * 0.5f + sy + margin); /* Upper bound. */
}
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);
/* 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". */
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;
}
/** 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.
*
@ -883,7 +1045,12 @@ static void pack_island_xatlas(const Span<UVAABBIsland *> island_indices,
float max_u = 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;
/* 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 (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];
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++) {
phi = find_best_fit_for_island(
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. */
scan_line = 0;
occupancy.increase_scale();
/* 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);
}
traced_islands = 0; /* Will trigger a re-trace of previously solved islands. */
continue;
}
/* Place island. */
r_phis[island_indices[i]->index] = phi;
occupancy.trace_island(island, phi, scale, margin, true);
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. */
float2 top_right = island->get_diagonal_support(scale, phi.rotation, margin) + phi.translation;
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);
}
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);
}
@ -1283,9 +1473,8 @@ class OverlapMerger {
return result;
}
static void pack_islands_overlap(const Span<PackIsland *> &islands,
const UVPackIsland_Params &params,
float r_scale[2])
static float pack_islands_overlap(const Span<PackIsland *> &islands,
const UVPackIsland_Params &params)
{
/* 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`. */
UVPackIsland_Params sub_params(params);
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! */
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_;
delete merge;
}
return result;
}
};
@ -1347,31 +1538,25 @@ static void finalize_geometry(const Span<PackIsland *> &islands, const UVPackIsl
BLI_memarena_free(arena);
}
void pack_islands(const Span<PackIsland *> &islands,
const UVPackIsland_Params &params,
float r_scale[2])
float pack_islands(const Span<PackIsland *> &islands, const UVPackIsland_Params &params)
{
BLI_assert(0.0f <= params.margin);
BLI_assert(0.0f <= params.target_aspect_y);
if (islands.size() == 0) {
r_scale[0] = 1.0f;
r_scale[1] = 1.0f;
return; /* Nothing to do, just create a safe default. */
return 1.0f; /* Nothing to do, just create a safe default. */
}
if (params.merge_overlap) {
return OverlapMerger::pack_islands_overlap(islands, params, r_scale);
return OverlapMerger::pack_islands_overlap(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. */
const float scale = pack_islands_margin_fraction(islands, params.margin, params);
r_scale[0] = scale;
r_scale[1] = scale;
return;
return pack_islands_margin_fraction(islands, params.margin, params);
}
float margin = params.margin;
@ -1395,8 +1580,7 @@ void pack_islands(const Span<PackIsland *> &islands,
for (const int64_t i : islands.index_range()) {
islands[i]->place_(scale, phis[i]);
}
r_scale[0] = 1.0f / max_uv;
r_scale[1] = r_scale[0];
return params.scale_to_fit ? 1.0f / max_uv : 1.0f;
}
/** \} */

View File

@ -4131,15 +4131,14 @@ void uv_parametrizer_pack(ParamHandle *handle, float margin, bool do_rotate, boo
pack_island_vector.append(pack_island);
}
float scale[2] = {1.0f, 1.0f};
pack_islands(pack_island_vector, params, scale);
const float scale = pack_islands(pack_island_vector, params);
for (const int64_t i : pack_island_vector.index_range()) {
PackIsland *pack_island = pack_island_vector[i];
PChart *chart = handle->charts[pack_island->caller_index];
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) {
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) {
const std::string blender_usd_data_folder = blender_usd_datafiles;
/* 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
}

View File

@ -18,7 +18,7 @@ class obj_mtl_parser_test : public testing::Test {
BKE_tempdir_init(nullptr);
std::string tmp_dir = BKE_tempdir_base();
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");
fputs(text, 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)
{
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);
}
void check_impl(StringRefNull mtl_file_path,

View File

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

View File

@ -3,6 +3,8 @@
#include "UI_interface.h"
#include "UI_resources.h"
#include "BLT_translation.h"
#include "node_geometry_util.hh"
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)
{
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;
});
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;
});
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;
});
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;
});
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;
});
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;
});
}

View File

@ -61,7 +61,7 @@ static void node_geo_exec(GeoNodeExecParams params)
const bool is_recursive = BKE_collection_has_object_recursive_instanced(
collection, const_cast<Object *>(self_object));
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();
return;
}

View File

@ -59,12 +59,15 @@ static void node_geo_exec(GeoNodeExecParams params)
}
if (!attribute_exists) {
params.error_message_add(NodeWarningType::Info,
TIP_("Attribute does not exist: \"") + name + "\"");
char *message = BLI_sprintfN(TIP_("Attribute does not exist: \"%s\""), name.c_str());
params.error_message_add(NodeWarningType::Warning, message);
MEM_freeN(message);
}
if (cannot_delete) {
params.error_message_add(NodeWarningType::Warning,
TIP_("Cannot delete built-in attribute with name \"") + name + "\"");
char *message = BLI_sprintfN(TIP_("Cannot delete built-in attribute with name \"%s\""),
name.c_str());
params.error_message_add(NodeWarningType::Warning, message);
MEM_freeN(message);
}
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));
}
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 */
ot->invoke = gizmo_select_invoke;
ot->poll = ED_operator_region_gizmo_active;
ot->flag = OPTYPE_UNDO;
@ -606,6 +607,7 @@ void GIZMOGROUP_OT_gizmo_tweak(wmOperatorType *ot)
/* api callbacks */
ot->invoke = gizmo_tweak_invoke;
ot->modal = gizmo_tweak_modal;
ot->poll = ED_operator_region_gizmo_active;
/* TODO(@ideasman42): This causes problems tweaking settings for operators,
* 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)
{
if (G.background) {
return false;
}
return (bool)GHOST_hasClipboardImage();
}
ImBuf *WM_clipboard_image_get(void)
{
if (G.background) {
return NULL;
}
int 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)
{
if (G.background) {
return false;
}
bool free_byte_buffer = false;
if (ibuf->rect == NULL) {
/* Add a byte buffer if it does not have one. */

View File

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