Nodes: Panels integration with blend files and UI #111348
|
@ -108,6 +108,7 @@ const UserDef U_default = {
|
|||
.gp_euclideandist = 2,
|
||||
.gp_eraser = 25,
|
||||
.gp_settings = 0,
|
||||
.playback_fps_samples = 8,
|
||||
#ifdef __APPLE__
|
||||
.gpu_backend = GPU_BACKEND_METAL,
|
||||
#else
|
||||
|
|
|
@ -720,6 +720,9 @@ class USERPREF_PT_viewport_display(ViewportPanel, CenterAlignMixIn, Panel):
|
|||
col.prop(view, "show_object_info", text="Object Info")
|
||||
col.prop(view, "show_view_name", text="View Name")
|
||||
col.prop(view, "show_playback_fps", text="Playback Frame Rate (FPS)")
|
||||
row = col.row()
|
||||
row.active = view.show_playback_fps
|
||||
row.prop(view, "playback_fps_samples", text="Frame Rate Samples")
|
||||
|
||||
layout.separator()
|
||||
|
||||
|
|
|
@ -305,7 +305,7 @@ class LayerRuntime {
|
|||
*/
|
||||
Vector<LayerMask> masks_;
|
||||
|
||||
/* Runtime data used for frame transformations.*/
|
||||
/* Runtime data used for frame transformations. */
|
||||
LayerTransformData trans_data_;
|
||||
};
|
||||
|
||||
|
|
|
@ -604,7 +604,7 @@ GreasePencilFrame *Layer::add_frame(const FramesMapKey key,
|
|||
return frame;
|
||||
}
|
||||
next_key_it = this->remove_leading_null_frames_in_range(next_key_it, sorted_keys.end());
|
||||
/* If the duration is set to 0, the frame is marked as an implicit hold.*/
|
||||
/* If the duration is set to 0, the frame is marked as an implicit hold. */
|
||||
if (duration == 0) {
|
||||
frame->flag |= GP_FRAME_IMPLICIT_HOLD;
|
||||
return frame;
|
||||
|
|
|
@ -184,6 +184,7 @@ static void shapekey_blend_read_after_liblink(BlendLibReader * /*reader*/, ID *i
|
|||
/* ShapeKeys should always only be linked indirectly through their user ID (mesh, Curve etc.), or
|
||||
* be fully local data. */
|
||||
BLI_assert((id->tag & LIB_TAG_EXTERN) == 0);
|
||||
UNUSED_VARS_NDEBUG(id);
|
||||
}
|
||||
|
||||
IDTypeInfo IDType_ID_KE = {
|
||||
|
|
|
@ -433,11 +433,4 @@ class Array {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Same as a normal Array, but does not use Blender's guarded allocator. This is useful when
|
||||
* allocating memory with static storage duration.
|
||||
*/
|
||||
template<typename T, int64_t InlineBufferCapacity = default_inline_buffer_capacity(sizeof(T))>
|
||||
using RawArray = Array<T, InlineBufferCapacity, RawAllocator>;
|
||||
|
||||
} // namespace blender
|
||||
|
|
|
@ -497,7 +497,7 @@ void BLO_main_expander(BLOExpandDoitCallback expand_doit_func);
|
|||
* Loop over all ID data in Main to mark relations.
|
||||
* Set (id->tag & LIB_TAG_NEED_EXPAND) to mark expanding. Flags get cleared after expanding.
|
||||
*
|
||||
* \param fdhandle: usually file-data, or own handle.
|
||||
* \param fdhandle: usually file-data, or own handle. May be nullptr.
|
||||
* \param mainvar: the Main database to expand.
|
||||
*/
|
||||
void BLO_expand_main(void *fdhandle, struct Main *mainvar);
|
||||
|
|
|
@ -4148,7 +4148,9 @@ void BLO_expand_main(void *fdhandle, Main *mainvar)
|
|||
* Expanding should never modify ID pointers themselves.
|
||||
* Handling of DNA deprecated data should never be needed in undo case. */
|
||||
const int flag = IDWALK_READONLY | IDWALK_NO_ORIG_POINTERS_ACCESS |
|
||||
((fd->flags & FD_FLAGS_IS_MEMFILE) ? 0 : IDWALK_DO_DEPRECATED_POINTERS);
|
||||
((!fd || (fd->flags & FD_FLAGS_IS_MEMFILE)) ?
|
||||
0 :
|
||||
IDWALK_DO_DEPRECATED_POINTERS);
|
||||
BKE_library_foreach_ID_link(nullptr, id_iter, expand_cb, &expander, flag);
|
||||
|
||||
do_it = true;
|
||||
|
|
|
@ -852,6 +852,10 @@ void blo_do_versions_userdef(UserDef *userdef)
|
|||
userdef->node_preview_res = 120;
|
||||
}
|
||||
|
||||
if (!USER_VERSION_ATLEAST(400, 18)) {
|
||||
userdef->playback_fps_samples = 8;
|
||||
}
|
||||
|
||||
/**
|
||||
* Versioning code until next subversion bump goes here.
|
||||
*
|
||||
|
|
|
@ -15,8 +15,10 @@
|
|||
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_shadow_tilemap_lib.glsl)
|
||||
|
||||
shared ivec2 rect_min;
|
||||
shared ivec2 rect_max;
|
||||
shared int rect_min_x;
|
||||
shared int rect_min_y;
|
||||
shared int rect_max_x;
|
||||
shared int rect_max_y;
|
||||
shared int view_index;
|
||||
|
||||
/**
|
||||
|
@ -68,8 +70,10 @@ void main()
|
|||
|
||||
/* Compute update area. */
|
||||
if (all(equal(gl_LocalInvocationID, uvec3(0)))) {
|
||||
rect_min = ivec2(SHADOW_TILEMAP_RES);
|
||||
rect_max = ivec2(0);
|
||||
rect_min_x = SHADOW_TILEMAP_RES;
|
||||
rect_min_y = SHADOW_TILEMAP_RES;
|
||||
rect_max_x = 0;
|
||||
rect_max_y = 0;
|
||||
view_index = -1;
|
||||
}
|
||||
|
||||
|
@ -78,14 +82,17 @@ void main()
|
|||
bool lod_valid_thread = all(equal(tile_co, tile_co_lod << lod));
|
||||
bool do_page_render = tile.is_used && tile.do_update && lod_valid_thread;
|
||||
if (do_page_render) {
|
||||
atomicMin(rect_min.x, tile_co_lod.x);
|
||||
atomicMin(rect_min.y, tile_co_lod.y);
|
||||
atomicMax(rect_max.x, tile_co_lod.x + 1);
|
||||
atomicMax(rect_max.y, tile_co_lod.y + 1);
|
||||
atomicMin(rect_min_x, tile_co_lod.x);
|
||||
atomicMin(rect_min_y, tile_co_lod.y);
|
||||
atomicMax(rect_max_x, tile_co_lod.x + 1);
|
||||
atomicMax(rect_max_y, tile_co_lod.y + 1);
|
||||
}
|
||||
|
||||
barrier();
|
||||
|
||||
ivec2 rect_min = ivec2(rect_min_x, rect_min_y);
|
||||
ivec2 rect_max = ivec2(rect_max_x, rect_max_y);
|
||||
|
||||
int viewport_index = viewport_select(rect_max - rect_min);
|
||||
ivec2 viewport_size = viewport_size_get(viewport_index);
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_shadow_tilemap_lib.glsl)
|
||||
|
||||
shared bool directional_range_changed;
|
||||
shared int directional_range_changed;
|
||||
|
||||
ShadowTileDataPacked init_tile_data(ShadowTileDataPacked tile, bool do_update)
|
||||
{
|
||||
|
@ -39,7 +39,7 @@ void main()
|
|||
/* Reset shift to not tag for update more than once per sync cycle. */
|
||||
tilemaps_buf[tilemap_index].grid_shift = ivec2(0);
|
||||
|
||||
directional_range_changed = false;
|
||||
directional_range_changed = 0;
|
||||
|
||||
int clip_index = tilemap.clip_data_index;
|
||||
if (clip_index == -1) {
|
||||
|
@ -51,7 +51,7 @@ void main()
|
|||
float clip_far_new = orderedIntBitsToFloat(clip_data.clip_far);
|
||||
bool near_changed = clip_near_new != clip_data.clip_near_stored;
|
||||
bool far_changed = clip_far_new != clip_data.clip_far_stored;
|
||||
directional_range_changed = near_changed || far_changed;
|
||||
directional_range_changed = int(near_changed || far_changed);
|
||||
/* NOTE(fclem): This assumes clip near/far are computed each time the initial phase runs. */
|
||||
tilemaps_clip_buf[clip_index].clip_near_stored = clip_near_new;
|
||||
tilemaps_clip_buf[clip_index].clip_far_stored = clip_far_new;
|
||||
|
@ -78,7 +78,7 @@ void main()
|
|||
bool do_update = !in_range_inclusive(tile_shifted, ivec2(0), ivec2(SHADOW_TILEMAP_RES - 1));
|
||||
|
||||
/* TODO(fclem): Might be better to resize the depth stored instead of a full render update. */
|
||||
if (directional_range_changed) {
|
||||
if (directional_range_changed != 0) {
|
||||
do_update = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -2192,6 +2192,14 @@ static int animchannels_delete_exec(bContext *C, wmOperator * /*op*/)
|
|||
ale->update = ANIM_UPDATE_DEPS;
|
||||
break;
|
||||
}
|
||||
case ANIMTYPE_GREASE_PENCIL_LAYER: {
|
||||
using namespace blender::bke::greasepencil;
|
||||
GreasePencil *grease_pencil = reinterpret_cast<GreasePencil *>(ale->id);
|
||||
Layer *layer = static_cast<Layer *>(ale->data);
|
||||
grease_pencil->remove_layer(*layer);
|
||||
DEG_id_tag_update(&grease_pencil->id, ID_RECALC_GEOMETRY);
|
||||
break;
|
||||
}
|
||||
case ANIMTYPE_MASKLAYER: {
|
||||
/* Mask layer */
|
||||
Mask *mask = (Mask *)ale->id;
|
||||
|
|
|
@ -43,20 +43,24 @@ enum {
|
|||
|
||||
/* ----------------------------------------------------- */
|
||||
|
||||
#define REDRAW_FRAME_AVERAGE 8
|
||||
|
||||
/**
|
||||
* For playback frame-rate info stored during runtime as `scene->fps_info`.
|
||||
*/
|
||||
struct ScreenFrameRateInfo {
|
||||
double redrawtime;
|
||||
double lredrawtime;
|
||||
float redrawtimes_fps[REDRAW_FRAME_AVERAGE];
|
||||
short redrawtime_index;
|
||||
|
||||
/** The target FPS, use to reset on change. */
|
||||
float fps_target;
|
||||
/** Final result, ignore when -1.0. */
|
||||
float fps_average;
|
||||
|
||||
int redrawtimes_index;
|
||||
int redrawtimes_num;
|
||||
int redrawtimes_num_set;
|
||||
|
||||
/** Over allocate. */
|
||||
float redrawtimes_fps[0];
|
||||
};
|
||||
|
||||
/* ----------------------------------------------------- */
|
||||
|
|
|
@ -294,15 +294,15 @@ static int view_pan_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
|||
}
|
||||
|
||||
if (deltax != 0) {
|
||||
RNA_int_set(op->ptr, "deltax", deltax);
|
||||
vpd->lastx = event->xy[0];
|
||||
}
|
||||
if (deltay != 0) {
|
||||
RNA_int_set(op->ptr, "deltay", deltay);
|
||||
vpd->lasty = event->xy[1];
|
||||
}
|
||||
|
||||
if (deltax || deltay) {
|
||||
RNA_int_set(op->ptr, "deltax", deltax);
|
||||
RNA_int_set(op->ptr, "deltay", deltay);
|
||||
view_pan_apply(C, op);
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -1694,22 +1694,30 @@ void ED_scene_fps_average_accumulate(Scene *scene, const double ltime)
|
|||
|
||||
/* Playback running. */
|
||||
const float fps_target = float(FPS);
|
||||
ScreenFrameRateInfo *fpsi = static_cast<ScreenFrameRateInfo *>(scene->fps_info);
|
||||
|
||||
/* Reset when the target FPS changes.
|
||||
* Needed redraw times from when a different FPS was set do not contribute
|
||||
* to an average that is over/under the new target. */
|
||||
if (fpsi && (fpsi->fps_target != fps_target)) {
|
||||
MEM_freeN(fpsi);
|
||||
fpsi = nullptr;
|
||||
scene->fps_info = nullptr;
|
||||
ScreenFrameRateInfo *fpsi = static_cast<ScreenFrameRateInfo *>(scene->fps_info);
|
||||
const int redrawtimes_num = U.playback_fps_samples ? U.playback_fps_samples :
|
||||
max_ii(1, int(ceilf(fps_target)));
|
||||
|
||||
if (fpsi) {
|
||||
/* Reset when the target FPS changes.
|
||||
* Needed redraw times from when a different FPS was set do not contribute
|
||||
* to an average that is over/under the new target. */
|
||||
if ((fpsi->fps_target != fps_target) || (fpsi->redrawtimes_num != redrawtimes_num)) {
|
||||
MEM_freeN(fpsi);
|
||||
fpsi = nullptr;
|
||||
scene->fps_info = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/* If there isn't any info, initialize it first. */
|
||||
if (fpsi == nullptr) {
|
||||
fpsi = static_cast<ScreenFrameRateInfo *>(
|
||||
scene->fps_info = MEM_callocN(sizeof(ScreenFrameRateInfo), __func__));
|
||||
scene->fps_info = MEM_callocN(sizeof(ScreenFrameRateInfo) + (sizeof(float) * redrawtimes_num),
|
||||
__func__);
|
||||
fpsi = static_cast<ScreenFrameRateInfo *>(scene->fps_info);
|
||||
fpsi->fps_target = fps_target;
|
||||
fpsi->redrawtimes_num = redrawtimes_num;
|
||||
fpsi->redrawtimes_num_set = 0;
|
||||
}
|
||||
|
||||
/* Update the values. */
|
||||
|
@ -1738,22 +1746,23 @@ bool ED_scene_fps_average_calc(const Scene *scene)
|
|||
return true;
|
||||
}
|
||||
|
||||
fpsi->redrawtimes_fps[fpsi->redrawtime_index] = float(1.0 /
|
||||
(fpsi->lredrawtime - fpsi->redrawtime));
|
||||
if (fpsi->redrawtimes_index >= fpsi->redrawtimes_num) {
|
||||
fpsi->redrawtimes_index = 0;
|
||||
}
|
||||
|
||||
/* Doing an average for a more robust calculation. */
|
||||
fpsi->redrawtimes_fps[fpsi->redrawtimes_index] = float(1.0 /
|
||||
(fpsi->lredrawtime - fpsi->redrawtime));
|
||||
fpsi->redrawtimes_index++;
|
||||
if (fpsi->redrawtimes_index > fpsi->redrawtimes_num_set) {
|
||||
fpsi->redrawtimes_num_set = fpsi->redrawtimes_index;
|
||||
}
|
||||
BLI_assert(fpsi->redrawtimes_num_set > 0);
|
||||
float fps = 0.0f;
|
||||
int tot = 0;
|
||||
for (int i = 0; i < REDRAW_FRAME_AVERAGE; i++) {
|
||||
if (fpsi->redrawtimes_fps[i]) {
|
||||
fps += fpsi->redrawtimes_fps[i];
|
||||
tot++;
|
||||
}
|
||||
for (int i = 0; i < fpsi->redrawtimes_num_set; i++) {
|
||||
fps += fpsi->redrawtimes_fps[i];
|
||||
}
|
||||
if (tot) {
|
||||
fpsi->redrawtime_index = (fpsi->redrawtime_index + 1) % REDRAW_FRAME_AVERAGE;
|
||||
fps = fps / tot;
|
||||
}
|
||||
fpsi->fps_average = fps;
|
||||
fpsi->fps_average = fps / float(fpsi->redrawtimes_num_set);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -114,7 +114,7 @@ struct EraseOperationExecutor {
|
|||
}
|
||||
|
||||
struct SegmentCircleIntersection {
|
||||
/* Position of the intersection in the segment.*/
|
||||
/* Position of the intersection in the segment. */
|
||||
float factor = -1.0f;
|
||||
|
||||
/* True if the intersection corresponds to an inside/outside transition with respect to the
|
||||
|
|
|
@ -923,7 +923,10 @@ typedef struct UserDef {
|
|||
/** #eGPUBackendType */
|
||||
short gpu_backend;
|
||||
|
||||
char _pad7[4];
|
||||
/** Number of samples for FPS display calculations. */
|
||||
uchar playback_fps_samples;
|
||||
|
||||
char _pad7[3];
|
||||
|
||||
/** Private, defaults to 20 for 72 DPI setting. */
|
||||
short widget_unit;
|
||||
|
|
|
@ -4833,6 +4833,16 @@ static void rna_def_userdef_view(BlenderRNA *brna)
|
|||
"overlay while animation is played back");
|
||||
RNA_def_property_update(prop, 0, "rna_userdef_update");
|
||||
|
||||
prop = RNA_def_property(srna, "playback_fps_samples", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_int_sdna(prop, nullptr, "playback_fps_samples");
|
||||
RNA_def_property_range(prop, 0, 200);
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"FPS Average Samples",
|
||||
"The number of frames to use for calculating FPS average. "
|
||||
"Zero to calculate this automatically, where the number of samples matches the target FPS");
|
||||
RNA_def_property_update(prop, 0, "rna_userdef_update");
|
||||
|
||||
USERDEF_TAG_DIRTY_PROPERTY_UPDATE_DISABLE;
|
||||
prop = RNA_def_property(srna, "show_addons_enabled_only", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(
|
||||
|
|
|
@ -49,6 +49,52 @@ class TestBlendFileSaveLoadBasic(TestHelper):
|
|||
assert orig_data == read_data
|
||||
|
||||
|
||||
class TestBlendFileSavePartial(TestHelper):
|
||||
OBJECT_MESH_NAME = "ObjectMesh"
|
||||
OBJECT_MATERIAL_NAME = "ObjectMaterial"
|
||||
OBJECT_NAME = "Object"
|
||||
UNUSED_MESH_NAME = "UnusedMesh"
|
||||
|
||||
def __init__(self, args):
|
||||
self.args = args
|
||||
|
||||
def test_save_load(self):
|
||||
bpy.ops.wm.read_homefile(use_empty=True, use_factory_startup=True)
|
||||
|
||||
ob_mesh = bpy.data.meshes.new(self.OBJECT_MESH_NAME)
|
||||
ob_material = bpy.data.materials.new(self.OBJECT_MATERIAL_NAME)
|
||||
ob_mesh.materials.append(ob_material)
|
||||
ob = bpy.data.objects.new(self.OBJECT_NAME, object_data=ob_mesh)
|
||||
bpy.context.collection.objects.link(ob)
|
||||
|
||||
unused_mesh = bpy.data.meshes.new(self.UNUSED_MESH_NAME)
|
||||
unused_mesh.materials.append(ob_material)
|
||||
|
||||
assert ob_mesh.users == 1
|
||||
assert ob_material.users == 2
|
||||
assert ob.users == 1
|
||||
assert unused_mesh.users == 0
|
||||
|
||||
output_dir = self.args.output_dir
|
||||
self.ensure_path(output_dir)
|
||||
|
||||
# Take care to keep the name unique so multiple test jobs can run at once.
|
||||
output_path = os.path.join(output_dir, "blendfile_io_partial.blend")
|
||||
|
||||
bpy.data.libraries.write(filepath=output_path, datablocks={ob, unused_mesh}, fake_user=False)
|
||||
bpy.ops.wm.open_mainfile(filepath=output_path, load_ui=False)
|
||||
|
||||
assert self.OBJECT_MESH_NAME in bpy.data.meshes
|
||||
assert self.OBJECT_MATERIAL_NAME in bpy.data.materials
|
||||
assert self.OBJECT_NAME in bpy.data.objects
|
||||
assert self.UNUSED_MESH_NAME in bpy.data.meshes
|
||||
|
||||
assert bpy.data.meshes[self.OBJECT_MESH_NAME].users == 1
|
||||
assert bpy.data.materials[self.OBJECT_MATERIAL_NAME].users == 2
|
||||
assert bpy.data.objects[self.OBJECT_NAME].users == 0
|
||||
assert bpy.data.meshes[self.UNUSED_MESH_NAME].users == 0
|
||||
|
||||
|
||||
# NOTE: Technically this should rather be in `bl_id_management.py` test, but that file uses `unittest` module,
|
||||
# which makes mixing it with tests system used here and passing extra parameters complicated.
|
||||
# Since the main effect of 'RUNTIME' ID tag is on file save, it can as well be here for now.
|
||||
|
@ -145,6 +191,7 @@ class TestIdRuntimeTag(TestHelper):
|
|||
|
||||
TESTS = (
|
||||
TestBlendFileSaveLoadBasic,
|
||||
TestBlendFileSavePartial,
|
||||
|
||||
TestIdRuntimeTag,
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue