2 * ***** BEGIN GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * The Original Code is Copyright (C) 2008 Blender Foundation.
19 * All rights reserved.
22 * Contributor(s): Blender Foundation
24 * ***** END GPL LICENSE BLOCK *****
27 /** \file blender/editors/space_time/space_time.c
35 #include "DNA_cachefile_types.h"
36 #include "DNA_constraint_types.h"
37 #include "DNA_gpencil_types.h"
38 #include "DNA_modifier_types.h"
39 #include "DNA_object_types.h"
40 #include "DNA_scene_types.h"
42 #include "MEM_guardedalloc.h"
44 #include "BLI_blenlib.h"
45 #include "BLI_dlrbTree.h"
46 #include "BLI_utildefines.h"
48 #include "BKE_constraint.h"
49 #include "BKE_context.h"
51 #include "BKE_modifier.h"
52 #include "BKE_screen.h"
53 #include "BKE_pointcache.h"
55 #include "ED_anim_api.h"
56 #include "ED_keyframes_draw.h"
57 #include "ED_screen.h"
64 #include "UI_resources.h"
65 #include "UI_view2d.h"
66 #include "UI_interface.h"
68 #include "ED_space_api.h"
69 #include "ED_markers.h"
71 #include "GPU_immediate.h"
72 #include "GPU_matrix.h"
74 #include "time_intern.h"
76 /* ************************ main time area region *********************** */
78 static void time_draw_sfra_efra(Scene *scene, View2D *v2d)
80 /* draw darkened area outside of active timeline
81 * frame range used is preview range or scene range
83 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
86 Gwn_VertFormat *format = immVertexFormat();
87 unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
89 immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
90 immUniformColor4f(0.0f, 0.0f, 0.0f, 0.4f);
93 immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, (float)PSFRA, v2d->cur.ymax);
94 immRectf(pos, (float)PEFRA, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
97 immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
102 /* thin lines where the actual frames are */
103 immUniformThemeColorShade(TH_BACK, -60);
105 immBegin(GWN_PRIM_LINES, 4);
107 immVertex2f(pos, (float)PSFRA, v2d->cur.ymin);
108 immVertex2f(pos, (float)PSFRA, v2d->cur.ymax);
110 immVertex2f(pos, (float)PEFRA, v2d->cur.ymin);
111 immVertex2f(pos, (float)PEFRA, v2d->cur.ymax);
117 static void time_draw_cache(SpaceTime *stime, Object *ob, Scene *scene)
121 const float cache_draw_height = (4.0f * UI_DPI_FAC * U.pixelsize);
124 if (!(stime->cache_display & TIME_CACHE_DISPLAY) || (!ob))
127 BKE_ptcache_ids_from_object(&pidlist, ob, scene, 0);
129 unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
130 immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
132 /* iterate over pointcaches on the active object,
133 * add spacetimecache and vertex array for each */
134 for (pid = pidlist.first; pid; pid = pid->next) {
138 case PTCACHE_TYPE_SOFTBODY:
139 if (!(stime->cache_display & TIME_CACHE_SOFTBODY)) continue;
141 case PTCACHE_TYPE_PARTICLES:
142 if (!(stime->cache_display & TIME_CACHE_PARTICLES)) continue;
144 case PTCACHE_TYPE_CLOTH:
145 if (!(stime->cache_display & TIME_CACHE_CLOTH)) continue;
147 case PTCACHE_TYPE_SMOKE_DOMAIN:
148 case PTCACHE_TYPE_SMOKE_HIGHRES:
149 if (!(stime->cache_display & TIME_CACHE_SMOKE)) continue;
151 case PTCACHE_TYPE_DYNAMICPAINT:
152 if (!(stime->cache_display & TIME_CACHE_DYNAMICPAINT)) continue;
154 case PTCACHE_TYPE_RIGIDBODY:
155 if (!(stime->cache_display & TIME_CACHE_RIGIDBODY)) continue;
159 if (pid->cache->cached_frames == NULL)
163 gpuTranslate2f(0.0, (float)V2D_SCROLL_HEIGHT + yoffs);
164 gpuScale2f(1.0, cache_draw_height);
167 case PTCACHE_TYPE_SOFTBODY:
168 col[0] = 1.0; col[1] = 0.4; col[2] = 0.02;
171 case PTCACHE_TYPE_PARTICLES:
172 col[0] = 1.0; col[1] = 0.1; col[2] = 0.02;
175 case PTCACHE_TYPE_CLOTH:
176 col[0] = 0.1; col[1] = 0.1; col[2] = 0.75;
179 case PTCACHE_TYPE_SMOKE_DOMAIN:
180 case PTCACHE_TYPE_SMOKE_HIGHRES:
181 col[0] = 0.2; col[1] = 0.2; col[2] = 0.2;
184 case PTCACHE_TYPE_DYNAMICPAINT:
185 col[0] = 1.0; col[1] = 0.1; col[2] = 0.75;
188 case PTCACHE_TYPE_RIGIDBODY:
189 col[0] = 1.0; col[1] = 0.6; col[2] = 0.0;
193 col[0] = 1.0; col[1] = 0.0; col[2] = 1.0;
199 const int sta = pid->cache->startframe, end = pid->cache->endframe;
200 const int len = (end - sta + 1) * 6;
204 immUniformColor4fv(col);
205 immRectf(pos, (float)sta, 0.0, (float)end, 1.0);
208 if (pid->cache->flag & PTCACHE_BAKED) {
209 col[0] -= 0.4f; col[1] -= 0.4f; col[2] -= 0.4f;
211 else if (pid->cache->flag & PTCACHE_OUTDATED) {
212 col[0] += 0.4f; col[1] += 0.4f; col[2] += 0.4f;
215 immUniformColor4fv(col);
218 immBeginAtMost(GWN_PRIM_TRIS, len);
220 /* draw a quad for each cached frame */
221 for (int i = sta; i <= end; i++) {
222 if (pid->cache->cached_frames[i - sta]) {
223 immVertex2f(pos, (float)i - 0.5f, 0.0f);
224 immVertex2f(pos, (float)i - 0.5f, 1.0f);
225 immVertex2f(pos, (float)i + 0.5f, 1.0f);
227 immVertex2f(pos, (float)i - 0.5f, 0.0f);
228 immVertex2f(pos, (float)i + 0.5f, 1.0f);
229 immVertex2f(pos, (float)i + 0.5f, 0.0f);
240 yoffs += cache_draw_height;
245 BLI_freelistN(&pidlist);
248 /* helper function - find actkeycolumn that occurs on cframe, or the nearest one if not found */
249 static ActKeyColumn *time_cfra_find_ak(ActKeyColumn *ak, float cframe)
251 ActKeyColumn *akn = NULL;
257 /* check if this is a match, or whether it is in some subtree */
258 if (cframe < ak->cfra)
259 akn = time_cfra_find_ak(ak->left, cframe);
260 else if (cframe > ak->cfra)
261 akn = time_cfra_find_ak(ak->right, cframe);
263 /* if no match found (or found match), just use the current one */
270 /* helper for time_draw_keyframes() */
271 static void time_draw_idblock_keyframes(View2D *v2d, ID *id, short onlysel, const unsigned char color[3])
273 bDopeSheet ads = {NULL};
277 float fac1 = (GS(id->name) == ID_GD) ? 0.8f : 0.6f; /* draw GPencil keys taller, to help distinguish them */
278 float fac2 = 1.0f - fac1;
280 float ymin = v2d->tot.ymin;
281 float ymax = v2d->tot.ymax * fac1 + ymin * fac2;
283 /* init binarytree-list for getting keyframes */
284 BLI_dlrbTree_init(&keys);
286 /* init dopesheet settings */
288 ads.filterflag |= ADS_FILTER_ONLYSEL;
290 /* populate tree with keyframe nodes */
291 switch (GS(id->name)) {
293 scene_to_keylist(&ads, (Scene *)id, &keys, NULL);
296 ob_to_keylist(&ads, (Object *)id, &keys, NULL);
299 gpencil_to_keylist(&ads, (bGPdata *)id, &keys);
302 cachefile_to_keylist(&ads, (CacheFile *)id, &keys, NULL);
308 /* build linked-list for searching */
309 BLI_dlrbTree_linkedlist_sync(&keys);
311 /* start drawing keyframes
312 * - we use the binary-search capabilities of the tree to only start from
313 * the first visible keyframe (last one can then be easily checked)
314 * - draw within a single GL block to be faster
320 ak = time_cfra_find_ak(keys.root, v2d->cur.xmin);
322 for (link = ak; link; link = link->next) {
328 Gwn_VertFormat *format = immVertexFormat();
329 unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
331 immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
332 immUniformColor3ubv(color);
334 immBeginAtMost(GWN_PRIM_LINES, max_len * 2);
336 for (; (ak) && (ak->cfra <= v2d->cur.xmax);
339 immVertex2f(pos, ak->cfra, ymin);
340 immVertex2f(pos, ak->cfra, ymax);
347 /* free temp stuff */
348 BLI_dlrbTree_free(&keys);
351 static void time_draw_caches_keyframes(Main *bmain, SceneLayer *sl, View2D *v2d, bool onlysel, const unsigned char color[3])
353 CacheFile *cache_file;
355 for (cache_file = bmain->cachefiles.first;
357 cache_file = cache_file->id.next)
359 cache_file->draw_flag &= ~CACHEFILE_KEYFRAME_DRAWN;
362 for (Base *base = sl->object_bases.first; base; base = base->next) {
363 Object *ob = base->object;
365 ModifierData *md = modifiers_findByType(ob, eModifierType_MeshSequenceCache);
368 MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
370 cache_file = mcmd->cache_file;
372 if (!cache_file || (cache_file->draw_flag & CACHEFILE_KEYFRAME_DRAWN) != 0) {
376 cache_file->draw_flag |= CACHEFILE_KEYFRAME_DRAWN;
378 time_draw_idblock_keyframes(v2d, (ID *)cache_file, onlysel, color);
381 for (bConstraint *con = ob->constraints.first; con; con = con->next) {
382 if (con->type != CONSTRAINT_TYPE_TRANSFORM_CACHE) {
386 bTransformCacheConstraint *data = con->data;
388 cache_file = data->cache_file;
390 if (!cache_file || (cache_file->draw_flag & CACHEFILE_KEYFRAME_DRAWN) != 0) {
394 cache_file->draw_flag |= CACHEFILE_KEYFRAME_DRAWN;
396 time_draw_idblock_keyframes(v2d, (ID *)cache_file, onlysel, color);
401 /* draw keyframe lines for timeline */
402 static void time_draw_keyframes(const bContext *C, ARegion *ar)
404 Scene *scene = CTX_data_scene(C);
405 SceneLayer *sl = CTX_data_scene_layer(C);
406 Object *ob = CTX_data_active_object(C);
407 View2D *v2d = &ar->v2d;
408 bool onlysel = ((scene->flag & SCE_KEYS_NO_SELONLY) == 0);
409 unsigned char color[3];
411 /* set this for all keyframe lines once and for all */
414 /* draw cache files keyframes (if available) */
415 UI_GetThemeColor3ubv(TH_TIME_KEYFRAME, color);
416 time_draw_caches_keyframes(CTX_data_main(C), sl, v2d, onlysel, color);
418 /* draw grease pencil keyframes (if available) */
419 UI_GetThemeColor3ubv(TH_TIME_GP_KEYFRAME, color);
422 time_draw_idblock_keyframes(v2d, (ID *)scene->gpd, onlysel, color);
425 time_draw_idblock_keyframes(v2d, (ID *)ob->gpd, onlysel, color);
428 /* draw scene keyframes first
429 * - don't try to do this when only drawing active/selected data keyframes,
430 * since this can become quite slow
434 UI_GetThemeColorShade3ubv(TH_TIME_KEYFRAME, -50, color);
435 time_draw_idblock_keyframes(v2d, (ID *)scene, onlysel, color);
438 /* draw keyframes from selected objects
439 * - only do the active object if in posemode (i.e. showing only keyframes for the bones)
440 * OR the onlysel flag was set, which means that only active object's keyframes should
443 UI_GetThemeColor3ubv(TH_TIME_KEYFRAME, color);
445 if (ob && ((ob->mode == OB_MODE_POSE) || onlysel)) {
446 /* draw keyframes for active object only */
447 time_draw_idblock_keyframes(v2d, (ID *)ob, onlysel, color);
450 bool active_done = false;
452 /* draw keyframes from all selected objects */
453 CTX_DATA_BEGIN (C, Object *, obsel, selected_objects)
455 /* last arg is 0, since onlysel doesn't apply here... */
456 time_draw_idblock_keyframes(v2d, (ID *)obsel, 0, color);
458 /* if this object is the active one, set flag so that we don't draw again */
464 /* if active object hasn't been done yet, draw it... */
465 if (ob && (active_done == 0))
466 time_draw_idblock_keyframes(v2d, (ID *)ob, 0, color);
470 /* ---------------- */
472 /* editor level listener */
473 static void time_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn, const Scene *UNUSED(scene))
476 /* mainly for updating cache display */
477 switch (wmn->category) {
487 ED_area_tag_refresh(sa);
488 ED_area_tag_redraw(sa);
496 case ND_RENDER_RESULT:
497 ED_area_tag_redraw(sa);
501 ED_area_tag_refresh(sa);
506 Scene *scene = wmn->reference;
508 for (ar = sa->regionbase.first; ar; ar = ar->next) {
509 if (ar->regiontype == RGN_TYPE_WINDOW) {
510 ar->v2d.tot.xmin = (float)(SFRA - 4);
511 ar->v2d.tot.xmax = (float)(EFRA + 4);
523 case ND_SPACE_CHANGED:
524 ED_area_tag_refresh(sa);
533 ED_area_tag_refresh(sa);
541 /* ---------------- */
543 /* add handlers, stuff you only do once or on area/region changes */
544 static void time_main_region_init(wmWindowManager *wm, ARegion *ar)
548 UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy);
551 keymap = WM_keymap_find(wm->defaultconf, "Timeline", SPACE_TIME, 0);
552 WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
555 static void time_main_region_draw(const bContext *C, ARegion *ar)
557 /* draw entirely, view changes should be handled here */
558 Scene *scene = CTX_data_scene(C);
559 SpaceTime *stime = CTX_wm_space_time(C);
560 Object *obact = CTX_data_active_object(C);
561 View2D *v2d = &ar->v2d;
563 View2DScrollers *scrollers;
566 /* clear and setup matrix */
567 UI_ThemeClearColor(TH_BACK);
568 glClear(GL_COLOR_BUFFER_BIT);
570 UI_view2d_view_ortho(v2d);
573 unit = (stime->flag & TIME_DRAWFRAMES) ? V2D_UNIT_FRAMES : V2D_UNIT_SECONDS;
574 grid = UI_view2d_grid_calc(scene, v2d, unit, V2D_GRID_CLAMP, V2D_ARG_DUMMY, V2D_ARG_DUMMY, ar->winx, ar->winy);
575 UI_view2d_grid_draw(v2d, grid, (V2D_VERTICAL_LINES | V2D_VERTICAL_AXIS));
576 UI_view2d_grid_free(grid);
578 ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW);
580 /* start and end frame */
581 time_draw_sfra_efra(scene, v2d);
584 flag = DRAWCFRA_WIDE; /* this is only really needed on frames where there's a keyframe, but this will do... */
585 if ((stime->flag & TIME_DRAWFRAMES) == 0) flag |= DRAWCFRA_UNIT_SECONDS;
586 if (stime->flag & TIME_CFRA_NUM) flag |= DRAWCFRA_SHOW_NUMBOX;
587 ANIM_draw_cfra(C, v2d, flag);
589 UI_view2d_view_ortho(v2d);
592 time_draw_keyframes(C, ar);
595 UI_view2d_view_orthoSpecial(ar, v2d, 1);
596 ED_markers_draw(C, 0);
599 time_draw_cache(stime, obact, scene);
602 UI_view2d_view_ortho(v2d);
603 ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW);
605 /* reset view matrix */
606 UI_view2d_view_restore(C);
609 scrollers = UI_view2d_scrollers_calc(C, v2d, unit, V2D_GRID_CLAMP, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
610 UI_view2d_scrollers_draw(C, v2d, scrollers);
611 UI_view2d_scrollers_free(scrollers);
614 static void time_main_region_listener(
615 bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
616 wmNotifier *wmn, const Scene *UNUSED(scene))
618 /* context changes */
619 switch (wmn->category) {
621 if (wmn->data == ND_SPACE_TIME)
622 ED_region_tag_redraw(ar);
626 ED_region_tag_redraw(ar);
636 case ND_RENDER_OPTIONS:
637 ED_region_tag_redraw(ar);
642 if (wmn->data == ND_DATA)
643 ED_region_tag_redraw(ar);
646 if (ELEM(wmn->data, ND_LAYER)) {
647 ED_region_tag_redraw(ar);
653 /* ************************ header time area region *********************** */
655 /* add handlers, stuff you only do once or on area/region changes */
656 static void time_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar)
658 ED_region_header_init(ar);
661 static void time_header_region_draw(const bContext *C, ARegion *ar)
663 ED_region_header(C, ar);
666 static void time_header_region_listener(
667 bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
668 wmNotifier *wmn, const Scene *UNUSED(scene))
670 /* context changes */
671 switch (wmn->category) {
674 if (wmn->data == ND_ANIMPLAY)
675 ED_region_tag_redraw(ar);
681 case ND_RENDER_RESULT:
686 case ND_RENDER_OPTIONS:
687 ED_region_tag_redraw(ar);
694 if (wmn->data == ND_SPACE_TIME)
695 ED_region_tag_redraw(ar);
701 /* ******************** default callbacks for time space ***************** */
703 static SpaceLink *time_new(const bContext *C)
705 Scene *scene = CTX_data_scene(C);
709 stime = MEM_callocN(sizeof(SpaceTime), "inittime");
711 stime->spacetype = SPACE_TIME;
712 stime->flag |= TIME_DRAWFRAMES;
715 ar = MEM_callocN(sizeof(ARegion), "header for time");
717 BLI_addtail(&stime->regionbase, ar);
718 ar->regiontype = RGN_TYPE_HEADER;
719 ar->alignment = RGN_ALIGN_BOTTOM;
722 ar = MEM_callocN(sizeof(ARegion), "main region for time");
724 BLI_addtail(&stime->regionbase, ar);
725 ar->regiontype = RGN_TYPE_WINDOW;
727 ar->v2d.tot.xmin = (float)(SFRA - 4);
728 ar->v2d.tot.ymin = 0.0f;
729 ar->v2d.tot.xmax = (float)(EFRA + 4);
730 ar->v2d.tot.ymax = 50.0f;
732 ar->v2d.cur = ar->v2d.tot;
734 ar->v2d.min[0] = 1.0f;
735 ar->v2d.min[1] = 50.0f;
737 ar->v2d.max[0] = MAXFRAMEF;
738 ar->v2d.max[1] = 50.0;
740 ar->v2d.minzoom = 0.1f;
741 ar->v2d.maxzoom = 10.0;
743 ar->v2d.scroll |= (V2D_SCROLL_BOTTOM | V2D_SCROLL_SCALE_HORIZONTAL);
744 ar->v2d.align |= V2D_ALIGN_NO_NEG_Y;
745 ar->v2d.keepofs |= V2D_LOCKOFS_Y;
746 ar->v2d.keepzoom |= V2D_LOCKZOOM_Y;
749 return (SpaceLink *)stime;
752 /* spacetype; init callback in ED_area_initialize() */
753 /* init is called to (re)initialize an existing editor (file read, screen changes) */
754 /* validate spacedata, add own area level handlers */
755 static void time_init(wmWindowManager *UNUSED(wm), ScrArea *sa)
757 SpaceTime *stime = (SpaceTime *)sa->spacedata.first;
759 /* enable all cache display */
760 stime->cache_display |= TIME_CACHE_DISPLAY;
761 stime->cache_display |= (TIME_CACHE_SOFTBODY | TIME_CACHE_PARTICLES);
762 stime->cache_display |= (TIME_CACHE_CLOTH | TIME_CACHE_SMOKE | TIME_CACHE_DYNAMICPAINT);
763 stime->cache_display |= TIME_CACHE_RIGIDBODY;
766 static SpaceLink *time_duplicate(SpaceLink *sl)
768 SpaceTime *stime = (SpaceTime *)sl;
769 SpaceTime *stimen = MEM_dupallocN(stime);
771 BLI_listbase_clear(&stimen->caches);
773 return (SpaceLink *)stimen;
776 /* only called once, from space_api/spacetypes.c */
777 /* it defines all callbacks to maintain spaces */
778 void ED_spacetype_time(void)
780 SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype time");
783 st->spaceid = SPACE_TIME;
784 strncpy(st->name, "Timeline", BKE_ST_MAXNAME);
787 st->init = time_init;
788 st->duplicate = time_duplicate;
789 st->operatortypes = time_operatortypes;
791 st->listener = time_listener;
793 /* regions: main window */
794 art = MEM_callocN(sizeof(ARegionType), "spacetype time region");
795 art->regionid = RGN_TYPE_WINDOW;
796 art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_MARKERS | ED_KEYMAP_ANIMATION | ED_KEYMAP_FRAMES;
798 art->init = time_main_region_init;
799 art->draw = time_main_region_draw;
800 art->listener = time_main_region_listener;
801 art->keymap = time_keymap;
802 art->lock = 1; /* Due to pointcache, see T4960. */
803 BLI_addhead(&st->regiontypes, art);
805 /* regions: header */
806 art = MEM_callocN(sizeof(ARegionType), "spacetype time region");
807 art->regionid = RGN_TYPE_HEADER;
808 art->prefsizey = HEADERY;
809 art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER;
811 art->init = time_header_region_init;
812 art->draw = time_header_region_draw;
813 art->listener = time_header_region_listener;
814 BLI_addhead(&st->regiontypes, art);
816 BKE_spacetype_register(st);