1
1

Compare commits

...

22 Commits

Author SHA1 Message Date
8ea027379d Merge branch 'main' into realtime-clock 2023-03-27 17:55:58 +02:00
7e45dddca0 Add a realtime clock time source node in view layer depsgraphs. 2023-03-27 17:53:56 +02:00
070ac1898a Added a BKE_scene_graph_update_for_timestep function to handle different clocks.
The original `BKE_scene_graph_update_for_newframe` function sets the scene frame
and only tags the scene time source. The new function supports all clock types
while still ensuring only one actual depsgraph evaluation.

It would be nicer if this could be split such that the update passes are more
agnostic towards the specific clock types. The current update pass loop is
quite complicated and handles a lot of corner cases.
2023-03-27 17:22:09 +02:00
76dc5bb263 Match strings to the actual enums of eTimeSourceType. 2023-03-27 16:11:52 +02:00
b26cb5cc0f Merge branch 'main' into realtime-clock 2023-03-27 15:45:56 +02:00
098f6e77d5 Make sure the active_clock flags are updated alongside the animtimer. 2023-03-27 13:53:07 +02:00
1ae6ec4843 Include source type in the depsgraph debug output for time source nodes. 2023-03-27 13:38:28 +02:00
9101a11529 Moved the time source enum into a public C header for tagging functions. 2023-03-27 11:43:45 +02:00
6f48a0f8c0 Separate tagging functions for both clocks and a single depsgraph update. 2023-03-24 15:31:46 +01:00
74b50cf429 Fix memory leak: operators were running as modal when they shouldn't.
The bool return value of the ED_ functions got converted to 1, which
is the operator return value for modal operators.
2023-03-24 15:06:58 +01:00
72ea9f9623 Make sure clock data is cleared when starting a clock again. 2023-03-24 13:56:11 +01:00
2c4e71f4ef Use the same operator for both clocks.
If separate operators are used they will have to return pass-through and,
more importantly, we won't be easily able to ensure a single depsgraph
update.
2023-03-24 13:05:56 +01:00
63f7ffe5c2 Added counters to keep track of elapsed time and frames. 2023-03-24 12:23:34 +01:00
b8e774122f Own editor function for the realtime step depsgraph update. 2023-03-23 18:10:21 +01:00
8794619343 Added operator that runs on timer updates when the realtime clock is running. 2023-03-23 17:20:49 +01:00
21da2024c0 Finished the operators for starting and stopping the realtime clock. 2023-03-23 16:38:52 +01:00
53582157f4 Store both animation and realtime clock data in the animtimer customdata.
Running clocks are identified by the `active_clock` flags now,
the `animtimer` pointer is not sufficient any longer to determine if
animation playback is running.
2023-03-23 15:15:57 +01:00
de531aef2b Only use the animtimer in TransInfo if anim playback is running. 2023-03-23 12:30:59 +01:00
8ca3840b4f Replaced checks for animtimer that are used to check if anim playback is running.
Since the timer is now shared, the existence of the pointer alone is not enough
to determine if animation playback is running. The screen flag (or better:
the ED_screen_animation_is_playing function) should be used for such checks.
2023-03-23 12:24:03 +01:00
b77436b534 Added realtime clock struct in the animtimer customdata.
Multiple clocks can run at the same time, using the same animtimer.
The `active_clock` flags show which clocks are running. If any clock
is running (`active_clock != 0`) the `animtimer` must also exist.
2023-03-23 12:21:52 +01:00
1d13280b01 Operators for starting/stopping the realtime clock. 2023-03-22 17:13:34 +01:00
8501a773e7 Placeholder buttons for starting/stopping realtime clock. 2023-03-22 15:45:31 +01:00
30 changed files with 750 additions and 140 deletions

View File

@@ -8097,6 +8097,31 @@ class VIEW3D_PT_viewport_debug(Panel):
layout.prop(overlay, "use_debug_freeze_view_culling")
class VIEW3D_PT_realtime_clock(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_category = "Realtime"
bl_label = "Realtime Clock"
def draw(self, context):
layout = self.layout
screen = context.screen
row = layout.row(align=True)
row.scale_x = 2
if not screen.is_realtime_clock_running:
row.operator("screen.realtime_clock_start", text="", icon='PLAY')
else:
row.operator("screen.realtime_clock_stop", text="", icon='PAUSE')
row.scale_x = 1
layout.separator_spacer()
layout.prop(screen, "realtime_clock_elapsed_real_time", text="Elapsed Real Time")
layout.prop(screen, "realtime_clock_elapsed_scene_time", text="Elapsed Scene Time")
layout.prop(screen, "realtime_clock_elapsed_frames", text="Elapsed Frames")
classes = (
VIEW3D_HT_header,
VIEW3D_HT_tool_header,
@@ -8339,6 +8364,7 @@ classes = (
VIEW3D_PT_curves_sculpt_parameter_falloff,
VIEW3D_PT_curves_sculpt_grow_shrink_scaling,
VIEW3D_PT_viewport_debug,
VIEW3D_PT_realtime_clock,
)

View File

@@ -206,6 +206,11 @@ void BKE_scene_graph_update_for_newframe(struct Depsgraph *depsgraph);
*/
void BKE_scene_graph_update_for_newframe_ex(struct Depsgraph *depsgraph, bool clear_recalc);
void BKE_scene_graph_update_for_timestep_ex(struct Depsgraph *depsgraph,
int active_clock,
bool clear_recalc);
void BKE_scene_graph_update_for_timestep(struct Depsgraph *depsgraph, int active_clock);
/**
* Ensures given scene/view_layer pair has a valid, up-to-date depsgraph.
*

View File

@@ -2817,6 +2817,103 @@ void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph)
BKE_scene_graph_update_for_newframe_ex(depsgraph, true);
}
void BKE_scene_graph_update_for_timestep_ex(Depsgraph *depsgraph,
const int active_clock,
const bool clear_recalc)
{
Scene *scene = DEG_get_input_scene(depsgraph);
Main *bmain = DEG_get_bmain(depsgraph);
bool used_multiple_passes = false;
/* Keep this first. */
switch (active_clock) {
case ANIMTIMER_ANIMATION:
BKE_callback_exec_id(bmain, &scene->id, BKE_CB_EVT_FRAME_CHANGE_PRE);
break;
case ANIMTIMER_REALTIME:
/* TODO callback for realtime clock updates */
break;
}
for (int pass = 0; pass < 2; pass++) {
switch (active_clock) {
case ANIMTIMER_ANIMATION:
/* Update animated image textures for particles, modifiers, gpu, etc,
* call this at the start so modifiers with textures don't lag 1 frame.
*/
BKE_image_editors_update_frame(bmain, scene->r.cfra);
BKE_sound_set_cfra(scene->r.cfra);
break;
case ANIMTIMER_REALTIME:
break;
}
DEG_graph_relations_update(depsgraph);
/* Update all objects: drivers, matrices, etc. flags set
* by depsgraph or manual, no layer check here, gets correct flushed.
*
* NOTE: Only update for new frame on first iteration. Second iteration is for ensuring user
* edits from callback are properly taken into account. Doing a time update on those would
* lose any possible unkeyed changes made by the handler. */
if (pass == 0) {
DEG_evaluate_on_timestep(depsgraph, active_clock);
}
else {
DEG_evaluate_on_refresh(depsgraph);
}
/* Update sound system animation. */
BKE_scene_update_sound(depsgraph, bmain);
/* Notify editors and python about recalc. */
if (pass == 0) {
switch (active_clock) {
case ANIMTIMER_ANIMATION:
BKE_callback_exec_id_depsgraph(bmain, &scene->id, depsgraph, BKE_CB_EVT_FRAME_CHANGE_POST);
break;
case ANIMTIMER_REALTIME:
/* TODO callback for realtime clock updates */
break;
}
/* NOTE: Similar to this case in scene_graph_update_tagged(). Need to ensure that
* DEG_editors_update() doesn't access freed memory of possibly removed ID. */
DEG_graph_relations_update(depsgraph);
}
/* If user callback did not tag anything for update we can skip second iteration.
* Otherwise we update scene once again, but without running callbacks to bring
* scene to a fully evaluated state with user modifications taken into account. */
if (DEG_is_fully_evaluated(depsgraph)) {
break;
}
/* Clear recalc flags for second pass, but back them up for editors update. */
const bool backup = true;
DEG_ids_clear_recalc(depsgraph, backup);
used_multiple_passes = true;
}
/* Inform editors about changes, using recalc flags from both passes. */
if (used_multiple_passes) {
DEG_ids_restore_recalc(depsgraph);
}
const bool is_time_update = true;
DEG_editors_update(depsgraph, is_time_update);
/* Clear recalc flags, can be skipped for e.g. renderers that will read these
* and clear the flags later. */
if (clear_recalc) {
const bool backup = false;
DEG_ids_clear_recalc(depsgraph, backup);
}
}
void BKE_scene_graph_update_for_timestep(Depsgraph *depsgraph, const int active_clock)
{
BKE_scene_graph_update_for_timestep_ex(depsgraph, active_clock, true);
}
void BKE_scene_view_layer_graph_evaluated_ensure(Main *bmain, Scene *scene, ViewLayer *view_layer)
{
Depsgraph *depsgraph = BKE_scene_ensure_depsgraph(bmain, scene, view_layer);

View File

@@ -263,6 +263,7 @@ static void screen_blend_read_lib(BlendLibReader *reader, ID *id)
BLO_read_id_address(reader, screen->id.lib, &screen->scene);
screen->animtimer = NULL; /* saved in rare cases */
screen->active_clock = 0;
screen->tool_tip = NULL;
screen->scrubbing = false;

View File

@@ -931,7 +931,7 @@ void BKE_sound_seek_scene(Main *bmain, Scene *scene)
animation_playing = 0;
for (screen = bmain->screens.first; screen; screen = screen->id.next) {
if (screen->animtimer) {
if (screen->active_clock & ANIMTIMER_ANIMATION) {
animation_playing = 1;
break;
}

View File

@@ -57,6 +57,14 @@ enum {
DAG_EVAL_NEED_SHRINKWRAP_BOUNDARY = (1 << 1),
};
/* Types of time sources. */
typedef enum eTimeSourceType {
/* Changes of the current scene frame. */
DEG_TIME_SOURCE_SCENE,
/* Ticks of the realtime clock. */
DEG_TIME_SOURCE_REALTIME,
} eTimeSourceType;
#ifdef __cplusplus
extern "C" {
#endif
@@ -134,10 +142,10 @@ void DEG_graph_id_tag_update(struct Main *bmain,
unsigned int flags);
/** Tag all dependency graphs when time has changed. */
void DEG_time_tag_update(struct Main *bmain);
void DEG_time_tag_update(struct Main *bmain, eTimeSourceType time_source_type);
/** Tag a dependency graph when time has changed. */
void DEG_graph_time_tag_update(struct Depsgraph *depsgraph);
void DEG_graph_time_tag_update(struct Depsgraph *depsgraph, eTimeSourceType time_source_type);
/**
* Mark a particular data-block type as having changing.
@@ -187,6 +195,11 @@ void DEG_evaluate_on_framechange(Depsgraph *graph, float frame);
*/
void DEG_evaluate_on_refresh(Depsgraph *graph);
/**
* Generic time step update from frame change or realtime node.
*/
void DEG_evaluate_on_timestep(Depsgraph *graph, int active_clock);
/** \} */
/* -------------------------------------------------------------------- */

View File

@@ -19,7 +19,10 @@ namespace blender::deg {
string TimeSourceKey::identifier() const
{
return string("TimeSourceKey");
string result = string("TimeSourceKey(");
result += string(timeSourceTypeAsString(source_type));
result += ')';
return result;
}
/** \} */

View File

@@ -12,6 +12,7 @@
#include "intern/node/deg_node_component.h"
#include "intern/node/deg_node_id.h"
#include "intern/node/deg_node_operation.h"
#include "intern/node/deg_node_time.h"
#include "DNA_ID.h"
@@ -26,7 +27,13 @@ namespace blender::deg {
struct TimeSourceKey {
TimeSourceKey() = default;
inline TimeSourceKey(eTimeSourceType source_type) : source_type(source_type)
{
}
string identifier() const;
eTimeSourceType source_type = eTimeSourceType::DEG_TIME_SOURCE_SCENE;
};
struct ComponentKey {

View File

@@ -214,9 +214,9 @@ IDNode *DepsgraphNodeBuilder::find_id_node(const ID *id)
return graph_->find_id_node(id);
}
TimeSourceNode *DepsgraphNodeBuilder::add_time_source()
TimeSourceNode *DepsgraphNodeBuilder::add_time_source(eTimeSourceType source_type)
{
return graph_->add_time_source();
return graph_->add_time_source(source_type);
}
ComponentNode *DepsgraphNodeBuilder::add_component_node(ID *id,

View File

@@ -95,7 +95,7 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
IDNode *add_id_node(ID *id);
IDNode *find_id_node(const ID *id);
TimeSourceNode *add_time_source();
TimeSourceNode *add_time_source(eTimeSourceType source_type);
ComponentNode *add_component_node(ID *id, NodeType comp_type, const char *comp_name = "");
ComponentNode *find_component_node(const ID *id, NodeType comp_type, const char *comp_name = "");

View File

@@ -19,7 +19,7 @@ void DepsgraphNodeBuilder::build_scene_render(Scene *scene, ViewLayer *view_laye
const bool build_sequencer = (scene->r.scemode & R_DOSEQ);
IDNode *id_node = add_id_node(&scene->id);
id_node->linked_state = DEG_ID_LINKED_DIRECTLY;
add_time_source();
add_time_source(eTimeSourceType::DEG_TIME_SOURCE_SCENE);
build_animdata(&scene->id);
build_scene_parameters(scene);
build_scene_audio(scene);

View File

@@ -79,7 +79,8 @@ void DepsgraphNodeBuilder::build_view_layer(Scene *scene,
IDNode *id_node = add_id_node(&scene->id);
id_node->linked_state = linked_state;
/* Time source. */
add_time_source();
add_time_source(eTimeSourceType::DEG_TIME_SOURCE_SCENE);
add_time_source(eTimeSourceType::DEG_TIME_SOURCE_REALTIME);
/* Setup currently building context. */
scene_ = scene;
view_layer_ = view_layer;

View File

@@ -245,9 +245,9 @@ DepsgraphRelationBuilder::DepsgraphRelationBuilder(Main *bmain,
{
}
TimeSourceNode *DepsgraphRelationBuilder::get_node(const TimeSourceKey & /*key*/) const
TimeSourceNode *DepsgraphRelationBuilder::get_node(const TimeSourceKey &key) const
{
return graph_->time_source;
return graph_->find_time_source(key.source_type);
}
ComponentNode *DepsgraphRelationBuilder::get_node(const ComponentKey &key) const

View File

@@ -470,10 +470,9 @@ static void deg_debug_graphviz_graph_nodes(DotExportContext &ctx, const Depsgrap
for (Node *node : graph->id_nodes) {
deg_debug_graphviz_node(ctx, node, nullptr);
}
TimeSourceNode *time_source = graph->find_time_source();
if (time_source != nullptr) {
graph->time_sources.foreach_item([&ctx](eTimeSourceType, const TimeSourceNode *time_source) {
deg_debug_graphviz_node(ctx, time_source, nullptr);
}
});
}
static void deg_debug_graphviz_graph_relations(DotExportContext &ctx, const Depsgraph *graph)
@@ -486,10 +485,9 @@ static void deg_debug_graphviz_graph_relations(DotExportContext &ctx, const Deps
}
}
TimeSourceNode *time_source = graph->find_time_source();
if (time_source != nullptr) {
graph->time_sources.foreach_item([&ctx](eTimeSourceType, const TimeSourceNode *time_source) {
deg_debug_graphviz_node_relations(ctx, time_source);
}
});
}
} // namespace blender::deg

View File

@@ -44,8 +44,7 @@ namespace deg = blender::deg;
namespace blender::deg {
Depsgraph::Depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluationMode mode)
: time_source(nullptr),
has_animated_visibility(false),
: has_animated_visibility(false),
need_update_relations(true),
need_update_nodes_visibility(true),
need_tag_id_on_graph_visibility_update(true),
@@ -68,35 +67,47 @@ Depsgraph::Depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluati
memset(id_type_exist, 0, sizeof(id_type_exist));
memset(physics_relations, 0, sizeof(physics_relations));
add_time_source();
add_time_source(eTimeSourceType::DEG_TIME_SOURCE_SCENE);
}
Depsgraph::~Depsgraph()
{
clear_id_nodes();
delete time_source;
clear_time_sources();
BLI_spin_end(&lock);
}
/* Node Management ---------------------------- */
TimeSourceNode *Depsgraph::add_time_source()
TimeSourceNode *Depsgraph::add_time_source(eTimeSourceType source_type)
{
if (time_source == nullptr) {
return time_sources.lookup_or_add_cb(source_type, [source_type]() {
DepsNodeFactory *factory = type_get_factory(NodeType::TIMESOURCE);
time_source = (TimeSourceNode *)factory->create_node(nullptr, "", "Time Source");
TimeSourceNode *time_source = (TimeSourceNode *)factory->create_node(nullptr, "", "Time Source");
time_source->source_type = source_type;
return time_source;
});
}
TimeSourceNode *Depsgraph::find_time_source(eTimeSourceType source_type) const
{
return time_sources.lookup_default(source_type, nullptr);
}
void Depsgraph::clear_time_sources()
{
time_sources.foreach_item([](eTimeSourceType, TimeSourceNode *time_source) {
delete time_source;
});
time_sources.clear();
}
void Depsgraph::tag_time_source(eTimeSourceType source_type)
{
TimeSourceNode *time_source = time_sources.lookup_default(source_type, nullptr);
if (time_source) {
time_source->tag_update(this, DEG_UPDATE_SOURCE_TIME);
}
return time_source;
}
TimeSourceNode *Depsgraph::find_time_source() const
{
return time_source;
}
void Depsgraph::tag_time_source()
{
time_source->tag_update(this, DEG_UPDATE_SOURCE_TIME);
}
IDNode *Depsgraph::find_id_node(const ID *id) const
@@ -230,8 +241,7 @@ void Depsgraph::add_entry_tag(OperationNode *node)
void Depsgraph::clear_all_nodes()
{
clear_id_nodes();
delete time_source;
time_source = nullptr;
clear_time_sources();
}
ID *Depsgraph::get_cow_id(const ID *id_orig) const

View File

@@ -47,9 +47,10 @@ struct Depsgraph {
Depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluationMode mode);
~Depsgraph();
TimeSourceNode *add_time_source();
TimeSourceNode *find_time_source() const;
void tag_time_source();
TimeSourceNode *add_time_source(eTimeSourceType source_type);
TimeSourceNode *find_time_source(eTimeSourceType source_type) const;
void clear_time_sources();
void tag_time_source(eTimeSourceType source_type);
IDNode *find_id_node(const ID *id) const;
IDNode *add_id_node(ID *id, ID *id_cow_hint = nullptr);
@@ -85,8 +86,8 @@ struct Depsgraph {
* keep exact order of iteration. */
IDDepsNodes id_nodes;
/* Top-level time source node. */
TimeSourceNode *time_source;
/* Top-level time source node by source type. */
Map<eTimeSourceType, TimeSourceNode *> time_sources;
/* The graph contains data-blocks whose visibility depends on evaluation (driven or animated). */
bool has_animated_visibility;

View File

@@ -209,10 +209,9 @@ void DEG_stats_simple(const Depsgraph *graph,
}
}
deg::TimeSourceNode *time_source = deg_graph->find_time_source();
if (time_source != nullptr) {
deg_graph->time_sources.foreach_item([&tot_rels](eTimeSourceType, const deg::TimeSourceNode *time_source) {
tot_rels += time_source->inlinks.size();
}
});
if (r_relations) {
*r_relations = tot_rels;

View File

@@ -16,6 +16,7 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
@@ -52,7 +53,8 @@ void DEG_evaluate_on_refresh(Depsgraph *graph)
const float ctime = BKE_scene_ctime_get(scene);
if (deg_graph->frame != frame || ctime != deg_graph->ctime) {
deg_graph->tag_time_source();
/* Scene frame changed. */
deg_graph->tag_time_source(eTimeSourceType::DEG_TIME_SOURCE_SCENE);
deg_graph->frame = frame;
deg_graph->ctime = ctime;
}
@@ -62,7 +64,7 @@ void DEG_evaluate_on_refresh(Depsgraph *graph)
* In this case reading back the undo state will behave as if no updates on frame change
* is needed as the #Depsgraph.ctime & frame will match the values in the input scene.
* Use #ID_RECALC_FRAME_CHANGE to detect that recalculation is necessary. see: #66913. */
deg_graph->tag_time_source();
deg_graph->tag_time_source(eTimeSourceType::DEG_TIME_SOURCE_SCENE);
}
deg_flush_updates_and_refresh(deg_graph);
@@ -73,8 +75,30 @@ void DEG_evaluate_on_framechange(Depsgraph *graph, float frame)
deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(graph);
const Scene *scene = DEG_get_input_scene(graph);
deg_graph->tag_time_source();
deg_graph->tag_time_source(eTimeSourceType::DEG_TIME_SOURCE_SCENE);
deg_graph->frame = frame;
deg_graph->ctime = BKE_scene_frame_to_ctime(scene, frame);
deg_flush_updates_and_refresh(deg_graph);
}
void DEG_evaluate_on_timestep(Depsgraph *graph, int active_clock)
{
deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(graph);
switch (active_clock) {
case ANIMTIMER_ANIMATION: {
const Scene *scene = DEG_get_input_scene(graph);
const float frame = BKE_scene_frame_get(scene);
const float ctime = BKE_scene_ctime_get(scene);
deg_graph->tag_time_source(eTimeSourceType::DEG_TIME_SOURCE_SCENE);
deg_graph->frame = frame;
deg_graph->ctime = ctime;
break;
}
case ANIMTIMER_REALTIME:
deg_graph->tag_time_source(eTimeSourceType::DEG_TIME_SOURCE_REALTIME);
break;
}
deg_flush_updates_and_refresh(deg_graph);
}

View File

@@ -789,17 +789,17 @@ void DEG_graph_id_tag_update(struct Main *bmain,
deg::graph_id_tag_update(bmain, graph, id, flags, deg::DEG_UPDATE_SOURCE_USER_EDIT);
}
void DEG_time_tag_update(struct Main *bmain)
void DEG_time_tag_update(struct Main *bmain, eTimeSourceType time_source_type)
{
for (deg::Depsgraph *depsgraph : deg::get_all_registered_graphs(bmain)) {
DEG_graph_time_tag_update(reinterpret_cast<::Depsgraph *>(depsgraph));
DEG_graph_time_tag_update(reinterpret_cast<::Depsgraph *>(depsgraph), time_source_type);
}
}
void DEG_graph_time_tag_update(struct Depsgraph *depsgraph)
void DEG_graph_time_tag_update(struct Depsgraph *depsgraph, eTimeSourceType time_source_type)
{
deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(depsgraph);
deg_graph->tag_time_source();
deg_graph->tag_time_source(time_source_type);
}
void DEG_graph_id_type_tag(Depsgraph *depsgraph, short id_type)

View File

@@ -347,7 +347,10 @@ void deg_graph_flush_updates(Depsgraph *graph)
BLI_assert(graph != nullptr);
Main *bmain = graph->bmain;
graph->time_source->flush_update_tag(graph);
graph->time_sources.foreach_item(
[graph](eTimeSourceType, TimeSourceNode *time_source) {
time_source->flush_update_tag(graph);
});
/* Nothing to update, early out. */
if (graph->entry_tags.is_empty()) {
@@ -392,7 +395,9 @@ void deg_graph_clear_tags(Depsgraph *graph)
/* Clear any entry tags which haven't been flushed. */
graph->entry_tags.clear();
graph->time_source->tagged_for_update = false;
graph->time_sources.foreach_item([](eTimeSourceType, TimeSourceNode *time_source) {
time_source->tagged_for_update = false;
});
}
} // namespace blender::deg

View File

@@ -11,9 +11,35 @@
#include "intern/depsgraph.h"
#include "intern/depsgraph_relation.h"
#include "intern/node/deg_node_factory.h"
namespace blender::deg {
const char *timeSourceTypeAsString(eTimeSourceType source_type)
{
switch (source_type) {
case eTimeSourceType::DEG_TIME_SOURCE_SCENE:
return "SCENE";
case eTimeSourceType::DEG_TIME_SOURCE_REALTIME:
return "REALTIME";
}
BLI_assert_msg(0, "Unhandled time source type, should never happen.");
return "UNKNOWN";
}
TimeSourceNode::TimeSourceNode() : source_type(eTimeSourceType::DEG_TIME_SOURCE_SCENE)
{
}
string TimeSourceNode::identifier() const
{
const string type_name = type_get_factory(type)->type_name();
const string name_part = name[0] ? (string(" '") + name + "'") : "";
return "[" + type_name + "]" + name_part + " : " +
"(source_type: " + timeSourceTypeAsString(source_type) + ")";
}
void TimeSourceNode::tag_update(Depsgraph * /*graph*/, eUpdateSource /*source*/)
{
tagged_for_update = true;

View File

@@ -7,13 +7,19 @@
#pragma once
#include "DEG_depsgraph.h"
#include "intern/node/deg_node.h"
namespace blender::deg {
const char *timeSourceTypeAsString(eTimeSourceType source_type);
/* Time Source Node. */
struct TimeSourceNode : public Node {
bool tagged_for_update = false;
TimeSourceNode();
virtual string identifier() const override;
// TODO: evaluate() operation needed
@@ -21,6 +27,11 @@ struct TimeSourceNode : public Node {
void flush_update_tag(Depsgraph *graph);
/* Type of time source. */
eTimeSourceType source_type;
bool tagged_for_update = false;
DEG_DEPSNODE_DECLARE;
};

View File

@@ -320,7 +320,9 @@ void ED_screen_exit(struct bContext *C, struct wmWindow *window, struct bScreen
* \param enable: 1 - forward on, -1 - backwards on, 0 - off.
*/
void ED_screen_animation_timer(struct bContext *C, int redraws, int sync, int enable);
void ED_screen_realtime_timer(struct bContext *C, int redraws, bool enable);
void ED_screen_animation_timer_update(struct bScreen *screen, int redraws);
void ED_screen_realtime_timer_update(struct bScreen *screen, int redraws);
void ED_screen_restore_temp_type(struct bContext *C, ScrArea *area);
ScrArea *ED_screen_full_newspace(struct bContext *C, ScrArea *area, int type);
/**
@@ -473,6 +475,14 @@ void ED_workspace_status_text(struct bContext *C, const char *str);
void ED_workspace_do_listen(struct bContext *C, const struct wmNotifier *note);
/* anim */
/**
* Tag for depsgraph update after frame changes.
*/
void ED_tag_for_newframe(struct Main *bmain, struct Scene *scene);
/**
* Tag for depsgraph update after realtime clock step.
*/
void ED_tag_for_realtime_clock(struct Main *bmain, struct Scene *scene);
/**
* Results in fully updated anim system.
*/
@@ -486,11 +496,31 @@ void ED_refresh_viewport_fps(struct bContext *C);
* Toggle operator.
*/
int ED_screen_animation_play(struct bContext *C, int sync, int mode);
/**
* Start realtime clock.
*/
int ED_screen_realtime_clock_start(struct bContext *C);
/**
* Stop realtime clock.
*/
int ED_screen_realtime_clock_stop(struct bContext *C);
/**
* Animation is playing.
*/
bool ED_screen_animation_is_playing(struct bScreen *screen);
/**
* Realtime clock is running.
*/
bool ED_screen_realtime_clock_is_running(struct bScreen *screen);
/**
* Find window that owns the animation timer.
*/
bScreen *ED_screen_animation_playing(const struct wmWindowManager *wm);
bScreen *ED_screen_animation_no_scrub(const struct wmWindowManager *wm);
/**
* Find screen that owns the realtime clock timer.
*/
bScreen *ED_screen_realtime_clock_running(const struct wmWindowManager *wm);
/* screen keymaps */
/* called in spacetypes.c */

View File

@@ -14,7 +14,7 @@ extern "C" {
/* ----------------------------------------------------- */
/**
* For animation playback operator, stored in #bScreen.animtimer.customdata.
* For animation playback operator.
*/
typedef struct ScreenAnimData {
ARegion *region; /* do not read from this, only for comparing if region exists */
@@ -26,7 +26,27 @@ typedef struct ScreenAnimData {
bool from_anim_edit; /* playback was invoked from animation editor */
} ScreenAnimData;
/** #ScreenAnimData.flag */
/**
* Realtime clock data.
*/
typedef struct ScreenRealtimeData {
ARegion *region; /* do not read from this, only for comparing if region exists */
short flag;
short redraws; /* Which editors get redrawn during animation playback */
float elapsed_real_time; /* Real physical time elapsed since the clock was started */
float elapsed_scene_time; /* Scene time (1/fps) elapsed since the clock was started */
int elapsed_frames; /* Amount of frames since the clock was started */
} ScreenRealtimeData;
/**
* Shared timer data for animation playback and realtime clock, stored in #bScreen.animtimer.customdata.
*/
typedef struct ScreenTimerData {
ScreenAnimData animation;
ScreenRealtimeData realtime;
} ScreenTimerData;
/** #ScreenAnimData.animation.flag */
enum {
/* user-setting - frame range is played backwards */
ANIMPLAY_FLAG_REVERSE = (1 << 0),

View File

@@ -795,6 +795,7 @@ void ED_screen_exit(bContext *C, wmWindow *window, bScreen *screen)
BKE_sound_stop_scene(scene_eval);
}
screen->animtimer = NULL;
screen->active_clock = 0;
screen->scrubbing = false;
screen->active_region = NULL;
@@ -1137,6 +1138,7 @@ void screen_change_prepare(
if (screen_old != screen_new) {
wmTimer *wt = screen_old->animtimer;
int active_clock = screen_old->active_clock;
/* remove handlers referencing areas in old screen */
LISTBASE_FOREACH (ScrArea *, area, &screen_old->areabase) {
@@ -1145,6 +1147,7 @@ void screen_change_prepare(
/* we put timer to sleep, so screen_exit has to think there's no timer */
screen_old->animtimer = NULL;
screen_old->active_clock = 0;
if (wt) {
WM_event_timer_sleep(CTX_wm_manager(C), win, wt, true);
}
@@ -1153,6 +1156,7 @@ void screen_change_prepare(
/* Same scene, "transfer" playback to new screen. */
if (wt) {
screen_new->animtimer = wt;
screen_new->active_clock = active_clock;
}
}
}
@@ -1409,7 +1413,9 @@ static bScreen *screen_state_to_nonnormal(bContext *C,
/* timer */
screen->animtimer = oldscreen->animtimer;
screen->active_clock = oldscreen->active_clock;
oldscreen->animtimer = NULL;
oldscreen->active_clock = 0;
newa = (ScrArea *)screen->areabase.first;
@@ -1522,7 +1528,9 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, const
/* animtimer back */
screen->animtimer = oldscreen->animtimer;
screen->active_clock = oldscreen->active_clock;
oldscreen->animtimer = NULL;
oldscreen->active_clock = 0;
ED_screen_change(C, screen);
@@ -1636,24 +1644,59 @@ void ED_refresh_viewport_fps(bContext *C)
}
}
void ED_screen_animation_timer(bContext *C, int redraws, int sync, int enable)
static ScreenTimerData *screen_timer_ensure(bContext *C, int clock)
{
bScreen *screen = CTX_wm_screen(C);
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
Scene *scene = CTX_data_scene(C);
bScreen *stopscreen = ED_screen_animation_playing(wm);
if (stopscreen) {
WM_event_remove_timer(wm, win, stopscreen->animtimer);
stopscreen->animtimer = NULL;
}
if (enable) {
ScreenAnimData *sad = MEM_callocN(sizeof(ScreenAnimData), "ScreenAnimData");
BLI_assert(screen != NULL);
/* Check that timer exists if any clock is active */
BLI_assert((screen->animtimer == NULL) == (screen->active_clock == 0));
if (screen->animtimer == NULL) {
screen->animtimer = WM_event_add_timer(wm, win, TIMER0, (1.0 / FPS));
ScreenTimerData *timer_data = MEM_callocN(sizeof(ScreenTimerData), "ScreenTimerData");
screen->animtimer->customdata = timer_data;
}
screen->active_clock |= clock;
return (ScreenTimerData *)screen->animtimer->customdata;
}
static void screen_timer_stop(bContext *C, bScreen *screen, int clock)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
if (screen) {
/* Check that timer exists if any clock is active */
BLI_assert((screen->animtimer == NULL) == (screen->active_clock == 0));
screen->active_clock &= ~clock;
if (screen->active_clock == 0) {
WM_event_remove_timer(wm, win, screen->animtimer);
screen->animtimer = NULL;
}
}
}
void ED_screen_animation_timer(bContext *C, int redraws, int sync, int enable)
{
wmWindowManager *wm = CTX_wm_manager(C);
Scene *scene = CTX_data_scene(C);
bScreen *stopscreen = ED_screen_animation_playing(wm);
screen_timer_stop(C, stopscreen, ANIMTIMER_ANIMATION);
if (enable) {
ScreenAnimData *sad = &screen_timer_ensure(C, ANIMTIMER_ANIMATION)->animation;
memset(sad, 0, sizeof(*sad));
sad->region = CTX_wm_region(C);
/* If start-frame is larger than current frame, we put current-frame on start-frame.
* NOTE(ton): first frame then is not drawn! */
@@ -1688,8 +1731,6 @@ void ED_screen_animation_timer(bContext *C, int redraws, int sync, int enable)
}
sad->from_anim_edit = ELEM(spacetype, SPACE_GRAPH, SPACE_ACTION, SPACE_NLA);
screen->animtimer->customdata = sad;
}
/* Seek audio to ensure playback in preview range with AV sync. */
@@ -1699,6 +1740,29 @@ void ED_screen_animation_timer(bContext *C, int redraws, int sync, int enable)
WM_event_add_notifier(C, NC_SCREEN | ND_ANIMPLAY, NULL);
}
void ED_screen_realtime_timer(bContext *C, int redraws, bool enable)
{
wmWindowManager *wm = CTX_wm_manager(C);
bScreen *stopscreen = ED_screen_realtime_clock_running(wm);
screen_timer_stop(C, stopscreen, ANIMTIMER_REALTIME);
if (enable) {
ScreenRealtimeData *srd = &screen_timer_ensure(C, ANIMTIMER_REALTIME)->realtime;
memset(srd, 0, sizeof(*srd));
srd->region = CTX_wm_region(C);
srd->flag = 0;
srd->redraws = redraws;
}
// /* Seek audio to ensure playback in preview range with AV sync. */
// DEG_id_tag_update(&scene->id, ID_RECALC_FRAME_CHANGE);
// /* Notifier caught by top header, for button. */
// WM_event_add_notifier(C, NC_SCREEN | ND_ANIMPLAY, NULL);
}
/* helper for screen_animation_play() - only to be used for TimeLine */
static ARegion *time_top_left_3dwindow(bScreen *screen)
{
@@ -1723,9 +1787,9 @@ static ARegion *time_top_left_3dwindow(bScreen *screen)
void ED_screen_animation_timer_update(bScreen *screen, int redraws)
{
if (screen && screen->animtimer) {
wmTimer *wt = screen->animtimer;
ScreenAnimData *sad = wt->customdata;
if (screen && (screen->active_clock & ANIMTIMER_ANIMATION)) {
ScreenTimerData *timer_data = screen->animtimer->customdata;
ScreenAnimData *sad = &timer_data->animation;
sad->redraws = redraws;
sad->region = NULL;
@@ -1735,11 +1799,25 @@ void ED_screen_animation_timer_update(bScreen *screen, int redraws)
}
}
void ED_update_for_newframe(Main *bmain, Depsgraph *depsgraph)
void ED_screen_realtime_timer_update(bScreen *screen, int redraws)
{
Scene *scene = DEG_get_input_scene(depsgraph);
if (screen && (screen->active_clock & ANIMTIMER_REALTIME)) {
ScreenTimerData *timer_data = screen->animtimer->customdata;
ScreenRealtimeData *srd = &timer_data->realtime;
DEG_time_tag_update(bmain);
srd->redraws = redraws;
srd->redraws = redraws;
srd->region = NULL;
/* TODO this might require its own TIME_ region flag depending on where the realtime clock ends up. */
// if (redraws & TIME_REGION) {
// srd->region = time_top_left_3dwindow(screen);
// }
}
}
void ED_tag_for_newframe(Main *bmain, Scene *scene)
{
DEG_time_tag_update(bmain, DEG_TIME_SOURCE_SCENE);
#ifdef DURIAN_CAMERA_SWITCH
void *camera = BKE_scene_camera_switch_find(scene);
@@ -1754,6 +1832,17 @@ void ED_update_for_newframe(Main *bmain, Depsgraph *depsgraph)
#endif
ED_clip_update_frame(bmain, scene->r.cfra);
}
void ED_tag_for_realtime_clock(Main *bmain, Scene *scene)
{
DEG_time_tag_update(bmain, DEG_TIME_SOURCE_REALTIME);
}
void ED_update_for_newframe(Main *bmain, Depsgraph *depsgraph)
{
Scene *scene = DEG_get_input_scene(depsgraph);
ED_tag_for_newframe(bmain, scene);
/* this function applies the changes too */
BKE_scene_graph_update_for_newframe(depsgraph);

View File

@@ -2995,14 +2995,14 @@ static void SCREEN_OT_frame_offset(wmOperatorType *ot)
static int frame_jump_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
wmTimer *animtimer = CTX_wm_screen(C)->animtimer;
bScreen *screen = CTX_wm_screen(C);
/* Don't change scene->r.cfra directly if animtimer is running as this can cause
* first/last frame not to be actually shown (bad since for example physics
* simulations aren't reset properly).
*/
if (animtimer) {
ScreenAnimData *sad = animtimer->customdata;
if (ED_screen_animation_is_playing(screen)) {
ScreenAnimData *sad = &((ScreenTimerData *)screen->animtimer->customdata)->animation;
sad->flag |= ANIMPLAY_FLAG_USE_NEXT_FRAME;
@@ -4415,7 +4415,8 @@ static bool screen_animation_region_supports_time_follow(eSpace_Type spacetype,
static bool match_region_with_redraws(const ScrArea *area,
eRegion_Type regiontype,
eScreen_Redraws_Flag redraws,
bool from_anim_edit)
bool from_anim_edit,
bool from_realtime_clock)
{
const eSpace_Type spacetype = area->spacetype;
if (regiontype == RGN_TYPE_WINDOW) {
@@ -4469,13 +4470,21 @@ static bool match_region_with_redraws(const ScrArea *area,
}
}
else if (regiontype == RGN_TYPE_UI) {
if (spacetype == SPACE_CLIP) {
/* Track Preview button is on Properties Editor in SpaceClip,
* and it's very common case when users want it be refreshing
* during playback, so asking people to enable special option
* for this is a bit tricky, so add exception here for refreshing
* Properties Editor for SpaceClip always */
return true;
switch (spacetype) {
case SPACE_CLIP:
/* Track Preview button is on Properties Editor in SpaceClip,
* and it's very common case when users want it be refreshing
* during playback, so asking people to enable special option
* for this is a bit tricky, so add exception here for refreshing
* Properties Editor for SpaceClip always */
return true;
case SPACE_VIEW3D:
/* Realtime clock is displayed in View3D buttons */
if (from_realtime_clock) {
return true;
}
default:
break;
}
if (redraws & TIME_ALL_BUTS_WIN) {
@@ -4566,15 +4575,10 @@ static void screen_animation_region_tag_redraw(
//#define PROFILE_AUDIO_SYNCH
static int screen_animation_step_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
static void screen_animation_step_playback(bContext *C)
{
bScreen *screen = CTX_wm_screen(C);
wmTimer *wt = screen->animtimer;
if (!(wt && wt == event->customdata)) {
return OPERATOR_PASS_THROUGH;
}
wmWindow *win = CTX_wm_window(C);
#ifdef PROFILE_AUDIO_SYNCH
@@ -4582,13 +4586,11 @@ static int screen_animation_step_invoke(bContext *C, wmOperator *UNUSED(op), con
int newfra_int;
#endif
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer);
Scene *scene_eval = (depsgraph != NULL) ? DEG_get_evaluated_scene(depsgraph) : NULL;
ScreenAnimData *sad = wt->customdata;
wmWindowManager *wm = CTX_wm_manager(C);
ScreenAnimData *sad = &((ScreenTimerData *)wt->customdata)->animation;
int sync;
double time;
@@ -4726,10 +4728,53 @@ static int screen_animation_step_invoke(bContext *C, wmOperator *UNUSED(op), con
old_frame = scene->r.cfra;
#endif
}
}
static void screen_animation_step_realtime(bContext *C)
{
bScreen *screen = CTX_wm_screen(C);
wmTimer *wt = screen->animtimer;
ScreenRealtimeData *srd = &((ScreenTimerData *)wt->customdata)->realtime;
srd->elapsed_real_time += wt->delta;
srd->elapsed_scene_time += wt->timestep;
srd->elapsed_frames += 1;
}
static int screen_animation_step_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
wmWindowManager *wm = CTX_wm_manager(C);
bScreen *screen = CTX_wm_screen(C);
wmTimer *wt = screen->animtimer;
wmWindow *win = CTX_wm_window(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer);
if (screen->active_clock == 0 || !wt || wt != event->customdata) {
return OPERATOR_PASS_THROUGH;
}
if (screen->active_clock & ANIMTIMER_ANIMATION) {
screen_animation_step_playback(C);
}
if (screen->active_clock & ANIMTIMER_REALTIME) {
screen_animation_step_realtime(C);
}
/* Since we follow draw-flags, we can't send notifier but tag regions ourselves. */
if (depsgraph != NULL) {
ED_update_for_newframe(bmain, depsgraph);
Main *bmain = CTX_data_main(C);
Scene *eval_scene = DEG_get_input_scene(depsgraph);
if (screen->active_clock & ANIMTIMER_ANIMATION) {
ED_tag_for_newframe(bmain, eval_scene);
}
if (screen->active_clock & ANIMTIMER_REALTIME) {
ED_tag_for_realtime_clock(bmain, eval_scene);
}
BKE_scene_graph_update_for_timestep(depsgraph, screen->active_clock);
}
LISTBASE_FOREACH (wmWindow *, window, &wm->windows) {
@@ -4737,17 +4782,28 @@ static int screen_animation_step_invoke(bContext *C, wmOperator *UNUSED(op), con
LISTBASE_FOREACH (ScrArea *, area, &win_screen->areabase) {
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
bool redraw = false;
if (region == sad->region) {
redraw = true;
if (screen->active_clock & ANIMTIMER_ANIMATION) {
ScreenAnimData *sad = &((ScreenTimerData *)wt->customdata)->animation;
bool redraw = false;
if (region == sad->region ||
match_region_with_redraws(
area, region->regiontype, sad->redraws, sad->from_anim_edit, false)) {
redraw = true;
}
if (redraw) {
screen_animation_region_tag_redraw(C, area, region, scene, sad->redraws);
}
}
else if (match_region_with_redraws(
area, region->regiontype, sad->redraws, sad->from_anim_edit)) {
redraw = true;
}
if (redraw) {
screen_animation_region_tag_redraw(C, area, region, scene, sad->redraws);
if (screen->active_clock & ANIMTIMER_REALTIME) {
ScreenRealtimeData *srd = &((ScreenTimerData *)wt->customdata)->realtime;
bool redraw = false;
if (region == srd->region ||
match_region_with_redraws(area, region->regiontype, srd->redraws, false, true)) {
redraw = true;
}
if (redraw) {
screen_animation_region_tag_redraw(C, area, region, scene, srd->redraws);
}
}
}
}
@@ -4790,32 +4846,6 @@ static void SCREEN_OT_animation_step(wmOperatorType *ot)
* Animation Playback with Timer.
* \{ */
bScreen *ED_screen_animation_playing(const wmWindowManager *wm)
{
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
bScreen *screen = WM_window_get_active_screen(win);
if (screen->animtimer || screen->scrubbing) {
return screen;
}
}
return NULL;
}
bScreen *ED_screen_animation_no_scrub(const wmWindowManager *wm)
{
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
bScreen *screen = WM_window_get_active_screen(win);
if (screen->animtimer) {
return screen;
}
}
return NULL;
}
int ED_screen_animation_play(bContext *C, int sync, int mode)
{
bScreen *screen = CTX_wm_screen(C);
@@ -4837,9 +4867,8 @@ int ED_screen_animation_play(bContext *C, int sync, int mode)
ED_screen_animation_timer(C, screen->redraws_flag, sync, mode);
if (screen->animtimer) {
wmTimer *wt = screen->animtimer;
ScreenAnimData *sad = wt->customdata;
if (screen->active_clock & ANIMTIMER_ANIMATION) {
ScreenAnimData *sad = &((ScreenTimerData *)screen->animtimer->customdata)->animation;
sad->region = CTX_wm_region(C);
}
@@ -4848,6 +4877,80 @@ int ED_screen_animation_play(bContext *C, int sync, int mode)
return OPERATOR_FINISHED;
}
int ED_screen_realtime_clock_start(bContext *C)
{
bScreen *screen = CTX_wm_screen(C);
// Scene *scene_eval = DEG_get_evaluated_scene(CTX_data_ensure_evaluated_depsgraph(C));
// BKE_sound_play_scene(scene_eval);
ED_screen_realtime_timer(C, screen->redraws_flag, true);
return OPERATOR_FINISHED;
}
int ED_screen_realtime_clock_stop(bContext *C)
{
Scene *scene = CTX_data_scene(C);
// Scene *scene_eval = DEG_get_evaluated_scene(CTX_data_ensure_evaluated_depsgraph(C));
/* stop playback now */
ED_screen_realtime_timer(C, 0, false);
// BKE_sound_stop_scene(scene_eval);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
return OPERATOR_FINISHED;
}
bool ED_screen_animation_is_playing(bScreen *screen)
{
return screen && screen->active_clock & ANIMTIMER_ANIMATION;
}
bool ED_screen_realtime_clock_is_running(bScreen *screen)
{
return screen && screen->active_clock & ANIMTIMER_REALTIME;
}
bScreen *ED_screen_animation_playing(const wmWindowManager *wm)
{
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
bScreen *screen = WM_window_get_active_screen(win);
if (screen->active_clock & ANIMTIMER_ANIMATION || screen->scrubbing) {
return screen;
}
}
return NULL;
}
bScreen *ED_screen_animation_no_scrub(const wmWindowManager *wm)
{
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
bScreen *screen = WM_window_get_active_screen(win);
if (screen->active_clock & ANIMTIMER_ANIMATION) {
return screen;
}
}
return NULL;
}
bScreen *ED_screen_realtime_clock_running(const wmWindowManager *wm)
{
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
bScreen *screen = WM_window_get_active_screen(win);
if (screen->active_clock & ANIMTIMER_REALTIME) {
return screen;
}
}
return NULL;
}
static int screen_animation_play_exec(bContext *C, wmOperator *op)
{
int mode = RNA_boolean_get(op->ptr, "reverse") ? -1 : 1;
@@ -4892,8 +4995,9 @@ static int screen_animation_cancel_exec(bContext *C, wmOperator *op)
bScreen *screen = ED_screen_animation_playing(CTX_wm_manager(C));
if (screen) {
if (RNA_boolean_get(op->ptr, "restore_frame") && screen->animtimer) {
ScreenAnimData *sad = screen->animtimer->customdata;
if (RNA_boolean_get(op->ptr, "restore_frame") &&
(screen->active_clock & ANIMTIMER_ANIMATION)) {
ScreenAnimData *sad = &((ScreenTimerData *)screen->animtimer->customdata)->animation;
Scene *scene = CTX_data_scene(C);
/* reset current frame before stopping, and just send a notifier to deal with the rest
@@ -4932,6 +5036,59 @@ static void SCREEN_OT_animation_cancel(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
/** \name Realtime Clock Start
* \{ */
static int screen_realtime_clock_start_exec(bContext *C, wmOperator *UNUSED(op))
{
return ED_screen_realtime_clock_start(C);
}
static void SCREEN_OT_realtime_clock_start(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Start Realtime Clock";
ot->description = "Start realtime clock";
ot->idname = "SCREEN_OT_realtime_clock_start";
/* api callbacks */
ot->exec = screen_realtime_clock_start_exec;
ot->poll = ED_operator_screenactive_norender;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Realtime Clock Stop Operator
* \{ */
static int screen_realtime_clock_stop_exec(bContext *C, wmOperator *UNUSED(op))
{
bScreen *screen = ED_screen_realtime_clock_running(CTX_wm_manager(C));
if (screen) {
/* call the other "toggling" operator to clean up now */
ED_screen_realtime_clock_stop(C);
}
return OPERATOR_PASS_THROUGH;
}
static void SCREEN_OT_realtime_clock_stop(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Stop Realtime Clock";
ot->description = "Stop realtime clock";
ot->idname = "SCREEN_OT_realtime_clock_stop";
/* api callbacks */
ot->exec = screen_realtime_clock_stop_exec;
ot->poll = ED_operator_screenactive;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Box Select Operator (Template)
* \{ */
@@ -5720,6 +5877,10 @@ void ED_operatortypes_screen(void)
WM_operatortype_append(SCREEN_OT_animation_play);
WM_operatortype_append(SCREEN_OT_animation_cancel);
/* Realtime clock */
WM_operatortype_append(SCREEN_OT_realtime_clock_start);
WM_operatortype_append(SCREEN_OT_realtime_clock_stop);
/* New/delete. */
WM_operatortype_append(SCREEN_OT_new);
WM_operatortype_append(SCREEN_OT_delete);

View File

@@ -250,7 +250,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
if (t->spacetype == SPACE_VIEW3D) {
bScreen *animscreen = ED_screen_animation_playing(CTX_wm_manager(C));
t->animtimer = (animscreen) ? animscreen->animtimer : NULL;
t->animtimer = ED_screen_animation_is_playing(animscreen) ? animscreen->animtimer : NULL;
if (t->scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) {
t->flag |= T_V3D_ALIGN;
@@ -310,7 +310,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
/* Needed for autokeying transforms in preview during playback. */
bScreen *animscreen = ED_screen_animation_playing(CTX_wm_manager(C));
t->animtimer = (animscreen) ? animscreen->animtimer : NULL;
t->animtimer = ED_screen_animation_is_playing(animscreen) ? animscreen->animtimer : NULL;
}
setTransformViewAspect(t, t->aspect);

View File

@@ -77,13 +77,17 @@ typedef struct bScreen {
char skip_handling;
/** Set when scrubbing to avoid some costly updates. */
char scrubbing;
char _pad[1];
char _pad1[1];
/** Active region that has mouse focus. */
struct ARegion *active_region;
/** If set, screen has timer handler added in window. */
struct wmTimer *animtimer;
/** Clocks that are currently running on this timer. */
int active_clock;
char _pad2[4];
/** Context callback. */
void /*bContextDataCallback*/ *context;
@@ -93,6 +97,14 @@ typedef struct bScreen {
PreviewImage *preview;
} bScreen;
/** #ScreenAnimData.active_clock. */
enum {
/** Animation playback. */
ANIMTIMER_ANIMATION = (1 << 0),
/** Realtime clock. */
ANIMTIMER_REALTIME = (1 << 1),
};
typedef struct ScrVert {
struct ScrVert *next, *prev, *newv;
vec2s vec;

View File

@@ -51,6 +51,8 @@ const EnumPropertyItem rna_enum_region_type_items[] = {
# include "DEG_depsgraph.h"
# include "ED_screen_types.h"
# include "UI_view2d.h"
# ifdef WITH_PYTHON
@@ -87,6 +89,55 @@ static bool rna_Screen_is_scrubbing_get(PointerRNA *ptr)
return screen->scrubbing;
}
static bool rna_Screen_is_realtime_clock_running_get(PointerRNA *UNUSED(ptr))
{
/* can be NULL on file load, #42619 */
wmWindowManager *wm = G_MAIN->wm.first;
return wm ? (ED_screen_realtime_clock_running(wm) != NULL) : false;
}
static float rna_Screen_realtime_clock_elapsed_real_time_get(PointerRNA *ptr)
{
/* can be NULL on file load, #42619 */
wmWindowManager *wm = G_MAIN->wm.first;
if (wm) {
bScreen *screen = ED_screen_realtime_clock_running(wm);
if (screen) {
ScreenTimerData *timer_data = screen->animtimer->customdata;
return timer_data->realtime.elapsed_real_time;
}
}
return 0.0f;
}
static float rna_Screen_realtime_clock_elapsed_scene_time_get(PointerRNA *ptr)
{
/* can be NULL on file load, #42619 */
wmWindowManager *wm = G_MAIN->wm.first;
if (wm) {
bScreen *screen = ED_screen_realtime_clock_running(wm);
if (screen) {
ScreenTimerData *timer_data = screen->animtimer->customdata;
return timer_data->realtime.elapsed_scene_time;
}
}
return 0.0f;
}
static int rna_Screen_realtime_clock_elapsed_frames_get(PointerRNA *ptr)
{
/* can be NULL on file load, #42619 */
wmWindowManager *wm = G_MAIN->wm.first;
if (wm) {
bScreen *screen = ED_screen_realtime_clock_running(wm);
if (screen) {
ScreenTimerData *timer_data = screen->animtimer->customdata;
return timer_data->realtime.elapsed_frames;
}
}
return 0;
}
static int rna_region_alignment_get(PointerRNA *ptr)
{
ARegion *region = ptr->data;
@@ -599,6 +650,26 @@ static void rna_def_screen(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "User is Scrubbing", "True when the user is scrubbing through time");
prop = RNA_def_property(srna, "is_realtime_clock_running", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_boolean_funcs(prop, "rna_Screen_is_realtime_clock_running_get", NULL);
RNA_def_property_ui_text(prop, "Realtime Clock Running", "Realtime clock is running");
prop = RNA_def_property(srna, "realtime_clock_elapsed_real_time", PROP_FLOAT, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_float_funcs(prop, "rna_Screen_realtime_clock_elapsed_real_time_get", NULL, NULL);
RNA_def_property_ui_text(prop, "Realtime Clock Elapsed Real Time", "Real physical time elapsed since the clock was started");
prop = RNA_def_property(srna, "realtime_clock_elapsed_scene_time", PROP_FLOAT, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_float_funcs(prop, "rna_Screen_realtime_clock_elapsed_scene_time_get", NULL, NULL);
RNA_def_property_ui_text(prop, "Realtime Clock Elapsed Scene Time", "Scene time (1/fps) elapsed since the clock was started");
prop = RNA_def_property(srna, "realtime_clock_elapsed_frames", PROP_INT, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_int_funcs(prop, "rna_Screen_realtime_clock_elapsed_frames_get", NULL, NULL);
RNA_def_property_ui_text(prop, "Realtime Clock Elapsed Frames", "Elapsed frames since the realtime clock was started");
prop = RNA_def_property(srna, "is_temporary", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_boolean_sdna(prop, NULL, "temp", 1);

View File

@@ -81,7 +81,7 @@ typedef struct PrefetchJob {
static bool seq_prefetch_is_playing(const Main *bmain)
{
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
if (screen->animtimer) {
if (screen->active_clock & ANIMTIMER_ANIMATION) {
return true;
}
}