Camera tracking: initial commit of dopesheet view for clip editor

- Displays dopesheet information for selected tracks, and currently does not
  support any kind of editing.
- Changed regions to use the whole main region for such views as curves and dopesheet.
  This allows to have own panels with tools/properties in this area.
- Active clip is getting synchronized between different clip editor editors in the
  same screen, so updating of curve/dopesheet views happens automatically when one
  changes current clip in one of this editors.
- Panels in toolbox and properties panels are now separated to rely on current view
  mode, but some operators and poll functions still need to be updated.
- Added new screen called "Movie Tracking" where layout is configured to
  display timeline, main clip window, curves and dopesheet.
This commit is contained in:
Sergey Sharybin 2012-04-30 16:19:20 +00:00
parent 323aedb81e
commit f111131ca6
25 changed files with 8443 additions and 7057 deletions

@ -38,19 +38,20 @@ class CLIP_HT_header(Header):
sub = row.row(align=True)
sub.menu("CLIP_MT_view")
if clip:
sub.menu("CLIP_MT_select")
if sc.view == 'CLIP':
if clip:
sub.menu("CLIP_MT_select")
sub.menu("CLIP_MT_clip")
sub.menu("CLIP_MT_clip")
if clip:
sub.menu("CLIP_MT_track")
sub.menu("CLIP_MT_reconstruction")
if clip:
layout.prop(sc, "mode", text="")
layout.prop(sc, "view", text="", expand=True)
layout.prop(sc, "view", text="", expand=True)
if clip:
if sc.view == 'CLIP':
layout.prop(sc, "mode", text="")
if sc.view == 'GRAPH':
row = layout.row(align=True)
@ -79,24 +80,56 @@ class CLIP_HT_header(Header):
else:
r = tracking.reconstruction
if r.is_valid:
if r.is_valid and sc.view == 'CLIP':
layout.label(text="Average solve error: %.4f" %
(r.average_error))
layout.template_running_jobs()
class CLIP_PT_tools_marker(Panel):
bl_space_type = 'CLIP_EDITOR'
bl_region_type = 'TOOLS'
bl_label = "Marker"
class CLIP_PT_clip_view_panel:
@classmethod
def poll(cls, context):
sc = context.space_data
clip = sc.clip
return clip and sc.mode == 'TRACKING'
return clip and sc.view == 'CLIP'
class CLIP_PT_tracking_panel:
@classmethod
def poll(cls, context):
sc = context.space_data
clip = sc.clip
return clip and sc.mode == 'TRACKING' and sc.view == 'CLIP'
class CLIP_PT_reconstruction_panel:
@classmethod
def poll(cls, context):
sc = context.space_data
clip = sc.clip
return clip and sc.mode == 'RECONSTRUCTION' and sc.view == 'CLIP'
class CLIP_PT_distortion_panel:
@classmethod
def poll(cls, context):
sc = context.space_data
clip = sc.clip
return clip and sc.mode == 'DISTORTION' and sc.view == 'CLIP'
class CLIP_PT_tools_marker(CLIP_PT_tracking_panel, Panel):
bl_space_type = 'CLIP_EDITOR'
bl_region_type = 'TOOLS'
bl_label = "Marker"
def draw(self, context):
sc = context.space_data
@ -162,18 +195,11 @@ class CLIP_PT_tools_marker(Panel):
text="Copy From Active Track")
class CLIP_PT_tools_tracking(Panel):
class CLIP_PT_tools_tracking(CLIP_PT_tracking_panel, Panel):
bl_space_type = 'CLIP_EDITOR'
bl_region_type = 'TOOLS'
bl_label = "Track"
@classmethod
def poll(cls, context):
sc = context.space_data
clip = sc.clip
return clip and sc.mode == 'TRACKING'
def draw(self, context):
layout = self.layout
@ -201,18 +227,11 @@ class CLIP_PT_tools_tracking(Panel):
layout.operator("clip.join_tracks", text="Join")
class CLIP_PT_tools_solve(Panel):
class CLIP_PT_tools_solve(CLIP_PT_tracking_panel, Panel):
bl_space_type = 'CLIP_EDITOR'
bl_region_type = 'TOOLS'
bl_label = "Solve"
@classmethod
def poll(cls, context):
sc = context.space_data
clip = sc.clip
return clip and sc.mode == 'TRACKING'
def draw(self, context):
layout = self.layout
clip = context.space_data.clip
@ -241,18 +260,11 @@ class CLIP_PT_tools_solve(Panel):
col.prop(settings, "refine_intrinsics", text="")
class CLIP_PT_tools_cleanup(Panel):
class CLIP_PT_tools_cleanup(CLIP_PT_tracking_panel, Panel):
bl_space_type = 'CLIP_EDITOR'
bl_region_type = 'TOOLS'
bl_label = "Clean up"
@classmethod
def poll(cls, context):
sc = context.space_data
clip = sc.clip
return clip and sc.mode == 'TRACKING'
def draw(self, context):
layout = self.layout
clip = context.space_data.clip
@ -265,18 +277,11 @@ class CLIP_PT_tools_cleanup(Panel):
layout.prop(settings, 'clean_action', text="")
class CLIP_PT_tools_geometry(Panel):
class CLIP_PT_tools_geometry(CLIP_PT_reconstruction_panel, Panel):
bl_space_type = 'CLIP_EDITOR'
bl_region_type = 'TOOLS'
bl_label = "Geometry"
@classmethod
def poll(cls, context):
sc = context.space_data
clip = sc.clip
return clip and sc.mode == 'RECONSTRUCTION'
def draw(self, context):
layout = self.layout
@ -284,18 +289,11 @@ class CLIP_PT_tools_geometry(Panel):
layout.operator("clip.track_to_empty")
class CLIP_PT_tools_orientation(Panel):
class CLIP_PT_tools_orientation(CLIP_PT_reconstruction_panel, Panel):
bl_space_type = 'CLIP_EDITOR'
bl_region_type = 'TOOLS'
bl_label = "Orientation"
@classmethod
def poll(cls, context):
sc = context.space_data
clip = sc.clip
return clip and sc.mode == 'RECONSTRUCTION'
def draw(self, context):
sc = context.space_data
layout = self.layout
@ -320,18 +318,19 @@ class CLIP_PT_tools_orientation(Panel):
col.prop(settings, "distance")
class CLIP_PT_tools_object(Panel):
class CLIP_PT_tools_object(CLIP_PT_reconstruction_panel, Panel):
bl_space_type = 'CLIP_EDITOR'
bl_region_type = 'TOOLS'
bl_label = "Object"
@classmethod
def poll(cls, context):
sc = context.space_data
clip = sc.clip
if CLIP_PT_reconstruction_panel.poll(context):
sc = context.space_data
clip = sc.clip
if clip and sc.mode == 'RECONSTRUCTION':
tracking_object = clip.tracking.objects.active
return not tracking_object.is_camera
return False
@ -354,18 +353,11 @@ class CLIP_PT_tools_object(Panel):
col.prop(settings, "object_distance")
class CLIP_PT_tools_grease_pencil(Panel):
class CLIP_PT_tools_grease_pencil(CLIP_PT_distortion_panel, Panel):
bl_space_type = 'CLIP_EDITOR'
bl_region_type = 'TOOLS'
bl_label = "Grease Pencil"
@classmethod
def poll(cls, context):
sc = context.space_data
clip = sc.clip
return clip and sc.mode == 'DISTORTION'
def draw(self, context):
layout = self.layout
@ -383,18 +375,12 @@ class CLIP_PT_tools_grease_pencil(Panel):
row.prop(context.tool_settings, "use_grease_pencil_sessions")
class CLIP_PT_objects(Panel):
class CLIP_PT_objects(CLIP_PT_clip_view_panel, Panel):
bl_space_type = 'CLIP_EDITOR'
bl_region_type = 'UI'
bl_label = "Objects"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
sc = context.space_data
return sc.clip
def draw(self, context):
layout = self.layout
@ -415,18 +401,11 @@ class CLIP_PT_objects(Panel):
layout.prop(active, "name")
class CLIP_PT_track(Panel):
class CLIP_PT_track(CLIP_PT_tracking_panel, Panel):
bl_space_type = 'CLIP_EDITOR'
bl_region_type = 'UI'
bl_label = "Track"
@classmethod
def poll(cls, context):
sc = context.space_data
clip = sc.clip
return sc.mode == 'TRACKING' and clip
def draw(self, context):
layout = self.layout
sc = context.space_data
@ -482,18 +461,12 @@ class CLIP_PT_track(Panel):
layout.label(text=label_text)
class CLIP_PT_track_settings(Panel):
class CLIP_PT_track_settings(CLIP_PT_tracking_panel, Panel):
bl_space_type = 'CLIP_EDITOR'
bl_region_type = 'UI'
bl_label = "Tracking Settings"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
sc = context.space_data
return sc.mode == 'TRACKING' and sc.clip
def draw(self, context):
layout = self.layout
clip = context.space_data.clip
@ -525,9 +498,12 @@ class CLIP_PT_tracking_camera(Panel):
@classmethod
def poll(cls, context):
sc = context.space_data
if CLIP_PT_clip_view_panel.poll(context):
sc = context.space_data
return sc.mode in {'TRACKING', 'DISTORTION'} and sc.clip
return sc.mode in {'TRACKING', 'DISTORTION'} and sc.clip
return False
def draw(self, context):
layout = self.layout
@ -568,7 +544,7 @@ class CLIP_PT_tracking_camera(Panel):
col.prop(clip.tracking.camera, "k3")
class CLIP_PT_display(Panel):
class CLIP_PT_display(CLIP_PT_clip_view_panel, Panel):
bl_space_type = 'CLIP_EDITOR'
bl_region_type = 'UI'
bl_label = "Display"
@ -613,7 +589,7 @@ class CLIP_PT_display(Panel):
row.prop(clip, "display_aspect", text="")
class CLIP_PT_marker_display(Panel):
class CLIP_PT_marker_display(CLIP_PT_clip_view_panel, Panel):
bl_space_type = 'CLIP_EDITOR'
bl_region_type = 'UI'
bl_label = "Marker Display"
@ -636,18 +612,12 @@ class CLIP_PT_marker_display(Panel):
row.prop(sc, "path_length", text="Length")
class CLIP_PT_stabilization(Panel):
class CLIP_PT_stabilization(CLIP_PT_reconstruction_panel, Panel):
bl_space_type = 'CLIP_EDITOR'
bl_region_type = 'UI'
bl_label = "2D Stabilization"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
sc = context.space_data
return sc.mode == 'RECONSTRUCTION' and sc.clip
def draw_header(self, context):
stab = context.space_data.clip.tracking.stabilization
@ -695,19 +665,12 @@ class CLIP_PT_stabilization(Panel):
layout.prop(stab, "filter_type")
class CLIP_PT_marker(Panel):
class CLIP_PT_marker(CLIP_PT_tracking_panel, Panel):
bl_space_type = 'CLIP_EDITOR'
bl_region_type = 'UI'
bl_label = "Marker"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
sc = context.space_data
clip = sc.clip
return sc.mode == 'TRACKING' and clip
def draw(self, context):
layout = self.layout
sc = context.space_data
@ -721,18 +684,12 @@ class CLIP_PT_marker(Panel):
layout.label(text="No active track")
class CLIP_PT_proxy(Panel):
class CLIP_PT_proxy(CLIP_PT_clip_view_panel, Panel):
bl_space_type = 'CLIP_EDITOR'
bl_region_type = 'UI'
bl_label = "Proxy / Timecode"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
sc = context.space_data
return sc.clip
def draw_header(self, context):
sc = context.space_data
@ -782,18 +739,12 @@ class CLIP_PT_proxy(Panel):
col.prop(sc.clip_user, "use_render_undistorted")
class CLIP_PT_footage(Panel):
class CLIP_PT_footage(CLIP_PT_clip_view_panel, Panel):
bl_space_type = 'CLIP_EDITOR'
bl_region_type = 'UI'
bl_label = "Footage Settings"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
sc = context.space_data
return sc.clip
def draw(self, context):
layout = self.layout
@ -806,17 +757,11 @@ class CLIP_PT_footage(Panel):
layout.operator("clip.open", icon='FILESEL')
class CLIP_PT_tools_clip(Panel):
class CLIP_PT_tools_clip(CLIP_PT_clip_view_panel, Panel):
bl_space_type = 'CLIP_EDITOR'
bl_region_type = 'TOOLS'
bl_label = "Clip"
@classmethod
def poll(cls, context):
sc = context.space_data
return sc.clip
def draw(self, context):
layout = self.layout

@ -42,7 +42,7 @@ extern "C" {
* and keep comment above the defines.
* Use STRINGIFY() rather than defining with quotes */
#define BLENDER_VERSION 263
#define BLENDER_SUBVERSION 1
#define BLENDER_SUBVERSION 2
#define BLENDER_MINVERSION 250
#define BLENDER_MINSUBVERSION 0

@ -164,6 +164,9 @@ struct MovieTrackingObject *BKE_tracking_named_object(struct MovieTracking *trac
void BKE_tracking_select_track(struct ListBase *tracksbase, struct MovieTrackingTrack *track, int area, int extend);
void BKE_tracking_deselect_track(struct MovieTrackingTrack *track, int area);
/* Dopesheet */
void BKE_tracking_update_dopesheet(struct MovieTracking *tracking);
#define TRACK_SELECTED(track) ((track)->flag&SELECT || (track)->pat_flag&SELECT || (track)->search_flag&SELECT)
#define TRACK_AREA_SELECTED(track, area) ((area)==TRACK_AREA_POINT ? (track)->flag&SELECT : \

@ -453,7 +453,7 @@ static MovieClip *movieclip_alloc(const char *name)
MovieClip *BKE_movieclip_file_add(const char *name)
{
MovieClip *clip;
MovieClipUser user;
MovieClipUser user = {0};
int file, len, width, height;
const char *libname;
char str[FILE_MAX], strtest[FILE_MAX];

@ -632,6 +632,12 @@ static void tracking_objects_free(ListBase *objects)
BLI_freelistN(objects);
}
static void tracking_dopesheet_free(MovieTrackingDopesheet *dopesheet)
{
BLI_freelistN(&dopesheet->channels);
dopesheet->tot_channel = 0;
}
void BKE_tracking_free(MovieTracking *tracking)
{
tracking_tracks_free(&tracking->tracks);
@ -643,6 +649,8 @@ void BKE_tracking_free(MovieTracking *tracking)
if (tracking->camera.intrinsics)
BKE_tracking_distortion_destroy(tracking->camera.intrinsics);
tracking_dopesheet_free(&tracking->dopesheet);
}
static MovieTrackingTrack *duplicate_track(MovieTrackingTrack *track)
@ -1352,6 +1360,8 @@ void BKE_tracking_sync(MovieTrackingContext *context)
newframe = context->user.framenr - 1;
context->sync_frame = newframe;
BKE_tracking_update_dopesheet(tracking);
}
void BKE_tracking_sync_user(MovieClipUser *user, MovieTrackingContext *context)
@ -3033,3 +3043,53 @@ MovieTrackingObject *BKE_tracking_named_object(MovieTracking *tracking, const ch
return NULL;
}
/*********************** dopesheet functions *************************/
static int channels_alpha_sort(void *a, void *b)
{
MovieTrackingDopesheetChannel *channel_a = a;
MovieTrackingDopesheetChannel *channel_b = b;
if (BLI_strcasecmp(channel_a->track->name, channel_b->track->name) > 0)
return 1;
else
return 0;
}
void BKE_tracking_update_dopesheet(MovieTracking *tracking)
{
MovieTrackingObject *object = BKE_tracking_active_object(tracking);
MovieTrackingDopesheet *dopesheet = &tracking->dopesheet;
MovieTrackingTrack *track;
ListBase *tracksbase = BKE_tracking_object_tracks(tracking, object);
ListBase old_channels;
old_channels = dopesheet->channels;
dopesheet->channels.first = dopesheet->channels.last = NULL;
dopesheet->tot_channel = 0;
for (track = tracksbase->first; track; track = track->next) {
if (TRACK_SELECTED(track) && (track->flag & TRACK_HIDDEN) == 0) {
MovieTrackingDopesheetChannel *channel, *old_channel;
channel = MEM_callocN(sizeof(MovieTrackingDopesheetChannel), "tracking dopesheet channel");
channel->track = track;
/* copy flags from current dopsheet information to new one */
for (old_channel = old_channels.first; old_channel; old_channel = old_channel->next) {
if (old_channel->track == track) {
channel->flag = old_channel->flag;
break;
}
}
BLI_addtail(&dopesheet->channels, channel);
dopesheet->tot_channel++;
}
}
BLI_sortlist(&dopesheet->channels, channels_alpha_sort);
BLI_freelistN(&old_channels);
}

@ -6168,6 +6168,20 @@ static void direct_link_movieTracks(FileData *fd, ListBase *tracksbase)
}
}
static void direct_link_movieDopesheet(FileData *fd, MovieTrackingDopesheet *dopesheet)
{
MovieTrackingDopesheetChannel *channel;
link_list(fd, &dopesheet->channels);
channel = dopesheet->channels.first;
while (channel) {
channel->track = newdataadr(fd, channel->track);
channel = channel->next;
}
}
static void direct_link_movieclip(FileData *fd, MovieClip *clip)
{
MovieTracking *tracking= &clip->tracking;
@ -6203,6 +6217,8 @@ static void direct_link_movieclip(FileData *fd, MovieClip *clip)
object= object->next;
}
direct_link_movieDopesheet(fd, &clip->tracking.dopesheet);
}
static void lib_link_movieclip(FileData *fd, Main *main)
@ -13284,6 +13300,40 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
}
}
if (main->versionfile < 263 || (main->versionfile == 263 && main->subversionfile < 2)) {
bScreen *sc;
for (sc = main->screen.first; sc; sc = sc->id.next) {
ScrArea *sa;
for (sa = sc->areabase.first; sa; sa = sa->next) {
SpaceLink *sl;
for (sl = sa->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_CLIP) {
SpaceClip *sclip = (SpaceClip *)sl;
ARegion *ar;
int hide = FALSE;
for (ar = sa->regionbase.first; ar; ar = ar->next) {
if (ar->regiontype == RGN_TYPE_PREVIEW) {
if (ar->alignment != RGN_ALIGN_NONE) {
ar->flag |= RGN_FLAG_HIDDEN;
ar->v2d.flag &= ~V2D_IS_INITIALISED;
ar->alignment = RGN_ALIGN_NONE;
hide = TRUE;
}
}
}
if (hide) {
sclip->view = SC_VIEW_CLIP;
}
}
}
}
}
}
/* WATCH IT!!!: pointers from libdata have not been converted yet here! */
/* WATCH IT 2!: Userdef struct init has to be in editors/interface/resources.c! */

@ -2677,6 +2677,18 @@ static void write_movieTracks(WriteData *wd, ListBase *tracks)
}
}
static void write_movieDopesheet(WriteData *wd, MovieTrackingDopesheet *dopesheet)
{
MovieTrackingDopesheetChannel *channel;
channel = dopesheet->channels.first;
while (channel) {
writestruct(wd, DATA, "MovieTrackingDopesheetChannel", 1, channel);
channel = channel->next;
}
}
static void write_movieReconstruction(WriteData *wd, MovieTrackingReconstruction *reconstruction)
{
if (reconstruction->camnr)
@ -2709,6 +2721,8 @@ static void write_movieclips(WriteData *wd, ListBase *idbase)
object= object->next;
}
write_movieDopesheet(wd, &tracking->dopesheet);
}
clip= clip->id.next;

File diff suppressed because it is too large Load Diff

@ -33,6 +33,7 @@
struct ARegion;
struct bContext;
struct bScreen;
struct ImBuf;
struct Main;
struct MovieClip;
@ -45,7 +46,7 @@ int ED_space_clip_tracking_poll(struct bContext *C);
int ED_space_clip_tracking_size_poll(struct bContext *C);
int ED_space_clip_tracking_frame_poll(struct bContext *C);
void ED_space_clip_set(struct bContext *C, struct SpaceClip *sc, struct MovieClip *clip);
void ED_space_clip_set(struct bContext *C, struct bScreen *screen, struct SpaceClip *sc, struct MovieClip *clip);
struct MovieClip *ED_space_clip(struct SpaceClip *sc);
void ED_space_clip_size(struct SpaceClip *sc, int *width, int *height);
void ED_space_clip_zoom(struct SpaceClip *sc, ARegion *ar, float *zoomx, float *zoomy);
@ -68,6 +69,8 @@ void ED_space_clip_free_texture_buffer(struct SpaceClip *sc);
int ED_space_clip_show_trackedit(struct SpaceClip *sc);
void ED_space_clip_update_dopesheet(struct SpaceClip *sc);
/* clip_ops.c */
void ED_operatormacros_clip(void);

@ -864,6 +864,9 @@ void ui_theme_init_default(void)
rgba_char_args_set(btheme->tclip.cframe, 0x60, 0xc0, 0x40, 255);
rgba_char_args_set(btheme->tclip.handle_vertex, 0x00, 0x00, 0x00, 0xff);
rgba_char_args_set(btheme->tclip.handle_vertex_select, 0xff, 0xff, 0, 0xff);
rgba_char_args_set(btheme->tclip.list, 0x66, 0x66, 0x66, 0xff);
rgba_char_args_set(btheme->tclip.strip, 0x0c, 0x0a, 0x0a, 0x80);
rgba_char_args_set(btheme->tclip.strip_select, 0xff, 0x8c, 0x00, 0xff);
btheme->tclip.handle_vertex_size = 4;
}
@ -1775,6 +1778,17 @@ void init_userdef_do_versions(void)
}
}
if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 2)) {
bTheme *btheme;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
if (btheme->tclip.strip[0] == 0) {
rgba_char_args_set(btheme->tclip.list, 0x66, 0x66, 0x66, 0xff);
rgba_char_args_set(btheme->tclip.strip, 0x0c, 0x0a, 0x0a, 0x80);
rgba_char_args_set(btheme->tclip.strip_select, 0xff, 0x8c, 0x00, 0xff);
}
}
}
/* GL Texture Garbage Collection (variable abused above!) */
if (U.textimeout == 0) {
U.texcollectrate = 60;

@ -40,15 +40,17 @@ set(INC_SYS
)
set(SRC
space_clip.c
clip_draw.c
clip_toolbar.c
clip_ops.c
clip_graph_ops.c
clip_graph_draw.c
clip_editor.c
clip_buttons.c
clip_dopesheet_draw.c
clip_dopesheet_ops.c
clip_draw.c
clip_editor.c
clip_graph_draw.c
clip_graph_ops.c
clip_ops.c
clip_toolbar.c
clip_utils.c
space_clip.c
tracking_ops.c
clip_intern.h

@ -63,9 +63,11 @@
/* Panels */
static int clip_grease_pencil_panel_poll(const bContext *UNUSED(C), PanelType *UNUSED(pt))
static int clip_grease_pencil_panel_poll(const bContext *C, PanelType *UNUSED(pt))
{
return TRUE;
SpaceClip *sc = CTX_wm_space_clip(C);
return sc->view == SC_VIEW_CLIP;
}
void ED_clip_buttons_register(ARegionType *art)

@ -0,0 +1,377 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2012 Blender Foundation.
* All rights reserved.
*
*
* Contributor(s): Blender Foundation,
* Sergey Sharybin
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/editors/space_clip/clip_graph_draw.c
* \ingroup spclip
*/
#include "DNA_movieclip_types.h"
#include "DNA_object_types.h" /* SELECT */
#include "DNA_scene_types.h"
#include "MEM_guardedalloc.h"
#include "BKE_context.h"
#include "BKE_movieclip.h"
#include "BKE_tracking.h"
#include "BLI_utildefines.h"
#include "BLI_math.h"
#include "BLI_string.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "ED_screen.h"
#include "ED_clip.h"
#include "BIF_gl.h"
#include "BIF_glutil.h"
#include "WM_types.h"
#include "UI_interface.h"
#include "UI_resources.h"
#include "UI_view2d.h"
#include "BLF_api.h"
#include "RNA_access.h"
#include "clip_intern.h" // own include
static void track_channel_color(MovieTrackingTrack *track, float default_color[3], float color[3])
{
if (track->flag & TRACK_CUSTOMCOLOR) {
float bg[3];
UI_GetThemeColor3fv(TH_HEADER, bg);
interp_v3_v3v3(color, track->color, bg, 0.5);
}
else {
if (default_color)
copy_v3_v3(color, default_color);
else
UI_GetThemeColor3fv(TH_HEADER, color);
}
}
static void draw_keyframe_shape(float x, float y, float xscale, float yscale, short sel, float alpha)
{
/* coordinates for diamond shape */
static const float _unit_diamond_shape[4][2] = {
{0.0f, 1.0f}, /* top vert */
{1.0f, 0.0f}, /* mid-right */
{0.0f, -1.0f}, /* bottom vert */
{-1.0f, 0.0f} /* mid-left */
};
static GLuint displist1 = 0;
static GLuint displist2 = 0;
int hsize = STRIP_HEIGHT_HALF;
/* initialize 2 display lists for diamond shape - one empty, one filled */
if (displist1 == 0) {
displist1 = glGenLists(1);
glNewList(displist1, GL_COMPILE);
glBegin(GL_LINE_LOOP);
glVertex2fv(_unit_diamond_shape[0]);
glVertex2fv(_unit_diamond_shape[1]);
glVertex2fv(_unit_diamond_shape[2]);
glVertex2fv(_unit_diamond_shape[3]);
glEnd();
glEndList();
}
if (displist2 == 0) {
displist2 = glGenLists(1);
glNewList(displist2, GL_COMPILE);
glBegin(GL_QUADS);
glVertex2fv(_unit_diamond_shape[0]);
glVertex2fv(_unit_diamond_shape[1]);
glVertex2fv(_unit_diamond_shape[2]);
glVertex2fv(_unit_diamond_shape[3]);
glEnd();
glEndList();
}
glPushMatrix();
/* adjust view transform before starting */
glTranslatef(x, y, 0.0f);
glScalef(1.0f/xscale*hsize, 1.0f/yscale*hsize, 1.0f);
/* anti-aliased lines for more consistent appearance */
glEnable(GL_LINE_SMOOTH);
if (sel)
UI_ThemeColorShadeAlpha(TH_STRIP_SELECT, 50, -255*(1.0f-alpha));
else
glColor4f(0.91f, 0.91f, 0.91f, alpha);
glCallList(displist2);
/* exterior - black frame */
glColor4f(0.0f, 0.0f, 0.0f, alpha);
glCallList(displist1);
glDisable(GL_LINE_SMOOTH);
/* restore view transform */
glPopMatrix();
}
void clip_draw_dopesheet_main(SpaceClip *sc, ARegion *ar, Scene *scene)
{
MovieClip *clip = ED_space_clip(sc);
View2D *v2d = &ar->v2d;
/* frame range */
clip_draw_sfra_efra(v2d, scene);
if (clip) {
MovieTracking *tracking = &clip->tracking;
MovieTrackingDopesheet *dopesheet = &tracking->dopesheet;
MovieTrackingDopesheetChannel *channel;
float y, xscale, yscale;
float strip[4], selected_strip[4];
y = (float) CHANNEL_FIRST;
UI_view2d_getscale(v2d, &xscale, &yscale);
/* setup colors for regular and selected strips */
UI_GetThemeColor3fv(TH_STRIP, strip);
UI_GetThemeColor3fv(TH_STRIP_SELECT, selected_strip);
strip[3] = 0.5f;
selected_strip[3] = 1.0f;
glEnable(GL_BLEND);
for (channel = dopesheet->channels.first; channel; channel = channel->next) {
float yminc = (float) (y - CHANNEL_HEIGHT_HALF);
float ymaxc = (float) (y + CHANNEL_HEIGHT_HALF);
/* check if visible */
if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax))
{
MovieTrackingTrack *track = channel->track;
float alpha;
int i, sel = track->flag & TRACK_DOPE_SEL;
/* selection background */
if (sel) {
float color[4] = {0.0f, 0.0f, 0.0f, 0.3f};
float default_color[4] = {0.8f, 0.93f, 0.8f, 0.3f};
track_channel_color(track, default_color, color);
glColor4fv(color);
glRectf(v2d->cur.xmin, (float) y - CHANNEL_HEIGHT_HALF,
v2d->cur.xmax + EXTRA_SCROLL_PAD, (float) y + CHANNEL_HEIGHT_HALF);
}
alpha = (track->flag & TRACK_LOCKED) ? 0.5f : 1.0f;
/* tracked segments */
i = 0;
while (i < track->markersnr) {
MovieTrackingMarker *marker = &track->markers[i];
if ((marker->flag & MARKER_DISABLED) == 0) {
MovieTrackingMarker *start_marker = marker;
int prev_fra = marker->framenr, len = 0;
i++;
while (i < track->markersnr) {
marker = &track->markers[i];
if (marker->framenr != prev_fra + 1)
break;
if (marker->flag & MARKER_DISABLED)
break;
prev_fra = marker->framenr;
len++;
i++;
}
if (sel)
glColor4fv(selected_strip);
else
glColor4fv(strip);
if (len) {
glRectf(start_marker->framenr, (float) y - STRIP_HEIGHT_HALF,
start_marker->framenr + len, (float) y + STRIP_HEIGHT_HALF);
draw_keyframe_shape(start_marker->framenr, y, xscale, yscale, sel, alpha);
draw_keyframe_shape(start_marker->framenr + len, y, xscale, yscale, sel, alpha);
}
else {
draw_keyframe_shape(start_marker->framenr, y, xscale, yscale, sel, alpha);
}
}
i++;
}
/* keyframes */
i = 0;
while (i < track->markersnr) {
MovieTrackingMarker *marker = &track->markers[i];
if ((marker->flag & (MARKER_DISABLED | MARKER_TRACKED)) == 0)
draw_keyframe_shape(marker->framenr, y, xscale, yscale, sel, alpha);
i++;
}
}
/* adjust y-position for next one */
y -= CHANNEL_STEP;
}
glDisable(GL_BLEND);
}
/* current frame */
clip_draw_cfra(sc, ar, scene);
}
void clip_draw_dopesheet_channels(const bContext *C, ARegion *ar)
{
ScrArea *sa = CTX_wm_area(C);
SpaceClip *sc = CTX_wm_space_clip(C);
View2D *v2d = &ar->v2d;
MovieClip *clip = ED_space_clip(sc);
MovieTracking *tracking;
MovieTrackingDopesheet *dopesheet;
MovieTrackingDopesheetChannel *channel;
uiStyle *style = UI_GetStyle();
uiBlock *block;
int fontid = style->widget.uifont_id;
int height;
float y;
if (!clip)
return;
tracking = &clip->tracking;
dopesheet = &tracking->dopesheet;
height = (dopesheet->tot_channel * CHANNEL_STEP) + (CHANNEL_HEIGHT * 2);
if (height > (v2d->mask.ymax - v2d->mask.ymin)) {
/* don't use totrect set, as the width stays the same
* (NOTE: this is ok here, the configuration is pretty straightforward)
*/
v2d->tot.ymin = (float)(-height);
}
/* need to do a view-sync here, so that the keys area doesn't jump around (it must copy this) */
UI_view2d_sync(NULL, sa, v2d, V2D_LOCK_COPY);
/* loop through channels, and set up drawing depending on their type
* first pass: just the standard GL-drawing for backdrop + text
*/
y = (float) CHANNEL_FIRST;
BLF_size(fontid, 11.0f, U.dpi);
for (channel = dopesheet->channels.first; channel; channel = channel->next) {
float yminc = (float) (y - CHANNEL_HEIGHT_HALF);
float ymaxc = (float) (y + CHANNEL_HEIGHT_HALF);
/* check if visible */
if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax))
{
MovieTrackingTrack *track = channel->track;
float font_height, color[3];
int sel = track->flag & TRACK_DOPE_SEL;
track_channel_color(track, NULL, color);
glColor3fv(color);
glRectf(v2d->cur.xmin, (float) y - CHANNEL_HEIGHT_HALF,
v2d->cur.xmax + EXTRA_SCROLL_PAD, (float) y + CHANNEL_HEIGHT_HALF);
if (sel)
UI_ThemeColor(TH_TEXT_HI);
else
UI_ThemeColor(TH_TEXT);
font_height = BLF_height(fontid, track->name);
BLF_position(fontid, v2d->cur.xmin + CHANNEL_PAD,
y - font_height / 2.0f, 0.0f);
BLF_draw(fontid, track->name, strlen(track->name));
}
/* adjust y-position for next one */
y -= CHANNEL_STEP;
}
/* second pass: widgets */
block = uiBeginBlock(C, ar, __func__, UI_EMBOSS);
y = (float) CHANNEL_FIRST;
glEnable(GL_BLEND);
for (channel = dopesheet->channels.first; channel; channel = channel->next) {
float yminc = (float)(y - CHANNEL_HEIGHT_HALF);
float ymaxc = (float)(y + CHANNEL_HEIGHT_HALF);
/* check if visible */
if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) ||
IN_RANGE(ymaxc, v2d->cur.ymin, v2d->cur.ymax))
{
MovieTrackingTrack *track = channel->track;
uiBut *but;
PointerRNA ptr;
int icon;
RNA_pointer_create(&clip->id, &RNA_MovieTrackingTrack, track, &ptr);
if (track->flag & TRACK_LOCKED)
icon = ICON_LOCKED;
else
icon = ICON_UNLOCKED;
uiBlockSetEmboss(block, UI_EMBOSSN);
but = uiDefIconButR(block, ICONTOG, 1, icon,
v2d->cur.xmax - UI_UNIT_X - CHANNEL_PAD, y - UI_UNIT_Y / 2.0f,
UI_UNIT_X, UI_UNIT_Y, &ptr, "lock", 0, 0, 0, 0, 0, NULL);
uiBlockSetEmboss(block, UI_EMBOSS);
}
/* adjust y-position for next one */
y -= CHANNEL_STEP;
}
glDisable(GL_BLEND);
uiEndBlock(C, block);
uiDrawBlock(C, block);
}

@ -0,0 +1,139 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2012 Blender Foundation.
* All rights reserved.
*
*
* Contributor(s): Blender Foundation,
* Sergey Sharybin
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/editors/space_clip/clip_graph_ops.c
* \ingroup spclip
*/
#include "DNA_object_types.h" /* SELECT */
#include "DNA_scene_types.h"
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
#include "BLI_math.h"
#include "BLI_listbase.h"
#include "BLI_rect.h"
#include "BKE_context.h"
#include "BKE_movieclip.h"
#include "BKE_tracking.h"
#include "BKE_depsgraph.h"
#include "WM_api.h"
#include "WM_types.h"
#include "ED_screen.h"
#include "ED_clip.h"
#include "UI_interface.h"
#include "RNA_access.h"
#include "RNA_define.h"
#include "UI_view2d.h"
#include "clip_intern.h" // own include
/********************** select channel operator *********************/
static int dopesheet_select_channel_poll(bContext *C)
{
SpaceClip *sc = CTX_wm_space_clip(C);
if (sc && sc->clip)
return sc->view == SC_VIEW_DOPESHEET;
return FALSE;
}
static int dopesheet_select_channel_exec(bContext *C, wmOperator *op)
{
SpaceClip *sc = CTX_wm_space_clip(C);
MovieClip *clip = ED_space_clip(sc);
MovieTracking *tracking = &clip->tracking;
MovieTrackingDopesheet *dopesheet = &tracking->dopesheet;
MovieTrackingDopesheetChannel *channel;
float location[2];
int extend = RNA_boolean_get(op->ptr, "extend");
int current_channel_index = 0, channel_index;
RNA_float_get_array(op->ptr, "location", location);
channel_index = -(location[1] - (CHANNEL_FIRST + CHANNEL_HEIGHT_HALF)) / CHANNEL_STEP;
for (channel = dopesheet->channels.first; channel; channel = channel->next) {
MovieTrackingTrack *track = channel->track;
if (current_channel_index == channel_index) {
if (extend)
track->flag ^= TRACK_DOPE_SEL;
else
track->flag |= TRACK_DOPE_SEL;
}
else if (!extend)
track->flag &= ~TRACK_DOPE_SEL;
current_channel_index++;
}
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
return OPERATOR_FINISHED;
}
static int dopesheet_select_channel_invoke(bContext *C, wmOperator *op, wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
float location[2];
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &location[0], &location[1]);
RNA_float_set_array(op->ptr, "location", location);
return dopesheet_select_channel_exec(C, op);
}
void CLIP_OT_dopesheet_select_channel(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Select Channel";
ot->description = "Select movie tracking channel";
ot->idname = "CLIP_OT_dopesheet_select_channel";
/* api callbacks */
ot->invoke = dopesheet_select_channel_invoke;
ot->exec = dopesheet_select_channel_exec;
ot->poll = dopesheet_select_channel_poll;
/* flags */
ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
/* properties */
RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
"Location", "Mouse location to select channel", -100.0f, 100.0f);
RNA_def_boolean(ot->srna, "extend", 0,
"Extend", "Extend selection rather than clearing the existing selection");
}

@ -118,13 +118,38 @@ int ED_space_clip_tracking_frame_poll(bContext *C)
/* ******** editing functions ******** */
void ED_space_clip_set(bContext *C, SpaceClip *sc, MovieClip *clip)
void ED_space_clip_set(bContext *C, bScreen *screen, SpaceClip *sc, MovieClip *clip)
{
MovieClip *old_clip;
if (!screen && C)
screen = CTX_wm_screen(C);
old_clip = sc->clip;
sc->clip = clip;
if (sc->clip && sc->clip->id.us==0)
sc->clip->id.us = 1;
if (screen) {
ScrArea *area;
SpaceLink *sl;
for (area = screen->areabase.first; area; area = area->next) {
for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_CLIP) {
SpaceClip *cur_sc = (SpaceClip *) sl;
if (cur_sc != sc) {
if (cur_sc->clip == old_clip || cur_sc->clip == NULL) {
cur_sc->clip = clip;
}
}
}
}
}
}
if (C)
WM_event_add_notifier(C, NC_MOVIECLIP|NA_SELECTED, sc->clip);
}
@ -516,3 +541,11 @@ int ED_space_clip_show_trackedit(SpaceClip *sc)
return FALSE;
}
void ED_space_clip_update_dopesheet(SpaceClip *sc)
{
MovieClip *clip = sc->clip;
MovieTracking *tracking = &clip->tracking;
BKE_tracking_update_dopesheet(tracking);
}

@ -64,9 +64,13 @@
static int ED_space_clip_graph_poll(bContext *C)
{
if (ED_space_clip_tracking_poll(C)) {
ARegion *ar = CTX_wm_region(C);
SpaceClip *sc = CTX_wm_space_clip(C);
return ar->regiontype == RGN_TYPE_PREVIEW;
if (sc->view == SC_VIEW_GRAPH) {
ARegion *ar = CTX_wm_region(C);
return ar->regiontype == RGN_TYPE_PREVIEW;
}
}
return FALSE;
@ -225,16 +229,10 @@ static int mouse_select_curve(bContext *C, float co[2], int extend)
}
}
else if (act_track != userdata.track) {
MovieTrackingMarker *marker;
SelectUserData selectdata = {SEL_DESELECT};
tracking->act_track = userdata.track;
/* make active track be centered to screen */
marker = BKE_tracking_get_marker(userdata.track, sc->user.framenr);
clip_view_center_to_point(sc, marker->pos[0], marker->pos[1]);
/* deselect all knots on newly selected curve */
clip_graph_tracking_iterate(sc, &selectdata, toggle_selection_cb);
}

@ -42,11 +42,32 @@ struct ScrArea;
struct SpaceClip;
struct wmOperatorType;
/* channel heights */
#define CHANNEL_FIRST -UI_UNIT_Y
#define CHANNEL_HEIGHT UI_UNIT_Y
#define CHANNEL_HEIGHT_HALF (UI_UNIT_Y / 2.0f)
#define CHANNEL_SKIP 2
#define CHANNEL_STEP (CHANNEL_HEIGHT + CHANNEL_SKIP)
#define CHANNEL_PAD 4
/* extra padding for lengths (to go under scrollers) */
#define EXTRA_SCROLL_PAD 100.0f
#define STRIP_HEIGHT_HALF 5
/* internal exports only */
/* clip_buttons.c */
void ED_clip_buttons_register(struct ARegionType *art);
/* clip_dopesheet_draw.c */
void clip_draw_dopesheet_main(struct SpaceClip *sc, struct ARegion *ar, struct Scene *scene);
void clip_draw_dopesheet_channels(const struct bContext *C, struct ARegion *ar);
/* clip_dopesheet_ops.c */
void CLIP_OT_dopesheet_select_channel(struct wmOperatorType *ot);
/* clip_draw.c */
void clip_draw_main(struct SpaceClip *sc, struct ARegion *ar, struct Scene *scene);
void clip_draw_grease_pencil(struct bContext *C, int onlyv2d);

@ -147,6 +147,7 @@ static int open_cancel(bContext *UNUSED(C), wmOperator *op)
static int open_exec(bContext *C, wmOperator *op)
{
SpaceClip *sc = CTX_wm_space_clip(C);
bScreen *screen = CTX_wm_screen(C);
PropertyPointerRNA *pprop;
PointerRNA idptr;
MovieClip *clip = NULL;
@ -184,7 +185,7 @@ static int open_exec(bContext *C, wmOperator *op)
RNA_property_update(C, &pprop->ptr, pprop->prop);
}
else if (sc) {
ED_space_clip_set(C, sc, clip);
ED_space_clip_set(C, screen, sc, clip);
}
WM_event_add_notifier(C, NC_MOVIECLIP|NA_ADDED, clip);

@ -72,28 +72,76 @@
static void init_preview_region(const bContext *C, ARegion *ar)
{
Scene *scene = CTX_data_scene(C);
ScrArea *sa = CTX_wm_area(C);
SpaceClip *sc = CTX_wm_space_clip(C);
ar->regiontype = RGN_TYPE_PREVIEW;
ar->alignment = RGN_ALIGN_TOP;
ar->flag |= RGN_FLAG_HIDDEN;
ar->v2d.tot.xmin = 0.0f;
ar->v2d.tot.ymin = -10.0f;
ar->v2d.tot.xmax = (float)scene->r.efra;
ar->v2d.tot.ymax = 10.0f;
if (sc->view == SC_VIEW_DOPESHEET) {
ar->v2d.tot.xmin = -10.0f;
ar->v2d.tot.ymin = (float)(-sa->winy)/3.0f;
ar->v2d.tot.xmax = (float)(sa->winx);
ar->v2d.tot.ymax = 0.0f;
ar->v2d.cur = ar->v2d.tot;
ar->v2d.cur = ar->v2d.tot;
ar->v2d.min[0] = FLT_MIN;
ar->v2d.min[1] = FLT_MIN;
ar->v2d.min[0] = 0.0f;
ar->v2d.min[1] = 0.0f;
ar->v2d.max[0] = MAXFRAMEF;
ar->v2d.max[1] = FLT_MAX;
ar->v2d.max[0] = MAXFRAMEF;
ar->v2d.max[1] = FLT_MAX;
ar->v2d.scroll = (V2D_SCROLL_BOTTOM|V2D_SCROLL_SCALE_HORIZONTAL);
ar->v2d.scroll |= (V2D_SCROLL_LEFT|V2D_SCROLL_SCALE_VERTICAL);
ar->v2d.minzoom = 0.01f;
ar->v2d.maxzoom = 50;
ar->v2d.scroll = (V2D_SCROLL_BOTTOM|V2D_SCROLL_SCALE_HORIZONTAL);
ar->v2d.scroll |= (V2D_SCROLL_RIGHT);
ar->v2d.keepzoom = V2D_LOCKZOOM_Y;
ar->v2d.keepofs = V2D_KEEPOFS_Y;
ar->v2d.align = V2D_ALIGN_NO_POS_Y;
ar->v2d.flag = V2D_VIEWSYNC_AREA_VERTICAL;
}
else {
ar->v2d.tot.xmin = 0.0f;
ar->v2d.tot.ymin = -10.0f;
ar->v2d.tot.xmax = (float)scene->r.efra;
ar->v2d.tot.ymax = 10.0f;
ar->v2d.keeptot = 0;
ar->v2d.cur = ar->v2d.tot;
ar->v2d.min[0] = FLT_MIN;
ar->v2d.min[1] = FLT_MIN;
ar->v2d.max[0] = MAXFRAMEF;
ar->v2d.max[1] = FLT_MAX;
ar->v2d.scroll = (V2D_SCROLL_BOTTOM|V2D_SCROLL_SCALE_HORIZONTAL);
ar->v2d.scroll |= (V2D_SCROLL_LEFT|V2D_SCROLL_SCALE_VERTICAL);
ar->v2d.minzoom = 0.0f;
ar->v2d.maxzoom = 0.0f;
ar->v2d.keepzoom = 0;
ar->v2d.keepofs = 0;
ar->v2d.align = 0;
ar->v2d.flag = 0;
ar->v2d.keeptot = 0;
}
}
static void reinit_preview_region(const bContext *C, ARegion *ar)
{
SpaceClip *sc = CTX_wm_space_clip(C);
if (sc->view == SC_VIEW_DOPESHEET) {
if ((ar->v2d.flag & V2D_VIEWSYNC_AREA_VERTICAL) == 0)
init_preview_region(C, ar);
}
else {
if (ar->v2d.flag & V2D_VIEWSYNC_AREA_VERTICAL)
init_preview_region(C, ar);
}
}
static ARegion *ED_clip_has_preview_region(const bContext *C, ScrArea *sa)
@ -119,6 +167,33 @@ static ARegion *ED_clip_has_preview_region(const bContext *C, ScrArea *sa)
return arnew;
}
static ARegion *ED_clip_has_channels_region(ScrArea *sa)
{
ARegion *ar, *arnew;
ar = BKE_area_find_region_type(sa, RGN_TYPE_CHANNELS);
if (ar)
return ar;
/* add subdiv level; after header */
ar = BKE_area_find_region_type(sa, RGN_TYPE_PREVIEW);
/* is error! */
if (ar == NULL)
return NULL;
arnew = MEM_callocN(sizeof(ARegion), "clip channels region");
BLI_insertlinkbefore(&sa->regionbase, ar, arnew);
arnew->regiontype = RGN_TYPE_CHANNELS;
arnew->alignment = RGN_ALIGN_LEFT;
arnew->v2d.scroll = V2D_SCROLL_BOTTOM;
arnew->v2d.flag = V2D_VIEWSYNC_AREA_VERTICAL;
return arnew;
}
static void clip_scopes_tag_refresh(ScrArea *sa)
{
SpaceClip *sc = (SpaceClip *)sa->spacedata.first;
@ -190,6 +265,16 @@ static SpaceLink *clip_new(const bContext *C)
ar->regiontype = RGN_TYPE_UI;
ar->alignment = RGN_ALIGN_RIGHT;
/* channels view */
ar = MEM_callocN(sizeof(ARegion), "channels for clip");
BLI_addtail(&sc->regionbase, ar);
ar->regiontype = RGN_TYPE_CHANNELS;
ar->alignment = RGN_ALIGN_LEFT;
ar->v2d.scroll = V2D_SCROLL_BOTTOM;
ar->v2d.flag = V2D_VIEWSYNC_AREA_VERTICAL;
/* preview view */
ar = MEM_callocN(sizeof(ARegion), "preview for clip");
@ -214,6 +299,8 @@ static void clip_free(SpaceLink *sl)
if (sc->scopes.track_preview)
IMB_freeImBuf(sc->scopes.track_preview);
ED_space_clip_free_texture_buffer(sc);
}
/* spacetype; init callback */
@ -229,6 +316,7 @@ static SpaceLink *clip_duplicate(SpaceLink *sl)
/* clear or remove stuff from old */
scn->scopes.track_preview = NULL;
scn->scopes.ok = FALSE;
scn->draw_context = NULL;
return (SpaceLink *)scn;
}
@ -391,6 +479,10 @@ static void clip_operatortypes(void)
WM_operatortype_append(CLIP_OT_graph_center_current_frame);
WM_operatortype_append(CLIP_OT_graph_disable_markers);
/* ** clip_dopesheet_ops.c ** */
WM_operatortype_append(CLIP_OT_dopesheet_select_channel);
}
static void clip_keymap(struct wmKeyConfig *keyconf)
@ -609,6 +701,13 @@ static void clip_keymap(struct wmKeyConfig *keyconf)
RNA_enum_set(kmi->ptr, "action", 2); /* toggle */
transform_keymap_for_space(keyconf, keymap, SPACE_CLIP);
/* ******** Hotkeys avalaible for channels region only ******** */
keymap = WM_keymap_find(keyconf, "Clip Dopesheet Editor", SPACE_CLIP, 0);
kmi = WM_keymap_add_item(keymap, "CLIP_OT_dopesheet_select_channel", ACTIONMOUSE, KM_PRESS, 0, 0);
RNA_boolean_set(kmi->ptr, "extend", TRUE); /* toggle */
}
const char *clip_context_dir[]= {"edit_movieclip", NULL};
@ -643,8 +742,9 @@ static void clip_refresh(const bContext *C, ScrArea *sa)
ARegion *ar_tool_props = BKE_area_find_region_type(sa, RGN_TYPE_TOOL_PROPS);
ARegion *ar_preview = ED_clip_has_preview_region(C, sa);
ARegion *ar_properties = ED_clip_has_properties_region(sa);
ARegion *ar_channels = ED_clip_has_channels_region(sa);
int main_visible = FALSE, preview_visible = FALSE, tools_visible = FALSE;
int tool_props_visible = FALSE, properties_visible = FALSE;
int tool_props_visible = FALSE, properties_visible = FALSE, channels_visible = FALSE;
int view_changed = FALSE;
switch (sc->view) {
@ -654,13 +754,27 @@ static void clip_refresh(const bContext *C, ScrArea *sa)
tools_visible = TRUE;
tool_props_visible = TRUE;
properties_visible = TRUE;
channels_visible = FALSE;
break;
case SC_VIEW_GRAPH:
main_visible = TRUE;
main_visible = FALSE;
preview_visible = TRUE;
tools_visible = TRUE;
tool_props_visible = TRUE;
properties_visible = TRUE;
tools_visible = FALSE;
tool_props_visible = FALSE;
properties_visible = FALSE;
channels_visible = FALSE;
reinit_preview_region(C, ar_preview);
break;
case SC_VIEW_DOPESHEET:
main_visible = FALSE;
preview_visible = TRUE;
tools_visible = FALSE;
tool_props_visible = FALSE;
properties_visible = FALSE;
channels_visible = TRUE;
reinit_preview_region(C, ar_preview);
break;
}
@ -768,23 +882,12 @@ static void clip_refresh(const bContext *C, ScrArea *sa)
ar_preview->v2d.cur = ar_preview->v2d.tot;
view_changed = TRUE;
}
if (ar_preview && !ELEM(ar_preview->alignment, RGN_ALIGN_TOP, RGN_ALIGN_BOTTOM)) {
if (sc->runtime_flag & SC_GRAPH_BOTTOM)
ar_preview->alignment = RGN_ALIGN_BOTTOM;
else
ar_preview->alignment = RGN_ALIGN_TOP;
if (ar_preview && ar_preview->alignment != RGN_ALIGN_NONE) {
ar_preview->alignment = RGN_ALIGN_NONE;
view_changed = TRUE;
}
}
else {
/* store graph region align */
if (ar_preview) {
if (ar_preview->alignment == RGN_ALIGN_TOP)
sc->runtime_flag &= ~SC_GRAPH_BOTTOM;
else if (ar_preview->alignment == RGN_ALIGN_BOTTOM)
sc->runtime_flag |= SC_GRAPH_BOTTOM;
}
if (ar_preview && !(ar_preview->flag & RGN_FLAG_HIDDEN)) {
ar_preview->flag |= RGN_FLAG_HIDDEN;
ar_preview->v2d.flag &= ~V2D_IS_INITIALISED;
@ -797,6 +900,30 @@ static void clip_refresh(const bContext *C, ScrArea *sa)
}
}
if (channels_visible) {
if (ar_channels && (ar_channels->flag & RGN_FLAG_HIDDEN)) {
ar_channels->flag &= ~RGN_FLAG_HIDDEN;
ar_channels->v2d.flag &= ~V2D_IS_INITIALISED;
view_changed = TRUE;
}
if (ar_channels && ar_channels->alignment != RGN_ALIGN_LEFT) {
ar_channels->alignment = RGN_ALIGN_LEFT;
view_changed = TRUE;
}
}
else {
if (ar_channels && !(ar_channels->flag & RGN_FLAG_HIDDEN)) {
ar_channels->flag |= RGN_FLAG_HIDDEN;
ar_channels->v2d.flag &= ~V2D_IS_INITIALISED;
WM_event_remove_handlers((bContext *)C, &ar_tools->handlers);
view_changed = TRUE;
}
if (ar_channels && ar_channels->alignment != RGN_ALIGN_NONE) {
ar_channels->alignment = RGN_ALIGN_NONE;
view_changed = TRUE;
}
}
if (view_changed) {
ED_area_initialize(wm, window, sa);
ED_area_tag_redraw(sa);
@ -976,15 +1103,92 @@ static void graph_area_draw(const bContext *C, ARegion *ar)
UI_view2d_scrollers_free(scrollers);
}
static void dopesheet_area_draw(const bContext *C, ARegion *ar)
{
Scene *scene = CTX_data_scene(C);
SpaceClip *sc = CTX_wm_space_clip(C);
View2D *v2d = &ar->v2d;
View2DGrid *grid;
View2DScrollers *scrollers;
short unit = 0;
/* clear and setup matrix */
UI_ThemeClearColor(TH_BACK);
glClear(GL_COLOR_BUFFER_BIT);
UI_view2d_view_ortho(v2d);
/* time grid */
unit = (sc->flag & SC_SHOW_SECONDS)? V2D_UNIT_SECONDS : V2D_UNIT_FRAMES;
grid = UI_view2d_grid_calc(CTX_data_scene(C), v2d, unit, V2D_GRID_CLAMP, V2D_ARG_DUMMY, V2D_ARG_DUMMY, ar->winx, ar->winy);
UI_view2d_grid_draw(v2d, grid, V2D_GRIDLINES_ALL);
UI_view2d_grid_free(grid);
/* data... */
clip_draw_dopesheet_main(sc, ar, scene);
/* reset view matrix */
UI_view2d_view_restore(C);
/* scrollers */
scrollers= UI_view2d_scrollers_calc(C, v2d, unit, V2D_GRID_CLAMP, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
UI_view2d_scrollers_draw(C, v2d, scrollers);
UI_view2d_scrollers_free(scrollers);
}
static void clip_preview_area_draw(const bContext *C, ARegion *ar)
{
graph_area_draw(C, ar);
SpaceClip *sc = CTX_wm_space_clip(C);
if (sc->view == SC_VIEW_GRAPH)
graph_area_draw(C, ar);
else if (sc->view == SC_VIEW_DOPESHEET)
dopesheet_area_draw(C, ar);
}
static void clip_preview_area_listener(ARegion *UNUSED(ar), wmNotifier *UNUSED(wmn))
{
}
/****************** channels region ******************/
static void clip_channels_area_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_LIST, ar->winx, ar->winy);
keymap = WM_keymap_find(wm->defaultconf, "Clip Dopesheet Editor", SPACE_CLIP, 0);
WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
}
static void clip_channels_area_draw(const bContext *C, ARegion *ar)
{
View2D *v2d = &ar->v2d;
View2DScrollers *scrollers;
/* clear and setup matrix */
UI_ThemeClearColor(TH_BACK);
glClear(GL_COLOR_BUFFER_BIT);
UI_view2d_view_ortho(v2d);
/* data... */
clip_draw_dopesheet_channels(C, ar);
/* reset view matrix */
UI_view2d_view_restore(C);
/* scrollers */
scrollers = UI_view2d_scrollers_calc(C, v2d, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
UI_view2d_scrollers_draw(C, v2d, scrollers);
UI_view2d_scrollers_free(scrollers);
}
static void clip_channels_area_listener(ARegion *UNUSED(ar), wmNotifier *UNUSED(wmn))
{
}
/****************** header region ******************/
/* add handlers, stuff you only do once or on area/region changes */
@ -1162,4 +1366,15 @@ void ED_spacetype_clip(void)
BLI_addhead(&st->regiontypes, art);
BKE_spacetype_register(st);
/* channels */
art = MEM_callocN(sizeof(ARegionType), "spacetype clip channels region");
art->regionid = RGN_TYPE_CHANNELS;
art->prefsizex = UI_COMPACT_PANEL_WIDTH;
art->keymapflag = ED_KEYMAP_FRAMES|ED_KEYMAP_UI;
art->listener = clip_channels_area_listener;
art->init = clip_channels_area_init;
art->draw = clip_channels_area_draw;
BLI_addhead(&st->regiontypes, art);
}

@ -95,6 +95,8 @@ static void add_marker(SpaceClip *sc, float x, float y)
BKE_tracking_select_track(tracksbase, track, TRACK_AREA_ALL, 0);
clip->tracking.act_track = track;
ED_space_clip_update_dopesheet(sc);
}
static int add_marker_exec(bContext *C, wmOperator *op)
@ -174,6 +176,8 @@ static int delete_track_exec(bContext *C, wmOperator *UNUSED(op))
/* nothing selected now, unlock view so it can be scrolled nice again */
sc->flag &= ~SC_LOCK_SELECTION;
ED_space_clip_update_dopesheet(sc);
return OPERATOR_FINISHED;
}
@ -225,6 +229,8 @@ static int delete_marker_exec(bContext *C, wmOperator *UNUSED(op))
sc->flag &= ~SC_LOCK_SELECTION;
}
ED_space_clip_update_dopesheet(sc);
return OPERATOR_FINISHED;
}
@ -790,6 +796,7 @@ static int mouse_select(bContext *C, float co[2], int extend)
}
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
ED_space_clip_update_dopesheet(sc);
return OPERATOR_FINISHED;
}
@ -901,6 +908,8 @@ static int border_select_exec(bContext *C, wmOperator *op)
}
if (change) {
ED_space_clip_update_dopesheet(sc);
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
return OPERATOR_FINISHED;
@ -985,6 +994,8 @@ static int circle_select_exec(bContext *C, wmOperator *op)
}
if (change) {
ED_space_clip_update_dopesheet(sc);
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
return OPERATOR_FINISHED;
@ -1081,6 +1092,8 @@ static int select_all_exec(bContext *C, wmOperator *op)
if (!has_selection)
sc->flag &= ~SC_LOCK_SELECTION;
ED_space_clip_update_dopesheet(sc);
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, NULL);
return OPERATOR_FINISHED;
@ -1161,6 +1174,8 @@ static int select_groped_exec(bContext *C, wmOperator *op)
track = track->next;
}
ED_space_clip_update_dopesheet(sc);
WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, clip);
return OPERATOR_FINISHED;
@ -2730,6 +2745,8 @@ static int hide_tracks_exec(bContext *C, wmOperator *op)
sc->flag &= ~SC_LOCK_SELECTION;
}
BKE_tracking_update_dopesheet(tracking);
WM_event_add_notifier(C, NC_MOVIECLIP|ND_DISPLAY, NULL);
return OPERATOR_FINISHED;

@ -520,9 +520,7 @@ typedef struct SpaceClip {
* defined when drawing and used for mouse position calculation */
/* movie postprocessing */
int postproc_flag;
int runtime_flag; /* different runtime flags */
int postproc_flag, pad2;
void *draw_context;
} SpaceClip;
@ -916,6 +914,7 @@ enum {
/* SpaceClip->view */
#define SC_VIEW_CLIP 0
#define SC_VIEW_GRAPH 1
#define SC_VIEW_DOPESHEET 2
/* SpaceClip->runtime_flag */
#define SC_GRAPH_BOTTOM (1<<0)

@ -193,6 +193,17 @@ typedef struct MovieTrackingStats {
char message[256];
} MovieTrackingStats;
typedef struct MovieTrackingDopesheetChannel {
struct MovieTrackingDopesheetChannel *next, *prev;
MovieTrackingTrack *track;
int flag, pad;
} MovieTrackingDopesheetChannel;
typedef struct MovieTrackingDopesheet {
ListBase channels;
int tot_channel, pad;
} MovieTrackingDopesheet;
typedef struct MovieTracking {
MovieTrackingSettings settings; /* different tracking-related settings */
MovieTrackingCamera camera; /* camera intrinsics */
@ -205,6 +216,8 @@ typedef struct MovieTracking {
int objectnr, tot_object; /* index of active object and total number of objects */
MovieTrackingStats *stats; /* statistics displaying in clip editor */
MovieTrackingDopesheet dopesheet; /* dopesheet data */
} MovieTracking;
/* MovieTrackingCamera->units */
@ -230,6 +243,7 @@ enum {
#define TRACK_CUSTOMCOLOR (1<<7)
#define TRACK_USE_2D_STAB (1<<8)
#define TRACK_PREVIEW_GRAYSCALE (1<<9)
#define TRACK_DOPE_SEL (1<<10)
/* MovieTrackingTrack->tracker */
#define TRACKER_KLT 0

@ -337,6 +337,7 @@ extern StructRNA RNA_MotionPathVert;
extern StructRNA RNA_MouseSensor;
extern StructRNA RNA_MovieSequence;
extern StructRNA RNA_MovieClipSequence;
extern StructRNA RNA_MovieTrackingTrack;
extern StructRNA RNA_MovieTrackingObject;
extern StructRNA RNA_MulticamSequence;
extern StructRNA RNA_MultiresModifier;

@ -1024,8 +1024,9 @@ static EnumPropertyItem *rna_SpaceProperties_texture_context_itemf(bContext *C,
static void rna_SpaceClipEditor_clip_set(PointerRNA *ptr, PointerRNA value)
{
SpaceClip *sc = (SpaceClip*)(ptr->data);
bScreen *screen = (bScreen*)ptr->id.data;
ED_space_clip_set(NULL, sc, (MovieClip*)value.data);
ED_space_clip_set(NULL, screen, sc, (MovieClip*)value.data);
}
static void rna_SpaceClipEditor_clip_mode_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
@ -2930,6 +2931,7 @@ static void rna_def_space_clip(BlenderRNA *brna)
static EnumPropertyItem view_items[] = {
{SC_VIEW_CLIP, "CLIP", ICON_SEQUENCE, "Clip", "Show editing clip preview"},
{SC_VIEW_GRAPH, "GRAPH", ICON_IPO, "Graph", "Show graph view for active element"},
{SC_VIEW_DOPESHEET, "DOPESHEET", ICON_ACTION, "Dopesheet", "Dopesheet view for tracking data"},
{0, NULL, 0, NULL, NULL}};
srna = RNA_def_struct(brna, "SpaceClipEditor", "Space");

@ -1997,6 +1997,7 @@ static void rna_def_userdef_theme_space_clip(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Theme Clip Editor", "Theme settings for the Movie Clip Editor");
rna_def_userdef_theme_spaces_main(srna);
rna_def_userdef_theme_spaces_list_main(srna);
prop = RNA_def_property(srna, "marker_outline", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "marker_outline");
@ -2071,6 +2072,18 @@ static void rna_def_userdef_theme_space_clip(BlenderRNA *brna)
RNA_def_property_range(prop, 0, 255);
RNA_def_property_ui_text(prop, "Handle Vertex Size", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
prop = RNA_def_property(srna, "strips", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "strip");
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Strips", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
prop = RNA_def_property(srna, "strips_selected", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "strip_select");
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Strips Selected", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
}
static void rna_def_userdef_themes(BlenderRNA *brna)