Compare commits
22 Commits
tmp_lib_up
...
realtime-c
Author | SHA1 | Date | |
---|---|---|---|
8ea027379d | |||
7e45dddca0 | |||
070ac1898a | |||
76dc5bb263 | |||
b26cb5cc0f | |||
098f6e77d5 | |||
1ae6ec4843 | |||
9101a11529 | |||
6f48a0f8c0 | |||
74b50cf429 | |||
72ea9f9623 | |||
2c4e71f4ef | |||
63f7ffe5c2 | |||
b8e774122f | |||
8794619343 | |||
21da2024c0 | |||
53582157f4 | |||
de531aef2b | |||
8ca3840b4f | |||
b77436b534 | |||
1d13280b01 | |||
8501a773e7 |
@@ -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,
|
||||
)
|
||||
|
||||
|
||||
|
@@ -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.
|
||||
*
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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);
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@@ -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 {
|
||||
|
@@ -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,
|
||||
|
@@ -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 = "");
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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)
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
};
|
||||
|
||||
|
@@ -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 */
|
||||
|
@@ -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),
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user