WIP: Onion Skinning Prototype #107641
@ -1056,6 +1056,7 @@ def km_time_scrub(_params):
|
||||
|
||||
items.extend([
|
||||
("anim.change_frame", {"type": 'LEFTMOUSE', "value": 'PRESS'}, None),
|
||||
("anim.change_onion_skin_range", {"type": 'LEFTMOUSE', "value": 'PRESS', "alt": True}, None),
|
||||
])
|
||||
|
||||
return keymap
|
||||
|
@ -715,6 +715,33 @@ class RENDER_PT_gpencil(RenderButtonsPanel, Panel):
|
||||
col.prop(props, "antialias_threshold")
|
||||
|
||||
|
||||
class RENDER_PT_onion_skins(RenderButtonsPanel, Panel):
|
||||
bl_label = "Onion Skins"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
bl_order = 10
|
||||
COMPAT_ENGINES = {
|
||||
'BLENDER_RENDER',
|
||||
'BLENDER_EEVEE',
|
||||
'BLENDER_EEVEE_NEXT',
|
||||
'BLENDER_WORKBENCH',
|
||||
'BLENDER_WORKBENCH_NEXT'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
# layout.use_property_split = True
|
||||
# layout.use_property_decorate = False # No animation.
|
||||
|
||||
scene = context.scene
|
||||
|
||||
col = layout.column()
|
||||
col.prop(scene, "onion_skin_color_left")
|
||||
col.prop(scene, "onion_skin_color_right")
|
||||
col.prop(scene, "os_relative_left")
|
||||
col.prop(scene, "os_relative_right")
|
||||
col.prop(scene, "onion_skin_alpha")
|
||||
col.prop(scene, "onion_skin_draw_modes")
|
||||
|
||||
|
||||
class RENDER_PT_opengl_sampling(RenderButtonsPanel, Panel):
|
||||
bl_label = "Sampling"
|
||||
COMPAT_ENGINES = {'BLENDER_WORKBENCH', 'BLENDER_WORKBENCH_NEXT'}
|
||||
@ -921,6 +948,8 @@ classes = (
|
||||
RENDER_PT_simplify_viewport,
|
||||
RENDER_PT_simplify_render,
|
||||
RENDER_PT_simplify_greasepencil,
|
||||
|
||||
RENDER_PT_onion_skins,
|
||||
)
|
||||
|
||||
if __name__ == "__main__": # only for live edit.
|
||||
|
@ -6532,7 +6532,7 @@ class VIEW3D_PT_overlay_geometry(Panel):
|
||||
|
||||
col.prop(overlay, "show_face_orientation")
|
||||
|
||||
# sub.prop(overlay, "show_onion_skins")
|
||||
sub.prop(overlay, "show_onion_skins")
|
||||
|
||||
|
||||
class VIEW3D_PT_overlay_motion_tracking(Panel):
|
||||
|
@ -225,6 +225,7 @@ set(SRC
|
||||
engines/overlay/overlay_viewer_attribute.cc
|
||||
engines/overlay/overlay_volume.cc
|
||||
engines/overlay/overlay_wireframe.cc
|
||||
engines/overlay/overlay_onion_skin.cc
|
||||
|
||||
DRW_engine.h
|
||||
DRW_pbvh.hh
|
||||
@ -698,6 +699,8 @@ set(GLSL_SRC
|
||||
engines/overlay/shaders/overlay_motion_path_line_vert.glsl
|
||||
engines/overlay/shaders/overlay_motion_path_line_vert_no_geom.glsl
|
||||
engines/overlay/shaders/overlay_motion_path_point_vert.glsl
|
||||
engines/overlay/shaders/overlay_onion_skin_mesh_frag.glsl
|
||||
engines/overlay/shaders/overlay_onion_skin_mesh_vert.glsl
|
||||
engines/overlay/shaders/overlay_outline_detect_frag.glsl
|
||||
engines/overlay/shaders/overlay_outline_prepass_curves_vert.glsl
|
||||
engines/overlay/shaders/overlay_outline_prepass_frag.glsl
|
||||
|
@ -137,6 +137,7 @@ static void OVERLAY_engine_init(void *vedata)
|
||||
OVERLAY_outline_init(data);
|
||||
OVERLAY_wireframe_init(data);
|
||||
OVERLAY_paint_init(data);
|
||||
OVERLAY_onion_skin_init(data);
|
||||
}
|
||||
|
||||
static void OVERLAY_cache_init(void *vedata)
|
||||
@ -365,6 +366,8 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob)
|
||||
|
||||
const bool draw_motion_paths = (pd->overlay.flag & V3D_OVERLAY_HIDE_MOTION_PATHS) == 0;
|
||||
|
||||
const bool draw_onion_skins = pd->overlay.flag & V3D_OVERLAY_ONION_SKINS;
|
||||
|
||||
bool do_init;
|
||||
OVERLAY_DupliData *dupli = OVERLAY_duplidata_get(ob, vedata, &do_init);
|
||||
|
||||
@ -386,6 +389,9 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob)
|
||||
if (draw_bone_selection) {
|
||||
OVERLAY_pose_cache_populate(data, ob);
|
||||
}
|
||||
if (draw_onion_skins) {
|
||||
OVERLAY_onion_skin_populate(data, ob);
|
||||
}
|
||||
|
||||
if (pd->overlay.flag & V3D_OVERLAY_VIEWER_ATTRIBUTE) {
|
||||
if (is_preview) {
|
||||
@ -686,6 +692,7 @@ static void OVERLAY_draw_scene(void *vedata)
|
||||
|
||||
OVERLAY_image_in_front_draw(data);
|
||||
OVERLAY_motion_path_draw(data);
|
||||
OVERLAY_onion_skin_draw(data);
|
||||
OVERLAY_extra_centers_draw(data);
|
||||
|
||||
if (DRW_state_is_select() || DRW_state_is_depth()) {
|
||||
|
88
source/blender/draw/engines/overlay/overlay_onion_skin.cc
Normal file
88
source/blender/draw/engines/overlay/overlay_onion_skin.cc
Normal file
@ -0,0 +1,88 @@
|
||||
#include "BKE_mesh.h"
|
||||
#include "DRW_render.h"
|
||||
#include "draw_cache_impl.h"
|
||||
#include "overlay_private.hh"
|
||||
|
||||
void OVERLAY_onion_skin_init(OVERLAY_Data *vedata)
|
||||
{
|
||||
OVERLAY_PassList *psl = vedata->psl;
|
||||
OVERLAY_PrivateData *pd = vedata->stl->pd;
|
||||
|
||||
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA;
|
||||
DRW_PASS_CREATE(psl->onion_skin_ps, state | pd->clipping_state);
|
||||
|
||||
DRWShadingGroup *grp;
|
||||
|
||||
GPUShader *shader = OVERLAY_shader_onion_skin_mesh();
|
||||
pd->onion_skin_grp = grp = DRW_shgroup_create(shader, psl->onion_skin_ps);
|
||||
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
|
||||
|
||||
GPUShader *shader_outline = OVERLAY_shader_onion_skin_outline();
|
||||
pd->onion_skin_outline_grp = grp = DRW_shgroup_create(shader_outline, psl->onion_skin_ps);
|
||||
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
|
||||
}
|
||||
|
||||
static bool str_equals(const char *__restrict str, const char *__restrict start)
|
||||
{
|
||||
for (; *str && *start; str++, start++) {
|
||||
if (*str != *start) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return (*start == *str);
|
||||
}
|
||||
|
||||
void OVERLAY_onion_skin_populate(OVERLAY_Data *vedata, Object *ob)
|
||||
{
|
||||
OVERLAY_PrivateData *pd = vedata->stl->pd;
|
||||
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
|
||||
Scene *scene = draw_ctx->scene;
|
||||
const float current_frame = BKE_scene_ctime_get(scene);
|
||||
|
||||
DRWShadingGroup *grp = nullptr;
|
||||
if (scene->onion_skin_cache.draw_method == ONION_SKIN_DRAW_SOLID) {
|
||||
grp = pd->onion_skin_grp;
|
||||
}
|
||||
else {
|
||||
grp = pd->onion_skin_outline_grp;
|
||||
}
|
||||
DRW_shgroup_uniform_float_copy(grp, "alpha", scene->onion_skin_cache.alpha);
|
||||
|
||||
LISTBASE_FOREACH (OnionSkinMeshLink *, mesh_link, &scene->onion_skin_cache.objects) {
|
||||
if (!str_equals(ob->id.name, mesh_link->object->id.name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (compare_ff(mesh_link->frame, current_frame, FLT_EPSILON)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mesh_link->frame < current_frame - scene->onion_skin_cache.relative_left) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mesh_link->frame > current_frame + scene->onion_skin_cache.relative_right) {
|
||||
continue;
|
||||
}
|
||||
if (mesh_link->frame < current_frame) {
|
||||
DRW_shgroup_uniform_vec3_copy(grp, "color", draw_ctx->scene->onion_skin_cache.color_left);
|
||||
}
|
||||
else {
|
||||
DRW_shgroup_uniform_vec3_copy(grp, "color", draw_ctx->scene->onion_skin_cache.color_right);
|
||||
}
|
||||
|
||||
struct GPUBatch *geom = DRW_cache_object_surface_get(ob);
|
||||
if (geom) {
|
||||
DRW_shgroup_call(grp, geom, ob);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OVERLAY_onion_skin_draw(OVERLAY_Data *vedata)
|
||||
{
|
||||
OVERLAY_PassList *psl = vedata->psl;
|
||||
DRW_draw_pass(psl->onion_skin_ps);
|
||||
}
|
@ -113,6 +113,7 @@ typedef struct OVERLAY_PassList {
|
||||
DRWPass *image_foreground_scene_ps;
|
||||
DRWPass *metaball_ps[2];
|
||||
DRWPass *motion_paths_ps;
|
||||
DRWPass *onion_skin_ps;
|
||||
DRWPass *outlines_prepass_ps;
|
||||
DRWPass *outlines_detect_ps;
|
||||
DRWPass *outlines_resolve_ps;
|
||||
@ -279,6 +280,8 @@ typedef struct OVERLAY_PrivateData {
|
||||
DRWShadingGroup *flash_grp[2];
|
||||
DRWShadingGroup *motion_path_lines_grp;
|
||||
DRWShadingGroup *motion_path_points_grp;
|
||||
DRWShadingGroup *onion_skin_grp;
|
||||
DRWShadingGroup *onion_skin_outline_grp;
|
||||
DRWShadingGroup *outlines_grp;
|
||||
DRWShadingGroup *outlines_curves_grp;
|
||||
DRWShadingGroup *outlines_ptcloud_grp;
|
||||
@ -653,6 +656,7 @@ void OVERLAY_image_empty_cache_populate(OVERLAY_Data *vedata, Object *ob);
|
||||
void OVERLAY_image_cache_finish(OVERLAY_Data *vedata);
|
||||
void OVERLAY_image_draw(OVERLAY_Data *vedata);
|
||||
void OVERLAY_image_background_draw(OVERLAY_Data *vedata);
|
||||
|
||||
/**
|
||||
* This function draws images that needs the view transform applied.
|
||||
* It draws these images directly into the scene color buffer.
|
||||
@ -670,6 +674,10 @@ void OVERLAY_motion_path_cache_init(OVERLAY_Data *vedata);
|
||||
void OVERLAY_motion_path_cache_populate(OVERLAY_Data *vedata, Object *ob);
|
||||
void OVERLAY_motion_path_draw(OVERLAY_Data *vedata);
|
||||
|
||||
void OVERLAY_onion_skin_init(OVERLAY_Data *vedata);
|
||||
void OVERLAY_onion_skin_populate(OVERLAY_Data *vedata, Object *ob);
|
||||
void OVERLAY_onion_skin_draw(OVERLAY_Data *vedata);
|
||||
|
||||
void OVERLAY_outline_init(OVERLAY_Data *vedata);
|
||||
void OVERLAY_outline_cache_init(OVERLAY_Data *vedata);
|
||||
void OVERLAY_outline_cache_populate(OVERLAY_Data *vedata,
|
||||
@ -769,6 +777,8 @@ GPUShader *OVERLAY_shader_grid_image(void);
|
||||
GPUShader *OVERLAY_shader_image(void);
|
||||
GPUShader *OVERLAY_shader_motion_path_line(void);
|
||||
GPUShader *OVERLAY_shader_motion_path_vert(void);
|
||||
GPUShader *OVERLAY_shader_onion_skin_mesh(void);
|
||||
GPUShader *OVERLAY_shader_onion_skin_outline(void);
|
||||
GPUShader *OVERLAY_shader_uniform_color(void);
|
||||
GPUShader *OVERLAY_shader_uniform_color_pointcloud(void);
|
||||
GPUShader *OVERLAY_shader_outline_prepass(bool use_wire);
|
||||
|
@ -78,6 +78,8 @@ struct OVERLAY_Shaders {
|
||||
GPUShader *image;
|
||||
GPUShader *motion_path_line;
|
||||
GPUShader *motion_path_vert;
|
||||
GPUShader *onion_skin_mesh;
|
||||
GPUShader *onion_skin_outline;
|
||||
GPUShader *outline_prepass;
|
||||
GPUShader *outline_prepass_curves;
|
||||
GPUShader *outline_prepass_gpencil;
|
||||
@ -685,6 +687,26 @@ GPUShader *OVERLAY_shader_motion_path_vert(void)
|
||||
return sh_data->motion_path_vert;
|
||||
}
|
||||
|
||||
GPUShader *OVERLAY_shader_onion_skin_mesh(void)
|
||||
{
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
|
||||
if (!sh_data->onion_skin_mesh) {
|
||||
sh_data->onion_skin_mesh = GPU_shader_create_from_info_name("overlay_onion_skin_mesh");
|
||||
}
|
||||
return sh_data->onion_skin_mesh;
|
||||
}
|
||||
|
||||
GPUShader *OVERLAY_shader_onion_skin_outline(void)
|
||||
{
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
|
||||
if (!sh_data->onion_skin_outline) {
|
||||
sh_data->onion_skin_outline = GPU_shader_create_from_info_name("overlay_outline_detect");
|
||||
}
|
||||
return sh_data->onion_skin_outline;
|
||||
}
|
||||
|
||||
GPUShader *OVERLAY_shader_outline_prepass(bool use_wire)
|
||||
{
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
|
@ -248,6 +248,26 @@ GPU_SHADER_CREATE_INFO(overlay_motion_path_point_clipped)
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Onion Skin
|
||||
* \{ */
|
||||
|
||||
GPU_SHADER_INTERFACE_INFO(onion_skin_iface, "interp").smooth(Type::VEC4, "color");
|
||||
|
||||
GPU_SHADER_CREATE_INFO(overlay_onion_skin_mesh)
|
||||
.do_static_compilation(true)
|
||||
.vertex_in(0, Type::VEC3, "pos")
|
||||
.vertex_out(onion_skin_iface)
|
||||
.push_constant(Type::VEC3, "color")
|
||||
.push_constant(Type::FLOAT, "alpha")
|
||||
.push_constant(Type::INT, "draw_method")
|
||||
.fragment_out(0, Type::VEC4, "fragColor")
|
||||
.fragment_source("overlay_onion_skin_mesh_frag.glsl")
|
||||
.vertex_source("overlay_onion_skin_mesh_vert.glsl")
|
||||
.additional_info("draw_mesh", "draw_globals");
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Image Empty
|
||||
* \{ */
|
||||
|
@ -0,0 +1,4 @@
|
||||
void main()
|
||||
{
|
||||
fragColor = interp.color;
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
#pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
|
||||
void main()
|
||||
{
|
||||
interp.color.rgb = color;
|
||||
interp.color.a = alpha;
|
||||
vec3 world_pos = point_object_to_world(pos);
|
||||
gl_Position = point_world_to_ndc(world_pos);
|
||||
/* view_clipping_distances(world_pos); */
|
||||
}
|
@ -29,6 +29,7 @@ set(SRC
|
||||
anim_ipo_utils.c
|
||||
anim_markers.c
|
||||
anim_motion_paths.c
|
||||
anim_onion_skin.c
|
||||
anim_ops.c
|
||||
drivers.c
|
||||
fmodifier_ui.c
|
||||
|
99
source/blender/editors/animation/anim_onion_skin.c
Normal file
99
source/blender/editors/animation/anim_onion_skin.c
Normal file
@ -0,0 +1,99 @@
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_layer.h"
|
||||
#include "BKE_lib_id.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_mesh.h"
|
||||
#include "BKE_object.h"
|
||||
#include "BKE_scene.h"
|
||||
#include "DEG_depsgraph.h"
|
||||
#include "DEG_depsgraph_build.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_windowmanager_types.h"
|
||||
#include "ED_onion_skin.h"
|
||||
#include "ED_outliner.h"
|
||||
#include "MEM_guardedalloc.h"
|
||||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
|
||||
static void graveyard()
|
||||
{
|
||||
ListBase selected = {NULL, NULL};
|
||||
LISTBASE_FOREACH (CollectionPointerLink *, object_ptr_link, &selected) {
|
||||
/* Mesh *mesh = BKE_mesh_from_object(ob);
|
||||
if (!mesh) {
|
||||
continue;
|
||||
} */
|
||||
/* Mesh *copy = BKE_mesh_copy_for_eval(mesh); */
|
||||
/* Mesh *mesh_result = (Mesh *)BKE_id_copy_ex(
|
||||
NULL, &mesh->id, NULL, LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT); */
|
||||
/*
|
||||
OnionSkinMeshLink *link = MEM_callocN(sizeof(OnionSkinMeshLink), "onion skin mesh link");
|
||||
link->mesh = copy;
|
||||
BLI_addtail(&scene->onion_skin_cache.meshes, link); */
|
||||
}
|
||||
BLI_freelistN(&selected);
|
||||
}
|
||||
|
||||
static int onion_skin_add_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
Main *bmain = CTX_data_main(C);
|
||||
BKE_main_id_newptr_and_tag_clear(bmain);
|
||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
|
||||
Object *ob = CTX_data_active_object(C);
|
||||
if (!ob) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
Mesh *mesh = BKE_mesh_from_object(ob);
|
||||
if (!mesh) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
/* Mesh *copy = BKE_mesh_copy_for_eval(mesh); */
|
||||
/* Mesh *copy = (Mesh *)BKE_id_copy_ex(bmain, &mesh->id, NULL, LIB_ID_COPY_DEFAULT); */
|
||||
Object *ob_new = BKE_object_duplicate(bmain,
|
||||
ob,
|
||||
(eDupli_ID_Flags)U.dupflag,
|
||||
LIB_ID_DUPLICATE_IS_SUBPROCESS |
|
||||
LIB_ID_DUPLICATE_IS_ROOT_ID);
|
||||
LayerCollection *layer_collection = BKE_layer_collection_from_index(view_layer, 2);
|
||||
BKE_collection_object_add(bmain, layer_collection->collection, ob_new);
|
||||
OnionSkinMeshLink *link = MEM_callocN(sizeof(OnionSkinMeshLink), "onion skin mesh link");
|
||||
link->object = ob_new;
|
||||
ob_new->adt = NULL;
|
||||
link->frame = BKE_scene_ctime_get(scene);
|
||||
BLI_addtail(&scene->onion_skin_cache.objects, link);
|
||||
|
||||
ED_outliner_select_sync_from_object_tag(C);
|
||||
|
||||
DEG_relations_tag_update(bmain);
|
||||
DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT);
|
||||
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT | ND_LAYER_CONTENT, scene);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static void ANIM_OT_onion_skin_add(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Add Onion Skin";
|
||||
ot->description = "foobar";
|
||||
ot->idname = "ANIM_OT_onion_skin_add";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = onion_skin_add_exec;
|
||||
/* ot->cancel = WM_gesture_box_cancel; */
|
||||
|
||||
/* ot->poll = ed_markers_poll_markers_exist; */
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
|
||||
|
||||
/* properties */
|
||||
}
|
||||
|
||||
void ED_operatortypes_onion_skin(void)
|
||||
{
|
||||
WM_operatortype_append(ANIM_OT_onion_skin_add);
|
||||
}
|
@ -395,6 +395,138 @@ static void ANIM_OT_change_frame(wmOperatorType *ot)
|
||||
|
||||
/** \} */
|
||||
|
||||
/* Set the new frame number */
|
||||
static void change_onion_skin_range_apply(bContext *C, wmOperator *op)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
const int left = RNA_int_get(op->ptr, "left");
|
||||
const int right = RNA_int_get(op->ptr, "right");
|
||||
|
||||
scene->onion_skin_cache.relative_left = left;
|
||||
scene->onion_skin_cache.relative_right = right;
|
||||
|
||||
DEG_id_tag_update(&scene->id, ID_RECALC_FRAME_CHANGE);
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
|
||||
}
|
||||
|
||||
static void onion_skin_range_foo(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
const int clicked_frame = roundf(frame_from_event(C, event));
|
||||
const int current_scene_frame = BKE_scene_ctime_get(scene);
|
||||
if (clicked_frame > current_scene_frame) {
|
||||
RNA_int_set(op->ptr, "right", clicked_frame - current_scene_frame);
|
||||
}
|
||||
else if (clicked_frame < current_scene_frame) {
|
||||
RNA_int_set(op->ptr, "left", current_scene_frame - clicked_frame);
|
||||
}
|
||||
}
|
||||
|
||||
static void change_onion_skin_range_cancel(bContext *C, wmOperator *UNUSED(op))
|
||||
{
|
||||
bScreen *screen = CTX_wm_screen(C);
|
||||
screen->scrubbing = false;
|
||||
|
||||
SpaceSeq *sseq = CTX_wm_space_seq(C);
|
||||
if (sseq != NULL) {
|
||||
change_frame_seq_preview_end(sseq);
|
||||
}
|
||||
|
||||
if (need_extra_redraw_after_scrubbing_ends(C)) {
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
|
||||
}
|
||||
}
|
||||
|
||||
/* Modal event handling of frame changing */
|
||||
static int change_onion_skin_range_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
int ret = OPERATOR_RUNNING_MODAL;
|
||||
/* execute the events */
|
||||
switch (event->type) {
|
||||
case EVT_ESCKEY:
|
||||
ret = OPERATOR_FINISHED;
|
||||
break;
|
||||
|
||||
case MOUSEMOVE:
|
||||
onion_skin_range_foo(C, op, event);
|
||||
change_onion_skin_range_apply(C, op);
|
||||
break;
|
||||
|
||||
case LEFTMOUSE:
|
||||
case RIGHTMOUSE:
|
||||
case MIDDLEMOUSE:
|
||||
/* We check for either mouse-button to end, to work with all user keymaps. */
|
||||
if (event->val == KM_RELEASE) {
|
||||
ret = OPERATOR_FINISHED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret != OPERATOR_RUNNING_MODAL) {
|
||||
bScreen *screen = CTX_wm_screen(C);
|
||||
screen->scrubbing = false;
|
||||
|
||||
if (need_extra_redraw_after_scrubbing_ends(C)) {
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Modal Operator init */
|
||||
static int change_onion_skin_range_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
ARegion *region = CTX_wm_region(C);
|
||||
bScreen *screen = CTX_wm_screen(C);
|
||||
if (CTX_wm_space_seq(C) != NULL && region->regiontype == RGN_TYPE_PREVIEW) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
RNA_int_set(op->ptr, "right", scene->onion_skin_cache.relative_right);
|
||||
RNA_int_set(op->ptr, "left", scene->onion_skin_cache.relative_left);
|
||||
|
||||
onion_skin_range_foo(C, op, event);
|
||||
|
||||
screen->scrubbing = true;
|
||||
|
||||
change_onion_skin_range_apply(C, op);
|
||||
|
||||
/* add temp handler */
|
||||
WM_event_add_modal_handler(C, op);
|
||||
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
static int change_onion_skin_range_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
change_onion_skin_range_apply(C, op);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static void ANIM_OT_change_onion_skin_range(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Change Onion Skin Range";
|
||||
ot->idname = "ANIM_OT_change_onion_skin_range";
|
||||
ot->description = "Interactively change the amount of onion skins shown";
|
||||
|
||||
ot->exec = change_onion_skin_range_exec;
|
||||
ot->poll = change_frame_poll;
|
||||
ot->invoke = change_onion_skin_range_invoke;
|
||||
ot->modal = change_onion_skin_range_modal;
|
||||
ot->cancel = change_onion_skin_range_cancel;
|
||||
|
||||
/* rna */
|
||||
ot->prop = RNA_def_int(
|
||||
ot->srna, "left", 0, MINAFRAME, MAXFRAME, "Left", "", MINAFRAME, MAXFRAME);
|
||||
ot->prop = RNA_def_int(
|
||||
ot->srna, "right", 0, MINAFRAME, MAXFRAME, "Right", "", MINAFRAME, MAXFRAME);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Start/End Frame Operators
|
||||
* \{ */
|
||||
@ -652,6 +784,7 @@ void ED_operatortypes_anim(void)
|
||||
{
|
||||
/* Animation Editors only -------------------------- */
|
||||
WM_operatortype_append(ANIM_OT_change_frame);
|
||||
WM_operatortype_append(ANIM_OT_change_onion_skin_range);
|
||||
|
||||
WM_operatortype_append(ANIM_OT_start_frame_set);
|
||||
WM_operatortype_append(ANIM_OT_end_frame_set);
|
||||
|
@ -122,6 +122,41 @@ static void draw_current_frame(const Scene *scene,
|
||||
float outline_color[4];
|
||||
UI_GetThemeColorShade4fv(TH_CFRAME, 5, outline_color);
|
||||
|
||||
if (scene->onion_skin_cache.relative_left != 0) {
|
||||
const int frame_relative_left = UI_view2d_view_to_region_x(
|
||||
v2d, current_frame - scene->onion_skin_cache.relative_left);
|
||||
UI_draw_roundbox_4fv_ex(
|
||||
&(const rctf){
|
||||
.xmin = frame_relative_left - box_width / 4 + U.pixelsize / 2,
|
||||
.xmax = frame_relative_left + box_width / 4 + U.pixelsize / 2,
|
||||
.ymin = scrub_region_rect->ymin + box_padding,
|
||||
.ymax = scrub_region_rect->ymax - box_padding,
|
||||
},
|
||||
bg_color,
|
||||
NULL,
|
||||
1.0f,
|
||||
outline_color,
|
||||
U.pixelsize,
|
||||
4 * UI_SCALE_FAC);
|
||||
}
|
||||
if (scene->onion_skin_cache.relative_right != 0) {
|
||||
const int frame_relative_right = UI_view2d_view_to_region_x(
|
||||
v2d, current_frame + scene->onion_skin_cache.relative_right);
|
||||
UI_draw_roundbox_4fv_ex(
|
||||
&(const rctf){
|
||||
.xmin = frame_relative_right - box_width / 4 + U.pixelsize / 2,
|
||||
.xmax = frame_relative_right + box_width / 4 + U.pixelsize / 2,
|
||||
.ymin = scrub_region_rect->ymin + box_padding,
|
||||
.ymax = scrub_region_rect->ymax - box_padding,
|
||||
},
|
||||
bg_color,
|
||||
NULL,
|
||||
1.0f,
|
||||
outline_color,
|
||||
U.pixelsize,
|
||||
4 * UI_SCALE_FAC);
|
||||
}
|
||||
|
||||
UI_draw_roundbox_4fv_ex(
|
||||
&(const rctf){
|
||||
.xmin = frame_x - box_width / 2 + U.pixelsize / 2,
|
||||
|
2
source/blender/editors/include/ED_onion_skin.h
Normal file
2
source/blender/editors/include/ED_onion_skin.h
Normal file
@ -0,0 +1,2 @@
|
||||
|
||||
void ED_operatortypes_onion_skin(void);
|
@ -41,6 +41,7 @@
|
||||
#include "ED_mesh.h"
|
||||
#include "ED_node.h"
|
||||
#include "ED_object.h"
|
||||
#include "ED_onion_skin.h"
|
||||
#include "ED_paint.h"
|
||||
#include "ED_physics.h"
|
||||
#include "ED_render.h"
|
||||
@ -105,6 +106,7 @@ void ED_spacetypes_init(void)
|
||||
ED_operatortypes_curves();
|
||||
ED_operatortypes_armature();
|
||||
ED_operatortypes_marker();
|
||||
ED_operatortypes_onion_skin();
|
||||
ED_operatortypes_metaball();
|
||||
ED_operatortypes_sound();
|
||||
ED_operatortypes_render();
|
||||
|
@ -1857,6 +1857,28 @@ typedef struct SceneGpencil {
|
||||
char _pad[4];
|
||||
} SceneGpencil;
|
||||
|
||||
typedef struct OnionSkinMeshLink {
|
||||
struct OnionSkinMeshLink *prev, *next;
|
||||
/* Having a Mesh pointer here breaks compilation. Complains about "extern C" issues. */
|
||||
struct Object *object;
|
||||
float frame;
|
||||
char _pad[4];
|
||||
} OnionSkinMeshLink;
|
||||
|
||||
enum {
|
||||
ONION_SKIN_DRAW_SOLID = 0,
|
||||
ONION_SKIN_DRAW_OUTLINE = 1,
|
||||
};
|
||||
|
||||
typedef struct SceneOnionSkin {
|
||||
float color_left[3];
|
||||
float color_right[3];
|
||||
float alpha;
|
||||
int relative_left, relative_right;
|
||||
int draw_method;
|
||||
ListBase objects /* OnionSkinMeshLink */;
|
||||
} SceneOnionSkin;
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
@ -2003,6 +2025,7 @@ typedef struct Scene {
|
||||
struct SceneDisplay display;
|
||||
struct SceneEEVEE eevee;
|
||||
struct SceneGpencil grease_pencil_settings;
|
||||
struct SceneOnionSkin onion_skin_cache;
|
||||
} Scene;
|
||||
|
||||
/** \} */
|
||||
|
@ -671,6 +671,12 @@ static const EnumPropertyItem plane_orientation_items[] = {
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
static const EnumPropertyItem onion_skin_draw_modes[] = {
|
||||
{ONION_SKIN_DRAW_SOLID, "SOLID", 0, "Solid", "Draw solid shape"},
|
||||
{ONION_SKIN_DRAW_OUTLINE, "OUTLINE", 0, "Outline", "Draw outline"},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
static const EnumPropertyItem snap_to_items[] = {
|
||||
{SCE_SNAP_MODE_GEOM, "GEOMETRY", 0, "Geometry", "Snap to all geometry"},
|
||||
{SCE_SNAP_MODE_NONE, "DEFAULT", 0, "Default", "Use the current snap settings"},
|
||||
@ -8442,6 +8448,48 @@ void RNA_def_scene(BlenderRNA *brna)
|
||||
RNA_def_property_struct_type(prop, "SceneGpencil");
|
||||
RNA_def_property_ui_text(prop, "Grease Pencil", "Grease Pencil settings for the scene");
|
||||
|
||||
prop = RNA_def_property(srna, "onion_skin_color_left", PROP_FLOAT, PROP_COLOR);
|
||||
RNA_def_property_float_sdna(prop, NULL, "onion_skin_cache.color_left");
|
||||
RNA_def_property_array(prop, 3);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_ui_text(prop, "Onion Skin Color Left", "Define the color of onion skins");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "onion_skin_color_right", PROP_FLOAT, PROP_COLOR);
|
||||
RNA_def_property_float_sdna(prop, NULL, "onion_skin_cache.color_right");
|
||||
RNA_def_property_array(prop, 3);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_ui_text(prop, "Onion Skin Color Right", "Define the color of onion skins");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "os_relative_left", PROP_INT, PROP_UNSIGNED);
|
||||
RNA_def_property_int_sdna(prop, NULL, "onion_skin_cache.relative_left");
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Onion Skin Range Left", "how far to the lef to draw onion skins");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "os_relative_right", PROP_INT, PROP_UNSIGNED);
|
||||
RNA_def_property_int_sdna(prop, NULL, "onion_skin_cache.relative_right");
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Onion Skin Range Right", "how far to the lef to draw onion skins");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "onion_skin_alpha", PROP_FLOAT, PROP_FACTOR);
|
||||
RNA_def_property_float_sdna(prop, NULL, "onion_skin_cache.alpha");
|
||||
RNA_def_property_ui_text(prop, "Onion Skin Alpha", "Alpha of drawn onion skins");
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 1, 2);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "onion_skin_draw_modes", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "onion_skin_cache.draw_method");
|
||||
RNA_def_property_enum_items(prop, onion_skin_draw_modes);
|
||||
RNA_def_property_enum_default(prop, ONION_SKIN_DRAW_SOLID);
|
||||
RNA_def_property_ui_text(prop, "Onion Skin Draw Modes", "How to draw os's");
|
||||
|
||||
/* Nestled Data. */
|
||||
/* *** Non-Animated *** */
|
||||
RNA_define_animate_sdna(false);
|
||||
|
@ -1542,7 +1542,8 @@ static void rna_3DViewShading_render_pass_set(PointerRNA *ptr, int value)
|
||||
STRNCPY(shading->aov_name, aov->name);
|
||||
}
|
||||
else if (value == EEVEE_RENDER_PASS_BLOOM &&
|
||||
((scene->eevee.flag & SCE_EEVEE_BLOOM_ENABLED) == 0)) {
|
||||
((scene->eevee.flag & SCE_EEVEE_BLOOM_ENABLED) == 0))
|
||||
{
|
||||
shading->render_pass = EEVEE_RENDER_PASS_COMBINED;
|
||||
}
|
||||
else {
|
||||
@ -3299,7 +3300,8 @@ const EnumPropertyItem *rna_SpaceSpreadsheet_attribute_domain_itemf(bContext *UN
|
||||
ATTR_DOMAIN_CORNER,
|
||||
ATTR_DOMAIN_EDGE,
|
||||
ATTR_DOMAIN_POINT,
|
||||
ATTR_DOMAIN_FACE)) {
|
||||
ATTR_DOMAIN_FACE))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user