UI Code Quality: Rename UI_ACTIVE
button flag to UI_HOVER
#114113
|
@ -37,6 +37,16 @@ else()
|
|||
PREFIX ${BUILD_DIR}/ssl
|
||||
CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/ssl/src/external_ssl/ && ${SSL_CONFIGURE_COMMAND} --prefix=${LIBDIR}/ssl
|
||||
--openssldir=${LIBDIR}/ssl
|
||||
# Without this: Python will use the build directories:
|
||||
# To see these values in use, check the output of `ssl.get_default_verify_paths()`.
|
||||
# This definition causes the following values to be set:
|
||||
# - `capath='/etc/ssl/certs'`
|
||||
# - `openssl_cafile='/etc/ssl/cert.pem'`
|
||||
# - `openssl_capath='/etc/ssl/certs'`
|
||||
# Note that the output from the command `openssl info -configdir` on the users system
|
||||
# would be ideal but this is more involved.
|
||||
# See #111132 & https://github.com/openssl/openssl/issues/20185 for details.
|
||||
-DOPENSSLDIR=\\"/etc/ssl\\"
|
||||
no-shared
|
||||
no-idea no-mdc2 no-rc5 no-zlib no-ssl3 enable-unit-test no-ssl3-method enable-rfc3779 enable-cms
|
||||
--config=${CMAKE_CURRENT_SOURCE_DIR}/cmake/ssl.conf
|
||||
|
|
|
@ -26,6 +26,7 @@ class MetalDevice : public Device {
|
|||
id<MTLLibrary> mtlLibrary[PSO_NUM] = {nil};
|
||||
id<MTLArgumentEncoder> mtlBufferKernelParamsEncoder =
|
||||
nil; /* encoder used for fetching device pointers from MTLBuffers */
|
||||
id<MTLCommandQueue> mtlComputeCommandQueue = nil;
|
||||
id<MTLCommandQueue> mtlGeneralCommandQueue = nil;
|
||||
id<MTLArgumentEncoder> mtlAncillaryArgEncoder =
|
||||
nil; /* encoder used for fetching device pointers from MTLBuffers */
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -6377,7 +6377,9 @@ GHOST_TSuccess GHOST_SystemWayland::getModifierKeys(GHOST_ModifierKeys &keys) co
|
|||
/* NOTE(@ideasman42): it's important to write the XKB state back to #GWL_KeyboardDepressedState
|
||||
* otherwise changes to modifiers in the future wont generate events.
|
||||
* This can cause modifiers to be stuck when switching between windows in GNOME because
|
||||
* window activation is handled before the keyboard enter callback runs, see: #107314. */
|
||||
* window activation is handled before the keyboard enter callback runs, see: #107314.
|
||||
* Now resolved upstream, keep this for GNOME 45 and older releases & misbehaving compositors
|
||||
* as the workaround doesn't have significant down-sides. */
|
||||
int16_t &depressed_l = seat->key_depressed.mods[GHOST_KEY_MODIFIER_TO_INDEX(mod_info.key_l)];
|
||||
int16_t &depressed_r = seat->key_depressed.mods[GHOST_KEY_MODIFIER_TO_INDEX(mod_info.key_r)];
|
||||
bool val_l = depressed_l > 0;
|
||||
|
|
|
@ -73,6 +73,8 @@ struct WGL_LibDecor_Window {
|
|||
|
||||
/** The window has been configured (see #xdg_surface_ack_configure). */
|
||||
bool initial_configure_seen = false;
|
||||
/** The window state has been configured. */
|
||||
bool initial_state_seen = false;
|
||||
};
|
||||
|
||||
static void gwl_libdecor_window_destroy(WGL_LibDecor_Window *decor)
|
||||
|
@ -1274,7 +1276,14 @@ static void libdecor_frame_handle_configure(libdecor_frame *frame,
|
|||
* #wp_fractional_scale_v1_listener::preferred_scale provides fractional scaling values. */
|
||||
decor.scale_fractional_from_output = 0;
|
||||
|
||||
decor.initial_configure_seen = true;
|
||||
if (decor.initial_configure_seen == false) {
|
||||
decor.initial_configure_seen = true;
|
||||
}
|
||||
else {
|
||||
if (decor.initial_state_seen == false) {
|
||||
decor.initial_state_seen = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1614,7 +1623,21 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
|
|||
}
|
||||
|
||||
xdg_toplevel *toplevel = libdecor_frame_get_xdg_toplevel(decor.frame);
|
||||
gwl_window_state_set_for_xdg(toplevel, state, GHOST_kWindowStateNormal);
|
||||
gwl_window_state_set_for_xdg(toplevel, state, gwl_window_state_get(window_));
|
||||
|
||||
/* Needed for maximize to use the size of the maximized frame instead of the size
|
||||
* from `width` & `height`, see #113961 (follow up comments). */
|
||||
int roundtrip_count = 0;
|
||||
while (!decor.initial_state_seen) {
|
||||
/* Use round-trip so as not to block in the case setting
|
||||
* the state is ignored by the compositor. */
|
||||
wl_display_roundtrip(system_->wl_display_get());
|
||||
/* Avoid waiting continuously if the requested state is ignored
|
||||
* (2x round-trips should be enough). */
|
||||
if (++roundtrip_count >= 2) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif /* WITH_GHOST_WAYLAND_LIBDECOR */
|
||||
|
|
|
@ -454,12 +454,9 @@ class NODE_PT_geometry_node_tool_object_types(Panel):
|
|||
col = layout.column()
|
||||
col.active = group.is_tool
|
||||
for prop, name, icon in types:
|
||||
row = col.row()
|
||||
row_checkbox = row.row()
|
||||
row_checkbox.prop(group, prop, text="")
|
||||
row_label = row.row()
|
||||
row_label.label(text=name, icon=icon)
|
||||
row_label.active = getattr(group, prop)
|
||||
row = col.row(align=True)
|
||||
row.label(text=name, icon=icon)
|
||||
row.prop(group, prop, text="")
|
||||
|
||||
|
||||
class NODE_PT_geometry_node_tool_mode(Panel):
|
||||
|
@ -482,12 +479,9 @@ class NODE_PT_geometry_node_tool_mode(Panel):
|
|||
col = layout.column()
|
||||
col.active = group.is_tool
|
||||
for prop, name, icon in modes:
|
||||
row = col.row()
|
||||
row_checkbox = row.row()
|
||||
row_checkbox.prop(group, prop, text="")
|
||||
row_label = row.row()
|
||||
row_label.label(text=name, icon=icon)
|
||||
row_label.active = getattr(group, prop)
|
||||
row = col.row(align=True)
|
||||
row.label(text=name, icon=icon)
|
||||
row.prop(group, prop, text="")
|
||||
|
||||
|
||||
class NODE_PT_node_color_presets(PresetPanel, Panel):
|
||||
|
|
|
@ -3520,7 +3520,7 @@ class VIEW3D_MT_paint_weight(Menu):
|
|||
class VIEW3D_MT_sculpt(Menu):
|
||||
bl_label = "Sculpt"
|
||||
|
||||
def draw(self, _context):
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
layout.operator("transform.translate")
|
||||
|
@ -3613,6 +3613,11 @@ class VIEW3D_MT_sculpt(Menu):
|
|||
# Rebuild BVH
|
||||
layout.operator("sculpt.optimize")
|
||||
|
||||
layout.operator(
|
||||
"sculpt.dynamic_topology_toggle",
|
||||
icon='CHECKBOX_HLT' if context.sculpt_object.use_dynamic_topology_sculpting else 'CHECKBOX_DEHLT',
|
||||
)
|
||||
|
||||
layout.separator()
|
||||
|
||||
layout.operator("object.transfer_mode", text="Transfer Sculpt Mode")
|
||||
|
|
|
@ -79,10 +79,15 @@ struct CustomDataLayer *BKE_id_attribute_find(const struct ID *id,
|
|||
eCustomDataType type,
|
||||
eAttrDomain domain);
|
||||
|
||||
struct CustomDataLayer *BKE_id_attribute_search(struct ID *id,
|
||||
const char *name,
|
||||
eCustomDataMask type,
|
||||
eAttrDomainMask domain_mask);
|
||||
const struct CustomDataLayer *BKE_id_attribute_search(const struct ID *id,
|
||||
const char *name,
|
||||
eCustomDataMask type,
|
||||
eAttrDomainMask domain_mask);
|
||||
|
||||
struct CustomDataLayer *BKE_id_attribute_search_for_write(struct ID *id,
|
||||
const char *name,
|
||||
eCustomDataMask type,
|
||||
eAttrDomainMask domain_mask);
|
||||
|
||||
eAttrDomain BKE_id_attribute_domain(const struct ID *id, const struct CustomDataLayer *layer);
|
||||
int BKE_id_attribute_data_length(struct ID *id, struct CustomDataLayer *layer);
|
||||
|
|
|
@ -158,7 +158,7 @@ static bool bke_id_attribute_rename_if_exists(ID *id,
|
|||
const char *new_name,
|
||||
ReportList *reports)
|
||||
{
|
||||
CustomDataLayer *layer = BKE_id_attribute_search(
|
||||
CustomDataLayer *layer = BKE_id_attribute_search_for_write(
|
||||
id, old_name, CD_MASK_PROP_ALL, ATTR_DOMAIN_MASK_ALL);
|
||||
if (layer == nullptr) {
|
||||
return false;
|
||||
|
@ -194,7 +194,7 @@ bool BKE_id_attribute_rename(ID *id,
|
|||
}
|
||||
}
|
||||
|
||||
CustomDataLayer *layer = BKE_id_attribute_search(
|
||||
CustomDataLayer *layer = BKE_id_attribute_search_for_write(
|
||||
id, old_name, CD_MASK_PROP_ALL, ATTR_DOMAIN_MASK_ALL);
|
||||
if (layer == nullptr) {
|
||||
BKE_report(reports, RPT_ERROR, "Attribute is not part of this geometry");
|
||||
|
@ -383,7 +383,7 @@ CustomDataLayer *BKE_id_attribute_duplicate(ID *id, const char *name, ReportList
|
|||
BKE_uv_map_pin_name_get(uniquename, buffer_dst));
|
||||
}
|
||||
|
||||
return BKE_id_attribute_search(id, uniquename, CD_MASK_PROP_ALL, ATTR_DOMAIN_MASK_ALL);
|
||||
return BKE_id_attribute_search_for_write(id, uniquename, CD_MASK_PROP_ALL, ATTR_DOMAIN_MASK_ALL);
|
||||
}
|
||||
|
||||
static int color_name_to_index(ID *id, const char *name)
|
||||
|
@ -540,10 +540,10 @@ CustomDataLayer *BKE_id_attribute_find(const ID *id,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
CustomDataLayer *BKE_id_attribute_search(ID *id,
|
||||
const char *name,
|
||||
const eCustomDataMask type_mask,
|
||||
const eAttrDomainMask domain_mask)
|
||||
const CustomDataLayer *BKE_id_attribute_search(const ID *id,
|
||||
const char *name,
|
||||
const eCustomDataMask type_mask,
|
||||
const eAttrDomainMask domain_mask)
|
||||
{
|
||||
if (!name) {
|
||||
return nullptr;
|
||||
|
@ -574,6 +574,28 @@ CustomDataLayer *BKE_id_attribute_search(ID *id,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
CustomDataLayer *BKE_id_attribute_search_for_write(ID *id,
|
||||
const char *name,
|
||||
const eCustomDataMask type_mask,
|
||||
const eAttrDomainMask domain_mask)
|
||||
{
|
||||
/* Reuse the implementation of the const version.
|
||||
* Implicit sharing for the layer's data is handled below. */
|
||||
CustomDataLayer *layer = const_cast<CustomDataLayer *>(
|
||||
BKE_id_attribute_search(id, name, type_mask, domain_mask));
|
||||
if (!layer) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DomainInfo info[ATTR_DOMAIN_NUM];
|
||||
get_domains(id, info);
|
||||
|
||||
const eAttrDomain domain = BKE_id_attribute_domain(id, layer);
|
||||
CustomData_ensure_data_is_mutable(layer, info[domain].length);
|
||||
|
||||
return layer;
|
||||
}
|
||||
|
||||
int BKE_id_attributes_length(const ID *id, eAttrDomainMask domain_mask, eCustomDataMask mask)
|
||||
{
|
||||
DomainInfo info[ATTR_DOMAIN_NUM];
|
||||
|
|
|
@ -677,7 +677,9 @@ GeometryDeformation get_evaluated_grease_pencil_drawing_deformation(const Object
|
|||
const GreasePencil &grease_pencil_orig = *static_cast<const GreasePencil *>(ob_orig.data);
|
||||
|
||||
const int eval_frame = grease_pencil.runtime->eval_frame;
|
||||
const int drawing_index = grease_pencil_orig.layers()[layer_index]->drawing_index_at(eval_frame);
|
||||
const Span<const bke::greasepencil::Layer *> layers_orig = grease_pencil_orig.layers();
|
||||
BLI_assert(layer_index >= 0 && layer_index < layers_orig.size());
|
||||
const int drawing_index = layers_orig[layer_index]->drawing_index_at(eval_frame);
|
||||
if (drawing_index == -1) {
|
||||
return {};
|
||||
}
|
||||
|
@ -707,11 +709,12 @@ GeometryDeformation get_evaluated_grease_pencil_drawing_deformation(const Object
|
|||
if (edit_hints != nullptr && &edit_hints->grease_pencil_id_orig == &grease_pencil_orig &&
|
||||
edit_hints->drawing_hints.has_value())
|
||||
{
|
||||
BLI_assert(edit_hints->drawing_hints->size() == grease_pencil_orig.layers().size());
|
||||
BLI_assert(edit_hints->drawing_hints->size() == layers_orig.size());
|
||||
const GreasePencilDrawingEditHints &drawing_hints =
|
||||
edit_hints->drawing_hints.value()[layer_index];
|
||||
if (drawing_hints.positions.has_value()) {
|
||||
deformation.positions = *drawing_hints.positions;
|
||||
return deformation;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -721,18 +724,21 @@ GeometryDeformation get_evaluated_grease_pencil_drawing_deformation(const Object
|
|||
{
|
||||
if (const GreasePencil *grease_pencil_eval = grease_pencil_component_eval->get()) {
|
||||
Span<const bke::greasepencil::Layer *> layers_eval = grease_pencil_eval->layers();
|
||||
const bke::greasepencil::Layer *layer_eval = layers_eval[layer_index];
|
||||
const int drawing_index_eval = layer_eval->drawing_index_at(eval_frame);
|
||||
if (drawing_index_eval != -1) {
|
||||
const GreasePencilDrawingBase *drawing_base_eval = grease_pencil_eval->drawing(
|
||||
drawing_index_eval);
|
||||
if (drawing_base_eval->type != GP_DRAWING) {
|
||||
return {};
|
||||
}
|
||||
const bke::greasepencil::Drawing &drawing_eval =
|
||||
reinterpret_cast<const GreasePencilDrawing *>(drawing_base_eval)->wrap();
|
||||
if (drawing_eval.strokes().points_num() == drawing_orig.strokes().points_num()) {
|
||||
deformation.positions = drawing_eval.strokes().positions();
|
||||
if (layers_eval.size() != layers_orig.size()) {
|
||||
const bke::greasepencil::Layer *layer_eval = layers_eval[layer_index];
|
||||
const int drawing_index_eval = layer_eval->drawing_index_at(eval_frame);
|
||||
if (drawing_index_eval != -1) {
|
||||
const GreasePencilDrawingBase *drawing_base_eval = grease_pencil_eval->drawing(
|
||||
drawing_index_eval);
|
||||
if (drawing_base_eval->type != GP_DRAWING) {
|
||||
return deformation;
|
||||
}
|
||||
const bke::greasepencil::Drawing &drawing_eval =
|
||||
reinterpret_cast<const GreasePencilDrawing *>(drawing_base_eval)->wrap();
|
||||
if (drawing_eval.strokes().points_num() == drawing_orig.strokes().points_num()) {
|
||||
deformation.positions = drawing_eval.strokes().positions();
|
||||
return deformation;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,14 @@
|
|||
|
||||
namespace blender::bke {
|
||||
|
||||
static int segments_num_no_duplicate_edge(const int points_num, const bool cyclic)
|
||||
{
|
||||
if (points_num <= 2) {
|
||||
return curves::segments_num(points_num, false);
|
||||
}
|
||||
return curves::segments_num(points_num, cyclic);
|
||||
}
|
||||
|
||||
static void fill_mesh_topology(const int vert_offset,
|
||||
const int edge_offset,
|
||||
const int face_offset,
|
||||
|
@ -36,7 +44,7 @@ static void fill_mesh_topology(const int vert_offset,
|
|||
MutableSpan<int> corner_edges,
|
||||
MutableSpan<int> face_offsets)
|
||||
{
|
||||
const int main_segment_num = curves::segments_num(main_point_num, main_cyclic);
|
||||
const int main_segment_num = segments_num_no_duplicate_edge(main_point_num, main_cyclic);
|
||||
const int profile_segment_num = curves::segments_num(profile_point_num, profile_cyclic);
|
||||
|
||||
if (profile_point_num == 1) {
|
||||
|
@ -46,7 +54,7 @@ static void fill_mesh_topology(const int vert_offset,
|
|||
edge[1] = vert_offset + i + 1;
|
||||
}
|
||||
|
||||
if (main_cyclic && main_segment_num > 1) {
|
||||
if (main_cyclic && main_segment_num > 2) {
|
||||
int2 &edge = edges[edge_offset + main_segment_num - 1];
|
||||
edge[0] = vert_offset + main_point_num - 1;
|
||||
edge[1] = vert_offset;
|
||||
|
@ -268,7 +276,7 @@ static ResultOffsets calculate_result_offsets(const CurvesInfo &info, const bool
|
|||
for (const int i_main : main_offsets.index_range()) {
|
||||
const bool main_cyclic = info.main_cyclic[i_main];
|
||||
const int main_point_num = main_offsets[i_main].size();
|
||||
const int main_segment_num = curves::segments_num(main_point_num, main_cyclic);
|
||||
const int main_segment_num = segments_num_no_duplicate_edge(main_point_num, main_cyclic);
|
||||
for (const int i_profile : profile_offsets.index_range()) {
|
||||
result.vert[mesh_index] = vert_offset;
|
||||
result.edge[mesh_index] = edge_offset;
|
||||
|
|
|
@ -1199,7 +1199,9 @@ void BKE_grease_pencil_data_update(Depsgraph *depsgraph, Scene *scene, Object *o
|
|||
grease_pencil_evaluate_modifiers(depsgraph, scene, object, geometry_set);
|
||||
|
||||
if (!geometry_set.has_grease_pencil()) {
|
||||
geometry_set.replace_grease_pencil(BKE_grease_pencil_new_nomain());
|
||||
GreasePencil *empty_grease_pencil = BKE_grease_pencil_new_nomain();
|
||||
empty_grease_pencil->runtime->eval_frame = int(DEG_get_ctime(depsgraph));
|
||||
geometry_set.replace_grease_pencil(empty_grease_pencil);
|
||||
}
|
||||
|
||||
/* For now the evaluated data is not const. We could use #get_grease_pencil_for_write, but that
|
||||
|
|
|
@ -805,17 +805,15 @@ void BKE_pbvh_update_mesh_pointers(PBVH *pbvh, Mesh *mesh)
|
|||
pbvh->looptri_faces = mesh->looptri_faces();
|
||||
|
||||
if (!pbvh->deformed) {
|
||||
/* Deformed positions not matching the original mesh are owned directly by the PBVH, and are
|
||||
/* Deformed data not matching the original mesh are owned directly by the PBVH, and are
|
||||
* set separately by #BKE_pbvh_vert_coords_apply. */
|
||||
pbvh->vert_positions = mesh->vert_positions_for_write();
|
||||
pbvh->vert_normals = mesh->vert_normals();
|
||||
pbvh->face_normals = mesh->face_normals();
|
||||
}
|
||||
|
||||
BKE_pbvh_update_hide_attributes_from_mesh(pbvh);
|
||||
|
||||
/* Make sure cached normals start out calculated. */
|
||||
pbvh->vert_normals = mesh->vert_normals();
|
||||
pbvh->face_normals = mesh->face_normals();
|
||||
|
||||
pbvh->vert_data = &mesh->vert_data;
|
||||
pbvh->loop_data = &mesh->loop_data;
|
||||
pbvh->face_data = &mesh->face_data;
|
||||
|
@ -1276,6 +1274,38 @@ static bool update_search(PBVHNode *node, const int flag)
|
|||
return true;
|
||||
}
|
||||
|
||||
static void normals_calc_faces(const Span<float3> positions,
|
||||
const blender::OffsetIndices<int> faces,
|
||||
const Span<int> corner_verts,
|
||||
const Span<int> mask,
|
||||
MutableSpan<float3> face_normals)
|
||||
{
|
||||
using namespace blender;
|
||||
using namespace blender::bke;
|
||||
threading::parallel_for(mask.index_range(), 512, [&](const IndexRange range) {
|
||||
for (const int i : mask.slice(range)) {
|
||||
face_normals[i] = mesh::face_normal_calc(positions, corner_verts.slice(faces[i]));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void normals_calc_verts_simple(const blender::GroupedSpan<int> vert_to_face_map,
|
||||
const Span<float3> face_normals,
|
||||
const Span<int> mask,
|
||||
MutableSpan<float3> vert_normals)
|
||||
{
|
||||
using namespace blender;
|
||||
threading::parallel_for(mask.index_range(), 1024, [&](const IndexRange range) {
|
||||
for (const int vert : mask.slice(range)) {
|
||||
float3 normal(0.0f);
|
||||
for (const int face : vert_to_face_map[vert]) {
|
||||
normal += face_normals[face];
|
||||
}
|
||||
vert_normals[vert] = math::normalize(normal);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void pbvh_faces_update_normals(PBVH *pbvh, Span<PBVHNode *> nodes, Mesh &mesh)
|
||||
{
|
||||
using namespace blender;
|
||||
|
@ -1302,13 +1332,17 @@ static void pbvh_faces_update_normals(PBVH *pbvh, Span<PBVHNode *> nodes, Mesh &
|
|||
VectorSet<int> verts_to_update;
|
||||
threading::parallel_invoke(
|
||||
[&]() {
|
||||
mesh.runtime->face_normals_cache.update([&](Vector<float3> &r_data) {
|
||||
threading::parallel_for(faces_to_update.index_range(), 512, [&](const IndexRange range) {
|
||||
for (const int i : faces_to_update.as_span().slice(range)) {
|
||||
r_data[i] = mesh::face_normal_calc(positions, corner_verts.slice(faces[i]));
|
||||
}
|
||||
if (pbvh->deformed) {
|
||||
normals_calc_faces(
|
||||
positions, faces, corner_verts, faces_to_update, pbvh->face_normals_deformed);
|
||||
}
|
||||
else {
|
||||
mesh.runtime->face_normals_cache.update([&](Vector<float3> &r_data) {
|
||||
normals_calc_faces(positions, faces, corner_verts, faces_to_update, r_data);
|
||||
});
|
||||
});
|
||||
/* #SharedCache::update() reallocates cached vectors if they were shared initially. */
|
||||
pbvh->face_normals = mesh.runtime->face_normals_cache.data();
|
||||
}
|
||||
},
|
||||
[&]() {
|
||||
/* Update all normals connected to affected faces, even if not explicitly tagged. */
|
||||
|
@ -1325,22 +1359,16 @@ static void pbvh_faces_update_normals(PBVH *pbvh, Span<PBVHNode *> nodes, Mesh &
|
|||
}
|
||||
});
|
||||
|
||||
const Span<float3> face_normals = mesh.face_normals();
|
||||
mesh.runtime->vert_normals_cache.update([&](Vector<float3> &r_data) {
|
||||
threading::parallel_for(verts_to_update.index_range(), 1024, [&](const IndexRange range) {
|
||||
for (const int vert : verts_to_update.as_span().slice(range)) {
|
||||
float3 normal(0.0f);
|
||||
for (const int face : pbvh->pmap[vert]) {
|
||||
normal += face_normals[face];
|
||||
}
|
||||
r_data[vert] = math::normalize(normal);
|
||||
}
|
||||
if (pbvh->deformed) {
|
||||
normals_calc_verts_simple(
|
||||
pbvh->pmap, pbvh->face_normals, verts_to_update, pbvh->vert_normals_deformed);
|
||||
}
|
||||
else {
|
||||
mesh.runtime->vert_normals_cache.update([&](Vector<float3> &r_data) {
|
||||
normals_calc_verts_simple(pbvh->pmap, pbvh->face_normals, verts_to_update, r_data);
|
||||
});
|
||||
});
|
||||
|
||||
/* #SharedCache::update() reallocates the cached vectors if they were shared initially. */
|
||||
pbvh->face_normals = mesh.runtime->face_normals_cache.data();
|
||||
pbvh->vert_normals = mesh.runtime->vert_normals_cache.data();
|
||||
pbvh->vert_normals = mesh.runtime->vert_normals_cache.data();
|
||||
}
|
||||
}
|
||||
|
||||
static void node_update_mask_redraw(PBVH &pbvh, PBVHNode &node)
|
||||
|
@ -1402,7 +1430,7 @@ static void pbvh_update_BB_redraw(PBVH *pbvh, Span<PBVHNode *> nodes, int flag)
|
|||
|
||||
bool BKE_pbvh_get_color_layer(Mesh *me, CustomDataLayer **r_layer, eAttrDomain *r_domain)
|
||||
{
|
||||
*r_layer = BKE_id_attribute_search(
|
||||
*r_layer = BKE_id_attribute_search_for_write(
|
||||
&me->id, me->active_color_attribute, CD_MASK_COLOR_ALL, ATTR_DOMAIN_MASK_COLOR);
|
||||
*r_domain = *r_layer ? BKE_id_attribute_domain(&me->id, *r_layer) : ATTR_DOMAIN_POINT;
|
||||
return *r_layer != nullptr;
|
||||
|
@ -2967,14 +2995,21 @@ void BKE_pbvh_vert_coords_apply(PBVH *pbvh, const float (*vertCos)[3], const int
|
|||
|
||||
if (!pbvh->deformed) {
|
||||
if (!pbvh->vert_positions.is_empty()) {
|
||||
/* if pbvh is not already deformed, verts/faces points to the */
|
||||
/* original data and applying new coords to this arrays would lead to */
|
||||
/* unneeded deformation -- duplicate verts/faces to avoid this */
|
||||
pbvh->vert_positions_deformed = blender::Array<float3>(pbvh->vert_positions.as_span());
|
||||
/* When the PBVH is deformed, it creates a separate vertex position array that it owns
|
||||
* directly. Conceptually these copies often aren't and often adds extra indirection, but:
|
||||
* - Sculpting shape keys, the deformations are flushed back to the keys as a separate step.
|
||||
* - Sculpting on a deformed mesh, deformations are also flushed to original positions
|
||||
* separately.
|
||||
* - The PBVH currently always assumes we want to change positions, and has no way to avoid
|
||||
* calculating normals if it's only used for painting, for example. */
|
||||
pbvh->vert_positions_deformed = pbvh->vert_positions.as_span();
|
||||
pbvh->vert_positions = pbvh->vert_positions_deformed;
|
||||
|
||||
/* No need to dupalloc pbvh->looptri, this one is 'totally owned' by pbvh,
|
||||
* it's never some mesh data. */
|
||||
pbvh->vert_normals_deformed = pbvh->vert_normals;
|
||||
pbvh->vert_normals = pbvh->vert_normals_deformed;
|
||||
|
||||
pbvh->face_normals_deformed = pbvh->face_normals;
|
||||
pbvh->face_normals = pbvh->face_normals_deformed;
|
||||
|
||||
pbvh->deformed = true;
|
||||
}
|
||||
|
|
|
@ -154,13 +154,19 @@ struct PBVH {
|
|||
/* Mesh data */
|
||||
Mesh *mesh;
|
||||
|
||||
/** Local array used when not sculpting base mesh positions directly. */
|
||||
blender::Array<blender::float3> vert_positions_deformed;
|
||||
/** Local array used when not sculpting base mesh positions directly. */
|
||||
blender::Array<blender::float3> vert_normals_deformed;
|
||||
/** Local array used when not sculpting base mesh positions directly. */
|
||||
blender::Array<blender::float3> face_normals_deformed;
|
||||
|
||||
blender::MutableSpan<blender::float3> vert_positions;
|
||||
blender::Span<blender::float3> vert_normals;
|
||||
blender::Span<blender::float3> face_normals;
|
||||
bool *hide_vert;
|
||||
blender::MutableSpan<blender::float3> vert_positions;
|
||||
/** Local vertex positions owned by the PVBH when not sculpting base mesh positions directly. */
|
||||
blender::Array<blender::float3> vert_positions_deformed;
|
||||
|
||||
blender::OffsetIndices<int> faces;
|
||||
bool *hide_vert;
|
||||
bool *hide_poly;
|
||||
/** Only valid for polygon meshes. */
|
||||
blender::Span<int> corner_verts;
|
||||
|
|
|
@ -77,11 +77,10 @@ void transform(Context &context,
|
|||
}
|
||||
else {
|
||||
input.pass_through(output);
|
||||
const float3x3 translation_matrix = math::from_location<float3x3>(translation);
|
||||
output.transform(translation_matrix);
|
||||
}
|
||||
|
||||
/* Translation transformations are delayed and are only stored in the result. */
|
||||
const float3x3 translation_matrix = math::from_location<float3x3>(translation);
|
||||
output.transform(translation_matrix);
|
||||
output.get_realization_options().interpolation = interpolation;
|
||||
}
|
||||
|
||||
|
|
|
@ -747,12 +747,15 @@ void film_process_data(ivec2 texel_film, out vec4 out_color, out float out_depth
|
|||
ao_accum);
|
||||
film_sample_accum_mist(src, mist_accum);
|
||||
}
|
||||
/* Monochrome render passes that have colored outputs. Set alpha to 1. */
|
||||
vec4 shadow_accum_color = vec4(vec3(shadow_accum), weight_accum);
|
||||
vec4 ao_accum_color = vec4(vec3(ao_accum), weight_accum);
|
||||
|
||||
film_store_color(dst, uniform_buf.film.diffuse_color_id, diffuse_color_accum, out_color);
|
||||
film_store_color(dst, uniform_buf.film.specular_color_id, specular_color_accum, out_color);
|
||||
film_store_color(dst, uniform_buf.film.environment_id, environment_accum, out_color);
|
||||
film_store_color(dst, uniform_buf.film.shadow_id, vec4(vec3(shadow_accum), 1.0), out_color);
|
||||
film_store_color(
|
||||
dst, uniform_buf.film.ambient_occlusion_id, vec4(vec3(ao_accum), 1.0), out_color);
|
||||
film_store_color(dst, uniform_buf.film.shadow_id, shadow_accum_color, out_color);
|
||||
film_store_color(dst, uniform_buf.film.ambient_occlusion_id, ao_accum_color, out_color);
|
||||
film_store_value(dst, uniform_buf.film.mist_id, mist_accum, out_color);
|
||||
}
|
||||
|
||||
|
|
|
@ -745,7 +745,7 @@ void UI_panel_header_buttons_end(Panel *panel)
|
|||
/* Repurpose the first header button group if it is empty, in case the first button added to
|
||||
* the panel doesn't add a new group (if the button is created directly rather than through an
|
||||
* interface layout call). */
|
||||
if (block->button_groups.size() > 0) {
|
||||
if (block->button_groups.size() == 1 && button_group.buttons.is_empty()) {
|
||||
button_group.flag &= ~UI_BUTTON_GROUP_PANEL_HEADER;
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -59,7 +59,13 @@ struct EraseOperationExecutor {
|
|||
int2 mouse_position_pixels{};
|
||||
int64_t eraser_squared_radius_pixels{};
|
||||
|
||||
EraseOperationExecutor(const bContext & /*C*/) {}
|
||||
bke::greasepencil::DrawingTransforms transforms_;
|
||||
|
||||
EraseOperationExecutor(const bContext &C)
|
||||
{
|
||||
Object *object = CTX_data_active_object(&C);
|
||||
transforms_ = bke::greasepencil::DrawingTransforms(*object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the intersections between a 2D line segment and a circle with integer values.
|
||||
|
@ -759,10 +765,12 @@ struct EraseOperationExecutor {
|
|||
Array<float2> screen_space_positions(src.points_num());
|
||||
threading::parallel_for(src.points_range(), 4096, [&](const IndexRange src_points) {
|
||||
for (const int src_point : src_points) {
|
||||
ED_view3d_project_float_global(region,
|
||||
deformation.positions[src_point],
|
||||
screen_space_positions[src_point],
|
||||
V3D_PROJ_TEST_NOP);
|
||||
ED_view3d_project_float_global(
|
||||
region,
|
||||
math::transform_point(transforms_.layer_space_to_world_space,
|
||||
deformation.positions[src_point]),
|
||||
screen_space_positions[src_point],
|
||||
V3D_PROJ_TEST_NOP);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -1766,7 +1766,7 @@ static void sculpt_undo_set_active_layer(bContext *C, SculptAttrRef *attr)
|
|||
* domain and just unconvert it.
|
||||
*/
|
||||
if (!layer) {
|
||||
layer = BKE_id_attribute_search(&me->id, attr->name, CD_MASK_PROP_ALL, ATTR_DOMAIN_MASK_ALL);
|
||||
layer = BKE_id_attribute_search_for_write(&me->id, attr->name, CD_MASK_PROP_ALL, ATTR_DOMAIN_MASK_ALL);
|
||||
if (layer) {
|
||||
if (ED_geometry_attribute_convert(
|
||||
me, attr->name, eCustomDataType(attr->type), attr->domain, nullptr))
|
||||
|
|
|
@ -916,7 +916,7 @@ static TransConvertTypeInfo *convert_type_get(const TransInfo *t, Object **r_obj
|
|||
if (t->options & CTX_EDGE_DATA) {
|
||||
return &TransConvertType_MeshEdge;
|
||||
}
|
||||
if (t->options & CTX_GPENCIL_STROKES) {
|
||||
if ((t->options & CTX_GPENCIL_STROKES) && (t->spacetype == SPACE_VIEW3D)) {
|
||||
if (t->obedit_type == OB_GREASE_PENCIL) {
|
||||
return &TransConvertType_GreasePencil;
|
||||
}
|
||||
|
|
|
@ -6,69 +6,9 @@
|
|||
#pragma BLENDER_REQUIRE(gpu_shader_common_math_utils.glsl)
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_material_voronoi.glsl)
|
||||
|
||||
/* The fractalization logic is the same as for fBM Noise, except that some additions are replaced
|
||||
* by lerps. */
|
||||
#define FRACTAL_VORONOI_X_FX(T) \
|
||||
VoronoiOutput fractal_voronoi_x_fx(VoronoiParams params, T coord) \
|
||||
{ \
|
||||
float amplitude = 1.0; \
|
||||
float max_amplitude = 0.0; \
|
||||
float scale = 1.0; \
|
||||
\
|
||||
VoronoiOutput Output; \
|
||||
Output.Distance = 0.0; \
|
||||
Output.Color = vec3(0.0, 0.0, 0.0); \
|
||||
Output.Position = vec4(0.0, 0.0, 0.0, 0.0); \
|
||||
bool zero_input = params.detail == 0.0 || params.roughness == 0.0; \
|
||||
\
|
||||
for (int i = 0; i <= ceil(params.detail); ++i) { \
|
||||
VoronoiOutput octave; \
|
||||
if (params.feature == SHD_VORONOI_F2) { \
|
||||
octave = voronoi_f2(params, coord * scale); \
|
||||
} \
|
||||
else if (params.feature == SHD_VORONOI_SMOOTH_F1 && params.smoothness != 0.0) { \
|
||||
octave = voronoi_smooth_f1(params, coord * scale); \
|
||||
} \
|
||||
else { \
|
||||
octave = voronoi_f1(params, coord * scale); \
|
||||
} \
|
||||
\
|
||||
if (zero_input) { \
|
||||
max_amplitude = 1.0; \
|
||||
Output = octave; \
|
||||
break; \
|
||||
} \
|
||||
else if (i <= params.detail) { \
|
||||
max_amplitude += amplitude; \
|
||||
Output.Distance += octave.Distance * amplitude; \
|
||||
Output.Color += octave.Color * amplitude; \
|
||||
Output.Position = mix(Output.Position, octave.Position / scale, amplitude); \
|
||||
scale *= params.lacunarity; \
|
||||
amplitude *= params.roughness; \
|
||||
} \
|
||||
else { \
|
||||
float remainder = params.detail - floor(params.detail); \
|
||||
if (remainder != 0.0) { \
|
||||
max_amplitude = mix(max_amplitude, max_amplitude + amplitude, remainder); \
|
||||
Output.Distance = mix( \
|
||||
Output.Distance, Output.Distance + octave.Distance * amplitude, remainder); \
|
||||
Output.Color = mix(Output.Color, Output.Color + octave.Color * amplitude, remainder); \
|
||||
Output.Position = mix(Output.Position, \
|
||||
mix(Output.Position, octave.Position / scale, amplitude), \
|
||||
remainder); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
if (params.normalize) { \
|
||||
Output.Distance /= max_amplitude * params.max_distance; \
|
||||
Output.Color /= max_amplitude; \
|
||||
} \
|
||||
\
|
||||
Output.Position = safe_divide(Output.Position, params.scale); \
|
||||
\
|
||||
return Output; \
|
||||
}
|
||||
/* TODO(jbakker): Deduplicate code when OpenGL backend has been removed.
|
||||
* `fractal_voronoi_x_fx` functions are identical, except for the input parameter.
|
||||
* It used to be a macro, but didn't work on legacy drivers. */
|
||||
|
||||
/* The fractalization logic is the same as for fBM Noise, except that some additions are replaced
|
||||
* by lerps. */
|
||||
|
@ -115,24 +55,264 @@
|
|||
|
||||
/* **** 1D Fractal Voronoi **** */
|
||||
|
||||
FRACTAL_VORONOI_X_FX(float)
|
||||
/* The fractalization logic is the same as for fBM Noise, except that some additions are replaced
|
||||
* by lerps. */
|
||||
VoronoiOutput fractal_voronoi_x_fx(VoronoiParams params, float coord)
|
||||
{
|
||||
float amplitude = 1.0;
|
||||
float max_amplitude = 0.0;
|
||||
float scale = 1.0;
|
||||
|
||||
VoronoiOutput Output;
|
||||
Output.Distance = 0.0;
|
||||
Output.Color = vec3(0.0, 0.0, 0.0);
|
||||
Output.Position = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
bool zero_input = params.detail == 0.0 || params.roughness == 0.0;
|
||||
|
||||
for (int i = 0; i <= ceil(params.detail); ++i) {
|
||||
VoronoiOutput octave;
|
||||
if (params.feature == SHD_VORONOI_F2) {
|
||||
octave = voronoi_f2(params, coord * scale);
|
||||
}
|
||||
else if (params.feature == SHD_VORONOI_SMOOTH_F1 && params.smoothness != 0.0) {
|
||||
octave = voronoi_smooth_f1(params, coord * scale);
|
||||
}
|
||||
else {
|
||||
octave = voronoi_f1(params, coord * scale);
|
||||
}
|
||||
|
||||
if (zero_input) {
|
||||
max_amplitude = 1.0;
|
||||
Output = octave;
|
||||
break;
|
||||
}
|
||||
else if (i <= params.detail) {
|
||||
max_amplitude += amplitude;
|
||||
Output.Distance += octave.Distance * amplitude;
|
||||
Output.Color += octave.Color * amplitude;
|
||||
Output.Position = mix(Output.Position, octave.Position / scale, amplitude);
|
||||
scale *= params.lacunarity;
|
||||
amplitude *= params.roughness;
|
||||
}
|
||||
else {
|
||||
float remainder = params.detail - floor(params.detail);
|
||||
if (remainder != 0.0) {
|
||||
max_amplitude = mix(max_amplitude, max_amplitude + amplitude, remainder);
|
||||
Output.Distance = mix(
|
||||
Output.Distance, Output.Distance + octave.Distance * amplitude, remainder);
|
||||
Output.Color = mix(Output.Color, Output.Color + octave.Color * amplitude, remainder);
|
||||
Output.Position = mix(
|
||||
Output.Position, mix(Output.Position, octave.Position / scale, amplitude), remainder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (params.normalize) {
|
||||
Output.Distance /= max_amplitude * params.max_distance;
|
||||
Output.Color /= max_amplitude;
|
||||
}
|
||||
|
||||
Output.Position = safe_divide(Output.Position, params.scale);
|
||||
|
||||
return Output;
|
||||
}
|
||||
|
||||
FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(float)
|
||||
|
||||
/* **** 2D Fractal Voronoi **** */
|
||||
|
||||
FRACTAL_VORONOI_X_FX(vec2)
|
||||
/* The fractalization logic is the same as for fBM Noise, except that some additions are replaced
|
||||
* by lerps. */
|
||||
VoronoiOutput fractal_voronoi_x_fx(VoronoiParams params, vec2 coord)
|
||||
{
|
||||
float amplitude = 1.0;
|
||||
float max_amplitude = 0.0;
|
||||
float scale = 1.0;
|
||||
|
||||
VoronoiOutput Output;
|
||||
Output.Distance = 0.0;
|
||||
Output.Color = vec3(0.0, 0.0, 0.0);
|
||||
Output.Position = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
bool zero_input = params.detail == 0.0 || params.roughness == 0.0;
|
||||
|
||||
for (int i = 0; i <= ceil(params.detail); ++i) {
|
||||
VoronoiOutput octave;
|
||||
if (params.feature == SHD_VORONOI_F2) {
|
||||
octave = voronoi_f2(params, coord * scale);
|
||||
}
|
||||
else if (params.feature == SHD_VORONOI_SMOOTH_F1 && params.smoothness != 0.0) {
|
||||
octave = voronoi_smooth_f1(params, coord * scale);
|
||||
}
|
||||
else {
|
||||
octave = voronoi_f1(params, coord * scale);
|
||||
}
|
||||
|
||||
if (zero_input) {
|
||||
max_amplitude = 1.0;
|
||||
Output = octave;
|
||||
break;
|
||||
}
|
||||
else if (i <= params.detail) {
|
||||
max_amplitude += amplitude;
|
||||
Output.Distance += octave.Distance * amplitude;
|
||||
Output.Color += octave.Color * amplitude;
|
||||
Output.Position = mix(Output.Position, octave.Position / scale, amplitude);
|
||||
scale *= params.lacunarity;
|
||||
amplitude *= params.roughness;
|
||||
}
|
||||
else {
|
||||
float remainder = params.detail - floor(params.detail);
|
||||
if (remainder != 0.0) {
|
||||
max_amplitude = mix(max_amplitude, max_amplitude + amplitude, remainder);
|
||||
Output.Distance = mix(
|
||||
Output.Distance, Output.Distance + octave.Distance * amplitude, remainder);
|
||||
Output.Color = mix(Output.Color, Output.Color + octave.Color * amplitude, remainder);
|
||||
Output.Position = mix(
|
||||
Output.Position, mix(Output.Position, octave.Position / scale, amplitude), remainder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (params.normalize) {
|
||||
Output.Distance /= max_amplitude * params.max_distance;
|
||||
Output.Color /= max_amplitude;
|
||||
}
|
||||
|
||||
Output.Position = safe_divide(Output.Position, params.scale);
|
||||
|
||||
return Output;
|
||||
}
|
||||
|
||||
FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(vec2)
|
||||
|
||||
/* **** 3D Fractal Voronoi **** */
|
||||
|
||||
FRACTAL_VORONOI_X_FX(vec3)
|
||||
/* The fractalization logic is the same as for fBM Noise, except that some additions are replaced
|
||||
* by lerps. */
|
||||
VoronoiOutput fractal_voronoi_x_fx(VoronoiParams params, vec3 coord)
|
||||
{
|
||||
float amplitude = 1.0;
|
||||
float max_amplitude = 0.0;
|
||||
float scale = 1.0;
|
||||
|
||||
VoronoiOutput Output;
|
||||
Output.Distance = 0.0;
|
||||
Output.Color = vec3(0.0, 0.0, 0.0);
|
||||
Output.Position = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
bool zero_input = params.detail == 0.0 || params.roughness == 0.0;
|
||||
|
||||
for (int i = 0; i <= ceil(params.detail); ++i) {
|
||||
VoronoiOutput octave;
|
||||
if (params.feature == SHD_VORONOI_F2) {
|
||||
octave = voronoi_f2(params, coord * scale);
|
||||
}
|
||||
else if (params.feature == SHD_VORONOI_SMOOTH_F1 && params.smoothness != 0.0) {
|
||||
octave = voronoi_smooth_f1(params, coord * scale);
|
||||
}
|
||||
else {
|
||||
octave = voronoi_f1(params, coord * scale);
|
||||
}
|
||||
|
||||
if (zero_input) {
|
||||
max_amplitude = 1.0;
|
||||
Output = octave;
|
||||
break;
|
||||
}
|
||||
else if (i <= params.detail) {
|
||||
max_amplitude += amplitude;
|
||||
Output.Distance += octave.Distance * amplitude;
|
||||
Output.Color += octave.Color * amplitude;
|
||||
Output.Position = mix(Output.Position, octave.Position / scale, amplitude);
|
||||
scale *= params.lacunarity;
|
||||
amplitude *= params.roughness;
|
||||
}
|
||||
else {
|
||||
float remainder = params.detail - floor(params.detail);
|
||||
if (remainder != 0.0) {
|
||||
max_amplitude = mix(max_amplitude, max_amplitude + amplitude, remainder);
|
||||
Output.Distance = mix(
|
||||
Output.Distance, Output.Distance + octave.Distance * amplitude, remainder);
|
||||
Output.Color = mix(Output.Color, Output.Color + octave.Color * amplitude, remainder);
|
||||
Output.Position = mix(
|
||||
Output.Position, mix(Output.Position, octave.Position / scale, amplitude), remainder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (params.normalize) {
|
||||
Output.Distance /= max_amplitude * params.max_distance;
|
||||
Output.Color /= max_amplitude;
|
||||
}
|
||||
|
||||
Output.Position = safe_divide(Output.Position, params.scale);
|
||||
|
||||
return Output;
|
||||
}
|
||||
|
||||
FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(vec3)
|
||||
|
||||
/* **** 4D Fractal Voronoi **** */
|
||||
|
||||
FRACTAL_VORONOI_X_FX(vec4)
|
||||
/* The fractalization logic is the same as for fBM Noise, except that some additions are replaced
|
||||
* by lerps. */
|
||||
VoronoiOutput fractal_voronoi_x_fx(VoronoiParams params, vec4 coord)
|
||||
{
|
||||
float amplitude = 1.0;
|
||||
float max_amplitude = 0.0;
|
||||
float scale = 1.0;
|
||||
|
||||
VoronoiOutput Output;
|
||||
Output.Distance = 0.0;
|
||||
Output.Color = vec3(0.0, 0.0, 0.0);
|
||||
Output.Position = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
bool zero_input = params.detail == 0.0 || params.roughness == 0.0;
|
||||
|
||||
for (int i = 0; i <= ceil(params.detail); ++i) {
|
||||
VoronoiOutput octave;
|
||||
if (params.feature == SHD_VORONOI_F2) {
|
||||
octave = voronoi_f2(params, coord * scale);
|
||||
}
|
||||
else if (params.feature == SHD_VORONOI_SMOOTH_F1 && params.smoothness != 0.0) {
|
||||
octave = voronoi_smooth_f1(params, coord * scale);
|
||||
}
|
||||
else {
|
||||
octave = voronoi_f1(params, coord * scale);
|
||||
}
|
||||
|
||||
if (zero_input) {
|
||||
max_amplitude = 1.0;
|
||||
Output = octave;
|
||||
break;
|
||||
}
|
||||
else if (i <= params.detail) {
|
||||
max_amplitude += amplitude;
|
||||
Output.Distance += octave.Distance * amplitude;
|
||||
Output.Color += octave.Color * amplitude;
|
||||
Output.Position = mix(Output.Position, octave.Position / scale, amplitude);
|
||||
scale *= params.lacunarity;
|
||||
amplitude *= params.roughness;
|
||||
}
|
||||
else {
|
||||
float remainder = params.detail - floor(params.detail);
|
||||
if (remainder != 0.0) {
|
||||
max_amplitude = mix(max_amplitude, max_amplitude + amplitude, remainder);
|
||||
Output.Distance = mix(
|
||||
Output.Distance, Output.Distance + octave.Distance * amplitude, remainder);
|
||||
Output.Color = mix(Output.Color, Output.Color + octave.Color * amplitude, remainder);
|
||||
Output.Position = mix(
|
||||
Output.Position, mix(Output.Position, octave.Position / scale, amplitude), remainder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (params.normalize) {
|
||||
Output.Distance /= max_amplitude * params.max_distance;
|
||||
Output.Color /= max_amplitude;
|
||||
}
|
||||
|
||||
Output.Position = safe_divide(Output.Position, params.scale);
|
||||
|
||||
return Output;
|
||||
}
|
||||
|
||||
FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(vec4)
|
||||
|
|
|
@ -181,6 +181,12 @@ static std::optional<eCustomDataType> convert_usd_type_to_blender(
|
|||
map.add_new(pxr::SdfValueTypeNames->TexCoord3fArray, CD_PROP_FLOAT2);
|
||||
map.add_new(pxr::SdfValueTypeNames->TexCoord3hArray, CD_PROP_FLOAT2);
|
||||
map.add_new(pxr::SdfValueTypeNames->Float3Array, CD_PROP_FLOAT3);
|
||||
map.add_new(pxr::SdfValueTypeNames->Point3fArray, CD_PROP_FLOAT3);
|
||||
map.add_new(pxr::SdfValueTypeNames->Point3dArray, CD_PROP_FLOAT3);
|
||||
map.add_new(pxr::SdfValueTypeNames->Point3hArray, CD_PROP_FLOAT3);
|
||||
map.add_new(pxr::SdfValueTypeNames->Normal3fArray, CD_PROP_FLOAT3);
|
||||
map.add_new(pxr::SdfValueTypeNames->Normal3dArray, CD_PROP_FLOAT3);
|
||||
map.add_new(pxr::SdfValueTypeNames->Normal3hArray, CD_PROP_FLOAT3);
|
||||
map.add_new(pxr::SdfValueTypeNames->Vector3fArray, CD_PROP_FLOAT3);
|
||||
map.add_new(pxr::SdfValueTypeNames->Vector3hArray, CD_PROP_FLOAT3);
|
||||
map.add_new(pxr::SdfValueTypeNames->Vector3dArray, CD_PROP_FLOAT3);
|
||||
|
@ -190,6 +196,8 @@ static std::optional<eCustomDataType> convert_usd_type_to_blender(
|
|||
map.add_new(pxr::SdfValueTypeNames->StringArray, CD_PROP_STRING);
|
||||
map.add_new(pxr::SdfValueTypeNames->BoolArray, CD_PROP_BOOL);
|
||||
map.add_new(pxr::SdfValueTypeNames->QuatfArray, CD_PROP_QUATERNION);
|
||||
map.add_new(pxr::SdfValueTypeNames->QuatdArray, CD_PROP_QUATERNION);
|
||||
map.add_new(pxr::SdfValueTypeNames->QuathArray, CD_PROP_QUATERNION);
|
||||
return map;
|
||||
}();
|
||||
|
||||
|
@ -902,6 +910,11 @@ void USDMeshReader::read_custom_data(const ImportSettings *settings,
|
|||
continue;
|
||||
}
|
||||
|
||||
if (!pv.GetAttr().GetTypeName().IsArray()) {
|
||||
/* Non-array attributes are technically improper USD. */
|
||||
continue;
|
||||
}
|
||||
|
||||
const pxr::SdfValueTypeName type = pv.GetTypeName();
|
||||
const pxr::TfToken varying_type = pv.GetInterpolation();
|
||||
const pxr::TfToken name = pv.StripPrimvarsName(pv.GetPrimvarName());
|
||||
|
@ -914,6 +927,16 @@ void USDMeshReader::read_custom_data(const ImportSettings *settings,
|
|||
continue;
|
||||
}
|
||||
|
||||
if (ELEM(type,
|
||||
pxr::SdfValueTypeNames->StringArray,
|
||||
pxr::SdfValueTypeNames->QuatfArray,
|
||||
pxr::SdfValueTypeNames->QuatdArray,
|
||||
pxr::SdfValueTypeNames->QuathArray))
|
||||
{
|
||||
/* Skip creating known unsupported types, and avoid spammy error prints. */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Read Color primvars. */
|
||||
if (convert_usd_type_to_blender(type, reports()) == CD_PROP_COLOR) {
|
||||
if ((settings->read_flag & MOD_MESHSEQ_READ_COLOR) != 0) {
|
||||
|
|
|
@ -590,10 +590,11 @@ static void rna_AttributeGroup_update_active(Main *bmain, Scene *scene, PointerR
|
|||
static PointerRNA rna_AttributeGroup_active_color_get(PointerRNA *ptr)
|
||||
{
|
||||
ID *id = ptr->owner_id;
|
||||
CustomDataLayer *layer = BKE_id_attribute_search(ptr->owner_id,
|
||||
BKE_id_attributes_active_color_name(id),
|
||||
CD_MASK_COLOR_ALL,
|
||||
ATTR_DOMAIN_MASK_COLOR);
|
||||
CustomDataLayer *layer = BKE_id_attribute_search_for_write(
|
||||
ptr->owner_id,
|
||||
BKE_id_attributes_active_color_name(id),
|
||||
CD_MASK_COLOR_ALL,
|
||||
ATTR_DOMAIN_MASK_COLOR);
|
||||
|
||||
PointerRNA attribute_ptr = RNA_pointer_create(id, &RNA_Attribute, layer);
|
||||
return attribute_ptr;
|
||||
|
|
|
@ -1080,7 +1080,7 @@ DEFINE_CUSTOMDATA_LAYER_COLLECTION(vertex_color, ldata, CD_PROP_BYTE_COLOR)
|
|||
static PointerRNA rna_Mesh_vertex_color_active_get(PointerRNA *ptr)
|
||||
{
|
||||
Mesh *mesh = (Mesh *)ptr->data;
|
||||
CustomDataLayer *layer = BKE_id_attribute_search(
|
||||
CustomDataLayer *layer = BKE_id_attribute_search_for_write(
|
||||
&mesh->id, mesh->active_color_attribute, CD_MASK_PROP_BYTE_COLOR, ATTR_DOMAIN_MASK_CORNER);
|
||||
return rna_pointer_inherit_refine(ptr, &RNA_MeshLoopColorLayer, layer);
|
||||
}
|
||||
|
@ -1102,7 +1102,7 @@ static void rna_Mesh_vertex_color_active_set(PointerRNA *ptr,
|
|||
static int rna_Mesh_vertex_color_active_index_get(PointerRNA *ptr)
|
||||
{
|
||||
Mesh *mesh = (Mesh *)ptr->data;
|
||||
CustomDataLayer *layer = BKE_id_attribute_search(
|
||||
const CustomDataLayer *layer = BKE_id_attribute_search(
|
||||
&mesh->id, mesh->active_color_attribute, CD_MASK_PROP_BYTE_COLOR, ATTR_DOMAIN_MASK_CORNER);
|
||||
if (!layer) {
|
||||
return 0;
|
||||
|
|
|
@ -11,11 +11,11 @@
|
|||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BLI_kdtree.h"
|
||||
#include "BLI_map.hh"
|
||||
#include "BLI_math_matrix.h"
|
||||
#include "BLI_math_rotation.h"
|
||||
#include "BLI_math_vector.h"
|
||||
#include "BLI_rand.h"
|
||||
#include "BLI_vector_set.hh"
|
||||
|
||||
#include "BLT_translation.h"
|
||||
|
||||
|
@ -208,9 +208,9 @@ static void createFacepa(ExplodeModifierData *emd, ParticleSystemModifierData *p
|
|||
BLI_rng_free(rng);
|
||||
}
|
||||
|
||||
static int edgecut_get(const blender::VectorSet<blender::OrderedEdge> &edgehash, uint v1, uint v2)
|
||||
static int edgecut_get(const blender::Map<blender::OrderedEdge, int> &edgehash, uint v1, uint v2)
|
||||
{
|
||||
return edgehash.index_of({int(v1), int(v2)});
|
||||
return edgehash.lookup({int(v1), int(v2)});
|
||||
}
|
||||
|
||||
static const short add_faces[24] = {
|
||||
|
@ -249,7 +249,7 @@ static void remap_faces_3_6_9_12(Mesh *mesh,
|
|||
int *facepa,
|
||||
const int *vertpa,
|
||||
int i,
|
||||
const blender::VectorSet<blender::OrderedEdge> &eh,
|
||||
const blender::Map<blender::OrderedEdge, int> &eh,
|
||||
int cur,
|
||||
int v1,
|
||||
int v2,
|
||||
|
@ -319,7 +319,7 @@ static void remap_faces_5_10(Mesh *mesh,
|
|||
int *facepa,
|
||||
const int *vertpa,
|
||||
int i,
|
||||
const blender::VectorSet<blender::OrderedEdge> &eh,
|
||||
const blender::Map<blender::OrderedEdge, int> &eh,
|
||||
int cur,
|
||||
int v1,
|
||||
int v2,
|
||||
|
@ -377,7 +377,7 @@ static void remap_faces_15(Mesh *mesh,
|
|||
int *facepa,
|
||||
const int *vertpa,
|
||||
int i,
|
||||
const blender::VectorSet<blender::OrderedEdge> &eh,
|
||||
const blender::Map<blender::OrderedEdge, int> &eh,
|
||||
int cur,
|
||||
int v1,
|
||||
int v2,
|
||||
|
@ -463,7 +463,7 @@ static void remap_faces_7_11_13_14(Mesh *mesh,
|
|||
int *facepa,
|
||||
const int *vertpa,
|
||||
int i,
|
||||
const blender::VectorSet<blender::OrderedEdge> &eh,
|
||||
const blender::Map<blender::OrderedEdge, int> &eh,
|
||||
int cur,
|
||||
int v1,
|
||||
int v2,
|
||||
|
@ -534,7 +534,7 @@ static void remap_faces_19_21_22(Mesh *mesh,
|
|||
int *facepa,
|
||||
const int *vertpa,
|
||||
int i,
|
||||
const blender::VectorSet<blender::OrderedEdge> &eh,
|
||||
const blender::Map<blender::OrderedEdge, int> &eh,
|
||||
int cur,
|
||||
int v1,
|
||||
int v2,
|
||||
|
@ -590,7 +590,7 @@ static void remap_faces_23(Mesh *mesh,
|
|||
int *facepa,
|
||||
const int *vertpa,
|
||||
int i,
|
||||
const blender::VectorSet<blender::OrderedEdge> &eh,
|
||||
const blender::Map<blender::OrderedEdge, int> &eh,
|
||||
int cur,
|
||||
int v1,
|
||||
int v2,
|
||||
|
@ -670,7 +670,8 @@ static Mesh *cutEdges(ExplodeModifierData *emd, Mesh *mesh)
|
|||
uv[4] = {0, 0, 0, 0}; /* To quite gcc barking... */
|
||||
int layers_num;
|
||||
|
||||
blender::VectorSet<blender::OrderedEdge> edgehash;
|
||||
int totesplit = totvert;
|
||||
blender::Map<blender::OrderedEdge, int> edgehash;
|
||||
|
||||
/* recreate vertpa from facepa calculation */
|
||||
for (i = 0, mf = mface; i < totface; i++, mf++) {
|
||||
|
@ -689,12 +690,12 @@ static Mesh *cutEdges(ExplodeModifierData *emd, Mesh *mesh)
|
|||
v3 = vertpa[mf->v3];
|
||||
|
||||
if (v1 != v2) {
|
||||
edgehash.add({mf->v1, mf->v2});
|
||||
edgehash.lookup_or_add_cb({mf->v1, mf->v2}, [&]() { return totesplit++; });
|
||||
(*fs) |= 1;
|
||||
}
|
||||
|
||||
if (v2 != v3) {
|
||||
edgehash.add({mf->v2, mf->v3});
|
||||
edgehash.lookup_or_add_cb({mf->v2, mf->v3}, [&]() { return totesplit++; });
|
||||
(*fs) |= 2;
|
||||
}
|
||||
|
||||
|
@ -702,25 +703,25 @@ static Mesh *cutEdges(ExplodeModifierData *emd, Mesh *mesh)
|
|||
v4 = vertpa[mf->v4];
|
||||
|
||||
if (v3 != v4) {
|
||||
edgehash.add({mf->v3, mf->v4});
|
||||
edgehash.lookup_or_add_cb({mf->v3, mf->v4}, [&]() { return totesplit++; });
|
||||
(*fs) |= 4;
|
||||
}
|
||||
|
||||
if (v1 != v4) {
|
||||
edgehash.add({mf->v1, mf->v4});
|
||||
edgehash.lookup_or_add_cb({mf->v1, mf->v4}, [&]() { return totesplit++; });
|
||||
(*fs) |= 8;
|
||||
}
|
||||
|
||||
/* mark center vertex as a fake edge split */
|
||||
if (*fs == 15) {
|
||||
edgehash.add({mf->v1, mf->v3});
|
||||
edgehash.lookup_or_add_cb({mf->v1, mf->v3}, [&]() { return totesplit++; });
|
||||
}
|
||||
}
|
||||
else {
|
||||
(*fs) |= 16; /* mark face as tri */
|
||||
|
||||
if (v1 != v3) {
|
||||
edgehash.add({mf->v1, mf->v3});
|
||||
edgehash.lookup_or_add_cb({mf->v1, mf->v3}, [&]() { return totesplit++; });
|
||||
(*fs) |= 4;
|
||||
}
|
||||
}
|
||||
|
@ -734,7 +735,7 @@ static Mesh *cutEdges(ExplodeModifierData *emd, Mesh *mesh)
|
|||
}
|
||||
|
||||
split_m = BKE_mesh_new_nomain_from_template_ex(
|
||||
mesh, totvert + edgehash.size(), 0, totface + totfsplit, 0, 0, CD_MASK_EVERYTHING);
|
||||
mesh, totesplit, 0, totface + totfsplit, 0, 0, CD_MASK_EVERYTHING);
|
||||
|
||||
layers_num = CustomData_number_of_layers(&split_m->fdata_legacy, CD_MTFACE);
|
||||
|
||||
|
@ -757,9 +758,9 @@ static Mesh *cutEdges(ExplodeModifierData *emd, Mesh *mesh)
|
|||
emd->facepa = facepa;
|
||||
|
||||
/* create new verts */
|
||||
for (const int esplit : edgehash.index_range()) {
|
||||
const int ed_v1 = edgehash[esplit].v_low;
|
||||
const int ed_v2 = edgehash[esplit].v_high;
|
||||
for (const auto [edge, esplit] : edgehash.items()) {
|
||||
const int ed_v1 = edge.v_low;
|
||||
const int ed_v2 = edge.v_high;
|
||||
|
||||
CustomData_free_elem(&split_m->vert_data, esplit, 1);
|
||||
CustomData_copy_data(&split_m->vert_data, &split_m->vert_data, ed_v2, esplit, 1);
|
||||
|
@ -912,7 +913,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
|
|||
float ctime;
|
||||
// float timestep;
|
||||
const int *facepa = emd->facepa;
|
||||
int totvert = 0, totface = 0, totpart = 0, delface = 0;
|
||||
int totdup = 0, totvert = 0, totface = 0, totpart = 0, delface = 0;
|
||||
int i, u;
|
||||
uint mindex = 0;
|
||||
|
||||
|
@ -933,7 +934,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
|
|||
ctime = BKE_scene_ctime_get(scene);
|
||||
|
||||
/* hash table for vertex <-> particle relations */
|
||||
blender::VectorSet<blender::OrderedEdge> vertpahash;
|
||||
blender::Map<blender::OrderedEdge, int> vertpahash;
|
||||
|
||||
for (i = 0; i < totface; i++) {
|
||||
if (facepa[i] != totpart) {
|
||||
|
@ -962,17 +963,17 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
|
|||
mf = &mface[i];
|
||||
|
||||
/* set face vertices to exist in particle group */
|
||||
vertpahash.add({mf->v1, mindex});
|
||||
vertpahash.add({mf->v2, mindex});
|
||||
vertpahash.add({mf->v3, mindex});
|
||||
vertpahash.lookup_or_add_cb({mf->v1, mindex}, [&]() { return totdup++; });
|
||||
vertpahash.lookup_or_add_cb({mf->v2, mindex}, [&]() { return totdup++; });
|
||||
vertpahash.lookup_or_add_cb({mf->v3, mindex}, [&]() { return totdup++; });
|
||||
if (mf->v4) {
|
||||
vertpahash.add({mf->v4, mindex});
|
||||
vertpahash.lookup_or_add_cb({mf->v4, mindex}, [&]() { return totdup++; });
|
||||
}
|
||||
}
|
||||
|
||||
/* the final duplicated vertices */
|
||||
explode = BKE_mesh_new_nomain_from_template_ex(
|
||||
mesh, vertpahash.size(), 0, totface - delface, 0, 0, CD_MASK_EVERYTHING);
|
||||
mesh, totdup, 0, totface - delface, 0, 0, CD_MASK_EVERYTHING);
|
||||
|
||||
MTFace *mtface = static_cast<MTFace *>(CustomData_get_layer_named_for_write(
|
||||
&explode->fdata_legacy, CD_MTFACE, emd->uvname, explode->totface_legacy));
|
||||
|
@ -985,10 +986,9 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
|
|||
const blender::Span<blender::float3> positions = mesh->vert_positions();
|
||||
blender::MutableSpan<blender::float3> explode_positions = explode->vert_positions_for_write();
|
||||
|
||||
for (const int v : vertpahash.index_range()) {
|
||||
/* get particle + vertex from hash */
|
||||
int ed_v1 = vertpahash[v].v_low;
|
||||
int ed_v2 = vertpahash[v].v_high;
|
||||
for (const auto [edge, v] : vertpahash.items()) {
|
||||
int ed_v1 = edge.v_low;
|
||||
int ed_v2 = edge.v_high;
|
||||
ed_v2 -= totvert;
|
||||
|
||||
copy_v3_v3(explode_positions[v], positions[ed_v1]);
|
||||
|
|
|
@ -616,6 +616,7 @@ void WM_exit_ex(bContext *C, const bool do_python_exit, const bool do_user_exit_
|
|||
BKE_vfont_clipboard_free();
|
||||
ED_node_clipboard_free();
|
||||
UV_clipboard_free();
|
||||
wm_clipboard_free();
|
||||
|
||||
#ifdef WITH_COMPOSITOR_CPU
|
||||
COM_deinitialize();
|
||||
|
|
|
@ -827,8 +827,6 @@ static bool operator_last_properties_init_impl(wmOperator *op, IDProperty *last_
|
|||
IDPropertyTemplate val = {0};
|
||||
IDProperty *replaceprops = IDP_New(IDP_GROUP, &val, "wmOperatorProperties");
|
||||
|
||||
CLOG_INFO(WM_LOG_OPERATORS, 1, "loading previous properties for '%s'", op->type->idname);
|
||||
|
||||
PropertyRNA *iterprop = RNA_struct_iterator_property(op->type->srna);
|
||||
|
||||
RNA_PROP_BEGIN (op->ptr, itemptr, iterprop) {
|
||||
|
@ -854,6 +852,9 @@ static bool operator_last_properties_init_impl(wmOperator *op, IDProperty *last_
|
|||
}
|
||||
RNA_PROP_END;
|
||||
|
||||
if (changed) {
|
||||
CLOG_INFO(WM_LOG_OPERATORS, 1, "loading previous properties for '%s'", op->type->idname);
|
||||
}
|
||||
IDP_MergeGroup(op->properties, replaceprops, true);
|
||||
IDP_FreeProperty(replaceprops);
|
||||
return changed;
|
||||
|
@ -882,7 +883,9 @@ bool WM_operator_last_properties_store(wmOperator *op)
|
|||
}
|
||||
|
||||
if (op->properties) {
|
||||
CLOG_INFO(WM_LOG_OPERATORS, 1, "storing properties for '%s'", op->type->idname);
|
||||
if (!BLI_listbase_is_empty(&op->properties->data.group)) {
|
||||
CLOG_INFO(WM_LOG_OPERATORS, 1, "storing properties for '%s'", op->type->idname);
|
||||
}
|
||||
op->type->last_properties = IDP_CopyProperty(op->properties);
|
||||
}
|
||||
|
||||
|
|
|
@ -1813,6 +1813,10 @@ static bool wm_main_playanim_intern(int argc, const char **argv, PlayArgs *args_
|
|||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Select GPU backend. */
|
||||
GPU_backend_type_selection_detect();
|
||||
|
||||
/* Init GHOST and open window. */
|
||||
GHOST_EventConsumerHandle ghost_event_consumer = nullptr;
|
||||
{
|
||||
ghost_event_consumer = GHOST_CreateEventConsumer(ghost_event_proc, &ps);
|
||||
|
@ -1840,7 +1844,7 @@ static bool wm_main_playanim_intern(int argc, const char **argv, PlayArgs *args_
|
|||
|
||||
// GHOST_ActivateWindowDrawingContext(ps.ghost_data.window);
|
||||
|
||||
/* Initialize GPU immediate mode. */
|
||||
/* Init Blender GPU context. */
|
||||
ps.ghost_data.gpu_context = GPU_context_create(ps.ghost_data.window, nullptr);
|
||||
GPU_init();
|
||||
|
||||
|
|
|
@ -2110,6 +2110,70 @@ void WM_event_timer_remove_notifier(wmWindowManager *wm, wmWindow *win, wmTimer
|
|||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Clipboard Wrappers
|
||||
*
|
||||
* GHOST function wrappers that support a "fake" clipboard used when simulating events.
|
||||
* This is useful user actions can be simulated while the system is in use without the system's
|
||||
* clipboard getting overwritten.
|
||||
* \{ */
|
||||
|
||||
struct {
|
||||
char *buffers[2];
|
||||
} *g_wm_clipboard_text_simulate = nullptr;
|
||||
|
||||
void wm_clipboard_free()
|
||||
{
|
||||
if (g_wm_clipboard_text_simulate == nullptr) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < ARRAY_SIZE(g_wm_clipboard_text_simulate->buffers); i++) {
|
||||
char *buf = g_wm_clipboard_text_simulate->buffers[i];
|
||||
if (buf) {
|
||||
MEM_freeN(buf);
|
||||
}
|
||||
}
|
||||
MEM_freeN(g_wm_clipboard_text_simulate);
|
||||
g_wm_clipboard_text_simulate = nullptr;
|
||||
}
|
||||
|
||||
static char *wm_clipboard_text_get_impl(bool selection)
|
||||
{
|
||||
if (UNLIKELY(G.f & G_FLAG_EVENT_SIMULATE)) {
|
||||
if (g_wm_clipboard_text_simulate == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
const char *buf_src = g_wm_clipboard_text_simulate->buffers[int(selection)];
|
||||
if (buf_src == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
size_t size = strlen(buf_src) + 1;
|
||||
char *buf = static_cast<char *>(malloc(size));
|
||||
memcpy(buf, buf_src, size);
|
||||
return buf;
|
||||
}
|
||||
|
||||
return GHOST_getClipboard(selection);
|
||||
}
|
||||
|
||||
static void wm_clipboard_text_set_impl(const char *buf, bool selection)
|
||||
{
|
||||
if (UNLIKELY(G.f & G_FLAG_EVENT_SIMULATE)) {
|
||||
if (g_wm_clipboard_text_simulate == nullptr) {
|
||||
g_wm_clipboard_text_simulate = static_cast<decltype(g_wm_clipboard_text_simulate)>(
|
||||
MEM_callocN(sizeof(*g_wm_clipboard_text_simulate), __func__));
|
||||
}
|
||||
char **buf_src_p = &(g_wm_clipboard_text_simulate->buffers[int(selection)]);
|
||||
MEM_SAFE_FREE(*buf_src_p);
|
||||
*buf_src_p = BLI_strdup(buf);
|
||||
return;
|
||||
}
|
||||
|
||||
GHOST_putClipboard(buf, selection);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Clipboard
|
||||
* \{ */
|
||||
|
@ -2124,7 +2188,7 @@ static char *wm_clipboard_text_get_ex(bool selection,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
char *buf = GHOST_getClipboard(selection);
|
||||
char *buf = wm_clipboard_text_get_impl(selection);
|
||||
if (!buf) {
|
||||
*r_len = 0;
|
||||
return nullptr;
|
||||
|
@ -2213,10 +2277,10 @@ void WM_clipboard_text_set(const char *buf, bool selection)
|
|||
}
|
||||
*p2 = '\0';
|
||||
|
||||
GHOST_putClipboard(newbuf, selection);
|
||||
wm_clipboard_text_set_impl(newbuf, selection);
|
||||
MEM_freeN(newbuf);
|
||||
#else
|
||||
GHOST_putClipboard(buf, selection);
|
||||
wm_clipboard_text_set_impl(buf, selection);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,8 @@ void wm_ghost_init(bContext *C);
|
|||
void wm_ghost_init_background();
|
||||
void wm_ghost_exit();
|
||||
|
||||
void wm_clipboard_free();
|
||||
|
||||
/**
|
||||
* This one should correctly check for apple top header...
|
||||
* done for Cocoa: returns window contents (and not frame) max size.
|
||||
|
|
Loading…
Reference in New Issue