Fix #103244: ghosting in Eevee with sculpt paint brush and canvas #104557
|
@ -105,6 +105,7 @@ MetalDevice::MetalDevice(const DeviceInfo &info, Stats &stats, Profiler &profile
|
|||
}
|
||||
case METAL_GPU_AMD: {
|
||||
max_threads_per_threadgroup = 128;
|
||||
use_metalrt = info.use_metalrt;
|
||||
break;
|
||||
}
|
||||
case METAL_GPU_APPLE: {
|
||||
|
|
|
@ -3478,7 +3478,8 @@ def km_animation_channels(params):
|
|||
# Selection.
|
||||
*_template_items_select_actions(params, "anim.channels_select_all"),
|
||||
("anim.channels_select_box", {"type": 'B', "value": 'PRESS'}, None),
|
||||
("anim.channels_select_box", {"type": 'LEFTMOUSE', "value": 'CLICK_DRAG'}, None),
|
||||
("anim.channels_select_box", {"type": 'LEFTMOUSE', "value": 'CLICK_DRAG'},
|
||||
{"properties": [("extend", False)]}),
|
||||
("anim.channels_select_box", {"type": 'LEFTMOUSE', "value": 'CLICK_DRAG', "shift": True},
|
||||
{"properties": [("extend", True)]}),
|
||||
("anim.channels_select_box", {"type": 'LEFTMOUSE', "value": 'CLICK_DRAG', "ctrl": True},
|
||||
|
|
|
@ -2329,6 +2329,9 @@ class USERPREF_PT_experimental_new_features(ExperimentalPanel, Panel):
|
|||
({"property": "use_override_templates"},
|
||||
("blender/blender/issues/73318",
|
||||
"Milestone 4")),
|
||||
({"property": "use_new_volume_nodes"},
|
||||
("blender/blender/issues/103248",
|
||||
"#103248")),
|
||||
),
|
||||
)
|
||||
|
||||
|
|
|
@ -2289,26 +2289,12 @@ bool CustomData_merge(const CustomData *source,
|
|||
return changed;
|
||||
}
|
||||
|
||||
static bool attribute_stored_in_bmesh_flag(const StringRef name)
|
||||
{
|
||||
return ELEM(name,
|
||||
"position",
|
||||
".hide_vert",
|
||||
".hide_edge",
|
||||
".hide_poly",
|
||||
".select_vert",
|
||||
".select_edge",
|
||||
".select_poly",
|
||||
"material_index",
|
||||
"sharp_edge");
|
||||
}
|
||||
|
||||
CustomData CustomData_shallow_copy_remove_non_bmesh_attributes(const CustomData *src,
|
||||
const eCustomDataMask mask)
|
||||
{
|
||||
Vector<CustomDataLayer> dst_layers;
|
||||
for (const CustomDataLayer &layer : Span<CustomDataLayer>{src->layers, src->totlayer}) {
|
||||
if (attribute_stored_in_bmesh_flag(layer.name)) {
|
||||
if (BM_attribute_stored_in_bmesh_builtin(layer.name)) {
|
||||
continue;
|
||||
}
|
||||
if (!(mask & CD_TYPE_AS_MASK(layer.type))) {
|
||||
|
|
|
@ -1261,7 +1261,9 @@ bGPDframe *BKE_gpencil_layer_frame_get(bGPDlayer *gpl, int cframe, eGP_GetFrame_
|
|||
found = true;
|
||||
break;
|
||||
}
|
||||
if ((gpf->next) && (gpf->next->framenum > cframe)) {
|
||||
/* If this is the last frame or the next frame is at a later time, we found the right
|
||||
* frame. */
|
||||
if (!(gpf->next) || (gpf->next->framenum > cframe)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -133,6 +133,20 @@ static char bm_face_flag_to_mflag(const BMFace *f)
|
|||
return ((hflag & BM_ELEM_SMOOTH) ? ME_SMOOTH : 0);
|
||||
}
|
||||
|
||||
bool BM_attribute_stored_in_bmesh_builtin(const StringRef name)
|
||||
{
|
||||
return ELEM(name,
|
||||
"position",
|
||||
".hide_vert",
|
||||
".hide_edge",
|
||||
".hide_poly",
|
||||
".select_vert",
|
||||
".select_edge",
|
||||
".select_poly",
|
||||
"material_index",
|
||||
"sharp_edge");
|
||||
}
|
||||
|
||||
/* Static function for alloc (duplicate in modifiers_bmesh.c) */
|
||||
static BMFace *bm_face_create_from_mpoly(BMesh &bm,
|
||||
Span<MLoop> loops,
|
||||
|
|
|
@ -9,6 +9,16 @@
|
|||
|
||||
#include "bmesh.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
# include "BLI_string_ref.hh"
|
||||
|
||||
/**
|
||||
* \return Whether attributes with the given name are stored in special flags or fields in BMesh
|
||||
* rather than in the regular custom data blocks.
|
||||
*/
|
||||
bool BM_attribute_stored_in_bmesh_builtin(const blender::StringRef name);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
|
|
@ -3499,7 +3499,8 @@ static int animchannels_mouseclick_invoke(bContext *C, wmOperator *op, const wmE
|
|||
/* set notifier that things have changed */
|
||||
WM_event_add_notifier(C, NC_ANIMATION | notifierFlags, NULL);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
return WM_operator_flag_only_pass_through_on_press(OPERATOR_FINISHED | OPERATOR_PASS_THROUGH,
|
||||
event);
|
||||
}
|
||||
|
||||
static void ANIM_OT_channels_click(wmOperatorType *ot)
|
||||
|
|
|
@ -3327,6 +3327,14 @@ void ED_gpencil_layer_merge(bGPdata *gpd,
|
|||
gpf_dst->key_type = gpf_src->key_type;
|
||||
BLI_ghash_insert(gh_frames_dst, POINTER_FROM_INT(gpf_src->framenum), gpf_dst);
|
||||
}
|
||||
|
||||
/* Copy current source frame to further frames
|
||||
* that are keyframes in destination layer and not in source layer
|
||||
* to keep the image equals. */
|
||||
if (gpf_dst->next && (!gpf_src->next || (gpf_dst->next->framenum < gpf_src->next->framenum))) {
|
||||
gpf_dst = gpf_dst->next;
|
||||
BKE_gpencil_layer_frame_get(gpl_src, gpf_dst->framenum, GP_GETFRAME_ADD_COPY);
|
||||
}
|
||||
}
|
||||
|
||||
/* Read all frames from merge layer and add strokes. */
|
||||
|
|
|
@ -19,7 +19,13 @@ struct bContext;
|
|||
void ED_sequencer_select_sequence_single(struct Scene *scene,
|
||||
struct Sequence *seq,
|
||||
bool deselect_all);
|
||||
void ED_sequencer_deselect_all(struct Scene *scene);
|
||||
/**
|
||||
* Iterates over a scene's sequences and deselects all of them.
|
||||
*
|
||||
* \param scene: scene containing sequences to be deselected.
|
||||
* \return true if any sequences were deselected; false otherwise.
|
||||
*/
|
||||
bool ED_sequencer_deselect_all(struct Scene *scene);
|
||||
|
||||
bool ED_space_sequencer_maskedit_mask_poll(struct bContext *C);
|
||||
bool ED_space_sequencer_check_show_maskedit(struct SpaceSeq *sseq, struct Scene *scene);
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
#include "BKE_pointcache.h"
|
||||
#include "BKE_scene.h"
|
||||
|
||||
#include "BLI_index_range.hh"
|
||||
|
||||
#include "DEG_depsgraph.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
|
@ -42,6 +44,8 @@
|
|||
#include "bmesh.h"
|
||||
#include "bmesh_tools.h"
|
||||
|
||||
using blender::IndexRange;
|
||||
|
||||
void SCULPT_dynamic_topology_triangulate(BMesh *bm)
|
||||
{
|
||||
if (bm->totloop != bm->totface * 3) {
|
||||
|
@ -281,8 +285,8 @@ static int dyntopo_warning_popup(bContext *C, wmOperatorType *ot, enum eDynTopoW
|
|||
uiLayout *layout = UI_popup_menu_layout(pup);
|
||||
|
||||
if (flag & (DYNTOPO_WARN_VDATA | DYNTOPO_WARN_EDATA | DYNTOPO_WARN_LDATA)) {
|
||||
const char *msg_error = TIP_("Vertex Data Detected!");
|
||||
const char *msg = TIP_("Dyntopo will not preserve vertex colors, UVs, or other customdata");
|
||||
const char *msg_error = TIP_("Attribute Data Detected");
|
||||
const char *msg = TIP_("Dyntopo will not preserve colors, UVs, or other attributes");
|
||||
uiItemL(layout, msg_error, ICON_INFO);
|
||||
uiItemL(layout, msg, ICON_NONE);
|
||||
uiItemS(layout);
|
||||
|
@ -305,6 +309,39 @@ static int dyntopo_warning_popup(bContext *C, wmOperatorType *ot, enum eDynTopoW
|
|||
return OPERATOR_INTERFACE;
|
||||
}
|
||||
|
||||
static bool dyntopo_supports_customdata_layers(const blender::Span<CustomDataLayer> layers,
|
||||
int totelem)
|
||||
{
|
||||
for (const CustomDataLayer &layer : layers) {
|
||||
if (CD_TYPE_AS_MASK(layer.type) & CD_MASK_PROP_ALL) {
|
||||
if (layer.name[0] == '\0') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (STREQ(layer.name, ".sculpt_face_sets") && totelem > 0) {
|
||||
int *fsets = static_cast<int *>(layer.data);
|
||||
int fset = fsets[0];
|
||||
|
||||
/* Check if only one face set exists. */
|
||||
for (int i : IndexRange(totelem)) {
|
||||
if (fsets[i] != fset) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Some data is stored as generic attributes on #Mesh but in flags or field on #BMesh. */
|
||||
return BM_attribute_stored_in_bmesh_builtin(layer.name);
|
||||
}
|
||||
/* Some layers just encode #Mesh topology or are handled as special cases for dyntopo. */
|
||||
return ELEM(layer.type, CD_MEDGE, CD_MFACE, CD_MLOOP, CD_MPOLY, CD_PAINT_MASK, CD_ORIGINDEX);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
enum eDynTopoWarnFlag SCULPT_dynamic_topology_check(Scene *scene, Object *ob)
|
||||
{
|
||||
Mesh *me = static_cast<Mesh *>(ob->data);
|
||||
|
@ -315,18 +352,17 @@ enum eDynTopoWarnFlag SCULPT_dynamic_topology_check(Scene *scene, Object *ob)
|
|||
BLI_assert(ss->bm == nullptr);
|
||||
UNUSED_VARS_NDEBUG(ss);
|
||||
|
||||
for (int i = 0; i < CD_NUMTYPES; i++) {
|
||||
if (!ELEM(i, CD_MEDGE, CD_MFACE, CD_MLOOP, CD_MPOLY, CD_PAINT_MASK, CD_ORIGINDEX)) {
|
||||
if (CustomData_has_layer(&me->vdata, i)) {
|
||||
flag |= DYNTOPO_WARN_VDATA;
|
||||
}
|
||||
if (CustomData_has_layer(&me->edata, i)) {
|
||||
flag |= DYNTOPO_WARN_EDATA;
|
||||
}
|
||||
if (CustomData_has_layer(&me->ldata, i)) {
|
||||
flag |= DYNTOPO_WARN_LDATA;
|
||||
}
|
||||
}
|
||||
if (!dyntopo_supports_customdata_layers({me->vdata.layers, me->vdata.totlayer}, me->totvert)) {
|
||||
flag |= DYNTOPO_WARN_VDATA;
|
||||
}
|
||||
if (!dyntopo_supports_customdata_layers({me->edata.layers, me->edata.totlayer}, me->totedge)) {
|
||||
flag |= DYNTOPO_WARN_EDATA;
|
||||
}
|
||||
if (!dyntopo_supports_customdata_layers({me->pdata.layers, me->pdata.totlayer}, me->totpoly)) {
|
||||
flag |= DYNTOPO_WARN_LDATA;
|
||||
}
|
||||
if (!dyntopo_supports_customdata_layers({me->ldata.layers, me->ldata.totlayer}, me->totloop)) {
|
||||
flag |= DYNTOPO_WARN_LDATA;
|
||||
}
|
||||
|
||||
{
|
||||
|
|
|
@ -2492,17 +2492,22 @@ void SEQUENCER_OT_copy(wmOperatorType *ot)
|
|||
/** \name Paste Operator
|
||||
* \{ */
|
||||
|
||||
void ED_sequencer_deselect_all(Scene *scene)
|
||||
bool ED_sequencer_deselect_all(Scene *scene)
|
||||
{
|
||||
Editing *ed = SEQ_editing_get(scene);
|
||||
bool changed = false;
|
||||
|
||||
if (ed == NULL) {
|
||||
return;
|
||||
return changed;
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
|
||||
seq->flag &= ~SEQ_ALLSEL;
|
||||
if (seq->flag & SEQ_ALLSEL) {
|
||||
seq->flag &= ~SEQ_ALLSEL;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
static void sequencer_paste_animation(bContext *C)
|
||||
|
|
|
@ -974,8 +974,7 @@ static int sequencer_select_exec(bContext *C, wmOperator *op)
|
|||
|
||||
/* Deselect everything */
|
||||
if (deselect_all || (seq && (extend == false && deselect == false && toggle == false))) {
|
||||
ED_sequencer_deselect_all(scene);
|
||||
changed = true;
|
||||
changed |= ED_sequencer_deselect_all(scene);
|
||||
}
|
||||
|
||||
/* Nothing to select, but strips could be deselected. */
|
||||
|
|
|
@ -653,7 +653,8 @@ typedef struct UserDef_Experimental {
|
|||
char enable_eevee_next;
|
||||
char use_sculpt_texture_paint;
|
||||
char enable_workbench_next;
|
||||
char _pad[7];
|
||||
char use_new_volume_nodes;
|
||||
char _pad[6];
|
||||
/** `makesdna` does not allow empty structs. */
|
||||
} UserDef_Experimental;
|
||||
|
||||
|
|
|
@ -6456,6 +6456,10 @@ static void rna_def_userdef_experimental(BlenderRNA *brna)
|
|||
"All Linked Data Direct",
|
||||
"Forces all linked data to be considered as directly linked. Workaround for current "
|
||||
"issues/limitations in BAT (Blender studio pipeline tool)");
|
||||
|
||||
prop = RNA_def_property(srna, "use_new_volume_nodes", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "New Volume Nodes", "Enables visibility of the new Volume nodes in the UI");
|
||||
}
|
||||
|
||||
static void rna_def_userdef_addon_collection(BlenderRNA *brna, PropertyRNA *cprop)
|
||||
|
|
Loading…
Reference in New Issue