WIP: Ghosting System #109552
|
@ -393,6 +393,7 @@ class OUTLINER_PT_filter(Panel):
|
|||
row.prop(space, "show_restrict_column_hide", text="")
|
||||
row.prop(space, "show_restrict_column_viewport", text="")
|
||||
row.prop(space, "show_restrict_column_render", text="")
|
||||
row.prop(space, "show_restrict_column_ghosts", text="")
|
||||
row.prop(space, "show_restrict_column_holdout", text="")
|
||||
row.prop(space, "show_restrict_column_indirect_only", text="")
|
||||
layout.separator()
|
||||
|
@ -403,6 +404,7 @@ class OUTLINER_PT_filter(Panel):
|
|||
row.prop(space, "show_restrict_column_hide", text="")
|
||||
row.prop(space, "show_restrict_column_viewport", text="")
|
||||
row.prop(space, "show_restrict_column_render", text="")
|
||||
row.prop(space, "show_restrict_column_ghosts", text="")
|
||||
layout.separator()
|
||||
|
||||
if display_mode != 'DATA_API':
|
||||
|
|
|
@ -920,6 +920,14 @@ class VIEW3D_HT_header(Header):
|
|||
sub.active = overlay.show_overlays
|
||||
sub.popover(panel="VIEW3D_PT_overlay", text="")
|
||||
|
||||
# Ghosting toggle & popover
|
||||
ghosts = view.ghosts
|
||||
row = layout.row(align=True)
|
||||
row.prop(ghosts, "show_ghosts", text="")
|
||||
sub = row.row(align=True)
|
||||
sub.active = ghosts.show_ghosts
|
||||
sub.popover(panel="VIEW3D_PT_ghosts", text="")
|
||||
|
||||
row = layout.row()
|
||||
row.active = (object_mode == 'EDIT') or (shading.type in {'WIREFRAME', 'SOLID'})
|
||||
|
||||
|
@ -7197,6 +7205,30 @@ class VIEW3D_PT_overlay_weight_paint(Panel):
|
|||
col.prop(overlay, "show_paint_wire")
|
||||
|
||||
|
||||
class VIEW3D_PT_ghosts(Panel):
|
||||
bl_space_type = 'VIEW_3D'
|
||||
bl_region_type = 'HEADER'
|
||||
bl_label = "Ghosts"
|
||||
bl_ui_units_x = 13
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.label(text="Ghosts")
|
||||
|
||||
view = context.space_data
|
||||
ghosts = view.ghosts
|
||||
display_all = ghosts.show_ghosts
|
||||
|
||||
col = layout.column(align=True)
|
||||
col.active = display_all
|
||||
|
||||
split = col.split()
|
||||
|
||||
sub = split.row(align=True)
|
||||
sub.prop(ghosts, "color_before", text="")
|
||||
sub.prop(ghosts, "color_after", text="")
|
||||
|
||||
|
||||
class VIEW3D_PT_snapping(Panel):
|
||||
bl_space_type = 'VIEW_3D'
|
||||
bl_region_type = 'HEADER'
|
||||
|
@ -8558,6 +8590,7 @@ classes = (
|
|||
VIEW3D_PT_overlay_bones,
|
||||
VIEW3D_PT_overlay_sculpt,
|
||||
VIEW3D_PT_overlay_sculpt_curves,
|
||||
VIEW3D_PT_ghosts,
|
||||
VIEW3D_PT_snapping,
|
||||
VIEW3D_PT_proportional_edit,
|
||||
VIEW3D_PT_gpencil_origin,
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
/** \file
|
||||
* \ingroup bke
|
||||
* \brief Ghosting system.
|
||||
*/
|
||||
|
||||
#include "BLI_function_ref.hh"
|
||||
#include "BLI_map.hh"
|
||||
#include "BLI_set.hh"
|
||||
#include "BLI_utility_mixins.hh"
|
||||
|
||||
struct Main;
|
||||
struct Depsgraph;
|
||||
struct Scene;
|
||||
struct ViewLayer;
|
||||
struct Object;
|
||||
|
||||
namespace blender::bke::ghosts {
|
||||
|
||||
struct GhostFrame {
|
||||
Depsgraph *depsgraph;
|
||||
Set<Object *> objects;
|
||||
};
|
||||
|
||||
class GhostingSystem : NonCopyable, NonMovable {
|
||||
private:
|
||||
Map<int, GhostFrame> ghost_frames_;
|
||||
|
||||
/* Main, scene, and view layer this ghosting system is built for. */
|
||||
Main *bmain_;
|
||||
Scene *scene_;
|
||||
ViewLayer *view_layer_;
|
||||
|
||||
public:
|
||||
GhostingSystem();
|
||||
~GhostingSystem();
|
||||
|
||||
bool is_empty();
|
||||
|
||||
void request_ghost(Main *bmain, Scene *scene, ViewLayer *view_layer, Object *object, int frame);
|
||||
|
||||
void evaluate_all_frames();
|
||||
void evaluate_frames(Span<int> frames);
|
||||
void evaluate_on_framechange();
|
||||
|
||||
void foreach_ghost_frame(FunctionRef<void(int, GhostFrame&)> function);
|
||||
};
|
||||
|
||||
} // namespace blender::bke::ghosts
|
|
@ -143,6 +143,7 @@ set(SRC
|
|||
intern/geometry_fields.cc
|
||||
intern/geometry_set.cc
|
||||
intern/geometry_set_instances.cc
|
||||
intern/ghosting_system.cc
|
||||
intern/gpencil_curve_legacy.cc
|
||||
intern/gpencil_geom_legacy.cc
|
||||
intern/gpencil_legacy.cc
|
||||
|
@ -391,6 +392,7 @@ set(SRC
|
|||
BKE_geometry_fields.hh
|
||||
BKE_geometry_set.hh
|
||||
BKE_geometry_set_instances.hh
|
||||
BKE_ghosting_system.hh
|
||||
BKE_global.h
|
||||
BKE_gpencil_curve_legacy.h
|
||||
BKE_gpencil_geom_legacy.h
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup bke
|
||||
*/
|
||||
|
||||
#include "BKE_ghosting_system.hh"
|
||||
|
||||
#include "DEG_depsgraph.h"
|
||||
#include "DEG_depsgraph_build.h"
|
||||
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
namespace blender::bke::ghosts {
|
||||
|
||||
GhostingSystem::GhostingSystem() {}
|
||||
|
||||
GhostingSystem::~GhostingSystem()
|
||||
{
|
||||
for (auto [key, ghost_frame] : this->ghost_frames_.items()) {
|
||||
DEG_graph_free(ghost_frame.depsgraph);
|
||||
}
|
||||
}
|
||||
|
||||
bool GhostingSystem::is_empty()
|
||||
{
|
||||
return ghost_frames_.is_empty();
|
||||
}
|
||||
|
||||
void GhostingSystem::request_ghost(
|
||||
Main *bmain, Scene *scene, ViewLayer *view_layer, Object *object, const int frame)
|
||||
{
|
||||
if (!ghost_frames_.contains(frame)) {
|
||||
GhostFrame new_ghost_frame;
|
||||
new_ghost_frame.depsgraph = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_VIEWPORT);
|
||||
new_ghost_frame.objects.add_new(object);
|
||||
ID *id = &object->id;
|
||||
DEG_graph_build_from_ids(new_ghost_frame.depsgraph, &id, 1);
|
||||
ghost_frames_.add_new(frame, new_ghost_frame);
|
||||
return;
|
||||
}
|
||||
GhostFrame &ghost_frame = ghost_frames_.lookup(frame);
|
||||
if (ghost_frame.objects.contains(object)) {
|
||||
/* Object already in the depsgraph. */
|
||||
return;
|
||||
}
|
||||
/* Ghost frame exists, but doesn't contain the object. Recreate the depsgraph with the new
|
||||
* object. */
|
||||
DEG_graph_free(ghost_frame.depsgraph);
|
||||
ghost_frame.depsgraph = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_VIEWPORT);
|
||||
|
||||
ghost_frame.objects.add_new(object);
|
||||
/* Collect all the IDs. */
|
||||
Array<ID *> ids(ghost_frame.objects.size());
|
||||
int i = 0;
|
||||
for (Object *ob : ghost_frame.objects) {
|
||||
ids[i] = &ob->id;
|
||||
i++;
|
||||
}
|
||||
/* Build depsgraph. */
|
||||
DEG_graph_build_from_ids(ghost_frame.depsgraph, ids.data(), ids.size());
|
||||
}
|
||||
|
||||
void GhostingSystem::evaluate_all_frames()
|
||||
{
|
||||
if (ghost_frames_.is_empty()) {
|
||||
/* No ghost frames are built. */
|
||||
return;
|
||||
}
|
||||
for (auto [key, ghost_frame] : ghost_frames_.items()) {
|
||||
DEG_evaluate_on_refresh(ghost_frame.depsgraph, false);
|
||||
}
|
||||
}
|
||||
|
||||
void GhostingSystem::evaluate_frames(Span<int> frames)
|
||||
{
|
||||
if (ghost_frames_.is_empty()) {
|
||||
/* No ghost frames are built. */
|
||||
return;
|
||||
}
|
||||
for (const int frame : frames) {
|
||||
if (!ghost_frames_.contains(frame)) {
|
||||
continue;
|
||||
}
|
||||
GhostFrame &ghost_frame = ghost_frames_.lookup(frame);
|
||||
DEG_evaluate_on_refresh(ghost_frame.depsgraph, false);
|
||||
}
|
||||
}
|
||||
|
||||
void GhostingSystem::evaluate_on_framechange()
|
||||
{
|
||||
if (ghost_frames_.is_empty()) {
|
||||
/* No ghost frames are built. */
|
||||
return;
|
||||
}
|
||||
for (auto [key, ghost_frame] : this->ghost_frames_.items()) {
|
||||
DEG_evaluate_on_framechange(ghost_frame.depsgraph, float(key));
|
||||
}
|
||||
}
|
||||
|
||||
void GhostingSystem::foreach_ghost_frame(FunctionRef<void(int, GhostFrame &)> function)
|
||||
{
|
||||
if (ghost_frames_.is_empty()) {
|
||||
/* No ghost frames are built. */
|
||||
return;
|
||||
}
|
||||
for (auto [key, ghost_frame] : ghost_frames_.items()) {
|
||||
function(key, ghost_frame);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::bke::ghosts
|
|
@ -66,6 +66,7 @@
|
|||
#include "BKE_effect.h"
|
||||
#include "BKE_fcurve.h"
|
||||
#include "BKE_freestyle.h"
|
||||
#include "BKE_ghosting_system.hh"
|
||||
#include "BKE_gpencil_legacy.h"
|
||||
#include "BKE_icons.h"
|
||||
#include "BKE_idprop.h"
|
||||
|
@ -247,6 +248,8 @@ static void scene_init_data(ID *id)
|
|||
scene->master_collection = BKE_collection_master_add(scene);
|
||||
|
||||
BKE_view_layer_add(scene, DATA_("ViewLayer"), nullptr, VIEWLAYER_ADD_NEW);
|
||||
|
||||
scene->ghosting_system = MEM_new<blender::bke::ghosts::GhostingSystem>(__func__);
|
||||
}
|
||||
|
||||
static void scene_copy_markers(Scene *scene_dst, const Scene *scene_src, const int flag)
|
||||
|
@ -367,6 +370,8 @@ static void scene_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
|
|||
}
|
||||
|
||||
BKE_scene_copy_data_eevee(scene_dst, scene_src);
|
||||
|
||||
scene_dst->ghosting_system = MEM_new<blender::bke::ghosts::GhostingSystem>(__func__);
|
||||
}
|
||||
|
||||
static void scene_free_markers(Scene *scene, bool do_id_user)
|
||||
|
@ -462,6 +467,9 @@ static void scene_free_data(ID *id)
|
|||
|
||||
/* These are freed on `do_versions`. */
|
||||
BLI_assert(scene->layer_properties == nullptr);
|
||||
|
||||
MEM_delete(scene->ghosting_system);
|
||||
scene->ghosting_system = nullptr;
|
||||
}
|
||||
|
||||
static void scene_foreach_rigidbodyworldSceneLooper(RigidBodyWorld * /*rbw*/,
|
||||
|
@ -1498,6 +1506,8 @@ static void scene_blend_read_data(BlendDataReader *reader, ID *id)
|
|||
|
||||
BLO_read_data_address(reader, &sce->layer_properties);
|
||||
IDP_BlendDataRead(reader, &sce->layer_properties);
|
||||
|
||||
sce->ghosting_system = MEM_new<blender::bke::ghosts::GhostingSystem>(__func__);
|
||||
}
|
||||
|
||||
/* patch for missing scene IDs, can't be in do-versions */
|
||||
|
@ -2709,7 +2719,13 @@ static void scene_graph_update_tagged(Depsgraph *depsgraph, Main *bmain, bool on
|
|||
prepare_mesh_for_viewport_render(bmain, scene, view_layer);
|
||||
/* Update all objects: drivers, matrices, etc. flags set
|
||||
* by depsgraph or manual, no layer check here, gets correct flushed. */
|
||||
DEG_evaluate_on_refresh(depsgraph);
|
||||
DEG_evaluate_on_refresh(depsgraph, true);
|
||||
|
||||
if (pass == 0) {
|
||||
/* Evaluate ghosting depsgraphs here (if needed). */
|
||||
scene->ghosting_system->evaluate_all_frames();
|
||||
}
|
||||
|
||||
/* Update sound system. */
|
||||
BKE_scene_update_sound(depsgraph, bmain);
|
||||
/* Notify python about depsgraph update. */
|
||||
|
@ -2791,9 +2807,12 @@ void BKE_scene_graph_update_for_newframe_ex(Depsgraph *depsgraph, const bool cle
|
|||
if (pass == 0) {
|
||||
const float frame = BKE_scene_frame_get(scene);
|
||||
DEG_evaluate_on_framechange(depsgraph, frame);
|
||||
|
||||
/* Evaluate ghosting depsgraphs. */
|
||||
scene->ghosting_system->evaluate_on_framechange();
|
||||
}
|
||||
else {
|
||||
DEG_evaluate_on_refresh(depsgraph);
|
||||
DEG_evaluate_on_refresh(depsgraph, true);
|
||||
}
|
||||
/* Update sound system animation. */
|
||||
BKE_scene_update_sound(depsgraph, bmain);
|
||||
|
|
|
@ -710,5 +710,30 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
|
|||
scene->eevee.gi_irradiance_pool_size = 16;
|
||||
}
|
||||
}
|
||||
|
||||
if (!DNA_struct_elem_find(fd->filesdna, "View3DGhosts", "float", "color_before[3]")) {
|
||||
LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
|
||||
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
|
||||
LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
|
||||
if (sl->spacetype == SPACE_VIEW3D) {
|
||||
View3D *v3d = (View3D *)sl;
|
||||
copy_v3_fl3(v3d->ghosts.color_before, 1.0f, 0.0f, 0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!DNA_struct_elem_find(fd->filesdna, "View3DGhosts", "float", "color_after[3]")) {
|
||||
LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
|
||||
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
|
||||
LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
|
||||
if (sl->spacetype == SPACE_VIEW3D) {
|
||||
View3D *v3d = (View3D *)sl;
|
||||
copy_v3_fl3(v3d->ghosts.color_after, 0.0f, 0.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -186,7 +186,7 @@ void DEG_evaluate_on_framechange(Depsgraph *graph, float frame);
|
|||
* Data changed recalculation entry point.
|
||||
* Evaluate all nodes tagged for updating.
|
||||
*/
|
||||
void DEG_evaluate_on_refresh(Depsgraph *graph);
|
||||
void DEG_evaluate_on_refresh(Depsgraph *graph, bool update_time);
|
||||
|
||||
/** \} */
|
||||
|
||||
|
|
|
@ -45,25 +45,27 @@ static void deg_flush_updates_and_refresh(deg::Depsgraph *deg_graph)
|
|||
deg::deg_evaluate_on_refresh(deg_graph);
|
||||
}
|
||||
|
||||
void DEG_evaluate_on_refresh(Depsgraph *graph)
|
||||
void DEG_evaluate_on_refresh(Depsgraph *graph, const bool update_time)
|
||||
{
|
||||
deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(graph);
|
||||
const Scene *scene = DEG_get_input_scene(graph);
|
||||
const float frame = BKE_scene_frame_get(scene);
|
||||
const float ctime = BKE_scene_ctime_get(scene);
|
||||
if (update_time) {
|
||||
const Scene *scene = DEG_get_input_scene(graph);
|
||||
const float frame = BKE_scene_frame_get(scene);
|
||||
const float ctime = BKE_scene_ctime_get(scene);
|
||||
|
||||
if (deg_graph->frame != frame || ctime != deg_graph->ctime) {
|
||||
deg_graph->tag_time_source();
|
||||
deg_graph->frame = frame;
|
||||
deg_graph->ctime = ctime;
|
||||
}
|
||||
else if (scene->id.recalc & ID_RECALC_FRAME_CHANGE) {
|
||||
/* Comparing depsgraph & scene frame fails in the case of undo,
|
||||
* since the undo state is stored before updates from the frame change have been applied.
|
||||
* 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();
|
||||
if (deg_graph->frame != frame || ctime != deg_graph->ctime) {
|
||||
deg_graph->tag_time_source();
|
||||
deg_graph->frame = frame;
|
||||
deg_graph->ctime = ctime;
|
||||
}
|
||||
else if (scene->id.recalc & ID_RECALC_FRAME_CHANGE) {
|
||||
/* Comparing depsgraph & scene frame fails in the case of undo,
|
||||
* since the undo state is stored before updates from the frame change have been applied.
|
||||
* 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_flush_updates_and_refresh(deg_graph);
|
||||
|
|
|
@ -189,7 +189,7 @@ Scene *DEG_get_evaluated_scene(const Depsgraph *graph)
|
|||
Scene *scene_cow = deg_graph->scene_cow;
|
||||
/* TODO(sergey): Shall we expand data-block here? Or is it OK to assume
|
||||
* that caller is OK with just a pointer in case scene is not updated yet? */
|
||||
BLI_assert(scene_cow != nullptr && deg::deg_copy_on_write_is_expanded(&scene_cow->id));
|
||||
// BLI_assert(scene_cow != nullptr && deg::deg_copy_on_write_is_expanded(&scene_cow->id));
|
||||
return scene_cow;
|
||||
}
|
||||
|
||||
|
|
|
@ -382,7 +382,8 @@ void workbench_cache_populate(void *ved, Object *ob)
|
|||
WORKBENCH_StorageList *stl = vedata->stl;
|
||||
WORKBENCH_PrivateData *wpd = stl->wpd;
|
||||
|
||||
if (!DRW_object_is_renderable(ob)) {
|
||||
/* Ghost frames are currently rendered using the workbench engine. */
|
||||
if ((ob->base_flag & BASE_IS_GHOST_FRAME) == 0 && !DRW_object_is_renderable(ob)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "BKE_curves.h"
|
||||
#include "BKE_duplilist.h"
|
||||
#include "BKE_editmesh.h"
|
||||
#include "BKE_ghosting_system.hh"
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_gpencil_legacy.h"
|
||||
#include "BKE_grease_pencil.h"
|
||||
|
@ -45,6 +46,7 @@
|
|||
#include "DNA_camera_types.h"
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_userdef_types.h"
|
||||
#include "DNA_view3d_types.h"
|
||||
#include "DNA_world_types.h"
|
||||
|
@ -195,6 +197,10 @@ bool DRW_object_is_renderable(const Object *ob)
|
|||
}
|
||||
}
|
||||
|
||||
if ((ob->base_flag & BASE_IS_GHOST_FRAME) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1655,6 +1661,8 @@ void DRW_draw_render_loop_ex(Depsgraph *depsgraph,
|
|||
ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
|
||||
RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
|
||||
|
||||
Scene *scene_orig = reinterpret_cast<Scene *>(DEG_get_original_id(&scene->id));
|
||||
|
||||
BKE_view_layer_synced_ensure(scene, view_layer);
|
||||
DST.draw_ctx = {};
|
||||
DST.draw_ctx.region = region;
|
||||
|
@ -1680,9 +1688,10 @@ void DRW_draw_render_loop_ex(Depsgraph *depsgraph,
|
|||
const bool internal_engine = (engine_type->flag & RE_INTERNAL) != 0;
|
||||
const bool draw_type_render = v3d->shading.type == OB_RENDER;
|
||||
const bool overlays_on = (v3d->flag2 & V3D_HIDE_OVERLAYS) == 0;
|
||||
const bool ghosts_on = (v3d->flag2 & V3D_HIDE_GHOSTS) == 0;
|
||||
const bool gpencil_engine_needed = drw_gpencil_engine_needed(depsgraph, v3d);
|
||||
const bool do_populate_loop = internal_engine || overlays_on || !draw_type_render ||
|
||||
gpencil_engine_needed;
|
||||
gpencil_engine_needed || ghosts_on;
|
||||
|
||||
/* Get list of enabled engines */
|
||||
drw_engines_enable(view_layer, engine_type, gpencil_engine_needed);
|
||||
|
@ -1732,6 +1741,37 @@ void DRW_draw_render_loop_ex(Depsgraph *depsgraph,
|
|||
drw_engines_cache_populate(ob);
|
||||
}
|
||||
DEG_OBJECT_ITER_END;
|
||||
|
||||
if (!scene_orig->ghosting_system->is_empty() && !draw_type_render && ghosts_on) {
|
||||
scene_orig->ghosting_system->foreach_ghost_frame(
|
||||
[&](int frame, blender::bke::ghosts::GhostFrame &ghost_frame) {
|
||||
if (!ghost_frame.depsgraph) {
|
||||
return;
|
||||
}
|
||||
DEGObjectIterSettings deg_ghost_iter_settings = {0};
|
||||
deg_ghost_iter_settings.depsgraph = ghost_frame.depsgraph;
|
||||
deg_ghost_iter_settings.flags = DEG_OBJECT_ITER_FOR_RENDER_ENGINE_FLAGS;
|
||||
|
||||
DEG_OBJECT_ITER_BEGIN (°_ghost_iter_settings, ob) {
|
||||
Object *ob_orig = DEG_get_original_object(ob);
|
||||
if (!BKE_object_is_visible_in_viewport(v3d, ob_orig)) {
|
||||
continue;
|
||||
}
|
||||
ob->base_flag |= BASE_IS_GHOST_FRAME;
|
||||
ob->base_flag &= ~BASE_SELECTED;
|
||||
const bool before = frame < scene_orig->r.cfra;
|
||||
if (before) {
|
||||
copy_v3_v3(ob->color, v3d->ghosts.color_before);
|
||||
}
|
||||
else {
|
||||
copy_v3_v3(ob->color, v3d->ghosts.color_after);
|
||||
}
|
||||
// ob->color[3] = (before) ? 0.1f + 0.2f * i : 0.7f - (i - 4) * 0.2f;
|
||||
drw_engines_cache_populate(ob);
|
||||
}
|
||||
DEG_OBJECT_ITER_END;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
drw_duplidata_free();
|
||||
|
|
|
@ -1186,7 +1186,7 @@ bool ED_object_modifier_apply(Main *bmain,
|
|||
ID *ids[] = {&ob->id};
|
||||
|
||||
DEG_graph_build_from_ids(local_depsgraph, ids, 1);
|
||||
DEG_evaluate_on_refresh(local_depsgraph);
|
||||
DEG_evaluate_on_refresh(local_depsgraph, true);
|
||||
|
||||
apply_depsgraph = local_depsgraph;
|
||||
|
||||
|
|
|
@ -827,7 +827,7 @@ static Scene *object_preview_scene_create(const ObjectPreviewData *preview_data,
|
|||
preview_base->flag |= BASE_SELECTED;
|
||||
|
||||
DEG_graph_build_from_view_layer(depsgraph);
|
||||
DEG_evaluate_on_refresh(depsgraph);
|
||||
DEG_evaluate_on_refresh(depsgraph, true);
|
||||
|
||||
ED_view3d_camera_to_view_selected_with_set_clipping(
|
||||
preview_data->pr_main, depsgraph, scene, camera_object);
|
||||
|
@ -958,7 +958,7 @@ static PoseBackup *action_preview_render_prepare(IconPreview *preview)
|
|||
|
||||
/* Force evaluation of the new pose, before the preview is rendered. */
|
||||
DEG_id_tag_update(&object->id, ID_RECALC_GEOMETRY);
|
||||
DEG_evaluate_on_refresh(preview->depsgraph);
|
||||
DEG_evaluate_on_refresh(preview->depsgraph, true);
|
||||
|
||||
return pose_backup;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "DNA_sequence_types.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_ghosting_system.hh"
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_layer.h"
|
||||
#include "BKE_lib_id.h"
|
||||
|
@ -422,6 +423,43 @@ static void SCENE_OT_delete(wmOperatorType *ot)
|
|||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
static bool scene_enable_ghosting_poll(bContext *C)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
Object *object = CTX_data_active_object(C);
|
||||
return scene != nullptr && object != nullptr;
|
||||
}
|
||||
|
||||
static int scene_enable_ghosting_exec(bContext *C, wmOperator * /*op*/)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
Object *active_object = CTX_data_active_object(C);
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
scene->ghosting_system->request_ghost(bmain, scene, view_layer, active_object, scene->r.cfra + 4 - i);
|
||||
}
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static void SCENE_OT_enable_ghosting(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Create Ghost Frames for Active Object";
|
||||
ot->description =
|
||||
"Clears and re-creates the ghost frames for the active object and all of its dependencies";
|
||||
ot->idname = "SCENE_OT_enable_ghosting";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = scene_enable_ghosting_exec;
|
||||
ot->poll = scene_enable_ghosting_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
@ -433,6 +471,8 @@ void ED_operatortypes_scene()
|
|||
WM_operatortype_append(SCENE_OT_new);
|
||||
WM_operatortype_append(SCENE_OT_delete);
|
||||
WM_operatortype_append(SCENE_OT_new_sequencer);
|
||||
|
||||
WM_operatortype_append(SCENE_OT_enable_ghosting);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -237,7 +237,7 @@ static void compo_initjob(void *cjv)
|
|||
|
||||
/* NOTE: Don't update animation to preserve unkeyed changes, this means can not use
|
||||
* evaluate_on_framechange. */
|
||||
DEG_evaluate_on_refresh(cj->compositor_depsgraph);
|
||||
DEG_evaluate_on_refresh(cj->compositor_depsgraph, true);
|
||||
|
||||
bNodeTree *ntree_eval = (bNodeTree *)DEG_get_evaluated_id(cj->compositor_depsgraph,
|
||||
&cj->ntree->id);
|
||||
|
|
|
@ -906,7 +906,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
|
|||
struct RestrictProperties {
|
||||
bool initialized;
|
||||
|
||||
PropertyRNA *object_hide_viewport, *object_hide_select, *object_hide_render;
|
||||
PropertyRNA *object_hide_viewport, *object_hide_select, *object_hide_render, *object_show_ghosts;
|
||||
PropertyRNA *base_hide_viewport;
|
||||
PropertyRNA *collection_hide_viewport, *collection_hide_select, *collection_hide_render;
|
||||
PropertyRNA *layer_collection_exclude, *layer_collection_holdout,
|
||||
|
@ -922,6 +922,7 @@ struct RestrictPropertiesActive {
|
|||
bool object_hide_viewport;
|
||||
bool object_hide_select;
|
||||
bool object_hide_render;
|
||||
bool object_show_ghosts;
|
||||
bool base_hide_viewport;
|
||||
bool collection_hide_viewport;
|
||||
bool collection_hide_select;
|
||||
|
@ -1066,6 +1067,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
|
|||
props.object_hide_viewport = RNA_struct_type_find_property(&RNA_Object, "hide_viewport");
|
||||
props.object_hide_select = RNA_struct_type_find_property(&RNA_Object, "hide_select");
|
||||
props.object_hide_render = RNA_struct_type_find_property(&RNA_Object, "hide_render");
|
||||
props.object_show_ghosts = RNA_struct_type_find_property(&RNA_Object, "show_ghosts");
|
||||
props.base_hide_viewport = RNA_struct_type_find_property(&RNA_ObjectBase, "hide_viewport");
|
||||
props.collection_hide_viewport = RNA_struct_type_find_property(&RNA_Collection,
|
||||
"hide_viewport");
|
||||
|
@ -1095,6 +1097,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
|
|||
int hide;
|
||||
int viewport;
|
||||
int render;
|
||||
int ghosts;
|
||||
int indirect_only;
|
||||
int holdout;
|
||||
} restrict_offsets = {0};
|
||||
|
@ -1118,6 +1121,9 @@ static void outliner_draw_restrictbuts(uiBlock *block,
|
|||
if (space_outliner->show_restrict_flags & SO_RESTRICT_HIDE) {
|
||||
restrict_offsets.hide = (++restrict_column_offset) * UI_UNIT_X + V2D_SCROLL_WIDTH;
|
||||
}
|
||||
if (space_outliner->show_restrict_flags & SO_RESTRICT_SHOW_GHOSTS) {
|
||||
restrict_offsets.ghosts = (++restrict_column_offset) * UI_UNIT_X + V2D_SCROLL_WIDTH;
|
||||
}
|
||||
if (space_outliner->show_restrict_flags & SO_RESTRICT_SELECT) {
|
||||
restrict_offsets.select = (++restrict_column_offset) * UI_UNIT_X + V2D_SCROLL_WIDTH;
|
||||
}
|
||||
|
@ -1281,6 +1287,32 @@ static void outliner_draw_restrictbuts(uiBlock *block,
|
|||
UI_but_flag_enable(bt, UI_BUT_INACTIVE);
|
||||
}
|
||||
}
|
||||
|
||||
if (space_outliner->show_restrict_flags & SO_RESTRICT_SHOW_GHOSTS &&
|
||||
OB_TYPE_SUPPORT_GHOSTING(ob->type))
|
||||
{
|
||||
bt = uiDefIconButR_prop(block,
|
||||
UI_BTYPE_ICON_TOGGLE,
|
||||
0,
|
||||
ICON_NONE,
|
||||
int(region->v2d.cur.xmax - restrict_offsets.ghosts),
|
||||
te->ys,
|
||||
UI_UNIT_X,
|
||||
UI_UNIT_Y,
|
||||
&ptr,
|
||||
props.object_show_ghosts,
|
||||
-1,
|
||||
0,
|
||||
0,
|
||||
-1,
|
||||
-1,
|
||||
TIP_("Show ghosts in viewport"));
|
||||
UI_but_func_set(bt, outliner__object_set_flag_recursive_fn, ob, (char *)"show_ghosts");
|
||||
UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
|
||||
if (!props_active.object_show_ghosts) {
|
||||
UI_but_flag_enable(bt, UI_BUT_INACTIVE);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (tselem->type == TSE_CONSTRAINT) {
|
||||
bConstraint *con = (bConstraint *)te->directdata;
|
||||
|
|
|
@ -337,6 +337,9 @@ float outliner_right_columns_width(const SpaceOutliner *space_outliner)
|
|||
if (space_outliner->show_restrict_flags & SO_RESTRICT_INDIRECT_ONLY) {
|
||||
num_columns++;
|
||||
}
|
||||
if (space_outliner->show_restrict_flags & SO_RESTRICT_SHOW_GHOSTS) {
|
||||
num_columns++;
|
||||
}
|
||||
ATTR_FALLTHROUGH;
|
||||
case SO_SCENES:
|
||||
if (space_outliner->show_restrict_flags & SO_RESTRICT_SELECT) {
|
||||
|
|
|
@ -1471,6 +1471,7 @@ static void view3d_main_region_message_subscribe(const wmRegionMessageSubscribeP
|
|||
&RNA_View3DCursor,
|
||||
&RNA_View3DOverlay,
|
||||
&RNA_View3DShading,
|
||||
&RNA_View3DGhosts,
|
||||
&RNA_World,
|
||||
};
|
||||
|
||||
|
@ -1979,8 +1980,10 @@ static void space_view3d_refresh(const bContext *C, ScrArea *area)
|
|||
view3d_lightcache_update((bContext *)C);
|
||||
}
|
||||
|
||||
View3D *v3d = (View3D *)area->spacedata.first;
|
||||
View3D *v3d = static_cast<View3D *>(area->spacedata.first);
|
||||
MEM_SAFE_FREE(v3d->runtime.local_stats);
|
||||
|
||||
// view3d_ghosts_update();
|
||||
}
|
||||
|
||||
const char *view3d_context_dir[] = {
|
||||
|
|
|
@ -247,6 +247,8 @@ enum {
|
|||
BASE_HOLDOUT = (1 << 10),
|
||||
/* Object only contributes indirectly to render */
|
||||
BASE_INDIRECT_ONLY = (1 << 11),
|
||||
/* Object is used for rendering ghost frames. */
|
||||
BASE_IS_GHOST_FRAME = (1 << 12),
|
||||
};
|
||||
|
||||
/* LayerCollection->flag */
|
||||
|
|
|
@ -657,6 +657,8 @@ typedef enum ObjectType {
|
|||
case ID_VO: \
|
||||
case ID_GP
|
||||
|
||||
#define OB_TYPE_SUPPORT_GHOSTING(_type) (ELEM(_type, OB_MESH, OB_GREASE_PENCIL))
|
||||
|
||||
/** #Object.partype: first 4 bits: type. */
|
||||
enum {
|
||||
PARTYPE = (1 << 4) - 1,
|
||||
|
@ -801,7 +803,8 @@ enum {
|
|||
OB_HIDE_VOLUME_SCATTER = 1 << 7,
|
||||
OB_HIDE_SHADOW = 1 << 8,
|
||||
OB_HOLDOUT = 1 << 9,
|
||||
OB_SHADOW_CATCHER = 1 << 10
|
||||
OB_SHADOW_CATCHER = 1 << 10,
|
||||
OB_HIDE_GHOSTS = 1 << 11
|
||||
};
|
||||
|
||||
/** #Object.shapeflag */
|
||||
|
|
|
@ -47,6 +47,7 @@ struct Scene;
|
|||
struct World;
|
||||
struct bGPdata;
|
||||
struct bNodeTree;
|
||||
struct Depsgraph;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name FFMPEG
|
||||
|
@ -1935,6 +1936,15 @@ enum {
|
|||
|
||||
/** \} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace blender::bke::ghosts {
|
||||
class GhostingSystem;
|
||||
} // namespace blender::bke::ghosts
|
||||
using GhostingSystemHandle = blender::bke::ghosts::GhostingSystem;
|
||||
#else
|
||||
typedef struct GhostingSystemHandle GhostingSystemHandle;
|
||||
#endif
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Scene ID-Block
|
||||
* \{ */
|
||||
|
@ -2057,6 +2067,8 @@ typedef struct Scene {
|
|||
struct SceneEEVEE eevee;
|
||||
struct SceneGpencil grease_pencil_settings;
|
||||
struct SceneHydra hydra;
|
||||
GhostingSystemHandle *ghosting_system;
|
||||
void *_pad9;
|
||||
} Scene;
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -393,6 +393,7 @@ typedef enum eSpaceOutliner_ShowRestrictFlag {
|
|||
SO_RESTRICT_RENDER = (1 << 4),
|
||||
SO_RESTRICT_HOLDOUT = (1 << 5),
|
||||
SO_RESTRICT_INDIRECT_ONLY = (1 << 6),
|
||||
SO_RESTRICT_SHOW_GHOSTS = (1 << 7),
|
||||
} eSpaceOutliner_Restrict;
|
||||
|
||||
/** #SpaceOutliner.outlinevis */
|
||||
|
|
|
@ -66,6 +66,12 @@
|
|||
.normals_constant_screen_size = 7.0f, \
|
||||
}
|
||||
|
||||
#define _DNA_DEFAULT_View3DGhosts \
|
||||
{ \
|
||||
.color_before = {1.0f, 0.0f, 0.0f}, \
|
||||
.color_after = {0.0f, 0.0f, 1.0f}, \
|
||||
} \
|
||||
|
||||
#define _DNA_DEFAULT_View3DCursor \
|
||||
{ \
|
||||
.rotation_mode = ROT_MODE_XYZ, \
|
||||
|
@ -82,6 +88,7 @@
|
|||
.gridsubdiv = 10, \
|
||||
.shading = _DNA_DEFAULT_View3DShading, \
|
||||
.overlay = _DNA_DEFAULT_View3DOverlay, \
|
||||
.ghosts = _DNA_DEFAULT_View3DGhosts, \
|
||||
\
|
||||
.gridflag = V3D_SHOW_X | V3D_SHOW_Y | V3D_SHOW_FLOOR | V3D_SHOW_ORTHO_GRID, \
|
||||
\
|
||||
|
|
|
@ -249,6 +249,12 @@ typedef enum eHandleDisplay {
|
|||
CURVE_HANDLE_NONE = 2,
|
||||
} eHandleDisplay;
|
||||
|
||||
/* 3D View Ghosting settings. */
|
||||
typedef struct View3DGhosts {
|
||||
float color_before[3];
|
||||
float color_after[3];
|
||||
} View3DGhosts;
|
||||
|
||||
typedef struct View3D_Runtime {
|
||||
/** Nkey panel stores stuff here. */
|
||||
void *properties_storage;
|
||||
|
@ -357,6 +363,7 @@ typedef struct View3D {
|
|||
/** Display settings. */
|
||||
View3DShading shading;
|
||||
View3DOverlay overlay;
|
||||
View3DGhosts ghosts;
|
||||
|
||||
/** Path to the viewer node that is currently previewed. This is retrieved from the workspace. */
|
||||
ViewerPath viewer_path;
|
||||
|
@ -484,6 +491,7 @@ enum {
|
|||
V3D_FLAG2_UNUSED_15 = 1 << 15, /* cleared */
|
||||
V3D_XR_SHOW_CONTROLLERS = 1 << 16,
|
||||
V3D_XR_SHOW_CUSTOM_OVERLAYS = 1 << 17,
|
||||
V3D_HIDE_GHOSTS = 1 << 18,
|
||||
};
|
||||
|
||||
/** #View3D::gp_flag (short) */
|
||||
|
|
|
@ -376,6 +376,13 @@ static void rna_Object_hide_update(Main *bmain, Scene * /*scene*/, PointerRNA *p
|
|||
WM_main_add_notifier(NC_OBJECT | ND_DRAW, &ob->id);
|
||||
}
|
||||
|
||||
static void rna_Object_show_ghosts_update(Main * /*bmain*/, Scene * /*scene*/, PointerRNA *ptr)
|
||||
{
|
||||
Object *ob = reinterpret_cast<Object *>(ptr->owner_id);
|
||||
DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
|
||||
WM_main_add_notifier(NC_OBJECT | ND_DRAW, &ob->id);
|
||||
}
|
||||
|
||||
static void rna_Object_duplicator_visibility_flag_update(Main * /*bmain*/,
|
||||
Scene * /*scene*/,
|
||||
PointerRNA *ptr)
|
||||
|
@ -2973,6 +2980,12 @@ static void rna_def_object_visibility(StructRNA *srna)
|
|||
"footage. Objects with this setting are considered to already exist in the footage, "
|
||||
"objects without it are synthetic objects being composited into it");
|
||||
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_internal_update_draw");
|
||||
|
||||
prop = RNA_def_property(srna, "show_ghosts", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_negative_sdna(prop, nullptr, "visibility_flag", OB_HIDE_GHOSTS);
|
||||
RNA_def_property_ui_text(prop, "Show Ghosts", "Show ghost frames in viewport");
|
||||
RNA_def_property_ui_icon(prop, ICON_ONIONSKIN_ON, -1);
|
||||
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_show_ghosts_update");
|
||||
}
|
||||
|
||||
static void rna_def_object(BlenderRNA *brna)
|
||||
|
|
|
@ -1637,6 +1637,16 @@ static char *rna_View3DOverlay_path(const PointerRNA * /*ptr*/)
|
|||
return BLI_strdup("overlay");
|
||||
}
|
||||
|
||||
static char *rna_View3DGhosts_path(const PointerRNA * /*ptr*/)
|
||||
{
|
||||
return BLI_strdup("ghosts");
|
||||
}
|
||||
|
||||
static PointerRNA rna_SpaceView3D_ghosts_get(PointerRNA *ptr)
|
||||
{
|
||||
return rna_pointer_inherit_refine(ptr, &RNA_View3DGhosts, ptr->data);
|
||||
}
|
||||
|
||||
/* Space Image Editor */
|
||||
|
||||
static PointerRNA rna_SpaceImage_overlay_get(PointerRNA *ptr)
|
||||
|
@ -3882,6 +3892,12 @@ static void rna_def_space_outliner(BlenderRNA *brna)
|
|||
RNA_def_property_ui_icon(prop, ICON_RESTRICT_RENDER_OFF, 0);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, nullptr);
|
||||
|
||||
prop = RNA_def_property(srna, "show_restrict_column_ghosts", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, nullptr, "show_restrict_flags", SO_RESTRICT_SHOW_GHOSTS);
|
||||
RNA_def_property_ui_text(prop, "Show Ghosts", "Show ghost frames in viewport");
|
||||
RNA_def_property_ui_icon(prop, ICON_ONIONSKIN_ON, 0);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, nullptr);
|
||||
|
||||
prop = RNA_def_property(srna, "show_restrict_column_holdout", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, nullptr, "show_restrict_flags", SO_RESTRICT_HOLDOUT);
|
||||
RNA_def_property_ui_text(prop, "Holdout", "Holdout");
|
||||
|
@ -4931,6 +4947,40 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
|
|||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, nullptr);
|
||||
}
|
||||
|
||||
static void rna_def_space_view3d_ghosts(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
srna = RNA_def_struct(brna, "View3DGhosts", nullptr);
|
||||
RNA_def_struct_sdna(srna, "View3D");
|
||||
RNA_def_struct_nested(brna, srna, "SpaceView3D");
|
||||
RNA_def_struct_path_func(srna, "rna_View3DGhosts_path");
|
||||
RNA_def_struct_ui_text(
|
||||
srna, "3D View Ghosting Settings", "Settings for display of ghosts in the 3D viewport");
|
||||
|
||||
prop = RNA_def_property(srna, "show_ghosts", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_negative_sdna(prop, nullptr, "flag2", V3D_HIDE_GHOSTS);
|
||||
RNA_def_property_ui_text(prop, "Show Ghosts", "Display ghosts in the viewport");
|
||||
RNA_def_property_ui_icon(prop, ICON_GHOST_ENABLED, 0);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, nullptr);
|
||||
|
||||
prop = RNA_def_property(srna, "color_before", PROP_FLOAT, PROP_COLOR);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "ghosts.color_before");
|
||||
RNA_def_property_array(prop, 3);
|
||||
RNA_def_property_ui_text(prop, "Before", "Color of the ghosts before the current frame");
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, nullptr);
|
||||
|
||||
prop = RNA_def_property(srna, "color_after", PROP_FLOAT, PROP_COLOR);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "ghosts.color_after");
|
||||
RNA_def_property_array(prop, 3);
|
||||
RNA_def_property_ui_text(prop, "After", "Color of the ghosts after the current frame");
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, nullptr);
|
||||
}
|
||||
|
||||
static void rna_def_space_view3d(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
|
@ -5283,8 +5333,16 @@ static void rna_def_space_view3d(BlenderRNA *brna)
|
|||
RNA_def_property_ui_text(
|
||||
prop, "Overlay Settings", "Settings for display of overlays in the 3D viewport");
|
||||
|
||||
prop = RNA_def_property(srna, "ghosts", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_flag(prop, PROP_NEVER_NULL);
|
||||
RNA_def_property_struct_type(prop, "View3DGhosts");
|
||||
RNA_def_property_pointer_funcs(prop, "rna_SpaceView3D_ghosts_get", nullptr, nullptr, nullptr);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Ghosting Settings", "Settings for display of ghosts in the 3D viewport");
|
||||
|
||||
rna_def_space_view3d_shading(brna);
|
||||
rna_def_space_view3d_overlay(brna);
|
||||
rna_def_space_view3d_ghosts(brna);
|
||||
|
||||
/* *** Animated *** */
|
||||
RNA_define_animate_sdna(true);
|
||||
|
|
Loading…
Reference in New Issue