WIP: Brush assets project #106303
|
@ -55,6 +55,7 @@ import pxr.Gf as Gf
|
|||
import pxr.Sdf as Sdf
|
||||
import pxr.Usd as Usd
|
||||
import pxr.UsdShade as UsdShade
|
||||
import textwrap
|
||||
|
||||
|
||||
class USDHookExample(bpy.types.USDHook):
|
||||
|
|
|
@ -102,7 +102,8 @@ GHOST_DropTargetX11::~GHOST_DropTargetX11()
|
|||
char *GHOST_DropTargetX11::FileUrlDecode(const char *fileUrl)
|
||||
{
|
||||
if (strncmp(fileUrl, "file://", 7) == 0) {
|
||||
return GHOST_URL_decode_alloc(fileUrl + 7);
|
||||
const char *file = fileUrl + 7;
|
||||
return GHOST_URL_decode_alloc(file, strlen(file));
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#include "GHOST_Debug.hh"
|
||||
#include "GHOST_PathUtils.hh"
|
||||
#include "GHOST_Types.h"
|
||||
|
||||
|
@ -24,9 +25,10 @@ using DecodeState_e = enum DecodeState_e {
|
|||
STATE_CONVERTING
|
||||
};
|
||||
|
||||
void GHOST_URL_decode(char *buf_dst, int buf_dst_size, const char *buf_src)
|
||||
void GHOST_URL_decode(char *buf_dst, int buf_dst_size, const char *buf_src, const int buf_src_len)
|
||||
{
|
||||
const uint buf_src_len = strlen(buf_src);
|
||||
GHOST_ASSERT(strnlen(buf_src, buf_src_len) == buf_src_len, "Incorrect length");
|
||||
|
||||
DecodeState_e state = STATE_SEARCH;
|
||||
uint ascii_character;
|
||||
|
||||
|
@ -85,12 +87,12 @@ void GHOST_URL_decode(char *buf_dst, int buf_dst_size, const char *buf_src)
|
|||
}
|
||||
}
|
||||
|
||||
char *GHOST_URL_decode_alloc(const char *buf_src)
|
||||
char *GHOST_URL_decode_alloc(const char *buf_src, const int buf_src_len)
|
||||
{
|
||||
/* Assume one character of encoded URL can be expanded to 4 chars max. */
|
||||
const size_t decoded_size_max = 4 * strlen(buf_src) + 1;
|
||||
const size_t decoded_size_max = 4 * buf_src_len + 1;
|
||||
char *buf_dst = (char *)malloc(decoded_size_max);
|
||||
GHOST_URL_decode(buf_dst, decoded_size_max, buf_src);
|
||||
GHOST_URL_decode(buf_dst, decoded_size_max, buf_src, buf_src_len);
|
||||
const size_t decoded_size = strlen(buf_dst) + 1;
|
||||
if (decoded_size != decoded_size_max) {
|
||||
char *buf_dst_trim = (char *)malloc(decoded_size);
|
||||
|
|
|
@ -14,12 +14,13 @@
|
|||
* \param buf_dst: Buffer for decoded URL.
|
||||
* \param buf_dst_maxlen: Size of output buffer.
|
||||
* \param buf_src: Input encoded buffer to be decoded.
|
||||
* \param buf_src_len: The length of `buf_src` to use.
|
||||
*/
|
||||
void GHOST_URL_decode(char *buf_dst, int buf_dst_size, const char *buf_src);
|
||||
void GHOST_URL_decode(char *buf_dst, int buf_dst_size, const char *buf_src, int buf_src_len);
|
||||
/**
|
||||
* A version of #GHOST_URL_decode that allocates the string & returns it.
|
||||
*
|
||||
* \param buf_src: Input encoded buffer to be decoded.
|
||||
* \return The decoded output buffer.
|
||||
*/
|
||||
char *GHOST_URL_decode_alloc(const char *buf_src);
|
||||
char *GHOST_URL_decode_alloc(const char *buf_src, int buf_src_len);
|
||||
|
|
|
@ -2926,6 +2926,9 @@ static char *read_buffer_from_data_offer(GWL_DataOffer *data_offer,
|
|||
}
|
||||
close(pipefd[0]);
|
||||
}
|
||||
else {
|
||||
*r_len = 0;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
@ -3259,20 +3262,19 @@ static void data_device_handle_drop(void *data, wl_data_device * /*wl_data_devic
|
|||
|
||||
CLOG_INFO(LOG, 2, "drop mime_recieve=%s", mime_receive);
|
||||
|
||||
auto read_uris_fn = [](GWL_Seat *const seat,
|
||||
GWL_DataOffer *data_offer,
|
||||
wl_surface *wl_surface_window,
|
||||
const char *mime_receive) {
|
||||
auto read_drop_data_fn = [](GWL_Seat *const seat,
|
||||
GWL_DataOffer *data_offer,
|
||||
wl_surface *wl_surface_window,
|
||||
const char *mime_receive) {
|
||||
const uint64_t event_ms = seat->system->getMilliSeconds();
|
||||
const wl_fixed_t xy[2] = {UNPACK2(data_offer->dnd.xy)};
|
||||
|
||||
const bool nil_terminate = (mime_receive != ghost_wl_mime_text_uri);
|
||||
size_t data_buf_len = 0;
|
||||
const char *data_buf = read_buffer_from_data_offer(
|
||||
data_offer, mime_receive, nullptr, false, &data_buf_len);
|
||||
std::string data = data_buf ? std::string(data_buf, data_buf_len) : "";
|
||||
free(const_cast<char *>(data_buf));
|
||||
data_offer, mime_receive, nullptr, nil_terminate, &data_buf_len);
|
||||
|
||||
CLOG_INFO(LOG, 2, "drop_read_uris mime_receive=%s, data=%s", mime_receive, data.c_str());
|
||||
CLOG_INFO(LOG, 2, "read_drop_data mime_receive=%s, data_len=%zu", mime_receive, data_buf_len);
|
||||
|
||||
wl_data_offer_finish(data_offer->wl.id);
|
||||
wl_data_offer_destroy(data_offer->wl.id);
|
||||
|
@ -3283,69 +3285,97 @@ static void data_device_handle_drop(void *data, wl_data_device * /*wl_data_devic
|
|||
delete data_offer;
|
||||
data_offer = nullptr;
|
||||
|
||||
GHOST_SystemWayland *const system = seat->system;
|
||||
/* Don't generate a drop event if the data could not be read,
|
||||
* an error will have been logged. */
|
||||
if (data_buf != nullptr) {
|
||||
GHOST_TDragnDropTypes ghost_dnd_type = GHOST_kDragnDropTypeUnknown;
|
||||
void *ghost_dnd_data = nullptr;
|
||||
|
||||
if (mime_receive == ghost_wl_mime_text_uri) {
|
||||
const char file_proto[] = "file://";
|
||||
/* NOTE: some applications CRLF (`\r\n`) GTK3 for e.g. & others don't `pcmanfm-qt`.
|
||||
* So support both, once `\n` is found, strip the preceding `\r` if found. */
|
||||
const char lf = '\n';
|
||||
/* Failure to receive drop data . */
|
||||
if (mime_receive == ghost_wl_mime_text_uri) {
|
||||
const char file_proto[] = "file://";
|
||||
/* NOTE: some applications CRLF (`\r\n`) GTK3 for e.g. & others don't `pcmanfm-qt`.
|
||||
* So support both, once `\n` is found, strip the preceding `\r` if found. */
|
||||
const char lf = '\n';
|
||||
|
||||
GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_window);
|
||||
std::vector<std::string> uris;
|
||||
const std::string_view data = std::string_view(data_buf, data_buf_len);
|
||||
std::vector<std::string_view> uris;
|
||||
|
||||
size_t pos = 0;
|
||||
while (pos != std::string::npos) {
|
||||
pos = data.find(file_proto, pos);
|
||||
if (pos == std::string::npos) {
|
||||
break;
|
||||
size_t pos = 0;
|
||||
while (pos != std::string::npos) {
|
||||
pos = data.find(file_proto, pos);
|
||||
if (pos == std::string::npos) {
|
||||
break;
|
||||
}
|
||||
const size_t start = pos + sizeof(file_proto) - 1;
|
||||
pos = data.find(lf, pos);
|
||||
|
||||
size_t end = pos;
|
||||
if (UNLIKELY(end == std::string::npos)) {
|
||||
/* Note that most well behaved file managers will add a trailing newline,
|
||||
* Gnome's web browser (44.3) doesn't, so support reading up until the last byte. */
|
||||
end = data.size();
|
||||
}
|
||||
/* Account for 'CRLF' case. */
|
||||
if (data[end - 1] == '\r') {
|
||||
end -= 1;
|
||||
}
|
||||
|
||||
std::string_view data_substr = data.substr(start, end - start);
|
||||
uris.push_back(data_substr);
|
||||
CLOG_INFO(LOG,
|
||||
2,
|
||||
"read_drop_data pos=%zu, text_uri=\"%.*s\"",
|
||||
start,
|
||||
int(data_substr.size()),
|
||||
data_substr.data());
|
||||
}
|
||||
const size_t start = pos + sizeof(file_proto) - 1;
|
||||
pos = data.find(lf, pos);
|
||||
|
||||
size_t end = pos;
|
||||
if (UNLIKELY(end == std::string::npos)) {
|
||||
/* Note that most well behaved file managers will add a trailing newline,
|
||||
* Gnome's web browser (44.3) doesn't, so support reading up until the last byte. */
|
||||
end = data.size();
|
||||
GHOST_TStringArray *flist = static_cast<GHOST_TStringArray *>(
|
||||
malloc(sizeof(GHOST_TStringArray)));
|
||||
flist->count = int(uris.size());
|
||||
flist->strings = static_cast<uint8_t **>(malloc(uris.size() * sizeof(uint8_t *)));
|
||||
for (size_t i = 0; i < uris.size(); i++) {
|
||||
flist->strings[i] = reinterpret_cast<uint8_t *>(
|
||||
GHOST_URL_decode_alloc(uris[i].data(), uris[i].size()));
|
||||
}
|
||||
/* Account for 'CRLF' case. */
|
||||
if (data[end - 1] == '\r') {
|
||||
end -= 1;
|
||||
}
|
||||
uris.push_back(data.substr(start, end - start));
|
||||
CLOG_INFO(LOG, 2, "drop_read_uris pos=%zu, text_uri=\"%s\"", start, uris.back().c_str());
|
||||
|
||||
CLOG_INFO(LOG, 2, "read_drop_data file_count=%d", flist->count);
|
||||
ghost_dnd_type = GHOST_kDragnDropTypeFilenames;
|
||||
ghost_dnd_data = flist;
|
||||
}
|
||||
else if (ELEM(mime_receive, ghost_wl_mime_text_plain, ghost_wl_mime_text_utf8)) {
|
||||
ghost_dnd_type = GHOST_kDragnDropTypeString;
|
||||
ghost_dnd_data = (void *)data_buf; /* Move ownership to the event. */
|
||||
data_buf = nullptr;
|
||||
}
|
||||
|
||||
GHOST_TStringArray *flist = static_cast<GHOST_TStringArray *>(
|
||||
malloc(sizeof(GHOST_TStringArray)));
|
||||
flist->count = int(uris.size());
|
||||
flist->strings = static_cast<uint8_t **>(malloc(uris.size() * sizeof(uint8_t *)));
|
||||
for (size_t i = 0; i < uris.size(); i++) {
|
||||
flist->strings[i] = reinterpret_cast<uint8_t *>(GHOST_URL_decode_alloc(uris[i].c_str()));
|
||||
if (ghost_dnd_type != GHOST_kDragnDropTypeUnknown) {
|
||||
GHOST_SystemWayland *const system = seat->system;
|
||||
GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_window);
|
||||
const int event_xy[2] = {WL_FIXED_TO_INT_FOR_WINDOW_V2(win, xy)};
|
||||
|
||||
system->pushEvent_maybe_pending(new GHOST_EventDragnDrop(event_ms,
|
||||
GHOST_kEventDraggingDropDone,
|
||||
ghost_dnd_type,
|
||||
win,
|
||||
UNPACK2(event_xy),
|
||||
ghost_dnd_data));
|
||||
|
||||
wl_display_roundtrip(system->wl_display_get());
|
||||
}
|
||||
else {
|
||||
CLOG_INFO(LOG, 2, "read_drop_data, unhandled!");
|
||||
}
|
||||
|
||||
CLOG_INFO(LOG, 2, "drop_read_uris_fn file_count=%d", flist->count);
|
||||
const int event_xy[2] = {WL_FIXED_TO_INT_FOR_WINDOW_V2(win, xy)};
|
||||
system->pushEvent_maybe_pending(new GHOST_EventDragnDrop(event_ms,
|
||||
GHOST_kEventDraggingDropDone,
|
||||
GHOST_kDragnDropTypeFilenames,
|
||||
win,
|
||||
UNPACK2(event_xy),
|
||||
flist));
|
||||
free(const_cast<char *>(data_buf));
|
||||
}
|
||||
else if (ELEM(mime_receive, ghost_wl_mime_text_plain, ghost_wl_mime_text_utf8)) {
|
||||
/* TODO: enable use of internal functions 'txt_insert_buf' and
|
||||
* 'text_update_edited' to behave like dropped text was pasted. */
|
||||
CLOG_INFO(LOG, 2, "drop_read_uris_fn (text_plain, text_utf8), unhandled!");
|
||||
}
|
||||
wl_display_roundtrip(system->wl_display_get());
|
||||
};
|
||||
|
||||
/* Pass in `seat->wl_surface_window_focus_dnd` instead of accessing it from `seat` since the
|
||||
* leave callback (#data_device_handle_leave) will clear the value once this function starts. */
|
||||
std::thread read_thread(
|
||||
read_uris_fn, seat, data_offer, seat->wl.surface_window_focus_dnd, mime_receive);
|
||||
read_drop_data_fn, seat, data_offer, seat->wl.surface_window_focus_dnd, mime_receive);
|
||||
read_thread.detach();
|
||||
}
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ class MotionPathButtonsPanel:
|
|||
col.prop(mps, "frame_step", text="Step")
|
||||
|
||||
row = col.row()
|
||||
row.prop(mps, "bake_in_camera_space", text="Bake to Active Camera")
|
||||
row.prop(mps, "use_camera_space_bake", text="Bake to Active Camera")
|
||||
|
||||
if bones:
|
||||
op_category = "pose"
|
||||
|
|
|
@ -48,8 +48,13 @@ class GREASE_PENCIL_MT_grease_pencil_add_layer_extra(Menu):
|
|||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
space = context.space_data
|
||||
if space.type == 'PROPERTIES':
|
||||
layout.operator("grease_pencil.layer_group_add", text="Add Group")
|
||||
|
||||
layout.operator("grease_pencil.layer_group_add", text="Add Group")
|
||||
layout.separator()
|
||||
layout.operator("grease_pencil.layer_duplicate", text="Duplicate", icon='DUPLICATE')
|
||||
layout.operator("grease_pencil.layer_duplicate", text="Duplicate Empty Keyframes").empty_keyframes = True
|
||||
|
||||
layout.separator()
|
||||
layout.operator("grease_pencil.layer_reveal", icon='RESTRICT_VIEW_OFF', text="Show All")
|
||||
|
|
|
@ -71,7 +71,7 @@ class OBJECT_MT_modifier_add(ModifierAddMenu, Menu):
|
|||
if geometry_nodes_supported:
|
||||
self.operator_modifier_add(layout, 'NODES')
|
||||
layout.separator()
|
||||
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE', 'LATTICE'}:
|
||||
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE', 'LATTICE', 'GREASEPENCIL'}:
|
||||
layout.menu("OBJECT_MT_modifier_add_edit")
|
||||
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE', 'VOLUME', 'GREASEPENCIL'}:
|
||||
layout.menu("OBJECT_MT_modifier_add_generate")
|
||||
|
@ -107,6 +107,8 @@ class OBJECT_MT_modifier_add_edit(ModifierAddMenu, Menu):
|
|||
self.operator_modifier_add(layout, 'VERTEX_WEIGHT_EDIT')
|
||||
self.operator_modifier_add(layout, 'VERTEX_WEIGHT_MIX')
|
||||
self.operator_modifier_add(layout, 'VERTEX_WEIGHT_PROXIMITY')
|
||||
if ob_type == 'GREASEPENCIL':
|
||||
self.operator_modifier_add(layout, 'GREASE_PENCIL_VERTEX_WEIGHT_ANGLE')
|
||||
layout.template_modifier_asset_menu_items(catalog_path=self.bl_label)
|
||||
|
||||
|
||||
|
@ -150,6 +152,7 @@ class OBJECT_MT_modifier_add_generate(ModifierAddMenu, Menu):
|
|||
if ob_type == 'MESH':
|
||||
self.operator_modifier_add(layout, 'WIREFRAME')
|
||||
if ob_type == 'GREASEPENCIL':
|
||||
self.operator_modifier_add(layout, 'GREASE_PENCIL_ARRAY')
|
||||
self.operator_modifier_add(layout, 'GREASE_PENCIL_DASH')
|
||||
self.operator_modifier_add(layout, 'GREASE_PENCIL_LENGTH')
|
||||
self.operator_modifier_add(layout, 'GREASE_PENCIL_MIRROR')
|
||||
|
|
|
@ -159,7 +159,7 @@ class GRAPH_MT_view(Menu):
|
|||
layout.prop(st, "use_realtime_update")
|
||||
layout.prop(st, "show_sliders")
|
||||
layout.prop(st, "use_auto_merge_keyframes")
|
||||
layout.prop(st, "autolock_translation_axis")
|
||||
layout.prop(st, "use_auto_lock_translation_axis")
|
||||
layout.separator()
|
||||
|
||||
if st.mode != 'DRIVERS':
|
||||
|
|
|
@ -39,7 +39,7 @@ class AssetRepresentation {
|
|||
*/
|
||||
const bool is_local_id_ = false;
|
||||
/** Asset library that owns this asset representation. */
|
||||
const AssetLibrary *owner_asset_library_;
|
||||
const AssetLibrary &owner_asset_library_;
|
||||
|
||||
struct ExternalAsset {
|
||||
std::string name;
|
||||
|
@ -67,16 +67,12 @@ class AssetRepresentation {
|
|||
AssetRepresentation(AssetIdentifier &&identifier,
|
||||
ID &id,
|
||||
const AssetLibrary &owner_asset_library);
|
||||
AssetRepresentation(AssetRepresentation &&other);
|
||||
/* Non-copyable type. */
|
||||
AssetRepresentation(const AssetRepresentation &other) = delete;
|
||||
~AssetRepresentation();
|
||||
|
||||
/* Non-move-assignable type. Move construction is fine, but treat the "identity" (e.g. local vs
|
||||
* external asset) of an asset representation as immutable. */
|
||||
AssetRepresentation &operator=(AssetRepresentation &&other) = delete;
|
||||
/* Non-copyable type. */
|
||||
AssetRepresentation &operator=(const AssetRepresentation &other) = delete;
|
||||
AssetRepresentation(const AssetRepresentation &) = delete;
|
||||
AssetRepresentation(AssetRepresentation &&) = delete;
|
||||
AssetRepresentation &operator=(AssetRepresentation &&) = delete;
|
||||
AssetRepresentation &operator=(const AssetRepresentation &) = delete;
|
||||
|
||||
const AssetIdentifier &get_identifier() const;
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
|
||||
#include "DNA_ID.h"
|
||||
#include "DNA_asset_types.h"
|
||||
#include "DNA_userdef_types.h"
|
||||
|
||||
#include "AS_asset_identifier.hh"
|
||||
#include "AS_asset_library.hh"
|
||||
|
@ -25,7 +24,7 @@ AssetRepresentation::AssetRepresentation(AssetIdentifier &&identifier,
|
|||
const AssetLibrary &owner_asset_library)
|
||||
: identifier_(identifier),
|
||||
is_local_id_(false),
|
||||
owner_asset_library_(&owner_asset_library),
|
||||
owner_asset_library_(owner_asset_library),
|
||||
external_asset_()
|
||||
{
|
||||
external_asset_.name = name;
|
||||
|
@ -38,7 +37,7 @@ AssetRepresentation::AssetRepresentation(AssetIdentifier &&identifier,
|
|||
const AssetLibrary &owner_asset_library)
|
||||
: identifier_(identifier),
|
||||
is_local_id_(true),
|
||||
owner_asset_library_(&owner_asset_library),
|
||||
owner_asset_library_(owner_asset_library),
|
||||
local_asset_id_(&id)
|
||||
{
|
||||
if (!id.asset_data) {
|
||||
|
@ -46,18 +45,6 @@ AssetRepresentation::AssetRepresentation(AssetIdentifier &&identifier,
|
|||
}
|
||||
}
|
||||
|
||||
AssetRepresentation::AssetRepresentation(AssetRepresentation &&other)
|
||||
: identifier_(std::move(other.identifier_)), is_local_id_(other.is_local_id_)
|
||||
{
|
||||
if (is_local_id_) {
|
||||
local_asset_id_ = other.local_asset_id_;
|
||||
other.local_asset_id_ = nullptr;
|
||||
}
|
||||
else {
|
||||
external_asset_ = std::move(other.external_asset_);
|
||||
}
|
||||
}
|
||||
|
||||
AssetRepresentation::~AssetRepresentation()
|
||||
{
|
||||
if (!is_local_id_) {
|
||||
|
@ -72,11 +59,7 @@ const AssetIdentifier &AssetRepresentation::get_identifier() const
|
|||
|
||||
AssetWeakReference *AssetRepresentation::make_weak_reference() const
|
||||
{
|
||||
if (!owner_asset_library_) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return AssetWeakReference::make_reference(*owner_asset_library_, identifier_);
|
||||
return AssetWeakReference::make_reference(owner_asset_library_, identifier_);
|
||||
}
|
||||
|
||||
StringRefNull AssetRepresentation::get_name() const
|
||||
|
@ -104,26 +87,20 @@ AssetMetaData &AssetRepresentation::get_metadata() const
|
|||
|
||||
std::optional<eAssetImportMethod> AssetRepresentation::get_import_method() const
|
||||
{
|
||||
if (!owner_asset_library_) {
|
||||
return {};
|
||||
}
|
||||
return owner_asset_library_->import_method_;
|
||||
return owner_asset_library_.import_method_;
|
||||
}
|
||||
|
||||
bool AssetRepresentation::may_override_import_method() const
|
||||
{
|
||||
if (!owner_asset_library_ || !owner_asset_library_->import_method_) {
|
||||
if (!owner_asset_library_.import_method_) {
|
||||
return true;
|
||||
}
|
||||
return owner_asset_library_->may_override_import_method_;
|
||||
return owner_asset_library_.may_override_import_method_;
|
||||
}
|
||||
|
||||
bool AssetRepresentation::get_use_relative_path() const
|
||||
{
|
||||
if (!owner_asset_library_) {
|
||||
return false;
|
||||
}
|
||||
return owner_asset_library_->use_relative_path_;
|
||||
return owner_asset_library_.use_relative_path_;
|
||||
}
|
||||
|
||||
ID *AssetRepresentation::local_id() const
|
||||
|
@ -138,7 +115,7 @@ bool AssetRepresentation::is_local_id() const
|
|||
|
||||
const AssetLibrary &AssetRepresentation::owner_asset_library() const
|
||||
{
|
||||
return *owner_asset_library_;
|
||||
return owner_asset_library_;
|
||||
}
|
||||
|
||||
} // namespace blender::asset_system
|
||||
|
|
|
@ -45,7 +45,7 @@ struct DupliObject {
|
|||
float mat[4][4];
|
||||
float orco[3], uv[2];
|
||||
|
||||
short type; /* from Object.transflag */
|
||||
short type; /* From #Object::transflag. */
|
||||
char no_draw;
|
||||
/* If this dupli object is belongs to a preview, this is non-null. */
|
||||
const blender::bke::GeometrySet *preview_base_geometry;
|
||||
|
|
|
@ -729,7 +729,9 @@ namespace convert {
|
|||
void legacy_gpencil_frame_to_grease_pencil_drawing(const bGPDframe &gpf,
|
||||
const ListBase &vertex_group_names,
|
||||
GreasePencilDrawing &r_drawing);
|
||||
void legacy_gpencil_to_grease_pencil(Main &main, GreasePencil &grease_pencil, bGPdata &gpd);
|
||||
void legacy_gpencil_to_grease_pencil(Main &bmain, GreasePencil &grease_pencil, bGPdata &gpd);
|
||||
|
||||
void legacy_gpencil_object(Main &bmain, Object &object);
|
||||
|
||||
} // namespace convert
|
||||
} // namespace greasepencil
|
||||
|
|
|
@ -74,7 +74,7 @@ void BKE_ffmpeg_context_free(void *context_v);
|
|||
void BKE_ffmpeg_exit();
|
||||
|
||||
/**
|
||||
* Gets a libswscale context for given size and format parameters.
|
||||
* Gets a `libswscale` context for given size and format parameters.
|
||||
* After you're done using the context, call #BKE_ffmpeg_sws_release_context
|
||||
* to release it. Internally the contexts are coming from the context
|
||||
* pool/cache.
|
||||
|
|
|
@ -367,6 +367,11 @@ void BKE_blender_userdef_app_template_data_swap(UserDef *userdef_a, UserDef *use
|
|||
* - various minor settings (add as needed).
|
||||
*/
|
||||
|
||||
#define VALUE_SWAP(id) \
|
||||
{ \
|
||||
std::swap(userdef_a->id, userdef_b->id); \
|
||||
}
|
||||
|
||||
#define DATA_SWAP(id) \
|
||||
{ \
|
||||
UserDef userdef_tmp; \
|
||||
|
@ -387,12 +392,12 @@ void BKE_blender_userdef_app_template_data_swap(UserDef *userdef_a, UserDef *use
|
|||
} \
|
||||
((void)0)
|
||||
|
||||
std::swap(userdef_a->uistyles, userdef_b->uistyles);
|
||||
std::swap(userdef_a->uifonts, userdef_b->uifonts);
|
||||
std::swap(userdef_a->themes, userdef_b->themes);
|
||||
std::swap(userdef_a->addons, userdef_b->addons);
|
||||
std::swap(userdef_a->user_keymaps, userdef_b->user_keymaps);
|
||||
std::swap(userdef_a->user_keyconfig_prefs, userdef_b->user_keyconfig_prefs);
|
||||
VALUE_SWAP(uistyles);
|
||||
VALUE_SWAP(uifonts);
|
||||
VALUE_SWAP(themes);
|
||||
VALUE_SWAP(addons);
|
||||
VALUE_SWAP(user_keymaps);
|
||||
VALUE_SWAP(user_keyconfig_prefs);
|
||||
|
||||
DATA_SWAP(font_path_ui);
|
||||
DATA_SWAP(font_path_ui_mono);
|
||||
|
@ -406,9 +411,8 @@ void BKE_blender_userdef_app_template_data_swap(UserDef *userdef_a, UserDef *use
|
|||
|
||||
DATA_SWAP(ui_scale);
|
||||
|
||||
#undef SWAP_TYPELESS
|
||||
#undef VALUE_SWAP
|
||||
#undef DATA_SWAP
|
||||
#undef LISTBASE_SWAP
|
||||
#undef FLAG_SWAP
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,9 @@
|
|||
#include "BKE_curves.hh"
|
||||
#include "BKE_deform.hh"
|
||||
#include "BKE_grease_pencil.hh"
|
||||
#include "BKE_lib_id.hh"
|
||||
#include "BKE_material.h"
|
||||
#include "BKE_object.hh"
|
||||
|
||||
#include "BLI_color.hh"
|
||||
#include "BLI_listbase.h"
|
||||
|
@ -75,13 +77,23 @@ void legacy_gpencil_frame_to_grease_pencil_drawing(const bGPDframe &gpf,
|
|||
|
||||
/* Get the number of points, number of strokes and the offsets for each stroke. */
|
||||
Vector<int> offsets;
|
||||
Vector<int8_t> curve_types;
|
||||
offsets.append(0);
|
||||
int num_strokes = 0;
|
||||
int num_points = 0;
|
||||
bool has_bezier_stroke = false;
|
||||
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf.strokes) {
|
||||
num_points += gps->totpoints;
|
||||
offsets.append(num_points);
|
||||
if (gps->editcurve != nullptr) {
|
||||
has_bezier_stroke = true;
|
||||
num_points += gps->editcurve->tot_curve_points;
|
||||
curve_types.append(CURVE_TYPE_BEZIER);
|
||||
}
|
||||
else {
|
||||
num_points += gps->totpoints;
|
||||
curve_types.append(CURVE_TYPE_POLY);
|
||||
}
|
||||
num_strokes++;
|
||||
offsets.append(num_points);
|
||||
}
|
||||
|
||||
/* Resize the CurvesGeometry. */
|
||||
|
@ -94,8 +106,14 @@ void legacy_gpencil_frame_to_grease_pencil_drawing(const bGPDframe &gpf,
|
|||
OffsetIndices<int> points_by_curve = curves.points_by_curve();
|
||||
MutableAttributeAccessor attributes = curves.attributes_for_write();
|
||||
|
||||
/* All strokes are poly curves. */
|
||||
curves.fill_curve_types(CURVE_TYPE_POLY);
|
||||
if (!has_bezier_stroke) {
|
||||
/* All strokes are poly curves. */
|
||||
curves.fill_curve_types(CURVE_TYPE_POLY);
|
||||
}
|
||||
else {
|
||||
curves.curve_types_for_write().copy_from(curve_types);
|
||||
curves.update_curve_types();
|
||||
}
|
||||
|
||||
/* Find used vertex groups in this drawing. */
|
||||
ListBase stroke_vertex_group_names;
|
||||
|
@ -118,6 +136,12 @@ void legacy_gpencil_frame_to_grease_pencil_drawing(const bGPDframe &gpf,
|
|||
|
||||
/* Point Attributes. */
|
||||
MutableSpan<float3> positions = curves.positions_for_write();
|
||||
MutableSpan<float3> handle_positions_left = has_bezier_stroke ?
|
||||
curves.handle_positions_left_for_write() :
|
||||
MutableSpan<float3>();
|
||||
MutableSpan<float3> handle_positions_right = has_bezier_stroke ?
|
||||
curves.handle_positions_right_for_write() :
|
||||
MutableSpan<float3>();
|
||||
MutableSpan<float> radii = drawing.radii_for_write();
|
||||
MutableSpan<float> opacities = drawing.opacities_for_write();
|
||||
SpanAttributeWriter<float> delta_times = attributes.lookup_or_add_for_write_span<float>(
|
||||
|
@ -158,9 +182,6 @@ void legacy_gpencil_frame_to_grease_pencil_drawing(const bGPDframe &gpf,
|
|||
|
||||
int stroke_i = 0;
|
||||
LISTBASE_FOREACH_INDEX (bGPDstroke *, gps, &gpf.strokes, stroke_i) {
|
||||
/* TODO: check if `gps->editcurve` is not nullptr and parse bezier curve instead. */
|
||||
|
||||
/* Write curve attributes. */
|
||||
stroke_cyclic.span[stroke_i] = (gps->flag & GP_STROKE_CYCLIC) != 0;
|
||||
/* TODO: This should be a `double` attribute. */
|
||||
stroke_init_times.span[stroke_i] = float(gps->inittime);
|
||||
|
@ -175,59 +196,86 @@ void legacy_gpencil_frame_to_grease_pencil_drawing(const bGPDframe &gpf,
|
|||
stroke_fill_colors.span[stroke_i] = ColorGeometry4f(gps->vert_color_fill);
|
||||
stroke_materials.span[stroke_i] = gps->mat_nr;
|
||||
|
||||
/* Write point attributes. */
|
||||
IndexRange stroke_points_range = points_by_curve[stroke_i];
|
||||
if (stroke_points_range.is_empty()) {
|
||||
IndexRange points = points_by_curve[stroke_i];
|
||||
if (points.is_empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Span<bGPDspoint> stroke_points{gps->points, gps->totpoints};
|
||||
MutableSpan<float3> stroke_positions = positions.slice(stroke_points_range);
|
||||
MutableSpan<float> stroke_radii = radii.slice(stroke_points_range);
|
||||
MutableSpan<float> stroke_opacities = opacities.slice(stroke_points_range);
|
||||
MutableSpan<float> stroke_deltatimes = delta_times.span.slice(stroke_points_range);
|
||||
MutableSpan<float> stroke_rotations = rotations.span.slice(stroke_points_range);
|
||||
MutableSpan<ColorGeometry4f> stroke_vertex_colors = vertex_colors.span.slice(
|
||||
stroke_points_range);
|
||||
MutableSpan<bool> stroke_selections = selection.span.slice(stroke_points_range);
|
||||
MutableSpan<MDeformVert> stroke_dverts = use_dverts ? dverts.slice(stroke_points_range) :
|
||||
MutableSpan<MDeformVert>();
|
||||
const Span<bGPDspoint> src_points{gps->points, gps->totpoints};
|
||||
/* Previously, Grease Pencil used a radius convention where 1 `px` = 0.001 units. This `px`
|
||||
* was the brush size which would be stored in the stroke thickness and then scaled by the
|
||||
* point pressure factor. Finally, the render engine would divide this thickness value by
|
||||
* 2000 (we're going from a thickness to a radius, hence the factor of two) to convert back
|
||||
* into blender units. Store the radius now directly in blender units. This makes it
|
||||
* consistent with how hair curves handle the radius. */
|
||||
const float stroke_thickness = float(gps->thickness) / 2000.0f;
|
||||
MutableSpan<float3> dst_positions = positions.slice(points);
|
||||
MutableSpan<float3> dst_handle_positions_left = has_bezier_stroke ?
|
||||
handle_positions_left.slice(points) :
|
||||
MutableSpan<float3>();
|
||||
MutableSpan<float3> dst_handle_positions_right = has_bezier_stroke ?
|
||||
handle_positions_right.slice(points) :
|
||||
MutableSpan<float3>();
|
||||
MutableSpan<float> dst_radii = radii.slice(points);
|
||||
MutableSpan<float> dst_opacities = opacities.slice(points);
|
||||
MutableSpan<float> dst_deltatimes = delta_times.span.slice(points);
|
||||
MutableSpan<float> dst_rotations = rotations.span.slice(points);
|
||||
MutableSpan<ColorGeometry4f> dst_vertex_colors = vertex_colors.span.slice(points);
|
||||
MutableSpan<bool> dst_selection = selection.span.slice(points);
|
||||
MutableSpan<MDeformVert> dst_dverts = use_dverts ? dverts.slice(points) :
|
||||
MutableSpan<MDeformVert>();
|
||||
|
||||
/* Do first point. */
|
||||
const bGPDspoint &first_pt = stroke_points.first();
|
||||
stroke_positions.first() = float3(first_pt.x, first_pt.y, first_pt.z);
|
||||
/* Previously, Grease Pencil used a radius convention where 1 `px` = 0.001 units. This `px` was
|
||||
* the brush size which would be stored in the stroke thickness and then scaled by the point
|
||||
* pressure factor. Finally, the render engine would divide this thickness value by 2000 (we're
|
||||
* going from a thickness to a radius, hence the factor of two) to convert back into blender
|
||||
* units.
|
||||
* Store the radius now directly in blender units. This makes it consistent with how hair
|
||||
* curves handle the radius. */
|
||||
stroke_radii.first() = gps->thickness * first_pt.pressure / 2000.0f;
|
||||
stroke_opacities.first() = first_pt.strength;
|
||||
stroke_deltatimes.first() = 0;
|
||||
stroke_rotations.first() = first_pt.uv_rot;
|
||||
stroke_vertex_colors.first() = ColorGeometry4f(first_pt.vert_color);
|
||||
stroke_selections.first() = (first_pt.flag & GP_SPOINT_SELECT) != 0;
|
||||
if (use_dverts && gps->dvert) {
|
||||
copy_dvert(gps->dvert[0], stroke_dverts.first());
|
||||
if (curve_types[stroke_i] == CURVE_TYPE_POLY) {
|
||||
threading::parallel_for(src_points.index_range(), 4096, [&](const IndexRange range) {
|
||||
for (const int point_i : range) {
|
||||
const bGPDspoint &pt = src_points[point_i];
|
||||
dst_positions[point_i] = float3(pt.x, pt.y, pt.z);
|
||||
dst_radii[point_i] = stroke_thickness * pt.pressure;
|
||||
dst_opacities[point_i] = pt.strength;
|
||||
dst_rotations[point_i] = pt.uv_rot;
|
||||
dst_vertex_colors[point_i] = ColorGeometry4f(pt.vert_color);
|
||||
dst_selection[point_i] = (pt.flag & GP_SPOINT_SELECT) != 0;
|
||||
if (use_dverts && gps->dvert) {
|
||||
copy_dvert(gps->dvert[point_i], dst_dverts[point_i]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
dst_deltatimes.first() = 0;
|
||||
threading::parallel_for(
|
||||
src_points.index_range().drop_front(1), 4096, [&](const IndexRange range) {
|
||||
for (const int point_i : range) {
|
||||
const bGPDspoint &pt = src_points[point_i];
|
||||
const bGPDspoint &pt_prev = src_points[point_i - 1];
|
||||
dst_deltatimes[point_i] = pt.time - pt_prev.time;
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (curve_types[stroke_i] == CURVE_TYPE_BEZIER) {
|
||||
BLI_assert(gps->editcurve != nullptr);
|
||||
Span<bGPDcurve_point> src_curve_points{gps->editcurve->curve_points,
|
||||
gps->editcurve->tot_curve_points};
|
||||
|
||||
/* Do the rest of the points. */
|
||||
for (const int i : stroke_points.index_range().drop_back(1)) {
|
||||
const int point_i = i + 1;
|
||||
const bGPDspoint &pt_prev = stroke_points[point_i - 1];
|
||||
const bGPDspoint &pt = stroke_points[point_i];
|
||||
stroke_positions[point_i] = float3(pt.x, pt.y, pt.z);
|
||||
stroke_radii[point_i] = gps->thickness * pt.pressure / 2000.0f;
|
||||
stroke_opacities[point_i] = pt.strength;
|
||||
stroke_deltatimes[point_i] = pt.time - pt_prev.time;
|
||||
stroke_rotations[point_i] = pt.uv_rot;
|
||||
stroke_vertex_colors[point_i] = ColorGeometry4f(pt.vert_color);
|
||||
stroke_selections[point_i] = (pt.flag & GP_SPOINT_SELECT) != 0;
|
||||
if (use_dverts && gps->dvert) {
|
||||
copy_dvert(gps->dvert[point_i], stroke_dverts[point_i]);
|
||||
}
|
||||
threading::parallel_for(src_curve_points.index_range(), 4096, [&](const IndexRange range) {
|
||||
for (const int point_i : range) {
|
||||
const bGPDcurve_point &cpt = src_curve_points[point_i];
|
||||
dst_positions[point_i] = float3(cpt.bezt.vec[1]);
|
||||
dst_handle_positions_left[point_i] = float3(cpt.bezt.vec[0]);
|
||||
dst_handle_positions_right[point_i] = float3(cpt.bezt.vec[2]);
|
||||
dst_radii[point_i] = stroke_thickness * cpt.pressure;
|
||||
dst_opacities[point_i] = cpt.strength;
|
||||
dst_rotations[point_i] = cpt.uv_rot;
|
||||
dst_vertex_colors[point_i] = ColorGeometry4f(cpt.vert_color);
|
||||
dst_selection[point_i] = (cpt.flag & GP_CURVE_POINT_SELECT) != 0;
|
||||
if (use_dverts && gps->dvert) {
|
||||
copy_dvert(gps->dvert[point_i], dst_dverts[point_i]);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
/* Unknown curve type. */
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -342,4 +390,24 @@ void legacy_gpencil_to_grease_pencil(Main &bmain, GreasePencil &grease_pencil, b
|
|||
BKE_id_materials_copy(&bmain, &gpd.id, &grease_pencil.id);
|
||||
}
|
||||
|
||||
void legacy_gpencil_object(Main &bmain, Object &object)
|
||||
{
|
||||
bGPdata *gpd = static_cast<bGPdata *>(object.data);
|
||||
|
||||
GreasePencil *new_grease_pencil = static_cast<GreasePencil *>(
|
||||
BKE_id_new(&bmain, ID_GP, gpd->id.name + 2));
|
||||
object.data = new_grease_pencil;
|
||||
object.type = OB_GREASE_PENCIL;
|
||||
|
||||
/* NOTE: Could also use #BKE_id_free_us, to also free the legacy GP if not used anymore? */
|
||||
id_us_min(&gpd->id);
|
||||
/* No need to increase usercount of `new_grease_pencil`, since ID creation already set it
|
||||
* to 1. */
|
||||
|
||||
legacy_gpencil_to_grease_pencil(bmain, *new_grease_pencil, *gpd);
|
||||
|
||||
BKE_object_free_derived_caches(&object);
|
||||
BKE_object_free_modifiers(&object, 0);
|
||||
}
|
||||
|
||||
} // namespace blender::bke::greasepencil::convert
|
||||
|
|
|
@ -107,6 +107,7 @@ static void id_type_init()
|
|||
init_types_num++;
|
||||
|
||||
BLI_assert_msg(init_types_num == INDEX_ID_MAX, "Some IDTypeInfo initialization is missing");
|
||||
UNUSED_VARS_NDEBUG(init_types_num);
|
||||
|
||||
#undef INIT_TYPE
|
||||
}
|
||||
|
|
|
@ -4211,6 +4211,11 @@ void BKE_lib_override_library_validate(Main * /*bmain*/, ID *id, ReportList *rep
|
|||
if (id->override_library == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* NOTE: In code deleting liboverride data below, #BKE_lib_override_library_make_local is used
|
||||
* instead of directly calling #BKE_lib_override_library_free, because the former also handles
|
||||
* properly 'liboverride embedded' IDs, like root nodetrees, or shapekeys. */
|
||||
|
||||
if (id->override_library->reference == nullptr) {
|
||||
/* This (probably) used to be a template ID, could be linked or local, not an override. */
|
||||
BKE_reportf(reports,
|
||||
|
@ -4218,7 +4223,7 @@ void BKE_lib_override_library_validate(Main * /*bmain*/, ID *id, ReportList *rep
|
|||
"Library override templates have been removed: removing all override data from "
|
||||
"the data-block '%s'",
|
||||
id->name);
|
||||
BKE_lib_override_library_free(&id->override_library, true);
|
||||
BKE_lib_override_library_make_local(nullptr, id);
|
||||
return;
|
||||
}
|
||||
if (id->override_library->reference == id) {
|
||||
|
@ -4229,7 +4234,7 @@ void BKE_lib_override_library_validate(Main * /*bmain*/, ID *id, ReportList *rep
|
|||
"Data corruption: data-block '%s' is using itself as library override reference, "
|
||||
"removing all override data",
|
||||
id->name);
|
||||
BKE_lib_override_library_free(&id->override_library, true);
|
||||
BKE_lib_override_library_make_local(nullptr, id);
|
||||
return;
|
||||
}
|
||||
if (!ID_IS_LINKED(id->override_library->reference)) {
|
||||
|
@ -4241,7 +4246,7 @@ void BKE_lib_override_library_validate(Main * /*bmain*/, ID *id, ReportList *rep
|
|||
"library override reference, removing all override data",
|
||||
id->name,
|
||||
id->override_library->reference->name);
|
||||
BKE_lib_override_library_free(&id->override_library, true);
|
||||
BKE_lib_override_library_make_local(nullptr, id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -316,8 +316,8 @@ TEST(lib_remap, never_null_usage_storage_requested_on_delete)
|
|||
remapper,
|
||||
(ID_REMAP_SKIP_NEVER_NULL_USAGE | ID_REMAP_STORE_NEVER_NULL_USAGE));
|
||||
|
||||
/* Never null usages unassignement is not enforced (no #ID_REMAP_FORCE_NEVER_NULL_USAGE), so the
|
||||
* obdta should still use the original mesh. */
|
||||
/* Never null usages un-assignment is not enforced (no #ID_REMAP_FORCE_NEVER_NULL_USAGE),
|
||||
* so the object-data should still use the original mesh. */
|
||||
EXPECT_EQ(context.test_data.object->data, context.test_data.mesh);
|
||||
EXPECT_NE(context.test_data.object->data, nullptr);
|
||||
EXPECT_TRUE(remapper.never_null_users().contains(&context.test_data.object->id));
|
||||
|
|
|
@ -32,14 +32,14 @@ using namespace blender;
|
|||
/** \name Internal Math Functions
|
||||
* \{ */
|
||||
|
||||
static float mul_v2_v2_cw_x(const float2 &mat, const float2 &vec)
|
||||
static float sincos_rotate_cw_x(const float2 &sincos, const float2 &p)
|
||||
{
|
||||
return (mat[0] * vec[0]) + (mat[1] * vec[1]);
|
||||
return (sincos[0] * p[0]) + (sincos[1] * p[1]);
|
||||
}
|
||||
|
||||
static float mul_v2_v2_cw_y(const float2 &mat, const float2 &vec)
|
||||
static float sincos_rotate_cw_y(const float2 &sincos, const float2 &p)
|
||||
{
|
||||
return (mat[1] * vec[0]) - (mat[0] * vec[1]);
|
||||
return (sincos[1] * p[0]) - (sincos[0] * p[1]);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@ -78,21 +78,23 @@ static int convexhull_2d_sorted(const float (*points)[2], const int points_num,
|
|||
/* Array scan index. */
|
||||
int i;
|
||||
|
||||
int minmin, minmax;
|
||||
int maxmin, maxmax;
|
||||
const int minmin = 0;
|
||||
const int maxmax = points_num - 1;
|
||||
int minmax;
|
||||
int maxmin;
|
||||
|
||||
float xmax;
|
||||
|
||||
/* Get the indices of points with min X-coord and min|max Y-coord. */
|
||||
float xmin = points[0][0];
|
||||
for (i = 1; i < points_num; i++) {
|
||||
for (i = 1; i <= maxmax; i++) {
|
||||
if (points[i][0] != xmin) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
minmin = 0;
|
||||
minmax = i - 1;
|
||||
if (minmax == points_num - 1) { /* Degenerate case: all x-coords == X-min. */
|
||||
if (minmax == maxmax) { /* Degenerate case: all x-coords == X-min. */
|
||||
r_points[++top] = minmin;
|
||||
if (points[minmax][1] != points[minmin][1]) {
|
||||
/* A nontrivial segment. */
|
||||
|
@ -104,9 +106,8 @@ static int convexhull_2d_sorted(const float (*points)[2], const int points_num,
|
|||
|
||||
/* Get the indices of points with max X-coord and min|max Y-coord. */
|
||||
|
||||
maxmax = points_num - 1;
|
||||
xmax = points[points_num - 1][0];
|
||||
for (i = points_num - 2; i >= 0; i--) {
|
||||
xmax = points[maxmax][0];
|
||||
for (i = maxmax - 1; i >= 0; i--) {
|
||||
if (points[i][0] != xmax) {
|
||||
break;
|
||||
}
|
||||
|
@ -235,12 +236,12 @@ static float convexhull_aabb_fit_hull_2d_brute_force(const float (*points_hull)[
|
|||
int points_hull_num)
|
||||
{
|
||||
float area_best = FLT_MAX;
|
||||
float2 dvec_best = {0.0f, 1.0f}; /* Track the best angle as a unit vector, delaying `atan2`. */
|
||||
float2 sincos_best = {0.0f, 1.0f}; /* Track the best angle as a unit vector, delaying `atan2`. */
|
||||
|
||||
for (int i = 0, i_prev = points_hull_num - 1; i < points_hull_num; i_prev = i++) {
|
||||
/* 2D rotation matrix. */
|
||||
float dvec_length = 0.0f;
|
||||
const float2 dvec = math::normalize_and_get_length(
|
||||
const float2 sincos = math::normalize_and_get_length(
|
||||
float2(points_hull[i]) - float2(points_hull[i_prev]), dvec_length);
|
||||
if (UNLIKELY(dvec_length == 0.0f)) {
|
||||
continue;
|
||||
|
@ -251,8 +252,8 @@ static float convexhull_aabb_fit_hull_2d_brute_force(const float (*points_hull)[
|
|||
|
||||
for (int j = 0; j < points_hull_num; j++) {
|
||||
const float2 tvec = {
|
||||
mul_v2_v2_cw_x(dvec, points_hull[j]),
|
||||
mul_v2_v2_cw_y(dvec, points_hull[j]),
|
||||
sincos_rotate_cw_x(sincos, points_hull[j]),
|
||||
sincos_rotate_cw_y(sincos, points_hull[j]),
|
||||
};
|
||||
|
||||
bounds[0].min = math::min(bounds[0].min, tvec[0]);
|
||||
|
@ -268,11 +269,11 @@ static float convexhull_aabb_fit_hull_2d_brute_force(const float (*points_hull)[
|
|||
|
||||
if (area_test < area_best) {
|
||||
area_best = area_test;
|
||||
dvec_best = dvec;
|
||||
sincos_best = sincos;
|
||||
}
|
||||
}
|
||||
|
||||
return (area_best != FLT_MAX) ? float(atan2(dvec_best[0], dvec_best[1])) : 0.0f;
|
||||
return (area_best != FLT_MAX) ? float(atan2(sincos_best[0], sincos_best[1])) : 0.0f;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@ -289,7 +290,7 @@ static float convexhull_aabb_fit_hull_2d_brute_force(const float (*points_hull)[
|
|||
template<int Axis, int AxisSign>
|
||||
static float convexhull_2d_compute_extent_on_axis(const float (*points_hull)[2],
|
||||
const int points_hull_num,
|
||||
const float2 &dvec,
|
||||
const float2 &sincos,
|
||||
int *index_p)
|
||||
{
|
||||
/* NOTE(@ideasman42): This could be optimized to use a search strategy
|
||||
|
@ -306,14 +307,14 @@ static float convexhull_2d_compute_extent_on_axis(const float (*points_hull)[2],
|
|||
|
||||
const int index_init = *index_p;
|
||||
int index_best = index_init;
|
||||
float value_init = (Axis == 0) ? mul_v2_v2_cw_x(dvec, points_hull[index_best]) :
|
||||
mul_v2_v2_cw_y(dvec, points_hull[index_best]);
|
||||
float value_init = (Axis == 0) ? sincos_rotate_cw_x(sincos, points_hull[index_best]) :
|
||||
sincos_rotate_cw_y(sincos, points_hull[index_best]);
|
||||
float value_best = value_init;
|
||||
/* Simply scan up the array. */
|
||||
for (int count = 1; count < points_hull_num; count++) {
|
||||
const int index_test = (index_init + count) % points_hull_num;
|
||||
const float value_test = (Axis == 0) ? mul_v2_v2_cw_x(dvec, points_hull[index_test]) :
|
||||
mul_v2_v2_cw_y(dvec, points_hull[index_test]);
|
||||
const float value_test = (Axis == 0) ? sincos_rotate_cw_x(sincos, points_hull[index_test]) :
|
||||
sincos_rotate_cw_y(sincos, points_hull[index_test]);
|
||||
if ((AxisSign == -1) ? (value_test > value_best) : (value_test < value_best)) {
|
||||
break;
|
||||
}
|
||||
|
@ -328,7 +329,7 @@ static float convexhull_2d_compute_extent_on_axis(const float (*points_hull)[2],
|
|||
static float convexhull_aabb_fit_hull_2d(const float (*points_hull)[2], int points_hull_num)
|
||||
{
|
||||
float area_best = FLT_MAX;
|
||||
float2 dvec_best; /* Track the best angle as a unit vector, delaying `atan2`. */
|
||||
float2 sincos_best; /* Track the best angle as a unit vector, delaying `atan2`. */
|
||||
bool is_first = true;
|
||||
|
||||
/* Initialize to zero because the first pass uses the first index to set the bounds. */
|
||||
|
@ -337,7 +338,7 @@ static float convexhull_aabb_fit_hull_2d(const float (*points_hull)[2], int poin
|
|||
for (int i = 0, i_prev = points_hull_num - 1; i < points_hull_num; i_prev = i++) {
|
||||
/* 2D rotation matrix. */
|
||||
float dvec_length = 0.0f;
|
||||
const float2 dvec = math::normalize_and_get_length(
|
||||
const float2 sincos = math::normalize_and_get_length(
|
||||
float2(points_hull[i]) - float2(points_hull[i_prev]), dvec_length);
|
||||
if (UNLIKELY(dvec_length == 0.0f)) {
|
||||
continue;
|
||||
|
@ -348,16 +349,16 @@ static float convexhull_aabb_fit_hull_2d(const float (*points_hull)[2], int poin
|
|||
|
||||
blender::Bounds<float> bounds[2];
|
||||
|
||||
bounds[0].min = bounds[0].max = mul_v2_v2_cw_x(dvec, points_hull[0]);
|
||||
bounds[1].min = bounds[1].max = mul_v2_v2_cw_y(dvec, points_hull[0]);
|
||||
bounds[0].min = bounds[0].max = sincos_rotate_cw_x(sincos, points_hull[0]);
|
||||
bounds[1].min = bounds[1].max = sincos_rotate_cw_y(sincos, points_hull[0]);
|
||||
|
||||
bounds_index[0].min = bounds_index[0].max = 0;
|
||||
bounds_index[1].min = bounds_index[1].max = 0;
|
||||
|
||||
for (int j = 1; j < points_hull_num; j++) {
|
||||
const float2 tvec = {
|
||||
mul_v2_v2_cw_x(dvec, points_hull[j]),
|
||||
mul_v2_v2_cw_y(dvec, points_hull[j]),
|
||||
sincos_rotate_cw_x(sincos, points_hull[j]),
|
||||
sincos_rotate_cw_y(sincos, points_hull[j]),
|
||||
};
|
||||
for (int axis = 0; axis < 2; axis++) {
|
||||
if (tvec[axis] < bounds[axis].min) {
|
||||
|
@ -372,20 +373,20 @@ static float convexhull_aabb_fit_hull_2d(const float (*points_hull)[2], int poin
|
|||
}
|
||||
|
||||
area_best = (bounds[0].max - bounds[0].min) * (bounds[1].max - bounds[1].min);
|
||||
dvec_best = dvec;
|
||||
sincos_best = sincos;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Step the calipers to the new rotation `dvec`, returning the bounds at the same time. */
|
||||
/* Step the calipers to the new rotation `sincos`, returning the bounds at the same time. */
|
||||
blender::Bounds<float> bounds_test[2] = {
|
||||
{convexhull_2d_compute_extent_on_axis<0, -1>(
|
||||
points_hull, points_hull_num, dvec, &bounds_index[0].min),
|
||||
points_hull, points_hull_num, sincos, &bounds_index[0].min),
|
||||
convexhull_2d_compute_extent_on_axis<0, 1>(
|
||||
points_hull, points_hull_num, dvec, &bounds_index[0].max)},
|
||||
points_hull, points_hull_num, sincos, &bounds_index[0].max)},
|
||||
{convexhull_2d_compute_extent_on_axis<1, -1>(
|
||||
points_hull, points_hull_num, dvec, &bounds_index[1].min),
|
||||
points_hull, points_hull_num, sincos, &bounds_index[1].min),
|
||||
convexhull_2d_compute_extent_on_axis<1, 1>(
|
||||
points_hull, points_hull_num, dvec, &bounds_index[1].max)},
|
||||
points_hull, points_hull_num, sincos, &bounds_index[1].max)},
|
||||
|
||||
};
|
||||
|
||||
|
@ -394,11 +395,11 @@ static float convexhull_aabb_fit_hull_2d(const float (*points_hull)[2], int poin
|
|||
|
||||
if (area_test < area_best) {
|
||||
area_best = area_test;
|
||||
dvec_best = dvec;
|
||||
sincos_best = sincos;
|
||||
}
|
||||
}
|
||||
|
||||
const float angle = (area_best != FLT_MAX) ? float(atan2(dvec_best[0], dvec_best[1])) : 0.0f;
|
||||
const float angle = (area_best != FLT_MAX) ? float(atan2(sincos_best[0], sincos_best[1])) : 0.0f;
|
||||
|
||||
#ifdef USE_BRUTE_FORCE_ASSERT
|
||||
/* Ensure the optimized result matches the brute-force version. */
|
||||
|
|
|
@ -59,7 +59,6 @@ set(SRC
|
|||
|
||||
set(LIB
|
||||
PRIVATE bf::animrig
|
||||
PRIVATE bf::blenfont
|
||||
bf_blenkernel
|
||||
PRIVATE bf::blenlib
|
||||
PRIVATE bf::depsgraph
|
||||
|
@ -118,6 +117,7 @@ if(WITH_GTESTS)
|
|||
)
|
||||
set(TEST_UTIL_LIB
|
||||
${LIB}
|
||||
PRIVATE bf::blenfont
|
||||
bf_blenloader
|
||||
)
|
||||
blender_add_lib(bf_blenloader_test_util "${TEST_UTIL_SRC}" "${TEST_UTIL_INC}" "${TEST_UTIL_INC_SYS}" "${TEST_UTIL_LIB}")
|
||||
|
|
|
@ -31,10 +31,7 @@ void Profiler::add_operation_execution_time(const NodeOperation &operation,
|
|||
void Profiler::add_execution_time(const bNodeInstanceKey key,
|
||||
const timeit::Nanoseconds &execution_time)
|
||||
{
|
||||
data_.per_node_execution_time.add_or_modify(
|
||||
key,
|
||||
[&](timeit::Nanoseconds *total_execution_time) { *total_execution_time = execution_time; },
|
||||
[&](timeit::Nanoseconds *total_execution_time) { *total_execution_time += execution_time; });
|
||||
data_.per_node_execution_time.lookup_or_add(key, timeit::Nanoseconds(0)) += execution_time;
|
||||
}
|
||||
|
||||
void Profiler::finalize(const bNodeTree &node_tree)
|
||||
|
|
|
@ -147,6 +147,19 @@ static void add_meta_data_for_input(realtime_compositor::FileOutput &file_output
|
|||
|
||||
void FileOutputOperation::deinit_execution()
|
||||
{
|
||||
/* It is possible that none of the inputs would have an image connected, which will materialize
|
||||
* as a size of zero, so check this here and return early doing nothing. Just make sure to free
|
||||
* the allocated buffers. */
|
||||
const int2 size = int2(get_width(), get_height());
|
||||
if (size == int2(0)) {
|
||||
for (const FileOutputInput &input : file_output_inputs_) {
|
||||
if (input.output_buffer) {
|
||||
MEM_freeN(input.output_buffer);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_multi_layer()) {
|
||||
execute_multi_layer();
|
||||
}
|
||||
|
|
|
@ -134,51 +134,34 @@ void TextureBaseOperation::update_memory_buffer_partial(MemoryBuffer *output,
|
|||
const rcti &area,
|
||||
Span<MemoryBuffer *> inputs)
|
||||
{
|
||||
const int op_width = this->get_width();
|
||||
const int op_height = this->get_height();
|
||||
const float center_x = op_width / 2;
|
||||
const float center_y = op_height / 2;
|
||||
TexResult tex_result = {0};
|
||||
float vec[3];
|
||||
const int thread_id = WorkScheduler::current_thread_id();
|
||||
const float3 offset = inputs[0]->get_elem(0, 0);
|
||||
const float3 scale = inputs[1]->get_elem(0, 0);
|
||||
const int2 size = int2(this->get_width(), this->get_height());
|
||||
for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
|
||||
const float *tex_offset = it.in(0);
|
||||
const float *tex_size = it.in(1);
|
||||
float u = (it.x - center_x) / op_width * 2;
|
||||
float v = (it.y - center_y) / op_height * 2;
|
||||
/* Compute the coordinates in the [-1, 1] range and add 0.5 to evaluate the texture at the
|
||||
* center of pixels in case it was interpolated. */
|
||||
const float2 pixel_coordinates = ((float2(it.x, it.y) + 0.5f) / float2(size)) * 2.0f - 1.0f;
|
||||
/* Note that it is expected that the offset is scaled by the scale. */
|
||||
const float3 coordinates = (float3(pixel_coordinates, 0.0f) + offset) * scale;
|
||||
|
||||
/* When no interpolation/filtering happens in multitex() force nearest interpolation.
|
||||
* We do it here because (a) we can't easily say multitex() that we want nearest
|
||||
* interpolation and (b) in such configuration multitex() simply floor's the value
|
||||
* which often produces artifacts.
|
||||
*/
|
||||
if (texture_ != nullptr && (texture_->imaflag & TEX_INTERPOL) == 0) {
|
||||
u += 0.5f / center_x;
|
||||
v += 0.5f / center_y;
|
||||
}
|
||||
|
||||
vec[0] = tex_size[0] * (u + tex_offset[0]);
|
||||
vec[1] = tex_size[1] * (v + tex_offset[1]);
|
||||
vec[2] = tex_size[2] * tex_offset[2];
|
||||
|
||||
const int retval = multitex_ext(texture_,
|
||||
vec,
|
||||
nullptr,
|
||||
nullptr,
|
||||
0,
|
||||
&tex_result,
|
||||
thread_id,
|
||||
pool_,
|
||||
scene_color_manage_,
|
||||
false);
|
||||
|
||||
it.out[3] = tex_result.talpha ? tex_result.trgba[3] : tex_result.tin;
|
||||
if (retval & TEX_RGB) {
|
||||
copy_v3_v3(it.out, tex_result.trgba);
|
||||
}
|
||||
else {
|
||||
it.out[0] = it.out[1] = it.out[2] = it.out[3];
|
||||
TexResult texture_result;
|
||||
const int result_type = multitex_ext(texture_,
|
||||
coordinates,
|
||||
nullptr,
|
||||
nullptr,
|
||||
0,
|
||||
&texture_result,
|
||||
WorkScheduler::current_thread_id(),
|
||||
pool_,
|
||||
scene_color_manage_,
|
||||
false);
|
||||
|
||||
float4 color = float4(texture_result.trgba);
|
||||
color.w = texture_result.talpha ? color.w : texture_result.tin;
|
||||
if (!(result_type & TEX_RGB)) {
|
||||
copy_v3_fl(color, color.w);
|
||||
}
|
||||
copy_v4_v4(it.out, color);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -117,6 +117,18 @@ void TranslateOperation::update_memory_buffer_partial(MemoryBuffer *output,
|
|||
return;
|
||||
}
|
||||
|
||||
/* Some compositor operations produce an empty output buffer by specifying a COM_AREA_NONE canvas
|
||||
* to indicate an invalid output, for instance, when the Mask operation reference an invalid
|
||||
* mask. The intention is that this buffer would signal that a fallback value would fill the
|
||||
* canvas of consumer operations. Since the aforementioned filling is achieved through the
|
||||
* Translate operation as part of canvas conversion in COM_convert_canvas, we handle the empty
|
||||
* buffer case here and fill the output using a fallback black color. */
|
||||
if (BLI_rcti_is_empty(&input->get_rect())) {
|
||||
const float value[4] = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||
output->fill(area, value);
|
||||
return;
|
||||
}
|
||||
|
||||
const int delta_x = this->get_delta_x();
|
||||
const int delta_y = this->get_delta_y();
|
||||
for (int y = area.ymin; y < area.ymax; y++) {
|
||||
|
|
|
@ -112,6 +112,10 @@ class Context {
|
|||
* render pipeline. */
|
||||
virtual RenderContext *render_context() const;
|
||||
|
||||
/* Returns true if the compositor evaluation is canceled and that the evaluator should stop
|
||||
* executing as soon as possible. */
|
||||
virtual bool is_canceled() const;
|
||||
|
||||
/* Get the size of the compositing region. See get_compositing_region(). The output size is
|
||||
* sanitized such that it is at least 1 in both dimensions. However, the developer is expected to
|
||||
* gracefully handled zero sizes regions by checking the is_valid_compositing_region method. */
|
||||
|
|
|
@ -5,10 +5,13 @@
|
|||
#include "BLI_math_vector.hh"
|
||||
#include "BLI_rect.h"
|
||||
|
||||
#include "DNA_node_types.h"
|
||||
#include "DNA_vec_types.h"
|
||||
|
||||
#include "GPU_shader.h"
|
||||
|
||||
#include "BKE_node_runtime.hh"
|
||||
|
||||
#include "COM_context.hh"
|
||||
#include "COM_render_context.hh"
|
||||
#include "COM_static_cache_manager.hh"
|
||||
|
@ -23,6 +26,14 @@ RenderContext *Context::render_context() const
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
bool Context::is_canceled() const
|
||||
{
|
||||
if (!this->get_node_tree().runtime->test_break) {
|
||||
return false;
|
||||
}
|
||||
return this->get_node_tree().runtime->test_break(get_node_tree().runtime->tbh);
|
||||
}
|
||||
|
||||
int2 Context::get_compositing_region_size() const
|
||||
{
|
||||
const rcti compositing_region = get_compositing_region();
|
||||
|
|
|
@ -4028,6 +4028,12 @@ static bool select_anim_channel_keys(bAnimContext *ac, int channel_index, bool e
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Only FCuves can have their keys selected. */
|
||||
if (ale->datatype != ALE_FCURVE) {
|
||||
ANIM_animdata_freelist(&anim_data);
|
||||
return false;
|
||||
}
|
||||
|
||||
fcu = (FCurve *)ale->key_data;
|
||||
success = (fcu != nullptr);
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_grease_pencil.hh"
|
||||
#include "BKE_report.hh"
|
||||
|
||||
#include "DEG_depsgraph.hh"
|
||||
|
||||
|
@ -372,7 +373,7 @@ static void GREASE_PENCIL_OT_layer_reveal(wmOperatorType *ot)
|
|||
|
||||
static int grease_pencil_layer_isolate_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
using namespace ::blender::bke::greasepencil;
|
||||
using namespace blender::bke::greasepencil;
|
||||
Object *object = CTX_data_active_object(C);
|
||||
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
|
||||
const int affect_visibility = RNA_boolean_get(op->ptr, "affect_visibility");
|
||||
|
@ -469,6 +470,60 @@ static void GREASE_PENCIL_OT_layer_lock_all(wmOperatorType *ot)
|
|||
/* properties */
|
||||
RNA_def_boolean(ot->srna, "lock", true, "Lock Value", "Lock/Unlock all layers");
|
||||
}
|
||||
|
||||
static int grease_pencil_layer_duplicate_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
using namespace ::blender::bke::greasepencil;
|
||||
Object *object = CTX_data_active_object(C);
|
||||
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
|
||||
const bool empty_keyframes = RNA_boolean_get(op->ptr, "empty_keyframes");
|
||||
|
||||
if (!grease_pencil.has_active_layer()) {
|
||||
BKE_reportf(op->reports, RPT_ERROR, "No active layer to duplicate");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
Layer &active_layer = *grease_pencil.get_active_layer();
|
||||
Layer &new_layer = grease_pencil.add_layer(active_layer.name());
|
||||
|
||||
for (auto [key, frame] : active_layer.frames().items()) {
|
||||
const int duration = frame.is_implicit_hold() ? 0 : active_layer.get_frame_duration_at(key);
|
||||
const int drawing_index = grease_pencil.drawings().size();
|
||||
GreasePencilFrame *new_frame = new_layer.add_frame(key, drawing_index, duration);
|
||||
new_frame->type = frame.type;
|
||||
if (empty_keyframes) {
|
||||
grease_pencil.add_empty_drawings(1);
|
||||
}
|
||||
else {
|
||||
const Drawing &drawing = *grease_pencil.get_drawing_at(active_layer, key);
|
||||
grease_pencil.add_duplicate_drawings(1, drawing);
|
||||
}
|
||||
}
|
||||
|
||||
grease_pencil.move_node_after(new_layer.as_node(), active_layer.as_node());
|
||||
grease_pencil.set_active_layer(&new_layer);
|
||||
DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
|
||||
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, nullptr);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static void GREASE_PENCIL_OT_layer_duplicate(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Duplicate Layer";
|
||||
ot->idname = "GREASE_PENCIL_OT_layer_duplicate";
|
||||
ot->description = "Make a copy of the active Grease Pencil layer";
|
||||
|
||||
/* callbacks */
|
||||
ot->exec = grease_pencil_layer_duplicate_exec;
|
||||
ot->poll = active_grease_pencil_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
/* properties */
|
||||
RNA_def_boolean(ot->srna, "empty_keyframes", false, "Empty Keyframes", "Add Empty Keyframes");
|
||||
}
|
||||
} // namespace blender::ed::greasepencil
|
||||
|
||||
void ED_operatortypes_grease_pencil_layers()
|
||||
|
@ -482,6 +537,7 @@ void ED_operatortypes_grease_pencil_layers()
|
|||
WM_operatortype_append(GREASE_PENCIL_OT_layer_reveal);
|
||||
WM_operatortype_append(GREASE_PENCIL_OT_layer_isolate);
|
||||
WM_operatortype_append(GREASE_PENCIL_OT_layer_lock_all);
|
||||
WM_operatortype_append(GREASE_PENCIL_OT_layer_duplicate);
|
||||
|
||||
WM_operatortype_append(GREASE_PENCIL_OT_layer_group_add);
|
||||
}
|
||||
|
|
|
@ -69,17 +69,19 @@ class StepDrawingGeometryBase {
|
|||
/* Index of this drawing in the original combined array of all drawings in GreasePencil ID. */
|
||||
int index_;
|
||||
|
||||
/* Data from #GreasePencilDrawingBase that needs to be saved in udo steps. */
|
||||
/* Data from #GreasePencilDrawingBase that needs to be saved in undo steps. */
|
||||
uint32_t flag_;
|
||||
|
||||
protected:
|
||||
/* Ensures that the drawing from the given array at the current index exists, and has the propoer
|
||||
* type.
|
||||
/**
|
||||
* Ensures that the drawing from the given array at the current index exists,
|
||||
* and has the proposer type.
|
||||
*
|
||||
* Non-existing drawings can happen after extenting the drawings array.
|
||||
* Non-existing drawings can happen after extending the drawings array.
|
||||
*
|
||||
* Mismatch in drawing types can happen when some drawings have been deleted between the undo
|
||||
* step storage, and the current state of the GreasePencil data. */
|
||||
* step storage, and the current state of the GreasePencil data.
|
||||
*/
|
||||
void decode_valid_drawingtype_at_index_ensure(MutableSpan<GreasePencilDrawingBase *> &drawings,
|
||||
const GreasePencilDrawingType drawing_type) const
|
||||
{
|
||||
|
|
|
@ -1875,10 +1875,6 @@ void UI_but_drag_set_rna(uiBut *but, PointerRNA *ptr);
|
|||
*/
|
||||
void UI_but_drag_set_path(uiBut *but, const char *path);
|
||||
void UI_but_drag_set_name(uiBut *but, const char *name);
|
||||
/**
|
||||
* Value from button itself.
|
||||
*/
|
||||
void UI_but_drag_set_value(uiBut *but);
|
||||
|
||||
/**
|
||||
* Sets #UI_BUT_DRAG_FULL_BUT so the full button can be dragged.
|
||||
|
|
|
@ -78,11 +78,6 @@ void UI_but_drag_set_name(uiBut *but, const char *name)
|
|||
but->dragpoin = (void *)name;
|
||||
}
|
||||
|
||||
void UI_but_drag_set_value(uiBut *but)
|
||||
{
|
||||
but->dragtype = WM_DRAG_VALUE;
|
||||
}
|
||||
|
||||
void UI_but_drag_set_image(uiBut *but, const char *path, int icon, const ImBuf *imb, float scale)
|
||||
{
|
||||
ui_def_but_icon(but, icon, 0); /* no flag UI_HAS_ICON, so icon doesn't draw in button */
|
||||
|
@ -108,7 +103,6 @@ void ui_but_drag_start(bContext *C, uiBut *but)
|
|||
but->icon,
|
||||
but->dragtype,
|
||||
but->dragpoin,
|
||||
ui_but_value_get(but),
|
||||
(but->dragflag & UI_BUT_DRAGPOIN_FREE) ? WM_DRAG_FREE_DATA :
|
||||
WM_DRAG_NOP);
|
||||
/* wmDrag has ownership over dragpoin now, stop messing with it. */
|
||||
|
@ -123,6 +117,6 @@ void ui_but_drag_start(bContext *C, uiBut *but)
|
|||
/* Special feature for assets: We add another drag item that supports multiple assets. It
|
||||
* gets the assets from context. */
|
||||
if (ELEM(but->dragtype, WM_DRAG_ASSET, WM_DRAG_ID)) {
|
||||
WM_event_start_drag(C, ICON_NONE, WM_DRAG_ASSET_LIST, nullptr, 0, WM_DRAG_NOP);
|
||||
WM_event_start_drag(C, ICON_NONE, WM_DRAG_ASSET_LIST, nullptr, WM_DRAG_NOP);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -414,8 +414,6 @@ struct uiHandleButtonData {
|
|||
/* coords are Window/uiBlock relative (depends on the button) */
|
||||
int draglastx, draglasty;
|
||||
int dragstartx, dragstarty;
|
||||
int draglastvalue;
|
||||
int dragstartvalue;
|
||||
bool dragchange, draglock;
|
||||
int dragsel;
|
||||
float dragf, dragfstart;
|
||||
|
@ -435,7 +433,6 @@ struct uiHandleButtonData {
|
|||
|
||||
/* Menu open, see: #UI_screen_free_active_but_highlight. */
|
||||
uiPopupBlockHandle *menu;
|
||||
int menuretval;
|
||||
|
||||
/* Search box see: #UI_screen_free_active_but_highlight. */
|
||||
ARegion *searchbox;
|
||||
|
@ -2174,7 +2171,7 @@ static bool ui_but_drag_init(bContext *C,
|
|||
}
|
||||
|
||||
if (valid) {
|
||||
WM_event_start_drag(C, ICON_COLOR, WM_DRAG_COLOR, drag_info, 0.0, WM_DRAG_FREE_DATA);
|
||||
WM_event_start_drag(C, ICON_COLOR, WM_DRAG_COLOR, drag_info, WM_DRAG_FREE_DATA);
|
||||
}
|
||||
else {
|
||||
MEM_freeN(drag_info);
|
||||
|
|
|
@ -1167,8 +1167,9 @@ static void panel_draw_aligned_backdrop(const ARegion *region,
|
|||
const rcti *rect,
|
||||
const rcti *header_rect)
|
||||
{
|
||||
const bool is_subpanel = panel->type->parent != nullptr;
|
||||
const bool is_open = !UI_panel_is_closed(panel);
|
||||
const bool is_subpanel = panel->type->parent != nullptr;
|
||||
const bool has_header = (panel->type->flag & PANEL_TYPE_NO_HEADER) == 0;
|
||||
|
||||
if (is_subpanel && !is_open) {
|
||||
return;
|
||||
|
@ -1182,10 +1183,15 @@ static void panel_draw_aligned_backdrop(const ARegion *region,
|
|||
GPU_blend(GPU_BLEND_ALPHA);
|
||||
|
||||
/* Panel backdrop. */
|
||||
if (is_open || panel->type->flag & PANEL_TYPE_NO_HEADER) {
|
||||
if (is_open || !has_header) {
|
||||
float panel_backcolor[4];
|
||||
UI_draw_roundbox_corner_set(is_open ? UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT : UI_CNR_ALL);
|
||||
UI_GetThemeColor4fv((is_subpanel ? TH_PANEL_SUB_BACK : TH_PANEL_BACK), panel_backcolor);
|
||||
if (!has_header) {
|
||||
UI_GetThemeColor4fv(TH_BACK, panel_backcolor);
|
||||
}
|
||||
else {
|
||||
UI_GetThemeColor4fv((is_subpanel ? TH_PANEL_SUB_BACK : TH_PANEL_BACK), panel_backcolor);
|
||||
}
|
||||
|
||||
rctf box_rect;
|
||||
box_rect.xmin = rect->xmin;
|
||||
|
@ -1222,7 +1228,7 @@ static void panel_draw_aligned_backdrop(const ARegion *region,
|
|||
}
|
||||
|
||||
/* Panel header backdrops for non sub-panels. */
|
||||
if (!is_subpanel) {
|
||||
if (!is_subpanel && has_header) {
|
||||
float panel_headercolor[4];
|
||||
UI_GetThemeColor4fv(UI_panel_matches_search_filter(panel) ? TH_MATCH : TH_PANEL_HEADER,
|
||||
panel_headercolor);
|
||||
|
@ -1259,7 +1265,7 @@ void ui_draw_aligned_panel(const ARegion *region,
|
|||
rect->ymax + int(floor(PNL_HEADER / block->aspect + 0.001f)),
|
||||
};
|
||||
|
||||
if (show_background) {
|
||||
if (show_background || (panel->type->flag & PANEL_TYPE_NO_HEADER)) {
|
||||
panel_draw_aligned_backdrop(region, panel, rect, &header_rect);
|
||||
}
|
||||
|
||||
|
|
|
@ -381,7 +381,6 @@ class ViewItemAPIWrapper {
|
|||
ICON_NONE,
|
||||
drag_controller->get_drag_type(),
|
||||
drag_controller->create_drag_data(),
|
||||
0,
|
||||
WM_DRAG_FREE_DATA);
|
||||
drag_controller->on_drag_start();
|
||||
|
||||
|
|
|
@ -3222,8 +3222,6 @@ static int object_convert_exec(bContext *C, wmOperator *op)
|
|||
{
|
||||
ob->flag |= OB_DONE;
|
||||
|
||||
bGPdata *gpd = static_cast<bGPdata *>(ob->data);
|
||||
|
||||
if (keep_original) {
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
|
@ -3231,16 +3229,7 @@ static int object_convert_exec(bContext *C, wmOperator *op)
|
|||
newob = ob;
|
||||
}
|
||||
|
||||
GreasePencil *new_grease_pencil = static_cast<GreasePencil *>(
|
||||
BKE_id_new(bmain, ID_GP, newob->id.name + 2));
|
||||
newob->data = new_grease_pencil;
|
||||
newob->type = OB_GREASE_PENCIL;
|
||||
|
||||
bke::greasepencil::convert::legacy_gpencil_to_grease_pencil(
|
||||
*bmain, *new_grease_pencil, *gpd);
|
||||
|
||||
BKE_object_free_derived_caches(newob);
|
||||
BKE_object_free_modifiers(newob, 0);
|
||||
bke::greasepencil::convert::legacy_gpencil_object(*bmain, *newob);
|
||||
}
|
||||
else if (target == OB_CURVES) {
|
||||
ob->flag |= OB_DONE;
|
||||
|
|
|
@ -150,12 +150,12 @@ static void console_cursor(wmWindow *win, ScrArea * /*area*/, ARegion *region)
|
|||
|
||||
/* ************* dropboxes ************* */
|
||||
|
||||
static bool id_drop_poll(bContext * /*C*/, wmDrag *drag, const wmEvent * /*event*/)
|
||||
static bool console_drop_id_poll(bContext * /*C*/, wmDrag *drag, const wmEvent * /*event*/)
|
||||
{
|
||||
return WM_drag_get_local_ID(drag, 0) != nullptr;
|
||||
}
|
||||
|
||||
static void id_drop_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *drop)
|
||||
static void console_drop_id_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *drop)
|
||||
{
|
||||
ID *id = WM_drag_get_local_ID(drag, 0);
|
||||
|
||||
|
@ -164,25 +164,47 @@ static void id_drop_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *drop)
|
|||
RNA_string_set(drop->ptr, "text", text.c_str());
|
||||
}
|
||||
|
||||
static bool path_drop_poll(bContext * /*C*/, wmDrag *drag, const wmEvent * /*event*/)
|
||||
static bool console_drop_path_poll(bContext * /*C*/, wmDrag *drag, const wmEvent * /*event*/)
|
||||
{
|
||||
return (drag->type == WM_DRAG_PATH);
|
||||
}
|
||||
|
||||
static void path_drop_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *drop)
|
||||
static void console_drop_path_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *drop)
|
||||
{
|
||||
char pathname[FILE_MAX + 2];
|
||||
SNPRINTF(pathname, "\"%s\"", WM_drag_get_single_path(drag));
|
||||
RNA_string_set(drop->ptr, "text", pathname);
|
||||
}
|
||||
|
||||
static bool console_drop_string_poll(bContext * /*C*/, wmDrag *drag, const wmEvent * /*event*/)
|
||||
{
|
||||
return (drag->type == WM_DRAG_STRING);
|
||||
}
|
||||
|
||||
static void console_drop_string_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *drop)
|
||||
{
|
||||
/* NOTE(@ideasman42): Only a single line is supported, multiple lines could be supported
|
||||
* but this implies executing all lines except for the last. While we could consider that,
|
||||
* there are some security implications for this, so just drop one line for now. */
|
||||
std::string str = WM_drag_get_string_firstline(drag);
|
||||
RNA_string_set(drop->ptr, "text", str.c_str());
|
||||
}
|
||||
|
||||
/* this region dropbox definition */
|
||||
static void console_dropboxes()
|
||||
{
|
||||
ListBase *lb = WM_dropboxmap_find("Console", SPACE_CONSOLE, RGN_TYPE_WINDOW);
|
||||
|
||||
WM_dropbox_add(lb, "CONSOLE_OT_insert", id_drop_poll, id_drop_copy, nullptr, nullptr);
|
||||
WM_dropbox_add(lb, "CONSOLE_OT_insert", path_drop_poll, path_drop_copy, nullptr, nullptr);
|
||||
WM_dropbox_add(
|
||||
lb, "CONSOLE_OT_insert", console_drop_id_poll, console_drop_id_copy, nullptr, nullptr);
|
||||
WM_dropbox_add(
|
||||
lb, "CONSOLE_OT_insert", console_drop_path_poll, console_drop_path_copy, nullptr, nullptr);
|
||||
WM_dropbox_add(lb,
|
||||
"CONSOLE_OT_insert",
|
||||
console_drop_string_poll,
|
||||
console_drop_string_copy,
|
||||
nullptr,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
/* ************* end drop *********** */
|
||||
|
|
|
@ -1453,7 +1453,7 @@ static int outliner_item_drag_drop_invoke(bContext *C, wmOperator * /*op*/, cons
|
|||
TSE_GPENCIL_EFFECT_BASE);
|
||||
|
||||
const eWM_DragDataType wm_drag_type = use_datastack_drag ? WM_DRAG_DATASTACK : WM_DRAG_ID;
|
||||
wmDrag *drag = WM_drag_data_create(C, data.icon, wm_drag_type, nullptr, 0.0, WM_DRAG_NOP);
|
||||
wmDrag *drag = WM_drag_data_create(C, data.icon, wm_drag_type, nullptr, WM_DRAG_NOP);
|
||||
|
||||
if (use_datastack_drag) {
|
||||
TreeElement *te_bone = nullptr;
|
||||
|
|
|
@ -301,7 +301,7 @@ static void text_cursor(wmWindow *win, ScrArea *area, ARegion *region)
|
|||
|
||||
/* ************* dropboxes ************* */
|
||||
|
||||
static bool text_drop_poll(bContext * /*C*/, wmDrag *drag, const wmEvent * /*event*/)
|
||||
static bool text_drop_path_poll(bContext * /*C*/, wmDrag *drag, const wmEvent * /*event*/)
|
||||
{
|
||||
if (drag->type == WM_DRAG_PATH) {
|
||||
const eFileSel_File_Types file_type = eFileSel_File_Types(WM_drag_get_path_file_type(drag));
|
||||
|
@ -312,18 +312,18 @@ static bool text_drop_poll(bContext * /*C*/, wmDrag *drag, const wmEvent * /*eve
|
|||
return false;
|
||||
}
|
||||
|
||||
static void text_drop_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *drop)
|
||||
static void text_drop_path_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *drop)
|
||||
{
|
||||
/* copy drag path to properties */
|
||||
RNA_string_set(drop->ptr, "filepath", WM_drag_get_single_path(drag));
|
||||
}
|
||||
|
||||
static bool text_drop_paste_poll(bContext * /*C*/, wmDrag *drag, const wmEvent * /*event*/)
|
||||
static bool text_drop_id_poll(bContext * /*C*/, wmDrag *drag, const wmEvent * /*event*/)
|
||||
{
|
||||
return (drag->type == WM_DRAG_ID);
|
||||
}
|
||||
|
||||
static void text_drop_paste(bContext * /*C*/, wmDrag *drag, wmDropBox *drop)
|
||||
static void text_drop_id_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *drop)
|
||||
{
|
||||
ID *id = WM_drag_get_local_ID(drag, 0);
|
||||
|
||||
|
@ -332,13 +332,26 @@ static void text_drop_paste(bContext * /*C*/, wmDrag *drag, wmDropBox *drop)
|
|||
RNA_string_set(drop->ptr, "text", text.c_str());
|
||||
}
|
||||
|
||||
static bool text_drop_string_poll(bContext * /*C*/, wmDrag *drag, const wmEvent * /*event*/)
|
||||
{
|
||||
return (drag->type == WM_DRAG_STRING);
|
||||
}
|
||||
|
||||
static void text_drop_string_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *drop)
|
||||
{
|
||||
const std::string &str = WM_drag_get_string(drag);
|
||||
RNA_string_set(drop->ptr, "text", str.c_str());
|
||||
}
|
||||
|
||||
/* this region dropbox definition */
|
||||
static void text_dropboxes()
|
||||
{
|
||||
ListBase *lb = WM_dropboxmap_find("Text", SPACE_TEXT, RGN_TYPE_WINDOW);
|
||||
|
||||
WM_dropbox_add(lb, "TEXT_OT_open", text_drop_poll, text_drop_copy, nullptr, nullptr);
|
||||
WM_dropbox_add(lb, "TEXT_OT_insert", text_drop_paste_poll, text_drop_paste, nullptr, nullptr);
|
||||
WM_dropbox_add(lb, "TEXT_OT_open", text_drop_path_poll, text_drop_path_copy, nullptr, nullptr);
|
||||
WM_dropbox_add(lb, "TEXT_OT_insert", text_drop_id_poll, text_drop_id_copy, nullptr, nullptr);
|
||||
WM_dropbox_add(
|
||||
lb, "TEXT_OT_insert", text_drop_string_poll, text_drop_string_copy, nullptr, nullptr);
|
||||
}
|
||||
|
||||
/* ************* end drop *********** */
|
||||
|
|
|
@ -335,7 +335,12 @@ static void TimeToTransData(
|
|||
copy_v3_v3(td->iloc, td->loc);
|
||||
td->val = time;
|
||||
td->ival = *(time);
|
||||
td->center[0] = td->ival;
|
||||
if (adt) {
|
||||
td->center[0] = BKE_nla_tweakedit_remap(adt, td->ival, NLATIME_CONVERT_MAP);
|
||||
}
|
||||
else {
|
||||
td->center[0] = td->ival;
|
||||
}
|
||||
td->center[1] = ypos;
|
||||
|
||||
/* Store the AnimData where this keyframe exists as a keyframe of the
|
||||
|
|
|
@ -37,7 +37,7 @@ static void extend_curves_straight(const float used_percent_length,
|
|||
float overshoot_point_param = used_percent_length * (new_size - 1);
|
||||
if (start_points[curve]) {
|
||||
/** Here we use the vector between two adjacent points around #overshoot_point_param as
|
||||
* our reference forthe direction of extention, however to have better tolerance for jitter,
|
||||
* our reference for the direction of extension, however to have better tolerance for jitter,
|
||||
* using the vector (a_few_points_back - end_point) might be a better solution in the future.
|
||||
*/
|
||||
int index1 = math::floor(overshoot_point_param);
|
||||
|
@ -271,7 +271,7 @@ bke::CurvesGeometry extend_curves(bke::CurvesGeometry &src_curves,
|
|||
OffsetIndices dst_indices = offset_indices::accumulate_counts_to_offsets(dst_points_by_curve);
|
||||
int target_point_count = dst_points_by_curve.last();
|
||||
|
||||
/* Make dest to source map for points. */
|
||||
/* Make destination to source map for points. */
|
||||
Array<int> dst_to_src_point(target_point_count);
|
||||
for (const int curve : src_curves.curves_range()) {
|
||||
const int point_count = points_by_curve[curve].size();
|
||||
|
|
|
@ -333,13 +333,13 @@ typedef enum {
|
|||
int GPU_shader_get_builtin_uniform(GPUShader *shader, int builtin);
|
||||
|
||||
/**
|
||||
* Compile all staticly defined shaders and print a report to the console.
|
||||
* Compile all statically defined shaders and print a report to the console.
|
||||
*
|
||||
* This is used for platform support, where bug reports can list all failing shaders.
|
||||
*/
|
||||
void GPU_shader_compile_static();
|
||||
|
||||
/** DEPRECATED: Use hardcoded buffer location instead. */
|
||||
/** DEPRECATED: Use hard-coded buffer location instead. */
|
||||
typedef enum {
|
||||
GPU_UNIFORM_BLOCK_VIEW = 0, /* viewBlock */
|
||||
GPU_UNIFORM_BLOCK_MODEL, /* modelBlock */
|
||||
|
@ -353,7 +353,7 @@ typedef enum {
|
|||
GPU_NUM_UNIFORM_BLOCKS, /* Special value, denotes number of builtin uniforms block. */
|
||||
} GPUUniformBlockBuiltin;
|
||||
|
||||
/** DEPRECATED: Use hardcoded buffer location instead. */
|
||||
/** DEPRECATED: Use hard-coded buffer location instead. */
|
||||
int GPU_shader_get_builtin_block(GPUShader *shader, int builtin);
|
||||
|
||||
/** DEPRECATED: Kept only because of Python GPU API. */
|
||||
|
|
|
@ -577,29 +577,26 @@ void GPU_shader_constant_int_ex(GPUShader *sh, int location, int value)
|
|||
{
|
||||
Shader &shader = *unwrap(sh);
|
||||
BLI_assert(shader.constants.types[location] == gpu::shader::Type::INT);
|
||||
shader.constants.values[location].i = value;
|
||||
shader.constants.is_dirty = true;
|
||||
shader.constants.is_dirty |= assign_if_different(shader.constants.values[location].i, value);
|
||||
}
|
||||
void GPU_shader_constant_uint_ex(GPUShader *sh, int location, uint value)
|
||||
{
|
||||
Shader &shader = *unwrap(sh);
|
||||
BLI_assert(shader.constants.types[location] == gpu::shader::Type::UINT);
|
||||
shader.constants.values[location].u = value;
|
||||
shader.constants.is_dirty = true;
|
||||
shader.constants.is_dirty |= assign_if_different(shader.constants.values[location].u, value);
|
||||
}
|
||||
void GPU_shader_constant_float_ex(GPUShader *sh, int location, float value)
|
||||
{
|
||||
Shader &shader = *unwrap(sh);
|
||||
BLI_assert(shader.constants.types[location] == gpu::shader::Type::FLOAT);
|
||||
shader.constants.values[location].f = value;
|
||||
shader.constants.is_dirty = true;
|
||||
shader.constants.is_dirty |= assign_if_different(shader.constants.values[location].f, value);
|
||||
}
|
||||
void GPU_shader_constant_bool_ex(GPUShader *sh, int location, bool value)
|
||||
{
|
||||
Shader &shader = *unwrap(sh);
|
||||
BLI_assert(shader.constants.types[location] == gpu::shader::Type::BOOL);
|
||||
shader.constants.values[location].u = value;
|
||||
shader.constants.is_dirty = true;
|
||||
shader.constants.is_dirty |= assign_if_different(shader.constants.values[location].u,
|
||||
static_cast<uint32_t>(value));
|
||||
}
|
||||
|
||||
void GPU_shader_constant_int(GPUShader *sh, const char *name, int value)
|
||||
|
|
|
@ -9,11 +9,10 @@
|
|||
#include <boost/python/call_method.hpp>
|
||||
#include <boost/python/class.hpp>
|
||||
#include <boost/python/import.hpp>
|
||||
#include <boost/python/object.hpp>
|
||||
#include <boost/python/return_value_policy.hpp>
|
||||
#include <boost/python/to_python_converter.hpp>
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BKE_report.hh"
|
||||
|
||||
|
@ -22,49 +21,52 @@
|
|||
#include "RNA_types.hh"
|
||||
#include "bpy_rna.h"
|
||||
|
||||
#include "WM_api.hh"
|
||||
#include "WM_types.hh"
|
||||
|
||||
#include <list>
|
||||
#include <memory>
|
||||
|
||||
using namespace boost;
|
||||
|
||||
namespace blender::io::usd {
|
||||
|
||||
using USDHookList = std::list<USDHook *>;
|
||||
using USDHookList = std::list<std::unique_ptr<USDHook>>;
|
||||
|
||||
/* USD hook type declarations */
|
||||
static USDHookList g_usd_hooks;
|
||||
|
||||
void USD_register_hook(USDHook *hook)
|
||||
static USDHookList &hook_list()
|
||||
{
|
||||
if (std::find(g_usd_hooks.begin(), g_usd_hooks.end(), hook) != g_usd_hooks.end()) {
|
||||
static USDHookList hooks{};
|
||||
return hooks;
|
||||
}
|
||||
|
||||
void USD_register_hook(std::unique_ptr<USDHook> hook)
|
||||
{
|
||||
if (USD_find_hook_name(hook->idname)) {
|
||||
/* The hook is already in the list. */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Add hook type to the list. */
|
||||
g_usd_hooks.push_back(hook);
|
||||
hook_list().push_back(std::move(hook));
|
||||
}
|
||||
|
||||
void USD_unregister_hook(USDHook *hook)
|
||||
{
|
||||
g_usd_hooks.remove(hook);
|
||||
hook_list().remove_if(
|
||||
[hook](const std::unique_ptr<USDHook> &item) { return item.get() == hook; });
|
||||
}
|
||||
|
||||
USDHook *USD_find_hook_name(const char name[])
|
||||
USDHook *USD_find_hook_name(const char idname[])
|
||||
{
|
||||
/* sanity checks */
|
||||
if (g_usd_hooks.empty() || (name == nullptr) || (name[0] == 0)) {
|
||||
if (hook_list().empty() || (idname == nullptr) || (idname[0] == 0)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
USDHookList::iterator hook_iter = std::find_if(
|
||||
g_usd_hooks.begin(), g_usd_hooks.end(), [name](USDHook *hook) {
|
||||
return STREQ(hook->idname, name);
|
||||
hook_list().begin(), hook_list().end(), [idname](const std::unique_ptr<USDHook> &item) {
|
||||
return STREQ(item->idname, idname);
|
||||
});
|
||||
|
||||
return (hook_iter == g_usd_hooks.end()) ? nullptr : *hook_iter;
|
||||
return (hook_iter == hook_list().end()) ? nullptr : hook_iter->get();
|
||||
}
|
||||
|
||||
/* Convert PointerRNA to a PyObject*. */
|
||||
|
@ -136,7 +138,7 @@ void register_hook_converters()
|
|||
static bool registered = false;
|
||||
|
||||
/* No need to register if there are no hooks. */
|
||||
if (g_usd_hooks.empty()) {
|
||||
if (hook_list().empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -196,22 +198,22 @@ class USDHookInvoker {
|
|||
/* Attempt to call the function, if defined by the registered hooks. */
|
||||
void call() const
|
||||
{
|
||||
if (g_usd_hooks.empty()) {
|
||||
if (hook_list().empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
PyGILState_STATE gilstate = PyGILState_Ensure();
|
||||
|
||||
/* Iterate over the hooks and invoke the hook function, if it's defined. */
|
||||
USDHookList::const_iterator hook_iter = g_usd_hooks.begin();
|
||||
while (hook_iter != g_usd_hooks.end()) {
|
||||
USDHookList::const_iterator hook_iter = hook_list().begin();
|
||||
while (hook_iter != hook_list().end()) {
|
||||
|
||||
/* XXX: Not sure if this is necessary:
|
||||
* Advance the iterator before invoking the callback, to guard
|
||||
* against the unlikely error where the hook is de-registered in
|
||||
* the callback. This would prevent a crash due to the iterator
|
||||
* getting invalidated. */
|
||||
USDHook *hook = *hook_iter;
|
||||
USDHook *hook = hook_iter->get();
|
||||
++hook_iter;
|
||||
|
||||
if (!hook->rna_ext.data) {
|
||||
|
@ -329,7 +331,7 @@ class OnImportInvoker : public USDHookInvoker {
|
|||
|
||||
void call_export_hooks(pxr::UsdStageRefPtr stage, Depsgraph *depsgraph, ReportList *reports)
|
||||
{
|
||||
if (g_usd_hooks.empty()) {
|
||||
if (hook_list().empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -342,7 +344,7 @@ void call_material_export_hooks(pxr::UsdStageRefPtr stage,
|
|||
pxr::UsdShadeMaterial &usd_material,
|
||||
ReportList *reports)
|
||||
{
|
||||
if (g_usd_hooks.empty()) {
|
||||
if (hook_list().empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -352,7 +354,7 @@ void call_material_export_hooks(pxr::UsdStageRefPtr stage,
|
|||
|
||||
void call_import_hooks(pxr::UsdStageRefPtr stage, ReportList *reports)
|
||||
{
|
||||
if (g_usd_hooks.empty()) {
|
||||
if (hook_list().empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -204,13 +204,12 @@ struct USDHook {
|
|||
ExtensionRNA rna_ext;
|
||||
};
|
||||
|
||||
void USD_register_hook(USDHook *hook);
|
||||
void USD_register_hook(std::unique_ptr<USDHook> hook);
|
||||
/**
|
||||
* Remove the given entry from the list of registered hooks.
|
||||
* Note that this does not free the allocated memory for the
|
||||
* hook instance, so a separate call to `MEM_freeN(hook)` is required.
|
||||
* Remove the given entry from the list of registered hooks and
|
||||
* free the allocated memory for the hook instance.
|
||||
*/
|
||||
void USD_unregister_hook(USDHook *hook);
|
||||
USDHook *USD_find_hook_name(const char name[]);
|
||||
USDHook *USD_find_hook_name(const char idname[]);
|
||||
|
||||
}; // namespace blender::io::usd
|
||||
|
|
|
@ -923,4 +923,24 @@
|
|||
.step = 4,\
|
||||
}
|
||||
|
||||
#define _DNA_DEFAULT_GreasePencilWeightAngleModifierData \
|
||||
{ \
|
||||
.flag = 0, \
|
||||
.axis = 1, \
|
||||
}
|
||||
|
||||
#define _DNA_DEFAULT_GreasePencilArrayModifierData \
|
||||
{ \
|
||||
.object = NULL, \
|
||||
.count = 2, \
|
||||
.flag = GP_ARRAY_USE_RELATIVE, \
|
||||
.offset = {0.0f, 0.0f, 0.0f}, \
|
||||
.shift = {1.0f, 0.0f, 0.0f}, \
|
||||
.rnd_offset = {0.0f, 0.0f, 0.0f}, \
|
||||
.rnd_rot = {0.0f, 0.0f, 0.0f}, \
|
||||
.rnd_scale = {0.0f, 0.0f, 0.0f}, \
|
||||
.seed = 1, \
|
||||
.mat_rpl = 0, \
|
||||
}
|
||||
|
||||
/* clang-format off */
|
||||
|
|
|
@ -108,6 +108,8 @@ typedef enum ModifierType {
|
|||
eModifierType_GreasePencilDash = 71,
|
||||
eModifierType_GreasePencilMultiply = 72,
|
||||
eModifierType_GreasePencilLength = 73,
|
||||
eModifierType_GreasePencilWeightAngle = 74,
|
||||
eModifierType_GreasePencilArray = 75,
|
||||
NUM_MODIFIER_TYPES,
|
||||
} ModifierType;
|
||||
|
||||
|
@ -2867,3 +2869,60 @@ typedef struct GreasePencilLengthModifierData {
|
|||
|
||||
void *_pad1;
|
||||
} GreasePencilLengthModifierData;
|
||||
|
||||
typedef struct GreasePencilWeightAngleModifierData {
|
||||
ModifierData modifier;
|
||||
GreasePencilModifierInfluenceData influence;
|
||||
/** #GreasePencilWeightAngleModifierFlag */
|
||||
int flag;
|
||||
float min_weight;
|
||||
/** Axis. */
|
||||
int16_t axis;
|
||||
/** #GreasePencilWeightAngleModifierSpace */
|
||||
int16_t space;
|
||||
/** Angle */
|
||||
float angle;
|
||||
/** Weights output to this vertex group, can be the same as source group. */
|
||||
char target_vgname[64];
|
||||
|
||||
void *_pad;
|
||||
} GreasePencilWeightAngleModifierData;
|
||||
|
||||
typedef enum GreasePencilWeightAngleModifierFlag {
|
||||
MOD_GREASE_PENCIL_WEIGHT_ANGLE_MULTIPLY_DATA = (1 << 5),
|
||||
MOD_GREASE_PENCIL_WEIGHT_ANGLE_INVERT_OUTPUT = (1 << 6),
|
||||
} GreasePencilWeightAngleModifierFlag;
|
||||
|
||||
typedef enum GreasePencilWeightAngleModifierSpace {
|
||||
MOD_GREASE_PENCIL_WEIGHT_ANGLE_SPACE_LOCAL = 0,
|
||||
MOD_GREASE_PENCIL_WEIGHT_ANGLE_SPACE_WORLD = 1,
|
||||
} GreasePencilWeightAngleModifierSpace;
|
||||
|
||||
typedef struct GreasePencilArrayModifierData {
|
||||
ModifierData modifier;
|
||||
GreasePencilModifierInfluenceData influence;
|
||||
struct Object *object;
|
||||
int count;
|
||||
/** #GreasePencilArrayModifierFlag */
|
||||
int flag;
|
||||
float offset[3];
|
||||
float shift[3];
|
||||
|
||||
float rnd_offset[3];
|
||||
float rnd_rot[3];
|
||||
float rnd_scale[3];
|
||||
|
||||
char _pad[4];
|
||||
/** (first element is the index) random values. (?) */
|
||||
int seed;
|
||||
|
||||
/* Replacement material index. */
|
||||
int mat_rpl;
|
||||
} GreasePencilArrayModifierData;
|
||||
|
||||
typedef enum GreasePencilArrayModifierFlag {
|
||||
MOD_GREASE_PENCIL_ARRAY_USE_OFFSET = (1 << 7),
|
||||
MOD_GREASE_PENCIL_ARRAY_USE_RELATIVE = (1 << 8),
|
||||
MOD_GREASE_PENCIL_ARRAY_USE_OB_OFFSET = (1 << 9),
|
||||
MOD_GREASE_PENCIL_ARRAY_UNIFORM_RANDOM_SCALE = (1 << 10),
|
||||
} GreasePencilArrayModifierFlag;
|
||||
|
|
|
@ -339,6 +339,8 @@ SDNA_DEFAULT_DECL_STRUCT(GreasePencilLatticeModifierData);
|
|||
SDNA_DEFAULT_DECL_STRUCT(GreasePencilDashModifierSegment);
|
||||
SDNA_DEFAULT_DECL_STRUCT(GreasePencilDashModifierData);
|
||||
SDNA_DEFAULT_DECL_STRUCT(GreasePencilMultiModifierData);
|
||||
SDNA_DEFAULT_DECL_STRUCT(GreasePencilWeightAngleModifierData);
|
||||
SDNA_DEFAULT_DECL_STRUCT(GreasePencilArrayModifierData);
|
||||
|
||||
#undef SDNA_DEFAULT_DECL_STRUCT
|
||||
|
||||
|
@ -557,6 +559,7 @@ const void *DNA_default_table[SDNA_TYPE_MAX] = {
|
|||
SDNA_DEFAULT_DECL(GreasePencilSubdivModifierData),
|
||||
SDNA_DEFAULT_DECL(GreasePencilNoiseModifierData),
|
||||
SDNA_DEFAULT_DECL(GreasePencilLengthModifierData),
|
||||
SDNA_DEFAULT_DECL(GreasePencilWeightAngleModifierData),
|
||||
|
||||
/* Grease Pencil 3.0 defaults. */
|
||||
SDNA_DEFAULT_DECL(GreasePencilSmoothModifierData),
|
||||
|
@ -600,6 +603,7 @@ const void *DNA_default_table[SDNA_TYPE_MAX] = {
|
|||
SDNA_DEFAULT_DECL(GreasePencilDashModifierSegment),
|
||||
SDNA_DEFAULT_DECL(GreasePencilDashModifierData),
|
||||
SDNA_DEFAULT_DECL(GreasePencilMultiModifierData),
|
||||
SDNA_DEFAULT_DECL(GreasePencilArrayModifierData),
|
||||
};
|
||||
#undef SDNA_DEFAULT_DECL
|
||||
#undef SDNA_DEFAULT_DECL_EX
|
||||
|
|
|
@ -314,7 +314,7 @@ static void rna_def_animviz_paths(BlenderRNA *brna)
|
|||
prop, "Has Motion Paths", "Are there any bone paths that will need updating (read-only)");
|
||||
|
||||
/* If enabled, bakes the motion paths into camera space. */
|
||||
prop = RNA_def_property(srna, "bake_in_camera_space", PROP_BOOLEAN, PROP_NONE);
|
||||
prop = RNA_def_property(srna, "use_camera_space_bake", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, nullptr, "path_bakeflag", MOTIONPATH_BAKE_CAMERA_SPACE);
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
|
|
|
@ -403,6 +403,10 @@ static PointerRNA rna_AttributeGroup_new(
|
|||
CustomDataLayer *layer = BKE_id_attribute_new(
|
||||
id, name, eCustomDataType(type), AttrDomain(domain), reports);
|
||||
|
||||
if (!layer) {
|
||||
return PointerRNA_NULL;
|
||||
}
|
||||
|
||||
if ((GS(id->name) == ID_ME) && ELEM(layer->type, CD_PROP_COLOR, CD_PROP_BYTE_COLOR)) {
|
||||
Mesh *mesh = (Mesh *)id;
|
||||
if (!mesh->active_color_attribute) {
|
||||
|
|
|
@ -116,6 +116,11 @@ const EnumPropertyItem rna_enum_object_modifier_type_items[] = {
|
|||
ICON_MOD_OPACITY,
|
||||
"Opacity",
|
||||
"Change the opacity of the strokes"},
|
||||
{eModifierType_GreasePencilWeightAngle,
|
||||
"GREASE_PENCIL_VERTEX_WEIGHT_ANGLE",
|
||||
ICON_MOD_VERTEX_WEIGHT,
|
||||
"Vertex Weight Angle",
|
||||
"Generate vertex weights base on stroke angle"},
|
||||
|
||||
RNA_ENUM_ITEM_HEADING(N_("Generate"), nullptr),
|
||||
{eModifierType_Array,
|
||||
|
@ -211,6 +216,11 @@ const EnumPropertyItem rna_enum_object_modifier_type_items[] = {
|
|||
ICON_MOD_WIREFRAME,
|
||||
"Wireframe",
|
||||
"Convert faces into thickened edges"},
|
||||
{eModifierType_GreasePencilArray,
|
||||
"GREASE_PENCIL_ARRAY",
|
||||
ICON_MOD_ARRAY,
|
||||
"Array strokes",
|
||||
"Duplicate strokes into an array"},
|
||||
{eModifierType_GreasePencilLength,
|
||||
"GREASE_PENCIL_LENGTH",
|
||||
ICON_MOD_LENGTH,
|
||||
|
@ -888,6 +898,7 @@ RNA_MOD_VGROUP_NAME_SET(WeightVGProximity, mask_defgrp_name);
|
|||
RNA_MOD_VGROUP_NAME_SET(WeightedNormal, defgrp_name);
|
||||
RNA_MOD_VGROUP_NAME_SET(Weld, defgrp_name);
|
||||
RNA_MOD_VGROUP_NAME_SET(Wireframe, defgrp_name);
|
||||
RNA_MOD_VGROUP_NAME_SET(GreasePencilWeightAngle, target_vgname);
|
||||
|
||||
static void rna_ExplodeModifier_vgroup_get(PointerRNA *ptr, char *value)
|
||||
{
|
||||
|
@ -1882,6 +1893,8 @@ RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilLattice);
|
|||
RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilDash);
|
||||
RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilMulti);
|
||||
RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilLength);
|
||||
RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilWeightAngle);
|
||||
RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilArray);
|
||||
|
||||
RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilOffset);
|
||||
RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilOpacity);
|
||||
|
@ -1892,6 +1905,7 @@ RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilNoise);
|
|||
RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilThick);
|
||||
RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilLattice);
|
||||
RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilLength);
|
||||
RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilWeightAngle);
|
||||
|
||||
static void rna_GreasePencilOpacityModifier_opacity_factor_range(
|
||||
PointerRNA *ptr, float *min, float *max, float *softmin, float *softmax)
|
||||
|
@ -8649,6 +8663,116 @@ static void rna_def_modifier_grease_pencil_thickness(BlenderRNA *brna)
|
|||
RNA_define_lib_overridable(false);
|
||||
}
|
||||
|
||||
static void rna_def_modifier_grease_pencil_array(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
srna = RNA_def_struct(brna, "GreasePencilArrayModifier", "Modifier");
|
||||
RNA_def_struct_ui_text(srna, "Instance Modifier", "Create grid of duplicate instances");
|
||||
RNA_def_struct_sdna(srna, "GreasePencilArrayModifierData");
|
||||
RNA_def_struct_ui_icon(srna, ICON_MOD_ARRAY);
|
||||
|
||||
rna_def_modifier_grease_pencil_layer_filter(srna);
|
||||
rna_def_modifier_grease_pencil_material_filter(
|
||||
srna, "rna_GreasePencilArrayModifier_material_filter_set");
|
||||
|
||||
rna_def_modifier_panel_open_prop(srna, "open_constant_offset_panel", 0);
|
||||
rna_def_modifier_panel_open_prop(srna, "open_relative_offset_panel", 1);
|
||||
rna_def_modifier_panel_open_prop(srna, "open_object_offset_panel", 2);
|
||||
rna_def_modifier_panel_open_prop(srna, "open_randomize_panel", 3);
|
||||
rna_def_modifier_panel_open_prop(srna, "open_influence_panel", 4);
|
||||
|
||||
RNA_define_lib_overridable(true);
|
||||
|
||||
prop = RNA_def_property(srna, "count", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 1, SHRT_MAX);
|
||||
RNA_def_property_ui_range(prop, 1, 50, 1, -1);
|
||||
RNA_def_property_ui_text(prop, "Count", "Number of items");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
/* Offset parameters */
|
||||
prop = RNA_def_property(srna, "offset_object", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_pointer_sdna(prop, nullptr, "object");
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Offset Object",
|
||||
"Use the location and rotation of another object to determine the distance and "
|
||||
"rotational change between arrayed items");
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
|
||||
|
||||
prop = RNA_def_property(srna, "constant_offset", PROP_FLOAT, PROP_TRANSLATION);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "offset");
|
||||
RNA_def_property_ui_text(prop, "Constant Offset", "Value for the distance between items");
|
||||
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "relative_offset", PROP_FLOAT, PROP_XYZ);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "shift");
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Relative Offset",
|
||||
"The size of the geometry will determine the distance between arrayed items");
|
||||
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "random_offset", PROP_FLOAT, PROP_XYZ);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "rnd_offset");
|
||||
RNA_def_property_ui_text(prop, "Random Offset", "Value for changes in location");
|
||||
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "random_rotation", PROP_FLOAT, PROP_EULER);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "rnd_rot");
|
||||
RNA_def_property_ui_text(prop, "Random Rotation", "Value for changes in rotation");
|
||||
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 100, RNA_TRANSLATION_PREC_DEFAULT);
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "random_scale", PROP_FLOAT, PROP_XYZ);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "rnd_scale");
|
||||
RNA_def_property_ui_text(prop, "Scale", "Value for changes in scale");
|
||||
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "seed", PROP_INT, PROP_UNSIGNED);
|
||||
RNA_def_property_ui_text(prop, "Seed", "Random seed");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "replace_material", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_int_sdna(prop, nullptr, "mat_rpl");
|
||||
RNA_def_property_range(prop, 0, SHRT_MAX);
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Material",
|
||||
"Index of the material used for generated strokes (0 keep original material)");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "use_constant_offset", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, nullptr, "flag", MOD_GREASE_PENCIL_ARRAY_USE_OFFSET);
|
||||
RNA_def_property_ui_text(prop, "Offset", "Enable offset");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "use_object_offset", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, nullptr, "flag", MOD_GREASE_PENCIL_ARRAY_USE_OB_OFFSET);
|
||||
RNA_def_property_ui_text(prop, "Use Object Offset", "Enable object offset");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "use_relative_offset", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, nullptr, "flag", MOD_GREASE_PENCIL_ARRAY_USE_RELATIVE);
|
||||
RNA_def_property_ui_text(prop, "Shift", "Enable shift");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "use_uniform_random_scale", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(
|
||||
prop, nullptr, "flag", MOD_GREASE_PENCIL_ARRAY_UNIFORM_RANDOM_SCALE);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Uniform Scale", "Use the same random seed for each scale axis for a uniform scale");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
RNA_define_lib_overridable(false);
|
||||
}
|
||||
|
||||
static void rna_def_modifier_grease_pencil_lattice(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
|
@ -8794,6 +8918,85 @@ static void rna_def_modifier_grease_pencil_dash(BlenderRNA *brna)
|
|||
RNA_define_lib_overridable(false);
|
||||
}
|
||||
|
||||
static void rna_def_modifier_grease_pencil_weight_angle(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
static const EnumPropertyItem axis_items[] = {
|
||||
{0, "X", 0, "X", ""},
|
||||
{1, "Y", 0, "Y", ""},
|
||||
{2, "Z", 0, "Z", ""},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
static const EnumPropertyItem space_items[] = {
|
||||
{MOD_GREASE_PENCIL_WEIGHT_ANGLE_SPACE_LOCAL, "LOCAL", 0, "Local Space", ""},
|
||||
{MOD_GREASE_PENCIL_WEIGHT_ANGLE_SPACE_WORLD, "WORLD", 0, "World Space", ""},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
srna = RNA_def_struct(brna, "GreasePencilWeightAngleModifier", "Modifier");
|
||||
RNA_def_struct_ui_text(srna, "Weight Modifier Angle", "Calculate Vertex Weight dynamically");
|
||||
RNA_def_struct_sdna(srna, "GreasePencilWeightAngleModifierData");
|
||||
RNA_def_struct_ui_icon(srna, ICON_MOD_VERTEX_WEIGHT);
|
||||
|
||||
rna_def_modifier_grease_pencil_layer_filter(srna);
|
||||
rna_def_modifier_grease_pencil_material_filter(
|
||||
srna, "rna_GreasePencilWeightAngleModifier_material_filter_set");
|
||||
rna_def_modifier_grease_pencil_vertex_group(
|
||||
srna, "rna_GreasePencilWeightAngleModifier_vertex_group_name_set");
|
||||
|
||||
rna_def_modifier_panel_open_prop(srna, "open_influence_panel", 0);
|
||||
|
||||
RNA_define_lib_overridable(true);
|
||||
|
||||
prop = RNA_def_property(srna, "target_vertex_group", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_string_sdna(prop, nullptr, "target_vgname");
|
||||
RNA_def_property_ui_text(prop, "Vertex Group", "Output Vertex group");
|
||||
RNA_def_property_string_funcs(
|
||||
prop, nullptr, nullptr, "rna_GreasePencilWeightAngleModifier_target_vgname_set");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "use_multiply", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, nullptr, "flag", GP_WEIGHT_MULTIPLY_DATA);
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Multiply Weights",
|
||||
"Multiply the calculated weights with the existing values in the vertex group");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "use_invert_output", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, nullptr, "flag", GP_WEIGHT_INVERT_OUTPUT);
|
||||
RNA_def_property_ui_text(prop, "Invert", "Invert output weight values");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "angle", PROP_FLOAT, PROP_ANGLE);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "angle");
|
||||
RNA_def_property_ui_text(prop, "Angle", "Angle");
|
||||
RNA_def_property_range(prop, 0.0f, DEG2RAD(180.0f));
|
||||
RNA_def_property_update(prop, NC_SCENE, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "axis", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, nullptr, "axis");
|
||||
RNA_def_property_enum_items(prop, axis_items);
|
||||
RNA_def_property_ui_text(prop, "Axis", "");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "space", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, nullptr, "space");
|
||||
RNA_def_property_enum_items(prop, space_items);
|
||||
RNA_def_property_ui_text(prop, "Space", "Coordinates space");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "minimum_weight", PROP_FLOAT, PROP_FACTOR);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "min_weight");
|
||||
RNA_def_property_ui_text(prop, "Minimum", "Minimum value for vertex weight");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
RNA_define_lib_overridable(false);
|
||||
}
|
||||
|
||||
static void rna_def_modifier_grease_pencil_multiply(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
|
@ -9035,6 +9238,8 @@ void RNA_def_modifier(BlenderRNA *brna)
|
|||
rna_def_modifier_grease_pencil_dash(brna);
|
||||
rna_def_modifier_grease_pencil_multiply(brna);
|
||||
rna_def_modifier_grease_pencil_length(brna);
|
||||
rna_def_modifier_grease_pencil_weight_angle(brna);
|
||||
rna_def_modifier_grease_pencil_array(brna);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -6422,7 +6422,7 @@ static void rna_def_space_graph(BlenderRNA *brna)
|
|||
RNA_def_property_ui_text(prop, "Show Handles", "Show handles of Bézier control points");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, nullptr);
|
||||
|
||||
prop = RNA_def_property(srna, "autolock_translation_axis", PROP_BOOLEAN, PROP_NONE);
|
||||
prop = RNA_def_property(srna, "use_auto_lock_translation_axis", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, nullptr, "flag", SIPO_AUTOLOCK_AXIS);
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Auto-Lock Key Axis",
|
||||
|
|
|
@ -46,8 +46,6 @@ static bool rna_USDHook_unregister(Main * /*bmain*/, StructRNA *type)
|
|||
/* unlink Blender-side data */
|
||||
USD_unregister_hook(hook);
|
||||
|
||||
MEM_freeN(hook);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -60,8 +58,7 @@ static StructRNA *rna_USDHook_register(Main *bmain,
|
|||
StructFreeFunc free)
|
||||
{
|
||||
const char *error_prefix = "Registering USD hook class:";
|
||||
USDHook dummy_hook = {{0}};
|
||||
USDHook *hook;
|
||||
USDHook dummy_hook{};
|
||||
|
||||
/* setup dummy type info to store static properties in */
|
||||
PointerRNA dummy_hook_ptr = RNA_pointer_create(nullptr, &RNA_USDHook, &dummy_hook);
|
||||
|
@ -82,8 +79,7 @@ static StructRNA *rna_USDHook_register(Main *bmain,
|
|||
}
|
||||
|
||||
/* check if we have registered this hook before, and remove it */
|
||||
hook = USD_find_hook_name(dummy_hook.idname);
|
||||
if (hook) {
|
||||
if (USDHook *hook = USD_find_hook_name(dummy_hook.idname)) {
|
||||
BKE_reportf(reports,
|
||||
RPT_INFO,
|
||||
"%s '%s', bl_idname '%s' has been registered before, unregistering previous",
|
||||
|
@ -105,23 +101,24 @@ static StructRNA *rna_USDHook_register(Main *bmain,
|
|||
}
|
||||
|
||||
/* create a new KeyingSetInfo type */
|
||||
hook = static_cast<USDHook *>(MEM_mallocN(sizeof(USDHook), "python USD hook"));
|
||||
memcpy(hook, &dummy_hook, sizeof(USDHook));
|
||||
auto hook = std::make_unique<USDHook>();
|
||||
*hook = dummy_hook;
|
||||
|
||||
/* set RNA-extensions info */
|
||||
hook->rna_ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, hook->idname, &RNA_USDHook);
|
||||
hook->rna_ext.data = data;
|
||||
hook->rna_ext.call = call;
|
||||
hook->rna_ext.free = free;
|
||||
RNA_struct_blender_type_set(hook->rna_ext.srna, hook);
|
||||
RNA_struct_blender_type_set(hook->rna_ext.srna, hook.get());
|
||||
|
||||
/* add and register with other info as needed */
|
||||
USD_register_hook(hook);
|
||||
StructRNA *srna = hook->rna_ext.srna;
|
||||
USD_register_hook(std::move(hook));
|
||||
|
||||
WM_main_add_notifier(NC_WINDOW, nullptr);
|
||||
|
||||
/* return the struct-rna added */
|
||||
return hook->rna_ext.srna;
|
||||
return srna;
|
||||
}
|
||||
|
||||
#else
|
||||
|
|
|
@ -44,6 +44,7 @@ set(SRC
|
|||
intern/MOD_edgesplit.cc
|
||||
intern/MOD_explode.cc
|
||||
intern/MOD_fluid.cc
|
||||
intern/MOD_grease_pencil_array.cc
|
||||
intern/MOD_grease_pencil_color.cc
|
||||
intern/MOD_grease_pencil_dash.cc
|
||||
intern/MOD_grease_pencil_lattice.cc
|
||||
|
@ -58,6 +59,7 @@ set(SRC
|
|||
intern/MOD_grease_pencil_thickness.cc
|
||||
intern/MOD_grease_pencil_tint.cc
|
||||
intern/MOD_grease_pencil_util.cc
|
||||
intern/MOD_grease_pencil_weight_angle.cc
|
||||
intern/MOD_hook.cc
|
||||
intern/MOD_laplaciandeform.cc
|
||||
intern/MOD_laplaciansmooth.cc
|
||||
|
|
|
@ -86,6 +86,8 @@ extern ModifierTypeInfo modifierType_GreasePencilLattice;
|
|||
extern ModifierTypeInfo modifierType_GreasePencilDash;
|
||||
extern ModifierTypeInfo modifierType_GreasePencilMultiply;
|
||||
extern ModifierTypeInfo modifierType_GreasePencilLength;
|
||||
extern ModifierTypeInfo modifierType_GreasePencilWeightAngle;
|
||||
extern ModifierTypeInfo modifierType_GreasePencilArray;
|
||||
|
||||
/* MOD_util.cc */
|
||||
|
||||
|
|
|
@ -0,0 +1,397 @@
|
|||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup modifiers
|
||||
*/
|
||||
|
||||
#include "DNA_defaults.h"
|
||||
#include "DNA_modifier_types.h"
|
||||
|
||||
#include "BKE_curves.hh"
|
||||
#include "BKE_geometry_set.hh"
|
||||
#include "BKE_grease_pencil.hh"
|
||||
#include "BKE_instances.hh"
|
||||
#include "BKE_lib_query.hh"
|
||||
#include "BKE_material.h"
|
||||
#include "BKE_modifier.hh"
|
||||
#include "BKE_screen.hh"
|
||||
|
||||
#include "BLO_read_write.hh"
|
||||
|
||||
#include "GEO_realize_instances.hh"
|
||||
|
||||
#include "UI_interface.hh"
|
||||
#include "UI_resources.hh"
|
||||
|
||||
#include "BLT_translation.hh"
|
||||
|
||||
#include "BLI_bounds_types.hh"
|
||||
#include "BLI_hash.h"
|
||||
#include "BLI_math_matrix.hh"
|
||||
#include "BLI_rand.h"
|
||||
|
||||
#include "WM_types.hh"
|
||||
|
||||
#include "RNA_access.hh"
|
||||
#include "RNA_prototypes.h"
|
||||
|
||||
#include "MOD_grease_pencil_util.hh"
|
||||
#include "MOD_modifiertypes.hh"
|
||||
#include "MOD_ui_common.hh"
|
||||
|
||||
namespace blender {
|
||||
|
||||
static void init_data(ModifierData *md)
|
||||
{
|
||||
auto *mmd = reinterpret_cast<GreasePencilArrayModifierData *>(md);
|
||||
|
||||
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(mmd, modifier));
|
||||
|
||||
MEMCPY_STRUCT_AFTER(mmd, DNA_struct_default_get(GreasePencilArrayModifierData), modifier);
|
||||
modifier::greasepencil::init_influence_data(&mmd->influence, false);
|
||||
}
|
||||
|
||||
static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
|
||||
{
|
||||
const auto *mmd = reinterpret_cast<const GreasePencilArrayModifierData *>(md);
|
||||
auto *tmmd = reinterpret_cast<GreasePencilArrayModifierData *>(target);
|
||||
|
||||
modifier::greasepencil::free_influence_data(&tmmd->influence);
|
||||
|
||||
BKE_modifier_copydata_generic(md, target, flag);
|
||||
modifier::greasepencil::copy_influence_data(&mmd->influence, &tmmd->influence, flag);
|
||||
}
|
||||
|
||||
static void free_data(ModifierData *md)
|
||||
{
|
||||
auto *mmd = reinterpret_cast<GreasePencilArrayModifierData *>(md);
|
||||
modifier::greasepencil::free_influence_data(&mmd->influence);
|
||||
}
|
||||
|
||||
static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
|
||||
{
|
||||
auto *mmd = reinterpret_cast<GreasePencilArrayModifierData *>(md);
|
||||
walk(user_data, ob, (ID **)&mmd->object, IDWALK_CB_NOP);
|
||||
modifier::greasepencil::foreach_influence_ID_link(&mmd->influence, ob, walk, user_data);
|
||||
}
|
||||
|
||||
static void update_depsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
|
||||
{
|
||||
auto *mmd = reinterpret_cast<GreasePencilArrayModifierData *>(md);
|
||||
if (mmd->object != nullptr) {
|
||||
DEG_add_object_relation(
|
||||
ctx->node, mmd->object, DEG_OB_COMP_TRANSFORM, "Grease Pencil Array Modifier");
|
||||
DEG_add_depends_on_transform_relation(ctx->node, "Grease Pencil Array Modifier");
|
||||
}
|
||||
}
|
||||
|
||||
static float4x4 get_array_matrix(const Object &ob,
|
||||
const GreasePencilArrayModifierData &mmd,
|
||||
const int elem_idx,
|
||||
const bool use_object_offset)
|
||||
{
|
||||
|
||||
if (use_object_offset) {
|
||||
float4x4 mat_offset = float4x4::identity();
|
||||
|
||||
if (mmd.flag & MOD_GREASE_PENCIL_ARRAY_USE_OFFSET) {
|
||||
mat_offset[3] += mmd.offset;
|
||||
}
|
||||
const float4x4 obinv = ob.world_to_object();
|
||||
|
||||
return mat_offset * obinv * mmd.object->object_to_world();
|
||||
}
|
||||
|
||||
const float3 offset = [&]() {
|
||||
if (mmd.flag & MOD_GREASE_PENCIL_ARRAY_USE_OFFSET) {
|
||||
return float3(mmd.offset) * elem_idx;
|
||||
}
|
||||
return float3(0.0f);
|
||||
}();
|
||||
|
||||
return math::from_location<float4x4>(offset);
|
||||
}
|
||||
|
||||
static float4x4 get_rand_matrix(const GreasePencilArrayModifierData &mmd,
|
||||
const Object &ob,
|
||||
const int elem_id)
|
||||
{
|
||||
int seed = mmd.seed;
|
||||
seed += BLI_hash_string(ob.id.name + 2);
|
||||
seed += BLI_hash_string(mmd.modifier.name);
|
||||
const float rand_offset = BLI_hash_int_01(seed);
|
||||
float3x3 rand;
|
||||
for (int j = 0; j < 3; j++) {
|
||||
const uint3 primes(2, 3, 7);
|
||||
double3 offset(0.0);
|
||||
double3 r;
|
||||
/* To ensure a nice distribution, we use halton sequence and offset using the seed. */
|
||||
BLI_halton_3d(primes, offset, elem_id, r);
|
||||
|
||||
if ((mmd.flag & MOD_GREASE_PENCIL_ARRAY_UNIFORM_RANDOM_SCALE) && j == 2) {
|
||||
float rand_value;
|
||||
rand_value = math::mod(r[0] * 2.0 - 1.0 + rand_offset, 1.0);
|
||||
rand_value = math::mod(math::sin(rand_value * 12.9898 + j * 78.233) * 43758.5453, 1.0);
|
||||
rand[j] = float3(rand_value);
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
rand[j][i] = math::mod(r[i] * 2.0 - 1.0 + rand_offset, 1.0);
|
||||
rand[j][i] = math::mod(math::sin(rand[j][i] * 12.9898 + j * 78.233) * 43758.5453, 1.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Calculate Random matrix. */
|
||||
return math::from_loc_rot_scale<float4x4>(
|
||||
mmd.rnd_offset * rand[0], mmd.rnd_rot * rand[1], float3(1.0f) + mmd.rnd_scale * rand[2]);
|
||||
};
|
||||
|
||||
static bke::CurvesGeometry create_array_copies(const Object &ob,
|
||||
const GreasePencilArrayModifierData &mmd,
|
||||
const bke::CurvesGeometry &base_curves,
|
||||
bke::CurvesGeometry filtered_curves)
|
||||
{
|
||||
/* Assign replacement material on filterd curves so all copies can have this material when later
|
||||
* when they get instanced. */
|
||||
if (mmd.mat_rpl > 0) {
|
||||
bke::MutableAttributeAccessor attributes = filtered_curves.attributes_for_write();
|
||||
bke::SpanAttributeWriter<int> stroke_materials = attributes.lookup_or_add_for_write_span<int>(
|
||||
"material_index", bke::AttrDomain::Curve);
|
||||
stroke_materials.span.fill(mmd.mat_rpl - 1);
|
||||
stroke_materials.finish();
|
||||
}
|
||||
|
||||
Curves *base_curves_id = bke::curves_new_nomain(base_curves);
|
||||
Curves *filtered_curves_id = bke::curves_new_nomain(filtered_curves);
|
||||
bke::GeometrySet base_geo = bke::GeometrySet::from_curves(base_curves_id);
|
||||
bke::GeometrySet filtered_geo = bke::GeometrySet::from_curves(filtered_curves_id);
|
||||
|
||||
std::unique_ptr<bke::Instances> instances = std::make_unique<bke::Instances>();
|
||||
const int base_handle = instances->add_reference(bke::InstanceReference{base_geo});
|
||||
const int filtered_handle = instances->add_reference(bke::InstanceReference{filtered_geo});
|
||||
|
||||
/* Always add untouched original curves. */
|
||||
instances->add_instance(base_handle, float4x4::identity());
|
||||
|
||||
float3 size(0.0f);
|
||||
if (mmd.flag & MOD_GREASE_PENCIL_ARRAY_USE_RELATIVE) {
|
||||
std::optional<blender::Bounds<float3>> bounds = filtered_curves.bounds_min_max();
|
||||
if (bounds.has_value()) {
|
||||
size = bounds.value().max - bounds.value().min;
|
||||
/* Need a minimum size (for flat drawings). */
|
||||
size = math::max(size, float3(0.01f));
|
||||
}
|
||||
}
|
||||
|
||||
float4x4 current_offset = float4x4::identity();
|
||||
for (const int elem_id : IndexRange(1, mmd.count - 1)) {
|
||||
const bool use_object_offset = (mmd.flag & MOD_GREASE_PENCIL_ARRAY_USE_OB_OFFSET) &&
|
||||
(mmd.object);
|
||||
const float4x4 mat = get_array_matrix(ob, mmd, elem_id, use_object_offset);
|
||||
|
||||
if (use_object_offset) {
|
||||
current_offset = current_offset * mat;
|
||||
}
|
||||
else {
|
||||
current_offset = mat;
|
||||
}
|
||||
|
||||
/* Apply relative offset. */
|
||||
if (mmd.flag & MOD_GREASE_PENCIL_ARRAY_USE_RELATIVE) {
|
||||
float3 relative = size * float3(mmd.shift);
|
||||
float3 translate = relative * float3(float(elem_id));
|
||||
current_offset.w += float4(translate, 1.0f);
|
||||
}
|
||||
|
||||
current_offset *= get_rand_matrix(mmd, ob, elem_id);
|
||||
|
||||
instances->add_instance(filtered_handle, current_offset);
|
||||
}
|
||||
|
||||
geometry::RealizeInstancesOptions options;
|
||||
options.keep_original_ids = true;
|
||||
options.realize_instance_attributes = false; /* Should this be true? */
|
||||
options.propagation_info = {};
|
||||
bke::GeometrySet result_geo = geometry::realize_instances(
|
||||
bke::GeometrySet::from_instances(instances.release()), options);
|
||||
return std::move(result_geo.get_curves_for_write()->geometry.wrap());
|
||||
}
|
||||
|
||||
static void modify_drawing(const GreasePencilArrayModifierData &mmd,
|
||||
const ModifierEvalContext &ctx,
|
||||
bke::greasepencil::Drawing &drawing)
|
||||
{
|
||||
const bke::CurvesGeometry &src_curves = drawing.strokes();
|
||||
if (src_curves.curve_num == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
IndexMaskMemory curve_mask_memory;
|
||||
const IndexMask curves_mask = modifier::greasepencil::get_filtered_stroke_mask(
|
||||
ctx.object, src_curves, mmd.influence, curve_mask_memory);
|
||||
|
||||
if (curves_mask.size() == src_curves.curve_num) {
|
||||
/* Make a full copy so we can modify materials inside #create_array_copies before instancing.
|
||||
*/
|
||||
bke::CurvesGeometry copy = bke::CurvesGeometry(src_curves);
|
||||
|
||||
drawing.strokes_for_write() = create_array_copies(
|
||||
*ctx.object, mmd, src_curves, std::move(copy));
|
||||
}
|
||||
else {
|
||||
bke::CurvesGeometry masked_curves = bke::curves_copy_curve_selection(
|
||||
src_curves, curves_mask, {});
|
||||
|
||||
drawing.strokes_for_write() = create_array_copies(
|
||||
*ctx.object, mmd, src_curves, std::move(masked_curves));
|
||||
}
|
||||
|
||||
drawing.tag_topology_changed();
|
||||
}
|
||||
|
||||
static void modify_geometry_set(ModifierData *md,
|
||||
const ModifierEvalContext *ctx,
|
||||
bke::GeometrySet *geometry_set)
|
||||
{
|
||||
using bke::greasepencil::Drawing;
|
||||
|
||||
auto *mmd = reinterpret_cast<GreasePencilArrayModifierData *>(md);
|
||||
|
||||
if (!geometry_set->has_grease_pencil()) {
|
||||
return;
|
||||
}
|
||||
GreasePencil &grease_pencil = *geometry_set->get_grease_pencil_for_write();
|
||||
const int frame = grease_pencil.runtime->eval_frame;
|
||||
|
||||
IndexMaskMemory mask_memory;
|
||||
const IndexMask layer_mask = modifier::greasepencil::get_filtered_layer_mask(
|
||||
grease_pencil, mmd->influence, mask_memory);
|
||||
|
||||
const Vector<Drawing *> drawings = modifier::greasepencil::get_drawings_for_write(
|
||||
grease_pencil, layer_mask, frame);
|
||||
threading::parallel_for_each(drawings,
|
||||
[&](Drawing *drawing) { modify_drawing(*mmd, *ctx, *drawing); });
|
||||
}
|
||||
|
||||
static void panel_draw(const bContext *C, Panel *panel)
|
||||
{
|
||||
uiLayout *layout = panel->layout;
|
||||
|
||||
PointerRNA ob_ptr;
|
||||
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
|
||||
|
||||
uiLayoutSetPropSep(layout, true);
|
||||
|
||||
uiItemR(layout, ptr, "count", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
uiItemR(layout, ptr, "replace_material", UI_ITEM_NONE, IFACE_("Material Override"), ICON_NONE);
|
||||
|
||||
if (uiLayout *sub = uiLayoutPanelProp(
|
||||
C, layout, ptr, "open_relative_offset_panel", "Relative Offset"))
|
||||
{
|
||||
uiLayoutSetPropSep(sub, true);
|
||||
uiItemR(sub, ptr, "use_relative_offset", UI_ITEM_NONE, IFACE_("Enable"), ICON_NONE);
|
||||
|
||||
uiLayout *col = uiLayoutColumn(sub, false);
|
||||
uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_relative_offset"));
|
||||
uiItemR(col, ptr, "relative_offset", UI_ITEM_NONE, IFACE_("Factor"), ICON_NONE);
|
||||
}
|
||||
|
||||
if (uiLayout *sub = uiLayoutPanelProp(
|
||||
C, layout, ptr, "open_constant_offset_panel", "Constant Offset"))
|
||||
{
|
||||
uiLayoutSetPropSep(sub, true);
|
||||
uiItemR(sub, ptr, "use_constant_offset", UI_ITEM_NONE, IFACE_("Enable"), ICON_NONE);
|
||||
|
||||
uiLayout *col = uiLayoutColumn(sub, false);
|
||||
uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_constant_offset"));
|
||||
uiItemR(col, ptr, "constant_offset", UI_ITEM_NONE, IFACE_("Distance"), ICON_NONE);
|
||||
}
|
||||
|
||||
if (uiLayout *sub = uiLayoutPanelProp(
|
||||
C, layout, ptr, "open_object_offset_panel", "Object Offset"))
|
||||
{
|
||||
uiLayoutSetPropSep(sub, true);
|
||||
uiItemR(sub, ptr, "use_object_offset", UI_ITEM_NONE, IFACE_("Enable"), ICON_NONE);
|
||||
|
||||
uiLayout *col = uiLayoutColumn(sub, false);
|
||||
uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_object_offset"));
|
||||
uiItemR(col, ptr, "offset_object", UI_ITEM_NONE, IFACE_("Object"), ICON_NONE);
|
||||
}
|
||||
|
||||
if (uiLayout *sub = uiLayoutPanelProp(C, layout, ptr, "open_randomize_panel", "Randomize")) {
|
||||
uiLayoutSetPropSep(sub, true);
|
||||
uiItemR(sub, ptr, "random_offset", UI_ITEM_NONE, IFACE_("Offset"), ICON_NONE);
|
||||
uiItemR(sub, ptr, "random_rotation", UI_ITEM_NONE, IFACE_("Rotation"), ICON_NONE);
|
||||
uiItemR(sub, ptr, "random_scale", UI_ITEM_NONE, IFACE_("Scale"), ICON_NONE);
|
||||
uiItemR(sub, ptr, "use_uniform_random_scale", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
uiItemR(sub, ptr, "seed", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
}
|
||||
|
||||
if (uiLayout *influence_panel = uiLayoutPanelProp(
|
||||
C, layout, ptr, "open_influence_panel", "Influence"))
|
||||
{
|
||||
modifier::greasepencil::draw_layer_filter_settings(C, influence_panel, ptr);
|
||||
modifier::greasepencil::draw_material_filter_settings(C, influence_panel, ptr);
|
||||
}
|
||||
|
||||
modifier_panel_end(layout, ptr);
|
||||
}
|
||||
|
||||
static void panel_register(ARegionType *region_type)
|
||||
{
|
||||
modifier_panel_register(region_type, eModifierType_GreasePencilArray, panel_draw);
|
||||
}
|
||||
|
||||
static void blend_write(BlendWriter *writer, const ID * /*id_owner*/, const ModifierData *md)
|
||||
{
|
||||
const auto *mmd = reinterpret_cast<const GreasePencilArrayModifierData *>(md);
|
||||
|
||||
BLO_write_struct(writer, GreasePencilArrayModifierData, mmd);
|
||||
modifier::greasepencil::write_influence_data(writer, &mmd->influence);
|
||||
}
|
||||
|
||||
static void blend_read(BlendDataReader *reader, ModifierData *md)
|
||||
{
|
||||
auto *mmd = reinterpret_cast<GreasePencilArrayModifierData *>(md);
|
||||
|
||||
modifier::greasepencil::read_influence_data(reader, &mmd->influence);
|
||||
}
|
||||
|
||||
} // namespace blender
|
||||
|
||||
ModifierTypeInfo modifierType_GreasePencilArray = {
|
||||
/*idname*/ "GreasePencilArrayModifier",
|
||||
/*name*/ N_("Array"),
|
||||
/*struct_name*/ "GreasePencilArrayModifierData",
|
||||
/*struct_size*/ sizeof(GreasePencilArrayModifierData),
|
||||
/*srna*/ &RNA_GreasePencilArrayModifier,
|
||||
/*type*/ ModifierTypeType::Constructive,
|
||||
/*flags*/ eModifierTypeFlag_AcceptsGreasePencil | eModifierTypeFlag_SupportsEditmode |
|
||||
eModifierTypeFlag_EnableInEditmode | eModifierTypeFlag_SupportsMapping,
|
||||
/*icon*/ ICON_MOD_ARRAY,
|
||||
|
||||
/*copy_data*/ blender::copy_data,
|
||||
|
||||
/*deform_verts*/ nullptr,
|
||||
/*deform_matrices*/ nullptr,
|
||||
/*deform_verts_EM*/ nullptr,
|
||||
/*deform_matrices_EM*/ nullptr,
|
||||
/*modify_mesh*/ nullptr,
|
||||
/*modify_geometry_set*/ blender::modify_geometry_set,
|
||||
|
||||
/*init_data*/ blender::init_data,
|
||||
/*required_data_mask*/ nullptr,
|
||||
/*free_data*/ blender::free_data,
|
||||
/*is_disabled*/ nullptr,
|
||||
/*update_depsgraph*/ blender::update_depsgraph,
|
||||
/*depends_on_time*/ nullptr,
|
||||
/*depends_on_normals*/ nullptr,
|
||||
/*foreach_ID_link*/ blender::foreach_ID_link,
|
||||
/*foreach_tex_link*/ nullptr,
|
||||
/*free_runtime_data*/ nullptr,
|
||||
/*panel_register*/ blender::panel_register,
|
||||
/*blend_write*/ blender::blend_write,
|
||||
/*blend_read*/ blender::blend_read,
|
||||
};
|
|
@ -196,9 +196,9 @@ static void deform_drawing(const ModifierData &md,
|
|||
/* Always do the stretching first since it might depend on points which could be deleted by the
|
||||
* shrink. */
|
||||
if (mmd.start_fac < 0.0f || mmd.end_fac < 0.0f || needs_additional_shrinking) {
|
||||
/* `trim_curves()` accepts the `end` valueas if it's sampling from the beginning of the
|
||||
* curve, so we need to get the lengths of the curves and substract it from the back when the
|
||||
* modifier is in Absolute mode. For convenience, we always call `trim_curves()` in LENGTH
|
||||
/* #trim_curves() accepts the `end` values if it's sampling from the beginning of the
|
||||
* curve, so we need to get the lengths of the curves and subtract it from the back when the
|
||||
* modifier is in Absolute mode. For convenience, we always call #trim_curves() in LENGTH
|
||||
* mode since the function itself will need length to be sampled anyway. */
|
||||
Array<float> starts(curves.curves_num());
|
||||
Array<float> ends(curves.curves_num());
|
||||
|
|
|
@ -0,0 +1,310 @@
|
|||
/* SPDX-FileCopyrightText: 2005 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup modifiers
|
||||
*/
|
||||
|
||||
#include "BLI_index_mask.hh"
|
||||
#include "BLI_math_rotation.hh"
|
||||
#include "BLI_string.h" /* For #STRNCPY. */
|
||||
|
||||
#include "BLT_translation.hh"
|
||||
|
||||
#include "BLO_read_write.hh"
|
||||
|
||||
#include "DNA_defaults.h"
|
||||
#include "DNA_modifier_types.h"
|
||||
#include "DNA_screen_types.h"
|
||||
|
||||
#include "RNA_access.hh"
|
||||
|
||||
#include "BKE_curves.hh"
|
||||
#include "BKE_geometry_set.hh"
|
||||
#include "BKE_grease_pencil.hh"
|
||||
#include "BKE_lib_query.hh"
|
||||
#include "BKE_modifier.hh"
|
||||
|
||||
#include "UI_interface.hh"
|
||||
#include "UI_resources.hh"
|
||||
|
||||
#include "MOD_grease_pencil_util.hh"
|
||||
#include "MOD_modifiertypes.hh"
|
||||
#include "MOD_ui_common.hh"
|
||||
|
||||
#include "RNA_prototypes.h"
|
||||
|
||||
namespace blender {
|
||||
|
||||
static void init_data(ModifierData *md)
|
||||
{
|
||||
GreasePencilWeightAngleModifierData *gpmd =
|
||||
reinterpret_cast<GreasePencilWeightAngleModifierData *>(md);
|
||||
|
||||
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(gpmd, modifier));
|
||||
|
||||
MEMCPY_STRUCT_AFTER(gpmd, DNA_struct_default_get(GreasePencilWeightAngleModifierData), modifier);
|
||||
modifier::greasepencil::init_influence_data(&gpmd->influence, false);
|
||||
}
|
||||
|
||||
static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
|
||||
{
|
||||
const GreasePencilWeightAngleModifierData *gmd =
|
||||
reinterpret_cast<const GreasePencilWeightAngleModifierData *>(md);
|
||||
GreasePencilWeightAngleModifierData *tgmd =
|
||||
reinterpret_cast<GreasePencilWeightAngleModifierData *>(target);
|
||||
|
||||
BKE_modifier_copydata_generic(md, target, flag);
|
||||
modifier::greasepencil::copy_influence_data(&gmd->influence, &tgmd->influence, flag);
|
||||
}
|
||||
|
||||
static void free_data(ModifierData *md)
|
||||
{
|
||||
GreasePencilWeightAngleModifierData *mmd =
|
||||
reinterpret_cast<GreasePencilWeightAngleModifierData *>(md);
|
||||
|
||||
modifier::greasepencil::free_influence_data(&mmd->influence);
|
||||
}
|
||||
|
||||
static bool is_disabled(const Scene * /*scene*/, ModifierData *md, bool /*use_render_params*/)
|
||||
{
|
||||
GreasePencilWeightAngleModifierData *mmd = (GreasePencilWeightAngleModifierData *)md;
|
||||
|
||||
return (mmd->target_vgname[0] == '\0');
|
||||
}
|
||||
|
||||
static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
|
||||
{
|
||||
GreasePencilWeightAngleModifierData *mmd =
|
||||
reinterpret_cast<GreasePencilWeightAngleModifierData *>(md);
|
||||
|
||||
modifier::greasepencil::foreach_influence_ID_link(&mmd->influence, ob, walk, user_data);
|
||||
}
|
||||
|
||||
static void blend_write(BlendWriter *writer, const ID * /*id_owner*/, const ModifierData *md)
|
||||
{
|
||||
const GreasePencilWeightAngleModifierData *mmd =
|
||||
reinterpret_cast<const GreasePencilWeightAngleModifierData *>(md);
|
||||
|
||||
BLO_write_struct(writer, GreasePencilWeightAngleModifierData, mmd);
|
||||
modifier::greasepencil::write_influence_data(writer, &mmd->influence);
|
||||
}
|
||||
|
||||
static void blend_read(BlendDataReader *reader, ModifierData *md)
|
||||
{
|
||||
GreasePencilWeightAngleModifierData *mmd =
|
||||
reinterpret_cast<GreasePencilWeightAngleModifierData *>(md);
|
||||
modifier::greasepencil::read_influence_data(reader, &mmd->influence);
|
||||
}
|
||||
|
||||
static int ensure_vertex_group(const StringRefNull name, ListBase &vertex_group_names)
|
||||
{
|
||||
int def_nr = BLI_findstringindex(
|
||||
&vertex_group_names, name.c_str(), offsetof(bDeformGroup, name));
|
||||
if (def_nr < 0) {
|
||||
bDeformGroup *defgroup = MEM_cnew<bDeformGroup>(__func__);
|
||||
STRNCPY(defgroup->name, name.c_str());
|
||||
BLI_addtail(&vertex_group_names, defgroup);
|
||||
def_nr = BLI_listbase_count(&vertex_group_names) - 1;
|
||||
BLI_assert(def_nr >= 0);
|
||||
}
|
||||
return def_nr;
|
||||
}
|
||||
|
||||
static bool target_vertex_group_available(const StringRefNull name,
|
||||
const ListBase &vertex_group_names)
|
||||
{
|
||||
const int def_nr = BLI_findstringindex(
|
||||
&vertex_group_names, name.c_str(), offsetof(bDeformGroup, name));
|
||||
if (def_nr < 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void write_weights_for_drawing(const ModifierData &md,
|
||||
const Object &ob,
|
||||
bke::greasepencil::Drawing &drawing)
|
||||
{
|
||||
const auto &mmd = reinterpret_cast<const GreasePencilWeightAngleModifierData &>(md);
|
||||
bke::CurvesGeometry &curves = drawing.strokes_for_write();
|
||||
if (curves.points_num() == 0) {
|
||||
return;
|
||||
}
|
||||
IndexMaskMemory memory;
|
||||
const IndexMask strokes = modifier::greasepencil::get_filtered_stroke_mask(
|
||||
&ob, curves, mmd.influence, memory);
|
||||
if (strokes.is_empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Make sure that the target vertex group is added to this drawing so we can write to it. */
|
||||
ensure_vertex_group(mmd.target_vgname, curves.vertex_group_names);
|
||||
|
||||
bke::MutableAttributeAccessor attributes = curves.attributes_for_write();
|
||||
bke::SpanAttributeWriter<float> dst_weights = attributes.lookup_for_write_span<float>(
|
||||
mmd.target_vgname);
|
||||
|
||||
BLI_assert(!dst_weights.span.is_empty());
|
||||
|
||||
const VArray<float> input_weights = modifier::greasepencil::get_influence_vertex_weights(
|
||||
curves, mmd.influence);
|
||||
|
||||
/* Use default Z up. */
|
||||
const float3 z_up(0.0f, 0.0f, 1.0f);
|
||||
float3 axis(0.0f);
|
||||
axis[mmd.axis] = 1.0f;
|
||||
float3 vec_ref;
|
||||
/* Apply modifier rotation (sub 90 degrees for Y axis due Z-Up vector). */
|
||||
const float rot_angle = mmd.angle - ((mmd.axis == 1) ? M_PI_2 : 0.0f);
|
||||
rotate_normalized_v3_v3v3fl(vec_ref, z_up, axis, rot_angle);
|
||||
|
||||
const float3x3 obmat3x3(ob.object_to_world());
|
||||
|
||||
/* Apply the rotation of the object. */
|
||||
if (mmd.space == MOD_GREASE_PENCIL_WEIGHT_ANGLE_SPACE_LOCAL) {
|
||||
vec_ref = math::transform_point(obmat3x3, vec_ref);
|
||||
}
|
||||
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
const Span<float3> positions = curves.positions();
|
||||
|
||||
strokes.foreach_index(GrainSize(512), [&](const int stroke) {
|
||||
const IndexRange points = points_by_curve[stroke];
|
||||
if (points.size() == 1) {
|
||||
dst_weights.span[points.start()] = 1.0f;
|
||||
return;
|
||||
}
|
||||
for (const int point : points.drop_front(1)) {
|
||||
const float3 p1 = math::transform_point(obmat3x3, positions[point]);
|
||||
const float3 p2 = math::transform_point(obmat3x3, positions[point - 1]);
|
||||
const float3 vec = p2 - p1;
|
||||
const float angle = angle_on_axis_v3v3_v3(vec_ref, vec, axis);
|
||||
float weight = 1.0f - math::sin(angle);
|
||||
|
||||
if (mmd.flag & MOD_GREASE_PENCIL_WEIGHT_ANGLE_INVERT_OUTPUT) {
|
||||
weight = 1.0f - weight;
|
||||
}
|
||||
|
||||
dst_weights.span[point] = (mmd.flag & MOD_GREASE_PENCIL_WEIGHT_ANGLE_MULTIPLY_DATA) ?
|
||||
dst_weights.span[point] * weight :
|
||||
weight;
|
||||
dst_weights.span[point] = math::clamp(dst_weights.span[point], mmd.min_weight, 1.0f);
|
||||
}
|
||||
/* First point has the same weight as the second one. */
|
||||
dst_weights.span[points[0]] = dst_weights.span[points[1]];
|
||||
});
|
||||
|
||||
dst_weights.finish();
|
||||
}
|
||||
|
||||
static void modify_geometry_set(ModifierData *md,
|
||||
const ModifierEvalContext *ctx,
|
||||
bke::GeometrySet *geometry_set)
|
||||
{
|
||||
const GreasePencilWeightAngleModifierData *mmd =
|
||||
reinterpret_cast<GreasePencilWeightAngleModifierData *>(md);
|
||||
|
||||
if (!geometry_set->has_grease_pencil()) {
|
||||
return;
|
||||
}
|
||||
|
||||
GreasePencil &grease_pencil = *geometry_set->get_grease_pencil_for_write();
|
||||
|
||||
if (!target_vertex_group_available(mmd->target_vgname, grease_pencil.vertex_group_names)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int current_frame = grease_pencil.runtime->eval_frame;
|
||||
|
||||
IndexMaskMemory mask_memory;
|
||||
const IndexMask layer_mask = modifier::greasepencil::get_filtered_layer_mask(
|
||||
grease_pencil, mmd->influence, mask_memory);
|
||||
const Vector<bke::greasepencil::Drawing *> drawings =
|
||||
modifier::greasepencil::get_drawings_for_write(grease_pencil, layer_mask, current_frame);
|
||||
|
||||
threading::parallel_for_each(drawings, [&](bke::greasepencil::Drawing *drawing) {
|
||||
write_weights_for_drawing(*md, *ctx->object, *drawing);
|
||||
});
|
||||
}
|
||||
|
||||
static void panel_draw(const bContext *C, Panel *panel)
|
||||
{
|
||||
uiLayout *row, *sub;
|
||||
uiLayout *layout = panel->layout;
|
||||
|
||||
PointerRNA ob_ptr;
|
||||
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
|
||||
|
||||
uiLayoutSetPropSep(layout, true);
|
||||
|
||||
row = uiLayoutRow(layout, true);
|
||||
uiItemPointerR(row, ptr, "target_vertex_group", &ob_ptr, "vertex_groups", nullptr, ICON_NONE);
|
||||
|
||||
sub = uiLayoutRow(row, true);
|
||||
bool has_output = RNA_string_length(ptr, "target_vertex_group") != 0;
|
||||
uiLayoutSetPropDecorate(sub, false);
|
||||
uiLayoutSetActive(sub, has_output);
|
||||
uiItemR(sub, ptr, "use_invert_output", UI_ITEM_NONE, "", ICON_ARROW_LEFTRIGHT);
|
||||
|
||||
uiItemR(layout, ptr, "angle", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
uiItemR(layout, ptr, "axis", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
uiItemR(layout, ptr, "space", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
|
||||
uiItemR(layout, ptr, "minimum_weight", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
uiItemR(layout, ptr, "use_multiply", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
|
||||
if (uiLayout *influence_panel = uiLayoutPanelProp(
|
||||
C, layout, ptr, "open_influence_panel", "Influence"))
|
||||
{
|
||||
modifier::greasepencil::draw_layer_filter_settings(C, influence_panel, ptr);
|
||||
modifier::greasepencil::draw_material_filter_settings(C, influence_panel, ptr);
|
||||
modifier::greasepencil::draw_vertex_group_settings(C, influence_panel, ptr);
|
||||
}
|
||||
|
||||
modifier_panel_end(layout, ptr);
|
||||
}
|
||||
|
||||
static void panel_register(ARegionType *region_type)
|
||||
{
|
||||
modifier_panel_register(region_type, eModifierType_GreasePencilWeightAngle, panel_draw);
|
||||
}
|
||||
|
||||
} // namespace blender
|
||||
|
||||
ModifierTypeInfo modifierType_GreasePencilWeightAngle = {
|
||||
/*idname*/ "GreasePencilWeightAngleModifier",
|
||||
/*name*/ N_("Weight Angle"),
|
||||
/*struct_name*/ "GreasePencilWeightAngleModifierData",
|
||||
/*struct_size*/ sizeof(GreasePencilWeightAngleModifierData),
|
||||
/*srna*/ &RNA_GreasePencilWeightAngleModifier,
|
||||
/*type*/ ModifierTypeType::NonGeometrical,
|
||||
/*flags*/
|
||||
eModifierTypeFlag_AcceptsGreasePencil | eModifierTypeFlag_SupportsEditmode |
|
||||
eModifierTypeFlag_EnableInEditmode | eModifierTypeFlag_SupportsMapping,
|
||||
/*icon*/ ICON_MOD_VERTEX_WEIGHT,
|
||||
|
||||
/*copy_data*/ blender::copy_data,
|
||||
|
||||
/*deform_verts*/ nullptr,
|
||||
/*deform_matrices*/ nullptr,
|
||||
/*deform_verts_EM*/ nullptr,
|
||||
/*deform_matrices_EM*/ nullptr,
|
||||
/*modify_mesh*/ nullptr,
|
||||
/*modify_geometry_set*/ blender::modify_geometry_set,
|
||||
|
||||
/*init_data*/ blender::init_data,
|
||||
/*required_data_mask*/ nullptr,
|
||||
/*free_data*/ blender::free_data,
|
||||
/*is_disabled*/ blender::is_disabled,
|
||||
/*update_depsgraph*/ nullptr,
|
||||
/*depends_on_time*/ nullptr,
|
||||
/*depends_on_normals*/ nullptr,
|
||||
/*foreach_ID_link*/ blender::foreach_ID_link,
|
||||
/*foreach_tex_link*/ nullptr,
|
||||
/*free_runtime_data*/ nullptr,
|
||||
/*panel_register*/ blender::panel_register,
|
||||
/*blend_write*/ blender::blend_write,
|
||||
/*blend_read*/ blender::blend_read,
|
||||
};
|
|
@ -277,5 +277,7 @@ void modifier_type_init(ModifierTypeInfo *types[])
|
|||
INIT_TYPE(GreasePencilDash);
|
||||
INIT_TYPE(GreasePencilMultiply);
|
||||
INIT_TYPE(GreasePencilLength);
|
||||
INIT_TYPE(GreasePencilWeightAngle);
|
||||
INIT_TYPE(GreasePencilArray);
|
||||
#undef INIT_TYPE
|
||||
}
|
||||
|
|
|
@ -76,6 +76,17 @@ static void node_composit_buts_denoise(uiLayout *layout, bContext * /*C*/, Point
|
|||
|
||||
using namespace blender::realtime_compositor;
|
||||
|
||||
/* A callback to cancel the filter operations by evaluating the context's is_canceled method. The
|
||||
* API specifies that true indicates the filter should continue, while false indicates it should
|
||||
* stop, so invert the condition. This callback can also be used to track progress using the given
|
||||
* n argument, but we currently don't make use of it. See OIDNProgressMonitorFunction in the API
|
||||
* for more information. */
|
||||
[[maybe_unused]] static bool oidn_progress_monitor_function(void *user_ptr, double /*n*/)
|
||||
{
|
||||
const Context *context = static_cast<const Context *>(user_ptr);
|
||||
return !context->is_canceled();
|
||||
}
|
||||
|
||||
class DenoiseOperation : public NodeOperation {
|
||||
public:
|
||||
using NodeOperation::NodeOperation;
|
||||
|
@ -108,6 +119,7 @@ class DenoiseOperation : public NodeOperation {
|
|||
filter.setImage("output", color, oidn::Format::Float3, width, height, 0, pixel_stride);
|
||||
filter.set("hdr", use_hdr());
|
||||
filter.set("cleanAux", auxiliary_passes_are_clean());
|
||||
filter.setProgressMonitorFunction(oidn_progress_monitor_function, &context());
|
||||
|
||||
/* If the albedo input is not a single value input, download the albedo texture, denoise it
|
||||
* in-place if denoising auxiliary passes is needed, and set it to the main filter. */
|
||||
|
@ -122,6 +134,7 @@ class DenoiseOperation : public NodeOperation {
|
|||
"albedo", albedo, oidn::Format::Float3, width, height, 0, pixel_stride);
|
||||
albedoFilter.setImage(
|
||||
"output", albedo, oidn::Format::Float3, width, height, 0, pixel_stride);
|
||||
albedoFilter.setProgressMonitorFunction(oidn_progress_monitor_function, &context());
|
||||
albedoFilter.commit();
|
||||
albedoFilter.execute();
|
||||
}
|
||||
|
@ -144,6 +157,7 @@ class DenoiseOperation : public NodeOperation {
|
|||
"normal", normal, oidn::Format::Float3, width, height, 0, pixel_stride);
|
||||
normalFilter.setImage(
|
||||
"output", normal, oidn::Format::Float3, width, height, 0, pixel_stride);
|
||||
normalFilter.setProgressMonitorFunction(oidn_progress_monitor_function, &context());
|
||||
normalFilter.commit();
|
||||
normalFilter.execute();
|
||||
}
|
||||
|
|
|
@ -1373,7 +1373,7 @@ int WM_operator_flag_only_pass_through_on_press(int retval, const wmEvent *event
|
|||
* Note that \a poin should be valid allocated and not on stack.
|
||||
*/
|
||||
void WM_event_start_drag(
|
||||
bContext *C, int icon, eWM_DragDataType type, void *poin, double value, unsigned int flags);
|
||||
bContext *C, int icon, eWM_DragDataType type, void *poin, unsigned int flags);
|
||||
/**
|
||||
* Create and fill the dragging data, but don't start dragging just yet (unlike
|
||||
* #WM_event_start_drag()). Must be followed up by #WM_event_start_prepared_drag(), otherwise the
|
||||
|
@ -1382,7 +1382,7 @@ void WM_event_start_drag(
|
|||
* Note that \a poin should be valid allocated and not on stack.
|
||||
*/
|
||||
wmDrag *WM_drag_data_create(
|
||||
bContext *C, int icon, eWM_DragDataType type, void *poin, double value, unsigned int flags);
|
||||
bContext *C, int icon, eWM_DragDataType type, void *poin, unsigned int flags);
|
||||
/**
|
||||
* Invoke dragging using the given \a drag data.
|
||||
*/
|
||||
|
@ -1496,6 +1496,9 @@ bool WM_drag_has_path_file_type(const wmDrag *drag, int file_type);
|
|||
*/
|
||||
int /* #eFileSel_File_Types */ WM_drag_get_path_file_type(const wmDrag *drag);
|
||||
|
||||
const std::string &WM_drag_get_string(const wmDrag *drag);
|
||||
std::string WM_drag_get_string_firstline(const wmDrag *drag);
|
||||
|
||||
/* Set OpenGL viewport and scissor */
|
||||
void wmViewport(const rcti *winrct);
|
||||
void wmPartialViewport(rcti *drawrct, const rcti *winrct, const rcti *partialrct);
|
||||
|
|
|
@ -1143,7 +1143,14 @@ enum eWM_DragDataType {
|
|||
WM_DRAG_RNA,
|
||||
WM_DRAG_PATH,
|
||||
WM_DRAG_NAME,
|
||||
WM_DRAG_VALUE,
|
||||
/**
|
||||
* Arbitrary text such as dragging from a text editor,
|
||||
* this is also used when dragging a URL from a browser.
|
||||
*
|
||||
* An #std::string expected to be UTF8 encoded.
|
||||
* Callers that require valid UTF8 sequences must validate the text.
|
||||
*/
|
||||
WM_DRAG_STRING,
|
||||
WM_DRAG_COLOR,
|
||||
WM_DRAG_DATASTACK,
|
||||
WM_DRAG_ASSET_CATALOG,
|
||||
|
@ -1255,7 +1262,6 @@ struct wmDrag {
|
|||
int icon;
|
||||
eWM_DragDataType type;
|
||||
void *poin;
|
||||
double value;
|
||||
|
||||
/** If no icon but imbuf should be drawn around cursor. */
|
||||
const ImBuf *imb;
|
||||
|
|
|
@ -258,8 +258,7 @@ static void wm_dropbox_invoke(bContext *C, wmDrag *drag)
|
|||
}
|
||||
}
|
||||
|
||||
wmDrag *WM_drag_data_create(
|
||||
bContext *C, int icon, eWM_DragDataType type, void *poin, double value, uint flags)
|
||||
wmDrag *WM_drag_data_create(bContext *C, int icon, eWM_DragDataType type, void *poin, uint flags)
|
||||
{
|
||||
wmDrag *drag = MEM_new<wmDrag>(__func__);
|
||||
|
||||
|
@ -302,7 +301,6 @@ wmDrag *WM_drag_data_create(
|
|||
drag->poin = poin;
|
||||
break;
|
||||
}
|
||||
drag->value = value;
|
||||
|
||||
return drag;
|
||||
}
|
||||
|
@ -315,10 +313,9 @@ void WM_event_start_prepared_drag(bContext *C, wmDrag *drag)
|
|||
wm_dropbox_invoke(C, drag);
|
||||
}
|
||||
|
||||
void WM_event_start_drag(
|
||||
bContext *C, int icon, eWM_DragDataType type, void *poin, double value, uint flags)
|
||||
void WM_event_start_drag(bContext *C, int icon, eWM_DragDataType type, void *poin, uint flags)
|
||||
{
|
||||
wmDrag *drag = WM_drag_data_create(C, icon, type, poin, value, flags);
|
||||
wmDrag *drag = WM_drag_data_create(C, icon, type, poin, flags);
|
||||
WM_event_start_prepared_drag(C, drag);
|
||||
}
|
||||
|
||||
|
@ -382,6 +379,11 @@ void WM_drag_data_free(eWM_DragDataType dragtype, void *poin)
|
|||
wm_drag_free_path_data(&path_data);
|
||||
break;
|
||||
}
|
||||
case WM_DRAG_STRING: {
|
||||
std::string *str = static_cast<std::string *>(poin);
|
||||
MEM_delete(str);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
MEM_freeN(poin);
|
||||
break;
|
||||
|
@ -920,6 +922,24 @@ int WM_drag_get_path_file_type(const wmDrag *drag)
|
|||
return path_data->file_types[0];
|
||||
}
|
||||
|
||||
const std::string &WM_drag_get_string(const wmDrag *drag)
|
||||
{
|
||||
BLI_assert(drag->type == WM_DRAG_STRING);
|
||||
const std::string *str = static_cast<const std::string *>(drag->poin);
|
||||
return *str;
|
||||
}
|
||||
|
||||
std::string WM_drag_get_string_firstline(const wmDrag *drag)
|
||||
{
|
||||
BLI_assert(drag->type == WM_DRAG_STRING);
|
||||
const std::string *str = static_cast<const std::string *>(drag->poin);
|
||||
const size_t str_eol = str->find('\n');
|
||||
if (str_eol != std::string::npos) {
|
||||
return str->substr(0, str_eol);
|
||||
}
|
||||
return *str;
|
||||
}
|
||||
|
||||
/* ************** draw ***************** */
|
||||
|
||||
static void wm_drop_operator_draw(const blender::StringRef name, int x, int y)
|
||||
|
|
|
@ -1663,10 +1663,15 @@ static bool ghost_event_proc(GHOST_EventHandle ghost_event, GHOST_TUserDataPtr C
|
|||
int icon = ED_file_extension_icon((char *)stra->strings[0]);
|
||||
wmDragPath *path_data = WM_drag_create_path_data(
|
||||
blender::Span((char **)stra->strings, stra->count));
|
||||
WM_event_start_drag(C, icon, WM_DRAG_PATH, path_data, 0.0, WM_DRAG_NOP);
|
||||
WM_event_start_drag(C, icon, WM_DRAG_PATH, path_data, WM_DRAG_NOP);
|
||||
/* Void pointer should point to string, it makes a copy. */
|
||||
}
|
||||
}
|
||||
else if (ddd->dataType == GHOST_kDragnDropTypeString) {
|
||||
/* Drop an arbitrary string. */
|
||||
std::string *str = MEM_new<std::string>(__func__, static_cast<const char *>(ddd->data));
|
||||
WM_event_start_drag(C, ICON_NONE, WM_DRAG_STRING, str, WM_DRAG_FREE_DATA);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -1227,7 +1227,7 @@ static int arg_handle_debug_gpu_set(int /*argc*/, const char ** /*argv*/, void *
|
|||
|
||||
static const char arg_handle_debug_gpu_compile_shaders_set_doc[] =
|
||||
"\n"
|
||||
"\tCompile all staticly defined shaders to test platform compatibility.";
|
||||
"\tCompile all statically defined shaders to test platform compatibility.";
|
||||
static int arg_handle_debug_gpu_compile_shaders_set(int /*argc*/,
|
||||
const char ** /*argv*/,
|
||||
void * /*data*/)
|
||||
|
|
Loading…
Reference in New Issue