Merge branch 'master' into sculpt-dev

This commit is contained in:
Pablo Dobarro 2021-01-14 17:56:31 +01:00
commit 97ab225428
48 changed files with 742 additions and 386 deletions

View File

@ -610,7 +610,13 @@ endif()
# GNU Compiler
if(CMAKE_COMPILER_IS_GNUCC)
set(PLATFORM_CFLAGS "-pipe -fPIC -funsigned-char -fno-strict-aliasing")
# ffp-contract=off:
# Automatically turned on when building with "-march=native". This is
# explicitly turned off here as it will make floating point math give a bit
# different results. This will lead to automated test failures. So disable
# this until we support it. Seems to default to off in clang and the intel
# compiler.
set(PLATFORM_CFLAGS "-pipe -fPIC -funsigned-char -fno-strict-aliasing -ffp-contract=off")
# `maybe-uninitialized` is unreliable in release builds, but fine in debug builds.
set(GCC_EXTRA_FLAGS_RELEASE "-Wno-maybe-uninitialized")

View File

@ -379,6 +379,9 @@ endif()
# Subdirectories
if(WITH_CYCLES_BLENDER)
# Not needed to make cycles automated tests pass with -march=native.
# However Blender itself needs this flag.
remove_cc_flag("-ffp-contract=off")
add_definitions(-DWITH_BLENDER_GUARDEDALLOC)
add_subdirectory(blender)
endif()

View File

@ -541,11 +541,11 @@ GHOST_TSuccess GHOST_SystemWin32::setCursorPosition(GHOST_TInt32 x, GHOST_TInt32
input.type = INPUT_MOUSE;
input.mi.mouseData = 0;
input.mi.time = ::GetTickCount();
/* Map from virtual screen to 0-65536. */
input.mi.dx = (x - GetSystemMetrics(SM_XVIRTUALSCREEN)) * 65536 /
GetSystemMetrics(SM_CXVIRTUALSCREEN);
input.mi.dy = (y - GetSystemMetrics(SM_YVIRTUALSCREEN)) * 65536 /
GetSystemMetrics(SM_CYVIRTUALSCREEN);
/* Map from virtual screen to 0-65535 inclusive. */
input.mi.dx = (x - GetSystemMetrics(SM_XVIRTUALSCREEN)) * 65535 /
(GetSystemMetrics(SM_CXVIRTUALSCREEN) - 1);
input.mi.dy = (y - GetSystemMetrics(SM_YVIRTUALSCREEN)) * 65535 /
(GetSystemMetrics(SM_CYVIRTUALSCREEN) - 1);
input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK;
SendInput(1, &input, sizeof(input));

View File

@ -74,9 +74,11 @@ def kmi_args_as_data(kmi):
s.append(f"\"key_modifier\": '{kmi.key_modifier}'")
if kmi.repeat:
if kmi.map_type == 'KEYBOARD':
if kmi.value in {'PRESS', 'ANY'}:
s.append("\"repeat\": True")
if (
(kmi.map_type == 'KEYBOARD' and kmi.value in {'PRESS', 'ANY'}) or
(kmi.map_type == 'TEXTINPUT')
):
s.append("\"repeat\": True")
return "{" + ", ".join(s) + "}"

View File

@ -537,6 +537,9 @@ def km_screen(params):
("ed.undo_history", {"type": 'Z', "value": 'PRESS', "ctrl": True, "alt": True}, None),
("screen.screen_full_area", {"type": 'UP_ARROW', "value": 'PRESS', "ctrl": True}, None),
("screen.screen_full_area", {"type": 'DOWN_ARROW', "value": 'PRESS', "ctrl": True}, None),
("screen.screen_full_area", {"type": 'SPACE', "value": 'PRESS', "shift": True}, None),
("screen.screen_full_area", {"type": 'F10', "value": 'PRESS', "alt": True},
{"properties": [("use_hide_panels", True)]}),
("screen.screen_set", {"type": 'RIGHT_ARROW', "value": 'PRESS', "ctrl": True},
{"properties": [("delta", 1)]}),
("screen.screen_set", {"type": 'LEFT_ARROW', "value": 'PRESS', "ctrl": True},
@ -1591,12 +1594,26 @@ def km_graph_editor(params):
("wm.context_toggle", {"type": 'O', "value": 'PRESS'},
{"properties": [("data_path", 'tool_settings.use_proportional_fcurve')]}),
op_menu_pie("VIEW3D_MT_proportional_editing_falloff_pie", {"type": 'O', "value": 'PRESS', "shift": True}),
op_menu_pie("GRAPH_MT_pivot_pie", {"type": 'PERIOD', "value": 'PRESS'}),
("marker.add", {"type": 'M', "value": 'PRESS'}, None),
("marker.rename", {"type": 'M', "value": 'PRESS', "ctrl": True}, None),
*_template_items_context_menu("GRAPH_MT_context_menu", params.context_menu_event),
])
if not params.legacy:
items.extend([
op_menu_pie("GRAPH_MT_pivot_pie", {"type": 'PERIOD', "value": 'PRESS'}),
])
else:
items.extend([
# Old pivot.
("wm.context_set_enum", {"type": 'COMMA', "value": 'PRESS'},
{"properties": [("data_path", 'space_data.pivot_point'), ("value", 'BOUNDING_BOX_CENTER')]}),
("wm.context_set_enum", {"type": 'PERIOD', "value": 'PRESS'},
{"properties": [("data_path", 'space_data.pivot_point'), ("value", 'CURSOR')]}),
("wm.context_set_enum", {"type": 'PERIOD', "value": 'PRESS', "ctrl": True},
{"properties": [("data_path", 'space_data.pivot_point'), ("value", 'INDIVIDUAL_ORIGINS')]}),
])
if params.select_mouse == 'LEFTMOUSE' and not params.legacy:
items.extend([
("graph.cursor_set", {"type": 'RIGHTMOUSE', "value": 'PRESS', "shift": True}, None),
@ -1697,14 +1714,25 @@ def km_image(params):
for i in range(9)
)
),
op_menu_pie("IMAGE_MT_pivot_pie", {"type": 'PERIOD', "value": 'PRESS'}),
("image.render_border", {"type": 'B', "value": 'PRESS', "ctrl": True}, None),
("image.clear_render_border", {"type": 'B', "value": 'PRESS', "ctrl": True, "alt": True}, None),
*_template_items_context_menu("IMAGE_MT_mask_context_menu", params.context_menu_event),
])
if params.legacy:
if not params.legacy:
items.extend([
op_menu_pie("IMAGE_MT_pivot_pie", {"type": 'PERIOD', "value": 'PRESS'}),
])
else:
items.extend([
# Old pivot.
("wm.context_set_enum", {"type": 'COMMA', "value": 'PRESS'},
{"properties": [("data_path", 'space_data.pivot_point'), ("value", 'CENTER')]}),
("wm.context_set_enum", {"type": 'COMMA', "value": 'PRESS', "ctrl": True},
{"properties": [("data_path", 'space_data.pivot_point'), ("value", 'MEDIAN')]}),
("wm.context_set_enum", {"type": 'PERIOD', "value": 'PRESS'},
{"properties": [("data_path", 'space_data.pivot_point'), ("value", 'CURSOR')]}),
("image.view_center_cursor", {"type": 'HOME', "value": 'PRESS', "alt": True}, None),
])
@ -2826,14 +2854,25 @@ def km_clip_editor(params):
("clip.clear_track_path", {"type": 'T', "value": 'PRESS', "shift": True, "alt": True},
{"properties": [("action", 'ALL'), ("clear_active", False)]}),
("clip.cursor_set", params.cursor_set_event, None),
op_menu_pie("CLIP_MT_pivot_pie", {"type": 'PERIOD', "value": 'PRESS'}),
("clip.copy_tracks", {"type": 'C', "value": 'PRESS', "ctrl": True}, None),
("clip.paste_tracks", {"type": 'V', "value": 'PRESS', "ctrl": True}, None),
*_template_items_context_menu("CLIP_MT_tracking_context_menu", params.context_menu_event),
])
if params.legacy:
if not params.legacy:
op_menu_pie("CLIP_MT_pivot_pie", {"type": 'PERIOD', "value": 'PRESS'}),
else:
items.extend([
# Old pivot.
("wm.context_set_enum", {"type": 'COMMA', "value": 'PRESS'},
{"properties": [("data_path", 'space_data.pivot_point'), ("value", 'BOUNDING_BOX_CENTER')]}),
("wm.context_set_enum", {"type": 'COMMA', "value": 'PRESS', "ctrl": True},
{"properties": [("data_path", 'space_data.pivot_point'), ("value", 'MEDIAN_POINT')]}),
("wm.context_set_enum", {"type": 'PERIOD', "value": 'PRESS'},
{"properties": [("data_path", 'space_data.pivot_point'), ("value", 'CURSOR')]}),
("wm.context_set_enum", {"type": 'PERIOD', "value": 'PRESS', "ctrl": True},
{"properties": [("data_path", 'space_data.pivot_point'), ("value", 'INDIVIDUAL_ORIGINS')]}),
("clip.view_center_cursor", {"type": 'HOME', "value": 'PRESS', "alt": True}, None),
])

View File

@ -1435,7 +1435,7 @@ class VIEW3D_PT_tools_grease_pencil_brush_advanced(View3DPanel, Panel):
row.prop(gp_settings, "fill_layer_mode", text="Layers")
col.separator()
col.prop(gp_settings, "fill_factor", text="Resolution")
col.prop(gp_settings, "fill_factor")
if gp_settings.fill_draw_mode != 'STROKE':
col = layout.column(align=False, heading="Ignore Transparent")
col.use_property_decorate = False

View File

@ -65,6 +65,62 @@ template<> struct DefaultHash<GeometryComponentType> {
};
} // namespace blender
class GeometryComponent;
/**
* An #OutputAttributePtr wraps a #WriteAttributePtr that might not be stored in its final
* destination yet. Therefore, once the attribute has been filled with data, the #save method has
* to be called, to store the attribute where it belongs (possibly by replacing an existing
* attribute with the same name).
*
* This is useful for example in the Attribute Color Ramp node, when the same attribute name is
* used as input and output. Typically the input is a float attribute, and the output is a color.
* Those two attributes cannot exist at the same time, due to a name collision. To handle this
* situation well, first the output colors have to be computed before the input floats are deleted.
* Therefore, the outputs have to be written to a temporary buffer that replaces the existing
* attribute once all computations are done.
*/
class OutputAttributePtr {
private:
blender::bke::WriteAttributePtr attribute_;
public:
OutputAttributePtr() = default;
OutputAttributePtr(blender::bke::WriteAttributePtr attribute);
OutputAttributePtr(GeometryComponent &component,
AttributeDomain domain,
std::string name,
CustomDataType data_type);
~OutputAttributePtr();
/* Returns false, when this wrapper is empty. */
operator bool() const
{
return static_cast<bool>(attribute_);
}
/* Get a reference to the underlying #WriteAttribute. */
blender::bke::WriteAttribute &get()
{
BLI_assert(attribute_);
return *attribute_;
}
blender::bke::WriteAttribute &operator*()
{
return *attribute_;
}
blender::bke::WriteAttribute *operator->()
{
return attribute_.get();
}
void save();
void apply_span_and_save();
};
/**
* This is the base class for specialized geometry component types.
*/
@ -185,14 +241,17 @@ class GeometryComponent {
}
/**
* Returns the attribute with the given parameters if it exists.
* If an exact match does not exist, other attributes with the same name are deleted and a new
* attribute is created if possible.
* If an attribute with the given params exist, it is returned.
* If no attribute with the given name exists, it is created and returned.
* If an attribute with the given name but different domain or type exists, a temporary attribute
* is created that has to be saved after the output has been computed. This avoids deleting
* another attribute, before a computation is finished.
*
* This might return no attribute when the attribute cannot exist on the component.
*/
blender::bke::WriteAttributePtr attribute_try_ensure_for_write(
const blender::StringRef attribute_name,
const AttributeDomain domain,
const CustomDataType data_type);
OutputAttributePtr attribute_try_get_for_output(const blender::StringRef attribute_name,
const AttributeDomain domain,
const CustomDataType data_type);
};
template<typename T>

View File

@ -40,8 +40,10 @@ static CLG_LogRef LOG = {"bke.attribute_access"};
using blender::float3;
using blender::Set;
using blender::StringRef;
using blender::StringRefNull;
using blender::bke::ReadAttributePtr;
using blender::bke::WriteAttributePtr;
using blender::fn::GMutableSpan;
/* Can't include BKE_object_deform.h right now, due to an enum forward declaration. */
extern "C" MDeformVert *BKE_object_defgroup_data_create(ID *id);
@ -250,6 +252,54 @@ template<typename T> class ArrayWriteAttribute final : public WriteAttribute {
}
};
/* This is used by the #OutputAttributePtr class. */
class TemporaryWriteAttribute final : public WriteAttribute {
public:
GMutableSpan data;
GeometryComponent &component;
std::string final_name;
TemporaryWriteAttribute(AttributeDomain domain,
GMutableSpan data,
GeometryComponent &component,
std::string final_name)
: WriteAttribute(domain, data.type(), data.size()),
data(data),
component(component),
final_name(std::move(final_name))
{
}
~TemporaryWriteAttribute() override
{
if (data.data() != nullptr) {
cpp_type_.destruct_n(data.data(), data.size());
MEM_freeN(data.data());
}
}
void get_internal(const int64_t index, void *r_value) const override
{
data.type().copy_to_uninitialized(data[index], r_value);
}
void set_internal(const int64_t index, const void *value) override
{
data.type().copy_to_initialized(value, data[index]);
}
void initialize_span(const bool UNUSED(write_only)) override
{
array_buffer_ = data.data();
array_is_temporary_ = false;
}
void apply_span_if_necessary() override
{
/* Do nothing, because the span contains the attribute itself already. */
}
};
template<typename T> class ArrayReadAttribute final : public ReadAttribute {
private:
Span<T> data_;
@ -762,30 +812,117 @@ blender::bke::ReadAttributePtr GeometryComponent::attribute_get_constant_for_rea
return attribute;
}
WriteAttributePtr GeometryComponent::attribute_try_ensure_for_write(const StringRef attribute_name,
const AttributeDomain domain,
const CustomDataType data_type)
OutputAttributePtr GeometryComponent::attribute_try_get_for_output(const StringRef attribute_name,
const AttributeDomain domain,
const CustomDataType data_type)
{
BLI_assert(this->attribute_domain_with_type_supported(domain, data_type));
const blender::fn::CPPType *cpp_type = blender::bke::custom_data_type_to_cpp_type(data_type);
BLI_assert(cpp_type != nullptr);
WriteAttributePtr attribute = this->attribute_try_get_for_write(attribute_name);
if (attribute && attribute->domain() == domain && attribute->cpp_type() == *cpp_type) {
return attribute;
/* If the attribute doesn't exist, make a new one with the correct type. */
if (!attribute) {
this->attribute_try_create(attribute_name, domain, data_type);
attribute = this->attribute_try_get_for_write(attribute_name);
return OutputAttributePtr(std::move(attribute));
}
if (attribute) {
if (!this->attribute_try_delete(attribute_name)) {
return {};
}
/* If an existing attribute has a matching domain and type, just use that. */
if (attribute->domain() == domain && attribute->cpp_type() == *cpp_type) {
return OutputAttributePtr(std::move(attribute));
}
if (!this->attribute_domain_with_type_supported(domain, data_type)) {
return {};
/* Otherwise create a temporary buffer to use before saving the new attribute. */
return OutputAttributePtr(*this, domain, attribute_name, data_type);
}
/* Construct from an attribute that already exists in the geometry component. */
OutputAttributePtr::OutputAttributePtr(WriteAttributePtr attribute)
: attribute_(std::move(attribute))
{
}
/* Construct a temporary attribute that has to replace an existing one later on. */
OutputAttributePtr::OutputAttributePtr(GeometryComponent &component,
AttributeDomain domain,
std::string final_name,
CustomDataType data_type)
{
const blender::fn::CPPType *cpp_type = blender::bke::custom_data_type_to_cpp_type(data_type);
BLI_assert(cpp_type != nullptr);
const int domain_size = component.attribute_domain_size(domain);
void *buffer = MEM_malloc_arrayN(domain_size, cpp_type->size(), __func__);
cpp_type->construct_default_n(buffer, domain_size);
attribute_ = std::make_unique<blender::bke::TemporaryWriteAttribute>(
domain, GMutableSpan{*cpp_type, buffer, domain_size}, component, std::move(final_name));
}
/* Store the computed attribute. If it was stored from the beginning already, nothing is done. This
* might delete another attribute with the same name. */
void OutputAttributePtr::save()
{
if (!attribute_) {
CLOG_WARN(&LOG, "Trying to save an attribute that does not exist anymore.");
return;
}
if (!this->attribute_try_create(attribute_name, domain, data_type)) {
return {};
blender::bke::TemporaryWriteAttribute *attribute =
dynamic_cast<blender::bke::TemporaryWriteAttribute *>(attribute_.get());
if (attribute == nullptr) {
/* The attribute is saved already. */
attribute_.reset();
return;
}
return this->attribute_try_get_for_write(attribute_name);
StringRefNull name = attribute->final_name;
const blender::fn::CPPType &cpp_type = attribute->cpp_type();
/* Delete an existing attribute with the same name if necessary. */
attribute->component.attribute_try_delete(name);
if (!attribute->component.attribute_try_create(
name, attribute_->domain(), attribute_->custom_data_type())) {
/* Cannot create the target attribute for some reason. */
CLOG_WARN(&LOG,
"Creating the '%s' attribute with type '%s' failed.",
name.c_str(),
cpp_type.name().c_str());
attribute_.reset();
return;
}
WriteAttributePtr new_attribute = attribute->component.attribute_try_get_for_write(name);
GMutableSpan temp_span = attribute->data;
GMutableSpan new_span = new_attribute->get_span_for_write_only();
BLI_assert(temp_span.size() == new_span.size());
/* Currently we copy over the attribute. In the future we want to reuse the buffer. */
cpp_type.move_to_initialized_n(temp_span.data(), new_span.data(), new_span.size());
new_attribute->apply_span();
attribute_.reset();
}
OutputAttributePtr::~OutputAttributePtr()
{
if (attribute_) {
CLOG_ERROR(&LOG, "Forgot to call #save or #apply_span_and_save.");
}
}
/* Utility function to call #apply_span and #save in the right order. */
void OutputAttributePtr::apply_span_and_save()
{
BLI_assert(attribute_);
attribute_->apply_span();
this->save();
}
/** \} */

View File

@ -1032,7 +1032,7 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type)
brush->gpencil_settings->fill_leak = 3;
brush->gpencil_settings->fill_threshold = 0.1f;
brush->gpencil_settings->fill_simplylvl = 1;
brush->gpencil_settings->fill_factor = 1;
brush->gpencil_settings->fill_factor = 1.0f;
brush->gpencil_settings->draw_strength = 1.0f;
brush->gpencil_settings->hardeness = 1.0f;

View File

@ -2519,7 +2519,7 @@ void BKE_gpencil_visible_stroke_iter(ViewLayer *view_layer,
int cfra)
{
bGPdata *gpd = (bGPdata *)ob->data;
const bool is_multiedit = GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
const bool is_multiedit = ((GPENCIL_MULTIEDIT_SESSIONS_ON(gpd)) && (!GPENCIL_PLAY_ON(gpd)));
const bool is_onion = do_onion && ((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0);
const bool is_drawing = (gpd->runtime.sbuffer_used > 0);

View File

@ -214,6 +214,7 @@ void GPENCIL_cache_init(void *ved)
NULL :
false;
pd->do_onion = show_onion && !hide_overlay && !playing;
pd->playing = playing;
/* Save simplify flags (can change while drawing, so it's better to save). */
Scene *scene = draw_ctx->scene;
pd->simplify_fill = GPENCIL_SIMPLIFY_FILL(scene, playing);
@ -241,6 +242,7 @@ void GPENCIL_cache_init(void *ved)
pd->simplify_fill = false;
pd->simplify_fx = false;
pd->fade_layer_opacity = -1.0f;
pd->playing = false;
}
{
@ -617,7 +619,7 @@ void GPENCIL_cache_populate(void *ved, Object *ob)
/* Special case for rendering onion skin. */
bGPdata *gpd = (bGPdata *)ob->data;
bool do_onion = (!pd->is_render) ? pd->do_onion : (gpd->onion_flag & GP_ONION_GHOST_ALWAYS);
gpd->runtime.playing = (short)pd->playing;
BKE_gpencil_visible_stroke_iter(is_final_render ? pd->view_layer : NULL,
ob,
gpencil_layer_cache_populate,

View File

@ -342,6 +342,8 @@ typedef struct GPENCIL_PrivateData {
/* Display onion skinning */
bool do_onion;
/* Playing animation */
bool playing;
/* simplify settings */
bool simplify_fill;
bool simplify_fx;

View File

@ -81,6 +81,7 @@
#define LEAK_HORZ 0
#define LEAK_VERT 1
#define MIN_WINDOW_SIZE 128
/* Temporary fill operation data (op->customdata) */
typedef struct tGPDfill {
@ -137,7 +138,7 @@ typedef struct tGPDfill {
/** boundary limits drawing mode */
int fill_draw_mode;
/* scaling factor */
short fill_factor;
float fill_factor;
/* Frame to use. */
int active_cfra;
@ -398,8 +399,8 @@ static bool gpencil_render_offscreen(tGPDfill *tgpf)
/* resize region */
tgpf->region->winrct.xmin = 0;
tgpf->region->winrct.ymin = 0;
tgpf->region->winrct.xmax = (int)tgpf->region->winx * tgpf->fill_factor;
tgpf->region->winrct.ymax = (int)tgpf->region->winy * tgpf->fill_factor;
tgpf->region->winrct.xmax = max_ii((int)tgpf->region->winx * tgpf->fill_factor, MIN_WINDOW_SIZE);
tgpf->region->winrct.ymax = max_ii((int)tgpf->region->winy * tgpf->fill_factor, MIN_WINDOW_SIZE);
tgpf->region->winx = (short)abs(tgpf->region->winrct.xmax - tgpf->region->winrct.xmin);
tgpf->region->winy = (short)abs(tgpf->region->winrct.ymax - tgpf->region->winrct.ymin);
@ -456,7 +457,7 @@ static bool gpencil_render_offscreen(tGPDfill *tgpf)
}
GPU_matrix_push_projection();
GPU_matrix_identity_set();
GPU_matrix_identity_projection_set();
GPU_matrix_push();
GPU_matrix_identity_set();
@ -1394,11 +1395,12 @@ static tGPDfill *gpencil_session_init_fill(bContext *C, wmOperator *UNUSED(op))
Brush *brush = BKE_paint_brush(&ts->gp_paint->paint);
tgpf->brush = brush;
tgpf->flag = brush->gpencil_settings->flag;
tgpf->fill_leak = brush->gpencil_settings->fill_leak;
tgpf->fill_threshold = brush->gpencil_settings->fill_threshold;
tgpf->fill_simplylvl = brush->gpencil_settings->fill_simplylvl;
tgpf->fill_draw_mode = brush->gpencil_settings->fill_draw_mode;
tgpf->fill_factor = (short)max_ii(1, min_ii((int)brush->gpencil_settings->fill_factor, 8));
tgpf->fill_factor = max_ff(GPENCIL_MIN_FILL_FAC,
min_ff(brush->gpencil_settings->fill_factor, 8.0f));
tgpf->fill_leak = (int)ceil((float)brush->gpencil_settings->fill_leak * tgpf->fill_factor);
int totcol = tgpf->ob->totcol;

View File

@ -61,28 +61,22 @@ int ED_gpencil_session_active(void)
return (BLI_listbase_is_empty(&undo_nodes) == false);
}
int ED_undo_gpencil_step(bContext *C, int step, const char *name)
int ED_undo_gpencil_step(bContext *C, const int step)
{
bGPdata **gpd_ptr = NULL, *new_gpd = NULL;
gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
if (step == 1) { /* undo */
// printf("\t\tGP - undo step\n");
if (step == -1) { /* undo */
if (cur_node->prev) {
if (!name || STREQ(cur_node->name, name)) {
cur_node = cur_node->prev;
new_gpd = cur_node->gpd;
}
cur_node = cur_node->prev;
new_gpd = cur_node->gpd;
}
}
else if (step == -1) {
// printf("\t\tGP - redo step\n");
else if (step == 1) {
if (cur_node->next) {
if (!name || STREQ(cur_node->name, name)) {
cur_node = cur_node->next;
new_gpd = cur_node->gpd;
}
cur_node = cur_node->next;
new_gpd = cur_node->gpd;
}
}

View File

@ -213,7 +213,7 @@ bool ED_gpencil_anim_copybuf_paste(struct bAnimContext *ac, const short copy_mod
/* ------------ Grease-Pencil Undo System ------------------ */
int ED_gpencil_session_active(void);
int ED_undo_gpencil_step(struct bContext *C, int step, const char *name);
int ED_undo_gpencil_step(struct bContext *C, const int step);
/* ------------ Grease-Pencil Armature ------------------ */
bool ED_gpencil_add_armature(const struct bContext *C,

View File

@ -65,6 +65,7 @@
#include "ED_space_api.h"
#include "ED_transform.h"
#include "ED_userpref.h"
#include "ED_util.h"
#include "ED_uvedit.h"
#include "io_ops.h"
@ -124,6 +125,7 @@ void ED_spacetypes_init(void)
ED_operatortypes_render();
ED_operatortypes_mask();
ED_operatortypes_io();
ED_operatortypes_edutils();
ED_operatortypes_view2d();
ED_operatortypes_ui();

View File

@ -987,7 +987,10 @@ static void clip_main_region_draw(const bContext *C, ARegion *region)
}
/* callback */
GPU_matrix_push_projection();
wmOrtho2(region->v2d.cur.xmin, region->v2d.cur.xmax, region->v2d.cur.ymin, region->v2d.cur.ymax);
ED_region_draw_cb_draw(C, region, REGION_DRAW_POST_VIEW);
GPU_matrix_pop_projection();
/* reset view matrix */
UI_view2d_view_restore(C);

View File

@ -104,6 +104,7 @@ static ARegion *file_tool_props_region_ensure(ScrArea *area, ARegion *region_pre
BLI_insertlinkafter(&area->regionbase, region_prev, region);
region->regiontype = RGN_TYPE_TOOL_PROPS;
region->alignment = RGN_ALIGN_RIGHT;
region->flag = RGN_FLAG_HIDDEN;
return region;
}
@ -246,13 +247,13 @@ static void file_ensure_valid_region_state(bContext *C,
BLI_assert(region_tools);
if (sfile->browse_mode == FILE_BROWSE_MODE_ASSETS) {
ARegion *region_execute = file_execute_region_ensure(area, region_tools);
ARegion *region_props = file_tool_props_region_ensure(area, region_execute);
/* Hide specific regions by default. */
region_props->flag |= RGN_FLAG_HIDDEN;
region_execute->flag |= RGN_FLAG_HIDDEN;
file_tool_props_region_ensure(area, region_tools);
ARegion *region_execute = BKE_area_find_region_type(area, RGN_TYPE_EXECUTE);
if (region_execute) {
ED_region_remove(C, area, region_execute);
needs_init = true;
}
ARegion *region_ui = BKE_area_find_region_type(area, RGN_TYPE_UI);
if (region_ui) {
ED_region_remove(C, area, region_ui);
@ -281,13 +282,14 @@ static void file_ensure_valid_region_state(bContext *C,
ARegion *region_ui = file_ui_region_ensure(area, region_tools);
UNUSED_VARS(region_ui);
if (region_props) {
BLI_assert(region_execute);
ED_region_remove(C, area, region_props);
if (region_execute) {
ED_region_remove(C, area, region_execute);
needs_init = true;
}
if (region_props) {
ED_region_remove(C, area, region_props);
needs_init = true;
}
}
if (needs_init) {

View File

@ -946,6 +946,24 @@ static void view3d_interactive_add_begin(bContext *C, wmOperator *op, const wmEv
}
}
/* For tweak events the snap target may have changed since dragging,
* update the snap target at the cursor location where tweak began.
*
* NOTE: we could investigating solving this in a more generic way,
* so each operator doesn't have to account for it. */
if (ISTWEAK(event->type)) {
if (ipd->snap_gizmo != NULL) {
ED_gizmotypes_snap_3d_update(ipd->snap_gizmo,
CTX_data_ensure_evaluated_depsgraph(C),
ipd->region,
ipd->v3d,
G_MAIN->wm.first,
mval_fl,
NULL,
NULL);
}
}
ipd->launch_event = WM_userdef_event_type_from_keymap_type(event->type);
view3d_interactive_add_calc_plane(C,

View File

@ -52,6 +52,7 @@ typedef struct TransDataTracking {
float (*smarkers)[2];
int markersnr;
int framenr;
MovieTrackingMarker *markers;
/* marker transformation from curves editor */
@ -73,9 +74,25 @@ enum transDataTracking_Mode {
*
* \{ */
static void markerToTransDataInit(TransData *td,
TransData2D *td2d,
TransDataTracking *tdt,
typedef struct TransformInitContext {
SpaceClip *space_clip;
TransInfo *t;
TransDataContainer *tc;
/* MOTE: There pointers will be nullptr during counting step.
* This means, that the transformation data initialization functions are to increment
* `tc->data_len` instead of filling in the transformation data when these pointers are nullptr.
* For simplicitly, check the `current.td` against nullptr.
* Do not `tc->data_len` when filling in the transformation data. */
struct {
TransData *td;
TransData2D *td2d;
TransDataTracking *tdt;
} current;
} TransformInitContext;
static void markerToTransDataInit(TransformInitContext *init_context,
MovieTrackingTrack *track,
MovieTrackingMarker *marker,
int area,
@ -84,8 +101,19 @@ static void markerToTransDataInit(TransData *td,
const float off[2],
const float aspect[2])
{
TransData *td = init_context->current.td;
TransData2D *td2d = init_context->current.td2d;
TransDataTracking *tdt = init_context->current.tdt;
if (td == NULL) {
init_context->tc->data_len++;
return;
}
int anchor = area == TRACK_AREA_POINT && off;
tdt->flag = marker->flag;
tdt->framenr = marker->framenr;
tdt->mode = transDataTracking_ModeTracks;
if (anchor) {
@ -143,23 +171,20 @@ static void markerToTransDataInit(TransData *td,
unit_m3(td->mtx);
unit_m3(td->smtx);
init_context->current.td++;
init_context->current.td2d++;
init_context->current.tdt++;
}
static void trackToTransData(const int framenr,
TransData *td,
TransData2D *td2d,
TransDataTracking *tdt,
static void trackToTransData(TransformInitContext *init_context,
const int framenr,
MovieTrackingTrack *track,
const float aspect[2])
{
MovieTrackingMarker *marker = BKE_tracking_marker_ensure(track, framenr);
tdt->flag = marker->flag;
marker->flag &= ~(MARKER_DISABLED | MARKER_TRACKED);
markerToTransDataInit(td++,
td2d++,
tdt++,
markerToTransDataInit(init_context,
track,
marker,
TRACK_AREA_POINT,
@ -170,16 +195,14 @@ static void trackToTransData(const int framenr,
if (track->flag & SELECT) {
markerToTransDataInit(
td++, td2d++, tdt++, track, marker, TRACK_AREA_POINT, marker->pos, NULL, NULL, aspect);
init_context, track, marker, TRACK_AREA_POINT, marker->pos, NULL, NULL, aspect);
}
if (track->pat_flag & SELECT) {
int a;
for (a = 0; a < 4; a++) {
markerToTransDataInit(td++,
td2d++,
tdt++,
markerToTransDataInit(init_context,
track,
marker,
TRACK_AREA_PAT,
@ -191,9 +214,7 @@ static void trackToTransData(const int framenr,
}
if (track->search_flag & SELECT) {
markerToTransDataInit(td++,
td2d++,
tdt++,
markerToTransDataInit(init_context,
track,
marker,
TRACK_AREA_SEARCH,
@ -202,9 +223,7 @@ static void trackToTransData(const int framenr,
NULL,
aspect);
markerToTransDataInit(td++,
td2d++,
tdt++,
markerToTransDataInit(init_context,
track,
marker,
TRACK_AREA_SEARCH,
@ -213,15 +232,43 @@ static void trackToTransData(const int framenr,
NULL,
aspect);
}
if (init_context->current.td != NULL) {
marker->flag &= ~(MARKER_DISABLED | MARKER_TRACKED);
}
}
static void planeMarkerToTransDataInit(TransData *td,
TransData2D *td2d,
TransDataTracking *tdt,
static void trackToTransDataIfNeeded(TransformInitContext *init_context,
const int framenr,
MovieTrackingTrack *track,
const float aspect[2])
{
if (!TRACK_VIEW_SELECTED(init_context->space_clip, track)) {
return;
}
if (track->flag & TRACK_LOCKED) {
return;
}
trackToTransData(init_context, framenr, track, aspect);
}
static void planeMarkerToTransDataInit(TransformInitContext *init_context,
MovieTrackingPlaneTrack *plane_track,
MovieTrackingPlaneMarker *plane_marker,
float corner[2],
const float aspect[2])
{
TransData *td = init_context->current.td;
TransData2D *td2d = init_context->current.td2d;
TransDataTracking *tdt = init_context->current.tdt;
if (td == NULL) {
init_context->tc->data_len++;
return;
}
tdt->flag = plane_marker->flag;
tdt->framenr = plane_marker->framenr;
tdt->mode = transDataTracking_ModePlaneTracks;
tdt->plane_track = plane_track;
@ -247,24 +294,38 @@ static void planeMarkerToTransDataInit(TransData *td,
unit_m3(td->mtx);
unit_m3(td->smtx);
init_context->current.td++;
init_context->current.td2d++;
init_context->current.tdt++;
}
static void planeTrackToTransData(const int framenr,
TransData *td,
TransData2D *td2d,
TransDataTracking *tdt,
static void planeTrackToTransData(TransformInitContext *init_context,
const int framenr,
MovieTrackingPlaneTrack *plane_track,
const float aspect[2])
{
MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_ensure(plane_track, framenr);
int i;
tdt->flag = plane_marker->flag;
plane_marker->flag &= ~PLANE_MARKER_TRACKED;
for (i = 0; i < 4; i++) {
planeMarkerToTransDataInit(td++, td2d++, tdt++, plane_track, plane_marker->corners[i], aspect);
for (int i = 0; i < 4; i++) {
planeMarkerToTransDataInit(
init_context, plane_track, plane_marker, plane_marker->corners[i], aspect);
}
if (init_context->current.td != NULL) {
plane_marker->flag &= ~PLANE_MARKER_TRACKED;
}
}
static void planeTrackToTransDataIfNeeded(TransformInitContext *init_context,
const int framenr,
MovieTrackingPlaneTrack *plane_track,
const float aspect[2])
{
if (!PLANE_TRACK_VIEW_SELECTED(plane_track)) {
return;
}
planeTrackToTransData(init_context, framenr, plane_track, aspect);
}
static void transDataTrackingFree(TransInfo *UNUSED(t),
@ -284,101 +345,53 @@ static void transDataTrackingFree(TransInfo *UNUSED(t),
static void createTransTrackingTracksData(bContext *C, TransInfo *t)
{
TransData *td;
TransData2D *td2d;
SpaceClip *sc = CTX_wm_space_clip(C);
MovieClip *clip = ED_space_clip_get_clip(sc);
ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking);
MovieTrackingTrack *track;
MovieTrackingPlaneTrack *plane_track;
TransDataTracking *tdt;
int framenr = ED_space_clip_get_clip_frame_number(sc);
SpaceClip *space_clip = CTX_wm_space_clip(C);
MovieClip *clip = ED_space_clip_get_clip(space_clip);
const ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
const ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking);
const int framenr = ED_space_clip_get_clip_frame_number(space_clip);
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
/* count */
TransformInitContext init_context = {NULL};
init_context.space_clip = space_clip;
init_context.t = t;
init_context.tc = tc;
/* Count required tranformation data. */
tc->data_len = 0;
track = tracksbase->first;
while (track) {
if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
tc->data_len++; /* offset */
if (track->flag & SELECT) {
tc->data_len++;
}
if (track->pat_flag & SELECT) {
tc->data_len += 4;
}
if (track->search_flag & SELECT) {
tc->data_len += 2;
}
}
track = track->next;
LISTBASE_FOREACH (MovieTrackingTrack *, track, tracksbase) {
trackToTransDataIfNeeded(&init_context, framenr, track, t->aspect);
}
for (plane_track = plane_tracks_base->first; plane_track; plane_track = plane_track->next) {
if (PLANE_TRACK_VIEW_SELECTED(plane_track)) {
tc->data_len += 4;
}
LISTBASE_FOREACH (MovieTrackingPlaneTrack *, plane_track, plane_tracks_base) {
planeTrackToTransDataIfNeeded(&init_context, framenr, plane_track, t->aspect);
}
if (tc->data_len == 0) {
return;
}
td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransTracking TransData");
td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D),
"TransTracking TransData2D");
tdt = tc->custom.type.data = MEM_callocN(tc->data_len * sizeof(TransDataTracking),
"TransTracking TransDataTracking");
tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransTracking TransData");
tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "TransTracking TransData2D");
tc->custom.type.data = MEM_callocN(tc->data_len * sizeof(TransDataTracking),
"TransTracking TransDataTracking");
tc->custom.type.free_cb = transDataTrackingFree;
/* create actual data */
track = tracksbase->first;
while (track) {
if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
trackToTransData(framenr, td, td2d, tdt, track, t->aspect);
init_context.current.td = tc->data;
init_context.current.td2d = tc->data_2d;
init_context.current.tdt = tc->custom.type.data;
/* offset */
td++;
td2d++;
tdt++;
/* Create actual transformation data. */
if (track->flag & SELECT) {
td++;
td2d++;
tdt++;
}
if (track->pat_flag & SELECT) {
td += 4;
td2d += 4;
tdt += 4;
}
if (track->search_flag & SELECT) {
td += 2;
td2d += 2;
tdt += 2;
}
}
track = track->next;
LISTBASE_FOREACH (MovieTrackingTrack *, track, tracksbase) {
trackToTransDataIfNeeded(&init_context, framenr, track, t->aspect);
}
for (plane_track = plane_tracks_base->first; plane_track; plane_track = plane_track->next) {
if (PLANE_TRACK_VIEW_SELECTED(plane_track)) {
planeTrackToTransData(framenr, td, td2d, tdt, plane_track, t->aspect);
td += 4;
td2d += 4;
tdt += 4;
}
LISTBASE_FOREACH (MovieTrackingPlaneTrack *, plane_track, plane_tracks_base) {
planeTrackToTransDataIfNeeded(&init_context, framenr, plane_track, t->aspect);
}
}
@ -560,17 +573,17 @@ void createTransTrackingData(bContext *C, TransInfo *t)
static void cancelTransTracking(TransInfo *t)
{
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
SpaceClip *sc = t->area->spacedata.first;
int i, framenr = ED_space_clip_get_clip_frame_number(sc);
TransDataTracking *tdt_array = tc->custom.type.data;
i = 0;
int i = 0;
while (i < tc->data_len) {
TransDataTracking *tdt = &tdt_array[i];
if (tdt->mode == transDataTracking_ModeTracks) {
MovieTrackingTrack *track = tdt->track;
MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
MovieTrackingMarker *marker = BKE_tracking_marker_get_exact(track, tdt->framenr);
BLI_assert(marker != NULL);
marker->flag = tdt->flag;
@ -606,7 +619,10 @@ static void cancelTransTracking(TransInfo *t)
}
else if (tdt->mode == transDataTracking_ModePlaneTracks) {
MovieTrackingPlaneTrack *plane_track = tdt->plane_track;
MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track, framenr);
MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track,
tdt->framenr);
BLI_assert(plane_marker != NULL);
plane_marker->flag = tdt->flag;
i += 3;

View File

@ -3026,7 +3026,11 @@ static short transform_snap_context_project_view3d_mixed_impl(
bool has_hit = false;
Object *ob = NULL;
float loc[3], no[3], obmat[4][4];
float loc[3];
/* Not all snapping callbacks set the normal,
* initialize this since any hit copies both the `loc` and `no`. */
float no[3] = {0.0f, 0.0f, 0.0f};
float obmat[4][4];
int index = -1;
const ARegion *region = sctx->v3d_data.region;

View File

@ -70,6 +70,17 @@
/** We only need this locally. */
static CLG_LogRef LOG = {"ed.undo"};
/**
* \warning Values are used in #ED_undo_gpencil_step,
* which should eventually be replaced with the undo-system.
*/
enum eUndoStepDir {
STEP_REDO = 1,
STEP_UNDO = -1,
/** Only used when the undo step name or index is passed to #ed_undo_step_impl. */
STEP_NONE = 0,
};
/* -------------------------------------------------------------------- */
/** \name Generic Undo System Access
*
@ -171,13 +182,16 @@ void ED_undo_push(bContext *C, const char *str)
/**
* \note Also check #undo_history_exec in bottom if you change notifiers.
*/
static int ed_undo_step_impl(
bContext *C, int step, const char *undoname, int undo_index, ReportList *reports)
static int ed_undo_step_impl(bContext *C,
enum eUndoStepDir step,
const char *undo_name,
const int undo_index,
ReportList *reports)
{
/* Mutually exclusives, ensure correct input. */
BLI_assert(((undoname || undo_index != -1) && !step) ||
(!(undoname || undo_index != -1) && step));
CLOG_INFO(&LOG, 1, "name='%s', step=%d", undoname, step);
BLI_assert(((undo_name || undo_index != -1) && (step == STEP_NONE)) ||
(!(undo_name || undo_index != -1) && (step != STEP_NONE)));
CLOG_INFO(&LOG, 1, "name='%s', index=%d, step=%d", undo_name, undo_index, step);
wmWindowManager *wm = CTX_wm_manager(C);
Scene *scene = CTX_data_scene(C);
ScrArea *area = CTX_wm_area(C);
@ -196,8 +210,12 @@ static int ed_undo_step_impl(
/* TODO(campbell): undo_system: use undo system */
/* grease pencil can be can be used in plenty of spaces, so check it first */
/* FIXME: This gpencil undo effectively only supports the one step undo/redo, undo based on name
* or index is fully not implemented.
* FIXME: However, it seems to never be used in current code (`ED_gpencil_session_active` seems
* to always return false). */
if (ED_gpencil_session_active()) {
return ED_undo_gpencil_step(C, step, undoname);
return ED_undo_gpencil_step(C, (int)step);
}
if (area && (area->spacetype == SPACE_VIEW3D)) {
Object *obact = CTX_data_active_object(C);
@ -207,9 +225,9 @@ static int ed_undo_step_impl(
}
UndoStep *step_data_from_name = NULL;
int step_for_callback = step;
if (undoname != NULL) {
step_data_from_name = BKE_undosys_step_find_by_name(wm->undo_stack, undoname);
enum eUndoStepDir step_for_callback = step;
if (undo_name != NULL) {
step_data_from_name = BKE_undosys_step_find_by_name(wm->undo_stack, undo_name);
if (step_data_from_name == NULL) {
return OPERATOR_CANCELLED;
}
@ -218,14 +236,14 @@ static int ed_undo_step_impl(
/* Pointers match on redo. */
step_for_callback = (BLI_findindex(&wm->undo_stack->steps, step_data_from_name) <
BLI_findindex(&wm->undo_stack->steps, wm->undo_stack->step_active)) ?
1 :
-1;
STEP_UNDO :
STEP_REDO;
}
else if (undo_index != -1) {
step_for_callback = (undo_index <
BLI_findindex(&wm->undo_stack->steps, wm->undo_stack->step_active)) ?
1 :
-1;
STEP_UNDO :
STEP_REDO;
}
/* App-Handlers (pre). */
@ -240,14 +258,14 @@ static int ed_undo_step_impl(
/* Undo System */
{
if (undoname) {
if (undo_name) {
BKE_undosys_step_undo_with_data(wm->undo_stack, C, step_data_from_name);
}
else if (undo_index != -1) {
BKE_undosys_step_undo_from_index(wm->undo_stack, C, undo_index);
}
else {
if (step == 1) {
if (step == STEP_UNDO) {
BKE_undosys_step_undo(wm->undo_stack, C);
}
else {
@ -310,19 +328,19 @@ static int ed_undo_step_impl(
return OPERATOR_FINISHED;
}
static int ed_undo_step_direction(bContext *C, int step, ReportList *reports)
static int ed_undo_step_direction(bContext *C, enum eUndoStepDir step, ReportList *reports)
{
return ed_undo_step_impl(C, step, NULL, -1, reports);
}
static int ed_undo_step_by_name(bContext *C, const char *undo_name, ReportList *reports)
{
return ed_undo_step_impl(C, 0, undo_name, -1, reports);
return ed_undo_step_impl(C, STEP_NONE, undo_name, -1, reports);
}
static int ed_undo_step_by_index(bContext *C, int index, ReportList *reports)
static int ed_undo_step_by_index(bContext *C, const int undo_index, ReportList *reports)
{
return ed_undo_step_impl(C, 0, NULL, index, reports);
return ed_undo_step_impl(C, STEP_NONE, NULL, undo_index, reports);
}
void ED_undo_grouped_push(bContext *C, const char *str)
@ -340,11 +358,11 @@ void ED_undo_grouped_push(bContext *C, const char *str)
void ED_undo_pop(bContext *C)
{
ed_undo_step_direction(C, 1, NULL);
ed_undo_step_direction(C, STEP_UNDO, NULL);
}
void ED_undo_redo(bContext *C)
{
ed_undo_step_direction(C, -1, NULL);
ed_undo_step_direction(C, STEP_REDO, NULL);
}
void ED_undo_push_op(bContext *C, wmOperator *op)
@ -448,7 +466,7 @@ static int ed_undo_exec(bContext *C, wmOperator *op)
{
/* "last operator" should disappear, later we can tie this with undo stack nicer */
WM_operator_stack_clear(CTX_wm_manager(C));
int ret = ed_undo_step_direction(C, 1, op->reports);
int ret = ed_undo_step_direction(C, STEP_UNDO, op->reports);
if (ret & OPERATOR_FINISHED) {
/* Keep button under the cursor active. */
WM_event_add_mousemove(CTX_wm_window(C));
@ -477,7 +495,7 @@ static int ed_undo_push_exec(bContext *C, wmOperator *op)
static int ed_redo_exec(bContext *C, wmOperator *op)
{
int ret = ed_undo_step_direction(C, -1, op->reports);
int ret = ed_undo_step_direction(C, STEP_REDO, op->reports);
if (ret & OPERATOR_FINISHED) {
/* Keep button under the cursor active. */
WM_event_add_mousemove(CTX_wm_window(C));

View File

@ -161,6 +161,14 @@ class GMutableSpan {
void *operator[](int64_t index)
{
BLI_assert(index >= 0);
BLI_assert(index < size_);
return POINTER_OFFSET(data_, type_->size() * index);
}
void *operator[](int64_t index) const
{
BLI_assert(index >= 0);
BLI_assert(index < size_);
return POINTER_OFFSET(data_, type_->size() * index);
}

View File

@ -292,6 +292,7 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemR(col, ptr, "factor_thickness", 0, IFACE_("Thickness"), ICON_NONE);
uiItemR(col, ptr, "factor_uvs", 0, IFACE_("UV"), ICON_NONE);
uiItemR(col, ptr, "noise_scale", 0, NULL, ICON_NONE);
uiItemR(col, ptr, "seed", 0, NULL, ICON_NONE);
gpencil_modifier_panel_end(layout, ptr);
}
@ -316,7 +317,6 @@ static void random_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiLayoutSetActive(layout, RNA_boolean_get(ptr, "random"));
uiItemR(layout, ptr, "step", 0, NULL, ICON_NONE);
uiItemR(layout, ptr, "seed", 0, NULL, ICON_NONE);
}
static void mask_panel_draw(const bContext *UNUSED(C), Panel *panel)

View File

@ -324,6 +324,11 @@ struct _RGBAZ {
using RGBAZ = _RGBAZ;
static half float_to_half_safe(const float value)
{
return half(clamp_f(value, -HALF_MAX, HALF_MAX));
}
extern "C" {
/**
@ -472,10 +477,10 @@ static bool imb_save_openexr_half(ImBuf *ibuf, const char *name, const int flags
from = ibuf->rect_float + channels * i * width;
for (int j = ibuf->x; j > 0; j--) {
to->r = from[0];
to->g = (channels >= 2) ? from[1] : from[0];
to->b = (channels >= 3) ? from[2] : from[0];
to->a = (channels >= 4) ? from[3] : 1.0f;
to->r = float_to_half_safe(from[0]);
to->g = float_to_half_safe((channels >= 2) ? from[1] : from[0]);
to->b = float_to_half_safe((channels >= 3) ? from[2] : from[0]);
to->a = float_to_half_safe((channels >= 4) ? from[3] : 1.0f);
to++;
from += channels;
}
@ -1116,7 +1121,7 @@ void IMB_exr_write_channels(void *handle)
float *rect = echan->rect;
half *cur = current_rect_half;
for (size_t i = 0; i < num_pixels; i++, cur++) {
*cur = rect[i * echan->xstride];
*cur = float_to_half_safe(rect[i * echan->xstride]);
}
half *rect_to_write = current_rect_half + (data->height - 1L) * data->width;
frameBuffer.insert(

View File

@ -47,10 +47,13 @@ typedef struct BrushClone {
char _pad[4];
} BrushClone;
#define GPENCIL_MIN_FILL_FAC 0.05f
typedef struct BrushGpencilSettings {
/** Amount of smoothing to apply to newly created strokes. */
float draw_smoothfac;
char _pad2[4];
/** Fill zoom factor */
float fill_factor;
/** Amount of alpha strength to apply to newly created strokes. */
float draw_strength;
/** Amount of jitter to apply to newly created strokes. */
@ -75,8 +78,8 @@ typedef struct BrushGpencilSettings {
float fill_threshold;
/** Number of pixel to consider the leak is too small (x 2). */
short fill_leak;
/** Fill zoom factor */
short fill_factor;
char _pad2[2];
int flag2;
/** Number of simplify steps. */

View File

@ -574,7 +574,9 @@ typedef struct bGPdata_Runtime {
/** Temp stroke used for drawing. */
struct bGPDstroke *sbuffer_gps;
char _pad[2];
/** Animation playing flag. */
short playing;
/** Material index of the stroke. */
short matid;
@ -840,6 +842,8 @@ typedef enum eGP_DrawMode {
((flag & (GP_VERTEX_MASK_SELECTMODE_POINT | GP_VERTEX_MASK_SELECTMODE_STROKE | \
GP_VERTEX_MASK_SELECTMODE_SEGMENT)))
#define GPENCIL_PLAY_ON(gpd) ((gpd) && ((gpd)->runtime.playing == 1))
#ifdef __cplusplus
}
#endif

View File

@ -1466,13 +1466,13 @@ static void rna_def_gpencil_options(BlenderRNA *brna)
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
/* fill factor size */
prop = RNA_def_property(srna, "fill_factor", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "fill_factor");
RNA_def_property_range(prop, 1, 8);
prop = RNA_def_property(srna, "fill_factor", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "fill_factor");
RNA_def_property_range(prop, GPENCIL_MIN_FILL_FAC, 8.0f);
RNA_def_property_ui_text(
prop,
"Resolution",
"Multiplier for fill resolution, higher resolution is more accurate but slower");
"Precision",
"Factor for fill boundary accuracy, higher values are more accurate but slower");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);

View File

@ -489,7 +489,7 @@ static void rna_def_modifier_gpencilnoise(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "seed", PROP_INT, PROP_UNSIGNED);
RNA_def_property_ui_text(prop, "Seed", "Random seed");
RNA_def_property_ui_text(prop, "Noise Seed", "Random seed");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "noise_scale", PROP_FLOAT, PROP_FACTOR);

View File

@ -9347,7 +9347,6 @@ static void rna_def_node_socket_vector(BlenderRNA *brna,
prop = RNA_def_property(srna, "default_value", PROP_FLOAT, subtype);
RNA_def_property_float_sdna(prop, NULL, "value");
RNA_def_property_float_array_default(prop, value_default);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_float_funcs(prop, NULL, NULL, "rna_NodeSocketStandard_vector_range");
RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketStandard_value_update");

View File

@ -110,17 +110,26 @@ static bool meshcache_read_mdd_range_from_time(FILE *fp,
return false;
}
size_t num_frames_read = 0;
size_t num_frames_expect = mdd_head.frame_tot;
errno = 0;
for (i = 0; i < mdd_head.frame_tot; i++) {
fread(&f_time, sizeof(float), 1, fp);
num_frames_read += fread(&f_time, sizeof(float), 1, fp);
#ifdef __LITTLE_ENDIAN__
BLI_endian_switch_float(&f_time);
#endif
if (f_time >= time) {
num_frames_expect = i + 1;
break;
}
f_time_prev = f_time;
}
if (num_frames_read != num_frames_expect) {
*err_str = errno ? strerror(errno) : "Timestamp read failed";
return false;
}
if (i == mdd_head.frame_tot) {
frame = (float)(mdd_head.frame_tot - 1);
}
@ -165,12 +174,14 @@ bool MOD_meshcache_read_mdd_index(FILE *fp,
return false;
}
size_t num_verts_read = 0;
errno = 0;
if (factor >= 1.0f) {
#if 1
float *vco = *vertexCos;
uint i;
for (i = mdd_head.verts_tot; i != 0; i--, vco += 3) {
fread(vco, sizeof(float[3]), 1, fp);
num_verts_read += fread(vco, sizeof(float[3]), 1, fp);
# ifdef __LITTLE_ENDIAN__
BLI_endian_switch_float(vco + 0);
@ -195,7 +206,7 @@ bool MOD_meshcache_read_mdd_index(FILE *fp,
uint i;
for (i = mdd_head.verts_tot; i != 0; i--, vco += 3) {
float tvec[3];
fread(tvec, sizeof(float[3]), 1, fp);
num_verts_read += fread(tvec, sizeof(float[3]), 1, fp);
#ifdef __LITTLE_ENDIAN__
BLI_endian_switch_float(tvec + 0);
@ -209,6 +220,11 @@ bool MOD_meshcache_read_mdd_index(FILE *fp,
}
}
if (num_verts_read != mdd_head.verts_tot) {
*err_str = errno ? strerror(errno) : "Vertex coordinate read failed";
return false;
}
return true;
}

View File

@ -151,11 +151,13 @@ bool MOD_meshcache_read_pc2_index(FILE *fp,
return false;
}
size_t num_verts_read = 0;
errno = 0;
if (factor >= 1.0f) {
float *vco = *vertexCos;
uint i;
for (i = pc2_head.verts_tot; i != 0; i--, vco += 3) {
fread(vco, sizeof(float[3]), 1, fp);
num_verts_read += fread(vco, sizeof(float[3]), 1, fp);
#ifdef __BIG_ENDIAN__
BLI_endian_switch_float(vco + 0);
@ -170,7 +172,7 @@ bool MOD_meshcache_read_pc2_index(FILE *fp,
uint i;
for (i = pc2_head.verts_tot; i != 0; i--, vco += 3) {
float tvec[3];
fread(tvec, sizeof(float[3]), 1, fp);
num_verts_read += fread(tvec, sizeof(float[3]), 1, fp);
#ifdef __BIG_ENDIAN__
BLI_endian_switch_float(tvec + 0);
@ -184,6 +186,11 @@ bool MOD_meshcache_read_pc2_index(FILE *fp,
}
}
if (num_verts_read != pc2_head.verts_tot) {
*err_str = errno ? strerror(errno) : "Vertex coordinate read failed";
return false;
}
return true;
}

View File

@ -41,12 +41,12 @@ static void align_rotations_on_component(GeometryComponent &component,
const NodeGeometryAlignRotationToVector &storage = *(const NodeGeometryAlignRotationToVector *)
node.storage;
WriteAttributePtr rotation_attribute = component.attribute_try_ensure_for_write(
OutputAttributePtr rotation_attribute = component.attribute_try_get_for_output(
"rotation", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
if (!rotation_attribute) {
return;
}
MutableSpan<float3> rotations = rotation_attribute->get_span().typed<float3>();
MutableSpan<float3> rotations = rotation_attribute->get_span<float3>();
FloatReadAttribute factors = params.get_input_attribute<float>(
"Factor", component, ATTR_DOMAIN_POINT, 1.0f);
@ -85,7 +85,7 @@ static void align_rotations_on_component(GeometryComponent &component,
rotations[i] = new_rotation;
}
rotation_attribute->apply_span();
rotation_attribute.apply_span_and_save();
}
static void geo_node_align_rotation_to_vector_exec(GeoNodeExecParams params)

View File

@ -37,15 +37,16 @@ static void execute_on_component(const GeoNodeExecParams &params, GeometryCompon
const bNode &bnode = params.node();
NodeAttributeColorRamp *node_storage = (NodeAttributeColorRamp *)bnode.storage;
/* Use the type of the input attribute, but create a color attribute if it doesn't exist yet. */
const CustomDataType result_type = params.get_input_attribute_data_type(
"Attribute", component, CD_PROP_COLOR);
/* Always output a color attribute for now. We might want to allow users to customize.
* Using the type of an existing attribute could work, but does not have a real benefit
* currently. */
const CustomDataType result_type = CD_PROP_COLOR;
const std::string result_name = params.get_input<std::string>("Result");
/* Once we support more domains at the user level, we have to decide how the result domain is
* chosen. */
const AttributeDomain result_domain = ATTR_DOMAIN_POINT;
WriteAttributePtr attribute_result = component.attribute_try_ensure_for_write(
OutputAttributePtr attribute_result = component.attribute_try_get_for_output(
result_name, result_domain, result_type);
if (!attribute_result) {
return;
@ -63,7 +64,7 @@ static void execute_on_component(const GeoNodeExecParams &params, GeometryCompon
BKE_colorband_evaluate(color_ramp, data_in[i], data_out[i]);
}
attribute_result->apply_span();
attribute_result.apply_span_and_save();
}
static void geo_node_attribute_color_ramp_exec(GeoNodeExecParams params)

View File

@ -242,7 +242,7 @@ static void attribute_compare_calc(GeometryComponent &component, const GeoNodeEx
/* Get result attribute first, in case it has to overwrite one of the existing attributes. */
const std::string result_name = params.get_input<std::string>("Result");
WriteAttributePtr attribute_result = component.attribute_try_ensure_for_write(
OutputAttributePtr attribute_result = component.attribute_try_get_for_output(
result_name, result_domain, result_type);
if (!attribute_result) {
return;
@ -260,8 +260,7 @@ static void attribute_compare_calc(GeometryComponent &component, const GeoNodeEx
return;
}
BooleanWriteAttribute attribute_result_bool = *attribute_result;
MutableSpan<bool> result_span = attribute_result_bool.get_span_for_write_only();
MutableSpan<bool> result_span = attribute_result->get_span_for_write_only<bool>();
/* Use specific types for correct equality operations, but for other operations we use implicit
* conversions and float comparison. In other words, the comparison is not element-wise. */
@ -300,7 +299,7 @@ static void attribute_compare_calc(GeometryComponent &component, const GeoNodeEx
do_math_operation(*attribute_a, *attribute_b, operation, result_span);
}
attribute_result_bool.apply_span();
attribute_result.apply_span_and_save();
}
static void geo_node_attribute_compare_exec(GeoNodeExecParams params)

View File

@ -68,7 +68,7 @@ static void fill_attribute(GeometryComponent &component, const GeoNodeExecParams
return;
}
WriteAttributePtr attribute = component.attribute_try_ensure_for_write(
OutputAttributePtr attribute = component.attribute_try_get_for_output(
attribute_name, domain, data_type);
if (!attribute) {
return;
@ -79,33 +79,31 @@ static void fill_attribute(GeometryComponent &component, const GeoNodeExecParams
const float value = params.get_input<float>("Value_001");
MutableSpan<float> attribute_span = attribute->get_span_for_write_only<float>();
attribute_span.fill(value);
attribute->apply_span();
break;
}
case CD_PROP_FLOAT3: {
const float3 value = params.get_input<float3>("Value");
MutableSpan<float3> attribute_span = attribute->get_span_for_write_only<float3>();
attribute_span.fill(value);
attribute->apply_span();
break;
}
case CD_PROP_COLOR: {
const Color4f value = params.get_input<Color4f>("Value_002");
MutableSpan<Color4f> attribute_span = attribute->get_span_for_write_only<Color4f>();
attribute_span.fill(value);
attribute->apply_span();
break;
}
case CD_PROP_BOOL: {
const bool value = params.get_input<bool>("Value_003");
MutableSpan<bool> attribute_span = attribute->get_span_for_write_only<bool>();
attribute_span.fill(value);
attribute->apply_span();
break;
}
default:
break;
}
attribute.apply_span_and_save();
}
static void geo_node_attribute_fill_exec(GeoNodeExecParams params)

View File

@ -107,7 +107,7 @@ static void attribute_math_calc(GeometryComponent &component, const GeoNodeExecP
/* Get result attribute first, in case it has to overwrite one of the existing attributes. */
const std::string result_name = params.get_input<std::string>("Result");
WriteAttributePtr attribute_result = component.attribute_try_ensure_for_write(
OutputAttributePtr attribute_result = component.attribute_try_get_for_output(
result_name, result_domain, result_type);
if (!attribute_result) {
return;
@ -123,6 +123,7 @@ static void attribute_math_calc(GeometryComponent &component, const GeoNodeExecP
}
do_math_operation(*attribute_a, *attribute_b, *attribute_result, operation);
attribute_result.save();
}
static void geo_node_attribute_math_exec(GeoNodeExecParams params)

View File

@ -136,7 +136,7 @@ static void attribute_mix_calc(GeometryComponent &component, const GeoNodeExecPa
result_domain = result_attribute_read->domain();
}
WriteAttributePtr attribute_result = component.attribute_try_ensure_for_write(
OutputAttributePtr attribute_result = component.attribute_try_get_for_output(
result_name, result_domain, result_type);
if (!attribute_result) {
return;
@ -155,6 +155,7 @@ static void attribute_mix_calc(GeometryComponent &component, const GeoNodeExecPa
*attribute_a,
*attribute_b,
*attribute_result);
attribute_result.save();
}
static void geo_node_attribute_mix_exec(GeoNodeExecParams params)

View File

@ -151,7 +151,7 @@ static void randomize_attribute(GeometryComponent &component,
return;
}
WriteAttributePtr attribute = component.attribute_try_ensure_for_write(
OutputAttributePtr attribute = component.attribute_try_get_for_output(
attribute_name, domain, data_type);
if (!attribute) {
return;
@ -179,6 +179,8 @@ static void randomize_attribute(GeometryComponent &component,
default:
break;
}
attribute.save();
}
static void geo_node_random_attribute_exec(GeoNodeExecParams params)

View File

@ -345,7 +345,7 @@ static void attribute_vector_math_calc(GeometryComponent &component,
/* Get result attribute first, in case it has to overwrite one of the existing attributes. */
const std::string result_name = params.get_input<std::string>("Result");
WriteAttributePtr attribute_result = component.attribute_try_ensure_for_write(
OutputAttributePtr attribute_result = component.attribute_try_get_for_output(
result_name, result_domain, result_type);
if (!attribute_result) {
return;
@ -390,6 +390,7 @@ static void attribute_vector_math_calc(GeometryComponent &component,
*attribute_a, *attribute_b, *attribute_c, *attribute_result, operation);
break;
}
attribute_result.save();
}
static void geo_node_attribute_vector_math_exec(GeoNodeExecParams params)

View File

@ -217,12 +217,12 @@ BLI_NOINLINE static void eliminate_points_based_on_mask(Span<bool> elimination_m
}
}
BLI_NOINLINE static void compute_remaining_point_data(const Mesh &mesh,
Span<float3> bary_coords,
Span<int> looptri_indices,
MutableSpan<float3> r_normals,
MutableSpan<int> r_ids,
MutableSpan<float3> r_rotations)
BLI_NOINLINE static void compute_special_attributes(const Mesh &mesh,
Span<float3> bary_coords,
Span<int> looptri_indices,
MutableSpan<float3> r_normals,
MutableSpan<int> r_ids,
MutableSpan<float3> r_rotations)
{
Span<MLoopTri> looptris = get_mesh_looptris(mesh);
for (const int i : bary_coords.index_range()) {
@ -243,6 +243,30 @@ BLI_NOINLINE static void compute_remaining_point_data(const Mesh &mesh,
}
}
BLI_NOINLINE static void add_remaining_point_attributes(const Mesh &mesh,
GeometryComponent &component,
Span<float3> bary_coords,
Span<int> looptri_indices)
{
OutputAttributePtr id_attribute = component.attribute_try_get_for_output(
"id", ATTR_DOMAIN_POINT, CD_PROP_INT32);
OutputAttributePtr normal_attribute = component.attribute_try_get_for_output(
"normal", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
OutputAttributePtr rotation_attribute = component.attribute_try_get_for_output(
"rotation", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
compute_special_attributes(mesh,
bary_coords,
looptri_indices,
normal_attribute->get_span_for_write_only<float3>(),
id_attribute->get_span_for_write_only<int>(),
rotation_attribute->get_span_for_write_only<float3>());
id_attribute.apply_span_and_save();
normal_attribute.apply_span_and_save();
rotation_attribute.apply_span_and_save();
}
static void sample_mesh_surface_with_minimum_distance(const Mesh &mesh,
const float max_density,
const float minimum_distance,
@ -315,11 +339,6 @@ static void geo_node_point_distribute_exec(GeoNodeExecParams params)
break;
}
const int tot_points = positions.size();
Array<float3> normals(tot_points);
Array<int> stable_ids(tot_points);
Array<float3> rotations(tot_points);
compute_remaining_point_data(
*mesh_in, bary_coords, looptri_indices, normals, stable_ids, rotations);
PointCloud *pointcloud = BKE_pointcloud_new_nomain(tot_points);
memcpy(pointcloud->co, positions.data(), sizeof(float3) * tot_points);
@ -332,29 +351,7 @@ static void geo_node_point_distribute_exec(GeoNodeExecParams params)
geometry_set_out.get_component_for_write<PointCloudComponent>();
point_component.replace(pointcloud);
{
Int32WriteAttribute stable_id_attribute = point_component.attribute_try_ensure_for_write(
"id", ATTR_DOMAIN_POINT, CD_PROP_INT32);
MutableSpan<int> stable_ids_span = stable_id_attribute.get_span();
stable_ids_span.copy_from(stable_ids);
stable_id_attribute.apply_span();
}
{
Float3WriteAttribute normals_attribute = point_component.attribute_try_ensure_for_write(
"normal", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
MutableSpan<float3> normals_span = normals_attribute.get_span();
normals_span.copy_from(normals);
normals_attribute.apply_span();
}
{
Float3WriteAttribute rotations_attribute = point_component.attribute_try_ensure_for_write(
"rotation", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
MutableSpan<float3> rotations_span = rotations_attribute.get_span();
rotations_span.copy_from(rotations);
rotations_attribute.apply_span();
}
add_remaining_point_attributes(*mesh_in, point_component, bary_coords, looptri_indices);
params.set_output("Geometry", std::move(geometry_set_out));
}

View File

@ -104,13 +104,13 @@ static void point_rotate_on_component(GeometryComponent &component,
const bNode &node = params.node();
const NodeGeometryRotatePoints &storage = *(const NodeGeometryRotatePoints *)node.storage;
WriteAttributePtr rotation_attribute = component.attribute_try_ensure_for_write(
OutputAttributePtr rotation_attribute = component.attribute_try_get_for_output(
"rotation", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
if (!rotation_attribute) {
return;
}
MutableSpan<float3> rotations = rotation_attribute->get_span().typed<float3>();
MutableSpan<float3> rotations = rotation_attribute->get_span<float3>();
const int domain_size = rotations.size();
if (storage.type == GEO_NODE_POINT_ROTATE_TYPE_AXIS_ANGLE) {
@ -138,7 +138,7 @@ static void point_rotate_on_component(GeometryComponent &component,
}
}
rotation_attribute->apply_span();
rotation_attribute.apply_span_and_save();
}
static void geo_node_point_rotate_exec(GeoNodeExecParams params)

View File

@ -34,7 +34,7 @@ namespace blender::nodes {
static void execute_on_component(GeoNodeExecParams params, GeometryComponent &component)
{
Float3WriteAttribute scale_attribute = component.attribute_try_ensure_for_write(
OutputAttributePtr scale_attribute = component.attribute_try_get_for_output(
"scale", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
ReadAttributePtr attribute = params.get_input_attribute(
"Factor", component, ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, nullptr);
@ -43,12 +43,12 @@ static void execute_on_component(GeoNodeExecParams params, GeometryComponent &co
}
Span<float3> data = attribute->get_span<float3>();
MutableSpan<float3> scale_span = scale_attribute.get_span();
MutableSpan<float3> scale_span = scale_attribute->get_span<float3>();
for (const int i : scale_span.index_range()) {
scale_span[i] = scale_span[i] * data[i];
}
scale_attribute.apply_span();
scale_attribute.apply_span_and_save();
}
static void geo_node_point_scale_exec(GeoNodeExecParams params)

View File

@ -34,7 +34,7 @@ namespace blender::nodes {
static void execute_on_component(GeoNodeExecParams params, GeometryComponent &component)
{
Float3WriteAttribute position_attribute = component.attribute_try_ensure_for_write(
OutputAttributePtr position_attribute = component.attribute_try_get_for_output(
"position", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
ReadAttributePtr attribute = params.get_input_attribute(
"Translation", component, ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, nullptr);
@ -43,12 +43,12 @@ static void execute_on_component(GeoNodeExecParams params, GeometryComponent &co
}
Span<float3> data = attribute->get_span<float3>();
MutableSpan<float3> scale_span = position_attribute.get_span();
MutableSpan<float3> scale_span = position_attribute->get_span<float3>();
for (const int i : scale_span.index_range()) {
scale_span[i] = scale_span[i] + data[i];
}
position_attribute.apply_span();
position_attribute.apply_span_and_save();
}
static void geo_node_point_translate_exec(GeoNodeExecParams params)

View File

@ -1079,7 +1079,12 @@ PyDoc_STRVAR(
" :arg cage: Get the mesh as a deformed cage.\n"
" :type cage: boolean\n"
" :arg face_normals: Calculate face normals.\n"
" :type face_normals: boolean\n");
" :type face_normals: boolean\n"
"\n"
" .. deprecated:: 2.93\n"
"\n"
" The deform parameter is deprecated, assumed to be True, and will be removed in version "
"3.0.\n");
static PyObject *bpy_bmesh_from_object(BPy_BMesh *self, PyObject *args, PyObject *kw)
{
static const char *kwlist[] = {"object", "depsgraph", "deform", "cage", "face_normals", NULL};
@ -1120,45 +1125,36 @@ static PyObject *bpy_bmesh_from_object(BPy_BMesh *self, PyObject *args, PyObject
return NULL;
}
if (use_deform == false) {
PyErr_WarnEx(PyExc_FutureWarning,
"from_object(...): the deform parameter is deprecated, assumed to be True, and "
"will be removed in version 3.0",
1);
}
const bool use_render = DEG_get_mode(depsgraph) == DAG_EVAL_RENDER;
scene_eval = DEG_get_evaluated_scene(depsgraph);
ob_eval = DEG_get_evaluated_object(depsgraph, ob);
bool need_free = false;
/* Write the display mesh into the dummy mesh */
if (use_deform) {
if (use_render) {
if (use_cage) {
PyErr_SetString(PyExc_ValueError,
"from_object(...): cage arg is unsupported when dependency graph "
"evaluation mode is RENDER");
return NULL;
}
me_eval = BKE_mesh_new_from_object(depsgraph, ob_eval, true);
need_free = true;
}
else {
if (use_cage) {
me_eval = mesh_get_eval_deform(depsgraph, scene_eval, ob_eval, &data_masks);
}
else {
me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_eval, &data_masks);
}
}
}
else {
/* !use_deform */
if (use_render) {
if (use_cage) {
PyErr_SetString(PyExc_ValueError,
"from_object(...): cage arg is unsupported when deform=False");
"from_object(...): cage arg is unsupported when dependency graph "
"evaluation mode is RENDER");
return NULL;
}
if (use_render) {
me_eval = mesh_create_eval_no_deform_render(depsgraph, scene_eval, ob, &data_masks);
me_eval = BKE_mesh_new_from_object(depsgraph, ob_eval, true);
need_free = true;
}
else {
if (use_cage) {
me_eval = mesh_get_eval_deform(depsgraph, scene_eval, ob_eval, &data_masks);
}
else {
me_eval = mesh_create_eval_no_deform(depsgraph, scene_eval, ob, &data_masks);
me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_eval, &data_masks);
}
}

View File

@ -651,6 +651,9 @@ if(WITH_CYCLES OR WITH_OPENGL_RENDER_TESTS)
# Cycles
if(WITH_CYCLES)
if(NOT WITH_CYCLES_OSL)
set(_cycles_blacklist OSL)
endif()
foreach(_cycles_device ${CYCLES_TEST_DEVICES})
string(TOLOWER "${_cycles_device}" _cycles_device_lower)
set(_cycles_render_tests bake;${render_tests};osl)
@ -664,6 +667,7 @@ if(WITH_CYCLES OR WITH_OPENGL_RENDER_TESTS)
-idiff "${OPENIMAGEIO_IDIFF}"
-outdir "${TEST_OUT_DIR}/cycles"
-device ${_cycles_device}
-blacklist ${_cycles_blacklist}
)
endforeach()
endforeach()

View File

@ -9,6 +9,53 @@ import subprocess
import sys
from pathlib import Path
# List of .blend files that are known to be failing and are not ready to be
# tested, or that only make sense on some devices. Accepts regular expressions.
BLACKLIST_OSL = [
# OSL only supported on CPU.
'.*_osl.blend',
'osl_.*.blend',
]
BLACKLIST_OPTIX = [
# No branched path on Optix.
'T53854.blend',
'T50164.blend',
'portal.blend',
'denoise_sss.blend',
'denoise_passes.blend',
'distant_light.blend',
'aov_position.blend',
'subsurface_branched_path.blend',
'T43865.blend',
]
BLACKLIST_GPU = [
# Missing equiangular sampling on GPU.
'area_light.blend',
'denoise_hair.blend',
'point_density_.*.blend',
'point_light.blend',
'shadow_catcher_bpt_.*.blend',
'sphere_light.blend',
'spot_light.blend',
'T48346.blend',
'world_volume.blend',
# Uninvestigated differences with GPU.
'image_log.blend',
'subsurface_behind_glass_branched.blend',
'T40964.blend',
'T45609.blend',
'T48860.blend',
'smoke_color.blend',
'bevel_mblur.blend',
# Inconsistency between Embree and Hair primitive on GPU.
'hair_basemesh_intercept.blend',
'hair_instancer_uv.blend',
'hair_particle_random.blend',
'principled_hair_.*.blend',
'transparent_shadow_hair.*.blend',
]
def get_arguments(filepath, output_filepath):
dirname = os.path.dirname(filepath)
@ -51,6 +98,7 @@ def create_argparse():
parser.add_argument("-outdir", nargs=1)
parser.add_argument("-idiff", nargs=1)
parser.add_argument("-device", nargs=1)
parser.add_argument("-blacklist", nargs="*")
return parser
@ -64,8 +112,16 @@ def main():
output_dir = args.outdir[0]
device = args.device[0]
blacklist = []
if device != 'CPU':
blacklist += BLACKLIST_GPU
if device != 'CPU' or 'OSL' in args.blacklist:
blacklist += BLACKLIST_OSL
if device == 'OPTIX':
blacklist += BLACKLIST_OPTIX
from modules import render_report
report = render_report.Report('Cycles', output_dir, idiff, device)
report = render_report.Report('Cycles', output_dir, idiff, device, blacklist)
report.set_pixelated(True)
report.set_reference_dir("cycles_renders")
if device == 'CPU':

View File

@ -29,57 +29,6 @@ class COLORS_DUMMY:
COLORS = COLORS_DUMMY
# List of .blend files that are known to be failing and are not ready to be
# tested, or that only make sense on some devices. Accepts regular expressions.
BLACKLIST = (
# OSL only supported on CPU.
('.*_osl.blend', '(?!CPU)'),
('osl_.*.blend', '(?!CPU)'),
# No baking, branched path and shader raytrace on Optix.
('bake_.*.blend', 'OPTIX'),
('ambient_occlusion.blend', 'OPTIX'),
('ambient_occlusion_only_local.blend', 'OPTIX'),
('bevel.blend', 'OPTIX'),
('bevel_mblur.blend', 'OPTIX'),
('T53854.blend', 'OPTIX'),
('T50164.blend', 'OPTIX'),
('portal.blend', 'OPTIX'),
('denoise_sss.blend', 'OPTIX'),
('denoise_passes.blend', 'OPTIX'),
('distant_light.blend', 'OPTIX'),
('aov_position.blend', 'OPTIX'),
('subsurface_branched_path.blend', 'OPTIX'),
# Missing equiangular sampling on GPU.
('area_light.blend', '(?!CPU)'),
('denoise_hair.blend', '(?!CPU)'),
('point_density_.*.blend', '(?!CPU)'),
('point_light.blend', '(?!CPU)'),
('shadow_catcher_bpt_.*.blend', '(?!CPU)'),
('sphere_light.blend', '(?!CPU)'),
('spot_light.blend', '(?!CPU)'),
('T48346.blend', '(?!CPU)'),
('world_volume.blend', '(?!CPU)'),
# Inconsistency between Embree and Hair primitive on GPU.
('hair_basemesh_intercept.blend', '(?!CPU)'),
('hair_instancer_uv.blend', '(?!CPU)'),
('hair_particle_random.blend', '(?!CPU)'),
('principled_hair_.*.blend', '(?!CPU)'),
('transparent_shadow_hair.*.blend', '(?!CPU)'),
# Uninvestigated differences with GPU.
('image_log.blend', '(?!CPU)'),
('subsurface_behind_glass_branched.blend', '(?!CPU)'),
('T40964.blend', '(?!CPU)'),
('T45609.blend', '(?!CPU)'),
('T48860.blend', '(?!CPU)'),
('smoke_color.blend', '(?!CPU)'),
('T43865.blend', 'OPTIX')
)
def print_message(message, type=None, status=''):
if type == 'SUCCESS':
print(COLORS.GREEN, end="")
@ -103,7 +52,7 @@ def print_message(message, type=None, status=''):
sys.stdout.flush()
def blend_list(dirpath, device):
def blend_list(dirpath, device, blacklist):
import re
for root, dirs, files in os.walk(dirpath):
@ -112,12 +61,10 @@ def blend_list(dirpath, device):
continue
skip = False
for blacklist in BLACKLIST:
if not re.match(blacklist[0], filename):
continue
if device and blacklist[1] and not re.match(blacklist[1], device):
continue
skip = True
for blacklist_entry in blacklist:
if re.match(blacklist_entry, filename):
skip = True
break
if not skip:
filepath = os.path.join(root, filename)
@ -169,10 +116,11 @@ class Report:
'passed_tests',
'compare_tests',
'compare_engine',
'device'
'device',
'blacklist',
)
def __init__(self, title, output_dir, idiff, device=None):
def __init__(self, title, output_dir, idiff, device=None, blacklist=[]):
self.title = title
self.output_dir = output_dir
self.global_dir = os.path.dirname(output_dir)
@ -182,6 +130,7 @@ class Report:
self.fail_threshold = 0.016
self.fail_percent = 1
self.device = device
self.blacklist = blacklist
if device:
self.title = self._engine_title(title, device)
@ -575,7 +524,7 @@ class Report:
def _run_all_tests(self, dirname, dirpath, blender, arguments_cb, batch):
passed_tests = []
failed_tests = []
all_files = list(blend_list(dirpath, self.device))
all_files = list(blend_list(dirpath, self.device, self.blacklist))
all_files.sort()
print_message("Running {} tests from 1 test case." .
format(len(all_files)),